@akinon/akifilter 1.7.1 → 1.8.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.
Files changed (35) hide show
  1. package/dist/cjs/akifilter.d.ts +0 -10
  2. package/dist/cjs/akifilter.d.ts.map +1 -1
  3. package/dist/cjs/akifilter.js +14 -108
  4. package/dist/cjs/common/storage.d.ts +1 -0
  5. package/dist/cjs/common/storage.d.ts.map +1 -1
  6. package/dist/cjs/common/storage.js +3 -1
  7. package/dist/cjs/components/section-fieldset.d.ts +29 -0
  8. package/dist/cjs/components/section-fieldset.d.ts.map +1 -0
  9. package/dist/cjs/components/section-fieldset.js +97 -0
  10. package/dist/cjs/hooks/use-field-visibility.d.ts +45 -0
  11. package/dist/cjs/hooks/use-field-visibility.d.ts.map +1 -0
  12. package/dist/cjs/hooks/use-field-visibility.js +129 -0
  13. package/dist/cjs/styles.css +23 -0
  14. package/dist/cjs/types.d.ts +8 -1
  15. package/dist/cjs/types.d.ts.map +1 -1
  16. package/dist/cjs/utils/schema.d.ts +3 -13
  17. package/dist/cjs/utils/schema.d.ts.map +1 -1
  18. package/dist/esm/akifilter.d.ts +0 -10
  19. package/dist/esm/akifilter.d.ts.map +1 -1
  20. package/dist/esm/akifilter.js +16 -109
  21. package/dist/esm/common/storage.d.ts +1 -0
  22. package/dist/esm/common/storage.d.ts.map +1 -1
  23. package/dist/esm/common/storage.js +1 -0
  24. package/dist/esm/components/section-fieldset.d.ts +29 -0
  25. package/dist/esm/components/section-fieldset.d.ts.map +1 -0
  26. package/dist/esm/components/section-fieldset.js +93 -0
  27. package/dist/esm/hooks/use-field-visibility.d.ts +45 -0
  28. package/dist/esm/hooks/use-field-visibility.d.ts.map +1 -0
  29. package/dist/esm/hooks/use-field-visibility.js +125 -0
  30. package/dist/esm/styles.css +23 -0
  31. package/dist/esm/types.d.ts +8 -1
  32. package/dist/esm/types.d.ts.map +1 -1
  33. package/dist/esm/utils/schema.d.ts +3 -13
  34. package/dist/esm/utils/schema.d.ts.map +1 -1
  35. package/package.json +4 -4
@@ -1,6 +1,5 @@
1
1
  import './styles.css';
2
2
  import { FieldValues, Path } from '@akinon/akiform';
3
- import { type PanelProps } from '@akinon/ui-collapse';
4
3
  import React from 'react';
5
4
  import { type AppliedFilter } from './components/applied-filters';
6
5
  import type { AkifilterActionsRef, AkifilterButton, AkifilterSchema } from './types';
@@ -73,15 +72,6 @@ export type AkifilterProps<TFieldValues extends AkifilterFieldValues = Akifilter
73
72
  */
74
73
  onFilterButtonsChange?: (activeButtons: AkifilterButton[]) => void;
75
74
  };
