@12-apps/ui 6.66.2 → 6.67.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/dist/_internal/components/data-display/Avatar/Avatar.js +4 -4
  2. package/dist/_internal/components/data-display/Avatar/Avatar.view.js +2 -2
  3. package/dist/_internal/components/data-display/Carousel/Carousel.js +2 -2
  4. package/dist/_internal/components/data-display/Chart/Chart.js +3 -3
  5. package/dist/_internal/components/data-display/Chart/SpecChart.js +6 -6
  6. package/dist/_internal/components/data-display/Chart/chart-renderers.js +2 -2
  7. package/dist/_internal/components/data-display/Chart/chart-spec.js +2 -2
  8. package/dist/_internal/components/data-display/DataGrid/DataGrid.js +2 -2
  9. package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +31 -28
  10. package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +33 -30
  11. package/dist/_internal/components/data-display/DataViews/base-card.js +2 -2
  12. package/dist/_internal/components/data-display/DataViews/base-list-card-geometry.js +5 -5
  13. package/dist/_internal/components/data-display/DataViews/base-list-card-layout.js +6 -6
  14. package/dist/_internal/components/data-display/DataViews/base-list-card-slots.js +4 -4
  15. package/dist/_internal/components/data-display/DataViews/base-list-card.js +8 -8
  16. package/dist/_internal/components/data-display/DataViews/data-views-display-panel.js +4 -4
  17. package/dist/_internal/components/data-display/DataViews/data-views-display-tabs.js +3 -3
  18. package/dist/_internal/components/data-display/DataViews/data-views-empty.js +5 -3
  19. package/dist/_internal/components/data-display/DataViews/data-views-filter-panel.js +3 -3
  20. package/dist/_internal/components/data-display/DataViews/data-views-grid-bodies.js +7 -6
  21. package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +28 -25
  22. package/dist/_internal/components/data-display/DataViews/data-views-inline-bar.js +11 -5
  23. package/dist/_internal/components/data-display/DataViews/data-views-layout-context.js +2 -2
  24. package/dist/_internal/components/data-display/DataViews/data-views-more-fields.js +8 -3
  25. package/dist/_internal/components/data-display/DataViews/data-views-more-filters.js +7 -4
  26. package/dist/_internal/components/data-display/DataViews/data-views-overflow-fields.js +18 -0
  27. package/dist/_internal/components/data-display/DataViews/data-views-overflow-fields.js.map +1 -0
  28. package/dist/_internal/components/data-display/DataViews/data-views-overflow.js +6 -2
  29. package/dist/_internal/components/data-display/DataViews/data-views-quick-chip.js +20 -0
  30. package/dist/_internal/components/data-display/DataViews/data-views-quick-chip.js.map +1 -0
  31. package/dist/_internal/components/data-display/DataViews/data-views-quick-types.js +1 -0
  32. package/dist/_internal/components/data-display/DataViews/data-views-quick-types.js.map +1 -0
  33. package/dist/_internal/components/data-display/DataViews/data-views-range-pill.js +2 -2
  34. package/dist/_internal/components/data-display/DataViews/data-views-scope-tabs.js +3 -3
  35. package/dist/_internal/components/data-display/DataViews/data-views-shell-toolbar.js +8 -7
  36. package/dist/_internal/components/data-display/DataViews/data-views-sticky-head.js +21 -0
  37. package/dist/_internal/components/data-display/DataViews/data-views-sticky-head.js.map +1 -0
  38. package/dist/_internal/components/data-display/DataViews/data-views-toolbar.js +7 -6
  39. package/dist/_internal/components/data-display/DataViews/data-views-types.js +1 -1
  40. package/dist/_internal/components/data-display/DataViews/list-card-rails.js +3 -3
  41. package/dist/_internal/components/data-display/DataViews/use-data-views-state.js +3 -3
  42. package/dist/_internal/components/data-display/DataViews/use-saved-views-controller.js +2 -2
  43. package/dist/_internal/components/data-display/index.js +19 -19
  44. package/dist/_internal/components/index.js +19 -19
  45. package/dist/_internal/user-avatar/user-avatar.js +5 -5
  46. package/dist/charts.js +11 -11
  47. package/dist/{chunk-35L5YMYQ.js → chunk-2QB4WIU5.js} +6 -6
  48. package/dist/chunk-4IE66GY2.js +89 -0
  49. package/dist/chunk-4IE66GY2.js.map +1 -0
  50. package/dist/{chunk-JYMXYSDP.js → chunk-5CAWRMDX.js} +2 -2
  51. package/dist/{chunk-L7OWFJUU.js → chunk-5RC7WAHH.js} +40 -34
  52. package/dist/chunk-5RC7WAHH.js.map +1 -0
  53. package/dist/{chunk-647DEGIU.js → chunk-5WJFCQFN.js} +7 -7
  54. package/dist/{chunk-K6KBASL2.js → chunk-72L5C74V.js} +2 -2
  55. package/dist/{chunk-TKLPPAS5.js → chunk-AHNEEFK6.js} +2 -2
  56. package/dist/chunk-AT6UKTH4.js +129 -0
  57. package/dist/chunk-AT6UKTH4.js.map +1 -0
  58. package/dist/{chunk-BI7YMVKZ.js → chunk-B2JSUFDX.js} +2 -2
  59. package/dist/{chunk-7J5JR33K.js → chunk-BBBHPK2Q.js} +2 -2
  60. package/dist/{chunk-UZ2CEJOO.js → chunk-CSJ7WNXU.js} +2 -2
  61. package/dist/{chunk-6QYKZMEE.js → chunk-CSLBRJ7N.js} +40 -25
  62. package/dist/chunk-CSLBRJ7N.js.map +1 -0
  63. package/dist/{chunk-LMIOWP6H.js → chunk-D34PZJH3.js} +2 -2
  64. package/dist/{chunk-SUZLGB5I.js → chunk-E6K2UZGR.js} +3 -3
  65. package/dist/{chunk-7XSCEHGA.js → chunk-EOQ6EKTS.js} +7 -7
  66. package/dist/chunk-GCYGVWOI.js +59 -0
  67. package/dist/chunk-GCYGVWOI.js.map +1 -0
  68. package/dist/{chunk-AMLHEKSV.js → chunk-HI7JPDD6.js} +5 -5
  69. package/dist/{chunk-O2P2KTKN.js → chunk-HLYYB4O5.js} +1 -1
  70. package/dist/chunk-HLYYB4O5.js.map +1 -0
  71. package/dist/{chunk-KARMRTTM.js → chunk-J2RUDZVJ.js} +7 -7
  72. package/dist/{chunk-HQCZT6TO.js → chunk-JVOEVTCZ.js} +5 -5
  73. package/dist/{chunk-VJB63DUM.js → chunk-K3PMMW23.js} +2 -2
  74. package/dist/{chunk-J6DYHBID.js → chunk-LIN4A2BW.js} +7 -7
  75. package/dist/{chunk-FXZUVZON.js → chunk-LWZ2K225.js} +6 -6
  76. package/dist/{chunk-6S3S2K7O.js → chunk-P3USTYIO.js} +3 -3
  77. package/dist/chunk-P3USTYIO.js.map +1 -0
  78. package/dist/{chunk-MJ6EAND6.js → chunk-Q7BGMLCX.js} +2 -2
  79. package/dist/{chunk-6ATXOJVQ.js → chunk-QADTI63U.js} +4 -4
  80. package/dist/{chunk-M6V7Y7CP.js → chunk-QAZLQYSD.js} +3 -3
  81. package/dist/chunk-QAZLQYSD.js.map +1 -0
  82. package/dist/{chunk-L6MGAPBX.js → chunk-RCZ4KL2H.js} +5 -3
  83. package/dist/chunk-RCZ4KL2H.js.map +1 -0
  84. package/dist/{chunk-YLSSQJZM.js → chunk-T7ZERP7A.js} +30 -2
  85. package/dist/chunk-T7ZERP7A.js.map +1 -0
  86. package/dist/{chunk-SB2SEGR6.js → chunk-TIM4PXWN.js} +3 -3
  87. package/dist/{chunk-Y7YKIIYS.js → chunk-TQXB2OHP.js} +28 -4
  88. package/dist/chunk-TQXB2OHP.js.map +1 -0
  89. package/dist/{chunk-3WLS7Z7D.js → chunk-UMOHHWXY.js} +3 -3
  90. package/dist/{chunk-S4JXSC4D.js → chunk-V6SRBQMN.js} +5 -5
  91. package/dist/{chunk-JY5YINUH.js → chunk-WQ32YFM5.js} +15 -7
  92. package/dist/chunk-WQ32YFM5.js.map +1 -0
  93. package/dist/{chunk-ERA3AEWU.js → chunk-WTGIW7LX.js} +12 -3
  94. package/dist/chunk-WTGIW7LX.js.map +1 -0
  95. package/dist/{chunk-2VMIHFMX.js → chunk-WVIJFS5Y.js} +9 -4
  96. package/dist/chunk-WVIJFS5Y.js.map +1 -0
  97. package/dist/{chunk-375HTCF2.js → chunk-Y2CCXB7R.js} +18 -2
  98. package/dist/chunk-Y2CCXB7R.js.map +1 -0
  99. package/dist/{chunk-33XGC4YU.js → chunk-YEGZIYVM.js} +2 -2
  100. package/dist/data-display/Avatar.js +4 -4
  101. package/dist/data-display/CardKit.js +7 -7
  102. package/dist/data-display/Carousel.js +2 -2
  103. package/dist/data-display/Chart.js +11 -11
  104. package/dist/data-display/DataGrid.js +2 -2
  105. package/dist/data-display/DataViews.js +42 -39
  106. package/dist/types/components/data-display/DataViews/DataViewsGrid.d.ts +15 -1
  107. package/dist/types/components/data-display/DataViews/DataViewsGrid.d.ts.map +1 -1
  108. package/dist/types/components/data-display/DataViews/DataViewsTableBase.d.ts +5 -1
  109. package/dist/types/components/data-display/DataViews/DataViewsTableBase.d.ts.map +1 -1
  110. package/dist/types/components/data-display/DataViews/data-views-empty.d.ts +10 -0
  111. package/dist/types/components/data-display/DataViews/data-views-empty.d.ts.map +1 -1
  112. package/dist/types/components/data-display/DataViews/data-views-grid-bodies.d.ts +2 -0
  113. package/dist/types/components/data-display/DataViews/data-views-grid-bodies.d.ts.map +1 -1
  114. package/dist/types/components/data-display/DataViews/data-views-grid-parts.d.ts +5 -1
  115. package/dist/types/components/data-display/DataViews/data-views-grid-parts.d.ts.map +1 -1
  116. package/dist/types/components/data-display/DataViews/data-views-inline-bar.d.ts +4 -1
  117. package/dist/types/components/data-display/DataViews/data-views-inline-bar.d.ts.map +1 -1
  118. package/dist/types/components/data-display/DataViews/data-views-more-fields.d.ts +10 -1
  119. package/dist/types/components/data-display/DataViews/data-views-more-fields.d.ts.map +1 -1
  120. package/dist/types/components/data-display/DataViews/data-views-more-filters.d.ts.map +1 -1
  121. package/dist/types/components/data-display/DataViews/data-views-overflow-fields.d.ts +56 -0
  122. package/dist/types/components/data-display/DataViews/data-views-overflow-fields.d.ts.map +1 -0
  123. package/dist/types/components/data-display/DataViews/data-views-overflow.d.ts +7 -5
  124. package/dist/types/components/data-display/DataViews/data-views-overflow.d.ts.map +1 -1
  125. package/dist/types/components/data-display/DataViews/data-views-quick-chip.d.ts +16 -0
  126. package/dist/types/components/data-display/DataViews/data-views-quick-chip.d.ts.map +1 -0
  127. package/dist/types/components/data-display/DataViews/data-views-quick-types.d.ts +33 -0
  128. package/dist/types/components/data-display/DataViews/data-views-quick-types.d.ts.map +1 -0
  129. package/dist/types/components/data-display/DataViews/data-views-range-types.d.ts +2 -0
  130. package/dist/types/components/data-display/DataViews/data-views-range-types.d.ts.map +1 -1
  131. package/dist/types/components/data-display/DataViews/data-views-shell-toolbar.d.ts +11 -6
  132. package/dist/types/components/data-display/DataViews/data-views-shell-toolbar.d.ts.map +1 -1
  133. package/dist/types/components/data-display/DataViews/data-views-sticky-head.d.ts +45 -0
  134. package/dist/types/components/data-display/DataViews/data-views-sticky-head.d.ts.map +1 -0
  135. package/dist/types/components/data-display/DataViews/data-views-toolbar.d.ts +6 -0
  136. package/dist/types/components/data-display/DataViews/data-views-toolbar.d.ts.map +1 -1
  137. package/dist/types/components/data-display/DataViews/data-views-types.d.ts +7 -4
  138. package/dist/types/components/data-display/DataViews/data-views-types.d.ts.map +1 -1
  139. package/dist/types/components/data-display/DataViews/index.d.ts +1 -1
  140. package/dist/types/components/data-display/DataViews/index.d.ts.map +1 -1
  141. package/dist/user-avatar.js +5 -5
  142. package/package.json +1 -1
  143. package/src/components/data-display/DataViews/DataViewsGrid.tsx +15 -0
  144. package/src/components/data-display/DataViews/DataViewsTableBase.tsx +5 -0
  145. package/src/components/data-display/DataViews/RESPONSIVE-BEHAVIOUR.md +50 -0
  146. package/src/components/data-display/DataViews/data-views-empty.tsx +25 -0
  147. package/src/components/data-display/DataViews/data-views-grid-bodies.tsx +11 -1
  148. package/src/components/data-display/DataViews/data-views-grid-parts.tsx +27 -15
  149. package/src/components/data-display/DataViews/data-views-inline-bar.tsx +24 -1
  150. package/src/components/data-display/DataViews/data-views-more-fields.tsx +34 -1
  151. package/src/components/data-display/DataViews/data-views-more-filters.tsx +20 -4
  152. package/src/components/data-display/DataViews/data-views-overflow-fields.ts +110 -0
  153. package/src/components/data-display/DataViews/data-views-overflow.ts +58 -36
  154. package/src/components/data-display/DataViews/data-views-quick-chip.tsx +143 -0
  155. package/src/components/data-display/DataViews/data-views-quick-types.ts +33 -0
  156. package/src/components/data-display/DataViews/data-views-range-types.ts +2 -0
  157. package/src/components/data-display/DataViews/data-views-shell-toolbar.tsx +31 -23
  158. package/src/components/data-display/DataViews/data-views-sticky-head.ts +132 -0
  159. package/src/components/data-display/DataViews/data-views-toolbar.tsx +9 -0
  160. package/src/components/data-display/DataViews/data-views-types.ts +7 -11
  161. package/src/components/data-display/DataViews/index.ts +1 -0
  162. package/dist/chunk-2VMIHFMX.js.map +0 -1
  163. package/dist/chunk-375HTCF2.js.map +0 -1
  164. package/dist/chunk-6QYKZMEE.js.map +0 -1
  165. package/dist/chunk-6S3S2K7O.js.map +0 -1
  166. package/dist/chunk-ERA3AEWU.js.map +0 -1
  167. package/dist/chunk-JY5YINUH.js.map +0 -1
  168. package/dist/chunk-L6MGAPBX.js.map +0 -1
  169. package/dist/chunk-L7OWFJUU.js.map +0 -1
  170. package/dist/chunk-M6V7Y7CP.js.map +0 -1
  171. package/dist/chunk-O2P2KTKN.js.map +0 -1
  172. package/dist/chunk-Y7YKIIYS.js.map +0 -1
  173. package/dist/chunk-YLSSQJZM.js.map +0 -1
  174. /package/dist/{chunk-35L5YMYQ.js.map → chunk-2QB4WIU5.js.map} +0 -0
  175. /package/dist/{chunk-JYMXYSDP.js.map → chunk-5CAWRMDX.js.map} +0 -0
  176. /package/dist/{chunk-647DEGIU.js.map → chunk-5WJFCQFN.js.map} +0 -0
  177. /package/dist/{chunk-K6KBASL2.js.map → chunk-72L5C74V.js.map} +0 -0
  178. /package/dist/{chunk-TKLPPAS5.js.map → chunk-AHNEEFK6.js.map} +0 -0
  179. /package/dist/{chunk-BI7YMVKZ.js.map → chunk-B2JSUFDX.js.map} +0 -0
  180. /package/dist/{chunk-7J5JR33K.js.map → chunk-BBBHPK2Q.js.map} +0 -0
  181. /package/dist/{chunk-UZ2CEJOO.js.map → chunk-CSJ7WNXU.js.map} +0 -0
  182. /package/dist/{chunk-LMIOWP6H.js.map → chunk-D34PZJH3.js.map} +0 -0
  183. /package/dist/{chunk-SUZLGB5I.js.map → chunk-E6K2UZGR.js.map} +0 -0
  184. /package/dist/{chunk-7XSCEHGA.js.map → chunk-EOQ6EKTS.js.map} +0 -0
  185. /package/dist/{chunk-AMLHEKSV.js.map → chunk-HI7JPDD6.js.map} +0 -0
  186. /package/dist/{chunk-KARMRTTM.js.map → chunk-J2RUDZVJ.js.map} +0 -0
  187. /package/dist/{chunk-HQCZT6TO.js.map → chunk-JVOEVTCZ.js.map} +0 -0
  188. /package/dist/{chunk-VJB63DUM.js.map → chunk-K3PMMW23.js.map} +0 -0
  189. /package/dist/{chunk-J6DYHBID.js.map → chunk-LIN4A2BW.js.map} +0 -0
  190. /package/dist/{chunk-FXZUVZON.js.map → chunk-LWZ2K225.js.map} +0 -0
  191. /package/dist/{chunk-MJ6EAND6.js.map → chunk-Q7BGMLCX.js.map} +0 -0
  192. /package/dist/{chunk-6ATXOJVQ.js.map → chunk-QADTI63U.js.map} +0 -0
  193. /package/dist/{chunk-SB2SEGR6.js.map → chunk-TIM4PXWN.js.map} +0 -0
  194. /package/dist/{chunk-3WLS7Z7D.js.map → chunk-UMOHHWXY.js.map} +0 -0
  195. /package/dist/{chunk-S4JXSC4D.js.map → chunk-V6SRBQMN.js.map} +0 -0
  196. /package/dist/{chunk-33XGC4YU.js.map → chunk-YEGZIYVM.js.map} +0 -0
