@akinon/akifilter 1.4.4-260521-3 → 1.5.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.
@@ -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;AAazB,OAAO,KAAK,MAAM,OAAO,CAAC;AAa1B,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,8BAA8B,CAAC;AAYtC,OAAO,KAAK,EACV,mBAAmB,EAEnB,eAAe,EAChB,MAAM,SAAS,CAAC;AAajB,KAAK,oBAAoB,GAAG,WAAW,CAAC;AA8JxC,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;AAu1BF,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,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;AAiKxC,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;AAq0BF,eAAO,MAAM,UAAU,GAAI,cAAc,UAAU;;;;;;;;CAQjD,CAAC;AA8CH,eAAO,MAAM,SAAS;KACpB,YAAY,SAAS,oBAAoB,uBAElC,cAAc,CAAC,YAAY,CAAC;;CAmBpC,CAAC"}
@@ -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,21 @@ const resolveClearedFieldValue = (field, defaultValue) => {
97
97
  return defaultValue;
98
98
  }
99
99
  switch (field.type) {
100
- case 'text':
101
- case 'textarea':
100
+ case constants_1.FIELD_TYPES.TEXT:
101
+ case constants_1.FIELD_TYPES.TEXTAREA:
102
102
  return '';
103
- case 'checkbox':
103
+ case constants_1.FIELD_TYPES.CHECKBOX:
104
104
  return false;
105
- case 'number':
106
- case 'date':
105
+ case constants_1.FIELD_TYPES.NUMBER:
106
+ case constants_1.FIELD_TYPES.DATE:
107
107
  return null;
108
- case 'select':
109
- if (field.mode === 'multiple' || field.mode === 'tags') {
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
- case 'file':
114
+ case constants_1.FIELD_TYPES.FILE:
114
115
  return null;
115
116
  default:
116
117
  return undefined;
@@ -119,6 +120,7 @@ const resolveClearedFieldValue = (field, defaultValue) => {
119
120
  const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onValuesChange, onVisibleFieldsChange, onImportCsv, onImportXls, onClearAll, enableImportCsv, enableImportXls, filterActionsRef, externalAppliedFilters, onRemoveExternalFilter }) => {
120
121
  // Separate regular fields from section fields
121
122
  const { regularFields, sectionFields } = react_1.default.useMemo(() => (0, schema_1.partitionSchema)(filterSchema), [filterSchema]);
123
+ const excludeSectionKeys = react_1.default.useMemo(() => (0, schema_1.deriveExcludeSectionKeys)(sectionFields), [sectionFields]);
122
124
  // Flatten schema for storage and form value operations
123
125
  const flattenedSchema = react_1.default.useMemo(() => (0, schema_1.flattenSchema)(filterSchema), [filterSchema]);
124
126
  const storageKey = react_1.default.useMemo(() => (0, storage_1.buildStorageKey)(regularFields, storageNamespace), [regularFields, storageNamespace]);
@@ -160,7 +162,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
160
162
  if (Array.isArray(currentValue) && currentValue.length === 0) {
161
163
  return acc;
162
164
  }
163
- if (field.type === 'checkbox' && currentValue !== true) {
165
+ if (field.type === constants_1.FIELD_TYPES.CHECKBOX && currentValue !== true) {
164
166
  return acc;
165
167
  }
166
168
  const label = field.label || field.placeholder || key;
@@ -183,18 +185,20 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
183
185
  return resolveLabel(currentValue);
184
186
  };
185
187
  const resolveValue = () => {
186
- if (field.type === 'file') {
188
+ if (field.type === constants_1.FIELD_TYPES.FILE) {
187
189
  const fileValue = currentValue;
188
190
  return fileValue instanceof File ? fileValue.name : String(fileValue);
189
191
  }
190
- if (field.type === 'select') {
192
+ if (field.type === constants_1.FIELD_TYPES.SELECT) {
191
193
  return resolveSelectLabel();
192
194
  }
193
195
  // For custom fields with options (like custom selects), try to find the label
194
- if (field.type === 'custom' && 'options' in field && field.options) {
196
+ if (field.type === constants_1.FIELD_TYPES.CUSTOM &&
197
+ 'options' in field &&
198
+ field.options) {
195
199
  return resolveSelectLabel();
196
200
  }
197
- if (field.type === 'date') {
201
+ if (field.type === constants_1.FIELD_TYPES.DATE) {
198
202
  const iso = akidate_1.akidate.toIsoDate(currentValue);
199
203
  if (iso) {
200
204
  // Use localized format with time if showTime is enabled
@@ -221,10 +225,15 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
221
225
  }
222
226
  return String(currentValue);
223
227
  };
224
- acc.push({ key, label, value: resolveValue() });
228
+ acc.push({
229
+ key,
230
+ label,
231
+ value: resolveValue(),
232
+ isExclude: excludeSectionKeys.has(key)
233
+ });
225
234
  return acc;
226
235
  }, []);
227
- }, [flattenedSchema, formValues]);
236
+ }, [flattenedSchema, formValues, excludeSectionKeys]);
228
237
  const resolveInitialVisibleKeys = react_1.default.useCallback(() => {
229
238
  const storedKeys = (0, storage_1.readVisibleKeys)(regularFields, storageKey);
230
239
  const defaultKeys = (0, schema_1.deriveDefaultVisibleKeys)(regularFields);
@@ -498,21 +507,21 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
498
507
  const ariaLabel = (0, schema_1.getFieldAriaLabel)(field);
499
508
  const isDisabled = checkIsDisabled(field, formValues !== null && formValues !== void 0 ? formValues : {});
500
509
  switch (field.type) {
501
- case 'text':
510
+ case constants_1.FIELD_TYPES.TEXT:
502
511
  return (react_1.default.createElement(ui_input_1.Input, { placeholder: field.placeholder, size: "large", allowClear: true, "aria-label": ariaLabel, disabled: isDisabled }));
503
- case 'number':
512
+ case constants_1.FIELD_TYPES.NUMBER:
504
513
  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 'select':
514
+ case constants_1.FIELD_TYPES.SELECT:
506
515
  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 'checkbox':
516
+ case constants_1.FIELD_TYPES.CHECKBOX:
508
517
  return react_1.default.createElement(ui_checkbox_1.Checkbox, { disabled: isDisabled }, field.label);
509
- case 'date':
518
+ case constants_1.FIELD_TYPES.DATE:
510
519
  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 'textarea':
520
+ case constants_1.FIELD_TYPES.TEXTAREA:
512
521
  return (react_1.default.createElement(ui_input_1.InputTextArea, { placeholder: field.placeholder, autoSize: { minRows: 3, maxRows: 6 }, "aria-label": ariaLabel, disabled: isDisabled }));
513
- case 'file':
522
+ case constants_1.FIELD_TYPES.FILE:
514
523
  return (react_1.default.createElement(FileFilterInput, { accept: field.fileAccept, "aria-label": ariaLabel, disabled: isDisabled }));
515
- case 'custom':
524
+ case constants_1.FIELD_TYPES.CUSTOM:
516
525
  if (typeof field.render === 'function') {
517
526
  return field.render({
518
527
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -524,7 +533,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
524
533
  });
525
534
  }
526
535
  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 'section':
536
+ case constants_1.FIELD_TYPES.SECTION:
528
537
  // Section fields should not be rendered inline
529
538
  // They are rendered separately after the main grid
530
539
  return null;
@@ -533,7 +542,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
533
542
  }
534
543
  };
535
544
  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 === 'checkbox' ? 'checked' : undefined }, renderFieldComponent(field)));