76
- export declare const ExpandIcon: ({ isActive }: PanelProps) => {
77
- name: "chevron_down";
78
- size: number;
79
- style: {
80
- transform: string;
81
- transition: string;
82
- marginTop: number;
83
- };
84
- };
85
75
  export declare const Akifilter: {
86
76
  <TFieldValues extends AkifilterFieldValues = FieldValues>(props: AkifilterProps<TFieldValues>): React.JSX.Element;
87
77
  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;AAIzB,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAShE,OAAO,KAAK,MAAM,OAAO,CAAC;AAgB1B,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,8BAA8B,CAAC;AAetC,OAAO,KAAK,EACV,mBAAmB,EACnB,eAAe,EAEf,eAAe,EAChB,MAAM,SAAS,CAAC;AAcjB,KAAK,oBAAoB,GAAG,WAAW,CAAC;AA2KxC,MAAM,MAAM,cAAc,CACxB,YAAY,SAAS,oBAAoB,GAAG,oBAAoB,IAC9D;IACF;;OAEG;IACH,YAAY,CAAC,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;IAC7C;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACtC;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACzD;;OAEG;IACH,qBAAqB,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,IAAI,CAAC;IAClE;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,gBAAgB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAClD;;;OAGG;IACH,sBAAsB,CAAC,EAAE,aAAa,EAAE,CAAC;IACzC;;OAEG;IACH,sBAAsB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C;;;;;OAKG;IACH,aAAa,CAAC,EAAE,eAAe,EAAE,CAAC;IAClC;;OAEG;IACH,qBAAqB,CAAC,EAAE,CAAC,aAAa,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;CACpE,CAAC;AAq9BF,eAAO,MAAM,UAAU,GAAI,cAAc,UAAU;;;;;;;;CAQjD,CAAC;AA8CH,eAAO,MAAM,SAAS;KACpB,YAAY,SAAS,oBAAoB,uBAElC,cAAc,CAAC,YAAY,CAAC;;CAoBpC,CAAC"}
1
+ {"version":3,"file":"akifilter.d.ts","sourceRoot":"","sources":["../../src/akifilter.tsx"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AAGtB,OAAO,EAIL,WAAW,EACX,IAAI,EAIL,MAAM,iBAAiB,CAAC;AAYzB,OAAO,KAAK,MAAM,OAAO,CAAC;AAc1B,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,8BAA8B,CAAC;AAgBtC,OAAO,KAAK,EACV,mBAAmB,EACnB,eAAe,EAEf,eAAe,EAChB,MAAM,SAAS,CAAC;AAWjB,KAAK,oBAAoB,GAAG,WAAW,CAAC;AA2KxC,MAAM,MAAM,cAAc,CACxB,YAAY,SAAS,oBAAoB,GAAG,oBAAoB,IAC9D;IACF;;OAEG;IACH,YAAY,CAAC,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;IAC7C;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACtC;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACzD;;OAEG;IACH,qBAAqB,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,IAAI,CAAC;IAClE;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,gBAAgB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAClD;;;OAGG;IACH,sBAAsB,CAAC,EAAE,aAAa,EAAE,CAAC;IACzC;;OAEG;IACH,sBAAsB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C;;;;;OAKG;IACH,aAAa,CAAC,EAAE,eAAe,EAAE,CAAC;IAClC;;OAEG;IACH,qBAAqB,CAAC,EAAE,CAAC,aAAa,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;CACpE,CAAC;AA+3BF,eAAO,MAAM,SAAS;KACpB,YAAY,SAAS,oBAAoB,uBAElC,cAAc,CAAC,YAAY,CAAC;;CAoBpC,CAAC"}
@@ -11,14 +11,13 @@ 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 = exports.ExpandIcon = void 0;
14
+ exports.Akifilter = void 0;
15
15
  require("./styles.css");
16
16
  const akidate_1 = require("@akinon/akidate");
17
17
  const akiform_1 = require("@akinon/akiform");
18
18
  const ui_button_1 = require("@akinon/ui-button");
19
19
  const ui_card_1 = require("@akinon/ui-card");
20
20
  const ui_checkbox_1 = require("@akinon/ui-checkbox");
21
- const ui_collapse_1 = require("@akinon/ui-collapse");
22
21
  const ui_date_picker_1 = require("@akinon/ui-date-picker");
23
22
  const ui_input_1 = require("@akinon/ui-input");
24
23
  const ui_input_number_1 = require("@akinon/ui-input-number");
@@ -33,10 +32,12 @@ const theme_overrides_1 = require("./common/theme-overrides");
33
32
  const applied_filters_1 = require("./components/applied-filters");
34
33
  const filter_buttons_1 = require("./components/filter-buttons");
35
34
  const filter_toolbar_1 = require("./components/filter-toolbar");
35
+ const section_fieldset_1 = require("./components/section-fieldset");
36
36
  const visibility_modal_1 = require("./components/visibility-modal");
37
37
  const constants_1 = require("./constants");
38
38
  const use_debounced_value_1 = require("./hooks/use-debounced-value");
39
39
  const use_dynamic_visibility_1 = require("./hooks/use-dynamic-visibility");
40
+ const use_field_visibility_1 = require("./hooks/use-field-visibility");
40
41
  const use_visibility_cleanup_1 = require("./hooks/use-visibility-cleanup");
41
42
  const i18n_1 = require("./i18n");
42
43
  const schema_1 = require("./utils/schema");
@@ -152,10 +153,6 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
152
153
  defaultValues: mergedDefaultValues
153
154
  });
154
155
  const formValues = (0, akiform_1.useWatch)({ control: formMethods.control });
155
- const [isModalOpen, setIsModalOpen] = react_1.default.useState(false);
156
- const [searchTerm, setSearchTerm] = react_1.default.useState('');
157
- const [modalPage, setModalPage] = react_1.default.useState(1);
158
- const [modalPageSize, setModalPageSize] = react_1.default.useState(constants_1.DEFAULT_MODAL_PAGE_SIZE);
159
156
  // --- Filter buttons (quick-filter toggles) ---------------------------------
160
157
  // A button is identified by its `value`, which must be unique across the
161
158
  // whole `filterButtons` array.
@@ -283,41 +280,14 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
283
280
  value: button.label
284
281
  }));
285
282
  }, [filterButtons, activeButtonValues]);
286
- const resolveInitialVisibleKeys = react_1.default.useCallback(() => {
287
- const storedKeys = (0, storage_1.readVisibleKeys)(regularFields, storageKey);
288
- const defaultKeys = (0, schema_1.deriveDefaultVisibleKeys)(regularFields);
289
- const baseKeys = storedKeys && storedKeys.length > 0
290
- ? (0, schema_1.ensureSchemaOrder)(regularFields, storedKeys)
291
- : defaultKeys;
292
- return regularFields.reduce((acc, field) => {
293
- const key = String(field.key);
294
- const explicitVisibility = (0, schema_1.resolveFieldVisibility)(field);
295
- if (explicitVisibility !== undefined) {
296
- if (explicitVisibility)
297
- acc.push(key);
298
- return acc;
299
- }
300
- // No explicit boolean visibility, use stored/default
301
- if (baseKeys.includes(key)) {
302
- acc.push(key);
303
- }
304
- return acc;
305
- }, []);
306
- }, [regularFields, storageKey]);
307
- const [visibleKeys, setVisibleKeys] = react_1.default.useState(resolveInitialVisibleKeys);
308
- react_1.default.useEffect(() => {
309
- setVisibleKeys(previous => {
310
- const ordered = (0, schema_1.ensureSchemaOrder)(regularFields, previous);
311
- if (ordered.length) {
312
- return ordered;
313
- }
314
- return resolveInitialVisibleKeys();
315
- });
316
- }, [regularFields, resolveInitialVisibleKeys]);
317
- react_1.default.useEffect(() => {
318
- (0, storage_1.writeVisibleKeys)(storageKey, visibleKeys);
319
- onVisibleFieldsChange === null || onVisibleFieldsChange === void 0 ? void 0 : onVisibleFieldsChange(visibleKeys);
320
- }, [visibleKeys, onVisibleFieldsChange, storageKey]);
283
+ const handleVisibleKeysChange = react_1.default.useCallback((keys) => {
284
+ onVisibleFieldsChange === null || onVisibleFieldsChange === void 0 ? void 0 : onVisibleFieldsChange(keys);
285
+ }, [onVisibleFieldsChange]);
286
+ const { visibleKeys, setVisibleKeys, visibleFields, openModal, modalProps } = (0, use_field_visibility_1.useFieldVisibility)({
287
+ fields: regularFields,
288
+ storageKey,
289
+ onVisibleKeysChange: handleVisibleKeysChange
290
+ });
321
291
  const normalisedValues = react_1.default.useMemo(() => (0, values_1.normaliseOutputValues)(flattenedSchema, formValues), [flattenedSchema, formValues]);
