@planningcenter/tapestry 4.8.0-rc.0 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist/components/DataTable/ActiveFilterInstance.d.ts +2 -2
  2. package/dist/components/DataTable/ActiveFilterInstance.d.ts.map +1 -1
  3. package/dist/components/DataTable/ActiveFilterInstance.js +4 -1
  4. package/dist/components/DataTable/ActiveFilterInstance.js.map +1 -1
  5. package/dist/components/DataTable/ActiveFilters.d.ts +7 -4
  6. package/dist/components/DataTable/ActiveFilters.d.ts.map +1 -1
  7. package/dist/components/DataTable/ActiveFilters.js +43 -15
  8. package/dist/components/DataTable/ActiveFilters.js.map +1 -1
  9. package/dist/components/DataTable/CollectionEditorsShared.d.ts +33 -0
  10. package/dist/components/DataTable/CollectionEditorsShared.d.ts.map +1 -0
  11. package/dist/components/DataTable/CollectionEditorsShared.js +16 -0
  12. package/dist/components/DataTable/CollectionEditorsShared.js.map +1 -0
  13. package/dist/components/DataTable/CollectionEditorsStatic.d.ts +14 -0
  14. package/dist/components/DataTable/CollectionEditorsStatic.d.ts.map +1 -0
  15. package/dist/components/DataTable/CollectionEditorsStatic.js +67 -0
  16. package/dist/components/DataTable/CollectionEditorsStatic.js.map +1 -0
  17. package/dist/components/DataTable/DataTable.d.ts +1 -1
  18. package/dist/components/DataTable/DataTable.d.ts.map +1 -1
  19. package/dist/components/DataTable/DataTable.js +59 -56
  20. package/dist/components/DataTable/DataTable.js.map +1 -1
  21. package/dist/components/DataTable/FilterChip.d.ts.map +1 -1
  22. package/dist/components/DataTable/FilterChip.js +25 -1
  23. package/dist/components/DataTable/FilterChip.js.map +1 -1
  24. package/dist/components/DataTable/FilterContext.d.ts +10 -1
  25. package/dist/components/DataTable/FilterContext.d.ts.map +1 -1
  26. package/dist/components/DataTable/FilterContext.js +52 -9
  27. package/dist/components/DataTable/FilterContext.js.map +1 -1
  28. package/dist/components/DataTable/FilterControls.d.ts.map +1 -1
  29. package/dist/components/DataTable/FilterControls.js +85 -23
  30. package/dist/components/DataTable/FilterControls.js.map +1 -1
  31. package/dist/components/DataTable/FilterControls.module.css.js +4 -0
  32. package/dist/components/DataTable/FilterControls.module.css.js.map +1 -0
  33. package/dist/components/DataTable/FilterTypes.d.ts +34 -0
  34. package/dist/components/DataTable/FilterTypes.d.ts.map +1 -1
  35. package/dist/components/DataTable/FilterTypes.js +7 -0
  36. package/dist/components/DataTable/FilterTypes.js.map +1 -0
  37. package/dist/components/DataTable/PendingFilterContext.d.ts +12 -0
  38. package/dist/components/DataTable/PendingFilterContext.d.ts.map +1 -0
  39. package/dist/components/DataTable/PendingFilterContext.js +33 -0
  40. package/dist/components/DataTable/PendingFilterContext.js.map +1 -0
  41. package/dist/components/DataTable/PendingFilterQueue.d.ts +13 -0
  42. package/dist/components/DataTable/PendingFilterQueue.d.ts.map +1 -0
  43. package/dist/components/DataTable/PendingFilterQueue.js +42 -0
  44. package/dist/components/DataTable/PendingFilterQueue.js.map +1 -0
  45. package/dist/components/DataTable/SearchableFilters.d.ts +4 -0
  46. package/dist/components/DataTable/SearchableFilters.d.ts.map +1 -1
  47. package/dist/components/DataTable/SearchableFilters.js +26 -0
  48. package/dist/components/DataTable/SearchableFilters.js.map +1 -1
  49. package/dist/components/DataTable/collectionFilter.d.ts +0 -2
  50. package/dist/components/DataTable/collectionFilter.d.ts.map +1 -1
  51. package/dist/components/DataTable/collectionFilter.js +3 -45
  52. package/dist/components/DataTable/collectionFilter.js.map +1 -1
  53. package/dist/components/DataTable/dateFilter.d.ts.map +1 -1
  54. package/dist/components/DataTable/dateFilter.js +23 -7
  55. package/dist/components/DataTable/dateFilter.js.map +1 -1
  56. package/dist/components/DataTable/filters.d.ts +1 -0
  57. package/dist/components/DataTable/filters.d.ts.map +1 -1
  58. package/dist/components/DataTable/index.d.ts +2 -1
  59. package/dist/components/DataTable/index.d.ts.map +1 -1
  60. package/dist/components/DataTable/numberFilter.d.ts.map +1 -1
  61. package/dist/components/DataTable/numberFilter.js +15 -4
  62. package/dist/components/DataTable/numberFilter.js.map +1 -1
  63. package/dist/components/DataTable/scopedFilter.d.ts +13 -0
  64. package/dist/components/DataTable/scopedFilter.d.ts.map +1 -0
  65. package/dist/components/DataTable/scopedFilter.js +114 -0
  66. package/dist/components/DataTable/scopedFilter.js.map +1 -0
  67. package/dist/components/DataTable/textFilter.d.ts.map +1 -1
  68. package/dist/components/DataTable/textFilter.js +8 -3
  69. package/dist/components/DataTable/textFilter.js.map +1 -1
  70. package/dist/components/DataTable/useShelfExpanded.d.ts +4 -3
  71. package/dist/components/DataTable/useShelfExpanded.d.ts.map +1 -1
  72. package/dist/components/DataTable/useShelfExpanded.js +16 -8
  73. package/dist/components/DataTable/useShelfExpanded.js.map +1 -1
  74. package/dist/components/DataTable/utils.d.ts +4 -0
  75. package/dist/components/DataTable/utils.d.ts.map +1 -0
  76. package/dist/components/DataTable/utils.js +13 -0
  77. package/dist/components/DataTable/utils.js.map +1 -0
  78. package/dist/components/currency-input/CurrencyInput.d.ts +51 -0
  79. package/dist/components/currency-input/CurrencyInput.d.ts.map +1 -0
  80. package/dist/components/currency-input/CurrencyInput.js +64 -0
  81. package/dist/components/currency-input/CurrencyInput.js.map +1 -0
  82. package/dist/components/currency-input/index.d.ts +4 -0
  83. package/dist/components/currency-input/index.d.ts.map +1 -0
  84. package/dist/components/popover/Popover.d.ts +12 -7
  85. package/dist/components/popover/Popover.d.ts.map +1 -1
  86. package/dist/components/popover/Popover.js +26 -4
  87. package/dist/components/popover/Popover.js.map +1 -1
  88. package/dist/reactRender.css +1305 -1090
  89. package/dist/reactRender.css.map +1 -1
  90. package/dist/reactRenderLegacy.css +1305 -1090
  91. package/dist/reactRenderLegacy.css.map +1 -1
  92. package/dist/unstable.css +442 -227
  93. package/dist/unstable.css.map +1 -1
  94. package/dist/unstable.d.ts +1 -0
  95. package/dist/unstable.d.ts.map +1 -1
  96. package/dist/unstable.js +2 -0
  97. package/dist/unstable.js.map +1 -1
  98. package/package.json +3 -3
@@ -1,11 +1,6 @@
1
- import { Checkbox } from '../checkbox/Checkbox.js';
2
- import { CheckboxGroup } from '../checkbox-group/CheckboxGroup.js';
3
- import { ComboBox, ComboBoxItem } from '../combo-box/ComboBox.js';
4
- import { Radio } from '../radio/Radio.js';
5
- import { RadioGroup } from '../radio-group/RadioGroup.js';
6
- import { Select } from '../select/Select.js';
7
1
  import React__default from 'react';
8
2
  import { ActiveFilterInstance } from './ActiveFilterInstance.js';
3
+ import { CollectionFilterEditorStatic } from './CollectionEditorsStatic.js';
9
4
  import { resolveOperators } from './resolveOperators.js';
10
5
 
