@nexgrid/react 0.1.0 → 0.2.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/dist/index.cjs CHANGED
@@ -35,6 +35,7 @@ __export(index_exports, {
35
35
  DEFAULT_PAGE_SIZE: () => import_core4.DEFAULT_PAGE_SIZE,
36
36
  NexGrid: () => NexGrid,
37
37
  PAGE_SIZES: () => import_core4.PAGE_SIZES,
38
+ TableX: () => TableX,
38
39
  buildODataUrl: () => import_core4.buildODataUrl,
39
40
  buildQueryUrl: () => import_core4.buildQueryUrl,
40
41
  defaultQuery: () => import_core4.defaultQuery,
@@ -48,16 +49,18 @@ __export(index_exports, {
48
49
  toODataParams: () => import_core4.toODataParams,
49
50
  totalPagesFor: () => import_core4.totalPagesFor,
50
51
  useClientNexGrid: () => useClientNexGrid,
52
+ useClientTableX: () => useClientTableX,
51
53
  withFilter: () => import_core4.withFilter,
52
54
  withPage: () => import_core4.withPage,
53
55
  withPageSize: () => import_core4.withPageSize,
54
56
  withSearch: () => import_core4.withSearch,
55
57
  withSort: () => import_core4.withSort,
58
+ withToggledMultiSort: () => import_core4.withToggledMultiSort,
56
59
  withToggledSort: () => import_core4.withToggledSort
57
60
  });
58
61
  module.exports = __toCommonJS(index_exports);
59
62
 
60
- // src/nex-grid.tsx
63
+ // src/table-x.tsx
61
64
  var React4 = __toESM(require("react"), 1);
62
65
  var import_core2 = require("@nexgrid/core");
63
66
 
@@ -99,29 +102,22 @@ function XIcon(props) {
99
102
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m6 6 12 12" })
100
103
  ] });
101
104
  }
102
- function SlidersIcon(props) {
105
+ function ColumnsIcon(props) {
103
106
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Icon, { ...props, children: [
104
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "21", x2: "14", y1: "4", y2: "4" }),
105
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "10", x2: "3", y1: "4", y2: "4" }),
106
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "21", x2: "12", y1: "12", y2: "12" }),
107
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "8", x2: "3", y1: "12", y2: "12" }),
108
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "21", x2: "16", y1: "20", y2: "20" }),
109
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", x2: "3", y1: "20", y2: "20" }),
110
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "14", x2: "14", y1: "2", y2: "6" }),
111
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "8", x2: "8", y1: "10", y2: "14" }),
112
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "16", x2: "16", y1: "18", y2: "22" })
107
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
108
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9 3v18" }),
109
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M15 3v18" })
113
110
  ] });
114
111
  }
115
- function FilterIcon(props) {
116
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polygon", { points: "22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3" }) });
117
- }
118
- function DownloadIcon(props) {
112
+ function DensityIcon(props) {
119
113
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Icon, { ...props, children: [
120
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
121
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "7 10 12 15 17 10" }),
122
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", x2: "12", y1: "15", y2: "3" })
114
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "3", y: "4.5", width: "18", height: "6", rx: "1.5" }),
115
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "3", y: "13.5", width: "18", height: "6", rx: "1.5" })
123
116
  ] });
124
117
  }
118
+ function ChevronDownIcon(props) {
119
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m6 9 6 6 6-6" }) });
120
+ }
125
121
  function FileSpreadsheetIcon(props) {
126
122
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Icon, { ...props, children: [
127
123
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
@@ -170,6 +166,26 @@ function ArrowUpDownIcon(props) {
170
166
  function CheckIcon(props) {
171
167
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M20 6 9 17l-5-5" }) });
172
168
  }
169
+ function RotateCcwIcon(props) {
170
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Icon, { ...props, children: [
171
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
172
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 3v5h5" })
173
+ ] });
174
+ }
175
+ function DownloadTrayIcon(props) {
176
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Icon, { ...props, children: [
177
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
178
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "7 10 12 15 17 10" }),
179
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", x2: "12", y1: "15", y2: "3" })
180
+ ] });
181
+ }
182
+ function DotsVerticalIcon(props) {
183
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Icon, { ...props, children: [
184
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "5", r: "1.5" }),
185
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "1.5" }),
186
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "19", r: "1.5" })
187
+ ] });
188
+ }
173
189
 
174
190
  // src/render.tsx
175
191
  var React = __toESM(require("react"), 1);
@@ -201,9 +217,9 @@ function bodyCellStyle(col) {
201
217
  }
202
218
  function headerInnerClass(col) {
203
219
  const align = col.meta?.align;
204
- if (align === "center") return "nxg-th-inner nxg-th-inner--center";
205
- if (align === "right") return "nxg-th-inner nxg-th-inner--right";
206
- return "nxg-th-inner";
220
+ if (align === "center") return "tbx-th-inner tbx-th-inner--center";
221
+ if (align === "right") return "tbx-th-inner tbx-th-inner--right";
222
+ return "tbx-th-inner";
207
223
  }
