orbital-ds 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/AGENTS.md +18 -1
  2. package/components.manifest.json +388 -1
  3. package/contract.json +5 -0
  4. package/dist/hooks/use-ds-messages.d.ts +59 -1
  5. package/dist/hooks/use-ds-messages.js +6 -0
  6. package/dist/lib/echarts-presets.d.ts +153 -0
  7. package/dist/lib/echarts-presets.js +311 -0
  8. package/dist/lib/echarts-server.d.ts +15 -0
  9. package/dist/lib/echarts-server.js +15 -0
  10. package/dist/lib/echarts-setup.d.ts +4 -0
  11. package/dist/lib/echarts-setup.js +60 -0
  12. package/dist/lib/echarts-theme.d.ts +36 -0
  13. package/dist/lib/echarts-theme.js +142 -0
  14. package/dist/lib/i18n.d.ts +57 -1
  15. package/dist/lib/i18n.js +169 -3
  16. package/dist/styles.css +43 -5
  17. package/dist/themes/friendly.css +3 -1
  18. package/dist/themes/friendly.scoped.css +3 -1
  19. package/dist/themes/friendly.tokens.json +45 -0
  20. package/dist/themes/qratia.tokens.json +49 -0
  21. package/dist/themes/tactile.css +3 -1
  22. package/dist/themes/tactile.scoped.css +3 -1
  23. package/dist/themes/tactile.tokens.json +42 -0
  24. package/dist/themes/twitter.css +3 -1
  25. package/dist/themes/twitter.scoped.css +3 -1
  26. package/dist/themes/twitter.tokens.json +45 -0
  27. package/dist/themes/zyro.css +3 -1
  28. package/dist/themes/zyro.scoped.css +3 -1
  29. package/dist/themes/zyro.tokens.json +46 -0
  30. package/dist/ui/calendar.js +4 -0
  31. package/dist/ui/code-block.d.ts +14 -0
  32. package/dist/ui/code-block.js +106 -0
  33. package/dist/ui/data-table.d.ts +185 -0
  34. package/dist/ui/data-table.js +714 -0
  35. package/dist/ui/date-picker.d.ts +65 -0
  36. package/dist/ui/date-picker.js +362 -0
  37. package/dist/ui/dropzone.d.ts +42 -0
  38. package/dist/ui/dropzone.js +220 -0
  39. package/dist/ui/echart.d.ts +31 -0
  40. package/dist/ui/echart.js +88 -0
  41. package/dist/ui/eyebrow.d.ts +7 -0
  42. package/dist/ui/eyebrow.js +16 -0
  43. package/dist/ui/filter-bar.d.ts +36 -0
  44. package/dist/ui/filter-bar.js +193 -0
  45. package/dist/ui/heatmap-grid.d.ts +39 -0
  46. package/dist/ui/heatmap-grid.js +195 -0
  47. package/dist/ui/i18n-provider.js +3 -3
  48. package/dist/ui/legend.d.ts +30 -0
  49. package/dist/ui/legend.js +124 -0
  50. package/dist/ui/notifications.d.ts +69 -0
  51. package/dist/ui/notifications.js +335 -0
  52. package/dist/ui/page-header.d.ts +19 -0
  53. package/dist/ui/page-header.js +132 -0
  54. package/dist/ui/panel.d.ts +12 -0
  55. package/dist/ui/panel.js +41 -0
  56. package/dist/ui/proportion-bar.d.ts +27 -0
  57. package/dist/ui/proportion-bar.js +92 -0
  58. package/dist/ui/sparkline.d.ts +26 -0
  59. package/dist/ui/sparkline.js +97 -0
  60. package/dist/ui/stat.d.ts +61 -0
  61. package/dist/ui/stat.js +238 -0
  62. package/dist/ui/status-badge.d.ts +38 -0
  63. package/dist/ui/status-badge.js +153 -0
  64. package/dist/ui/stepper.d.ts +20 -0
  65. package/dist/ui/stepper.js +152 -0
  66. package/dist/ui/timeline.d.ts +29 -0
  67. package/dist/ui/timeline.js +157 -0
  68. package/docs/GRAFICOS.md +125 -0
  69. package/docs/adr/0001-rtl-clases-logicas.md +78 -0
  70. package/package.json +171 -160
  71. package/scripts/doctor.mjs +0 -0
  72. package/scripts/i18n.mjs +0 -0
  73. package/scripts/init.mjs +1 -0
