@akinon/akifilter 1.3.6 → 1.4.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 (71) hide show
  1. package/dist/cjs/akifilter.d.ts +16 -4
  2. package/dist/cjs/akifilter.d.ts.map +1 -1
  3. package/dist/cjs/akifilter.js +93 -26
  4. package/dist/cjs/common/storage.d.ts.map +1 -1
  5. package/dist/cjs/common/storage.js +6 -1
  6. package/dist/cjs/components/applied-filters.d.ts.map +1 -1
  7. package/dist/cjs/components/applied-filters.js +2 -2
  8. package/dist/cjs/components/filter-toolbar.d.ts +2 -2
  9. package/dist/cjs/components/filter-toolbar.d.ts.map +1 -1
  10. package/dist/cjs/components/filter-toolbar.js +18 -2
  11. package/dist/cjs/filter-builder.d.ts +3 -3
  12. package/dist/cjs/filter-builder.d.ts.map +1 -1
  13. package/dist/cjs/filter-builder.js +5 -8
  14. package/dist/cjs/hooks/use-dynamic-visibility.d.ts +8 -0
  15. package/dist/cjs/hooks/use-dynamic-visibility.d.ts.map +1 -0
  16. package/dist/cjs/hooks/use-dynamic-visibility.js +36 -0
  17. package/dist/cjs/hooks/use-visibility-cleanup.d.ts +13 -0
  18. package/dist/cjs/hooks/use-visibility-cleanup.d.ts.map +1 -0
  19. package/dist/cjs/hooks/use-visibility-cleanup.js +39 -0
  20. package/dist/cjs/i18n/translations/en.d.ts +2 -2
  21. package/dist/cjs/i18n/translations/en.js +2 -2
  22. package/dist/cjs/i18n/translations/tr.d.ts +2 -2
  23. package/dist/cjs/i18n/translations/tr.js +2 -2
  24. package/dist/cjs/index.d.ts +1 -0
  25. package/dist/cjs/index.d.ts.map +1 -1
  26. package/dist/cjs/index.js +1 -0
  27. package/dist/cjs/styles.css +15 -3
  28. package/dist/cjs/styles.d.ts +1 -0
  29. package/dist/cjs/types.d.ts +9 -6
  30. package/dist/cjs/types.d.ts.map +1 -1
  31. package/dist/cjs/utils/schema.d.ts +5 -0
  32. package/dist/cjs/utils/schema.d.ts.map +1 -1
  33. package/dist/cjs/utils/schema.js +25 -3
  34. package/dist/cjs/utils/values.d.ts.map +1 -1
  35. package/dist/cjs/utils/values.js +3 -0
  36. package/dist/esm/akifilter.d.ts +16 -4
  37. package/dist/esm/akifilter.d.ts.map +1 -1
  38. package/dist/esm/akifilter.js +94 -27
  39. package/dist/esm/common/storage.d.ts.map +1 -1
  40. package/dist/esm/common/storage.js +6 -1
  41. package/dist/esm/components/applied-filters.d.ts.map +1 -1
  42. package/dist/esm/components/applied-filters.js +2 -2
  43. package/dist/esm/components/filter-toolbar.d.ts +2 -2
  44. package/dist/esm/components/filter-toolbar.d.ts.map +1 -1
  45. package/dist/esm/components/filter-toolbar.js +18 -2
  46. package/dist/esm/filter-builder.d.ts +3 -3
  47. package/dist/esm/filter-builder.d.ts.map +1 -1
  48. package/dist/esm/filter-builder.js +5 -8
  49. package/dist/esm/hooks/use-dynamic-visibility.d.ts +8 -0
  50. package/dist/esm/hooks/use-dynamic-visibility.d.ts.map +1 -0
  51. package/dist/esm/hooks/use-dynamic-visibility.js +32 -0
  52. package/dist/esm/hooks/use-visibility-cleanup.d.ts +13 -0
  53. package/dist/esm/hooks/use-visibility-cleanup.d.ts.map +1 -0
  54. package/dist/esm/hooks/use-visibility-cleanup.js +35 -0
  55. package/dist/esm/i18n/translations/en.d.ts +2 -2
  56. package/dist/esm/i18n/translations/en.js +2 -2
  57. package/dist/esm/i18n/translations/tr.d.ts +2 -2
  58. package/dist/esm/i18n/translations/tr.js +2 -2
  59. package/dist/esm/index.d.ts +1 -0
  60. package/dist/esm/index.d.ts.map +1 -1
  61. package/dist/esm/index.js +1 -0
  62. package/dist/esm/styles.css +15 -3
  63. package/dist/esm/styles.d.ts +1 -0
  64. package/dist/esm/types.d.ts +9 -6
  65. package/dist/esm/types.d.ts.map +1 -1
  66. package/dist/esm/utils/schema.d.ts +5 -0
  67. package/dist/esm/utils/schema.d.ts.map +1 -1
  68. package/dist/esm/utils/schema.js +22 -2
  69. package/dist/esm/utils/values.d.ts.map +1 -1
  70. package/dist/esm/utils/values.js +3 -0
  71. package/package.json +25 -22
@@ -22,13 +22,24 @@
22
22
  height: 36px;
23
23
  }
24
24
 