208
224
  function renderTemplate(template, values) {
209
225
  const parts = [];
@@ -275,7 +291,7 @@ function useDropdown() {
275
291
  return { isOpen, toggle, close, containerRef, triggerRef };
276
292
  }
277
293
 
278
- // src/nex-grid.tsx
294
+ // src/table-x.tsx
279
295
  var import_jsx_runtime3 = require("react/jsx-runtime");
280
296
  function defaultRowId(row) {
281
297
  const record = row;
@@ -287,53 +303,189 @@ var DENSITY_LABEL_KEY = {
287
303
  default: "densityDefault",
288
304
  comfortable: "densityComfortable"
289
305
  };
290
- function NexGrid({
291
- columns,
292
- data,
293
- total,
294
- query,
295
- onQueryChange,
296
- caption,
297
- density: initialDensity = "default",
298
- isLoading = false,
299
- error = false,
300
- onRetry,
301
- enableSelection = false,
302
- onSelectionChange,
303
- enableSearch = true,
304
- searchPlaceholder,
305
- toolbarActions,
306
- onRowClick,
307
- getRowId = defaultRowId,
308
- className,
309
- showSerialNumber = true,
310
- enableExport = true,
311
- exportFileName,
312
- onExportAll,
313
- fetchEndpoint,
314
- badgeRules,
315
- locale: localeOverrides,
316
- onNotify,
317
- theme = "light"
318
- }) {
306
+ function TableX(props) {
307
+ const {
308
+ columns,
309
+ data,
310
+ total: totalProp,
311
+ query: queryProp,
312
+ onQueryChange: onQueryChangeProp,
313
+ clientSidePagination,
314
+ paginationMode,
315
+ caption,
316
+ density: initialDensity = "default",
317
+ isLoading = false,
318
+ error = false,
319
+ onRetry,
320
+ enableSelection = false,
321
+ selectionMode = "multi",
322
+ enableColumnFilters = true,
323
+ enableColumnResize = true,
324
+ onSelectionChange,
325
+ enableSearch = true,
326
+ searchPlaceholder,
327
+ enableColumns = true,
328
+ showColumnsButton,
329
+ enableDensity = true,
330
+ showDensityButton,
331
+ enableExport = true,
332
+ showExportButton,
333
+ enableSorting = true,
334
+ enablePagination = true,
335
+ showPagination,
336
+ enableRowsPerPage = true,
337
+ showRowsPerPage,
338
+ enableJumpToPage = true,
339
+ showJumpToPage,
340
+ showToolbar = true,
341
+ showFooter = true,
342
+ renderExpandedRow,
343
+ enableBulkActions = true,
344
+ bulkActions,
345
+ enableSummaryRow,
346
+ enableColumnReorder = false,
347
+ onColumnOrderChange,
348
+ onCellEdit,
349
+ storageKey,
350
+ showFilterPills = true,
351
+ toolbarActions,
352
+ onRowClick,
353
+ getRowId = defaultRowId,
354
+ className,
355
+ showSerialNumber = true,
356
+ exportFileName,
357
+ onExportAll,
358
+ fetchEndpoint,
359
+ badgeRules,
360
+ locale: localeOverrides,
361
+ onNotify,
362
+ theme = "light"
363
+ } = props;
364
+ const isClientSide = clientSidePagination === true || paginationMode === "client" || onQueryChangeProp === void 0 && queryProp === void 0;
365
+ const [internalQuery, setInternalQuery] = React4.useState(() => queryProp ?? (0, import_core2.defaultQuery)());
366
+ const query = queryProp ?? internalQuery;
367
+ const onQueryChange = React4.useCallback(
368
+ (next) => {
369
+ setInternalQuery(next);
370
+ onQueryChangeProp?.(next);
371
+ },
372
+ [onQueryChangeProp]
373
+ );
374
+ const clientPaged = React4.useMemo(() => {
375
+ if (!isClientSide) return null;
376
+ return (0, import_core2.queryClientData)(data, query);
377
+ }, [isClientSide, data, query]);
378
+ const rows = isClientSide ? clientPaged?.items ?? data : data;
379
+ const total = isClientSide ? clientPaged?.total ?? data.length : totalProp ?? data.length;
319
380
  const locale = (0, import_core2.resolveLocale)(localeOverrides);
320
381
  const boolLabels = { yes: locale.booleanYes, no: locale.booleanNo };
382
+ const isColumnsVisible = enableColumns && showColumnsButton !== false;
383
+ const isDensityVisible = enableDensity && showDensityButton !== false;
384
+ const isExportVisible = enableExport && showExportButton !== false;
385
+ const isPaginationVisible = enablePagination && showPagination !== false;
386
+ const isRowsPerPageVisible = enableRowsPerPage && showRowsPerPage !== false;
387
+ const isJumpToPageVisible = enableJumpToPage && showJumpToPage !== false;
388
+ const [colList, setColList] = React4.useState(columns);
389
+ React4.useEffect(() => {
390
+ setColList(columns);
391
+ }, [columns]);
321
392
  const [density, setDensity] = React4.useState(initialDensity);
322
393
  const [hiddenCols, setHiddenCols] = React4.useState(
323
- () => (0, import_core2.initialHiddenColumns)(columns)
394
+ () => (0, import_core2.initialHiddenColumns)((0, import_core2.flattenColumns)(columns))
324
395
  );
325
396
  const [selectedIds, setSelectedIds] = React4.useState(
326
397
  () => /* @__PURE__ */ new Set()
327
398
  );
399
+ const [expandedRows, setExpandedRows] = React4.useState(
400
+ () => /* @__PURE__ */ new Set()
401
+ );
402
+ const [editingCell, setEditingCell] = React4.useState(null);
403
+ const [draggedColId, setDraggedColId] = React4.useState(null);
328
404
  const [isExporting, setIsExporting] = React4.useState(false);
405
+ const [openFilterCol, setOpenFilterCol] = React4.useState(null);
406
+ const [colWidths, setColWidths] = React4.useState({});
407
+ React4.useEffect(() => {
408
+ if (!storageKey) return;
409
+ const persisted = (0, import_core2.loadGridState)(storageKey);
410
+ if (persisted) {
411
+ if (persisted.density) setDensity(persisted.density);
412
+ if (persisted.columnWidths) setColWidths(persisted.columnWidths);
413
+ if (persisted.hiddenColumns && Array.isArray(persisted.hiddenColumns)) {
414
+ const hiddenMap = {};
415
+ for (const col of columns) {
416
+ const id = (0, import_core2.getColumnId)(col);
417
+ if (id) hiddenMap[id] = persisted.hiddenColumns.includes(id);
418
+ }
419
+ setHiddenCols(hiddenMap);
420
+ }
421
+ if (persisted.columnOrder && Array.isArray(persisted.columnOrder)) {
422
+ const colMap = new Map(columns.map((c) => [(0, import_core2.getColumnId)(c), c]));
423
+ const reordered = [];
424
+ for (const id of persisted.columnOrder) {
425
+ const col = colMap.get(id);
426
+ if (col) {
427
+ reordered.push(col);
428
+ colMap.delete(id);
429
+ }
430
+ }
431
+ for (const remaining of colMap.values()) {
432
+ reordered.push(remaining);
433
+ }
434
+ if (reordered.length === columns.length) {
435
+ setColList(reordered);
436
+ }
437
+ }
438
+ }
439
+ }, [storageKey, columns]);
440
+ React4.useEffect(() => {
441
+ if (!storageKey) return;
442
+ const hiddenList = Object.entries(hiddenCols).filter(([_, isHidden]) => isHidden).map(([id]) => id);
443
+ (0, import_core2.saveGridState)(storageKey, {
444
+ density,
445
+ columnWidths: colWidths,
446
+ columnOrder: colList.map(import_core2.getColumnId).filter(Boolean),
447
+ hiddenColumns: hiddenList
448
+ });
449
+ }, [storageKey, density, hiddenCols, colList, colWidths]);
329
450
  const columnsMenu = useDropdown();
330
451
  const densityMenu = useDropdown();
331
452
  const exportMenu = useDropdown();
453
+ const handleResetView = React4.useCallback(() => {
454
+ if (storageKey) {
455
+ (0, import_core2.clearGridState)(storageKey);
456
+ }
457
+ setDensity(initialDensity);
458
+ setColWidths({});
459
+ setColList(columns);
460
+ setHiddenCols((0, import_core2.initialHiddenColumns)((0, import_core2.flattenColumns)(columns)));
461
+ columnsMenu.close();
462
+ }, [storageKey, initialDensity, columns, columnsMenu]);
463
+ const leafCols = React4.useMemo(() => (0, import_core2.flattenColumns)(colList), [colList]);
464
+ const autoFitColumn = React4.useCallback((id) => {
465
+ const col = leafCols.find((c) => (0, import_core2.getColumnId)(c) === id);
466
+ if (!col) return;
467
+ const meta = col.meta ?? {};
468
+ let maxContentWidth = 0;
469
+ const headerTitle = (0, import_core2.getColumnTitle)(col) || id;
470
+ maxContentWidth = Math.max(maxContentWidth, headerTitle.length * 8.5 + 50);
471
+ for (const row of rows) {
472
+ const rawVal = (0, import_core2.getCellValue)(col, row);
473
+ const val = (0, import_core2.getCellText)(rawVal);
474
+ if (val) {
475
+ maxContentWidth = Math.max(maxContentWidth, String(val).length * 8 + 26);
476
+ }
477
+ }
478
+ const minW = meta.minWidth ?? 60;
479
+ const maxW = 550;
480
+ const finalWidth = Math.min(maxW, Math.max(minW, Math.round(maxContentWidth)));
481
+ setColWidths((prev) => ({ ...prev, [id]: finalWidth }));
482
+ }, [leafCols, rows]);
332
483
  const instanceId = React4.useId();
333
484
  const columnsButtonId = `${instanceId}-columns`;
334
485
  const densityButtonId = `${instanceId}-density`;
335
486
  const exportButtonId = `${instanceId}-export`;
336
487
  const jumpInputId = `${instanceId}-jump`;
488
+ const rootRef = React4.useRef(null);
337
489
  const notify = (type, message) => {
338
490
  onNotify?.({ type, message });
339
491
  };
@@ -342,127 +494,193 @@ function NexGrid({
342
494
  const totalPages = (0, import_core2.totalPagesFor)(total, pageSize);
343
495
  const range = (0, import_core2.getRecordRange)(currentPage, pageSize, total);
344
496
  const sort = (0, import_core2.primarySort)(query);
497
+ const headerRows = React4.useMemo(
498
+ () => (0, import_core2.buildHeaderRows)(colList, hiddenCols),
499
+ [colList, hiddenCols]
500
+ );
345
501
  const visible = React4.useMemo(
346
- () => (0, import_core2.visibleColumns)(columns, hiddenCols),
347
- [columns, hiddenCols]
502
+ () => (0, import_core2.visibleColumns)(leafCols, hiddenCols),
503
+ [leafCols, hiddenCols]
348
504
  );
349
- const hideable = React4.useMemo(() => columns.filter(import_core2.isHideable), [columns]);
505
+ const hideable = React4.useMemo(() => leafCols.filter(import_core2.isHideable), [leafCols]);
350
506
  const pageItems = React4.useMemo(
351
507
  () => (0, import_core2.getPageNumbers)(currentPage, totalPages),
352
508
  [currentPage, totalPages]
353
509
  );
354
- const pageRowIds = React4.useMemo(() => data.map((row) => getRowId(row)), [data, getRowId]);
355
- const columnCount = visible.length + (showSerialNumber ? 1 : 0) + (enableSelection ? 1 : 0);
510
+ const pageRowIds = React4.useMemo(() => rows.map((row) => getRowId(row)), [rows, getRowId]);
511
+ const columnCount = visible.length + (renderExpandedRow ? 1 : 0) + (showSerialNumber ? 1 : 0) + (enableSelection ? 1 : 0);
512
+ const getPinnedOffsets = (visibleCols) => {
513
+ const leftOffsets2 = /* @__PURE__ */ new Map();
514
+ const rightOffsets2 = /* @__PURE__ */ new Map();
515
+ let currentLeft = 0;
516
+ let lastLeftPinnedId2 = null;
517
+ if (renderExpandedRow) {
518
+ leftOffsets2.set("__expand", currentLeft);
519
+ currentLeft += 40;
520
+ lastLeftPinnedId2 = "__expand";
521
+ }
522
+ if (enableSelection) {
523
+ leftOffsets2.set("__select", currentLeft);
524
+ currentLeft += 44;
525
+ lastLeftPinnedId2 = "__select";
526
+ }
527
+ if (showSerialNumber) {
528
+ leftOffsets2.set("__serial", currentLeft);
529
+ currentLeft += 56;
530
+ lastLeftPinnedId2 = "__serial";
531
+ }
532
+ for (const col of visibleCols) {
533
+ const id = (0, import_core2.getColumnId)(col);
534
+ const pin = col.meta?.pinned;
535
+ const width = colWidths[id] ?? col.meta?.width ?? 140;
536
+ if (pin === "left") {
537
+ leftOffsets2.set(id, currentLeft);
538
+ currentLeft += width;
539
+ lastLeftPinnedId2 = id;
540
+ }
541
+ }
542
+ let currentRight = 0;
543
+ let firstRightPinnedId2 = null;
544
+ for (let i = visibleCols.length - 1; i >= 0; i--) {
545
+ const col = visibleCols[i];
546
+ if (!col) continue;
547
+ const id = (0, import_core2.getColumnId)(col);
548
+ const pin = col.meta?.pinned;
549
+ const width = colWidths[id] ?? col.meta?.width ?? 140;
550
+ if (pin === "right") {
551
+ rightOffsets2.set(id, currentRight);
552
+ currentRight += width;
553
+ firstRightPinnedId2 = id;
554
+ }
555
+ }
556
+ return { leftOffsets: leftOffsets2, rightOffsets: rightOffsets2, lastLeftPinnedId: lastLeftPinnedId2, firstRightPinnedId: firstRightPinnedId2 };
557
+ };
558
+ const { leftOffsets, rightOffsets, lastLeftPinnedId, firstRightPinnedId } = getPinnedOffsets(visible);
356
559
  const [searchText, setSearchText] = useDebouncedSearch(query.q ?? "", (text) => {
357
560
  onQueryChange((0, import_core2.withSearch)(query, text));
358
561
  });
359
562
  const [jumpText, setJumpText] = React4.useState(() => String(currentPage));
360
563
  React4.useEffect(() => setJumpText(String(currentPage)), [currentPage]);
361
- const submitJump = (event) => {
362
- event?.preventDefault();
363
- const parsed = Number.parseInt(jumpText, 10);
364
- if (Number.isFinite(parsed) && parsed >= 1 && parsed <= totalPages) {
365
- setJumpText(String(parsed));
366
- if (parsed !== currentPage) onQueryChange((0, import_core2.withPage)(query, parsed, totalPages));
564
+ const submitJump = (raw) => {
565
+ const page = Number.parseInt(raw, 10);
566
+ if (Number.isNaN(page) || page < 1 || page > totalPages) {
567
+ setJumpText(String(currentPage));
367
568
  return;
368
569
  }
369
- setJumpText(String(currentPage));
570
+ if (page !== currentPage) {
571
+ onQueryChange((0, import_core2.withPage)(query, page, totalPages));
572
+ }
370
573
  };
371
- const toggleSort = (columnId) => {
372
- onQueryChange((0, import_core2.withToggledSort)(query, columnId));
574
+ const toggleSort = (field, multiSort = false) => {
575
+ const next = multiSort ? (0, import_core2.withToggledMultiSort)(query, field) : (0, import_core2.withToggledSort)(query, field);
576
+ onQueryChange(next);
373
577
  };
374
- const selectedOnPage = pageRowIds.filter((id) => selectedIds.has(id)).length;
375
- const allPageSelected = pageRowIds.length > 0 && selectedOnPage === pageRowIds.length;
376
- const somePageSelected = selectedOnPage > 0 && !allPageSelected;
377
- const commitSelection = (next) => {
578
+ const isSingleSelect = selectionMode === "single";
579
+ const allPageSelected = pageRowIds.length > 0 && pageRowIds.every((id) => selectedIds.has(id));
580
+ const somePageSelected = !allPageSelected && pageRowIds.some((id) => selectedIds.has(id));
581
+ const toggleSelectAll = () => {
582
+ if (isSingleSelect) return;
583
+ const next = new Set(selectedIds);
584
+ if (allPageSelected) {
585
+ for (const id of pageRowIds) next.delete(id);
586
+ } else {
587
+ for (const id of pageRowIds) next.add(id);
588
+ }
378
589
  setSelectedIds(next);
379
590
  onSelectionChange?.(Array.from(next), false);
380
591
  };
381
- const toggleSelectAll = () => {
382
- const next = new Set(selectedIds);
383
- for (const id of pageRowIds) {
384
- if (allPageSelected) next.delete(id);
592
+ const toggleSelectRow = (id) => {
593
+ const next = isSingleSelect ? selectedIds.has(id) ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([id]) : new Set(selectedIds);
594
+ if (!isSingleSelect) {
595
+ if (next.has(id)) next.delete(id);
385
596
  else next.add(id);
386
597
  }
387
- commitSelection(next);
598
+ setSelectedIds(next);
599
+ onSelectionChange?.(Array.from(next), false);
388
600
  };
389
- const toggleSelectRow = (id) => {
390
- const next = new Set(selectedIds);
391
- if (next.has(id)) next.delete(id);
392
- else next.add(id);
393
- commitSelection(next);
601
+ const deselectAll = () => {
602
+ setSelectedIds(/* @__PURE__ */ new Set());
603
+ onSelectionChange?.([], false);
604
+ };
605
+ const toggleExpandRow = (id) => {
606
+ setExpandedRows((prev) => {
607
+ const next = new Set(prev);
608
+ if (next.has(id)) next.delete(id);
609
+ else next.add(id);
610
+ return next;
611
+ });
394
612
  };
395
613
  const toggleColumn = (columnId) => {
396
614
  setHiddenCols((prev) => ({ ...prev, [columnId]: prev[columnId] !== true }));
397
615
  };
398
- const collectExportRows = async () => {
399
- if (data.length >= total || !fetchEndpoint) return data;
400
- notify("info", (0, import_core2.formatMessage)(locale.exportFetchingAll, { total: total.toLocaleString() }));
401
- try {
402
- const result = await (0, import_core2.fetchAllPages)(async (page, size) => {
403
- const url = (0, import_core2.buildQueryUrl)(fetchEndpoint, {
404
- ...query,
405
- page,
406
- pageSize: (0, import_core2.isPageSize)(size) ? size : query.pageSize
407
- });
408
- const response = await fetch(url, { cache: "no-store" });
409
- if (!response.ok) throw new Error(`HTTP ${response.status}`);
410
- return await response.json();
411
- });
412
- return result.items;
413
- } catch {
414
- notify("error", locale.exportFetchFailed);
415
- return data;
416
- }
417
- };
418
616
  const handleExport = async (format) => {
419
617
  exportMenu.close();
420
618
  if (onExportAll) {
421
- void onExportAll();
619
+ try {
620
+ await onExportAll();
621
+ } catch (err) {
622
+ notify("error", err instanceof Error ? err.message : "Export failed");
623
+ }
422
624
  return;
423
625
  }
424
626
  setIsExporting(true);
627
+ notify("info", "Exporting...");
425
628
  try {
426
- const rows = await collectExportRows();
427
- if (rows.length === 0) {
428
- notify("error", locale.exportNoData);
429
- return;
629
+ let exportRows = rows;
630
+ if (fetchEndpoint) {
631
+ const full = await (0, import_core2.fetchAllPages)(async (page, size) => {
632
+ const url = (0, import_core2.buildQueryUrl)(fetchEndpoint, {
633
+ ...query,
634
+ page,
635
+ pageSize: (0, import_core2.isPageSize)(size) ? size : query.pageSize
636
+ });
637
+ const response = await fetch(url, { cache: "no-store" });
638
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
639
+ return await response.json();
640
+ });
641
+ exportRows = full.items;
642
+ } else if (isClientSide) {
643
+ const full = (0, import_core2.queryClientData)(data, query, { paginate: false });
644
+ exportRows = full.items;
430
645
  }
431
646
  const exportColumns = (0, import_core2.toExportColumns)(visible, boolLabels);
432
647
  const prefix = exportFileName ?? (0, import_core2.filePrefixFromCaption)(caption);
433
- if (format === "excel") {
434
- const count = (0, import_core2.downloadExcel)({
648
+ if (format === "clipboard") {
649
+ const ok = await (0, import_core2.copyToClipboard)(exportRows, exportColumns);
650
+ if (ok) notify("success", "Copied to clipboard");
651
+ else notify("error", "Failed to copy to clipboard");
652
+ } else if (format === "excel") {
653
+ (0, import_core2.downloadExcel)({
435
654
  filename: prefix,
436
655
  caption,
437
- rows,
656
+ rows: exportRows,
438
657
  columns: exportColumns,
439
658
  badgeRules,
440
659
  serialHeader: locale.serialHeader
441
660
  });
442
- notify(
443
- "success",
444
- (0, import_core2.formatMessage)(locale.exportExcelSuccess, { count: count.toLocaleString() })
445
- );
661
+ notify("success", "Excel downloaded");
446
662
  } else {
447
- const count = (0, import_core2.downloadCsv)((0, import_core2.timestampedFilename)(prefix), rows, exportColumns);
448
- notify(
449
- "success",
450
- (0, import_core2.formatMessage)(locale.exportCsvSuccess, { count: count.toLocaleString() })
451
- );
663
+ (0, import_core2.downloadCsv)((0, import_core2.timestampedFilename)(prefix), exportRows, exportColumns);
664
+ notify("success", "CSV downloaded");
452
665
  }
666
+ } catch {
667
+ notify("error", "Export failed");
453
668
  } finally {
454
669
  setIsExporting(false);
455
670
  }
456
671
  };
457
- const rootClassName = [
458
- "nxg-root",
459
- theme === "dark" ? "nxg-dark" : theme === "auto" ? "nxg-auto" : void 0,
672
+ const rootClasses = [
673
+ "tbx-root",
674
+ theme === "dark" ? "tbx-dark" : theme === "auto" ? "tbx-auto" : void 0,
460
675
  className
461
- ].filter((part) => Boolean(part)).join(" ");
676
+ ].filter(Boolean);
462
677
  if (error) {
463
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: rootClassName, "data-density": density, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-state-card", children: [
464
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "nxg-state-text", children: locale.errorText }),
465
- onRetry ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "nxg-btn", onClick: onRetry, children: locale.retryButton }) : null
678
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: rootClasses.join(" "), "data-density": density, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-state-card", children: [
679
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "tbx-state-text", children: locale.errorText }),
680
+ onRetry ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("button", { type: "button", className: "tbx-btn", onClick: onRetry, children: [
681
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(RotateCcwIcon, { className: "tbx-icon" }),
682
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: locale.retryButton })
683
+ ] }) : null
466
684
  ] }) });
467
685
  }
468
686
  const rowIsClickable = typeof onRowClick === "function";
@@ -474,56 +692,256 @@ function NexGrid({
474
692
  event.preventDefault();
475
693
  onRowClick?.(row);
476
694
  };
477
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: rootClassName, "data-density": density, children: [
478
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-toolbar", children: [
479
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-toolbar-group", children: [
480
- enableSearch ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-search", children: [
481
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SearchIcon, { className: "nxg-search-icon" }),
482
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
483
- "input",
484
- {
485
- type: "search",
486
- className: "nxg-search-input",
487
- value: searchText,
488
- onChange: (event) => setSearchText(event.target.value),
489
- placeholder: searchPlaceholder ?? locale.searchPlaceholder,
490
- "aria-label": `Search ${caption}`
491
- }
492
- ),
493
- searchText ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
494
- "button",
695
+ const hasSummary = enableSummaryRow === true || visible.some((col) => col.meta?.aggregation !== void 0);
696
+ const renderLeafTh = (col, rowSpan = 1, isGroupChild = false) => {
697
+ const id = (0, import_core2.getColumnId)(col);
698
+ const sortable = (0, import_core2.isSortable)(col) && enableSorting !== false;
699
+ const sortIndex = query.sort.findIndex((s) => s.field === id);
700
+ const sortItem = sortIndex >= 0 ? query.sort[sortIndex] : void 0;
701
+ const sorted = sortable && sortItem !== void 0;
702
+ const title = (0, import_core2.getColumnTitle)(col) || id;
703
+ const meta = col.meta;
704
+ const activeFilter = query.filter?.[id];
705
+ const isFilterActive = activeFilter !== void 0 && activeFilter !== "";
706
+ const customWidth = colWidths[id];
707
+ const baseStyle = headerCellStyle(col);
708
+ const thStyle = {
709
+ ...baseStyle,
710
+ ...customWidth !== void 0 ? { width: `${customWidth}px` } : {},
711
+ ...leftOffsets.has(id) ? { left: leftOffsets.get(id) } : {},
712
+ ...rightOffsets.has(id) ? { right: rightOffsets.get(id) } : {}
713
+ };
714
+ const startResize = (e) => {
715
+ e.preventDefault();
716
+ e.stopPropagation();
717
+ const startX = e.clientX;
718
+ const targetTh = e.currentTarget.parentElement || null;
719
+ const startWidth = targetTh ? targetTh.getBoundingClientRect().width : customWidth ?? meta?.width ?? 120;
720
+ const onMove = (moveEvent) => {
721
+ const nextW = Math.max(meta?.minWidth ?? 60, Math.round(startWidth + (moveEvent.clientX - startX)));
722
+ setColWidths((prev) => ({ ...prev, [id]: nextW }));
723
+ };
724
+ const onUp = () => {
725
+ document.removeEventListener("pointermove", onMove);
726
+ document.removeEventListener("pointerup", onUp);
727
+ document.body?.classList.remove("tbx-resizing");
728
+ };
729
+ document.body?.classList.add("tbx-resizing");
730
+ document.addEventListener("pointermove", onMove);
731
+ document.addEventListener("pointerup", onUp);
732
+ };
733
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
734
+ "th",
735
+ {
736
+ scope: "col",
737
+ rowSpan: rowSpan > 1 ? rowSpan : void 0,
738
+ "aria-sort": !sortable ? void 0 : sorted ? sortItem?.dir === "asc" ? "ascending" : "descending" : "none",
739
+ tabIndex: sortable ? 0 : void 0,
740
+ "data-column-id": id,
741
+ "data-tbx-focus": sortable ? `sort:${id}` : void 0,
742
+ draggable: enableColumnReorder && !isGroupChild,
743
+ onDragStart: enableColumnReorder && !isGroupChild ? (e) => {
744
+ setDraggedColId(id);
745
+ e.dataTransfer.effectAllowed = "move";
746
+ e.dataTransfer.setData("text/plain", id);
747
+ } : void 0,
748
+ onDragOver: enableColumnReorder && !isGroupChild ? (e) => {
749
+ e.preventDefault();
750
+ } : void 0,
751
+ onDrop: enableColumnReorder && !isGroupChild ? (e) => {
752
+ e.preventDefault();
753
+ if (!draggedColId || draggedColId === id) return;
754
+ const fromIdx = colList.findIndex((c) => (0, import_core2.getColumnId)(c) === draggedColId);
755
+ const toIdx = colList.findIndex((c) => (0, import_core2.getColumnId)(c) === id);
756
+ if (fromIdx >= 0 && toIdx >= 0) {
757
+ const nextCols = [...colList];
758
+ const moved = nextCols[fromIdx];
759
+ if (!moved) return;
760
+ nextCols.splice(fromIdx, 1);
761
+ nextCols.splice(toIdx, 0, moved);
762
+ setColList(nextCols);
763
+ onColumnOrderChange?.(nextCols.map(import_core2.getColumnId));
764
+ }
765
+ } : void 0,
766
+ onDragEnd: enableColumnReorder && !isGroupChild ? () => {
767
+ setDraggedColId(null);
768
+ } : void 0,
769
+ className: [
770
+ "tbx-th",
771
+ sortable ? "tbx-th--sortable" : void 0,
772
+ isGroupChild ? "tbx-th--grouped-child" : void 0,
773
+ enableColumnReorder && !isGroupChild ? "tbx-th--draggable" : void 0,
774
+ draggedColId === id ? "tbx-th--dragging" : void 0,
775
+ (0, import_core2.isPinned)(col) === "left" ? "tbx-th--pinned-left" : void 0,
776
+ (0, import_core2.isPinned)(col) === "right" ? "tbx-th--pinned-right" : void 0,
777
+ lastLeftPinnedId === id ? "tbx-pinned-border-left" : void 0,
778
+ firstRightPinnedId === id ? "tbx-pinned-border-right" : void 0
779
+ ].filter(Boolean).join(" "),
780
+ style: thStyle,
781
+ onClick: sortable ? (event) => {
782
+ const t = event.target;
783
+ if (t?.closest(".tbx-col-filter-wrap") || t?.closest(".tbx-resize-handle")) return;
784
+ toggleSort(id, event.shiftKey);
785
+ } : void 0,
786
+ onKeyDown: sortable ? (event) => {
787
+ if (event.key !== "Enter" && event.key !== " ") return;
788
+ const t = event.target;
789
+ if (t?.closest(".tbx-col-filter-wrap")) return;
790
+ event.preventDefault();
791
+ toggleSort(id, event.shiftKey);
792
+ } : void 0,
793
+ children: [
794
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: headerInnerClass(col), children: [
795
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: renderColumnHeader(col) }),
796
+ sortable ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "tbx-sort-icon-wrap", children: [
797
+ sorted ? sortItem?.dir === "asc" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ArrowUpIcon, { className: "tbx-sort-icon" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ArrowDownIcon, { className: "tbx-sort-icon" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ArrowUpDownIcon, { className: "tbx-sort-icon tbx-sort-icon--idle" }),
798
+ query.sort.length > 1 && sortIndex >= 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "tbx-sort-order", children: sortIndex + 1 }) : null
799
+ ] }) : null,
800
+ (0, import_core2.isFilterable)(col, enableColumnFilters) ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-col-filter-wrap", children: [
801
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
802
+ "button",
803
+ {
804
+ type: "button",
805
+ className: isFilterActive ? "tbx-col-filter-btn tbx-col-filter-btn--active" : "tbx-col-filter-btn",
806
+ "aria-label": `Filter ${title}`,
807
+ onClick: (e) => {
808
+ e.stopPropagation();
809
+ setOpenFilterCol(openFilterCol === id ? null : id);
810
+ },
811
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DotsVerticalIcon, { className: "tbx-icon" })
812
+ }
813
+ ),
814
+ openFilterCol === id ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
815
+ "div",
816
+ {
817
+ className: "tbx-filter-popover",
818
+ onClick: (e) => e.stopPropagation(),
819
+ children: [
820
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
821
+ "input",
822
+ {
823
+ autoFocus: true,
824
+ type: "text",
825
+ className: "tbx-filter-popover-input",
826
+ defaultValue: activeFilter ?? "",
827
+ placeholder: `Filter by ${title}...`,
828
+ onKeyDown: (e) => {
829
+ if (e.key === "Enter") {
830
+ e.preventDefault();
831
+ const val = e.currentTarget.value.trim();
832
+ setOpenFilterCol(null);
833
+ onQueryChange((0, import_core2.withFilter)(query, id, val || void 0));
834
+ } else if (e.key === "Escape") {
835
+ setOpenFilterCol(null);
836
+ }
837
+ }
838
+ }
839
+ ),
840
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-filter-popover-actions", children: [
841
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
842
+ "button",
843
+ {
844
+ type: "button",
845
+ className: "tbx-filter-popover-btn",
846
+ onClick: (e) => {
847
+ e.stopPropagation();
848
+ setOpenFilterCol(null);
849
+ onQueryChange((0, import_core2.withFilter)(query, id, void 0));
850
+ },
851
+ children: [
852
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(RotateCcwIcon, { className: "tbx-icon" }),
853
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: locale.clearFilter })
854
+ ]
855
+ }
856
+ ),
857
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
858
+ "button",
859
+ {
860
+ type: "button",
861
+ className: "tbx-filter-popover-btn tbx-filter-popover-btn--primary",
862
+ onClick: (e) => {
863
+ e.stopPropagation();
864
+ const parent = e.currentTarget.closest(".tbx-filter-popover");
865
+ const inputEl = parent?.querySelector("input");
866
+ const val = inputEl?.value.trim();
867
+ setOpenFilterCol(null);
868
+ onQueryChange((0, import_core2.withFilter)(query, id, val || void 0));
869
+ },
870
+ children: [
871
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CheckIcon, { className: "tbx-icon" }),
872
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: locale.applyFilter })
873
+ ]
874
+ }
875
+ )
876
+ ] })
877
+ ]
878
+ }
879
+ ) : null
880
+ ] }) : null
881
+ ] }),
882
+ enableColumnResize ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
883
+ "div",
495
884
  {
496
- type: "button",
497
- className: "nxg-search-clear",
498
- onClick: () => setSearchText(""),
499
- "aria-label": locale.clearSearch,
500
- children: [
501
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(XIcon, { className: "nxg-icon" }),
502
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "nxg-sr-only", children: locale.clearSearch })
503
- ]
885
+ className: "tbx-resize-handle",
886
+ onPointerDown: startResize,
887
+ onDoubleClick: () => autoFitColumn(id)
504
888
  }
