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/dist/index.d.cts CHANGED
@@ -1927,7 +1927,9 @@ interface DatatableProps<T = any> extends Omit<React.HTMLAttributes<HTMLDivEleme
1927
1927
  /** #339: let end-users build their own combined columns at runtime. Adds a **"Combine columns…"** item to
1928
1928
  * each column's ⋮ menu that opens an editor to fold other columns' data into that column (they show in its
1929
1929
  * cell and their own columns hide); layout (inline/stacked) + labels are configurable, and "Uncombine"
1930
- * restores them. The result is the same as a declarative `column.combine` and persists via `stateKey`.
1930
+ * restores them. The result is like a declarative `column.combine` and persists via `stateKey` — except a
1931
+ * runtime combine also applies the source-join value + render over a target's own `valueGetter`/`renderCell`
1932
+ * (so a synthetic getter-backed column can still be a target), which a declarative `combine` defers to (#369).
1931
1933
  * @default false */
1932
1934
  columnCombining?: boolean;
1933
1935
  /** Make all columns editable by default (double-click a cell to edit; per-column `editable` overrides). @default false */
@@ -2179,10 +2181,21 @@ interface DatatableColumn<T = any> {
2179
2181
  * (label-prefixed when `labels`), while the **cell render** additionally applies each source column's
2180
2182
  * `valueFormatter`. The combined value is synthetic, so the column is display-only (never inline-editable).
2181
2183
  * Supplying your own `valueGetter` and/or `renderCell` overrides the derived one(s) independently —
2182
- * override `valueGetter` alone and the cell shows that value (not the source-join). */
2184
+ * override `valueGetter` alone and the cell shows that value (not the source-join). **This precedence is
2185
+ * for a *declarative* `combine` only.** A *runtime* combine the user builds via `columnCombining` (the ⋮ →
2186
+ * "Combine columns…" editor) is an explicit action, so it applies the source-join value + render even when
2187
+ * the target column has its own `valueGetter`/`renderCell` — a synthetic getter-backed column can still be
2188
+ * a combine target (#369). Uncombining restores the column's own value/render. */
2183
2189
  combine?: string[] | { fields: string[]; layout?: "inline" | "stack"; separator?: string; labels?: boolean };
2184
2190
  /** Header label. @default field ("Actions" for actions columns) */
2185
2191
  headerName?: string;
2192
+ /** #367: fully custom column-header renderer — the header analogue of `renderCell`, mirroring MUI
2193
+ * DataGrid's `renderHeader`. Receives the resolved column and returns the node rendered inside the
2194
+ * header cell (e.g. a label + a trailing (i) `Tooltip`) in place of `headerName`. `headerName` stays
2195
+ * the plain-text label used for quick-search, the Columns menu, CSV/Excel export, aggregation, and the
2196
+ * a11y sort/resize labels, so a custom header never breaks those string consumers — keep it set to that
2197
+ * label. (A non-string `headerName` also no longer throws in the Columns menu.) */
2198
+ renderHeader?: (args: { column: DatatableColumn<T> }) => React.ReactNode;
2186
2199
  /** Data type. "actions" renders per-row action buttons via getActions. @default "string" */
2187
2200
  type?: "string" | "number" | "actions";
2188
2201
  /** Filter operators + value comparison for this column, **decoupled from the edit `type`** (#270).
package/dist/index.d.ts CHANGED
@@ -1927,7 +1927,9 @@ interface DatatableProps<T = any> extends Omit<React.HTMLAttributes<HTMLDivEleme
1927
1927
  /** #339: let end-users build their own combined columns at runtime. Adds a **"Combine columns…"** item to
1928
1928
  * each column's ⋮ menu that opens an editor to fold other columns' data into that column (they show in its
1929
1929
  * cell and their own columns hide); layout (inline/stacked) + labels are configurable, and "Uncombine"
1930
- * restores them. The result is the same as a declarative `column.combine` and persists via `stateKey`.
1930
+ * restores them. The result is like a declarative `column.combine` and persists via `stateKey` — except a
1931
+ * runtime combine also applies the source-join value + render over a target's own `valueGetter`/`renderCell`
1932
+ * (so a synthetic getter-backed column can still be a target), which a declarative `combine` defers to (#369).
1931
1933
  * @default false */
1932
1934
  columnCombining?: boolean;
1933
1935
  /** Make all columns editable by default (double-click a cell to edit; per-column `editable` overrides). @default false */
@@ -2179,10 +2181,21 @@ interface DatatableColumn<T = any> {
2179
2181
  * (label-prefixed when `labels`), while the **cell render** additionally applies each source column's
2180
2182
  * `valueFormatter`. The combined value is synthetic, so the column is display-only (never inline-editable).
2181
2183
  * Supplying your own `valueGetter` and/or `renderCell` overrides the derived one(s) independently —
2182
- * override `valueGetter` alone and the cell shows that value (not the source-join). */
2184
+ * override `valueGetter` alone and the cell shows that value (not the source-join). **This precedence is
2185
+ * for a *declarative* `combine` only.** A *runtime* combine the user builds via `columnCombining` (the ⋮ →
2186
+ * "Combine columns…" editor) is an explicit action, so it applies the source-join value + render even when
2187
+ * the target column has its own `valueGetter`/`renderCell` — a synthetic getter-backed column can still be
2188
+ * a combine target (#369). Uncombining restores the column's own value/render. */
2183
2189
  combine?: string[] | { fields: string[]; layout?: "inline" | "stack"; separator?: string; labels?: boolean };
2184
2190
  /** Header label. @default field ("Actions" for actions columns) */
2185
2191
  headerName?: string;
2192
+ /** #367: fully custom column-header renderer — the header analogue of `renderCell`, mirroring MUI
2193
+ * DataGrid's `renderHeader`. Receives the resolved column and returns the node rendered inside the
2194
+ * header cell (e.g. a label + a trailing (i) `Tooltip`) in place of `headerName`. `headerName` stays
2195
+ * the plain-text label used for quick-search, the Columns menu, CSV/Excel export, aggregation, and the
2196
+ * a11y sort/resize labels, so a custom header never breaks those string consumers — keep it set to that
2197
+ * label. (A non-string `headerName` also no longer throws in the Columns menu.) */
2198
+ renderHeader?: (args: { column: DatatableColumn<T> }) => React.ReactNode;
2186
2199
  /** Data type. "actions" renders per-row action buttons via getActions. @default "string" */
2187
2200
  type?: "string" | "number" | "actions";
2188
2201
  /** Filter operators + value comparison for this column, **decoupled from the edit `type`** (#270).
package/dist/index.mjs CHANGED
@@ -8869,11 +8869,12 @@ function combineCfg(combine) {
8869
8869
  if (!fields.length) return null;
8870
8870
  return { fields, separator: cfg.separator != null ? cfg.separator : " \xB7 ", labels: !!cfg.labels, layout: cfg.layout === "stack" ? "stack" : "inline" };
8871
8871
  }
8872
+ var colLabel = (c) => typeof c.headerName === "string" ? c.headerName : String(c.field ?? "");
8872
8873
  var combineSrcCols = (cfg, byField) => cfg.fields.map((f) => byField && byField[f] || { field: f, headerName: String(f) });
8873
8874
  var combineValueGetter = (srcCols, cfg) => (row) => srcCols.map((sc) => {
8874
8875
  const v = getColVal(sc, row);
8875
8876
  const s = v == null ? "" : String(v);
8876
- return cfg.labels && s ? `${sc.headerName ?? sc.field}: ${s}` : s;
8877
+ return cfg.labels && s ? `${colLabel(sc)}: ${s}` : s;
8877
8878
  }).filter(Boolean).join(cfg.separator);
8878
8879
  function renderCombined(srcCols, row, cfg) {
8879
8880
  const nodes = [];
@@ -8882,7 +8883,7 @@ function renderCombined(srcCols, row, cfg) {
8882
8883
  const v = getColVal(sc, row);
8883
8884
  if (v == null || v === "") return;
8884
8885
  const disp = sc.valueFormatter ? sc.valueFormatter(v, row) : v;
8885
- const label = cfg.labels ? React51__default.createElement("span", { className: "twc-dt__combine-label" }, (sc.headerName ?? sc.field) + ": ") : null;
8886
+ const label = cfg.labels ? React51__default.createElement("span", { className: "twc-dt__combine-label" }, colLabel(sc) + ": ") : null;
8886
8887
  if (count > 0 && cfg.layout !== "stack") nodes.push(React51__default.createElement("span", { key: "sep" + idx, className: "twc-dt__combine-sep", "aria-hidden": "true" }, cfg.separator));
8887
8888
  nodes.push(React51__default.createElement("span", { key: idx, className: "twc-dt__combine-item" }, label, disp));
8888
8889
  count++;
@@ -9132,7 +9133,7 @@ function EditCell({ col, value, options, onChange, onCommit, onCommitValue, onCa
9132
9133
  className: "twc-dt__editor",
9133
9134
  type: col.type === "number" ? "number" : "text",
9134
9135
  value: value ?? "",
9135
- "aria-label": `Edit ${col.headerName}`,
9136
+ "aria-label": `Edit ${colLabel(col)}`,
9136
9137
  onChange: (e) => onChange(e.target.value),
9137
9138
  onKeyDown,
9138
9139
  onBlur: onCommit
@@ -9359,7 +9360,7 @@ function Datatable({
9359
9360
  for (const c of columnsProp) if (c && c.field != null) byField[c.field] = c;
9360
9361
  return [DIFF_OP_COLUMN, ...columnsProp.map((c) => {
9361
9362
  const cfg = combineCfg(userCombine[c.field] || c.combine);
9362
- const base = cfg && !c.valueGetter ? { ...c, valueGetter: combineValueGetter(combineSrcCols(cfg, byField), cfg) } : c;
9363
+ const base = cfg && (!!userCombine[c.field] || !c.valueGetter) ? { ...c, valueGetter: combineValueGetter(combineSrcCols(cfg, byField), cfg) } : c;
9363
9364
  return { ...base, renderCell: (val, row) => renderDiffCell(base, val, row) };
9364
9365
  })];
9365
9366
  },
@@ -9410,15 +9411,17 @@ function Datatable({
9410
9411
  const cfg = combineCfg(userCombine[c.field] || c.combine);
9411
9412
  if (!cfg) continue;
9412
9413
  const srcCols = combineSrcCols(cfg, byField);
9414
+ const explicit = !!userCombine[c.field];
9415
+ const useJoin = explicit || !c.valueGetter;
9413
9416
  out[i] = {
9414
9417
  ...c,
9415
9418
  editable: false,
9416
9419
  // the combined value is synthetic — inline editing would write to a phantom field
9417
- valueGetter: c.valueGetter || combineValueGetter(srcCols, cfg),
9418
- // Consumer renderCell wins. If they overrode only valueGetter, fall back to the DEFAULT cell render
9419
- // (renderCell: undefined) so the cell shows THEIR value — keeping display in sync with what
9420
- // sort/filter/search/export use — rather than the auto source-join. Otherwise render the combined cell.
9421
- renderCell: c.renderCell || (c.valueGetter ? void 0 : ((value, row) => renderCombined(srcCols, row, cfg)))
9420
+ valueGetter: useJoin ? combineValueGetter(srcCols, cfg) : c.valueGetter,
9421
+ // In diff mode the diff `columns` memo already wrapped renderCell in renderDiffCell (over the enriched
9422
+ // combined value) — keep that wrapper, or an EXPLICIT combine's `!explicit` short-circuit would strip the
9423
+ // diff arrows / old→new styling (#369 review). Declarative diff already preserved it (c.renderCell truthy).
9424
+ renderCell: isDiff ? c.renderCell : !explicit && c.renderCell || (useJoin ? ((value, row) => renderCombined(srcCols, row, cfg)) : void 0)
9422
9425
  };
9423
9426
  }
9424
9427
  return out;
@@ -9783,7 +9786,7 @@ function Datatable({
9783
9786
  }, [rowGroupingKey]);
9784
9787
  const AUTO_CHROME = 74;
9785
9788
  const autoWidth = (c) => {
9786
- const label = typeof c.headerName === "string" ? c.headerName : String(c.field ?? "");
9789
+ const label = colLabel(c);
9787
9790
  return AUTO_CHROME + Math.ceil(label.length * 8);
9788
9791
  };
9789
9792
  const clampWidth = (w, c) => {
@@ -9907,6 +9910,7 @@ function Datatable({
9907
9910
  };
9908
9911
  }, [exportOpen]);
9909
9912
  const colByField = React51__default.useMemo(() => Object.fromEntries(cols.map((c) => [c.field, c])), [cols]);
9913
+ const fieldLabel = (f) => colLabel(colByField[f] || { field: f });
9910
9914
  const combineSources = React51__default.useMemo(() => {
9911
9915
  const s = /* @__PURE__ */ new Set();
9912
9916
  for (const cfg of Object.values(userCombine)) (cfg && cfg.fields ? cfg.fields : []).slice(1).forEach((f) => s.add(f));
@@ -10067,7 +10071,7 @@ function Datatable({
10067
10071
  const v = computeAgg({ ...c, aggregation: agg }, rowsIn);
10068
10072
  if (v == null) continue;
10069
10073
  const disp = c.aggregationFormatter ? c.aggregationFormatter(v) : c.valueFormatter ? c.valueFormatter(v, null) : typeof v === "number" ? v.toLocaleString() : v;
10070
- parts.push(`${c.headerName} ${disp}`);
10074
+ parts.push(`${colLabel(c)} ${disp}`);
10071
10075
  }
10072
10076
  return parts;
10073
10077
  }
@@ -10420,7 +10424,7 @@ function Datatable({
10420
10424
  next.splice(dir > 0 ? b + 1 : b, 0, field);
10421
10425
  return next;
10422
10426
  });
10423
- const label = colByField[field]?.headerName || field;
10427
+ const label = fieldLabel(field);
10424
10428
  setReorderMsg(`Moved ${label} ${dir < 0 ? "left" : "right"}.`);
10425
10429
  }
10426
10430
  function optionsForField(field) {
@@ -10527,7 +10531,7 @@ function Datatable({
10527
10531
  const rowXml = (cells, r2) => `<row r="${r2}">${cells.map((v, ci) => cell(`${colLetter(ci)}${r2}`, v)).join("")}</row>`;
10528
10532
  const lastCell = `${expCols.length ? colLetter(expCols.length - 1) : "A"}${source.length + 1}`;
10529
10533
  const sheet = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
10530
- <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>";
10534
+ <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>";
10531
10535
  download(xlsxPackage(sheet), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "xlsx");
10532
10536
  return;
10533
10537
  }
@@ -10535,7 +10539,7 @@ function Datatable({
10535
10539
  const s = defang(v, v == null ? "" : String(v));
10536
10540
  return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
10537
10541
  };
10538
- const header = expCols.map((c) => escape(c.headerName)).join(",");
10542
+ const header = expCols.map((c) => escape(colLabel(c))).join(",");
10539
10543
  const lines = source.map((row) => expCols.map((c) => escape(cellValue(c, row))).join(","));
10540
10544
  const text = "\uFEFF" + [header, ...lines].join("\r\n");
10541
10545
  download(text, "text/csv;charset=utf-8;", "csv");
@@ -11072,7 +11076,7 @@ function Datatable({
11072
11076
  const widest = (labels) => labels.reduce((m, l) => Math.max(m, ctx.measureText(String(l)).width), 0);
11073
11077
  const logicW = Math.min(180, Math.max(84, Math.ceil(widest(["And", "Or"]) + chrome)));
11074
11078
  const colCap = Math.max(118, Math.min(210, el.clientWidth - logicW - 118 - 30 - 30 - 140 - 5 * 6 - 2 * 4));
11075
- const colW = Math.min(colCap, Math.max(118, Math.ceil(widest(filterableCols.map((c) => c.headerName ?? c.field)) + chrome)));
11079
+ const colW = Math.min(colCap, Math.max(118, Math.ceil(widest(filterableCols.map((c) => colLabel(c))) + chrome)));
11076
11080
  const opW = Math.min(170, Math.max(118, Math.ceil(widest(ALL_OP_LABELS) + chrome)));
11077
11081
  if (Number.isFinite(logicW)) el.style.setProperty("--twc-dt-flogic-fit", `${logicW}px`);
11078
11082
  if (Number.isFinite(colW)) el.style.setProperty("--twc-dt-fcol-fit", `${colW}px`);
@@ -11435,7 +11439,7 @@ function Datatable({
11435
11439
  const i = order.indexOf(f);
11436
11440
  return i === -1 ? 9999 : i;
11437
11441
  };
11438
- const shownColRows = cols.filter((c) => c.field !== "__pinactions__" && c.headerName.toLowerCase().includes(colQuery.trim().toLowerCase())).sort((a, b) => orderIdxOf(a.field) - orderIdxOf(b.field));
11442
+ const shownColRows = cols.filter((c) => c.field !== "__pinactions__" && colLabel(c).toLowerCase().includes(colQuery.trim().toLowerCase())).sort((a, b) => orderIdxOf(a.field) - orderIdxOf(b.field));
11439
11443
  const rowNumMatch = rowNumbers && "row number".includes(colQuery.trim().toLowerCase());
11440
11444
  const manageableCols = cols.filter((c) => c.field !== "__pinactions__");
11441
11445
  const visibleColCount = manageableCols.filter((c) => !effectiveHidden.has(c.field)).length;
@@ -11455,7 +11459,7 @@ function Datatable({
11455
11459
  children: [
11456
11460
  /* @__PURE__ */ jsx("span", { className: "twc-dt__group-chev", "data-open": !item.collapsed || void 0, children: /* @__PURE__ */ jsx(Svg, { d: I.chevDown }) }),
11457
11461
  /* @__PURE__ */ jsxs("span", { className: "twc-dt__group-name", children: [
11458
- colByField[item.field]?.headerName || item.field,
11462
+ fieldLabel(item.field),
11459
11463
  ":"
11460
11464
  ] }),
11461
11465
  /* @__PURE__ */ jsx("span", { className: "twc-dt__group-val", children: String(item.value) }),
@@ -11677,8 +11681,8 @@ function Datatable({
11677
11681
  const f = v.valueFormatter || col?.valueFormatter;
11678
11682
  return f ? f(val, null) : typeof val === "number" ? val.toLocaleString() : val;
11679
11683
  };
11680
- const vlabel = (v) => v.label || (colByField[v.field]?.headerName || v.field);
11681
- const rowFieldLabel = rFields.map((f) => colByField[f]?.headerName || f).join(" / ");
11684
+ const vlabel = (v) => v.label || fieldLabel(v.field);
11685
+ const rowFieldLabel = rFields.map((f) => fieldLabel(f)).join(" / ");
11682
11686
  const leafPaths = [];
11683
11687
  const seen2 = /* @__PURE__ */ new Set();
11684
11688
  for (const r2 of rows) {
@@ -11973,8 +11977,8 @@ function Datatable({
11973
11977
  /* @__PURE__ */ jsx(Svg, { d: I.group }),
11974
11978
  /* @__PURE__ */ jsx("span", { className: "twc-dt__groupbar-label", children: "Grouped by" }),
11975
11979
  activeGroupBy.map((f) => /* @__PURE__ */ jsxs("span", { className: "twc-dt__groupchip", children: [
11976
- colByField[f]?.headerName || f,
11977
- /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__groupchip-x", "aria-label": `Stop grouping by ${colByField[f]?.headerName || f}`, onClick: () => toggleGroupField(f), children: /* @__PURE__ */ jsx(Svg, { d: I.x }) })
11980
+ fieldLabel(f),
11981
+ /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__groupchip-x", "aria-label": `Stop grouping by ${fieldLabel(f)}`, onClick: () => toggleGroupField(f), children: /* @__PURE__ */ jsx(Svg, { d: I.x }) })
11978
11982
  ] }, f)),
11979
11983
  /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__groupbar-clear", onClick: () => setGroupBy([]), children: "Clear all" })
11980
11984
  ] }) : null,
@@ -12096,8 +12100,8 @@ function Datatable({
12096
12100
  className: "twc-dt__th-label",
12097
12101
  role: c.sortable ? "button" : void 0,
12098
12102
  tabIndex: c.sortable ? 0 : void 0,
12099
- "data-ovtext": typeof c.headerName === "string" ? c.headerName : void 0,
12100
- "aria-label": c.sortable ? `${c.headerName}, sort` : void 0,
12103
+ "data-ovtext": !c.renderHeader && typeof c.headerName === "string" ? c.headerName : void 0,
12104
+ "aria-label": c.sortable ? `${colLabel(c)}, sort` : void 0,
12101
12105
  draggable: reorderable || void 0,
12102
12106
  onDragStart: reorderable ? (e) => {
12103
12107
  setDrag({ from: c.field, over: null, after: false });
@@ -12115,7 +12119,7 @@ function Datatable({
12115
12119
  children: [
12116
12120
  reorderable ? /* @__PURE__ */ jsx("span", { className: "twc-dt__grip", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Svg, { d: I.grip }) }) : null,
12117
12121
  filteredFields.has(c.field) ? /* @__PURE__ */ jsx("span", { className: "twc-dt__filterdot" }) : null,
12118
- c.headerName,
12122
+ c.renderHeader ? c.renderHeader({ column: c }) : c.headerName,
12119
12123
  c.sortable ? /* @__PURE__ */ jsx("span", { className: "twc-dt__sort", children: /* @__PURE__ */ jsx(Svg, { d: I.arrow }) }) : null
12120
12124
  ]
12121
12125
  }
@@ -12151,7 +12155,7 @@ function Datatable({
12151
12155
  "data-active": resizing || void 0,
12152
12156
  role: "separator",
12153
12157
  "aria-orientation": "vertical",
12154
- "aria-label": `Resize ${c.headerName} column (double-click to fit content)`,
12158
+ "aria-label": `Resize ${colLabel(c)} column (double-click to fit content)`,
12155
12159
  "aria-valuenow": w,
12156
12160
  "aria-valuemin": 72,
12157
12161
  tabIndex: 0,
@@ -12326,15 +12330,15 @@ function Datatable({
12326
12330
  placeholder: "Add a column\u2026",
12327
12331
  value: "",
12328
12332
  "aria-label": "Add a column to edit",
12329
- options: unpicked.map((c) => ({ value: c.field, label: String(c.headerName ?? c.field) })),
12333
+ options: unpicked.map((c) => ({ value: c.field, label: colLabel(c) })),
12330
12334
  onChange: addField
12331
12335
  }
12332
12336
  ) }) : null,
12333
12337
  /* @__PURE__ */ jsx("div", { className: "twc-dt__cfg-list", children: pickedCols.length === 0 ? /* @__PURE__ */ jsx("div", { className: "twc-dt__be-empty", children: "Pick a column to set its value on all selected rows." }) : pickedCols.map((c, i) => {
12334
12338
  const opts = c.valueOptions ? c.valueOptions.map((o) => typeof o === "string" ? { value: o, label: o } : o) : null;
12335
12339
  return /* @__PURE__ */ jsxs("div", { className: "twc-dt__be-row", children: [
12336
- /* @__PURE__ */ jsxs("span", { className: "twc-dt__be-name", title: String(c.headerName ?? c.field), children: [
12337
- /* @__PURE__ */ jsx("span", { className: "twc-dt__be-name-txt", children: c.headerName }),
12340
+ /* @__PURE__ */ jsxs("span", { className: "twc-dt__be-name", title: colLabel(c), children: [
12341
+ /* @__PURE__ */ jsx("span", { className: "twc-dt__be-name-txt", children: colLabel(c) }),
12338
12342
  resizableFilters && i === 0 ? /* @__PURE__ */ jsx(
12339
12343
  "span",
12340
12344
  {
@@ -12374,7 +12378,7 @@ function Datatable({
12374
12378
  onChange: (e) => setBatchEdit((b) => ({ ...b, values: { ...b.values, [c.field]: e.target.value } }))
12375
12379
  }
12376
12380
  ) }),
12377
- /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__be-x", "aria-label": `Remove ${String(c.headerName ?? c.field)}`, onClick: () => removeField(c.field), children: /* @__PURE__ */ jsx(Svg, { d: I.x }) })
12381
+ /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__be-x", "aria-label": `Remove ${colLabel(c)}`, onClick: () => removeField(c.field), children: /* @__PURE__ */ jsx(Svg, { d: I.x }) })
12378
12382
  ] }, c.field);
12379
12383
  }) }),
12380
12384
  /* @__PURE__ */ jsxs("div", { className: "twc-dt__cfg-foot", children: [
@@ -12646,7 +12650,7 @@ function Datatable({
12646
12650
  children: [
12647
12651
  canDrag ? /* @__PURE__ */ jsx("span", { className: "twc-dt__col-grip", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Svg, { d: I.grip }) }) : null,
12648
12652
  /* @__PURE__ */ jsxs("span", { className: "twc-dt__col-name", children: [
12649
- c.headerName,
12653
+ colLabel(c),
12650
12654
  combineSources.has(c.field) ? /* @__PURE__ */ jsx("span", { className: "twc-dt__col-combined", children: " \xB7 combined" }) : null
12651
12655
  ] }),
12652
12656
  c.pinnable && c.type !== "actions" ? (
@@ -12659,7 +12663,7 @@ function Datatable({
12659
12663
  className: "twc-dt__col-pin",
12660
12664
  "data-on": pins.left.includes(c.field) || void 0,
12661
12665
  "aria-pressed": pins.left.includes(c.field),
12662
- "aria-label": `Pin ${c.headerName} to left`,
12666
+ "aria-label": `Pin ${colLabel(c)} to left`,
12663
12667
  title: pins.left.includes(c.field) ? "Unpin" : "Pin to left",
12664
12668
  onClick: () => setPin(c.field, pins.left.includes(c.field) ? null : "left"),
12665
12669
  children: /* @__PURE__ */ jsx(Svg, { d: I.pinL })
@@ -12672,7 +12676,7 @@ function Datatable({
12672
12676
  className: "twc-dt__col-pin",
12673
12677
  "data-on": pins.right.includes(c.field) || void 0,
12674
12678
  "aria-pressed": pins.right.includes(c.field),
12675
- "aria-label": `Pin ${c.headerName} to right`,
12679
+ "aria-label": `Pin ${colLabel(c)} to right`,
12676
12680
  title: pins.right.includes(c.field) ? "Unpin" : "Pin to right",
12677
12681
  onClick: () => setPin(c.field, pins.right.includes(c.field) ? null : "right"),
12678
12682
  children: /* @__PURE__ */ jsx(Svg, { d: I.pin })
@@ -12687,7 +12691,7 @@ function Datatable({
12687
12691
  "data-on": !effectiveHidden.has(c.field) || void 0,
12688
12692
  role: "switch",
12689
12693
  "aria-checked": !effectiveHidden.has(c.field),
12690
- "aria-label": c.headerName,
12694
+ "aria-label": colLabel(c),
12691
12695
  "aria-disabled": !c.hideable || combineSources.has(c.field) || void 0,
12692
12696
  tabIndex: c.hideable && !combineSources.has(c.field) ? 0 : -1,
12693
12697
  onKeyDown: (e) => {
@@ -12711,17 +12715,17 @@ function Datatable({
12711
12715
  const target = colByField[combineTarget];
12712
12716
  const candidates = cols.filter((c) => c.field !== combineTarget && c.type !== "actions" && c.field !== "__pinactions__" && c.hideable !== false && !userCombine[c.field]);
12713
12717
  const toggle = (f) => setCombineDraft((d) => ({ ...d, selected: d.selected.includes(f) ? d.selected.filter((x) => x !== f) : [...d.selected, f] }));
12714
- return /* @__PURE__ */ 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: [
12718
+ return /* @__PURE__ */ 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: [
12715
12719
  /* @__PURE__ */ jsx("div", { className: "twc-dt__panel-head", children: /* @__PURE__ */ jsxs("span", { className: "twc-dt__panel-title", children: [
12716
12720
  "Combine into \u201C",
12717
- target?.headerName || combineTarget,
12721
+ target ? colLabel(target) : combineTarget,
12718
12722
  "\u201D"
12719
12723
  ] }) }),
12720
12724
  /* @__PURE__ */ 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." }),
12721
12725
  /* @__PURE__ */ jsx("div", { className: "twc-dt__col-list", children: candidates.length === 0 ? /* @__PURE__ */ jsx("div", { className: "twc-dt__empty", style: { padding: "18px 12px" }, children: "No other columns" }) : candidates.map((c) => {
12722
12726
  const on = combineDraft.selected.includes(c.field);
12723
12727
  return /* @__PURE__ */ jsxs("div", { className: "twc-dt__col-row", onClick: () => toggle(c.field), children: [
12724
- /* @__PURE__ */ jsx("span", { className: "twc-dt__col-name", children: c.headerName }),
12728
+ /* @__PURE__ */ jsx("span", { className: "twc-dt__col-name", children: colLabel(c) }),
12725
12729
  /* @__PURE__ */ jsx(
12726
12730
  "span",
12727
12731
  {
@@ -12729,7 +12733,7 @@ function Datatable({
12729
12733
  "data-on": on || void 0,
12730
12734
  role: "switch",
12731
12735
  "aria-checked": on,
12732
- "aria-label": c.headerName,
12736
+ "aria-label": colLabel(c),
12733
12737
  tabIndex: 0,
12734
12738
  onKeyDown: (e) => {
12735
12739
  if (e.key === "Enter" || e.key === " ") {
@@ -12812,7 +12816,7 @@ function Datatable({
12812
12816
  const numeric = c.type === "number";
12813
12817
  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" }];
12814
12818
  return /* @__PURE__ */ jsxs("div", { className: "twc-dt__cfg-row", children: [
12815
- /* @__PURE__ */ jsx("span", { className: "twc-dt__cfg-name", children: c.headerName }),
12819
+ /* @__PURE__ */ jsx("span", { className: "twc-dt__cfg-name", children: colLabel(c) }),
12816
12820
  /* @__PURE__ */ jsx("div", { className: "twc-dt__cfg-ctl", children: /* @__PURE__ */ jsx(
12817
12821
  Select,
12818
12822
  {
@@ -12836,9 +12840,9 @@ function Datatable({
12836
12840
  popGrip("agg")
12837
12841
  ] }) : null,
12838
12842
  panel === "pivot" && panelPos ? (() => {
12839
- const fieldOpts = ordered.filter((c) => c.type !== "actions").map((c) => ({ value: c.field, label: c.headerName }));
12843
+ const fieldOpts = ordered.filter((c) => c.type !== "actions").map((c) => ({ value: c.field, label: colLabel(c) }));
12840
12844
  const aggOpts = [{ value: "sum", label: "Sum" }, { value: "avg", label: "Avg" }, { value: "min", label: "Min" }, { value: "max", label: "Max" }, { value: "count", label: "Count" }];
12841
- const valueFieldOpts = ordered.filter((c) => c.type !== "actions" && !pivotConfig.values.some((v) => v.field === c.field)).map((c) => ({ value: c.field, label: c.headerName }));
12845
+ const valueFieldOpts = ordered.filter((c) => c.type !== "actions" && !pivotConfig.values.some((v) => v.field === c.field)).map((c) => ({ value: c.field, label: colLabel(c) }));
12842
12846
  return /* @__PURE__ */ 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: [
12843
12847
  /* @__PURE__ */ jsxs("div", { className: "twc-dt__panel-head", children: [
12844
12848
  /* @__PURE__ */ jsx("span", { className: "twc-dt__panel-title", children: "Pivot" }),
@@ -12907,7 +12911,7 @@ function Datatable({
12907
12911
  /* @__PURE__ */ jsxs("div", { className: "twc-dt__cfg-section", children: [
12908
12912
  /* @__PURE__ */ jsx("span", { className: "twc-dt__cfg-label", children: "Values" }),
12909
12913
  pivotConfig.values.map((v, i) => /* @__PURE__ */ jsxs("div", { className: "twc-dt__cfg-row", children: [
12910
- /* @__PURE__ */ jsx("span", { className: "twc-dt__cfg-name", children: colByField[v.field]?.headerName || v.field }),
12914
+ /* @__PURE__ */ jsx("span", { className: "twc-dt__cfg-name", children: fieldLabel(v.field) }),
12911
12915
  /* @__PURE__ */ jsx("div", { className: "twc-dt__cfg-ctl", children: /* @__PURE__ */ jsx(
12912
12916
  Select,
12913
12917
  {
@@ -12923,7 +12927,7 @@ function Datatable({
12923
12927
  {
12924
12928
  type: "button",
12925
12929
  className: "twc-dt__cfg-x",
12926
- "aria-label": `Remove ${colByField[v.field]?.headerName || v.field}`,
12930
+ "aria-label": `Remove ${fieldLabel(v.field)}`,
12927
12931
  onClick: () => setPivotConfig((p) => ({ ...p, values: p.values.filter((_, j) => j !== i) })),
12928
12932
  children: /* @__PURE__ */ jsx(Svg, { d: I.x })
12929
12933
  }
@@ -13005,7 +13009,7 @@ function Datatable({
13005
13009
  size: "sm",
13006
13010
  portal: true,
13007
13011
  value: f.field,
13008
- options: filterableCols.map((c) => ({ value: c.field, label: c.headerName })),
13012
+ options: filterableCols.map((c) => ({ value: c.field, label: colLabel(c) })),
13009
13013
  onChange: (v) => {
13010
13014
  const nc = colByField[v];
13011
13015
  setFilters((arr) => arr.map((x) => x.id === f.id ? { ...x, field: v, op: opsFor(filterTypeOf(nc))[0].value, value: "" } : x));
@@ -13062,7 +13066,7 @@ function Datatable({
13062
13066
  ),
13063
13067
  fieldHandle("val", i)
13064
13068
  ] }),
13065
- /* @__PURE__ */ 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__ */ jsx(Svg, { d: I.plus }) }),
13069
+ /* @__PURE__ */ 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__ */ jsx(Svg, { d: I.plus }) }),
13066
13070
  /* @__PURE__ */ 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__ */ jsx(Svg, { d: I.x }) })
13067
13071
  ] }, f.id);
13068
13072
  }) }),