545
+ 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
546
  };
538
547
  return (react_1.default.createElement(ui_card_1.Card, { size: "small", className: "akinon-filter shadow", "data-testid": "akifilter-root" },
539
548
  react_1.default.createElement(antd_1.ConfigProvider, { theme: theme_overrides_1.themeOverrides },
@@ -545,10 +554,11 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
545
554
  visibleFields.map(renderFormField),
546
555
  visibleFields.length === 0 ? (react_1.default.createElement("div", { className: "akinon-filter__empty" }, i18n_1.i18n.t('form.noVisibleFields'))) : null),
547
556
  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: [
557
+ 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
558
  {
550
559
  key: section.key,
551
- label: section.label,
560
+ label: (react_1.default.createElement(ui_typography_1.Title, { className: "akinon-filter__title", level: 4 }, section.label)),
561
+ headerClass: 'akinon-filter__section-header',
552
562
  children: (react_1.default.createElement("div", { className: "akinon-filter__form-grid" }, section.fields.map(renderFormField)))
553
563
  }
554
564
  ] }));
@@ -563,6 +573,16 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
563
573
  }
564
574
  }, page: modalPage, pageSize: modalPageSize }))));
565
575
  };
576
+ const ExpandIcon = ({ isActive }) => ({
577
+ name: 'chevron_down',
578
+ size: 10,
579
+ style: {
580
+ transform: isActive ? 'rotate(-180deg)' : 'rotate(0deg)',
581
+ transition: 'transform 0.2s ease-in-out',
582
+ marginTop: 8
583
+ }
584
+ });
585
+ exports.ExpandIcon = ExpandIcon;
566
586
  const AkifilterEmptyState = () => {
567
587
  const { t } = i18n_1.i18n;
568
588
  return (react_1.default.createElement(ui_card_1.Card, { size: "small", className: "akinon-filter shadow", "data-testid": "akifilter-empty" },
@@ -3,6 +3,7 @@ type AppliedFilter = {
3
3
  key: string;
4
4
  label: string;
5
5
  value: string;
6
+ isExclude?: boolean;
6
7
  };
7
8
  type AppliedFiltersProps = {
8
9
  filters: AppliedFilter[];
@@ -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;CACf,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,sBAwDrB,CAAC;AAEF,YAAY,EAAE,aAAa,EAAE,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: "akinon-filter__chip" },
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,
@@ -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"}
@@ -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
+ };
@@ -47,11 +47,11 @@
47
47
  background-color: var(--color-ebonyClay-900);
48
48
  flex: 1;
49
49
  display: flex;
50
- align-items: center;
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
- top: 1px;
62
+ white-space: nowrap;
63
+ top: 7px;
63
64
  }
64
65
 
65
- .akinon-filter__common-filters {
66
- margin-top: 2rem;
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: 1px;
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;AAInD,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,MAAM,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;KACvC,CACF,CAAC;CAwBH,CAAC;AAEF,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,CAyCtB,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"}
@@ -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 === 'section' && 'fields' in field) {
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 === 'section') {
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 === 'date') {
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 === 'select' &&
107
- (field.mode === 'multiple' || field.mode === 'tags') &&
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];
@@ -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) === 'checkbox' && value !== true) {
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) === 'file') {
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) === 'date') {
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;
@@ -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;AAazB,OAAO,KAAK,MAAM,OAAO,CAAC;AAa1B,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,8BAA8B,CAAC;AAYtC,OAAO,KAAK,EACV,mBAAmB,EAEnB,eAAe,EAChB,MAAM,SAAS,CAAC;AAajB,KAAK,oBAAoB,GAAG,WAAW,CAAC;AA8JxC,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;AAu1BF,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,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;AAiKxC,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;AAq0BF,eAAO,MAAM,UAAU,GAAI,cAAc,UAAU;;;;;;;;CAQjD,CAAC;AA8CH,eAAO,MAAM,SAAS;KACpB,YAAY,SAAS,oBAAoB,uBAElC,cAAc,CAAC,YAAY,CAAC;;CAmBpC,CAAC"}
@@ -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,21 @@ const resolveClearedFieldValue = (field, defaultValue) => {
94
94
  return defaultValue;
95
95
  }
96
96
  switch (field.type) {
97
- case 'text':
98
- case 'textarea':
97
+ case FIELD_TYPES.TEXT:
98
+ case FIELD_TYPES.TEXTAREA:
99
99
  return '';
100
- case 'checkbox':
100
+ case FIELD_TYPES.CHECKBOX:
101
101
  return false;
102
- case 'number':
103
- case 'date':
102
+ case FIELD_TYPES.NUMBER:
103
+ case FIELD_TYPES.DATE:
104
104
  return null;
105
- case 'select':
106
- if (field.mode === 'multiple' || field.mode === 'tags') {
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
- case 'file':
111
+ case FIELD_TYPES.FILE:
111
112
  return null;
112
113
  default:
113
114
  return undefined;
@@ -116,6 +117,7 @@ const resolveClearedFieldValue = (field, defaultValue) => {
116
117
  const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onValuesChange, onVisibleFieldsChange, onImportCsv, onImportXls, onClearAll, enableImportCsv, enableImportXls, filterActionsRef, externalAppliedFilters, onRemoveExternalFilter }) => {
117
118
  // Separate regular fields from section fields
118
119
  const { regularFields, sectionFields } = React.useMemo(() => partitionSchema(filterSchema), [filterSchema]);
120
+ const excludeSectionKeys = React.useMemo(() => deriveExcludeSectionKeys(sectionFields), [sectionFields]);
119
121
  // Flatten schema for storage and form value operations
120
122
  const flattenedSchema = React.useMemo(() => flattenSchema(filterSchema), [filterSchema]);
121
123
  const storageKey = React.useMemo(() => buildStorageKey(regularFields, storageNamespace), [regularFields, storageNamespace]);
@@ -157,7 +159,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
157
159
  if (Array.isArray(currentValue) && currentValue.length === 0) {
158
160
  return acc;
159
161
  }
160
- if (field.type === 'checkbox' && currentValue !== true) {
162
+ if (field.type === FIELD_TYPES.CHECKBOX && currentValue !== true) {
161
163
  return acc;
162
164
  }
163
165
  const label = field.label || field.placeholder || key;
@@ -180,18 +182,20 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
180
182
  return resolveLabel(currentValue);
181
183
  };
182
184
  const resolveValue = () => {
183
- if (field.type === 'file') {
185
+ if (field.type === FIELD_TYPES.FILE) {
184
186
  const fileValue = currentValue;
185
187
  return fileValue instanceof File ? fileValue.name : String(fileValue);
186
188
  }
187
- if (field.type === 'select') {
189
+ if (field.type === FIELD_TYPES.SELECT) {
188
190
  return resolveSelectLabel();
189
191
  }
190
192
  // For custom fields with options (like custom selects), try to find the label
191
- if (field.type === 'custom' && 'options' in field && field.options) {
193
+ if (field.type === FIELD_TYPES.CUSTOM &&
194
+ 'options' in field &&
195
+ field.options) {
192
196
  return resolveSelectLabel();
193
197
  }
194
- if (field.type === 'date') {
198
+ if (field.type === FIELD_TYPES.DATE) {
195
199
  const iso = akidate.toIsoDate(currentValue);
196
200
  if (iso) {
197
201
  // Use localized format with time if showTime is enabled
@@ -218,10 +222,15 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
218
222
  }
219
223
  return String(currentValue);
220
224
  };
221
- acc.push({ key, label, value: resolveValue() });
225
+ acc.push({
226
+ key,
227
+ label,
228
+ value: resolveValue(),
229
+ isExclude: excludeSectionKeys.has(key)
230
+ });
222
231
  return acc;
223
232
  }, []);
224
- }, [flattenedSchema, formValues]);
233
+ }, [flattenedSchema, formValues, excludeSectionKeys]);
225
234
  const resolveInitialVisibleKeys = React.useCallback(() => {
226
235
  const storedKeys = readVisibleKeys(regularFields, storageKey);
227
236
  const defaultKeys = deriveDefaultVisibleKeys(regularFields);
@@ -495,21 +504,21 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
495
504
  const ariaLabel = getFieldAriaLabel(field);
496
505
  const isDisabled = checkIsDisabled(field, formValues !== null && formValues !== void 0 ? formValues : {});
497
506
  switch (field.type) {
498
- case 'text':
507
+ case FIELD_TYPES.TEXT:
499
508
  return (React.createElement(Input, { placeholder: field.placeholder, size: "large", allowClear: true, "aria-label": ariaLabel, disabled: isDisabled }));
500
- case 'number':
509
+ case FIELD_TYPES.NUMBER:
501
510
  return (React.createElement(InputNumber, { placeholder: field.placeholder, size: "large", className: "akinon-filter__field--number", "aria-label": ariaLabel, disabled: isDisabled }));
502
- case 'select':
511
+ case FIELD_TYPES.SELECT:
503
512
  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 'checkbox':
513
+ case FIELD_TYPES.CHECKBOX:
505
514
  return React.createElement(Checkbox, { disabled: isDisabled }, field.label);
506
- case 'date':
515
+ case FIELD_TYPES.DATE:
507
516
  return (React.createElement(DatePicker, { placeholder: field.placeholder, showTime: field.showTime, suffixIcon: "calendar", suffixIconSize: "16px", "aria-label": ariaLabel, disabled: isDisabled }));
508
- case 'textarea':
517
+ case FIELD_TYPES.TEXTAREA:
509
518
  return (React.createElement(InputTextArea, { placeholder: field.placeholder, autoSize: { minRows: 3, maxRows: 6 }, "aria-label": ariaLabel, disabled: isDisabled }));
510
- case 'file':
519
+ case FIELD_TYPES.FILE:
511
520
  return (React.createElement(FileFilterInput, { accept: field.fileAccept, "aria-label": ariaLabel, disabled: isDisabled }));
512
- case 'custom':
521
+ case FIELD_TYPES.CUSTOM:
513
522
  if (typeof field.render === 'function') {
514
523
  return field.render({
515
524
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -521,7 +530,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
521
530
  });
522
531
  }
523
532
  return (React.createElement(Text, { type: "secondary", className: "akinon-filter__unsupported" }, i18n.t('form.unsupportedField', { field: String(field.type) })));
524
- case 'section':
533
+ case FIELD_TYPES.SECTION:
525
534
  // Section fields should not be rendered inline
526
535
  // They are rendered separately after the main grid
527
536
  return null;
@@ -530,7 +539,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
530
539
  }
531
540
  };
532
541
  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 === 'checkbox' ? 'checked' : undefined }, renderFieldComponent(field)));
