Separate out into files
This commit is contained in:
117
packages/core/src/runtime/vue-router-bridge.ts
Normal file
117
packages/core/src/runtime/vue-router-bridge.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import type { App } from "vue";
|
||||
import {
|
||||
isNavigationFailure,
|
||||
loadRouteLocation,
|
||||
routeLocationKey,
|
||||
START_LOCATION,
|
||||
type NavigationFailure,
|
||||
type RouteLocationNormalizedLoaded,
|
||||
type RouteLocationRaw,
|
||||
type RouteLocationResolved,
|
||||
type Router,
|
||||
} from "vue-router";
|
||||
import type { NativeTransaction, NativeViewEntry } from "../types";
|
||||
import type { NativeHistoryLedger } from "./history-ledger";
|
||||
|
||||
export type NavigationResult = NavigationFailure | void | true;
|
||||
|
||||
export function isFailedNavigation(value: unknown) {
|
||||
return Boolean(value && isNavigationFailure(value));
|
||||
}
|
||||
|
||||
const nativeScopedRouteProperty = "__nativeVueRouterScopedRoute";
|
||||
|
||||
export class VueRouterBridge {
|
||||
private removeAfterEach?: () => void;
|
||||
private pendingPop?: (failure?: NavigationFailure | void) => void;
|
||||
|
||||
constructor(
|
||||
readonly router: Router,
|
||||
acceptRoute: (route: RouteLocationNormalizedLoaded) => void,
|
||||
) {
|
||||
this.removeAfterEach = router.afterEach((to, _from, failure) => {
|
||||
if (!failure) acceptRoute(to);
|
||||
this.pendingPop?.(failure);
|
||||
this.pendingPop = undefined;
|
||||
});
|
||||
}
|
||||
|
||||
installRouteScope(app: App) {
|
||||
// Vue Router's global `$route` always reads currentRoute. Preview trees
|
||||
// provide their own routeLocationKey, so bridge that injection to the
|
||||
// Options API too.
|
||||
app.mixin({
|
||||
inject: {
|
||||
[nativeScopedRouteProperty]: { from: routeLocationKey },
|
||||
},
|
||||
computed: {
|
||||
$route() {
|
||||
return (
|
||||
this as unknown as Record<
|
||||
typeof nativeScopedRouteProperty,
|
||||
RouteLocationNormalizedLoaded
|
||||
>
|
||||
)[nativeScopedRouteProperty];
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async initialRoute() {
|
||||
await this.router.isReady();
|
||||
return this.router.currentRoute.value === START_LOCATION
|
||||
? undefined
|
||||
: this.router.currentRoute.value;
|
||||
}
|
||||
|
||||
resolve(to: RouteLocationRaw) {
|
||||
return this.router.resolve(to);
|
||||
}
|
||||
|
||||
currentFullPath() {
|
||||
return this.router.currentRoute.value.fullPath;
|
||||
}
|
||||
|
||||
load(route: RouteLocationResolved) {
|
||||
return loadRouteLocation(route);
|
||||
}
|
||||
|
||||
async commit(
|
||||
transaction: NativeTransaction,
|
||||
target: NativeViewEntry,
|
||||
history: NativeHistoryLedger,
|
||||
): Promise<NavigationResult> {
|
||||
if (transaction.kind === "pop" || transaction.kind === "dismiss") {
|
||||
if (target.synthetic)
|
||||
return await this.router.replace(target.route.fullPath);
|
||||
return await this.navigateHistory(-1);
|
||||
}
|
||||
|
||||
if (transaction.replace) {
|
||||
const targetIndex = history.indexOf(target.key);
|
||||
if (targetIndex >= 0 && targetIndex < history.length - 1)
|
||||
return await this.navigateHistory(targetIndex - (history.length - 1));
|
||||
}
|
||||
|
||||
return transaction.replace
|
||||
? await this.router.replace(target.route.fullPath)
|
||||
: await this.router.push(target.route.fullPath);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.removeAfterEach?.();
|
||||
}
|
||||
|
||||
private async navigateHistory(delta: number) {
|
||||
return await new Promise<NavigationFailure | void>((resolve) => {
|
||||
this.pendingPop = resolve;
|
||||
this.router.go(delta);
|
||||
globalThis.setTimeout(() => {
|
||||
if (this.pendingPop === resolve) {
|
||||
this.pendingPop = undefined;
|
||||
resolve();
|
||||
}
|
||||
}, 1200);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user