@12-apps/ui 6.30.1 → 6.30.2

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 (39) hide show
  1. package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +8 -8
  2. package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +9 -9
  3. package/dist/_internal/components/data-display/DataViews/data-views-category-pill.js +1 -1
  4. package/dist/_internal/components/data-display/DataViews/data-views-filter-panel.js +2 -2
  5. package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +7 -7
  6. package/dist/_internal/components/data-display/DataViews/data-views-inline-bar.js +4 -4
  7. package/dist/_internal/components/data-display/DataViews/data-views-more-fields.js +24 -1
  8. package/dist/_internal/components/data-display/DataViews/data-views-more-filters.js +25 -2
  9. package/dist/_internal/components/data-display/DataViews/data-views-overflow.js +1 -1
  10. package/dist/{chunk-VEGT5PAD.js → chunk-ALEITBJX.js} +4 -4
  11. package/dist/{chunk-KUJLZFDW.js → chunk-BTKMGXAK.js} +2 -2
  12. package/dist/{chunk-I3FXTIKA.js → chunk-D5GCWSGS.js} +2 -2
  13. package/dist/chunk-D5GCWSGS.js.map +1 -0
  14. package/dist/{chunk-VNGYJXAU.js → chunk-DH5OA4VK.js} +2 -2
  15. package/dist/{chunk-6FUOUUYO.js → chunk-J2UZOMTA.js} +2 -2
  16. package/dist/{chunk-JQL4GG5L.js → chunk-LBLX3Q2C.js} +2 -2
  17. package/dist/{chunk-CASZGBCA.js → chunk-PZAXUO6F.js} +5 -5
  18. package/dist/{chunk-TQ6FPOPD.js → chunk-TPKSOHB5.js} +5 -2
  19. package/dist/{chunk-TQ6FPOPD.js.map → chunk-TPKSOHB5.js.map} +1 -1
  20. package/dist/{chunk-EZMCWRXO.js → chunk-ZJ66D63E.js} +23 -25
  21. package/dist/chunk-ZJ66D63E.js.map +1 -0
  22. package/dist/data-display/DataViews.js +9 -9
  23. package/dist/types/components/data-display/DataViews/data-views-category-pill.d.ts +6 -1
  24. package/dist/types/components/data-display/DataViews/data-views-category-pill.d.ts.map +1 -1
  25. package/dist/types/components/data-display/DataViews/data-views-more-fields.d.ts +0 -11
  26. package/dist/types/components/data-display/DataViews/data-views-more-fields.d.ts.map +1 -1
  27. package/dist/types/components/data-display/DataViews/data-views-overflow.d.ts.map +1 -1
  28. package/package.json +1 -1
  29. package/src/components/data-display/DataViews/data-views-category-pill.tsx +6 -1
  30. package/src/components/data-display/DataViews/data-views-more-fields.tsx +43 -37
  31. package/src/components/data-display/DataViews/data-views-overflow.ts +12 -1
  32. package/dist/chunk-EZMCWRXO.js.map +0 -1
  33. package/dist/chunk-I3FXTIKA.js.map +0 -1
  34. /package/dist/{chunk-VEGT5PAD.js.map → chunk-ALEITBJX.js.map} +0 -0
  35. /package/dist/{chunk-KUJLZFDW.js.map → chunk-BTKMGXAK.js.map} +0 -0
  36. /package/dist/{chunk-VNGYJXAU.js.map → chunk-DH5OA4VK.js.map} +0 -0
  37. /package/dist/{chunk-6FUOUUYO.js.map → chunk-J2UZOMTA.js.map} +0 -0
  38. /package/dist/{chunk-JQL4GG5L.js.map → chunk-LBLX3Q2C.js.map} +0 -0
  39. /package/dist/{chunk-CASZGBCA.js.map → chunk-PZAXUO6F.js.map} +0 -0
@@ -1,17 +1,17 @@
1
1
  "use client";
2
2
  import {
3
3
  DataViewsGrid
4
- } from "../../../../chunk-KUJLZFDW.js";
5
- import "../../../../chunk-VEGT5PAD.js";
4
+ } from "../../../../chunk-BTKMGXAK.js";
5
+ import "../../../../chunk-ALEITBJX.js";
6
6
  import "../../../../chunk-6PKVHFCK.js";
7
7
  import "../../../../chunk-VKH7AENA.js";
8
- import "../../../../chunk-VNGYJXAU.js";
8
+ import "../../../../chunk-DH5OA4VK.js";
9
9
  import "../../../../chunk-4XVH6IWN.js";
10
- import "../../../../chunk-CASZGBCA.js";
10
+ import "../../../../chunk-PZAXUO6F.js";
11
11
  import "../../../../chunk-5WNQJ5KS.js";
12
- import "../../../../chunk-I3FXTIKA.js";
13
- import "../../../../chunk-6FUOUUYO.js";
14
- import "../../../../chunk-EZMCWRXO.js";
12
+ import "../../../../chunk-J2UZOMTA.js";
13
+ import "../../../../chunk-ZJ66D63E.js";
14
+ import "../../../../chunk-D5GCWSGS.js";
15
15
  import "../../../../chunk-UC6A6ASM.js";
16
16
  import "../../../../chunk-DFLTUI7W.js";
17
17
  import "../../../../chunk-FV36LFPX.js";
@@ -19,7 +19,7 @@ import "../../../../chunk-GCZJH4XL.js";
19
19
  import "../../../../chunk-F4RR4666.js";
20
20
  import "../../../../chunk-CBOB5AV6.js";
21
21
  import "../../../../chunk-HP2ODXNA.js";
22
- import "../../../../chunk-TQ6FPOPD.js";
22
+ import "../../../../chunk-TPKSOHB5.js";
23
23
  import "../../../../chunk-IAGOUTI6.js";
24
24
  import "../../../../chunk-KX75HM5U.js";
25
25
  import "../../../../chunk-FGUK3D54.js";
@@ -1,20 +1,20 @@
1
1
  "use client";
2
2
  import {
3
3
  DataViewsTableBase
4
- } from "../../../../chunk-JQL4GG5L.js";
4
+ } from "../../../../chunk-LBLX3Q2C.js";
5
5
  import "../../../../chunk-MSS6IU5X.js";
6
- import "../../../../chunk-KUJLZFDW.js";
6
+ import "../../../../chunk-BTKMGXAK.js";
7
7
  import "../../../../chunk-ZOLAYP2D.js";
8
- import "../../../../chunk-VEGT5PAD.js";
8
+ import "../../../../chunk-ALEITBJX.js";
9
9
  import "../../../../chunk-6PKVHFCK.js";
10
10
  import "../../../../chunk-VKH7AENA.js";
11
- import "../../../../chunk-VNGYJXAU.js";
11
+ import "../../../../chunk-DH5OA4VK.js";
12
12
  import "../../../../chunk-4XVH6IWN.js";
13
- import "../../../../chunk-CASZGBCA.js";
13
+ import "../../../../chunk-PZAXUO6F.js";
14
14
  import "../../../../chunk-5WNQJ5KS.js";
15
- import "../../../../chunk-I3FXTIKA.js";
16
- import "../../../../chunk-6FUOUUYO.js";
17
- import "../../../../chunk-EZMCWRXO.js";
15
+ import "../../../../chunk-J2UZOMTA.js";
16
+ import "../../../../chunk-ZJ66D63E.js";
17
+ import "../../../../chunk-D5GCWSGS.js";
18
18
  import "../../../../chunk-UC6A6ASM.js";
19
19
  import "../../../../chunk-DFLTUI7W.js";
20
20
  import "../../../../chunk-FV36LFPX.js";
@@ -22,7 +22,7 @@ import "../../../../chunk-GCZJH4XL.js";
22
22
  import "../../../../chunk-F4RR4666.js";
23
23
  import "../../../../chunk-CBOB5AV6.js";
24
24
  import "../../../../chunk-HP2ODXNA.js";
25
- import "../../../../chunk-TQ6FPOPD.js";
25
+ import "../../../../chunk-TPKSOHB5.js";
26
26
  import "../../../../chunk-IAGOUTI6.js";
27
27
  import "../../../../chunk-KX75HM5U.js";
28
28
  import "../../../../chunk-FGUK3D54.js";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  PillControl,
4
4
  emitPillDiff
5
- } from "../../../../chunk-I3FXTIKA.js";
5
+ } from "../../../../chunk-D5GCWSGS.js";
6
6
  import "../../../../chunk-KHG57NAE.js";
7
7
  import "../../../../chunk-MOLQGQEQ.js";
8
8
  import "../../../../chunk-4T6W43TO.js";
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  FilterDialog,
4
4
  GridFilterPanel
5
- } from "../../../../chunk-VNGYJXAU.js";
6
- import "../../../../chunk-I3FXTIKA.js";
5
+ } from "../../../../chunk-DH5OA4VK.js";
6
+ import "../../../../chunk-D5GCWSGS.js";
7
7
  import "../../../../chunk-DFLTUI7W.js";
8
8
  import "../../../../chunk-FV36LFPX.js";
9
9
  import "../../../../chunk-GCZJH4XL.js";
@@ -1,16 +1,16 @@
1
1
  "use client";
2
2
  import {
3
3
  GridShell
4
- } from "../../../../chunk-VEGT5PAD.js";
4
+ } from "../../../../chunk-ALEITBJX.js";
5
5
  import "../../../../chunk-6PKVHFCK.js";
6
6
  import "../../../../chunk-VKH7AENA.js";
7
- import "../../../../chunk-VNGYJXAU.js";
7
+ import "../../../../chunk-DH5OA4VK.js";
8
8
  import "../../../../chunk-4XVH6IWN.js";
9
- import "../../../../chunk-CASZGBCA.js";
9
+ import "../../../../chunk-PZAXUO6F.js";
10
10
  import "../../../../chunk-5WNQJ5KS.js";
11
- import "../../../../chunk-I3FXTIKA.js";
12
- import "../../../../chunk-6FUOUUYO.js";
13
- import "../../../../chunk-EZMCWRXO.js";
11
+ import "../../../../chunk-J2UZOMTA.js";
12
+ import "../../../../chunk-ZJ66D63E.js";
13
+ import "../../../../chunk-D5GCWSGS.js";
14
14
  import "../../../../chunk-UC6A6ASM.js";
15
15
  import "../../../../chunk-DFLTUI7W.js";
16
16
  import "../../../../chunk-FV36LFPX.js";
@@ -18,7 +18,7 @@ import "../../../../chunk-GCZJH4XL.js";
18
18
  import "../../../../chunk-F4RR4666.js";
19
19
  import "../../../../chunk-CBOB5AV6.js";
20
20
  import "../../../../chunk-HP2ODXNA.js";
21
- import "../../../../chunk-TQ6FPOPD.js";
21
+ import "../../../../chunk-TPKSOHB5.js";
22
22
  import "../../../../chunk-IAGOUTI6.js";
23
23
  import "../../../../chunk-KX75HM5U.js";
24
24
  import "../../../../chunk-FGUK3D54.js";
@@ -1,11 +1,11 @@
1
1
  "use client";
2
2
  import {
3
3
  InlineFilterControls
4
- } from "../../../../chunk-CASZGBCA.js";
4
+ } from "../../../../chunk-PZAXUO6F.js";
5
5
  import "../../../../chunk-5WNQJ5KS.js";
6
- import "../../../../chunk-I3FXTIKA.js";
7
- import "../../../../chunk-6FUOUUYO.js";
8
- import "../../../../chunk-EZMCWRXO.js";
6
+ import "../../../../chunk-J2UZOMTA.js";
7
+ import "../../../../chunk-ZJ66D63E.js";
8
+ import "../../../../chunk-D5GCWSGS.js";
9
9
  import "../../../../chunk-DFLTUI7W.js";
10
10
  import "../../../../chunk-FV36LFPX.js";
11
11
  import "../../../../chunk-GCZJH4XL.js";
@@ -2,7 +2,8 @@
2
2
  import {
3
3
  MoreGroup,
4
4
  fieldClearing
5
- } from "../../../../chunk-EZMCWRXO.js";
5
+ } from "../../../../chunk-ZJ66D63E.js";
6
+ import "../../../../chunk-D5GCWSGS.js";
6
7
  import "../../../../chunk-DFLTUI7W.js";
7
8
  import "../../../../chunk-FV36LFPX.js";
8
9
  import "../../../../chunk-GCZJH4XL.js";
@@ -22,6 +23,27 @@ import "../../../../chunk-WQFIV5WD.js";
22
23
  import "../../../../chunk-EFEZWG4C.js";
23
24
  import "../../../../chunk-YB6MDGPR.js";
24
25
  import "../../../../chunk-UCU5FCYE.js";
26
+ import "../../../../chunk-N5ZWC6CB.js";
27
+ import "../../../../chunk-57W2C7HY.js";
28
+ import "../../../../chunk-VESIQYBF.js";
29
+ import "../../../../chunk-V6Z4XS3I.js";
30
+ import "../../../../chunk-LMXWI3DD.js";
31
+ import "../../../../chunk-V7F53GEO.js";
32
+ import "../../../../chunk-GH2DC7PS.js";
33
+ import "../../../../chunk-CJUOBTLL.js";
34
+ import "../../../../chunk-ZUY65MFH.js";
35
+ import "../../../../chunk-RZVUY2MO.js";
36
+ import "../../../../chunk-USJPZ5Q7.js";
37
+ import "../../../../chunk-XHHR6G35.js";
38
+ import "../../../../chunk-R2AZOWEZ.js";
39
+ import "../../../../chunk-PN4HVM43.js";
40
+ import "../../../../chunk-GVDJQMFI.js";
41
+ import "../../../../chunk-DMNZD3Q7.js";
42
+ import "../../../../chunk-ZS44PY7T.js";
43
+ import "../../../../chunk-C3UKR3NT.js";
44
+ import "../../../../chunk-IPPTOL53.js";
45
+ import "../../../../chunk-7FDU3FIN.js";
46
+ import "../../../../chunk-EPEJMTCQ.js";
25
47
  import "../../../../chunk-6DPAWXZ3.js";
26
48
  import "../../../../chunk-VUHLNYAE.js";
27
49
  import "../../../../chunk-YTYROOLY.js";
