@absolutejs/absolute 0.19.0-beta.837 → 0.19.0-beta.839

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.
@@ -25,26 +25,30 @@
25
25
  const registrationOrder = Number(id.slice(1));
26
26
 
27
27
  // Register synchronously at script-body time so SSR (which doesn't
28
- // run $effect) sees the registration. The Router itself owns
29
- // rendering of the winning route's content — Route emits no DOM and
30
- // no hydration markers, so a page with N <Route>s produces ONE
31
- // `{#if}` block in the rendered HTML, not N.
32
- const initialCompiled = compilePattern(
33
- joinBasepath(registry.basepath, path)
34
- );
28
+ // run $effect) sees the registration before the template runs.
35
29
  registry.register(id, {
36
- content: content as Snippet<[Record<string, string | undefined>]>,
37
- pattern: initialCompiled,
30
+ pattern: compilePattern(joinBasepath(registry.basepath, path)),
38
31
  registrationOrder
39
32
  });
40
33
 
41
34
  $effect(() => {
42
35
  registry.register(id, {
43
- content: content as Snippet<[Record<string, string | undefined>]>,
44
36
  pattern: compilePattern(joinBasepath(registry.basepath, path)),
45
37
  registrationOrder
46
38
  });
47
39
  });
48
40
 
49
41
  onDestroy(() => registry.deregister(id));
42
+
43
+ // The Router computes the active match across all registered Routes
44
+ // (specificity-ranked). Each Route checks if it's the winner and
45
+ // renders its own content at its own location in the markup. That
46
+ // way `<Route>` nested inside a layout `<section>` renders inside
47
+ // that section instead of getting hoisted to the Router's root.
48
+ const match = $derived(registry.getActiveMatch());
49
+ const isActive = $derived(match?.id === id);
50
50
  </script>
51
+
52
+ {#if isActive && match}
53
+ {@render content(match.params as ExtractRouteParams<Path>)}
54
+ {/if}
@@ -1,15 +1,14 @@
1
1
  <script lang="ts" module>
2
- import type { Snippet } from 'svelte';
3
-
4
2
  type RouteEntry = {
5
3
  // reactive — read by the winner-resolver
6
4
  pattern: ReturnType<typeof import('./matchPath').compilePattern>;
7
5
  // stable — assigned at registration time, used as tiebreaker
8
6
  registrationOrder: number;
9
- // the snippet the winning Route should render — extraction lives
10
- // on the Router so the active branch renders inside ONE if-block
11
- // instead of one per Route (one set of hydration markers, not N)
12
- content: Snippet<[Record<string, string | undefined>]>;
7
+ };
8
+
9
+ type ActiveMatch = {
10
+ id: string;
11
+ params: Record<string, string | undefined>;
13
12
  };
14
13
 
15
14
  export type RouterRegistry = {
@@ -18,11 +17,16 @@
18
17
  register: (id: string, entry: RouteEntry) => void;
19
18
  deregister: (id: string) => void;
20
19
  nextRouteId: () => string;
20
+ // Returns the currently-winning Route's id and matched params, or null
21
+ // if no Route matches. Routes call this to decide whether to render.
22
+ // Reads $state internally, so callers using it inside $derived/$effect
23
+ // auto-subscribe to URL + registration changes.
24
+ getActiveMatch: () => ActiveMatch | null;
21
25
  };
22
26
  </script>
23
27
 
24
28
  <script lang="ts">
25
- import { getContext, onMount, setContext } from 'svelte';
29
+ import { getContext, onMount, setContext, type Snippet } from 'svelte';
26
30
  import type { RouterMode } from '../../types/svelteRouter';
27
31
  import { setRouterMode } from './goto';
28
32
  import { hashPathnameOf } from './hashMode';
@@ -64,15 +68,17 @@
64
68
  const isOutermost = parent === undefined;
65
69
 
66
70
  // Specificity ranking across siblings: each <Route> registers with
67
- // its compiled pattern + content snippet + a stable mount-order
68
- // index. The winner is computed lazily from the current URL — highest
69
- // score wins; ties break by earlier registration order.
71
+ // its compiled pattern + a stable mount-order index. The winner is
72
+ // computed lazily from the current URL — highest score wins; ties
73
+ // break by earlier registration order. The winning Route then renders
74
+ // its own content at ITS location in the markup (so a Route nested
75
+ // inside a layout `<section>` renders inside that section, not at the
76
+ // Router's root).
70
77
  const routes = $state(new Map<string, RouteEntry>());
71
78
  let routeCounter = 0;
72
79
 
73
- const computeWinner = () => {
80
+ const computeWinner = (): ActiveMatch | null => {
74
81
  let bestId: string | null = null;
75
- let bestEntry: RouteEntry | null = null;
76
82
  let bestParams: Record<string, string | undefined> | null = null;
77
83
  let bestScore = -Infinity;
78
84
  let bestOrder = Infinity;
@@ -89,21 +95,25 @@
89
95
  bestScore = entry.pattern.score;
90
96
  bestOrder = entry.registrationOrder;
91
97
  bestId = id;
92
- bestEntry = entry;
93
98
  bestParams = match.params as Record<string, string | undefined>;
94
99
  }
95
100
  }
96
101
 
97
- return bestId && bestEntry && bestParams
98
- ? { content: bestEntry.content, params: bestParams }
102
+ return bestId && bestParams
103
+ ? { id: bestId, params: bestParams }
99
104
  : null;
100
105
  };
