@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
package/dist/resource.js CHANGED
@@ -1,722 +1,7 @@
1
- import { useReactTable, getCoreRowModel, flexRender } from '@tanstack/react-table';
2
- import { useRef, useMemo, useCallback } from 'react';
3
- import { clsx } from 'clsx';
4
- import { twMerge } from 'tailwind-merge';
5
- import { jsxs, jsx } from 'react/jsx-runtime';
6
- import { cva } from 'class-variance-authority';
7
- import { Slot } from 'radix-ui';
8
-
9
- // src/table/DataTable.tsx
10
- function cn(...inputs) {
11
- return twMerge(clsx(inputs));
12
- }
13
- function TableCell({ column, value }) {
14
- switch (column.type) {
15
- case "text":
16
- return /* @__PURE__ */ jsx(TextCell, { column, value });
17
- case "badge":
18
- return /* @__PURE__ */ jsx(BadgeCell, { column, value });
19
- case "boolean":
20
- return /* @__PURE__ */ jsx(BooleanCell, { column, value });
21
- case "date":
22
- return /* @__PURE__ */ jsx(DateCell, { column, value });
23
- case "number":
24
- return /* @__PURE__ */ jsx(NumberCell, { column, value });
25
- case "icon":
26
- return /* @__PURE__ */ jsx(IconCell, { column });
27
- case "image":
28
- return /* @__PURE__ */ jsx(ImageCell, { column, value });
29
- case "relationship":
30
- return /* @__PURE__ */ jsx(RelationshipCell, { column, value });
31
- case "computed":
32
- return /* @__PURE__ */ jsx(ComputedCell, { column, value });
33
- }
34
- }
35
- function asString(value) {
36
- if (value === null || value === void 0) return "";
37
- if (typeof value === "string") return value;
38
- if (typeof value === "number" || typeof value === "boolean") return String(value);
39
- return JSON.stringify(value);
40
- }
41
- function TextCell({ column, value }) {
42
- const str = asString(value);
43
- const truncated = column.props.truncate && str.length > column.props.truncate ? `${str.slice(0, column.props.truncate)}\u2026` : str;
44
- return /* @__PURE__ */ jsx(
45
- "span",
46
- {
47
- className: cn(
48
- column.props.weight === "bold" && "font-bold",
49
- column.props.weight === "medium" && "font-medium"
50
- ),
51
- children: truncated
52
- }
53
- );
54
- }
55
- function BadgeCell({ column, value }) {
56
- const option = column.props.options?.find((o) => o.value === value);
57
- const label = option?.label ?? asString(value);
58
- return /* @__PURE__ */ jsx(
59
- "span",
60
- {
61
- className: cn(
62
- "inline-flex items-center px-2 py-0.5 text-xs",
63
- column.props.pill ? "rounded-full" : "rounded-sm",
64
- "bg-muted text-foreground"
65
- ),
66
- children: label
67
- }
68
- );
69
- }
70
- function BooleanCell({ column, value }) {
71
- const truthy = Boolean(value);
72
- return /* @__PURE__ */ jsx("span", { role: "img", "aria-label": truthy ? "true" : "false", children: truthy ? column.props.trueIcon ?? "\u2713" : column.props.falseIcon ?? "\u2014" });
73
- }
74
- function DateCell({ column, value }) {
75
- if (!value) return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" });
76
- const raw = String(value);
77
- const date = new Date(raw);
78
- if (Number.isNaN(date.getTime())) return /* @__PURE__ */ jsx("span", { children: raw });
79
- if (column.props.mode === "since") {
80
- return /* @__PURE__ */ jsx("time", { dateTime: date.toISOString(), children: formatRelative(date) });
81
- }
82
- if (column.props.mode === "datetime") {
83
- return /* @__PURE__ */ jsx("time", { dateTime: date.toISOString(), children: date.toLocaleString() });
84
- }
85
- return /* @__PURE__ */ jsx("time", { dateTime: date.toISOString(), children: date.toLocaleDateString() });
86
- }
87
- function formatRelative(date) {
88
- const seconds = Math.round((Date.now() - date.getTime()) / 1e3);
89
- if (seconds < 60) return `${seconds}s ago`;
90
- const minutes = Math.round(seconds / 60);
91
- if (minutes < 60) return `${minutes}m ago`;
92
- const hours = Math.round(minutes / 60);
93
- if (hours < 24) return `${hours}h ago`;
94
- const days = Math.round(hours / 24);
95
- return `${days}d ago`;
96
- }
97
- function NumberCell({ column, value }) {
98
- if (value === null || value === void 0) return /* @__PURE__ */ jsx("span", { children: "\u2014" });
99
- const num = typeof value === "number" ? value : Number(value);
100
- if (Number.isNaN(num)) return /* @__PURE__ */ jsx("span", { children: asString(value) });
101
- const formatted = num.toFixed(column.props.decimals ?? 0);
102
- const [whole, dec] = formatted.split(".");
103
- const safeWhole = whole ?? "0";
104
- const ts = column.props.thousandsSeparator;
105
- const finalWhole = ts ? safeWhole.replace(/\B(?=(\d{3})+(?!\d))/g, ts) : safeWhole;
106
- const ds = column.props.decimalSeparator ?? ".";
107
- return /* @__PURE__ */ jsxs("span", { children: [
108
- column.props.prefix ?? "",
109
- finalWhole,
110
- dec ? `${ds}${dec}` : "",
111
- column.props.suffix ?? ""
112
- ] });
113
- }
114
- function IconCell({ column }) {
115
- return /* @__PURE__ */ jsx("span", { role: "img", "aria-label": column.props.icon, title: column.props.icon, children: column.props.icon });
116
- }
117
- function ImageCell({ column, value }) {
118
- const src = asString(value);
119
- if (!src) return null;
120
- const size = column.props.size ?? 32;
121
- return /* @__PURE__ */ jsx(
122
- "img",
123
- {
124
- src,
125
- alt: "",
126
- style: { width: size, height: size },
127
- className: cn(column.props.shape === "circular" ? "rounded-full" : "rounded")
128
- }
129
- );
130
- }
131
- function RelationshipCell({ column, value }) {
132
- if (value === null || value === void 0) return /* @__PURE__ */ jsx("span", { children: "\u2014" });
133
- if (typeof value === "object") {
134
- const attr = value[column.props.attribute];
135
- return /* @__PURE__ */ jsx("span", { children: asString(attr) });
136
- }
137
- return /* @__PURE__ */ jsx("span", { children: asString(value) });
138
- }
139
- function ComputedCell({ column, value }) {
140
- if (value === null || value === void 0) {
141
- return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: column.props.placeholder ?? "\u2014" });
142
- }
143
- return /* @__PURE__ */ jsx("span", { children: asString(value) });
144
- }
145
- function DataTable({
146
- columns,
147
- records,
148
- enableSelection = false,
149
- selectedIds = [],
150
- onSelectionChange,
151
- sort = null,
152
- onSortChange,
153
- rowActions,
154
- loading = false,
155
- emptyState,
156
- className
157
- }) {
158
- const lastClickedIndexRef = useRef(null);
159
- const visibleColumns = useMemo(() => columns.filter((col) => !col.hidden), [columns]);
160
- const tableColumns = useMemo(
161
- () => visibleColumns.map((col) => ({
162
- id: col.name,
163
- accessorFn: (row) => row[col.name],
164
- header: () => col.label ?? col.name,
165
- cell: (info) => /* @__PURE__ */ jsx(TableCell, { column: col, value: info.getValue() }),
166
- enableSorting: col.sortable
167
- })),
168
- [visibleColumns]
169
- );
170
- const table = useReactTable({
171
- data: records,
172
- columns: tableColumns,
173
- getCoreRowModel: getCoreRowModel()
174
- });
175
- const allSelected = enableSelection && records.length > 0 && selectedIds.length === records.length;
176
- const someSelected = enableSelection && selectedIds.length > 0 && selectedIds.length < records.length;
177
- const toggleAll = useCallback(() => {
178
- if (!onSelectionChange) return;
179
- if (allSelected) onSelectionChange([]);
180
- else onSelectionChange(records.map((r) => r.id));
181
- }, [allSelected, records, onSelectionChange]);
182
- const toggleRow = useCallback(
183
- (id, index, shiftKey) => {
184
- if (!onSelectionChange) return;
185
- const set = new Set(selectedIds);
186
- const lastIndex = lastClickedIndexRef.current;
187
- if (shiftKey && lastIndex !== null) {
188
- const [from, to] = lastIndex < index ? [lastIndex, index] : [index, lastIndex];
189
- const shouldSelect = !set.has(id);
190
- for (let i = from; i <= to; i++) {
191
- const rowId = records[i]?.id;
192
- if (rowId === void 0) continue;
193
- if (shouldSelect) set.add(rowId);
194
- else set.delete(rowId);
195
- }
196
- } else if (set.has(id)) {
197
- set.delete(id);
198
- } else {
199
- set.add(id);
200
- }
201
- lastClickedIndexRef.current = index;
202
- onSelectionChange(Array.from(set));
203
- },
204
- [records, selectedIds, onSelectionChange]
205
- );
206
- const headerSortDirection = (columnName) => {
207
- if (!sort || sort.column !== columnName) return null;
208
- return sort.direction === "desc" ? "desc" : "asc";
209
- };
210
- return /* @__PURE__ */ jsx("div", { className: cn("w-full overflow-x-auto", className), children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-sm", children: [
211
- /* @__PURE__ */ jsx("thead", { className: "sticky top-0 bg-background", children: table.getHeaderGroups().map((group) => /* @__PURE__ */ jsxs("tr", { className: "border-b border-border", children: [
212
- enableSelection && /* @__PURE__ */ jsx("th", { scope: "col", className: "w-10 px-3 py-2 text-left", children: /* @__PURE__ */ jsx(
213
- "input",
214
- {
215
- type: "checkbox",
216
- "aria-label": "Select all rows",
217
- checked: allSelected,
218
- ref: (el) => {
219
- if (el) el.indeterminate = someSelected;
220
- },
221
- onChange: toggleAll
222
- }
223
- ) }),
224
- group.headers.map((header) => {
225
- const col = visibleColumns.find((c) => c.name === header.column.id);
226
- const sortable = col?.sortable && onSortChange;
227
- const direction = headerSortDirection(header.column.id);
228
- return /* @__PURE__ */ jsx(
229
- "th",
230
- {
231
- scope: "col",
232
- className: cn(
233
- "px-3 py-2 text-left font-medium text-muted-foreground",
234
- col?.align === "center" && "text-center",
235
- col?.align === "end" && "text-right"
236
- ),
237
- "aria-sort": direction === "asc" ? "ascending" : direction === "desc" ? "descending" : "none",
238
- children: sortable ? /* @__PURE__ */ jsxs(
239
- "button",
240
- {
241
- type: "button",
242
- className: "inline-flex items-center gap-1 hover:text-foreground",
243
- onClick: () => onSortChange(header.column.id, direction === "asc" ? "desc" : "asc"),
244
- children: [
245
- flexRender(header.column.columnDef.header, header.getContext()),
246
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: direction === "asc" ? "\u25B2" : direction === "desc" ? "\u25BC" : "\u2195" })
247
- ]
248
- }
249
- ) : flexRender(header.column.columnDef.header, header.getContext())
250
- },
251
- header.id
252
- );
253
- }),
254
- rowActions && /* @__PURE__ */ jsx("th", { scope: "col", className: "w-24 px-3 py-2 text-right", "aria-label": "Actions" })
255
- ] }, group.id)) }),
256
- /* @__PURE__ */ jsxs("tbody", { children: [
257
- loading && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
258
- "td",
259
- {
260
- colSpan: visibleColumns.length + (enableSelection ? 1 : 0) + (rowActions ? 1 : 0),
261
- className: "px-3 py-4 text-center text-muted-foreground",
262
- children: "Loading\u2026"
263
- }
264
- ) }),
265
- !loading && records.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
266
- "td",
267
- {
268
- colSpan: visibleColumns.length + (enableSelection ? 1 : 0) + (rowActions ? 1 : 0),
269
- className: "px-3 py-8 text-center text-muted-foreground",
270
- children: emptyState ?? "No records found."
271
- }
272
- ) }),
273
- !loading && table.getRowModel().rows.map((row, index) => {
274
- const record = row.original;
275
- const checked = selectedIds.includes(record.id);
276
- return /* @__PURE__ */ jsxs(
277
- "tr",
278
- {
279
- "data-selected": checked || void 0,
280
- className: cn("border-b border-border", checked && "bg-muted"),
281
- children: [
282
- enableSelection && /* @__PURE__ */ jsx("td", { className: "w-10 px-3 py-2", children: /* @__PURE__ */ jsx(
283
- "input",
284
- {
285
- type: "checkbox",
286
- "aria-label": `Select row ${record.id}`,
287
- checked,
288
- onChange: (event) => {
289
- const native = event.nativeEvent;
290
- toggleRow(record.id, index, native.shiftKey === true);
291
- }
292
- }
293
- ) }),
294
- row.getVisibleCells().map((cell) => {
295
- const col = visibleColumns.find((c) => c.name === cell.column.id);
296
- return /* @__PURE__ */ jsx(
297
- "td",
298
- {
299
- className: cn(
300
- "px-3 py-2",
301
- col?.align === "center" && "text-center",
302
- col?.align === "end" && "text-right",
303
- col?.hiddenOnMobile && "hidden md:table-cell"
304
- ),
305
- children: flexRender(cell.column.columnDef.cell, cell.getContext())
306
- },
307
- cell.id
308
- );
309
- }),
310
- rowActions && /* @__PURE__ */ jsx("td", { className: "w-24 px-3 py-2 text-right", children: rowActions(record) })
311
- ]
312
- },
313
- row.id
314
- );
315
- })
316
- ] })
317
- ] }) });
318
- }
319
- var buttonVariants = cva(
320
- "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
321
- {
322
- variants: {
323
- variant: {
324
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
325
- destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
326
- outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
327
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
328
- ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
329
- link: "text-primary underline-offset-4 hover:underline"
330
- },
331
- size: {
332
- default: "h-9 px-4 py-2 has-[>svg]:px-3",
333
- xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
334
- sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
335
- lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
336
- icon: "size-9",
337
- "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
338
- "icon-sm": "size-8",
339
- "icon-lg": "size-10"
340
- }
341
- },
342
- defaultVariants: {
343
- variant: "default",
344
- size: "default"
345
- }
346
- }
347
- );
348
- function Button({
349
- className,
350
- variant = "default",
351
- size = "default",
352
- asChild = false,
353
- ...props
354
- }) {
355
- const Comp = asChild ? Slot.Root : "button";
356
- return /* @__PURE__ */ jsx(
357
- Comp,
358
- {
359
- "data-slot": "button",
360
- "data-variant": variant,
361
- "data-size": size,
362
- className: cn(buttonVariants({ variant, size, className })),
363
- ...props
364
- }
365
- );
366
- }
367
- function TableFilters({
368
- filters,
369
- values,
370
- onChange,
371
- onClearAll,
372
- className
373
- }) {
374
- if (filters.length === 0) return null;
375
- const activeCount = filters.reduce((acc, f) => {
376
- const v = values[f.name];
377
- return v !== void 0 && v !== null && v !== "" ? acc + 1 : acc;
378
- }, 0);
379
- return /* @__PURE__ */ jsxs("fieldset", { className: cn("flex flex-wrap items-end gap-2 border-0 p-0", className), children: [
380
- /* @__PURE__ */ jsx("legend", { className: "sr-only", children: "Filters" }),
381
- filters.map((filter) => /* @__PURE__ */ jsx(
382
- FilterControl,
383
- {
384
- filter,
385
- value: values[filter.name],
386
- onChange: (v) => onChange(filter.name, v)
387
- },
388
- filter.name
389
- )),
390
- activeCount > 0 && onClearAll && /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: onClearAll, children: [
391
- "Clear filters (",
392
- activeCount,
393
- ")"
394
- ] })
395
- ] });
396
- }
397
- function FilterControl({
398
- filter,
399
- value,
400
- onChange
401
- }) {
402
- switch (filter.type) {
403
- case "select":
404
- return /* @__PURE__ */ jsx(SelectFilter, { filter, value, onChange });
405
- case "multiSelect":
406
- return /* @__PURE__ */ jsx(MultiSelectFilter, { filter, value, onChange });
407
- case "text":
408
- return /* @__PURE__ */ jsx(TextFilter, { filter, value, onChange });
409
- case "ternary":
410
- return /* @__PURE__ */ jsx(TernaryFilter, { filter, value, onChange });
411
- case "dateRange":
412
- case "scope":
413
- return null;
414
- }
415
- }
416
- function controlClasses() {
417
- return cn(
418
- "h-9 rounded-sm border border-[var(--input)]",
419
- "bg-background px-3 text-sm",
420
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
421
- );
422
- }
423
- function SelectFilter({
424
- filter,
425
- value,
426
- onChange
427
- }) {
428
- return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1 text-xs text-muted-foreground", children: [
429
- filter.label ?? filter.name,
430
- /* @__PURE__ */ jsxs(
431
- "select",
432
- {
433
- className: controlClasses(),
434
- value: value === void 0 || value === null ? "" : String(value),
435
- onChange: (e) => onChange(e.target.value === "" ? null : e.target.value),
436
- children: [
437
- /* @__PURE__ */ jsx("option", { value: "", children: "All" }),
438
- filter.props.options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
439
- ]
440
- }
441
- )
442
- ] });
443
- }
444
- function MultiSelectFilter({
445
- filter,
446
- value,
447
- onChange
448
- }) {
449
- const arr = Array.isArray(value) ? value : [];
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
- "select",
454
- {
455
- multiple: true,
456
- className: cn(controlClasses(), "h-auto min-h-[2.25rem] py-1"),
457
- value: arr.map(String),
458
- onChange: (e) => {
459
- const next = Array.from(e.target.selectedOptions, (o) => o.value);
460
- onChange(next.length === 0 ? null : next);
461
- },
462
- children: filter.props.options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
463
- }
464
- )
465
- ] });
466
- }
467
- function TextFilter({
468
- filter,
469
- value,
470
- onChange
471
- }) {
472
- return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1 text-xs text-muted-foreground", children: [
473
- filter.label ?? filter.name,
474
- /* @__PURE__ */ jsx(
475
- "input",
476
- {
477
- type: "text",
478
- className: controlClasses(),
479
- value: typeof value === "string" ? value : "",
480
- onChange: (e) => onChange(e.target.value === "" ? null : e.target.value)
481
- }
482
- )
483
- ] });
484
- }
485
- function TernaryFilter({
486
- filter,
487
- value,
488
- onChange
489
- }) {
490
- const current = value === void 0 || value === null ? "all" : String(value);
491
- return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1 text-xs text-muted-foreground", children: [
492
- filter.label ?? filter.name,
493
- /* @__PURE__ */ jsxs(
494
- "select",
495
- {
496
- className: controlClasses(),
497
- value: current,
498
- onChange: (e) => {
499
- const v = e.target.value;
500
- onChange(v === "all" ? null : v);
501
- },
502
- children: [
503
- /* @__PURE__ */ jsx("option", { value: "all", children: filter.props.allLabel ?? "All" }),
504
- /* @__PURE__ */ jsx("option", { value: "true", children: filter.props.trueLabel ?? "Yes" }),
505
- /* @__PURE__ */ jsx("option", { value: "false", children: filter.props.falseLabel ?? "No" })
506
- ]
507
- }
508
- )
509
- ] });
510
- }
511
- function TablePagination({
512
- meta,
513
- onPageChange,
514
- onPerPageChange,
515
- perPageOptions = [10, 25, 50, 100],
516
- className
517
- }) {
518
- const from = (meta.currentPage - 1) * meta.perPage + 1;
519
- const to = Math.min(meta.currentPage * meta.perPage, meta.total);
520
- const isFirst = meta.currentPage <= 1;
521
- const isLast = meta.currentPage >= meta.lastPage;
522
- return /* @__PURE__ */ jsxs(
523
- "nav",
524
- {
525
- className: cn(
526
- "flex flex-wrap items-center justify-between gap-2 border-t border-border px-3 py-2 text-sm",
527
- className
528
- ),
529
- "aria-label": "Pagination",
530
- children: [
531
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: meta.total === 0 ? "No results" : `${from}\u2013${to} of ${meta.total}` }),
532
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
533
- onPerPageChange && /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
534
- "Per page",
535
- /* @__PURE__ */ jsx(
536
- "select",
537
- {
538
- className: "h-8 rounded-sm border border-[var(--input)] bg-background px-2",
539
- value: meta.perPage,
540
- onChange: (e) => onPerPageChange(Number(e.target.value)),
541
- children: perPageOptions.map((n) => /* @__PURE__ */ jsx("option", { value: n, children: n }, n))
542
- }
543
- )
544
- ] }),
545
- /* @__PURE__ */ jsx(
546
- Button,
547
- {
548
- variant: "outline",
549
- size: "sm",
550
- disabled: isFirst,
551
- onClick: () => onPageChange(meta.currentPage - 1),
552
- "aria-label": "Previous page",
553
- children: "Prev"
554
- }
555
- ),
556
- /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
557
- meta.currentPage,
558
- " / ",
559
- meta.lastPage
560
- ] }),
561
- /* @__PURE__ */ jsx(
562
- Button,
563
- {
564
- variant: "outline",
565
- size: "sm",
566
- disabled: isLast,
567
- onClick: () => onPageChange(meta.currentPage + 1),
568
- "aria-label": "Next page",
569
- children: "Next"
570
- }
571
- )
572
- ] })
573
- ]
574
- }
575
- );
576
- }
577
- function TableToolbar({
578
- search,
579
- filters,
580
- selectedCount = 0,
581
- bulkActions,
582
- onClearSelection,
583
- className
584
- }) {
585
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-3 px-3 py-3", className), children: [
586
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-end gap-2", children: [
587
- search,
588
- filters
589
- ] }),
590
- selectedCount > 0 && /* @__PURE__ */ jsxs(
591
- "section",
592
- {
593
- className: "flex flex-wrap items-center gap-2 rounded-sm border border-border bg-muted px-3 py-2",
594
- "aria-label": "Bulk actions",
595
- children: [
596
- /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium", children: [
597
- selectedCount,
598
- " selected"
599
- ] }),
600
- /* @__PURE__ */ jsxs("div", { className: "ml-auto flex flex-wrap items-center gap-2", children: [
601
- bulkActions,
602
- onClearSelection && /* @__PURE__ */ jsx(
603
- "button",
604
- {
605
- type: "button",
606
- className: "text-sm text-muted-foreground hover:underline",
607
- onClick: onClearSelection,
608
- children: "Clear"
609
- }
610
- )
611
- ] })
612
- ]
613
- }
614
- )
615
- ] });
616
- }
617
- function ResourceIndex({
618
- resource,
619
- records,
620
- pagination,
621
- columns,
622
- filters,
623
- search,
624
- sort,
625
- selectedIds = [],
626
- filterValues = {},
627
- onSelectionChange,
628
- onSortChange,
629
- onPageChange,
630
- onPerPageChange,
631
- onSearchChange,
632
- onFilterChange,
633
- onClearFilters,
634
- searchSlot,
635
- toolbarActions,
636
- rowActions,
637
- bulkActions,
638
- emptyState,
639
- loading = false,
640
- className
641
- }) {
642
- const enableSelection = Boolean(onSelectionChange);
643
- const renderSearch = () => {
644
- if (searchSlot) return searchSlot;
645
- if (!onSearchChange) return null;
646
- return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1 text-xs text-muted-foreground", children: [
647
- "Search",
648
- /* @__PURE__ */ jsx(
649
- "input",
650
- {
651
- type: "search",
652
- placeholder: `Search ${resource.pluralLabel.toLowerCase()}\u2026`,
653
- className: "h-9 w-64 rounded-sm border border-[var(--input)] bg-background px-3 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
654
- value: search ?? "",
655
- onChange: (e) => onSearchChange(e.target.value)
656
- }
657
- )
658
- ] });
659
- };
660
- const normalisedSort = sort?.column ? {
661
- column: sort.column,
662
- direction: sort.direction === "desc" ? "desc" : "asc"
663
- } : null;
664
- return /* @__PURE__ */ jsxs(
665
- "section",
666
- {
667
- className: cn("flex flex-col rounded-md border border-border bg-background", className),
668
- "aria-label": resource.pluralLabel,
669
- children: [
670
- /* @__PURE__ */ jsxs("header", { className: "flex flex-wrap items-center gap-3 border-b border-border px-4 py-3", children: [
671
- /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold", children: resource.pluralLabel }),
672
- /* @__PURE__ */ jsx("div", { className: "ml-auto flex flex-wrap items-center gap-2", children: toolbarActions })
673
- ] }),
674
- /* @__PURE__ */ jsx(
675
- TableToolbar,
676
- {
677
- search: renderSearch(),
678
- filters: filters.length > 0 ? /* @__PURE__ */ jsx(
679
- TableFilters,
680
- {
681
- filters,
682
- values: filterValues,
683
- onChange: (name, value) => onFilterChange?.(name, value),
684
- onClearAll: onClearFilters
685
- }
686
- ) : null,
687
- selectedCount: selectedIds.length,
688
- bulkActions,
689
- onClearSelection: onSelectionChange ? () => onSelectionChange([]) : void 0
690
- }
691
- ),
692
- /* @__PURE__ */ jsx(
693
- DataTable,
694
- {
695
- columns,
696
- records,
697
- enableSelection,
698
- selectedIds,
699
- onSelectionChange,
700
- sort: normalisedSort,
701
- onSortChange,
702
- rowActions: rowActions ? (record) => rowActions(record) : void 0,
703
- loading,
704
- emptyState
705
- }
706
- ),
707
- pagination && /* @__PURE__ */ jsx(
708
- TablePagination,
709
- {
710
- meta: pagination,
711
- onPageChange: (page) => onPageChange?.(page),
712
- onPerPageChange
713
- }
714
- )
715
- ]
716
- }
717
- );
718
- }
719
-
720
- export { ResourceIndex };
1
+ export { ResourceIndex } from './chunk-2LTZJ4R7.js';
2
+ import './chunk-PZEVKMZX.js';
3
+ import './chunk-RMPOR2YZ.js';
4
+ import './chunk-FHRQ7PWE.js';
5
+ import './chunk-B7ULUJVO.js';
721
6
  //# sourceMappingURL=resource.js.map
722
7
  //# sourceMappingURL=resource.js.map