25
+ .akinon-filter__toolbar-item--file {
26
+ width: 36px;
27
+ font-size: 11px;
28
+ font-weight: bold;
29
+ flex-direction: column;
30
+ justify-content: flex-end;
31
+ gap: 2px;
32
+ padding-inline: 0;
33
+ padding-block-end: 4px;
34
+ }
35
+
25
36
  .akinon-filter__applied {
26
37
  display: flex;
27
38
  align-items: center;
28
39
  padding: 6px;
29
40
  background-color: var(--color-ebonyClay-500);
30
41
  border-radius: 6px;
31
- box-shadow: inset 0 1px 4px 0 rgba(0, 0, 0, 0.2);
42
+ box-shadow: inset 0 1px 4px 0 var(--color-neutral-1000-20);
32
43
  margin-bottom: 1rem;
33
44
  }
34
45
 
@@ -89,12 +100,13 @@
89
100
  color: var(--color-gray-500);
90
101
  }
91
102
 
92
- .akinon-filter__section-fields .akinon-collapse-expand-icon .akinon-collapse-arrow {
103
+ .akinon-filter__section-fields
104
+ .akinon-collapse-expand-icon
105
+ .akinon-collapse-arrow {
93
106
  font-size: 1rem !important;
94
107
  color: var(--color-gray-500) !important;
95
108
  }
96
109
 
97
-
98
110
  @media (max-width: 1024px) {
99
111
  .akinon-filter__form-grid {
100
112
  grid-template-columns: repeat(2, minmax(0, 1fr));
@@ -0,0 +1 @@
1
+ declare module '*.css';
@@ -10,17 +10,19 @@ export interface AkifilterFieldConfig<TFieldValues extends FieldValues = FieldVa
10
10
  * Controls whether the field is visible.
11
11
  * Can be a boolean or a function that receives form values and returns a boolean.
12
12
  */
13
- visible?: boolean | ((formValues: TFieldValues) => boolean);
13
+ visible?: boolean | ((formValues: TFieldValues, currentVisible?: boolean) => boolean);
14
14
  }
15
- export type AkifilterField<TFieldValues extends FieldValues = FieldValues> = FormField<TFieldValues> & {
16
- /**
17
- * Controls whether the field is shown in the main filter form by default.
18
- */
19
- isVisible?: boolean;
15
+ type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
16
+ export type AkifilterField<TFieldValues extends FieldValues = FieldValues> = DistributiveOmit<FormField<TFieldValues>, 'config'> & {
20
17
  /**
21
18
  * Configuration options for field behavior (disabled, visible).
22
19
  */
23
20
  config?: AkifilterFieldConfig<TFieldValues>;
21
+ /**
22
+ * Accepted file types for file fields (e.g. '.csv,.xls').
23
+ * Only applicable when `type` is `'file'`.
24
+ */
25
+ fileAccept?: string;
24
26
  };
25
27
  export type AkifilterFieldKey<TFieldValues extends FieldValues = FieldValues> = Path<TFieldValues>;
26
28
  export type AkifilterSchema<TFieldValues extends FieldValues = FieldValues> = AkifilterField<TFieldValues>[];
@@ -34,4 +36,5 @@ export interface AkifilterActionsRef {
34
36
  */
35
37
  clearValue: (keys: string | string[]) => void;
36
38
  }
39
+ export {};
37
40
  //# sourceMappingURL=types.d.ts.map
@@ -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;AAEzD,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,EAAE,OAAO,GAAG,CAAC,CAAC,UAAU,EAAE,YAAY,KAAK,OAAO,CAAC,CAAC;CAC7D;AAED,MAAM,MAAM,cAAc,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW,IACvE,SAAS,CAAC,YAAY,CAAC,GAAG;IACxB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAC,YAAY,CAAC,CAAC;CAC7C,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;;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,MAAM,yBAAyB,CAAC;AAEzD,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;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC;CAC/C"}
@@ -17,7 +17,12 @@ export declare const partitionSchema: <TFieldValues extends FieldValues = FieldV
17
17
  export declare const getDisplayLabel: <TFieldValues extends FieldValues = FieldValues>(field: AkifilterField<TFieldValues>) => string;
18
18
  export declare const getFieldAriaLabel: <TFieldValues extends FieldValues = FieldValues>(field: AkifilterField<TFieldValues>) => string;
19
19
  export declare const ensureSchemaOrder: <TFieldValues extends FieldValues = FieldValues>(schema: AkifilterSchema<TFieldValues>, keys: string[]) => string[];
20
+ /**
21
+ * Resolves the visibility of a field.
22
+ */
23
+ export declare const resolveFieldVisibility: <TFieldValues extends FieldValues = FieldValues>(field: AkifilterField<TFieldValues>, formValues?: TFieldValues, currentVisible?: boolean) => boolean | undefined;
20
24
  export declare const deriveDefaultVisibleKeys: <TFieldValues extends FieldValues = FieldValues>(schema: AkifilterSchema<TFieldValues>) => string[];
21
25
  export declare const extractDefaultValues: <TFieldValues extends FieldValues = FieldValues>(schema: AkifilterSchema<TFieldValues>) => Partial<TFieldValues>;
26
+ export declare const hasDynamicVisibility: <TFieldValues extends FieldValues>(field: AkifilterField<TFieldValues>) => boolean;
22
27
  export declare const normaliseValuesBySchema: <TFieldValues extends FieldValues = FieldValues>(schema: AkifilterSchema<TFieldValues>, values?: Partial<TFieldValues>) => Partial<TFieldValues>;
23
28
  //# sourceMappingURL=schema.d.ts.map
@@ -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;AAGnD,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;AAEF,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,uBAAuB,GAClC,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,QAAQ,eAAe,CAAC,YAAY,CAAC,EACrC,SAAS,OAAO,CAAC,YAAY,CAAC,KAC7B,OAAO,CAAC,YAAY,CA+BtB,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;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,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.normaliseValuesBySchema = exports.extractDefaultValues = exports.deriveDefaultVisibleKeys = 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.partitionSchema = exports.flattenSchema = void 0;
4
4
  const akidate_1 = require("@akinon/akidate");
5
+ const lodash_es_1 = require("lodash-es");
5
6
  const constants_1 = require("../constants");
6
7
  /**
7
8
  * Flattens schema by extracting all nested fields from section fields.
@@ -50,12 +51,24 @@ const ensureSchemaOrder = (schema, keys) => {
50
51
  return schema.map(field => String(field.key)).filter(key => keySet.has(key));
51
52
  };
52
53
  exports.ensureSchemaOrder = ensureSchemaOrder;
54
+ const resolveVisibilityValue = (value, formValues, currentVisible) => {
55
+ if ((0, lodash_es_1.isBoolean)(value))
56
+ return value;
57
+ if ((0, lodash_es_1.isFunction)(value))
58
+ return value(formValues !== null && formValues !== void 0 ? formValues : {}, currentVisible !== null && currentVisible !== void 0 ? currentVisible : false);
59
+ return undefined;
60
+ };
61
+ /**
62
+ * Resolves the visibility of a field.
63
+ */
64
+ const resolveFieldVisibility = (field, formValues, currentVisible) => { var _a; return resolveVisibilityValue((_a = field.config) === null || _a === void 0 ? void 0 : _a.visible, formValues, currentVisible); };
65
+ exports.resolveFieldVisibility = resolveFieldVisibility;
53
66
  const deriveDefaultVisibleKeys = (schema) => {
54
67
  const explicitKeys = schema
55
- .filter(field => field.isVisible)
68
+ .filter(field => (0, exports.resolveFieldVisibility)(field) === true)
56
69
  .map(field => String(field.key));
57
70
  if (explicitKeys.length > 0) {
58
- return (0, exports.ensureSchemaOrder)(schema, Array.from(new Set(explicitKeys)));
71
+ return (0, exports.ensureSchemaOrder)(schema, explicitKeys);
59
72
  }
60
73
  return schema.slice(0, constants_1.DEFAULT_VISIBLE_COUNT).map(field => String(field.key));
61
74
  };
@@ -70,6 +83,8 @@ const extractDefaultValues = (schema) => {
70
83
  }, {});
71
84
  };
72
85
  exports.extractDefaultValues = extractDefaultValues;
86
+ const hasDynamicVisibility = (field) => { var _a; return (0, lodash_es_1.isFunction)((_a = field.config) === null || _a === void 0 ? void 0 : _a.visible); };
87
+ exports.hasDynamicVisibility = hasDynamicVisibility;
73
88
  const normaliseValuesBySchema = (schema, values) => {
74
89
  if (!values) {
75
90
  return {};
@@ -88,6 +103,13 @@ const normaliseValuesBySchema = (schema, values) => {
88
103
  return acc;
89
104
  }
90
105
  }
106
+ if (field.type === 'select' &&
107
+ (field.mode === 'multiple' || field.mode === 'tags') &&
108
+ currentValue != null &&
109
+ !Array.isArray(currentValue)) {
110
+ acc[key] = [currentValue];
111
+ return acc;
112
+ }
91
113
  acc[key] = currentValue;
92
114
  return acc;
93
115
  }, {});
