@arqel-dev/ui 0.11.0 → 0.13.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 (111) hide show
  1. package/SKILL.md +5 -2
  2. package/dist/AreaChart-NMQ2RQGA.js +33 -0
  3. package/dist/AreaChart-NMQ2RQGA.js.map +1 -0
  4. package/dist/ArqelCreatePage-P3G6TKIK.js +8 -0
  5. package/dist/ArqelCreatePage-P3G6TKIK.js.map +1 -0
  6. package/dist/ArqelDashboardPage-PX3Y75AA.js +6 -0
  7. package/dist/ArqelDashboardPage-PX3Y75AA.js.map +1 -0
  8. package/dist/ArqelEditPage-HKQSE6E5.js +8 -0
  9. package/dist/ArqelEditPage-HKQSE6E5.js.map +1 -0
  10. package/dist/ArqelIndexPage-MRH3572Z.js +12 -0
  11. package/dist/ArqelIndexPage-MRH3572Z.js.map +1 -0
  12. package/dist/ArqelShowPage-4FS5MTUN.js +6 -0
  13. package/dist/ArqelShowPage-4FS5MTUN.js.map +1 -0
  14. package/dist/BarChart-KLHKTLO2.js +19 -0
  15. package/dist/BarChart-KLHKTLO2.js.map +1 -0
  16. package/dist/DonutChart-L56R4QF2.js +11 -0
  17. package/dist/DonutChart-L56R4QF2.js.map +1 -0
  18. package/dist/LineChart-GHMPHFZZ.js +30 -0
  19. package/dist/LineChart-GHMPHFZZ.js.map +1 -0
  20. package/dist/PieChart-T2VQOFPP.js +4 -0
  21. package/dist/PieChart-T2VQOFPP.js.map +1 -0
  22. package/dist/RadarChart-CSWR5AO7.js +32 -0
  23. package/dist/RadarChart-CSWR5AO7.js.map +1 -0
  24. package/dist/Topbar-DffcNdcJ.d.ts +50 -0
  25. package/dist/action.d.ts +12 -2
  26. package/dist/action.js +6 -1090
  27. package/dist/action.js.map +1 -1
  28. package/dist/auth.js +1 -10
  29. package/dist/auth.js.map +1 -1
  30. package/dist/chunk-2LTZJ4R7.js +110 -0
  31. package/dist/chunk-2LTZJ4R7.js.map +1 -0
  32. package/dist/chunk-3JJOHYD7.js +57 -0
  33. package/dist/chunk-3JJOHYD7.js.map +1 -0
  34. package/dist/chunk-47HD7ALI.js +370 -0
  35. package/dist/chunk-47HD7ALI.js.map +1 -0
  36. package/dist/chunk-6UJQP7KU.js +737 -0
  37. package/dist/chunk-6UJQP7KU.js.map +1 -0
  38. package/dist/chunk-7LSZADUC.js +50 -0
  39. package/dist/chunk-7LSZADUC.js.map +1 -0
  40. package/dist/chunk-B7ULUJVO.js +11 -0
  41. package/dist/chunk-B7ULUJVO.js.map +1 -0
  42. package/dist/chunk-C5H44NSP.js +37 -0
  43. package/dist/chunk-C5H44NSP.js.map +1 -0
  44. package/dist/chunk-DSULVRB6.js +101 -0
  45. package/dist/chunk-DSULVRB6.js.map +1 -0
  46. package/dist/chunk-ERT7LL6C.js +199 -0
  47. package/dist/chunk-ERT7LL6C.js.map +1 -0
  48. package/dist/chunk-EYAUPJ6J.js +64 -0
  49. package/dist/chunk-EYAUPJ6J.js.map +1 -0
  50. package/dist/chunk-FHRQ7PWE.js +58 -0
  51. package/dist/chunk-FHRQ7PWE.js.map +1 -0
  52. package/dist/chunk-FV7RESKL.js +285 -0
  53. package/dist/chunk-FV7RESKL.js.map +1 -0
  54. package/dist/chunk-K7QY56XN.js +610 -0
  55. package/dist/chunk-K7QY56XN.js.map +1 -0
  56. package/dist/chunk-L3JBBN4H.js +27 -0
  57. package/dist/chunk-L3JBBN4H.js.map +1 -0
  58. package/dist/chunk-MSRTGCTJ.js +597 -0
  59. package/dist/chunk-MSRTGCTJ.js.map +1 -0
  60. package/dist/chunk-MTNFFSVA.js +92 -0
  61. package/dist/chunk-MTNFFSVA.js.map +1 -0
  62. package/dist/chunk-MTZJDFQ6.js +32 -0
  63. package/dist/chunk-MTZJDFQ6.js.map +1 -0
  64. package/dist/chunk-MXUXMHOK.js +16 -0
  65. package/dist/chunk-MXUXMHOK.js.map +1 -0
  66. package/dist/chunk-PXON56HL.js +35 -0
  67. package/dist/chunk-PXON56HL.js.map +1 -0
  68. package/dist/chunk-PZEVKMZX.js +598 -0
  69. package/dist/chunk-PZEVKMZX.js.map +1 -0
  70. package/dist/chunk-R4BOUU6Y.js +55 -0
  71. package/dist/chunk-R4BOUU6Y.js.map +1 -0
  72. package/dist/chunk-RMPOR2YZ.js +12 -0
  73. package/dist/chunk-RMPOR2YZ.js.map +1 -0
  74. package/dist/chunk-RNAMHQM6.js +12 -0
  75. package/dist/chunk-RNAMHQM6.js.map +1 -0
  76. package/dist/chunk-TNJEHYRF.js +387 -0
  77. package/dist/chunk-TNJEHYRF.js.map +1 -0
  78. package/dist/chunk-VSTRVXXZ.js +49 -0
  79. package/dist/chunk-VSTRVXXZ.js.map +1 -0
  80. package/dist/chunk-WKWV36PG.js +140 -0
  81. package/dist/chunk-WKWV36PG.js.map +1 -0
  82. package/dist/cn-By8XWiSA.d.ts +12 -0
  83. package/dist/flash.js +2 -104
  84. package/dist/flash.js.map +1 -1
  85. package/dist/form.js +4 -673
  86. package/dist/form.js.map +1 -1
  87. package/dist/index.d.ts +2 -2
  88. package/dist/index.js +18 -3706
  89. package/dist/index.js.map +1 -1
  90. package/dist/pages.js +23 -3025
  91. package/dist/pages.js.map +1 -1
  92. package/dist/palette.js +1 -283
  93. package/dist/palette.js.map +1 -1
  94. package/dist/primitives.js +3 -658
  95. package/dist/primitives.js.map +1 -1
  96. package/dist/resource.js +5 -720
  97. package/dist/resource.js.map +1 -1
  98. package/dist/shell.d.ts +26 -46
  99. package/dist/shell.js +46 -1039
  100. package/dist/shell.js.map +1 -1
  101. package/dist/table.js +4 -618
  102. package/dist/table.js.map +1 -1
  103. package/dist/utility.js +3 -104
  104. package/dist/utility.js.map +1 -1
  105. package/dist/utils.d.ts +12 -6
  106. package/dist/utils.js +2 -9
  107. package/dist/utils.js.map +1 -1
  108. package/dist/widgets.d.ts +7 -2
  109. package/dist/widgets.js +3 -675
  110. package/dist/widgets.js.map +1 -1
  111. package/package.json +15 -14
