twico-ui 1.31.1 → 1.32.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 +15 -0
- package/dist/index.cjs +365 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.mjs +365 -47
- package/dist/index.mjs.map +1 -1
- package/llms.txt +5 -0
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -8432,7 +8432,13 @@ var DT_CSS = `
|
|
|
8432
8432
|
/* #244: batch editor = pick columns (searchable), then set a value for each. */
|
|
8433
8433
|
.twc-dt__be-add { padding: 6px 6px 8px; border-bottom: var(--border-thin) solid var(--color-divider); }
|
|
8434
8434
|
.twc-dt__be-row { display: flex; align-items: center; gap: 8px; padding: 5px 6px; }
|
|
8435
|
-
|
|
8435
|
+
/* #341: cap width at min(260, row \u2212 160px) so the value control keeps ~120px (+ gaps + remove) and never
|
|
8436
|
+
collapses \u2014 panel-width-aware in pure CSS, so it also grows if the (resizable) panel is widened. */
|
|
8437
|
+
.twc-dt__be-name { position: relative; flex: none; width: clamp(88px, var(--twc-dt-be-name-usr, 108px), min(260px, 100% - 160px)); font-size: var(--text-sm); color: var(--color-text); }
|
|
8438
|
+
/* #341: ellipsis lives on the inner text span so the outer field can host the (edge-overhanging) resize handle without clipping it. */
|
|
8439
|
+
.twc-dt__be-name-txt { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
8440
|
+
/* #341: reveal the batch-name resize handle (reused .twc-dt__f-rz) on row hover, like the filter fields. */
|
|
8441
|
+
.twc-dt__be-row:hover .twc-dt__f-rz { opacity: 1; }
|
|
8436
8442
|
.twc-dt__be-ctl { flex: 1; min-width: 0; }
|
|
8437
8443
|
.twc-dt__be-x { flex: none; display: inline-grid; place-items: center; width: 24px; height: 24px; padding: 0; border: none;
|
|
8438
8444
|
background: transparent; color: var(--color-text-subtle); cursor: pointer; border-radius: var(--radius-sm);
|
|
@@ -8497,6 +8503,19 @@ var DT_CSS = `
|
|
|
8497
8503
|
clipping to one line. height stays a per-row minimum, so single-line cells are unchanged. */
|
|
8498
8504
|
.twc-dt__td[data-wrap="true"] { white-space: normal; overflow: hidden; text-overflow: clip;
|
|
8499
8505
|
word-break: break-word; overflow-wrap: anywhere; vertical-align: top; padding-block: 10px; line-height: 1.45; }
|
|
8506
|
+
/* #338: "combined" column cell \u2014 one column showing several source columns' values. */
|
|
8507
|
+
.twc-dt__combine--stack { display: flex; flex-direction: column; gap: 1px; }
|
|
8508
|
+
.twc-dt__combine-sep { color: var(--color-text-subtle); padding-inline: 3px; }
|
|
8509
|
+
.twc-dt__combine-label { color: var(--color-text-muted); font-weight: var(--font-medium); }
|
|
8510
|
+
/* #339: the runtime combine-columns editor panel. */
|
|
8511
|
+
.twc-dt__combine-hint { padding: 2px 12px 8px; font-size: var(--text-xs); color: var(--color-text-muted); }
|
|
8512
|
+
.twc-dt__combine-opts { padding: 8px 12px; border-top: var(--border-thin) solid var(--color-divider); display: flex; flex-direction: column; gap: 8px; }
|
|
8513
|
+
.twc-dt__combine-opt { display: flex; align-items: center; justify-content: space-between; gap: 10px; font-size: var(--text-sm); color: var(--color-text); }
|
|
8514
|
+
.twc-dt__combine-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 8px 12px; border-top: var(--border-thin) solid var(--color-divider); }
|
|
8515
|
+
.twc-dt__combine-apply { border: none; background: var(--color-primary); color: var(--color-primary-fg); font-family: inherit; font-size: var(--text-sm); font-weight: var(--font-semibold); padding: 6px 14px; border-radius: var(--radius-md); cursor: pointer; }
|
|
8516
|
+
.twc-dt__combine-apply:hover { opacity: 0.9; }
|
|
8517
|
+
.twc-dt__combine-apply:focus-visible { outline: none; box-shadow: var(--ring); }
|
|
8518
|
+
.twc-dt__col-combined { color: var(--color-text-subtle); font-size: var(--text-xs); font-style: italic; }
|
|
8500
8519
|
.twc-dt__td[data-num="true"] { text-align: end; font-variant-numeric: tabular-nums; }
|
|
8501
8520
|
/* Auto row-number gutter (rowNumbers) \u2014 a sticky-left ordinal column. */
|
|
8502
8521
|
.twc-dt__rownum { text-align: end; font-variant-numeric: tabular-nums; color: var(--color-text-subtle);
|
|
@@ -8831,6 +8850,34 @@ function mergeColOrder(saved, propFields) {
|
|
|
8831
8850
|
return result;
|
|
8832
8851
|
}
|
|
8833
8852
|
var getColVal = (col, row) => col && col.valueGetter ? col.valueGetter(row) : row == null ? void 0 : row[col && col.field];
|
|
8853
|
+
function combineCfg(combine) {
|
|
8854
|
+
if (!combine) return null;
|
|
8855
|
+
const cfg = Array.isArray(combine) ? { fields: combine } : combine;
|
|
8856
|
+
const fields = Array.isArray(cfg.fields) ? cfg.fields.filter((f) => f != null) : [];
|
|
8857
|
+
if (!fields.length) return null;
|
|
8858
|
+
return { fields, separator: cfg.separator != null ? cfg.separator : " \xB7 ", labels: !!cfg.labels, layout: cfg.layout === "stack" ? "stack" : "inline" };
|
|
8859
|
+
}
|
|
8860
|
+
var combineSrcCols = (cfg, byField) => cfg.fields.map((f) => byField && byField[f] || { field: f, headerName: String(f) });
|
|
8861
|
+
var combineValueGetter = (srcCols, cfg) => (row) => srcCols.map((sc) => {
|
|
8862
|
+
const v = getColVal(sc, row);
|
|
8863
|
+
const s = v == null ? "" : String(v);
|
|
8864
|
+
return cfg.labels && s ? `${sc.headerName ?? sc.field}: ${s}` : s;
|
|
8865
|
+
}).filter(Boolean).join(cfg.separator);
|
|
8866
|
+
function renderCombined(srcCols, row, cfg) {
|
|
8867
|
+
const nodes = [];
|
|
8868
|
+
let count = 0;
|
|
8869
|
+
srcCols.forEach((sc, idx) => {
|
|
8870
|
+
const v = getColVal(sc, row);
|
|
8871
|
+
if (v == null || v === "") return;
|
|
8872
|
+
const disp = sc.valueFormatter ? sc.valueFormatter(v, row) : v;
|
|
8873
|
+
const label = cfg.labels ? React51__default.createElement("span", { className: "twc-dt__combine-label" }, (sc.headerName ?? sc.field) + ": ") : null;
|
|
8874
|
+
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));
|
|
8875
|
+
nodes.push(React51__default.createElement("span", { key: idx, className: "twc-dt__combine-item" }, label, disp));
|
|
8876
|
+
count++;
|
|
8877
|
+
});
|
|
8878
|
+
if (!nodes.length) return "";
|
|
8879
|
+
return React51__default.createElement("span", { className: cfg.layout === "stack" ? "twc-dt__combine twc-dt__combine--stack" : "twc-dt__combine" }, nodes);
|
|
8880
|
+
}
|
|
8834
8881
|
var diffValueNode = (col, v, row) => col.renderCell ? col.renderCell(v, row) : col.valueFormatter ? col.valueFormatter(v, row) : v == null ? "" : v;
|
|
8835
8882
|
function renderDiffCell(col, val, row) {
|
|
8836
8883
|
const meta = row && row.__diffMeta;
|
|
@@ -9211,6 +9258,7 @@ function Datatable({
|
|
|
9211
9258
|
aggregationValues = null,
|
|
9212
9259
|
disableColumnReorder = false,
|
|
9213
9260
|
disableColumnResize = false,
|
|
9261
|
+
columnCombining = false,
|
|
9214
9262
|
emptyMessage,
|
|
9215
9263
|
renderEmpty,
|
|
9216
9264
|
editMode = false,
|
|
@@ -9277,9 +9325,19 @@ function Datatable({
|
|
|
9277
9325
|
if (diffData && onClassifiedRef.current) onClassifiedRef.current(diffData.counts);
|
|
9278
9326
|
}, [diffData]);
|
|
9279
9327
|
const diffRowKeyFn = React51__default.useCallback((r2) => r2.__diffKey, []);
|
|
9328
|
+
const [userCombine, setUserCombine] = React51__default.useState({});
|
|
9280
9329
|
const columns = React51__default.useMemo(
|
|
9281
|
-
() =>
|
|
9282
|
-
|
|
9330
|
+
() => {
|
|
9331
|
+
if (!isDiff) return columnsProp;
|
|
9332
|
+
const byField = {};
|
|
9333
|
+
for (const c of columnsProp) if (c && c.field != null) byField[c.field] = c;
|
|
9334
|
+
return [DIFF_OP_COLUMN, ...columnsProp.map((c) => {
|
|
9335
|
+
const cfg = combineCfg(userCombine[c.field] || c.combine);
|
|
9336
|
+
const base = cfg && !c.valueGetter ? { ...c, valueGetter: combineValueGetter(combineSrcCols(cfg, byField), cfg) } : c;
|
|
9337
|
+
return { ...base, renderCell: (val, row) => renderDiffCell(base, val, row) };
|
|
9338
|
+
})];
|
|
9339
|
+
},
|
|
9340
|
+
[isDiff, columnsProp, userCombine]
|
|
9283
9341
|
);
|
|
9284
9342
|
const rows = React51__default.useMemo(
|
|
9285
9343
|
() => isDiff ? diffData.rows.filter((r2) => !diffOnly || r2.op !== "unchanged").map((r2) => ({ ...r2.to || r2.from, __diffop: r2.op, __diffMeta: r2, __diffKey: r2.key })) : rowsProp,
|
|
@@ -9319,8 +9377,26 @@ function Datatable({
|
|
|
9319
9377
|
getActions: () => []
|
|
9320
9378
|
});
|
|
9321
9379
|
}
|
|
9380
|
+
const byField = {};
|
|
9381
|
+
for (const c of out) if (c.field != null) byField[c.field] = c;
|
|
9382
|
+
for (let i = 0; i < out.length; i++) {
|
|
9383
|
+
const c = out[i];
|
|
9384
|
+
const cfg = combineCfg(userCombine[c.field] || c.combine);
|
|
9385
|
+
if (!cfg) continue;
|
|
9386
|
+
const srcCols = combineSrcCols(cfg, byField);
|
|
9387
|
+
out[i] = {
|
|
9388
|
+
...c,
|
|
9389
|
+
editable: false,
|
|
9390
|
+
// the combined value is synthetic — inline editing would write to a phantom field
|
|
9391
|
+
valueGetter: c.valueGetter || combineValueGetter(srcCols, cfg),
|
|
9392
|
+
// Consumer renderCell wins. If they overrode only valueGetter, fall back to the DEFAULT cell render
|
|
9393
|
+
// (renderCell: undefined) so the cell shows THEIR value — keeping display in sync with what
|
|
9394
|
+
// sort/filter/search/export use — rather than the auto source-join. Otherwise render the combined cell.
|
|
9395
|
+
renderCell: c.renderCell || (c.valueGetter ? void 0 : ((value, row) => renderCombined(srcCols, row, cfg)))
|
|
9396
|
+
};
|
|
9397
|
+
}
|
|
9322
9398
|
return out;
|
|
9323
|
-
}, [columns, rowPinning]);
|
|
9399
|
+
}, [columns, rowPinning, userCombine]);
|
|
9324
9400
|
const _autoKey = React51__default.useRef();
|
|
9325
9401
|
if (!_autoKey.current) _autoKey.current = { map: /* @__PURE__ */ new WeakMap(), n: 0 };
|
|
9326
9402
|
const keyOf = rowKey || ((r2, i) => {
|
|
@@ -9354,6 +9430,42 @@ function Datatable({
|
|
|
9354
9430
|
n.has(field) ? n.delete(field) : n.add(field);
|
|
9355
9431
|
return n;
|
|
9356
9432
|
});
|
|
9433
|
+
const openCombineEditor = (field) => {
|
|
9434
|
+
const existing = userCombine[field];
|
|
9435
|
+
setCombineTarget(field);
|
|
9436
|
+
setCombineDraft({
|
|
9437
|
+
selected: existing ? existing.fields.filter((f) => f !== field) : [],
|
|
9438
|
+
layout: existing && existing.layout === "stack" ? "stack" : "inline",
|
|
9439
|
+
labels: !!(existing && existing.labels)
|
|
9440
|
+
});
|
|
9441
|
+
};
|
|
9442
|
+
const closeCombineEditor = () => {
|
|
9443
|
+
setPanel(null);
|
|
9444
|
+
closePanel();
|
|
9445
|
+
setCombineTarget(null);
|
|
9446
|
+
setCombineDraft(null);
|
|
9447
|
+
restoreTriggerFocus();
|
|
9448
|
+
};
|
|
9449
|
+
const applyCombine = () => {
|
|
9450
|
+
if (!combineTarget || !combineDraft) return;
|
|
9451
|
+
const field = combineTarget;
|
|
9452
|
+
const sources = combineDraft.selected.filter((f) => f !== field);
|
|
9453
|
+
setUserCombine((m) => {
|
|
9454
|
+
const next = { ...m };
|
|
9455
|
+
if (sources.length) next[field] = { fields: [field, ...sources], layout: combineDraft.layout === "stack" ? "stack" : "inline", separator: " \xB7 ", labels: !!combineDraft.labels };
|
|
9456
|
+
else delete next[field];
|
|
9457
|
+
return next;
|
|
9458
|
+
});
|
|
9459
|
+
closeCombineEditor();
|
|
9460
|
+
};
|
|
9461
|
+
const uncombine = (field) => {
|
|
9462
|
+
setUserCombine((m) => {
|
|
9463
|
+
const next = { ...m };
|
|
9464
|
+
delete next[field];
|
|
9465
|
+
return next;
|
|
9466
|
+
});
|
|
9467
|
+
closeCombineEditor();
|
|
9468
|
+
};
|
|
9357
9469
|
const [pins, setPins] = React51__default.useState(() => {
|
|
9358
9470
|
const left = [], right = [];
|
|
9359
9471
|
columns.forEach((c) => {
|
|
@@ -9415,6 +9527,7 @@ function Datatable({
|
|
|
9415
9527
|
const rowFocusRef = React51__default.useRef(null);
|
|
9416
9528
|
const [fWidths, setFWidths] = React51__default.useState({});
|
|
9417
9529
|
const [fPanelSize, setFPanelSize] = React51__default.useState(null);
|
|
9530
|
+
const [batchNameW, setBatchNameW] = React51__default.useState(null);
|
|
9418
9531
|
const [popSizes, setPopSizes] = React51__default.useState({});
|
|
9419
9532
|
const serializeState = () => ({
|
|
9420
9533
|
filters: filters.map(({ id, ...f }) => f),
|
|
@@ -9435,7 +9548,11 @@ function Datatable({
|
|
|
9435
9548
|
filterPanelSize: fPanelSize || void 0,
|
|
9436
9549
|
filterFieldWidths: fWidths.col != null || fWidths.op != null || fWidths.val != null || fWidths.logic != null ? fWidths : void 0,
|
|
9437
9550
|
// #304: additive, optional — user-resized sizes of the other toolbar popovers, keyed by popover id.
|
|
9438
|
-
popoverSizes: Object.keys(popSizes).length ? popSizes : void 0
|
|
9551
|
+
popoverSizes: Object.keys(popSizes).length ? popSizes : void 0,
|
|
9552
|
+
// #339: additive, optional — runtime user-defined combined columns, keyed by target field.
|
|
9553
|
+
columnCombine: Object.keys(userCombine).length ? userCombine : void 0,
|
|
9554
|
+
// #341: additive, optional — user-resized batch-editor column-name field width (px).
|
|
9555
|
+
batchNameWidth: batchNameW != null ? batchNameW : void 0
|
|
9439
9556
|
});
|
|
9440
9557
|
const applyState = (s) => {
|
|
9441
9558
|
if (!s || typeof s !== "object") return;
|
|
@@ -9480,6 +9597,16 @@ function Datatable({
|
|
|
9480
9597
|
}
|
|
9481
9598
|
if (Object.keys(next).length) setPopSizes(next);
|
|
9482
9599
|
}
|
|
9600
|
+
if (s.columnCombine && typeof s.columnCombine === "object") {
|
|
9601
|
+
const uc = {};
|
|
9602
|
+
for (const [f, cfg] of Object.entries(s.columnCombine)) {
|
|
9603
|
+
if (!known.has(f) || !cfg || !Array.isArray(cfg.fields)) continue;
|
|
9604
|
+
const rest2 = cfg.fields.filter((x) => known.has(x) && x !== f);
|
|
9605
|
+
if (rest2.length) uc[f] = { fields: [f, ...rest2], layout: cfg.layout === "stack" ? "stack" : "inline", separator: typeof cfg.separator === "string" ? cfg.separator : " \xB7 ", labels: !!cfg.labels };
|
|
9606
|
+
}
|
|
9607
|
+
if (Object.keys(uc).length) setUserCombine(uc);
|
|
9608
|
+
}
|
|
9609
|
+
if (typeof s.batchNameWidth === "number") setBatchNameW(clampNum(s.batchNameWidth, 88, 260));
|
|
9483
9610
|
};
|
|
9484
9611
|
const stateReadyRef = React51__default.useRef(false);
|
|
9485
9612
|
const stateRestoredRef = React51__default.useRef(false);
|
|
@@ -9497,7 +9624,7 @@ function Datatable({
|
|
|
9497
9624
|
}
|
|
9498
9625
|
}
|
|
9499
9626
|
return void 0;
|
|
9500
|
-
}, [filters, filterLogic, sort, quick, pageVal, sizeVal, order, widths, hidden, pins, density, fWidths, fPanelSize, popSizes, stateKey]);
|
|
9627
|
+
}, [filters, filterLogic, sort, quick, pageVal, sizeVal, order, widths, hidden, pins, density, fWidths, fPanelSize, popSizes, userCombine, batchNameW, stateKey]);
|
|
9501
9628
|
const restoreState = () => {
|
|
9502
9629
|
let saved = null;
|
|
9503
9630
|
if (stateKey) {
|
|
@@ -9638,6 +9765,15 @@ function Datatable({
|
|
|
9638
9765
|
const [menuPos, openMenu, closeMenu] = useFloating();
|
|
9639
9766
|
const [panel, setPanel] = React51__default.useState(null);
|
|
9640
9767
|
const [panelPos, openPanel, closePanel] = useFloating();
|
|
9768
|
+
const [combineTarget, setCombineTarget] = React51__default.useState(null);
|
|
9769
|
+
const [combineDraft, setCombineDraft] = React51__default.useState(null);
|
|
9770
|
+
const combinePanelRef = React51__default.useRef(null);
|
|
9771
|
+
React51__default.useEffect(() => {
|
|
9772
|
+
if (panel === "combine" && combinePanelRef.current) {
|
|
9773
|
+
const el = combinePanelRef.current.querySelector('[role="switch"], button, [tabindex]');
|
|
9774
|
+
(el || combinePanelRef.current).focus?.();
|
|
9775
|
+
}
|
|
9776
|
+
}, [panel]);
|
|
9641
9777
|
const [rowMenu, setRowMenu] = React51__default.useState(null);
|
|
9642
9778
|
const [rowMenuPos, openRowMenu, closeRowMenu] = useFloating();
|
|
9643
9779
|
const [exportOpen, setExportOpen] = React51__default.useState(false);
|
|
@@ -9738,7 +9874,21 @@ function Datatable({
|
|
|
9738
9874
|
};
|
|
9739
9875
|
}, [exportOpen]);
|
|
9740
9876
|
const colByField = React51__default.useMemo(() => Object.fromEntries(cols.map((c) => [c.field, c])), [cols]);
|
|
9741
|
-
const
|
|
9877
|
+
const combineSources = React51__default.useMemo(() => {
|
|
9878
|
+
const s = /* @__PURE__ */ new Set();
|
|
9879
|
+
for (const cfg of Object.values(userCombine)) (cfg && cfg.fields ? cfg.fields : []).slice(1).forEach((f) => s.add(f));
|
|
9880
|
+
return s;
|
|
9881
|
+
}, [userCombine]);
|
|
9882
|
+
const stackCombineTargets = React51__default.useMemo(
|
|
9883
|
+
() => new Set(cols.filter((c) => {
|
|
9884
|
+
const cfg = combineCfg(userCombine[c.field] || c.combine);
|
|
9885
|
+
return cfg && cfg.layout === "stack";
|
|
9886
|
+
}).map((c) => c.field)),
|
|
9887
|
+
[cols, userCombine]
|
|
9888
|
+
);
|
|
9889
|
+
const effectiveHidden = React51__default.useMemo(() => combineSources.size ? /* @__PURE__ */ new Set([...hidden, ...combineSources]) : hidden, [hidden, combineSources]);
|
|
9890
|
+
const effectiveWrapped = React51__default.useMemo(() => stackCombineTargets.size ? /* @__PURE__ */ new Set([...wrapped, ...stackCombineTargets]) : wrapped, [wrapped, stackCombineTargets]);
|
|
9891
|
+
const visibleCols = cols.filter((c) => !effectiveHidden.has(c.field));
|
|
9742
9892
|
const colFieldsKey = JSON.stringify(
|
|
9743
9893
|
cols.filter((c) => typeof c.field === "string" && c.type !== "actions").map((c) => c.field)
|
|
9744
9894
|
);
|
|
@@ -9757,17 +9907,17 @@ function Datatable({
|
|
|
9757
9907
|
const i = order.indexOf(f);
|
|
9758
9908
|
return i === -1 ? 9999 : i;
|
|
9759
9909
|
};
|
|
9760
|
-
const L = pins.left.map((f) => colByField[f]).filter((c) => c && !
|
|
9761
|
-
const R = pins.right.map((f) => colByField[f]).filter((c) => c && !
|
|
9910
|
+
const L = pins.left.map((f) => colByField[f]).filter((c) => c && !effectiveHidden.has(c.field));
|
|
9911
|
+
const R = pins.right.map((f) => colByField[f]).filter((c) => c && !effectiveHidden.has(c.field));
|
|
9762
9912
|
const mid = visibleCols.filter((c) => !pins.left.includes(c.field) && !pins.right.includes(c.field)).sort((a, b) => orderIdx(a.field) - orderIdx(b.field));
|
|
9763
9913
|
return [...L, ...mid, ...R];
|
|
9764
|
-
}, [pins,
|
|
9914
|
+
}, [pins, effectiveHidden, visibleCols, colByField, order]);
|
|
9765
9915
|
const NUM_W = 56;
|
|
9766
9916
|
const CHK_W = checkboxSelection ? rowReorder ? 68 : 44 : 0;
|
|
9767
9917
|
const numLeft = CHK_W;
|
|
9768
9918
|
const leadW = numLeft + (showRowNum ? NUM_W : 0);
|
|
9769
|
-
const visLeft = React51__default.useMemo(() => pins.left.filter((f) => colByField[f] && !
|
|
9770
|
-
const visRight = React51__default.useMemo(() => pins.right.filter((f) => colByField[f] && !
|
|
9919
|
+
const visLeft = React51__default.useMemo(() => pins.left.filter((f) => colByField[f] && !effectiveHidden.has(f)), [pins.left, colByField, effectiveHidden]);
|
|
9920
|
+
const visRight = React51__default.useMemo(() => pins.right.filter((f) => colByField[f] && !effectiveHidden.has(f)), [pins.right, colByField, effectiveHidden]);
|
|
9771
9921
|
const stickyOf = (field) => {
|
|
9772
9922
|
if (visLeft.includes(field)) {
|
|
9773
9923
|
let off = leadW;
|
|
@@ -10932,6 +11082,54 @@ function Datatable({
|
|
|
10932
11082
|
if (field === "val") p.removeAttribute("data-val-fixed");
|
|
10933
11083
|
}
|
|
10934
11084
|
};
|
|
11085
|
+
const BE_NAME_MIN = 88, BE_NAME_MAX = 260;
|
|
11086
|
+
const startBeNameResize = (e) => {
|
|
11087
|
+
if (e.button != null && e.button !== 0) return;
|
|
11088
|
+
e.preventDefault();
|
|
11089
|
+
e.stopPropagation();
|
|
11090
|
+
const handle = e.currentTarget;
|
|
11091
|
+
const panel2 = handle.closest(".twc-dt__cfg"), nameEl = handle.closest(".twc-dt__be-name");
|
|
11092
|
+
if (!panel2 || !nameEl) return;
|
|
11093
|
+
const startX = e.clientX, startW = nameEl.getBoundingClientRect().width;
|
|
11094
|
+
const dir = getComputedStyle(panel2).direction === "rtl" ? -1 : 1;
|
|
11095
|
+
handle.setAttribute("data-active", "true");
|
|
11096
|
+
let last = startW;
|
|
11097
|
+
const onMove = (ev) => {
|
|
11098
|
+
last = clampNum(startW + (ev.clientX - startX) * dir, BE_NAME_MIN, BE_NAME_MAX);
|
|
11099
|
+
panel2.style.setProperty("--twc-dt-be-name-usr", `${last}px`);
|
|
11100
|
+
};
|
|
11101
|
+
const onUp = () => {
|
|
11102
|
+
setBatchNameW(last);
|
|
11103
|
+
handle.removeAttribute("data-active");
|
|
11104
|
+
window.removeEventListener("pointermove", onMove);
|
|
11105
|
+
window.removeEventListener("pointerup", onUp);
|
|
11106
|
+
};
|
|
11107
|
+
window.addEventListener("pointermove", onMove);
|
|
11108
|
+
window.addEventListener("pointerup", onUp);
|
|
11109
|
+
};
|
|
11110
|
+
const onBeNameResizeKey = (e) => {
|
|
11111
|
+
const panel2 = e.currentTarget.closest(".twc-dt__cfg");
|
|
11112
|
+
if (e.key === "Enter" || e.key === " " || e.key === "Backspace") {
|
|
11113
|
+
e.preventDefault();
|
|
11114
|
+
e.stopPropagation();
|
|
11115
|
+
setBatchNameW(null);
|
|
11116
|
+
if (panel2) panel2.style.removeProperty("--twc-dt-be-name-usr");
|
|
11117
|
+
return;
|
|
11118
|
+
}
|
|
11119
|
+
if (!["ArrowLeft", "ArrowRight", "Home", "End"].includes(e.key)) return;
|
|
11120
|
+
e.preventDefault();
|
|
11121
|
+
e.stopPropagation();
|
|
11122
|
+
const nameEl = e.currentTarget.closest(".twc-dt__be-name");
|
|
11123
|
+
const cur = nameEl ? nameEl.getBoundingClientRect().width : batchNameW ?? 108;
|
|
11124
|
+
const dir = panel2 && getComputedStyle(panel2).direction === "rtl" ? -1 : 1;
|
|
11125
|
+
const step = e.shiftKey ? 2 : 10;
|
|
11126
|
+
let next = cur;
|
|
11127
|
+
if (e.key === "ArrowRight") next = cur + step * dir;
|
|
11128
|
+
else if (e.key === "ArrowLeft") next = cur - step * dir;
|
|
11129
|
+
else if (e.key === "Home") next = BE_NAME_MIN;
|
|
11130
|
+
else if (e.key === "End") next = BE_NAME_MAX;
|
|
11131
|
+
setBatchNameW(clampNum(next, BE_NAME_MIN, BE_NAME_MAX));
|
|
11132
|
+
};
|
|
10935
11133
|
const startPanelResize = (e) => {
|
|
10936
11134
|
if (e.button != null && e.button !== 0) return;
|
|
10937
11135
|
e.preventDefault();
|
|
@@ -11154,7 +11352,7 @@ function Datatable({
|
|
|
11154
11352
|
const shownColRows = cols.filter((c) => c.field !== "__pinactions__" && c.headerName.toLowerCase().includes(colQuery.trim().toLowerCase())).sort((a, b) => orderIdxOf(a.field) - orderIdxOf(b.field));
|
|
11155
11353
|
const rowNumMatch = rowNumbers && "row number".includes(colQuery.trim().toLowerCase());
|
|
11156
11354
|
const manageableCols = cols.filter((c) => c.field !== "__pinactions__");
|
|
11157
|
-
const visibleColCount = manageableCols.filter((c) => !
|
|
11355
|
+
const visibleColCount = manageableCols.filter((c) => !effectiveHidden.has(c.field)).length;
|
|
11158
11356
|
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) }));
|
|
11159
11357
|
const totalCols = ordered.length + (checkboxSelection ? 1 : 0) + (showRowNum ? 1 : 0);
|
|
11160
11358
|
function renderGroupRow(item) {
|
|
@@ -11312,7 +11510,7 @@ function Datatable({
|
|
|
11312
11510
|
"data-cell-active": cellActive || void 0,
|
|
11313
11511
|
"data-cell-selected": cellSelected || void 0,
|
|
11314
11512
|
"data-copied": cellFlash || void 0,
|
|
11315
|
-
"data-wrap":
|
|
11513
|
+
"data-wrap": effectiveWrapped.has(c.field) || void 0,
|
|
11316
11514
|
"data-pin": st.pin,
|
|
11317
11515
|
"data-pin-edge": st.edge,
|
|
11318
11516
|
style: { width: widthOf(c), ...st.style },
|
|
@@ -12009,7 +12207,7 @@ function Datatable({
|
|
|
12009
12207
|
delete values[f];
|
|
12010
12208
|
return { ...b, fields, values };
|
|
12011
12209
|
});
|
|
12012
|
-
return /* @__PURE__ */ jsxs("div", { className: "twc-dt__pop twc-dt__cfg", style: { top: batchEditPos.top, left: batchEditPos.left, width: 320, ...popStyle("batchedit") }, "data-pop-sized": popSizes.batchedit ? "" : void 0, children: [
|
|
12210
|
+
return /* @__PURE__ */ jsxs("div", { className: "twc-dt__pop twc-dt__cfg", style: { top: batchEditPos.top, left: batchEditPos.left, width: 320, "--twc-dt-be-name-usr": batchNameW != null ? `${batchNameW}px` : void 0, ...popStyle("batchedit") }, "data-pop-sized": popSizes.batchedit ? "" : void 0, children: [
|
|
12013
12211
|
/* @__PURE__ */ jsx(Caret, { pos: batchEditPos }),
|
|
12014
12212
|
/* @__PURE__ */ jsxs("div", { className: "twc-dt__cfg-head", children: [
|
|
12015
12213
|
"Edit ",
|
|
@@ -12030,10 +12228,25 @@ function Datatable({
|
|
|
12030
12228
|
onChange: addField
|
|
12031
12229
|
}
|
|
12032
12230
|
) }) : null,
|
|
12033
|
-
/* @__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) => {
|
|
12231
|
+
/* @__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) => {
|
|
12034
12232
|
const opts = c.valueOptions ? c.valueOptions.map((o) => typeof o === "string" ? { value: o, label: o } : o) : null;
|
|
12035
12233
|
return /* @__PURE__ */ jsxs("div", { className: "twc-dt__be-row", children: [
|
|
12036
|
-
/* @__PURE__ */
|
|
12234
|
+
/* @__PURE__ */ jsxs("span", { className: "twc-dt__be-name", title: String(c.headerName ?? c.field), children: [
|
|
12235
|
+
/* @__PURE__ */ jsx("span", { className: "twc-dt__be-name-txt", children: c.headerName }),
|
|
12236
|
+
resizableFilters && i === 0 ? /* @__PURE__ */ jsx(
|
|
12237
|
+
"span",
|
|
12238
|
+
{
|
|
12239
|
+
className: "twc-dt__f-rz",
|
|
12240
|
+
role: "separator",
|
|
12241
|
+
"aria-orientation": "vertical",
|
|
12242
|
+
tabIndex: 0,
|
|
12243
|
+
"aria-label": "Resize column name field (Enter to reset)",
|
|
12244
|
+
onPointerDown: startBeNameResize,
|
|
12245
|
+
onClick: (e) => e.stopPropagation(),
|
|
12246
|
+
onKeyDown: onBeNameResizeKey
|
|
12247
|
+
}
|
|
12248
|
+
) : null
|
|
12249
|
+
] }),
|
|
12037
12250
|
/* @__PURE__ */ jsx("div", { className: "twc-dt__be-ctl", children: c.renderBatchEditCell ? c.renderBatchEditCell({
|
|
12038
12251
|
value: batchEdit.values[c.field],
|
|
12039
12252
|
field: c.field,
|
|
@@ -12148,6 +12361,18 @@ function Datatable({
|
|
|
12148
12361
|
" ",
|
|
12149
12362
|
groupBy.includes(c.field) ? "Stop grouping" : "Group by this column"
|
|
12150
12363
|
] }) : null,
|
|
12364
|
+
columnCombining && c.type !== "actions" ? /* @__PURE__ */ jsxs("button", { type: "button", role: "menuitem", className: "twc-dt__mi", "data-active": !!userCombine[c.field] || void 0, onClick: () => {
|
|
12365
|
+
const anchor = menuTriggerRef.current;
|
|
12366
|
+
setColMenu(null);
|
|
12367
|
+
closeMenu();
|
|
12368
|
+
openCombineEditor(c.field);
|
|
12369
|
+
setPanel("combine");
|
|
12370
|
+
openPanel(anchor, "right", 300);
|
|
12371
|
+
}, children: [
|
|
12372
|
+
/* @__PURE__ */ jsx(Svg, { d: I.columns }),
|
|
12373
|
+
" ",
|
|
12374
|
+
userCombine[c.field] ? "Edit combined column\u2026" : "Combine columns\u2026"
|
|
12375
|
+
] }) : null,
|
|
12151
12376
|
!disableColumnReorder && c.reorderable !== false && c.type !== "actions" && !pins.left.includes(c.field) && !pins.right.includes(c.field) && movableMidFields.length > 1 ? (() => {
|
|
12152
12377
|
const midIdx = movableMidFields.indexOf(c.field);
|
|
12153
12378
|
const atFirst = midIdx === 0;
|
|
@@ -12315,10 +12540,13 @@ function Datatable({
|
|
|
12315
12540
|
e.preventDefault();
|
|
12316
12541
|
onColDrop(c.field);
|
|
12317
12542
|
} : void 0,
|
|
12318
|
-
onClick: () => c.hideable && toggleHiddenField(c.field),
|
|
12543
|
+
onClick: () => c.hideable && !combineSources.has(c.field) && toggleHiddenField(c.field),
|
|
12319
12544
|
children: [
|
|
12320
12545
|
canDrag ? /* @__PURE__ */ jsx("span", { className: "twc-dt__col-grip", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Svg, { d: I.grip }) }) : null,
|
|
12321
|
-
/* @__PURE__ */
|
|
12546
|
+
/* @__PURE__ */ jsxs("span", { className: "twc-dt__col-name", children: [
|
|
12547
|
+
c.headerName,
|
|
12548
|
+
combineSources.has(c.field) ? /* @__PURE__ */ jsx("span", { className: "twc-dt__col-combined", children: " \xB7 combined" }) : null
|
|
12549
|
+
] }),
|
|
12322
12550
|
c.pinnable && c.type !== "actions" ? (
|
|
12323
12551
|
// Pin from here too, so columns scrolled out of view (no reachable header ⋮) can still be pinned.
|
|
12324
12552
|
/* @__PURE__ */ jsxs("span", { className: "twc-dt__col-pins", draggable: false, onClick: (e) => e.stopPropagation(), children: [
|
|
@@ -12354,19 +12582,19 @@ function Datatable({
|
|
|
12354
12582
|
"span",
|
|
12355
12583
|
{
|
|
12356
12584
|
className: "twc-dt__sw",
|
|
12357
|
-
"data-on": !
|
|
12585
|
+
"data-on": !effectiveHidden.has(c.field) || void 0,
|
|
12358
12586
|
role: "switch",
|
|
12359
|
-
"aria-checked": !
|
|
12587
|
+
"aria-checked": !effectiveHidden.has(c.field),
|
|
12360
12588
|
"aria-label": c.headerName,
|
|
12361
|
-
"aria-disabled": !c.hideable || void 0,
|
|
12362
|
-
tabIndex: c.hideable ? 0 : -1,
|
|
12589
|
+
"aria-disabled": !c.hideable || combineSources.has(c.field) || void 0,
|
|
12590
|
+
tabIndex: c.hideable && !combineSources.has(c.field) ? 0 : -1,
|
|
12363
12591
|
onKeyDown: (e) => {
|
|
12364
|
-
if ((e.key === "Enter" || e.key === " ") && c.hideable) {
|
|
12592
|
+
if ((e.key === "Enter" || e.key === " ") && c.hideable && !combineSources.has(c.field)) {
|
|
12365
12593
|
e.preventDefault();
|
|
12366
12594
|
toggleHiddenField(c.field);
|
|
12367
12595
|
}
|
|
12368
12596
|
},
|
|
12369
|
-
style: c.hideable ? void 0 : { opacity: 0.4 }
|
|
12597
|
+
style: c.hideable && !combineSources.has(c.field) ? void 0 : { opacity: 0.4 }
|
|
12370
12598
|
}
|
|
12371
12599
|
)
|
|
12372
12600
|
]
|
|
@@ -12377,6 +12605,82 @@ function Datatable({
|
|
|
12377
12605
|
] }),
|
|
12378
12606
|
popGrip("columns")
|
|
12379
12607
|
] }) : null,
|
|
12608
|
+
panel === "combine" && panelPos && combineTarget && combineDraft ? (() => {
|
|
12609
|
+
const target = colByField[combineTarget];
|
|
12610
|
+
const candidates = cols.filter((c) => c.field !== combineTarget && c.type !== "actions" && c.field !== "__pinactions__" && c.hideable !== false && !userCombine[c.field]);
|
|
12611
|
+
const toggle = (f) => setCombineDraft((d) => ({ ...d, selected: d.selected.includes(f) ? d.selected.filter((x) => x !== f) : [...d.selected, f] }));
|
|
12612
|
+
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: [
|
|
12613
|
+
/* @__PURE__ */ jsx("div", { className: "twc-dt__panel-head", children: /* @__PURE__ */ jsxs("span", { className: "twc-dt__panel-title", children: [
|
|
12614
|
+
"Combine into \u201C",
|
|
12615
|
+
target?.headerName || combineTarget,
|
|
12616
|
+
"\u201D"
|
|
12617
|
+
] }) }),
|
|
12618
|
+
/* @__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." }),
|
|
12619
|
+
/* @__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) => {
|
|
12620
|
+
const on = combineDraft.selected.includes(c.field);
|
|
12621
|
+
return /* @__PURE__ */ jsxs("div", { className: "twc-dt__col-row", onClick: () => toggle(c.field), children: [
|
|
12622
|
+
/* @__PURE__ */ jsx("span", { className: "twc-dt__col-name", children: c.headerName }),
|
|
12623
|
+
/* @__PURE__ */ jsx(
|
|
12624
|
+
"span",
|
|
12625
|
+
{
|
|
12626
|
+
className: "twc-dt__sw",
|
|
12627
|
+
"data-on": on || void 0,
|
|
12628
|
+
role: "switch",
|
|
12629
|
+
"aria-checked": on,
|
|
12630
|
+
"aria-label": c.headerName,
|
|
12631
|
+
tabIndex: 0,
|
|
12632
|
+
onKeyDown: (e) => {
|
|
12633
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
12634
|
+
e.preventDefault();
|
|
12635
|
+
toggle(c.field);
|
|
12636
|
+
}
|
|
12637
|
+
}
|
|
12638
|
+
}
|
|
12639
|
+
)
|
|
12640
|
+
] }, c.field);
|
|
12641
|
+
}) }),
|
|
12642
|
+
/* @__PURE__ */ jsxs("div", { className: "twc-dt__combine-opts", children: [
|
|
12643
|
+
/* @__PURE__ */ jsxs("label", { className: "twc-dt__combine-opt", children: [
|
|
12644
|
+
/* @__PURE__ */ jsx("span", { children: "Layout" }),
|
|
12645
|
+
/* @__PURE__ */ jsx(
|
|
12646
|
+
Select,
|
|
12647
|
+
{
|
|
12648
|
+
size: "sm",
|
|
12649
|
+
portal: true,
|
|
12650
|
+
matchTriggerWidth: false,
|
|
12651
|
+
value: combineDraft.layout,
|
|
12652
|
+
options: [{ value: "inline", label: "Inline" }, { value: "stack", label: "Stacked" }],
|
|
12653
|
+
onChange: (v) => setCombineDraft((d) => ({ ...d, layout: v }))
|
|
12654
|
+
}
|
|
12655
|
+
)
|
|
12656
|
+
] }),
|
|
12657
|
+
/* @__PURE__ */ jsxs("div", { className: "twc-dt__combine-opt", onClick: () => setCombineDraft((d) => ({ ...d, labels: !d.labels })), style: { cursor: "pointer" }, children: [
|
|
12658
|
+
/* @__PURE__ */ jsx("span", { children: "Show labels" }),
|
|
12659
|
+
/* @__PURE__ */ jsx(
|
|
12660
|
+
"span",
|
|
12661
|
+
{
|
|
12662
|
+
className: "twc-dt__sw",
|
|
12663
|
+
"data-on": combineDraft.labels || void 0,
|
|
12664
|
+
role: "switch",
|
|
12665
|
+
"aria-checked": combineDraft.labels,
|
|
12666
|
+
"aria-label": "Show labels",
|
|
12667
|
+
tabIndex: 0,
|
|
12668
|
+
onKeyDown: (e) => {
|
|
12669
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
12670
|
+
e.preventDefault();
|
|
12671
|
+
setCombineDraft((d) => ({ ...d, labels: !d.labels }));
|
|
12672
|
+
}
|
|
12673
|
+
}
|
|
12674
|
+
}
|
|
12675
|
+
)
|
|
12676
|
+
] })
|
|
12677
|
+
] }),
|
|
12678
|
+
/* @__PURE__ */ jsxs("div", { className: "twc-dt__combine-foot", children: [
|
|
12679
|
+
userCombine[combineTarget] ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__link", onClick: () => uncombine(combineTarget), children: "Uncombine" }) : /* @__PURE__ */ jsx("span", {}),
|
|
12680
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__combine-apply", onClick: applyCombine, children: "Apply" })
|
|
12681
|
+
] })
|
|
12682
|
+
] });
|
|
12683
|
+
})() : null,
|
|
12380
12684
|
panel === "agg" && panelPos ? /* @__PURE__ */ jsxs("div", { className: "twc-dt__pop twc-dt__cfg", style: { top: panelPos.top, left: panelPos.left, width: 300, ...popStyle("agg") }, "data-pop-sized": popSizes.agg ? "" : void 0, role: "dialog", "aria-label": "Aggregation settings", children: [
|
|
12381
12685
|
/* @__PURE__ */ jsxs("div", { className: "twc-dt__panel-head", children: [
|
|
12382
12686
|
/* @__PURE__ */ jsx("span", { className: "twc-dt__panel-title", children: "Aggregation" }),
|
|
@@ -15529,6 +15833,8 @@ var ICONBTN_CSS = `
|
|
|
15529
15833
|
.twc-iconbtn:focus-visible { outline: none; box-shadow: var(--ring); }
|
|
15530
15834
|
.twc-iconbtn:active:not(:disabled) { transform: scale(var(--press-scale)); }
|
|
15531
15835
|
.twc-iconbtn:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
15836
|
+
/* #342: disabled state for the anchor form (as="a") \u2014 :disabled doesn't apply to <a>. */
|
|
15837
|
+
.twc-iconbtn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; pointer-events: none; }
|
|
15532
15838
|
.twc-iconbtn svg { width: 1.25em; height: 1.25em; }
|
|
15533
15839
|
|
|
15534
15840
|
/* tone supplies the accent set; variant decides how it's applied \u2014 mirrors Button. Default tone
|
|
@@ -15547,6 +15853,11 @@ var ICONBTN_CSS = `
|
|
|
15547
15853
|
.twc-iconbtn[data-variant="outline"]:hover:not(:disabled) { border-color: var(--_accent); color: var(--_accent); background: var(--color-surface-sunken); }
|
|
15548
15854
|
.twc-iconbtn[data-variant="ghost"]:hover:not(:disabled) { background: var(--color-surface-sunken); color: var(--_accent); }
|
|
15549
15855
|
`;
|
|
15856
|
+
function safeHref6(url) {
|
|
15857
|
+
if (url == null) return void 0;
|
|
15858
|
+
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
15859
|
+
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
15860
|
+
}
|
|
15550
15861
|
function IconButton({
|
|
15551
15862
|
children,
|
|
15552
15863
|
icon,
|
|
@@ -15555,21 +15866,28 @@ function IconButton({
|
|
|
15555
15866
|
size = "md",
|
|
15556
15867
|
round = false,
|
|
15557
15868
|
disabled = false,
|
|
15869
|
+
as = "button",
|
|
15870
|
+
href,
|
|
15558
15871
|
className = "",
|
|
15559
15872
|
"aria-label": ariaLabel,
|
|
15560
15873
|
...rest
|
|
15561
15874
|
}) {
|
|
15562
15875
|
const __twcStyles = useScopedStyles("twc-iconbtn-styles", ICONBTN_CSS);
|
|
15876
|
+
const Tag2 = as;
|
|
15877
|
+
const inert = Tag2 === "a" && disabled;
|
|
15563
15878
|
return /* @__PURE__ */ jsxs(
|
|
15564
|
-
|
|
15879
|
+
Tag2,
|
|
15565
15880
|
{
|
|
15566
15881
|
className: `twc-iconbtn ${className}`,
|
|
15567
15882
|
"data-variant": variant,
|
|
15568
15883
|
"data-tone": tone,
|
|
15569
15884
|
"data-size": size,
|
|
15570
15885
|
"data-round": round || void 0,
|
|
15571
|
-
disabled,
|
|
15572
|
-
type: "button",
|
|
15886
|
+
disabled: Tag2 === "button" ? disabled : void 0,
|
|
15887
|
+
type: Tag2 === "button" ? "button" : void 0,
|
|
15888
|
+
href: Tag2 === "a" && !inert ? safeHref6(href) : void 0,
|
|
15889
|
+
"aria-disabled": inert || void 0,
|
|
15890
|
+
tabIndex: inert ? -1 : void 0,
|
|
15573
15891
|
"aria-label": ariaLabel,
|
|
15574
15892
|
...rest,
|
|
15575
15893
|
children: [
|
|
@@ -15771,7 +16089,7 @@ var LIST_CSS = `
|
|
|
15771
16089
|
`;
|
|
15772
16090
|
function List({ items, plain = false, emptyMessage, className = "", ...rest }) {
|
|
15773
16091
|
const __twcStyles = useScopedStyles("twc-list-styles", LIST_CSS);
|
|
15774
|
-
const
|
|
16092
|
+
const safeHref14 = (url) => {
|
|
15775
16093
|
if (url == null) return void 0;
|
|
15776
16094
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
15777
16095
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -15783,7 +16101,7 @@ function List({ items, plain = false, emptyMessage, className = "", ...rest }) {
|
|
|
15783
16101
|
/* @__PURE__ */ jsxs("ul", { className: `twc-list ${className}`, role: "list", "data-plain": plain || void 0, ...rest, children: [
|
|
15784
16102
|
__twcStyles,
|
|
15785
16103
|
items.length === 0 ? /* @__PURE__ */ jsx("li", { role: "presentation", style: { display: "contents" }, children: /* @__PURE__ */ jsx("div", { className: "twc-list__empty", children: emptyMessage ?? "Nothing here yet" }) }) : items.map((it, i) => {
|
|
15786
|
-
const href =
|
|
16104
|
+
const href = safeHref14(it.href);
|
|
15787
16105
|
const interactive = Boolean(it.onClick || href);
|
|
15788
16106
|
const Tag2 = href ? "a" : interactive ? "button" : "div";
|
|
15789
16107
|
const content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -15839,7 +16157,7 @@ button.twc-navbar__brand, a.twc-navbar__brand { cursor: pointer; }
|
|
|
15839
16157
|
.twc-navbar__menu-btn { display: inline-grid; }
|
|
15840
16158
|
}
|
|
15841
16159
|
`;
|
|
15842
|
-
function
|
|
16160
|
+
function safeHref7(url) {
|
|
15843
16161
|
if (url == null) return void 0;
|
|
15844
16162
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
15845
16163
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -15862,9 +16180,9 @@ function Navbar({
|
|
|
15862
16180
|
return /* @__PURE__ */ jsxs("header", { className: `twc-navbar ${className}`, "data-sticky": sticky || void 0, ...rest, children: [
|
|
15863
16181
|
__twcStyles,
|
|
15864
16182
|
onMenuClick ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-navbar__menu-btn", "aria-expanded": menuOpen, "aria-controls": menuControls, "aria-label": menuOpen ? "Close menu" : "Open menu", onClick: onMenuClick, children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M4 6h16M4 12h16M4 18h16" }) }) }) : null,
|
|
15865
|
-
brand ? brandHref ? /* @__PURE__ */ jsx("a", { className: "twc-navbar__brand", href:
|
|
16183
|
+
brand ? brandHref ? /* @__PURE__ */ jsx("a", { className: "twc-navbar__brand", href: safeHref7(brandHref), children: brand }) : onBrandClick ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-navbar__brand", onClick: onBrandClick, children: brand }) : /* @__PURE__ */ jsx("span", { className: "twc-navbar__brand", children: brand }) : null,
|
|
15866
16184
|
/* @__PURE__ */ jsx("nav", { className: "twc-navbar__links", "aria-label": navLabel, children: links.map((l, i) => {
|
|
15867
|
-
const href =
|
|
16185
|
+
const href = safeHref7(l.href);
|
|
15868
16186
|
const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
15869
16187
|
l.icon,
|
|
15870
16188
|
l.label
|
|
@@ -16651,13 +16969,13 @@ function Sidebar({
|
|
|
16651
16969
|
document.addEventListener("keydown", onKey);
|
|
16652
16970
|
return () => document.removeEventListener("keydown", onKey);
|
|
16653
16971
|
}, [overlay, open, openProp, onOpenChange]);
|
|
16654
|
-
const
|
|
16972
|
+
const safeHref14 = (url) => {
|
|
16655
16973
|
if (url == null) return void 0;
|
|
16656
16974
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
16657
16975
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
16658
16976
|
};
|
|
16659
16977
|
const renderItem = (it, i) => {
|
|
16660
|
-
const href =
|
|
16978
|
+
const href = safeHref14(it.href);
|
|
16661
16979
|
const labelStr = typeof it.label === "string" ? it.label : void 0;
|
|
16662
16980
|
const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16663
16981
|
it.icon ? /* @__PURE__ */ jsx("span", { className: "twc-sidebar__ic", "aria-hidden": "true", children: it.icon }) : labelStr != null ? /* @__PURE__ */ jsx("span", { className: "twc-sidebar__ic twc-sidebar__ic--initial", "aria-hidden": "true", children: labelStr.charAt(0) }) : null,
|
|
@@ -18371,7 +18689,7 @@ function bgValue(bg) {
|
|
|
18371
18689
|
if (BG[bg]) return `var(${BG[bg]})`;
|
|
18372
18690
|
return String(bg).startsWith("--") ? `var(${bg})` : bg;
|
|
18373
18691
|
}
|
|
18374
|
-
function
|
|
18692
|
+
function safeHref8(url) {
|
|
18375
18693
|
if (url == null) return void 0;
|
|
18376
18694
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
18377
18695
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -18419,7 +18737,7 @@ var Box = React51__default.forwardRef(function Box2({
|
|
|
18419
18737
|
...style,
|
|
18420
18738
|
...flatStyle
|
|
18421
18739
|
};
|
|
18422
|
-
if (Tag2 === "a" && rest.href != null) rest.href =
|
|
18740
|
+
if (Tag2 === "a" && rest.href != null) rest.href = safeHref8(rest.href);
|
|
18423
18741
|
return /* @__PURE__ */ jsxs(Tag2, { ref, className: `twc-box ${className}`.trim(), style: s, "data-twc-sx": sxAttr, ...rest, children: [
|
|
18424
18742
|
styleNode,
|
|
18425
18743
|
children
|
|
@@ -18427,7 +18745,7 @@ var Box = React51__default.forwardRef(function Box2({
|
|
|
18427
18745
|
});
|
|
18428
18746
|
Box.displayName = "Box";
|
|
18429
18747
|
var SIZES = { sm: 640, md: 768, lg: 1024, xl: 1280, full: "100%" };
|
|
18430
|
-
function
|
|
18748
|
+
function safeHref9(url) {
|
|
18431
18749
|
if (url == null) return void 0;
|
|
18432
18750
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
18433
18751
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -18444,7 +18762,7 @@ var Container = React51__default.forwardRef(function Container2({
|
|
|
18444
18762
|
}, ref) {
|
|
18445
18763
|
const { flatStyle, styleNode, sxAttr } = useSx(sx);
|
|
18446
18764
|
const max = SIZES[size] ?? size;
|
|
18447
|
-
if (Tag2 === "a" && rest.href != null) rest.href =
|
|
18765
|
+
if (Tag2 === "a" && rest.href != null) rest.href = safeHref9(rest.href);
|
|
18448
18766
|
return /* @__PURE__ */ jsxs(
|
|
18449
18767
|
Tag2,
|
|
18450
18768
|
{
|
|
@@ -18475,7 +18793,7 @@ function space2(v) {
|
|
|
18475
18793
|
if (typeof v === "number") return `var(--space-${String(v).replace(".", "-")})`;
|
|
18476
18794
|
return v;
|
|
18477
18795
|
}
|
|
18478
|
-
function
|
|
18796
|
+
function safeHref10(url) {
|
|
18479
18797
|
if (url == null) return void 0;
|
|
18480
18798
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
18481
18799
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -18503,7 +18821,7 @@ var Stack = React51__default.forwardRef(function Stack2({
|
|
|
18503
18821
|
...rest
|
|
18504
18822
|
}, ref) {
|
|
18505
18823
|
const { flatStyle, styleNode, sxAttr } = useSx(sx);
|
|
18506
|
-
if (Tag2 === "a" && rest.href != null) rest.href =
|
|
18824
|
+
if (Tag2 === "a" && rest.href != null) rest.href = safeHref10(rest.href);
|
|
18507
18825
|
const kids = divider != null ? React51__default.Children.toArray(children).flatMap((child, i, arr) => i < arr.length - 1 ? [child, /* @__PURE__ */ jsx(React51__default.Fragment, { children: divider }, `twc-stack-div-${i}`)] : [child]) : children;
|
|
18508
18826
|
return /* @__PURE__ */ jsxs(
|
|
18509
18827
|
Tag2,
|
|
@@ -18558,7 +18876,7 @@ var CODE_CSS = `
|
|
|
18558
18876
|
.twc-code__copy:focus-visible { outline: none; box-shadow: var(--ring); }
|
|
18559
18877
|
.twc-code__copy svg { width: 15px; height: 15px; display: block; }
|
|
18560
18878
|
`;
|
|
18561
|
-
function
|
|
18879
|
+
function safeHref11(url) {
|
|
18562
18880
|
if (url == null) return void 0;
|
|
18563
18881
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
18564
18882
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -18575,7 +18893,7 @@ function Code({
|
|
|
18575
18893
|
}) {
|
|
18576
18894
|
const __twcStyles = useScopedStyles("twc-code-styles", CODE_CSS);
|
|
18577
18895
|
const Tag2 = as ?? (block ? "pre" : "code");
|
|
18578
|
-
if (Tag2 === "a" && rest.href != null) rest.href =
|
|
18896
|
+
if (Tag2 === "a" && rest.href != null) rest.href = safeHref11(rest.href);
|
|
18579
18897
|
const rootRef = React51__default.useRef(null);
|
|
18580
18898
|
const [copied, setCopied] = React51__default.useState(false);
|
|
18581
18899
|
const timerRef = React51__default.useRef(null);
|
|
@@ -18600,7 +18918,7 @@ function Code({
|
|
|
18600
18918
|
] });
|
|
18601
18919
|
}
|
|
18602
18920
|
var LEVEL_SIZE = { 1: "4xl", 2: "2xl", 3: "xl", 4: "lg", 5: "base", 6: "sm" };
|
|
18603
|
-
function
|
|
18921
|
+
function safeHref12(url) {
|
|
18604
18922
|
if (url == null) return void 0;
|
|
18605
18923
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
18606
18924
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -18622,7 +18940,7 @@ var Heading = React51__default.forwardRef(function Heading2({
|
|
|
18622
18940
|
const { flatStyle, styleNode, sxAttr } = useSx(sx);
|
|
18623
18941
|
const Tag2 = as || `h${level}`;
|
|
18624
18942
|
const sz = size || (display ? "display" : LEVEL_SIZE[level]) || "2xl";
|
|
18625
|
-
if (Tag2 === "a" && rest.href != null) rest.href =
|
|
18943
|
+
if (Tag2 === "a" && rest.href != null) rest.href = safeHref12(rest.href);
|
|
18626
18944
|
return /* @__PURE__ */ jsxs(
|
|
18627
18945
|
Tag2,
|
|
18628
18946
|
{
|
|
@@ -18669,7 +18987,7 @@ var TONE = {
|
|
|
18669
18987
|
// Adopt the surrounding color (e.g. inside a solid Button/Badge/Alert or a link).
|
|
18670
18988
|
inherit: "inherit"
|
|
18671
18989
|
};
|
|
18672
|
-
function
|
|
18990
|
+
function safeHref13(url) {
|
|
18673
18991
|
if (url == null) return void 0;
|
|
18674
18992
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
18675
18993
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -18689,7 +19007,7 @@ var Text = React51__default.forwardRef(function Text2({
|
|
|
18689
19007
|
...rest
|
|
18690
19008
|
}, ref) {
|
|
18691
19009
|
const { flatStyle, styleNode, sxAttr } = useSx(sx);
|
|
18692
|
-
if (Tag2 === "a" && rest.href != null) rest.href =
|
|
19010
|
+
if (Tag2 === "a" && rest.href != null) rest.href = safeHref13(rest.href);
|
|
18693
19011
|
const toneToken = TONE[tone] || TONE.default;
|
|
18694
19012
|
return /* @__PURE__ */ jsxs(
|
|
18695
19013
|
Tag2,
|