@bmsuisse/datagrid 0.25.2 → 0.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/dist/index.d.ts +221 -2
- package/dist/index.js +573 -132
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1235,6 +1235,10 @@ function isSortable(column) {
|
|
|
1235
1235
|
function isFilterable(column) {
|
|
1236
1236
|
return column.filterable === true;
|
|
1237
1237
|
}
|
|
1238
|
+
function isEditable(column, row) {
|
|
1239
|
+
if (!column.editable) return false;
|
|
1240
|
+
return typeof column.editable === "function" ? column.editable(row) : true;
|
|
1241
|
+
}
|
|
1238
1242
|
|
|
1239
1243
|
// src/filter/facetedValues.ts
|
|
1240
1244
|
function withoutColumn(filter, columnId) {
|
|
@@ -1365,6 +1369,202 @@ function renderDefaultFilterWidget(column, value, onChange) {
|
|
|
1365
1369
|
}
|
|
1366
1370
|
}
|
|
1367
1371
|
|
|
1372
|
+
// src/edit/widget-types.ts
|
|
1373
|
+
function editErrorId(rowId, columnId) {
|
|
1374
|
+
return `edit-error-${rowId}-${columnId}`;
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
// src/edit/EditFieldError.tsx
|
|
1378
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1379
|
+
function EditFieldError({ id, message }) {
|
|
1380
|
+
return /* @__PURE__ */ jsx15("span", { id, className: "mt-0.5 block text-xs text-destructive", children: message });
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
// src/edit/BooleanEditor.tsx
|
|
1384
|
+
import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1385
|
+
function toBoolean(value) {
|
|
1386
|
+
if (typeof value === "boolean") return value;
|
|
1387
|
+
if (typeof value === "string") return value.trim().toLowerCase() === "true";
|
|
1388
|
+
if (typeof value === "number") return value !== 0;
|
|
1389
|
+
return false;
|
|
1390
|
+
}
|
|
1391
|
+
function BooleanEditor({
|
|
1392
|
+
column,
|
|
1393
|
+
rowId,
|
|
1394
|
+
value,
|
|
1395
|
+
onChange,
|
|
1396
|
+
error,
|
|
1397
|
+
autoFocus
|
|
1398
|
+
}) {
|
|
1399
|
+
const errorId = editErrorId(rowId, column.id);
|
|
1400
|
+
return (
|
|
1401
|
+
// No `gap-*` here (unlike a plain flex stack) — `EditFieldError`'s own
|
|
1402
|
+
// `mt-0.5` already provides the same spacing every other editor gets;
|
|
1403
|
+
// adding both would double it for this one editor only.
|
|
1404
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex flex-col items-center", children: [
|
|
1405
|
+
/* @__PURE__ */ jsx16(
|
|
1406
|
+
Checkbox,
|
|
1407
|
+
{
|
|
1408
|
+
"aria-label": `Edit ${column.header}`,
|
|
1409
|
+
"aria-invalid": error ? true : void 0,
|
|
1410
|
+
"aria-describedby": error ? errorId : void 0,
|
|
1411
|
+
"data-testid": `edit-${rowId}-${column.id}`,
|
|
1412
|
+
autoFocus,
|
|
1413
|
+
checked: toBoolean(value),
|
|
1414
|
+
onCheckedChange: (next) => onChange(next === true)
|
|
1415
|
+
}
|
|
1416
|
+
),
|
|
1417
|
+
error && /* @__PURE__ */ jsx16(EditFieldError, { id: errorId, message: error })
|
|
1418
|
+
] })
|
|
1419
|
+
);
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
// src/edit/DateEditor.tsx
|
|
1423
|
+
import { format as formatDate, parseISO as parseISO4 } from "date-fns";
|
|
1424
|
+
import { jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1425
|
+
function inputValueOf(value, columnType) {
|
|
1426
|
+
const date = toDate(value);
|
|
1427
|
+
if (!date) return "";
|
|
1428
|
+
return columnType === "datetime" ? formatDate(date, "yyyy-MM-dd'T'HH:mm:ss") : formatDate(date, "yyyy-MM-dd");
|
|
1429
|
+
}
|
|
1430
|
+
function DateEditor({
|
|
1431
|
+
column,
|
|
1432
|
+
rowId,
|
|
1433
|
+
value,
|
|
1434
|
+
onChange,
|
|
1435
|
+
error,
|
|
1436
|
+
autoFocus
|
|
1437
|
+
}) {
|
|
1438
|
+
const errorId = editErrorId(rowId, column.id);
|
|
1439
|
+
return /* @__PURE__ */ jsxs10("div", { children: [
|
|
1440
|
+
/* @__PURE__ */ jsx17(
|
|
1441
|
+
Input,
|
|
1442
|
+
{
|
|
1443
|
+
type: column.type === "datetime" ? "datetime-local" : "date",
|
|
1444
|
+
step: column.type === "datetime" ? 1 : void 0,
|
|
1445
|
+
className: "h-8",
|
|
1446
|
+
"aria-label": `Edit ${column.header}`,
|
|
1447
|
+
"aria-invalid": error ? true : void 0,
|
|
1448
|
+
"aria-describedby": error ? errorId : void 0,
|
|
1449
|
+
"data-testid": `edit-${rowId}-${column.id}`,
|
|
1450
|
+
autoFocus,
|
|
1451
|
+
value: inputValueOf(value, column.type),
|
|
1452
|
+
onChange: (event) => onChange(event.target.value === "" ? null : parseISO4(event.target.value))
|
|
1453
|
+
}
|
|
1454
|
+
),
|
|
1455
|
+
error && /* @__PURE__ */ jsx17(EditFieldError, { id: errorId, message: error })
|
|
1456
|
+
] });
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
// src/edit/EnumEditor.tsx
|
|
1460
|
+
import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1461
|
+
function EnumEditor({
|
|
1462
|
+
column,
|
|
1463
|
+
rowId,
|
|
1464
|
+
value,
|
|
1465
|
+
onChange,
|
|
1466
|
+
error,
|
|
1467
|
+
autoFocus
|
|
1468
|
+
}) {
|
|
1469
|
+
const errorId = editErrorId(rowId, column.id);
|
|
1470
|
+
return /* @__PURE__ */ jsxs11("div", { children: [
|
|
1471
|
+
/* @__PURE__ */ jsxs11(Select, { value: value === null || value === void 0 ? "" : String(value), onValueChange: onChange, children: [
|
|
1472
|
+
/* @__PURE__ */ jsx18(
|
|
1473
|
+
SelectTrigger,
|
|
1474
|
+
{
|
|
1475
|
+
className: "h-8",
|
|
1476
|
+
"aria-label": `Edit ${column.header}`,
|
|
1477
|
+
"aria-invalid": error ? true : void 0,
|
|
1478
|
+
"aria-describedby": error ? errorId : void 0,
|
|
1479
|
+
"data-testid": `edit-${rowId}-${column.id}`,
|
|
1480
|
+
autoFocus,
|
|
1481
|
+
children: /* @__PURE__ */ jsx18(SelectValue, {})
|
|
1482
|
+
}
|
|
1483
|
+
),
|
|
1484
|
+
/* @__PURE__ */ jsx18(SelectContent, { children: column.options.map((option) => /* @__PURE__ */ jsx18(SelectItem, { value: option.value, children: option.label }, option.value)) })
|
|
1485
|
+
] }),
|
|
1486
|
+
error && /* @__PURE__ */ jsx18(EditFieldError, { id: errorId, message: error })
|
|
1487
|
+
] });
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
// src/edit/NumberEditor.tsx
|
|
1491
|
+
import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1492
|
+
function NumberEditor({
|
|
1493
|
+
column,
|
|
1494
|
+
rowId,
|
|
1495
|
+
value,
|
|
1496
|
+
onChange,
|
|
1497
|
+
error,
|
|
1498
|
+
autoFocus
|
|
1499
|
+
}) {
|
|
1500
|
+
const errorId = editErrorId(rowId, column.id);
|
|
1501
|
+
return /* @__PURE__ */ jsxs12("div", { children: [
|
|
1502
|
+
/* @__PURE__ */ jsx19(
|
|
1503
|
+
Input,
|
|
1504
|
+
{
|
|
1505
|
+
type: "number",
|
|
1506
|
+
className: "h-8",
|
|
1507
|
+
"aria-label": `Edit ${column.header}`,
|
|
1508
|
+
"aria-invalid": error ? true : void 0,
|
|
1509
|
+
"aria-describedby": error ? errorId : void 0,
|
|
1510
|
+
"data-testid": `edit-${rowId}-${column.id}`,
|
|
1511
|
+
autoFocus,
|
|
1512
|
+
value: value === null || value === void 0 ? "" : String(value),
|
|
1513
|
+
onChange: (event) => onChange(event.target.value === "" ? null : Number(event.target.value))
|
|
1514
|
+
}
|
|
1515
|
+
),
|
|
1516
|
+
error && /* @__PURE__ */ jsx19(EditFieldError, { id: errorId, message: error })
|
|
1517
|
+
] });
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
// src/edit/StringEditor.tsx
|
|
1521
|
+
import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1522
|
+
function StringEditor({
|
|
1523
|
+
column,
|
|
1524
|
+
rowId,
|
|
1525
|
+
value,
|
|
1526
|
+
onChange,
|
|
1527
|
+
error,
|
|
1528
|
+
autoFocus
|
|
1529
|
+
}) {
|
|
1530
|
+
const errorId = editErrorId(rowId, column.id);
|
|
1531
|
+
return /* @__PURE__ */ jsxs13("div", { children: [
|
|
1532
|
+
/* @__PURE__ */ jsx20(
|
|
1533
|
+
Input,
|
|
1534
|
+
{
|
|
1535
|
+
className: "h-8",
|
|
1536
|
+
"aria-label": `Edit ${column.header}`,
|
|
1537
|
+
"aria-invalid": error ? true : void 0,
|
|
1538
|
+
"aria-describedby": error ? errorId : void 0,
|
|
1539
|
+
"data-testid": `edit-${rowId}-${column.id}`,
|
|
1540
|
+
autoFocus,
|
|
1541
|
+
value: value === null || value === void 0 ? "" : String(value),
|
|
1542
|
+
onChange: (event) => onChange(event.target.value)
|
|
1543
|
+
}
|
|
1544
|
+
),
|
|
1545
|
+
error && /* @__PURE__ */ jsx20(EditFieldError, { id: errorId, message: error })
|
|
1546
|
+
] });
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
// src/edit/registry.tsx
|
|
1550
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
1551
|
+
function renderDefaultEditWidget(column, rowId, value, onChange, error, autoFocus) {
|
|
1552
|
+
switch (column.type) {
|
|
1553
|
+
case "string":
|
|
1554
|
+
return /* @__PURE__ */ jsx21(StringEditor, { column, rowId, value, onChange, error, autoFocus });
|
|
1555
|
+
case "enum":
|
|
1556
|
+
return /* @__PURE__ */ jsx21(EnumEditor, { column, rowId, value, onChange, error, autoFocus });
|
|
1557
|
+
case "boolean":
|
|
1558
|
+
return /* @__PURE__ */ jsx21(BooleanEditor, { column, rowId, value, onChange, error, autoFocus });
|
|
1559
|
+
case "number":
|
|
1560
|
+
case "currency":
|
|
1561
|
+
return /* @__PURE__ */ jsx21(NumberEditor, { column, rowId, value, onChange, error, autoFocus });
|
|
1562
|
+
case "date":
|
|
1563
|
+
case "datetime":
|
|
1564
|
+
return /* @__PURE__ */ jsx21(DateEditor, { column, rowId, value, onChange, error, autoFocus });
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1368
1568
|
// src/column-selector/ColumnSelector.tsx
|
|
1369
1569
|
import { Columns3 } from "lucide-react";
|
|
1370
1570
|
import { useEffect as useEffect4 } from "react";
|
|
@@ -1373,10 +1573,10 @@ import { useEffect as useEffect4 } from "react";
|
|
|
1373
1573
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
1374
1574
|
import { X } from "lucide-react";
|
|
1375
1575
|
import { forwardRef as forwardRef6 } from "react";
|
|
1376
|
-
import { jsx as
|
|
1576
|
+
import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1377
1577
|
var Dialog = DialogPrimitive.Root;
|
|
1378
1578
|
var DialogTrigger = DialogPrimitive.Trigger;
|
|
1379
|
-
var DialogOverlay = forwardRef6(({ className, ...props }, ref) => /* @__PURE__ */
|
|
1579
|
+
var DialogOverlay = forwardRef6(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
|
|
1380
1580
|
DialogPrimitive.Overlay,
|
|
1381
1581
|
{
|
|
1382
1582
|
ref,
|
|
@@ -1385,9 +1585,9 @@ var DialogOverlay = forwardRef6(({ className, ...props }, ref) => /* @__PURE__ *
|
|
|
1385
1585
|
}
|
|
1386
1586
|
));
|
|
1387
1587
|
DialogOverlay.displayName = "DialogOverlay";
|
|
1388
|
-
var DialogContent = forwardRef6(({ className, children, ...props }, ref) => /* @__PURE__ */
|
|
1389
|
-
/* @__PURE__ */
|
|
1390
|
-
/* @__PURE__ */
|
|
1588
|
+
var DialogContent = forwardRef6(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs14(DialogPrimitive.Portal, { children: [
|
|
1589
|
+
/* @__PURE__ */ jsx22(DialogOverlay, {}),
|
|
1590
|
+
/* @__PURE__ */ jsxs14(
|
|
1391
1591
|
DialogPrimitive.Content,
|
|
1392
1592
|
{
|
|
1393
1593
|
ref,
|
|
@@ -1398,9 +1598,9 @@ var DialogContent = forwardRef6(({ className, children, ...props }, ref) => /* @
|
|
|
1398
1598
|
...props,
|
|
1399
1599
|
children: [
|
|
1400
1600
|
children,
|
|
1401
|
-
/* @__PURE__ */
|
|
1402
|
-
/* @__PURE__ */
|
|
1403
|
-
/* @__PURE__ */
|
|
1601
|
+
/* @__PURE__ */ jsxs14(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 hover:opacity-100", children: [
|
|
1602
|
+
/* @__PURE__ */ jsx22(X, { className: "h-4 w-4" }),
|
|
1603
|
+
/* @__PURE__ */ jsx22("span", { className: "sr-only", children: "Close" })
|
|
1404
1604
|
] })
|
|
1405
1605
|
]
|
|
1406
1606
|
}
|
|
@@ -1410,10 +1610,10 @@ DialogContent.displayName = "DialogContent";
|
|
|
1410
1610
|
var DialogHeader = ({
|
|
1411
1611
|
className,
|
|
1412
1612
|
...props
|
|
1413
|
-
}) => /* @__PURE__ */
|
|
1414
|
-
var DialogTitle = forwardRef6(({ className, ...props }, ref) => /* @__PURE__ */
|
|
1613
|
+
}) => /* @__PURE__ */ jsx22("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
1614
|
+
var DialogTitle = forwardRef6(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(DialogPrimitive.Title, { ref, className: cn("text-lg font-semibold", className), ...props }));
|
|
1415
1615
|
DialogTitle.displayName = "DialogTitle";
|
|
1416
|
-
var DialogDescription = forwardRef6(({ className, ...props }, ref) => /* @__PURE__ */
|
|
1616
|
+
var DialogDescription = forwardRef6(({ className, ...props }, ref) => /* @__PURE__ */ jsx22(
|
|
1417
1617
|
DialogPrimitive.Description,
|
|
1418
1618
|
{
|
|
1419
1619
|
ref,
|
|
@@ -1481,7 +1681,7 @@ function canHideGroup(columns, visibility, groupColumnIds) {
|
|
|
1481
1681
|
}
|
|
1482
1682
|
|
|
1483
1683
|
// src/column-selector/ColumnSelector.tsx
|
|
1484
|
-
import { jsx as
|
|
1684
|
+
import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1485
1685
|
function ColumnSelector({
|
|
1486
1686
|
columns,
|
|
1487
1687
|
visibility,
|
|
@@ -1506,20 +1706,20 @@ function ColumnSelector({
|
|
|
1506
1706
|
}
|
|
1507
1707
|
const totalVisible = countVisible(columns, visibility);
|
|
1508
1708
|
const groups = groupColumns(columns);
|
|
1509
|
-
return /* @__PURE__ */
|
|
1510
|
-
/* @__PURE__ */
|
|
1511
|
-
/* @__PURE__ */
|
|
1512
|
-
/* @__PURE__ */
|
|
1513
|
-
/* @__PURE__ */
|
|
1514
|
-
group && /* @__PURE__ */
|
|
1709
|
+
return /* @__PURE__ */ jsxs15(Dialog, { open, onOpenChange, children: [
|
|
1710
|
+
/* @__PURE__ */ jsx23(DialogTrigger, { asChild: true, children: trigger ?? /* @__PURE__ */ jsx23(Button, { variant: "outline", size: "icon", "aria-label": "Choose columns", children: /* @__PURE__ */ jsx23(Columns3, { className: "h-4 w-4", "aria-hidden": true }) }) }),
|
|
1711
|
+
/* @__PURE__ */ jsxs15(DialogContent, { className: "w-fit max-w-[calc(100vw-2rem)] sm:max-w-2xl", children: [
|
|
1712
|
+
/* @__PURE__ */ jsx23(DialogHeader, { children: /* @__PURE__ */ jsx23(DialogTitle, { children: "Columns" }) }),
|
|
1713
|
+
/* @__PURE__ */ jsx23("div", { className: "flex flex-wrap gap-x-8 gap-y-5", children: groups.map(({ group, columns: groupCols }) => /* @__PURE__ */ jsxs15("div", { className: "flex min-w-32 flex-col gap-1.5", children: [
|
|
1714
|
+
group && /* @__PURE__ */ jsx23("span", { className: "border-b pb-1.5 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: group }),
|
|
1515
1715
|
groupCols.map((column) => {
|
|
1516
1716
|
const visible = isColumnVisible(visibility, column.id);
|
|
1517
|
-
return /* @__PURE__ */
|
|
1717
|
+
return /* @__PURE__ */ jsxs15(
|
|
1518
1718
|
"label",
|
|
1519
1719
|
{
|
|
1520
1720
|
className: "flex items-center gap-2 rounded-md px-1.5 py-1 text-sm hover:bg-accent/50 focus-within:bg-accent/50",
|
|
1521
1721
|
children: [
|
|
1522
|
-
/* @__PURE__ */
|
|
1722
|
+
/* @__PURE__ */ jsx23(
|
|
1523
1723
|
Checkbox,
|
|
1524
1724
|
{
|
|
1525
1725
|
checked: visible,
|
|
@@ -1556,10 +1756,10 @@ import { useMemo as useMemo3 } from "react";
|
|
|
1556
1756
|
// src/components/ui/dropdown-menu.tsx
|
|
1557
1757
|
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
1558
1758
|
import { forwardRef as forwardRef7 } from "react";
|
|
1559
|
-
import { jsx as
|
|
1759
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
1560
1760
|
var DropdownMenu = DropdownMenuPrimitive.Root;
|
|
1561
1761
|
var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
1562
|
-
var DropdownMenuContent = forwardRef7(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */
|
|
1762
|
+
var DropdownMenuContent = forwardRef7(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx24(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx24(
|
|
1563
1763
|
DropdownMenuPrimitive.Content,
|
|
1564
1764
|
{
|
|
1565
1765
|
ref,
|
|
@@ -1572,7 +1772,7 @@ var DropdownMenuContent = forwardRef7(({ className, sideOffset = 4, ...props },
|
|
|
1572
1772
|
}
|
|
1573
1773
|
) }));
|
|
1574
1774
|
DropdownMenuContent.displayName = "DropdownMenuContent";
|
|
1575
|
-
var DropdownMenuItem = forwardRef7(({ className, danger, ...props }, ref) => /* @__PURE__ */
|
|
1775
|
+
var DropdownMenuItem = forwardRef7(({ className, danger, ...props }, ref) => /* @__PURE__ */ jsx24(
|
|
1576
1776
|
DropdownMenuPrimitive.Item,
|
|
1577
1777
|
{
|
|
1578
1778
|
ref,
|
|
@@ -1585,7 +1785,7 @@ var DropdownMenuItem = forwardRef7(({ className, danger, ...props }, ref) => /*
|
|
|
1585
1785
|
}
|
|
1586
1786
|
));
|
|
1587
1787
|
DropdownMenuItem.displayName = "DropdownMenuItem";
|
|
1588
|
-
var DropdownMenuSeparator = forwardRef7(({ className, ...props }, ref) => /* @__PURE__ */
|
|
1788
|
+
var DropdownMenuSeparator = forwardRef7(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
|
|
1589
1789
|
DropdownMenuPrimitive.Separator,
|
|
1590
1790
|
{
|
|
1591
1791
|
ref,
|
|
@@ -1594,7 +1794,7 @@ var DropdownMenuSeparator = forwardRef7(({ className, ...props }, ref) => /* @__
|
|
|
1594
1794
|
}
|
|
1595
1795
|
));
|
|
1596
1796
|
DropdownMenuSeparator.displayName = "DropdownMenuSeparator";
|
|
1597
|
-
var DropdownMenuLabel = forwardRef7(({ className, ...props }, ref) => /* @__PURE__ */
|
|
1797
|
+
var DropdownMenuLabel = forwardRef7(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
|
|
1598
1798
|
DropdownMenuPrimitive.Label,
|
|
1599
1799
|
{
|
|
1600
1800
|
ref,
|
|
@@ -1605,16 +1805,16 @@ var DropdownMenuLabel = forwardRef7(({ className, ...props }, ref) => /* @__PURE
|
|
|
1605
1805
|
DropdownMenuLabel.displayName = "DropdownMenuLabel";
|
|
1606
1806
|
|
|
1607
1807
|
// src/menu/ActionsMenu.tsx
|
|
1608
|
-
import { jsx as
|
|
1808
|
+
import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1609
1809
|
function ActionsMenu({ items, ctx, triggerLabel }) {
|
|
1610
1810
|
const resolved = useMemo3(
|
|
1611
1811
|
() => resolveMenuItems(items, ctx),
|
|
1612
1812
|
[items, ctx.row, ctx.selectedRows]
|
|
1613
1813
|
);
|
|
1614
1814
|
if (resolved.length === 0) return null;
|
|
1615
|
-
return /* @__PURE__ */
|
|
1616
|
-
/* @__PURE__ */
|
|
1617
|
-
/* @__PURE__ */
|
|
1815
|
+
return /* @__PURE__ */ jsxs16(DropdownMenu, { children: [
|
|
1816
|
+
/* @__PURE__ */ jsx25(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx25(Button, { variant: "ghost", size: "icon", "aria-label": triggerLabel, onClick: stopRowClick, children: /* @__PURE__ */ jsx25(MoreVertical, { className: "h-4 w-4", "aria-hidden": true }) }) }),
|
|
1817
|
+
/* @__PURE__ */ jsx25(DropdownMenuContent, { align: "end", children: resolved.map((item) => /* @__PURE__ */ jsx25(
|
|
1618
1818
|
DropdownMenuItem,
|
|
1619
1819
|
{
|
|
1620
1820
|
danger: item.danger,
|
|
@@ -1632,7 +1832,7 @@ import { BarsArrowDownIcon, BarsArrowUpIcon, FunnelIcon as FunnelIcon7 } from "@
|
|
|
1632
1832
|
import { columnResizingFeature, columnSizingFeature, flexRender, tableFeatures, useTable } from "@tanstack/react-table";
|
|
1633
1833
|
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
1634
1834
|
import { ChevronRight, Loader2 } from "lucide-react";
|
|
1635
|
-
import { Fragment as Fragment2, useEffect as useEffect7, useMemo as useMemo6, useRef as useRef5, useState as useState6 } from "react";
|
|
1835
|
+
import { Fragment as Fragment2, useEffect as useEffect7, useLayoutEffect, useMemo as useMemo6, useRef as useRef5, useState as useState6 } from "react";
|
|
1636
1836
|
|
|
1637
1837
|
// src/lib/structuralColumns.ts
|
|
1638
1838
|
var SELECTION_COLUMN_WIDTH = 44;
|
|
@@ -1802,7 +2002,7 @@ function useGridState(dataSource, initialState, externalState) {
|
|
|
1802
2002
|
}
|
|
1803
2003
|
|
|
1804
2004
|
// src/grid/DataGrid.tsx
|
|
1805
|
-
import { Fragment as Fragment3, jsx as
|
|
2005
|
+
import { Fragment as Fragment3, jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1806
2006
|
var gridTableFeatures = tableFeatures({ columnSizingFeature, columnResizingFeature });
|
|
1807
2007
|
var DEFAULT_COLUMN_SIZE = 150;
|
|
1808
2008
|
var DETAIL_COLUMN_WIDTH = 44;
|
|
@@ -1833,15 +2033,77 @@ function computeHeaderRuns(columns) {
|
|
|
1833
2033
|
}
|
|
1834
2034
|
return runs;
|
|
1835
2035
|
}
|
|
1836
|
-
function toTanstackColumns(columns) {
|
|
2036
|
+
function toTanstackColumns(columns, editingCtxRef) {
|
|
1837
2037
|
return columns.map((column) => ({
|
|
1838
2038
|
id: column.id,
|
|
1839
2039
|
header: column.header,
|
|
1840
2040
|
size: column.width,
|
|
1841
2041
|
accessorFn: (row) => getColumnValue(column, row),
|
|
1842
|
-
cell: (info) =>
|
|
2042
|
+
cell: (info) => {
|
|
2043
|
+
const row = info.row.original;
|
|
2044
|
+
const editingCtx = editingCtxRef.current;
|
|
2045
|
+
const staticContent = (value) => column.cell ? column.cell(value, row) : defaultFormat(column, value);
|
|
2046
|
+
if (editingCtx && isEditable(column, row)) {
|
|
2047
|
+
const rowId = editingCtx.getRowId(row);
|
|
2048
|
+
const pendingRow = editingCtx.pendingEdits.get(rowId);
|
|
2049
|
+
const value = pendingRow?.values.has(column.id) ? pendingRow.values.get(column.id) : info.getValue();
|
|
2050
|
+
if (editingCtx.activeRowId === rowId) {
|
|
2051
|
+
const error = editingCtx.editErrors.get(rowId)?.get(column.id);
|
|
2052
|
+
const autoFocus = editingCtx.autoFocusTarget?.rowId === rowId && editingCtx.autoFocusTarget.columnId === column.id;
|
|
2053
|
+
const onChange = (next) => editingCtx.onEdit(column, row, next);
|
|
2054
|
+
const editor = column.renderEditCell ? column.renderEditCell(value, row, onChange, error, autoFocus) : renderDefaultEditWidget(column, rowId, value, onChange, error, autoFocus);
|
|
2055
|
+
return /* @__PURE__ */ jsx26(
|
|
2056
|
+
"div",
|
|
2057
|
+
{
|
|
2058
|
+
onKeyDown: (event) => {
|
|
2059
|
+
if (event.key !== "Escape") return;
|
|
2060
|
+
if (!event.currentTarget.contains(event.target)) return;
|
|
2061
|
+
event.stopPropagation();
|
|
2062
|
+
editingCtx.onEdit(column, row, getColumnValue(column, row));
|
|
2063
|
+
},
|
|
2064
|
+
children: editor
|
|
2065
|
+
}
|
|
2066
|
+
);
|
|
2067
|
+
}
|
|
2068
|
+
return /* @__PURE__ */ jsx26(
|
|
2069
|
+
"span",
|
|
2070
|
+
{
|
|
2071
|
+
role: "button",
|
|
2072
|
+
tabIndex: 0,
|
|
2073
|
+
"data-testid": `cell-${rowId}-${column.id}`,
|
|
2074
|
+
className: "block w-full cursor-text",
|
|
2075
|
+
onClick: (event) => {
|
|
2076
|
+
stopRowClick(event);
|
|
2077
|
+
editingCtx.onActivateRow(rowId, column.id);
|
|
2078
|
+
},
|
|
2079
|
+
onKeyDown: (event) => {
|
|
2080
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
2081
|
+
event.preventDefault();
|
|
2082
|
+
stopRowClick(event);
|
|
2083
|
+
editingCtx.onActivateRow(rowId, column.id);
|
|
2084
|
+
},
|
|
2085
|
+
children: staticContent(value)
|
|
2086
|
+
}
|
|
2087
|
+
);
|
|
2088
|
+
}
|
|
2089
|
+
return staticContent(info.getValue());
|
|
2090
|
+
}
|
|
1843
2091
|
}));
|
|
1844
2092
|
}
|
|
2093
|
+
function editValuesEqual(a, b) {
|
|
2094
|
+
if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();
|
|
2095
|
+
return a === b;
|
|
2096
|
+
}
|
|
2097
|
+
function resolveEditLabel(label, changedRowCount, fallback) {
|
|
2098
|
+
if (label === void 0) return fallback(changedRowCount);
|
|
2099
|
+
return typeof label === "function" ? label(changedRowCount) : label;
|
|
2100
|
+
}
|
|
2101
|
+
function describeErrorRows(editErrors) {
|
|
2102
|
+
const rowIds = [...editErrors.keys()];
|
|
2103
|
+
const shown = rowIds.slice(0, 3);
|
|
2104
|
+
const suffix = rowIds.length > shown.length ? `, and ${rowIds.length - shown.length} more` : "";
|
|
2105
|
+
return `row${rowIds.length === 1 ? "" : "s"} ${shown.join(", ")}${suffix}`;
|
|
2106
|
+
}
|
|
1845
2107
|
function DataGrid({
|
|
1846
2108
|
columns,
|
|
1847
2109
|
dataSource,
|
|
@@ -1870,7 +2132,8 @@ function DataGrid({
|
|
|
1870
2132
|
defaultGroupsExpanded = true,
|
|
1871
2133
|
expandedGroups: controlledExpandedGroups,
|
|
1872
2134
|
onExpandedGroupsChange,
|
|
1873
|
-
zebra = true
|
|
2135
|
+
zebra = true,
|
|
2136
|
+
editing
|
|
1874
2137
|
}) {
|
|
1875
2138
|
const { state, filtersByColumn, setColumnFilter, toggleSort, setPage } = useGridState(
|
|
1876
2139
|
dataSource,
|
|
@@ -1910,6 +2173,102 @@ function DataGrid({
|
|
|
1910
2173
|
function toggleGroupExpanded(key) {
|
|
1911
2174
|
updateExpandedGroups({ ...expandedGroupsState, [key]: !isGroupExpanded(key) });
|
|
1912
2175
|
}
|
|
2176
|
+
const [pendingEdits, setPendingEdits] = useState6(/* @__PURE__ */ new Map());
|
|
2177
|
+
const [editErrors, setEditErrors] = useState6(/* @__PURE__ */ new Map());
|
|
2178
|
+
const hasEditErrors = editErrors.size > 0;
|
|
2179
|
+
const [activeRowId, setActiveRowId] = useState6(null);
|
|
2180
|
+
const [autoFocusTarget, setAutoFocusTarget] = useState6(null);
|
|
2181
|
+
function activateRow(rowId, columnId) {
|
|
2182
|
+
setActiveRowId(rowId);
|
|
2183
|
+
setAutoFocusTarget({ rowId, columnId });
|
|
2184
|
+
}
|
|
2185
|
+
useEffect7(() => {
|
|
2186
|
+
if (autoFocusTarget) setAutoFocusTarget(null);
|
|
2187
|
+
}, [autoFocusTarget]);
|
|
2188
|
+
function commitEdit(column, row, value) {
|
|
2189
|
+
const rowId = getRowId(row);
|
|
2190
|
+
const baseline = getColumnValue(column, row);
|
|
2191
|
+
setPendingEdits((prev) => {
|
|
2192
|
+
const next = new Map(prev);
|
|
2193
|
+
const values = new Map(next.get(rowId)?.values);
|
|
2194
|
+
if (editValuesEqual(value, baseline)) values.delete(column.id);
|
|
2195
|
+
else values.set(column.id, value);
|
|
2196
|
+
if (values.size === 0) next.delete(rowId);
|
|
2197
|
+
else next.set(rowId, { row, values });
|
|
2198
|
+
return next;
|
|
2199
|
+
});
|
|
2200
|
+
const message = column.validateEdit?.(value, row);
|
|
2201
|
+
setEditErrors((prev) => {
|
|
2202
|
+
const next = new Map(prev);
|
|
2203
|
+
const rowErrors = new Map(next.get(rowId));
|
|
2204
|
+
if (message) rowErrors.set(column.id, message);
|
|
2205
|
+
else rowErrors.delete(column.id);
|
|
2206
|
+
if (rowErrors.size === 0) next.delete(rowId);
|
|
2207
|
+
else next.set(rowId, rowErrors);
|
|
2208
|
+
return next;
|
|
2209
|
+
});
|
|
2210
|
+
}
|
|
2211
|
+
async function handleSaveEdits() {
|
|
2212
|
+
if (!editing || pendingEdits.size === 0) return;
|
|
2213
|
+
const snapshot = pendingEdits;
|
|
2214
|
+
const edited = [...snapshot.entries()].map(([rowId, entry]) => ({
|
|
2215
|
+
rowId,
|
|
2216
|
+
row: entry.row,
|
|
2217
|
+
values: Object.fromEntries(entry.values)
|
|
2218
|
+
}));
|
|
2219
|
+
try {
|
|
2220
|
+
await editing.onSave(edited);
|
|
2221
|
+
} catch {
|
|
2222
|
+
return;
|
|
2223
|
+
}
|
|
2224
|
+
const snapshotRowIds = new Set(snapshot.keys());
|
|
2225
|
+
const survivedRowIds = /* @__PURE__ */ new Set();
|
|
2226
|
+
const clearedErrorKeys = [];
|
|
2227
|
+
setPendingEdits((prev) => {
|
|
2228
|
+
const next = new Map(prev);
|
|
2229
|
+
for (const [rowId, snapshotEntry] of snapshot) {
|
|
2230
|
+
const current = next.get(rowId);
|
|
2231
|
+
if (!current) continue;
|
|
2232
|
+
const values = new Map(current.values);
|
|
2233
|
+
for (const [columnId, snapshotValue] of snapshotEntry.values) {
|
|
2234
|
+
if (values.has(columnId) && editValuesEqual(values.get(columnId), snapshotValue)) {
|
|
2235
|
+
values.delete(columnId);
|
|
2236
|
+
clearedErrorKeys.push({ rowId, columnId });
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
if (values.size === 0) next.delete(rowId);
|
|
2240
|
+
else {
|
|
2241
|
+
next.set(rowId, { row: current.row, values });
|
|
2242
|
+
survivedRowIds.add(rowId);
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
return next;
|
|
2246
|
+
});
|
|
2247
|
+
setEditErrors((prev) => {
|
|
2248
|
+
if (clearedErrorKeys.length === 0) return prev;
|
|
2249
|
+
const next = new Map(prev);
|
|
2250
|
+
for (const { rowId, columnId } of clearedErrorKeys) {
|
|
2251
|
+
const rowErrors = next.get(rowId);
|
|
2252
|
+
if (!rowErrors) continue;
|
|
2253
|
+
const nextRowErrors = new Map(rowErrors);
|
|
2254
|
+
nextRowErrors.delete(columnId);
|
|
2255
|
+
if (nextRowErrors.size === 0) next.delete(rowId);
|
|
2256
|
+
else next.set(rowId, nextRowErrors);
|
|
2257
|
+
}
|
|
2258
|
+
return next;
|
|
2259
|
+
});
|
|
2260
|
+
setActiveRowId(
|
|
2261
|
+
(prev) => prev !== null && snapshotRowIds.has(prev) && !survivedRowIds.has(prev) ? null : prev
|
|
2262
|
+
);
|
|
2263
|
+
}
|
|
2264
|
+
function handleDiscardEdits() {
|
|
2265
|
+
setPendingEdits(/* @__PURE__ */ new Map());
|
|
2266
|
+
setEditErrors(/* @__PURE__ */ new Map());
|
|
2267
|
+
setActiveRowId(null);
|
|
2268
|
+
editing?.onDiscard?.();
|
|
2269
|
+
}
|
|
2270
|
+
const editingCtxRef = useRef5(void 0);
|
|
2271
|
+
editingCtxRef.current = editing ? { pendingEdits, editErrors, activeRowId, autoFocusTarget, getRowId, onEdit: commitEdit, onActivateRow: activateRow } : void 0;
|
|
1913
2272
|
const visibleColumns = useMemo6(
|
|
1914
2273
|
() => columnVisibility ? columns.filter((column) => isColumnVisible(columnVisibility, column.id)) : columns,
|
|
1915
2274
|
[columns, columnVisibility]
|
|
@@ -1938,7 +2297,7 @@ function DataGrid({
|
|
|
1938
2297
|
}
|
|
1939
2298
|
updateSelectedIds(next);
|
|
1940
2299
|
}
|
|
1941
|
-
const tanstackColumns = useMemo6(() => toTanstackColumns(visibleColumns), [visibleColumns]);
|
|
2300
|
+
const tanstackColumns = useMemo6(() => toTanstackColumns(visibleColumns, editingCtxRef), [visibleColumns]);
|
|
1942
2301
|
const columnById = useMemo6(() => {
|
|
1943
2302
|
const map = /* @__PURE__ */ new Map();
|
|
1944
2303
|
for (const column of visibleColumns) map.set(column.id, column);
|
|
@@ -2065,6 +2424,18 @@ function DataGrid({
|
|
|
2065
2424
|
() => groupBy ? groupRows(tableRows, (row) => groupBy(row.original)) : void 0,
|
|
2066
2425
|
[tableRows, groupBy]
|
|
2067
2426
|
);
|
|
2427
|
+
const theadRef = useRef5(null);
|
|
2428
|
+
const [groupHeaderTop, setGroupHeaderTop] = useState6(0);
|
|
2429
|
+
useLayoutEffect(() => {
|
|
2430
|
+
if (!groupBy) return;
|
|
2431
|
+
const theadEl = theadRef.current;
|
|
2432
|
+
if (!theadEl) return;
|
|
2433
|
+
const updateHeight = () => setGroupHeaderTop(theadEl.getBoundingClientRect().height);
|
|
2434
|
+
updateHeight();
|
|
2435
|
+
const observer = new ResizeObserver(updateHeight);
|
|
2436
|
+
observer.observe(theadEl);
|
|
2437
|
+
return () => observer.disconnect();
|
|
2438
|
+
}, [groupBy]);
|
|
2068
2439
|
const scrollRef = useRef5(null);
|
|
2069
2440
|
const virtualizer = useVirtualizer({
|
|
2070
2441
|
count: tableRows.length,
|
|
@@ -2091,20 +2462,20 @@ function DataGrid({
|
|
|
2091
2462
|
const rowProps = getRowProps?.(row.original);
|
|
2092
2463
|
const rowTestId = getRowTestId?.(row.original) ?? `row-${row.id}`;
|
|
2093
2464
|
const isOddRow = zebra && row.index % 2 === 1;
|
|
2094
|
-
return /* @__PURE__ */
|
|
2095
|
-
/* @__PURE__ */
|
|
2465
|
+
return /* @__PURE__ */ jsxs17("tbody", { ref: measureRef, "data-index": row.index, children: [
|
|
2466
|
+
/* @__PURE__ */ jsxs17(
|
|
2096
2467
|
"tr",
|
|
2097
2468
|
{
|
|
2098
2469
|
...rowProps,
|
|
2099
2470
|
"data-testid": rowTestId,
|
|
2100
2471
|
className: rowProps?.className ? cn("divide-x divide-border", rowProps.className, isOddRow && "bg-foreground/5") : `divide-x divide-border${isOddRow ? " bg-foreground/5" : ""}`,
|
|
2101
2472
|
children: [
|
|
2102
|
-
showDetailColumn && /* @__PURE__ */
|
|
2473
|
+
showDetailColumn && /* @__PURE__ */ jsx26(
|
|
2103
2474
|
"td",
|
|
2104
2475
|
{
|
|
2105
2476
|
className: isOddRow ? detailCellProps.classNameOdd : detailCellProps.className,
|
|
2106
2477
|
style: detailCellProps.style,
|
|
2107
|
-
children: /* @__PURE__ */
|
|
2478
|
+
children: /* @__PURE__ */ jsx26(
|
|
2108
2479
|
Button,
|
|
2109
2480
|
{
|
|
2110
2481
|
type: "button",
|
|
@@ -2116,7 +2487,7 @@ function DataGrid({
|
|
|
2116
2487
|
stopRowClick(event);
|
|
2117
2488
|
toggleRowExpanded(row.id);
|
|
2118
2489
|
},
|
|
2119
|
-
children: /* @__PURE__ */
|
|
2490
|
+
children: /* @__PURE__ */ jsx26(
|
|
2120
2491
|
ChevronRight,
|
|
2121
2492
|
{
|
|
2122
2493
|
className: `h-4 w-4 transition-transform${isExpanded ? " rotate-90" : ""}`,
|
|
@@ -2127,12 +2498,12 @@ function DataGrid({
|
|
|
2127
2498
|
)
|
|
2128
2499
|
}
|
|
2129
2500
|
),
|
|
2130
|
-
showSelectionColumn && /* @__PURE__ */
|
|
2501
|
+
showSelectionColumn && /* @__PURE__ */ jsx26(
|
|
2131
2502
|
"td",
|
|
2132
2503
|
{
|
|
2133
2504
|
className: isOddRow ? selectionCellProps.classNameOdd : selectionCellProps.className,
|
|
2134
2505
|
style: selectionCellProps.style,
|
|
2135
|
-
children: /* @__PURE__ */
|
|
2506
|
+
children: /* @__PURE__ */ jsx26(
|
|
2136
2507
|
"input",
|
|
2137
2508
|
{
|
|
2138
2509
|
type: "checkbox",
|
|
@@ -2146,45 +2517,56 @@ function DataGrid({
|
|
|
2146
2517
|
),
|
|
2147
2518
|
row.getAllCells().map((cell) => {
|
|
2148
2519
|
const cellProps = bodyCellPropsByColumn.get(cell.column.id);
|
|
2149
|
-
return /* @__PURE__ */
|
|
2520
|
+
return /* @__PURE__ */ jsx26("td", { style: cellProps?.style, className: cellProps?.className ?? BODY_TD_BASE_CLASS, children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id);
|
|
2150
2521
|
}),
|
|
2151
|
-
showRowActionsColumn && rowActions && /* @__PURE__ */
|
|
2522
|
+
showRowActionsColumn && rowActions && /* @__PURE__ */ jsx26(
|
|
2152
2523
|
"td",
|
|
2153
2524
|
{
|
|
2154
2525
|
className: isOddRow ? rowActionsCellProps.classNameOdd : rowActionsCellProps.className,
|
|
2155
2526
|
style: rowActionsCellProps.style,
|
|
2156
|
-
children: /* @__PURE__ */
|
|
2527
|
+
children: /* @__PURE__ */ jsx26(ActionsMenu, { items: rowActions, ctx: { row: row.original }, triggerLabel: `Row actions for ${row.id}` })
|
|
2157
2528
|
}
|
|
2158
2529
|
)
|
|
2159
2530
|
]
|
|
2160
2531
|
}
|
|
2161
2532
|
),
|
|
2162
|
-
showDetailColumn && isExpanded && renderDetail && /* @__PURE__ */
|
|
2533
|
+
showDetailColumn && isExpanded && renderDetail && /* @__PURE__ */ jsx26("tr", { "data-testid": `${rowTestId}-detail`, children: /* @__PURE__ */ jsx26("td", { colSpan: totalColumnCount, className: "border-b border-border p-2", children: renderDetail(row.original) }) })
|
|
2163
2534
|
] }, row.id);
|
|
2164
2535
|
}
|
|
2165
2536
|
function renderGroupedBucket(bucket) {
|
|
2166
2537
|
const expanded = isGroupExpanded(bucket.key);
|
|
2167
2538
|
const originalRows = bucket.items.map((row) => row.original);
|
|
2168
|
-
return /* @__PURE__ */
|
|
2169
|
-
/* @__PURE__ */
|
|
2170
|
-
"
|
|
2539
|
+
return /* @__PURE__ */ jsxs17(Fragment2, { children: [
|
|
2540
|
+
/* @__PURE__ */ jsx26("tbody", { children: /* @__PURE__ */ jsx26("tr", { "data-testid": `group-header-${bucket.key}`, children: /* @__PURE__ */ jsx26(
|
|
2541
|
+
"td",
|
|
2171
2542
|
{
|
|
2172
|
-
|
|
2173
|
-
className:
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2543
|
+
colSpan: totalColumnCount,
|
|
2544
|
+
className: cn(
|
|
2545
|
+
"sticky z-20 border-b p-2 font-medium",
|
|
2546
|
+
zebra ? "bg-muted" : "bg-background"
|
|
2547
|
+
),
|
|
2548
|
+
style: { top: groupHeaderTop },
|
|
2549
|
+
children: /* @__PURE__ */ jsxs17(
|
|
2550
|
+
"button",
|
|
2551
|
+
{
|
|
2552
|
+
type: "button",
|
|
2553
|
+
className: "flex w-full items-center gap-1 text-left",
|
|
2554
|
+
onClick: () => toggleGroupExpanded(bucket.key),
|
|
2555
|
+
"aria-expanded": expanded,
|
|
2556
|
+
children: [
|
|
2557
|
+
/* @__PURE__ */ jsx26(
|
|
2558
|
+
ChevronRight,
|
|
2559
|
+
{
|
|
2560
|
+
className: `h-4 w-4 shrink-0 transition-transform${expanded ? " rotate-90" : ""}`,
|
|
2561
|
+
"aria-hidden": true
|
|
2562
|
+
}
|
|
2563
|
+
),
|
|
2564
|
+
renderGroupHeader ? renderGroupHeader(bucket.key, originalRows, expanded) : `${bucket.key} (${originalRows.length})`
|
|
2565
|
+
]
|
|
2566
|
+
}
|
|
2567
|
+
)
|
|
2186
2568
|
}
|
|
2187
|
-
) }) })
|
|
2569
|
+
) }) }),
|
|
2188
2570
|
expanded && bucket.items.map((row) => renderRow(row))
|
|
2189
2571
|
] }, `group-${bucket.key}`);
|
|
2190
2572
|
}
|
|
@@ -2201,32 +2583,81 @@ function DataGrid({
|
|
|
2201
2583
|
// containers (that one scrolling vertically, this component's own
|
|
2202
2584
|
// `overflow-x-auto` div scrolling horizontally) fighting over which one
|
|
2203
2585
|
// a sticky header/pinned column is actually stuck relative to.
|
|
2204
|
-
/* @__PURE__ */
|
|
2205
|
-
|
|
2206
|
-
|
|
2586
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex h-full min-h-0 flex-col gap-2", "data-testid": "datagrid", children: [
|
|
2587
|
+
editing && pendingEdits.size > 0 && /* @__PURE__ */ jsxs17(
|
|
2588
|
+
"div",
|
|
2589
|
+
{
|
|
2590
|
+
"data-testid": "datagrid-edit-bar",
|
|
2591
|
+
className: "flex shrink-0 flex-wrap items-center justify-between gap-2 rounded-md border bg-muted/50 px-3 py-2 text-sm",
|
|
2592
|
+
children: [
|
|
2593
|
+
/* @__PURE__ */ jsxs17("span", { "aria-live": "polite", children: [
|
|
2594
|
+
pendingEdits.size,
|
|
2595
|
+
" row",
|
|
2596
|
+
pendingEdits.size === 1 ? "" : "s",
|
|
2597
|
+
" changed",
|
|
2598
|
+
hasEditErrors && /* @__PURE__ */ jsxs17("span", { className: "ml-2 text-destructive", children: [
|
|
2599
|
+
"Fix the highlighted errors before saving (",
|
|
2600
|
+
describeErrorRows(editErrors),
|
|
2601
|
+
")."
|
|
2602
|
+
] })
|
|
2603
|
+
] }),
|
|
2604
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex gap-2", children: [
|
|
2605
|
+
/* @__PURE__ */ jsx26(
|
|
2606
|
+
Button,
|
|
2607
|
+
{
|
|
2608
|
+
type: "button",
|
|
2609
|
+
variant: "outline",
|
|
2610
|
+
size: "sm",
|
|
2611
|
+
"data-testid": "datagrid-discard-edits",
|
|
2612
|
+
disabled: editing.saving,
|
|
2613
|
+
onClick: handleDiscardEdits,
|
|
2614
|
+
children: resolveEditLabel(editing.discardLabel, pendingEdits.size, () => "Discard")
|
|
2615
|
+
}
|
|
2616
|
+
),
|
|
2617
|
+
/* @__PURE__ */ jsx26(
|
|
2618
|
+
Button,
|
|
2619
|
+
{
|
|
2620
|
+
type: "button",
|
|
2621
|
+
size: "sm",
|
|
2622
|
+
"data-testid": "datagrid-save-edits",
|
|
2623
|
+
disabled: editing.saving || hasEditErrors,
|
|
2624
|
+
onClick: () => void handleSaveEdits(),
|
|
2625
|
+
children: resolveEditLabel(
|
|
2626
|
+
editing.saveLabel,
|
|
2627
|
+
pendingEdits.size,
|
|
2628
|
+
(count) => `Save ${count} change${count === 1 ? "" : "s"}`
|
|
2629
|
+
)
|
|
2630
|
+
}
|
|
2631
|
+
)
|
|
2632
|
+
] })
|
|
2633
|
+
]
|
|
2634
|
+
}
|
|
2635
|
+
),
|
|
2636
|
+
showSelectionColumn && headerActions && /* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center justify-between text-sm", children: [
|
|
2637
|
+
/* @__PURE__ */ jsxs17("span", { children: [
|
|
2207
2638
|
selectedRows.length,
|
|
2208
2639
|
" selected"
|
|
2209
2640
|
] }),
|
|
2210
|
-
/* @__PURE__ */
|
|
2641
|
+
/* @__PURE__ */ jsx26(ActionsMenu, { items: headerActions, ctx: { selectedRows }, triggerLabel: "Bulk actions" })
|
|
2211
2642
|
] }),
|
|
2212
|
-
/* @__PURE__ */
|
|
2213
|
-
loading && /* @__PURE__ */
|
|
2643
|
+
/* @__PURE__ */ jsxs17("div", { className: "relative min-h-0 flex-1", children: [
|
|
2644
|
+
loading && /* @__PURE__ */ jsx26(
|
|
2214
2645
|
"div",
|
|
2215
2646
|
{
|
|
2216
2647
|
"data-testid": "datagrid-loading-overlay",
|
|
2217
2648
|
className: "absolute inset-0 z-30 flex items-center justify-center bg-background/60",
|
|
2218
|
-
children: /* @__PURE__ */
|
|
2649
|
+
children: /* @__PURE__ */ jsx26(Loader2, { className: "h-6 w-6 animate-spin text-muted-foreground", "aria-hidden": true })
|
|
2219
2650
|
}
|
|
2220
2651
|
),
|
|
2221
|
-
/* @__PURE__ */
|
|
2652
|
+
/* @__PURE__ */ jsx26(
|
|
2222
2653
|
"div",
|
|
2223
2654
|
{
|
|
2224
2655
|
ref: scrollRef,
|
|
2225
2656
|
"data-testid": testId,
|
|
2226
2657
|
className: "h-full overflow-auto rounded-md border",
|
|
2227
2658
|
style: shouldVirtualize ? { maxHeight: virtualize?.maxBodyHeight ?? 480 } : void 0,
|
|
2228
|
-
children: /* @__PURE__ */
|
|
2229
|
-
/* @__PURE__ */
|
|
2659
|
+
children: /* @__PURE__ */ jsxs17("table", { className: cn("w-full border-collapse text-sm", enableColumnResizing && "table-fixed"), children: [
|
|
2660
|
+
/* @__PURE__ */ jsxs17("thead", { ref: theadRef, className: "bg-muted", children: [
|
|
2230
2661
|
table.getHeaderGroups().map((headerGroup) => {
|
|
2231
2662
|
const headerById = new Map(headerGroup.headers.map((header) => [header.id, header]));
|
|
2232
2663
|
function renderLeafHeaderCell(column, rowSpan) {
|
|
@@ -2237,9 +2668,9 @@ function DataGrid({
|
|
|
2237
2668
|
const filterable = isFilterable(column) && column.filterDisplay !== "row";
|
|
2238
2669
|
const cellProps = leafHeaderCellPropsByColumn.get(column.id);
|
|
2239
2670
|
const headerContent = column.renderHeader ? column.renderHeader(column) : column.header;
|
|
2240
|
-
return /* @__PURE__ */
|
|
2241
|
-
/* @__PURE__ */
|
|
2242
|
-
sortable ? /* @__PURE__ */
|
|
2671
|
+
return /* @__PURE__ */ jsxs17("th", { rowSpan, style: cellProps?.style, className: cellProps?.className, children: [
|
|
2672
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-1", children: [
|
|
2673
|
+
sortable ? /* @__PURE__ */ jsxs17(
|
|
2243
2674
|
"button",
|
|
2244
2675
|
{
|
|
2245
2676
|
type: "button",
|
|
@@ -2247,8 +2678,8 @@ function DataGrid({
|
|
|
2247
2678
|
onClick: (event) => toggleSort(column.id, enableMultiSort && event.shiftKey, column.sortDescFirst === true),
|
|
2248
2679
|
children: [
|
|
2249
2680
|
headerContent,
|
|
2250
|
-
sortEntry?.dir === "asc" && /* @__PURE__ */
|
|
2251
|
-
sortEntry?.dir === "desc" && /* @__PURE__ */
|
|
2681
|
+
sortEntry?.dir === "asc" && /* @__PURE__ */ jsx26(BarsArrowUpIcon, { className: "h-3 w-3", "aria-hidden": true }),
|
|
2682
|
+
sortEntry?.dir === "desc" && /* @__PURE__ */ jsx26(BarsArrowDownIcon, { className: "h-3 w-3", "aria-hidden": true })
|
|
2252
2683
|
]
|
|
2253
2684
|
}
|
|
2254
2685
|
) : (
|
|
@@ -2257,10 +2688,10 @@ function DataGrid({
|
|
|
2257
2688
|
// silently breaking any interactive content a column's own `renderHeader`
|
|
2258
2689
|
// embeds directly (bare filter inputs, "select/reject all" buttons) —
|
|
2259
2690
|
// clicks never reach them at all, even though nothing looks wrong visually.
|
|
2260
|
-
/* @__PURE__ */
|
|
2691
|
+
/* @__PURE__ */ jsx26("div", { className: "flex items-center gap-1 px-1", children: headerContent })
|
|
2261
2692
|
),
|
|
2262
|
-
filterable && /* @__PURE__ */
|
|
2263
|
-
/* @__PURE__ */
|
|
2693
|
+
filterable && /* @__PURE__ */ jsxs17(Popover, { children: [
|
|
2694
|
+
/* @__PURE__ */ jsx26(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx26(Button, { variant: "ghost", size: "icon", "aria-label": `Filter ${column.header}`, children: /* @__PURE__ */ jsx26(
|
|
2264
2695
|
FunnelIcon7,
|
|
2265
2696
|
{
|
|
2266
2697
|
className: cn(
|
|
@@ -2270,10 +2701,10 @@ function DataGrid({
|
|
|
2270
2701
|
"aria-hidden": true
|
|
2271
2702
|
}
|
|
2272
2703
|
) }) }),
|
|
2273
|
-
/* @__PURE__ */
|
|
2704
|
+
/* @__PURE__ */ jsx26(PopoverContent, { children: renderFilterWidget(column) })
|
|
2274
2705
|
] })
|
|
2275
2706
|
] }),
|
|
2276
|
-
enableColumnResizing && /* @__PURE__ */
|
|
2707
|
+
enableColumnResizing && /* @__PURE__ */ jsx26(
|
|
2277
2708
|
"div",
|
|
2278
2709
|
{
|
|
2279
2710
|
"data-testid": `resize-handle-${column.id}`,
|
|
@@ -2284,9 +2715,9 @@ function DataGrid({
|
|
|
2284
2715
|
)
|
|
2285
2716
|
] }, header.id);
|
|
2286
2717
|
}
|
|
2287
|
-
return /* @__PURE__ */
|
|
2288
|
-
hasHeaderGroups && /* @__PURE__ */
|
|
2289
|
-
showDetailColumn && /* @__PURE__ */
|
|
2718
|
+
return /* @__PURE__ */ jsxs17(Fragment2, { children: [
|
|
2719
|
+
hasHeaderGroups && /* @__PURE__ */ jsxs17("tr", { "data-testid": "header-group-row", className: "divide-x divide-border", children: [
|
|
2720
|
+
showDetailColumn && /* @__PURE__ */ jsx26(
|
|
2290
2721
|
"th",
|
|
2291
2722
|
{
|
|
2292
2723
|
rowSpan: 2,
|
|
@@ -2295,13 +2726,13 @@ function DataGrid({
|
|
|
2295
2726
|
"aria-hidden": true
|
|
2296
2727
|
}
|
|
2297
2728
|
),
|
|
2298
|
-
showSelectionColumn && /* @__PURE__ */
|
|
2729
|
+
showSelectionColumn && /* @__PURE__ */ jsx26(
|
|
2299
2730
|
"th",
|
|
2300
2731
|
{
|
|
2301
2732
|
rowSpan: 2,
|
|
2302
2733
|
className: selectionHeaderCellProps.className,
|
|
2303
2734
|
style: selectionHeaderCellProps.style,
|
|
2304
|
-
children: /* @__PURE__ */
|
|
2735
|
+
children: /* @__PURE__ */ jsx26(
|
|
2305
2736
|
"input",
|
|
2306
2737
|
{
|
|
2307
2738
|
type: "checkbox",
|
|
@@ -2313,7 +2744,7 @@ function DataGrid({
|
|
|
2313
2744
|
}
|
|
2314
2745
|
),
|
|
2315
2746
|
headerRuns.map(
|
|
2316
|
-
(run) => run.kind === "single" ? renderLeafHeaderCell(run.column, 2) : /* @__PURE__ */
|
|
2747
|
+
(run) => run.kind === "single" ? renderLeafHeaderCell(run.column, 2) : /* @__PURE__ */ jsx26(
|
|
2317
2748
|
"th",
|
|
2318
2749
|
{
|
|
2319
2750
|
colSpan: run.columns.length,
|
|
@@ -2323,7 +2754,7 @@ function DataGrid({
|
|
|
2323
2754
|
`group-${run.label}-${run.columns[0].id}`
|
|
2324
2755
|
)
|
|
2325
2756
|
),
|
|
2326
|
-
showRowActionsColumn && /* @__PURE__ */
|
|
2757
|
+
showRowActionsColumn && /* @__PURE__ */ jsx26(
|
|
2327
2758
|
"th",
|
|
2328
2759
|
{
|
|
2329
2760
|
rowSpan: 2,
|
|
@@ -2333,8 +2764,8 @@ function DataGrid({
|
|
|
2333
2764
|
}
|
|
2334
2765
|
)
|
|
2335
2766
|
] }, `${headerGroup.id}-groups`),
|
|
2336
|
-
/* @__PURE__ */
|
|
2337
|
-
!hasHeaderGroups && showDetailColumn && /* @__PURE__ */
|
|
2767
|
+
/* @__PURE__ */ jsxs17("tr", { className: "divide-x divide-border", children: [
|
|
2768
|
+
!hasHeaderGroups && showDetailColumn && /* @__PURE__ */ jsx26(
|
|
2338
2769
|
"th",
|
|
2339
2770
|
{
|
|
2340
2771
|
className: detailHeaderCellProps.className,
|
|
@@ -2342,12 +2773,12 @@ function DataGrid({
|
|
|
2342
2773
|
"aria-hidden": true
|
|
2343
2774
|
}
|
|
2344
2775
|
),
|
|
2345
|
-
!hasHeaderGroups && showSelectionColumn && /* @__PURE__ */
|
|
2776
|
+
!hasHeaderGroups && showSelectionColumn && /* @__PURE__ */ jsx26(
|
|
2346
2777
|
"th",
|
|
2347
2778
|
{
|
|
2348
2779
|
className: selectionHeaderCellProps.className,
|
|
2349
2780
|
style: selectionHeaderCellProps.style,
|
|
2350
|
-
children: /* @__PURE__ */
|
|
2781
|
+
children: /* @__PURE__ */ jsx26(
|
|
2351
2782
|
"input",
|
|
2352
2783
|
{
|
|
2353
2784
|
type: "checkbox",
|
|
@@ -2363,7 +2794,7 @@ function DataGrid({
|
|
|
2363
2794
|
if (!column || hasHeaderGroups && !column.headerGroup) return null;
|
|
2364
2795
|
return renderLeafHeaderCell(column);
|
|
2365
2796
|
}),
|
|
2366
|
-
!hasHeaderGroups && showRowActionsColumn && /* @__PURE__ */
|
|
2797
|
+
!hasHeaderGroups && showRowActionsColumn && /* @__PURE__ */ jsx26(
|
|
2367
2798
|
"th",
|
|
2368
2799
|
{
|
|
2369
2800
|
className: rowActionsHeaderCellProps.className,
|
|
@@ -2374,9 +2805,9 @@ function DataGrid({
|
|
|
2374
2805
|
] }, headerGroup.id)
|
|
2375
2806
|
] }, headerGroup.id);
|
|
2376
2807
|
}),
|
|
2377
|
-
hasFilterRow && /* @__PURE__ */
|
|
2378
|
-
showDetailColumn && /* @__PURE__ */
|
|
2379
|
-
showSelectionColumn && /* @__PURE__ */
|
|
2808
|
+
hasFilterRow && /* @__PURE__ */ jsxs17("tr", { "data-testid": "filter-row", className: "divide-x divide-border", children: [
|
|
2809
|
+
showDetailColumn && /* @__PURE__ */ jsx26("th", { className: detailHeaderCellProps.className, style: detailHeaderCellProps.style }),
|
|
2810
|
+
showSelectionColumn && /* @__PURE__ */ jsx26(
|
|
2380
2811
|
"th",
|
|
2381
2812
|
{
|
|
2382
2813
|
className: selectionHeaderCellProps.className,
|
|
@@ -2385,9 +2816,9 @@ function DataGrid({
|
|
|
2385
2816
|
),
|
|
2386
2817
|
visibleColumns.map((column) => {
|
|
2387
2818
|
const cellProps = filterHeaderCellPropsByColumn.get(column.id);
|
|
2388
|
-
return /* @__PURE__ */
|
|
2819
|
+
return /* @__PURE__ */ jsx26("th", { style: cellProps?.style, className: cellProps?.className, children: isFilterable(column) && column.filterDisplay === "row" ? renderFilterWidget(column) : null }, column.id);
|
|
2389
2820
|
}),
|
|
2390
|
-
showRowActionsColumn && /* @__PURE__ */
|
|
2821
|
+
showRowActionsColumn && /* @__PURE__ */ jsx26(
|
|
2391
2822
|
"th",
|
|
2392
2823
|
{
|
|
2393
2824
|
className: rowActionsHeaderCellProps.className,
|
|
@@ -2396,19 +2827,19 @@ function DataGrid({
|
|
|
2396
2827
|
)
|
|
2397
2828
|
] })
|
|
2398
2829
|
] }),
|
|
2399
|
-
rows.length === 0 ? /* @__PURE__ */
|
|
2400
|
-
paddingTop > 0 && /* @__PURE__ */
|
|
2830
|
+
rows.length === 0 ? /* @__PURE__ */ jsx26("tbody", { children: /* @__PURE__ */ jsx26("tr", { children: /* @__PURE__ */ jsx26("td", { colSpan: totalColumnCount, className: "p-4 text-center text-muted-foreground", children: loading ? "Loading..." : "No results." }) }) }) : shouldVirtualize ? /* @__PURE__ */ jsxs17(Fragment3, { children: [
|
|
2831
|
+
paddingTop > 0 && /* @__PURE__ */ jsx26("tbody", { children: /* @__PURE__ */ jsx26("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx26("td", { colSpan: totalColumnCount, style: { padding: 0, border: "none", height: paddingTop } }) }) }),
|
|
2401
2832
|
virtualItems.map(
|
|
2402
2833
|
(virtualItem) => renderRow(tableRows[virtualItem.index], (el) => virtualizer.measureElement(el))
|
|
2403
2834
|
),
|
|
2404
|
-
paddingBottom > 0 && /* @__PURE__ */
|
|
2835
|
+
paddingBottom > 0 && /* @__PURE__ */ jsx26("tbody", { children: /* @__PURE__ */ jsx26("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx26("td", { colSpan: totalColumnCount, style: { padding: 0, border: "none", height: paddingBottom } }) }) })
|
|
2405
2836
|
] }) : groupedBuckets ? groupedBuckets.map((bucket) => renderGroupedBucket(bucket)) : tableRows.map((row) => renderRow(row))
|
|
2406
2837
|
] })
|
|
2407
2838
|
}
|
|
2408
2839
|
)
|
|
2409
2840
|
] }),
|
|
2410
|
-
showPagination && /* @__PURE__ */
|
|
2411
|
-
/* @__PURE__ */
|
|
2841
|
+
showPagination && /* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center justify-between text-sm", children: [
|
|
2842
|
+
/* @__PURE__ */ jsxs17("span", { children: [
|
|
2412
2843
|
"Page ",
|
|
2413
2844
|
state.page + 1,
|
|
2414
2845
|
" of ",
|
|
@@ -2419,8 +2850,8 @@ function DataGrid({
|
|
|
2419
2850
|
rowCount === 1 ? "" : "s",
|
|
2420
2851
|
")"
|
|
2421
2852
|
] }),
|
|
2422
|
-
/* @__PURE__ */
|
|
2423
|
-
/* @__PURE__ */
|
|
2853
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex gap-2", children: [
|
|
2854
|
+
/* @__PURE__ */ jsx26(
|
|
2424
2855
|
Button,
|
|
2425
2856
|
{
|
|
2426
2857
|
variant: "outline",
|
|
@@ -2430,7 +2861,7 @@ function DataGrid({
|
|
|
2430
2861
|
children: "Previous"
|
|
2431
2862
|
}
|
|
2432
2863
|
),
|
|
2433
|
-
/* @__PURE__ */
|
|
2864
|
+
/* @__PURE__ */ jsx26(
|
|
2434
2865
|
Button,
|
|
2435
2866
|
{
|
|
2436
2867
|
variant: "outline",
|
|
@@ -2611,7 +3042,7 @@ function useTreeState({
|
|
|
2611
3042
|
}
|
|
2612
3043
|
|
|
2613
3044
|
// src/tree/TreeDataGrid.tsx
|
|
2614
|
-
import { Fragment as Fragment4, jsx as
|
|
3045
|
+
import { Fragment as Fragment4, jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2615
3046
|
var EMPTY_SELECTED_IDS = /* @__PURE__ */ new Set();
|
|
2616
3047
|
var UNCHECKED_STATE = { checked: false, indeterminate: false };
|
|
2617
3048
|
function renderCell(column, row) {
|
|
@@ -2627,8 +3058,8 @@ function TreeCell({
|
|
|
2627
3058
|
onToggle,
|
|
2628
3059
|
onRetry
|
|
2629
3060
|
}) {
|
|
2630
|
-
return /* @__PURE__ */
|
|
2631
|
-
flatRow.hasChildren ? /* @__PURE__ */
|
|
3061
|
+
return /* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-1", style: { paddingLeft: flatRow.depth * indentSize }, children: [
|
|
3062
|
+
flatRow.hasChildren ? /* @__PURE__ */ jsx27(
|
|
2632
3063
|
"button",
|
|
2633
3064
|
{
|
|
2634
3065
|
type: "button",
|
|
@@ -2640,14 +3071,14 @@ function TreeCell({
|
|
|
2640
3071
|
"aria-label": flatRow.isExpanded ? "Collapse" : "Expand",
|
|
2641
3072
|
"aria-expanded": flatRow.isExpanded,
|
|
2642
3073
|
className: "flex h-4 w-4 shrink-0 items-center justify-center text-muted-foreground hover:text-foreground disabled:opacity-50",
|
|
2643
|
-
children: isLoading ? /* @__PURE__ */
|
|
3074
|
+
children: isLoading ? /* @__PURE__ */ jsx27(Loader22, { className: "h-3.5 w-3.5 animate-spin", "aria-hidden": "true" }) : flatRow.isExpanded ? /* @__PURE__ */ jsx27(ChevronDown2, { className: "h-3.5 w-3.5", "aria-hidden": "true" }) : /* @__PURE__ */ jsx27(ChevronRight2, { className: "h-3.5 w-3.5", "aria-hidden": "true" })
|
|
2644
3075
|
}
|
|
2645
|
-
) : /* @__PURE__ */
|
|
2646
|
-
/* @__PURE__ */
|
|
2647
|
-
flatRow.isExpanded && error ? /* @__PURE__ */
|
|
2648
|
-
/* @__PURE__ */
|
|
3076
|
+
) : /* @__PURE__ */ jsx27("span", { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
|
|
3077
|
+
/* @__PURE__ */ jsx27("span", { className: "truncate", children: renderCell(column, flatRow.row) }),
|
|
3078
|
+
flatRow.isExpanded && error ? /* @__PURE__ */ jsxs18("span", { className: "ml-1 flex shrink-0 items-center gap-1 text-xs text-destructive", children: [
|
|
3079
|
+
/* @__PURE__ */ jsx27(AlertCircle, { className: "h-3 w-3", "aria-hidden": "true" }),
|
|
2649
3080
|
"Failed to load.",
|
|
2650
|
-
/* @__PURE__ */
|
|
3081
|
+
/* @__PURE__ */ jsx27("button", { type: "button", className: "underline underline-offset-2", onClick: onRetry, children: "Retry" })
|
|
2651
3082
|
] }) : null
|
|
2652
3083
|
] });
|
|
2653
3084
|
}
|
|
@@ -2754,7 +3185,7 @@ function TreeDataGrid({
|
|
|
2754
3185
|
const rowProps = getRowProps?.(flatRow.row, flatRow.depth, index);
|
|
2755
3186
|
const rowTestId = getRowTestId?.(flatRow.row) ?? `tree-row-${flatRow.id}`;
|
|
2756
3187
|
const isOddRow = zebra && index % 2 === 1;
|
|
2757
|
-
return /* @__PURE__ */
|
|
3188
|
+
return /* @__PURE__ */ jsxs18(
|
|
2758
3189
|
"tr",
|
|
2759
3190
|
{
|
|
2760
3191
|
ref: measureRef,
|
|
@@ -2767,9 +3198,9 @@ function TreeDataGrid({
|
|
|
2767
3198
|
isOddRow && "bg-foreground/5"
|
|
2768
3199
|
) : `border-b border-border divide-x divide-border${isOddRow ? " bg-foreground/5" : ""}`,
|
|
2769
3200
|
children: [
|
|
2770
|
-
showSelectionColumn && /* @__PURE__ */
|
|
3201
|
+
showSelectionColumn && /* @__PURE__ */ jsx27("td", { className: "p-1", style: { width: SELECTION_COLUMN_WIDTH }, children: (() => {
|
|
2771
3202
|
const state = resolveSelectionState(flatRow.row, flatRow.id);
|
|
2772
|
-
return /* @__PURE__ */
|
|
3203
|
+
return /* @__PURE__ */ jsx27(
|
|
2773
3204
|
Checkbox,
|
|
2774
3205
|
{
|
|
2775
3206
|
"aria-label": `Select row ${flatRow.id}`,
|
|
@@ -2780,7 +3211,7 @@ function TreeDataGrid({
|
|
|
2780
3211
|
}
|
|
2781
3212
|
);
|
|
2782
3213
|
})() }),
|
|
2783
|
-
columns.map((column) => /* @__PURE__ */
|
|
3214
|
+
columns.map((column) => /* @__PURE__ */ jsx27("td", { className: bodyTdClassByColumn.get(column.id), children: column.id === treeColId ? /* @__PURE__ */ jsx27(
|
|
2784
3215
|
TreeCell,
|
|
2785
3216
|
{
|
|
2786
3217
|
flatRow,
|
|
@@ -2792,7 +3223,7 @@ function TreeDataGrid({
|
|
|
2792
3223
|
onRetry: () => retry(flatRow.row)
|
|
2793
3224
|
}
|
|
2794
3225
|
) : renderCell(column, flatRow.row) }, column.id)),
|
|
2795
|
-
showRowActionsColumn && rowActions && /* @__PURE__ */
|
|
3226
|
+
showRowActionsColumn && rowActions && /* @__PURE__ */ jsx27("td", { className: "p-2", children: /* @__PURE__ */ jsx27(
|
|
2796
3227
|
ActionsMenu,
|
|
2797
3228
|
{
|
|
2798
3229
|
items: rowActions,
|
|
@@ -2808,15 +3239,15 @@ function TreeDataGrid({
|
|
|
2808
3239
|
const virtualItems = shouldVirtualize ? virtualizer.getVirtualItems() : [];
|
|
2809
3240
|
const paddingTop = virtualItems.length > 0 ? virtualItems[0].start : 0;
|
|
2810
3241
|
const paddingBottom = virtualItems.length > 0 ? virtualizer.getTotalSize() - virtualItems[virtualItems.length - 1].end : 0;
|
|
2811
|
-
return /* @__PURE__ */
|
|
3242
|
+
return /* @__PURE__ */ jsx27("div", { className: "flex flex-col gap-2", "data-testid": "tree-datagrid", children: /* @__PURE__ */ jsx27(
|
|
2812
3243
|
"div",
|
|
2813
3244
|
{
|
|
2814
3245
|
ref: scrollRef,
|
|
2815
3246
|
className: shouldVirtualize ? "overflow-y-auto" : void 0,
|
|
2816
3247
|
style: shouldVirtualize ? { maxHeight: maxBodyHeight } : void 0,
|
|
2817
|
-
children: /* @__PURE__ */
|
|
2818
|
-
/* @__PURE__ */
|
|
2819
|
-
showSelectionColumn && /* @__PURE__ */
|
|
3248
|
+
children: /* @__PURE__ */ jsxs18("table", { className: "w-full border-collapse text-sm", children: [
|
|
3249
|
+
/* @__PURE__ */ jsx27("thead", { children: /* @__PURE__ */ jsxs18("tr", { className: "divide-x divide-border", children: [
|
|
3250
|
+
showSelectionColumn && /* @__PURE__ */ jsx27("th", { className: "border-b border-border p-1", style: { width: SELECTION_COLUMN_WIDTH }, children: /* @__PURE__ */ jsx27(
|
|
2820
3251
|
Checkbox,
|
|
2821
3252
|
{
|
|
2822
3253
|
"aria-label": "Select all visible rows",
|
|
@@ -2824,7 +3255,7 @@ function TreeDataGrid({
|
|
|
2824
3255
|
onCheckedChange: toggleAllVisibleSelected
|
|
2825
3256
|
}
|
|
2826
3257
|
) }),
|
|
2827
|
-
columns.map((column) => /* @__PURE__ */
|
|
3258
|
+
columns.map((column) => /* @__PURE__ */ jsx27(
|
|
2828
3259
|
"th",
|
|
2829
3260
|
{
|
|
2830
3261
|
style: column.width ? { width: column.width } : void 0,
|
|
@@ -2833,14 +3264,14 @@ function TreeDataGrid({
|
|
|
2833
3264
|
},
|
|
2834
3265
|
column.id
|
|
2835
3266
|
)),
|
|
2836
|
-
showRowActionsColumn && /* @__PURE__ */
|
|
3267
|
+
showRowActionsColumn && /* @__PURE__ */ jsx27("th", { className: "border-b border-border p-2", "aria-label": "Row actions" })
|
|
2837
3268
|
] }) }),
|
|
2838
|
-
/* @__PURE__ */
|
|
2839
|
-
paddingTop > 0 && /* @__PURE__ */
|
|
3269
|
+
/* @__PURE__ */ jsx27("tbody", { children: flatRows.length === 0 ? /* @__PURE__ */ jsx27("tr", { children: /* @__PURE__ */ jsx27("td", { colSpan: totalColumnCount, className: "p-4 text-center text-muted-foreground", children: "No results." }) }) : shouldVirtualize ? /* @__PURE__ */ jsxs18(Fragment4, { children: [
|
|
3270
|
+
paddingTop > 0 && /* @__PURE__ */ jsx27("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx27("td", { colSpan: totalColumnCount, style: { padding: 0, border: "none", height: paddingTop } }) }),
|
|
2840
3271
|
virtualItems.map(
|
|
2841
3272
|
(virtualItem) => renderRow(flatRows[virtualItem.index], virtualItem.index, (el) => virtualizer.measureElement(el))
|
|
2842
3273
|
),
|
|
2843
|
-
paddingBottom > 0 && /* @__PURE__ */
|
|
3274
|
+
paddingBottom > 0 && /* @__PURE__ */ jsx27("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx27(
|
|
2844
3275
|
"td",
|
|
2845
3276
|
{
|
|
2846
3277
|
colSpan: totalColumnCount,
|
|
@@ -2854,14 +3285,20 @@ function TreeDataGrid({
|
|
|
2854
3285
|
}
|
|
2855
3286
|
export {
|
|
2856
3287
|
ActionsMenu,
|
|
3288
|
+
BooleanEditor,
|
|
2857
3289
|
BooleanFilter,
|
|
2858
3290
|
ColumnSelector,
|
|
2859
3291
|
DataGrid,
|
|
3292
|
+
DateEditor,
|
|
2860
3293
|
DateRangeFilter,
|
|
3294
|
+
EditFieldError,
|
|
3295
|
+
EnumEditor,
|
|
2861
3296
|
EnumFilter,
|
|
2862
3297
|
NumberComparisonFilter,
|
|
3298
|
+
NumberEditor,
|
|
2863
3299
|
NumberHistogramFilter,
|
|
2864
3300
|
NumberRangeFilter,
|
|
3301
|
+
StringEditor,
|
|
2865
3302
|
StringFilter,
|
|
2866
3303
|
TreeDataGrid,
|
|
2867
3304
|
UNARY_OPERATORS,
|
|
@@ -2871,6 +3308,7 @@ export {
|
|
|
2871
3308
|
countVisible,
|
|
2872
3309
|
defaultAlign,
|
|
2873
3310
|
defaultFormat,
|
|
3311
|
+
editErrorId,
|
|
2874
3312
|
evaluateFilter,
|
|
2875
3313
|
facetedNumberValues,
|
|
2876
3314
|
fieldKey,
|
|
@@ -2879,13 +3317,16 @@ export {
|
|
|
2879
3317
|
groupColumns,
|
|
2880
3318
|
isColumnVisible,
|
|
2881
3319
|
isCompositeFilterDescriptor,
|
|
3320
|
+
isEditable,
|
|
2882
3321
|
isFilterDescriptor,
|
|
2883
3322
|
isFilterable,
|
|
2884
3323
|
isSortable,
|
|
2885
3324
|
processClientData,
|
|
3325
|
+
renderDefaultEditWidget,
|
|
2886
3326
|
renderDefaultFilterWidget,
|
|
2887
3327
|
resolveMenuItems,
|
|
2888
3328
|
storageKeyFor,
|
|
3329
|
+
toDate,
|
|
2889
3330
|
useDebouncedCallback,
|
|
2890
3331
|
useGridState,
|
|
2891
3332
|
useTreeState
|