@akinon/akifilter 1.4.4-260521-3 → 1.6.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/dist/cjs/akifilter.d.ts +10 -0
- package/dist/cjs/akifilter.d.ts.map +1 -1
- package/dist/cjs/akifilter.js +57 -39
- package/dist/cjs/components/applied-filters.d.ts +1 -0
- package/dist/cjs/components/applied-filters.d.ts.map +1 -1
- package/dist/cjs/components/applied-filters.js +2 -1
- package/dist/cjs/constants.d.ts +15 -0
- package/dist/cjs/constants.d.ts.map +1 -1
- package/dist/cjs/constants.js +16 -1
- package/dist/cjs/styles.css +26 -12
- package/dist/cjs/utils/schema.d.ts +9 -0
- package/dist/cjs/utils/schema.d.ts.map +1 -1
- package/dist/cjs/utils/schema.js +11 -6
- package/dist/cjs/utils/values.js +3 -3
- package/dist/esm/akifilter.d.ts +10 -0
- package/dist/esm/akifilter.d.ts.map +1 -1
- package/dist/esm/akifilter.js +57 -40
- package/dist/esm/components/applied-filters.d.ts +1 -0
- package/dist/esm/components/applied-filters.d.ts.map +1 -1
- package/dist/esm/components/applied-filters.js +2 -1
- package/dist/esm/constants.d.ts +15 -0
- package/dist/esm/constants.d.ts.map +1 -1
- package/dist/esm/constants.js +15 -0
- package/dist/esm/styles.css +26 -12
- package/dist/esm/utils/schema.d.ts +9 -0
- package/dist/esm/utils/schema.d.ts.map +1 -1
- package/dist/esm/utils/schema.js +10 -6
- package/dist/esm/utils/values.js +4 -4
- package/package.json +4 -4
package/dist/cjs/akifilter.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import './styles.css';
|
|
2
2
|
import { FieldValues, Path } from '@akinon/akiform';
|
|
3
|
+
import { type PanelProps } from '@akinon/ui-collapse';
|
|
3
4
|
import React from 'react';
|
|
4
5
|
import { type AppliedFilter } from './components/applied-filters';
|
|
5
6
|
import type { AkifilterActionsRef, AkifilterSchema } from './types';
|
|
@@ -61,6 +62,15 @@ export type AkifilterProps<TFieldValues extends AkifilterFieldValues = Akifilter
|
|
|
61
62
|
*/
|
|
62
63
|
onRemoveExternalFilter?: (key: string) => void;
|
|
63
64
|
};
|
|
65
|
+
export declare const ExpandIcon: ({ isActive }: PanelProps) => {
|
|
66
|
+
name: "chevron_down";
|
|
67
|
+
size: number;
|
|
68
|
+
style: {
|
|
69
|
+
transform: string;
|
|
70
|
+
transition: string;
|
|
71
|
+
marginTop: number;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
64
74
|
export declare const Akifilter: {
|
|
65
75
|
<TFieldValues extends AkifilterFieldValues = FieldValues>(props: AkifilterProps<TFieldValues>): React.JSX.Element;
|
|
66
76
|
displayName: string;
|
|
@@ -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;
|
|
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;AAIzB,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAShE,OAAO,KAAK,MAAM,OAAO,CAAC;AAa1B,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,8BAA8B,CAAC;AActC,OAAO,KAAK,EACV,mBAAmB,EAEnB,eAAe,EAChB,MAAM,SAAS,CAAC;AAcjB,KAAK,oBAAoB,GAAG,WAAW,CAAC;AAoKxC,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;CAChD,CAAC;AA4zBF,eAAO,MAAM,UAAU,GAAI,cAAc,UAAU;;;;;;;;CAQjD,CAAC;AA8CH,eAAO,MAAM,SAAS;KACpB,YAAY,SAAS,oBAAoB,uBAElC,cAAc,CAAC,YAAY,CAAC;;CAmBpC,CAAC"}
|
package/dist/cjs/akifilter.js
CHANGED
|
@@ -11,7 +11,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
11
11
|
return t;
|
|
12
12
|
};
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.Akifilter = void 0;
|
|
14
|
+
exports.Akifilter = exports.ExpandIcon = void 0;
|
|
15
15
|
require("./styles.css");
|
|
16
16
|
const akidate_1 = require("@akinon/akidate");
|
|
17
17
|
const akiform_1 = require("@akinon/akiform");
|
|
@@ -97,20 +97,24 @@ const resolveClearedFieldValue = (field, defaultValue) => {
|
|
|
97
97
|
return defaultValue;
|
|
98
98
|
}
|
|
99
99
|
switch (field.type) {
|
|
100
|
-
case
|
|
101
|
-
case
|
|
100
|
+
case constants_1.FIELD_TYPES.TEXT:
|
|
101
|
+
case constants_1.FIELD_TYPES.TEXTAREA:
|
|
102
102
|
return '';
|
|
103
|
-
case
|
|
103
|
+
case constants_1.FIELD_TYPES.CHECKBOX:
|
|
104
104
|
return false;
|
|
105
|
-
case
|
|
106
|
-
case
|
|
105
|
+
case constants_1.FIELD_TYPES.NUMBER:
|
|
106
|
+
case constants_1.FIELD_TYPES.DATE:
|
|
107
107
|
return null;
|
|
108
|
-
case
|
|
109
|
-
if (field.mode ===
|
|
108
|
+
case constants_1.FIELD_TYPES.SELECT:
|
|
109
|
+
if (field.mode === constants_1.FIELD_MODES.MULTIPLE ||
|
|
110
|
+
field.mode === constants_1.FIELD_MODES.TAGS) {
|
|
110
111
|
return [];
|
|
111
112
|
}
|
|
112
113
|
return null;
|
|
113
|
-
|
|
114
|
+
// Custom fields must clear to `null`, not `undefined` (PUF-5666): otherwise
|
|
115
|
+
// react-hook-form rewrites the cleared value as a "zombie" and resurrects the filter.
|
|
116
|
+
case constants_1.FIELD_TYPES.FILE:
|
|
117
|
+
case constants_1.FIELD_TYPES.CUSTOM:
|
|
114
118
|
return null;
|
|
115
119
|
default:
|
|
116
120
|
return undefined;
|
|
@@ -119,6 +123,7 @@ const resolveClearedFieldValue = (field, defaultValue) => {
|
|
|
119
123
|
const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onValuesChange, onVisibleFieldsChange, onImportCsv, onImportXls, onClearAll, enableImportCsv, enableImportXls, filterActionsRef, externalAppliedFilters, onRemoveExternalFilter }) => {
|
|
120
124
|
// Separate regular fields from section fields
|
|
121
125
|
const { regularFields, sectionFields } = react_1.default.useMemo(() => (0, schema_1.partitionSchema)(filterSchema), [filterSchema]);
|
|
126
|
+
const excludeSectionKeys = react_1.default.useMemo(() => (0, schema_1.deriveExcludeSectionKeys)(sectionFields), [sectionFields]);
|
|
122
127
|
// Flatten schema for storage and form value operations
|
|
123
128
|
const flattenedSchema = react_1.default.useMemo(() => (0, schema_1.flattenSchema)(filterSchema), [filterSchema]);
|
|
124
129
|
const storageKey = react_1.default.useMemo(() => (0, storage_1.buildStorageKey)(regularFields, storageNamespace), [regularFields, storageNamespace]);
|
|
@@ -160,7 +165,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
160
165
|
if (Array.isArray(currentValue) && currentValue.length === 0) {
|
|
161
166
|
return acc;
|
|
162
167
|
}
|
|
163
|
-
if (field.type ===
|
|
168
|
+
if (field.type === constants_1.FIELD_TYPES.CHECKBOX && currentValue !== true) {
|
|
164
169
|
return acc;
|
|
165
170
|
}
|
|
166
171
|
const label = field.label || field.placeholder || key;
|
|
@@ -183,18 +188,20 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
183
188
|
return resolveLabel(currentValue);
|
|
184
189
|
};
|
|
185
190
|
const resolveValue = () => {
|
|
186
|
-
if (field.type ===
|
|
191
|
+
if (field.type === constants_1.FIELD_TYPES.FILE) {
|
|
187
192
|
const fileValue = currentValue;
|
|
188
193
|
return fileValue instanceof File ? fileValue.name : String(fileValue);
|
|
189
194
|
}
|
|
190
|
-
if (field.type ===
|
|
195
|
+
if (field.type === constants_1.FIELD_TYPES.SELECT) {
|
|
191
196
|
return resolveSelectLabel();
|
|
192
197
|
}
|
|
193
198
|
// For custom fields with options (like custom selects), try to find the label
|
|
194
|
-
if (field.type ===
|
|
199
|
+
if (field.type === constants_1.FIELD_TYPES.CUSTOM &&
|
|
200
|
+
'options' in field &&
|
|
201
|
+
field.options) {
|
|
195
202
|
return resolveSelectLabel();
|
|
196
203
|
}
|
|
197
|
-
if (field.type ===
|
|
204
|
+
if (field.type === constants_1.FIELD_TYPES.DATE) {
|
|
198
205
|
const iso = akidate_1.akidate.toIsoDate(currentValue);
|
|
199
206
|
if (iso) {
|
|
200
207
|
// Use localized format with time if showTime is enabled
|
|
@@ -221,10 +228,15 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
221
228
|
}
|
|
222
229
|
return String(currentValue);
|
|
223
230
|
};
|
|
224
|
-
acc.push({
|
|
231
|
+
acc.push({
|
|
232
|
+
key,
|
|
233
|
+
label,
|
|
234
|
+
value: resolveValue(),
|
|
235
|
+
isExclude: excludeSectionKeys.has(key)
|
|
236
|
+
});
|
|
225
237
|
return acc;
|
|
226
238
|
}, []);
|
|
227
|
-
}, [flattenedSchema, formValues]);
|
|
239
|
+
}, [flattenedSchema, formValues, excludeSectionKeys]);
|
|
228
240
|
const resolveInitialVisibleKeys = react_1.default.useCallback(() => {
|
|
229
241
|
const storedKeys = (0, storage_1.readVisibleKeys)(regularFields, storageKey);
|
|
230
242
|
const defaultKeys = (0, schema_1.deriveDefaultVisibleKeys)(regularFields);
|
|
@@ -260,16 +272,6 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
260
272
|
(0, storage_1.writeVisibleKeys)(storageKey, visibleKeys);
|
|
261
273
|
onVisibleFieldsChange === null || onVisibleFieldsChange === void 0 ? void 0 : onVisibleFieldsChange(visibleKeys);
|
|
262
274
|
}, [visibleKeys, onVisibleFieldsChange, storageKey]);
|
|
263
|
-
// Track previous mergedDefaultValues to avoid unnecessary resets
|
|
264
|
-
const previousMergedDefaultValuesRef = react_1.default.useRef(null);
|
|
265
|
-
react_1.default.useEffect(() => {
|
|
266
|
-
const serialised = JSON.stringify(mergedDefaultValues);
|
|
267
|
-
// Skip if the values haven't actually changed (deep comparison)
|
|
268
|
-
if (previousMergedDefaultValuesRef.current === serialised) {
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
previousMergedDefaultValuesRef.current = serialised;
|
|
272
|
-
}, [mergedDefaultValues]);
|
|
273
275
|
const normalisedValues = react_1.default.useMemo(() => (0, values_1.normaliseOutputValues)(flattenedSchema, formValues), [flattenedSchema, formValues]);
|
|
274
276
|
const hasInitialValuesRef = react_1.default.useRef(false);
|
|
275
277
|
react_1.default.useEffect(() => {
|
|
@@ -370,6 +372,9 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
370
372
|
clearedDefaults[key] = resolved;
|
|
371
373
|
}
|
|
372
374
|
});
|
|
375
|
+
// clearedDefaults carries an explicit cleared value (e.g. `null` for custom/file
|
|
376
|
+
// fields) for every key, so reset overwrites stale values instead of leaving the
|
|
377
|
+
// field untouched and resurrecting the filter (PUF-5666).
|
|
373
378
|
formMethods.reset(clearedDefaults, {
|
|
374
379
|
keepDirty: false,
|
|
375
380
|
keepTouched: false
|
|
@@ -422,7 +427,9 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
422
427
|
const updatedFormValues = Object.assign(Object.assign({}, currentFormValues), { [String(schemaField.key)]: nextValue });
|
|
423
428
|
// Normalize the values (removes empty/undefined entries)
|
|
424
429
|
const nextValues = (0, values_1.normaliseOutputValues)(flattenedSchema, updatedFormValues);
|
|
425
|
-
//
|
|
430
|
+
// updatedFormValues holds an explicit cleared value (e.g. `null` for custom/file
|
|
431
|
+
// fields) for the removed key, so reset overwrites the stale value rather than
|
|
432
|
+
// leaving it in place and resurrecting the filter (PUF-5666).
|
|
426
433
|
formMethods.reset(updatedFormValues, {
|
|
427
434
|
keepDirty: false,
|
|
428
435
|
keepTouched: false,
|
|
@@ -498,21 +505,21 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
498
505
|
const ariaLabel = (0, schema_1.getFieldAriaLabel)(field);
|
|
499
506
|
const isDisabled = checkIsDisabled(field, formValues !== null && formValues !== void 0 ? formValues : {});
|
|
500
507
|
switch (field.type) {
|
|
501
|
-
case
|
|
508
|
+
case constants_1.FIELD_TYPES.TEXT:
|
|
502
509
|
return (react_1.default.createElement(ui_input_1.Input, { placeholder: field.placeholder, size: "large", allowClear: true, "aria-label": ariaLabel, disabled: isDisabled }));
|
|
503
|
-
case
|
|
510
|
+
case constants_1.FIELD_TYPES.NUMBER:
|
|
504
511
|
return (react_1.default.createElement(ui_input_number_1.InputNumber, { placeholder: field.placeholder, size: "large", className: "akinon-filter__field--number", "aria-label": ariaLabel, disabled: isDisabled }));
|
|
505
|
-
case
|
|
512
|
+
case constants_1.FIELD_TYPES.SELECT:
|
|
506
513
|
return (react_1.default.createElement(ui_select_1.Select, { placeholder: field.placeholder, size: "large", options: field.options, showSearch: true, optionFilterProp: "label", "aria-label": ariaLabel, disabled: isDisabled, mode: field.mode }));
|
|
507
|
-
case
|
|
514
|
+
case constants_1.FIELD_TYPES.CHECKBOX:
|
|
508
515
|
return react_1.default.createElement(ui_checkbox_1.Checkbox, { disabled: isDisabled }, field.label);
|
|
509
|
-
case
|
|
516
|
+
case constants_1.FIELD_TYPES.DATE:
|
|
510
517
|
return (react_1.default.createElement(ui_date_picker_1.DatePicker, { placeholder: field.placeholder, showTime: field.showTime, suffixIcon: "calendar", suffixIconSize: "16px", "aria-label": ariaLabel, disabled: isDisabled }));
|
|
511
|
-
case
|
|
518
|
+
case constants_1.FIELD_TYPES.TEXTAREA:
|
|
512
519
|
return (react_1.default.createElement(ui_input_1.InputTextArea, { placeholder: field.placeholder, autoSize: { minRows: 3, maxRows: 6 }, "aria-label": ariaLabel, disabled: isDisabled }));
|
|
513
|
-
case
|
|
520
|
+
case constants_1.FIELD_TYPES.FILE:
|
|
514
521
|
return (react_1.default.createElement(FileFilterInput, { accept: field.fileAccept, "aria-label": ariaLabel, disabled: isDisabled }));
|
|
515
|
-
case
|
|
522
|
+
case constants_1.FIELD_TYPES.CUSTOM:
|
|
516
523
|
if (typeof field.render === 'function') {
|
|
517
524
|
return field.render({
|
|
518
525
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -524,7 +531,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
524
531
|
});
|
|
525
532
|
}
|
|
526
533
|
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) })));
|
|
527
|
-
case
|
|
534
|
+
case constants_1.FIELD_TYPES.SECTION:
|
|
528
535
|
// Section fields should not be rendered inline
|
|
529
536
|
// They are rendered separately after the main grid
|
|
530
537
|
return null;
|
|
@@ -533,7 +540,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
533
540
|
}
|
|
534
541
|
};
|
|
535
542
|
const renderFormField = (field) => {
|
|
536
|
-
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 ===
|
|
543
|
+
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)));
|
|
537
544
|
};
|
|
538
545
|
return (react_1.default.createElement(ui_card_1.Card, { size: "small", className: "akinon-filter shadow", "data-testid": "akifilter-root" },
|
|
539
546
|
react_1.default.createElement(antd_1.ConfigProvider, { theme: theme_overrides_1.themeOverrides },
|
|
@@ -545,10 +552,11 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
545
552
|
visibleFields.map(renderFormField),
|
|
546
553
|
visibleFields.length === 0 ? (react_1.default.createElement("div", { className: "akinon-filter__empty" }, i18n_1.i18n.t('form.noVisibleFields'))) : null),
|
|
547
554
|
sectionFields.length > 0 && (react_1.default.createElement("div", { className: "akinon-filter__section-fields" }, sectionFields.map(section => {
|
|
548
|
-
return (react_1.default.createElement(ui_collapse_1.Collapse, { key: section.key, defaultActiveKey: section.key, ghost: true, items: [
|
|
555
|
+
return (react_1.default.createElement(ui_collapse_1.Collapse, { expandIconPosition: "end", key: section.key, expandIcon: exports.ExpandIcon, defaultActiveKey: section.defaultExpanded === false ? [] : [section.key], ghost: true, items: [
|
|
549
556
|
{
|
|
550
557
|
key: section.key,
|
|
551
|
-
label: section.label,
|
|
558
|
+
label: (react_1.default.createElement(ui_typography_1.Title, { className: "akinon-filter__title", level: 4 }, section.label)),
|
|
559
|
+
headerClass: 'akinon-filter__section-header',
|
|
552
560
|
children: (react_1.default.createElement("div", { className: "akinon-filter__form-grid" }, section.fields.map(renderFormField)))
|
|
553
561
|
}
|
|
554
562
|
] }));
|
|
@@ -563,6 +571,16 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
563
571
|
}
|
|
564
572
|
}, page: modalPage, pageSize: modalPageSize }))));
|
|
565
573
|
};
|
|
574
|
+
const ExpandIcon = ({ isActive }) => ({
|
|
575
|
+
name: 'chevron_down',
|
|
576
|
+
size: 10,
|
|
577
|
+
style: {
|
|
578
|
+
transform: isActive ? 'rotate(-180deg)' : 'rotate(0deg)',
|
|
579
|
+
transition: 'transform 0.2s ease-in-out',
|
|
580
|
+
marginTop: 8
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
exports.ExpandIcon = ExpandIcon;
|
|
566
584
|
const AkifilterEmptyState = () => {
|
|
567
585
|
const { t } = i18n_1.i18n;
|
|
568
586
|
return (react_1.default.createElement(ui_card_1.Card, { size: "small", className: "akinon-filter shadow", "data-testid": "akifilter-empty" },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applied-filters.d.ts","sourceRoot":"","sources":["../../../src/components/applied-filters.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,KAAK,aAAa,GAAG;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"applied-filters.d.ts","sourceRoot":"","sources":["../../../src/components/applied-filters.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,KAAK,aAAa,GAAG;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,mCAI5B,mBAAmB,sBA+DrB,CAAC;AAEF,YAAY,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -12,7 +12,8 @@ const AppliedFilters = ({ filters, onRemove, onClearAll }) => {
|
|
|
12
12
|
return (react_1.default.createElement("div", { className: "akinon-filter__applied", "data-testid": "akifilter-applied" },
|
|
13
13
|
react_1.default.createElement(ui_space_1.Space, { className: "akinon-filter__applied-summary", size: 8 },
|
|
14
14
|
react_1.default.createElement(ui_typography_1.Text, { className: "akinon-filter__applied-label" }, i18n_1.i18n.t('applied.label')),
|
|
15
|
-
hasFilters ? (react_1.default.createElement(ui_space_1.Space, { className: "akinon-filter__applied-items", size: 8, wrap: true }, filters.map(item => (react_1.default.createElement("div", { key: `${item.key}-${item.value}`, className:
|
|
15
|
+
hasFilters ? (react_1.default.createElement(ui_space_1.Space, { className: "akinon-filter__applied-items", size: 8, wrap: true }, filters.map(item => (react_1.default.createElement("div", { key: `${item.key}-${item.value}`, className: `akinon-filter__chip${item.isExclude ? ' akinon-filter__chip--exclude' : ''}` },
|
|
16
|
+
item.isExclude ? (react_1.default.createElement(icons_1.Icon, { icon: "exclude", size: 12, className: "akinon-filter__chip-exclude-icon" })) : null,
|
|
16
17
|
item.label ? (react_1.default.createElement("span", { className: "akinon-filter__chip-label" },
|
|
17
18
|
item.label,
|
|
18
19
|
":")) : null,
|
package/dist/cjs/constants.d.ts
CHANGED
|
@@ -7,4 +7,19 @@ export declare const BOOLEAN_STRING: {
|
|
|
7
7
|
readonly TRUE: "true";
|
|
8
8
|
readonly FALSE: "false";
|
|
9
9
|
};
|
|
10
|
+
export declare const FIELD_TYPES: {
|
|
11
|
+
readonly TEXT: "text";
|
|
12
|
+
readonly NUMBER: "number";
|
|
13
|
+
readonly SELECT: "select";
|
|
14
|
+
readonly CHECKBOX: "checkbox";
|
|
15
|
+
readonly DATE: "date";
|
|
16
|
+
readonly TEXTAREA: "textarea";
|
|
17
|
+
readonly SECTION: "section";
|
|
18
|
+
readonly CUSTOM: "custom";
|
|
19
|
+
readonly FILE: "file";
|
|
20
|
+
};
|
|
21
|
+
export declare const FIELD_MODES: {
|
|
22
|
+
readonly TAGS: "tags";
|
|
23
|
+
readonly MULTIPLE: "multiple";
|
|
24
|
+
};
|
|
10
25
|
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,IAAI,CAAC;AACvC,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAC1C,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC,eAAO,MAAM,WAAW,eAAe,CAAC;AACxC,eAAO,MAAM,eAAe,wBAAwB,CAAC;AAErD,eAAO,MAAM,cAAc;;;CAGjB,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,IAAI,CAAC;AACvC,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAC1C,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC,eAAO,MAAM,WAAW,eAAe,CAAC;AACxC,eAAO,MAAM,eAAe,wBAAwB,CAAC;AAErD,eAAO,MAAM,cAAc;;;CAGjB,CAAC;AAEX,eAAO,MAAM,WAAW;;;;;;;;;;CAUd,CAAC;AAEX,eAAO,MAAM,WAAW;;;CAGd,CAAC"}
|
package/dist/cjs/constants.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BOOLEAN_STRING = exports.DATETIME_FORMAT = exports.DATE_FORMAT = exports.FILTER_DEBOUNCE_DELAY = exports.DEFAULT_MODAL_PAGE_SIZE = exports.DEFAULT_VISIBLE_COUNT = void 0;
|
|
3
|
+
exports.FIELD_MODES = exports.FIELD_TYPES = exports.BOOLEAN_STRING = exports.DATETIME_FORMAT = exports.DATE_FORMAT = exports.FILTER_DEBOUNCE_DELAY = exports.DEFAULT_MODAL_PAGE_SIZE = exports.DEFAULT_VISIBLE_COUNT = void 0;
|
|
4
4
|
exports.DEFAULT_VISIBLE_COUNT = 8;
|
|
5
5
|
exports.DEFAULT_MODAL_PAGE_SIZE = 40;
|
|
6
6
|
exports.FILTER_DEBOUNCE_DELAY = 300;
|
|
@@ -10,3 +10,18 @@ exports.BOOLEAN_STRING = {
|
|
|
10
10
|
TRUE: 'true',
|
|
11
11
|
FALSE: 'false'
|
|
12
12
|
};
|
|
13
|
+
exports.FIELD_TYPES = {
|
|
14
|
+
TEXT: 'text',
|
|
15
|
+
NUMBER: 'number',
|
|
16
|
+
SELECT: 'select',
|
|
17
|
+
CHECKBOX: 'checkbox',
|
|
18
|
+
DATE: 'date',
|
|
19
|
+
TEXTAREA: 'textarea',
|
|
20
|
+
SECTION: 'section',
|
|
21
|
+
CUSTOM: 'custom',
|
|
22
|
+
FILE: 'file'
|
|
23
|
+
};
|
|
24
|
+
exports.FIELD_MODES = {
|
|
25
|
+
TAGS: 'tags',
|
|
26
|
+
MULTIPLE: 'multiple'
|
|
27
|
+
};
|
package/dist/cjs/styles.css
CHANGED
|
@@ -47,11 +47,11 @@
|
|
|
47
47
|
background-color: var(--color-ebonyClay-900);
|
|
48
48
|
flex: 1;
|
|
49
49
|
display: flex;
|
|
50
|
-
align-items:
|
|
50
|
+
align-items: flex-start;
|
|
51
51
|
border-radius: 5px;
|
|
52
52
|
padding: 6px 8px;
|
|
53
53
|
margin-right: 6px;
|
|
54
|
-
height: 36px;
|
|
54
|
+
min-height: 36px;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
.akinon-filter__applied-label {
|
|
@@ -59,16 +59,13 @@
|
|
|
59
59
|
font-weight: 600;
|
|
60
60
|
font-size: 13px;
|
|
61
61
|
position: relative;
|
|
62
|
-
|
|
62
|
+
white-space: nowrap;
|
|
63
|
+
top: 7px;
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
.akinon-
|
|
66
|
-
margin-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
.akinon-filter__common-filters-title {
|
|
70
|
-
color: var(--color-gray-500);
|
|
71
|
-
margin-bottom: 1rem;
|
|
66
|
+
.akinon-filter__section-header span {
|
|
67
|
+
margin-inline-end: unset !important;
|
|
68
|
+
flex: unset !important;
|
|
72
69
|
}
|
|
73
70
|
|
|
74
71
|
.akinon-filter__form-grid {
|
|
@@ -121,8 +118,10 @@
|
|
|
121
118
|
|
|
122
119
|
.akinon-filter__applied-items {
|
|
123
120
|
display: flex;
|
|
121
|
+
flex: 1;
|
|
124
122
|
flex-wrap: wrap;
|
|
125
123
|
gap: 8px;
|
|
124
|
+
min-width: 0;
|
|
126
125
|
}
|
|
127
126
|
|
|
128
127
|
.akinon-filter__chip {
|
|
@@ -136,6 +135,16 @@
|
|
|
136
135
|
height: 24px;
|
|
137
136
|
}
|
|
138
137
|
|
|
138
|
+
.akinon-filter__chip--exclude {
|
|
139
|
+
background-color: #ffe0e4;
|
|
140
|
+
border: 1px solid #ff354e;
|
|
141
|
+
height: 23px;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.akinon-filter__chip-exclude-icon {
|
|
145
|
+
margin-right: 5px;
|
|
146
|
+
}
|
|
147
|
+
|
|
139
148
|
.akinon-filter__chip-label {
|
|
140
149
|
font-weight: 600;
|
|
141
150
|
color: var(--color-ebonyClay-300);
|
|
@@ -162,7 +171,7 @@
|
|
|
162
171
|
color: color(--color-ebonyClay-500);
|
|
163
172
|
font-size: 12px;
|
|
164
173
|
position: relative;
|
|
165
|
-
top:
|
|
174
|
+
top: 8px;
|
|
166
175
|
}
|
|
167
176
|
|
|
168
177
|
.akinon-filter__modal-list {
|
|
@@ -187,13 +196,13 @@
|
|
|
187
196
|
column-gap: 8px; /* replaces Ant's label padding, zeroed out below */
|
|
188
197
|
line-height: 1.4;
|
|
189
198
|
margin-inline-start: 0; /* override Ant's adjacent-sibling margin */
|
|
199
|
+
color: var(--color-white);
|
|
190
200
|
}
|
|
191
201
|
|
|
192
202
|
.akinon-filter__modal-list
|
|
193
203
|
.akinon-filter__modal-checkbox.ant-checkbox-wrapper
|
|
194
204
|
> .ant-checkbox {
|
|
195
205
|
align-self: start;
|
|
196
|
-
margin-block-start: 0.15em; /* em-relative baseline nudge */
|
|
197
206
|
}
|
|
198
207
|
|
|
199
208
|
.akinon-filter__modal-list
|
|
@@ -253,6 +262,11 @@
|
|
|
253
262
|
width: auto;
|
|
254
263
|
}
|
|
255
264
|
|
|
265
|
+
.akinon-filter .akinon-select-multiple .akinon-select-selector {
|
|
266
|
+
height: 40px;
|
|
267
|
+
overflow: hidden;
|
|
268
|
+
}
|
|
269
|
+
|
|
256
270
|
/* Modal window. */
|
|
257
271
|
|
|
258
272
|
.akinon-filter__modal-toolbar {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FieldValues } from '@akinon/akiform';
|
|
2
|
+
import { FIELD_TYPES } from '../constants';
|
|
2
3
|
import type { AkifilterField, AkifilterSchema } from '../types';
|
|
3
4
|
/**
|
|
4
5
|
* Flattens schema by extracting all nested fields from section fields.
|
|
@@ -11,9 +12,17 @@ export declare const flattenSchema: <TFieldValues extends FieldValues = FieldVal
|
|
|
11
12
|
export declare const partitionSchema: <TFieldValues extends FieldValues = FieldValues>(schema: AkifilterSchema<TFieldValues>) => {
|
|
12
13
|
regularFields: AkifilterSchema<TFieldValues>;
|
|
13
14
|
sectionFields: Array<AkifilterField<TFieldValues> & {
|
|
15
|
+
type: typeof FIELD_TYPES.SECTION;
|
|
14
16
|
fields: AkifilterSchema<TFieldValues>;
|
|
17
|
+
defaultExpanded?: boolean;
|
|
18
|
+
isExcludeSection?: boolean;
|
|
15
19
|
}>;
|
|
16
20
|
};
|
|
21
|
+
export declare const deriveExcludeSectionKeys: <TFieldValues extends FieldValues = FieldValues>(sectionFields: Array<AkifilterField<TFieldValues> & {
|
|
22
|
+
type: typeof FIELD_TYPES.SECTION;
|
|
23
|
+
fields: AkifilterSchema<TFieldValues>;
|
|
24
|
+
isExcludeSection?: boolean;
|
|
25
|
+
}>) => Set<string>;
|
|
17
26
|
export declare const getDisplayLabel: <TFieldValues extends FieldValues = FieldValues>(field: AkifilterField<TFieldValues>) => string;
|
|
18
27
|
export declare const getFieldAriaLabel: <TFieldValues extends FieldValues = FieldValues>(field: AkifilterField<TFieldValues>) => string;
|
|
19
28
|
export declare const ensureSchemaOrder: <TFieldValues extends FieldValues = FieldValues>(schema: AkifilterSchema<TFieldValues>, keys: string[]) => string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/utils/schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/utils/schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,OAAO,EAAsC,WAAW,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEhE;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,YAAY,SAAS,WAAW,GAAG,WAAW,EAC1E,QAAQ,eAAe,CAAC,YAAY,CAAC,KACpC,eAAe,CAAC,YAAY,CAW9B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,YAAY,SAAS,WAAW,GAAG,WAAW,EAC5E,QAAQ,eAAe,CAAC,YAAY,CAAC,KACpC;IACD,aAAa,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;IAC7C,aAAa,EAAE,KAAK,CAClB,cAAc,CAAC,YAAY,CAAC,GAAG;QAC7B,IAAI,EAAE,OAAO,WAAW,CAAC,OAAO,CAAC;QACjC,MAAM,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;QACtC,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;KAC5B,CACF,CAAC;CAwBH,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,eAAe,KAAK,CAClB,cAAc,CAAC,YAAY,CAAC,GAAG;IAC7B,IAAI,EAAE,OAAO,WAAW,CAAC,OAAO,CAAC;IACjC,MAAM,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;IACtC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CACF,KACA,GAAG,CAAC,MAAM,CAKV,CAAC;AAEJ,eAAO,MAAM,eAAe,GAAI,YAAY,SAAS,WAAW,GAAG,WAAW,EAC5E,OAAO,cAAc,CAAC,YAAY,CAAC,KAClC,MAEF,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,OAAO,cAAc,CAAC,YAAY,CAAC,KAClC,MAEF,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,QAAQ,eAAe,CAAC,YAAY,CAAC,EACrC,MAAM,MAAM,EAAE,KACb,MAAM,EAGR,CAAC;AAkBF;;GAEG;AACH,eAAO,MAAM,sBAAsB,GACjC,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,OAAO,cAAc,CAAC,YAAY,CAAC,EACnC,aAAa,YAAY,EACzB,iBAAiB,OAAO,KACvB,OAAO,GAAG,SAC8D,CAAC;AAE5E,eAAO,MAAM,wBAAwB,GACnC,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,QAAQ,eAAe,CAAC,YAAY,CAAC,KACpC,MAAM,EAUR,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,QAAQ,eAAe,CAAC,YAAY,CAAC,KACpC,OAAO,CAAC,YAAY,CAQtB,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,YAAY,SAAS,WAAW,EACnE,OAAO,cAAc,CAAC,YAAY,CAAC,KAClC,OAA4C,CAAC;AAEhD,eAAO,MAAM,uBAAuB,GAClC,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,QAAQ,eAAe,CAAC,YAAY,CAAC,EACrC,SAAS,OAAO,CAAC,YAAY,CAAC,KAC7B,OAAO,CAAC,YAAY,CA0CtB,CAAC"}
|
package/dist/cjs/utils/schema.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.normaliseValuesBySchema = exports.hasDynamicVisibility = exports.extractDefaultValues = exports.deriveDefaultVisibleKeys = exports.resolveFieldVisibility = exports.ensureSchemaOrder = exports.getFieldAriaLabel = exports.getDisplayLabel = exports.partitionSchema = exports.flattenSchema = void 0;
|
|
3
|
+
exports.normaliseValuesBySchema = exports.hasDynamicVisibility = exports.extractDefaultValues = exports.deriveDefaultVisibleKeys = exports.resolveFieldVisibility = exports.ensureSchemaOrder = exports.getFieldAriaLabel = exports.getDisplayLabel = exports.deriveExcludeSectionKeys = exports.partitionSchema = exports.flattenSchema = void 0;
|
|
4
4
|
const akidate_1 = require("@akinon/akidate");
|
|
5
5
|
const lodash_es_1 = require("lodash-es");
|
|
6
6
|
const constants_1 = require("../constants");
|
|
@@ -10,7 +10,7 @@ const constants_1 = require("../constants");
|
|
|
10
10
|
*/
|
|
11
11
|
const flattenSchema = (schema) => {
|
|
12
12
|
return schema.reduce((acc, field) => {
|
|
13
|
-
if (field.type ===
|
|
13
|
+
if (field.type === constants_1.FIELD_TYPES.SECTION && 'fields' in field) {
|
|
14
14
|
// Recursively flatten nested section fields
|
|
15
15
|
return [
|
|
16
16
|
...acc,
|
|
@@ -28,7 +28,7 @@ const partitionSchema = (schema) => {
|
|
|
28
28
|
const regularFields = [];
|
|
29
29
|
const sectionFields = [];
|
|
30
30
|
schema.forEach(field => {
|
|
31
|
-
if (field.type ===
|
|
31
|
+
if (field.type === constants_1.FIELD_TYPES.SECTION) {
|
|
32
32
|
sectionFields.push(field);
|
|
33
33
|
}
|
|
34
34
|
else {
|
|
@@ -38,6 +38,10 @@ const partitionSchema = (schema) => {
|
|
|
38
38
|
return { regularFields, sectionFields };
|
|
39
39
|
};
|
|
40
40
|
exports.partitionSchema = partitionSchema;
|
|
41
|
+
const deriveExcludeSectionKeys = (sectionFields) => new Set(sectionFields
|
|
42
|
+
.filter(s => s.isExcludeSection)
|
|
43
|
+
.flatMap(s => s.fields.map(f => String(f.key))));
|
|
44
|
+
exports.deriveExcludeSectionKeys = deriveExcludeSectionKeys;
|
|
41
45
|
const getDisplayLabel = (field) => {
|
|
42
46
|
return field.label || field.placeholder || String(field.key);
|
|
43
47
|
};
|
|
@@ -96,15 +100,16 @@ const normaliseValuesBySchema = (schema, values) => {
|
|
|
96
100
|
return acc;
|
|
97
101
|
}
|
|
98
102
|
const currentValue = values[key];
|
|
99
|
-
if (field.type ===
|
|
103
|
+
if (field.type === constants_1.FIELD_TYPES.DATE) {
|
|
100
104
|
const parsed = akidate_1.akidate.parse(currentValue);
|
|
101
105
|
if (parsed) {
|
|
102
106
|
acc[key] = parsed;
|
|
103
107
|
return acc;
|
|
104
108
|
}
|
|
105
109
|
}
|
|
106
|
-
if (field.type ===
|
|
107
|
-
(field.mode ===
|
|
110
|
+
if (field.type === constants_1.FIELD_TYPES.SELECT &&
|
|
111
|
+
(field.mode === constants_1.FIELD_MODES.MULTIPLE ||
|
|
112
|
+
field.mode === constants_1.FIELD_MODES.TAGS) &&
|
|
108
113
|
currentValue != null &&
|
|
109
114
|
!Array.isArray(currentValue)) {
|
|
110
115
|
acc[key] = [currentValue];
|
package/dist/cjs/utils/values.js
CHANGED
|
@@ -13,10 +13,10 @@ const shouldPersistValue = (field, value) => {
|
|
|
13
13
|
if (Array.isArray(value) && value.length === 0) {
|
|
14
14
|
return false;
|
|
15
15
|
}
|
|
16
|
-
if ((field === null || field === void 0 ? void 0 : field.type) ===
|
|
16
|
+
if ((field === null || field === void 0 ? void 0 : field.type) === constants_1.FIELD_TYPES.CHECKBOX && value !== true) {
|
|
17
17
|
return false;
|
|
18
18
|
}
|
|
19
|
-
if ((field === null || field === void 0 ? void 0 : field.type) ===
|
|
19
|
+
if ((field === null || field === void 0 ? void 0 : field.type) === constants_1.FIELD_TYPES.FILE) {
|
|
20
20
|
return value instanceof File;
|
|
21
21
|
}
|
|
22
22
|
return true;
|
|
@@ -33,7 +33,7 @@ const normaliseOutputValues = (schema, values) => {
|
|
|
33
33
|
return acc;
|
|
34
34
|
}
|
|
35
35
|
let normalisedValue = rawValue;
|
|
36
|
-
if ((field === null || field === void 0 ? void 0 : field.type) ===
|
|
36
|
+
if ((field === null || field === void 0 ? void 0 : field.type) === constants_1.FIELD_TYPES.DATE) {
|
|
37
37
|
const normalised = akidate_1.akidate.toIsoDate(rawValue);
|
|
38
38
|
if (!normalised) {
|
|
39
39
|
return acc;
|
package/dist/esm/akifilter.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import './styles.css';
|
|
2
2
|
import { FieldValues, Path } from '@akinon/akiform';
|
|
3
|
+
import { type PanelProps } from '@akinon/ui-collapse';
|
|
3
4
|
import React from 'react';
|
|
4
5
|
import { type AppliedFilter } from './components/applied-filters';
|
|
5
6
|
import type { AkifilterActionsRef, AkifilterSchema } from './types';
|
|
@@ -61,6 +62,15 @@ export type AkifilterProps<TFieldValues extends AkifilterFieldValues = Akifilter
|
|
|
61
62
|
*/
|
|
62
63
|
onRemoveExternalFilter?: (key: string) => void;
|
|
63
64
|
};
|
|
65
|
+
export declare const ExpandIcon: ({ isActive }: PanelProps) => {
|
|
66
|
+
name: "chevron_down";
|
|
67
|
+
size: number;
|
|
68
|
+
style: {
|
|
69
|
+
transform: string;
|
|
70
|
+
transition: string;
|
|
71
|
+
marginTop: number;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
64
74
|
export declare const Akifilter: {
|
|
65
75
|
<TFieldValues extends AkifilterFieldValues = FieldValues>(props: AkifilterProps<TFieldValues>): React.JSX.Element;
|
|
66
76
|
displayName: string;
|
|
@@ -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;
|
|
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;AAIzB,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAShE,OAAO,KAAK,MAAM,OAAO,CAAC;AAa1B,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,8BAA8B,CAAC;AActC,OAAO,KAAK,EACV,mBAAmB,EAEnB,eAAe,EAChB,MAAM,SAAS,CAAC;AAcjB,KAAK,oBAAoB,GAAG,WAAW,CAAC;AAoKxC,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;CAChD,CAAC;AA4zBF,eAAO,MAAM,UAAU,GAAI,cAAc,UAAU;;;;;;;;CAQjD,CAAC;AA8CH,eAAO,MAAM,SAAS;KACpB,YAAY,SAAS,oBAAoB,uBAElC,cAAc,CAAC,YAAY,CAAC;;CAmBpC,CAAC"}
|
package/dist/esm/akifilter.js
CHANGED
|
@@ -30,12 +30,12 @@ import { themeOverrides } from './common/theme-overrides';
|
|
|
30
30
|
import { AppliedFilters } from './components/applied-filters';
|
|
31
31
|
import { FilterToolbar } from './components/filter-toolbar';
|
|
32
32
|
import { VisibilityModal } from './components/visibility-modal';
|
|
33
|
-
import { BOOLEAN_STRING, DEFAULT_MODAL_PAGE_SIZE, FILTER_DEBOUNCE_DELAY } from './constants';
|
|
33
|
+
import { BOOLEAN_STRING, DEFAULT_MODAL_PAGE_SIZE, FIELD_MODES, FIELD_TYPES, FILTER_DEBOUNCE_DELAY } from './constants';
|
|
34
34
|
import { useDebouncedValue } from './hooks/use-debounced-value';
|
|
35
35
|
import { useDynamicVisibility } from './hooks/use-dynamic-visibility';
|
|
36
36
|
import { useVisibilityCleanup } from './hooks/use-visibility-cleanup';
|
|
37
37
|
import { i18n } from './i18n';
|
|
38
|
-
import { deriveDefaultVisibleKeys, ensureSchemaOrder, extractDefaultValues, flattenSchema, getFieldAriaLabel, normaliseValuesBySchema, partitionSchema, resolveFieldVisibility } from './utils/schema';
|
|
38
|
+
import { deriveDefaultVisibleKeys, deriveExcludeSectionKeys, ensureSchemaOrder, extractDefaultValues, flattenSchema, getFieldAriaLabel, normaliseValuesBySchema, partitionSchema, resolveFieldVisibility } from './utils/schema';
|
|
39
39
|
import { normaliseOutputValues } from './utils/values';
|
|
40
40
|
const FilterFormItem = (_a) => {
|
|
41
41
|
var _b, _c;
|
|
@@ -94,20 +94,24 @@ const resolveClearedFieldValue = (field, defaultValue) => {
|
|
|
94
94
|
return defaultValue;
|
|
95
95
|
}
|
|
96
96
|
switch (field.type) {
|
|
97
|
-
case
|
|
98
|
-
case
|
|
97
|
+
case FIELD_TYPES.TEXT:
|
|
98
|
+
case FIELD_TYPES.TEXTAREA:
|
|
99
99
|
return '';
|
|
100
|
-
case
|
|
100
|
+
case FIELD_TYPES.CHECKBOX:
|
|
101
101
|
return false;
|
|
102
|
-
case
|
|
103
|
-
case
|
|
102
|
+
case FIELD_TYPES.NUMBER:
|
|
103
|
+
case FIELD_TYPES.DATE:
|
|
104
104
|
return null;
|
|
105
|
-
case
|
|
106
|
-
if (field.mode ===
|
|
105
|
+
case FIELD_TYPES.SELECT:
|
|
106
|
+
if (field.mode === FIELD_MODES.MULTIPLE ||
|
|
107
|
+
field.mode === FIELD_MODES.TAGS) {
|
|
107
108
|
return [];
|
|
108
109
|
}
|
|
109
110
|
return null;
|
|
110
|
-
|
|
111
|
+
// Custom fields must clear to `null`, not `undefined` (PUF-5666): otherwise
|
|
112
|
+
// react-hook-form rewrites the cleared value as a "zombie" and resurrects the filter.
|
|
113
|
+
case FIELD_TYPES.FILE:
|
|
114
|
+
case FIELD_TYPES.CUSTOM:
|
|
111
115
|
return null;
|
|
112
116
|
default:
|
|
113
117
|
return undefined;
|
|
@@ -116,6 +120,7 @@ const resolveClearedFieldValue = (field, defaultValue) => {
|
|
|
116
120
|
const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onValuesChange, onVisibleFieldsChange, onImportCsv, onImportXls, onClearAll, enableImportCsv, enableImportXls, filterActionsRef, externalAppliedFilters, onRemoveExternalFilter }) => {
|
|
117
121
|
// Separate regular fields from section fields
|
|
118
122
|
const { regularFields, sectionFields } = React.useMemo(() => partitionSchema(filterSchema), [filterSchema]);
|
|
123
|
+
const excludeSectionKeys = React.useMemo(() => deriveExcludeSectionKeys(sectionFields), [sectionFields]);
|
|
119
124
|
// Flatten schema for storage and form value operations
|
|
120
125
|
const flattenedSchema = React.useMemo(() => flattenSchema(filterSchema), [filterSchema]);
|
|
121
126
|
const storageKey = React.useMemo(() => buildStorageKey(regularFields, storageNamespace), [regularFields, storageNamespace]);
|
|
@@ -157,7 +162,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
157
162
|
if (Array.isArray(currentValue) && currentValue.length === 0) {
|
|
158
163
|
return acc;
|
|
159
164
|
}
|
|
160
|
-
if (field.type ===
|
|
165
|
+
if (field.type === FIELD_TYPES.CHECKBOX && currentValue !== true) {
|
|
161
166
|
return acc;
|
|
162
167
|
}
|
|
163
168
|
const label = field.label || field.placeholder || key;
|
|
@@ -180,18 +185,20 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
180
185
|
return resolveLabel(currentValue);
|
|
181
186
|
};
|
|
182
187
|
const resolveValue = () => {
|
|
183
|
-
if (field.type ===
|
|
188
|
+
if (field.type === FIELD_TYPES.FILE) {
|
|
184
189
|
const fileValue = currentValue;
|
|
185
190
|
return fileValue instanceof File ? fileValue.name : String(fileValue);
|
|
186
191
|
}
|
|
187
|
-
if (field.type ===
|
|
192
|
+
if (field.type === FIELD_TYPES.SELECT) {
|
|
188
193
|
return resolveSelectLabel();
|
|
189
194
|
}
|
|
190
195
|
// For custom fields with options (like custom selects), try to find the label
|
|
191
|
-
if (field.type ===
|
|
196
|
+
if (field.type === FIELD_TYPES.CUSTOM &&
|
|
197
|
+
'options' in field &&
|
|
198
|
+
field.options) {
|
|
192
199
|
return resolveSelectLabel();
|
|
193
200
|
}
|
|
194
|
-
if (field.type ===
|
|
201
|
+
if (field.type === FIELD_TYPES.DATE) {
|
|
195
202
|
const iso = akidate.toIsoDate(currentValue);
|
|
196
203
|
if (iso) {
|
|
197
204
|
// Use localized format with time if showTime is enabled
|
|
@@ -218,10 +225,15 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
218
225
|
}
|
|
219
226
|
return String(currentValue);
|
|
220
227
|
};
|
|
221
|
-
acc.push({
|
|
228
|
+
acc.push({
|
|
229
|
+
key,
|
|
230
|
+
label,
|
|
231
|
+
value: resolveValue(),
|
|
232
|
+
isExclude: excludeSectionKeys.has(key)
|
|
233
|
+
});
|
|
222
234
|
return acc;
|
|
223
235
|
}, []);
|
|
224
|
-
}, [flattenedSchema, formValues]);
|
|
236
|
+
}, [flattenedSchema, formValues, excludeSectionKeys]);
|
|
225
237
|
const resolveInitialVisibleKeys = React.useCallback(() => {
|
|
226
238
|
const storedKeys = readVisibleKeys(regularFields, storageKey);
|
|
227
239
|
const defaultKeys = deriveDefaultVisibleKeys(regularFields);
|
|
@@ -257,16 +269,6 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
257
269
|
writeVisibleKeys(storageKey, visibleKeys);
|
|
258
270
|
onVisibleFieldsChange === null || onVisibleFieldsChange === void 0 ? void 0 : onVisibleFieldsChange(visibleKeys);
|
|
259
271
|
}, [visibleKeys, onVisibleFieldsChange, storageKey]);
|
|
260
|
-
// Track previous mergedDefaultValues to avoid unnecessary resets
|
|
261
|
-
const previousMergedDefaultValuesRef = React.useRef(null);
|
|
262
|
-
React.useEffect(() => {
|
|
263
|
-
const serialised = JSON.stringify(mergedDefaultValues);
|
|
264
|
-
// Skip if the values haven't actually changed (deep comparison)
|
|
265
|
-
if (previousMergedDefaultValuesRef.current === serialised) {
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
previousMergedDefaultValuesRef.current = serialised;
|
|
269
|
-
}, [mergedDefaultValues]);
|
|
270
272
|
const normalisedValues = React.useMemo(() => normaliseOutputValues(flattenedSchema, formValues), [flattenedSchema, formValues]);
|
|
271
273
|
const hasInitialValuesRef = React.useRef(false);
|
|
272
274
|
React.useEffect(() => {
|
|
@@ -367,6 +369,9 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
367
369
|
clearedDefaults[key] = resolved;
|
|
368
370
|
}
|
|
369
371
|
});
|
|
372
|
+
// clearedDefaults carries an explicit cleared value (e.g. `null` for custom/file
|
|
373
|
+
// fields) for every key, so reset overwrites stale values instead of leaving the
|
|
374
|
+
// field untouched and resurrecting the filter (PUF-5666).
|
|
370
375
|
formMethods.reset(clearedDefaults, {
|
|
371
376
|
keepDirty: false,
|
|
372
377
|
keepTouched: false
|
|
@@ -419,7 +424,9 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
419
424
|
const updatedFormValues = Object.assign(Object.assign({}, currentFormValues), { [String(schemaField.key)]: nextValue });
|
|
420
425
|
// Normalize the values (removes empty/undefined entries)
|
|
421
426
|
const nextValues = normaliseOutputValues(flattenedSchema, updatedFormValues);
|
|
422
|
-
//
|
|
427
|
+
// updatedFormValues holds an explicit cleared value (e.g. `null` for custom/file
|
|
428
|
+
// fields) for the removed key, so reset overwrites the stale value rather than
|
|
429
|
+
// leaving it in place and resurrecting the filter (PUF-5666).
|
|
423
430
|
formMethods.reset(updatedFormValues, {
|
|
424
431
|
keepDirty: false,
|
|
425
432
|
keepTouched: false,
|
|
@@ -495,21 +502,21 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
495
502
|
const ariaLabel = getFieldAriaLabel(field);
|
|
496
503
|
const isDisabled = checkIsDisabled(field, formValues !== null && formValues !== void 0 ? formValues : {});
|
|
497
504
|
switch (field.type) {
|
|
498
|
-
case
|
|
505
|
+
case FIELD_TYPES.TEXT:
|
|
499
506
|
return (React.createElement(Input, { placeholder: field.placeholder, size: "large", allowClear: true, "aria-label": ariaLabel, disabled: isDisabled }));
|
|
500
|
-
case
|
|
507
|
+
case FIELD_TYPES.NUMBER:
|
|
501
508
|
return (React.createElement(InputNumber, { placeholder: field.placeholder, size: "large", className: "akinon-filter__field--number", "aria-label": ariaLabel, disabled: isDisabled }));
|
|
502
|
-
case
|
|
509
|
+
case FIELD_TYPES.SELECT:
|
|
503
510
|
return (React.createElement(Select, { placeholder: field.placeholder, size: "large", options: field.options, showSearch: true, optionFilterProp: "label", "aria-label": ariaLabel, disabled: isDisabled, mode: field.mode }));
|
|
504
|
-
case
|
|
511
|
+
case FIELD_TYPES.CHECKBOX:
|
|
505
512
|
return React.createElement(Checkbox, { disabled: isDisabled }, field.label);
|
|
506
|
-
case
|
|
513
|
+
case FIELD_TYPES.DATE:
|
|
507
514
|
return (React.createElement(DatePicker, { placeholder: field.placeholder, showTime: field.showTime, suffixIcon: "calendar", suffixIconSize: "16px", "aria-label": ariaLabel, disabled: isDisabled }));
|
|
508
|
-
case
|
|
515
|
+
case FIELD_TYPES.TEXTAREA:
|
|
509
516
|
return (React.createElement(InputTextArea, { placeholder: field.placeholder, autoSize: { minRows: 3, maxRows: 6 }, "aria-label": ariaLabel, disabled: isDisabled }));
|
|
510
|
-
case
|
|
517
|
+
case FIELD_TYPES.FILE:
|
|
511
518
|
return (React.createElement(FileFilterInput, { accept: field.fileAccept, "aria-label": ariaLabel, disabled: isDisabled }));
|
|
512
|
-
case
|
|
519
|
+
case FIELD_TYPES.CUSTOM:
|
|
513
520
|
if (typeof field.render === 'function') {
|
|
514
521
|
return field.render({
|
|
515
522
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -521,7 +528,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
521
528
|
});
|
|
522
529
|
}
|
|
523
530
|
return (React.createElement(Text, { type: "secondary", className: "akinon-filter__unsupported" }, i18n.t('form.unsupportedField', { field: String(field.type) })));
|
|
524
|
-
case
|
|
531
|
+
case FIELD_TYPES.SECTION:
|
|
525
532
|
// Section fields should not be rendered inline
|
|
526
533
|
// They are rendered separately after the main grid
|
|
527
534
|
return null;
|
|
@@ -530,7 +537,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
530
537
|
}
|
|
531
538
|
};
|
|
532
539
|
const renderFormField = (field) => {
|
|
533
|
-
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 ===
|
|
540
|
+
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)));
|
|
534
541
|
};
|
|
535
542
|
return (React.createElement(Card, { size: "small", className: "akinon-filter shadow", "data-testid": "akifilter-root" },
|
|
536
543
|
React.createElement(ConfigProvider, { theme: themeOverrides },
|
|
@@ -542,10 +549,11 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
542
549
|
visibleFields.map(renderFormField),
|
|
543
550
|
visibleFields.length === 0 ? (React.createElement("div", { className: "akinon-filter__empty" }, i18n.t('form.noVisibleFields'))) : null),
|
|
544
551
|
sectionFields.length > 0 && (React.createElement("div", { className: "akinon-filter__section-fields" }, sectionFields.map(section => {
|
|
545
|
-
return (React.createElement(Collapse, { key: section.key, defaultActiveKey: section.key, ghost: true, items: [
|
|
552
|
+
return (React.createElement(Collapse, { expandIconPosition: "end", key: section.key, expandIcon: ExpandIcon, defaultActiveKey: section.defaultExpanded === false ? [] : [section.key], ghost: true, items: [
|
|
546
553
|
{
|
|
547
554
|
key: section.key,
|
|
548
|
-
label: section.label,
|
|
555
|
+
label: (React.createElement(Title, { className: "akinon-filter__title", level: 4 }, section.label)),
|
|
556
|
+
headerClass: 'akinon-filter__section-header',
|
|
549
557
|
children: (React.createElement("div", { className: "akinon-filter__form-grid" }, section.fields.map(renderFormField)))
|
|
550
558
|
}
|
|
551
559
|
] }));
|
|
@@ -560,6 +568,15 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
|
|
|
560
568
|
}
|
|
561
569
|
}, page: modalPage, pageSize: modalPageSize }))));
|
|
562
570
|
};
|
|
571
|
+
export const ExpandIcon = ({ isActive }) => ({
|
|
572
|
+
name: 'chevron_down',
|
|
573
|
+
size: 10,
|
|
574
|
+
style: {
|
|
575
|
+
transform: isActive ? 'rotate(-180deg)' : 'rotate(0deg)',
|
|
576
|
+
transition: 'transform 0.2s ease-in-out',
|
|
577
|
+
marginTop: 8
|
|
578
|
+
}
|
|
579
|
+
});
|
|
563
580
|
const AkifilterEmptyState = () => {
|
|
564
581
|
const { t } = i18n;
|
|
565
582
|
return (React.createElement(Card, { size: "small", className: "akinon-filter shadow", "data-testid": "akifilter-empty" },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applied-filters.d.ts","sourceRoot":"","sources":["../../../src/components/applied-filters.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,KAAK,aAAa,GAAG;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"applied-filters.d.ts","sourceRoot":"","sources":["../../../src/components/applied-filters.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,KAAK,aAAa,GAAG;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,mCAI5B,mBAAmB,sBA+DrB,CAAC;AAEF,YAAY,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -9,7 +9,8 @@ export const AppliedFilters = ({ filters, onRemove, onClearAll }) => {
|
|
|
9
9
|
return (React.createElement("div", { className: "akinon-filter__applied", "data-testid": "akifilter-applied" },
|
|
10
10
|
React.createElement(Space, { className: "akinon-filter__applied-summary", size: 8 },
|
|
11
11
|
React.createElement(Text, { className: "akinon-filter__applied-label" }, i18n.t('applied.label')),
|
|
12
|
-
hasFilters ? (React.createElement(Space, { className: "akinon-filter__applied-items", size: 8, wrap: true }, filters.map(item => (React.createElement("div", { key: `${item.key}-${item.value}`, className:
|
|
12
|
+
hasFilters ? (React.createElement(Space, { className: "akinon-filter__applied-items", size: 8, wrap: true }, filters.map(item => (React.createElement("div", { key: `${item.key}-${item.value}`, className: `akinon-filter__chip${item.isExclude ? ' akinon-filter__chip--exclude' : ''}` },
|
|
13
|
+
item.isExclude ? (React.createElement(Icon, { icon: "exclude", size: 12, className: "akinon-filter__chip-exclude-icon" })) : null,
|
|
13
14
|
item.label ? (React.createElement("span", { className: "akinon-filter__chip-label" },
|
|
14
15
|
item.label,
|
|
15
16
|
":")) : null,
|
package/dist/esm/constants.d.ts
CHANGED
|
@@ -7,4 +7,19 @@ export declare const BOOLEAN_STRING: {
|
|
|
7
7
|
readonly TRUE: "true";
|
|
8
8
|
readonly FALSE: "false";
|
|
9
9
|
};
|
|
10
|
+
export declare const FIELD_TYPES: {
|
|
11
|
+
readonly TEXT: "text";
|
|
12
|
+
readonly NUMBER: "number";
|
|
13
|
+
readonly SELECT: "select";
|
|
14
|
+
readonly CHECKBOX: "checkbox";
|
|
15
|
+
readonly DATE: "date";
|
|
16
|
+
readonly TEXTAREA: "textarea";
|
|
17
|
+
readonly SECTION: "section";
|
|
18
|
+
readonly CUSTOM: "custom";
|
|
19
|
+
readonly FILE: "file";
|
|
20
|
+
};
|
|
21
|
+
export declare const FIELD_MODES: {
|
|
22
|
+
readonly TAGS: "tags";
|
|
23
|
+
readonly MULTIPLE: "multiple";
|
|
24
|
+
};
|
|
10
25
|
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,IAAI,CAAC;AACvC,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAC1C,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC,eAAO,MAAM,WAAW,eAAe,CAAC;AACxC,eAAO,MAAM,eAAe,wBAAwB,CAAC;AAErD,eAAO,MAAM,cAAc;;;CAGjB,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,IAAI,CAAC;AACvC,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAC1C,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC,eAAO,MAAM,WAAW,eAAe,CAAC;AACxC,eAAO,MAAM,eAAe,wBAAwB,CAAC;AAErD,eAAO,MAAM,cAAc;;;CAGjB,CAAC;AAEX,eAAO,MAAM,WAAW;;;;;;;;;;CAUd,CAAC;AAEX,eAAO,MAAM,WAAW;;;CAGd,CAAC"}
|
package/dist/esm/constants.js
CHANGED
|
@@ -7,3 +7,18 @@ export const BOOLEAN_STRING = {
|
|
|
7
7
|
TRUE: 'true',
|
|
8
8
|
FALSE: 'false'
|
|
9
9
|
};
|
|
10
|
+
export const FIELD_TYPES = {
|
|
11
|
+
TEXT: 'text',
|
|
12
|
+
NUMBER: 'number',
|
|
13
|
+
SELECT: 'select',
|
|
14
|
+
CHECKBOX: 'checkbox',
|
|
15
|
+
DATE: 'date',
|
|
16
|
+
TEXTAREA: 'textarea',
|
|
17
|
+
SECTION: 'section',
|
|
18
|
+
CUSTOM: 'custom',
|
|
19
|
+
FILE: 'file'
|
|
20
|
+
};
|
|
21
|
+
export const FIELD_MODES = {
|
|
22
|
+
TAGS: 'tags',
|
|
23
|
+
MULTIPLE: 'multiple'
|
|
24
|
+
};
|
package/dist/esm/styles.css
CHANGED
|
@@ -47,11 +47,11 @@
|
|
|
47
47
|
background-color: var(--color-ebonyClay-900);
|
|
48
48
|
flex: 1;
|
|
49
49
|
display: flex;
|
|
50
|
-
align-items:
|
|
50
|
+
align-items: flex-start;
|
|
51
51
|
border-radius: 5px;
|
|
52
52
|
padding: 6px 8px;
|
|
53
53
|
margin-right: 6px;
|
|
54
|
-
height: 36px;
|
|
54
|
+
min-height: 36px;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
.akinon-filter__applied-label {
|
|
@@ -59,16 +59,13 @@
|
|
|
59
59
|
font-weight: 600;
|
|
60
60
|
font-size: 13px;
|
|
61
61
|
position: relative;
|
|
62
|
-
|
|
62
|
+
white-space: nowrap;
|
|
63
|
+
top: 7px;
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
.akinon-
|
|
66
|
-
margin-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
.akinon-filter__common-filters-title {
|
|
70
|
-
color: var(--color-gray-500);
|
|
71
|
-
margin-bottom: 1rem;
|
|
66
|
+
.akinon-filter__section-header span {
|
|
67
|
+
margin-inline-end: unset !important;
|
|
68
|
+
flex: unset !important;
|
|
72
69
|
}
|
|
73
70
|
|
|
74
71
|
.akinon-filter__form-grid {
|
|
@@ -121,8 +118,10 @@
|
|
|
121
118
|
|
|
122
119
|
.akinon-filter__applied-items {
|
|
123
120
|
display: flex;
|
|
121
|
+
flex: 1;
|
|
124
122
|
flex-wrap: wrap;
|
|
125
123
|
gap: 8px;
|
|
124
|
+
min-width: 0;
|
|
126
125
|
}
|
|
127
126
|
|
|
128
127
|
.akinon-filter__chip {
|
|
@@ -136,6 +135,16 @@
|
|
|
136
135
|
height: 24px;
|
|
137
136
|
}
|
|
138
137
|
|
|
138
|
+
.akinon-filter__chip--exclude {
|
|
139
|
+
background-color: #ffe0e4;
|
|
140
|
+
border: 1px solid #ff354e;
|
|
141
|
+
height: 23px;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.akinon-filter__chip-exclude-icon {
|
|
145
|
+
margin-right: 5px;
|
|
146
|
+
}
|
|
147
|
+
|
|
139
148
|
.akinon-filter__chip-label {
|
|
140
149
|
font-weight: 600;
|
|
141
150
|
color: var(--color-ebonyClay-300);
|
|
@@ -162,7 +171,7 @@
|
|
|
162
171
|
color: color(--color-ebonyClay-500);
|
|
163
172
|
font-size: 12px;
|
|
164
173
|
position: relative;
|
|
165
|
-
top:
|
|
174
|
+
top: 8px;
|
|
166
175
|
}
|
|
167
176
|
|
|
168
177
|
.akinon-filter__modal-list {
|
|
@@ -187,13 +196,13 @@
|
|
|
187
196
|
column-gap: 8px; /* replaces Ant's label padding, zeroed out below */
|
|
188
197
|
line-height: 1.4;
|
|
189
198
|
margin-inline-start: 0; /* override Ant's adjacent-sibling margin */
|
|
199
|
+
color: var(--color-white);
|
|
190
200
|
}
|
|
191
201
|
|
|
192
202
|
.akinon-filter__modal-list
|
|
193
203
|
.akinon-filter__modal-checkbox.ant-checkbox-wrapper
|
|
194
204
|
> .ant-checkbox {
|
|
195
205
|
align-self: start;
|
|
196
|
-
margin-block-start: 0.15em; /* em-relative baseline nudge */
|
|
197
206
|
}
|
|
198
207
|
|
|
199
208
|
.akinon-filter__modal-list
|
|
@@ -253,6 +262,11 @@
|
|
|
253
262
|
width: auto;
|
|
254
263
|
}
|
|
255
264
|
|
|
265
|
+
.akinon-filter .akinon-select-multiple .akinon-select-selector {
|
|
266
|
+
height: 40px;
|
|
267
|
+
overflow: hidden;
|
|
268
|
+
}
|
|
269
|
+
|
|
256
270
|
/* Modal window. */
|
|
257
271
|
|
|
258
272
|
.akinon-filter__modal-toolbar {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FieldValues } from '@akinon/akiform';
|
|
2
|
+
import { FIELD_TYPES } from '../constants';
|
|
2
3
|
import type { AkifilterField, AkifilterSchema } from '../types';
|
|
3
4
|
/**
|
|
4
5
|
* Flattens schema by extracting all nested fields from section fields.
|
|
@@ -11,9 +12,17 @@ export declare const flattenSchema: <TFieldValues extends FieldValues = FieldVal
|
|
|
11
12
|
export declare const partitionSchema: <TFieldValues extends FieldValues = FieldValues>(schema: AkifilterSchema<TFieldValues>) => {
|
|
12
13
|
regularFields: AkifilterSchema<TFieldValues>;
|
|
13
14
|
sectionFields: Array<AkifilterField<TFieldValues> & {
|
|
15
|
+
type: typeof FIELD_TYPES.SECTION;
|
|
14
16
|
fields: AkifilterSchema<TFieldValues>;
|
|
17
|
+
defaultExpanded?: boolean;
|
|
18
|
+
isExcludeSection?: boolean;
|
|
15
19
|
}>;
|
|
16
20
|
};
|
|
21
|
+
export declare const deriveExcludeSectionKeys: <TFieldValues extends FieldValues = FieldValues>(sectionFields: Array<AkifilterField<TFieldValues> & {
|
|
22
|
+
type: typeof FIELD_TYPES.SECTION;
|
|
23
|
+
fields: AkifilterSchema<TFieldValues>;
|
|
24
|
+
isExcludeSection?: boolean;
|
|
25
|
+
}>) => Set<string>;
|
|
17
26
|
export declare const getDisplayLabel: <TFieldValues extends FieldValues = FieldValues>(field: AkifilterField<TFieldValues>) => string;
|
|
18
27
|
export declare const getFieldAriaLabel: <TFieldValues extends FieldValues = FieldValues>(field: AkifilterField<TFieldValues>) => string;
|
|
19
28
|
export declare const ensureSchemaOrder: <TFieldValues extends FieldValues = FieldValues>(schema: AkifilterSchema<TFieldValues>, keys: string[]) => string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/utils/schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/utils/schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,OAAO,EAAsC,WAAW,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEhE;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,YAAY,SAAS,WAAW,GAAG,WAAW,EAC1E,QAAQ,eAAe,CAAC,YAAY,CAAC,KACpC,eAAe,CAAC,YAAY,CAW9B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,YAAY,SAAS,WAAW,GAAG,WAAW,EAC5E,QAAQ,eAAe,CAAC,YAAY,CAAC,KACpC;IACD,aAAa,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;IAC7C,aAAa,EAAE,KAAK,CAClB,cAAc,CAAC,YAAY,CAAC,GAAG;QAC7B,IAAI,EAAE,OAAO,WAAW,CAAC,OAAO,CAAC;QACjC,MAAM,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;QACtC,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;KAC5B,CACF,CAAC;CAwBH,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,eAAe,KAAK,CAClB,cAAc,CAAC,YAAY,CAAC,GAAG;IAC7B,IAAI,EAAE,OAAO,WAAW,CAAC,OAAO,CAAC;IACjC,MAAM,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;IACtC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CACF,KACA,GAAG,CAAC,MAAM,CAKV,CAAC;AAEJ,eAAO,MAAM,eAAe,GAAI,YAAY,SAAS,WAAW,GAAG,WAAW,EAC5E,OAAO,cAAc,CAAC,YAAY,CAAC,KAClC,MAEF,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,OAAO,cAAc,CAAC,YAAY,CAAC,KAClC,MAEF,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,QAAQ,eAAe,CAAC,YAAY,CAAC,EACrC,MAAM,MAAM,EAAE,KACb,MAAM,EAGR,CAAC;AAkBF;;GAEG;AACH,eAAO,MAAM,sBAAsB,GACjC,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,OAAO,cAAc,CAAC,YAAY,CAAC,EACnC,aAAa,YAAY,EACzB,iBAAiB,OAAO,KACvB,OAAO,GAAG,SAC8D,CAAC;AAE5E,eAAO,MAAM,wBAAwB,GACnC,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,QAAQ,eAAe,CAAC,YAAY,CAAC,KACpC,MAAM,EAUR,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,QAAQ,eAAe,CAAC,YAAY,CAAC,KACpC,OAAO,CAAC,YAAY,CAQtB,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,YAAY,SAAS,WAAW,EACnE,OAAO,cAAc,CAAC,YAAY,CAAC,KAClC,OAA4C,CAAC;AAEhD,eAAO,MAAM,uBAAuB,GAClC,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,QAAQ,eAAe,CAAC,YAAY,CAAC,EACrC,SAAS,OAAO,CAAC,YAAY,CAAC,KAC7B,OAAO,CAAC,YAAY,CA0CtB,CAAC"}
|
package/dist/esm/utils/schema.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { akidate } from '@akinon/akidate';
|
|
2
2
|
import { isBoolean, isFunction } from 'lodash-es';
|
|
3
|
-
import { DEFAULT_VISIBLE_COUNT } from '../constants';
|
|
3
|
+
import { DEFAULT_VISIBLE_COUNT, FIELD_MODES, FIELD_TYPES } from '../constants';
|
|
4
4
|
/**
|
|
5
5
|
* Flattens schema by extracting all nested fields from section fields.
|
|
6
6
|
* This is used for storage operations and form value management.
|
|
7
7
|
*/
|
|
8
8
|
export const flattenSchema = (schema) => {
|
|
9
9
|
return schema.reduce((acc, field) => {
|
|
10
|
-
if (field.type ===
|
|
10
|
+
if (field.type === FIELD_TYPES.SECTION && 'fields' in field) {
|
|
11
11
|
// Recursively flatten nested section fields
|
|
12
12
|
return [
|
|
13
13
|
...acc,
|
|
@@ -24,7 +24,7 @@ export const partitionSchema = (schema) => {
|
|
|
24
24
|
const regularFields = [];
|
|
25
25
|
const sectionFields = [];
|
|
26
26
|
schema.forEach(field => {
|
|
27
|
-
if (field.type ===
|
|
27
|
+
if (field.type === FIELD_TYPES.SECTION) {
|
|
28
28
|
sectionFields.push(field);
|
|
29
29
|
}
|
|
30
30
|
else {
|
|
@@ -33,6 +33,9 @@ export const partitionSchema = (schema) => {
|
|
|
33
33
|
});
|
|
34
34
|
return { regularFields, sectionFields };
|
|
35
35
|
};
|
|
36
|
+
export const deriveExcludeSectionKeys = (sectionFields) => new Set(sectionFields
|
|
37
|
+
.filter(s => s.isExcludeSection)
|
|
38
|
+
.flatMap(s => s.fields.map(f => String(f.key))));
|
|
36
39
|
export const getDisplayLabel = (field) => {
|
|
37
40
|
return field.label || field.placeholder || String(field.key);
|
|
38
41
|
};
|
|
@@ -84,15 +87,16 @@ export const normaliseValuesBySchema = (schema, values) => {
|
|
|
84
87
|
return acc;
|
|
85
88
|
}
|
|
86
89
|
const currentValue = values[key];
|
|
87
|
-
if (field.type ===
|
|
90
|
+
if (field.type === FIELD_TYPES.DATE) {
|
|
88
91
|
const parsed = akidate.parse(currentValue);
|
|
89
92
|
if (parsed) {
|
|
90
93
|
acc[key] = parsed;
|
|
91
94
|
return acc;
|
|
92
95
|
}
|
|
93
96
|
}
|
|
94
|
-
if (field.type ===
|
|
95
|
-
(field.mode ===
|
|
97
|
+
if (field.type === FIELD_TYPES.SELECT &&
|
|
98
|
+
(field.mode === FIELD_MODES.MULTIPLE ||
|
|
99
|
+
field.mode === FIELD_MODES.TAGS) &&
|
|
96
100
|
currentValue != null &&
|
|
97
101
|
!Array.isArray(currentValue)) {
|
|
98
102
|
acc[key] = [currentValue];
|
package/dist/esm/utils/values.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { akidate } from '@akinon/akidate';
|
|
2
|
-
import { DATE_FORMAT, DATETIME_FORMAT } from '../constants';
|
|
2
|
+
import { DATE_FORMAT, DATETIME_FORMAT, FIELD_TYPES } from '../constants';
|
|
3
3
|
export const shouldPersistValue = (field, value) => {
|
|
4
4
|
if (value === undefined || value === null) {
|
|
5
5
|
return false;
|
|
@@ -10,10 +10,10 @@ export const shouldPersistValue = (field, value) => {
|
|
|
10
10
|
if (Array.isArray(value) && value.length === 0) {
|
|
11
11
|
return false;
|
|
12
12
|
}
|
|
13
|
-
if ((field === null || field === void 0 ? void 0 : field.type) ===
|
|
13
|
+
if ((field === null || field === void 0 ? void 0 : field.type) === FIELD_TYPES.CHECKBOX && value !== true) {
|
|
14
14
|
return false;
|
|
15
15
|
}
|
|
16
|
-
if ((field === null || field === void 0 ? void 0 : field.type) ===
|
|
16
|
+
if ((field === null || field === void 0 ? void 0 : field.type) === FIELD_TYPES.FILE) {
|
|
17
17
|
return value instanceof File;
|
|
18
18
|
}
|
|
19
19
|
return true;
|
|
@@ -29,7 +29,7 @@ export const normaliseOutputValues = (schema, values) => {
|
|
|
29
29
|
return acc;
|
|
30
30
|
}
|
|
31
31
|
let normalisedValue = rawValue;
|
|
32
|
-
if ((field === null || field === void 0 ? void 0 : field.type) ===
|
|
32
|
+
if ((field === null || field === void 0 ? void 0 : field.type) === FIELD_TYPES.DATE) {
|
|
33
33
|
const normalised = akidate.toIsoDate(rawValue);
|
|
34
34
|
if (!normalised) {
|
|
35
35
|
return acc;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akinon/akifilter",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Akifilter is a filtering library for Akinon frontend applications.",
|
|
6
6
|
"type": "module",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"lodash-es": "^4.17.21",
|
|
16
16
|
"@akinon/akiform": "1.1.9",
|
|
17
17
|
"@akinon/akidate": "1.2.7",
|
|
18
|
-
"@akinon/icons": "1.3.2",
|
|
19
18
|
"@akinon/akilocale": "1.2.8",
|
|
19
|
+
"@akinon/icons": "1.3.2",
|
|
20
20
|
"@akinon/ui-button": "1.5.3",
|
|
21
21
|
"@akinon/ui-card": "1.2.10",
|
|
22
22
|
"@akinon/ui-checkbox": "1.4.10",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@akinon/ui-select": "1.4.13",
|
|
30
30
|
"@akinon/ui-space": "1.4.10",
|
|
31
31
|
"@akinon/ui-typography": "1.2.7",
|
|
32
|
-
"@akinon/ui-upload": "1.
|
|
32
|
+
"@akinon/ui-upload": "1.6.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/lodash-es": "^4.17.12",
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"copyfiles": "^2.4.1",
|
|
38
38
|
"rimraf": "^5.0.5",
|
|
39
39
|
"typescript": "*",
|
|
40
|
+
"@akinon/akiform-builder": "1.6.0",
|
|
40
41
|
"@akinon/typescript-config": "1.1.8",
|
|
41
|
-
"@akinon/akiform-builder": "1.5.11",
|
|
42
42
|
"@akinon/utils": "1.2.11",
|
|
43
43
|
"@akinon/ui-theme": "1.3.1",
|
|
44
44
|
"@akinon/vitest-config": "1.1.8"
|