@tanstack/react-router 1.39.8 → 1.41.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.
Files changed (142) hide show
  1. package/dist/cjs/CatchBoundary.d.cts +2 -2
  2. package/dist/cjs/Match.cjs +238 -0
  3. package/dist/cjs/Match.cjs.map +1 -0
  4. package/dist/cjs/Match.d.cts +5 -0
  5. package/dist/cjs/Matches.cjs +8 -253
  6. package/dist/cjs/Matches.cjs.map +1 -1
  7. package/dist/cjs/Matches.d.cts +2 -11
  8. package/dist/cjs/RouterProvider.cjs.map +1 -1
  9. package/dist/cjs/RouterProvider.d.cts +3 -2
  10. package/dist/cjs/SafeFragment.cjs +8 -0
  11. package/dist/cjs/SafeFragment.cjs.map +1 -0
  12. package/dist/cjs/SafeFragment.d.cts +1 -0
  13. package/dist/cjs/ScriptOnce.cjs +28 -0
  14. package/dist/cjs/ScriptOnce.cjs.map +1 -0
  15. package/dist/cjs/ScriptOnce.d.cts +5 -0
  16. package/dist/cjs/Transitioner.cjs +2 -1
  17. package/dist/cjs/Transitioner.cjs.map +1 -1
  18. package/dist/cjs/awaited.cjs +14 -71
  19. package/dist/cjs/awaited.cjs.map +1 -1
  20. package/dist/cjs/awaited.d.cts +3 -6
  21. package/dist/cjs/defer.cjs +7 -13
  22. package/dist/cjs/defer.cjs.map +1 -1
  23. package/dist/cjs/defer.d.cts +2 -6
  24. package/dist/cjs/index.cjs +11 -7
  25. package/dist/cjs/index.cjs.map +1 -1
  26. package/dist/cjs/index.d.cts +8 -3
  27. package/dist/cjs/isServerSideError.cjs +22 -0
  28. package/dist/cjs/isServerSideError.cjs.map +1 -0
  29. package/dist/cjs/isServerSideError.d.cts +5 -0
  30. package/dist/cjs/link.cjs +8 -9
  31. package/dist/cjs/link.cjs.map +1 -1
  32. package/dist/cjs/link.d.cts +1 -0
  33. package/dist/cjs/matchContext.cjs +23 -0
  34. package/dist/cjs/matchContext.cjs.map +1 -0
  35. package/dist/cjs/matchContext.d.cts +2 -0
  36. package/dist/cjs/not-found.cjs +1 -2
  37. package/dist/cjs/not-found.cjs.map +1 -1
  38. package/dist/cjs/not-found.d.cts +2 -2
  39. package/dist/cjs/path.cjs +3 -6
  40. package/dist/cjs/path.cjs.map +1 -1
  41. package/dist/cjs/qss.cjs +3 -6
  42. package/dist/cjs/qss.cjs.map +1 -1
  43. package/dist/cjs/qss.d.cts +1 -1
  44. package/dist/cjs/redirects.cjs.map +1 -1
  45. package/dist/cjs/renderRouteNotFound.cjs +22 -0
  46. package/dist/cjs/renderRouteNotFound.cjs.map +1 -0
  47. package/dist/cjs/renderRouteNotFound.d.cts +4 -0
  48. package/dist/cjs/root.cjs.map +1 -1
  49. package/dist/cjs/root.d.cts +1 -1
  50. package/dist/cjs/route.cjs.map +1 -1
  51. package/dist/cjs/router.cjs +33 -26
  52. package/dist/cjs/router.cjs.map +1 -1
  53. package/dist/cjs/router.d.cts +16 -11
  54. package/dist/cjs/scroll-restoration.cjs +1 -2
  55. package/dist/cjs/scroll-restoration.cjs.map +1 -1
  56. package/dist/cjs/useMatch.cjs +2 -2
  57. package/dist/cjs/useMatch.cjs.map +1 -1
  58. package/dist/cjs/utils.cjs +4 -3
  59. package/dist/cjs/utils.cjs.map +1 -1
  60. package/dist/cjs/utils.d.cts +3 -2
  61. package/dist/esm/CatchBoundary.d.ts +2 -2
  62. package/dist/esm/Match.d.ts +5 -0
  63. package/dist/esm/Match.js +221 -0
  64. package/dist/esm/Match.js.map +1 -0
  65. package/dist/esm/Matches.d.ts +2 -11
  66. package/dist/esm/Matches.js +5 -250
  67. package/dist/esm/Matches.js.map +1 -1
  68. package/dist/esm/RouterProvider.d.ts +3 -2
  69. package/dist/esm/RouterProvider.js.map +1 -1
  70. package/dist/esm/SafeFragment.d.ts +1 -0
  71. package/dist/esm/SafeFragment.js +8 -0
  72. package/dist/esm/SafeFragment.js.map +1 -0
  73. package/dist/esm/ScriptOnce.d.ts +5 -0
  74. package/dist/esm/ScriptOnce.js +28 -0
  75. package/dist/esm/ScriptOnce.js.map +1 -0
  76. package/dist/esm/Transitioner.js +2 -1
  77. package/dist/esm/Transitioner.js.map +1 -1
  78. package/dist/esm/awaited.d.ts +3 -6
  79. package/dist/esm/awaited.js +16 -73
  80. package/dist/esm/awaited.js.map +1 -1
  81. package/dist/esm/defer.d.ts +2 -6
  82. package/dist/esm/defer.js +8 -14
  83. package/dist/esm/defer.js.map +1 -1
  84. package/dist/esm/index.d.ts +8 -3
  85. package/dist/esm/index.js +9 -5
  86. package/dist/esm/index.js.map +1 -1
  87. package/dist/esm/isServerSideError.d.ts +5 -0
  88. package/dist/esm/isServerSideError.js +22 -0
  89. package/dist/esm/isServerSideError.js.map +1 -0
  90. package/dist/esm/link.d.ts +1 -0
  91. package/dist/esm/link.js +8 -9
  92. package/dist/esm/link.js.map +1 -1
  93. package/dist/esm/matchContext.d.ts +2 -0
  94. package/dist/esm/matchContext.js +6 -0
  95. package/dist/esm/matchContext.js.map +1 -0
  96. package/dist/esm/not-found.d.ts +2 -2
  97. package/dist/esm/not-found.js +1 -2
  98. package/dist/esm/not-found.js.map +1 -1
  99. package/dist/esm/path.js +3 -6
  100. package/dist/esm/path.js.map +1 -1
  101. package/dist/esm/qss.d.ts +1 -1
  102. package/dist/esm/qss.js +3 -6
  103. package/dist/esm/qss.js.map +1 -1
  104. package/dist/esm/redirects.js.map +1 -1
  105. package/dist/esm/renderRouteNotFound.d.ts +4 -0
  106. package/dist/esm/renderRouteNotFound.js +22 -0
  107. package/dist/esm/renderRouteNotFound.js.map +1 -0
  108. package/dist/esm/root.d.ts +1 -1
  109. package/dist/esm/root.js.map +1 -1
  110. package/dist/esm/route.js.map +1 -1
  111. package/dist/esm/router.d.ts +16 -11
  112. package/dist/esm/router.js +33 -26
  113. package/dist/esm/router.js.map +1 -1
  114. package/dist/esm/scroll-restoration.js +1 -2
  115. package/dist/esm/scroll-restoration.js.map +1 -1
  116. package/dist/esm/useMatch.js +1 -1
  117. package/dist/esm/useMatch.js.map +1 -1
  118. package/dist/esm/utils.d.ts +3 -2
  119. package/dist/esm/utils.js +4 -3
  120. package/dist/esm/utils.js.map +1 -1
  121. package/package.json +6 -5
  122. package/src/Match.tsx +296 -0
  123. package/src/Matches.tsx +4 -333
  124. package/src/RouterProvider.tsx +2 -1
  125. package/src/SafeFragment.tsx +5 -0
  126. package/src/ScriptOnce.tsx +27 -0
  127. package/src/Transitioner.tsx +1 -1
  128. package/src/awaited.tsx +17 -89
  129. package/src/defer.ts +9 -26
  130. package/src/index.tsx +7 -13
  131. package/src/isServerSideError.tsx +23 -0
  132. package/src/link.tsx +5 -0
  133. package/src/matchContext.tsx +3 -0
  134. package/src/not-found.tsx +1 -1
  135. package/src/qss.ts +5 -6
  136. package/src/redirects.ts +0 -1
  137. package/src/renderRouteNotFound.tsx +28 -0
  138. package/src/root.ts +1 -1
  139. package/src/route.ts +1 -1
  140. package/src/router.ts +54 -39
  141. package/src/useMatch.tsx +1 -1
  142. package/src/utils.ts +11 -9