@@ -1 +1 @@
1
- {"version":3,"file":"values.d.ts","sourceRoot":"","sources":["../../../src/utils/values.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEhE,eAAO,MAAM,kBAAkB,GAC7B,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,OAAO,cAAc,CAAC,YAAY,CAAC,GAAG,SAAS,EAC/C,OAAO,OAAO,KACb,OAkBF,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,QAAQ,eAAe,CAAC,YAAY,CAAC,EACrC,SAAS,OAAO,CAAC,YAAY,CAAC,GAAG,WAAW,KAC3C,OAAO,CAAC,YAAY,CAkCtB,CAAC"}
1
+ {"version":3,"file":"values.d.ts","sourceRoot":"","sources":["../../../src/utils/values.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEhE,eAAO,MAAM,kBAAkB,GAC7B,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,OAAO,cAAc,CAAC,YAAY,CAAC,GAAG,SAAS,EAC/C,OAAO,OAAO,KACb,OAsBF,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,YAAY,SAAS,WAAW,GAAG,WAAW,EAE9C,QAAQ,eAAe,CAAC,YAAY,CAAC,EACrC,SAAS,OAAO,CAAC,YAAY,CAAC,GAAG,WAAW,KAC3C,OAAO,CAAC,YAAY,CAkCtB,CAAC"}
@@ -16,6 +16,9 @@ const shouldPersistValue = (field, value) => {
16
16
  if ((field === null || field === void 0 ? void 0 : field.type) === 'checkbox' && value !== true) {
17
17
  return false;
18
18
  }
19
+ if ((field === null || field === void 0 ? void 0 : field.type) === 'file') {
20
+ return value instanceof File;
21
+ }
19
22
  return true;
20
23
  };
21
24
  exports.shouldPersistValue = shouldPersistValue;
@@ -1,6 +1,7 @@
1
1
  import './styles.css';
2
2
  import { FieldValues, Path } from '@akinon/akiform';
3
3
  import React from 'react';
4
+ import { type AppliedFilter } from './components/applied-filters';
4
5
  import type { AkifilterActionsRef, AkifilterSchema } from './types';
5
6
  type AkifilterFieldValues = FieldValues;
6
7
  export type AkifilterProps<TFieldValues extends AkifilterFieldValues = AkifilterFieldValues> = {
@@ -25,13 +26,15 @@ export type AkifilterProps<TFieldValues extends AkifilterFieldValues = Akifilter
25
26
  */
26
27
  onVisibleFieldsChange?: (keys: Array<Path<TFieldValues>>) => void;
27
28
  /**
28
- * Triggered when user opts to import filters via CSV.
29
+ * Triggered when user selects a file via the CSV import button.
30
+ * Receives the selected File object.
29
31
  */
30
- onImportCsv?: () => void;
32
+ onImportCsv?: (file: File) => void;
31
33
  /**
32
- * Triggered when user opts to import filters via XLS/XLSX.
34
+ * Triggered when user selects a file via the XLS import button.
35
+ * Receives the selected File object.
33
36
  */
34
- onImportXls?: () => void;
37
+ onImportXls?: (file: File) => void;
35
38
  /**
36
39
  * Triggered when user requests clearing all filters.
37
40
  */
@@ -48,6 +51,15 @@ export type AkifilterProps<TFieldValues extends AkifilterFieldValues = Akifilter
48
51
  * Ref to access imperative filter actions like clearing values.
49
52
  */
50
53
  filterActionsRef?: React.Ref<AkifilterActionsRef>;
54
+ /**
55
+ * Additional chips to display in the applied filters area alongside form-based filters.
56
+ * Useful for out-of-band filters such as file uploads.
57
+ */
58
+ externalAppliedFilters?: AppliedFilter[];
59
+ /**
60
+ * Called when the user removes an externally-provided chip.
61
+ */
62
+ onRemoveExternalFilter?: (key: string) => void;
51
63
  };
52
64
  export declare const Akifilter: {
53
65
  <TFieldValues extends AkifilterFieldValues = FieldValues>(props: AkifilterProps<TFieldValues>): React.JSX.Element;
@@ -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;AAWzB,OAAO,KAAK,MAAM,OAAO,CAAC;AA0B1B,OAAO,KAAK,EACV,mBAAmB,EAEnB,eAAe,EAChB,MAAM,SAAS,CAAC;AAYjB,KAAK,oBAAoB,GAAG,WAAW,CAAC;AA0HxC,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;IAC1B;;OAEG;IACH,gBAAgB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;CACnD,CAAC;AA8wBF,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;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"}
@@ -21,6 +21,7 @@ import { Input, InputTextArea } from '@akinon/ui-input';
21
21
  import { InputNumber } from '@akinon/ui-input-number';
22
22
  import { Select } from '@akinon/ui-select';
23
23
  import { Text, Title } from '@akinon/ui-typography';
24
+ import { Upload } from '@akinon/ui-upload';
24
25
  import { ConfigProvider } from 'antd';
25
26
  import React from 'react';
26
27
  import { ErrorBoundary } from 'react-error-boundary';
@@ -31,8 +32,10 @@ import { FilterToolbar } from './components/filter-toolbar';
31
32
  import { VisibilityModal } from './components/visibility-modal';
32
33
  import { BOOLEAN_STRING, DEFAULT_MODAL_PAGE_SIZE, FILTER_DEBOUNCE_DELAY } from './constants';
33
34
  import { useDebouncedValue } from './hooks/use-debounced-value';
35
+ import { useDynamicVisibility } from './hooks/use-dynamic-visibility';
36
+ import { useVisibilityCleanup } from './hooks/use-visibility-cleanup';
34
37
  import { i18n } from './i18n';
35
- import { deriveDefaultVisibleKeys, ensureSchemaOrder, extractDefaultValues, flattenSchema, getFieldAriaLabel, normaliseValuesBySchema, partitionSchema } from './utils/schema';
38
+ import { deriveDefaultVisibleKeys, ensureSchemaOrder, extractDefaultValues, flattenSchema, getFieldAriaLabel, normaliseValuesBySchema, partitionSchema, resolveFieldVisibility } from './utils/schema';
36
39
  import { normaliseOutputValues } from './utils/values';
37
40
  const FilterFormItem = (_a) => {
38
41
  var _b, _c;
@@ -60,6 +63,21 @@ const FilterFormItem = (_a) => {
60
63
  });
61
64
  return (React.createElement(Akiform.Item, Object.assign({}, props, { validateStatus: fieldState.invalid ? 'error' : undefined, help: (_c = (_b = fieldState.error) === null || _b === void 0 ? void 0 : _b.message) !== null && _c !== void 0 ? _c : props.help, className: props.className }), childrenWithProps));
62
65
  };
66
+ const FileFilterInput = ({ value, onChange, accept, disabled, 'aria-label': ariaLabel }) => {
67
+ const handleBeforeUpload = (file) => {
68
+ var _a;
69
+ onChange === null || onChange === void 0 ? void 0 : onChange((_a = file.originFileObj) !== null && _a !== void 0 ? _a : file);
70
+ // Prevent antd from uploading automatically
71
+ return false;
72
+ };
73
+ const handleRemove = () => {
74
+ onChange === null || onChange === void 0 ? void 0 : onChange(null);
75
+ };
76
+ const fileList = value
77
+ ? [{ uid: value.name, name: value.name, originFileObj: value }]
78
+ : [];
79
+ return (React.createElement(Upload, { accept: accept, beforeUpload: handleBeforeUpload, onRemove: handleRemove, fileList: fileList, maxCount: 1, disabled: disabled, "aria-label": ariaLabel }));
80
+ };
63
81
  /**
64
82
  * Checks if a field should be disabled based on config.disabled property.
65
83
  */
@@ -71,17 +89,6 @@ const checkIsDisabled = (field, formValues) => {
71
89
  }
72
90
  return Boolean(configDisabled);
73
91
  };
74
- /**
75
- * Checks if a field should be visible based on config.visible property.
76
- */
77
- const checkIsVisible = (field, formValues) => {
78
- var _a;
79
- const configVisible = (_a = field.config) === null || _a === void 0 ? void 0 : _a.visible;
80
- if (typeof configVisible === 'function') {
81
- return configVisible(formValues);
82
- }
83
- return configVisible !== false;
84
- };
85
92
  const resolveClearedFieldValue = (field, defaultValue) => {
86
93
  if (defaultValue !== undefined) {
87
94
  return defaultValue;
@@ -94,13 +101,19 @@ const resolveClearedFieldValue = (field, defaultValue) => {
94
101
  return false;
95
102
  case 'number':
96
103
  case 'date':
104
+ return null;
97
105
  case 'select':
106
+ if (field.mode === 'multiple' || field.mode === 'tags') {
107
+ return [];
108
+ }
109
+ return null;
110
+ case 'file':
98
111
  return null;
99
112
  default:
100
113
  return undefined;
101
114
  }
102
115
  };
103
- const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onValuesChange, onVisibleFieldsChange, onImportCsv, onImportXls, onClearAll, enableImportCsv, enableImportXls, filterActionsRef }) => {
116
+ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onValuesChange, onVisibleFieldsChange, onImportCsv, onImportXls, onClearAll, enableImportCsv, enableImportXls, filterActionsRef, externalAppliedFilters, onRemoveExternalFilter }) => {
104
117
  // Separate regular fields from section fields
105
118
  const { regularFields, sectionFields } = React.useMemo(() => partitionSchema(filterSchema), [filterSchema]);
106
119
  // Flatten schema for storage and form value operations
@@ -148,15 +161,29 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
148
161
  return acc;
149
162
  }
