@nextelco/common-ui 2.1.106 → 2.1.107

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 (177) hide show
  1. package/dist/esm/index.js +201 -145
  2. package/dist/esm/index.js.map +1 -1
  3. package/dist/esm/legacy/components/atoms/InputData/InputData.js +2 -13
  4. package/dist/esm/legacy/components/atoms/InputData/InputData.js.map +1 -1
  5. package/dist/esm/legacy/components/charts/Charts.js +147 -57
  6. package/dist/esm/legacy/components/charts/Charts.js.map +1 -1
  7. package/dist/esm/legacy/components/layout/Layout/Layout.js +21 -82
  8. package/dist/esm/legacy/components/layout/Layout/Layout.js.map +1 -1
  9. package/dist/esm/legacy/components/layout/Sidebar/Sidebar.js +29 -218
  10. package/dist/esm/legacy/components/layout/Sidebar/Sidebar.js.map +1 -1
  11. package/dist/esm/legacy/components/molecules/ColumnPicker/ColumnPicker.js +77 -10
  12. package/dist/esm/legacy/components/molecules/ColumnPicker/ColumnPicker.js.map +1 -1
  13. package/dist/esm/legacy/components/molecules/DataTable/DataTable.js +445 -337
  14. package/dist/esm/legacy/components/molecules/DataTable/DataTable.js.map +1 -1
  15. package/dist/esm/legacy/components/molecules/UserAvatar/UserAvatar.js +15 -97
  16. package/dist/esm/legacy/components/molecules/UserAvatar/UserAvatar.js.map +1 -1
  17. package/dist/esm/legacy/components/organisms/MapaPontos/MapaPontos.js +3 -3
  18. package/dist/esm/legacy/components/organisms/MapaPontos/MapaPontos.js.map +1 -1
  19. package/dist/esm/legacy/components/organisms/PainelFiltros/PainelFiltros.js +15 -3
  20. package/dist/esm/legacy/components/organisms/PainelFiltros/PainelFiltros.js.map +1 -1
  21. package/dist/esm/legacy/components/organisms/Selector/Selector.js +4 -4
  22. package/dist/esm/legacy/components/organisms/Selector/Selector.js.map +1 -1
  23. package/dist/esm/legacy/components/ui/Avisos.js +23 -76
  24. package/dist/esm/legacy/components/ui/Avisos.js.map +1 -1
  25. package/dist/esm/legacy/components/ui/CabecalhoPagina.js +14 -27
  26. package/dist/esm/legacy/components/ui/CabecalhoPagina.js.map +1 -1
  27. package/dist/esm/legacy/components/ui/CaixaPesquisa.js +3 -51
  28. package/dist/esm/legacy/components/ui/CaixaPesquisa.js.map +1 -1
  29. package/dist/esm/legacy/components/ui/Confirmacao.js +13 -31
  30. package/dist/esm/legacy/components/ui/Confirmacao.js.map +1 -1
  31. package/dist/esm/legacy/components/ui/Escolha.js +21 -137
  32. package/dist/esm/legacy/components/ui/Escolha.js.map +1 -1
  33. package/dist/esm/legacy/components/ui/FaixaAviso.js +13 -11
  34. package/dist/esm/legacy/components/ui/FaixaAviso.js.map +1 -1
  35. package/dist/esm/legacy/components/ui/Separadores.js +11 -46
  36. package/dist/esm/legacy/components/ui/Separadores.js.map +1 -1
  37. package/dist/esm/legacy/components/ui/Ui.js +18 -115
  38. package/dist/esm/legacy/components/ui/Ui.js.map +1 -1
  39. package/dist/esm/legacy/components/ui/painelFlutuante.js +5 -44
  40. package/dist/esm/legacy/components/ui/painelFlutuante.js.map +1 -1
  41. package/dist/esm/v1/capabilities/overlay/useFloatingPanel.js +52 -0
  42. package/dist/esm/v1/capabilities/overlay/useFloatingPanel.js.map +1 -0
  43. package/dist/esm/v1/capabilities/theme/useIsDark.js +15 -0
  44. package/dist/esm/v1/capabilities/theme/useIsDark.js.map +1 -0
  45. package/dist/esm/v1/capabilities/theme/useTheme.js +66 -0
  46. package/dist/esm/v1/capabilities/theme/useTheme.js.map +1 -0
  47. package/dist/esm/v1/components/data/Pagination/Pagination.js +66 -0
  48. package/dist/esm/v1/components/data/Pagination/Pagination.js.map +1 -0
  49. package/dist/esm/v1/components/feedback/Toast/Toast.js +105 -0
  50. package/dist/esm/v1/components/feedback/Toast/Toast.js.map +1 -0
  51. package/dist/esm/v1/components/layout/AppShell/AppShell.js +89 -0
  52. package/dist/esm/v1/components/layout/AppShell/AppShell.js.map +1 -0
  53. package/dist/esm/v1/components/layout/Page/Page.js +16 -0
  54. package/dist/esm/v1/components/layout/Page/Page.js.map +1 -0
  55. package/dist/esm/v1/components/layout/PageHeader/PageHeader.js +26 -0
  56. package/dist/esm/v1/components/layout/PageHeader/PageHeader.js.map +1 -0
  57. package/dist/esm/v1/components/layout/SideNav/SideNav.js +277 -0
  58. package/dist/esm/v1/components/layout/SideNav/SideNav.js.map +1 -0
  59. package/dist/esm/v1/components/layout/navTrail.js +19 -0
  60. package/dist/esm/v1/components/layout/navTrail.js.map +1 -0
  61. package/dist/esm/v1/components/overlays/ConfirmDialog/ConfirmDialog.js +95 -0
  62. package/dist/esm/v1/components/overlays/ConfirmDialog/ConfirmDialog.js.map +1 -0
  63. package/dist/esm/v1/components/overlays/Dialog/Dialog.js.map +1 -1
  64. package/dist/esm/v1/components/overlays/Tooltip/Tooltip.js +98 -0
  65. package/dist/esm/v1/components/overlays/Tooltip/Tooltip.js.map +1 -0
  66. package/dist/esm/v1/components/overlays/Tooltip/TooltipLayer.js +84 -0
  67. package/dist/esm/v1/components/overlays/Tooltip/TooltipLayer.js.map +1 -0
  68. package/dist/esm/v1/components/overlays/Tooltip/TooltipPanel.js +33 -0
  69. package/dist/esm/v1/components/overlays/Tooltip/TooltipPanel.js.map +1 -0
  70. package/dist/esm/v1/components/overlays/topLayer.js +28 -0
  71. package/dist/esm/v1/components/overlays/topLayer.js.map +1 -0
  72. package/dist/esm/v1/foundations/icons/icons.js +61 -2
  73. package/dist/esm/v1/foundations/icons/icons.js.map +1 -1
  74. package/dist/esm/v1/primitives/buttons/Button/Button.js +18 -4
  75. package/dist/esm/v1/primitives/buttons/Button/Button.js.map +1 -1
  76. package/dist/esm/v1/primitives/buttons/SegmentedControl/SegmentedControl.js +65 -0
  77. package/dist/esm/v1/primitives/buttons/SegmentedControl/SegmentedControl.js.map +1 -0
  78. package/dist/esm/v1/primitives/buttons/SegmentedControl/segmentedStyles.js +10 -0
  79. package/dist/esm/v1/primitives/buttons/SegmentedControl/segmentedStyles.js.map +1 -0
  80. package/dist/esm/v1/primitives/display/Avatar/Avatar.js +120 -0
  81. package/dist/esm/v1/primitives/display/Avatar/Avatar.js.map +1 -0
  82. package/dist/esm/v1/primitives/display/Badge/Badge.js +23 -0
  83. package/dist/esm/v1/primitives/display/Badge/Badge.js.map +1 -0
  84. package/dist/esm/v1/primitives/display/Card/Card.js +22 -0
  85. package/dist/esm/v1/primitives/display/Card/Card.js.map +1 -0
  86. package/dist/esm/v1/primitives/display/FilterChips/FilterChips.js +45 -0
  87. package/dist/esm/v1/primitives/display/FilterChips/FilterChips.js.map +1 -0
  88. package/dist/esm/v1/primitives/display/Kpi/Kpi.js +103 -0
  89. package/dist/esm/v1/primitives/display/Kpi/Kpi.js.map +1 -0
  90. package/dist/esm/v1/primitives/display/Notice/Notice.js +71 -0
  91. package/dist/esm/v1/primitives/display/Notice/Notice.js.map +1 -0
  92. package/dist/esm/v1/primitives/display/Person/Person.js +14 -0
  93. package/dist/esm/v1/primitives/display/Person/Person.js.map +1 -0
  94. package/dist/esm/v1/primitives/forms/Checkbox/Checkbox.js +1 -1
  95. package/dist/esm/v1/primitives/forms/Checkbox/Checkbox.js.map +1 -1
  96. package/dist/esm/v1/primitives/forms/DateInput/DateInput.js +150 -0
  97. package/dist/esm/v1/primitives/forms/DateInput/DateInput.js.map +1 -0
  98. package/dist/esm/v1/primitives/forms/SearchInput/SearchInput.js +43 -0
  99. package/dist/esm/v1/primitives/forms/SearchInput/SearchInput.js.map +1 -0
  100. package/dist/esm/v1/primitives/forms/SelectInput/SelectInput.js +190 -12
  101. package/dist/esm/v1/primitives/forms/SelectInput/SelectInput.js.map +1 -1
  102. package/dist/esm/v1/primitives/forms/field.js +4 -2
  103. package/dist/esm/v1/primitives/forms/field.js.map +1 -1
  104. package/dist/esm/v1/primitives/navigation/Tabs/Tabs.js +96 -0
  105. package/dist/esm/v1/primitives/navigation/Tabs/Tabs.js.map +1 -0
  106. package/dist/style.components.css +1 -1
  107. package/dist/style.css +1 -1
  108. package/dist/style.layered.css +1 -1
  109. package/dist/tailwind.css +24 -0
  110. package/dist/theme-boot.js +1 -0
  111. package/dist/theme.css +10 -3
  112. package/dist/tokens.css +119 -0
  113. package/dist/types/legacy/components/atoms/InputData/InputData.d.ts +4 -1
  114. package/dist/types/legacy/components/charts/Charts.d.ts +58 -5
  115. package/dist/types/legacy/components/layout/Layout/Layout.d.ts +7 -20
  116. package/dist/types/legacy/components/layout/Sidebar/Sidebar.d.ts +13 -26
  117. package/dist/types/legacy/components/molecules/ColumnPicker/ColumnPicker.d.ts +56 -3
  118. package/dist/types/legacy/components/molecules/DataTable/DataTable.d.ts +72 -7
  119. package/dist/types/legacy/components/molecules/UserAvatar/UserAvatar.d.ts +4 -5
  120. package/dist/types/legacy/components/ui/Avisos.d.ts +6 -16
  121. package/dist/types/legacy/components/ui/CabecalhoPagina.d.ts +6 -20
  122. package/dist/types/legacy/components/ui/CaixaPesquisa.d.ts +2 -4
  123. package/dist/types/legacy/components/ui/Confirmacao.d.ts +3 -10
  124. package/dist/types/legacy/components/ui/Escolha.d.ts +5 -15
  125. package/dist/types/legacy/components/ui/FaixaAviso.d.ts +2 -6
  126. package/dist/types/legacy/components/ui/Separadores.d.ts +3 -10
  127. package/dist/types/legacy/components/ui/Ui.d.ts +12 -54
  128. package/dist/types/legacy/components/ui/painelFlutuante.d.ts +6 -10
  129. package/dist/types/legacy/exports/atoms.d.ts +1 -1
  130. package/dist/types/legacy/exports/charts.d.ts +2 -2
  131. package/dist/types/legacy/exports/hooks.d.ts +2 -2
  132. package/dist/types/legacy/exports/molecules.d.ts +2 -2
  133. package/dist/types/v1/capabilities/overlay/useFloatingPanel.d.ts +20 -0
  134. package/dist/types/v1/capabilities/theme/useIsDark.d.ts +10 -0
  135. package/dist/types/v1/capabilities/theme/useTheme.d.ts +29 -0
  136. package/dist/types/v1/components/data/Pagination/Pagination.d.ts +33 -0
  137. package/dist/types/v1/components/feedback/Toast/Toast.d.ts +51 -0
  138. package/dist/types/v1/components/layout/AppShell/AppShell.d.ts +35 -0
  139. package/dist/types/v1/components/layout/Page/Page.d.ts +23 -0
  140. package/dist/types/v1/components/layout/PageHeader/PageHeader.d.ts +35 -0
  141. package/dist/types/v1/components/layout/SideNav/SideNav.d.ts +92 -0
  142. package/dist/types/v1/components/layout/navTrail.d.ts +15 -0
  143. package/dist/types/v1/components/overlays/ConfirmDialog/ConfirmDialog.d.ts +59 -0
  144. package/dist/types/v1/components/overlays/Dialog/Dialog.d.ts +3 -2
  145. package/dist/types/v1/components/overlays/Tooltip/Tooltip.d.ts +34 -0
  146. package/dist/types/v1/components/overlays/Tooltip/TooltipLayer.d.ts +18 -0
  147. package/dist/types/v1/components/overlays/Tooltip/TooltipPanel.d.ts +23 -0
  148. package/dist/types/v1/components/overlays/topLayer.d.ts +23 -0
  149. package/dist/types/v1/foundations/icons/icons.d.ts +20 -0
  150. package/dist/types/v1/index.d.ts +43 -1
  151. package/dist/types/v1/primitives/buttons/Button/Button.d.ts +20 -5
  152. package/dist/types/v1/primitives/buttons/SegmentedControl/SegmentedControl.d.ts +28 -0
  153. package/dist/types/v1/primitives/buttons/SegmentedControl/segmentedStyles.d.ts +16 -0
  154. package/dist/types/v1/primitives/display/Avatar/Avatar.d.ts +30 -0
  155. package/dist/types/v1/primitives/display/Badge/Badge.d.ts +25 -0
  156. package/dist/types/v1/primitives/display/Card/Card.d.ts +22 -0
  157. package/dist/types/v1/primitives/display/FilterChips/FilterChips.d.ts +33 -0
  158. package/dist/types/v1/primitives/display/Kpi/Kpi.d.ts +68 -0
  159. package/dist/types/v1/primitives/display/Notice/Notice.d.ts +29 -0
  160. package/dist/types/v1/primitives/display/Person/Person.d.ts +15 -0
  161. package/dist/types/v1/primitives/forms/DateInput/DateInput.d.ts +43 -0
  162. package/dist/types/v1/primitives/forms/SearchInput/SearchInput.d.ts +23 -0
  163. package/dist/types/v1/primitives/forms/SelectInput/SelectInput.d.ts +60 -12
  164. package/dist/types/v1/primitives/forms/field.d.ts +2 -0
  165. package/dist/types/v1/primitives/navigation/Tabs/Tabs.d.ts +58 -0
  166. package/package.json +3 -3
  167. package/dist/esm/legacy/components/atoms/Tooltip/Tooltip.css +0 -17
  168. package/dist/esm/legacy/components/atoms/Tooltip/Tooltip.js +0 -41
  169. package/dist/esm/legacy/components/atoms/Tooltip/Tooltip.js.map +0 -1
  170. package/dist/esm/legacy/components/molecules/Search/Search.css +0 -18
  171. package/dist/esm/legacy/components/molecules/Search/Search.js +0 -30
  172. package/dist/esm/legacy/components/molecules/Search/Search.js.map +0 -1
  173. package/dist/esm/legacy/hooks/useTheme.js +0 -39
  174. package/dist/esm/legacy/hooks/useTheme.js.map +0 -1
  175. package/dist/types/legacy/components/atoms/Tooltip/Tooltip.d.ts +0 -13
  176. package/dist/types/legacy/components/molecules/Search/Search.d.ts +0 -7
  177. package/dist/types/legacy/hooks/useTheme.d.ts +0 -17
