@akinon/akifilter 0.5.3 → 1.0.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 (160) hide show
  1. package/README.md +44 -0
  2. package/dist/cjs/akifilter.d.ts +53 -0
  3. package/dist/cjs/akifilter.d.ts.map +1 -0
  4. package/dist/cjs/akifilter.js +299 -0
  5. package/dist/cjs/common/storage.d.ts +10 -0
  6. package/dist/cjs/common/storage.d.ts.map +1 -0
  7. package/dist/cjs/common/storage.js +124 -0
  8. package/dist/cjs/common/theme-overrides.d.ts +3 -0
  9. package/dist/cjs/common/theme-overrides.d.ts.map +1 -0
  10. package/dist/cjs/common/theme-overrides.js +9 -0
  11. package/dist/cjs/components/applied-filters.d.ts +14 -0
  12. package/dist/cjs/components/applied-filters.d.ts.map +1 -0
  13. package/dist/cjs/components/applied-filters.js +26 -0
  14. package/dist/cjs/components/filter-toolbar.d.ts +11 -0
  15. package/dist/cjs/components/filter-toolbar.d.ts.map +1 -0
  16. package/dist/cjs/components/filter-toolbar.js +17 -0
  17. package/dist/cjs/components/visibility-modal.d.ts +19 -0
  18. package/dist/cjs/components/visibility-modal.d.ts.map +1 -0
  19. package/dist/cjs/components/visibility-modal.js +30 -0
  20. package/dist/cjs/constants.d.ts +4 -0
  21. package/dist/cjs/constants.d.ts.map +1 -0
  22. package/dist/cjs/constants.js +6 -0
  23. package/dist/cjs/hooks/use-debounced-value.d.ts +2 -0
  24. package/dist/cjs/hooks/use-debounced-value.d.ts.map +1 -0
  25. package/dist/cjs/hooks/use-debounced-value.js +17 -0
  26. package/dist/cjs/i18n/index.d.ts +2 -4
  27. package/dist/cjs/i18n/index.d.ts.map +1 -1
  28. package/dist/cjs/i18n/index.js +1 -1
  29. package/dist/cjs/i18n/translations/en.d.ts +33 -3
  30. package/dist/cjs/i18n/translations/en.d.ts.map +1 -1
  31. package/dist/cjs/i18n/translations/en.js +33 -3
  32. package/dist/cjs/i18n/translations/tr.d.ts +33 -3
  33. package/dist/cjs/i18n/translations/tr.d.ts.map +1 -1
  34. package/dist/cjs/i18n/translations/tr.js +33 -3
  35. package/dist/cjs/index.d.ts +3 -14
  36. package/dist/cjs/index.d.ts.map +1 -1
  37. package/dist/cjs/index.js +17 -32
  38. package/dist/cjs/styles.css +182 -0
  39. package/dist/cjs/types.d.ts +11 -0
  40. package/dist/cjs/types.d.ts.map +1 -0
  41. package/dist/cjs/types.js +2 -0
  42. package/dist/cjs/utils/schema.d.ts +9 -0
  43. package/dist/cjs/utils/schema.d.ts.map +1 -0
  44. package/dist/cjs/utils/schema.js +61 -0
  45. package/dist/cjs/utils/values.d.ts +5 -0
  46. package/dist/cjs/utils/values.d.ts.map +1 -0
  47. package/dist/cjs/utils/values.js +44 -0
  48. package/dist/esm/akifilter.d.ts +53 -0
  49. package/dist/esm/akifilter.d.ts.map +1 -0
  50. package/dist/esm/akifilter.js +295 -0
  51. package/dist/esm/common/storage.d.ts +10 -0
  52. package/dist/esm/common/storage.d.ts.map +1 -0
  53. package/dist/esm/common/storage.js +114 -0
  54. package/dist/esm/common/theme-overrides.d.ts +3 -0
  55. package/dist/esm/common/theme-overrides.d.ts.map +1 -0
  56. package/dist/esm/common/theme-overrides.js +6 -0
  57. package/dist/esm/components/applied-filters.d.ts +14 -0
  58. package/dist/esm/components/applied-filters.d.ts.map +1 -0
  59. package/dist/esm/components/applied-filters.js +22 -0
  60. package/dist/esm/components/filter-toolbar.d.ts +11 -0
  61. package/dist/esm/components/filter-toolbar.d.ts.map +1 -0
  62. package/dist/esm/components/filter-toolbar.js +13 -0
  63. package/dist/esm/components/visibility-modal.d.ts +19 -0
  64. package/dist/esm/components/visibility-modal.d.ts.map +1 -0
  65. package/dist/esm/components/visibility-modal.js +26 -0
  66. package/dist/esm/constants.d.ts +4 -0
  67. package/dist/esm/constants.d.ts.map +1 -0
  68. package/dist/esm/constants.js +3 -0
  69. package/dist/esm/hooks/use-debounced-value.d.ts +2 -0
  70. package/dist/esm/hooks/use-debounced-value.d.ts.map +1 -0
  71. package/dist/esm/hooks/use-debounced-value.js +13 -0
  72. package/dist/esm/i18n/index.d.ts +2 -4
  73. package/dist/esm/i18n/index.d.ts.map +1 -1
  74. package/dist/esm/i18n/index.js +5 -5
  75. package/dist/esm/i18n/translations/en.d.ts +33 -3
  76. package/dist/esm/i18n/translations/en.d.ts.map +1 -1
  77. package/dist/esm/i18n/translations/en.js +33 -3
  78. package/dist/esm/i18n/translations/tr.d.ts +33 -3
  79. package/dist/esm/i18n/translations/tr.d.ts.map +1 -1
  80. package/dist/esm/i18n/translations/tr.js +33 -3
  81. package/dist/esm/index.d.ts +3 -14
  82. package/dist/esm/index.d.ts.map +1 -1
  83. package/dist/esm/index.js +3 -30
  84. package/dist/esm/styles.css +182 -0
  85. package/dist/esm/types.d.ts +11 -0
  86. package/dist/esm/types.d.ts.map +1 -0
  87. package/dist/esm/types.js +1 -0
  88. package/dist/esm/utils/schema.d.ts +9 -0
  89. package/dist/esm/utils/schema.d.ts.map +1 -0
  90. package/dist/esm/utils/schema.js +52 -0
  91. package/dist/esm/utils/values.d.ts +5 -0
  92. package/dist/esm/utils/values.d.ts.map +1 -0
  93. package/dist/esm/utils/values.js +39 -0
  94. package/package.json +40 -33
  95. package/dist/cjs/components/AppliedFilters/AppliedFilterItem.d.ts +0 -12
  96. package/dist/cjs/components/AppliedFilters/AppliedFilterItem.d.ts.map +0 -1
  97. package/dist/cjs/components/AppliedFilters/AppliedFilterItem.js +0 -62
  98. package/dist/cjs/components/AppliedFilters/common.d.ts +0 -6
  99. package/dist/cjs/components/AppliedFilters/common.d.ts.map +0 -1
  100. package/dist/cjs/components/AppliedFilters/common.js +0 -33
  101. package/dist/cjs/components/AppliedFilters/index.d.ts +0 -4
  102. package/dist/cjs/components/AppliedFilters/index.d.ts.map +0 -1
  103. package/dist/cjs/components/AppliedFilters/index.js +0 -26
  104. package/dist/cjs/components/AppliedFilters/styles.css +0 -65
  105. package/dist/cjs/components/ConditionalFilters/index.d.ts +0 -3
  106. package/dist/cjs/components/ConditionalFilters/index.d.ts.map +0 -1
  107. package/dist/cjs/components/ConditionalFilters/index.js +0 -32
  108. package/dist/cjs/components/FilterContext/index.d.ts +0 -45
  109. package/dist/cjs/components/FilterContext/index.d.ts.map +0 -1
  110. package/dist/cjs/components/FilterContext/index.js +0 -85
  111. package/dist/cjs/components/SelectShownFilters/index.d.ts +0 -7
  112. package/dist/cjs/components/SelectShownFilters/index.d.ts.map +0 -1
  113. package/dist/cjs/components/SelectShownFilters/index.js +0 -111
  114. package/dist/cjs/components/SelectShownFilters/styles.css +0 -99
  115. package/dist/cjs/components/ShownFilters/index.d.ts +0 -3
  116. package/dist/cjs/components/ShownFilters/index.d.ts.map +0 -1
  117. package/dist/cjs/components/ShownFilters/index.js +0 -45
  118. package/dist/cjs/components/index.d.ts +0 -6
  119. package/dist/cjs/components/index.d.ts.map +0 -1
  120. package/dist/cjs/components/index.js +0 -21
  121. package/dist/cjs/constants/index.d.ts +0 -56
  122. package/dist/cjs/constants/index.d.ts.map +0 -1
  123. package/dist/cjs/constants/index.js +0 -58
  124. package/dist/cjs/index.css +0 -67
  125. package/dist/cjs/utils/index.d.ts +0 -25
  126. package/dist/cjs/utils/index.d.ts.map +0 -1
  127. package/dist/cjs/utils/index.js +0 -40
  128. package/dist/esm/components/AppliedFilters/AppliedFilterItem.d.ts +0 -12
  129. package/dist/esm/components/AppliedFilters/AppliedFilterItem.d.ts.map +0 -1
  130. package/dist/esm/components/AppliedFilters/AppliedFilterItem.js +0 -58
  131. package/dist/esm/components/AppliedFilters/common.d.ts +0 -6
  132. package/dist/esm/components/AppliedFilters/common.d.ts.map +0 -1
  133. package/dist/esm/components/AppliedFilters/common.js +0 -28
  134. package/dist/esm/components/AppliedFilters/index.d.ts +0 -4
  135. package/dist/esm/components/AppliedFilters/index.d.ts.map +0 -1
  136. package/dist/esm/components/AppliedFilters/index.js +0 -22
  137. package/dist/esm/components/AppliedFilters/styles.css +0 -65
  138. package/dist/esm/components/ConditionalFilters/index.d.ts +0 -3
  139. package/dist/esm/components/ConditionalFilters/index.d.ts.map +0 -1
  140. package/dist/esm/components/ConditionalFilters/index.js +0 -28
  141. package/dist/esm/components/FilterContext/index.d.ts +0 -45
  142. package/dist/esm/components/FilterContext/index.d.ts.map +0 -1
  143. package/dist/esm/components/FilterContext/index.js +0 -80
  144. package/dist/esm/components/SelectShownFilters/index.d.ts +0 -7
  145. package/dist/esm/components/SelectShownFilters/index.d.ts.map +0 -1
  146. package/dist/esm/components/SelectShownFilters/index.js +0 -107
  147. package/dist/esm/components/SelectShownFilters/styles.css +0 -99
  148. package/dist/esm/components/ShownFilters/index.d.ts +0 -3
  149. package/dist/esm/components/ShownFilters/index.d.ts.map +0 -1
  150. package/dist/esm/components/ShownFilters/index.js +0 -41
  151. package/dist/esm/components/index.d.ts +0 -6
  152. package/dist/esm/components/index.d.ts.map +0 -1
  153. package/dist/esm/components/index.js +0 -5
  154. package/dist/esm/constants/index.d.ts +0 -56
  155. package/dist/esm/constants/index.d.ts.map +0 -1
  156. package/dist/esm/constants/index.js +0 -55
  157. package/dist/esm/index.css +0 -67
  158. package/dist/esm/utils/index.d.ts +0 -25
  159. package/dist/esm/utils/index.d.ts.map +0 -1
  160. package/dist/esm/utils/index.js +0 -35
