@tanstack/vue-router
Version:
Modern and scalable routing for Vue applications
147 lines (146 loc) • 4.54 kB
JavaScript
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