505
889
  ) : null
506
- ] }) : null,
507
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-menu-wrap", ref: columnsMenu.containerRef, children: [
890
+ ]
891
+ },
892
+ id
893
+ );
894
+ };
895
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: rootClasses.join(" "), "data-density": density, ref: rootRef, children: [
896
+ showToolbar ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-toolbar", children: [
897
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "tbx-toolbar-group", children: enableSearch ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-search", children: [
898
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SearchIcon, { className: "tbx-search-icon" }),
899
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
900
+ "input",
901
+ {
902
+ type: "search",
903
+ className: "tbx-search-input",
904
+ value: searchText,
905
+ onChange: (event) => setSearchText(event.target.value),
906
+ placeholder: searchPlaceholder ?? locale.searchPlaceholder,
907
+ "aria-label": `Search ${caption}`
908
+ }
909
+ ),
910
+ searchText ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
911
+ "button",
912
+ {
913
+ type: "button",
914
+ className: "tbx-search-clear",
915
+ onClick: () => setSearchText(""),
916
+ "aria-label": locale.clearSearch,
917
+ children: [
918
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(XIcon, { className: "tbx-icon" }),
919
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "tbx-sr-only", children: locale.clearSearch })
920
+ ]
921
+ }
922
+ ) : null
923
+ ] }) : null }),
924
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-toolbar-group tbx-toolbar-group--end", children: [
925
+ isColumnsVisible ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-menu-wrap", ref: columnsMenu.containerRef, children: [
508
926
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
509
927
  "button",
