@ng-native/router 0.13.0 → 0.14.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.
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/native-back.d.ts +8 -0
- package/dist/native-back.js +9 -0
- package/dist/native-back.js.map +1 -1
- package/dist/native-header-item.d.ts +10 -1
- package/dist/native-header-item.js +13 -3
- package/dist/native-header-item.js.map +1 -1
- package/dist/native-navigation.d.ts +13 -1
- package/dist/native-navigation.js +48 -11
- package/dist/native-navigation.js.map +1 -1
- package/dist/native-router-link.d.ts +1 -1
- package/dist/native-router-link.js +18 -15
- package/dist/native-router-link.js.map +1 -1
- package/dist/native-stack-outlet.d.ts +13 -0
- package/dist/native-stack-outlet.js +49 -2
- package/dist/native-stack-outlet.js.map +1 -1
- package/dist/native-tab.d.ts +48 -6
- package/dist/native-tab.js +91 -5
- package/dist/native-tab.js.map +1 -1
- package/dist/native-tabs-outlet.d.ts +2 -0
- package/dist/native-tabs-outlet.js +12 -2
- package/dist/native-tabs-outlet.js.map +1 -1
- package/dist/presented-route.js +3 -1
- package/dist/presented-route.js.map +1 -1
- package/dist/provide-native-router.d.ts +11 -1
- package/dist/provide-native-router.js +16 -10
- package/dist/provide-native-router.js.map +1 -1
- package/dist/screen-presentation.d.ts +16 -0
- package/dist/screen-presentation.js.map +1 -1
- package/dist/screens.js +10 -1
- package/dist/screens.js.map +1 -1
- package/dist/svg-icons.d.ts +23 -0
- package/dist/svg-icons.js +15 -0
- package/dist/svg-icons.js.map +1 -0
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -17,12 +17,13 @@ export { NativeHeaderItem, type HeaderItemType } from './native-header-item.ts';
|
|
|
17
17
|
export { NativeToolbar, NativeToolbarItem, type ToolbarItemType } from './native-toolbar.ts';
|
|
18
18
|
export { NativeSearchBar, type SearchBarPlacement } from './native-search-bar.ts';
|
|
19
19
|
export { NativeStackOutlet } from './native-stack-outlet.ts';
|
|
20
|
-
export { NativeTab, type TabAppearance, type TabBarBlurEffect, type TabIcon, type TabIconProps, type TabItemAppearance, type TabStateAppearance, type TabSystemItem, } from './native-tab.ts';
|
|
20
|
+
export { NativeTab, type TabAppearance, type TabBarBlurEffect, type TabIcon, type TabIconProps, type TabItemAppearance, type TabRole, type TabStateAppearance, type TabSystemItem, } from './native-tab.ts';
|
|
21
21
|
export { NativeTabsOutlet } from './native-tabs-outlet.ts';
|
|
22
22
|
export { ScreenSafeAreaView, type ScreenSafeAreaEdge } from './screen-safe-area-view.ts';
|
|
23
23
|
export { TabSafeAreaView, type TabSafeAreaEdge } from './tab-safe-area-view.ts';
|
|
24
24
|
export { NativeStackReuseStrategy, reuseScreen } from './native-stack-reuse-strategy.ts';
|
|
25
|
-
export { provideNativeRouter, withHeaderDefaults, withLinkParent, withTabDefaults, type NativeRouterFeature, } from './provide-native-router.ts';
|
|
25
|
+
export { provideNativeRouter, withHeaderDefaults, withLinkParent, withSvgIcons, withTabDefaults, type NativeRouterFeature, } from './provide-native-router.ts';
|
|
26
|
+
export { type SvgIconRenderer } from './svg-icons.ts';
|
|
26
27
|
export { type GestureResponseDistance, type ReplaceAnimation, type ScreenPresentation, type StackAnimation, type StackPresentation, type SwipeDirection, } from './screen-presentation.ts';
|
|
27
28
|
export { ActivityState, type ActivityStateValue } from './screens.ts';
|
|
28
29
|
export { fileRoutes, type FileRoutesOptions, type PageContext, type PageFiles, type RouteMeta, } from './file-routes.ts';
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,8 @@ export { NativeTabsOutlet } from "./native-tabs-outlet.js";
|
|
|
22
22
|
export { ScreenSafeAreaView } from "./screen-safe-area-view.js";
|
|
23
23
|
export { TabSafeAreaView } from "./tab-safe-area-view.js";
|
|
24
24
|
export { NativeStackReuseStrategy, reuseScreen } from "./native-stack-reuse-strategy.js";
|
|
25
|
-
export { provideNativeRouter, withHeaderDefaults, withLinkParent, withTabDefaults, } from "./provide-native-router.js";
|
|
25
|
+
export { provideNativeRouter, withHeaderDefaults, withLinkParent, withSvgIcons, withTabDefaults, } from "./provide-native-router.js";
|
|
26
|
+
export {} from "./svg-icons.js";
|
|
26
27
|
export {} from "./screen-presentation.js";
|
|
27
28
|
export { ActivityState } from "./screens.js";
|
|
28
29
|
export { fileRoutes, } from "./file-routes.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,UAAU,EAAmB,MAAM,mBAAmB,CAAC;AAChE,OAAO,EACL,gBAAgB,GAIjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,sBAAsB,EAAmB,MAAM,+BAA+B,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EACL,sBAAsB,EACtB,mBAAmB,GAIpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,YAAY,GAKb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GAEtB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAuB,MAAM,yBAAyB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAwB,MAAM,qBAAqB,CAAC;AAC7F,OAAO,EAAE,eAAe,EAA2B,MAAM,wBAAwB,CAAC;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EACL,SAAS,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,UAAU,EAAmB,MAAM,mBAAmB,CAAC;AAChE,OAAO,EACL,gBAAgB,GAIjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,sBAAsB,EAAmB,MAAM,+BAA+B,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EACL,sBAAsB,EACtB,mBAAmB,GAIpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,YAAY,GAKb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GAEtB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAuB,MAAM,yBAAyB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAwB,MAAM,qBAAqB,CAAC;AAC7F,OAAO,EAAE,eAAe,EAA2B,MAAM,wBAAwB,CAAC;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EACL,SAAS,GASV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAA2B,MAAM,4BAA4B,CAAC;AACzF,OAAO,EAAE,eAAe,EAAwB,MAAM,yBAAyB,CAAC;AAChF,OAAO,EAAE,wBAAwB,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACzF,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,eAAe,GAEhB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAwB,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAON,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,aAAa,EAA2B,MAAM,cAAc,CAAC;AACtE,OAAO,EACL,UAAU,GAKX,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,gBAAgB,GAEjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC","sourcesContent":["/**\n * `@angular/router` on a native stack: the outlet that maps activated routes onto `RNSScreen`,\n * the `PlatformLocation` that stands in for the browser's history, and the reuse strategy that\n * keeps a popped screen's component alive while it animates out.\n *\n * Two of these are decorated, so the same caveat as the components barrel applies: a Node test\n * reaches the source file, not this.\n */\nexport { followLink, type LinkParent } from './native-links.ts';\nexport {\n NativeNavigation,\n type NativeNavigationOptions,\n type NavigationCommands,\n type PresentOptions,\n} from './native-navigation.ts';\nexport { NativePlatformLocation, type LinkSource } from './native-platform-location.ts';\nexport { NativeRouterLink } from './native-router-link.ts';\nexport {\n NATIVE_HEADER_DEFAULTS,\n NATIVE_TAB_DEFAULTS,\n type HeaderDefaults,\n type SchemeDefaults,\n type TabDefaults,\n} from './native-bar-defaults.ts';\nexport {\n NativeHeader,\n type BackButtonDisplayMode,\n type BlurEffect,\n type HeaderDirection,\n type HeaderInterfaceStyle,\n} from './native-header.ts';\nexport {\n DEFAULT_HEADER_PALETTE,\n NATIVE_HEADER_PALETTE,\n type HeaderColors,\n} from './native-header-palette.ts';\nexport { NativeHeaderItem, type HeaderItemType } from './native-header-item.ts';\nexport { NativeToolbar, NativeToolbarItem, type ToolbarItemType } from './native-toolbar.ts';\nexport { NativeSearchBar, type SearchBarPlacement } from './native-search-bar.ts';\nexport { NativeStackOutlet } from './native-stack-outlet.ts';\nexport {\n NativeTab,\n type TabAppearance,\n type TabBarBlurEffect,\n type TabIcon,\n type TabIconProps,\n type TabItemAppearance,\n type TabRole,\n type TabStateAppearance,\n type TabSystemItem,\n} from './native-tab.ts';\nexport { NativeTabsOutlet } from './native-tabs-outlet.ts';\nexport { ScreenSafeAreaView, type ScreenSafeAreaEdge } from './screen-safe-area-view.ts';\nexport { TabSafeAreaView, type TabSafeAreaEdge } from './tab-safe-area-view.ts';\nexport { NativeStackReuseStrategy, reuseScreen } from './native-stack-reuse-strategy.ts';\nexport {\n provideNativeRouter,\n withHeaderDefaults,\n withLinkParent,\n withSvgIcons,\n withTabDefaults,\n type NativeRouterFeature,\n} from './provide-native-router.ts';\nexport { type SvgIconRenderer } from './svg-icons.ts';\nexport {\n type GestureResponseDistance,\n type ReplaceAnimation,\n type ScreenPresentation,\n type StackAnimation,\n type StackPresentation,\n type SwipeDirection,\n} from './screen-presentation.ts';\nexport { ActivityState, type ActivityStateValue } from './screens.ts';\nexport {\n fileRoutes,\n type FileRoutesOptions,\n type PageContext,\n type PageFiles,\n type RouteMeta,\n} from './file-routes.ts';\nexport {\n MARKDOWN_PAGE,\n injectMarkdownPage,\n markdownPageFile,\n type MarkdownPageFile,\n} from './markdown-page.ts';\nexport { FullWindowOverlay } from './full-window-overlay.ts';\n"]}
|
package/dist/native-back.d.ts
CHANGED
|
@@ -21,6 +21,12 @@ export interface TabBar {
|
|
|
21
21
|
unopenedTabOf(url: string): string | null;
|
|
22
22
|
/** Whether `url` is a tab other than the one in front, or a page inside one. */
|
|
23
23
|
behind(url: string): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Where the tab `url` is in was left, when a screen of the stack the bar is on covers the bar:
|
|
26
|
+
* the url that brings the bar back in front at that tab. Null when the bar is in front, or
|
|
27
|
+
* `url` is in none of its tabs.
|
|
28
|
+
*/
|
|
29
|
+
coveredAt(url: string): string | null;
|
|
24
30
|
}
|
|
25
31
|
export declare class NativeBack {
|
|
26
32
|
private readonly hardwareBack;
|
|
@@ -34,6 +40,8 @@ export declare class NativeBack {
|
|
|
34
40
|
addTabBar(bar: TabBar): () => void;
|
|
35
41
|
/** The url of the unopened tab `url` is a page inside, or null: see `TabBar`. */
|
|
36
42
|
unopenedTabOf(url: string): string | null;
|
|
43
|
+
/** Where a covered bar's tab holding `url` was left, or null: see `TabBar.coveredAt`. */
|
|
44
|
+
coveredTabAt(url: string): string | null;
|
|
37
45
|
/** Whether `url` belongs to a tab that is not the one in front. */
|
|
38
46
|
inTabBehind(url: string): boolean;
|
|
39
47
|
/**
|
package/dist/native-back.js
CHANGED
|
@@ -40,6 +40,15 @@ export class NativeBack {
|
|
|
40
40
|
}
|
|
41
41
|
return null;
|
|
42
42
|
}
|
|
43
|
+
/** Where a covered bar's tab holding `url` was left, or null: see `TabBar.coveredAt`. */
|
|
44
|
+
coveredTabAt(url) {
|
|
45
|
+
for (const bar of this.tabBars) {
|
|
46
|
+
const at = bar.coveredAt(url);
|
|
47
|
+
if (at)
|
|
48
|
+
return at;
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
43
52
|
/** Whether `url` belongs to a tab that is not the one in front. */
|
|
44
53
|
inTabBehind(url) {
|
|
45
54
|
return this.tabBars.some((bar) => bar.behind(url));
|
package/dist/native-back.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-back.js","sourceRoot":"","sources":["../src/native-back.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Who answers a back: Android's hardware button, and `NativeNavigation.back()`.\n *\n * Every outlet offers an answer, and the one in front takes it. Each answer is also handed to\n * `HardwareBack` directly, where React Native asks the newest first. An outlet always subscribes\n * after the outlet it sits inside, so that order runs from the innermost outlet out, and a\n * screen's own handler, subscribed after its outlet, still outranks it. `back()` asks the outlets\n * in that same order, without the screens' own handlers: those are for the button.\n *\n * Newest first is not enough on its own. A stack in a tab behind the one in front, or under a\n * screen pushed over the whole tab bar, is still subscribed, so each answer first checks that\n * its outlet is showing what the router is showing.\n */\nimport { Service, inject } from '@angular/core';\nimport type { ActivatedRoute, Router } from '@angular/router';\nimport { HardwareBack } from '@ng-native/device';\n\n/** What a stack offers `NativeNavigation` beyond a back: going down it several screens at once. */\nexport interface PoppableStack {\n /** Whether this stack is part of what the router shows now. */\n showing(): boolean;\n /** Pop to its first screen, or null when it is showing only that one. */\n popToRoot(): Promise<boolean> | null;\n /** Pop to the screen showing `url`, or null when no screen below the top shows it. */\n popTo(url: string): Promise<boolean> | null;\n /** Take every screen under the top off at once, or false when it is showing only that one. */\n dropUnderTop(): boolean;\n}\n\n/**\n * What a tab bar offers `NativeNavigation` for a push into one of its tabs from outside it. A tab\n * nobody has opened has no stack yet, and a page pushed into it would be the stack's first\n * screen, with nothing under it to go back to.\n */\nexport interface TabBar {\n /** The url of the tab `url` is a page inside, when that tab has not been opened. */\n unopenedTabOf(url: string): string | null;\n /** Whether `url` is a tab other than the one in front, or a page inside one. */\n behind(url: string): boolean;\n}\n\n@Service()\nexport class NativeBack {\n private readonly hardwareBack = inject(HardwareBack);\n /** Oldest first, as `HardwareBack` holds them. */\n private readonly answers: BackAnswer[] = [];\n /** Oldest first, and so outermost first, as the answers are. */\n private readonly stacks: PoppableStack[] = [];\n\n /** Oldest first. */\n private readonly tabBars: TabBar[] = [];\n\n /** Offer a tab bar's unopened tabs to a push into one. Returns an unsubscribe. */\n addTabBar(bar: TabBar): () => void {\n this.tabBars.push(bar);\n return () => {\n const index = this.tabBars.indexOf(bar);\n if (index !== -1) this.tabBars.splice(index, 1);\n };\n }\n\n /** The url of the unopened tab `url` is a page inside, or null: see `TabBar`. */\n unopenedTabOf(url: string): string | null {\n for (const bar of this.tabBars) {\n const root = bar.unopenedTabOf(url);\n if (root) return root;\n }\n return null;\n }\n\n /** Whether `url` belongs to a tab that is not the one in front. */\n inTabBehind(url: string): boolean {\n return this.tabBars.some((bar) => bar.behind(url));\n }\n\n /**\n * Whether the app's own stack takes a page presented over whatever is showing. Set by the root\n * stack outlet for as long as there is one: see `presented-route.ts`.\n */\n presents = false;\n\n /** Offer a stack for popping several screens at once. Returns an unsubscribe. */\n addStack(stack: PoppableStack): () => void {\n this.stacks.push(stack);\n return () => {\n const index = this.stacks.indexOf(stack);\n if (index !== -1) this.stacks.splice(index, 1);\n };\n }\n\n /** Pop the innermost stack in front that is deeper than one screen, to its first. */\n popToRoot(): Promise<boolean> {\n for (const stack of [...this.stacks].reverse()) {\n if (!stack.showing()) continue;\n const popped = stack.popToRoot();\n if (popped) return popped;\n }\n return Promise.resolve(false);\n }\n\n /**\n * Take the screens under the top of the innermost stack in front that has any off it, leaving\n * the top one: a reset that lands on the screen already on top, which no stack activates\n * anything for. False when no stack in front had any.\n */\n resetToTop(): boolean {\n return [...this.stacks].reverse().some((stack) => stack.showing() && stack.dropUnderTop());\n }\n\n /** The id of the last navigation a stack put a screen on top for. */\n private lastStacked: number | undefined;\n\n /** A stack put a screen on top, a new one or one it kept, for the navigation with that id. */\n stacked(navigation: number | undefined): void {\n if (navigation !== undefined) this.lastStacked = navigation;\n }\n\n /**\n * Whether a stack put a screen on top for the navigation with that id. One that put none left\n * the screen on top where it was, as a navigation to it with another query does.\n */\n stackedIn(navigation: number): boolean {\n return this.lastStacked === navigation;\n }\n\n /** Pop the innermost stack in front that has a screen at `url` below its top, down to it. */\n popTo(url: string): Promise<boolean> {\n for (const stack of [...this.stacks].reverse()) {\n if (!stack.showing()) continue;\n const popped = stack.popTo(url);\n if (popped) return popped;\n }\n return Promise.resolve(false);\n }\n\n /**\n * Offer an outlet's answer to a back. It returns whether it took the back, and false lets the\n * next one out try. Returns an unsubscribe.\n */\n handle(answer: BackAnswer): () => void {\n this.answers.push(answer);\n const stop = this.hardwareBack.handle(() => answer('button'));\n return () => {\n stop();\n const index = this.answers.indexOf(answer);\n if (index !== -1) this.answers.splice(index, 1);\n };\n }\n\n /** Go back as the button would, innermost outlet first. False when none had anywhere to go. */\n back(): boolean {\n return [...this.answers].reverse().some((answer) => answer('app'));\n }\n}\n\n/**\n * An outlet's answer to a back, told where it came from: Android's button, which is the platform's\n * own dismissal and a screen may refuse, or the app's `NativeNavigation.back()`, which it may not.\n */\nexport type BackAnswer = (from: 'button' | 'app') => boolean;\n\n/**\n * Whether a route is part of what the router shows now, rather than a subtree the reuse strategy\n * detached and is keeping for later: a tab behind, or a screen covered by one pushed over it.\n */\nexport function isShowing(router: Router, route: ActivatedRoute | null): boolean {\n if (!route) return false;\n const visit = (node: ActivatedRoute): boolean => node === route || node.children.some(visit);\n return visit(router.routerState.root);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"native-back.js","sourceRoot":"","sources":["../src/native-back.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Who answers a back: Android's hardware button, and `NativeNavigation.back()`.\n *\n * Every outlet offers an answer, and the one in front takes it. Each answer is also handed to\n * `HardwareBack` directly, where React Native asks the newest first. An outlet always subscribes\n * after the outlet it sits inside, so that order runs from the innermost outlet out, and a\n * screen's own handler, subscribed after its outlet, still outranks it. `back()` asks the outlets\n * in that same order, without the screens' own handlers: those are for the button.\n *\n * Newest first is not enough on its own. A stack in a tab behind the one in front, or under a\n * screen pushed over the whole tab bar, is still subscribed, so each answer first checks that\n * its outlet is showing what the router is showing.\n */\nimport { Service, inject } from '@angular/core';\nimport type { ActivatedRoute, Router } from '@angular/router';\nimport { HardwareBack } from '@ng-native/device';\n\n/** What a stack offers `NativeNavigation` beyond a back: going down it several screens at once. */\nexport interface PoppableStack {\n /** Whether this stack is part of what the router shows now. */\n showing(): boolean;\n /** Pop to its first screen, or null when it is showing only that one. */\n popToRoot(): Promise<boolean> | null;\n /** Pop to the screen showing `url`, or null when no screen below the top shows it. */\n popTo(url: string): Promise<boolean> | null;\n /** Take every screen under the top off at once, or false when it is showing only that one. */\n dropUnderTop(): boolean;\n}\n\n/**\n * What a tab bar offers `NativeNavigation` for a push into one of its tabs from outside it. A tab\n * nobody has opened has no stack yet, and a page pushed into it would be the stack's first\n * screen, with nothing under it to go back to.\n */\nexport interface TabBar {\n /** The url of the tab `url` is a page inside, when that tab has not been opened. */\n unopenedTabOf(url: string): string | null;\n /** Whether `url` is a tab other than the one in front, or a page inside one. */\n behind(url: string): boolean;\n /**\n * Where the tab `url` is in was left, when a screen of the stack the bar is on covers the bar:\n * the url that brings the bar back in front at that tab. Null when the bar is in front, or\n * `url` is in none of its tabs.\n */\n coveredAt(url: string): string | null;\n}\n\n@Service()\nexport class NativeBack {\n private readonly hardwareBack = inject(HardwareBack);\n /** Oldest first, as `HardwareBack` holds them. */\n private readonly answers: BackAnswer[] = [];\n /** Oldest first, and so outermost first, as the answers are. */\n private readonly stacks: PoppableStack[] = [];\n\n /** Oldest first. */\n private readonly tabBars: TabBar[] = [];\n\n /** Offer a tab bar's unopened tabs to a push into one. Returns an unsubscribe. */\n addTabBar(bar: TabBar): () => void {\n this.tabBars.push(bar);\n return () => {\n const index = this.tabBars.indexOf(bar);\n if (index !== -1) this.tabBars.splice(index, 1);\n };\n }\n\n /** The url of the unopened tab `url` is a page inside, or null: see `TabBar`. */\n unopenedTabOf(url: string): string | null {\n for (const bar of this.tabBars) {\n const root = bar.unopenedTabOf(url);\n if (root) return root;\n }\n return null;\n }\n\n /** Where a covered bar's tab holding `url` was left, or null: see `TabBar.coveredAt`. */\n coveredTabAt(url: string): string | null {\n for (const bar of this.tabBars) {\n const at = bar.coveredAt(url);\n if (at) return at;\n }\n return null;\n }\n\n /** Whether `url` belongs to a tab that is not the one in front. */\n inTabBehind(url: string): boolean {\n return this.tabBars.some((bar) => bar.behind(url));\n }\n\n /**\n * Whether the app's own stack takes a page presented over whatever is showing. Set by the root\n * stack outlet for as long as there is one: see `presented-route.ts`.\n */\n presents = false;\n\n /** Offer a stack for popping several screens at once. Returns an unsubscribe. */\n addStack(stack: PoppableStack): () => void {\n this.stacks.push(stack);\n return () => {\n const index = this.stacks.indexOf(stack);\n if (index !== -1) this.stacks.splice(index, 1);\n };\n }\n\n /** Pop the innermost stack in front that is deeper than one screen, to its first. */\n popToRoot(): Promise<boolean> {\n for (const stack of [...this.stacks].reverse()) {\n if (!stack.showing()) continue;\n const popped = stack.popToRoot();\n if (popped) return popped;\n }\n return Promise.resolve(false);\n }\n\n /**\n * Take the screens under the top of the innermost stack in front that has any off it, leaving\n * the top one: a reset that lands on the screen already on top, which no stack activates\n * anything for. False when no stack in front had any.\n */\n resetToTop(): boolean {\n return [...this.stacks].reverse().some((stack) => stack.showing() && stack.dropUnderTop());\n }\n\n /** The id of the last navigation a stack put a screen on top for. */\n private lastStacked: number | undefined;\n\n /** A stack put a screen on top, a new one or one it kept, for the navigation with that id. */\n stacked(navigation: number | undefined): void {\n if (navigation !== undefined) this.lastStacked = navigation;\n }\n\n /**\n * Whether a stack put a screen on top for the navigation with that id. One that put none left\n * the screen on top where it was, as a navigation to it with another query does.\n */\n stackedIn(navigation: number): boolean {\n return this.lastStacked === navigation;\n }\n\n /** Pop the innermost stack in front that has a screen at `url` below its top, down to it. */\n popTo(url: string): Promise<boolean> {\n for (const stack of [...this.stacks].reverse()) {\n if (!stack.showing()) continue;\n const popped = stack.popTo(url);\n if (popped) return popped;\n }\n return Promise.resolve(false);\n }\n\n /**\n * Offer an outlet's answer to a back. It returns whether it took the back, and false lets the\n * next one out try. Returns an unsubscribe.\n */\n handle(answer: BackAnswer): () => void {\n this.answers.push(answer);\n const stop = this.hardwareBack.handle(() => answer('button'));\n return () => {\n stop();\n const index = this.answers.indexOf(answer);\n if (index !== -1) this.answers.splice(index, 1);\n };\n }\n\n /** Go back as the button would, innermost outlet first. False when none had anywhere to go. */\n back(): boolean {\n return [...this.answers].reverse().some((answer) => answer('app'));\n }\n}\n\n/**\n * An outlet's answer to a back, told where it came from: Android's button, which is the platform's\n * own dismissal and a screen may refuse, or the app's `NativeNavigation.back()`, which it may not.\n */\nexport type BackAnswer = (from: 'button' | 'app') => boolean;\n\n/**\n * Whether a route is part of what the router shows now, rather than a subtree the reuse strategy\n * detached and is keeping for later: a tab behind, or a screen covered by one pushed over it.\n */\nexport function isShowing(router: Router, route: ActivatedRoute | null): boolean {\n if (!route) return false;\n const visit = (node: ActivatedRoute): boolean => node === route || node.children.some(visit);\n return visit(router.routerState.root);\n}\n"]}
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
import * as i0 from "@angular/core";
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* The bar slots. `title` and `center` are the same place: iOS draws both as the title view, and
|
|
4
|
+
* `title` is committed as `center`, the only spelling Android's header knows.
|
|
5
|
+
*/
|
|
3
6
|
export type HeaderItemType = 'back' | 'left' | 'center' | 'title' | 'right' | 'searchBar';
|
|
4
7
|
export declare class NativeHeaderItem {
|
|
5
8
|
constructor();
|
|
6
9
|
/** Which slot to sit in. Native defaults to `left`. */
|
|
7
10
|
readonly type: import("@angular/core").InputSignal<HeaderItemType | undefined>;
|
|
11
|
+
/**
|
|
12
|
+
* What reaches native. react-native-screens' spec lists `title`, and iOS takes it, but Android's
|
|
13
|
+
* `ScreenStackHeaderSubviewManager` throws `Unknown type title` while mounting the item, which
|
|
14
|
+
* takes the screen down with it: a page that worked on iOS crashed on Android as it opened.
|
|
15
|
+
*/
|
|
16
|
+
protected readonly slot: import("@angular/core").Signal<"back" | "left" | "center" | "right" | "searchBar" | undefined>;
|
|
8
17
|
/** Opt out of the bar's shared background behind this item. */
|
|
9
18
|
readonly hidesSharedBackground: import("@angular/core").InputSignalWithTransform<boolean | undefined, unknown>;
|
|
10
19
|
static ɵfac: i0.ɵɵFactoryDeclaration<NativeHeaderItem, never>;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* Native bar button items would look truer to the platform and bring menus and system symbols
|
|
11
11
|
* with them, but they are data rather than views; they are a later opt-in.
|
|
12
12
|
*/
|
|
13
|
-
import { Component, ElementRef, inject, input } from '@angular/core';
|
|
13
|
+
import { Component, ElementRef, computed, inject, input } from '@angular/core';
|
|
14
14
|
import { ownHost } from "./own-host.js";
|
|
15
15
|
import { optionalBoolean } from "./transforms.js";
|
|
16
16
|
import * as i0 from "@angular/core";
|
|
@@ -21,10 +21,20 @@ export class NativeHeaderItem {
|
|
|
21
21
|
/** Which slot to sit in. Native defaults to `left`. */
|
|
22
22
|
type = input(/* @ts-ignore */
|
|
23
23
|
...(ngDevMode ? [undefined, { debugName: "type" }] : /* istanbul ignore next */ []));
|
|
24
|
+
/**
|
|
25
|
+
* What reaches native. react-native-screens' spec lists `title`, and iOS takes it, but Android's
|
|
26
|
+
* `ScreenStackHeaderSubviewManager` throws `Unknown type title` while mounting the item, which
|
|
27
|
+
* takes the screen down with it: a page that worked on iOS crashed on Android as it opened.
|
|
28
|
+
*/
|
|
29
|
+
slot = computed(() => {
|
|
30
|
+
const type = this.type();
|
|
31
|
+
return type === 'title' ? 'center' : type;
|
|
32
|
+
}, /* @ts-ignore */
|
|
33
|
+
...(ngDevMode ? [{ debugName: "slot" }] : /* istanbul ignore next */ []));
|
|
24
34
|
/** Opt out of the bar's shared background behind this item. */
|
|
25
35
|
hidesSharedBackground = input(undefined, { ...(ngDevMode ? { debugName: "hidesSharedBackground" } : /* istanbul ignore next */ {}), transform: optionalBoolean });
|
|
26
36
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: NativeHeaderItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
27
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.2.0", type: NativeHeaderItem, isStandalone: true, selector: "native-header-item", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, hidesSharedBackground: { classPropertyName: "hidesSharedBackground", publicName: "hidesSharedBackground", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "type": "
|
|
37
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.2.0", type: NativeHeaderItem, isStandalone: true, selector: "native-header-item", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, hidesSharedBackground: { classPropertyName: "hidesSharedBackground", publicName: "hidesSharedBackground", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "type": "slot()", "hidesSharedBackground": "hidesSharedBackground()" } }, ngImport: i0, template: '<ng-content />', isInline: true });
|
|
28
38
|
}
|
|
29
39
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: NativeHeaderItem, decorators: [{
|
|
30
40
|
type: Component,
|
|
@@ -32,7 +42,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
|
|
|
32
42
|
selector: 'native-header-item',
|
|
33
43
|
template: '<ng-content />',
|
|
34
44
|
host: {
|
|
35
|
-
'[type]': '
|
|
45
|
+
'[type]': 'slot()',
|
|
36
46
|
'[hidesSharedBackground]': 'hidesSharedBackground()',
|
|
37
47
|
},
|
|
38
48
|
}]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-header-item.js","sourceRoot":"","sources":["../src/native-header-item.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"native-header-item.js","sourceRoot":"","sources":["../src/native-header-item.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAE/E,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;;AAgBlD,MAAM,OAAO,gBAAgB;IAC3B;QACE,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,aAA2B,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAC5E,CAAC;IAED,uDAAuD;IAC9C,IAAI,GAAG,KAAK;wFAAkB,CAAC;IAExC;;;;OAIG;IACgB,IAAI,GAAG,QAAQ,CAAC,GAAG,EAAE;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACzB,OAAO,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5C,CAAC;6EAAC,CAAC;IACH,+DAA+D;IACtD,qBAAqB,GAAG,KAAK,CAAC,SAAS,6FAAI,SAAS,EAAE,eAAe,GAAG,CAAC;uGAlBvE,gBAAgB;2FAAhB,gBAAgB,udANjB,gBAAgB;;2FAMf,gBAAgB;kBAR5B,SAAS;mBAAC;oBACT,QAAQ,EAAE,oBAAoB;oBAC9B,QAAQ,EAAE,gBAAgB;oBAC1B,IAAI,EAAE;wBACJ,QAAQ,EAAE,QAAQ;wBAClB,yBAAyB,EAAE,yBAAyB;qBACrD;iBACF","sourcesContent":["/**\n * Anything Angular can render, placed in one of the navigation bar's slots.\n *\n * Commits as `RNSScreenStackHeaderSubview`, whose `type` picks the slot. A `right` item is the\n * usual \"Done\" or \"Edit\" button; `back` replaces the chevron, which needs\n * `backButtonInCustomView` on the header; `searchBar` expects a search bar rather than\n * arbitrary content.\n *\n * Press handling is the responder system, so a `pressable` inside one works like anywhere else.\n * Native bar button items would look truer to the platform and bring menus and system symbols\n * with them, but they are data rather than views; they are a later opt-in.\n */\nimport { Component, ElementRef, computed, inject, input } from '@angular/core';\nimport type { EngineNode } from '@ng-native/fabric';\nimport { ownHost } from './own-host.ts';\nimport { optionalBoolean } from './transforms.ts';\n\n/**\n * The bar slots. `title` and `center` are the same place: iOS draws both as the title view, and\n * `title` is committed as `center`, the only spelling Android's header knows.\n */\nexport type HeaderItemType = 'back' | 'left' | 'center' | 'title' | 'right' | 'searchBar';\n\n@Component({\n selector: 'native-header-item',\n template: '<ng-content />',\n host: {\n '[type]': 'slot()',\n '[hidesSharedBackground]': 'hidesSharedBackground()',\n },\n})\nexport class NativeHeaderItem {\n constructor() {\n ownHost(inject(ElementRef).nativeElement as EngineNode, this.constructor);\n }\n\n /** Which slot to sit in. Native defaults to `left`. */\n readonly type = input<HeaderItemType>();\n\n /**\n * What reaches native. react-native-screens' spec lists `title`, and iOS takes it, but Android's\n * `ScreenStackHeaderSubviewManager` throws `Unknown type title` while mounting the item, which\n * takes the screen down with it: a page that worked on iOS crashed on Android as it opened.\n */\n protected readonly slot = computed(() => {\n const type = this.type();\n return type === 'title' ? 'center' : type;\n });\n /** Opt out of the bar's shared background behind this item. */\n readonly hidesSharedBackground = input(undefined, { transform: optionalBoolean });\n}\n"]}
|
|
@@ -88,6 +88,11 @@ export declare class NativeNavigation {
|
|
|
88
88
|
popToRoot(): Promise<boolean>;
|
|
89
89
|
private go;
|
|
90
90
|
/**
|
|
91
|
+
* A push to a page of a tab bar that a screen over it covers, pushed on the app's own stack or
|
|
92
|
+
* presented, goes back to the bar first: to its tab, where that was left, and then pushes the
|
|
93
|
+
* page there unless the tab is already showing it. One tab bar, as a native app has. Pushed as
|
|
94
|
+
* it was asked, the page would build a second bar over the screen.
|
|
95
|
+
*
|
|
91
96
|
* A push into a tab nobody has opened goes to the tab first, so its stack has the tab's own
|
|
92
97
|
* first screen under the page, and a back from the page lands there: what a tab bar with a
|
|
93
98
|
* navigation controller per tab does. Without it the page is the stack's only screen, and the
|
|
@@ -98,7 +103,8 @@ export declare class NativeNavigation {
|
|
|
98
103
|
/** The path the commands lead to, without its query and fragment. */
|
|
99
104
|
private pathFor;
|
|
100
105
|
/**
|
|
101
|
-
* A page of a tab that is not in front, presented over the one that is
|
|
106
|
+
* A page of a tab that is not in front, presented over the one that is, or over a screen that
|
|
107
|
+
* covers the bar: its url would select
|
|
102
108
|
* its own tab and show it there, so it goes to the root's presented outlet instead, where the
|
|
103
109
|
* app's own stack shows it over everything. See `presented-route.ts`. Null for a page of the
|
|
104
110
|
* tab in front, or of no tab, which is presented where its url puts it.
|
|
@@ -113,3 +119,9 @@ export declare class NativeNavigation {
|
|
|
113
119
|
private firstNavigationRunning;
|
|
114
120
|
private firstNavigation;
|
|
115
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Whether a navigation ended only for another to take its place: a guard's redirect does, and so
|
|
124
|
+
* does a newer navigation. Waiting for a navigation to end goes on past one of these, or what
|
|
125
|
+
* starts next supersedes the redirect and opens with nothing beneath it, past the guard.
|
|
126
|
+
*/
|
|
127
|
+
export declare function carriesOn(event: unknown): boolean;
|
|
@@ -22,6 +22,10 @@ import { leavingPresented, presentedCommands } from "./presented-route.js";
|
|
|
22
22
|
* one reserved key rather than spread through it.
|
|
23
23
|
*/
|
|
24
24
|
export const NATIVE_INTENT = 'ɵnativeStack';
|
|
25
|
+
/** Whether commands ask for a query or a fragment, written into a url string or as extras. */
|
|
26
|
+
const asksMore = (commands, extras) => (typeof commands === 'string' && /[?#]/.test(commands)) ||
|
|
27
|
+
extras.queryParams != null ||
|
|
28
|
+
extras.fragment != null;
|
|
25
29
|
/** A url string up to its query or fragment. */
|
|
26
30
|
const pathOf = (url) => url.split(/[?#]/, 1)[0];
|
|
27
31
|
/** Read the intent off a navigation's state, if it carries one. */
|
|
@@ -135,6 +139,9 @@ export class NativeNavigation {
|
|
|
135
139
|
* `gestureEnabled: false` neither can.
|
|
136
140
|
*/
|
|
137
141
|
present(commands, options = {}) {
|
|
142
|
+
if (this.firstNavigationRunning()) {
|
|
143
|
+
return this.firstNavigation().then(() => this.present(commands, options));
|
|
144
|
+
}
|
|
138
145
|
const { as = 'modal', presentation, ...extras } = options;
|
|
139
146
|
const intent = {
|
|
140
147
|
stack: 'push',
|
|
@@ -228,6 +235,11 @@ export class NativeNavigation {
|
|
|
228
235
|
: start();
|
|
229
236
|
}
|
|
230
237
|
/**
|
|
238
|
+
* A push to a page of a tab bar that a screen over it covers, pushed on the app's own stack or
|
|
239
|
+
* presented, goes back to the bar first: to its tab, where that was left, and then pushes the
|
|
240
|
+
* page there unless the tab is already showing it. One tab bar, as a native app has. Pushed as
|
|
241
|
+
* it was asked, the page would build a second bar over the screen.
|
|
242
|
+
*
|
|
231
243
|
* A push into a tab nobody has opened goes to the tab first, so its stack has the tab's own
|
|
232
244
|
* first screen under the page, and a back from the page lands there: what a tab bar with a
|
|
233
245
|
* navigation controller per tab does. Without it the page is the stack's only screen, and the
|
|
@@ -237,20 +249,36 @@ export class NativeNavigation {
|
|
|
237
249
|
underTabRoot(commands, extras, intent, navigate) {
|
|
238
250
|
if (intent.stack !== 'push' || intent.presentation)
|
|
239
251
|
return navigate();
|
|
240
|
-
const
|
|
252
|
+
const path = this.pathFor(commands, extras);
|
|
253
|
+
const left = this.outlets.coveredTabAt(path);
|
|
254
|
+
if (left) {
|
|
255
|
+
// The tab is open once the bar is back, so the page goes straight onto it, unless it is the
|
|
256
|
+
// page the tab was left on and nothing more, a query or a fragment, is asked of it.
|
|
257
|
+
const asked = pathOf(left) !== path || asksMore(commands, extras);
|
|
258
|
+
// A guard that redirects elsewhere still resolves true, so the tab must be in front now.
|
|
259
|
+
return this.router.navigateByUrl(left).then((arrived) => {
|
|
260
|
+
const there = arrived && !this.outlets.coveredTabAt(path) && !this.outlets.inTabBehind(path);
|
|
261
|
+
return there && asked ? navigate() : there;
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
const tab = this.outlets.unopenedTabOf(path);
|
|
241
265
|
if (!tab)
|
|
242
266
|
return navigate();
|
|
243
|
-
return this.router
|
|
267
|
+
return this.router
|
|
268
|
+
.navigateByUrl(tab)
|
|
269
|
+
.then((arrived) => (arrived && !this.outlets.unopenedTabOf(path) ? navigate() : false));
|
|
244
270
|
}
|
|
245
271
|
/** The path the commands lead to, without its query and fragment. */
|
|
246
272
|
pathFor(commands, extras) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
273
|
+
if (typeof commands === 'string' && commands.startsWith('/'))
|
|
274
|
+
return pathOf(commands);
|
|
275
|
+
// Resolved as `go` navigates them: a relative string against `relativeTo`, as a command.
|
|
276
|
+
const list = typeof commands === 'string' ? [pathOf(commands)] : [...commands];
|
|
277
|
+
return pathOf(this.router.serializeUrl(this.router.createUrlTree(list, extras)));
|
|
251
278
|
}
|
|
252
279
|
/**
|
|
253
|
-
* A page of a tab that is not in front, presented over the one that is
|
|
280
|
+
* A page of a tab that is not in front, presented over the one that is, or over a screen that
|
|
281
|
+
* covers the bar: its url would select
|
|
254
282
|
* its own tab and show it there, so it goes to the root's presented outlet instead, where the
|
|
255
283
|
* app's own stack shows it over everything. See `presented-route.ts`. Null for a page of the
|
|
256
284
|
* tab in front, or of no tab, which is presented where its url puts it.
|
|
@@ -259,7 +287,8 @@ export class NativeNavigation {
|
|
|
259
287
|
if (!this.outlets.presents)
|
|
260
288
|
return null;
|
|
261
289
|
const path = this.pathFor(commands, extras);
|
|
262
|
-
|
|
290
|
+
// A tab in front of a bar a screen covers is behind that screen just the same.
|
|
291
|
+
if (!this.outlets.inTabBehind(path) && !this.outlets.coveredTabAt(path))
|
|
263
292
|
return null;
|
|
264
293
|
const query = typeof commands === 'string' ? this.queryOf(commands, extras) : {};
|
|
265
294
|
return presentedCommands(this.router, path).then((presented) => presented && { commands: presented, extras: { ...extras, ...query, relativeTo: null } });
|
|
@@ -286,9 +315,7 @@ export class NativeNavigation {
|
|
|
286
315
|
firstNavigation() {
|
|
287
316
|
return new Promise((resolve) => {
|
|
288
317
|
const events = this.router.events.subscribe((event) => {
|
|
289
|
-
if (event
|
|
290
|
-
event instanceof NavigationCancel ||
|
|
291
|
-
event instanceof NavigationError) {
|
|
318
|
+
if (ended(event) && !carriesOn(event)) {
|
|
292
319
|
events.unsubscribe();
|
|
293
320
|
resolve();
|
|
294
321
|
}
|
|
@@ -296,4 +323,14 @@ export class NativeNavigation {
|
|
|
296
323
|
});
|
|
297
324
|
}
|
|
298
325
|
}
|
|
326
|
+
/**
|
|
327
|
+
* Whether a navigation ended only for another to take its place: a guard's redirect does, and so
|
|
328
|
+
* does a newer navigation. Waiting for a navigation to end goes on past one of these, or what
|
|
329
|
+
* starts next supersedes the redirect and opens with nothing beneath it, past the guard.
|
|
330
|
+
*/
|
|
331
|
+
export function carriesOn(event) {
|
|
332
|
+
return (event instanceof NavigationCancel &&
|
|
333
|
+
(event.code === NavigationCancellationCode.Redirect ||
|
|
334
|
+
event.code === NavigationCancellationCode.SupersededByNewNavigation));
|
|
335
|
+
}
|
|
299
336
|
//# sourceMappingURL=native-navigation.js.map
|
|
@@ -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; 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"]}
|
|
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/** Whether commands ask for a query or a fragment, written into a url string or as extras. */\nconst asksMore = (commands: NavigationCommands, extras: NavigationExtras): boolean =>\n (typeof commands === 'string' && /[?#]/.test(commands)) ||\n extras.queryParams != null ||\n extras.fragment != null;\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 if (this.firstNavigationRunning()) {\n return this.firstNavigation().then(() => this.present(commands, options));\n }\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 to a page of a tab bar that a screen over it covers, pushed on the app's own stack or\n * presented, goes back to the bar first: to its tab, where that was left, and then pushes the\n * page there unless the tab is already showing it. One tab bar, as a native app has. Pushed as\n * it was asked, the page would build a second bar over the screen.\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 path = this.pathFor(commands, extras);\n const left = this.outlets.coveredTabAt(path);\n if (left) {\n // The tab is open once the bar is back, so the page goes straight onto it, unless it is the\n // page the tab was left on and nothing more, a query or a fragment, is asked of it.\n const asked = pathOf(left) !== path || asksMore(commands, extras);\n // A guard that redirects elsewhere still resolves true, so the tab must be in front now.\n return this.router.navigateByUrl(left).then((arrived) => {\n const there =\n arrived && !this.outlets.coveredTabAt(path) && !this.outlets.inTabBehind(path);\n return there && asked ? navigate() : there;\n });\n }\n const tab = this.outlets.unopenedTabOf(path);\n if (!tab) return navigate();\n return this.router\n .navigateByUrl(tab)\n .then((arrived) => (arrived && !this.outlets.unopenedTabOf(path) ? 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 if (typeof commands === 'string' && commands.startsWith('/')) return pathOf(commands);\n // Resolved as `go` navigates them: a relative string against `relativeTo`, as a command.\n const list = typeof commands === 'string' ? [pathOf(commands)] : [...commands];\n return pathOf(this.router.serializeUrl(this.router.createUrlTree(list, extras)));\n }\n\n /**\n * A page of a tab that is not in front, presented over the one that is, or over a screen that\n * covers the bar: 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 // A tab in front of a bar a screen covers is behind that screen just the same.\n if (!this.outlets.inTabBehind(path) && !this.outlets.coveredTabAt(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 (ended(event) && !carriesOn(event)) {\n events.unsubscribe();\n resolve();\n }\n });\n });\n }\n}\n\n/**\n * Whether a navigation ended only for another to take its place: a guard's redirect does, and so\n * does a newer navigation. Waiting for a navigation to end goes on past one of these, or what\n * starts next supersedes the redirect and opens with nothing beneath it, past the guard.\n */\nexport function carriesOn(event: unknown): boolean {\n return (\n event instanceof NavigationCancel &&\n (event.code === NavigationCancellationCode.Redirect ||\n event.code === NavigationCancellationCode.SupersededByNewNavigation)\n );\n}\n"]}
|
|
@@ -6,7 +6,7 @@ export declare class NativeRouterLink {
|
|
|
6
6
|
readonly extras: import("@angular/core").InputSignal<NavigationExtras | undefined>;
|
|
7
7
|
/** Replace the current screen rather than pushing a new one. */
|
|
8
8
|
readonly replace: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
|
|
9
|
-
private readonly
|
|
9
|
+
private readonly navigation;
|
|
10
10
|
private readonly route;
|
|
11
11
|
protected navigate(): void;
|
|
12
12
|
static ɵfac: i0.ɵɵFactoryDeclaration<NativeRouterLink, never>;
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* depend on the components package.
|
|
10
10
|
*/
|
|
11
11
|
import { Directive, booleanAttribute, inject, input } from '@angular/core';
|
|
12
|
-
import { ActivatedRoute
|
|
13
|
-
import {
|
|
12
|
+
import { ActivatedRoute } from '@angular/router';
|
|
13
|
+
import { NativeNavigation } from "./native-navigation.js";
|
|
14
14
|
import * as i0 from "@angular/core";
|
|
15
15
|
export class NativeRouterLink {
|
|
16
16
|
/** A url string, or the command array `Router.navigate` takes. */
|
|
@@ -20,25 +20,28 @@ export class NativeRouterLink {
|
|
|
20
20
|
...(ngDevMode ? [undefined, { debugName: "extras" }] : /* istanbul ignore next */ []));
|
|
21
21
|
/** Replace the current screen rather than pushing a new one. */
|
|
22
22
|
replace = input(false, { ...(ngDevMode ? { debugName: "replace" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
23
|
-
|
|
23
|
+
navigation = inject(NativeNavigation);
|
|
24
24
|
route = inject(ActivatedRoute, { optional: true });
|
|
25
25
|
navigate() {
|
|
26
26
|
const target = this.nativeRouterLink();
|
|
27
|
-
const
|
|
27
|
+
const first = Array.isArray(target) ? target[0] : target;
|
|
28
|
+
// An absolute link leads to the same place from anywhere. Resolved against a route inside a
|
|
29
|
+
// presented page, it would keep that page's outlet in the url, and the page on screen.
|
|
30
|
+
const absolute = typeof first === 'string' && first.startsWith('/');
|
|
28
31
|
const extras = {
|
|
29
|
-
relativeTo: this.route,
|
|
32
|
+
relativeTo: absolute ? null : this.route,
|
|
30
33
|
replaceUrl: this.replace(),
|
|
31
|
-
...
|
|
34
|
+
...this.extras(),
|
|
32
35
|
};
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
// `replaceUrl` only swaps the history entry: without a replace the replaced screen stays
|
|
37
|
+
// mounted underneath, and a swipe back lands on a page the history no longer has. So the link
|
|
38
|
+
// replaces when the navigation has `replaceUrl`, `[extras]` included, not the `replace` input
|
|
39
|
+
// alone. Everything else is a push, the same one `NativeNavigation.push()` makes: into a tab
|
|
40
|
+
// nobody has opened, over the tab's first screen, and out of a presented page.
|
|
41
|
+
const commands = Array.isArray(target) ? [...target] : target;
|
|
42
|
+
void (extras.replaceUrl
|
|
43
|
+
? this.navigation.replace(commands, extras)
|
|
44
|
+
: this.navigation.push(commands, extras));
|
|
42
45
|
}
|
|
43
46
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: NativeRouterLink, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
44
47
|
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.2.0", type: NativeRouterLink, isStandalone: true, selector: "[nativeRouterLink]", inputs: { nativeRouterLink: { classPropertyName: "nativeRouterLink", publicName: "nativeRouterLink", isSignal: true, isRequired: true, transformFunction: null }, extras: { classPropertyName: "extras", publicName: "extras", isSignal: true, isRequired: false, transformFunction: null }, replace: { classPropertyName: "replace", publicName: "replace", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "press": "navigate()" } }, ngImport: i0 });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-router-link.js","sourceRoot":"","sources":["../src/native-router-link.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"native-router-link.js","sourceRoot":"","sources":["../src/native-router-link.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAyB,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;;AAM1D,MAAM,OAAO,gBAAgB;IAC3B,kEAAkE;IACzD,gBAAgB,GAAG,KAAK,CAAC,QAAQ;yFAA+B,CAAC;IACjE,MAAM,GAAG,KAAK;0FAAoB,CAAC;IAE5C,gEAAgE;IACvD,OAAO,GAAG,KAAK,CAAC,KAAK,+EAAI,SAAS,EAAE,gBAAgB,GAAG,CAAC;IAEhD,UAAU,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACtC,KAAK,GAAG,MAAM,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1D,QAAQ;QAChB,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACvC,MAAM,KAAK,GAAY,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAClE,4FAA4F;QAC5F,uFAAuF;QACvF,MAAM,QAAQ,GAAG,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACpE,MAAM,MAAM,GAAqB;YAC/B,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK;YACxC,UAAU,EAAE,IAAI,CAAC,OAAO,EAAE;YAC1B,GAAG,IAAI,CAAC,MAAM,EAAE;SACjB,CAAC;QACF,yFAAyF;QACzF,8FAA8F;QAC9F,8FAA8F;QAC9F,6FAA6F;QAC7F,+EAA+E;QAC/E,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC9D,KAAK,CAAC,MAAM,CAAC,UAAU;YACrB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC;YAC3C,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9C,CAAC;uGA/BU,gBAAgB;2FAAhB,gBAAgB;;2FAAhB,gBAAgB;kBAJ5B,SAAS;mBAAC;oBACT,QAAQ,EAAE,oBAAoB;oBAC9B,IAAI,EAAE,EAAE,SAAS,EAAE,YAAY,EAAE;iBAClC","sourcesContent":["/**\n * `routerLink` for native.\n *\n * Angular's `RouterLink` host-binds `href` and listens for a DOM click, neither of which exists\n * here. This binds to a `<pressable>`'s `press` output instead.\n *\n * Because Angular resolves outputs across every directive on an element, the host listener below\n * binds to `Pressable`'s `press` output without importing it, so the router package does not\n * depend on the components package.\n */\nimport { Directive, booleanAttribute, inject, input } from '@angular/core';\nimport { ActivatedRoute, type NavigationExtras } from '@angular/router';\nimport { NativeNavigation } from './native-navigation.ts';\n\n@Directive({\n selector: '[nativeRouterLink]',\n host: { '(press)': 'navigate()' },\n})\nexport class NativeRouterLink {\n /** A url string, or the command array `Router.navigate` takes. */\n readonly nativeRouterLink = input.required<string | readonly unknown[]>();\n readonly extras = input<NavigationExtras>();\n\n /** Replace the current screen rather than pushing a new one. */\n readonly replace = input(false, { transform: booleanAttribute });\n\n private readonly navigation = inject(NativeNavigation);\n private readonly route = inject(ActivatedRoute, { optional: true });\n\n protected navigate(): void {\n const target = this.nativeRouterLink();\n const first: unknown = Array.isArray(target) ? target[0] : target;\n // An absolute link leads to the same place from anywhere. Resolved against a route inside a\n // presented page, it would keep that page's outlet in the url, and the page on screen.\n const absolute = typeof first === 'string' && first.startsWith('/');\n const extras: NavigationExtras = {\n relativeTo: absolute ? null : this.route,\n replaceUrl: this.replace(),\n ...this.extras(),\n };\n // `replaceUrl` only swaps the history entry: without a replace the replaced screen stays\n // mounted underneath, and a swipe back lands on a page the history no longer has. So the link\n // replaces when the navigation has `replaceUrl`, `[extras]` included, not the `replace` input\n // alone. Everything else is a push, the same one `NativeNavigation.push()` makes: into a tab\n // nobody has opened, over the tab's first screen, and out of a presented page.\n const commands = Array.isArray(target) ? [...target] : target;\n void (extras.replaceUrl\n ? this.navigation.replace(commands, extras)\n : this.navigation.push(commands, extras));\n }\n}\n"]}
|