@dataverse-kit/grid-kit 0.2.0 → 0.3.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.
@@ -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,CAsHd"}
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,EAAE,WAAW,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;eA8BhD,MAAM,KAAG,WAAW,CAAC,CAAC,GAAG,SAAS;kBAfxD,MAAM,UAAU,CAAC;EAkB1B"}
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
@@ -2308,10 +2308,17 @@ function GroupedGrid(props) {
2308
2308
  * never fetches — this just normalizes the consumer-supplied resolver and tracks
2309
2309
  * loading. Call `ensure(key, parent)` on demand (row expand / panel open / hover).
2310
2310
  */
2311
- function useChildren(getChildren) {
2311
+ function useChildren(getChildren, reloadToken) {
2312
2312
  const [cache, setCache] = useState({});
2313
2313
  const cacheRef = useRef(cache);
2314
2314
  cacheRef.current = cache;
2315
+ // Remember the parent object per cached key so a `reloadToken` bump can re-run
2316
+ // `getChildren(parent)` for already-loaded rows.
2317
+ const parentsRef = useRef({});
2318
+ // `getChildren` accessed via a ref inside the reload effect → the effect can depend
2319
+ // on `reloadToken` alone without a stale closure or an exhaustive-deps warning.
2320
+ const getChildrenRef = useRef(getChildren);
2321
+ getChildrenRef.current = getChildren;
2315
2322
  // Guard against setState after unmount (e.g. host swapped while a child fetch
2316
2323
  // is in flight) — mirrors NestedTriggerCell / DetailPaneChildren.
2317
2324
  const mounted = useRef(true);
@@ -2324,6 +2331,7 @@ function useChildren(getChildren) {
2324
2331
  const ensure = useCallback((key, parent) => {
2325
2332
  if (cacheRef.current[key])
2326
2333
  return;
2334
+ parentsRef.current[key] = parent;
2327
2335
  const result = getChildren(parent);
2328
2336
  if (Array.isArray(result)) {
2329
2337
  setCache((p) => ({ ...p, [key]: { loading: false, rows: result } }));
@@ -2336,6 +2344,30 @@ function useChildren(getChildren) {
2336
2344
  });
2337
2345
  }
2338
2346
  }, [getChildren]);
2347
+ // Re-fetch every already-loaded parent's children when `reloadToken` changes. Compare
2348
+ // the token by VALUE (not a first-run counter) so it's safe under StrictMode's
2349
+ // double-invoke. Crucially we do NOT flip `loading: true` here — the old rows stay
2350
+ // rendered until the fresh ones land, so there's no spinner flash and (since `ensure`
2351
+ // is only re-called on expand) no perpetual spinner for an already-expanded row.
2352
+ const prevToken = useRef(reloadToken);
2353
+ useEffect(() => {
2354
+ if (reloadToken === prevToken.current)
2355
+ return;
2356
+ prevToken.current = reloadToken;
2357
+ for (const key of Object.keys(parentsRef.current)) {
2358
+ const parent = parentsRef.current[key];
2359
+ const result = getChildrenRef.current(parent);
2360
+ if (Array.isArray(result)) {
2361
+ setCache((p) => ({ ...p, [key]: { loading: false, rows: result } }));
2362
+ }
2363
+ else {
2364
+ Promise.resolve(result).then((rows) => {
2365
+ if (mounted.current)
2366
+ setCache((p) => ({ ...p, [key]: { loading: false, rows } }));
2367
+ });
2368
+ }
2369
+ }
2370
+ }, [reloadToken]);
2339
2371
  const get = useCallback((key) => cache[key], [cache]);
2340
2372
  return { get, ensure };
2341
2373
  }
@@ -2362,7 +2394,7 @@ function NestedInline(props) {
2362
2394
  const { items, columns, nested, selectionMode, isLoading, compact, alternateRowColors, pagination, onPageChange, aggregateItems, onSelectionChanged, rowCommands, } = parentProps;
2363
2395
  const { onItemContextMenu, contextMenuElement } = useRowContextMenu(rowCommands);
2364
2396
  const [expanded, setExpanded] = useState(new Set());
2365
- const { get, ensure } = useChildren(nested.getChildren);
2397
+ const { get, ensure } = useChildren(nested.getChildren, nested.reloadToken);
2366
2398
  // Forward parent-row selection to the consumer (DataGrid does this; inline did
2367
2399
  // not). A ref keeps the once-created Selection's callback from going stale when
2368
2400
  // the prop changes (mirrors DataGrid's onSelectionChangedRef).
@@ -2490,7 +2522,7 @@ function NestedCardParent(props) {
2490
2522
  const hasAggregate = columns.some((c) => c.aggregate);
2491
2523
  const [selected, setSelected] = useState(new Set());
2492
2524
  const [expanded, setExpanded] = useState(new Set());
2493
- const { get, ensure } = useChildren(nested.getChildren);
2525
+ const { get, ensure } = useChildren(nested.getChildren, nested.reloadToken);
2494
2526
  // requires-parent gating needs a Fluent Selection over the parent rows; cards have
2495
2527
  // none, so surface the unsupported config and fall back to independent selection.
2496
2528
  React.useEffect(() => {
@@ -2613,6 +2645,18 @@ function NestedTriggerCell(props) {
2613
2645
  clearTimeout(hoverTimer.current);
2614
2646
  };
2615
2647
  }, []);
2648
+ // Invalidate the on-demand cache when `reloadToken` changes (e.g. after associating a
2649
+ // new child): drop the loaded `entry` so the next open/hover re-fetches via `load()`
2650
+ // (which early-returns on a non-null `entry`). Value-compared so it's StrictMode-safe.
2651
+ // Edge: if the panel/callout is OPEN at bump time it shows the spinner until reopened —
2652
+ // acceptable, these modes are on-demand and usually closed during a toolbar action.
2653
+ const prevReloadToken = useRef(nested.reloadToken);
2654
+ useEffect(() => {
2655
+ if (nested.reloadToken === prevReloadToken.current)
2656
+ return;
2657
+ prevReloadToken.current = nested.reloadToken;
2658
+ setEntry(null);
2659
+ }, [nested.reloadToken]);
2616
2660
  // Resolve children once, on demand.
2617
2661
  const load = useCallback(() => {
2618
2662
  setEntry((prev) => {
@@ -2790,7 +2834,9 @@ function DetailPaneChildren(props) {
2790
2834
  return () => {
2791
2835
  alive = false;
2792
2836
  };
2793
- }, [parent, nested]);
2837
+ // `nested.reloadToken` makes the refetch explicit on a child mutation (e.g. addExisting)
2838
+ // rather than relying on `nested`'s inline-literal identity changing each render.
2839
+ }, [parent, nested, nested.reloadToken]);
2794
2840
  if (rows === null)
2795
2841
  return jsx(Text, { variant: "small", children: "Loading\u2026" });
2796
2842
  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