510
928
  {
511
929
  type: "button",
512
930
  id: columnsButtonId,
513
- className: "nxg-btn",
931
+ className: "tbx-btn",
514
932
  ref: columnsMenu.triggerRef,
515
933
  "aria-haspopup": "menu",
516
934
  "aria-expanded": columnsMenu.isOpen,
517
935
  onClick: columnsMenu.toggle,
518
936
  children: [
519
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SlidersIcon, { className: "nxg-icon" }),
937
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ColumnsIcon, { className: "tbx-icon" }),
520
938
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: locale.columnsButton })
521
939
  ]
522
940
  }
523
941
  ),
524
- columnsMenu.isOpen ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-menu", role: "menu", "aria-labelledby": columnsButtonId, children: [
525
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "nxg-menu-label", children: locale.toggleColumnsLabel }),
526
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "nxg-menu-separator" }),
942
+ columnsMenu.isOpen ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-menu", role: "menu", "aria-labelledby": columnsButtonId, children: [
943
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "tbx-menu-label", children: locale.toggleColumnsLabel }),
944
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "tbx-menu-separator" }),
527
945
  hideable.map((col) => {
528
946
  const id = (0, import_core2.getColumnId)(col);
529
947
  const checked = hiddenCols[id] !== true;
@@ -531,42 +949,55 @@ function NexGrid({
531
949
  "button",
532
950
  {
533
951
  type: "button",
534
- className: "nxg-menu-item",
952
+ className: "tbx-menu-item",
535
953
  role: "menuitemcheckbox",
536
954
  "aria-checked": checked,
537
955
  onClick: () => toggleColumn(id),
538
956
  children: [
539
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CheckIcon, { className: "nxg-check" }),
957
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CheckIcon, { className: "tbx-check" }),
540
958
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: (0, import_core2.getColumnTitle)(col) || id })
541
959
  ]
542
960
  },
