Add experiments folder. Add usage.md and SKILL.md. Fix Sheet interactions and add dynamic sheet mode.

This commit is contained in:
2026-07-22 07:04:39 +00:00
parent bfe364c57d
commit 6aed7606ad
48 changed files with 5454 additions and 84 deletions
+49 -1
View File
@@ -9,6 +9,7 @@ import {
import {
isNavigationFailure,
loadRouteLocation,
routeLocationKey,
START_LOCATION,
type NavigationFailure,
type RouteLocationNormalizedLoaded,
@@ -32,6 +33,7 @@ import type {
} from "./types";
export const nativeRouterKey = Symbol("native-vue-router");
const nativeScopedRouteProperty = "__nativeVueRouterScopedRoute";
let entrySequence = 0;
@@ -55,6 +57,8 @@ function entryFor(
return {
key: `${route.fullPath}::${++entrySequence}`,
route,
presentation:
route.meta.native?.presentation ?? route.meta.native?.transition,
status,
mounted: true,
synthetic,
@@ -192,6 +196,24 @@ class NativeRouterRuntimeImpl implements NativeRouterRuntime {
install(app: App) {
app.provide(nativeRouterKey, this);
app.config.globalProperties.$nativeRouter = this;
// Vue Router's global `$route` getter always reads currentRoute. Preview
// trees instead provide their target through routeLocationKey, so bridge
// that injection into the Options API as well as useRoute().
app.mixin({
inject: {
[nativeScopedRouteProperty]: { from: routeLocationKey },
},
computed: {
$route() {
return (
this as unknown as Record<
typeof nativeScopedRouteProperty,
RouteLocationNormalizedLoaded
>
)[nativeScopedRouteProperty];
},
},
});
void this.router.isReady().then(() => {
if (
this.mutableEntries.value.length === 0 &&
@@ -379,6 +401,13 @@ class NativeRouterRuntimeImpl implements NativeRouterRuntime {
? this.siblingDirection(from.route, target.route)
: "forward");
if (isBack) {
from.presentation ??= presentation;
} else {
target.presentation = presentation;
target.underlayKey = presentation === "sheet" ? from.key : undefined;
}
const transaction: NativeTransaction = {
id: ++this.transactionSequence,
kind,
@@ -733,6 +762,7 @@ class NativeRouterRuntimeImpl implements NativeRouterRuntime {
to: RouteLocationNormalizedLoaded,
_from: RouteLocationNormalizedLoaded,
) {
const previousActiveKey = this.mutableActiveKey.value;
const transaction = this.mutableTransaction.value;
let target = transaction ? this.entryByKey(transaction.toKey) : undefined;
if (target && target.route.fullPath !== to.fullPath) target = undefined;
@@ -750,6 +780,8 @@ class NativeRouterRuntimeImpl implements NativeRouterRuntime {
this.mutableEntries.value = [...head, target];
} else {
target.route = to;
target.presentation ??=
to.meta.native?.presentation ?? to.meta.native?.transition;
target.mounted = true;
target.status = "active";
target.committed = true;
@@ -757,6 +789,8 @@ class NativeRouterRuntimeImpl implements NativeRouterRuntime {
target.evictionReason = undefined;
this.touchEntries();
}
if (target.presentation === "sheet" && target.key !== previousActiveKey)
target.underlayKey = previousActiveKey || undefined;
this.mutableActiveKey.value = target.key;
this.acceptHistory(target, transaction);
this.markStatuses();
@@ -857,6 +891,16 @@ class NativeRouterRuntimeImpl implements NativeRouterRuntime {
}
private enforceCache() {
const protectedUnderlayKeys = new Set<string>();
let presentedEntry = this.activeEntry();
while (
presentedEntry?.presentation === "sheet" &&
presentedEntry.underlayKey &&
!protectedUnderlayKeys.has(presentedEntry.underlayKey)
) {
protectedUnderlayKeys.add(presentedEntry.underlayKey);
presentedEntry = this.entryByKey(presentedEntry.underlayKey);
}
const inactive = this.mutableEntries.value
.filter(
(entry) =>
@@ -866,6 +910,7 @@ class NativeRouterRuntimeImpl implements NativeRouterRuntime {
)
.sort((a, b) => b.lastUsed - a.lastUsed);
for (const entry of inactive) {
if (protectedUnderlayKeys.has(entry.key)) continue;
if (!this.shouldRetainInactive(entry)) {
const reason: NativeEvictionReason =
entry.route.meta.native?.cache === false
@@ -875,7 +920,10 @@ class NativeRouterRuntimeImpl implements NativeRouterRuntime {
}
}
const retained = inactive.filter(
(entry) => entry.mounted && entry.route.meta.native?.cache !== "pin",
(entry) =>
entry.mounted &&
entry.route.meta.native?.cache !== "pin" &&
!protectedUnderlayKeys.has(entry.key),
);
for (const entry of retained.slice(this.maxInactive)) {
this.evictEntry(entry, "cache-limit");