@nexgrid/react 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -37
- package/dist/index.cjs +857 -303
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +93 -30
- package/dist/index.d.ts +93 -30
- package/dist/index.js +863 -306
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
- package/styles.css +1555 -411
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
// src/
|
|
3
|
+
// src/table-x.tsx
|
|
4
4
|
import * as React4 from "react";
|
|
5
5
|
import {
|
|
6
6
|
DENSITIES,
|
|
@@ -16,6 +16,8 @@ import {
|
|
|
16
16
|
getPageNumbers,
|
|
17
17
|
getRecordRange,
|
|
18
18
|
initialHiddenColumns,
|
|
19
|
+
isEditable,
|
|
20
|
+
isFilterable,
|
|
19
21
|
isHideable,
|
|
20
22
|
isPageSize,
|
|
21
23
|
isSortable,
|
|
@@ -26,10 +28,13 @@ import {
|
|
|
26
28
|
toExportColumns,
|
|
27
29
|
totalPagesFor,
|
|
28
30
|
visibleColumns,
|
|
31
|
+
withFilter,
|
|
29
32
|
withPage,
|
|
30
33
|
withPageSize,
|
|
31
34
|
withSearch,
|
|
32
|
-
withToggledSort
|
|
35
|
+
withToggledSort,
|
|
36
|
+
withToggledMultiSort,
|
|
37
|
+
copyToClipboard
|
|
33
38
|
} from "@nexgrid/core";
|
|
34
39
|
|
|
35
40
|
// src/icons.tsx
|
|
@@ -70,29 +75,22 @@ function XIcon(props) {
|
|
|
70
75
|
/* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
|
|
71
76
|
] });
|
|
72
77
|
}
|
|
73
|
-
function
|
|
78
|
+
function ColumnsIcon(props) {
|
|
74
79
|
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
75
|
-
/* @__PURE__ */ jsx("
|
|
76
|
-
/* @__PURE__ */ jsx("
|
|
77
|
-
/* @__PURE__ */ jsx("
|
|
78
|
-
/* @__PURE__ */ jsx("line", { x1: "8", x2: "3", y1: "12", y2: "12" }),
|
|
79
|
-
/* @__PURE__ */ jsx("line", { x1: "21", x2: "16", y1: "20", y2: "20" }),
|
|
80
|
-
/* @__PURE__ */ jsx("line", { x1: "12", x2: "3", y1: "20", y2: "20" }),
|
|
81
|
-
/* @__PURE__ */ jsx("line", { x1: "14", x2: "14", y1: "2", y2: "6" }),
|
|
82
|
-
/* @__PURE__ */ jsx("line", { x1: "8", x2: "8", y1: "10", y2: "14" }),
|
|
83
|
-
/* @__PURE__ */ jsx("line", { x1: "16", x2: "16", y1: "18", y2: "22" })
|
|
80
|
+
/* @__PURE__ */ jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
|
|
81
|
+
/* @__PURE__ */ jsx("path", { d: "M9 3v18" }),
|
|
82
|
+
/* @__PURE__ */ jsx("path", { d: "M15 3v18" })
|
|
84
83
|
] });
|
|
85
84
|
}
|
|
86
|
-
function
|
|
87
|
-
return /* @__PURE__ */ jsx(Icon, { ...props, children: /* @__PURE__ */ jsx("polygon", { points: "22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3" }) });
|
|
88
|
-
}
|
|
89
|
-
function DownloadIcon(props) {
|
|
85
|
+
function DensityIcon(props) {
|
|
90
86
|
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
91
|
-
/* @__PURE__ */ jsx("
|
|
92
|
-
/* @__PURE__ */ jsx("
|
|
93
|
-
/* @__PURE__ */ jsx("line", { x1: "12", x2: "12", y1: "15", y2: "3" })
|
|
87
|
+
/* @__PURE__ */ jsx("rect", { x: "3", y: "4.5", width: "18", height: "6", rx: "1.5" }),
|
|
88
|
+
/* @__PURE__ */ jsx("rect", { x: "3", y: "13.5", width: "18", height: "6", rx: "1.5" })
|
|
94
89
|
] });
|
|
95
90
|
}
|
|
91
|
+
function ChevronDownIcon(props) {
|
|
92
|
+
return /* @__PURE__ */ jsx(Icon, { ...props, children: /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" }) });
|
|
93
|
+
}
|
|
96
94
|
function FileSpreadsheetIcon(props) {
|
|
97
95
|
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
98
96
|
/* @__PURE__ */ jsx("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
|
|
@@ -141,6 +139,26 @@ function ArrowUpDownIcon(props) {
|
|
|
141
139
|
function CheckIcon(props) {
|
|
142
140
|
return /* @__PURE__ */ jsx(Icon, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) });
|
|
143
141
|
}
|
|
142
|
+
function RotateCcwIcon(props) {
|
|
143
|
+
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
144
|
+
/* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
|
|
145
|
+
/* @__PURE__ */ jsx("path", { d: "M3 3v5h5" })
|
|
146
|
+
] });
|
|
147
|
+
}
|
|
148
|
+
function DownloadTrayIcon(props) {
|
|
149
|
+
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
150
|
+
/* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
151
|
+
/* @__PURE__ */ jsx("polyline", { points: "7 10 12 15 17 10" }),
|
|
152
|
+
/* @__PURE__ */ jsx("line", { x1: "12", x2: "12", y1: "15", y2: "3" })
|
|
153
|
+
] });
|
|
154
|
+
}
|
|
155
|
+
function DotsVerticalIcon(props) {
|
|
156
|
+
return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
|
|
157
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "5", r: "1.5" }),
|
|
158
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "1.5" }),
|
|
159
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "19", r: "1.5" })
|
|
160
|
+
] });
|
|
161
|
+
}
|
|
144
162
|
|
|
145
163
|
// src/render.tsx
|
|
146
164
|
import * as React from "react";
|
|
@@ -176,9 +194,9 @@ function bodyCellStyle(col) {
|
|
|
176
194
|
}
|
|
177
195
|
function headerInnerClass(col) {
|
|
178
196
|
const align = col.meta?.align;
|
|
179
|
-
if (align === "center") return "
|
|
180
|
-
if (align === "right") return "
|
|
181
|
-
return "
|
|
197
|
+
if (align === "center") return "tbx-th-inner tbx-th-inner--center";
|
|
198
|
+
if (align === "right") return "tbx-th-inner tbx-th-inner--right";
|
|
199
|
+
return "tbx-th-inner";
|
|
182
200
|
}
|
|
183
201
|
function renderTemplate(template, values) {
|
|
184
202
|
const parts = [];
|
|
@@ -250,7 +268,7 @@ function useDropdown() {
|
|
|
250
268
|
return { isOpen, toggle, close, containerRef, triggerRef };
|
|
251
269
|
}
|
|
252
270
|
|
|
253
|
-
// src/
|
|
271
|
+
// src/table-x.tsx
|
|
254
272
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
255
273
|
function defaultRowId(row) {
|
|
256
274
|
const record = row;
|
|
@@ -262,37 +280,72 @@ var DENSITY_LABEL_KEY = {
|
|
|
262
280
|
default: "densityDefault",
|
|
263
281
|
comfortable: "densityComfortable"
|
|
264
282
|
};
|
|
265
|
-
function
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
283
|
+
function TableX(props) {
|
|
284
|
+
const {
|
|
285
|
+
columns,
|
|
286
|
+
data,
|
|
287
|
+
total,
|
|
288
|
+
query,
|
|
289
|
+
onQueryChange,
|
|
290
|
+
caption,
|
|
291
|
+
density: initialDensity = "default",
|
|
292
|
+
isLoading = false,
|
|
293
|
+
error = false,
|
|
294
|
+
onRetry,
|
|
295
|
+
enableSelection = false,
|
|
296
|
+
selectionMode = "multi",
|
|
297
|
+
enableColumnFilters = true,
|
|
298
|
+
enableColumnResize = true,
|
|
299
|
+
onSelectionChange,
|
|
300
|
+
enableSearch = true,
|
|
301
|
+
searchPlaceholder,
|
|
302
|
+
enableColumns = true,
|
|
303
|
+
showColumnsButton,
|
|
304
|
+
enableDensity = true,
|
|
305
|
+
showDensityButton,
|
|
306
|
+
enableExport = true,
|
|
307
|
+
showExportButton,
|
|
308
|
+
enableSorting = true,
|
|
309
|
+
enablePagination = true,
|
|
310
|
+
showPagination,
|
|
311
|
+
enableRowsPerPage = true,
|
|
312
|
+
showRowsPerPage,
|
|
313
|
+
enableJumpToPage = true,
|
|
314
|
+
showJumpToPage,
|
|
315
|
+
showToolbar = true,
|
|
316
|
+
showFooter = true,
|
|
317
|
+
renderExpandedRow,
|
|
318
|
+
enableBulkActions = true,
|
|
319
|
+
bulkActions,
|
|
320
|
+
enableSummaryRow,
|
|
321
|
+
enableColumnReorder = false,
|
|
322
|
+
onColumnOrderChange,
|
|
323
|
+
onCellEdit,
|
|
324
|
+
toolbarActions,
|
|
325
|
+
onRowClick,
|
|
326
|
+
getRowId = defaultRowId,
|
|
327
|
+
className,
|
|
328
|
+
showSerialNumber = true,
|
|
329
|
+
exportFileName,
|
|
330
|
+
onExportAll,
|
|
331
|
+
fetchEndpoint,
|
|
332
|
+
badgeRules,
|
|
333
|
+
locale: localeOverrides,
|
|
334
|
+
onNotify,
|
|
335
|
+
theme = "light"
|
|
336
|
+
} = props;
|
|
294
337
|
const locale = resolveLocale(localeOverrides);
|
|
295
338
|
const boolLabels = { yes: locale.booleanYes, no: locale.booleanNo };
|
|
339
|
+
const isColumnsVisible = enableColumns && showColumnsButton !== false;
|
|
340
|
+
const isDensityVisible = enableDensity && showDensityButton !== false;
|
|
341
|
+
const isExportVisible = enableExport && showExportButton !== false;
|
|
342
|
+
const isPaginationVisible = enablePagination && showPagination !== false;
|
|
343
|
+
const isRowsPerPageVisible = enableRowsPerPage && showRowsPerPage !== false;
|
|
344
|
+
const isJumpToPageVisible = enableJumpToPage && showJumpToPage !== false;
|
|
345
|
+
const [colList, setColList] = React4.useState(columns);
|
|
346
|
+
React4.useEffect(() => {
|
|
347
|
+
setColList(columns);
|
|
348
|
+
}, [columns]);
|
|
296
349
|
const [density, setDensity] = React4.useState(initialDensity);
|
|
297
350
|
const [hiddenCols, setHiddenCols] = React4.useState(
|
|
298
351
|
() => initialHiddenColumns(columns)
|
|
@@ -300,7 +353,14 @@ function NexGrid({
|
|
|
300
353
|
const [selectedIds, setSelectedIds] = React4.useState(
|
|
301
354
|
() => /* @__PURE__ */ new Set()
|
|
302
355
|
);
|
|
356
|
+
const [expandedRows, setExpandedRows] = React4.useState(
|
|
357
|
+
() => /* @__PURE__ */ new Set()
|
|
358
|
+
);
|
|
359
|
+
const [editingCell, setEditingCell] = React4.useState(null);
|
|
360
|
+
const [draggedColId, setDraggedColId] = React4.useState(null);
|
|
303
361
|
const [isExporting, setIsExporting] = React4.useState(false);
|
|
362
|
+
const [openFilterCol, setOpenFilterCol] = React4.useState(null);
|
|
363
|
+
const [colWidths, setColWidths] = React4.useState({});
|
|
304
364
|
const columnsMenu = useDropdown();
|
|
305
365
|
const densityMenu = useDropdown();
|
|
306
366
|
const exportMenu = useDropdown();
|
|
@@ -309,6 +369,7 @@ function NexGrid({
|
|
|
309
369
|
const densityButtonId = `${instanceId}-density`;
|
|
310
370
|
const exportButtonId = `${instanceId}-export`;
|
|
311
371
|
const jumpInputId = `${instanceId}-jump`;
|
|
372
|
+
const rootRef = React4.useRef(null);
|
|
312
373
|
const notify = (type, message) => {
|
|
313
374
|
onNotify?.({ type, message });
|
|
314
375
|
};
|
|
@@ -318,126 +379,185 @@ function NexGrid({
|
|
|
318
379
|
const range = getRecordRange(currentPage, pageSize, total);
|
|
319
380
|
const sort = primarySort(query);
|
|
320
381
|
const visible = React4.useMemo(
|
|
321
|
-
() => visibleColumns(
|
|
322
|
-
[
|
|
382
|
+
() => visibleColumns(colList, hiddenCols),
|
|
383
|
+
[colList, hiddenCols]
|
|
323
384
|
);
|
|
324
|
-
const hideable = React4.useMemo(() =>
|
|
385
|
+
const hideable = React4.useMemo(() => colList.filter(isHideable), [colList]);
|
|
325
386
|
const pageItems = React4.useMemo(
|
|
326
387
|
() => getPageNumbers(currentPage, totalPages),
|
|
327
388
|
[currentPage, totalPages]
|
|
328
389
|
);
|
|
329
390
|
const pageRowIds = React4.useMemo(() => data.map((row) => getRowId(row)), [data, getRowId]);
|
|
330
|
-
const columnCount = visible.length + (showSerialNumber ? 1 : 0) + (enableSelection ? 1 : 0);
|
|
391
|
+
const columnCount = visible.length + (renderExpandedRow ? 1 : 0) + (showSerialNumber ? 1 : 0) + (enableSelection ? 1 : 0);
|
|
392
|
+
const getPinnedOffsets = (visibleCols) => {
|
|
393
|
+
const leftOffsets2 = /* @__PURE__ */ new Map();
|
|
394
|
+
const rightOffsets2 = /* @__PURE__ */ new Map();
|
|
395
|
+
let currentLeft = 0;
|
|
396
|
+
let lastLeftPinnedId2 = null;
|
|
397
|
+
if (renderExpandedRow) {
|
|
398
|
+
leftOffsets2.set("__expand", currentLeft);
|
|
399
|
+
currentLeft += 40;
|
|
400
|
+
lastLeftPinnedId2 = "__expand";
|
|
401
|
+
}
|
|
402
|
+
if (enableSelection) {
|
|
403
|
+
leftOffsets2.set("__select", currentLeft);
|
|
404
|
+
currentLeft += 44;
|
|
405
|
+
lastLeftPinnedId2 = "__select";
|
|
406
|
+
}
|
|
407
|
+
if (showSerialNumber) {
|
|
408
|
+
leftOffsets2.set("__serial", currentLeft);
|
|
409
|
+
currentLeft += 56;
|
|
410
|
+
lastLeftPinnedId2 = "__serial";
|
|
411
|
+
}
|
|
412
|
+
for (const col of visibleCols) {
|
|
413
|
+
const id = getColumnId2(col);
|
|
414
|
+
const pin = col.meta?.pinned;
|
|
415
|
+
const width = colWidths[id] ?? col.meta?.width ?? 140;
|
|
416
|
+
if (pin === "left") {
|
|
417
|
+
leftOffsets2.set(id, currentLeft);
|
|
418
|
+
currentLeft += width;
|
|
419
|
+
lastLeftPinnedId2 = id;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
let currentRight = 0;
|
|
423
|
+
let firstRightPinnedId2 = null;
|
|
424
|
+
for (let i = visibleCols.length - 1; i >= 0; i--) {
|
|
425
|
+
const col = visibleCols[i];
|
|
426
|
+
if (!col) continue;
|
|
427
|
+
const id = getColumnId2(col);
|
|
428
|
+
const pin = col.meta?.pinned;
|
|
429
|
+
const width = colWidths[id] ?? col.meta?.width ?? 140;
|
|
430
|
+
if (pin === "right") {
|
|
431
|
+
rightOffsets2.set(id, currentRight);
|
|
432
|
+
currentRight += width;
|
|
433
|
+
firstRightPinnedId2 = id;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return { leftOffsets: leftOffsets2, rightOffsets: rightOffsets2, lastLeftPinnedId: lastLeftPinnedId2, firstRightPinnedId: firstRightPinnedId2 };
|
|
437
|
+
};
|
|
438
|
+
const { leftOffsets, rightOffsets, lastLeftPinnedId, firstRightPinnedId } = getPinnedOffsets(visible);
|
|
331
439
|
const [searchText, setSearchText] = useDebouncedSearch(query.q ?? "", (text) => {
|
|
332
440
|
onQueryChange(withSearch(query, text));
|
|
333
441
|
});
|
|
334
442
|
const [jumpText, setJumpText] = React4.useState(() => String(currentPage));
|
|
335
443
|
React4.useEffect(() => setJumpText(String(currentPage)), [currentPage]);
|
|
336
|
-
const submitJump = (
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
setJumpText(String(parsed));
|
|
341
|
-
if (parsed !== currentPage) onQueryChange(withPage(query, parsed, totalPages));
|
|
444
|
+
const submitJump = (raw) => {
|
|
445
|
+
const page = Number.parseInt(raw, 10);
|
|
446
|
+
if (Number.isNaN(page) || page < 1 || page > totalPages) {
|
|
447
|
+
setJumpText(String(currentPage));
|
|
342
448
|
return;
|
|
343
449
|
}
|
|
344
|
-
|
|
450
|
+
if (page !== currentPage) {
|
|
451
|
+
onQueryChange(withPage(query, page, totalPages));
|
|
452
|
+
}
|
|
345
453
|
};
|
|
346
|
-
const toggleSort = (
|
|
347
|
-
|
|
454
|
+
const toggleSort = (field, multiSort = false) => {
|
|
455
|
+
const next = multiSort ? withToggledMultiSort(query, field) : withToggledSort(query, field);
|
|
456
|
+
onQueryChange(next);
|
|
348
457
|
};
|
|
349
|
-
const
|
|
350
|
-
const allPageSelected = pageRowIds.length > 0 &&
|
|
351
|
-
const somePageSelected =
|
|
352
|
-
const
|
|
458
|
+
const isSingleSelect = selectionMode === "single";
|
|
459
|
+
const allPageSelected = pageRowIds.length > 0 && pageRowIds.every((id) => selectedIds.has(id));
|
|
460
|
+
const somePageSelected = !allPageSelected && pageRowIds.some((id) => selectedIds.has(id));
|
|
461
|
+
const toggleSelectAll = () => {
|
|
462
|
+
if (isSingleSelect) return;
|
|
463
|
+
const next = new Set(selectedIds);
|
|
464
|
+
if (allPageSelected) {
|
|
465
|
+
for (const id of pageRowIds) next.delete(id);
|
|
466
|
+
} else {
|
|
467
|
+
for (const id of pageRowIds) next.add(id);
|
|
468
|
+
}
|
|
353
469
|
setSelectedIds(next);
|
|
354
470
|
onSelectionChange?.(Array.from(next), false);
|
|
355
471
|
};
|
|
356
|
-
const
|
|
357
|
-
const next = new Set(selectedIds);
|
|
358
|
-
|
|
359
|
-
if (
|
|
472
|
+
const toggleSelectRow = (id) => {
|
|
473
|
+
const next = isSingleSelect ? selectedIds.has(id) ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([id]) : new Set(selectedIds);
|
|
474
|
+
if (!isSingleSelect) {
|
|
475
|
+
if (next.has(id)) next.delete(id);
|
|
360
476
|
else next.add(id);
|
|
361
477
|
}
|
|
362
|
-
|
|
478
|
+
setSelectedIds(next);
|
|
479
|
+
onSelectionChange?.(Array.from(next), false);
|
|
363
480
|
};
|
|
364
|
-
const
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
481
|
+
const deselectAll = () => {
|
|
482
|
+
setSelectedIds(/* @__PURE__ */ new Set());
|
|
483
|
+
onSelectionChange?.([], false);
|
|
484
|
+
};
|
|
485
|
+
const toggleExpandRow = (id) => {
|
|
486
|
+
setExpandedRows((prev) => {
|
|
487
|
+
const next = new Set(prev);
|
|
488
|
+
if (next.has(id)) next.delete(id);
|
|
489
|
+
else next.add(id);
|
|
490
|
+
return next;
|
|
491
|
+
});
|
|
369
492
|
};
|
|
370
493
|
const toggleColumn = (columnId) => {
|
|
371
494
|
setHiddenCols((prev) => ({ ...prev, [columnId]: prev[columnId] !== true }));
|
|
372
495
|
};
|
|
373
|
-
const collectExportRows = async () => {
|
|
374
|
-
if (data.length >= total || !fetchEndpoint) return data;
|
|
375
|
-
notify("info", formatMessage(locale.exportFetchingAll, { total: total.toLocaleString() }));
|
|
376
|
-
try {
|
|
377
|
-
const result = await fetchAllPages(async (page, size) => {
|
|
378
|
-
const url = buildQueryUrl(fetchEndpoint, {
|
|
379
|
-
...query,
|
|
380
|
-
page,
|
|
381
|
-
pageSize: isPageSize(size) ? size : query.pageSize
|
|
382
|
-
});
|
|
383
|
-
const response = await fetch(url, { cache: "no-store" });
|
|
384
|
-
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
385
|
-
return await response.json();
|
|
386
|
-
});
|
|
387
|
-
return result.items;
|
|
388
|
-
} catch {
|
|
389
|
-
notify("error", locale.exportFetchFailed);
|
|
390
|
-
return data;
|
|
391
|
-
}
|
|
392
|
-
};
|
|
393
496
|
const handleExport = async (format) => {
|
|
394
497
|
exportMenu.close();
|
|
395
498
|
if (onExportAll) {
|
|
396
|
-
|
|
499
|
+
try {
|
|
500
|
+
await onExportAll();
|
|
501
|
+
} catch (err) {
|
|
502
|
+
notify("error", err instanceof Error ? err.message : "Export failed");
|
|
503
|
+
}
|
|
397
504
|
return;
|
|
398
505
|
}
|
|
399
506
|
setIsExporting(true);
|
|
507
|
+
notify("info", "Exporting...");
|
|
400
508
|
try {
|
|
401
|
-
|
|
402
|
-
if (
|
|
403
|
-
|
|
404
|
-
|
|
509
|
+
let exportRows = data;
|
|
510
|
+
if (fetchEndpoint) {
|
|
511
|
+
const full = await fetchAllPages(async (page, size) => {
|
|
512
|
+
const url = buildQueryUrl(fetchEndpoint, {
|
|
513
|
+
...query,
|
|
514
|
+
page,
|
|
515
|
+
pageSize: isPageSize(size) ? size : query.pageSize
|
|
516
|
+
});
|
|
517
|
+
const response = await fetch(url, { cache: "no-store" });
|
|
518
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
519
|
+
return await response.json();
|
|
520
|
+
});
|
|
521
|
+
exportRows = full.items;
|
|
405
522
|
}
|
|
406
523
|
const exportColumns = toExportColumns(visible, boolLabels);
|
|
407
524
|
const prefix = exportFileName ?? filePrefixFromCaption(caption);
|
|
408
|
-
if (format === "
|
|
409
|
-
const
|
|
525
|
+
if (format === "clipboard") {
|
|
526
|
+
const ok = await copyToClipboard(exportRows, exportColumns);
|
|
527
|
+
if (ok) notify("success", "Copied to clipboard");
|
|
528
|
+
else notify("error", "Failed to copy to clipboard");
|
|
529
|
+
} else if (format === "excel") {
|
|
530
|
+
downloadExcel({
|
|
410
531
|
filename: prefix,
|
|
411
532
|
caption,
|
|
412
|
-
rows,
|
|
533
|
+
rows: exportRows,
|
|
413
534
|
columns: exportColumns,
|
|
414
535
|
badgeRules,
|
|
415
536
|
serialHeader: locale.serialHeader
|
|
416
537
|
});
|
|
417
|
-
notify(
|
|
418
|
-
"success",
|
|
419
|
-
formatMessage(locale.exportExcelSuccess, { count: count.toLocaleString() })
|
|
420
|
-
);
|
|
538
|
+
notify("success", "Excel downloaded");
|
|
421
539
|
} else {
|
|
422
|
-
|
|
423
|
-
notify(
|
|
424
|
-
"success",
|
|
425
|
-
formatMessage(locale.exportCsvSuccess, { count: count.toLocaleString() })
|
|
426
|
-
);
|
|
540
|
+
downloadCsv(timestampedFilename(prefix), exportRows, exportColumns);
|
|
541
|
+
notify("success", "CSV downloaded");
|
|
427
542
|
}
|
|
543
|
+
} catch {
|
|
544
|
+
notify("error", "Export failed");
|
|
428
545
|
} finally {
|
|
429
546
|
setIsExporting(false);
|
|
430
547
|
}
|
|
431
548
|
};
|
|
432
|
-
const
|
|
433
|
-
"
|
|
434
|
-
theme === "dark" ? "
|
|
549
|
+
const rootClasses = [
|
|
550
|
+
"tbx-root",
|
|
551
|
+
theme === "dark" ? "tbx-dark" : theme === "auto" ? "tbx-auto" : void 0,
|
|
435
552
|
className
|
|
436
|
-
].filter(
|
|
553
|
+
].filter(Boolean);
|
|
437
554
|
if (error) {
|
|
438
|
-
return /* @__PURE__ */ jsx3("div", { className:
|
|
439
|
-
/* @__PURE__ */ jsx3("p", { className: "
|
|
440
|
-
onRetry ? /* @__PURE__ */
|
|
555
|
+
return /* @__PURE__ */ jsx3("div", { className: rootClasses.join(" "), "data-density": density, children: /* @__PURE__ */ jsxs2("div", { className: "tbx-state-card", children: [
|
|
556
|
+
/* @__PURE__ */ jsx3("p", { className: "tbx-state-text", children: locale.errorText }),
|
|
557
|
+
onRetry ? /* @__PURE__ */ jsxs2("button", { type: "button", className: "tbx-btn", onClick: onRetry, children: [
|
|
558
|
+
/* @__PURE__ */ jsx3(RotateCcwIcon, { className: "tbx-icon" }),
|
|
559
|
+
/* @__PURE__ */ jsx3("span", { children: locale.retryButton })
|
|
560
|
+
] }) : null
|
|
441
561
|
] }) });
|
|
442
562
|
}
|
|
443
563
|
const rowIsClickable = typeof onRowClick === "function";
|
|
@@ -449,56 +569,57 @@ function NexGrid({
|
|
|
449
569
|
event.preventDefault();
|
|
450
570
|
onRowClick?.(row);
|
|
451
571
|
};
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
572
|
+
const hasSummary = enableSummaryRow === true || visible.some((col) => col.meta?.aggregation !== void 0);
|
|
573
|
+
return /* @__PURE__ */ jsxs2("div", { className: rootClasses.join(" "), "data-density": density, ref: rootRef, children: [
|
|
574
|
+
showToolbar ? /* @__PURE__ */ jsxs2("div", { className: "tbx-toolbar", children: [
|
|
575
|
+
/* @__PURE__ */ jsx3("div", { className: "tbx-toolbar-group", children: enableSearch ? /* @__PURE__ */ jsxs2("div", { className: "tbx-search", children: [
|
|
576
|
+
/* @__PURE__ */ jsx3(SearchIcon, { className: "tbx-search-icon" }),
|
|
577
|
+
/* @__PURE__ */ jsx3(
|
|
578
|
+
"input",
|
|
579
|
+
{
|
|
580
|
+
type: "search",
|
|
581
|
+
className: "tbx-search-input",
|
|
582
|
+
value: searchText,
|
|
583
|
+
onChange: (event) => setSearchText(event.target.value),
|
|
584
|
+
placeholder: searchPlaceholder ?? locale.searchPlaceholder,
|
|
585
|
+
"aria-label": `Search ${caption}`
|
|
586
|
+
}
|
|
587
|
+
),
|
|
588
|
+
searchText ? /* @__PURE__ */ jsxs2(
|
|
589
|
+
"button",
|
|
590
|
+
{
|
|
591
|
+
type: "button",
|
|
592
|
+
className: "tbx-search-clear",
|
|
593
|
+
onClick: () => setSearchText(""),
|
|
594
|
+
"aria-label": locale.clearSearch,
|
|
595
|
+
children: [
|
|
596
|
+
/* @__PURE__ */ jsx3(XIcon, { className: "tbx-icon" }),
|
|
597
|
+
/* @__PURE__ */ jsx3("span", { className: "tbx-sr-only", children: locale.clearSearch })
|
|
598
|
+
]
|
|
599
|
+
}
|
|
600
|
+
) : null
|
|
601
|
+
] }) : null }),
|
|
602
|
+
/* @__PURE__ */ jsxs2("div", { className: "tbx-toolbar-group tbx-toolbar-group--end", children: [
|
|
603
|
+
isColumnsVisible ? /* @__PURE__ */ jsxs2("div", { className: "tbx-menu-wrap", ref: columnsMenu.containerRef, children: [
|
|
483
604
|
/* @__PURE__ */ jsxs2(
|
|
484
605
|
"button",
|
|
485
606
|
{
|
|
486
607
|
type: "button",
|
|
487
608
|
id: columnsButtonId,
|
|
488
|
-
className: "
|
|
609
|
+
className: "tbx-btn",
|
|
489
610
|
ref: columnsMenu.triggerRef,
|
|
490
611
|
"aria-haspopup": "menu",
|
|
491
612
|
"aria-expanded": columnsMenu.isOpen,
|
|
492
613
|
onClick: columnsMenu.toggle,
|
|
493
614
|
children: [
|
|
494
|
-
/* @__PURE__ */ jsx3(
|
|
615
|
+
/* @__PURE__ */ jsx3(ColumnsIcon, { className: "tbx-icon" }),
|
|
495
616
|
/* @__PURE__ */ jsx3("span", { children: locale.columnsButton })
|
|
496
617
|
]
|
|
497
618
|
}
|
|
498
619
|
),
|
|
499
|
-
columnsMenu.isOpen ? /* @__PURE__ */ jsxs2("div", { className: "
|
|
500
|
-
/* @__PURE__ */ jsx3("div", { className: "
|
|
501
|
-
/* @__PURE__ */ jsx3("div", { className: "
|
|
620
|
+
columnsMenu.isOpen ? /* @__PURE__ */ jsxs2("div", { className: "tbx-menu", role: "menu", "aria-labelledby": columnsButtonId, children: [
|
|
621
|
+
/* @__PURE__ */ jsx3("div", { className: "tbx-menu-label", children: locale.toggleColumnsLabel }),
|
|
622
|
+
/* @__PURE__ */ jsx3("div", { className: "tbx-menu-separator" }),
|
|
502
623
|
hideable.map((col) => {
|
|
503
624
|
const id = getColumnId2(col);
|
|
504
625
|
const checked = hiddenCols[id] !== true;
|
|
@@ -506,12 +627,12 @@ function NexGrid({
|
|
|
506
627
|
"button",
|
|
507
628
|
{
|
|
508
629
|
type: "button",
|
|
509
|
-
className: "
|
|
630
|
+
className: "tbx-menu-item",
|
|
510
631
|
role: "menuitemcheckbox",
|
|
511
632
|
"aria-checked": checked,
|
|
512
633
|
onClick: () => toggleColumn(id),
|
|
513
634
|
children: [
|
|
514
|
-
/* @__PURE__ */ jsx3(CheckIcon, { className: "
|
|
635
|
+
/* @__PURE__ */ jsx3(CheckIcon, { className: "tbx-check" }),
|
|
515
636
|
/* @__PURE__ */ jsx3("span", { children: getColumnTitle(col) || id })
|
|
516
637
|
]
|
|
517
638
|
},
|
|
@@ -519,29 +640,29 @@ function NexGrid({
|
|
|
519
640
|
);
|
|
520
641
|
})
|
|
521
642
|
] }) : null
|
|
522
|
-
] }),
|
|
523
|
-
/* @__PURE__ */ jsxs2("div", { className: "
|
|
643
|
+
] }) : null,
|
|
644
|
+
isDensityVisible ? /* @__PURE__ */ jsxs2("div", { className: "tbx-menu-wrap", ref: densityMenu.containerRef, children: [
|
|
524
645
|
/* @__PURE__ */ jsxs2(
|
|
525
646
|
"button",
|
|
526
647
|
{
|
|
527
648
|
type: "button",
|
|
528
649
|
id: densityButtonId,
|
|
529
|
-
className: "
|
|
650
|
+
className: "tbx-btn tbx-capitalize",
|
|
530
651
|
ref: densityMenu.triggerRef,
|
|
531
652
|
"aria-haspopup": "menu",
|
|
532
653
|
"aria-expanded": densityMenu.isOpen,
|
|
533
654
|
onClick: densityMenu.toggle,
|
|
534
655
|
children: [
|
|
535
|
-
/* @__PURE__ */ jsx3(
|
|
656
|
+
/* @__PURE__ */ jsx3(DensityIcon, { className: "tbx-icon" }),
|
|
536
657
|
/* @__PURE__ */ jsx3("span", { children: formatMessage(locale.densityButton, { density }) })
|
|
537
658
|
]
|
|
538
659
|
}
|
|
539
660
|
),
|
|
540
|
-
densityMenu.isOpen ? /* @__PURE__ */ jsx3("div", { className: "
|
|
661
|
+
densityMenu.isOpen ? /* @__PURE__ */ jsx3("div", { className: "tbx-menu", role: "menu", "aria-labelledby": densityButtonId, children: DENSITIES.map((option) => /* @__PURE__ */ jsxs2(
|
|
541
662
|
"button",
|
|
542
663
|
{
|
|
543
664
|
type: "button",
|
|
544
|
-
className: "
|
|
665
|
+
className: "tbx-menu-item",
|
|
545
666
|
role: "menuitemcheckbox",
|
|
546
667
|
"aria-checked": density === option,
|
|
547
668
|
onClick: () => {
|
|
@@ -549,37 +670,36 @@ function NexGrid({
|
|
|
549
670
|
densityMenu.close();
|
|
550
671
|
},
|
|
551
672
|
children: [
|
|
552
|
-
/* @__PURE__ */ jsx3(CheckIcon, { className: "
|
|
673
|
+
/* @__PURE__ */ jsx3(CheckIcon, { className: "tbx-check" }),
|
|
553
674
|
/* @__PURE__ */ jsx3("span", { children: locale[DENSITY_LABEL_KEY[option]] })
|
|
554
675
|
]
|
|
555
676
|
},
|
|
556
677
|
option
|
|
557
678
|
)) }) : null
|
|
558
|
-
] })
|
|
559
|
-
|
|
560
|
-
/* @__PURE__ */ jsxs2("div", { className: "nxg-toolbar-group nxg-toolbar-group--end", children: [
|
|
561
|
-
enableExport ? /* @__PURE__ */ jsxs2("div", { className: "nxg-menu-wrap", ref: exportMenu.containerRef, children: [
|
|
679
|
+
] }) : null,
|
|
680
|
+
isExportVisible ? /* @__PURE__ */ jsxs2("div", { className: "tbx-menu-wrap", ref: exportMenu.containerRef, children: [
|
|
562
681
|
/* @__PURE__ */ jsxs2(
|
|
563
682
|
"button",
|
|
564
683
|
{
|
|
565
684
|
type: "button",
|
|
566
685
|
id: exportButtonId,
|
|
567
|
-
className: "
|
|
686
|
+
className: "tbx-btn tbx-btn--export",
|
|
568
687
|
ref: exportMenu.triggerRef,
|
|
569
688
|
disabled: isExporting,
|
|
570
689
|
"aria-haspopup": "menu",
|
|
571
690
|
"aria-expanded": exportMenu.isOpen,
|
|
572
691
|
onClick: exportMenu.toggle,
|
|
573
692
|
children: [
|
|
574
|
-
/* @__PURE__ */ jsx3(
|
|
575
|
-
/* @__PURE__ */ jsx3("span", { children: isExporting ? locale.exportingButton : locale.exportButton })
|
|
693
|
+
/* @__PURE__ */ jsx3(DownloadTrayIcon, { className: "tbx-icon" }),
|
|
694
|
+
/* @__PURE__ */ jsx3("span", { children: isExporting ? locale.exportingButton : locale.exportButton }),
|
|
695
|
+
/* @__PURE__ */ jsx3(ChevronDownIcon, { className: "tbx-icon tbx-chevron" })
|
|
576
696
|
]
|
|
577
697
|
}
|
|
578
698
|
),
|
|
579
699
|
exportMenu.isOpen ? /* @__PURE__ */ jsxs2(
|
|
580
700
|
"div",
|
|
581
701
|
{
|
|
582
|
-
className: "
|
|
702
|
+
className: "tbx-menu tbx-menu--end",
|
|
583
703
|
role: "menu",
|
|
584
704
|
"aria-labelledby": exportButtonId,
|
|
585
705
|
children: [
|
|
@@ -587,12 +707,12 @@ function NexGrid({
|
|
|
587
707
|
"button",
|
|
588
708
|
{
|
|
589
709
|
type: "button",
|
|
590
|
-
className: "
|
|
710
|
+
className: "tbx-menu-item",
|
|
591
711
|
role: "menuitem",
|
|
592
712
|
onClick: () => void handleExport("excel"),
|
|
593
713
|
children: [
|
|
594
|
-
/* @__PURE__ */ jsx3(FileSpreadsheetIcon, { className: "
|
|
595
|
-
/* @__PURE__ */ jsxs2("div", { className: "
|
|
714
|
+
/* @__PURE__ */ jsx3(FileSpreadsheetIcon, { className: "tbx-icon--excel" }),
|
|
715
|
+
/* @__PURE__ */ jsxs2("div", { className: "tbx-menu-item-title", children: [
|
|
596
716
|
/* @__PURE__ */ jsx3("strong", { children: locale.exportExcelTitle }),
|
|
597
717
|
/* @__PURE__ */ jsx3("small", { children: locale.exportExcelSubtitle })
|
|
598
718
|
] })
|
|
@@ -603,17 +723,33 @@ function NexGrid({
|
|
|
603
723
|
"button",
|
|
604
724
|
{
|
|
605
725
|
type: "button",
|
|
606
|
-
className: "
|
|
726
|
+
className: "tbx-menu-item",
|
|
607
727
|
role: "menuitem",
|
|
608
728
|
onClick: () => void handleExport("csv"),
|
|
609
729
|
children: [
|
|
610
|
-
/* @__PURE__ */ jsx3(FileTextIcon, { className: "
|
|
611
|
-
/* @__PURE__ */ jsxs2("div", { className: "
|
|
730
|
+
/* @__PURE__ */ jsx3(FileTextIcon, { className: "tbx-icon--csv" }),
|
|
731
|
+
/* @__PURE__ */ jsxs2("div", { className: "tbx-menu-item-title", children: [
|
|
612
732
|
/* @__PURE__ */ jsx3("strong", { children: locale.exportCsvTitle }),
|
|
613
733
|
/* @__PURE__ */ jsx3("small", { children: locale.exportCsvSubtitle })
|
|
614
734
|
] })
|
|
615
735
|
]
|
|
616
736
|
}
|
|
737
|
+
),
|
|
738
|
+
/* @__PURE__ */ jsxs2(
|
|
739
|
+
"button",
|
|
740
|
+
{
|
|
741
|
+
type: "button",
|
|
742
|
+
className: "tbx-menu-item",
|
|
743
|
+
role: "menuitem",
|
|
744
|
+
onClick: () => void handleExport("clipboard"),
|
|
745
|
+
children: [
|
|
746
|
+
/* @__PURE__ */ jsx3(FileTextIcon, { className: "tbx-icon--csv" }),
|
|
747
|
+
/* @__PURE__ */ jsxs2("div", { className: "tbx-menu-item-title", children: [
|
|
748
|
+
/* @__PURE__ */ jsx3("strong", { children: locale.exportClipboardTitle }),
|
|
749
|
+
/* @__PURE__ */ jsx3("small", { children: locale.exportClipboardSubtitle })
|
|
750
|
+
] })
|
|
751
|
+
]
|
|
752
|
+
}
|
|
617
753
|
)
|
|
618
754
|
]
|
|
619
755
|
}
|
|
@@ -621,137 +757,539 @@ function NexGrid({
|
|
|
621
757
|
] }) : null,
|
|
622
758
|
toolbarActions
|
|
623
759
|
] })
|
|
624
|
-
] }),
|
|
625
|
-
/* @__PURE__ */ jsx3("div", { className: "
|
|
760
|
+
] }) : null,
|
|
761
|
+
/* @__PURE__ */ jsx3("div", { className: "tbx-table-wrap", children: /* @__PURE__ */ jsxs2("table", { className: "tbx-table", "aria-label": caption, children: [
|
|
626
762
|
/* @__PURE__ */ jsx3("thead", { children: /* @__PURE__ */ jsxs2("tr", { children: [
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
763
|
+
renderExpandedRow ? /* @__PURE__ */ jsx3(
|
|
764
|
+
"th",
|
|
765
|
+
{
|
|
766
|
+
className: [
|
|
767
|
+
"tbx-th tbx-th--expand",
|
|
768
|
+
leftOffsets.has("__expand") ? "tbx-th--pinned-left" : void 0,
|
|
769
|
+
lastLeftPinnedId === "__expand" ? "tbx-pinned-border-left" : void 0
|
|
770
|
+
].filter(Boolean).join(" "),
|
|
771
|
+
style: {
|
|
772
|
+
width: "40px",
|
|
773
|
+
left: leftOffsets.get("__expand")
|
|
774
|
+
},
|
|
775
|
+
scope: "col"
|
|
776
|
+
}
|
|
777
|
+
) : null,
|
|
778
|
+
enableSelection ? /* @__PURE__ */ jsx3(
|
|
779
|
+
"th",
|
|
780
|
+
{
|
|
781
|
+
className: [
|
|
782
|
+
"tbx-th tbx-th--select",
|
|
783
|
+
leftOffsets.has("__select") ? "tbx-th--pinned-left" : void 0,
|
|
784
|
+
lastLeftPinnedId === "__select" ? "tbx-pinned-border-left" : void 0
|
|
785
|
+
].filter(Boolean).join(" "),
|
|
786
|
+
style: {
|
|
787
|
+
left: leftOffsets.get("__select")
|
|
788
|
+
},
|
|
789
|
+
scope: "col",
|
|
790
|
+
children: !isSingleSelect ? /* @__PURE__ */ jsx3(
|
|
791
|
+
"input",
|
|
792
|
+
{
|
|
793
|
+
type: "checkbox",
|
|
794
|
+
className: "tbx-checkbox",
|
|
795
|
+
checked: allPageSelected,
|
|
796
|
+
ref: (el) => {
|
|
797
|
+
if (el) el.indeterminate = somePageSelected;
|
|
798
|
+
},
|
|
799
|
+
onChange: toggleSelectAll,
|
|
800
|
+
"aria-label": locale.selectAllLabel
|
|
801
|
+
}
|
|
802
|
+
) : null
|
|
803
|
+
}
|
|
804
|
+
) : null,
|
|
805
|
+
showSerialNumber ? /* @__PURE__ */ jsx3(
|
|
806
|
+
"th",
|
|
630
807
|
{
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
808
|
+
className: [
|
|
809
|
+
"tbx-th tbx-th--serial",
|
|
810
|
+
leftOffsets.has("__serial") ? "tbx-th--pinned-left" : void 0,
|
|
811
|
+
lastLeftPinnedId === "__serial" ? "tbx-pinned-border-left" : void 0
|
|
812
|
+
].filter(Boolean).join(" "),
|
|
813
|
+
style: {
|
|
814
|
+
left: leftOffsets.get("__serial")
|
|
636
815
|
},
|
|
637
|
-
|
|
638
|
-
|
|
816
|
+
scope: "col",
|
|
817
|
+
children: locale.serialHeader
|
|
639
818
|
}
|
|
640
|
-
)
|
|
819
|
+
) : null,
|
|
641
820
|
visible.map((col, index) => {
|
|
642
821
|
const id = getColumnId2(col);
|
|
643
|
-
const sortable = isSortable(col);
|
|
644
|
-
const
|
|
822
|
+
const sortable = isSortable(col) && enableSorting !== false;
|
|
823
|
+
const sortIndex = query.sort.findIndex((s) => s.field === id);
|
|
824
|
+
const sortItem = sortIndex >= 0 ? query.sort[sortIndex] : void 0;
|
|
825
|
+
const sorted = sortable && sortItem !== void 0;
|
|
645
826
|
const title = getColumnTitle(col) || id;
|
|
646
|
-
|
|
827
|
+
const meta = col.meta;
|
|
828
|
+
const activeFilter = query.filter?.[id];
|
|
829
|
+
const isFilterActive = activeFilter !== void 0 && activeFilter !== "";
|
|
830
|
+
const customWidth = colWidths[id];
|
|
831
|
+
const baseStyle = headerCellStyle(col);
|
|
832
|
+
const thStyle = {
|
|
833
|
+
...baseStyle,
|
|
834
|
+
...customWidth !== void 0 ? { width: `${customWidth}px` } : {},
|
|
835
|
+
...leftOffsets.has(id) ? { left: leftOffsets.get(id) } : {},
|
|
836
|
+
...rightOffsets.has(id) ? { right: rightOffsets.get(id) } : {}
|
|
837
|
+
};
|
|
838
|
+
const startResize = (e) => {
|
|
839
|
+
e.preventDefault();
|
|
840
|
+
e.stopPropagation();
|
|
841
|
+
const startX = e.clientX;
|
|
842
|
+
const targetTh = e.currentTarget.parentElement || null;
|
|
843
|
+
const startWidth = targetTh ? targetTh.getBoundingClientRect().width : customWidth ?? meta?.width ?? 120;
|
|
844
|
+
const onMove = (moveEvent) => {
|
|
845
|
+
const nextW = Math.max(meta?.minWidth ?? 60, Math.round(startWidth + (moveEvent.clientX - startX)));
|
|
846
|
+
setColWidths((prev) => ({ ...prev, [id]: nextW }));
|
|
847
|
+
};
|
|
848
|
+
const onUp = () => {
|
|
849
|
+
document.removeEventListener("pointermove", onMove);
|
|
850
|
+
document.removeEventListener("pointerup", onUp);
|
|
851
|
+
document.body?.classList.remove("tbx-resizing");
|
|
852
|
+
};
|
|
853
|
+
document.body?.classList.add("tbx-resizing");
|
|
854
|
+
document.addEventListener("pointermove", onMove);
|
|
855
|
+
document.addEventListener("pointerup", onUp);
|
|
856
|
+
};
|
|
857
|
+
const isPinnedLeft = leftOffsets.has(id);
|
|
858
|
+
const isPinnedRight = rightOffsets.has(id);
|
|
859
|
+
const isLastLeft = lastLeftPinnedId === id;
|
|
860
|
+
const isFirstRight = firstRightPinnedId === id;
|
|
861
|
+
return /* @__PURE__ */ jsxs2(
|
|
647
862
|
"th",
|
|
648
863
|
{
|
|
649
864
|
scope: "col",
|
|
650
|
-
className:
|
|
651
|
-
|
|
652
|
-
|
|
865
|
+
className: [
|
|
866
|
+
"tbx-th",
|
|
867
|
+
sortable ? "tbx-th--sortable" : void 0,
|
|
868
|
+
enableColumnReorder ? "tbx-th--draggable" : void 0,
|
|
869
|
+
isPinnedLeft ? "tbx-th--pinned-left" : void 0,
|
|
870
|
+
isPinnedRight ? "tbx-th--pinned-right" : void 0,
|
|
871
|
+
isLastLeft ? "tbx-pinned-border-left" : void 0,
|
|
872
|
+
isFirstRight ? "tbx-pinned-border-right" : void 0
|
|
873
|
+
].filter(Boolean).join(" "),
|
|
874
|
+
style: thStyle,
|
|
875
|
+
"aria-sort": sorted ? sortItem?.dir === "asc" ? "ascending" : "descending" : sortable ? "none" : void 0,
|
|
653
876
|
"aria-label": title || void 0,
|
|
654
877
|
tabIndex: sortable ? 0 : void 0,
|
|
655
|
-
|
|
878
|
+
draggable: enableColumnReorder,
|
|
879
|
+
onDragStart: enableColumnReorder ? (e) => {
|
|
880
|
+
setDraggedColId(id);
|
|
881
|
+
e.dataTransfer.setData("text/plain", id);
|
|
882
|
+
} : void 0,
|
|
883
|
+
onDragOver: enableColumnReorder ? (e) => {
|
|
884
|
+
e.preventDefault();
|
|
885
|
+
} : void 0,
|
|
886
|
+
onDrop: enableColumnReorder ? (e) => {
|
|
887
|
+
e.preventDefault();
|
|
888
|
+
if (!draggedColId || draggedColId === id) return;
|
|
889
|
+
const fromIdx = colList.findIndex((c) => getColumnId2(c) === draggedColId);
|
|
890
|
+
const toIdx = colList.findIndex((c) => getColumnId2(c) === id);
|
|
891
|
+
if (fromIdx >= 0 && toIdx >= 0) {
|
|
892
|
+
const nextCols = [...colList];
|
|
893
|
+
const moved = nextCols[fromIdx];
|
|
894
|
+
if (!moved) return;
|
|
895
|
+
nextCols.splice(fromIdx, 1);
|
|
896
|
+
nextCols.splice(toIdx, 0, moved);
|
|
897
|
+
setColList(nextCols);
|
|
898
|
+
onColumnOrderChange?.(nextCols.map(getColumnId2));
|
|
899
|
+
}
|
|
900
|
+
setDraggedColId(null);
|
|
901
|
+
} : void 0,
|
|
902
|
+
onClick: sortable ? (event) => {
|
|
903
|
+
const t = event.target;
|
|
904
|
+
if (t?.closest(".tbx-col-filter-wrap") || t?.closest(".tbx-resize-handle")) return;
|
|
905
|
+
toggleSort(id, event.shiftKey);
|
|
906
|
+
} : void 0,
|
|
656
907
|
onKeyDown: sortable ? (event) => {
|
|
657
908
|
if (event.key !== "Enter" && event.key !== " ") return;
|
|
909
|
+
const t = event.target;
|
|
910
|
+
if (t?.closest(".tbx-col-filter-wrap")) return;
|
|
658
911
|
event.preventDefault();
|
|
659
|
-
toggleSort(id);
|
|
912
|
+
toggleSort(id, event.shiftKey);
|
|
660
913
|
} : void 0,
|
|
661
|
-
children:
|
|
662
|
-
/* @__PURE__ */
|
|
663
|
-
|
|
664
|
-
|
|
914
|
+
children: [
|
|
915
|
+
/* @__PURE__ */ jsxs2("div", { className: headerInnerClass(col), children: [
|
|
916
|
+
/* @__PURE__ */ jsx3("span", { children: renderColumnHeader(col) }),
|
|
917
|
+
sortable ? /* @__PURE__ */ jsxs2("span", { className: "tbx-sort-icon-wrap", children: [
|
|
918
|
+
sorted ? sortItem?.dir === "asc" ? /* @__PURE__ */ jsx3(ArrowUpIcon, { className: "tbx-sort-icon" }) : /* @__PURE__ */ jsx3(ArrowDownIcon, { className: "tbx-sort-icon" }) : /* @__PURE__ */ jsx3(ArrowUpDownIcon, { className: "tbx-sort-icon tbx-sort-icon--idle" }),
|
|
919
|
+
query.sort.length > 1 && sortIndex >= 0 ? /* @__PURE__ */ jsx3("span", { className: "tbx-sort-order", children: sortIndex + 1 }) : null
|
|
920
|
+
] }) : null,
|
|
921
|
+
isFilterable(col, enableColumnFilters) ? /* @__PURE__ */ jsxs2("div", { className: "tbx-col-filter-wrap", children: [
|
|
922
|
+
/* @__PURE__ */ jsx3(
|
|
923
|
+
"button",
|
|
924
|
+
{
|
|
925
|
+
type: "button",
|
|
926
|
+
className: isFilterActive ? "tbx-col-filter-btn tbx-col-filter-btn--active" : "tbx-col-filter-btn",
|
|
927
|
+
"aria-label": `Filter ${title}`,
|
|
928
|
+
onClick: (e) => {
|
|
929
|
+
e.stopPropagation();
|
|
930
|
+
setOpenFilterCol(openFilterCol === id ? null : id);
|
|
931
|
+
},
|
|
932
|
+
children: /* @__PURE__ */ jsx3(DotsVerticalIcon, { className: "tbx-icon" })
|
|
933
|
+
}
|
|
934
|
+
),
|
|
935
|
+
openFilterCol === id ? /* @__PURE__ */ jsxs2(
|
|
936
|
+
"div",
|
|
937
|
+
{
|
|
938
|
+
className: "tbx-filter-popover",
|
|
939
|
+
onClick: (e) => e.stopPropagation(),
|
|
940
|
+
children: [
|
|
941
|
+
/* @__PURE__ */ jsx3(
|
|
942
|
+
"input",
|
|
943
|
+
{
|
|
944
|
+
autoFocus: true,
|
|
945
|
+
type: "text",
|
|
946
|
+
className: "tbx-filter-popover-input",
|
|
947
|
+
defaultValue: activeFilter ?? "",
|
|
948
|
+
placeholder: meta?.filterPlaceholder || formatMessage(locale.filterColumnPlaceholder, { column: title }),
|
|
949
|
+
"aria-label": `Filter ${title}`,
|
|
950
|
+
onChange: (e) => {
|
|
951
|
+
const val = e.currentTarget.value.toLowerCase().trim();
|
|
952
|
+
const pop = e.currentTarget.closest(".tbx-filter-popover");
|
|
953
|
+
const opts = pop?.querySelectorAll(".tbx-filter-option:not(:first-child)");
|
|
954
|
+
opts?.forEach((opt) => {
|
|
955
|
+
const text = opt.textContent?.toLowerCase() ?? "";
|
|
956
|
+
opt.style.display = !val || text.includes(val) ? "" : "none";
|
|
957
|
+
});
|
|
958
|
+
},
|
|
959
|
+
onKeyDown: (e) => {
|
|
960
|
+
if (e.key === "Enter") {
|
|
961
|
+
e.preventDefault();
|
|
962
|
+
const val = e.currentTarget.value.trim();
|
|
963
|
+
setOpenFilterCol(null);
|
|
964
|
+
onQueryChange(withFilter(query, id, val || void 0));
|
|
965
|
+
} else if (e.key === "Escape") {
|
|
966
|
+
e.preventDefault();
|
|
967
|
+
setOpenFilterCol(null);
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
),
|
|
972
|
+
meta?.filterOptions && meta.filterOptions.length > 0 ? /* @__PURE__ */ jsxs2("div", { className: "tbx-filter-popover-options", children: [
|
|
973
|
+
/* @__PURE__ */ jsx3(
|
|
974
|
+
"div",
|
|
975
|
+
{
|
|
976
|
+
className: !activeFilter ? "tbx-filter-option tbx-filter-option--selected" : "tbx-filter-option",
|
|
977
|
+
onClick: () => {
|
|
978
|
+
setOpenFilterCol(null);
|
|
979
|
+
onQueryChange(withFilter(query, id, void 0));
|
|
980
|
+
},
|
|
981
|
+
children: locale.filterAll
|
|
982
|
+
}
|
|
983
|
+
),
|
|
984
|
+
meta.filterOptions.map((opt) => /* @__PURE__ */ jsx3(
|
|
985
|
+
"div",
|
|
986
|
+
{
|
|
987
|
+
className: activeFilter === opt ? "tbx-filter-option tbx-filter-option--selected" : "tbx-filter-option",
|
|
988
|
+
onClick: () => {
|
|
989
|
+
setOpenFilterCol(null);
|
|
990
|
+
onQueryChange(withFilter(query, id, opt));
|
|
991
|
+
},
|
|
992
|
+
children: opt
|
|
993
|
+
},
|
|
994
|
+
opt
|
|
995
|
+
))
|
|
996
|
+
] }) : null,
|
|
997
|
+
/* @__PURE__ */ jsxs2("div", { className: "tbx-filter-popover-actions", children: [
|
|
998
|
+
/* @__PURE__ */ jsxs2(
|
|
999
|
+
"button",
|
|
1000
|
+
{
|
|
1001
|
+
type: "button",
|
|
1002
|
+
className: "tbx-filter-popover-btn",
|
|
1003
|
+
onClick: (e) => {
|
|
1004
|
+
e.stopPropagation();
|
|
1005
|
+
setOpenFilterCol(null);
|
|
1006
|
+
onQueryChange(withFilter(query, id, void 0));
|
|
1007
|
+
},
|
|
1008
|
+
children: [
|
|
1009
|
+
/* @__PURE__ */ jsx3(RotateCcwIcon, { className: "tbx-icon" }),
|
|
1010
|
+
/* @__PURE__ */ jsx3("span", { children: locale.clearFilter })
|
|
1011
|
+
]
|
|
1012
|
+
}
|
|
1013
|
+
),
|
|
1014
|
+
/* @__PURE__ */ jsxs2(
|
|
1015
|
+
"button",
|
|
1016
|
+
{
|
|
1017
|
+
type: "button",
|
|
1018
|
+
className: "tbx-filter-popover-btn tbx-filter-popover-btn--primary",
|
|
1019
|
+
onClick: (e) => {
|
|
1020
|
+
e.stopPropagation();
|
|
1021
|
+
const parent = e.currentTarget.closest(".tbx-filter-popover");
|
|
1022
|
+
const inputEl = parent?.querySelector("input");
|
|
1023
|
+
const val = inputEl?.value.trim();
|
|
1024
|
+
setOpenFilterCol(null);
|
|
1025
|
+
onQueryChange(withFilter(query, id, val || void 0));
|
|
1026
|
+
},
|
|
1027
|
+
children: [
|
|
1028
|
+
/* @__PURE__ */ jsx3(CheckIcon, { className: "tbx-icon" }),
|
|
1029
|
+
/* @__PURE__ */ jsx3("span", { children: locale.applyFilter })
|
|
1030
|
+
]
|
|
1031
|
+
}
|
|
1032
|
+
)
|
|
1033
|
+
] })
|
|
1034
|
+
]
|
|
1035
|
+
}
|
|
1036
|
+
) : null
|
|
1037
|
+
] }) : null
|
|
1038
|
+
] }),
|
|
1039
|
+
enableColumnResize ? /* @__PURE__ */ jsx3("div", { className: "tbx-resize-handle", onPointerDown: startResize }) : null
|
|
1040
|
+
]
|
|
665
1041
|
},
|
|
666
1042
|
id || `col-${index}`
|
|
667
1043
|
);
|
|
668
1044
|
})
|
|
669
1045
|
] }) }),
|
|
670
|
-
/* @__PURE__ */ jsx3("tbody", { children: isLoading ? /* @__PURE__ */ jsx3("tr", { children: /* @__PURE__ */ jsxs2("td", { className: "
|
|
671
|
-
/* @__PURE__ */
|
|
672
|
-
|
|
673
|
-
|
|
1046
|
+
/* @__PURE__ */ jsx3("tbody", { children: isLoading ? /* @__PURE__ */ jsx3("tr", { children: /* @__PURE__ */ jsxs2("td", { className: "tbx-state", colSpan: Math.max(1, columnCount), children: [
|
|
1047
|
+
/* @__PURE__ */ jsxs2("div", { className: "tbx-dotted-loader", "aria-hidden": "true", children: [
|
|
1048
|
+
/* @__PURE__ */ jsx3("span", { className: "tbx-dot" }),
|
|
1049
|
+
/* @__PURE__ */ jsx3("span", { className: "tbx-dot" }),
|
|
1050
|
+
/* @__PURE__ */ jsx3("span", { className: "tbx-dot" }),
|
|
1051
|
+
/* @__PURE__ */ jsx3("span", { className: "tbx-dot" })
|
|
1052
|
+
] }),
|
|
1053
|
+
/* @__PURE__ */ jsx3("div", { className: "tbx-loading-text", "aria-live": "polite", children: locale.loadingText })
|
|
1054
|
+
] }) }) : data.length === 0 ? /* @__PURE__ */ jsx3("tr", { children: /* @__PURE__ */ jsx3("td", { className: "tbx-state", colSpan: Math.max(1, columnCount), children: locale.emptyText }) }) : data.map((row, index) => {
|
|
674
1055
|
const id = pageRowIds[index] ?? String(index);
|
|
675
1056
|
const isSelected = selectedIds.has(id);
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
1057
|
+
const isExpanded = expandedRows.has(id);
|
|
1058
|
+
return /* @__PURE__ */ jsxs2(React4.Fragment, { children: [
|
|
1059
|
+
/* @__PURE__ */ jsxs2(
|
|
1060
|
+
"tr",
|
|
1061
|
+
{
|
|
1062
|
+
className: [
|
|
1063
|
+
"tbx-row",
|
|
1064
|
+
isSelected ? "tbx-row--selected" : void 0,
|
|
1065
|
+
isExpanded ? "tbx-row--expanded" : void 0,
|
|
1066
|
+
rowIsClickable ? "tbx-row--clickable" : void 0
|
|
1067
|
+
].filter(Boolean).join(" "),
|
|
1068
|
+
onClick: rowIsClickable ? activateRow(row) : void 0,
|
|
1069
|
+
onKeyDown: rowIsClickable ? rowKeyDown(row) : void 0,
|
|
1070
|
+
tabIndex: rowIsClickable ? 0 : void 0,
|
|
1071
|
+
children: [
|
|
1072
|
+
renderExpandedRow ? /* @__PURE__ */ jsx3(
|
|
1073
|
+
"td",
|
|
1074
|
+
{
|
|
1075
|
+
className: [
|
|
1076
|
+
"tbx-td tbx-td--expand",
|
|
1077
|
+
leftOffsets.has("__expand") ? "tbx-td--pinned-left" : void 0,
|
|
1078
|
+
lastLeftPinnedId === "__expand" ? "tbx-pinned-border-left" : void 0
|
|
1079
|
+
].filter(Boolean).join(" "),
|
|
1080
|
+
style: {
|
|
1081
|
+
width: "40px",
|
|
1082
|
+
left: leftOffsets.get("__expand")
|
|
1083
|
+
},
|
|
1084
|
+
onClick: (e) => e.stopPropagation(),
|
|
1085
|
+
children: /* @__PURE__ */ jsx3(
|
|
1086
|
+
"button",
|
|
1087
|
+
{
|
|
1088
|
+
type: "button",
|
|
1089
|
+
className: isExpanded ? "tbx-expand-btn tbx-expand-btn--open" : "tbx-expand-btn",
|
|
1090
|
+
"aria-label": isExpanded ? "Collapse row" : "Expand row",
|
|
1091
|
+
onClick: (e) => {
|
|
1092
|
+
e.stopPropagation();
|
|
1093
|
+
toggleExpandRow(id);
|
|
1094
|
+
},
|
|
1095
|
+
children: /* @__PURE__ */ jsx3(ChevronRightIcon, { className: "tbx-icon" })
|
|
1096
|
+
}
|
|
1097
|
+
)
|
|
1098
|
+
}
|
|
1099
|
+
) : null,
|
|
1100
|
+
enableSelection ? /* @__PURE__ */ jsx3(
|
|
1101
|
+
"td",
|
|
1102
|
+
{
|
|
1103
|
+
className: [
|
|
1104
|
+
"tbx-td tbx-td--select",
|
|
1105
|
+
leftOffsets.has("__select") ? "tbx-td--pinned-left" : void 0,
|
|
1106
|
+
lastLeftPinnedId === "__select" ? "tbx-pinned-border-left" : void 0
|
|
1107
|
+
].filter(Boolean).join(" "),
|
|
1108
|
+
style: {
|
|
1109
|
+
left: leftOffsets.get("__select")
|
|
1110
|
+
},
|
|
1111
|
+
onClick: (event) => event.stopPropagation(),
|
|
1112
|
+
children: /* @__PURE__ */ jsx3(
|
|
1113
|
+
"input",
|
|
1114
|
+
{
|
|
1115
|
+
type: isSingleSelect ? "radio" : "checkbox",
|
|
1116
|
+
name: isSingleSelect ? `${instanceId}-select` : void 0,
|
|
1117
|
+
className: "tbx-checkbox",
|
|
1118
|
+
checked: isSelected,
|
|
1119
|
+
onChange: () => toggleSelectRow(id),
|
|
1120
|
+
onClick: (event) => event.stopPropagation(),
|
|
1121
|
+
"aria-label": formatMessage(locale.selectRowLabel, { id })
|
|
1122
|
+
}
|
|
1123
|
+
)
|
|
1124
|
+
}
|
|
1125
|
+
) : null,
|
|
1126
|
+
showSerialNumber ? /* @__PURE__ */ jsx3(
|
|
1127
|
+
"td",
|
|
1128
|
+
{
|
|
1129
|
+
className: [
|
|
1130
|
+
"tbx-td tbx-td--serial",
|
|
1131
|
+
leftOffsets.has("__serial") ? "tbx-td--pinned-left" : void 0,
|
|
1132
|
+
lastLeftPinnedId === "__serial" ? "tbx-pinned-border-left" : void 0
|
|
1133
|
+
].filter(Boolean).join(" "),
|
|
1134
|
+
style: {
|
|
1135
|
+
left: leftOffsets.get("__serial")
|
|
1136
|
+
},
|
|
1137
|
+
children: serialNumber(currentPage, pageSize, index)
|
|
1138
|
+
}
|
|
1139
|
+
) : null,
|
|
1140
|
+
visible.map((col, colIndex) => {
|
|
1141
|
+
const colId = getColumnId2(col);
|
|
1142
|
+
const isPinnedLeft = leftOffsets.has(colId);
|
|
1143
|
+
const isPinnedRight = rightOffsets.has(colId);
|
|
1144
|
+
const isLastLeft = lastLeftPinnedId === colId;
|
|
1145
|
+
const isFirstRight = firstRightPinnedId === colId;
|
|
1146
|
+
const isCellEditable = isEditable(col);
|
|
1147
|
+
const isCurrentlyEditing = editingCell?.rowId === id && editingCell?.columnId === colId;
|
|
1148
|
+
const tdStyle = {
|
|
1149
|
+
...bodyCellStyle(col),
|
|
1150
|
+
...isPinnedLeft ? { left: leftOffsets.get(colId) } : {},
|
|
1151
|
+
...isPinnedRight ? { right: rightOffsets.get(colId) } : {}
|
|
1152
|
+
};
|
|
1153
|
+
return /* @__PURE__ */ jsx3(
|
|
1154
|
+
"td",
|
|
696
1155
|
{
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
1156
|
+
className: [
|
|
1157
|
+
"tbx-td",
|
|
1158
|
+
isCellEditable ? "tbx-cell--editable" : void 0,
|
|
1159
|
+
isPinnedLeft ? "tbx-td--pinned-left" : void 0,
|
|
1160
|
+
isPinnedRight ? "tbx-td--pinned-right" : void 0,
|
|
1161
|
+
isLastLeft ? "tbx-pinned-border-left" : void 0,
|
|
1162
|
+
isFirstRight ? "tbx-pinned-border-right" : void 0
|
|
1163
|
+
].filter(Boolean).join(" "),
|
|
1164
|
+
style: tdStyle,
|
|
1165
|
+
onDoubleClick: isCellEditable ? (e) => {
|
|
1166
|
+
e.stopPropagation();
|
|
1167
|
+
setEditingCell({ rowId: id, columnId: colId });
|
|
1168
|
+
} : void 0,
|
|
1169
|
+
children: isCurrentlyEditing ? /* @__PURE__ */ jsxs2(
|
|
1170
|
+
"div",
|
|
1171
|
+
{
|
|
1172
|
+
className: "tbx-cell-edit-wrap",
|
|
1173
|
+
onClick: (e) => e.stopPropagation(),
|
|
1174
|
+
children: [
|
|
1175
|
+
col.meta?.editType === "select" && col.meta.editOptions ? /* @__PURE__ */ jsx3(
|
|
1176
|
+
"select",
|
|
1177
|
+
{
|
|
1178
|
+
autoFocus: true,
|
|
1179
|
+
className: "tbx-cell-edit-select tbx-cell-edit-input",
|
|
1180
|
+
defaultValue: String(row[colId] ?? ""),
|
|
1181
|
+
id: `${instanceId}-edit-${id}-${colId}`,
|
|
1182
|
+
children: col.meta.editOptions.map((opt) => /* @__PURE__ */ jsx3("option", { value: opt, children: opt }, opt))
|
|
1183
|
+
}
|
|
1184
|
+
) : /* @__PURE__ */ jsx3(
|
|
1185
|
+
"input",
|
|
1186
|
+
{
|
|
1187
|
+
autoFocus: true,
|
|
1188
|
+
type: col.meta?.editType === "number" ? "number" : "text",
|
|
1189
|
+
className: "tbx-cell-edit-input",
|
|
1190
|
+
defaultValue: String(row[colId] ?? ""),
|
|
1191
|
+
id: `${instanceId}-edit-${id}-${colId}`,
|
|
1192
|
+
onKeyDown: (e) => {
|
|
1193
|
+
if (e.key === "Enter") {
|
|
1194
|
+
e.preventDefault();
|
|
1195
|
+
const el = e.currentTarget;
|
|
1196
|
+
const val = col.meta?.editType === "number" ? Number(el.value) : el.value;
|
|
1197
|
+
const oldVal = row[colId];
|
|
1198
|
+
row[colId] = val;
|
|
1199
|
+
onCellEdit?.({ row, columnId: colId, oldValue: oldVal, newValue: val });
|
|
1200
|
+
setEditingCell(null);
|
|
1201
|
+
} else if (e.key === "Escape") {
|
|
1202
|
+
e.preventDefault();
|
|
1203
|
+
setEditingCell(null);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
),
|
|
1208
|
+
/* @__PURE__ */ jsxs2("div", { className: "tbx-cell-edit-actions", children: [
|
|
1209
|
+
/* @__PURE__ */ jsx3(
|
|
1210
|
+
"button",
|
|
1211
|
+
{
|
|
1212
|
+
type: "button",
|
|
1213
|
+
className: "tbx-cell-edit-btn tbx-cell-edit-btn--save",
|
|
1214
|
+
onClick: (e) => {
|
|
1215
|
+
e.stopPropagation();
|
|
1216
|
+
const el = document.getElementById(`${instanceId}-edit-${id}-${colId}`);
|
|
1217
|
+
if (el) {
|
|
1218
|
+
const val = col.meta?.editType === "number" ? Number(el.value) : el.value;
|
|
1219
|
+
const oldVal = row[colId];
|
|
1220
|
+
row[colId] = val;
|
|
1221
|
+
onCellEdit?.({ row, columnId: colId, oldValue: oldVal, newValue: val });
|
|
1222
|
+
}
|
|
1223
|
+
setEditingCell(null);
|
|
1224
|
+
},
|
|
1225
|
+
children: /* @__PURE__ */ jsx3(CheckIcon, { className: "tbx-icon" })
|
|
1226
|
+
}
|
|
1227
|
+
),
|
|
1228
|
+
/* @__PURE__ */ jsx3(
|
|
1229
|
+
"button",
|
|
1230
|
+
{
|
|
1231
|
+
type: "button",
|
|
1232
|
+
className: "tbx-cell-edit-btn tbx-cell-edit-btn--cancel",
|
|
1233
|
+
onClick: (e) => {
|
|
1234
|
+
e.stopPropagation();
|
|
1235
|
+
setEditingCell(null);
|
|
1236
|
+
},
|
|
1237
|
+
children: /* @__PURE__ */ jsx3(XIcon, { className: "tbx-icon" })
|
|
1238
|
+
}
|
|
1239
|
+
)
|
|
1240
|
+
] })
|
|
1241
|
+
]
|
|
1242
|
+
}
|
|
1243
|
+
) : renderCellContent(col, row, boolLabels)
|
|
1244
|
+
},
|
|
1245
|
+
colId || `col-${colIndex}`
|
|
1246
|
+
);
|
|
1247
|
+
})
|
|
1248
|
+
]
|
|
1249
|
+
}
|
|
1250
|
+
),
|
|
1251
|
+
isExpanded && renderExpandedRow ? /* @__PURE__ */ jsx3("tr", { className: "tbx-expanded-row", children: /* @__PURE__ */ jsx3("td", { className: "tbx-expanded-cell", colSpan: columnCount, children: /* @__PURE__ */ jsx3("div", { className: "tbx-detail-panel", children: renderExpandedRow(row) }) }) }) : null
|
|
1252
|
+
] }, id || index);
|
|
720
1253
|
}) })
|
|
721
1254
|
] }) }),
|
|
722
|
-
/* @__PURE__ */ jsx3("div", { className: "
|
|
723
|
-
/* @__PURE__ */
|
|
724
|
-
|
|
725
|
-
|
|
1255
|
+
/* @__PURE__ */ jsx3("div", { className: "tbx-cards", children: isLoading ? /* @__PURE__ */ jsx3("div", { className: "tbx-card", children: /* @__PURE__ */ jsxs2("div", { className: "tbx-state", children: [
|
|
1256
|
+
/* @__PURE__ */ jsxs2("div", { className: "tbx-dotted-loader", "aria-hidden": "true", children: [
|
|
1257
|
+
/* @__PURE__ */ jsx3("span", { className: "tbx-dot" }),
|
|
1258
|
+
/* @__PURE__ */ jsx3("span", { className: "tbx-dot" }),
|
|
1259
|
+
/* @__PURE__ */ jsx3("span", { className: "tbx-dot" }),
|
|
1260
|
+
/* @__PURE__ */ jsx3("span", { className: "tbx-dot" })
|
|
1261
|
+
] }),
|
|
1262
|
+
/* @__PURE__ */ jsx3("div", { className: "tbx-loading-text", "aria-live": "polite", children: locale.loadingText })
|
|
1263
|
+
] }) }) : data.length === 0 ? /* @__PURE__ */ jsx3("div", { className: "tbx-card", children: /* @__PURE__ */ jsx3("div", { className: "tbx-state", children: locale.emptyText }) }) : data.map((row, index) => {
|
|
726
1264
|
const id = pageRowIds[index] ?? String(index);
|
|
727
1265
|
const isSelected = selectedIds.has(id);
|
|
728
1266
|
return /* @__PURE__ */ jsxs2(
|
|
729
1267
|
"div",
|
|
730
1268
|
{
|
|
731
1269
|
className: [
|
|
732
|
-
"
|
|
733
|
-
isSelected ? "
|
|
734
|
-
rowIsClickable ? "
|
|
1270
|
+
"tbx-card",
|
|
1271
|
+
isSelected ? "tbx-card--selected" : void 0,
|
|
1272
|
+
rowIsClickable ? "tbx-card--clickable" : void 0
|
|
735
1273
|
].filter(Boolean).join(" "),
|
|
736
1274
|
onClick: rowIsClickable ? activateRow(row) : void 0,
|
|
737
1275
|
onKeyDown: rowIsClickable ? rowKeyDown(row) : void 0,
|
|
738
1276
|
tabIndex: rowIsClickable ? 0 : void 0,
|
|
739
1277
|
children: [
|
|
740
|
-
showSerialNumber || enableSelection ? /* @__PURE__ */ jsxs2("div", { className: "
|
|
741
|
-
showSerialNumber ? /* @__PURE__ */ jsxs2("span", { className: "
|
|
1278
|
+
showSerialNumber || enableSelection ? /* @__PURE__ */ jsxs2("div", { className: "tbx-card-head", children: [
|
|
1279
|
+
showSerialNumber ? /* @__PURE__ */ jsxs2("span", { className: "tbx-card-serial", children: [
|
|
742
1280
|
"#",
|
|
743
1281
|
serialNumber(currentPage, pageSize, index)
|
|
744
1282
|
] }) : null,
|
|
745
1283
|
enableSelection ? /* @__PURE__ */ jsx3(
|
|
746
1284
|
"span",
|
|
747
1285
|
{
|
|
748
|
-
className: "
|
|
1286
|
+
className: "tbx-card-select",
|
|
749
1287
|
onClick: (event) => event.stopPropagation(),
|
|
750
1288
|
children: /* @__PURE__ */ jsx3(
|
|
751
1289
|
"input",
|
|
752
1290
|
{
|
|
753
1291
|
type: "checkbox",
|
|
754
|
-
className: "
|
|
1292
|
+
className: "tbx-checkbox",
|
|
755
1293
|
checked: isSelected,
|
|
756
1294
|
onChange: () => toggleSelectRow(id),
|
|
757
1295
|
onClick: (event) => event.stopPropagation(),
|
|
@@ -761,9 +1299,9 @@ function NexGrid({
|
|
|
761
1299
|
}
|
|
762
1300
|
) : null
|
|
763
1301
|
] }) : null,
|
|
764
|
-
/* @__PURE__ */ jsx3("dl", { className: "
|
|
1302
|
+
/* @__PURE__ */ jsx3("dl", { className: "tbx-card-rows", children: visible.map((col, colIndex) => {
|
|
765
1303
|
const colId = getColumnId2(col);
|
|
766
|
-
return /* @__PURE__ */ jsxs2("div", { className: "
|
|
1304
|
+
return /* @__PURE__ */ jsxs2("div", { className: "tbx-card-row", children: [
|
|
767
1305
|
/* @__PURE__ */ jsx3("dt", { children: getColumnTitle(col) || colId }),
|
|
768
1306
|
/* @__PURE__ */ jsx3("dd", { children: renderCellContent(col, row, boolLabels) })
|
|
769
1307
|
] }, colId || `col-${colIndex}`);
|
|
@@ -773,52 +1311,55 @@ function NexGrid({
|
|
|
773
1311
|
id || index
|
|
774
1312
|
);
|
|
775
1313
|
}) }),
|
|
776
|
-
/* @__PURE__ */ jsxs2("div", { className: "
|
|
777
|
-
/* @__PURE__ */ jsxs2("div", { className: "
|
|
1314
|
+
showFooter ? /* @__PURE__ */ jsxs2("div", { className: "tbx-footer", children: [
|
|
1315
|
+
/* @__PURE__ */ jsxs2("div", { className: "tbx-range", children: [
|
|
778
1316
|
/* @__PURE__ */ jsx3("span", { children: renderTemplate(locale.showingRange, {
|
|
779
1317
|
start: /* @__PURE__ */ jsx3("strong", { children: range.start }),
|
|
780
1318
|
end: /* @__PURE__ */ jsx3("strong", { children: range.end }),
|
|
781
|
-
total: /* @__PURE__ */ jsx3("strong", { className: "
|
|
1319
|
+
total: /* @__PURE__ */ jsx3("strong", { className: "tbx-range-total", children: total.toLocaleString() })
|
|
782
1320
|
}) }),
|
|
783
|
-
selectedIds.size > 0 ? /* @__PURE__ */ jsx3("span", { className: "
|
|
1321
|
+
selectedIds.size > 0 ? /* @__PURE__ */ jsx3("span", { className: "tbx-selected-badge", children: formatMessage(locale.selectedBadge, { count: selectedIds.size }) }) : null
|
|
784
1322
|
] }),
|
|
785
|
-
/* @__PURE__ */ jsxs2("div", { className: "
|
|
786
|
-
/* @__PURE__ */ jsxs2("div", { className: "
|
|
1323
|
+
/* @__PURE__ */ jsxs2("div", { className: "tbx-pagination", children: [
|
|
1324
|
+
isRowsPerPageVisible ? /* @__PURE__ */ jsxs2("div", { className: "tbx-rows-per-page", children: [
|
|
787
1325
|
/* @__PURE__ */ jsx3("span", { children: locale.rowsPerPage }),
|
|
788
1326
|
/* @__PURE__ */ jsx3(
|
|
789
1327
|
"select",
|
|
790
1328
|
{
|
|
791
|
-
className: "
|
|
1329
|
+
className: "tbx-rows-select",
|
|
792
1330
|
value: String(pageSize),
|
|
793
1331
|
onChange: (event) => {
|
|
794
1332
|
onQueryChange(withPageSize(query, Number.parseInt(event.target.value, 10)));
|
|
795
1333
|
},
|
|
796
1334
|
"aria-label": locale.rowsPerPage,
|
|
797
|
-
children: PAGE_SIZES.map((size) => /* @__PURE__ */
|
|
1335
|
+
children: PAGE_SIZES.map((size) => /* @__PURE__ */ jsxs2("option", { value: size, children: [
|
|
1336
|
+
size,
|
|
1337
|
+
" rows"
|
|
1338
|
+
] }, size))
|
|
798
1339
|
}
|
|
799
1340
|
)
|
|
800
|
-
] }),
|
|
801
|
-
/* @__PURE__ */ jsxs2("div", { className: "
|
|
1341
|
+
] }) : null,
|
|
1342
|
+
isPaginationVisible ? /* @__PURE__ */ jsxs2("div", { className: "tbx-pager", children: [
|
|
802
1343
|
/* @__PURE__ */ jsxs2(
|
|
803
1344
|
"button",
|
|
804
1345
|
{
|
|
805
1346
|
type: "button",
|
|
806
|
-
className: "
|
|
1347
|
+
className: "tbx-page-nav",
|
|
807
1348
|
disabled: currentPage <= 1,
|
|
808
1349
|
onClick: () => onQueryChange(withPage(query, currentPage - 1, totalPages)),
|
|
809
1350
|
"aria-label": locale.previousPage,
|
|
810
1351
|
children: [
|
|
811
1352
|
/* @__PURE__ */ jsx3(ChevronLeftIcon, { size: 16 }),
|
|
812
|
-
/* @__PURE__ */ jsx3("span", { className: "
|
|
1353
|
+
/* @__PURE__ */ jsx3("span", { className: "tbx-sr-only", children: locale.previousPage })
|
|
813
1354
|
]
|
|
814
1355
|
}
|
|
815
1356
|
),
|
|
816
1357
|
pageItems.map(
|
|
817
|
-
(item, index) => item === "..." ? /* @__PURE__ */ jsx3("span", { className: "
|
|
1358
|
+
(item, index) => item === "..." ? /* @__PURE__ */ jsx3("span", { className: "tbx-page-ellipsis", children: "\u2026" }, `gap-${index}`) : /* @__PURE__ */ jsx3(
|
|
818
1359
|
"button",
|
|
819
1360
|
{
|
|
820
1361
|
type: "button",
|
|
821
|
-
className: item === currentPage ? "
|
|
1362
|
+
className: item === currentPage ? "tbx-page-btn tbx-page-btn--current" : "tbx-page-btn",
|
|
822
1363
|
onClick: () => onQueryChange(withPage(query, item, totalPages)),
|
|
823
1364
|
"aria-label": formatMessage(locale.pageLabel, { page: item }),
|
|
824
1365
|
"aria-current": item === currentPage ? "page" : void 0,
|
|
@@ -831,46 +1372,57 @@ function NexGrid({
|
|
|
831
1372
|
"button",
|
|
832
1373
|
{
|
|
833
1374
|
type: "button",
|
|
834
|
-
className: "
|
|
1375
|
+
className: "tbx-page-nav",
|
|
835
1376
|
disabled: currentPage >= totalPages,
|
|
836
1377
|
onClick: () => onQueryChange(withPage(query, currentPage + 1, totalPages)),
|
|
837
1378
|
"aria-label": locale.nextPage,
|
|
838
1379
|
children: [
|
|
839
1380
|
/* @__PURE__ */ jsx3(ChevronRightIcon, { size: 16 }),
|
|
840
|
-
/* @__PURE__ */ jsx3("span", { className: "
|
|
1381
|
+
/* @__PURE__ */ jsx3("span", { className: "tbx-sr-only", children: locale.nextPage })
|
|
841
1382
|
]
|
|
842
1383
|
}
|
|
843
1384
|
)
|
|
844
|
-
] }),
|
|
845
|
-
/* @__PURE__ */ jsxs2(
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
"
|
|
849
|
-
{
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
1385
|
+
] }) : null,
|
|
1386
|
+
isJumpToPageVisible ? /* @__PURE__ */ jsxs2(
|
|
1387
|
+
"form",
|
|
1388
|
+
{
|
|
1389
|
+
className: "tbx-jump",
|
|
1390
|
+
onSubmit: (event) => {
|
|
1391
|
+
event.preventDefault();
|
|
1392
|
+
submitJump(jumpText);
|
|
1393
|
+
},
|
|
1394
|
+
children: [
|
|
1395
|
+
/* @__PURE__ */ jsx3("label", { className: "tbx-jump-label", htmlFor: jumpInputId, children: locale.goToPage }),
|
|
1396
|
+
/* @__PURE__ */ jsx3(
|
|
1397
|
+
"input",
|
|
1398
|
+
{
|
|
1399
|
+
id: jumpInputId,
|
|
1400
|
+
type: "number",
|
|
1401
|
+
className: "tbx-jump-input",
|
|
1402
|
+
min: 1,
|
|
1403
|
+
max: totalPages,
|
|
1404
|
+
value: jumpText,
|
|
1405
|
+
onChange: (event) => setJumpText(event.target.value),
|
|
1406
|
+
onBlur: () => submitJump(jumpText),
|
|
1407
|
+
"aria-label": locale.goToPageOf
|
|
1408
|
+
}
|
|
1409
|
+
)
|
|
1410
|
+
]
|
|
1411
|
+
}
|
|
1412
|
+
) : null
|
|
862
1413
|
] })
|
|
863
|
-
] })
|
|
1414
|
+
] }) : null
|
|
864
1415
|
] });
|
|
865
1416
|
}
|
|
1417
|
+
var NexGrid = TableX;
|
|
866
1418
|
|
|
867
|
-
// src/use-client-
|
|
1419
|
+
// src/use-client-table-x.ts
|
|
868
1420
|
import { useMemo as useMemo2, useState as useState4 } from "react";
|
|
869
1421
|
import {
|
|
870
1422
|
defaultQuery,
|
|
871
1423
|
queryClientData
|
|
872
1424
|
} from "@nexgrid/core";
|
|
873
|
-
function
|
|
1425
|
+
function useClientTableX(allData, options) {
|
|
874
1426
|
const [query, setQuery] = useState4(() => ({
|
|
875
1427
|
...defaultQuery(),
|
|
876
1428
|
...options?.initialQuery
|
|
@@ -890,6 +1442,7 @@ function useClientNexGrid(allData, options) {
|
|
|
890
1442
|
setQuery
|
|
891
1443
|
};
|
|
892
1444
|
}
|
|
1445
|
+
var useClientNexGrid = useClientTableX;
|
|
893
1446
|
|
|
894
1447
|
// src/index.ts
|
|
895
1448
|
import {
|
|
@@ -903,11 +1456,12 @@ import {
|
|
|
903
1456
|
fromODataResponse,
|
|
904
1457
|
primarySort as primarySort2,
|
|
905
1458
|
withToggledSort as withToggledSort2,
|
|
1459
|
+
withToggledMultiSort as withToggledMultiSort2,
|
|
906
1460
|
withSort,
|
|
907
1461
|
withSearch as withSearch2,
|
|
908
1462
|
withPage as withPage2,
|
|
909
1463
|
withPageSize as withPageSize2,
|
|
910
|
-
withFilter,
|
|
1464
|
+
withFilter as withFilter2,
|
|
911
1465
|
totalPagesFor as totalPagesFor2,
|
|
912
1466
|
isPageSize as isPageSize2,
|
|
913
1467
|
PAGE_SIZES as PAGE_SIZES2,
|
|
@@ -920,6 +1474,7 @@ export {
|
|
|
920
1474
|
DEFAULT_PAGE_SIZE,
|
|
921
1475
|
NexGrid,
|
|
922
1476
|
PAGE_SIZES2 as PAGE_SIZES,
|
|
1477
|
+
TableX,
|
|
923
1478
|
buildODataUrl,
|
|
924
1479
|
buildQueryUrl2 as buildQueryUrl,
|
|
925
1480
|
defaultQuery2 as defaultQuery,
|
|
@@ -933,11 +1488,13 @@ export {
|
|
|
933
1488
|
toODataParams,
|
|
934
1489
|
totalPagesFor2 as totalPagesFor,
|
|
935
1490
|
useClientNexGrid,
|
|
936
|
-
|
|
1491
|
+
useClientTableX,
|
|
1492
|
+
withFilter2 as withFilter,
|
|
937
1493
|
withPage2 as withPage,
|
|
938
1494
|
withPageSize2 as withPageSize,
|
|
939
1495
|
withSearch2 as withSearch,
|
|
940
1496
|
withSort,
|
|
1497
|
+
withToggledMultiSort2 as withToggledMultiSort,
|
|
941
1498
|
withToggledSort2 as withToggledSort
|
|
942
1499
|
};
|
|
943
1500
|
//# sourceMappingURL=index.js.map
|