@databiosphere/findable-ui 42.1.0 → 43.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/CHANGELOG.md +13 -0
  3. package/lib/common/categories/config/range/typeGuards.d.ts +8 -0
  4. package/lib/common/categories/config/range/typeGuards.js +9 -0
  5. package/lib/components/Filter/components/SearchAllFilters/common/constants.d.ts +3 -13
  6. package/lib/components/Filter/components/SearchAllFilters/common/constants.js +12 -36
  7. package/lib/components/Filter/components/SearchAllFilters/components/OutlinedInput/constants.d.ts +2 -0
  8. package/lib/components/Filter/components/SearchAllFilters/components/OutlinedInput/constants.js +7 -0
  9. package/lib/components/Filter/components/SearchAllFilters/components/OutlinedInput/outlinedInput.d.ts +2 -0
  10. package/lib/components/Filter/components/SearchAllFilters/components/OutlinedInput/outlinedInput.js +13 -0
  11. package/lib/components/Filter/components/SearchAllFilters/components/OutlinedInput/utils.d.ts +11 -0
  12. package/lib/components/Filter/components/SearchAllFilters/components/OutlinedInput/utils.js +17 -0
  13. package/lib/components/Filter/components/SearchAllFilters/components/VariableSizeList/VariableSizeList.d.ts +2 -0
  14. package/lib/components/Filter/components/SearchAllFilters/components/VariableSizeList/VariableSizeList.js +9 -10
  15. package/lib/components/Filter/components/SearchAllFilters/context/context.d.ts +2 -0
  16. package/lib/components/Filter/components/SearchAllFilters/context/context.js +10 -0
  17. package/lib/components/Filter/components/SearchAllFilters/context/hook.d.ts +6 -0
  18. package/lib/components/Filter/components/SearchAllFilters/context/hook.js +9 -0
  19. package/lib/components/Filter/components/SearchAllFilters/context/types.d.ts +11 -0
  20. package/lib/components/Filter/components/SearchAllFilters/context/types.js +1 -0
  21. package/lib/components/Filter/components/SearchAllFilters/searchAllFilters.d.ts +2 -19
  22. package/lib/components/Filter/components/SearchAllFilters/searchAllFilters.js +37 -74
  23. package/lib/components/Filter/components/SearchAllFilters/searchAllFilters.styles.d.ts +2 -2
  24. package/lib/components/Filter/components/SearchAllFilters/searchAllFilters.styles.js +7 -8
  25. package/lib/components/Filter/components/SearchAllFilters/stories/args.d.ts +3 -0
  26. package/lib/components/Filter/components/SearchAllFilters/stories/args.js +8 -0
  27. package/lib/components/Filter/components/SearchAllFilters/stories/searchAllFilters.stories.d.ts +6 -0
  28. package/lib/components/Filter/components/SearchAllFilters/stories/searchAllFilters.stories.js +19 -0
  29. package/lib/components/Filter/components/SearchAllFilters/types.d.ts +10 -0
  30. package/lib/components/Filter/components/SearchAllFilters/types.js +1 -0
  31. package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/columnFiltersAdapter.js +10 -1
  32. package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/types.d.ts +5 -1
  33. package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/utils.js +105 -10
  34. package/lib/components/Filter/components/surfaces/popper/Popper/popper.styles.d.ts +6 -0
  35. package/lib/components/Filter/components/surfaces/popper/Popper/popper.styles.js +18 -0
  36. package/lib/components/Filter/components/surfaces/types.d.ts +3 -1
  37. package/lib/components/Filter/components/surfaces/types.js +2 -0
  38. package/lib/styles/common/mui/textField.d.ts +11 -0
  39. package/lib/styles/common/mui/textField.js +22 -0
  40. package/lib/views/ExploreView/exploreView.js +1 -1
  41. package/package.json +1 -1
  42. package/src/common/categories/config/range/typeGuards.ts +14 -0
  43. package/src/components/Filter/components/SearchAllFilters/common/constants.ts +24 -37
  44. package/src/components/Filter/components/SearchAllFilters/components/OutlinedInput/constants.ts +9 -0
  45. package/src/components/Filter/components/SearchAllFilters/components/OutlinedInput/outlinedInput.tsx +31 -0
  46. package/src/components/Filter/components/SearchAllFilters/components/OutlinedInput/utils.ts +22 -0
  47. package/src/components/Filter/components/SearchAllFilters/components/VariableSizeList/VariableSizeList.tsx +12 -13
  48. package/src/components/Filter/components/SearchAllFilters/context/context.ts +12 -0
  49. package/src/components/Filter/components/SearchAllFilters/context/hook.ts +11 -0
  50. package/src/components/Filter/components/SearchAllFilters/context/types.ts +12 -0
  51. package/src/components/Filter/components/SearchAllFilters/searchAllFilters.styles.ts +8 -9
  52. package/src/components/Filter/components/SearchAllFilters/searchAllFilters.tsx +70 -132
  53. package/src/components/Filter/components/SearchAllFilters/stories/args.ts +15 -0
  54. package/src/components/Filter/components/SearchAllFilters/stories/searchAllFilters.stories.tsx +29 -0
  55. package/src/components/Filter/components/SearchAllFilters/types.ts +16 -0
  56. package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/columnFiltersAdapter.tsx +12 -1
  57. package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/types.ts +10 -1
  58. package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/utils.ts +147 -12
  59. package/src/components/Filter/components/surfaces/popper/Popper/popper.styles.ts +20 -0
  60. package/src/components/Filter/components/surfaces/types.ts +2 -0
  61. package/src/styles/common/mui/textField.ts +33 -0
  62. package/src/views/ExploreView/exploreView.tsx +3 -0
  63. package/lib/components/Filter/components/SearchAllFilters/components/AutocompletePopper/autocompletePopper.styles.d.ts +0 -3
  64. package/lib/components/Filter/components/SearchAllFilters/components/AutocompletePopper/autocompletePopper.styles.js +0 -15
  65. package/lib/components/Filter/components/SearchAllFilters/searchAllFilters.stories.d.ts +0 -6
  66. package/lib/components/Filter/components/SearchAllFilters/searchAllFilters.stories.js +0 -82
  67. package/lib/components/Filter/components/SearchAllFiltersSearch/components/SearchCloseButton/searchCloseButton.d.ts +0 -1
  68. package/lib/components/Filter/components/SearchAllFiltersSearch/components/SearchCloseButton/searchCloseButton.js +0 -13
  69. package/lib/components/Filter/components/SearchAllFiltersSearch/searchAllFiltersSearch.d.ts +0 -2
  70. package/lib/components/Filter/components/SearchAllFiltersSearch/searchAllFiltersSearch.js +0 -12
  71. package/lib/components/Filter/components/SearchAllFiltersSearch/searchAllFiltersSearch.styles.d.ts +0 -5
  72. package/lib/components/Filter/components/SearchAllFiltersSearch/searchAllFiltersSearch.styles.js +0 -34
  73. package/src/components/Filter/components/SearchAllFilters/components/AutocompletePopper/autocompletePopper.styles.ts +0 -16
  74. package/src/components/Filter/components/SearchAllFilters/searchAllFilters.stories.tsx +0 -92
  75. package/src/components/Filter/components/SearchAllFiltersSearch/components/SearchCloseButton/searchCloseButton.tsx +0 -25
  76. package/src/components/Filter/components/SearchAllFiltersSearch/searchAllFiltersSearch.styles.ts +0 -35
  77. package/src/components/Filter/components/SearchAllFiltersSearch/searchAllFiltersSearch.tsx +0 -29
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "42.1.0"
2
+ ".": "43.0.0"
3
3
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [43.0.0](https://github.com/DataBiosphere/findable-ui/compare/v42.1.0...v43.0.0) (2025-08-19)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * add surfacetype prop to searchallfilters ([#636](https://github.com/DataBiosphere/findable-ui/issues/636)) (#637)
9
+
10
+ ### Features
11
+
12
+ * add surfacetype prop to searchallfilters ([#636](https://github.com/DataBiosphere/findable-ui/issues/636)) ([#637](https://github.com/DataBiosphere/findable-ui/issues/637)) ([026f522](https://github.com/DataBiosphere/findable-ui/commit/026f522e383dca64903b68859f10997ead191fe9))
13
+ * update columnfiltersadapter to handle grouping of column filters ([#632](https://github.com/DataBiosphere/findable-ui/issues/632)) ([#633](https://github.com/DataBiosphere/findable-ui/issues/633)) ([23c54e9](https://github.com/DataBiosphere/findable-ui/commit/23c54e99a83522d8eef4b2f4b544b3cb3367ce32))
14
+ * update columnfiltersadapter to handle range category filtering ([#634](https://github.com/DataBiosphere/findable-ui/issues/634)) ([#635](https://github.com/DataBiosphere/findable-ui/issues/635)) ([5b5a5b8](https://github.com/DataBiosphere/findable-ui/commit/5b5a5b8d36c2d847f2b97bfbb55f094f5961dbb5))
15
+
3
16
  ## [42.1.0](https://github.com/DataBiosphere/findable-ui/compare/v42.0.1...v42.1.0) (2025-08-13)
4
17
 
5
18
 
@@ -0,0 +1,8 @@
1
+ import { RangeCategoryView } from "../../views/range/types";
2
+ import { CategoryConfig } from "../types";
3
+ /**
4
+ * Determine if the given category config is a range category.
5
+ * @param categoryConfig - Category config.
6
+ * @returns True if the category config is a range category, false otherwise.
7
+ */
8
+ export declare function isRangeCategoryConfig(categoryConfig: CategoryConfig): categoryConfig is RangeCategoryView;
@@ -0,0 +1,9 @@
1
+ import { VIEW_KIND } from "../../views/types";
2
+ /**
3
+ * Determine if the given category config is a range category.
4
+ * @param categoryConfig - Category config.
5
+ * @returns True if the category config is a range category, false otherwise.
6
+ */
7
+ export function isRangeCategoryConfig(categoryConfig) {
8
+ return categoryConfig.viewKind === VIEW_KIND.RANGE;
9
+ }
@@ -1,18 +1,8 @@
1
- import { PaperProps, PopperProps } from "@mui/material";
1
+ import { AutocompleteProps } from "@mui/material";
2
2
  import { DividerItem, NoResultsItem } from "./entites";
3
3
  export declare const DEFAULT_LIST_HEIGHT = 0;
4
4
  export declare const DIVIDER_HEIGHT = 17;
5
- export declare const DEFAULT_PAPER_PROPS: Partial<PaperProps>;
6
- export declare const DEFAULT_POPPER_PROPS: Partial<PopperProps>;
7
- export declare const DEFAULT_SLOT_PROPS: {
8
- paper: Partial<PaperProps>;
9
- popper: Partial<PopperProps>;
10
- };
11
- export declare const DRAWER_PAPER_PROPS: Partial<PaperProps>;
12
- export declare const DRAWER_POPPER_PROPS: Partial<PopperProps>;
13
- export declare const DRAWER_SLOT_PROPS: {
14
- paper: Partial<PaperProps>;
15
- popper: Partial<PopperProps>;
16
- };
5
+ export declare const POPPER_MENU_SLOT_PROPS: AutocompleteProps<string, false, false, true>["slotProps"];
6
+ export declare const POPPER_DRAWER_SLOT_PROPS: AutocompleteProps<string, false, false, true>["slotProps"];
17
7
  export declare const DIVIDER_ITEM: DividerItem;
18
8
  export declare const NO_RESULTS_ITEM: NoResultsItem;
@@ -1,47 +1,23 @@
1
1
  import { ITEM_TYPE } from "./entites";
2
2
  export const DEFAULT_LIST_HEIGHT = 0;
3
3
  export const DIVIDER_HEIGHT = 17;
4
- export const DEFAULT_PAPER_PROPS = {
5
- sx: {
6
- width: 368,
7
- },
8
- variant: "menu",
9
- };
10
- export const DEFAULT_POPPER_PROPS = {
11
- modifiers: [
12
- {
13
- name: "offset",
14
- options: {
15
- offset: [0, 8],
16
- },
17
- },
18
- ],
4
+ const POPPER_MENU_PAPER_PROPS = { variant: "menu" };
5
+ const POPPER_MENU_POPPER_PROPS = {
6
+ modifiers: [{ name: "offset", options: { offset: [0, 8] } }],
19
7
  placement: "bottom-start",
20
8
  };
21
- export const DEFAULT_SLOT_PROPS = {
22
- paper: DEFAULT_PAPER_PROPS,
23
- popper: DEFAULT_POPPER_PROPS,
24
- };
25
- export const DRAWER_PAPER_PROPS = {
26
- elevation: 0,
27
- sx: {
28
- width: 312,
29
- },
9
+ export const POPPER_MENU_SLOT_PROPS = {
10
+ paper: POPPER_MENU_PAPER_PROPS,
11
+ popper: POPPER_MENU_POPPER_PROPS,
30
12
  };
31
- export const DRAWER_POPPER_PROPS = {
32
- modifiers: [
33
- {
34
- name: "offset",
35
- options: {
36
- offset: [-16, 8],
37
- },
38
- },
39
- ],
13
+ const POPPER_DRAWER_PAPER_PROPS = { elevation: 0 };
14
+ const POPPER_DRAWER_POPPER_PROPS = {
15
+ modifiers: [{ name: "offset", options: { offset: [-16, 8] } }],
40
16
  popperOptions: { strategy: "absolute" },
41
17
  };
42
- export const DRAWER_SLOT_PROPS = {
43
- paper: DRAWER_PAPER_PROPS,
44
- popper: DRAWER_POPPER_PROPS,
18
+ export const POPPER_DRAWER_SLOT_PROPS = {
19
+ paper: POPPER_DRAWER_PAPER_PROPS,
20
+ popper: POPPER_DRAWER_POPPER_PROPS,
45
21
  };
46
22
  export const DIVIDER_ITEM = {
47
23
  type: ITEM_TYPE.DIVIDER,
@@ -0,0 +1,2 @@
1
+ import { OutlinedInputProps } from "@mui/material";
2
+ export declare const TEXT_FIELD_PROPS: OutlinedInputProps;
@@ -0,0 +1,7 @@
1
+ import { TEXT_FIELD_PROPS as MUI_TEXT_FIELD_PROPS } from "../../../../../../styles/common/mui/textField";
2
+ export const TEXT_FIELD_PROPS = {
3
+ color: MUI_TEXT_FIELD_PROPS.COLOR.SECONDARY,
4
+ fullWidth: true,
5
+ placeholder: "Search all filters...",
6
+ size: MUI_TEXT_FIELD_PROPS.SIZE.SMALL,
7
+ };
@@ -0,0 +1,2 @@
1
+ import { AutocompleteRenderInputParams } from "@mui/material";
2
+ export declare const OutlinedInput: (props: AutocompleteRenderInputParams) => JSX.Element;
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ import { ClearInputAdornment } from "../../../../../common/OutlinedInput/components/InputAdornment/components/ClearInputAdornment/clearInputAdornment";
3
+ import { SearchInputAdornment } from "../../../../../common/OutlinedInput/components/InputAdornment/components/SearchInputAdornment/searchInputAdornment";
4
+ import { StyledOutlinedInput } from "../../../../../common/OutlinedInput/outlinedInput.styles";
5
+ import { useAutocomplete } from "../../context/hook";
6
+ import { TEXT_FIELD_PROPS } from "./constants";
7
+ import { isButtonIn } from "./utils";
8
+ export const OutlinedInput = (props) => {
9
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars -- Intended behavior, destructure InputLabelProps, as they are not used on the component.
10
+ const { InputLabelProps, InputProps, ...outlinedInputProps } = props;
11
+ const { onClear, open, searchTerm, surfaceType } = useAutocomplete();
12
+ return (React.createElement(StyledOutlinedInput, { ...TEXT_FIELD_PROPS, ...InputProps, ...outlinedInputProps, endAdornment: React.createElement(ClearInputAdornment, { in: isButtonIn(surfaceType, searchTerm, open), onClick: onClear }), hasValue: !!searchTerm, startAdornment: React.createElement(SearchInputAdornment, null) }));
13
+ };
@@ -0,0 +1,11 @@
1
+ import { SURFACE_TYPE } from "../../../surfaces/types";
2
+ /**
3
+ * Returns true if the clear button should display.
4
+ * Displays always for popper drawer surface type when open.
5
+ * Displays when there is a search term for other surface types when open.
6
+ * @param surfaceType - Surface type.
7
+ * @param searchTerm - Search term.
8
+ * @param open - Autocomplete open state.
9
+ * @returns True if the clear button should display.
10
+ */
11
+ export declare function isButtonIn(surfaceType: SURFACE_TYPE, searchTerm: string, open: boolean): boolean;
@@ -0,0 +1,17 @@
1
+ import { SURFACE_TYPE } from "../../../surfaces/types";
2
+ /**
3
+ * Returns true if the clear button should display.
4
+ * Displays always for popper drawer surface type when open.
5
+ * Displays when there is a search term for other surface types when open.
6
+ * @param surfaceType - Surface type.
7
+ * @param searchTerm - Search term.
8
+ * @param open - Autocomplete open state.
9
+ * @returns True if the clear button should display.
10
+ */
11
+ export function isButtonIn(surfaceType, searchTerm, open) {
12
+ if (!open)
13
+ return false;
14
+ if (surfaceType === SURFACE_TYPE.POPPER_DRAWER)
15
+ return true;
16
+ return !!searchTerm;
17
+ }
@@ -3,6 +3,7 @@ import React from "react";
3
3
  import { VariableSizeListProps as ListProps } from "react-window";
4
4
  import { SelectCategoryView } from "../../../../../../common/entities";
5
5
  import { OnFilterFn } from "../../../../../../hooks/useCategoryFilter";
6
+ import { SURFACE_TYPE } from "../../../surfaces/types";
6
7
  export type ItemSizeByItemKey = Map<string, number>;
7
8
  export interface VariableSizeListProps {
8
9
  autocompleteListProps: Omit<MListProps, "children">;
@@ -12,6 +13,7 @@ export interface VariableSizeListProps {
12
13
  overscanCount?: ListProps["overscanCount"];
13
14
  searchTerm: string;
14
15
  selectCategoryViews: SelectCategoryView[];
16
+ surfaceType: SURFACE_TYPE;
15
17
  width?: ListProps["width"];
16
18
  }
17
19
  export declare const VariableSizeList: React.ForwardRefExoticComponent<VariableSizeListProps & React.RefAttributes<HTMLUListElement>>;
@@ -1,11 +1,11 @@
1
1
  import { Divider, List as MList } from "@mui/material";
2
2
  import React, { createContext, forwardRef, useCallback, useContext, useEffect, useRef, useState, } from "react";
3
3
  import { VariableSizeList as List, } from "react-window";
4
- import { BREAKPOINT_FN_NAME, useBreakpointHelper, } from "../../../../../../hooks/useBreakpointHelper";
5
4
  import { useWindowResize } from "../../../../../../hooks/useWindowResize";
6
5
  import { LIST_ITEM_HEIGHT, LIST_MARGIN, MAX_DISPLAYABLE_LIST_ITEMS, MAX_LIST_HEIGHT_PX, } from "../../../../common/constants";
7
6
  import { getSortMatchesFn } from "../../../../common/utils";
8
7
  import { StyledList } from "../../../FilterList/filterList.styles";
8
+ import { SURFACE_TYPE } from "../../../surfaces/types";
9
9
  import { DIVIDER_HEIGHT, DIVIDER_ITEM, NO_RESULTS_ITEM, } from "../../common/constants";
10
10
  import { ITEM_TYPE, } from "../../common/entites";
11
11
  import VariableSizeListItem from "../VariableSizeListItem/variableSizeListItem";
@@ -32,10 +32,9 @@ const OuterElement = forwardRef(function OuterElement({ children, ...props }, re
32
32
  return (React.createElement("div", { ref: ref, ...props },
33
33
  React.createElement(MList, { ref: autocompleteListRef, style: { maxHeight: "none", padding: 0 }, ...autocompleteListProps }, children)));
34
34
  });
35
- export const VariableSizeList = forwardRef(function VariableSizeList({ autocompleteListProps, height: initHeight = MAX_LIST_HEIGHT_PX, itemSize = LIST_ITEM_HEIGHT, onFilter, overscanCount = MAX_DISPLAYABLE_LIST_ITEMS * 2, searchTerm, selectCategoryViews, width = "100%", }, autocompleteListRef) {
35
+ export const VariableSizeList = forwardRef(function VariableSizeList({ autocompleteListProps, height: initHeight = MAX_LIST_HEIGHT_PX, itemSize = LIST_ITEM_HEIGHT, onFilter, overscanCount = MAX_DISPLAYABLE_LIST_ITEMS * 2, searchTerm, selectCategoryViews, surfaceType, width = "100%", }, autocompleteListRef) {
36
36
  const filteredItems = applyMenuFilter(selectCategoryViews, searchTerm);
37
37
  let resizeRequired = true;
38
- const bpDownMd = useBreakpointHelper(BREAKPOINT_FN_NAME.DOWN, "md");
39
38
  const { height: windowHeight } = useWindowResize();
40
39
  const [height, setHeight] = useState(initHeight);
41
40
  const itemSizeByItemKeyRef = useRef(new Map());
@@ -47,8 +46,8 @@ export const VariableSizeList = forwardRef(function VariableSizeList({ autocompl
47
46
  // Sets height of list.
48
47
  useEffect(() => {
49
48
  if (innerRef.current && outerRef.current)
50
- setHeight(calculateListHeight(outerRef.current, innerRef.current, windowHeight, bpDownMd));
51
- }, [bpDownMd, windowHeight]);
49
+ setHeight(calculateListHeight(outerRef.current, innerRef.current, windowHeight, surfaceType));
50
+ }, [surfaceType, windowHeight]);
52
51
  // Clears VariableSizeList cache (offsets and measurements) when values are updated (filtered).
53
52
  // Facilitates correct positioning of list items when list is updated.
54
53
  useEffect(() => {
@@ -72,7 +71,7 @@ export const VariableSizeList = forwardRef(function VariableSizeList({ autocompl
72
71
  outerRef.current) {
73
72
  // Set height of list.
74
73
  resizeRequired = false;
75
- setHeight(calculateListHeight(outerRef.current, innerRef.current, windowHeight, bpDownMd));
74
+ setHeight(calculateListHeight(outerRef.current, innerRef.current, windowHeight, surfaceType));
76
75
  }
77
76
  listRef.current?.resetAfterIndex(0); // Facilitates correct positioning of list items when list scrolls.
78
77
  });
@@ -119,15 +118,15 @@ function applyMenuFilter(selectCategoryViews, inputValue) {
119
118
  * @param outerListElem - Outer list element to reference list position from.
120
119
  * @param innerListElem - Element containing list items.
121
120
  * @param windowHeight - Window height.
122
- * @param bpDownMd - True if viewport is "md" or smaller.
121
+ * @param surfaceType - Type of surface "POPPER_MENU" or "POPPER_DRAWER".
123
122
  * @returns calculated height.
124
123
  */
125
- function calculateListHeight(outerListElem, innerListElem, windowHeight, bpDownMd) {
124
+ function calculateListHeight(outerListElem, innerListElem, windowHeight, surfaceType) {
126
125
  // Calculate max possible list height, based on window height and top position of the list element.
127
126
  const maxHeight = windowHeight - outerListElem.getBoundingClientRect().top;
128
- if (bpDownMd) {
127
+ // Return the maximum possible height if the list is in a popper drawer.
128
+ if (surfaceType === SURFACE_TYPE.POPPER_DRAWER)
129
129
  return maxHeight;
130
- }
131
130
  // Grab the first and last element in the list.
132
131
  const { firstElementChild: firstListEl, lastElementChild: lastListEl } = innerListElem;
133
132
  // Grab the scroll position to adjust calculated list height.
@@ -0,0 +1,2 @@
1
+ import { AutocompleteContextProps } from "./types";
2
+ export declare const AutocompleteContext: import("react").Context<AutocompleteContextProps>;
@@ -0,0 +1,10 @@
1
+ import { createContext } from "react";
2
+ import { SURFACE_TYPE } from "../../surfaces/types";
3
+ export const AutocompleteContext = createContext({
4
+ onClear: () => undefined,
5
+ onFilter: () => undefined,
6
+ open: false,
7
+ searchTerm: "",
8
+ selectCategoryViews: [],
9
+ surfaceType: SURFACE_TYPE.POPPER_MENU,
10
+ });
@@ -0,0 +1,6 @@
1
+ import { AutocompleteContextProps } from "./types";
2
+ /**
3
+ * Returns autocomplete context.
4
+ * @returns autocomplete context.
5
+ */
6
+ export declare const useAutocomplete: () => AutocompleteContextProps;
@@ -0,0 +1,9 @@
1
+ import { useContext } from "react";
2
+ import { AutocompleteContext } from "./context";
3
+ /**
4
+ * Returns autocomplete context.
5
+ * @returns autocomplete context.
6
+ */
7
+ export const useAutocomplete = () => {
8
+ return useContext(AutocompleteContext);
9
+ };
@@ -0,0 +1,11 @@
1
+ import { SelectCategoryView } from "../../../../../common/entities";
2
+ import { OnFilterFn } from "../../../../../hooks/useCategoryFilter";
3
+ import { SURFACE_TYPE } from "../../surfaces/types";
4
+ export interface AutocompleteContextProps {
5
+ onClear: () => void;
6
+ onFilter: OnFilterFn;
7
+ open: boolean;
8
+ searchTerm: string;
9
+ selectCategoryViews: SelectCategoryView[];
10
+ surfaceType: SURFACE_TYPE;
11
+ }
@@ -1,19 +1,2 @@
1
- import React from "react";
2
- import { CategoryView } from "../../../../common/categories/views/types";
3
- import { SelectCategoryView } from "../../../../common/entities";
4
- import { OnFilterFn } from "../../../../hooks/useCategoryFilter";
5
- export interface SearchAllFiltersProps {
6
- categoryViews: CategoryView[];
7
- onFilter: OnFilterFn;
8
- }
9
- interface ListboxContextValue {
10
- onClearSearch: () => void;
11
- onCloseSearch: () => void;
12
- onFilter: OnFilterFn;
13
- open: boolean;
14
- searchTerm: string;
15
- selectCategoryViews: SelectCategoryView[];
16
- }
17
- export declare const ListboxContext: React.Context<ListboxContextValue>;
18
- export declare const SearchAllFilters: ({ categoryViews, onFilter, }: SearchAllFiltersProps) => JSX.Element;
19
- export {};
1
+ import { SearchAllFiltersProps } from "./types";
2
+ export declare const SearchAllFilters: ({ categoryViews, className, onFilter, surfaceType, ...props }: SearchAllFiltersProps) => JSX.Element;
@@ -1,103 +1,66 @@
1
- import React, { createContext, useContext, useEffect, useRef, useState, } from "react";
1
+ import React, { useCallback, useRef, useState } from "react";
2
2
  import { isSelectCategoryView } from "../../../../common/categories/views/select/typeGuards";
3
3
  import { SELECTOR } from "../../../../common/selectors";
4
- import { BREAKPOINT_FN_NAME, useBreakpointHelper, } from "../../../../hooks/useBreakpointHelper";
5
4
  import { TEST_IDS } from "../../../../tests/testIds";
6
- import { useDrawer } from "../../../common/Drawer/provider/hook";
7
- import { SearchCloseButton } from "../SearchAllFiltersSearch/components/SearchCloseButton/searchCloseButton";
8
- import { SearchAllFiltersSearch } from "../SearchAllFiltersSearch/searchAllFiltersSearch";
9
- import { DEFAULT_SLOT_PROPS, DRAWER_SLOT_PROPS } from "./common/constants";
5
+ import { StyledPopper, StyledPopperDrawer, } from "../surfaces/popper/Popper/popper.styles";
6
+ import { SURFACE_TYPE } from "../surfaces/types";
7
+ import { POPPER_DRAWER_SLOT_PROPS, POPPER_MENU_SLOT_PROPS, } from "./common/constants";
10
8
  import { OVERFLOW_STYLE } from "./common/entites";
11
9
  import { setElementsOverflowStyle } from "./common/utils";
12
- import { AutocompletePopper } from "./components/AutocompletePopper/autocompletePopper.styles";
10
+ import { OutlinedInput } from "./components/OutlinedInput/outlinedInput";
13
11
  import { VariableSizeList } from "./components/VariableSizeList/VariableSizeList";
14
- import { Autocomplete } from "./searchAllFilters.styles";
15
- const renderInput = (params) => (React.createElement(SearchAllFiltersSearch, { ...params }));
16
- export const ListboxContext = createContext({
17
- onClearSearch: () => undefined,
18
- onCloseSearch: () => undefined,
19
- onFilter: () => undefined,
20
- open: false,
21
- searchTerm: "",
22
- selectCategoryViews: [],
23
- });
12
+ import { AutocompleteContext } from "./context/context";
13
+ import { useAutocomplete } from "./context/hook";
14
+ import { StyledAutocomplete } from "./searchAllFilters.styles";
24
15
  const Listbox = React.forwardRef(function Listbox(props, ref) {
25
16
  props = Object.assign({}, props, {
26
17
  children: undefined, // Content is controlled by VariableSizeList
27
18
  });
28
- const { onFilter, searchTerm, selectCategoryViews } = useContext(ListboxContext);
29
- return (React.createElement(VariableSizeList, { autocompleteListProps: props, onFilter: onFilter, ref: ref, searchTerm: searchTerm, selectCategoryViews: selectCategoryViews }));
19
+ const { onFilter, searchTerm, selectCategoryViews, surfaceType } = useAutocomplete();
20
+ return (React.createElement(VariableSizeList, { autocompleteListProps: props, onFilter: onFilter, ref: ref, searchTerm: searchTerm, selectCategoryViews: selectCategoryViews, surfaceType: surfaceType }));
30
21
  });
31
- export const SearchAllFilters = ({ categoryViews, onFilter, }) => {
32
- const { open: isDrawerOpen } = useDrawer();
33
- const bpUpMd = useBreakpointHelper(BREAKPOINT_FN_NAME.UP, "md");
22
+ export const SearchAllFilters = ({ categoryViews, className, onFilter, surfaceType = SURFACE_TYPE.POPPER_MENU, ...props /* Mui AutocompleteProps */ }) => {
34
23
  const autocompleteRef = useRef(null);
35
24
  const [open, setOpen] = useState(false);
36
25
  const [searchTerm, setSearchTerm] = useState("");
37
- const selectCategoryViews = categoryViews.filter((view) => isSelectCategoryView(view));
38
- // Handles background scroll action ("md" and up).
39
- const handleBackgroundScroll = (overflowStyle) => {
40
- if (bpUpMd) {
26
+ const selectCategoryViews = categoryViews.filter(isSelectCategoryView);
27
+ // Handles background scroll action.
28
+ const handleBackgroundScroll = useCallback((overflowStyle) => {
29
+ if (surfaceType === SURFACE_TYPE.POPPER_MENU) {
41
30
  setElementsOverflowStyle([
42
31
  document.querySelector(SELECTOR.BODY),
43
32
  document.getElementById(SELECTOR.SIDEBAR_POSITIONER),
44
33
  ], overflowStyle);
45
34
  }
46
- };
47
- // Callback fired when the value is changed.
48
- const onChange = (event) => {
49
- setSearchTerm(event.target.value);
50
- };
51
- // Clear search
52
- const onClearSearch = () => {
53
- setSearchTerm("");
54
- };
55
- // Close search.
56
- const onCloseSearch = () => {
35
+ }, [surfaceType]);
36
+ const onClose = useCallback(() => {
57
37
  setSearchTerm("");
58
38
  setOpen(false);
59
39
  handleBackgroundScroll(OVERFLOW_STYLE.NONE);
60
- };
61
- // Callback fired when the popup requests to be opened.
62
- const onOpen = () => {
63
- handleBackgroundScroll(OVERFLOW_STYLE.HIDDEN);
64
- };
65
- // Open search.
66
- const onOpenSearch = () => {
67
- if (open) {
68
- return;
69
- }
70
- setOpen(true);
71
- };
72
- useEffect(() => {
73
- if (!open) {
40
+ setTimeout(() => {
74
41
  autocompleteRef.current?.querySelector("input")?.blur();
75
- }
76
- }, [open]);
77
- // Close search when filter drawer is closed.
78
- useEffect(() => {
79
- if (!isDrawerOpen) {
80
- setSearchTerm("");
81
- setOpen(false);
82
- }
83
- }, [isDrawerOpen]);
84
- return (React.createElement(ListboxContext.Provider, { value: {
85
- onClearSearch,
86
- onCloseSearch,
42
+ }, 100);
43
+ }, [handleBackgroundScroll]);
44
+ const onOpen = useCallback(() => {
45
+ setOpen(true);
46
+ handleBackgroundScroll(OVERFLOW_STYLE.HIDDEN);
47
+ }, [handleBackgroundScroll]);
48
+ const onClear = useCallback(() => {
49
+ setSearchTerm("");
50
+ if (surfaceType === SURFACE_TYPE.POPPER_DRAWER)
51
+ onClose();
52
+ }, [onClose, surfaceType]);
53
+ return (React.createElement(AutocompleteContext.Provider, { value: {
54
+ onClear,
87
55
  onFilter,
88
56
  open,
89
57
  searchTerm,
90
58
  selectCategoryViews,
59
+ surfaceType,
91
60
  } },
92
- React.createElement(Autocomplete, { clearOnBlur: bpUpMd, "data-testid": TEST_IDS.SEARCH_ALL_FILTERS, filterOptions: (options) => options, freeSolo: true, ListboxComponent: Listbox, onBlur: bpUpMd ? onCloseSearch : undefined, onClose: bpUpMd ? onCloseSearch : undefined, onFocus: onOpenSearch, onOpen: onOpen, open: open, options: [""], PopperComponent: AutocompletePopper, ref: autocompleteRef, renderInput: (props) => renderInput({
93
- ...props,
94
- InputProps: {
95
- ...props.InputProps,
96
- endAdornment: React.createElement(SearchCloseButton, null),
97
- },
98
- inputProps: {
99
- ...props.inputProps,
100
- onChange,
101
- },
102
- }), slotProps: bpUpMd ? DEFAULT_SLOT_PROPS : DRAWER_SLOT_PROPS })));
61
+ React.createElement(StyledAutocomplete, { className: className, "data-testid": TEST_IDS.SEARCH_ALL_FILTERS, filterOptions: (options) => options, freeSolo: true, onClose: onClose, onInputChange: (_, v = "") => setSearchTerm(v), onOpen: onOpen, open: open, options: [""], ref: autocompleteRef, renderInput: OutlinedInput, slotProps: surfaceType === SURFACE_TYPE.POPPER_MENU
62
+ ? POPPER_MENU_SLOT_PROPS
63
+ : POPPER_DRAWER_SLOT_PROPS, slots: surfaceType === SURFACE_TYPE.POPPER_MENU
64
+ ? { listbox: Listbox, popper: StyledPopper }
65
+ : { listbox: Listbox, popper: StyledPopperDrawer }, value: searchTerm, ...props })));
103
66
  };
@@ -1,2 +1,2 @@
1
- import { Autocomplete as MAutocomplete } from "@mui/material";
2
- export declare const Autocomplete: typeof MAutocomplete;
1
+ import { Autocomplete } from "@mui/material";
2
+ export declare const StyledAutocomplete: typeof Autocomplete;
@@ -1,13 +1,12 @@
1
1
  import styled from "@emotion/styled";
2
- import { Autocomplete as MAutocomplete } from "@mui/material";
3
- import { PALETTE } from "../../../../styles/common/constants/palette";
4
- export const Autocomplete = styled(MAutocomplete) `
5
- &.Mui-expanded {
2
+ import { Autocomplete } from "@mui/material";
3
+ export const StyledAutocomplete = styled(Autocomplete) `
4
+ &.MuiAutocomplete-root {
6
5
  .MuiOutlinedInput-root {
7
- .MuiIconButton-root {
8
- .MuiSvgIcon-root {
9
- color: ${PALETTE.INK_MAIN};
10
- }
6
+ padding: 0 12px;
7
+
8
+ .MuiAutocomplete-input {
9
+ padding: 10px 0;
11
10
  }
12
11
  }
13
12
  }
@@ -0,0 +1,3 @@
1
+ import { ComponentProps } from "react";
2
+ import { SearchAllFilters } from "../searchAllFilters";
3
+ export declare const DEFAULT_ARGS: ComponentProps<typeof SearchAllFilters>;
@@ -0,0 +1,8 @@
1
+ import { fn } from "@storybook/test";
2
+ import { BIOLOGICAL_SEX, DONOR_COUNT, GENUS_SPECIES, } from "../../Filters/stories/constants";
3
+ import { SURFACE_TYPE } from "../../surfaces/types";
4
+ export const DEFAULT_ARGS = {
5
+ categoryViews: [BIOLOGICAL_SEX, GENUS_SPECIES, DONOR_COUNT],
6
+ onFilter: fn(),
7
+ surfaceType: SURFACE_TYPE.POPPER_MENU,
8
+ };
@@ -0,0 +1,6 @@
1
+ import { Meta, StoryObj } from "@storybook/react";
2
+ import { SearchAllFilters } from "../searchAllFilters";
3
+ declare const meta: Meta<typeof SearchAllFilters>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof meta>;
6
+ export declare const Default: Story;
@@ -0,0 +1,19 @@
1
+ import { Box } from "@mui/material";
2
+ import React from "react";
3
+ import { PALETTE } from "../../../../../styles/common/constants/palette";
4
+ import { SearchAllFilters } from "../searchAllFilters";
5
+ import { DEFAULT_ARGS } from "./args";
6
+ const meta = {
7
+ component: SearchAllFilters,
8
+ decorators: [
9
+ (Story) => (React.createElement(Box, { sx: { backgroundColor: PALETTE.COMMON_WHITE, minWidth: 264 } },
10
+ React.createElement(Story, null))),
11
+ ],
12
+ };
13
+ export default meta;
14
+ const DefaultStory = () => {
15
+ return React.createElement(SearchAllFilters, { ...DEFAULT_ARGS });
16
+ };
17
+ export const Default = {
18
+ render: () => React.createElement(DefaultStory, null),
19
+ };
@@ -0,0 +1,10 @@
1
+ import { AutocompleteProps } from "@mui/material";
2
+ import { CategoryView } from "../../../../common/categories/views/types";
3
+ import { OnFilterFn } from "../../../../hooks/useCategoryFilter";
4
+ import { BaseComponentProps } from "../../../types";
5
+ import { SURFACE_TYPE } from "../surfaces/types";
6
+ export interface SearchAllFiltersProps extends Omit<AutocompleteProps<string, false, false, true>, "options" | "renderInput">, BaseComponentProps {
7
+ categoryViews: CategoryView[];
8
+ onFilter: OnFilterFn;
9
+ surfaceType?: SURFACE_TYPE;
10
+ }
@@ -1,4 +1,5 @@
1
1
  import { useCallback } from "react";
2
+ import { VIEW_KIND } from "../../../../../../common/categories/views/types";
2
3
  import { CLEAR_ALL, } from "../../../../../../common/entities";
3
4
  import { updater } from "../../../../../Table/components/TableFeatures/ColumnFilter/utils";
4
5
  import { buildColumnFilters, getColumnFiltersCount } from "./utils";
@@ -7,11 +8,19 @@ export const ColumnFiltersAdapter = ({ renderSurface, table, }) => {
7
8
  const count = getColumnFiltersCount(table);
8
9
  const onFilter = useCallback((categoryKey, selectedCategoryValue,
9
10
  // eslint-disable-next-line @typescript-eslint/no-unused-vars -- `selected` is not required by TanStack adapter.
10
- _selected) => {
11
+ _selected,
12
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars -- `categorySection` is not required by TanStack adapter.
13
+ _categorySection, viewKind) => {
11
14
  if (categoryKey === CLEAR_ALL) {
12
15
  table.resetColumnFilters();
13
16
  return;
14
17
  }
18
+ // Range filters use direct value assignment (e.g., [min, max] tuple for numeric ranges).
19
+ if (viewKind === VIEW_KIND.RANGE) {
20
+ table.getColumn(categoryKey)?.setFilterValue(selectedCategoryValue);
21
+ return;
22
+ }
23
+ // Select filters use an updater function to toggle individual values in/out of the filter array.
15
24
  table
16
25
  .getColumn(categoryKey)
17
26
  ?.setFilterValue(updater(selectedCategoryValue));
@@ -1,6 +1,10 @@
1
- import { RowData, Table } from "@tanstack/react-table";
1
+ import { RowData, Table, TableMeta as TanStackTableMeta } from "@tanstack/react-table";
2
+ import { CategoryGroup } from "../../../../../../config/entities";
2
3
  import { SurfaceProps } from "../../../surfaces/types";
3
4
  export interface ColumnFiltersAdapterProps<T extends RowData> {
4
5
  renderSurface: (props: SurfaceProps) => JSX.Element | null;
5
6
  table: Table<T>;
6
7
  }
8
+ export interface ColumnFiltersTableMeta<T extends RowData> extends TanStackTableMeta<T> {
9
+ categoryGroups?: CategoryGroup[];
10
+ }