543
961
  id
544
962
  );
545
- })
963
+ }),
964
+ storageKey ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
965
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "tbx-menu-separator" }),
966
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
967
+ "button",
968
+ {
969
+ type: "button",
970
+ className: "tbx-menu-item tbx-menu-item--reset",
971
+ role: "menuitem",
972
+ onClick: handleResetView,
973
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Reset to default view" })
974
+ }
975
+ )
976
+ ] }) : null
546
977
  ] }) : null
547
- ] }),
548
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-menu-wrap", ref: densityMenu.containerRef, children: [
978
+ ] }) : null,
979
+ isDensityVisible ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-menu-wrap", ref: densityMenu.containerRef, children: [
549
980
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
550
981
  "button",
551
982
  {
552
983
  type: "button",
553
984
  id: densityButtonId,
554
- className: "nxg-btn nxg-capitalize",
985
+ className: "tbx-btn tbx-capitalize",
555
986
  ref: densityMenu.triggerRef,
556
987
  "aria-haspopup": "menu",
557
988
  "aria-expanded": densityMenu.isOpen,
558
989
  onClick: densityMenu.toggle,
559
990
  children: [
560
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FilterIcon, { className: "nxg-icon" }),
991
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DensityIcon, { className: "tbx-icon" }),
561
992
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: (0, import_core2.formatMessage)(locale.densityButton, { density }) })
562
993
  ]
563
994
  }
564
995
  ),
565
- densityMenu.isOpen ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "nxg-menu", role: "menu", "aria-labelledby": densityButtonId, children: import_core2.DENSITIES.map((option) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
996
+ densityMenu.isOpen ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "tbx-menu", role: "menu", "aria-labelledby": densityButtonId, children: import_core2.DENSITIES.map((option) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
566
997
  "button",
567
998
  {
568
999
  type: "button",
569
- className: "nxg-menu-item",
1000
+ className: "tbx-menu-item",
570
1001
  role: "menuitemcheckbox",
571
1002
  "aria-checked": density === option,
572
1003
  onClick: () => {
@@ -574,37 +1005,36 @@ function NexGrid({
574
1005
  densityMenu.close();
575
1006
  },
576
1007
  children: [
577
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CheckIcon, { className: "nxg-check" }),
1008
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CheckIcon, { className: "tbx-check" }),
578
1009
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: locale[DENSITY_LABEL_KEY[option]] })
579
1010
  ]
580
1011
  },
581
1012
  option
582
1013
  )) }) : null
583
- ] })
584
- ] }),
585
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-toolbar-group nxg-toolbar-group--end", children: [
586
- enableExport ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-menu-wrap", ref: exportMenu.containerRef, children: [
1014
+ ] }) : null,
1015
+ isExportVisible ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-menu-wrap", ref: exportMenu.containerRef, children: [
587
1016
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
588
1017
  "button",
589
1018
  {
590
1019
  type: "button",
591
1020
  id: exportButtonId,
592
- className: "nxg-btn nxg-btn--export",
1021
+ className: "tbx-btn tbx-btn--export",
593
1022
  ref: exportMenu.triggerRef,
594
1023
  disabled: isExporting,
595
1024
  "aria-haspopup": "menu",
596
1025
  "aria-expanded": exportMenu.isOpen,
597
1026
  onClick: exportMenu.toggle,
598
1027
  children: [
599
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DownloadIcon, { className: "nxg-icon" }),
600
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: isExporting ? locale.exportingButton : locale.exportButton })
1028
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DownloadTrayIcon, { className: "tbx-icon" }),
1029
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: isExporting ? locale.exportingButton : locale.exportButton }),
1030
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChevronDownIcon, { className: "tbx-icon tbx-chevron" })
601
1031
  ]
602
1032
  }
603
1033
  ),
604
1034
  exportMenu.isOpen ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
605
1035
  "div",
606
1036
  {
607
- className: "nxg-menu nxg-menu--end",
1037
+ className: "tbx-menu tbx-menu--end",
608
1038
  role: "menu",
609
1039
  "aria-labelledby": exportButtonId,
610
1040
  children: [
@@ -612,12 +1042,12 @@ function NexGrid({
612
1042
  "button",
613
1043
  {
614
1044
  type: "button",
615
- className: "nxg-menu-item",
1045
+ className: "tbx-menu-item",
616
1046
  role: "menuitem",
617
1047
  onClick: () => void handleExport("excel"),
618
1048
  children: [
619
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FileSpreadsheetIcon, { className: "nxg-icon--excel" }),
620
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-menu-item-title", children: [
1049
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FileSpreadsheetIcon, { className: "tbx-icon--excel" }),
1050
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-menu-item-title", children: [
621
1051
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: locale.exportExcelTitle }),
622
1052
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("small", { children: locale.exportExcelSubtitle })
623
1053
  ] })
@@ -628,17 +1058,33 @@ function NexGrid({
628
1058
  "button",
629
1059
  {
630
1060
  type: "button",
631
- className: "nxg-menu-item",
1061
+ className: "tbx-menu-item",
632
1062
  role: "menuitem",
633
1063
  onClick: () => void handleExport("csv"),
634
1064
  children: [
635
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FileTextIcon, { className: "nxg-icon--csv" }),
636
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-menu-item-title", children: [
1065
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FileTextIcon, { className: "tbx-icon--csv" }),
1066
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-menu-item-title", children: [
637
1067
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: locale.exportCsvTitle }),
638
1068
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("small", { children: locale.exportCsvSubtitle })
639
1069
  ] })
640
1070
  ]
641
1071
  }
1072
+ ),
1073
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1074
+ "button",
1075
+ {
1076
+ type: "button",
1077
+ className: "tbx-menu-item",
1078
+ role: "menuitem",
1079
+ onClick: () => void handleExport("clipboard"),
1080
+ children: [
1081
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FileTextIcon, { className: "tbx-icon--csv" }),
1082
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-menu-item-title", children: [
1083
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: locale.exportClipboardTitle }),
1084
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("small", { children: locale.exportClipboardSubtitle })
1085
+ ] })
1086
+ ]
1087
+ }
642
1088
  )
643
1089
  ]
644
1090
  }
@@ -646,137 +1092,400 @@ function NexGrid({
646
1092
  ] }) : null,
647
1093
  toolbarActions
648
1094
  ] })
649
- ] }),
650
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "nxg-table-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("table", { className: "nxg-table", "aria-label": caption, children: [
651
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("tr", { children: [
652
- showSerialNumber ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("th", { className: "nxg-th nxg-th--serial", scope: "col", children: locale.serialHeader }) : null,
653
- enableSelection ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("th", { className: "nxg-th nxg-th--select", scope: "col", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
654
- "input",
1095
+ ] }) : null,
1096
+ showFilterPills !== false && (Boolean(query.q?.trim()) || Object.keys(query.filter ?? {}).some((k) => query.filter?.[k])) ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-filter-pills-bar", children: [
1097
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "tbx-filter-pills-title", children: "Active filters:" }),
1098
+ query.q?.trim() ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-filter-pill", children: [
1099
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "tbx-filter-pill-label", children: [
1100
+ searchPlaceholder || locale.searchPlaceholder || "Search",
1101
+ ":"
1102
+ ] }),
1103
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "tbx-filter-pill-val", children: [
1104
+ '"',
1105
+ query.q,
1106
+ '"'
1107
+ ] }),
1108
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1109
+ "button",
655
1110
  {
656
- type: "checkbox",
657
- className: "nxg-checkbox",
658
- checked: allPageSelected,
659
- ref: (el) => {
660
- if (el) el.indeterminate = somePageSelected;
661
- },
662
- onChange: toggleSelectAll,
663
- "aria-label": locale.selectAllLabel
1111
+ type: "button",
1112
+ className: "tbx-filter-pill-remove",
1113
+ title: "Clear search",
1114
+ "aria-label": "Clear search",
1115
+ onClick: () => onQueryChange((0, import_core2.withSearch)(query, "")),
1116
+ children: "\u2715"
664
1117
  }
