@bmsuisse/datagrid 0.25.3 → 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 +535 -117
- 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,
|
|
@@ -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);
|
|
@@ -2103,20 +2462,20 @@ function DataGrid({
|
|
|
2103
2462
|
const rowProps = getRowProps?.(row.original);
|
|
2104
2463
|
const rowTestId = getRowTestId?.(row.original) ?? `row-${row.id}`;
|
|
2105
2464
|
const isOddRow = zebra && row.index % 2 === 1;
|
|
2106
|
-
return /* @__PURE__ */
|
|
2107
|
-
/* @__PURE__ */
|
|
2465
|
+
return /* @__PURE__ */ jsxs17("tbody", { ref: measureRef, "data-index": row.index, children: [
|
|
2466
|
+
/* @__PURE__ */ jsxs17(
|
|
2108
2467
|
"tr",
|
|
2109
2468
|
{
|
|
2110
2469
|
...rowProps,
|
|
2111
2470
|
"data-testid": rowTestId,
|
|
2112
2471
|
className: rowProps?.className ? cn("divide-x divide-border", rowProps.className, isOddRow && "bg-foreground/5") : `divide-x divide-border${isOddRow ? " bg-foreground/5" : ""}`,
|
|
2113
2472
|
children: [
|
|
2114
|
-
showDetailColumn && /* @__PURE__ */
|
|
2473
|
+
showDetailColumn && /* @__PURE__ */ jsx26(
|
|
2115
2474
|
"td",
|
|
2116
2475
|
{
|
|
2117
2476
|
className: isOddRow ? detailCellProps.classNameOdd : detailCellProps.className,
|
|
2118
2477
|
style: detailCellProps.style,
|
|
2119
|
-
children: /* @__PURE__ */
|
|
2478
|
+
children: /* @__PURE__ */ jsx26(
|
|
2120
2479
|
Button,
|
|
2121
2480
|
{
|
|
2122
2481
|
type: "button",
|
|
@@ -2128,7 +2487,7 @@ function DataGrid({
|
|
|
2128
2487
|
stopRowClick(event);
|
|
2129
2488
|
toggleRowExpanded(row.id);
|
|
2130
2489
|
},
|
|
2131
|
-
children: /* @__PURE__ */
|
|
2490
|
+
children: /* @__PURE__ */ jsx26(
|
|
2132
2491
|
ChevronRight,
|
|
2133
2492
|
{
|
|
2134
2493
|
className: `h-4 w-4 transition-transform${isExpanded ? " rotate-90" : ""}`,
|
|
@@ -2139,12 +2498,12 @@ function DataGrid({
|
|
|
2139
2498
|
)
|
|
2140
2499
|
}
|
|
2141
2500
|
),
|
|
2142
|
-
showSelectionColumn && /* @__PURE__ */
|
|
2501
|
+
showSelectionColumn && /* @__PURE__ */ jsx26(
|
|
2143
2502
|
"td",
|
|
2144
2503
|
{
|
|
2145
2504
|
className: isOddRow ? selectionCellProps.classNameOdd : selectionCellProps.className,
|
|
2146
2505
|
style: selectionCellProps.style,
|
|
2147
|
-
children: /* @__PURE__ */
|
|
2506
|
+
children: /* @__PURE__ */ jsx26(
|
|
2148
2507
|
"input",
|
|
2149
2508
|
{
|
|
2150
2509
|
type: "checkbox",
|
|
@@ -2158,27 +2517,27 @@ function DataGrid({
|
|
|
2158
2517
|
),
|
|
2159
2518
|
row.getAllCells().map((cell) => {
|
|
2160
2519
|
const cellProps = bodyCellPropsByColumn.get(cell.column.id);
|
|
2161
|
-
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);
|
|
2162
2521
|
}),
|
|
2163
|
-
showRowActionsColumn && rowActions && /* @__PURE__ */
|
|
2522
|
+
showRowActionsColumn && rowActions && /* @__PURE__ */ jsx26(
|
|
2164
2523
|
"td",
|
|
2165
2524
|
{
|
|
2166
2525
|
className: isOddRow ? rowActionsCellProps.classNameOdd : rowActionsCellProps.className,
|
|
2167
2526
|
style: rowActionsCellProps.style,
|
|
2168
|
-
children: /* @__PURE__ */
|
|
2527
|
+
children: /* @__PURE__ */ jsx26(ActionsMenu, { items: rowActions, ctx: { row: row.original }, triggerLabel: `Row actions for ${row.id}` })
|
|
2169
2528
|
}
|
|
2170
2529
|
)
|
|
2171
2530
|
]
|
|
2172
2531
|
}
|
|
2173
2532
|
),
|
|
2174
|
-
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) }) })
|
|
2175
2534
|
] }, row.id);
|
|
2176
2535
|
}
|
|
2177
2536
|
function renderGroupedBucket(bucket) {
|
|
2178
2537
|
const expanded = isGroupExpanded(bucket.key);
|
|
2179
2538
|
const originalRows = bucket.items.map((row) => row.original);
|
|
2180
|
-
return /* @__PURE__ */
|
|
2181
|
-
/* @__PURE__ */
|
|
2539
|
+
return /* @__PURE__ */ jsxs17(Fragment2, { children: [
|
|
2540
|
+
/* @__PURE__ */ jsx26("tbody", { children: /* @__PURE__ */ jsx26("tr", { "data-testid": `group-header-${bucket.key}`, children: /* @__PURE__ */ jsx26(
|
|
2182
2541
|
"td",
|
|
2183
2542
|
{
|
|
2184
2543
|
colSpan: totalColumnCount,
|
|
@@ -2187,7 +2546,7 @@ function DataGrid({
|
|
|
2187
2546
|
zebra ? "bg-muted" : "bg-background"
|
|
2188
2547
|
),
|
|
2189
2548
|
style: { top: groupHeaderTop },
|
|
2190
|
-
children: /* @__PURE__ */
|
|
2549
|
+
children: /* @__PURE__ */ jsxs17(
|
|
2191
2550
|
"button",
|
|
2192
2551
|
{
|
|
2193
2552
|
type: "button",
|
|
@@ -2195,7 +2554,7 @@ function DataGrid({
|
|
|
2195
2554
|
onClick: () => toggleGroupExpanded(bucket.key),
|
|
2196
2555
|
"aria-expanded": expanded,
|
|
2197
2556
|
children: [
|
|
2198
|
-
/* @__PURE__ */
|
|
2557
|
+
/* @__PURE__ */ jsx26(
|
|
2199
2558
|
ChevronRight,
|
|
2200
2559
|
{
|
|
2201
2560
|
className: `h-4 w-4 shrink-0 transition-transform${expanded ? " rotate-90" : ""}`,
|
|
@@ -2224,32 +2583,81 @@ function DataGrid({
|
|
|
2224
2583
|
// containers (that one scrolling vertically, this component's own
|
|
2225
2584
|
// `overflow-x-auto` div scrolling horizontally) fighting over which one
|
|
2226
2585
|
// a sticky header/pinned column is actually stuck relative to.
|
|
2227
|
-
/* @__PURE__ */
|
|
2228
|
-
|
|
2229
|
-
|
|
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: [
|
|
2230
2638
|
selectedRows.length,
|
|
2231
2639
|
" selected"
|
|
2232
2640
|
] }),
|
|
2233
|
-
/* @__PURE__ */
|
|
2641
|
+
/* @__PURE__ */ jsx26(ActionsMenu, { items: headerActions, ctx: { selectedRows }, triggerLabel: "Bulk actions" })
|
|
2234
2642
|
] }),
|
|
2235
|
-
/* @__PURE__ */
|
|
2236
|
-
loading && /* @__PURE__ */
|
|
2643
|
+
/* @__PURE__ */ jsxs17("div", { className: "relative min-h-0 flex-1", children: [
|
|
2644
|
+
loading && /* @__PURE__ */ jsx26(
|
|
2237
2645
|
"div",
|
|
2238
2646
|
{
|
|
2239
2647
|
"data-testid": "datagrid-loading-overlay",
|
|
2240
2648
|
className: "absolute inset-0 z-30 flex items-center justify-center bg-background/60",
|
|
2241
|
-
children: /* @__PURE__ */
|
|
2649
|
+
children: /* @__PURE__ */ jsx26(Loader2, { className: "h-6 w-6 animate-spin text-muted-foreground", "aria-hidden": true })
|
|
2242
2650
|
}
|
|
2243
2651
|
),
|
|
2244
|
-
/* @__PURE__ */
|
|
2652
|
+
/* @__PURE__ */ jsx26(
|
|
2245
2653
|
"div",
|
|
2246
2654
|
{
|
|
2247
2655
|
ref: scrollRef,
|
|
2248
2656
|
"data-testid": testId,
|
|
2249
2657
|
className: "h-full overflow-auto rounded-md border",
|
|
2250
2658
|
style: shouldVirtualize ? { maxHeight: virtualize?.maxBodyHeight ?? 480 } : void 0,
|
|
2251
|
-
children: /* @__PURE__ */
|
|
2252
|
-
/* @__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: [
|
|
2253
2661
|
table.getHeaderGroups().map((headerGroup) => {
|
|
2254
2662
|
const headerById = new Map(headerGroup.headers.map((header) => [header.id, header]));
|
|
2255
2663
|
function renderLeafHeaderCell(column, rowSpan) {
|
|
@@ -2260,9 +2668,9 @@ function DataGrid({
|
|
|
2260
2668
|
const filterable = isFilterable(column) && column.filterDisplay !== "row";
|
|
2261
2669
|
const cellProps = leafHeaderCellPropsByColumn.get(column.id);
|
|
2262
2670
|
const headerContent = column.renderHeader ? column.renderHeader(column) : column.header;
|
|
2263
|
-
return /* @__PURE__ */
|
|
2264
|
-
/* @__PURE__ */
|
|
2265
|
-
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(
|
|
2266
2674
|
"button",
|
|
2267
2675
|
{
|
|
2268
2676
|
type: "button",
|
|
@@ -2270,8 +2678,8 @@ function DataGrid({
|
|
|
2270
2678
|
onClick: (event) => toggleSort(column.id, enableMultiSort && event.shiftKey, column.sortDescFirst === true),
|
|
2271
2679
|
children: [
|
|
2272
2680
|
headerContent,
|
|
2273
|
-
sortEntry?.dir === "asc" && /* @__PURE__ */
|
|
2274
|
-
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 })
|
|
2275
2683
|
]
|
|
2276
2684
|
}
|
|
2277
2685
|
) : (
|
|
@@ -2280,10 +2688,10 @@ function DataGrid({
|
|
|
2280
2688
|
// silently breaking any interactive content a column's own `renderHeader`
|
|
2281
2689
|
// embeds directly (bare filter inputs, "select/reject all" buttons) —
|
|
2282
2690
|
// clicks never reach them at all, even though nothing looks wrong visually.
|
|
2283
|
-
/* @__PURE__ */
|
|
2691
|
+
/* @__PURE__ */ jsx26("div", { className: "flex items-center gap-1 px-1", children: headerContent })
|
|
2284
2692
|
),
|
|
2285
|
-
filterable && /* @__PURE__ */
|
|
2286
|
-
/* @__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(
|
|
2287
2695
|
FunnelIcon7,
|
|
2288
2696
|
{
|
|
2289
2697
|
className: cn(
|
|
@@ -2293,10 +2701,10 @@ function DataGrid({
|
|
|
2293
2701
|
"aria-hidden": true
|
|
2294
2702
|
}
|
|
2295
2703
|
) }) }),
|
|
2296
|
-
/* @__PURE__ */
|
|
2704
|
+
/* @__PURE__ */ jsx26(PopoverContent, { children: renderFilterWidget(column) })
|
|
2297
2705
|
] })
|
|
2298
2706
|
] }),
|
|
2299
|
-
enableColumnResizing && /* @__PURE__ */
|
|
2707
|
+
enableColumnResizing && /* @__PURE__ */ jsx26(
|
|
2300
2708
|
"div",
|
|
2301
2709
|
{
|
|
2302
2710
|
"data-testid": `resize-handle-${column.id}`,
|
|
@@ -2307,9 +2715,9 @@ function DataGrid({
|
|
|
2307
2715
|
)
|
|
2308
2716
|
] }, header.id);
|
|
2309
2717
|
}
|
|
2310
|
-
return /* @__PURE__ */
|
|
2311
|
-
hasHeaderGroups && /* @__PURE__ */
|
|
2312
|
-
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(
|
|
2313
2721
|
"th",
|
|
2314
2722
|
{
|
|
2315
2723
|
rowSpan: 2,
|
|
@@ -2318,13 +2726,13 @@ function DataGrid({
|
|
|
2318
2726
|
"aria-hidden": true
|
|
2319
2727
|
}
|
|
2320
2728
|
),
|
|
2321
|
-
showSelectionColumn && /* @__PURE__ */
|
|
2729
|
+
showSelectionColumn && /* @__PURE__ */ jsx26(
|
|
2322
2730
|
"th",
|
|
2323
2731
|
{
|
|
2324
2732
|
rowSpan: 2,
|
|
2325
2733
|
className: selectionHeaderCellProps.className,
|
|
2326
2734
|
style: selectionHeaderCellProps.style,
|
|
2327
|
-
children: /* @__PURE__ */
|
|
2735
|
+
children: /* @__PURE__ */ jsx26(
|
|
2328
2736
|
"input",
|
|
2329
2737
|
{
|
|
2330
2738
|
type: "checkbox",
|
|
@@ -2336,7 +2744,7 @@ function DataGrid({
|
|
|
2336
2744
|
}
|
|
2337
2745
|
),
|
|
2338
2746
|
headerRuns.map(
|
|
2339
|
-
(run) => run.kind === "single" ? renderLeafHeaderCell(run.column, 2) : /* @__PURE__ */
|
|
2747
|
+
(run) => run.kind === "single" ? renderLeafHeaderCell(run.column, 2) : /* @__PURE__ */ jsx26(
|
|
2340
2748
|
"th",
|
|
2341
2749
|
{
|
|
2342
2750
|
colSpan: run.columns.length,
|
|
@@ -2346,7 +2754,7 @@ function DataGrid({
|
|
|
2346
2754
|
`group-${run.label}-${run.columns[0].id}`
|
|
2347
2755
|
)
|
|
2348
2756
|
),
|
|
2349
|
-
showRowActionsColumn && /* @__PURE__ */
|
|
2757
|
+
showRowActionsColumn && /* @__PURE__ */ jsx26(
|
|
2350
2758
|
"th",
|
|
2351
2759
|
{
|
|
2352
2760
|
rowSpan: 2,
|
|
@@ -2356,8 +2764,8 @@ function DataGrid({
|
|
|
2356
2764
|
}
|
|
2357
2765
|
)
|
|
2358
2766
|
] }, `${headerGroup.id}-groups`),
|
|
2359
|
-
/* @__PURE__ */
|
|
2360
|
-
!hasHeaderGroups && showDetailColumn && /* @__PURE__ */
|
|
2767
|
+
/* @__PURE__ */ jsxs17("tr", { className: "divide-x divide-border", children: [
|
|
2768
|
+
!hasHeaderGroups && showDetailColumn && /* @__PURE__ */ jsx26(
|
|
2361
2769
|
"th",
|
|
2362
2770
|
{
|
|
2363
2771
|
className: detailHeaderCellProps.className,
|
|
@@ -2365,12 +2773,12 @@ function DataGrid({
|
|
|
2365
2773
|
"aria-hidden": true
|
|
2366
2774
|
}
|
|
2367
2775
|
),
|
|
2368
|
-
!hasHeaderGroups && showSelectionColumn && /* @__PURE__ */
|
|
2776
|
+
!hasHeaderGroups && showSelectionColumn && /* @__PURE__ */ jsx26(
|
|
2369
2777
|
"th",
|
|
2370
2778
|
{
|
|
2371
2779
|
className: selectionHeaderCellProps.className,
|
|
2372
2780
|
style: selectionHeaderCellProps.style,
|
|
2373
|
-
children: /* @__PURE__ */
|
|
2781
|
+
children: /* @__PURE__ */ jsx26(
|
|
2374
2782
|
"input",
|
|
2375
2783
|
{
|
|
2376
2784
|
type: "checkbox",
|
|
@@ -2386,7 +2794,7 @@ function DataGrid({
|
|
|
2386
2794
|
if (!column || hasHeaderGroups && !column.headerGroup) return null;
|
|
2387
2795
|
return renderLeafHeaderCell(column);
|
|
2388
2796
|
}),
|
|
2389
|
-
!hasHeaderGroups && showRowActionsColumn && /* @__PURE__ */
|
|
2797
|
+
!hasHeaderGroups && showRowActionsColumn && /* @__PURE__ */ jsx26(
|
|
2390
2798
|
"th",
|
|
2391
2799
|
{
|
|
2392
2800
|
className: rowActionsHeaderCellProps.className,
|
|
@@ -2397,9 +2805,9 @@ function DataGrid({
|
|
|
2397
2805
|
] }, headerGroup.id)
|
|
2398
2806
|
] }, headerGroup.id);
|
|
2399
2807
|
}),
|
|
2400
|
-
hasFilterRow && /* @__PURE__ */
|
|
2401
|
-
showDetailColumn && /* @__PURE__ */
|
|
2402
|
-
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(
|
|
2403
2811
|
"th",
|
|
2404
2812
|
{
|
|
2405
2813
|
className: selectionHeaderCellProps.className,
|
|
@@ -2408,9 +2816,9 @@ function DataGrid({
|
|
|
2408
2816
|
),
|
|
2409
2817
|
visibleColumns.map((column) => {
|
|
2410
2818
|
const cellProps = filterHeaderCellPropsByColumn.get(column.id);
|
|
2411
|
-
return /* @__PURE__ */
|
|
2819
|
+
return /* @__PURE__ */ jsx26("th", { style: cellProps?.style, className: cellProps?.className, children: isFilterable(column) && column.filterDisplay === "row" ? renderFilterWidget(column) : null }, column.id);
|
|
2412
2820
|
}),
|
|
2413
|
-
showRowActionsColumn && /* @__PURE__ */
|
|
2821
|
+
showRowActionsColumn && /* @__PURE__ */ jsx26(
|
|
2414
2822
|
"th",
|
|
2415
2823
|
{
|
|
2416
2824
|
className: rowActionsHeaderCellProps.className,
|
|
@@ -2419,19 +2827,19 @@ function DataGrid({
|
|
|
2419
2827
|
)
|
|
2420
2828
|
] })
|
|
2421
2829
|
] }),
|
|
2422
|
-
rows.length === 0 ? /* @__PURE__ */
|
|
2423
|
-
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 } }) }) }),
|
|
2424
2832
|
virtualItems.map(
|
|
2425
2833
|
(virtualItem) => renderRow(tableRows[virtualItem.index], (el) => virtualizer.measureElement(el))
|
|
2426
2834
|
),
|
|
2427
|
-
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 } }) }) })
|
|
2428
2836
|
] }) : groupedBuckets ? groupedBuckets.map((bucket) => renderGroupedBucket(bucket)) : tableRows.map((row) => renderRow(row))
|
|
2429
2837
|
] })
|
|
2430
2838
|
}
|
|
2431
2839
|
)
|
|
2432
2840
|
] }),
|
|
2433
|
-
showPagination && /* @__PURE__ */
|
|
2434
|
-
/* @__PURE__ */
|
|
2841
|
+
showPagination && /* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center justify-between text-sm", children: [
|
|
2842
|
+
/* @__PURE__ */ jsxs17("span", { children: [
|
|
2435
2843
|
"Page ",
|
|
2436
2844
|
state.page + 1,
|
|
2437
2845
|
" of ",
|
|
@@ -2442,8 +2850,8 @@ function DataGrid({
|
|
|
2442
2850
|
rowCount === 1 ? "" : "s",
|
|
2443
2851
|
")"
|
|
2444
2852
|
] }),
|
|
2445
|
-
/* @__PURE__ */
|
|
2446
|
-
/* @__PURE__ */
|
|
2853
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex gap-2", children: [
|
|
2854
|
+
/* @__PURE__ */ jsx26(
|
|
2447
2855
|
Button,
|
|
2448
2856
|
{
|
|
2449
2857
|
variant: "outline",
|
|
@@ -2453,7 +2861,7 @@ function DataGrid({
|
|
|
2453
2861
|
children: "Previous"
|
|
2454
2862
|
}
|
|
2455
2863
|
),
|
|
2456
|
-
/* @__PURE__ */
|
|
2864
|
+
/* @__PURE__ */ jsx26(
|
|
2457
2865
|
Button,
|
|
2458
2866
|
{
|
|
2459
2867
|
variant: "outline",
|
|
@@ -2634,7 +3042,7 @@ function useTreeState({
|
|
|
2634
3042
|
}
|
|
2635
3043
|
|
|
2636
3044
|
// src/tree/TreeDataGrid.tsx
|
|
2637
|
-
import { Fragment as Fragment4, jsx as
|
|
3045
|
+
import { Fragment as Fragment4, jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2638
3046
|
var EMPTY_SELECTED_IDS = /* @__PURE__ */ new Set();
|
|
2639
3047
|
var UNCHECKED_STATE = { checked: false, indeterminate: false };
|
|
2640
3048
|
function renderCell(column, row) {
|
|
@@ -2650,8 +3058,8 @@ function TreeCell({
|
|
|
2650
3058
|
onToggle,
|
|
2651
3059
|
onRetry
|
|
2652
3060
|
}) {
|
|
2653
|
-
return /* @__PURE__ */
|
|
2654
|
-
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(
|
|
2655
3063
|
"button",
|
|
2656
3064
|
{
|
|
2657
3065
|
type: "button",
|
|
@@ -2663,14 +3071,14 @@ function TreeCell({
|
|
|
2663
3071
|
"aria-label": flatRow.isExpanded ? "Collapse" : "Expand",
|
|
2664
3072
|
"aria-expanded": flatRow.isExpanded,
|
|
2665
3073
|
className: "flex h-4 w-4 shrink-0 items-center justify-center text-muted-foreground hover:text-foreground disabled:opacity-50",
|
|
2666
|
-
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" })
|
|
2667
3075
|
}
|
|
2668
|
-
) : /* @__PURE__ */
|
|
2669
|
-
/* @__PURE__ */
|
|
2670
|
-
flatRow.isExpanded && error ? /* @__PURE__ */
|
|
2671
|
-
/* @__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" }),
|
|
2672
3080
|
"Failed to load.",
|
|
2673
|
-
/* @__PURE__ */
|
|
3081
|
+
/* @__PURE__ */ jsx27("button", { type: "button", className: "underline underline-offset-2", onClick: onRetry, children: "Retry" })
|
|
2674
3082
|
] }) : null
|
|
2675
3083
|
] });
|
|
2676
3084
|
}
|
|
@@ -2777,7 +3185,7 @@ function TreeDataGrid({
|
|
|
2777
3185
|
const rowProps = getRowProps?.(flatRow.row, flatRow.depth, index);
|
|
2778
3186
|
const rowTestId = getRowTestId?.(flatRow.row) ?? `tree-row-${flatRow.id}`;
|
|
2779
3187
|
const isOddRow = zebra && index % 2 === 1;
|
|
2780
|
-
return /* @__PURE__ */
|
|
3188
|
+
return /* @__PURE__ */ jsxs18(
|
|
2781
3189
|
"tr",
|
|
2782
3190
|
{
|
|
2783
3191
|
ref: measureRef,
|
|
@@ -2790,9 +3198,9 @@ function TreeDataGrid({
|
|
|
2790
3198
|
isOddRow && "bg-foreground/5"
|
|
2791
3199
|
) : `border-b border-border divide-x divide-border${isOddRow ? " bg-foreground/5" : ""}`,
|
|
2792
3200
|
children: [
|
|
2793
|
-
showSelectionColumn && /* @__PURE__ */
|
|
3201
|
+
showSelectionColumn && /* @__PURE__ */ jsx27("td", { className: "p-1", style: { width: SELECTION_COLUMN_WIDTH }, children: (() => {
|
|
2794
3202
|
const state = resolveSelectionState(flatRow.row, flatRow.id);
|
|
2795
|
-
return /* @__PURE__ */
|
|
3203
|
+
return /* @__PURE__ */ jsx27(
|
|
2796
3204
|
Checkbox,
|
|
2797
3205
|
{
|
|
2798
3206
|
"aria-label": `Select row ${flatRow.id}`,
|
|
@@ -2803,7 +3211,7 @@ function TreeDataGrid({
|
|
|
2803
3211
|
}
|
|
2804
3212
|
);
|
|
2805
3213
|
})() }),
|
|
2806
|
-
columns.map((column) => /* @__PURE__ */
|
|
3214
|
+
columns.map((column) => /* @__PURE__ */ jsx27("td", { className: bodyTdClassByColumn.get(column.id), children: column.id === treeColId ? /* @__PURE__ */ jsx27(
|
|
2807
3215
|
TreeCell,
|
|
2808
3216
|
{
|
|
2809
3217
|
flatRow,
|
|
@@ -2815,7 +3223,7 @@ function TreeDataGrid({
|
|
|
2815
3223
|
onRetry: () => retry(flatRow.row)
|
|
2816
3224
|
}
|
|
2817
3225
|
) : renderCell(column, flatRow.row) }, column.id)),
|
|
2818
|
-
showRowActionsColumn && rowActions && /* @__PURE__ */
|
|
3226
|
+
showRowActionsColumn && rowActions && /* @__PURE__ */ jsx27("td", { className: "p-2", children: /* @__PURE__ */ jsx27(
|
|
2819
3227
|
ActionsMenu,
|
|
2820
3228
|
{
|
|
2821
3229
|
items: rowActions,
|
|
@@ -2831,15 +3239,15 @@ function TreeDataGrid({
|
|
|
2831
3239
|
const virtualItems = shouldVirtualize ? virtualizer.getVirtualItems() : [];
|
|
2832
3240
|
const paddingTop = virtualItems.length > 0 ? virtualItems[0].start : 0;
|
|
2833
3241
|
const paddingBottom = virtualItems.length > 0 ? virtualizer.getTotalSize() - virtualItems[virtualItems.length - 1].end : 0;
|
|
2834
|
-
return /* @__PURE__ */
|
|
3242
|
+
return /* @__PURE__ */ jsx27("div", { className: "flex flex-col gap-2", "data-testid": "tree-datagrid", children: /* @__PURE__ */ jsx27(
|
|
2835
3243
|
"div",
|
|
2836
3244
|
{
|
|
2837
3245
|
ref: scrollRef,
|
|
2838
3246
|
className: shouldVirtualize ? "overflow-y-auto" : void 0,
|
|
2839
3247
|
style: shouldVirtualize ? { maxHeight: maxBodyHeight } : void 0,
|
|
2840
|
-
children: /* @__PURE__ */
|
|
2841
|
-
/* @__PURE__ */
|
|
2842
|
-
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(
|
|
2843
3251
|
Checkbox,
|
|
2844
3252
|
{
|
|
2845
3253
|
"aria-label": "Select all visible rows",
|
|
@@ -2847,7 +3255,7 @@ function TreeDataGrid({
|
|
|
2847
3255
|
onCheckedChange: toggleAllVisibleSelected
|
|
2848
3256
|
}
|
|
2849
3257
|
) }),
|
|
2850
|
-
columns.map((column) => /* @__PURE__ */
|
|
3258
|
+
columns.map((column) => /* @__PURE__ */ jsx27(
|
|
2851
3259
|
"th",
|
|
2852
3260
|
{
|
|
2853
3261
|
style: column.width ? { width: column.width } : void 0,
|
|
@@ -2856,14 +3264,14 @@ function TreeDataGrid({
|
|
|
2856
3264
|
},
|
|
2857
3265
|
column.id
|
|
2858
3266
|
)),
|
|
2859
|
-
showRowActionsColumn && /* @__PURE__ */
|
|
3267
|
+
showRowActionsColumn && /* @__PURE__ */ jsx27("th", { className: "border-b border-border p-2", "aria-label": "Row actions" })
|
|
2860
3268
|
] }) }),
|
|
2861
|
-
/* @__PURE__ */
|
|
2862
|
-
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 } }) }),
|
|
2863
3271
|
virtualItems.map(
|
|
2864
3272
|
(virtualItem) => renderRow(flatRows[virtualItem.index], virtualItem.index, (el) => virtualizer.measureElement(el))
|
|
2865
3273
|
),
|
|
2866
|
-
paddingBottom > 0 && /* @__PURE__ */
|
|
3274
|
+
paddingBottom > 0 && /* @__PURE__ */ jsx27("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx27(
|
|
2867
3275
|
"td",
|
|
2868
3276
|
{
|
|
2869
3277
|
colSpan: totalColumnCount,
|
|
@@ -2877,14 +3285,20 @@ function TreeDataGrid({
|
|
|
2877
3285
|
}
|
|
2878
3286
|
export {
|
|
2879
3287
|
ActionsMenu,
|
|
3288
|
+
BooleanEditor,
|
|
2880
3289
|
BooleanFilter,
|
|
2881
3290
|
ColumnSelector,
|
|
2882
3291
|
DataGrid,
|
|
3292
|
+
DateEditor,
|
|
2883
3293
|
DateRangeFilter,
|
|
3294
|
+
EditFieldError,
|
|
3295
|
+
EnumEditor,
|
|
2884
3296
|
EnumFilter,
|
|
2885
3297
|
NumberComparisonFilter,
|
|
3298
|
+
NumberEditor,
|
|
2886
3299
|
NumberHistogramFilter,
|
|
2887
3300
|
NumberRangeFilter,
|
|
3301
|
+
StringEditor,
|
|
2888
3302
|
StringFilter,
|
|
2889
3303
|
TreeDataGrid,
|
|
2890
3304
|
UNARY_OPERATORS,
|
|
@@ -2894,6 +3308,7 @@ export {
|
|
|
2894
3308
|
countVisible,
|
|
2895
3309
|
defaultAlign,
|
|
2896
3310
|
defaultFormat,
|
|
3311
|
+
editErrorId,
|
|
2897
3312
|
evaluateFilter,
|
|
2898
3313
|
facetedNumberValues,
|
|
2899
3314
|
fieldKey,
|
|
@@ -2902,13 +3317,16 @@ export {
|
|
|
2902
3317
|
groupColumns,
|
|
2903
3318
|
isColumnVisible,
|
|
2904
3319
|
isCompositeFilterDescriptor,
|
|
3320
|
+
isEditable,
|
|
2905
3321
|
isFilterDescriptor,
|
|
2906
3322
|
isFilterable,
|
|
2907
3323
|
isSortable,
|
|
2908
3324
|
processClientData,
|
|
3325
|
+
renderDefaultEditWidget,
|
|
2909
3326
|
renderDefaultFilterWidget,
|
|
2910
3327
|
resolveMenuItems,
|
|
2911
3328
|
storageKeyFor,
|
|
3329
|
+
toDate,
|
|
2912
3330
|
useDebouncedCallback,
|
|
2913
3331
|
useGridState,
|
|
2914
3332
|
useTreeState
|