@akinon/akifilter 1.10.2-261002-0 → 1.11.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/README.md +48 -0
- package/dist/cjs/akifilter.d.ts +30 -0
- package/dist/cjs/akifilter.d.ts.map +1 -1
- package/dist/cjs/akifilter.js +38 -11
- package/dist/cjs/styles.css +4 -0
- package/dist/esm/akifilter.d.ts +30 -0
- package/dist/esm/akifilter.d.ts.map +1 -1
- package/dist/esm/akifilter.js +38 -11
- package/dist/esm/styles.css +4 -0
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -45,6 +45,54 @@
|
|
|
45
45
|
|
|
46
46
|
---
|
|
47
47
|
|
|
48
|
+
## Value Persistence (`persistValues`)
|
|
49
|
+
|
|
50
|
+
By default, field values and active filter buttons are written to local storage
|
|
51
|
+
and restored on the next mount. Set `persistValues={false}` when the filter has
|
|
52
|
+
to start from values the host supplies (for example filters loaded from an API):
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
<Akifilter
|
|
56
|
+
filterSchema={filterSchema}
|
|
57
|
+
storageNamespace="saved-filters"
|
|
58
|
+
persistValues={false}
|
|
59
|
+
defaultValues={savedFilters}
|
|
60
|
+
onValuesChange={setFilters}
|
|
61
|
+
/>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
- Values and button state are never read or written; the form starts from
|
|
65
|
+
schema defaults + `defaultValues`, and buttons start inactive.
|
|
66
|
+
- Values stored before the prop was set are ignored, not deleted.
|
|
67
|
+
- Visible-field (and per-section visibility) persistence is unaffected.
|
|
68
|
+
- Leaving the prop out keeps today's behaviour (`true`).
|
|
69
|
+
- `persistValues` and `defaultValues` are read on mount; changing them later
|
|
70
|
+
does not reset the form. When the values come from an API, render
|
|
71
|
+
`Akifilter` only after they have loaded. Turning `persistValues` off after
|
|
72
|
+
mount stops further writes but keeps what was already restored.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Footer
|
|
77
|
+
|
|
78
|
+
`footer` renders host content inside the filter card, below every field and
|
|
79
|
+
section. Pass a node, or a function that receives `{ values }` (the
|
|
80
|
+
`onValuesChange` shape, not debounced) to render conditionally. A falsy result
|
|
81
|
+
(`null`, `undefined`, `false`, `''`, `0`) renders nothing:
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
<Akifilter
|
|
85
|
+
filterSchema={filterSchema}
|
|
86
|
+
footer={({ values }) =>
|
|
87
|
+
Object.keys(values).length > 0 ? <Button>Save as rule</Button> : null
|
|
88
|
+
}
|
|
89
|
+
/>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The footer sits outside the form, so a button there never submits it.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
48
96
|
## Section Fields
|
|
49
97
|
|
|
50
98
|
Fields declared with `type: 'section'` render as collapsible panels below the
|
package/dist/cjs/akifilter.d.ts
CHANGED
|
@@ -4,6 +4,16 @@ import React from 'react';
|
|
|
4
4
|
import { type AppliedFilter } from './components/applied-filters';
|
|
5
5
|
import type { AkifilterActionsRef, AkifilterButton, AkifilterSchema } from './types';
|
|
6
6
|
type AkifilterFieldValues = FieldValues;
|
|
7
|
+
/**
|
|
8
|
+
* What a `footer` render function receives.
|
|
9
|
+
*/
|
|
10
|
+
export type AkifilterFooterContext<TFieldValues extends AkifilterFieldValues = AkifilterFieldValues> = {
|
|
11
|
+
/**
|
|
12
|
+
* Current filter values in the `onValuesChange` shape (normalised form values
|
|
13
|
+
* merged with active filter-button values), without the debounce.
|
|
14
|
+
*/
|
|
15
|
+
values: Partial<TFieldValues>;
|
|
16
|
+
};
|
|
7
17
|
export type AkifilterProps<TFieldValues extends AkifilterFieldValues = AkifilterFieldValues> = {
|
|
8
18
|
/**
|
|
9
19
|
* Declarative description of the filter fields.
|
|
@@ -13,6 +23,18 @@ export type AkifilterProps<TFieldValues extends AkifilterFieldValues = Akifilter
|
|
|
13
23
|
* Optional namespace for local storage persistence.
|
|
14
24
|
*/
|
|
15
25
|
storageNamespace?: string;
|
|
26
|
+
/**
|
|
27
|
+
* When false, field values and filter-button state are never read from or
|
|
28
|
+
* written to localStorage; the form starts from schema defaults +
|
|
29
|
+
* `defaultValues`. Use it when the filter must start from values supplied by
|
|
30
|
+
* the host (e.g. filters loaded from an API). Values stored before the prop
|
|
31
|
+
* was set are ignored, not deleted. Visible-field persistence is unaffected.
|
|
32
|
+
* Read on mount, like `defaultValues`: render the filter once the values are
|
|
33
|
+
* ready instead of passing them in later, and changing this prop afterwards
|
|
34
|
+
* does not clear state that was already restored.
|
|
35
|
+
* @default true
|
|
36
|
+
*/
|
|
37
|
+
persistValues?: boolean;
|
|
16
38
|
/**
|
|
17
39
|
* Default values supplied by the host application.
|
|
18
40
|
*/
|
|
@@ -101,6 +123,14 @@ export type AkifilterProps<TFieldValues extends AkifilterFieldValues = Akifilter
|
|
|
101
123
|
* function on every render re-notifies with an unchanged list.
|
|
102
124
|
*/
|
|
103
125
|
onSectionVisibleFieldsChange?: (sectionKey: string, keys: Array<Path<TFieldValues>>) => void;
|
|
126
|
+
/**
|
|
127
|
+
* Host content rendered inside the filter card, below every field and
|
|
128
|
+
* section (e.g. an action button). Pass a node, or a function that receives
|
|
129
|
+
* the current values to render conditionally. Rendered outside the form, so a
|
|
130
|
+
* button here never submits it. Nothing is rendered when it returns a
|
|
131
|
+
* falsy value (`null`, `undefined`, `false`, `''`, `0`).
|
|
132
|
+
*/
|
|
133
|
+
footer?: React.ReactNode | ((context: AkifilterFooterContext<TFieldValues>) => React.ReactNode);
|
|
104
134
|
};
|
|
105
135
|
export declare const Akifilter: {
|
|
106
136
|
<TFieldValues extends AkifilterFieldValues = FieldValues>(props: AkifilterProps<TFieldValues>): React.JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"akifilter.d.ts","sourceRoot":"","sources":["../../src/akifilter.tsx"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AAGtB,OAAO,EAIL,WAAW,EACX,IAAI,EAIL,MAAM,iBAAiB,CAAC;AAYzB,OAAO,KAAK,MAAM,OAAO,CAAC;AAc1B,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,8BAA8B,CAAC;AAgBtC,OAAO,KAAK,EACV,mBAAmB,EACnB,eAAe,EAEf,eAAe,EAChB,MAAM,SAAS,CAAC;AAYjB,KAAK,oBAAoB,GAAG,WAAW,CAAC;AAiLxC,MAAM,MAAM,cAAc,CACxB,YAAY,SAAS,oBAAoB,GAAG,oBAAoB,IAC9D;IACF;;OAEG;IACH,YAAY,CAAC,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;IAC7C;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACtC;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACzD;;OAEG;IACH,qBAAqB,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,IAAI,CAAC;IAClE;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,gBAAgB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAClD;;;OAGG;IACH,sBAAsB,CAAC,EAAE,aAAa,EAAE,CAAC;IACzC;;OAEG;IACH,sBAAsB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C;;;;;OAKG;IACH,aAAa,CAAC,EAAE,eAAe,EAAE,CAAC;IAClC;;OAEG;IACH,qBAAqB,CAAC,EAAE,CAAC,aAAa,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;IACnE;;;;;;;;;;OAUG;IACH,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC9D;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC9D;;;;;;;;;OASG;IACH,4BAA4B,CAAC,EAAE,CAC7B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAC5B,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"akifilter.d.ts","sourceRoot":"","sources":["../../src/akifilter.tsx"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AAGtB,OAAO,EAIL,WAAW,EACX,IAAI,EAIL,MAAM,iBAAiB,CAAC;AAYzB,OAAO,KAAK,MAAM,OAAO,CAAC;AAc1B,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,8BAA8B,CAAC;AAgBtC,OAAO,KAAK,EACV,mBAAmB,EACnB,eAAe,EAEf,eAAe,EAChB,MAAM,SAAS,CAAC;AAYjB,KAAK,oBAAoB,GAAG,WAAW,CAAC;AAiLxC;;GAEG;AACH,MAAM,MAAM,sBAAsB,CAChC,YAAY,SAAS,oBAAoB,GAAG,oBAAoB,IAC9D;IACF;;;OAGG;IACH,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,cAAc,CACxB,YAAY,SAAS,oBAAoB,GAAG,oBAAoB,IAC9D;IACF;;OAEG;IACH,YAAY,CAAC,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;IAC7C;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACtC;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACzD;;OAEG;IACH,qBAAqB,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,IAAI,CAAC;IAClE;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,gBAAgB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAClD;;;OAGG;IACH,sBAAsB,CAAC,EAAE,aAAa,EAAE,CAAC;IACzC;;OAEG;IACH,sBAAsB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C;;;;;OAKG;IACH,aAAa,CAAC,EAAE,eAAe,EAAE,CAAC;IAClC;;OAEG;IACH,qBAAqB,CAAC,EAAE,CAAC,aAAa,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;IACnE;;;;;;;;;;OAUG;IACH,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC9D;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC9D;;;;;;;;;OASG;IACH,4BAA4B,CAAC,EAAE,CAC7B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAC5B,IAAI,CAAC;IACV;;;;;;OAMG;IACH,MAAM,CAAC,EACH,KAAK,CAAC,SAAS,GACf,CAAC,CAAC,OAAO,EAAE,sBAAsB,CAAC,YAAY,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;CAC1E,CAAC;AAsgCF,eAAO,MAAM,SAAS;KACpB,YAAY,SAAS,oBAAoB,uBAElC,cAAc,CAAC,YAAY,CAAC;;CAoBpC,CAAC"}
|
package/dist/cjs/akifilter.js
CHANGED
|
@@ -134,7 +134,7 @@ const resolveClearedFieldValue = (field, defaultValue) => {
|
|
|
134
134
|
return undefined;
|
|
135
135
|
}
|
|
136
136
|
};
|
|
137
|
-
const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onValuesChange, onVisibleFieldsChange, onImportCsv, onImportXls, onClearAll, enableImportCsv, enableImportXls, filterActionsRef, externalAppliedFilters, onRemoveExternalFilter, filterButtons, onFilterButtonsChange, onSectionImportCsv, onSectionImportXls, onSectionVisibleFieldsChange }) => {
|
|
137
|
+
const AkifilterContent = ({ filterSchema, storageNamespace, persistValues: shouldPersistValues = true, defaultValues, onValuesChange, onVisibleFieldsChange, onImportCsv, onImportXls, onClearAll, enableImportCsv, enableImportXls, filterActionsRef, externalAppliedFilters, onRemoveExternalFilter, filterButtons, onFilterButtonsChange, onSectionImportCsv, onSectionImportXls, onSectionVisibleFieldsChange, footer }) => {
|
|
138
138
|
// Separate regular fields from section fields
|
|
139
139
|
const { regularFields, sectionFields } = react_1.default.useMemo(() => (0, schema_1.partitionSchema)(filterSchema), [filterSchema]);
|
|
140
140
|
const excludeSectionKeys = react_1.default.useMemo(() => (0, schema_1.deriveExcludeSectionKeys)(sectionFields), [sectionFields]);
|
|
@@ -148,15 +148,22 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
148
148
|
// Read against the *flattened* schema: `readStoredValues` drops keys that are
|
|
149
149
|
// not in the schema it is given, so passing only the top-level fields would
|
|
150
150
|
// silently discard every section field's persisted value on reload.
|
|
151
|
+
// With `persistValues={false}` storage is never read, so the form starts from
|
|
152
|
+
// `baseDefaultValues` alone.
|
|
151
153
|
const [persistedDefaults, setPersistedDefaults] = react_1.default.useState(() => {
|
|
152
154
|
var _a;
|
|
153
|
-
return
|
|
155
|
+
return shouldPersistValues
|
|
156
|
+
? (0, schema_1.normaliseValuesBySchema)(flattenedSchema, (_a = (0, storage_1.readStoredValues)(flattenedSchema, storageKey)) !== null && _a !== void 0 ? _a : undefined)
|
|
157
|
+
: {};
|
|
154
158
|
});
|
|
155
159
|
// Re-read from localStorage when storageKey changes
|
|
156
160
|
react_1.default.useEffect(() => {
|
|
157
161
|
var _a;
|
|
162
|
+
if (!shouldPersistValues) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
158
165
|
setPersistedDefaults((0, schema_1.normaliseValuesBySchema)(flattenedSchema, (_a = (0, storage_1.readStoredValues)(flattenedSchema, storageKey)) !== null && _a !== void 0 ? _a : undefined));
|
|
159
|
-
}, [flattenedSchema, storageKey]);
|
|
166
|
+
}, [flattenedSchema, storageKey, shouldPersistValues]);
|
|
160
167
|
const mergedDefaultValues = react_1.default.useMemo(() => (Object.assign(Object.assign({}, baseDefaultValues), persistedDefaults)), [baseDefaultValues, persistedDefaults]);
|
|
161
168
|
const formMethods = (0, akiform_1.useForm)({
|
|
162
169
|
defaultValues: mergedDefaultValues
|
|
@@ -165,12 +172,15 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
165
172
|
// --- Filter buttons (quick-filter toggles) ---------------------------------
|
|
166
173
|
// A button is identified by its `value`, which must be unique across the
|
|
167
174
|
// whole `filterButtons` array.
|
|
168
|
-
const [activeButtonValues, setActiveButtonValues] = react_1.default.useState(() => { var _a; return (_a = (0, storage_1.readStoredButtonValues)(storageKey)) !== null && _a !== void 0 ? _a : []; });
|
|
175
|
+
const [activeButtonValues, setActiveButtonValues] = react_1.default.useState(() => { var _a; return shouldPersistValues ? ((_a = (0, storage_1.readStoredButtonValues)(storageKey)) !== null && _a !== void 0 ? _a : []) : []; });
|
|
169
176
|
// Re-read persisted button state when the storage key changes.
|
|
170
177
|
react_1.default.useEffect(() => {
|
|
171
178
|
var _a;
|
|
179
|
+
if (!shouldPersistValues) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
172
182
|
setActiveButtonValues((_a = (0, storage_1.readStoredButtonValues)(storageKey)) !== null && _a !== void 0 ? _a : []);
|
|
173
|
-
}, [storageKey]);
|
|
183
|
+
}, [storageKey, shouldPersistValues]);
|
|
174
184
|
// Build the `{ key: value[] }` object contributed by the active buttons.
|
|
175
185
|
// Buttons that share a key are merged into an array (legacy behaviour).
|
|
176
186
|
const computeButtonValues = react_1.default.useCallback((values) => {
|
|
@@ -327,13 +337,16 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
327
337
|
const persistValues = react_1.default.useCallback((values, serialised) => {
|
|
328
338
|
const nextSerialised = serialised !== null && serialised !== void 0 ? serialised : JSON.stringify(values);
|
|
329
339
|
lastPersistedValuesRef.current = nextSerialised;
|
|
340
|
+
if (!shouldPersistValues) {
|
|
341
|
+
return nextSerialised;
|
|
342
|
+
}
|
|
330
343
|
if (Object.keys(values).length === 0) {
|
|
331
344
|
(0, storage_1.clearStoredValues)(storageKey);
|
|
332
345
|
return nextSerialised;
|
|
333
346
|
}
|
|
334
347
|
(0, storage_1.writeStoredValues)(storageKey, values);
|
|
335
348
|
return nextSerialised;
|
|
336
|
-
}, [storageKey]);
|
|
349
|
+
}, [storageKey, shouldPersistValues]);
|
|
337
350
|
// Emit the normalised form values merged with the active filter-button
|
|
338
351
|
// values. Buttons live outside the form state, so every emission point routes
|
|
339
352
|
// through here to keep the two slices combined in the payload.
|
|
@@ -405,10 +418,12 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
405
418
|
lastPersistedValuesRef.current = nextSerialised;
|
|
406
419
|
currentSerialisedValuesRef.current = nextSerialised;
|
|
407
420
|
// Update persistedDefaults to prevent stale mergedDefaultValues on re-render
|
|
408
|
-
|
|
421
|
+
if (shouldPersistValues) {
|
|
422
|
+
setPersistedDefaults(currParsed);
|
|
423
|
+
}
|
|
409
424
|
emitValues(currParsed);
|
|
410
425
|
}
|
|
411
|
-
}, [serialisedValues, emitValues, persistValues]);
|
|
426
|
+
}, [serialisedValues, emitValues, persistValues, shouldPersistValues]);
|
|
412
427
|
const handleClearAll = react_1.default.useCallback(() => {
|
|
413
428
|
const clearedDefaults = Object.assign({}, schemaDefaults);
|
|
414
429
|
flattenedSchema.forEach(field => {
|
|
@@ -521,7 +536,9 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
521
536
|
// before the state-update effect runs.
|
|
522
537
|
buttonValuesRef.current = computeButtonValues(nextValues);
|
|
523
538
|
setActiveButtonValues(nextValues);
|
|
524
|
-
(
|
|
539
|
+
if (shouldPersistValues) {
|
|
540
|
+
(0, storage_1.writeStoredButtonValues)(storageKey, nextValues);
|
|
541
|
+
}
|
|
525
542
|
const formValuesNow = (0, values_1.normaliseOutputValues)(flattenedSchema, formMethods.getValues());
|
|
526
543
|
hasEmittedValuesRef.current = true;
|
|
527
544
|
emitValues(formValuesNow);
|
|
@@ -530,6 +547,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
530
547
|
activeButtonValues,
|
|
531
548
|
computeButtonValues,
|
|
532
549
|
storageKey,
|
|
550
|
+
shouldPersistValues,
|
|
533
551
|
flattenedSchema,
|
|
534
552
|
formMethods,
|
|
535
553
|
emitValues,
|
|
@@ -589,7 +607,9 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
589
607
|
if (activeButtonValues.length > 0) {
|
|
590
608
|
buttonValuesRef.current = {};
|
|
591
609
|
setActiveButtonValues([]);
|
|
592
|
-
|
|
610
|
+
if (shouldPersistValues) {
|
|
611
|
+
(0, storage_1.clearStoredButtonValues)(storageKey);
|
|
612
|
+
}
|
|
593
613
|
onFilterButtonsChange === null || onFilterButtonsChange === void 0 ? void 0 : onFilterButtonsChange([]);
|
|
594
614
|
}
|
|
595
615
|
handleClearAll();
|
|
@@ -600,6 +620,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
600
620
|
onRemoveExternalFilter,
|
|
601
621
|
activeButtonValues,
|
|
602
622
|
storageKey,
|
|
623
|
+
shouldPersistValues,
|
|
603
624
|
onFilterButtonsChange
|
|
604
625
|
]);
|
|
605
626
|
const renderFieldComponent = (field) => {
|
|
@@ -640,6 +661,11 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
640
661
|
return (react_1.default.createElement(ui_typography_1.Text, { type: "secondary", className: "akinon-filter__unsupported" }, i18n_1.i18n.t('form.unsupportedField', { field: String(field.type) })));
|
|
641
662
|
}
|
|
642
663
|
};
|
|
664
|
+
const footerContent = typeof footer === 'function'
|
|
665
|
+
? footer({
|
|
666
|
+
values: Object.assign(Object.assign({}, normalisedValues), computeButtonValues(activeButtonValues))
|
|
667
|
+
})
|
|
668
|
+
: footer;
|
|
643
669
|
const renderFormField = (field) => {
|
|
644
670
|
return (react_1.default.createElement(FilterFormItem, { key: String(field.key), control: formMethods.control, name: field.key, tooltip: field.tooltip, help: field.help, labelDescription: field.labelDescription, required: Boolean(field.validation), className: "mb-0", valuePropName: field.type === constants_1.FIELD_TYPES.CHECKBOX ? 'checked' : undefined }, renderFieldComponent(field)));
|
|
645
671
|
};
|
|
@@ -658,7 +684,8 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
658
684
|
visibleFields.length === 0 && regularFields.length > 0 ? (react_1.default.createElement("div", { className: "akinon-filter__empty" }, i18n_1.i18n.t('form.noVisibleFields'))) : null),
|
|
659
685
|
sectionFields.length > 0 && (react_1.default.createElement("div", { className: "akinon-filter__section-fields" }, sectionFields.map(section => (react_1.default.createElement(section_fieldset_1.SectionFieldset, { key: String(section.key), section: section, storageKey: storageKey, renderFormField: renderFormField, onRemoveField: handleRemoveFilter, formValues: normalisedValues, onImportCsv: onSectionImportCsv &&
|
|
660
686
|
(file => onSectionImportCsv(String(section.key), file)), onImportXls: onSectionImportXls &&
|
|
661
|
-
(file => onSectionImportXls(String(section.key), file)), onVisibleFieldsChange: onSectionVisibleFieldsChange }))))))
|
|
687
|
+
(file => onSectionImportXls(String(section.key), file)), onVisibleFieldsChange: onSectionVisibleFieldsChange })))))),
|
|
688
|
+
footerContent ? (react_1.default.createElement("div", { className: "akinon-filter__footer", "data-testid": "akifilter-footer" }, footerContent)) : null),
|
|
662
689
|
react_1.default.createElement(visibility_modal_1.VisibilityModal, Object.assign({}, modalProps)))));
|
|
663
690
|
};
|
|
664
691
|
const AkifilterEmptyState = () => {
|
package/dist/cjs/styles.css
CHANGED
package/dist/esm/akifilter.d.ts
CHANGED
|
@@ -4,6 +4,16 @@ import React from 'react';
|
|
|
4
4
|
import { type AppliedFilter } from './components/applied-filters';
|
|
5
5
|
import type { AkifilterActionsRef, AkifilterButton, AkifilterSchema } from './types';
|
|
6
6
|
type AkifilterFieldValues = FieldValues;
|
|
7
|
+
/**
|
|
8
|
+
* What a `footer` render function receives.
|
|
9
|
+
*/
|
|
10
|
+
export type AkifilterFooterContext<TFieldValues extends AkifilterFieldValues = AkifilterFieldValues> = {
|
|
11
|
+
/**
|
|
12
|
+
* Current filter values in the `onValuesChange` shape (normalised form values
|
|
13
|
+
* merged with active filter-button values), without the debounce.
|
|
14
|
+
*/
|
|
15
|
+
values: Partial<TFieldValues>;
|
|
16
|
+
};
|
|
7
17
|
export type AkifilterProps<TFieldValues extends AkifilterFieldValues = AkifilterFieldValues> = {
|
|
8
18
|
/**
|
|
9
19
|
* Declarative description of the filter fields.
|
|
@@ -13,6 +23,18 @@ export type AkifilterProps<TFieldValues extends AkifilterFieldValues = Akifilter
|
|
|
13
23
|
* Optional namespace for local storage persistence.
|
|
14
24
|
*/
|
|
15
25
|
storageNamespace?: string;
|
|
26
|
+
/**
|
|
27
|
+
* When false, field values and filter-button state are never read from or
|
|
28
|
+
* written to localStorage; the form starts from schema defaults +
|
|
29
|
+
* `defaultValues`. Use it when the filter must start from values supplied by
|
|
30
|
+
* the host (e.g. filters loaded from an API). Values stored before the prop
|
|
31
|
+
* was set are ignored, not deleted. Visible-field persistence is unaffected.
|
|
32
|
+
* Read on mount, like `defaultValues`: render the filter once the values are
|
|
33
|
+
* ready instead of passing them in later, and changing this prop afterwards
|
|
34
|
+
* does not clear state that was already restored.
|
|
35
|
+
* @default true
|
|
36
|
+
*/
|
|
37
|
+
persistValues?: boolean;
|
|
16
38
|
/**
|
|
17
39
|
* Default values supplied by the host application.
|
|
18
40
|
*/
|
|
@@ -101,6 +123,14 @@ export type AkifilterProps<TFieldValues extends AkifilterFieldValues = Akifilter
|
|
|
101
123
|
* function on every render re-notifies with an unchanged list.
|
|
102
124
|
*/
|
|
103
125
|
onSectionVisibleFieldsChange?: (sectionKey: string, keys: Array<Path<TFieldValues>>) => void;
|
|
126
|
+
/**
|
|
127
|
+
* Host content rendered inside the filter card, below every field and
|
|
128
|
+
* section (e.g. an action button). Pass a node, or a function that receives
|
|
129
|
+
* the current values to render conditionally. Rendered outside the form, so a
|
|
130
|
+
* button here never submits it. Nothing is rendered when it returns a
|
|
131
|
+
* falsy value (`null`, `undefined`, `false`, `''`, `0`).
|
|
132
|
+
*/
|
|
133
|
+
footer?: React.ReactNode | ((context: AkifilterFooterContext<TFieldValues>) => React.ReactNode);
|
|
104
134
|
};
|
|
105
135
|
export declare const Akifilter: {
|
|
106
136
|
<TFieldValues extends AkifilterFieldValues = FieldValues>(props: AkifilterProps<TFieldValues>): React.JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"akifilter.d.ts","sourceRoot":"","sources":["../../src/akifilter.tsx"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AAGtB,OAAO,EAIL,WAAW,EACX,IAAI,EAIL,MAAM,iBAAiB,CAAC;AAYzB,OAAO,KAAK,MAAM,OAAO,CAAC;AAc1B,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,8BAA8B,CAAC;AAgBtC,OAAO,KAAK,EACV,mBAAmB,EACnB,eAAe,EAEf,eAAe,EAChB,MAAM,SAAS,CAAC;AAYjB,KAAK,oBAAoB,GAAG,WAAW,CAAC;AAiLxC,MAAM,MAAM,cAAc,CACxB,YAAY,SAAS,oBAAoB,GAAG,oBAAoB,IAC9D;IACF;;OAEG;IACH,YAAY,CAAC,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;IAC7C;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACtC;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACzD;;OAEG;IACH,qBAAqB,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,IAAI,CAAC;IAClE;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,gBAAgB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAClD;;;OAGG;IACH,sBAAsB,CAAC,EAAE,aAAa,EAAE,CAAC;IACzC;;OAEG;IACH,sBAAsB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C;;;;;OAKG;IACH,aAAa,CAAC,EAAE,eAAe,EAAE,CAAC;IAClC;;OAEG;IACH,qBAAqB,CAAC,EAAE,CAAC,aAAa,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;IACnE;;;;;;;;;;OAUG;IACH,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC9D;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC9D;;;;;;;;;OASG;IACH,4BAA4B,CAAC,EAAE,CAC7B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAC5B,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"akifilter.d.ts","sourceRoot":"","sources":["../../src/akifilter.tsx"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AAGtB,OAAO,EAIL,WAAW,EACX,IAAI,EAIL,MAAM,iBAAiB,CAAC;AAYzB,OAAO,KAAK,MAAM,OAAO,CAAC;AAc1B,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,8BAA8B,CAAC;AAgBtC,OAAO,KAAK,EACV,mBAAmB,EACnB,eAAe,EAEf,eAAe,EAChB,MAAM,SAAS,CAAC;AAYjB,KAAK,oBAAoB,GAAG,WAAW,CAAC;AAiLxC;;GAEG;AACH,MAAM,MAAM,sBAAsB,CAChC,YAAY,SAAS,oBAAoB,GAAG,oBAAoB,IAC9D;IACF;;;OAGG;IACH,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,cAAc,CACxB,YAAY,SAAS,oBAAoB,GAAG,oBAAoB,IAC9D;IACF;;OAEG;IACH,YAAY,CAAC,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;IAC7C;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACtC;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACzD;;OAEG;IACH,qBAAqB,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,IAAI,CAAC;IAClE;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,gBAAgB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAClD;;;OAGG;IACH,sBAAsB,CAAC,EAAE,aAAa,EAAE,CAAC;IACzC;;OAEG;IACH,sBAAsB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C;;;;;OAKG;IACH,aAAa,CAAC,EAAE,eAAe,EAAE,CAAC;IAClC;;OAEG;IACH,qBAAqB,CAAC,EAAE,CAAC,aAAa,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;IACnE;;;;;;;;;;OAUG;IACH,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC9D;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC9D;;;;;;;;;OASG;IACH,4BAA4B,CAAC,EAAE,CAC7B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAC5B,IAAI,CAAC;IACV;;;;;;OAMG;IACH,MAAM,CAAC,EACH,KAAK,CAAC,SAAS,GACf,CAAC,CAAC,OAAO,EAAE,sBAAsB,CAAC,YAAY,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;CAC1E,CAAC;AAsgCF,eAAO,MAAM,SAAS;KACpB,YAAY,SAAS,oBAAoB,uBAElC,cAAc,CAAC,YAAY,CAAC;;CAoBpC,CAAC"}
|
package/dist/esm/akifilter.js
CHANGED
|
@@ -131,7 +131,7 @@ const resolveClearedFieldValue = (field, defaultValue) => {
|
|
|
131
131
|
return undefined;
|
|
132
132
|
}
|
|
133
133
|
};
|
|
134
|
-
const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onValuesChange, onVisibleFieldsChange, onImportCsv, onImportXls, onClearAll, enableImportCsv, enableImportXls, filterActionsRef, externalAppliedFilters, onRemoveExternalFilter, filterButtons, onFilterButtonsChange, onSectionImportCsv, onSectionImportXls, onSectionVisibleFieldsChange }) => {
|
|
134
|
+
const AkifilterContent = ({ filterSchema, storageNamespace, persistValues: shouldPersistValues = true, defaultValues, onValuesChange, onVisibleFieldsChange, onImportCsv, onImportXls, onClearAll, enableImportCsv, enableImportXls, filterActionsRef, externalAppliedFilters, onRemoveExternalFilter, filterButtons, onFilterButtonsChange, onSectionImportCsv, onSectionImportXls, onSectionVisibleFieldsChange, footer }) => {
|
|
135
135
|
// Separate regular fields from section fields
|
|
136
136
|
const { regularFields, sectionFields } = React.useMemo(() => partitionSchema(filterSchema), [filterSchema]);
|
|
137
137
|
const excludeSectionKeys = React.useMemo(() => deriveExcludeSectionKeys(sectionFields), [sectionFields]);
|
|
@@ -145,15 +145,22 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
145
145
|
// Read against the *flattened* schema: `readStoredValues` drops keys that are
|
|
146
146
|
// not in the schema it is given, so passing only the top-level fields would
|
|
147
147
|
// silently discard every section field's persisted value on reload.
|
|
148
|
+
// With `persistValues={false}` storage is never read, so the form starts from
|
|
149
|
+
// `baseDefaultValues` alone.
|
|
148
150
|
const [persistedDefaults, setPersistedDefaults] = React.useState(() => {
|
|
149
151
|
var _a;
|
|
150
|
-
return
|
|
152
|
+
return shouldPersistValues
|
|
153
|
+
? normaliseValuesBySchema(flattenedSchema, (_a = readStoredValues(flattenedSchema, storageKey)) !== null && _a !== void 0 ? _a : undefined)
|
|
154
|
+
: {};
|
|
151
155
|
});
|
|
152
156
|
// Re-read from localStorage when storageKey changes
|
|
153
157
|
React.useEffect(() => {
|
|
154
158
|
var _a;
|
|
159
|
+
if (!shouldPersistValues) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
155
162
|
setPersistedDefaults(normaliseValuesBySchema(flattenedSchema, (_a = readStoredValues(flattenedSchema, storageKey)) !== null && _a !== void 0 ? _a : undefined));
|
|
156
|
-
}, [flattenedSchema, storageKey]);
|
|
163
|
+
}, [flattenedSchema, storageKey, shouldPersistValues]);
|
|
157
164
|
const mergedDefaultValues = React.useMemo(() => (Object.assign(Object.assign({}, baseDefaultValues), persistedDefaults)), [baseDefaultValues, persistedDefaults]);
|
|
158
165
|
const formMethods = useForm({
|
|
159
166
|
defaultValues: mergedDefaultValues
|
|
@@ -162,12 +169,15 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
162
169
|
// --- Filter buttons (quick-filter toggles) ---------------------------------
|
|
163
170
|
// A button is identified by its `value`, which must be unique across the
|
|
164
171
|
// whole `filterButtons` array.
|
|
165
|
-
const [activeButtonValues, setActiveButtonValues] = React.useState(() => { var _a; return (_a = readStoredButtonValues(storageKey)) !== null && _a !== void 0 ? _a : []; });
|
|
172
|
+
const [activeButtonValues, setActiveButtonValues] = React.useState(() => { var _a; return shouldPersistValues ? ((_a = readStoredButtonValues(storageKey)) !== null && _a !== void 0 ? _a : []) : []; });
|
|
166
173
|
// Re-read persisted button state when the storage key changes.
|
|
167
174
|
React.useEffect(() => {
|
|
168
175
|
var _a;
|
|
176
|
+
if (!shouldPersistValues) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
169
179
|
setActiveButtonValues((_a = readStoredButtonValues(storageKey)) !== null && _a !== void 0 ? _a : []);
|
|
170
|
-
}, [storageKey]);
|
|
180
|
+
}, [storageKey, shouldPersistValues]);
|
|
171
181
|
// Build the `{ key: value[] }` object contributed by the active buttons.
|
|
172
182
|
// Buttons that share a key are merged into an array (legacy behaviour).
|
|
173
183
|
const computeButtonValues = React.useCallback((values) => {
|
|
@@ -324,13 +334,16 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
324
334
|
const persistValues = React.useCallback((values, serialised) => {
|
|
325
335
|
const nextSerialised = serialised !== null && serialised !== void 0 ? serialised : JSON.stringify(values);
|
|
326
336
|
lastPersistedValuesRef.current = nextSerialised;
|
|
337
|
+
if (!shouldPersistValues) {
|
|
338
|
+
return nextSerialised;
|
|
339
|
+
}
|
|
327
340
|
if (Object.keys(values).length === 0) {
|
|
328
341
|
clearStoredValues(storageKey);
|
|
329
342
|
return nextSerialised;
|
|
330
343
|
}
|
|
331
344
|
writeStoredValues(storageKey, values);
|
|
332
345
|
return nextSerialised;
|
|
333
|
-
}, [storageKey]);
|
|
346
|
+
}, [storageKey, shouldPersistValues]);
|
|
334
347
|
// Emit the normalised form values merged with the active filter-button
|
|
335
348
|
// values. Buttons live outside the form state, so every emission point routes
|
|
336
349
|
// through here to keep the two slices combined in the payload.
|
|
@@ -402,10 +415,12 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
402
415
|
lastPersistedValuesRef.current = nextSerialised;
|
|
403
416
|
currentSerialisedValuesRef.current = nextSerialised;
|
|
404
417
|
// Update persistedDefaults to prevent stale mergedDefaultValues on re-render
|
|
405
|
-
|
|
418
|
+
if (shouldPersistValues) {
|
|
419
|
+
setPersistedDefaults(currParsed);
|
|
420
|
+
}
|
|
406
421
|
emitValues(currParsed);
|
|
407
422
|
}
|
|
408
|
-
}, [serialisedValues, emitValues, persistValues]);
|
|
423
|
+
}, [serialisedValues, emitValues, persistValues, shouldPersistValues]);
|
|
409
424
|
const handleClearAll = React.useCallback(() => {
|
|
410
425
|
const clearedDefaults = Object.assign({}, schemaDefaults);
|
|
411
426
|
flattenedSchema.forEach(field => {
|
|
@@ -518,7 +533,9 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
518
533
|
// before the state-update effect runs.
|
|
519
534
|
buttonValuesRef.current = computeButtonValues(nextValues);
|
|
520
535
|
setActiveButtonValues(nextValues);
|
|
521
|
-
|
|
536
|
+
if (shouldPersistValues) {
|
|
537
|
+
writeStoredButtonValues(storageKey, nextValues);
|
|
538
|
+
}
|
|
522
539
|
const formValuesNow = normaliseOutputValues(flattenedSchema, formMethods.getValues());
|
|
523
540
|
hasEmittedValuesRef.current = true;
|
|
524
541
|
emitValues(formValuesNow);
|
|
@@ -527,6 +544,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
527
544
|
activeButtonValues,
|
|
528
545
|
computeButtonValues,
|
|
529
546
|
storageKey,
|
|
547
|
+
shouldPersistValues,
|
|
530
548
|
flattenedSchema,
|
|
531
549
|
formMethods,
|
|
532
550
|
emitValues,
|
|
@@ -586,7 +604,9 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
586
604
|
if (activeButtonValues.length > 0) {
|
|
587
605
|
buttonValuesRef.current = {};
|
|
588
606
|
setActiveButtonValues([]);
|
|
589
|
-
|
|
607
|
+
if (shouldPersistValues) {
|
|
608
|
+
clearStoredButtonValues(storageKey);
|
|
609
|
+
}
|
|
590
610
|
onFilterButtonsChange === null || onFilterButtonsChange === void 0 ? void 0 : onFilterButtonsChange([]);
|
|
591
611
|
}
|
|
592
612
|
handleClearAll();
|
|
@@ -597,6 +617,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
597
617
|
onRemoveExternalFilter,
|
|
598
618
|
activeButtonValues,
|
|
599
619
|
storageKey,
|
|
620
|
+
shouldPersistValues,
|
|
600
621
|
onFilterButtonsChange
|
|
601
622
|
]);
|
|
602
623
|
const renderFieldComponent = (field) => {
|
|
@@ -637,6 +658,11 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
637
658
|
return (React.createElement(Text, { type: "secondary", className: "akinon-filter__unsupported" }, i18n.t('form.unsupportedField', { field: String(field.type) })));
|
|
638
659
|
}
|
|
639
660
|
};
|
|
661
|
+
const footerContent = typeof footer === 'function'
|
|
662
|
+
? footer({
|
|
663
|
+
values: Object.assign(Object.assign({}, normalisedValues), computeButtonValues(activeButtonValues))
|
|
664
|
+
})
|
|
665
|
+
: footer;
|
|
640
666
|
const renderFormField = (field) => {
|
|
641
667
|
return (React.createElement(FilterFormItem, { key: String(field.key), control: formMethods.control, name: field.key, tooltip: field.tooltip, help: field.help, labelDescription: field.labelDescription, required: Boolean(field.validation), className: "mb-0", valuePropName: field.type === FIELD_TYPES.CHECKBOX ? 'checked' : undefined }, renderFieldComponent(field)));
|
|
642
668
|
};
|
|
@@ -655,7 +681,8 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
655
681
|
visibleFields.length === 0 && regularFields.length > 0 ? (React.createElement("div", { className: "akinon-filter__empty" }, i18n.t('form.noVisibleFields'))) : null),
|
|
656
682
|
sectionFields.length > 0 && (React.createElement("div", { className: "akinon-filter__section-fields" }, sectionFields.map(section => (React.createElement(SectionFieldset, { key: String(section.key), section: section, storageKey: storageKey, renderFormField: renderFormField, onRemoveField: handleRemoveFilter, formValues: normalisedValues, onImportCsv: onSectionImportCsv &&
|
|
657
683
|
(file => onSectionImportCsv(String(section.key), file)), onImportXls: onSectionImportXls &&
|
|
658
|
-
(file => onSectionImportXls(String(section.key), file)), onVisibleFieldsChange: onSectionVisibleFieldsChange }))))))
|
|
684
|
+
(file => onSectionImportXls(String(section.key), file)), onVisibleFieldsChange: onSectionVisibleFieldsChange })))))),
|
|
685
|
+
footerContent ? (React.createElement("div", { className: "akinon-filter__footer", "data-testid": "akifilter-footer" }, footerContent)) : null),
|
|
659
686
|
React.createElement(VisibilityModal, Object.assign({}, modalProps)))));
|
|
660
687
|
};
|
|
661
688
|
const AkifilterEmptyState = () => {
|
package/dist/esm/styles.css
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akinon/akifilter",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Akifilter is a filtering library for Akinon frontend applications.",
|
|
6
6
|
"type": "module",
|
|
@@ -16,20 +16,20 @@
|
|
|
16
16
|
"@akinon/akiform": "1.1.9",
|
|
17
17
|
"@akinon/akidate": "1.2.7",
|
|
18
18
|
"@akinon/akilocale": "1.2.8",
|
|
19
|
-
"@akinon/icons": "1.6.0
|
|
20
|
-
"@akinon/ui-button": "1.5.8
|
|
19
|
+
"@akinon/icons": "1.6.0",
|
|
20
|
+
"@akinon/ui-button": "1.5.8",
|
|
21
21
|
"@akinon/ui-card": "1.2.12",
|
|
22
22
|
"@akinon/ui-checkbox": "1.4.12",
|
|
23
23
|
"@akinon/ui-collapse": "1.4.8",
|
|
24
|
-
"@akinon/ui-date-picker": "1.5.8
|
|
24
|
+
"@akinon/ui-date-picker": "1.5.8",
|
|
25
25
|
"@akinon/ui-input": "1.2.12",
|
|
26
26
|
"@akinon/ui-input-number": "1.4.12",
|
|
27
27
|
"@akinon/ui-modal": "1.2.13",
|
|
28
|
-
"@akinon/ui-pagination": "1.4.19
|
|
29
|
-
"@akinon/ui-select": "1.4.19
|
|
28
|
+
"@akinon/ui-pagination": "1.4.19",
|
|
29
|
+
"@akinon/ui-select": "1.4.19",
|
|
30
30
|
"@akinon/ui-space": "1.4.12",
|
|
31
31
|
"@akinon/ui-typography": "1.2.7",
|
|
32
|
-
"@akinon/ui-upload": "1.6.5
|
|
32
|
+
"@akinon/ui-upload": "1.6.5"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/lodash-es": "^4.17.12",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"copyfiles": "^2.4.1",
|
|
38
38
|
"rimraf": "^5.0.5",
|
|
39
39
|
"typescript": "*",
|
|
40
|
-
"@akinon/akiform-builder": "1.8.4
|
|
40
|
+
"@akinon/akiform-builder": "1.8.4",
|
|
41
41
|
"@akinon/typescript-config": "1.1.8",
|
|
42
42
|
"@akinon/utils": "1.2.13",
|
|
43
43
|
"@akinon/ui-theme": "1.3.3",
|