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.cjs
CHANGED
|
@@ -8453,7 +8453,13 @@ var DT_CSS = `
|
|
|
8453
8453
|
/* #244: batch editor = pick columns (searchable), then set a value for each. */
|
|
8454
8454
|
.twc-dt__be-add { padding: 6px 6px 8px; border-bottom: var(--border-thin) solid var(--color-divider); }
|
|
8455
8455
|
.twc-dt__be-row { display: flex; align-items: center; gap: 8px; padding: 5px 6px; }
|
|
8456
|
-
|
|
8456
|
+
/* #341: cap width at min(260, row \u2212 160px) so the value control keeps ~120px (+ gaps + remove) and never
|
|
8457
|
+
collapses \u2014 panel-width-aware in pure CSS, so it also grows if the (resizable) panel is widened. */
|
|
8458
|
+
.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); }
|
|
8459
|
+
/* #341: ellipsis lives on the inner text span so the outer field can host the (edge-overhanging) resize handle without clipping it. */
|
|
8460
|
+
.twc-dt__be-name-txt { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
8461
|
+
/* #341: reveal the batch-name resize handle (reused .twc-dt__f-rz) on row hover, like the filter fields. */
|
|
8462
|
+
.twc-dt__be-row:hover .twc-dt__f-rz { opacity: 1; }
|
|
8457
8463
|
.twc-dt__be-ctl { flex: 1; min-width: 0; }
|
|
8458
8464
|
.twc-dt__be-x { flex: none; display: inline-grid; place-items: center; width: 24px; height: 24px; padding: 0; border: none;
|
|
8459
8465
|
background: transparent; color: var(--color-text-subtle); cursor: pointer; border-radius: var(--radius-sm);
|
|
@@ -8518,6 +8524,19 @@ var DT_CSS = `
|
|
|
8518
8524
|
clipping to one line. height stays a per-row minimum, so single-line cells are unchanged. */
|
|
8519
8525
|
.twc-dt__td[data-wrap="true"] { white-space: normal; overflow: hidden; text-overflow: clip;
|
|
8520
8526
|
word-break: break-word; overflow-wrap: anywhere; vertical-align: top; padding-block: 10px; line-height: 1.45; }
|
|
8527
|
+
/* #338: "combined" column cell \u2014 one column showing several source columns' values. */
|
|
8528
|
+
.twc-dt__combine--stack { display: flex; flex-direction: column; gap: 1px; }
|
|
8529
|
+
.twc-dt__combine-sep { color: var(--color-text-subtle); padding-inline: 3px; }
|
|
8530
|
+
.twc-dt__combine-label { color: var(--color-text-muted); font-weight: var(--font-medium); }
|
|
8531
|
+
/* #339: the runtime combine-columns editor panel. */
|
|
8532
|
+
.twc-dt__combine-hint { padding: 2px 12px 8px; font-size: var(--text-xs); color: var(--color-text-muted); }
|
|
8533
|
+
.twc-dt__combine-opts { padding: 8px 12px; border-top: var(--border-thin) solid var(--color-divider); display: flex; flex-direction: column; gap: 8px; }
|
|
8534
|
+
.twc-dt__combine-opt { display: flex; align-items: center; justify-content: space-between; gap: 10px; font-size: var(--text-sm); color: var(--color-text); }
|
|
8535
|
+
.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); }
|
|
8536
|
+
.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; }
|
|
8537
|
+
.twc-dt__combine-apply:hover { opacity: 0.9; }
|
|
8538
|
+
.twc-dt__combine-apply:focus-visible { outline: none; box-shadow: var(--ring); }
|
|
8539
|
+
.twc-dt__col-combined { color: var(--color-text-subtle); font-size: var(--text-xs); font-style: italic; }
|
|
8521
8540
|
.twc-dt__td[data-num="true"] { text-align: end; font-variant-numeric: tabular-nums; }
|
|
8522
8541
|
/* Auto row-number gutter (rowNumbers) \u2014 a sticky-left ordinal column. */
|
|
8523
8542
|
.twc-dt__rownum { text-align: end; font-variant-numeric: tabular-nums; color: var(--color-text-subtle);
|
|
@@ -8852,6 +8871,34 @@ function mergeColOrder(saved, propFields) {
|
|
|
8852
8871
|
return result;
|
|
8853
8872
|
}
|
|
8854
8873
|
var getColVal = (col, row) => col && col.valueGetter ? col.valueGetter(row) : row == null ? void 0 : row[col && col.field];
|
|
8874
|
+
function combineCfg(combine) {
|
|
8875
|
+
if (!combine) return null;
|
|
8876
|
+
const cfg = Array.isArray(combine) ? { fields: combine } : combine;
|
|
8877
|
+
const fields = Array.isArray(cfg.fields) ? cfg.fields.filter((f) => f != null) : [];
|
|
8878
|
+
if (!fields.length) return null;
|
|
8879
|
+
return { fields, separator: cfg.separator != null ? cfg.separator : " \xB7 ", labels: !!cfg.labels, layout: cfg.layout === "stack" ? "stack" : "inline" };
|
|
8880
|
+
}
|
|
8881
|
+
var combineSrcCols = (cfg, byField) => cfg.fields.map((f) => byField && byField[f] || { field: f, headerName: String(f) });
|
|
8882
|
+
var combineValueGetter = (srcCols, cfg) => (row) => srcCols.map((sc) => {
|
|
8883
|
+
const v = getColVal(sc, row);
|
|
8884
|
+
const s = v == null ? "" : String(v);
|
|
8885
|
+
return cfg.labels && s ? `${sc.headerName ?? sc.field}: ${s}` : s;
|
|
8886
|
+
}).filter(Boolean).join(cfg.separator);
|
|
8887
|
+
function renderCombined(srcCols, row, cfg) {
|
|
8888
|
+
const nodes = [];
|
|
8889
|
+
let count = 0;
|
|
8890
|
+
srcCols.forEach((sc, idx) => {
|
|
8891
|
+
const v = getColVal(sc, row);
|
|
8892
|
+
if (v == null || v === "") return;
|
|
8893
|
+
const disp = sc.valueFormatter ? sc.valueFormatter(v, row) : v;
|
|
8894
|
+
const label = cfg.labels ? React51__namespace.default.createElement("span", { className: "twc-dt__combine-label" }, (sc.headerName ?? sc.field) + ": ") : null;
|
|
8895
|
+
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));
|
|
8896
|
+
nodes.push(React51__namespace.default.createElement("span", { key: idx, className: "twc-dt__combine-item" }, label, disp));
|
|
8897
|
+
count++;
|
|
8898
|
+
});
|
|
8899
|
+
if (!nodes.length) return "";
|
|
8900
|
+
return React51__namespace.default.createElement("span", { className: cfg.layout === "stack" ? "twc-dt__combine twc-dt__combine--stack" : "twc-dt__combine" }, nodes);
|
|
8901
|
+
}
|
|
8855
8902
|
var diffValueNode = (col, v, row) => col.renderCell ? col.renderCell(v, row) : col.valueFormatter ? col.valueFormatter(v, row) : v == null ? "" : v;
|
|
8856
8903
|
function renderDiffCell(col, val, row) {
|
|
8857
8904
|
const meta = row && row.__diffMeta;
|
|
@@ -9232,6 +9279,7 @@ function Datatable({
|
|
|
9232
9279
|
aggregationValues = null,
|
|
9233
9280
|
disableColumnReorder = false,
|
|
9234
9281
|
disableColumnResize = false,
|
|
9282
|
+
columnCombining = false,
|
|
9235
9283
|
emptyMessage,
|
|
9236
9284
|
renderEmpty,
|
|
9237
9285
|
editMode = false,
|
|
@@ -9298,9 +9346,19 @@ function Datatable({
|
|
|
9298
9346
|
if (diffData && onClassifiedRef.current) onClassifiedRef.current(diffData.counts);
|
|
9299
9347
|
}, [diffData]);
|
|
9300
9348
|
const diffRowKeyFn = React51__namespace.default.useCallback((r2) => r2.__diffKey, []);
|
|
9349
|
+
const [userCombine, setUserCombine] = React51__namespace.default.useState({});
|
|
9301
9350
|
const columns = React51__namespace.default.useMemo(
|
|
9302
|
-
() =>
|
|
9303
|
-
|
|
9351
|
+
() => {
|
|
9352
|
+
if (!isDiff) return columnsProp;
|
|
9353
|
+
const byField = {};
|
|
9354
|
+
for (const c of columnsProp) if (c && c.field != null) byField[c.field] = c;
|
|
9355
|
+
return [DIFF_OP_COLUMN, ...columnsProp.map((c) => {
|
|
9356
|
+
const cfg = combineCfg(userCombine[c.field] || c.combine);
|
|
9357
|
+
const base = cfg && !c.valueGetter ? { ...c, valueGetter: combineValueGetter(combineSrcCols(cfg, byField), cfg) } : c;
|
|
9358
|
+
return { ...base, renderCell: (val, row) => renderDiffCell(base, val, row) };
|
|
9359
|
+
})];
|
|
9360
|
+
},
|
|
9361
|
+
[isDiff, columnsProp, userCombine]
|
|
9304
9362
|
);
|
|
9305
9363
|
const rows = React51__namespace.default.useMemo(
|
|
9306
9364
|
() => isDiff ? diffData.rows.filter((r2) => !diffOnly || r2.op !== "unchanged").map((r2) => ({ ...r2.to || r2.from, __diffop: r2.op, __diffMeta: r2, __diffKey: r2.key })) : rowsProp,
|
|
@@ -9340,8 +9398,26 @@ function Datatable({
|
|
|
9340
9398
|
getActions: () => []
|
|
9341
9399
|
});
|
|
9342
9400
|
}
|
|
9401
|
+
const byField = {};
|
|
9402
|
+
for (const c of out) if (c.field != null) byField[c.field] = c;
|
|
9403
|
+
for (let i = 0; i < out.length; i++) {
|
|
9404
|
+
const c = out[i];
|
|
9405
|
+
const cfg = combineCfg(userCombine[c.field] || c.combine);
|
|
9406
|
+
if (!cfg) continue;
|
|
9407
|
+
const srcCols = combineSrcCols(cfg, byField);
|
|
9408
|
+
out[i] = {
|
|
9409
|
+
...c,
|
|
9410
|
+
editable: false,
|
|
9411
|
+
// the combined value is synthetic — inline editing would write to a phantom field
|
|
9412
|
+
valueGetter: c.valueGetter || combineValueGetter(srcCols, cfg),
|
|
9413
|
+
// Consumer renderCell wins. If they overrode only valueGetter, fall back to the DEFAULT cell render
|
|
9414
|
+
// (renderCell: undefined) so the cell shows THEIR value — keeping display in sync with what
|
|
9415
|
+
// sort/filter/search/export use — rather than the auto source-join. Otherwise render the combined cell.
|
|
9416
|
+
renderCell: c.renderCell || (c.valueGetter ? void 0 : ((value, row) => renderCombined(srcCols, row, cfg)))
|
|
9417
|
+
};
|
|
9418
|
+
}
|
|
9343
9419
|
return out;
|
|
9344
|
-
}, [columns, rowPinning]);
|
|
9420
|
+
}, [columns, rowPinning, userCombine]);
|
|
9345
9421
|
const _autoKey = React51__namespace.default.useRef();
|
|
9346
9422
|
if (!_autoKey.current) _autoKey.current = { map: /* @__PURE__ */ new WeakMap(), n: 0 };
|
|
9347
9423
|
const keyOf = rowKey || ((r2, i) => {
|
|
@@ -9375,6 +9451,42 @@ function Datatable({
|
|
|
9375
9451
|
n.has(field) ? n.delete(field) : n.add(field);
|
|
9376
9452
|
return n;
|
|
9377
9453
|
});
|
|
9454
|
+
const openCombineEditor = (field) => {
|
|
9455
|
+
const existing = userCombine[field];
|
|
9456
|
+
setCombineTarget(field);
|
|
9457
|
+
setCombineDraft({
|
|
9458
|
+
selected: existing ? existing.fields.filter((f) => f !== field) : [],
|
|
9459
|
+
layout: existing && existing.layout === "stack" ? "stack" : "inline",
|
|
9460
|
+
labels: !!(existing && existing.labels)
|
|
9461
|
+
});
|
|
9462
|
+
};
|
|
9463
|
+
const closeCombineEditor = () => {
|
|
9464
|
+
setPanel(null);
|
|
9465
|
+
closePanel();
|
|
9466
|
+
setCombineTarget(null);
|
|
9467
|
+
setCombineDraft(null);
|
|
9468
|
+
restoreTriggerFocus();
|
|
9469
|
+
};
|
|
9470
|
+
const applyCombine = () => {
|
|
9471
|
+
if (!combineTarget || !combineDraft) return;
|
|
9472
|
+
const field = combineTarget;
|
|
9473
|
+
const sources = combineDraft.selected.filter((f) => f !== field);
|
|
9474
|
+
setUserCombine((m) => {
|
|
9475
|
+
const next = { ...m };
|
|
9476
|
+
if (sources.length) next[field] = { fields: [field, ...sources], layout: combineDraft.layout === "stack" ? "stack" : "inline", separator: " \xB7 ", labels: !!combineDraft.labels };
|
|
9477
|
+
else delete next[field];
|
|
9478
|
+
return next;
|
|
9479
|
+
});
|
|
9480
|
+
closeCombineEditor();
|
|
9481
|
+
};
|
|
9482
|
+
const uncombine = (field) => {
|
|
9483
|
+
setUserCombine((m) => {
|
|
9484
|
+
const next = { ...m };
|
|
9485
|
+
delete next[field];
|
|
9486
|
+
return next;
|
|
9487
|
+
});
|
|
9488
|
+
closeCombineEditor();
|
|
9489
|
+
};
|
|
9378
9490
|
const [pins, setPins] = React51__namespace.default.useState(() => {
|
|
9379
9491
|
const left = [], right = [];
|
|
9380
9492
|
columns.forEach((c) => {
|
|
@@ -9436,6 +9548,7 @@ function Datatable({
|
|
|
9436
9548
|
const rowFocusRef = React51__namespace.default.useRef(null);
|
|
9437
9549
|
const [fWidths, setFWidths] = React51__namespace.default.useState({});
|
|
9438
9550
|
const [fPanelSize, setFPanelSize] = React51__namespace.default.useState(null);
|
|
9551
|
+
const [batchNameW, setBatchNameW] = React51__namespace.default.useState(null);
|
|
9439
9552
|
const [popSizes, setPopSizes] = React51__namespace.default.useState({});
|
|
9440
9553
|
const serializeState = () => ({
|
|
9441
9554
|
filters: filters.map(({ id, ...f }) => f),
|
|
@@ -9456,7 +9569,11 @@ function Datatable({
|
|
|
9456
9569
|
filterPanelSize: fPanelSize || void 0,
|
|
9457
9570
|
filterFieldWidths: fWidths.col != null || fWidths.op != null || fWidths.val != null || fWidths.logic != null ? fWidths : void 0,
|
|
9458
9571
|
// #304: additive, optional — user-resized sizes of the other toolbar popovers, keyed by popover id.
|
|
9459
|
-
popoverSizes: Object.keys(popSizes).length ? popSizes : void 0
|
|
9572
|
+
popoverSizes: Object.keys(popSizes).length ? popSizes : void 0,
|
|
9573
|
+
// #339: additive, optional — runtime user-defined combined columns, keyed by target field.
|
|
9574
|
+
columnCombine: Object.keys(userCombine).length ? userCombine : void 0,
|
|
9575
|
+
// #341: additive, optional — user-resized batch-editor column-name field width (px).
|
|
9576
|
+
batchNameWidth: batchNameW != null ? batchNameW : void 0
|
|
9460
9577
|
});
|
|
9461
9578
|
const applyState = (s) => {
|
|
9462
9579
|
if (!s || typeof s !== "object") return;
|
|
@@ -9501,6 +9618,16 @@ function Datatable({
|
|
|
9501
9618
|
}
|
|
9502
9619
|
if (Object.keys(next).length) setPopSizes(next);
|
|
9503
9620
|
}
|
|
9621
|
+
if (s.columnCombine && typeof s.columnCombine === "object") {
|
|
9622
|
+
const uc = {};
|
|
9623
|
+
for (const [f, cfg] of Object.entries(s.columnCombine)) {
|
|
9624
|
+
if (!known.has(f) || !cfg || !Array.isArray(cfg.fields)) continue;
|
|
9625
|
+
const rest2 = cfg.fields.filter((x) => known.has(x) && x !== f);
|
|
9626
|
+
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 };
|
|
9627
|
+
}
|
|
9628
|
+
if (Object.keys(uc).length) setUserCombine(uc);
|
|
9629
|
+
}
|
|
9630
|
+
if (typeof s.batchNameWidth === "number") setBatchNameW(clampNum(s.batchNameWidth, 88, 260));
|
|
9504
9631
|
};
|
|
9505
9632
|
const stateReadyRef = React51__namespace.default.useRef(false);
|
|
9506
9633
|
const stateRestoredRef = React51__namespace.default.useRef(false);
|
|
@@ -9518,7 +9645,7 @@ function Datatable({
|
|
|
9518
9645
|
}
|
|
9519
9646
|
}
|
|
9520
9647
|
return void 0;
|
|
9521
|
-
}, [filters, filterLogic, sort, quick, pageVal, sizeVal, order, widths, hidden, pins, density, fWidths, fPanelSize, popSizes, stateKey]);
|
|
9648
|
+
}, [filters, filterLogic, sort, quick, pageVal, sizeVal, order, widths, hidden, pins, density, fWidths, fPanelSize, popSizes, userCombine, batchNameW, stateKey]);
|
|
9522
9649
|
const restoreState = () => {
|
|
9523
9650
|
let saved = null;
|
|
9524
9651
|
if (stateKey) {
|
|
@@ -9659,6 +9786,15 @@ function Datatable({
|
|
|
9659
9786
|
const [menuPos, openMenu, closeMenu] = useFloating();
|
|
9660
9787
|
const [panel, setPanel] = React51__namespace.default.useState(null);
|
|
9661
9788
|
const [panelPos, openPanel, closePanel] = useFloating();
|
|
9789
|
+
const [combineTarget, setCombineTarget] = React51__namespace.default.useState(null);
|
|
9790
|
+
const [combineDraft, setCombineDraft] = React51__namespace.default.useState(null);
|
|
9791
|
+
const combinePanelRef = React51__namespace.default.useRef(null);
|
|
9792
|
+
React51__namespace.default.useEffect(() => {
|
|
9793
|
+
if (panel === "combine" && combinePanelRef.current) {
|
|
9794
|
+
const el = combinePanelRef.current.querySelector('[role="switch"], button, [tabindex]');
|
|
9795
|
+
(el || combinePanelRef.current).focus?.();
|
|
9796
|
+
}
|
|
9797
|
+
}, [panel]);
|
|
9662
9798
|
const [rowMenu, setRowMenu] = React51__namespace.default.useState(null);
|
|
9663
9799
|
const [rowMenuPos, openRowMenu, closeRowMenu] = useFloating();
|
|
9664
9800
|
const [exportOpen, setExportOpen] = React51__namespace.default.useState(false);
|
|
@@ -9759,7 +9895,21 @@ function Datatable({
|
|
|
9759
9895
|
};
|
|
9760
9896
|
}, [exportOpen]);
|
|
9761
9897
|
const colByField = React51__namespace.default.useMemo(() => Object.fromEntries(cols.map((c) => [c.field, c])), [cols]);
|
|
9762
|
-
const
|
|
9898
|
+
const combineSources = React51__namespace.default.useMemo(() => {
|
|
9899
|
+
const s = /* @__PURE__ */ new Set();
|
|
9900
|
+
for (const cfg of Object.values(userCombine)) (cfg && cfg.fields ? cfg.fields : []).slice(1).forEach((f) => s.add(f));
|
|
9901
|
+
return s;
|
|
9902
|
+
}, [userCombine]);
|
|
9903
|
+
const stackCombineTargets = React51__namespace.default.useMemo(
|
|
9904
|
+
() => new Set(cols.filter((c) => {
|
|
9905
|
+
const cfg = combineCfg(userCombine[c.field] || c.combine);
|
|
9906
|
+
return cfg && cfg.layout === "stack";
|
|
9907
|
+
}).map((c) => c.field)),
|
|
9908
|
+
[cols, userCombine]
|
|
9909
|
+
);
|
|
9910
|
+
const effectiveHidden = React51__namespace.default.useMemo(() => combineSources.size ? /* @__PURE__ */ new Set([...hidden, ...combineSources]) : hidden, [hidden, combineSources]);
|
|
9911
|
+
const effectiveWrapped = React51__namespace.default.useMemo(() => stackCombineTargets.size ? /* @__PURE__ */ new Set([...wrapped, ...stackCombineTargets]) : wrapped, [wrapped, stackCombineTargets]);
|
|
9912
|
+
const visibleCols = cols.filter((c) => !effectiveHidden.has(c.field));
|
|
9763
9913
|
const colFieldsKey = JSON.stringify(
|
|
9764
9914
|
cols.filter((c) => typeof c.field === "string" && c.type !== "actions").map((c) => c.field)
|
|
9765
9915
|
);
|
|
@@ -9778,17 +9928,17 @@ function Datatable({
|
|
|
9778
9928
|
const i = order.indexOf(f);
|
|
9779
9929
|
return i === -1 ? 9999 : i;
|
|
9780
9930
|
};
|
|
9781
|
-
const L = pins.left.map((f) => colByField[f]).filter((c) => c && !
|
|
9782
|
-
const R = pins.right.map((f) => colByField[f]).filter((c) => c && !
|
|
9931
|
+
const L = pins.left.map((f) => colByField[f]).filter((c) => c && !effectiveHidden.has(c.field));
|
|
9932
|
+
const R = pins.right.map((f) => colByField[f]).filter((c) => c && !effectiveHidden.has(c.field));
|
|
9783
9933
|
const mid = visibleCols.filter((c) => !pins.left.includes(c.field) && !pins.right.includes(c.field)).sort((a, b) => orderIdx(a.field) - orderIdx(b.field));
|
|
9784
9934
|
return [...L, ...mid, ...R];
|
|
9785
|
-
}, [pins,
|
|
9935
|
+
}, [pins, effectiveHidden, visibleCols, colByField, order]);
|
|
9786
9936
|
const NUM_W = 56;
|
|
9787
9937
|
const CHK_W = checkboxSelection ? rowReorder ? 68 : 44 : 0;
|
|
9788
9938
|
const numLeft = CHK_W;
|
|
9789
9939
|
const leadW = numLeft + (showRowNum ? NUM_W : 0);
|
|
9790
|
-
const visLeft = React51__namespace.default.useMemo(() => pins.left.filter((f) => colByField[f] && !
|
|
9791
|
-
const visRight = React51__namespace.default.useMemo(() => pins.right.filter((f) => colByField[f] && !
|
|
9940
|
+
const visLeft = React51__namespace.default.useMemo(() => pins.left.filter((f) => colByField[f] && !effectiveHidden.has(f)), [pins.left, colByField, effectiveHidden]);
|
|
9941
|
+
const visRight = React51__namespace.default.useMemo(() => pins.right.filter((f) => colByField[f] && !effectiveHidden.has(f)), [pins.right, colByField, effectiveHidden]);
|
|
9792
9942
|
const stickyOf = (field) => {
|
|
9793
9943
|
if (visLeft.includes(field)) {
|
|
9794
9944
|
let off = leadW;
|
|
@@ -10953,6 +11103,54 @@ function Datatable({
|
|
|
10953
11103
|
if (field === "val") p.removeAttribute("data-val-fixed");
|
|
10954
11104
|
}
|
|
10955
11105
|
};
|
|
11106
|
+
const BE_NAME_MIN = 88, BE_NAME_MAX = 260;
|
|
11107
|
+
const startBeNameResize = (e) => {
|
|
11108
|
+
if (e.button != null && e.button !== 0) return;
|
|
11109
|
+
e.preventDefault();
|
|
11110
|
+
e.stopPropagation();
|
|
11111
|
+
const handle = e.currentTarget;
|
|
11112
|
+
const panel2 = handle.closest(".twc-dt__cfg"), nameEl = handle.closest(".twc-dt__be-name");
|
|
11113
|
+
if (!panel2 || !nameEl) return;
|
|
11114
|
+
const startX = e.clientX, startW = nameEl.getBoundingClientRect().width;
|
|
11115
|
+
const dir = getComputedStyle(panel2).direction === "rtl" ? -1 : 1;
|
|
11116
|
+
handle.setAttribute("data-active", "true");
|
|
11117
|
+
let last = startW;
|
|
11118
|
+
const onMove = (ev) => {
|
|
11119
|
+
last = clampNum(startW + (ev.clientX - startX) * dir, BE_NAME_MIN, BE_NAME_MAX);
|
|
11120
|
+
panel2.style.setProperty("--twc-dt-be-name-usr", `${last}px`);
|
|
11121
|
+
};
|
|
11122
|
+
const onUp = () => {
|
|
11123
|
+
setBatchNameW(last);
|
|
11124
|
+
handle.removeAttribute("data-active");
|
|
11125
|
+
window.removeEventListener("pointermove", onMove);
|
|
11126
|
+
window.removeEventListener("pointerup", onUp);
|
|
11127
|
+
};
|
|
11128
|
+
window.addEventListener("pointermove", onMove);
|
|
11129
|
+
window.addEventListener("pointerup", onUp);
|
|
11130
|
+
};
|
|
11131
|
+
const onBeNameResizeKey = (e) => {
|
|
11132
|
+
const panel2 = e.currentTarget.closest(".twc-dt__cfg");
|
|
11133
|
+
if (e.key === "Enter" || e.key === " " || e.key === "Backspace") {
|
|
11134
|
+
e.preventDefault();
|
|
11135
|
+
e.stopPropagation();
|
|
11136
|
+
setBatchNameW(null);
|
|
11137
|
+
if (panel2) panel2.style.removeProperty("--twc-dt-be-name-usr");
|
|
11138
|
+
return;
|
|
11139
|
+
}
|
|
11140
|
+
if (!["ArrowLeft", "ArrowRight", "Home", "End"].includes(e.key)) return;
|
|
11141
|
+
e.preventDefault();
|
|
11142
|
+
e.stopPropagation();
|
|
11143
|
+
const nameEl = e.currentTarget.closest(".twc-dt__be-name");
|
|
11144
|
+
const cur = nameEl ? nameEl.getBoundingClientRect().width : batchNameW ?? 108;
|
|
11145
|
+
const dir = panel2 && getComputedStyle(panel2).direction === "rtl" ? -1 : 1;
|
|
11146
|
+
const step = e.shiftKey ? 2 : 10;
|
|
11147
|
+
let next = cur;
|
|
11148
|
+
if (e.key === "ArrowRight") next = cur + step * dir;
|
|
11149
|
+
else if (e.key === "ArrowLeft") next = cur - step * dir;
|
|
11150
|
+
else if (e.key === "Home") next = BE_NAME_MIN;
|
|
11151
|
+
else if (e.key === "End") next = BE_NAME_MAX;
|
|
11152
|
+
setBatchNameW(clampNum(next, BE_NAME_MIN, BE_NAME_MAX));
|
|
11153
|
+
};
|
|
10956
11154
|
const startPanelResize = (e) => {
|
|
10957
11155
|
if (e.button != null && e.button !== 0) return;
|
|
10958
11156
|
e.preventDefault();
|
|
@@ -11175,7 +11373,7 @@ function Datatable({
|
|
|
11175
11373
|
const shownColRows = cols.filter((c) => c.field !== "__pinactions__" && c.headerName.toLowerCase().includes(colQuery.trim().toLowerCase())).sort((a, b) => orderIdxOf(a.field) - orderIdxOf(b.field));
|
|
11176
11374
|
const rowNumMatch = rowNumbers && "row number".includes(colQuery.trim().toLowerCase());
|
|
11177
11375
|
const manageableCols = cols.filter((c) => c.field !== "__pinactions__");
|
|
11178
|
-
const visibleColCount = manageableCols.filter((c) => !
|
|
11376
|
+
const visibleColCount = manageableCols.filter((c) => !effectiveHidden.has(c.field)).length;
|
|
11179
11377
|
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) }));
|
|
11180
11378
|
const totalCols = ordered.length + (checkboxSelection ? 1 : 0) + (showRowNum ? 1 : 0);
|
|
11181
11379
|
function renderGroupRow(item) {
|
|
@@ -11333,7 +11531,7 @@ function Datatable({
|
|
|
11333
11531
|
"data-cell-active": cellActive || void 0,
|
|
11334
11532
|
"data-cell-selected": cellSelected || void 0,
|
|
11335
11533
|
"data-copied": cellFlash || void 0,
|
|
11336
|
-
"data-wrap":
|
|
11534
|
+
"data-wrap": effectiveWrapped.has(c.field) || void 0,
|
|
11337
11535
|
"data-pin": st.pin,
|
|
11338
11536
|
"data-pin-edge": st.edge,
|
|
11339
11537
|
style: { width: widthOf(c), ...st.style },
|
|
@@ -12030,7 +12228,7 @@ function Datatable({
|
|
|
12030
12228
|
delete values[f];
|
|
12031
12229
|
return { ...b, fields, values };
|
|
12032
12230
|
});
|
|
12033
|
-
return /* @__PURE__ */ jsxRuntime.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: [
|
|
12231
|
+
return /* @__PURE__ */ jsxRuntime.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: [
|
|
12034
12232
|
/* @__PURE__ */ jsxRuntime.jsx(Caret, { pos: batchEditPos }),
|
|
12035
12233
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__cfg-head", children: [
|
|
12036
12234
|
"Edit ",
|
|
@@ -12051,10 +12249,25 @@ function Datatable({
|
|
|
12051
12249
|
onChange: addField
|
|
12052
12250
|
}
|
|
12053
12251
|
) }) : null,
|
|
12054
|
-
/* @__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) => {
|
|
12252
|
+
/* @__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) => {
|
|
12055
12253
|
const opts = c.valueOptions ? c.valueOptions.map((o) => typeof o === "string" ? { value: o, label: o } : o) : null;
|
|
12056
12254
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__be-row", children: [
|
|
12057
|
-
/* @__PURE__ */ jsxRuntime.
|
|
12255
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__be-name", title: String(c.headerName ?? c.field), children: [
|
|
12256
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__be-name-txt", children: c.headerName }),
|
|
12257
|
+
resizableFilters && i === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
12258
|
+
"span",
|
|
12259
|
+
{
|
|
12260
|
+
className: "twc-dt__f-rz",
|
|
12261
|
+
role: "separator",
|
|
12262
|
+
"aria-orientation": "vertical",
|
|
12263
|
+
tabIndex: 0,
|
|
12264
|
+
"aria-label": "Resize column name field (Enter to reset)",
|
|
12265
|
+
onPointerDown: startBeNameResize,
|
|
12266
|
+
onClick: (e) => e.stopPropagation(),
|
|
12267
|
+
onKeyDown: onBeNameResizeKey
|
|
12268
|
+
}
|
|
12269
|
+
) : null
|
|
12270
|
+
] }),
|
|
12058
12271
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__be-ctl", children: c.renderBatchEditCell ? c.renderBatchEditCell({
|
|
12059
12272
|
value: batchEdit.values[c.field],
|
|
12060
12273
|
field: c.field,
|
|
@@ -12169,6 +12382,18 @@ function Datatable({
|
|
|
12169
12382
|
" ",
|
|
12170
12383
|
groupBy.includes(c.field) ? "Stop grouping" : "Group by this column"
|
|
12171
12384
|
] }) : null,
|
|
12385
|
+
columnCombining && c.type !== "actions" ? /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", role: "menuitem", className: "twc-dt__mi", "data-active": !!userCombine[c.field] || void 0, onClick: () => {
|
|
12386
|
+
const anchor = menuTriggerRef.current;
|
|
12387
|
+
setColMenu(null);
|
|
12388
|
+
closeMenu();
|
|
12389
|
+
openCombineEditor(c.field);
|
|
12390
|
+
setPanel("combine");
|
|
12391
|
+
openPanel(anchor, "right", 300);
|
|
12392
|
+
}, children: [
|
|
12393
|
+
/* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.columns }),
|
|
12394
|
+
" ",
|
|
12395
|
+
userCombine[c.field] ? "Edit combined column\u2026" : "Combine columns\u2026"
|
|
12396
|
+
] }) : null,
|
|
12172
12397
|
!disableColumnReorder && c.reorderable !== false && c.type !== "actions" && !pins.left.includes(c.field) && !pins.right.includes(c.field) && movableMidFields.length > 1 ? (() => {
|
|
12173
12398
|
const midIdx = movableMidFields.indexOf(c.field);
|
|
12174
12399
|
const atFirst = midIdx === 0;
|
|
@@ -12336,10 +12561,13 @@ function Datatable({
|
|
|
12336
12561
|
e.preventDefault();
|
|
12337
12562
|
onColDrop(c.field);
|
|
12338
12563
|
} : void 0,
|
|
12339
|
-
onClick: () => c.hideable && toggleHiddenField(c.field),
|
|
12564
|
+
onClick: () => c.hideable && !combineSources.has(c.field) && toggleHiddenField(c.field),
|
|
12340
12565
|
children: [
|
|
12341
12566
|
canDrag ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__col-grip", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.grip }) }) : null,
|
|
12342
|
-
/* @__PURE__ */ jsxRuntime.
|
|
12567
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__col-name", children: [
|
|
12568
|
+
c.headerName,
|
|
12569
|
+
combineSources.has(c.field) ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__col-combined", children: " \xB7 combined" }) : null
|
|
12570
|
+
] }),
|
|
12343
12571
|
c.pinnable && c.type !== "actions" ? (
|
|
12344
12572
|
// Pin from here too, so columns scrolled out of view (no reachable header ⋮) can still be pinned.
|
|
12345
12573
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__col-pins", draggable: false, onClick: (e) => e.stopPropagation(), children: [
|
|
@@ -12375,19 +12603,19 @@ function Datatable({
|
|
|
12375
12603
|
"span",
|
|
12376
12604
|
{
|
|
12377
12605
|
className: "twc-dt__sw",
|
|
12378
|
-
"data-on": !
|
|
12606
|
+
"data-on": !effectiveHidden.has(c.field) || void 0,
|
|
12379
12607
|
role: "switch",
|
|
12380
|
-
"aria-checked": !
|
|
12608
|
+
"aria-checked": !effectiveHidden.has(c.field),
|
|
12381
12609
|
"aria-label": c.headerName,
|
|
12382
|
-
"aria-disabled": !c.hideable || void 0,
|
|
12383
|
-
tabIndex: c.hideable ? 0 : -1,
|
|
12610
|
+
"aria-disabled": !c.hideable || combineSources.has(c.field) || void 0,
|
|
12611
|
+
tabIndex: c.hideable && !combineSources.has(c.field) ? 0 : -1,
|
|
12384
12612
|
onKeyDown: (e) => {
|
|
12385
|
-
if ((e.key === "Enter" || e.key === " ") && c.hideable) {
|
|
12613
|
+
if ((e.key === "Enter" || e.key === " ") && c.hideable && !combineSources.has(c.field)) {
|
|
12386
12614
|
e.preventDefault();
|
|
12387
12615
|
toggleHiddenField(c.field);
|
|
12388
12616
|
}
|
|
12389
12617
|
},
|
|
12390
|
-
style: c.hideable ? void 0 : { opacity: 0.4 }
|
|
12618
|
+
style: c.hideable && !combineSources.has(c.field) ? void 0 : { opacity: 0.4 }
|
|
12391
12619
|
}
|
|
12392
12620
|
)
|
|
12393
12621
|
]
|
|
@@ -12398,6 +12626,82 @@ function Datatable({
|
|
|
12398
12626
|
] }),
|
|
12399
12627
|
popGrip("columns")
|
|
12400
12628
|
] }) : null,
|
|
12629
|
+
panel === "combine" && panelPos && combineTarget && combineDraft ? (() => {
|
|
12630
|
+
const target = colByField[combineTarget];
|
|
12631
|
+
const candidates = cols.filter((c) => c.field !== combineTarget && c.type !== "actions" && c.field !== "__pinactions__" && c.hideable !== false && !userCombine[c.field]);
|
|
12632
|
+
const toggle = (f) => setCombineDraft((d) => ({ ...d, selected: d.selected.includes(f) ? d.selected.filter((x) => x !== f) : [...d.selected, f] }));
|
|
12633
|
+
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: [
|
|
12634
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__panel-head", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__panel-title", children: [
|
|
12635
|
+
"Combine into \u201C",
|
|
12636
|
+
target?.headerName || combineTarget,
|
|
12637
|
+
"\u201D"
|
|
12638
|
+
] }) }),
|
|
12639
|
+
/* @__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." }),
|
|
12640
|
+
/* @__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) => {
|
|
12641
|
+
const on = combineDraft.selected.includes(c.field);
|
|
12642
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__col-row", onClick: () => toggle(c.field), children: [
|
|
12643
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__col-name", children: c.headerName }),
|
|
12644
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12645
|
+
"span",
|
|
12646
|
+
{
|
|
12647
|
+
className: "twc-dt__sw",
|
|
12648
|
+
"data-on": on || void 0,
|
|
12649
|
+
role: "switch",
|
|
12650
|
+
"aria-checked": on,
|
|
12651
|
+
"aria-label": c.headerName,
|
|
12652
|
+
tabIndex: 0,
|
|
12653
|
+
onKeyDown: (e) => {
|
|
12654
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
12655
|
+
e.preventDefault();
|
|
12656
|
+
toggle(c.field);
|
|
12657
|
+
}
|
|
12658
|
+
}
|
|
12659
|
+
}
|
|
12660
|
+
)
|
|
12661
|
+
] }, c.field);
|
|
12662
|
+
}) }),
|
|
12663
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__combine-opts", children: [
|
|
12664
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "twc-dt__combine-opt", children: [
|
|
12665
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Layout" }),
|
|
12666
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12667
|
+
Select,
|
|
12668
|
+
{
|
|
12669
|
+
size: "sm",
|
|
12670
|
+
portal: true,
|
|
12671
|
+
matchTriggerWidth: false,
|
|
12672
|
+
value: combineDraft.layout,
|
|
12673
|
+
options: [{ value: "inline", label: "Inline" }, { value: "stack", label: "Stacked" }],
|
|
12674
|
+
onChange: (v) => setCombineDraft((d) => ({ ...d, layout: v }))
|
|
12675
|
+
}
|
|
12676
|
+
)
|
|
12677
|
+
] }),
|
|
12678
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__combine-opt", onClick: () => setCombineDraft((d) => ({ ...d, labels: !d.labels })), style: { cursor: "pointer" }, children: [
|
|
12679
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Show labels" }),
|
|
12680
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12681
|
+
"span",
|
|
12682
|
+
{
|
|
12683
|
+
className: "twc-dt__sw",
|
|
12684
|
+
"data-on": combineDraft.labels || void 0,
|
|
12685
|
+
role: "switch",
|
|
12686
|
+
"aria-checked": combineDraft.labels,
|
|
12687
|
+
"aria-label": "Show labels",
|
|
12688
|
+
tabIndex: 0,
|
|
12689
|
+
onKeyDown: (e) => {
|
|
12690
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
12691
|
+
e.preventDefault();
|
|
12692
|
+
setCombineDraft((d) => ({ ...d, labels: !d.labels }));
|
|
12693
|
+
}
|
|
12694
|
+
}
|
|
12695
|
+
}
|
|
12696
|
+
)
|
|
12697
|
+
] })
|
|
12698
|
+
] }),
|
|
12699
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__combine-foot", children: [
|
|
12700
|
+
userCombine[combineTarget] ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__link", onClick: () => uncombine(combineTarget), children: "Uncombine" }) : /* @__PURE__ */ jsxRuntime.jsx("span", {}),
|
|
12701
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__combine-apply", onClick: applyCombine, children: "Apply" })
|
|
12702
|
+
] })
|
|
12703
|
+
] });
|
|
12704
|
+
})() : null,
|
|
12401
12705
|
panel === "agg" && panelPos ? /* @__PURE__ */ jsxRuntime.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: [
|
|
12402
12706
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__panel-head", children: [
|
|
12403
12707
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__panel-title", children: "Aggregation" }),
|
|
@@ -15550,6 +15854,8 @@ var ICONBTN_CSS = `
|
|
|
15550
15854
|
.twc-iconbtn:focus-visible { outline: none; box-shadow: var(--ring); }
|
|
15551
15855
|
.twc-iconbtn:active:not(:disabled) { transform: scale(var(--press-scale)); }
|
|
15552
15856
|
.twc-iconbtn:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
15857
|
+
/* #342: disabled state for the anchor form (as="a") \u2014 :disabled doesn't apply to <a>. */
|
|
15858
|
+
.twc-iconbtn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; pointer-events: none; }
|
|
15553
15859
|
.twc-iconbtn svg { width: 1.25em; height: 1.25em; }
|
|
15554
15860
|
|
|
15555
15861
|
/* tone supplies the accent set; variant decides how it's applied \u2014 mirrors Button. Default tone
|
|
@@ -15568,6 +15874,11 @@ var ICONBTN_CSS = `
|
|
|
15568
15874
|
.twc-iconbtn[data-variant="outline"]:hover:not(:disabled) { border-color: var(--_accent); color: var(--_accent); background: var(--color-surface-sunken); }
|
|
15569
15875
|
.twc-iconbtn[data-variant="ghost"]:hover:not(:disabled) { background: var(--color-surface-sunken); color: var(--_accent); }
|
|
15570
15876
|
`;
|
|
15877
|
+
function safeHref6(url) {
|
|
15878
|
+
if (url == null) return void 0;
|
|
15879
|
+
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
15880
|
+
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
15881
|
+
}
|
|
15571
15882
|
function IconButton({
|
|
15572
15883
|
children,
|
|
15573
15884
|
icon,
|
|
@@ -15576,21 +15887,28 @@ function IconButton({
|
|
|
15576
15887
|
size = "md",
|
|
15577
15888
|
round = false,
|
|
15578
15889
|
disabled = false,
|
|
15890
|
+
as = "button",
|
|
15891
|
+
href,
|
|
15579
15892
|
className = "",
|
|
15580
15893
|
"aria-label": ariaLabel,
|
|
15581
15894
|
...rest
|
|
15582
15895
|
}) {
|
|
15583
15896
|
const __twcStyles = useScopedStyles("twc-iconbtn-styles", ICONBTN_CSS);
|
|
15897
|
+
const Tag2 = as;
|
|
15898
|
+
const inert = Tag2 === "a" && disabled;
|
|
15584
15899
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
15585
|
-
|
|
15900
|
+
Tag2,
|
|
15586
15901
|
{
|
|
15587
15902
|
className: `twc-iconbtn ${className}`,
|
|
15588
15903
|
"data-variant": variant,
|
|
15589
15904
|
"data-tone": tone,
|
|
15590
15905
|
"data-size": size,
|
|
15591
15906
|
"data-round": round || void 0,
|
|
15592
|
-
disabled,
|
|
15593
|
-
type: "button",
|
|
15907
|
+
disabled: Tag2 === "button" ? disabled : void 0,
|
|
15908
|
+
type: Tag2 === "button" ? "button" : void 0,
|
|
15909
|
+
href: Tag2 === "a" && !inert ? safeHref6(href) : void 0,
|
|
15910
|
+
"aria-disabled": inert || void 0,
|
|
15911
|
+
tabIndex: inert ? -1 : void 0,
|
|
15594
15912
|
"aria-label": ariaLabel,
|
|
15595
15913
|
...rest,
|
|
15596
15914
|
children: [
|
|
@@ -15792,7 +16110,7 @@ var LIST_CSS = `
|
|
|
15792
16110
|
`;
|
|
15793
16111
|
function List({ items, plain = false, emptyMessage, className = "", ...rest }) {
|
|
15794
16112
|
const __twcStyles = useScopedStyles("twc-list-styles", LIST_CSS);
|
|
15795
|
-
const
|
|
16113
|
+
const safeHref14 = (url) => {
|
|
15796
16114
|
if (url == null) return void 0;
|
|
15797
16115
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
15798
16116
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -15804,7 +16122,7 @@ function List({ items, plain = false, emptyMessage, className = "", ...rest }) {
|
|
|
15804
16122
|
/* @__PURE__ */ jsxRuntime.jsxs("ul", { className: `twc-list ${className}`, role: "list", "data-plain": plain || void 0, ...rest, children: [
|
|
15805
16123
|
__twcStyles,
|
|
15806
16124
|
items.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("li", { role: "presentation", style: { display: "contents" }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-list__empty", children: emptyMessage ?? "Nothing here yet" }) }) : items.map((it, i) => {
|
|
15807
|
-
const href =
|
|
16125
|
+
const href = safeHref14(it.href);
|
|
15808
16126
|
const interactive = Boolean(it.onClick || href);
|
|
15809
16127
|
const Tag2 = href ? "a" : interactive ? "button" : "div";
|
|
15810
16128
|
const content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
@@ -15860,7 +16178,7 @@ button.twc-navbar__brand, a.twc-navbar__brand { cursor: pointer; }
|
|
|
15860
16178
|
.twc-navbar__menu-btn { display: inline-grid; }
|
|
15861
16179
|
}
|
|
15862
16180
|
`;
|
|
15863
|
-
function
|
|
16181
|
+
function safeHref7(url) {
|
|
15864
16182
|
if (url == null) return void 0;
|
|
15865
16183
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
15866
16184
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -15883,9 +16201,9 @@ function Navbar({
|
|
|
15883
16201
|
return /* @__PURE__ */ jsxRuntime.jsxs("header", { className: `twc-navbar ${className}`, "data-sticky": sticky || void 0, ...rest, children: [
|
|
15884
16202
|
__twcStyles,
|
|
15885
16203
|
onMenuClick ? /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 6h16M4 12h16M4 18h16" }) }) }) : null,
|
|
15886
|
-
brand ? brandHref ? /* @__PURE__ */ jsxRuntime.jsx("a", { className: "twc-navbar__brand", href:
|
|
16204
|
+
brand ? brandHref ? /* @__PURE__ */ jsxRuntime.jsx("a", { className: "twc-navbar__brand", href: safeHref7(brandHref), children: brand }) : onBrandClick ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-navbar__brand", onClick: onBrandClick, children: brand }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-navbar__brand", children: brand }) : null,
|
|
15887
16205
|
/* @__PURE__ */ jsxRuntime.jsx("nav", { className: "twc-navbar__links", "aria-label": navLabel, children: links.map((l, i) => {
|
|
15888
|
-
const href =
|
|
16206
|
+
const href = safeHref7(l.href);
|
|
15889
16207
|
const inner = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
15890
16208
|
l.icon,
|
|
15891
16209
|
l.label
|
|
@@ -16672,13 +16990,13 @@ function Sidebar({
|
|
|
16672
16990
|
document.addEventListener("keydown", onKey);
|
|
16673
16991
|
return () => document.removeEventListener("keydown", onKey);
|
|
16674
16992
|
}, [overlay, open, openProp, onOpenChange]);
|
|
16675
|
-
const
|
|
16993
|
+
const safeHref14 = (url) => {
|
|
16676
16994
|
if (url == null) return void 0;
|
|
16677
16995
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
16678
16996
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
16679
16997
|
};
|
|
16680
16998
|
const renderItem = (it, i) => {
|
|
16681
|
-
const href =
|
|
16999
|
+
const href = safeHref14(it.href);
|
|
16682
17000
|
const labelStr = typeof it.label === "string" ? it.label : void 0;
|
|
16683
17001
|
const inner = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
16684
17002
|
it.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-sidebar__ic", "aria-hidden": "true", children: it.icon }) : labelStr != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-sidebar__ic twc-sidebar__ic--initial", "aria-hidden": "true", children: labelStr.charAt(0) }) : null,
|
|
@@ -18392,7 +18710,7 @@ function bgValue(bg) {
|
|
|
18392
18710
|
if (BG[bg]) return `var(${BG[bg]})`;
|
|
18393
18711
|
return String(bg).startsWith("--") ? `var(${bg})` : bg;
|
|
18394
18712
|
}
|
|
18395
|
-
function
|
|
18713
|
+
function safeHref8(url) {
|
|
18396
18714
|
if (url == null) return void 0;
|
|
18397
18715
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
18398
18716
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -18440,7 +18758,7 @@ var Box = React51__namespace.default.forwardRef(function Box2({
|
|
|
18440
18758
|
...style,
|
|
18441
18759
|
...flatStyle
|
|
18442
18760
|
};
|
|
18443
|
-
if (Tag2 === "a" && rest.href != null) rest.href =
|
|
18761
|
+
if (Tag2 === "a" && rest.href != null) rest.href = safeHref8(rest.href);
|
|
18444
18762
|
return /* @__PURE__ */ jsxRuntime.jsxs(Tag2, { ref, className: `twc-box ${className}`.trim(), style: s, "data-twc-sx": sxAttr, ...rest, children: [
|
|
18445
18763
|
styleNode,
|
|
18446
18764
|
children
|
|
@@ -18448,7 +18766,7 @@ var Box = React51__namespace.default.forwardRef(function Box2({
|
|
|
18448
18766
|
});
|
|
18449
18767
|
Box.displayName = "Box";
|
|
18450
18768
|
var SIZES = { sm: 640, md: 768, lg: 1024, xl: 1280, full: "100%" };
|
|
18451
|
-
function
|
|
18769
|
+
function safeHref9(url) {
|
|
18452
18770
|
if (url == null) return void 0;
|
|
18453
18771
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
18454
18772
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -18465,7 +18783,7 @@ var Container = React51__namespace.default.forwardRef(function Container2({
|
|
|
18465
18783
|
}, ref) {
|
|
18466
18784
|
const { flatStyle, styleNode, sxAttr } = useSx(sx);
|
|
18467
18785
|
const max = SIZES[size] ?? size;
|
|
18468
|
-
if (Tag2 === "a" && rest.href != null) rest.href =
|
|
18786
|
+
if (Tag2 === "a" && rest.href != null) rest.href = safeHref9(rest.href);
|
|
18469
18787
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
18470
18788
|
Tag2,
|
|
18471
18789
|
{
|
|
@@ -18496,7 +18814,7 @@ function space2(v) {
|
|
|
18496
18814
|
if (typeof v === "number") return `var(--space-${String(v).replace(".", "-")})`;
|
|
18497
18815
|
return v;
|
|
18498
18816
|
}
|
|
18499
|
-
function
|
|
18817
|
+
function safeHref10(url) {
|
|
18500
18818
|
if (url == null) return void 0;
|
|
18501
18819
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
18502
18820
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -18524,7 +18842,7 @@ var Stack = React51__namespace.default.forwardRef(function Stack2({
|
|
|
18524
18842
|
...rest
|
|
18525
18843
|
}, ref) {
|
|
18526
18844
|
const { flatStyle, styleNode, sxAttr } = useSx(sx);
|
|
18527
|
-
if (Tag2 === "a" && rest.href != null) rest.href =
|
|
18845
|
+
if (Tag2 === "a" && rest.href != null) rest.href = safeHref10(rest.href);
|
|
18528
18846
|
const kids = divider != null ? React51__namespace.default.Children.toArray(children).flatMap((child, i, arr) => i < arr.length - 1 ? [child, /* @__PURE__ */ jsxRuntime.jsx(React51__namespace.default.Fragment, { children: divider }, `twc-stack-div-${i}`)] : [child]) : children;
|
|
18529
18847
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
18530
18848
|
Tag2,
|
|
@@ -18579,7 +18897,7 @@ var CODE_CSS = `
|
|
|
18579
18897
|
.twc-code__copy:focus-visible { outline: none; box-shadow: var(--ring); }
|
|
18580
18898
|
.twc-code__copy svg { width: 15px; height: 15px; display: block; }
|
|
18581
18899
|
`;
|
|
18582
|
-
function
|
|
18900
|
+
function safeHref11(url) {
|
|
18583
18901
|
if (url == null) return void 0;
|
|
18584
18902
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
18585
18903
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -18596,7 +18914,7 @@ function Code({
|
|
|
18596
18914
|
}) {
|
|
18597
18915
|
const __twcStyles = useScopedStyles("twc-code-styles", CODE_CSS);
|
|
18598
18916
|
const Tag2 = as ?? (block ? "pre" : "code");
|
|
18599
|
-
if (Tag2 === "a" && rest.href != null) rest.href =
|
|
18917
|
+
if (Tag2 === "a" && rest.href != null) rest.href = safeHref11(rest.href);
|
|
18600
18918
|
const rootRef = React51__namespace.default.useRef(null);
|
|
18601
18919
|
const [copied, setCopied] = React51__namespace.default.useState(false);
|
|
18602
18920
|
const timerRef = React51__namespace.default.useRef(null);
|
|
@@ -18621,7 +18939,7 @@ function Code({
|
|
|
18621
18939
|
] });
|
|
18622
18940
|
}
|
|
18623
18941
|
var LEVEL_SIZE = { 1: "4xl", 2: "2xl", 3: "xl", 4: "lg", 5: "base", 6: "sm" };
|
|
18624
|
-
function
|
|
18942
|
+
function safeHref12(url) {
|
|
18625
18943
|
if (url == null) return void 0;
|
|
18626
18944
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
18627
18945
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -18643,7 +18961,7 @@ var Heading = React51__namespace.default.forwardRef(function Heading2({
|
|
|
18643
18961
|
const { flatStyle, styleNode, sxAttr } = useSx(sx);
|
|
18644
18962
|
const Tag2 = as || `h${level}`;
|
|
18645
18963
|
const sz = size || (display ? "display" : LEVEL_SIZE[level]) || "2xl";
|
|
18646
|
-
if (Tag2 === "a" && rest.href != null) rest.href =
|
|
18964
|
+
if (Tag2 === "a" && rest.href != null) rest.href = safeHref12(rest.href);
|
|
18647
18965
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
18648
18966
|
Tag2,
|
|
18649
18967
|
{
|
|
@@ -18690,7 +19008,7 @@ var TONE = {
|
|
|
18690
19008
|
// Adopt the surrounding color (e.g. inside a solid Button/Badge/Alert or a link).
|
|
18691
19009
|
inherit: "inherit"
|
|
18692
19010
|
};
|
|
18693
|
-
function
|
|
19011
|
+
function safeHref13(url) {
|
|
18694
19012
|
if (url == null) return void 0;
|
|
18695
19013
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
18696
19014
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -18710,7 +19028,7 @@ var Text = React51__namespace.default.forwardRef(function Text2({
|
|
|
18710
19028
|
...rest
|
|
18711
19029
|
}, ref) {
|
|
18712
19030
|
const { flatStyle, styleNode, sxAttr } = useSx(sx);
|
|
18713
|
-
if (Tag2 === "a" && rest.href != null) rest.href =
|
|
19031
|
+
if (Tag2 === "a" && rest.href != null) rest.href = safeHref13(rest.href);
|
|
18714
19032
|
const toneToken = TONE[tone] || TONE.default;
|
|
18715
19033
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
18716
19034
|
Tag2,
|