@@ -1,9 +1,11 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { useState, useEffect, useRef, useLayoutEffect, useMemo, Fragment } from "react";
3
- import Escolha from "../../ui/Escolha.js";
2
+ import { useState, useEffect, useMemo, useRef, useLayoutEffect, Fragment } from "react";
3
+ import { FilterChips } from "../../../../v1/primitives/display/FilterChips/FilterChips.js";
4
+ import { Pagination } from "../../../../v1/components/data/Pagination/Pagination.js";
4
5
  import { createPortal } from "react-dom";
5
6
  const DEFAULT_LABELS = {
6
7
  total: "Total",
8
+ scrollRegion: "Tabela (deslizar na horizontal)",
7
9
  results: "{count} results",
8
10
  resizeColumn: "Drag to resize · double-click to reset",
9
11
  export: "Export",
@@ -19,11 +21,17 @@ const DEFAULT_LABELS = {
19
21
  loadingOptions: "Loading options from all pages…",
20
22
  min: "From",
21
23
  max: "To",
24
+ from: "From",
25
+ to: "To",
22
26
  page: "Page {page}/{pages}",
23
27
  prev: "Prev",
24
28
  next: "Next",
25
29
  sortAsc: "Sort ascending",
26
30
  sortDesc: "Sort descending",
31
+ sortOldest: "Oldest first",
32
+ sortNewest: "Newest first",
33
+ sortSmallest: "Smallest first",
34
+ sortLargest: "Largest first",
27
35
  groupBy: "Group by {label}",
28
36
  ungroup: "Remove grouping by {label}",
29
37
  clearGroups: "Clear grouping",
@@ -37,6 +45,7 @@ const Layers = ({ size = 11, className }) => /* @__PURE__ */ jsxs("svg", { xmlns
37
45
  /* @__PURE__ */ jsx("path", { d: "m3 17 9 5 9-5M3 12l9 5 9-5" })
38
46
  ] });
39
47
  const Caret = ({ size = 11, className }) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", className, children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" }) });
48
+ const Spinner = ({ size = 16, className }) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", className: `animate-spin ${className ?? ""}`, "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) });
40
49
  const EMPTY = "—";
41
50
  const MAX_OPCOES_FILTRO = 50;
42
51
  const DEFAULT_STICKY_WIDTH = 160;
@@ -51,19 +60,70 @@ function rawValue(row, col) {
51
60
  if (typeof v === "number" || typeof v === "string") return v;
52
61
  return String(v);
53
62
  }
63
+ const normalizarRotulo = (v) => v == null || v === "" ? EMPTY : String(v);
54
64
  function filterKey(row, col) {
55
- const v = rawValue(row, col);
56
- return v == null || v === "" ? EMPTY : String(v);
65
+ return normalizarRotulo(rawValue(row, col));
66
+ }
67
+ function temValor(row, col) {
68
+ if (col.filterValues) return col.filterValues(row).some((v) => v != null && v !== "");
69
+ return rawValue(row, col) !== null;
70
+ }
71
+ function lerFiltrosGuardados(columns, f) {
72
+ return Object.fromEntries(
73
+ Object.entries(f).map(([k, v]) => {
74
+ const data = columns.find((c) => c.key === k)?.sortType === "date";
75
+ return [k, new Set(data ? v.map(rotuloDeData) : v)];
76
+ })
77
+ );
78
+ }
79
+ function chaveDosFiltros(f) {
80
+ return JSON.stringify(
81
+ Object.entries(f).map(([k, v]) => [k, [...v].sort()]).sort()
82
+ );
57
83
  }
58
84
  function timestampDeData(v) {
59
85
  if (v == null || v === "") return NaN;
60
86
  if (v instanceof Date) return v.getTime();
87
+ if (typeof v === "number") return Number.isFinite(v) ? v : NaN;
61
88
  const s = String(v).trim();
62
89
  const m = /^(\d{1,2})[/-](\d{1,2})[/-](\d{4})/.exec(s);
63
90
  if (m) return Date.UTC(Number(m[3]), Number(m[2]) - 1, Number(m[1]));
64
91
  const t = new Date(s).getTime();
65
92
  return Number.isNaN(t) ? NaN : t;
66
93
  }
