searchBarAction.tsx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import styled from '@emotion/styled';
  2. import DropdownButton from 'sentry/components/dropdownButton';
  3. import CompactSelect from 'sentry/components/forms/compactSelect';
  4. import SearchBar from 'sentry/components/searchBar';
  5. import {t, tn} from 'sentry/locale';
  6. import space from 'sentry/styles/space';
  7. type FilterOption = React.ComponentProps<typeof CompactSelect>['options'][0];
  8. type Props = {
  9. onChange: (value: string) => void;
  10. placeholder: string;
  11. query: string;
  12. className?: string;
  13. filterOptions?: FilterOption[];
  14. filterSelections?: FilterOption[];
  15. onFilterChange?: (options: FilterOption[]) => void;
  16. };
  17. function SearchBarAction({
  18. onChange,
  19. query,
  20. placeholder,
  21. filterOptions,
  22. filterSelections,
  23. onFilterChange,
  24. className,
  25. }: Props) {
  26. const trigger: React.ComponentProps<typeof CompactSelect>['trigger'] = ({
  27. props,
  28. ref,
  29. }) => (
  30. <StyledTrigger
  31. size="sm"
  32. priority={filterSelections && filterSelections.length > 0 ? 'primary' : 'default'}
  33. ref={ref}
  34. {...props}
  35. >
  36. {filterSelections?.length
  37. ? tn('%s Active Filter', '%s Active Filters', filterSelections.length)
  38. : t('Filter By')}
  39. </StyledTrigger>
  40. );
  41. return (
  42. <Wrapper className={className}>
  43. {filterOptions && (
  44. <CompactSelect
  45. size="sm"
  46. multiple
  47. maxMenuHeight={400}
  48. options={filterOptions}
  49. value={filterSelections?.map(f => f.value)}
  50. onChange={onFilterChange}
  51. trigger={trigger}
  52. />
  53. )}
  54. <StyledSearchBar
  55. size="sm"
  56. onChange={onChange}
  57. query={query}
  58. placeholder={placeholder}
  59. blendWithFilter={!!filterOptions}
  60. />
  61. </Wrapper>
  62. );
  63. }
  64. export default SearchBarAction;
  65. const Wrapper = styled('div')`
  66. display: flex;
  67. width: 100%;
  68. justify-content: flex-end;
  69. @media (max-width: ${p => p.theme.breakpoints.small}) {
  70. margin-top: ${space(1)};
  71. flex-direction: column;
  72. }
  73. @media (min-width: ${p => p.theme.breakpoints.medium}) {
  74. width: 400px;
  75. }
  76. @media (min-width: ${p => p.theme.breakpoints.xlarge}) {
  77. width: 600px;
  78. }
  79. `;
  80. const StyledSearchBar = styled(SearchBar)<{blendWithFilter?: boolean}>`
  81. width: 100%;
  82. ${p =>
  83. p.blendWithFilter &&
  84. `
  85. input {
  86. border-radius: ${p.theme.borderRadiusRight};
  87. border-left-width: 0;
  88. }
  89. `}
  90. @media (max-width: ${p => p.theme.breakpoints.small}) {
  91. input {
  92. border-radius: ${p => p.theme.borderRadius};
  93. border-left-width: 1px;
  94. }
  95. }
  96. `;
  97. const StyledTrigger = styled(DropdownButton)`
  98. border-radius: ${p => p.theme.borderRadiusLeft};
  99. @media (max-width: ${p => p.theme.breakpoints.small}) {
  100. border-radius: ${p => p.theme.borderRadius};
  101. margin-bottom: ${space(1)};
  102. }
  103. `;