{"version":3,"file":"navigation.cjs","names":[],"sources":["../../src/navigation.ts"],"sourcesContent":["/**\n * @deijose/nix-ionic / navigation.ts\n *\n * NavigationManager — a single coordination authority for Ionic navigation.\n *\n * The IonRouterOutlet handles DOM rendering, transitions, and cache. The\n * NavigationManager handles:\n *   - Per-tab navigation stacks (extracted from the outlet)\n *   - Navigation state tracking (isTransitioning, pending navigation)\n *   - Navigation hooks (beforeNav, afterNav, onTabChange)\n *   - Programmatic tab switching\n *   - Route-pattern-based cache invalidation hooks\n *   - Guard coordination (delegated to the core router when auto-bootstrapped)\n *\n * The outlet delegates navigation state to the manager, keeping a clean\n * separation: navigation logic lives here, rendering lives in the outlet.\n *\n * @example\n * ```ts\n * import { NavigationManager } from \"@deijose/nix-ionic\";\n *\n * const nav = new NavigationManager({ tabs: [\"/home\", \"/search\", \"/profile\"] });\n *\n * // Navigation hooks\n * nav.beforeNav((path, intent) => {\n *   console.log(\"navigating to\", path);\n *   // return false to cancel\n * });\n * nav.afterNav((path) => {\n *   analytics.track(\"page_view\", { path });\n * });\n * nav.onTabChange((tab) => {\n *   console.log(\"active tab:\", tab);\n * });\n *\n * // Programmatic tab switching\n * nav.switchTab(\"/search\");\n *\n * // The outlet uses the manager for stack/state:\n * const outlet = new IonRouterOutlet(routes, { navigation: nav });\n * ```\n */\n\nimport { signal, type Signal, type NavigationIntent, type NavigationDirection } from \"@deijose/nix-js\";\n\n// --- Types ---\n\n/** A function called before navigation completes. Return false to cancel. */\nexport type BeforeNavHook = (\n    path: string,\n    intent: NavigationIntent,\n) => boolean | void | Promise<boolean | void>;\n\n/** A function called after navigation completes. */\nexport type AfterNavHook = (\n    path: string,\n    direction: NavigationDirection,\n) => void;\n\n/** A function called when the active tab changes. */\nexport type TabChangeHook = (\n    tab: string,\n    previousTab: string | null,\n) => void;\n\n/** Options for NavigationManager construction. */\nexport interface NavigationManagerOptions {\n    /** Tab prefixes for per-tab stack management. */\n    tabs?: string[];\n}\n\n// --- Per-tab stack management (extracted from IonRouterOutlet) ---\n\ninterface TabStack {\n    prefix: string;\n    entries: string[];\n}\n\n/**\n * Manages per-tab navigation stacks. Each tab has its own back/forward\n * stack. When the user switches tabs, the stack for the new tab is\n * restored.\n */\nexport class StackManager {\n    private _stacks = new Map<string, TabStack>();\n    private _activeTabKey: string;\n    private _tabPrefixes: string[];\n\n    constructor(tabs: string[] | undefined) {\n        this._stacks.set(\"\", { prefix: \"\", entries: [] });\n        if (tabs?.length) {\n            for (const prefix of tabs) {\n                const norm = this._normalize(prefix);\n                this._stacks.set(norm, { prefix: norm, entries: [] });\n            }\n            this._tabPrefixes = tabs.map((t) => this._normalize(t))\n                .sort((a, b) => b.length - a.length);\n        } else {\n            this._tabPrefixes = [];\n        }\n        this._activeTabKey = \"\";\n    }\n\n    /** Get the tab key for a given path. */\n    keyForPath(path: string): string {\n        for (const prefix of this._tabPrefixes) {\n            if (path === prefix || path.startsWith(prefix + \"/\")) {\n                return prefix;\n            }\n        }\n        return \"\";\n    }\n\n    /** Get the active tab key. */\n    get activeTabKey(): string {\n        return this._activeTabKey;\n    }\n\n    /** Get all registered tab prefixes. */\n    get tabPrefixes(): readonly string[] {\n        return this._tabPrefixes;\n    }\n\n    /** Get the current stack depth for a tab. */\n    stackDepth(tabKey?: string): number {\n        const key = tabKey ?? this._activeTabKey;\n        return this._stacks.get(key)?.entries.length ?? 0;\n    }\n\n    /** Get the top of the stack for a tab. */\n    stackTop(tabKey?: string): string | null {\n        const key = tabKey ?? this._activeTabKey;\n        const stack = this._stacks.get(key);\n        if (!stack || stack.entries.length === 0) return null;\n        return stack.entries[stack.entries.length - 1];\n    }\n\n    /** Get all entries in a tab's stack (copy). */\n    stackEntries(tabKey?: string): string[] {\n        const key = tabKey ?? this._activeTabKey;\n        return [...(this._stacks.get(key)?.entries ?? [])];\n    }\n\n    /**\n     * Apply a navigation to the stacks. Returns the effective direction.\n     * This is the same logic that was in IonRouterOutlet._stacks.apply().\n     */\n    apply(path: string, intent: NavigationIntent): NavigationDirection {\n        const targetKey = this.keyForPath(path);\n        const stack = this._stacks.get(targetKey)!;\n\n        if (targetKey !== this._activeTabKey) {\n            this._activeTabKey = targetKey;\n            const top = stack.entries[stack.entries.length - 1];\n            if (top !== path) stack.entries.push(path);\n            return \"none\";\n        }\n\n        if (intent.direction === \"back\") {\n            while (stack.entries.length > 0\n                && stack.entries[stack.entries.length - 1] !== path) {\n                stack.entries.pop();\n            }\n            if (stack.entries.length === 0) stack.entries.push(path);\n            return \"back\";\n        }\n\n        if (intent.action === \"replace\" || intent.direction === \"root\") {\n            if (stack.entries.length === 0) stack.entries.push(path);\n            else stack.entries[stack.entries.length - 1] = path;\n            return intent.direction === \"forward\" ? \"forward\" : \"root\";\n        }\n\n        if (intent.action === \"initial\") {\n            if (stack.entries.length === 0) stack.entries.push(path);\n            return \"none\";\n        }\n\n        const top = stack.entries[stack.entries.length - 1];\n        if (top !== path) stack.entries.push(path);\n        return intent.direction;\n    }\n\n    /** Reset a specific tab's stack. */\n    resetTab(tabKey: string): void {\n        const stack = this._stacks.get(tabKey);\n        if (stack) stack.entries = [];\n    }\n\n    /** Clear a specific tab's stack and return the paths that were in it. */\n    clearTabStack(tabKey: string): string[] {\n        const stack = this._stacks.get(tabKey);\n        if (!stack) return [];\n        const entries = [...stack.entries];\n        stack.entries = [];\n        return entries;\n    }\n\n    /** Reset all stacks. */\n    resetAll(): void {\n        for (const stack of this._stacks.values()) {\n            stack.entries = [];\n        }\n        this._activeTabKey = \"\";\n    }\n\n    private _normalize(p: string): string {\n        if (!p || p === \"/\") return \"/\";\n        return p.endsWith(\"/\") ? p.slice(0, -1) : p;\n    }\n}\n\n// --- NavigationManager ---\n\n/**\n * Single coordination authority for Ionic navigation.\n *\n * Wraps the per-tab stack manager and adds:\n *   - Navigation hooks (beforeNav, afterNav, onTabChange)\n *   - Transition state tracking (isTransitioning, pending)\n *   - Programmatic tab switching\n *   - Route-pattern-based cache invalidation hooks\n */\nexport class NavigationManager {\n    private _stacks: StackManager;\n    private _beforeNavHooks: BeforeNavHook[] = [];\n    private _afterNavHooks: AfterNavHook[] = [];\n    private _tabChangeHooks: TabChangeHook[] = [];\n    private _cacheInvalidationHandlers = new Map<string, (params?: Record<string, string>) => void>();\n\n    private _isTransitioning = false;\n    private _pendingNav: { path: string; intent: NavigationIntent } | null = null;\n    private _lastTabKey: string | null = null;\n\n    /** Reactive signal: true when the active tab has a back stack. */\n    readonly canGoBack: Signal<boolean>;\n\n    constructor(options: NavigationManagerOptions = {}) {\n        this._stacks = new StackManager(options.tabs);\n        this.canGoBack = signal(false);\n    }\n\n    // --- Stack access ---\n\n    get stacks(): StackManager {\n        return this._stacks;\n    }\n\n    get activeTab(): string {\n        return this._stacks.activeTabKey;\n    }\n\n    get tabPrefixes(): readonly string[] {\n        return this._stacks.tabPrefixes;\n    }\n\n    stackDepth(tabKey?: string): number {\n        return this._stacks.stackDepth(tabKey);\n    }\n\n    stackTop(tabKey?: string): string | null {\n        return this._stacks.stackTop(tabKey);\n    }\n\n    stackEntries(tabKey?: string): string[] {\n        return this._stacks.stackEntries(tabKey);\n    }\n\n    // --- Transition state ---\n\n    get isTransitioning(): boolean {\n        return this._isTransitioning;\n    }\n\n    get pendingNav(): { path: string; intent: NavigationIntent } | null {\n        return this._pendingNav;\n    }\n\n    /** Called by the outlet when a transition starts. */\n    beginTransition(): void {\n        this._isTransitioning = true;\n    }\n\n    /** Called by the outlet when a transition ends. */\n    endTransition(): void {\n        this._isTransitioning = false;\n    }\n\n    /** Queue a pending navigation (called by the outlet when already transitioning). */\n    setPendingNav(path: string, intent: NavigationIntent): void {\n        this._pendingNav = { path, intent };\n    }\n\n    /** Clear pending navigation. */\n    clearPendingNav(): void {\n        this._pendingNav = null;\n    }\n\n    /** Consume and return the pending navigation, if any. */\n    consumePendingNav(): { path: string; intent: NavigationIntent } | null {\n        const pending = this._pendingNav;\n        this._pendingNav = null;\n        return pending;\n    }\n\n    // --- Navigation hooks ---\n\n    /**\n     * Register a hook called before navigation completes.\n     * Return `false` to cancel the navigation.\n     * Multiple hooks are called in registration order.\n     */\n    beforeNav(hook: BeforeNavHook): () => void {\n        this._beforeNavHooks.push(hook);\n        return () => {\n            const i = this._beforeNavHooks.indexOf(hook);\n            if (i >= 0) this._beforeNavHooks.splice(i, 1);\n        };\n    }\n\n    /**\n     * Register a hook called after navigation completes.\n     */\n    afterNav(hook: AfterNavHook): () => void {\n        this._afterNavHooks.push(hook);\n        return () => {\n            const i = this._afterNavHooks.indexOf(hook);\n            if (i >= 0) this._afterNavHooks.splice(i, 1);\n        };\n    }\n\n    /**\n     * Register a hook called when the active tab changes.\n     */\n    onTabChange(hook: TabChangeHook): () => void {\n        this._tabChangeHooks.push(hook);\n        return () => {\n            const i = this._tabChangeHooks.indexOf(hook);\n            if (i >= 0) this._tabChangeHooks.splice(i, 1);\n        };\n    }\n\n    /**\n     * Run beforeNav hooks. Returns true if all hooks allow navigation,\n     * false if any hook cancelled.\n     */\n    async runBeforeNav(path: string, intent: NavigationIntent): Promise<boolean> {\n        for (const hook of this._beforeNavHooks) {\n            try {\n                const result = await hook(path, intent);\n                if (result === false) return false;\n            } catch {\n                // Hook error — don't block navigation\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Run afterNav hooks. Called by the outlet after a transition completes.\n     */\n    runAfterNav(path: string, direction: NavigationDirection): void {\n        for (const hook of this._afterNavHooks) {\n            try {\n                hook(path, direction);\n            } catch { /* ignore */ }\n        }\n    }\n\n    /**\n     * Run tab change hooks if the tab actually changed.\n     */\n    runTabChangeIfNeeded(currentPath: string): void {\n        const newTab = this._stacks.keyForPath(currentPath);\n        if (newTab !== this._lastTabKey) {\n            const prev = this._lastTabKey;\n            this._lastTabKey = newTab;\n            for (const hook of this._tabChangeHooks) {\n                try {\n                    hook(newTab, prev);\n                } catch { /* ignore */ }\n            }\n        }\n    }\n\n    /**\n     * Update the reactive `canGoBack` signal based on the active tab's\n     * stack depth. Called by the outlet after each transition.\n     */\n    updateCanGoBack(): void {\n        this.canGoBack.value = this._stacks.stackDepth() > 1;\n    }\n\n    // --- Programmatic tab switching ---\n\n    /**\n     * Switch to a specific tab. Navigates to the tab's current stack top,\n     * or the tab prefix if the stack is empty.\n     *\n     * @example\n     * ```ts\n     * nav.switchTab(\"/search\"); // switches to the search tab\n     * ```\n     */\n    switchTab(tabPrefix: string): string | null {\n        const normalized = this._stacks.keyForPath(tabPrefix);\n        if (normalized === this._stacks.activeTabKey) return null;\n        const top = this._stacks.stackTop(normalized);\n        return top ?? tabPrefix;\n    }\n\n    // --- Cache invalidation by route pattern ---\n\n    /**\n     * Register a cache invalidation handler for a route pattern.\n     * The outlet registers handlers for each route on construction.\n     *\n     * @example\n     * ```ts\n     * nav.registerInvalidationHandler(\"/user/:id\", (params) => {\n     *   // called when invalidateRoute(\"/user/:id\", { id: \"42\" }) is invoked\n     * });\n     * ```\n     */\n    registerInvalidationHandler(\n        routePattern: string,\n        handler: (params?: Record<string, string>) => void,\n    ): () => void {\n        this._cacheInvalidationHandlers.set(routePattern, handler);\n        return () => {\n            this._cacheInvalidationHandlers.delete(routePattern);\n        };\n    }\n\n    /**\n     * Invalidate cached pages for a specific route pattern + params.\n     * If the route has dynamic segments, provide params to target a\n     * specific instance. Omit params to invalidate all instances.\n     *\n     * @example\n     * ```ts\n     * nav.invalidateRoute(\"/user/:id\", { id: \"42\" }); // invalidate user 42\n     * nav.invalidateRoute(\"/search\"); // invalidate all search instances\n     * ```\n     */\n    invalidateRoute(\n        routePattern: string,\n        params?: Record<string, string>,\n    ): void {\n        const handler = this._cacheInvalidationHandlers.get(routePattern);\n        if (handler) handler(params);\n    }\n\n    /**\n     * Invalidate all cached pages matching a glob pattern.\n     * Supports `*` as a wildcard suffix.\n     *\n     * @example\n     * ```ts\n     * nav.invalidatePattern(\"/admin/*\"); // invalidate all admin pages\n     * nav.invalidatePattern(\"/*\");       // invalidate everything\n     * ```\n     */\n    invalidatePattern(pattern: string): void {\n        const isWildcard = pattern.endsWith(\"/*\");\n        const prefix = isWildcard ? pattern.slice(0, -2) : pattern;\n\n        for (const routePattern of this._cacheInvalidationHandlers.keys()) {\n            if (isWildcard) {\n                if (routePattern === prefix || routePattern.startsWith(prefix + \"/\") ||\n                    routePattern.startsWith(prefix + \":\")) {\n                    this._cacheInvalidationHandlers.get(routePattern)?.();\n                }\n            } else if (routePattern === pattern) {\n                this._cacheInvalidationHandlers.get(routePattern)?.();\n            }\n        }\n    }\n\n    // --- Cleanup ---\n\n    /** Reset all navigation state (stacks, hooks, pending). */\n    dispose(): void {\n        this._stacks.resetAll();\n        this._beforeNavHooks = [];\n        this._afterNavHooks = [];\n        this._tabChangeHooks = [];\n        this._cacheInvalidationHandlers.clear();\n        this._pendingNav = null;\n        this._isTransitioning = false;\n        this._lastTabKey = null;\n    }\n}\n"],"mappings":"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"}