@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.
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +13 -0
- package/lib/common/categories/config/range/typeGuards.d.ts +8 -0
- package/lib/common/categories/config/range/typeGuards.js +9 -0
- package/lib/components/Filter/components/SearchAllFilters/common/constants.d.ts +3 -13
- package/lib/components/Filter/components/SearchAllFilters/common/constants.js +12 -36
- package/lib/components/Filter/components/SearchAllFilters/components/OutlinedInput/constants.d.ts +2 -0
- package/lib/components/Filter/components/SearchAllFilters/components/OutlinedInput/constants.js +7 -0
- package/lib/components/Filter/components/SearchAllFilters/components/OutlinedInput/outlinedInput.d.ts +2 -0
- package/lib/components/Filter/components/SearchAllFilters/components/OutlinedInput/outlinedInput.js +13 -0
- package/lib/components/Filter/components/SearchAllFilters/components/OutlinedInput/utils.d.ts +11 -0
- package/lib/components/Filter/components/SearchAllFilters/components/OutlinedInput/utils.js +17 -0
- package/lib/components/Filter/components/SearchAllFilters/components/VariableSizeList/VariableSizeList.d.ts +2 -0
- package/lib/components/Filter/components/SearchAllFilters/components/VariableSizeList/VariableSizeList.js +9 -10
- package/lib/components/Filter/components/SearchAllFilters/context/context.d.ts +2 -0
- package/lib/components/Filter/components/SearchAllFilters/context/context.js +10 -0
- package/lib/components/Filter/components/SearchAllFilters/context/hook.d.ts +6 -0
- package/lib/components/Filter/components/SearchAllFilters/context/hook.js +9 -0
- package/lib/components/Filter/components/SearchAllFilters/context/types.d.ts +11 -0
- package/lib/components/Filter/components/SearchAllFilters/context/types.js +1 -0
- package/lib/components/Filter/components/SearchAllFilters/searchAllFilters.d.ts +2 -19
- package/lib/components/Filter/components/SearchAllFilters/searchAllFilters.js +37 -74
- package/lib/components/Filter/components/SearchAllFilters/searchAllFilters.styles.d.ts +2 -2
- package/lib/components/Filter/components/SearchAllFilters/searchAllFilters.styles.js +7 -8
- package/lib/components/Filter/components/SearchAllFilters/stories/args.d.ts +3 -0
- package/lib/components/Filter/components/SearchAllFilters/stories/args.js +8 -0
- package/lib/components/Filter/components/SearchAllFilters/stories/searchAllFilters.stories.d.ts +6 -0
- package/lib/components/Filter/components/SearchAllFilters/stories/searchAllFilters.stories.js +19 -0
- package/lib/components/Filter/components/SearchAllFilters/types.d.ts +10 -0
- package/lib/components/Filter/components/SearchAllFilters/types.js +1 -0
- package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/columnFiltersAdapter.js +10 -1
- package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/types.d.ts +5 -1
- package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/utils.js +105 -10
- package/lib/components/Filter/components/surfaces/popper/Popper/popper.styles.d.ts +6 -0
- package/lib/components/Filter/components/surfaces/popper/Popper/popper.styles.js +18 -0
- package/lib/components/Filter/components/surfaces/types.d.ts +3 -1
- package/lib/components/Filter/components/surfaces/types.js +2 -0
- package/lib/styles/common/mui/textField.d.ts +11 -0
- package/lib/styles/common/mui/textField.js +22 -0
- package/lib/views/ExploreView/exploreView.js +1 -1
- package/package.json +1 -1
- package/src/common/categories/config/range/typeGuards.ts +14 -0
- package/src/components/Filter/components/SearchAllFilters/common/constants.ts +24 -37
- package/src/components/Filter/components/SearchAllFilters/components/OutlinedInput/constants.ts +9 -0
- package/src/components/Filter/components/SearchAllFilters/components/OutlinedInput/outlinedInput.tsx +31 -0
- package/src/components/Filter/components/SearchAllFilters/components/OutlinedInput/utils.ts +22 -0
- package/src/components/Filter/components/SearchAllFilters/components/VariableSizeList/VariableSizeList.tsx +12 -13
- package/src/components/Filter/components/SearchAllFilters/context/context.ts +12 -0
- package/src/components/Filter/components/SearchAllFilters/context/hook.ts +11 -0
- package/src/components/Filter/components/SearchAllFilters/context/types.ts +12 -0
- package/src/components/Filter/components/SearchAllFilters/searchAllFilters.styles.ts +8 -9
- package/src/components/Filter/components/SearchAllFilters/searchAllFilters.tsx +70 -132
- package/src/components/Filter/components/SearchAllFilters/stories/args.ts +15 -0
- package/src/components/Filter/components/SearchAllFilters/stories/searchAllFilters.stories.tsx +29 -0
- package/src/components/Filter/components/SearchAllFilters/types.ts +16 -0
- package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/columnFiltersAdapter.tsx +12 -1
- package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/types.ts +10 -1
- package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/utils.ts +147 -12
- package/src/components/Filter/components/surfaces/popper/Popper/popper.styles.ts +20 -0
- package/src/components/Filter/components/surfaces/types.ts +2 -0
- package/src/styles/common/mui/textField.ts +33 -0
- package/src/views/ExploreView/exploreView.tsx +3 -0
- package/lib/components/Filter/components/SearchAllFilters/components/AutocompletePopper/autocompletePopper.styles.d.ts +0 -3
- package/lib/components/Filter/components/SearchAllFilters/components/AutocompletePopper/autocompletePopper.styles.js +0 -15
- package/lib/components/Filter/components/SearchAllFilters/searchAllFilters.stories.d.ts +0 -6
- package/lib/components/Filter/components/SearchAllFilters/searchAllFilters.stories.js +0 -82
- package/lib/components/Filter/components/SearchAllFiltersSearch/components/SearchCloseButton/searchCloseButton.d.ts +0 -1
- package/lib/components/Filter/components/SearchAllFiltersSearch/components/SearchCloseButton/searchCloseButton.js +0 -13
- package/lib/components/Filter/components/SearchAllFiltersSearch/searchAllFiltersSearch.d.ts +0 -2
- package/lib/components/Filter/components/SearchAllFiltersSearch/searchAllFiltersSearch.js +0 -12
- package/lib/components/Filter/components/SearchAllFiltersSearch/searchAllFiltersSearch.styles.d.ts +0 -5
- package/lib/components/Filter/components/SearchAllFiltersSearch/searchAllFiltersSearch.styles.js +0 -34
- package/src/components/Filter/components/SearchAllFilters/components/AutocompletePopper/autocompletePopper.styles.ts +0 -16
- package/src/components/Filter/components/SearchAllFilters/searchAllFilters.stories.tsx +0 -92
- package/src/components/Filter/components/SearchAllFiltersSearch/components/SearchCloseButton/searchCloseButton.tsx +0 -25
- package/src/components/Filter/components/SearchAllFiltersSearch/searchAllFiltersSearch.styles.ts +0 -35
- package/src/components/Filter/components/SearchAllFiltersSearch/searchAllFiltersSearch.tsx +0 -29
|
@@ -1,61 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
ListProps as MListProps,
|
|
4
|
-
} from "@mui/material";
|
|
5
|
-
import React, {
|
|
6
|
-
ChangeEvent,
|
|
7
|
-
createContext,
|
|
8
|
-
useContext,
|
|
9
|
-
useEffect,
|
|
10
|
-
useRef,
|
|
11
|
-
useState,
|
|
12
|
-
} from "react";
|
|
1
|
+
import { ListProps as MListProps } from "@mui/material";
|
|
2
|
+
import React, { useCallback, useRef, useState } from "react";
|
|
13
3
|
import { isSelectCategoryView } from "../../../../common/categories/views/select/typeGuards";
|
|
14
|
-
import { CategoryView } from "../../../../common/categories/views/types";
|
|
15
|
-
import { SelectCategoryView } from "../../../../common/entities";
|
|
16
4
|
import { SELECTOR } from "../../../../common/selectors";
|
|
17
|
-
import {
|
|
18
|
-
BREAKPOINT_FN_NAME,
|
|
19
|
-
useBreakpointHelper,
|
|
20
|
-
} from "../../../../hooks/useBreakpointHelper";
|
|
21
|
-
import { OnFilterFn } from "../../../../hooks/useCategoryFilter";
|
|
22
5
|
import { TEST_IDS } from "../../../../tests/testIds";
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
6
|
+
import {
|
|
7
|
+
StyledPopper,
|
|
8
|
+
StyledPopperDrawer,
|
|
9
|
+
} from "../surfaces/popper/Popper/popper.styles";
|
|
10
|
+
import { SURFACE_TYPE } from "../surfaces/types";
|
|
11
|
+
import {
|
|
12
|
+
POPPER_DRAWER_SLOT_PROPS,
|
|
13
|
+
POPPER_MENU_SLOT_PROPS,
|
|
14
|
+
} from "./common/constants";
|
|
27
15
|
import { OVERFLOW_STYLE } from "./common/entites";
|
|
28
16
|
import { setElementsOverflowStyle } from "./common/utils";
|
|
29
|
-
import {
|
|
17
|
+
import { OutlinedInput } from "./components/OutlinedInput/outlinedInput";
|
|
30
18
|
import { VariableSizeList } from "./components/VariableSizeList/VariableSizeList";
|
|
31
|
-
import {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
onFilter: OnFilterFn;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
interface ListboxContextValue {
|
|
39
|
-
onClearSearch: () => void;
|
|
40
|
-
onCloseSearch: () => void;
|
|
41
|
-
onFilter: OnFilterFn;
|
|
42
|
-
open: boolean;
|
|
43
|
-
searchTerm: string;
|
|
44
|
-
selectCategoryViews: SelectCategoryView[];
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const renderInput = (params: AutocompleteRenderInputParams): JSX.Element => (
|
|
48
|
-
<SearchAllFiltersSearch {...params} />
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
export const ListboxContext = createContext<ListboxContextValue>({
|
|
52
|
-
onClearSearch: (): void => undefined,
|
|
53
|
-
onCloseSearch: (): void => undefined,
|
|
54
|
-
onFilter: (): void => undefined,
|
|
55
|
-
open: false,
|
|
56
|
-
searchTerm: "",
|
|
57
|
-
selectCategoryViews: [],
|
|
58
|
-
});
|
|
19
|
+
import { AutocompleteContext } from "./context/context";
|
|
20
|
+
import { useAutocomplete } from "./context/hook";
|
|
21
|
+
import { StyledAutocomplete } from "./searchAllFilters.styles";
|
|
22
|
+
import { SearchAllFiltersProps } from "./types";
|
|
59
23
|
|
|
60
24
|
const Listbox = React.forwardRef<HTMLUListElement, MListProps>(function Listbox(
|
|
61
25
|
props,
|
|
@@ -64,8 +28,8 @@ const Listbox = React.forwardRef<HTMLUListElement, MListProps>(function Listbox(
|
|
|
64
28
|
props = Object.assign({}, props, {
|
|
65
29
|
children: undefined, // Content is controlled by VariableSizeList
|
|
66
30
|
});
|
|
67
|
-
const { onFilter, searchTerm, selectCategoryViews } =
|
|
68
|
-
|
|
31
|
+
const { onFilter, searchTerm, selectCategoryViews, surfaceType } =
|
|
32
|
+
useAutocomplete();
|
|
69
33
|
return (
|
|
70
34
|
<VariableSizeList
|
|
71
35
|
autocompleteListProps={props}
|
|
@@ -73,120 +37,94 @@ const Listbox = React.forwardRef<HTMLUListElement, MListProps>(function Listbox(
|
|
|
73
37
|
ref={ref}
|
|
74
38
|
searchTerm={searchTerm}
|
|
75
39
|
selectCategoryViews={selectCategoryViews}
|
|
40
|
+
surfaceType={surfaceType}
|
|
76
41
|
/>
|
|
77
42
|
);
|
|
78
43
|
});
|
|
79
44
|
|
|
80
45
|
export const SearchAllFilters = ({
|
|
81
46
|
categoryViews,
|
|
47
|
+
className,
|
|
82
48
|
onFilter,
|
|
49
|
+
surfaceType = SURFACE_TYPE.POPPER_MENU,
|
|
50
|
+
...props /* Mui AutocompleteProps */
|
|
83
51
|
}: SearchAllFiltersProps): JSX.Element => {
|
|
84
|
-
const { open: isDrawerOpen } = useDrawer();
|
|
85
|
-
const bpUpMd = useBreakpointHelper(BREAKPOINT_FN_NAME.UP, "md");
|
|
86
52
|
const autocompleteRef = useRef<HTMLDivElement>(null);
|
|
87
53
|
const [open, setOpen] = useState(false);
|
|
88
54
|
const [searchTerm, setSearchTerm] = useState("");
|
|
89
|
-
const selectCategoryViews = categoryViews.filter(
|
|
90
|
-
isSelectCategoryView(view)
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
// Handles background scroll action ("md" and up).
|
|
94
|
-
const handleBackgroundScroll = (overflowStyle: OVERFLOW_STYLE): void => {
|
|
95
|
-
if (bpUpMd) {
|
|
96
|
-
setElementsOverflowStyle(
|
|
97
|
-
[
|
|
98
|
-
document.querySelector(SELECTOR.BODY),
|
|
99
|
-
document.getElementById(SELECTOR.SIDEBAR_POSITIONER),
|
|
100
|
-
],
|
|
101
|
-
overflowStyle
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
};
|
|
55
|
+
const selectCategoryViews = categoryViews.filter(isSelectCategoryView);
|
|
105
56
|
|
|
106
|
-
//
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
57
|
+
// Handles background scroll action.
|
|
58
|
+
const handleBackgroundScroll = useCallback(
|
|
59
|
+
(overflowStyle: OVERFLOW_STYLE): void => {
|
|
60
|
+
if (surfaceType === SURFACE_TYPE.POPPER_MENU) {
|
|
61
|
+
setElementsOverflowStyle(
|
|
62
|
+
[
|
|
63
|
+
document.querySelector(SELECTOR.BODY),
|
|
64
|
+
document.getElementById(SELECTOR.SIDEBAR_POSITIONER),
|
|
65
|
+
],
|
|
66
|
+
overflowStyle
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
[surfaceType]
|
|
71
|
+
);
|
|
115
72
|
|
|
116
|
-
|
|
117
|
-
const onCloseSearch = (): void => {
|
|
73
|
+
const onClose = useCallback((): void => {
|
|
118
74
|
setSearchTerm("");
|
|
119
75
|
setOpen(false);
|
|
120
76
|
handleBackgroundScroll(OVERFLOW_STYLE.NONE);
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
handleBackgroundScroll(OVERFLOW_STYLE.HIDDEN);
|
|
126
|
-
};
|
|
77
|
+
setTimeout(() => {
|
|
78
|
+
autocompleteRef.current?.querySelector("input")?.blur();
|
|
79
|
+
}, 100);
|
|
80
|
+
}, [handleBackgroundScroll]);
|
|
127
81
|
|
|
128
|
-
|
|
129
|
-
const onOpenSearch = (): void => {
|
|
130
|
-
if (open) {
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
82
|
+
const onOpen = useCallback((): void => {
|
|
133
83
|
setOpen(true);
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
useEffect(() => {
|
|
137
|
-
if (!open) {
|
|
138
|
-
autocompleteRef.current?.querySelector("input")?.blur();
|
|
139
|
-
}
|
|
140
|
-
}, [open]);
|
|
84
|
+
handleBackgroundScroll(OVERFLOW_STYLE.HIDDEN);
|
|
85
|
+
}, [handleBackgroundScroll]);
|
|
141
86
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if (
|
|
145
|
-
|
|
146
|
-
setOpen(false);
|
|
147
|
-
}
|
|
148
|
-
}, [isDrawerOpen]);
|
|
87
|
+
const onClear = useCallback((): void => {
|
|
88
|
+
setSearchTerm("");
|
|
89
|
+
if (surfaceType === SURFACE_TYPE.POPPER_DRAWER) onClose();
|
|
90
|
+
}, [onClose, surfaceType]);
|
|
149
91
|
|
|
150
92
|
return (
|
|
151
|
-
<
|
|
93
|
+
<AutocompleteContext.Provider
|
|
152
94
|
value={{
|
|
153
|
-
|
|
154
|
-
onCloseSearch,
|
|
95
|
+
onClear,
|
|
155
96
|
onFilter,
|
|
156
97
|
open,
|
|
157
98
|
searchTerm,
|
|
158
99
|
selectCategoryViews,
|
|
100
|
+
surfaceType,
|
|
159
101
|
}}
|
|
160
102
|
>
|
|
161
|
-
<
|
|
162
|
-
|
|
103
|
+
<StyledAutocomplete
|
|
104
|
+
className={className}
|
|
163
105
|
data-testid={TEST_IDS.SEARCH_ALL_FILTERS}
|
|
164
106
|
filterOptions={(options): string[] => options}
|
|
165
107
|
freeSolo
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
onClose={bpUpMd ? onCloseSearch : undefined}
|
|
169
|
-
onFocus={onOpenSearch}
|
|
108
|
+
onClose={onClose}
|
|
109
|
+
onInputChange={(_, v = "") => setSearchTerm(v)}
|
|
170
110
|
onOpen={onOpen}
|
|
171
111
|
open={open}
|
|
172
112
|
options={[""]} // Placeholder options, since item rendering is fully controlled by VariableSizeList
|
|
173
|
-
PopperComponent={AutocompletePopper}
|
|
174
113
|
ref={autocompleteRef}
|
|
175
|
-
renderInput={
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
},
|
|
186
|
-
})
|
|
114
|
+
renderInput={OutlinedInput}
|
|
115
|
+
slotProps={
|
|
116
|
+
surfaceType === SURFACE_TYPE.POPPER_MENU
|
|
117
|
+
? POPPER_MENU_SLOT_PROPS
|
|
118
|
+
: POPPER_DRAWER_SLOT_PROPS
|
|
119
|
+
}
|
|
120
|
+
slots={
|
|
121
|
+
surfaceType === SURFACE_TYPE.POPPER_MENU
|
|
122
|
+
? { listbox: Listbox, popper: StyledPopper }
|
|
123
|
+
: { listbox: Listbox, popper: StyledPopperDrawer }
|
|
187
124
|
}
|
|
188
|
-
|
|
125
|
+
value={searchTerm}
|
|
126
|
+
{...props}
|
|
189
127
|
/>
|
|
190
|
-
</
|
|
128
|
+
</AutocompleteContext.Provider>
|
|
191
129
|
);
|
|
192
130
|
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { fn } from "@storybook/test";
|
|
2
|
+
import { ComponentProps } from "react";
|
|
3
|
+
import {
|
|
4
|
+
BIOLOGICAL_SEX,
|
|
5
|
+
DONOR_COUNT,
|
|
6
|
+
GENUS_SPECIES,
|
|
7
|
+
} from "../../Filters/stories/constants";
|
|
8
|
+
import { SURFACE_TYPE } from "../../surfaces/types";
|
|
9
|
+
import { SearchAllFilters } from "../searchAllFilters";
|
|
10
|
+
|
|
11
|
+
export const DEFAULT_ARGS: ComponentProps<typeof SearchAllFilters> = {
|
|
12
|
+
categoryViews: [BIOLOGICAL_SEX, GENUS_SPECIES, DONOR_COUNT],
|
|
13
|
+
onFilter: fn(),
|
|
14
|
+
surfaceType: SURFACE_TYPE.POPPER_MENU,
|
|
15
|
+
};
|
package/src/components/Filter/components/SearchAllFilters/stories/searchAllFilters.stories.tsx
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Box } from "@mui/material";
|
|
2
|
+
import { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { PALETTE } from "../../../../../styles/common/constants/palette";
|
|
5
|
+
import { SearchAllFilters } from "../searchAllFilters";
|
|
6
|
+
import { DEFAULT_ARGS } from "./args";
|
|
7
|
+
|
|
8
|
+
const meta: Meta<typeof SearchAllFilters> = {
|
|
9
|
+
component: SearchAllFilters,
|
|
10
|
+
decorators: [
|
|
11
|
+
(Story): JSX.Element => (
|
|
12
|
+
<Box sx={{ backgroundColor: PALETTE.COMMON_WHITE, minWidth: 264 }}>
|
|
13
|
+
<Story />
|
|
14
|
+
</Box>
|
|
15
|
+
),
|
|
16
|
+
],
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default meta;
|
|
20
|
+
|
|
21
|
+
type Story = StoryObj<typeof meta>;
|
|
22
|
+
|
|
23
|
+
const DefaultStory = (): JSX.Element => {
|
|
24
|
+
return <SearchAllFilters {...DEFAULT_ARGS} />;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const Default: Story = {
|
|
28
|
+
render: () => <DefaultStory />,
|
|
29
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
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
|
+
|
|
7
|
+
export interface SearchAllFiltersProps
|
|
8
|
+
extends Omit<
|
|
9
|
+
AutocompleteProps<string, false, false, true>,
|
|
10
|
+
"options" | "renderInput"
|
|
11
|
+
>,
|
|
12
|
+
BaseComponentProps {
|
|
13
|
+
categoryViews: CategoryView[];
|
|
14
|
+
onFilter: OnFilterFn;
|
|
15
|
+
surfaceType?: SURFACE_TYPE;
|
|
16
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RowData } from "@tanstack/react-table";
|
|
2
2
|
import { useCallback } from "react";
|
|
3
|
+
import { VIEW_KIND } from "../../../../../../common/categories/views/types";
|
|
3
4
|
import {
|
|
4
5
|
CategoryKey,
|
|
5
6
|
CategoryValueKey,
|
|
@@ -22,13 +23,23 @@ export const ColumnFiltersAdapter = <T extends RowData>({
|
|
|
22
23
|
categoryKey: CategoryKey | ClearAll,
|
|
23
24
|
selectedCategoryValue: CategoryValueKey,
|
|
24
25
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- `selected` is not required by TanStack adapter.
|
|
25
|
-
_selected: boolean
|
|
26
|
+
_selected: boolean,
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- `categorySection` is not required by TanStack adapter.
|
|
28
|
+
_categorySection?: string,
|
|
29
|
+
viewKind?: VIEW_KIND
|
|
26
30
|
) => {
|
|
27
31
|
if (categoryKey === CLEAR_ALL) {
|
|
28
32
|
table.resetColumnFilters();
|
|
29
33
|
return;
|
|
30
34
|
}
|
|
31
35
|
|
|
36
|
+
// Range filters use direct value assignment (e.g., [min, max] tuple for numeric ranges).
|
|
37
|
+
if (viewKind === VIEW_KIND.RANGE) {
|
|
38
|
+
table.getColumn(categoryKey)?.setFilterValue(selectedCategoryValue);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Select filters use an updater function to toggle individual values in/out of the filter array.
|
|
32
43
|
table
|
|
33
44
|
.getColumn(categoryKey)
|
|
34
45
|
?.setFilterValue(updater(selectedCategoryValue));
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
RowData,
|
|
3
|
+
Table,
|
|
4
|
+
TableMeta as TanStackTableMeta,
|
|
5
|
+
} from "@tanstack/react-table";
|
|
6
|
+
import { CategoryGroup } from "../../../../../../config/entities";
|
|
2
7
|
import { SurfaceProps } from "../../../surfaces/types";
|
|
3
8
|
|
|
4
9
|
export interface ColumnFiltersAdapterProps<T extends RowData> {
|
|
5
10
|
renderSurface: (props: SurfaceProps) => JSX.Element | null;
|
|
6
11
|
table: Table<T>;
|
|
7
12
|
}
|
|
13
|
+
export interface ColumnFiltersTableMeta<T extends RowData>
|
|
14
|
+
extends TanStackTableMeta<T> {
|
|
15
|
+
categoryGroups?: CategoryGroup[];
|
|
16
|
+
}
|
|
@@ -1,9 +1,52 @@
|
|
|
1
1
|
import { Column, RowData, Table } from "@tanstack/react-table";
|
|
2
|
+
import { isRangeCategoryConfig } from "../../../../../../common/categories/config/range/typeGuards";
|
|
3
|
+
import { CategoryConfig } from "../../../../../../common/categories/config/types";
|
|
4
|
+
import { RangeCategoryView } from "../../../../../../common/categories/views/range/types";
|
|
2
5
|
import { CategoryView } from "../../../../../../common/categories/views/types";
|
|
3
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
SelectCategoryValueView,
|
|
8
|
+
SelectCategoryView,
|
|
9
|
+
} from "../../../../../../common/entities";
|
|
10
|
+
import { CategoryGroup } from "../../../../../../config/entities";
|
|
4
11
|
import { getColumnHeader } from "../../../../../Table/common/utils";
|
|
5
12
|
import { getSortedFacetedValues } from "../../../../../Table/featureOptions/facetedColumn/utils";
|
|
13
|
+
import { CategoryFilter } from "../../../Filters/filters";
|
|
6
14
|
import { SurfaceProps } from "../../../surfaces/types";
|
|
15
|
+
import { ColumnFiltersTableMeta } from "./types";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Adapter for TanStack table to category configs.
|
|
19
|
+
* @param table - Table.
|
|
20
|
+
* @returns Category configs.
|
|
21
|
+
*/
|
|
22
|
+
function buildCategoryConfigs<T extends RowData>(
|
|
23
|
+
table: Table<T>
|
|
24
|
+
): CategoryConfig[] {
|
|
25
|
+
return table
|
|
26
|
+
.getAllColumns()
|
|
27
|
+
.filter((column) => column.getCanFilter())
|
|
28
|
+
.map(mapCategoryConfig);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Adapter for TanStack table to category filters.
|
|
33
|
+
* @param table - Table.
|
|
34
|
+
* @param categoryGroups - Category groups.
|
|
35
|
+
* @returns Category filters.
|
|
36
|
+
*/
|
|
37
|
+
function buildCategoryFilters<T extends RowData>(
|
|
38
|
+
table: Table<T>,
|
|
39
|
+
categoryGroups: CategoryGroup[]
|
|
40
|
+
): SurfaceProps["categoryFilters"] {
|
|
41
|
+
return categoryGroups.reduce<SurfaceProps["categoryFilters"]>(
|
|
42
|
+
(acc, categoryGroup) => {
|
|
43
|
+
const categoryFilter = mapCategoryFilter(table, categoryGroup);
|
|
44
|
+
if (categoryFilter) acc.push(categoryFilter);
|
|
45
|
+
return acc;
|
|
46
|
+
},
|
|
47
|
+
[]
|
|
48
|
+
);
|
|
49
|
+
}
|
|
7
50
|
|
|
8
51
|
/**
|
|
9
52
|
* Adapter for TanStack table column filters to category filters.
|
|
@@ -13,13 +56,19 @@ import { SurfaceProps } from "../../../surfaces/types";
|
|
|
13
56
|
export function buildColumnFilters<T extends RowData>(
|
|
14
57
|
table: Table<T>
|
|
15
58
|
): SurfaceProps["categoryFilters"] {
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
.filter((column) => column.getCanFilter())
|
|
20
|
-
.map(mapColumnToCategoryView);
|
|
59
|
+
const { options } = table;
|
|
60
|
+
const { meta = {} } = options;
|
|
61
|
+
const { categoryGroups } = meta as ColumnFiltersTableMeta<T>;
|
|
21
62
|
|
|
22
|
-
|
|
63
|
+
if (!categoryGroups) {
|
|
64
|
+
// Build single category group with all (filterable) columns.
|
|
65
|
+
const categoryConfigs: CategoryConfig[] = buildCategoryConfigs(table);
|
|
66
|
+
// Build category filters from single category group.
|
|
67
|
+
return buildCategoryFilters(table, [{ categoryConfigs, label: "" }]);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Build category filters from category groups.
|
|
71
|
+
return buildCategoryFilters(table, categoryGroups);
|
|
23
72
|
}
|
|
24
73
|
|
|
25
74
|
/**
|
|
@@ -39,14 +88,99 @@ export function getColumnFiltersCount<T extends RowData>(
|
|
|
39
88
|
}
|
|
40
89
|
|
|
41
90
|
/**
|
|
42
|
-
* Adapter for TanStack column to category
|
|
43
|
-
* Currently supports only select category views.
|
|
91
|
+
* Adapter for TanStack column to category config.
|
|
44
92
|
* @param column - Column.
|
|
45
|
-
* @returns Category
|
|
93
|
+
* @returns Category config.
|
|
46
94
|
*/
|
|
47
|
-
function
|
|
95
|
+
function mapCategoryConfig<T extends RowData>(
|
|
48
96
|
column: Column<T>
|
|
49
|
-
):
|
|
97
|
+
): CategoryConfig {
|
|
98
|
+
return {
|
|
99
|
+
key: column.id,
|
|
100
|
+
label: getColumnHeader(column),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Adapter for TanStack table to category filter.
|
|
106
|
+
* @param table - Table.
|
|
107
|
+
* @param categoryGroup - Category group.
|
|
108
|
+
* @returns Category filter.
|
|
109
|
+
*/
|
|
110
|
+
function mapCategoryFilter<T extends RowData>(
|
|
111
|
+
table: Table<T>,
|
|
112
|
+
categoryGroup: CategoryGroup
|
|
113
|
+
): CategoryFilter | undefined {
|
|
114
|
+
const { categoryConfigs, label } = categoryGroup;
|
|
115
|
+
|
|
116
|
+
const categoryViews = categoryConfigs.reduce<CategoryView[]>(
|
|
117
|
+
(acc, categoryConfig) => {
|
|
118
|
+
const column = table.getColumn(categoryConfig.key);
|
|
119
|
+
if (!column) return acc;
|
|
120
|
+
if (!column.getCanFilter()) return acc;
|
|
121
|
+
|
|
122
|
+
let categoryView: CategoryView;
|
|
123
|
+
|
|
124
|
+
if (isRangeCategoryConfig(categoryConfig)) {
|
|
125
|
+
// Build range category view.
|
|
126
|
+
categoryView = mapColumnToRangeCategoryView(column, categoryConfig);
|
|
127
|
+
} else {
|
|
128
|
+
// Build select category view.
|
|
129
|
+
categoryView = mapColumnToSelectCategoryView(column, categoryConfig);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return [...acc, categoryView];
|
|
133
|
+
},
|
|
134
|
+
[]
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
if (categoryViews.length === 0) return;
|
|
138
|
+
|
|
139
|
+
return { categoryViews, label };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Adapter for TanStack column to range category view.
|
|
144
|
+
* @param column - Column.
|
|
145
|
+
* @param categoryConfig - Category config.
|
|
146
|
+
* @returns Range category view.
|
|
147
|
+
*/
|
|
148
|
+
function mapColumnToRangeCategoryView<T extends RowData>(
|
|
149
|
+
column: Column<T>,
|
|
150
|
+
categoryConfig?: CategoryConfig
|
|
151
|
+
): RangeCategoryView {
|
|
152
|
+
const minMax = column.getFacetedMinMaxValues();
|
|
153
|
+
const isDisabled = !minMax;
|
|
154
|
+
|
|
155
|
+
// Selected values for the column.
|
|
156
|
+
const filterValue = (column.getFilterValue() || [null, null]) as [
|
|
157
|
+
number | null,
|
|
158
|
+
number | null
|
|
159
|
+
];
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
annotation: undefined,
|
|
163
|
+
isDisabled,
|
|
164
|
+
key: column.id,
|
|
165
|
+
label: getColumnHeader(column),
|
|
166
|
+
max: minMax?.[1] || Infinity,
|
|
167
|
+
min: minMax?.[0] || -Infinity,
|
|
168
|
+
selectedMax: filterValue[1],
|
|
169
|
+
selectedMin: filterValue[0],
|
|
170
|
+
...categoryConfig,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Adapter for TanStack column to select category view.
|
|
176
|
+
* @param column - Column.
|
|
177
|
+
* @param categoryConfig - Category config.
|
|
178
|
+
* @returns Select category view.
|
|
179
|
+
*/
|
|
180
|
+
function mapColumnToSelectCategoryView<T extends RowData>(
|
|
181
|
+
column: Column<T>,
|
|
182
|
+
categoryConfig?: CategoryConfig
|
|
183
|
+
): SelectCategoryView {
|
|
50
184
|
const facetedUniqueValues = column.getFacetedUniqueValues();
|
|
51
185
|
const isDisabled = facetedUniqueValues.size === 0;
|
|
52
186
|
const values = mapColumnToSelectCategoryValueView(column);
|
|
@@ -57,6 +191,7 @@ function mapColumnToCategoryView<T extends RowData>(
|
|
|
57
191
|
key: column.id,
|
|
58
192
|
label: getColumnHeader(column),
|
|
59
193
|
values,
|
|
194
|
+
...categoryConfig,
|
|
60
195
|
};
|
|
61
196
|
}
|
|
62
197
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import styled from "@emotion/styled";
|
|
2
|
+
import { Popper } from "@mui/material";
|
|
3
|
+
import { PALETTE } from "../../../../../../styles/common/constants/palette";
|
|
4
|
+
|
|
5
|
+
export const StyledPopper = styled(Popper)`
|
|
6
|
+
.MuiPaper-root {
|
|
7
|
+
width: 368px;
|
|
8
|
+
}
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
export const StyledPopperDrawer = styled(Popper)`
|
|
12
|
+
.MuiPaper-root {
|
|
13
|
+
background-color: ${PALETTE.SMOKE_LIGHT};
|
|
14
|
+
width: 312px;
|
|
15
|
+
|
|
16
|
+
.MuiList-root {
|
|
17
|
+
margin: 0;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
`;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { TextFieldProps } from "@mui/material";
|
|
2
|
+
|
|
3
|
+
type TextFieldPropsOptions = {
|
|
4
|
+
COLOR: typeof COLOR;
|
|
5
|
+
SIZE: typeof SIZE;
|
|
6
|
+
VARIANT: typeof VARIANT;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const COLOR: Record<string, TextFieldProps["color"]> = {
|
|
10
|
+
ERROR: "error",
|
|
11
|
+
INFO: "info",
|
|
12
|
+
PRIMARY: "primary",
|
|
13
|
+
SECONDARY: "secondary",
|
|
14
|
+
SUCCESS: "success",
|
|
15
|
+
WARNING: "warning",
|
|
16
|
+
} as const;
|
|
17
|
+
|
|
18
|
+
const SIZE: Record<string, TextFieldProps["size"]> = {
|
|
19
|
+
MEDIUM: "medium",
|
|
20
|
+
SMALL: "small",
|
|
21
|
+
} as const;
|
|
22
|
+
|
|
23
|
+
const VARIANT: Record<string, TextFieldProps["variant"]> = {
|
|
24
|
+
FILLED: "filled",
|
|
25
|
+
OUTLINED: "outlined",
|
|
26
|
+
STANDARD: "standard",
|
|
27
|
+
} as const;
|
|
28
|
+
|
|
29
|
+
export const TEXT_FIELD_PROPS: TextFieldPropsOptions = {
|
|
30
|
+
COLOR,
|
|
31
|
+
SIZE,
|
|
32
|
+
VARIANT,
|
|
33
|
+
};
|
|
@@ -135,6 +135,9 @@ export const ExploreView = (props: ExploreViewProps): JSX.Element => {
|
|
|
135
135
|
<SearchAllFilters
|
|
136
136
|
categoryViews={categoryViews}
|
|
137
137
|
onFilter={onFilterChange.bind(null, true)}
|
|
138
|
+
surfaceType={
|
|
139
|
+
mdDown ? SURFACE_TYPE.POPPER_DRAWER : SURFACE_TYPE.POPPER_MENU
|
|
140
|
+
}
|
|
138
141
|
/>
|
|
139
142
|
</SidebarTools>
|
|
140
143
|
<Filters
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import styled from "@emotion/styled";
|
|
2
|
-
import { Popper as MPopper } from "@mui/material";
|
|
3
|
-
import { PALETTE } from "../../../../../../styles/common/constants/palette";
|
|
4
|
-
import { bpDownMd } from "../../../../../../styles/common/mixins/breakpoints";
|
|
5
|
-
export const AutocompletePopper = styled(MPopper) `
|
|
6
|
-
${bpDownMd} {
|
|
7
|
-
.MuiPaper-root {
|
|
8
|
-
background-color: ${PALETTE.SMOKE_LIGHT};
|
|
9
|
-
|
|
10
|
-
.MuiList-root {
|
|
11
|
-
margin: 0;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
`;
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { Meta, StoryObj } from "@storybook/react";
|
|
2
|
-
import { SearchAllFilters } from "./searchAllFilters";
|
|
3
|
-
declare const _default: Meta<typeof SearchAllFilters>;
|
|
4
|
-
export default _default;
|
|
5
|
-
type Story = StoryObj<typeof SearchAllFilters>;
|
|
6
|
-
export declare const SearchAllFiltersStory: Story;
|