@tanstack/react-router 1.31.28 → 1.32.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":"utils.cjs","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 UnionToIntersection<T> = (\n T extends any ? (k: T) => void : never\n) extends (k: infer I) => any\n ? I\n : never\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 : 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\n// from https://github.com/type-challenges/type-challenges/issues/737\ntype LastInUnion<T> =\n UnionToIntersection<T extends unknown ? (x: T) => 0 : never> extends (\n x: infer L,\n ) => 0\n ? L\n : never\nexport type UnionToTuple<T, TLast = LastInUnion<T>> = [T] extends [never]\n ? []\n : [...UnionToTuple<Exclude<T, TLast>>, TLast]\n\n//\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<TFrom, TReturnIntersection extends boolean = false> =\n | {\n from: StringLiteral<TFrom> | TFrom\n strict?: true\n }\n | {\n from?: never\n strict: false\n experimental_returnIntersection?: TReturnIntersection\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 function removeTrailingSlash(value: string): string {\n if (value.endsWith('/') && value !== '/') {\n return value.slice(0, -1)\n }\n return value\n}\n\n// intended to only compare path name\n// see the usage in the isActive under useLinkProps\n// /sample/path1 = /sample/path1/\n// /sample/path1/some <> /sample/path1\nexport function exactPathTest(pathName1: string, pathName2: string): boolean {\n return removeTrailingSlash(pathName1) === removeTrailingSlash(pathName2)\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 * Removes all segments from a given path that start with an underscore ('_').\n *\n * @param {string} routePath - The path from which to remove segments. Defaults to '/'.\n * @returns {string} The path with all underscore-prefixed segments removed.\n * @example\n * removeLayoutSegments('/workspace/_auth/foo') // '/workspace/foo'\n */\nexport function removeLayoutSegments(routePath: string): string {\n const segments = routePath.split('/')\n const newSegments = segments.filter((segment) => !segment.startsWith('_'))\n return newSegments.join('/')\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":["React"],"mappings":"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"}
1
+ {"version":3,"file":"utils.cjs","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 UnionToIntersection<T> = (\n T extends any ? (k: T) => void : never\n) extends (k: infer I) => any\n ? I\n : never\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 : 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\n// from https://github.com/type-challenges/type-challenges/issues/737\ntype LastInUnion<T> =\n UnionToIntersection<T extends unknown ? (x: T) => 0 : never> extends (\n x: infer L,\n ) => 0\n ? L\n : never\nexport type UnionToTuple<T, TLast = LastInUnion<T>> = [T] extends [never]\n ? []\n : [...UnionToTuple<Exclude<T, TLast>>, TLast]\n\n//\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<TFrom, TReturnIntersection extends boolean = false> =\n | {\n from: StringLiteral<TFrom> | TFrom\n strict?: true\n }\n | {\n from?: never\n strict: false\n experimental_returnIntersection?: TReturnIntersection\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 function removeTrailingSlash(value: string): string {\n if (value.endsWith('/') && value !== '/') {\n return value.slice(0, -1)\n }\n return value\n}\n\n// intended to only compare path name\n// see the usage in the isActive under useLinkProps\n// /sample/path1 = /sample/path1/\n// /sample/path1/some <> /sample/path1\nexport function exactPathTest(pathName1: string, pathName2: string): boolean {\n return removeTrailingSlash(pathName1) === removeTrailingSlash(pathName2)\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":["React"],"mappings":"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"}
@@ -61,15 +61,6 @@ export type ControlledPromise<T> = Promise<T> & {
61
61
  status: 'pending' | 'resolved' | 'rejected';
62
62
  };
63
63
  export declare function createControlledPromise<T>(onResolve?: () => void): ControlledPromise<T>;
64
- /**
65
- * Removes all segments from a given path that start with an underscore ('_').
66
- *
67
- * @param {string} routePath - The path from which to remove segments. Defaults to '/'.
68
- * @returns {string} The path with all underscore-prefixed segments removed.
69
- * @example
70
- * removeLayoutSegments('/workspace/_auth/foo') // '/workspace/foo'
71
- */
72
- export declare function removeLayoutSegments(routePath: string): string;
73
64
  /**
74
65
  * Taken from https://www.developerway.com/posts/implementing-advanced-use-previous-hook#part3
75
66
  */
@@ -27,6 +27,7 @@ export { getRouterContext, } from './routerContext.js';
27
27
  export { useRouteContext } from './useRouteContext.js';