@@ -0,0 +1,598 @@
1
+ import { resolveLucideIcon } from './chunk-RMPOR2YZ.js';
2
+ import { Button } from './chunk-FHRQ7PWE.js';
3
+ import { cn } from './chunk-B7ULUJVO.js';
4
+ import { jsx, jsxs } from 'react/jsx-runtime';
5
+ import { useReactTable, getCoreRowModel, flexRender } from '@tanstack/react-table';
6
+ import { useRef, useMemo, useCallback } from 'react';
7
+
8
+ function TableCell({ column, value }) {
9
+ switch (column.type) {
10
+ case "text":
11
+ return /* @__PURE__ */ jsx(TextCell, { column, value });
12
+ case "badge":
13
+ return /* @__PURE__ */ jsx(BadgeCell, { column, value });
14
+ case "boolean":
15
+ return /* @__PURE__ */ jsx(BooleanCell, { column, value });
16
+ case "date":
17
+ return /* @__PURE__ */ jsx(DateCell, { column, value });
18
+ case "number":
19
+ return /* @__PURE__ */ jsx(NumberCell, { column, value });
20
+ case "icon":
21
+ return /* @__PURE__ */ jsx(IconCell, { column });
22
+ case "image":
23
+ return /* @__PURE__ */ jsx(ImageCell, { column, value });
24
+ case "relationship":
25
+ return /* @__PURE__ */ jsx(RelationshipCell, { column, value });
26
+ case "computed":
27
+ return /* @__PURE__ */ jsx(ComputedCell, { column, value });
28
+ }
29
+ }
30
+ function asString(value) {
31
+ if (value === null || value === void 0) return "";
32
+ if (typeof value === "string") return value;
33
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
34
+ return JSON.stringify(value);
35
+ }
36
+ function TextCell({ column, value }) {
37
+ const str = asString(value);
38
+ const truncated = column.props.truncate && str.length > column.props.truncate ? `${str.slice(0, column.props.truncate)}\u2026` : str;
39
+ return /* @__PURE__ */ jsx(
40
+ "span",
41
+ {
42
+ className: cn(
43
+ column.props.weight === "bold" && "font-bold",
44
+ column.props.weight === "medium" && "font-medium"
45
+ ),
46
+ children: truncated
47
+ }
48
+ );
49
+ }
50
+ var BADGE_COLOR_CLASS = {
51
+ gray: "bg-muted text-foreground",
52
+ slate: "bg-slate-100 text-slate-800 dark:bg-slate-800/40 dark:text-slate-200",
53
+ zinc: "bg-zinc-100 text-zinc-800 dark:bg-zinc-800/40 dark:text-zinc-200",
54
+ red: "bg-red-100 text-red-800 dark:bg-red-900/40 dark:text-red-200",
55
+ orange: "bg-orange-100 text-orange-800 dark:bg-orange-900/40 dark:text-orange-200",
56
+ amber: "bg-amber-100 text-amber-800 dark:bg-amber-900/40 dark:text-amber-200",
57
+ yellow: "bg-yellow-100 text-yellow-800 dark:bg-yellow-900/40 dark:text-yellow-200",
58
+ lime: "bg-lime-100 text-lime-800 dark:bg-lime-900/40 dark:text-lime-200",
59
+ green: "bg-green-100 text-green-800 dark:bg-green-900/40 dark:text-green-200",
60
+ emerald: "bg-emerald-100 text-emerald-800 dark:bg-emerald-900/40 dark:text-emerald-200",
61
+ teal: "bg-teal-100 text-teal-800 dark:bg-teal-900/40 dark:text-teal-200",
62
+ cyan: "bg-cyan-100 text-cyan-800 dark:bg-cyan-900/40 dark:text-cyan-200",
63
+ sky: "bg-sky-100 text-sky-800 dark:bg-sky-900/40 dark:text-sky-200",
64
+ blue: "bg-blue-100 text-blue-800 dark:bg-blue-900/40 dark:text-blue-200",
65
+ indigo: "bg-indigo-100 text-indigo-800 dark:bg-indigo-900/40 dark:text-indigo-200",
66
+ violet: "bg-violet-100 text-violet-800 dark:bg-violet-900/40 dark:text-violet-200",
67
+ purple: "bg-purple-100 text-purple-800 dark:bg-purple-900/40 dark:text-purple-200",
68
+ fuchsia: "bg-fuchsia-100 text-fuchsia-800 dark:bg-fuchsia-900/40 dark:text-fuchsia-200",
69
+ pink: "bg-pink-100 text-pink-800 dark:bg-pink-900/40 dark:text-pink-200",
70
+ rose: "bg-rose-100 text-rose-800 dark:bg-rose-900/40 dark:text-rose-200"
71
+ };
72
+ var BADGE_MUTED_CLASS = "bg-muted text-foreground";
73
+ function BadgeCell({ column, value }) {
74
+ const key = asString(value);
75
+ const option = column.props.options?.find((o) => o.value === value);
76
+ const label = option?.label ?? key;
77
+ const colorToken = column.props.colors?.[key];
78
+ const colorClass = colorToken && BADGE_COLOR_CLASS[colorToken] || BADGE_MUTED_CLASS;
79
+ const iconName = column.props.icons?.[key];
80
+ const Icon = iconName ? resolveLucideIcon(iconName) : void 0;
81
+ return /* @__PURE__ */ jsxs(
82
+ "span",
83
+ {
84
+ className: cn(
85
+ "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium",
86
+ column.props.pill ? "rounded-full" : "rounded-sm",
87
+ colorClass
88
+ ),
89
+ children: [
90
+ Icon ? /* @__PURE__ */ jsx(Icon, { className: "size-3 shrink-0", "aria-hidden": true }) : null,
91
+ label
92
+ ]
93
+ }
94
+ );
95
+ }
96
+ function BooleanCell({ column, value }) {
97
+ const truthy = Boolean(value);
98
+ return /* @__PURE__ */ jsx("span", { role: "img", "aria-label": truthy ? "true" : "false", children: truthy ? column.props.trueIcon ?? "\u2713" : column.props.falseIcon ?? "\u2014" });
99
+ }
100
+ function DateCell({ column, value }) {
101
+ if (!value) return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" });
102
+ const raw = String(value);
103
+ const date = new Date(raw);
104
+ if (Number.isNaN(date.getTime())) return /* @__PURE__ */ jsx("span", { children: raw });
105
+ if (column.props.mode === "since") {
106
+ return /* @__PURE__ */ jsx("time", { dateTime: date.toISOString(), children: formatRelative(date) });
107
+ }
108
+ if (column.props.mode === "datetime") {
109
+ return /* @__PURE__ */ jsx("time", { dateTime: date.toISOString(), children: date.toLocaleString() });
110
+ }
111
+ return /* @__PURE__ */ jsx("time", { dateTime: date.toISOString(), children: date.toLocaleDateString() });
112
+ }
113
+ function formatRelative(date) {
114
+ const seconds = Math.round((Date.now() - date.getTime()) / 1e3);
115
+ if (seconds < 60) return `${seconds}s ago`;
116
+ const minutes = Math.round(seconds / 60);
117
+ if (minutes < 60) return `${minutes}m ago`;
118
+ const hours = Math.round(minutes / 60);
119
+ if (hours < 24) return `${hours}h ago`;
120
+ const days = Math.round(hours / 24);
121
+ return `${days}d ago`;
122
+ }
123
+ function NumberCell({ column, value }) {
124
+ if (value === null || value === void 0) return /* @__PURE__ */ jsx("span", { children: "\u2014" });
125
+ const num = typeof value === "number" ? value : Number(value);
126
+ if (Number.isNaN(num)) return /* @__PURE__ */ jsx("span", { children: asString(value) });
127
+ const formatted = num.toFixed(column.props.decimals ?? 0);
128
+ const [whole, dec] = formatted.split(".");
129
+ const safeWhole = whole ?? "0";
130
+ const ts = column.props.thousandsSeparator;
131
+ const finalWhole = ts ? safeWhole.replace(/\B(?=(\d{3})+(?!\d))/g, ts) : safeWhole;
132
+ const ds = column.props.decimalSeparator ?? ".";
133
+ return /* @__PURE__ */ jsxs("span", { children: [
134
+ column.props.prefix ?? "",
135
+ finalWhole,
136
+ dec ? `${ds}${dec}` : "",
137
+ column.props.suffix ?? ""
138
+ ] });
139
+ }
140
+ function IconCell({ column }) {
141
+ return /* @__PURE__ */ jsx("span", { role: "img", "aria-label": column.props.icon, title: column.props.icon, children: column.props.icon });
142
+ }
143
+ function ImageCell({ column, value }) {
144
+ const src = asString(value);
145
+ if (!src) return null;
146
+ const size = column.props.size ?? 32;
147
+ return /* @__PURE__ */ jsx(
148
+ "img",
149
+ {
150
+ src,
151
+ alt: "",
152
+ style: { width: size, height: size },
153
+ className: cn(column.props.shape === "circular" ? "rounded-full" : "rounded")
154
+ }
155
+ );
156
+ }
157
+ function RelationshipCell({ column, value }) {
158
+ if (value === null || value === void 0) return /* @__PURE__ */ jsx("span", { children: "\u2014" });
159
+ if (typeof value === "object") {
160
+ const attr = value[column.props.attribute];
161
+ return /* @__PURE__ */ jsx("span", { children: asString(attr) });
162
+ }
163
+ return /* @__PURE__ */ jsx("span", { children: asString(value) });
164
+ }
165
+ function ComputedCell({ column, value }) {
166
+ if (value === null || value === void 0) {
167
+ return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: column.props.placeholder ?? "\u2014" });
168
+ }
169
+ return /* @__PURE__ */ jsx("span", { children: asString(value) });
170
+ }
171
+ function DataTable({
172
+ columns,
173
+ records,
174
+ enableSelection = false,
175
+ selectedIds = [],
176
+ onSelectionChange,
177
+ sort = null,
178
+ onSortChange,
179
+ rowActions,
180
+ loading = false,
181
+ emptyState,
182
+ className
183
+ }) {
184
+ const lastClickedIndexRef = useRef(null);
185
+ const visibleColumns = useMemo(() => columns.filter((col) => !col.hidden), [columns]);
186
+ const tableColumns = useMemo(
187
+ () => visibleColumns.map((col) => ({
188
+ id: col.name,
189
+ accessorFn: (row) => row[col.name],
190
+ header: () => col.label ?? col.name,
191
+ cell: (info) => /* @__PURE__ */ jsx(TableCell, { column: col, value: info.getValue() }),
192
+ enableSorting: col.sortable
193
+ })),
194
+ [visibleColumns]
195
+ );
196
+ const table = useReactTable({
197
+ data: records,
198
+ columns: tableColumns,
199
+ getCoreRowModel: getCoreRowModel()
200
+ });
201
+ const allSelected = enableSelection && records.length > 0 && selectedIds.length === records.length;
202
+ const someSelected = enableSelection && selectedIds.length > 0 && selectedIds.length < records.length;
203
+ const toggleAll = useCallback(() => {
204
+ if (!onSelectionChange) return;
205
+ if (allSelected) onSelectionChange([]);
206
+ else onSelectionChange(records.map((r) => r.id));
207
+ }, [allSelected, records, onSelectionChange]);
208
+ const toggleRow = useCallback(
209
+ (id, index, shiftKey) => {
210
+ if (!onSelectionChange) return;
211
+ const set = new Set(selectedIds);
212
+ const lastIndex = lastClickedIndexRef.current;
213
+ if (shiftKey && lastIndex !== null) {
214
+ const [from, to] = lastIndex < index ? [lastIndex, index] : [index, lastIndex];
215
+ const shouldSelect = !set.has(id);
216
+ for (let i = from; i <= to; i++) {
217
+ const rowId = records[i]?.id;
218
+ if (rowId === void 0) continue;
219
+ if (shouldSelect) set.add(rowId);
220
+ else set.delete(rowId);
221
+ }
222
+ } else if (set.has(id)) {
223
+ set.delete(id);
224
+ } else {
225
+ set.add(id);
226
+ }
227
+ lastClickedIndexRef.current = index;
228
+ onSelectionChange(Array.from(set));
229
+ },
230
+ [records, selectedIds, onSelectionChange]
231
+ );
232
+ const headerSortDirection = (columnName) => {
233
+ if (!sort || sort.column !== columnName) return null;
234
+ return sort.direction === "desc" ? "desc" : "asc";
235
+ };
236
+ return /* @__PURE__ */ jsx("div", { className: cn("w-full overflow-x-auto", className), children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-sm", children: [
237
+ /* @__PURE__ */ jsx("thead", { className: "sticky top-0 bg-background", children: table.getHeaderGroups().map((group) => /* @__PURE__ */ jsxs("tr", { className: "border-b border-border", children: [
238
+ enableSelection && /* @__PURE__ */ jsx("th", { scope: "col", className: "w-10 px-3 py-2 text-left", children: /* @__PURE__ */ jsx(
239
+ "input",
240
+ {
241
+ type: "checkbox",
242
+ "aria-label": "Select all rows",
243
+ checked: allSelected,
244
+ ref: (el) => {
245
+ if (el) el.indeterminate = someSelected;
246
+ },
247
+ onChange: toggleAll
248
+ }
249
+ ) }),
250
+ group.headers.map((header) => {
251
+ const col = visibleColumns.find((c) => c.name === header.column.id);
252
+ const sortable = col?.sortable && onSortChange;
253
+ const direction = headerSortDirection(header.column.id);
254
+ return /* @__PURE__ */ jsx(
255
+ "th",
256
+ {
257
+ scope: "col",
258
+ className: cn(
259
+ "px-3 py-2 text-left font-medium text-muted-foreground",
260
+ col?.align === "center" && "text-center",
261
+ col?.align === "end" && "text-right"
262
+ ),
263
+ "aria-sort": direction === "asc" ? "ascending" : direction === "desc" ? "descending" : "none",
264
+ children: sortable ? /* @__PURE__ */ jsxs(
265
+ "button",
266
+ {
267
+ type: "button",
268
+ className: "inline-flex items-center gap-1 hover:text-foreground",
269
+ onClick: () => onSortChange(header.column.id, direction === "asc" ? "desc" : "asc"),
270
+ children: [
271
+ flexRender(header.column.columnDef.header, header.getContext()),
272
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: direction === "asc" ? "\u25B2" : direction === "desc" ? "\u25BC" : "\u2195" })
273
+ ]
274
+ }
275
+ ) : flexRender(header.column.columnDef.header, header.getContext())
276
+ },
277
+ header.id
278
+ );
279
+ }),
280
+ rowActions && /* @__PURE__ */ jsx("th", { scope: "col", className: "w-24 px-3 py-2 text-right", "aria-label": "Actions" })
281
+ ] }, group.id)) }),
282
+ /* @__PURE__ */ jsxs("tbody", { children: [
283
+ loading && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
284
+ "td",
285
+ {
286
+ colSpan: visibleColumns.length + (enableSelection ? 1 : 0) + (rowActions ? 1 : 0),
287
+ className: "px-3 py-4 text-center text-muted-foreground",
288
+ children: "Loading\u2026"
289
+ }
290
+ ) }),
291
+ !loading && records.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
292
+ "td",
293
+ {
294
+ colSpan: visibleColumns.length + (enableSelection ? 1 : 0) + (rowActions ? 1 : 0),
295
+ className: "px-3 py-8 text-center text-muted-foreground",
296
+ children: emptyState ?? "No records found."
297
+ }
298
+ ) }),
299
+ !loading && table.getRowModel().rows.map((row, index) => {
300
+ const record = row.original;
301
+ const checked = selectedIds.includes(record.id);
302
+ return /* @__PURE__ */ jsxs(
303
+ "tr",
304
+ {
305
+ "data-selected": checked || void 0,
306
+ className: cn("border-b border-border", checked && "bg-muted"),
307
+ children: [
308
+ enableSelection && /* @__PURE__ */ jsx("td", { className: "w-10 px-3 py-2", children: /* @__PURE__ */ jsx(
309
+ "input",
310
+ {
311
+ type: "checkbox",
312
+ "aria-label": `Select row ${record.id}`,
313
+ checked,
314
+ onChange: (event) => {
315
+ const native = event.nativeEvent;
316
+ toggleRow(record.id, index, native.shiftKey === true);
317
+ }
318
+ }
319
+ ) }),
320
+ row.getVisibleCells().map((cell) => {
321
+ const col = visibleColumns.find((c) => c.name === cell.column.id);
322
+ return /* @__PURE__ */ jsx(
323
+ "td",
324
+ {
325
+ className: cn(
326
+ "px-3 py-2",
327
+ col?.align === "center" && "text-center",
328
+ col?.align === "end" && "text-right",
329
+ col?.hiddenOnMobile && "hidden md:table-cell"
330
+ ),
331
+ children: flexRender(cell.column.columnDef.cell, cell.getContext())
332
+ },
333
+ cell.id
334
+ );
335
+ }),
336
+ rowActions && /* @__PURE__ */ jsx("td", { className: "w-24 px-3 py-2 text-right", children: rowActions(record) })
337
+ ]
338
+ },
339
+ row.id
340
+ );
341
+ })
342
+ ] })
343
+ ] }) });
344
+ }
345
+ function TableFilters({
346
+ filters,
347
+ values,
348
+ onChange,
349
+ onClearAll,
350
+ className
351
+ }) {
352
+ if (filters.length === 0) return null;
353
+ const activeCount = filters.reduce((acc, f) => {
354
+ const v = values[f.name];
355
+ return v !== void 0 && v !== null && v !== "" ? acc + 1 : acc;
356
+ }, 0);
357
+ return /* @__PURE__ */ jsxs("fieldset", { className: cn("flex flex-wrap items-end gap-2 border-0 p-0", className), children: [
358
+ /* @__PURE__ */ jsx("legend", { className: "sr-only", children: "Filters" }),
359
+ filters.map((filter) => /* @__PURE__ */ jsx(
360
+ FilterControl,
361
+ {
362
+ filter,
363
+ value: values[filter.name],
364
+ onChange: (v) => onChange(filter.name, v)
365
+ },
366
+ filter.name
367
+ )),
368
+ activeCount > 0 && onClearAll && /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: onClearAll, children: [
369
+ "Clear filters (",
370
+ activeCount,
371
+ ")"
372
+ ] })
373
+ ] });
374
+ }
375
+ function FilterControl({
376
+ filter,
377
+ value,
378
+ onChange
379
+ }) {
380
+ switch (filter.type) {
381
+ case "select":
382
+ return /* @__PURE__ */ jsx(SelectFilter, { filter, value, onChange });
383
+ case "multiSelect":
384
+ return /* @__PURE__ */ jsx(MultiSelectFilter, { filter, value, onChange });
385
+ case "text":
386
+ return /* @__PURE__ */ jsx(TextFilter, { filter, value, onChange });
387
+ case "ternary":
388
+ return /* @__PURE__ */ jsx(TernaryFilter, { filter, value, onChange });
389
+ case "dateRange":
390
+ case "scope":
391
+ return null;
392
+ }
393
+ }
394
+ function controlClasses() {
395
+ return cn(
396
+ "h-9 rounded-sm border border-[var(--input)]",
397
+ "bg-background px-3 text-sm",
398
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
399
+ );
400
+ }
401
+ function SelectFilter({
402
+ filter,
403
+ value,
404
+ onChange
405
+ }) {
406
+ return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1 text-xs text-muted-foreground", children: [
407
+ filter.label ?? filter.name,
408
+ /* @__PURE__ */ jsxs(
409
+ "select",
410
+ {
411
+ className: controlClasses(),
412
+ value: value === void 0 || value === null ? "" : String(value),
413
+ onChange: (e) => onChange(e.target.value === "" ? null : e.target.value),
414
+ children: [
415
+ /* @__PURE__ */ jsx("option", { value: "", children: "All" }),
416
+ filter.props.options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
417
+ ]
418
+ }
419
+ )
420
+ ] });
421
+ }
422
+ function MultiSelectFilter({
423
+ filter,
424
+ value,
425
+ onChange
426
+ }) {
427
+ const arr = Array.isArray(value) ? value : [];
428
+ return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1 text-xs text-muted-foreground", children: [
429
+ filter.label ?? filter.name,
430
+ /* @__PURE__ */ jsx(
431
+ "select",
432
+ {
433
+ multiple: true,
434
+ className: cn(controlClasses(), "h-auto min-h-[2.25rem] py-1"),
435
+ value: arr.map(String),
436
+ onChange: (e) => {
437
+ const next = Array.from(e.target.selectedOptions, (o) => o.value);
438
+ onChange(next.length === 0 ? null : next);
439
+ },
440
+ children: filter.props.options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
441
+ }
442
+ )
443
+ ] });
444
+ }
445
+ function TextFilter({
446
+ filter,
447
+ value,
448
+ onChange
449
+ }) {
450
+ return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1 text-xs text-muted-foreground", children: [
451
+ filter.label ?? filter.name,
452
+ /* @__PURE__ */ jsx(
453
+ "input",
454
+ {
455
+ type: "text",
456
+ className: controlClasses(),
457
+ value: typeof value === "string" ? value : "",
458
+ onChange: (e) => onChange(e.target.value === "" ? null : e.target.value)
459
+ }
460
+ )
461
+ ] });
462
+ }
463
+ function TernaryFilter({
464
+ filter,
465
+ value,
466
+ onChange
467
+ }) {
468
+ const current = value === void 0 || value === null ? "all" : String(value);
469
+ return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1 text-xs text-muted-foreground", children: [
470
+ filter.label ?? filter.name,
471
+ /* @__PURE__ */ jsxs(
472
+ "select",
473
+ {
474
+ className: controlClasses(),
475
+ value: current,
476
+ onChange: (e) => {
477
+ const v = e.target.value;
478
+ onChange(v === "all" ? null : v);
479
+ },
480
+ children: [
481
+ /* @__PURE__ */ jsx("option", { value: "all", children: filter.props.allLabel ?? "All" }),
482
+ /* @__PURE__ */ jsx("option", { value: "true", children: filter.props.trueLabel ?? "Yes" }),
483
+ /* @__PURE__ */ jsx("option", { value: "false", children: filter.props.falseLabel ?? "No" })
484
+ ]
485
+ }
486
+ )
487
+ ] });
488
+ }
489
+ function TablePagination({
490
+ meta,
491
+ onPageChange,
492
+ onPerPageChange,
493
+ perPageOptions = [10, 25, 50, 100],
494
+ className
495
+ }) {
496
+ const from = (meta.currentPage - 1) * meta.perPage + 1;
497
+ const to = Math.min(meta.currentPage * meta.perPage, meta.total);
498
+ const isFirst = meta.currentPage <= 1;
499
+ const isLast = meta.currentPage >= meta.lastPage;
500
+ return /* @__PURE__ */ jsxs(
501
+ "nav",
502
+ {
503
+ className: cn(
504
+ "flex flex-wrap items-center justify-between gap-2 border-t border-border px-3 py-2 text-sm",
505
+ className
506
+ ),
507
+ "aria-label": "Pagination",
508
+ children: [
509
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: meta.total === 0 ? "No results" : `${from}\u2013${to} of ${meta.total}` }),
510
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
511
+ onPerPageChange && /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
512
+ "Per page",
513
+ /* @__PURE__ */ jsx(
514
+ "select",
515
+ {
516
+ className: "h-8 rounded-sm border border-[var(--input)] bg-background px-2",
517
+ value: meta.perPage,
518
+ onChange: (e) => onPerPageChange(Number(e.target.value)),
519
+ children: perPageOptions.map((n) => /* @__PURE__ */ jsx("option", { value: n, children: n }, n))
520
+ }
521
+ )
522
+ ] }),
523
+ /* @__PURE__ */ jsx(
524
+ Button,
525
+ {
526
+ variant: "outline",
527
+ size: "sm",
528
+ disabled: isFirst,
529
+ onClick: () => onPageChange(meta.currentPage - 1),
530
+ "aria-label": "Previous page",
531
+ children: "Prev"
532
+ }
533
+ ),
534
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
535
+ meta.currentPage,
536
+ " / ",
537
+ meta.lastPage
538
+ ] }),
539
+ /* @__PURE__ */ jsx(
540
+ Button,
541
+ {
542
+ variant: "outline",
543
+ size: "sm",
544
+ disabled: isLast,
545
+ onClick: () => onPageChange(meta.currentPage + 1),
546
+ "aria-label": "Next page",
547
+ children: "Next"
548
+ }
549
+ )
550
+ ] })
551
+ ]
552
+ }
553
+ );
554
+ }
555
+ function TableToolbar({
556
+ search,
557
+ filters,
558
+ selectedCount = 0,
559
+ bulkActions,
560
+ onClearSelection,
561
+ className
562
+ }) {
563
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-3 px-3 py-3", className), children: [
564
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-end gap-2", children: [
565
+ search,
566
+ filters
567
+ ] }),
568
+ selectedCount > 0 && /* @__PURE__ */ jsxs(
569
+ "section",
570
+ {
571
+ className: "flex flex-wrap items-center gap-2 rounded-sm border border-border bg-muted px-3 py-2",
572
+ "aria-label": "Bulk actions",
573
+ children: [
574
+ /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium", children: [
575
+ selectedCount,
576
+ " selected"
577
+ ] }),
578
+ /* @__PURE__ */ jsxs("div", { className: "ml-auto flex flex-wrap items-center gap-2", children: [
579
+ bulkActions,
580
+ onClearSelection && /* @__PURE__ */ jsx(
581
+ "button",
582
+ {
583
+ type: "button",
584
+ className: "text-sm text-muted-foreground hover:underline",
585
+ onClick: onClearSelection,
586
+ children: "Clear"
587
+ }
588
+ )
589
+ ] })
590
+ ]
591
+ }
592
+ )
593
+ ] });
594
+ }
595
+
596
+ export { DataTable, TableCell, TableFilters, TablePagination, TableToolbar };
597
+ //# sourceMappingURL=chunk-PZEVKMZX.js.map
598
+ //# sourceMappingURL=chunk-PZEVKMZX.js.map