react-glide-table 1.6.0 → 2.0.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.js CHANGED
@@ -51,6 +51,7 @@ var ROW_HOVER_CLASS = "row-hoverable";
51
51
  var ROW_HOVERED_BG_CLASS = "row-hovered";
52
52
  var CELL_SELECTION_FILL_CLASS = "cell-selection-fill";
53
53
  var DATA_TABLE_ROW_HEIGHT = 44;
54
+ var DATA_TABLE_HEADER_ROW_HEIGHT = 40;
54
55
  var DATA_TABLE_VIRTUAL_OVERSCAN = 8;
55
56
  var DATA_TABLE_COLUMN_SIZE = 150;
56
57
  var DATA_TABLE_COLUMN_MIN_SIZE = 40;
@@ -105,6 +106,37 @@ function applyCellEdit(data, rows, rowIndex, colIndex, raw) {
105
106
  return newData;
106
107
  }
107
108
 
109
+ // src/components/ui/table/features/cell-render/commitCellValue.ts
110
+ function commitCellValue({
111
+ data,
112
+ rows,
113
+ rowId,
114
+ columnId,
115
+ value,
116
+ onCellChange,
117
+ onDataChange
118
+ }) {
119
+ if (!onCellChange && !onDataChange) return true;
120
+ if (onCellChange) {
121
+ onCellChange(rowId, columnId, value);
122
+ return true;
123
+ }
124
+ const row = rows.find((item) => item.id === rowId);
125
+ if (!row) return false;
126
+ const cell = row.getAllCells().find((item) => item.column.id === columnId) ?? row.getVisibleCells().find((item) => item.column.id === columnId);
127
+ if (!cell) return false;
128
+ const accessorKey = getColumnAccessorKey(cell.column.columnDef);
129
+ if (!accessorKey) return false;
130
+ const dataIndex = row.index;
131
+ if (dataIndex < 0 || dataIndex >= data.length) return false;
132
+ const next = data.map((item) => ({ ...item }));
133
+ const target = next[dataIndex];
134
+ if (!target) return false;
135
+ target[accessorKey] = value;
136
+ onDataChange?.(next);
137
+ return true;
138
+ }
139
+
108
140
  // src/components/ui/table/features/cell-edit/useCellEdit.ts
