import { NavigationTransition, NavigationTransitionNavigationType, NavigationTransitionWait, NavigationIntercept, } from "./navigation-transition"; import { Navigation } from "./navigation"; import { NavigationHistoryEntry } from "./navigation-entry"; import { InvalidStateError } from "./navigation-errors"; export interface NavigationTransitionPlannerOptions { transition: NavigationTransition; currentPlan?: NavigationTransitionPlan; finishedTransitions?: Set; constructNavigation(): Navigation; } export const NavigationTransitionPlanNavigationSymbol = Symbol.for( "@virtualstate/navigation/transition/plan/Navigation" ); export const NavigationTransitionPlanWhile = Symbol.for( "@virtualstate/navigation/transition/plan/while" ); export const NavigationTransitionPlanWait = Symbol.for( "@virtualstate/navigation/transition/plan/wait" ); export interface NavigationTransitionPlan { [NavigationTransitionPlanNavigationSymbol]: Navigation; [NavigationTransitionPlanWhile](promise: Promise): void; [NavigationTransitionPlanWait](): Promise>; transitions: NavigationTransition[]; known: Set>; knownTransitions: Set; resolve(): Promise; } export function plan(options: NavigationTransitionPlannerOptions) { const { transition, currentPlan, constructNavigation, finishedTransitions } = options; const nextPlan: NavigationTransitionPlan = { [NavigationTransitionPlanNavigationSymbol]: currentPlan?.[NavigationTransitionPlanNavigationSymbol] ?? constructNavigation(), transitions: [], ...currentPlan, knownTransitions: new Set(currentPlan?.knownTransitions ?? []), [NavigationTransitionPlanWhile]: transition[NavigationIntercept], [NavigationTransitionPlanWait]: transition[NavigationTransitionWait], }; if (nextPlan.knownTransitions.has(transition)) { throw new InvalidStateError( "Transition already found in plan, this may lead to unexpected behaviour, please raise an issue at " ); } nextPlan.knownTransitions.add(transition); if (transition[NavigationTransitionNavigationType] === "traverse") { nextPlan.transitions.push(transition); } else { // Reset on non traversal nextPlan.transitions = [].concat([transition]); } nextPlan.transitions = nextPlan.transitions // Remove finished transitions .filter((transition) => finishedTransitions?.has(transition)); return nextPlan; }