665
- ) }) : null,
666
- visible.map((col, index) => {
667
- const id = (0, import_core2.getColumnId)(col);
668
- const sortable = (0, import_core2.isSortable)(col);
669
- const sorted = sortable && id !== "" && sort?.field === id;
670
- const title = (0, import_core2.getColumnTitle)(col) || id;
671
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1118
+ )
1119
+ ] }) : null,
1120
+ Object.entries(query.filter ?? {}).map(([key, val]) => {
1121
+ if (val === void 0 || val === "") return null;
1122
+ const col = leafCols.find((c) => (0, import_core2.getColumnId)(c) === key);
1123
+ const title = col ? (0, import_core2.getColumnTitle)(col) || key : key;
1124
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-filter-pill", children: [
1125
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "tbx-filter-pill-label", children: [
1126
+ title,
1127
+ ":"
1128
+ ] }),
1129
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "tbx-filter-pill-val", children: String(val) }),
1130
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1131
+ "button",
1132
+ {
1133
+ type: "button",
1134
+ className: "tbx-filter-pill-remove",
1135
+ title: `Remove ${title} filter`,
1136
+ "aria-label": `Remove filter for ${title}`,
1137
+ onClick: () => onQueryChange((0, import_core2.withFilter)(query, key, void 0)),
1138
+ children: "\u2715"
1139
+ }
1140
+ )
1141
+ ] }, key);
1142
+ }),
1143
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1144
+ "button",
1145
+ {
1146
+ type: "button",
1147
+ className: "tbx-filter-pill-clear-all",
1148
+ onClick: () => onQueryChange({ ...query, page: 1, q: void 0, filter: {} }),
1149
+ children: "Clear all"
1150
+ }
1151
+ )
1152
+ ] }) : null,
1153
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "tbx-table-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("table", { className: "tbx-table", "aria-label": caption, children: [
1154
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("thead", { children: [
1155
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("tr", { children: [
1156
+ renderExpandedRow ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1157
+ "th",
1158
+ {
1159
+ rowSpan: headerRows.hasGroups ? 2 : void 0,
1160
+ className: [
1161
+ "tbx-th tbx-th--expand",
1162
+ leftOffsets.has("__expand") ? "tbx-th--pinned-left" : void 0,
1163
+ lastLeftPinnedId === "__expand" ? "tbx-pinned-border-left" : void 0
1164
+ ].filter(Boolean).join(" "),
1165
+ style: {
1166
+ width: "40px",
1167
+ left: leftOffsets.get("__expand")
1168
+ },
1169
+ scope: "col"
1170
+ }
1171
+ ) : null,
1172
+ enableSelection ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
672
1173
  "th",
673
1174
  {
1175
+ rowSpan: headerRows.hasGroups ? 2 : void 0,
1176
+ className: [
1177
+ "tbx-th tbx-th--select",
1178
+ leftOffsets.has("__select") ? "tbx-th--pinned-left" : void 0,
1179
+ lastLeftPinnedId === "__select" ? "tbx-pinned-border-left" : void 0
1180
+ ].filter(Boolean).join(" "),
1181
+ style: {
1182
+ left: leftOffsets.get("__select")
1183
+ },
674
1184
  scope: "col",
675
- className: sortable ? "nxg-th nxg-th--sortable" : "nxg-th",
676
- style: headerCellStyle(col),
677
- "aria-sort": sorted ? sort?.dir === "asc" ? "ascending" : "descending" : sortable ? "none" : void 0,
678
- "aria-label": title || void 0,
679
- tabIndex: sortable ? 0 : void 0,
680
- onClick: sortable ? () => toggleSort(id) : void 0,
681
- onKeyDown: sortable ? (event) => {
682
- if (event.key !== "Enter" && event.key !== " ") return;
683
- event.preventDefault();
684
- toggleSort(id);
685
- } : void 0,
686
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: headerInnerClass(col), children: [
687
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: renderColumnHeader(col) }),
688
- sortable ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: sorted ? sort?.dir === "asc" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ArrowUpIcon, { className: "nxg-sort-icon" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ArrowDownIcon, { className: "nxg-sort-icon" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ArrowUpDownIcon, { className: "nxg-sort-icon nxg-sort-icon--idle" }) }) : null
689
- ] })
690
- },
691
- id || `col-${index}`
692
- );
693
- })
694
- ] }) }),
695
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("tbody", { children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("td", { className: "nxg-state", colSpan: Math.max(1, columnCount), children: [
696
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "nxg-spinner", "aria-hidden": "true" }),
697
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { "aria-live": "polite", children: locale.loadingText })
698
- ] }) }) : data.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { className: "nxg-state", colSpan: Math.max(1, columnCount), children: locale.emptyText }) }) : data.map((row, index) => {
699
- const id = pageRowIds[index] ?? String(index);
700
- const isSelected = selectedIds.has(id);
701
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
702
- "tr",
703
- {
704
- className: [
705
- "nxg-row",
706
- isSelected ? "nxg-row--selected" : void 0,
707
- rowIsClickable ? "nxg-row--clickable" : void 0
708
- ].filter(Boolean).join(" "),
709
- onClick: rowIsClickable ? activateRow(row) : void 0,
710
- onKeyDown: rowIsClickable ? rowKeyDown(row) : void 0,
711
- tabIndex: rowIsClickable ? 0 : void 0,
712
- children: [
713
- showSerialNumber ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { className: "nxg-td nxg-td--serial", children: (0, import_core2.serialNumber)(currentPage, pageSize, index) }) : null,
714
- enableSelection ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
715
- "td",
1185
+ children: !isSingleSelect ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1186
+ "input",
716
1187
  {
717
- className: "nxg-td nxg-td--select",
718
- onClick: (event) => event.stopPropagation(),
719
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
720
- "input",
721
- {
722
- type: "checkbox",
723
- className: "nxg-checkbox",
724
- checked: isSelected,
725
- onChange: () => toggleSelectRow(id),
726
- onClick: (event) => event.stopPropagation(),
727
- "aria-label": (0, import_core2.formatMessage)(locale.selectRowLabel, { id })
728
- }
729
- )
1188
+ type: "checkbox",
1189
+ className: "tbx-checkbox",
1190
+ checked: allPageSelected,
1191
+ ref: (el) => {
1192
+ if (el) el.indeterminate = somePageSelected;
1193
+ },
1194
+ onChange: toggleSelectAll,
1195
+ "aria-label": locale.selectAllLabel
730
1196
  }
731
- ) : null,
732
- visible.map((col, colIndex) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
733
- "td",
1197
+ ) : null
1198
+ }
1199
+ ) : null,
1200
+ showSerialNumber ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1201
+ "th",
1202
+ {
1203
+ rowSpan: headerRows.hasGroups ? 2 : void 0,
1204
+ className: [
1205
+ "tbx-th tbx-th--serial",
1206
+ leftOffsets.has("__serial") ? "tbx-th--pinned-left" : void 0,
1207
+ lastLeftPinnedId === "__serial" ? "tbx-pinned-border-left" : void 0
1208
+ ].filter(Boolean).join(" "),
1209
+ style: {
1210
+ left: leftOffsets.get("__serial")
1211
+ },
1212
+ scope: "col",
1213
+ children: locale.serialHeader
1214
+ }
1215
+ ) : null,
1216
+ !headerRows.hasGroups ? visible.map((col) => renderLeafTh(col, 1, false)) : headerRows.topRow.map((cell, idx) => {
1217
+ if (cell.isGroup) {
1218
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1219
+ "th",
734
1220
  {
735
- className: "nxg-td",
736
- style: bodyCellStyle(col),
737
- children: renderCellContent(col, row, boolLabels)
1221
+ colSpan: cell.colSpan,
1222
+ className: "tbx-th tbx-th--group",
1223
+ scope: "colgroup",
1224
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "tbx-th-group-title", children: cell.title })
738
1225
  },
739
- (0, import_core2.getColumnId)(col) || `col-${colIndex}`
740
- ))
741
- ]
742
- },
743
- id || index
744
- );
1226
+ `grp-${cell.id}-${idx}`
1227
+ );
1228
+ }
1229
+ if (cell.leafColumn) {
1230
+ return renderLeafTh(cell.leafColumn, cell.rowSpan, false);
1231
+ }
1232
+ return null;
1233
+ })
1234
+ ] }),
1235
+ headerRows.hasGroups ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("tr", { children: headerRows.bottomRow.map((cell) => {
1236
+ if (cell.leafColumn) {
1237
+ return renderLeafTh(cell.leafColumn, 1, true);
1238
+ }
1239
+ return null;
1240
+ }) }) : null
1241
+ ] }),
1242
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("tbody", { children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("td", { className: "tbx-state", colSpan: Math.max(1, columnCount), children: [
1243
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-dotted-loader", "aria-hidden": "true", children: [
1244
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "tbx-dot" }),
1245
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "tbx-dot" }),
1246
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "tbx-dot" }),
1247
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "tbx-dot" })
1248
+ ] }),
1249
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "tbx-loading-text", "aria-live": "polite", children: locale.loadingText })
1250
+ ] }) }) : rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { className: "tbx-state", colSpan: Math.max(1, columnCount), children: locale.emptyText }) }) : rows.map((row, index) => {
1251
+ const id = pageRowIds[index] ?? String(index);
1252
+ const isSelected = selectedIds.has(id);
1253
+ const isExpanded = expandedRows.has(id);
1254
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(React4.Fragment, { children: [
1255
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1256
+ "tr",
1257
+ {
1258
+ className: [
1259
+ "tbx-row",
1260
+ isSelected ? "tbx-row--selected" : void 0,
1261
+ isExpanded ? "tbx-row--expanded" : void 0,
1262
+ rowIsClickable ? "tbx-row--clickable" : void 0
1263
+ ].filter(Boolean).join(" "),
1264
+ onClick: rowIsClickable ? activateRow(row) : void 0,
1265
+ onKeyDown: rowIsClickable ? rowKeyDown(row) : void 0,
1266
+ tabIndex: rowIsClickable ? 0 : void 0,
1267
+ children: [
1268
+ renderExpandedRow ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1269
+ "td",
1270
+ {
1271
+ className: [
1272
+ "tbx-td tbx-td--expand",
1273
+ leftOffsets.has("__expand") ? "tbx-td--pinned-left" : void 0,
1274
+ lastLeftPinnedId === "__expand" ? "tbx-pinned-border-left" : void 0
1275
+ ].filter(Boolean).join(" "),
1276
+ style: {
1277
+ width: "40px",
1278
+ left: leftOffsets.get("__expand")
1279
+ },
1280
+ onClick: (e) => e.stopPropagation(),
1281
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1282
+ "button",
1283
+ {
1284
+ type: "button",
1285
+ className: isExpanded ? "tbx-expand-btn tbx-expand-btn--open" : "tbx-expand-btn",
1286
+ "aria-label": isExpanded ? "Collapse row" : "Expand row",
1287
+ onClick: (e) => {
1288
+ e.stopPropagation();
1289
+ toggleExpandRow(id);
1290
+ },
1291
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChevronRightIcon, { className: "tbx-icon" })
1292
+ }
1293
+ )
1294
+ }
1295
+ ) : null,
1296
+ enableSelection ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1297
+ "td",
1298
+ {
1299
+ className: [
1300
+ "tbx-td tbx-td--select",
1301
+ leftOffsets.has("__select") ? "tbx-td--pinned-left" : void 0,
1302
+ lastLeftPinnedId === "__select" ? "tbx-pinned-border-left" : void 0
1303
+ ].filter(Boolean).join(" "),
1304
+ style: {
1305
+ left: leftOffsets.get("__select")
1306
+ },
1307
+ onClick: (event) => event.stopPropagation(),
1308
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1309
+ "input",
1310
+ {
1311
+ type: isSingleSelect ? "radio" : "checkbox",
1312
+ name: isSingleSelect ? `${instanceId}-select` : void 0,
1313
+ className: "tbx-checkbox",
1314
+ checked: isSelected,
1315
+ onChange: () => toggleSelectRow(id),
1316
+ onClick: (event) => event.stopPropagation(),
1317
+ "aria-label": (0, import_core2.formatMessage)(locale.selectRowLabel, { id })
1318
+ }
1319
+ )
1320
+ }
1321
+ ) : null,
1322
+ showSerialNumber ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1323
+ "td",
1324
+ {
1325
+ className: [
1326
+ "tbx-td tbx-td--serial",
1327
+ leftOffsets.has("__serial") ? "tbx-td--pinned-left" : void 0,
1328
+ lastLeftPinnedId === "__serial" ? "tbx-pinned-border-left" : void 0
1329
+ ].filter(Boolean).join(" "),
1330
+ style: {
1331
+ left: leftOffsets.get("__serial")
1332
+ },
1333
+ children: (0, import_core2.serialNumber)(currentPage, pageSize, index)
1334
+ }
1335
+ ) : null,
1336
+ visible.map((col, colIndex) => {
1337
+ const colId = (0, import_core2.getColumnId)(col);
1338
+ const isPinnedLeft = leftOffsets.has(colId);
1339
+ const isPinnedRight = rightOffsets.has(colId);
1340
+ const isLastLeft = lastLeftPinnedId === colId;
1341
+ const isFirstRight = firstRightPinnedId === colId;
1342
+ const isCellEditable = (0, import_core2.isEditable)(col);
1343
+ const isCurrentlyEditing = editingCell?.rowId === id && editingCell?.columnId === colId;
1344
+ const tdStyle = {
1345
+ ...bodyCellStyle(col),
1346
+ ...isPinnedLeft ? { left: leftOffsets.get(colId) } : {},
1347
+ ...isPinnedRight ? { right: rightOffsets.get(colId) } : {}
1348
+ };
1349
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1350
+ "td",
1351
+ {
1352
+ className: [
1353
+ "tbx-td",
1354
+ isCellEditable ? "tbx-cell--editable" : void 0,
1355
+ isPinnedLeft ? "tbx-td--pinned-left" : void 0,
1356
+ isPinnedRight ? "tbx-td--pinned-right" : void 0,
1357
+ isLastLeft ? "tbx-pinned-border-left" : void 0,
1358
+ isFirstRight ? "tbx-pinned-border-right" : void 0
1359
+ ].filter(Boolean).join(" "),
1360
+ style: tdStyle,
1361
+ onDoubleClick: isCellEditable ? (e) => {
1362
+ e.stopPropagation();
1363
+ setEditingCell({ rowId: id, columnId: colId });
1364
+ } : void 0,
1365
+ children: isCurrentlyEditing ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1366
+ "div",
1367
+ {
1368
+ className: "tbx-cell-edit-wrap",
1369
+ onClick: (e) => e.stopPropagation(),
1370
+ children: [
1371
+ col.meta?.editType === "select" && col.meta.editOptions ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1372
+ "select",
1373
+ {
1374
+ autoFocus: true,
1375
+ className: "tbx-cell-edit-select tbx-cell-edit-input",
1376
+ defaultValue: String(row[colId] ?? ""),
1377
+ id: `${instanceId}-edit-${id}-${colId}`,
1378
+ children: col.meta.editOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: opt, children: opt }, opt))
1379
+ }
1380
+ ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1381
+ "input",
1382
+ {
1383
+ autoFocus: true,
1384
+ type: col.meta?.editType === "number" ? "number" : "text",
1385
+ className: "tbx-cell-edit-input",
1386
+ defaultValue: String(row[colId] ?? ""),
1387
+ id: `${instanceId}-edit-${id}-${colId}`,
1388
+ onKeyDown: (e) => {
1389
+ if (e.key === "Enter") {
1390
+ e.preventDefault();
1391
+ const el = e.currentTarget;
1392
+ const val = col.meta?.editType === "number" ? Number(el.value) : el.value;
1393
+ const oldVal = row[colId];
1394
+ row[colId] = val;
1395
+ onCellEdit?.({ row, columnId: colId, oldValue: oldVal, newValue: val });
1396
+ setEditingCell(null);
1397
+ } else if (e.key === "Escape") {
1398
+ e.preventDefault();
1399
+ setEditingCell(null);
1400
+ }
1401
+ }
1402
+ }
1403
+ ),
1404
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-cell-edit-actions", children: [
1405
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1406
+ "button",
1407
+ {
1408
+ type: "button",
1409
+ className: "tbx-cell-edit-btn tbx-cell-edit-btn--save",
1410
+ onClick: (e) => {
1411
+ e.stopPropagation();
1412
+ const el = document.getElementById(`${instanceId}-edit-${id}-${colId}`);
1413
+ if (el) {
1414
+ const val = col.meta?.editType === "number" ? Number(el.value) : el.value;
1415
+ const oldVal = row[colId];
1416
+ row[colId] = val;
1417
+ onCellEdit?.({ row, columnId: colId, oldValue: oldVal, newValue: val });
1418
+ }
1419
+ setEditingCell(null);
1420
+ },
1421
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CheckIcon, { className: "tbx-icon" })
1422
+ }
1423
+ ),
1424
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1425
+ "button",
1426
+ {
1427
+ type: "button",
1428
+ className: "tbx-cell-edit-btn tbx-cell-edit-btn--cancel",
1429
+ onClick: (e) => {
1430
+ e.stopPropagation();
1431
+ setEditingCell(null);
1432
+ },
1433
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(XIcon, { className: "tbx-icon" })
1434
+ }
1435
+ )
1436
+ ] })
1437
+ ]
1438
+ }
1439
+ ) : renderCellContent(col, row, boolLabels)
1440
+ },
1441
+ colId || `col-${colIndex}`
1442
+ );
1443
+ })
1444
+ ]
1445
+ }
1446
+ ),
1447
+ isExpanded && renderExpandedRow ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("tr", { className: "tbx-expanded-row", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { className: "tbx-expanded-cell", colSpan: columnCount, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "tbx-detail-panel", children: renderExpandedRow(row) }) }) }) : null
1448
+ ] }, id || index);
745
1449
  }) })
