146 lines
3.9 KiB
Plaintext
146 lines
3.9 KiB
Plaintext
import * as React from "react";
|
|
import { useRouter } from "./useRouter.js";
|
|
function _resolveBlockerOpts(opts, condition) {
|
|
if (opts === void 0) {
|
|
return {
|
|
shouldBlockFn: () => true,
|
|
withResolver: false
|
|
};
|
|
}
|
|
if ("shouldBlockFn" in opts) {
|
|
return opts;
|
|
}
|
|
if (typeof opts === "function") {
|
|
const shouldBlock2 = Boolean(condition ?? true);
|
|
const _customBlockerFn2 = async () => {
|
|
if (shouldBlock2) return await opts();
|
|
return false;
|
|
};
|
|
return {
|
|
shouldBlockFn: _customBlockerFn2,
|
|
enableBeforeUnload: shouldBlock2,
|
|
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
|
|
};
|
|
}
|
|
function useBlocker(opts, condition) {
|
|
const {
|
|
shouldBlockFn,
|
|
enableBeforeUnload = true,
|
|
disabled = false,
|
|
withResolver = false
|
|
} = _resolveBlockerOpts(opts, condition);
|
|
const router = useRouter();
|
|
const { history } = router;
|
|
const [resolver, setResolver] = React.useState({
|
|
status: "idle",
|
|
current: void 0,
|
|
next: void 0,
|
|
action: void 0,
|
|
proceed: void 0,
|
|
reset: void 0
|
|
});
|
|
React.useEffect(() => {
|
|
const blockerFnComposed = async (blockerFnArgs) => {
|
|
function getLocation(location) {
|
|
const parsedLocation = router.parseLocation(void 0, location);
|
|
const matchedRoutes = router.getMatchedRoutes(parsedLocation);
|
|
if (matchedRoutes.foundRoute === void 0) {
|
|
throw new Error(`No route found for location ${location.href}`);
|
|
}
|
|
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);
|
|
const shouldBlock = await shouldBlockFn({
|
|
action: blockerFnArgs.action,
|
|
current,
|
|
next
|
|
});
|
|
if (!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: void 0,
|
|
next: void 0,
|
|
action: void 0,
|
|
proceed: void 0,
|
|
reset: void 0
|
|
});
|
|
return canNavigateAsync;
|
|
};
|
|
return disabled ? void 0 : history.block({ blockerFn: blockerFnComposed, enableBeforeUnload });
|
|
}, [
|
|
shouldBlockFn,
|
|
enableBeforeUnload,
|
|
disabled,
|
|
withResolver,
|
|
history,
|
|
router
|
|
]);
|
|
return resolver;
|
|
}
|
|
const _resolvePromptBlockerArgs = (props) => {
|
|
if ("shouldBlockFn" in props) {
|
|
return { ...props };
|
|
}
|
|
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,
|
|
withResolver: fn === void 0
|
|
};
|
|
};
|
|
function Block(opts) {
|
|
const { children, ...rest } = opts;
|
|
const args = _resolvePromptBlockerArgs(rest);
|
|
const resolver = useBlocker(args);
|
|
return children ? typeof children === "function" ? children(resolver) : children : null;
|
|
}
|
|
export {
|
|
Block,
|
|
useBlocker
|
|
};
|
|
//# sourceMappingURL=useBlocker.js.map
|