@drivenets/design-system 0.19.0 → 0.20.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/CHANGELOG.md +28 -0
- package/dist/index.cjs +12409 -10548
- package/dist/index.d.cts +678 -312
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +679 -313
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12404 -10550
- package/dist/index.js.map +1 -1
- package/dist/index.min.css +1 -1
- package/package.json +29 -29
- package/src/components/ds-checkbox/ds-checkbox.figma.ts +3 -0
- package/src/components/ds-checkbox/ds-checkbox.module.scss +102 -20
- package/src/components/ds-checkbox/ds-checkbox.tsx +30 -2
- package/src/components/ds-checkbox/ds-checkbox.types.ts +10 -0
- package/src/components/ds-code-input/collapsed-code-field/collapsed-code-field.module.scss +169 -0
- package/src/components/ds-code-input/collapsed-code-field/collapsed-code-field.tsx +92 -0
- package/src/components/ds-code-input/collapsed-code-field/index.ts +1 -0
- package/src/components/ds-code-input/ds-code-input-panel/ds-code-input-panel.module.scss +110 -0
- package/src/components/ds-code-input/ds-code-input-panel/ds-code-input-panel.tsx +61 -0
- package/src/components/ds-code-input/ds-code-input-panel/index.ts +1 -0
- package/src/components/ds-code-input/ds-code-input.module.scss +25 -0
- package/src/components/ds-code-input/ds-code-input.tsx +401 -0
- package/src/components/ds-code-input/ds-code-input.types.ts +166 -0
- package/src/components/ds-code-input/ds-code-input.utils.ts +94 -0
- package/src/components/ds-code-input/ds-code-input.utils.unit.test.ts +166 -0
- package/src/components/ds-code-input/index.ts +2 -0
- package/src/components/ds-code-input/use-collapsed-viewport.ts +289 -0
- package/src/components/ds-code-input/use-editor-host.ts +87 -0
- package/src/components/ds-filters-bar/components/ds-filters-bar-builder/ds-filters-bar-builder.ts +11 -0
- package/src/components/ds-filters-bar/components/ds-filters-bar-builder/ds-filters-bar-builder.types.ts +41 -0
- package/src/components/ds-filters-bar/components/ds-filters-bar-builder/index.ts +1 -0
- package/src/components/ds-filters-bar/components/ds-filters-bar-clear-all.ts +11 -0
- package/src/components/ds-filters-bar/components/ds-filters-bar-conditions/ds-filters-bar-conditions.ts +11 -0
- package/src/components/ds-filters-bar/components/ds-filters-bar-conditions/ds-filters-bar-conditions.types.ts +30 -0
- package/src/components/ds-filters-bar/components/ds-filters-bar-conditions/index.ts +1 -0
- package/src/components/ds-filters-bar/components/ds-filters-bar-pinned.ts +31 -0
- package/src/components/ds-filters-bar/components/ds-filters-bar-query/ds-filters-bar-query.ts +11 -0
- package/src/components/ds-filters-bar/components/ds-filters-bar-query/ds-filters-bar-query.types.ts +22 -0
- package/src/components/ds-filters-bar/components/ds-filters-bar-query/index.ts +1 -0
- package/src/components/ds-filters-bar/components/ds-filters-bar-saved-filters.ts +19 -0
- package/src/components/ds-filters-bar/components/ds-filters-bar-search.ts +11 -0
- package/src/components/ds-filters-bar/components/ds-filters-bar-summary.ts +11 -0
- package/src/components/ds-filters-bar/components/ds-filters-bar-toolbar.ts +11 -0
- package/src/components/ds-filters-bar/components/ds-filters-bar-view-switch.ts +11 -0
- package/src/components/ds-filters-bar/components/ds-filters-bar-view.ts +11 -0
- package/src/components/ds-filters-bar/components/index.ts +11 -0
- package/src/components/ds-filters-bar/ds-filters-bar.context.ts +69 -0
- package/src/components/ds-filters-bar/ds-filters-bar.tsx +120 -0
- package/src/components/ds-filters-bar/ds-filters-bar.types.ts +440 -0
- package/src/components/ds-filters-bar/ds-filters-bar.unit.test.ts +216 -0
- package/src/components/ds-filters-bar/ds-filters-bar.utils.ts +141 -0
- package/src/components/ds-filters-bar/index.ts +1 -0
- package/src/components/ds-form-control/ds-form-control.module.scss +18 -0
- package/src/components/ds-form-control/ds-form-control.tsx +43 -9
- package/src/components/ds-form-control/ds-form-control.types.ts +2 -1
- package/src/components/ds-icon/custom-icons/index.ts +2 -0
- package/src/components/ds-icon/custom-icons/special-adv-filters.tsx +28 -0
- package/src/components/ds-pin-toggle/ds-pin-toggle.figma.ts +27 -0
- package/src/components/ds-pin-toggle/ds-pin-toggle.module.scss +41 -0
- package/src/components/ds-pin-toggle/ds-pin-toggle.tsx +43 -0
- package/src/components/ds-pin-toggle/ds-pin-toggle.types.ts +29 -0
- package/src/components/ds-pin-toggle/index.ts +2 -0
- package/src/components/ds-popover/components/popover-trigger/index.ts +1 -0
- package/src/components/ds-popover/components/popover-trigger/popover-trigger.tsx +15 -0
- package/src/components/ds-popover/ds-popover.context.ts +18 -0
- package/src/components/ds-popover/ds-popover.hover-intent.ts +65 -0
- package/src/components/ds-popover/ds-popover.tsx +163 -41
- package/src/components/ds-popover/ds-popover.types.ts +59 -1
- package/src/components/ds-popover/ds-popover.utils.ts +60 -0
- package/src/components/ds-popover/ds-popover.utils.unit.test.ts +25 -0
- package/src/components/ds-saved-filters/components/ds-saved-filters-delete-confirm.tsx +53 -0
- package/src/components/ds-saved-filters/components/ds-saved-filters-name-entry.tsx +64 -0
- package/src/components/ds-saved-filters/components/ds-saved-filters-name-modal.tsx +50 -0
- package/src/components/ds-saved-filters/components/ds-saved-filters-row/ds-saved-filters-row.module.scss +68 -0
- package/src/components/ds-saved-filters/components/ds-saved-filters-row/ds-saved-filters-row.tsx +83 -0
- package/src/components/ds-saved-filters/components/ds-saved-filters-row/index.ts +1 -0
- package/src/components/ds-saved-filters/components/ds-saved-filters-save.tsx +164 -0
- package/src/components/ds-saved-filters/components/ds-saved-filters-trigger/ds-saved-filters-trigger.module.scss +21 -0
- package/src/components/ds-saved-filters/components/ds-saved-filters-trigger/ds-saved-filters-trigger.tsx +237 -0
- package/src/components/ds-saved-filters/components/ds-saved-filters-trigger/index.ts +1 -0
- package/src/components/ds-saved-filters/components/index.ts +2 -0
- package/src/components/ds-saved-filters/ds-saved-filters.ts +6 -0
- package/src/components/ds-saved-filters/ds-saved-filters.types.ts +106 -0
- package/src/components/ds-saved-filters/ds-saved-filters.utils.ts +35 -0
- package/src/components/ds-saved-filters/hooks/index.ts +1 -0
- package/src/components/ds-saved-filters/hooks/use-picker-outside-dismiss.ts +42 -0
- package/src/components/ds-saved-filters/index.ts +2 -0
- package/src/components/ds-segment-group/ds-segment-group.module.scss +65 -37
- package/src/components/ds-segment-group/ds-segment-group.tsx +17 -5
- package/src/components/ds-segment-group/ds-segment-group.types.ts +20 -5
- package/src/components/ds-segment-group/figma/ds-segment-group-v2-item.figma.ts +109 -0
- package/src/components/ds-segment-group/figma/ds-segment-group-v2.figma.ts +31 -0
- package/src/components/ds-tag/ds-tag.figma.ts +23 -3
- package/src/components/ds-tag/ds-tag.module.scss +71 -7
- package/src/components/ds-tag/ds-tag.tsx +115 -14
- package/src/components/ds-tag/ds-tag.types.ts +70 -3
- package/src/components/ds-tag/ds-tag.unit.test.ts +23 -4
- package/src/components/ds-tag/index.ts +2 -2
- package/src/components/ds-text-input/ds-input-field-v02.figma.ts +2 -0
- package/src/components/ds-toggle/ds-toggle.tsx +19 -15
- package/src/components/ds-toggle/ds-toggle.types.ts +6 -0
- package/src/components/ds-toggle-filter-data/ds-toggle-filter-data.module.scss +69 -0
- package/src/components/ds-toggle-filter-data/ds-toggle-filter-data.tsx +55 -0
- package/src/components/ds-toggle-filter-data/ds-toggle-filter-data.types.ts +43 -0
- package/src/components/ds-toggle-filter-data/index.ts +1 -0
- package/src/components/ds-tooltip/ds-tooltip.module.scss +8 -0
- package/src/components/ds-tooltip/ds-tooltip.tsx +1 -1
- package/src/components/ds-tree/ds-tree.tsx +10 -10
- package/src/components/ds-tree/ds-tree.types.ts +40 -7
- package/src/index.ts +2 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
import type {
|
|
3
|
+
DsFilterCondition,
|
|
4
|
+
DsFilterField,
|
|
5
|
+
DsFilterPin,
|
|
6
|
+
DsFiltersBarLocale,
|
|
7
|
+
DsFiltersBarView,
|
|
8
|
+
} from './ds-filters-bar.types';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The contract every part builds on. View parts read the filter document from here and write it
|
|
12
|
+
* back through these actions only, so all views stay one source of truth.
|
|
13
|
+
*/
|
|
14
|
+
export interface DsFiltersBarContextValue {
|
|
15
|
+
fields: ReadonlyArray<DsFilterField>;
|
|
16
|
+
conditions: ReadonlyArray<DsFilterCondition>;
|
|
17
|
+
/**
|
|
18
|
+
* Edited advanced query, or `null` while the conditions are the source
|
|
19
|
+
*/
|
|
20
|
+
query: string | null;
|
|
21
|
+
/**
|
|
22
|
+
* What the advanced view shows: the edited query, or the consumer's rendering of the conditions
|
|
23
|
+
*/
|
|
24
|
+
queryText: string;
|
|
25
|
+
pins: ReadonlyArray<DsFilterPin>;
|
|
26
|
+
/**
|
|
27
|
+
* No conditions and no edited query
|
|
28
|
+
*/
|
|
29
|
+
isEmpty: boolean;
|
|
30
|
+
lockedViews: ReadonlyArray<DsFiltersBarView>;
|
|
31
|
+
expanded: boolean;
|
|
32
|
+
view: DsFiltersBarView;
|
|
33
|
+
/**
|
|
34
|
+
* Id of the expanded toolbar, referenced by the disclosure button's `aria-controls`
|
|
35
|
+
*/
|
|
36
|
+
toolbarId: string;
|
|
37
|
+
locale: Required<DsFiltersBarLocale>;
|
|
38
|
+
setConditions: (conditions: ReadonlyArray<DsFilterCondition>) => void;
|
|
39
|
+
addCondition: (condition: DsFilterCondition) => void;
|
|
40
|
+
/**
|
|
41
|
+
* Replaces the condition with the same `id`
|
|
42
|
+
*/
|
|
43
|
+
updateCondition: (condition: DsFilterCondition) => void;
|
|
44
|
+
removeCondition: (id: string) => void;
|
|
45
|
+
/**
|
|
46
|
+
* Setting text makes the query the source; blank text or `null` hands control back to the
|
|
47
|
+
* conditions.
|
|
48
|
+
*/
|
|
49
|
+
setQuery: (query: string | null) => void;
|
|
50
|
+
setPins: (pins: ReadonlyArray<DsFilterPin>) => void;
|
|
51
|
+
/**
|
|
52
|
+
* Empties the conditions and drops the edited query. Pins stay.
|
|
53
|
+
*/
|
|
54
|
+
clear: () => void;
|
|
55
|
+
setExpanded: (expanded: boolean) => void;
|
|
56
|
+
setView: (view: DsFiltersBarView) => void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const DsFiltersBarContext = createContext<DsFiltersBarContextValue | null>(null);
|
|
60
|
+
|
|
61
|
+
export const useDsFiltersBarContext = () => {
|
|
62
|
+
const context = useContext(DsFiltersBarContext);
|
|
63
|
+
|
|
64
|
+
if (!context) {
|
|
65
|
+
throw new Error('DsFiltersBar compound components must be used within DsFiltersBar.Root');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return context;
|
|
69
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { useId } from 'react';
|
|
2
|
+
import { useControlled } from '../../utils/use-controlled';
|
|
3
|
+
import {
|
|
4
|
+
Builder,
|
|
5
|
+
ClearAll,
|
|
6
|
+
Conditions,
|
|
7
|
+
Pinned,
|
|
8
|
+
PinnedGroup,
|
|
9
|
+
PinnedToggle,
|
|
10
|
+
Query,
|
|
11
|
+
SavedFilters,
|
|
12
|
+
SaveFilter,
|
|
13
|
+
Search,
|
|
14
|
+
Summary,
|
|
15
|
+
Toolbar,
|
|
16
|
+
View,
|
|
17
|
+
ViewSwitch,
|
|
18
|
+
} from './components';
|
|
19
|
+
import { DsFiltersBarContext } from './ds-filters-bar.context';
|
|
20
|
+
import {
|
|
21
|
+
defaultDsFiltersBarLocale,
|
|
22
|
+
type DsFilterCondition,
|
|
23
|
+
type DsFilterPin,
|
|
24
|
+
type DsFiltersBarRootProps,
|
|
25
|
+
type DsFiltersBarView,
|
|
26
|
+
} from './ds-filters-bar.types';
|
|
27
|
+
import {
|
|
28
|
+
appendCondition,
|
|
29
|
+
lockedViewsFor,
|
|
30
|
+
normalizeQuery,
|
|
31
|
+
removeConditionById,
|
|
32
|
+
replaceCondition,
|
|
33
|
+
} from './ds-filters-bar.utils';
|
|
34
|
+
|
|
35
|
+
const EMPTY_FIELDS = Object.freeze([]);
|
|
36
|
+
const EMPTY_CONDITIONS: ReadonlyArray<DsFilterCondition> = Object.freeze([]);
|
|
37
|
+
const EMPTY_PINS: ReadonlyArray<DsFilterPin> = Object.freeze([]);
|
|
38
|
+
const formatNothing = () => '';
|
|
39
|
+
|
|
40
|
+
// TODO: render. Root only provides the context and every part returns null.
|
|
41
|
+
const Root = ({
|
|
42
|
+
fields = EMPTY_FIELDS,
|
|
43
|
+
conditions: conditionsProp,
|
|
44
|
+
defaultConditions = EMPTY_CONDITIONS,
|
|
45
|
+
query: queryProp,
|
|
46
|
+
defaultQuery = null,
|
|
47
|
+
pins: pinsProp,
|
|
48
|
+
defaultPins = EMPTY_PINS,
|
|
49
|
+
expanded: expandedProp,
|
|
50
|
+
defaultExpanded = false,
|
|
51
|
+
view: viewProp,
|
|
52
|
+
defaultView = 'filters',
|
|
53
|
+
formatQuery = formatNothing,
|
|
54
|
+
locale,
|
|
55
|
+
children,
|
|
56
|
+
onConditionsChange,
|
|
57
|
+
onQueryChange,
|
|
58
|
+
onPinsChange,
|
|
59
|
+
onExpandedChange,
|
|
60
|
+
onViewChange,
|
|
61
|
+
}: DsFiltersBarRootProps) => {
|
|
62
|
+
const [conditions, setConditions] = useControlled(conditionsProp, onConditionsChange, defaultConditions);
|
|
63
|
+
const [query, setQuery] = useControlled<string | null>(queryProp, onQueryChange, defaultQuery);
|
|
64
|
+
const [pins, setPins] = useControlled(pinsProp, onPinsChange, defaultPins);
|
|
65
|
+
const [expanded, setExpanded] = useControlled(expandedProp, onExpandedChange, defaultExpanded);
|
|
66
|
+
const [view, setView] = useControlled<DsFiltersBarView>(viewProp, onViewChange, defaultView);
|
|
67
|
+
const toolbarId = useId();
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<DsFiltersBarContext.Provider
|
|
71
|
+
value={{
|
|
72
|
+
fields,
|
|
73
|
+
conditions,
|
|
74
|
+
query,
|
|
75
|
+
queryText: query ?? formatQuery(conditions, fields),
|
|
76
|
+
pins,
|
|
77
|
+
isEmpty: query === null && conditions.length === 0,
|
|
78
|
+
lockedViews: lockedViewsFor(query),
|
|
79
|
+
expanded,
|
|
80
|
+
view,
|
|
81
|
+
toolbarId,
|
|
82
|
+
locale: { ...defaultDsFiltersBarLocale, ...locale },
|
|
83
|
+
setConditions,
|
|
84
|
+
addCondition: (condition) => setConditions(appendCondition(conditions, condition)),
|
|
85
|
+
updateCondition: (condition) => setConditions(replaceCondition(conditions, condition)),
|
|
86
|
+
removeCondition: (id) => setConditions(removeConditionById(conditions, id)),
|
|
87
|
+
setQuery: (next) => setQuery(normalizeQuery(next)),
|
|
88
|
+
setPins,
|
|
89
|
+
clear: () => {
|
|
90
|
+
setConditions(EMPTY_CONDITIONS);
|
|
91
|
+
setQuery(null);
|
|
92
|
+
},
|
|
93
|
+
setExpanded,
|
|
94
|
+
setView,
|
|
95
|
+
}}
|
|
96
|
+
>
|
|
97
|
+
{children}
|
|
98
|
+
</DsFiltersBarContext.Provider>
|
|
99
|
+
);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
Root.displayName = 'DsFiltersBar.Root';
|
|
103
|
+
|
|
104
|
+
export const DsFiltersBar = {
|
|
105
|
+
Root,
|
|
106
|
+
Summary,
|
|
107
|
+
Toolbar,
|
|
108
|
+
SavedFilters,
|
|
109
|
+
SaveFilter,
|
|
110
|
+
Search,
|
|
111
|
+
ViewSwitch,
|
|
112
|
+
View,
|
|
113
|
+
Conditions,
|
|
114
|
+
Builder,
|
|
115
|
+
Query,
|
|
116
|
+
ClearAll,
|
|
117
|
+
Pinned,
|
|
118
|
+
PinnedGroup,
|
|
119
|
+
PinnedToggle,
|
|
120
|
+
};
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
import type { CSSProperties, ReactNode, Ref } from 'react';
|
|
2
|
+
import type { DsSavedFiltersSaveProps, DsSavedFiltersTriggerProps } from '../ds-saved-filters';
|
|
3
|
+
|
|
4
|
+
export interface DsFilterOperator {
|
|
5
|
+
/**
|
|
6
|
+
* Stable id stored on the condition, for example `!=`
|
|
7
|
+
*/
|
|
8
|
+
value: string;
|
|
9
|
+
/**
|
|
10
|
+
* Words for the summary line and menus, for example `not equals`
|
|
11
|
+
*/
|
|
12
|
+
label: string;
|
|
13
|
+
/**
|
|
14
|
+
* Compact form for chips, for example `≠`. Falls back to `label`.
|
|
15
|
+
*/
|
|
16
|
+
symbol?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface DsFilterOption {
|
|
20
|
+
value: string;
|
|
21
|
+
label: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface DsFilterFieldBase {
|
|
25
|
+
id: string;
|
|
26
|
+
label: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Picked from a fixed list of options, possibly several at once
|
|
31
|
+
*/
|
|
32
|
+
export interface DsFilterEnumField extends DsFilterFieldBase {
|
|
33
|
+
type: 'enum';
|
|
34
|
+
operators: ReadonlyArray<DsFilterOperator>;
|
|
35
|
+
options: ReadonlyArray<DsFilterOption>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface DsFilterTextField extends DsFilterFieldBase {
|
|
39
|
+
type: 'text';
|
|
40
|
+
operators: ReadonlyArray<DsFilterOperator>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface DsFilterNumberField extends DsFilterFieldBase {
|
|
44
|
+
type: 'number';
|
|
45
|
+
operators: ReadonlyArray<DsFilterOperator>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Filtered by a named preset such as "Today", or by a range of ISO 8601 dates
|
|
50
|
+
*/
|
|
51
|
+
export interface DsFilterDateField extends DsFilterFieldBase {
|
|
52
|
+
type: 'date';
|
|
53
|
+
operators: ReadonlyArray<DsFilterOperator>;
|
|
54
|
+
/**
|
|
55
|
+
* @default []
|
|
56
|
+
*/
|
|
57
|
+
presets?: ReadonlyArray<DsFilterOption>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* An object with named parts, for example Input › Name / Vendor / Version. A condition on it names
|
|
62
|
+
* one subfield.
|
|
63
|
+
*/
|
|
64
|
+
export interface DsFilterCompoundField extends DsFilterFieldBase {
|
|
65
|
+
type: 'compound';
|
|
66
|
+
subfields: ReadonlyArray<DsFilterScalarField>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export type DsFilterScalarField =
|
|
70
|
+
| DsFilterEnumField
|
|
71
|
+
| DsFilterTextField
|
|
72
|
+
| DsFilterNumberField
|
|
73
|
+
| DsFilterDateField;
|
|
74
|
+
export type DsFilterField = DsFilterScalarField | DsFilterCompoundField;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Inclusive range. `null` leaves that side open.
|
|
78
|
+
*/
|
|
79
|
+
export interface DsFilterRange<T> {
|
|
80
|
+
from: T | null;
|
|
81
|
+
to: T | null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The value shape depends on the field type:
|
|
86
|
+
* - enum: option values, always an array, even for one
|
|
87
|
+
* - text: a string
|
|
88
|
+
* - number: a number, or a range
|
|
89
|
+
* - date: a preset value, or a range of ISO 8601 dates
|
|
90
|
+
*/
|
|
91
|
+
export type DsFilterValue =
|
|
92
|
+
| ReadonlyArray<string>
|
|
93
|
+
| string
|
|
94
|
+
| number
|
|
95
|
+
| DsFilterRange<number>
|
|
96
|
+
| DsFilterRange<string>;
|
|
97
|
+
|
|
98
|
+
export interface DsFilterSearchCondition {
|
|
99
|
+
kind: 'search';
|
|
100
|
+
id: string;
|
|
101
|
+
text: string;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface DsFilterFieldCondition {
|
|
105
|
+
kind: 'field';
|
|
106
|
+
id: string;
|
|
107
|
+
/**
|
|
108
|
+
* `DsFilterField.id`
|
|
109
|
+
*/
|
|
110
|
+
field: string;
|
|
111
|
+
/**
|
|
112
|
+
* Subfield id. Required when `field` is a compound field, absent otherwise.
|
|
113
|
+
*/
|
|
114
|
+
subfield?: string;
|
|
115
|
+
/**
|
|
116
|
+
* `DsFilterOperator.value`
|
|
117
|
+
*/
|
|
118
|
+
operator: string;
|
|
119
|
+
value: DsFilterValue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* One **Filter condition**: produced by any view, rendered by any view
|
|
124
|
+
*/
|
|
125
|
+
export type DsFilterCondition = DsFilterSearchCondition | DsFilterFieldCondition;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* A field option the user pinned for quick access in the pinned row. A user preference, not part
|
|
129
|
+
* of the filter document: loading a saved filter or clearing leaves pins alone.
|
|
130
|
+
*/
|
|
131
|
+
export interface DsFilterPin {
|
|
132
|
+
field: string;
|
|
133
|
+
value: string;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export const filtersBarViews = ['filters', 'builder', 'advanced'] as const;
|
|
137
|
+
export type DsFiltersBarView = (typeof filtersBarViews)[number];
|
|
138
|
+
|
|
139
|
+
export interface DsFiltersBarLocale {
|
|
140
|
+
/**
|
|
141
|
+
* Accessible name of the region that holds the bar
|
|
142
|
+
*/
|
|
143
|
+
label?: string;
|
|
144
|
+
/**
|
|
145
|
+
* Accessible name of the disclosure button while collapsed
|
|
146
|
+
*/
|
|
147
|
+
expand?: string;
|
|
148
|
+
/**
|
|
149
|
+
* Accessible name of the disclosure button while expanded
|
|
150
|
+
*/
|
|
151
|
+
collapse?: string;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export const defaultDsFiltersBarLocale: Required<DsFiltersBarLocale> = Object.freeze({
|
|
155
|
+
label: 'Filters',
|
|
156
|
+
expand: 'Show filters',
|
|
157
|
+
collapse: 'Hide filters',
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
export interface DsFiltersBarRootProps {
|
|
161
|
+
/**
|
|
162
|
+
* What can be filtered. Omit for a search-only bar.
|
|
163
|
+
* @default []
|
|
164
|
+
*/
|
|
165
|
+
fields?: ReadonlyArray<DsFilterField>;
|
|
166
|
+
/**
|
|
167
|
+
* Current conditions. Pair with `onConditionsChange`.
|
|
168
|
+
*/
|
|
169
|
+
conditions?: ReadonlyArray<DsFilterCondition>;
|
|
170
|
+
/**
|
|
171
|
+
* @default []
|
|
172
|
+
*/
|
|
173
|
+
defaultConditions?: ReadonlyArray<DsFilterCondition>;
|
|
174
|
+
/**
|
|
175
|
+
* Edited advanced query, or `null` while the conditions are the source. While set, it alone
|
|
176
|
+
* filters the data, the conditions are ignored, and the filters and builder views lock. The bar
|
|
177
|
+
* never parses it. Pair with `onQueryChange`.
|
|
178
|
+
*/
|
|
179
|
+
query?: string | null;
|
|
180
|
+
/**
|
|
181
|
+
* @default null
|
|
182
|
+
*/
|
|
183
|
+
defaultQuery?: string | null;
|
|
184
|
+
/**
|
|
185
|
+
* Pinned field options. Pair with `onPinsChange`.
|
|
186
|
+
*/
|
|
187
|
+
pins?: ReadonlyArray<DsFilterPin>;
|
|
188
|
+
/**
|
|
189
|
+
* @default []
|
|
190
|
+
*/
|
|
191
|
+
defaultPins?: ReadonlyArray<DsFilterPin>;
|
|
192
|
+
/**
|
|
193
|
+
* Whether the full toolbar is shown. Collapsed shows the one-line summary. Pair with
|
|
194
|
+
* `onExpandedChange`.
|
|
195
|
+
*/
|
|
196
|
+
expanded?: boolean;
|
|
197
|
+
/**
|
|
198
|
+
* @default false
|
|
199
|
+
*/
|
|
200
|
+
defaultExpanded?: boolean;
|
|
201
|
+
/**
|
|
202
|
+
* Active view. Pair with `onViewChange`.
|
|
203
|
+
*/
|
|
204
|
+
view?: DsFiltersBarView;
|
|
205
|
+
/**
|
|
206
|
+
* @default 'filters'
|
|
207
|
+
*/
|
|
208
|
+
defaultView?: DsFiltersBarView;
|
|
209
|
+
/**
|
|
210
|
+
* Renders the conditions as query text, shown by the advanced view while `query` is `null`. The
|
|
211
|
+
* query language belongs to the consumer.
|
|
212
|
+
* @default () => ''
|
|
213
|
+
*/
|
|
214
|
+
formatQuery?: (
|
|
215
|
+
conditions: ReadonlyArray<DsFilterCondition>,
|
|
216
|
+
fields: ReadonlyArray<DsFilterField>,
|
|
217
|
+
) => string;
|
|
218
|
+
locale?: DsFiltersBarLocale;
|
|
219
|
+
ref?: Ref<HTMLDivElement>;
|
|
220
|
+
className?: string;
|
|
221
|
+
style?: CSSProperties;
|
|
222
|
+
children: ReactNode;
|
|
223
|
+
onConditionsChange?: (conditions: ReadonlyArray<DsFilterCondition>) => void;
|
|
224
|
+
onQueryChange?: (query: string | null) => void;
|
|
225
|
+
onPinsChange?: (pins: ReadonlyArray<DsFilterPin>) => void;
|
|
226
|
+
onExpandedChange?: (expanded: boolean) => void;
|
|
227
|
+
onViewChange?: (view: DsFiltersBarView) => void;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface DsFiltersBarSummaryLocale {
|
|
231
|
+
/**
|
|
232
|
+
* Announced result count. Receives the count.
|
|
233
|
+
*/
|
|
234
|
+
resultCount?: (count: number) => string;
|
|
235
|
+
/**
|
|
236
|
+
* Label shown before `activeSavedFilterName`
|
|
237
|
+
*/
|
|
238
|
+
activeSavedFilter?: string;
|
|
239
|
+
/**
|
|
240
|
+
* Label and value shown while there are no conditions, as in `View: All`
|
|
241
|
+
*/
|
|
242
|
+
emptyLabel?: string;
|
|
243
|
+
emptyValue?: string;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export const defaultDsFiltersBarSummaryLocale: Required<DsFiltersBarSummaryLocale> = Object.freeze({
|
|
247
|
+
resultCount: (count: number) => `${String(count)} results`,
|
|
248
|
+
activeSavedFilter: 'Filter',
|
|
249
|
+
emptyLabel: 'View',
|
|
250
|
+
emptyValue: 'All',
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Collapsed row. Lists the conditions from the filter document; renders nothing while expanded.
|
|
255
|
+
*/
|
|
256
|
+
export interface DsFiltersBarSummaryProps {
|
|
257
|
+
/**
|
|
258
|
+
* Number of results the current filters produce. Omit to hide the trailing count.
|
|
259
|
+
*/
|
|
260
|
+
count?: number;
|
|
261
|
+
/**
|
|
262
|
+
* Name of the **Active saved filter**, shown before the conditions
|
|
263
|
+
*/
|
|
264
|
+
activeSavedFilterName?: string;
|
|
265
|
+
locale?: DsFiltersBarSummaryLocale;
|
|
266
|
+
className?: string;
|
|
267
|
+
style?: CSSProperties;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Expanded row. Renders nothing while collapsed.
|
|
272
|
+
*/
|
|
273
|
+
export interface DsFiltersBarToolbarProps {
|
|
274
|
+
className?: string;
|
|
275
|
+
style?: CSSProperties;
|
|
276
|
+
children: ReactNode;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Clearing the **Active saved filter** also clears the filter document before `onClear` runs.
|
|
281
|
+
*/
|
|
282
|
+
export type DsFiltersBarSavedFiltersProps = DsSavedFiltersTriggerProps;
|
|
283
|
+
|
|
284
|
+
export interface DsFiltersBarSaveFilterProps extends Omit<DsSavedFiltersSaveProps, 'disabled'> {
|
|
285
|
+
/**
|
|
286
|
+
* Defaults to disabled while the filter document is empty
|
|
287
|
+
*/
|
|
288
|
+
disabled?: boolean;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export interface DsFiltersBarSearchLocale {
|
|
292
|
+
label?: string;
|
|
293
|
+
placeholder?: string;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export const defaultDsFiltersBarSearchLocale: Required<DsFiltersBarSearchLocale> = Object.freeze({
|
|
297
|
+
label: 'Search',
|
|
298
|
+
placeholder: 'Type ‘/’ to search',
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Free-text input. Enter adds the trimmed text as a search condition and clears the input; `/`
|
|
303
|
+
* focuses it from anywhere outside an editable element.
|
|
304
|
+
*/
|
|
305
|
+
export interface DsFiltersBarSearchProps {
|
|
306
|
+
/**
|
|
307
|
+
* Pending text, before it becomes a condition. Pair with `onValueChange`.
|
|
308
|
+
*/
|
|
309
|
+
value?: string;
|
|
310
|
+
/**
|
|
311
|
+
* @default ''
|
|
312
|
+
*/
|
|
313
|
+
defaultValue?: string;
|
|
314
|
+
/**
|
|
315
|
+
* @default false
|
|
316
|
+
*/
|
|
317
|
+
disabled?: boolean;
|
|
318
|
+
locale?: DsFiltersBarSearchLocale;
|
|
319
|
+
ref?: Ref<HTMLInputElement>;
|
|
320
|
+
className?: string;
|
|
321
|
+
style?: CSSProperties;
|
|
322
|
+
onValueChange?: (value: string) => void;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export interface DsFiltersBarViewSwitchLocale {
|
|
326
|
+
label?: string;
|
|
327
|
+
/**
|
|
328
|
+
* Accessible names of the icon-only items
|
|
329
|
+
*/
|
|
330
|
+
views?: Partial<Record<DsFiltersBarView, string>>;
|
|
331
|
+
/**
|
|
332
|
+
* Tooltip on a view locked by an edited advanced query
|
|
333
|
+
*/
|
|
334
|
+
lockedView?: string;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export const defaultDsFiltersBarViewSwitchLocale = Object.freeze({
|
|
338
|
+
label: 'Filter view',
|
|
339
|
+
views: Object.freeze({
|
|
340
|
+
filters: 'Filters',
|
|
341
|
+
builder: 'Query builder',
|
|
342
|
+
advanced: 'Advanced query',
|
|
343
|
+
}),
|
|
344
|
+
lockedView: 'Clear the advanced query to switch views',
|
|
345
|
+
}) satisfies Required<DsFiltersBarViewSwitchLocale>;
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* While an edited advanced query is the source, the filters and builder views are locked.
|
|
349
|
+
*/
|
|
350
|
+
export interface DsFiltersBarViewSwitchProps {
|
|
351
|
+
locale?: DsFiltersBarViewSwitchLocale;
|
|
352
|
+
className?: string;
|
|
353
|
+
style?: CSSProperties;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export interface DsFiltersBarViewProps {
|
|
357
|
+
/**
|
|
358
|
+
* Children render only while this view is active
|
|
359
|
+
*/
|
|
360
|
+
value: DsFiltersBarView;
|
|
361
|
+
children: ReactNode;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
export interface DsFiltersBarClearAllLocale {
|
|
365
|
+
label?: string;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export const defaultDsFiltersBarClearAllLocale: Required<DsFiltersBarClearAllLocale> = Object.freeze({
|
|
369
|
+
label: 'Clear all',
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Empties the conditions and drops the advanced query. Renders nothing while the filter document
|
|
374
|
+
* is empty.
|
|
375
|
+
*/
|
|
376
|
+
export interface DsFiltersBarClearAllProps {
|
|
377
|
+
locale?: DsFiltersBarClearAllLocale;
|
|
378
|
+
ref?: Ref<HTMLButtonElement>;
|
|
379
|
+
className?: string;
|
|
380
|
+
style?: CSSProperties;
|
|
381
|
+
/**
|
|
382
|
+
* Called after the document is cleared, for example to drop the **Active saved filter**
|
|
383
|
+
*/
|
|
384
|
+
onClick?: () => void;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
export interface DsFiltersBarPinnedLocale {
|
|
388
|
+
label?: string;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
export const defaultDsFiltersBarPinnedLocale: Required<DsFiltersBarPinnedLocale> = Object.freeze({
|
|
392
|
+
label: 'Pinned',
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Quick-toggle row, shown in both collapsed and expanded states. Toggles narrow the results the
|
|
397
|
+
* conditions already produced; they never widen them.
|
|
398
|
+
*/
|
|
399
|
+
export interface DsFiltersBarPinnedProps {
|
|
400
|
+
locale?: DsFiltersBarPinnedLocale;
|
|
401
|
+
className?: string;
|
|
402
|
+
style?: CSSProperties;
|
|
403
|
+
/**
|
|
404
|
+
* `DsFiltersBar.PinnedGroup` elements
|
|
405
|
+
*/
|
|
406
|
+
children: ReactNode;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export interface DsFiltersBarPinnedGroupProps {
|
|
410
|
+
/**
|
|
411
|
+
* Category name, also the accessible name of the group
|
|
412
|
+
*/
|
|
413
|
+
label: string;
|
|
414
|
+
className?: string;
|
|
415
|
+
style?: CSSProperties;
|
|
416
|
+
/**
|
|
417
|
+
* `DsFiltersBar.PinnedToggle` elements
|
|
418
|
+
*/
|
|
419
|
+
children: ReactNode;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
export interface DsFiltersBarPinnedToggleProps {
|
|
423
|
+
label: string;
|
|
424
|
+
/**
|
|
425
|
+
* Matches within the results the conditions already produced
|
|
426
|
+
*/
|
|
427
|
+
count: number;
|
|
428
|
+
/**
|
|
429
|
+
* Controlled. Surfaced as `aria-pressed`.
|
|
430
|
+
*/
|
|
431
|
+
active: boolean;
|
|
432
|
+
/**
|
|
433
|
+
* Defaults to disabled when `count` is 0
|
|
434
|
+
*/
|
|
435
|
+
disabled?: boolean;
|
|
436
|
+
ref?: Ref<HTMLButtonElement>;
|
|
437
|
+
className?: string;
|
|
438
|
+
style?: CSSProperties;
|
|
439
|
+
onActiveChange?: (active: boolean) => void;
|
|
440
|
+
}
|