package/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # akifilter
2
+
3
+ ## Legacy Functionality Snapshot (`@akinon/ui/akifilter-old`)
4
+ - **Schema-driven forms**: Builds the main filter UI from `filterSchema` using `FormBuilderWatch`, applying `labelRightAligned` props and reflecting initial values from `useAppliedFilters[0]` or persisted storage.
5
+ - **Context-managed state**: `FilterContextProvider` derives `mainPath` from the router (or `customMainPath`), stores `appliedFilters`, `applicableFilters`, and `shownFilters` via `useImmerReducer`, and exposes actions for updates.
6
+ - **Local storage persistence**: Reads/writes `appliedFilters-{mainPath}` and `shownFilters-{mainPath}` so filter selections survive reloads; defaults to the first eight filters when no history exists.
7
+ - **Parent synchronization**: Propagates every applied-filter change back through `useAppliedFilters[1]`, allowing host apps to react or override initial state.
8
+ - **Applied filter chips**: Renders active filters with labels sourced from placeholders, formats values (dates via akidate utilities, arrays, booleans) for display, and supports removing individual filters or clearing all.
9
+ - **Dynamic filter visibility**: `SelectShownFilters` opens a modal with searchable, paginated checkboxes for every applicable filter; selections update `shownFilters` and trigger form recreation to avoid stale state.
10
+ - **Conditional filters**: Optional `conditionalFiltersSchema` renders a secondary form whose values merge into `appliedFilters` without local storage persistence, rebuilding whenever the schema changes.
11
+ - **Utility helpers**: Provides path parsing (`getPathFragments`) to scope state per route and a tree search helper (`getTreeNodeByValue`) for nested option lookups.
12
+ - **Internationalization scaffolding**: Loads static i18n bundles (EN/TR) through `Akilocale` for component copy such as the panel title.
13
+
14
+ ## Implementation Plan (User Experience Focus)
15
+ 1. **Filter Workspace Shell**
16
+ - Recreate the legacy layout with updated styling hooks, keeping the header title, filter-selection trigger, applied filter strip, and main filter grid so existing users feel familiar while allowing future visual tweaks.
17
+ - Integrate `akilocale` for default copy (`title`, modal labels) and expose translation keys for host apps.
18
+
19
+ 2. **Schema Intake & Form Rendering**
20
+ - Accept an external `filterSchema` (and optional `conditionalFiltersSchema`) and translate each field into `akiform` widgets, honoring component-specific props, labels, and placeholders.
21
+ - Default-render only “primary” filters on first load (configurable count), but respect any persisted selections on subsequent visits.
22
+
23
+ 3. **User Input & Applied State**
24
+ - Mirror user edits into an internal state model while emitting JSON payloads to the host via the provided `useAppliedFilters` tuple so parent apps receive canonical data.
25
+ - Display currently applied filters as removable chips; value formatting should transparently handle primitives, arrays, booleans, and date-like objects.
26
+
27
+ 4. **Filter Visibility Management**
28
+ - Provide a modal (using `@akinon/ui-modal`, `@akinon/ui-input`, `@akinon/ui-pagination`) that lists all available filters with search, pagination, and checkbox toggles to control visibility.
29
+ - Persist visibility selections and main-form order to local storage, ensuring a stable experience across sessions.
30
+
31
+ 5. **Persistence Strategy**
32
+ - Derive unique local-storage keys using a caller-supplied prefix plus a deterministic suffix (e.g., hash of schema or route) so multiple filter instances cannot collide.
33
+ - Support optional overrides (custom key + custom main path) while always appending our uniqueness salt.
34
+
35
+ 6. **Conditional Filter Surface**
36
+ - Render an auxiliary `akiform` section beneath the main filters when `conditionalFiltersSchema` exists, reset its form state whenever the schema changes, and merge its values into the emitted applied-filter JSON without persisting to storage.
37
+
38
+ 7. **Bulk Actions & Import Filters**
39
+ - Retain the “clear all” action for quick resets, updating UI state, storage, and parent callbacks consistently.
40
+ - Plan dedicated affordances for CSV/XLS import: display buttons in the options toolbar, accept uploads via `@akinon/ui-upload`, and parse/normalize records into applied filters (details to be implemented in later stages).
41
+
42
+ 8. **Testing & Quality Targets**
43
+ - Cover all interactive flows (form entry, chip removal, modal toggles, persistence, conditional schema changes, CSV/XLS hooks) with Vitest and Testing Library, targeting ≥90% coverage without regressing existing suites.
44
+ - Document sample integration snippets so partner apps can verify behavior during development.
@@ -0,0 +1,53 @@
1
+ import './styles.css';
2
+ import { FieldValues, Path } from '@akinon/akiform';
3
+ import React from 'react';
4
+ import type { AkifilterSchema } from './types';
5
+ type AkifilterFieldValues = FieldValues;
6
+ export type AkifilterProps<TFieldValues extends AkifilterFieldValues = AkifilterFieldValues> = {
7
+ /**
8
+ * Declarative description of the filter fields.
9
+ */
10
+ filterSchema?: AkifilterSchema<TFieldValues>;
11
+ /**
12
+ * Optional namespace for local storage persistence.
13
+ */
14
+ storageNamespace?: string;
15
+ /**
16
+ * Default values supplied by the host application.
17
+ */
18
+ defaultValues?: Partial<TFieldValues>;
19
+ /**
20
+ * Notified on every value change with the normalised payload.
21
+ */
22
+ onValuesChange?: (values: Partial<TFieldValues>) => void;
23
+ /**
24
+ * Notified whenever visible field keys change.
25
+ */
26
+ onVisibleFieldsChange?: (keys: Array<Path<TFieldValues>>) => void;
27
+ /**
28
+ * Triggered when user opts to import filters via CSV.
29
+ */
30
+ onImportCsv?: () => void;
31
+ /**
32
+ * Triggered when user opts to import filters via XLS/XLSX.
33
+ */
34
+ onImportXls?: () => void;
35
+ /**
36
+ * Triggered when user requests clearing all filters.
37
+ */
38
+ onClearAll?: () => void;
39
+ /**
40
+ * Shows the CSV import button in the toolbar. Hidden by default.
41
+ */
42
+ enableImportCsv?: boolean;
43
+ /**
44
+ * Shows the XLS/XLSX import button in the toolbar. Hidden by default.
45
+ */
46
+ enableImportXls?: boolean;
47
+ };
48
+ export declare const Akifilter: {
49
+ <TFieldValues extends AkifilterFieldValues = FieldValues>(props: AkifilterProps<TFieldValues>): React.JSX.Element;
50
+ displayName: string;
51
+ };
52
+ export {};
53
+ //# sourceMappingURL=akifilter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"akifilter.d.ts","sourceRoot":"","sources":["../../src/akifilter.tsx"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AAGtB,OAAO,EAIL,WAAW,EAEX,IAAI,EAGL,MAAM,iBAAiB,CAAC;AAUzB,OAAO,KAAK,MAAM,OAAO,CAAC;AAsB1B,OAAO,KAAK,EAAkB,eAAe,EAAE,MAAM,SAAS,CAAC;AAU/D,KAAK,oBAAoB,GAAG,WAAW,CAAC;AAExC,MAAM,MAAM,cAAc,CACxB,YAAY,SAAS,oBAAoB,GAAG,oBAAoB,IAC9D;IACF;;OAEG;IACH,YAAY,CAAC,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;IAC7C;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACtC;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACzD;;OAEG;IACH,qBAAqB,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,IAAI,CAAC;IAClE;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAohBF,eAAO,MAAM,SAAS;KACpB,YAAY,SAAS,oBAAoB,uBAElC,cAAc,CAAC,YAAY,CAAC;;CAmBpC,CAAC"}
@@ -0,0 +1,299 @@
1
+ "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.Akifilter = void 0;
15
+ require("./styles.css");
16
+ const akidate_1 = require("@akinon/akidate");
17
+ const akiform_1 = require("@akinon/akiform");
18
+ const ui_button_1 = require("@akinon/ui-button");
19
+ const ui_card_1 = require("@akinon/ui-card");
20
+ const ui_checkbox_1 = require("@akinon/ui-checkbox");
21
+ const ui_date_picker_1 = require("@akinon/ui-date-picker");
22
+ const ui_input_1 = require("@akinon/ui-input");
23
+ const ui_input_number_1 = require("@akinon/ui-input-number");
24
+ const ui_select_1 = require("@akinon/ui-select");
25
+ const ui_typography_1 = require("@akinon/ui-typography");
26
+ const antd_1 = require("antd");
27
+ const react_1 = require("react");
28
+ const react_error_boundary_1 = require("react-error-boundary");
29
+ const storage_1 = require("./common/storage");
30
+ const theme_overrides_1 = require("./common/theme-overrides");
31
+ const applied_filters_1 = require("./components/applied-filters");
32
+ const filter_toolbar_1 = require("./components/filter-toolbar");
33
+ const visibility_modal_1 = require("./components/visibility-modal");
34
+ const constants_1 = require("./constants");
35
+ const use_debounced_value_1 = require("./hooks/use-debounced-value");
36
+ const i18n_1 = require("./i18n");
37
+ const schema_1 = require("./utils/schema");
38
+ const values_1 = require("./utils/values");
39
+ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onValuesChange, onVisibleFieldsChange, onImportCsv, onImportXls, onClearAll, enableImportCsv, enableImportXls }) => {
40
+ const storageKey = react_1.default.useMemo(() => (0, storage_1.buildStorageKey)(filterSchema, storageNamespace), [filterSchema, storageNamespace]);
41
+ const schemaDefaults = react_1.default.useMemo(() => (0, schema_1.normaliseValuesBySchema)(filterSchema, (0, schema_1.extractDefaultValues)(filterSchema)), [filterSchema]);
42
+ const externalDefaults = react_1.default.useMemo(() => (0, schema_1.normaliseValuesBySchema)(filterSchema, defaultValues), [filterSchema, defaultValues]);
43
+ const baseDefaultValues = react_1.default.useMemo(() => (Object.assign(Object.assign({}, schemaDefaults), externalDefaults)), [schemaDefaults, externalDefaults]);
44
+ const persistedDefaults = react_1.default.useMemo(() => {
45
+ var _a;
46
+ return (0, schema_1.normaliseValuesBySchema)(filterSchema, (_a = (0, storage_1.readStoredValues)(filterSchema, storageKey)) !== null && _a !== void 0 ? _a : undefined);
47
+ }, [filterSchema, storageKey]);
48
+ const mergedDefaultValues = react_1.default.useMemo(() => (Object.assign(Object.assign({}, baseDefaultValues), persistedDefaults)), [baseDefaultValues, persistedDefaults]);
49
+ const formMethods = (0, akiform_1.useForm)({
50
+ defaultValues: mergedDefaultValues
51
+ });
52
+ const formValues = (0, akiform_1.useWatch)({ control: formMethods.control });
53
+ const [isModalOpen, setIsModalOpen] = react_1.default.useState(false);
54
+ const [searchTerm, setSearchTerm] = react_1.default.useState('');
55
+ const [modalPage, setModalPage] = react_1.default.useState(1);
56
+ const [modalPageSize, setModalPageSize] = react_1.default.useState(constants_1.DEFAULT_MODAL_PAGE_SIZE);
57
+ const appliedFilters = react_1.default.useMemo(() => {
58
+ if (!formValues) {
59
+ return [];
60
+ }
61
+ return filterSchema.reduce((acc, field) => {
62
+ const key = String(field.key);
63
+ const currentValue = formValues[key];
64
+ if (currentValue === undefined || currentValue === null) {
65
+ return acc;
66
+ }
67
+ if (typeof currentValue === 'string' && currentValue.trim() === '') {
68
+ return acc;
69
+ }
70
+ if (Array.isArray(currentValue) && currentValue.length === 0) {
71
+ return acc;
72
+ }
73
+ if (field.type === 'checkbox' && currentValue !== true) {
74
+ return acc;
75
+ }
76
+ const label = field.placeholder || field.label || key;
77
+ const resolveSelectLabel = () => {
78
+ var _a;
79
+ if (!('options' in field) || !field.options) {
80
+ return String(currentValue);
81
+ }
82
+ const match = field.options.find(option => option.value === currentValue);
83
+ return String((_a = match === null || match === void 0 ? void 0 : match.label) !== null && _a !== void 0 ? _a : currentValue);
84
+ };
85
+ const resolveValue = () => {
86
+ if (field.type === 'select') {
87
+ return resolveSelectLabel();
88
+ }
89
+ if (field.type === 'date') {
90
+ const iso = akidate_1.akidate.toIsoDate(currentValue);
91
+ if (iso) {
92
+ return akidate_1.akidate.formatIsoDate(iso, 'YYYY-MM-DD');
93
+ }
94
+ }
95
+ if (Array.isArray(currentValue)) {
96
+ return currentValue.map((value) => String(value)).join(', ');
97
+ }
98
+ if (typeof currentValue === 'boolean') {
99
+ return currentValue ? 'true' : 'false';
100
+ }
101
+ if (typeof currentValue === 'string' ||
102
+ typeof currentValue === 'number') {
103
+ return String(currentValue);
104
+ }
105
+ const iso = akidate_1.akidate.toIsoDate(currentValue);
106
+ if (iso) {
107
+ return akidate_1.akidate.formatIsoDate(iso, 'YYYY-MM-DD');
108
+ }
109
+ return String(currentValue);
110
+ };
111
+ acc.push({ key, label, value: resolveValue() });
112
+ return acc;
113
+ }, []);
114
+ }, [filterSchema, formValues]);
115
+ const resolveInitialVisibleKeys = react_1.default.useCallback(() => {
116
+ const storedKeys = (0, storage_1.readVisibleKeys)(filterSchema, storageKey);
117
+ if (storedKeys && storedKeys.length > 0) {
118
+ return (0, schema_1.ensureSchemaOrder)(filterSchema, storedKeys);
119
+ }
120
+ return (0, schema_1.deriveDefaultVisibleKeys)(filterSchema);
121
+ }, [filterSchema, storageKey]);
122
+ const [visibleKeys, setVisibleKeys] = react_1.default.useState(resolveInitialVisibleKeys);
123
+ react_1.default.useEffect(() => {
124
+ setVisibleKeys(previous => {
125
+ const ordered = (0, schema_1.ensureSchemaOrder)(filterSchema, previous);
126
+ if (ordered.length) {
127
+ return ordered;
128
+ }
129
+ return resolveInitialVisibleKeys();
130
+ });
131
+ }, [filterSchema, resolveInitialVisibleKeys]);
132
+ react_1.default.useEffect(() => {
133
+ (0, storage_1.writeVisibleKeys)(storageKey, visibleKeys);
134
+ onVisibleFieldsChange === null || onVisibleFieldsChange === void 0 ? void 0 : onVisibleFieldsChange(visibleKeys);
135
+ }, [visibleKeys, onVisibleFieldsChange, storageKey]);
136
+ react_1.default.useEffect(() => {
137
+ formMethods.reset(mergedDefaultValues);
138
+ }, [formMethods, mergedDefaultValues]);
139
+ const normalisedValues = react_1.default.useMemo(() => (0, values_1.normaliseOutputValues)(filterSchema, formValues), [filterSchema, formValues]);
140
+ const initialOutputValues = react_1.default.useMemo(() => (0, values_1.normaliseOutputValues)(filterSchema, mergedDefaultValues), [filterSchema, mergedDefaultValues]);
141
+ const hasInitialValues = react_1.default.useMemo(() => Object.keys(initialOutputValues).length > 0, [initialOutputValues]);
142
+ const serialisedValues = react_1.default.useMemo(() => JSON.stringify(normalisedValues), [normalisedValues]);
143
+ const debouncedSerialisedValues = (0, use_debounced_value_1.useDebouncedValue)(serialisedValues, constants_1.FILTER_DEBOUNCE_DELAY);
144
+ const lastPersistedValuesRef = react_1.default.useRef(null);
145
+ const hasEmittedValuesRef = react_1.default.useRef(false);
146
+ react_1.default.useEffect(() => {
147
+ if (debouncedSerialisedValues == null) {
148
+ return;
149
+ }
150
+ if (hasEmittedValuesRef.current &&
151
+ lastPersistedValuesRef.current === debouncedSerialisedValues) {
152
+ return;
153
+ }
154
+ const parsedValues = JSON.parse(debouncedSerialisedValues);
155
+ const isEmpty = Object.keys(parsedValues).length === 0;
156
+ if (!hasEmittedValuesRef.current && isEmpty && !hasInitialValues) {
157
+ hasEmittedValuesRef.current = true;
158
+ lastPersistedValuesRef.current = debouncedSerialisedValues;
159
+ (0, storage_1.clearStoredValues)(storageKey);
160
+ return;
161
+ }
162
+ hasEmittedValuesRef.current = true;
163
+ lastPersistedValuesRef.current = debouncedSerialisedValues;
164
+ onValuesChange === null || onValuesChange === void 0 ? void 0 : onValuesChange(parsedValues);
165
+ if (isEmpty) {
166
+ (0, storage_1.clearStoredValues)(storageKey);
167
+ }
168
+ else {
169
+ (0, storage_1.writeStoredValues)(storageKey, parsedValues);
170
+ }
171
+ }, [debouncedSerialisedValues, hasInitialValues, onValuesChange, storageKey]);
172
+ react_1.default.useEffect(() => {
173
+ lastPersistedValuesRef.current = null;
174
+ }, [storageKey]);
175
+ const handleClearAll = react_1.default.useCallback(() => {
176
+ formMethods.reset(baseDefaultValues);
177
+ onClearAll === null || onClearAll === void 0 ? void 0 : onClearAll();
178
+ (0, storage_1.clearStoredValues)(storageKey);
179
+ }, [baseDefaultValues, formMethods, onClearAll, storageKey]);
180
+ const handleOpenModal = react_1.default.useCallback(() => {
181
+ setIsModalOpen(true);
182
+ setSearchTerm('');
183
+ setModalPage(1);
184
+ }, []);
185
+ const handleCloseModal = react_1.default.useCallback(() => {
186
+ setIsModalOpen(false);
187
+ }, []);
188
+ const handleToggleVisibility = react_1.default.useCallback((key) => {
189
+ setVisibleKeys(prev => {
190
+ const exists = prev.includes(key);
191
+ if (exists && prev.length === 1) {
192
+ return prev;
193
+ }
194
+ const nextKeys = exists
195
+ ? prev.filter(item => item !== key)
196
+ : [...prev, key];
197
+ return (0, schema_1.ensureSchemaOrder)(filterSchema, nextKeys);
198
+ });
199
+ }, [filterSchema]);
200
+ const handleRemoveFilter = react_1.default.useCallback((key) => {
201
+ const schemaField = filterSchema.find(field => String(field.key) === key);
202
+ if (!schemaField) {
203
+ return;
204
+ }
205
+ const defaultValue = baseDefaultValues[String(schemaField.key)];
206
+ formMethods.resetField(schemaField.key, {
207
+ defaultValue
208
+ });
209
+ }, [baseDefaultValues, filterSchema, formMethods]);
210
+ const filteredFields = react_1.default.useMemo(() => {
211
+ const normalisedTerm = searchTerm.trim().toLowerCase();
212
+ if (!normalisedTerm) {
213
+ return filterSchema;
214
+ }
215
+ return filterSchema.filter(field => {
216
+ const searchable = [field.label, field.placeholder, String(field.key)]
217
+ .filter(Boolean)
218
+ .map(value => String(value).toLowerCase());
219
+ return searchable.some(text => text.includes(normalisedTerm));
220
+ });
221
+ }, [filterSchema, searchTerm]);
222
+ const paginatedFields = react_1.default.useMemo(() => {
223
+ const start = (modalPage - 1) * modalPageSize;
224
+ return filteredFields.slice(start, start + modalPageSize);
225
+ }, [filteredFields, modalPage, modalPageSize]);
226
+ const visibleFields = react_1.default.useMemo(() => filterSchema.filter(field => visibleKeys.includes(String(field.key))), [filterSchema, visibleKeys]);
227
+ const renderFieldComponent = (field) => {
228
+ const ariaLabel = (0, schema_1.getFieldAriaLabel)(field);
229
+ switch (field.type) {
230
+ case 'text':
231
+ return (react_1.default.createElement(ui_input_1.Input, { placeholder: field.placeholder, size: "large", allowClear: true, "aria-label": ariaLabel }));
232
+ case 'number':
233
+ return (react_1.default.createElement(ui_input_number_1.InputNumber, { placeholder: field.placeholder, size: "large", className: "akinon-filter__field--number", "aria-label": ariaLabel }));
234
+ case 'select':
235
+ return (react_1.default.createElement(ui_select_1.Select, { placeholder: field.placeholder, size: "large", options: field.options, showSearch: true, optionFilterProp: "label", "aria-label": ariaLabel }));
236
+ case 'checkbox':
237
+ return react_1.default.createElement(ui_checkbox_1.Checkbox, null, field.label);
238
+ case 'date':
239
+ return (react_1.default.createElement(ui_date_picker_1.DatePicker, { placeholder: field.placeholder, size: "large", showTime: field.showTime, suffixIcon: "calendar", suffixIconSize: "16px", "aria-label": ariaLabel }));
240
+ case 'textarea':
241
+ return (react_1.default.createElement(ui_input_1.InputTextArea, { placeholder: field.placeholder, autoSize: { minRows: 3, maxRows: 6 }, "aria-label": ariaLabel }));
242
+ case 'custom':
243
+ if (typeof field.render === 'function') {
244
+ return field.render({
245
+ field,
246
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
247
+ control: formMethods.control,
248
+ formValues: formMethods.getValues(),
249
+ formState: formMethods.formState
250
+ });
251
+ }
252
+ 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) })));
253
+ default:
254
+ 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) })));
255
+ }
256
+ };
257
+ return (react_1.default.createElement(ui_card_1.Card, { size: "small", className: "akinon-filter shadow", "data-testid": "akifilter-root" },
258
+ react_1.default.createElement(antd_1.ConfigProvider, { theme: theme_overrides_1.themeOverrides },
259
+ react_1.default.createElement(filter_toolbar_1.FilterToolbar, { onOpenModal: handleOpenModal, enableImportCsv: enableImportCsv, enableImportXls: enableImportXls, onImportCsv: onImportCsv, onImportXls: onImportXls }),
260
+ react_1.default.createElement(applied_filters_1.AppliedFilters, { filters: appliedFilters, onRemove: handleRemoveFilter, onClearAll: handleClearAll }),
261
+ react_1.default.createElement("div", { className: "akinon-filter__body" },
262
+ react_1.default.createElement(akiform_1.Akiform, { layout: "vertical", className: "akinon-filter__form" },
263
+ react_1.default.createElement("div", { className: "akinon-filter__form-grid", "data-testid": "akifilter-form-grid" },
264
+ visibleFields.map(field => (react_1.default.createElement(akiform_1.FormItem, { key: String(field.key), control: formMethods.control, name: field.key, tooltip: field.tooltip, help: field.help, labelDescription: field.labelDescription, required: Boolean(field.validation), valuePropName: field.type === 'checkbox' ? 'checked' : undefined }, renderFieldComponent(field)))),
265
+ visibleFields.length === 0 ? (react_1.default.createElement("div", { className: "akinon-filter__empty" }, i18n_1.i18n.t('form.noVisibleFields'))) : null))),
266
+ react_1.default.createElement(visibility_modal_1.VisibilityModal, { open: isModalOpen, onClose: handleCloseModal, searchTerm: searchTerm, paginatedFields: paginatedFields, filteredCount: filteredFields.length, visibleKeys: visibleKeys, onSearchTermChange: value => {
267
+ setSearchTerm(value);
268
+ setModalPage(1);
269
+ }, onToggleVisibility: handleToggleVisibility, onPaginationChange: (page, pageSize) => {
270
+ setModalPage(page);
271
+ if (pageSize !== modalPageSize) {
272
+ setModalPageSize(pageSize);
273
+ }
274
+ }, page: modalPage, pageSize: modalPageSize }))));
275
+ };
276
+ const AkifilterEmptyState = () => {
277
+ const { t } = i18n_1.i18n;
278
+ return (react_1.default.createElement(ui_card_1.Card, { size: "small", className: "akinon-filter shadow", "data-testid": "akifilter-empty" },
279
+ react_1.default.createElement(antd_1.ConfigProvider, { theme: theme_overrides_1.themeOverrides },
280
+ react_1.default.createElement("div", { className: "akinon-filter__empty-state" },
281
+ react_1.default.createElement(ui_typography_1.Text, null, t('emptyState.message'))))));
282
+ };
283
+ const renderErrorFallback = ({ resetErrorBoundary }) => {
284
+ const { t } = i18n_1.i18n;
285
+ return (react_1.default.createElement(ui_card_1.Card, { size: "small", className: "akinon-filter shadow", "data-testid": "akifilter-error" },
286
+ react_1.default.createElement(antd_1.ConfigProvider, { theme: theme_overrides_1.themeOverrides },
287
+ react_1.default.createElement("div", { className: "akinon-filter__error-state" },
288
+ react_1.default.createElement(ui_typography_1.Title, { level: 5, className: "akinon-filter__error-title" }, t('errors.title')),
289
+ react_1.default.createElement(ui_typography_1.Text, { type: "secondary", className: "akinon-filter__error-description" }, t('errors.description')),
290
+ react_1.default.createElement(ui_button_1.Button, { type: "primary", onClick: resetErrorBoundary, size: "small" }, t('errors.retry'))))));
291
+ };
292
+ const Akifilter = (props) => {
293
+ const { filterSchema } = props, restProps = __rest(props, ["filterSchema"]);
294
+ const resolvedSchema = (filterSchema !== null && filterSchema !== void 0 ? filterSchema : []);
295
+ const hasSchema = resolvedSchema.length > 0;
296
+ return (react_1.default.createElement(react_error_boundary_1.ErrorBoundary, { fallbackRender: renderErrorFallback }, hasSchema ? (react_1.default.createElement(AkifilterContent, Object.assign({}, restProps, { filterSchema: resolvedSchema }))) : (react_1.default.createElement(AkifilterEmptyState, null))));
297
+ };
298
+ exports.Akifilter = Akifilter;
299
+ exports.Akifilter.displayName = 'Akifilter';
@@ -0,0 +1,10 @@
1
+ import type { FieldValues } from '@akinon/akiform';
2
+ import type { AkifilterField } from '../types';
3
+ export declare const buildStorageKey: <TFieldValues extends FieldValues>(schema: AkifilterField<TFieldValues>[], namespace?: string) => string;
4
+ export declare const readVisibleKeys: <TFieldValues extends FieldValues>(schema: AkifilterField<TFieldValues>[], storageKey: string) => string[] | null;
5
+ export declare const writeVisibleKeys: (storageKey: string, keys: string[]) => void;
6
+ export declare const clearVisibleKeys: (storageKey: string) => void;
7
+ export declare const readStoredValues: <TFieldValues extends FieldValues>(schema: AkifilterField<TFieldValues>[], storageKey: string) => Partial<TFieldValues> | null;
8
+ export declare const writeStoredValues: <TFieldValues extends FieldValues>(storageKey: string, values: Partial<TFieldValues>) => void;
9
+ export declare const clearStoredValues: (storageKey: string) => void;
10
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +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;AAEnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAqB/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,IAuBb,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"}
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.clearStoredValues = exports.writeStoredValues = exports.readStoredValues = exports.clearVisibleKeys = exports.writeVisibleKeys = exports.readVisibleKeys = exports.buildStorageKey = void 0;
4
+ const STORAGE_PREFIX = 'akifilter:v1';
5
+ const VALUES_SUFFIX = ':values';
6
+ const hashString = (value) => {
7
+ let hash = 0;
8
+ for (let i = 0; i < value.length; i += 1) {
9
+ const chr = value.charCodeAt(i);
10
+ hash = (hash << 5) - hash + chr;
11
+ hash |= 0; // Convert to 32bit integer
12
+ }
13
+ return Math.abs(hash).toString(36);
14
+ };
15
+ const buildSchemaSignature = (schema) => {
16
+ return schema.map(field => `${String(field.key)}:${field.type}`).join('|');
17
+ };
18
+ const buildStorageKey = (schema, namespace) => {
19
+ const signature = buildSchemaSignature(schema);
20
+ const hashedSignature = hashString(signature);
21
+ const base = namespace ? namespace.trim() : 'default';
22
+ return `${STORAGE_PREFIX}:${base}:${hashedSignature}`;
23
+ };
24
+ exports.buildStorageKey = buildStorageKey;
25
+ const isBrowser = typeof window !== 'undefined';
26
+ const readVisibleKeys = (schema, storageKey) => {
27
+ if (!isBrowser)
28
+ return null;
29
+ try {
30
+ const rawValue = window.localStorage.getItem(storageKey);
31
+ if (!rawValue) {
32
+ return null;
33
+ }
34
+ const parsed = JSON.parse(rawValue);
35
+ if (!Array.isArray(parsed)) {
36
+ return null;
37
+ }
38
+ const schemaKeys = new Set(schema.map(field => String(field.key)));
39
+ return parsed.filter(key => schemaKeys.has(String(key)));
40
+ }
41
+ catch (error) {
42
+ console.warn('Akifilter: unable to read visibility state from storage', error);
43
+ return null;
44
+ }
45
+ };
46
+ exports.readVisibleKeys = readVisibleKeys;
47
+ const writeVisibleKeys = (storageKey, keys) => {
48
+ if (!isBrowser)
49
+ return;
50
+ try {
51
+ window.localStorage.setItem(storageKey, JSON.stringify(keys));
52
+ }
53
+ catch (error) {
54
+ console.warn('Akifilter: unable to persist visibility state', error);
55
+ }
56
+ };
57
+ exports.writeVisibleKeys = writeVisibleKeys;
58
+ const clearVisibleKeys = (storageKey) => {
59
+ if (!isBrowser)
60
+ return;
61
+ try {
62
+ window.localStorage.removeItem(storageKey);
63
+ }
64
+ catch (error) {
65
+ console.warn('Akifilter: unable to clear visibility state', error);
66
+ }
67
+ };
68
+ exports.clearVisibleKeys = clearVisibleKeys;
69
+ const buildValuesStorageKey = (storageKey) => `${storageKey}${VALUES_SUFFIX}`;
70
+ const readStoredValues = (schema, storageKey) => {
71
+ if (!isBrowser)
72
+ return null;
73
+ try {
74
+ const rawValue = window.localStorage.getItem(buildValuesStorageKey(storageKey));
75
+ if (!rawValue) {
76
+ return null;
77
+ }
78
+ const parsed = JSON.parse(rawValue);
79
+ if (!parsed || typeof parsed !== 'object') {
80
+ return null;
81
+ }
82
+ const schemaKeys = new Set(schema.map(field => String(field.key)));
83
+ return Object.entries(parsed).reduce((acc, [key, value]) => {
84
+ if (schemaKeys.has(String(key))) {
85
+ acc[key] =
86
+ value;
87
+ }
88
+ return acc;
89
+ }, {});
90
+ }
91
+ catch (error) {
92
+ console.warn('Akifilter: unable to read values from storage', error);
93
+ return null;
94
+ }
95
+ };
96
+ exports.readStoredValues = readStoredValues;
97
+ const writeStoredValues = (storageKey, values) => {
98
+ if (!isBrowser)
99
+ return;
100
+ const valuesKey = buildValuesStorageKey(storageKey);
101
+ const entries = Object.entries(values);
102
+ try {
103
+ if (entries.length === 0) {
104
+ window.localStorage.removeItem(valuesKey);
105
+ return;
106
+ }
107
+ window.localStorage.setItem(valuesKey, JSON.stringify(values));
108
+ }
109
+ catch (error) {
110
+ console.warn('Akifilter: unable to persist values', error);
111
+ }
112
+ };
113
+ exports.writeStoredValues = writeStoredValues;
114
+ const clearStoredValues = (storageKey) => {
115
+ if (!isBrowser)
116
+ return;
117
+ try {
118
+ window.localStorage.removeItem(buildValuesStorageKey(storageKey));
119
+ }
120
+ catch (error) {
121
+ console.warn('Akifilter: unable to clear stored values', error);
122
+ }
123
+ };
124
+ exports.clearStoredValues = clearStoredValues;
@@ -0,0 +1,3 @@
1
+ import { ThemeConfig } from 'antd';
2
+ export declare const themeOverrides: ThemeConfig;
3
+ //# sourceMappingURL=theme-overrides.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-overrides.d.ts","sourceRoot":"","sources":["../../../src/common/theme-overrides.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAEnC,eAAO,MAAM,cAAc,EAAE,WAsB5B,CAAC"}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ var _a, _b;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.themeOverrides = void 0;
5
+ const ui_theme_1 = require("@akinon/ui-theme");
6
+ exports.themeOverrides = Object.assign(Object.assign({}, ui_theme_1.theme), { algorithm: ui_theme_1.theme.algorithm, token: {
7
+ colorTextBase: ui_theme_1.theme.colors.ebonyClay['900'],
8
+ colorText: ui_theme_1.theme.colors.ebonyClay['900']
9
+ }, components: Object.assign(Object.assign({}, ui_theme_1.theme.components), { Typography: Object.assign(Object.assign({}, (_a = ui_theme_1.theme.components) === null || _a === void 0 ? void 0 : _a.Typography), { colorTextHeading: ui_theme_1.theme.colors.neutral['100'], colorText: ui_theme_1.theme.colors.neutral['500'], titleMarginBottom: 0 }), Modal: Object.assign(Object.assign({}, (_b = ui_theme_1.theme.components) === null || _b === void 0 ? void 0 : _b.Modal), { headerBg: ui_theme_1.theme.colors.ebonyClay['600'], contentBg: ui_theme_1.theme.colors.ebonyClay['600'], titleColor: ui_theme_1.theme.colors.neutral['200'] }) }) });
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ type AppliedFilter = {
3
+ key: string;
4
+ label: string;
5
+ value: string;
6
+ };
7
+ type AppliedFiltersProps = {
8
+ filters: AppliedFilter[];
9
+ onRemove: (key: string) => void;
10
+ onClearAll: () => void;
11
+ };
12
+ export declare const AppliedFilters: ({ filters, onRemove, onClearAll }: AppliedFiltersProps) => React.JSX.Element;
13
+ export type { AppliedFilter };
14
+ //# sourceMappingURL=applied-filters.d.ts.map
@@ -0,0 +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,sBAoDrB,CAAC;AAEF,YAAY,EAAE,aAAa,EAAE,CAAC"}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AppliedFilters = void 0;
4
+ const icons_1 = require("@akinon/icons");
5
+ const ui_button_1 = require("@akinon/ui-button");
6
+ const ui_space_1 = require("@akinon/ui-space");
7
+ const ui_typography_1 = require("@akinon/ui-typography");
8
+ const react_1 = require("react");
9
+ const i18n_1 = require("../i18n");
10
+ const AppliedFilters = ({ filters, onRemove, onClearAll }) => {
11
+ const hasFilters = filters.length > 0;
12
+ return (react_1.default.createElement("div", { className: "akinon-filter__applied", "data-testid": "akifilter-applied" },
13
+ react_1.default.createElement(ui_space_1.Space, { className: "akinon-filter__applied-summary", size: 8 },
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" },
16
+ react_1.default.createElement("span", { className: "akinon-filter__chip-label" },
17
+ item.label,
18
+ ":"),
19
+ react_1.default.createElement("span", { className: "akinon-filter__chip-value" }, item.value),
20
+ react_1.default.createElement("button", { type: "button", "aria-label": i18n_1.i18n.t('applied.clearSingle', {
21
+ field: item.label
22
+ }), className: "akinon-filter__chip-button", onClick: () => onRemove(item.key) },
23
+ react_1.default.createElement(icons_1.Icon, { icon: "no", size: 16 }))))))) : (react_1.default.createElement(ui_typography_1.Text, { className: "akinon-filter__applied-empty" }, i18n_1.i18n.t('applied.empty')))),
24
+ react_1.default.createElement(ui_button_1.Button, { className: "akinon-filter__clear", icon: "bin", iconSize: 16, onClick: onClearAll, size: "small", type: "icon", title: i18n_1.i18n.t('applied.clearAll'), "aria-label": i18n_1.i18n.t('applied.clearAll'), disabled: !hasFilters })));
25
+ };
26
+ exports.AppliedFilters = AppliedFilters;
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ type FilterToolbarProps = {
3
+ onOpenModal: () => void;
4
+ enableImportCsv?: boolean;
5
+ enableImportXls?: boolean;
6
+ onImportCsv?: () => void;
7
+ onImportXls?: () => void;
8
+ };
9
+ export declare const FilterToolbar: ({ onOpenModal, enableImportCsv, enableImportXls, onImportCsv, onImportXls }: FilterToolbarProps) => React.JSX.Element;
10
+ export {};
11
+ //# sourceMappingURL=filter-toolbar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter-toolbar.d.ts","sourceRoot":"","sources":["../../../src/components/filter-toolbar.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,KAAK,kBAAkB,GAAG;IACxB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,6EAM3B,kBAAkB,sBAwCpB,CAAC"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FilterToolbar = void 0;
4
+ const ui_button_1 = require("@akinon/ui-button");
5
+ const ui_space_1 = require("@akinon/ui-space");
6
+ const ui_typography_1 = require("@akinon/ui-typography");
7
+ const react_1 = require("react");
8
+ const i18n_1 = require("../i18n");
9
+ const FilterToolbar = ({ onOpenModal, enableImportCsv, enableImportXls, onImportCsv, onImportXls }) => {
10
+ return (react_1.default.createElement("div", { className: "akinon-filter__top" },
11
+ react_1.default.createElement(ui_typography_1.Title, { className: "akinon-filter__title", level: 4 }, i18n_1.i18n.t('header.title')),
12
+ react_1.default.createElement(ui_space_1.Space, { className: "akinon-filter__toolbar", size: 6 },
13
+ enableImportCsv && onImportCsv ? (react_1.default.createElement(ui_button_1.Button, { className: "akinon-filter__toolbar-item", onClick: onImportCsv, type: "primary" }, i18n_1.i18n.t('header.actions.importCsv'))) : null,
14
+ enableImportXls && onImportXls ? (react_1.default.createElement(ui_button_1.Button, { className: "akinon-filter__toolbar-item", onClick: onImportXls, type: "primary" }, i18n_1.i18n.t('header.actions.importXls'))) : null,
15
+ react_1.default.createElement(ui_button_1.Button, { className: "akinon-filter__toolbar-item", icon: "filter", iconSize: 16, onClick: onOpenModal, type: "primary", title: i18n_1.i18n.t('header.actions.selectFilters'), "aria-label": i18n_1.i18n.t('header.actions.selectFilters') }))));
16
+ };
17
+ exports.FilterToolbar = FilterToolbar;