UNPKG

@tanstack/vue-router

Version:

Modern and scalable routing for Vue applications

147 lines (146 loc) 4.54 kB
import { useRouter } from "./useRouter.js"; import { usePrevious } from "./utils.js"; import { getLocationChangeInfo, trimPathRight } from "@tanstack/router-core"; import * as Vue from "vue"; import { isServer } from "@tanstack/router-core/isServer"; import { batch, useStore } from "@tanstack/vue-store"; //#region src/Transitioner.tsx var mountLoadForRouter = { router: null, mounted: false }; /** * Composable that sets up router transition logic. * This is called from MatchesContent to set up: * - router.startTransition * - router.startViewTransition * - History subscription * - Router event watchers * * Must be called during component setup phase. */ function useTransitionerSetup() { const router = useRouter(); if (isServer ?? router.isServer) return; const isLoading = useStore(router.stores.isLoading, (value) => value); const isTransitioning = Vue.ref(false); const hasPending = useStore(router.stores.hasPending, (value) => value); const previousIsLoading = usePrevious(() => isLoading.value); const isAnyPending = Vue.computed(() => isLoading.value || isTransitioning.value || hasPending.value); const previousIsAnyPending = usePrevious(() => isAnyPending.value); const isPagePending = Vue.computed(() => isLoading.value || hasPending.value); const previousIsPagePending = usePrevious(() => isPagePending.value); router.startTransition = (fn) => { isTransitioning.value = true; try { router.stores.isTransitioning.set(true); } catch {} const endTransition = () => { Vue.nextTick(() => { try { isTransitioning.value = false; router.stores.isTransitioning.set(false); } catch {} }); }; fn(); endTransition(); }; const originalStartViewTransition = router.__tsrOriginalStartViewTransition ?? router.startViewTransition; router.__tsrOriginalStartViewTransition = originalStartViewTransition; router.startViewTransition = (fn) => { return originalStartViewTransition?.(async () => { await fn(); await Vue.nextTick(); }); }; let unsubscribe; Vue.onMounted(() => { unsubscribe = router.history.subscribe(router.load); const nextLocation = router.buildLocation({ to: router.latestLocation.pathname, search: true, params: true, hash: true, state: true, _includeValidateSearch: true }); if (trimPathRight(router.latestLocation.publicHref) !== trimPathRight(nextLocation.publicHref)) router.commitLocation({ ...nextLocation, replace: true }); }); const isMounted = Vue.ref(false); Vue.onMounted(() => { isMounted.value = true; if (!isAnyPending.value) { if (router.stores.status.get() === "pending") batch(() => { router.stores.status.set("idle"); router.stores.resolvedLocation.set(router.stores.location.get()); }); } }); Vue.onUnmounted(() => { isMounted.value = false; if (unsubscribe) unsubscribe(); }); Vue.onMounted(() => { if (typeof window !== "undefined" && router.ssr || mountLoadForRouter.router === router && mountLoadForRouter.mounted) return; mountLoadForRouter = { router, mounted: true }; const tryLoad = async () => { try { await router.load(); } catch (err) { console.error(err); } }; tryLoad(); }); Vue.watch(() => isLoading.value, (newValue) => { if (!isMounted.value) return; try { if (previousIsLoading.value.previous && !newValue) router.emit({ type: "onLoad", ...getLocationChangeInfo(router.stores.location.get(), router.stores.resolvedLocation.get()) }); } catch {} }); Vue.watch(isPagePending, (newValue) => { if (!isMounted.value) return; try { if (previousIsPagePending.value.previous && !newValue) router.emit({ type: "onBeforeRouteMount", ...getLocationChangeInfo(router.stores.location.get(), router.stores.resolvedLocation.get()) }); } catch {} }); Vue.watch(isAnyPending, (newValue) => { if (!isMounted.value) return; try { if (!newValue && router.stores.status.get() === "pending") batch(() => { router.stores.status.set("idle"); router.stores.resolvedLocation.set(router.stores.location.get()); }); if (previousIsAnyPending.value.previous && !newValue) { const changeInfo = getLocationChangeInfo(router.stores.location.get(), router.stores.resolvedLocation.get()); router.emit({ type: "onResolved", ...changeInfo }); } } catch {} }); } Vue.defineComponent({ name: "Transitioner", setup() { useTransitionerSetup(); return () => null; } }); //#endregion export { useTransitionerSetup }; //# sourceMappingURL=Transitioner.js.map