@nextelco/common-ui 2.1.104 → 2.1.105
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.
- package/dist/esm/assets/imagem-6ee08a37d9.png +0 -0
- package/dist/esm/assets/imagem-6fcae1b87b.png +0 -0
- package/dist/esm/index.js +142 -119
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/legacy/components/layout/Header/Header.css +1 -1
- package/dist/esm/legacy/components/molecules/Sidebar/Sidebar.css +1 -1
- package/dist/esm/legacy/components/organisms/RoleGuard/RoleGuard.js +14 -3
- package/dist/esm/legacy/components/organisms/RoleGuard/RoleGuard.js.map +1 -1
- package/dist/esm/legacy/pages/Error/ErrorPage.css +1 -1
- package/dist/esm/legacy/pages/Loading/Loading.css +2 -2
- package/dist/esm/legacy/pages/NotFound/NotFound.css +1 -1
- package/dist/esm/v1/components/lists/ListFinder/ListFinder.js +214 -0
- package/dist/esm/v1/components/lists/ListFinder/ListFinder.js.map +1 -0
- package/dist/esm/v1/components/lists/ListFinder/labels.js +18 -0
- package/dist/esm/v1/components/lists/ListFinder/labels.js.map +1 -0
- package/dist/esm/v1/components/tables/PaginatedTable/PaginatedTable.js +50 -0
- package/dist/esm/v1/components/tables/PaginatedTable/PaginatedTable.js.map +1 -0
- package/dist/esm/v1/components/tables/Table/ColumnFilter.js +292 -0
- package/dist/esm/v1/components/tables/Table/ColumnFilter.js.map +1 -0
- package/dist/esm/v1/components/tables/Table/OverlayScrollbar.js +129 -0
- package/dist/esm/v1/components/tables/Table/OverlayScrollbar.js.map +1 -0
- package/dist/esm/v1/components/tables/Table/Table.js +1410 -0
- package/dist/esm/v1/components/tables/Table/Table.js.map +1 -0
- package/dist/esm/v1/components/tables/Table/labels.js +44 -0
- package/dist/esm/v1/components/tables/Table/labels.js.map +1 -0
- package/dist/esm/v1/foundations/icons/icons.js +45 -2
- package/dist/esm/v1/foundations/icons/icons.js.map +1 -1
- package/dist/esm/v1/primitives/forms/Checkbox/Checkbox.js +32 -0
- package/dist/esm/v1/primitives/forms/Checkbox/Checkbox.js.map +1 -0
- package/dist/esm/v1/primitives/lists/ListItem/ListCheckbox.js +28 -0
- package/dist/esm/v1/primitives/lists/ListItem/ListCheckbox.js.map +1 -0
- package/dist/esm/v1/primitives/lists/ListItem/ListItem.js +39 -0
- package/dist/esm/v1/primitives/lists/ListItem/ListItem.js.map +1 -0
- package/dist/style.components.css +1 -1
- package/dist/style.css +1 -1
- package/dist/style.layered.css +1 -1
- package/dist/theme.css +256 -0
- package/dist/types/v1/components/lists/ListFinder/ListFinder.d.ts +60 -0
- package/dist/types/v1/components/lists/ListFinder/labels.d.ts +24 -0
- package/dist/types/v1/components/tables/PaginatedTable/PaginatedTable.d.ts +41 -0
- package/dist/types/v1/components/tables/Table/ColumnFilter.d.ts +48 -0
- package/dist/types/v1/components/tables/Table/OverlayScrollbar.d.ts +34 -0
- package/dist/types/v1/components/tables/Table/Table.d.ts +250 -0
- package/dist/types/v1/components/tables/Table/labels.d.ts +54 -0
- package/dist/types/v1/foundations/icons/icons.d.ts +17 -0
- package/dist/types/v1/index.d.ts +15 -1
- package/dist/types/v1/primitives/forms/Checkbox/Checkbox.d.ts +18 -0
- package/dist/types/v1/primitives/lists/ListItem/ListCheckbox.d.ts +14 -0
- package/dist/types/v1/primitives/lists/ListItem/ListItem.d.ts +35 -0
- package/package.json +2 -2
|
@@ -0,0 +1,1410 @@
|
|
|
1
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useRef, useEffect, useMemo, useCallback, useLayoutEffect, Fragment as Fragment$1 } from "react";
|
|
3
|
+
import { CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, LayersIcon, CloseIcon, ChevronUpIcon, ChevronsUpDownIcon, FilterIcon } from "../../../foundations/icons/icons.js";
|
|
4
|
+
import { ColumnFilter } from "./ColumnFilter.js";
|
|
5
|
+
import { OverlayScrollbar } from "./OverlayScrollbar.js";
|
|
6
|
+
import { DEFAULT_TABLE_LABELS } from "./labels.js";
|
|
7
|
+
const comparador = new Intl.Collator();
|
|
8
|
+
const MOLA_RIGIDEZ = 1200;
|
|
9
|
+
const MOLA_AMORTECIMENTO = 2 * Math.sqrt(MOLA_RIGIDEZ);
|
|
10
|
+
const PERTO_DE_ASSENTAR = 6;
|
|
11
|
+
let estiloArrasto = null;
|
|
12
|
+
function cursorDeArrasto(ligado) {
|
|
13
|
+
if (ligado && !estiloArrasto) {
|
|
14
|
+
estiloArrasto = document.createElement("style");
|
|
15
|
+
estiloArrasto.textContent = "*{cursor:grabbing!important;user-select:none!important}";
|
|
16
|
+
document.head.appendChild(estiloArrasto);
|
|
17
|
+
} else if (!ligado && estiloArrasto) {
|
|
18
|
+
estiloArrasto.remove();
|
|
19
|
+
estiloArrasto = null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const LIMIAR_ARRASTO = 4;
|
|
23
|
+
const FOLGA_TROCA = 0.75;
|
|
24
|
+
function TableBase({
|
|
25
|
+
paginacaoNoTopo,
|
|
26
|
+
columns: colunasBase,
|
|
27
|
+
data,
|
|
28
|
+
allData,
|
|
29
|
+
pageSize,
|
|
30
|
+
rowKey,
|
|
31
|
+
onRowClick,
|
|
32
|
+
onRowDoubleClick,
|
|
33
|
+
loading: isLoading,
|
|
34
|
+
allDataLoading: isAllDataLoading,
|
|
35
|
+
loadingLabel,
|
|
36
|
+
emptyLabel,
|
|
37
|
+
emptySubLabel,
|
|
38
|
+
storageKey,
|
|
39
|
+
selectable,
|
|
40
|
+
onSelectionChange,
|
|
41
|
+
clearSelectionTrigger,
|
|
42
|
+
onAllDataNeeded: onDataNeeded,
|
|
43
|
+
alwaysClient,
|
|
44
|
+
defaultSortColumn: defaultSortCol,
|
|
45
|
+
defaultSortDirection: defaultSortDir,
|
|
46
|
+
viewRef,
|
|
47
|
+
fillHeight: preencheAltura = false,
|
|
48
|
+
onVisibleChange: onVista,
|
|
49
|
+
frozenColumns: colunasFixas = 0,
|
|
50
|
+
onMoveColumn: onMoverColuna,
|
|
51
|
+
measureAllData: larguraPeloConjunto = false,
|
|
52
|
+
overlayScrollbars: barraSobreposta = false,
|
|
53
|
+
headerRowClassName: classeCabecalho = "bg-slate-50",
|
|
54
|
+
scrollbarOnEdge: barraNaBorda = true,
|
|
55
|
+
horizontalScrollbarBelow: barraHorizontalFora = false,
|
|
56
|
+
skeleton: esqueletoAoCarregar = false,
|
|
57
|
+
fadeRight: esbaterDireita = false,
|
|
58
|
+
rowClassName,
|
|
59
|
+
maxHeight,
|
|
60
|
+
labels
|
|
61
|
+
}) {
|
|
62
|
+
const L = { ...DEFAULT_TABLE_LABELS, ...labels };
|
|
63
|
+
const vazio = emptyLabel ?? L.empty;
|
|
64
|
+
const columns = colunasBase;
|
|
65
|
+
const [arrastada, setArrastada] = useState(null);
|
|
66
|
+
const [realcada, setRealcada] = useState(null);
|
|
67
|
+
const alvoArrasto = useRef(void 0);
|
|
68
|
+
const recuoFim = (i) => barraSobreposta && i === columns.length - 1 ? "pr-6!" : "";
|
|
69
|
+
const realce = (chave, cabecalho2 = false) => realcada === chave ? fixaMedida(chave) ? "" : `${cabecalho2 ? "bg-proef-blue/15" : "bg-proef-blue/5"} shadow-[inset_1px_0_0_0_rgb(0_118_206/0.35),inset_-1px_0_0_0_rgb(0_118_206/0.35)]` : cabecalho2 && fundoNosTitulos ? "bg-slate-50" : "";
|
|
70
|
+
const bordasSeparadas = !!onMoverColuna;
|
|
71
|
+
const fundoNosTitulos = bordasSeparadas && !preencheAltura;
|
|
72
|
+
const classeTabela = bordasSeparadas ? "text-left border-separate border-spacing-0" : "text-left";
|
|
73
|
+
const transicaoRealce = onMoverColuna ? "transition-[background-color,box-shadow] duration-300" : "";
|
|
74
|
+
const [sortCol, setSortCol] = useState(defaultSortCol ?? null);
|
|
75
|
+
const [sortDir, setSortDir] = useState(defaultSortDir ?? "asc");
|
|
76
|
+
const [columnFilters, setColumnFilters] = useState(() => {
|
|
77
|
+
if (!storageKey) return {};
|
|
78
|
+
try {
|
|
79
|
+
const raw = sessionStorage.getItem(`dt_filters_${storageKey}`);
|
|
80
|
+
if (!raw) return {};
|
|
81
|
+
const parsed = JSON.parse(raw);
|
|
82
|
+
return Object.fromEntries(Object.entries(parsed).map(([k, v]) => [k, new Set(v)]));
|
|
83
|
+
} catch {
|
|
84
|
+
return {};
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
const [dateFilters, setDateFilters] = useState(() => {
|
|
88
|
+
if (!storageKey) return {};
|
|
89
|
+
try {
|
|
90
|
+
const raw = sessionStorage.getItem(`dt_datefilters_${storageKey}`);
|
|
91
|
+
return raw ? JSON.parse(raw) : {};
|
|
92
|
+
} catch {
|
|
93
|
+
return {};
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
const [numFilters, setNumFilters] = useState(() => {
|
|
97
|
+
if (!storageKey) return {};
|
|
98
|
+
try {
|
|
99
|
+
const raw = sessionStorage.getItem(`dt_numfilters_${storageKey}`);
|
|
100
|
+
return raw ? JSON.parse(raw) : {};
|
|
101
|
+
} catch {
|
|
102
|
+
return {};
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
const [groupByKeys, setGroupByKeys] = useState([]);
|
|
106
|
+
const [collapsedGroups, setCollapsedGroups] = useState(/* @__PURE__ */ new Set());
|
|
107
|
+
const [internalPage, setInternalPage] = useState(1);
|
|
108
|
+
const [openFilterCol, setOpenFilterCol] = useState(null);
|
|
109
|
+
const [ancoraFiltro, setAncoraFiltro] = useState(null);
|
|
110
|
+
const [selectedKeys, setSelectedKeys] = useState(/* @__PURE__ */ new Set());
|
|
111
|
+
const isGrouped = groupByKeys.length > 0;
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
if (!storageKey) return;
|
|
114
|
+
const serializable = Object.fromEntries(Object.entries(columnFilters).map(([k, v]) => [k, Array.from(v)]));
|
|
115
|
+
sessionStorage.setItem(`dt_filters_${storageKey}`, JSON.stringify(serializable));
|
|
116
|
+
sessionStorage.setItem(`dt_datefilters_${storageKey}`, JSON.stringify(dateFilters));
|
|
117
|
+
sessionStorage.setItem(`dt_numfilters_${storageKey}`, JSON.stringify(numFilters));
|
|
118
|
+
}, [columnFilters, dateFilters, numFilters, storageKey]);
|
|
119
|
+
const resolveValueFn = (colKey) => {
|
|
120
|
+
const col = columns.find((c) => c.key === colKey);
|
|
121
|
+
if (col?.value) return col.value;
|
|
122
|
+
for (const c of columns) {
|
|
123
|
+
const ef = c.extraFilters?.find((f) => f.key === colKey);
|
|
124
|
+
if (ef) return ef.value;
|
|
125
|
+
}
|
|
126
|
+
return void 0;
|
|
127
|
+
};
|
|
128
|
+
const getUniqueValues = (colKey) => {
|
|
129
|
+
const valueFn = resolveValueFn(colKey);
|
|
130
|
+
if (!valueFn) return [];
|
|
131
|
+
let source = allData ?? data;
|
|
132
|
+
for (const [otherKey, selectedVals] of Object.entries(columnFilters)) {
|
|
133
|
+
if (otherKey === colKey || !selectedVals || selectedVals.size === 0) continue;
|
|
134
|
+
const otherFn = resolveValueFn(otherKey);
|
|
135
|
+
if (!otherFn) continue;
|
|
136
|
+
source = source.filter((row) => {
|
|
137
|
+
const v = otherFn(row);
|
|
138
|
+
return selectedVals.has(v == null || v === "" ? "—" : String(v));
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
for (const [otherKey, range] of Object.entries(dateFilters)) {
|
|
142
|
+
if (otherKey === colKey || !dateFilterActive(range)) continue;
|
|
143
|
+
const otherFn = resolveValueFn(otherKey);
|
|
144
|
+
if (!otherFn) continue;
|
|
145
|
+
source = source.filter((row) => {
|
|
146
|
+
const d = asDay(otherFn(row));
|
|
147
|
+
if (!d) return false;
|
|
148
|
+
if (range.from && d < range.from) return false;
|
|
149
|
+
if (range.to && d > range.to) return false;
|
|
150
|
+
return true;
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
const vals = /* @__PURE__ */ new Set();
|
|
154
|
+
source.forEach((row) => {
|
|
155
|
+
const v = valueFn(row);
|
|
156
|
+
vals.add(v == null || v === "" ? "—" : String(v));
|
|
157
|
+
});
|
|
158
|
+
return Array.from(vals).sort((a, b) => a === "—" ? 1 : b === "—" ? -1 : a.localeCompare(b));
|
|
159
|
+
};
|
|
160
|
+
const asDay = (v) => v == null ? "" : String(v).substring(0, 10);
|
|
161
|
+
const dateFilterActive = (r) => !!(r && (r.from || r.to));
|
|
162
|
+
const numFilterActive = (r) => !!(r && (r.min !== void 0 && r.min !== "" || r.max !== void 0 && r.max !== ""));
|
|
163
|
+
const asNum = (v) => {
|
|
164
|
+
if (v == null || v === "") return null;
|
|
165
|
+
const n = Number(v);
|
|
166
|
+
return Number.isFinite(n) ? n : null;
|
|
167
|
+
};
|
|
168
|
+
const hasActiveFilters = useMemo(
|
|
169
|
+
() => Object.values(columnFilters).some((s) => s?.size > 0) || Object.values(dateFilters).some(dateFilterActive) || Object.values(numFilters).some(numFilterActive),
|
|
170
|
+
[columnFilters, dateFilters, numFilters]
|
|
171
|
+
);
|
|
172
|
+
const isClientMode = !!allData && (alwaysClient || hasActiveFilters || !!sortCol || isGrouped);
|
|
173
|
+
const effectiveData = isClientMode ? allData : data;
|
|
174
|
+
useEffect(() => {
|
|
175
|
+
setInternalPage(1);
|
|
176
|
+
}, [sortCol, sortDir, columnFilters, dateFilters, numFilters, groupByKeys, pageSize]);
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
if (clearSelectionTrigger === void 0) return;
|
|
179
|
+
setSelectedKeys(/* @__PURE__ */ new Set());
|
|
180
|
+
}, [clearSelectionTrigger]);
|
|
181
|
+
const chaveFiltrosCol = JSON.stringify(
|
|
182
|
+
Object.entries(columnFilters).map(([k, v]) => [k, [...v].sort()]).sort()
|
|
183
|
+
);
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
setSelectedKeys(/* @__PURE__ */ new Set());
|
|
186
|
+
onSelectionChange?.(/* @__PURE__ */ new Set());
|
|
187
|
+
}, [chaveFiltrosCol]);
|
|
188
|
+
useEffect(() => {
|
|
189
|
+
if (!allData && (hasActiveFilters || sortCol || isGrouped)) onDataNeeded?.();
|
|
190
|
+
}, [allData, hasActiveFilters, sortCol, isGrouped]);
|
|
191
|
+
const sortColAtual = sortCol, sortDirAtual = sortDir;
|
|
192
|
+
const filtrosDeColuna = columnFilters, filtrosDeData = dateFilters, filtrosNumericos = numFilters;
|
|
193
|
+
const sortRows = (rows, sortCol2 = sortColAtual, sortDir2 = sortDirAtual) => {
|
|
194
|
+
if (!sortCol2) return rows;
|
|
195
|
+
const col = columns.find((c) => c.key === sortCol2);
|
|
196
|
+
if (!col?.value) return rows;
|
|
197
|
+
return [...rows].sort((a, b) => {
|
|
198
|
+
const av = col.value(a);
|
|
199
|
+
const bv = col.value(b);
|
|
200
|
+
if (av == null && bv == null) return 0;
|
|
201
|
+
if (av == null) return 1;
|
|
202
|
+
if (bv == null) return -1;
|
|
203
|
+
if (typeof av === "number" && typeof bv === "number") return sortDir2 === "asc" ? av - bv : bv - av;
|
|
204
|
+
const cmp = comparador.compare(String(av), String(bv));
|
|
205
|
+
return sortDir2 === "asc" ? cmp : -cmp;
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
const filterRows = (rows, columnFilters2 = filtrosDeColuna, dateFilters2 = filtrosDeData, numFilters2 = filtrosNumericos) => {
|
|
209
|
+
let result = rows;
|
|
210
|
+
for (const [colKey, selectedVals] of Object.entries(columnFilters2)) {
|
|
211
|
+
if (!selectedVals || selectedVals.size === 0) continue;
|
|
212
|
+
const valueFn = resolveValueFn(colKey);
|
|
213
|
+
if (!valueFn) continue;
|
|
214
|
+
result = result.filter((row) => {
|
|
215
|
+
const v = valueFn(row);
|
|
216
|
+
return selectedVals.has(v == null || v === "" ? "—" : String(v));
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
for (const [colKey, range] of Object.entries(dateFilters2)) {
|
|
220
|
+
if (!dateFilterActive(range)) continue;
|
|
221
|
+
const valueFn = resolveValueFn(colKey);
|
|
222
|
+
if (!valueFn) continue;
|
|
223
|
+
result = result.filter((row) => {
|
|
224
|
+
const d = asDay(valueFn(row));
|
|
225
|
+
if (!d) return false;
|
|
226
|
+
if (range.from && d < range.from) return false;
|
|
227
|
+
if (range.to && d > range.to) return false;
|
|
228
|
+
return true;
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
for (const [colKey, range] of Object.entries(numFilters2)) {
|
|
232
|
+
if (!numFilterActive(range)) continue;
|
|
233
|
+
const valueFn = resolveValueFn(colKey);
|
|
234
|
+
if (!valueFn) continue;
|
|
235
|
+
result = result.filter((row) => {
|
|
236
|
+
const n = asNum(valueFn(row));
|
|
237
|
+
if (n == null) return false;
|
|
238
|
+
if (range.min !== void 0 && range.min !== "" && n < Number(range.min)) return false;
|
|
239
|
+
if (range.max !== void 0 && range.max !== "" && n > Number(range.max)) return false;
|
|
240
|
+
return true;
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
return result;
|
|
244
|
+
};
|
|
245
|
+
const sortedData = useMemo(() => sortRows(effectiveData), [effectiveData, sortCol, sortDir, colunasBase]);
|
|
246
|
+
const filteredData = useMemo(() => filterRows(sortedData), [sortedData, columnFilters, dateFilters, numFilters]);
|
|
247
|
+
useEffect(() => {
|
|
248
|
+
if (!viewRef) return;
|
|
249
|
+
viewRef.current = {
|
|
250
|
+
apply: (rows) => filterRows(sortRows(rows)),
|
|
251
|
+
applyWith: (rows, e) => filterRows(
|
|
252
|
+
sortRows(rows, e.sortCol ?? null, e.sortDir ?? "asc"),
|
|
253
|
+
Object.fromEntries(Object.entries(e.columnFilters ?? {}).map(([k, v]) => [k, new Set(v)])),
|
|
254
|
+
e.dateFilters ?? {},
|
|
255
|
+
e.numFilters ?? {}
|
|
256
|
+
),
|
|
257
|
+
rows: filteredData,
|
|
258
|
+
hasFilters: hasActiveFilters,
|
|
259
|
+
needsAllData: hasActiveFilters || !!sortCol || isGrouped,
|
|
260
|
+
getState: () => ({
|
|
261
|
+
columnFilters: Object.fromEntries(
|
|
262
|
+
Object.entries(columnFilters).filter(([, v]) => v?.size).map(([k, v]) => [k, [...v]])
|
|
263
|
+
),
|
|
264
|
+
dateFilters: Object.fromEntries(Object.entries(dateFilters).filter(([, r]) => dateFilterActive(r))),
|
|
265
|
+
numFilters: Object.fromEntries(Object.entries(numFilters).filter(([, r]) => numFilterActive(r))),
|
|
266
|
+
sortCol,
|
|
267
|
+
sortDir,
|
|
268
|
+
groupBy: groupByKeys
|
|
269
|
+
}),
|
|
270
|
+
restore: (e) => {
|
|
271
|
+
setColumnFilters(Object.fromEntries(Object.entries(e?.columnFilters ?? {}).map(([k, v]) => [k, new Set(v)])));
|
|
272
|
+
setDateFilters(e?.dateFilters ?? {});
|
|
273
|
+
setNumFilters(e?.numFilters ?? {});
|
|
274
|
+
setSortCol(e?.sortCol ?? null);
|
|
275
|
+
setSortDir(e?.sortDir ?? "asc");
|
|
276
|
+
setGroupByKeys(e?.groupBy ?? []);
|
|
277
|
+
setCollapsedGroups(/* @__PURE__ */ new Set());
|
|
278
|
+
const precisaTudo = !!e?.sortCol || !!e?.groupBy?.length || Object.keys(e?.columnFilters ?? {}).length > 0 || Object.keys(e?.dateFilters ?? {}).length > 0;
|
|
279
|
+
if (precisaTudo && !allData) onDataNeeded?.();
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
});
|
|
283
|
+
const toggleGroup = (colKey) => {
|
|
284
|
+
if (!allData) onDataNeeded?.();
|
|
285
|
+
setGroupByKeys(
|
|
286
|
+
(prev) => prev.includes(colKey) ? prev.filter((k) => k !== colKey) : [...prev, colKey]
|
|
287
|
+
);
|
|
288
|
+
setCollapsedGroups(/* @__PURE__ */ new Set());
|
|
289
|
+
};
|
|
290
|
+
const removeGroup = (colKey) => {
|
|
291
|
+
setGroupByKeys((prev) => prev.filter((k) => k !== colKey));
|
|
292
|
+
setCollapsedGroups(/* @__PURE__ */ new Set());
|
|
293
|
+
};
|
|
294
|
+
const clearAllGroups = () => {
|
|
295
|
+
setGroupByKeys([]);
|
|
296
|
+
setCollapsedGroups(/* @__PURE__ */ new Set());
|
|
297
|
+
};
|
|
298
|
+
const toggleCollapse = (path) => setCollapsedGroups((prev) => {
|
|
299
|
+
const n = new Set(prev);
|
|
300
|
+
if (n.has(path)) n.delete(path);
|
|
301
|
+
else n.add(path);
|
|
302
|
+
return n;
|
|
303
|
+
});
|
|
304
|
+
const buildGroups = (items, keys, depth, parentPath) => {
|
|
305
|
+
if (depth >= keys.length) return [];
|
|
306
|
+
const valueFn = resolveValueFn(keys[depth]);
|
|
307
|
+
if (!valueFn) return [];
|
|
308
|
+
const map = /* @__PURE__ */ new Map();
|
|
309
|
+
items.forEach((item) => {
|
|
310
|
+
const v = valueFn(item);
|
|
311
|
+
const label = v == null || v === "" ? "—" : String(v);
|
|
312
|
+
if (!map.has(label)) map.set(label, []);
|
|
313
|
+
map.get(label).push(item);
|
|
314
|
+
});
|
|
315
|
+
return Array.from(map.entries()).sort(([a], [b]) => a === "—" ? 1 : b === "—" ? -1 : a.localeCompare(b)).map(([val, groupItems]) => {
|
|
316
|
+
const path = parentPath ? `${parentPath}\0${val}` : val;
|
|
317
|
+
return { val, path, items: groupItems, children: buildGroups(groupItems, keys, depth + 1, path) };
|
|
318
|
+
});
|
|
319
|
+
};
|
|
320
|
+
const groups = useMemo(
|
|
321
|
+
() => isGrouped ? buildGroups(filteredData, groupByKeys, 0, "") : [],
|
|
322
|
+
[filteredData, groupByKeys, isGrouped]
|
|
323
|
+
);
|
|
324
|
+
const colCount = columns.length + (selectable ? 1 : 0);
|
|
325
|
+
const nFixas = colunasFixas ? Math.min(colunasFixas + (selectable ? 1 : 0), colCount) : 0;
|
|
326
|
+
const cabecalhoRef = useRef(null);
|
|
327
|
+
const raizRef = useRef(null);
|
|
328
|
+
const posColunas = useRef(/* @__PURE__ */ new Map());
|
|
329
|
+
const aoAssentar = useRef(() => {
|
|
330
|
+
});
|
|
331
|
+
const emArrasto = useRef(false);
|
|
332
|
+
aoAssentar.current = () => {
|
|
333
|
+
if (!emArrasto.current) setRealcada(null);
|
|
334
|
+
};
|
|
335
|
+
const molas = useRef(/* @__PURE__ */ new Map());
|
|
336
|
+
const celulasArrasto = useRef(/* @__PURE__ */ new Map());
|
|
337
|
+
const frame = useRef(null);
|
|
338
|
+
const ultimoFrame = useRef(0);
|
|
339
|
+
const animarMolas = useCallback((t) => {
|
|
340
|
+
const dt = Math.min(0.032, (t - ultimoFrame.current) / 1e3);
|
|
341
|
+
ultimoFrame.current = t;
|
|
342
|
+
const passos = Math.max(1, Math.ceil(dt / 8e-3));
|
|
343
|
+
const h = dt / passos;
|
|
344
|
+
let aMexer = false;
|
|
345
|
+
let longe = false;
|
|
346
|
+
for (const [k, m] of molas.current) {
|
|
347
|
+
if (m.parada) continue;
|
|
348
|
+
for (let i = 0; i < passos; i++) {
|
|
349
|
+
m.v += (-MOLA_RIGIDEZ * (m.x - m.destino) - MOLA_AMORTECIMENTO * m.v) * h;
|
|
350
|
+
m.x += m.v * h;
|
|
351
|
+
}
|
|
352
|
+
if (Math.abs(m.x - m.destino) < 0.3 && Math.abs(m.v) < 5) {
|
|
353
|
+
m.x = m.destino;
|
|
354
|
+
m.v = 0;
|
|
355
|
+
m.parada = true;
|
|
356
|
+
if (!m.destino) {
|
|
357
|
+
for (const el of m.els) el.style.transform = "";
|
|
358
|
+
molas.current.delete(k);
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
} else {
|
|
362
|
+
aMexer = true;
|
|
363
|
+
if (Math.abs(m.x - m.destino) > PERTO_DE_ASSENTAR) longe = true;
|
|
364
|
+
}
|
|
365
|
+
const tr = `translateX(${m.x}px)`;
|
|
366
|
+
for (const el of m.els) el.style.transform = tr;
|
|
367
|
+
}
|
|
368
|
+
frame.current = aMexer ? requestAnimationFrame(animarMolas) : null;
|
|
369
|
+
if (!longe) aoAssentar.current();
|
|
370
|
+
}, []);
|
|
371
|
+
useEffect(() => () => {
|
|
372
|
+
if (frame.current !== null) cancelAnimationFrame(frame.current);
|
|
373
|
+
}, []);
|
|
374
|
+
const arrancarMolas = useCallback(() => {
|
|
375
|
+
if (frame.current !== null) return;
|
|
376
|
+
ultimoFrame.current = performance.now();
|
|
377
|
+
frame.current = requestAnimationFrame(animarMolas);
|
|
378
|
+
}, [animarMolas]);
|
|
379
|
+
const apontarMolas = (destinos) => {
|
|
380
|
+
for (const [k, els] of celulasArrasto.current) {
|
|
381
|
+
const destino = destinos.get(k) ?? 0;
|
|
382
|
+
const m = molas.current.get(k);
|
|
383
|
+
if (!m && !destino) continue;
|
|
384
|
+
const mola = m ?? { x: 0, v: 0, destino: 0, parada: true, els };
|
|
385
|
+
mola.destino = destino;
|
|
386
|
+
mola.parada = false;
|
|
387
|
+
mola.els = els;
|
|
388
|
+
molas.current.set(k, mola);
|
|
389
|
+
}
|
|
390
|
+
arrancarMolas();
|
|
391
|
+
};
|
|
392
|
+
const grelhaPrevista = (chave, alvo) => {
|
|
393
|
+
const ths = Array.from(cabecalhoRef.current?.children ?? []).filter((th) => th.dataset.col);
|
|
394
|
+
const ordem = ths.map((th) => th.dataset.col);
|
|
395
|
+
if (alvo !== void 0) {
|
|
396
|
+
const resto = ordem.filter((k) => k !== chave);
|
|
397
|
+
const onde = alvo === null ? resto.length : resto.indexOf(alvo);
|
|
398
|
+
resto.splice(onde < 0 ? resto.length : onde, 0, chave);
|
|
399
|
+
ordem.splice(0, ordem.length, ...resto);
|
|
400
|
+
}
|
|
401
|
+
const porChave = new Map(ths.map((th) => [th.dataset.col, th]));
|
|
402
|
+
const esquerda = /* @__PURE__ */ new Map();
|
|
403
|
+
let acc = ths[0]?.offsetLeft ?? 0;
|
|
404
|
+
for (const k of ordem) {
|
|
405
|
+
esquerda.set(k, acc);
|
|
406
|
+
acc += porChave.get(k)?.offsetWidth ?? 0;
|
|
407
|
+
}
|
|
408
|
+
return { ordem, esquerda, porChave };
|
|
409
|
+
};
|
|
410
|
+
const arrastarPorCima = (clientX) => {
|
|
411
|
+
if (!arrastada) return;
|
|
412
|
+
const tabela = cabecalhoRef.current?.closest("table");
|
|
413
|
+
if (!tabela) return;
|
|
414
|
+
const fixas = new Set(columns.slice(0, colunasFixas).map((c) => c.key));
|
|
415
|
+
const arrastadaFixa = fixas.has(arrastada);
|
|
416
|
+
const caixa = caixaCorpo ?? caixaSimples;
|
|
417
|
+
const x = clientX - tabela.getBoundingClientRect().left + (arrastadaFixa && caixa ? caixa.scrollLeft : 0);
|
|
418
|
+
const { ordem, esquerda, porChave } = grelhaPrevista(arrastada, alvoArrasto.current);
|
|
419
|
+
const larguraArrastada = porChave.get(arrastada)?.offsetWidth ?? 0;
|
|
420
|
+
let alvo = null;
|
|
421
|
+
let aEsquerda = true;
|
|
422
|
+
for (const k of ordem) {
|
|
423
|
+
if (k === arrastada) {
|
|
424
|
+
aEsquerda = false;
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
const largura = porChave.get(k)?.offsetWidth ?? 0;
|
|
428
|
+
const folga = Math.max(0, Math.min(largura * FOLGA_TROCA, larguraArrastada - 1));
|
|
429
|
+
const ponto = (esquerda.get(k) ?? 0) + (aEsquerda ? folga : largura - folga);
|
|
430
|
+
if (ponto > x) {
|
|
431
|
+
alvo = k;
|
|
432
|
+
break;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
if (colunasFixas > 0) {
|
|
436
|
+
const primeiraSolta = ordem.find((k) => k !== arrastada && !fixas.has(k)) ?? null;
|
|
437
|
+
if (arrastadaFixa && (alvo === null || !fixas.has(alvo))) alvo = primeiraSolta;
|
|
438
|
+
else if (!arrastadaFixa && alvo !== null && fixas.has(alvo)) alvo = primeiraSolta;
|
|
439
|
+
}
|
|
440
|
+
if (alvo === alvoArrasto.current) return;
|
|
441
|
+
alvoArrasto.current = alvo;
|
|
442
|
+
const prevista = grelhaPrevista(arrastada, alvo);
|
|
443
|
+
apontarMolas(new Map([...prevista.porChave].map(([k, th]) => [k, (prevista.esquerda.get(k) ?? 0) - th.offsetLeft])));
|
|
444
|
+
};
|
|
445
|
+
const acabarArrasto = (gravar) => {
|
|
446
|
+
const chave = arrastada;
|
|
447
|
+
const alvo = alvoArrasto.current;
|
|
448
|
+
emArrasto.current = false;
|
|
449
|
+
setArrastada(null);
|
|
450
|
+
requestAnimationFrame(() => {
|
|
451
|
+
if (frame.current === null) aoAssentar.current();
|
|
452
|
+
});
|
|
453
|
+
setTimeout(() => aoAssentar.current(), 1e3);
|
|
454
|
+
alvoArrasto.current = void 0;
|
|
455
|
+
if (chave && gravar && alvo !== void 0 && alvo !== chave) {
|
|
456
|
+
onMoverColuna?.(chave, alvo);
|
|
457
|
+
} else {
|
|
458
|
+
apontarMolas(/* @__PURE__ */ new Map());
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
const comecarArrasto = (chave) => {
|
|
462
|
+
setArrastada(chave);
|
|
463
|
+
setRealcada(chave);
|
|
464
|
+
emArrasto.current = true;
|
|
465
|
+
alvoArrasto.current = void 0;
|
|
466
|
+
const ths = Array.from(cabecalhoRef.current?.children ?? []).filter((th) => th.dataset.col);
|
|
467
|
+
posColunas.current = new Map(ths.map((th) => [th.dataset.col, th.offsetLeft]));
|
|
468
|
+
const raiz = raizRef.current;
|
|
469
|
+
celulasArrasto.current = new Map(ths.map((th) => [
|
|
470
|
+
th.dataset.col,
|
|
471
|
+
raiz ? Array.from(raiz.querySelectorAll(`[data-col="${CSS.escape(th.dataset.col)}"]`)) : []
|
|
472
|
+
]));
|
|
473
|
+
};
|
|
474
|
+
const aoComecar = useRef(comecarArrasto);
|
|
475
|
+
aoComecar.current = comecarArrasto;
|
|
476
|
+
const aoPassar = useRef(arrastarPorCima);
|
|
477
|
+
aoPassar.current = arrastarPorCima;
|
|
478
|
+
const aoAcabar = useRef(acabarArrasto);
|
|
479
|
+
aoAcabar.current = acabarArrasto;
|
|
480
|
+
const largarOuvintes = useRef(() => {
|
|
481
|
+
});
|
|
482
|
+
const acabarPendente = useRef(() => {
|
|
483
|
+
});
|
|
484
|
+
useEffect(() => () => {
|
|
485
|
+
largarOuvintes.current();
|
|
486
|
+
cursorDeArrasto(false);
|
|
487
|
+
}, []);
|
|
488
|
+
const premirTitulo = (e, chave) => {
|
|
489
|
+
if (e.button !== 0 || !e.isPrimary) return;
|
|
490
|
+
if (e.target.closest("input, textarea, select")) return;
|
|
491
|
+
acabarPendente.current();
|
|
492
|
+
largarOuvintes.current();
|
|
493
|
+
const x0 = e.clientX;
|
|
494
|
+
const y0 = e.clientY;
|
|
495
|
+
let comecou = false;
|
|
496
|
+
const mover = (ev) => {
|
|
497
|
+
if (!comecou) {
|
|
498
|
+
if (Math.hypot(ev.clientX - x0, ev.clientY - y0) < LIMIAR_ARRASTO) return;
|
|
499
|
+
comecou = true;
|
|
500
|
+
cursorDeArrasto(true);
|
|
501
|
+
aoComecar.current(chave);
|
|
502
|
+
}
|
|
503
|
+
aoPassar.current(ev.clientX);
|
|
504
|
+
};
|
|
505
|
+
const acabar = (gravar) => {
|
|
506
|
+
acabarPendente.current = () => {
|
|
507
|
+
};
|
|
508
|
+
largarOuvintes.current();
|
|
509
|
+
if (!comecou) return;
|
|
510
|
+
cursorDeArrasto(false);
|
|
511
|
+
aoAcabar.current(gravar);
|
|
512
|
+
};
|
|
513
|
+
const soltar = () => {
|
|
514
|
+
if (comecou) {
|
|
515
|
+
const engolir = (ev) => {
|
|
516
|
+
ev.stopPropagation();
|
|
517
|
+
ev.preventDefault();
|
|
518
|
+
};
|
|
519
|
+
document.addEventListener("click", engolir, { capture: true, once: true });
|
|
520
|
+
setTimeout(() => document.removeEventListener("click", engolir, { capture: true }), 0);
|
|
521
|
+
}
|
|
522
|
+
acabar(true);
|
|
523
|
+
};
|
|
524
|
+
const cancelar = () => acabar(false);
|
|
525
|
+
acabarPendente.current = () => acabar(true);
|
|
526
|
+
const tecla = (ev) => {
|
|
527
|
+
if (ev.key === "Escape") acabar(false);
|
|
528
|
+
};
|
|
529
|
+
document.addEventListener("pointermove", mover);
|
|
530
|
+
document.addEventListener("pointerup", soltar);
|
|
531
|
+
document.addEventListener("pointercancel", cancelar);
|
|
532
|
+
document.addEventListener("keydown", tecla);
|
|
533
|
+
largarOuvintes.current = () => {
|
|
534
|
+
document.removeEventListener("pointermove", mover);
|
|
535
|
+
document.removeEventListener("pointerup", soltar);
|
|
536
|
+
document.removeEventListener("pointercancel", cancelar);
|
|
537
|
+
document.removeEventListener("keydown", tecla);
|
|
538
|
+
largarOuvintes.current = () => {
|
|
539
|
+
};
|
|
540
|
+
};
|
|
541
|
+
};
|
|
542
|
+
useLayoutEffect(() => {
|
|
543
|
+
const ths = Array.from(cabecalhoRef.current?.children ?? []);
|
|
544
|
+
const agora = /* @__PURE__ */ new Map();
|
|
545
|
+
for (const th of ths) {
|
|
546
|
+
const k = th.dataset.col;
|
|
547
|
+
if (k) agora.set(k, th.offsetLeft);
|
|
548
|
+
}
|
|
549
|
+
const antes = posColunas.current;
|
|
550
|
+
posColunas.current = agora;
|
|
551
|
+
if (!onMoverColuna || !antes.size) return;
|
|
552
|
+
const raiz = raizRef.current;
|
|
553
|
+
if (!raiz) return;
|
|
554
|
+
let mexeu = false;
|
|
555
|
+
for (const [k, x] of agora) {
|
|
556
|
+
const delta = (antes.get(k) ?? x) - x;
|
|
557
|
+
const m = molas.current.get(k);
|
|
558
|
+
if (!delta && !m) continue;
|
|
559
|
+
const mola = m ?? { x: 0, v: 0, destino: 0, parada: false, els: [] };
|
|
560
|
+
mola.x += delta;
|
|
561
|
+
mola.destino = 0;
|
|
562
|
+
mola.parada = false;
|
|
563
|
+
mola.els = Array.from(raiz.querySelectorAll(`[data-col="${CSS.escape(k)}"]`));
|
|
564
|
+
const tr = `translateX(${mola.x}px)`;
|
|
565
|
+
for (const el of mola.els) el.style.transform = tr;
|
|
566
|
+
molas.current.set(k, mola);
|
|
567
|
+
mexeu = true;
|
|
568
|
+
}
|
|
569
|
+
if (mexeu) arrancarMolas();
|
|
570
|
+
}, [columns, onMoverColuna, arrancarMolas]);
|
|
571
|
+
const [esquerdas, setEsquerdas] = useState([]);
|
|
572
|
+
useLayoutEffect(() => {
|
|
573
|
+
if (!nFixas) {
|
|
574
|
+
setEsquerdas((e) => e.length ? [] : e);
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
const medir = () => {
|
|
578
|
+
const ths = Array.from(cabecalhoRef.current?.children ?? []);
|
|
579
|
+
let acc = 0;
|
|
580
|
+
const out = [];
|
|
581
|
+
for (let i = 0; i < nFixas; i++) {
|
|
582
|
+
out.push(acc);
|
|
583
|
+
acc += ths[i]?.offsetWidth ?? 0;
|
|
584
|
+
}
|
|
585
|
+
setEsquerdas((prev) => prev.length === out.length && prev.every((v, i) => v === out[i]) ? prev : out);
|
|
586
|
+
};
|
|
587
|
+
medir();
|
|
588
|
+
const ro = new ResizeObserver(medir);
|
|
589
|
+
for (const th of Array.from(cabecalhoRef.current?.children ?? [])) ro.observe(th);
|
|
590
|
+
return () => ro.disconnect();
|
|
591
|
+
}, [nFixas, columns, data, esquerdas]);
|
|
592
|
+
const fundoLinha = (k) => `${selectable && selectedKeys.has(k) ? "bg-[#f2fdf9]" : "bg-white"} group-hover/linha:bg-slate-50`;
|
|
593
|
+
const cabecaFixa = (i) => {
|
|
594
|
+
const realcadaAqui = realcada !== null && realcada === chaveDoIndice(i);
|
|
595
|
+
const linhaDeBaixo = bordasSeparadas && !fundoNosTitulos;
|
|
596
|
+
const f = fixa(
|
|
597
|
+
i,
|
|
598
|
+
realcadaAqui ? "bg-[color-mix(in_srgb,var(--color-proef-blue)_15%,var(--color-slate-50))]" : "bg-slate-50",
|
|
599
|
+
realcadaAqui ? linhaDeBaixo ? "shadow-[inset_0_-2px_0_0_var(--color-slate-200),inset_1px_0_0_0_rgb(0_118_206/0.35),inset_-1px_0_0_0_rgb(0_118_206/0.35)]" : "shadow-[inset_1px_0_0_0_rgb(0_118_206/0.35),inset_-1px_0_0_0_rgb(0_118_206/0.35)]" : linhaDeBaixo ? "shadow-[inset_0_-2px_0_0_var(--color-slate-200)]" : ""
|
|
600
|
+
);
|
|
601
|
+
return { className: f.className, style: f.style ? { ...f.style, zIndex: 30 } : void 0 };
|
|
602
|
+
};
|
|
603
|
+
const filetesFixos = bordasSeparadas ? "[tr+tr>&]:shadow-[inset_0_1px_0_0_var(--color-slate-100)]" : "";
|
|
604
|
+
const fundoRealceFixa = "bg-[color-mix(in_srgb,var(--color-proef-blue)_5%,white)]";
|
|
605
|
+
const filetesRealceFixa = bordasSeparadas ? "shadow-[inset_1px_0_0_0_rgb(0_118_206/0.35),inset_-1px_0_0_0_rgb(0_118_206/0.35)] [tr+tr>&]:shadow-[inset_0_1px_0_0_var(--color-slate-100),inset_1px_0_0_0_rgb(0_118_206/0.35),inset_-1px_0_0_0_rgb(0_118_206/0.35)]" : "shadow-[inset_1px_0_0_0_rgb(0_118_206/0.35),inset_-1px_0_0_0_rgb(0_118_206/0.35)]";
|
|
606
|
+
const chaveDoIndice = (i) => columns[i - (selectable ? 1 : 0)]?.key;
|
|
607
|
+
const fixaMedida = (chave) => {
|
|
608
|
+
const i = columns.findIndex((c) => c.key === chave) + (selectable ? 1 : 0);
|
|
609
|
+
return i < nFixas && esquerdas.length === nFixas;
|
|
610
|
+
};
|
|
611
|
+
const fixa = (i, fundo, filete = filetesFixos) => {
|
|
612
|
+
if (filete === filetesFixos && realcada !== null && realcada === chaveDoIndice(i)) {
|
|
613
|
+
fundo = fundoRealceFixa;
|
|
614
|
+
filete = filetesRealceFixa;
|
|
615
|
+
}
|
|
616
|
+
return i < nFixas && esquerdas.length === nFixas ? {
|
|
617
|
+
style: { position: "sticky", left: esquerdas[i], zIndex: 10 },
|
|
618
|
+
// Opaca de propósito: por baixo passa o resto da tabela a rolar.
|
|
619
|
+
// A borda marca onde acaba o bloco congelado, e só aparece quando
|
|
620
|
+
// há mesmo colunas a passar por baixo (rolado para o lado): parada,
|
|
621
|
+
// era uma linha a mais sem razão à vista.
|
|
622
|
+
className: `${fundo} ${filete} ${i === nFixas - 1 && roladoLado ? "border-r border-slate-200" : ""}`
|
|
623
|
+
} : { style: void 0, className: "" };
|
|
624
|
+
};
|
|
625
|
+
const renderGroupNodes = (nodes, depth) => {
|
|
626
|
+
return nodes.map((node) => {
|
|
627
|
+
const isCollapsed = collapsedGroups.has(node.path);
|
|
628
|
+
const hasChildren = node.children.length > 0;
|
|
629
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
630
|
+
/* @__PURE__ */ jsx("tr", { className: "bg-slate-50/80 cursor-pointer select-none", onClick: () => toggleCollapse(node.path), children: /* @__PURE__ */ jsx("td", { colSpan: colCount, className: "px-4 py-1.5 border-b border-t border-slate-100", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", style: { paddingLeft: depth * 16 }, children: [
|
|
631
|
+
/* @__PURE__ */ jsx(
|
|
632
|
+
ChevronRightIcon,
|
|
633
|
+
{
|
|
634
|
+
size: 11,
|
|
635
|
+
className: `text-proef-blue/60 transition-transform flex-shrink-0 ${isCollapsed ? "" : "rotate-90"}`
|
|
636
|
+
}
|
|
637
|
+
),
|
|
638
|
+
/* @__PURE__ */ jsx("span", { className: "text-micro font-black uppercase tracking-[0.15em] text-proef-blue/70", children: node.val }),
|
|
639
|
+
/* @__PURE__ */ jsxs("span", { className: "text-micro text-slate-400 ml-1", children: [
|
|
640
|
+
"(",
|
|
641
|
+
node.items.length,
|
|
642
|
+
")"
|
|
643
|
+
] })
|
|
644
|
+
] }) }) }),
|
|
645
|
+
!isCollapsed && (hasChildren ? renderGroupNodes(node.children, depth + 1) : node.items.map((row) => /* @__PURE__ */ jsxs(
|
|
646
|
+
"tr",
|
|
647
|
+
{
|
|
648
|
+
onClick: () => onRowClick?.(row),
|
|
649
|
+
onDoubleClick: () => onRowDoubleClick?.(row),
|
|
650
|
+
className: `group/linha hover:bg-slate-50 transition-colors ${onRowClick || onRowDoubleClick ? "cursor-pointer" : ""} ${selectable && selectedKeys.has(rowKey(row)) ? "bg-proef-turquoise/5" : ""} ${rowClassName?.(row) ?? ""}`,
|
|
651
|
+
children: [
|
|
652
|
+
selectable && /* @__PURE__ */ jsx("td", { style: fixa(0, fundoLinha(rowKey(row))).style, className: `px-4 py-3 ${fixa(0, fundoLinha(rowKey(row))).className}`, onClick: (e) => {
|
|
653
|
+
e.stopPropagation();
|
|
654
|
+
toggleRow(rowKey(row));
|
|
655
|
+
}, children: /* @__PURE__ */ jsx("div", { className: `w-4 h-4 flex items-center justify-center border transition-colors ${selectedKeys.has(rowKey(row)) ? "bg-primary border-primary" : "border-slate-300 hover:border-slate-400"}`, children: selectedKeys.has(rowKey(row)) && /* @__PURE__ */ jsx(CheckIcon, { size: 9, strokeWidth: 3, className: "text-white" }) }) }),
|
|
656
|
+
columns.map((col, i) => {
|
|
657
|
+
const f = fixa(i + (selectable ? 1 : 0), fundoLinha(rowKey(row)));
|
|
658
|
+
return /* @__PURE__ */ jsx("td", { style: f.style, className: `px-3 py-1.5 ${col.cellClassName ?? ""} ${f.className} ${recuoFim(i)} ${realce(col.key)} ${transicaoRealce}`, "data-col": col.key, children: col.render(row) }, col.key);
|
|
659
|
+
})
|
|
660
|
+
]
|
|
661
|
+
},
|
|
662
|
+
rowKey(row)
|
|
663
|
+
)))
|
|
664
|
+
] }, node.path);
|
|
665
|
+
});
|
|
666
|
+
};
|
|
667
|
+
const aCarregar = isLoading || (isAllDataLoading || !allData) && (hasActiveFilters || !!sortCol || isGrouped);
|
|
668
|
+
const internalTotalPages = pageSize && isClientMode && !isGrouped ? Math.max(1, Math.ceil(filteredData.length / pageSize)) : 1;
|
|
669
|
+
useEffect(() => {
|
|
670
|
+
setInternalPage((p) => Math.min(Math.max(1, p), internalTotalPages));
|
|
671
|
+
}, [internalTotalPages]);
|
|
672
|
+
const paginatedData = pageSize && isClientMode && !isGrouped ? filteredData.slice((internalPage - 1) * pageSize, internalPage * pageSize) : filteredData;
|
|
673
|
+
const onVistaRef = useRef(onVista);
|
|
674
|
+
onVistaRef.current = onVista;
|
|
675
|
+
useEffect(() => {
|
|
676
|
+
onVistaRef.current?.({
|
|
677
|
+
visible: filteredData.length,
|
|
678
|
+
filtered: isClientMode && hasActiveFilters,
|
|
679
|
+
selfPaginated: isClientMode
|
|
680
|
+
});
|
|
681
|
+
}, [filteredData.length, isClientMode, hasActiveFilters]);
|
|
682
|
+
const semLinhas = aCarregar || (isGrouped ? groups.length === 0 : paginatedData.length === 0);
|
|
683
|
+
const setDateFilter = (colKey, part, val) => {
|
|
684
|
+
if (!allData) onDataNeeded?.();
|
|
685
|
+
setDateFilters((prev) => {
|
|
686
|
+
const cur = { ...prev[colKey] ?? {} };
|
|
687
|
+
if (val) cur[part] = val;
|
|
688
|
+
else delete cur[part];
|
|
689
|
+
const next = { ...prev };
|
|
690
|
+
if (!cur.from && !cur.to) delete next[colKey];
|
|
691
|
+
else next[colKey] = cur;
|
|
692
|
+
return next;
|
|
693
|
+
});
|
|
694
|
+
};
|
|
695
|
+
const clearColumnFilter = (colKey) => {
|
|
696
|
+
setColumnFilters((prev) => {
|
|
697
|
+
const n = { ...prev };
|
|
698
|
+
delete n[colKey];
|
|
699
|
+
return n;
|
|
700
|
+
});
|
|
701
|
+
setDateFilters((prev) => {
|
|
702
|
+
const n = { ...prev };
|
|
703
|
+
delete n[colKey];
|
|
704
|
+
return n;
|
|
705
|
+
});
|
|
706
|
+
setNumFilters((prev) => {
|
|
707
|
+
const n = { ...prev };
|
|
708
|
+
delete n[colKey];
|
|
709
|
+
return n;
|
|
710
|
+
});
|
|
711
|
+
};
|
|
712
|
+
const clearAllFilters = () => {
|
|
713
|
+
setColumnFilters({});
|
|
714
|
+
setDateFilters({});
|
|
715
|
+
setNumFilters({});
|
|
716
|
+
};
|
|
717
|
+
const setNumFilter = (colKey, min, max) => {
|
|
718
|
+
if (!allData) onDataNeeded?.();
|
|
719
|
+
setColumnFilters((prev) => {
|
|
720
|
+
if (!(colKey in prev)) return prev;
|
|
721
|
+
const n = { ...prev };
|
|
722
|
+
delete n[colKey];
|
|
723
|
+
return n;
|
|
724
|
+
});
|
|
725
|
+
setNumFilters((prev) => {
|
|
726
|
+
const n = { ...prev };
|
|
727
|
+
if (min === "" && max === "") delete n[colKey];
|
|
728
|
+
else n[colKey] = { ...min !== "" ? { min } : {}, ...max !== "" ? { max } : {} };
|
|
729
|
+
return n;
|
|
730
|
+
});
|
|
731
|
+
};
|
|
732
|
+
const aplicarValores = (colKey, vals) => {
|
|
733
|
+
if (!allData) onDataNeeded?.();
|
|
734
|
+
setNumFilters((prev) => {
|
|
735
|
+
if (!(colKey in prev)) return prev;
|
|
736
|
+
const n = { ...prev };
|
|
737
|
+
delete n[colKey];
|
|
738
|
+
return n;
|
|
739
|
+
});
|
|
740
|
+
setColumnFilters((prev) => {
|
|
741
|
+
const n = { ...prev };
|
|
742
|
+
if (vals.size) n[colKey] = vals;
|
|
743
|
+
else delete n[colKey];
|
|
744
|
+
return n;
|
|
745
|
+
});
|
|
746
|
+
};
|
|
747
|
+
const hasActiveFilter = (colKey) => (columnFilters[colKey]?.size ?? 0) > 0 || dateFilterActive(dateFilters[colKey]) || numFilterActive(numFilters[colKey]);
|
|
748
|
+
const totalActiveFilters = Object.values(columnFilters).filter((s) => s?.size > 0).length + Object.values(dateFilters).filter(dateFilterActive).length + Object.values(numFilters).filter(numFilterActive).length;
|
|
749
|
+
const visibleKeys = useMemo(() => paginatedData.map((row) => rowKey(row)), [paginatedData, rowKey]);
|
|
750
|
+
const toggleRow = (key) => setSelectedKeys((prev) => {
|
|
751
|
+
const next = new Set(prev);
|
|
752
|
+
if (next.has(key)) next.delete(key);
|
|
753
|
+
else next.add(key);
|
|
754
|
+
onSelectionChange?.(next);
|
|
755
|
+
return next;
|
|
756
|
+
});
|
|
757
|
+
const toggleAll = () => setSelectedKeys((prev) => {
|
|
758
|
+
const allSelected = visibleKeys.every((k) => prev.has(k));
|
|
759
|
+
const next = new Set(prev);
|
|
760
|
+
if (allSelected) visibleKeys.forEach((k) => next.delete(k));
|
|
761
|
+
else visibleKeys.forEach((k) => next.add(k));
|
|
762
|
+
onSelectionChange?.(next);
|
|
763
|
+
return next;
|
|
764
|
+
});
|
|
765
|
+
const allVisibleSelected = visibleKeys.length > 0 && visibleKeys.every((k) => selectedKeys.has(k));
|
|
766
|
+
const someVisibleSelected = visibleKeys.some((k) => selectedKeys.has(k)) && !allVisibleSelected;
|
|
767
|
+
const fechaFiltro = () => {
|
|
768
|
+
setOpenFilterCol(null);
|
|
769
|
+
setAncoraFiltro(null);
|
|
770
|
+
};
|
|
771
|
+
const chaveColunas = `${columns.map((c) => c.key).sort().join("|")}|${selectable ? 1 : 0}`;
|
|
772
|
+
const SEL = "\0sel";
|
|
773
|
+
const chavesVista = [...selectable ? [SEL] : [], ...columns.map((c) => c.key)];
|
|
774
|
+
const [larguras, setLarguras] = useState(null);
|
|
775
|
+
const corpoRef = useRef(null);
|
|
776
|
+
const medidaRef = useRef(null);
|
|
777
|
+
const peloConjunto = preencheAltura && larguraPeloConjunto;
|
|
778
|
+
useLayoutEffect(() => {
|
|
779
|
+
setLarguras(null);
|
|
780
|
+
}, [chaveColunas, peloConjunto ? allData : null]);
|
|
781
|
+
const exemplares = useMemo(() => {
|
|
782
|
+
if (!peloConjunto || larguras || !allData?.length) return null;
|
|
783
|
+
const porColuna = columns.map((col) => {
|
|
784
|
+
const vistos = /* @__PURE__ */ new Map();
|
|
785
|
+
for (const row of allData) {
|
|
786
|
+
const k = String(col.value ? col.value(row) ?? "" : "");
|
|
787
|
+
if (!vistos.has(k)) vistos.set(k, row);
|
|
788
|
+
}
|
|
789
|
+
return [...vistos.values()];
|
|
790
|
+
});
|
|
791
|
+
const n = Math.max(...porColuna.map((l) => l.length));
|
|
792
|
+
return { porColuna, n };
|
|
793
|
+
}, [peloConjunto, larguras, allData, chaveColunas]);
|
|
794
|
+
useLayoutEffect(() => {
|
|
795
|
+
if (!preencheAltura || larguras || isGrouped) return;
|
|
796
|
+
if (aCarregar && esqueletoAoCarregar) return;
|
|
797
|
+
const ths = Array.from(cabecalhoRef.current?.children ?? []);
|
|
798
|
+
const fonte = peloConjunto ? medidaRef.current : corpoRef.current;
|
|
799
|
+
const tds = Array.from(fonte?.rows?.[0]?.cells ?? []);
|
|
800
|
+
if (!ths.length || !tds.length) return;
|
|
801
|
+
const novas = Object.fromEntries(ths.map((th, i) => [
|
|
802
|
+
chavesVista[i] ?? String(i),
|
|
803
|
+
Math.ceil(Math.max(th.getBoundingClientRect().width, tds[i]?.getBoundingClientRect().width ?? 0))
|
|
804
|
+
]));
|
|
805
|
+
setLarguras(novas);
|
|
806
|
+
if (esqueletoAoCarregar && storageKey) {
|
|
807
|
+
try {
|
|
808
|
+
localStorage.setItem(`dt_larguras_${storageKey}`, JSON.stringify({ colunas: chaveColunas, larguras: novas }));
|
|
809
|
+
} catch {
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
}, [preencheAltura, larguras, isGrouped, chaveColunas, paginatedData, exemplares, aCarregar, esqueletoAoCarregar]);
|
|
813
|
+
const largurasGuardadas = useMemo(() => {
|
|
814
|
+
if (!esqueletoAoCarregar || !storageKey) return null;
|
|
815
|
+
try {
|
|
816
|
+
const g = JSON.parse(localStorage.getItem(`dt_larguras_${storageKey}`) ?? "null");
|
|
817
|
+
return g?.colunas === chaveColunas ? g.larguras : null;
|
|
818
|
+
} catch {
|
|
819
|
+
return null;
|
|
820
|
+
}
|
|
821
|
+
}, [esqueletoAoCarregar, storageKey, chaveColunas]);
|
|
822
|
+
const [largurasTitulos, setLargurasTitulos] = useState(null);
|
|
823
|
+
const esqueletoSemMedida = preencheAltura && !isGrouped && aCarregar && esqueletoAoCarregar && !larguras && !largurasGuardadas;
|
|
824
|
+
useLayoutEffect(() => {
|
|
825
|
+
if (!esqueletoSemMedida) {
|
|
826
|
+
setLargurasTitulos(null);
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
const ths = Array.from(cabecalhoRef.current?.children ?? []);
|
|
830
|
+
if (!ths.length) return;
|
|
831
|
+
setLargurasTitulos(Object.fromEntries(ths.map((th, i) => [chavesVista[i] ?? String(i), Math.ceil(th.getBoundingClientRect().width)])));
|
|
832
|
+
}, [esqueletoSemMedida, chaveColunas]);
|
|
833
|
+
const largurasVista = larguras ?? (aCarregar && esqueletoAoCarregar ? largurasGuardadas ?? largurasTitulos : null);
|
|
834
|
+
const caixaCorpoRef = useRef(null);
|
|
835
|
+
const [caixaCorpo, setCaixaCorpo] = useState(null);
|
|
836
|
+
const refCaixaCorpo = useCallback((el) => {
|
|
837
|
+
caixaCorpoRef.current = el;
|
|
838
|
+
setCaixaCorpo(el);
|
|
839
|
+
}, []);
|
|
840
|
+
const caixaCabecalhoRef = useRef(null);
|
|
841
|
+
const [restaDireita, setRestaDireita] = useState(false);
|
|
842
|
+
const [roladoLado, setRoladoLado] = useState(false);
|
|
843
|
+
const [caixaSimples, setCaixaSimples] = useState(null);
|
|
844
|
+
useEffect(() => {
|
|
845
|
+
const c = caixaCorpo ?? caixaSimples;
|
|
846
|
+
if (!nFixas || !c) return;
|
|
847
|
+
const ver = () => {
|
|
848
|
+
const rolado = c.scrollLeft > 0;
|
|
849
|
+
setRoladoLado((prev) => prev === rolado ? prev : rolado);
|
|
850
|
+
};
|
|
851
|
+
ver();
|
|
852
|
+
c.addEventListener("scroll", ver, { passive: true });
|
|
853
|
+
return () => c.removeEventListener("scroll", ver);
|
|
854
|
+
}, [nFixas, caixaCorpo, caixaSimples]);
|
|
855
|
+
useEffect(() => {
|
|
856
|
+
const c = caixaCorpo;
|
|
857
|
+
if (!esbaterDireita || !c) return;
|
|
858
|
+
const ver = () => {
|
|
859
|
+
const resta = c.scrollLeft + c.clientWidth < c.scrollWidth - 1;
|
|
860
|
+
setRestaDireita((prev) => prev === resta ? prev : resta);
|
|
861
|
+
};
|
|
862
|
+
ver();
|
|
863
|
+
c.addEventListener("scroll", ver, { passive: true });
|
|
864
|
+
const ro = new ResizeObserver(ver);
|
|
865
|
+
ro.observe(c);
|
|
866
|
+
if (c.firstElementChild) ro.observe(c.firstElementChild);
|
|
867
|
+
return () => {
|
|
868
|
+
c.removeEventListener("scroll", ver);
|
|
869
|
+
ro.disconnect();
|
|
870
|
+
};
|
|
871
|
+
}, [esbaterDireita, caixaCorpo]);
|
|
872
|
+
const mascaraDireita = "linear-gradient(to right, #000 calc(100% - 48px), transparent)";
|
|
873
|
+
const [barra, setBarra] = useState(0);
|
|
874
|
+
useLayoutEffect(() => {
|
|
875
|
+
const medir = () => {
|
|
876
|
+
const c2 = caixaCorpoRef.current;
|
|
877
|
+
if (!c2) return;
|
|
878
|
+
const w = c2.offsetWidth - c2.clientWidth;
|
|
879
|
+
setBarra((prev) => prev === w ? prev : w);
|
|
880
|
+
};
|
|
881
|
+
medir();
|
|
882
|
+
const c = caixaCorpoRef.current;
|
|
883
|
+
if (!c) return;
|
|
884
|
+
const ro = new ResizeObserver(medir);
|
|
885
|
+
ro.observe(c);
|
|
886
|
+
return () => ro.disconnect();
|
|
887
|
+
}, [preencheAltura, paginatedData]);
|
|
888
|
+
const grupoColunas = largurasVista ? /* @__PURE__ */ jsx("colgroup", { children: chavesVista.map((k) => /* @__PURE__ */ jsx("col", { style: { width: largurasVista[k] } }, k)) }) : null;
|
|
889
|
+
const estiloTabela = largurasVista ? { tableLayout: "fixed", width: chavesVista.reduce((a, k) => a + (largurasVista[k] ?? 0), 0), minWidth: "100%" } : { width: "max-content" };
|
|
890
|
+
const cabecalho = (fixoNoTopo) => /* @__PURE__ */ jsx("thead", { className: fixoNoTopo ? "sticky top-0 z-20" : void 0, children: /* @__PURE__ */ jsxs("tr", { ref: cabecalhoRef, className: `text-micro font-black uppercase text-slate-400 tracking-[0.15em] ${!bordasSeparadas ? "border-b-2 border-slate-200 bg-slate-50" : fundoNosTitulos ? "[&>th]:border-b-2 [&>th]:border-slate-200" : "shadow-[inset_0_-2px_0_0_var(--color-slate-200)]"}`, children: [
|
|
891
|
+
selectable && /* @__PURE__ */ jsx("th", { style: cabecaFixa(0).style, className: `px-4 py-3 w-10 ${fundoNosTitulos ? "bg-slate-50" : ""} ${cabecaFixa(0).className}`, children: /* @__PURE__ */ jsx("button", { onClick: toggleAll, className: `w-4 h-4 flex items-center justify-center border transition-colors ${allVisibleSelected ? "bg-primary border-primary" : someVisibleSelected ? "bg-slate-300 border-slate-300" : "border-slate-300 hover:border-slate-400"}`, children: (allVisibleSelected || someVisibleSelected) && /* @__PURE__ */ jsx(CheckIcon, { size: 9, strokeWidth: 3, className: "text-white" }) }) }),
|
|
892
|
+
columns.map((col, i) => {
|
|
893
|
+
const canSort = col.sortable !== false && !!col.value;
|
|
894
|
+
const canFilter = col.filterable !== false && !!col.value;
|
|
895
|
+
const canGroup = col.groupable === true && !!col.value;
|
|
896
|
+
const isSortActive = sortCol === col.key;
|
|
897
|
+
const isFiltered = hasActiveFilter(col.key);
|
|
898
|
+
const isFilterOpen = openFilterCol === col.key;
|
|
899
|
+
const isColGrouped = groupByKeys.includes(col.key);
|
|
900
|
+
const arrastavel = !!onMoverColuna && !isFilterOpen;
|
|
901
|
+
return /* @__PURE__ */ jsxs(
|
|
902
|
+
"th",
|
|
903
|
+
{
|
|
904
|
+
style: cabecaFixa(i + (selectable ? 1 : 0)).style,
|
|
905
|
+
onPointerDown: arrastavel ? (e) => premirTitulo(e, col.key) : void 0,
|
|
906
|
+
className: `px-4 py-3 ${col.headerClassName ?? ""} ${cabecaFixa(i + (selectable ? 1 : 0)).className} ${arrastavel ? "cursor-grab" : ""} ${realce(col.key, true)} ${transicaoRealce}`,
|
|
907
|
+
"data-col": col.key,
|
|
908
|
+
children: [
|
|
909
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 group/hdr whitespace-nowrap select-none", children: [
|
|
910
|
+
canSort ? /* @__PURE__ */ jsxs(
|
|
911
|
+
"button",
|
|
912
|
+
{
|
|
913
|
+
onClick: () => {
|
|
914
|
+
if (!allData) onDataNeeded?.();
|
|
915
|
+
if (sortCol === col.key) setSortDir((d) => d === "asc" ? "desc" : "asc");
|
|
916
|
+
else {
|
|
917
|
+
setSortCol(col.key);
|
|
918
|
+
setSortDir("asc");
|
|
919
|
+
}
|
|
920
|
+
},
|
|
921
|
+
className: `flex items-center gap-0.5 transition-colors hover:text-slate-700 ${isSortActive ? "text-proef-blue" : ""}`,
|
|
922
|
+
children: [
|
|
923
|
+
/* @__PURE__ */ jsx("span", { children: col.label }),
|
|
924
|
+
isSortActive && sortDir === "asc" ? /* @__PURE__ */ jsx(ChevronUpIcon, { size: 11 }) : isSortActive && sortDir === "desc" ? /* @__PURE__ */ jsx(ChevronDownIcon, { size: 11 }) : /* @__PURE__ */ jsx(ChevronsUpDownIcon, { size: 11, className: "opacity-50 group-hover/hdr:opacity-100" })
|
|
925
|
+
]
|
|
926
|
+
}
|
|
927
|
+
) : /* @__PURE__ */ jsx("span", { children: col.label }),
|
|
928
|
+
canGroup && /* @__PURE__ */ jsx(
|
|
929
|
+
"button",
|
|
930
|
+
{
|
|
931
|
+
onClick: () => toggleGroup(col.key),
|
|
932
|
+
title: isColGrouped ? L.ungroupBy(col.label) : L.groupBy(col.label),
|
|
933
|
+
"aria-label": isColGrouped ? L.ungroupBy(col.label) : L.groupBy(col.label),
|
|
934
|
+
"aria-pressed": isColGrouped,
|
|
935
|
+
className: `p-0.5 rounded transition-colors ${isColGrouped ? "text-violet-600 bg-violet-100 opacity-100" : "text-slate-400 opacity-50 group-hover/hdr:opacity-100 hover:text-slate-600"}`,
|
|
936
|
+
children: /* @__PURE__ */ jsx(LayersIcon, { size: 10 })
|
|
937
|
+
}
|
|
938
|
+
),
|
|
939
|
+
canFilter && /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
940
|
+
/* @__PURE__ */ jsx(
|
|
941
|
+
"button",
|
|
942
|
+
{
|
|
943
|
+
onClick: (e) => {
|
|
944
|
+
const r = e.currentTarget.getBoundingClientRect();
|
|
945
|
+
if (isFilterOpen) {
|
|
946
|
+
fechaFiltro();
|
|
947
|
+
} else {
|
|
948
|
+
if (!allData) onDataNeeded?.();
|
|
949
|
+
setAncoraFiltro(r);
|
|
950
|
+
setOpenFilterCol(col.key);
|
|
951
|
+
}
|
|
952
|
+
},
|
|
953
|
+
title: L.filterBy(col.label),
|
|
954
|
+
"aria-label": L.filterBy(col.label),
|
|
955
|
+
"aria-expanded": isFilterOpen,
|
|
956
|
+
className: `p-0.5 transition-colors ${isFiltered || isFilterOpen ? "text-proef-blue opacity-100" : "text-slate-400 opacity-50 group-hover/hdr:opacity-100 hover:text-slate-600"}`,
|
|
957
|
+
children: /* @__PURE__ */ jsx(FilterIcon, { size: 10 })
|
|
958
|
+
}
|
|
959
|
+
),
|
|
960
|
+
isFilterOpen && ancoraFiltro && /* @__PURE__ */ jsx(
|
|
961
|
+
ColumnFilter,
|
|
962
|
+
{
|
|
963
|
+
labels: L,
|
|
964
|
+
canSort,
|
|
965
|
+
ancora: ancoraFiltro,
|
|
966
|
+
tipo: col.filterType === "date" ? "data" : col.filterType === "number" ? "numero" : "texto",
|
|
967
|
+
valores: col.filterType === "date" ? [] : getUniqueValues(col.key),
|
|
968
|
+
seleccionados: columnFilters[col.key] ?? /* @__PURE__ */ new Set(),
|
|
969
|
+
intervalo: dateFilters[col.key] ?? {},
|
|
970
|
+
numero: numFilters[col.key] ?? {},
|
|
971
|
+
ordenadaPor: sortCol === col.key ? sortDir : null,
|
|
972
|
+
aCarregar: !allData && !!isAllDataLoading,
|
|
973
|
+
onOrdenar: (dir) => {
|
|
974
|
+
setSortCol(col.key);
|
|
975
|
+
setSortDir(dir);
|
|
976
|
+
},
|
|
977
|
+
onAplicar: (vals) => {
|
|
978
|
+
aplicarValores(col.key, vals);
|
|
979
|
+
fechaFiltro();
|
|
980
|
+
},
|
|
981
|
+
onAplicarDatas: (de, ate) => {
|
|
982
|
+
setDateFilter(col.key, "from", de);
|
|
983
|
+
setDateFilter(col.key, "to", ate);
|
|
984
|
+
fechaFiltro();
|
|
985
|
+
},
|
|
986
|
+
onAplicarNumeros: (min, max) => {
|
|
987
|
+
setNumFilter(col.key, min, max);
|
|
988
|
+
fechaFiltro();
|
|
989
|
+
},
|
|
990
|
+
onLimpar: () => {
|
|
991
|
+
clearColumnFilter(col.key);
|
|
992
|
+
fechaFiltro();
|
|
993
|
+
},
|
|
994
|
+
onFechar: fechaFiltro
|
|
995
|
+
}
|
|
996
|
+
)
|
|
997
|
+
] }),
|
|
998
|
+
col.extraFilters?.map((sf) => {
|
|
999
|
+
const isEfFiltered = hasActiveFilter(sf.key);
|
|
1000
|
+
const isEfOpen = openFilterCol === sf.key;
|
|
1001
|
+
return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
1002
|
+
/* @__PURE__ */ jsx(
|
|
1003
|
+
"button",
|
|
1004
|
+
{
|
|
1005
|
+
onClick: (e) => {
|
|
1006
|
+
const r = e.currentTarget.getBoundingClientRect();
|
|
1007
|
+
if (isEfOpen) {
|
|
1008
|
+
fechaFiltro();
|
|
1009
|
+
} else {
|
|
1010
|
+
setAncoraFiltro(r);
|
|
1011
|
+
setOpenFilterCol(sf.key);
|
|
1012
|
+
}
|
|
1013
|
+
},
|
|
1014
|
+
title: L.filterBy(sf.label),
|
|
1015
|
+
"aria-label": L.filterBy(sf.label),
|
|
1016
|
+
"aria-expanded": isEfOpen,
|
|
1017
|
+
className: `p-0.5 transition-colors ${isEfFiltered || isEfOpen ? "text-violet-600 opacity-100" : "text-slate-300 opacity-40 group-hover/hdr:opacity-90 hover:text-slate-500"}`,
|
|
1018
|
+
children: /* @__PURE__ */ jsx(FilterIcon, { size: 9 })
|
|
1019
|
+
}
|
|
1020
|
+
),
|
|
1021
|
+
isEfOpen && ancoraFiltro && /* @__PURE__ */ jsx(
|
|
1022
|
+
ColumnFilter,
|
|
1023
|
+
{
|
|
1024
|
+
labels: L,
|
|
1025
|
+
label: sf.label,
|
|
1026
|
+
ancora: ancoraFiltro,
|
|
1027
|
+
tipo: sf.filterType === "date" ? "data" : sf.filterType === "number" ? "numero" : "texto",
|
|
1028
|
+
valores: sf.filterType === "date" ? [] : getUniqueValues(sf.key),
|
|
1029
|
+
seleccionados: columnFilters[sf.key] ?? /* @__PURE__ */ new Set(),
|
|
1030
|
+
intervalo: dateFilters[sf.key] ?? {},
|
|
1031
|
+
numero: numFilters[sf.key] ?? {},
|
|
1032
|
+
ordenadaPor: null,
|
|
1033
|
+
aCarregar: !allData && !!isAllDataLoading,
|
|
1034
|
+
onAplicar: (vals) => {
|
|
1035
|
+
aplicarValores(sf.key, vals);
|
|
1036
|
+
fechaFiltro();
|
|
1037
|
+
},
|
|
1038
|
+
onAplicarDatas: (de, ate) => {
|
|
1039
|
+
setDateFilter(sf.key, "from", de);
|
|
1040
|
+
setDateFilter(sf.key, "to", ate);
|
|
1041
|
+
fechaFiltro();
|
|
1042
|
+
},
|
|
1043
|
+
onAplicarNumeros: (min, max) => {
|
|
1044
|
+
setNumFilter(sf.key, min, max);
|
|
1045
|
+
fechaFiltro();
|
|
1046
|
+
},
|
|
1047
|
+
onLimpar: () => {
|
|
1048
|
+
clearColumnFilter(sf.key);
|
|
1049
|
+
fechaFiltro();
|
|
1050
|
+
},
|
|
1051
|
+
onFechar: fechaFiltro
|
|
1052
|
+
}
|
|
1053
|
+
)
|
|
1054
|
+
] }, sf.key);
|
|
1055
|
+
})
|
|
1056
|
+
] }),
|
|
1057
|
+
col.headerExtra && /* @__PURE__ */ jsx("div", { className: "mt-0.5 normal-case font-normal tracking-normal", children: col.headerExtra(filteredData) })
|
|
1058
|
+
]
|
|
1059
|
+
},
|
|
1060
|
+
col.key
|
|
1061
|
+
);
|
|
1062
|
+
})
|
|
1063
|
+
] }) });
|
|
1064
|
+
const LARGURAS_ESQUELETO = ["w-3/4", "w-1/2", "w-2/3", "w-5/6", "w-2/5"];
|
|
1065
|
+
const linhasEsqueleto = Array.from({ length: 20 }, (_, r) => /* @__PURE__ */ jsxs("tr", { "aria-hidden": true, className: "animate-pulse motion-reduce:animate-none", children: [
|
|
1066
|
+
selectable && /* @__PURE__ */ jsx("td", { style: fixa(0, "bg-white").style, className: `px-4 py-3 ${fixa(0, "bg-white").className}`, children: /* @__PURE__ */ jsx("div", { className: "w-4 h-4 border border-slate-200 bg-slate-50" }) }),
|
|
1067
|
+
columns.map((col, i) => {
|
|
1068
|
+
const f = fixa(i + (selectable ? 1 : 0), "bg-white");
|
|
1069
|
+
return /* @__PURE__ */ jsx("td", { style: f.style, className: `px-3 py-2.5 ${f.className} ${recuoFim(i)}`, children: /* @__PURE__ */ jsx("div", { className: `h-2 bg-slate-200 ${LARGURAS_ESQUELETO[(r + i) % LARGURAS_ESQUELETO.length]} ${/text-right/.test(col.cellClassName ?? "") ? "ml-auto" : /text-center/.test(col.cellClassName ?? "") ? "mx-auto" : ""}` }) }, col.key);
|
|
1070
|
+
})
|
|
1071
|
+
] }, `esqueleto-${r}`));
|
|
1072
|
+
const corpo = /* @__PURE__ */ jsx("tbody", { className: bordasSeparadas ? "[&>tr+tr]:shadow-[inset_0_1px_0_0_var(--color-slate-100)]" : "divide-y divide-slate-100", children: aCarregar ? esqueletoAoCarregar ? linhasEsqueleto : null : isGrouped ? /* @__PURE__ */ jsx(Fragment, { children: renderGroupNodes(groups, 0) }) : paginatedData.map((row) => /* @__PURE__ */ jsxs(
|
|
1073
|
+
"tr",
|
|
1074
|
+
{
|
|
1075
|
+
onClick: () => onRowClick?.(row),
|
|
1076
|
+
onDoubleClick: () => onRowDoubleClick?.(row),
|
|
1077
|
+
className: `group/linha hover:bg-slate-50 transition-colors ${onRowClick || onRowDoubleClick ? "cursor-pointer" : ""} ${selectable && selectedKeys.has(rowKey(row)) ? "bg-proef-turquoise/5" : ""} ${rowClassName?.(row) ?? ""}`,
|
|
1078
|
+
children: [
|
|
1079
|
+
selectable && /* @__PURE__ */ jsx("td", { style: fixa(0, fundoLinha(rowKey(row))).style, className: `px-4 py-3 ${fixa(0, fundoLinha(rowKey(row))).className}`, onClick: (e) => {
|
|
1080
|
+
e.stopPropagation();
|
|
1081
|
+
toggleRow(rowKey(row));
|
|
1082
|
+
}, children: /* @__PURE__ */ jsx("div", { className: `w-4 h-4 flex items-center justify-center border transition-colors ${selectedKeys.has(rowKey(row)) ? "bg-primary border-primary" : "border-slate-300 hover:border-slate-400"}`, children: selectedKeys.has(rowKey(row)) && /* @__PURE__ */ jsx(CheckIcon, { size: 9, strokeWidth: 3, className: "text-white" }) }) }),
|
|
1083
|
+
columns.map((col, i) => {
|
|
1084
|
+
const f = fixa(i + (selectable ? 1 : 0), fundoLinha(rowKey(row)));
|
|
1085
|
+
return /* @__PURE__ */ jsx("td", { style: f.style, className: `px-3 py-1.5 ${col.cellClassName ?? ""} ${f.className} ${recuoFim(i)} ${realce(col.key)} ${transicaoRealce}`, "data-col": col.key, children: col.render(row) }, col.key);
|
|
1086
|
+
})
|
|
1087
|
+
]
|
|
1088
|
+
},
|
|
1089
|
+
rowKey(row)
|
|
1090
|
+
)) });
|
|
1091
|
+
const aviso = aCarregar && esqueletoAoCarregar ? (
|
|
1092
|
+
// O esqueleto já diz que está a carregar; o texto fica para leitores de ecrã.
|
|
1093
|
+
loadingLabel ? /* @__PURE__ */ jsx("span", { role: "status", className: "sr-only", children: loadingLabel }) : null
|
|
1094
|
+
) : semLinhas ? /* @__PURE__ */ jsx("div", { className: "sticky left-0 w-full flex-1 py-10 flex flex-col items-center justify-center gap-3 text-center", children: aCarregar ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1095
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "inline-block h-7 w-7 animate-spin rounded-full border-2 border-current border-t-transparent text-proef-turquoise" }),
|
|
1096
|
+
loadingLabel && /* @__PURE__ */ jsx("span", { className: "text-xs font-bold uppercase tracking-widest text-slate-400", children: loadingLabel })
|
|
1097
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1098
|
+
/* @__PURE__ */ jsx("p", { className: "text-slate-600 font-bold text-sm", children: vazio }),
|
|
1099
|
+
emptySubLabel && /* @__PURE__ */ jsx("p", { className: "text-slate-400 text-xs -mt-1", children: emptySubLabel })
|
|
1100
|
+
] }) }) : null;
|
|
1101
|
+
const temRodape = !paginacaoNoTopo && isClientMode && !isGrouped && !!pageSize && internalTotalPages > 1;
|
|
1102
|
+
const topo = paginacaoNoTopo;
|
|
1103
|
+
const peloServidor = !!topo?.onPageChange && topo.page !== void 0 && !isClientMode;
|
|
1104
|
+
const paginaTopo = peloServidor ? topo.page : internalPage;
|
|
1105
|
+
const totalPaginasTopo = peloServidor ? Math.max(1, Math.ceil((topo.total ?? data.length) / (pageSize || data.length || 1))) : internalTotalPages;
|
|
1106
|
+
const irParaPagina = (p) => peloServidor ? topo.onPageChange(p) : setInternalPage(p);
|
|
1107
|
+
const totalTopo = topo?.total ?? (allData ?? data).length;
|
|
1108
|
+
const filtradaTopo = isClientMode && hasActiveFilters;
|
|
1109
|
+
const contagem = filtradaTopo ? filteredData.length : totalTopo;
|
|
1110
|
+
const topoACarregar = !!isLoading && data.length === 0;
|
|
1111
|
+
const numerosPagina = totalPaginasTopo <= 7 ? Array.from({ length: totalPaginasTopo }, (_, i) => i + 1) : paginaTopo <= 4 ? [1, 2, 3, 4, 5, "…", totalPaginasTopo] : paginaTopo >= totalPaginasTopo - 3 ? [1, "…", ...Array.from({ length: 5 }, (_, i) => totalPaginasTopo - 4 + i)] : [1, "…", paginaTopo - 1, paginaTopo, paginaTopo + 1, "…", totalPaginasTopo];
|
|
1112
|
+
const esqueletoTopo = /* @__PURE__ */ jsx("span", { className: "inline-block h-2 w-8 rounded-sm bg-slate-200 animate-pulse motion-reduce:animate-none", "aria-hidden": true });
|
|
1113
|
+
const nomeDoFiltro = (colKey) => columns.find((c) => c.key === colKey)?.label ?? columns.flatMap((c) => c.extraFilters ?? []).find((f) => f.key === colKey)?.label ?? colKey;
|
|
1114
|
+
const itemChip = (chave, tipo, rotulo, valor, remover) => ({ chave, tipo, rotulo, valor, remover, texto: tipo === "grupo" ? `${rotulo} ${valor}` : `${rotulo}: ${valor}` });
|
|
1115
|
+
const textoData = (r) => r.from && r.to ? `${r.from} → ${r.to}` : r.from ? `≥ ${r.from}` : `≤ ${r.to}`;
|
|
1116
|
+
const textoNum = (r) => {
|
|
1117
|
+
const temMin = r.min !== void 0 && r.min !== "";
|
|
1118
|
+
const temMax = r.max !== void 0 && r.max !== "";
|
|
1119
|
+
return temMin && temMax ? `${r.min} – ${r.max}` : temMin ? `≥ ${r.min}` : `≤ ${r.max}`;
|
|
1120
|
+
};
|
|
1121
|
+
const itensChips = [
|
|
1122
|
+
...groupByKeys.map((k) => itemChip(`g-${k}`, "grupo", L.groupedBy, columns.find((c) => c.key === k)?.label ?? k, () => removeGroup(k))),
|
|
1123
|
+
...Object.entries(columnFilters).filter(([, v]) => v && v.size > 0).map(([k, v]) => {
|
|
1124
|
+
const arr = Array.from(v);
|
|
1125
|
+
return itemChip(`v-${k}`, "filtro", nomeDoFiltro(k), arr.length > 2 ? L.selectedCount(arr.length) : arr.join(", "), () => clearColumnFilter(k));
|
|
1126
|
+
}),
|
|
1127
|
+
...Object.entries(dateFilters).filter(([, r]) => dateFilterActive(r)).map(([k, r]) => itemChip(`d-${k}`, "filtro", nomeDoFiltro(k), textoData(r), () => clearColumnFilter(k))),
|
|
1128
|
+
// Os intervalos Mín/Máx também levam chip: sem ele, um filtro de números
|
|
1129
|
+
// escondia linhas sem nada à vista que o dissesse.
|
|
1130
|
+
...Object.entries(numFilters).filter(([, r]) => numFilterActive(r)).map(([k, r]) => itemChip(`n-${k}`, "filtro", nomeDoFiltro(k), textoNum(r), () => clearColumnFilter(k)))
|
|
1131
|
+
];
|
|
1132
|
+
const chip = (it, focavel = true) => /* @__PURE__ */ jsxs("div", { className: "shrink-0 whitespace-nowrap h-7 flex items-center gap-1.5 pl-2.5 pr-1 rounded-md border border-slate-200 bg-white text-caption", children: [
|
|
1133
|
+
it.tipo === "grupo" && /* @__PURE__ */ jsx(LayersIcon, { size: 12, className: "text-slate-400" }),
|
|
1134
|
+
/* @__PURE__ */ jsx("span", { className: "text-slate-500", children: it.rotulo }),
|
|
1135
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold text-slate-800", children: it.valor }),
|
|
1136
|
+
/* @__PURE__ */ jsx(
|
|
1137
|
+
"button",
|
|
1138
|
+
{
|
|
1139
|
+
type: "button",
|
|
1140
|
+
tabIndex: focavel ? void 0 : -1,
|
|
1141
|
+
"aria-label": L.removeChip(it.texto),
|
|
1142
|
+
onClick: it.remover,
|
|
1143
|
+
className: "h-5 w-5 flex items-center justify-center rounded text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700",
|
|
1144
|
+
children: /* @__PURE__ */ jsx(CloseIcon, { size: 10 })
|
|
1145
|
+
}
|
|
1146
|
+
)
|
|
1147
|
+
] }, it.chave);
|
|
1148
|
+
const classeLimpar = "shrink-0 whitespace-nowrap text-caption font-medium text-slate-500 hover:text-red-600 transition-colors";
|
|
1149
|
+
const chipsGrupo = isGrouped ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1150
|
+
itensChips.filter((i) => i.tipo === "grupo").map((i) => chip(i)),
|
|
1151
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: clearAllGroups, className: classeLimpar, children: L.clearGroups })
|
|
1152
|
+
] }) : null;
|
|
1153
|
+
const chipsFiltro = totalActiveFilters > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1154
|
+
itensChips.filter((i) => i.tipo === "filtro").map((i) => chip(i)),
|
|
1155
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: clearAllFilters, className: classeLimpar, children: L.clearAll })
|
|
1156
|
+
] }) : null;
|
|
1157
|
+
const classeMais = "shrink-0 whitespace-nowrap h-7 px-2 rounded-md border border-slate-200 bg-slate-50 text-caption font-semibold text-slate-600 hover:bg-slate-100 transition-colors";
|
|
1158
|
+
const meioRef = useRef(null);
|
|
1159
|
+
const medidaChipsRef = useRef(null);
|
|
1160
|
+
const limparRef = useRef(null);
|
|
1161
|
+
const maisRef = useRef(null);
|
|
1162
|
+
const [chipsQueCabem, setChipsQueCabem] = useState(Number.POSITIVE_INFINITY);
|
|
1163
|
+
const [maisAberto, setMaisAberto] = useState(false);
|
|
1164
|
+
const chaveChips = itensChips.map((i) => `${i.chave}=${i.texto}`).join("|");
|
|
1165
|
+
useLayoutEffect(() => {
|
|
1166
|
+
const meio = meioRef.current;
|
|
1167
|
+
const medida = medidaChipsRef.current;
|
|
1168
|
+
if (!topo || !meio || !medida) return;
|
|
1169
|
+
const calcular = () => {
|
|
1170
|
+
const larguras2 = Array.from(medida.children, (c) => c.getBoundingClientRect().width);
|
|
1171
|
+
const mais = larguras2.pop() ?? 0;
|
|
1172
|
+
const ESPACO = 6;
|
|
1173
|
+
const limpar = limparRef.current?.getBoundingClientRect().width ?? 0;
|
|
1174
|
+
const disponivel = meio.clientWidth - (limpar ? limpar + ESPACO * 2 : 0);
|
|
1175
|
+
let usado = 0;
|
|
1176
|
+
let k = 0;
|
|
1177
|
+
for (; k < larguras2.length; k++) {
|
|
1178
|
+
const proximo = usado + (k ? ESPACO : 0) + larguras2[k];
|
|
1179
|
+
const sobram = larguras2.length - k - 1;
|
|
1180
|
+
if (proximo + (sobram > 0 ? ESPACO + mais : 0) > disponivel) break;
|
|
1181
|
+
usado = proximo;
|
|
1182
|
+
}
|
|
1183
|
+
setChipsQueCabem((prev) => prev === k ? prev : k);
|
|
1184
|
+
};
|
|
1185
|
+
calcular();
|
|
1186
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
1187
|
+
const ro = new ResizeObserver(calcular);
|
|
1188
|
+
ro.observe(meio);
|
|
1189
|
+
return () => ro.disconnect();
|
|
1190
|
+
}, [topo, chaveChips]);
|
|
1191
|
+
const chipsVisiveis = itensChips.slice(0, chipsQueCabem);
|
|
1192
|
+
const chipsEscondidos = itensChips.slice(chipsQueCabem);
|
|
1193
|
+
useEffect(() => {
|
|
1194
|
+
if (!maisAberto) return;
|
|
1195
|
+
const fora = (e) => {
|
|
1196
|
+
if (!maisRef.current?.contains(e.target)) setMaisAberto(false);
|
|
1197
|
+
};
|
|
1198
|
+
const tecla = (e) => {
|
|
1199
|
+
if (e.key === "Escape") setMaisAberto(false);
|
|
1200
|
+
};
|
|
1201
|
+
document.addEventListener("mousedown", fora);
|
|
1202
|
+
document.addEventListener("keydown", tecla);
|
|
1203
|
+
return () => {
|
|
1204
|
+
document.removeEventListener("mousedown", fora);
|
|
1205
|
+
document.removeEventListener("keydown", tecla);
|
|
1206
|
+
};
|
|
1207
|
+
}, [maisAberto]);
|
|
1208
|
+
useEffect(() => {
|
|
1209
|
+
if (!chipsEscondidos.length) setMaisAberto(false);
|
|
1210
|
+
}, [chipsEscondidos.length]);
|
|
1211
|
+
const barraTopo = topo ? /* @__PURE__ */ jsxs("div", { className: "px-4 py-2 bg-white border-b border-slate-200 flex items-center justify-between gap-3 text-caption text-slate-500 shrink-0", children: [
|
|
1212
|
+
/* @__PURE__ */ jsxs("div", { className: "shrink-0 flex items-center gap-3", children: [
|
|
1213
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
|
|
1214
|
+
topoACarregar ? esqueletoTopo : /* @__PURE__ */ jsx("span", { className: "font-semibold text-slate-800 tabular-nums", children: contagem }),
|
|
1215
|
+
filtradaTopo && !topoACarregar && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1216
|
+
L.of,
|
|
1217
|
+
" ",
|
|
1218
|
+
/* @__PURE__ */ jsx("span", { className: "tabular-nums", children: totalTopo })
|
|
1219
|
+
] }),
|
|
1220
|
+
L.rowsNoun(filtradaTopo ? totalTopo : contagem)
|
|
1221
|
+
] }),
|
|
1222
|
+
topo.pageSizeOptions && topo.onPageSizeChange && /* @__PURE__ */ jsxs("span", { className: "relative inline-flex items-center", children: [
|
|
1223
|
+
/* @__PURE__ */ jsx(
|
|
1224
|
+
"select",
|
|
1225
|
+
{
|
|
1226
|
+
value: pageSize,
|
|
1227
|
+
onChange: (e) => topo.onPageSizeChange(Number(e.target.value)),
|
|
1228
|
+
"aria-label": L.pageSize,
|
|
1229
|
+
className: "h-7 appearance-none rounded-md border border-slate-200 bg-white pl-2.5 pr-7 text-caption font-medium text-slate-600 cursor-pointer transition-colors hover:border-slate-300 focus:outline-none focus-visible:border-proef-blue focus-visible:ring-2 focus-visible:ring-proef-blue/15",
|
|
1230
|
+
children: topo.pageSizeOptions.map((n) => /* @__PURE__ */ jsx("option", { value: n, children: L.perPage(n) }, n))
|
|
1231
|
+
}
|
|
1232
|
+
),
|
|
1233
|
+
/* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: "pointer-events-none absolute right-2 text-slate-400" })
|
|
1234
|
+
] })
|
|
1235
|
+
] }),
|
|
1236
|
+
/* @__PURE__ */ jsxs("div", { ref: meioRef, className: "relative flex-1 min-w-0 flex items-center gap-1.5", children: [
|
|
1237
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 overflow-hidden pointer-events-none", "aria-hidden": true, children: /* @__PURE__ */ jsxs("div", { ref: medidaChipsRef, className: "invisible flex w-max gap-1.5", children: [
|
|
1238
|
+
itensChips.map((i) => chip(i, false)),
|
|
1239
|
+
/* @__PURE__ */ jsx("span", { className: `flex items-center ${classeMais}`, children: "+99" })
|
|
1240
|
+
] }) }),
|
|
1241
|
+
/* @__PURE__ */ jsx("div", { className: "min-w-0 flex items-center gap-1.5 overflow-hidden", children: chipsVisiveis.map((i) => chip(i)) }),
|
|
1242
|
+
chipsEscondidos.length > 0 && /* @__PURE__ */ jsxs("div", { ref: maisRef, className: "relative shrink-0", children: [
|
|
1243
|
+
/* @__PURE__ */ jsxs(
|
|
1244
|
+
"button",
|
|
1245
|
+
{
|
|
1246
|
+
type: "button",
|
|
1247
|
+
"aria-expanded": maisAberto,
|
|
1248
|
+
"aria-label": L.moreChips(chipsEscondidos.length),
|
|
1249
|
+
onClick: () => setMaisAberto((a) => !a),
|
|
1250
|
+
className: classeMais,
|
|
1251
|
+
children: [
|
|
1252
|
+
"+",
|
|
1253
|
+
chipsEscondidos.length
|
|
1254
|
+
]
|
|
1255
|
+
}
|
|
1256
|
+
),
|
|
1257
|
+
maisAberto && /* @__PURE__ */ jsx("div", { className: "absolute left-0 top-full mt-1.5 z-40 w-max max-w-[22rem] p-2 flex flex-wrap gap-1.5 bg-white border border-slate-200 shadow-popover", children: chipsEscondidos.map((i) => chip(i)) })
|
|
1258
|
+
] }),
|
|
1259
|
+
itensChips.length > 0 && /* @__PURE__ */ jsx(
|
|
1260
|
+
"button",
|
|
1261
|
+
{
|
|
1262
|
+
ref: limparRef,
|
|
1263
|
+
type: "button",
|
|
1264
|
+
onClick: () => {
|
|
1265
|
+
clearAllFilters();
|
|
1266
|
+
clearAllGroups();
|
|
1267
|
+
},
|
|
1268
|
+
className: `ml-auto ${classeLimpar}`,
|
|
1269
|
+
children: L.clearAll
|
|
1270
|
+
}
|
|
1271
|
+
)
|
|
1272
|
+
] }),
|
|
1273
|
+
/* @__PURE__ */ jsx("div", { className: "shrink-0 min-w-[220px] flex justify-end", children: topoACarregar ? /* @__PURE__ */ jsx("div", { className: "shrink-0 flex items-center gap-1", "aria-hidden": true, children: Array.from({ length: 7 }, (_, i) => /* @__PURE__ */ jsx("span", { className: "h-7 min-w-7 flex items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "h-2 w-3 rounded-sm bg-slate-200 animate-pulse motion-reduce:animate-none" }) }, i)) }) : totalPaginasTopo > 1 && !isGrouped && /* @__PURE__ */ jsxs("nav", { "aria-label": L.pagination, className: "shrink-0 flex items-center gap-1", children: [
|
|
1274
|
+
/* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
|
|
1275
|
+
L.page,
|
|
1276
|
+
" ",
|
|
1277
|
+
paginaTopo,
|
|
1278
|
+
" / ",
|
|
1279
|
+
totalPaginasTopo
|
|
1280
|
+
] }),
|
|
1281
|
+
numerosPagina.map((p, i) => p === "…" ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "h-7 min-w-5 flex items-center justify-center text-slate-300", children: "…" }, `r${i}`) : /* @__PURE__ */ jsx(
|
|
1282
|
+
"button",
|
|
1283
|
+
{
|
|
1284
|
+
type: "button",
|
|
1285
|
+
onClick: () => irParaPagina(p),
|
|
1286
|
+
"aria-current": p === paginaTopo ? "page" : void 0,
|
|
1287
|
+
className: `h-7 min-w-7 px-1.5 rounded-md text-caption font-semibold tabular-nums transition-colors ${p === paginaTopo ? "bg-primary text-white cursor-default" : "text-slate-500 hover:bg-slate-100 hover:text-slate-800"}`,
|
|
1288
|
+
children: p
|
|
1289
|
+
},
|
|
1290
|
+
p
|
|
1291
|
+
))
|
|
1292
|
+
] }) })
|
|
1293
|
+
] }) : null;
|
|
1294
|
+
return (
|
|
1295
|
+
/* A coluna só existe a preencher: as barras de chips e o rodapé são irmãos
|
|
1296
|
+
da caixa de scroll, e é a coluna que lhes dá topo e fundo fixos com o
|
|
1297
|
+
scroll pelo meio. */
|
|
1298
|
+
/* @__PURE__ */ jsxs("div", { ref: raizRef, className: `v1-reset text-control text-slate-800 ${preencheAltura ? "h-full min-h-0 flex flex-col" : ""}`, children: [
|
|
1299
|
+
barraTopo,
|
|
1300
|
+
!topo && isGrouped && /* @__PURE__ */ jsx("div", { className: "px-4 py-2 bg-slate-50 border-b border-slate-200 flex items-center gap-1.5 flex-wrap", children: chipsGrupo }),
|
|
1301
|
+
!topo && totalActiveFilters > 0 && /* @__PURE__ */ jsx("div", { className: "px-4 py-2 bg-slate-50 border-b border-slate-200 flex items-center gap-1.5 flex-wrap", children: chipsFiltro }),
|
|
1302
|
+
preencheAltura ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1303
|
+
!barraSobreposta && /* @__PURE__ */ jsx(
|
|
1304
|
+
"div",
|
|
1305
|
+
{
|
|
1306
|
+
ref: caixaCabecalhoRef,
|
|
1307
|
+
className: `overflow-x-hidden shrink-0 ${bordasSeparadas ? classeCabecalho : ""}`,
|
|
1308
|
+
style: { paddingRight: barra },
|
|
1309
|
+
children: /* @__PURE__ */ jsxs("table", { className: classeTabela, style: estiloTabela, children: [
|
|
1310
|
+
grupoColunas,
|
|
1311
|
+
cabecalho(false)
|
|
1312
|
+
] })
|
|
1313
|
+
}
|
|
1314
|
+
),
|
|
1315
|
+
/* @__PURE__ */ jsxs("div", { className: `relative flex-1 min-h-0 flex flex-col ${barraSobreposta && barraHorizontalFora ? "pb-3" : ""}`, children: [
|
|
1316
|
+
/* @__PURE__ */ jsx(
|
|
1317
|
+
"div",
|
|
1318
|
+
{
|
|
1319
|
+
ref: refCaixaCorpo,
|
|
1320
|
+
onScroll: (e) => {
|
|
1321
|
+
const cab = caixaCabecalhoRef.current;
|
|
1322
|
+
if (cab) cab.scrollLeft = e.currentTarget.scrollLeft;
|
|
1323
|
+
},
|
|
1324
|
+
className: `overflow-auto flex-1 min-h-0 ${barraSobreposta ? "scrollbar-none" : ""}`,
|
|
1325
|
+
style: esbaterDireita && restaDireita ? { maskImage: mascaraDireita, WebkitMaskImage: mascaraDireita } : void 0,
|
|
1326
|
+
children: /* @__PURE__ */ jsxs("div", { className: semLinhas ? "min-h-full flex flex-col" : void 0, children: [
|
|
1327
|
+
barraSobreposta && /* @__PURE__ */ jsx("div", { "data-barra-cabecalho": true, className: `sticky top-0 z-20 w-max min-w-full ${bordasSeparadas ? classeCabecalho : ""}`, children: /* @__PURE__ */ jsxs("table", { className: classeTabela, style: estiloTabela, children: [
|
|
1328
|
+
grupoColunas,
|
|
1329
|
+
cabecalho(false)
|
|
1330
|
+
] }) }),
|
|
1331
|
+
/* @__PURE__ */ jsxs("table", { ref: corpoRef, className: classeTabela, style: estiloTabela, children: [
|
|
1332
|
+
grupoColunas,
|
|
1333
|
+
corpo
|
|
1334
|
+
] }),
|
|
1335
|
+
aviso
|
|
1336
|
+
] })
|
|
1337
|
+
}
|
|
1338
|
+
),
|
|
1339
|
+
barraSobreposta && /* @__PURE__ */ jsx(OverlayScrollbar, { alvo: caixaCorpo, borda: 0, canto: !barraHorizontalFora }),
|
|
1340
|
+
barraSobreposta && /* @__PURE__ */ jsx(OverlayScrollbar, { alvo: caixaCorpo, eixo: "horizontal", borda: 0, canto: !barraHorizontalFora, naBorda: !barraHorizontalFora && barraNaBorda && temRodape })
|
|
1341
|
+
] }),
|
|
1342
|
+
exemplares && /* @__PURE__ */ jsx(
|
|
1343
|
+
"table",
|
|
1344
|
+
{
|
|
1345
|
+
ref: medidaRef,
|
|
1346
|
+
"aria-hidden": true,
|
|
1347
|
+
className: classeTabela,
|
|
1348
|
+
style: { position: "fixed", left: -1e5, top: 0, visibility: "hidden", width: "max-content" },
|
|
1349
|
+
children: /* @__PURE__ */ jsx("tbody", { children: Array.from({ length: exemplares.n }, (_, r) => /* @__PURE__ */ jsxs("tr", { children: [
|
|
1350
|
+
selectable && /* @__PURE__ */ jsx("td", { className: "px-4 py-3 w-10", children: /* @__PURE__ */ jsx("div", { className: "w-4 h-4" }) }),
|
|
1351
|
+
columns.map((col, i) => {
|
|
1352
|
+
const row = exemplares.porColuna[i][r];
|
|
1353
|
+
return /* @__PURE__ */ jsx("td", { className: `px-3 py-1.5 ${col.cellClassName ?? ""} ${recuoFim(i)}`, children: row !== void 0 ? col.render(row) : null }, col.key);
|
|
1354
|
+
})
|
|
1355
|
+
] }, r)) })
|
|
1356
|
+
}
|
|
1357
|
+
)
|
|
1358
|
+
] }) : /* @__PURE__ */ jsx("div", { ref: setCaixaSimples, className: "overflow-auto", style: { maxHeight }, children: /* @__PURE__ */ jsxs("div", { className: semLinhas ? "min-h-full flex flex-col" : void 0, children: [
|
|
1359
|
+
/* @__PURE__ */ jsxs("table", { className: "w-full text-left", children: [
|
|
1360
|
+
cabecalho(true),
|
|
1361
|
+
corpo
|
|
1362
|
+
] }),
|
|
1363
|
+
aviso
|
|
1364
|
+
] }) }),
|
|
1365
|
+
temRodape && /* @__PURE__ */ jsxs("div", { className: "px-4 py-3 bg-slate-50 border-t border-slate-100 flex items-center justify-between", children: [
|
|
1366
|
+
/* @__PURE__ */ jsxs("span", { className: "text-micro font-black uppercase text-slate-400 tracking-wider", children: [
|
|
1367
|
+
L.page,
|
|
1368
|
+
" ",
|
|
1369
|
+
internalPage,
|
|
1370
|
+
" / ",
|
|
1371
|
+
internalTotalPages
|
|
1372
|
+
] }),
|
|
1373
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
1374
|
+
/* @__PURE__ */ jsxs(
|
|
1375
|
+
"button",
|
|
1376
|
+
{
|
|
1377
|
+
disabled: internalPage <= 1,
|
|
1378
|
+
onClick: () => setInternalPage((p) => p - 1),
|
|
1379
|
+
className: "flex items-center gap-1 px-3 py-1.5 text-micro font-black uppercase tracking-widest bg-white border border-slate-200 disabled:opacity-30 hover:enabled:border-proef-blue hover:enabled:text-proef-blue transition-colors",
|
|
1380
|
+
children: [
|
|
1381
|
+
/* @__PURE__ */ jsx(ChevronLeftIcon, { size: 12 }),
|
|
1382
|
+
L.prev
|
|
1383
|
+
]
|
|
1384
|
+
}
|
|
1385
|
+
),
|
|
1386
|
+
/* @__PURE__ */ jsxs(
|
|
1387
|
+
"button",
|
|
1388
|
+
{
|
|
1389
|
+
disabled: internalPage >= internalTotalPages,
|
|
1390
|
+
onClick: () => setInternalPage((p) => p + 1),
|
|
1391
|
+
className: "flex items-center gap-1 px-3 py-1.5 text-micro font-black uppercase tracking-widest bg-white border border-slate-200 disabled:opacity-30 hover:enabled:border-proef-blue hover:enabled:text-proef-blue transition-colors",
|
|
1392
|
+
children: [
|
|
1393
|
+
L.next,
|
|
1394
|
+
/* @__PURE__ */ jsx(ChevronRightIcon, { size: 12 })
|
|
1395
|
+
]
|
|
1396
|
+
}
|
|
1397
|
+
)
|
|
1398
|
+
] })
|
|
1399
|
+
] })
|
|
1400
|
+
] })
|
|
1401
|
+
);
|
|
1402
|
+
}
|
|
1403
|
+
function Table(props) {
|
|
1404
|
+
return /* @__PURE__ */ jsx(TableBase, { ...props });
|
|
1405
|
+
}
|
|
1406
|
+
export {
|
|
1407
|
+
TableBase,
|
|
1408
|
+
Table as default
|
|
1409
|
+
};
|
|
1410
|
+
//# sourceMappingURL=Table.js.map
|