101
106
 
107
+ // Recompute on every page.url change OR routes registry mutation.
108
+ // Reading $state during $derived auto-tracks both dependencies.
109
+ const winner = $derived(computeWinner());
110
+
102
111
  const registry: RouterRegistry = {
103
112
  basepath: stackedBasepath,
104
113
  deregister: (id) => {
105
114
  routes.delete(id);
106
115
  },
116
+ getActiveMatch: () => winner,
107
117
  mode: stackedMode,
108
118
  nextRouteId: () => `r${routeCounter++}`,
109
119
  register: (id, entry) => {
@@ -113,10 +123,6 @@
113
123
 
114
124
  setContext<RouterRegistry>(ROUTER_CONTEXT_KEY, registry);
115
125
 
116
- // Recompute on every page.url change OR routes registry mutation.
117
- // Reading $state during $derived auto-tracks both dependencies.
118
- const winner = $derived(computeWinner());
119
-
120
126
  if (isOutermost) {
121
127
  setRouterMode(stackedMode);
122
128
 
@@ -176,6 +182,3 @@
176
182
  </script>
177
183
 
178
184
  {@render children?.()}
179
- {#if winner}
180
- {@render winner.content(winner.params)}
181
- {/if}
@@ -2725,11 +2725,26 @@ var restorePrimedStream = (firstChunk, reader) => new ReadableStream({
2725
2725
  pumpLoop();
2726
2726
  }
2727
2727
  });
2728
+ var resolveRequestPathname = (request) => {
2729
+ if (!request)
2730
+ return;
2731
+ try {
2732
+ const parsed = new URL(request.url);
2733
+ return `${parsed.pathname}${parsed.search}`;
2734
+ } catch {
2735
+ return;
2736
+ }
2737
+ };
2728
2738
  var handleSveltePageRequest = async (input) => {
2729
2739
  const resolvedIndexPath = input.indexPath;
2730
2740
  const resolvedOptions = input;
2731
2741
  const resolvedPagePath = input.pagePath;
2732
- const resolvedProps = input.props;
2742
+ const userProps = input.props;
2743
+ const requestPathname = resolveRequestPathname(input.request);
2744
+ const resolvedProps = requestPathname !== undefined && (!userProps || !("url" in userProps)) ? {
2745
+ ...userProps ?? {},
2746
+ url: requestPathname
2747
+ } : userProps;
2733
2748
  if (isSsrCacheDirty("svelte")) {
2734
2749
  return buildDirtyResponse(resolvedIndexPath, resolvedProps);
2735
2750
  }
@@ -2797,5 +2812,5 @@ export {
2797
2812
  handleSveltePageRequest
2798
2813
  };
2799
2814
 
2800
- //# debugId=B8C8F2877A6C528964756E2164756E21
2815
+ //# debugId=6E5BE74C546EE7C964756E2164756E21
2801
2816
  //# sourceMappingURL=server.js.map