@tanstack/vue-router
Version:
Modern and scalable routing for Vue applications
251 lines (250 loc) • 6.97 kB
JavaScript
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