@dataverse-kit/grid-kit 0.2.0 → 0.4.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/hosts/GroupedGrid.d.ts.map +1 -1
- package/dist/hosts/nested/NestedTriggerCell.d.ts.map +1 -1
- package/dist/hosts/nested/useChildren.d.ts +1 -1
- package/dist/hosts/nested/useChildren.d.ts.map +1 -1
- package/dist/index.esm.js +69 -7
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +69 -7
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GroupedGrid.d.ts","sourceRoot":"","sources":["../../src/hosts/GroupedGrid.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"GroupedGrid.d.ts","sourceRoot":"","sources":["../../src/hosts/GroupedGrid.tsx"],"names":[],"mappings":";AAYA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAqBjD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,CA6HtG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NestedTriggerCell.d.ts","sourceRoot":"","sources":["../../../src/hosts/nested/NestedTriggerCell.tsx"],"names":[],"mappings":";AASA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAUhD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE;IAC7G,MAAM,EAAE,CAAC,CAAC;IACV,MAAM,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CAC5B,GAAG,GAAG,CAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"NestedTriggerCell.d.ts","sourceRoot":"","sources":["../../../src/hosts/nested/NestedTriggerCell.tsx"],"names":[],"mappings":";AASA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAUhD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE;IAC7G,MAAM,EAAE,CAAC,CAAC;IACV,MAAM,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CAC5B,GAAG,GAAG,CAAC,OAAO,CAkId"}
|
|
@@ -8,7 +8,7 @@ export interface ChildEntry<C> {
|
|
|
8
8
|
* never fetches — this just normalizes the consumer-supplied resolver and tracks
|
|
9
9
|
* loading. Call `ensure(key, parent)` on demand (row expand / panel open / hover).
|
|
10
10
|
*/
|
|
11
|
-
export declare function useChildren<T, C>(getChildren: (parent: T) => C[] | Promise<C[]
|
|
11
|
+
export declare function useChildren<T, C>(getChildren: (parent: T) => C[] | Promise<C[]>, reloadToken?: string | number): {
|
|
12
12
|
get: (key: string) => ChildEntry<C> | undefined;
|
|
13
13
|
ensure: (key: string, parent: T) => void;
|
|
14
14
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChildren.d.ts","sourceRoot":"","sources":["../../../src/hosts/nested/useChildren.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,CAAC,EAAE,CAAC;CACX;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"useChildren.d.ts","sourceRoot":"","sources":["../../../src/hosts/nested/useChildren.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,CAAC,EAAE,CAAC;CACX;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,CAAC,EAC9B,WAAW,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,EAC9C,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM;eA6DC,MAAM,KAAG,WAAW,CAAC,CAAC,GAAG,SAAS;kBAtCxD,MAAM,UAAU,CAAC;EAyC1B"}
|
package/dist/index.esm.js
CHANGED
|
@@ -2253,13 +2253,29 @@ const GROUP_CHEVRON_WIDTH = 36;
|
|
|
2253
2253
|
* groups + count badges), reusing the same columns/registry as `<DataGrid>`.
|
|
2254
2254
|
*/
|
|
2255
2255
|
function GroupedGrid(props) {
|
|
2256
|
-
const { items, columns, group, selectionMode = 'none', isLoading, pagination, onPageChange, aggregateItems, toolbar, compact, alternateRowColors, fill, height, rowCommands } = props;
|
|
2256
|
+
const { items, columns, group, selectionMode = 'none', onSelectionChanged, isLoading, pagination, onPageChange, aggregateItems, toolbar, compact, alternateRowColors, fill, height, rowCommands } = props;
|
|
2257
2257
|
const edit = useEditState();
|
|
2258
|
-
const { ctx } = useGridContext(props, edit);
|
|
2258
|
+
const { ctx, getKeyFn } = useGridContext(props, edit);
|
|
2259
2259
|
const dlColumns = useMemo(() => toDetailsListColumns(columns, ctx), [columns, ctx]);
|
|
2260
2260
|
// Per-row right-click menu (DetailsList path, same as DataGrid/NestedInline). No-op when
|
|
2261
2261
|
// rowCommands is unset (onItemContextMenu is undefined → no handler attached).
|
|
2262
2262
|
const { onItemContextMenu, contextMenuElement } = useRowContextMenu(rowCommands);
|
|
2263
|
+
// Fluent Selection so a toolbar's selection-gated commands can read the checked rows via
|
|
2264
|
+
// onSelectionChanged. Ported verbatim from <DataGrid> (the grouped DetailsList supports
|
|
2265
|
+
// selection + groups together: the Selection is over the flattened `orderedItems`, and
|
|
2266
|
+
// group headers select-all per group). `getKey` (= the consumer's getKey via getKeyFn) keys
|
|
2267
|
+
// the selection per row; null-safe for enableShimmer placeholder rows. selectionMode='none'
|
|
2268
|
+
// (the default) passes no selection → display-only / per-row-menu-only grids are unchanged.
|
|
2269
|
+
const safeRowKey = (it, index) => it == null ? `__gridkit_shimmer_${index ?? 0}` : getKeyFn(it);
|
|
2270
|
+
const onSelectionChangedRef = useRef(onSelectionChanged);
|
|
2271
|
+
onSelectionChangedRef.current = onSelectionChanged;
|
|
2272
|
+
const selectionRef = useRef();
|
|
2273
|
+
if (!selectionRef.current) {
|
|
2274
|
+
selectionRef.current = new Selection({
|
|
2275
|
+
getKey: (it, index) => safeRowKey(it, index),
|
|
2276
|
+
onSelectionChanged: () => onSelectionChangedRef.current?.(selectionRef.current.getSelection()),
|
|
2277
|
+
});
|
|
2278
|
+
}
|
|
2263
2279
|
// Bucket by groupBy → ordered items + IGroup[] (DetailsList needs contiguous
|
|
2264
2280
|
// group ranges). See buildGroups (pure + unit-tested).
|
|
2265
2281
|
const { orderedItems, groups } = useMemo(() => buildGroups(items, group), [items, group]);
|
|
@@ -2291,7 +2307,7 @@ function GroupedGrid(props) {
|
|
|
2291
2307
|
});
|
|
2292
2308
|
}
|
|
2293
2309
|
: undefined, [alternateRowColors]);
|
|
2294
|
-
return (jsxs(Stack, { styles: fillStackStyles(fill, height), children: [toolbar && jsx(GridToolbar, { config: toolbar }), jsx(FillRegion, { fill: fill, children: jsx(ShimmeredDetailsList, { items: orderedItems, columns: dlColumns, groups: groups, selectionMode: mapSelectionMode$1(selectionMode), layoutMode: DetailsListLayoutMode.justified, compact: compact, setKey: "grid-kit-grouped", onRenderRow: onRenderRow, onItemContextMenu: onItemContextMenu, styles: getDetailsListStyles(), ariaLabelForGrid: "Grouped grid", groupProps: {
|
|
2310
|
+
return (jsxs(Stack, { styles: fillStackStyles(fill, height), children: [toolbar && jsx(GridToolbar, { config: toolbar }), jsx(FillRegion, { fill: fill, children: jsx(ShimmeredDetailsList, { items: orderedItems, columns: dlColumns, groups: groups, selectionMode: mapSelectionMode$1(selectionMode), selection: selectionMode !== 'none' ? selectionRef.current : undefined, getKey: (it, index) => safeRowKey(it, index), layoutMode: DetailsListLayoutMode.justified, compact: compact, setKey: "grid-kit-grouped", onRenderRow: onRenderRow, onItemContextMenu: onItemContextMenu, styles: getDetailsListStyles(), ariaLabelForGrid: "Grouped grid", groupProps: {
|
|
2295
2311
|
showEmptyGroups: false,
|
|
2296
2312
|
// Render a subtotal under each EXPANDED group. Fluent v8 calls the group
|
|
2297
2313
|
// footer renderer even for collapsed groups, so guard on isCollapsed —
|
|
@@ -2308,10 +2324,17 @@ function GroupedGrid(props) {
|
|
|
2308
2324
|
* never fetches — this just normalizes the consumer-supplied resolver and tracks
|
|
2309
2325
|
* loading. Call `ensure(key, parent)` on demand (row expand / panel open / hover).
|
|
2310
2326
|
*/
|
|
2311
|
-
function useChildren(getChildren) {
|
|
2327
|
+
function useChildren(getChildren, reloadToken) {
|
|
2312
2328
|
const [cache, setCache] = useState({});
|
|
2313
2329
|
const cacheRef = useRef(cache);
|
|
2314
2330
|
cacheRef.current = cache;
|
|
2331
|
+
// Remember the parent object per cached key so a `reloadToken` bump can re-run
|
|
2332
|
+
// `getChildren(parent)` for already-loaded rows.
|
|
2333
|
+
const parentsRef = useRef({});
|
|
2334
|
+
// `getChildren` accessed via a ref inside the reload effect → the effect can depend
|
|
2335
|
+
// on `reloadToken` alone without a stale closure or an exhaustive-deps warning.
|
|
2336
|
+
const getChildrenRef = useRef(getChildren);
|
|
2337
|
+
getChildrenRef.current = getChildren;
|
|
2315
2338
|
// Guard against setState after unmount (e.g. host swapped while a child fetch
|
|
2316
2339
|
// is in flight) — mirrors NestedTriggerCell / DetailPaneChildren.
|
|
2317
2340
|
const mounted = useRef(true);
|
|
@@ -2324,6 +2347,7 @@ function useChildren(getChildren) {
|
|
|
2324
2347
|
const ensure = useCallback((key, parent) => {
|
|
2325
2348
|
if (cacheRef.current[key])
|
|
2326
2349
|
return;
|
|
2350
|
+
parentsRef.current[key] = parent;
|
|
2327
2351
|
const result = getChildren(parent);
|
|
2328
2352
|
if (Array.isArray(result)) {
|
|
2329
2353
|
setCache((p) => ({ ...p, [key]: { loading: false, rows: result } }));
|
|
@@ -2336,6 +2360,30 @@ function useChildren(getChildren) {
|
|
|
2336
2360
|
});
|
|
2337
2361
|
}
|
|
2338
2362
|
}, [getChildren]);
|
|
2363
|
+
// Re-fetch every already-loaded parent's children when `reloadToken` changes. Compare
|
|
2364
|
+
// the token by VALUE (not a first-run counter) so it's safe under StrictMode's
|
|
2365
|
+
// double-invoke. Crucially we do NOT flip `loading: true` here — the old rows stay
|
|
2366
|
+
// rendered until the fresh ones land, so there's no spinner flash and (since `ensure`
|
|
2367
|
+
// is only re-called on expand) no perpetual spinner for an already-expanded row.
|
|
2368
|
+
const prevToken = useRef(reloadToken);
|
|
2369
|
+
useEffect(() => {
|
|
2370
|
+
if (reloadToken === prevToken.current)
|
|
2371
|
+
return;
|
|
2372
|
+
prevToken.current = reloadToken;
|
|
2373
|
+
for (const key of Object.keys(parentsRef.current)) {
|
|
2374
|
+
const parent = parentsRef.current[key];
|
|
2375
|
+
const result = getChildrenRef.current(parent);
|
|
2376
|
+
if (Array.isArray(result)) {
|
|
2377
|
+
setCache((p) => ({ ...p, [key]: { loading: false, rows: result } }));
|
|
2378
|
+
}
|
|
2379
|
+
else {
|
|
2380
|
+
Promise.resolve(result).then((rows) => {
|
|
2381
|
+
if (mounted.current)
|
|
2382
|
+
setCache((p) => ({ ...p, [key]: { loading: false, rows } }));
|
|
2383
|
+
});
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
}, [reloadToken]);
|
|
2339
2387
|
const get = useCallback((key) => cache[key], [cache]);
|
|
2340
2388
|
return { get, ensure };
|
|
2341
2389
|
}
|
|
@@ -2362,7 +2410,7 @@ function NestedInline(props) {
|
|
|
2362
2410
|
const { items, columns, nested, selectionMode, isLoading, compact, alternateRowColors, pagination, onPageChange, aggregateItems, onSelectionChanged, rowCommands, } = parentProps;
|
|
2363
2411
|
const { onItemContextMenu, contextMenuElement } = useRowContextMenu(rowCommands);
|
|
2364
2412
|
const [expanded, setExpanded] = useState(new Set());
|
|
2365
|
-
const { get, ensure } = useChildren(nested.getChildren);
|
|
2413
|
+
const { get, ensure } = useChildren(nested.getChildren, nested.reloadToken);
|
|
2366
2414
|
// Forward parent-row selection to the consumer (DataGrid does this; inline did
|
|
2367
2415
|
// not). A ref keeps the once-created Selection's callback from going stale when
|
|
2368
2416
|
// the prop changes (mirrors DataGrid's onSelectionChangedRef).
|
|
@@ -2490,7 +2538,7 @@ function NestedCardParent(props) {
|
|
|
2490
2538
|
const hasAggregate = columns.some((c) => c.aggregate);
|
|
2491
2539
|
const [selected, setSelected] = useState(new Set());
|
|
2492
2540
|
const [expanded, setExpanded] = useState(new Set());
|
|
2493
|
-
const { get, ensure } = useChildren(nested.getChildren);
|
|
2541
|
+
const { get, ensure } = useChildren(nested.getChildren, nested.reloadToken);
|
|
2494
2542
|
// requires-parent gating needs a Fluent Selection over the parent rows; cards have
|
|
2495
2543
|
// none, so surface the unsupported config and fall back to independent selection.
|
|
2496
2544
|
React.useEffect(() => {
|
|
@@ -2613,6 +2661,18 @@ function NestedTriggerCell(props) {
|
|
|
2613
2661
|
clearTimeout(hoverTimer.current);
|
|
2614
2662
|
};
|
|
2615
2663
|
}, []);
|
|
2664
|
+
// Invalidate the on-demand cache when `reloadToken` changes (e.g. after associating a
|
|
2665
|
+
// new child): drop the loaded `entry` so the next open/hover re-fetches via `load()`
|
|
2666
|
+
// (which early-returns on a non-null `entry`). Value-compared so it's StrictMode-safe.
|
|
2667
|
+
// Edge: if the panel/callout is OPEN at bump time it shows the spinner until reopened —
|
|
2668
|
+
// acceptable, these modes are on-demand and usually closed during a toolbar action.
|
|
2669
|
+
const prevReloadToken = useRef(nested.reloadToken);
|
|
2670
|
+
useEffect(() => {
|
|
2671
|
+
if (nested.reloadToken === prevReloadToken.current)
|
|
2672
|
+
return;
|
|
2673
|
+
prevReloadToken.current = nested.reloadToken;
|
|
2674
|
+
setEntry(null);
|
|
2675
|
+
}, [nested.reloadToken]);
|
|
2616
2676
|
// Resolve children once, on demand.
|
|
2617
2677
|
const load = useCallback(() => {
|
|
2618
2678
|
setEntry((prev) => {
|
|
@@ -2790,7 +2850,9 @@ function DetailPaneChildren(props) {
|
|
|
2790
2850
|
return () => {
|
|
2791
2851
|
alive = false;
|
|
2792
2852
|
};
|
|
2793
|
-
|
|
2853
|
+
// `nested.reloadToken` makes the refetch explicit on a child mutation (e.g. addExisting)
|
|
2854
|
+
// rather than relying on `nested`'s inline-literal identity changing each render.
|
|
2855
|
+
}, [parent, nested, nested.reloadToken]);
|
|
2794
2856
|
if (rows === null)
|
|
2795
2857
|
return jsx(Text, { variant: "small", children: "Loading\u2026" });
|
|
2796
2858
|
return (jsx(DataGrid, { items: rows, columns: nested.childColumns, registry: nested.childRegistry, compact: true, selectionMode: nested.childSelectionMode, onSelectionChanged: nested.onChildSelectionChanged ? (sel) => nested.onChildSelectionChanged(parent, sel) : undefined, editable: nested.childEditable, editTrigger: nested.childEditTrigger, onValueChange: nested.onChildValueChange
|