@axinom/mosaic-ui 0.72.0-rc.9 → 0.72.1
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/dist/cjs/components/Badge/Badge.d.ts +13 -0
- package/dist/cjs/components/Badge/Badge.d.ts.map +1 -0
- package/dist/cjs/components/Badge/Badge.model.d.ts +42 -0
- package/dist/cjs/components/Badge/Badge.model.d.ts.map +1 -0
- package/dist/cjs/components/Badge/index.d.ts +3 -0
- package/dist/cjs/components/Badge/index.d.ts.map +1 -0
- package/dist/cjs/components/Explorer/Explorer.d.ts.map +1 -1
- package/dist/cjs/components/Explorer/helpers/useActions.d.ts +1 -4
- package/dist/cjs/components/Explorer/helpers/useActions.d.ts.map +1 -1
- package/dist/cjs/components/Explorer/helpers/useFilters.d.ts +0 -2
- package/dist/cjs/components/Explorer/helpers/useFilters.d.ts.map +1 -1
- package/dist/cjs/components/Filters/Filters.d.ts +12 -10
- package/dist/cjs/components/Filters/Filters.d.ts.map +1 -1
- package/dist/cjs/components/Filters/index.d.ts +1 -0
- package/dist/cjs/components/Filters/index.d.ts.map +1 -1
- package/dist/cjs/components/Icons/Icons.d.ts.map +1 -1
- package/dist/cjs/components/Icons/Icons.models.d.ts +17 -16
- package/dist/cjs/components/Icons/Icons.models.d.ts.map +1 -1
- package/dist/cjs/components/index.d.ts +1 -0
- package/dist/cjs/components/index.d.ts.map +1 -1
- package/dist/cjs/index.js +4 -4
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/components/Badge/Badge.d.ts +13 -0
- package/dist/esm/components/Badge/Badge.d.ts.map +1 -0
- package/dist/esm/components/Badge/Badge.model.d.ts +42 -0
- package/dist/esm/components/Badge/Badge.model.d.ts.map +1 -0
- package/dist/esm/components/Badge/index.d.ts +3 -0
- package/dist/esm/components/Badge/index.d.ts.map +1 -0
- package/dist/esm/components/Explorer/Explorer.d.ts.map +1 -1
- package/dist/esm/components/Explorer/helpers/useActions.d.ts +1 -4
- package/dist/esm/components/Explorer/helpers/useActions.d.ts.map +1 -1
- package/dist/esm/components/Explorer/helpers/useFilters.d.ts +0 -2
- package/dist/esm/components/Explorer/helpers/useFilters.d.ts.map +1 -1
- package/dist/esm/components/Filters/Filters.d.ts +12 -10
- package/dist/esm/components/Filters/Filters.d.ts.map +1 -1
- package/dist/esm/components/Filters/index.d.ts +1 -0
- package/dist/esm/components/Filters/index.d.ts.map +1 -1
- package/dist/esm/components/Icons/Icons.d.ts.map +1 -1
- package/dist/esm/components/Icons/Icons.models.d.ts +17 -16
- package/dist/esm/components/Icons/Icons.models.d.ts.map +1 -1
- package/dist/esm/components/index.d.ts +1 -0
- package/dist/esm/components/index.d.ts.map +1 -1
- package/dist/esm/index.js +4 -4
- package/dist/esm/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/Badge/Badge.model.ts +46 -0
- package/src/components/Badge/Badge.module.scss +62 -0
- package/src/components/Badge/Badge.spec.tsx +40 -0
- package/src/components/Badge/Badge.stories.tsx +43 -0
- package/src/components/Badge/Badge.tsx +59 -0
- package/src/components/Badge/index.ts +2 -0
- package/src/components/Explorer/Explorer.tsx +40 -55
- package/src/components/Explorer/helpers/useActions.ts +0 -29
- package/src/components/Explorer/helpers/useFilters.spec.tsx +9 -25
- package/src/components/Explorer/helpers/useFilters.tsx +17 -21
- package/src/components/Filters/Filters.module.scss +39 -0
- package/src/components/Filters/Filters.tsx +102 -10
- package/src/components/Filters/index.ts +1 -0
- package/src/components/Icons/Icons.models.ts +1 -0
- package/src/components/Icons/Icons.stories.tsx +1 -1
- package/src/components/Icons/Icons.tsx +10 -0
- package/src/components/index.ts +1 -0
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import clsx from 'clsx';
|
|
2
2
|
import React, {
|
|
3
|
+
type ForwardedRef,
|
|
4
|
+
forwardRef,
|
|
3
5
|
type PropsWithChildren,
|
|
6
|
+
useCallback,
|
|
4
7
|
useEffect,
|
|
8
|
+
useImperativeHandle,
|
|
5
9
|
useRef,
|
|
6
10
|
useState,
|
|
7
11
|
} from 'react';
|
|
12
|
+
import { useExpand } from '../../hooks';
|
|
8
13
|
import type { Data } from '../../types/data';
|
|
14
|
+
import { Badge } from '../Badge';
|
|
15
|
+
import { Button, ButtonContext } from '../Buttons';
|
|
16
|
+
import { IconName } from '../Icons';
|
|
9
17
|
import { Filter } from './Filter/Filter';
|
|
10
18
|
import type { FilterType, FilterValue, FilterValues } from './Filters.model';
|
|
11
19
|
import classes from './Filters.module.scss';
|
|
@@ -17,6 +25,19 @@ export interface FiltersProps<T extends Data> {
|
|
|
17
25
|
className?: string;
|
|
18
26
|
}
|
|
19
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Imperative handle exposed to consumers of the {@link Filters} component
|
|
30
|
+
* through a ref, allowing them to control the component programmatically.
|
|
31
|
+
*/
|
|
32
|
+
export interface FiltersHandle {
|
|
33
|
+
/** Collapses the currently expanded filter, if any. */
|
|
34
|
+
collapse: () => void;
|
|
35
|
+
/** Toggles the expanded state of the filter. */
|
|
36
|
+
toggleExpanded: () => void;
|
|
37
|
+
/** Returns whether any filter is currently expanded. */
|
|
38
|
+
isExpanded: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
20
41
|
type CompositeFilters<T extends Data> = {
|
|
21
42
|
[K in keyof T]?: (FilterType<T> & { index: number })[];
|
|
22
43
|
};
|
|
@@ -31,18 +52,33 @@ type CompositeFilters<T extends Data> = {
|
|
|
31
52
|
* @example
|
|
32
53
|
* <Filter filters={[freeTextFilter, optionsFilter, customFilter]} onFiltersChange={callBackFn} />
|
|
33
54
|
*/
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
55
|
+
const FiltersComponent = <T extends Data>(
|
|
56
|
+
{
|
|
57
|
+
defaultValues: defaultFilters = {},
|
|
58
|
+
options,
|
|
59
|
+
onFiltersChange,
|
|
60
|
+
className = '',
|
|
61
|
+
}: PropsWithChildren<FiltersProps<T>>,
|
|
62
|
+
ref: ForwardedRef<FiltersHandle>,
|
|
63
|
+
): JSX.Element | null => {
|
|
64
|
+
const { collapse, toggleExpanded, isExpanded } = useExpand(true);
|
|
40
65
|
const activeFilters = useRef<FilterValues<T>>(defaultFilters);
|
|
41
66
|
const [compositeFilters, setCompositeFilters] = useState<CompositeFilters<T>>(
|
|
42
67
|
{},
|
|
43
68
|
);
|
|
44
69
|
const [activeFilterIndex, setActiveFilterIndex] = useState<number>(-1);
|
|
45
70
|
|
|
71
|
+
// Expose imperative controls to the component rendering <Filters />.
|
|
72
|
+
useImperativeHandle(
|
|
73
|
+
ref,
|
|
74
|
+
() => ({
|
|
75
|
+
collapse,
|
|
76
|
+
toggleExpanded,
|
|
77
|
+
isExpanded,
|
|
78
|
+
}),
|
|
79
|
+
[collapse, toggleExpanded, isExpanded],
|
|
80
|
+
);
|
|
81
|
+
|
|
46
82
|
useEffect(() => {
|
|
47
83
|
const compositeFiltersUpdate: CompositeFilters<T> = {};
|
|
48
84
|
|
|
@@ -119,6 +155,13 @@ export const Filters = <T extends Data>({
|
|
|
119
155
|
setActiveFilterIndex(idx);
|
|
120
156
|
};
|
|
121
157
|
|
|
158
|
+
// Reset all active filters and emit the empty set. `hasValue` in each Filter is
|
|
159
|
+
// derived from its `value`, so re-rendering with empty values hides every chip.
|
|
160
|
+
const clearAllFilters = useCallback(() => {
|
|
161
|
+
activeFilters.current = {};
|
|
162
|
+
onFiltersChange?.({});
|
|
163
|
+
}, [onFiltersChange]);
|
|
164
|
+
|
|
122
165
|
const renderFilter = (filter: FilterType<T>, index: number): JSX.Element => {
|
|
123
166
|
let value = activeFilters.current[filter.property];
|
|
124
167
|
if (Object.keys(compositeFilters).indexOf(String(filter.property)) > -1) {
|
|
@@ -149,18 +192,67 @@ export const Filters = <T extends Data>({
|
|
|
149
192
|
);
|
|
150
193
|
};
|
|
151
194
|
|
|
195
|
+
const filterCount = Object.keys(activeFilters.current).length;
|
|
196
|
+
|
|
197
|
+
// Nothing to filter by - don't render the filter panel at all.
|
|
198
|
+
if (!options?.length) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
|
|
152
202
|
return (
|
|
153
203
|
<div
|
|
154
204
|
className={clsx(
|
|
155
|
-
|
|
205
|
+
classes.container,
|
|
206
|
+
{ [classes.collapsed]: !isExpanded },
|
|
156
207
|
'filter-container',
|
|
157
208
|
className,
|
|
158
209
|
)}
|
|
159
210
|
data-test-id="filters"
|
|
160
211
|
>
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
212
|
+
<div className={classes.header}>
|
|
213
|
+
<Badge
|
|
214
|
+
content={!isExpanded && filterCount > 0 ? filterCount : undefined}
|
|
215
|
+
position="bottom-right"
|
|
216
|
+
overlap={false}
|
|
217
|
+
dataTestId="filters-count-badge"
|
|
218
|
+
max={9}
|
|
219
|
+
>
|
|
220
|
+
<Button
|
|
221
|
+
icon={IconName.Filters}
|
|
222
|
+
className={classes.headerButton}
|
|
223
|
+
buttonContext={ButtonContext.None}
|
|
224
|
+
onButtonClicked={toggleExpanded}
|
|
225
|
+
dataTestId="filters-toggle"
|
|
226
|
+
/>
|
|
227
|
+
</Badge>
|
|
228
|
+
{isExpanded && (
|
|
229
|
+
<>
|
|
230
|
+
<span className={classes.count} data-test-id="filters-count">
|
|
231
|
+
{filterCount > 0 ? `Filters (${filterCount})` : 'Filters'}
|
|
232
|
+
</span>
|
|
233
|
+
{filterCount > 0 && (
|
|
234
|
+
<Button
|
|
235
|
+
icon={IconName.RemoveAllFilters}
|
|
236
|
+
className={classes.headerButton}
|
|
237
|
+
buttonContext={ButtonContext.None}
|
|
238
|
+
onButtonClicked={clearAllFilters}
|
|
239
|
+
dataTestId="filters-clear-all"
|
|
240
|
+
/>
|
|
241
|
+
)}
|
|
242
|
+
</>
|
|
243
|
+
)}
|
|
244
|
+
</div>
|
|
245
|
+
{isExpanded &&
|
|
246
|
+
options?.map((filter: FilterType<T>, index: number) =>
|
|
247
|
+
renderFilter(filter, index),
|
|
248
|
+
)}
|
|
164
249
|
</div>
|
|
165
250
|
);
|
|
166
251
|
};
|
|
252
|
+
|
|
253
|
+
// `forwardRef` does not preserve the generic `T`, so the wrapped component is
|
|
254
|
+
// re-typed to keep the generic call signature while accepting a `ref`.
|
|
255
|
+
export const Filters = forwardRef(FiltersComponent) as <T extends Data>(
|
|
256
|
+
props: PropsWithChildren<FiltersProps<T>> &
|
|
257
|
+
React.RefAttributes<FiltersHandle>,
|
|
258
|
+
) => JSX.Element | null;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import classes from '../../../.storybook/static/css/icons.module.scss';
|
|
4
|
-
import { SvgElement, SvgElementProps } from '../VisualElements/SvgElement';
|
|
4
|
+
import { SvgElement, type SvgElementProps } from '../VisualElements/SvgElement';
|
|
5
5
|
import { Icons } from './Icons';
|
|
6
6
|
import { IconName } from './Icons.models';
|
|
7
7
|
|
|
@@ -410,6 +410,15 @@ const RemoveFilterIcon: React.FC<SvgElementProps> = (props) => (
|
|
|
410
410
|
</SvgElement>
|
|
411
411
|
);
|
|
412
412
|
|
|
413
|
+
const RemoveAllFiltersIcon: React.FC<SvgElementProps> = (props) => (
|
|
414
|
+
<SvgElement {...props}>
|
|
415
|
+
<path
|
|
416
|
+
{...DEFAULT_PATH_PROPS}
|
|
417
|
+
d="M11.6,10.9h20.7l-8.2,8.7v9.9l-4.7,3.7v-13.4s-7.8-8.9-7.8-8.9ZM33.3,24.2l4.4,4.4-4.4-4.4ZM33.3,24.2l-4.4-4.4,4.4,4.4-4.4,4.4,4.4-4.4ZM33.3,24.2l4.4-4.4-4.4,4.4ZM21,6.5H2.1l12.8,15.2v10.4"
|
|
418
|
+
/>
|
|
419
|
+
</SvgElement>
|
|
420
|
+
);
|
|
421
|
+
|
|
413
422
|
const ReplaceIcon: React.FC<SvgElementProps> = (props) => (
|
|
414
423
|
<SvgElement {...props}>
|
|
415
424
|
<path
|
|
@@ -610,6 +619,7 @@ export const Icons: React.FC<IconsProps> = ({ icon, className, ...props }) => {
|
|
|
610
619
|
[IconName.QuickEdit]: QuickEditIcon,
|
|
611
620
|
[IconName.QuickEditStation]: QuickEditStationIcon,
|
|
612
621
|
[IconName.RemoveFilter]: RemoveFilterIcon,
|
|
622
|
+
[IconName.RemoveAllFilters]: RemoveAllFiltersIcon,
|
|
613
623
|
[IconName.Replace]: ReplaceIcon,
|
|
614
624
|
[IconName.Retry]: RetryIcon,
|
|
615
625
|
[IconName.Save]: SaveIcon,
|
package/src/components/index.ts
CHANGED