322
292
  const hasInitialValuesRef = react_1.default.useRef(false);
323
293
  react_1.default.useEffect(() => {
@@ -448,26 +418,6 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
448
418
  emitValues,
449
419
  persistValues
450
420
  ]);
451
- const handleOpenModal = react_1.default.useCallback(() => {
452
- setIsModalOpen(true);
453
- setSearchTerm('');
454
- setModalPage(1);
455
- }, []);
456
- const handleCloseModal = react_1.default.useCallback(() => {
457
- setIsModalOpen(false);
458
- }, []);
459
- const handleToggleVisibility = react_1.default.useCallback((key) => {
460
- setVisibleKeys(prev => {
461
- const exists = prev.includes(key);
462
- if (exists && prev.length === 1) {
463
- return prev;
464
- }
465
- const nextKeys = exists
466
- ? prev.filter(item => item !== key)
467
- : [...prev, key];
468
- return (0, schema_1.ensureSchemaOrder)(regularFields, nextKeys);
469
- });
470
- }, [regularFields]);
471
421
  const handleRemoveFilter = react_1.default.useCallback((key) => {
472
422
  const schemaField = flattenedSchema.find(field => String(field.key) === key);
473
423
  if (!schemaField) {
@@ -548,23 +498,6 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
548
498
  keysArray.forEach(key => handleRemoveFilter(key));
549
499
  }
550
500
  }), [handleRemoveFilter]);
551
- const filteredFields = react_1.default.useMemo(() => {
552
- const normalisedTerm = searchTerm.trim().toLowerCase();
553
- if (!normalisedTerm) {
554
- return regularFields;
555
- }
556
- return regularFields.filter(field => {
557
- const searchable = [field.label, field.placeholder, String(field.key)]
558
- .filter(Boolean)
559
- .map(value => String(value).toLowerCase());
560
- return searchable.some(text => text.includes(normalisedTerm));
561
- });
562
- }, [regularFields, searchTerm]);
563
- const paginatedFields = react_1.default.useMemo(() => {
564
- const start = (modalPage - 1) * modalPageSize;
565
- return filteredFields.slice(start, start + modalPageSize);
566
- }, [filteredFields, modalPage, modalPageSize]);
567
- const visibleFields = react_1.default.useMemo(() => regularFields.filter(field => visibleKeys.includes(String(field.key))), [regularFields, visibleKeys]);
568
501
  // Dynamic visibility
569
502
  (0, use_dynamic_visibility_1.useDynamicVisibility)({
570
503
  regularFields,
@@ -655,7 +588,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
655
588
  };
656
589
  return (react_1.default.createElement(ui_card_1.Card, { size: "small", className: "akinon-filter shadow", "data-testid": "akifilter-root" },
657
590
  react_1.default.createElement(antd_1.ConfigProvider, { theme: theme_overrides_1.themeOverrides },
658
- react_1.default.createElement(filter_toolbar_1.FilterToolbar, { onOpenModal: handleOpenModal, enableImportCsv: enableImportCsv, enableImportXls: enableImportXls, onImportCsv: onImportCsv, onImportXls: onImportXls }),
591
+ react_1.default.createElement(filter_toolbar_1.FilterToolbar, { onOpenModal: openModal, enableImportCsv: enableImportCsv, enableImportXls: enableImportXls, onImportCsv: onImportCsv, onImportXls: onImportXls }),
659
592
  react_1.default.createElement(applied_filters_1.AppliedFilters, { filters: [
660
593
  ...appliedFilters,
661
594
  ...buttonAppliedFilters,
@@ -666,36 +599,9 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
666
599
  react_1.default.createElement("div", { className: "akinon-filter__form-grid", "data-testid": "akifilter-form-grid" },
667
600
  visibleFields.map(renderFormField),
668
601
  visibleFields.length === 0 && regularFields.length > 0 ? (react_1.default.createElement("div", { className: "akinon-filter__empty" }, i18n_1.i18n.t('form.noVisibleFields'))) : null),
669
- sectionFields.length > 0 && (react_1.default.createElement("div", { className: "akinon-filter__section-fields" }, sectionFields.map(section => {
670
- 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: [
671
- {
672
- key: section.key,
673
- label: (react_1.default.createElement(ui_typography_1.Title, { className: "akinon-filter__title", level: 4 }, section.label)),
674
- headerClass: 'akinon-filter__section-header',
675
- children: (react_1.default.createElement("div", { className: "akinon-filter__form-grid" }, section.fields.map(renderFormField)))
676
- }
677
- ] }));
678
- }))))),
679
- react_1.default.createElement(visibility_modal_1.VisibilityModal, { open: isModalOpen, onClose: handleCloseModal, searchTerm: searchTerm, paginatedFields: paginatedFields, filteredCount: filteredFields.length, visibleKeys: visibleKeys, onSearchTermChange: value => {
680
- setSearchTerm(value);
681
- setModalPage(1);
682
- }, onToggleVisibility: handleToggleVisibility, onPaginationChange: (page, pageSize) => {
683
- setModalPage(page);
684
- if (pageSize !== modalPageSize) {
685
- setModalPageSize(pageSize);
686
- }
687
- }, page: modalPage, pageSize: modalPageSize }))));
602
+ sectionFields.length > 0 && (react_1.default.createElement("div", { className: "akinon-filter__section-fields" }, sectionFields.map(section => (react_1.default.createElement(section_fieldset_1.SectionFieldset, { key: String(section.key), section: section, storageKey: storageKey, renderFormField: renderFormField, onRemoveField: handleRemoveFilter, formValues: normalisedValues }))))))),
603
+ react_1.default.createElement(visibility_modal_1.VisibilityModal, Object.assign({}, modalProps)))));
688
604
  };
