@akinon/akifilter 1.0.0 → 1.0.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"akifilter.d.ts","sourceRoot":"","sources":["../../src/akifilter.tsx"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AAGtB,OAAO,EAIL,WAAW,EAEX,IAAI,EAGL,MAAM,iBAAiB,CAAC;AAUzB,OAAO,KAAK,MAAM,OAAO,CAAC;AAsB1B,OAAO,KAAK,EAAkB,eAAe,EAAE,MAAM,SAAS,CAAC;AAU/D,KAAK,oBAAoB,GAAG,WAAW,CAAC;AAExC,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;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAohBF,eAAO,MAAM,SAAS;KACpB,YAAY,SAAS,oBAAoB,uBAElC,cAAc,CAAC,YAAY,CAAC;;CAmBpC,CAAC"}
1
+ {"version":3,"file":"akifilter.d.ts","sourceRoot":"","sources":["../../src/akifilter.tsx"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AAGtB,OAAO,EAIL,WAAW,EAEX,IAAI,EAGL,MAAM,iBAAiB,CAAC;AAUzB,OAAO,KAAK,MAAM,OAAO,CAAC;AAsB1B,OAAO,KAAK,EAAkB,eAAe,EAAE,MAAM,SAAS,CAAC;AAU/D,KAAK,oBAAoB,GAAG,WAAW,CAAC;AA0BxC,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;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAulBF,eAAO,MAAM,SAAS;KACpB,YAAY,SAAS,oBAAoB,uBAElC,cAAc,CAAC,YAAY,CAAC;;CAmBpC,CAAC"}
@@ -36,6 +36,23 @@ const use_debounced_value_1 = require("./hooks/use-debounced-value");
36
36
  const i18n_1 = require("./i18n");
37
37
  const schema_1 = require("./utils/schema");
38
38
  const values_1 = require("./utils/values");
39
+ const resolveClearedFieldValue = (field, defaultValue) => {
40
+ if (defaultValue !== undefined) {
41
+ return defaultValue;
42
+ }
43
+ switch (field.type) {
44
+ case 'text':
45
+ case 'textarea':
46
+ return '';
47
+ case 'checkbox':
48
+ return false;
49
+ case 'date':
50
+ case 'select':
51
+ return null;
52
+ default:
53
+ return undefined;
54
+ }
55
+ };
39
56
  const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onValuesChange, onVisibleFieldsChange, onImportCsv, onImportXls, onClearAll, enableImportCsv, enableImportXls }) => {
40
57
  const storageKey = react_1.default.useMemo(() => (0, storage_1.buildStorageKey)(filterSchema, storageNamespace), [filterSchema, storageNamespace]);
41
58
  const schemaDefaults = react_1.default.useMemo(() => (0, schema_1.normaliseValuesBySchema)(filterSchema, (0, schema_1.extractDefaultValues)(filterSchema)), [filterSchema]);
@@ -73,7 +90,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
73
90
  if (field.type === 'checkbox' && currentValue !== true) {
74
91
  return acc;
75
92
  }
76
- const label = field.placeholder || field.label || key;
93
+ const label = field.label || field.placeholder || key;
77
94
  const resolveSelectLabel = () => {
78
95
  var _a;
79
96
  if (!('options' in field) || !field.options) {
@@ -137,12 +154,25 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
137
154
  formMethods.reset(mergedDefaultValues);
138
155
  }, [formMethods, mergedDefaultValues]);
139
156
  const normalisedValues = react_1.default.useMemo(() => (0, values_1.normaliseOutputValues)(filterSchema, formValues), [filterSchema, formValues]);
140
- const initialOutputValues = react_1.default.useMemo(() => (0, values_1.normaliseOutputValues)(filterSchema, mergedDefaultValues), [filterSchema, mergedDefaultValues]);
141
- const hasInitialValues = react_1.default.useMemo(() => Object.keys(initialOutputValues).length > 0, [initialOutputValues]);
157
+ const hasInitialValuesRef = react_1.default.useRef(false);
158
+ react_1.default.useEffect(() => {
159
+ const initialValues = (0, values_1.normaliseOutputValues)(filterSchema, mergedDefaultValues);
160
+ hasInitialValuesRef.current = Object.keys(initialValues).length > 0;
161
+ }, [filterSchema, mergedDefaultValues]);
142
162
  const serialisedValues = react_1.default.useMemo(() => JSON.stringify(normalisedValues), [normalisedValues]);
143
163
  const debouncedSerialisedValues = (0, use_debounced_value_1.useDebouncedValue)(serialisedValues, constants_1.FILTER_DEBOUNCE_DELAY);
144
164
  const lastPersistedValuesRef = react_1.default.useRef(null);
145
165
  const hasEmittedValuesRef = react_1.default.useRef(false);
166
+ const persistValues = react_1.default.useCallback((values, serialised) => {
167
+ const nextSerialised = serialised !== null && serialised !== void 0 ? serialised : JSON.stringify(values);
168
+ lastPersistedValuesRef.current = nextSerialised;
169
+ if (Object.keys(values).length === 0) {
170
+ (0, storage_1.clearStoredValues)(storageKey);
171
+ return nextSerialised;
172
+ }
173
+ (0, storage_1.writeStoredValues)(storageKey, values);
174
+ return nextSerialised;
175
+ }, [storageKey]);
146
176
  react_1.default.useEffect(() => {
147
177
  if (debouncedSerialisedValues == null) {
148
178
  return;
@@ -153,30 +183,45 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
153
183
  }
154
184
  const parsedValues = JSON.parse(debouncedSerialisedValues);
155
185
  const isEmpty = Object.keys(parsedValues).length === 0;
156
- if (!hasEmittedValuesRef.current && isEmpty && !hasInitialValues) {
186
+ if (!hasEmittedValuesRef.current &&
187
+ isEmpty &&
188
+ !hasInitialValuesRef.current) {
157
189
  hasEmittedValuesRef.current = true;
158
- lastPersistedValuesRef.current = debouncedSerialisedValues;
159
- (0, storage_1.clearStoredValues)(storageKey);
190
+ persistValues(parsedValues, debouncedSerialisedValues);
160
191
  return;
161
192
  }
162
193
  hasEmittedValuesRef.current = true;
163
- lastPersistedValuesRef.current = debouncedSerialisedValues;
164
194
  onValuesChange === null || onValuesChange === void 0 ? void 0 : onValuesChange(parsedValues);
165
- if (isEmpty) {
166
- (0, storage_1.clearStoredValues)(storageKey);
167
- }
168
- else {
169
- (0, storage_1.writeStoredValues)(storageKey, parsedValues);
170
- }
171
- }, [debouncedSerialisedValues, hasInitialValues, onValuesChange, storageKey]);
195
+ persistValues(parsedValues, debouncedSerialisedValues);
196
+ }, [debouncedSerialisedValues, onValuesChange, persistValues]);
172
197
  react_1.default.useEffect(() => {
173
198
  lastPersistedValuesRef.current = null;
174
199
  }, [storageKey]);
175
200
  const handleClearAll = react_1.default.useCallback(() => {
176
- formMethods.reset(baseDefaultValues);
201
+ const clearedDefaults = Object.assign({}, baseDefaultValues);
202
+ filterSchema.forEach(field => {
203
+ const key = String(field.key);
204
+ const defaultValue = baseDefaultValues[key];
205
+ const resolved = resolveClearedFieldValue(field, defaultValue);
206
+ if (resolved === undefined) {
207
+ delete clearedDefaults[key];
208
+ }
209
+ else {
210
+ clearedDefaults[key] = resolved;
211
+ }
212
+ });
213
+ formMethods.reset(clearedDefaults, {
214
+ keepDirty: false,
215
+ keepTouched: false
216
+ });
177
217
  onClearAll === null || onClearAll === void 0 ? void 0 : onClearAll();
178
- (0, storage_1.clearStoredValues)(storageKey);
179
- }, [baseDefaultValues, formMethods, onClearAll, storageKey]);
218
+ const nextValues = (0, values_1.normaliseOutputValues)(filterSchema, clearedDefaults);
219
+ hasInitialValuesRef.current = Object.keys(nextValues).length > 0;
220
+ const nextSerialised = persistValues(nextValues);
221
+ hasEmittedValuesRef.current = true;
222
+ lastPersistedValuesRef.current = nextSerialised !== null && nextSerialised !== void 0 ? nextSerialised : null;
223
+ onValuesChange === null || onValuesChange === void 0 ? void 0 : onValuesChange(nextValues);
224
+ }, [baseDefaultValues, filterSchema, formMethods, onClearAll, persistValues]);
180
225
  const handleOpenModal = react_1.default.useCallback(() => {
181
226
  setIsModalOpen(true);
182
227
  setSearchTerm('');
@@ -203,10 +248,26 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
203
248
  return;
204
249
  }
205
250
  const defaultValue = baseDefaultValues[String(schemaField.key)];
206
- formMethods.resetField(schemaField.key, {
207
- defaultValue
251
+ const fieldPath = schemaField.key;
252
+ const nextValue = resolveClearedFieldValue(schemaField, defaultValue);
253
+ formMethods.setValue(fieldPath, nextValue, {
254
+ shouldDirty: false,
255
+ shouldTouch: false,
256
+ shouldValidate: false
208
257
  });
209
- }, [baseDefaultValues, filterSchema, formMethods]);
258
+ const nextValues = (0, values_1.normaliseOutputValues)(filterSchema, formMethods.getValues());
259
+ const nextSerialised = persistValues(nextValues);
260
+ hasEmittedValuesRef.current = true;
261
+ lastPersistedValuesRef.current = nextSerialised !== null && nextSerialised !== void 0 ? nextSerialised : null;
262
+ hasInitialValuesRef.current = Object.keys(nextValues).length > 0;
263
+ onValuesChange === null || onValuesChange === void 0 ? void 0 : onValuesChange(nextValues);
264
+ }, [
265
+ baseDefaultValues,
266
+ filterSchema,
267
+ formMethods,
268
+ onValuesChange,
269
+ persistValues
270
+ ]);
210
271
  const filteredFields = react_1.default.useMemo(() => {
211
272
  const normalisedTerm = searchTerm.trim().toLowerCase();
212
273
  if (!normalisedTerm) {
@@ -236,7 +297,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
236
297
  case 'checkbox':
237
298
  return react_1.default.createElement(ui_checkbox_1.Checkbox, null, field.label);
238
299
  case 'date':
239
- return (react_1.default.createElement(ui_date_picker_1.DatePicker, { placeholder: field.placeholder, size: "large", showTime: field.showTime, suffixIcon: "calendar", suffixIconSize: "16px", "aria-label": ariaLabel }));
300
+ return (react_1.default.createElement(ui_date_picker_1.DatePicker, { placeholder: field.placeholder, showTime: field.showTime, suffixIcon: "calendar", suffixIconSize: "16px", "aria-label": ariaLabel }));
240
301
  case 'textarea':
241
302
  return (react_1.default.createElement(ui_input_1.InputTextArea, { placeholder: field.placeholder, autoSize: { minRows: 3, maxRows: 6 }, "aria-label": ariaLabel }));
242
303
  case 'custom':
@@ -261,7 +322,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
261
322
  react_1.default.createElement("div", { className: "akinon-filter__body" },
262
323
  react_1.default.createElement(akiform_1.Akiform, { layout: "vertical", className: "akinon-filter__form" },
263
324
  react_1.default.createElement("div", { className: "akinon-filter__form-grid", "data-testid": "akifilter-form-grid" },
264
- visibleFields.map(field => (react_1.default.createElement(akiform_1.FormItem, { key: String(field.key), control: formMethods.control, name: field.key, tooltip: field.tooltip, help: field.help, labelDescription: field.labelDescription, required: Boolean(field.validation), valuePropName: field.type === 'checkbox' ? 'checked' : undefined }, renderFieldComponent(field)))),
325
+ visibleFields.map(field => (react_1.default.createElement(akiform_1.FormItem, { 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 === 'checkbox' ? 'checked' : undefined }, renderFieldComponent(field)))),
265
326
  visibleFields.length === 0 ? (react_1.default.createElement("div", { className: "akinon-filter__empty" }, i18n_1.i18n.t('form.noVisibleFields'))) : null))),
266
327
  react_1.default.createElement(visibility_modal_1.VisibilityModal, { open: isModalOpen, onClose: handleCloseModal, searchTerm: searchTerm, paginatedFields: paginatedFields, filteredCount: filteredFields.length, visibleKeys: visibleKeys, onSearchTermChange: value => {
267
328
  setSearchTerm(value);
@@ -1 +1 @@
1
- {"version":3,"file":"theme-overrides.d.ts","sourceRoot":"","sources":["../../../src/common/theme-overrides.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAEnC,eAAO,MAAM,cAAc,EAAE,WAsB5B,CAAC"}
1
+ {"version":3,"file":"theme-overrides.d.ts","sourceRoot":"","sources":["../../../src/common/theme-overrides.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAEnC,eAAO,MAAM,cAAc,EAAE,WAkB5B,CAAC"}
@@ -3,7 +3,4 @@ var _a, _b;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.themeOverrides = void 0;
5
5
  const ui_theme_1 = require("@akinon/ui-theme");
6
- exports.themeOverrides = Object.assign(Object.assign({}, ui_theme_1.theme), { algorithm: ui_theme_1.theme.algorithm, token: {
7
- colorTextBase: ui_theme_1.theme.colors.ebonyClay['900'],
8
- colorText: ui_theme_1.theme.colors.ebonyClay['900']
9
- }, components: Object.assign(Object.assign({}, ui_theme_1.theme.components), { Typography: Object.assign(Object.assign({}, (_a = ui_theme_1.theme.components) === null || _a === void 0 ? void 0 : _a.Typography), { colorTextHeading: ui_theme_1.theme.colors.neutral['100'], colorText: ui_theme_1.theme.colors.neutral['500'], titleMarginBottom: 0 }), Modal: Object.assign(Object.assign({}, (_b = ui_theme_1.theme.components) === null || _b === void 0 ? void 0 : _b.Modal), { headerBg: ui_theme_1.theme.colors.ebonyClay['600'], contentBg: ui_theme_1.theme.colors.ebonyClay['600'], titleColor: ui_theme_1.theme.colors.neutral['200'] }) }) });
6
+ exports.themeOverrides = Object.assign(Object.assign({}, ui_theme_1.theme), { algorithm: ui_theme_1.theme.algorithm, components: Object.assign(Object.assign({}, ui_theme_1.theme.components), { Typography: Object.assign(Object.assign({}, (_a = ui_theme_1.theme.components) === null || _a === void 0 ? void 0 : _a.Typography), { colorTextHeading: ui_theme_1.theme.colors.neutral['100'], colorText: ui_theme_1.theme.colors.neutral['500'], titleMarginBottom: 0 }), Modal: Object.assign(Object.assign({}, (_b = ui_theme_1.theme.components) === null || _b === void 0 ? void 0 : _b.Modal), { headerBg: ui_theme_1.theme.colors.ebonyClay['600'], contentBg: ui_theme_1.theme.colors.ebonyClay['600'], titleColor: ui_theme_1.theme.colors.neutral['200'] }) }) });
@@ -54,7 +54,7 @@
54
54
  .akinon-filter__form-grid {
55
55
  display: grid;
56
56
  grid-template-columns: repeat(4, minmax(0, 1fr));
57
- gap: 16px;
57
+ gap: 8px;
58
58
  }
59
59
 
60
60
  .akinon-filter__form-grid > .akinon-form-item {
@@ -120,7 +120,7 @@
120
120
  color: color(--color-ebonyClay-500);
121
121
  font-size: 12px;
122
122
  position: relative;
123
- top: 2px;
123
+ top: 1px;
124
124
  }
125
125
 
126
126
  .akinon-filter__modal-list {
@@ -172,11 +172,13 @@
172
172
  max-width: 360px;
173
173
  }
174
174
 
175
- /* Modal window. */
176
-
177
- .akinon-filter__modal {
175
+ .akinon-filter__field--number {
176
+ display: block;
177
+ width: auto;
178
178
  }
179
179
 
180
+ /* Modal window. */
181
+
180
182
  .akinon-filter__modal-toolbar {
181
183
  margin-bottom: 1rem;
182
184
  }
@@ -4,7 +4,7 @@ exports.normaliseValuesBySchema = exports.extractDefaultValues = exports.deriveD
4
4
  const akidate_1 = require("@akinon/akidate");
5
5
  const constants_1 = require("../constants");
6
6
  const getDisplayLabel = (field) => {
7
- return field.placeholder || field.label || String(field.key);
7
+ return field.label || field.placeholder || String(field.key);
8
8
  };
9
9
  exports.getDisplayLabel = getDisplayLabel;
10
10
  const getFieldAriaLabel = (field) => {
@@ -1 +1 @@
1
- {"version":3,"file":"akifilter.d.ts","sourceRoot":"","sources":["../../src/akifilter.tsx"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AAGtB,OAAO,EAIL,WAAW,EAEX,IAAI,EAGL,MAAM,iBAAiB,CAAC;AAUzB,OAAO,KAAK,MAAM,OAAO,CAAC;AAsB1B,OAAO,KAAK,EAAkB,eAAe,EAAE,MAAM,SAAS,CAAC;AAU/D,KAAK,oBAAoB,GAAG,WAAW,CAAC;AAExC,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;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAohBF,eAAO,MAAM,SAAS;KACpB,YAAY,SAAS,oBAAoB,uBAElC,cAAc,CAAC,YAAY,CAAC;;CAmBpC,CAAC"}
1
+ {"version":3,"file":"akifilter.d.ts","sourceRoot":"","sources":["../../src/akifilter.tsx"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AAGtB,OAAO,EAIL,WAAW,EAEX,IAAI,EAGL,MAAM,iBAAiB,CAAC;AAUzB,OAAO,KAAK,MAAM,OAAO,CAAC;AAsB1B,OAAO,KAAK,EAAkB,eAAe,EAAE,MAAM,SAAS,CAAC;AAU/D,KAAK,oBAAoB,GAAG,WAAW,CAAC;AA0BxC,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;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAulBF,eAAO,MAAM,SAAS;KACpB,YAAY,SAAS,oBAAoB,uBAElC,cAAc,CAAC,YAAY,CAAC;;CAmBpC,CAAC"}
@@ -33,6 +33,23 @@ import { useDebouncedValue } from './hooks/use-debounced-value';
33
33
  import { i18n } from './i18n';
34
34
  import { deriveDefaultVisibleKeys, ensureSchemaOrder, extractDefaultValues, getFieldAriaLabel, normaliseValuesBySchema } from './utils/schema';
35
35
  import { normaliseOutputValues } from './utils/values';
36
+ const resolveClearedFieldValue = (field, defaultValue) => {
37
+ if (defaultValue !== undefined) {
38
+ return defaultValue;
39
+ }
40
+ switch (field.type) {
41
+ case 'text':
42
+ case 'textarea':
43
+ return '';
44
+ case 'checkbox':
45
+ return false;
46
+ case 'date':
47
+ case 'select':
48
+ return null;
49
+ default:
50
+ return undefined;
51
+ }
52
+ };
36
53
  const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onValuesChange, onVisibleFieldsChange, onImportCsv, onImportXls, onClearAll, enableImportCsv, enableImportXls }) => {
37
54
  const storageKey = React.useMemo(() => buildStorageKey(filterSchema, storageNamespace), [filterSchema, storageNamespace]);
38
55
  const schemaDefaults = React.useMemo(() => normaliseValuesBySchema(filterSchema, extractDefaultValues(filterSchema)), [filterSchema]);
@@ -70,7 +87,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
70
87
  if (field.type === 'checkbox' && currentValue !== true) {
71
88
  return acc;
72
89
  }
73
- const label = field.placeholder || field.label || key;
90
+ const label = field.label || field.placeholder || key;
74
91
  const resolveSelectLabel = () => {
75
92
  var _a;
76
93
  if (!('options' in field) || !field.options) {
@@ -134,12 +151,25 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
134
151
  formMethods.reset(mergedDefaultValues);
135
152
  }, [formMethods, mergedDefaultValues]);
136
153
  const normalisedValues = React.useMemo(() => normaliseOutputValues(filterSchema, formValues), [filterSchema, formValues]);
137
- const initialOutputValues = React.useMemo(() => normaliseOutputValues(filterSchema, mergedDefaultValues), [filterSchema, mergedDefaultValues]);
138
- const hasInitialValues = React.useMemo(() => Object.keys(initialOutputValues).length > 0, [initialOutputValues]);
154
+ const hasInitialValuesRef = React.useRef(false);
155
+ React.useEffect(() => {
156
+ const initialValues = normaliseOutputValues(filterSchema, mergedDefaultValues);
157
+ hasInitialValuesRef.current = Object.keys(initialValues).length > 0;
158
+ }, [filterSchema, mergedDefaultValues]);
139
159
  const serialisedValues = React.useMemo(() => JSON.stringify(normalisedValues), [normalisedValues]);
140
160
  const debouncedSerialisedValues = useDebouncedValue(serialisedValues, FILTER_DEBOUNCE_DELAY);
141
161
  const lastPersistedValuesRef = React.useRef(null);
142
162
  const hasEmittedValuesRef = React.useRef(false);
163
+ const persistValues = React.useCallback((values, serialised) => {
164
+ const nextSerialised = serialised !== null && serialised !== void 0 ? serialised : JSON.stringify(values);
165
+ lastPersistedValuesRef.current = nextSerialised;
166
+ if (Object.keys(values).length === 0) {
167
+ clearStoredValues(storageKey);
168
+ return nextSerialised;
169
+ }
170
+ writeStoredValues(storageKey, values);
171
+ return nextSerialised;
172
+ }, [storageKey]);
143
173
  React.useEffect(() => {
144
174
  if (debouncedSerialisedValues == null) {
145
175
  return;
@@ -150,30 +180,45 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
150
180
  }
151
181
  const parsedValues = JSON.parse(debouncedSerialisedValues);
152
182
  const isEmpty = Object.keys(parsedValues).length === 0;
153
- if (!hasEmittedValuesRef.current && isEmpty && !hasInitialValues) {
183
+ if (!hasEmittedValuesRef.current &&
184
+ isEmpty &&
185
+ !hasInitialValuesRef.current) {
154
186
  hasEmittedValuesRef.current = true;
155
- lastPersistedValuesRef.current = debouncedSerialisedValues;
156
- clearStoredValues(storageKey);
187
+ persistValues(parsedValues, debouncedSerialisedValues);
157
188
  return;
158
189
  }
159
190
  hasEmittedValuesRef.current = true;
160
- lastPersistedValuesRef.current = debouncedSerialisedValues;
161
191
  onValuesChange === null || onValuesChange === void 0 ? void 0 : onValuesChange(parsedValues);
162
- if (isEmpty) {
163
- clearStoredValues(storageKey);
164
- }
165
- else {
166
- writeStoredValues(storageKey, parsedValues);
167
- }
168
- }, [debouncedSerialisedValues, hasInitialValues, onValuesChange, storageKey]);
192
+ persistValues(parsedValues, debouncedSerialisedValues);
193
+ }, [debouncedSerialisedValues, onValuesChange, persistValues]);
169
194
  React.useEffect(() => {
170
195
  lastPersistedValuesRef.current = null;
171
196
  }, [storageKey]);
172
197
  const handleClearAll = React.useCallback(() => {
173
- formMethods.reset(baseDefaultValues);
198
+ const clearedDefaults = Object.assign({}, baseDefaultValues);
199
+ filterSchema.forEach(field => {
200
+ const key = String(field.key);
201
+ const defaultValue = baseDefaultValues[key];
202
+ const resolved = resolveClearedFieldValue(field, defaultValue);
203
+ if (resolved === undefined) {
204
+ delete clearedDefaults[key];
205
+ }
206
+ else {
207
+ clearedDefaults[key] = resolved;
208
+ }
209
+ });
210
+ formMethods.reset(clearedDefaults, {
211
+ keepDirty: false,
212
+ keepTouched: false
213
+ });
174
214
  onClearAll === null || onClearAll === void 0 ? void 0 : onClearAll();
175
- clearStoredValues(storageKey);
176
- }, [baseDefaultValues, formMethods, onClearAll, storageKey]);
215
+ const nextValues = normaliseOutputValues(filterSchema, clearedDefaults);
216
+ hasInitialValuesRef.current = Object.keys(nextValues).length > 0;
217
+ const nextSerialised = persistValues(nextValues);
218
+ hasEmittedValuesRef.current = true;
219
+ lastPersistedValuesRef.current = nextSerialised !== null && nextSerialised !== void 0 ? nextSerialised : null;
220
+ onValuesChange === null || onValuesChange === void 0 ? void 0 : onValuesChange(nextValues);
221
+ }, [baseDefaultValues, filterSchema, formMethods, onClearAll, persistValues]);
177
222
  const handleOpenModal = React.useCallback(() => {
178
223
  setIsModalOpen(true);
179
224
  setSearchTerm('');
@@ -200,10 +245,26 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
200
245
  return;
201
246
  }
202
247
  const defaultValue = baseDefaultValues[String(schemaField.key)];
203
- formMethods.resetField(schemaField.key, {
204
- defaultValue
248
+ const fieldPath = schemaField.key;
249
+ const nextValue = resolveClearedFieldValue(schemaField, defaultValue);
250
+ formMethods.setValue(fieldPath, nextValue, {
251
+ shouldDirty: false,
252
+ shouldTouch: false,
253
+ shouldValidate: false
205
254
  });
206
- }, [baseDefaultValues, filterSchema, formMethods]);
255
+ const nextValues = normaliseOutputValues(filterSchema, formMethods.getValues());
256
+ const nextSerialised = persistValues(nextValues);
257
+ hasEmittedValuesRef.current = true;
258
+ lastPersistedValuesRef.current = nextSerialised !== null && nextSerialised !== void 0 ? nextSerialised : null;
259
+ hasInitialValuesRef.current = Object.keys(nextValues).length > 0;
260
+ onValuesChange === null || onValuesChange === void 0 ? void 0 : onValuesChange(nextValues);
261
+ }, [
262
+ baseDefaultValues,
263
+ filterSchema,
264
+ formMethods,
265
+ onValuesChange,
266
+ persistValues
267
+ ]);
207
268
  const filteredFields = React.useMemo(() => {
208
269
  const normalisedTerm = searchTerm.trim().toLowerCase();
209
270
  if (!normalisedTerm) {
@@ -233,7 +294,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
233
294
  case 'checkbox':
234
295
  return React.createElement(Checkbox, null, field.label);
235
296
  case 'date':
236
- return (React.createElement(DatePicker, { placeholder: field.placeholder, size: "large", showTime: field.showTime, suffixIcon: "calendar", suffixIconSize: "16px", "aria-label": ariaLabel }));
297
+ return (React.createElement(DatePicker, { placeholder: field.placeholder, showTime: field.showTime, suffixIcon: "calendar", suffixIconSize: "16px", "aria-label": ariaLabel }));
237
298
  case 'textarea':
238
299
  return (React.createElement(InputTextArea, { placeholder: field.placeholder, autoSize: { minRows: 3, maxRows: 6 }, "aria-label": ariaLabel }));
239
300
  case 'custom':
@@ -258,7 +319,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
258
319
  React.createElement("div", { className: "akinon-filter__body" },
259
320
  React.createElement(Akiform, { layout: "vertical", className: "akinon-filter__form" },
260
321
  React.createElement("div", { className: "akinon-filter__form-grid", "data-testid": "akifilter-form-grid" },
261
- visibleFields.map(field => (React.createElement(FormItem, { key: String(field.key), control: formMethods.control, name: field.key, tooltip: field.tooltip, help: field.help, labelDescription: field.labelDescription, required: Boolean(field.validation), valuePropName: field.type === 'checkbox' ? 'checked' : undefined }, renderFieldComponent(field)))),
322
+ visibleFields.map(field => (React.createElement(FormItem, { 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 === 'checkbox' ? 'checked' : undefined }, renderFieldComponent(field)))),
262
323
  visibleFields.length === 0 ? (React.createElement("div", { className: "akinon-filter__empty" }, i18n.t('form.noVisibleFields'))) : null))),
263
324
  React.createElement(VisibilityModal, { open: isModalOpen, onClose: handleCloseModal, searchTerm: searchTerm, paginatedFields: paginatedFields, filteredCount: filteredFields.length, visibleKeys: visibleKeys, onSearchTermChange: value => {
264
325
  setSearchTerm(value);
@@ -1 +1 @@
1
- {"version":3,"file":"theme-overrides.d.ts","sourceRoot":"","sources":["../../../src/common/theme-overrides.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAEnC,eAAO,MAAM,cAAc,EAAE,WAsB5B,CAAC"}
1
+ {"version":3,"file":"theme-overrides.d.ts","sourceRoot":"","sources":["../../../src/common/theme-overrides.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAEnC,eAAO,MAAM,cAAc,EAAE,WAkB5B,CAAC"}
@@ -1,6 +1,3 @@
1
1
  var _a, _b;
2
2
  import { theme } from '@akinon/ui-theme';
3
- export const themeOverrides = Object.assign(Object.assign({}, theme), { algorithm: theme.algorithm, token: {
4
- colorTextBase: theme.colors.ebonyClay['900'],
5
- colorText: theme.colors.ebonyClay['900']
6
- }, components: Object.assign(Object.assign({}, theme.components), { Typography: Object.assign(Object.assign({}, (_a = theme.components) === null || _a === void 0 ? void 0 : _a.Typography), { colorTextHeading: theme.colors.neutral['100'], colorText: theme.colors.neutral['500'], titleMarginBottom: 0 }), Modal: Object.assign(Object.assign({}, (_b = theme.components) === null || _b === void 0 ? void 0 : _b.Modal), { headerBg: theme.colors.ebonyClay['600'], contentBg: theme.colors.ebonyClay['600'], titleColor: theme.colors.neutral['200'] }) }) });
3
+ export const themeOverrides = Object.assign(Object.assign({}, theme), { algorithm: theme.algorithm, components: Object.assign(Object.assign({}, theme.components), { Typography: Object.assign(Object.assign({}, (_a = theme.components) === null || _a === void 0 ? void 0 : _a.Typography), { colorTextHeading: theme.colors.neutral['100'], colorText: theme.colors.neutral['500'], titleMarginBottom: 0 }), Modal: Object.assign(Object.assign({}, (_b = theme.components) === null || _b === void 0 ? void 0 : _b.Modal), { headerBg: theme.colors.ebonyClay['600'], contentBg: theme.colors.ebonyClay['600'], titleColor: theme.colors.neutral['200'] }) }) });
@@ -54,7 +54,7 @@
54
54
  .akinon-filter__form-grid {
55
55
  display: grid;
56
56
  grid-template-columns: repeat(4, minmax(0, 1fr));
57
- gap: 16px;
57
+ gap: 8px;
58
58
  }
59
59
 
60
60
  .akinon-filter__form-grid > .akinon-form-item {
@@ -120,7 +120,7 @@
120
120
  color: color(--color-ebonyClay-500);
121
121
  font-size: 12px;
122
122
  position: relative;
123
- top: 2px;
123
+ top: 1px;
124
124
  }
125
125
 
126
126
  .akinon-filter__modal-list {
@@ -172,11 +172,13 @@
172
172
  max-width: 360px;
173
173
  }
174
174
 
175
- /* Modal window. */
176
-
177
- .akinon-filter__modal {
175
+ .akinon-filter__field--number {
176
+ display: block;
177
+ width: auto;
178
178
  }
179
179
 
180
+ /* Modal window. */
181
+
180
182
  .akinon-filter__modal-toolbar {
181
183
  margin-bottom: 1rem;
182
184
  }
@@ -1,7 +1,7 @@
1
1
  import { akidate } from '@akinon/akidate';
2
2
  import { DEFAULT_VISIBLE_COUNT } from '../constants';
3
3
  export const getDisplayLabel = (field) => {
4
- return field.placeholder || field.label || String(field.key);
4
+ return field.label || field.placeholder || String(field.key);
5
5
  };
6
6
  export const getFieldAriaLabel = (field) => {
7
7
  return field.label || field.placeholder || String(field.key);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akinon/akifilter",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "private": false,
5
5
  "description": "Akifilter is a filtering library for Akinon frontend applications.",
6
6
  "type": "module",
@@ -12,21 +12,21 @@
12
12
  "dependencies": {
13
13
  "antd": "^5.27.0",
14
14
  "react-error-boundary": "^6.0.0",
15
- "@akinon/akilocale": "1.2.0",
16
15
  "@akinon/akiform": "1.1.1",
16
+ "@akinon/akidate": "1.1.1",
17
17
  "@akinon/icons": "1.1.0",
18
+ "@akinon/ui-button": "1.3.0",
19
+ "@akinon/akilocale": "1.2.0",
18
20
  "@akinon/ui-checkbox": "1.3.0",
19
21
  "@akinon/ui-card": "1.1.0",
22
+ "@akinon/ui-date-picker": "1.3.0",
20
23
  "@akinon/ui-input": "1.1.0",
21
- "@akinon/akidate": "1.1.1",
22
24
  "@akinon/ui-input-number": "1.3.0",
23
- "@akinon/ui-modal": "1.1.0",
24
25
  "@akinon/ui-pagination": "1.3.1",
25
- "@akinon/ui-date-picker": "1.3.0",
26
+ "@akinon/ui-modal": "1.1.0",
26
27
  "@akinon/ui-select": "1.3.1",
27
28
  "@akinon/ui-space": "1.3.0",
28
- "@akinon/ui-typography": "1.1.0",
29
- "@akinon/ui-button": "1.3.0"
29
+ "@akinon/ui-typography": "1.1.0"
30
30
  },
31
31
  "devDependencies": {
32
32
  "clean-package": "2.2.0",
@@ -36,8 +36,8 @@
36
36
  "@akinon/akiform-builder": "1.3.2",
37
37
  "@akinon/typescript-config": "1.1.0",
38
38
  "@akinon/ui-theme": "1.1.0",
39
- "@akinon/utils": "1.1.1",
40
- "@akinon/vitest-config": "1.1.0"
39
+ "@akinon/vitest-config": "1.1.0",
40
+ "@akinon/utils": "1.1.1"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "react": "^18 || ^19",