UNPKG

@tanstack/solid-router

Version:

Modern and scalable routing for Solid applications

163 lines 5.55 kB
import * as Solid from 'solid-js'; import { useRouter } from './useRouter'; function _resolveBlockerOpts(opts, condition) { if (opts === undefined) { return { shouldBlockFn: () => true, withResolver: false, }; } if ('shouldBlockFn' in opts) { return opts; } if (typeof opts === 'function') { const shouldBlock = Boolean(condition ?? true); const _customBlockerFn = async () => { if (shouldBlock) return await opts(); return false; }; return { shouldBlockFn: _customBlockerFn, enableBeforeUnload: shouldBlock, withResolver: false, }; } const shouldBlock = Solid.createMemo(() => Boolean(opts.condition ?? true)); const _customBlockerFn = async () => { if (shouldBlock() && opts.blockerFn !== undefined) { return await opts.blockerFn(); } return shouldBlock(); }; return { get shouldBlockFn() { return _customBlockerFn; }, get enableBeforeUnload() { return shouldBlock(); }, get withResolver() { return opts.blockerFn === undefined; }, }; } export function useBlocker(opts, condition) { const props = Solid.mergeProps({ enableBeforeUnload: true, disabled: false, withResolver: false, }, _resolveBlockerOpts(opts, condition)); const router = useRouter(); const [resolver, setResolver] = Solid.createSignal({ status: 'idle', current: undefined, next: undefined, action: undefined, proceed: undefined, reset: undefined, }); Solid.createEffect(() => { const blockerFnComposed = async (blockerFnArgs) => { function getLocation(location) { const parsedLocation = router.parseLocation(location); const matchedRoutes = router.getMatchedRoutes(parsedLocation.pathname); if (matchedRoutes.foundRoute === undefined) { return { routeId: '__notFound__', fullPath: parsedLocation.pathname, pathname: parsedLocation.pathname, params: matchedRoutes.routeParams, search: parsedLocation.search, }; } return { routeId: matchedRoutes.foundRoute.id, fullPath: matchedRoutes.foundRoute.fullPath, pathname: parsedLocation.pathname, params: matchedRoutes.routeParams, search: parsedLocation.search, }; } const current = getLocation(blockerFnArgs.currentLocation); const next = getLocation(blockerFnArgs.nextLocation); if (current.routeId === '__notFound__' && next.routeId !== '__notFound__') { return false; } const shouldBlock = await props.shouldBlockFn({ action: blockerFnArgs.action, current, next, }); if (!props.withResolver) { return shouldBlock; } if (!shouldBlock) { return false; } const promise = new Promise((resolve) => { setResolver({ status: 'blocked', current, next, action: blockerFnArgs.action, proceed: () => resolve(false), reset: () => resolve(true), }); }); const canNavigateAsync = await promise; setResolver({ status: 'idle', current: undefined, next: undefined, action: undefined, proceed: undefined, reset: undefined, }); return canNavigateAsync; }; const disposeBlock = props.disabled ? undefined : router.history.block({ blockerFn: blockerFnComposed, enableBeforeUnload: props.enableBeforeUnload, }); Solid.onCleanup(() => disposeBlock?.()); }); return resolver; } const _resolvePromptBlockerArgs = (props) => { if ('shouldBlockFn' in props) { return props; } const shouldBlock = Solid.createMemo(() => Boolean(props.condition ?? true)); const _customBlockerFn = async () => { if (shouldBlock() && props.blockerFn !== undefined) { return await props.blockerFn(); } return shouldBlock; }; return { shouldBlockFn: _customBlockerFn, get enableBeforeUnload() { return shouldBlock(); }, get withResolver() { return props.blockerFn === undefined; }, }; }; export const Block = function Block(opts) { const [propsWithChildren, rest] = Solid.splitProps(opts, ['children']); const args = _resolvePromptBlockerArgs(rest); const resolver = useBlocker(args); const children = Solid.createMemo(() => { const child = propsWithChildren.children; if (resolver && typeof child === 'function') return child(resolver()); return child; }); return <>{children()}</>; }; //# sourceMappingURL=useBlocker.jsx.map