689
- const ExpandIcon = ({ isActive }) => ({
690
- name: 'chevron_down',
691
- size: 10,
692
- style: {
693
- transform: isActive ? 'rotate(-180deg)' : 'rotate(0deg)',
694
- transition: 'transform 0.2s ease-in-out',
695
- marginTop: 8
696
- }
697
- });
698
- exports.ExpandIcon = ExpandIcon;
699
605
  const AkifilterEmptyState = () => {
700
606
  const { t } = i18n_1.i18n;
701
607
  return (react_1.default.createElement(ui_card_1.Card, { size: "small", className: "akinon-filter shadow", "data-testid": "akifilter-empty" },
@@ -3,6 +3,7 @@ import type { AkifilterField } from '../types';
3
3
  export declare const buildStorageKey: <TFieldValues extends FieldValues>(schema: AkifilterField<TFieldValues>[], namespace?: string) => string;
4
4
  export declare const readVisibleKeys: <TFieldValues extends FieldValues>(schema: AkifilterField<TFieldValues>[], storageKey: string) => string[] | null;
5
5
  export declare const writeVisibleKeys: (storageKey: string, keys: string[]) => void;
6
+ export declare const buildSectionVisibilityKey: (storageKey: string, sectionKey: string | number) => string;
6
7
  export declare const clearVisibleKeys: (storageKey: string) => void;
7
8
  export declare const readStoredValues: <TFieldValues extends FieldValues>(schema: AkifilterField<TFieldValues>[], storageKey: string) => Partial<TFieldValues> | null;
8
9
  export declare const writeStoredValues: <TFieldValues extends FieldValues>(storageKey: string, values: Partial<TFieldValues>) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/common/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AA4B/C,eAAO,MAAM,eAAe,GAAI,YAAY,SAAS,WAAW,EAC9D,QAAQ,cAAc,CAAC,YAAY,CAAC,EAAE,EACtC,YAAY,MAAM,KACjB,MAKF,CAAC;AAIF,eAAO,MAAM,eAAe,GAAI,YAAY,SAAS,WAAW,EAC9D,QAAQ,cAAc,CAAC,YAAY,CAAC,EAAE,EACtC,YAAY,MAAM,KACjB,MAAM,EAAE,GAAG,IAoBb,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,YAAY,MAAM,EAAE,MAAM,MAAM,EAAE,KAAG,IAQrE,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,YAAY,MAAM,KAAG,IAQrD,CAAC;AAKF,eAAO,MAAM,gBAAgB,GAAI,YAAY,SAAS,WAAW,EAC/D,QAAQ,cAAc,CAAC,YAAY,CAAC,EAAE,EACtC,YAAY,MAAM,KACjB,OAAO,CAAC,YAAY,CAAC,GAAG,IA+B1B,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,YAAY,SAAS,WAAW,EAChE,YAAY,MAAM,EAClB,QAAQ,OAAO,CAAC,YAAY,CAAC,KAC5B,IAeF,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,YAAY,MAAM,KAAG,IAQtD,CAAC;AAKF,eAAO,MAAM,sBAAsB,GACjC,YAAY,MAAM,KACjB,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,IAwB3B,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,YAAY,MAAM,EAClB,QAAQ,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,KAC7B,IAcF,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,YAAY,MAAM,KAAG,IAQ5D,CAAC"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/common/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AA4B/C,eAAO,MAAM,eAAe,GAAI,YAAY,SAAS,WAAW,EAC9D,QAAQ,cAAc,CAAC,YAAY,CAAC,EAAE,EACtC,YAAY,MAAM,KACjB,MAKF,CAAC;AAIF,eAAO,MAAM,eAAe,GAAI,YAAY,SAAS,WAAW,EAC9D,QAAQ,cAAc,CAAC,YAAY,CAAC,EAAE,EACtC,YAAY,MAAM,KACjB,MAAM,EAAE,GAAG,IAoBb,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,YAAY,MAAM,EAAE,MAAM,MAAM,EAAE,KAAG,IAQrE,CAAC;AAEF,eAAO,MAAM,yBAAyB,GACpC,YAAY,MAAM,EAClB,YAAY,MAAM,GAAG,MAAM,KAC1B,MAAuD,CAAC;AAE3D,eAAO,MAAM,gBAAgB,GAAI,YAAY,MAAM,KAAG,IAQrD,CAAC;AAKF,eAAO,MAAM,gBAAgB,GAAI,YAAY,SAAS,WAAW,EAC/D,QAAQ,cAAc,CAAC,YAAY,CAAC,EAAE,EACtC,YAAY,MAAM,KACjB,OAAO,CAAC,YAAY,CAAC,GAAG,IA+B1B,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,YAAY,SAAS,WAAW,EAChE,YAAY,MAAM,EAClB,QAAQ,OAAO,CAAC,YAAY,CAAC,KAC5B,IAeF,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,YAAY,MAAM,KAAG,IAQtD,CAAC;AAKF,eAAO,MAAM,sBAAsB,GACjC,YAAY,MAAM,KACjB,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,IAwB3B,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,YAAY,MAAM,EAClB,QAAQ,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,KAC7B,IAcF,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,YAAY,MAAM,KAAG,IAQ5D,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.clearStoredButtonValues = exports.writeStoredButtonValues = exports.readStoredButtonValues = exports.clearStoredValues = exports.writeStoredValues = exports.readStoredValues = exports.clearVisibleKeys = exports.writeVisibleKeys = exports.readVisibleKeys = exports.buildStorageKey = void 0;
3
+ exports.clearStoredButtonValues = exports.writeStoredButtonValues = exports.readStoredButtonValues = exports.clearStoredValues = exports.writeStoredValues = exports.readStoredValues = exports.clearVisibleKeys = exports.buildSectionVisibilityKey = exports.writeVisibleKeys = exports.readVisibleKeys = exports.buildStorageKey = void 0;
4
4
  const i18n_1 = require("../i18n");
5
5
  const STORAGE_PREFIX = 'akifilter:v1';
6
6
  const VALUES_SUFFIX = ':values';
@@ -62,6 +62,8 @@ const writeVisibleKeys = (storageKey, keys) => {
62
62
  }
63
63
  };
64
64
  exports.writeVisibleKeys = writeVisibleKeys;
65
+ const buildSectionVisibilityKey = (storageKey, sectionKey) => `${storageKey}:section:${String(sectionKey)}`;
66
+ exports.buildSectionVisibilityKey = buildSectionVisibilityKey;
65
67
  const clearVisibleKeys = (storageKey) => {
66
68
  if (!isBrowser)
67
69
  return;
@@ -0,0 +1,29 @@
1
+ import type { FieldValues } from '@akinon/akiform';
2
+ import React from 'react';
3
+ import type { AkifilterField, AkifilterSectionField } from '../types';
4
+ type SectionFieldsetProps<TFieldValues extends FieldValues = FieldValues> = {
5
+ section: AkifilterSectionField<TFieldValues>;
6
+ /**
7
+ * Base storage key of the host Akifilter; combined with the section key to
8
+ * persist this section's visible-field selection.
9
+ */
10
+ storageKey: string;
11
+ renderFormField: (field: AkifilterField<TFieldValues>) => React.ReactNode;
12
+ /**
13
+ * Clears a field's form value; used to drop the value of a field that gets
14
+ * hidden from the section.
15
+ */
16
+ onRemoveField: (key: string) => void;
17
+ /**
18
+ * Current normalised form values, needed to resolve dynamic visibility.
19
+ */
20
+ formValues: Partial<TFieldValues> | undefined;
21
+ };
22
+ /**
23
+ * Renders a single section field. Sections flagged with `selectableFields`
24
+ * expose a funnel icon + visibility modal; all others render every field
25
+ * inline as before.
26
+ */
27
+ export declare const SectionFieldset: <TFieldValues extends FieldValues = FieldValues>(props: SectionFieldsetProps<TFieldValues>) => React.JSX.Element;
28
+ export {};
29
+ //# sourceMappingURL=section-fieldset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"section-fieldset.d.ts","sourceRoot":"","sources":["../../../src/components/section-fieldset.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAKnD,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AA8CtE,KAAK,oBAAoB,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW,IAAI;IAC1E,OAAO,EAAE,qBAAqB,CAAC,YAAY,CAAC,CAAC;IAC7C;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,YAAY,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC;IAC1E;;;OAGG;IACH,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC;;OAEG;IACH,UAAU,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC;CAC/C,CAAC;AAwGF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,YAAY,SAAS,WAAW,GAAG,WAAW,EAC5E,OAAO,oBAAoB,CAAC,YAAY,CAAC,sBAuB1C,CAAC"}
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SectionFieldset = void 0;
4
+ const icons_1 = require("@akinon/icons");
5
+ const ui_button_1 = require("@akinon/ui-button");
6
+ const ui_collapse_1 = require("@akinon/ui-collapse");
7
+ const ui_typography_1 = require("@akinon/ui-typography");
8
+ const react_1 = require("react");
9
+ const storage_1 = require("../common/storage");
10
+ const use_dynamic_visibility_1 = require("../hooks/use-dynamic-visibility");
11
+ const use_field_visibility_1 = require("../hooks/use-field-visibility");
12
+ const use_visibility_cleanup_1 = require("../hooks/use-visibility-cleanup");
13
+ const i18n_1 = require("../i18n");
14
+ const visibility_modal_1 = require("./visibility-modal");
15
+ const ExpandIcon = ({ isActive }) => ({
16
+ name: 'chevron_down',
17
+ size: 10,
18
+ style: {
19
+ transform: isActive ? 'rotate(-180deg)' : 'rotate(0deg)',
20
+ transition: 'transform 0.2s ease-in-out',
21
+ marginTop: 8
22
+ }
23
+ });
24
+ /**
25
+ * Presentational wrapper around the collapsible panel used by every section,
26
+ * so the selectable and plain variants share one markup.
27
+ */
28
+ const SectionCollapse = ({ sectionKey, label, defaultExpanded, children }) => (react_1.default.createElement(ui_collapse_1.Collapse, { expandIconPosition: "end", expandIcon: ExpandIcon, defaultActiveKey: defaultExpanded === false ? [] : [sectionKey], ghost: true, items: [
29
+ {
30
+ key: sectionKey,
31
+ label,
32
+ headerClass: 'akinon-filter__section-header',
33
+ children: react_1.default.createElement("div", { className: "akinon-filter__form-grid" }, children)
34
+ }
35
+ ] }));
36
+ /**
37
+ * A section whose header exposes a funnel icon that opens the visibility modal,
38
+ * mirroring the top-level filter field-selection behaviour.
39
+ */
40
+ const SelectableSectionFieldset = ({ section, storageKey, renderFormField, onRemoveField, formValues }) => {
41
+ const sectionStorageKey = react_1.default.useMemo(() => (0, storage_1.buildSectionVisibilityKey)(storageKey, section.key), [storageKey, section.key]);
42
+ const { visibleKeys, setVisibleKeys, visibleFields, openModal, modalProps } = (0, use_field_visibility_1.useFieldVisibility)({
43
+ fields: section.fields,
44
+ storageKey: sectionStorageKey
45
+ });
46
+ (0, use_dynamic_visibility_1.useDynamicVisibility)({
47
+ regularFields: section.fields,
48
+ formValues,
49
+ setVisibleKeys
50
+ });
51
+ (0, use_visibility_cleanup_1.useVisibilityCleanup)({
52
+ visibleKeys,
53
+ regularFields: section.fields,
54
+ onRemove: onRemoveField
55
+ });
56
+ // Controlled so we can render our own chevron in the header and keep the
57
+ // funnel button pinned to the far right (after the arrow).
58
+ const sectionKey = String(section.key);
59
+ const [activeKeys, setActiveKeys] = react_1.default.useState(section.defaultExpanded === false ? [] : [sectionKey]);
60
+ const isExpanded = activeKeys.includes(sectionKey);
61
+ const label = (react_1.default.createElement("div", { className: "akinon-filter__section-header-content" },
62
+ react_1.default.createElement(ui_typography_1.Title, { className: "akinon-filter__title", level: 4 }, section.label),
63
+ react_1.default.createElement(icons_1.Icon, { icon: "chevron_down", size: 10, className: "akinon-filter__section-arrow", style: {
64
+ transform: isExpanded ? 'rotate(-180deg)' : 'rotate(0deg)',
65
+ transition: 'transform 0.2s ease-in-out'
66
+ } }),
67
+ react_1.default.createElement(ui_button_1.Button, { className: "akinon-filter__toolbar-item akinon-filter__section-funnel", icon: "filter", iconSize: 16, type: "primary", title: i18n_1.i18n.t('header.actions.selectFilters'), "aria-label": i18n_1.i18n.t('header.actions.selectFilters'), onClick: event => {
68
+ // Prevent the header click from toggling the collapse.
69
+ event.stopPropagation();
70
+ openModal();
71
+ } })));
72
+ return (react_1.default.createElement(react_1.default.Fragment, null,
73
+ react_1.default.createElement(ui_collapse_1.Collapse, { activeKey: activeKeys, onChange: keys => setActiveKeys((Array.isArray(keys) ? keys : [keys]).map(String)), ghost: true, items: [
74
+ {
75
+ key: sectionKey,
76
+ label,
77
+ headerClass: 'akinon-filter__section-header akinon-filter__section-header--selectable',
78
+ showArrow: false,
79
+ children: (react_1.default.createElement("div", { className: "akinon-filter__form-grid" }, visibleFields.map(renderFormField)))
80
+ }
81
+ ] }),
82
+ react_1.default.createElement(visibility_modal_1.VisibilityModal, Object.assign({}, modalProps))));
83
+ };
84
+ /**
85
+ * Renders a single section field. Sections flagged with `selectableFields`
86
+ * expose a funnel icon + visibility modal; all others render every field
87
+ * inline as before.
88
+ */
89
+ const SectionFieldset = (props) => {
90
+ const { section, renderFormField } = props;
91
+ if (section.selectableFields) {
92
+ return react_1.default.createElement(SelectableSectionFieldset, Object.assign({}, props));
93
+ }
94
+ const label = (react_1.default.createElement(ui_typography_1.Title, { className: "akinon-filter__title", level: 4 }, section.label));
95
+ return (react_1.default.createElement(SectionCollapse, { sectionKey: String(section.key), label: label, defaultExpanded: section.defaultExpanded }, section.fields.map(renderFormField)));
96
+ };
97
+ exports.SectionFieldset = SectionFieldset;
@@ -0,0 +1,45 @@
1
+ import { type FieldValues } from '@akinon/akiform';
2
+ import React from 'react';
3
+ import type { AkifilterSchema } from '../types';
4
+ type UseFieldVisibilityParams<TFieldValues extends FieldValues> = {
5
+ /**
6
+ * Fields whose visibility this hook manages (top-level filters or the fields
7
+ * of a single section).
8
+ */
9
+ fields: AkifilterSchema<TFieldValues>;
10
+ /**
11
+ * Storage key under which the visible-field selection is persisted. Callers
12
+ * pass distinct keys per group so selections never collide.
13
+ */
14
+ storageKey: string;
15
+ /**
16
+ * Notified whenever the resolved visible keys change.
17
+ */
18
+ onVisibleKeysChange?: (keys: string[]) => void;
19
+ };
20
+ /**
21
+ * Encapsulates the visible-field selection and its accompanying modal state for
22
+ * a single group of fields. Used both for the top-level filters and for each
23
+ * selectable section so the two share one implementation.
24
+ */
25
+ export declare const useFieldVisibility: <TFieldValues extends FieldValues = FieldValues>({ fields, storageKey, onVisibleKeysChange }: UseFieldVisibilityParams<TFieldValues>) => {
26
+ visibleKeys: string[];
27
+ setVisibleKeys: React.Dispatch<React.SetStateAction<string[]>>;
28
+ visibleFields: import("../types").AkifilterField<TFieldValues>[];
29
+ openModal: () => void;
30
+ modalProps: {
31
+ open: boolean;
32
+ searchTerm: string;
33
+ paginatedFields: import("../types").AkifilterField<TFieldValues>[];
34
+ filteredCount: number;
35
+ visibleKeys: string[];
36
+ onClose: () => void;
37
+ onSearchTermChange: (value: string) => void;
38
+ onToggleVisibility: (key: string) => void;
39
+ onPaginationChange: (page: number, pageSize: number) => void;
40
+ page: number;
41
+ pageSize: number;
42
+ };
43
+ };
44
+ export {};
45
+ //# sourceMappingURL=use-field-visibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-field-visibility.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-field-visibility.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAOhD,KAAK,wBAAwB,CAAC,YAAY,SAAS,WAAW,IAAI;IAChE;;;OAGG;IACH,MAAM,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;IACtC;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAC7B,YAAY,SAAS,WAAW,GAAG,WAAW,EAC9C,6CAIC,wBAAwB,CAAC,YAAY,CAAC;;;;;;;;;;;;oCAiHP,MAAM;kCAlD9B,MAAM;mCAuDiB,MAAM,YAAY,MAAM;;;;CA6BxD,CAAC"}
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useFieldVisibility = void 0;
4
+ const react_1 = require("react");
5
+ const storage_1 = require("../common/storage");
6
+ const constants_1 = require("../constants");
7
+ const schema_1 = require("../utils/schema");
8
+ /**
9
+ * Encapsulates the visible-field selection and its accompanying modal state for
10
+ * a single group of fields. Used both for the top-level filters and for each
11
+ * selectable section so the two share one implementation.
12
+ */
13
+ const useFieldVisibility = ({ fields, storageKey, onVisibleKeysChange }) => {
14
+ const [isModalOpen, setIsModalOpen] = react_1.default.useState(false);
15
+ const [searchTerm, setSearchTerm] = react_1.default.useState('');
16
+ const [modalPage, setModalPage] = react_1.default.useState(1);
17
+ const [modalPageSize, setModalPageSize] = react_1.default.useState(constants_1.DEFAULT_MODAL_PAGE_SIZE);
18
+ const resolveInitialVisibleKeys = react_1.default.useCallback(() => {
19
+ const storedKeys = (0, storage_1.readVisibleKeys)(fields, storageKey);
20
+ const defaultKeys = (0, schema_1.deriveDefaultVisibleKeys)(fields);
21
+ const baseKeys = storedKeys && storedKeys.length > 0
22
+ ? (0, schema_1.ensureSchemaOrder)(fields, storedKeys)
23
+ : defaultKeys;
24
+ return fields.reduce((acc, field) => {
25
+ const key = String(field.key);
26
+ const explicitVisibility = (0, schema_1.resolveFieldVisibility)(field);
27
+ if (explicitVisibility !== undefined) {
28
+ if (explicitVisibility)
29
+ acc.push(key);
30
+ return acc;
31
+ }
32
+ // No explicit boolean visibility, use stored/default
33
+ if (baseKeys.includes(key)) {
34
+ acc.push(key);
35
+ }
36
+ return acc;
37
+ }, []);
38
+ }, [fields, storageKey]);
39
+ const [visibleKeys, setVisibleKeys] = react_1.default.useState(resolveInitialVisibleKeys);
40
+ react_1.default.useEffect(() => {
41
+ setVisibleKeys(previous => {
42
+ const ordered = (0, schema_1.ensureSchemaOrder)(fields, previous);
43
+ if (ordered.length) {
44
+ return ordered;
45
+ }
46
+ return resolveInitialVisibleKeys();
47
+ });
48
+ }, [fields, resolveInitialVisibleKeys]);
49
+ react_1.default.useEffect(() => {
50
+ (0, storage_1.writeVisibleKeys)(storageKey, visibleKeys);
51
+ onVisibleKeysChange === null || onVisibleKeysChange === void 0 ? void 0 : onVisibleKeysChange(visibleKeys);
52
+ }, [visibleKeys, onVisibleKeysChange, storageKey]);
53
+ const openModal = react_1.default.useCallback(() => {
54
+ setIsModalOpen(true);
55
+ setSearchTerm('');
56
+ setModalPage(1);
57
+ }, []);
58
+ const closeModal = react_1.default.useCallback(() => {
59
+ setIsModalOpen(false);
60
+ }, []);
61
+ const handleToggleVisibility = react_1.default.useCallback((key) => {
62
+ setVisibleKeys(prev => {
63
+ const exists = prev.includes(key);
64
+ if (exists && prev.length === 1) {
65
+ return prev;
66
+ }
67
+ const nextKeys = exists
68
+ ? prev.filter(item => item !== key)
69
+ : [...prev, key];
70
+ return (0, schema_1.ensureSchemaOrder)(fields, nextKeys);
71
+ });
72
+ }, [fields]);
73
+ const filteredFields = react_1.default.useMemo(() => {
74
+ const normalisedTerm = searchTerm.trim().toLowerCase();
75
+ if (!normalisedTerm) {
76
+ return fields;
77
+ }
78
+ return fields.filter(field => {
79
+ const searchable = [field.label, field.placeholder, String(field.key)]
80
+ .filter(Boolean)
81
+ .map(value => String(value).toLowerCase());
82
+ return searchable.some(text => text.includes(normalisedTerm));
83
+ });
84
+ }, [fields, searchTerm]);
85
+ const paginatedFields = react_1.default.useMemo(() => {
86
+ const start = (modalPage - 1) * modalPageSize;
87
+ return filteredFields.slice(start, start + modalPageSize);
88
+ }, [filteredFields, modalPage, modalPageSize]);
89
+ const visibleFields = react_1.default.useMemo(() => fields.filter(field => visibleKeys.includes(String(field.key))), [fields, visibleKeys]);
90
+ const modalProps = react_1.default.useMemo(() => ({
91
+ open: isModalOpen,
92
+ searchTerm,
93
+ paginatedFields,
94
+ filteredCount: filteredFields.length,
95
+ visibleKeys,
96
+ onClose: closeModal,
97
+ onSearchTermChange: (value) => {
98
+ setSearchTerm(value);
99
+ setModalPage(1);
100
+ },
101
+ onToggleVisibility: handleToggleVisibility,
102
+ onPaginationChange: (page, pageSize) => {
103
+ setModalPage(page);
104
+ if (pageSize !== modalPageSize) {
105
+ setModalPageSize(pageSize);
106
+ }
107
+ },
108
+ page: modalPage,
109
+ pageSize: modalPageSize
110
+ }), [
111
+ isModalOpen,
112
+ searchTerm,
113
+ paginatedFields,
114
+ filteredFields.length,
115
+ visibleKeys,
116
+ closeModal,
117
+ handleToggleVisibility,
118
+ modalPage,
119
+ modalPageSize
120
+ ]);
121
+ return {
122
+ visibleKeys,
123
+ setVisibleKeys,
124
+ visibleFields,
125
+ openModal,
126
+ modalProps
127
+ };
128
+ };
129
+ exports.useFieldVisibility = useFieldVisibility;
@@ -70,6 +70,29 @@
70
70
  flex: unset !important;
71
71
  }
72
72
 
73
+ .akinon-filter__section-header-content {
74
+ display: flex;
75
+ align-items: center;
76
+ gap: 0.5rem;
77
+ width: 100%;
78
+ }
79
+
80
+ /* Let the header text span fill the header so the funnel can sit at the far right. */
81
+ .akinon-filter__section-header--selectable .akinon-collapse-header-text {
82
+ flex: 1 1 auto !important;
83
+ }
84
+
85
+ .akinon-filter__section-arrow {
86
+ color: var(--color-gray-500);
87
+ }
88
+
89
+ /* Funnel pinned to the far right of the header, after the title and arrow. */
90
+ .akinon-filter__section-funnel.akinon-filter__toolbar-item {
91
+ width: 36px;
92
+ justify-content: center;
93
+ margin-left: auto;
94
+ }
95
+
73
96
  .akinon-filter__buttons {
74
97
  display: flex;
75
98
  align-items: center;
@@ -1,5 +1,5 @@
1
1
  import type { FieldValues, Path } from '@akinon/akiform';
2
- import type { FormField } from '@akinon/akiform-builder';
2
+ import type { FormField, SectionField } from '@akinon/akiform-builder';
3
3
  import type { IconName } from '@akinon/icons';
4
4
  export interface AkifilterFieldConfig<TFieldValues extends FieldValues = FieldValues> {
5
5
  /**
@@ -25,6 +25,13 @@ export type AkifilterField<TFieldValues extends FieldValues = FieldValues> = Dis
25
25
  */
26
26
  fileAccept?: string;
27
27
  };
28
+ /**
29
+ * Section field as consumed by Akifilter. Derived from the shared
30
+ * `SectionField` so flags like `selectableFields`/`isExcludeSection` stay
31
+ * single-sourced, but omits `collapsible` — Akifilter always renders sections
32
+ * as collapsible panels and does not honor that prop.
33
+ */
34
+ export type AkifilterSectionField<TFieldValues extends FieldValues = FieldValues> = Omit<SectionField<TFieldValues>, 'collapsible'>;
28
35
  export type AkifilterFieldKey<TFieldValues extends FieldValues = FieldValues> = Path<TFieldValues>;
29
36
  export type AkifilterSchema<TFieldValues extends FieldValues = FieldValues> = AkifilterField<TFieldValues>[];
30
37
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,WAAW,oBAAoB,CACnC,YAAY,SAAS,WAAW,GAAG,WAAW;IAE9C;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,UAAU,EAAE,YAAY,KAAK,OAAO,CAAC,CAAC;IAC7D;;;OAGG;IACH,OAAO,CAAC,EACJ,OAAO,GACP,CAAC,CAAC,UAAU,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC;CACvE;AAED,KAAK,gBAAgB,CAAC,CAAC,EAAE,CAAC,SAAS,WAAW,IAAI,CAAC,SAAS,OAAO,GAC/D,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GACV,KAAK,CAAC;AAEV,MAAM,MAAM,cAAc,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW,IACvE,gBAAgB,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,GAAG;IACpD;;OAEG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAC,YAAY,CAAC,CAAC;IAC5C;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEJ,MAAM,MAAM,iBAAiB,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW,IAC1E,IAAI,CAAC,YAAY,CAAC,CAAC;AAErB,MAAM,MAAM,eAAe,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW,IACxE,cAAc,CAAC,YAAY,CAAC,EAAE,CAAC;AAEjC;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;OAMG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;OAKG;IACH,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,IAAI,EAAE,QAAQ,CAAC;IACf;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC;CAC/C"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,WAAW,oBAAoB,CACnC,YAAY,SAAS,WAAW,GAAG,WAAW;IAE9C;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,UAAU,EAAE,YAAY,KAAK,OAAO,CAAC,CAAC;IAC7D;;;OAGG;IACH,OAAO,CAAC,EACJ,OAAO,GACP,CAAC,CAAC,UAAU,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC;CACvE;AAED,KAAK,gBAAgB,CAAC,CAAC,EAAE,CAAC,SAAS,WAAW,IAAI,CAAC,SAAS,OAAO,GAC/D,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GACV,KAAK,CAAC;AAEV,MAAM,MAAM,cAAc,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW,IACvE,gBAAgB,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,GAAG;IACpD;;OAEG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAC,YAAY,CAAC,CAAC;IAC5C;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEJ;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,CAC/B,YAAY,SAAS,WAAW,GAAG,WAAW,IAC5C,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,aAAa,CAAC,CAAC;AAEpD,MAAM,MAAM,iBAAiB,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW,IAC1E,IAAI,CAAC,YAAY,CAAC,CAAC;AAErB,MAAM,MAAM,eAAe,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW,IACxE,cAAc,CAAC,YAAY,CAAC,EAAE,CAAC;AAEjC;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;OAMG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;OAKG;IACH,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,IAAI,EAAE,QAAQ,CAAC;IACf;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC;CAC/C"}