twico-ui 1.25.0 → 1.26.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 +7 -0
- package/dist/index.cjs +274 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.mjs +274 -23
- package/dist/index.mjs.map +1 -1
- package/llms.txt +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to Twico UI are documented here (newest first). This file is generated automatically on each release by [semantic-release](https://semantic-release.gitbook.io/) from [Conventional Commits](https://www.conventionalcommits.org/) — do not edit it by hand. The same notes appear on each [GitHub Release](https://github.com/EncryptionL/twico-ui/releases).
|
|
4
4
|
|
|
5
|
+
# [1.26.0](https://github.com/EncryptionL/twico-ui/compare/v1.25.0...v1.26.0) (2026-08-03)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **datatable:** bottom-left popover grip, cell range selection, keyboard clipboard ([#316](https://github.com/EncryptionL/twico-ui/issues/316), [#317](https://github.com/EncryptionL/twico-ui/issues/317), [#318](https://github.com/EncryptionL/twico-ui/issues/318)) ([0c1a583](https://github.com/EncryptionL/twico-ui/commit/0c1a583ef8b983410547f7f1fb92f8660ec926c3))
|
|
11
|
+
|
|
5
12
|
# [1.25.0](https://github.com/EncryptionL/twico-ui/compare/v1.24.0...v1.25.0) (2026-08-03)
|
|
6
13
|
|
|
7
14
|
|
package/dist/index.cjs
CHANGED
|
@@ -8461,6 +8461,8 @@ th.twc-dt__rownum .twc-dt__th-inner { padding-inline: 8px; gap: 2px; justify-con
|
|
|
8461
8461
|
.twc-dt__row[data-selectable="true"] { cursor: pointer; }
|
|
8462
8462
|
.twc-dt__row[data-active="true"] .twc-dt__td { background: var(--color-primary-subtle); box-shadow: inset 0 0 0 9999px transparent; }
|
|
8463
8463
|
.twc-dt__row[data-active="true"] .twc-dt__td[data-pin] { background: var(--color-primary-subtle); }
|
|
8464
|
+
/* #317: data-cell-selected fills the range rectangle; data-cell-active keeps the ring on the moving corner. */
|
|
8465
|
+
.twc-dt__td[data-cell-selected="true"] { background: var(--color-primary-subtle); }
|
|
8464
8466
|
.twc-dt__td[data-cell-active="true"] { box-shadow: inset 0 0 0 2px var(--color-primary); background: var(--color-primary-subtle); }
|
|
8465
8467
|
.twc-dt__row:last-child .twc-dt__td { border-bottom: none; }
|
|
8466
8468
|
|
|
@@ -8615,6 +8617,9 @@ th.twc-dt__rownum .twc-dt__th-inner { padding-inline: 8px; gap: 2px; justify-con
|
|
|
8615
8617
|
.twc-dt__pop-grip:hover, .twc-dt__pop-grip:focus-visible, .twc-dt__pop-grip[data-active="true"] { opacity: 1; }
|
|
8616
8618
|
.twc-dt__pop-grip:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 1px; }
|
|
8617
8619
|
[dir="rtl"] .twc-dt__pop-grip { cursor: nesw-resize; }
|
|
8620
|
+
/* #316: a second grip in the bottom-inline-start corner grows a right-anchored panel toward the empty side (right edge pinned). */
|
|
8621
|
+
.twc-dt__pop-grip[data-side="start"] { inset-inline-start: 2px; inset-inline-end: auto; cursor: nesw-resize; background: linear-gradient(225deg, transparent 0 55%, var(--color-border-strong) 55% 64%, transparent 64% 73%, var(--color-border-strong) 73% 82%, transparent 82%); }
|
|
8622
|
+
[dir="rtl"] .twc-dt__pop-grip[data-side="start"] { cursor: nwse-resize; }
|
|
8618
8623
|
@media (pointer: coarse) {
|
|
8619
8624
|
.twc-dt__f-rz { width: 16px; inset-inline-end: -6px; opacity: 0.4; }
|
|
8620
8625
|
.twc-dt__pop-grip { width: 20px; height: 20px; opacity: 0.6; }
|
|
@@ -9169,6 +9174,8 @@ function Datatable({
|
|
|
9169
9174
|
onRowClick,
|
|
9170
9175
|
onCellClick,
|
|
9171
9176
|
onActiveCellChange,
|
|
9177
|
+
onCellSelectionChange,
|
|
9178
|
+
enableClipboard = false,
|
|
9172
9179
|
showAggregation = false,
|
|
9173
9180
|
ariaLabel = "Data table",
|
|
9174
9181
|
"aria-label": ariaLabelAttr,
|
|
@@ -9299,6 +9306,8 @@ function Datatable({
|
|
|
9299
9306
|
const [selected, setSelected] = React51__namespace.default.useState(() => /* @__PURE__ */ new Set());
|
|
9300
9307
|
const [activeRow, setActiveRow] = React51__namespace.default.useState(null);
|
|
9301
9308
|
const [activeCell, setActiveCell] = React51__namespace.default.useState(null);
|
|
9309
|
+
const [anchorCell, setAnchorCell] = React51__namespace.default.useState(null);
|
|
9310
|
+
const gridId = React51__namespace.default.useId();
|
|
9302
9311
|
const [internalPage, setInternalPage] = React51__namespace.default.useState(0);
|
|
9303
9312
|
const [internalRpp, setInternalRpp] = React51__namespace.default.useState(pageSize > 0 ? pageSize : 10);
|
|
9304
9313
|
const pageControlled = page !== void 0;
|
|
@@ -9398,6 +9407,7 @@ function Datatable({
|
|
|
9398
9407
|
for (const [id, sz] of Object.entries(s.popoverSizes)) {
|
|
9399
9408
|
if (!sz || typeof sz !== "object" || typeof sz.w !== "number" || typeof sz.h !== "number") continue;
|
|
9400
9409
|
next[id] = { w: clampNum(sz.w, popMinW(id), fMaxW()), h: clampNum(sz.h, 120, fMaxH()) };
|
|
9410
|
+
if (typeof sz.left === "number") next[id].left = clampNum(sz.left, 8, fMaxW());
|
|
9401
9411
|
}
|
|
9402
9412
|
if (Object.keys(next).length) setPopSizes(next);
|
|
9403
9413
|
}
|
|
@@ -9849,6 +9859,38 @@ function Datatable({
|
|
|
9849
9859
|
middleRows.forEach((r2, i) => m.set(keyOf(r2, keyIndex.get(keyOf(r2)) ?? i), i));
|
|
9850
9860
|
return m;
|
|
9851
9861
|
}, [middleRows, keyIndex]);
|
|
9862
|
+
const cellColIndex = React51__namespace.default.useCallback((field) => ordered.findIndex((c) => c.field === field), [ordered]);
|
|
9863
|
+
const cellRect = React51__namespace.default.useMemo(() => {
|
|
9864
|
+
if (selectionMode !== "cell" || !activeCell) return null;
|
|
9865
|
+
const ar = keyIndex.get(activeCell.key), ac = cellColIndex(activeCell.field);
|
|
9866
|
+
if (ar == null || ac < 0) return null;
|
|
9867
|
+
const anchor = anchorCell || activeCell;
|
|
9868
|
+
const nr = keyIndex.get(anchor.key), nc = cellColIndex(anchor.field);
|
|
9869
|
+
const r0 = nr == null ? ar : Math.min(ar, nr), r1 = nr == null ? ar : Math.max(ar, nr);
|
|
9870
|
+
const c0 = nc < 0 ? ac : Math.min(ac, nc), c1 = nc < 0 ? ac : Math.max(ac, nc);
|
|
9871
|
+
return { r0, r1, c0, c1 };
|
|
9872
|
+
}, [selectionMode, activeCell, anchorCell, keyIndex, cellColIndex]);
|
|
9873
|
+
const activeCellId = React51__namespace.default.useMemo(() => {
|
|
9874
|
+
if (selectionMode !== "cell" || !activeCell) return void 0;
|
|
9875
|
+
const ar = keyIndex.get(activeCell.key), ac = cellColIndex(activeCell.field);
|
|
9876
|
+
return ar == null || ac < 0 ? void 0 : `${gridId}-${ar}-${ac}`;
|
|
9877
|
+
}, [selectionMode, activeCell, keyIndex, cellColIndex, gridId]);
|
|
9878
|
+
const onCellSelRef = React51__namespace.default.useRef(onCellSelectionChange);
|
|
9879
|
+
onCellSelRef.current = onCellSelectionChange;
|
|
9880
|
+
const prevSelSigRef = React51__namespace.default.useRef("");
|
|
9881
|
+
React51__namespace.default.useEffect(() => {
|
|
9882
|
+
const cb = onCellSelRef.current;
|
|
9883
|
+
if (selectionMode !== "cell" || !cb) return;
|
|
9884
|
+
const cells = [];
|
|
9885
|
+
if (cellRect) for (let r2 = cellRect.r0; r2 <= cellRect.r1; r2++) for (let c = cellRect.c0; c <= cellRect.c1; c++) {
|
|
9886
|
+
const row = leafRows[r2], col = ordered[c];
|
|
9887
|
+
if (row && col) cells.push({ key: keyOf(row, r2), field: col.field });
|
|
9888
|
+
}
|
|
9889
|
+
const sig = cells.map((x) => `${x.key}|${x.field}`).join(",");
|
|
9890
|
+
if (sig === prevSelSigRef.current) return;
|
|
9891
|
+
prevSelSigRef.current = sig;
|
|
9892
|
+
cb(cells);
|
|
9893
|
+
}, [cellRect, selectionMode, leafRows, ordered]);
|
|
9852
9894
|
const canReorderRows = rowReorder && !activeGroupBy.length && !sort;
|
|
9853
9895
|
function onRowDrop(targetKey) {
|
|
9854
9896
|
const fromKey = rowDrag.from;
|
|
@@ -10261,6 +10303,7 @@ function Datatable({
|
|
|
10261
10303
|
const next = { key: k, field: col.field };
|
|
10262
10304
|
setActiveCell(next);
|
|
10263
10305
|
setActiveRow(k);
|
|
10306
|
+
if (!(e.shiftKey && anchorCell)) setAnchorCell(next);
|
|
10264
10307
|
onCellClick?.(row[col.field], row, col.field);
|
|
10265
10308
|
onActiveCellChange?.(next);
|
|
10266
10309
|
}
|
|
@@ -10272,6 +10315,24 @@ function Datatable({
|
|
|
10272
10315
|
if (editing) return;
|
|
10273
10316
|
const td = e.target.closest(".twc-dt__td[data-r]");
|
|
10274
10317
|
if (!td) return;
|
|
10318
|
+
if (enableClipboard && selectionMode === "cell" && (e.ctrlKey || e.metaKey)) {
|
|
10319
|
+
const k = e.key.toLowerCase();
|
|
10320
|
+
if (k === "c") {
|
|
10321
|
+
e.preventDefault();
|
|
10322
|
+
copySelection(false);
|
|
10323
|
+
return;
|
|
10324
|
+
}
|
|
10325
|
+
if (k === "x") {
|
|
10326
|
+
e.preventDefault();
|
|
10327
|
+
copySelection(true);
|
|
10328
|
+
return;
|
|
10329
|
+
}
|
|
10330
|
+
if (k === "v") {
|
|
10331
|
+
e.preventDefault();
|
|
10332
|
+
pasteSelection();
|
|
10333
|
+
return;
|
|
10334
|
+
}
|
|
10335
|
+
}
|
|
10275
10336
|
let r2 = +td.getAttribute("data-r"), c = +td.getAttribute("data-c");
|
|
10276
10337
|
const maxR = leafRows.length - 1, maxC = ordered.length - 1;
|
|
10277
10338
|
let handled = true;
|
|
@@ -10324,6 +10385,16 @@ function Datatable({
|
|
|
10324
10385
|
e.preventDefault();
|
|
10325
10386
|
setFocus({ r: r2, c });
|
|
10326
10387
|
focusCell(r2, c);
|
|
10388
|
+
if (selectionMode === "cell") {
|
|
10389
|
+
const nk = keyOf(leafRows[r2], r2), col = ordered[c];
|
|
10390
|
+
if (col) {
|
|
10391
|
+
const nc = { key: nk, field: col.field };
|
|
10392
|
+
setActiveCell(nc);
|
|
10393
|
+
setActiveRow(nk);
|
|
10394
|
+
if (!e.shiftKey) setAnchorCell(nc);
|
|
10395
|
+
onActiveCellChange?.(nc);
|
|
10396
|
+
}
|
|
10397
|
+
}
|
|
10327
10398
|
}
|
|
10328
10399
|
}
|
|
10329
10400
|
React51__namespace.default.useEffect(() => {
|
|
@@ -10440,6 +10511,142 @@ function Datatable({
|
|
|
10440
10511
|
setBatchEdit(null);
|
|
10441
10512
|
closeBatchEdit();
|
|
10442
10513
|
}
|
|
10514
|
+
const [clipboardMsg, setClipboardMsg] = React51__namespace.default.useState("");
|
|
10515
|
+
const clipboardRef = React51__namespace.default.useRef(null);
|
|
10516
|
+
const copyTypeOf = (col) => col && col.copyType != null ? col.copyType : col && col.type === "number" ? "number" : "text";
|
|
10517
|
+
const writeClipboard = (text) => {
|
|
10518
|
+
const execFallback = () => {
|
|
10519
|
+
try {
|
|
10520
|
+
if (typeof document !== "undefined") {
|
|
10521
|
+
const ta = document.createElement("textarea");
|
|
10522
|
+
ta.value = text;
|
|
10523
|
+
ta.style.position = "fixed";
|
|
10524
|
+
ta.style.opacity = "0";
|
|
10525
|
+
document.body.appendChild(ta);
|
|
10526
|
+
ta.focus();
|
|
10527
|
+
ta.select();
|
|
10528
|
+
document.execCommand("copy");
|
|
10529
|
+
document.body.removeChild(ta);
|
|
10530
|
+
}
|
|
10531
|
+
} catch {
|
|
10532
|
+
}
|
|
10533
|
+
};
|
|
10534
|
+
try {
|
|
10535
|
+
if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.writeText) return navigator.clipboard.writeText(text).catch(execFallback);
|
|
10536
|
+
} catch {
|
|
10537
|
+
}
|
|
10538
|
+
execFallback();
|
|
10539
|
+
return Promise.resolve();
|
|
10540
|
+
};
|
|
10541
|
+
const writeCellPatches = (patchByKey) => {
|
|
10542
|
+
if (!patchByKey.size) return 0;
|
|
10543
|
+
const changed = [];
|
|
10544
|
+
const nextAll = rows.map((r2, i) => {
|
|
10545
|
+
const k = keyOf(r2, i);
|
|
10546
|
+
const patch = patchByKey.get(k);
|
|
10547
|
+
if (!patch) return r2;
|
|
10548
|
+
const updated = { ...r2, ...patch };
|
|
10549
|
+
changed.push([updated, r2, patch]);
|
|
10550
|
+
return updated;
|
|
10551
|
+
});
|
|
10552
|
+
changed.forEach(([updated, orig, patch]) => {
|
|
10553
|
+
for (const f of Object.keys(patch)) onRowUpdate?.(updated, orig, f);
|
|
10554
|
+
});
|
|
10555
|
+
if (onRowsChange && changed.length) onRowsChange(nextAll);
|
|
10556
|
+
return changed.length;
|
|
10557
|
+
};
|
|
10558
|
+
const rectCells = () => {
|
|
10559
|
+
if (!cellRect) return null;
|
|
10560
|
+
const out = [];
|
|
10561
|
+
for (let r2 = cellRect.r0; r2 <= cellRect.r1; r2++) {
|
|
10562
|
+
const row = leafRows[r2];
|
|
10563
|
+
if (!row) continue;
|
|
10564
|
+
const line = [];
|
|
10565
|
+
for (let c = cellRect.c0; c <= cellRect.c1; c++) {
|
|
10566
|
+
const col = ordered[c];
|
|
10567
|
+
if (col) line.push({ key: keyOf(row, r2), field: col.field, col, value: getColVal(col, row) });
|
|
10568
|
+
}
|
|
10569
|
+
out.push(line);
|
|
10570
|
+
}
|
|
10571
|
+
return out.length ? out : null;
|
|
10572
|
+
};
|
|
10573
|
+
const copySelection = (cut) => {
|
|
10574
|
+
const grid = rectCells();
|
|
10575
|
+
if (!grid) return;
|
|
10576
|
+
const tsv = grid.map((line) => line.map((cell) => cell.value == null ? "" : String(cell.value)).join(" ")).join("\n");
|
|
10577
|
+
clipboardRef.current = { tsv, colTypes: grid[0].map((cell) => copyTypeOf(cell.col)), matrix: grid.map((line) => line.map((cell) => cell.value)) };
|
|
10578
|
+
writeClipboard(tsv);
|
|
10579
|
+
const n = grid.reduce((a, line) => a + line.length, 0);
|
|
10580
|
+
if (cut) {
|
|
10581
|
+
const patchByKey = /* @__PURE__ */ new Map();
|
|
10582
|
+
let clearable = 0;
|
|
10583
|
+
for (const line of grid) for (const cell of line) {
|
|
10584
|
+
if (!isColEditable(cell.col)) continue;
|
|
10585
|
+
clearable++;
|
|
10586
|
+
const p = patchByKey.get(cell.key) || {};
|
|
10587
|
+
p[cell.field] = cell.col.type === "number" ? null : "";
|
|
10588
|
+
patchByKey.set(cell.key, p);
|
|
10589
|
+
}
|
|
10590
|
+
writeCellPatches(patchByKey);
|
|
10591
|
+
setClipboardMsg(`Cut ${clearable} cell${clearable === 1 ? "" : "s"}${clearable < n ? `, ${n - clearable} read-only kept` : ""}`);
|
|
10592
|
+
} else {
|
|
10593
|
+
setClipboardMsg(`Copied ${n} cell${n === 1 ? "" : "s"}`);
|
|
10594
|
+
}
|
|
10595
|
+
};
|
|
10596
|
+
const pasteSelection = async () => {
|
|
10597
|
+
if (!cellRect) return;
|
|
10598
|
+
let text = null;
|
|
10599
|
+
try {
|
|
10600
|
+
if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.readText) text = await navigator.clipboard.readText();
|
|
10601
|
+
} catch {
|
|
10602
|
+
setClipboardMsg("Paste unavailable \u2014 clipboard permission denied");
|
|
10603
|
+
return;
|
|
10604
|
+
}
|
|
10605
|
+
if (text == null) {
|
|
10606
|
+
setClipboardMsg("Nothing to paste");
|
|
10607
|
+
return;
|
|
10608
|
+
}
|
|
10609
|
+
const inApp = clipboardRef.current && clipboardRef.current.tsv === text ? clipboardRef.current : null;
|
|
10610
|
+
let matrix;
|
|
10611
|
+
if (inApp) matrix = inApp.matrix;
|
|
10612
|
+
else {
|
|
10613
|
+
const lines = text.replace(/\r\n?/g, "\n").split("\n");
|
|
10614
|
+
if (lines.length && lines[lines.length - 1] === "") lines.pop();
|
|
10615
|
+
matrix = lines.map((line) => line.split(" "));
|
|
10616
|
+
}
|
|
10617
|
+
const patchByKey = /* @__PURE__ */ new Map();
|
|
10618
|
+
let written = 0, skipped = 0;
|
|
10619
|
+
for (let i = 0; i < matrix.length; i++) {
|
|
10620
|
+
const rr = cellRect.r0 + i;
|
|
10621
|
+
const row = leafRows[rr];
|
|
10622
|
+
if (!row) break;
|
|
10623
|
+
for (let j = 0; j < matrix[i].length; j++) {
|
|
10624
|
+
const cc = cellRect.c0 + j;
|
|
10625
|
+
const col = ordered[cc];
|
|
10626
|
+
if (!col) break;
|
|
10627
|
+
if (!isColEditable(col)) {
|
|
10628
|
+
skipped++;
|
|
10629
|
+
continue;
|
|
10630
|
+
}
|
|
10631
|
+
if (inApp && inApp.colTypes[j] != null && inApp.colTypes[j] !== copyTypeOf(col)) {
|
|
10632
|
+
skipped++;
|
|
10633
|
+
continue;
|
|
10634
|
+
}
|
|
10635
|
+
let v = matrix[i][j];
|
|
10636
|
+
if (col.type === "number") {
|
|
10637
|
+
v = v === "" ? null : Number(v);
|
|
10638
|
+
if (Number.isNaN(v)) v = null;
|
|
10639
|
+
}
|
|
10640
|
+
const k = keyOf(row, rr);
|
|
10641
|
+
const p = patchByKey.get(k) || {};
|
|
10642
|
+
p[col.field] = v;
|
|
10643
|
+
patchByKey.set(k, p);
|
|
10644
|
+
written++;
|
|
10645
|
+
}
|
|
10646
|
+
}
|
|
10647
|
+
writeCellPatches(patchByKey);
|
|
10648
|
+
setClipboardMsg(`Pasted ${written} cell${written === 1 ? "" : "s"}${skipped ? `, ${skipped} skipped (incompatible column)` : ""}`);
|
|
10649
|
+
};
|
|
10443
10650
|
React51__namespace.default.useEffect(() => {
|
|
10444
10651
|
if (!editing) return;
|
|
10445
10652
|
const onDown = (e) => {
|
|
@@ -10696,6 +10903,7 @@ function Datatable({
|
|
|
10696
10903
|
if (node) {
|
|
10697
10904
|
node.style.removeProperty("--twc-dt-pop-w");
|
|
10698
10905
|
node.style.removeProperty("--twc-dt-pop-h");
|
|
10906
|
+
node.style.removeProperty("left");
|
|
10699
10907
|
node.removeAttribute("data-pop-sized");
|
|
10700
10908
|
}
|
|
10701
10909
|
setPopSizes((s) => {
|
|
@@ -10705,7 +10913,7 @@ function Datatable({
|
|
|
10705
10913
|
return n;
|
|
10706
10914
|
});
|
|
10707
10915
|
};
|
|
10708
|
-
const startPopResize = (id) => (e) => {
|
|
10916
|
+
const startPopResize = (id, side) => (e) => {
|
|
10709
10917
|
if (e.button != null && e.button !== 0) return;
|
|
10710
10918
|
e.preventDefault();
|
|
10711
10919
|
e.stopPropagation();
|
|
@@ -10714,21 +10922,27 @@ function Datatable({
|
|
|
10714
10922
|
const grip = e.currentTarget;
|
|
10715
10923
|
const startX = e.clientX, startY = e.clientY;
|
|
10716
10924
|
const r2 = pop.getBoundingClientRect();
|
|
10717
|
-
const startW = r2.width, startH = r2.height;
|
|
10925
|
+
const startW = r2.width, startH = r2.height, startLeft = r2.left, startRight = r2.right;
|
|
10718
10926
|
const dir = typeof getComputedStyle !== "undefined" && getComputedStyle(pop).direction === "rtl" ? -1 : 1;
|
|
10927
|
+
const toStart = side === "start";
|
|
10719
10928
|
pop.style.setProperty("--twc-dt-pop-w", `${startW}px`);
|
|
10720
10929
|
pop.style.setProperty("--twc-dt-pop-h", `${startH}px`);
|
|
10721
10930
|
grip.setAttribute("data-active", "true");
|
|
10722
10931
|
pop.setAttribute("data-pop-sized", "");
|
|
10723
|
-
let lw = startW, lh = startH;
|
|
10932
|
+
let lw = startW, lh = startH, ll = startLeft;
|
|
10724
10933
|
const onMove = (ev) => {
|
|
10725
|
-
|
|
10934
|
+
const dw = toStart ? (startX - ev.clientX) * dir : (ev.clientX - startX) * dir;
|
|
10935
|
+
lw = clampNum(startW + dw, popMinW(id), fMaxW());
|
|
10726
10936
|
lh = clampNum(startH + (ev.clientY - startY), 120, fMaxH());
|
|
10727
10937
|
pop.style.setProperty("--twc-dt-pop-w", `${lw}px`);
|
|
10728
10938
|
pop.style.setProperty("--twc-dt-pop-h", `${lh}px`);
|
|
10939
|
+
if (toStart) {
|
|
10940
|
+
ll = Math.max(8, startRight - lw);
|
|
10941
|
+
pop.style.left = `${ll}px`;
|
|
10942
|
+
}
|
|
10729
10943
|
};
|
|
10730
10944
|
const onUp = () => {
|
|
10731
|
-
setPopSizes((s) => ({ ...s, [id]: { w: lw, h: lh } }));
|
|
10945
|
+
setPopSizes((s) => ({ ...s, [id]: { ...s[id] || {}, w: lw, h: lh, ...toStart ? { left: ll } : {} } }));
|
|
10732
10946
|
grip.removeAttribute("data-active");
|
|
10733
10947
|
window.removeEventListener("pointermove", onMove);
|
|
10734
10948
|
window.removeEventListener("pointerup", onUp);
|
|
@@ -10736,7 +10950,7 @@ function Datatable({
|
|
|
10736
10950
|
window.addEventListener("pointermove", onMove);
|
|
10737
10951
|
window.addEventListener("pointerup", onUp);
|
|
10738
10952
|
};
|
|
10739
|
-
const onPopGripKey = (id) => (e) => {
|
|
10953
|
+
const onPopGripKey = (id, side) => (e) => {
|
|
10740
10954
|
if (e.key === "Enter" || e.key === " " || e.key === "Backspace") {
|
|
10741
10955
|
e.preventDefault();
|
|
10742
10956
|
clearPop(id, e.currentTarget.closest(".twc-dt__pop"));
|
|
@@ -10761,25 +10975,54 @@ function Datatable({
|
|
|
10761
10975
|
w = fMaxW();
|
|
10762
10976
|
h = fMaxH();
|
|
10763
10977
|
}
|
|
10764
|
-
|
|
10978
|
+
w = clampNum(w, popMinW(id), fMaxW());
|
|
10979
|
+
h = clampNum(h, 120, fMaxH());
|
|
10980
|
+
const left = side === "start" ? Math.max(8, r2.right - w) : void 0;
|
|
10981
|
+
setPopSizes((s) => ({ ...s, [id]: { ...s[id] || {}, w, h, ...left != null ? { left } : {} } }));
|
|
10765
10982
|
};
|
|
10766
|
-
const popStyle = (id) =>
|
|
10767
|
-
|
|
10768
|
-
|
|
10769
|
-
{
|
|
10770
|
-
|
|
10771
|
-
|
|
10772
|
-
|
|
10773
|
-
|
|
10774
|
-
|
|
10775
|
-
|
|
10776
|
-
|
|
10777
|
-
|
|
10778
|
-
|
|
10779
|
-
|
|
10983
|
+
const popStyle = (id) => {
|
|
10984
|
+
const s = popSizes[id];
|
|
10985
|
+
if (!s) return null;
|
|
10986
|
+
const st = { "--twc-dt-pop-w": `${s.w}px`, "--twc-dt-pop-h": `${s.h}px` };
|
|
10987
|
+
if (s.left != null) st.left = `${s.left}px`;
|
|
10988
|
+
return st;
|
|
10989
|
+
};
|
|
10990
|
+
const popGrip = (id) => resizablePopovers ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10991
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10992
|
+
"span",
|
|
10993
|
+
{
|
|
10994
|
+
className: "twc-dt__pop-grip",
|
|
10995
|
+
"data-side": "end",
|
|
10996
|
+
role: "slider",
|
|
10997
|
+
tabIndex: 0,
|
|
10998
|
+
"aria-label": "Resize panel (Enter or double-click to reset)",
|
|
10999
|
+
"aria-valuetext": popSizes[id] ? `Width ${Math.round(popSizes[id].w)} pixels, height ${Math.round(popSizes[id].h)} pixels` : "Default size",
|
|
11000
|
+
onPointerDown: startPopResize(id, "end"),
|
|
11001
|
+
onKeyDown: onPopGripKey(id, "end"),
|
|
11002
|
+
onDoubleClick: (e) => {
|
|
11003
|
+
e.preventDefault();
|
|
11004
|
+
clearPop(id, e.currentTarget.closest(".twc-dt__pop"));
|
|
11005
|
+
}
|
|
10780
11006
|
}
|
|
10781
|
-
|
|
10782
|
-
|
|
11007
|
+
),
|
|
11008
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11009
|
+
"span",
|
|
11010
|
+
{
|
|
11011
|
+
className: "twc-dt__pop-grip",
|
|
11012
|
+
"data-side": "start",
|
|
11013
|
+
role: "slider",
|
|
11014
|
+
tabIndex: 0,
|
|
11015
|
+
"aria-label": "Resize panel leftward (Enter or double-click to reset)",
|
|
11016
|
+
"aria-valuetext": popSizes[id] ? `Width ${Math.round(popSizes[id].w)} pixels, height ${Math.round(popSizes[id].h)} pixels` : "Default size",
|
|
11017
|
+
onPointerDown: startPopResize(id, "start"),
|
|
11018
|
+
onKeyDown: onPopGripKey(id, "start"),
|
|
11019
|
+
onDoubleClick: (e) => {
|
|
11020
|
+
e.preventDefault();
|
|
11021
|
+
clearPop(id, e.currentTarget.closest(".twc-dt__pop"));
|
|
11022
|
+
}
|
|
11023
|
+
}
|
|
11024
|
+
)
|
|
11025
|
+
] }) : null;
|
|
10783
11026
|
const fieldHandle = (field, rowIdx) => resizableFilters && rowIdx === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
10784
11027
|
"span",
|
|
10785
11028
|
{
|
|
@@ -10935,22 +11178,27 @@ function Datatable({
|
|
|
10935
11178
|
const editable = isColEditable(c);
|
|
10936
11179
|
const isEditing = editing && editing.key === k && editing.field === c.field;
|
|
10937
11180
|
const cellActive = selectionMode === "cell" && activeCell && activeCell.key === k && activeCell.field === c.field;
|
|
11181
|
+
const cellSelected = selectionMode === "cell" && cellRect && ri >= cellRect.r0 && ri <= cellRect.r1 && ci >= cellRect.c0 && ci <= cellRect.c1;
|
|
11182
|
+
const cellId = selectionMode === "cell" ? `${gridId}-${ri}-${ci}` : void 0;
|
|
10938
11183
|
const display = c.valueFormatter ? c.valueFormatter(val, row) : val;
|
|
10939
11184
|
const cellTitle = !isActions && !c.renderCell && !isEditing && (typeof display === "string" || typeof display === "number") ? String(display) : void 0;
|
|
10940
11185
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10941
11186
|
"td",
|
|
10942
11187
|
{
|
|
11188
|
+
id: cellId,
|
|
10943
11189
|
className: "twc-dt__td",
|
|
10944
11190
|
role: "gridcell",
|
|
10945
11191
|
"data-r": ri,
|
|
10946
11192
|
"data-c": ci,
|
|
10947
11193
|
"aria-colindex": ci + 1 + (checkboxSelection ? 1 : 0),
|
|
10948
11194
|
tabIndex: focus.r === ri && focus.c === ci ? 0 : -1,
|
|
11195
|
+
"aria-selected": cellSelected || void 0,
|
|
10949
11196
|
"data-num": c.type === "number" || void 0,
|
|
10950
11197
|
"data-actions": isActions || void 0,
|
|
10951
11198
|
"data-editable": editable && !isEditing || void 0,
|
|
10952
11199
|
"data-editing": isEditing || void 0,
|
|
10953
11200
|
"data-cell-active": cellActive || void 0,
|
|
11201
|
+
"data-cell-selected": cellSelected || void 0,
|
|
10954
11202
|
"data-wrap": wrapped.has(c.field) || void 0,
|
|
10955
11203
|
"data-pin": st.pin,
|
|
10956
11204
|
"data-pin-edge": st.edge,
|
|
@@ -11312,6 +11560,7 @@ function Datatable({
|
|
|
11312
11560
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dt__groupbar-clear", onClick: () => setGroupBy([]), children: "Clear all" })
|
|
11313
11561
|
] }) : null,
|
|
11314
11562
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__sr", role: "status", "aria-live": "polite", children: reorderMsg }),
|
|
11563
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__sr", role: "status", "aria-live": "polite", children: clipboardMsg }),
|
|
11315
11564
|
pivotActive ? renderPivot() : /* @__PURE__ */ jsxRuntime.jsx(
|
|
11316
11565
|
"div",
|
|
11317
11566
|
{
|
|
@@ -11333,6 +11582,8 @@ function Datatable({
|
|
|
11333
11582
|
"aria-label": ariaLabelAttr || ariaLabel,
|
|
11334
11583
|
"aria-rowcount": totalRows + 1,
|
|
11335
11584
|
"aria-colcount": ordered.length + (checkboxSelection ? 1 : 0),
|
|
11585
|
+
"aria-multiselectable": selectionMode === "cell" || void 0,
|
|
11586
|
+
"aria-activedescendant": activeCellId,
|
|
11336
11587
|
"aria-busy": loading || void 0,
|
|
11337
11588
|
onKeyDown: onGridKeyDown,
|
|
11338
11589
|
children: [
|