beez-ui 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -19
- package/README.md +49 -11
- package/dist/adapters/unpic-image.js +92 -14
- package/dist/components/alert-dialog.js +444 -26
- package/dist/components/alert.js +153 -18
- package/dist/components/animated-theme-toggler.js +215 -76
- package/dist/components/avatar.js +247 -15
- package/dist/components/badge.js +18 -16
- package/dist/components/button.js +85 -28
- package/dist/components/calendar.js +327 -68
- package/dist/components/card.js +39 -9
- package/dist/components/carousel.js +454 -84
- package/dist/components/checkbox.js +50 -3
- package/dist/components/data-table.js +827 -583
- package/dist/components/dialog.js +363 -22
- package/dist/components/dropdown-menu.js +543 -32
- package/dist/components/filter-query-bar.js +809 -468
- package/dist/components/filter-query-grammar.js +781 -736
- package/dist/components/form.js +305 -43
- package/dist/components/highlighter.js +142 -87
- package/dist/components/hover-card.js +97 -7
- package/dist/components/input-group.js +261 -41
- package/dist/components/input.js +8 -2
- package/dist/components/label.js +38 -3
- package/dist/components/link.js +45 -7
- package/dist/components/pagination.js +332 -16
- package/dist/components/popover.js +222 -16
- package/dist/components/radio-group.js +85 -5
- package/dist/components/select.js +451 -22
- package/dist/components/separator.js +43 -3
- package/dist/components/sheet.js +345 -22
- package/dist/components/sidebar.js +1385 -193
- package/dist/components/skeleton.js +6 -2
- package/dist/components/svgs/whatsappIcon.js +11 -1
- package/dist/components/switch.js +55 -3
- package/dist/components/table.js +288 -18
- package/dist/components/tabs.js +161 -18
- package/dist/components/textarea.js +7 -2
- package/dist/components/themed-toaster.js +63 -20
- package/dist/components/tooltip.js +128 -9
- package/dist/components/typing-animation.js +335 -150
- package/dist/constants/sidebar.js +1 -4
- package/dist/hooks/use-mobile.js +8 -8
- package/dist/hooks/use-sidebar-persistence.js +27 -27
- package/dist/lib/image-dimensions.js +2 -2
- package/dist/lib/year-month-filter.js +38 -40
- package/dist/next.js +69 -17
- package/dist/providers/beez-ui-provider.js +48 -7
- package/dist/providers/native-provider.js +40 -6
- package/dist/tanstack.js +35 -23
- package/package.json +7 -1
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
2
|
import * as React from "react";
|
|
4
|
-
import { flexRender, getCoreRowModel, getFilteredRowModel, getSortedRowModel, useReactTable
|
|
5
|
-
import { CircleAlert, ChevronDown, ChevronRight, Ellipsis, Eraser, X
|
|
3
|
+
import { flexRender, getCoreRowModel, getFilteredRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
|
|
4
|
+
import { CircleAlert, ChevronDown, ChevronRight, Ellipsis, Eraser, X } from "lucide-react";
|
|
6
5
|
import { Button } from "./button.js";
|
|
7
6
|
import { Badge } from "./badge.js";
|
|
8
7
|
import { FilterQueryBar } from "./filter-query-bar.js";
|
|
9
|
-
import { parseFilterQuery, serializeFilterQuery
|
|
10
|
-
import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger
|
|
8
|
+
import { parseFilterQuery, serializeFilterQuery } from "./filter-query-grammar.js";
|
|
9
|
+
import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "./dropdown-menu.js";
|
|
11
10
|
import { Input } from "./input.js";
|
|
12
|
-
import { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow
|
|
11
|
+
import { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "./table.js";
|
|
12
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
13
13
|
const DIACRITICS_PATTERN = /[\u0300-\u036f]/g;
|
|
14
14
|
const CLEAR_FILTER_ARIA_LABEL = "Limpiar filtro";
|
|
15
15
|
const ACTIVE_EXCLUSIONS_SR_LABEL = "Filtros de exclusión activos";
|
|
@@ -21,592 +21,836 @@ const CLEAR_ALL_EXCLUSIONS_ARIA_LABEL = "Quitar todas las exclusiones";
|
|
|
21
21
|
const CLEAR_ALL_EXCLUSIONS_FROM_INPUT_ARIA_LABEL = "Limpiar filtros excluidos";
|
|
22
22
|
const REVERSE_FILTER_PENDING_MESSAGE = "Estás escribiendo una exclusión. Presioná Enter para aplicarla.";
|
|
23
23
|
function normalizeFilterToken(value) {
|
|
24
|
-
|
|
25
|
-
.normalize("NFD")
|
|
26
|
-
.replace(DIACRITICS_PATTERN, "")
|
|
27
|
-
.toLocaleLowerCase()
|
|
28
|
-
.trim();
|
|
24
|
+
return value.normalize("NFD").replace(DIACRITICS_PATTERN, "").toLocaleLowerCase().trim();
|
|
29
25
|
}
|
|
30
26
|
function getTableFilterValue(filterValue, showExcludeFilterToggle) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
const normalizedFilterValue = filterValue.trimStart();
|
|
28
|
+
if (showExcludeFilterToggle && normalizedFilterValue.startsWith("-")) {
|
|
29
|
+
return "";
|
|
30
|
+
}
|
|
31
|
+
return filterValue;
|
|
36
32
|
}
|
|
37
33
|
function areColumnFiltersEqual(leftFilters, rightFilters) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
leftFilter.value === rightFilters[index]?.value);
|
|
34
|
+
if (leftFilters.length !== rightFilters.length) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
return leftFilters.every((leftFilter, index) => leftFilter.id === rightFilters[index]?.id && leftFilter.value === rightFilters[index]?.value);
|
|
43
38
|
}
|
|
44
39
|
function areStringArraysEqual(leftValues, rightValues) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
40
|
+
if (leftValues.length !== rightValues.length) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
return leftValues.every((value, index) => value === rightValues[index]);
|
|
49
44
|
}
|
|
50
45
|
function areColumnFilterValuesEqual(leftValue, rightValue) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
return false;
|
|
46
|
+
if (leftValue.kind !== rightValue.kind) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
if (leftValue.kind === "numberRange" && rightValue.kind === "numberRange") {
|
|
50
|
+
return leftValue.min === rightValue.min && leftValue.max === rightValue.max;
|
|
51
|
+
}
|
|
52
|
+
if (leftValue.kind === "yearMonthRange" && rightValue.kind === "yearMonthRange") {
|
|
53
|
+
return leftValue.mode === rightValue.mode && leftValue.min === rightValue.min && leftValue.max === rightValue.max;
|
|
54
|
+
}
|
|
55
|
+
if (leftValue.kind === "enum" && rightValue.kind === "enum") {
|
|
56
|
+
return leftValue.value === rightValue.value;
|
|
57
|
+
}
|
|
58
|
+
if (leftValue.kind === "presence" && rightValue.kind === "presence") {
|
|
59
|
+
return leftValue.value === rightValue.value;
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
69
62
|
}
|
|
70
63
|
function areAdvancedFilterMapsEqual(leftMap, rightMap) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
64
|
+
const leftKeys = Object.keys(leftMap);
|
|
65
|
+
const rightKeys = Object.keys(rightMap);
|
|
66
|
+
if (leftKeys.length !== rightKeys.length) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return leftKeys.every((key) => {
|
|
70
|
+
const rightValue = rightMap[key];
|
|
71
|
+
return rightValue != null && areColumnFilterValuesEqual(leftMap[key], rightValue);
|
|
72
|
+
});
|
|
80
73
|
}
|
|
81
|
-
export function DataTable({ columns, data, emptyMessage, toolbarActions, onVisibleRowsChange, onCellClick, getRowClassName, sorting: controlledSorting, onSortingChange, columnVisibility: controlledColumnVisibility, onColumnVisibilityChange, filterColumnId, filterLabel = "Filtrar", filterPlaceholder = "Filtrar...", filterExtraContent, filterValue: controlledFilterValue, onFilterValueChange, queryFilterConfig, queryFilterPlaceholder, queryFilterLabel, onAppliedFiltersChange, queryFilterControlsRef, queryFilterTrailingAction, rowGroups, showExcludeFilterToggle = false, excludeFilterValues: controlledExcludeFilterValues, onExcludeFilterValuesChange, excludeFilterPlaceholder = "Excluir por descripción", excludeFilterLabel = "Filtro de exclusión", excludeFilterToggleLabel = "Mostrar filtros de exclusión", excludeFilterRowsCountByValue, excludeFilterUniqueRowsCount, showColumnVisibilityToggle = false, columnVisibilityButtonLabel = "Columnas", columnVisibilityMenuLabel = "Mostrar columnas", columnVisibilityMenuExtraContent, sortingBadgeLabelOverrides, sortingBadgeIgnoredColumnIds, selectAllColumnsLabel = "Mostrar todas", deselectAllColumnsLabel = "Ocultar todas", hideableColumnsDefaultVisibility
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
74
|
+
export function DataTable({ columns, data, emptyMessage, toolbarActions, onVisibleRowsChange, onCellClick, getRowClassName, sorting: controlledSorting, onSortingChange, columnVisibility: controlledColumnVisibility, onColumnVisibilityChange, filterColumnId, filterLabel = "Filtrar", filterPlaceholder = "Filtrar...", filterExtraContent, filterValue: controlledFilterValue, onFilterValueChange, queryFilterConfig, queryFilterPlaceholder, queryFilterLabel, onAppliedFiltersChange, queryFilterControlsRef, queryFilterTrailingAction, rowGroups, showExcludeFilterToggle = false, excludeFilterValues: controlledExcludeFilterValues, onExcludeFilterValuesChange, excludeFilterPlaceholder = "Excluir por descripción", excludeFilterLabel = "Filtro de exclusión", excludeFilterToggleLabel = "Mostrar filtros de exclusión", excludeFilterRowsCountByValue, excludeFilterUniqueRowsCount, showColumnVisibilityToggle = false, columnVisibilityButtonLabel = "Columnas", columnVisibilityMenuLabel = "Mostrar columnas", columnVisibilityMenuExtraContent, sortingBadgeLabelOverrides, sortingBadgeIgnoredColumnIds, selectAllColumnsLabel = "Mostrar todas", deselectAllColumnsLabel = "Ocultar todas", hideableColumnsDefaultVisibility }) {
|
|
75
|
+
const [uncontrolledSorting, setUncontrolledSorting] = React.useState([]);
|
|
76
|
+
const [columnFilters, setColumnFilters] = React.useState([]);
|
|
77
|
+
const [uncontrolledFilterValue, setUncontrolledFilterValue] = React.useState("");
|
|
78
|
+
const [filterQueryDraft, setFilterQueryDraft] = React.useState("");
|
|
79
|
+
// Filtros estructurados de la última query parseada. Se preservan para que la
|
|
80
|
+
// re-sincronización canónica (al perder foco) NO descarte los qualifiers sin
|
|
81
|
+
// columna (textMatch/folder) ni los negados, que no viven en
|
|
82
|
+
// `advancedFiltersAppliedByColumn` y quedarían como filtros activos invisibles.
|
|
83
|
+
const [appliedFiltersDraft, setAppliedFiltersDraft] = React.useState([]);
|
|
84
|
+
const [isQueryFilterFocused, setIsQueryFilterFocused] = React.useState(false);
|
|
85
|
+
const [uncontrolledExcludeFilterValues, setUncontrolledExcludeFilterValues] = React.useState([]);
|
|
86
|
+
const [excludeFilterInputValue, setExcludeFilterInputValue] = React.useState("");
|
|
87
|
+
const [excludeFilterErrorMessage, setExcludeFilterErrorMessage] = React.useState(null);
|
|
88
|
+
const [isExcludeFilterInputVisible, setIsExcludeFilterInputVisible] = React.useState(false);
|
|
89
|
+
const [uncontrolledColumnVisibility, setUncontrolledColumnVisibility] = React.useState({});
|
|
90
|
+
const [advancedFiltersAppliedByColumn, setAdvancedFiltersAppliedByColumn] = React.useState({});
|
|
91
|
+
const sorting = controlledSorting ?? uncontrolledSorting;
|
|
92
|
+
const columnVisibility = controlledColumnVisibility ?? uncontrolledColumnVisibility;
|
|
93
|
+
const shouldShowQueryFilter = queryFilterConfig != null;
|
|
94
|
+
const isFilterValueControlled = controlledFilterValue != null;
|
|
95
|
+
const isExcludeFilterValuesControlled = controlledExcludeFilterValues != null;
|
|
96
|
+
const resolvedFilterValue = isFilterValueControlled ? controlledFilterValue : uncontrolledFilterValue;
|
|
97
|
+
const resolvedExcludeFilterValues = isExcludeFilterValuesControlled ? controlledExcludeFilterValues : uncontrolledExcludeFilterValues;
|
|
98
|
+
const hasActiveExcludeFilterValues = resolvedExcludeFilterValues.length > 0;
|
|
99
|
+
const tableFilterValue = getTableFilterValue(resolvedFilterValue, showExcludeFilterToggle);
|
|
100
|
+
const hasPendingReverseFilter = showExcludeFilterToggle && resolvedFilterValue.trimStart().startsWith("-");
|
|
101
|
+
const advancedFilterColumnIds = React.useMemo(() => {
|
|
102
|
+
const columnIds = new Set();
|
|
103
|
+
for (const queryQualifier of queryFilterConfig ?? []) {
|
|
104
|
+
if (queryQualifier.columnId) {
|
|
105
|
+
columnIds.add(queryQualifier.columnId);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return columnIds;
|
|
109
|
+
}, [queryFilterConfig]);
|
|
110
|
+
const handleExcludeFilterValuesChange = React.useCallback((nextExcludeFilterValues) => {
|
|
111
|
+
if (!isExcludeFilterValuesControlled) {
|
|
112
|
+
setUncontrolledExcludeFilterValues(nextExcludeFilterValues);
|
|
113
|
+
}
|
|
114
|
+
onExcludeFilterValuesChange?.(nextExcludeFilterValues);
|
|
115
|
+
}, [isExcludeFilterValuesControlled, onExcludeFilterValuesChange]);
|
|
116
|
+
// La barra de query es la fuente de verdad mientras se tipea: parsea el texto
|
|
117
|
+
// y escribe en los mismos canales que usan los controles clásicos (descripción,
|
|
118
|
+
// exclusiones y avanzados), de modo que ambas vistas queden sincronizadas.
|
|
119
|
+
const handleQueryFilterChange = React.useCallback((nextQuery) => {
|
|
120
|
+
// Update urgente: mantiene el input y el dropdown de sugerencias
|
|
121
|
+
// respondiendo de inmediato a cada tecla.
|
|
122
|
+
setFilterQueryDraft(nextQuery);
|
|
123
|
+
if (!queryFilterConfig) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const parsedQuery = parseFilterQuery(nextQuery, queryFilterConfig);
|
|
127
|
+
// El re-filtrado vuelve a renderizar toda la tabla (celdas con popovers,
|
|
128
|
+
// tooltips y menús por fila), lo que bloquearía el commit del dropdown si
|
|
129
|
+
// corriera urgente. Se difiere como transición de baja prioridad para que
|
|
130
|
+
// el tipeo y las sugerencias no se cuelguen.
|
|
131
|
+
React.startTransition(() => {
|
|
132
|
+
// Cada canal se actualiza solo si cambió. Propagar valores iguales
|
|
133
|
+
// (p. ej. una lista de exclusiones vacía nueva en cada tecla) dispararía
|
|
134
|
+
// re-cálculos de memos y un re-render extra de todas las filas sin
|
|
135
|
+
// ningún cambio observable.
|
|
136
|
+
if (parsedQuery.descriptionFilter !== resolvedFilterValue) {
|
|
137
|
+
if (!isFilterValueControlled) {
|
|
138
|
+
setUncontrolledFilterValue(parsedQuery.descriptionFilter);
|
|
139
|
+
}
|
|
140
|
+
onFilterValueChange?.(parsedQuery.descriptionFilter);
|
|
141
|
+
}
|
|
142
|
+
if (!areStringArraysEqual(parsedQuery.excludedDescriptionFilters, resolvedExcludeFilterValues)) {
|
|
143
|
+
handleExcludeFilterValuesChange(parsedQuery.excludedDescriptionFilters);
|
|
144
|
+
}
|
|
145
|
+
if (!areAdvancedFilterMapsEqual(parsedQuery.advancedFiltersByColumn, advancedFiltersAppliedByColumn)) {
|
|
146
|
+
setAdvancedFiltersAppliedByColumn(parsedQuery.advancedFiltersByColumn);
|
|
147
|
+
}
|
|
148
|
+
setAppliedFiltersDraft(parsedQuery.appliedFilters);
|
|
149
|
+
onAppliedFiltersChange?.(parsedQuery.appliedFilters);
|
|
150
|
+
});
|
|
151
|
+
}, [
|
|
152
|
+
advancedFiltersAppliedByColumn,
|
|
153
|
+
handleExcludeFilterValuesChange,
|
|
154
|
+
isFilterValueControlled,
|
|
155
|
+
onAppliedFiltersChange,
|
|
156
|
+
onFilterValueChange,
|
|
157
|
+
queryFilterConfig,
|
|
158
|
+
resolvedExcludeFilterValues,
|
|
159
|
+
resolvedFilterValue
|
|
160
|
+
]);
|
|
161
|
+
// Forma canónica de los filtros activos, para reflejarlos en la barra de query.
|
|
162
|
+
// Se serializa desde los filtros aplicados id-backed (no desde el texto de la
|
|
163
|
+
// barra), de modo que un filtro de carpeta apunte siempre por `folderId`: si la
|
|
164
|
+
// carpeta se renombra, su slug se re-deriva del nombre nuevo; si desaparece, el
|
|
165
|
+
// filtro se descarta. Definida antes del efecto de reparse para que este pueda
|
|
166
|
+
// re-propagar la forma id-backed cuando cambia la config.
|
|
167
|
+
const canonicalQueryFromFilters = React.useMemo(() => {
|
|
168
|
+
if (!queryFilterConfig) {
|
|
169
|
+
return "";
|
|
170
|
+
}
|
|
171
|
+
return serializeFilterQuery({
|
|
172
|
+
advancedFiltersByColumn: advancedFiltersAppliedByColumn,
|
|
173
|
+
appliedFilters: appliedFiltersDraft,
|
|
174
|
+
descriptionFilter: tableFilterValue,
|
|
175
|
+
excludedDescriptionFilters: resolvedExcludeFilterValues,
|
|
176
|
+
invalidTokens: []
|
|
177
|
+
}, queryFilterConfig);
|
|
178
|
+
}, [
|
|
179
|
+
advancedFiltersAppliedByColumn,
|
|
180
|
+
appliedFiltersDraft,
|
|
181
|
+
queryFilterConfig,
|
|
182
|
+
resolvedExcludeFilterValues,
|
|
183
|
+
tableFilterValue
|
|
184
|
+
]);
|
|
185
|
+
// Firma estructural de la config de qualifiers: dispara la reconciliación solo
|
|
186
|
+
// cuando su CONTENIDO cambia (no en cada render con una referencia de array
|
|
187
|
+
// nueva), evitando re-propagar la forma canónica mientras el usuario tipea.
|
|
188
|
+
const queryFilterConfigSignature = React.useMemo(() => queryFilterConfig ? JSON.stringify(queryFilterConfig) : "", [queryFilterConfig]);
|
|
189
|
+
const previousQueryFilterConfigSignatureRef = React.useRef(null);
|
|
190
|
+
// Si la config de qualifiers cambia (p. ej. se renombra una carpeta y su opción
|
|
191
|
+
// pasa de `carpeta:hogar` a `carpeta:casa`, o se borra y desaparece), se
|
|
192
|
+
// re-propaga la forma canónica id-backed contra la NUEVA config en vez de
|
|
193
|
+
// re-parsear el texto con el slug viejo. Así un filtro de carpeta seleccionado
|
|
194
|
+
// sobrevive a renames y colisiones de slug (se vuelve a serializar por
|
|
195
|
+
// `folderId`), mientras que un filtro realmente huérfano (cuyo `folderId` ya no
|
|
196
|
+
// existe) se descarta del predicado en vez de seguir filtrando de forma
|
|
197
|
+
// invisible.
|
|
198
|
+
React.useEffect(() => {
|
|
199
|
+
const previousSignature = previousQueryFilterConfigSignatureRef.current;
|
|
200
|
+
previousQueryFilterConfigSignatureRef.current = queryFilterConfigSignature;
|
|
201
|
+
// Primer render o config sin contenido: nada que reconciliar todavía.
|
|
202
|
+
if (previousSignature === null) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (!queryFilterConfig || !filterQueryDraft || previousSignature === queryFilterConfigSignature) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
handleQueryFilterChange(canonicalQueryFromFilters);
|
|
209
|
+
// Solo debe re-correr cuando cambia el contenido de la config; el resto de los
|
|
210
|
+
// valores se leen como estado actual y no como disparadores para no re-parsear
|
|
211
|
+
// en cada tecla.
|
|
212
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
213
|
+
}, [queryFilterConfigSignature]);
|
|
214
|
+
// Reemplaza los filtros de carpeta de la barra por un único `carpeta:<id>` (o
|
|
215
|
+
// ninguno si `folderId` es `null`), preservando el resto. Lo usa el consumidor
|
|
216
|
+
// al clickear un chip de carpeta, para que la barra sea la única fuente de
|
|
217
|
+
// verdad y no queden filtros de carpeta inconsistentes.
|
|
218
|
+
const setSingleFolderFilter = React.useCallback((folderId) => {
|
|
219
|
+
if (!queryFilterConfig) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const folderQualifierKey = queryFilterConfig.find((config) => config.kind === "folder")?.key;
|
|
223
|
+
if (!folderQualifierKey) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const parsedQuery = parseFilterQuery(filterQueryDraft, queryFilterConfig);
|
|
227
|
+
// Limpia TODO filtro que apunte a la key de carpeta —tanto `carpeta:<id>`
|
|
228
|
+
// (kind "folder") como la presencia `tiene:carpeta`/`no:carpeta`—, para que
|
|
229
|
+
// el chip sea la única fuente de verdad y no queden filtros contradictorios
|
|
230
|
+
// (p. ej. `no:carpeta` + `carpeta:hogar`, que oculta todas las filas).
|
|
231
|
+
const nonFolderFilters = parsedQuery.appliedFilters.filter((appliedFilter) => appliedFilter.value.kind !== "folder" && appliedFilter.key !== folderQualifierKey);
|
|
232
|
+
const nextAppliedFilters = folderId == null ? nonFolderFilters : [...nonFolderFilters, {
|
|
233
|
+
key: folderQualifierKey,
|
|
234
|
+
negated: false,
|
|
235
|
+
value: {
|
|
236
|
+
folderId,
|
|
237
|
+
kind: "folder"
|
|
238
|
+
}
|
|
239
|
+
}];
|
|
240
|
+
handleQueryFilterChange(serializeFilterQuery({
|
|
241
|
+
...parsedQuery,
|
|
242
|
+
appliedFilters: nextAppliedFilters
|
|
243
|
+
}, queryFilterConfig));
|
|
244
|
+
}, [
|
|
245
|
+
filterQueryDraft,
|
|
246
|
+
handleQueryFilterChange,
|
|
247
|
+
queryFilterConfig
|
|
248
|
+
]);
|
|
249
|
+
React.useEffect(() => {
|
|
250
|
+
if (!queryFilterControlsRef) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
queryFilterControlsRef.current = {
|
|
254
|
+
getQueryText: () => filterQueryDraft,
|
|
255
|
+
setQueryText: handleQueryFilterChange,
|
|
256
|
+
setSingleFolderFilter
|
|
257
|
+
};
|
|
258
|
+
return () => {
|
|
259
|
+
queryFilterControlsRef.current = null;
|
|
260
|
+
};
|
|
261
|
+
}, [
|
|
262
|
+
filterQueryDraft,
|
|
263
|
+
handleQueryFilterChange,
|
|
264
|
+
queryFilterControlsRef,
|
|
265
|
+
setSingleFolderFilter
|
|
266
|
+
]);
|
|
267
|
+
const addExcludeFilterValue = React.useCallback((rawExcludeFilterValue, options = {}) => {
|
|
268
|
+
const normalizedCandidate = normalizeFilterToken(rawExcludeFilterValue);
|
|
269
|
+
if (!normalizedCandidate) {
|
|
270
|
+
setExcludeFilterErrorMessage(EMPTY_EXCLUDE_FILTER_ERROR_MESSAGE);
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
const hasDuplicateExcludeFilter = resolvedExcludeFilterValues.some((excludeFilterValue) => normalizeFilterToken(excludeFilterValue) === normalizedCandidate);
|
|
274
|
+
if (hasDuplicateExcludeFilter) {
|
|
275
|
+
setExcludeFilterErrorMessage(DUPLICATE_EXCLUDE_FILTER_ERROR_MESSAGE);
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
handleExcludeFilterValuesChange([...resolvedExcludeFilterValues, rawExcludeFilterValue.trim()]);
|
|
279
|
+
if (options.clearExcludeInputValue ?? true) {
|
|
280
|
+
setExcludeFilterInputValue("");
|
|
281
|
+
}
|
|
282
|
+
setExcludeFilterErrorMessage(null);
|
|
283
|
+
return true;
|
|
284
|
+
}, [handleExcludeFilterValuesChange, resolvedExcludeFilterValues]);
|
|
285
|
+
const removeExcludeFilterValue = React.useCallback((excludeFilterValueToRemove) => {
|
|
286
|
+
handleExcludeFilterValuesChange(resolvedExcludeFilterValues.filter((excludeFilterValue) => excludeFilterValue !== excludeFilterValueToRemove));
|
|
287
|
+
}, [handleExcludeFilterValuesChange, resolvedExcludeFilterValues]);
|
|
288
|
+
const handleClearAllExcludeFilters = React.useCallback(() => {
|
|
289
|
+
handleExcludeFilterValuesChange([]);
|
|
290
|
+
setExcludeFilterInputValue("");
|
|
291
|
+
setExcludeFilterErrorMessage(null);
|
|
292
|
+
}, [handleExcludeFilterValuesChange]);
|
|
293
|
+
const handleSortingChange = React.useCallback((updater) => {
|
|
294
|
+
const nextSorting = typeof updater === "function" ? updater(sorting) : updater;
|
|
295
|
+
if (controlledSorting == null) {
|
|
296
|
+
setUncontrolledSorting(nextSorting);
|
|
297
|
+
}
|
|
298
|
+
onSortingChange?.(nextSorting);
|
|
299
|
+
}, [
|
|
300
|
+
controlledSorting,
|
|
301
|
+
onSortingChange,
|
|
302
|
+
sorting
|
|
303
|
+
]);
|
|
304
|
+
const handleColumnVisibilityChange = React.useCallback((updater) => {
|
|
305
|
+
if (controlledColumnVisibility == null) {
|
|
306
|
+
setUncontrolledColumnVisibility(updater);
|
|
307
|
+
}
|
|
308
|
+
onColumnVisibilityChange?.(updater);
|
|
309
|
+
}, [controlledColumnVisibility, onColumnVisibilityChange]);
|
|
310
|
+
// TanStack Table manages internal reactive state through this hook.
|
|
311
|
+
const table = useReactTable({
|
|
312
|
+
columns,
|
|
313
|
+
data,
|
|
314
|
+
// La tabla no pagina (no hay `getPaginationRowModel`). Con el auto-reset por
|
|
315
|
+
// defecto, cada cambio de filtro dispara `resetPageIndex` → `setPagination`,
|
|
316
|
+
// que vuelve a renderizar y re-dispara el reset en bucle: "Maximum update
|
|
317
|
+
// depth exceeded" y la página colgada al tipear. Se desactivan los
|
|
318
|
+
// auto-resets porque no hay estado de paginado/expansión que reiniciar.
|
|
319
|
+
autoResetPageIndex: false,
|
|
320
|
+
autoResetExpanded: false,
|
|
321
|
+
getCoreRowModel: getCoreRowModel(),
|
|
322
|
+
getFilteredRowModel: getFilteredRowModel(),
|
|
323
|
+
getSortedRowModel: getSortedRowModel(),
|
|
324
|
+
onColumnFiltersChange: setColumnFilters,
|
|
325
|
+
onSortingChange: handleSortingChange,
|
|
326
|
+
onColumnVisibilityChange: handleColumnVisibilityChange,
|
|
327
|
+
state: {
|
|
328
|
+
columnFilters,
|
|
329
|
+
columnVisibility,
|
|
330
|
+
sorting
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
const hideableColumns = table.getAllLeafColumns().filter((column) => column.getCanHide());
|
|
334
|
+
const getHideableColumnDefaultVisibility = React.useCallback((columnId) => hideableColumnsDefaultVisibility?.[columnId] ?? true, [hideableColumnsDefaultVisibility]);
|
|
335
|
+
const areHideableColumnsAtDefaultVisibility = hideableColumns.every((column) => column.getIsVisible() === getHideableColumnDefaultVisibility(column.id));
|
|
336
|
+
const areSomeHideableColumnsVisible = hideableColumns.some((column) => column.getIsVisible());
|
|
337
|
+
const shouldShowColumnVisibilityToggle = showColumnVisibilityToggle && hideableColumns.length > 0;
|
|
338
|
+
const hasModifiedColumnVisibility = shouldShowColumnVisibilityToggle && !areHideableColumnsAtDefaultVisibility;
|
|
339
|
+
const hasToolbarChanges = hasModifiedColumnVisibility;
|
|
340
|
+
const shouldShowToolbarActions = shouldShowColumnVisibilityToggle || toolbarActions != null;
|
|
341
|
+
const shouldShowToolbar = shouldShowQueryFilter || Boolean(filterColumnId) || shouldShowToolbarActions;
|
|
342
|
+
const filterColumn = filterColumnId ? table.getColumn(filterColumnId) : undefined;
|
|
343
|
+
const activeSortingEntry = sorting.find((sortingEntry) => !sortingBadgeIgnoredColumnIds?.has(sortingEntry.id));
|
|
344
|
+
const activeSortingColumn = activeSortingEntry ? table.getColumn(activeSortingEntry.id) : undefined;
|
|
345
|
+
const activeSortingColumnMeta = activeSortingColumn?.columnDef.meta;
|
|
346
|
+
const activeSortingColumnLabel = (activeSortingEntry ? sortingBadgeLabelOverrides?.[activeSortingEntry.id] : undefined) ?? activeSortingColumnMeta?.label ?? (typeof activeSortingColumn?.columnDef.header === "string" ? activeSortingColumn.columnDef.header : activeSortingEntry?.id);
|
|
347
|
+
const shouldShowSortingBadge = activeSortingEntry != null && activeSortingColumnLabel != null;
|
|
348
|
+
const activeSortingDirectionSymbol = activeSortingEntry?.desc ? "↓" : "↑";
|
|
349
|
+
const activeSortingDirectionLabel = activeSortingEntry?.desc ? "descendente" : "ascendente";
|
|
350
|
+
const footerGroups = table.getFooterGroups();
|
|
351
|
+
const hasFooterContent = footerGroups.some((footerGroup) => footerGroup.headers.some((footer) => !footer.isPlaceholder && footer.column.columnDef.footer != null));
|
|
352
|
+
const handleResetSorting = React.useCallback(() => {
|
|
353
|
+
handleSortingChange([]);
|
|
354
|
+
}, [handleSortingChange]);
|
|
355
|
+
const handleClearMainFilter = React.useCallback(() => {
|
|
356
|
+
if (!isFilterValueControlled) {
|
|
357
|
+
setUncontrolledFilterValue("");
|
|
358
|
+
}
|
|
359
|
+
onFilterValueChange?.("");
|
|
360
|
+
filterColumn?.setFilterValue("");
|
|
361
|
+
}, [
|
|
362
|
+
filterColumn,
|
|
363
|
+
isFilterValueControlled,
|
|
364
|
+
onFilterValueChange
|
|
365
|
+
]);
|
|
366
|
+
React.useEffect(() => {
|
|
367
|
+
if (!filterColumn) {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
const currentFilterValue = String(filterColumn.getFilterValue() ?? "");
|
|
371
|
+
if (currentFilterValue === tableFilterValue) {
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
filterColumn.setFilterValue(tableFilterValue);
|
|
375
|
+
}, [filterColumn, tableFilterValue]);
|
|
376
|
+
// Mientras la barra está enfocada, el usuario es la fuente de verdad y no se
|
|
377
|
+
// pisa su texto; al perder el foco (o al editar los controles clásicos) la
|
|
378
|
+
// barra se re-sincroniza con la forma canónica de los filtros activos.
|
|
379
|
+
React.useEffect(() => {
|
|
380
|
+
if (!queryFilterConfig || isQueryFilterFocused) {
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
setFilterQueryDraft((previousDraft) => previousDraft === canonicalQueryFromFilters ? previousDraft : canonicalQueryFromFilters);
|
|
384
|
+
}, [
|
|
385
|
+
canonicalQueryFromFilters,
|
|
386
|
+
isQueryFilterFocused,
|
|
387
|
+
queryFilterConfig
|
|
388
|
+
]);
|
|
389
|
+
React.useEffect(() => {
|
|
390
|
+
if (advancedFilterColumnIds.size === 0 && Object.keys(advancedFiltersAppliedByColumn).length === 0) {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
setColumnFilters((previousColumnFilters) => {
|
|
394
|
+
const nextColumnFilters = previousColumnFilters.filter((columnFilter) => !advancedFilterColumnIds.has(columnFilter.id));
|
|
395
|
+
for (const [columnId, filterValue] of Object.entries(advancedFiltersAppliedByColumn)) {
|
|
396
|
+
nextColumnFilters.push({
|
|
397
|
+
id: columnId,
|
|
398
|
+
value: filterValue
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
if (areColumnFiltersEqual(previousColumnFilters, nextColumnFilters)) {
|
|
402
|
+
return previousColumnFilters;
|
|
403
|
+
}
|
|
404
|
+
return nextColumnFilters;
|
|
405
|
+
});
|
|
406
|
+
}, [advancedFilterColumnIds, advancedFiltersAppliedByColumn]);
|
|
407
|
+
React.useEffect(() => {
|
|
408
|
+
onVisibleRowsChange?.(table.getRowModel().rows.map((row) => row.original));
|
|
409
|
+
}, [
|
|
410
|
+
columnFilters,
|
|
411
|
+
columnVisibility,
|
|
412
|
+
data,
|
|
413
|
+
onVisibleRowsChange,
|
|
414
|
+
sorting,
|
|
415
|
+
table
|
|
416
|
+
]);
|
|
417
|
+
const sortingBadgeNode = shouldShowSortingBadge ? /* @__PURE__ */ _jsxs(Badge, {
|
|
418
|
+
"aria-live": "polite",
|
|
419
|
+
className: "inline-flex w-fit items-center gap-1.5",
|
|
420
|
+
variant: "secondary",
|
|
421
|
+
children: [
|
|
422
|
+
/* @__PURE__ */ _jsx("span", { children: `Ordenado por: ${activeSortingColumnLabel} ${activeSortingDirectionSymbol}` }),
|
|
423
|
+
/* @__PURE__ */ _jsx("span", {
|
|
424
|
+
className: "sr-only",
|
|
425
|
+
children: `Orden ${activeSortingDirectionLabel}`
|
|
426
|
+
}),
|
|
427
|
+
/* @__PURE__ */ _jsx("button", {
|
|
428
|
+
"aria-label": "Quitar orden",
|
|
429
|
+
className: "inline-flex size-4 items-center justify-center rounded-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
430
|
+
onClick: handleResetSorting,
|
|
431
|
+
type: "button",
|
|
432
|
+
children: /* @__PURE__ */ _jsx(X, {
|
|
433
|
+
"aria-hidden": "true",
|
|
434
|
+
className: "size-3"
|
|
435
|
+
})
|
|
436
|
+
})
|
|
437
|
+
]
|
|
438
|
+
}) : null;
|
|
439
|
+
const filterExtraContentNode = filterExtraContent ? /* @__PURE__ */ _jsx("div", {
|
|
440
|
+
className: "grid gap-1",
|
|
441
|
+
children: filterExtraContent
|
|
442
|
+
}) : null;
|
|
443
|
+
const tableRowModelRows = table.getRowModel().rows;
|
|
444
|
+
const visibleLeafColumnsCount = table.getVisibleLeafColumns().length;
|
|
445
|
+
// El cuerpo de la tabla es la parte más cara de renderizar (cientos de celdas
|
|
446
|
+
// con popovers, tooltips y menús). Se memoiza para que los cambios de estado
|
|
447
|
+
// locales del toolbar —el draft de la barra de query, el foco, los inputs de
|
|
448
|
+
// filtros— no vuelvan a renderizar todas las filas. Solo se recalcula cuando
|
|
449
|
+
// cambia el row model (datos/filtros/orden), la visibilidad de columnas o los
|
|
450
|
+
// callbacks de fila. Sin esto, cada tecla disparaba varios re-render completos
|
|
451
|
+
// del cuerpo y colgaba la página. Se sigue el patrón de memoización de
|
|
452
|
+
// TanStack: no se depende de la identidad de `table`, que cambia en cada render.
|
|
453
|
+
const tableBodyRows = React.useMemo(() => {
|
|
454
|
+
// Con agrupado activo, el conteo por grupo se calcula sobre el row model
|
|
455
|
+
// visible (post filtros/orden) para que el encabezado refleje lo que se ve.
|
|
456
|
+
const groupRowCounts = new Map();
|
|
457
|
+
if (rowGroups) {
|
|
458
|
+
for (const row of tableRowModelRows) {
|
|
459
|
+
const groupKey = rowGroups.getGroupKey(row.original);
|
|
460
|
+
groupRowCounts.set(groupKey, (groupRowCounts.get(groupKey) ?? 0) + 1);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
// Partición por grupo: garantiza un único bloque por clave aunque el row
|
|
464
|
+
// model llegue intercalado (orden manual, sorting sin la columna fantasma,
|
|
465
|
+
// etc.). El orden interno de cada grupo respeta el row model; el orden de
|
|
466
|
+
// los grupos usa getGroupSortValue (del primer row) o la primera aparición.
|
|
467
|
+
let rowsToRender = tableRowModelRows;
|
|
468
|
+
if (rowGroups) {
|
|
469
|
+
const rowsByGroupKey = new Map();
|
|
470
|
+
for (const row of tableRowModelRows) {
|
|
471
|
+
const groupKey = rowGroups.getGroupKey(row.original);
|
|
472
|
+
const groupRows = rowsByGroupKey.get(groupKey);
|
|
473
|
+
if (groupRows) {
|
|
474
|
+
groupRows.push(row);
|
|
475
|
+
} else {
|
|
476
|
+
rowsByGroupKey.set(groupKey, [row]);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
const groupEntries = [...rowsByGroupKey.values()];
|
|
480
|
+
const getGroupSortValue = rowGroups.getGroupSortValue;
|
|
481
|
+
if (getGroupSortValue) {
|
|
482
|
+
groupEntries.sort((leftRows, rightRows) => {
|
|
483
|
+
const leftValue = getGroupSortValue(leftRows[0].original);
|
|
484
|
+
const rightValue = getGroupSortValue(rightRows[0].original);
|
|
485
|
+
if (leftValue === rightValue) {
|
|
486
|
+
return 0;
|
|
487
|
+
}
|
|
488
|
+
return leftValue < rightValue ? -1 : 1;
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
rowsToRender = groupEntries.flat();
|
|
492
|
+
}
|
|
493
|
+
const renderedRows = [];
|
|
494
|
+
let previousGroupKey = null;
|
|
495
|
+
for (const row of rowsToRender) {
|
|
496
|
+
if (rowGroups) {
|
|
497
|
+
const groupKey = rowGroups.getGroupKey(row.original);
|
|
498
|
+
const isGroupCollapsed = rowGroups.collapsedGroupKeys?.has(groupKey) ?? false;
|
|
499
|
+
if (groupKey !== previousGroupKey) {
|
|
500
|
+
const groupHeaderContent = rowGroups.renderGroupHeader(groupKey, groupRowCounts.get(groupKey) ?? 0);
|
|
501
|
+
const handleGroupToggle = rowGroups.onGroupToggle;
|
|
502
|
+
renderedRows.push(/* @__PURE__ */ _jsx(TableRow, {
|
|
503
|
+
className: "hover:bg-transparent",
|
|
504
|
+
"data-slot": "table-group-header-row",
|
|
505
|
+
children: /* @__PURE__ */ _jsx(TableCell, {
|
|
506
|
+
className: "bg-muted/40",
|
|
507
|
+
colSpan: Math.max(visibleLeafColumnsCount, 1),
|
|
508
|
+
children: handleGroupToggle ? /* @__PURE__ */ _jsxs("button", {
|
|
509
|
+
"aria-expanded": !isGroupCollapsed,
|
|
510
|
+
className: "flex w-full items-center gap-1.5 text-left",
|
|
511
|
+
onClick: () => handleGroupToggle(groupKey),
|
|
512
|
+
type: "button",
|
|
513
|
+
children: [isGroupCollapsed ? /* @__PURE__ */ _jsx(ChevronRight, {
|
|
514
|
+
"aria-hidden": "true",
|
|
515
|
+
className: "size-4 shrink-0"
|
|
516
|
+
}) : /* @__PURE__ */ _jsx(ChevronDown, {
|
|
517
|
+
"aria-hidden": "true",
|
|
518
|
+
className: "size-4 shrink-0"
|
|
519
|
+
}), groupHeaderContent]
|
|
520
|
+
}) : groupHeaderContent
|
|
521
|
+
})
|
|
522
|
+
}, `group-header-${groupKey}-${row.id}`));
|
|
523
|
+
previousGroupKey = groupKey;
|
|
524
|
+
}
|
|
525
|
+
// Grupo colapsado: solo queda el encabezado; sus filas no se renderizan.
|
|
526
|
+
if (isGroupCollapsed) {
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
const rowClassName = getRowClassName?.(row.original);
|
|
531
|
+
renderedRows.push(/* @__PURE__ */ _jsx(TableRow, {
|
|
532
|
+
className: rowClassName,
|
|
533
|
+
children: row.getVisibleCells().map((cell) => {
|
|
534
|
+
const columnMeta = cell.column.columnDef.meta;
|
|
535
|
+
const handleCellClick = onCellClick && columnMeta?.isClickable ? (event) => {
|
|
536
|
+
onCellClick(event, row.original, cell.column.id);
|
|
537
|
+
} : undefined;
|
|
538
|
+
return /* @__PURE__ */ _jsx(TableCell, {
|
|
539
|
+
className: columnMeta?.cellClassName,
|
|
540
|
+
"data-label": columnMeta?.label,
|
|
541
|
+
onClick: handleCellClick,
|
|
542
|
+
children: flexRender(cell.column.columnDef.cell, cell.getContext())
|
|
543
|
+
}, cell.id);
|
|
544
|
+
})
|
|
545
|
+
}, row.id));
|
|
546
|
+
}
|
|
547
|
+
return renderedRows;
|
|
548
|
+
// `columnVisibility` se incluye a propósito: alterna qué celdas devuelve
|
|
549
|
+
// `row.getVisibleCells()` sin cambiar la referencia de `tableRowModelRows`,
|
|
550
|
+
// por lo que es necesaria para invalidar la memo al mostrar/ocultar columnas
|
|
551
|
+
// aunque el linter no la vea referenciada léxicamente.
|
|
552
|
+
// `emptyMessage` se mantiene FUERA de esta memo a propósito: cambia al pasar
|
|
553
|
+
// de "sin filtro" a "con filtro" y, si estuviera acá, invalidaría la memo y
|
|
554
|
+
// re-renderizaría todas las filas en la primera tecla aunque no cambien.
|
|
555
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
556
|
+
}, [
|
|
557
|
+
columnVisibility,
|
|
558
|
+
getRowClassName,
|
|
559
|
+
onCellClick,
|
|
560
|
+
rowGroups,
|
|
561
|
+
tableRowModelRows,
|
|
562
|
+
visibleLeafColumnsCount
|
|
563
|
+
]);
|
|
564
|
+
const tableBodyContent = tableBodyRows.length ? tableBodyRows : /* @__PURE__ */ _jsx(TableRow, { children: /* @__PURE__ */ _jsx(TableCell, {
|
|
565
|
+
className: "h-24 text-center",
|
|
566
|
+
colSpan: Math.max(visibleLeafColumnsCount, 1),
|
|
567
|
+
children: emptyMessage
|
|
568
|
+
}) });
|
|
569
|
+
return /* @__PURE__ */ _jsxs("div", {
|
|
570
|
+
className: "grid gap-4",
|
|
571
|
+
children: [shouldShowToolbar ? /* @__PURE__ */ _jsxs("div", {
|
|
572
|
+
className: "grid gap-2",
|
|
573
|
+
children: [shouldShowQueryFilter ? /* @__PURE__ */ _jsx(FilterQueryBar, {
|
|
574
|
+
ariaLabel: queryFilterLabel,
|
|
575
|
+
configs: queryFilterConfig,
|
|
576
|
+
onFocusChange: setIsQueryFilterFocused,
|
|
577
|
+
onValueChange: handleQueryFilterChange,
|
|
578
|
+
placeholder: queryFilterPlaceholder,
|
|
579
|
+
trailingAction: queryFilterTrailingAction,
|
|
580
|
+
value: filterQueryDraft
|
|
581
|
+
}) : null, /* @__PURE__ */ _jsxs("div", {
|
|
582
|
+
className: "flex flex-wrap items-center gap-3",
|
|
583
|
+
children: [filterColumnId ? /* @__PURE__ */ _jsxs("div", {
|
|
584
|
+
className: "grid w-full max-w-sm gap-2",
|
|
585
|
+
children: [
|
|
586
|
+
!shouldShowQueryFilter ? /* @__PURE__ */ _jsxs(_Fragment, { children: [
|
|
587
|
+
/* @__PURE__ */ _jsxs("div", {
|
|
588
|
+
className: "relative w-full",
|
|
589
|
+
children: [/* @__PURE__ */ _jsx(Input, {
|
|
590
|
+
"aria-label": filterLabel,
|
|
591
|
+
className: `w-full pr-16 ${hasPendingReverseFilter ? "text-red-400" : ""}`,
|
|
592
|
+
onChange: (event) => {
|
|
593
|
+
const nextFilterValue = event.target.value;
|
|
594
|
+
if (!isFilterValueControlled) {
|
|
595
|
+
setUncontrolledFilterValue(nextFilterValue);
|
|
596
|
+
}
|
|
597
|
+
onFilterValueChange?.(nextFilterValue);
|
|
598
|
+
filterColumn?.setFilterValue(getTableFilterValue(nextFilterValue, showExcludeFilterToggle));
|
|
599
|
+
},
|
|
600
|
+
onKeyDown: (event) => {
|
|
601
|
+
if (event.key !== "Enter") {
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
const trimmedResolvedFilterValue = resolvedFilterValue.trimStart();
|
|
605
|
+
if (!showExcludeFilterToggle || !trimmedResolvedFilterValue.startsWith("-")) {
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
event.preventDefault();
|
|
609
|
+
const excludeFilterCandidate = trimmedResolvedFilterValue.slice(1);
|
|
610
|
+
const wasExcludeFilterAdded = addExcludeFilterValue(excludeFilterCandidate, { clearExcludeInputValue: false });
|
|
611
|
+
if (wasExcludeFilterAdded) {
|
|
612
|
+
handleClearMainFilter();
|
|
613
|
+
}
|
|
614
|
+
},
|
|
615
|
+
placeholder: filterPlaceholder,
|
|
616
|
+
type: "text",
|
|
617
|
+
value: resolvedFilterValue
|
|
618
|
+
}), /* @__PURE__ */ _jsxs("div", {
|
|
619
|
+
className: "absolute right-1 top-1/2 flex -translate-y-1/2 items-center gap-0.5",
|
|
620
|
+
children: [resolvedFilterValue ? /* @__PURE__ */ _jsx(Button, {
|
|
621
|
+
"aria-label": CLEAR_FILTER_ARIA_LABEL,
|
|
622
|
+
className: "active:-translate-y-0",
|
|
623
|
+
onClick: handleClearMainFilter,
|
|
624
|
+
size: "icon-xs",
|
|
625
|
+
type: "button",
|
|
626
|
+
variant: "ghost",
|
|
627
|
+
children: /* @__PURE__ */ _jsx(X, { "aria-hidden": "true" })
|
|
628
|
+
}) : null, showExcludeFilterToggle ? /* @__PURE__ */ _jsxs(Button, {
|
|
629
|
+
"aria-expanded": isExcludeFilterInputVisible,
|
|
630
|
+
"aria-label": isExcludeFilterInputVisible ? HIDE_EXCLUDE_FILTERS_ARIA_LABEL : excludeFilterToggleLabel,
|
|
631
|
+
className: "relative",
|
|
632
|
+
onClick: () => {
|
|
633
|
+
setIsExcludeFilterInputVisible((previousState) => {
|
|
634
|
+
const nextState = !previousState;
|
|
635
|
+
if (!nextState) {
|
|
636
|
+
setExcludeFilterInputValue("");
|
|
637
|
+
setExcludeFilterErrorMessage(null);
|
|
638
|
+
}
|
|
639
|
+
return nextState;
|
|
640
|
+
});
|
|
641
|
+
},
|
|
642
|
+
size: "icon-xs",
|
|
643
|
+
type: "button",
|
|
644
|
+
variant: "ghost",
|
|
645
|
+
children: [/* @__PURE__ */ _jsx(Ellipsis, { "aria-hidden": "true" }), hasActiveExcludeFilterValues ? /* @__PURE__ */ _jsxs(_Fragment, { children: [/* @__PURE__ */ _jsx("span", {
|
|
646
|
+
"aria-hidden": "true",
|
|
647
|
+
className: "absolute -right-0.5 -top-0.5 size-2 rounded-full bg-destructive ring-2 ring-background"
|
|
648
|
+
}), /* @__PURE__ */ _jsx("span", {
|
|
649
|
+
className: "sr-only",
|
|
650
|
+
children: ACTIVE_EXCLUSIONS_SR_LABEL
|
|
651
|
+
})] }) : null]
|
|
652
|
+
}) : null]
|
|
653
|
+
})]
|
|
654
|
+
}),
|
|
655
|
+
showExcludeFilterToggle && isExcludeFilterInputVisible ? /* @__PURE__ */ _jsxs("div", {
|
|
656
|
+
className: "grid gap-1",
|
|
657
|
+
children: [/* @__PURE__ */ _jsxs("div", {
|
|
658
|
+
className: "flex items-center gap-1",
|
|
659
|
+
children: [/* @__PURE__ */ _jsx(Input, {
|
|
660
|
+
"aria-invalid": excludeFilterErrorMessage != null,
|
|
661
|
+
"aria-label": excludeFilterLabel,
|
|
662
|
+
onChange: (event) => {
|
|
663
|
+
setExcludeFilterInputValue(event.target.value);
|
|
664
|
+
if (excludeFilterErrorMessage != null) {
|
|
665
|
+
setExcludeFilterErrorMessage(null);
|
|
666
|
+
}
|
|
667
|
+
},
|
|
668
|
+
onKeyDown: (event) => {
|
|
669
|
+
if (event.key !== "Enter") {
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
event.preventDefault();
|
|
673
|
+
addExcludeFilterValue(excludeFilterInputValue);
|
|
674
|
+
},
|
|
675
|
+
placeholder: excludeFilterPlaceholder,
|
|
676
|
+
type: "text",
|
|
677
|
+
value: excludeFilterInputValue
|
|
678
|
+
}), /* @__PURE__ */ _jsx(Button, {
|
|
679
|
+
"aria-label": CLEAR_ALL_EXCLUSIONS_FROM_INPUT_ARIA_LABEL,
|
|
680
|
+
className: "shrink-0",
|
|
681
|
+
disabled: !hasActiveExcludeFilterValues,
|
|
682
|
+
onClick: handleClearAllExcludeFilters,
|
|
683
|
+
size: "icon-xs",
|
|
684
|
+
type: "button",
|
|
685
|
+
variant: "ghost",
|
|
686
|
+
children: /* @__PURE__ */ _jsx(Eraser, { "aria-hidden": "true" })
|
|
687
|
+
})]
|
|
688
|
+
}), excludeFilterErrorMessage ? /* @__PURE__ */ _jsx("p", {
|
|
689
|
+
"aria-live": "polite",
|
|
690
|
+
className: "text-sm text-destructive",
|
|
691
|
+
children: excludeFilterErrorMessage
|
|
692
|
+
}) : null]
|
|
693
|
+
}) : null,
|
|
694
|
+
hasPendingReverseFilter ? /* @__PURE__ */ _jsxs("div", {
|
|
695
|
+
"aria-live": "polite",
|
|
696
|
+
className: "rounded-md border border-border/80 bg-muted/40 px-3 py-2 text-muted-foreground",
|
|
697
|
+
role: "status",
|
|
698
|
+
children: [/* @__PURE__ */ _jsxs("div", {
|
|
699
|
+
className: "flex items-center gap-2 text-sm font-medium text-foreground/80",
|
|
700
|
+
children: [/* @__PURE__ */ _jsx(CircleAlert, {
|
|
701
|
+
"aria-hidden": "true",
|
|
702
|
+
className: "size-4"
|
|
703
|
+
}), /* @__PURE__ */ _jsx("span", { children: "Exclusión pendiente" })]
|
|
704
|
+
}), /* @__PURE__ */ _jsx("p", {
|
|
705
|
+
className: "mt-1 text-xs",
|
|
706
|
+
children: REVERSE_FILTER_PENDING_MESSAGE
|
|
707
|
+
})]
|
|
708
|
+
}) : null
|
|
709
|
+
] }) : null,
|
|
710
|
+
showExcludeFilterToggle && resolvedExcludeFilterValues.length > 0 ? /* @__PURE__ */ _jsxs("div", {
|
|
711
|
+
className: "flex flex-wrap items-center gap-2",
|
|
712
|
+
children: [excludeFilterUniqueRowsCount != null ? /* @__PURE__ */ _jsxs(Badge, {
|
|
713
|
+
"aria-label": `Total de filas excluidas únicas: ${excludeFilterUniqueRowsCount}`,
|
|
714
|
+
className: "inline-flex h-6 items-center gap-1.5 px-2.5",
|
|
715
|
+
variant: "destructive",
|
|
716
|
+
children: [
|
|
717
|
+
/* @__PURE__ */ _jsx("span", { children: `${EXCLUDED_ROWS_SUMMARY_LABEL}:` }),
|
|
718
|
+
/* @__PURE__ */ _jsx("span", {
|
|
719
|
+
className: "inline-flex min-w-5 items-center justify-center rounded-full bg-destructive/20 px-1.5 text-[10px] leading-4 font-semibold",
|
|
720
|
+
children: excludeFilterUniqueRowsCount
|
|
721
|
+
}),
|
|
722
|
+
/* @__PURE__ */ _jsx("button", {
|
|
723
|
+
"aria-label": CLEAR_ALL_EXCLUSIONS_ARIA_LABEL,
|
|
724
|
+
className: "inline-flex size-4 items-center justify-center rounded-sm text-destructive transition-colors hover:bg-destructive/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-destructive/40",
|
|
725
|
+
onClick: handleClearAllExcludeFilters,
|
|
726
|
+
type: "button",
|
|
727
|
+
children: /* @__PURE__ */ _jsx(X, {
|
|
728
|
+
"aria-hidden": "true",
|
|
729
|
+
className: "size-3"
|
|
730
|
+
})
|
|
731
|
+
})
|
|
732
|
+
]
|
|
733
|
+
}) : null, resolvedExcludeFilterValues.map((excludeFilterValue) => {
|
|
734
|
+
const excludedRowsCount = excludeFilterRowsCountByValue?.[excludeFilterValue];
|
|
735
|
+
return /* @__PURE__ */ _jsxs(Badge, {
|
|
736
|
+
className: "inline-flex h-6 items-center gap-1.5 px-2.5",
|
|
737
|
+
variant: "destructive",
|
|
738
|
+
children: [
|
|
739
|
+
/* @__PURE__ */ _jsx("span", { children: `− ${excludeFilterValue}` }),
|
|
740
|
+
excludedRowsCount != null ? /* @__PURE__ */ _jsx("span", {
|
|
741
|
+
"aria-label": `Filas excluidas por ${excludeFilterValue}: ${excludedRowsCount}`,
|
|
742
|
+
className: "inline-flex min-w-5 items-center justify-center rounded-full bg-destructive/20 px-1.5 text-[10px] leading-4 font-semibold",
|
|
743
|
+
children: excludedRowsCount
|
|
744
|
+
}) : null,
|
|
745
|
+
/* @__PURE__ */ _jsx("button", {
|
|
746
|
+
"aria-label": `Quitar exclusión ${excludeFilterValue}`,
|
|
747
|
+
className: "inline-flex size-4 items-center justify-center rounded-sm text-destructive transition-colors hover:bg-destructive/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-destructive/40",
|
|
748
|
+
onClick: () => removeExcludeFilterValue(excludeFilterValue),
|
|
749
|
+
type: "button",
|
|
750
|
+
children: /* @__PURE__ */ _jsx(X, {
|
|
751
|
+
"aria-hidden": "true",
|
|
752
|
+
className: "size-3"
|
|
753
|
+
})
|
|
754
|
+
})
|
|
755
|
+
]
|
|
756
|
+
}, excludeFilterValue);
|
|
757
|
+
})]
|
|
758
|
+
}) : null,
|
|
759
|
+
sortingBadgeNode,
|
|
760
|
+
filterExtraContentNode
|
|
761
|
+
]
|
|
762
|
+
}) : null, shouldShowToolbarActions ? /* @__PURE__ */ _jsxs("div", {
|
|
763
|
+
className: "ml-auto flex flex-wrap items-center gap-2",
|
|
764
|
+
children: [toolbarActions, shouldShowColumnVisibilityToggle ? /* @__PURE__ */ _jsxs(DropdownMenu, { children: [/* @__PURE__ */ _jsx(DropdownMenuTrigger, {
|
|
765
|
+
asChild: true,
|
|
766
|
+
children: /* @__PURE__ */ _jsxs(Button, {
|
|
767
|
+
"aria-label": columnVisibilityButtonLabel,
|
|
768
|
+
className: "relative",
|
|
769
|
+
type: "button",
|
|
770
|
+
variant: "outline",
|
|
771
|
+
children: [
|
|
772
|
+
columnVisibilityButtonLabel,
|
|
773
|
+
/* @__PURE__ */ _jsx(ChevronDown, { "aria-hidden": "true" }),
|
|
774
|
+
hasToolbarChanges ? /* @__PURE__ */ _jsxs(_Fragment, { children: [/* @__PURE__ */ _jsx("span", {
|
|
775
|
+
"aria-hidden": "true",
|
|
776
|
+
className: "absolute -right-0.5 -top-0.5 size-2 rounded-full bg-destructive ring-2 ring-background"
|
|
777
|
+
}), /* @__PURE__ */ _jsx("span", {
|
|
778
|
+
className: "sr-only",
|
|
779
|
+
children: "Columnas modificadas"
|
|
780
|
+
})] }) : null
|
|
781
|
+
]
|
|
782
|
+
})
|
|
783
|
+
}), /* @__PURE__ */ _jsxs(DropdownMenuContent, {
|
|
784
|
+
align: "end",
|
|
785
|
+
children: [
|
|
786
|
+
columnVisibilityMenuExtraContent ? /* @__PURE__ */ _jsxs(_Fragment, { children: [columnVisibilityMenuExtraContent, /* @__PURE__ */ _jsx(DropdownMenuSeparator, {})] }) : null,
|
|
787
|
+
/* @__PURE__ */ _jsx(DropdownMenuLabel, { children: columnVisibilityMenuLabel }),
|
|
788
|
+
/* @__PURE__ */ _jsx(DropdownMenuItem, {
|
|
789
|
+
disabled: areHideableColumnsAtDefaultVisibility,
|
|
790
|
+
onSelect: (event) => {
|
|
791
|
+
event.preventDefault();
|
|
792
|
+
hideableColumns.forEach((column) => {
|
|
793
|
+
column.toggleVisibility(getHideableColumnDefaultVisibility(column.id));
|
|
794
|
+
});
|
|
795
|
+
},
|
|
796
|
+
children: selectAllColumnsLabel
|
|
797
|
+
}),
|
|
798
|
+
/* @__PURE__ */ _jsx(DropdownMenuItem, {
|
|
799
|
+
disabled: !areSomeHideableColumnsVisible,
|
|
800
|
+
onSelect: (event) => {
|
|
801
|
+
event.preventDefault();
|
|
802
|
+
hideableColumns.forEach((column) => {
|
|
803
|
+
column.toggleVisibility(false);
|
|
804
|
+
});
|
|
805
|
+
},
|
|
806
|
+
children: deselectAllColumnsLabel
|
|
807
|
+
}),
|
|
808
|
+
/* @__PURE__ */ _jsx(DropdownMenuSeparator, {}),
|
|
809
|
+
hideableColumns.map((column) => {
|
|
810
|
+
const columnMeta = column.columnDef.meta;
|
|
811
|
+
const isColumnVisible = column.getIsVisible();
|
|
812
|
+
const label = columnMeta?.label ?? (typeof column.columnDef.header === "string" ? column.columnDef.header : column.id);
|
|
813
|
+
return /* @__PURE__ */ _jsxs(DropdownMenuCheckboxItem, {
|
|
814
|
+
checked: isColumnVisible,
|
|
815
|
+
onSelect: (event) => {
|
|
816
|
+
event.preventDefault();
|
|
817
|
+
},
|
|
818
|
+
onCheckedChange: (nextVisible) => {
|
|
819
|
+
column.toggleVisibility(Boolean(nextVisible));
|
|
820
|
+
},
|
|
821
|
+
children: [label, !isColumnVisible ? /* @__PURE__ */ _jsxs(_Fragment, { children: [/* @__PURE__ */ _jsx("span", {
|
|
822
|
+
"aria-hidden": "true",
|
|
823
|
+
className: "absolute right-2 top-1.5 size-2 rounded-full bg-destructive ring-2 ring-background"
|
|
824
|
+
}), /* @__PURE__ */ _jsx("span", {
|
|
825
|
+
className: "sr-only",
|
|
826
|
+
children: "Columna deseleccionada"
|
|
827
|
+
})] }) : null]
|
|
828
|
+
}, column.id);
|
|
829
|
+
})
|
|
830
|
+
]
|
|
831
|
+
})] }) : null]
|
|
832
|
+
}) : null]
|
|
833
|
+
})]
|
|
834
|
+
}) : null, /* @__PURE__ */ _jsx("div", {
|
|
835
|
+
className: "relative w-full overflow-x-auto",
|
|
836
|
+
children: /* @__PURE__ */ _jsxs(Table, { children: [
|
|
837
|
+
/* @__PURE__ */ _jsx(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ _jsx(TableRow, { children: headerGroup.headers.map((header) => {
|
|
838
|
+
const columnMeta = header.column.columnDef.meta;
|
|
839
|
+
return /* @__PURE__ */ _jsx(TableHead, {
|
|
840
|
+
className: columnMeta?.headerClassName,
|
|
841
|
+
onClick: columnMeta?.onHeaderClick,
|
|
842
|
+
children: header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())
|
|
843
|
+
}, header.id);
|
|
844
|
+
}) }, headerGroup.id)) }),
|
|
845
|
+
/* @__PURE__ */ _jsx(TableBody, { children: tableBodyContent }),
|
|
846
|
+
hasFooterContent ? /* @__PURE__ */ _jsx(TableFooter, { children: footerGroups.map((footerGroup) => /* @__PURE__ */ _jsx(TableRow, {
|
|
847
|
+
className: "hover:bg-transparent",
|
|
848
|
+
children: footerGroup.headers.map((footer) => /* @__PURE__ */ _jsx(TableCell, {
|
|
849
|
+
"data-label": footer.column.columnDef.meta?.label,
|
|
850
|
+
children: footer.isPlaceholder ? null : flexRender(footer.column.columnDef.footer, footer.getContext())
|
|
851
|
+
}, footer.id))
|
|
852
|
+
}, footerGroup.id)) }) : null
|
|
853
|
+
] })
|
|
854
|
+
})]
|
|
855
|
+
});
|
|
612
856
|
}
|