twico-ui 1.35.0 → 1.36.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/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
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.1](https://github.com/EncryptionL/twico-ui/compare/v1.36.0...v1.36.1) (2026-09-09)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * **datatable:** runtime combine into a valueGetter/renderCell target ([#369](https://github.com/EncryptionL/twico-ui/issues/369)) ([6363f38](https://github.com/EncryptionL/twico-ui/commit/6363f38ffd2b754dc7be9ddb6f47cbfc9bab10e2)), closes [#338](https://github.com/EncryptionL/twico-ui/issues/338)
11
+
12
+ # [1.36.0](https://github.com/EncryptionL/twico-ui/compare/v1.35.0...v1.36.0) (2026-09-09)
13
+
14
+
15
+ ### Features
16
+
17
+ * **datatable:** custom column header via renderHeader ([#367](https://github.com/EncryptionL/twico-ui/issues/367)) ([647ab35](https://github.com/EncryptionL/twico-ui/commit/647ab35d171170b215d2945c5aa624e02230f144))
18
+
5
19
  # [1.35.0](https://github.com/EncryptionL/twico-ui/compare/v1.34.0...v1.35.0) (2026-08-28)
6
20
 
7
21
 
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
@@ -9380,7 +9381,7 @@ function Datatable({
9380
9381
  for (const c of columnsProp) if (c && c.field != null) byField[c.field] = c;
9381
9382
  return [DIFF_OP_COLUMN, ...columnsProp.map((c) => {
9382
9383
  const cfg = combineCfg(userCombine[c.field] || c.combine);
9383
- const base = cfg && !c.valueGetter ? { ...c, valueGetter: combineValueGetter(combineSrcCols(cfg, byField), cfg) } : c;
9384
+ const base = cfg && (!!userCombine[c.field] || !c.valueGetter) ? { ...c, valueGetter: combineValueGetter(combineSrcCols(cfg, byField), cfg) } : c;
9384
9385
  return { ...base, renderCell: (val, row) => renderDiffCell(base, val, row) };
9385
9386
  })];
9386
9387
  },
@@ -9431,15 +9432,17 @@ function Datatable({
9431
9432
  const cfg = combineCfg(userCombine[c.field] || c.combine);
9432
9433
  if (!cfg) continue;
9433
9434
  const srcCols = combineSrcCols(cfg, byField);
9435
+ const explicit = !!userCombine[c.field];
9436
+ const useJoin = explicit || !c.valueGetter;
9434
9437
  out[i] = {
9435
9438
  ...c,
9436
9439
  editable: false,
9437
9440
  // the combined value is synthetic — inline editing would write to a phantom field
9438
- valueGetter: c.valueGetter || combineValueGetter(srcCols, cfg),
9439
- // Consumer renderCell wins. If they overrode only valueGetter, fall back to the DEFAULT cell render
9440
- // (renderCell: undefined) so the cell shows THEIR value — keeping display in sync with what
9441
- // sort/filter/search/export use — rather than the auto source-join. Otherwise render the combined cell.
9442
- renderCell: c.renderCell || (c.valueGetter ? void 0 : ((value, row) => renderCombined(srcCols, row, cfg)))
9441
+ valueGetter: useJoin ? combineValueGetter(srcCols, cfg) : c.valueGetter,
9442
+ // In diff mode the diff `columns` memo already wrapped renderCell in renderDiffCell (over the enriched
9443
+ // combined value) — keep that wrapper, or an EXPLICIT combine's `!explicit` short-circuit would strip the
9444
+ // diff arrows / old→new styling (#369 review). Declarative diff already preserved it (c.renderCell truthy).
9445
+ renderCell: isDiff ? c.renderCell : !explicit && c.renderCell || (useJoin ? ((value, row) => renderCombined(srcCols, row, cfg)) : void 0)
9443
9446
  };
9444
9447
  }
9445
9448
  return out;
@@ -9804,7 +9807,7 @@ function Datatable({
9804
9807
  }, [rowGroupingKey]);
9805
9808
  const AUTO_CHROME = 74;
9806
9809
  const autoWidth = (c) => {
9807
- const label = typeof c.headerName === "string" ? c.headerName : String(c.field ?? "");
9810
+ const label = colLabel(c);
9808
9811
  return AUTO_CHROME + Math.ceil(label.length * 8);
9809
9812
  };
9810
9813
  const clampWidth = (w, c) => {
@@ -9928,6 +9931,7 @@ function Datatable({
9928
9931
  };
9929
9932
  }, [exportOpen]);
9930
9933
  const colByField = React51__namespace.default.useMemo(() => Object.fromEntries(cols.map((c) => [c.field, c])), [cols]);
9934
+ const fieldLabel = (f) => colLabel(colByField[f] || { field: f });
9931
9935
  const combineSources = React51__namespace.default.useMemo(() => {
9932
9936
  const s = /* @__PURE__ */ new Set();
9933
9937
  for (const cfg of Object.values(userCombine)) (cfg && cfg.fields ? cfg.fields : []).slice(1).forEach((f) => s.add(f));
@@ -10088,7 +10092,7 @@ function Datatable({
10088
10092
  const v = computeAgg({ ...c, aggregation: agg }, rowsIn);
10089
10093
  if (v == null) continue;
10090
10094
  const disp = c.aggregationFormatter ? c.aggregationFormatter(v) : c.valueFormatter ? c.valueFormatter(v, null) : typeof v === "number" ? v.toLocaleString() : v;
10091
- parts.push(`${c.headerName} ${disp}`);
10095
+ parts.push(`${colLabel(c)} ${disp}`);
10092
10096
  }
10093
10097
  return parts;
10094
10098
  }
@@ -10441,7 +10445,7 @@ function Datatable({
10441
10445
  next.splice(dir > 0 ? b + 1 : b, 0, field);
10442
10446
  return next;
10443
10447
  });
10444
- const label = colByField[field]?.headerName || field;
10448
+ const label = fieldLabel(field);
10445
10449
  setReorderMsg(`Moved ${label} ${dir < 0 ? "left" : "right"}.`);
10446
10450
  }
10447
10451
  function optionsForField(field) {
@@ -10548,7 +10552,7 @@ function Datatable({
10548
10552
  const rowXml = (cells, r2) => `<row r="${r2}">${cells.map((v, ci) => cell(`${colLetter(ci)}${r2}`, v)).join("")}</row>`;
10549
10553
  const lastCell = `${expCols.length ? colLetter(expCols.length - 1) : "A"}${source.length + 1}`;
10550
10554
  const sheet = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
10551
- <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>";
10555
+ <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>";
10552
10556
  download(xlsxPackage(sheet), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "xlsx");
10553
10557
  return;
10554
10558
  }
@@ -10556,7 +10560,7 @@ function Datatable({
10556
10560
  const s = defang(v, v == null ? "" : String(v));
10557
10561
  return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
10558
10562
  };
10559
- const header = expCols.map((c) => escape(c.headerName)).join(",");
10563
+ const header = expCols.map((c) => escape(colLabel(c))).join(",");
10560
10564
  const lines = source.map((row) => expCols.map((c) => escape(cellValue(c, row))).join(","));
10561
10565
  const text = "\uFEFF" + [header, ...lines].join("\r\n");
10562
10566
  download(text, "text/csv;charset=utf-8;", "csv");
@@ -11093,7 +11097,7 @@ function Datatable({
11093
11097
  const widest = (labels) => labels.reduce((m, l) => Math.max(m, ctx.measureText(String(l)).width), 0);
11094
11098
  const logicW = Math.min(180, Math.max(84, Math.ceil(widest(["And", "Or"]) + chrome)));
11095
11099
  const colCap = Math.max(118, Math.min(210, el.clientWidth - logicW - 118 - 30 - 30 - 140 - 5 * 6 - 2 * 4));
11096
- const colW = Math.min(colCap, Math.max(118, Math.ceil(widest(filterableCols.map((c) => c.headerName ?? c.field)) + chrome)));
11100
+ const colW = Math.min(colCap, Math.max(118, Math.ceil(widest(filterableCols.map((c) => colLabel(c))) + chrome)));
11097
11101
  const opW = Math.min(170, Math.max(118, Math.ceil(widest(ALL_OP_LABELS) + chrome)));
11098
11102
  if (Number.isFinite(logicW)) el.style.setProperty("--twc-dt-flogic-fit", `${logicW}px`);
11099
11103
  if (Number.isFinite(colW)) el.style.setProperty("--twc-dt-fcol-fit", `${colW}px`);
@@ -11456,7 +11460,7 @@ function Datatable({
11456
11460
  const i = order.indexOf(f);
11457
11461
  return i === -1 ? 9999 : i;
11458
11462
  };
11459
- const shownColRows = cols.filter((c) => c.field !== "__pinactions__" && c.headerName.toLowerCase().includes(colQuery.trim().toLowerCase())).sort((a, b) => orderIdxOf(a.field) - orderIdxOf(b.field));
11463
+ const shownColRows = cols.filter((c) => c.field !== "__pinactions__" && colLabel(c).toLowerCase().includes(colQuery.trim().toLowerCase())).sort((a, b) => orderIdxOf(a.field) - orderIdxOf(b.field));
11460
11464
  const rowNumMatch = rowNumbers && "row number".includes(colQuery.trim().toLowerCase());
11461
11465
  const manageableCols = cols.filter((c) => c.field !== "__pinactions__");
11462
11466
  const visibleColCount = manageableCols.filter((c) => !effectiveHidden.has(c.field)).length;
@@ -11476,7 +11480,7 @@ function Datatable({
11476
11480
  children: [
11477
11481
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__group-chev", "data-open": !item.collapsed || void 0, children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.chevDown }) }),
11478
11482
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__group-name", children: [
11479
- colByField[item.field]?.headerName || item.field,
11483
+ fieldLabel(item.field),
11480
11484
  ":"
11481
11485
  ] }),
11482
11486
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__group-val", children: String(item.value) }),
@@ -11698,8 +11702,8 @@ function Datatable({
11698
11702
  const f = v.valueFormatter || col?.valueFormatter;
11699
11703
  return f ? f(val, null) : typeof val === "number" ? val.toLocaleString() : val;
11700
11704
  };
11701
- const vlabel = (v) => v.label || (colByField[v.field]?.headerName || v.field);
11702
- const rowFieldLabel = rFields.map((f) => colByField[f]?.headerName || f).join(" / ");
11705
+ const vlabel = (v) => v.label || fieldLabel(v.field);
11706
+ const rowFieldLabel = rFields.map((f) => fieldLabel(f)).join(" / ");
11703
11707
  const leafPaths = [];
11704
11708
  const seen2 = /* @__PURE__ */ new Set();
11705
11709
  for (const r2 of rows) {
@@ -11994,8 +11998,8 @@ function Datatable({
11994
11998
  /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.group }),
11995
11999
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__groupbar-label", children: "Grouped by" }),
11996
12000
  activeGroupBy.map((f) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__groupchip", children: [
11997
- colByField[f]?.headerName || f,
11998
- /* @__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 }) })
12001
+ fieldLabel(f),
12002
+ /* @__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 }) })
11999
12003
  ] }, f)),
12000
12004
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__groupbar-clear", onClick: () => setGroupBy([]), children: "Clear all" })
12001
12005
  ] }) : null,
@@ -12117,8 +12121,8 @@ function Datatable({
12117
12121
  className: "twc-dt__th-label",
12118
12122
  role: c.sortable ? "button" : void 0,
12119
12123
  tabIndex: c.sortable ? 0 : void 0,
12120
- "data-ovtext": typeof c.headerName === "string" ? c.headerName : void 0,
12121
- "aria-label": c.sortable ? `${c.headerName}, sort` : void 0,
12124
+ "data-ovtext": !c.renderHeader && typeof c.headerName === "string" ? c.headerName : void 0,
12125
+ "aria-label": c.sortable ? `${colLabel(c)}, sort` : void 0,
12122
12126
  draggable: reorderable || void 0,
12123
12127
  onDragStart: reorderable ? (e) => {
12124
12128
  setDrag({ from: c.field, over: null, after: false });
@@ -12136,7 +12140,7 @@ function Datatable({
12136
12140
  children: [
12137
12141
  reorderable ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__grip", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.grip }) }) : null,
12138
12142
  filteredFields.has(c.field) ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__filterdot" }) : null,
12139
- c.headerName,
12143
+ c.renderHeader ? c.renderHeader({ column: c }) : c.headerName,
12140
12144
  c.sortable ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__sort", children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.arrow }) }) : null
12141
12145
  ]
12142
12146
  }
@@ -12172,7 +12176,7 @@ function Datatable({
12172
12176
  "data-active": resizing || void 0,
12173
12177
  role: "separator",
12174
12178
  "aria-orientation": "vertical",
12175
- "aria-label": `Resize ${c.headerName} column (double-click to fit content)`,
12179
+ "aria-label": `Resize ${colLabel(c)} column (double-click to fit content)`,
12176
12180
  "aria-valuenow": w,
12177
12181
  "aria-valuemin": 72,
12178
12182
  tabIndex: 0,
@@ -12347,15 +12351,15 @@ function Datatable({
12347
12351
  placeholder: "Add a column\u2026",
12348
12352
  value: "",
12349
12353
  "aria-label": "Add a column to edit",
12350
- options: unpicked.map((c) => ({ value: c.field, label: String(c.headerName ?? c.field) })),
12354
+ options: unpicked.map((c) => ({ value: c.field, label: colLabel(c) })),
12351
12355
  onChange: addField
12352
12356
  }
12353
12357
  ) }) : null,
12354
12358
  /* @__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) => {
12355
12359
  const opts = c.valueOptions ? c.valueOptions.map((o) => typeof o === "string" ? { value: o, label: o } : o) : null;
12356
12360
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__be-row", children: [
12357
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__be-name", title: String(c.headerName ?? c.field), children: [
12358
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__be-name-txt", children: c.headerName }),
12361
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__be-name", title: colLabel(c), children: [
12362
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__be-name-txt", children: colLabel(c) }),
12359
12363
  resizableFilters && i === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
12360
12364
  "span",
12361
12365
  {
@@ -12395,7 +12399,7 @@ function Datatable({
12395
12399
  onChange: (e) => setBatchEdit((b) => ({ ...b, values: { ...b.values, [c.field]: e.target.value } }))
12396
12400
  }
12397
12401
  ) }),
12398
- /* @__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 }) })
12402
+ /* @__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 }) })
12399
12403
  ] }, c.field);
12400
12404
  }) }),
12401
12405
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-foot", children: [
@@ -12667,7 +12671,7 @@ function Datatable({
12667
12671
  children: [
12668
12672
  canDrag ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__col-grip", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.grip }) }) : null,
12669
12673
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__col-name", children: [
12670
- c.headerName,
12674
+ colLabel(c),
12671
12675
  combineSources.has(c.field) ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__col-combined", children: " \xB7 combined" }) : null
12672
12676
  ] }),
12673
12677
  c.pinnable && c.type !== "actions" ? (
@@ -12680,7 +12684,7 @@ function Datatable({
12680
12684
  className: "twc-dt__col-pin",
12681
12685
  "data-on": pins.left.includes(c.field) || void 0,
12682
12686
  "aria-pressed": pins.left.includes(c.field),
12683
- "aria-label": `Pin ${c.headerName} to left`,
12687
+ "aria-label": `Pin ${colLabel(c)} to left`,
12684
12688
  title: pins.left.includes(c.field) ? "Unpin" : "Pin to left",
12685
12689
  onClick: () => setPin(c.field, pins.left.includes(c.field) ? null : "left"),
12686
12690
  children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.pinL })
@@ -12693,7 +12697,7 @@ function Datatable({
12693
12697
  className: "twc-dt__col-pin",
12694
12698
  "data-on": pins.right.includes(c.field) || void 0,
12695
12699
  "aria-pressed": pins.right.includes(c.field),
12696
- "aria-label": `Pin ${c.headerName} to right`,
12700
+ "aria-label": `Pin ${colLabel(c)} to right`,
12697
12701
  title: pins.right.includes(c.field) ? "Unpin" : "Pin to right",
12698
12702
  onClick: () => setPin(c.field, pins.right.includes(c.field) ? null : "right"),
12699
12703
  children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.pin })
@@ -12708,7 +12712,7 @@ function Datatable({
12708
12712
  "data-on": !effectiveHidden.has(c.field) || void 0,
12709
12713
  role: "switch",
12710
12714
  "aria-checked": !effectiveHidden.has(c.field),
12711
- "aria-label": c.headerName,
12715
+ "aria-label": colLabel(c),
12712
12716
  "aria-disabled": !c.hideable || combineSources.has(c.field) || void 0,
12713
12717
  tabIndex: c.hideable && !combineSources.has(c.field) ? 0 : -1,
12714
12718
  onKeyDown: (e) => {
@@ -12732,17 +12736,17 @@ function Datatable({
12732
12736
  const target = colByField[combineTarget];
12733
12737
  const candidates = cols.filter((c) => c.field !== combineTarget && c.type !== "actions" && c.field !== "__pinactions__" && c.hideable !== false && !userCombine[c.field]);
12734
12738
  const toggle = (f) => setCombineDraft((d) => ({ ...d, selected: d.selected.includes(f) ? d.selected.filter((x) => x !== f) : [...d.selected, f] }));
12735
- 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: [
12739
+ 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: [
12736
12740
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__panel-head", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__panel-title", children: [
12737
12741
  "Combine into \u201C",
12738
- target?.headerName || combineTarget,
12742
+ target ? colLabel(target) : combineTarget,
12739
12743
  "\u201D"
12740
12744
  ] }) }),
12741
12745
  /* @__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." }),
12742
12746
  /* @__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) => {
12743
12747
  const on = combineDraft.selected.includes(c.field);
12744
12748
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__col-row", onClick: () => toggle(c.field), children: [
12745
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__col-name", children: c.headerName }),
12749
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__col-name", children: colLabel(c) }),
12746
12750
  /* @__PURE__ */ jsxRuntime.jsx(
12747
12751
  "span",
12748
12752
  {
@@ -12750,7 +12754,7 @@ function Datatable({
12750
12754
  "data-on": on || void 0,
12751
12755
  role: "switch",
12752
12756
  "aria-checked": on,
12753
- "aria-label": c.headerName,
12757
+ "aria-label": colLabel(c),
12754
12758
  tabIndex: 0,
12755
12759
  onKeyDown: (e) => {
12756
12760
  if (e.key === "Enter" || e.key === " ") {
@@ -12833,7 +12837,7 @@ function Datatable({
12833
12837
  const numeric = c.type === "number";
12834
12838
  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" }];
12835
12839
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-row", children: [
12836
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__cfg-name", children: c.headerName }),
12840
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__cfg-name", children: colLabel(c) }),
12837
12841
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__cfg-ctl", children: /* @__PURE__ */ jsxRuntime.jsx(
12838
12842
  Select,
12839
12843
  {
@@ -12857,9 +12861,9 @@ function Datatable({
12857
12861
  popGrip("agg")
12858
12862
  ] }) : null,
12859
12863
  panel === "pivot" && panelPos ? (() => {
12860
- const fieldOpts = ordered.filter((c) => c.type !== "actions").map((c) => ({ value: c.field, label: c.headerName }));
12864
+ const fieldOpts = ordered.filter((c) => c.type !== "actions").map((c) => ({ value: c.field, label: colLabel(c) }));
12861
12865
  const aggOpts = [{ value: "sum", label: "Sum" }, { value: "avg", label: "Avg" }, { value: "min", label: "Min" }, { value: "max", label: "Max" }, { value: "count", label: "Count" }];
12862
- const valueFieldOpts = ordered.filter((c) => c.type !== "actions" && !pivotConfig.values.some((v) => v.field === c.field)).map((c) => ({ value: c.field, label: c.headerName }));
12866
+ const valueFieldOpts = ordered.filter((c) => c.type !== "actions" && !pivotConfig.values.some((v) => v.field === c.field)).map((c) => ({ value: c.field, label: colLabel(c) }));
12863
12867
  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: [
12864
12868
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__panel-head", children: [
12865
12869
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__panel-title", children: "Pivot" }),
@@ -12928,7 +12932,7 @@ function Datatable({
12928
12932
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-section", children: [
12929
12933
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__cfg-label", children: "Values" }),
12930
12934
  pivotConfig.values.map((v, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-row", children: [
12931
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__cfg-name", children: colByField[v.field]?.headerName || v.field }),
12935
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__cfg-name", children: fieldLabel(v.field) }),
12932
12936
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__cfg-ctl", children: /* @__PURE__ */ jsxRuntime.jsx(
12933
12937
  Select,
12934
12938
  {
@@ -12944,7 +12948,7 @@ function Datatable({
12944
12948
  {
12945
12949
  type: "button",
12946
12950
  className: "twc-dt__cfg-x",
12947
- "aria-label": `Remove ${colByField[v.field]?.headerName || v.field}`,
12951
+ "aria-label": `Remove ${fieldLabel(v.field)}`,
12948
12952
  onClick: () => setPivotConfig((p) => ({ ...p, values: p.values.filter((_, j) => j !== i) })),
12949
12953
  children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.x })
12950
12954
  }
@@ -13026,7 +13030,7 @@ function Datatable({
13026
13030
  size: "sm",
13027
13031
  portal: true,
13028
13032
  value: f.field,
13029
- options: filterableCols.map((c) => ({ value: c.field, label: c.headerName })),
13033
+ options: filterableCols.map((c) => ({ value: c.field, label: colLabel(c) })),
13030
13034
  onChange: (v) => {
13031
13035
  const nc = colByField[v];
13032
13036
  setFilters((arr) => arr.map((x) => x.id === f.id ? { ...x, field: v, op: opsFor(filterTypeOf(nc))[0].value, value: "" } : x));
@@ -13083,7 +13087,7 @@ function Datatable({
13083
13087
  ),
13084
13088
  fieldHandle("val", i)
13085
13089
  ] }),
13086
- /* @__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 }) }),
13090
+ /* @__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 }) }),
13087
13091
  /* @__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 }) })
13088
13092
  ] }, f.id);
13089
13093
  }) }),