UNPKG

@tanstack/vue-router

Version:

Modern and scalable routing for Vue applications

251 lines (250 loc) 6.97 kB
import { useRouter } from "./useRouter.js"; import * as Vue from "vue"; //#region src/useBlocker.tsx function _resolveBlockerOpts(opts, condition) { if (opts === void 0) 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 = Boolean(opts.condition ?? true); const fn = opts.blockerFn; const _customBlockerFn = async () => { if (shouldBlock && fn !== void 0) return await fn(); return shouldBlock; }; return { shouldBlockFn: _customBlockerFn, enableBeforeUnload: shouldBlock, withResolver: fn === void 0 }; } /** * @deprecated Use the shouldBlockFn property instead */ /** * @deprecated Use the UseBlockerOpts object syntax instead */ function useBlocker(opts, condition) { const { shouldBlockFn, enableBeforeUnload = true, disabled = false, withResolver = false } = _resolveBlockerOpts(opts, condition); const router = useRouter(); const { history } = router; const resolver = Vue.ref({ status: "idle", current: void 0, next: void 0, action: void 0, proceed: void 0, reset: void 0 }); Vue.watchEffect((onCleanup) => { const blockerFnComposed = async (blockerFnArgs) => { function getLocation(location) { const parsedLocation = router.parseLocation(location); const matchedRoutes = router.getMatchedRoutes(parsedLocation.pathname); if (matchedRoutes.foundRoute === void 0) 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 shouldBlockFn({ action: blockerFnArgs.action, current, next }); if (!withResolver) return shouldBlock; if (!shouldBlock) return false; const canNavigateAsync = await new Promise((resolve) => { resolver.value = { status: "blocked", current, next, action: blockerFnArgs.action, proceed: () => resolve(false), reset: () => resolve(true) }; }); resolver.value = { status: "idle", current: void 0, next: void 0, action: void 0, proceed: void 0, reset: void 0 }; return canNavigateAsync; }; if (disabled) return; const unsubscribe = history.block({ blockerFn: blockerFnComposed, enableBeforeUnload }); onCleanup(() => { if (unsubscribe) unsubscribe(); }); }); return withResolver ? resolver : void 0; } var BlockImpl = Vue.defineComponent({ name: "Block", props: { shouldBlockFn: { type: Function, required: false }, enableBeforeUnload: { type: [Boolean, Function], default: true }, disabled: { type: Boolean, default: false }, withResolver: { type: Boolean, default: false }, blockerFn: { type: Function, required: false }, condition: { type: [Boolean, Object], required: false } }, setup(props, { slots }) { const blockerArgs = Vue.computed(() => { if (props.shouldBlockFn) return { shouldBlockFn: props.shouldBlockFn, enableBeforeUnload: props.enableBeforeUnload, disabled: props.disabled, withResolver: props.withResolver }; const shouldBlock = Boolean(props.condition ?? true); const fn = props.blockerFn; const _customBlockerFn = async () => { if (shouldBlock && fn !== void 0) return await fn(); return shouldBlock; }; return { shouldBlockFn: _customBlockerFn, enableBeforeUnload: shouldBlock, disabled: props.disabled, withResolver: fn === void 0 }; }); const router = useRouter(); const { history } = router; const resolver = Vue.ref({ status: "idle", current: void 0, next: void 0, action: void 0, proceed: void 0, reset: void 0 }); Vue.watchEffect((onCleanup) => { const args = blockerArgs.value; if (args.disabled) return; const blockerFnComposed = async (blockerFnArgs) => { function getLocation(location) { const parsedLocation = router.parseLocation(location); const matchedRoutes = router.getMatchedRoutes(parsedLocation.pathname); if (matchedRoutes.foundRoute === void 0) 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 args.shouldBlockFn({ action: blockerFnArgs.action, current, next }); if (!args.withResolver) return shouldBlock; if (!shouldBlock) return false; const canNavigateAsync = await new Promise((resolve) => { resolver.value = { status: "blocked", current, next, action: blockerFnArgs.action, proceed: () => resolve(false), reset: () => resolve(true) }; }); resolver.value = { status: "idle", current: void 0, next: void 0, action: void 0, proceed: void 0, reset: void 0 }; return canNavigateAsync; }; const unsubscribe = history.block({ blockerFn: blockerFnComposed, enableBeforeUnload: args.enableBeforeUnload }); onCleanup(() => { if (unsubscribe) unsubscribe(); }); }); return () => { const defaultSlot = slots.default; if (!defaultSlot) return Vue.h(Vue.Fragment, null); const slotContent = defaultSlot(resolver.value); return Vue.h(Vue.Fragment, null, slotContent); }; } }); /** * @deprecated Use the UseBlockerOpts property instead */ function Block(opts) { const { children, ...rest } = opts; const slots = children ? typeof children === "function" ? { default: children } : { default: () => children } : void 0; return Vue.h(BlockImpl, rest, slots); } //#endregion export { Block, useBlocker }; //# sourceMappingURL=useBlocker.js.map