542
+ 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
543
  };
535
544
  return (React.createElement(Card, { size: "small", className: "akinon-filter shadow", "data-testid": "akifilter-root" },
536
545
  React.createElement(ConfigProvider, { theme: themeOverrides },
@@ -542,10 +551,11 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
542
551
  visibleFields.map(renderFormField),
543
552
  visibleFields.length === 0 ? (React.createElement("div", { className: "akinon-filter__empty" }, i18n.t('form.noVisibleFields'))) : null),
544
553
  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: [
554
+ return (React.createElement(Collapse, { expandIconPosition: "end", key: section.key, expandIcon: ExpandIcon, defaultActiveKey: section.defaultExpanded === false ? [] : [section.key], ghost: true, items: [
546
555
  {
547
556
  key: section.key,
548
- label: section.label,
557
+ label: (React.createElement(Title, { className: "akinon-filter__title", level: 4 }, section.label)),
558
+ headerClass: 'akinon-filter__section-header',
549
559
  children: (React.createElement("div", { className: "akinon-filter__form-grid" }, section.fields.map(renderFormField)))
550
560
  }
551
561
  ] }));
@@ -560,6 +570,15 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
560
570
  }
561
571
  }, page: modalPage, pageSize: modalPageSize }))));
562
572
  };
573
+ export const ExpandIcon = ({ isActive }) => ({
574
+ name: 'chevron_down',
575
+ size: 10,
576
+ style: {
577
+ transform: isActive ? 'rotate(-180deg)' : 'rotate(0deg)',
578
+ transition: 'transform 0.2s ease-in-out',
579
+ marginTop: 8
580
+ }
581
+ });
563
582
  const AkifilterEmptyState = () => {
564
583
  const { t } = i18n;
565
584
  return (React.createElement(Card, { size: "small", className: "akinon-filter shadow", "data-testid": "akifilter-empty" },
@@ -3,6 +3,7 @@ type AppliedFilter = {
3
3
  key: string;
4
4
  label: string;
5
5
  value: string;
6
+ isExclude?: boolean;
6
7
  };
7
8
  type AppliedFiltersProps = {
8
9
  filters: AppliedFilter[];
@@ -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;CACf,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,sBAwDrB,CAAC;AAEF,YAAY,EAAE,aAAa,EAAE,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: "akinon-filter__chip" },
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,
@@ -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"}
@@ -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
+ };
@@ -47,11 +47,11 @@
47
47
  background-color: var(--color-ebonyClay-900);
48
48
  flex: 1;
49
49
  display: flex;
50
- align-items: center;
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
- top: 1px;
62
+ white-space: nowrap;
63
+ top: 7px;
63
64
  }
64
65
 
65
- .akinon-filter__common-filters {
66
- margin-top: 2rem;
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: 1px;
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;AAInD,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,MAAM,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;KACvC,CACF,CAAC;CAwBH,CAAC;AAEF,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,CAyCtB,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"}
@@ -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 === 'section' && 'fields' in field) {
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 === 'section') {
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 === 'date') {
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 === 'select' &&
95
- (field.mode === 'multiple' || field.mode === 'tags') &&
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];
@@ -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) === 'checkbox' && value !== true) {
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) === 'file') {
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) === 'date') {
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.4.4-260521-3",
3
+ "version": "1.5.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",
@@ -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"