UNPKG

@tanstack/react-router

Version:

Modern and scalable routing for React applications

322 lines (321 loc) 9.79 kB
"use strict"; 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