@@ -32,6 +54,7 @@ import "../../../../chunk-AG66JBNH.js";
32
54
  import "../../../../chunk-2BYKTBDL.js";
33
55
  import "../../../../chunk-6JAIFIPW.js";
34
56
  import "../../../../chunk-FZXKH2ZT.js";
57
+ import "../../../../chunk-MFU4Y25U.js";
35
58
  import "../../../../chunk-PZ5AY32C.js";
36
59
  export {
37
60
  MoreGroup,
@@ -1,8 +1,9 @@
1
1
  "use client";
2
2
  import {
3
3
  MoreFilters
4
- } from "../../../../chunk-6FUOUUYO.js";
5
- import "../../../../chunk-EZMCWRXO.js";
4
+ } from "../../../../chunk-J2UZOMTA.js";
5
+ import "../../../../chunk-ZJ66D63E.js";
6
+ import "../../../../chunk-D5GCWSGS.js";
6
7
  import "../../../../chunk-DFLTUI7W.js";
7
8
  import "../../../../chunk-FV36LFPX.js";
8
9
  import "../../../../chunk-GCZJH4XL.js";
@@ -22,6 +23,27 @@ import "../../../../chunk-WQFIV5WD.js";
22
23
  import "../../../../chunk-EFEZWG4C.js";
23
24
  import "../../../../chunk-YB6MDGPR.js";
24
25
  import "../../../../chunk-UCU5FCYE.js";
26
+ import "../../../../chunk-N5ZWC6CB.js";
27
+ import "../../../../chunk-57W2C7HY.js";
28
+ import "../../../../chunk-VESIQYBF.js";
29
+ import "../../../../chunk-V6Z4XS3I.js";
30
+ import "../../../../chunk-LMXWI3DD.js";
31
+ import "../../../../chunk-V7F53GEO.js";
32
+ import "../../../../chunk-GH2DC7PS.js";
33
+ import "../../../../chunk-CJUOBTLL.js";
34
+ import "../../../../chunk-ZUY65MFH.js";
35
+ import "../../../../chunk-RZVUY2MO.js";
36
+ import "../../../../chunk-USJPZ5Q7.js";
37
+ import "../../../../chunk-XHHR6G35.js";
38
+ import "../../../../chunk-R2AZOWEZ.js";
39
+ import "../../../../chunk-PN4HVM43.js";
40
+ import "../../../../chunk-GVDJQMFI.js";
41
+ import "../../../../chunk-DMNZD3Q7.js";
42
+ import "../../../../chunk-ZS44PY7T.js";
43
+ import "../../../../chunk-C3UKR3NT.js";
44
+ import "../../../../chunk-IPPTOL53.js";
45
+ import "../../../../chunk-7FDU3FIN.js";
46
+ import "../../../../chunk-EPEJMTCQ.js";
25
47
  import "../../../../chunk-6DPAWXZ3.js";
26
48
  import "../../../../chunk-VUHLNYAE.js";
27
49
  import "../../../../chunk-BA4RHQ3B.js";
@@ -37,6 +59,7 @@ import "../../../../chunk-AG66JBNH.js";
37
59
  import "../../../../chunk-2BYKTBDL.js";
38
60
  import "../../../../chunk-6JAIFIPW.js";
39
61
  import "../../../../chunk-FZXKH2ZT.js";
62
+ import "../../../../chunk-MFU4Y25U.js";
40
63
  import "../../../../chunk-PZ5AY32C.js";
41
64
  export {
42
65
  MoreFilters
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  toOverflowFields,
4
4
  useFilterOverflow
5
- } from "../../../../chunk-TQ6FPOPD.js";
5
+ } from "../../../../chunk-TPKSOHB5.js";
6
6
  import "../../../../chunk-IAGOUTI6.js";
7
7
  import "../../../../chunk-NCS2TBIP.js";
8
8
  import "../../../../chunk-Y4KKS6WL.js";
@@ -4,13 +4,13 @@ import {
4
4
  import {
5
5
  FilterDialog,
6
6
  GridFilterPanel
7
- } from "./chunk-VNGYJXAU.js";
7
+ } from "./chunk-DH5OA4VK.js";
8
8
  import {
9
9
  DataViewsEmpty
10
10
  } from "./chunk-4XVH6IWN.js";
11
11
  import {
12
12
  InlineFilterControls
13
- } from "./chunk-CASZGBCA.js";
13
+ } from "./chunk-PZAXUO6F.js";
14
14
  import {
15
15
  GridHeaderRow
16
16
  } from "./chunk-UC6A6ASM.js";
@@ -20,7 +20,7 @@ import {
20
20
  import {
21
21
  toOverflowFields,
22
22
  useFilterOverflow
23
- } from "./chunk-TQ6FPOPD.js";
23
+ } from "./chunk-TPKSOHB5.js";
24
24
  import {
25
25
  resolveSelectionExtra
26
26
  } from "./chunk-KX75HM5U.js";
@@ -238,4 +238,4 @@ function GridShell(props) {
238
238
  export {
239
239
  GridShell
240
240
  };
241
- //# sourceMappingURL=chunk-VEGT5PAD.js.map
241
+ //# sourceMappingURL=chunk-ALEITBJX.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  GridShell
3
- } from "./chunk-VEGT5PAD.js";
3
+ } from "./chunk-ALEITBJX.js";
4
4
  import {
5
5
  useDataViewsState
6
6
  } from "./chunk-K2JH7QPR.js";
@@ -27,4 +27,4 @@ function DataViewsGrid(props) {
27
27
  export {
28
28
  DataViewsGrid
29
29
  };
30
- //# sourceMappingURL=chunk-KUJLZFDW.js.map
30
+ //# sourceMappingURL=chunk-BTKMGXAK.js.map
@@ -33,10 +33,10 @@ function PillControl({
33
33
  onClearField,
34
34
  onOpenChange,
35
35
  testIdPrefix,
36
+ testId = `${testIdPrefix}-filter-${fieldId}`,
36
37
  layout = "pill"
37
38
  }) {
38
39
  const copy = useDataViewsCopy();
39
- const testId = `${testIdPrefix}-filter-${fieldId}`;
40
40
  if (pill.control === "category") {
41
41
  return /* @__PURE__ */ jsx(
42
42
  CategorySelect,
@@ -79,4 +79,4 @@ export {
79
79
  emitPillDiff,
80
80
  PillControl
81
81
  };
82
- //# sourceMappingURL=chunk-I3FXTIKA.js.map
82
+ //# sourceMappingURL=chunk-D5GCWSGS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/data-display/DataViews/data-views-category-pill.tsx"],"sourcesContent":["\"use client\";\n\nimport { useDataViewsCopy } from \"./data-views-copy-context\";\nimport { CategorySelect } from \"../../form/CategorySelect\";\nimport { MultiSelectDropdown } from \"../../layout/ContentToolbar\";\n\nimport type { FilterFieldConfig, FilterOption } from \"./data-views-types\";\n\n/**\n * Diff a whole-array selection back into per-value toggles.\n *\n * The filter state's only channel is `onTogglePill(field, value, checked)`, but\n * a tree hands back the entire selection at once. Diffing here keeps that one\n * channel the single way a pill ever changes, rather than giving the\n * hierarchical control a private path into the state.\n */\nexport function emitPillDiff(\n fieldId: string,\n before: readonly string[],\n after: readonly string[],\n onTogglePill: (fieldId: string, value: string, checked: boolean) => void,\n): void {\n const had = new Set(before);\n const wants = new Set(after);\n after.forEach((value) => {\n if (!had.has(value)) onTogglePill(fieldId, value, true);\n });\n before.forEach((value) => {\n if (!wants.has(value)) onTogglePill(fieldId, value, false);\n });\n}\n\n/** A filter option as the category tree wants it. */\nconst toCategoryOption = (option: FilterOption) => ({\n id: option.value,\n name: option.label,\n parentId: option.parentId ?? null,\n});\n\ninterface PillControlProps<T extends Record<string, unknown>> {\n fieldId: string;\n pill: FilterFieldConfig<T>;\n selected: string[];\n onTogglePill: (fieldId: string, value: string, checked: boolean) => void;\n onClearField: (fieldId: string) => void;\n onOpenChange?: (open: boolean) => void;\n testIdPrefix: string;\n /**\n * Overrides the `<prefix>-filter-<id>` test id — the \"Mais\" panel keys its\n * fields `<prefix>-more-<id>` so a spec can tell which surface it drove.\n */\n testId?: string;\n /** `stacked` in the filter panel, `pill` on the inline bar. */\n layout?: \"stacked\" | \"pill\";\n}\n\n/**\n * One filter pill: the hierarchical category tree, or the flat multi-select.\n *\n * A category set nests, and flattening it into one list is what made \"Massas\"\n * (mercearia) indistinguishable from \"Massas\" (pratos principais). `control:\n * \"category\"` opts a field into the tree, which shows each hit under its parent.\n *\n * {@link FilterFieldConfig.allowParentSelection} decides whether a parent row is\n * itself tickable. It is forwarded rather than fixed here because it is a\n * per-SCREEN question: a filter over a catalogue where products sit on leaves\n * wants \"the whole category\" as one click, while one whose parents are pure\n * grouping would only offer a tick that means nothing.\n */\nexport function PillControl<T extends Record<string, unknown>>({\n fieldId,\n pill,\n selected,\n onTogglePill,\n onClearField,\n onOpenChange,\n testIdPrefix,\n testId = `${testIdPrefix}-filter-${fieldId}`,\n layout = \"pill\",\n}: PillControlProps<T>): React.JSX.Element {\n const copy = useDataViewsCopy();\n if (pill.control === \"category\") {\n return (\n <CategorySelect\n copy={copy.categorySelect}\n placeholder={pill.label}\n label={layout === \"stacked\" ? pill.label : undefined}\n fullWidth={layout === \"stacked\"}\n options={pill.options.map(toCategoryOption)}\n allowParentSelection={pill.allowParentSelection ?? false}\n value={selected}\n onChange={(next) => emitPillDiff(fieldId, selected, next, onTogglePill)}\n dataTestId={testId}\n />\n );\n }\n return (\n <MultiSelectDropdown\n extraOptionsHeading={copy.filters.optionsHeading}\n clearText={copy.filters.clear}\n clearLabel={copy.filters.clearRange(pill.label)}\n label={pill.label}\n options={pill.options}\n selected={new Set(selected)}\n onToggle={(value, checked) => onTogglePill(fieldId, value, checked)}\n onClear={() => onClearField(fieldId)}\n allLabel={copy.filters.allOption}\n searchable={pill.searchEnabled ? true : undefined}\n searchPlaceholder={copy.filters.optionSearchPlaceholder}\n noResultsLabel={copy.filters.optionsEmpty}\n layout={layout}\n onOpenChange={onOpenChange}\n data-testid={testId}\n />\n );\n}\n"],"mappings":";;;;;;;;;;;AAmFM;AAnEC,SAAS,aACd,SACA,QACA,OACA,cACM;AACN,QAAM,MAAM,IAAI,IAAI,MAAM;AAC1B,QAAM,QAAQ,IAAI,IAAI,KAAK;AAC3B,QAAM,QAAQ,CAAC,UAAU;AACvB,QAAI,CAAC,IAAI,IAAI,KAAK,EAAG,cAAa,SAAS,OAAO,IAAI;AAAA,EACxD,CAAC;AACD,SAAO,QAAQ,CAAC,UAAU;AACxB,QAAI,CAAC,MAAM,IAAI,KAAK,EAAG,cAAa,SAAS,OAAO,KAAK;AAAA,EAC3D,CAAC;AACH;AAGA,IAAM,mBAAmB,CAAC,YAA0B;AAAA,EAClD,IAAI,OAAO;AAAA,EACX,MAAM,OAAO;AAAA,EACb,UAAU,OAAO,YAAY;AAC/B;AAgCO,SAAS,YAA+C;AAAA,EAC7D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS,GAAG,YAAY,WAAW,OAAO;AAAA,EAC1C,SAAS;AACX,GAA2C;AACzC,QAAM,OAAO,iBAAiB;AAC9B,MAAI,KAAK,YAAY,YAAY;AAC/B,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,KAAK;AAAA,QACX,aAAa,KAAK;AAAA,QAClB,OAAO,WAAW,YAAY,KAAK,QAAQ;AAAA,QAC3C,WAAW,WAAW;AAAA,QACtB,SAAS,KAAK,QAAQ,IAAI,gBAAgB;AAAA,QAC1C,sBAAsB,KAAK,wBAAwB;AAAA,QACnD,OAAO;AAAA,QACP,UAAU,CAAC,SAAS,aAAa,SAAS,UAAU,MAAM,YAAY;AAAA,QACtE,YAAY;AAAA;AAAA,IACd;AAAA,EAEJ;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,qBAAqB,KAAK,QAAQ;AAAA,MAClC,WAAW,KAAK,QAAQ;AAAA,MACxB,YAAY,KAAK,QAAQ,WAAW,KAAK,KAAK;AAAA,MAC9C,OAAO,KAAK;AAAA,MACZ,SAAS,KAAK;AAAA,MACd,UAAU,IAAI,IAAI,QAAQ;AAAA,MAC1B,UAAU,CAAC,OAAO,YAAY,aAAa,SAAS,OAAO,OAAO;AAAA,MAClE,SAAS,MAAM,aAAa,OAAO;AAAA,MACnC,UAAU,KAAK,QAAQ;AAAA,MACvB,YAAY,KAAK,gBAAgB,OAAO;AAAA,MACxC,mBAAmB,KAAK,QAAQ;AAAA,MAChC,gBAAgB,KAAK,QAAQ;AAAA,MAC7B;AAAA,MACA;AAAA,MACA,eAAa;AAAA;AAAA,EACf;AAEJ;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  PillControl
3
- } from "./chunk-I3FXTIKA.js";
3
+ } from "./chunk-D5GCWSGS.js";
4
4
  import {
5
5
  PanelRangeField
6
6
  } from "./chunk-DFLTUI7W.js";
@@ -154,4 +154,4 @@ export {
154
154
  GridFilterPanel,
155
155
  FilterDialog
156
156
  };
157
- //# sourceMappingURL=chunk-VNGYJXAU.js.map
157
+ //# sourceMappingURL=chunk-DH5OA4VK.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  MoreGroup,
3
3
  fieldClearing
4
- } from "./chunk-EZMCWRXO.js";
4
+ } from "./chunk-ZJ66D63E.js";
5
5
  import {
6
6
  useDataViewsCopy
7
7
  } from "./chunk-KHG57NAE.js";
