@ng-native/router 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -76,8 +76,9 @@ export declare class NativeNavigation {
76
76
  /**
77
77
  * Pop straight back to the screen at `commands`, taking every screen above it off the stack at
78
78
  * once - `popToViewController`. The screen is the one already there, with its state, not a new
79
- * one. Resolves false, doing nothing, when no screen below the top of a stack in front is
80
- * showing that url; a push is the way to a screen that is not there.
79
+ * one; where that url is also the one showing, the screen on top is the one kept. Resolves
80
+ * false, doing nothing, when no screen below the top of a stack in front is showing that url; a
81
+ * push is the way to a screen that is not there.
81
82
  */
82
83
  popTo(commands: NavigationCommands): Promise<boolean>;
83
84
  /**
@@ -186,8 +186,9 @@ export class NativeNavigation {
186
186
  /**
187
187
  * Pop straight back to the screen at `commands`, taking every screen above it off the stack at
188
188
  * once - `popToViewController`. The screen is the one already there, with its state, not a new
189
- * one. Resolves false, doing nothing, when no screen below the top of a stack in front is
190
- * showing that url; a push is the way to a screen that is not there.
189
+ * one; where that url is also the one showing, the screen on top is the one kept. Resolves
190
+ * false, doing nothing, when no screen below the top of a stack in front is showing that url; a
191
+ * push is the way to a screen that is not there.
191
192
  */
192
193
  popTo(commands) {
193
194
  const tree = typeof commands === 'string'
@@ -1 +1 @@
1
- {"version":3,"file":"native-navigation.js","sourceRoot":"","sources":["../src/native-navigation.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The typed facade over `Router` for the intents a URL cannot express (ADR 0003).\n *\n * Angular's `Router` stays the single source of truth: each of these is a line over\n * `router.navigate`, setting `replaceUrl` and a presentation on `NavigationExtras.state`. Deep\n * links, guards and resolvers keep working because it is still the Router, and because state\n * rides in history a back restores the presentation the screen was opened with.\n *\n * A navigation service that owns the stack was rejected: it either re-implements guards,\n * resolvers and deep linking, or it drifts from the URL, and once the stack is not derived from\n * router state the two can disagree.\n *\n * No decorators, so tests can import it at runtime and so it can be provided with `useClass`,\n * exactly as `NativePlatformLocation` and `NativeStackReuseStrategy` are.\n */\nimport { DestroyRef, inject } from '@angular/core';\nimport {\n NavigationCancel,\n NavigationCancellationCode,\n NavigationEnd,\n NavigationError,\n NavigationSkipped,\n NavigationSkippedCode,\n Router,\n type Navigation,\n type NavigationExtras,\n} from '@angular/router';\nimport { NativeBack } from './native-back.ts';\nimport type { ScreenPresentation, StackPresentation } from './screen-presentation.ts';\nimport { leavingPresented, presentedCommands } from './presented-route.ts';\n\n/** What `Router` takes: a url string, or the array form with segments and params. */\nexport type NavigationCommands = string | readonly unknown[];\n\n/**\n * Where the intent rides. `NavigationExtras.state` is the app's own object, so ours sits under\n * one reserved key rather than spread through it.\n */\nexport const NATIVE_INTENT = 'ɵnativeStack';\n\n/** What a navigation asks the outlet to do with the stack, over and above rendering the route. */\nexport interface NativeIntent {\n /** `replace` drops the screen it supersedes; `reset` empties the stack first. */\n readonly stack?: 'push' | 'replace' | 'reset';\n readonly presentation?: ScreenPresentation;\n}\n\nexport interface NativeNavigationOptions extends NavigationExtras {\n /** How the screen arrives: presentation, animation, gesture and sheet props. */\n presentation?: ScreenPresentation;\n}\n\nexport interface PresentOptions extends NativeNavigationOptions {\n /** Shorthand for `presentation.stackPresentation`. Defaults to `modal`. */\n as?: StackPresentation;\n}\n\n/** A url string up to its query or fragment. */\nconst pathOf = (url: string): string => url.split(/[?#]/, 1)[0]!;\n\n/** Read the intent off a navigation's state, if it carries one. */\nexport function intentOf(state: unknown): NativeIntent | null {\n if (!state || typeof state !== 'object') return null;\n const intent = (state as Record<string, unknown>)[NATIVE_INTENT];\n return intent && typeof intent === 'object' ? (intent as NativeIntent) : null;\n}\n\n/**\n * The intent of a navigation a guard redirected, for the navigation the redirect starts.\n *\n * The router starts a new navigation for a guard's `UrlTree`, keeping `replaceUrl` but not\n * `state`, so a reset to a page that sends a signed-out user to sign in would push the sign-in\n * page over the stack it was meant to clear. Held for that one navigation by its id, which no\n * later navigation shares.\n */\nconst redirected = new WeakMap<object, { readonly id: number; readonly intent: NativeIntent }>();\n\n/** What a navigation asks of the stack: its own intent, or the one it was redirected from. */\nexport function navigationIntent(\n router: object,\n navigation: Pick<Navigation, 'id' | 'extras'> | null | undefined,\n): NativeIntent | null {\n if (!navigation) return null;\n const own = intentOf(navigation.extras.state);\n if (own) return own;\n const carried = redirected.get(router);\n return carried?.id === navigation.id ? carried.intent : null;\n}\n\n/**\n * Hand a navigation's intent on to the one its guard redirects it to. The router schedules that\n * navigation as soon as it has reported the cancel, so it takes the next id.\n *\n * A reset that lands on the screen already on top, its own url or the one a redirect sends it to,\n * is one no outlet activates anything for: the router skips the url already showing, and reuses\n * the screen for another url of it. So the stack is reset here, to the screen on top.\n */\nexport function carryIntentAcrossRedirects(): void {\n const router = inject(Router);\n const outlets = inject(NativeBack);\n const events = router.events.subscribe((event) => {\n if (event instanceof NavigationCancel && event.code === NavigationCancellationCode.Redirect) {\n carryPast(router, event.id);\n return;\n }\n if (keptTop(event, outlets) && intentAt(router, event.id)?.stack === 'reset') {\n outlets.resetToTop();\n }\n if (ended(event) && redirected.get(router)?.id === event.id) redirected.delete(router);\n });\n inject(DestroyRef).onDestroy(() => events.unsubscribe());\n}\n\n/**\n * Whether the navigation `event` ends left the screen on top where it was: one the router skipped\n * for the url already showing, or one no stack put a screen on top for, such as a url with another\n * query, or one a redirect sends to the page on top.\n */\nfunction keptTop(event: unknown, outlets: NativeBack): event is { readonly id: number } {\n if (event instanceof NavigationSkipped) {\n return event.code === NavigationSkippedCode.IgnoredSameUrlNavigation;\n }\n return event instanceof NavigationEnd && !outlets.stackedIn(event.id);\n}\n\n/** The intent of the navigation in progress, when it is the one with `id`. */\nfunction intentAt(router: Router, id: number): NativeIntent | null {\n const navigation = router.currentNavigation();\n return navigation?.id === id ? navigationIntent(router, navigation) : null;\n}\n\n/** Hold the intent of the navigation a guard redirected for the one the redirect starts. */\nfunction carryPast(router: Router, id: number): void {\n const intent = intentAt(router, id);\n if (intent) redirected.set(router, { id: id + 1, intent });\n else redirected.delete(router);\n}\n\n/** Whether the event is the last a navigation reports. */\nfunction ended(event: unknown): event is { readonly id: number } {\n return (\n event instanceof NavigationEnd ||\n event instanceof NavigationCancel ||\n event instanceof NavigationError ||\n event instanceof NavigationSkipped\n );\n}\n\nexport class NativeNavigation {\n private readonly router = inject(Router);\n private readonly outlets = inject(NativeBack);\n\n /**\n * Push a new screen onto the stack. The plain case, and what `nativeRouterLink` does.\n *\n * From a presented screen the new one is presented the same way, over it, since a pushed\n * screen would slide in under it; `presentation` says otherwise, `stackAnimation` and all.\n */\n push(commands: NavigationCommands, options: NativeNavigationOptions = {}): Promise<boolean> {\n return this.go(commands, options, { stack: 'push' });\n }\n\n /**\n * Swap the current screen for another. The history entry is replaced too, so a back from the\n * new screen goes where a back from the old one would have.\n */\n replace(commands: NavigationCommands, options: NavigationExtras = {}): Promise<boolean> {\n return this.go(commands, { ...options, replaceUrl: true }, { stack: 'replace' });\n }\n\n /**\n * Present a screen over the stack rather than pushing into it: a modal, or a sheet.\n *\n * `present('/filters', { as: 'formSheet', presentation: { sheetAllowedDetents: [0.5, 1] } })`.\n *\n * A presented screen is put on screen outside the stack's navigation controller, so it has no\n * native header and no automatic safe-area insets: it needs its own way out, and its own\n * `safe-area-view`. A sheet can also be dragged away, but `fullScreenModal` cannot, and with\n * `gestureEnabled: false` neither can.\n */\n present(commands: NavigationCommands, options: PresentOptions = {}): Promise<boolean> {\n const { as = 'modal', presentation, ...extras } = options;\n const intent: NativeIntent = {\n stack: 'push',\n presentation: { stackPresentation: as, ...presentation },\n };\n // Asked at once, and only waited for when the page is another tab's: finding its route may\n // load a lazy one.\n const over = this.overTheTabInFront(commands, extras);\n if (!over) return this.go(commands, extras, intent);\n return over.then((found) =>\n this.go(found?.commands ?? commands, found?.extras ?? extras, intent),\n );\n }\n\n /**\n * Replace the whole stack with one screen, the way signing out or finishing onboarding does.\n * Every screen below is destroyed, so there is nothing to go back to.\n */\n reset(commands: NavigationCommands, options: NavigationExtras = {}): Promise<boolean> {\n return this.go(commands, { ...options, replaceUrl: true }, { stack: 'reset' });\n }\n\n /**\n * Go back exactly as the Android back button does: pop the stack in front, or at the root of a\n * tab's stack, go to the first tab. Not one entry back through history, which after a trip to\n * another tab is that tab. At the root of the app there is nowhere to go, and this does nothing.\n */\n back(): void {\n // Optional call: a test that stands a plain object in for the router has no such signal.\n if (!this.router.currentNavigation?.()) {\n this.outlets.back();\n return;\n }\n // Asked while a navigation is still putting its screen up: a page that leaves as it appears,\n // from an effect in its constructor. No stack has that screen to pop yet, so the back waits\n // for the navigation, and goes nowhere if the navigation does not arrive.\n if (this.backWaiting) return;\n this.backWaiting = this.router.events.subscribe((event) => {\n const ended = event instanceof NavigationEnd;\n if (!ended && !(event instanceof NavigationCancel) && !(event instanceof NavigationError)) {\n return;\n }\n this.backWaiting?.unsubscribe();\n this.backWaiting = null;\n if (ended) this.outlets.back();\n });\n }\n\n /** The wait of a back asked for mid-navigation, so two asked for in one are one. */\n private backWaiting: { unsubscribe(): void } | null = null;\n\n /**\n * Pop straight back to the screen at `commands`, taking every screen above it off the stack at\n * once - `popToViewController`. The screen is the one already there, with its state, not a new\n * one. Resolves false, doing nothing, when no screen below the top of a stack in front is\n * showing that url; a push is the way to a screen that is not there.\n */\n popTo(commands: NavigationCommands): Promise<boolean> {\n const tree =\n typeof commands === 'string'\n ? this.router.parseUrl(commands)\n : this.router.createUrlTree([...commands]);\n return this.outlets.popTo(this.router.serializeUrl(tree));\n }\n\n /**\n * Pop the stack in front to its first screen - `popToRootViewController`. Inside a tab, that is\n * the tab's first screen; the screens below keep their state. Resolves false at the root already.\n */\n popToRoot(): Promise<boolean> {\n return this.outlets.popToRoot();\n }\n\n private go(\n commands: NavigationCommands,\n options: NativeNavigationOptions,\n intent: NativeIntent,\n ): Promise<boolean> {\n const { presentation, state, ...extras } = options;\n const full: NativeIntent = presentation\n ? { ...intent, presentation: { ...intent.presentation, ...presentation } }\n : intent;\n\n const navigate = () => {\n const list = typeof commands === 'string' ? [pathOf(commands)] : [...commands];\n const all = {\n ...extras,\n ...(typeof commands === 'string' ? this.queryOf(commands, extras) : {}),\n state: { ...(state as object), [NATIVE_INTENT]: full },\n };\n const leaving = leavingPresented(this.router, list, all);\n return leaving ? this.router.navigateByUrl(leaving, all) : this.router.navigate(list, all);\n };\n // A screen stacked on the first one waits for it. Navigating while the router's first\n // navigation is still running - a lazily loaded root waiting on its import - cancels that\n // navigation, and the app opens on this screen with nothing beneath it. A reset replaces the\n // stack anyway, so it goes at once.\n const start = () => this.underTabRoot(commands, extras, full, navigate);\n return intent.stack !== 'reset' && this.firstNavigationRunning()\n ? this.firstNavigation().then(start)\n : start();\n }\n\n /**\n * A push into a tab nobody has opened goes to the tab first, so its stack has the tab's own\n * first screen under the page, and a back from the page lands there: what a tab bar with a\n * navigation controller per tab does. Without it the page is the stack's only screen, and the\n * same push leaves a different stack behind depending on whether the tab was ever tapped. A\n * presented screen goes where it is asked, and a replace or a reset has nothing to keep.\n */\n private underTabRoot(\n commands: NavigationCommands,\n extras: NavigationExtras,\n intent: NativeIntent,\n navigate: () => Promise<boolean>,\n ): Promise<boolean> {\n if (intent.stack !== 'push' || intent.presentation) return navigate();\n const tab = this.outlets.unopenedTabOf(this.pathFor(commands, extras));\n if (!tab) return navigate();\n return this.router.navigateByUrl(tab).then((arrived) => (arrived ? navigate() : false));\n }\n\n /** The path the commands lead to, without its query and fragment. */\n private pathFor(commands: NavigationCommands, extras: NavigationExtras): string {\n const url =\n typeof commands === 'string'\n ? commands\n : this.router.serializeUrl(this.router.createUrlTree([...commands], extras));\n return pathOf(url);\n }\n\n /**\n * A page of a tab that is not in front, presented over the one that is: its url would select\n * its own tab and show it there, so it goes to the root's presented outlet instead, where the\n * app's own stack shows it over everything. See `presented-route.ts`. Null for a page of the\n * tab in front, or of no tab, which is presented where its url puts it.\n */\n private overTheTabInFront(\n commands: NavigationCommands,\n extras: NavigationExtras,\n ): Promise<{ commands: unknown[]; extras: NavigationExtras } | null> | null {\n if (!this.outlets.presents) return null;\n const path = this.pathFor(commands, extras);\n if (!this.outlets.inTabBehind(path)) return null;\n const query = typeof commands === 'string' ? this.queryOf(commands, extras) : {};\n return presentedCommands(this.router, path).then(\n (presented) =>\n presented && { commands: presented, extras: { ...extras, ...query, relativeTo: null } },\n );\n }\n\n /**\n * The query and fragment written into a url string, as the extras `navigate` takes them: it\n * reads a string command as one path segment, and would encode a `?` into it. Extras given\n * alongside win over the ones in the string.\n */\n private queryOf(url: string, extras: NavigationExtras): NavigationExtras {\n const cut = url.search(/[?#]/);\n if (cut < 0) return {};\n const { queryParams, fragment } = this.router.parseUrl(url.slice(cut));\n return {\n queryParams: { ...queryParams, ...extras.queryParams },\n fragment: extras.fragment ?? fragment ?? undefined,\n };\n }\n\n private firstNavigationRunning(): boolean {\n const router = this.router as Partial<Router>;\n return router.navigated === false && !!router.currentNavigation?.();\n }\n\n private firstNavigation(): Promise<void> {\n return new Promise((resolve) => {\n const events = this.router.events.subscribe((event) => {\n if (\n event instanceof NavigationEnd ||\n event instanceof NavigationCancel ||\n event instanceof NavigationError\n ) {\n events.unsubscribe();\n resolve();\n }\n });\n });\n }\n}\n"]}
1
+ {"version":3,"file":"native-navigation.js","sourceRoot":"","sources":["../src/native-navigation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EACL,gBAAgB,EAChB,0BAA0B,EAC1B,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,MAAM,GAGP,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAK3E;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,cAAc,CAAC;AAmB5C,gDAAgD;AAChD,MAAM,MAAM,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC;AAEjE,mEAAmE;AACnE,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACrD,MAAM,MAAM,GAAI,KAAiC,CAAC,aAAa,CAAC,CAAC;IACjE,OAAO,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAE,MAAuB,CAAC,CAAC,CAAC,IAAI,CAAC;AAChF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,GAAG,IAAI,OAAO,EAAkE,CAAC;AAEjG,8FAA8F;AAC9F,MAAM,UAAU,gBAAgB,CAC9B,MAAc,EACd,UAAgE;IAEhE,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAC7B,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9C,IAAI,GAAG;QAAE,OAAO,GAAG,CAAC;IACpB,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACvC,OAAO,OAAO,EAAE,EAAE,KAAK,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/D,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,0BAA0B;IACxC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAC9B,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;QAC/C,IAAI,KAAK,YAAY,gBAAgB,IAAI,KAAK,CAAC,IAAI,KAAK,0BAA0B,CAAC,QAAQ,EAAE,CAAC;YAC5F,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;YAC5B,OAAO;QACT,CAAC;QACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,EAAE,KAAK,KAAK,OAAO,EAAE,CAAC;YAC7E,OAAO,CAAC,UAAU,EAAE,CAAC;QACvB,CAAC;QACD,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,KAAK,CAAC,EAAE;YAAE,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACzF,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED;;;;GAIG;AACH,SAAS,OAAO,CAAC,KAAc,EAAE,OAAmB;IAClD,IAAI,KAAK,YAAY,iBAAiB,EAAE,CAAC;QACvC,OAAO,KAAK,CAAC,IAAI,KAAK,qBAAqB,CAAC,wBAAwB,CAAC;IACvE,CAAC;IACD,OAAO,KAAK,YAAY,aAAa,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AACxE,CAAC;AAED,8EAA8E;AAC9E,SAAS,QAAQ,CAAC,MAAc,EAAE,EAAU;IAC1C,MAAM,UAAU,GAAG,MAAM,CAAC,iBAAiB,EAAE,CAAC;IAC9C,OAAO,UAAU,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7E,CAAC;AAED,4FAA4F;AAC5F,SAAS,SAAS,CAAC,MAAc,EAAE,EAAU;IAC3C,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACpC,IAAI,MAAM;QAAE,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;;QACtD,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AACjC,CAAC;AAED,0DAA0D;AAC1D,SAAS,KAAK,CAAC,KAAc;IAC3B,OAAO,CACL,KAAK,YAAY,aAAa;QAC9B,KAAK,YAAY,gBAAgB;QACjC,KAAK,YAAY,eAAe;QAChC,KAAK,YAAY,iBAAiB,CACnC,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,gBAAgB;IACV,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACxB,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IAE9C;;;;;OAKG;IACH,IAAI,CAAC,QAA4B,EAAE,UAAmC,EAAE;QACtE,OAAO,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACvD,CAAC;IAED;;;OAGG;IACH,OAAO,CAAC,QAA4B,EAAE,UAA4B,EAAE;QAClE,OAAO,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IACnF,CAAC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,QAA4B,EAAE,UAA0B,EAAE;QAChE,MAAM,EAAE,EAAE,GAAG,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC;QAC1D,MAAM,MAAM,GAAiB;YAC3B,KAAK,EAAE,MAAM;YACb,YAAY,EAAE,EAAE,iBAAiB,EAAE,EAAE,EAAE,GAAG,YAAY,EAAE;SACzD,CAAC;QACF,2FAA2F;QAC3F,mBAAmB;QACnB,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACtD,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QACpD,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CACzB,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,IAAI,QAAQ,EAAE,KAAK,EAAE,MAAM,IAAI,MAAM,EAAE,MAAM,CAAC,CACtE,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,QAA4B,EAAE,UAA4B,EAAE;QAChE,OAAO,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IACjF,CAAC;IAED;;;;OAIG;IACH,IAAI;QACF,yFAAyF;QACzF,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,EAAE,EAAE,CAAC;YACvC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YACpB,OAAO;QACT,CAAC;QACD,6FAA6F;QAC7F,4FAA4F;QAC5F,0EAA0E;QAC1E,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO;QAC7B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;YACxD,MAAM,KAAK,GAAG,KAAK,YAAY,aAAa,CAAC;YAC7C,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,YAAY,gBAAgB,CAAC,IAAI,CAAC,CAAC,KAAK,YAAY,eAAe,CAAC,EAAE,CAAC;gBAC1F,OAAO;YACT,CAAC;YACD,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,CAAC;YAChC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,IAAI,KAAK;gBAAE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,oFAAoF;IAC5E,WAAW,GAAmC,IAAI,CAAC;IAE3D;;;;;;OAMG;IACH,KAAK,CAAC,QAA4B;QAChC,MAAM,IAAI,GACR,OAAO,QAAQ,KAAK,QAAQ;YAC1B,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAChC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;QAC/C,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED;;;OAGG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;IAClC,CAAC;IAEO,EAAE,CACR,QAA4B,EAC5B,OAAgC,EAChC,MAAoB;QAEpB,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC;QACnD,MAAM,IAAI,GAAiB,YAAY;YACrC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,YAAY,EAAE,EAAE,GAAG,MAAM,CAAC,YAAY,EAAE,GAAG,YAAY,EAAE,EAAE;YAC1E,CAAC,CAAC,MAAM,CAAC;QAEX,MAAM,QAAQ,GAAG,GAAG,EAAE;YACpB,MAAM,IAAI,GAAG,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC;YAC/E,MAAM,GAAG,GAAG;gBACV,GAAG,MAAM;gBACT,GAAG,CAAC,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvE,KAAK,EAAE,EAAE,GAAI,KAAgB,EAAE,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE;aACvD,CAAC;YACF,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;YACzD,OAAO,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC7F,CAAC,CAAC;QACF,sFAAsF;QACtF,0FAA0F;QAC1F,6FAA6F;QAC7F,oCAAoC;QACpC,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QACxE,OAAO,MAAM,CAAC,KAAK,KAAK,OAAO,IAAI,IAAI,CAAC,sBAAsB,EAAE;YAC9D,CAAC,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;YACpC,CAAC,CAAC,KAAK,EAAE,CAAC;IACd,CAAC;IAED;;;;;;OAMG;IACK,YAAY,CAClB,QAA4B,EAC5B,MAAwB,EACxB,MAAoB,EACpB,QAAgC;QAEhC,IAAI,MAAM,CAAC,KAAK,KAAK,MAAM,IAAI,MAAM,CAAC,YAAY;YAAE,OAAO,QAAQ,EAAE,CAAC;QACtE,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;QACvE,IAAI,CAAC,GAAG;YAAE,OAAO,QAAQ,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1F,CAAC;IAED,qEAAqE;IAC7D,OAAO,CAAC,QAA4B,EAAE,MAAwB;QACpE,MAAM,GAAG,GACP,OAAO,QAAQ,KAAK,QAAQ;YAC1B,CAAC,CAAC,QAAQ;YACV,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACjF,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IAED;;;;;OAKG;IACK,iBAAiB,CACvB,QAA4B,EAC5B,MAAwB;QAExB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACjD,MAAM,KAAK,GAAG,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACjF,OAAO,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAC9C,CAAC,SAAS,EAAE,EAAE,CACZ,SAAS,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,GAAG,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,CAC1F,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACK,OAAO,CAAC,GAAW,EAAE,MAAwB;QACnD,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,GAAG,GAAG,CAAC;YAAE,OAAO,EAAE,CAAC;QACvB,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QACvE,OAAO;YACL,WAAW,EAAE,EAAE,GAAG,WAAW,EAAE,GAAG,MAAM,CAAC,WAAW,EAAE;YACtD,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,QAAQ,IAAI,SAAS;SACnD,CAAC;IACJ,CAAC;IAEO,sBAAsB;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAyB,CAAC;QAC9C,OAAO,MAAM,CAAC,SAAS,KAAK,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC,iBAAiB,EAAE,EAAE,CAAC;IACtE,CAAC;IAEO,eAAe;QACrB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;gBACpD,IACE,KAAK,YAAY,aAAa;oBAC9B,KAAK,YAAY,gBAAgB;oBACjC,KAAK,YAAY,eAAe,EAChC,CAAC;oBACD,MAAM,CAAC,WAAW,EAAE,CAAC;oBACrB,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;CACF","sourcesContent":["/**\n * The typed facade over `Router` for the intents a URL cannot express (ADR 0003).\n *\n * Angular's `Router` stays the single source of truth: each of these is a line over\n * `router.navigate`, setting `replaceUrl` and a presentation on `NavigationExtras.state`. Deep\n * links, guards and resolvers keep working because it is still the Router, and because state\n * rides in history a back restores the presentation the screen was opened with.\n *\n * A navigation service that owns the stack was rejected: it either re-implements guards,\n * resolvers and deep linking, or it drifts from the URL, and once the stack is not derived from\n * router state the two can disagree.\n *\n * No decorators, so tests can import it at runtime and so it can be provided with `useClass`,\n * exactly as `NativePlatformLocation` and `NativeStackReuseStrategy` are.\n */\nimport { DestroyRef, inject } from '@angular/core';\nimport {\n NavigationCancel,\n NavigationCancellationCode,\n NavigationEnd,\n NavigationError,\n NavigationSkipped,\n NavigationSkippedCode,\n Router,\n type Navigation,\n type NavigationExtras,\n} from '@angular/router';\nimport { NativeBack } from './native-back.ts';\nimport type { ScreenPresentation, StackPresentation } from './screen-presentation.ts';\nimport { leavingPresented, presentedCommands } from './presented-route.ts';\n\n/** What `Router` takes: a url string, or the array form with segments and params. */\nexport type NavigationCommands = string | readonly unknown[];\n\n/**\n * Where the intent rides. `NavigationExtras.state` is the app's own object, so ours sits under\n * one reserved key rather than spread through it.\n */\nexport const NATIVE_INTENT = 'ɵnativeStack';\n\n/** What a navigation asks the outlet to do with the stack, over and above rendering the route. */\nexport interface NativeIntent {\n /** `replace` drops the screen it supersedes; `reset` empties the stack first. */\n readonly stack?: 'push' | 'replace' | 'reset';\n readonly presentation?: ScreenPresentation;\n}\n\nexport interface NativeNavigationOptions extends NavigationExtras {\n /** How the screen arrives: presentation, animation, gesture and sheet props. */\n presentation?: ScreenPresentation;\n}\n\nexport interface PresentOptions extends NativeNavigationOptions {\n /** Shorthand for `presentation.stackPresentation`. Defaults to `modal`. */\n as?: StackPresentation;\n}\n\n/** A url string up to its query or fragment. */\nconst pathOf = (url: string): string => url.split(/[?#]/, 1)[0]!;\n\n/** Read the intent off a navigation's state, if it carries one. */\nexport function intentOf(state: unknown): NativeIntent | null {\n if (!state || typeof state !== 'object') return null;\n const intent = (state as Record<string, unknown>)[NATIVE_INTENT];\n return intent && typeof intent === 'object' ? (intent as NativeIntent) : null;\n}\n\n/**\n * The intent of a navigation a guard redirected, for the navigation the redirect starts.\n *\n * The router starts a new navigation for a guard's `UrlTree`, keeping `replaceUrl` but not\n * `state`, so a reset to a page that sends a signed-out user to sign in would push the sign-in\n * page over the stack it was meant to clear. Held for that one navigation by its id, which no\n * later navigation shares.\n */\nconst redirected = new WeakMap<object, { readonly id: number; readonly intent: NativeIntent }>();\n\n/** What a navigation asks of the stack: its own intent, or the one it was redirected from. */\nexport function navigationIntent(\n router: object,\n navigation: Pick<Navigation, 'id' | 'extras'> | null | undefined,\n): NativeIntent | null {\n if (!navigation) return null;\n const own = intentOf(navigation.extras.state);\n if (own) return own;\n const carried = redirected.get(router);\n return carried?.id === navigation.id ? carried.intent : null;\n}\n\n/**\n * Hand a navigation's intent on to the one its guard redirects it to. The router schedules that\n * navigation as soon as it has reported the cancel, so it takes the next id.\n *\n * A reset that lands on the screen already on top, its own url or the one a redirect sends it to,\n * is one no outlet activates anything for: the router skips the url already showing, and reuses\n * the screen for another url of it. So the stack is reset here, to the screen on top.\n */\nexport function carryIntentAcrossRedirects(): void {\n const router = inject(Router);\n const outlets = inject(NativeBack);\n const events = router.events.subscribe((event) => {\n if (event instanceof NavigationCancel && event.code === NavigationCancellationCode.Redirect) {\n carryPast(router, event.id);\n return;\n }\n if (keptTop(event, outlets) && intentAt(router, event.id)?.stack === 'reset') {\n outlets.resetToTop();\n }\n if (ended(event) && redirected.get(router)?.id === event.id) redirected.delete(router);\n });\n inject(DestroyRef).onDestroy(() => events.unsubscribe());\n}\n\n/**\n * Whether the navigation `event` ends left the screen on top where it was: one the router skipped\n * for the url already showing, or one no stack put a screen on top for, such as a url with another\n * query, or one a redirect sends to the page on top.\n */\nfunction keptTop(event: unknown, outlets: NativeBack): event is { readonly id: number } {\n if (event instanceof NavigationSkipped) {\n return event.code === NavigationSkippedCode.IgnoredSameUrlNavigation;\n }\n return event instanceof NavigationEnd && !outlets.stackedIn(event.id);\n}\n\n/** The intent of the navigation in progress, when it is the one with `id`. */\nfunction intentAt(router: Router, id: number): NativeIntent | null {\n const navigation = router.currentNavigation();\n return navigation?.id === id ? navigationIntent(router, navigation) : null;\n}\n\n/** Hold the intent of the navigation a guard redirected for the one the redirect starts. */\nfunction carryPast(router: Router, id: number): void {\n const intent = intentAt(router, id);\n if (intent) redirected.set(router, { id: id + 1, intent });\n else redirected.delete(router);\n}\n\n/** Whether the event is the last a navigation reports. */\nfunction ended(event: unknown): event is { readonly id: number } {\n return (\n event instanceof NavigationEnd ||\n event instanceof NavigationCancel ||\n event instanceof NavigationError ||\n event instanceof NavigationSkipped\n );\n}\n\nexport class NativeNavigation {\n private readonly router = inject(Router);\n private readonly outlets = inject(NativeBack);\n\n /**\n * Push a new screen onto the stack. The plain case, and what `nativeRouterLink` does.\n *\n * From a presented screen the new one is presented the same way, over it, since a pushed\n * screen would slide in under it; `presentation` says otherwise, `stackAnimation` and all.\n */\n push(commands: NavigationCommands, options: NativeNavigationOptions = {}): Promise<boolean> {\n return this.go(commands, options, { stack: 'push' });\n }\n\n /**\n * Swap the current screen for another. The history entry is replaced too, so a back from the\n * new screen goes where a back from the old one would have.\n */\n replace(commands: NavigationCommands, options: NavigationExtras = {}): Promise<boolean> {\n return this.go(commands, { ...options, replaceUrl: true }, { stack: 'replace' });\n }\n\n /**\n * Present a screen over the stack rather than pushing into it: a modal, or a sheet.\n *\n * `present('/filters', { as: 'formSheet', presentation: { sheetAllowedDetents: [0.5, 1] } })`.\n *\n * A presented screen is put on screen outside the stack's navigation controller, so it has no\n * native header and no automatic safe-area insets: it needs its own way out, and its own\n * `safe-area-view`. A sheet can also be dragged away, but `fullScreenModal` cannot, and with\n * `gestureEnabled: false` neither can.\n */\n present(commands: NavigationCommands, options: PresentOptions = {}): Promise<boolean> {\n const { as = 'modal', presentation, ...extras } = options;\n const intent: NativeIntent = {\n stack: 'push',\n presentation: { stackPresentation: as, ...presentation },\n };\n // Asked at once, and only waited for when the page is another tab's: finding its route may\n // load a lazy one.\n const over = this.overTheTabInFront(commands, extras);\n if (!over) return this.go(commands, extras, intent);\n return over.then((found) =>\n this.go(found?.commands ?? commands, found?.extras ?? extras, intent),\n );\n }\n\n /**\n * Replace the whole stack with one screen, the way signing out or finishing onboarding does.\n * Every screen below is destroyed, so there is nothing to go back to.\n */\n reset(commands: NavigationCommands, options: NavigationExtras = {}): Promise<boolean> {\n return this.go(commands, { ...options, replaceUrl: true }, { stack: 'reset' });\n }\n\n /**\n * Go back exactly as the Android back button does: pop the stack in front, or at the root of a\n * tab's stack, go to the first tab. Not one entry back through history, which after a trip to\n * another tab is that tab. At the root of the app there is nowhere to go, and this does nothing.\n */\n back(): void {\n // Optional call: a test that stands a plain object in for the router has no such signal.\n if (!this.router.currentNavigation?.()) {\n this.outlets.back();\n return;\n }\n // Asked while a navigation is still putting its screen up: a page that leaves as it appears,\n // from an effect in its constructor. No stack has that screen to pop yet, so the back waits\n // for the navigation, and goes nowhere if the navigation does not arrive.\n if (this.backWaiting) return;\n this.backWaiting = this.router.events.subscribe((event) => {\n const ended = event instanceof NavigationEnd;\n if (!ended && !(event instanceof NavigationCancel) && !(event instanceof NavigationError)) {\n return;\n }\n this.backWaiting?.unsubscribe();\n this.backWaiting = null;\n if (ended) this.outlets.back();\n });\n }\n\n /** The wait of a back asked for mid-navigation, so two asked for in one are one. */\n private backWaiting: { unsubscribe(): void } | null = null;\n\n /**\n * Pop straight back to the screen at `commands`, taking every screen above it off the stack at\n * once - `popToViewController`. The screen is the one already there, with its state, not a new\n * one; where that url is also the one showing, the screen on top is the one kept. Resolves\n * false, doing nothing, when no screen below the top of a stack in front is showing that url; a\n * push is the way to a screen that is not there.\n */\n popTo(commands: NavigationCommands): Promise<boolean> {\n const tree =\n typeof commands === 'string'\n ? this.router.parseUrl(commands)\n : this.router.createUrlTree([...commands]);\n return this.outlets.popTo(this.router.serializeUrl(tree));\n }\n\n /**\n * Pop the stack in front to its first screen - `popToRootViewController`. Inside a tab, that is\n * the tab's first screen; the screens below keep their state. Resolves false at the root already.\n */\n popToRoot(): Promise<boolean> {\n return this.outlets.popToRoot();\n }\n\n private go(\n commands: NavigationCommands,\n options: NativeNavigationOptions,\n intent: NativeIntent,\n ): Promise<boolean> {\n const { presentation, state, ...extras } = options;\n const full: NativeIntent = presentation\n ? { ...intent, presentation: { ...intent.presentation, ...presentation } }\n : intent;\n\n const navigate = () => {\n const list = typeof commands === 'string' ? [pathOf(commands)] : [...commands];\n const all = {\n ...extras,\n ...(typeof commands === 'string' ? this.queryOf(commands, extras) : {}),\n state: { ...(state as object), [NATIVE_INTENT]: full },\n };\n const leaving = leavingPresented(this.router, list, all);\n return leaving ? this.router.navigateByUrl(leaving, all) : this.router.navigate(list, all);\n };\n // A screen stacked on the first one waits for it. Navigating while the router's first\n // navigation is still running - a lazily loaded root waiting on its import - cancels that\n // navigation, and the app opens on this screen with nothing beneath it. A reset replaces the\n // stack anyway, so it goes at once.\n const start = () => this.underTabRoot(commands, extras, full, navigate);\n return intent.stack !== 'reset' && this.firstNavigationRunning()\n ? this.firstNavigation().then(start)\n : start();\n }\n\n /**\n * A push into a tab nobody has opened goes to the tab first, so its stack has the tab's own\n * first screen under the page, and a back from the page lands there: what a tab bar with a\n * navigation controller per tab does. Without it the page is the stack's only screen, and the\n * same push leaves a different stack behind depending on whether the tab was ever tapped. A\n * presented screen goes where it is asked, and a replace or a reset has nothing to keep.\n */\n private underTabRoot(\n commands: NavigationCommands,\n extras: NavigationExtras,\n intent: NativeIntent,\n navigate: () => Promise<boolean>,\n ): Promise<boolean> {\n if (intent.stack !== 'push' || intent.presentation) return navigate();\n const tab = this.outlets.unopenedTabOf(this.pathFor(commands, extras));\n if (!tab) return navigate();\n return this.router.navigateByUrl(tab).then((arrived) => (arrived ? navigate() : false));\n }\n\n /** The path the commands lead to, without its query and fragment. */\n private pathFor(commands: NavigationCommands, extras: NavigationExtras): string {\n const url =\n typeof commands === 'string'\n ? commands\n : this.router.serializeUrl(this.router.createUrlTree([...commands], extras));\n return pathOf(url);\n }\n\n /**\n * A page of a tab that is not in front, presented over the one that is: its url would select\n * its own tab and show it there, so it goes to the root's presented outlet instead, where the\n * app's own stack shows it over everything. See `presented-route.ts`. Null for a page of the\n * tab in front, or of no tab, which is presented where its url puts it.\n */\n private overTheTabInFront(\n commands: NavigationCommands,\n extras: NavigationExtras,\n ): Promise<{ commands: unknown[]; extras: NavigationExtras } | null> | null {\n if (!this.outlets.presents) return null;\n const path = this.pathFor(commands, extras);\n if (!this.outlets.inTabBehind(path)) return null;\n const query = typeof commands === 'string' ? this.queryOf(commands, extras) : {};\n return presentedCommands(this.router, path).then(\n (presented) =>\n presented && { commands: presented, extras: { ...extras, ...query, relativeTo: null } },\n );\n }\n\n /**\n * The query and fragment written into a url string, as the extras `navigate` takes them: it\n * reads a string command as one path segment, and would encode a `?` into it. Extras given\n * alongside win over the ones in the string.\n */\n private queryOf(url: string, extras: NavigationExtras): NavigationExtras {\n const cut = url.search(/[?#]/);\n if (cut < 0) return {};\n const { queryParams, fragment } = this.router.parseUrl(url.slice(cut));\n return {\n queryParams: { ...queryParams, ...extras.queryParams },\n fragment: extras.fragment ?? fragment ?? undefined,\n };\n }\n\n private firstNavigationRunning(): boolean {\n const router = this.router as Partial<Router>;\n return router.navigated === false && !!router.currentNavigation?.();\n }\n\n private firstNavigation(): Promise<void> {\n return new Promise((resolve) => {\n const events = this.router.events.subscribe((event) => {\n if (\n event instanceof NavigationEnd ||\n event instanceof NavigationCancel ||\n event instanceof NavigationError\n ) {\n events.unsubscribe();\n resolve();\n }\n });\n });\n }\n}\n"]}
@@ -28,9 +28,10 @@ export declare class NativePlatformLocation implements PlatformLocation {
28
28
  private readonly popStateListeners;
29
29
  private readonly hashChangeListeners;
30
30
  /**
31
- * A deep link is history, not a navigation of its own: the launch url *is* the first entry,
32
- * and one that arrives later is pushed and announced as a popstate, which is the only thing
33
- * the router listens to. `links` is null in a test that has no interest in either.
31
+ * A deep link is history, not a navigation of its own: the launch url *is* the first entry.
32
+ * One that arrives later is pushed and announced as a popstate when `links` hands it here;
33
+ * `provideNativeRouter` hands those to `NativeNavigation` instead, so a link is pushed over
34
+ * the screen showing. `links` is null in a test that has no interest in either.
34
35
  */
35
36
  constructor(links?: LinkSource | null);
36
37
  /** Follow a link that arrived while the app was running. */
@@ -14,9 +14,10 @@ export class NativePlatformLocation {
14
14
  popStateListeners = new Set();
15
15
  hashChangeListeners = new Set();
16
16
  /**
17
- * A deep link is history, not a navigation of its own: the launch url *is* the first entry,
18
- * and one that arrives later is pushed and announced as a popstate, which is the only thing
19
- * the router listens to. `links` is null in a test that has no interest in either.
17
+ * A deep link is history, not a navigation of its own: the launch url *is* the first entry.
18
+ * One that arrives later is pushed and announced as a popstate when `links` hands it here;
19
+ * `provideNativeRouter` hands those to `NativeNavigation` instead, so a link is pushed over
20
+ * the screen showing. `links` is null in a test that has no interest in either.
20
21
  */
21
22
  constructor(links = null) {
22
23
  const initial = links?.initialUrl();
@@ -1 +1 @@
1
- {"version":3,"file":"native-platform-location.js","sourceRoot":"","sources":["../src/native-platform-location.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `PlatformLocation` over an in-memory history.\n *\n * Angular's `Location` reads and writes the URL through this. On the web the browser owns the\n * history stack; here nothing does, so we keep it ourselves and the URL tree stays the source of\n * truth in both directions: `router.navigate()` pushes an entry, and a swipe-back reaches the\n * outlet as the screen's `dismissed` event, which usually calls `historyGo(-1)` here and emits\n * `popstate` so the router follows. Not always: see the stack outlet's `popBy` for when the entry\n * behind is another tab.\n *\n * No decorators, so tests can import it at runtime and so it can be provided with `useClass`.\n */\nimport type { LocationChangeListener, PlatformLocation } from '@angular/common';\n/**\n * What the history needs of a deep-link source, which `DeepLinks` from\n * `@ng-native/device` satisfies. Structural rather than the class itself: the router has no\n * use for the rest of it, and a test has no use for a real one.\n */\nexport interface LinkSource {\n /** The path the app was launched with, or null for a normal launch. */\n initialUrl(): string | null;\n /** Links that arrive while the app is running. Returns an unsubscribe. */\n subscribe(listener: (url: string) => void): () => void;\n}\n\ninterface HistoryEntry {\n url: string;\n state: unknown;\n}\n\n/** Split a url into its path, `?search` and `#hash` parts. */\nfunction parse(url: string): { pathname: string; search: string; hash: string } {\n const hashAt = url.indexOf('#');\n const hash = hashAt === -1 ? '' : url.slice(hashAt);\n const withoutHash = hashAt === -1 ? url : url.slice(0, hashAt);\n\n const searchAt = withoutHash.indexOf('?');\n const search = searchAt === -1 ? '' : withoutHash.slice(searchAt);\n const pathname = searchAt === -1 ? withoutHash : withoutHash.slice(0, searchAt);\n\n return { pathname: pathname || '/', search, hash };\n}\n\nexport class NativePlatformLocation implements PlatformLocation {\n private readonly entries: HistoryEntry[] = [{ url: '/', state: null }];\n private cursor = 0;\n\n private readonly popStateListeners = new Set<LocationChangeListener>();\n private readonly hashChangeListeners = new Set<LocationChangeListener>();\n\n /**\n * A deep link is history, not a navigation of its own: the launch url *is* the first entry,\n * and one that arrives later is pushed and announced as a popstate, which is the only thing\n * the router listens to. `links` is null in a test that has no interest in either.\n */\n constructor(links: LinkSource | null = null) {\n const initial = links?.initialUrl();\n if (initial) this.entries[0] = { url: initial, state: null };\n links?.subscribe((url) => this.open(url));\n }\n\n /** Follow a link that arrived while the app was running. */\n open(url: string): void {\n if (url === this.current.url) return;\n this.pushState(null, '', url);\n this.emitPopState();\n }\n\n /**\n * The url of the entry `offset` away from the current one, or null past either end. For the\n * stack outlet, which has to know whether going back reaches the screen a native pop revealed.\n */\n ɵurlAt(offset: number): string | null {\n return this.entries[this.cursor + offset]?.url ?? null;\n }\n\n /** The history up to the page showing, oldest first. For parking it across a reload. */\n ɵpages(): readonly { readonly url: string; readonly state: unknown }[] {\n return this.entries.slice(0, this.cursor + 1);\n }\n\n private get current(): HistoryEntry {\n return this.entries[this.cursor]!;\n }\n\n // --- PlatformLocation ---------------------------------------------------\n\n getBaseHrefFromDOM(): string {\n return '/';\n }\n\n getState(): unknown {\n return this.current.state;\n }\n\n onPopState(fn: LocationChangeListener): VoidFunction {\n this.popStateListeners.add(fn);\n return () => this.popStateListeners.delete(fn);\n }\n\n onHashChange(fn: LocationChangeListener): VoidFunction {\n this.hashChangeListeners.add(fn);\n return () => this.hashChangeListeners.delete(fn);\n }\n\n get href(): string {\n return this.current.url;\n }\n\n /** There is no origin on a device. Angular only ever compares these, never resolves them. */\n get protocol(): string {\n return 'app:';\n }\n\n get hostname(): string {\n return '';\n }\n\n get port(): string {\n return '';\n }\n\n get pathname(): string {\n return parse(this.current.url).pathname;\n }\n\n get search(): string {\n return parse(this.current.url).search;\n }\n\n get hash(): string {\n return parse(this.current.url).hash;\n }\n\n pushState(state: unknown, _title: string, url: string): void {\n // A push after going back discards the forward entries, as a browser does.\n this.entries.length = this.cursor + 1;\n this.entries.push({ url, state });\n this.cursor++;\n }\n\n replaceState(state: unknown, _title: string, url: string): void {\n this.entries[this.cursor] = { url, state };\n }\n\n forward(): void {\n this.historyGo(1);\n }\n\n back(): void {\n this.historyGo(-1);\n }\n\n historyGo(relativePosition = 0): void {\n const target = this.cursor + relativePosition;\n // Out of range is a no-op, matching the browser rather than throwing.\n if (target < 0 || target >= this.entries.length) return;\n this.cursor = target;\n this.emitPopState();\n }\n\n private emitPopState(): void {\n const event = { type: 'popstate', state: this.current.state };\n for (const listener of [...this.popStateListeners]) listener(event);\n }\n}\n"]}
1
+ {"version":3,"file":"native-platform-location.js","sourceRoot":"","sources":["../src/native-platform-location.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `PlatformLocation` over an in-memory history.\n *\n * Angular's `Location` reads and writes the URL through this. On the web the browser owns the\n * history stack; here nothing does, so we keep it ourselves and the URL tree stays the source of\n * truth in both directions: `router.navigate()` pushes an entry, and a swipe-back reaches the\n * outlet as the screen's `dismissed` event, which usually calls `historyGo(-1)` here and emits\n * `popstate` so the router follows. Not always: see the stack outlet's `popBy` for when the entry\n * behind is another tab.\n *\n * No decorators, so tests can import it at runtime and so it can be provided with `useClass`.\n */\nimport type { LocationChangeListener, PlatformLocation } from '@angular/common';\n/**\n * What the history needs of a deep-link source, which `DeepLinks` from\n * `@ng-native/device` satisfies. Structural rather than the class itself: the router has no\n * use for the rest of it, and a test has no use for a real one.\n */\nexport interface LinkSource {\n /** The path the app was launched with, or null for a normal launch. */\n initialUrl(): string | null;\n /** Links that arrive while the app is running. Returns an unsubscribe. */\n subscribe(listener: (url: string) => void): () => void;\n}\n\ninterface HistoryEntry {\n url: string;\n state: unknown;\n}\n\n/** Split a url into its path, `?search` and `#hash` parts. */\nfunction parse(url: string): { pathname: string; search: string; hash: string } {\n const hashAt = url.indexOf('#');\n const hash = hashAt === -1 ? '' : url.slice(hashAt);\n const withoutHash = hashAt === -1 ? url : url.slice(0, hashAt);\n\n const searchAt = withoutHash.indexOf('?');\n const search = searchAt === -1 ? '' : withoutHash.slice(searchAt);\n const pathname = searchAt === -1 ? withoutHash : withoutHash.slice(0, searchAt);\n\n return { pathname: pathname || '/', search, hash };\n}\n\nexport class NativePlatformLocation implements PlatformLocation {\n private readonly entries: HistoryEntry[] = [{ url: '/', state: null }];\n private cursor = 0;\n\n private readonly popStateListeners = new Set<LocationChangeListener>();\n private readonly hashChangeListeners = new Set<LocationChangeListener>();\n\n /**\n * A deep link is history, not a navigation of its own: the launch url *is* the first entry.\n * One that arrives later is pushed and announced as a popstate when `links` hands it here;\n * `provideNativeRouter` hands those to `NativeNavigation` instead, so a link is pushed over\n * the screen showing. `links` is null in a test that has no interest in either.\n */\n constructor(links: LinkSource | null = null) {\n const initial = links?.initialUrl();\n if (initial) this.entries[0] = { url: initial, state: null };\n links?.subscribe((url) => this.open(url));\n }\n\n /** Follow a link that arrived while the app was running. */\n open(url: string): void {\n if (url === this.current.url) return;\n this.pushState(null, '', url);\n this.emitPopState();\n }\n\n /**\n * The url of the entry `offset` away from the current one, or null past either end. For the\n * stack outlet, which has to know whether going back reaches the screen a native pop revealed.\n */\n ɵurlAt(offset: number): string | null {\n return this.entries[this.cursor + offset]?.url ?? null;\n }\n\n /** The history up to the page showing, oldest first. For parking it across a reload. */\n ɵpages(): readonly { readonly url: string; readonly state: unknown }[] {\n return this.entries.slice(0, this.cursor + 1);\n }\n\n private get current(): HistoryEntry {\n return this.entries[this.cursor]!;\n }\n\n // --- PlatformLocation ---------------------------------------------------\n\n getBaseHrefFromDOM(): string {\n return '/';\n }\n\n getState(): unknown {\n return this.current.state;\n }\n\n onPopState(fn: LocationChangeListener): VoidFunction {\n this.popStateListeners.add(fn);\n return () => this.popStateListeners.delete(fn);\n }\n\n onHashChange(fn: LocationChangeListener): VoidFunction {\n this.hashChangeListeners.add(fn);\n return () => this.hashChangeListeners.delete(fn);\n }\n\n get href(): string {\n return this.current.url;\n }\n\n /** There is no origin on a device. Angular only ever compares these, never resolves them. */\n get protocol(): string {\n return 'app:';\n }\n\n get hostname(): string {\n return '';\n }\n\n get port(): string {\n return '';\n }\n\n get pathname(): string {\n return parse(this.current.url).pathname;\n }\n\n get search(): string {\n return parse(this.current.url).search;\n }\n\n get hash(): string {\n return parse(this.current.url).hash;\n }\n\n pushState(state: unknown, _title: string, url: string): void {\n // A push after going back discards the forward entries, as a browser does.\n this.entries.length = this.cursor + 1;\n this.entries.push({ url, state });\n this.cursor++;\n }\n\n replaceState(state: unknown, _title: string, url: string): void {\n this.entries[this.cursor] = { url, state };\n }\n\n forward(): void {\n this.historyGo(1);\n }\n\n back(): void {\n this.historyGo(-1);\n }\n\n historyGo(relativePosition = 0): void {\n const target = this.cursor + relativePosition;\n // Out of range is a no-op, matching the browser rather than throwing.\n if (target < 0 || target >= this.entries.length) return;\n this.cursor = target;\n this.emitPopState();\n }\n\n private emitPopState(): void {\n const event = { type: 'popstate', state: this.current.state };\n for (const listener of [...this.popStateListeners]) listener(event);\n }\n}\n"]}
@@ -160,6 +160,10 @@ export declare class NativeStackOutlet implements RouterOutletContract, OnInit {
160
160
  * at once when there is no navigation to wait for. A replaced screen has already been detached
161
161
  * by the router, and with `replaceUrl` its history entry is gone too, so nothing will attach it
162
162
  * again; the reuse strategy notices the ref is destroyed and drops its handle.
163
+ *
164
+ * A page that navigates as it is created, a sign-in check in `ngOnInit`, cancels the navigation
165
+ * creating it before this is reached, so that one never ends: the page stays, and what it
166
+ * superseded goes at once.
163
167
  */
164
168
  private supersede;
165
169
  /** A navigation succeeded: what it superseded goes, and what it did is no longer undoable. */
@@ -309,10 +309,11 @@ export class NativeStackOutlet {
309
309
  // else the page's style set - a background colour, say - still merges and stays.
310
310
  this.fillScreen(screen);
311
311
  this.back.stacked(navigation);
312
+ const pending = this.navigationId() === navigation ? navigation : undefined;
312
313
  if (intent?.stack === 'reset')
313
- this.supersede(this.entries.slice(), navigation);
314
+ this.supersede(this.entries.slice(), pending);
314
315
  else if (intent?.stack === 'replace' && this.top)
315
- this.supersede([this.top], navigation);
316
+ this.supersede([this.top], pending);
316
317
  this.entries.push({
317
318
  route,
318
319
  ref,
@@ -419,6 +420,9 @@ export class NativeStackOutlet {
419
420
  else {
420
421
  for (const above of this.entries.splice(index + 1))
421
422
  this.drop(above);
423
+ if (this.currentIntent()?.stack === 'reset') {
424
+ this.supersede(this.entries.slice(0, index), this.navigationId());
425
+ }
422
426
  const entry = this.entries[index];
423
427
  entry.detached = false;
424
428
  entry.inFront.set(true);
@@ -517,6 +521,10 @@ export class NativeStackOutlet {
517
521
  * at once when there is no navigation to wait for. A replaced screen has already been detached
518
522
  * by the router, and with `replaceUrl` its history entry is gone too, so nothing will attach it
519
523
  * again; the reuse strategy notices the ref is destroyed and drops its handle.
524
+ *
525
+ * A page that navigates as it is created, a sign-in check in `ngOnInit`, cancels the navigation
526
+ * creating it before this is reached, so that one never ends: the page stays, and what it
527
+ * superseded goes at once.
520
528
  */
521
529
  supersede(entries, navigation) {
522
530
  if (navigation === undefined) {
@@ -726,6 +734,16 @@ export class NativeStackOutlet {
726
734
  popToEntry(index) {
727
735
  const url = this.urlOf(this.entries[index]);
728
736
  const steps = this.entries.length - 1 - index;
737
+ // The url the router is on already, where the same one is on the stack twice: a navigation
738
+ // to it is skipped, and would pop nothing. The screen on top is showing it, so that one
739
+ // stays and the ones under it go, down to the one asked for.
740
+ if (url === this.router.url) {
741
+ for (const entry of this.entries.slice(index, -1))
742
+ this.remove(entry);
743
+ if (this.historyUrl(-steps) === url)
744
+ this.location.historyGo(-steps);
745
+ return Promise.resolve(true);
746
+ }
729
747
  if (this.historyUrl(-steps) === url) {
730
748
  const arrived = this.nextNavigation();
731
749
  this.location.historyGo(-steps);