150
163
  const label = field.label || field.placeholder || key;
151
- const resolveSelectLabel = () => {
164
+ const fieldOptions = 'options' in field && field.options ? field.options : undefined;
165
+ const resolveLabel = (val) => {
152
166
  var _a;
153
- if (!('options' in field) || !field.options) {
167
+ const match = fieldOptions === null || fieldOptions === void 0 ? void 0 : fieldOptions.find(option => option.value === val);
168
+ return String((_a = match === null || match === void 0 ? void 0 : match.label) !== null && _a !== void 0 ? _a : val);
169
+ };
170
+ const resolveArrayLabels = (values) => {
171
+ return values.map(resolveLabel).join(', ');
172
+ };
173
+ const resolveSelectLabel = () => {
174
+ if (!fieldOptions) {
154
175
  return String(currentValue);
155
176
  }
156
- const match = field.options.find(option => option.value === currentValue);
157
- return String((_a = match === null || match === void 0 ? void 0 : match.label) !== null && _a !== void 0 ? _a : currentValue);
177
+ if (Array.isArray(currentValue)) {
178
+ return resolveArrayLabels(currentValue);
179
+ }
180
+ return resolveLabel(currentValue);
158
181
  };
159
182
  const resolveValue = () => {
183
+ if (field.type === 'file') {
184
+ const fileValue = currentValue;
185
+ return fileValue instanceof File ? fileValue.name : String(fileValue);
186
+ }
160
187
  if (field.type === 'select') {
161
188
  return resolveSelectLabel();
162
189
  }
@@ -175,7 +202,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
175
202
  }
176
203
  }
177
204
  if (Array.isArray(currentValue)) {
178
- return currentValue.map((value) => String(value)).join(', ');
205
+ return resolveArrayLabels(currentValue);
179
206
  }
180
207
  if (typeof currentValue === 'boolean') {
181
208
  return currentValue ? BOOLEAN_STRING.TRUE : BOOLEAN_STRING.FALSE;
@@ -197,10 +224,24 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
197
224
  }, [flattenedSchema, formValues]);
