@tanstack/react-router
Version:
Modern and scalable routing for React applications
322 lines (321 loc) • 9.79 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const jsxRuntime = require("react/jsx-runtime");
const React = require("react");
const reactDom = require("react-dom");
const routerCore = require("@tanstack/router-core");
const useRouterState = require("./useRouterState.cjs");
const useRouter = require("./useRouter.cjs");
const utils = require("./utils.cjs");
const Matches = require("./Matches.cjs");
function _interopNamespaceDefault(e) {
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
if (e) {
for (const k in e) {
if (k !== "default") {
const d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: () => e[k]
});
}
}
}
n.default = e;
return Object.freeze(n);
}
const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
function useLinkProps(options, forwardedRef) {
const router = useRouter.useRouter();
const [isTransitioning, setIsTransitioning] = React__namespace.useState(false);
const hasRenderFetched = React__namespace.useRef(false);
const innerRef = utils.useForwardedRef(forwardedRef);
const {
// custom props
activeProps = () => ({ className: "active" }),
inactiveProps = () => ({}),
activeOptions,
to,
preload: userPreload,
preloadDelay: userPreloadDelay,
hashScrollIntoView,
replace,
startTransition,
resetScroll,
viewTransition,
// element props
children,
target,
disabled,
style,
className,
onClick,
onFocus,
onMouseEnter,
onMouseLeave,
onTouchStart,
ignoreBlocker,
...rest
} = options;
const {
// prevent these from being returned
params: _params,
search: _search,
hash: _hash,
state: _state,
mask: _mask,
reloadDocument: _reloadDocument,
...propsSafeToSpread
} = rest;
const type = React__namespace.useMemo(() => {
try {
new URL(`${to}`);
return "external";
} catch {
}
return "internal";
}, [to]);
const currentSearch = useRouterState.useRouterState({
select: (s) => s.location.search,
structuralSharing: true
});
const from = Matches.useMatches({
select: (matches) => {
var _a;
return options.from ?? ((_a = matches[matches.length - 1]) == null ? void 0 : _a.fullPath);
}
});
const _options = React__namespace.useMemo(() => ({ ...options, from }), [options, from]);
const next = React__namespace.useMemo(
() => router.buildLocation(_options),
// eslint-disable-next-line react-hooks/exhaustive-deps
[router, _options, currentSearch]
);
const preload = React__namespace.useMemo(() => {
if (_options.reloadDocument) {
return false;
}
return userPreload ?? router.options.defaultPreload;
}, [router.options.defaultPreload, userPreload, _options.reloadDocument]);
const preloadDelay = userPreloadDelay ?? router.options.defaultPreloadDelay ?? 0;
const isActive = useRouterState.useRouterState({
select: (s) => {
if (activeOptions == null ? void 0 : activeOptions.exact) {
const testExact = routerCore.exactPathTest(
s.location.pathname,
next.pathname,
router.basepath
);
if (!testExact) {
return false;
}
} else {
const currentPathSplit = routerCore.removeTrailingSlash(
s.location.pathname,
router.basepath
).split("/");
const nextPathSplit = routerCore.removeTrailingSlash(
next.pathname,
router.basepath
).split("/");
const pathIsFuzzyEqual = nextPathSplit.every(
(d, i) => d === currentPathSplit[i]
);
if (!pathIsFuzzyEqual) {
return false;
}
}
if ((activeOptions == null ? void 0 : activeOptions.includeSearch) ?? true) {
const searchTest = routerCore.deepEqual(s.location.search, next.search, {
partial: !(activeOptions == null ? void 0 : activeOptions.exact),
ignoreUndefined: !(activeOptions == null ? void 0 : activeOptions.explicitUndefined)
});
if (!searchTest) {
return false;
}
}
if (activeOptions == null ? void 0 : activeOptions.includeHash) {
return s.location.hash === next.hash;
}
return true;
}
});
const doPreload = React__namespace.useCallback(() => {
router.preloadRoute(_options).catch((err) => {
console.warn(err);
console.warn(routerCore.preloadWarning);
});
}, [_options, router]);
const preloadViewportIoCallback = React__namespace.useCallback(
(entry) => {
if (entry == null ? void 0 : entry.isIntersecting) {
doPreload();
}
},
[doPreload]
);
utils.useIntersectionObserver(
innerRef,
preloadViewportIoCallback,
{ rootMargin: "100px" },
{ disabled: !!disabled || !(preload === "viewport") }
);
utils.useLayoutEffect(() => {
if (hasRenderFetched.current) {
return;
}
if (!disabled && preload === "render") {
doPreload();
hasRenderFetched.current = true;
}
}, [disabled, doPreload, preload]);
if (type === "external") {
return {
...propsSafeToSpread,
ref: innerRef,
type,
href: to,
...children && { children },
...target && { target },
...disabled && { disabled },
...style && { style },
...className && { className },
...onClick && { onClick },
...onFocus && { onFocus },
...onMouseEnter && { onMouseEnter },
...onMouseLeave && { onMouseLeave },
...onTouchStart && { onTouchStart }
};
}
const handleClick = (e) => {
if (!disabled && !isCtrlEvent(e) && !e.defaultPrevented && (!target || target === "_self") && e.button === 0) {
e.preventDefault();
reactDom.flushSync(() => {
setIsTransitioning(true);
});
const unsub = router.subscribe("onResolved", () => {
unsub();
setIsTransitioning(false);
});
return router.navigate({
..._options,
replace,
resetScroll,
hashScrollIntoView,
startTransition,
viewTransition,
ignoreBlocker
});
}
};
const handleFocus = (_) => {
if (disabled) return;
if (preload) {
doPreload();
}
};
const handleTouchStart = handleFocus;
const handleEnter = (e) => {
if (disabled) return;
const eventTarget = e.target || {};
if (preload) {
if (eventTarget.preloadTimeout) {
return;
}
eventTarget.preloadTimeout = setTimeout(() => {
eventTarget.preloadTimeout = null;
doPreload();
}, preloadDelay);
}
};
const handleLeave = (e) => {
if (disabled) return;
const eventTarget = e.target || {};
if (eventTarget.preloadTimeout) {
clearTimeout(eventTarget.preloadTimeout);
eventTarget.preloadTimeout = null;
}
};
const composeHandlers = (handlers) => (e) => {
var _a;
(_a = e.persist) == null ? void 0 : _a.call(e);
handlers.filter(Boolean).forEach((handler) => {
if (e.defaultPrevented) return;
handler(e);
});
};
const resolvedActiveProps = isActive ? routerCore.functionalUpdate(activeProps, {}) ?? {} : {};
const resolvedInactiveProps = isActive ? {} : routerCore.functionalUpdate(inactiveProps, {});
const resolvedClassName = [
className,
resolvedActiveProps.className,
resolvedInactiveProps.className
].filter(Boolean).join(" ");
const resolvedStyle = {
...style,
...resolvedActiveProps.style,
...resolvedInactiveProps.style
};
return {
...propsSafeToSpread,
...resolvedActiveProps,
...resolvedInactiveProps,
href: disabled ? void 0 : next.maskedLocation ? router.history.createHref(next.maskedLocation.href) : router.history.createHref(next.href),
ref: innerRef,
onClick: composeHandlers([onClick, handleClick]),
onFocus: composeHandlers([onFocus, handleFocus]),
onMouseEnter: composeHandlers([onMouseEnter, handleEnter]),
onMouseLeave: composeHandlers([onMouseLeave, handleLeave]),
onTouchStart: composeHandlers([onTouchStart, handleTouchStart]),
disabled: !!disabled,
target,
...Object.keys(resolvedStyle).length && { style: resolvedStyle },
...resolvedClassName && { className: resolvedClassName },
...disabled && {
role: "link",
"aria-disabled": true
},
...isActive && { "data-status": "active", "aria-current": "page" },
...isTransitioning && { "data-transitioning": "transitioning" }
};
}
function createLink(Comp) {
return React__namespace.forwardRef(function CreatedLink(props, ref) {
return /* @__PURE__ */ jsxRuntime.jsx(Link, { ...props, _asChild: Comp, ref });
});
}
const Link = React__namespace.forwardRef(
(props, ref) => {
const { _asChild, ...rest } = props;
const {
type: _type,
ref: innerRef,
...linkProps
} = useLinkProps(rest, ref);
const children = typeof rest.children === "function" ? rest.children({
isActive: linkProps["data-status"] === "active"
}) : rest.children;
if (typeof _asChild === "undefined") {
delete linkProps.disabled;
}
return React__namespace.createElement(
_asChild ? _asChild : "a",
{
...linkProps,
ref: innerRef
},
children
);
}
);
function isCtrlEvent(e) {
return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
}
const linkOptions = (options) => {
return options;
};
exports.Link = Link;
exports.createLink = createLink;
exports.linkOptions = linkOptions;
exports.useLinkProps = useLinkProps;
//# sourceMappingURL=link.cjs.map
;