@tanstack/solid-router
Version:
Modern and scalable routing for Solid applications
316 lines (315 loc) • 10.9 kB
JavaScript
const require_runtime = require("./_virtual/_rolldown/runtime.cjs");
const require_ClientOnly = require("./ClientOnly.cjs");
const require_useRouter = require("./useRouter.cjs");
const require_useRouterState = require("./useRouterState.cjs");
const require_utils = require("./utils.cjs");
let _tanstack_router_core = require("@tanstack/router-core");
let solid_js_web = require("solid-js/web");
let solid_js = require("solid-js");
solid_js = require_runtime.__toESM(solid_js);
let _solid_primitives_refs = require("@solid-primitives/refs");
let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer");
//#region src/link.tsx
var _tmpl$ = /* @__PURE__ */ (0, solid_js_web.template)(`<svg><a>`);
var timeoutMap = /* @__PURE__ */ new WeakMap();
function useLinkProps(options) {
const router = require_useRouter.useRouter();
const [isTransitioning, setIsTransitioning] = solid_js.createSignal(false);
const shouldHydrateHash = !_tanstack_router_core_isServer.isServer && !!router.options.ssr;
const hasHydrated = require_ClientOnly.useHydrated();
let hasRenderFetched = false;
const [local, rest] = solid_js.splitProps(solid_js.mergeProps({
activeProps: () => ({ class: "active" }),
inactiveProps: () => ({})
}, options), [
"activeProps",
"inactiveProps",
"activeOptions",
"to",
"preload",
"preloadDelay",
"hashScrollIntoView",
"replace",
"startTransition",
"resetScroll",
"viewTransition",
"target",
"disabled",
"style",
"class",
"onClick",
"onBlur",
"onFocus",
"onMouseEnter",
"onMouseLeave",
"onMouseOver",
"onMouseOut",
"onTouchStart",
"ignoreBlocker"
]);
const [_, propsSafeToSpread] = solid_js.splitProps(rest, [
"params",
"search",
"hash",
"state",
"mask",
"reloadDocument",
"unsafeRelative"
]);
const currentLocation = require_useRouterState.useRouterState({ select: (s) => s.location });
const buildLocationKey = require_useRouterState.useRouterState({ select: (s) => {
const leaf = s.matches[s.matches.length - 1];
return {
search: leaf?.search,
hash: s.location.hash,
path: leaf?.pathname
};
} });
const from = options.from;
const _options = () => {
return {
...options,
from
};
};
const next = solid_js.createMemo(() => {
buildLocationKey();
return router.buildLocation(_options());
});
const hrefOption = solid_js.createMemo(() => {
if (_options().disabled) return void 0;
const location = next().maskedLocation ?? next();
const publicHref = location.publicHref;
if (location.external) return {
href: publicHref,
external: true
};
return {
href: router.history.createHref(publicHref) || "/",
external: false
};
});
const externalLink = solid_js.createMemo(() => {
const _href = hrefOption();
if (_href?.external) {
if ((0, _tanstack_router_core.isDangerousProtocol)(_href.href, router.protocolAllowlist)) {
if (process.env.NODE_ENV !== "production") console.warn(`Blocked Link with dangerous protocol: ${_href.href}`);
return;
}
return _href.href;
}
const to = _options().to;
if (typeof to === "string" && to.charCodeAt(0) === 47 && to.charCodeAt(1) !== 47) return void 0;
try {
new URL(to);
if ((0, _tanstack_router_core.isDangerousProtocol)(to, router.protocolAllowlist)) {
if (process.env.NODE_ENV !== "production") console.warn(`Blocked Link with dangerous protocol: ${to}`);
return;
}
return to;
} catch {}
});
const preload = solid_js.createMemo(() => {
if (_options().reloadDocument || externalLink()) return false;
return local.preload ?? router.options.defaultPreload;
});
const preloadDelay = () => local.preloadDelay ?? router.options.defaultPreloadDelay ?? 0;
const isActive = solid_js.createMemo(() => {
if (externalLink()) return false;
if (local.activeOptions?.exact) {
if (!(0, _tanstack_router_core.exactPathTest)(currentLocation().pathname, next().pathname, router.basepath)) return false;
} else {
const currentPathSplit = (0, _tanstack_router_core.removeTrailingSlash)(currentLocation().pathname, router.basepath).split("/");
if (!((0, _tanstack_router_core.removeTrailingSlash)(next()?.pathname, router.basepath)?.split("/"))?.every((d, i) => d === currentPathSplit[i])) return false;
}
if (local.activeOptions?.includeSearch ?? true) {
if (!(0, _tanstack_router_core.deepEqual)(currentLocation().search, next().search, {
partial: !local.activeOptions?.exact,
ignoreUndefined: !local.activeOptions?.explicitUndefined
})) return false;
}
if (local.activeOptions?.includeHash) return (shouldHydrateHash && !hasHydrated() ? "" : currentLocation().hash) === next().hash;
return true;
});
const doPreload = () => router.preloadRoute(_options()).catch((err) => {
console.warn(err);
console.warn(_tanstack_router_core.preloadWarning);
});
const preloadViewportIoCallback = (entry) => {
if (entry?.isIntersecting) doPreload();
};
const [ref, setRef] = solid_js.createSignal(null);
require_utils.useIntersectionObserver(ref, preloadViewportIoCallback, { rootMargin: "100px" }, { disabled: !!local.disabled || !(preload() === "viewport") });
solid_js.createEffect(() => {
if (hasRenderFetched) return;
if (!local.disabled && preload() === "render") {
doPreload();
hasRenderFetched = true;
}
});
if (externalLink()) return solid_js.mergeProps(propsSafeToSpread, {
ref: (0, _solid_primitives_refs.mergeRefs)(setRef, _options().ref),
href: externalLink()
}, solid_js.splitProps(local, [
"target",
"disabled",
"style",
"class",
"onClick",
"onBlur",
"onFocus",
"onMouseEnter",
"onMouseLeave",
"onMouseOut",
"onMouseOver",
"onTouchStart"
])[0]);
const handleClick = (e) => {
const elementTarget = e.currentTarget.getAttribute("target");
const effectiveTarget = local.target !== void 0 ? local.target : elementTarget;
if (!local.disabled && !isCtrlEvent(e) && !e.defaultPrevented && (!effectiveTarget || effectiveTarget === "_self") && e.button === 0) {
e.preventDefault();
setIsTransitioning(true);
const unsub = router.subscribe("onResolved", () => {
unsub();
setIsTransitioning(false);
});
router.navigate({
..._options(),
replace: local.replace,
resetScroll: local.resetScroll,
hashScrollIntoView: local.hashScrollIntoView,
startTransition: local.startTransition,
viewTransition: local.viewTransition,
ignoreBlocker: local.ignoreBlocker
});
}
};
const enqueueIntentPreload = (e) => {
if (local.disabled || preload() !== "intent") return;
if (!preloadDelay()) {
doPreload();
return;
}
const eventTarget = e.currentTarget || e.target;
if (!eventTarget || timeoutMap.has(eventTarget)) return;
timeoutMap.set(eventTarget, setTimeout(() => {
timeoutMap.delete(eventTarget);
doPreload();
}, preloadDelay()));
};
const handleTouchStart = (_) => {
if (local.disabled || preload() !== "intent") return;
doPreload();
};
const handleLeave = (e) => {
if (local.disabled) return;
const eventTarget = e.currentTarget || e.target;
if (eventTarget) {
const id = timeoutMap.get(eventTarget);
clearTimeout(id);
timeoutMap.delete(eventTarget);
}
};
/** Call a JSX.EventHandlerUnion with the event. */
function callHandler(event, handler) {
if (handler) if (typeof handler === "function") handler(event);
else handler[0](handler[1], event);
return event.defaultPrevented;
}
function composeEventHandlers(handlers) {
return (event) => {
for (const handler of handlers) callHandler(event, handler);
};
}
const resolvedActiveProps = () => isActive() ? (0, _tanstack_router_core.functionalUpdate)(local.activeProps, {}) ?? {} : {};
const resolvedInactiveProps = () => isActive() ? {} : (0, _tanstack_router_core.functionalUpdate)(local.inactiveProps, {});
const resolvedClassName = () => [
local.class,
resolvedActiveProps().class,
resolvedInactiveProps().class
].filter(Boolean).join(" ");
const resolvedStyle = () => ({
...local.style,
...resolvedActiveProps().style,
...resolvedInactiveProps().style
});
return solid_js.mergeProps(propsSafeToSpread, resolvedActiveProps, resolvedInactiveProps, () => {
return {
href: hrefOption()?.href,
ref: (0, _solid_primitives_refs.mergeRefs)(setRef, _options().ref),
onClick: composeEventHandlers([local.onClick, handleClick]),
onBlur: composeEventHandlers([local.onBlur, handleLeave]),
onFocus: composeEventHandlers([local.onFocus, enqueueIntentPreload]),
onMouseEnter: composeEventHandlers([local.onMouseEnter, enqueueIntentPreload]),
onMouseOver: composeEventHandlers([local.onMouseOver, enqueueIntentPreload]),
onMouseLeave: composeEventHandlers([local.onMouseLeave, handleLeave]),
onMouseOut: composeEventHandlers([local.onMouseOut, handleLeave]),
onTouchStart: composeEventHandlers([local.onTouchStart, handleTouchStart]),
disabled: !!local.disabled,
target: local.target,
...(() => {
const s = resolvedStyle();
return Object.keys(s).length ? { style: s } : {};
})(),
...(() => {
const c = resolvedClassName();
return c ? { class: c } : {};
})(),
...local.disabled && {
role: "link",
"aria-disabled": true
},
...isActive() && {
"data-status": "active",
"aria-current": "page"
},
...isTransitioning() && { "data-transitioning": "transitioning" }
};
});
}
function createLink(Comp) {
return (props) => (0, solid_js_web.createComponent)(Link, (0, solid_js_web.mergeProps)(props, { _asChild: Comp }));
}
var Link = (props) => {
const [local, rest] = solid_js.splitProps(props, ["_asChild", "children"]);
const [_, linkProps] = solid_js.splitProps(useLinkProps(rest), ["type"]);
const children = solid_js.createMemo(() => {
const ch = local.children;
if (typeof ch === "function") return ch({
get isActive() {
return linkProps["data-status"] === "active";
},
get isTransitioning() {
return linkProps["data-transitioning"] === "transitioning";
}
});
return ch;
});
if (local._asChild === "svg") {
const [_, svgLinkProps] = solid_js.splitProps(linkProps, ["class"]);
return (() => {
var _el$ = _tmpl$(), _el$2 = _el$.firstChild;
(0, solid_js_web.spread)(_el$2, svgLinkProps, false, true);
(0, solid_js_web.insert)(_el$2, children);
return _el$;
})();
}
return (0, solid_js_web.createComponent)(solid_js_web.Dynamic, (0, solid_js_web.mergeProps)({ get component() {
return (0, solid_js_web.memo)(() => !!local._asChild)() ? local._asChild : "a";
} }, linkProps, { get children() {
return children();
} }));
};
function isCtrlEvent(e) {
return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
}
var linkOptions = (options) => {
return options;
};
//#endregion
exports.Link = Link;
exports.createLink = createLink;
exports.linkOptions = linkOptions;
exports.useLinkProps = useLinkProps;
//# sourceMappingURL=link.cjs.map