twico-ui 1.33.0 → 1.34.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 +20 -0
- package/dist/index.cjs +270 -164
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.mjs +270 -164
- package/dist/index.mjs.map +1 -1
- package/llms.txt +4 -0
- package/package.json +4 -4
package/dist/index.mjs
CHANGED
|
@@ -7942,6 +7942,9 @@ var TOOLTIP_CSS = `
|
|
|
7942
7942
|
.twc-tooltip-wrap { display: inline-flex; }
|
|
7943
7943
|
.twc-tooltip {
|
|
7944
7944
|
position: fixed; z-index: var(--z-tooltip);
|
|
7945
|
+
/* #348: purely presentational \u2014 the bubble must NEVER intercept the pointer, so neither a hidden
|
|
7946
|
+
(opacity:0) nor a shown bubble can block neighbouring cells/buttons (matches MUI/Radix tooltips). */
|
|
7947
|
+
pointer-events: none;
|
|
7945
7948
|
padding: 6px 10px; border-radius: var(--radius-md);
|
|
7946
7949
|
background: var(--color-text); color: var(--color-surface);
|
|
7947
7950
|
font-family: var(--font-sans); font-size: var(--text-xs); font-weight: var(--font-medium);
|
|
@@ -7953,7 +7956,6 @@ var TOOLTIP_CSS = `
|
|
|
7953
7956
|
width: max-content; max-width: var(--_tw-maxw, 320px); box-shadow: var(--shadow-md);
|
|
7954
7957
|
opacity: 0; transform: scale(0.9); transition: opacity var(--duration-fast) var(--ease-out), transform var(--duration-fast) var(--ease-spring);
|
|
7955
7958
|
}
|
|
7956
|
-
.twc-tooltip[data-show="true"] { pointer-events: auto; }
|
|
7957
7959
|
.twc-tooltip[data-show="true"] { opacity: 1; transform: scale(1); }
|
|
7958
7960
|
.twc-tooltip[data-place="top"] { transform-origin: bottom center; translate: -50% 0; }
|
|
7959
7961
|
.twc-tooltip[data-place="bottom"] { transform-origin: top center; translate: -50% 0; }
|
|
@@ -8000,9 +8002,6 @@ function Tooltip({
|
|
|
8000
8002
|
clearTimeout(closeTimer.current);
|
|
8001
8003
|
closeTimer.current = setTimeout(() => setShowU(false), 120);
|
|
8002
8004
|
};
|
|
8003
|
-
const cancelClose = () => {
|
|
8004
|
-
clearTimeout(closeTimer.current);
|
|
8005
|
-
};
|
|
8006
8005
|
React51__default.useEffect(() => () => {
|
|
8007
8006
|
clearTimeout(timer.current);
|
|
8008
8007
|
clearTimeout(closeTimer.current);
|
|
@@ -8078,8 +8077,6 @@ function Tooltip({
|
|
|
8078
8077
|
"data-show": show || void 0,
|
|
8079
8078
|
role: "tooltip",
|
|
8080
8079
|
"aria-hidden": show ? void 0 : "true",
|
|
8081
|
-
onMouseEnter: anchored ? void 0 : cancelClose,
|
|
8082
|
-
onMouseLeave: anchored ? void 0 : close,
|
|
8083
8080
|
style: {
|
|
8084
8081
|
position: "fixed",
|
|
8085
8082
|
left: coords.left,
|
|
@@ -8365,6 +8362,16 @@ var DT_CSS = `
|
|
|
8365
8362
|
.twc-dt__group-sub span { font-variant-numeric: tabular-nums; }
|
|
8366
8363
|
.twc-dt__group-sub span b { color: var(--color-text); }
|
|
8367
8364
|
|
|
8365
|
+
/* #350: expandable row detail (renderRowDetail) \u2014 leading chevron column + full-width detail row */
|
|
8366
|
+
.twc-dt__expand-cell { text-align: center; padding-inline: 0; }
|
|
8367
|
+
.twc-dt__expand-btn { display: inline-grid; place-items: center; width: 24px; height: 24px; border: none; padding: 0; background: transparent; color: var(--color-text-subtle); cursor: pointer; border-radius: var(--radius-sm); }
|
|
8368
|
+
.twc-dt__expand-btn:hover { color: var(--color-text); background: color-mix(in srgb, currentColor 12%, transparent); }
|
|
8369
|
+
.twc-dt__expand-btn:focus-visible { outline: none; box-shadow: var(--ring); }
|
|
8370
|
+
.twc-dt__expand-chev { display: inline-flex; transform: rotate(-90deg); transition: transform var(--duration-base) var(--ease-spring); }
|
|
8371
|
+
.twc-dt__expand-chev[data-open] { transform: rotate(0deg); color: var(--color-primary); }
|
|
8372
|
+
.twc-dt__expand-chev svg { width: 16px; height: 16px; }
|
|
8373
|
+
.twc-dt__detail-cell { box-sizing: border-box; background: var(--color-surface-sunken); border-bottom: var(--border-thin) solid var(--color-divider); padding: 12px 16px; }
|
|
8374
|
+
|
|
8368
8375
|
/* Pivot view */
|
|
8369
8376
|
.twc-dt__pivot { table-layout: auto; width: 100%; }
|
|
8370
8377
|
.twc-dt__pivot th, .twc-dt__pivot td { white-space: nowrap; }
|
|
@@ -9312,6 +9319,13 @@ function Datatable({
|
|
|
9312
9319
|
virtualized = false,
|
|
9313
9320
|
overscan = 8,
|
|
9314
9321
|
rowHeight,
|
|
9322
|
+
// #350 (first pass): expandable/collapsible rows. `renderRowDetail(row)` returns the detail panel for a
|
|
9323
|
+
// row (return null/undefined ⇒ that row isn't expandable). Presence of the fn enables a leading chevron
|
|
9324
|
+
// column + a full-width detail <tr> under each expanded row. Expansion is uncontrolled unless
|
|
9325
|
+
// `expandedRowIds` is supplied; `onExpandedRowsChange` fires the next expanded-key array on every toggle.
|
|
9326
|
+
renderRowDetail,
|
|
9327
|
+
expandedRowIds,
|
|
9328
|
+
onExpandedRowsChange,
|
|
9315
9329
|
className = "",
|
|
9316
9330
|
...rest
|
|
9317
9331
|
}) {
|
|
@@ -9518,6 +9532,12 @@ function Datatable({
|
|
|
9518
9532
|
const gridRef = React51__default.useRef(null);
|
|
9519
9533
|
const [groupBy, setGroupBy] = React51__default.useState(rowGrouping || []);
|
|
9520
9534
|
const [collapsed, setCollapsed] = React51__default.useState(() => /* @__PURE__ */ new Set());
|
|
9535
|
+
const [internalExpanded, setInternalExpanded] = React51__default.useState(() => /* @__PURE__ */ new Set());
|
|
9536
|
+
const expandControlled = expandedRowIds !== void 0;
|
|
9537
|
+
const expandedSet = React51__default.useMemo(
|
|
9538
|
+
() => new Set(expandControlled ? expandedRowIds : internalExpanded),
|
|
9539
|
+
[expandControlled, expandedRowIds, internalExpanded]
|
|
9540
|
+
);
|
|
9521
9541
|
const [pinnedRows, setPinnedRows] = React51__default.useState({ top: [], bottom: [] });
|
|
9522
9542
|
const [headH, setHeadH] = React51__default.useState(41);
|
|
9523
9543
|
const theadRef = React51__default.useRef(null);
|
|
@@ -9919,7 +9939,9 @@ function Datatable({
|
|
|
9919
9939
|
}, [pins, effectiveHidden, visibleCols, colByField, order]);
|
|
9920
9940
|
const NUM_W = 56;
|
|
9921
9941
|
const CHK_W = checkboxSelection ? rowReorder ? 68 : 44 : 0;
|
|
9922
|
-
const
|
|
9942
|
+
const hasRowDetail = typeof renderRowDetail === "function";
|
|
9943
|
+
const EXP_W = hasRowDetail ? 44 : 0;
|
|
9944
|
+
const numLeft = EXP_W + CHK_W;
|
|
9923
9945
|
const leadW = numLeft + (showRowNum ? NUM_W : 0);
|
|
9924
9946
|
const visLeft = React51__default.useMemo(() => pins.left.filter((f) => colByField[f] && !effectiveHidden.has(f)), [pins.left, colByField, effectiveHidden]);
|
|
9925
9947
|
const visRight = React51__default.useMemo(() => pins.right.filter((f) => colByField[f] && !effectiveHidden.has(f)), [pins.right, colByField, effectiveHidden]);
|
|
@@ -10514,6 +10536,12 @@ function Datatable({
|
|
|
10514
10536
|
return n;
|
|
10515
10537
|
});
|
|
10516
10538
|
}
|
|
10539
|
+
function toggleRowDetail(k) {
|
|
10540
|
+
const n = new Set(expandedSet);
|
|
10541
|
+
n.has(k) ? n.delete(k) : n.add(k);
|
|
10542
|
+
onExpandedRowsChange?.([...n]);
|
|
10543
|
+
if (!expandControlled) setInternalExpanded(n);
|
|
10544
|
+
}
|
|
10517
10545
|
function handleRowClick(e, k, row) {
|
|
10518
10546
|
if (selectionMode === "none") return;
|
|
10519
10547
|
if (e.target.closest("button, a, input, select, .twc-dt__check, .twc-dt__editor-wrap")) return;
|
|
@@ -11360,7 +11388,7 @@ function Datatable({
|
|
|
11360
11388
|
const manageableCols = cols.filter((c) => c.field !== "__pinactions__");
|
|
11361
11389
|
const visibleColCount = manageableCols.filter((c) => !effectiveHidden.has(c.field)).length;
|
|
11362
11390
|
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) }));
|
|
11363
|
-
const totalCols = ordered.length + (checkboxSelection ? 1 : 0) + (showRowNum ? 1 : 0);
|
|
11391
|
+
const totalCols = ordered.length + (checkboxSelection ? 1 : 0) + (showRowNum ? 1 : 0) + (hasRowDetail ? 1 : 0);
|
|
11364
11392
|
function renderGroupRow(item) {
|
|
11365
11393
|
const subs = aggOn ? subtotalText(item.rows) : [];
|
|
11366
11394
|
return /* @__PURE__ */ jsx("tr", { className: "twc-dt__group-row", role: "row", children: /* @__PURE__ */ jsxs("td", { className: "twc-dt__group-cell", role: "gridcell", colSpan: totalCols, style: { maxWidth: "none" }, children: [
|
|
@@ -11414,6 +11442,9 @@ function Datatable({
|
|
|
11414
11442
|
function renderLeaf(row, ri, pinSide, midIdx) {
|
|
11415
11443
|
const k = keyOf(row, ri);
|
|
11416
11444
|
const sel = selected.has(k);
|
|
11445
|
+
const detail = hasRowDetail && !pinSide ? renderRowDetail(row) : null;
|
|
11446
|
+
const expandable = detail != null;
|
|
11447
|
+
const open = expandable && expandedSet.has(k);
|
|
11417
11448
|
const rowActive = selectionMode === "row" && activeRowVal === k;
|
|
11418
11449
|
const stickyStyle = pinSide === "top" ? { position: "sticky", top: headH, zIndex: 5 } : pinSide === "bottom" ? { position: "sticky", bottom: 0, zIndex: 5 } : void 0;
|
|
11419
11450
|
const h = rowHeights[k];
|
|
@@ -11421,159 +11452,165 @@ function Datatable({
|
|
|
11421
11452
|
const reorderable = canReorderRows && !pinSide;
|
|
11422
11453
|
const grabbed = rowGrab && rowGrab.key === k;
|
|
11423
11454
|
const grabTarget = rowGrab && !grabbed && midIdx != null && rowGrab.index === midIdx ? rowGrab.index >= keyIndexMid.get(rowGrab.key) ? "after" : "before" : void 0;
|
|
11424
|
-
return /* @__PURE__ */ jsxs(
|
|
11425
|
-
|
|
11426
|
-
|
|
11427
|
-
|
|
11428
|
-
|
|
11429
|
-
|
|
11430
|
-
|
|
11431
|
-
|
|
11432
|
-
|
|
11433
|
-
|
|
11434
|
-
|
|
11435
|
-
|
|
11436
|
-
|
|
11437
|
-
|
|
11438
|
-
|
|
11439
|
-
|
|
11440
|
-
|
|
11441
|
-
|
|
11442
|
-
|
|
11443
|
-
|
|
11444
|
-
|
|
11445
|
-
|
|
11446
|
-
|
|
11447
|
-
|
|
11448
|
-
|
|
11449
|
-
|
|
11450
|
-
|
|
11451
|
-
|
|
11452
|
-
|
|
11453
|
-
|
|
11454
|
-
|
|
11455
|
-
|
|
11456
|
-
|
|
11457
|
-
|
|
11458
|
-
|
|
11459
|
-
|
|
11460
|
-
|
|
11461
|
-
|
|
11462
|
-
|
|
11463
|
-
|
|
11464
|
-
/* @__PURE__ */
|
|
11465
|
-
|
|
11466
|
-
|
|
11467
|
-
|
|
11455
|
+
return /* @__PURE__ */ jsxs(React51__default.Fragment, { children: [
|
|
11456
|
+
/* @__PURE__ */ jsxs(
|
|
11457
|
+
"tr",
|
|
11458
|
+
{
|
|
11459
|
+
className: "twc-dt__row",
|
|
11460
|
+
role: "row",
|
|
11461
|
+
"aria-rowindex": (paginated && !serverMode ? pageVal * sizeVal : 0) + ri + 2,
|
|
11462
|
+
"aria-selected": (checkboxSelection ? sel : rowActive) || void 0,
|
|
11463
|
+
"data-op": row.__diffop || void 0,
|
|
11464
|
+
"data-selected": sel || void 0,
|
|
11465
|
+
"data-active": rowActive || void 0,
|
|
11466
|
+
"data-pinned-row": pinSide || void 0,
|
|
11467
|
+
"data-reorderable": reorderable || void 0,
|
|
11468
|
+
"data-row-dragging": rowDrag.from === k || void 0,
|
|
11469
|
+
"data-row-grabbed": grabbed || void 0,
|
|
11470
|
+
"data-row-grabtarget": grabTarget,
|
|
11471
|
+
"data-row-dropbefore": reorderable && rowDrag.over === k && !rowDrag.after || void 0,
|
|
11472
|
+
"data-row-dropafter": reorderable && rowDrag.over === k && rowDrag.after || void 0,
|
|
11473
|
+
"data-vrow": virtualizing && midIdx != null ? String(k) : void 0,
|
|
11474
|
+
"data-selectable": selectionMode !== "none" || void 0,
|
|
11475
|
+
style: Object.keys(rowStyle).length ? rowStyle : void 0,
|
|
11476
|
+
draggable: reorderable || void 0,
|
|
11477
|
+
onDragStart: reorderable ? (e) => {
|
|
11478
|
+
setRowDrag({ from: k, over: null, after: false });
|
|
11479
|
+
e.dataTransfer.effectAllowed = "move";
|
|
11480
|
+
e.dataTransfer.setData("text/plain", String(k));
|
|
11481
|
+
} : void 0,
|
|
11482
|
+
onDragOver: reorderable && rowDrag.from != null ? (e) => {
|
|
11483
|
+
e.preventDefault();
|
|
11484
|
+
const r2 = e.currentTarget.getBoundingClientRect();
|
|
11485
|
+
const after = e.clientY > r2.top + r2.height / 2;
|
|
11486
|
+
setRowDrag((d) => d.over === k && d.after === after ? d : { ...d, over: k, after });
|
|
11487
|
+
} : void 0,
|
|
11488
|
+
onDrop: reorderable && rowDrag.from != null ? (e) => {
|
|
11489
|
+
e.preventDefault();
|
|
11490
|
+
onRowDrop(k);
|
|
11491
|
+
} : void 0,
|
|
11492
|
+
onDragEnd: reorderable ? () => setRowDrag({ from: null, over: null, after: false }) : void 0,
|
|
11493
|
+
onClick: (e) => handleRowClick(e, k, row),
|
|
11494
|
+
children: [
|
|
11495
|
+
hasRowDetail ? /* @__PURE__ */ jsx("td", { className: "twc-dt__td twc-dt__expand-cell", role: "gridcell", "data-pin": "left", "data-pin-edge": checkboxSelection || showRowNum || visLeft.length ? void 0 : "left", style: { insetInlineStart: 0, width: EXP_W }, children: expandable ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__expand-btn", "aria-expanded": open, "aria-controls": open ? `${gridId}-detail-${ri}` : void 0, "aria-label": open ? "Collapse row" : "Expand row", onClick: (e) => {
|
|
11496
|
+
e.stopPropagation();
|
|
11497
|
+
toggleRowDetail(k);
|
|
11498
|
+
}, children: /* @__PURE__ */ jsx("span", { className: "twc-dt__expand-chev", "data-open": open || void 0, children: /* @__PURE__ */ jsx(Svg, { d: I.chevDown }) }) }) : null }) : null,
|
|
11499
|
+
checkboxSelection ? /* @__PURE__ */ jsxs("td", { className: "twc-dt__td", role: "gridcell", "data-pin": "left", "data-pin-edge": visLeft.length || showRowNum ? void 0 : "left", style: { insetInlineStart: EXP_W, width: CHK_W }, children: [
|
|
11500
|
+
/* @__PURE__ */ jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 4 }, children: [
|
|
11501
|
+
reorderable ? rowHandle(k, midIdx, row) : null,
|
|
11502
|
+
/* @__PURE__ */ jsx(
|
|
11503
|
+
"span",
|
|
11504
|
+
{
|
|
11505
|
+
className: "twc-dt__check",
|
|
11506
|
+
"data-checked": sel || void 0,
|
|
11507
|
+
onClick: () => toggleRow(k),
|
|
11508
|
+
role: "checkbox",
|
|
11509
|
+
"aria-checked": sel,
|
|
11510
|
+
"aria-label": "Select row",
|
|
11511
|
+
tabIndex: 0,
|
|
11512
|
+
onKeyDown: (e) => {
|
|
11513
|
+
if (e.key === " " || e.key === "Enter") {
|
|
11514
|
+
e.preventDefault();
|
|
11515
|
+
toggleRow(k);
|
|
11516
|
+
}
|
|
11517
|
+
},
|
|
11518
|
+
children: /* @__PURE__ */ jsx(Svg, { d: I.check })
|
|
11519
|
+
}
|
|
11520
|
+
)
|
|
11521
|
+
] }),
|
|
11522
|
+
rowResize && !pinSide ? /* @__PURE__ */ jsx("span", { className: "twc-dt__row-resizer", title: "Drag to resize row", onPointerDown: (e) => startRowResize(e, k, e.currentTarget.closest("tr")), onClick: (e) => e.stopPropagation() }) : null
|
|
11523
|
+
] }) : null,
|
|
11524
|
+
showRowNum ? /* @__PURE__ */ jsx("td", { className: "twc-dt__td twc-dt__rownum", role: "gridcell", "aria-hidden": "true", "data-pin": "left", "data-pin-edge": visLeft.length ? void 0 : "left", style: { insetInlineStart: numLeft, width: NUM_W }, children: typeof ri === "number" ? (paginated || serverMode ? pageVal * sizeVal : 0) + ri + 1 : "" }) : null,
|
|
11525
|
+
ordered.map((c, ci) => {
|
|
11526
|
+
const st = stickyOf(c.field);
|
|
11527
|
+
const val = getColVal(c, row);
|
|
11528
|
+
const isActions = c.type === "actions";
|
|
11529
|
+
const editable = isColEditable(c);
|
|
11530
|
+
const isEditing = editing && editing.key === k && editing.field === c.field;
|
|
11531
|
+
const cellActive = selectionMode === "cell" && activeCell && activeCell.key === k && activeCell.field === c.field;
|
|
11532
|
+
const cellSelected = selectionMode === "cell" && cellRect && ri >= cellRect.r0 && ri <= cellRect.r1 && ci >= cellRect.c0 && ci <= cellRect.c1;
|
|
11533
|
+
const cellFlash = clipFx && clipFx.rect && ri >= clipFx.rect.r0 && ri <= clipFx.rect.r1 && ci >= clipFx.rect.c0 && ci <= clipFx.rect.c1;
|
|
11534
|
+
const cellId = selectionMode === "cell" ? `${gridId}-${ri}-${ci}` : void 0;
|
|
11535
|
+
const display = c.valueFormatter ? c.valueFormatter(val, row) : val;
|
|
11536
|
+
const cellTitle = !isActions && !c.renderCell && !isEditing && (typeof display === "string" || typeof display === "number") ? String(display) : void 0;
|
|
11537
|
+
const cellClass = c.cellClassName ? c.cellClassName(val, row) : void 0;
|
|
11538
|
+
const cellSty = c.cellStyle ? c.cellStyle(val, row) : void 0;
|
|
11539
|
+
return /* @__PURE__ */ jsxs(
|
|
11540
|
+
"td",
|
|
11468
11541
|
{
|
|
11469
|
-
|
|
11470
|
-
|
|
11471
|
-
|
|
11472
|
-
|
|
11473
|
-
"
|
|
11474
|
-
"aria-
|
|
11475
|
-
tabIndex: 0,
|
|
11476
|
-
|
|
11477
|
-
|
|
11478
|
-
|
|
11479
|
-
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
|
|
11484
|
-
|
|
11485
|
-
|
|
11486
|
-
|
|
11487
|
-
|
|
11488
|
-
|
|
11489
|
-
|
|
11490
|
-
|
|
11491
|
-
|
|
11492
|
-
|
|
11493
|
-
|
|
11494
|
-
|
|
11495
|
-
|
|
11496
|
-
|
|
11497
|
-
|
|
11498
|
-
|
|
11499
|
-
|
|
11500
|
-
|
|
11501
|
-
|
|
11502
|
-
|
|
11503
|
-
|
|
11504
|
-
|
|
11505
|
-
|
|
11506
|
-
|
|
11507
|
-
|
|
11508
|
-
|
|
11509
|
-
|
|
11510
|
-
|
|
11511
|
-
|
|
11512
|
-
|
|
11513
|
-
|
|
11514
|
-
|
|
11515
|
-
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
|
|
11519
|
-
"data-cell-selected": cellSelected || void 0,
|
|
11520
|
-
"data-copied": cellFlash || void 0,
|
|
11521
|
-
"data-wrap": effectiveWrapped.has(c.field) || void 0,
|
|
11522
|
-
"data-pin": st.pin,
|
|
11523
|
-
"data-pin-edge": st.edge,
|
|
11524
|
-
style: { width: widthOf(c), ...cellSty, ...st.style, ...st.pin ? { position: "sticky", zIndex: 2 } : null },
|
|
11525
|
-
"data-ovtext": cellTitle,
|
|
11526
|
-
onClick: selectionMode === "cell" ? (e) => handleCellClick(e, k, row, c) : void 0,
|
|
11527
|
-
onFocus: () => setFocus((f) => f.r === ri && f.c === ci ? f : { r: ri, c: ci }),
|
|
11528
|
-
onDoubleClick: editable ? () => beginEdit(k, c, row) : void 0,
|
|
11529
|
-
children: [
|
|
11530
|
-
!checkboxSelection && reorderable && ci === 0 && !isEditing ? /* @__PURE__ */ jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 6, maxWidth: "100%" }, children: [
|
|
11531
|
-
rowHandle(k, midIdx, row),
|
|
11532
|
-
/* @__PURE__ */ jsx("span", { style: { overflow: "hidden", textOverflow: "ellipsis" }, children: isActions ? renderActions(c, row) : c.renderCell ? c.renderCell(val, row) : display })
|
|
11533
|
-
] }) : isEditing ? c.renderEditCell ? (
|
|
11534
|
-
// #236: full escape hatch — the host drops in its own editor (searchable/creatable/
|
|
11535
|
-
// async Combobox, …) and drives the lifecycle via commit/cancel. Wrapped in
|
|
11536
|
-
// .twc-dt__editor-wrap so inline clicks (and any .twc-pop portal dropdown) don't
|
|
11537
|
-
// trip the outside-click auto-cancel.
|
|
11538
|
-
// #273: the wrapper handles Escape → cancel so it works for every custom editor without
|
|
11539
|
-
// each having to wire a keydown (they only get commit/cancel). A custom control that
|
|
11540
|
-
// wants Escape itself (e.g. to close its own open dropdown) stops propagation first.
|
|
11541
|
-
/* @__PURE__ */ jsx(
|
|
11542
|
-
"div",
|
|
11542
|
+
id: cellId,
|
|
11543
|
+
className: cellClass ? `twc-dt__td ${cellClass}` : "twc-dt__td",
|
|
11544
|
+
role: "gridcell",
|
|
11545
|
+
"data-r": ri,
|
|
11546
|
+
"data-c": ci,
|
|
11547
|
+
"aria-colindex": ci + 1 + (checkboxSelection ? 1 : 0) + (hasRowDetail ? 1 : 0),
|
|
11548
|
+
tabIndex: focus.r === ri && focus.c === ci ? 0 : -1,
|
|
11549
|
+
"aria-selected": cellSelected || void 0,
|
|
11550
|
+
"data-num": c.type === "number" || void 0,
|
|
11551
|
+
"data-actions": isActions || void 0,
|
|
11552
|
+
"data-editable": editable && !isEditing || void 0,
|
|
11553
|
+
"data-editing": isEditing || void 0,
|
|
11554
|
+
"data-cell-active": cellActive || void 0,
|
|
11555
|
+
"data-cell-selected": cellSelected || void 0,
|
|
11556
|
+
"data-copied": cellFlash || void 0,
|
|
11557
|
+
"data-wrap": effectiveWrapped.has(c.field) || void 0,
|
|
11558
|
+
"data-pin": st.pin,
|
|
11559
|
+
"data-pin-edge": st.edge,
|
|
11560
|
+
style: { width: widthOf(c), ...cellSty, ...st.style, ...st.pin ? { position: "sticky", zIndex: 2 } : null },
|
|
11561
|
+
"data-ovtext": cellTitle,
|
|
11562
|
+
onClick: selectionMode === "cell" ? (e) => handleCellClick(e, k, row, c) : void 0,
|
|
11563
|
+
onFocus: () => setFocus((f) => f.r === ri && f.c === ci ? f : { r: ri, c: ci }),
|
|
11564
|
+
onDoubleClick: editable ? () => beginEdit(k, c, row) : void 0,
|
|
11565
|
+
children: [
|
|
11566
|
+
!checkboxSelection && reorderable && ci === 0 && !isEditing ? /* @__PURE__ */ jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 6, maxWidth: "100%" }, children: [
|
|
11567
|
+
rowHandle(k, midIdx, row),
|
|
11568
|
+
/* @__PURE__ */ jsx("span", { style: { overflow: "hidden", textOverflow: "ellipsis" }, children: isActions ? renderActions(c, row) : c.renderCell ? c.renderCell(val, row) : display })
|
|
11569
|
+
] }) : isEditing ? c.renderEditCell ? (
|
|
11570
|
+
// #236: full escape hatch — the host drops in its own editor (searchable/creatable/
|
|
11571
|
+
// async Combobox, …) and drives the lifecycle via commit/cancel. Wrapped in
|
|
11572
|
+
// .twc-dt__editor-wrap so inline clicks (and any .twc-pop portal dropdown) don't
|
|
11573
|
+
// trip the outside-click auto-cancel.
|
|
11574
|
+
// #273: the wrapper handles Escape → cancel so it works for every custom editor without
|
|
11575
|
+
// each having to wire a keydown (they only get commit/cancel). A custom control that
|
|
11576
|
+
// wants Escape itself (e.g. to close its own open dropdown) stops propagation first.
|
|
11577
|
+
/* @__PURE__ */ jsx(
|
|
11578
|
+
"div",
|
|
11579
|
+
{
|
|
11580
|
+
className: "twc-dt__editor-wrap",
|
|
11581
|
+
onKeyDown: (e) => {
|
|
11582
|
+
if (e.key === "Escape") {
|
|
11583
|
+
e.stopPropagation();
|
|
11584
|
+
cancelEdit();
|
|
11585
|
+
}
|
|
11586
|
+
},
|
|
11587
|
+
children: c.renderEditCell({ value: editing.value, row, field: c.field, commit: (v) => commitEdit(v), cancel: cancelEdit })
|
|
11588
|
+
}
|
|
11589
|
+
)
|
|
11590
|
+
) : /* @__PURE__ */ jsx(
|
|
11591
|
+
EditCell,
|
|
11543
11592
|
{
|
|
11544
|
-
|
|
11545
|
-
|
|
11546
|
-
|
|
11547
|
-
|
|
11548
|
-
|
|
11549
|
-
|
|
11550
|
-
|
|
11551
|
-
|
|
11593
|
+
col: c,
|
|
11594
|
+
value: editing.value,
|
|
11595
|
+
options: c.valueOptions ? optionsForField(c.field) : null,
|
|
11596
|
+
onChange: (v) => setEditing((e) => ({ ...e, value: v })),
|
|
11597
|
+
onCommit: () => commitEdit(),
|
|
11598
|
+
onCommitValue: (v) => commitEdit(v),
|
|
11599
|
+
onCancel: cancelEdit,
|
|
11600
|
+
onKeyDown: onEditKey
|
|
11552
11601
|
}
|
|
11553
|
-
)
|
|
11554
|
-
|
|
11555
|
-
|
|
11556
|
-
|
|
11557
|
-
|
|
11558
|
-
|
|
11559
|
-
|
|
11560
|
-
|
|
11561
|
-
|
|
11562
|
-
|
|
11563
|
-
|
|
11564
|
-
|
|
11565
|
-
}
|
|
11566
|
-
) : isActions ? renderActions(c, row) : c.renderCell ? c.renderCell(val, row) : display,
|
|
11567
|
-
editable && !isEditing ? /* @__PURE__ */ jsx("span", { className: "twc-dt__edit-hint", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Svg, { d: I.pencil }) }) : null
|
|
11568
|
-
]
|
|
11569
|
-
},
|
|
11570
|
-
c.field
|
|
11571
|
-
);
|
|
11572
|
-
})
|
|
11573
|
-
]
|
|
11574
|
-
},
|
|
11575
|
-
(pinSide ? "p-" : "") + k
|
|
11576
|
-
);
|
|
11602
|
+
) : isActions ? renderActions(c, row) : c.renderCell ? c.renderCell(val, row) : display,
|
|
11603
|
+
editable && !isEditing ? /* @__PURE__ */ jsx("span", { className: "twc-dt__edit-hint", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Svg, { d: I.pencil }) }) : null
|
|
11604
|
+
]
|
|
11605
|
+
},
|
|
11606
|
+
c.field
|
|
11607
|
+
);
|
|
11608
|
+
})
|
|
11609
|
+
]
|
|
11610
|
+
}
|
|
11611
|
+
),
|
|
11612
|
+
open ? /* @__PURE__ */ jsx("tr", { className: "twc-dt__detail-row", role: "row", children: /* @__PURE__ */ jsx("td", { id: `${gridId}-detail-${ri}`, className: "twc-dt__detail-cell", role: "gridcell", colSpan: totalCols, style: { maxWidth: "none" }, children: detail }) }) : null
|
|
11613
|
+
] }, (pinSide ? "p-" : "") + k);
|
|
11577
11614
|
}
|
|
11578
11615
|
function renderPivot() {
|
|
11579
11616
|
const rFields = pivotConfig.rows, cFields = pivotConfig.columns || [], values = pivotConfig.values;
|
|
@@ -11910,14 +11947,15 @@ function Datatable({
|
|
|
11910
11947
|
role: "grid",
|
|
11911
11948
|
"aria-label": ariaLabelAttr || ariaLabel,
|
|
11912
11949
|
"aria-rowcount": totalRows + 1,
|
|
11913
|
-
"aria-colcount": ordered.length + (checkboxSelection ? 1 : 0),
|
|
11950
|
+
"aria-colcount": ordered.length + (checkboxSelection ? 1 : 0) + (hasRowDetail ? 1 : 0),
|
|
11914
11951
|
"aria-multiselectable": selectionMode === "cell" || void 0,
|
|
11915
11952
|
"aria-activedescendant": activeCellId,
|
|
11916
11953
|
"aria-busy": loading || void 0,
|
|
11917
11954
|
onKeyDown: onGridKeyDown,
|
|
11918
11955
|
children: [
|
|
11919
11956
|
/* @__PURE__ */ jsx("thead", { ref: theadRef, children: /* @__PURE__ */ jsxs("tr", { role: "row", "aria-rowindex": 1, children: [
|
|
11920
|
-
|
|
11957
|
+
hasRowDetail ? /* @__PURE__ */ jsx("th", { className: "twc-dt__th twc-dt__expand-cell", role: "columnheader", "aria-label": "Expand", "data-pin": "left", "data-pin-edge": checkboxSelection || showRowNum || visLeft.length ? void 0 : "left", style: { insetInlineStart: 0, width: EXP_W, minWidth: EXP_W } }) : null,
|
|
11958
|
+
checkboxSelection ? /* @__PURE__ */ jsx("th", { className: "twc-dt__th", role: "columnheader", "aria-label": "Select", "data-pin": "left", "data-pin-edge": visLeft.length || showRowNum ? void 0 : "left", style: { insetInlineStart: EXP_W, width: CHK_W, minWidth: CHK_W }, children: /* @__PURE__ */ jsx("div", { className: "twc-dt__th-inner", style: { justifyContent: "center", padding: 0 }, children: /* @__PURE__ */ jsx(
|
|
11921
11959
|
"span",
|
|
11922
11960
|
{
|
|
11923
11961
|
className: "twc-dt__check",
|
|
@@ -12093,7 +12131,8 @@ function Datatable({
|
|
|
12093
12131
|
})
|
|
12094
12132
|
] }) }),
|
|
12095
12133
|
/* @__PURE__ */ jsx("tbody", { children: loading ? Array.from({ length: paginated ? Math.min(sizeVal, 8) : 8 }).map((_, ri) => /* @__PURE__ */ jsxs("tr", { className: "twc-dt__row", role: "row", children: [
|
|
12096
|
-
|
|
12134
|
+
hasRowDetail ? /* @__PURE__ */ jsx("td", { className: "twc-dt__td twc-dt__expand-cell", role: "gridcell", "data-pin": "left", style: { insetInlineStart: 0, width: EXP_W } }) : null,
|
|
12135
|
+
checkboxSelection ? /* @__PURE__ */ jsx("td", { className: "twc-dt__td", role: "gridcell", "data-pin": "left", style: { insetInlineStart: EXP_W, width: CHK_W }, children: /* @__PURE__ */ jsx("span", { className: "twc-dt__sk", "aria-hidden": "true", style: { "--_w": "18px", height: 18, borderRadius: 4 } }) }) : null,
|
|
12097
12136
|
showRowNum ? /* @__PURE__ */ jsx("td", { className: "twc-dt__td twc-dt__rownum", role: "gridcell", "aria-hidden": "true", "data-pin": "left", style: { insetInlineStart: numLeft, width: NUM_W }, children: /* @__PURE__ */ jsx("span", { className: "twc-dt__sk", "aria-hidden": "true", style: { "--_w": "16px", height: 14, borderRadius: 4 } }) }) : null,
|
|
12098
12137
|
ordered.map((c, ci) => {
|
|
12099
12138
|
const st = stickyOf(c.field);
|
|
@@ -12115,7 +12154,8 @@ function Datatable({
|
|
|
12115
12154
|
pinnedBottomRows.map((row) => renderLeaf(row, keyIndex.get(keyOf(row)), "bottom"))
|
|
12116
12155
|
] }) }),
|
|
12117
12156
|
hasAggregation && aggOn && !loading && paged.length > 0 ? /* @__PURE__ */ jsx("tfoot", { children: /* @__PURE__ */ jsxs("tr", { role: "row", children: [
|
|
12118
|
-
|
|
12157
|
+
hasRowDetail ? /* @__PURE__ */ jsx("td", { role: "gridcell", "data-pin": "left", "data-pin-edge": checkboxSelection || showRowNum || visLeft.length ? void 0 : "left", style: { insetInlineStart: 0, width: EXP_W } }) : null,
|
|
12158
|
+
checkboxSelection ? /* @__PURE__ */ jsx("td", { role: "gridcell", "data-pin": "left", "data-pin-edge": visLeft.length || showRowNum ? void 0 : "left", style: { insetInlineStart: EXP_W, width: CHK_W } }) : null,
|
|
12119
12159
|
showRowNum ? /* @__PURE__ */ jsx("td", { className: "twc-dt__rownum", role: "gridcell", "aria-hidden": "true", "data-pin": "left", "data-pin-edge": visLeft.length ? void 0 : "left", style: { insetInlineStart: numLeft, width: NUM_W } }) : null,
|
|
12120
12160
|
ordered.map((c) => {
|
|
12121
12161
|
const st = stickyOf(c.field);
|
|
@@ -17150,6 +17190,18 @@ var SLIDER_CSS = `
|
|
|
17150
17190
|
transition: opacity var(--duration-fast) var(--ease-standard), transform var(--duration-fast) var(--ease-spring);
|
|
17151
17191
|
}
|
|
17152
17192
|
.twc-slider__track[data-show-bubble="true"] .twc-slider__bubble { opacity: 1; transform: translateX(-50%) scale(1); }
|
|
17193
|
+
/* #351: editable numeric inputs (manual entry, synced with the thumbs) */
|
|
17194
|
+
.twc-slider__inputs { display: inline-flex; align-items: center; gap: var(--space-1-5); }
|
|
17195
|
+
.twc-slider__input-sep { color: var(--color-text-muted); font-weight: var(--font-semibold); }
|
|
17196
|
+
.twc-slider__input {
|
|
17197
|
+
min-width: 0; text-align: end; font-family: inherit; font-size: var(--text-sm); font-weight: var(--font-semibold);
|
|
17198
|
+
color: var(--_accent); font-variant-numeric: tabular-nums;
|
|
17199
|
+
padding: 2px 6px; border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface);
|
|
17200
|
+
transition: border-color var(--duration-fast) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard);
|
|
17201
|
+
}
|
|
17202
|
+
.twc-slider__input:hover:not(:disabled) { border-color: var(--color-border-strong); }
|
|
17203
|
+
.twc-slider__input:focus-visible { outline: none; border-color: var(--_accent); box-shadow: var(--ring); }
|
|
17204
|
+
.twc-slider[data-disabled="true"] .twc-slider__input { cursor: not-allowed; }
|
|
17153
17205
|
`;
|
|
17154
17206
|
function Slider({
|
|
17155
17207
|
label,
|
|
@@ -17168,6 +17220,7 @@ function Slider({
|
|
|
17168
17220
|
range: range2 = false,
|
|
17169
17221
|
showValue = true,
|
|
17170
17222
|
showTicks = false,
|
|
17223
|
+
editable = false,
|
|
17171
17224
|
formatValue,
|
|
17172
17225
|
getAriaValueText,
|
|
17173
17226
|
name,
|
|
@@ -17206,6 +17259,7 @@ function Slider({
|
|
|
17206
17259
|
const indices = isRange ? [0, 1] : [0];
|
|
17207
17260
|
const trackRef = React51__default.useRef(null);
|
|
17208
17261
|
const [dragging, setDragging] = React51__default.useState(false);
|
|
17262
|
+
const [typed, setTyped] = React51__default.useState({});
|
|
17209
17263
|
const fmt = (v) => formatValue ? formatValue(v) : v.toFixed(decimals);
|
|
17210
17264
|
const valueTextFor = (v) => {
|
|
17211
17265
|
if (getAriaValueText) return getAriaValueText(v);
|
|
@@ -17229,6 +17283,27 @@ function Slider({
|
|
|
17229
17283
|
}
|
|
17230
17284
|
commit(next);
|
|
17231
17285
|
};
|
|
17286
|
+
const commitInput = (i) => {
|
|
17287
|
+
const s = typed[i];
|
|
17288
|
+
setTyped((t) => {
|
|
17289
|
+
const n = { ...t };
|
|
17290
|
+
delete n[i];
|
|
17291
|
+
return n;
|
|
17292
|
+
});
|
|
17293
|
+
if (s == null || String(s).trim() === "") return;
|
|
17294
|
+
const num = parseFloat(s);
|
|
17295
|
+
if (Number.isFinite(num)) setThumb(i, num);
|
|
17296
|
+
};
|
|
17297
|
+
const stepInput = (i, dir) => {
|
|
17298
|
+
const base = typed[i] != null && Number.isFinite(parseFloat(typed[i])) ? parseFloat(typed[i]) : clampedVals[i];
|
|
17299
|
+
setTyped((t) => {
|
|
17300
|
+
const n = { ...t };
|
|
17301
|
+
delete n[i];
|
|
17302
|
+
return n;
|
|
17303
|
+
});
|
|
17304
|
+
setThumb(i, base + dir * step);
|
|
17305
|
+
};
|
|
17306
|
+
const inputSize = Math.max(String(min).length, String(max).length, decimals > 0 ? decimals + 2 : 1) + 1;
|
|
17232
17307
|
const fromClientX = (clientX) => {
|
|
17233
17308
|
const node = trackRef.current;
|
|
17234
17309
|
if (!node) return clampedVals[0];
|
|
@@ -17284,9 +17359,40 @@ function Slider({
|
|
|
17284
17359
|
return /* @__PURE__ */ jsxs("div", { className: `twc-slider ${className}`, "data-tone": tone, "data-size": size, "data-disabled": disabled || void 0, ...rest, children: [
|
|
17285
17360
|
__twcStyles,
|
|
17286
17361
|
name ? clampedVals.map((v, i) => /* @__PURE__ */ jsx("input", { type: "hidden", name, value: v, disabled: disabled || void 0 }, i)) : null,
|
|
17287
|
-
label || showValue ? /* @__PURE__ */ jsxs("div", { className: "twc-slider__head", children: [
|
|
17362
|
+
label || showValue || editable ? /* @__PURE__ */ jsxs("div", { className: "twc-slider__head", children: [
|
|
17288
17363
|
label ? /* @__PURE__ */ jsx("label", { className: "twc-slider__label", id: labelId, children: label }) : /* @__PURE__ */ jsx("span", {}),
|
|
17289
|
-
|
|
17364
|
+
editable ? /* @__PURE__ */ jsx("span", { className: "twc-slider__inputs", children: indices.map((i) => /* @__PURE__ */ jsxs(React51__default.Fragment, { children: [
|
|
17365
|
+
i > 0 ? /* @__PURE__ */ jsx("span", { className: "twc-slider__input-sep", "aria-hidden": "true", children: "\u2013" }) : null,
|
|
17366
|
+
/* @__PURE__ */ jsx(
|
|
17367
|
+
"input",
|
|
17368
|
+
{
|
|
17369
|
+
className: "twc-slider__input",
|
|
17370
|
+
type: "text",
|
|
17371
|
+
inputMode: min < 0 ? "text" : "decimal",
|
|
17372
|
+
size: inputSize,
|
|
17373
|
+
value: typed[i] != null ? typed[i] : String(clampedVals[i]),
|
|
17374
|
+
disabled: disabled || void 0,
|
|
17375
|
+
"aria-labelledby": isRange ? void 0 : labelId,
|
|
17376
|
+
"aria-label": isRange ? i === 0 ? "Minimum value" : "Maximum value" : labelId ? void 0 : "Value",
|
|
17377
|
+
onChange: (e) => setTyped((t) => ({ ...t, [i]: e.target.value })),
|
|
17378
|
+
onBlur: () => commitInput(i),
|
|
17379
|
+
onKeyDown: (e) => {
|
|
17380
|
+
if (e.key === "Enter") {
|
|
17381
|
+
if (typed[i] != null) {
|
|
17382
|
+
e.preventDefault();
|
|
17383
|
+
commitInput(i);
|
|
17384
|
+
}
|
|
17385
|
+
} else if (e.key === "ArrowUp") {
|
|
17386
|
+
e.preventDefault();
|
|
17387
|
+
stepInput(i, 1);
|
|
17388
|
+
} else if (e.key === "ArrowDown") {
|
|
17389
|
+
e.preventDefault();
|
|
17390
|
+
stepInput(i, -1);
|
|
17391
|
+
}
|
|
17392
|
+
}
|
|
17393
|
+
}
|
|
17394
|
+
)
|
|
17395
|
+
] }, i)) }) : showValue ? /* @__PURE__ */ jsx("span", { className: "twc-slider__value", children: headValue }) : null
|
|
17290
17396
|
] }) : null,
|
|
17291
17397
|
/* @__PURE__ */ jsxs("div", { className: "twc-slider__track", ref: trackRef, "data-show-bubble": dragging || void 0, onPointerDown, children: [
|
|
17292
17398
|
/* @__PURE__ */ jsx("div", { className: "twc-slider__rail" }),
|