one 1.14.5 → 1.15.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.
Files changed (34) hide show
  1. package/dist/cjs/createApp.cjs +4 -2
  2. package/dist/cjs/router/interceptRoutes.cjs +2 -21
  3. package/dist/cjs/router/interceptRoutes.native.js +2 -21
  4. package/dist/cjs/router/interceptRoutes.native.js.map +1 -1
  5. package/dist/cjs/router/matchers.cjs +31 -0
  6. package/dist/cjs/router/matchers.native.js +31 -0
  7. package/dist/cjs/router/matchers.native.js.map +1 -1
  8. package/dist/cjs/views/Navigator.cjs +18 -10
  9. package/dist/cjs/views/Navigator.native.js +20 -30
  10. package/dist/cjs/views/Navigator.native.js.map +1 -1
  11. package/dist/esm/createApp.mjs +4 -2
  12. package/dist/esm/createApp.mjs.map +1 -1
  13. package/dist/esm/router/interceptRoutes.mjs +3 -22
  14. package/dist/esm/router/interceptRoutes.mjs.map +1 -1
  15. package/dist/esm/router/interceptRoutes.native.js +3 -22
  16. package/dist/esm/router/interceptRoutes.native.js.map +1 -1
  17. package/dist/esm/router/matchers.mjs +31 -1
  18. package/dist/esm/router/matchers.mjs.map +1 -1
  19. package/dist/esm/router/matchers.native.js +31 -1
  20. package/dist/esm/router/matchers.native.js.map +1 -1
  21. package/dist/esm/views/Navigator.mjs +18 -10
  22. package/dist/esm/views/Navigator.mjs.map +1 -1
  23. package/dist/esm/views/Navigator.native.js +20 -30
  24. package/dist/esm/views/Navigator.native.js.map +1 -1
  25. package/package.json +9 -9
  26. package/src/createApp.tsx +10 -2
  27. package/src/router/interceptRoutes.ts +12 -43
  28. package/src/router/matchers.ts +58 -0
  29. package/src/views/Navigator.tsx +43 -18
  30. package/types/createApp.d.ts.map +1 -1
  31. package/types/router/interceptRoutes.d.ts.map +1 -1
  32. package/types/router/matchers.d.ts +22 -0
  33. package/types/router/matchers.d.ts.map +1 -1
  34. package/types/views/Navigator.d.ts.map +1 -1
