@arqel-dev/ui 0.14.0 → 0.15.1
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/README.md +1 -1
- package/dist/{AreaChart-NMQ2RQGA.js → AreaChart-JAZ6LUYG.js} +8 -4
- package/dist/AreaChart-JAZ6LUYG.js.map +1 -0
- package/dist/ArqelCreatePage-UZAHV4DK.js +8 -0
- package/dist/{ArqelCreatePage-O6KNXPAO.js.map → ArqelCreatePage-UZAHV4DK.js.map} +1 -1
- package/dist/ArqelDashboardPage-Z5R4XSH4.js +6 -0
- package/dist/{ArqelDashboardPage-PX3Y75AA.js.map → ArqelDashboardPage-Z5R4XSH4.js.map} +1 -1
- package/dist/ArqelEditPage-RRYFYOTC.js +8 -0
- package/dist/{ArqelShowPage-LGVTL6UZ.js.map → ArqelEditPage-RRYFYOTC.js.map} +1 -1
- package/dist/ArqelIndexPage-RGZWKKAX.js +12 -0
- package/dist/{ArqelIndexPage-GC33PNBL.js.map → ArqelIndexPage-RGZWKKAX.js.map} +1 -1
- package/dist/ArqelShowPage-TVCJAV2F.js +6 -0
- package/dist/{ArqelEditPage-NAMWJ5MC.js.map → ArqelShowPage-TVCJAV2F.js.map} +1 -1
- package/dist/{BarChart-KLHKTLO2.js → BarChart-E52NJSJE.js} +8 -4
- package/dist/BarChart-E52NJSJE.js.map +1 -0
- package/dist/{DonutChart-L56R4QF2.js → DonutChart-IGSF4LEB.js} +3 -3
- package/dist/{DonutChart-L56R4QF2.js.map → DonutChart-IGSF4LEB.js.map} +1 -1
- package/dist/{FormRenderer-BJBRIkfH.d.ts → FormRenderer-By8fZp4t.d.ts} +2 -0
- package/dist/{LineChart-GHMPHFZZ.js → LineChart-RRPGAZON.js} +8 -4
- package/dist/LineChart-RRPGAZON.js.map +1 -0
- package/dist/PieChart-SGN7V5LQ.js +4 -0
- package/dist/{PieChart-T2VQOFPP.js.map → PieChart-SGN7V5LQ.js.map} +1 -1
- package/dist/{RadarChart-CSWR5AO7.js → RadarChart-3AOM736J.js} +8 -4
- package/dist/RadarChart-3AOM736J.js.map +1 -0
- package/dist/action.d.ts +1 -1
- package/dist/action.js +5 -5
- package/dist/{chunk-IKJYLSTK.js → chunk-2JUWLJ3K.js} +90 -29
- package/dist/chunk-2JUWLJ3K.js.map +1 -0
- package/dist/chunk-3HN4ARGG.js +157 -0
- package/dist/chunk-3HN4ARGG.js.map +1 -0
- package/dist/{chunk-PXON56HL.js → chunk-3VSDQCFO.js} +3 -3
- package/dist/{chunk-PXON56HL.js.map → chunk-3VSDQCFO.js.map} +1 -1
- package/dist/{chunk-6UJQP7KU.js → chunk-4VWNBMMA.js} +34 -118
- package/dist/chunk-4VWNBMMA.js.map +1 -0
- package/dist/{chunk-4JJS2SVS.js → chunk-CMNZLA32.js} +83 -32
- package/dist/chunk-CMNZLA32.js.map +1 -0
- package/dist/{chunk-2LTZJ4R7.js → chunk-EG2DASKR.js} +16 -7
- package/dist/chunk-EG2DASKR.js.map +1 -0
- package/dist/{chunk-DSULVRB6.js → chunk-GJ2FKAOM.js} +5 -3
- package/dist/chunk-GJ2FKAOM.js.map +1 -0
- package/dist/{chunk-FHRQ7PWE.js → chunk-H23VX3RR.js} +4 -3
- package/dist/chunk-H23VX3RR.js.map +1 -0
- package/dist/{chunk-FV7RESKL.js → chunk-HNUUZEOL.js} +28 -16
- package/dist/chunk-HNUUZEOL.js.map +1 -0
- package/dist/{chunk-M6NI45DQ.js → chunk-IO6RMVUF.js} +9 -5
- package/dist/chunk-IO6RMVUF.js.map +1 -0
- package/dist/{chunk-I6MWOIFR.js → chunk-LLANMODS.js} +6 -5
- package/dist/chunk-LLANMODS.js.map +1 -0
- package/dist/{chunk-MTZJDFQ6.js → chunk-MZMYV43C.js} +11 -7
- package/dist/chunk-MZMYV43C.js.map +1 -0
- package/dist/{chunk-E2ORVQM5.js → chunk-Q7WGPKUN.js} +6 -4
- package/dist/chunk-Q7WGPKUN.js.map +1 -0
- package/dist/{chunk-PZEVKMZX.js → chunk-S5UNPCMQ.js} +315 -152
- package/dist/chunk-S5UNPCMQ.js.map +1 -0
- package/dist/{chunk-MTNFFSVA.js → chunk-SK6H7ARE.js} +5 -3
- package/dist/chunk-SK6H7ARE.js.map +1 -0
- package/dist/{chunk-WKWV36PG.js → chunk-WMOBLT3Z.js} +12 -5
- package/dist/chunk-WMOBLT3Z.js.map +1 -0
- package/dist/{chunk-C5H44NSP.js → chunk-WZRPGPLH.js} +10 -5
- package/dist/chunk-WZRPGPLH.js.map +1 -0
- package/dist/{chunk-QTUBBZVT.js → chunk-YQ6KXR3U.js} +9 -11
- package/dist/chunk-YQ6KXR3U.js.map +1 -0
- package/dist/{chunk-47HD7ALI.js → chunk-YYQ45W25.js} +37 -24
- package/dist/chunk-YYQ45W25.js.map +1 -0
- package/dist/flash.js +1 -1
- package/dist/form.d.ts +3 -1
- package/dist/form.js +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +12 -12
- package/dist/pages.js +19 -19
- package/dist/palette.js +1 -1
- package/dist/resource.js +3 -3
- package/dist/shell.js +10 -6
- package/dist/shell.js.map +1 -1
- package/dist/table.js +2 -2
- package/dist/utility.js +1 -1
- package/dist/widgets.js +2 -2
- package/package.json +6 -6
- package/src/styles/globals.css +7 -0
- package/dist/AreaChart-NMQ2RQGA.js.map +0 -1
- package/dist/ArqelCreatePage-O6KNXPAO.js +0 -8
- package/dist/ArqelDashboardPage-PX3Y75AA.js +0 -6
- package/dist/ArqelEditPage-NAMWJ5MC.js +0 -8
- package/dist/ArqelIndexPage-GC33PNBL.js +0 -12
- package/dist/ArqelShowPage-LGVTL6UZ.js +0 -6
- package/dist/BarChart-KLHKTLO2.js.map +0 -1
- package/dist/LineChart-GHMPHFZZ.js.map +0 -1
- package/dist/PieChart-T2VQOFPP.js +0 -4
- package/dist/RadarChart-CSWR5AO7.js.map +0 -1
- package/dist/chunk-2LTZJ4R7.js.map +0 -1
- package/dist/chunk-47HD7ALI.js.map +0 -1
- package/dist/chunk-4JJS2SVS.js.map +0 -1
- package/dist/chunk-6UJQP7KU.js.map +0 -1
- package/dist/chunk-C5H44NSP.js.map +0 -1
- package/dist/chunk-DSULVRB6.js.map +0 -1
- package/dist/chunk-E2ORVQM5.js.map +0 -1
- package/dist/chunk-EYAUPJ6J.js +0 -64
- package/dist/chunk-EYAUPJ6J.js.map +0 -1
- package/dist/chunk-FHRQ7PWE.js.map +0 -1
- package/dist/chunk-FV7RESKL.js.map +0 -1
- package/dist/chunk-I6MWOIFR.js.map +0 -1
- package/dist/chunk-IKJYLSTK.js.map +0 -1
- package/dist/chunk-M6NI45DQ.js.map +0 -1
- package/dist/chunk-MTNFFSVA.js.map +0 -1
- package/dist/chunk-MTZJDFQ6.js.map +0 -1
- package/dist/chunk-PZEVKMZX.js.map +0 -1
- package/dist/chunk-QTUBBZVT.js.map +0 -1
- package/dist/chunk-WKWV36PG.js.map +0 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { resolveLucideIcon } from './chunk-RMPOR2YZ.js';
|
|
2
|
-
import { Button } from './chunk-
|
|
2
|
+
import { Button } from './chunk-H23VX3RR.js';
|
|
3
3
|
import { cn } from './chunk-B7ULUJVO.js';
|
|
4
|
-
import {
|
|
4
|
+
import { useArqelTranslations, useArqelLocale } from '@arqel-dev/react/utils';
|
|
5
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
6
|
import { useReactTable, getCoreRowModel, flexRender } from '@tanstack/react-table';
|
|
6
7
|
import { useRef, useMemo, useCallback } from 'react';
|
|
7
8
|
|
|
@@ -94,46 +95,93 @@ function BadgeCell({ column, value }) {
|
|
|
94
95
|
);
|
|
95
96
|
}
|
|
96
97
|
function BooleanCell({ column, value }) {
|
|
98
|
+
const t = useArqelTranslations();
|
|
97
99
|
const truthy = Boolean(value);
|
|
98
|
-
|
|
100
|
+
const ariaLabel = truthy ? t("table.boolean.true_label", "true") : t("table.boolean.false_label", "false");
|
|
101
|
+
return /* @__PURE__ */ jsx("span", { role: "img", "aria-label": ariaLabel, children: truthy ? column.props.trueIcon ?? "\u2713" : column.props.falseIcon ?? "\u2014" });
|
|
99
102
|
}
|
|
100
103
|
function DateCell({ column, value }) {
|
|
104
|
+
const locale = useArqelLocale();
|
|
101
105
|
if (!value) return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" });
|
|
102
106
|
const raw = String(value);
|
|
103
107
|
const date = new Date(raw);
|
|
104
108
|
if (Number.isNaN(date.getTime())) return /* @__PURE__ */ jsx("span", { children: raw });
|
|
109
|
+
const timeZone = column.props.timezone || void 0;
|
|
105
110
|
if (column.props.mode === "since") {
|
|
106
|
-
return /* @__PURE__ */ jsx("time", { dateTime: date.toISOString(), children: formatRelative(date) });
|
|
111
|
+
return /* @__PURE__ */ jsx("time", { dateTime: date.toISOString(), children: formatRelative(date, locale) });
|
|
107
112
|
}
|
|
108
113
|
if (column.props.mode === "datetime") {
|
|
109
|
-
return /* @__PURE__ */ jsx("time", { dateTime: date.toISOString(), children: date
|
|
114
|
+
return /* @__PURE__ */ jsx("time", { dateTime: date.toISOString(), children: formatDate(date, locale, "datetime", timeZone) });
|
|
110
115
|
}
|
|
111
|
-
return /* @__PURE__ */ jsx("time", { dateTime: date.toISOString(), children: date
|
|
116
|
+
return /* @__PURE__ */ jsx("time", { dateTime: date.toISOString(), children: formatDate(date, locale, "date", timeZone) });
|
|
112
117
|
}
|
|
113
|
-
function
|
|
118
|
+
function formatDate(date, locale, mode, timeZone) {
|
|
119
|
+
const options = mode === "datetime" ? { dateStyle: "medium", timeStyle: "short" } : { dateStyle: "medium" };
|
|
120
|
+
if (timeZone !== void 0) options.timeZone = timeZone;
|
|
121
|
+
try {
|
|
122
|
+
return new Intl.DateTimeFormat(locale, options).format(date);
|
|
123
|
+
} catch {
|
|
124
|
+
if (timeZone !== void 0) {
|
|
125
|
+
const { timeZone: _drop, ...rest } = options;
|
|
126
|
+
return new Intl.DateTimeFormat(locale, rest).format(date);
|
|
127
|
+
}
|
|
128
|
+
return mode === "datetime" ? date.toISOString() : date.toISOString().slice(0, 10);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function formatRelative(date, locale) {
|
|
114
132
|
const seconds = Math.round((Date.now() - date.getTime()) / 1e3);
|
|
115
|
-
|
|
133
|
+
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
|
|
134
|
+
const absSeconds = Math.abs(seconds);
|
|
135
|
+
if (absSeconds < 60) return rtf.format(-seconds, "second");
|
|
116
136
|
const minutes = Math.round(seconds / 60);
|
|
117
|
-
if (minutes < 60) return
|
|
137
|
+
if (Math.abs(minutes) < 60) return rtf.format(-minutes, "minute");
|
|
118
138
|
const hours = Math.round(minutes / 60);
|
|
119
|
-
if (hours < 24) return
|
|
139
|
+
if (Math.abs(hours) < 24) return rtf.format(-hours, "hour");
|
|
120
140
|
const days = Math.round(hours / 24);
|
|
121
|
-
return
|
|
141
|
+
return rtf.format(-days, "day");
|
|
122
142
|
}
|
|
123
143
|
function NumberCell({ column, value }) {
|
|
144
|
+
const locale = useArqelLocale();
|
|
124
145
|
if (value === null || value === void 0) return /* @__PURE__ */ jsx("span", { children: "\u2014" });
|
|
125
146
|
const num = typeof value === "number" ? value : Number(value);
|
|
126
147
|
if (Number.isNaN(num)) return /* @__PURE__ */ jsx("span", { children: asString(value) });
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
148
|
+
if (column.props.currency) {
|
|
149
|
+
try {
|
|
150
|
+
const formatted = new Intl.NumberFormat(locale, {
|
|
151
|
+
style: "currency",
|
|
152
|
+
currency: column.props.currency,
|
|
153
|
+
...column.props.decimals !== void 0 ? {
|
|
154
|
+
minimumFractionDigits: column.props.decimals,
|
|
155
|
+
maximumFractionDigits: column.props.decimals
|
|
156
|
+
} : {}
|
|
157
|
+
}).format(num);
|
|
158
|
+
return /* @__PURE__ */ jsxs("span", { children: [
|
|
159
|
+
column.props.prefix ?? "",
|
|
160
|
+
formatted,
|
|
161
|
+
column.props.suffix ?? ""
|
|
162
|
+
] });
|
|
163
|
+
} catch {
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const decimals = column.props.decimals ?? 0;
|
|
130
167
|
const ts = column.props.thousandsSeparator;
|
|
131
|
-
const
|
|
132
|
-
|
|
168
|
+
const ds = column.props.decimalSeparator;
|
|
169
|
+
let body;
|
|
170
|
+
if (ts === void 0 && ds === void 0) {
|
|
171
|
+
body = new Intl.NumberFormat(locale, {
|
|
172
|
+
minimumFractionDigits: decimals,
|
|
173
|
+
maximumFractionDigits: decimals
|
|
174
|
+
}).format(num);
|
|
175
|
+
} else {
|
|
176
|
+
const formatted = num.toFixed(decimals);
|
|
177
|
+
const [whole, dec] = formatted.split(".");
|
|
178
|
+
const safeWhole = whole ?? "0";
|
|
179
|
+
const finalWhole = ts ? safeWhole.replace(/\B(?=(\d{3})+(?!\d))/g, ts) : safeWhole;
|
|
180
|
+
body = dec ? `${finalWhole}${ds ?? "."}${dec}` : finalWhole;
|
|
181
|
+
}
|
|
133
182
|
return /* @__PURE__ */ jsxs("span", { children: [
|
|
134
183
|
column.props.prefix ?? "",
|
|
135
|
-
|
|
136
|
-
dec ? `${ds}${dec}` : "",
|
|
184
|
+
body,
|
|
137
185
|
column.props.suffix ?? ""
|
|
138
186
|
] });
|
|
139
187
|
}
|
|
@@ -181,6 +229,7 @@ function DataTable({
|
|
|
181
229
|
emptyState,
|
|
182
230
|
className
|
|
183
231
|
}) {
|
|
232
|
+
const t = useArqelTranslations();
|
|
184
233
|
const lastClickedIndexRef = useRef(null);
|
|
185
234
|
const visibleColumns = useMemo(() => columns.filter((col) => !col.hidden), [columns]);
|
|
186
235
|
const tableColumns = useMemo(
|
|
@@ -233,114 +282,213 @@ function DataTable({
|
|
|
233
282
|
if (!sort || sort.column !== columnName) return null;
|
|
234
283
|
return sort.direction === "desc" ? "desc" : "asc";
|
|
235
284
|
};
|
|
236
|
-
return /* @__PURE__ */
|
|
237
|
-
/* @__PURE__ */ jsx("
|
|
238
|
-
|
|
239
|
-
"
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
285
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
286
|
+
/* @__PURE__ */ jsx("div", { className: cn("hidden w-full min-w-0 overflow-x-auto md:block", className), children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-sm", children: [
|
|
287
|
+
/* @__PURE__ */ jsx("thead", { className: "sticky top-0 bg-background", children: table.getHeaderGroups().map((group) => /* @__PURE__ */ jsxs("tr", { className: "border-b border-border", children: [
|
|
288
|
+
enableSelection && /* @__PURE__ */ jsx("th", { scope: "col", className: "w-10 px-3 py-2 text-left", children: /* @__PURE__ */ jsx(
|
|
289
|
+
"input",
|
|
290
|
+
{
|
|
291
|
+
type: "checkbox",
|
|
292
|
+
"aria-label": t("table.bulk.select_all_rows", "Select all rows"),
|
|
293
|
+
checked: allSelected,
|
|
294
|
+
ref: (el) => {
|
|
295
|
+
if (el) el.indeterminate = someSelected;
|
|
296
|
+
},
|
|
297
|
+
onChange: toggleAll
|
|
298
|
+
}
|
|
299
|
+
) }),
|
|
300
|
+
group.headers.map((header) => {
|
|
301
|
+
const col = visibleColumns.find((c) => c.name === header.column.id);
|
|
302
|
+
const sortable = col?.sortable && onSortChange;
|
|
303
|
+
const direction = headerSortDirection(header.column.id);
|
|
304
|
+
return /* @__PURE__ */ jsx(
|
|
305
|
+
"th",
|
|
306
|
+
{
|
|
307
|
+
scope: "col",
|
|
308
|
+
className: cn(
|
|
309
|
+
"px-3 py-2 text-left font-medium text-muted-foreground",
|
|
310
|
+
col?.align === "center" && "text-center",
|
|
311
|
+
col?.align === "end" && "text-right",
|
|
312
|
+
col?.hiddenOnMobile && "hidden md:table-cell"
|
|
313
|
+
),
|
|
314
|
+
"aria-sort": direction === "asc" ? "ascending" : direction === "desc" ? "descending" : "none",
|
|
315
|
+
children: sortable ? /* @__PURE__ */ jsxs(
|
|
316
|
+
"button",
|
|
317
|
+
{
|
|
318
|
+
type: "button",
|
|
319
|
+
className: cn(
|
|
320
|
+
// -mx-3 px-3 stretches the button across the cell's
|
|
321
|
+
// horizontal padding; min-h-11 + w-full give a ≥44px
|
|
322
|
+
// touch target on mobile (WCAG 2.5.5) without changing
|
|
323
|
+
// the header's visual density.
|
|
324
|
+
"-mx-3 inline-flex min-h-11 w-full items-center gap-1 px-3 hover:text-foreground",
|
|
325
|
+
col?.align === "center" && "justify-center",
|
|
326
|
+
col?.align === "end" && "justify-end"
|
|
327
|
+
),
|
|
328
|
+
onClick: () => onSortChange(header.column.id, direction === "asc" ? "desc" : "asc"),
|
|
329
|
+
children: [
|
|
330
|
+
flexRender(header.column.columnDef.header, header.getContext()),
|
|
331
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: direction === "asc" ? "\u25B2" : direction === "desc" ? "\u25BC" : "\u2195" })
|
|
332
|
+
]
|
|
333
|
+
}
|
|
334
|
+
) : flexRender(header.column.columnDef.header, header.getContext())
|
|
335
|
+
},
|
|
336
|
+
header.id
|
|
337
|
+
);
|
|
338
|
+
}),
|
|
339
|
+
rowActions && /* @__PURE__ */ jsx(
|
|
255
340
|
"th",
|
|
256
341
|
{
|
|
257
342
|
scope: "col",
|
|
258
|
-
className:
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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",
|
|
343
|
+
className: "w-24 px-3 py-2 text-right",
|
|
344
|
+
"aria-label": t("table.column.actions", "Actions")
|
|
345
|
+
}
|
|
346
|
+
)
|
|
347
|
+
] }, group.id)) }),
|
|
348
|
+
/* @__PURE__ */ jsxs("tbody", { children: [
|
|
349
|
+
loading && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
350
|
+
"td",
|
|
304
351
|
{
|
|
305
|
-
|
|
306
|
-
className:
|
|
307
|
-
children:
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
352
|
+
colSpan: visibleColumns.length + (enableSelection ? 1 : 0) + (rowActions ? 1 : 0),
|
|
353
|
+
className: "px-3 py-4 text-center text-muted-foreground",
|
|
354
|
+
children: t("table.loading", "Loading\u2026")
|
|
355
|
+
}
|
|
356
|
+
) }),
|
|
357
|
+
!loading && records.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
358
|
+
"td",
|
|
359
|
+
{
|
|
360
|
+
colSpan: visibleColumns.length + (enableSelection ? 1 : 0) + (rowActions ? 1 : 0),
|
|
361
|
+
className: "px-3 py-8 text-center text-muted-foreground",
|
|
362
|
+
children: emptyState ?? t("table.empty", "No records found.")
|
|
363
|
+
}
|
|
364
|
+
) }),
|
|
365
|
+
!loading && table.getRowModel().rows.map((row, index) => {
|
|
366
|
+
const record = row.original;
|
|
367
|
+
const checked = selectedIds.includes(record.id);
|
|
368
|
+
return /* @__PURE__ */ jsxs(
|
|
369
|
+
"tr",
|
|
370
|
+
{
|
|
371
|
+
"data-selected": checked || void 0,
|
|
372
|
+
className: cn("border-b border-border", checked && "bg-muted"),
|
|
373
|
+
children: [
|
|
374
|
+
enableSelection && /* @__PURE__ */ jsx("td", { className: "w-10 px-3 py-2", children: /* @__PURE__ */ jsx(
|
|
375
|
+
"input",
|
|
376
|
+
{
|
|
377
|
+
type: "checkbox",
|
|
378
|
+
"aria-label": t("table.bulk.select_row", `Select row ${record.id}`, {
|
|
379
|
+
id: String(record.id)
|
|
380
|
+
}),
|
|
381
|
+
checked,
|
|
382
|
+
onChange: (event) => {
|
|
383
|
+
const native = event.nativeEvent;
|
|
384
|
+
toggleRow(record.id, index, native.shiftKey === true);
|
|
385
|
+
}
|
|
317
386
|
}
|
|
387
|
+
) }),
|
|
388
|
+
row.getVisibleCells().map((cell) => {
|
|
389
|
+
const col = visibleColumns.find((c) => c.name === cell.column.id);
|
|
390
|
+
return /* @__PURE__ */ jsx(
|
|
391
|
+
"td",
|
|
392
|
+
{
|
|
393
|
+
className: cn(
|
|
394
|
+
"px-3 py-2",
|
|
395
|
+
col?.align === "center" && "text-center",
|
|
396
|
+
col?.align === "end" && "text-right",
|
|
397
|
+
col?.hiddenOnMobile && "hidden md:table-cell"
|
|
398
|
+
),
|
|
399
|
+
children: flexRender(cell.column.columnDef.cell, cell.getContext())
|
|
400
|
+
},
|
|
401
|
+
cell.id
|
|
402
|
+
);
|
|
403
|
+
}),
|
|
404
|
+
rowActions && /* @__PURE__ */ jsx("td", { className: "w-24 px-3 py-2 text-right", children: rowActions(record) })
|
|
405
|
+
]
|
|
406
|
+
},
|
|
407
|
+
row.id
|
|
408
|
+
);
|
|
409
|
+
})
|
|
410
|
+
] })
|
|
411
|
+
] }) }),
|
|
412
|
+
/* @__PURE__ */ jsx(
|
|
413
|
+
DataCards,
|
|
414
|
+
{
|
|
415
|
+
columns: visibleColumns,
|
|
416
|
+
rows: table.getRowModel().rows,
|
|
417
|
+
enableSelection,
|
|
418
|
+
selectedIds,
|
|
419
|
+
onToggleRow: toggleRow,
|
|
420
|
+
rowActions,
|
|
421
|
+
loading,
|
|
422
|
+
emptyState
|
|
423
|
+
}
|
|
424
|
+
)
|
|
425
|
+
] });
|
|
426
|
+
}
|
|
427
|
+
function DataCards({
|
|
428
|
+
columns,
|
|
429
|
+
rows,
|
|
430
|
+
enableSelection,
|
|
431
|
+
selectedIds,
|
|
432
|
+
onToggleRow,
|
|
433
|
+
rowActions,
|
|
434
|
+
loading,
|
|
435
|
+
emptyState
|
|
436
|
+
}) {
|
|
437
|
+
const t = useArqelTranslations();
|
|
438
|
+
const cardColumns = columns.filter((col) => !col.hiddenOnMobile);
|
|
439
|
+
if (loading) {
|
|
440
|
+
return /* @__PURE__ */ jsx("div", { className: "px-3 py-4 text-center text-muted-foreground md:hidden", children: t("table.loading", "Loading\u2026") });
|
|
441
|
+
}
|
|
442
|
+
if (rows.length === 0) {
|
|
443
|
+
return /* @__PURE__ */ jsx("div", { className: "px-3 py-8 text-center text-muted-foreground md:hidden", children: emptyState ?? t("table.empty", "No records found.") });
|
|
444
|
+
}
|
|
445
|
+
return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3 md:hidden", children: rows.map((row, index) => {
|
|
446
|
+
const record = row.original;
|
|
447
|
+
const checked = selectedIds.includes(record.id);
|
|
448
|
+
return /* @__PURE__ */ jsxs(
|
|
449
|
+
"article",
|
|
450
|
+
{
|
|
451
|
+
"data-arqel-data-card": "",
|
|
452
|
+
"data-selected": checked || void 0,
|
|
453
|
+
className: cn("rounded-lg border border-border p-4 text-sm", checked && "bg-muted"),
|
|
454
|
+
children: [
|
|
455
|
+
(enableSelection || rowActions) && /* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-center justify-between gap-2", children: [
|
|
456
|
+
enableSelection ? /* @__PURE__ */ jsx("label", { className: "-m-2.5 inline-flex size-11 cursor-pointer items-center justify-center p-2.5", children: /* @__PURE__ */ jsx(
|
|
457
|
+
"input",
|
|
458
|
+
{
|
|
459
|
+
type: "checkbox",
|
|
460
|
+
"aria-label": t("table.bulk.select_row", `Select row ${record.id}`, {
|
|
461
|
+
id: String(record.id)
|
|
462
|
+
}),
|
|
463
|
+
className: "size-5",
|
|
464
|
+
checked,
|
|
465
|
+
onChange: (event) => {
|
|
466
|
+
const native = event.nativeEvent;
|
|
467
|
+
onToggleRow(record.id, index, native.shiftKey === true);
|
|
318
468
|
}
|
|
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
|
-
] }) });
|
|
469
|
+
}
|
|
470
|
+
) }) : /* @__PURE__ */ jsx("span", {}),
|
|
471
|
+
rowActions ? /* @__PURE__ */ jsx("div", { className: "ml-auto", children: rowActions(record) }) : null
|
|
472
|
+
] }),
|
|
473
|
+
/* @__PURE__ */ jsx("dl", { className: "grid grid-cols-[minmax(0,auto)_1fr] gap-x-3 gap-y-2", children: cardColumns.map((col) => /* @__PURE__ */ jsxs("div", { className: "contents", children: [
|
|
474
|
+
/* @__PURE__ */ jsx("dt", { className: "font-medium text-muted-foreground", children: col.label ?? col.name }),
|
|
475
|
+
/* @__PURE__ */ jsx(
|
|
476
|
+
"dd",
|
|
477
|
+
{
|
|
478
|
+
className: cn(
|
|
479
|
+
"min-w-0 break-words",
|
|
480
|
+
col.align === "end" && "text-right",
|
|
481
|
+
col.align === "center" && "text-center"
|
|
482
|
+
),
|
|
483
|
+
children: /* @__PURE__ */ jsx(TableCell, { column: col, value: record[col.name] })
|
|
484
|
+
}
|
|
485
|
+
)
|
|
486
|
+
] }, col.name)) })
|
|
487
|
+
]
|
|
488
|
+
},
|
|
489
|
+
row.id
|
|
490
|
+
);
|
|
491
|
+
}) });
|
|
344
492
|
}
|
|
345
493
|
function TableFilters({
|
|
346
494
|
filters,
|
|
@@ -349,13 +497,14 @@ function TableFilters({
|
|
|
349
497
|
onClearAll,
|
|
350
498
|
className
|
|
351
499
|
}) {
|
|
500
|
+
const t = useArqelTranslations();
|
|
352
501
|
if (filters.length === 0) return null;
|
|
353
502
|
const activeCount = filters.reduce((acc, f) => {
|
|
354
503
|
const v = values[f.name];
|
|
355
504
|
return v !== void 0 && v !== null && v !== "" ? acc + 1 : acc;
|
|
356
505
|
}, 0);
|
|
357
506
|
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" }),
|
|
507
|
+
/* @__PURE__ */ jsx("legend", { className: "sr-only", children: t("table.filters.legend", "Filters") }),
|
|
359
508
|
filters.map((filter) => /* @__PURE__ */ jsx(
|
|
360
509
|
FilterControl,
|
|
361
510
|
{
|
|
@@ -365,11 +514,7 @@ function TableFilters({
|
|
|
365
514
|
},
|
|
366
515
|
filter.name
|
|
367
516
|
)),
|
|
368
|
-
activeCount > 0 && onClearAll && /* @__PURE__ */
|
|
369
|
-
"Clear filters (",
|
|
370
|
-
activeCount,
|
|
371
|
-
")"
|
|
372
|
-
] })
|
|
517
|
+
activeCount > 0 && onClearAll && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: onClearAll, children: t("table.filters.clear", `Clear filters (${activeCount})`, { count: activeCount }) })
|
|
373
518
|
] });
|
|
374
519
|
}
|
|
375
520
|
function FilterControl({
|
|
@@ -393,7 +538,8 @@ function FilterControl({
|
|
|
393
538
|
}
|
|
394
539
|
function controlClasses() {
|
|
395
540
|
return cn(
|
|
396
|
-
|
|
541
|
+
// 44px touch target on mobile (WCAG 2.5.5); dense 36px on >=md.
|
|
542
|
+
"h-11 rounded-sm border border-[var(--input)] md:h-9",
|
|
397
543
|
"bg-background px-3 text-sm",
|
|
398
544
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
399
545
|
);
|
|
@@ -403,6 +549,7 @@ function SelectFilter({
|
|
|
403
549
|
value,
|
|
404
550
|
onChange
|
|
405
551
|
}) {
|
|
552
|
+
const t = useArqelTranslations();
|
|
406
553
|
return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1 text-xs text-muted-foreground", children: [
|
|
407
554
|
filter.label ?? filter.name,
|
|
408
555
|
/* @__PURE__ */ jsxs(
|
|
@@ -412,7 +559,7 @@ function SelectFilter({
|
|
|
412
559
|
value: value === void 0 || value === null ? "" : String(value),
|
|
413
560
|
onChange: (e) => onChange(e.target.value === "" ? null : e.target.value),
|
|
414
561
|
children: [
|
|
415
|
-
/* @__PURE__ */ jsx("option", { value: "", children: "All" }),
|
|
562
|
+
/* @__PURE__ */ jsx("option", { value: "", children: t("table.filters.all", "All") }),
|
|
416
563
|
filter.props.options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
|
|
417
564
|
]
|
|
418
565
|
}
|
|
@@ -431,7 +578,7 @@ function MultiSelectFilter({
|
|
|
431
578
|
"select",
|
|
432
579
|
{
|
|
433
580
|
multiple: true,
|
|
434
|
-
className: cn(controlClasses(), "h-auto min-h-[2.25rem]
|
|
581
|
+
className: cn(controlClasses(), "h-auto min-h-11 py-1 md:min-h-[2.25rem]"),
|
|
435
582
|
value: arr.map(String),
|
|
436
583
|
onChange: (e) => {
|
|
437
584
|
const next = Array.from(e.target.selectedOptions, (o) => o.value);
|
|
@@ -465,6 +612,7 @@ function TernaryFilter({
|
|
|
465
612
|
value,
|
|
466
613
|
onChange
|
|
467
614
|
}) {
|
|
615
|
+
const t = useArqelTranslations();
|
|
468
616
|
const current = value === void 0 || value === null ? "all" : String(value);
|
|
469
617
|
return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1 text-xs text-muted-foreground", children: [
|
|
470
618
|
filter.label ?? filter.name,
|
|
@@ -478,9 +626,9 @@ function TernaryFilter({
|
|
|
478
626
|
onChange(v === "all" ? null : v);
|
|
479
627
|
},
|
|
480
628
|
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" })
|
|
629
|
+
/* @__PURE__ */ jsx("option", { value: "all", children: filter.props.allLabel ?? t("table.filters.all", "All") }),
|
|
630
|
+
/* @__PURE__ */ jsx("option", { value: "true", children: filter.props.trueLabel ?? t("table.filters.yes", "Yes") }),
|
|
631
|
+
/* @__PURE__ */ jsx("option", { value: "false", children: filter.props.falseLabel ?? t("table.filters.no", "No") })
|
|
484
632
|
]
|
|
485
633
|
}
|
|
486
634
|
)
|
|
@@ -493,8 +641,14 @@ function TablePagination({
|
|
|
493
641
|
perPageOptions = [10, 25, 50, 100],
|
|
494
642
|
className
|
|
495
643
|
}) {
|
|
496
|
-
const
|
|
497
|
-
const
|
|
644
|
+
const t = useArqelTranslations();
|
|
645
|
+
const locale = useArqelLocale();
|
|
646
|
+
const numberFormatter = useMemo(() => new Intl.NumberFormat(locale), [locale]);
|
|
647
|
+
const fromRaw = (meta.currentPage - 1) * meta.perPage + 1;
|
|
648
|
+
const toRaw = Math.min(meta.currentPage * meta.perPage, meta.total);
|
|
649
|
+
const from = numberFormatter.format(fromRaw);
|
|
650
|
+
const to = numberFormatter.format(toRaw);
|
|
651
|
+
const total = numberFormatter.format(meta.total);
|
|
498
652
|
const isFirst = meta.currentPage <= 1;
|
|
499
653
|
const isLast = meta.currentPage >= meta.lastPage;
|
|
500
654
|
return /* @__PURE__ */ jsxs(
|
|
@@ -504,16 +658,23 @@ function TablePagination({
|
|
|
504
658
|
"flex flex-wrap items-center justify-between gap-2 border-t border-border px-3 py-2 text-sm",
|
|
505
659
|
className
|
|
506
660
|
),
|
|
507
|
-
"aria-label": "Pagination",
|
|
661
|
+
"aria-label": t("table.pagination.label", "Pagination"),
|
|
508
662
|
children: [
|
|
509
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: meta.total === 0 ? "No
|
|
663
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: meta.total === 0 ? t("table.empty", "No records found.") : t(
|
|
664
|
+
"table.pagination.showing",
|
|
665
|
+
// Fallback is rendered verbatim when the key is missing, so it must
|
|
666
|
+
// already carry the interpolated values (the replacements map only
|
|
667
|
+
// applies to a resolved dictionary string).
|
|
668
|
+
`Showing ${from} to ${to} of ${total} results`,
|
|
669
|
+
{ from, to, total }
|
|
670
|
+
) }),
|
|
510
671
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
511
672
|
onPerPageChange && /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
512
|
-
"Per page",
|
|
673
|
+
t("table.per_page", "Per page"),
|
|
513
674
|
/* @__PURE__ */ jsx(
|
|
514
675
|
"select",
|
|
515
676
|
{
|
|
516
|
-
className: "h-
|
|
677
|
+
className: "h-11 rounded-sm border border-[var(--input)] bg-background px-2 md:h-8",
|
|
517
678
|
value: meta.perPage,
|
|
518
679
|
onChange: (e) => onPerPageChange(Number(e.target.value)),
|
|
519
680
|
children: perPageOptions.map((n) => /* @__PURE__ */ jsx("option", { value: n, children: n }, n))
|
|
@@ -525,26 +686,28 @@ function TablePagination({
|
|
|
525
686
|
{
|
|
526
687
|
variant: "outline",
|
|
527
688
|
size: "sm",
|
|
689
|
+
className: "h-11 md:h-8",
|
|
528
690
|
disabled: isFirst,
|
|
529
691
|
onClick: () => onPageChange(meta.currentPage - 1),
|
|
530
|
-
"aria-label": "Previous page",
|
|
531
|
-
children: "Prev"
|
|
692
|
+
"aria-label": t("table.pagination.previous_page", "Previous page"),
|
|
693
|
+
children: t("table.pagination.previous", "Prev")
|
|
532
694
|
}
|
|
533
695
|
),
|
|
534
696
|
/* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
535
|
-
meta.currentPage,
|
|
697
|
+
numberFormatter.format(meta.currentPage),
|
|
536
698
|
" / ",
|
|
537
|
-
meta.lastPage
|
|
699
|
+
numberFormatter.format(meta.lastPage)
|
|
538
700
|
] }),
|
|
539
701
|
/* @__PURE__ */ jsx(
|
|
540
702
|
Button,
|
|
541
703
|
{
|
|
542
704
|
variant: "outline",
|
|
543
705
|
size: "sm",
|
|
706
|
+
className: "h-11 md:h-8",
|
|
544
707
|
disabled: isLast,
|
|
545
708
|
onClick: () => onPageChange(meta.currentPage + 1),
|
|
546
|
-
"aria-label": "Next page",
|
|
547
|
-
children: "Next"
|
|
709
|
+
"aria-label": t("table.pagination.next_page", "Next page"),
|
|
710
|
+
children: t("table.pagination.next", "Next")
|
|
548
711
|
}
|
|
549
712
|
)
|
|
550
713
|
] })
|
|
@@ -560,6 +723,7 @@ function TableToolbar({
|
|
|
560
723
|
onClearSelection,
|
|
561
724
|
className
|
|
562
725
|
}) {
|
|
726
|
+
const t = useArqelTranslations();
|
|
563
727
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-3 px-3 py-3", className), children: [
|
|
564
728
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-end gap-2", children: [
|
|
565
729
|
search,
|
|
@@ -569,12 +733,11 @@ function TableToolbar({
|
|
|
569
733
|
"section",
|
|
570
734
|
{
|
|
571
735
|
className: "flex flex-wrap items-center gap-2 rounded-sm border border-border bg-muted px-3 py-2",
|
|
572
|
-
"aria-label": "Bulk actions",
|
|
736
|
+
"aria-label": t("table.bulk.label", "Bulk actions"),
|
|
573
737
|
children: [
|
|
574
|
-
/* @__PURE__ */
|
|
575
|
-
selectedCount
|
|
576
|
-
|
|
577
|
-
] }),
|
|
738
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: t("table.bulk.selected", "{one} :count selected|{other} :count selected", {
|
|
739
|
+
count: selectedCount
|
|
740
|
+
}) }),
|
|
578
741
|
/* @__PURE__ */ jsxs("div", { className: "ml-auto flex flex-wrap items-center gap-2", children: [
|
|
579
742
|
bulkActions,
|
|
580
743
|
onClearSelection && /* @__PURE__ */ jsx(
|
|
@@ -583,7 +746,7 @@ function TableToolbar({
|
|
|
583
746
|
type: "button",
|
|
584
747
|
className: "text-sm text-muted-foreground hover:underline",
|
|
585
748
|
onClick: onClearSelection,
|
|
586
|
-
children: "Clear"
|
|
749
|
+
children: t("table.bulk.clear", "Clear")
|
|
587
750
|
}
|
|
588
751
|
)
|
|
589
752
|
] })
|
|
@@ -594,5 +757,5 @@ function TableToolbar({
|
|
|
594
757
|
}
|
|
595
758
|
|
|
596
759
|
export { DataTable, TableCell, TableFilters, TablePagination, TableToolbar };
|
|
597
|
-
//# sourceMappingURL=chunk-
|
|
598
|
-
//# sourceMappingURL=chunk-
|
|
760
|
+
//# sourceMappingURL=chunk-S5UNPCMQ.js.map
|
|
761
|
+
//# sourceMappingURL=chunk-S5UNPCMQ.js.map
|