@@ -1,3 +1,8 @@
1
+ import {
2
+ anyApplied,
3
+ isQuickActive,
4
+ keepChipsInOrder
5
+ } from "./chunk-GCYGVWOI.js";
1
6
  import {
2
7
  RESERVED,
3
8
  estimateWidth,
@@ -18,42 +23,51 @@ import {
18
23
  // src/components/data-display/DataViews/data-views-overflow.ts
19
24
  import { useTheme } from "@mui/material/styles/index.js";
20
25
  import { useRef } from "react";
21
- function toOverflowFields(fields, rangeFields) {
22
- return [
23
- ...fields.map((pill) => ({ id: pill.id, label: pill.label, group: "pill", pill })),
24
- ...rangeFields.map((range) => ({ id: range.id, label: range.label, group: "range", range }))
25
- ];
26
- }
27
26
  function isActiveField(field, pills, ranges) {
27
+ if (field.group === "quick" && field.quick) return isQuickActive(field.quick, pills);
28
28
  return field.group === "pill" ? (pills[field.id]?.length ?? 0) > 0 : isRangeSet(ranges[field.id]);
29
29
  }
30
30
  function fieldWidth(theme, field, pills, ranges) {
31
+ if (field.group === "quick") return estimateWidth(theme, `${field.label} ${field.quick?.count ?? ""}`, -20);
31
32
  if (field.group === "pill") return estimateWidth(theme, pillText(field, pills[field.id] ?? []), 0);
32
33
  return estimateWidth(theme, field.label, isRangeSet(ranges[field.id]) ? 100 : 0);
33
34
  }
34
35
  function splitFilters(all, pills, ranges, width, furniture, compact, theme) {
35
- const active = all.filter((field) => isActiveField(field, pills, ranges));
36
- const idle = all.filter((field) => !isActiveField(field, pills, ranges));
36
+ const pinned = all.filter((field) => field.pinned);
37
+ const candidates = all.filter((field) => !field.pinned);
38
+ const chips = candidates.filter((field) => field.group === "quick");
39
+ const rest = candidates.filter((field) => field.group !== "quick");
40
+ const active = rest.filter((field) => isActiveField(field, pills, ranges));
41
+ const idle = rest.filter((field) => !isActiveField(field, pills, ranges));
37
42
  const price = pricesFor(theme);
43
+ const moreCost = compact ? price.overflowButtonCompact : price.overflowButton;
38
44
  const gap = remPx(theme, RESERVED.betweenControls);
39
- const clearCost = active.length > 0 ? price.clearAll + gap : 0;
40
- const split = splitToFit(all, {
41
- widthOf: (field) => fieldWidth(theme, field, pills, ranges),
42
- keyOf: (field) => field.id,
43
- gap,
44
- available: width - furniture - clearCost,
45
- // The overflow button at the width it will actually have, which on a phone
46
- // is the icon-and-badge one.
47
- overflowCost: compact ? price.overflowButtonCompact : price.overflowButton,
48
- priority: [...active, ...idle]
49
- });
50
- return { ...split, used: split.used + clearCost };
45
+ const clearCost = anyApplied(all, pills, ranges) ? price.clearAll + gap : 0;
46
+ const pinnedCost = pinned.length > 0 ? moreCost + gap : 0;
47
+ const widthOf = (field) => fieldWidth(theme, field, pills, ranges);
48
+ const split = keepChipsInOrder(
49
+ splitToFit(candidates, {
50
+ widthOf,
51
+ keyOf: (field) => field.id,
52
+ gap,
53
+ available: width - furniture - clearCost - pinnedCost,
54
+ overflowCost: pinned.length > 0 ? 0 : moreCost,
55
+ priority: [...chips, ...active, ...idle]
56
+ }),
57
+ chips,
58
+ (field) => widthOf(field) + gap
59
+ );
60
+ return {
61
+ inline: split.inline,
62
+ overflow: [...split.overflow, ...pinned],
63
+ used: split.used + clearCost + pinnedCost
64
+ };
51
65
  }
52
66
  function computeSplit(all, pills, ranges, width, hasExport, theme) {
53
67
  if (width === 0) {
54
68
  return {
55
- inline: all,
56
- overflow: [],
69
+ inline: all.filter((field) => !field.pinned),
70
+ overflow: all.filter((field) => field.pinned),
57
71
  compactControls: false,
58
72
  counterHidden: false,
59
73
  searchCollapsed: false,
@@ -93,7 +107,9 @@ function useFilterOverflow(all, pills, ranges, frozen = false, hasExport = true)
93
107
  const { ref: barRef, width } = useMeasuredWidth();
94
108
  const theme = useTheme();
95
109
  const signature = JSON.stringify({
96
- ids: all.map((field) => field.id),
110
+ // A chip's count and a field's `inMore` change its price or its place
111
+ // without changing its id, so both are part of the key.
112
+ ids: all.map((field) => [field.id, field.quick?.count ?? null, field.pinned === true]),
97
113
  pills,
98
114
  ranges,
99
115
  width,
@@ -111,7 +127,6 @@ function useFilterOverflow(all, pills, ranges, frozen = false, hasExport = true)
111
127
  }
112
128
 
113
129
  export {
114
- toOverflowFields,
115
130
  useFilterOverflow
116
131
  };
117
- //# sourceMappingURL=chunk-6QYKZMEE.js.map
132
+ //# sourceMappingURL=chunk-CSLBRJ7N.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/data-display/DataViews/data-views-overflow.ts"],"sourcesContent":["\"use client\";\n\nimport { useTheme, type Theme } from \"@mui/material/styles/index.js\";\nimport { useRef } from \"react\";\n\nimport { remPx } from \"../../../tokens/relative\";\nimport { splitToFit, useMeasuredWidth } from \"../../utility/Overflow\";\nimport {\n estimateWidth,\n furnitureCost,\n isRangeSet,\n pillText,\n pricesFor,\n RESERVED,\n rightClusterCost,\n type Prices,\n} from \"./data-views-overflow-costs\";\nimport type { FilterFieldConfig, QuickFilterConfig, RangeFieldConfig, RangeValue } from \"./data-views-types\";\nimport { anyApplied, isQuickActive, keepChipsInOrder } from \"./data-views-overflow-fields\";\n\n// Declaring the controls lives in its own module (size gate); re-exported for its callers.\nexport { isQuickActive, toOverflowFields } from \"./data-views-overflow-fields\";\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, a min/max range or a quick chip. */\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\" | \"quick\";\n pill?: FilterFieldConfig<T>;\n range?: RangeFieldConfig<T>;\n quick?: QuickFilterConfig;\n /** Declared `inMore`: never on the bar, always behind \"Mais\". */\n pinned?: boolean;\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/** 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 if (field.group === \"quick\" && field.quick) return isQuickActive(field.quick, pills);\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, in px at `theme`'s scale. */\nfunction fieldWidth<T extends Record<string, unknown>>(\n theme: Theme,\n field: OverflowField<T>,\n pills: Record<string, string[]>,\n ranges: Record<string, RangeValue>,\n): number {\n // A chip is a pill with its count beside the label and no chevron.\n if (field.group === \"quick\") return estimateWidth(theme, `${field.label} ${field.quick?.count ?? \"\"}`, -20);\n if (field.group === \"pill\") return estimateWidth(theme, pillText(field, pills[field.id] ?? []), 0);\n // A bounded range renders two number inputs (100 design px) beside its label.\n return estimateWidth(theme, 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 /** Whose type scale every price is read at — the bar's own. */\n theme: Theme,\n): Split<T> {\n // `inMore` fields never compete for the bar: they are behind \"Mais\" from the\n // start, so \"Mais\" is on the bar whatever else fits.\n const pinned = all.filter((field) => field.pinned);\n const candidates = all.filter((field) => !field.pinned);\n const chips = candidates.filter((field) => field.group === \"quick\");\n const rest = candidates.filter((field) => field.group !== \"quick\");\n const active = rest.filter((field) => isActiveField(field, pills, ranges));\n const idle = rest.filter((field) => !isActiveField(field, pills, ranges));\n const price = pricesFor(theme);\n const moreCost = compact ? price.overflowButtonCompact : price.overflowButton;\n const gap = remPx(theme, RESERVED.betweenControls);\n\n // \"Limpar\" rides the end of the cluster whenever anything is applied —\n // ANYTHING, a pinned field and a chip's field included, since the bar draws\n // it on the active count, not on what it can see. Pressing a chip can\n // therefore cost the bar room; chips rank first and stay a prefix (below),\n // so what leaves is an idle pill, or the chips together — never one chip\n // swapped for another.\n const clearCost = anyApplied(all, pills, ranges) ? price.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 // Quick chips come before all of it, in their DECLARED order whatever is\n // pressed: they are the bar's fixed vocabulary, so their slots never move.\n //\n // The keep-what-fits loop is `splitToFit` (`utility/Overflow`). With pinned\n // fields \"Mais\" is always drawn, so its cost is paid up front.\n const pinnedCost = pinned.length > 0 ? moreCost + gap : 0;\n const widthOf = (field: OverflowField<T>): number => fieldWidth(theme, field, pills, ranges);\n const split = keepChipsInOrder(\n splitToFit(candidates, {\n widthOf,\n keyOf: (field) => field.id,\n gap,\n available: width - furniture - clearCost - pinnedCost,\n overflowCost: pinned.length > 0 ? 0 : moreCost,\n priority: [...chips, ...active, ...idle],\n }),\n chips,\n (field) => widthOf(field) + gap,\n );\n return {\n inline: split.inline,\n overflow: [...split.overflow, ...pinned],\n used: split.used + clearCost + pinnedCost,\n };\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 theme: Theme,\n): Omit<OverflowSplit<T>, \"barRef\"> {\n // Unmeasured (SSR, or jsdom without a ResizeObserver) ⇒ degrade nothing.\n if (width === 0) {\n return {\n inline: all.filter((field) => !field.pinned),\n overflow: all.filter((field) => field.pinned),\n compactControls: false,\n counterHidden: false,\n searchCollapsed: false,\n clearAllHidden: false,\n searchTakeover: false,\n };\n }\n const price = pricesFor(theme);\n // Pass 1 prices the furniture at its widest — no rung has been taken yet.\n let budget = furnitureCost(price, UNCOLLAPSED, hasExport);\n let split = splitFilters(all, pills, ranges, width, budget, false, theme);\n let flags = ladderFlags(split, width, hasExport, price);\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 for (let pass = 0; pass < 3; pass += 1) {\n const freed = furnitureCost(price, flags, hasExport);\n if (freed >= budget) break;\n budget = freed;\n split = splitFilters(all, pills, ranges, width, budget, flags.compactControls, theme);\n flags = ladderFlags(split, width, hasExport, price);\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 price: Prices,\n): Omit<OverflowSplit<T>, \"barRef\" | \"inline\" | \"overflow\"> {\n const { overflow, used } = split;\n const base = width - used - price.chrome;\n\n // Would the search still make its minimum with the labels on?\n const compactControls = base - price.counter - rightClusterCost(price, hasExport, false) < price.search;\n const rightCost = rightClusterCost(price, hasExport, compactControls);\n // …and with them off?\n const searchCollapsed = base - price.counter - rightCost < price.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 - price.counter - rightCost < price.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 ? price.overflowButtonCompact\n : price.overflowButton;\n const shedRoom = width - price.chrome - (overflow.length > 0 ? overflowButton : 0);\n const searchBoxRoom = shedRoom - (counterHidden ? 0 : price.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 < price.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 // The prices follow the theme's type scale, so the answer does too.\n const theme = useTheme();\n const signature = JSON.stringify({\n // A chip's count and a field's `inMore` change its price or its place\n // without changing its id, so both are part of the key.\n ids: all.map((field) => [field.id, field.quick?.count ?? null, field.pinned === true]),\n pills,\n ranges,\n width,\n hasExport,\n scale: remPx(theme, 1),\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, theme) };\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":[]}
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-K4EKTMTC.js";
12
12
  import {
13
13
  CARD_ASPECT_RATIOS
14
- } from "./chunk-O2P2KTKN.js";
14
+ } from "./chunk-HLYYB4O5.js";
15
15
  import {
16
16
  useDataViewsCopy
17
17
  } from "./chunk-KHG57NAE.js";
@@ -268,4 +268,4 @@ function BaseCard(props) {
268
268
  export {
269
269
  BaseCard
270
270
  };
271
- //# sourceMappingURL=chunk-LMIOWP6H.js.map
271
+ //# sourceMappingURL=chunk-D34PZJH3.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  rowGutters
3
- } from "./chunk-3WLS7Z7D.js";
3
+ } from "./chunk-UMOHHWXY.js";
4
4
  import {
5
5
  cellRailsTemplate
6
- } from "./chunk-7J5JR33K.js";
6
+ } from "./chunk-BBBHPK2Q.js";
7
7
  import {
8
8
  cellTracks,
9
9
  compactCellTracks,
@@ -55,4 +55,4 @@ export {
55
55
  useRowLayout,
56
56
  StandaloneContainer
57
57
  };
58
- //# sourceMappingURL=chunk-SUZLGB5I.js.map
58
+ //# sourceMappingURL=chunk-E6K2UZGR.js.map
@@ -1,9 +1,3 @@
1
- import {
2
- pulseAnimation,
3
- rotateAnimation,
4
- scaleInAnimation,
5
- shimmerAnimation
6
- } from "./chunk-MTEQEPNY.js";
7
1
  import {
8
2
  ACTIVE_SCALE,
9
3
  AVATAR_SIZES,
@@ -23,6 +17,12 @@ import {
23
17
  SPINNER,
24
18
  STATUS_DOT
25
19
  } from "./chunk-6ZZGK5DT.js";
20
+ import {
21
+ pulseAnimation,
22
+ rotateAnimation,
23
+ scaleInAnimation,
24
+ shimmerAnimation
25
+ } from "./chunk-MTEQEPNY.js";
26
26
  import {
27
27
  absoluteInk,
28
28
  controlNeutral,
@@ -277,4 +277,4 @@ function AvatarView(props) {
277
277
  export {
278
278
  AvatarView
279
279
  };
280
- //# sourceMappingURL=chunk-7XSCEHGA.js.map
280
+ //# sourceMappingURL=chunk-EOQ6EKTS.js.map
@@ -0,0 +1,59 @@
1
+ import {
2
+ isRangeSet
3
+ } from "./chunk-DNT5PZLF.js";
4
+
5
+ // src/components/data-display/DataViews/data-views-overflow-fields.ts
6
+ function toOverflowFields(fields, rangeFields, quickFilters = []) {
7
+ const chipFields = new Set(quickFilters.map((quick) => quick.fieldId));
8
+ return [
9
+ ...quickFilters.map((quick) => ({
10
+ id: `quick:${quick.id}`,
11
+ label: quick.label,
12
+ group: "quick",
13
+ quick
14
+ })),
15
+ ...fields.filter((pill) => !chipFields.has(pill.id)).map((pill) => ({ id: pill.id, label: pill.label, group: "pill", pill, pinned: pill.inMore === true })),
16
+ ...rangeFields.map((range) => ({
17
+ id: range.id,
18
+ label: range.label,
19
+ group: "range",
20
+ range,
21
+ pinned: range.inMore === true
22
+ }))
23
+ ];
24
+ }
25
+ function isQuickActive(quick, pills) {
26
+ const selected = pills[quick.fieldId] ?? [];
27
+ return selected.length === 1 && selected[0] === quick.value;
28
+ }
29
+ function anyApplied(all, pills, ranges) {
30
+ return all.some((field) => {
31
+ if (field.group === "range") return isRangeSet(ranges[field.id]);
32
+ const id = field.quick?.fieldId ?? field.id;
33
+ return (pills[id]?.length ?? 0) > 0;
34
+ });
35
+ }
36
+ function keepChipsInOrder(split, chips, cost) {
37
+ const firstOut = chips.findIndex((chip) => split.overflow.includes(chip));
38
+ if (firstOut < 0) return split;
39
+ const evicted = chips.slice(firstOut).filter((chip) => split.inline.includes(chip));
40
+ if (evicted.length === 0) return split;
41
+ return {
42
+ inline: split.inline.filter((field) => !evicted.includes(field)),
43
+ overflow: [...chips.slice(firstOut), ...split.overflow.filter((field) => !chips.includes(field))],
44
+ used: split.used - evicted.reduce((sum, chip) => sum + cost(chip), 0)
45
+ };
46
+ }
47
+ function toggleQuick(pills, quick) {
48
+ const pressed = isQuickActive(quick, pills);
49
+ return { ...pills, [quick.fieldId]: pressed ? [] : [quick.value] };
50
+ }
51
+
52
+ export {
53
+ toOverflowFields,
54
+ isQuickActive,
55
+ anyApplied,
56
+ keepChipsInOrder,
57
+ toggleQuick
58
+ };
59
+ //# sourceMappingURL=chunk-GCYGVWOI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/data-display/DataViews/data-views-overflow-fields.ts"],"sourcesContent":["/**\n * WHICH CONTROLS THE BAR DECLARES — split from `data-views-overflow` at the\n * file-size gate. That module decides where each control goes; this one only\n * lists them, in the order the bar renders them.\n */\nimport type { OverflowField } from \"./data-views-overflow\";\nimport { isRangeSet } from \"./data-views-overflow-costs\";\nimport type { FilterFieldConfig, QuickFilterConfig, RangeFieldConfig, RangeValue } from \"./data-views-types\";\n\n/**\n * Every declared control in the order the bar renders them: quick chips first,\n * then pills, then ranges.\n *\n * A pill field a quick chip writes to is NOT a control of its own — the chips\n * stand in for it (see `QuickFilterConfig`) — so it is left out here, and only\n * here: it stays in `fields`, where the active count and saved views read it.\n */\nexport function toOverflowFields<T extends Record<string, unknown>>(\n fields: FilterFieldConfig<T>[],\n rangeFields: RangeFieldConfig<T>[],\n quickFilters: QuickFilterConfig[] = [],\n): OverflowField<T>[] {\n const chipFields = new Set(quickFilters.map((quick) => quick.fieldId));\n return [\n ...quickFilters.map((quick) => ({\n id: `quick:${quick.id}`,\n label: quick.label,\n group: \"quick\" as const,\n quick,\n })),\n ...fields\n .filter((pill) => !chipFields.has(pill.id))\n .map((pill) => ({ id: pill.id, label: pill.label, group: \"pill\" as const, pill, pinned: pill.inMore === true })),\n ...rangeFields.map((range) => ({\n id: range.id,\n label: range.label,\n group: \"range\" as const,\n range,\n pinned: range.inMore === true,\n })),\n ];\n}\n\n/**\n * Is this quick chip pressed — its one value the field's WHOLE selection?\n *\n * Exactly, not \"includes\": a field holding two values (from a saved view, the\n * URL or the side panel) is not what either chip applies, and reading both as\n * pressed made pressing one clear the other.\n */\nexport function isQuickActive(quick: QuickFilterConfig, pills: Record<string, string[]>): boolean {\n const selected = pills[quick.fieldId] ?? [];\n return selected.length === 1 && selected[0] === quick.value;\n}\n\n/**\n * Is any DECLARED filter applied — a pill value or a bounded range, wherever it\n * is drawn (on the bar, in \"Mais\", or as a chip)? Only declared ids count: the\n * bar draws \"Limpar\" on the active count, which ignores a stale key a saved view\n * still carries for a field since removed.\n */\nexport function anyApplied<T extends Record<string, unknown>>(\n all: OverflowField<T>[],\n pills: Record<string, string[]>,\n ranges: Record<string, RangeValue>,\n): boolean {\n return all.some((field) => {\n if (field.group === \"range\") return isRangeSet(ranges[field.id]);\n const id = field.quick?.fieldId ?? field.id;\n return (pills[id]?.length ?? 0) > 0;\n });\n}\n\n/**\n * Quick chips stay a PREFIX of their declared order on the bar.\n *\n * The keep-what-fits loop skips a control that does not fit and tries the next,\n * which for pills is right (any narrower one is worth the room) and for chips\n * is not: \"Zerado\" alone on the bar, with \"Estoque baixo\" in \"Mais\", reads as a\n * different bar from the one declared. So the first chip that went to \"Mais\"\n * takes every later chip with it. Their room is NOT re-spent here — `used`\n * drops, and the ladder's later passes can hand it to the furniture.\n */\nexport function keepChipsInOrder<T extends Record<string, unknown>>(\n split: { inline: OverflowField<T>[]; overflow: OverflowField<T>[]; used: number },\n chips: OverflowField<T>[],\n cost: (field: OverflowField<T>) => number,\n): { inline: OverflowField<T>[]; overflow: OverflowField<T>[]; used: number } {\n const firstOut = chips.findIndex((chip) => split.overflow.includes(chip));\n if (firstOut < 0) return split;\n const evicted = chips.slice(firstOut).filter((chip) => split.inline.includes(chip));\n if (evicted.length === 0) return split;\n return {\n inline: split.inline.filter((field) => !evicted.includes(field)),\n overflow: [...chips.slice(firstOut), ...split.overflow.filter((field) => !chips.includes(field))],\n used: split.used - evicted.reduce((sum, chip) => sum + cost(chip), 0),\n };\n}\n\n\n\n/**\n * A quick chip's press, as a pill write. Exclusive within the field: the chip's\n * value REPLACES the selection, and pressing the pressed chip empties it.\n */\nexport function toggleQuick(pills: Record<string, string[]>, quick: QuickFilterConfig): Record<string, string[]> {\n const pressed = isQuickActive(quick, pills);\n return { ...pills, [quick.fieldId]: pressed ? [] : [quick.value] };\n}\n\n"],"mappings":";;;;;AAiBO,SAAS,iBACd,QACA,aACA,eAAoC,CAAC,GACjB;AACpB,QAAM,aAAa,IAAI,IAAI,aAAa,IAAI,CAAC,UAAU,MAAM,OAAO,CAAC;AACrE,SAAO;AAAA,IACL,GAAG,aAAa,IAAI,CAAC,WAAW;AAAA,MAC9B,IAAI,SAAS,MAAM,EAAE;AAAA,MACrB,OAAO,MAAM;AAAA,MACb,OAAO;AAAA,MACP;AAAA,IACF,EAAE;AAAA,IACF,GAAG,OACA,OAAO,CAAC,SAAS,CAAC,WAAW,IAAI,KAAK,EAAE,CAAC,EACzC,IAAI,CAAC,UAAU,EAAE,IAAI,KAAK,IAAI,OAAO,KAAK,OAAO,OAAO,QAAiB,MAAM,QAAQ,KAAK,WAAW,KAAK,EAAE;AAAA,IACjH,GAAG,YAAY,IAAI,CAAC,WAAW;AAAA,MAC7B,IAAI,MAAM;AAAA,MACV,OAAO,MAAM;AAAA,MACb,OAAO;AAAA,MACP;AAAA,MACA,QAAQ,MAAM,WAAW;AAAA,IAC3B,EAAE;AAAA,EACJ;AACF;AASO,SAAS,cAAc,OAA0B,OAA0C;AAChG,QAAM,WAAW,MAAM,MAAM,OAAO,KAAK,CAAC;AAC1C,SAAO,SAAS,WAAW,KAAK,SAAS,CAAC,MAAM,MAAM;AACxD;AAQO,SAAS,WACd,KACA,OACA,QACS;AACT,SAAO,IAAI,KAAK,CAAC,UAAU;AACzB,QAAI,MAAM,UAAU,QAAS,QAAO,WAAW,OAAO,MAAM,EAAE,CAAC;AAC/D,UAAM,KAAK,MAAM,OAAO,WAAW,MAAM;AACzC,YAAQ,MAAM,EAAE,GAAG,UAAU,KAAK;AAAA,EACpC,CAAC;AACH;AAYO,SAAS,iBACd,OACA,OACA,MAC4E;AAC5E,QAAM,WAAW,MAAM,UAAU,CAAC,SAAS,MAAM,SAAS,SAAS,IAAI,CAAC;AACxE,MAAI,WAAW,EAAG,QAAO;AACzB,QAAM,UAAU,MAAM,MAAM,QAAQ,EAAE,OAAO,CAAC,SAAS,MAAM,OAAO,SAAS,IAAI,CAAC;AAClF,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,SAAO;AAAA,IACL,QAAQ,MAAM,OAAO,OAAO,CAAC,UAAU,CAAC,QAAQ,SAAS,KAAK,CAAC;AAAA,IAC/D,UAAU,CAAC,GAAG,MAAM,MAAM,QAAQ,GAAG,GAAG,MAAM,SAAS,OAAO,CAAC,UAAU,CAAC,MAAM,SAAS,KAAK,CAAC,CAAC;AAAA,IAChG,MAAM,MAAM,OAAO,QAAQ,OAAO,CAAC,KAAK,SAAS,MAAM,KAAK,IAAI,GAAG,CAAC;AAAA,EACtE;AACF;AAQO,SAAS,YAAY,OAAiC,OAAoD;AAC/G,QAAM,UAAU,cAAc,OAAO,KAAK;AAC1C,SAAO,EAAE,GAAG,OAAO,CAAC,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,KAAK,EAAE;AACnE;","names":[]}
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  renderChartByType
3
- } from "./chunk-6ATXOJVQ.js";
3
+ } from "./chunk-QADTI63U.js";
4
+ import {
5
+ ChartContainer
6
+ } from "./chunk-RIRTW5EU.js";
4
7
  import {
5
8
  getSizeStyles,
6
9
  getVariantStyles,
7
10
  plotHeightPx
8
11
  } from "./chunk-TCWISGSS.js";
9
- import {
10
- ChartContainer
11
- } from "./chunk-RIRTW5EU.js";
12
12
  import {
13
13
  muiColor
14
14
  } from "./chunk-7ZPUN7TV.js";
@@ -111,4 +111,4 @@ var Chart = (props) => {
111
111
  export {
112
112
  Chart
113
113
  };
114
- //# sourceMappingURL=chunk-AMLHEKSV.js.map
114
+ //# sourceMappingURL=chunk-HI7JPDD6.js.map
@@ -53,4 +53,4 @@ export {
53
53
  DATA_VIEWS_LAYOUTS,
54
54
  toSavedViewSummary
55
55
  };
56
- //# sourceMappingURL=chunk-O2P2KTKN.js.map
56
+ //# sourceMappingURL=chunk-HLYYB4O5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/data-display/DataViews/data-views-types.ts"],"sourcesContent":["import type { GridColumn, GridSort } from \"../DataGrid\";\nimport type { DropdownMenuItem } from \"../../navigation/DropdownMenu\";\n// A re-export does not bring the name into local scope, and the state/query\n// types below are written in terms of it.\nimport type { RangeValue } from \"./data-views-range-types\";\n\n/**\n * Shared types for the reusable admin \"DataViews\" table (FUT-88): a filter bar\n * (search-across-all + typed multi-select pills + column visibility) whose full\n * state — filters + sort + visible columns — a saved view (FUT-89) can capture\n * and restore. Each table declares its own columns + filter fields.\n */\n\n/**\n * A single, reusable row action. ONE definition drives BOTH the per-row \"⋮\"\n * kebab menu and the bulk-actions menu (tabwoah model): `onSelect` receives the\n * affected rows — `[row]` from a kebab, the whole selection from the bulk menu.\n * Single-item-only actions (e.g. \"Editar\") set `bulk: false` so they never\n * appear in the bulk menu.\n */\nexport interface RowAction<T extends Record<string, unknown>> {\n /** Stable id (also the `data-testid` suffix). */\n id: string;\n /** Menu label. In the kebab, `rowLabel` overrides it per row when provided. */\n label: string;\n /** Menu-item colour (e.g. `\"error\"` for destructive). */\n color?: DropdownMenuItem[\"color\"];\n /**\n * Runs on the affected rows: `[row]` from the kebab, all selected from bulk.\n * May be async — the bulk menu awaits it and only clears the selection once it\n * settles (keeping the selection on failure so the user can retry).\n */\n onSelect: (rows: T[]) => void | Promise<void>;\n /** Include in the bulk menu (2+ selected). Defaults to `true`. */\n bulk?: boolean;\n /** Include in the per-row kebab. Defaults to `true`. */\n row?: boolean;\n /** Per-row kebab label (e.g. `row.active ? \"Inativar\" : \"Ativar\"`). */\n rowLabel?: (row: T) => string;\n /**\n * Per-row applicability (e.g. state-machine guards). `false` hides the\n * kebab item for that row; in bulk the action runs only on the passing\n * rows and is dropped when none pass. Defaults to applicable.\n */\n isVisible?: (row: T) => boolean;\n}\n\n/** Selection state handed to a card renderer so it can drive its own checkbox. */\nexport interface DataViewCardSelection {\n selected: boolean;\n /** Absent when the grid is `selectable={false}`: pass it on as-is, and no checkbox is drawn. */\n onToggleSelect?: () => void;\n /**\n * Card SIZE multiplier from the toolbar zoom slider. The grid sizes the card's\n * width to `base × scale`; a card passes this to {@link BaseCard} `scale` so its\n * padding + typography grow by the same factor — the whole card scales together\n * (scale 2 → ~2× size). The proportion (aspect ratio) stays constant.\n */\n scale: number;\n}\n\n/**\n * The fixed proportions a {@link BaseCard} tile can take. The tile keeps this\n * ratio and grows in BOTH width and height as the zoom slider widens its grid\n * track, so a grid of cards stays visually uniform.\n */\nexport type CardAspectRatio = \"1:1\" | \"4:3\" | \"16:9\" | \"9:16\" | \"3:4\" | \"3:1\";\n\n/** Numeric width/height factor for each {@link CardAspectRatio} (CSS `aspect-ratio`). */\nexport const CARD_ASPECT_RATIOS: Record<CardAspectRatio, number> = {\n \"1:1\": 1,\n \"4:3\": 4 / 3,\n \"16:9\": 16 / 9,\n \"9:16\": 9 / 16,\n \"3:4\": 3 / 4,\n /**\n * The BANNER tile: too short for media, sized for two lines of text.\n *\n * Every other ratio here is picture-shaped, because they were added for cards\n * built around a thumbnail. A card whose subject is a NAME and a NUMBER — a\n * cart, an order, anything triaged rather than browsed — spends most of a 4:3\n * tile on an icon that repeats down the whole grid and says nothing.\n */\n \"3:1\": 3,\n};\n\n/** One selectable value inside a filter pill. */\nexport interface FilterOption {\n value: string;\n label: string;\n /**\n * Parent option's `value`, for a hierarchical field (`control: \"category\"`).\n * Ignored by the flat controls, so one option list serves both.\n */\n parentId?: string | null;\n}\n\n/** A typed, multi-select filter pill's configuration for a table. */\nexport interface FilterFieldConfig<T extends Record<string, unknown>> {\n /** Stable id; also the default row key when no `accessor` is given. */\n id: string;\n label: string;\n options: FilterOption[];\n /**\n * How the field renders in the filter panel. `checkboxes` (default) is best for\n * a few fixed options; `multiselect` is a compact dropdown for long option\n * lists; `category` is the hierarchical picker, for an option set that nests\n * via {@link FilterOption.parentId} — it renders parents as headings and\n * their children as the selectable rows, rather than flattening the tree into\n * one indistinguishable list.\n */\n control?: \"checkboxes\" | \"multiselect\" | \"category\";\n /**\n * Lets a `control: \"category\"` pill select a PARENT category, not just its\n * children. Off by default, which keeps the leaf-only reading: the parent is\n * a heading and its subcategories are the rows you tick.\n *\n * Turn it on where \"the whole category\" is a filter a user would reach for —\n * selecting a parent then selects every subcategory under it, and the chip\n * tray collapses that back to one chip bearing the category's name.\n *\n * A category with NO children is selectable either way: it is itself the\n * leaf, so the flag has nothing to gate there.\n */\n allowParentSelection?: boolean;\n /**\n * Forces this filter to render as a searchable multi-select dropdown with the\n * search box always shown, regardless of how many options are currently\n * loaded. Use it when the option set can grow unbounded (e.g. a filter backed\n * by a relation such as Roles or Categories). Omit it for a closed value set\n * (an enum), which keeps the plain checkbox / \"search only when long\"\n * behavior.\n */\n searchEnabled?: boolean;\n /**\n * Reads the row's value(s) for this field. A row matches the pill when any of\n * its values is selected. Defaults to `String(row[id])`.\n */\n accessor?: (row: T) => string | string[];\n /** Never on the bar, always behind \"Mais\" (beside quick chips); still counted, saved, cleared. */\n inMore?: boolean;\n}\n\n/**\n * The range and quick-chip types live in their own modules (this file outgrew\n * the size gate); re-exported so `data-views-types` stays the one import.\n */\nexport type { QuickFilterConfig } from \"./data-views-quick-types\";\nexport type { DayRangeFieldConfig, NumberRangeFieldConfig, RangeFieldConfig } from \"./data-views-range-types\";\nexport type { RangeFieldKind, RangePreset, RangeValue } from \"./data-views-range-types\";\n\n/** A grid column that can join the search scan and the column-visibility menu. */\nexport interface DataViewColumn<T extends Record<string, unknown>> extends GridColumn<T> {\n /** Included in \"search across all columns\" (needs a resolvable value). */\n searchable?: boolean;\n /** Toggleable in the column-visibility menu. Defaults to true; set false for\n * structural columns (image thumbnail, actions kebab) that must always show. */\n hideable?: boolean;\n}\n\n/**\n * The DataViews layout (view type): the dense \"Tabela\" grid, the \"Grade\" of\n * cards, the \"Lista\" of full-width rows, or the \"Quadro\" board of state columns.\n * Lives with the state types rather than with the toggle because a saved view\n * CAPTURES it — see {@link DataViewState.layout}.\n */\nexport type DataViewsLayout = \"cards\" | \"list\" | \"board\" | \"table\";\n\n/** The full, serializable state a view captures. */\n/**\n * A view-state patch: the fields to merge, or an updater given the CURRENT\n * state. Use the updater whenever the patch derives from state it also changes\n * — a render-scoped snapshot would let two calls in one tick read the same\n * `prev` and the second overwrite the first, which is exactly what a control\n * emitting one call per changed value does.\n */\nexport type DataViewStatePatch =\n | Partial<DataViewState>\n | ((prev: DataViewState) => Partial<DataViewState>);\n\nexport interface DataViewState {\n /** Free text matched across every `searchable` column. */\n search: string;\n /** fieldId → selected option values (empty/absent = no constraint). */\n pills: Record<string, string[]>;\n /** fieldId → selected numeric range (min/max). Absent/empty = no constraint. */\n ranges?: Record<string, RangeValue>;\n sortBy: GridSort[];\n /** Column ids kept visible; a hideable column not listed here is hidden. */\n visibleColumns: string[];\n /**\n * Column ids in READING ORDER. Absent ⇒ the order the table declared them in.\n *\n * Order is view state for the same reason visibility is: reordering columns is\n * an operator deciding what to read FIRST, and a saved view that restored the\n * columns but not their order would restore half a decision. Ids the table no\n * longer declares are ignored at render, and ids missing from a stale list\n * fall in after it — so a column added since the view was saved appears rather\n * than disappearing.\n */\n order?: string[];\n /**\n * The active SCOPE id — the page-level partition the scope tabs select (see\n * `ScopeConfig`). Optional, so a table that declares no scopes is untouched\n * and no view persisted before scopes existed breaks.\n *\n * Stored raw and RESOLVED at read time: the declared scopes change underneath\n * a saved view, and a view naming a scope that has since been removed must\n * fall back at render rather than break.\n */\n scope?: string;\n /**\n * The layout the view was saved in. Optional — absent means \"whatever the user\n * is currently using\", which is the pre-existing behaviour.\n *\n * A LAYOUT FALLBACK IS NOT A LAYOUT CHANGE: a table rendered as stacked rows\n * on a phone still has `\"table\"` stored here, so the view round-trips the\n * stored layout regardless of the device that opened it.\n */\n layout?: DataViewsLayout;\n}\n\n/** A pristine view state showing every given column and no filters/sort. */\nexport function emptyViewState(visibleColumns: string[]): DataViewState {\n return { search: \"\", pills: {}, ranges: {}, sortBy: [], visibleColumns };\n}\n\n/**\n * The URL-driven slice of {@link DataViewState} — the controls a server-mode host\n * mirrors from the address bar (search / pills / ranges / sort), WITHOUT\n * `visibleColumns`. Supplying it re-applies those controls when its reference\n * changes (e.g. browser back/forward or a deep-link on the same route), merging\n * over the current state so a user's show/hide column choices are preserved —\n * unlike `appliedState`, which fully replaces the state to apply a saved view.\n */\nexport type DataViewSyncState = Pick<\n DataViewState,\n \"search\" | \"pills\" | \"ranges\" | \"sortBy\" | \"scope\"\n>;\n\n/**\n * The query a SERVER-mode table emits whenever its filter/sort/page changes\n * (FUT-180). The host translates this into a backend request (see\n * `@12-apps/shared-helpers/search`) — in server mode the grid never filters,\n * sorts, or paginates in the browser; it renders exactly the page the server\n * returned. `page` is 1-based to match the backend contract.\n */\nexport interface DataViewQuery {\n search: string;\n pills: Record<string, string[]>;\n ranges: Record<string, RangeValue>;\n sortBy: GridSort[];\n /**\n * The RESOLVED active scope (see `resolveScope`), when the table declares\n * scopes. The KEY IS ABSENT for a table that declares none — not present-and-\n * undefined — so a host that never opted in sees a byte-identical query.\n *\n * It carries the resolved id, never the stored one: a deep link or a saved\n * view naming a scope the table no longer declares must not put that id on the\n * wire, where the backend would reject it and replace the page with an error.\n */\n scope?: string;\n page: number;\n pageSize: number;\n}\n\n/**\n * Server-mode wiring for a DataViews table. Its PRESENCE flips the table from\n * in-browser filtering/sorting/pagination to backend-driven: the rows handed in\n * are already the current page, `totalCount` is the unpaginated total, and\n * `onQueryChange` fires (search debounced by the host) whenever the user changes\n * a filter, the sort, or the page. This is the ONLY way an admin list should run\n * (see the app-side `DataViewsTable` wrapper, which requires it).\n */\nexport interface DataViewServer {\n /** Total matched rows across all pages (drives the counter + page count). */\n totalCount: number;\n /** Current 1-based page. */\n page: number;\n /** Rows per page. */\n pageSize: number;\n /** Fired when the effective query changes; the host re-fetches the page. */\n onQueryChange: (query: DataViewQuery) => void;\n /**\n * Per-scope totals for the scope tabs: `scopeId → count`. THE ONLY PIECE OF\n * THIS CONTRACT THAT CANNOT BE DONE CLIENT-SIDE — a count computed from the\n * loaded page is wrong the moment there is a second page, which is the\n * concrete bug scopes exist to fix.\n *\n * Compute it over search + pills + ranges while IGNORING the active scope.\n * Computed WITH the scope applied, every inactive tab reads zero, which is\n * worse than no counts at all.\n *\n * Omit it and the tabs render with no numbers. Nothing is ever invented from\n * the loaded rows to fill the gap.\n */\n scopeCounts?: Record<string, number>;\n}\n\n/**\n * Coerce an opaque persisted state (a saved view's JSON) into a valid\n * DataViewState, filling any missing part with a sane default. Guards against\n * legacy/older shapes so applying a saved view never renders an empty grid.\n */\nexport function coerceViewState(raw: unknown, allColumnIds: string[]): DataViewState {\n const value = (raw ?? {}) as Partial<DataViewState>;\n return {\n search: typeof value.search === \"string\" ? value.search : \"\",\n pills: asRecord<string[]>(value.pills),\n ranges: asRecord<RangeValue>(value.ranges),\n sortBy: Array.isArray(value.sortBy) ? value.sortBy : [],\n visibleColumns: Array.isArray(value.visibleColumns) ? value.visibleColumns : allColumnIds,\n order: Array.isArray(value.order) ? value.order : undefined,\n // Carried through UNVALIDATED against the declared scopes on purpose: a view\n // written before scopes existed has none (⇒ undefined ⇒ the first declared\n // scope at render), and one naming a since-removed scope keeps its stored id\n // here and falls back at READ time. Resolving here would rewrite the view.\n scope: typeof value.scope === \"string\" ? value.scope : undefined,\n layout: isLayout(value.layout) ? value.layout : undefined,\n };\n}\n\n/** Every layout this build knows how to render — the guard's single source. */\nexport const DATA_VIEWS_LAYOUTS: readonly DataViewsLayout[] = [\"cards\", \"list\", \"board\", \"table\"];\n\n/** Is this a layout this build knows how to render? Guards persisted JSON. */\nfunction isLayout(value: unknown): value is DataViewsLayout {\n return DATA_VIEWS_LAYOUTS.includes(value as DataViewsLayout);\n}\n\n/** A persisted map, or an empty one — persisted JSON can hold anything. */\nfunction asRecord<V>(value: unknown): Record<string, V> {\n return value !== null && typeof value === \"object\" ? (value as Record<string, V>) : {};\n}\n\n/** A saved view as consumed by the DataViews UI (FUT-89), with ownership flag. */\nexport interface SavedViewSummary {\n id: string;\n name: string;\n description: string | null;\n state: DataViewState;\n shared: boolean;\n pinned: boolean;\n isDefault: boolean;\n /** True when the current user owns the view (may edit/delete/pin/share it). */\n isOwner: boolean;\n}\n\n/** A saved-view repository record (opaque `state`), as returned to server pages. */\ninterface SavedViewRecordLike {\n id: string;\n name: string;\n description: string | null;\n state: unknown;\n shared: boolean;\n pinned: boolean;\n isDefault: boolean;\n isOwner: boolean;\n}\n\n/** Map a repository record to the client summary (opaque state → DataViewState). */\nexport function toSavedViewSummary(record: SavedViewRecordLike): SavedViewSummary {\n return { ...record, state: (record.state ?? {}) as DataViewState };\n}\n\n/**\n * Dependency-injection contracts for the framework-agnostic DataViewsTableBase:\n * the host app supplies saved-view persistence + router side-effects so the ui\n * component imports neither a backend (server actions) nor a framework router.\n */\n\n/** A saved view's editable fields, as the host persists them. */\nexport interface DataViewSaveInput {\n name: string;\n description: string;\n state: DataViewState;\n shared: boolean;\n pinned: boolean;\n isDefault: boolean;\n}\n\n/** Result of a persistence call — mirrors the app's `Result` without importing it. */\nexport type DataViewMutationResult = { ok: true } | { ok: false; error: string };\n\n/** Injected saved-view persistence (create/update/delete), wired by the host. */\nexport interface DataViewPersistence {\n create: (input: DataViewSaveInput) => Promise<DataViewMutationResult>;\n update: (id: string, input: DataViewSaveInput) => Promise<DataViewMutationResult>;\n remove: (id: string) => Promise<DataViewMutationResult>;\n}\n\n/** Injected router side-effects: sync the `?view=` param and re-fetch on change. */\nexport interface DataViewRouter {\n syncViewParam: (viewId: string | null) => void;\n refresh: () => void;\n}\n"],"mappings":";AAqEO,IAAM,qBAAsD;AAAA,EACjE,OAAO;AAAA,EACP,OAAO,IAAI;AAAA,EACX,QAAQ,KAAK;AAAA,EACb,QAAQ,IAAI;AAAA,EACZ,OAAO,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASX,OAAO;AACT;AA2IO,SAAS,eAAe,gBAAyC;AACtE,SAAO,EAAE,QAAQ,IAAI,OAAO,CAAC,GAAG,QAAQ,CAAC,GAAG,QAAQ,CAAC,GAAG,eAAe;AACzE;AA+EO,SAAS,gBAAgB,KAAc,cAAuC;AACnF,QAAM,QAAS,OAAO,CAAC;AACvB,SAAO;AAAA,IACL,QAAQ,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS;AAAA,IAC1D,OAAO,SAAmB,MAAM,KAAK;AAAA,IACrC,QAAQ,SAAqB,MAAM,MAAM;AAAA,IACzC,QAAQ,MAAM,QAAQ,MAAM,MAAM,IAAI,MAAM,SAAS,CAAC;AAAA,IACtD,gBAAgB,MAAM,QAAQ,MAAM,cAAc,IAAI,MAAM,iBAAiB;AAAA,IAC7E,OAAO,MAAM,QAAQ,MAAM,KAAK,IAAI,MAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,IAKlD,OAAO,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ;AAAA,IACvD,QAAQ,SAAS,MAAM,MAAM,IAAI,MAAM,SAAS;AAAA,EAClD;AACF;AAGO,IAAM,qBAAiD,CAAC,SAAS,QAAQ,SAAS,OAAO;AAGhG,SAAS,SAAS,OAA0C;AAC1D,SAAO,mBAAmB,SAAS,KAAwB;AAC7D;AAGA,SAAS,SAAY,OAAmC;AACtD,SAAO,UAAU,QAAQ,OAAO,UAAU,WAAY,QAA8B,CAAC;AACvF;AA4BO,SAAS,mBAAmB,QAA+C;AAChF,SAAO,EAAE,GAAG,QAAQ,OAAQ,OAAO,SAAS,CAAC,EAAoB;AACnE;","names":[]}
@@ -1,17 +1,17 @@
1
+ import {
2
+ AVATAR_DEFAULTS,
3
+ contentTypeOf,
4
+ pickAvatarContent
5
+ } from "./chunk-3ZVUNSFF.js";
1
6
  import {
2
7
  AvatarView
3
- } from "./chunk-7XSCEHGA.js";
8
+ } from "./chunk-EOQ6EKTS.js";
4
9
  import {
5
10
  BORDER_WIDTH,
6
11
  GROUP_HOVER,
7
12
  GROUP_MAX,
8
13
  GROUP_OVERLAP
9
14
  } from "./chunk-6ZZGK5DT.js";
10
- import {
11
- AVATAR_DEFAULTS,
12
- contentTypeOf,
13
- pickAvatarContent
14
- } from "./chunk-3ZVUNSFF.js";
15
15
  import {
16
16
  rem
17
17
  } from "./chunk-YKCAJ2TN.js";
@@ -175,4 +175,4 @@ export {
175
175
  Avatar,
176
176
  AvatarGroup
177
177
  };
178
- //# sourceMappingURL=chunk-KARMRTTM.js.map
178
+ //# sourceMappingURL=chunk-J2RUDZVJ.js.map
@@ -1,11 +1,11 @@
1
- import {
2
- chartAxisValueFormatter,
3
- chartValueFormatter
4
- } from "./chunk-6GPNZSAE.js";
5
1
  import {
6
2
  getChartSpecRenderer,
7
3
  getRegisteredChartSpecTypes
8
4
  } from "./chunk-WKUA6P3W.js";
5
+ import {
6
+ chartAxisValueFormatter,
7
+ chartValueFormatter
8
+ } from "./chunk-6GPNZSAE.js";
9
9
 
10
10
  // src/components/data-display/Chart/chart-spec.ts
11
11
  var CHART_SEMANTIC_COLORS = [
@@ -151,4 +151,4 @@ export {
151
151
  parseChartSpec,
152
152
  specToChartProps
153
153
  };
154
- //# sourceMappingURL=chunk-HQCZT6TO.js.map
154
+ //# sourceMappingURL=chunk-JVOEVTCZ.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-PL2AB5HJ.js";
4
4
  import {
5
5
  useDataViewsLayout
6
- } from "./chunk-JYMXYSDP.js";
6
+ } from "./chunk-5CAWRMDX.js";
7
7
 
8
8
  // src/components/data-display/DataViews/data-views-scope-tabs.tsx
9
9
  import { jsx } from "react/jsx-runtime";
@@ -34,4 +34,4 @@ function ScopeTabsSlot({
34
34
  export {
35
35
  ScopeTabsSlot
36
36
  };
37
- //# sourceMappingURL=chunk-VJB63DUM.js.map
37
+ //# sourceMappingURL=chunk-K3PMMW23.js.map
@@ -1,10 +1,7 @@
1
- import {
2
- useDisclosure
3
- } from "./chunk-2JCRNWHE.js";
4
1
  import {
5
2
  StandaloneContainer,
6
3
  useRowLayout
7
- } from "./chunk-SUZLGB5I.js";
4
+ } from "./chunk-E6K2UZGR.js";
8
5
  import {
9
6
  DiscloseSlot,
10
7
  DragSlot,
@@ -15,13 +12,16 @@ import {
15
12
  metaShape,
16
13
  rowStyles,
17
14
  useRowShell
18
- } from "./chunk-3WLS7Z7D.js";
15
+ } from "./chunk-UMOHHWXY.js";
19
16
  import {
20
17
  ListCardActions,
21
18
  ListCardCaption,
22
19
  ListCardMeta,
23
20
  ListCardTail
24
- } from "./chunk-UZ2CEJOO.js";
21
+ } from "./chunk-CSJ7WNXU.js";
22
+ import {
23
+ useDisclosure
24
+ } from "./chunk-2JCRNWHE.js";
25
25
  import {
26
26
  DropIndicator
27
27
  } from "./chunk-K4EKTMTC.js";
@@ -185,4 +185,4 @@ function BaseListCard(props) {
185
185
  export {
186
186
  BaseListCard
187
187
  };
188
- //# sourceMappingURL=chunk-J6DYHBID.js.map
188
+ //# sourceMappingURL=chunk-LIN4A2BW.js.map
@@ -1,8 +1,3 @@
1
- import {
2
- DataGridEmpty,
3
- DataGridError,
4
- DataGridLoading
5
- } from "./chunk-EARWC6PD.js";
6
1
  import {
7
2
  useDataGridModel
8
3
  } from "./chunk-LDROG4QI.js";
@@ -10,6 +5,11 @@ import {
10
5
  GridBody,
11
6
  GridHeader
12
7
  } from "./chunk-ZFXTRPQO.js";
8
+ import {
9
+ DataGridEmpty,
10
+ DataGridError,
11
+ DataGridLoading
12
+ } from "./chunk-EARWC6PD.js";
13
13
 
14
14
  // src/components/data-display/DataGrid/DataGrid.tsx
15
15
  import Paper from "@mui/material/Paper/index.js";
@@ -120,4 +120,4 @@ export {
120
120
  DataGrid,
121
121
  GRID_ONLY_PROPS
122
122
  };
123
- //# sourceMappingURL=chunk-FXZUVZON.js.map
123
+ //# sourceMappingURL=chunk-LWZ2K225.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-ZEVFMQAQ.js";
4
4
  import {
5
5
  DataViewsGrid
6
- } from "./chunk-M6V7Y7CP.js";
6
+ } from "./chunk-QAZLQYSD.js";
7
7
  import {
8
8
  viewStateKey
9
9
  } from "./chunk-ZOLAYP2D.js";
@@ -17,7 +17,7 @@ import {
17
17
  } from "./chunk-YNIOCELQ.js";
18
18
  import {
19
19
  useSavedViewsController
20
- } from "./chunk-BI7YMVKZ.js";
20
+ } from "./chunk-B2JSUFDX.js";
21
21
 
22
22
  // src/components/data-display/DataViews/DataViewsTableBase.tsx
23
23
  import { useEffect, useRef, useState } from "react";
@@ -166,4 +166,4 @@ function renderViewDialogs(ctl, fields, columns, views, testIdPrefix, onSaved) {
166
166
  export {
167
167
  DataViewsTableBase
168
168
  };
169
- //# sourceMappingURL=chunk-6S3S2K7O.js.map
169
+ //# sourceMappingURL=chunk-P3USTYIO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/data-display/DataViews/DataViewsTableBase.tsx"],"sourcesContent":["\"use client\";\n\nimport type { SortFieldDefinition } from \"../../layout/ContentToolbar\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport { DataViewsGrid } from \"./DataViewsGrid\";\nimport type { SelectionExtraRender } from \"./data-views-selection-extra\";\nimport type { ListGroupConfig } from \"./list-card-rails\";\nimport type { DisplayPanelView } from \"./data-views-display-panel\";\nimport { viewStateKey } from \"./data-views-dirty\";\nimport { DeleteViewDialog } from \"./DeleteViewDialog\";\nimport type { BoardConfig } from \"./DataViewsBoard\";\nimport type { DataViewExport } from \"./data-views-export\";\nimport type { ScopeConfig } from \"./data-views-scopes\";\nimport type { DataViewRowDetail } from \"./data-views-row-detail\";\nimport { ViewDialogs, ViewMutationErrorAlert } from \"./data-views-table-parts\";\nimport { useUrlEchoGuard, useUrlSyncState } from \"./data-views-url-echo\";\nimport {\n useSavedViewsController,\n type SavedViewsController,\n} from \"./use-saved-views-controller\";\nimport {\n type DataViewColumn,\n type DataViewsLayout,\n type DataViewServer,\n type DataViewState,\n type DataViewPersistence,\n type DataViewRouter,\n type FilterFieldConfig,\n type QuickFilterConfig,\n type RangeFieldConfig,\n type DataViewCardSelection,\n type RowAction,\n type SavedViewSummary,\n} from \"./data-views-types\";\n\nexport interface DataViewsTableBaseProps<T extends Record<string, unknown>> {\n /** The applied-view id read from the URL (`?view=`) on load, or null. */\n initialViewId?: string | null;\n /** Injected saved-view persistence (create/update/delete). */\n persistence: DataViewPersistence;\n /** Injected router side-effects (URL sync + refresh). */\n router: DataViewRouter;\n rows: T[];\n columns: DataViewColumn<T>[];\n fields: FilterFieldConfig<T>[];\n /** Optional numeric min/max range filters (advanced \"filter by amount\"). */\n rangeFields?: RangeFieldConfig<T>[];\n getRowId: (row: T) => string | number;\n onRowClick?: (row: T) => void;\n emptyState?: React.ReactNode;\n dataTestId?: string;\n testIdPrefix?: string;\n /** The user's + shared views for this table (from the server). */\n views: SavedViewSummary[];\n /** Big page title in the table header, beside the funnel + gear (GTA layout). */\n title?: string;\n /** Primary page actions (e.g. \"Novo produto\") rendered at the header's right. */\n headerActions?: React.ReactNode;\n /** Sort options for the toolbar's \"Sort By\" dropdown (defaults to sortable columns). */\n sortFields?: SortFieldDefinition[];\n /**\n * Per-sort-field VALUE KIND (`\"currency\" | \"number\" | \"date\" | \"text\"`), so the\n * Exibir panel phrases the direction in that column's own terms. \"Crescente\"\n * on a currency column is a puzzle; \"Menor → maior\" is not. Defaults to text.\n */\n sortKinds?: Record<string, string>;\n /**\n * Opt-in \"Exportar\" control. The grid hands the host the current query,\n * UNPAGINATED, and the host re-queries — the grid never fetches, and an\n * export therefore follows the filters rather than the loaded page.\n */\n exportConfig?: DataViewExport;\n /** Notified with the currently-visible (filtered) rows, so Export matches the view. */\n onVisibleRowsChange?: (rows: T[]) => void;\n /** Reusable row actions driving both the row \"⋮\" kebab and the bulk menu. */\n rowActions?: RowAction<T>[];\n /** Leading control in the auto kebab column (e.g. a favourite star). */\n rowActionsLeading?: (row: T) => React.ReactNode;\n /** Low-level bulk-action override; prefer `rowActions`. */\n bulkActions?: (selectedRows: T[], clearSelection: () => void) => React.ReactNode;\n /** A selection-widening control beside the count (e.g. \"select all matching\"). */\n selectionExtra?: SelectionExtraRender<T>;\n /** Bespoke per-row menu (an entity's self-contained 3-dots menu) instead of the auto kebab. */\n renderRowMenu?: (row: T) => React.ReactNode;\n /**\n * Row selection, default `true`. `false` draws no checkbox in any layout and\n * no select-all, so the toolbar's selection mode can never hide the search,\n * the pills and Exportar — for a grid with no bulk action. Row click and the\n * row menu are unaffected.\n */\n selectable?: boolean;\n /** Opt-in expandable rows (table layout only) — see {@link DataViewRowDetail}. */\n rowDetail?: DataViewRowDetail<T>;\n /** Opt-in \"Grade\" (cards) layout — a card renderer per row; adds a Grade/Tabela toggle. */\n renderCard?: (row: T, selection: DataViewCardSelection) => React.ReactNode;\n /** Opt-in \"Quadro\" (board) layout — the loaded page as columns of one field. Needs `renderCard`. */\n board?: BoardConfig<T>;\n /** Opt-in \"Lista\" layout — one full-width, entity-rendered row per record (FUT-733). */\n renderListRow?: (row: T, selection: DataViewCardSelection) => React.ReactNode;\n /** The Lista's shared columns, so its rows line up by construction not convention. */\n listGroup?: ListGroupConfig<T>;\n /** The page-level partition rendered as tabs under the toolbar (server mode only). */\n scopes?: ScopeConfig[];\n /** The row field the scopes partition by — used only to reject a pill over the same field. */\n scopeFieldId?: string;\n /** Which layout to show first when the user has expressed no preference (default \"table\"). */\n defaultLayout?: DataViewsLayout;\n /**\n * Ignore the remembered cross-screen layout preference and pin to\n * `defaultLayout`. For tables that exist to SHOW a layout — stories, docs,\n * screenshots — not for real screens.\n */\n ignoreStoredLayout?: boolean;\n /** Opt into the responsive inline filter UX (collapsible row / modal). Default keeps the panel. */\n inlineFilters?: boolean;\n /** Keep the inline search visible with no filter fields and no active search. */\n alwaysShowSearch?: boolean;\n /** One-click toggle chips at the head of the toolbar — see `QuickFilterConfig`. */\n quickFilters?: QuickFilterConfig[];\n /** Pin the toolbar and the table header while the page scrolls — see `DataViewsGrid`. */\n stickyToolbar?: boolean;\n /** Server-mode wiring (FUT-180): backend-driven rows/total + re-fetch. Omit for client mode. */\n server?: DataViewServer;\n /** Seed the initial view state (search/pills/ranges/sort) from the URL when no saved view applies. */\n initialState?: DataViewState;\n}\n\n/**\n * Resolve the initial applied view: a `?view=<id>` shortcut (FUT-90) wins, else\n * the user's default view, else none. Drives the seed state + trigger label.\n */\nfunction resolveInitialView(\n views: SavedViewSummary[],\n requestedId: string | null,\n): SavedViewSummary | undefined {\n const requested = requestedId ? views.find((view) => view.id === requestedId) : undefined;\n return requested ?? views.find((view) => view.isDefault);\n}\n\n/**\n * The Exibir panel's view chrome, assembled from the saved-views controller.\n * Extracted so {@link DataViewsTableBase} stays inside its size budget.\n */\nfunction buildDisplayView({\n ctl,\n views,\n activeView,\n dirty,\n onRequestDelete,\n}: {\n ctl: SavedViewsController;\n views: SavedViewSummary[];\n activeView: SavedViewSummary | undefined;\n dirty: boolean;\n /** Opens the confirmation; the delete itself happens on confirm. */\n onRequestDelete: (view: SavedViewSummary) => void;\n}): DisplayPanelView {\n return {\n activeViewName: ctl.activeViewName,\n dirty,\n onReset: () => (activeView ? ctl.applyView(activeView) : ctl.selectMain()),\n // Only offer \"Atualizar\" when there IS a view to update — otherwise the\n // single footer button is a plain \"Salvar visão\".\n onUpdate: activeView ? () => ctl.openEdit(activeView) : undefined,\n onSaveAs: ctl.openCreate,\n // The views themselves, not a dropdown: the panel renders them in its own\n // body (see `data-views-view-nav`), so there is no second popover to clip\n // the row actions.\n nav: {\n views,\n activeViewId: activeView?.id ?? null,\n onSelectView: (id) => {\n const next = id === null ? null : views.find((view) => view.id === id);\n if (next) ctl.applyView(next);\n else ctl.selectMain();\n },\n onEditView: ctl.openEdit,\n onPatchView: (view, changes) => void ctl.patchView(view, changes),\n onDeleteView: onRequestDelete,\n },\n };\n}\n\n/**\n * \"Are there unsaved changes?\" — the dot on Exibir, and whether Redefinir and\n * Salvar visão are live.\n *\n * Two things it gets right that the inline version did not. It compares\n * NORMALISED states (`viewStateKey`), so a filter applied and then removed is\n * clean again rather than clean-looking but flagged; and it re-baselines after\n * a SAVE, because the state just written is the clean one from that point.\n *\n * The baseline is the first state the grid emits for a view, not the view\n * itself: the grid normalises what it is handed — resolving visible columns,\n * filling in layout — so the applied view is never byte-identical to the state\n * it produces.\n */\nfunction useDirtyTracking(ctl: SavedViewsController): {\n dirty: boolean;\n noteState: (state: DataViewState) => void;\n markSaved: () => void;\n} {\n const [dirty, setDirty] = useState(false);\n const [savedAt, setSavedAt] = useState(0);\n const baseline = useRef<string | null>(null);\n const appliedKey = JSON.stringify(ctl.applied ?? null);\n\n useEffect(() => {\n baseline.current = null;\n setDirty(false);\n }, [appliedKey, savedAt]);\n\n return {\n dirty,\n noteState: (state) => {\n ctl.currentRef.current = state;\n const key = viewStateKey(state);\n if (baseline.current === null) {\n baseline.current = key;\n setDirty(false);\n return;\n }\n const next = key !== baseline.current;\n setDirty((prev) => (prev === next ? prev : next));\n },\n markSaved: () => setSavedAt((tick) => tick + 1),\n };\n}\n\n/**\n * The reusable admin table (FUT-89): the DataViews grid plus the full saved-views\n * experience — a views dropdown, a save/edit modal (with preview), and a manage\n * dialog. Framework-agnostic: saved-view persistence and router side-effects are\n * INJECTED (`persistence`, `router`, `initialViewId`) so the host app wires them\n * to its backend + framework router. A default view auto-applies on load; applying\n * a view restores its filters + columns + sort. Each table supplies its own columns\n * + filter fields; everything else is shared.\n */\nexport function DataViewsTableBase<T extends Record<string, unknown>>(\n props: DataViewsTableBaseProps<T>,\n): React.JSX.Element {\n // Forwarded as a whole rather than restated name-by-name twice (as in\n // DataViewsGrid): this component only ADDS the saved-views chrome, and a\n // 30-name destructure repeated in the JSX is exactly where a newly added prop\n // silently stops being passed on.\n const {\n initialViewId = null,\n persistence,\n router,\n columns,\n fields,\n testIdPrefix = \"table\",\n views,\n server,\n initialState,\n } = props;\n const initialView = resolveInitialView(views, initialViewId);\n const columnIds = columns.map((col) => col.id);\n const ctl = useSavedViewsController(persistence, router, columnIds, views, initialView, initialState);\n // Unsaved-changes flag for the Exibir panel. Set from `onStateChange` rather\n // than derived in render because the live state lives in a REF (the grid owns\n // it); the equality bail-out in `setDirty` is what stops the update loop.\n const { dirty, noteState, markSaved } = useDirtyTracking(ctl);\n // Deleting a saved view is confirmed, not immediate — see `DeleteViewDialog`.\n const [pendingDelete, setPendingDelete] = useState<SavedViewSummary | null>(null);\n // The view the panel's \"Redefinir\" restores: the applied one, or the built-in\n // \"Visão principal\" when none is.\n const activeView = views.find((view) => view.name === ctl.activeViewName);\n const displayView = buildDisplayView({\n ctl,\n views,\n activeView,\n dirty,\n onRequestDelete: setPendingDelete,\n });\n // Server-mode lists re-apply URL-derived controls on back/forward (not just\n // the mount seed), but never the grid's own query echoing back through the URL.\n const echo = useUrlEchoGuard(server);\n const syncState = useUrlSyncState(echo.server, initialState, echo.consumeEcho);\n\n return (\n <>\n <ViewMutationErrorAlert error={ctl.mutationError} onClose={ctl.clearMutationError} testIdPrefix={testIdPrefix} />\n <DataViewsGrid<T>\n {...props}\n server={echo.server}\n testIdPrefix={testIdPrefix}\n appliedState={ctl.applied}\n syncState={syncState}\n onStateChange={noteState}\n // The saved-views menu is NOT a toolbar control any more: it lives in\n // the Exibir panel's VISÃO header, passed through `displayView`.\n displayView={displayView}\n />\n {renderViewDialogs(ctl, fields, columns, views, testIdPrefix, markSaved)}\n <DeleteViewDialog\n view={pendingDelete}\n onClose={() => setPendingDelete(null)}\n onConfirm={(view) => {\n void ctl.handleDelete(view);\n setPendingDelete(null);\n }}\n testIdPrefix={testIdPrefix}\n />\n </>\n );\n}\n\n/** The save + manage saved-view dialogs, split out to keep the base thin. */\nfunction renderViewDialogs<T extends Record<string, unknown>>(\n ctl: SavedViewsController,\n fields: DataViewsTableBaseProps<T>[\"fields\"],\n columns: DataViewsTableBaseProps<T>[\"columns\"],\n views: SavedViewSummary[],\n testIdPrefix: string,\n onSaved: () => void,\n): React.JSX.Element {\n return (\n <ViewDialogs<T>\n saveOpen={ctl.saveOpen}\n onCloseSave={ctl.closeSave}\n currentState={ctl.editing ? ctl.editing.state : ctl.currentRef.current}\n fields={fields}\n columns={columns}\n editing={ctl.editing}\n onSave={async (payload) => {\n await ctl.handleSave(payload);\n // The saved state is the clean one from here on.\n onSaved();\n }}\n manageOpen={ctl.manageOpen}\n onCloseManage={() => ctl.setManageOpen(false)}\n views={views}\n onEditFromManage={ctl.editFromManage}\n onDelete={(view) => void ctl.handleDelete(view)}\n testIdPrefix={testIdPrefix}\n />\n );\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Avatar
3
- } from "./chunk-KARMRTTM.js";
3
+ } from "./chunk-J2RUDZVJ.js";
4
4
  import {
5
5
  Card
6
6
  } from "./chunk-W2RXXF7K.js";
@@ -74,4 +74,4 @@ export {
74
74
  UserAvatar,
75
75
  UserMenu
76
76
  };
77
- //# sourceMappingURL=chunk-MJ6EAND6.js.map
77
+ //# sourceMappingURL=chunk-Q7BGMLCX.js.map
@@ -1,10 +1,10 @@
1
- import {
2
- buildChartContext
3
- } from "./chunk-TZC6KIK2.js";
4
1
  import {
5
2
  ChartLegendContent,
6
3
  ChartTooltipContent
7
4
  } from "./chunk-RIRTW5EU.js";
5
+ import {
6
+ buildChartContext
7
+ } from "./chunk-TZC6KIK2.js";
8
8
  import {
9
9
  uiInk
10
10
  } from "./chunk-XJAD6E3V.js";
@@ -318,4 +318,4 @@ function renderChartByType(props, theme) {
318
318
  export {
319
319
  renderChartByType
320
320
  };
321
- //# sourceMappingURL=chunk-6ATXOJVQ.js.map
321
+ //# sourceMappingURL=chunk-QADTI63U.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  GridShell
3
- } from "./chunk-L7OWFJUU.js";
3
+ } from "./chunk-5RC7WAHH.js";
4
4
  import {
5
5
  useDataViewsState
6
- } from "./chunk-35L5YMYQ.js";
6
+ } from "./chunk-2QB4WIU5.js";
7
7
 
8
8
  // src/components/data-display/DataViews/DataViewsGrid.tsx
9
9
  import { useEffect, useRef } from "react";
@@ -27,4 +27,4 @@ function DataViewsGrid(props) {
27
27
  export {
28
28
  DataViewsGrid
29
29
  };
30
- //# sourceMappingURL=chunk-M6V7Y7CP.js.map
30
+ //# sourceMappingURL=chunk-QAZLQYSD.js.map