@tanstack/vue-router
Version:
Modern and scalable routing for Vue applications
154 lines (153 loc) • 4.51 kB
JavaScript
import { useRouter } from "./useRouter.js";
import { useRouterState } from "./useRouterState.js";
import { usePrevious } from "./utils.js";
import { getLocationChangeInfo, handleHashScroll, trimPathRight } from "@tanstack/router-core";
import * as Vue from "vue";
import { isServer } from "@tanstack/router-core/isServer";
//#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 = useRouterState({ select: ({ isLoading }) => isLoading });
const isTransitioning = Vue.ref(false);
const hasPendingMatches = useRouterState({ select: (s) => s.matches.some((d) => d.status === "pending") });
const previousIsLoading = usePrevious(() => isLoading.value);
const isAnyPending = Vue.computed(() => isLoading.value || isTransitioning.value || hasPendingMatches.value);
const previousIsAnyPending = usePrevious(() => isAnyPending.value);
const isPagePending = Vue.computed(() => isLoading.value || hasPendingMatches.value);
const previousIsPagePending = usePrevious(() => isPagePending.value);
router.startTransition = (fn) => {
isTransitioning.value = true;
try {
router.__store.setState((s) => ({
...s,
isTransitioning: true
}));
} catch {}
const endTransition = () => {
Vue.nextTick(() => {
try {
isTransitioning.value = false;
router.__store.setState((s) => ({
...s,
isTransitioning: 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) router.__store.setState((s) => s.status === "pending" ? {
...s,
status: "idle",
resolvedLocation: s.location
} : s);
});
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.state)
});
} catch {}
});
Vue.watch(isPagePending, (newValue) => {
if (!isMounted.value) return;
try {
if (previousIsPagePending.value.previous && !newValue) router.emit({
type: "onBeforeRouteMount",
...getLocationChangeInfo(router.state)
});
} catch {}
});
Vue.watch(isAnyPending, (newValue) => {
if (!isMounted.value) return;
try {
if (!newValue && router.__store.state.status === "pending") router.__store.setState((s) => ({
...s,
status: "idle",
resolvedLocation: s.location
}));
if (previousIsAnyPending.value.previous && !newValue) {
const changeInfo = getLocationChangeInfo(router.state);
router.emit({
type: "onResolved",
...changeInfo
});
if (changeInfo.hrefChanged) handleHashScroll(router);
}
} catch {}
});
}
Vue.defineComponent({
name: "Transitioner",
setup() {
useTransitionerSetup();
return () => null;
}
});
//#endregion
export { useTransitionerSetup };
//# sourceMappingURL=Transitioner.js.map