11
6
  const COLLECTION_IS = {
@@ -19,9 +14,6 @@ const COLLECTION_NOT = {
19
14
  name: "not",
20
15
  };
21
16
  const COLLECTION_OPERATORS = [COLLECTION_IS, COLLECTION_NOT];
22
- function orderByOptions(options, selected) {
23
- return options.filter((o) => selected.has(o.value)).map((o) => o.value);
24
- }
25
17
  function collectionFilter({ display = "select", excludes, includes, multiple = false, options, ...config }) {
26
18
  const filter = {
27
19
  ...config,
@@ -43,44 +35,10 @@ class CollectionActiveFilter extends ActiveFilterInstance {
43
35
  value)
44
36
  .join(", ");
45
37
  }
46
- renderEditor(updateActiveFilter) {
47
- const { display, multiple, options } = this.config;
48
- const onCommit = (value) => updateActiveFilter({ value });
49
- if (display === "combobox") {
50
- return (React__default.createElement(ComboBox, { hideLabel: true, label: this.operator.label, selectionMode: multiple ? "multiple" : "single", value: this.value, onChange: (value) => {
51
- if (Array.isArray(value)) {
52
- onCommit(orderByOptions(options, new Set(value.map(String))));
53
- }
54
- else if (value !== null) {
55
- onCommit(String(value));
56
- }
57
- } }, options.map((option) => (React__default.createElement(ComboBoxItem, { key: option.value, id: option.value }, option.label)))));
58
- }
59
- if (multiple) {
60
- const selected = Array.isArray(this.value) ? this.value : [this.value];
61
- return (React__default.createElement(CheckboxesEditor, { label: this.filter.label, options: options, value: selected, onCommit: onCommit }));
62
- }
63
- const selected = Array.isArray(this.value) ? this.value[0] : this.value;
64
- if (display === "checkboxes") {
65
- return (React__default.createElement(RadiosEditor, { label: this.filter.label, name: this.filter.name, options: options, value: selected, onCommit: onCommit }));
66
- }
67
- return (React__default.createElement(Select, { hideLabel: true, label: this.operator.label, options: options, value: selected, onChange: (e) => onCommit(e.target.value) }));
38
+ renderEditor(onChange) {
39
+ return (React__default.createElement(CollectionFilterEditorStatic, { config: this.config, onChange: onChange, operator: this.operator, value: this.value, filter: this.filter }));
68
40
  }
69
41
  }
70
- function CheckboxesEditor({ label, onCommit, options, value, }) {
71
- const toggle = (optionValue, checked) => {
72
- const next = new Set(value);
73
- if (checked)
74
- next.add(optionValue);
75
- else
76
- next.delete(optionValue);
77
- onCommit(orderByOptions(options, next));
78
- };
79
- return (React__default.createElement(CheckboxGroup, { label: label }, options.map((option) => (React__default.createElement(Checkbox, { key: option.value, checked: value.includes(option.value), label: option.label, onChange: (e) => toggle(option.value, e.target.checked) })))));
80
- }
81
- function RadiosEditor({ label, name, onCommit, options, value, }) {
82
- return (React__default.createElement(RadioGroup, { label: label }, options.map((option) => (React__default.createElement(Radio, { key: option.value, checked: value === option.value, label: option.label, name: name, onChange: () => onCommit(option.value) })))));
83
- }
84
42
 
85
43
  export { COLLECTION_IS, COLLECTION_NOT, collectionFilter };
86
44
  //# sourceMappingURL=collectionFilter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"collectionFilter.js","sources":["../../../src/components/DataTable/collectionFilter.tsx"],"sourcesContent":["import { Checkbox } from \"@components/checkbox\"\nimport { CheckboxGroup } from \"@components/checkbox-group\"\nimport { ComboBox, ComboBoxItem } from \"@components/combo-box\"\nimport { Radio } from \"@components/radio\"\nimport { RadioGroup } from \"@components/radio-group\"\nimport { Select } from \"@components/select\"\nimport React from \"react\"\n\nimport { ActiveFilterInstance } from \"./ActiveFilterInstance\"\nimport type {\n FilterItemConfig,\n FilterNodeItem,\n Operator,\n UpdateActiveFilter,\n} from \"./FilterTypes\"\nimport { resolveOperators } from \"./resolveOperators\"\n\n// A type alias (not an interface) so it satisfies `Select`'s `data-*` index signature.\nexport type CollectionOption = {\n label: string\n value: string\n}\n\n/** A single option's `value`, or the selected `value`s when `multiple`. */\nexport type CollectionFilterValue = string | string[]\n\nexport type CollectionDisplay = \"checkboxes\" | \"combobox\" | \"select\"\n\nexport const COLLECTION_IS = {\n inputType: { type: \"collection\" },\n label: \"is\",\n name: \"eq\",\n} as const satisfies Operator\nexport const COLLECTION_NOT = {\n inputType: { type: \"collection\" },\n label: \"is not\",\n name: \"not\",\n} as const satisfies Operator\n\nconst COLLECTION_OPERATORS = [COLLECTION_IS, COLLECTION_NOT]\n\nexport type CollectionOperatorName =\n (typeof COLLECTION_OPERATORS)[number][\"name\"]\n\nexport type CollectionFilterConfig =\n FilterItemConfig<CollectionOperatorName> & {\n options: CollectionOption[]\n } & (\n | { display?: CollectionDisplay; multiple?: false }\n | { display?: Exclude<CollectionDisplay, \"select\">; multiple: true }\n )\n\nfunction orderByOptions(options: CollectionOption[], selected: Set<string>) {\n return options.filter((o) => selected.has(o.value)).map((o) => o.value)\n}\n\nexport function collectionFilter({\n display = \"select\",\n excludes,\n includes,\n multiple = false,\n options,\n ...config\n}: CollectionFilterConfig): FilterNodeItem {\n const filter: FilterNodeItem = {\n ...config,\n createActiveFilterInstance: (activeFilter, operator) =>\n new CollectionActiveFilter(\n filter,\n operator,\n activeFilter.value as CollectionFilterValue,\n { display, multiple, options }\n ),\n operators: resolveOperators(COLLECTION_OPERATORS, { excludes, includes }),\n }\n return filter\n}\n\nclass CollectionActiveFilter extends ActiveFilterInstance<CollectionFilterValue> {\n constructor(\n filter: FilterNodeItem,\n operator: FilterNodeItem[\"operators\"][number],\n value: CollectionFilterValue,\n private readonly config: {\n display: CollectionDisplay\n multiple: boolean\n options: CollectionOption[]\n }\n ) {\n super(filter, operator, value)\n }\n\n formatValue() {\n const values = Array.isArray(this.value) ? this.value : [this.value]\n return values\n .map(\n (value) =>\n this.config.options.find((option) => option.value === value)?.label ??\n value\n )\n .join(\", \")\n }\n\n renderEditor(updateActiveFilter: UpdateActiveFilter) {\n const { display, multiple, options } = this.config\n const onCommit = (value: CollectionFilterValue) =>\n updateActiveFilter({ value })\n\n if (display === \"combobox\") {\n return (\n <ComboBox\n hideLabel\n label={this.operator.label}\n selectionMode={multiple ? \"multiple\" : \"single\"}\n value={this.value}\n onChange={(value: React.Key | React.Key[] | null) => {\n if (Array.isArray(value)) {\n onCommit(orderByOptions(options, new Set(value.map(String))))\n } else if (value !== null) {\n onCommit(String(value))\n }\n }}\n >\n {options.map((option) => (\n <ComboBoxItem key={option.value} id={option.value}>\n {option.label}\n </ComboBoxItem>\n ))}\n </ComboBox>\n )\n }\n\n if (multiple) {\n const selected = Array.isArray(this.value) ? this.value : [this.value]\n return (\n <CheckboxesEditor\n label={this.filter.label}\n options={options}\n value={selected}\n onCommit={onCommit}\n />\n )\n }\n\n const selected = Array.isArray(this.value) ? this.value[0] : this.value\n if (display === \"checkboxes\") {\n return (\n <RadiosEditor\n label={this.filter.label}\n name={this.filter.name}\n options={options}\n value={selected}\n onCommit={onCommit}\n />\n )\n }\n return (\n <Select\n hideLabel\n label={this.operator.label}\n options={options}\n value={selected}\n onChange={(e) => onCommit(e.target.value)}\n />\n )\n }\n}\n\nfunction CheckboxesEditor({\n label,\n onCommit,\n options,\n value,\n}: {\n label: string\n onCommit: (value: string[]) => void\n options: CollectionOption[]\n value: string[]\n}) {\n const toggle = (optionValue: string, checked: boolean) => {\n const next = new Set(value)\n if (checked) next.add(optionValue)\n else next.delete(optionValue)\n onCommit(orderByOptions(options, next))\n }\n return (\n <CheckboxGroup label={label}>\n {options.map((option) => (\n <Checkbox\n key={option.value}\n checked={value.includes(option.value)}\n label={option.label}\n onChange={(e) => toggle(option.value, e.target.checked)}\n />\n ))}\n </CheckboxGroup>\n )\n}\n\nfunction RadiosEditor({\n label,\n name,\n onCommit,\n options,\n value,\n}: {\n label: string\n name: string\n onCommit: (value: string) => void\n options: CollectionOption[]\n value: string\n}) {\n return (\n <RadioGroup label={label}>\n {options.map((option) => (\n <Radio\n key={option.value}\n checked={value === option.value}\n label={option.label}\n name={name}\n onChange={() => onCommit(option.value)}\n />\n ))}\n </RadioGroup>\n )\n}\n"],"names":["React"],"mappings":"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"}
1
+ {"version":3,"file":"collectionFilter.js","sources":["../../../src/components/DataTable/collectionFilter.tsx"],"sourcesContent":["import React from \"react\"\n\nimport { ActiveFilterInstance } from \"./ActiveFilterInstance\"\nimport type { CollectionFilterValue } from \"./CollectionEditorsShared\"\nimport { CollectionFilterEditorStatic } from \"./CollectionEditorsStatic\"\nimport type {\n FilterChange,\n FilterItemConfig,\n FilterNodeItem,\n Operator,\n} from \"./FilterTypes\"\nimport { resolveOperators } from \"./resolveOperators\"\n\n// A type alias (not an interface) so it satisfies `Select`'s `data-*` index signature.\nexport type CollectionOption = {\n label: string\n value: string\n}\n\nexport type CollectionDisplay = \"checkboxes\" | \"combobox\" | \"select\"\n\nexport const COLLECTION_IS = {\n inputType: { type: \"collection\" },\n label: \"is\",\n name: \"eq\",\n} as const satisfies Operator\nexport const COLLECTION_NOT = {\n inputType: { type: \"collection\" },\n label: \"is not\",\n name: \"not\",\n} as const satisfies Operator\n\nconst COLLECTION_OPERATORS = [COLLECTION_IS, COLLECTION_NOT]\n\nexport type CollectionOperatorName =\n (typeof COLLECTION_OPERATORS)[number][\"name\"]\n\nexport type CollectionFilterConfig =\n FilterItemConfig<CollectionOperatorName> & {\n options: CollectionOption[]\n } & (\n | { display?: CollectionDisplay; multiple?: false }\n | { display?: Exclude<CollectionDisplay, \"select\">; multiple: true }\n )\n\nexport function collectionFilter({\n display = \"select\",\n excludes,\n includes,\n multiple = false,\n options,\n ...config\n}: CollectionFilterConfig): FilterNodeItem {\n const filter: FilterNodeItem = {\n ...config,\n createActiveFilterInstance: (activeFilter, operator) =>\n new CollectionActiveFilter(\n filter,\n operator,\n activeFilter.value as CollectionFilterValue,\n { display, multiple, options }\n ),\n operators: resolveOperators(COLLECTION_OPERATORS, { excludes, includes }),\n }\n return filter\n}\n\nclass CollectionActiveFilter extends ActiveFilterInstance<CollectionFilterValue> {\n constructor(\n filter: FilterNodeItem,\n operator: FilterNodeItem[\"operators\"][number],\n value: CollectionFilterValue,\n private readonly config: {\n display: CollectionDisplay\n multiple: boolean\n options: CollectionOption[]\n }\n ) {\n super(filter, operator, value)\n }\n\n formatValue() {\n const values = Array.isArray(this.value) ? this.value : [this.value]\n return values\n .map(\n (value) =>\n this.config.options.find((option) => option.value === value)?.label ??\n value\n )\n .join(\", \")\n }\n\n renderEditor(onChange: FilterChange) {\n return (\n <CollectionFilterEditorStatic\n config={this.config}\n onChange={onChange}\n operator={this.operator}\n value={this.value}\n filter={this.filter}\n />\n )\n }\n}\n"],"names":["React"],"mappings":";;;;;AAqBO,MAAM,aAAa,GAAG;AAC3B,IAAA,SAAS,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;AACjC,IAAA,KAAK,EAAE,IAAI;AACX,IAAA,IAAI,EAAE,IAAI;;AAEL,MAAM,cAAc,GAAG;AAC5B,IAAA,SAAS,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;AACjC,IAAA,KAAK,EAAE,QAAQ;AACf,IAAA,IAAI,EAAE,KAAK;;AAGb,MAAM,oBAAoB,GAAG,CAAC,aAAa,EAAE,cAAc,CAAC;AAatD,SAAU,gBAAgB,CAAC,EAC/B,OAAO,GAAG,QAAQ,EAClB,QAAQ,EACR,QAAQ,EACR,QAAQ,GAAG,KAAK,EAChB,OAAO,EACP,GAAG,MAAM,EACc,EAAA;AACvB,IAAA,MAAM,MAAM,GAAmB;AAC7B,QAAA,GAAG,MAAM;QACT,0BAA0B,EAAE,CAAC,YAAY,EAAE,QAAQ,KACjD,IAAI,sBAAsB,CACxB,MAAM,EACN,QAAQ,EACR,YAAY,CAAC,KAA8B,EAC3C,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAC/B;QACH,SAAS,EAAE,gBAAgB,CAAC,oBAAoB,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;KAC1E;AACD,IAAA,OAAO,MAAM;AACf;AAEA,MAAM,sBAAuB,SAAQ,oBAA2C,CAAA;AAK3D,IAAA,MAAA;AAJnB,IAAA,WAAA,CACE,MAAsB,EACtB,QAA6C,EAC7C,KAA4B,EACX,MAIhB,EAAA;AAED,QAAA,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC;QANb,IAAA,CAAA,MAAM,GAAN,MAAM;IAOzB;IAEA,WAAW,GAAA;QACT,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;AACpE,QAAA,OAAO;aACJ,GAAG,CACF,CAAC,KAAK,KACJ,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,KAAK,KAAK,KAAK,CAAC,EAAE,KAAK;AACnE,YAAA,KAAK;aAER,IAAI,CAAC,IAAI,CAAC;IACf;AAEA,IAAA,YAAY,CAAC,QAAsB,EAAA;AACjC,QAAA,QACEA,cAAA,CAAA,aAAA,CAAC,4BAA4B,EAAA,EAC3B,MAAM,EAAE,IAAI,CAAC,MAAM,EACnB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,IAAI,CAAC,QAAQ,EACvB,KAAK,EAAE,IAAI,CAAC,KAAK,EACjB,MAAM,EAAE,IAAI,CAAC,MAAM,EAAA,CACnB;IAEN;AACD;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"dateFilter.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/dateFilter.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EAGf,MAAM,eAAe,CAAA;AAGtB,sDAAsD;AACtD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAEvD,eAAO,MAAM,OAAO;;;;;;CAIS,CAAA;AAC7B,eAAO,MAAM,MAAM;;;;;;CAIU,CAAA;AAC7B,eAAO,MAAM,KAAK;;;;;;CAIW,CAAA;AAC7B,eAAO,MAAM,UAAU;;;;;;CAIM,CAAA;AAE7B,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;IAAuC,CAAA;AAE3D,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAA;AAUtE,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,QAAQ,EACR,GAAG,MAAM,EACV,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,GAAG,cAAc,CAYrD"}
1
+ {"version":3,"file":"dateFilter.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/dateFilter.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAEV,gBAAgB,EAChB,cAAc,EAEf,MAAM,eAAe,CAAA;AAGtB,sDAAsD;AACtD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAEvD,eAAO,MAAM,OAAO;;;;;;CAIS,CAAA;AAC7B,eAAO,MAAM,MAAM;;;;;;CAIU,CAAA;AAC7B,eAAO,MAAM,KAAK;;;;;;CAIW,CAAA;AAC7B,eAAO,MAAM,UAAU;;;;;;CAIM,CAAA;AAE7B,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;IAAuC,CAAA;AAE3D,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAA;AAUtE,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,QAAQ,EACR,GAAG,MAAM,EACV,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,GAAG,cAAc,CAYrD"}
@@ -40,25 +40,41 @@ function dateFilter({ excludes, includes, ...config }) {
40
40
  }
41
41
  class DateActiveFilter extends ActiveFilterInstance {
42
42
  formatValue() {
43
- return Array.isArray(this.value)
44
- ? [formatDate(this.value[0]), "and", formatDate(this.value[1])]
45
- : formatDate(this.value);
43
+ if (Array.isArray(this.value)) {
44
+ const [start, end] = this.value;
45
+ if (start === undefined || end === undefined) {
46
+ return [start, end].filter((date) => date !== undefined).map(formatDate);
47
+ }
48
+ return [formatDate(start), "and", formatDate(end)];
49
+ }
50
+ return this.value === undefined ? "" : formatDate(this.value);
46
51
  }
47
- renderEditor(updateActiveFilter) {
52
+ renderEditor(onChange) {
48
53
  const { label } = this.operator;
49
54
  if (this.operator.inputType.type === "date-range") {
50
55
  const range = Array.isArray(this.value)
51
56
  ? this.value
52
57
  : [this.value, this.value];
53
- return (React__default.createElement(DateRangeEditor, { label: label, value: range, onCommit: (value) => updateActiveFilter({ value }) }));
58
+ return (React__default.createElement(DateRangeEditor, { label: label, value: range, onCommit: (value) => {
59
+ const complete = value.length === 2 && value.every((v) => v !== undefined);
60
+ onChange({ value }, { complete });
61
+ } }));
54
62
  }
55
63
  const single = Array.isArray(this.value) ? this.value[0] : this.value;
56
- return (React__default.createElement(DatePicker, { hideLabel: true, label: label, value: single, onChange: (date) => date && updateActiveFilter({ value: date.toString() }) }));
64
+ return (React__default.createElement(DatePicker
65
+ // eslint-disable-next-line jsx-a11y/no-autofocus -- the editor only ever renders inside a chip popover that just opened, per ARIA dialog practices
66
+ , {
67
+ // eslint-disable-next-line jsx-a11y/no-autofocus -- the editor only ever renders inside a chip popover that just opened, per ARIA dialog practices
68
+ autoFocus: true, hideLabel: true, label: label, value: single, onChange: (date) => date && onChange({ value: date.toString() }) }));
57
69
  }
58
70
  }
59
71
  function DateRangeEditor({ label, onCommit, value: [start, end], }) {
60
72
  return (React__default.createElement(Flex, { gap: 1 },
61
- React__default.createElement(DatePicker, { hideLabel: true, label: `${label} from`, value: start, onChange: (date) => date && onCommit([date.toString(), end]) }),
73
+ React__default.createElement(DatePicker
74
+ // eslint-disable-next-line jsx-a11y/no-autofocus -- the editor only ever renders inside a chip popover that just opened, per ARIA dialog practices
75
+ , {
76
+ // eslint-disable-next-line jsx-a11y/no-autofocus -- the editor only ever renders inside a chip popover that just opened, per ARIA dialog practices
77
+ autoFocus: true, hideLabel: true, label: `${label} from`, value: start, onChange: (date) => date && onCommit([date.toString(), end]) }),
62
78
  React__default.createElement("div", null, "and"),
63
79
  React__default.createElement(DatePicker, { hideLabel: true, label: `${label} to`, value: end, onChange: (date) => date && onCommit([start, date.toString()]) })));
64
80
  }
@@ -1 +1 @@
1
- {"version":3,"file":"dateFilter.js","sources":["../../../src/components/DataTable/dateFilter.tsx"],"sourcesContent":["import { DatePicker } from \"@components/date-picker\"\nimport { Flex } from \"@components/flex\"\nimport {\n DateFormatter,\n getLocalTimeZone,\n parseDate,\n} from \"@internationalized/date\"\nimport React from \"react\"\n\nimport { ActiveFilterInstance } from \"./ActiveFilterInstance\"\nimport type {\n FilterItemConfig,\n FilterNodeItem,\n Operator,\n UpdateActiveFilter,\n} from \"./FilterTypes\"\nimport { resolveOperators } from \"./resolveOperators\"\n\n/** ISO `YYYY-MM-DD` strings; a pair for `between`. */\nexport type DateFilterValue = string | [string, string]\n\nexport const DATE_IS = {\n inputType: { type: \"date\" },\n label: \"is\",\n name: \"eq\",\n} as const satisfies Operator\nexport const BEFORE = {\n inputType: { type: \"date\" },\n label: \"before\",\n name: \"before\",\n} as const satisfies Operator\nexport const AFTER = {\n inputType: { type: \"date\" },\n label: \"after\",\n name: \"after\",\n} as const satisfies Operator\nexport const DATE_RANGE = {\n inputType: { type: \"date-range\" },\n label: \"between\",\n name: \"date_range\",\n} as const satisfies Operator\n\nconst DATE_OPERATORS = [DATE_IS, BEFORE, AFTER, DATE_RANGE]\n\nexport type DateOperatorName = (typeof DATE_OPERATORS)[number][\"name\"]\n\nconst formatter = new DateFormatter(\n new Intl.DateTimeFormat().resolvedOptions().locale,\n { dateStyle: \"medium\" }\n)\n\nconst formatDate = (iso: string) =>\n formatter.format(parseDate(iso).toDate(getLocalTimeZone()))\n\nexport function dateFilter({\n excludes,\n includes,\n ...config\n}: FilterItemConfig<DateOperatorName>): FilterNodeItem {\n const filter: FilterNodeItem = {\n ...config,\n createActiveFilterInstance: (activeFilter, operator) =>\n new DateActiveFilter(\n filter,\n operator,\n activeFilter.value as DateFilterValue\n ),\n operators: resolveOperators(DATE_OPERATORS, { excludes, includes }),\n }\n return filter\n}\n\nclass DateActiveFilter extends ActiveFilterInstance<DateFilterValue> {\n formatValue() {\n return Array.isArray(this.value)\n ? [formatDate(this.value[0]), \"and\", formatDate(this.value[1])]\n : formatDate(this.value)\n }\n\n renderEditor(updateActiveFilter: UpdateActiveFilter) {\n const { label } = this.operator\n\n if (this.operator.inputType.type === \"date-range\") {\n const range: [string, string] = Array.isArray(this.value)\n ? this.value\n : [this.value, this.value]\n return (\n <DateRangeEditor\n label={label}\n value={range}\n onCommit={(value) => updateActiveFilter({ value })}\n />\n )\n }\n const single = Array.isArray(this.value) ? this.value[0] : this.value\n return (\n <DatePicker\n hideLabel\n label={label}\n value={single}\n onChange={(date) =>\n date && updateActiveFilter({ value: date.toString() })\n }\n />\n )\n }\n}\n\nfunction DateRangeEditor({\n label,\n onCommit,\n value: [start, end],\n}: {\n label: string\n onCommit: (value: [string, string]) => void\n value: [string, string]\n}) {\n return (\n <Flex gap={1}>\n <DatePicker\n hideLabel\n label={`${label} from`}\n value={start}\n onChange={(date) => date && onCommit([date.toString(), end])}\n />\n <div>and</div>\n <DatePicker\n hideLabel\n label={`${label} to`}\n value={end}\n onChange={(date) => date && onCommit([start, date.toString()])}\n />\n </Flex>\n )\n}\n"],"names":["DateFormatter","parseDate","getLocalTimeZone","React"],"mappings":";;;;;;;;;AAqBO,MAAM,OAAO,GAAG;AACrB,IAAA,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;AAC3B,IAAA,KAAK,EAAE,IAAI;AACX,IAAA,IAAI,EAAE,IAAI;;AAEL,MAAM,MAAM,GAAG;AACpB,IAAA,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;AAC3B,IAAA,KAAK,EAAE,QAAQ;AACf,IAAA,IAAI,EAAE,QAAQ;;AAET,MAAM,KAAK,GAAG;AACnB,IAAA,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;AAC3B,IAAA,KAAK,EAAE,OAAO;AACd,IAAA,IAAI,EAAE,OAAO;;AAER,MAAM,UAAU,GAAG;AACxB,IAAA,SAAS,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;AACjC,IAAA,KAAK,EAAE,SAAS;AAChB,IAAA,IAAI,EAAE,YAAY;;AAGpB,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC;AAI3D,MAAM,SAAS,GAAG,IAAIA,yCAAa,CACjC,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC,eAAe,EAAE,CAAC,MAAM,EAClD,EAAE,SAAS,EAAE,QAAQ,EAAE,CACxB;AAED,MAAM,UAAU,GAAG,CAAC,GAAW,KAC7B,SAAS,CAAC,MAAM,CAACC,wCAAS,CAAC,GAAG,CAAC,CAAC,MAAM,CAACC,yCAAgB,EAAE,CAAC,CAAC;AAEvD,SAAU,UAAU,CAAC,EACzB,QAAQ,EACR,QAAQ,EACR,GAAG,MAAM,EAC0B,EAAA;AACnC,IAAA,MAAM,MAAM,GAAmB;AAC7B,QAAA,GAAG,MAAM;AACT,QAAA,0BAA0B,EAAE,CAAC,YAAY,EAAE,QAAQ,KACjD,IAAI,gBAAgB,CAClB,MAAM,EACN,QAAQ,EACR,YAAY,CAAC,KAAwB,CACtC;QACH,SAAS,EAAE,gBAAgB,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;KACpE;AACD,IAAA,OAAO,MAAM;AACf;AAEA,MAAM,gBAAiB,SAAQ,oBAAqC,CAAA;IAClE,WAAW,GAAA;AACT,QAAA,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK;cAC3B,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9D,cAAE,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;IAC5B;AAEA,IAAA,YAAY,CAAC,kBAAsC,EAAA;AACjD,QAAA,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,QAAQ;QAE/B,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,KAAK,YAAY,EAAE;YACjD,MAAM,KAAK,GAAqB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK;kBACpD,IAAI,CAAC;kBACL,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC;YAC5B,QACEC,cAAA,CAAA,aAAA,CAAC,eAAe,EAAA,EACd,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,KAAK,KAAK,kBAAkB,CAAC,EAAE,KAAK,EAAE,CAAC,EAAA,CAClD;QAEN;QACA,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK;AACrE,QAAA,QACEA,cAAA,CAAA,aAAA,CAAC,UAAU,EAAA,EACT,SAAS,QACT,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,CAAC,IAAI,KACb,IAAI,IAAI,kBAAkB,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAA,CAExD;IAEN;AACD;AAED,SAAS,eAAe,CAAC,EACvB,KAAK,EACL,QAAQ,EACR,KAAK,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,GAKpB,EAAA;AACC,IAAA,QACEA,cAAA,CAAA,aAAA,CAAC,IAAI,EAAA,EAAC,GAAG,EAAE,CAAC,EAAA;AACV,QAAAA,cAAA,CAAA,aAAA,CAAC,UAAU,EAAA,EACT,SAAS,EAAA,IAAA,EACT,KAAK,EAAE,CAAA,EAAG,KAAK,CAAA,KAAA,CAAO,EACtB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,IAAI,KAAK,IAAI,IAAI,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,GAAG,CAAC,CAAC,EAAA,CAC5D;QACFA,cAAA,CAAA,aAAA,CAAA,KAAA,EAAA,IAAA,EAAA,KAAA,CAAc;AACd,QAAAA,cAAA,CAAA,aAAA,CAAC,UAAU,EAAA,EACT,SAAS,EAAA,IAAA,EACT,KAAK,EAAE,CAAA,EAAG,KAAK,CAAA,GAAA,CAAK,EACpB,KAAK,EAAE,GAAG,EACV,QAAQ,EAAE,CAAC,IAAI,KAAK,IAAI,IAAI,QAAQ,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAA,CAC9D,CACG;AAEX;;;;"}
1
+ {"version":3,"file":"dateFilter.js","sources":["../../../src/components/DataTable/dateFilter.tsx"],"sourcesContent":["import { DatePicker } from \"@components/date-picker\"\nimport { Flex } from \"@components/flex\"\nimport {\n DateFormatter,\n getLocalTimeZone,\n parseDate,\n} from \"@internationalized/date\"\nimport React from \"react\"\n\nimport { ActiveFilterInstance } from \"./ActiveFilterInstance\"\nimport type {\n FilterChange,\n FilterItemConfig,\n FilterNodeItem,\n Operator,\n} from \"./FilterTypes\"\nimport { resolveOperators } from \"./resolveOperators\"\n\n/** ISO `YYYY-MM-DD` strings; a pair for `between`. */\nexport type DateFilterValue = string | [string, string]\n\nexport const DATE_IS = {\n inputType: { type: \"date\" },\n label: \"is\",\n name: \"eq\",\n} as const satisfies Operator\nexport const BEFORE = {\n inputType: { type: \"date\" },\n label: \"before\",\n name: \"before\",\n} as const satisfies Operator\nexport const AFTER = {\n inputType: { type: \"date\" },\n label: \"after\",\n name: \"after\",\n} as const satisfies Operator\nexport const DATE_RANGE = {\n inputType: { type: \"date-range\" },\n label: \"between\",\n name: \"date_range\",\n} as const satisfies Operator\n\nconst DATE_OPERATORS = [DATE_IS, BEFORE, AFTER, DATE_RANGE]\n\nexport type DateOperatorName = (typeof DATE_OPERATORS)[number][\"name\"]\n\nconst formatter = new DateFormatter(\n new Intl.DateTimeFormat().resolvedOptions().locale,\n { dateStyle: \"medium\" }\n)\n\nconst formatDate = (iso: string) =>\n formatter.format(parseDate(iso).toDate(getLocalTimeZone()))\n\nexport function dateFilter({\n excludes,\n includes,\n ...config\n}: FilterItemConfig<DateOperatorName>): FilterNodeItem {\n const filter: FilterNodeItem = {\n ...config,\n createActiveFilterInstance: (activeFilter, operator) =>\n new DateActiveFilter(\n filter,\n operator,\n activeFilter.value as DateFilterValue\n ),\n operators: resolveOperators(DATE_OPERATORS, { excludes, includes }),\n }\n return filter\n}\n\nclass DateActiveFilter extends ActiveFilterInstance<DateFilterValue> {\n formatValue() {\n if (Array.isArray(this.value)) {\n const [start, end] = this.value\n if (start === undefined || end === undefined) {\n return [start, end].filter((date) => date !== undefined).map(formatDate)\n }\n return [formatDate(start), \"and\", formatDate(end)]\n }\n return this.value === undefined ? \"\" : formatDate(this.value)\n }\n\n renderEditor(onChange: FilterChange) {\n const { label } = this.operator\n\n if (this.operator.inputType.type === \"date-range\") {\n const range: [string, string] = Array.isArray(this.value)\n ? this.value\n : [this.value, this.value]\n return (\n <DateRangeEditor\n label={label}\n value={range}\n onCommit={(value) => {\n const complete =\n value.length === 2 && value.every((v) => v !== undefined)\n onChange({ value }, { complete })\n }}\n />\n )\n }\n const single = Array.isArray(this.value) ? this.value[0] : this.value\n return (\n <DatePicker\n // eslint-disable-next-line jsx-a11y/no-autofocus -- the editor only ever renders inside a chip popover that just opened, per ARIA dialog practices\n autoFocus\n hideLabel\n label={label}\n value={single}\n onChange={(date) => date && onChange({ value: date.toString() })}\n />\n )\n }\n}\n\nfunction DateRangeEditor({\n label,\n onCommit,\n value: [start, end],\n}: {\n label: string\n onCommit: (value: [string, string]) => void\n value: [string, string]\n}) {\n return (\n <Flex gap={1}>\n <DatePicker\n // eslint-disable-next-line jsx-a11y/no-autofocus -- the editor only ever renders inside a chip popover that just opened, per ARIA dialog practices\n autoFocus\n hideLabel\n label={`${label} from`}\n value={start}\n onChange={(date) => date && onCommit([date.toString(), end])}\n />\n <div>and</div>\n <DatePicker\n hideLabel\n label={`${label} to`}\n value={end}\n onChange={(date) => date && onCommit([start, date.toString()])}\n />\n </Flex>\n )\n}\n"],"names":["DateFormatter","parseDate","getLocalTimeZone","React"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  export { collectionFilter } from "./collectionFilter";
2
2
  export { dateFilter } from "./dateFilter";
3
3
  export { numberFilter } from "./numberFilter";
4
+ export { scopedFilter } from "./scopedFilter";
4
5
  export { textFilter } from "./textFilter";
5
6
  //# sourceMappingURL=filters.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"filters.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/filters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA"}
1
+ {"version":3,"file":"filters.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/filters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA"}
@@ -4,6 +4,7 @@ export type { DataTableElementProps, DataTableLoadingState, DataTableProps, Data
4
4
  export { DataTable } from "./DataTable";
5
5
  export type { BooleanColumn, CurrencyColumn, CustomColumn, DataTableColumn, DataTableColumnAlign, DataTableColumnType, DateColumn, DateTimeColumn, EnumColumn, NumberColumn, StringColumn, } from "./DataTableColumn";
6
6
  export * from "./filters";
7
- export type { ActiveFilter, FilterItemConfig, FilterNode, FilterNodeGroup, FilterNodeItem, Operator, } from "./FilterTypes";
7
+ export type { ActiveFilter, FilterItemConfig, FilterNode, FilterNodeGroup, FilterNodeItem, FilterNodeScoped, Operator, } from "./FilterTypes";
8
8
  export type { NumberFilterValue } from "./numberFilter";
9
+ export type { ScopedFilterConfig, ScopedFilterOptions } from "./scopedFilter";
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AACpB,OAAO,eAAe,CAAA;AAEtB,YAAY,EACV,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACd,kBAAkB,GACnB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,YAAY,EACV,aAAa,EACb,cAAc,EACd,YAAY,EACZ,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,UAAU,EACV,cAAc,EACd,UAAU,EACV,YAAY,EACZ,YAAY,GACb,MAAM,mBAAmB,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,cAAc,EACd,QAAQ,GACT,MAAM,eAAe,CAAA;AACtB,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AACpB,OAAO,eAAe,CAAA;AAEtB,YAAY,EACV,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACd,kBAAkB,GACnB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,YAAY,EACV,aAAa,EACb,cAAc,EACd,YAAY,EACZ,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,UAAU,EACV,cAAc,EACd,UAAU,EACV,YAAY,EACZ,YAAY,GACb,MAAM,mBAAmB,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,QAAQ,GACT,MAAM,eAAe,CAAA;AACtB,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AACvD,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"numberFilter.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/numberFilter.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EAGf,MAAM,eAAe,CAAA;AAGtB,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAEzD,eAAO,MAAM,GAAG;;;;;;CAIa,CAAA;AAC7B,eAAO,MAAM,GAAG;;;;;;CAIa,CAAA;AAC7B,eAAO,MAAM,YAAY;;;;;;CAII,CAAA;AAE7B,QAAA,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;IAA2B,CAAA;AAEjD,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAA;AAE1E,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,QAAQ,EACR,GAAG,MAAM,EACV,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,GAAG,cAAc,CAYvD"}
1
+ {"version":3,"file":"numberFilter.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/numberFilter.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAEV,gBAAgB,EAChB,cAAc,EAEf,MAAM,eAAe,CAAA;AAItB,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAEzD,eAAO,MAAM,GAAG;;;;;;CAIa,CAAA;AAC7B,eAAO,MAAM,GAAG;;;;;;CAIa,CAAA;AAC7B,eAAO,MAAM,YAAY;;;;;;CAII,CAAA;AAE7B,QAAA,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;IAA2B,CAAA;AAEjD,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAA;AAE1E,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,QAAQ,EACR,GAAG,MAAM,EACV,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,GAAG,cAAc,CAYvD"}
@@ -3,6 +3,7 @@ import { NumberStepper } from '../number-stepper/NumberStepper.js';
3
3
  import React__default, { useState } from 'react';
4
4
  import { ActiveFilterInstance } from './ActiveFilterInstance.js';
5
5
  import { resolveOperators } from './resolveOperators.js';
6
+ import { isEmptyValue } from './utils.js';
6
7
 
7
8
  const GTE = {
8
9
  inputType: { type: "number" },
@@ -30,13 +31,15 @@ function numberFilter({ excludes, includes, ...config }) {
30
31
  }
31
32
  class NumberActiveFilter extends ActiveFilterInstance {
32
33
  formatValue() {
34
+ if (this.value === undefined)
35
+ return "";
33
36
  return Array.isArray(this.value)
34
37
  ? this.value.join(" and ")
35
38
  : String(this.value);
36
39
  }
37
- renderEditor(updateActiveFilter) {
40
+ renderEditor(onChange) {
38
41
  const { label } = this.operator;
39
- const onCommit = (value) => updateActiveFilter({ value });
42
+ const onCommit = (value) => onChange({ value }, { complete: !isEmptyValue(value) });
40
43
  if (this.operator.inputType.type === "number-range") {
41
44
  const range = Array.isArray(this.value)
42
45
  ? this.value
@@ -49,12 +52,20 @@ class NumberActiveFilter extends ActiveFilterInstance {
49
52
  }
50
53
  function NumberEditor({ label, onCommit, value: initialValue, }) {
51
54
  const [value, setValue] = useState(initialValue);
52
- return (React__default.createElement(NumberStepper, { hideLabel: true, label: label, value: value, onChange: setValue, onBlur: () => onCommit(value) }));
55
+ return (React__default.createElement(NumberStepper
56
+ // eslint-disable-next-line jsx-a11y/no-autofocus -- the editor only ever renders inside a chip popover that just opened, per ARIA dialog practices
57
+ , {
58
+ // eslint-disable-next-line jsx-a11y/no-autofocus -- the editor only ever renders inside a chip popover that just opened, per ARIA dialog practices
59
+ autoFocus: true, hideLabel: true, label: label, value: value, onChange: setValue, onBlur: () => onCommit(value) }));
53
60
  }
54
61
  function NumberRangeEditor({ label, onCommit, value: initialValue, }) {
55
62
  const [[start, end], setRange] = useState(initialValue);
56
63
  return (React__default.createElement(Flex, { gap: 1 },
57
- React__default.createElement(NumberStepper, { hideLabel: true, label: `${label} from`, value: start, onChange: (value) => setRange([value, end]), onBlur: () => onCommit([start, end]) }),
64
+ React__default.createElement(NumberStepper
65
+ // eslint-disable-next-line jsx-a11y/no-autofocus -- the editor only ever renders inside a chip popover that just opened, per ARIA dialog practices
66
+ , {
67
+ // eslint-disable-next-line jsx-a11y/no-autofocus -- the editor only ever renders inside a chip popover that just opened, per ARIA dialog practices
68
+ autoFocus: true, hideLabel: true, label: `${label} from`, value: start, onChange: (value) => setRange([value, end]), onBlur: () => onCommit([start, end]) }),
58
69
  React__default.createElement("span", null, "and"),
59
70
  React__default.createElement(NumberStepper, { hideLabel: true, label: `${label} to`, value: end, onChange: (value) => setRange([start, value]), onBlur: () => onCommit([start, end]) })));
60
71
  }
@@ -1 +1 @@
1
- {"version":3,"file":"numberFilter.js","sources":["../../../src/components/DataTable/numberFilter.tsx"],"sourcesContent":["import { Flex } from \"@components/flex\"\nimport { NumberStepper } from \"@components/number-stepper\"\nimport React, { useState } from \"react\"\n\nimport { ActiveFilterInstance } from \"./ActiveFilterInstance\"\nimport type {\n FilterItemConfig,\n FilterNodeItem,\n Operator,\n UpdateActiveFilter,\n} from \"./FilterTypes\"\nimport { resolveOperators } from \"./resolveOperators\"\n\nexport type NumberFilterValue = number | [number, number]\n\nexport const GTE = {\n inputType: { type: \"number\" },\n label: \">=\",\n name: \"gte\",\n} as const satisfies Operator\nexport const LTE = {\n inputType: { type: \"number\" },\n label: \"<=\",\n name: \"lte\",\n} as const satisfies Operator\nexport const NUMBER_RANGE = {\n inputType: { type: \"number-range\" },\n label: \"between\",\n name: \"number_range\",\n} as const satisfies Operator\n\nconst NUMBER_OPERATORS = [GTE, LTE, NUMBER_RANGE]\n\nexport type NumberOperatorName = (typeof NUMBER_OPERATORS)[number][\"name\"]\n\nexport function numberFilter({\n excludes,\n includes,\n ...config\n}: FilterItemConfig<NumberOperatorName>): FilterNodeItem {\n const filter: FilterNodeItem = {\n ...config,\n createActiveFilterInstance: (activeFilter, operator) =>\n new NumberActiveFilter(\n filter,\n operator,\n activeFilter.value as NumberFilterValue\n ),\n operators: resolveOperators(NUMBER_OPERATORS, { excludes, includes }),\n }\n return filter\n}\n\nclass NumberActiveFilter extends ActiveFilterInstance<NumberFilterValue> {\n formatValue() {\n return Array.isArray(this.value)\n ? this.value.join(\" and \")\n : String(this.value)\n }\n\n renderEditor(updateActiveFilter: UpdateActiveFilter) {\n const { label } = this.operator\n const onCommit = (value: NumberFilterValue) => updateActiveFilter({ value })\n\n if (this.operator.inputType.type === \"number-range\") {\n const range: [number, number] = Array.isArray(this.value)\n ? this.value\n : [this.value, this.value]\n return (\n <NumberRangeEditor label={label} value={range} onCommit={onCommit} />\n )\n }\n const single = Array.isArray(this.value) ? this.value[0] : this.value\n return <NumberEditor label={label} value={single} onCommit={onCommit} />\n }\n}\n\nfunction NumberEditor({\n label,\n onCommit,\n value: initialValue,\n}: {\n label: string\n onCommit: (value: number) => void\n value: number\n}) {\n const [value, setValue] = useState(initialValue)\n return (\n <NumberStepper\n hideLabel\n label={label}\n value={value}\n onChange={setValue}\n onBlur={() => onCommit(value)}\n />\n )\n}\n\nfunction NumberRangeEditor({\n label,\n onCommit,\n value: initialValue,\n}: {\n label: string\n onCommit: (value: [number, number]) => void\n value: [number, number]\n}) {\n const [[start, end], setRange] = useState(initialValue)\n return (\n <Flex gap={1}>\n <NumberStepper\n hideLabel\n label={`${label} from`}\n value={start}\n onChange={(value) => setRange([value, end])}\n onBlur={() => onCommit([start, end])}\n />\n <span>and</span>\n <NumberStepper\n hideLabel\n label={`${label} to`}\n value={end}\n onChange={(value) => setRange([start, value])}\n onBlur={() => onCommit([start, end])}\n />\n </Flex>\n )\n}\n"],"names":["React"],"mappings":"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"}
1
+ {"version":3,"file":"numberFilter.js","sources":["../../../src/components/DataTable/numberFilter.tsx"],"sourcesContent":["import { Flex } from \"@components/flex\"\nimport { NumberStepper } from \"@components/number-stepper\"\nimport React, { useState } from \"react\"\n\nimport { ActiveFilterInstance } from \"./ActiveFilterInstance\"\nimport type {\n FilterChange,\n FilterItemConfig,\n FilterNodeItem,\n Operator,\n} from \"./FilterTypes\"\nimport { resolveOperators } from \"./resolveOperators\"\nimport { isEmptyValue } from \"./utils\"\n\nexport type NumberFilterValue = number | [number, number]\n\nexport const GTE = {\n inputType: { type: \"number\" },\n label: \">=\",\n name: \"gte\",\n} as const satisfies Operator\nexport const LTE = {\n inputType: { type: \"number\" },\n label: \"<=\",\n name: \"lte\",\n} as const satisfies Operator\nexport const NUMBER_RANGE = {\n inputType: { type: \"number-range\" },\n label: \"between\",\n name: \"number_range\",\n} as const satisfies Operator\n\nconst NUMBER_OPERATORS = [GTE, LTE, NUMBER_RANGE]\n\nexport type NumberOperatorName = (typeof NUMBER_OPERATORS)[number][\"name\"]\n\nexport function numberFilter({\n excludes,\n includes,\n ...config\n}: FilterItemConfig<NumberOperatorName>): FilterNodeItem {\n const filter: FilterNodeItem = {\n ...config,\n createActiveFilterInstance: (activeFilter, operator) =>\n new NumberActiveFilter(\n filter,\n operator,\n activeFilter.value as NumberFilterValue\n ),\n operators: resolveOperators(NUMBER_OPERATORS, { excludes, includes }),\n }\n return filter\n}\n\nclass NumberActiveFilter extends ActiveFilterInstance<NumberFilterValue> {\n formatValue() {\n if (this.value === undefined) return \"\"\n return Array.isArray(this.value)\n ? this.value.join(\" and \")\n : String(this.value)\n }\n\n renderEditor(onChange: FilterChange) {\n const { label } = this.operator\n const onCommit = (value: NumberFilterValue) =>\n onChange({ value }, { complete: !isEmptyValue(value) })\n\n if (this.operator.inputType.type === \"number-range\") {\n const range: [number, number] = Array.isArray(this.value)\n ? this.value\n : [this.value, this.value]\n return (\n <NumberRangeEditor label={label} value={range} onCommit={onCommit} />\n )\n }\n const single = Array.isArray(this.value) ? this.value[0] : this.value\n return <NumberEditor label={label} value={single} onCommit={onCommit} />\n }\n}\n\nfunction NumberEditor({\n label,\n onCommit,\n value: initialValue,\n}: {\n label: string\n onCommit: (value: number) => void\n value: number\n}) {\n const [value, setValue] = useState(initialValue)\n return (\n <NumberStepper\n // eslint-disable-next-line jsx-a11y/no-autofocus -- the editor only ever renders inside a chip popover that just opened, per ARIA dialog practices\n autoFocus\n hideLabel\n label={label}\n value={value}\n onChange={setValue}\n onBlur={() => onCommit(value)}\n />\n )\n}\n\nfunction NumberRangeEditor({\n label,\n onCommit,\n value: initialValue,\n}: {\n label: string\n onCommit: (value: [number, number]) => void\n value: [number, number]\n}) {\n const [[start, end], setRange] = useState(initialValue)\n return (\n <Flex gap={1}>\n <NumberStepper\n // eslint-disable-next-line jsx-a11y/no-autofocus -- the editor only ever renders inside a chip popover that just opened, per ARIA dialog practices\n autoFocus\n hideLabel\n label={`${label} from`}\n value={start}\n onChange={(value) => setRange([value, end])}\n onBlur={() => onCommit([start, end])}\n />\n <span>and</span>\n <NumberStepper\n hideLabel\n label={`${label} to`}\n value={end}\n onChange={(value) => setRange([start, value])}\n onBlur={() => onCommit([start, end])}\n />\n </Flex>\n )\n}\n"],"names":["React"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { FilterItemConfig, FilterNodeItem, FilterNodeScoped } from "./FilterTypes";
2
+ /**
3
+ * The filters a nested filter can delegate to. Each one's `name` is the scope
4
+ * identifier and its `label` is the scope's entry in the dropdown, so there's
5
+ * no separate option wrapper to keep in sync. Names need only be unique within
6
+ * this list — they're resolved here, not in the table's flat filter registry.
7
+ */
8
+ export type ScopedFilterOptions = FilterNodeItem[];
9
+ export type ScopedFilterConfig = Omit<FilterItemConfig, "excludes" | "includes"> & {
10
+ options: ScopedFilterOptions;
11
+ };
12
+ export declare function scopedFilter({ options, ...config }: ScopedFilterConfig): FilterNodeScoped;
13
+ //# sourceMappingURL=scopedFilter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopedFilter.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/scopedFilter.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAGV,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAEjB,MAAM,eAAe,CAAA;AAUtB;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG,cAAc,EAAE,CAAA;AAElD,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACnC,gBAAgB,EAChB,UAAU,GAAG,UAAU,CACxB,GAAG;IACF,OAAO,EAAE,mBAAmB,CAAA;CAC7B,CAAA;AAED,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,GAAG,MAAM,EACV,EAAE,kBAAkB,GAAG,gBAAgB,CASvC"}
@@ -0,0 +1,114 @@
1
+ import { Select } from '../select/Select.js';
2
+ import React__default from 'react';
3
+ import { ActiveFilterInstance } from './ActiveFilterInstance.js';
4
+ import { findScopedOption } from './FilterContext.js';
5
+ import { OperatorSelect } from './OperatorSelect.js';
6
+ import { isEmptyValue, getDefaultOperatorName } from './utils.js';
7
+
8
+ const SCOPED_DEFAULT = {
9
+ inputType: { type: "scoped" },
10
+ label: "",
11
+ name: "scoped",
12
+ };
13
+ function scopedFilter({ options, ...config }) {
14
+ const filter = {
15
+ ...config,
16
+ createActiveFilterInstance: (activeFilter, operator) => new ScopedActiveFilter(filter, operator, activeFilter),
17
+ operators: [SCOPED_DEFAULT],
18
+ options,
19
+ };
20
+ return filter;
21
+ }
22
+ function defaultScopedActiveFilter(parentName, option) {
23
+ return {
24
+ name: parentName,
25
+ operator: getDefaultOperatorName(option),
26
+ scope: option.name,
27
+ value: undefined,
28
+ };
29
+ }
30
+ class ScopedActiveFilter extends ActiveFilterInstance {
31
+ scopedFilter;
32
+ activeFilter;
33
+ constructor(scopedFilter, operator, activeFilter) {
34
+ super(scopedFilter, operator, activeFilter.value);
35
+ this.scopedFilter = scopedFilter;
36
+ this.activeFilter = activeFilter;
37
+ }
38
+ get options() {
39
+ return this.scopedFilter.options;
40
+ }
41
+ get selectedOption() {
42
+ return findScopedOption(this.scopedFilter, this.activeFilter.scope);
43
+ }
44
+ get selectedOptionInstance() {
45
+ const option = this.selectedOption;
46
+ if (!option)
47
+ return undefined;
48
+ return option.createActiveFilterInstance({ ...this.activeFilter, name: option.name, scope: undefined }, this.operator);
49
+ }
50
+ get selectedOptionSegmentsAfterLabel() {
51
+ const SKIP_OPTION_LABEL = 1;
52
+ return (this.selectedOptionInstance?.toSegments().slice(SKIP_OPTION_LABEL) ?? []);
53
+ }
54
+ toSegments() {
55
+ const { selectedOption } = this;
56
+ if (!selectedOption)
57
+ return [this.filter.label];
58
+ if (this.activeFilter.value === undefined)
59
+ return [this.filter.label, selectedOption.label];
60
+ return [
61
+ this.filter.label,
62
+ selectedOption.label,
63
+ ...this.selectedOptionSegmentsAfterLabel,
64
+ ];
65
+ }
66
+ formatValue() {
67
+ return this.selectedOptionInstance?.formatValue() ?? [];
68
+ }
69
+ renderEditor(onChange) {
70
+ return (React__default.createElement(ScopeEditor, { activeFilter: this.activeFilter, selectedOption: this.selectedOption, selectedOptionInstance: this.selectedOptionInstance, label: this.filter.label, options: this.options, onChange: onChange }));
71
+ }
72
+ }
73
+ function ScopeEditor({ activeFilter, selectedOption, selectedOptionInstance, label, options, onChange, }) {
74
+ const remembered = React__default.useRef({});
75
+ return (React__default.createElement(React__default.Fragment, null,
76
+ React__default.createElement(Select, { hideLabel: true, label: label, options: options.map((option) => ({
77
+ label: option.label,
78
+ value: option.name,
79
+ })), placeholder: `Select a ${label.toLowerCase()}`, value: activeFilter.scope ?? "", onChange: (e) => {
80
+ const { operator, scope, value } = activeFilter;
81
+ if (scope !== undefined) {
82
+ if (isEmptyValue(value)) {
83
+ delete remembered.current[scope];
84
+ }
85
+ else {
86
+ remembered.current[scope] = { operator, value };
87
+ }
88
+ }
89
+ const next = options.find((option) => option.name === e.target.value);
90
+ if (!next)
91
+ return;
92
+ const restored = remembered.current[next.name];
93
+ const scoped = {
94
+ ...defaultScopedActiveFilter(activeFilter.name, next),
95
+ ...restored,
96
+ };
97
+ onChange(scoped, { complete: !isEmptyValue(scoped.value) });
98
+ } }),
99
+ selectedOption && selectedOptionInstance && (React__default.createElement(SelectedScopeEditor, { activeFilter: activeFilter, instance: selectedOptionInstance, selectedOption: selectedOption, onChange: onChange }))));
100
+ }
101
+ function SelectedScopeEditor({ activeFilter, instance, selectedOption, onChange, }) {
102
+ return (React__default.createElement(React__default.Fragment, null,
103
+ React__default.createElement(OperatorSelect, { operator: instance.operator, relatedFilter: selectedOption, updateActiveFilter: (updates) => {
104
+ if (updates.operator && updates.operator !== activeFilter.operator) {
105
+ onChange({ ...updates, value: undefined }, { complete: false });
106
+ return;
107
+ }
108
+ onChange(updates, { complete: false });
109
+ } }),
110
+ React__default.createElement(React__default.Fragment, { key: `${activeFilter.scope}:${instance.operator.name}` }, instance.renderEditor(onChange))));
111
+ }
112
+
113
+ export { scopedFilter };
114
+ //# sourceMappingURL=scopedFilter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopedFilter.js","sources":["../../../src/components/DataTable/scopedFilter.tsx"],"sourcesContent":["import { Select } from \"@components/select\"\nimport React from \"react\"\n\nimport { ActiveFilterInstance } from \"./ActiveFilterInstance\"\nimport { findScopedOption } from \"./FilterContext\"\nimport type {\n ActiveFilter,\n FilterChange,\n FilterItemConfig,\n FilterNodeItem,\n FilterNodeScoped,\n Operator,\n} from \"./FilterTypes\"\nimport { OperatorSelect } from \"./OperatorSelect\"\nimport { getDefaultOperatorName, isEmptyValue } from \"./utils\"\n\nconst SCOPED_DEFAULT = {\n inputType: { type: \"scoped\" },\n label: \"\",\n name: \"scoped\",\n} as const satisfies Operator\n\n/**\n * The filters a nested filter can delegate to. Each one's `name` is the scope\n * identifier and its `label` is the scope's entry in the dropdown, so there's\n * no separate option wrapper to keep in sync. Names need only be unique within\n * this list — they're resolved here, not in the table's flat filter registry.\n */\nexport type ScopedFilterOptions = FilterNodeItem[]\n\nexport type ScopedFilterConfig = Omit<\n FilterItemConfig,\n \"excludes\" | \"includes\"\n> & {\n options: ScopedFilterOptions\n}\n\nexport function scopedFilter({\n options,\n ...config\n}: ScopedFilterConfig): FilterNodeScoped {\n const filter: FilterNodeScoped = {\n ...config,\n createActiveFilterInstance: (activeFilter, operator) =>\n new ScopedActiveFilter(filter, operator, activeFilter),\n operators: [SCOPED_DEFAULT],\n options,\n }\n return filter\n}\n\nfunction defaultScopedActiveFilter(\n parentName: string,\n option: FilterNodeItem\n): ActiveFilter {\n return {\n name: parentName,\n operator: getDefaultOperatorName(option),\n scope: option.name,\n value: undefined,\n }\n}\n\nclass ScopedActiveFilter extends ActiveFilterInstance<unknown> {\n private readonly activeFilter: ActiveFilter\n\n constructor(\n private readonly scopedFilter: FilterNodeScoped,\n operator: Operator,\n activeFilter: ActiveFilter\n ) {\n super(scopedFilter, operator, activeFilter.value)\n this.activeFilter = activeFilter\n }\n\n private get options(): ScopedFilterOptions {\n return this.scopedFilter.options\n }\n\n private get selectedOption() {\n return findScopedOption(this.scopedFilter, this.activeFilter.scope)\n }\n\n private get selectedOptionInstance() {\n const option = this.selectedOption\n if (!option) return undefined\n return option.createActiveFilterInstance(\n { ...this.activeFilter, name: option.name, scope: undefined },\n this.operator\n )\n }\n\n private get selectedOptionSegmentsAfterLabel() {\n const SKIP_OPTION_LABEL = 1\n return (\n this.selectedOptionInstance?.toSegments().slice(SKIP_OPTION_LABEL) ?? []\n )\n }\n\n toSegments() {\n const { selectedOption } = this\n if (!selectedOption) return [this.filter.label]\n\n if (this.activeFilter.value === undefined)\n return [this.filter.label, selectedOption.label]\n\n return [\n this.filter.label,\n selectedOption.label,\n ...this.selectedOptionSegmentsAfterLabel,\n ]\n }\n\n formatValue() {\n return this.selectedOptionInstance?.formatValue() ?? []\n }\n\n renderEditor(onChange: FilterChange) {\n return (\n <ScopeEditor\n activeFilter={this.activeFilter}\n selectedOption={this.selectedOption}\n selectedOptionInstance={this.selectedOptionInstance}\n label={this.filter.label}\n options={this.options}\n onChange={onChange}\n />\n )\n }\n}\n\nfunction ScopeEditor({\n activeFilter,\n selectedOption,\n selectedOptionInstance,\n label,\n options,\n onChange,\n}: {\n activeFilter: ActiveFilter\n label: string\n onChange: FilterChange\n options: ScopedFilterOptions\n selectedOption: FilterNodeItem | undefined\n selectedOptionInstance: ActiveFilterInstance | undefined\n}) {\n const remembered = React.useRef<\n Record<string, Pick<ActiveFilter, \"operator\" | \"value\">>\n >({})\n\n return (\n <>\n <Select\n hideLabel\n label={label}\n options={options.map((option) => ({\n label: option.label,\n value: option.name,\n }))}\n placeholder={`Select a ${label.toLowerCase()}`}\n value={activeFilter.scope ?? \"\"}\n onChange={(e) => {\n const { operator, scope, value } = activeFilter\n if (scope !== undefined) {\n if (isEmptyValue(value)) {\n delete remembered.current[scope]\n } else {\n remembered.current[scope] = { operator, value }\n }\n }\n const next = options.find((option) => option.name === e.target.value)\n if (!next) return\n const restored = remembered.current[next.name]\n const scoped = {\n ...defaultScopedActiveFilter(activeFilter.name, next),\n ...restored,\n }\n onChange(scoped, { complete: !isEmptyValue(scoped.value) })\n }}\n />\n {selectedOption && selectedOptionInstance && (\n <SelectedScopeEditor\n activeFilter={activeFilter}\n instance={selectedOptionInstance}\n selectedOption={selectedOption}\n onChange={onChange}\n />\n )}\n </>\n )\n}\n\nfunction SelectedScopeEditor({\n activeFilter,\n instance,\n selectedOption,\n onChange,\n}: {\n activeFilter: ActiveFilter\n instance: ActiveFilterInstance\n onChange: FilterChange\n selectedOption: FilterNodeItem\n}) {\n return (\n <>\n <OperatorSelect\n operator={instance.operator}\n relatedFilter={selectedOption}\n updateActiveFilter={(updates) => {\n if (updates.operator && updates.operator !== activeFilter.operator) {\n onChange({ ...updates, value: undefined }, { complete: false })\n return\n }\n onChange(updates, { complete: false })\n }}\n />\n <React.Fragment key={`${activeFilter.scope}:${instance.operator.name}`}>\n {instance.renderEditor(onChange)}\n </React.Fragment>\n </>\n )\n}\n"],"names":["React"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"textFilter.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/textFilter.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EAGf,MAAM,eAAe,CAAA;AAGtB,eAAO,MAAM,EAAE;;;;;;CAIc,CAAA;AAC7B,eAAO,MAAM,QAAQ;;;;;;CAIQ,CAAA;AAC7B,eAAO,MAAM,GAAG;;;;;;CAIa,CAAA;AAC7B,eAAO,MAAM,WAAW;;;;;;CAIK,CAAA;AAE7B,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;IAAmC,CAAA;AAEvD,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAA;AAEtE,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,QAAQ,EACR,GAAG,MAAM,EACV,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,GAAG,cAAc,CAQrD"}
1
+ {"version":3,"file":"textFilter.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/textFilter.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,gBAAgB,EAChB,cAAc,EAEf,MAAM,eAAe,CAAA;AAItB,eAAO,MAAM,EAAE;;;;;;CAIc,CAAA;AAC7B,eAAO,MAAM,QAAQ;;;;;;CAIQ,CAAA;AAC7B,eAAO,MAAM,GAAG;;;;;;CAIa,CAAA;AAC7B,eAAO,MAAM,WAAW;;;;;;CAIK,CAAA;AAE7B,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;IAAmC,CAAA;AAEvD,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAA;AAEtE,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,QAAQ,EACR,GAAG,MAAM,EACV,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,GAAG,cAAc,CAQrD"}
@@ -2,6 +2,7 @@ import { Input } from '../input/Input.js';
2
2
  import React__default, { useState } from 'react';
3
3
  import { ActiveFilterInstance } from './ActiveFilterInstance.js';
4
4
  import { resolveOperators } from './resolveOperators.js';
5
+ import { isEmptyValue } from './utils.js';
5
6
 
6
7
  const EQ = {
7
8
  inputType: { type: "text" },
@@ -36,13 +37,17 @@ class TextActiveFilter extends ActiveFilterInstance {
36
37
  formatValue() {
37
38
  return this.value;
38
39
  }
39
- renderEditor(updateActiveFilter) {
40
- return (React__default.createElement(TextEditor, { label: this.operator.label, value: this.value, onCommit: (value) => updateActiveFilter({ value }) }));
40
+ renderEditor(onChange) {
41
+ return (React__default.createElement(TextEditor, { label: this.operator.label, value: this.value, onCommit: (value) => onChange({ value }, { complete: !isEmptyValue(value) }) }));
41
42
  }
42
43
  }
43
44
  function TextEditor({ label, onCommit, value: initialValue, }) {
44
45
  const [value, setValue] = useState(initialValue);
45
- return (React__default.createElement(Input, { hideLabel: true, label: label, value: value, onChange: (e) => setValue(e.target.value), onBlur: () => onCommit(value) }));
46
+ return (React__default.createElement(Input
47
+ // eslint-disable-next-line jsx-a11y/no-autofocus -- the editor only ever renders inside a chip popover that just opened, per ARIA dialog practices
48
+ , {
49
+ // eslint-disable-next-line jsx-a11y/no-autofocus -- the editor only ever renders inside a chip popover that just opened, per ARIA dialog practices
50
+ autoFocus: true, hideLabel: true, label: label, value: value, onChange: (e) => setValue(e.target.value), onBlur: () => onCommit(value) }));
46
51
  }
47
52
 
48
53
  export { CONTAINS, EQ, NOT, STARTS_WITH, textFilter };
@@ -1 +1 @@
1
- {"version":3,"file":"textFilter.js","sources":["../../../src/components/DataTable/textFilter.tsx"],"sourcesContent":["import { Input } from \"@components/input\"\nimport React, { useState } from \"react\"\n\nimport { ActiveFilterInstance } from \"./ActiveFilterInstance\"\nimport type {\n FilterItemConfig,\n FilterNodeItem,\n Operator,\n UpdateActiveFilter,\n} from \"./FilterTypes\"\nimport { resolveOperators } from \"./resolveOperators\"\n\nexport const EQ = {\n inputType: { type: \"text\" },\n label: \"is\",\n name: \"eq\",\n} as const satisfies Operator\nexport const CONTAINS = {\n inputType: { type: \"text\" },\n label: \"contains\",\n name: \"contains\",\n} as const satisfies Operator\nexport const NOT = {\n inputType: { type: \"text\" },\n label: \"is not\",\n name: \"not\",\n} as const satisfies Operator\nexport const STARTS_WITH = {\n inputType: { type: \"text\" },\n label: \"starts with\",\n name: \"starts_with\",\n} as const satisfies Operator\n\nconst TEXT_OPERATORS = [EQ, CONTAINS, NOT, STARTS_WITH]\n\nexport type TextOperatorName = (typeof TEXT_OPERATORS)[number][\"name\"]\n\nexport function textFilter({\n excludes,\n includes,\n ...config\n}: FilterItemConfig<TextOperatorName>): FilterNodeItem {\n const filter: FilterNodeItem = {\n ...config,\n createActiveFilterInstance: (activeFilter, operator) =>\n new TextActiveFilter(filter, operator, activeFilter.value as string),\n operators: resolveOperators(TEXT_OPERATORS, { excludes, includes }),\n }\n return filter\n}\n\nclass TextActiveFilter extends ActiveFilterInstance<string> {\n formatValue() {\n return this.value\n }\n\n renderEditor(updateActiveFilter: UpdateActiveFilter) {\n return (\n <TextEditor\n label={this.operator.label}\n value={this.value}\n onCommit={(value) => updateActiveFilter({ value })}\n />\n )\n }\n}\n\nfunction TextEditor({\n label,\n onCommit,\n value: initialValue,\n}: {\n label: string\n onCommit: (value: string) => void\n value: string\n}) {\n const [value, setValue] = useState(initialValue)\n return (\n <Input\n hideLabel\n label={label}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onBlur={() => onCommit(value)}\n />\n )\n}\n"],"names":["React"],"mappings":";;;;;AAYO,MAAM,EAAE,GAAG;AAChB,IAAA,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;AAC3B,IAAA,KAAK,EAAE,IAAI;AACX,IAAA,IAAI,EAAE,IAAI;;AAEL,MAAM,QAAQ,GAAG;AACtB,IAAA,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;AAC3B,IAAA,KAAK,EAAE,UAAU;AACjB,IAAA,IAAI,EAAE,UAAU;;AAEX,MAAM,GAAG,GAAG;AACjB,IAAA,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;AAC3B,IAAA,KAAK,EAAE,QAAQ;AACf,IAAA,IAAI,EAAE,KAAK;;AAEN,MAAM,WAAW,GAAG;AACzB,IAAA,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;AAC3B,IAAA,KAAK,EAAE,aAAa;AACpB,IAAA,IAAI,EAAE,aAAa;;AAGrB,MAAM,cAAc,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,WAAW,CAAC;AAIjD,SAAU,UAAU,CAAC,EACzB,QAAQ,EACR,QAAQ,EACR,GAAG,MAAM,EAC0B,EAAA;AACnC,IAAA,MAAM,MAAM,GAAmB;AAC7B,QAAA,GAAG,MAAM;AACT,QAAA,0BAA0B,EAAE,CAAC,YAAY,EAAE,QAAQ,KACjD,IAAI,gBAAgB,CAAC,MAAM,EAAE,QAAQ,EAAE,YAAY,CAAC,KAAe,CAAC;QACtE,SAAS,EAAE,gBAAgB,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;KACpE;AACD,IAAA,OAAO,MAAM;AACf;AAEA,MAAM,gBAAiB,SAAQ,oBAA4B,CAAA;IACzD,WAAW,GAAA;QACT,OAAO,IAAI,CAAC,KAAK;IACnB;AAEA,IAAA,YAAY,CAAC,kBAAsC,EAAA;AACjD,QAAA,QACEA,cAAA,CAAA,aAAA,CAAC,UAAU,EAAA,EACT,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,EAC1B,KAAK,EAAE,IAAI,CAAC,KAAK,EACjB,QAAQ,EAAE,CAAC,KAAK,KAAK,kBAAkB,CAAC,EAAE,KAAK,EAAE,CAAC,EAAA,CAClD;IAEN;AACD;AAED,SAAS,UAAU,CAAC,EAClB,KAAK,EACL,QAAQ,EACR,KAAK,EAAE,YAAY,GAKpB,EAAA;IACC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,YAAY,CAAC;AAChD,IAAA,QACEA,cAAA,CAAA,aAAA,CAAC,KAAK,IACJ,SAAS,EAAA,IAAA,EACT,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EACzC,MAAM,EAAE,MAAM,QAAQ,CAAC,KAAK,CAAC,EAAA,CAC7B;AAEN;;;;"}
1
+ {"version":3,"file":"textFilter.js","sources":["../../../src/components/DataTable/textFilter.tsx"],"sourcesContent":["import { Input } from \"@components/input\"\nimport React, { useState } from \"react\"\n\nimport { ActiveFilterInstance } from \"./ActiveFilterInstance\"\nimport type {\n FilterChange,\n FilterItemConfig,\n FilterNodeItem,\n Operator,\n} from \"./FilterTypes\"\nimport { resolveOperators } from \"./resolveOperators\"\nimport { isEmptyValue } from \"./utils\"\n\nexport const EQ = {\n inputType: { type: \"text\" },\n label: \"is\",\n name: \"eq\",\n} as const satisfies Operator\nexport const CONTAINS = {\n inputType: { type: \"text\" },\n label: \"contains\",\n name: \"contains\",\n} as const satisfies Operator\nexport const NOT = {\n inputType: { type: \"text\" },\n label: \"is not\",\n name: \"not\",\n} as const satisfies Operator\nexport const STARTS_WITH = {\n inputType: { type: \"text\" },\n label: \"starts with\",\n name: \"starts_with\",\n} as const satisfies Operator\n\nconst TEXT_OPERATORS = [EQ, CONTAINS, NOT, STARTS_WITH]\n\nexport type TextOperatorName = (typeof TEXT_OPERATORS)[number][\"name\"]\n\nexport function textFilter({\n excludes,\n includes,\n ...config\n}: FilterItemConfig<TextOperatorName>): FilterNodeItem {\n const filter: FilterNodeItem = {\n ...config,\n createActiveFilterInstance: (activeFilter, operator) =>\n new TextActiveFilter(filter, operator, activeFilter.value as string),\n operators: resolveOperators(TEXT_OPERATORS, { excludes, includes }),\n }\n return filter\n}\n\nclass TextActiveFilter extends ActiveFilterInstance<string> {\n formatValue() {\n return this.value\n }\n\n renderEditor(onChange: FilterChange) {\n return (\n <TextEditor\n label={this.operator.label}\n value={this.value}\n onCommit={(value) =>\n onChange({ value }, { complete: !isEmptyValue(value) })\n }\n />\n )\n }\n}\n\nfunction TextEditor({\n label,\n onCommit,\n value: initialValue,\n}: {\n label: string\n onCommit: (value: string) => void\n value: string\n}) {\n const [value, setValue] = useState(initialValue)\n return (\n <Input\n // eslint-disable-next-line jsx-a11y/no-autofocus -- the editor only ever renders inside a chip popover that just opened, per ARIA dialog practices\n autoFocus\n hideLabel\n label={label}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onBlur={() => onCommit(value)}\n />\n )\n}\n"],"names":["React"],"mappings":";;;;;;AAaO,MAAM,EAAE,GAAG;AAChB,IAAA,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;AAC3B,IAAA,KAAK,EAAE,IAAI;AACX,IAAA,IAAI,EAAE,IAAI;;AAEL,MAAM,QAAQ,GAAG;AACtB,IAAA,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;AAC3B,IAAA,KAAK,EAAE,UAAU;AACjB,IAAA,IAAI,EAAE,UAAU;;AAEX,MAAM,GAAG,GAAG;AACjB,IAAA,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;AAC3B,IAAA,KAAK,EAAE,QAAQ;AACf,IAAA,IAAI,EAAE,KAAK;;AAEN,MAAM,WAAW,GAAG;AACzB,IAAA,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;AAC3B,IAAA,KAAK,EAAE,aAAa;AACpB,IAAA,IAAI,EAAE,aAAa;;AAGrB,MAAM,cAAc,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,WAAW,CAAC;AAIjD,SAAU,UAAU,CAAC,EACzB,QAAQ,EACR,QAAQ,EACR,GAAG,MAAM,EAC0B,EAAA;AACnC,IAAA,MAAM,MAAM,GAAmB;AAC7B,QAAA,GAAG,MAAM;AACT,QAAA,0BAA0B,EAAE,CAAC,YAAY,EAAE,QAAQ,KACjD,IAAI,gBAAgB,CAAC,MAAM,EAAE,QAAQ,EAAE,YAAY,CAAC,KAAe,CAAC;QACtE,SAAS,EAAE,gBAAgB,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;KACpE;AACD,IAAA,OAAO,MAAM;AACf;AAEA,MAAM,gBAAiB,SAAQ,oBAA4B,CAAA;IACzD,WAAW,GAAA;QACT,OAAO,IAAI,CAAC,KAAK;IACnB;AAEA,IAAA,YAAY,CAAC,QAAsB,EAAA;AACjC,QAAA,QACEA,cAAA,CAAA,aAAA,CAAC,UAAU,IACT,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,EAC1B,KAAK,EAAE,IAAI,CAAC,KAAK,EACjB,QAAQ,EAAE,CAAC,KAAK,KACd,QAAQ,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,EAAA,CAEzD;IAEN;AACD;AAED,SAAS,UAAU,CAAC,EAClB,KAAK,EACL,QAAQ,EACR,KAAK,EAAE,YAAY,GAKpB,EAAA;IACC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,YAAY,CAAC;IAChD,QACEA,6BAAC;;;;AAEC,QAAA,SAAS,QACT,SAAS,EAAA,IAAA,EACT,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EACzC,MAAM,EAAE,MAAM,QAAQ,CAAC,KAAK,CAAC,EAAA,CAC7B;AAEN;;;;"}
@@ -1,6 +1,7 @@
1
1
  /**
2
- * Expands the filters shelf when the active filter count leaves zero, and
3
- * collapses it when the count returns to zero. Returns a toggle to control it.
2
+ * Expands the filters shelf when the filter count leaves zero or a pending
3
+ * filter is added, and collapses it when the count returns to zero. Returns a
4
+ * toggle to control it.
4
5
  */
5
- export declare function useShelfExpanded(activeFilterCount: number): [boolean, () => void];
6
+ export declare function useShelfExpanded(filterCount: number, pendingCount: number): [boolean, () => void];
6
7
  //# sourceMappingURL=useShelfExpanded.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useShelfExpanded.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/useShelfExpanded.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,iBAAiB,EAAE,MAAM,GACxB,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC,CAqBvB"}
1
+ {"version":3,"file":"useShelfExpanded.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/useShelfExpanded.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC,CA4BvB"}
@@ -1,21 +1,29 @@
1
1
  import { useState, useCallback } from 'react';
2
2
 
3
3
  /**
4
- * Expands the filters shelf when the active filter count leaves zero, and
5
- * collapses it when the count returns to zero. Returns a toggle to control it.
4
+ * Expands the filters shelf when the filter count leaves zero or a pending
5
+ * filter is added, and collapses it when the count returns to zero. Returns a
6
+ * toggle to control it.
6
7
  */
7
- function useShelfExpanded(activeFilterCount) {
8
- const [isShelfExpanded, setIsShelfExpanded] = useState(() => activeFilterCount > 0);
9
- const [previousCount, setPreviousCount] = useState(activeFilterCount);
10
- if (activeFilterCount !== previousCount) {
11
- setPreviousCount(activeFilterCount);
12
- if (activeFilterCount === 0) {
8
+ function useShelfExpanded(filterCount, pendingCount) {
9
+ const [isShelfExpanded, setIsShelfExpanded] = useState(() => filterCount > 0);
10
+ const [previousCount, setPreviousCount] = useState(filterCount);
11
+ const [previousPendingCount, setPreviousPendingCount] = useState(pendingCount);
12
+ if (filterCount !== previousCount) {
13
+ setPreviousCount(filterCount);
14
+ if (filterCount === 0) {
13
15
  setIsShelfExpanded(false);
14
16
  }
15
17
  else if (previousCount === 0) {
16
18
  setIsShelfExpanded(true);
17
19
  }
18
20
  }
21
+ if (pendingCount !== previousPendingCount) {
22
+ setPreviousPendingCount(pendingCount);
23
+ if (pendingCount > previousPendingCount) {
24
+ setIsShelfExpanded(true);
25
+ }
26
+ }
19
27
  const toggleShelf = useCallback(() => {
20
28
  setIsShelfExpanded((expanded) => !expanded);
21
29
  }, []);