@bmsuisse/datagrid 0.28.0 → 0.29.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 +23 -4
- package/dist/index.js +59 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1103,10 +1103,29 @@ interface DataGridProps<TRow> {
|
|
|
1103
1103
|
* split across pages. Omit entirely to disable — no grouping, no header
|
|
1104
1104
|
* rows, unchanged default rendering.
|
|
1105
1105
|
*
|
|
1106
|
-
*
|
|
1107
|
-
*
|
|
1108
|
-
*
|
|
1109
|
-
*
|
|
1106
|
+
* Composes with `virtualize` — header rows and member rows are flattened
|
|
1107
|
+
* into one virtualizable list together, so a large grouped dataset windows
|
|
1108
|
+
* the same way an ungrouped one does. `virtualize.threshold` still gates
|
|
1109
|
+
* on the real row count (`groupBy`'s synthetic header entries never push a
|
|
1110
|
+
* grid over a threshold its actual data didn't cross), and
|
|
1111
|
+
* `virtualize.onEndReached`'s own "won't fire again for the same data"
|
|
1112
|
+
* dedup is keyed off that same real row count too — a pure expand/collapse
|
|
1113
|
+
* click, with no new data loaded, never re-fires it.
|
|
1114
|
+
*
|
|
1115
|
+
* Two gaps this doesn't close, both pre-existing/out of scope for this
|
|
1116
|
+
* pass rather than introduced by composing with `virtualize`: `zebra`'s
|
|
1117
|
+
* odd/even striping is keyed off a row's position in the flat, ungrouped
|
|
1118
|
+
* row list, not its rendered position within its own bucket, so grouped
|
|
1119
|
+
* rows can stripe unevenly (`groupBy` alone already had this, virtualizing
|
|
1120
|
+
* doesn't fix or worsen it); and a sticky group header stays pinned below
|
|
1121
|
+
* the real `<thead>` only while its own `<tbody>` (or one of its member
|
|
1122
|
+
* rows') is actually mounted in the virtualized window — scrolling deep
|
|
1123
|
+
* into one bucket whose row count itself exceeds `virtualize`'s overscan
|
|
1124
|
+
* will eventually unmount that bucket's header and let it scroll away
|
|
1125
|
+
* rather than staying pinned, since `position: sticky` needs the element
|
|
1126
|
+
* mounted to stick at all. Both are harmless for the common case (buckets
|
|
1127
|
+
* no bigger than a couple dozen rows); see AGENTS.md's "Known limitations"
|
|
1128
|
+
* for the full writeup.
|
|
1110
1129
|
*/
|
|
1111
1130
|
groupBy?: (row: TRow) => string;
|
|
1112
1131
|
/** Customizes a group-header row's content. Defaults to `` `${key} (${rows.length})` ``. */
|
package/dist/index.js
CHANGED
|
@@ -2551,15 +2551,28 @@ function DataGrid({
|
|
|
2551
2551
|
return map;
|
|
2552
2552
|
}, [visibleColumns, enableColumnResizing, leftPinnedOffsets, rightPinnedOffsets, columnSizing]);
|
|
2553
2553
|
const tableRows = table.getRowModel().rows;
|
|
2554
|
-
const shouldVirtualize = Boolean(virtualize) && !groupBy && tableRows.length > (virtualize?.threshold ?? 100);
|
|
2555
2554
|
const groupedBuckets = useMemo7(
|
|
2556
2555
|
() => groupBy ? groupRows(tableRows, (row) => groupBy(row.original)) : void 0,
|
|
2557
2556
|
[tableRows, groupBy]
|
|
2558
2557
|
);
|
|
2559
2558
|
const { theadRef, groupHeaderTop } = useStickyGroupHeaderTop(Boolean(groupBy));
|
|
2559
|
+
const shouldVirtualize = Boolean(virtualize) && tableRows.length > (virtualize?.threshold ?? 100);
|
|
2560
|
+
const flatItems = useMemo7(() => {
|
|
2561
|
+
if (!shouldVirtualize) return [];
|
|
2562
|
+
if (!groupedBuckets) return tableRows.map((row) => ({ kind: "row", row }));
|
|
2563
|
+
const items = [];
|
|
2564
|
+
for (const bucket of groupedBuckets) {
|
|
2565
|
+
const originalRows = bucket.items.map((row) => row.original);
|
|
2566
|
+
items.push({ kind: "header", key: bucket.key, rows: originalRows });
|
|
2567
|
+
if (isGroupExpanded(bucket.key)) {
|
|
2568
|
+
for (const row of bucket.items) items.push({ kind: "row", row });
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
return items;
|
|
2572
|
+
}, [shouldVirtualize, groupedBuckets, tableRows, isGroupExpanded]);
|
|
2560
2573
|
const scrollRef = useRef8(null);
|
|
2561
2574
|
const virtualizer = useVirtualizer({
|
|
2562
|
-
count:
|
|
2575
|
+
count: flatItems.length,
|
|
2563
2576
|
getScrollElement: () => scrollRef.current,
|
|
2564
2577
|
estimateSize: () => virtualize?.estimatedRowHeight ?? 40,
|
|
2565
2578
|
overscan: virtualize?.overscan ?? 10,
|
|
@@ -2572,18 +2585,18 @@ function DataGrid({
|
|
|
2572
2585
|
const notifiedForLengthRef = useRef8(-1);
|
|
2573
2586
|
useEffect9(() => {
|
|
2574
2587
|
if (!virtualize?.onEndReached) return;
|
|
2575
|
-
if (lastVisibleIndex < 0 || lastVisibleIndex <
|
|
2588
|
+
if (lastVisibleIndex < 0 || lastVisibleIndex < flatItems.length - 1) return;
|
|
2576
2589
|
if (virtualize.hasMore === false) return;
|
|
2577
2590
|
if (notifiedForLengthRef.current === tableRows.length) return;
|
|
2578
2591
|
notifiedForLengthRef.current = tableRows.length;
|
|
2579
2592
|
virtualize.onEndReached();
|
|
2580
|
-
}, [lastVisibleIndex, tableRows.length, virtualize]);
|
|
2581
|
-
function renderRow(row, measureRef) {
|
|
2593
|
+
}, [lastVisibleIndex, flatItems.length, tableRows.length, virtualize]);
|
|
2594
|
+
function renderRow(row, measureRef, dataIndex = row.index) {
|
|
2582
2595
|
const isExpanded = expandedIds.has(row.id);
|
|
2583
2596
|
const rowProps = getRowProps?.(row.original);
|
|
2584
2597
|
const rowTestId = getRowTestId?.(row.original) ?? `row-${row.id}`;
|
|
2585
2598
|
const isOddRow = zebra && row.index % 2 === 1;
|
|
2586
|
-
return /* @__PURE__ */ jsxs18("tbody", { ref: measureRef, "data-index":
|
|
2599
|
+
return /* @__PURE__ */ jsxs18("tbody", { ref: measureRef, "data-index": dataIndex, children: [
|
|
2587
2600
|
/* @__PURE__ */ jsxs18(
|
|
2588
2601
|
"tr",
|
|
2589
2602
|
{
|
|
@@ -2654,43 +2667,48 @@ function DataGrid({
|
|
|
2654
2667
|
showDetailColumn && isExpanded && renderDetail && /* @__PURE__ */ jsx28("tr", { "data-testid": `${rowTestId}-detail`, children: /* @__PURE__ */ jsx28("td", { colSpan: totalColumnCount, className: "border-b border-border p-2", children: renderDetail(row.original) }) })
|
|
2655
2668
|
] }, row.id);
|
|
2656
2669
|
}
|
|
2670
|
+
function renderGroupHeaderTbody(key, rows2, measureRef, dataIndex) {
|
|
2671
|
+
const expanded = isGroupExpanded(key);
|
|
2672
|
+
return /* @__PURE__ */ jsx28("tbody", { ref: measureRef, "data-index": dataIndex, children: /* @__PURE__ */ jsx28("tr", { "data-testid": `group-header-${key}`, children: /* @__PURE__ */ jsx28(
|
|
2673
|
+
"td",
|
|
2674
|
+
{
|
|
2675
|
+
colSpan: totalColumnCount,
|
|
2676
|
+
className: cn("sticky z-20 border-b p-2 font-medium", zebra ? "bg-muted" : "bg-background"),
|
|
2677
|
+
style: { top: groupHeaderTop },
|
|
2678
|
+
children: /* @__PURE__ */ jsxs18(
|
|
2679
|
+
"button",
|
|
2680
|
+
{
|
|
2681
|
+
type: "button",
|
|
2682
|
+
className: "flex w-full items-center gap-1 text-left",
|
|
2683
|
+
onClick: () => toggleGroupExpanded(key),
|
|
2684
|
+
"aria-expanded": expanded,
|
|
2685
|
+
children: [
|
|
2686
|
+
/* @__PURE__ */ jsx28(
|
|
2687
|
+
ChevronRight,
|
|
2688
|
+
{
|
|
2689
|
+
className: `h-4 w-4 shrink-0 transition-transform${expanded ? " rotate-90" : ""}`,
|
|
2690
|
+
"aria-hidden": true
|
|
2691
|
+
}
|
|
2692
|
+
),
|
|
2693
|
+
renderGroupHeader ? renderGroupHeader(key, rows2, expanded) : `${key} (${rows2.length})`
|
|
2694
|
+
]
|
|
2695
|
+
}
|
|
2696
|
+
)
|
|
2697
|
+
}
|
|
2698
|
+
) }) }, `group-${key}`);
|
|
2699
|
+
}
|
|
2657
2700
|
function renderGroupedBucket(bucket) {
|
|
2658
2701
|
const expanded = isGroupExpanded(bucket.key);
|
|
2659
2702
|
const originalRows = bucket.items.map((row) => row.original);
|
|
2660
2703
|
return /* @__PURE__ */ jsxs18(Fragment2, { children: [
|
|
2661
|
-
|
|
2662
|
-
"td",
|
|
2663
|
-
{
|
|
2664
|
-
colSpan: totalColumnCount,
|
|
2665
|
-
className: cn(
|
|
2666
|
-
"sticky z-20 border-b p-2 font-medium",
|
|
2667
|
-
zebra ? "bg-muted" : "bg-background"
|
|
2668
|
-
),
|
|
2669
|
-
style: { top: groupHeaderTop },
|
|
2670
|
-
children: /* @__PURE__ */ jsxs18(
|
|
2671
|
-
"button",
|
|
2672
|
-
{
|
|
2673
|
-
type: "button",
|
|
2674
|
-
className: "flex w-full items-center gap-1 text-left",
|
|
2675
|
-
onClick: () => toggleGroupExpanded(bucket.key),
|
|
2676
|
-
"aria-expanded": expanded,
|
|
2677
|
-
children: [
|
|
2678
|
-
/* @__PURE__ */ jsx28(
|
|
2679
|
-
ChevronRight,
|
|
2680
|
-
{
|
|
2681
|
-
className: `h-4 w-4 shrink-0 transition-transform${expanded ? " rotate-90" : ""}`,
|
|
2682
|
-
"aria-hidden": true
|
|
2683
|
-
}
|
|
2684
|
-
),
|
|
2685
|
-
renderGroupHeader ? renderGroupHeader(bucket.key, originalRows, expanded) : `${bucket.key} (${originalRows.length})`
|
|
2686
|
-
]
|
|
2687
|
-
}
|
|
2688
|
-
)
|
|
2689
|
-
}
|
|
2690
|
-
) }) }),
|
|
2704
|
+
renderGroupHeaderTbody(bucket.key, originalRows),
|
|
2691
2705
|
expanded && bucket.items.map((row) => renderRow(row))
|
|
2692
2706
|
] }, `group-${bucket.key}`);
|
|
2693
2707
|
}
|
|
2708
|
+
function renderFlatItem(item, index, measureRef) {
|
|
2709
|
+
if (item.kind === "header") return renderGroupHeaderTbody(item.key, item.rows, measureRef, index);
|
|
2710
|
+
return renderRow(item.row, measureRef, index);
|
|
2711
|
+
}
|
|
2694
2712
|
return (
|
|
2695
2713
|
// `h-full`/`min-h-0` here and on the two wrappers below are no-ops unless
|
|
2696
2714
|
// a consumer itself gives <DataGrid> a bounded height (e.g. wraps it in
|
|
@@ -2912,7 +2930,11 @@ function DataGrid({
|
|
|
2912
2930
|
rows.length === 0 ? /* @__PURE__ */ jsx28("tbody", { children: /* @__PURE__ */ jsx28("tr", { children: /* @__PURE__ */ jsx28("td", { colSpan: totalColumnCount, className: "p-4 text-center text-muted-foreground", children: loading ? "Loading..." : "No results." }) }) }) : shouldVirtualize ? /* @__PURE__ */ jsxs18(Fragment3, { children: [
|
|
2913
2931
|
paddingTop > 0 && /* @__PURE__ */ jsx28("tbody", { children: /* @__PURE__ */ jsx28("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx28("td", { colSpan: totalColumnCount, style: { padding: 0, border: "none", height: paddingTop } }) }) }),
|
|
2914
2932
|
virtualItems.map(
|
|
2915
|
-
(virtualItem) =>
|
|
2933
|
+
(virtualItem) => renderFlatItem(
|
|
2934
|
+
flatItems[virtualItem.index],
|
|
2935
|
+
virtualItem.index,
|
|
2936
|
+
(el) => virtualizer.measureElement(el)
|
|
2937
|
+
)
|
|
2916
2938
|
),
|
|
2917
2939
|
paddingBottom > 0 && /* @__PURE__ */ jsx28("tbody", { children: /* @__PURE__ */ jsx28("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx28("td", { colSpan: totalColumnCount, style: { padding: 0, border: "none", height: paddingBottom } }) }) })
|
|
2918
2940
|
] }) : groupedBuckets ? groupedBuckets.map((bucket) => renderGroupedBucket(bucket)) : tableRows.map((row) => renderRow(row))
|