@tanstack/solid-router
Version:
Modern and scalable routing for Solid applications
142 lines (141 loc) • 4.14 kB
JavaScript
import { useRouter } from "./useRouter.js";
import { memo } from "solid-js/web";
import * as Solid from "solid-js";
//#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 = Solid.createMemo(() => Boolean(opts.condition ?? true));
const _customBlockerFn = async () => {
if (shouldBlock() && opts.blockerFn !== void 0) return await opts.blockerFn();
return shouldBlock();
};
return {
get shouldBlockFn() {
return _customBlockerFn;
},
get enableBeforeUnload() {
return shouldBlock();
},
get withResolver() {
return opts.blockerFn === void 0;
}
};
}
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: void 0,
next: void 0,
action: void 0,
proceed: void 0,
reset: void 0
});
Solid.createEffect(() => {
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 props.shouldBlockFn({
action: blockerFnArgs.action,
current,
next
});
if (!props.withResolver) return shouldBlock;
if (!shouldBlock) return false;
const canNavigateAsync = await new Promise((resolve) => {
setResolver({
status: "blocked",
current,
next,
action: blockerFnArgs.action,
proceed: () => resolve(false),
reset: () => resolve(true)
});
});
setResolver({
status: "idle",
current: void 0,
next: void 0,
action: void 0,
proceed: void 0,
reset: void 0
});
return canNavigateAsync;
};
const disposeBlock = props.disabled ? void 0 : router.history.block({
blockerFn: blockerFnComposed,
enableBeforeUnload: props.enableBeforeUnload
});
Solid.onCleanup(() => disposeBlock?.());
});
return resolver;
}
var _resolvePromptBlockerArgs = (props) => {
if ("shouldBlockFn" in props) return props;
const shouldBlock = Solid.createMemo(() => Boolean(props.condition ?? true));
const _customBlockerFn = async () => {
if (shouldBlock() && props.blockerFn !== void 0) return await props.blockerFn();
return shouldBlock;
};
return {
shouldBlockFn: _customBlockerFn,
get enableBeforeUnload() {
return shouldBlock();
},
get withResolver() {
return props.blockerFn === void 0;
}
};
};
var Block = function Block(opts) {
const [propsWithChildren, rest] = Solid.splitProps(opts, ["children"]);
const resolver = useBlocker(_resolvePromptBlockerArgs(rest));
return memo(Solid.createMemo(() => {
const child = propsWithChildren.children;
if (resolver && typeof child === "function") return child(resolver());
return child;
}));
};
//#endregion
export { Block, useBlocker };
//# sourceMappingURL=useBlocker.js.map