@ng-native/router 0.18.2 → 0.19.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/file-routes.js +25 -9
- package/dist/file-routes.js.map +1 -1
- package/dist/native-back.d.ts +8 -0
- package/dist/native-back.js +8 -0
- package/dist/native-back.js.map +1 -1
- package/dist/native-header.d.ts +6 -1
- package/dist/native-header.js +6 -1
- package/dist/native-header.js.map +1 -1
- package/dist/native-navigation.d.ts +4 -0
- package/dist/native-navigation.js +7 -2
- package/dist/native-navigation.js.map +1 -1
- package/dist/native-search-bar.js +3 -1
- package/dist/native-search-bar.js.map +1 -1
- package/dist/native-stack-outlet.d.ts +11 -11
- package/dist/native-stack-outlet.js +23 -27
- package/dist/native-stack-outlet.js.map +1 -1
- package/dist/native-stack-reuse-strategy.d.ts +2 -0
- package/dist/native-stack-reuse-strategy.js +8 -6
- package/dist/native-stack-reuse-strategy.js.map +1 -1
- package/dist/native-tabs-outlet.d.ts +24 -2
- package/dist/native-tabs-outlet.js +83 -18
- package/dist/native-tabs-outlet.js.map +1 -1
- package/dist/presented-route.d.ts +2 -1
- package/dist/presented-route.js +48 -7
- package/dist/presented-route.js.map +1 -1
- package/dist/provide-native-router.js +2 -0
- package/dist/provide-native-router.js.map +1 -1
- package/dist/refuse-screens-under-full-screen.d.ts +15 -0
- package/dist/refuse-screens-under-full-screen.js +80 -0
- package/dist/refuse-screens-under-full-screen.js.map +1 -0
- package/dist/screens.js +4 -5
- package/dist/screens.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presented-route.js","sourceRoot":"","sources":["../src/presented-route.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A page presented over whatever is showing, when its url belongs to a tab that is not.\n *\n * The router puts a route where its url sits in the route tree: `/invoices/7` is the Invoices\n * tab's, so navigating there selects that tab and shows the page in its stack. A sheet over the\n * tab the user is on has to be somewhere else, and the router has a place for that, a named\n * outlet at the root. So the page's route gets a copy there, made the first time it is presented,\n * and `present()` navigates to the copy: `/home(presented:invoices/7)`. The router still runs the\n * navigation, so the page's guards, resolvers, lazy component and params are what they are in its\n * tab, and a back goes through history as any other does.\n */\nimport {\n PRIMARY_OUTLET,\n type NavigationExtras,\n type Route,\n type Router,\n type Routes,\n type UrlTree,\n} from '@angular/router';\nimport { primarySegments, segmentCommands } from './url-commands.ts';\n\n/** The root outlet a page of another tab is presented in. */\nexport const PRESENTED = 'presented';\n\n/**\n * How many of `segments` a route's path takes, or null when it does not match them or is one this\n * does not follow: a redirect, a custom matcher, a wildcard, or a route of another outlet.\n *\n * ponytail: static and `:param` segments only, which is what a page's url is made of. The rest\n * falls back to presenting the page where its url puts it, as before.\n */\nexport function taken(route: Route, segments: readonly string[]): number | null {\n if (route.outlet && route.outlet !== PRIMARY_OUTLET) return null;\n if (route.redirectTo !== undefined || route.matcher || route.path === undefined) return null;\n const parts = route.path ? route.path.split('/') : [];\n if (parts.includes('**') || parts.length > segments.length) return null;\n const matches = parts.every((part, index) => part.startsWith(':') || part === segments[index]);\n return matches ? parts.length : null;\n}\n\n/** The children each lazily loaded route answered with, or null when they are not plain routes. */\nconst lazyChildren = new WeakMap<Route, Promise<Routes | null>>();\n\n/**\n * A route's children, loading them when they are lazy. The router loads them again when it\n * navigates, from the same function, which a dynamic import answers from its cache.\n *\n * ponytail: a loader that answers routes, or a module whose default export is routes, as\n * `loadChildren: () => import('./invoices.routes')` does. An NgModule or an observable falls back\n * to presenting the page where its url puts it.\n */\nfunction childrenOf(route: Route): Promise<Routes | null> | Routes | undefined {\n if (route.children || !route.loadChildren) return route.children;\n let loading = lazyChildren.get(route);\n if (!loading) {\n loading = Promise.resolve()\n .then(() => (route.loadChildren as () => unknown)())\n .then((answer) => {\n const routes = (answer as { default?: unknown } | null)?.default ?? answer;\n return Array.isArray(routes) ? (routes as Routes) : null;\n })\n // A loader that fails is the router's to report, when it navigates there as before.\n .catch(() => null);\n lazyChildren.set(route, loading);\n }\n return loading;\n}\n\n/** A route on the way that the copy cannot stand in for: the search stops, with no copy made. */\nconst STOP = Symbol('stop');\n\n/** A route's children, or `STOP` where the copy cannot follow it: see `chainTo`. */\nasync function followable(route: Route): Promise<Routes | undefined | typeof STOP> {\n if (route.canMatch?.length) return STOP;\n return (await childrenOf(route)) ?? (route.loadChildren ? STOP : undefined);\n}\n\n/**\n * The routes from the root to the one that shows `segments`, null when none of `routes` leads\n * there, or `STOP` at a route with a `canMatch` guard. The router runs that guard against the\n * route and the segments it was matched with, which a copy under another path cannot give it,\n * and leaving it out would let the page match where its own route refuses to.\n */\nasync function chainTo(\n routes: Routes,\n segments: readonly string[],\n): Promise<Route[] | null | typeof STOP> {\n for (const route of routes) {\n const count = taken(route, segments);\n if (count === null) continue;\n const rest = segments.slice(count);\n const children = await followable(route);\n if (children === STOP) return STOP;\n const inside = children && (await chainTo(children, rest));\n if (inside === STOP) return STOP;\n if (inside) return [route, ...inside];\n // A page of its own: a component, and no children to choose among.\n if (!rest.length && !children && (route.component || route.loadComponent)) return [route];\n }\n return null;\n}\n\n/**\n * The page's route as a root route of the presented outlet: its own component, title, data and\n * resolvers, under the whole path, with the guards and providers of the routes it sat inside.\n * Their components are left out: the tab bar and the tab's stack are not what is presented.\n */\nfunction presentedCopy(chain: readonly Route[]): Route {\n const page = chain.at(-1)!;\n const above = chain.slice(0, -1);\n return {\n ...page,\n // Its own children are in the copy by now, where they were lazy.\n loadChildren: undefined,\n path: chain\n .map((route) => route.path)\n .filter(Boolean)\n .join('/'),\n pathMatch: undefined,\n outlet: PRESENTED,\n canActivate: [\n ...above.flatMap((route) => [\n ...(route.canActivate ?? []),\n ...(route.canActivateChild ?? []),\n ]),\n ...(page.canActivate ?? []),\n ],\n providers: [...above.flatMap((route) => route.providers ?? []), ...(page.providers ?? [])],\n resolve: Object.assign({}, ...above.map((route) => route.resolve), page.resolve),\n data: Object.assign({}, ...above.map((route) => route.data), page.data),\n };\n}\n\n/**\n * The commands that present the page at `path` in the root's presented outlet, having given its\n * route a copy there, or null when the config is not one this follows.\n */\nexport async function presentedCommands(router: Router, path: string): Promise<unknown[] | null> {\n // Parsed, so the routes are matched against decoded segments and the escapes are written once.\n const parsed = primarySegments(router, path);\n const segments = parsed.map((segment) => segment.path);\n const config = router.config;\n const chain = await chainTo(config, segments);\n // Routes reset while lazy children loaded: the copy is made from the routes the router has.\n if (router.config !== config) return presentedCommands(router, path);\n if (!chain || chain === STOP) return null;\n const copy = presentedCopy(chain);\n const copied = router.config.some(\n (route) => route.outlet === PRESENTED && route.path === copy.path,\n );\n if (!copied) router.config.push(copy);\n return [{ outlets: { [PRESENTED]: parsed.flatMap(segmentCommands) } }];\n}\n\n/** `url` without the page presented over it: where the app is, under the page. */\nexport function withoutPresented(router: Router, url: string): string {\n // A named outlet is written `(name:path)`, so a url without that has no page to take off.\n if (!url.includes(`${PRESENTED}:`)) return url;\n const tree = router.parseUrl(url);\n delete tree.root.children[PRESENTED];\n return router.serializeUrl(tree);\n}\n\n/**\n * Where `commands` lead with the presented page left behind, when one is up and the commands are\n * not a presentation themselves; null otherwise. A navigation from a presented page goes to its\n * url's own place, which the page is over: left up, it would hide where the app went.\n */\nexport function leavingPresented(\n router: Router,\n commands: readonly unknown[],\n extras: NavigationExtras,\n): UrlTree | null {\n // A named outlet is written `(name:path)`, so a url without that has no page up.\n if (!router.url?.includes(`${PRESENTED}:`)) return null;\n const first = commands[0] as { outlets?: Record<string, unknown> } | undefined;\n if (first?.outlets && PRESENTED in first.outlets) return null;\n const tree = router.createUrlTree([...commands], extras);\n // Commands relative to the page itself, as a link inside it gives them, resolve inside the\n // presented outlet: where they lead is that path in its own place, not beside the page.\n const start = commands[0];\n const absolute = typeof start === 'string' && start.startsWith('/');\n const beside =\n !absolute && extras.relativeTo?.pathFromRoot.some((route) => route.outlet === PRESENTED)\n ? tree.root.children[PRESENTED]\n : undefined;\n if (beside) {\n const path = beside.segments.map((segment) => segment.path);\n const { queryParams, fragment } = tree;\n const own = router.createUrlTree(['/', ...path], {\n queryParams,\n fragment: fragment ?? undefined,\n });\n delete own.root.children[PRESENTED];\n return own;\n }\n delete tree.root.children[PRESENTED];\n return tree;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"presented-route.js","sourceRoot":"","sources":["../src/presented-route.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A page presented over whatever is showing, when its url belongs to a tab that is not.\n *\n * The router puts a route where its url sits in the route tree: `/invoices/7` is the Invoices\n * tab's, so navigating there selects that tab and shows the page in its stack. A sheet over the\n * tab the user is on has to be somewhere else, and the router has a place for that, a named\n * outlet at the root. So the page's route gets a copy there, made the first time it is presented,\n * and `present()` navigates to the copy: `/home(presented:invoices/7)`. The router still runs the\n * navigation, so the page's guards, resolvers, lazy component and params are what they are in its\n * tab, and a back goes through history as any other does.\n */\nimport {\n createEnvironmentInjector,\n runInInjectionContext,\n type EnvironmentInjector,\n} from '@angular/core';\nimport {\n PRIMARY_OUTLET,\n type NavigationExtras,\n type Route,\n type Router,\n type Routes,\n type UrlTree,\n} from '@angular/router';\nimport { primarySegments, segmentCommands } from './url-commands.ts';\n\n/** The root outlet a page of another tab is presented in. */\nexport const PRESENTED = 'presented';\n\n/**\n * How many of `segments` a route's path takes, or null when it does not match them or is one this\n * does not follow: a redirect, a custom matcher, a wildcard, or a route of another outlet.\n *\n * ponytail: static and `:param` segments only, which is what a page's url is made of. The rest\n * falls back to presenting the page where its url puts it, as before.\n */\nexport function taken(route: Route, segments: readonly string[]): number | null {\n if (route.outlet && route.outlet !== PRIMARY_OUTLET) return null;\n if (route.redirectTo !== undefined || route.matcher || route.path === undefined) return null;\n const parts = route.path ? route.path.split('/') : [];\n if (parts.includes('**') || parts.length > segments.length) return null;\n const matches = parts.every((part, index) => part.startsWith(':') || part === segments[index]);\n return matches ? parts.length : null;\n}\n\n/** The children each lazily loaded route answered with, or null when they are not plain routes. */\nconst lazyChildren = new WeakMap<Route, Promise<Routes | null>>();\n\n/**\n * A route's children, loading them when they are lazy. The router loads them again when it\n * navigates, from the same function, which a dynamic import answers from its cache.\n *\n * ponytail: a loader that answers routes, or a module whose default export is routes, as\n * `loadChildren: () => import('./invoices.routes')` does. An NgModule or an observable falls back\n * to presenting the page where its url puts it.\n */\nfunction childrenOf(route: Route): Promise<Routes | null> | Routes | undefined {\n if (route.children || !route.loadChildren) return route.children;\n let loading = lazyChildren.get(route);\n if (!loading) {\n loading = Promise.resolve()\n .then(() => (route.loadChildren as () => unknown)())\n .then((answer) => {\n const routes = (answer as { default?: unknown } | null)?.default ?? answer;\n return Array.isArray(routes) ? (routes as Routes) : null;\n })\n // A loader that fails is the router's to report, when it navigates there as before.\n .catch(() => null);\n lazyChildren.set(route, loading);\n }\n return loading;\n}\n\n/** A route on the way that the copy cannot stand in for: the search stops, with no copy made. */\nconst STOP = Symbol('stop');\n\n/** A route's children, or `STOP` where the copy cannot follow it: see `chainTo`. */\nasync function followable(route: Route): Promise<Routes | undefined | typeof STOP> {\n if (route.canMatch?.length) return STOP;\n return (await childrenOf(route)) ?? (route.loadChildren ? STOP : undefined);\n}\n\n/**\n * The routes from the root to the one that shows `segments`, null when none of `routes` leads\n * there, or `STOP` at a route with a `canMatch` guard. The router runs that guard against the\n * route and the segments it was matched with, which a copy under another path cannot give it,\n * and leaving it out would let the page match where its own route refuses to.\n */\nasync function chainTo(\n routes: Routes,\n segments: readonly string[],\n): Promise<Route[] | null | typeof STOP> {\n for (const route of routes) {\n const count = taken(route, segments);\n if (count === null) continue;\n const rest = segments.slice(count);\n const children = await followable(route);\n if (children === STOP) return STOP;\n const inside = children && (await chainTo(children, rest));\n if (inside === STOP) return STOP;\n if (inside) return [route, ...inside];\n // A page of its own: a component, and no children to choose among.\n if (!rest.length && !children && (route.component || route.loadComponent)) return [route];\n }\n return null;\n}\n\n/**\n * The page's route as a root route of the presented outlet: its own component, title, data and\n * resolvers, under the whole path, with the guards and providers of the routes it sat inside.\n * Their components are left out: the tab bar and the tab's stack are not what is presented.\n */\nfunction presentedCopy(chain: readonly Route[], root: EnvironmentInjector | undefined): Route {\n const page = chain.at(-1)!;\n const above = chain.slice(0, -1);\n const scopeOf = root ? scopes(above, root) : undefined;\n // An ancestor's guard is run where it was: the copy has the providers of every route, and a\n // page's override of one that guard reads would otherwise decide it.\n const guarded = (route: Route, level: number, kind: 'canActivate' | 'canActivateChild') =>\n (route[kind] ?? []).map((guard: unknown) =>\n root && chain.slice(level + 1).some((below) => below.providers?.length)\n ? scoped(guard, kind, () => scopeOf!(level))\n : guard,\n ) as NonNullable<Route['canActivate']>;\n return {\n ...page,\n // Its own children are in the copy by now, where they were lazy.\n loadChildren: undefined,\n path: chain\n .map((route) => route.path)\n .filter(Boolean)\n .join('/'),\n pathMatch: undefined,\n outlet: PRESENTED,\n canActivate: [\n ...above.flatMap((route, level) => [\n ...guarded(route, level, 'canActivate'),\n ...guarded(route, level, 'canActivateChild'),\n ]),\n ...(page.canActivate ?? []),\n ],\n providers: [...above.flatMap((route) => route.providers ?? []), ...(page.providers ?? [])],\n resolve: Object.assign({}, ...above.map((route) => route.resolve), page.resolve),\n data: Object.assign({}, ...above.map((route) => route.data), page.data),\n };\n}\n\n/**\n * The injector each route above the page made, made when one of their guards first asks: its own\n * providers over those above it, the first over `root`.\n * ponytail: `root` stands for what a root route's injector is under; an ancestor inside a lazily\n * loaded NgModule leaves that module's providers out.\n */\nfunction scopes(\n above: readonly Route[],\n root: EnvironmentInjector,\n): (level: number) => EnvironmentInjector {\n const made: EnvironmentInjector[] = [];\n const scopeOf = (level: number): EnvironmentInjector => {\n if (level < 0) return root;\n const providers = above[level]!.providers;\n return (made[level] ??= providers?.length\n ? createEnvironmentInjector(providers, scopeOf(level - 1))\n : scopeOf(level - 1));\n };\n return scopeOf;\n}\n\nconst NOT_FOUND = {};\n\n/**\n * A guard run in `scope` as Angular runs one: a class or token as what `scope` gives for it, a\n * function in its injection context.\n */\nfunction scoped(guard: unknown, kind: string, scope: () => EnvironmentInjector): unknown {\n return (...args: unknown[]) => {\n const injector = scope();\n const found = injector.get(guard as never, NOT_FOUND as never) as unknown;\n const value = (found === NOT_FOUND ? guard : found) as Record<string, unknown>;\n const method = value[kind];\n return typeof method === 'function'\n ? (method as (...a: unknown[]) => unknown).apply(value, args)\n : runInInjectionContext(injector, () =>\n (value as unknown as (...a: unknown[]) => unknown)(...args),\n );\n };\n}\n\n/**\n * The commands that present the page at `path` in the root's presented outlet, having given its\n * route a copy there, or null when the config is not one this follows.\n */\nexport async function presentedCommands(\n router: Router,\n path: string,\n root?: EnvironmentInjector,\n): Promise<unknown[] | null> {\n // Parsed, so the routes are matched against decoded segments and the escapes are written once.\n const parsed = primarySegments(router, path);\n const segments = parsed.map((segment) => segment.path);\n const config = router.config;\n const chain = await chainTo(config, segments);\n // Routes reset while lazy children loaded: the copy is made from the routes the router has.\n if (router.config !== config) return presentedCommands(router, path, root);\n if (!chain || chain === STOP) return null;\n const copy = presentedCopy(chain, root);\n const copied = router.config.some(\n (route) => route.outlet === PRESENTED && route.path === copy.path,\n );\n if (!copied) router.config.push(copy);\n return [{ outlets: { [PRESENTED]: parsed.flatMap(segmentCommands) } }];\n}\n\n/** `url` without the page presented over it: where the app is, under the page. */\nexport function withoutPresented(router: Router, url: string): string {\n // A named outlet is written `(name:path)`, so a url without that has no page to take off.\n if (!url.includes(`${PRESENTED}:`)) return url;\n const tree = router.parseUrl(url);\n delete tree.root.children[PRESENTED];\n return router.serializeUrl(tree);\n}\n\n/**\n * Where `commands` lead with the presented page left behind, when one is up and the commands are\n * not a presentation themselves; null otherwise. A navigation from a presented page goes to its\n * url's own place, which the page is over: left up, it would hide where the app went.\n */\nexport function leavingPresented(\n router: Router,\n commands: readonly unknown[],\n extras: NavigationExtras,\n): UrlTree | null {\n // A named outlet is written `(name:path)`, so a url without that has no page up.\n if (!router.url?.includes(`${PRESENTED}:`)) return null;\n const first = commands[0] as { outlets?: Record<string, unknown> } | undefined;\n if (first?.outlets && PRESENTED in first.outlets) return null;\n const tree = router.createUrlTree([...commands], extras);\n // Commands relative to the page itself, as a link inside it gives them, resolve inside the\n // presented outlet: where they lead is that path in its own place, not beside the page.\n const start = commands[0];\n const absolute = typeof start === 'string' && start.startsWith('/');\n const beside =\n !absolute && extras.relativeTo?.pathFromRoot.some((route) => route.outlet === PRESENTED)\n ? tree.root.children[PRESENTED]\n : undefined;\n if (beside) {\n const path = beside.segments.map((segment) => segment.path);\n const { queryParams, fragment } = tree;\n const own = router.createUrlTree(['/', ...path], {\n queryParams,\n fragment: fragment ?? undefined,\n });\n delete own.root.children[PRESENTED];\n return own;\n }\n delete tree.root.children[PRESENTED];\n return tree;\n}\n"]}
|
|
@@ -22,6 +22,7 @@ import { restoreFailedSnapshots } from "./native-back.js";
|
|
|
22
22
|
import { followLink, linkAncestry } from "./native-links.js";
|
|
23
23
|
import { NATIVE_INTENT, NativeNavigation, carriesOn, carryIntentAcrossRedirects, intentOf, } from "./native-navigation.js";
|
|
24
24
|
import { NativePlatformLocation } from "./native-platform-location.js";
|
|
25
|
+
import { refuseScreensUnderFullScreen } from "./refuse-screens-under-full-screen.js";
|
|
25
26
|
import { SVG_ICON_RENDERER } from "./svg-icons.js";
|
|
26
27
|
import { NativeStackReuseStrategy } from "./native-stack-reuse-strategy.js";
|
|
27
28
|
import { ROUTE_PARKING } from "./route-parking.js";
|
|
@@ -107,6 +108,7 @@ function nativeProviders(parentOf) {
|
|
|
107
108
|
provideEnvironmentInitializer(carryIntentAcrossRedirects),
|
|
108
109
|
provideEnvironmentInitializer(discardFailedEntries),
|
|
109
110
|
provideEnvironmentInitializer(restoreFailedSnapshots),
|
|
111
|
+
provideEnvironmentInitializer(refuseScreensUnderFullScreen),
|
|
110
112
|
provideEnvironmentInitializer(keepHistoryAcrossReloads),
|
|
111
113
|
];
|
|
112
114
|
if (!parentOf) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provide-native-router.js","sourceRoot":"","sources":["../src/provide-native-router.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Angular's Router, on native navigation: `provideRouter` and the native pieces under it, in one\n * call.\n *\n * `provideNativeRouter(routes, withComponentInputBinding())` takes the same routes and the same\n * router features as `provideRouter` - it calls it - and adds what native needs on top: a\n * `PlatformLocation` over an in-memory history, a `RouteReuseStrategy` that detaches a pushed-away\n * screen instead of destroying it, and `NativeNavigation`. Those come after `provideRouter`'s own\n * providers, so they win over the web defaults without the app having to order anything.\n *\n * Deep links and Android's back button come from `@ng-native/device` and need no wiring: off a\n * device both report nothing, and navigation works either way. The native options - `withLinkParent`,\n * `withHeaderDefaults` and `withTabDefaults` - are passed like any other feature.\n */\nimport { PlatformLocation } from '@angular/common';\nimport {\n NavigationCancel,\n NavigationEnd,\n NavigationError,\n NavigationSkipped,\n RouteReuseStrategy,\n Router,\n provideRouter,\n type RouterFeatures,\n type Routes,\n} from '@angular/router';\nimport {\n DestroyRef,\n ErrorHandler,\n computed,\n inject,\n makeEnvironmentProviders,\n provideEnvironmentInitializer,\n type EnvironmentProviders,\n type InjectionToken,\n type Provider,\n type Signal,\n type Type,\n} from '@angular/core';\nimport { ColorScheme, DeepLinks, NATIVE_HISTORY, type Scheme } from '@ng-native/device';\nimport {\n NATIVE_HEADER_DEFAULTS,\n NATIVE_TAB_DEFAULTS,\n type HeaderDefaults,\n type SchemeDefaults,\n type TabDefaults,\n} from './native-bar-defaults.ts';\nimport { discardFailedEntries } from './discard-failed-entries.ts';\nimport { restoreFailedSnapshots } from './native-back.ts';\nimport { followLink, linkAncestry, type LinkParent } from './native-links.ts';\nimport {\n NATIVE_INTENT,\n NativeNavigation,\n carriesOn,\n carryIntentAcrossRedirects,\n intentOf,\n} from './native-navigation.ts';\nimport { NativePlatformLocation } from './native-platform-location.ts';\nimport { SVG_ICON_RENDERER, type SvgIconRenderer } from './svg-icons.ts';\nimport { NativeStackReuseStrategy } from './native-stack-reuse-strategy.ts';\nimport { ROUTE_PARKING, type ParkedPage } from './route-parking.ts';\nimport { registerScreenComponents } from './screens.ts';\n\n/** A native-only router option, passed to `provideNativeRouter` beside Angular's own features. */\nexport interface NativeRouterFeature {\n readonly ɵnativeRouter: { readonly linkParent?: LinkParent; readonly providers?: Provider[] };\n}\n\n/**\n * The page a deep link opens on top of, or null to open it alone. Without it a link to\n * `/settings/notifications` opens that page with no Back. See native-links.ts.\n */\nexport function withLinkParent(parentOf: LinkParent): NativeRouterFeature {\n return { ɵnativeRouter: { linkParent: parentOf } };\n}\n\n/**\n * How every `<native-header>` looks when it does not say: its colours, blur, shadow, fonts and\n * light or dark style. A header's own binding always wins.\n *\n * ```ts\n * provideNativeRouter(\n * routes,\n * withHeaderDefaults((scheme) => ({\n * backgroundColor: scheme === 'dark' ? '#101014' : '#f4f4f7',\n * titleColor: scheme === 'dark' ? '#ffffff' : '#101014',\n * color: '#3b6ef5',\n * })),\n * );\n * ```\n *\n * Colours it leaves out still come from `NATIVE_HEADER_PALETTE`.\n */\nexport function withHeaderDefaults(defaults: SchemeDefaults<HeaderDefaults>): NativeRouterFeature {\n return { ɵnativeRouter: { providers: [bySchemeProvider(NATIVE_HEADER_DEFAULTS, defaults)] } };\n}\n\n/**\n * How every `<native-tabs-outlet>` and `<native-tab>` looks when it does not say: the tint, the\n * background behind the tabs, the light or dark style, and each tab's bar appearance. An outlet's\n * or a tab's own binding always wins.\n */\nexport function withTabDefaults(defaults: SchemeDefaults<TabDefaults>): NativeRouterFeature {\n return { ɵnativeRouter: { providers: [bySchemeProvider(NATIVE_TAB_DEFAULTS, defaults)] } };\n}\n\n/**\n * What draws a `<native-tab>` icon written as SVG markup, `[icon]=\"{ svg }\"`, which neither\n * platform's tab bar can draw itself. `SvgImages` from `@ng-native/icons` is one:\n *\n * ```ts\n * provideNativeRouter(routes, withSvgIcons(SvgImages));\n * ```\n */\nexport function withSvgIcons(renderer: Type<SvgIconRenderer>): NativeRouterFeature {\n return { ɵnativeRouter: { providers: [{ provide: SVG_ICON_RENDERER, useClass: renderer }] } };\n}\n\n/** One signal for the whole app, rather than every bar calling the function again. */\nfunction bySchemeProvider<T>(\n token: InjectionToken<Signal<T>>,\n defaults: SchemeDefaults<T>,\n): Provider {\n return {\n provide: token,\n useFactory: () => {\n if (typeof defaults !== 'function') return computed(() => defaults);\n const scheme = inject(ColorScheme);\n return computed(() => (defaults as (scheme: Scheme) => T)(scheme.current()));\n },\n };\n}\n\nfunction isNative(feature: RouterFeatures | NativeRouterFeature): feature is NativeRouterFeature {\n return 'ɵnativeRouter' in feature;\n}\n\nexport function provideNativeRouter(\n routes: Routes,\n ...features: (RouterFeatures | NativeRouterFeature)[]\n): EnvironmentProviders {\n const angular = features.filter((feature): feature is RouterFeatures => !isNative(feature));\n const native = features.filter(isNative).map((feature) => feature.ɵnativeRouter);\n const parentOf = native.find((feature) => feature.linkParent)?.linkParent;\n return makeEnvironmentProviders([\n provideRouter(routes, ...angular),\n ...nativeProviders(parentOf),\n ...native.flatMap((feature) => feature.providers ?? []),\n ]);\n}\n\nfunction nativeProviders(parentOf: LinkParent | undefined): (Provider | EnvironmentProviders)[] {\n // The engine needs the element-to-view-name mapping before the first navigation renders.\n registerScreenComponents();\n\n const shared = [\n // Without this the router never detaches, so a pushed-away screen is destroyed and rebuilt.\n { provide: RouteReuseStrategy, useClass: NativeStackReuseStrategy },\n NativeNavigation,\n provideEnvironmentInitializer(carryIntentAcrossRedirects),\n provideEnvironmentInitializer(discardFailedEntries),\n provideEnvironmentInitializer(restoreFailedSnapshots),\n provideEnvironmentInitializer(keepHistoryAcrossReloads),\n ];\n if (!parentOf) {\n return [\n // Kept under the token too, which web-compat's stand-in yields to: see `NATIVE_HISTORY`.\n { provide: PlatformLocation, useExisting: NATIVE_HISTORY },\n {\n provide: NATIVE_HISTORY,\n useFactory: () => {\n const links = inject(DeepLinks);\n return new NativePlatformLocation({\n initialUrl: () => links.initialUrl(),\n subscribe: () => () => {},\n });\n },\n },\n provideEnvironmentInitializer(() => {\n const navigation = inject(NativeNavigation);\n const errors = inject(ErrorHandler);\n inject(DeepLinks).subscribe((url) => {\n navigation.push(url).catch((error: unknown) => errors.handleError(error));\n });\n }),\n ...shared,\n ];\n }\n\n return [\n // Kept under the token too, which web-compat's stand-in yields to: see `NATIVE_HISTORY`.\n { provide: PlatformLocation, useExisting: NATIVE_HISTORY },\n {\n provide: NATIVE_HISTORY,\n // The app launches on the page the link belongs under; the link follows once it is shown.\n // Links while running go through the router below rather than straight into history.\n useFactory: () => {\n const initial = inject(DeepLinks).initialUrl();\n return new NativePlatformLocation({\n initialUrl: () => (initial && linkAncestry(initial, parentOf)[0]) || initial,\n subscribe: () => () => {},\n });\n },\n },\n provideEnvironmentInitializer(() => {\n const router = inject(Router);\n const links = inject(DeepLinks);\n const errors = inject(ErrorHandler);\n // A link nobody awaits: a page that fails to load is reported, as a tab tap's is, rather\n // than left as an unhandled rejection. The app's navigation error handler hears it too.\n const follow = (url: string) =>\n followLink(router, url, parentOf).catch((error: unknown) => errors.handleError(error));\n const initial = links.initialUrl();\n if (initial && parentOf(initial)) {\n // Followed over the first page to show, or not at all: one that failed to load leaves\n // the link nothing to go over, and the next page to show is not the one it waited for.\n const first = router.events.subscribe((event) => {\n if (!isEnd(event) || carriesOn(event)) return;\n first.unsubscribe();\n if (event instanceof NavigationEnd) void follow(initial);\n });\n }\n // A launch link arrives the way any other does, once `getInitialURL()` settles, which is\n // usually while the router's first navigation is still going: following it then cancels that\n // navigation, and the app opens with no root screen under the link. So links wait for it.\n const settled = new Promise<void>((resolve) => {\n if (router.navigated) return resolve();\n const first = router.events.subscribe((event) => {\n if (!isEnd(event) || carriesOn(event)) return;\n first.unsubscribe();\n resolve();\n });\n });\n links.subscribe((url) => void settled.then(() => follow(url)));\n }),\n ...shared,\n ];\n}\n\n/**\n * A history without its round trips: each page once, reached the way it last was. An app that went\n * from one tab to another and back has a history three entries long and is one page deep, and the\n * app that comes back has no use for the detour: gone through at the speed of a reload, the tab\n * bar is still on its way to the second tab when the third navigation asks for the first.\n */\nfunction direct(pages: ParkedPage[]): ParkedPage[] {\n const route: ParkedPage[] = [];\n for (const page of pages) {\n const before = route.findIndex((one) => one.url === page.url);\n if (before !== -1) route.length = before;\n route.push(page);\n }\n return route;\n}\n\ndeclare const __DEV__: boolean | undefined;\n\n/** A push's animation, with room to spare: 350ms on iOS, about the same on Android. */\nconst PUSH_SETTLES = 450;\n\n/**\n * In development, come back from a reload on the page it left: see `route-parking.ts`.\n *\n * The history a reload left is gone through again once the first navigation has ended, as a\n * launch link is and for the same reason. The hook is what `mount`'s reload waits on.\n */\nfunction keepHistoryAcrossReloads(): void {\n // The bare identifier, so a release build folds the rest away.\n if (typeof __DEV__ === 'undefined' || !__DEV__) return;\n const parking = inject(ROUTE_PARKING);\n if (!parking) return;\n const router = inject(Router);\n const history = inject(PlatformLocation);\n const errors = inject(ErrorHandler);\n const scope = globalThis as {\n __angularNativePark?: () => Promise<void>;\n __angularNativeRestoring?: Promise<void>;\n };\n // A page keeps how it was presented, a sheet or a modal, and nothing else of its navigation:\n // a replace has already happened to the history, and an app's own state may not survive JSON.\n const pages = (): ParkedPage[] =>\n history instanceof NativePlatformLocation\n ? history.ɵpages().map(({ url, state }) => {\n const presentation = intentOf(state)?.presentation;\n return presentation ? { url, presentation } : { url };\n })\n : [{ url: router.url }];\n const park = () => parking.park(direct(pages()));\n scope.__angularNativePark = park;\n\n // `mount` keeps the app out of sight until this settles, so the pages arrive unseen.\n const restoring = parking\n .collect()\n .then(async (parked) => {\n if (!parked) return;\n await new Promise<void>((resolve) => {\n if (router.navigated) return resolve();\n const first = router.events.subscribe((event) => {\n if (!isEnd(event) || carriesOn(event)) return;\n first.unsubscribe();\n resolve();\n });\n });\n let moved = false;\n for (const { url, presentation } of parked) {\n if (url === router.url) continue;\n const state = presentation && { [NATIVE_INTENT]: { stack: 'push', presentation } };\n moved = (await router.navigateByUrl(url, { state })) || moved;\n }\n // The last page is still sliding in when its navigation ends.\n if (moved) await new Promise((resolve) => setTimeout(resolve, PUSH_SETTLES));\n })\n .catch((error: unknown) => errors.handleError(error));\n scope.__angularNativeRestoring = restoring;\n inject(DestroyRef).onDestroy(() => {\n if (scope.__angularNativePark === park) delete scope.__angularNativePark;\n if (scope.__angularNativeRestoring === restoring) delete scope.__angularNativeRestoring;\n });\n}\n\n/** A navigation's last event, whichever way it went. */\nfunction isEnd(event: unknown): boolean {\n return (\n event instanceof NavigationEnd ||\n event instanceof NavigationCancel ||\n event instanceof NavigationError ||\n // A url the app's `UrlHandlingStrategy` leaves to something else: it ends with no page.\n event instanceof NavigationSkipped\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"provide-native-router.js","sourceRoot":"","sources":["../src/provide-native-router.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Angular's Router, on native navigation: `provideRouter` and the native pieces under it, in one\n * call.\n *\n * `provideNativeRouter(routes, withComponentInputBinding())` takes the same routes and the same\n * router features as `provideRouter` - it calls it - and adds what native needs on top: a\n * `PlatformLocation` over an in-memory history, a `RouteReuseStrategy` that detaches a pushed-away\n * screen instead of destroying it, and `NativeNavigation`. Those come after `provideRouter`'s own\n * providers, so they win over the web defaults without the app having to order anything.\n *\n * Deep links and Android's back button come from `@ng-native/device` and need no wiring: off a\n * device both report nothing, and navigation works either way. The native options - `withLinkParent`,\n * `withHeaderDefaults` and `withTabDefaults` - are passed like any other feature.\n */\nimport { PlatformLocation } from '@angular/common';\nimport {\n NavigationCancel,\n NavigationEnd,\n NavigationError,\n NavigationSkipped,\n RouteReuseStrategy,\n Router,\n provideRouter,\n type RouterFeatures,\n type Routes,\n} from '@angular/router';\nimport {\n DestroyRef,\n ErrorHandler,\n computed,\n inject,\n makeEnvironmentProviders,\n provideEnvironmentInitializer,\n type EnvironmentProviders,\n type InjectionToken,\n type Provider,\n type Signal,\n type Type,\n} from '@angular/core';\nimport { ColorScheme, DeepLinks, NATIVE_HISTORY, type Scheme } from '@ng-native/device';\nimport {\n NATIVE_HEADER_DEFAULTS,\n NATIVE_TAB_DEFAULTS,\n type HeaderDefaults,\n type SchemeDefaults,\n type TabDefaults,\n} from './native-bar-defaults.ts';\nimport { discardFailedEntries } from './discard-failed-entries.ts';\nimport { restoreFailedSnapshots } from './native-back.ts';\nimport { followLink, linkAncestry, type LinkParent } from './native-links.ts';\nimport {\n NATIVE_INTENT,\n NativeNavigation,\n carriesOn,\n carryIntentAcrossRedirects,\n intentOf,\n} from './native-navigation.ts';\nimport { NativePlatformLocation } from './native-platform-location.ts';\nimport { refuseScreensUnderFullScreen } from './refuse-screens-under-full-screen.ts';\nimport { SVG_ICON_RENDERER, type SvgIconRenderer } from './svg-icons.ts';\nimport { NativeStackReuseStrategy } from './native-stack-reuse-strategy.ts';\nimport { ROUTE_PARKING, type ParkedPage } from './route-parking.ts';\nimport { registerScreenComponents } from './screens.ts';\n\n/** A native-only router option, passed to `provideNativeRouter` beside Angular's own features. */\nexport interface NativeRouterFeature {\n readonly ɵnativeRouter: { readonly linkParent?: LinkParent; readonly providers?: Provider[] };\n}\n\n/**\n * The page a deep link opens on top of, or null to open it alone. Without it a link to\n * `/settings/notifications` opens that page with no Back. See native-links.ts.\n */\nexport function withLinkParent(parentOf: LinkParent): NativeRouterFeature {\n return { ɵnativeRouter: { linkParent: parentOf } };\n}\n\n/**\n * How every `<native-header>` looks when it does not say: its colours, blur, shadow, fonts and\n * light or dark style. A header's own binding always wins.\n *\n * ```ts\n * provideNativeRouter(\n * routes,\n * withHeaderDefaults((scheme) => ({\n * backgroundColor: scheme === 'dark' ? '#101014' : '#f4f4f7',\n * titleColor: scheme === 'dark' ? '#ffffff' : '#101014',\n * color: '#3b6ef5',\n * })),\n * );\n * ```\n *\n * Colours it leaves out still come from `NATIVE_HEADER_PALETTE`.\n */\nexport function withHeaderDefaults(defaults: SchemeDefaults<HeaderDefaults>): NativeRouterFeature {\n return { ɵnativeRouter: { providers: [bySchemeProvider(NATIVE_HEADER_DEFAULTS, defaults)] } };\n}\n\n/**\n * How every `<native-tabs-outlet>` and `<native-tab>` looks when it does not say: the tint, the\n * background behind the tabs, the light or dark style, and each tab's bar appearance. An outlet's\n * or a tab's own binding always wins.\n */\nexport function withTabDefaults(defaults: SchemeDefaults<TabDefaults>): NativeRouterFeature {\n return { ɵnativeRouter: { providers: [bySchemeProvider(NATIVE_TAB_DEFAULTS, defaults)] } };\n}\n\n/**\n * What draws a `<native-tab>` icon written as SVG markup, `[icon]=\"{ svg }\"`, which neither\n * platform's tab bar can draw itself. `SvgImages` from `@ng-native/icons` is one:\n *\n * ```ts\n * provideNativeRouter(routes, withSvgIcons(SvgImages));\n * ```\n */\nexport function withSvgIcons(renderer: Type<SvgIconRenderer>): NativeRouterFeature {\n return { ɵnativeRouter: { providers: [{ provide: SVG_ICON_RENDERER, useClass: renderer }] } };\n}\n\n/** One signal for the whole app, rather than every bar calling the function again. */\nfunction bySchemeProvider<T>(\n token: InjectionToken<Signal<T>>,\n defaults: SchemeDefaults<T>,\n): Provider {\n return {\n provide: token,\n useFactory: () => {\n if (typeof defaults !== 'function') return computed(() => defaults);\n const scheme = inject(ColorScheme);\n return computed(() => (defaults as (scheme: Scheme) => T)(scheme.current()));\n },\n };\n}\n\nfunction isNative(feature: RouterFeatures | NativeRouterFeature): feature is NativeRouterFeature {\n return 'ɵnativeRouter' in feature;\n}\n\nexport function provideNativeRouter(\n routes: Routes,\n ...features: (RouterFeatures | NativeRouterFeature)[]\n): EnvironmentProviders {\n const angular = features.filter((feature): feature is RouterFeatures => !isNative(feature));\n const native = features.filter(isNative).map((feature) => feature.ɵnativeRouter);\n const parentOf = native.find((feature) => feature.linkParent)?.linkParent;\n return makeEnvironmentProviders([\n provideRouter(routes, ...angular),\n ...nativeProviders(parentOf),\n ...native.flatMap((feature) => feature.providers ?? []),\n ]);\n}\n\nfunction nativeProviders(parentOf: LinkParent | undefined): (Provider | EnvironmentProviders)[] {\n // The engine needs the element-to-view-name mapping before the first navigation renders.\n registerScreenComponents();\n\n const shared = [\n // Without this the router never detaches, so a pushed-away screen is destroyed and rebuilt.\n { provide: RouteReuseStrategy, useClass: NativeStackReuseStrategy },\n NativeNavigation,\n provideEnvironmentInitializer(carryIntentAcrossRedirects),\n provideEnvironmentInitializer(discardFailedEntries),\n provideEnvironmentInitializer(restoreFailedSnapshots),\n provideEnvironmentInitializer(refuseScreensUnderFullScreen),\n provideEnvironmentInitializer(keepHistoryAcrossReloads),\n ];\n if (!parentOf) {\n return [\n // Kept under the token too, which web-compat's stand-in yields to: see `NATIVE_HISTORY`.\n { provide: PlatformLocation, useExisting: NATIVE_HISTORY },\n {\n provide: NATIVE_HISTORY,\n useFactory: () => {\n const links = inject(DeepLinks);\n return new NativePlatformLocation({\n initialUrl: () => links.initialUrl(),\n subscribe: () => () => {},\n });\n },\n },\n provideEnvironmentInitializer(() => {\n const navigation = inject(NativeNavigation);\n const errors = inject(ErrorHandler);\n inject(DeepLinks).subscribe((url) => {\n navigation.push(url).catch((error: unknown) => errors.handleError(error));\n });\n }),\n ...shared,\n ];\n }\n\n return [\n // Kept under the token too, which web-compat's stand-in yields to: see `NATIVE_HISTORY`.\n { provide: PlatformLocation, useExisting: NATIVE_HISTORY },\n {\n provide: NATIVE_HISTORY,\n // The app launches on the page the link belongs under; the link follows once it is shown.\n // Links while running go through the router below rather than straight into history.\n useFactory: () => {\n const initial = inject(DeepLinks).initialUrl();\n return new NativePlatformLocation({\n initialUrl: () => (initial && linkAncestry(initial, parentOf)[0]) || initial,\n subscribe: () => () => {},\n });\n },\n },\n provideEnvironmentInitializer(() => {\n const router = inject(Router);\n const links = inject(DeepLinks);\n const errors = inject(ErrorHandler);\n // A link nobody awaits: a page that fails to load is reported, as a tab tap's is, rather\n // than left as an unhandled rejection. The app's navigation error handler hears it too.\n const follow = (url: string) =>\n followLink(router, url, parentOf).catch((error: unknown) => errors.handleError(error));\n const initial = links.initialUrl();\n if (initial && parentOf(initial)) {\n // Followed over the first page to show, or not at all: one that failed to load leaves\n // the link nothing to go over, and the next page to show is not the one it waited for.\n const first = router.events.subscribe((event) => {\n if (!isEnd(event) || carriesOn(event)) return;\n first.unsubscribe();\n if (event instanceof NavigationEnd) void follow(initial);\n });\n }\n // A launch link arrives the way any other does, once `getInitialURL()` settles, which is\n // usually while the router's first navigation is still going: following it then cancels that\n // navigation, and the app opens with no root screen under the link. So links wait for it.\n const settled = new Promise<void>((resolve) => {\n if (router.navigated) return resolve();\n const first = router.events.subscribe((event) => {\n if (!isEnd(event) || carriesOn(event)) return;\n first.unsubscribe();\n resolve();\n });\n });\n links.subscribe((url) => void settled.then(() => follow(url)));\n }),\n ...shared,\n ];\n}\n\n/**\n * A history without its round trips: each page once, reached the way it last was. An app that went\n * from one tab to another and back has a history three entries long and is one page deep, and the\n * app that comes back has no use for the detour: gone through at the speed of a reload, the tab\n * bar is still on its way to the second tab when the third navigation asks for the first.\n */\nfunction direct(pages: ParkedPage[]): ParkedPage[] {\n const route: ParkedPage[] = [];\n for (const page of pages) {\n const before = route.findIndex((one) => one.url === page.url);\n if (before !== -1) route.length = before;\n route.push(page);\n }\n return route;\n}\n\ndeclare const __DEV__: boolean | undefined;\n\n/** A push's animation, with room to spare: 350ms on iOS, about the same on Android. */\nconst PUSH_SETTLES = 450;\n\n/**\n * In development, come back from a reload on the page it left: see `route-parking.ts`.\n *\n * The history a reload left is gone through again once the first navigation has ended, as a\n * launch link is and for the same reason. The hook is what `mount`'s reload waits on.\n */\nfunction keepHistoryAcrossReloads(): void {\n // The bare identifier, so a release build folds the rest away.\n if (typeof __DEV__ === 'undefined' || !__DEV__) return;\n const parking = inject(ROUTE_PARKING);\n if (!parking) return;\n const router = inject(Router);\n const history = inject(PlatformLocation);\n const errors = inject(ErrorHandler);\n const scope = globalThis as {\n __angularNativePark?: () => Promise<void>;\n __angularNativeRestoring?: Promise<void>;\n };\n // A page keeps how it was presented, a sheet or a modal, and nothing else of its navigation:\n // a replace has already happened to the history, and an app's own state may not survive JSON.\n const pages = (): ParkedPage[] =>\n history instanceof NativePlatformLocation\n ? history.ɵpages().map(({ url, state }) => {\n const presentation = intentOf(state)?.presentation;\n return presentation ? { url, presentation } : { url };\n })\n : [{ url: router.url }];\n const park = () => parking.park(direct(pages()));\n scope.__angularNativePark = park;\n\n // `mount` keeps the app out of sight until this settles, so the pages arrive unseen.\n const restoring = parking\n .collect()\n .then(async (parked) => {\n if (!parked) return;\n await new Promise<void>((resolve) => {\n if (router.navigated) return resolve();\n const first = router.events.subscribe((event) => {\n if (!isEnd(event) || carriesOn(event)) return;\n first.unsubscribe();\n resolve();\n });\n });\n let moved = false;\n for (const { url, presentation } of parked) {\n if (url === router.url) continue;\n const state = presentation && { [NATIVE_INTENT]: { stack: 'push', presentation } };\n moved = (await router.navigateByUrl(url, { state })) || moved;\n }\n // The last page is still sliding in when its navigation ends.\n if (moved) await new Promise((resolve) => setTimeout(resolve, PUSH_SETTLES));\n })\n .catch((error: unknown) => errors.handleError(error));\n scope.__angularNativeRestoring = restoring;\n inject(DestroyRef).onDestroy(() => {\n if (scope.__angularNativePark === park) delete scope.__angularNativePark;\n if (scope.__angularNativeRestoring === restoring) delete scope.__angularNativeRestoring;\n });\n}\n\n/** A navigation's last event, whichever way it went. */\nfunction isEnd(event: unknown): boolean {\n return (\n event instanceof NavigationEnd ||\n event instanceof NavigationCancel ||\n event instanceof NavigationError ||\n // A url the app's `UrlHandlingStrategy` leaves to something else: it ends with no page.\n event instanceof NavigationSkipped\n );\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Refuse a navigation that would put a screen on iOS where it cannot show: on a stack further out
|
|
3
|
+
* than one presenting a screen `fullScreenModal`.
|
|
4
|
+
*
|
|
5
|
+
* A full-screen modal takes everything under it out of the window, and react-native-screens' iOS
|
|
6
|
+
* stack makes no change while it is out of the window: it waits to be back in it. So a screen
|
|
7
|
+
* pushed or presented on the app's own stack, from a modal a tab's stack presented, never appears,
|
|
8
|
+
* though the url says it is there, and the next back takes off the screen nobody saw. The
|
|
9
|
+
* navigation is aborted once its routes are known, before the url changes, and resolves false.
|
|
10
|
+
*
|
|
11
|
+
* Only iOS refuses: Android's stack puts a nested stack's modal inside the screen holding it, so a
|
|
12
|
+
* screen pushed over that one covers both. A replace or a reset takes the screen holding the modal
|
|
13
|
+
* off the stack, and the modal with it.
|
|
14
|
+
*/
|
|
15
|
+
export declare function refuseScreensUnderFullScreen(): void;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { DestroyRef, inject } from '@angular/core';
|
|
2
|
+
import { PRIMARY_OUTLET, ResolveEnd, Router, } from '@angular/router';
|
|
3
|
+
import { OS } from '@ng-native/device';
|
|
4
|
+
import { NativeBack } from "./native-back.js";
|
|
5
|
+
import { navigationIntent } from "./native-navigation.js";
|
|
6
|
+
import { sameScreen } from "./native-stack-reuse-strategy.js";
|
|
7
|
+
import { PRESENTED } from "./presented-route.js";
|
|
8
|
+
/**
|
|
9
|
+
* Refuse a navigation that would put a screen on iOS where it cannot show: on a stack further out
|
|
10
|
+
* than one presenting a screen `fullScreenModal`.
|
|
11
|
+
*
|
|
12
|
+
* A full-screen modal takes everything under it out of the window, and react-native-screens' iOS
|
|
13
|
+
* stack makes no change while it is out of the window: it waits to be back in it. So a screen
|
|
14
|
+
* pushed or presented on the app's own stack, from a modal a tab's stack presented, never appears,
|
|
15
|
+
* though the url says it is there, and the next back takes off the screen nobody saw. The
|
|
16
|
+
* navigation is aborted once its routes are known, before the url changes, and resolves false.
|
|
17
|
+
*
|
|
18
|
+
* Only iOS refuses: Android's stack puts a nested stack's modal inside the screen holding it, so a
|
|
19
|
+
* screen pushed over that one covers both. A replace or a reset takes the screen holding the modal
|
|
20
|
+
* off the stack, and the modal with it.
|
|
21
|
+
*/
|
|
22
|
+
export function refuseScreensUnderFullScreen() {
|
|
23
|
+
if (inject(OS) !== 'ios')
|
|
24
|
+
return;
|
|
25
|
+
const router = inject(Router);
|
|
26
|
+
const back = inject(NativeBack);
|
|
27
|
+
const events = router.events.subscribe((event) => {
|
|
28
|
+
if (event instanceof ResolveEnd && hidden(router, back, event)) {
|
|
29
|
+
router.currentNavigation()?.abort();
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
inject(DestroyRef).onDestroy(() => events.unsubscribe());
|
|
33
|
+
}
|
|
34
|
+
/** Whether the navigation `event` reports puts a screen over one holding a full-screen modal. */
|
|
35
|
+
function hidden(router, back, event) {
|
|
36
|
+
const modals = back.fullScreens();
|
|
37
|
+
if (!modals.length)
|
|
38
|
+
return false;
|
|
39
|
+
const navigation = router.currentNavigation();
|
|
40
|
+
if (!navigation)
|
|
41
|
+
return false;
|
|
42
|
+
const stack = navigationIntent(router, navigation)?.stack;
|
|
43
|
+
if (stack === 'replace' || stack === 'reset')
|
|
44
|
+
return false;
|
|
45
|
+
// A navigation that is not a push goes back to a screen still on the stack where there is one.
|
|
46
|
+
const pushing = navigation.trigger !== 'popstate' && stack === 'push';
|
|
47
|
+
return arrivals(router.routerState.root, event.state.root).some(({ covered, arriving }) => back.onTopOfStack(covered) &&
|
|
48
|
+
(pushing || !router.routeReuseStrategy.retrieve(arriving)) &&
|
|
49
|
+
modals.some((modal) => modal !== covered && modal.pathFromRoot.includes(covered)));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Where the navigation to `target` changes what `current` shows: each screen it replaces in an
|
|
53
|
+
* outlet, with the route arriving there. A page presented over everything covers the screen the
|
|
54
|
+
* app's own stack shows.
|
|
55
|
+
*/
|
|
56
|
+
function arrivals(current, target) {
|
|
57
|
+
return target.children.flatMap((next) => {
|
|
58
|
+
const now = current.children.find((child) => child.outlet === next.outlet);
|
|
59
|
+
if (now && sameScreen(next, now.snapshot))
|
|
60
|
+
return arrivals(now, next);
|
|
61
|
+
const covered = now ??
|
|
62
|
+
(next.outlet === PRESENTED
|
|
63
|
+
? current.children.find((child) => child.outlet === PRIMARY_OUTLET)
|
|
64
|
+
: undefined);
|
|
65
|
+
return covered ? [{ covered: screenOf(covered), arriving: screenOf(next) }] : [];
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The route with a component at or under `route`: a route with none, a group or a `loadChildren`
|
|
70
|
+
* wrapper, has the router put its child in its parent's outlet. A lazy component is not loaded
|
|
71
|
+
* yet when the navigation's routes are known, so the config says.
|
|
72
|
+
*/
|
|
73
|
+
function screenOf(route) {
|
|
74
|
+
let found = route;
|
|
75
|
+
while (!(found.component ?? found.routeConfig?.loadComponent) && found.firstChild) {
|
|
76
|
+
found = found.firstChild;
|
|
77
|
+
}
|
|
78
|
+
return found;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=refuse-screens-under-full-screen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refuse-screens-under-full-screen.js","sourceRoot":"","sources":["../src/refuse-screens-under-full-screen.ts"],"names":[],"mappings":"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","sourcesContent":["import { DestroyRef, inject } from '@angular/core';\nimport {\n PRIMARY_OUTLET,\n ResolveEnd,\n Router,\n type ActivatedRoute,\n type ActivatedRouteSnapshot,\n} from '@angular/router';\nimport { OS } from '@ng-native/device';\nimport { NativeBack } from './native-back.ts';\nimport { navigationIntent } from './native-navigation.ts';\nimport { sameScreen } from './native-stack-reuse-strategy.ts';\nimport { PRESENTED } from './presented-route.ts';\n\n/**\n * Refuse a navigation that would put a screen on iOS where it cannot show: on a stack further out\n * than one presenting a screen `fullScreenModal`.\n *\n * A full-screen modal takes everything under it out of the window, and react-native-screens' iOS\n * stack makes no change while it is out of the window: it waits to be back in it. So a screen\n * pushed or presented on the app's own stack, from a modal a tab's stack presented, never appears,\n * though the url says it is there, and the next back takes off the screen nobody saw. The\n * navigation is aborted once its routes are known, before the url changes, and resolves false.\n *\n * Only iOS refuses: Android's stack puts a nested stack's modal inside the screen holding it, so a\n * screen pushed over that one covers both. A replace or a reset takes the screen holding the modal\n * off the stack, and the modal with it.\n */\nexport function refuseScreensUnderFullScreen(): void {\n if (inject(OS) !== 'ios') return;\n const router = inject(Router);\n const back = inject(NativeBack);\n const events = router.events.subscribe((event) => {\n if (event instanceof ResolveEnd && hidden(router, back, event)) {\n router.currentNavigation()?.abort();\n }\n });\n inject(DestroyRef).onDestroy(() => events.unsubscribe());\n}\n\n/** Whether the navigation `event` reports puts a screen over one holding a full-screen modal. */\nfunction hidden(router: Router, back: NativeBack, event: ResolveEnd): boolean {\n const modals = back.fullScreens();\n if (!modals.length) return false;\n const navigation = router.currentNavigation();\n if (!navigation) return false;\n const stack = navigationIntent(router, navigation)?.stack;\n if (stack === 'replace' || stack === 'reset') return false;\n // A navigation that is not a push goes back to a screen still on the stack where there is one.\n const pushing = navigation.trigger !== 'popstate' && stack === 'push';\n return arrivals(router.routerState.root, event.state.root).some(\n ({ covered, arriving }) =>\n back.onTopOfStack(covered) &&\n (pushing || !router.routeReuseStrategy.retrieve(arriving)) &&\n modals.some((modal) => modal !== covered && modal.pathFromRoot.includes(covered)),\n );\n}\n\n/**\n * Where the navigation to `target` changes what `current` shows: each screen it replaces in an\n * outlet, with the route arriving there. A page presented over everything covers the screen the\n * app's own stack shows.\n */\nfunction arrivals(\n current: ActivatedRoute,\n target: ActivatedRouteSnapshot,\n): { covered: ActivatedRoute; arriving: ActivatedRouteSnapshot }[] {\n return target.children.flatMap((next) => {\n const now = current.children.find((child) => child.outlet === next.outlet);\n if (now && sameScreen(next, now.snapshot)) return arrivals(now, next);\n const covered =\n now ??\n (next.outlet === PRESENTED\n ? current.children.find((child) => child.outlet === PRIMARY_OUTLET)\n : undefined);\n return covered ? [{ covered: screenOf(covered), arriving: screenOf(next) }] : [];\n });\n}\n\n/**\n * The route with a component at or under `route`: a route with none, a group or a `loadChildren`\n * wrapper, has the router put its child in its parent's outlet. A lazy component is not loaded\n * yet when the navigation's routes are known, so the config says.\n */\nfunction screenOf<T extends ActivatedRoute | ActivatedRouteSnapshot>(route: T): T {\n let found: T = route;\n while (!(found.component ?? found.routeConfig?.loadComponent) && found.firstChild) {\n found = found.firstChild as T;\n }\n return found;\n}\n"]}
|
package/dist/screens.js
CHANGED
|
@@ -40,12 +40,11 @@ export const SCREEN_VIEW_NAMES = {
|
|
|
40
40
|
'RNSScreenStackHeaderSubview',
|
|
41
41
|
{ flexDirection: 'row', alignItems: 'center', justifyContent: 'center' },
|
|
42
42
|
],
|
|
43
|
-
// What a stack page's content commits in on iOS 26 and later, where the screen runs under the
|
|
44
|
-
// navigation bar: see `insetContent` in `native-stack-outlet.ts`. The fill is `SafeAreaView.tsx`'s.
|
|
45
|
-
'screen-content': ['RNSSafeAreaView', { flex: 1 }],
|
|
46
43
|
// Insets by what the screen it is in says is covered: a translucent navigation bar, and the tab
|
|
47
|
-
// bar. See `screen-safe-area-view.ts`. The same name on both platforms.
|
|
48
|
-
|
|
44
|
+
// bar. See `screen-safe-area-view.ts`. The same name on both platforms. The fill is
|
|
45
|
+
// react-native-screens' `SafeAreaView.tsx`'s, and defaults are a native view's, so the tab one
|
|
46
|
+
// below takes it too.
|
|
47
|
+
'screen-safe-area-view': ['RNSSafeAreaView', { flex: 1 }],
|
|
49
48
|
'tab-safe-area-view': ['RNSSafeAreaView'],
|
|
50
49
|
};
|
|
51
50
|
/**
|
package/dist/screens.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screens.js","sourceRoot":"","sources":["../src/screens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAEpE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA0D;IACtF,qDAAqD;IACrD,qBAAqB,EAAE,CAAC,gBAAgB,CAAC;IACzC,oFAAoF;IACpF,MAAM,EAAE,CAAC,WAAW,CAAC;IACrB,eAAe,EAAE;QACf,4BAA4B;QAC5B;YACE,QAAQ,EAAE,UAAU;YACpB,KAAK,EAAE,MAAM;YACb,aAAa,EAAE,KAAK;YACpB,cAAc,EAAE,eAAe;YAC/B,UAAU,EAAE,QAAQ;SACrB;KACF;IACD,+FAA+F;IAC/F,mBAAmB,EAAE,CAAC,cAAc,CAAC;IACrC,oBAAoB,EAAE;QACpB,6BAA6B;QAC7B,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE;KACzE;IACD,8FAA8F;IAC9F,oGAAoG;IACpG,gBAAgB,EAAE,CAAC,iBAAiB,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAClD,gGAAgG;IAChG,wEAAwE;IACxE,uBAAuB,EAAE,CAAC,iBAAiB,CAAC;IAC5C,oBAAoB,EAAE,CAAC,iBAAiB,CAAC;CAC1C,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,cAAc,GAAsE;IACxF,oBAAoB,EAAE;QACpB,gBAAgB;QAChB,oBAAoB;QACpB,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;KAC3C;IACD,YAAY,EAAE;QACZ,kBAAkB;QAClB,sBAAsB;QACtB,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;KACjE;CACF,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,gDAAgD;IAChD,QAAQ,EAAE,CAAC;IACX,oDAAoD;IACpD,aAAa,EAAE,CAAC;IAChB,iCAAiC;IACjC,MAAM,EAAE,CAAC;CACD,CAAC;AAIX;;;;;;;GAOG;AACH,SAAS,qBAAqB,CAAC,IAAY;IACzC,MAAM,UAAU,GAAI,UAA8D,CAAC,IAAI;QACrF,EAAE,uBAAuB,CAAC;IAC5B,OAAO,8CAA8C,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACnG,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,iBAAiB;IACxB,MAAM,IAAI,GAAG,UAGZ,CAAC;IACF,KAAK,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;AACzF,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,wBAAwB;IACtC,iBAAiB,EAAE,CAAC;IACpB,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAChF,gBAAgB,CAAC,OAAO,EAAE,QAAQ,EAAE,QAA+C,CAAC,CAAC;IACvF,CAAC;IACD,6FAA6F;IAC7F,kDAAkD;IAClD,yFAAyF;IACzF,gBAAgB,CAAC,qBAAqB,EAAE,EAAE,GAAG,EAAE,sBAAsB,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;IAC7F,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;QACjF,gBAAgB,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,QAAmC,CAAC,CAAC;IACnF,CAAC;IACD,0FAA0F;IAC1F,uFAAuF;IACvF,gBAAgB,CAAC,gBAAgB,EAAE;QACjC,GAAG,EAAE,qBAAqB,CAAC,uBAAuB,CAAC;QACnD,OAAO,EAAE,SAAS;KACnB,CAAC,CAAC;IACH,gBAAgB,CAAC,qBAAqB,EAAE;QACtC,GAAG,EAAE,qBAAqB,CAAC,uBAAuB,CAAC;QACnD,OAAO,EAAE,SAAS;KACnB,CAAC,CAAC;IACH,+FAA+F;IAC/F,+FAA+F;IAC/F,+FAA+F;IAC/F,2FAA2F;IAC3F,8FAA8F;IAC9F,iDAAiD;IACjD,aAAa,CAAC,eAAe,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IAChG,+FAA+F;IAC/F,+FAA+F;IAC/F,kFAAkF;IAClF,aAAa,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAC;IAC1C,8FAA8F;IAC9F,6EAA6E;IAC7E,aAAa,CAAC,oBAAoB,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AACvE,CAAC","sourcesContent":["/**\n * react-native-screens, driven directly.\n *\n * The native half of navigation already exists as codegen'd Fabric components. We register their\n * names and drive them with `createNode`; their React components are unreachable (hooks) and\n * `react-navigation` is not a dependency.\n *\n * No decorators here on purpose: tests import these at runtime, and Node's type stripping\n * refuses decorators.\n */\nimport { registerHoist, registerViewName } from '@ng-native/fabric';\n\n/**\n * Element name -> codegen'd Fabric component name, and the base style that component's React\n * wrapper would have applied in JS. Element names are lowercase, because the compiler silently\n * empties a template containing a capitalized one.\n *\n * The header's styles are `ScreenStackHeaderConfig.tsx`'s own, and the absolute positioning is\n * load-bearing: without it the config view takes part in the screen's flex layout and every page\n * renders a header's height too far down. `alignItems` is iOS-only there; it is harmless on\n * Android, where the native side lays the bar out itself.\n */\nexport const SCREEN_VIEW_NAMES: Record<string, [viewName: string, defaults?: object]> = {\n // NativeStackOutlet's own host element is the stack.\n 'native-stack-outlet': ['RNSScreenStack'],\n // Created by the outlet, one per activated route; nobody writes this in a template.\n screen: ['RNSScreen'],\n 'native-header': [\n 'RNSScreenStackHeaderConfig',\n {\n position: 'absolute',\n width: '100%',\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n },\n ],\n // Placed in a `<native-header-item type=\"searchBar\">`, as react-native-screens places its own.\n 'native-search-bar': ['RNSSearchBar'],\n 'native-header-item': [\n 'RNSScreenStackHeaderSubview',\n { flexDirection: 'row', alignItems: 'center', justifyContent: 'center' },\n ],\n // What a stack page's content commits in on iOS 26 and later, where the screen runs under the\n // navigation bar: see `insetContent` in `native-stack-outlet.ts`. The fill is `SafeAreaView.tsx`'s.\n 'screen-content': ['RNSSafeAreaView', { flex: 1 }],\n // Insets by what the screen it is in says is covered: a translucent navigation bar, and the tab\n // bar. See `screen-safe-area-view.ts`. The same name on both platforms.\n 'screen-safe-area-view': ['RNSSafeAreaView'],\n 'tab-safe-area-view': ['RNSSafeAreaView'],\n};\n\n/**\n * The tabs half, which react-native-screens names per platform rather than sharing one component:\n * `RNSTabsHostIOS` wraps a `UITabBarController`, `RNSTabsHostAndroid` a bottom navigation bar,\n * and their props differ enough that the codegen specs are separate files.\n *\n * The fills are `TabsHost.ios.tsx`'s and `TabsScreen.ios.tsx`'s own. A tab screen is positioned\n * absolutely because it is one of several occupying the same space, only one of which is visible.\n */\nconst TAB_VIEW_NAMES: Record<string, [ios: string, android: string, defaults?: object]> = {\n 'native-tabs-outlet': [\n 'RNSTabsHostIOS',\n 'RNSTabsHostAndroid',\n { flex: 1, width: '100%', height: '100%' },\n ],\n 'native-tab': [\n 'RNSTabsScreenIOS',\n 'RNSTabsScreenAndroid',\n { position: 'absolute', flex: 1, width: '100%', height: '100%' },\n ],\n};\n\n/**\n * How visible a screen is. The native stack keeps every screen mounted and reads this rather\n * than adding and removing views, which is what preserves a pushed-away screen's native state.\n *\n * `Screen.tsx` throws if this ever *decreases* while in a native stack, so a screen goes\n * 0 -> 2 on push and is removed outright on pop rather than walked back down.\n */\nexport const ActivityState = {\n /** Off screen, and a candidate for freezing. */\n Inactive: 0,\n /** Mid transition: on screen but not the target. */\n Transitioning: 1,\n /** The screen the user is on. */\n Active: 2,\n} as const;\n\nexport type ActivityStateValue = (typeof ActivityState)[keyof typeof ActivityState];\n\n/**\n * The Fabric name of one of `ExpoRouterToolbarModule`'s views, as `requireNativeView` in\n * `expo-modules-core` computes it. Expo Go runs many projects in one binary and names every view\n * after the one it is running; a build of the app's own has no such suffix.\n *\n * `@ng-native/expo` derives the same name for its own views. The Angular-facing packages do not\n * import each other, and this is three lines.\n */\nfunction expoRouterToolbarView(view: string): string {\n const identifier = (globalThis as { expo?: { __expo_app_identifier__?: string } }).expo\n ?.__expo_app_identifier__;\n return `ViewManagerAdapter_ExpoRouterToolbarModule_${view}${identifier ? `_${identifier}` : ''}`;\n}\n\n/**\n * Ask React Native for react-native-screens' native module, which is what makes it.\n *\n * `ScreensModule` on Android installs, as it is made, the listener that starts a removed screen's\n * transition before its views are unmounted: without it a sheet is emptied and then slides away,\n * and a popped screen leaves as a blank one. React Native makes a module when JavaScript first\n * asks, and react-native-screens asks as its own JavaScript is imported (`fabric/\n * NativeScreensModule`), none of which is imported here. Through the two globals React Native's\n * own `TurboModuleRegistry` reads, in its order, so nothing of React Native is imported either:\n * the second is the only one there is without the bridge.\n */\nfunction loadScreensModule(): void {\n const host = globalThis as {\n __turboModuleProxy?: (name: string) => unknown;\n nativeModuleProxy?: Record<string, unknown>;\n };\n void (host.__turboModuleProxy?.('RNSModule') ?? host.nativeModuleProxy?.['RNSModule']);\n}\n\n/**\n * Call once at startup, before the first navigation.\n *\n * The app must also have `react-native-screens` installed so the native side registers these\n * components; this only teaches the engine the element-to-view-name mapping. A name the native\n * side does not know renders as `UnimplementedNativeView`, not an error. None of its JavaScript\n * is imported - Expo Go happens to bundle the native half, which is why the canary worked before\n * it declared the dependency at all, and why an app that forgets it fails only once it ships.\n */\nexport function registerScreenComponents(): void {\n loadScreensModule();\n for (const [element, [viewName, defaults]] of Object.entries(SCREEN_VIEW_NAMES)) {\n registerViewName(element, viewName, defaults as Record<string, unknown> | undefined);\n }\n // By platform, chosen when the view is looked up: this runs as the app's config is imported,\n // before its `main.ts` has reported the platform.\n // A window of its own on iOS; see `full-window-overlay.ts`. Its fill is the component's.\n registerViewName('full-window-overlay', { ios: 'RNSFullWindowOverlay', android: 'RCTView' });\n for (const [element, [ios, android, defaults]] of Object.entries(TAB_VIEW_NAMES)) {\n registerViewName(element, { ios, android }, defaults as Record<string, unknown>);\n }\n // A screen's bottom toolbar is Expo Router's, which react-native-screens has none of: see\n // `native-toolbar.ts`. Android has no such bar, so the elements are plain views there.\n registerViewName('native-toolbar', {\n ios: expoRouterToolbarView('RouterToolbarHostView'),\n android: 'RCTView',\n });\n registerViewName('native-toolbar-item', {\n ios: expoRouterToolbarView('RouterToolbarItemView'),\n android: 'RCTView',\n });\n // `findHeaderConfig` in `RNSScreen.mm` looks at the screen's direct children and no deeper, so\n // a header a page wrote inside a `safe-area-view` or a component of its own commits beside it.\n // Nothing in `RNSScreen.mm` updates the bar when its config is unmounted, so a header an `@if`\n // takes away leaves a config behind that hides the bar, and one that comes back adopts it.\n // A tab's page with no stack has no screen of its own: past its tab is the screen holding the\n // whole tab bar, so its header stops at the tab.\n registerHoist('native-header', 'screen', { standIn: { hidden: true }, stopAt: ['native-tab'] });\n // The toolbar host is a view of its own, absolute and out of the layout, that finds its screen\n // through its superviews. Written ahead of a page's scroll view it would be the screen's first\n // subview, where UIKit looks for the scroll view a large title collapses against.\n registerHoist('native-toolbar', 'screen');\n // The header config takes header items and nothing else, so one written inside a component of\n // the header commits as the config's child, not inside the component's view.\n registerHoist('native-header-item', 'native-header', { only: true });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"screens.js","sourceRoot":"","sources":["../src/screens.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * react-native-screens, driven directly.\n *\n * The native half of navigation already exists as codegen'd Fabric components. We register their\n * names and drive them with `createNode`; their React components are unreachable (hooks) and\n * `react-navigation` is not a dependency.\n *\n * No decorators here on purpose: tests import these at runtime, and Node's type stripping\n * refuses decorators.\n */\nimport { registerHoist, registerViewName } from '@ng-native/fabric';\n\n/**\n * Element name -> codegen'd Fabric component name, and the base style that component's React\n * wrapper would have applied in JS. Element names are lowercase, because the compiler silently\n * empties a template containing a capitalized one.\n *\n * The header's styles are `ScreenStackHeaderConfig.tsx`'s own, and the absolute positioning is\n * load-bearing: without it the config view takes part in the screen's flex layout and every page\n * renders a header's height too far down. `alignItems` is iOS-only there; it is harmless on\n * Android, where the native side lays the bar out itself.\n */\nexport const SCREEN_VIEW_NAMES: Record<string, [viewName: string, defaults?: object]> = {\n // NativeStackOutlet's own host element is the stack.\n 'native-stack-outlet': ['RNSScreenStack'],\n // Created by the outlet, one per activated route; nobody writes this in a template.\n screen: ['RNSScreen'],\n 'native-header': [\n 'RNSScreenStackHeaderConfig',\n {\n position: 'absolute',\n width: '100%',\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n },\n ],\n // Placed in a `<native-header-item type=\"searchBar\">`, as react-native-screens places its own.\n 'native-search-bar': ['RNSSearchBar'],\n 'native-header-item': [\n 'RNSScreenStackHeaderSubview',\n { flexDirection: 'row', alignItems: 'center', justifyContent: 'center' },\n ],\n // Insets by what the screen it is in says is covered: a translucent navigation bar, and the tab\n // bar. See `screen-safe-area-view.ts`. The same name on both platforms. The fill is\n // react-native-screens' `SafeAreaView.tsx`'s, and defaults are a native view's, so the tab one\n // below takes it too.\n 'screen-safe-area-view': ['RNSSafeAreaView', { flex: 1 }],\n 'tab-safe-area-view': ['RNSSafeAreaView'],\n};\n\n/**\n * The tabs half, which react-native-screens names per platform rather than sharing one component:\n * `RNSTabsHostIOS` wraps a `UITabBarController`, `RNSTabsHostAndroid` a bottom navigation bar,\n * and their props differ enough that the codegen specs are separate files.\n *\n * The fills are `TabsHost.ios.tsx`'s and `TabsScreen.ios.tsx`'s own. A tab screen is positioned\n * absolutely because it is one of several occupying the same space, only one of which is visible.\n */\nconst TAB_VIEW_NAMES: Record<string, [ios: string, android: string, defaults?: object]> = {\n 'native-tabs-outlet': [\n 'RNSTabsHostIOS',\n 'RNSTabsHostAndroid',\n { flex: 1, width: '100%', height: '100%' },\n ],\n 'native-tab': [\n 'RNSTabsScreenIOS',\n 'RNSTabsScreenAndroid',\n { position: 'absolute', flex: 1, width: '100%', height: '100%' },\n ],\n};\n\n/**\n * How visible a screen is. The native stack keeps every screen mounted and reads this rather\n * than adding and removing views, which is what preserves a pushed-away screen's native state.\n *\n * `Screen.tsx` throws if this ever *decreases* while in a native stack, so a screen goes\n * 0 -> 2 on push and is removed outright on pop rather than walked back down.\n */\nexport const ActivityState = {\n /** Off screen, and a candidate for freezing. */\n Inactive: 0,\n /** Mid transition: on screen but not the target. */\n Transitioning: 1,\n /** The screen the user is on. */\n Active: 2,\n} as const;\n\nexport type ActivityStateValue = (typeof ActivityState)[keyof typeof ActivityState];\n\n/**\n * The Fabric name of one of `ExpoRouterToolbarModule`'s views, as `requireNativeView` in\n * `expo-modules-core` computes it. Expo Go runs many projects in one binary and names every view\n * after the one it is running; a build of the app's own has no such suffix.\n *\n * `@ng-native/expo` derives the same name for its own views. The Angular-facing packages do not\n * import each other, and this is three lines.\n */\nfunction expoRouterToolbarView(view: string): string {\n const identifier = (globalThis as { expo?: { __expo_app_identifier__?: string } }).expo\n ?.__expo_app_identifier__;\n return `ViewManagerAdapter_ExpoRouterToolbarModule_${view}${identifier ? `_${identifier}` : ''}`;\n}\n\n/**\n * Ask React Native for react-native-screens' native module, which is what makes it.\n *\n * `ScreensModule` on Android installs, as it is made, the listener that starts a removed screen's\n * transition before its views are unmounted: without it a sheet is emptied and then slides away,\n * and a popped screen leaves as a blank one. React Native makes a module when JavaScript first\n * asks, and react-native-screens asks as its own JavaScript is imported (`fabric/\n * NativeScreensModule`), none of which is imported here. Through the two globals React Native's\n * own `TurboModuleRegistry` reads, in its order, so nothing of React Native is imported either:\n * the second is the only one there is without the bridge.\n */\nfunction loadScreensModule(): void {\n const host = globalThis as {\n __turboModuleProxy?: (name: string) => unknown;\n nativeModuleProxy?: Record<string, unknown>;\n };\n void (host.__turboModuleProxy?.('RNSModule') ?? host.nativeModuleProxy?.['RNSModule']);\n}\n\n/**\n * Call once at startup, before the first navigation.\n *\n * The app must also have `react-native-screens` installed so the native side registers these\n * components; this only teaches the engine the element-to-view-name mapping. A name the native\n * side does not know renders as `UnimplementedNativeView`, not an error. None of its JavaScript\n * is imported - Expo Go happens to bundle the native half, which is why the canary worked before\n * it declared the dependency at all, and why an app that forgets it fails only once it ships.\n */\nexport function registerScreenComponents(): void {\n loadScreensModule();\n for (const [element, [viewName, defaults]] of Object.entries(SCREEN_VIEW_NAMES)) {\n registerViewName(element, viewName, defaults as Record<string, unknown> | undefined);\n }\n // By platform, chosen when the view is looked up: this runs as the app's config is imported,\n // before its `main.ts` has reported the platform.\n // A window of its own on iOS; see `full-window-overlay.ts`. Its fill is the component's.\n registerViewName('full-window-overlay', { ios: 'RNSFullWindowOverlay', android: 'RCTView' });\n for (const [element, [ios, android, defaults]] of Object.entries(TAB_VIEW_NAMES)) {\n registerViewName(element, { ios, android }, defaults as Record<string, unknown>);\n }\n // A screen's bottom toolbar is Expo Router's, which react-native-screens has none of: see\n // `native-toolbar.ts`. Android has no such bar, so the elements are plain views there.\n registerViewName('native-toolbar', {\n ios: expoRouterToolbarView('RouterToolbarHostView'),\n android: 'RCTView',\n });\n registerViewName('native-toolbar-item', {\n ios: expoRouterToolbarView('RouterToolbarItemView'),\n android: 'RCTView',\n });\n // `findHeaderConfig` in `RNSScreen.mm` looks at the screen's direct children and no deeper, so\n // a header a page wrote inside a `safe-area-view` or a component of its own commits beside it.\n // Nothing in `RNSScreen.mm` updates the bar when its config is unmounted, so a header an `@if`\n // takes away leaves a config behind that hides the bar, and one that comes back adopts it.\n // A tab's page with no stack has no screen of its own: past its tab is the screen holding the\n // whole tab bar, so its header stops at the tab.\n registerHoist('native-header', 'screen', { standIn: { hidden: true }, stopAt: ['native-tab'] });\n // The toolbar host is a view of its own, absolute and out of the layout, that finds its screen\n // through its superviews. Written ahead of a page's scroll view it would be the screen's first\n // subview, where UIKit looks for the scroll view a large title collapses against.\n registerHoist('native-toolbar', 'screen');\n // The header config takes header items and nothing else, so one written inside a component of\n // the header commits as the config's child, not inside the component's view.\n registerHoist('native-header-item', 'native-header', { only: true });\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ng-native/router",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "@angular/router over native navigation for Angular Native: stack and tab outlets, native headers and links.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"angular",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"type": "module",
|
|
18
18
|
"main": "dist/index.js",
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@ng-native/device": "0.
|
|
21
|
-
"@ng-native/fabric": "0.
|
|
20
|
+
"@ng-native/device": "0.19.0",
|
|
21
|
+
"@ng-native/fabric": "0.19.0"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
24
|
"@angular/common": "^22.0.0",
|