198
225
  const resolveInitialVisibleKeys = React.useCallback(() => {
199
226
  const storedKeys = readVisibleKeys(regularFields, storageKey);
200
- if (storedKeys && storedKeys.length > 0) {
201
- return ensureSchemaOrder(regularFields, storedKeys);
202
- }
203
- return deriveDefaultVisibleKeys(regularFields);
227
+ const defaultKeys = deriveDefaultVisibleKeys(regularFields);
228
+ const baseKeys = storedKeys && storedKeys.length > 0
229
+ ? ensureSchemaOrder(regularFields, storedKeys)
230
+ : defaultKeys;
231
+ return regularFields.reduce((acc, field) => {
232
+ const key = String(field.key);
233
+ const explicitVisibility = resolveFieldVisibility(field);
234
+ if (explicitVisibility !== undefined) {
235
+ if (explicitVisibility)
236
+ acc.push(key);
237
+ return acc;
238
+ }
239
+ // No explicit boolean visibility, use stored/default
240
+ if (baseKeys.includes(key)) {
241
+ acc.push(key);
242
+ }
243
+ return acc;
244
+ }, []);
204
245
  }, [regularFields, storageKey]);
205
246
  const [visibleKeys, setVisibleKeys] = React.useState(resolveInitialVisibleKeys);
