UNPKG

@tanstack/solid-router

Version:

Modern and scalable routing for Solid applications

1 lines 13.1 kB
{"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","mergeProps","router","resolver","setResolver","createSignal","createEffect","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","rest","splitProps","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.mergeProps(\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.createEffect(() => {\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, rest] = Solid.splitProps(opts, ['children'])\n const args = _resolvePromptBlockerArgs(rest)\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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"}