@rangojs/router 0.24.0 → 0.24.1

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.
@@ -58,6 +58,14 @@ export interface ClientUrlRouteRecord {
58
58
  readonly options: Readonly<ClientPathOptions> | undefined;
59
59
  readonly component: ComponentType;
60
60
  readonly layouts: readonly ComponentType[];
61
+ /**
62
+ * One per entry in `layouts`: the layout() item's ordinal among its sibling
63
+ * layout()s, its React key. Routes under the same layout() share it, so
64
+ * ClientUrlsRoot keeps that layout's instance across them (#1124). Keys only
65
+ * need to be unique among siblings: a differing parent layout remounts the
66
+ * whole subtree anyway.
67
+ */
68
+ readonly layoutKeys: readonly number[];
61
69
  readonly loaders: readonly ClientUrlLoaderRecord[];
62
70
  readonly loading: ReactNode | undefined;
63
71
  readonly transition: Readonly<ClientTransitionConfig> | undefined;
@@ -5929,7 +5929,7 @@ import { resolve } from "node:path";
5929
5929
  // package.json
5930
5930
  var package_default = {
5931
5931
  name: "@rangojs/router",
5932
- version: "0.24.0",
5932
+ version: "0.24.1",
5933
5933
  description: "Django-inspired RSC router with composable URL patterns",
5934
5934
  keywords: [
5935
5935
  "react",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rangojs/router",
3
- "version": "0.24.0",
3
+ "version": "0.24.1",
4
4
  "description": "Django-inspired RSC router with composable URL patterns",
5
5
  "keywords": [
6
6
  "react",
@@ -526,7 +526,8 @@ a hard load of the target URL renders the full route.
526
526
  reconciles instead of remounting. The canonical commit runs in a
527
527
  `startTransition` when no new segments mount, and the wrapping layout sees
528
528
  `useOutlet().pending === true` for the held window; a route-level
529
- `loading()` does not re-flash there. `transition()` is not needed for the
529
+ `loading()` does not re-flash there. Across different routes, a `layout()`
530
+ keeps its instance while the navigation stays under it. `transition()` is not needed for the
530
531
  hold; it adds the view-transition animation. Inline `<Suspense>` above each
531
532
  `useLoader` read is still the finer-grained tool when different reads on
532
533
  one route should wait independently.
@@ -194,13 +194,13 @@ export function ClientUrlsRoot({
194
194
  });
195
195
  }
196
196
 
197
+ // Keyed per layout() item, not per route (#1124).
197
198
  for (let index = route.layouts.length - 1; index >= 0; index--) {
198
- const layoutKey = `${route.id}-layout-${index}`;
199
199
  content = createElement(OutletProvider, {
200
- key: layoutKey,
200
+ key: route.layoutKeys[index],
201
201
  content,
202
202
  pending,
203
- children: createElement(route.layouts[index], { key: layoutKey }),
203
+ children: createElement(route.layouts[index]),
204
204
  });
205
205
  }
206
206
 
@@ -154,12 +154,14 @@ interface LoadingItem extends ItemBase {
154
154
 
155
155
  interface FlattenContext {
156
156
  readonly layouts: readonly ComponentType[];
157
+ readonly layoutKeys: readonly number[];
157
158
  readonly loaders: readonly ClientUrlLoaderRecord[];
158
159
  readonly loading: ReactNode | undefined;
159
160
  }
160
161
 
161
162
  const EMPTY_CONTEXT: FlattenContext = {
162
163
  layouts: [],
164
+ layoutKeys: [],
163
165
  loaders: [],
164
166
  loading: undefined,
165
167
  };
@@ -588,6 +590,7 @@ function applyConfig(
588
590
 
589
591
  return {
590
592
  layouts: context.layouts,
593
+ layoutKeys: context.layoutKeys,
591
594
  loaders,
592
595
  loading,
593
596
  };
@@ -614,6 +617,7 @@ function addPathRecord(
614
617
  options,
615
618
  component: item.component,
616
619
  layouts: Object.freeze([...routeContext.layouts]),
620
+ layoutKeys: Object.freeze([...routeContext.layoutKeys]),
617
621
  loaders: Object.freeze([...routeContext.loaders]),
618
622
  loading: routeContext.loading,
619
623
  transition: transitionItem
@@ -625,6 +629,7 @@ function addPathRecord(
625
629
 
626
630
  function flattenLayout(
627
631
  item: LayoutItem,
632
+ ordinal: number,
628
633
  context: FlattenContext,
629
634
  routes: ClientUrlRouteRecord[],
630
635
  ): void {
@@ -633,6 +638,7 @@ function flattenLayout(
633
638
  {
634
639
  ...context,
635
640
  layouts: [...context.layouts, item.component],
641
+ layoutKeys: [...context.layoutKeys, ordinal],
636
642
  },
637
643
  item.children,
638
644
  );
@@ -650,11 +656,12 @@ function flattenRoutes(
650
656
  context: FlattenContext,
651
657
  routes: ClientUrlRouteRecord[],
652
658
  ): void {
659
+ let layoutOrdinal = 0;
653
660
  for (const item of items) {
654
661
  if (item.type === "path") {
655
662
  addPathRecord(item, context, routes);
656
663
  } else if (item.type === "layout") {
657
- flattenLayout(item, context, routes);
664
+ flattenLayout(item, layoutOrdinal++, context, routes);
658
665
  }
659
666
  }
660
667
  }
@@ -105,6 +105,14 @@ export interface ClientUrlRouteRecord {
105
105
  readonly options: Readonly<ClientPathOptions> | undefined;
106
106
  readonly component: ComponentType;
107
107
  readonly layouts: readonly ComponentType[];
108
+ /**
109
+ * One per entry in `layouts`: the layout() item's ordinal among its sibling
110
+ * layout()s, its React key. Routes under the same layout() share it, so
111
+ * ClientUrlsRoot keeps that layout's instance across them (#1124). Keys only
112
+ * need to be unique among siblings: a differing parent layout remounts the
113
+ * whole subtree anyway.
114
+ */
115
+ readonly layoutKeys: readonly number[];
108
116
  readonly loaders: readonly ClientUrlLoaderRecord[];
109
117
  readonly loading: ReactNode | undefined;
110
118
  readonly transition: Readonly<ClientTransitionConfig> | undefined;