206
247
  React.useEffect(() => {
@@ -425,8 +466,31 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
425
466
  const start = (modalPage - 1) * modalPageSize;
426
467
  return filteredFields.slice(start, start + modalPageSize);
427
468
  }, [filteredFields, modalPage, modalPageSize]);
428
- const visibleFields = React.useMemo(() => regularFields.filter(field => visibleKeys.includes(String(field.key)) &&
429
- checkIsVisible(field, formValues !== null && formValues !== void 0 ? formValues : {})), [regularFields, visibleKeys, formValues]);
469
+ const visibleFields = React.useMemo(() => regularFields.filter(field => visibleKeys.includes(String(field.key))), [regularFields, visibleKeys]);
470
+ // Dynamic visibility
471
+ useDynamicVisibility({
472
+ regularFields,
473
+ formValues: normalisedValues,
474
+ setVisibleKeys
475
+ });
476
+ // Visibility cleanup
477
+ useVisibilityCleanup({
478
+ visibleKeys,
479
+ regularFields,
480
+ onRemove: handleRemoveFilter
481
+ });
482
+ const handleAppliedFilterRemove = React.useCallback((key) => {
483
+ if (externalAppliedFilters === null || externalAppliedFilters === void 0 ? void 0 : externalAppliedFilters.some(f => f.key === key)) {
484
+ onRemoveExternalFilter === null || onRemoveExternalFilter === void 0 ? void 0 : onRemoveExternalFilter(key);
485
+ }
486
+ else {
487
+ handleRemoveFilter(key);
488
+ }
489
+ }, [externalAppliedFilters, onRemoveExternalFilter, handleRemoveFilter]);
490
+ const handleClearAllApplied = React.useCallback(() => {
491
+ handleClearAll();
492
+ externalAppliedFilters === null || externalAppliedFilters === void 0 ? void 0 : externalAppliedFilters.forEach(f => onRemoveExternalFilter === null || onRemoveExternalFilter === void 0 ? void 0 : onRemoveExternalFilter(f.key));
493
+ }, [handleClearAll, externalAppliedFilters, onRemoveExternalFilter]);
430
494
  const renderFieldComponent = (field) => {
431
495
  const ariaLabel = getFieldAriaLabel(field);
432
496
  const isDisabled = checkIsDisabled(field, formValues !== null && formValues !== void 0 ? formValues : {});
@@ -436,17 +500,20 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
436
500
  case 'number':
437
501
  return (React.createElement(InputNumber, { placeholder: field.placeholder, size: "large", className: "akinon-filter__field--number", "aria-label": ariaLabel, disabled: isDisabled }));
438
502
  case 'select':
439
- return (React.createElement(Select, { placeholder: field.placeholder, size: "large", options: field.options, showSearch: true, optionFilterProp: "label", "aria-label": ariaLabel, disabled: isDisabled }));
503
+ return (React.createElement(Select, { placeholder: field.placeholder, size: "large", options: field.options, showSearch: true, optionFilterProp: "label", "aria-label": ariaLabel, disabled: isDisabled, mode: field.mode }));
440
504
  case 'checkbox':
441
505
  return React.createElement(Checkbox, { disabled: isDisabled }, field.label);
442
506
  case 'date':
443
507
  return (React.createElement(DatePicker, { placeholder: field.placeholder, showTime: field.showTime, suffixIcon: "calendar", suffixIconSize: "16px", "aria-label": ariaLabel, disabled: isDisabled }));
444
508
  case 'textarea':
445
509
  return (React.createElement(InputTextArea, { placeholder: field.placeholder, autoSize: { minRows: 3, maxRows: 6 }, "aria-label": ariaLabel, disabled: isDisabled }));
510
+ case 'file':
511
+ return (React.createElement(FileFilterInput, { accept: field.fileAccept, "aria-label": ariaLabel, disabled: isDisabled }));
446
512
  case 'custom':
447
513
  if (typeof field.render === 'function') {
448
514
  return field.render({
449
- field,
515
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
516
+ field: field,
450
517
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
451
518
  control: formMethods.control,
452
519
  formValues: formMethods.getValues(),
@@ -468,7 +535,7 @@ const AkifilterContent = ({ filterSchema, storageNamespace, defaultValues, onVal
468
535
  return (React.createElement(Card, { size: "small", className: "akinon-filter shadow", "data-testid": "akifilter-root" },
469
536
  React.createElement(ConfigProvider, { theme: themeOverrides },
470
537
  React.createElement(FilterToolbar, { onOpenModal: handleOpenModal, enableImportCsv: enableImportCsv, enableImportXls: enableImportXls, onImportCsv: onImportCsv, onImportXls: onImportXls }),
471
- React.createElement(AppliedFilters, { filters: appliedFilters, onRemove: handleRemoveFilter, onClearAll: handleClearAll }),
538
+ React.createElement(AppliedFilters, { filters: [...appliedFilters, ...(externalAppliedFilters !== null && externalAppliedFilters !== void 0 ? externalAppliedFilters : [])], onRemove: handleAppliedFilterRemove, onClearAll: handleClearAllApplied }),
472
539
  React.createElement("div", { className: "akinon-filter__body" },
473
540
  React.createElement(Akiform, { layout: "vertical", className: "akinon-filter__form" },
474
541
  React.createElement("div", { className: "akinon-filter__form-grid", "data-testid": "akifilter-form-grid" },
@@ -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;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,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"}
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;AA2B/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"}
@@ -11,7 +11,12 @@ const hashString = (value) => {
11
11
  return Math.abs(hash).toString(36);
12
12
  };
13
13
  const buildSchemaSignature = (schema) => {
14
- return schema.map(field => `${String(field.key)}:${field.type}`).join('|');
14
+ return schema
15
+ .map(field => {
16
+ const mode = field.type === 'select' && field.mode ? `:${field.mode}` : '';
17
+ return `${String(field.key)}:${field.type}${mode}`;
18
+ })
19
+ .join('|');
15
20
  };
16
21
  export const buildStorageKey = (schema, namespace) => {
17
22
  const signature = buildSchemaSignature(schema);
@@ -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,sBAoDrB,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;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"}
@@ -10,9 +10,9 @@ export const AppliedFilters = ({ filters, onRemove, onClearAll }) => {
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
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" },
13
- React.createElement("span", { className: "akinon-filter__chip-label" },
13
+ item.label ? (React.createElement("span", { className: "akinon-filter__chip-label" },
14
14
  item.label,
15
- ":"),
15
+ ":")) : null,
16
16
  React.createElement("span", { className: "akinon-filter__chip-value" }, item.value),
17
17
  React.createElement("button", { type: "button", "aria-label": i18n.t('applied.clearSingle', {
18
18
  field: item.label
@@ -3,8 +3,8 @@ type FilterToolbarProps = {
3
3
  onOpenModal: () => void;
4
4
  enableImportCsv?: boolean;
5
5
  enableImportXls?: boolean;
6
- onImportCsv?: () => void;
7
- onImportXls?: () => void;
6
+ onImportCsv?: (file: File) => void;
7
+ onImportXls?: (file: File) => void;
8
8
  };
9
9
  export declare const FilterToolbar: ({ onOpenModal, enableImportCsv, enableImportXls, onImportCsv, onImportXls }: FilterToolbarProps) => React.JSX.Element;
10
10
  export {};
@@ -1 +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"}
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,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;CACpC,CAAC;AAgDF,eAAO,MAAM,aAAa,GAAI,6EAM3B,kBAAkB,sBAoCpB,CAAC"}
@@ -3,11 +3,27 @@ import { Space } from '@akinon/ui-space';
3
3
  import { Title } from '@akinon/ui-typography';
4
4
  import React from 'react';
5
5
  import { i18n } from '../i18n';
6
+ const FileImportButton = ({ accept, label, onImport }) => {
7
+ const inputRef = React.useRef(null);
8
+ const handleClick = () => { var _a; return (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.click(); };
9
+ const handleChange = (e) => {
10
+ var _a;
11
+ const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
12
+ if (file) {
13
+ onImport(file);
14
+ }
15
+ // Reset so same file can be re-selected
16
+ e.target.value = '';
17
+ };
18
+ return (React.createElement(React.Fragment, null,
19
+ React.createElement("input", { ref: inputRef, type: "file", accept: accept, style: { display: 'none' }, onChange: handleChange }),
20
+ React.createElement(Button, { className: "akinon-filter__toolbar-item akinon-filter__toolbar-item--file", icon: "filter", iconSize: 13, onClick: handleClick, type: "primary", title: label, "aria-label": label }, label)));
21
+ };
6
22
  export const FilterToolbar = ({ onOpenModal, enableImportCsv, enableImportXls, onImportCsv, onImportXls }) => {
7
23
  return (React.createElement("div", { className: "akinon-filter__top" },
8
24
  React.createElement(Title, { className: "akinon-filter__title", level: 4 }, i18n.t('header.title')),
9
25
  React.createElement(Space, { className: "akinon-filter__toolbar", size: 6 },
10
- enableImportCsv && onImportCsv ? (React.createElement(Button, { className: "akinon-filter__toolbar-item", onClick: onImportCsv, type: "primary" }, i18n.t('header.actions.importCsv'))) : null,
11
- enableImportXls && onImportXls ? (React.createElement(Button, { className: "akinon-filter__toolbar-item", onClick: onImportXls, type: "primary" }, i18n.t('header.actions.importXls'))) : null,
26
+ enableImportCsv && onImportCsv ? (React.createElement(FileImportButton, { accept: ".csv", label: i18n.t('header.actions.importCsv'), onImport: onImportCsv })) : null,
27
+ enableImportXls && onImportXls ? (React.createElement(FileImportButton, { accept: ".xls,.xlsx", label: i18n.t('header.actions.importXls'), onImport: onImportXls })) : null,
12
28
  React.createElement(Button, { className: "akinon-filter__toolbar-item", icon: "filter", iconSize: 16, onClick: onOpenModal, type: "primary", title: i18n.t('header.actions.selectFilters'), "aria-label": i18n.t('header.actions.selectFilters') }))));
13
29
  };
@@ -1,9 +1,9 @@
1
1
  import type { FieldValues } from '@akinon/akiform';
2
2
  import { field } from '@akinon/akiform-builder';
3
- import type { AkifilterField } from './types';
3
+ import type { AkifilterField, AkifilterFieldConfig } from './types';
4
4
  type BaseBuilder<TFieldValues extends FieldValues> = ReturnType<typeof field<TFieldValues>>;
5
- type AkifilterFieldBuilder<TFieldValues extends FieldValues> = BaseBuilder<TFieldValues> & {
6
- visible(isVisible?: boolean): AkifilterFieldBuilder<TFieldValues>;
5
+ type AkifilterFieldBuilder<TFieldValues extends FieldValues> = Omit<BaseBuilder<TFieldValues>, 'build' | 'config'> & {
6
+ config(cfg: AkifilterFieldConfig<TFieldValues>): AkifilterFieldBuilder<TFieldValues>;
7
7
  build(): AkifilterField<TFieldValues>;
8
8
  };
9
9
  export declare const filterField: <TFieldValues extends FieldValues = FieldValues>() => AkifilterFieldBuilder<TFieldValues>;
@@ -1 +1 @@
1
- {"version":3,"file":"filter-builder.d.ts","sourceRoot":"","sources":["../../src/filter-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAEhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,KAAK,WAAW,CAAC,YAAY,SAAS,WAAW,IAAI,UAAU,CAC7D,OAAO,KAAK,CAAC,YAAY,CAAC,CAC3B,CAAC;AAEF,KAAK,qBAAqB,CAAC,YAAY,SAAS,WAAW,IACzD,WAAW,CAAC,YAAY,CAAC,GAAG;IAC1B,OAAO,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC;IAClE,KAAK,IAAI,cAAc,CAAC,YAAY,CAAC,CAAC;CACvC,CAAC;AAEJ,eAAO,MAAM,WAAW,GACtB,YAAY,SAAS,WAAW,GAAG,WAAW,0CA8B/C,CAAC;AAEF,YAAY,EAAE,qBAAqB,EAAE,CAAC"}
1
+ {"version":3,"file":"filter-builder.d.ts","sourceRoot":"","sources":["../../src/filter-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAEhD,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEpE,KAAK,WAAW,CAAC,YAAY,SAAS,WAAW,IAAI,UAAU,CAC7D,OAAO,KAAK,CAAC,YAAY,CAAC,CAC3B,CAAC;AAEF,KAAK,qBAAqB,CAAC,YAAY,SAAS,WAAW,IAAI,IAAI,CACjE,WAAW,CAAC,YAAY,CAAC,EACzB,OAAO,GAAG,QAAQ,CACnB,GAAG;IACF,MAAM,CACJ,GAAG,EAAE,oBAAoB,CAAC,YAAY,CAAC,GACtC,qBAAqB,CAAC,YAAY,CAAC,CAAC;IACvC,KAAK,IAAI,cAAc,CAAC,YAAY,CAAC,CAAC;CACvC,CAAC;AAEF,eAAO,MAAM,WAAW,GACtB,YAAY,SAAS,WAAW,GAAG,WAAW,0CA+B/C,CAAC;AAEF,YAAY,EAAE,qBAAqB,EAAE,CAAC"}
@@ -1,21 +1,18 @@
1
1
  import { field } from '@akinon/akiform-builder';
2
2
  export const filterField = () => {
3
3
  const baseBuilder = field();
4
- let visibility;
4
+ let fieldConfig;
5
5
  const builder = baseBuilder;
6
- builder.visible = (isVisible = true) => {
7
- visibility = isVisible;
6
+ builder.config = cfg => {
7
+ fieldConfig = Object.assign(Object.assign({}, fieldConfig), cfg);
8
8
  return builder;
9
9
  };
10
10
  const originalBuild = baseBuilder.build.bind(baseBuilder);
11
11
  builder.build = () => {
12
12
  const builtField = originalBuild();
13
13
  const filterFieldDefinition = Object.assign({}, builtField);
14
- if (visibility !== undefined) {
15
- filterFieldDefinition.isVisible = visibility;
16
- }
17
- else {
18
- delete filterFieldDefinition.isVisible;
14
+ if (fieldConfig !== undefined) {
15
+ filterFieldDefinition.config = Object.assign(Object.assign({}, filterFieldDefinition.config), fieldConfig);
19
16
  }
20
17
  return filterFieldDefinition;
21
18
  };
@@ -0,0 +1,8 @@
1
+ import type { FieldValues } from '@akinon/akiform';
2
+ import type { AkifilterSchema } from '../types';
3
+ export declare const useDynamicVisibility: <TFieldValues extends FieldValues>({ regularFields, formValues, setVisibleKeys }: {
4
+ regularFields: AkifilterSchema<TFieldValues>;
5
+ formValues: Partial<TFieldValues> | undefined;
6
+ setVisibleKeys: React.Dispatch<React.SetStateAction<string[]>>;
7
+ }) => void;
8
+ //# sourceMappingURL=use-dynamic-visibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-dynamic-visibility.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-dynamic-visibility.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AA0ChD,eAAO,MAAM,oBAAoB,GAAI,YAAY,SAAS,WAAW,EAAE,+CAIpE;IACD,aAAa,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;IAC7C,UAAU,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC;IAC9C,cAAc,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;CAChE,SAcA,CAAC"}