746
1450
  ] }) }),
747
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "nxg-cards", children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "nxg-card", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-state", children: [
748
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "nxg-spinner", "aria-hidden": "true" }),
749
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { "aria-live": "polite", children: locale.loadingText })
750
- ] }) }) : data.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "nxg-card", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "nxg-state", children: locale.emptyText }) }) : data.map((row, index) => {
1451
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "tbx-cards", children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "tbx-card", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-state", children: [
1452
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-dotted-loader", "aria-hidden": "true", children: [
1453
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "tbx-dot" }),
1454
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "tbx-dot" }),
1455
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "tbx-dot" }),
1456
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "tbx-dot" })
1457
+ ] }),
1458
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "tbx-loading-text", "aria-live": "polite", children: locale.loadingText })
1459
+ ] }) }) : rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "tbx-card", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "tbx-state", children: locale.emptyText }) }) : rows.map((row, index) => {
751
1460
  const id = pageRowIds[index] ?? String(index);
752
1461
  const isSelected = selectedIds.has(id);
753
1462
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
754
1463
  "div",
755
1464
  {
756
1465
  className: [
757
- "nxg-card",
758
- isSelected ? "nxg-card--selected" : void 0,
759
- rowIsClickable ? "nxg-card--clickable" : void 0
1466
+ "tbx-card",
1467
+ isSelected ? "tbx-card--selected" : void 0,
1468
+ rowIsClickable ? "tbx-card--clickable" : void 0
760
1469
  ].filter(Boolean).join(" "),
761
1470
  onClick: rowIsClickable ? activateRow(row) : void 0,
762
1471
  onKeyDown: rowIsClickable ? rowKeyDown(row) : void 0,
763
1472
  tabIndex: rowIsClickable ? 0 : void 0,
764
1473
  children: [
765
- showSerialNumber || enableSelection ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-card-head", children: [
766
- showSerialNumber ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "nxg-card-serial", children: [
1474
+ showSerialNumber || enableSelection ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-card-head", children: [
1475
+ showSerialNumber ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "tbx-card-serial", children: [
767
1476
  "#",
768
1477
  (0, import_core2.serialNumber)(currentPage, pageSize, index)
769
1478
  ] }) : null,
770
1479
  enableSelection ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
771
1480
  "span",
772
1481
  {
773
- className: "nxg-card-select",
1482
+ className: "tbx-card-select",
774
1483
  onClick: (event) => event.stopPropagation(),
775
1484
  children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
776
1485
  "input",
777
1486
  {
778
1487
  type: "checkbox",
779
- className: "nxg-checkbox",
1488
+ className: "tbx-checkbox",
780
1489
  checked: isSelected,
781
1490
  onChange: () => toggleSelectRow(id),
782
1491
  onClick: (event) => event.stopPropagation(),
@@ -786,9 +1495,9 @@ function NexGrid({
786
1495
  }
787
1496
  ) : null
788
1497
  ] }) : null,
789
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("dl", { className: "nxg-card-rows", children: visible.map((col, colIndex) => {
1498
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("dl", { className: "tbx-card-rows", children: visible.map((col, colIndex) => {
790
1499
  const colId = (0, import_core2.getColumnId)(col);
791
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-card-row", children: [
1500
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-card-row", children: [
792
1501
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("dt", { children: (0, import_core2.getColumnTitle)(col) || colId }),
793
1502
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("dd", { children: renderCellContent(col, row, boolLabels) })
794
1503
  ] }, colId || `col-${colIndex}`);
@@ -798,52 +1507,55 @@ function NexGrid({
798
1507
  id || index
799
1508
  );
800
1509
  }) }),
801
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-footer", children: [
802
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-range", children: [
1510
+ showFooter ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-footer", children: [
1511
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-range", children: [
803
1512
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: renderTemplate(locale.showingRange, {
804
1513
  start: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: range.start }),
805
1514
  end: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: range.end }),
806
- total: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { className: "nxg-range-total", children: total.toLocaleString() })
1515
+ total: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { className: "tbx-range-total", children: total.toLocaleString() })
807
1516
  }) }),