94
+ const doisDigitos = (n) => String(n).padStart(2, "0");
95
+ const RX_CHAVE_DIA = /^(\d{4})-(\d{2})-(\d{2})$/;
96
+ function chaveDia(v) {
97
+ if (v == null || v === "") return null;
98
+ if (typeof v === "string") {
99
+ const s = v.trim();
100
+ const pt = /^(\d{1,2})[/-](\d{1,2})[/-](\d{4})/.exec(s);
101
+ if (pt) return `${pt[3]}-${doisDigitos(pt[2])}-${doisDigitos(pt[1])}`;
102
+ if (RX_CHAVE_DIA.test(s)) return s;
103
+ }
104
+ const t = timestampDeData(v);
105
+ if (!Number.isFinite(t)) return null;
106
+ const d = new Date(t);
107
+ return `${d.getFullYear()}-${doisDigitos(d.getMonth() + 1)}-${doisDigitos(d.getDate())}`;
108
+ }
109
+ function rotuloDeData(v) {
110
+ if (v == null || v === "") return EMPTY;
111
+ return chaveDia(v) ?? String(v);
112
+ }
113
+ function diaVisivel(v) {
114
+ const m = RX_CHAVE_DIA.exec(v);
115
+ return m ? `${m[3]}/${m[2]}/${m[1]}` : v;
116
+ }
117
+ function ordenarDias(a, b) {
118
+ if (a === EMPTY) return 1;
119
+ if (b === EMPTY) return -1;
120
+ const da = RX_CHAVE_DIA.test(a);
121
+ const db = RX_CHAVE_DIA.test(b);
122
+ if (da && db) return a < b ? 1 : a > b ? -1 : 0;
123
+ if (da) return -1;
124
+ if (db) return 1;
125
+ return COLLATOR.compare(a, b);
126
+ }
67
127
  function compare(a, b, type) {
68
128
  if (a == null && b == null) return 0;
69
129
  if (a == null) return 1;
@@ -122,6 +182,7 @@ function DataTable({
122
182
  onDataNeeded,
123
183
  isAllDataLoading,
124
184
  alwaysClient,
185
+ totalCount,
125
186
  onClientModeChange,
126
187
  rowKey,
127
188
  onRowClick,
@@ -135,6 +196,8 @@ function DataTable({
135
196
  pageSizeOptions,
136
197
  selectable,
137
198
  onSelectionChange,
199
+ isRowSelectable,
200
+ initialSelectedKeys,
138
201
  clearSelectionTrigger,
139
202
  storageKey,
140
203
  defaultMaxColumnWidth = 360,
@@ -151,7 +214,12 @@ function DataTable({
151
214
  emptyIcon,
152
215
  labels,
153
216
  totalRow = false,
154
- defaultGroupBy
217
+ defaultGroupBy,
218
+ groupBy,
219
+ onGroupByChange,
220
+ onSortChange,
221
+ onColumnFiltersChange,
222
+ scrollAffordance = false
155
223
  }) {
156
224
  const L = { ...DEFAULT_LABELS, ...labels };
157
225
  const [larguras, setLarguras] = useState(() => {
@@ -210,8 +278,7 @@ function DataTable({
210
278
  try {
211
279
  const raw = sessionStorage.getItem(`dt_filters_${storageKey}`);
212
280
  if (!raw) return {};
213
- const parsed = JSON.parse(raw);
214
- return Object.fromEntries(Object.entries(parsed).map(([k, v]) => [k, new Set(v)]));
281
+ return lerFiltrosGuardados(columns, JSON.parse(raw));
215
282
  } catch {
216
283
  return {};
217
284
  }
@@ -225,17 +292,27 @@ function DataTable({
225
292
  return {};
226
293
  }
227
294
  });
228
- const [groupByKeys, setGroupByKeys] = useState(
295
+ const [groupByInterno, setGroupByInterno] = useState(
229
296
  () => (lerSessao("group") ?? defaultGroupBy ?? []).filter((k) => columns.some((c) => c.key === k))
230
297
  );
298
+ const grupoControlado = groupBy !== void 0;
299
+ const chaveGrupoExterno = groupBy?.join("\0");
300
+ const chaveColunas = columns.map((c) => c.key).join("\0");
301
+ const groupByKeys = useMemo(
302
+ () => grupoControlado ? groupBy.filter((k) => columns.some((c) => c.key === k)) : groupByInterno,
303
+ // eslint-disable-next-line react-hooks/exhaustive-deps
304
+ [grupoControlado, chaveGrupoExterno, groupByInterno, chaveColunas]
305
+ );
231
306
  const [collapsedGroups, setCollapsedGroups] = useState(/* @__PURE__ */ new Set());
232
- const [selectedKeys, setSelectedKeys] = useState(/* @__PURE__ */ new Set());
307
+ const selecaoInicial = initialSelectedKeys ? Array.from(initialSelectedKeys, String) : null;
308
+ const [selectedKeys, setSelectedKeys] = useState(() => new Set(selecaoInicial ?? []));
233
309
  const [openFilter, setOpenFilter] = useState(null);
234
310
  const [filterSearch, setFilterSearch] = useState("");
235
311
  const filterRefs = useRef(/* @__PURE__ */ new Map());
236
312
  const popupRef = useRef(null);
237
313
  const [popupPos, setPopupPos] = useState(null);
238
314
  const isGrouped = groupByKeys.length > 0;
315
+ const funilAberto = openFilter ? columns.find((c) => c.key === openFilter || c.extraFilters?.some((f) => f.key === openFilter))?.key ?? openFilter : null;
239
316
  useEffect(() => {
240
317
  if (!storageKey) return;
241
318
  const serializavel = Object.fromEntries(Object.entries(columnFilters).map(([k, v]) => [k, Array.from(v)]));
@@ -243,17 +320,17 @@ function DataTable({
243
320
  sessionStorage.setItem(`dt_filters_${storageKey}`, JSON.stringify(serializavel));
244
321
  sessionStorage.setItem(`dt_ranges_${storageKey}`, JSON.stringify(rangeFilters));
245
322
  sessionStorage.setItem(`dt_sort_${storageKey}`, JSON.stringify(sort));
246
- sessionStorage.setItem(`dt_group_${storageKey}`, JSON.stringify(groupByKeys));
323
+ if (!grupoControlado) sessionStorage.setItem(`dt_group_${storageKey}`, JSON.stringify(groupByKeys));
247
324
  } catch {
248
325
  }
249
- }, [columnFilters, rangeFilters, sort, groupByKeys, storageKey]);
326
+ }, [columnFilters, rangeFilters, sort, groupByKeys, grupoControlado, storageKey]);
250
327
  useLayoutEffect(() => {
251
- if (!openFilter) {
328
+ if (!funilAberto) {
252
329
  setPopupPos(null);
253
330
  return;
254
331
  }
255
332
  const recalcular = () => {
256
- const el = filterRefs.current.get(openFilter);
333
+ const el = filterRefs.current.get(funilAberto);
257
334
  if (!el) return;
258
335
  const r = el.getBoundingClientRect();
259
336
  const largura = Math.min(288, window.innerWidth * 0.8);
@@ -267,19 +344,19 @@ function DataTable({
267
344
  window.removeEventListener("scroll", recalcular, true);
268
345
  window.removeEventListener("resize", recalcular);
269
346
  };
270
- }, [openFilter]);
347
+ }, [funilAberto]);
271
348
  useEffect(() => {
272
349
  const onDown = (e) => {
273
- if (!openFilter) return;
350
+ if (!funilAberto) return;
274
351
  const alvo = e.target;
275
- const botao = filterRefs.current.get(openFilter);
352
+ const botao = filterRefs.current.get(funilAberto);
276
353
  if (botao?.contains(alvo) || popupRef.current?.contains(alvo)) return;
277
354
  setOpenFilter(null);
278
355
  setFilterSearch("");
279
356
  };
280
357
  document.addEventListener("mousedown", onDown);
281
358
  return () => document.removeEventListener("mousedown", onDown);
282
- }, [openFilter]);
359
+ }, [funilAberto]);
283
360
  const resolverValor = (key) => {
284
361
  const col = columns.find((c) => c.key === key);
285
362
  if (col) return (row) => rawValue(row, col);
@@ -289,9 +366,34 @@ function DataTable({
289
366
  }
290
367
  return void 0;
291
368
  };
292
- const rotuloDe = (fn, row) => {
293
- const v = fn(row);
294
- return v == null || v === "" ? EMPTY : String(v);
369
+ const rotuloDe = (fn, row) => normalizarRotulo(fn(row));
370
+ const eColunaData = (key) => columns.find((c) => c.key === key)?.sortType === "date";
371
+ const resolverRotulos = (key) => {
372
+ const col = columns.find((c) => c.key === key);
373
+ const normalizar = col?.sortType === "date" ? rotuloDeData : (v) => normalizarRotulo(v);
374
+ if (col?.filterValues) {
375
+ const fv = col.filterValues;
376
+ return (row) => {
377
+ const vs = Array.from(new Set(fv(row).map(normalizar)));
378
+ return vs.length > 0 ? vs : [EMPTY];
379
+ };
380
+ }
381
+ if (col?.sortType === "date") {
382
+ const ler = col.value ?? ((row) => row[col.key]);
383
+ return (row) => [rotuloDeData(ler(row))];
384
+ }
385
+ const fn = resolverValor(key);
386
+ return fn ? (row) => [rotuloDe(fn, row)] : void 0;
387
+ };
388
+ const rotuloVisivel = (key, v) => eColunaData(key) ? diaVisivel(v) : v;
389
+ const passaFiltro = (key, sel) => {
390
+ const col = columns.find((c) => c.key === key);
391
+ if (col?.filterValues || col?.sortType === "date") {
392
+ const rotulos = resolverRotulos(key);
393
+ return (row) => rotulos(row).some((v) => sel.has(v));
394
+ }
395
+ const fn = resolverValor(key);
396
+ return fn ? (row) => sel.has(rotuloDe(fn, row)) : void 0;
295
397
  };
296
398
  const modoExcel = filterMode === "excel";
297
399
  const activeFilters = useMemo(
@@ -315,25 +417,51 @@ function DataTable({
315
417
  if (clearSelectionTrigger === void 0) return;
316
418
  setSelectedKeys(/* @__PURE__ */ new Set());
317
419
  }, [clearSelectionTrigger]);
318
- const chaveFiltrosCol = JSON.stringify(
319
- Object.entries(columnFilters).map(([k, v]) => [k, [...v].sort()]).sort()
320
- );
420
+ const chaveSelecaoInicial = selecaoInicial ? JSON.stringify([...selecaoInicial].sort()) : null;
421
+ const selecaoInicialAnterior = useRef(chaveSelecaoInicial);
321
422
  useEffect(() => {
423
+ if (chaveSelecaoInicial === selecaoInicialAnterior.current) return;
424
+ selecaoInicialAnterior.current = chaveSelecaoInicial;
425
+ if (chaveSelecaoInicial !== null) setSelectedKeys(new Set(JSON.parse(chaveSelecaoInicial)));
426
+ }, [chaveSelecaoInicial]);
427
+ const mudarFiltrosCol = (proximo) => {
428
+ const next = proximo(columnFilters);
429
+ if (chaveDosFiltros(next) === chaveDosFiltros(columnFilters)) return;
430
+ setColumnFilters(next);
322
431
  if (!selectable) return;
323
432
  setSelectedKeys(/* @__PURE__ */ new Set());
324
433
  onSelectionChange?.(/* @__PURE__ */ new Set());
325
- }, [chaveFiltrosCol]);
434
+ };
435
+ const avisarOrdenacao = useRef(onSortChange);
436
+ avisarOrdenacao.current = onSortChange;
437
+ const ordenacaoAvisada = useRef("null");
438
+ useEffect(() => {
439
+ const s = sort ? { key: sort.key, dir: sort.dir === 1 ? "asc" : "desc" } : null;
440
+ const chave = JSON.stringify(s);
441
+ if (chave === ordenacaoAvisada.current) return;
442
+ ordenacaoAvisada.current = chave;
443
+ avisarOrdenacao.current?.(s);
444
+ }, [sort]);
445
+ const avisarFiltros = useRef(onColumnFiltersChange);
446
+ avisarFiltros.current = onColumnFiltersChange;
447
+ const filtrosAvisados = useRef(chaveDosFiltros({}));
448
+ const chaveFiltrosAtivos = chaveDosFiltros(Object.fromEntries(activeFilters));
449
+ useEffect(() => {
450
+ if (chaveFiltrosAtivos === filtrosAvisados.current) return;
451
+ filtrosAvisados.current = chaveFiltrosAtivos;
452
+ avisarFiltros.current?.(Object.fromEntries(JSON.parse(chaveFiltrosAtivos)));
453
+ }, [chaveFiltrosAtivos]);
326
454
  const cruzFiltros = modoExcel ? SEM_CRUZAMENTO : activeFilters;
327
455
  const cruzRanges = modoExcel ? SEM_CRUZAMENTO : activeRanges;
328
456
  const distinctValues = (key) => {
329
- const valueFn = resolverValor(key);
330
- if (!valueFn) return [];
457
+ const rotulosFn = resolverRotulos(key);
458
+ if (!rotulosFn) return [];
331
459
  let fonte = allData ?? data;
332
460
  for (const [outraKey, escolhidos] of cruzFiltros) {
333
461
  if (outraKey === key) continue;
334
- const outraFn = resolverValor(outraKey);
335
- if (!outraFn) continue;
336
- fonte = fonte.filter((row) => escolhidos.has(rotuloDe(outraFn, row)));
462
+ const passa = passaFiltro(outraKey, escolhidos);
463
+ if (!passa) continue;
464
+ fonte = fonte.filter(passa);
337
465
  }
338
466
  for (const [outraKey, r] of cruzRanges) {
339
467
  if (outraKey === key) continue;
@@ -348,14 +476,18 @@ function DataTable({
348
476
  });
349
477
  }
350
478
  const set = /* @__PURE__ */ new Set();
351
- fonte.forEach((row) => set.add(rotuloDe(valueFn, row)));
352
- return Array.from(set).sort(ordenarRotulos);
479
+ fonte.forEach((row) => rotulosFn(row).forEach((v) => set.add(v)));
480
+ return Array.from(set).sort(eColunaData(key) ? ordenarDias : ordenarRotulos);
353
481
  };
354
482
  const openFilterOptions = useMemo(() => {
355
483
  if (!openFilter) return [];
356
484
  return distinctValues(openFilter);
357
485
  }, [openFilter, data, allData, columns, cruzFiltros, cruzRanges]);
358
- const openFilterOptionsLower = useMemo(() => openFilterOptions.map((v) => v.toLowerCase()), [openFilterOptions]);
486
+ const openFilterOptionsLower = useMemo(
487
+ () => openFilterOptions.map((v) => (openFilter ? rotuloVisivel(openFilter, v) : v).toLowerCase()),
488
+ // eslint-disable-next-line react-hooks/exhaustive-deps
489
+ [openFilterOptions]
490
+ );
359
491
  const opcoesVisiveis = useMemo(() => {
360
492
  const q = filterSearch.toLowerCase();
361
493
  const corresponde = q ? modoExcel ? pesquisaCuringa(q) : (v) => v.includes(q) : null;
@@ -370,11 +502,9 @@ function DataTable({
370
502
  }, [openFilterOptions, openFilterOptionsLower, filterSearch, modoExcel]);
371
503
  const filtrar = (rows) => {
372
504
  if (activeFilters.length === 0 && activeRanges.length === 0) return rows;
505
+ const predicados = activeFilters.flatMap(([key, sel]) => passaFiltro(key, sel) ?? []);
373
506
  return rows.filter(
374
- (row) => activeFilters.every(([key, sel]) => {
375
- const fn = resolverValor(key);
376
- return fn ? sel.has(rotuloDe(fn, row)) : true;
377
- }) && activeRanges.every(([key, r]) => {
507
+ (row) => predicados.every((passa) => passa(row)) && activeRanges.every(([key, r]) => {
378
508
  const col = columns.find((c) => c.key === key);
379
509
  if (!col) return true;
380
510
  const n = valorParaIntervalo(row, col);
@@ -406,19 +536,17 @@ function DataTable({
406
536
  useEffect(() => {
407
537
  avisarVisiveis.current?.(sorted);
408
538
  }, [sorted]);
409
- const alternarGrupo = (key) => {
410
- if (!allData) onDataNeeded?.();
411
- setGroupByKeys((prev) => prev.includes(key) ? prev.filter((k) => k !== key) : [...prev, key]);
412
- setCollapsedGroups(/* @__PURE__ */ new Set());
413
- };
414
- const removerGrupo = (key) => {
415
- setGroupByKeys((prev) => prev.filter((k) => k !== key));
539
+ const mudarGrupos = (proximo) => {
540
+ if (!grupoControlado) setGroupByInterno(proximo);
541
+ onGroupByChange?.(proximo);
416
542
  setCollapsedGroups(/* @__PURE__ */ new Set());
417
543
  };
418
- const limparGrupos = () => {
419
- setGroupByKeys([]);
420
- setCollapsedGroups(/* @__PURE__ */ new Set());
544
+ const alternarGrupo = (key) => {
545
+ if (!allData) onDataNeeded?.();
546
+ mudarGrupos(groupByKeys.includes(key) ? groupByKeys.filter((k) => k !== key) : [...groupByKeys, key]);
421
547
  };
548
+ const removerGrupo = (key) => mudarGrupos(groupByKeys.filter((k) => k !== key));
549
+ const limparGrupos = () => mudarGrupos([]);
422
550
  const alternarColapso = (path) => setCollapsedGroups((prev) => {
423
551
  const n = new Set(prev);
424
552
  if (n.has(path)) n.delete(path);
@@ -450,12 +578,34 @@ function DataTable({
450
578
  [sorted, groupByKeys, isGrouped, columns]
451
579
  );
452
580
  const [page, setPage] = useState(1);
453
- const [pageSizeAtual, setPageSizeAtual] = useState(pageSize);
454
- useEffect(() => setPageSizeAtual(pageSize), [pageSize]);
581
+ const chavePageSize = storageKey ? `dt_pagesize_${storageKey}` : null;
582
+ const [pageSizeAtual, setPageSizeAtual] = useState(() => {
583
+ if (!pageSize || !chavePageSize) return pageSize;
584
+ try {
585
+ const guardado = Number(sessionStorage.getItem(chavePageSize));
586
+ return Number.isFinite(guardado) && guardado > 0 ? guardado : pageSize;
587
+ } catch {
588
+ return pageSize;
589
+ }
590
+ });
591
+ const pageSizeProp = useRef(pageSize);
592
+ useEffect(() => {
593
+ if (pageSizeProp.current === pageSize) return;
594
+ pageSizeProp.current = pageSize;
595
+ setPageSizeAtual(pageSize);
596
+ }, [pageSize]);
597
+ const escolherPageSize = (n) => {
598
+ setPageSizeAtual(n);
599
+ if (!chavePageSize) return;
600
+ try {
601
+ sessionStorage.setItem(chavePageSize, String(n));
602
+ } catch {
603
+ }
604
+ };
455
605
  useEffect(() => {
456
606
  setPage(1);
457
- }, [columnFilters, rangeFilters, sort, groupByKeys, pageSizeAtual]);
458
- const paginando = !!pageSizeAtual && !isGrouped;
607
+ }, [columnFilters, rangeFilters, sort, groupByKeys, pageSizeAtual, isClientMode]);
608
+ const paginando = !!pageSizeAtual && !isGrouped && (!allData || isClientMode);
459
609
  const totalPages = paginando ? Math.max(1, Math.ceil(sorted.length / pageSizeAtual)) : 1;
460
610
  const currentPage = Math.min(page, totalPages);
461
611
  const pageData = paginando ? sorted.slice((currentPage - 1) * pageSizeAtual, currentPage * pageSizeAtual) : sorted;
@@ -465,10 +615,11 @@ function DataTable({
465
615
  sorted.forEach((r, i) => m.set(r, i));
466
616
  return m;
467
617
  }, [sorted]);
618
+ const podeSelecionar = (row) => !isRowSelectable || isRowSelectable(row);
468
619
  const visibleKeys = useMemo(
469
- () => pageData.map((row, i) => chaveDe(row, i)),
620
+ () => pageData.flatMap((row, i) => podeSelecionar(row) ? [chaveDe(row, i)] : []),
470
621
  // eslint-disable-next-line react-hooks/exhaustive-deps
471
- [pageData, rowKey]
622
+ [pageData, rowKey, isRowSelectable]
472
623
  );
473
624
  const alternarLinha = (key) => setSelectedKeys((prev) => {
474
625
  const next = new Set(prev);
@@ -502,11 +653,10 @@ function DataTable({
502
653
  groupBy: groupByKeys
503
654
  }),
504
655
  repor: (e) => {
505
- setColumnFilters(Object.fromEntries(Object.entries(e?.columnFilters ?? {}).map(([k, v]) => [k, new Set(v)])));
656
+ setColumnFilters(lerFiltrosGuardados(columns, e?.columnFilters ?? {}));
506
657
  setRangeFilters(e?.rangeFilters ?? {});
507
658
  setSort(e?.sortKey ? { key: e.sortKey, dir: e.sortDir === "desc" ? -1 : 1 } : null);
508
- setGroupByKeys(e?.groupBy ?? []);
509
- setCollapsedGroups(/* @__PURE__ */ new Set());
659
+ mudarGrupos(e?.groupBy ?? []);
510
660
  const precisaTudo = !!e?.sortKey || !!e?.groupBy?.length || Object.keys(e?.columnFilters ?? {}).length > 0 || Object.keys(e?.rangeFilters ?? {}).length > 0;
511
661
  if (precisaTudo && !allData) onDataNeeded?.();
512
662
  }
@@ -517,7 +667,7 @@ function DataTable({
517
667
  setSort((s) => s?.key === key ? s.dir === 1 ? { key, dir: -1 } : null : { key, dir: 1 });
518
668
  };
519
669
  const selecaoDaColuna = (key) => new Set(columnFilters[key] ?? (modoExcel ? openFilterOptions : []));
520
- const aplicarSelecao = (key, sel) => setColumnFilters((prev) => {
670
+ const aplicarSelecao = (key, sel) => mudarFiltrosCol((prev) => {
521
671
  const proximo = { ...prev };
522
672
  if (modoExcel && sel.size === openFilterOptions.length) delete proximo[key];
523
673
  else proximo[key] = sel;
@@ -553,7 +703,7 @@ function DataTable({
553
703
  });
554
704
  };
555
705
  const clearColumnFilter = (key) => {
556
- setColumnFilters((prev) => {
706
+ mudarFiltrosCol((prev) => {
557
707
  const n = { ...prev };
558
708
  delete n[key];
559
709
  return n;
@@ -565,7 +715,7 @@ function DataTable({
565
715
  });
566
716
  };
567
717
  const clearAllFilters = () => {
568
- setColumnFilters({});
718
+ mudarFiltrosCol(() => ({}));
569
719
  setRangeFilters({});
570
720
  };
571
721
  const temIntervalo = (key) => {
@@ -613,26 +763,41 @@ function DataTable({
613
763
  return void 0;
614
764
  };
615
765
  const nColunas = columns.length + (selectable ? 1 : 0);
616
- const aEsperarDataset = !allData && !!isAllDataLoading && (hasActiveFilters || !!sort || isGrouped);
766
+ const totalResultados = totalCount != null && !isClientMode && !hasActiveFilters ? totalCount : sorted.length;
767
+ const aEsperarDataset = !allData && (!!isAllDataLoading || !!onDataNeeded) && (hasActiveFilters || !!sort || isGrouped);
617
768
  const linhasBase = allData ?? data;
618
769
  const semDados = useMemo(
619
- () => new Set(columns.filter((c) => !linhasBase.some((r) => rawValue(r, c) !== null)).map((c) => c.key)),
770
+ () => new Set(columns.filter((c) => !linhasBase.some((r) => temValor(r, c))).map((c) => c.key)),
620
771
  [columns, linhasBase]
621
772
  );
622
773
  const filtravel = (c) => c.filterable ?? !semDados.has(c.key);
623
774
  const agrupavel = (c) => c.groupable ?? (!semDados.has(c.key) && !c.groupAggregate && (!c.sortType || c.sortType === "text"));
624
- if (isLoading) {
625
- return /* @__PURE__ */ jsx("div", { className: "py-16 text-center text-sm font-bold uppercase tracking-widest text-slate-400", children: L.loading });
626
- }
775
+ const rolarComTeclado = (e) => {
776
+ if (e.target !== e.currentTarget) return;
777
+ const el = e.currentTarget;
778
+ const passo = Math.max(40, Math.round(el.clientWidth * 0.2));
779
+ if (e.key === "ArrowRight") el.scrollLeft += passo;
780
+ else if (e.key === "ArrowLeft") el.scrollLeft -= passo;
781
+ else if (e.key === "Home") el.scrollLeft = 0;
782
+ else if (e.key === "End") el.scrollLeft = el.scrollWidth;
783
+ else return;
784
+ e.preventDefault();
785
+ };
627
786
  if (isError) {
628
787
  return /* @__PURE__ */ jsx("div", { className: "py-16 text-center text-sm font-bold uppercase tracking-widest text-red-400", children: L.error });
629
788
  }
630
- const renderPopup = (key, col, tituloExtra) => {
789
+ const renderPopup = (coluna, key, listas) => {
790
+ const col = key === coluna.key ? coluna : void 0;
631
791
  const { opts, total: totalOpcoes } = opcoesVisiveis;
632
792
  const sel = columnFilters[key];
633
793
  const isFiltered = temFiltro(key);
634
794
  const podeOrdenar = !!sortFromFilter && !!col && col.sortable !== false;
635
- const temRange = !!col && (col.sortType === "number" || col.sortType === "date");
795
+ const eData = col?.sortType === "date";
796
+ const temRange = !!col && (col.sortType === "number" || eData);
797
+ const [rotuloAsc, rotuloDesc] = eData ? [L.sortOldest, L.sortNewest] : col?.sortType === "number" ? [L.sortSmallest, L.sortLargest] : [L.sortAsc, L.sortDesc];
798
+ const [rotuloMin, rotuloMax] = eData ? [L.from, L.to] : [L.min, L.max];
799
+ const intervalo = rangeFilters[key];
800
+ const valorCampo = (n, campo) => n == null ? "" : eData ? new Date(campo === "max" ? n - 86399999 : n).toISOString().slice(0, 10) : String(n);
636
801
  return createPortal(
637
802
  /* @__PURE__ */ jsxs(
638
803
  "div",
@@ -641,7 +806,28 @@ function DataTable({
641
806
  style: { position: "fixed", top: popupPos.top, left: popupPos.left },
642
807
  className: "z-[100] w-72 max-w-[80vw] bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 shadow-2xl rounded-xl overflow-hidden",
643
808
  children: [
644
- tituloExtra && /* @__PURE__ */ jsx("div", { className: "px-3 pt-2.5 pb-2 border-b border-slate-100 dark:border-slate-800", children: /* @__PURE__ */ jsx("span", { className: "text-[9px] font-black uppercase tracking-widest text-proef-blue dark:text-proef-turquoise", children: tituloExtra }) }),
809
+ listas.length > 1 && // Seletor da lista a filtrar: a coluna e cada filtro extra partilham o mesmo funil.
810
+ /* @__PURE__ */ jsx("div", { className: "px-2 pt-2 pb-2 border-b border-slate-100 dark:border-slate-800", children: /* @__PURE__ */ jsx("div", { role: "group", "aria-label": coluna.label, className: "flex flex-wrap gap-0.5 p-0.5 rounded-lg bg-slate-100 dark:bg-slate-800", children: listas.map((l) => {
811
+ const ativa = l.key === key;
812
+ return /* @__PURE__ */ jsxs(
813
+ "button",
814
+ {
815
+ type: "button",
816
+ "aria-pressed": ativa,
817
+ onClick: () => {
818
+ if (ativa) return;
819
+ setOpenFilter(l.key);
820
+ setFilterSearch("");
821
+ },
822
+ className: `appearance-none border-0 cursor-pointer flex-1 min-w-0 inline-flex items-center justify-center gap-1 px-2 py-1 rounded-md text-[10px] font-black uppercase tracking-wider truncate transition-colors ${ativa ? "bg-white dark:bg-slate-900 text-proef-blue dark:text-proef-turquoise shadow-sm" : "bg-transparent text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200"}`,
823
+ children: [
824
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: l.label }),
825
+ temFiltro(l.key) && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "w-1.5 h-1.5 rounded-full bg-proef-turquoise shrink-0" })
826
+ ]
827
+ },
828
+ l.key
829
+ );
830
+ }) }) }),
645
831
  !allData && isAllDataLoading && // As opções à vista ainda são só as de `data`. Dizê-lo é melhor do que deixar
646
832
  // escolher de uma lista incompleta.
647
833
  /* @__PURE__ */ jsx("div", { className: "px-2 py-1.5 bg-amber-50 dark:bg-amber-500/10 border-b border-amber-100 dark:border-amber-500/20 text-[10px] text-amber-700 dark:text-amber-300", children: L.loadingOptions }),
@@ -656,7 +842,7 @@ function DataTable({
656
842
  className: `appearance-none bg-transparent border-0 cursor-pointer w-full flex items-center gap-2 px-2.5 py-1.5 text-[11px] font-semibold text-left hover:bg-slate-50 dark:hover:bg-slate-800 ${sort?.key === key && sort.dir === 1 ? "text-proef-blue dark:text-proef-turquoise bg-slate-50 dark:bg-slate-800" : "text-slate-600 dark:text-slate-300"}`,
657
843
  children: [
658
844
  "▲ ",
659
- L.sortAsc
845
+ rotuloAsc
660
846
  ]
661
847
  }
662
848
  ),
@@ -670,7 +856,7 @@ function DataTable({
670
856
  className: `appearance-none bg-transparent border-0 cursor-pointer w-full flex items-center gap-2 px-2.5 py-1.5 text-[11px] font-semibold text-left hover:bg-slate-50 dark:hover:bg-slate-800 ${sort?.key === key && sort.dir === -1 ? "text-proef-blue dark:text-proef-turquoise bg-slate-50 dark:bg-slate-800" : "text-slate-600 dark:text-slate-300"}`,
671
857
  children: [
672
858
  "▼ ",
673
- L.sortDesc
859
+ rotuloDesc
674
860
  ]
675
861
  }
676
862
  )
@@ -682,24 +868,28 @@ function DataTable({
682
868
  /* @__PURE__ */ jsx(
683
869
  "input",
684
870
  {
685
- type: col.sortType === "date" ? "date" : "number",
686
- defaultValue: "",
871
+ type: eData ? "date" : "number",
872
+ defaultValue: valorCampo(intervalo?.min, "min"),
687
873
  onChange: (e) => setRange(key, "min", e.target.value, col.sortType),
688
- placeholder: L.min,
689
- title: L.min,
874
+ placeholder: rotuloMin,
875
+ title: rotuloMin,
876
+ "aria-label": rotuloMin,
690
877
  className: "w-1/2 bg-slate-50 dark:bg-slate-800 dark:text-slate-100 dark:[color-scheme:dark] border border-slate-200 dark:border-slate-700 rounded-lg px-2 py-1.5 text-xs outline-none focus:border-proef-blue dark:focus:border-proef-turquoise"
691
- }
878
+ },
879
+ `${key}-min`
692
880
  ),
693
881
  /* @__PURE__ */ jsx(
694
882
  "input",
695
883
  {
696
- type: col.sortType === "date" ? "date" : "number",
697
- defaultValue: "",
884
+ type: eData ? "date" : "number",
885
+ defaultValue: valorCampo(intervalo?.max, "max"),
698
886
  onChange: (e) => setRange(key, "max", e.target.value, col.sortType),
699
- placeholder: L.max,
700
- title: L.max,
887
+ placeholder: rotuloMax,
888
+ title: rotuloMax,
889
+ "aria-label": rotuloMax,
701
890
  className: "w-1/2 bg-slate-50 dark:bg-slate-800 dark:text-slate-100 dark:[color-scheme:dark] border border-slate-200 dark:border-slate-700 rounded-lg px-2 py-1.5 text-xs outline-none focus:border-proef-blue dark:focus:border-proef-turquoise"
702
- }
891
+ },
892
+ `${key}-max`
703
893
  )
704
894
  ] }),
705
895
  /* @__PURE__ */ jsx(
@@ -753,7 +943,7 @@ function DataTable({
753
943
  children: checked && /* @__PURE__ */ jsx("span", { className: "text-[9px] leading-none", children: "✓" })
754
944
  }
755
945
  ),
756
- /* @__PURE__ */ jsx("span", { className: "text-xs text-slate-700 dark:text-slate-200 font-normal break-words", children: v })
946
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-slate-700 dark:text-slate-200 font-normal break-words", children: rotuloVisivel(key, v) })
757
947
  ]
758
948
  },
759
949
  v
@@ -776,16 +966,18 @@ function DataTable({
776
966
  document.body
777
967
  );
778
968
  };
779
- const botaoFunil = (key, col, extra) => {
780
- const isOpen = openFilter === key;
781
- const isFiltered = temFiltro(key);
969
+ const botaoFunil = (c) => {
970
+ const listas = [...filtravel(c) ? [{ key: c.key, label: c.label }] : [], ...(c.extraFilters ?? []).map((f) => ({ key: f.key, label: f.label }))];
971
+ if (listas.length === 0) return null;
972
+ const isOpen = funilAberto === c.key;
973
+ const isFiltered = listas.some((l) => temFiltro(l.key));
782
974
  return /* @__PURE__ */ jsxs(
783
975
  "div",
784
976
  {
785
977
  className: "relative",
786
978
  ref: (el) => {
787
- if (el) filterRefs.current.set(key, el);
788
- else filterRefs.current.delete(key);
979
+ if (el) filterRefs.current.set(c.key, el);
980
+ else filterRefs.current.delete(c.key);
789
981
  },
790
982
  children: [
791
983
  /* @__PURE__ */ jsx(
@@ -793,23 +985,26 @@ function DataTable({
793
985
  {
794
986
  onClick: () => {
795
987
  if (!isOpen && !allData) onDataNeeded?.();
796
- setOpenFilter(isOpen ? null : key);
988
+ setOpenFilter(isOpen ? null : listas[0].key);
797
989
  setFilterSearch("");
798
990
  },
799
- className: `appearance-none border-0 bg-transparent cursor-pointer p-0.5 transition-colors ${extra ? isFiltered || isOpen ? "text-violet-600 dark:text-violet-300" : "text-slate-300 dark:text-slate-600 hover:text-slate-500 dark:hover:text-slate-300" : isFiltered || isOpen ? "text-proef-turquoise" : "text-slate-300 dark:text-slate-600 hover:text-slate-500 dark:hover:text-slate-300"}`,
800
- title: extra?.label ?? col?.label,
801
- children: /* @__PURE__ */ jsx(Funnel, { size: extra ? 10 : 11, className: isFiltered ? "fill-current" : "" })
991
+ className: `appearance-none border-0 bg-transparent cursor-pointer p-0.5 transition-colors ${isFiltered || isOpen ? "text-proef-turquoise" : "text-slate-300 dark:text-slate-600 hover:text-slate-500 dark:hover:text-slate-300"}`,
992
+ title: c.label,
993
+ "aria-label": c.label,
994
+ "aria-expanded": isOpen,
995
+ children: /* @__PURE__ */ jsx(Funnel, { size: 11, className: isFiltered ? "fill-current" : "" })
802
996
  }
803
997
  ),
804
- isOpen && popupPos && renderPopup(key, col, extra?.label)
998
+ isOpen && popupPos && openFilter && renderPopup(c, openFilter, listas)
805
999
  ]
806
1000
  },
807
- key
1001
+ c.key
808
1002
  );
809
1003
  };
810
1004
  const renderLinha = (row, i) => {
811
1005
  const k = chaveDe(row, i);
812
1006
  const marcada = selectable && selectedKeys.has(k);
1007
+ const selecionavel = !!selectable && podeSelecionar(row);
813
1008
  return /* @__PURE__ */ jsxs(
814
1009
  "tr",
815
1010
  {
@@ -823,12 +1018,15 @@ function DataTable({
823
1018
  className: "px-3 py-2.5 border-b border-slate-100 dark:border-slate-800 w-10",
824
1019
  onClick: (e) => {
825
1020
  e.stopPropagation();
826
- alternarLinha(k);
1021
+ if (selecionavel) alternarLinha(k);
827
1022
  },
828
1023
  children: /* @__PURE__ */ jsx(
829
1024
  "span",
830
1025
  {
831
- className: `w-4 h-4 flex items-center justify-center border transition-colors rounded ${marcada ? "bg-proef-navy dark:bg-proef-turquoise border-proef-navy dark:border-proef-turquoise text-white dark:text-proef-navy" : "border-slate-300 dark:border-slate-600 hover:border-slate-400 dark:hover:border-slate-500"}`,
1026
+ role: "checkbox",
1027
+ "aria-checked": !!marcada,
1028
+ "aria-disabled": !selecionavel || void 0,
1029
+ className: `w-4 h-4 flex items-center justify-center border transition-colors rounded ${marcada ? "bg-proef-navy dark:bg-proef-turquoise border-proef-navy dark:border-proef-turquoise text-white dark:text-proef-navy" : "border-slate-300 dark:border-slate-600 hover:border-slate-400 dark:hover:border-slate-500"} ${selecionavel ? "" : "opacity-40 cursor-not-allowed bg-slate-100 dark:bg-slate-800"}`,
832
1030
  children: marcada && /* @__PURE__ */ jsx("span", { className: "text-[9px] leading-none", children: "✓" })
833
1031
  }
834
1032
  )
@@ -844,7 +1042,8 @@ function DataTable({
844
1042
  const max = larguraMax(c);
845
1043
  if (!max) return conteudo;
846
1044
  const v = rawValue(row, c);
847
- return /* @__PURE__ */ jsx("div", { className: "overflow-hidden text-ellipsis", style: { maxWidth: max, width: larguras[c.key] }, title: v !== null && v !== void 0 ? String(v) : void 0, children: conteudo });
1045
+ const dica = typeof conteudo === "string" || typeof conteudo === "number" ? String(conteudo) : c.sortType !== "date" && v !== null && v !== void 0 ? String(v) : void 0;
1046
+ return /* @__PURE__ */ jsx("div", { className: "overflow-hidden text-ellipsis", style: { maxWidth: max, width: larguras[c.key] }, title: dica, children: conteudo });
848
1047
  })()
849
1048
  },
850
1049
  c.key
@@ -882,9 +1081,9 @@ function DataTable({
882
1081
  ] }, no.path);
883
1082
  });
884
1083
  return /* @__PURE__ */ jsxs("div", { children: [
885
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-2.5", children: [
886
- /* @__PURE__ */ jsx("span", { className: "text-xs text-slate-500 dark:text-slate-400", children: L.results.replace("{count}", String(sorted.length)) }),
887
- /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-2", children: [
1084
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 mb-2.5", children: [
1085
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-slate-500 dark:text-slate-400", children: isLoading ? "" : L.results.replace("{count}", String(totalResultados)) }),
1086
+ /* @__PURE__ */ jsxs("div", { className: "ml-auto flex flex-wrap items-center justify-end gap-2", children: [
888
1087
  extraToolbar,
889
1088
  exportFileName && sorted.length > 0 && /* @__PURE__ */ jsxs(
890
1089
  "button",
@@ -899,248 +1098,157 @@ function DataTable({
899
1098
  )
900
1099
  ] })
901
1100
  ] }),
902
- isGrouped && /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center gap-2 flex-wrap", children: [
903
- groupByKeys.map((key) => {
904
- const col = columns.find((c) => c.key === key);
905
- return /* @__PURE__ */ jsxs(
906
- "div",
907
- {
908
- className: "flex items-center gap-1.5 bg-violet-100 dark:bg-violet-500/20 text-violet-800 dark:text-violet-200 px-2.5 py-1 text-[10px] font-black uppercase tracking-wider",
909
- children: [
910
- /* @__PURE__ */ jsx(Layers, { size: 9 }),
911
- /* @__PURE__ */ jsx("span", { children: col?.label ?? key }),
912
- /* @__PURE__ */ jsx(
913
- "button",
914
- {
915
- onClick: () => removerGrupo(key),
916
- className: "appearance-none bg-transparent border-0 cursor-pointer ml-0.5 hover:text-violet-600",
917
- children: "✕"
918
- }
919
- )
920
- ]
921
- },
922
- key
923
- );
924
- }),
925
- /* @__PURE__ */ jsx(
926
- "button",
927
- {
928
- onClick: limparGrupos,
929
- className: "appearance-none bg-transparent border-0 cursor-pointer text-[10px] font-black uppercase tracking-wider text-slate-400 hover:text-red-500 transition-colors",
930
- children: L.clearGroups
931
- }
932
- )
933
- ] }),
934
- (activeFilters.length > 0 || activeRanges.length > 0) && /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center gap-2 flex-wrap", children: [
935
- activeRanges.map(([key, r]) => {
936
- const col = columns.find((c) => c.key === key);
937
- const fmt = (v) => v == null ? "" : col?.sortType === "date" ? new Date(v).toLocaleDateString() : String(v);
938
- const txt = r.min != null && r.max != null ? `${fmt(r.min)} – ${fmt(r.max)}` : r.min != null ? `≥ ${fmt(r.min)}` : `≤ ${fmt(r.max)}`;
939
- return /* @__PURE__ */ jsxs(
940
- "div",
941
- {
942
- className: "flex items-center gap-1.5 bg-proef-turquoise/15 text-proef-navy dark:text-proef-turquoise px-2.5 py-1 text-[10px] font-black uppercase tracking-wider",
943
- children: [
944
- /* @__PURE__ */ jsxs("span", { children: [
945
- col?.label ?? key,
946
- ": ",
947
- txt
948
- ] }),
949
- /* @__PURE__ */ jsx(
950
- "button",
951
- {
952
- onClick: () => clearColumnFilter(key),
953
- className: "appearance-none bg-transparent border-0 cursor-pointer ml-0.5 hover:text-proef-blue dark:hover:text-proef-turquoise",
954
- children: "✕"
955
- }
956
- )
957
- ]
958
- },
959
- `r-${key}`
960
- );
961
- }),
962
- activeFilters.flatMap(([key, sel]) => {
963
- const col = columns.find((c) => c.key === key);
964
- const extra = !col ? columns.flatMap((c) => c.extraFilters ?? []).find((f) => f.key === key) : void 0;
965
- const chipLabel = col?.label ?? extra?.label ?? key;
966
- const arr = Array.from(sel);
967
- if (col?.valueChipColors) {
968
- const cores = col.valueChipColors;
969
- return arr.map((v) => /* @__PURE__ */ jsxs(
970
- "div",
971
- {
972
- className: `flex items-center gap-1.5 px-2.5 py-1 text-[10px] font-black uppercase tracking-wider ${cores[v] ?? "bg-proef-turquoise/15 text-proef-navy dark:text-proef-turquoise"}`,
973
- children: [
974
- /* @__PURE__ */ jsxs("span", { children: [
975
- chipLabel,
976
- ": ",
977
- v
978
- ] }),
979
- /* @__PURE__ */ jsx(
980
- "button",
981
- {
982
- onClick: () => toggleFilterValue(key, v),
983
- className: "appearance-none bg-transparent border-0 cursor-pointer ml-0.5 hover:opacity-70",
984
- children: "✕"
985
- }
986
- )
987
- ]
988
- },
989
- `${key}:${v}`
990
- ));
991
- }
992
- const txt = arr.length > 2 || arr.length === 0 ? L.selected.replace("{count}", String(arr.length)) : arr.join(", ");
993
- return [
994
- /* @__PURE__ */ jsxs(
995
- "div",
996
- {
997
- className: "flex items-center gap-1.5 bg-proef-turquoise/15 text-proef-navy dark:text-proef-turquoise px-2.5 py-1 text-[10px] font-black uppercase tracking-wider",
998
- children: [
999
- /* @__PURE__ */ jsxs("span", { children: [
1000
- chipLabel,
1001
- ": ",
1002
- txt
1003
- ] }),
1004
- /* @__PURE__ */ jsx(
1005
- "button",
1006
- {
1007
- onClick: () => clearColumnFilter(key),
1008
- className: "appearance-none bg-transparent border-0 cursor-pointer ml-0.5 hover:text-proef-blue dark:hover:text-proef-turquoise",
1009
- children: "✕"
1010
- }
1011
- )
1012
- ]
1013
- },
1014
- key
1015
- )
1016
- ];
1017
- }),
1018
- /* @__PURE__ */ jsx(
1019
- "button",
1020
- {
1021
- onClick: clearAllFilters,
1022
- className: "appearance-none bg-transparent border-0 cursor-pointer text-[10px] font-black uppercase tracking-wider text-slate-400 hover:text-red-500 transition-colors",
1023
- children: L.clearAll
1024
- }
1025
- )
1026
- ] }),
1027
- /* @__PURE__ */ jsx("div", { className: "overflow-auto rounded-xl border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900", style: { maxHeight }, children: /* @__PURE__ */ jsxs("table", { className: "w-full text-[13px] border-collapse dark:text-slate-200", children: [
1028
- /* @__PURE__ */ jsx("thead", { className: "sticky top-0 z-[2]", children: /* @__PURE__ */ jsxs("tr", { children: [
1029
- selectable && /* @__PURE__ */ jsx("th", { className: "bg-slate-50 dark:bg-slate-800 px-3 py-2.5 border-b border-slate-200 dark:border-slate-700 w-10 sticky left-0 z-[3]", children: /* @__PURE__ */ jsx(
1030
- "button",
1031
- {
1032
- onClick: alternarTodas,
1033
- className: `appearance-none cursor-pointer w-4 h-4 flex items-center justify-center border transition-colors rounded ${todasVisiveisMarcadas ? "bg-proef-navy dark:bg-proef-turquoise border-proef-navy dark:border-proef-turquoise text-white dark:text-proef-navy" : algumaVisivelMarcada ? "bg-slate-300 dark:bg-slate-600 border-slate-300 dark:border-slate-600 text-white" : "bg-white dark:bg-slate-900 border-slate-300 dark:border-slate-600 hover:border-slate-400 dark:hover:border-slate-500"}`,
1034
- children: (todasVisiveisMarcadas || algumaVisivelMarcada) && /* @__PURE__ */ jsx("span", { className: "text-[9px] leading-none", children: "✓" })
1035
- }
1036
- ) }),
1037
- columns.map((c) => {
1038
- temFiltro(c.key);
1039
- const podeOrdenar = c.sortable !== false;
1040
- const podeAgrupar = agrupavel(c);
1041
- const agrupada = groupByKeys.includes(c.key);
1042
- return /* @__PURE__ */ jsxs(
1043
- "th",
1044
- {
1045
- style: {
1046
- ...c.width ? { minWidth: c.width } : {},
1047
- ...larguras[c.key] ? { width: larguras[c.key], minWidth: larguras[c.key], maxWidth: larguras[c.key] } : {},
1048
- ...estiloPreso(c) ?? {}
1049
- },
1050
- className: `group/th relative bg-slate-50 dark:bg-slate-800 text-[11.5px] uppercase tracking-wide text-slate-500 dark:text-slate-400 font-semibold px-3 py-2.5 border-b border-slate-200 dark:border-slate-700 whitespace-nowrap select-none ${alignClass(
1051
- c.align
1052
- )} ${c.sticky ? `sticky z-[3] bg-slate-50 dark:bg-slate-800 ${c.sticky === "right" ? "border-l border-slate-200 dark:border-slate-700" : ""}` : ""} ${c.headerClassName ?? ""}`,
1053
- children: [
1054
- resizableColumns && // Pega no limite direito: arrastar redimensiona; duplo clique repõe a largura automática
1055
- /* @__PURE__ */ jsx(
1056
- "span",
1057
- {
1058
- role: "separator",
1059
- "aria-orientation": "vertical",
1060
- title: L.resizeColumn,
1061
- onMouseDown: (e) => iniciarResize(e, c.key),
1062
- onDoubleClick: () => reporLargura(c.key),
1063
- onClick: (e) => e.stopPropagation(),
1064
- className: "absolute right-0 top-0 z-[4] h-full w-1.5 cursor-col-resize bg-transparent hover:bg-proef-blue/40 group-hover/th:bg-slate-300/60 dark:group-hover/th:bg-slate-600/60"
1065
- }
1066
- ),
1067
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
1068
- podeOrdenar ? /* @__PURE__ */ jsxs(
1069
- "button",
1070
- {
1071
- onClick: () => toggleSort(c.key),
1072
- className: "appearance-none bg-transparent border-0 cursor-pointer p-0 uppercase tracking-wide text-slate-500 dark:text-slate-400 hover:text-proef-blue dark:hover:text-proef-turquoise font-semibold",
1073
- children: [
1074
- c.label,
1075
- sort?.key === c.key && /* @__PURE__ */ jsx("span", { className: "ml-1", children: sort.dir === 1 ? "▲" : "▼" })
1076
- ]
1077
- }
1078
- ) : /* @__PURE__ */ jsx("span", { children: c.label }),
1079
- podeAgrupar && /* @__PURE__ */ jsx(
1080
- "button",
1081
- {
1082
- onClick: () => alternarGrupo(c.key),
1083
- title: (agrupada ? L.ungroup : L.groupBy).replace("{label}", c.label),
1084
- className: `appearance-none bg-transparent border-0 cursor-pointer p-0.5 transition-colors ${agrupada ? "text-violet-600 dark:text-violet-300" : "text-slate-300 dark:text-slate-600 hover:text-slate-500 dark:hover:text-slate-300"}`,
1085
- children: /* @__PURE__ */ jsx(Layers, { size: 10 })
1086
- }
1087
- ),
1088
- filtravel(c) && botaoFunil(c.key, c),
1089
- c.extraFilters?.map((ef) => botaoFunil(ef.key, void 0, { label: ef.label }))
1090
- ] }),
1091
- c.headerExtra && /* @__PURE__ */ jsx("div", { className: "mt-0.5 normal-case font-normal tracking-normal", children: c.headerExtra(filtered) })
1092
- ]
1093
- },
1094
- c.key
1095
- );
1096
- })
1097
- ] }) }),
1098
- /* @__PURE__ */ jsx("tbody", { children: aEsperarDataset ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: nColunas, className: "py-16 text-center text-sm font-bold uppercase tracking-widest text-slate-400", children: L.loading }) }) : isGrouped ? grupos.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: nColunas, className: "py-16 text-center text-sm text-slate-400", children: L.empty }) }) : renderGrupos(grupos, 0) : sorted.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsxs("td", { colSpan: nColunas, className: "py-16 text-center", children: [
1099
- emptyIcon && /* @__PURE__ */ jsx("div", { className: "flex justify-center mb-2", children: emptyIcon }),
1100
- /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-400", children: L.empty }),
1101
- emptySubLabel && /* @__PURE__ */ jsx("p", { className: "text-xs text-slate-400 mt-1", children: emptySubLabel })
1102
- ] }) }) : pageData.map((row, i) => renderLinha(row, i)) }),
1103
- totalRow && !aEsperarDataset && sorted.length > 0 && /* @__PURE__ */ jsx("tfoot", { className: "sticky bottom-0 z-[2]", children: /* @__PURE__ */ jsxs("tr", { className: "bg-slate-100 dark:bg-slate-800 font-black text-slate-800 dark:text-slate-100", children: [
1104
- /* @__PURE__ */ jsx("td", { colSpan: colunasRotuloGrupo, className: "px-3 py-2 border-t-2 border-slate-200 dark:border-slate-700 text-[10px] uppercase tracking-widest", children: L.total }),
1105
- colunasComValor.map((c) => /* @__PURE__ */ jsx("td", { className: `px-3 py-2 border-t-2 border-slate-200 dark:border-slate-700 whitespace-nowrap text-xs ${alignClass(c.align)}`, children: c.groupAggregate?.(sorted) }, c.key))
1106
- ] }) })
1107
- ] }) }),
1108
- paginando && (totalPages > 1 || (pageSizeOptions?.length ?? 0) > 0) && /* @__PURE__ */ jsxs("div", { className: "mt-2.5 flex items-center justify-between gap-2", children: [
1109
- /* @__PURE__ */ jsx("span", { className: "text-[10px] font-black uppercase tracking-widest text-slate-400", children: L.page.replace("{page}", String(currentPage)).replace("{pages}", String(totalPages)) }),
1110
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
1111
- (pageSizeOptions?.length ?? 0) > 0 && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 mr-2 text-[10px] font-black uppercase tracking-widest text-slate-400", children: [
1112
- L.perPage,
1113
- /* @__PURE__ */ jsx(
1114
- Escolha,
1115
- {
1116
- rotulo: L.perPage,
1117
- valor: String(pageSizeAtual),
1118
- onMudar: (v) => setPageSizeAtual(Number(v)),
1119
- className: "w-20 normal-case tracking-normal font-normal",
1120
- opcoes: [.../* @__PURE__ */ new Set([...pageSizeOptions ?? [], pageSizeAtual])].sort((a, b) => a - b).map(String)
1101
+ isGrouped && /* @__PURE__ */ jsx(
1102
+ FilterChips,
1103
+ {
1104
+ className: "mb-2",
1105
+ items: groupByKeys.map((key) => ({
1106
+ key,
1107
+ tone: "group",
1108
+ icon: /* @__PURE__ */ jsx(Layers, { size: 9 }),
1109
+ label: columns.find((c) => c.key === key)?.label ?? key,
1110
+ onRemove: () => removerGrupo(key)
1111
+ })),
1112
+ onClearAll: limparGrupos,
1113
+ clearAllLabel: L.clearGroups
1114
+ }
1115
+ ),
1116
+ (activeFilters.length > 0 || activeRanges.length > 0) && /* @__PURE__ */ jsx(
1117
+ FilterChips,
1118
+ {
1119
+ className: "mb-2",
1120
+ items: [
1121
+ ...activeRanges.map(([key, r]) => {
1122
+ const col = columns.find((c) => c.key === key);
1123
+ const fmt = (v) => v == null ? "" : col?.sortType === "date" ? new Date(v).toLocaleDateString() : String(v);
1124
+ const txt = r.min != null && r.max != null ? `${fmt(r.min)} – ${fmt(r.max)}` : r.min != null ? `≥ ${fmt(r.min)}` : `≤ ${fmt(r.max)}`;
1125
+ return { key: `r-${key}`, label: `${col?.label ?? key}: ${txt}`, onRemove: () => clearColumnFilter(key) };
1126
+ }),
1127
+ ...activeFilters.flatMap(([key, sel]) => {
1128
+ const col = columns.find((c) => c.key === key);
1129
+ const extra = !col ? columns.flatMap((c) => c.extraFilters ?? []).find((f) => f.key === key) : void 0;
1130
+ const chipLabel = col?.label ?? extra?.label ?? key;
1131
+ const arr = Array.from(sel);
1132
+ if (col?.valueChipColors) {
1133
+ const cores = col.valueChipColors;
1134
+ return arr.map((v) => ({
1135
+ key: `${key}:${v}`,
1136
+ label: `${chipLabel}: ${rotuloVisivel(key, v)}`,
1137
+ colorClassName: cores[v],
1138
+ onRemove: () => toggleFilterValue(key, v)
1139
+ }));
1121
1140
  }
1122
- )
1123
- ] }),
1124
- /* @__PURE__ */ jsx(
1125
- "button",
1126
- {
1127
- disabled: currentPage <= 1,
1128
- onClick: () => setPage((p) => Math.max(1, p - 1)),
1129
- className: "appearance-none cursor-pointer bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 text-[10px] font-black uppercase rounded-lg tracking-widest px-3 py-1.5 text-slate-500 dark:text-slate-400 hover:enabled:border-proef-navy dark:hover:enabled:border-proef-turquoise hover:enabled:text-proef-navy dark:hover:enabled:text-proef-turquoise disabled:opacity-30 disabled:cursor-not-allowed transition-colors",
1130
- children: L.prev
1131
- }
1132
- ),
1133
- /* @__PURE__ */ jsx(
1134
- "button",
1135
- {
1136
- disabled: currentPage >= totalPages,
1137
- onClick: () => setPage((p) => Math.min(totalPages, p + 1)),
1138
- className: "appearance-none cursor-pointer bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 text-[10px] font-black uppercase rounded-lg tracking-widest px-3 py-1.5 text-slate-500 dark:text-slate-400 hover:enabled:border-proef-navy dark:hover:enabled:border-proef-turquoise hover:enabled:text-proef-navy dark:hover:enabled:text-proef-turquoise disabled:opacity-30 disabled:cursor-not-allowed transition-colors",
1139
- children: L.next
1140
- }
1141
- )
1142
- ] })
1143
- ] })
1141
+ const txt = arr.length > 2 || arr.length === 0 ? L.selected.replace("{count}", String(arr.length)) : arr.map((v) => rotuloVisivel(key, v)).join(", ");
1142
+ return [{ key, label: `${chipLabel}: ${txt}`, onRemove: () => clearColumnFilter(key) }];
1143
+ })
1144
+ ],
1145
+ onClearAll: clearAllFilters,
1146
+ clearAllLabel: L.clearAll
1147
+ }
1148
+ ),
1149
+ /* @__PURE__ */ jsx(
1150
+ "div",
1151
+ {
1152
+ className: `overflow-auto rounded-xl border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 ${scrollAffordance ? "outline-none focus-visible:ring-2 focus-visible:ring-proef-blue dark:focus-visible:ring-proef-turquoise" : ""}`,
1153
+ style: { maxHeight },
1154
+ ...scrollAffordance ? { tabIndex: 0, role: "region", "aria-label": L.scrollRegion ?? DEFAULT_LABELS.scrollRegion, onKeyDown: rolarComTeclado } : {},
1155
+ children: /* @__PURE__ */ jsxs("table", { className: "w-full text-[13px] border-collapse dark:text-slate-200", children: [
1156
+ /* @__PURE__ */ jsx("thead", { className: "sticky top-0 z-[2]", children: /* @__PURE__ */ jsxs("tr", { children: [
1157
+ selectable && /* @__PURE__ */ jsx("th", { className: "bg-slate-50 dark:bg-slate-800 px-3 py-2.5 border-b border-slate-200 dark:border-slate-700 w-10 sticky left-0 z-[3]", children: /* @__PURE__ */ jsx(
1158
+ "button",
1159
+ {
1160
+ onClick: alternarTodas,
1161
+ className: `appearance-none cursor-pointer w-4 h-4 flex items-center justify-center border transition-colors rounded ${todasVisiveisMarcadas ? "bg-proef-navy dark:bg-proef-turquoise border-proef-navy dark:border-proef-turquoise text-white dark:text-proef-navy" : algumaVisivelMarcada ? "bg-slate-300 dark:bg-slate-600 border-slate-300 dark:border-slate-600 text-white" : "bg-white dark:bg-slate-900 border-slate-300 dark:border-slate-600 hover:border-slate-400 dark:hover:border-slate-500"}`,
1162
+ children: (todasVisiveisMarcadas || algumaVisivelMarcada) && /* @__PURE__ */ jsx("span", { className: "text-[9px] leading-none", children: "✓" })
1163
+ }
1164
+ ) }),
1165
+ columns.map((c) => {
1166
+ const podeOrdenar = c.sortable !== false;
1167
+ const podeAgrupar = agrupavel(c);
1168
+ const agrupada = groupByKeys.includes(c.key);
1169
+ return /* @__PURE__ */ jsxs(
1170
+ "th",
1171
+ {
1172
+ style: {
1173
+ ...c.width ? { minWidth: c.width } : {},
1174
+ ...larguras[c.key] ? { width: larguras[c.key], minWidth: larguras[c.key], maxWidth: larguras[c.key] } : {},
1175
+ ...estiloPreso(c) ?? {}
1176
+ },
1177
+ className: `group/th relative bg-slate-50 dark:bg-slate-800 text-[11.5px] uppercase tracking-wide text-slate-500 dark:text-slate-400 font-semibold px-3 py-2.5 border-b border-slate-200 dark:border-slate-700 whitespace-nowrap select-none ${alignClass(
1178
+ c.align
1179
+ )} ${c.sticky ? `sticky z-[3] bg-slate-50 dark:bg-slate-800 ${c.sticky === "right" ? "border-l border-slate-200 dark:border-slate-700" : ""}` : ""} ${c.headerClassName ?? ""}`,
1180
+ children: [
1181
+ resizableColumns && // Pega no limite direito: arrastar redimensiona; duplo clique repõe a largura automática
1182
+ /* @__PURE__ */ jsx(
1183
+ "span",
1184
+ {
1185
+ role: "separator",
1186
+ "aria-orientation": "vertical",
1187
+ title: L.resizeColumn,
1188
+ onMouseDown: (e) => iniciarResize(e, c.key),
1189
+ onDoubleClick: () => reporLargura(c.key),
1190
+ onClick: (e) => e.stopPropagation(),
1191
+ className: "absolute right-0 top-0 z-[4] h-full w-1.5 cursor-col-resize bg-transparent hover:bg-proef-blue/40 group-hover/th:bg-slate-300/60 dark:group-hover/th:bg-slate-600/60"
1192
+ }
1193
+ ),
1194
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
1195
+ podeOrdenar ? /* @__PURE__ */ jsxs(
1196
+ "button",
1197
+ {
1198
+ onClick: () => toggleSort(c.key),
1199
+ className: "appearance-none bg-transparent border-0 cursor-pointer p-0 uppercase tracking-wide text-slate-500 dark:text-slate-400 hover:text-proef-blue dark:hover:text-proef-turquoise font-semibold",
1200
+ children: [
1201
+ c.label,
1202
+ sort?.key === c.key && /* @__PURE__ */ jsx("span", { className: "ml-1", children: sort.dir === 1 ? "▲" : "▼" })
1203
+ ]
1204
+ }
1205
+ ) : /* @__PURE__ */ jsx("span", { children: c.label }),
1206
+ podeAgrupar && /* @__PURE__ */ jsx(
1207
+ "button",
1208
+ {
1209
+ onClick: () => alternarGrupo(c.key),
1210
+ title: (agrupada ? L.ungroup : L.groupBy).replace("{label}", c.label),
1211
+ className: `appearance-none bg-transparent border-0 cursor-pointer p-0.5 transition-colors ${agrupada ? "text-violet-600 dark:text-violet-300" : "text-slate-300 dark:text-slate-600 hover:text-slate-500 dark:hover:text-slate-300"}`,
1212
+ children: /* @__PURE__ */ jsx(Layers, { size: 10 })
1213
+ }
1214
+ ),
1215
+ botaoFunil(c)
1216
+ ] }),
1217
+ c.headerExtra && /* @__PURE__ */ jsx("div", { className: "mt-0.5 normal-case font-normal tracking-normal", children: c.headerExtra(filtered) })
1218
+ ]
1219
+ },
1220
+ c.key
1221
+ );
1222
+ })
1223
+ ] }) }),
1224
+ /* @__PURE__ */ jsx("tbody", { children: isLoading ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: nColunas, className: "py-16 text-center text-sm font-bold uppercase tracking-widest text-slate-400", children: /* @__PURE__ */ jsxs("div", { role: "status", "aria-live": "polite", className: "inline-flex items-center gap-2", children: [
1225
+ /* @__PURE__ */ jsx(Spinner, { size: 16, className: "text-proef-blue dark:text-proef-turquoise" }),
1226
+ /* @__PURE__ */ jsx("span", { children: L.loading })
1227
+ ] }) }) }) : aEsperarDataset ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: nColunas, className: "py-16 text-center text-sm font-bold uppercase tracking-widest text-slate-400", children: L.loading }) }) : isGrouped ? grupos.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: nColunas, className: "py-16 text-center text-sm text-slate-400", children: L.empty }) }) : renderGrupos(grupos, 0) : sorted.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsxs("td", { colSpan: nColunas, className: "py-16 text-center", children: [
1228
+ emptyIcon && /* @__PURE__ */ jsx("div", { className: "flex justify-center mb-2", children: emptyIcon }),
1229
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-400", children: L.empty }),
1230
+ emptySubLabel && /* @__PURE__ */ jsx("p", { className: "text-xs text-slate-400 mt-1", children: emptySubLabel })
1231
+ ] }) }) : pageData.map((row, i) => renderLinha(row, i)) }),
1232
+ totalRow && !isLoading && !aEsperarDataset && sorted.length > 0 && /* @__PURE__ */ jsx("tfoot", { className: "sticky bottom-0 z-[2]", children: /* @__PURE__ */ jsxs("tr", { className: "bg-slate-100 dark:bg-slate-800 font-black text-slate-800 dark:text-slate-100", children: [
1233
+ /* @__PURE__ */ jsx("td", { colSpan: colunasRotuloGrupo, className: "px-3 py-2 border-t-2 border-slate-200 dark:border-slate-700 text-[10px] uppercase tracking-widest", children: L.total }),
1234
+ colunasComValor.map((c) => /* @__PURE__ */ jsx("td", { className: `px-3 py-2 border-t-2 border-slate-200 dark:border-slate-700 whitespace-nowrap text-xs ${alignClass(c.align)}`, children: c.groupAggregate?.(sorted) }, c.key))
1235
+ ] }) })
1236
+ ] })
1237
+ }
1238
+ ),
1239
+ !isLoading && paginando && (totalPages > 1 || (pageSizeOptions?.length ?? 0) > 0) && /* @__PURE__ */ jsx(
1240
+ Pagination,
1241
+ {
1242
+ className: "mt-2.5",
1243
+ page: currentPage,
1244
+ pages: totalPages,
1245
+ onPageChange: (p) => setPage(Math.min(totalPages, Math.max(1, p))),
1246
+ pageSize: pageSizeAtual,
1247
+ pageSizeOptions,
1248
+ onPageSizeChange: escolherPageSize,
1249
+ labels: { page: L.page, perPage: L.perPage, prev: L.prev, next: L.next }
1250
+ }
1251
+ )
1144
1252
  ] });
1145
1253
  }
1146
1254
  export {