@@ -1 +1 @@
1
- {"version":3,"file":"scroll-restoration.js","sources":["../../src/scroll-restoration.tsx"],"sourcesContent":["import * as React from 'react'\n\nconst useLayoutEffect =\n typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect\n\nimport { useRouter } from './useRouter'\nimport { functionalUpdate } from './utils'\nimport type { ParsedLocation } from './location'\nimport type { NonNullableUpdater } from './utils'\n\nconst windowKey = 'window'\nconst delimiter = '___'\n\nlet weakScrolledElements = new WeakSet<any>()\n\ntype CacheValue = Record<string, { scrollX: number; scrollY: number }>\ntype CacheState = {\n cached: CacheValue\n next: CacheValue\n}\n\ntype Cache = {\n state: CacheState\n set: (updater: NonNullableUpdater<CacheState>) => void\n}\n\nconst sessionsStorage = typeof window !== 'undefined' && window.sessionStorage\n\nconst cache: Cache = sessionsStorage\n ? (() => {\n const storageKey = 'tsr-scroll-restoration-v2'\n\n const state: CacheState = JSON.parse(\n window.sessionStorage.getItem(storageKey) || 'null',\n ) || { cached: {}, next: {} }\n\n return {\n state,\n set: (updater) => {\n cache.state = functionalUpdate(updater, cache.state)\n window.sessionStorage.setItem(storageKey, JSON.stringify(cache.state))\n },\n }\n })()\n : (undefined as any)\n\nexport type ScrollRestorationOptions = {\n getKey?: (location: ParsedLocation) => string\n}\n\nconst defaultGetKey = (location: ParsedLocation) => location.state.key!\n\nexport function useScrollRestoration(options?: ScrollRestorationOptions) {\n const router = useRouter()\n\n useLayoutEffect(() => {\n const getKey = options?.getKey || defaultGetKey\n\n const { history } = window\n history.scrollRestoration = 'manual'\n\n const onScroll = (event: Event) => {\n if (weakScrolledElements.has(event.target)) return\n weakScrolledElements.add(event.target)\n\n let elementSelector = ''\n\n if (event.target === document || event.target === window) {\n elementSelector = windowKey\n } else {\n const attrId = (event.target as Element).getAttribute(\n 'data-scroll-restoration-id',\n )\n\n if (attrId) {\n elementSelector = `[data-scroll-restoration-id=\"${attrId}\"]`\n } else {\n elementSelector = getCssSelector(event.target)\n }\n }\n\n if (!cache.state.next[elementSelector]) {\n cache.set((c) => ({\n ...c,\n next: {\n ...c.next,\n [elementSelector]: {\n scrollX: NaN,\n scrollY: NaN,\n },\n },\n }))\n }\n }\n\n if (typeof document !== 'undefined') {\n document.addEventListener('scroll', onScroll, true)\n }\n\n const unsubOnBeforeLoad = router.subscribe('onBeforeLoad', (event) => {\n if (event.pathChanged) {\n const restoreKey = getKey(event.fromLocation)\n for (const elementSelector in cache.state.next) {\n const entry = cache.state.next[elementSelector]!\n if (elementSelector === windowKey) {\n entry.scrollX = window.scrollX || 0\n entry.scrollY = window.scrollY || 0\n } else if (elementSelector) {\n const element = document.querySelector(elementSelector)\n entry.scrollX = element?.scrollLeft || 0\n entry.scrollY = element?.scrollTop || 0\n }\n\n cache.set((c) => {\n const next = { ...c.next }\n delete next[elementSelector]\n\n return {\n ...c,\n next,\n cached: {\n ...c.cached,\n [[restoreKey, elementSelector].join(delimiter)]: entry,\n },\n }\n })\n }\n }\n })\n\n const unsubOnResolved = router.subscribe('onResolved', (event) => {\n if (event.pathChanged) {\n if (!router.resetNextScroll) {\n return\n }\n\n router.resetNextScroll = true\n\n const restoreKey = getKey(event.toLocation)\n let windowRestored = false\n\n for (const cacheKey in cache.state.cached) {\n const entry = cache.state.cached[cacheKey]!\n const [key, elementSelector] = cacheKey.split(delimiter)\n if (key === restoreKey) {\n if (elementSelector === windowKey) {\n windowRestored = true\n window.scrollTo(entry.scrollX, entry.scrollY)\n } else if (elementSelector) {\n const element = document.querySelector(elementSelector)\n if (element) {\n element.scrollLeft = entry.scrollX\n element.scrollTop = entry.scrollY\n }\n }\n }\n }\n\n if (!windowRestored) {\n window.scrollTo(0, 0)\n }\n\n cache.set((c) => ({ ...c, next: {} }))\n weakScrolledElements = new WeakSet<any>()\n }\n })\n\n return () => {\n document.removeEventListener('scroll', onScroll)\n unsubOnBeforeLoad()\n unsubOnResolved()\n }\n }, [options?.getKey, router])\n}\n\nexport function ScrollRestoration(props: ScrollRestorationOptions) {\n useScrollRestoration(props)\n return null\n}\n\nexport function useElementScrollRestoration(\n options: (\n | {\n id: string\n getElement?: () => Element | undefined | null\n }\n | {\n id?: string\n getElement: () => Element | undefined | null\n }\n ) & {\n getKey?: (location: ParsedLocation) => string\n },\n) {\n const router = useRouter()\n const getKey = options.getKey || defaultGetKey\n\n let elementSelector = ''\n\n if (options.id) {\n elementSelector = `[data-scroll-restoration-id=\"${options.id}\"]`\n } else {\n const element = options.getElement?.()\n if (!element) {\n return\n }\n elementSelector = getCssSelector(element)\n }\n\n const restoreKey = getKey(router.latestLocation)\n const cacheKey = [restoreKey, elementSelector].join(delimiter)\n return cache.state.cached[cacheKey]\n}\n\nfunction getCssSelector(el: any): string {\n const path = []\n let parent\n while ((parent = el.parentNode)) {\n path.unshift(\n `${el.tagName}:nth-child(${\n ([].indexOf as any).call(parent.children, el) + 1\n })`,\n )\n el = parent\n }\n return `${path.join(' > ')}`.toLowerCase()\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scroll-restoration.js","sources":["../../src/scroll-restoration.tsx"],"sourcesContent":["import * as React from 'react'\n\nconst useLayoutEffect =\n typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect\n\nimport { useRouter } from './useRouter'\nimport { functionalUpdate } from './utils'\nimport type { ParsedLocation } from './location'\nimport type { NonNullableUpdater } from './utils'\n\nconst windowKey = 'window'\nconst delimiter = '___'\n\nlet weakScrolledElements = new WeakSet<any>()\n\ntype CacheValue = Record<string, { scrollX: number; scrollY: number }>\ntype CacheState = {\n cached: CacheValue\n next: CacheValue\n}\n\ntype Cache = {\n state: CacheState\n set: (updater: NonNullableUpdater<CacheState>) => void\n}\n\nconst sessionsStorage = typeof window !== 'undefined' && window.sessionStorage\n\nconst cache: Cache = sessionsStorage\n ? (() => {\n const storageKey = 'tsr-scroll-restoration-v2'\n\n const state: CacheState = JSON.parse(\n window.sessionStorage.getItem(storageKey) || 'null',\n ) || { cached: {}, next: {} }\n\n return {\n state,\n set: (updater) => {\n cache.state = functionalUpdate(updater, cache.state)\n window.sessionStorage.setItem(storageKey, JSON.stringify(cache.state))\n },\n }\n })()\n : (undefined as any)\n\nexport type ScrollRestorationOptions = {\n getKey?: (location: ParsedLocation) => string\n}\n\nconst defaultGetKey = (location: ParsedLocation) => location.state.key!\n\nexport function useScrollRestoration(options?: ScrollRestorationOptions) {\n const router = useRouter()\n\n useLayoutEffect(() => {\n const getKey = options?.getKey || defaultGetKey\n\n const { history } = window\n history.scrollRestoration = 'manual'\n\n const onScroll = (event: Event) => {\n if (weakScrolledElements.has(event.target)) return\n weakScrolledElements.add(event.target)\n\n let elementSelector = ''\n\n if (event.target === document || event.target === window) {\n elementSelector = windowKey\n } else {\n const attrId = (event.target as Element).getAttribute(\n 'data-scroll-restoration-id',\n )\n\n if (attrId) {\n elementSelector = `[data-scroll-restoration-id=\"${attrId}\"]`\n } else {\n elementSelector = getCssSelector(event.target)\n }\n }\n\n if (!cache.state.next[elementSelector]) {\n cache.set((c) => ({\n ...c,\n next: {\n ...c.next,\n [elementSelector]: {\n scrollX: NaN,\n scrollY: NaN,\n },\n },\n }))\n }\n }\n\n if (typeof document !== 'undefined') {\n document.addEventListener('scroll', onScroll, true)\n }\n\n const unsubOnBeforeLoad = router.subscribe('onBeforeLoad', (event) => {\n if (event.pathChanged) {\n const restoreKey = getKey(event.fromLocation)\n for (const elementSelector in cache.state.next) {\n const entry = cache.state.next[elementSelector]!\n if (elementSelector === windowKey) {\n entry.scrollX = window.scrollX || 0\n entry.scrollY = window.scrollY || 0\n } else if (elementSelector) {\n const element = document.querySelector(elementSelector)\n entry.scrollX = element?.scrollLeft || 0\n entry.scrollY = element?.scrollTop || 0\n }\n\n cache.set((c) => {\n const next = { ...c.next }\n delete next[elementSelector]\n\n return {\n ...c,\n next,\n cached: {\n ...c.cached,\n [[restoreKey, elementSelector].join(delimiter)]: entry,\n },\n }\n })\n }\n }\n })\n\n const unsubOnResolved = router.subscribe('onResolved', (event) => {\n if (event.pathChanged) {\n if (!router.resetNextScroll) {\n return\n }\n\n router.resetNextScroll = true\n\n const restoreKey = getKey(event.toLocation)\n let windowRestored = false\n\n for (const cacheKey in cache.state.cached) {\n const entry = cache.state.cached[cacheKey]!\n const [key, elementSelector] = cacheKey.split(delimiter)\n if (key === restoreKey) {\n if (elementSelector === windowKey) {\n windowRestored = true\n window.scrollTo(entry.scrollX, entry.scrollY)\n } else if (elementSelector) {\n const element = document.querySelector(elementSelector)\n if (element) {\n element.scrollLeft = entry.scrollX\n element.scrollTop = entry.scrollY\n }\n }\n }\n }\n\n if (!windowRestored) {\n window.scrollTo(0, 0)\n }\n\n cache.set((c) => ({ ...c, next: {} }))\n weakScrolledElements = new WeakSet<any>()\n }\n })\n\n return () => {\n document.removeEventListener('scroll', onScroll)\n unsubOnBeforeLoad()\n unsubOnResolved()\n }\n }, [options?.getKey, router])\n}\n\nexport function ScrollRestoration(props: ScrollRestorationOptions) {\n useScrollRestoration(props)\n return null\n}\n\nexport function useElementScrollRestoration(\n options: (\n | {\n id: string\n getElement?: () => Element | undefined | null\n }\n | {\n id?: string\n getElement: () => Element | undefined | null\n }\n ) & {\n getKey?: (location: ParsedLocation) => string\n },\n) {\n const router = useRouter()\n const getKey = options.getKey || defaultGetKey\n\n let elementSelector = ''\n\n if (options.id) {\n elementSelector = `[data-scroll-restoration-id=\"${options.id}\"]`\n } else {\n const element = options.getElement?.()\n if (!element) {\n return\n }\n elementSelector = getCssSelector(element)\n }\n\n const restoreKey = getKey(router.latestLocation)\n const cacheKey = [restoreKey, elementSelector].join(delimiter)\n return cache.state.cached[cacheKey]\n}\n\nfunction getCssSelector(el: any): string {\n const path = []\n let parent\n while ((parent = el.parentNode)) {\n path.unshift(\n `${el.tagName}:nth-child(${\n ([].indexOf as any).call(parent.children, el) + 1\n })`,\n )\n el = parent\n }\n return `${path.join(' > ')}`.toLowerCase()\n}\n"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import * as React from "react";
2
2
  import invariant from "tiny-invariant";
3
3
  import { useRouterState } from "./useRouterState.js";
4
- import { matchContext } from "./Matches.js";
4
+ import { matchContext } from "./matchContext.js";
5
5
  function useMatch(opts) {
6
6
  const nearestMatchId = React.useContext(matchContext);
7
7
  const matchSelection = useRouterState({
@@ -1 +1 @@
1
- {"version":3,"file":"useMatch.js","sources":["../../src/useMatch.tsx"],"sourcesContent":["import * as React from 'react'\nimport invariant from 'tiny-invariant'\nimport { useRouterState } from './useRouterState'\nimport { type RegisteredRouter } from './router'\nimport { type AnyRoute } from './route'\nimport { matchContext } from './Matches'\nimport type { MakeRouteMatch } from './Matches'\nimport type { RouteIds } from './routeInfo'\nimport type { StrictOrFrom } from './utils'\n\nexport type UseMatchOptions<\n TFrom,\n TStrict extends boolean,\n TRouteMatch,\n TSelected,\n> = StrictOrFrom<TFrom, TStrict> & {\n select?: (match: TRouteMatch) => TSelected\n}\n\nexport function useMatch<\n TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],\n TFrom extends RouteIds<TRouteTree> = RouteIds<TRouteTree>,\n TStrict extends boolean = true,\n TRouteMatch = MakeRouteMatch<TRouteTree, TFrom, TStrict>,\n TSelected = TRouteMatch,\n>(opts: UseMatchOptions<TFrom, TStrict, TRouteMatch, TSelected>): TSelected {\n const nearestMatchId = React.useContext(matchContext)\n\n const matchSelection = useRouterState({\n select: (state) => {\n const match = state.matches.find((d) =>\n opts.from ? opts.from === d.routeId : d.id === nearestMatchId,\n )\n\n invariant(\n match,\n `Could not find ${opts.from ? `an active match from \"${opts.from}\"` : 'a nearest match!'}`,\n )\n\n return opts.select ? opts.select(match as any) : match\n },\n })\n\n return matchSelection as TSelected\n}\n"],"names":[],"mappings":";;;;AAmBO,SAAS,SAMd,MAA0E;AACpE,QAAA,iBAAiB,MAAM,WAAW,YAAY;AAEpD,QAAM,iBAAiB,eAAe;AAAA,IACpC,QAAQ,CAAC,UAAU;AACX,YAAA,QAAQ,MAAM,QAAQ;AAAA,QAAK,CAAC,MAChC,KAAK,OAAO,KAAK,SAAS,EAAE,UAAU,EAAE,OAAO;AAAA,MAAA;AAGjD;AAAA,QACE;AAAA,QACA,kBAAkB,KAAK,OAAO,yBAAyB,KAAK,IAAI,MAAM,kBAAkB;AAAA,MAAA;AAG1F,aAAO,KAAK,SAAS,KAAK,OAAO,KAAY,IAAI;AAAA,IACnD;AAAA,EAAA,CACD;AAEM,SAAA;AACT;"}
1
+ {"version":3,"file":"useMatch.js","sources":["../../src/useMatch.tsx"],"sourcesContent":["import * as React from 'react'\nimport invariant from 'tiny-invariant'\nimport { useRouterState } from './useRouterState'\nimport { type RegisteredRouter } from './router'\nimport { type AnyRoute } from './route'\nimport { matchContext } from './matchContext'\nimport type { MakeRouteMatch } from './Matches'\nimport type { RouteIds } from './routeInfo'\nimport type { StrictOrFrom } from './utils'\n\nexport type UseMatchOptions<\n TFrom,\n TStrict extends boolean,\n TRouteMatch,\n TSelected,\n> = StrictOrFrom<TFrom, TStrict> & {\n select?: (match: TRouteMatch) => TSelected\n}\n\nexport function useMatch<\n TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],\n TFrom extends RouteIds<TRouteTree> = RouteIds<TRouteTree>,\n TStrict extends boolean = true,\n TRouteMatch = MakeRouteMatch<TRouteTree, TFrom, TStrict>,\n TSelected = TRouteMatch,\n>(opts: UseMatchOptions<TFrom, TStrict, TRouteMatch, TSelected>): TSelected {\n const nearestMatchId = React.useContext(matchContext)\n\n const matchSelection = useRouterState({\n select: (state) => {\n const match = state.matches.find((d) =>\n opts.from ? opts.from === d.routeId : d.id === nearestMatchId,\n )\n\n invariant(\n match,\n `Could not find ${opts.from ? `an active match from \"${opts.from}\"` : 'a nearest match!'}`,\n )\n\n return opts.select ? opts.select(match as any) : match\n },\n })\n\n return matchSelection as TSelected\n}\n"],"names":[],"mappings":";;;;AAmBO,SAAS,SAMd,MAA0E;AACpE,QAAA,iBAAiB,MAAM,WAAW,YAAY;AAEpD,QAAM,iBAAiB,eAAe;AAAA,IACpC,QAAQ,CAAC,UAAU;AACX,YAAA,QAAQ,MAAM,QAAQ;AAAA,QAAK,CAAC,MAChC,KAAK,OAAO,KAAK,SAAS,EAAE,UAAU,EAAE,OAAO;AAAA,MAAA;AAGjD;AAAA,QACE;AAAA,QACA,kBAAkB,KAAK,OAAO,yBAAyB,KAAK,IAAI,MAAM,kBAAkB;AAAA,MAAA;AAG1F,aAAO,KAAK,SAAS,KAAK,OAAO,KAAY,IAAI;AAAA,IACnD;AAAA,EAAA,CACD;AAEM,SAAA;AACT;"}
@@ -38,7 +38,7 @@ export declare function pick<TValue, TKey extends keyof TValue>(parent: TValue,
38
38
  */
39
39
  export declare function replaceEqualDeep<T>(prev: any, _next: T): T;
40
40
  export declare function isPlainObject(o: any): boolean;
41
- export declare function isPlainArray(value: unknown): boolean;
41
+ export declare function isPlainArray(value: unknown): value is Array<unknown>;
42
42
  export declare function deepEqual(a: any, b: any, partial?: boolean): boolean;
43
43
  export declare function useStableCallback<T extends (...args: Array<any>) => any>(fn: T): T;
44
44
  export declare function shallow<T>(objA: T, objB: T): boolean;
@@ -60,8 +60,9 @@ export type ControlledPromise<T> = Promise<T> & {
60
60
  resolve: (value: T) => void;
61
61
  reject: (value: any) => void;
62
62
  status: 'pending' | 'resolved' | 'rejected';
63
+ value?: T;
63
64
  };
64
- export declare function createControlledPromise<T>(onResolve?: () => void): ControlledPromise<T>;
65
+ export declare function createControlledPromise<T>(onResolve?: (value: T) => void): ControlledPromise<T>;
65
66
  /**
66
67
  * Taken from https://www.developerway.com/posts/implementing-advanced-use-previous-hook#part3
67
68
  */
package/dist/esm/utils.js CHANGED
@@ -127,10 +127,11 @@ function createControlledPromise(onResolve) {
127
127
  rejectLoadPromise = reject;
128
128
  });
129
129
  controlledPromise.status = "pending";
130
- controlledPromise.resolve = () => {
130
+ controlledPromise.resolve = (value) => {
131
131
  controlledPromise.status = "resolved";
132
- resolveLoadPromise();
133
- onResolve == null ? void 0 : onResolve();
132
+ controlledPromise.value = value;
133
+ resolveLoadPromise(value);
134
+ onResolve == null ? void 0 : onResolve(value);
134
135
  };
135
136
  controlledPromise.reject = (e) => {
136
137
  controlledPromise.status = "rejected";
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["import * as React from 'react'\n\nexport type NoInfer<T> = [T][T extends any ? 0 : never]\nexport type IsAny<TValue, TYesResult, TNoResult = TValue> = 1 extends 0 & TValue\n ? TYesResult\n : TNoResult\nexport type PickAsRequired<TValue, TKey extends keyof TValue> = Omit<\n TValue,\n TKey\n> &\n Required<Pick<TValue, TKey>>\n\nexport type PickRequired<T> = {\n [K in keyof T as undefined extends T[K] ? never : K]: T[K]\n}\n\n// from https://stackoverflow.com/a/76458160\nexport type WithoutEmpty<T> = T extends any ? ({} extends T ? never : T) : never\n\n// export type Expand<T> = T\nexport type Expand<T> = T extends object\n ? T extends infer O\n ? O extends Function\n ? O\n : { [K in keyof O]: O[K] }\n : never\n : T\n\nexport type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>\n }\n : T\n\nexport type MakeDifferenceOptional<TLeft, TRight> = Omit<\n TRight,\n keyof TLeft\n> & {\n [K in keyof TLeft & keyof TRight]?: TRight[K]\n}\n\n// from https://stackoverflow.com/a/53955431\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type IsUnion<T, U extends T = T> = (\n T extends any ? (U extends T ? false : true) : never\n) extends false\n ? false\n : true\n\nexport type Assign<TLeft, TRight> = keyof TLeft extends never\n ? TRight\n : keyof TRight extends never\n ? TLeft\n : keyof TLeft & keyof TRight extends never\n ? TLeft & TRight\n : Omit<TLeft, keyof TRight> & TRight\n\nexport type Timeout = ReturnType<typeof setTimeout>\n\nexport type Updater<TPrevious, TResult = TPrevious> =\n | TResult\n | ((prev?: TPrevious) => TResult)\n\nexport type NonNullableUpdater<TPrevious, TResult = TPrevious> =\n | TResult\n | ((prev: TPrevious) => TResult)\n\nexport type MergeUnionObjects<TUnion> = TUnion extends MergeUnionPrimitive\n ? never\n : TUnion\n\nexport type MergeUnionObject<TUnion> =\n MergeUnionObjects<TUnion> extends infer TObj\n ? {\n [TKey in TObj extends any ? keyof TObj : never]?: TObj extends any\n ? TKey extends keyof TObj\n ? TObj[TKey]\n : never\n : never\n }\n : never\n\nexport type MergeUnionPrimitive =\n | ReadonlyArray<any>\n | number\n | string\n | bigint\n | boolean\n | symbol\n\nexport type MergeUnionPrimitives<TUnion> = TUnion extends MergeUnionPrimitive\n ? TUnion\n : TUnion extends object\n ? never\n : TUnion\n\nexport type MergeUnion<TUnion> =\n | MergeUnionPrimitives<TUnion>\n | MergeUnionObject<TUnion>\n\nexport function last<T>(arr: Array<T>) {\n return arr[arr.length - 1]\n}\n\nfunction isFunction(d: any): d is Function {\n return typeof d === 'function'\n}\n\nexport function functionalUpdate<TResult>(\n updater: Updater<TResult> | NonNullableUpdater<TResult>,\n previous: TResult,\n): TResult {\n if (isFunction(updater)) {\n return updater(previous)\n }\n\n return updater\n}\n\nexport function pick<TValue, TKey extends keyof TValue>(\n parent: TValue,\n keys: Array<TKey>,\n): Pick<TValue, TKey> {\n return keys.reduce((obj: any, key: TKey) => {\n obj[key] = parent[key]\n return obj\n }, {} as any)\n}\n\n/**\n * This function returns `prev` if `_next` is deeply equal.\n * If not, it will replace any deeply equal children of `b` with those of `a`.\n * This can be used for structural sharing between immutable JSON values for example.\n * Do not use this with signals\n */\nexport function replaceEqualDeep<T>(prev: any, _next: T): T {\n if (prev === _next) {\n return prev\n }\n\n const next = _next as any\n\n const array = isPlainArray(prev) && isPlainArray(next)\n\n if (array || (isPlainObject(prev) && isPlainObject(next))) {\n const prevItems = array ? prev : Object.keys(prev)\n const prevSize = prevItems.length\n const nextItems = array ? next : Object.keys(next)\n const nextSize = nextItems.length\n const copy: any = array ? [] : {}\n\n let equalItems = 0\n\n for (let i = 0; i < nextSize; i++) {\n const key = array ? i : nextItems[i]\n if (\n ((!array && prevItems.includes(key)) || array) &&\n prev[key] === undefined &&\n next[key] === undefined\n ) {\n copy[key] = undefined\n equalItems++\n } else {\n copy[key] = replaceEqualDeep(prev[key], next[key])\n if (copy[key] === prev[key] && prev[key] !== undefined) {\n equalItems++\n }\n }\n }\n\n return prevSize === nextSize && equalItems === prevSize ? prev : copy\n }\n\n return next\n}\n\n// Copied from: https://github.com/jonschlinkert/is-plain-object\nexport function isPlainObject(o: any) {\n if (!hasObjectPrototype(o)) {\n return false\n }\n\n // If has modified constructor\n const ctor = o.constructor\n if (typeof ctor === 'undefined') {\n return true\n }\n\n // If has modified prototype\n const prot = ctor.prototype\n if (!hasObjectPrototype(prot)) {\n return false\n }\n\n // If constructor does not have an Object-specific method\n if (!prot.hasOwnProperty('isPrototypeOf')) {\n return false\n }\n\n // Most likely a plain Object\n return true\n}\n\nfunction hasObjectPrototype(o: any) {\n return Object.prototype.toString.call(o) === '[object Object]'\n}\n\nexport function isPlainArray(value: unknown) {\n return Array.isArray(value) && value.length === Object.keys(value).length\n}\n\nexport function deepEqual(a: any, b: any, partial: boolean = false): boolean {\n if (a === b) {\n return true\n }\n\n if (typeof a !== typeof b) {\n return false\n }\n\n if (isPlainObject(a) && isPlainObject(b)) {\n const aKeys = Object.keys(a)\n const bKeys = Object.keys(b)\n\n if (!partial && aKeys.length !== bKeys.length) {\n return false\n }\n\n return !bKeys.some(\n (key) => !(key in a) || !deepEqual(a[key], b[key], partial),\n )\n }\n\n if (Array.isArray(a) && Array.isArray(b)) {\n return !a.some((item, index) => !deepEqual(item, b[index], partial))\n }\n\n return false\n}\n\nexport function useStableCallback<T extends (...args: Array<any>) => any>(\n fn: T,\n): T {\n const fnRef = React.useRef(fn)\n fnRef.current = fn\n\n const ref = React.useRef((...args: Array<any>) => fnRef.current(...args))\n return ref.current as T\n}\n\nexport function shallow<T>(objA: T, objB: T) {\n if (Object.is(objA, objB)) {\n return true\n }\n\n if (\n typeof objA !== 'object' ||\n objA === null ||\n typeof objB !== 'object' ||\n objB === null\n ) {\n return false\n }\n\n const keysA = Object.keys(objA)\n if (keysA.length !== Object.keys(objB).length) {\n return false\n }\n\n for (const item of keysA) {\n if (\n !Object.prototype.hasOwnProperty.call(objB, item) ||\n !Object.is(objA[item as keyof T], objB[item as keyof T])\n ) {\n return false\n }\n }\n return true\n}\n\nexport type StringLiteral<T> = T extends string\n ? string extends T\n ? string\n : T\n : never\n\nexport type StrictOrFrom<\n TFrom,\n TStrict extends boolean = true,\n> = TStrict extends false\n ? {\n from?: never\n strict: TStrict\n }\n : {\n from: StringLiteral<TFrom> | TFrom\n strict?: TStrict\n }\n\nexport const useLayoutEffect =\n typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect\n\n/**\n *\n * @deprecated use `jsesc` instead\n */\nexport function escapeJSON(jsonString: string) {\n return jsonString\n .replace(/\\\\/g, '\\\\\\\\') // Escape backslashes\n .replace(/'/g, \"\\\\'\") // Escape single quotes\n .replace(/\"/g, '\\\\\"') // Escape double quotes\n}\n\nexport type ControlledPromise<T> = Promise<T> & {\n resolve: (value: T) => void\n reject: (value: any) => void\n status: 'pending' | 'resolved' | 'rejected'\n}\n\nexport function createControlledPromise<T>(onResolve?: () => void) {\n let resolveLoadPromise!: () => void\n let rejectLoadPromise!: (value: any) => void\n\n const controlledPromise = new Promise<void>((resolve, reject) => {\n resolveLoadPromise = resolve\n rejectLoadPromise = reject\n }) as ControlledPromise<T>\n\n controlledPromise.status = 'pending'\n\n controlledPromise.resolve = () => {\n controlledPromise.status = 'resolved'\n resolveLoadPromise()\n onResolve?.()\n }\n\n controlledPromise.reject = (e) => {\n controlledPromise.status = 'rejected'\n rejectLoadPromise(e)\n }\n\n return controlledPromise\n}\n\n/**\n * Taken from https://www.developerway.com/posts/implementing-advanced-use-previous-hook#part3\n */\nexport function usePrevious<T>(value: T): T | null {\n // initialise the ref with previous and current values\n const ref = React.useRef<{ value: T; prev: T | null }>({\n value: value,\n prev: null,\n })\n\n const current = ref.current.value\n\n // if the value passed into hook doesn't match what we store as \"current\"\n // move the \"current\" to the \"previous\"\n // and store the passed value as \"current\"\n if (value !== current) {\n ref.current = {\n value: value,\n prev: current,\n }\n }\n\n // return the previous value only\n return ref.current.prev\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["import * as React from 'react'\n\nexport type NoInfer<T> = [T][T extends any ? 0 : never]\nexport type IsAny<TValue, TYesResult, TNoResult = TValue> = 1 extends 0 & TValue\n ? TYesResult\n : TNoResult\nexport type PickAsRequired<TValue, TKey extends keyof TValue> = Omit<\n TValue,\n TKey\n> &\n Required<Pick<TValue, TKey>>\n\nexport type PickRequired<T> = {\n [K in keyof T as undefined extends T[K] ? never : K]: T[K]\n}\n\n// from https://stackoverflow.com/a/76458160\nexport type WithoutEmpty<T> = T extends any ? ({} extends T ? never : T) : never\n\n// export type Expand<T> = T\nexport type Expand<T> = T extends object\n ? T extends infer O\n ? O extends Function\n ? O\n : { [K in keyof O]: O[K] }\n : never\n : T\n\nexport type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>\n }\n : T\n\nexport type MakeDifferenceOptional<TLeft, TRight> = Omit<\n TRight,\n keyof TLeft\n> & {\n [K in keyof TLeft & keyof TRight]?: TRight[K]\n}\n\n// from https://stackoverflow.com/a/53955431\n// eslint-disable-next-line ts/naming-convention\nexport type IsUnion<T, U extends T = T> = (\n T extends any ? (U extends T ? false : true) : never\n) extends false\n ? false\n : true\n\nexport type Assign<TLeft, TRight> = keyof TLeft extends never\n ? TRight\n : keyof TRight extends never\n ? TLeft\n : keyof TLeft & keyof TRight extends never\n ? TLeft & TRight\n : Omit<TLeft, keyof TRight> & TRight\n\nexport type Timeout = ReturnType<typeof setTimeout>\n\nexport type Updater<TPrevious, TResult = TPrevious> =\n | TResult\n | ((prev?: TPrevious) => TResult)\n\nexport type NonNullableUpdater<TPrevious, TResult = TPrevious> =\n | TResult\n | ((prev: TPrevious) => TResult)\n\nexport type MergeUnionObjects<TUnion> = TUnion extends MergeUnionPrimitive\n ? never\n : TUnion\n\nexport type MergeUnionObject<TUnion> =\n MergeUnionObjects<TUnion> extends infer TObj\n ? {\n [TKey in TObj extends any ? keyof TObj : never]?: TObj extends any\n ? TKey extends keyof TObj\n ? TObj[TKey]\n : never\n : never\n }\n : never\n\nexport type MergeUnionPrimitive =\n | ReadonlyArray<any>\n | number\n | string\n | bigint\n | boolean\n | symbol\n\nexport type MergeUnionPrimitives<TUnion> = TUnion extends MergeUnionPrimitive\n ? TUnion\n : TUnion extends object\n ? never\n : TUnion\n\nexport type MergeUnion<TUnion> =\n | MergeUnionPrimitives<TUnion>\n | MergeUnionObject<TUnion>\n\nexport function last<T>(arr: Array<T>) {\n return arr[arr.length - 1]\n}\n\nfunction isFunction(d: any): d is Function {\n return typeof d === 'function'\n}\n\nexport function functionalUpdate<TResult>(\n updater: Updater<TResult> | NonNullableUpdater<TResult>,\n previous: TResult,\n): TResult {\n if (isFunction(updater)) {\n return updater(previous)\n }\n\n return updater\n}\n\nexport function pick<TValue, TKey extends keyof TValue>(\n parent: TValue,\n keys: Array<TKey>,\n): Pick<TValue, TKey> {\n return keys.reduce((obj: any, key: TKey) => {\n obj[key] = parent[key]\n return obj\n }, {} as any)\n}\n\n/**\n * This function returns `prev` if `_next` is deeply equal.\n * If not, it will replace any deeply equal children of `b` with those of `a`.\n * This can be used for structural sharing between immutable JSON values for example.\n * Do not use this with signals\n */\nexport function replaceEqualDeep<T>(prev: any, _next: T): T {\n if (prev === _next) {\n return prev\n }\n\n const next = _next as any\n\n const array = isPlainArray(prev) && isPlainArray(next)\n\n if (array || (isPlainObject(prev) && isPlainObject(next))) {\n const prevItems = array ? prev : Object.keys(prev)\n const prevSize = prevItems.length\n const nextItems = array ? next : Object.keys(next)\n const nextSize = nextItems.length\n const copy: any = array ? [] : {}\n\n let equalItems = 0\n\n for (let i = 0; i < nextSize; i++) {\n const key = array ? i : (nextItems[i] as any)\n if (\n ((!array && prevItems.includes(key)) || array) &&\n prev[key] === undefined &&\n next[key] === undefined\n ) {\n copy[key] = undefined\n equalItems++\n } else {\n copy[key] = replaceEqualDeep(prev[key], next[key])\n if (copy[key] === prev[key] && prev[key] !== undefined) {\n equalItems++\n }\n }\n }\n\n return prevSize === nextSize && equalItems === prevSize ? prev : copy\n }\n\n return next\n}\n\n// Copied from: https://github.com/jonschlinkert/is-plain-object\nexport function isPlainObject(o: any) {\n if (!hasObjectPrototype(o)) {\n return false\n }\n\n // If has modified constructor\n const ctor = o.constructor\n if (typeof ctor === 'undefined') {\n return true\n }\n\n // If has modified prototype\n const prot = ctor.prototype\n if (!hasObjectPrototype(prot)) {\n return false\n }\n\n // If constructor does not have an Object-specific method\n if (!prot.hasOwnProperty('isPrototypeOf')) {\n return false\n }\n\n // Most likely a plain Object\n return true\n}\n\nfunction hasObjectPrototype(o: any) {\n return Object.prototype.toString.call(o) === '[object Object]'\n}\n\nexport function isPlainArray(value: unknown): value is Array<unknown> {\n return Array.isArray(value) && value.length === Object.keys(value).length\n}\n\nexport function deepEqual(a: any, b: any, partial: boolean = false): boolean {\n if (a === b) {\n return true\n }\n\n if (typeof a !== typeof b) {\n return false\n }\n\n if (isPlainObject(a) && isPlainObject(b)) {\n const aKeys = Object.keys(a)\n const bKeys = Object.keys(b)\n\n if (!partial && aKeys.length !== bKeys.length) {\n return false\n }\n\n return !bKeys.some(\n (key) => !(key in a) || !deepEqual(a[key], b[key], partial),\n )\n }\n\n if (Array.isArray(a) && Array.isArray(b)) {\n return !a.some((item, index) => !deepEqual(item, b[index], partial))\n }\n\n return false\n}\n\nexport function useStableCallback<T extends (...args: Array<any>) => any>(\n fn: T,\n): T {\n const fnRef = React.useRef(fn)\n fnRef.current = fn\n\n const ref = React.useRef((...args: Array<any>) => fnRef.current(...args))\n return ref.current as T\n}\n\nexport function shallow<T>(objA: T, objB: T) {\n if (Object.is(objA, objB)) {\n return true\n }\n\n if (\n typeof objA !== 'object' ||\n objA === null ||\n typeof objB !== 'object' ||\n objB === null\n ) {\n return false\n }\n\n const keysA = Object.keys(objA)\n if (keysA.length !== Object.keys(objB).length) {\n return false\n }\n\n for (const item of keysA) {\n if (\n !Object.prototype.hasOwnProperty.call(objB, item) ||\n !Object.is(objA[item as keyof T], objB[item as keyof T])\n ) {\n return false\n }\n }\n return true\n}\n\nexport type StringLiteral<T> = T extends string\n ? string extends T\n ? string\n : T\n : never\n\nexport type StrictOrFrom<\n TFrom,\n TStrict extends boolean = true,\n> = TStrict extends false\n ? {\n from?: never\n strict: TStrict\n }\n : {\n from: StringLiteral<TFrom> | TFrom\n strict?: TStrict\n }\n\nexport const useLayoutEffect =\n typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect\n\n/**\n *\n * @deprecated use `jsesc` instead\n */\nexport function escapeJSON(jsonString: string) {\n return jsonString\n .replace(/\\\\/g, '\\\\\\\\') // Escape backslashes\n .replace(/'/g, \"\\\\'\") // Escape single quotes\n .replace(/\"/g, '\\\\\"') // Escape double quotes\n}\n\nexport type ControlledPromise<T> = Promise<T> & {\n resolve: (value: T) => void\n reject: (value: any) => void\n status: 'pending' | 'resolved' | 'rejected'\n value?: T\n}\n\nexport function createControlledPromise<T>(onResolve?: (value: T) => void) {\n let resolveLoadPromise!: (value: T) => void\n let rejectLoadPromise!: (value: any) => void\n\n const controlledPromise = new Promise<T>((resolve, reject) => {\n resolveLoadPromise = resolve\n rejectLoadPromise = reject\n }) as ControlledPromise<T>\n\n controlledPromise.status = 'pending'\n\n controlledPromise.resolve = (value: T) => {\n controlledPromise.status = 'resolved'\n controlledPromise.value = value\n resolveLoadPromise(value)\n onResolve?.(value)\n }\n\n controlledPromise.reject = (e) => {\n controlledPromise.status = 'rejected'\n rejectLoadPromise(e)\n }\n\n return controlledPromise\n}\n\n/**\n * Taken from https://www.developerway.com/posts/implementing-advanced-use-previous-hook#part3\n */\nexport function usePrevious<T>(value: T): T | null {\n // initialise the ref with previous and current values\n const ref = React.useRef<{ value: T; prev: T | null }>({\n value: value,\n prev: null,\n })\n\n const current = ref.current.value\n\n // if the value passed into hook doesn't match what we store as \"current\"\n // move the \"current\" to the \"previous\"\n // and store the passed value as \"current\"\n if (value !== current) {\n ref.current = {\n value: value,\n prev: current,\n }\n }\n\n // return the previous value only\n return ref.current.prev\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/react-router",
3
- "version": "1.39.8",
3
+ "version": "1.41.0",
4
4
  "description": "",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -52,20 +52,21 @@
52
52
  "@tanstack/react-store": "^0.2.1",
53
53
  "tiny-invariant": "^1.3.1",
54
54
  "tiny-warning": "^1.0.3",
55
- "@tanstack/history": "1.31.16"
55
+ "@tanstack/history": "1.41.0"
56
56
  },
57
57
  "devDependencies": {
58
- "@testing-library/react": "^15.0.2",
59
58
  "@testing-library/jest-dom": "^6.4.5",
59
+ "@testing-library/react": "^15.0.2",
60
60
  "@vitejs/plugin-react": "^4.2.1",
61
+ "combinate": "^1.1.11",
61
62
  "jsdom": "^24.0.0",
62
63
  "react": "^18.2.0",
63
64
  "react-dom": "^18.2.0",
64
65
  "zod": "^3.22.4"
65
66
  },
66
67
  "peerDependencies": {
67
- "react": ">=16.8",
68
- "react-dom": ">=16.8"
68
+ "react": ">=18",
69
+ "react-dom": ">=18"
69
70
  },
70
71
  "scripts": {}
71
72
  }
package/src/Match.tsx ADDED
@@ -0,0 +1,296 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import invariant from 'tiny-invariant'
5
+ import warning from 'tiny-warning'
6
+ import { CatchBoundary, ErrorComponent } from './CatchBoundary'
7
+ import { useRouterState } from './useRouterState'
8
+ import { useRouter } from './useRouter'
9
+ import { createControlledPromise, pick } from './utils'
10
+ import { CatchNotFound, isNotFound } from './not-found'
11
+ import { isRedirect } from './redirects'
12
+ import { type AnyRoute } from './route'
13
+ import { matchContext } from './matchContext'
14
+ import { defaultDeserializeError, isServerSideError } from './isServerSideError'
15
+ import { SafeFragment } from './SafeFragment'
16
+ import { renderRouteNotFound } from './renderRouteNotFound'
17
+ import { rootRouteId } from './root'
18
+
19
+ export function Match({ matchId }: { matchId: string }) {
20
+ const router = useRouter()
21
+ const routeId = useRouterState({
22
+ select: (s) => s.matches.find((d) => d.id === matchId)?.routeId as string,
23
+ })
24
+
25
+ invariant(
26
+ routeId,
27
+ `Could not find routeId for matchId "${matchId}". Please file an issue!`,
28
+ )
29
+
30
+ const route: AnyRoute = router.routesById[routeId]
31
+
32
+ const PendingComponent =
33
+ route.options.pendingComponent ?? router.options.defaultPendingComponent
34
+
35
+ const pendingElement = PendingComponent ? <PendingComponent /> : null
36
+
37
+ const routeErrorComponent =
38
+ route.options.errorComponent ?? router.options.defaultErrorComponent
39
+
40
+ const routeOnCatch = route.options.onCatch ?? router.options.defaultOnCatch
41
+
42
+ const routeNotFoundComponent = route.isRoot
43
+ ? // If it's the root route, use the globalNotFound option, with fallback to the notFoundRoute's component
44
+ route.options.notFoundComponent ??
45
+ router.options.notFoundRoute?.options.component
46
+ : route.options.notFoundComponent
47
+
48
+ const ResolvedSuspenseBoundary =
49
+ // If we're on the root route, allow forcefully wrapping in suspense
50
+ (!route.isRoot || route.options.wrapInSuspense) &&
51
+ (route.options.wrapInSuspense ??
52
+ PendingComponent ??
53
+ (route.options.errorComponent as any)?.preload)
54
+ ? React.Suspense
55
+ : SafeFragment
56
+
57
+ const ResolvedCatchBoundary = routeErrorComponent
58
+ ? CatchBoundary
59
+ : SafeFragment
60
+
61
+ const ResolvedNotFoundBoundary = routeNotFoundComponent
62
+ ? CatchNotFound
63
+ : SafeFragment
64
+
65
+ const resetKey = useRouterState({
66
+ select: (s) => s.resolvedLocation.state.key!,
67
+ })
68
+
69
+ return (
70
+ <matchContext.Provider value={matchId}>
71
+ <ResolvedSuspenseBoundary fallback={pendingElement}>
72
+ <ResolvedCatchBoundary
73
+ getResetKey={() => resetKey}
74
+ errorComponent={routeErrorComponent || ErrorComponent}
75
+ onCatch={(error, errorInfo) => {
76
+ // Forward not found errors (we don't want to show the error component for these)
77
+ if (isNotFound(error)) throw error
78
+ warning(false, `Error in route match: ${matchId}`)
79
+ routeOnCatch?.(error, errorInfo)
80
+ }}
81
+ >
82
+ <ResolvedNotFoundBoundary
83
+ fallback={(error) => {
84
+ // If the current not found handler doesn't exist or it has a
85
+ // route ID which doesn't match the current route, rethrow the error
86
+ if (
87
+ !routeNotFoundComponent ||
88
+ (error.routeId && error.routeId !== routeId) ||
89
+ (!error.routeId && !route.isRoot)
90
+ )
91
+ throw error
92
+
93
+ return React.createElement(routeNotFoundComponent, error as any)
94
+ }}
95
+ >
96
+ <MatchInner matchId={matchId} />
97
+ </ResolvedNotFoundBoundary>
98
+ </ResolvedCatchBoundary>
99
+ </ResolvedSuspenseBoundary>
100
+ </matchContext.Provider>
101
+ )
102
+ }
103
+ function MatchInner({ matchId }: { matchId: string }): any {
104
+ const router = useRouter()
105
+ const routeId = useRouterState({
106
+ select: (s) => s.matches.find((d) => d.id === matchId)?.routeId as string,
107
+ })
108
+
109
+ const route = router.routesById[routeId]!
110
+
111
+ const [match, matchIndex] = useRouterState({
112
+ select: (s) => {
113
+ const matchIndex = s.matches.findIndex((d) => d.id === matchId)
114
+ const match = s.matches[matchIndex]!
115
+ return [
116
+ pick(match, [
117
+ 'id',
118
+ 'status',
119
+ 'error',
120
+ 'loadPromise',
121
+ 'minPendingPromise',
122
+ ]),
123
+ matchIndex,
124
+ ] as const
125
+ },
126
+ })
127
+
128
+ const RouteErrorComponent =
129
+ (route.options.errorComponent ?? router.options.defaultErrorComponent) ||
130
+ ErrorComponent
131
+
132
+ if (match.status === 'notFound') {
133
+ let error: unknown
134
+ if (isServerSideError(match.error)) {
135
+ const deserializeError =
136
+ router.options.errorSerializer?.deserialize ?? defaultDeserializeError
137
+
138
+ error = deserializeError(match.error.data)
139
+ } else {
140
+ error = match.error
141
+ }
142
+
143
+ invariant(isNotFound(error), 'Expected a notFound error')
144
+
145
+ return renderRouteNotFound(router, route, error)
146
+ }
147
+
148
+ if (match.status === 'redirected') {
149
+ // Redirects should be handled by the router transition. If we happen to
150
+ // encounter a redirect here, it's a bug. Let's warn, but render nothing.
151
+ invariant(isRedirect(match.error), 'Expected a redirect error')
152
+
153
+ // warning(
154
+ // false,
155
+ // 'Tried to render a redirected route match! This is a weird circumstance, please file an issue!',
156
+ // )
157
+ throw match.loadPromise
158
+ }
159
+
160
+ if (match.status === 'error') {
161
+ // If we're on the server, we need to use React's new and super
162
+ // wonky api for throwing errors from a server side render inside
163
+ // of a suspense boundary. This is the only way to get
164
+ // renderToPipeableStream to not hang indefinitely.
165
+ // We'll serialize the error and rethrow it on the client.
166
+ if (router.isServer) {
167
+ return (
168
+ <RouteErrorComponent
169
+ error={match.error}
170
+ info={{
171
+ componentStack: '',
172
+ }}
173
+ />
174
+ )
175
+ }
176
+
177
+ if (isServerSideError(match.error)) {
178
+ const deserializeError =
179
+ router.options.errorSerializer?.deserialize ?? defaultDeserializeError
180
+ throw deserializeError(match.error.data)
181
+ } else {
182
+ throw match.error
183
+ }
184
+ }
185
+
186
+ if (match.status === 'pending') {
187
+ // We're pending, and if we have a minPendingMs, we need to wait for it
188
+ const pendingMinMs =
189
+ route.options.pendingMinMs ?? router.options.defaultPendingMinMs
190
+
191
+ if (pendingMinMs && !match.minPendingPromise) {
192
+ // Create a promise that will resolve after the minPendingMs
193
+ match.minPendingPromise = createControlledPromise()
194
+
195
+ if (!router.isServer) {
196
+ Promise.resolve().then(() => {
197
+ router.__store.setState((s) => ({
198
+ ...s,
199
+ matches: s.matches.map((d) =>
200
+ d.id === match.id
201
+ ? { ...d, minPendingPromise: createControlledPromise() }
202
+ : d,
203
+ ),
204
+ }))
205
+ })
206
+
207
+ setTimeout(() => {
208
+ // We've handled the minPendingPromise, so we can delete it
209
+ router.__store.setState((s) => {
210
+ return {
211
+ ...s,
212
+ matches: s.matches.map((d) =>
213
+ d.id === match.id
214
+ ? {
215
+ ...d,
216
+ minPendingPromise:
217
+ (d.minPendingPromise?.resolve(), undefined),
218
+ }
219
+ : d,
220
+ ),
221
+ }
222
+ })
223
+ }, pendingMinMs)
224
+ }
225
+ }
226
+
227
+ throw match.loadPromise
228
+ }
229
+
230
+ const Comp = route.options.component ?? router.options.defaultComponent
231
+
232
+ const out = Comp ? <Comp /> : <Outlet />
233
+
234
+ return (
235
+ <>
236
+ {router.AfterEachMatch ? (
237
+ <router.AfterEachMatch match={match} matchIndex={matchIndex} />
238
+ ) : null}
239
+ {out}
240
+ </>
241
+ )
242
+ }
243
+
244
+ export const Outlet = React.memo(function Outlet() {
245
+ const router = useRouter()
246
+ const matchId = React.useContext(matchContext)
247
+ const routeId = useRouterState({
248
+ select: (s) => s.matches.find((d) => d.id === matchId)?.routeId as string,
249
+ })
250
+
251
+ const route = router.routesById[routeId]!
252
+
253
+ const { parentGlobalNotFound } = useRouterState({
254
+ select: (s) => {
255
+ const matches = s.matches
256
+ const parentMatch = matches.find((d) => d.id === matchId)
257
+ invariant(
258
+ parentMatch,
259
+ `Could not find parent match for matchId "${matchId}"`,
260
+ )
261
+ return {
262
+ parentGlobalNotFound: parentMatch.globalNotFound,
263
+ }
264
+ },
265
+ })
266
+
267
+ const childMatchId = useRouterState({
268
+ select: (s) => {
269
+ const matches = s.matches
270
+ const index = matches.findIndex((d) => d.id === matchId)
271
+ return matches[index + 1]?.id
272
+ },
273
+ })
274
+
275
+ if (parentGlobalNotFound) {
276
+ return renderRouteNotFound(router, route, undefined)
277
+ }
278
+
279
+ if (!childMatchId) {
280
+ return null
281
+ }
282
+
283
+ const nextMatch = <Match matchId={childMatchId} />
284
+
285
+ const pendingElement = router.options.defaultPendingComponent ? (
286
+ <router.options.defaultPendingComponent />
287
+ ) : null
288
+
289
+ if (matchId === rootRouteId) {
290
+ return (
291
+ <React.Suspense fallback={pendingElement}>{nextMatch}</React.Suspense>
292
+ )
293
+ }
294
+
295
+ return nextMatch
296
+ })