twico-ui 1.34.0 → 1.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  All notable changes to Twico UI are documented here (newest first). This file is generated automatically on each release by [semantic-release](https://semantic-release.gitbook.io/) from [Conventional Commits](https://www.conventionalcommits.org/) — do not edit it by hand. The same notes appear on each [GitHub Release](https://github.com/EncryptionL/twico-ui/releases).
4
4
 
5
+ # [1.36.0](https://github.com/EncryptionL/twico-ui/compare/v1.35.0...v1.36.0) (2026-09-09)
6
+
7
+
8
+ ### Features
9
+
10
+ * **datatable:** custom column header via renderHeader ([#367](https://github.com/EncryptionL/twico-ui/issues/367)) ([647ab35](https://github.com/EncryptionL/twico-ui/commit/647ab35d171170b215d2945c5aa624e02230f144))
11
+
12
+ # [1.35.0](https://github.com/EncryptionL/twico-ui/compare/v1.34.0...v1.35.0) (2026-08-28)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * **datatable:** harden [#359](https://github.com/EncryptionL/twico-ui/issues/359) row-tree (server no-refire, child edit, numbering, cycle) ([7c0c70b](https://github.com/EncryptionL/twico-ui/commit/7c0c70b11b1689a8f60912df3a9cbcc3a2c36a8c)), closes [#350](https://github.com/EncryptionL/twico-ui/issues/350) [#350](https://github.com/EncryptionL/twico-ui/issues/350)
18
+
19
+
20
+ ### Features
21
+
22
+ * **datatable:** server-mode lazy row-tree — getRowCanExpand/getSubRows/getRowDepth ([15c7c76](https://github.com/EncryptionL/twico-ui/commit/15c7c767212940c96d5f031466bd251ee4cc83cb)), closes [#350](https://github.com/EncryptionL/twico-ui/issues/350) [#350](https://github.com/EncryptionL/twico-ui/issues/350) [#350](https://github.com/EncryptionL/twico-ui/issues/350) [#359](https://github.com/EncryptionL/twico-ui/issues/359)
23
+
5
24
  # [1.34.0](https://github.com/EncryptionL/twico-ui/compare/v1.33.1...v1.34.0) (2026-08-14)
6
25
 
7
26
 
package/dist/index.cjs CHANGED
@@ -8890,11 +8890,12 @@ function combineCfg(combine) {
8890
8890
  if (!fields.length) return null;
8891
8891
  return { fields, separator: cfg.separator != null ? cfg.separator : " \xB7 ", labels: !!cfg.labels, layout: cfg.layout === "stack" ? "stack" : "inline" };
8892
8892
  }
8893
+ var colLabel = (c) => typeof c.headerName === "string" ? c.headerName : String(c.field ?? "");
8893
8894
  var combineSrcCols = (cfg, byField) => cfg.fields.map((f) => byField && byField[f] || { field: f, headerName: String(f) });
8894
8895
  var combineValueGetter = (srcCols, cfg) => (row) => srcCols.map((sc) => {
8895
8896
  const v = getColVal(sc, row);
8896
8897
  const s = v == null ? "" : String(v);
8897
- return cfg.labels && s ? `${sc.headerName ?? sc.field}: ${s}` : s;
8898
+ return cfg.labels && s ? `${colLabel(sc)}: ${s}` : s;
8898
8899
  }).filter(Boolean).join(cfg.separator);
8899
8900
  function renderCombined(srcCols, row, cfg) {
8900
8901
  const nodes = [];
@@ -8903,7 +8904,7 @@ function renderCombined(srcCols, row, cfg) {
8903
8904
  const v = getColVal(sc, row);
8904
8905
  if (v == null || v === "") return;
8905
8906
  const disp = sc.valueFormatter ? sc.valueFormatter(v, row) : v;
8906
- const label = cfg.labels ? React51__namespace.default.createElement("span", { className: "twc-dt__combine-label" }, (sc.headerName ?? sc.field) + ": ") : null;
8907
+ const label = cfg.labels ? React51__namespace.default.createElement("span", { className: "twc-dt__combine-label" }, colLabel(sc) + ": ") : null;
8907
8908
  if (count > 0 && cfg.layout !== "stack") nodes.push(React51__namespace.default.createElement("span", { key: "sep" + idx, className: "twc-dt__combine-sep", "aria-hidden": "true" }, cfg.separator));
8908
8909
  nodes.push(React51__namespace.default.createElement("span", { key: idx, className: "twc-dt__combine-item" }, label, disp));
8909
8910
  count++;
@@ -9153,7 +9154,7 @@ function EditCell({ col, value, options, onChange, onCommit, onCommitValue, onCa
9153
9154
  className: "twc-dt__editor",
9154
9155
  type: col.type === "number" ? "number" : "text",
9155
9156
  value: value ?? "",
9156
- "aria-label": `Edit ${col.headerName}`,
9157
+ "aria-label": `Edit ${colLabel(col)}`,
9157
9158
  onChange: (e) => onChange(e.target.value),
9158
9159
  onKeyDown,
9159
9160
  onBlur: onCommit
@@ -9347,6 +9348,13 @@ function Datatable({
9347
9348
  renderRowDetail,
9348
9349
  expandedRowIds,
9349
9350
  onExpandedRowsChange,
9351
+ // #359: server-mode lazy row-tree — `getRowCanExpand(row)` draws the same leading chevron on parent DATA
9352
+ // rows (independent of renderRowDetail); expanding reveals CHILD data rows in the SAME columns rather than a
9353
+ // panel. In server mode the host returns children inline (the expanded set is folded into onServerChange);
9354
+ // in client mode `getSubRows(row)` supplies them. `getRowDepth(row)` indents nested rows so they read as a tree.
9355
+ getRowCanExpand,
9356
+ getRowDepth,
9357
+ getSubRows,
9350
9358
  className = "",
9351
9359
  ...rest
9352
9360
  }) {
@@ -9559,6 +9567,7 @@ function Datatable({
9559
9567
  () => new Set(expandControlled ? expandedRowIds : internalExpanded),
9560
9568
  [expandControlled, expandedRowIds, internalExpanded]
9561
9569
  );
9570
+ const expandedKey = React51__namespace.default.useMemo(() => JSON.stringify([...expandedSet].sort()), [expandedSet]);
9562
9571
  const [pinnedRows, setPinnedRows] = React51__namespace.default.useState({ top: [], bottom: [] });
9563
9572
  const [headH, setHeadH] = React51__namespace.default.useState(41);
9564
9573
  const theadRef = React51__namespace.default.useRef(null);
@@ -9796,7 +9805,7 @@ function Datatable({
9796
9805
  }, [rowGroupingKey]);
9797
9806
  const AUTO_CHROME = 74;
9798
9807
  const autoWidth = (c) => {
9799
- const label = typeof c.headerName === "string" ? c.headerName : String(c.field ?? "");
9808
+ const label = colLabel(c);
9800
9809
  return AUTO_CHROME + Math.ceil(label.length * 8);
9801
9810
  };
9802
9811
  const clampWidth = (w, c) => {
@@ -9920,6 +9929,7 @@ function Datatable({
9920
9929
  };
9921
9930
  }, [exportOpen]);
9922
9931
  const colByField = React51__namespace.default.useMemo(() => Object.fromEntries(cols.map((c) => [c.field, c])), [cols]);
9932
+ const fieldLabel = (f) => colLabel(colByField[f] || { field: f });
9923
9933
  const combineSources = React51__namespace.default.useMemo(() => {
9924
9934
  const s = /* @__PURE__ */ new Set();
9925
9935
  for (const cfg of Object.values(userCombine)) (cfg && cfg.fields ? cfg.fields : []).slice(1).forEach((f) => s.add(f));
@@ -9961,7 +9971,10 @@ function Datatable({
9961
9971
  const NUM_W = 56;
9962
9972
  const CHK_W = checkboxSelection ? rowReorder ? 68 : 44 : 0;
9963
9973
  const hasRowDetail = typeof renderRowDetail === "function";
9964
- const EXP_W = hasRowDetail ? 44 : 0;
9974
+ const hasRowTree = typeof getRowCanExpand === "function";
9975
+ const hasExpandCol = hasRowDetail || hasRowTree;
9976
+ const treeExpandedKey = hasRowTree ? expandedKey : "";
9977
+ const EXP_W = hasExpandCol ? 44 : 0;
9965
9978
  const numLeft = EXP_W + CHK_W;
9966
9979
  const leadW = numLeft + (showRowNum ? NUM_W : 0);
9967
9980
  const visLeft = React51__namespace.default.useMemo(() => pins.left.filter((f) => colByField[f] && !effectiveHidden.has(f)), [pins.left, colByField, effectiveHidden]);
@@ -10034,6 +10047,40 @@ function Datatable({
10034
10047
  React51__namespace.default.useEffect(() => {
10035
10048
  if (pageVal > totalPages - 1) commitPage(0);
10036
10049
  }, [totalPages]);
10050
+ const treeRows = React51__namespace.default.useMemo(() => {
10051
+ if (serverMode || typeof getSubRows !== "function") return null;
10052
+ const out = [];
10053
+ const seen2 = /* @__PURE__ */ new Set();
10054
+ const walk = (r2, d) => {
10055
+ const key = keyOf(r2);
10056
+ if (seen2.has(key)) return;
10057
+ seen2.add(key);
10058
+ out.push({ row: r2, depth: d });
10059
+ if (expandedSet.has(key)) for (const c of getSubRows(r2) || []) walk(c, d + 1);
10060
+ };
10061
+ for (const r2 of paged) walk(r2, 0);
10062
+ return out;
10063
+ }, [serverMode, getSubRows, paged, expandedSet, keyOf]);
10064
+ const depthByKey = React51__namespace.default.useMemo(() => {
10065
+ const m = /* @__PURE__ */ new Map();
10066
+ if (treeRows) for (const t of treeRows) m.set(keyOf(t.row), t.depth);
10067
+ return m;
10068
+ }, [treeRows, keyOf]);
10069
+ const treeSeqByKey = React51__namespace.default.useMemo(() => {
10070
+ if (!treeRows) return null;
10071
+ const m = /* @__PURE__ */ new Map();
10072
+ const seen2 = /* @__PURE__ */ new Set();
10073
+ let n = 0;
10074
+ const walk = (r2) => {
10075
+ const key = keyOf(r2);
10076
+ if (seen2.has(key)) return;
10077
+ seen2.add(key);
10078
+ m.set(key, n++);
10079
+ if (expandedSet.has(key)) for (const c of getSubRows(r2) || []) walk(c);
10080
+ };
10081
+ for (const r2 of processed) walk(r2);
10082
+ return m;
10083
+ }, [treeRows, processed, expandedSet, getSubRows, keyOf]);
10037
10084
  const activeGroupBy = React51__namespace.default.useMemo(() => groupBy.filter((f) => colByField[f]), [groupBy, colByField]);
10038
10085
  function subtotalText(rowsIn) {
10039
10086
  const parts = [];
@@ -10043,7 +10090,7 @@ function Datatable({
10043
10090
  const v = computeAgg({ ...c, aggregation: agg }, rowsIn);
10044
10091
  if (v == null) continue;
10045
10092
  const disp = c.aggregationFormatter ? c.aggregationFormatter(v) : c.valueFormatter ? c.valueFormatter(v, null) : typeof v === "number" ? v.toLocaleString() : v;
10046
- parts.push(`${c.headerName} ${disp}`);
10093
+ parts.push(`${colLabel(c)} ${disp}`);
10047
10094
  }
10048
10095
  return parts;
10049
10096
  }
@@ -10084,7 +10131,7 @@ function Datatable({
10084
10131
  };
10085
10132
  return build(paged, 0, "");
10086
10133
  }, [activeGroupBy, collapsed, paged, ordered, aggOn]);
10087
- const leafRows = displayItems ? displayItems.filter((i) => i.kind === "leaf").map((i) => i.row) : paged;
10134
+ const leafRows = displayItems ? displayItems.filter((i) => i.kind === "leaf").map((i) => i.row) : treeRows ? treeRows.map((t) => t.row) : paged;
10088
10135
  function toggleGroup(key) {
10089
10136
  setCollapsed((s) => {
10090
10137
  const n = new Set(s);
@@ -10336,12 +10383,14 @@ function Datatable({
10336
10383
  // #303: "and" (default) | "or" — the server groups its WHERE accordingly
10337
10384
  quickFilter: quick.trim(),
10338
10385
  visibleColumns,
10339
- hiddenColumns
10386
+ hiddenColumns,
10340
10387
  // #191: server can project only the visible columns
10388
+ ...hasRowTree ? { expanded: [...expandedSet] } : null
10389
+ // #359: only a row-tree folds expanded parents in
10341
10390
  });
10342
10391
  }, 250);
10343
10392
  return () => clearTimeout(t);
10344
- }, [serverMode, pageVal, sizeVal, sort, filters, filterLogic, quick, visibleColumns, hiddenColumns]);
10393
+ }, [serverMode, pageVal, sizeVal, sort, filters, filterLogic, quick, visibleColumns, hiddenColumns, treeExpandedKey]);
10345
10394
  const onColVisRef = React51__namespace.default.useRef(onColumnVisibilityChange);
10346
10395
  onColVisRef.current = onColumnVisibilityChange;
10347
10396
  const lastVisibleKey = React51__namespace.default.useRef(null);
@@ -10394,7 +10443,7 @@ function Datatable({
10394
10443
  next.splice(dir > 0 ? b + 1 : b, 0, field);
10395
10444
  return next;
10396
10445
  });
10397
- const label = colByField[field]?.headerName || field;
10446
+ const label = fieldLabel(field);
10398
10447
  setReorderMsg(`Moved ${label} ${dir < 0 ? "left" : "right"}.`);
10399
10448
  }
10400
10449
  function optionsForField(field) {
@@ -10501,7 +10550,7 @@ function Datatable({
10501
10550
  const rowXml = (cells, r2) => `<row r="${r2}">${cells.map((v, ci) => cell(`${colLetter(ci)}${r2}`, v)).join("")}</row>`;
10502
10551
  const lastCell = `${expCols.length ? colLetter(expCols.length - 1) : "A"}${source.length + 1}`;
10503
10552
  const sheet = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
10504
- <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><dimension ref="A1:${lastCell}"/><sheetViews><sheetView tabSelected="1" workbookViewId="0"/></sheetViews><sheetData>` + rowXml(expCols.map((c) => c.headerName), 1) + source.map((row, ri) => rowXml(expCols.map((c) => cellValue(c, row)), ri + 2)).join("") + "</sheetData></worksheet>";
10553
+ <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><dimension ref="A1:${lastCell}"/><sheetViews><sheetView tabSelected="1" workbookViewId="0"/></sheetViews><sheetData>` + rowXml(expCols.map((c) => colLabel(c)), 1) + source.map((row, ri) => rowXml(expCols.map((c) => cellValue(c, row)), ri + 2)).join("") + "</sheetData></worksheet>";
10505
10554
  download(xlsxPackage(sheet), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "xlsx");
10506
10555
  return;
10507
10556
  }
@@ -10509,7 +10558,7 @@ function Datatable({
10509
10558
  const s = defang(v, v == null ? "" : String(v));
10510
10559
  return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
10511
10560
  };
10512
- const header = expCols.map((c) => escape(c.headerName)).join(",");
10561
+ const header = expCols.map((c) => escape(colLabel(c))).join(",");
10513
10562
  const lines = source.map((row) => expCols.map((c) => escape(cellValue(c, row))).join(","));
10514
10563
  const text = "\uFEFF" + [header, ...lines].join("\r\n");
10515
10564
  download(text, "text/csv;charset=utf-8;", "csv");
@@ -10715,12 +10764,12 @@ function Datatable({
10715
10764
  next = next === "" ? null : Number(next);
10716
10765
  if (Number.isNaN(next)) next = null;
10717
10766
  }
10718
- const row = paged.find((r2, i) => keyOf(r2, i) === editing.key);
10767
+ const row = leafRows.find((r2, i) => keyOf(r2, i) === editing.key);
10719
10768
  setEditing(null);
10720
10769
  if (!row || row[editing.field] === next) return;
10721
10770
  const updated = { ...row, [editing.field]: next };
10722
10771
  onRowUpdate?.(updated, row, editing.field);
10723
- if (onRowsChange) {
10772
+ if (onRowsChange && rows.some((r2, i) => keyOf(r2, i) === editing.key)) {
10724
10773
  onRowsChange(rows.map((r2, i) => keyOf(r2, i) === editing.key ? updated : r2));
10725
10774
  }
10726
10775
  }
@@ -10849,20 +10898,25 @@ function Datatable({
10849
10898
  };
10850
10899
  const writeCellPatches = (patchByKey) => {
10851
10900
  if (!patchByKey.size) return 0;
10852
- const changed = [];
10853
- const nextAll = rows.map((r2, i) => {
10854
- const k = keyOf(r2, i);
10855
- const patch = patchByKey.get(k);
10856
- if (!patch) return r2;
10901
+ let count = 0;
10902
+ leafRows.forEach((r2, i) => {
10903
+ const patch = patchByKey.get(keyOf(r2, i));
10904
+ if (!patch) return;
10857
10905
  const updated = { ...r2, ...patch };
10858
- changed.push([updated, r2, patch]);
10859
- return updated;
10906
+ for (const f of Object.keys(patch)) onRowUpdate?.(updated, r2, f);
10907
+ count++;
10860
10908
  });
10861
- changed.forEach(([updated, orig, patch]) => {
10862
- for (const f of Object.keys(patch)) onRowUpdate?.(updated, orig, f);
10863
- });
10864
- if (onRowsChange && changed.length) onRowsChange(nextAll);
10865
- return changed.length;
10909
+ if (onRowsChange) {
10910
+ let anyTop = false;
10911
+ const nextAll = rows.map((r2, i) => {
10912
+ const patch = patchByKey.get(keyOf(r2, i));
10913
+ if (!patch) return r2;
10914
+ anyTop = true;
10915
+ return { ...r2, ...patch };
10916
+ });
10917
+ if (anyTop) onRowsChange(nextAll);
10918
+ }
10919
+ return count;
10866
10920
  };
10867
10921
  const rectCells = () => {
10868
10922
  if (!cellRect) return null;
@@ -11041,7 +11095,7 @@ function Datatable({
11041
11095
  const widest = (labels) => labels.reduce((m, l) => Math.max(m, ctx.measureText(String(l)).width), 0);
11042
11096
  const logicW = Math.min(180, Math.max(84, Math.ceil(widest(["And", "Or"]) + chrome)));
11043
11097
  const colCap = Math.max(118, Math.min(210, el.clientWidth - logicW - 118 - 30 - 30 - 140 - 5 * 6 - 2 * 4));
11044
- const colW = Math.min(colCap, Math.max(118, Math.ceil(widest(filterableCols.map((c) => c.headerName ?? c.field)) + chrome)));
11098
+ const colW = Math.min(colCap, Math.max(118, Math.ceil(widest(filterableCols.map((c) => colLabel(c))) + chrome)));
11045
11099
  const opW = Math.min(170, Math.max(118, Math.ceil(widest(ALL_OP_LABELS) + chrome)));
11046
11100
  if (Number.isFinite(logicW)) el.style.setProperty("--twc-dt-flogic-fit", `${logicW}px`);
11047
11101
  if (Number.isFinite(colW)) el.style.setProperty("--twc-dt-fcol-fit", `${colW}px`);
@@ -11404,12 +11458,12 @@ function Datatable({
11404
11458
  const i = order.indexOf(f);
11405
11459
  return i === -1 ? 9999 : i;
11406
11460
  };
11407
- const shownColRows = cols.filter((c) => c.field !== "__pinactions__" && c.headerName.toLowerCase().includes(colQuery.trim().toLowerCase())).sort((a, b) => orderIdxOf(a.field) - orderIdxOf(b.field));
11461
+ const shownColRows = cols.filter((c) => c.field !== "__pinactions__" && colLabel(c).toLowerCase().includes(colQuery.trim().toLowerCase())).sort((a, b) => orderIdxOf(a.field) - orderIdxOf(b.field));
11408
11462
  const rowNumMatch = rowNumbers && "row number".includes(colQuery.trim().toLowerCase());
11409
11463
  const manageableCols = cols.filter((c) => c.field !== "__pinactions__");
11410
11464
  const visibleColCount = manageableCols.filter((c) => !effectiveHidden.has(c.field)).length;
11411
11465
  const rppOptions = Array.from(new Set([...pageSizeOptions || [], pageSize].filter((n) => n > 0))).sort((a, b) => a - b).map((n) => ({ value: String(n), label: String(n) }));
11412
- const totalCols = ordered.length + (checkboxSelection ? 1 : 0) + (showRowNum ? 1 : 0) + (hasRowDetail ? 1 : 0);
11466
+ const totalCols = ordered.length + (checkboxSelection ? 1 : 0) + (showRowNum ? 1 : 0) + (hasExpandCol ? 1 : 0);
11413
11467
  function renderGroupRow(item) {
11414
11468
  const subs = aggOn ? subtotalText(item.rows) : [];
11415
11469
  return /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "twc-dt__group-row", role: "row", children: /* @__PURE__ */ jsxRuntime.jsxs("td", { className: "twc-dt__group-cell", role: "gridcell", colSpan: totalCols, style: { maxWidth: "none" }, children: [
@@ -11424,7 +11478,7 @@ function Datatable({
11424
11478
  children: [
11425
11479
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__group-chev", "data-open": !item.collapsed || void 0, children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.chevDown }) }),
11426
11480
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__group-name", children: [
11427
- colByField[item.field]?.headerName || item.field,
11481
+ fieldLabel(item.field),
11428
11482
  ":"
11429
11483
  ] }),
11430
11484
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__group-val", children: String(item.value) }),
@@ -11464,8 +11518,10 @@ function Datatable({
11464
11518
  const k = keyOf(row, ri);
11465
11519
  const sel = selected.has(k);
11466
11520
  const detail = hasRowDetail && !pinSide ? renderRowDetail(row) : null;
11467
- const expandable = detail != null;
11521
+ const canTreeExpand = hasRowTree && !pinSide && !!getRowCanExpand(row);
11522
+ const expandable = detail != null || canTreeExpand;
11468
11523
  const open = expandable && expandedSet.has(k);
11524
+ const depth = getRowDepth ? getRowDepth(row) || 0 : depthByKey.get(k) || 0;
11469
11525
  const rowActive = selectionMode === "row" && activeRowVal === k;
11470
11526
  const stickyStyle = pinSide === "top" ? { position: "sticky", top: headH, zIndex: 5 } : pinSide === "bottom" ? { position: "sticky", bottom: 0, zIndex: 5 } : void 0;
11471
11527
  const h = rowHeights[k];
@@ -11479,7 +11535,7 @@ function Datatable({
11479
11535
  {
11480
11536
  className: "twc-dt__row",
11481
11537
  role: "row",
11482
- "aria-rowindex": (paginated && !serverMode ? pageVal * sizeVal : 0) + ri + 2,
11538
+ "aria-rowindex": treeSeqByKey ? treeSeqByKey.get(k) + 2 : (paginated && !serverMode ? pageVal * sizeVal : 0) + ri + 2,
11483
11539
  "aria-selected": (checkboxSelection ? sel : rowActive) || void 0,
11484
11540
  "data-op": row.__diffop || void 0,
11485
11541
  "data-selected": sel || void 0,
@@ -11513,7 +11569,7 @@ function Datatable({
11513
11569
  onDragEnd: reorderable ? () => setRowDrag({ from: null, over: null, after: false }) : void 0,
11514
11570
  onClick: (e) => handleRowClick(e, k, row),
11515
11571
  children: [
11516
- hasRowDetail ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: "twc-dt__td twc-dt__expand-cell", role: "gridcell", "data-pin": "left", "data-pin-edge": checkboxSelection || showRowNum || visLeft.length ? void 0 : "left", style: { insetInlineStart: 0, width: EXP_W }, children: expandable ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__expand-btn", "aria-expanded": open, "aria-controls": open ? `${gridId}-detail-${ri}` : void 0, "aria-label": open ? "Collapse row" : "Expand row", onClick: (e) => {
11572
+ hasExpandCol ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: "twc-dt__td twc-dt__expand-cell", role: "gridcell", "data-pin": "left", "data-pin-edge": checkboxSelection || showRowNum || visLeft.length ? void 0 : "left", style: { insetInlineStart: 0, width: EXP_W }, children: expandable ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__expand-btn", "aria-expanded": open, "aria-controls": open && detail != null ? `${gridId}-detail-${ri}` : void 0, "aria-label": open ? "Collapse row" : "Expand row", onClick: (e) => {
11517
11573
  e.stopPropagation();
11518
11574
  toggleRowDetail(k);
11519
11575
  }, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__expand-chev", "data-open": open || void 0, children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.chevDown }) }) }) : null }) : null,
@@ -11542,7 +11598,7 @@ function Datatable({
11542
11598
  ] }),
11543
11599
  rowResize && !pinSide ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__row-resizer", title: "Drag to resize row", onPointerDown: (e) => startRowResize(e, k, e.currentTarget.closest("tr")), onClick: (e) => e.stopPropagation() }) : null
11544
11600
  ] }) : null,
11545
- showRowNum ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: "twc-dt__td twc-dt__rownum", role: "gridcell", "aria-hidden": "true", "data-pin": "left", "data-pin-edge": visLeft.length ? void 0 : "left", style: { insetInlineStart: numLeft, width: NUM_W }, children: typeof ri === "number" ? (paginated || serverMode ? pageVal * sizeVal : 0) + ri + 1 : "" }) : null,
11601
+ showRowNum ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: "twc-dt__td twc-dt__rownum", role: "gridcell", "aria-hidden": "true", "data-pin": "left", "data-pin-edge": visLeft.length ? void 0 : "left", style: { insetInlineStart: numLeft, width: NUM_W }, children: treeSeqByKey ? treeSeqByKey.get(k) + 1 : typeof ri === "number" ? (paginated || serverMode ? pageVal * sizeVal : 0) + ri + 1 : "" }) : null,
11546
11602
  ordered.map((c, ci) => {
11547
11603
  const st = stickyOf(c.field);
11548
11604
  const val = getColVal(c, row);
@@ -11565,7 +11621,7 @@ function Datatable({
11565
11621
  role: "gridcell",
11566
11622
  "data-r": ri,
11567
11623
  "data-c": ci,
11568
- "aria-colindex": ci + 1 + (checkboxSelection ? 1 : 0) + (hasRowDetail ? 1 : 0),
11624
+ "aria-colindex": ci + 1 + (checkboxSelection ? 1 : 0) + (hasExpandCol ? 1 : 0),
11569
11625
  tabIndex: focus.r === ri && focus.c === ci ? 0 : -1,
11570
11626
  "aria-selected": cellSelected || void 0,
11571
11627
  "data-num": c.type === "number" || void 0,
@@ -11578,7 +11634,7 @@ function Datatable({
11578
11634
  "data-wrap": effectiveWrapped.has(c.field) || void 0,
11579
11635
  "data-pin": st.pin,
11580
11636
  "data-pin-edge": st.edge,
11581
- style: { width: widthOf(c), ...cellSty, ...st.style, ...st.pin ? { position: "sticky", zIndex: 2 } : null },
11637
+ style: { width: widthOf(c), ...cellSty, ...st.style, ...st.pin ? { position: "sticky", zIndex: 2 } : null, ...ci === 0 && depth ? { paddingInlineStart: `calc(12px + ${depth * 20}px)` } : null },
11582
11638
  "data-ovtext": cellTitle,
11583
11639
  onClick: selectionMode === "cell" ? (e) => handleCellClick(e, k, row, c) : void 0,
11584
11640
  onFocus: () => setFocus((f) => f.r === ri && f.c === ci ? f : { r: ri, c: ci }),
@@ -11630,7 +11686,7 @@ function Datatable({
11630
11686
  ]
11631
11687
  }
11632
11688
  ),
11633
- open ? /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "twc-dt__detail-row", role: "row", children: /* @__PURE__ */ jsxRuntime.jsx("td", { id: `${gridId}-detail-${ri}`, className: "twc-dt__detail-cell", role: "gridcell", colSpan: totalCols, style: { maxWidth: "none" }, children: detail }) }) : null
11689
+ open && detail != null ? /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "twc-dt__detail-row", role: "row", children: /* @__PURE__ */ jsxRuntime.jsx("td", { id: `${gridId}-detail-${ri}`, className: "twc-dt__detail-cell", role: "gridcell", colSpan: totalCols, style: { maxWidth: "none" }, children: detail }) }) : null
11634
11690
  ] }, (pinSide ? "p-" : "") + k);
11635
11691
  }
11636
11692
  function renderPivot() {
@@ -11644,8 +11700,8 @@ function Datatable({
11644
11700
  const f = v.valueFormatter || col?.valueFormatter;
11645
11701
  return f ? f(val, null) : typeof val === "number" ? val.toLocaleString() : val;
11646
11702
  };
11647
- const vlabel = (v) => v.label || (colByField[v.field]?.headerName || v.field);
11648
- const rowFieldLabel = rFields.map((f) => colByField[f]?.headerName || f).join(" / ");
11703
+ const vlabel = (v) => v.label || fieldLabel(v.field);
11704
+ const rowFieldLabel = rFields.map((f) => fieldLabel(f)).join(" / ");
11649
11705
  const leafPaths = [];
11650
11706
  const seen2 = /* @__PURE__ */ new Set();
11651
11707
  for (const r2 of rows) {
@@ -11940,8 +11996,8 @@ function Datatable({
11940
11996
  /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.group }),
11941
11997
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__groupbar-label", children: "Grouped by" }),
11942
11998
  activeGroupBy.map((f) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__groupchip", children: [
11943
- colByField[f]?.headerName || f,
11944
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__groupchip-x", "aria-label": `Stop grouping by ${colByField[f]?.headerName || f}`, onClick: () => toggleGroupField(f), children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.x }) })
11999
+ fieldLabel(f),
12000
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__groupchip-x", "aria-label": `Stop grouping by ${fieldLabel(f)}`, onClick: () => toggleGroupField(f), children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.x }) })
11945
12001
  ] }, f)),
11946
12002
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__groupbar-clear", onClick: () => setGroupBy([]), children: "Clear all" })
11947
12003
  ] }) : null,
@@ -11967,15 +12023,15 @@ function Datatable({
11967
12023
  ref: gridRef,
11968
12024
  role: "grid",
11969
12025
  "aria-label": ariaLabelAttr || ariaLabel,
11970
- "aria-rowcount": totalRows + 1,
11971
- "aria-colcount": ordered.length + (checkboxSelection ? 1 : 0) + (hasRowDetail ? 1 : 0),
12026
+ "aria-rowcount": (treeSeqByKey ? treeSeqByKey.size : totalRows) + 1,
12027
+ "aria-colcount": ordered.length + (checkboxSelection ? 1 : 0) + (hasExpandCol ? 1 : 0),
11972
12028
  "aria-multiselectable": selectionMode === "cell" || void 0,
11973
12029
  "aria-activedescendant": activeCellId,
11974
12030
  "aria-busy": loading || void 0,
11975
12031
  onKeyDown: onGridKeyDown,
11976
12032
  children: [
11977
12033
  /* @__PURE__ */ jsxRuntime.jsx("thead", { ref: theadRef, children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { role: "row", "aria-rowindex": 1, children: [
11978
- hasRowDetail ? /* @__PURE__ */ jsxRuntime.jsx("th", { className: "twc-dt__th twc-dt__expand-cell", role: "columnheader", "aria-label": "Expand", "data-pin": "left", "data-pin-edge": checkboxSelection || showRowNum || visLeft.length ? void 0 : "left", style: { insetInlineStart: 0, width: EXP_W, minWidth: EXP_W } }) : null,
12034
+ hasExpandCol ? /* @__PURE__ */ jsxRuntime.jsx("th", { className: "twc-dt__th twc-dt__expand-cell", role: "columnheader", "aria-label": "Expand", "data-pin": "left", "data-pin-edge": checkboxSelection || showRowNum || visLeft.length ? void 0 : "left", style: { insetInlineStart: 0, width: EXP_W, minWidth: EXP_W } }) : null,
11979
12035
  checkboxSelection ? /* @__PURE__ */ jsxRuntime.jsx("th", { className: "twc-dt__th", role: "columnheader", "aria-label": "Select", "data-pin": "left", "data-pin-edge": visLeft.length || showRowNum ? void 0 : "left", style: { insetInlineStart: EXP_W, width: CHK_W, minWidth: CHK_W }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__th-inner", style: { justifyContent: "center", padding: 0 }, children: /* @__PURE__ */ jsxRuntime.jsx(
11980
12036
  "span",
11981
12037
  {
@@ -12063,8 +12119,8 @@ function Datatable({
12063
12119
  className: "twc-dt__th-label",
12064
12120
  role: c.sortable ? "button" : void 0,
12065
12121
  tabIndex: c.sortable ? 0 : void 0,
12066
- "data-ovtext": typeof c.headerName === "string" ? c.headerName : void 0,
12067
- "aria-label": c.sortable ? `${c.headerName}, sort` : void 0,
12122
+ "data-ovtext": !c.renderHeader && typeof c.headerName === "string" ? c.headerName : void 0,
12123
+ "aria-label": c.sortable ? `${colLabel(c)}, sort` : void 0,
12068
12124
  draggable: reorderable || void 0,
12069
12125
  onDragStart: reorderable ? (e) => {
12070
12126
  setDrag({ from: c.field, over: null, after: false });
@@ -12082,7 +12138,7 @@ function Datatable({
12082
12138
  children: [
12083
12139
  reorderable ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__grip", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.grip }) }) : null,
12084
12140
  filteredFields.has(c.field) ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__filterdot" }) : null,
12085
- c.headerName,
12141
+ c.renderHeader ? c.renderHeader({ column: c }) : c.headerName,
12086
12142
  c.sortable ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__sort", children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.arrow }) }) : null
12087
12143
  ]
12088
12144
  }
@@ -12118,7 +12174,7 @@ function Datatable({
12118
12174
  "data-active": resizing || void 0,
12119
12175
  role: "separator",
12120
12176
  "aria-orientation": "vertical",
12121
- "aria-label": `Resize ${c.headerName} column (double-click to fit content)`,
12177
+ "aria-label": `Resize ${colLabel(c)} column (double-click to fit content)`,
12122
12178
  "aria-valuenow": w,
12123
12179
  "aria-valuemin": 72,
12124
12180
  tabIndex: 0,
@@ -12152,7 +12208,7 @@ function Datatable({
12152
12208
  })
12153
12209
  ] }) }),
12154
12210
  /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: loading ? Array.from({ length: paginated ? Math.min(sizeVal, 8) : 8 }).map((_, ri) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "twc-dt__row", role: "row", children: [
12155
- hasRowDetail ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: "twc-dt__td twc-dt__expand-cell", role: "gridcell", "data-pin": "left", style: { insetInlineStart: 0, width: EXP_W } }) : null,
12211
+ hasExpandCol ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: "twc-dt__td twc-dt__expand-cell", role: "gridcell", "data-pin": "left", style: { insetInlineStart: 0, width: EXP_W } }) : null,
12156
12212
  checkboxSelection ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: "twc-dt__td", role: "gridcell", "data-pin": "left", style: { insetInlineStart: EXP_W, width: CHK_W }, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__sk", "aria-hidden": "true", style: { "--_w": "18px", height: 18, borderRadius: 4 } }) }) : null,
12157
12213
  showRowNum ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: "twc-dt__td twc-dt__rownum", role: "gridcell", "aria-hidden": "true", "data-pin": "left", style: { insetInlineStart: numLeft, width: NUM_W }, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__sk", "aria-hidden": "true", style: { "--_w": "16px", height: 14, borderRadius: 4 } }) }) : null,
12158
12214
  ordered.map((c, ci) => {
@@ -12175,7 +12231,7 @@ function Datatable({
12175
12231
  pinnedBottomRows.map((row) => renderLeaf(row, keyIndex.get(keyOf(row)), "bottom"))
12176
12232
  ] }) }),
12177
12233
  hasAggregation && aggOn && !loading && paged.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("tfoot", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { role: "row", children: [
12178
- hasRowDetail ? /* @__PURE__ */ jsxRuntime.jsx("td", { role: "gridcell", "data-pin": "left", "data-pin-edge": checkboxSelection || showRowNum || visLeft.length ? void 0 : "left", style: { insetInlineStart: 0, width: EXP_W } }) : null,
12234
+ hasExpandCol ? /* @__PURE__ */ jsxRuntime.jsx("td", { role: "gridcell", "data-pin": "left", "data-pin-edge": checkboxSelection || showRowNum || visLeft.length ? void 0 : "left", style: { insetInlineStart: 0, width: EXP_W } }) : null,
12179
12235
  checkboxSelection ? /* @__PURE__ */ jsxRuntime.jsx("td", { role: "gridcell", "data-pin": "left", "data-pin-edge": visLeft.length || showRowNum ? void 0 : "left", style: { insetInlineStart: EXP_W, width: CHK_W } }) : null,
12180
12236
  showRowNum ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: "twc-dt__rownum", role: "gridcell", "aria-hidden": "true", "data-pin": "left", "data-pin-edge": visLeft.length ? void 0 : "left", style: { insetInlineStart: numLeft, width: NUM_W } }) : null,
12181
12237
  ordered.map((c) => {
@@ -12293,15 +12349,15 @@ function Datatable({
12293
12349
  placeholder: "Add a column\u2026",
12294
12350
  value: "",
12295
12351
  "aria-label": "Add a column to edit",
12296
- options: unpicked.map((c) => ({ value: c.field, label: String(c.headerName ?? c.field) })),
12352
+ options: unpicked.map((c) => ({ value: c.field, label: colLabel(c) })),
12297
12353
  onChange: addField
12298
12354
  }
12299
12355
  ) }) : null,
12300
12356
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__cfg-list", children: pickedCols.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__be-empty", children: "Pick a column to set its value on all selected rows." }) : pickedCols.map((c, i) => {
12301
12357
  const opts = c.valueOptions ? c.valueOptions.map((o) => typeof o === "string" ? { value: o, label: o } : o) : null;
12302
12358
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__be-row", children: [
12303
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__be-name", title: String(c.headerName ?? c.field), children: [
12304
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__be-name-txt", children: c.headerName }),
12359
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__be-name", title: colLabel(c), children: [
12360
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__be-name-txt", children: colLabel(c) }),
12305
12361
  resizableFilters && i === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
12306
12362
  "span",
12307
12363
  {
@@ -12341,7 +12397,7 @@ function Datatable({
12341
12397
  onChange: (e) => setBatchEdit((b) => ({ ...b, values: { ...b.values, [c.field]: e.target.value } }))
12342
12398
  }
12343
12399
  ) }),
12344
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__be-x", "aria-label": `Remove ${String(c.headerName ?? c.field)}`, onClick: () => removeField(c.field), children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.x }) })
12400
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__be-x", "aria-label": `Remove ${colLabel(c)}`, onClick: () => removeField(c.field), children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.x }) })
12345
12401
  ] }, c.field);
12346
12402
  }) }),
12347
12403
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-foot", children: [
@@ -12613,7 +12669,7 @@ function Datatable({
12613
12669
  children: [
12614
12670
  canDrag ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__col-grip", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.grip }) }) : null,
12615
12671
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__col-name", children: [
12616
- c.headerName,
12672
+ colLabel(c),
12617
12673
  combineSources.has(c.field) ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__col-combined", children: " \xB7 combined" }) : null
12618
12674
  ] }),
12619
12675
  c.pinnable && c.type !== "actions" ? (
@@ -12626,7 +12682,7 @@ function Datatable({
12626
12682
  className: "twc-dt__col-pin",
12627
12683
  "data-on": pins.left.includes(c.field) || void 0,
12628
12684
  "aria-pressed": pins.left.includes(c.field),
12629
- "aria-label": `Pin ${c.headerName} to left`,
12685
+ "aria-label": `Pin ${colLabel(c)} to left`,
12630
12686
  title: pins.left.includes(c.field) ? "Unpin" : "Pin to left",
12631
12687
  onClick: () => setPin(c.field, pins.left.includes(c.field) ? null : "left"),
12632
12688
  children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.pinL })
@@ -12639,7 +12695,7 @@ function Datatable({
12639
12695
  className: "twc-dt__col-pin",
12640
12696
  "data-on": pins.right.includes(c.field) || void 0,
12641
12697
  "aria-pressed": pins.right.includes(c.field),
12642
- "aria-label": `Pin ${c.headerName} to right`,
12698
+ "aria-label": `Pin ${colLabel(c)} to right`,
12643
12699
  title: pins.right.includes(c.field) ? "Unpin" : "Pin to right",
12644
12700
  onClick: () => setPin(c.field, pins.right.includes(c.field) ? null : "right"),
12645
12701
  children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.pin })
@@ -12654,7 +12710,7 @@ function Datatable({
12654
12710
  "data-on": !effectiveHidden.has(c.field) || void 0,
12655
12711
  role: "switch",
12656
12712
  "aria-checked": !effectiveHidden.has(c.field),
12657
- "aria-label": c.headerName,
12713
+ "aria-label": colLabel(c),
12658
12714
  "aria-disabled": !c.hideable || combineSources.has(c.field) || void 0,
12659
12715
  tabIndex: c.hideable && !combineSources.has(c.field) ? 0 : -1,
12660
12716
  onKeyDown: (e) => {
@@ -12678,17 +12734,17 @@ function Datatable({
12678
12734
  const target = colByField[combineTarget];
12679
12735
  const candidates = cols.filter((c) => c.field !== combineTarget && c.type !== "actions" && c.field !== "__pinactions__" && c.hideable !== false && !userCombine[c.field]);
12680
12736
  const toggle = (f) => setCombineDraft((d) => ({ ...d, selected: d.selected.includes(f) ? d.selected.filter((x) => x !== f) : [...d.selected, f] }));
12681
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: combinePanelRef, tabIndex: -1, className: "twc-dt__pop twc-dt__cols", style: { top: panelPos.top, left: panelPos.left, ...popStyle("combine") }, "data-pop-sized": popSizes.combine ? "" : void 0, role: "dialog", "aria-label": `Combine columns into ${target?.headerName || combineTarget}`, children: [
12737
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: combinePanelRef, tabIndex: -1, className: "twc-dt__pop twc-dt__cols", style: { top: panelPos.top, left: panelPos.left, ...popStyle("combine") }, "data-pop-sized": popSizes.combine ? "" : void 0, role: "dialog", "aria-label": `Combine columns into ${target ? colLabel(target) : combineTarget}`, children: [
12682
12738
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__panel-head", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__panel-title", children: [
12683
12739
  "Combine into \u201C",
12684
- target?.headerName || combineTarget,
12740
+ target ? colLabel(target) : combineTarget,
12685
12741
  "\u201D"
12686
12742
  ] }) }),
12687
12743
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__combine-hint", children: "Pick columns to merge into this one \u2014 their data shows in this cell and their own columns hide." }),
12688
12744
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__col-list", children: candidates.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__empty", style: { padding: "18px 12px" }, children: "No other columns" }) : candidates.map((c) => {
12689
12745
  const on = combineDraft.selected.includes(c.field);
12690
12746
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__col-row", onClick: () => toggle(c.field), children: [
12691
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__col-name", children: c.headerName }),
12747
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__col-name", children: colLabel(c) }),
12692
12748
  /* @__PURE__ */ jsxRuntime.jsx(
12693
12749
  "span",
12694
12750
  {
@@ -12696,7 +12752,7 @@ function Datatable({
12696
12752
  "data-on": on || void 0,
12697
12753
  role: "switch",
12698
12754
  "aria-checked": on,
12699
- "aria-label": c.headerName,
12755
+ "aria-label": colLabel(c),
12700
12756
  tabIndex: 0,
12701
12757
  onKeyDown: (e) => {
12702
12758
  if (e.key === "Enter" || e.key === " ") {
@@ -12779,7 +12835,7 @@ function Datatable({
12779
12835
  const numeric = c.type === "number";
12780
12836
  const opts = numeric ? [{ value: "", label: "None" }, { value: "sum", label: "Sum" }, { value: "avg", label: "Avg" }, { value: "min", label: "Min" }, { value: "max", label: "Max" }, { value: "count", label: "Count" }] : [{ value: "", label: "None" }, { value: "count", label: "Count" }];
12781
12837
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-row", children: [
12782
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__cfg-name", children: c.headerName }),
12838
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__cfg-name", children: colLabel(c) }),
12783
12839
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__cfg-ctl", children: /* @__PURE__ */ jsxRuntime.jsx(
12784
12840
  Select,
12785
12841
  {
@@ -12803,9 +12859,9 @@ function Datatable({
12803
12859
  popGrip("agg")
12804
12860
  ] }) : null,
12805
12861
  panel === "pivot" && panelPos ? (() => {
12806
- const fieldOpts = ordered.filter((c) => c.type !== "actions").map((c) => ({ value: c.field, label: c.headerName }));
12862
+ const fieldOpts = ordered.filter((c) => c.type !== "actions").map((c) => ({ value: c.field, label: colLabel(c) }));
12807
12863
  const aggOpts = [{ value: "sum", label: "Sum" }, { value: "avg", label: "Avg" }, { value: "min", label: "Min" }, { value: "max", label: "Max" }, { value: "count", label: "Count" }];
12808
- const valueFieldOpts = ordered.filter((c) => c.type !== "actions" && !pivotConfig.values.some((v) => v.field === c.field)).map((c) => ({ value: c.field, label: c.headerName }));
12864
+ const valueFieldOpts = ordered.filter((c) => c.type !== "actions" && !pivotConfig.values.some((v) => v.field === c.field)).map((c) => ({ value: c.field, label: colLabel(c) }));
12809
12865
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__pop twc-dt__cfg", style: { top: panelPos.top, left: panelPos.left, width: 320, ...popStyle("pivot") }, "data-pop-sized": popSizes.pivot ? "" : void 0, role: "dialog", "aria-label": "Pivot settings", children: [
12810
12866
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__panel-head", children: [
12811
12867
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__panel-title", children: "Pivot" }),
@@ -12874,7 +12930,7 @@ function Datatable({
12874
12930
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-section", children: [
12875
12931
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__cfg-label", children: "Values" }),
12876
12932
  pivotConfig.values.map((v, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-row", children: [
12877
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__cfg-name", children: colByField[v.field]?.headerName || v.field }),
12933
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__cfg-name", children: fieldLabel(v.field) }),
12878
12934
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__cfg-ctl", children: /* @__PURE__ */ jsxRuntime.jsx(
12879
12935
  Select,
12880
12936
  {
@@ -12890,7 +12946,7 @@ function Datatable({
12890
12946
  {
12891
12947
  type: "button",
12892
12948
  className: "twc-dt__cfg-x",
12893
- "aria-label": `Remove ${colByField[v.field]?.headerName || v.field}`,
12949
+ "aria-label": `Remove ${fieldLabel(v.field)}`,
12894
12950
  onClick: () => setPivotConfig((p) => ({ ...p, values: p.values.filter((_, j) => j !== i) })),
12895
12951
  children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.x })
12896
12952
  }
@@ -12972,7 +13028,7 @@ function Datatable({
12972
13028
  size: "sm",
12973
13029
  portal: true,
12974
13030
  value: f.field,
12975
- options: filterableCols.map((c) => ({ value: c.field, label: c.headerName })),
13031
+ options: filterableCols.map((c) => ({ value: c.field, label: colLabel(c) })),
12976
13032
  onChange: (v) => {
12977
13033
  const nc = colByField[v];
12978
13034
  setFilters((arr) => arr.map((x) => x.id === f.id ? { ...x, field: v, op: opsFor(filterTypeOf(nc))[0].value, value: "" } : x));
@@ -13029,7 +13085,7 @@ function Datatable({
13029
13085
  ),
13030
13086
  fieldHandle("val", i)
13031
13087
  ] }),
13032
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__frm-x", "aria-label": `Add another condition on ${col.headerName}`, title: "Add another condition on this column", onClick: () => addFilter(f.field), children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.plus }) }),
13088
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__frm-x", "aria-label": `Add another condition on ${colLabel(col)}`, title: "Add another condition on this column", onClick: () => addFilter(f.field), children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.plus }) }),
13033
13089
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__frm-x", "aria-label": "Remove filter", onClick: () => setFilters((arr) => arr.filter((x) => x.id !== f.id)), children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.x }) })
13034
13090
  ] }, f.id);
13035
13091
  }) }),