109
141
  function useCellEdit({
110
142
  data,
@@ -140,21 +172,23 @@ function useCellEdit({
140
172
  cancelEdit();
141
173
  return true;
142
174
  }
143
- const value = raw ?? draftValueRef.current;
144
175
  if (!isColumnEditable(cell.column.columnDef)) {
145
176
  cancelEdit();
146
177
  return true;
147
178
  }
179
+ const value = raw ?? draftValueRef.current;
148
180
  const parsed = parseCellEditValue(value, getColumnEditType(cell.column.columnDef));
149
181
  if (!parsed.ok) return false;
150
- if (onCellChange) {
151
- onCellChange(row.id, cell.column.id, parsed.value);
152
- cancelEdit();
153
- return true;
154
- }
155
- const next = applyCellEdit(data, rows, current.rowIndex, current.colIndex, value);
156
- if (!next) return false;
157
- onDataChange?.(next);
182
+ const committed = commitCellValue({
183
+ data,
184
+ rows,
185
+ rowId: row.id,
186
+ columnId: cell.column.id,
187
+ value: parsed.value,
188
+ onCellChange,
189
+ onDataChange
190
+ });
191
+ if (!committed) return false;
158
192
  cancelEdit();
159
193
  return true;
160
194
  },
@@ -183,6 +217,218 @@ function useCellEdit({
183
217
  };
184
218
  }
185
219
 
220
+ // src/components/ui/table/features/cell-render/builtins.tsx
221
+ import { jsx, jsxs } from "react/jsx-runtime";
222
+ function asString(value) {
223
+ if (value == null) return "";
224
+ return String(value);
225
+ }
226
+ function asStringList(value) {
227
+ if (Array.isArray(value)) {
228
+ return value.map((item) => asString(item)).filter(Boolean);
229
+ }
230
+ if (value == null || value === "") return [];
231
+ return [asString(value)];
232
+ }
233
+ function asDrilldownItems(value) {
234
+ if (!Array.isArray(value)) return [];
235
+ return value.flatMap((item) => {
236
+ if (item == null) return [];
237
+ if (typeof item === "string") return [{ text: item }];
238
+ if (typeof item === "object") {
239
+ const record = item;
240
+ const text = asString(record.text ?? record.label ?? "");
241
+ if (!text) return [];
242
+ const img = record.img ?? record.image;
243
+ return [{ text, ...typeof img === "string" ? { img } : {} }];
244
+ }
245
+ return [{ text: asString(item) }];
246
+ });
247
+ }
248
+ function escapeHtml(text) {
249
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
250
+ }
251
+ function simpleMarkdownToHtml(source) {
252
+ const escaped = escapeHtml(source);
253
+ return escaped.replace(/`([^`]+)`/g, "<code>$1</code>").replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>").replace(/\*([^*]+)\*/g, "<em>$1</em>").replace(/\n/g, "<br />");
254
+ }
255
+ function TextCell({ value }) {
256
+ return asString(value);
257
+ }
258
+ function NumberCell({ value }) {
259
+ if (value == null || value === "") return null;
260
+ return asString(value);
261
+ }
262
+ function BooleanCell({ value, update, cellProps }) {
263
+ const checked = Boolean(value);
264
+ const readonly = Boolean(cellProps?.readonly);
265
+ return /* @__PURE__ */ jsx(
266
+ "input",
267
+ {
268
+ type: "checkbox",
269
+ className: "data-table-cell-boolean",
270
+ checked,
271
+ disabled: readonly,
272
+ "aria-checked": checked,
273
+ onChange: (event) => {
274
+ if (readonly) return;
275
+ update(event.target.checked);
276
+ },
277
+ onClick: (event) => {
278
+ event.stopPropagation();
279
+ },
280
+ onMouseDown: (event) => {
281
+ event.stopPropagation();
282
+ }
283
+ }
284
+ );
285
+ }
286
+ function sanitizeUriHref(raw) {
287
+ const href = raw.trim();
288
+ if (!href) return null;
289
+ if (href.startsWith("/") || href.startsWith("#") || href.startsWith("?") || href.startsWith("./") || href.startsWith("../")) {
290
+ return href;
291
+ }
292
+ try {
293
+ const parsed = new URL(href);
294
+ const protocol = parsed.protocol.toLowerCase();
295
+ if (protocol === "http:" || protocol === "https:" || protocol === "mailto:") {
296
+ return href;
297
+ }
298
+ return null;
299
+ } catch {
300
+ if (/^[a-z][a-z0-9+.-]*:/i.test(href)) return null;
301
+ return href;
302
+ }
303
+ }
304
+ function UriCell({ value }) {
305
+ const raw = asString(value);
306
+ if (!raw) return null;
307
+ const href = sanitizeUriHref(raw);
308
+ if (!href) {
309
+ return /* @__PURE__ */ jsx("span", { className: "data-table-cell-uri", children: raw });
310
+ }
311
+ return /* @__PURE__ */ jsx(
312
+ "a",
313
+ {
314
+ className: "data-table-cell-uri",
315
+ href,
316
+ target: "_blank",
317
+ rel: "noopener noreferrer",
318
+ onClick: (event) => event.stopPropagation(),
319
+ onMouseDown: (event) => event.stopPropagation(),
320
+ children: raw
321
+ }
322
+ );
323
+ }
324
+ function ImageCell({ value }) {
325
+ const urls = asStringList(value);
326
+ if (urls.length === 0) return null;
327
+ return /* @__PURE__ */ jsx("span", { className: "data-table-cell-image", children: urls.map((url, index) => /* @__PURE__ */ jsx(
328
+ "img",
329
+ {
330
+ src: url,
331
+ alt: "",
332
+ className: "data-table-cell-image-item"
333
+ },
334
+ `${index}:${url}`
335
+ )) });
336
+ }
337
+ function BubbleCell({ value }) {
338
+ const items = asStringList(value);
339
+ if (items.length === 0) return null;
340
+ return /* @__PURE__ */ jsx("span", { className: "data-table-cell-bubble", children: items.map((item, index) => /* @__PURE__ */ jsx("span", { className: "data-table-cell-bubble-item", children: item }, `${index}:${item}`)) });
341
+ }
342
+ function MarkdownCell({ value }) {
343
+ const source = asString(value);
344
+ if (!source) return null;
345
+ return /* @__PURE__ */ jsx(
346
+ "span",
347
+ {
348
+ className: "data-table-cell-markdown",
349
+ dangerouslySetInnerHTML: { __html: simpleMarkdownToHtml(source) }
350
+ }
351
+ );
352
+ }
353
+ function DrilldownCell({ value }) {
354
+ const items = asDrilldownItems(value);
355
+ if (items.length === 0) return null;
356
+ return /* @__PURE__ */ jsx("span", { className: "data-table-cell-drilldown", children: items.map((item, index) => /* @__PURE__ */ jsxs(
357
+ "span",
358
+ {
359
+ className: "data-table-cell-drilldown-item",
360
+ children: [
361
+ item.img ? /* @__PURE__ */ jsx(
362
+ "img",
363
+ {
364
+ src: item.img,
365
+ alt: "",
366
+ className: "data-table-cell-drilldown-image"
367
+ }
368
+ ) : null,
369
+ /* @__PURE__ */ jsx("span", { className: "data-table-cell-drilldown-text", children: item.text })
370
+ ]
371
+ },
372
+ `${index}:${item.text}:${item.img ?? ""}`
373
+ )) });
374
+ }
375
+ function LoadingCell() {
376
+ return /* @__PURE__ */ jsx("span", { className: "data-table-cell-loading", "aria-busy": "true" });
377
+ }
378
+ function ProtectedCell() {
379
+ return /* @__PURE__ */ jsx("span", { className: "data-table-cell-protected", "aria-label": "protected", children: "****" });
380
+ }
381
+ function RowIdCell({ value }) {
382
+ return /* @__PURE__ */ jsx("span", { className: "data-table-cell-row-id", children: asString(value) });
383
+ }
384
+ var BUILTIN_RENDER_MAP = {
385
+ text: TextCell,
386
+ number: NumberCell,
387
+ boolean: BooleanCell,
388
+ uri: UriCell,
389
+ image: ImageCell,
390
+ bubble: BubbleCell,
391
+ markdown: MarkdownCell,
392
+ drilldown: DrilldownCell,
393
+ loading: LoadingCell,
394
+ protected: ProtectedCell,
395
+ "row-id": RowIdCell
396
+ };
397
+ var BUILTIN_CELL_RENDERERS = Object.keys(BUILTIN_RENDER_MAP).map((kind) => ({
398
+ kind,
399
+ render: BUILTIN_RENDER_MAP[kind]
400
+ }));
401
+
402
+ // src/components/ui/table/features/cell-render/registry.ts
403
+ function createCellRendererRegistry(customRenderers = []) {
404
+ const registry = /* @__PURE__ */ new Map();
405
+ for (const renderer of BUILTIN_CELL_RENDERERS) {
406
+ registry.set(renderer.kind, renderer);
407
+ }
408
+ for (const renderer of customRenderers) {
409
+ registry.set(renderer.kind, renderer);
410
+ }
411
+ return registry;
412
+ }
413
+ function resolveCellRenderer(registry, kind, ctx) {
414
+ if (!kind) return void 0;
415
+ const renderer = registry.get(kind);
416
+ if (!renderer) return void 0;
417
+ if (renderer.isMatch && !renderer.isMatch(ctx)) {
418
+ return void 0;
419
+ }
420
+ return renderer;
421
+ }
422
+ function formatDefaultCellValue(value) {
423
+ if (value == null) return null;
424
+ if (typeof value === "string") return value;
425
+ if (typeof value === "number" || typeof value === "boolean") {
426
+ return String(value);
427
+ }
428
+ if (typeof value === "bigint") return value.toString();
429
+ return String(value);
430
+ }
431
+
186
432
  // src/components/ui/table/features/cell-selection/useCellSelection.ts
187
433
  import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
188
434
 
@@ -492,9 +738,34 @@ function hasCellSelectionEdges(style) {
492
738
  }
493
739
 
494
740
  // src/components/ui/table/features/cell-selection/copyData.ts
741
+ function formatPrimitive(value) {
742
+ if (value === null || value === void 0) return "";
743
+ if (typeof value === "string") return value;
744
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
745
+ return String(value);
746
+ }
747
+ return "";
748
+ }
749
+ function formatObjectValue(value) {
750
+ const text = value.text ?? value.label ?? value.name ?? value.title;
751
+ if (text != null && text !== "") {
752
+ return formatCellValue(text);
753
+ }
754
+ try {
755
+ return JSON.stringify(value);
756
+ } catch {
757
+ return "";
758
+ }
759
+ }
495
760
  function formatCellValue(value) {
496
761
  if (value === null || value === void 0) return "";
497
- return String(value);
762
+ if (Array.isArray(value)) {
763
+ return value.map((item) => formatCellValue(item)).filter((item) => item.length > 0).join(", ");
764
+ }
765
+ if (typeof value === "object") {
766
+ return formatObjectValue(value);
767
+ }
768
+ return formatPrimitive(value);
498
769
  }
499
770
  function getNestedValue(row, path) {
500
771
  if (!path.includes(".")) return row[path];
@@ -1118,10 +1389,40 @@ function getColumnFreezeStyle(offset, options) {
1118
1389
  return {
1119
1390
  position: "sticky",
1120
1391
  ...offset.side === "left" ? { left: offset.offset } : { right: offset.offset },
1121
- zIndex: zBase + offset.stack,
1122
- ...options?.isHeader ? { top: 0 } : {}
1392
+ zIndex: zBase + offset.stack
1123
1393
  };
1124
1394
  }
1395
+ function resolveHeaderFreezeOffset(column, freezeOffsets) {
1396
+ const direct = freezeOffsets.get(column.id);
1397
+ if (direct) return direct;
1398
+ const leaves = typeof column.getLeafColumns === "function" ? column.getLeafColumns() : column.columns && column.columns.length > 0 ? flattenHeaderLeaves(column) : [];
1399
+ if (leaves.length === 0) return void 0;
1400
+ const leafOffsets = [];
1401
+ for (const leaf of leaves) {
1402
+ const offset2 = freezeOffsets.get(leaf.id);
1403
+ if (!offset2) return void 0;
1404
+ leafOffsets.push(offset2);
1405
+ }
1406
+ const side = leafOffsets[0]?.side;
1407
+ if (!side || leafOffsets.some((offset2) => offset2.side !== side)) {
1408
+ return void 0;
1409
+ }
1410
+ const offset = Math.min(...leafOffsets.map((item) => item.offset));
1411
+ const leftmost = leafOffsets[0];
1412
+ const rightmost = leafOffsets[leafOffsets.length - 1];
1413
+ return {
1414
+ side,
1415
+ offset,
1416
+ edgeLeft: leftmost.edgeLeft,
1417
+ edgeRight: rightmost.edgeRight,
1418
+ isEdge: leftmost.edgeLeft || rightmost.edgeRight,
1419
+ stack: Math.max(...leafOffsets.map((item) => item.stack))
1420
+ };
1421
+ }
1422
+ function flattenHeaderLeaves(column) {
1423
+ if (!column.columns || column.columns.length === 0) return [column];
1424
+ return column.columns.flatMap((child) => flattenHeaderLeaves(child));
1425
+ }
1125
1426
 
1126
1427
  // src/components/ui/table/features/inline-search/inlineSearch.ts
1127
1428
  var INLINE_SEARCH_MAX_RESULTS = 1e3;
@@ -1872,6 +2173,7 @@ function useGlideTable(options) {
1872
2173
  onDataChange,
1873
2174
  onCellChange,
1874
2175
  onBatchChange,
2176
+ cellRenderers,
1875
2177
  preserveRowSelection = false,
1876
2178
  toggleField,
1877
2179
  childField,
@@ -2097,6 +2399,22 @@ function useGlideTable(options) {
2097
2399
  commitEdit,
2098
2400
  cancelEdit
2099
2401
  } = useCellEdit({ data: tableData, rows, onDataChange, onCellChange });
2402
+ const cellRendererRegistry = useMemo3(
2403
+ () => createCellRendererRegistry(cellRenderers),
2404
+ [cellRenderers]
2405
+ );
2406
+ const commitRenderedCellValue = useCallback4(
2407
+ (rowId, columnId, value) => commitCellValue({
2408
+ data: tableData,
2409
+ rows,
2410
+ rowId,
2411
+ columnId,
2412
+ value,
2413
+ onCellChange,
2414
+ onDataChange
2415
+ }),
2416
+ [onCellChange, onDataChange, rows, tableData]
2417
+ );
2100
2418
  const handleCellMouseDownWithCommit = useCallback4(
2101
2419
  (rowIndex, colIndex, options2) => {
2102
2420
  const isSameEditingCell = editingCell?.rowIndex === rowIndex && editingCell?.colIndex === colIndex;
@@ -2333,6 +2651,10 @@ function useGlideTable(options) {
2333
2651
  onCommitEdit: commitEdit,
2334
2652
  onCancelEdit: cancelEdit
2335
2653
  },
2654
+ cellRender: {
2655
+ registry: cellRendererRegistry,
2656
+ commitValue: commitRenderedCellValue
2657
+ },
2336
2658
  expand: {
2337
2659
  enableExpand,
2338
2660
  toggleField,
@@ -2379,6 +2701,8 @@ function useGlideTable(options) {
2379
2701
  startEdit,
2380
2702
  commitEdit,
2381
2703
  cancelEdit,
2704
+ cellRendererRegistry,
2705
+ commitRenderedCellValue,
2382
2706
  enableExpand,
2383
2707
  toggleField,
2384
2708
  expandedRows,
@@ -2443,6 +2767,60 @@ function useGlideTable(options) {
2443
2767
  };
2444
2768
  }
2445
2769
 
2770
+ // src/components/ui/table/features/cell-render/ResolvedTableCell.tsx
2771
+ import { useCallback as useCallback5 } from "react";
2772
+
2773
+ // src/components/ui/table/DataTableContext.tsx
2774
+ import { createContext, use } from "react";
2775
+ import { jsx as jsx2 } from "react/jsx-runtime";
2776
+ var DataTableContext = createContext(null);
2777
+ function useDataTableRowContext() {
2778
+ const context = use(DataTableContext);
2779
+ if (!context) {
2780
+ throw new Error("useDataTableRowContext must be used within a DataTableContextProvider");
2781
+ }
2782
+ return context;
2783
+ }
2784
+ function DataTableContextProvider({
2785
+ value,
2786
+ children
2787
+ }) {
2788
+ return /* @__PURE__ */ jsx2(DataTableContext, { value, children });
2789
+ }
2790
+
2791
+ // src/components/ui/table/features/cell-render/ResolvedTableCell.tsx
2792
+ function ResolvedTableCell({
2793
+ info
2794
+ }) {
2795
+ const { cellRender } = useDataTableRowContext();
2796
+ const { row, column, getValue } = info;
2797
+ const meta = column.columnDef.meta;
2798
+ const value = getValue();
2799
+ const columnId = column.id;
2800
+ const update = useCallback5(
2801
+ (next) => {
2802
+ cellRender.commitValue(row.id, columnId, next);
2803
+ },
2804
+ [cellRender, columnId, row.id]
2805
+ );
2806
+ const ctx = {
2807
+ value,
2808
+ row,
2809
+ index: row.index,
2810
+ columnId,
2811
+ cellProps: meta?.cellProps,
2812
+ update
2813
+ };
2814
+ if (meta?.cellRender) {
2815
+ return meta.cellRender(ctx);
2816
+ }
2817
+ const renderer = resolveCellRenderer(cellRender.registry, meta?.kind, ctx);
2818
+ if (renderer) {
2819
+ return renderer.render(ctx);
2820
+ }
2821
+ return formatDefaultCellValue(value);
2822
+ }
2823
+
2446
2824
  // src/components/ui/table/features/column-resize/columnResize.ts
2447
2825
  function getColumnSizeStyle(size, options) {
2448
2826
  const { force = false, lockMax = false } = options ?? {};
@@ -2464,28 +2842,10 @@ import { useMemo as useMemo4 } from "react";
2464
2842
  import { flexRender } from "@tanstack/react-table";
2465
2843
  import { useEffect as useEffect6, useRef as useRef6 } from "react";
2466
2844
 
2467
- // src/components/ui/table/DataTableContext.tsx
2468
- import { createContext, use } from "react";
2469
- import { jsx } from "react/jsx-runtime";
2470
- var DataTableContext = createContext(null);
2471
- function useDataTableRowContext() {
2472
- const context = use(DataTableContext);
2473
- if (!context) {
2474
- throw new Error("useDataTableRowContext must be used within a DataTableContextProvider");
2475
- }
2476
- return context;
2477
- }
2478
- function DataTableContextProvider({
2479
- value,
2480
- children
2481
- }) {
2482
- return /* @__PURE__ */ jsx(DataTableContext, { value, children });
2483
- }
2484
-
2485
2845
  // src/components/ui/table/components/icons.tsx
2486
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
2846
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
2487
2847
  function ChevronDown({ className, "aria-hidden": ariaHidden = true }) {
2488
- return /* @__PURE__ */ jsx2(
2848
+ return /* @__PURE__ */ jsx3(
2489
2849
  "svg",
2490
2850
  {
2491
2851
  className,
@@ -2498,12 +2858,12 @@ function ChevronDown({ className, "aria-hidden": ariaHidden = true }) {
2498
2858
  strokeWidth: "2",
2499
2859
  strokeLinecap: "round",
2500
2860
  strokeLinejoin: "round",
2501
- children: /* @__PURE__ */ jsx2("path", { d: "m6 9 6 6 6-6" })
2861
+ children: /* @__PURE__ */ jsx3("path", { d: "m6 9 6 6 6-6" })
2502
2862
  }
2503
2863
  );
2504
2864
  }
2505
2865
  function ChevronUp({ className, "aria-hidden": ariaHidden = true }) {
2506
- return /* @__PURE__ */ jsx2(
2866
+ return /* @__PURE__ */ jsx3(
2507
2867
  "svg",
2508
2868
  {
2509
2869
  className,
@@ -2516,12 +2876,12 @@ function ChevronUp({ className, "aria-hidden": ariaHidden = true }) {
2516
2876
  strokeWidth: "2",
2517
2877
  strokeLinecap: "round",
2518
2878
  strokeLinejoin: "round",
2519
- children: /* @__PURE__ */ jsx2("path", { d: "m18 15-6-6-6 6" })
2879
+ children: /* @__PURE__ */ jsx3("path", { d: "m18 15-6-6-6 6" })
2520
2880
  }
2521
2881
  );
2522
2882
  }
2523
2883
  function ChevronLeft({ className, "aria-hidden": ariaHidden = true }) {
2524
- return /* @__PURE__ */ jsx2(
2884
+ return /* @__PURE__ */ jsx3(
2525
2885
  "svg",
2526
2886
  {
2527
2887
  className,
@@ -2534,12 +2894,12 @@ function ChevronLeft({ className, "aria-hidden": ariaHidden = true }) {
2534
2894
  strokeWidth: "2",
2535
2895
  strokeLinecap: "round",
2536
2896
  strokeLinejoin: "round",
2537
- children: /* @__PURE__ */ jsx2("path", { d: "m15 18-6-6 6-6" })
2897
+ children: /* @__PURE__ */ jsx3("path", { d: "m15 18-6-6 6-6" })
2538
2898
  }
2539
2899
  );
2540
2900
  }
2541
2901
  function ChevronRight({ className, "aria-hidden": ariaHidden = true }) {
2542
- return /* @__PURE__ */ jsx2(
2902
+ return /* @__PURE__ */ jsx3(
2543
2903
  "svg",
2544
2904
  {
2545
2905
  className,
@@ -2552,12 +2912,12 @@ function ChevronRight({ className, "aria-hidden": ariaHidden = true }) {
2552
2912
  strokeWidth: "2",
2553
2913
  strokeLinecap: "round",
2554
2914
  strokeLinejoin: "round",
2555
- children: /* @__PURE__ */ jsx2("path", { d: "m9 18 6-6-6-6" })
2915
+ children: /* @__PURE__ */ jsx3("path", { d: "m9 18 6-6-6-6" })
2556
2916
  }
2557
2917
  );
2558
2918
  }
2559
2919
  function ArrowUp({ className, "aria-hidden": ariaHidden = true }) {
2560
- return /* @__PURE__ */ jsxs(
2920
+ return /* @__PURE__ */ jsxs2(
2561
2921
  "svg",
2562
2922
  {
2563
2923
  className,
@@ -2571,14 +2931,14 @@ function ArrowUp({ className, "aria-hidden": ariaHidden = true }) {
2571
2931
  strokeLinecap: "round",
2572
2932
  strokeLinejoin: "round",
2573
2933
  children: [
2574
- /* @__PURE__ */ jsx2("path", { d: "m18 15-6-6-6 6" }),
2575
- /* @__PURE__ */ jsx2("path", { d: "M12 21V9" })
2934
+ /* @__PURE__ */ jsx3("path", { d: "m18 15-6-6-6 6" }),
2935
+ /* @__PURE__ */ jsx3("path", { d: "M12 21V9" })
2576
2936
  ]
2577
2937
  }
2578
2938
  );
2579
2939
  }
2580
2940
  function ArrowDown({ className, "aria-hidden": ariaHidden = true }) {
2581
- return /* @__PURE__ */ jsxs(
2941
+ return /* @__PURE__ */ jsxs2(
2582
2942
  "svg",
2583
2943
  {
2584
2944
  className,
@@ -2592,14 +2952,14 @@ function ArrowDown({ className, "aria-hidden": ariaHidden = true }) {
2592
2952
  strokeLinecap: "round",
2593
2953
  strokeLinejoin: "round",
2594
2954
  children: [
2595
- /* @__PURE__ */ jsx2("path", { d: "m6 9 6 6 6-6" }),
2596
- /* @__PURE__ */ jsx2("path", { d: "M12 3v12" })
2955
+ /* @__PURE__ */ jsx3("path", { d: "m6 9 6 6 6-6" }),
2956
+ /* @__PURE__ */ jsx3("path", { d: "M12 3v12" })
2597
2957
  ]
2598
2958
  }
2599
2959
  );
2600
2960
  }
2601
2961
  function ArrowUpDown({ className, "aria-hidden": ariaHidden = true }) {
2602
- return /* @__PURE__ */ jsxs(
2962
+ return /* @__PURE__ */ jsxs2(
2603
2963
  "svg",
2604
2964
  {
2605
2965
  className,
@@ -2613,10 +2973,10 @@ function ArrowUpDown({ className, "aria-hidden": ariaHidden = true }) {
2613
2973
  strokeLinecap: "round",
2614
2974
  strokeLinejoin: "round",
2615
2975
  children: [
2616
- /* @__PURE__ */ jsx2("path", { d: "m21 16-4 4-4-4" }),
2617
- /* @__PURE__ */ jsx2("path", { d: "M17 20V4" }),
2618
- /* @__PURE__ */ jsx2("path", { d: "m3 8 4-4 4 4" }),
2619
- /* @__PURE__ */ jsx2("path", { d: "M7 4v16" })
2976
+ /* @__PURE__ */ jsx3("path", { d: "m21 16-4 4-4-4" }),
2977
+ /* @__PURE__ */ jsx3("path", { d: "M17 20V4" }),
2978
+ /* @__PURE__ */ jsx3("path", { d: "m3 8 4-4 4 4" }),
2979
+ /* @__PURE__ */ jsx3("path", { d: "M7 4v16" })
2620
2980
  ]
2621
2981
  }
2622
2982
  );
@@ -2628,7 +2988,7 @@ function cn(...inputs) {
2628
2988
  }
2629
2989
 
2630
2990
  // src/components/ui/table/components/DataTable/DataTableRow.tsx
2631
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
2991
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
2632
2992
  function isInteractiveMouseTarget(target) {
2633
2993
  if (!(target instanceof Element)) return false;
2634
2994
  const interactiveSelector = [
@@ -2780,7 +3140,7 @@ function DataTableRow({
2780
3140
  editInputRef.current?.focus();
2781
3141
  editInputRef.current?.select();
2782
3142
  }, [isRowEditing, editingCell?.colIndex]);
2783
- return /* @__PURE__ */ jsx3(
3143
+ return /* @__PURE__ */ jsx4(
2784
3144
  "tr",
2785
3145
  {
2786
3146
  ref: measureElement,
@@ -2874,7 +3234,7 @@ function DataTableRow({
2874
3234
  const searchMatchKey = buildSearchMatchKey(cellIndex, rowIndex);
2875
3235
  const isSearchMatch = enableInlineSearch && searchMatchKeys.has(searchMatchKey);
2876
3236
  const isSearchActive = isSearchMatch && activeMatch !== null && activeMatch[0] === cellIndex && activeMatch[1] === rowIndex;
2877
- return /* @__PURE__ */ jsxs2(
3237
+ return /* @__PURE__ */ jsxs3(
2878
3238
  "td",
2879
3239
  {
2880
3240
  "data-row-index": rowIndex,
@@ -2948,7 +3308,7 @@ function DataTableRow({
2948
3308
  classNames?.cell
2949
3309
  ),
2950
3310
  children: [
2951
- isEditing ? /* @__PURE__ */ jsx3(
3311
+ isEditing ? /* @__PURE__ */ jsx4(
2952
3312
  "input",
2953
3313
  {
2954
3314
  ...editInputProps,
@@ -2991,8 +3351,8 @@ function DataTableRow({
2991
3351
  onCommitEdit(event.currentTarget.value);
2992
3352
  }
2993
3353
  }
2994
- ) : isExpandCell && enableExpand ? /* @__PURE__ */ jsxs2("div", { className: cn("expand-cell", classNames?.expandCell), children: [
2995
- /* @__PURE__ */ jsxs2(
3354
+ ) : isExpandCell && enableExpand ? /* @__PURE__ */ jsxs3("div", { className: cn("expand-cell", classNames?.expandCell), children: [
3355
+ /* @__PURE__ */ jsxs3(
2996
3356
  "div",
2997
3357
  {
2998
3358
  className: cn(
@@ -3000,7 +3360,7 @@ function DataTableRow({
3000
3360
  classNames?.expandCellContent
3001
3361
  ),
3002
3362
  children: [
3003
- rowLevel > 0 && /* @__PURE__ */ jsx3(
3363
+ rowLevel > 0 && /* @__PURE__ */ jsx4(
3004
3364
  "span",
3005
3365
  {
3006
3366
  className: cn(
@@ -3010,7 +3370,7 @@ function DataTableRow({
3010
3370
  children: "\xB7"
3011
3371
  }
3012
3372
  ),
3013
- /* @__PURE__ */ jsx3(
3373
+ /* @__PURE__ */ jsx4(
3014
3374
  "div",
3015
3375
  {
3016
3376
  className: cn(
@@ -3023,7 +3383,7 @@ function DataTableRow({
3023
3383
  ]
3024
3384
  }
3025
3385
  ),
3026
- canExpand && expandKey && /* @__PURE__ */ jsx3(
3386
+ canExpand && expandKey && /* @__PURE__ */ jsx4(
3027
3387
  "button",
3028
3388
  {
3029
3389
  type: "button",
@@ -3037,7 +3397,7 @@ function DataTableRow({
3037
3397
  onToggleExpand?.(expandKey);
3038
3398
  },
3039
3399
  onMouseDown: (event) => event.stopPropagation(),
3040
- children: isExpanded ? /* @__PURE__ */ jsx3(
3400
+ children: isExpanded ? /* @__PURE__ */ jsx4(
3041
3401
  ChevronUp,
3042
3402
  {
3043
3403
  className: cn(
@@ -3045,7 +3405,7 @@ function DataTableRow({
3045
3405
  classNames?.expandToggleIcon
3046
3406
  )
3047
3407
  }
3048
- ) : /* @__PURE__ */ jsx3(
3408
+ ) : /* @__PURE__ */ jsx4(
3049
3409
  ChevronDown,
3050
3410
  {
3051
3411
  className: cn(
@@ -3057,7 +3417,7 @@ function DataTableRow({
3057
3417
  }
3058
3418
  )
3059
3419
  ] }) : flexRender(cell.column.columnDef.cell, cell.getContext()),
3060
- isBottomRightCell && /* @__PURE__ */ jsx3(
3420
+ isBottomRightCell && /* @__PURE__ */ jsx4(
3061
3421
  "div",
3062
3422
  {
3063
3423
  role: "presentation",
@@ -3079,9 +3439,9 @@ function DataTableRow({
3079
3439
  }
3080
3440
 
3081
3441
  // src/components/ui/table/components/DataTable/DataTableSearch.tsx
3082
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
3442
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
3083
3443
  function SearchCloseIcon({ className }) {
3084
- return /* @__PURE__ */ jsxs3(
3444
+ return /* @__PURE__ */ jsxs4(
3085
3445
  "svg",
3086
3446
  {
3087
3447
  className,
@@ -3095,8 +3455,8 @@ function SearchCloseIcon({ className }) {
3095
3455
  strokeLinecap: "round",
3096
3456
  strokeLinejoin: "round",
3097
3457
  children: [
3098
- /* @__PURE__ */ jsx4("path", { d: "M18 6 6 18" }),
3099
- /* @__PURE__ */ jsx4("path", { d: "m6 6 12 12" })
3458
+ /* @__PURE__ */ jsx5("path", { d: "M18 6 6 18" }),
3459
+ /* @__PURE__ */ jsx5("path", { d: "m6 6 12 12" })
3100
3460
  ]
3101
3461
  }
3102
3462
  );
@@ -3142,15 +3502,15 @@ function DataTableSearch({
3142
3502
  onPrevious();
3143
3503
  }
3144
3504
  };
3145
- return /* @__PURE__ */ jsxs3(
3505
+ return /* @__PURE__ */ jsxs4(
3146
3506
  "div",
3147
3507
  {
3148
3508
  className: cn("data-table-search", classNames?.search),
3149
3509
  role: "search",
3150
3510
  onMouseDown: (event) => event.stopPropagation(),
3151
3511
  children: [
3152
- /* @__PURE__ */ jsxs3("div", { className: "data-table-search-row", children: [
3153
- /* @__PURE__ */ jsx4(
3512
+ /* @__PURE__ */ jsxs4("div", { className: "data-table-search-row", children: [
3513
+ /* @__PURE__ */ jsx5(
3154
3514
  "input",
3155
3515
  {
3156
3516
  ref: searchInputRef,
@@ -3166,7 +3526,7 @@ function DataTableSearch({
3166
3526
  onKeyDown: handleKeyDown
3167
3527
  }
3168
3528
  ),
3169
- /* @__PURE__ */ jsx4(
3529
+ /* @__PURE__ */ jsx5(
3170
3530
  "button",
3171
3531
  {
3172
3532
  type: "button",
@@ -3176,10 +3536,10 @@ function DataTableSearch({
3176
3536
  event.stopPropagation();
3177
3537
  onPrevious();
3178
3538
  },
3179
- children: /* @__PURE__ */ jsx4(ChevronUp, { className: "data-table-search-icon" })
3539
+ children: /* @__PURE__ */ jsx5(ChevronUp, { className: "data-table-search-icon" })
3180
3540
  }
3181
3541
  ),
3182
- /* @__PURE__ */ jsx4(
3542
+ /* @__PURE__ */ jsx5(
3183
3543
  "button",
3184
3544
  {
3185
3545
  type: "button",
@@ -3189,10 +3549,10 @@ function DataTableSearch({
3189
3549
  event.stopPropagation();
3190
3550
  onNext();
3191
3551
  },
3192
- children: /* @__PURE__ */ jsx4(ChevronDown, { className: "data-table-search-icon" })
3552
+ children: /* @__PURE__ */ jsx5(ChevronDown, { className: "data-table-search-icon" })
3193
3553
  }
3194
3554
  ),
3195
- canClose ? /* @__PURE__ */ jsx4(
3555
+ canClose ? /* @__PURE__ */ jsx5(
3196
3556
  "button",
3197
3557
  {
3198
3558
  type: "button",
@@ -3202,11 +3562,11 @@ function DataTableSearch({
3202
3562
  event.stopPropagation();
3203
3563
  onClose();
3204
3564
  },
3205
- children: /* @__PURE__ */ jsx4(SearchCloseIcon, { className: "data-table-search-icon" })
3565
+ children: /* @__PURE__ */ jsx5(SearchCloseIcon, { className: "data-table-search-icon" })
3206
3566
  }
3207
3567
  ) : null
3208
3568
  ] }),
3209
- /* @__PURE__ */ jsx4(
3569
+ /* @__PURE__ */ jsx5(
3210
3570
  "div",
3211
3571
  {
3212
3572
  className: cn("data-table-search-status", classNames?.searchStatus),
@@ -3214,7 +3574,7 @@ function DataTableSearch({
3214
3574
  children: resultString
3215
3575
  }
3216
3576
  ),
3217
- searchStatus !== void 0 ? /* @__PURE__ */ jsx4(
3577
+ searchStatus !== void 0 ? /* @__PURE__ */ jsx5(
3218
3578
  "div",
3219
3579
  {
3220
3580
  className: cn(
@@ -3225,7 +3585,7 @@ function DataTableSearch({
3225
3585
  "aria-valuemin": 0,
3226
3586
  "aria-valuemax": 100,
3227
3587
  "aria-valuenow": progress,
3228
- children: /* @__PURE__ */ jsx4(
3588
+ children: /* @__PURE__ */ jsx5(
3229
3589
  "div",
3230
3590
  {
3231
3591
  className: "data-table-search-progress-bar",
@@ -3240,7 +3600,7 @@ function DataTableSearch({
3240
3600
  }
3241
3601
 
3242
3602
  // src/components/ui/table/components/DataTable/DataTableToolbar.tsx
3243
- import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
3603
+ import { Fragment, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
3244
3604
  function DataTableToolbar({
3245
3605
  filteredCount,
3246
3606
  totalCount,
@@ -3258,39 +3618,71 @@ function DataTableToolbar({
3258
3618
  const selectionContent = selectionLabel?.(selectedCount) ?? null;
3259
3619
  const hasSelectionContent = selectionContent !== null && selectionContent !== false && selectionContent !== void 0 && typeof selectionContent !== "boolean";
3260
3620
  if (!hasLeftContent && !hasToolbar && !hasSelectionContent) return null;
3261
- return /* @__PURE__ */ jsxs4("div", { className: cn("DataTableToolbarJSX", classNames?.toolbar, className), children: [
3262
- /* @__PURE__ */ jsxs4("div", { className: cn("toolbar-left", classNames?.toolbarLeft), children: [
3263
- hasCount && /* @__PURE__ */ jsx5("span", { className: cn("toolbar-count", classNames?.toolbarCount), children: displayFiltered !== void 0 && totalCount !== void 0 ? /* @__PURE__ */ jsxs4(Fragment, { children: [
3264
- /* @__PURE__ */ jsx5("span", { className: "toolbar-count-primary", children: displayFiltered }),
3265
- /* @__PURE__ */ jsxs4("span", { className: "toolbar-count-placeholder", children: [
3621
+ return /* @__PURE__ */ jsxs5("div", { className: cn("DataTableToolbarJSX", classNames?.toolbar, className), children: [
3622
+ /* @__PURE__ */ jsxs5("div", { className: cn("toolbar-left", classNames?.toolbarLeft), children: [
3623
+ hasCount && /* @__PURE__ */ jsx6("span", { className: cn("toolbar-count", classNames?.toolbarCount), children: displayFiltered !== void 0 && totalCount !== void 0 ? /* @__PURE__ */ jsxs5(Fragment, { children: [
3624
+ /* @__PURE__ */ jsx6("span", { className: "toolbar-count-primary", children: displayFiltered }),
3625
+ /* @__PURE__ */ jsxs5("span", { className: "toolbar-count-placeholder", children: [
3266
3626
  " / ",
3267
3627
  totalCount
3268
3628
  ] })
3269
- ] }) : /* @__PURE__ */ jsx5("span", { className: "toolbar-count-primary", children: displayFiltered ?? totalCount }) }),
3629
+ ] }) : /* @__PURE__ */ jsx6("span", { className: "toolbar-count-primary", children: displayFiltered ?? totalCount }) }),
3270
3630
  summary
3271
3631
  ] }),
3272
- /* @__PURE__ */ jsxs4("div", { className: cn("toolbar-right", classNames?.toolbarRight), children: [
3273
- hasSelectionContent && (typeof selectionContent === "string" || typeof selectionContent === "number" ? /* @__PURE__ */ jsx5("span", { className: cn("toolbar-selection", classNames?.toolbarSelection), children: selectionContent }) : selectionContent),
3274
- hasToolbar && /* @__PURE__ */ jsx5("div", { className: cn("toolbar-actions", classNames?.toolbarActions), children: toolbar })
3632
+ /* @__PURE__ */ jsxs5("div", { className: cn("toolbar-right", classNames?.toolbarRight), children: [
3633
+ hasSelectionContent && (typeof selectionContent === "string" || typeof selectionContent === "number" ? /* @__PURE__ */ jsx6("span", { className: cn("toolbar-selection", classNames?.toolbarSelection), children: selectionContent }) : selectionContent),
3634
+ hasToolbar && /* @__PURE__ */ jsx6("div", { className: cn("toolbar-actions", classNames?.toolbarActions), children: toolbar })
3275
3635
  ] })
3276
3636
  ] });
3277
3637
  }
3278
3638
 
3639
+ // src/components/ui/table/features/column-groups/mergeHeaderGroups.ts
3640
+ function getMergedHeaderGroups(headerGroups) {
3641
+ if (headerGroups.length <= 1) {
3642
+ return headerGroups.map((group) => ({
3643
+ ...group,
3644
+ headers: group.headers.map((header) => ({
3645
+ ...header,
3646
+ mergedRowSpan: 1
3647
+ }))
3648
+ }));
3649
+ }
3650
+ const seenColumnIds = /* @__PURE__ */ new Set();
3651
+ const fullDepth = headerGroups.length;
3652
+ return headerGroups.map((group, depth) => ({
3653
+ ...group,
3654
+ headers: group.headers.filter((header) => !seenColumnIds.has(header.column.id)).map((header) => {
3655
+ seenColumnIds.add(header.column.id);
3656
+ if (header.isPlaceholder) {
3657
+ return {
3658
+ ...header,
3659
+ isPlaceholder: false,
3660
+ mergedRowSpan: fullDepth - depth
3661
+ };
3662
+ }
3663
+ return {
3664
+ ...header,
3665
+ mergedRowSpan: 1
3666
+ };
3667
+ })
3668
+ }));
3669
+ }
3670
+
3279
3671
  // src/components/ui/table/components/DataTable/DataTable.tsx
3280
- import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
3672
+ import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
3281
3673
  function DefaultScroll({
3282
3674
  scrollRef,
3283
3675
  children,
3284
3676
  className
3285
3677
  }) {
3286
- return /* @__PURE__ */ jsx6("div", { ref: scrollRef, className: cn("data-table-scroll", className), children });
3678
+ return /* @__PURE__ */ jsx7("div", { ref: scrollRef, className: cn("data-table-scroll", className), children });
3287
3679
  }
3288
3680
  function DefaultPending({
3289
3681
  loadingText,
3290
3682
  className,
3291
3683
  classNames
3292
3684
  }) {
3293
- return /* @__PURE__ */ jsx6(
3685
+ return /* @__PURE__ */ jsx7(
3294
3686
  "div",
3295
3687
  {
3296
3688
  className: cn(
@@ -3300,7 +3692,7 @@ function DefaultPending({
3300
3692
  classNames?.pending,
3301
3693
  className
3302
3694
  ),
3303
- children: /* @__PURE__ */ jsx6("span", { className: cn("data-table-loading-text", classNames?.loadingText), children: loadingText })
3695
+ children: /* @__PURE__ */ jsx7("span", { className: cn("data-table-loading-text", classNames?.loadingText), children: loadingText })
3304
3696
  }
3305
3697
  );
3306
3698
  }
@@ -3309,7 +3701,7 @@ function DefaultEmpty({
3309
3701
  columnCount,
3310
3702
  classNames
3311
3703
  }) {
3312
- return /* @__PURE__ */ jsx6("tr", { children: /* @__PURE__ */ jsx6(
3704
+ return /* @__PURE__ */ jsx7("tr", { children: /* @__PURE__ */ jsx7(
3313
3705
  "td",
3314
3706
  {
3315
3707
  colSpan: columnCount,
@@ -3361,12 +3753,13 @@ function DataTable({
3361
3753
  const PendingSlot = slots?.Pending ?? DefaultPending;
3362
3754
  const EmptySlot = slots?.Empty ?? DefaultEmpty;
3363
3755
  const freezeOffsets = rowContextValue.columnFreeze.offsets;
3756
+ const headerGroups = getMergedHeaderGroups(table.getHeaderGroups());
3364
3757
  const contextValue = useMemo4(
3365
3758
  () => ({ ...rowContextValue, classNames }),
3366
3759
  [rowContextValue, classNames]
3367
3760
  );
3368
3761
  if (isPending) {
3369
- return /* @__PURE__ */ jsx6(
3762
+ return /* @__PURE__ */ jsx7(
3370
3763
  PendingSlot,
3371
3764
  {
3372
3765
  loadingText,
@@ -3375,7 +3768,7 @@ function DataTable({
3375
3768
  }
3376
3769
  );
3377
3770
  }
3378
- return /* @__PURE__ */ jsxs5(
3771
+ return /* @__PURE__ */ jsxs6(
3379
3772
  "div",
3380
3773
  {
3381
3774
  ref: rootRef,
@@ -3389,7 +3782,7 @@ function DataTable({
3389
3782
  className
3390
3783
  ),
3391
3784
  children: [
3392
- /* @__PURE__ */ jsx6(
3785
+ /* @__PURE__ */ jsx7(
3393
3786
  ToolbarSlot,
3394
3787
  {
3395
3788
  filteredCount: filteredCount ?? tableData.length,
@@ -3401,7 +3794,7 @@ function DataTable({
3401
3794
  classNames
3402
3795
  }
3403
3796
  ),
3404
- enableInlineSearch ? /* @__PURE__ */ jsx6(
3797
+ enableInlineSearch ? /* @__PURE__ */ jsx7(
3405
3798
  DataTableSearch,
3406
3799
  {
3407
3800
  showSearch: inlineSearch.showSearch,
@@ -3423,14 +3816,14 @@ function DataTable({
3423
3816
  onPrevious: inlineSearch.goToPrevious
3424
3817
  }
3425
3818
  ) : null,
3426
- /* @__PURE__ */ jsx6(ScrollSlot, { scrollRef, className: classNames?.scroll, children: /* @__PURE__ */ jsxs5(
3819
+ /* @__PURE__ */ jsx7(ScrollSlot, { scrollRef, className: classNames?.scroll, children: /* @__PURE__ */ jsxs6(
3427
3820
  "table",
3428
3821
  {
3429
3822
  className: cn("data-table", classNames?.table),
3430
3823
  style: enableColumnResize ? { width: table.getTotalSize() } : void 0,
3431
3824
  onDragStart: enableCellSelection ? (event) => event.preventDefault() : void 0,
3432
3825
  children: [
3433
- /* @__PURE__ */ jsx6("thead", { className: cn("data-table-head", classNames?.head), children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx6(
3826
+ /* @__PURE__ */ jsx7("thead", { className: cn("data-table-head", classNames?.head), children: headerGroups.map((headerGroup) => /* @__PURE__ */ jsx7(
3434
3827
  "tr",
3435
3828
  {
3436
3829
  className: cn("data-table-head-row", classNames?.headRow),
@@ -3442,17 +3835,20 @@ function DataTable({
3442
3835
  force: enableColumnResize,
3443
3836
  lockMax: enableColumnResize
3444
3837
  });
3445
- const freezeOffset = enableColumnFreeze ? freezeOffsets.get(header.column.id) : void 0;
3838
+ const freezeOffset = enableColumnFreeze ? resolveHeaderFreezeOffset(header.column, freezeOffsets) : void 0;
3446
3839
  const freezeStyle = getColumnFreezeStyle(freezeOffset, {
3447
- isHeader: true
3840
+ isHeader: true,
3841
+ headerTop: header.depth * DATA_TABLE_HEADER_ROW_HEIGHT
3448
3842
  });
3449
3843
  const headerStyle = {
3450
3844
  ...sizeStyle,
3451
3845
  ...freezeStyle
3452
3846
  };
3453
- return /* @__PURE__ */ jsxs5(
3847
+ return /* @__PURE__ */ jsxs6(
3454
3848
  "th",
3455
3849
  {
3850
+ colSpan: header.colSpan,
3851
+ rowSpan: header.mergedRowSpan,
3456
3852
  "data-resizing": header.column.getIsResizing() ? "" : void 0,
3457
3853
  "data-frozen": freezeOffset?.side,
3458
3854
  "data-freeze-edge": getColumnFreezeEdgeAttr(freezeOffset),
@@ -3465,8 +3861,11 @@ function DataTable({
3465
3861
  headerClassName
3466
3862
  ),
3467
3863
  children: [
3468
- header.isPlaceholder ? null : flexRender2(header.column.columnDef.header, header.getContext()),
3469
- canResize ? /* @__PURE__ */ jsx6(
3864
+ header.isPlaceholder ? null : flexRender2(
3865
+ header.column.columnDef.header,
3866
+ header.getContext()
3867
+ ),
3868
+ canResize ? /* @__PURE__ */ jsx7(
3470
3869
  "div",
3471
3870
  {
3472
3871
  role: "separator",
@@ -3492,20 +3891,20 @@ function DataTable({
3492
3891
  },
3493
3892
  headerGroup.id
3494
3893
  )) }),
3495
- /* @__PURE__ */ jsx6(DataTableContextProvider, { value: contextValue, children: /* @__PURE__ */ jsx6(
3894
+ /* @__PURE__ */ jsx7(DataTableContextProvider, { value: contextValue, children: /* @__PURE__ */ jsx7(
3496
3895
  "tbody",
3497
3896
  {
3498
3897
  onMouseLeave: clearHover,
3499
3898
  className: cn("data-table-body", classNames?.body),
3500
- children: rows.length === 0 ? /* @__PURE__ */ jsx6(
3899
+ children: rows.length === 0 ? /* @__PURE__ */ jsx7(
3501
3900
  EmptySlot,
3502
3901
  {
3503
3902
  emptyText,
3504
3903
  columnCount,
3505
3904
  classNames
3506
3905
  }
3507
- ) : shouldVirtualize ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
3508
- paddingTop > 0 && /* @__PURE__ */ jsx6(
3906
+ ) : shouldVirtualize ? /* @__PURE__ */ jsxs6(Fragment2, { children: [
3907
+ paddingTop > 0 && /* @__PURE__ */ jsx7(
3509
3908
  "tr",
3510
3909
  {
3511
3910
  "aria-hidden": true,
@@ -3513,7 +3912,7 @@ function DataTable({
3513
3912
  "data-table-virtual-spacer",
3514
3913
  classNames?.virtualSpacer
3515
3914
  ),
3516
- children: /* @__PURE__ */ jsx6(
3915
+ children: /* @__PURE__ */ jsx7(
3517
3916
  "td",
3518
3917
  {
3519
3918
  colSpan: columnCount,
@@ -3529,7 +3928,7 @@ function DataTable({
3529
3928
  virtualRows.map((virtualRow) => {
3530
3929
  const row = rows[virtualRow.index];
3531
3930
  if (!row) return null;
3532
- return /* @__PURE__ */ jsx6(
3931
+ return /* @__PURE__ */ jsx7(
3533
3932
  RowSlot,
3534
3933
  {
3535
3934
  row,
@@ -3540,7 +3939,7 @@ function DataTable({
3540
3939
  row.id
3541
3940
  );
3542
3941
  }),
3543
- paddingBottom > 0 && /* @__PURE__ */ jsx6(
3942
+ paddingBottom > 0 && /* @__PURE__ */ jsx7(
3544
3943
  "tr",
3545
3944
  {
3546
3945
  "aria-hidden": true,
@@ -3548,7 +3947,7 @@ function DataTable({
3548
3947
  "data-table-virtual-spacer",
3549
3948
  classNames?.virtualSpacer
3550
3949
  ),
3551
- children: /* @__PURE__ */ jsx6(
3950
+ children: /* @__PURE__ */ jsx7(
3552
3951
  "td",
3553
3952
  {
3554
3953
  colSpan: columnCount,
@@ -3561,7 +3960,7 @@ function DataTable({
3561
3960
  )
3562
3961
  }
3563
3962
  )
3564
- ] }) : rows.map((row) => /* @__PURE__ */ jsx6(
3963
+ ] }) : rows.map((row) => /* @__PURE__ */ jsx7(
3565
3964
  RowSlot,
3566
3965
  {
3567
3966
  row,
@@ -3580,10 +3979,10 @@ function DataTable({
3580
3979
  }
3581
3980
 
3582
3981
  // src/components/ui/table/components/Table/Table.tsx
3583
- import { useCallback as useCallback5, useMemo as useMemo5, useState as useState5 } from "react";
3982
+ import { useCallback as useCallback6, useMemo as useMemo5, useState as useState5 } from "react";
3584
3983
 
3585
3984
  // src/components/ui/table/components/Table/buildColumnDef.tsx
3586
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
3985
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
3587
3986
  function SortableHeader({
3588
3987
  label,
3589
3988
  field,
@@ -3592,15 +3991,18 @@ function SortableHeader({
3592
3991
  }) {
3593
3992
  const isActive = sort?.field === field;
3594
3993
  const Icon = isActive ? sort.direction === "asc" ? ArrowUp : ArrowDown : ArrowUpDown;
3595
- return /* @__PURE__ */ jsxs6(
3994
+ return /* @__PURE__ */ jsxs7(
3596
3995
  "button",
3597
3996
  {
3598
3997
  type: "button",
3599
- className: cn("SortableHeaderJSX", isActive ? "is-active" : "is-inactive"),
3998
+ className: cn(
3999
+ "SortableHeaderJSX",
4000
+ isActive ? "is-active" : "is-inactive"
4001
+ ),
3600
4002
  onClick: () => onSort(field),
3601
4003
  children: [
3602
- /* @__PURE__ */ jsx7("span", { children: label }),
3603
- /* @__PURE__ */ jsx7(Icon, { className: "sortable-header-icon" })
4004
+ /* @__PURE__ */ jsx8("span", { children: label }),
4005
+ /* @__PURE__ */ jsx8(Icon, { className: "sortable-header-icon" })
3604
4006
  ]
3605
4007
  }
3606
4008
  );
@@ -3622,6 +4024,8 @@ function buildColumnDef(props, sort, onSort) {
3622
4024
  editable,
3623
4025
  editType,
3624
4026
  editInputProps,
4027
+ kind,
4028
+ cellProps,
3625
4029
  className,
3626
4030
  headerClassName,
3627
4031
  render
@@ -3633,18 +4037,20 @@ function buildColumnDef(props, sort, onSort) {
3633
4037
  ...minWidth != null ? { minSize: minWidth } : {},
3634
4038
  ...maxWidth != null ? { maxSize: maxWidth } : {},
3635
4039
  ...resizable === false ? { enableResizing: false } : {},
3636
- header: sortable ? () => /* @__PURE__ */ jsx7(SortableHeader, { label: children, field, sort, onSort }) : (
4040
+ header: sortable ? () => /* @__PURE__ */ jsx8(
4041
+ SortableHeader,
4042
+ {
4043
+ label: children,
4044
+ field,
4045
+ sort,
4046
+ onSort
4047
+ }
4048
+ ) : (
3637
4049
  // eslint-disable-next-line @typescript-eslint/promise-function-async
3638
4050
  () => children
3639
4051
  ),
3640
- ...render ? {
3641
- // eslint-disable-next-line @typescript-eslint/promise-function-async
3642
- cell: ({ row, getValue }) => render(
3643
- getValue(),
3644
- row,
3645
- row.index
3646
- )
3647
- } : {},
4052
+ // eslint-disable-next-line @typescript-eslint/promise-function-async
4053
+ cell: (info) => /* @__PURE__ */ jsx8(ResolvedTableCell, { info }),
3648
4054
  meta: {
3649
4055
  align,
3650
4056
  rowSpan,
@@ -3652,12 +4058,53 @@ function buildColumnDef(props, sort, onSort) {
3652
4058
  editable,
3653
4059
  editType,
3654
4060
  editInputProps,
4061
+ kind,
4062
+ cellProps,
4063
+ cellRender: render,
3655
4064
  frozen,
3656
4065
  className,
3657
4066
  headerClassName
3658
4067
  }
3659
4068
  };
3660
4069
  }
4070
+ function resolveGroupId(props, index) {
4071
+ if (props.id) return props.id;
4072
+ if (typeof props.header === "string" || typeof props.header === "number") {
4073
+ return `group:${props.header}:${index}`;
4074
+ }
4075
+ return `group:${index}`;
4076
+ }
4077
+ function buildColumnDefsFromTree(nodes, sort, onSort) {
4078
+ return nodes.map((node, index) => {
4079
+ if (node.type === "leaf") {
4080
+ return buildColumnDef(node.props, sort, onSort);
4081
+ }
4082
+ const childDefs = buildColumnDefsFromTree(node.columns, sort, onSort);
4083
+ const { header, align, headerClassName } = node.props;
4084
+ return {
4085
+ id: resolveGroupId(node.props, index),
4086
+ // eslint-disable-next-line @typescript-eslint/promise-function-async
4087
+ header: () => header,
4088
+ columns: childDefs,
4089
+ enableResizing: false,
4090
+ meta: {
4091
+ align,
4092
+ headerClassName
4093
+ }
4094
+ };
4095
+ });
4096
+ }
4097
+ function countLeafColumns(nodes) {
4098
+ let count = 0;
4099
+ for (const node of nodes) {
4100
+ if (node.type === "leaf") {
4101
+ count += 1;
4102
+ } else {
4103
+ count += countLeafColumns(node.columns);
4104
+ }
4105
+ }
4106
+ return count;
4107
+ }
3661
4108
 
3662
4109
  // src/components/ui/table/components/Table/parseTableChildren.ts
3663
4110
  import { Children, isValidElement as isValidElement2 } from "react";
@@ -3667,6 +4114,7 @@ import { isValidElement } from "react";
3667
4114
  var TABLE_HEADER_DISPLAY_NAME = "Table.Header";
3668
4115
  var TABLE_BODY_DISPLAY_NAME = "Table.Body";
3669
4116
  var TABLE_COLUMN_DISPLAY_NAME = "Table.Column";
4117
+ var TABLE_COLUMN_GROUP_DISPLAY_NAME = "Table.ColumnGroup";
3670
4118
  var TABLE_PAGINATION_DISPLAY_NAME = "Table.Pagination";
3671
4119
  function getComponentDisplayName(type) {
3672
4120
  if (typeof type === "function" || typeof type === "object" && type !== null) {
@@ -3683,6 +4131,9 @@ function isTableBodyElement(child) {
3683
4131
  function isTableColumnElement(child) {
3684
4132
  return isValidElement(child) && getComponentDisplayName(child.type) === TABLE_COLUMN_DISPLAY_NAME;
3685
4133
  }
4134
+ function isTableColumnGroupElement(child) {
4135
+ return isValidElement(child) && getComponentDisplayName(child.type) === TABLE_COLUMN_GROUP_DISPLAY_NAME;
4136
+ }
3686
4137
  function isTablePaginationElement(child) {
3687
4138
  return isValidElement(child) && getComponentDisplayName(child.type) === TABLE_PAGINATION_DISPLAY_NAME;
3688
4139
  }
@@ -3709,26 +4160,38 @@ function parseTableChildren(children) {
3709
4160
  }
3710
4161
  return slots;
3711
4162
  }
3712
- function flattenColumnElements(children) {
4163
+ function walkColumnTreeNodes(children) {
3713
4164
  const result = [];
3714
4165
  for (const child of Children.toArray(children)) {
3715
4166
  if (isTableColumnElement(child)) {
3716
- result.push(child);
4167
+ result.push({
4168
+ type: "leaf",
4169
+ props: child.props
4170
+ });
4171
+ continue;
4172
+ }
4173
+ if (isTableColumnGroupElement(child)) {
4174
+ const groupProps = child.props;
4175
+ result.push({
4176
+ type: "group",
4177
+ props: groupProps,
4178
+ columns: walkColumnTreeNodes(groupProps.children)
4179
+ });
3717
4180
  continue;
3718
4181
  }
3719
4182
  if (isValidElement2(child)) {
3720
4183
  const nested = child.props.children;
3721
4184
  if (nested != null) {
3722
- result.push(...flattenColumnElements(nested));
4185
+ result.push(...walkColumnTreeNodes(nested));
3723
4186
  }
3724
4187
  }
3725
4188
  }
3726
4189
  return result;
3727
4190
  }
3728
- function extractColumnElements(header) {
4191
+ function extractColumnTree(header) {
3729
4192
  if (!header) return [];
3730
4193
  const { children } = header.props;
3731
- return flattenColumnElements(children);
4194
+ return walkColumnTreeNodes(children);
3732
4195
  }
3733
4196
 
3734
4197
  // src/components/ui/table/components/Table/TableBody.tsx
@@ -3744,6 +4207,13 @@ function TableColumn(props) {
3744
4207
  }
3745
4208
  TableColumn.displayName = TABLE_COLUMN_DISPLAY_NAME;
3746
4209
 
4210
+ // src/components/ui/table/components/Table/TableColumnGroup.tsx
4211
+ function TableColumnGroup(props) {
4212
+ void props;
4213
+ return null;
4214
+ }
4215
+ TableColumnGroup.displayName = TABLE_COLUMN_GROUP_DISPLAY_NAME;
4216
+
3747
4217
  // src/components/ui/table/components/Table/tableDataPipeline.ts
3748
4218
  function sortTableData(data, sort) {
3749
4219
  if (!sort) return data;
@@ -3781,7 +4251,7 @@ function TableHeader(props) {
3781
4251
  TableHeader.displayName = TABLE_HEADER_DISPLAY_NAME;
3782
4252
 
3783
4253
  // src/components/ui/table/components/Table/TablePagination.tsx
3784
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
4254
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
3785
4255
  function TablePagination({
3786
4256
  page,
3787
4257
  pageSize = 10,
@@ -3793,8 +4263,8 @@ function TablePagination({
3793
4263
  const safePage = Math.min(Math.max(1, page), totalPages);
3794
4264
  const canGoPrev = safePage > 1;
3795
4265
  const canGoNext = safePage < totalPages;
3796
- return /* @__PURE__ */ jsxs7("div", { className: cn("TablePaginationJSX", className), children: [
3797
- /* @__PURE__ */ jsx8(
4266
+ return /* @__PURE__ */ jsxs8("div", { className: cn("TablePaginationJSX", className), children: [
4267
+ /* @__PURE__ */ jsx9(
3798
4268
  "button",
3799
4269
  {
3800
4270
  type: "button",
@@ -3802,15 +4272,15 @@ function TablePagination({
3802
4272
  disabled: !canGoPrev,
3803
4273
  onClick: () => onChange(safePage - 1),
3804
4274
  "aria-label": "Previous page",
3805
- children: /* @__PURE__ */ jsx8(ChevronLeft, { className: "pagination-button-icon" })
4275
+ children: /* @__PURE__ */ jsx9(ChevronLeft, { className: "pagination-button-icon" })
3806
4276
  }
3807
4277
  ),
3808
- /* @__PURE__ */ jsxs7("span", { className: "pagination-label", children: [
4278
+ /* @__PURE__ */ jsxs8("span", { className: "pagination-label", children: [
3809
4279
  safePage,
3810
4280
  " / ",
3811
4281
  totalPages
3812
4282
  ] }),
3813
- /* @__PURE__ */ jsx8(
4283
+ /* @__PURE__ */ jsx9(
3814
4284
  "button",
3815
4285
  {
3816
4286
  type: "button",
@@ -3818,7 +4288,7 @@ function TablePagination({
3818
4288
  disabled: !canGoNext,
3819
4289
  onClick: () => onChange(safePage + 1),
3820
4290
  "aria-label": "Next page",
3821
- children: /* @__PURE__ */ jsx8(ChevronRight, { className: "pagination-button-icon" })
4291
+ children: /* @__PURE__ */ jsx9(ChevronRight, { className: "pagination-button-icon" })
3822
4292
  }
3823
4293
  )
3824
4294
  ] });
@@ -3826,7 +4296,7 @@ function TablePagination({
3826
4296
  TablePagination.displayName = TABLE_PAGINATION_DISPLAY_NAME;
3827
4297
 
3828
4298
  // src/components/ui/table/components/Table/Table.tsx
3829
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
4299
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
3830
4300
  function TableRoot({
3831
4301
  data,
3832
4302
  children,
@@ -3840,7 +4310,7 @@ function TableRoot({
3840
4310
  [children]
3841
4311
  );
3842
4312
  const [sort, setSort] = useState5(null);
3843
- const handleSort = useCallback5((field) => {
4313
+ const handleSort = useCallback6((field) => {
3844
4314
  setSort((previous) => {
3845
4315
  if (previous?.field !== field) {
3846
4316
  return { field, direction: "asc" };
@@ -3851,11 +4321,11 @@ function TableRoot({
3851
4321
  return null;
3852
4322
  });
3853
4323
  }, []);
3854
- const columns = useMemo5(() => {
3855
- return extractColumnElements(header).map(
3856
- (columnElement) => buildColumnDef(columnElement.props, sort, handleSort)
3857
- );
3858
- }, [header, sort, handleSort]);
4324
+ const columnTree = useMemo5(() => extractColumnTree(header), [header]);
4325
+ const columns = useMemo5(
4326
+ () => buildColumnDefsFromTree(columnTree, sort, handleSort),
4327
+ [columnTree, sort, handleSort]
4328
+ );
3859
4329
  const paginationProps = paginationElement?.props;
3860
4330
  const pageSize = paginationProps?.pageSize ?? 10;
3861
4331
  const page = paginationProps?.page ?? 1;
@@ -3865,11 +4335,11 @@ function TableRoot({
3865
4335
  if (!paginationProps) return sortedData;
3866
4336
  return paginateTableData(sortedData, page, pageSize);
3867
4337
  }, [data, sort, paginationProps, page, pageSize]);
3868
- if (columns.length === 0) {
4338
+ if (countLeafColumns(columnTree) === 0) {
3869
4339
  console.warn("[Table] Declare at least one Table.Column inside Table.Header.");
3870
4340
  }
3871
- return /* @__PURE__ */ jsxs8("div", { className: "TableJSX", children: [
3872
- /* @__PURE__ */ jsx9(
4341
+ return /* @__PURE__ */ jsxs9("div", { className: "TableJSX", children: [
4342
+ /* @__PURE__ */ jsx10(
3873
4343
  DataTable,
3874
4344
  {
3875
4345
  ...dataTableProps,
@@ -3880,7 +4350,7 @@ function TableRoot({
3880
4350
  className: cn(className, paginationProps && "DataTableJSX--with-pagination")
3881
4351
  }
3882
4352
  ),
3883
- paginationProps && /* @__PURE__ */ jsx9(
4353
+ paginationProps && /* @__PURE__ */ jsx10(
3884
4354
  TablePagination,
3885
4355
  {
3886
4356
  page,
@@ -3898,13 +4368,19 @@ function createTable() {
3898
4368
  return null;
3899
4369
  }
3900
4370
  Column.displayName = TABLE_COLUMN_DISPLAY_NAME;
4371
+ function ColumnGroup(props) {
4372
+ void props;
4373
+ return null;
4374
+ }
4375
+ ColumnGroup.displayName = TABLE_COLUMN_GROUP_DISPLAY_NAME;
3901
4376
  return Object.assign(
3902
4377
  function BoundTable(props) {
3903
- return /* @__PURE__ */ jsx9(TableRoot, { ...props });
4378
+ return /* @__PURE__ */ jsx10(TableRoot, { ...props });
3904
4379
  },
3905
4380
  {
3906
4381
  Header: TableHeader,
3907
4382
  Column,
4383
+ ColumnGroup,
3908
4384
  Body: TableBody,
3909
4385
  Pagination: TablePagination
3910
4386
  }
@@ -3913,10 +4389,12 @@ function createTable() {
3913
4389
  var Table = Object.assign(TableRoot, {
3914
4390
  Header: TableHeader,
3915
4391
  Column: TableColumn,
4392
+ ColumnGroup: TableColumnGroup,
3916
4393
  Body: TableBody,
3917
4394
  Pagination: TablePagination
3918
4395
  });
3919
4396
  export {
4397
+ BUILTIN_CELL_RENDERERS,
3920
4398
  CELL_SELECTION_EDGES_CLASS,
3921
4399
  DEFAULT_DATA_TABLE_LABELS,
3922
4400
  DEFAULT_TREE_CHILDREN_FIELD,
@@ -3925,6 +4403,7 @@ export {
3925
4403
  DEFAULT_TREE_QTY_FIELD,
3926
4404
  DataTable,
3927
4405
  INLINE_SEARCH_MAX_RESULTS,
4406
+ ResolvedTableCell,
3928
4407
  Table,
3929
4408
  applyCellEdit,
3930
4409
  applyFillData,
@@ -3944,10 +4423,14 @@ export {
3944
4423
  collectFillChanges,
3945
4424
  collectRowSpanColumns,
3946
4425
  collectSearchMatchesInRange,
4426
+ commitCellValue,
4427
+ createCellRendererRegistry,
3947
4428
  createSearchRegex,
3948
4429
  createTable,
3949
4430
  escapeSearchRegex,
3950
4431
  flattenSubtreeRows,
4432
+ formatCellValue,
4433
+ formatDefaultCellValue,
3951
4434
  formatSearchResultLabel,
3952
4435
  getCellEditDraftValue,
3953
4436
  getCellSelectionEdgeStyle,
@@ -3969,8 +4452,10 @@ export {
3969
4452
  parseClipboardTSV,
3970
4453
  parseClipboardTSVWithDepths,
3971
4454
  previousSearchIndex,
4455
+ resolveCellRenderer,
3972
4456
  resolveColumnFreezeSide,
3973
4457
  resolveDataTableLabels,
4458
+ resolveHeaderFreezeOffset,
3974
4459
  resolvePasteColumnIds,
3975
4460
  resolveRowSelection,
3976
4461
  resolveRowSpanAt,