@@ -0,0 +1,714 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import {
4
+ columnFilteringFeature,
5
+ columnVisibilityFeature,
6
+ constructSortFn,
7
+ createColumnHelper,
8
+ createFilteredRowModel,
9
+ createSortedRowModel,
10
+ filterFn_equalsString,
11
+ filterFn_includesString,
12
+ functionalUpdate,
13
+ globalFilteringFeature,
14
+ rowSelectionFeature,
15
+ rowSortingFeature,
16
+ sortFn_alphanumeric,
17
+ sortFn_basic,
18
+ sortFn_datetime,
19
+ sortFn_text,
20
+ tableFeatures,
21
+ useTable
22
+ } from "@tanstack/react-table";
23
+ import {
24
+ ArrowDownIcon,
25
+ ArrowUpIcon,
26
+ ChevronLeftIcon,
27
+ ChevronRightIcon,
28
+ ChevronsUpDownIcon,
29
+ Columns3Icon,
30
+ SearchIcon
31
+ } from "lucide-react";
32
+ import * as React from "react";
33
+ import { useDsLocale, useDsMessages } from "../hooks/use-ds-messages";
34
+ import { dsFormat } from "../lib/i18n";
35
+ import { cn } from "../lib/utils";
36
+ import { Button } from "./button";
37
+ import { Checkbox } from "./checkbox";
38
+ import {
39
+ DropdownMenu,
40
+ DropdownMenuCheckboxItem,
41
+ DropdownMenuContent,
42
+ DropdownMenuGroup,
43
+ DropdownMenuLabel,
44
+ DropdownMenuTrigger
45
+ } from "./dropdown-menu";
46
+ import { Empty, EmptyHeader, EmptyTitle } from "./empty";
47
+ import { Input } from "./input";
48
+ import { NativeSelect, NativeSelectOption } from "./native-select";
49
+ import { ProportionBar } from "./proportion-bar";
50
+ import { Skeleton } from "./skeleton";
51
+ import {
52
+ Table,
53
+ TableBody,
54
+ TableCell,
55
+ TableHead,
56
+ TableHeader,
57
+ TableRow
58
+ } from "./table";
59
+ const sortFn_number = constructSortFn({
60
+ sort: (a, b) => {
61
+ const x = Number(a);
62
+ const y = Number(b);
63
+ return x === y ? 0 : x > y ? 1 : -1;
64
+ }
65
+ });
66
+ const dataTableFeatures = tableFeatures({
67
+ rowSortingFeature,
68
+ columnFilteringFeature,
69
+ globalFilteringFeature,
70
+ columnVisibilityFeature,
71
+ rowSelectionFeature,
72
+ sortedRowModel: createSortedRowModel(),
73
+ filteredRowModel: createFilteredRowModel(),
74
+ filterFns: {
75
+ includesString: filterFn_includesString,
76
+ equalsString: filterFn_equalsString
77
+ },
78
+ sortFns: {
79
+ alphanumeric: sortFn_alphanumeric,
80
+ text: sortFn_text,
81
+ basic: sortFn_basic,
82
+ datetime: sortFn_datetime,
83
+ number: sortFn_number
84
+ },
85
+ columnMeta: {}
86
+ });
87
+ function createDataTableColumnHelper() {
88
+ return createColumnHelper();
89
+ }
90
+ const DATA_TABLE_PAGE_SIZES = [10, 20, 50, 100];
91
+ const DEFAULT_STATE = {
92
+ search: "",
93
+ sorting: [],
94
+ page: 1,
95
+ pageSize: DATA_TABLE_PAGE_SIZES[0],
96
+ columnFilters: [],
97
+ columnVisibility: {},
98
+ rowSelection: {}
99
+ };
100
+ const ID_RE = /^[\w.-]+$/;
101
+ function validateDataTableSearch(search, options = {}) {
102
+ const sizes = options.pageSizes ?? DATA_TABLE_PAGE_SIZES;
103
+ const text = (v) => typeof v === "string" || typeof v === "number" ? String(v) : "";
104
+ const out = {};
105
+ const q = text(search.q);
106
+ if (q.trim()) out.q = q;
107
+ const sort = text(search.sort);
108
+ if (sort && sort.split(",").every((s) => ID_RE.test(s.replace(/^-/, ""))))
109
+ out.sort = sort;
110
+ const page = Number(search.page);
111
+ if (Number.isInteger(page) && page > 1) out.page = page;
112
+ const size = Number(search.size);
113
+ if (sizes.includes(size) && size !== sizes[0]) out.size = size;
114
+ const hide = text(search.hide);
115
+ if (hide && hide.split(",").every((s) => ID_RE.test(s))) out.hide = hide;
116
+ for (const [key, value] of Object.entries(search)) {
117
+ if (!key.startsWith("f.") || !ID_RE.test(key.slice(2))) continue;
118
+ const v = text(value);
119
+ if (v) out[key] = v;
120
+ }
121
+ return out;
122
+ }
123
+ function dataTableStateFromSearch(search, options = {}) {
124
+ const s = validateDataTableSearch(search, options);
125
+ const sizes = options.pageSizes ?? DATA_TABLE_PAGE_SIZES;
126
+ const columnFilters = [];
127
+ for (const [key, value] of Object.entries(s)) {
128
+ if (key.startsWith("f.") && typeof value === "string")
129
+ columnFilters.push({ id: key.slice(2), value });
130
+ }
131
+ return {
132
+ search: s.q ?? "",
133
+ sorting: s.sort ? s.sort.split(",").map((part) => ({
134
+ id: part.replace(/^-/, ""),
135
+ desc: part.startsWith("-")
136
+ })) : [],
137
+ page: s.page ?? 1,
138
+ pageSize: s.size ?? sizes[0] ?? DEFAULT_STATE.pageSize,
139
+ columnFilters,
140
+ columnVisibility: Object.fromEntries(
141
+ (s.hide ? s.hide.split(",") : []).map((id) => [id, false])
142
+ )
143
+ };
144
+ }
145
+ function dataTableStateToSearch(state, options = {}) {
146
+ const sizes = options.pageSizes ?? DATA_TABLE_PAGE_SIZES;
147
+ const raw = {
148
+ q: state.search,
149
+ sort: state.sorting?.map((s) => `${s.desc ? "-" : ""}${s.id}`).join(","),
150
+ page: state.page,
151
+ size: state.pageSize === sizes[0] ? void 0 : state.pageSize,
152
+ hide: Object.entries(state.columnVisibility ?? {}).filter(([, visible]) => !visible).map(([id]) => id).join(",")
153
+ };
154
+ for (const f of state.columnFilters ?? []) {
155
+ if (f.value !== void 0 && f.value !== null && f.value !== "")
156
+ raw[`f.${f.id}`] = String(f.value);
157
+ }
158
+ return validateDataTableSearch(raw, options);
159
+ }
160
+ function NoData() {
161
+ const t = useDsMessages();
162
+ return /* @__PURE__ */ jsxs("span", { "data-slot": "data-table-no-data", className: "text-muted-foreground", children: [
163
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2014" }),
164
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: t.statNoData })
165
+ ] });
166
+ }
167
+ function DataTableNumber({
168
+ value,
169
+ format,
170
+ className
171
+ }) {
172
+ const locale = useDsLocale();
173
+ const formatter = React.useMemo(
174
+ () => new Intl.NumberFormat(locale, format),
175
+ [locale, format]
176
+ );
177
+ if (value === null || value === void 0 || Number.isNaN(value))
178
+ return /* @__PURE__ */ jsx(NoData, {});
179
+ return /* @__PURE__ */ jsx("span", { "data-slot": "data-table-number", className: cn("tabular-nums", className), children: formatter.format(value) });
180
+ }
181
+ function DataTableBarCell({
182
+ value,
183
+ max,
184
+ format,
185
+ tone = "primary",
186
+ className
187
+ }) {
188
+ const missing = value === null || value === void 0 || Number.isNaN(value);
189
+ return /* @__PURE__ */ jsxs(
190
+ "div",
191
+ {
192
+ "data-slot": "data-table-bar-cell",
193
+ className: cn("flex items-center justify-end gap-2", className),
194
+ children: [
195
+ /* @__PURE__ */ jsx(
196
+ ProportionBar,
197
+ {
198
+ "aria-hidden": "true",
199
+ value: missing ? null : value,
200
+ unknown: missing,
201
+ max,
202
+ tone,
203
+ className: "w-full min-w-12 max-w-32"
204
+ }
205
+ ),
206
+ /* @__PURE__ */ jsx(DataTableNumber, { value, format, className: "shrink-0" })
207
+ ]
208
+ }
209
+ );
210
+ }
211
+ function metaOf(column) {
212
+ return column.columnDef.meta;
213
+ }
214
+ function alignOf(meta) {
215
+ return meta?.align ?? (meta?.numeric ? "end" : "start");
216
+ }
217
+ const ALIGN_CLASS = {
218
+ start: "text-start",
219
+ end: "text-end",
220
+ center: "text-center"
221
+ };
222
+ const JUSTIFY_CLASS = {
223
+ start: "justify-start",
224
+ end: "justify-end",
225
+ center: "justify-center"
226
+ };
227
+ function labelOf(column) {
228
+ const header = column.columnDef.header;
229
+ return metaOf(column)?.label ?? (typeof header === "string" ? header : column.id);
230
+ }
231
+ function readPath(row, path) {
232
+ let value = row;
233
+ for (const key of path.split(".")) {
234
+ if (value === null || value === void 0) return void 0;
235
+ value = value[key];
236
+ }
237
+ return value;
238
+ }
239
+ function prepareColumns(columns) {
240
+ return columns.map((input) => {
241
+ const col = { ...input };
242
+ const meta = col.meta;
243
+ if (meta?.filter && col.filterFn === void 0)
244
+ col.filterFn = meta.filter === "select" ? "equalsString" : "includesString";
245
+ if (meta?.numeric) {
246
+ if (typeof col.accessorKey === "string" && !col.accessorFn) {
247
+ const key = col.accessorKey;
248
+ col.id = col.id ?? key;
249
+ col.accessorFn = (row) => readPath(row, key) ?? void 0;
250
+ delete col.accessorKey;
251
+ } else if (typeof col.accessorFn === "function") {
252
+ const fn = col.accessorFn;
253
+ col.accessorFn = (...a) => fn(...a) ?? void 0;
254
+ }
255
+ col.sortFn ??= "number";
256
+ col.sortUndefined ??= "last";
257
+ col.cell ??= ({ getValue }) => {
258
+ const v = getValue();
259
+ return /* @__PURE__ */ jsx(
260
+ DataTableNumber,
261
+ {
262
+ value: v === void 0 || v === null ? null : Number(v),
263
+ format: meta.format
264
+ }
265
+ );
266
+ };
267
+ } else {
268
+ col.cell ??= ({ getValue }) => {
269
+ const v = getValue();
270
+ if (v === null || v === void 0 || v === "") return /* @__PURE__ */ jsx(NoData, {});
271
+ return String(v);
272
+ };
273
+ }
274
+ return col;
275
+ });
276
+ }
277
+ function DataTable({
278
+ columns,
279
+ data,
280
+ getRowId,
281
+ state: controlled,
282
+ onStateChange,
283
+ defaultState,
284
+ searchable = true,
285
+ selectable = false,
286
+ columnToggle = true,
287
+ pageSizes = DATA_TABLE_PAGE_SIZES,
288
+ loading = false,
289
+ empty,
290
+ onRowClick,
291
+ toolbar,
292
+ rowActions,
293
+ density = "comfortable",
294
+ "aria-label": ariaLabel,
295
+ className
296
+ }) {
297
+ const t = useDsMessages();
298
+ const id = React.useId();
299
+ const [own, setOwn] = React.useState(() => ({
300
+ ...DEFAULT_STATE,
301
+ pageSize: pageSizes[0] ?? DEFAULT_STATE.pageSize,
302
+ ...defaultState
303
+ }));
304
+ const current = { ...own, ...controlled };
305
+ const sorting = React.useMemo(
306
+ () => current.sorting,
307
+ // biome-ignore lint/correctness/useExhaustiveDependencies: comparación por valor
308
+ [JSON.stringify(current.sorting)]
309
+ );
310
+ const columnFilters = React.useMemo(
311
+ () => current.columnFilters,
312
+ // biome-ignore lint/correctness/useExhaustiveDependencies: comparación por valor
313
+ [JSON.stringify(current.columnFilters)]
314
+ );
315
+ const columnVisibility = React.useMemo(
316
+ () => current.columnVisibility,
317
+ // biome-ignore lint/correctness/useExhaustiveDependencies: comparación por valor
318
+ [JSON.stringify(current.columnVisibility)]
319
+ );
320
+ const rowSelection = React.useMemo(
321
+ () => current.rowSelection,
322
+ // biome-ignore lint/correctness/useExhaustiveDependencies: comparación por valor
323
+ [JSON.stringify(current.rowSelection)]
324
+ );
325
+ const latest = React.useRef(current);
326
+ latest.current = current;
327
+ const update = React.useCallback(
328
+ (patch) => {
329
+ const next = { ...latest.current, ...patch };
330
+ latest.current = next;
331
+ setOwn(next);
332
+ onStateChange?.(next);
333
+ },
334
+ [onStateChange]
335
+ );
336
+ const prepared = React.useMemo(() => prepareColumns(columns), [columns]);
337
+ const table = useTable({
338
+ features: dataTableFeatures,
339
+ data,
340
+ columns: prepared,
341
+ getRowId,
342
+ state: {
343
+ sorting,
344
+ globalFilter: current.search,
345
+ columnFilters,
346
+ columnVisibility,
347
+ rowSelection
348
+ },
349
+ onSortingChange: (u) => update({ sorting: functionalUpdate(u, latest.current.sorting), page: 1 }),
350
+ onGlobalFilterChange: (u) => update({ search: functionalUpdate(u, latest.current.search) ?? "", page: 1 }),
351
+ onColumnFiltersChange: (u) => update({
352
+ columnFilters: functionalUpdate(u, latest.current.columnFilters),
353
+ page: 1
354
+ }),
355
+ onColumnVisibilityChange: (u) => update({
356
+ columnVisibility: functionalUpdate(u, latest.current.columnVisibility)
357
+ }),
358
+ onRowSelectionChange: (u) => update({ rowSelection: functionalUpdate(u, latest.current.rowSelection) }),
359
+ globalFilterFn: "includesString",
360
+ enableRowSelection: selectable
361
+ });
362
+ const allRows = table.getPrePaginatedRowModel().rows;
363
+ const total = allRows.length;
364
+ const pageSize = current.pageSize;
365
+ const pageCount = Math.max(1, Math.ceil(total / pageSize));
366
+ const pageIndex = Math.min(Math.max(1, current.page), pageCount) - 1;
367
+ const rows = allRows.slice(pageIndex * pageSize, (pageIndex + 1) * pageSize);
368
+ const leafColumns = table.getVisibleLeafColumns();
369
+ const colSpan = leafColumns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0);
370
+ const filterColumns = table.getAllLeafColumns().filter((c) => metaOf(c)?.filter && c.getCanFilter());
371
+ const hideableColumns = table.getAllLeafColumns().filter((c) => c.getCanHide());
372
+ const pageSelected = rows.filter((r) => r.getIsSelected()).length;
373
+ const allPageSelected = rows.length > 0 && pageSelected === rows.length;
374
+ const somePageSelected = pageSelected > 0 && !allPageSelected;
375
+ const selectedCount = Object.keys(rowSelection).length;
376
+ const togglePage = (checked) => {
377
+ const next = { ...latest.current.rowSelection };
378
+ for (const r of rows) {
379
+ if (!r.getCanSelect()) continue;
380
+ if (checked) next[r.id] = true;
381
+ else delete next[r.id];
382
+ }
383
+ update({ rowSelection: next });
384
+ };
385
+ const stop = (e) => e.stopPropagation();
386
+ const skeletonRows = Math.min(pageSize, 5);
387
+ const hasToolbar = searchable || filterColumns.length > 0 || columnToggle && hideableColumns.length > 0 || toolbar;
388
+ return /* @__PURE__ */ jsxs(
389
+ "div",
390
+ {
391
+ "data-slot": "data-table",
392
+ "data-density": density,
393
+ "aria-busy": loading || void 0,
394
+ className: cn(
395
+ "group/data-table flex w-full min-w-0 flex-col gap-(--ds-section-gap)",
396
+ className
397
+ ),
398
+ children: [
399
+ hasToolbar && /* @__PURE__ */ jsxs(
400
+ "div",
401
+ {
402
+ "data-slot": "data-table-toolbar",
403
+ className: "flex flex-wrap items-center gap-(--ds-filter-gap)",
404
+ children: [
405
+ searchable && /* @__PURE__ */ jsxs("div", { "data-slot": "data-table-search", className: "relative w-full max-w-64", children: [
406
+ /* @__PURE__ */ jsx(
407
+ SearchIcon,
408
+ {
409
+ "aria-hidden": "true",
410
+ className: "pointer-events-none absolute start-2.5 top-1/2 size-4 -translate-y-1/2 text-muted-foreground"
411
+ }
412
+ ),
413
+ /* @__PURE__ */ jsx(
414
+ Input,
415
+ {
416
+ type: "search",
417
+ value: current.search,
418
+ onChange: (e) => table.setGlobalFilter(e.target.value),
419
+ placeholder: t.dataTableSearch,
420
+ "aria-label": t.dataTableSearch,
421
+ className: "ps-8"
422
+ }
423
+ )
424
+ ] }),
425
+ filterColumns.map((column) => {
426
+ const meta = metaOf(column);
427
+ const label = labelOf(column);
428
+ const value = column.getFilterValue() ?? "";
429
+ const name = `${t.dataTableFilter}: ${label}`;
430
+ return meta?.filter === "select" ? /* @__PURE__ */ jsxs(
431
+ NativeSelect,
432
+ {
433
+ "data-slot": "data-table-filter",
434
+ "aria-label": name,
435
+ value,
436
+ onChange: (e) => column.setFilterValue(e.target.value || void 0),
437
+ children: [
438
+ /* @__PURE__ */ jsx(NativeSelectOption, { value: "", children: label }),
439
+ meta.filterOptions?.map((o) => /* @__PURE__ */ jsx(NativeSelectOption, { value: o.value, children: o.label }, o.value))
440
+ ]
441
+ },
442
+ column.id
443
+ ) : /* @__PURE__ */ jsx(
444
+ Input,
445
+ {
446
+ "data-slot": "data-table-filter",
447
+ "aria-label": name,
448
+ placeholder: label,
449
+ value,
450
+ onChange: (e) => column.setFilterValue(e.target.value || void 0),
451
+ className: "w-auto max-w-48"
452
+ },
453
+ column.id
454
+ );
455
+ }),
456
+ toolbar,
457
+ columnToggle && hideableColumns.length > 0 && /* @__PURE__ */ jsxs(DropdownMenu, { children: [
458
+ /* @__PURE__ */ jsxs(
459
+ DropdownMenuTrigger,
460
+ {
461
+ "data-slot": "data-table-columns",
462
+ className: "ms-auto",
463
+ render: /* @__PURE__ */ jsx(Button, { variant: "outline" }),
464
+ children: [
465
+ /* @__PURE__ */ jsx(Columns3Icon, { "aria-hidden": "true" }),
466
+ t.dataTableColumns
467
+ ]
468
+ }
469
+ ),
470
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", className: "w-auto", children: /* @__PURE__ */ jsxs(DropdownMenuGroup, { children: [
471
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { children: t.dataTableColumns }),
472
+ hideableColumns.map((column) => /* @__PURE__ */ jsx(
473
+ DropdownMenuCheckboxItem,
474
+ {
475
+ checked: column.getIsVisible(),
476
+ onCheckedChange: (v) => column.toggleVisibility(!!v),
477
+ children: labelOf(column)
478
+ },
479
+ column.id
480
+ ))
481
+ ] }) })
482
+ ] })
483
+ ]
484
+ }
485
+ ),
486
+ /* @__PURE__ */ jsxs(Table, { "aria-label": ariaLabel, "aria-describedby": loading ? `${id}-status` : void 0, children: [
487
+ /* @__PURE__ */ jsx(TableHeader, { "data-slot": "data-table-header", children: table.getHeaderGroups().map((group) => /* @__PURE__ */ jsxs(TableRow, { children: [
488
+ selectable && /* @__PURE__ */ jsx(
489
+ TableHead,
490
+ {
491
+ "data-slot": "data-table-select",
492
+ className: "w-0 pe-0 group-data-[density=compact]/data-table:h-(--ds-table-head-h-compact)",
493
+ children: /* @__PURE__ */ jsx(
494
+ Checkbox,
495
+ {
496
+ checked: allPageSelected,
497
+ indeterminate: somePageSelected,
498
+ disabled: loading || rows.length === 0,
499
+ onCheckedChange: (v) => togglePage(!!v),
500
+ "aria-label": dsFormat(t.dataTableSelected, {
501
+ n: pageSelected,
502
+ total: rows.length
503
+ })
504
+ }
505
+ )
506
+ }
507
+ ),
508
+ group.headers.map((header) => {
509
+ const column = header.column;
510
+ const meta = metaOf(column);
511
+ const align = alignOf(meta);
512
+ const dir = column.getIsSorted();
513
+ const canSort = column.getCanSort();
514
+ const next = column.getNextSortingOrder();
515
+ return /* @__PURE__ */ jsx(
516
+ TableHead,
517
+ {
518
+ colSpan: header.colSpan,
519
+ "data-slot": "data-table-head",
520
+ "data-align": align,
521
+ "aria-sort": canSort ? dir === "asc" ? "ascending" : dir === "desc" ? "descending" : "none" : void 0,
522
+ className: cn(
523
+ ALIGN_CLASS[align],
524
+ "group-data-[density=compact]/data-table:h-(--ds-table-head-h-compact)",
525
+ meta?.className
526
+ ),
527
+ children: header.isPlaceholder ? null : canSort ? /* @__PURE__ */ jsxs(
528
+ "button",
529
+ {
530
+ type: "button",
531
+ "data-slot": "data-table-sort",
532
+ title: next === "desc" ? t.dataTableSortDesc : next === "asc" ? t.dataTableSortAsc : void 0,
533
+ onClick: column.getToggleSortingHandler(),
534
+ className: cn(
535
+ "-mx-1 inline-flex items-center gap-1 rounded-item px-1 outline-none hover:text-foreground focus-visible:ring-(length:--ds-ring-width) focus-visible:ring-(--ds-ring-color)",
536
+ align === "end" && "flex-row-reverse"
537
+ ),
538
+ children: [
539
+ /* @__PURE__ */ jsx(table.FlexRender, { header }),
540
+ dir === "asc" ? /* @__PURE__ */ jsx(ArrowUpIcon, { "aria-hidden": "true", className: "size-3.5" }) : dir === "desc" ? /* @__PURE__ */ jsx(ArrowDownIcon, { "aria-hidden": "true", className: "size-3.5" }) : /* @__PURE__ */ jsx(
541
+ ChevronsUpDownIcon,
542
+ {
543
+ "aria-hidden": "true",
544
+ className: "size-3.5 text-muted-foreground"
545
+ }
546
+ )
547
+ ]
548
+ }
549
+ ) : /* @__PURE__ */ jsx(table.FlexRender, { header })
550
+ },
551
+ header.id
552
+ );
553
+ }),
554
+ rowActions && /* @__PURE__ */ jsx(
555
+ TableHead,
556
+ {
557
+ "data-slot": "data-table-actions",
558
+ className: "w-0 group-data-[density=compact]/data-table:h-(--ds-table-head-h-compact)"
559
+ }
560
+ )
561
+ ] }, group.id)) }),
562
+ /* @__PURE__ */ jsx(TableBody, { "data-slot": "data-table-body", children: loading ? Array.from({ length: skeletonRows }, (_, i) => (
563
+ // biome-ignore lint/suspicious/noArrayIndexKey: filas skeleton sin identidad
564
+ /* @__PURE__ */ jsx(TableRow, { "data-slot": "data-table-skeleton-row", children: /* @__PURE__ */ jsx(TableCell, { colSpan, className: CELL_DENSITY, children: /* @__PURE__ */ jsx(Skeleton, { className: "h-(--ds-control-h-xs) w-full" }) }) }, i)
565
+ )) : rows.length === 0 ? /* @__PURE__ */ jsx(TableRow, { "data-slot": "data-table-empty-row", className: "hover:bg-transparent", children: /* @__PURE__ */ jsx(TableCell, { colSpan, className: "whitespace-normal", children: empty ?? /* @__PURE__ */ jsx(Empty, { "data-slot": "data-table-empty", children: /* @__PURE__ */ jsx(EmptyHeader, { children: /* @__PURE__ */ jsx(EmptyTitle, { children: t.dataTableNoResults }) }) }) }) }) : rows.map((row) => /* @__PURE__ */ jsxs(
566
+ TableRow,
567
+ {
568
+ "data-slot": "data-table-row",
569
+ "data-state": row.getIsSelected() ? "selected" : void 0,
570
+ "data-clickable": onRowClick ? "" : void 0,
571
+ tabIndex: onRowClick ? 0 : void 0,
572
+ onClick: onRowClick ? () => onRowClick(row.original) : void 0,
573
+ onKeyDown: onRowClick ? (e) => {
574
+ if (e.target !== e.currentTarget) return;
575
+ if (e.key === "Enter" || e.key === " ") {
576
+ e.preventDefault();
577
+ onRowClick(row.original);
578
+ }
579
+ } : void 0,
580
+ className: cn(
581
+ onRowClick && "cursor-pointer outline-none focus-visible:bg-(--ds-row-hover) focus-visible:ring-(length:--ds-ring-width) focus-visible:ring-(--ds-ring-color) focus-visible:ring-inset"
582
+ ),
583
+ children: [
584
+ selectable && /* @__PURE__ */ jsx(
585
+ TableCell,
586
+ {
587
+ "data-slot": "data-table-select",
588
+ className: cn("w-0 pe-0", CELL_DENSITY),
589
+ onClick: stop,
590
+ onKeyDown: stop,
591
+ children: /* @__PURE__ */ jsx(
592
+ Checkbox,
593
+ {
594
+ checked: row.getIsSelected(),
595
+ disabled: !row.getCanSelect(),
596
+ onCheckedChange: (v) => row.toggleSelected(!!v),
597
+ "aria-labelledby": `${id}-${row.id}`
598
+ }
599
+ )
600
+ }
601
+ ),
602
+ row.getVisibleCells().map(
603
+ (cell, i) => {
604
+ const meta = metaOf(cell.column);
605
+ const align = alignOf(meta);
606
+ return /* @__PURE__ */ jsx(
607
+ TableCell,
608
+ {
609
+ id: i === 0 ? `${id}-${row.id}` : void 0,
610
+ "data-slot": "data-table-cell",
611
+ "data-align": align,
612
+ className: cn(
613
+ ALIGN_CLASS[align],
614
+ meta?.numeric && "tabular-nums",
615
+ CELL_DENSITY,
616
+ meta?.className
617
+ ),
618
+ children: /* @__PURE__ */ jsx(table.FlexRender, { cell })
619
+ },
620
+ cell.id
621
+ );
622
+ }
623
+ ),
624
+ rowActions && /* @__PURE__ */ jsx(
625
+ TableCell,
626
+ {
627
+ "data-slot": "data-table-actions",
628
+ className: cn("w-0 text-end", CELL_DENSITY),
629
+ onClick: stop,
630
+ onKeyDown: stop,
631
+ children: /* @__PURE__ */ jsx("div", { className: cn("flex items-center gap-1", JUSTIFY_CLASS.end), children: rowActions(row.original) })
632
+ }
633
+ )
634
+ ]
635
+ },
636
+ row.id
637
+ )) })
638
+ ] }),
639
+ loading && /* @__PURE__ */ jsx("span", { id: `${id}-status`, role: "status", className: "sr-only", children: t.dataTableLoading }),
640
+ /* @__PURE__ */ jsxs(
641
+ "div",
642
+ {
643
+ "data-slot": "data-table-footer",
644
+ className: "flex flex-wrap items-center justify-between gap-(--ds-filter-gap) text-sm text-muted-foreground",
645
+ children: [
646
+ /* @__PURE__ */ jsx("span", { "data-slot": "data-table-selected", className: "tabular-nums", "aria-live": "polite", children: selectable ? dsFormat(t.dataTableSelected, { n: selectedCount, total }) : null }),
647
+ /* @__PURE__ */ jsxs(
648
+ "div",
649
+ {
650
+ "data-slot": "data-table-pagination",
651
+ className: "flex flex-wrap items-center gap-(--ds-filter-gap)",
652
+ children: [
653
+ /* @__PURE__ */ jsx("label", { className: "flex items-center gap-2", htmlFor: `${id}-size`, children: t.dataTableRowsPerPage }),
654
+ /* @__PURE__ */ jsx(
655
+ NativeSelect,
656
+ {
657
+ id: `${id}-size`,
658
+ size: "sm",
659
+ value: String(pageSize),
660
+ onChange: (e) => update({ pageSize: Number(e.target.value), page: 1 }),
661
+ children: pageSizes.map((n) => /* @__PURE__ */ jsx(NativeSelectOption, { value: n, children: n }, n))
662
+ }
663
+ ),
664
+ /* @__PURE__ */ jsx("span", { "data-slot": "data-table-page", className: "tabular-nums", "aria-live": "polite", children: dsFormat(t.dataTablePage, { page: pageIndex + 1, pages: pageCount }) }),
665
+ /* @__PURE__ */ jsxs(
666
+ Button,
667
+ {
668
+ variant: "outline",
669
+ size: "sm",
670
+ disabled: pageIndex === 0 || loading,
671
+ "aria-label": t.paginationPreviousLabel,
672
+ onClick: () => update({ page: pageIndex }),
673
+ children: [
674
+ /* @__PURE__ */ jsx(ChevronLeftIcon, { "aria-hidden": "true", className: "rtl:rotate-180" }),
675
+ t.paginationPrevious
676
+ ]
677
+ }
678
+ ),
679
+ /* @__PURE__ */ jsxs(
680
+ Button,
681
+ {
682
+ variant: "outline",
683
+ size: "sm",
684
+ disabled: pageIndex >= pageCount - 1 || loading,
685
+ "aria-label": t.paginationNextLabel,
686
+ onClick: () => update({ page: pageIndex + 2 }),
687
+ children: [
688
+ t.paginationNext,
689
+ /* @__PURE__ */ jsx(ChevronRightIcon, { "aria-hidden": "true", className: "rtl:rotate-180" })
690
+ ]
691
+ }
692
+ )
693
+ ]
694
+ }
695
+ )
696
+ ]
697
+ }
698
+ )
699
+ ]
700
+ }
701
+ );
702
+ }
703
+ const CELL_DENSITY = "group-data-[density=compact]/data-table:py-(--ds-cell-p-compact)";
704
+ export {
705
+ DATA_TABLE_PAGE_SIZES,
706
+ DataTable,
707
+ DataTableBarCell,
708
+ DataTableNumber,
709
+ createDataTableColumnHelper,
710
+ dataTableFeatures,
711
+ dataTableStateFromSearch,
712
+ dataTableStateToSearch,
713
+ validateDataTableSearch
714
+ };