808
- selectedIds.size > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "nxg-selected-badge", children: (0, import_core2.formatMessage)(locale.selectedBadge, { count: selectedIds.size }) }) : null
1517
+ selectedIds.size > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "tbx-selected-badge", children: (0, import_core2.formatMessage)(locale.selectedBadge, { count: selectedIds.size }) }) : null
809
1518
  ] }),
810
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-pagination", children: [
811
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-rows-per-page", children: [
1519
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-pagination", children: [
1520
+ isRowsPerPageVisible ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-rows-per-page", children: [
812
1521
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: locale.rowsPerPage }),
813
1522
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
814
1523
  "select",
815
1524
  {
816
- className: "nxg-rows-select",
1525
+ className: "tbx-rows-select",
817
1526
  value: String(pageSize),
818
1527
  onChange: (event) => {
819
1528
  onQueryChange((0, import_core2.withPageSize)(query, Number.parseInt(event.target.value, 10)));
820
1529
  },
821
1530
  "aria-label": locale.rowsPerPage,
822
- children: import_core2.PAGE_SIZES.map((size) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: size, children: size }, size))
1531
+ children: import_core2.PAGE_SIZES.map((size) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("option", { value: size, children: [
1532
+ size,
1533
+ " rows"
1534
+ ] }, size))
823
1535
  }
824
1536
  )
825
- ] }),
826
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nxg-pager", children: [
1537
+ ] }) : null,
1538
+ isPaginationVisible ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "tbx-pager", children: [
827
1539
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
828
1540
  "button",
829
1541
  {
830
1542
  type: "button",
831
- className: "nxg-page-nav",
1543
+ className: "tbx-page-nav",
832
1544
  disabled: currentPage <= 1,
833
1545
  onClick: () => onQueryChange((0, import_core2.withPage)(query, currentPage - 1, totalPages)),
834
1546
  "aria-label": locale.previousPage,
835
1547
  children: [
836
1548
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChevronLeftIcon, { size: 16 }),
837
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "nxg-sr-only", children: locale.previousPage })
1549
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "tbx-sr-only", children: locale.previousPage })
838
1550
  ]
839
1551
  }
840
1552
  ),
841
1553
  pageItems.map(
842
- (item, index) => item === "..." ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "nxg-page-ellipsis", children: "\u2026" }, `gap-${index}`) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1554
+ (item, index) => item === "..." ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "tbx-page-ellipsis", children: "\u2026" }, `gap-${index}`) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
843
1555
  "button",
844
1556
  {
845
1557
  type: "button",
846
- className: item === currentPage ? "nxg-page-btn nxg-page-btn--current" : "nxg-page-btn",
1558
+ className: item === currentPage ? "tbx-page-btn tbx-page-btn--current" : "tbx-page-btn",
847
1559
  onClick: () => onQueryChange((0, import_core2.withPage)(query, item, totalPages)),
848
1560
  "aria-label": (0, import_core2.formatMessage)(locale.pageLabel, { page: item }),
849
1561
  "aria-current": item === currentPage ? "page" : void 0,
@@ -856,43 +1568,54 @@ function NexGrid({
856
1568
  "button",
857
1569
  {
858
1570
  type: "button",
859
- className: "nxg-page-nav",
1571
+ className: "tbx-page-nav",
860
1572
  disabled: currentPage >= totalPages,
861
1573
  onClick: () => onQueryChange((0, import_core2.withPage)(query, currentPage + 1, totalPages)),
862
1574
  "aria-label": locale.nextPage,
863
1575
  children: [
864
1576
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChevronRightIcon, { size: 16 }),
865
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "nxg-sr-only", children: locale.nextPage })
1577
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "tbx-sr-only", children: locale.nextPage })
866
1578
  ]
867
1579
  }
868
1580
  )
869
- ] }),
870
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("form", { className: "nxg-jump", onSubmit: submitJump, children: [
871
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: "nxg-jump-label", htmlFor: jumpInputId, children: locale.goToPage }),
872
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
873
- "input",
874
- {
875
- id: jumpInputId,
876
- type: "number",
877
- className: "nxg-jump-input",
878
- min: 1,
879
- max: totalPages,
880
- value: jumpText,
881
- onChange: (event) => setJumpText(event.target.value),
882
- onBlur: () => submitJump(),
883
- "aria-label": locale.goToPageOf
884
- }
885
- )
886
- ] })
1581
+ ] }) : null,
1582
+ isJumpToPageVisible ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1583
+ "form",
1584
+ {
1585
+ className: "tbx-jump",
1586
+ onSubmit: (event) => {
1587
+ event.preventDefault();
1588
+ submitJump(jumpText);
1589
+ },
1590
+ children: [
1591
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: "tbx-jump-label", htmlFor: jumpInputId, children: locale.goToPage }),
1592
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1593
+ "input",
1594
+ {
1595
+ id: jumpInputId,
1596
+ type: "number",
1597
+ className: "tbx-jump-input",
1598
+ min: 1,
1599
+ max: totalPages,
1600
+ value: jumpText,
1601
+ onChange: (event) => setJumpText(event.target.value),
1602
+ onBlur: () => submitJump(jumpText),
1603
+ "aria-label": locale.goToPageOf
1604
+ }
1605
+ )
1606
+ ]
1607
+ }
1608
+ ) : null
887
1609
  ] })
888
- ] })
1610
+ ] }) : null
889
1611
  ] });
890
1612
  }
1613
+ var NexGrid = TableX;
891
1614
 
892
- // src/use-client-nex-grid.ts
1615
+ // src/use-client-table-x.ts
893
1616
  var import_react = require("react");
894
1617
  var import_core3 = require("@nexgrid/core");
895
- function useClientNexGrid(allData, options) {
1618
+ function useClientTableX(allData, options) {
896
1619
  const [query, setQuery] = (0, import_react.useState)(() => ({
897
1620
  ...(0, import_core3.defaultQuery)(),
898
1621
  ...options?.initialQuery
@@ -912,6 +1635,7 @@ function useClientNexGrid(allData, options) {
912
1635
  setQuery
913
1636
  };
914
1637
  }
1638
+ var useClientNexGrid = useClientTableX;
915
1639
 
916
1640
  // src/index.ts
917
1641
  var import_core4 = require("@nexgrid/core");
@@ -921,6 +1645,7 @@ var import_core4 = require("@nexgrid/core");
921
1645
  DEFAULT_PAGE_SIZE,
922
1646
  NexGrid,
923
1647
  PAGE_SIZES,
1648
+ TableX,
924
1649
  buildODataUrl,
925
1650
  buildQueryUrl,
926
1651
  defaultQuery,
@@ -934,11 +1659,13 @@ var import_core4 = require("@nexgrid/core");
934
1659
  toODataParams,
935
1660
  totalPagesFor,
936
1661
  useClientNexGrid,
1662
+ useClientTableX,
937
1663
  withFilter,
938
1664
  withPage,
939
1665
  withPageSize,
940
1666
  withSearch,
941
1667
  withSort,
1668
+ withToggledMultiSort,
942
1669
  withToggledSort
943
1670
  });
944
1671
  //# sourceMappingURL=index.cjs.map