28
28
  export { useRouter } from './useRouter.js';
29
29
  export { useRouterState } from './useRouterState.js';
30
+ export { useLocation } from './useLocation.js';
30
31
  export { escapeJSON, // SSR
31
32
  useLayoutEffect, // SSR
32
33
  pick, functionalUpdate, replaceEqualDeep, isPlainObject, isPlainArray, deepEqual, useStableCallback, shallow, } from './utils';
package/dist/esm/index.js CHANGED
@@ -24,6 +24,7 @@ import { getRouterContext } from "./routerContext.js";
24
24
  import { useRouteContext } from "./useRouteContext.js";
25
25
  import { useRouter } from "./useRouter.js";
26
26
  import { useRouterState } from "./useRouterState.js";
27
+ import { useLocation } from "./useLocation.js";
27
28
  import { deepEqual, escapeJSON, functionalUpdate, isPlainArray, isPlainObject, pick, replaceEqualDeep, shallow, useLayoutEffect, useStableCallback } from "./utils.js";
28
29
  import { CatchNotFound, DefaultGlobalNotFound, isNotFound, notFound } from "./not-found.js";
29
30
  export {
@@ -118,6 +119,7 @@ export {
118
119
  useLinkProps,
119
120
  useLoaderData,
120
121
  useLoaderDeps,
122
+ useLocation,
121
123
  useMatch,
122
124
  useMatchRoute,
123
125
  useMatches,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -4,7 +4,7 @@ import invariant from "tiny-invariant";
4
4
  import warning from "tiny-warning";
5
5
  import { rootRouteId } from "./route.js";
6
6
  import { defaultStringifySearch, defaultParseSearch } from "./searchParams.js";
7
- import { createControlledPromise, replaceEqualDeep, pick, last, deepEqual, escapeJSON, removeLayoutSegments, functionalUpdate } from "./utils.js";
7
+ import { createControlledPromise, replaceEqualDeep, pick, last, deepEqual, escapeJSON, functionalUpdate } from "./utils.js";
8
8
  import { getRouteMatch } from "./RouterProvider.js";
9
9
  import { trimPath, trimPathLeft, parsePathname, resolvePath, cleanPath, matchPathname, trimPathRight, interpolatePath, joinPaths } from "./path.js";
10
10
  import { isResolvedRedirect, isRedirect } from "./redirects.js";
@@ -398,7 +398,7 @@ class Router {
398
398
  };
399
399
  this.buildLocation = (opts) => {
400
400
  const build = (dest = {}, matches) => {
401
- var _a, _b, _c;
401
+ var _a, _b, _c, _d;
402
402
  let fromPath = this.latestLocation.pathname;
403
403
  let fromSearch = dest.fromSearch || this.latestLocation.search;
404
404
  const fromMatches = this.matchRoutes(
@@ -410,14 +410,12 @@ class Router {
410
410
  const stayingMatches = matches == null ? void 0 : matches.filter(
411
411
  (d) => fromMatches.find((e) => e.routeId === d.routeId)
412
412
  );
413
- const fromRouteByFromPath = stayingMatches == null ? void 0 : stayingMatches.find(
414
- (d) => d.pathname === fromPath
415
- );
413
+ const fromRouteByFromPathRouteId = this.routesById[(_c = stayingMatches == null ? void 0 : stayingMatches.find((d) => d.pathname === fromPath)) == null ? void 0 : _c.routeId];
416
414
  let pathname = dest.to ? this.resolvePathWithBase(fromPath, `${dest.to}`) : this.resolvePathWithBase(
417
415
  fromPath,
418
- fromRouteByFromPath ? removeLayoutSegments(fromRouteByFromPath.routeId) : fromPath
416
+ (fromRouteByFromPathRouteId == null ? void 0 : fromRouteByFromPathRouteId.to) ?? fromPath
419
417
  );
420
- const prevParams = { ...(_c = last(fromMatches)) == null ? void 0 : _c.params };
418
+ const prevParams = { ...(_d = last(fromMatches)) == null ? void 0 : _d.params };
421
419
  let nextParams = (dest.params ?? true) === true ? prevParams : { ...prevParams, ...functionalUpdate(dest.params, prevParams) };
422
420
  if (Object.keys(nextParams).length > 0) {
423
421
  matches == null ? void 0 : matches.map((d) => this.looseRoutesById[d.routeId].options.stringifyParams).filter(Boolean).forEach((fn) => {