package/src/createApp.tsx CHANGED
@@ -42,12 +42,18 @@ export function createApp(options: CreateAppProps) {
42
42
  render: async (props: RenderAppProps) => {
43
43
  // set render mode env before setup so users can conditionally skip setup in ssg/spa
44
44
  const renderMode = props.mode === 'spa-shell' ? 'spa' : props.mode
45
+ // skip setup for all build-time renders (ssg pages + spa-shell pages).
46
+ // both are generated at build time and persisted as static HTML, so
47
+ // running user setup code (analytics, db connections, etc.) would
48
+ // leak build-time side effects and can also race on process.env when
49
+ // renders run in parallel.
50
+ const shouldRunSetup = props.mode !== 'ssg' && props.mode !== 'spa-shell'
45
51
  // only set if changed to avoid process.env setter overhead
46
52
  if (process.env.ONE_RENDER_MODE !== renderMode) {
47
53
  process.env.ONE_RENDER_MODE = renderMode
48
54
  }
49
55
 
50
- if (!setupDone && options.getSetupPromise) {
56
+ if (shouldRunSetup && !setupDone && options.getSetupPromise) {
51
57
  await options.getSetupPromise()
52
58
  setupDone = true
53
59
  }
@@ -169,12 +175,14 @@ export function createApp(options: CreateAppProps) {
169
175
  // streaming SSR - returns ReadableStream, no post-processing
170
176
  renderStream: async (props: RenderAppProps): Promise<ReadableStream> => {
171
177
  const renderMode = props.mode === 'spa-shell' ? 'spa' : props.mode
178
+ // skip setup for build-time renders (ssg + spa-shell) — see render() above
179
+ const shouldRunSetup = props.mode !== 'ssg' && props.mode !== 'spa-shell'
172
180
  // only set if changed to avoid process.env setter overhead
173
181
  if (process.env.ONE_RENDER_MODE !== renderMode) {
174
182
  process.env.ONE_RENDER_MODE = renderMode
175
183
  }
176
184
 
177
- if (!setupDone && options.getSetupPromise) {
185
+ if (shouldRunSetup && !setupDone && options.getSetupPromise) {
178
186
  await options.getSetupPromise()
179
187
  setupDone = true
180
188
  }
@@ -1,5 +1,9 @@
1
1
  import type { RouteNode, SlotConfig } from './Route'
2
- import { matchDynamicName, stripGroupSegmentsFromPath } from './matchers'
2
+ import {
3
+ matchDynamicName,
4
+ matchRoutePattern,
5
+ stripGroupSegmentsFromPath,
6
+ } from './matchers'
3
7
  import { isNative } from '../constants'
4
8
 
5
9
  // ============================================
@@ -84,50 +88,15 @@ function getLayoutPath(node: RouteNode): string {
84
88
 
85
89
  /**
86
90
  * Check if a layout path is an ancestor of (or equal to) the current path.
87
- * A layout at /settings/account is an ancestor of /settings/account/foo
88
- * Handles dynamic segments: /[serverId]/[channelId] matches /tamagui/tamagui-apps
91
+ * A layout at /settings/account is an ancestor of /settings/account/foo.
92
+ * Handles dynamic segments: /[serverId]/[channelId] matches /tamagui/tamagui-apps.
89
93
  */
90
94
  function isLayoutAncestorOfPath(layoutPath: string, currentPath: string): boolean {
91
- // Normalize paths
92
- const normalizedLayout = layoutPath.replace(/\/+$/, '') || '/'
93
- const normalizedCurrent = currentPath.replace(/\/+$/, '') || '/'
94
-
95
- // Root layout is ancestor of everything
96
- if (normalizedLayout === '/') return true
97
-
98
- // Split into segments for dynamic matching
99
- const layoutParts = normalizedLayout.split('/').filter(Boolean)
100
- const currentParts = normalizedCurrent.split('/').filter(Boolean)
101
-
102
- // Layout can't be ancestor if it has more segments than current path
103
- if (layoutParts.length > currentParts.length) return false
104
-
105
- // Check each layout segment matches the corresponding current segment
106
- // Dynamic segments like [id] match any value
107
- for (let i = 0; i < layoutParts.length; i++) {
108
- const layoutPart = layoutParts[i]
109
- const currentPart = currentParts[i]
110
-
111
- // Check if this is a dynamic segment
112
- const dynamicMatch = matchDynamicName(layoutPart)
113
- if (dynamicMatch) {
114
- // Dynamic segment - matches any value (including catch-all)
115
- if (dynamicMatch.deep) {
116
- // Catch-all matches rest of path, so layout is definitely an ancestor
117
- return true
118
- }
119
- // Single dynamic segment - matches this position, continue checking
120
- continue
121
- }
122
-
123
- // Static segment - must match exactly
124
- if (layoutPart !== currentPart) {
125
- return false
126
- }
127
- }
128
-
129
- // All layout segments matched
130
- return true
95
+ // root layout is ancestor of everything
96
+ if (!layoutPath.replace(/\/+$/, '')) return true
97
+ // matchRoutePattern does prefix matching with dynamic segment support —
98
+ // a null result means the layout isn't an ancestor of currentPath
99
+ return matchRoutePattern(layoutPath, currentPath) !== null
131
100
  }
132
101
 
133
102
  /**
@@ -20,6 +20,64 @@ export function matchDynamicName(name: string): DynamicNameMatch | undefined {
20
20
  }
21
21
  }
22
22
 
23
+ /**
24
+ * Match a route pattern against a URL path, segment-by-segment, as a prefix.
25
+ *
26
+ * - Dynamic segments `[param]` match any single path segment
27
+ * - Catch-all `[...param]` matches all remaining path segments
28
+ * - Route groups like `(app)` in the pattern are skipped (they don't appear in URLs)
29
+ * - A trailing `/index` in the pattern is stripped (index routes match their parent path)
30
+ * - The pattern must match as a prefix of the path (leftover path segments are allowed)
31
+ *
32
+ * Returns `null` if the pattern doesn't match. Otherwise returns a specificity
33
+ * score — higher means the pattern is more specific. Callers that want an
34
+ * "exact" match (no leftover path) can check `result.specificity === pathSegmentsCount`.
35
+ * Callers picking the best match among several patterns should pick the
36
+ * highest specificity.
37
+ *
38
+ * Shared between:
39
+ * - `views/Navigator.tsx` — resolving initialRouteName for late-mounted navigators
40
+ * - `router/interceptRoutes.ts` — finding layouts that are ancestors of a path
41
+ */
42
+ export function matchRoutePattern(
43
+ pattern: string,
44
+ path: string
45
+ ): { specificity: number } | null {
46
+ const patternSegments = pattern.split('/').filter(Boolean)
47
+ // strip trailing `/index` — index routes match the parent path with nothing after
48
+ if (patternSegments[patternSegments.length - 1] === 'index') {
49
+ patternSegments.pop()
50
+ }
51
+ const pathSegments = path.split('/').filter(Boolean)
52
+
53
+ let specificity = 0
54
+ let pi = 0
55
+ for (let ui = 0; ui < patternSegments.length; ui++) {
56
+ const seg = patternSegments[ui]
57
+ // route groups like (app) don't appear in URLs — skip them but don't count specificity
58
+ if (seg.startsWith('(') && seg.endsWith(')')) continue
59
+ // catch-all [...param] consumes the rest of the path
60
+ if (seg.startsWith('[...') && seg.endsWith(']')) {
61
+ // count remaining path segments so a catch-all beats a non-catch-all at the same depth
62
+ return { specificity: specificity + (pathSegments.length - pi) }
63
+ }
64
+ // pattern has more segments than path → not a prefix match
65
+ if (pi >= pathSegments.length) return null
66
+ // dynamic [param] matches any single path segment (less specific than literal)
67
+ if (seg.startsWith('[') && seg.endsWith(']')) {
68
+ specificity += 1
69
+ pi += 1
70
+ continue
71
+ }
72
+ // literal segment must match exactly (most specific)
73
+ if (seg !== pathSegments[pi]) return null
74
+ specificity += 2
75
+ pi += 1
76
+ }
77
+ // all pattern segments consumed — this is a valid prefix match
78
+ return { specificity }
79
+ }
80
+
23
81
  /**
24
82
  * Match `[...page]` -> `page`
25
83
  * @deprecated Use matchDynamicName instead which returns {name, deep}
@@ -13,6 +13,7 @@ import {
13
13
  useNotFoundState,
14
14
  } from '../notFoundState'
15
15
  import { useContextKey } from '../router/Route'
16
+ import { matchRoutePattern, stripGroupSegmentsFromPath } from '../router/matchers'
16
17
  import { routeNode as globalRouteNode, initialPathname } from '../router/router'
17
18
  import { registerProtectedRoutes, unregisterProtectedRoutes } from '../router/router'
18
19
  import { useSortedScreens, getQualifiedRouteComponent } from '../router/useScreens'
@@ -171,12 +172,24 @@ function QualifiedNavigator({
171
172
  contextKey,
172
173
  router = StackRouter,
173
174
  }: NavigatorProps & { contextKey: string; screens: React.ReactNode[] }) {
174
- // LATE MOUNT FIX: when a parent layout conditionally renders (e.g. auth gate),
175
- // this navigator may mount after initialState was consumed. compute the
176
- // correct initialRouteName from the original URL so the navigator starts on
177
- // the right route instead of defaulting to the first one.
178
- // uses initialPathname (captured at setup) instead of window.location.pathname
179
- // because React Navigation's linking can push a wrong URL during the delay.
175
+ // LATE MOUNT FIX: when a parent layout conditionally renders (auth gate,
176
+ // suspense resolve, provider init, etc.), this navigator may mount after
177
+ // initialState was consumed. compute the correct initialRouteName from the
178
+ // original URL so the navigator starts on the right route instead of
179
+ // defaulting to the first child. uses initialPathname (captured at setup)
180
+ // instead of window.location.pathname because React Navigation's linking
181
+ // can push a wrong URL during the delay.
182
+ //
183
+ // this is especially important for hoisted deep dynamic routes: when a
184
+ // directory has no _layout.tsx file, one flattens its children into the
185
+ // nearest parent navigator. so for e.g. app/(app)/project/[projectId]/index.tsx
186
+ // with no intermediate _layout.tsx files, the (app) navigator ends up with
187
+ // children like ["index", "factory", "project/[projectId]/index"] as
188
+ // flat siblings. if this navigator re-initializes during hydration and we
189
+ // don't resolve the URL ourselves, React Navigation picks the first sibling
190
+ // as the default — mounting `index` while the browser is still on
191
+ // /project/foo. that produces a visible redirect flash (seen in soot,
192
+ // commit ea96e360).
180
193
  const resolvedInitialRouteName = React.useMemo(() => {
181
194
  if (initialRouteName) return initialRouteName
182
195
 
@@ -185,23 +198,35 @@ function QualifiedNavigator({
185
198
  (typeof window !== 'undefined' ? window.location.pathname : undefined)
186
199
  if (!browserPath) return undefined
187
200
 
188
- // extract screen names from the screens array
189
- const screenNames: string[] = []
190
- for (const screen of screens) {
191
- const props = (screen as any)?.props
192
- if (props?.name) screenNames.push(props.name)
201
+ // screen names are relative to this navigator's parent layout, so we
202
+ // need to strip the parent layout's URL prefix from browserPath before
203
+ // matching. contextKey is the layout's path (including group segments),
204
+ // e.g. `/hooks/cases/route-group-pathname/(tabs)` we strip groups
205
+ // to get the URL-relevant prefix and remove it from browserPath.
206
+ const layoutUrlPrefix = stripGroupSegmentsFromPath(contextKey).replace(/\/+$/, '')
207
+ let relativePath = browserPath
208
+ if (layoutUrlPrefix && browserPath.startsWith(layoutUrlPrefix)) {
209
+ relativePath = browserPath.slice(layoutUrlPrefix.length) || '/'
193
210
  }
194
211
 
195
- // find which screen matches the URL
196
- for (const name of screenNames) {
197
- const base = name.replace(/\/index$/, '')
198
- if (browserPath.endsWith('/' + base) || browserPath.includes('/' + base + '/')) {
199
- return name
212
+ // score each screen by how specifically its pattern matches the URL.
213
+ // screen names may contain dynamic segments `[param]`/`[...param]`.
214
+ // `matchRoutePattern` does a prefix match so layout screens (like
215
+ // `project`) can match deeper URLs; the specificity score then tiebreaks
216
+ // to pick the best leaf.
217
+ let best: { name: string; specificity: number } | undefined
218
+ for (const screen of screens) {
219
+ const name = (screen as any)?.props?.name
220
+ if (!name) continue
221
+ const match = matchRoutePattern(name, relativePath)
222
+ if (!match) continue
223
+ if (!best || match.specificity > best.specificity) {
224
+ best = { name, specificity: match.specificity }
200
225
  }
201
226
  }
202
227
 
203
- return undefined
204
- }, [initialRouteName, screens])
228
+ return best?.name
229
+ }, [initialRouteName, screens, contextKey])
205
230
 
206
231
  const { state, navigation, descriptors, NavigationContent } = useNavigationBuilder(
207
232
  router,
@@ -1 +1 @@
1
- {"version":3,"file":"createApp.d.ts","sourceRoot":"","sources":["../src/createApp.tsx"],"names":[],"mappings":"AAAA,OAAO,SAAS,CAAA;AAWhB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAM7C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAEvC,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC,CAAA;IAC9C,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,GAAG,CAAC,KAAK,CAAA;IACjB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;CACzC,CAAA;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,cAAc;;oBAWrB,cAAc;0BAgIR,cAAc,KAAG,OAAO,CAAC,cAAc,CAAC;EAuJzE"}
1
+ {"version":3,"file":"createApp.d.ts","sourceRoot":"","sources":["../src/createApp.tsx"],"names":[],"mappings":"AAAA,OAAO,SAAS,CAAA;AAWhB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAM7C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAEvC,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC,CAAA;IAC9C,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,GAAG,CAAC,KAAK,CAAA;IACjB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;CACzC,CAAA;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,cAAc;;oBAWrB,cAAc;0BAsIR,cAAc,KAAG,OAAO,CAAC,cAAc,CAAC;EAyJzE"}
@@ -1 +1 @@
1
- {"version":3,"file":"interceptRoutes.d.ts","sourceRoot":"","sources":["../../src/router/interceptRoutes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,SAAS,CAAA;AAiBpD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,QAEtD;AAED,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAMD,MAAM,WAAW,eAAe;IAC9B,uCAAuC;IACvC,cAAc,EAAE,SAAS,CAAA;IACzB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAA;IAChB,qEAAqE;IACrE,gBAAgB,EAAE,MAAM,CAAA;IACxB,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC/B;AAuHD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,SAAS,GAAG,IAAI,EAC1B,WAAW,EAAE,MAAM,GAClB,eAAe,GAAG,IAAI,CAsCxB;AAiJD;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,QAetD;AAKD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,IAAI,QAE3D;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAmBxC;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,OAAO,CAGjD;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,GAAG,IAAI,CAGxD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,IAAI,CAGlD;AAQD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,QAEvD;AAED,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAGD,QAAA,IAAI,oBAAoB,EACpB,CAAC,CACC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,eAAe,CAAC,EAAE,GAAG,CAAA;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,aAAa,EAAE,OAAO,CAAA;CACvB,GAAG,IAAI,KACL,IAAI,CAAC,GACV,IAAW,CAAA;AAEf,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,oBAAoB,QAEzE;AAOD,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,GAAG,EACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,QAK/B;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,IAAI,OAAO,CAoBrD"}
1
+ {"version":3,"file":"interceptRoutes.d.ts","sourceRoot":"","sources":["../../src/router/interceptRoutes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,SAAS,CAAA;AAqBpD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,QAEtD;AAED,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAMD,MAAM,WAAW,eAAe;IAC9B,uCAAuC;IACvC,cAAc,EAAE,SAAS,CAAA;IACzB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAA;IAChB,qEAAqE;IACrE,gBAAgB,EAAE,MAAM,CAAA;IACxB,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC/B;AAoFD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,SAAS,GAAG,IAAI,EAC1B,WAAW,EAAE,MAAM,GAClB,eAAe,GAAG,IAAI,CAsCxB;AAiJD;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,QAetD;AAKD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,IAAI,QAE3D;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAmBxC;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,OAAO,CAGjD;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,GAAG,IAAI,CAGxD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,IAAI,CAGlD;AAQD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,QAEvD;AAED,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAGD,QAAA,IAAI,oBAAoB,EACpB,CAAC,CACC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,eAAe,CAAC,EAAE,GAAG,CAAA;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,aAAa,EAAE,OAAO,CAAA;CACvB,GAAG,IAAI,KACL,IAAI,CAAC,GACV,IAAW,CAAA;AAEf,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,oBAAoB,QAEzE;AAOD,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,GAAG,EACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,QAK/B;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,IAAI,OAAO,CAoBrD"}
@@ -5,6 +5,28 @@ export interface DynamicNameMatch {
5
5
  }
6
6
  /** Match `[page]` -> `{ name: 'page', deep: false }` or `[...page]` -> `{ name: 'page', deep: true }` */
7
7
  export declare function matchDynamicName(name: string): DynamicNameMatch | undefined;
8
+ /**
9
+ * Match a route pattern against a URL path, segment-by-segment, as a prefix.
10
+ *
11
+ * - Dynamic segments `[param]` match any single path segment
12
+ * - Catch-all `[...param]` matches all remaining path segments
13
+ * - Route groups like `(app)` in the pattern are skipped (they don't appear in URLs)
14
+ * - A trailing `/index` in the pattern is stripped (index routes match their parent path)
15
+ * - The pattern must match as a prefix of the path (leftover path segments are allowed)
16
+ *
17
+ * Returns `null` if the pattern doesn't match. Otherwise returns a specificity
18
+ * score — higher means the pattern is more specific. Callers that want an
19
+ * "exact" match (no leftover path) can check `result.specificity === pathSegmentsCount`.
20
+ * Callers picking the best match among several patterns should pick the
21
+ * highest specificity.
22
+ *
23
+ * Shared between:
24
+ * - `views/Navigator.tsx` — resolving initialRouteName for late-mounted navigators
25
+ * - `router/interceptRoutes.ts` — finding layouts that are ancestors of a path
26
+ */
27
+ export declare function matchRoutePattern(pattern: string, path: string): {
28
+ specificity: number;
29
+ } | null;
8
30
  /**
9
31
  * Match `[...page]` -> `page`
10
32
  * @deprecated Use matchDynamicName instead which returns {name, deep}
@@ -1 +1 @@
1
- {"version":3,"file":"matchers.d.ts","sourceRoot":"","sources":["../../src/router/matchers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAA;AAKxC,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,OAAO,CAAA;CACd;AAED,yGAAyG;AACzG,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAS3E;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE1E;AAED,yBAAyB;AACzB,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,+BAA+B;AAC/B,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE/D;AAED,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,sBAE/C;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQlD;AAED,0CAA0C;AAC1C,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9D;AAGD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAU/D;AAED,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,WAMxC;AASD,MAAM,WAAW,wBAAwB;IACvC,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAA;IACZ,yCAAyC;IACzC,UAAU,EAAE,GAAG,CAAC,eAAe,GAAG,KAAK,CAAA;CACxC;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,GACX,wBAAwB,GAAG,SAAS,CAOtC;AASD,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE9D;AAED,oDAAoD;AACpD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,MAAM,WAAW,cAAc;IAC7B,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAA;IACd,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAA;IAClB,wDAAwD;IACxD,eAAe,EAAE,MAAM,CAAA;CACxB;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAiBhF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAG5D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK9D"}
1
+ {"version":3,"file":"matchers.d.ts","sourceRoot":"","sources":["../../src/router/matchers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAA;AAKxC,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,OAAO,CAAA;CACd;AAED,yGAAyG;AACzG,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAS3E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GACX;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAkChC;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE1E;AAED,yBAAyB;AACzB,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,+BAA+B;AAC/B,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE/D;AAED,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,sBAE/C;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQlD;AAED,0CAA0C;AAC1C,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9D;AAGD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAU/D;AAED,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,WAMxC;AASD,MAAM,WAAW,wBAAwB;IACvC,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAA;IACZ,yCAAyC;IACzC,UAAU,EAAE,GAAG,CAAC,eAAe,GAAG,KAAK,CAAA;CACxC;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,GACX,wBAAwB,GAAG,SAAS,CAOtC;AASD,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE9D;AAED,oDAAoD;AACpD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,MAAM,WAAW,cAAc;IAC7B,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAA;IACd,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAA;IAClB,wDAAwD;IACxD,eAAe,EAAE,MAAM,CAAA;CACxB;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAiBhF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAG5D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK9D"}
@@ -1 +1 @@
1
- {"version":3,"file":"Navigator.d.ts","sourceRoot":"","sources":["../../src/views/Navigator.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Navigator.d.ts","sourceRoot":"","sources":["../../src/views/Navigator.tsx"],"names":[],"mappings":"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"}