@tanstack/solid-router 2.0.0-alpha.4 → 2.0.0-alpha.6
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.
- package/bin/intent.js +25 -0
- package/dist/cjs/Transitioner.cjs +2 -2
- package/dist/cjs/Transitioner.cjs.map +1 -1
- package/dist/cjs/useBlocker.cjs +1 -1
- package/dist/cjs/useBlocker.cjs.map +1 -1
- package/dist/esm/Transitioner.js +2 -2
- package/dist/esm/Transitioner.js.map +1 -1
- package/dist/esm/useBlocker.js +1 -1
- package/dist/esm/useBlocker.js.map +1 -1
- package/dist/source/Transitioner.jsx +2 -2
- package/dist/source/Transitioner.jsx.map +1 -1
- package/dist/source/useBlocker.jsx +1 -1
- package/dist/source/useBlocker.jsx.map +1 -1
- package/package.json +16 -9
- package/skills/solid-router/SKILL.md +497 -0
- package/src/Transitioner.tsx +2 -2
- package/src/useBlocker.tsx +1 -1
package/bin/intent.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Auto-generated by @tanstack/intent setup
|
|
3
|
+
// Exposes the intent end-user CLI for consumers of this library.
|
|
4
|
+
// Commit this file, then add to your package.json:
|
|
5
|
+
// "bin": { "intent": "./bin/intent.js" }
|
|
6
|
+
try {
|
|
7
|
+
await import('@tanstack/intent/intent-library')
|
|
8
|
+
} catch (e) {
|
|
9
|
+
const isModuleNotFound =
|
|
10
|
+
e?.code === 'ERR_MODULE_NOT_FOUND' || e?.code === 'MODULE_NOT_FOUND'
|
|
11
|
+
const missingIntentLibrary =
|
|
12
|
+
typeof e?.message === 'string' && e.message.includes('@tanstack/intent')
|
|
13
|
+
|
|
14
|
+
if (isModuleNotFound && missingIntentLibrary) {
|
|
15
|
+
console.error('@tanstack/intent is not installed.')
|
|
16
|
+
console.error('')
|
|
17
|
+
console.error('Install it as a dev dependency:')
|
|
18
|
+
console.error(' npm add -D @tanstack/intent')
|
|
19
|
+
console.error('')
|
|
20
|
+
console.error('Or run directly:')
|
|
21
|
+
console.error(' npx @tanstack/intent@latest list')
|
|
22
|
+
process.exit(1)
|
|
23
|
+
}
|
|
24
|
+
throw e
|
|
25
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Transitioner.cjs","names":["Solid","getLocationChangeInfo","handleHashScroll","trimPathRight","useRouter","useRouterState","usePrevious","Transitioner","router","mountLoadForRouter","mounted","isLoading","select","isSolidTransitioning","hasPendingMatches","s","matches","some","d","status","previousIsLoading","isAnyPending","previousIsAnyPending","isPagePending","previousIsPagePending","startTransition","fn","Promise","runWithOwner","onSettled","unsub","history","subscribe","load","updateLatestLocation","nextLocation","buildLocation","to","latestLocation","pathname","search","params","hash","state","_includeValidateSearch","publicHref","commitLocation","replace","
|
|
1
|
+
{"version":3,"file":"Transitioner.cjs","names":["Solid","getLocationChangeInfo","handleHashScroll","trimPathRight","useRouter","useRouterState","usePrevious","Transitioner","router","mountLoadForRouter","mounted","isLoading","select","isSolidTransitioning","hasPendingMatches","s","matches","some","d","status","previousIsLoading","isAnyPending","previousIsAnyPending","isPagePending","previousIsPagePending","startTransition","fn","Promise","runWithOwner","onSettled","unsub","history","subscribe","load","updateLatestLocation","nextLocation","buildLocation","to","latestLocation","pathname","search","params","hash","state","_includeValidateSearch","publicHref","commitLocation","replace","createTrackedEffect","untrack","window","ssr","tryLoad","err","console","error","createEffect","const","previous","emit","type","changeInfo","__store","setState","resolvedLocation","location","hrefChanged"],"sources":["../../src/Transitioner.tsx"],"sourcesContent":["import * as Solid from 'solid-js'\nimport {\n getLocationChangeInfo,\n handleHashScroll,\n trimPathRight,\n} from '@tanstack/router-core'\nimport { useRouter } from './useRouter'\nimport { useRouterState } from './useRouterState'\nimport { usePrevious } from './utils'\n\nexport function Transitioner() {\n const router = useRouter()\n let mountLoadForRouter = { router, mounted: false }\n const isLoading = useRouterState({\n select: ({ isLoading }) => isLoading,\n })\n\n const [isSolidTransitioning] = [() => false]\n\n // Track pending state changes\n const hasPendingMatches = useRouterState({\n select: (s) => s.matches.some((d) => d.status === 'pending'),\n })\n\n const previousIsLoading = usePrevious(isLoading)\n\n const isAnyPending = () =>\n isLoading() || isSolidTransitioning() || hasPendingMatches()\n const previousIsAnyPending = usePrevious(isAnyPending)\n\n const isPagePending = () => isLoading() || hasPendingMatches()\n const previousIsPagePending = usePrevious(isPagePending)\n\n router.startTransition = (fn: () => void | Promise<void>) => {\n Solid.runWithOwner(null, fn)\n }\n\n // Subscribe to location changes\n // and try to load the new location\n Solid.onSettled(() => {\n const unsub = router.history.subscribe(router.load)\n\n // Refresh latestLocation from the current browser URL before comparing.\n // The URL may have been changed synchronously (e.g. via replaceState) after\n // render() but before this effect ran, so we must not use the stale\n // render-time location here.\n router.updateLatestLocation()\n\n const nextLocation = router.buildLocation({\n to: router.latestLocation.pathname,\n search: true,\n params: true,\n hash: true,\n state: true,\n _includeValidateSearch: true,\n })\n\n // Check if the current URL matches the canonical form.\n // Compare publicHref (browser-facing URL) for consistency with\n // the server-side redirect check in router.beforeLoad.\n if (\n trimPathRight(router.latestLocation.publicHref) !==\n trimPathRight(nextLocation.publicHref)\n ) {\n router.commitLocation({ ...nextLocation, replace: true })\n }\n\n return () => {\n unsub()\n }\n })\n\n // Try to load the initial location\n Solid.createTrackedEffect(() => {\n Solid.untrack(() => {\n if (\n // if we are hydrating from SSR, loading is triggered in ssr-client\n (typeof window !== 'undefined' && router.ssr) ||\n (mountLoadForRouter.router === router && mountLoadForRouter.mounted)\n ) {\n return\n }\n mountLoadForRouter = { router, mounted: true }\n const tryLoad = async () => {\n try {\n await router.load()\n } catch (err) {\n console.error(err)\n }\n }\n tryLoad()\n })\n })\n\n Solid.createEffect(\n () => [previousIsLoading(), isLoading()] as const,\n ([previousIsLoading, isLoading]) => {\n if (previousIsLoading.previous && !isLoading) {\n router.emit({\n type: 'onLoad',\n ...getLocationChangeInfo(router.state),\n })\n }\n },\n )\n\n Solid.createEffect(\n () => [isPagePending(), previousIsPagePending()] as const,\n ([isPagePending, previousIsPagePending]) => {\n // emit onBeforeRouteMount\n if (previousIsPagePending.previous && !isPagePending) {\n router.emit({\n type: 'onBeforeRouteMount',\n ...getLocationChangeInfo(router.state),\n })\n }\n },\n )\n\n Solid.createEffect(\n () => [isAnyPending(), previousIsAnyPending()] as const,\n ([isAnyPending, previousIsAnyPending]) => {\n if (previousIsAnyPending.previous && !isAnyPending) {\n const changeInfo = getLocationChangeInfo(router.state)\n router.emit({\n type: 'onResolved',\n ...changeInfo,\n })\n\n router.__store.setState((s) => ({\n ...s,\n status: 'idle',\n resolvedLocation: s.location,\n }))\n\n if (changeInfo.hrefChanged) {\n handleHashScroll(router)\n }\n }\n },\n )\n\n return null\n}\n"],"mappings":";;;;;;;;AAUA,SAAgBO,eAAe;CAC7B,MAAMC,SAASJ,kBAAAA,WAAW;CAC1B,IAAIK,qBAAqB;EAAED;EAAQE,SAAS;EAAO;CACnD,MAAMC,YAAYN,uBAAAA,eAAe,EAC/BO,SAAS,EAAED,gBAAgBA,WAC5B,CAAC;CAEF,MAAM,CAACE,wBAAwB,OAAO,MAAM;CAG5C,MAAMC,oBAAoBT,uBAAAA,eAAe,EACvCO,SAASG,MAAMA,EAAEC,QAAQC,MAAMC,MAAMA,EAAEC,WAAW,UAAS,EAC5D,CAAC;CAEF,MAAMC,oBAAoBd,cAAAA,YAAYK,UAAU;CAEhD,MAAMU,qBACJV,WAAW,IAAIE,sBAAsB,IAAIC,mBAAmB;CAC9D,MAAMQ,uBAAuBhB,cAAAA,YAAYe,aAAa;CAEtD,MAAME,sBAAsBZ,WAAW,IAAIG,mBAAmB;CAC9D,MAAMU,wBAAwBlB,cAAAA,YAAYiB,cAAc;AAExDf,QAAOiB,mBAAmBC,OAAmC;AAC3D1B,WAAM4B,aAAa,MAAMF,GAAG;;AAK9B1B,UAAM6B,gBAAgB;EACpB,MAAMC,QAAQtB,OAAOuB,QAAQC,UAAUxB,OAAOyB,KAAK;AAMnDzB,SAAO0B,sBAAsB;EAE7B,MAAMC,eAAe3B,OAAO4B,cAAc;GACxCC,IAAI7B,OAAO8B,eAAeC;GAC1BC,QAAQ;GACRC,QAAQ;GACRC,MAAM;GACNC,OAAO;GACPC,wBAAwB;GACzB,CAAC;AAKF,OAAA,GAAA,sBAAA,eACgBpC,OAAO8B,eAAeO,WAAW,MAAA,GAAA,sBAAA,eACjCV,aAAaU,WAAW,CAEtCrC,QAAOsC,eAAe;GAAE,GAAGX;GAAcY,SAAS;GAAM,CAAC;AAG3D,eAAa;AACXjB,UAAO;;GAET;AAGF9B,UAAMgD,0BAA0B;AAC9BhD,WAAMiD,cAAc;AAClB,OAEG,OAAOC,WAAW,eAAe1C,OAAO2C,OACxC1C,mBAAmBD,WAAWA,UAAUC,mBAAmBC,QAE5D;AAEFD,wBAAqB;IAAED;IAAQE,SAAS;IAAM;GAC9C,MAAM0C,UAAU,YAAY;AAC1B,QAAI;AACF,WAAM5C,OAAOyB,MAAM;aACZoB,KAAK;AACZC,aAAQC,MAAMF,IAAI;;;AAGtBD,YAAS;IACT;GACF;AAEFpD,UAAMwD,mBACE,CAACpC,mBAAmB,EAAET,WAAW,CAAC,GACvC,CAACS,mBAAmBT,eAAe;AAClC,MAAIS,kBAAkBsC,YAAY,CAAC/C,UACjCH,QAAOmD,KAAK;GACVC,MAAM;GACN,IAAA,GAAA,sBAAA,uBAAyBpD,OAAOmC,MAAK;GACtC,CAAC;GAGP;AAED3C,UAAMwD,mBACE,CAACjC,eAAe,EAAEC,uBAAuB,CAAC,GAC/C,CAACD,eAAeC,2BAA2B;AAE1C,MAAIA,sBAAsBkC,YAAY,CAACnC,cACrCf,QAAOmD,KAAK;GACVC,MAAM;GACN,IAAA,GAAA,sBAAA,uBAAyBpD,OAAOmC,MAAK;GACtC,CAAC;GAGP;AAED3C,UAAMwD,mBACE,CAACnC,cAAc,EAAEC,sBAAsB,CAAC,GAC7C,CAACD,cAAcC,0BAA0B;AACxC,MAAIA,qBAAqBoC,YAAY,CAACrC,cAAc;GAClD,MAAMwC,cAAAA,GAAAA,sBAAAA,uBAAmCrD,OAAOmC,MAAM;AACtDnC,UAAOmD,KAAK;IACVC,MAAM;IACN,GAAGC;IACJ,CAAC;AAEFrD,UAAOsD,QAAQC,UAAUhD,OAAO;IAC9B,GAAGA;IACHI,QAAQ;IACR6C,kBAAkBjD,EAAEkD;IACrB,EAAE;AAEH,OAAIJ,WAAWK,YACbhE,EAAAA,GAAAA,sBAAAA,kBAAiBM,OAAO;;GAI/B;AAED,QAAO"}
|
package/dist/cjs/useBlocker.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBlocker.cjs","names":["Solid","useRouter","BlockerFnArgs","HistoryAction","HistoryLocation","SolidNode","AnyRoute","AnyRouter","ParseRoute","RegisteredRouter","ShouldBlockFnLocation","routeId","TRouteId","fullPath","TFullPath","pathname","params","TAllParams","search","TFullSearchSchema","AnyShouldBlockFnLocation","MakeShouldBlockFnLocationUnion","TRouter","TRoute","BlockerResolver","status","current","next","action","proceed","reset","ShouldBlockFnArgs","ShouldBlockFn","args","Promise","UseBlockerOpts","shouldBlockFn","enableBeforeUnload","disabled","withResolver","TWithResolver","LegacyBlockerFn","LegacyBlockerOpts","blockerFn","condition","_resolveBlockerOpts","opts","undefined","shouldBlock","Boolean","_customBlockerFn","createMemo","useBlocker","Accessor","blockerFnOrOpts","props","merge","router","resolver","setResolver","createSignal","createTrackedEffect","blockerFnComposed","blockerFnArgs","getLocation","location","parsedLocation","parseLocation","matchedRoutes","getMatchedRoutes","foundRoute","routeParams","id","currentLocation","nextLocation","promise","resolve","canNavigateAsync","disposeBlock","history","block","onCleanup","_resolvePromptBlockerArgs","PromptProps","LegacyPromptProps","BlockComponent","Block","propsWithChildren","children","child","_$memo","TParams"],"sources":["../../src/useBlocker.tsx"],"sourcesContent":["import * as Solid from 'solid-js'\nimport { useRouter } from './useRouter'\nimport type {\n BlockerFnArgs,\n HistoryAction,\n HistoryLocation,\n} from '@tanstack/history'\nimport type { SolidNode } from './route'\nimport type {\n AnyRoute,\n AnyRouter,\n ParseRoute,\n RegisteredRouter,\n} from '@tanstack/router-core'\n\ninterface ShouldBlockFnLocation<\n out TRouteId,\n out TFullPath,\n out TAllParams,\n out TFullSearchSchema,\n> {\n routeId: TRouteId\n fullPath: TFullPath\n pathname: string\n params: TAllParams\n search: TFullSearchSchema\n}\n\ntype AnyShouldBlockFnLocation = ShouldBlockFnLocation<any, any, any, any>\ntype MakeShouldBlockFnLocationUnion<\n TRouter extends AnyRouter = RegisteredRouter,\n TRoute extends AnyRoute = ParseRoute<TRouter['routeTree']>,\n> = TRoute extends any\n ? ShouldBlockFnLocation<\n TRoute['id'],\n TRoute['fullPath'],\n TRoute['types']['allParams'],\n TRoute['types']['fullSearchSchema']\n >\n : never\n\ntype BlockerResolver<TRouter extends AnyRouter = RegisteredRouter> =\n | {\n status: 'blocked'\n current: MakeShouldBlockFnLocationUnion<TRouter>\n next: MakeShouldBlockFnLocationUnion<TRouter>\n action: HistoryAction\n proceed: () => void\n reset: () => void\n }\n | {\n status: 'idle'\n current: undefined\n next: undefined\n action: undefined\n proceed: undefined\n reset: undefined\n }\n\ntype ShouldBlockFnArgs<TRouter extends AnyRouter = RegisteredRouter> = {\n current: MakeShouldBlockFnLocationUnion<TRouter>\n next: MakeShouldBlockFnLocationUnion<TRouter>\n action: HistoryAction\n}\n\nexport type ShouldBlockFn<TRouter extends AnyRouter = RegisteredRouter> = (\n args: ShouldBlockFnArgs<TRouter>,\n) => boolean | Promise<boolean>\nexport type UseBlockerOpts<\n TRouter extends AnyRouter = RegisteredRouter,\n TWithResolver extends boolean = boolean,\n> = {\n shouldBlockFn: ShouldBlockFn<TRouter>\n enableBeforeUnload?: boolean | (() => boolean)\n disabled?: boolean\n withResolver?: TWithResolver\n}\n\ntype LegacyBlockerFn = () => Promise<any> | any\ntype LegacyBlockerOpts = {\n blockerFn?: LegacyBlockerFn\n condition?: boolean | any\n}\n\nfunction _resolveBlockerOpts(\n opts?: UseBlockerOpts | LegacyBlockerOpts | LegacyBlockerFn,\n condition?: boolean | any,\n): UseBlockerOpts {\n if (opts === undefined) {\n return {\n shouldBlockFn: () => true,\n withResolver: false,\n }\n }\n\n if ('shouldBlockFn' in opts) {\n return opts\n }\n\n if (typeof opts === 'function') {\n const shouldBlock = Boolean(condition ?? true)\n\n const _customBlockerFn = async () => {\n if (shouldBlock) return await opts()\n return false\n }\n\n return {\n shouldBlockFn: _customBlockerFn,\n enableBeforeUnload: shouldBlock,\n withResolver: false,\n }\n }\n\n const shouldBlock = Solid.createMemo(() => Boolean(opts.condition ?? true))\n\n const _customBlockerFn = async () => {\n if (shouldBlock() && opts.blockerFn !== undefined) {\n return await opts.blockerFn()\n }\n return shouldBlock()\n }\n\n return {\n get shouldBlockFn() {\n return _customBlockerFn\n },\n get enableBeforeUnload() {\n return shouldBlock()\n },\n get withResolver() {\n return opts.blockerFn === undefined\n },\n }\n}\n\nexport function useBlocker<\n TRouter extends AnyRouter = RegisteredRouter,\n TWithResolver extends boolean = false,\n>(\n opts: UseBlockerOpts<TRouter, TWithResolver>,\n): TWithResolver extends true ? Solid.Accessor<BlockerResolver<TRouter>> : void\n\n/**\n * @deprecated Use the shouldBlockFn property instead\n */\nexport function useBlocker(\n blockerFnOrOpts?: LegacyBlockerOpts,\n): Solid.Accessor<BlockerResolver>\n\n/**\n * @deprecated Use the UseBlockerOpts object syntax instead\n */\nexport function useBlocker(\n blockerFn?: LegacyBlockerFn,\n condition?: boolean | any,\n): Solid.Accessor<BlockerResolver>\n\nexport function useBlocker(\n opts?: UseBlockerOpts | LegacyBlockerOpts | LegacyBlockerFn,\n condition?: boolean | any,\n): Solid.Accessor<BlockerResolver> | void {\n const props = Solid.merge(\n {\n enableBeforeUnload: true,\n disabled: false,\n withResolver: false,\n },\n _resolveBlockerOpts(opts, condition),\n )\n\n const router = useRouter()\n\n const [resolver, setResolver] = Solid.createSignal<BlockerResolver>({\n status: 'idle',\n current: undefined,\n next: undefined,\n action: undefined,\n proceed: undefined,\n reset: undefined,\n })\n\n Solid.createTrackedEffect(() => {\n const blockerFnComposed = async (blockerFnArgs: BlockerFnArgs) => {\n function getLocation(\n location: HistoryLocation,\n ): AnyShouldBlockFnLocation {\n const parsedLocation = router.parseLocation(location)\n const matchedRoutes = router.getMatchedRoutes(parsedLocation.pathname)\n if (matchedRoutes.foundRoute === undefined) {\n return {\n routeId: '__notFound__',\n fullPath: parsedLocation.pathname,\n pathname: parsedLocation.pathname,\n params: matchedRoutes.routeParams,\n search: parsedLocation.search,\n }\n }\n return {\n routeId: matchedRoutes.foundRoute.id,\n fullPath: matchedRoutes.foundRoute.fullPath,\n pathname: parsedLocation.pathname,\n params: matchedRoutes.routeParams,\n search: parsedLocation.search,\n }\n }\n\n const current = getLocation(blockerFnArgs.currentLocation)\n const next = getLocation(blockerFnArgs.nextLocation)\n\n if (\n current.routeId === '__notFound__' &&\n next.routeId !== '__notFound__'\n ) {\n return false\n }\n\n const shouldBlock = await props.shouldBlockFn({\n action: blockerFnArgs.action,\n current,\n next,\n })\n if (!props.withResolver) {\n return shouldBlock\n }\n\n if (!shouldBlock) {\n return false\n }\n\n const promise = new Promise<boolean>((resolve) => {\n setResolver({\n status: 'blocked',\n current,\n next,\n action: blockerFnArgs.action,\n proceed: () => resolve(false),\n reset: () => resolve(true),\n })\n })\n\n const canNavigateAsync = await promise\n setResolver({\n status: 'idle',\n current: undefined,\n next: undefined,\n action: undefined,\n proceed: undefined,\n reset: undefined,\n })\n\n return canNavigateAsync\n }\n\n const disposeBlock = props.disabled\n ? undefined\n : router.history.block({\n blockerFn: blockerFnComposed,\n enableBeforeUnload: props.enableBeforeUnload,\n })\n\n Solid.onCleanup(() => disposeBlock?.())\n })\n\n return resolver\n}\n\nconst _resolvePromptBlockerArgs = (\n props: PromptProps | LegacyPromptProps,\n): UseBlockerOpts => {\n if ('shouldBlockFn' in props) {\n return props\n }\n\n const shouldBlock = Solid.createMemo(() => Boolean(props.condition ?? true))\n\n const _customBlockerFn = async () => {\n if (shouldBlock() && props.blockerFn !== undefined) {\n return await props.blockerFn()\n }\n return shouldBlock\n }\n\n return {\n shouldBlockFn: _customBlockerFn,\n get enableBeforeUnload() {\n return shouldBlock()\n },\n get withResolver() {\n return props.blockerFn === undefined\n },\n }\n}\n\ninterface BlockComponent {\n <\n TRouter extends AnyRouter = RegisteredRouter,\n TWithResolver extends boolean = boolean,\n >(\n opts: PromptProps<TRouter, TWithResolver>,\n ): SolidNode\n /**\n * @deprecated Use the UseBlockerOpts property instead\n */\n (opts: LegacyPromptProps): SolidNode\n}\n\nexport const Block: BlockComponent = function Block(\n opts: PromptProps | LegacyPromptProps,\n): SolidNode {\n const propsWithChildren = {\n get children() {\n return opts.children\n },\n }\n const args = _resolvePromptBlockerArgs(opts)\n\n const resolver = useBlocker(args)\n const children = Solid.createMemo(() => {\n const child = propsWithChildren.children\n if (resolver && typeof child === 'function') return child(resolver())\n return child\n })\n\n return <>{children()}</>\n}\n\ntype LegacyPromptProps = {\n blockerFn?: LegacyBlockerFn\n condition?: boolean | any\n children?: SolidNode | ((params: BlockerResolver) => SolidNode)\n}\n\ntype PromptProps<\n TRouter extends AnyRouter = RegisteredRouter,\n TWithResolver extends boolean = boolean,\n TParams = TWithResolver extends true ? BlockerResolver<TRouter> : void,\n> = UseBlockerOpts<TRouter, TWithResolver> & {\n children?: SolidNode | ((params: TParams) => SolidNode)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useBlocker.cjs","names":["Solid","useRouter","BlockerFnArgs","HistoryAction","HistoryLocation","SolidNode","AnyRoute","AnyRouter","ParseRoute","RegisteredRouter","ShouldBlockFnLocation","routeId","TRouteId","fullPath","TFullPath","pathname","params","TAllParams","search","TFullSearchSchema","AnyShouldBlockFnLocation","MakeShouldBlockFnLocationUnion","TRouter","TRoute","BlockerResolver","status","current","next","action","proceed","reset","ShouldBlockFnArgs","ShouldBlockFn","args","Promise","UseBlockerOpts","shouldBlockFn","enableBeforeUnload","disabled","withResolver","TWithResolver","LegacyBlockerFn","LegacyBlockerOpts","blockerFn","condition","_resolveBlockerOpts","opts","undefined","shouldBlock","Boolean","_customBlockerFn","createMemo","useBlocker","Accessor","blockerFnOrOpts","props","merge","router","resolver","setResolver","createSignal","createTrackedEffect","blockerFnComposed","blockerFnArgs","getLocation","location","parsedLocation","parseLocation","matchedRoutes","getMatchedRoutes","foundRoute","routeParams","id","currentLocation","nextLocation","promise","resolve","canNavigateAsync","disposeBlock","history","block","_resolvePromptBlockerArgs","PromptProps","LegacyPromptProps","BlockComponent","Block","propsWithChildren","children","child","_$memo","TParams"],"sources":["../../src/useBlocker.tsx"],"sourcesContent":["import * as Solid from 'solid-js'\nimport { useRouter } from './useRouter'\nimport type {\n BlockerFnArgs,\n HistoryAction,\n HistoryLocation,\n} from '@tanstack/history'\nimport type { SolidNode } from './route'\nimport type {\n AnyRoute,\n AnyRouter,\n ParseRoute,\n RegisteredRouter,\n} from '@tanstack/router-core'\n\ninterface ShouldBlockFnLocation<\n out TRouteId,\n out TFullPath,\n out TAllParams,\n out TFullSearchSchema,\n> {\n routeId: TRouteId\n fullPath: TFullPath\n pathname: string\n params: TAllParams\n search: TFullSearchSchema\n}\n\ntype AnyShouldBlockFnLocation = ShouldBlockFnLocation<any, any, any, any>\ntype MakeShouldBlockFnLocationUnion<\n TRouter extends AnyRouter = RegisteredRouter,\n TRoute extends AnyRoute = ParseRoute<TRouter['routeTree']>,\n> = TRoute extends any\n ? ShouldBlockFnLocation<\n TRoute['id'],\n TRoute['fullPath'],\n TRoute['types']['allParams'],\n TRoute['types']['fullSearchSchema']\n >\n : never\n\ntype BlockerResolver<TRouter extends AnyRouter = RegisteredRouter> =\n | {\n status: 'blocked'\n current: MakeShouldBlockFnLocationUnion<TRouter>\n next: MakeShouldBlockFnLocationUnion<TRouter>\n action: HistoryAction\n proceed: () => void\n reset: () => void\n }\n | {\n status: 'idle'\n current: undefined\n next: undefined\n action: undefined\n proceed: undefined\n reset: undefined\n }\n\ntype ShouldBlockFnArgs<TRouter extends AnyRouter = RegisteredRouter> = {\n current: MakeShouldBlockFnLocationUnion<TRouter>\n next: MakeShouldBlockFnLocationUnion<TRouter>\n action: HistoryAction\n}\n\nexport type ShouldBlockFn<TRouter extends AnyRouter = RegisteredRouter> = (\n args: ShouldBlockFnArgs<TRouter>,\n) => boolean | Promise<boolean>\nexport type UseBlockerOpts<\n TRouter extends AnyRouter = RegisteredRouter,\n TWithResolver extends boolean = boolean,\n> = {\n shouldBlockFn: ShouldBlockFn<TRouter>\n enableBeforeUnload?: boolean | (() => boolean)\n disabled?: boolean\n withResolver?: TWithResolver\n}\n\ntype LegacyBlockerFn = () => Promise<any> | any\ntype LegacyBlockerOpts = {\n blockerFn?: LegacyBlockerFn\n condition?: boolean | any\n}\n\nfunction _resolveBlockerOpts(\n opts?: UseBlockerOpts | LegacyBlockerOpts | LegacyBlockerFn,\n condition?: boolean | any,\n): UseBlockerOpts {\n if (opts === undefined) {\n return {\n shouldBlockFn: () => true,\n withResolver: false,\n }\n }\n\n if ('shouldBlockFn' in opts) {\n return opts\n }\n\n if (typeof opts === 'function') {\n const shouldBlock = Boolean(condition ?? true)\n\n const _customBlockerFn = async () => {\n if (shouldBlock) return await opts()\n return false\n }\n\n return {\n shouldBlockFn: _customBlockerFn,\n enableBeforeUnload: shouldBlock,\n withResolver: false,\n }\n }\n\n const shouldBlock = Solid.createMemo(() => Boolean(opts.condition ?? true))\n\n const _customBlockerFn = async () => {\n if (shouldBlock() && opts.blockerFn !== undefined) {\n return await opts.blockerFn()\n }\n return shouldBlock()\n }\n\n return {\n get shouldBlockFn() {\n return _customBlockerFn\n },\n get enableBeforeUnload() {\n return shouldBlock()\n },\n get withResolver() {\n return opts.blockerFn === undefined\n },\n }\n}\n\nexport function useBlocker<\n TRouter extends AnyRouter = RegisteredRouter,\n TWithResolver extends boolean = false,\n>(\n opts: UseBlockerOpts<TRouter, TWithResolver>,\n): TWithResolver extends true ? Solid.Accessor<BlockerResolver<TRouter>> : void\n\n/**\n * @deprecated Use the shouldBlockFn property instead\n */\nexport function useBlocker(\n blockerFnOrOpts?: LegacyBlockerOpts,\n): Solid.Accessor<BlockerResolver>\n\n/**\n * @deprecated Use the UseBlockerOpts object syntax instead\n */\nexport function useBlocker(\n blockerFn?: LegacyBlockerFn,\n condition?: boolean | any,\n): Solid.Accessor<BlockerResolver>\n\nexport function useBlocker(\n opts?: UseBlockerOpts | LegacyBlockerOpts | LegacyBlockerFn,\n condition?: boolean | any,\n): Solid.Accessor<BlockerResolver> | void {\n const props = Solid.merge(\n {\n enableBeforeUnload: true,\n disabled: false,\n withResolver: false,\n },\n _resolveBlockerOpts(opts, condition),\n )\n\n const router = useRouter()\n\n const [resolver, setResolver] = Solid.createSignal<BlockerResolver>({\n status: 'idle',\n current: undefined,\n next: undefined,\n action: undefined,\n proceed: undefined,\n reset: undefined,\n })\n\n Solid.createTrackedEffect(() => {\n const blockerFnComposed = async (blockerFnArgs: BlockerFnArgs) => {\n function getLocation(\n location: HistoryLocation,\n ): AnyShouldBlockFnLocation {\n const parsedLocation = router.parseLocation(location)\n const matchedRoutes = router.getMatchedRoutes(parsedLocation.pathname)\n if (matchedRoutes.foundRoute === undefined) {\n return {\n routeId: '__notFound__',\n fullPath: parsedLocation.pathname,\n pathname: parsedLocation.pathname,\n params: matchedRoutes.routeParams,\n search: parsedLocation.search,\n }\n }\n return {\n routeId: matchedRoutes.foundRoute.id,\n fullPath: matchedRoutes.foundRoute.fullPath,\n pathname: parsedLocation.pathname,\n params: matchedRoutes.routeParams,\n search: parsedLocation.search,\n }\n }\n\n const current = getLocation(blockerFnArgs.currentLocation)\n const next = getLocation(blockerFnArgs.nextLocation)\n\n if (\n current.routeId === '__notFound__' &&\n next.routeId !== '__notFound__'\n ) {\n return false\n }\n\n const shouldBlock = await props.shouldBlockFn({\n action: blockerFnArgs.action,\n current,\n next,\n })\n if (!props.withResolver) {\n return shouldBlock\n }\n\n if (!shouldBlock) {\n return false\n }\n\n const promise = new Promise<boolean>((resolve) => {\n setResolver({\n status: 'blocked',\n current,\n next,\n action: blockerFnArgs.action,\n proceed: () => resolve(false),\n reset: () => resolve(true),\n })\n })\n\n const canNavigateAsync = await promise\n setResolver({\n status: 'idle',\n current: undefined,\n next: undefined,\n action: undefined,\n proceed: undefined,\n reset: undefined,\n })\n\n return canNavigateAsync\n }\n\n const disposeBlock = props.disabled\n ? undefined\n : router.history.block({\n blockerFn: blockerFnComposed,\n enableBeforeUnload: props.enableBeforeUnload,\n })\n\n return () => disposeBlock?.()\n })\n\n return resolver\n}\n\nconst _resolvePromptBlockerArgs = (\n props: PromptProps | LegacyPromptProps,\n): UseBlockerOpts => {\n if ('shouldBlockFn' in props) {\n return props\n }\n\n const shouldBlock = Solid.createMemo(() => Boolean(props.condition ?? true))\n\n const _customBlockerFn = async () => {\n if (shouldBlock() && props.blockerFn !== undefined) {\n return await props.blockerFn()\n }\n return shouldBlock\n }\n\n return {\n shouldBlockFn: _customBlockerFn,\n get enableBeforeUnload() {\n return shouldBlock()\n },\n get withResolver() {\n return props.blockerFn === undefined\n },\n }\n}\n\ninterface BlockComponent {\n <\n TRouter extends AnyRouter = RegisteredRouter,\n TWithResolver extends boolean = boolean,\n >(\n opts: PromptProps<TRouter, TWithResolver>,\n ): SolidNode\n /**\n * @deprecated Use the UseBlockerOpts property instead\n */\n (opts: LegacyPromptProps): SolidNode\n}\n\nexport const Block: BlockComponent = function Block(\n opts: PromptProps | LegacyPromptProps,\n): SolidNode {\n const propsWithChildren = {\n get children() {\n return opts.children\n },\n }\n const args = _resolvePromptBlockerArgs(opts)\n\n const resolver = useBlocker(args)\n const children = Solid.createMemo(() => {\n const child = propsWithChildren.children\n if (resolver && typeof child === 'function') return child(resolver())\n return child\n })\n\n return <>{children()}</>\n}\n\ntype LegacyPromptProps = {\n blockerFn?: LegacyBlockerFn\n condition?: boolean | any\n children?: SolidNode | ((params: BlockerResolver) => SolidNode)\n}\n\ntype PromptProps<\n TRouter extends AnyRouter = RegisteredRouter,\n TWithResolver extends boolean = boolean,\n TParams = TWithResolver extends true ? BlockerResolver<TRouter> : void,\n> = UseBlockerOpts<TRouter, TWithResolver> & {\n children?: SolidNode | ((params: TParams) => SolidNode)\n}\n"],"mappings":"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"}
|
package/dist/esm/Transitioner.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Transitioner.js","names":["Solid","getLocationChangeInfo","handleHashScroll","trimPathRight","useRouter","useRouterState","usePrevious","Transitioner","router","mountLoadForRouter","mounted","isLoading","select","isSolidTransitioning","hasPendingMatches","s","matches","some","d","status","previousIsLoading","isAnyPending","previousIsAnyPending","isPagePending","previousIsPagePending","startTransition","fn","Promise","runWithOwner","onSettled","unsub","history","subscribe","load","updateLatestLocation","nextLocation","buildLocation","to","latestLocation","pathname","search","params","hash","state","_includeValidateSearch","publicHref","commitLocation","replace","
|
|
1
|
+
{"version":3,"file":"Transitioner.js","names":["Solid","getLocationChangeInfo","handleHashScroll","trimPathRight","useRouter","useRouterState","usePrevious","Transitioner","router","mountLoadForRouter","mounted","isLoading","select","isSolidTransitioning","hasPendingMatches","s","matches","some","d","status","previousIsLoading","isAnyPending","previousIsAnyPending","isPagePending","previousIsPagePending","startTransition","fn","Promise","runWithOwner","onSettled","unsub","history","subscribe","load","updateLatestLocation","nextLocation","buildLocation","to","latestLocation","pathname","search","params","hash","state","_includeValidateSearch","publicHref","commitLocation","replace","createTrackedEffect","untrack","window","ssr","tryLoad","err","console","error","createEffect","const","previous","emit","type","changeInfo","__store","setState","resolvedLocation","location","hrefChanged"],"sources":["../../src/Transitioner.tsx"],"sourcesContent":["import * as Solid from 'solid-js'\nimport {\n getLocationChangeInfo,\n handleHashScroll,\n trimPathRight,\n} from '@tanstack/router-core'\nimport { useRouter } from './useRouter'\nimport { useRouterState } from './useRouterState'\nimport { usePrevious } from './utils'\n\nexport function Transitioner() {\n const router = useRouter()\n let mountLoadForRouter = { router, mounted: false }\n const isLoading = useRouterState({\n select: ({ isLoading }) => isLoading,\n })\n\n const [isSolidTransitioning] = [() => false]\n\n // Track pending state changes\n const hasPendingMatches = useRouterState({\n select: (s) => s.matches.some((d) => d.status === 'pending'),\n })\n\n const previousIsLoading = usePrevious(isLoading)\n\n const isAnyPending = () =>\n isLoading() || isSolidTransitioning() || hasPendingMatches()\n const previousIsAnyPending = usePrevious(isAnyPending)\n\n const isPagePending = () => isLoading() || hasPendingMatches()\n const previousIsPagePending = usePrevious(isPagePending)\n\n router.startTransition = (fn: () => void | Promise<void>) => {\n Solid.runWithOwner(null, fn)\n }\n\n // Subscribe to location changes\n // and try to load the new location\n Solid.onSettled(() => {\n const unsub = router.history.subscribe(router.load)\n\n // Refresh latestLocation from the current browser URL before comparing.\n // The URL may have been changed synchronously (e.g. via replaceState) after\n // render() but before this effect ran, so we must not use the stale\n // render-time location here.\n router.updateLatestLocation()\n\n const nextLocation = router.buildLocation({\n to: router.latestLocation.pathname,\n search: true,\n params: true,\n hash: true,\n state: true,\n _includeValidateSearch: true,\n })\n\n // Check if the current URL matches the canonical form.\n // Compare publicHref (browser-facing URL) for consistency with\n // the server-side redirect check in router.beforeLoad.\n if (\n trimPathRight(router.latestLocation.publicHref) !==\n trimPathRight(nextLocation.publicHref)\n ) {\n router.commitLocation({ ...nextLocation, replace: true })\n }\n\n return () => {\n unsub()\n }\n })\n\n // Try to load the initial location\n Solid.createTrackedEffect(() => {\n Solid.untrack(() => {\n if (\n // if we are hydrating from SSR, loading is triggered in ssr-client\n (typeof window !== 'undefined' && router.ssr) ||\n (mountLoadForRouter.router === router && mountLoadForRouter.mounted)\n ) {\n return\n }\n mountLoadForRouter = { router, mounted: true }\n const tryLoad = async () => {\n try {\n await router.load()\n } catch (err) {\n console.error(err)\n }\n }\n tryLoad()\n })\n })\n\n Solid.createEffect(\n () => [previousIsLoading(), isLoading()] as const,\n ([previousIsLoading, isLoading]) => {\n if (previousIsLoading.previous && !isLoading) {\n router.emit({\n type: 'onLoad',\n ...getLocationChangeInfo(router.state),\n })\n }\n },\n )\n\n Solid.createEffect(\n () => [isPagePending(), previousIsPagePending()] as const,\n ([isPagePending, previousIsPagePending]) => {\n // emit onBeforeRouteMount\n if (previousIsPagePending.previous && !isPagePending) {\n router.emit({\n type: 'onBeforeRouteMount',\n ...getLocationChangeInfo(router.state),\n })\n }\n },\n )\n\n Solid.createEffect(\n () => [isAnyPending(), previousIsAnyPending()] as const,\n ([isAnyPending, previousIsAnyPending]) => {\n if (previousIsAnyPending.previous && !isAnyPending) {\n const changeInfo = getLocationChangeInfo(router.state)\n router.emit({\n type: 'onResolved',\n ...changeInfo,\n })\n\n router.__store.setState((s) => ({\n ...s,\n status: 'idle',\n resolvedLocation: s.location,\n }))\n\n if (changeInfo.hrefChanged) {\n handleHashScroll(router)\n }\n }\n },\n )\n\n return null\n}\n"],"mappings":";;;;;;AAUA,SAAgBO,eAAe;CAC7B,MAAMC,SAASJ,WAAW;CAC1B,IAAIK,qBAAqB;EAAED;EAAQE,SAAS;EAAO;CACnD,MAAMC,YAAYN,eAAe,EAC/BO,SAAS,EAAED,gBAAgBA,WAC5B,CAAC;CAEF,MAAM,CAACE,wBAAwB,OAAO,MAAM;CAG5C,MAAMC,oBAAoBT,eAAe,EACvCO,SAASG,MAAMA,EAAEC,QAAQC,MAAMC,MAAMA,EAAEC,WAAW,UAAS,EAC5D,CAAC;CAEF,MAAMC,oBAAoBd,YAAYK,UAAU;CAEhD,MAAMU,qBACJV,WAAW,IAAIE,sBAAsB,IAAIC,mBAAmB;CAC9D,MAAMQ,uBAAuBhB,YAAYe,aAAa;CAEtD,MAAME,sBAAsBZ,WAAW,IAAIG,mBAAmB;CAC9D,MAAMU,wBAAwBlB,YAAYiB,cAAc;AAExDf,QAAOiB,mBAAmBC,OAAmC;AAC3D1B,QAAM4B,aAAa,MAAMF,GAAG;;AAK9B1B,OAAM6B,gBAAgB;EACpB,MAAMC,QAAQtB,OAAOuB,QAAQC,UAAUxB,OAAOyB,KAAK;AAMnDzB,SAAO0B,sBAAsB;EAE7B,MAAMC,eAAe3B,OAAO4B,cAAc;GACxCC,IAAI7B,OAAO8B,eAAeC;GAC1BC,QAAQ;GACRC,QAAQ;GACRC,MAAM;GACNC,OAAO;GACPC,wBAAwB;GACzB,CAAC;AAKF,MACEzC,cAAcK,OAAO8B,eAAeO,WAAW,KAC/C1C,cAAcgC,aAAaU,WAAW,CAEtCrC,QAAOsC,eAAe;GAAE,GAAGX;GAAcY,SAAS;GAAM,CAAC;AAG3D,eAAa;AACXjB,UAAO;;GAET;AAGF9B,OAAMgD,0BAA0B;AAC9BhD,QAAMiD,cAAc;AAClB,OAEG,OAAOC,WAAW,eAAe1C,OAAO2C,OACxC1C,mBAAmBD,WAAWA,UAAUC,mBAAmBC,QAE5D;AAEFD,wBAAqB;IAAED;IAAQE,SAAS;IAAM;GAC9C,MAAM0C,UAAU,YAAY;AAC1B,QAAI;AACF,WAAM5C,OAAOyB,MAAM;aACZoB,KAAK;AACZC,aAAQC,MAAMF,IAAI;;;AAGtBD,YAAS;IACT;GACF;AAEFpD,OAAMwD,mBACE,CAACpC,mBAAmB,EAAET,WAAW,CAAC,GACvC,CAACS,mBAAmBT,eAAe;AAClC,MAAIS,kBAAkBsC,YAAY,CAAC/C,UACjCH,QAAOmD,KAAK;GACVC,MAAM;GACN,GAAG3D,sBAAsBO,OAAOmC,MAAK;GACtC,CAAC;GAGP;AAED3C,OAAMwD,mBACE,CAACjC,eAAe,EAAEC,uBAAuB,CAAC,GAC/C,CAACD,eAAeC,2BAA2B;AAE1C,MAAIA,sBAAsBkC,YAAY,CAACnC,cACrCf,QAAOmD,KAAK;GACVC,MAAM;GACN,GAAG3D,sBAAsBO,OAAOmC,MAAK;GACtC,CAAC;GAGP;AAED3C,OAAMwD,mBACE,CAACnC,cAAc,EAAEC,sBAAsB,CAAC,GAC7C,CAACD,cAAcC,0BAA0B;AACxC,MAAIA,qBAAqBoC,YAAY,CAACrC,cAAc;GAClD,MAAMwC,aAAa5D,sBAAsBO,OAAOmC,MAAM;AACtDnC,UAAOmD,KAAK;IACVC,MAAM;IACN,GAAGC;IACJ,CAAC;AAEFrD,UAAOsD,QAAQC,UAAUhD,OAAO;IAC9B,GAAGA;IACHI,QAAQ;IACR6C,kBAAkBjD,EAAEkD;IACrB,EAAE;AAEH,OAAIJ,WAAWK,YACbhE,kBAAiBM,OAAO;;GAI/B;AAED,QAAO"}
|
package/dist/esm/useBlocker.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBlocker.js","names":["Solid","useRouter","BlockerFnArgs","HistoryAction","HistoryLocation","SolidNode","AnyRoute","AnyRouter","ParseRoute","RegisteredRouter","ShouldBlockFnLocation","routeId","TRouteId","fullPath","TFullPath","pathname","params","TAllParams","search","TFullSearchSchema","AnyShouldBlockFnLocation","MakeShouldBlockFnLocationUnion","TRouter","TRoute","BlockerResolver","status","current","next","action","proceed","reset","ShouldBlockFnArgs","ShouldBlockFn","args","Promise","UseBlockerOpts","shouldBlockFn","enableBeforeUnload","disabled","withResolver","TWithResolver","LegacyBlockerFn","LegacyBlockerOpts","blockerFn","condition","_resolveBlockerOpts","opts","undefined","shouldBlock","Boolean","_customBlockerFn","createMemo","useBlocker","Accessor","blockerFnOrOpts","props","merge","router","resolver","setResolver","createSignal","createTrackedEffect","blockerFnComposed","blockerFnArgs","getLocation","location","parsedLocation","parseLocation","matchedRoutes","getMatchedRoutes","foundRoute","routeParams","id","currentLocation","nextLocation","promise","resolve","canNavigateAsync","disposeBlock","history","block","onCleanup","_resolvePromptBlockerArgs","PromptProps","LegacyPromptProps","BlockComponent","Block","propsWithChildren","children","child","_$memo","TParams"],"sources":["../../src/useBlocker.tsx"],"sourcesContent":["import * as Solid from 'solid-js'\nimport { useRouter } from './useRouter'\nimport type {\n BlockerFnArgs,\n HistoryAction,\n HistoryLocation,\n} from '@tanstack/history'\nimport type { SolidNode } from './route'\nimport type {\n AnyRoute,\n AnyRouter,\n ParseRoute,\n RegisteredRouter,\n} from '@tanstack/router-core'\n\ninterface ShouldBlockFnLocation<\n out TRouteId,\n out TFullPath,\n out TAllParams,\n out TFullSearchSchema,\n> {\n routeId: TRouteId\n fullPath: TFullPath\n pathname: string\n params: TAllParams\n search: TFullSearchSchema\n}\n\ntype AnyShouldBlockFnLocation = ShouldBlockFnLocation<any, any, any, any>\ntype MakeShouldBlockFnLocationUnion<\n TRouter extends AnyRouter = RegisteredRouter,\n TRoute extends AnyRoute = ParseRoute<TRouter['routeTree']>,\n> = TRoute extends any\n ? ShouldBlockFnLocation<\n TRoute['id'],\n TRoute['fullPath'],\n TRoute['types']['allParams'],\n TRoute['types']['fullSearchSchema']\n >\n : never\n\ntype BlockerResolver<TRouter extends AnyRouter = RegisteredRouter> =\n | {\n status: 'blocked'\n current: MakeShouldBlockFnLocationUnion<TRouter>\n next: MakeShouldBlockFnLocationUnion<TRouter>\n action: HistoryAction\n proceed: () => void\n reset: () => void\n }\n | {\n status: 'idle'\n current: undefined\n next: undefined\n action: undefined\n proceed: undefined\n reset: undefined\n }\n\ntype ShouldBlockFnArgs<TRouter extends AnyRouter = RegisteredRouter> = {\n current: MakeShouldBlockFnLocationUnion<TRouter>\n next: MakeShouldBlockFnLocationUnion<TRouter>\n action: HistoryAction\n}\n\nexport type ShouldBlockFn<TRouter extends AnyRouter = RegisteredRouter> = (\n args: ShouldBlockFnArgs<TRouter>,\n) => boolean | Promise<boolean>\nexport type UseBlockerOpts<\n TRouter extends AnyRouter = RegisteredRouter,\n TWithResolver extends boolean = boolean,\n> = {\n shouldBlockFn: ShouldBlockFn<TRouter>\n enableBeforeUnload?: boolean | (() => boolean)\n disabled?: boolean\n withResolver?: TWithResolver\n}\n\ntype LegacyBlockerFn = () => Promise<any> | any\ntype LegacyBlockerOpts = {\n blockerFn?: LegacyBlockerFn\n condition?: boolean | any\n}\n\nfunction _resolveBlockerOpts(\n opts?: UseBlockerOpts | LegacyBlockerOpts | LegacyBlockerFn,\n condition?: boolean | any,\n): UseBlockerOpts {\n if (opts === undefined) {\n return {\n shouldBlockFn: () => true,\n withResolver: false,\n }\n }\n\n if ('shouldBlockFn' in opts) {\n return opts\n }\n\n if (typeof opts === 'function') {\n const shouldBlock = Boolean(condition ?? true)\n\n const _customBlockerFn = async () => {\n if (shouldBlock) return await opts()\n return false\n }\n\n return {\n shouldBlockFn: _customBlockerFn,\n enableBeforeUnload: shouldBlock,\n withResolver: false,\n }\n }\n\n const shouldBlock = Solid.createMemo(() => Boolean(opts.condition ?? true))\n\n const _customBlockerFn = async () => {\n if (shouldBlock() && opts.blockerFn !== undefined) {\n return await opts.blockerFn()\n }\n return shouldBlock()\n }\n\n return {\n get shouldBlockFn() {\n return _customBlockerFn\n },\n get enableBeforeUnload() {\n return shouldBlock()\n },\n get withResolver() {\n return opts.blockerFn === undefined\n },\n }\n}\n\nexport function useBlocker<\n TRouter extends AnyRouter = RegisteredRouter,\n TWithResolver extends boolean = false,\n>(\n opts: UseBlockerOpts<TRouter, TWithResolver>,\n): TWithResolver extends true ? Solid.Accessor<BlockerResolver<TRouter>> : void\n\n/**\n * @deprecated Use the shouldBlockFn property instead\n */\nexport function useBlocker(\n blockerFnOrOpts?: LegacyBlockerOpts,\n): Solid.Accessor<BlockerResolver>\n\n/**\n * @deprecated Use the UseBlockerOpts object syntax instead\n */\nexport function useBlocker(\n blockerFn?: LegacyBlockerFn,\n condition?: boolean | any,\n): Solid.Accessor<BlockerResolver>\n\nexport function useBlocker(\n opts?: UseBlockerOpts | LegacyBlockerOpts | LegacyBlockerFn,\n condition?: boolean | any,\n): Solid.Accessor<BlockerResolver> | void {\n const props = Solid.merge(\n {\n enableBeforeUnload: true,\n disabled: false,\n withResolver: false,\n },\n _resolveBlockerOpts(opts, condition),\n )\n\n const router = useRouter()\n\n const [resolver, setResolver] = Solid.createSignal<BlockerResolver>({\n status: 'idle',\n current: undefined,\n next: undefined,\n action: undefined,\n proceed: undefined,\n reset: undefined,\n })\n\n Solid.createTrackedEffect(() => {\n const blockerFnComposed = async (blockerFnArgs: BlockerFnArgs) => {\n function getLocation(\n location: HistoryLocation,\n ): AnyShouldBlockFnLocation {\n const parsedLocation = router.parseLocation(location)\n const matchedRoutes = router.getMatchedRoutes(parsedLocation.pathname)\n if (matchedRoutes.foundRoute === undefined) {\n return {\n routeId: '__notFound__',\n fullPath: parsedLocation.pathname,\n pathname: parsedLocation.pathname,\n params: matchedRoutes.routeParams,\n search: parsedLocation.search,\n }\n }\n return {\n routeId: matchedRoutes.foundRoute.id,\n fullPath: matchedRoutes.foundRoute.fullPath,\n pathname: parsedLocation.pathname,\n params: matchedRoutes.routeParams,\n search: parsedLocation.search,\n }\n }\n\n const current = getLocation(blockerFnArgs.currentLocation)\n const next = getLocation(blockerFnArgs.nextLocation)\n\n if (\n current.routeId === '__notFound__' &&\n next.routeId !== '__notFound__'\n ) {\n return false\n }\n\n const shouldBlock = await props.shouldBlockFn({\n action: blockerFnArgs.action,\n current,\n next,\n })\n if (!props.withResolver) {\n return shouldBlock\n }\n\n if (!shouldBlock) {\n return false\n }\n\n const promise = new Promise<boolean>((resolve) => {\n setResolver({\n status: 'blocked',\n current,\n next,\n action: blockerFnArgs.action,\n proceed: () => resolve(false),\n reset: () => resolve(true),\n })\n })\n\n const canNavigateAsync = await promise\n setResolver({\n status: 'idle',\n current: undefined,\n next: undefined,\n action: undefined,\n proceed: undefined,\n reset: undefined,\n })\n\n return canNavigateAsync\n }\n\n const disposeBlock = props.disabled\n ? undefined\n : router.history.block({\n blockerFn: blockerFnComposed,\n enableBeforeUnload: props.enableBeforeUnload,\n })\n\n Solid.onCleanup(() => disposeBlock?.())\n })\n\n return resolver\n}\n\nconst _resolvePromptBlockerArgs = (\n props: PromptProps | LegacyPromptProps,\n): UseBlockerOpts => {\n if ('shouldBlockFn' in props) {\n return props\n }\n\n const shouldBlock = Solid.createMemo(() => Boolean(props.condition ?? true))\n\n const _customBlockerFn = async () => {\n if (shouldBlock() && props.blockerFn !== undefined) {\n return await props.blockerFn()\n }\n return shouldBlock\n }\n\n return {\n shouldBlockFn: _customBlockerFn,\n get enableBeforeUnload() {\n return shouldBlock()\n },\n get withResolver() {\n return props.blockerFn === undefined\n },\n }\n}\n\ninterface BlockComponent {\n <\n TRouter extends AnyRouter = RegisteredRouter,\n TWithResolver extends boolean = boolean,\n >(\n opts: PromptProps<TRouter, TWithResolver>,\n ): SolidNode\n /**\n * @deprecated Use the UseBlockerOpts property instead\n */\n (opts: LegacyPromptProps): SolidNode\n}\n\nexport const Block: BlockComponent = function Block(\n opts: PromptProps | LegacyPromptProps,\n): SolidNode {\n const propsWithChildren = {\n get children() {\n return opts.children\n },\n }\n const args = _resolvePromptBlockerArgs(opts)\n\n const resolver = useBlocker(args)\n const children = Solid.createMemo(() => {\n const child = propsWithChildren.children\n if (resolver && typeof child === 'function') return child(resolver())\n return child\n })\n\n return <>{children()}</>\n}\n\ntype LegacyPromptProps = {\n blockerFn?: LegacyBlockerFn\n condition?: boolean | any\n children?: SolidNode | ((params: BlockerResolver) => SolidNode)\n}\n\ntype PromptProps<\n TRouter extends AnyRouter = RegisteredRouter,\n TWithResolver extends boolean = boolean,\n TParams = TWithResolver extends true ? BlockerResolver<TRouter> : void,\n> = UseBlockerOpts<TRouter, TWithResolver> & {\n children?: SolidNode | ((params: TParams) => SolidNode)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useBlocker.js","names":["Solid","useRouter","BlockerFnArgs","HistoryAction","HistoryLocation","SolidNode","AnyRoute","AnyRouter","ParseRoute","RegisteredRouter","ShouldBlockFnLocation","routeId","TRouteId","fullPath","TFullPath","pathname","params","TAllParams","search","TFullSearchSchema","AnyShouldBlockFnLocation","MakeShouldBlockFnLocationUnion","TRouter","TRoute","BlockerResolver","status","current","next","action","proceed","reset","ShouldBlockFnArgs","ShouldBlockFn","args","Promise","UseBlockerOpts","shouldBlockFn","enableBeforeUnload","disabled","withResolver","TWithResolver","LegacyBlockerFn","LegacyBlockerOpts","blockerFn","condition","_resolveBlockerOpts","opts","undefined","shouldBlock","Boolean","_customBlockerFn","createMemo","useBlocker","Accessor","blockerFnOrOpts","props","merge","router","resolver","setResolver","createSignal","createTrackedEffect","blockerFnComposed","blockerFnArgs","getLocation","location","parsedLocation","parseLocation","matchedRoutes","getMatchedRoutes","foundRoute","routeParams","id","currentLocation","nextLocation","promise","resolve","canNavigateAsync","disposeBlock","history","block","_resolvePromptBlockerArgs","PromptProps","LegacyPromptProps","BlockComponent","Block","propsWithChildren","children","child","_$memo","TParams"],"sources":["../../src/useBlocker.tsx"],"sourcesContent":["import * as Solid from 'solid-js'\nimport { useRouter } from './useRouter'\nimport type {\n BlockerFnArgs,\n HistoryAction,\n HistoryLocation,\n} from '@tanstack/history'\nimport type { SolidNode } from './route'\nimport type {\n AnyRoute,\n AnyRouter,\n ParseRoute,\n RegisteredRouter,\n} from '@tanstack/router-core'\n\ninterface ShouldBlockFnLocation<\n out TRouteId,\n out TFullPath,\n out TAllParams,\n out TFullSearchSchema,\n> {\n routeId: TRouteId\n fullPath: TFullPath\n pathname: string\n params: TAllParams\n search: TFullSearchSchema\n}\n\ntype AnyShouldBlockFnLocation = ShouldBlockFnLocation<any, any, any, any>\ntype MakeShouldBlockFnLocationUnion<\n TRouter extends AnyRouter = RegisteredRouter,\n TRoute extends AnyRoute = ParseRoute<TRouter['routeTree']>,\n> = TRoute extends any\n ? ShouldBlockFnLocation<\n TRoute['id'],\n TRoute['fullPath'],\n TRoute['types']['allParams'],\n TRoute['types']['fullSearchSchema']\n >\n : never\n\ntype BlockerResolver<TRouter extends AnyRouter = RegisteredRouter> =\n | {\n status: 'blocked'\n current: MakeShouldBlockFnLocationUnion<TRouter>\n next: MakeShouldBlockFnLocationUnion<TRouter>\n action: HistoryAction\n proceed: () => void\n reset: () => void\n }\n | {\n status: 'idle'\n current: undefined\n next: undefined\n action: undefined\n proceed: undefined\n reset: undefined\n }\n\ntype ShouldBlockFnArgs<TRouter extends AnyRouter = RegisteredRouter> = {\n current: MakeShouldBlockFnLocationUnion<TRouter>\n next: MakeShouldBlockFnLocationUnion<TRouter>\n action: HistoryAction\n}\n\nexport type ShouldBlockFn<TRouter extends AnyRouter = RegisteredRouter> = (\n args: ShouldBlockFnArgs<TRouter>,\n) => boolean | Promise<boolean>\nexport type UseBlockerOpts<\n TRouter extends AnyRouter = RegisteredRouter,\n TWithResolver extends boolean = boolean,\n> = {\n shouldBlockFn: ShouldBlockFn<TRouter>\n enableBeforeUnload?: boolean | (() => boolean)\n disabled?: boolean\n withResolver?: TWithResolver\n}\n\ntype LegacyBlockerFn = () => Promise<any> | any\ntype LegacyBlockerOpts = {\n blockerFn?: LegacyBlockerFn\n condition?: boolean | any\n}\n\nfunction _resolveBlockerOpts(\n opts?: UseBlockerOpts | LegacyBlockerOpts | LegacyBlockerFn,\n condition?: boolean | any,\n): UseBlockerOpts {\n if (opts === undefined) {\n return {\n shouldBlockFn: () => true,\n withResolver: false,\n }\n }\n\n if ('shouldBlockFn' in opts) {\n return opts\n }\n\n if (typeof opts === 'function') {\n const shouldBlock = Boolean(condition ?? true)\n\n const _customBlockerFn = async () => {\n if (shouldBlock) return await opts()\n return false\n }\n\n return {\n shouldBlockFn: _customBlockerFn,\n enableBeforeUnload: shouldBlock,\n withResolver: false,\n }\n }\n\n const shouldBlock = Solid.createMemo(() => Boolean(opts.condition ?? true))\n\n const _customBlockerFn = async () => {\n if (shouldBlock() && opts.blockerFn !== undefined) {\n return await opts.blockerFn()\n }\n return shouldBlock()\n }\n\n return {\n get shouldBlockFn() {\n return _customBlockerFn\n },\n get enableBeforeUnload() {\n return shouldBlock()\n },\n get withResolver() {\n return opts.blockerFn === undefined\n },\n }\n}\n\nexport function useBlocker<\n TRouter extends AnyRouter = RegisteredRouter,\n TWithResolver extends boolean = false,\n>(\n opts: UseBlockerOpts<TRouter, TWithResolver>,\n): TWithResolver extends true ? Solid.Accessor<BlockerResolver<TRouter>> : void\n\n/**\n * @deprecated Use the shouldBlockFn property instead\n */\nexport function useBlocker(\n blockerFnOrOpts?: LegacyBlockerOpts,\n): Solid.Accessor<BlockerResolver>\n\n/**\n * @deprecated Use the UseBlockerOpts object syntax instead\n */\nexport function useBlocker(\n blockerFn?: LegacyBlockerFn,\n condition?: boolean | any,\n): Solid.Accessor<BlockerResolver>\n\nexport function useBlocker(\n opts?: UseBlockerOpts | LegacyBlockerOpts | LegacyBlockerFn,\n condition?: boolean | any,\n): Solid.Accessor<BlockerResolver> | void {\n const props = Solid.merge(\n {\n enableBeforeUnload: true,\n disabled: false,\n withResolver: false,\n },\n _resolveBlockerOpts(opts, condition),\n )\n\n const router = useRouter()\n\n const [resolver, setResolver] = Solid.createSignal<BlockerResolver>({\n status: 'idle',\n current: undefined,\n next: undefined,\n action: undefined,\n proceed: undefined,\n reset: undefined,\n })\n\n Solid.createTrackedEffect(() => {\n const blockerFnComposed = async (blockerFnArgs: BlockerFnArgs) => {\n function getLocation(\n location: HistoryLocation,\n ): AnyShouldBlockFnLocation {\n const parsedLocation = router.parseLocation(location)\n const matchedRoutes = router.getMatchedRoutes(parsedLocation.pathname)\n if (matchedRoutes.foundRoute === undefined) {\n return {\n routeId: '__notFound__',\n fullPath: parsedLocation.pathname,\n pathname: parsedLocation.pathname,\n params: matchedRoutes.routeParams,\n search: parsedLocation.search,\n }\n }\n return {\n routeId: matchedRoutes.foundRoute.id,\n fullPath: matchedRoutes.foundRoute.fullPath,\n pathname: parsedLocation.pathname,\n params: matchedRoutes.routeParams,\n search: parsedLocation.search,\n }\n }\n\n const current = getLocation(blockerFnArgs.currentLocation)\n const next = getLocation(blockerFnArgs.nextLocation)\n\n if (\n current.routeId === '__notFound__' &&\n next.routeId !== '__notFound__'\n ) {\n return false\n }\n\n const shouldBlock = await props.shouldBlockFn({\n action: blockerFnArgs.action,\n current,\n next,\n })\n if (!props.withResolver) {\n return shouldBlock\n }\n\n if (!shouldBlock) {\n return false\n }\n\n const promise = new Promise<boolean>((resolve) => {\n setResolver({\n status: 'blocked',\n current,\n next,\n action: blockerFnArgs.action,\n proceed: () => resolve(false),\n reset: () => resolve(true),\n })\n })\n\n const canNavigateAsync = await promise\n setResolver({\n status: 'idle',\n current: undefined,\n next: undefined,\n action: undefined,\n proceed: undefined,\n reset: undefined,\n })\n\n return canNavigateAsync\n }\n\n const disposeBlock = props.disabled\n ? undefined\n : router.history.block({\n blockerFn: blockerFnComposed,\n enableBeforeUnload: props.enableBeforeUnload,\n })\n\n return () => disposeBlock?.()\n })\n\n return resolver\n}\n\nconst _resolvePromptBlockerArgs = (\n props: PromptProps | LegacyPromptProps,\n): UseBlockerOpts => {\n if ('shouldBlockFn' in props) {\n return props\n }\n\n const shouldBlock = Solid.createMemo(() => Boolean(props.condition ?? true))\n\n const _customBlockerFn = async () => {\n if (shouldBlock() && props.blockerFn !== undefined) {\n return await props.blockerFn()\n }\n return shouldBlock\n }\n\n return {\n shouldBlockFn: _customBlockerFn,\n get enableBeforeUnload() {\n return shouldBlock()\n },\n get withResolver() {\n return props.blockerFn === undefined\n },\n }\n}\n\ninterface BlockComponent {\n <\n TRouter extends AnyRouter = RegisteredRouter,\n TWithResolver extends boolean = boolean,\n >(\n opts: PromptProps<TRouter, TWithResolver>,\n ): SolidNode\n /**\n * @deprecated Use the UseBlockerOpts property instead\n */\n (opts: LegacyPromptProps): SolidNode\n}\n\nexport const Block: BlockComponent = function Block(\n opts: PromptProps | LegacyPromptProps,\n): SolidNode {\n const propsWithChildren = {\n get children() {\n return opts.children\n },\n }\n const args = _resolvePromptBlockerArgs(opts)\n\n const resolver = useBlocker(args)\n const children = Solid.createMemo(() => {\n const child = propsWithChildren.children\n if (resolver && typeof child === 'function') return child(resolver())\n return child\n })\n\n return <>{children()}</>\n}\n\ntype LegacyPromptProps = {\n blockerFn?: LegacyBlockerFn\n condition?: boolean | any\n children?: SolidNode | ((params: BlockerResolver) => SolidNode)\n}\n\ntype PromptProps<\n TRouter extends AnyRouter = RegisteredRouter,\n TWithResolver extends boolean = boolean,\n TParams = TWithResolver extends true ? BlockerResolver<TRouter> : void,\n> = UseBlockerOpts<TRouter, TWithResolver> & {\n children?: SolidNode | ((params: TParams) => SolidNode)\n}\n"],"mappings":"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"}
|
|
@@ -46,9 +46,9 @@ export function Transitioner() {
|
|
|
46
46
|
trimPathRight(nextLocation.publicHref)) {
|
|
47
47
|
router.commitLocation({ ...nextLocation, replace: true });
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
return () => {
|
|
50
50
|
unsub();
|
|
51
|
-
}
|
|
51
|
+
};
|
|
52
52
|
});
|
|
53
53
|
// Try to load the initial location
|
|
54
54
|
Solid.createTrackedEffect(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Transitioner.jsx","sourceRoot":"","sources":["../../src/Transitioner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,UAAU,CAAA;AACjC,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,aAAa,GACd,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAErC,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAC1B,IAAI,kBAAkB,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAA;IACnD,MAAM,SAAS,GAAG,cAAc,CAAC;QAC/B,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,SAAS;KACrC,CAAC,CAAA;IAEF,MAAM,CAAC,oBAAoB,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAA;IAE5C,8BAA8B;IAC9B,MAAM,iBAAiB,GAAG,cAAc,CAAC;QACvC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC;KAC7D,CAAC,CAAA;IAEF,MAAM,iBAAiB,GAAG,WAAW,CAAC,SAAS,CAAC,CAAA;IAEhD,MAAM,YAAY,GAAG,GAAG,EAAE,CACxB,SAAS,EAAE,IAAI,oBAAoB,EAAE,IAAI,iBAAiB,EAAE,CAAA;IAC9D,MAAM,oBAAoB,GAAG,WAAW,CAAC,YAAY,CAAC,CAAA;IAEtD,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,SAAS,EAAE,IAAI,iBAAiB,EAAE,CAAA;IAC9D,MAAM,qBAAqB,GAAG,WAAW,CAAC,aAAa,CAAC,CAAA;IAExD,MAAM,CAAC,eAAe,GAAG,CAAC,EAA8B,EAAE,EAAE;QAC1D,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IAC9B,CAAC,CAAA;IAED,gCAAgC;IAChC,mCAAmC;IACnC,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QAEnD,wEAAwE;QACxE,4EAA4E;QAC5E,oEAAoE;QACpE,6BAA6B;QAC7B,MAAM,CAAC,oBAAoB,EAAE,CAAA;QAE7B,MAAM,YAAY,GAAG,MAAM,CAAC,aAAa,CAAC;YACxC,EAAE,EAAE,MAAM,CAAC,cAAc,CAAC,QAAQ;YAClC,MAAM,EAAE,IAAI;YACZ,MAAM,EAAE,IAAI;YACZ,IAAI,EAAE,IAAI;YACV,KAAK,EAAE,IAAI;YACX,sBAAsB,EAAE,IAAI;SAC7B,CAAC,CAAA;QAEF,uDAAuD;QACvD,+DAA+D;QAC/D,uDAAuD;QACvD,IACE,aAAa,CAAC,MAAM,CAAC,cAAc,CAAC,UAAU,CAAC;YAC/C,aAAa,CAAC,YAAY,CAAC,UAAU,CAAC,EACtC,CAAC;YACD,MAAM,CAAC,cAAc,CAAC,EAAE,GAAG,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;QAC3D,CAAC;QAED,
|
|
1
|
+
{"version":3,"file":"Transitioner.jsx","sourceRoot":"","sources":["../../src/Transitioner.tsx"],"names":[],"mappings":"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"}
|
|
@@ -123,7 +123,7 @@ export function useBlocker(opts, condition) {
|
|
|
123
123
|
blockerFn: blockerFnComposed,
|
|
124
124
|
enableBeforeUnload: props.enableBeforeUnload,
|
|
125
125
|
});
|
|
126
|
-
|
|
126
|
+
return () => disposeBlock?.();
|
|
127
127
|
});
|
|
128
128
|
return resolver;
|
|
129
129
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBlocker.jsx","sourceRoot":"","sources":["../../src/useBlocker.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"useBlocker.jsx","sourceRoot":"","sources":["../../src/useBlocker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAmFvC,SAAS,mBAAmB,CAC1B,IAA2D,EAC3D,SAAyB;IAEzB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO;YACL,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI;YACzB,YAAY,EAAE,KAAK;SACpB,CAAA;IACH,CAAC;IAED,IAAI,eAAe,IAAI,IAAI,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,OAAO,IAAI,KAAK,UAAU,EAAE,CAAC;QAC/B,MAAM,WAAW,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,CAAA;QAE9C,MAAM,gBAAgB,GAAG,KAAK,IAAI,EAAE;YAClC,IAAI,WAAW;gBAAE,OAAO,MAAM,IAAI,EAAE,CAAA;YACpC,OAAO,KAAK,CAAA;QACd,CAAC,CAAA;QAED,OAAO;YACL,aAAa,EAAE,gBAAgB;YAC/B,kBAAkB,EAAE,WAAW;YAC/B,YAAY,EAAE,KAAK;SACpB,CAAA;IACH,CAAC;IAED,MAAM,WAAW,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,CAAA;IAE3E,MAAM,gBAAgB,GAAG,KAAK,IAAI,EAAE;QAClC,IAAI,WAAW,EAAE,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YAClD,OAAO,MAAM,IAAI,CAAC,SAAS,EAAE,CAAA;QAC/B,CAAC;QACD,OAAO,WAAW,EAAE,CAAA;IACtB,CAAC,CAAA;IAED,OAAO;QACL,IAAI,aAAa;YACf,OAAO,gBAAgB,CAAA;QACzB,CAAC;QACD,IAAI,kBAAkB;YACpB,OAAO,WAAW,EAAE,CAAA;QACtB,CAAC;QACD,IAAI,YAAY;YACd,OAAO,IAAI,CAAC,SAAS,KAAK,SAAS,CAAA;QACrC,CAAC;KACF,CAAA;AACH,CAAC;AAwBD,MAAM,UAAU,UAAU,CACxB,IAA2D,EAC3D,SAAyB;IAEzB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CACvB;QACE,kBAAkB,EAAE,IAAI;QACxB,QAAQ,EAAE,KAAK;QACf,YAAY,EAAE,KAAK;KACpB,EACD,mBAAmB,CAAC,IAAI,EAAE,SAAS,CAAC,CACrC,CAAA;IAED,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAE1B,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,KAAK,CAAC,YAAY,CAAkB;QAClE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;QACjB,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,SAAS;KACjB,CAAC,CAAA;IAEF,KAAK,CAAC,mBAAmB,CAAC,GAAG,EAAE;QAC7B,MAAM,iBAAiB,GAAG,KAAK,EAAE,aAA4B,EAAE,EAAE;YAC/D,SAAS,WAAW,CAClB,QAAyB;gBAEzB,MAAM,cAAc,GAAG,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAA;gBACrD,MAAM,aAAa,GAAG,MAAM,CAAC,gBAAgB,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAA;gBACtE,IAAI,aAAa,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;oBAC3C,OAAO;wBACL,OAAO,EAAE,cAAc;wBACvB,QAAQ,EAAE,cAAc,CAAC,QAAQ;wBACjC,QAAQ,EAAE,cAAc,CAAC,QAAQ;wBACjC,MAAM,EAAE,aAAa,CAAC,WAAW;wBACjC,MAAM,EAAE,cAAc,CAAC,MAAM;qBAC9B,CAAA;gBACH,CAAC;gBACD,OAAO;oBACL,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,EAAE;oBACpC,QAAQ,EAAE,aAAa,CAAC,UAAU,CAAC,QAAQ;oBAC3C,QAAQ,EAAE,cAAc,CAAC,QAAQ;oBACjC,MAAM,EAAE,aAAa,CAAC,WAAW;oBACjC,MAAM,EAAE,cAAc,CAAC,MAAM;iBAC9B,CAAA;YACH,CAAC;YAED,MAAM,OAAO,GAAG,WAAW,CAAC,aAAa,CAAC,eAAe,CAAC,CAAA;YAC1D,MAAM,IAAI,GAAG,WAAW,CAAC,aAAa,CAAC,YAAY,CAAC,CAAA;YAEpD,IACE,OAAO,CAAC,OAAO,KAAK,cAAc;gBAClC,IAAI,CAAC,OAAO,KAAK,cAAc,EAC/B,CAAC;gBACD,OAAO,KAAK,CAAA;YACd,CAAC;YAED,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,aAAa,CAAC;gBAC5C,MAAM,EAAE,aAAa,CAAC,MAAM;gBAC5B,OAAO;gBACP,IAAI;aACL,CAAC,CAAA;YACF,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;gBACxB,OAAO,WAAW,CAAA;YACpB,CAAC;YAED,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,OAAO,KAAK,CAAA;YACd,CAAC;YAED,MAAM,OAAO,GAAG,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;gBAC/C,WAAW,CAAC;oBACV,MAAM,EAAE,SAAS;oBACjB,OAAO;oBACP,IAAI;oBACJ,MAAM,EAAE,aAAa,CAAC,MAAM;oBAC5B,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;oBAC7B,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;iBAC3B,CAAC,CAAA;YACJ,CAAC,CAAC,CAAA;YAEF,MAAM,gBAAgB,GAAG,MAAM,OAAO,CAAA;YACtC,WAAW,CAAC;gBACV,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,SAAS;gBAClB,IAAI,EAAE,SAAS;gBACf,MAAM,EAAE,SAAS;gBACjB,OAAO,EAAE,SAAS;gBAClB,KAAK,EAAE,SAAS;aACjB,CAAC,CAAA;YAEF,OAAO,gBAAgB,CAAA;QACzB,CAAC,CAAA;QAED,MAAM,YAAY,GAAG,KAAK,CAAC,QAAQ;YACjC,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;gBACnB,SAAS,EAAE,iBAAiB;gBAC5B,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;aAC7C,CAAC,CAAA;QAEN,OAAO,GAAG,EAAE,CAAC,YAAY,EAAE,EAAE,CAAA;IAC/B,CAAC,CAAC,CAAA;IAEF,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,MAAM,yBAAyB,GAAG,CAChC,KAAsC,EACtB,EAAE;IAClB,IAAI,eAAe,IAAI,KAAK,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAA;IACd,CAAC;IAED,MAAM,WAAW,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,CAAA;IAE5E,MAAM,gBAAgB,GAAG,KAAK,IAAI,EAAE;QAClC,IAAI,WAAW,EAAE,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YACnD,OAAO,MAAM,KAAK,CAAC,SAAS,EAAE,CAAA;QAChC,CAAC;QACD,OAAO,WAAW,CAAA;IACpB,CAAC,CAAA;IAED,OAAO;QACL,aAAa,EAAE,gBAAgB;QAC/B,IAAI,kBAAkB;YACpB,OAAO,WAAW,EAAE,CAAA;QACtB,CAAC;QACD,IAAI,YAAY;YACd,OAAO,KAAK,CAAC,SAAS,KAAK,SAAS,CAAA;QACtC,CAAC;KACF,CAAA;AACH,CAAC,CAAA;AAeD,MAAM,CAAC,MAAM,KAAK,GAAmB,SAAS,KAAK,CACjD,IAAqC;IAErC,MAAM,iBAAiB,GAAG;QACxB,IAAI,QAAQ;YACV,OAAO,IAAI,CAAC,QAAQ,CAAA;QACtB,CAAC;KACF,CAAA;IACD,MAAM,IAAI,GAAG,yBAAyB,CAAC,IAAI,CAAC,CAAA;IAE5C,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,CAAA;IACjC,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE;QACrC,MAAM,KAAK,GAAG,iBAAiB,CAAC,QAAQ,CAAA;QACxC,IAAI,QAAQ,IAAI,OAAO,KAAK,KAAK,UAAU;YAAE,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;QACrE,OAAO,KAAK,CAAA;IACd,CAAC,CAAC,CAAA;IAEF,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAA;AAC1B,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/solid-router",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.6",
|
|
4
4
|
"description": "Modern and scalable routing for Solid applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -78,7 +78,10 @@
|
|
|
78
78
|
"sideEffects": false,
|
|
79
79
|
"files": [
|
|
80
80
|
"dist",
|
|
81
|
-
"src"
|
|
81
|
+
"src",
|
|
82
|
+
"skills",
|
|
83
|
+
"bin",
|
|
84
|
+
"!skills/_artifacts"
|
|
82
85
|
],
|
|
83
86
|
"engines": {
|
|
84
87
|
"node": ">=20.19"
|
|
@@ -86,27 +89,31 @@
|
|
|
86
89
|
"dependencies": {
|
|
87
90
|
"@solid-devtools/logger": "^0.9.4",
|
|
88
91
|
"@solidjs/meta": "^0.29.4",
|
|
89
|
-
"@solidjs/web": "2.0.0-beta.
|
|
92
|
+
"@solidjs/web": "2.0.0-beta.4",
|
|
90
93
|
"isbot": "^5.1.22",
|
|
91
94
|
"tiny-invariant": "^1.3.3",
|
|
92
95
|
"tiny-warning": "^1.0.3",
|
|
93
96
|
"@tanstack/history": "1.161.6",
|
|
94
|
-
"@tanstack/router-core": "1.167.
|
|
97
|
+
"@tanstack/router-core": "1.167.5"
|
|
95
98
|
},
|
|
96
99
|
"devDependencies": {
|
|
97
100
|
"@solidjs/testing-library": "^0.8.10",
|
|
101
|
+
"@tanstack/intent": "^0.0.14",
|
|
98
102
|
"@testing-library/jest-dom": "^6.6.3",
|
|
99
103
|
"combinate": "^1.1.11",
|
|
100
104
|
"eslint-plugin-solid": "^0.14.5",
|
|
101
|
-
"solid-js": "2.0.0-beta.
|
|
102
|
-
"@solidjs/web": "2.0.0-beta.
|
|
105
|
+
"solid-js": "2.0.0-beta.4",
|
|
106
|
+
"@solidjs/web": "2.0.0-beta.4",
|
|
103
107
|
"vite": "*",
|
|
104
|
-
"vite-plugin-solid": "3.0.0-next.
|
|
108
|
+
"vite-plugin-solid": "3.0.0-next.3",
|
|
105
109
|
"zod": "^3.23.8"
|
|
106
110
|
},
|
|
107
111
|
"peerDependencies": {
|
|
108
|
-
"solid-js": "2.0.0-beta.
|
|
109
|
-
"@solidjs/web": "2.0.0-beta.
|
|
112
|
+
"solid-js": "2.0.0-beta.4",
|
|
113
|
+
"@solidjs/web": "2.0.0-beta.4"
|
|
114
|
+
},
|
|
115
|
+
"bin": {
|
|
116
|
+
"intent": "./bin/intent.js"
|
|
110
117
|
},
|
|
111
118
|
"scripts": {
|
|
112
119
|
"clean": "rimraf ./dist && rimraf ./coverage",
|
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: solid-router
|
|
3
|
+
description: >-
|
|
4
|
+
Solid bindings for TanStack Router: RouterProvider, useRouter,
|
|
5
|
+
useRouterState, useMatch, useMatches, useLocation, useSearch,
|
|
6
|
+
useParams, useNavigate, useLoaderData, useLoaderDeps,
|
|
7
|
+
useRouteContext, useBlocker, useCanGoBack, Link, Navigate,
|
|
8
|
+
Outlet, CatchBoundary, ErrorComponent. Solid-specific patterns
|
|
9
|
+
with Accessor<T> returns, createSignal/createMemo/createEffect,
|
|
10
|
+
Show/Switch/Match/Dynamic, and @solidjs/meta for head management.
|
|
11
|
+
type: framework
|
|
12
|
+
library: tanstack-router
|
|
13
|
+
library_version: '1.166.2'
|
|
14
|
+
framework: solid
|
|
15
|
+
requires:
|
|
16
|
+
- router-core
|
|
17
|
+
sources:
|
|
18
|
+
- TanStack/router:packages/solid-router/src
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# Solid Router (`@tanstack/solid-router`)
|
|
22
|
+
|
|
23
|
+
This skill builds on router-core. Read [router-core](../../../router-core/skills/router-core/SKILL.md) first for foundational concepts.
|
|
24
|
+
|
|
25
|
+
This skill covers the Solid-specific bindings, components, hooks, and setup for TanStack Router.
|
|
26
|
+
|
|
27
|
+
> **CRITICAL**: TanStack Router types are FULLY INFERRED. Never cast, never annotate inferred values.
|
|
28
|
+
> **CRITICAL**: TanStack Router is CLIENT-FIRST. Loaders run on the client by default, not on the server.
|
|
29
|
+
> **CRITICAL**: Most hooks return `Accessor<T>` — you MUST call the accessor (`value()`) to read the reactive value. This is the #1 difference from the React version.
|
|
30
|
+
> **CRITICAL**: Do not confuse `@tanstack/solid-router` with `@solidjs/router`. They are completely different libraries with different APIs.
|
|
31
|
+
|
|
32
|
+
## Full Setup: File-Based Routing with Vite
|
|
33
|
+
|
|
34
|
+
### 1. Install Dependencies
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install @tanstack/solid-router
|
|
38
|
+
npm install -D @tanstack/router-plugin @tanstack/solid-router-devtools
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 2. Configure Vite Plugin
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
// vite.config.ts
|
|
45
|
+
import { defineConfig } from 'vite'
|
|
46
|
+
import solidPlugin from 'vite-plugin-solid'
|
|
47
|
+
import { tanstackRouter } from '@tanstack/router-plugin/vite'
|
|
48
|
+
|
|
49
|
+
export default defineConfig({
|
|
50
|
+
plugins: [
|
|
51
|
+
// MUST come before solid plugin
|
|
52
|
+
tanstackRouter({
|
|
53
|
+
target: 'solid',
|
|
54
|
+
autoCodeSplitting: true,
|
|
55
|
+
}),
|
|
56
|
+
solidPlugin(),
|
|
57
|
+
],
|
|
58
|
+
})
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 3. Create Root Route
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
// src/routes/__root.tsx
|
|
65
|
+
import { createRootRoute, Link, Outlet } from '@tanstack/solid-router'
|
|
66
|
+
|
|
67
|
+
export const Route = createRootRoute({
|
|
68
|
+
component: RootLayout,
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
function RootLayout() {
|
|
72
|
+
return (
|
|
73
|
+
<>
|
|
74
|
+
<nav>
|
|
75
|
+
<Link to="/" activeClass="font-bold">
|
|
76
|
+
Home
|
|
77
|
+
</Link>
|
|
78
|
+
<Link to="/about" activeClass="font-bold">
|
|
79
|
+
About
|
|
80
|
+
</Link>
|
|
81
|
+
</nav>
|
|
82
|
+
<hr />
|
|
83
|
+
<Outlet />
|
|
84
|
+
</>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 4. Create Route Files
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
// src/routes/index.tsx
|
|
93
|
+
import { createFileRoute } from '@tanstack/solid-router'
|
|
94
|
+
|
|
95
|
+
export const Route = createFileRoute('/')({
|
|
96
|
+
component: HomePage,
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
function HomePage() {
|
|
100
|
+
return <h1>Welcome Home</h1>
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 5. Create Router Instance and Register Types
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
// src/main.tsx
|
|
108
|
+
import { render } from 'solid-js/web'
|
|
109
|
+
import { RouterProvider, createRouter } from '@tanstack/solid-router'
|
|
110
|
+
import { routeTree } from './routeTree.gen'
|
|
111
|
+
|
|
112
|
+
const router = createRouter({ routeTree })
|
|
113
|
+
|
|
114
|
+
// REQUIRED — without this, Link/useNavigate/useSearch have no type safety
|
|
115
|
+
declare module '@tanstack/solid-router' {
|
|
116
|
+
interface Register {
|
|
117
|
+
router: typeof router
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
render(
|
|
122
|
+
() => <RouterProvider router={router} />,
|
|
123
|
+
document.getElementById('root')!,
|
|
124
|
+
)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Hooks Reference
|
|
128
|
+
|
|
129
|
+
All hooks imported from `@tanstack/solid-router`. Most return `Accessor<T>` — call the result to read the value.
|
|
130
|
+
|
|
131
|
+
### `useRouter()` — returns `TRouter` (NOT an Accessor)
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
import { useRouter } from '@tanstack/solid-router'
|
|
135
|
+
|
|
136
|
+
function InvalidateButton() {
|
|
137
|
+
const router = useRouter()
|
|
138
|
+
return <button onClick={() => router.invalidate()}>Refresh data</button>
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### `useRouterState()` — returns `Accessor<T>`
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
import { useRouterState } from '@tanstack/solid-router'
|
|
146
|
+
|
|
147
|
+
function LoadingIndicator() {
|
|
148
|
+
const isLoading = useRouterState({ select: (s) => s.isLoading })
|
|
149
|
+
return (
|
|
150
|
+
<Show when={isLoading()}>
|
|
151
|
+
<div>Loading...</div>
|
|
152
|
+
</Show>
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### `useNavigate()` — returns a function (NOT an Accessor)
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
import { useNavigate } from '@tanstack/solid-router'
|
|
161
|
+
|
|
162
|
+
function AfterSubmit() {
|
|
163
|
+
const navigate = useNavigate()
|
|
164
|
+
|
|
165
|
+
const handleSubmit = async () => {
|
|
166
|
+
await saveData()
|
|
167
|
+
navigate({ to: '/posts/$postId', params: { postId: '123' } })
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return <button onClick={handleSubmit}>Save</button>
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### `useSearch({ from })` — returns `Accessor<T>`
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
import { useSearch } from '@tanstack/solid-router'
|
|
178
|
+
|
|
179
|
+
function Pagination() {
|
|
180
|
+
const search = useSearch({ from: '/products' })
|
|
181
|
+
return <span>Page {search().page}</span>
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### `useParams({ from })` — returns `Accessor<T>`
|
|
186
|
+
|
|
187
|
+
```tsx
|
|
188
|
+
import { useParams } from '@tanstack/solid-router'
|
|
189
|
+
|
|
190
|
+
function PostHeader() {
|
|
191
|
+
const params = useParams({ from: '/posts/$postId' })
|
|
192
|
+
return <h2>Post {params().postId}</h2>
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### `useLoaderData({ from })` — returns `Accessor<T>`
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
import { useLoaderData } from '@tanstack/solid-router'
|
|
200
|
+
|
|
201
|
+
function PostContent() {
|
|
202
|
+
const data = useLoaderData({ from: '/posts/$postId' })
|
|
203
|
+
return <article>{data().post.content}</article>
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### `useMatch({ from })` — returns `Accessor<T>`
|
|
208
|
+
|
|
209
|
+
```tsx
|
|
210
|
+
import { useMatch } from '@tanstack/solid-router'
|
|
211
|
+
|
|
212
|
+
function PostDetails() {
|
|
213
|
+
const match = useMatch({ from: '/posts/$postId' })
|
|
214
|
+
return <div>{match().loaderData.post.title}</div>
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Other Hooks
|
|
219
|
+
|
|
220
|
+
All imported from `@tanstack/solid-router`:
|
|
221
|
+
|
|
222
|
+
- **`useMatches()`** — `Accessor<Array<Match>>`, all active route matches
|
|
223
|
+
- **`useParentMatches()`** — `Accessor<Array<Match>>`, parent route matches
|
|
224
|
+
- **`useChildMatches()`** — `Accessor<Array<Match>>`, child route matches
|
|
225
|
+
- **`useRouteContext({ from })`** — `Accessor<T>`, context from `beforeLoad`
|
|
226
|
+
- **`useLoaderDeps({ from })`** — `Accessor<T>`, loader dependency values
|
|
227
|
+
- **`useBlocker({ shouldBlockFn })`** — blocks navigation for unsaved changes
|
|
228
|
+
- **`useCanGoBack()`** — `Accessor<boolean>`
|
|
229
|
+
- **`useLocation()`** — `Accessor<ParsedLocation>`
|
|
230
|
+
- **`useLinkProps({ to, params?, search? })`** — returns `ComponentProps<'a'>` (NOT an Accessor)
|
|
231
|
+
- **`useMatchRoute()`** — returns a function; calling it returns `Accessor<false | Params>`
|
|
232
|
+
- **`useHydrated()`** — `Accessor<boolean>`
|
|
233
|
+
|
|
234
|
+
## Components Reference
|
|
235
|
+
|
|
236
|
+
### `RouterProvider`
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
<RouterProvider router={router} />
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### `Link`
|
|
243
|
+
|
|
244
|
+
Type-safe navigation link. Children can be a function for active state:
|
|
245
|
+
|
|
246
|
+
```tsx
|
|
247
|
+
;<Link to="/posts/$postId" params={{ postId: '42' }}>
|
|
248
|
+
View Post
|
|
249
|
+
</Link>
|
|
250
|
+
|
|
251
|
+
{
|
|
252
|
+
/* Function children for active state */
|
|
253
|
+
}
|
|
254
|
+
;<Link to="/about">
|
|
255
|
+
{(state) => <span classList={{ active: state.isActive }}>About</span>}
|
|
256
|
+
</Link>
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### `Outlet`
|
|
260
|
+
|
|
261
|
+
Renders the matched child route component:
|
|
262
|
+
|
|
263
|
+
```tsx
|
|
264
|
+
function Layout() {
|
|
265
|
+
return (
|
|
266
|
+
<div>
|
|
267
|
+
<Sidebar />
|
|
268
|
+
<main>
|
|
269
|
+
<Outlet />
|
|
270
|
+
</main>
|
|
271
|
+
</div>
|
|
272
|
+
)
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### `Navigate`
|
|
277
|
+
|
|
278
|
+
Declarative redirect (triggers navigation in `onMount`):
|
|
279
|
+
|
|
280
|
+
```tsx
|
|
281
|
+
import { Navigate } from '@tanstack/solid-router'
|
|
282
|
+
|
|
283
|
+
function OldPage() {
|
|
284
|
+
return <Navigate to="/new-page" />
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### `Await`
|
|
289
|
+
|
|
290
|
+
Renders deferred data with Solid's `Suspense`:
|
|
291
|
+
|
|
292
|
+
```tsx
|
|
293
|
+
import { Await } from '@tanstack/solid-router'
|
|
294
|
+
import { Suspense } from 'solid-js'
|
|
295
|
+
|
|
296
|
+
function PostWithComments() {
|
|
297
|
+
const data = Route.useLoaderData()
|
|
298
|
+
return (
|
|
299
|
+
<Suspense fallback={<div>Loading...</div>}>
|
|
300
|
+
<Await promise={data().deferredComments}>
|
|
301
|
+
{(comments) => <For each={comments}>{(c) => <li>{c.text}</li>}</For>}
|
|
302
|
+
</Await>
|
|
303
|
+
</Suspense>
|
|
304
|
+
)
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### `CatchBoundary`
|
|
309
|
+
|
|
310
|
+
Error boundary wrapping `Solid.ErrorBoundary`:
|
|
311
|
+
|
|
312
|
+
```tsx
|
|
313
|
+
import { CatchBoundary } from '@tanstack/solid-router'
|
|
314
|
+
;<CatchBoundary
|
|
315
|
+
getResetKey={() => 'widget'}
|
|
316
|
+
errorComponent={({ error }) => <div>Error: {error.message}</div>}
|
|
317
|
+
>
|
|
318
|
+
<RiskyWidget />
|
|
319
|
+
</CatchBoundary>
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Other Components
|
|
323
|
+
|
|
324
|
+
- **`CatchNotFound`** — catches `notFound()` errors in children; `fallback` receives the error data
|
|
325
|
+
- **`Block`** — declarative navigation blocker; use `shouldBlockFn` and `withResolver` for custom UI
|
|
326
|
+
- **`ScrollRestoration`** — **deprecated**; use `createRouter`'s `scrollRestoration: true` option instead
|
|
327
|
+
- **`ClientOnly`** — renders children only after hydration; accepts `fallback` prop
|
|
328
|
+
|
|
329
|
+
### `Block`
|
|
330
|
+
|
|
331
|
+
Declarative navigation blocker component:
|
|
332
|
+
|
|
333
|
+
```tsx
|
|
334
|
+
import { Block } from '@tanstack/solid-router'
|
|
335
|
+
;<Block shouldBlockFn={() => formIsDirty()} withResolver>
|
|
336
|
+
{({ status, proceed, reset }) => (
|
|
337
|
+
<Show when={status === 'blocked'}>
|
|
338
|
+
<div>
|
|
339
|
+
<p>Are you sure?</p>
|
|
340
|
+
<button onClick={proceed}>Yes</button>
|
|
341
|
+
<button onClick={reset}>No</button>
|
|
342
|
+
</div>
|
|
343
|
+
</Show>
|
|
344
|
+
)}
|
|
345
|
+
</Block>
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### `ScrollRestoration`
|
|
349
|
+
|
|
350
|
+
Restores scroll position on navigation:
|
|
351
|
+
|
|
352
|
+
```tsx
|
|
353
|
+
import { ScrollRestoration } from '@tanstack/solid-router'
|
|
354
|
+
// In root route component
|
|
355
|
+
;<ScrollRestoration />
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### `ClientOnly`
|
|
359
|
+
|
|
360
|
+
Renders children only after hydration:
|
|
361
|
+
|
|
362
|
+
```tsx
|
|
363
|
+
import { ClientOnly } from '@tanstack/solid-router'
|
|
364
|
+
;<ClientOnly fallback={<div>Loading...</div>}>
|
|
365
|
+
<BrowserOnlyWidget />
|
|
366
|
+
</ClientOnly>
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Head Management
|
|
370
|
+
|
|
371
|
+
Uses `@solidjs/meta` under the hood:
|
|
372
|
+
|
|
373
|
+
```tsx
|
|
374
|
+
import { HeadContent, Scripts } from '@tanstack/solid-router'
|
|
375
|
+
|
|
376
|
+
function RootDocument(props) {
|
|
377
|
+
return (
|
|
378
|
+
<html>
|
|
379
|
+
<head>
|
|
380
|
+
<HeadContent />
|
|
381
|
+
</head>
|
|
382
|
+
<body>
|
|
383
|
+
{props.children}
|
|
384
|
+
<Scripts />
|
|
385
|
+
</body>
|
|
386
|
+
</html>
|
|
387
|
+
)
|
|
388
|
+
}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
## Solid-Specific Patterns
|
|
392
|
+
|
|
393
|
+
### Custom Link Component with `createLink`
|
|
394
|
+
|
|
395
|
+
```tsx
|
|
396
|
+
import { createLink } from '@tanstack/solid-router'
|
|
397
|
+
|
|
398
|
+
const StyledLinkComponent = (props) => (
|
|
399
|
+
<a {...props} class={`styled-link ${props.class ?? ''}`} />
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
const StyledLink = createLink(StyledLinkComponent)
|
|
403
|
+
|
|
404
|
+
function Nav() {
|
|
405
|
+
return (
|
|
406
|
+
<StyledLink to="/posts/$postId" params={{ postId: '42' }}>
|
|
407
|
+
Post
|
|
408
|
+
</StyledLink>
|
|
409
|
+
)
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Using Solid Primitives with Router State
|
|
414
|
+
|
|
415
|
+
```tsx
|
|
416
|
+
import { createMemo, Show, For } from 'solid-js'
|
|
417
|
+
import { useRouterState } from '@tanstack/solid-router'
|
|
418
|
+
|
|
419
|
+
function Breadcrumbs() {
|
|
420
|
+
const matches = useRouterState({ select: (s) => s.matches })
|
|
421
|
+
const crumbs = createMemo(() =>
|
|
422
|
+
matches().filter((m) => m.context?.breadcrumb),
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
return (
|
|
426
|
+
<nav>
|
|
427
|
+
<For each={crumbs()}>
|
|
428
|
+
{(match) => <span>{match.context.breadcrumb}</span>}
|
|
429
|
+
</For>
|
|
430
|
+
</nav>
|
|
431
|
+
)
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Auth with Router Context
|
|
436
|
+
|
|
437
|
+
```tsx
|
|
438
|
+
import { createRootRouteWithContext } from '@tanstack/solid-router'
|
|
439
|
+
|
|
440
|
+
const rootRoute = createRootRouteWithContext<{ auth: AuthState }>()({
|
|
441
|
+
component: RootComponent,
|
|
442
|
+
})
|
|
443
|
+
|
|
444
|
+
// In main.tsx — provide context at router creation
|
|
445
|
+
const router = createRouter({
|
|
446
|
+
routeTree,
|
|
447
|
+
context: { auth: authState },
|
|
448
|
+
})
|
|
449
|
+
|
|
450
|
+
// In a route — access via beforeLoad (NOT hooks)
|
|
451
|
+
beforeLoad: ({ context }) => {
|
|
452
|
+
if (!context.auth.isAuthenticated) {
|
|
453
|
+
throw redirect({ to: '/login' })
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
## Common Mistakes
|
|
459
|
+
|
|
460
|
+
### 1. CRITICAL: Forgetting to call Accessor
|
|
461
|
+
|
|
462
|
+
Hooks return `Accessor<T>` — you must call them to read the value. This is the #1 migration issue from React.
|
|
463
|
+
|
|
464
|
+
```tsx
|
|
465
|
+
// WRONG — comparing the accessor function, not its value
|
|
466
|
+
const params = useParams({ from: '/posts/$postId' })
|
|
467
|
+
if (params.postId === '42') { ... } // params is a function!
|
|
468
|
+
|
|
469
|
+
// CORRECT — call the accessor
|
|
470
|
+
const params = useParams({ from: '/posts/$postId' })
|
|
471
|
+
if (params().postId === '42') { ... }
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### 2. HIGH: Destructuring reactive values
|
|
475
|
+
|
|
476
|
+
Destructuring breaks Solid's reactivity tracking.
|
|
477
|
+
|
|
478
|
+
```tsx
|
|
479
|
+
// WRONG — loses reactivity
|
|
480
|
+
const { page } = useSearch({ from: '/products' })()
|
|
481
|
+
|
|
482
|
+
// CORRECT — access through accessor
|
|
483
|
+
const search = useSearch({ from: '/products' })
|
|
484
|
+
<span>Page {search().page}</span>
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### 3. HIGH: Using React hooks in beforeLoad or loader
|
|
488
|
+
|
|
489
|
+
`beforeLoad` and `loader` are NOT components — they are plain async functions. No hooks (React or Solid) can be used in them. Pass state via router context instead.
|
|
490
|
+
|
|
491
|
+
### 4. MEDIUM: Wrong plugin target
|
|
492
|
+
|
|
493
|
+
Must set `target: 'solid'` in the router plugin config. Default is `'react'`.
|
|
494
|
+
|
|
495
|
+
## Cross-References
|
|
496
|
+
|
|
497
|
+
- [router-core/SKILL.md](../../../router-core/skills/router-core/SKILL.md) — all sub-skills for domain-specific patterns (search params, data loading, navigation, auth, SSR, etc.)
|
package/src/Transitioner.tsx
CHANGED