@@ -180,4 +180,4 @@ function MoreFilters({
180
180
  export {
181
181
  MoreFilters
182
182
  };
183
- //# sourceMappingURL=chunk-6FUOUUYO.js.map
183
+ //# sourceMappingURL=chunk-J2UZOMTA.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-MSS6IU5X.js";
4
4
  import {
5
5
  DataViewsGrid
6
- } from "./chunk-KUJLZFDW.js";
6
+ } from "./chunk-BTKMGXAK.js";
7
7
  import {
8
8
  viewStateKey
9
9
  } from "./chunk-ZOLAYP2D.js";
@@ -178,4 +178,4 @@ function renderViewDialogs(ctl, fields, columns, views, testIdPrefix, onSaved) {
178
178
  export {
179
179
  DataViewsTableBase
180
180
  };
181
- //# sourceMappingURL=chunk-JQL4GG5L.js.map
181
+ //# sourceMappingURL=chunk-LBLX3Q2C.js.map
@@ -2,12 +2,12 @@ import {
2
2
  ClearAllControl,
3
3
  CloseSearchControl
4
4
  } from "./chunk-5WNQJ5KS.js";
5
- import {
6
- PillControl
7
- } from "./chunk-I3FXTIKA.js";
8
5
  import {
9
6
  MoreFilters
10
- } from "./chunk-6FUOUUYO.js";
7
+ } from "./chunk-J2UZOMTA.js";
8
+ import {
9
+ PillControl
10
+ } from "./chunk-D5GCWSGS.js";
11
11
  import {
12
12
  RangePill
13
13
  } from "./chunk-DFLTUI7W.js";
@@ -220,4 +220,4 @@ function FilterSlots({
220
220
  export {
221
221
  InlineFilterControls
222
222
  };
223
- //# sourceMappingURL=chunk-CASZGBCA.js.map
223
+ //# sourceMappingURL=chunk-PZAXUO6F.js.map
@@ -95,11 +95,14 @@ function useFilterOverflow(all, pills, ranges, frozen = false, hasExport = true)
95
95
  if (cache.current === null || !frozen && cache.current.signature !== signature) {
96
96
  cache.current = { signature, split: computeSplit(all, pills, ranges, width, hasExport) };
97
97
  }
98
- return { ...cache.current.split, barRef };
98
+ const { split } = cache.current;
99
+ const current = new Map(all.map((field) => [field.id, field]));
100
+ const fresh = (fields) => fields.map((field) => current.get(field.id) ?? field);
101
+ return { ...split, inline: fresh(split.inline), overflow: fresh(split.overflow), barRef };
99
102
  }
100
103
 
101
104
  export {
102
105
  toOverflowFields,
103
106
  useFilterOverflow
104
107
  };
105
- //# sourceMappingURL=chunk-TQ6FPOPD.js.map
108
+ //# sourceMappingURL=chunk-TPKSOHB5.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/data-display/DataViews/data-views-overflow.ts"],"sourcesContent":["\"use client\";\n\nimport { useRef } from \"react\";\n\nimport { splitToFit, useMeasuredWidth } from \"../../utility/Overflow\";\nimport {\n estimateWidth,\n furnitureCost,\n GAP,\n isRangeSet,\n pillText,\n RESERVED,\n rightClusterCost,\n} from \"./data-views-overflow-costs\";\nimport type { FilterFieldConfig, RangeFieldConfig, RangeValue } from \"./data-views-types\";\n\n/**\n * PROGRESSIVE COLLAPSE — which filter controls fit on the toolbar, measured.\n *\n * Two rules, and both come from watching the all-or-nothing version fail:\n *\n * 1. Controls shed ONE AT A TIME into an overflow, never all at once. With four\n * filters and room for three, hiding all four throws away the room that was\n * there.\n * 2. An APPLIED filter is ranked first, not exempt. Applied controls take the\n * visible slots ahead of idle ones, and go into \"Mais\" like anything else\n * when even those slots run out. Exempting them outright — the earlier rule\n * — meant four applied filters on a phone claimed more width than the row\n * had, and the bar painted past its own edge: the pills were reachable only\n * by scrolling the toolbar sideways. Hiding one is safe because \"Mais\" says\n * how many applied filters are behind it; scrolling one off-screen says\n * nothing at all.\n *\n * It MEASURES rather than picking a breakpoint, which is what\n * `FILTERS-CONTRACT.md` asks for: pages declare different numbers of filters\n * with different label lengths, and the same page collapses at a different\n * width in another language. A shared breakpoint is wrong for at least one\n * table by construction.\n *\n * Collapsing is presentation only — nothing here emits a query, drops a filter\n * or changes a rendered row.\n */\n\n/** A filter control on the bar: a multi-select pill or a min/max range. */\nexport interface OverflowField<T extends Record<string, unknown>> {\n id: string;\n label: string;\n /** Which control it is — the caller renders the right one. */\n group: \"pill\" | \"range\";\n pill?: FilterFieldConfig<T>;\n range?: RangeFieldConfig<T>;\n}\n\n/** What the caller renders inline, and what goes behind \"Mais\". */\nexport interface OverflowSplit<T extends Record<string, unknown>> {\n inline: OverflowField<T>[];\n overflow: OverflowField<T>[];\n /**\n * Step 2 — Exibir/Exportar drop their text labels and become icons.\n * Cheap: both keep their icon, their tooltip and their position.\n */\n compactControls: boolean;\n /**\n * Step 5, and the LAST resort — the \"N de N\" counter is dropped.\n *\n * Only once every control has already collapsed and the row STILL does not\n * fit, which on a six-filter table is below about 400px. The counter goes\n * last because it is the only thing left that reports rather than does: an\n * operator can act without knowing the total, but not without the search.\n */\n counterHidden: boolean;\n /**\n * Step 4 — the search collapses to a magnifier that expands on click.\n * The most expensive step, so it is taken last: the search is the one\n * control on the bar that cannot be guessed from an icon's position.\n */\n searchCollapsed: boolean;\n /**\n * Step 6, below even the counter — \"Limpar\" leaves the bar.\n *\n * The one control here with a second home: the overflow panel's footer\n * carries \"Limpar todos os filtros\". So it goes before the search icon or\n * \"Mais\", neither of which has anywhere else to be.\n */\n clearAllHidden: boolean;\n /**\n * Expanding the magnifier must take the whole cluster, filters and all.\n *\n * Only on the rungs where what is left over would be too narrow to read —\n * on a large phone the box simply shrinks and the filters stay, which is why\n * this is its own answer rather than `searchCollapsed` reused.\n */\n searchTakeover: boolean;\n /** Attach to the toolbar row being measured. */\n barRef: React.RefObject<HTMLDivElement | null>;\n}\n\n/** Every declared control, pills first, in the order the bar renders them. */\nexport function toOverflowFields<T extends Record<string, unknown>>(\n fields: FilterFieldConfig<T>[],\n rangeFields: RangeFieldConfig<T>[],\n): OverflowField<T>[] {\n return [\n ...fields.map((pill) => ({ id: pill.id, label: pill.label, group: \"pill\" as const, pill })),\n ...rangeFields.map((range) => ({ id: range.id, label: range.label, group: \"range\" as const, range })),\n ];\n}\n\n\n/** Is this control carrying a value the operator set? */\nfunction isActiveField<T extends Record<string, unknown>>(\n field: OverflowField<T>,\n pills: Record<string, string[]>,\n ranges: Record<string, RangeValue>,\n): boolean {\n return field.group === \"pill\"\n ? (pills[field.id]?.length ?? 0) > 0\n : isRangeSet(ranges[field.id]);\n}\n\n/** Estimated rendered width of one control at its CURRENT value. */\nfunction fieldWidth<T extends Record<string, unknown>>(\n field: OverflowField<T>,\n pills: Record<string, string[]>,\n ranges: Record<string, RangeValue>,\n): number {\n if (field.group === \"pill\") return estimateWidth(pillText(field, pills[field.id] ?? []), 0);\n // A bounded range renders two number inputs beside its label.\n return estimateWidth(field.label, isRangeSet(ranges[field.id]) ? 100 : 0);\n}\n\n/** What one split costs on the bar, so the ladder below can price the next step. */\ntype Split<T extends Record<string, unknown>> = {\n inline: OverflowField<T>[];\n overflow: OverflowField<T>[];\n /** Width the surviving inline controls occupy, incl. the \"Mais\" button. */\n used: number;\n};\n\n/** Step 1 — shed filter controls into the overflow. Pure. */\nfunction splitFilters<T extends Record<string, unknown>>(\n all: OverflowField<T>[],\n pills: Record<string, string[]>,\n ranges: Record<string, RangeValue>,\n width: number,\n /** Search + counter + right cluster + chrome, at the rung being considered. */\n furniture: number,\n /** Is the bar already down to icons? \"Mais\" shrinks with everything else. */\n compact: boolean,\n): Split<T> {\n const active = all.filter((field) => isActiveField(field, pills, ranges));\n const idle = all.filter((field) => !isActiveField(field, pills, ranges));\n\n // \"Limpar\" rides the end of the cluster whenever anything is applied.\n const clearCost = active.length > 0 ? RESERVED.clearAll + GAP : 0;\n // APPLIED FIRST, BUT NOT EXEMPT.\n //\n // Applied controls take the visible slots ahead of idle ones — that part was\n // always right. Exempting them from the overflow entirely was not: applying\n // a value LENGTHENS a control (\"Pagamento (1)\"), so on a phone four applied\n // filters claimed more width than the row had and the bar simply painted\n // past its own edge, leaving pills reachable only by scrolling sideways.\n //\n // An applied filter hidden in \"Mais\" is not lost the way it would be if it\n // vanished silently: the trigger goes to the applied tone and says how many\n // are in there (see `MoreTrigger`), which is the same signal the pill itself\n // was carrying. A control you scroll off-screen carries no signal at all.\n //\n // The keep-what-fits loop itself is `splitToFit` (`utility/Overflow`) — the\n // one part of this that is not filter-shaped, and the part a second cluster\n // in the design system would otherwise have had to reimplement.\n const split = splitToFit(all, {\n widthOf: (field) => fieldWidth(field, pills, ranges),\n keyOf: (field) => field.id,\n gap: GAP,\n available: width - furniture - clearCost,\n // The overflow button at the width it will actually have, which on a phone\n // is the icon-and-badge one.\n overflowCost: compact ? RESERVED.overflowButtonCompact : RESERVED.overflowButton,\n priority: [...active, ...idle],\n });\n return { ...split, used: split.used + clearCost };\n}\n\n/**\n * THE DEGRADATION LADDER — cheapest loss first, and each rung taken only if\n * the one before it did not free enough:\n *\n * 1. filter controls move into the \"Mais\" overflow (`splitFilters`)\n * 2. Exibir / Exportar drop their text labels (`compactControls`)\n * 3. the search shrinks toward its minimum (CSS: it is `flex: 1`)\n * 4. the search itself collapses to an icon (`searchCollapsed`)\n *\n * Step 3 needs no flag — the search is a flex child, so it gives up width on\n * its own until it hits `RESERVED.search`. The flags mark the two steps that\n * change what is RENDERED rather than how wide it is.\n *\n * Measured against what is CURRENTLY on the bar, never a breakpoint: a\n * two-filter page and a five-filter page would otherwise collapse at the same\n * width, and only one of them would be right.\n */\nfunction computeSplit<T extends Record<string, unknown>>(\n all: OverflowField<T>[],\n pills: Record<string, string[]>,\n ranges: Record<string, RangeValue>,\n width: number,\n /** Does the host render \"Exportar\" beside \"Exibir\"? Half the cluster if not. */\n hasExport: boolean,\n): Omit<OverflowSplit<T>, \"barRef\"> {\n // Unmeasured (SSR, or jsdom without a ResizeObserver) ⇒ degrade nothing.\n if (width === 0) {\n return {\n inline: all,\n overflow: [],\n compactControls: false,\n counterHidden: false,\n searchCollapsed: false,\n clearAllHidden: false,\n searchTakeover: false,\n };\n }\n // Pass 1 prices the furniture at its widest — no rung has been taken yet.\n let split = splitFilters(all, pills, ranges, width, furnitureCost(UNCOLLAPSED, hasExport), false);\n let flags = ladderFlags(split, width, hasExport);\n // RE-SPEND WHAT THE LATER RUNGS FREED.\n //\n // Rungs 2/4/5 turn 200 + 96 + 216 of furniture into 44 + 0 + 140, and until\n // this loop existed nobody handed those ~330px back to the filters: the\n // split was decided once, against the uncollapsed row, so a phone shed every\n // control and then sat with a band of empty bar beside \"Mais 5\".\n //\n // Settles rather than oscillates, and cannot overfill: a cheaper furniture\n // can only give the filters MORE room, more filter width can only push the\n // ladder FURTHER down, and a further rung can only make the furniture\n // cheaper again — so the budget decreases monotonically and the loop exits\n // the moment it stops moving. The bound is a backstop, not the exit.\n let budget = furnitureCost(UNCOLLAPSED, hasExport);\n for (let pass = 0; pass < 3; pass += 1) {\n const freed = furnitureCost(flags, hasExport);\n if (freed >= budget) break;\n budget = freed;\n split = splitFilters(all, pills, ranges, width, budget, flags.compactControls);\n flags = ladderFlags(split, width, hasExport);\n }\n return { inline: split.inline, overflow: split.overflow, ...flags };\n}\n\n/** The widest the furniture ever is — every rung still untaken. */\nconst UNCOLLAPSED = { searchCollapsed: false, counterHidden: false, compactControls: false };\n\n/** Rungs 2 and 4-6, priced against what the filters actually took. */\nfunction ladderFlags<T extends Record<string, unknown>>(\n split: Split<T>,\n width: number,\n hasExport: boolean,\n): Omit<OverflowSplit<T>, \"barRef\" | \"inline\" | \"overflow\"> {\n const { overflow, used } = split;\n const base = width - used - RESERVED.chrome;\n\n // Would the search still make its minimum with the labels on?\n const compactControls = base - RESERVED.counter - rightClusterCost(hasExport, false) < RESERVED.search;\n const rightCost = rightClusterCost(hasExport, compactControls);\n // …and with them off?\n const searchCollapsed = base - RESERVED.counter - rightCost < RESERVED.search;\n // Everything has collapsed and the row STILL overflows. The controls cannot\n // shrink further — they are `flexShrink: 0` precisely so an over-packed row\n // sheds rather than squeezes — so without this last rung they simply paint\n // outside the toolbar, which is what a narrow phone was doing.\n const counterHidden =\n searchCollapsed && base - RESERVED.counter - rightCost < RESERVED.searchIcon;\n // Step 6 — below even that, \"Limpar\" leaves the bar. It is the ONLY control\n // here with a second home: the overflow panel's footer carries \"Limpar todos\n // os filtros\", so nothing is lost, which is exactly why it goes before the\n // search icon or \"Mais\" (neither of which has anywhere else to be). Guarded\n // on there BEING an overflow, because with no panel the footer does not\n // exist and dropping this would strand the operator.\n const clearAllHidden = counterHidden && overflow.length > 0;\n // What the keyword box would get if the operator expanded the magnifier.\n // `searchCollapsed` is a different question — it asks whether the box fits at\n // its PREFERRED 200px, and is deliberately pessimistic — so reusing it to\n // decide the takeover evicted the filters on screens where the box had plenty\n // of room to simply shrink.\n //\n // Asked with the inline filters SHED, because shedding them is exactly what\n // expanding the box does: the row re-splits and they go behind \"Mais\".\n // Measuring against the resting row instead made a filter argue for its own\n // eviction — now that a large phone keeps one, its width came out of `base`,\n // pushed the box under `usableSearch`, and tipped a row that had ample space\n // to share into a full takeover.\n const overflowButton = compactControls\n ? RESERVED.overflowButtonCompact\n : RESERVED.overflowButton;\n const shedRoom = width - RESERVED.chrome - (overflow.length > 0 ? overflowButton : 0);\n const searchBoxRoom = shedRoom - (counterHidden ? 0 : RESERVED.counter) - rightCost;\n // Below this a box is too narrow to read what you typed into it, and shrinking\n // further buys nothing; that is the only point at which taking the whole\n // cluster is worth losing the filters.\n const searchTakeover = searchCollapsed && searchBoxRoom < RESERVED.usableSearch;\n\n return { compactControls, counterHidden, searchCollapsed, clearAllHidden, searchTakeover };\n}\n\n/**\n * Split the declared filter controls into what fits and what goes behind\n * \"Mais\", measured against the live toolbar width.\n *\n * Cached on a SIGNATURE rather than by `useMemo` over the inputs: hosts declare\n * their fields inline, so `all` is a fresh array on every render while the\n * configuration is unchanged, and a reference-keyed memo would never hit.\n */\nexport function useFilterOverflow<T extends Record<string, unknown>>(\n all: OverflowField<T>[],\n pills: Record<string, string[]>,\n ranges: Record<string, RangeValue>,\n /**\n * A filter control is open — hold the current answer until it closes.\n *\n * Applying a filter changes that control's LABEL (\"Valor\" becomes \"Valor: ≥\n * R$ 1\"), which changes its measured width, which re-runs the whole split\n * while its popover is open on top of it. Measured: setting a minimum moved\n * the trigger 192px left, took the popover with it, and pushed two other\n * controls into a newly-appeared \"Mais 2\" — so reaching for the second bound\n * meant chasing the control across the row. Nobody sets a range that way.\n *\n * Frozen only for the duration: closing re-measures against the new labels,\n * so the row still ends up correct, it just does not rearrange under a hand\n * that is mid-edit.\n */\n frozen = false,\n /** Whether \"Exportar\" is on the bar — see `rightClusterCost`. */\n hasExport = true,\n): OverflowSplit<T> {\n // The measurement is `useMeasuredWidth` (`utility/Overflow`): the same\n // ResizeObserver every collapsing cluster in the design system reads, so\n // there is one loop to get right rather than one per bar. `0` until the\n // first measurement lands (and forever under SSR or jsdom), which\n // `computeSplit` reads as \"degrade nothing\".\n const { ref: barRef, width } = useMeasuredWidth<HTMLDivElement>();\n const signature = JSON.stringify({\n ids: all.map((field) => field.id),\n pills,\n ranges,\n width,\n hasExport,\n });\n const cache = useRef<{ signature: string; split: ReturnType<typeof computeSplit<T>> } | null>(null);\n if (cache.current === null || (!frozen && cache.current.signature !== signature)) {\n cache.current = { signature, split: computeSplit(all, pills, ranges, width, hasExport) };\n }\n return { ...cache.current.split, barRef };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/components/data-display/DataViews/data-views-overflow.ts"],"sourcesContent":["\"use client\";\n\nimport { useRef } from \"react\";\n\nimport { splitToFit, useMeasuredWidth } from \"../../utility/Overflow\";\nimport {\n estimateWidth,\n furnitureCost,\n GAP,\n isRangeSet,\n pillText,\n RESERVED,\n rightClusterCost,\n} from \"./data-views-overflow-costs\";\nimport type { FilterFieldConfig, RangeFieldConfig, RangeValue } from \"./data-views-types\";\n\n/**\n * PROGRESSIVE COLLAPSE — which filter controls fit on the toolbar, measured.\n *\n * Two rules, and both come from watching the all-or-nothing version fail:\n *\n * 1. Controls shed ONE AT A TIME into an overflow, never all at once. With four\n * filters and room for three, hiding all four throws away the room that was\n * there.\n * 2. An APPLIED filter is ranked first, not exempt. Applied controls take the\n * visible slots ahead of idle ones, and go into \"Mais\" like anything else\n * when even those slots run out. Exempting them outright — the earlier rule\n * — meant four applied filters on a phone claimed more width than the row\n * had, and the bar painted past its own edge: the pills were reachable only\n * by scrolling the toolbar sideways. Hiding one is safe because \"Mais\" says\n * how many applied filters are behind it; scrolling one off-screen says\n * nothing at all.\n *\n * It MEASURES rather than picking a breakpoint, which is what\n * `FILTERS-CONTRACT.md` asks for: pages declare different numbers of filters\n * with different label lengths, and the same page collapses at a different\n * width in another language. A shared breakpoint is wrong for at least one\n * table by construction.\n *\n * Collapsing is presentation only — nothing here emits a query, drops a filter\n * or changes a rendered row.\n */\n\n/** A filter control on the bar: a multi-select pill or a min/max range. */\nexport interface OverflowField<T extends Record<string, unknown>> {\n id: string;\n label: string;\n /** Which control it is — the caller renders the right one. */\n group: \"pill\" | \"range\";\n pill?: FilterFieldConfig<T>;\n range?: RangeFieldConfig<T>;\n}\n\n/** What the caller renders inline, and what goes behind \"Mais\". */\nexport interface OverflowSplit<T extends Record<string, unknown>> {\n inline: OverflowField<T>[];\n overflow: OverflowField<T>[];\n /**\n * Step 2 — Exibir/Exportar drop their text labels and become icons.\n * Cheap: both keep their icon, their tooltip and their position.\n */\n compactControls: boolean;\n /**\n * Step 5, and the LAST resort — the \"N de N\" counter is dropped.\n *\n * Only once every control has already collapsed and the row STILL does not\n * fit, which on a six-filter table is below about 400px. The counter goes\n * last because it is the only thing left that reports rather than does: an\n * operator can act without knowing the total, but not without the search.\n */\n counterHidden: boolean;\n /**\n * Step 4 — the search collapses to a magnifier that expands on click.\n * The most expensive step, so it is taken last: the search is the one\n * control on the bar that cannot be guessed from an icon's position.\n */\n searchCollapsed: boolean;\n /**\n * Step 6, below even the counter — \"Limpar\" leaves the bar.\n *\n * The one control here with a second home: the overflow panel's footer\n * carries \"Limpar todos os filtros\". So it goes before the search icon or\n * \"Mais\", neither of which has anywhere else to be.\n */\n clearAllHidden: boolean;\n /**\n * Expanding the magnifier must take the whole cluster, filters and all.\n *\n * Only on the rungs where what is left over would be too narrow to read —\n * on a large phone the box simply shrinks and the filters stay, which is why\n * this is its own answer rather than `searchCollapsed` reused.\n */\n searchTakeover: boolean;\n /** Attach to the toolbar row being measured. */\n barRef: React.RefObject<HTMLDivElement | null>;\n}\n\n/** Every declared control, pills first, in the order the bar renders them. */\nexport function toOverflowFields<T extends Record<string, unknown>>(\n fields: FilterFieldConfig<T>[],\n rangeFields: RangeFieldConfig<T>[],\n): OverflowField<T>[] {\n return [\n ...fields.map((pill) => ({ id: pill.id, label: pill.label, group: \"pill\" as const, pill })),\n ...rangeFields.map((range) => ({ id: range.id, label: range.label, group: \"range\" as const, range })),\n ];\n}\n\n\n/** Is this control carrying a value the operator set? */\nfunction isActiveField<T extends Record<string, unknown>>(\n field: OverflowField<T>,\n pills: Record<string, string[]>,\n ranges: Record<string, RangeValue>,\n): boolean {\n return field.group === \"pill\"\n ? (pills[field.id]?.length ?? 0) > 0\n : isRangeSet(ranges[field.id]);\n}\n\n/** Estimated rendered width of one control at its CURRENT value. */\nfunction fieldWidth<T extends Record<string, unknown>>(\n field: OverflowField<T>,\n pills: Record<string, string[]>,\n ranges: Record<string, RangeValue>,\n): number {\n if (field.group === \"pill\") return estimateWidth(pillText(field, pills[field.id] ?? []), 0);\n // A bounded range renders two number inputs beside its label.\n return estimateWidth(field.label, isRangeSet(ranges[field.id]) ? 100 : 0);\n}\n\n/** What one split costs on the bar, so the ladder below can price the next step. */\ntype Split<T extends Record<string, unknown>> = {\n inline: OverflowField<T>[];\n overflow: OverflowField<T>[];\n /** Width the surviving inline controls occupy, incl. the \"Mais\" button. */\n used: number;\n};\n\n/** Step 1 — shed filter controls into the overflow. Pure. */\nfunction splitFilters<T extends Record<string, unknown>>(\n all: OverflowField<T>[],\n pills: Record<string, string[]>,\n ranges: Record<string, RangeValue>,\n width: number,\n /** Search + counter + right cluster + chrome, at the rung being considered. */\n furniture: number,\n /** Is the bar already down to icons? \"Mais\" shrinks with everything else. */\n compact: boolean,\n): Split<T> {\n const active = all.filter((field) => isActiveField(field, pills, ranges));\n const idle = all.filter((field) => !isActiveField(field, pills, ranges));\n\n // \"Limpar\" rides the end of the cluster whenever anything is applied.\n const clearCost = active.length > 0 ? RESERVED.clearAll + GAP : 0;\n // APPLIED FIRST, BUT NOT EXEMPT.\n //\n // Applied controls take the visible slots ahead of idle ones — that part was\n // always right. Exempting them from the overflow entirely was not: applying\n // a value LENGTHENS a control (\"Pagamento (1)\"), so on a phone four applied\n // filters claimed more width than the row had and the bar simply painted\n // past its own edge, leaving pills reachable only by scrolling sideways.\n //\n // An applied filter hidden in \"Mais\" is not lost the way it would be if it\n // vanished silently: the trigger goes to the applied tone and says how many\n // are in there (see `MoreTrigger`), which is the same signal the pill itself\n // was carrying. A control you scroll off-screen carries no signal at all.\n //\n // The keep-what-fits loop itself is `splitToFit` (`utility/Overflow`) — the\n // one part of this that is not filter-shaped, and the part a second cluster\n // in the design system would otherwise have had to reimplement.\n const split = splitToFit(all, {\n widthOf: (field) => fieldWidth(field, pills, ranges),\n keyOf: (field) => field.id,\n gap: GAP,\n available: width - furniture - clearCost,\n // The overflow button at the width it will actually have, which on a phone\n // is the icon-and-badge one.\n overflowCost: compact ? RESERVED.overflowButtonCompact : RESERVED.overflowButton,\n priority: [...active, ...idle],\n });\n return { ...split, used: split.used + clearCost };\n}\n\n/**\n * THE DEGRADATION LADDER — cheapest loss first, and each rung taken only if\n * the one before it did not free enough:\n *\n * 1. filter controls move into the \"Mais\" overflow (`splitFilters`)\n * 2. Exibir / Exportar drop their text labels (`compactControls`)\n * 3. the search shrinks toward its minimum (CSS: it is `flex: 1`)\n * 4. the search itself collapses to an icon (`searchCollapsed`)\n *\n * Step 3 needs no flag — the search is a flex child, so it gives up width on\n * its own until it hits `RESERVED.search`. The flags mark the two steps that\n * change what is RENDERED rather than how wide it is.\n *\n * Measured against what is CURRENTLY on the bar, never a breakpoint: a\n * two-filter page and a five-filter page would otherwise collapse at the same\n * width, and only one of them would be right.\n */\nfunction computeSplit<T extends Record<string, unknown>>(\n all: OverflowField<T>[],\n pills: Record<string, string[]>,\n ranges: Record<string, RangeValue>,\n width: number,\n /** Does the host render \"Exportar\" beside \"Exibir\"? Half the cluster if not. */\n hasExport: boolean,\n): Omit<OverflowSplit<T>, \"barRef\"> {\n // Unmeasured (SSR, or jsdom without a ResizeObserver) ⇒ degrade nothing.\n if (width === 0) {\n return {\n inline: all,\n overflow: [],\n compactControls: false,\n counterHidden: false,\n searchCollapsed: false,\n clearAllHidden: false,\n searchTakeover: false,\n };\n }\n // Pass 1 prices the furniture at its widest — no rung has been taken yet.\n let split = splitFilters(all, pills, ranges, width, furnitureCost(UNCOLLAPSED, hasExport), false);\n let flags = ladderFlags(split, width, hasExport);\n // RE-SPEND WHAT THE LATER RUNGS FREED.\n //\n // Rungs 2/4/5 turn 200 + 96 + 216 of furniture into 44 + 0 + 140, and until\n // this loop existed nobody handed those ~330px back to the filters: the\n // split was decided once, against the uncollapsed row, so a phone shed every\n // control and then sat with a band of empty bar beside \"Mais 5\".\n //\n // Settles rather than oscillates, and cannot overfill: a cheaper furniture\n // can only give the filters MORE room, more filter width can only push the\n // ladder FURTHER down, and a further rung can only make the furniture\n // cheaper again — so the budget decreases monotonically and the loop exits\n // the moment it stops moving. The bound is a backstop, not the exit.\n let budget = furnitureCost(UNCOLLAPSED, hasExport);\n for (let pass = 0; pass < 3; pass += 1) {\n const freed = furnitureCost(flags, hasExport);\n if (freed >= budget) break;\n budget = freed;\n split = splitFilters(all, pills, ranges, width, budget, flags.compactControls);\n flags = ladderFlags(split, width, hasExport);\n }\n return { inline: split.inline, overflow: split.overflow, ...flags };\n}\n\n/** The widest the furniture ever is — every rung still untaken. */\nconst UNCOLLAPSED = { searchCollapsed: false, counterHidden: false, compactControls: false };\n\n/** Rungs 2 and 4-6, priced against what the filters actually took. */\nfunction ladderFlags<T extends Record<string, unknown>>(\n split: Split<T>,\n width: number,\n hasExport: boolean,\n): Omit<OverflowSplit<T>, \"barRef\" | \"inline\" | \"overflow\"> {\n const { overflow, used } = split;\n const base = width - used - RESERVED.chrome;\n\n // Would the search still make its minimum with the labels on?\n const compactControls = base - RESERVED.counter - rightClusterCost(hasExport, false) < RESERVED.search;\n const rightCost = rightClusterCost(hasExport, compactControls);\n // …and with them off?\n const searchCollapsed = base - RESERVED.counter - rightCost < RESERVED.search;\n // Everything has collapsed and the row STILL overflows. The controls cannot\n // shrink further — they are `flexShrink: 0` precisely so an over-packed row\n // sheds rather than squeezes — so without this last rung they simply paint\n // outside the toolbar, which is what a narrow phone was doing.\n const counterHidden =\n searchCollapsed && base - RESERVED.counter - rightCost < RESERVED.searchIcon;\n // Step 6 — below even that, \"Limpar\" leaves the bar. It is the ONLY control\n // here with a second home: the overflow panel's footer carries \"Limpar todos\n // os filtros\", so nothing is lost, which is exactly why it goes before the\n // search icon or \"Mais\" (neither of which has anywhere else to be). Guarded\n // on there BEING an overflow, because with no panel the footer does not\n // exist and dropping this would strand the operator.\n const clearAllHidden = counterHidden && overflow.length > 0;\n // What the keyword box would get if the operator expanded the magnifier.\n // `searchCollapsed` is a different question — it asks whether the box fits at\n // its PREFERRED 200px, and is deliberately pessimistic — so reusing it to\n // decide the takeover evicted the filters on screens where the box had plenty\n // of room to simply shrink.\n //\n // Asked with the inline filters SHED, because shedding them is exactly what\n // expanding the box does: the row re-splits and they go behind \"Mais\".\n // Measuring against the resting row instead made a filter argue for its own\n // eviction — now that a large phone keeps one, its width came out of `base`,\n // pushed the box under `usableSearch`, and tipped a row that had ample space\n // to share into a full takeover.\n const overflowButton = compactControls\n ? RESERVED.overflowButtonCompact\n : RESERVED.overflowButton;\n const shedRoom = width - RESERVED.chrome - (overflow.length > 0 ? overflowButton : 0);\n const searchBoxRoom = shedRoom - (counterHidden ? 0 : RESERVED.counter) - rightCost;\n // Below this a box is too narrow to read what you typed into it, and shrinking\n // further buys nothing; that is the only point at which taking the whole\n // cluster is worth losing the filters.\n const searchTakeover = searchCollapsed && searchBoxRoom < RESERVED.usableSearch;\n\n return { compactControls, counterHidden, searchCollapsed, clearAllHidden, searchTakeover };\n}\n\n/**\n * Split the declared filter controls into what fits and what goes behind\n * \"Mais\", measured against the live toolbar width.\n *\n * Cached on a SIGNATURE rather than by `useMemo` over the inputs: hosts declare\n * their fields inline, so `all` is a fresh array on every render while the\n * configuration is unchanged, and a reference-keyed memo would never hit.\n */\nexport function useFilterOverflow<T extends Record<string, unknown>>(\n all: OverflowField<T>[],\n pills: Record<string, string[]>,\n ranges: Record<string, RangeValue>,\n /**\n * A filter control is open — hold the current answer until it closes.\n *\n * Applying a filter changes that control's LABEL (\"Valor\" becomes \"Valor: ≥\n * R$ 1\"), which changes its measured width, which re-runs the whole split\n * while its popover is open on top of it. Measured: setting a minimum moved\n * the trigger 192px left, took the popover with it, and pushed two other\n * controls into a newly-appeared \"Mais 2\" — so reaching for the second bound\n * meant chasing the control across the row. Nobody sets a range that way.\n *\n * Frozen only for the duration: closing re-measures against the new labels,\n * so the row still ends up correct, it just does not rearrange under a hand\n * that is mid-edit.\n */\n frozen = false,\n /** Whether \"Exportar\" is on the bar — see `rightClusterCost`. */\n hasExport = true,\n): OverflowSplit<T> {\n // The measurement is `useMeasuredWidth` (`utility/Overflow`): the same\n // ResizeObserver every collapsing cluster in the design system reads, so\n // there is one loop to get right rather than one per bar. `0` until the\n // first measurement lands (and forever under SSR or jsdom), which\n // `computeSplit` reads as \"degrade nothing\".\n const { ref: barRef, width } = useMeasuredWidth<HTMLDivElement>();\n const signature = JSON.stringify({\n ids: all.map((field) => field.id),\n pills,\n ranges,\n width,\n hasExport,\n });\n const cache = useRef<{ signature: string; split: ReturnType<typeof computeSplit<T>> } | null>(null);\n if (cache.current === null || (!frozen && cache.current.signature !== signature)) {\n cache.current = { signature, split: computeSplit(all, pills, ranges, width, hasExport) };\n }\n // The cache holds the ARRANGEMENT — which ids sit on the bar, which in \"Mais\"\n // — never the fields themselves. The signature keys on ids, so a field whose\n // options arrive after the first measurement (a category list still loading)\n // does not re-split, and handing back the cached objects served the empty\n // list for good: \"Categoria\" in \"Mais\" rendered a label with no control under\n // it (FUT-2828). Re-reading each field from `all` keeps the slots and the\n // current config.\n const { split } = cache.current;\n const current = new Map(all.map((field) => [field.id, field]));\n const fresh = (fields: OverflowField<T>[]): OverflowField<T>[] =>\n fields.map((field) => current.get(field.id) ?? field);\n return { ...split, inline: fresh(split.inline), overflow: fresh(split.overflow), barRef };\n}\n"],"mappings":"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","names":[]}
@@ -1,3 +1,6 @@
1
+ import {
2
+ PillControl
3
+ } from "./chunk-D5GCWSGS.js";
1
4
  import {
2
5
  RangeBounds
3
6
  } from "./chunk-DFLTUI7W.js";
@@ -7,9 +10,6 @@ import {
7
10
  import {
8
11
  useDataViewsCopy
9
12
  } from "./chunk-KHG57NAE.js";
10
- import {
11
- MultiSelectDropdown
12
- } from "./chunk-4T6W43TO.js";
13
13
  import {
14
14
  default as default2
15
15
  } from "./chunk-6DPAWXZ3.js";
@@ -21,43 +21,41 @@ import {
21
21
  import Checkbox from "@mui/material/Checkbox/index.js";
22
22
  import { jsx, jsxs } from "react/jsx-runtime";
23
23
  var INLINE_OPTION_LIMIT = 2;
24
+ function sharesBarControl(field) {
25
+ const pill = field.pill;
26
+ if (!pill) return false;
27
+ return pill.control === "category" || pill.control === "multiselect" || pill.searchEnabled === true || pill.options.length > INLINE_OPTION_LIMIT;
28
+ }
24
29
  function OverflowPill({
25
30
  field,
26
31
  values,
27
- onToggle,
32
+ onTogglePill,
28
33
  onClear,
29
34
  testIdPrefix
30
35
  }) {
31
- const copy = useDataViewsCopy();
32
- const options = field.pill?.options ?? [];
33
- if (options.length > INLINE_OPTION_LIMIT) {
36
+ const testId = `${testIdPrefix}-more-${field.id}`;
37
+ if (field.pill && sharesBarControl(field)) {
34
38
  return /* @__PURE__ */ jsx(
35
- MultiSelectDropdown,
39
+ PillControl,
36
40
  {
37
- extraOptionsHeading: copy.filters.optionsHeading,
38
- clearText: copy.filters.clear,
39
- clearLabel: copy.filters.clearRange(field.label),
40
- label: field.pill?.label ?? field.label,
41
- options,
42
- selected: new Set(values),
43
- onToggle,
44
- onClear,
45
- allLabel: copy.filters.allOption,
46
- searchable: options.length > 6 ? true : void 0,
47
- searchPlaceholder: copy.filters.optionSearchPlaceholder,
48
- noResultsLabel: copy.filters.optionsEmpty,
49
- layout: "pill",
50
- "data-testid": `${testIdPrefix}-more-${field.id}`
41
+ fieldId: field.id,
42
+ pill: field.pill,
43
+ selected: values,
44
+ onTogglePill,
45
+ onClearField: onClear,
46
+ testIdPrefix,
47
+ testId
51
48
  }
52
49
  );
53
50
  }
51
+ const onToggle = (value, checked) => onTogglePill(field.id, value, checked);
54
52
  return /* @__PURE__ */ jsx(default2, { sx: { display: "flex", flexWrap: "wrap", gap: 0.75 }, children: (field.pill?.options ?? []).map((option) => {
55
53
  const checked = values.includes(option.value);
56
54
  return /* @__PURE__ */ jsxs(
57
55
  default2,
58
56
  {
59
57
  component: "label",
60
- "data-testid": `${testIdPrefix}-more-${field.id}-${option.value}`,
58
+ "data-testid": `${testId}-${option.value}`,
61
59
  sx: {
62
60
  display: "inline-flex",
63
61
  alignItems: "center",
@@ -168,7 +166,7 @@ function MoreGroup({
168
166
  {
169
167
  field,
170
168
  values: pills[field.id] ?? [],
171
- onToggle: (value, checked) => onTogglePill(field.id, value, checked),
169
+ onTogglePill,
172
170
  onClear: () => (pills[field.id] ?? []).forEach((v) => onTogglePill(field.id, v, false)),
173
171
  testIdPrefix
174
172
  }
@@ -188,4 +186,4 @@ export {
188
186
  fieldClearing,
189
187
  MoreGroup
190
188
  };
191
- //# sourceMappingURL=chunk-EZMCWRXO.js.map
189
+ //# sourceMappingURL=chunk-ZJ66D63E.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/data-display/DataViews/data-views-more-fields.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * ONE FIELD, RENDERED INSIDE THE \"MAIS\" PANEL.\n *\n * Split from `data-views-more-filters` at the file-size gate, along the seam\n * that was already there: that module is the trigger, the panel and its\n * footer — the chrome — and this is what goes in it.\n *\n * A field with one or two options renders FLAT: inside a panel there is no\n * space to win back, and two labelled checkboxes are faster than a dropdown\n * needing a second click. Past that — or whenever the field asks for a tree or\n * a search — it is the bar's own {@link PillControl}; see `sharesBarControl`.\n */\nimport Checkbox from \"@mui/material/Checkbox/index.js\";\n\nimport { Box } from \"../../../mui/Box\";\nimport { Text } from \"../../typography/Text\";\n\nimport { PillControl } from \"./data-views-category-pill\";\nimport type { OverflowField } from \"./data-views-overflow\";\nimport { RangeBounds } from \"./data-views-range-pill\";\nimport { isRangeSet } from \"./data-views-range-values\";\nimport type { RangeValue } from \"./data-views-types\";\nimport { useDataViewsCopy } from \"./data-views-copy-context\";\n\n/** What each field's control needs, minus the panel's own chrome. */\nexport interface MoreFieldProps {\n pills: Record<string, string[]>;\n ranges: Record<string, RangeValue>;\n onTogglePill: (fieldId: string, value: string, checked: boolean) => void;\n onChangeRange: (fieldId: string, range: RangeValue) => void;\n testIdPrefix: string;\n}\n\n/**\n * Above this many options a field is a DROPDOWN rather than a flat row of\n * checkboxes. Two options cost two lines and read faster laid out; a \"Cliente\"\n * with a dozen turns the panel into a scrolling wall and buries every field\n * under it, which is exactly what the overflow was meant to avoid.\n */\nconst INLINE_OPTION_LIMIT = 2;\n\n/**\n * Whether an overflowed pill keeps the SAME control it has on the bar.\n *\n * The panel used to build its own flat dropdown for every field past two\n * options, so a field's config only held while it fitted: `control:\n * \"category\"` lost its tree (subcategories flattened into one list, no\n * \"Marcar tudo\", no count footer) and `searchEnabled` lost its search, on\n * exactly the phone widths where most filters live in here. Anything the bar\n * would render as a dropdown now renders as the bar's own {@link PillControl};\n * only a plain two-option field — one that did not ask for a dropdown, a tree\n * or a search — stays a flat checkbox row, which is a panel layout rather than\n * a different control (the filter panel draws the same line).\n */\nfunction sharesBarControl<T extends Record<string, unknown>>(field: OverflowField<T>): boolean {\n const pill = field.pill;\n if (!pill) return false;\n return (\n pill.control === \"category\" ||\n pill.control === \"multiselect\" ||\n pill.searchEnabled === true ||\n pill.options.length > INLINE_OPTION_LIMIT\n );\n}\n\n/** One overflowed pill: the bar's control, or its options as checkboxes. */\nfunction OverflowPill<T extends Record<string, unknown>>({\n field,\n values,\n onTogglePill,\n onClear,\n testIdPrefix,\n}: {\n field: OverflowField<T>;\n values: string[];\n onTogglePill: (fieldId: string, value: string, checked: boolean) => void;\n onClear: () => void;\n testIdPrefix: string;\n}): React.JSX.Element {\n const testId = `${testIdPrefix}-more-${field.id}`;\n if (field.pill && sharesBarControl(field)) {\n return (\n <PillControl\n fieldId={field.id}\n pill={field.pill}\n selected={values}\n onTogglePill={onTogglePill}\n onClearField={onClear}\n testIdPrefix={testIdPrefix}\n testId={testId}\n />\n );\n }\n const onToggle = (value: string, checked: boolean) => onTogglePill(field.id, value, checked);\n return (\n <Box sx={{ display: \"flex\", flexWrap: \"wrap\", gap: 0.75 }}>\n {(field.pill?.options ?? []).map((option) => {\n const checked = values.includes(option.value);\n return (\n <Box\n key={option.value}\n component=\"label\"\n data-testid={`${testId}-${option.value}`}\n sx={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 0.25,\n pr: 1,\n border: 1,\n borderStyle: \"solid\",\n borderColor: checked ? \"primary.main\" : \"divider\",\n bgcolor: checked ? \"action.selected\" : \"transparent\",\n borderRadius: 5,\n cursor: \"pointer\",\n fontSize: \"0.8125rem\",\n color: checked ? \"primary.main\" : \"text.secondary\",\n }}\n >\n <Checkbox\n size=\"small\"\n checked={checked}\n onChange={(event) => onToggle(option.value, event.target.checked)}\n inputProps={{ \"aria-label\": `${field.label}: ${option.label}` }}\n />\n {option.label}\n </Box>\n );\n })}\n </Box>\n );\n}\n\n\n/**\n * One overflowed range: its presets and its two bounds, as the same controls\n * the pill uses.\n *\n * The whole control DELEGATES to {@link RangeBounds} rather than being built\n * here, which is the point — this panel used to render a raw\n * `<input type=\"date\">`, so the masked `dd/mm/aaaa` field existed only while\n * the filter FITTED on the bar. The moment \"Data\" overflowed it reverted to the\n * native control the mask replaced, and a merchant on a narrow screen never saw\n * the fix at all (FUT-744). `Valor` had the twin bug: a bare `type=\"number\"`\n * plus `Number(raw)` dropped the decimal comma this panel is meant to accept.\n *\n * That also retires the intrinsic-width workaround this pair used to need — a\n * native date input reports a wide minimum (its own mask plus the picker\n * glyph), which is what made two of them refuse to shrink and scrolled the\n * panel sideways. A text input has no such minimum.\n *\n * `RangeBounds` renders the preset chips ITSELF, above the inputs. This panel\n * must NOT render its own row as well: when the delegation above landed, the\n * chips it used to draw by hand stayed behind, and \"Data\" showed Hoje/Ontem/\n * Esta semana/Este mês/Este ano twice — two rows, duplicated test ids, and half\n * the panel's height spent saying the same thing (FUT-751).\n */\nfunction OverflowRange<T extends Record<string, unknown>>({\n field,\n value,\n onChange,\n testIdPrefix,\n}: {\n field: OverflowField<T>;\n value: RangeValue;\n onChange: (range: RangeValue) => void;\n testIdPrefix: string;\n}): React.JSX.Element | null {\n // `group === \"range\"` is what selects this component, so `range` is always\n // set; the guard is for the type, not for a state the caller can reach.\n if (!field.range) return null;\n return (\n <RangeBounds\n field={field.range}\n value={value}\n onChange={onChange}\n testId={`${testIdPrefix}-more-${field.id}`}\n />\n );\n}\n\n/**\n * Whether a field has anything applied, and how to unapply it — the two shapes\n * (a pill's selected values, a range's bounds) answered in one place so the\n * group that renders them stays a renderer.\n */\nexport function fieldClearing<T extends Record<string, unknown>>({\n field,\n pills,\n ranges,\n onTogglePill,\n onChangeRange,\n}: {\n field: OverflowField<T>;\n} & Pick<MoreFieldProps, \"pills\" | \"ranges\" | \"onTogglePill\" | \"onChangeRange\">): {\n applied: boolean;\n clear: () => void;\n} {\n if (field.group === \"range\") {\n return {\n applied: isRangeSet(ranges[field.id] ?? {}),\n clear: () => onChangeRange(field.id, {}),\n };\n }\n const values = pills[field.id] ?? [];\n return {\n applied: values.length > 0,\n clear: () => values.forEach((value) => onTogglePill(field.id, value, false)),\n };\n}\n\n\n/** One labelled group in the panel: the field's name, then its control. */\nexport function MoreGroup<T extends Record<string, unknown>>({\n field,\n pills,\n ranges,\n onTogglePill,\n onChangeRange,\n testIdPrefix,\n}: {\n field: OverflowField<T>;\n} & MoreFieldProps): React.JSX.Element {\n const copy = useDataViewsCopy();\n const { applied, clear } = fieldClearing({ field, pills, ranges, onTogglePill, onChangeRange });\n return (\n <Box sx={{ mb: 1.5, \"&:last-of-type\": { mb: 0 } }}>\n <Box sx={{ display: \"flex\", alignItems: \"center\", gap: 1, mb: 0.5 }}>\n <Text variant=\"caption\" as=\"span\">\n <Box component=\"span\" sx={{ color: \"text.secondary\" }}>\n {field.label}\n {field.group === \"range\" && isRangeSet(ranges[field.id] ?? {}) ? \" •\" : \"\"}\n </Box>\n </Text>\n {/* The panel's equivalent of the pill's ✕. Without it a field applied\n in here could only be cleared by finding it again on the bar —\n which is where it goes the moment it becomes active, so the\n operator has to close this panel to undo what they just did. */}\n {applied && (\n <Box\n component=\"button\"\n type=\"button\"\n onClick={clear}\n data-testid={`${testIdPrefix}-more-${field.id}-clear`}\n sx={{\n ml: \"auto\",\n border: 0,\n p: 0,\n bgcolor: \"transparent\",\n cursor: \"pointer\",\n font: \"inherit\",\n fontSize: \"0.75rem\",\n color: \"primary.main\",\n \"&:hover\": { textDecoration: \"underline\" },\n }}\n >\n {copy.filters.clear}\n </Box>\n )}\n </Box>\n {field.group === \"pill\" ? (\n <OverflowPill\n field={field}\n values={pills[field.id] ?? []}\n onTogglePill={onTogglePill}\n onClear={() => (pills[field.id] ?? []).forEach((v) => onTogglePill(field.id, v, false))}\n testIdPrefix={testIdPrefix}\n />\n ) : (\n <OverflowRange\n field={field}\n value={ranges[field.id] ?? {}}\n onChange={(range) => onChangeRange(field.id, range)}\n testIdPrefix={testIdPrefix}\n />\n )}\n </Box>\n );\n}\n\n"],"mappings":"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","names":["default"]}
@@ -3,11 +3,11 @@ import {
3
3
  } from "../chunk-K5V3KCFI.js";
4
4
  import {
5
5
  DataViewsTableBase
6
- } from "../chunk-JQL4GG5L.js";
6
+ } from "../chunk-LBLX3Q2C.js";
7
7
  import "../chunk-MSS6IU5X.js";
8
8
  import {
9
9
  DataViewsGrid
10
- } from "../chunk-KUJLZFDW.js";
10
+ } from "../chunk-BTKMGXAK.js";
11
11
  import {
12
12
  BaseListCard
13
13
  } from "../chunk-7IKWIWWV.js";
@@ -22,18 +22,18 @@ import {
22
22
  DropIndicator,
23
23
  useDragItem
24
24
  } from "../chunk-JCJGJX7V.js";
25
- import "../chunk-VEGT5PAD.js";
25
+ import "../chunk-ALEITBJX.js";
26
26
  import "../chunk-6PKVHFCK.js";
27
27
  import {
28
28
  DataViewsBoard
29
29
  } from "../chunk-VKH7AENA.js";
30
- import "../chunk-VNGYJXAU.js";
30
+ import "../chunk-DH5OA4VK.js";
31
31
  import "../chunk-4XVH6IWN.js";
32
- import "../chunk-CASZGBCA.js";
32
+ import "../chunk-PZAXUO6F.js";
33
33
  import "../chunk-5WNQJ5KS.js";
34
- import "../chunk-I3FXTIKA.js";
35
- import "../chunk-6FUOUUYO.js";
36
- import "../chunk-EZMCWRXO.js";
34
+ import "../chunk-J2UZOMTA.js";
35
+ import "../chunk-ZJ66D63E.js";
36
+ import "../chunk-D5GCWSGS.js";
37
37
  import "../chunk-UC6A6ASM.js";
38
38
  import "../chunk-DFLTUI7W.js";
39
39
  import "../chunk-FV36LFPX.js";
@@ -41,7 +41,7 @@ import "../chunk-GCZJH4XL.js";
41
41
  import "../chunk-F4RR4666.js";
42
42
  import "../chunk-CBOB5AV6.js";
43
43
  import "../chunk-HP2ODXNA.js";
44
- import "../chunk-TQ6FPOPD.js";
44
+ import "../chunk-TPKSOHB5.js";
45
45
  import "../chunk-IAGOUTI6.js";
46
46
  import "../chunk-KX75HM5U.js";
47
47
  import "../chunk-FGUK3D54.js";
@@ -16,6 +16,11 @@ interface PillControlProps<T extends Record<string, unknown>> {
16
16
  onClearField: (fieldId: string) => void;
17
17
  onOpenChange?: (open: boolean) => void;
18
18
  testIdPrefix: string;
19
+ /**
20
+ * Overrides the `<prefix>-filter-<id>` test id — the "Mais" panel keys its
21
+ * fields `<prefix>-more-<id>` so a spec can tell which surface it drove.
22
+ */
23
+ testId?: string;
19
24
  /** `stacked` in the filter panel, `pill` on the inline bar. */
20
25
  layout?: "stacked" | "pill";
21
26
  }
@@ -32,6 +37,6 @@ interface PillControlProps<T extends Record<string, unknown>> {
32
37
  * wants "the whole category" as one click, while one whose parents are pure
33
38
  * grouping would only offer a tick that means nothing.
34
39
  */
35
- export declare function PillControl<T extends Record<string, unknown>>({ fieldId, pill, selected, onTogglePill, onClearField, onOpenChange, testIdPrefix, layout, }: PillControlProps<T>): React.JSX.Element;
40
+ export declare function PillControl<T extends Record<string, unknown>>({ fieldId, pill, selected, onTogglePill, onClearField, onOpenChange, testIdPrefix, testId, layout, }: PillControlProps<T>): React.JSX.Element;
36
41
  export {};
37
42
  //# sourceMappingURL=data-views-category-pill.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"data-views-category-pill.d.ts","sourceRoot":"","sources":["../../../../../src/components/data-display/DataViews/data-views-category-pill.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAgB,MAAM,oBAAoB,CAAC;AAE1E;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GACvE,IAAI,CASN;AASD,UAAU,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACzE,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC7D,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,MAAe,GAChB,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAqCzC"}
1
+ {"version":3,"file":"data-views-category-pill.d.ts","sourceRoot":"","sources":["../../../../../src/components/data-display/DataViews/data-views-category-pill.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAgB,MAAM,oBAAoB,CAAC;AAE1E;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GACvE,IAAI,CASN;AASD,UAAU,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACzE,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC7D,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,MAA4C,EAC5C,MAAe,GAChB,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAoCzC"}
@@ -8,17 +8,6 @@ export interface MoreFieldProps {
8
8
  onChangeRange: (fieldId: string, range: RangeValue) => void;
9
9
  testIdPrefix: string;
10
10
  }
11
- /**
12
- * The trigger, badged with how many fields had no room on the bar — and told
13
- * apart when some of them are APPLIED.
14
- *
15
- * An applied filter can land in here now (it is ranked first, not exempt), so
16
- * this button is the only thing on screen still saying it exists. A neutral
17
- * badge reading "3" would make "three filters you have not used" and "three
18
- * filters narrowing this list" look identical, which is the whole failure the
19
- * old exemption was written to avoid. So an overflow holding applied filters
20
- * takes the applied tone and counts them in its own badge.
21
-
22
11
  /**
23
12
  * Whether a field has anything applied, and how to unapply it — the two shapes
24
13
  * (a pill's selected values, a range's bounds) answered in one place so the
@@ -1 +1 @@
1
- {"version":3,"file":"data-views-more-fields.d.ts","sourceRoot":"","sources":["../../../../../src/components/data-display/DataViews/data-views-more-fields.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAG3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrD,qEAAqE;AACrE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACnC,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACzE,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAC5D,YAAY,EAAE,MAAM,CAAC;CACtB;AAoID;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC/D,KAAK,EACL,KAAK,EACL,MAAM,EACN,YAAY,EACZ,aAAa,GACd,EAAE;IACD,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;CACzB,GAAG,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,QAAQ,GAAG,cAAc,GAAG,eAAe,CAAC,GAAG;IAChF,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAYA;AAGD,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC3D,KAAK,EACL,KAAK,EACL,MAAM,EACN,YAAY,EACZ,aAAa,EACb,YAAY,GACb,EAAE;IACD,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;CACzB,GAAG,cAAc,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAwDrC"}
1
+ {"version":3,"file":"data-views-more-fields.d.ts","sourceRoot":"","sources":["../../../../../src/components/data-display/DataViews/data-views-more-fields.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAG3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrD,qEAAqE;AACrE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACnC,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACzE,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAC5D,YAAY,EAAE,MAAM,CAAC;CACtB;AAqJD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC/D,KAAK,EACL,KAAK,EACL,MAAM,EACN,YAAY,EACZ,aAAa,GACd,EAAE;IACD,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;CACzB,GAAG,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,QAAQ,GAAG,cAAc,GAAG,eAAe,CAAC,GAAG;IAChF,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAYA;AAGD,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC3D,KAAK,EACL,KAAK,EACL,MAAM,EACN,YAAY,EACZ,aAAa,EACb,YAAY,GACb,EAAE;IACD,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;CACzB,GAAG,cAAc,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAwDrC"}
@@ -1 +1 @@
1
- {"version":3,"file":"data-views-overflow.d.ts","sourceRoot":"","sources":["../../../../../src/components/data-display/DataViews/data-views-overflow.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE1F;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,2EAA2E;AAC3E,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC9D,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,IAAI,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAC5B,KAAK,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;CAC7B;AAED,mEAAmE;AACnE,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC9D,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3B,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7B;;;OAGG;IACH,eAAe,EAAE,OAAO,CAAC;IACzB;;;;;;;OAOG;IACH,aAAa,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,eAAe,EAAE,OAAO,CAAC;IACzB;;;;;;OAMG;IACH,cAAc,EAAE,OAAO,CAAC;IACxB;;;;;;OAMG;IACH,cAAc,EAAE,OAAO,CAAC;IACxB,gDAAgD;IAChD,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;CAChD;AAED,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChE,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAC9B,WAAW,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,GACjC,aAAa,CAAC,CAAC,CAAC,EAAE,CAKpB;AAoMD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjE,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,EACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC;AAClC;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAQ;AACd,iEAAiE;AACjE,SAAS,UAAO,GACf,aAAa,CAAC,CAAC,CAAC,CAmBlB"}
1
+ {"version":3,"file":"data-views-overflow.d.ts","sourceRoot":"","sources":["../../../../../src/components/data-display/DataViews/data-views-overflow.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE1F;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,2EAA2E;AAC3E,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC9D,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,IAAI,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAC5B,KAAK,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;CAC7B;AAED,mEAAmE;AACnE,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC9D,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3B,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7B;;;OAGG;IACH,eAAe,EAAE,OAAO,CAAC;IACzB;;;;;;;OAOG;IACH,aAAa,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,eAAe,EAAE,OAAO,CAAC;IACzB;;;;;;OAMG;IACH,cAAc,EAAE,OAAO,CAAC;IACxB;;;;;;OAMG;IACH,cAAc,EAAE,OAAO,CAAC;IACxB,gDAAgD;IAChD,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;CAChD;AAED,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChE,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAC9B,WAAW,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,GACjC,aAAa,CAAC,CAAC,CAAC,EAAE,CAKpB;AAoMD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjE,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,EACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC;AAClC;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAQ;AACd,iEAAiE;AACjE,SAAS,UAAO,GACf,aAAa,CAAC,CAAC,CAAC,CA8BlB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@12-apps/ui",
3
- "version": "6.30.1",
3
+ "version": "6.30.2",
4
4
  "license": "MIT",
5
5
  "packageManager": "pnpm@10.34.5",
6
6
  "type": "module",
@@ -45,6 +45,11 @@ interface PillControlProps<T extends Record<string, unknown>> {
45
45
  onClearField: (fieldId: string) => void;
46
46
  onOpenChange?: (open: boolean) => void;
47
47
  testIdPrefix: string;
48
+ /**
49
+ * Overrides the `<prefix>-filter-<id>` test id — the "Mais" panel keys its
50
+ * fields `<prefix>-more-<id>` so a spec can tell which surface it drove.
51
+ */
52
+ testId?: string;
48
53
  /** `stacked` in the filter panel, `pill` on the inline bar. */
49
54
  layout?: "stacked" | "pill";
50
55
  }
@@ -70,10 +75,10 @@ export function PillControl<T extends Record<string, unknown>>({
70
75
  onClearField,
71
76
  onOpenChange,
72
77
  testIdPrefix,
78
+ testId = `${testIdPrefix}-filter-${fieldId}`,
73
79
  layout = "pill",
74
80
  }: PillControlProps<T>): React.JSX.Element {
75
81
  const copy = useDataViewsCopy();
76
- const testId = `${testIdPrefix}-filter-${fieldId}`;
77
82
  if (pill.control === "category") {
78
83
  return (
79
84
  <CategorySelect
@@ -9,15 +9,15 @@
9
9
  *
10
10
  * A field with one or two options renders FLAT: inside a panel there is no
11
11
  * space to win back, and two labelled checkboxes are faster than a dropdown
12
- * needing a second click. Past that it becomes a {@link MultiSelectDropdown} —
13
- * see `INLINE_OPTION_LIMIT`.
12
+ * needing a second click. Past that — or whenever the field asks for a tree or
13
+ * a search — it is the bar's own {@link PillControl}; see `sharesBarControl`.
14
14
  */
15
15
  import Checkbox from "@mui/material/Checkbox/index.js";
16
16
 
17
- import { MultiSelectDropdown } from "../../layout/ContentToolbar";
18
17
  import { Box } from "../../../mui/Box";
19
18
  import { Text } from "../../typography/Text";
20
19
 
20
+ import { PillControl } from "./data-views-category-pill";
21
21
  import type { OverflowField } from "./data-views-overflow";
22
22
  import { RangeBounds } from "./data-views-range-pill";
23
23
  import { isRangeSet } from "./data-views-range-values";
@@ -41,42 +41,59 @@ export interface MoreFieldProps {
41
41
  */
42
42
  const INLINE_OPTION_LIMIT = 2;
43
43
 
44
- /** One overflowed pill: its options as checkboxes, all visible at once. */
44
+ /**
45
+ * Whether an overflowed pill keeps the SAME control it has on the bar.
46
+ *
47
+ * The panel used to build its own flat dropdown for every field past two
48
+ * options, so a field's config only held while it fitted: `control:
49
+ * "category"` lost its tree (subcategories flattened into one list, no
50
+ * "Marcar tudo", no count footer) and `searchEnabled` lost its search, on
51
+ * exactly the phone widths where most filters live in here. Anything the bar
52
+ * would render as a dropdown now renders as the bar's own {@link PillControl};
53
+ * only a plain two-option field — one that did not ask for a dropdown, a tree
54
+ * or a search — stays a flat checkbox row, which is a panel layout rather than
55
+ * a different control (the filter panel draws the same line).
56
+ */
57
+ function sharesBarControl<T extends Record<string, unknown>>(field: OverflowField<T>): boolean {
58
+ const pill = field.pill;
59
+ if (!pill) return false;
60
+ return (
61
+ pill.control === "category" ||
62
+ pill.control === "multiselect" ||
63
+ pill.searchEnabled === true ||
64
+ pill.options.length > INLINE_OPTION_LIMIT
65
+ );
66
+ }
67
+
68
+ /** One overflowed pill: the bar's control, or its options as checkboxes. */
45
69
  function OverflowPill<T extends Record<string, unknown>>({
46
70
  field,
47
71
  values,
48
- onToggle,
72
+ onTogglePill,
49
73
  onClear,
50
74
  testIdPrefix,
51
75
  }: {
52
76
  field: OverflowField<T>;
53
77
  values: string[];
54
- onToggle: (value: string, checked: boolean) => void;
78
+ onTogglePill: (fieldId: string, value: string, checked: boolean) => void;
55
79
  onClear: () => void;
56
80
  testIdPrefix: string;
57
81
  }): React.JSX.Element {
58
- const copy = useDataViewsCopy();
59
- const options = field.pill?.options ?? [];
60
- if (options.length > INLINE_OPTION_LIMIT) {
82
+ const testId = `${testIdPrefix}-more-${field.id}`;
83
+ if (field.pill && sharesBarControl(field)) {
61
84
  return (
62
- <MultiSelectDropdown
63
- extraOptionsHeading={copy.filters.optionsHeading}
64
- clearText={copy.filters.clear}
65
- clearLabel={copy.filters.clearRange(field.label)}
66
- label={field.pill?.label ?? field.label}
67
- options={options}
68
- selected={new Set(values)}
69
- onToggle={onToggle}
70
- onClear={onClear}
71
- allLabel={copy.filters.allOption}
72
- searchable={options.length > 6 ? true : undefined}
73
- searchPlaceholder={copy.filters.optionSearchPlaceholder}
74
- noResultsLabel={copy.filters.optionsEmpty}
75
- layout="pill"
76
- data-testid={`${testIdPrefix}-more-${field.id}`}
85
+ <PillControl
86
+ fieldId={field.id}
87
+ pill={field.pill}
88
+ selected={values}
89
+ onTogglePill={onTogglePill}
90
+ onClearField={onClear}
91
+ testIdPrefix={testIdPrefix}
92
+ testId={testId}
77
93
  />
78
94
  );
79
95
  }
96
+ const onToggle = (value: string, checked: boolean) => onTogglePill(field.id, value, checked);
80
97
  return (
81
98
  <Box sx={{ display: "flex", flexWrap: "wrap", gap: 0.75 }}>
82
99
  {(field.pill?.options ?? []).map((option) => {
@@ -85,7 +102,7 @@ function OverflowPill<T extends Record<string, unknown>>({
85
102
  <Box
86
103
  key={option.value}
87
104
  component="label"
88
- data-testid={`${testIdPrefix}-more-${field.id}-${option.value}`}
105
+ data-testid={`${testId}-${option.value}`}
89
106
  sx={{
90
107
  display: "inline-flex",
91
108
  alignItems: "center",
@@ -163,17 +180,6 @@ function OverflowRange<T extends Record<string, unknown>>({
163
180
  );
164
181
  }
165
182
 
166
- /**
167
- * The trigger, badged with how many fields had no room on the bar — and told
168
- * apart when some of them are APPLIED.
169
- *
170
- * An applied filter can land in here now (it is ranked first, not exempt), so
171
- * this button is the only thing on screen still saying it exists. A neutral
172
- * badge reading "3" would make "three filters you have not used" and "three
173
- * filters narrowing this list" look identical, which is the whole failure the
174
- * old exemption was written to avoid. So an overflow holding applied filters
175
- * takes the applied tone and counts them in its own badge.
176
-
177
183
  /**
178
184
  * Whether a field has anything applied, and how to unapply it — the two shapes
179
185
  * (a pill's selected values, a range's bounds) answered in one place so the
@@ -257,7 +263,7 @@ export function MoreGroup<T extends Record<string, unknown>>({
257
263
  <OverflowPill
258
264
  field={field}
259
265
  values={pills[field.id] ?? []}
260
- onToggle={(value, checked) => onTogglePill(field.id, value, checked)}
266
+ onTogglePill={onTogglePill}
261
267
  onClear={() => (pills[field.id] ?? []).forEach((v) => onTogglePill(field.id, v, false))}
262
268
  testIdPrefix={testIdPrefix}
263
269
  />
@@ -347,5 +347,16 @@ export function useFilterOverflow<T extends Record<string, unknown>>(
347
347
  if (cache.current === null || (!frozen && cache.current.signature !== signature)) {
348
348
  cache.current = { signature, split: computeSplit(all, pills, ranges, width, hasExport) };
349
349
  }
350
- return { ...cache.current.split, barRef };
350
+ // The cache holds the ARRANGEMENT — which ids sit on the bar, which in "Mais"
351
+ // — never the fields themselves. The signature keys on ids, so a field whose
352
+ // options arrive after the first measurement (a category list still loading)
353
+ // does not re-split, and handing back the cached objects served the empty
354
+ // list for good: "Categoria" in "Mais" rendered a label with no control under
355
+ // it (FUT-2828). Re-reading each field from `all` keeps the slots and the
356
+ // current config.
357
+ const { split } = cache.current;
358
+ const current = new Map(all.map((field) => [field.id, field]));
359
+ const fresh = (fields: OverflowField<T>[]): OverflowField<T>[] =>
360
+ fields.map((field) => current.get(field.id) ?? field);
361
+ return { ...split, inline: fresh(split.inline), overflow: fresh(split.overflow), barRef };
351
362
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/data-display/DataViews/data-views-more-fields.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * ONE FIELD, RENDERED INSIDE THE \"MAIS\" PANEL.\n *\n * Split from `data-views-more-filters` at the file-size gate, along the seam\n * that was already there: that module is the trigger, the panel and its\n * footer — the chrome — and this is what goes in it.\n *\n * A field with one or two options renders FLAT: inside a panel there is no\n * space to win back, and two labelled checkboxes are faster than a dropdown\n * needing a second click. Past that it becomes a {@link MultiSelectDropdown} —\n * see `INLINE_OPTION_LIMIT`.\n */\nimport Checkbox from \"@mui/material/Checkbox/index.js\";\n\nimport { MultiSelectDropdown } from \"../../layout/ContentToolbar\";\nimport { Box } from \"../../../mui/Box\";\nimport { Text } from \"../../typography/Text\";\n\nimport type { OverflowField } from \"./data-views-overflow\";\nimport { RangeBounds } from \"./data-views-range-pill\";\nimport { isRangeSet } from \"./data-views-range-values\";\nimport type { RangeValue } from \"./data-views-types\";\nimport { useDataViewsCopy } from \"./data-views-copy-context\";\n\n/** What each field's control needs, minus the panel's own chrome. */\nexport interface MoreFieldProps {\n pills: Record<string, string[]>;\n ranges: Record<string, RangeValue>;\n onTogglePill: (fieldId: string, value: string, checked: boolean) => void;\n onChangeRange: (fieldId: string, range: RangeValue) => void;\n testIdPrefix: string;\n}\n\n/**\n * Above this many options a field is a DROPDOWN rather than a flat row of\n * checkboxes. Two options cost two lines and read faster laid out; a \"Cliente\"\n * with a dozen turns the panel into a scrolling wall and buries every field\n * under it, which is exactly what the overflow was meant to avoid.\n */\nconst INLINE_OPTION_LIMIT = 2;\n\n/** One overflowed pill: its options as checkboxes, all visible at once. */\nfunction OverflowPill<T extends Record<string, unknown>>({\n field,\n values,\n onToggle,\n onClear,\n testIdPrefix,\n}: {\n field: OverflowField<T>;\n values: string[];\n onToggle: (value: string, checked: boolean) => void;\n onClear: () => void;\n testIdPrefix: string;\n}): React.JSX.Element {\n const copy = useDataViewsCopy();\n const options = field.pill?.options ?? [];\n if (options.length > INLINE_OPTION_LIMIT) {\n return (\n <MultiSelectDropdown\n extraOptionsHeading={copy.filters.optionsHeading}\n clearText={copy.filters.clear}\n clearLabel={copy.filters.clearRange(field.label)}\n label={field.pill?.label ?? field.label}\n options={options}\n selected={new Set(values)}\n onToggle={onToggle}\n onClear={onClear}\n allLabel={copy.filters.allOption}\n searchable={options.length > 6 ? true : undefined}\n searchPlaceholder={copy.filters.optionSearchPlaceholder}\n noResultsLabel={copy.filters.optionsEmpty}\n layout=\"pill\"\n data-testid={`${testIdPrefix}-more-${field.id}`}\n />\n );\n }\n return (\n <Box sx={{ display: \"flex\", flexWrap: \"wrap\", gap: 0.75 }}>\n {(field.pill?.options ?? []).map((option) => {\n const checked = values.includes(option.value);\n return (\n <Box\n key={option.value}\n component=\"label\"\n data-testid={`${testIdPrefix}-more-${field.id}-${option.value}`}\n sx={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 0.25,\n pr: 1,\n border: 1,\n borderStyle: \"solid\",\n borderColor: checked ? \"primary.main\" : \"divider\",\n bgcolor: checked ? \"action.selected\" : \"transparent\",\n borderRadius: 5,\n cursor: \"pointer\",\n fontSize: \"0.8125rem\",\n color: checked ? \"primary.main\" : \"text.secondary\",\n }}\n >\n <Checkbox\n size=\"small\"\n checked={checked}\n onChange={(event) => onToggle(option.value, event.target.checked)}\n inputProps={{ \"aria-label\": `${field.label}: ${option.label}` }}\n />\n {option.label}\n </Box>\n );\n })}\n </Box>\n );\n}\n\n\n/**\n * One overflowed range: its presets and its two bounds, as the same controls\n * the pill uses.\n *\n * The whole control DELEGATES to {@link RangeBounds} rather than being built\n * here, which is the point — this panel used to render a raw\n * `<input type=\"date\">`, so the masked `dd/mm/aaaa` field existed only while\n * the filter FITTED on the bar. The moment \"Data\" overflowed it reverted to the\n * native control the mask replaced, and a merchant on a narrow screen never saw\n * the fix at all (FUT-744). `Valor` had the twin bug: a bare `type=\"number\"`\n * plus `Number(raw)` dropped the decimal comma this panel is meant to accept.\n *\n * That also retires the intrinsic-width workaround this pair used to need — a\n * native date input reports a wide minimum (its own mask plus the picker\n * glyph), which is what made two of them refuse to shrink and scrolled the\n * panel sideways. A text input has no such minimum.\n *\n * `RangeBounds` renders the preset chips ITSELF, above the inputs. This panel\n * must NOT render its own row as well: when the delegation above landed, the\n * chips it used to draw by hand stayed behind, and \"Data\" showed Hoje/Ontem/\n * Esta semana/Este mês/Este ano twice — two rows, duplicated test ids, and half\n * the panel's height spent saying the same thing (FUT-751).\n */\nfunction OverflowRange<T extends Record<string, unknown>>({\n field,\n value,\n onChange,\n testIdPrefix,\n}: {\n field: OverflowField<T>;\n value: RangeValue;\n onChange: (range: RangeValue) => void;\n testIdPrefix: string;\n}): React.JSX.Element | null {\n // `group === \"range\"` is what selects this component, so `range` is always\n // set; the guard is for the type, not for a state the caller can reach.\n if (!field.range) return null;\n return (\n <RangeBounds\n field={field.range}\n value={value}\n onChange={onChange}\n testId={`${testIdPrefix}-more-${field.id}`}\n />\n );\n}\n\n/**\n * The trigger, badged with how many fields had no room on the bar — and told\n * apart when some of them are APPLIED.\n *\n * An applied filter can land in here now (it is ranked first, not exempt), so\n * this button is the only thing on screen still saying it exists. A neutral\n * badge reading \"3\" would make \"three filters you have not used\" and \"three\n * filters narrowing this list\" look identical, which is the whole failure the\n * old exemption was written to avoid. So an overflow holding applied filters\n * takes the applied tone and counts them in its own badge.\n\n/**\n * Whether a field has anything applied, and how to unapply it — the two shapes\n * (a pill's selected values, a range's bounds) answered in one place so the\n * group that renders them stays a renderer.\n */\nexport function fieldClearing<T extends Record<string, unknown>>({\n field,\n pills,\n ranges,\n onTogglePill,\n onChangeRange,\n}: {\n field: OverflowField<T>;\n} & Pick<MoreFieldProps, \"pills\" | \"ranges\" | \"onTogglePill\" | \"onChangeRange\">): {\n applied: boolean;\n clear: () => void;\n} {\n if (field.group === \"range\") {\n return {\n applied: isRangeSet(ranges[field.id] ?? {}),\n clear: () => onChangeRange(field.id, {}),\n };\n }\n const values = pills[field.id] ?? [];\n return {\n applied: values.length > 0,\n clear: () => values.forEach((value) => onTogglePill(field.id, value, false)),\n };\n}\n\n\n/** One labelled group in the panel: the field's name, then its control. */\nexport function MoreGroup<T extends Record<string, unknown>>({\n field,\n pills,\n ranges,\n onTogglePill,\n onChangeRange,\n testIdPrefix,\n}: {\n field: OverflowField<T>;\n} & MoreFieldProps): React.JSX.Element {\n const copy = useDataViewsCopy();\n const { applied, clear } = fieldClearing({ field, pills, ranges, onTogglePill, onChangeRange });\n return (\n <Box sx={{ mb: 1.5, \"&:last-of-type\": { mb: 0 } }}>\n <Box sx={{ display: \"flex\", alignItems: \"center\", gap: 1, mb: 0.5 }}>\n <Text variant=\"caption\" as=\"span\">\n <Box component=\"span\" sx={{ color: \"text.secondary\" }}>\n {field.label}\n {field.group === \"range\" && isRangeSet(ranges[field.id] ?? {}) ? \" •\" : \"\"}\n </Box>\n </Text>\n {/* The panel's equivalent of the pill's ✕. Without it a field applied\n in here could only be cleared by finding it again on the bar —\n which is where it goes the moment it becomes active, so the\n operator has to close this panel to undo what they just did. */}\n {applied && (\n <Box\n component=\"button\"\n type=\"button\"\n onClick={clear}\n data-testid={`${testIdPrefix}-more-${field.id}-clear`}\n sx={{\n ml: \"auto\",\n border: 0,\n p: 0,\n bgcolor: \"transparent\",\n cursor: \"pointer\",\n font: \"inherit\",\n fontSize: \"0.75rem\",\n color: \"primary.main\",\n \"&:hover\": { textDecoration: \"underline\" },\n }}\n >\n {copy.filters.clear}\n </Box>\n )}\n </Box>\n {field.group === \"pill\" ? (\n <OverflowPill\n field={field}\n values={pills[field.id] ?? []}\n onToggle={(value, checked) => onTogglePill(field.id, value, checked)}\n onClear={() => (pills[field.id] ?? []).forEach((v) => onTogglePill(field.id, v, false))}\n testIdPrefix={testIdPrefix}\n />\n ) : (\n <OverflowRange\n field={field}\n value={ranges[field.id] ?? {}}\n onChange={(range) => onChangeRange(field.id, range)}\n testIdPrefix={testIdPrefix}\n />\n )}\n </Box>\n );\n}\n\n"],"mappings":"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","names":["default"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/data-display/DataViews/data-views-category-pill.tsx"],"sourcesContent":["\"use client\";\n\nimport { useDataViewsCopy } from \"./data-views-copy-context\";\nimport { CategorySelect } from \"../../form/CategorySelect\";\nimport { MultiSelectDropdown } from \"../../layout/ContentToolbar\";\n\nimport type { FilterFieldConfig, FilterOption } from \"./data-views-types\";\n\n/**\n * Diff a whole-array selection back into per-value toggles.\n *\n * The filter state's only channel is `onTogglePill(field, value, checked)`, but\n * a tree hands back the entire selection at once. Diffing here keeps that one\n * channel the single way a pill ever changes, rather than giving the\n * hierarchical control a private path into the state.\n */\nexport function emitPillDiff(\n fieldId: string,\n before: readonly string[],\n after: readonly string[],\n onTogglePill: (fieldId: string, value: string, checked: boolean) => void,\n): void {\n const had = new Set(before);\n const wants = new Set(after);\n after.forEach((value) => {\n if (!had.has(value)) onTogglePill(fieldId, value, true);\n });\n before.forEach((value) => {\n if (!wants.has(value)) onTogglePill(fieldId, value, false);\n });\n}\n\n/** A filter option as the category tree wants it. */\nconst toCategoryOption = (option: FilterOption) => ({\n id: option.value,\n name: option.label,\n parentId: option.parentId ?? null,\n});\n\ninterface PillControlProps<T extends Record<string, unknown>> {\n fieldId: string;\n pill: FilterFieldConfig<T>;\n selected: string[];\n onTogglePill: (fieldId: string, value: string, checked: boolean) => void;\n onClearField: (fieldId: string) => void;\n onOpenChange?: (open: boolean) => void;\n testIdPrefix: string;\n /** `stacked` in the filter panel, `pill` on the inline bar. */\n layout?: \"stacked\" | \"pill\";\n}\n\n/**\n * One filter pill: the hierarchical category tree, or the flat multi-select.\n *\n * A category set nests, and flattening it into one list is what made \"Massas\"\n * (mercearia) indistinguishable from \"Massas\" (pratos principais). `control:\n * \"category\"` opts a field into the tree, which shows each hit under its parent.\n *\n * {@link FilterFieldConfig.allowParentSelection} decides whether a parent row is\n * itself tickable. It is forwarded rather than fixed here because it is a\n * per-SCREEN question: a filter over a catalogue where products sit on leaves\n * wants \"the whole category\" as one click, while one whose parents are pure\n * grouping would only offer a tick that means nothing.\n */\nexport function PillControl<T extends Record<string, unknown>>({\n fieldId,\n pill,\n selected,\n onTogglePill,\n onClearField,\n onOpenChange,\n testIdPrefix,\n layout = \"pill\",\n}: PillControlProps<T>): React.JSX.Element {\n const copy = useDataViewsCopy();\n const testId = `${testIdPrefix}-filter-${fieldId}`;\n if (pill.control === \"category\") {\n return (\n <CategorySelect\n copy={copy.categorySelect}\n placeholder={pill.label}\n label={layout === \"stacked\" ? pill.label : undefined}\n fullWidth={layout === \"stacked\"}\n options={pill.options.map(toCategoryOption)}\n allowParentSelection={pill.allowParentSelection ?? false}\n value={selected}\n onChange={(next) => emitPillDiff(fieldId, selected, next, onTogglePill)}\n dataTestId={testId}\n />\n );\n }\n return (\n <MultiSelectDropdown\n extraOptionsHeading={copy.filters.optionsHeading}\n clearText={copy.filters.clear}\n clearLabel={copy.filters.clearRange(pill.label)}\n label={pill.label}\n options={pill.options}\n selected={new Set(selected)}\n onToggle={(value, checked) => onTogglePill(fieldId, value, checked)}\n onClear={() => onClearField(fieldId)}\n allLabel={copy.filters.allOption}\n searchable={pill.searchEnabled ? true : undefined}\n searchPlaceholder={copy.filters.optionSearchPlaceholder}\n noResultsLabel={copy.filters.optionsEmpty}\n layout={layout}\n onOpenChange={onOpenChange}\n data-testid={testId}\n />\n );\n}\n"],"mappings":";;;;;;;;;;;AA8EM;AA9DC,SAAS,aACd,SACA,QACA,OACA,cACM;AACN,QAAM,MAAM,IAAI,IAAI,MAAM;AAC1B,QAAM,QAAQ,IAAI,IAAI,KAAK;AAC3B,QAAM,QAAQ,CAAC,UAAU;AACvB,QAAI,CAAC,IAAI,IAAI,KAAK,EAAG,cAAa,SAAS,OAAO,IAAI;AAAA,EACxD,CAAC;AACD,SAAO,QAAQ,CAAC,UAAU;AACxB,QAAI,CAAC,MAAM,IAAI,KAAK,EAAG,cAAa,SAAS,OAAO,KAAK;AAAA,EAC3D,CAAC;AACH;AAGA,IAAM,mBAAmB,CAAC,YAA0B;AAAA,EAClD,IAAI,OAAO;AAAA,EACX,MAAM,OAAO;AAAA,EACb,UAAU,OAAO,YAAY;AAC/B;AA2BO,SAAS,YAA+C;AAAA,EAC7D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS;AACX,GAA2C;AACzC,QAAM,OAAO,iBAAiB;AAC9B,QAAM,SAAS,GAAG,YAAY,WAAW,OAAO;AAChD,MAAI,KAAK,YAAY,YAAY;AAC/B,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,KAAK;AAAA,QACX,aAAa,KAAK;AAAA,QAClB,OAAO,WAAW,YAAY,KAAK,QAAQ;AAAA,QAC3C,WAAW,WAAW;AAAA,QACtB,SAAS,KAAK,QAAQ,IAAI,gBAAgB;AAAA,QAC1C,sBAAsB,KAAK,wBAAwB;AAAA,QACnD,OAAO;AAAA,QACP,UAAU,CAAC,SAAS,aAAa,SAAS,UAAU,MAAM,YAAY;AAAA,QACtE,YAAY;AAAA;AAAA,IACd;AAAA,EAEJ;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,qBAAqB,KAAK,QAAQ;AAAA,MAClC,WAAW,KAAK,QAAQ;AAAA,MACxB,YAAY,KAAK,QAAQ,WAAW,KAAK,KAAK;AAAA,MAC9C,OAAO,KAAK;AAAA,MACZ,SAAS,KAAK;AAAA,MACd,UAAU,IAAI,IAAI,QAAQ;AAAA,MAC1B,UAAU,CAAC,OAAO,YAAY,aAAa,SAAS,OAAO,OAAO;AAAA,MAClE,SAAS,MAAM,aAAa,OAAO;AAAA,MACnC,UAAU,KAAK,QAAQ;AAAA,MACvB,YAAY,KAAK,gBAAgB,OAAO;AAAA,MACxC,mBAAmB,KAAK,QAAQ;AAAA,MAChC,gBAAgB,KAAK,QAAQ;AAAA,MAC7B;AAAA,MACA;AAAA,MACA,eAAa;AAAA;AAAA,EACf;AAEJ;","names":[]}