@ng-native/router 0.17.1 → 0.18.1

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.
Files changed (54) hide show
  1. package/dist/discard-failed-entries.d.ts +11 -0
  2. package/dist/discard-failed-entries.js +48 -0
  3. package/dist/discard-failed-entries.js.map +1 -0
  4. package/dist/in-tab.d.ts +9 -1
  5. package/dist/in-tab.js +2 -0
  6. package/dist/in-tab.js.map +1 -1
  7. package/dist/native-back.d.ts +21 -1
  8. package/dist/native-back.js +94 -3
  9. package/dist/native-back.js.map +1 -1
  10. package/dist/native-header.d.ts +8 -1
  11. package/dist/native-header.js +18 -4
  12. package/dist/native-header.js.map +1 -1
  13. package/dist/native-navigation.d.ts +10 -2
  14. package/dist/native-navigation.js +45 -9
  15. package/dist/native-navigation.js.map +1 -1
  16. package/dist/native-platform-location.d.ts +42 -0
  17. package/dist/native-platform-location.js +66 -0
  18. package/dist/native-platform-location.js.map +1 -1
  19. package/dist/native-stack-outlet.d.ts +83 -0
  20. package/dist/native-stack-outlet.js +245 -19
  21. package/dist/native-stack-outlet.js.map +1 -1
  22. package/dist/native-stack-reuse-strategy.d.ts +34 -0
  23. package/dist/native-stack-reuse-strategy.js +119 -7
  24. package/dist/native-stack-reuse-strategy.js.map +1 -1
  25. package/dist/native-tab.d.ts +8 -6
  26. package/dist/native-tab.js +23 -2
  27. package/dist/native-tab.js.map +1 -1
  28. package/dist/native-tabs-outlet.d.ts +9 -3
  29. package/dist/native-tabs-outlet.js +21 -4
  30. package/dist/native-tabs-outlet.js.map +1 -1
  31. package/dist/popping-to.d.ts +8 -0
  32. package/dist/popping-to.js +2 -0
  33. package/dist/popping-to.js.map +1 -0
  34. package/dist/presented-route.js +12 -10
  35. package/dist/presented-route.js.map +1 -1
  36. package/dist/provide-native-router.js +4 -0
  37. package/dist/provide-native-router.js.map +1 -1
  38. package/dist/screen-header.d.ts +5 -3
  39. package/dist/screen-header.js +5 -3
  40. package/dist/screen-header.js.map +1 -1
  41. package/dist/screen-presentation.d.ts +5 -0
  42. package/dist/screen-presentation.js.map +1 -1
  43. package/dist/screen-safe-area-view.d.ts +6 -1
  44. package/dist/screen-safe-area-view.js +12 -4
  45. package/dist/screen-safe-area-view.js.map +1 -1
  46. package/dist/screens-version.d.ts +12 -0
  47. package/dist/screens-version.js +20 -0
  48. package/dist/screens-version.js.map +1 -0
  49. package/dist/screens.js +3 -0
  50. package/dist/screens.js.map +1 -1
  51. package/dist/url-commands.d.ts +24 -0
  52. package/dist/url-commands.js +102 -0
  53. package/dist/url-commands.js.map +1 -0
  54. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"native-stack-reuse-strategy.js","sourceRoot":"","sources":["../src/native-stack-reuse-strategy.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The reuse strategy that turns navigation into a stack.\n *\n * Angular's default strategy never detaches, so navigating away destroys the component and its\n * native views, and coming back rebuilds them from scratch: a list is back at the top, a form is\n * empty. Detaching instead hands the live `ComponentRef` to the outlet, which keeps its screen\n * mounted. That is the whole reason `RouterOutletContract.detach()` exists.\n *\n * No decorators, so tests can import it and so it can be provided with `useClass`.\n */\nimport { Injector, inject, type ComponentRef } from '@angular/core';\nimport {\n BaseRouteReuseStrategy,\n type ActivatedRouteSnapshot,\n type DetachedRouteHandle,\n Router,\n type Route,\n} from '@angular/router';\nimport { navigationIntent } from './native-navigation.ts';\nimport { PRESENTED } from './presented-route.ts';\nimport { isScreenRoute, isTabRoute } from './tab-routes.ts';\n\n/**\n * Where `reuseScreen` marks a route. On the config's `data` rather than in a set of configs,\n * because the router copies every route config it is given, so the object an app wrote is never\n * the one a snapshot points at.\n */\nconst REUSE_SCREEN = 'ɵreuseScreen';\n\n/**\n * Keep one screen for a route whatever its parameters, updating it in place as Angular's own\n * strategy does, instead of pushing a new screen for each url.\n *\n * `reuseScreen({ path: 'photo/:index', component: Photo })` for a route whose parameter picks\n * what one screen shows - a pager, a step through a list - rather than naming another screen to\n * go to. Everything else stacks: `/user/1` then `/user/2` is two screens, and back returns to the\n * first.\n */\nexport function reuseScreen<T extends Route>(route: T): T {\n return { ...route, data: { ...route.data, [REUSE_SCREEN]: true } };\n}\n\n/** What the router actually stores: `DetachedRouteHandle` is typed as an opaque object. */\ninterface StoredHandle {\n readonly componentRef?: ComponentRef<unknown>;\n}\n\n/**\n * Identify a screen by its resolved url rather than its route config, so `/user/1` and `/user/2`\n * are two screens on the stack rather than one that gets reused.\n *\n * One entry per level of the route tree, empty ones included. Flattened to a url, a tab at\n * `/tabs/library` and the list at path `''` beneath it are the same string, and the router, asking\n * for the list, is handed the tab's whole tree and makes the tab its own child.\n */\nfunction keyOf(route: ActivatedRouteSnapshot): string {\n const levels: string[] = [];\n for (let current: ActivatedRouteSnapshot | null = route; current; current = current.parent) {\n levels.unshift(current.url.map((segment) => segment.toString()).join('/'));\n }\n return JSON.stringify(levels);\n}\n\nfunction injectorHere(): Injector | null {\n try {\n return inject(Injector);\n } catch {\n return null;\n }\n}\n\nexport class NativeStackReuseStrategy extends BaseRouteReuseStrategy {\n /**\n * The screens kept for each url, oldest first. More than one where the same url is on the stack\n * twice: a customer, one of its jobs, and the customer again from the job.\n */\n private readonly handles = new Map<string, DetachedRouteHandle[]>();\n /**\n * For the navigation in flight, read when it is asked for: the router is built from this. Null\n * where the strategy is made by hand, outside an injector, and every navigation is then plain.\n */\n private readonly injector = injectorHere();\n\n /**\n * Only leaf routes become screens; a parent with children is layout, not a destination.\n *\n * A tab is the exception, and has to be. Detaching only its leaf would rebuild the tab itself\n * on every switch, and with it the stack outlet inside: a tab two screens deep would come back\n * one screen deep, having lost the screens the user could go back to. Detaching the tab keeps\n * its whole subtree, which is what makes each tab remember where it was.\n *\n * So is a parent a native stack put on screen, such as a root stack's tab bar: a sheet presented\n * over it has to leave it standing (see `markScreenRoute`).\n */\n override shouldDetach(route: ActivatedRouteSnapshot): boolean {\n if (route.component === null) return false;\n // A page presented over the tabs is dismissed, not kept: nothing goes back to it.\n if (route.outlet === PRESENTED) return false;\n return (\n route.children.length === 0 ||\n isTabRoute(route.routeConfig) ||\n isScreenRoute(route.routeConfig)\n );\n }\n\n override store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle | null): void {\n const key = keyOf(route);\n const kept = this.handles.get(key) ?? [];\n if (handle) {\n // The same screen stored again takes its place at the end, not a second one.\n this.handles.set(key, [...kept.filter((one) => one !== handle), handle]);\n this.forgetOnDestroy((handle as StoredHandle).componentRef);\n return;\n }\n // The router has re-attached the one `retrieve` answered with: the last.\n if (kept.length > 1) this.handles.set(key, kept.slice(0, -1));\n else this.handles.delete(key);\n }\n\n private readonly watched = new WeakSet<ComponentRef<unknown>>();\n\n /**\n * Drop a screen's handles the moment its component is destroyed.\n *\n * The router stores a handle for every screen it navigates away from, the one being popped\n * included, and the outlet then destroys that screen. A handle outlives its component, and holds\n * the component's whole view and every native node in it; `retrieve` notices only when the same\n * url is asked for again, so a url never revisited kept its last screen for as long as the app\n * ran.\n */\n private forgetOnDestroy(ref: ComponentRef<unknown> | undefined): void {\n if (!ref || this.watched.has(ref)) return;\n this.watched.add(ref);\n ref.onDestroy(() => {\n for (const [key, kept] of this.handles) {\n const left = kept.filter((handle) => (handle as StoredHandle).componentRef !== ref);\n if (left.length) this.handles.set(key, left);\n else this.handles.delete(key);\n }\n });\n }\n\n /**\n * Angular reuses a route whenever its config is the same, so on the web `/user/1` to `/user/2`\n * keeps the one component and feeds it the new params. On a native stack that turns a push into\n * an update in place: no push animation, one screen, and back skipping past `/user/1`. A screen\n * a stack put on screen is reused only when its url is the same too, so a different parameter\n * is a different screen, which the router detaches and stores as it does any screen pushed\n * away. A query or fragment change is not part of the url that identifies a screen, and a\n * parent that is only layout is reused as before, so its stack keeps what is in it.\n */\n override shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {\n if (future.routeConfig !== curr.routeConfig) return false;\n const config = curr.routeConfig;\n const reuse =\n !isScreenRoute(config) ||\n config?.data?.[REUSE_SCREEN] === true ||\n keyOf(future) === keyOf(curr);\n if (reuse) this.reused.add(future);\n return reuse;\n }\n\n /** The routes the navigation in flight keeps as they are, by the snapshot it is building. */\n private readonly reused = new WeakSet<ActivatedRouteSnapshot>();\n\n /**\n * Whether the router goes back to a kept screen for this url. Not for a push: a push to a url\n * already on the stack is a new screen over it, as a native stack makes one, and Back returns\n * to where the push came from. Going back to the kept one is a back, or `popTo`.\n *\n * Never for a route with no component, which is never kept: the router asks for every route,\n * and a group at path `''` has the same url as a page at `''` beside it, whose screen it would\n * otherwise be handed.\n *\n * A tab is attached for a push too: the push is into the tab's own stack, which is kept with it,\n * and building the tab again would leave a second stack in the tab's screen. Only into the bar\n * already showing, though: a push that builds another bar over it builds its tabs too, and the\n * one kept at the same url is the bar beneath's.\n */\n override shouldAttach(route: ActivatedRouteSnapshot): boolean {\n if (route.component === null) return false;\n if (this.pushing() && !(isTabRoute(route.routeConfig) && this.inKeptBar(route))) return false;\n return this.retrieve(route) !== null;\n }\n\n /** Whether the tab bar above a tab's route is one the navigation keeps rather than builds. */\n private inKeptBar(route: ActivatedRouteSnapshot): boolean {\n let bar = route.parent;\n while (bar && bar.component === null) bar = bar.parent;\n return bar !== null && this.reused.has(bar);\n }\n\n private pushing(): boolean {\n const router = this.injector?.get(Router);\n const navigation = router?.currentNavigation();\n // A back restores the state its history entry was pushed with, intent and all: that is the\n // screen being returned to, not a push.\n if (!router || !navigation || navigation.trigger === 'popstate') return false;\n return navigationIntent(router, navigation)?.stack === 'push';\n }\n\n override retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {\n const key = keyOf(route);\n const kept = (this.handles.get(key) ?? []).filter(\n (handle) => !(handle as StoredHandle).componentRef?.hostView.destroyed,\n );\n if (kept.length) this.handles.set(key, kept);\n else this.handles.delete(key);\n // The newest: the one a back from the top of the stack returns to.\n return kept.at(-1) ?? null;\n }\n}\n"]}
1
+ {"version":3,"file":"native-stack-reuse-strategy.js","sourceRoot":"","sources":["../src/native-stack-reuse-strategy.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The reuse strategy that turns navigation into a stack.\n *\n * Angular's default strategy never detaches, so navigating away destroys the component and its\n * native views, and coming back rebuilds them from scratch: a list is back at the top, a form is\n * empty. Detaching instead hands the live `ComponentRef` to the outlet, which keeps its screen\n * mounted. That is the whole reason `RouterOutletContract.detach()` exists.\n *\n * No decorators, so tests can import it and so it can be provided with `useClass`.\n */\nimport { PlatformLocation } from '@angular/common';\nimport { Injector, inject, type ComponentRef } from '@angular/core';\nimport {\n BaseRouteReuseStrategy,\n NavigationCancel,\n NavigationEnd,\n NavigationError,\n type ActivatedRouteSnapshot,\n type DetachedRouteHandle,\n Router,\n type Route,\n} from '@angular/router';\nimport { navigationIntent } from './native-navigation.ts';\nimport { NativePlatformLocation } from './native-platform-location.ts';\nimport { poppingTo } from './popping-to.ts';\nimport { PRESENTED } from './presented-route.ts';\nimport { isScreenRoute, isTabRoute } from './tab-routes.ts';\n\n/**\n * Where `reuseScreen` marks a route. On the config's `data` rather than in a set of configs,\n * because the router copies every route config it is given, so the object an app wrote is never\n * the one a snapshot points at.\n */\nconst REUSE_SCREEN = 'ɵreuseScreen';\n\n/**\n * Keep one screen for a route whatever its parameters, updating it in place as Angular's own\n * strategy does, instead of pushing a new screen for each url.\n *\n * `reuseScreen({ path: 'photo/:index', component: Photo })` for a route whose parameter picks\n * what one screen shows - a pager, a step through a list - rather than naming another screen to\n * go to. Everything else stacks: `/user/1` then `/user/2` is two screens, and back returns to the\n * first.\n */\nexport function reuseScreen<T extends Route>(route: T): T {\n return { ...route, data: { ...route.data, [REUSE_SCREEN]: true } };\n}\n\n/** Whether `event` is the last a navigation reports. */\nconst isNavigationEnding = (\n event: unknown,\n): event is NavigationEnd | NavigationCancel | NavigationError =>\n event instanceof NavigationEnd ||\n event instanceof NavigationCancel ||\n event instanceof NavigationError;\n\n/** What the router actually stores: `DetachedRouteHandle` is typed as an opaque object. */\ninterface StoredHandle {\n readonly componentRef?: ComponentRef<unknown>;\n}\n\n/**\n * Identify a screen by its resolved url rather than its route config, so `/user/1` and `/user/2`\n * are two screens on the stack rather than one that gets reused.\n *\n * One entry per level of the route tree, empty ones included. Flattened to a url, a tab at\n * `/tabs/library` and the list at path `''` beneath it are the same string, and the router, asking\n * for the list, is handed the tab's whole tree and makes the tab its own child.\n */\nfunction keyOf(route: ActivatedRouteSnapshot): string {\n const levels: string[] = [];\n for (let current: ActivatedRouteSnapshot | null = route; current; current = current.parent) {\n levels.unshift(current.url.map((segment) => segment.toString()).join('/'));\n }\n return JSON.stringify(levels);\n}\n\nfunction injectorHere(): Injector | null {\n try {\n return inject(Injector);\n } catch {\n return null;\n }\n}\n\nexport class NativeStackReuseStrategy extends BaseRouteReuseStrategy {\n /**\n * The screens kept for each url, oldest first. More than one where the same url is on the stack\n * twice: a customer, one of its jobs, and the customer again from the job.\n */\n private readonly handles = new Map<string, DetachedRouteHandle[]>();\n /**\n * For the navigation in flight, read when it is asked for: the router is built from this. Null\n * where the strategy is made by hand, outside an injector, and every navigation is then plain.\n */\n private readonly injector = injectorHere();\n\n /**\n * Only leaf routes become screens; a parent with children is layout, not a destination.\n *\n * A tab is the exception, and has to be. Detaching only its leaf would rebuild the tab itself\n * on every switch, and with it the stack outlet inside: a tab two screens deep would come back\n * one screen deep, having lost the screens the user could go back to. Detaching the tab keeps\n * its whole subtree, which is what makes each tab remember where it was.\n *\n * So is a parent a native stack put on screen, such as a root stack's tab bar: a sheet presented\n * over it has to leave it standing (see `markScreenRoute`).\n */\n override shouldDetach(route: ActivatedRouteSnapshot): boolean {\n if (route.component === null) return false;\n // A page presented over the tabs is dismissed, not kept: nothing goes back to it.\n if (route.outlet === PRESENTED) return false;\n return (\n route.children.length === 0 ||\n isTabRoute(route.routeConfig) ||\n isScreenRoute(route.routeConfig)\n );\n }\n\n override store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle | null): void {\n this.keepForRollBack();\n const key = keyOf(route);\n const kept = this.handles.get(key) ?? [];\n if (handle) {\n // The same screen stored again takes its place at the end, not a second one.\n this.handles.set(key, [...kept.filter((one) => one !== handle), handle]);\n this.entryOf.set(handle, this.inHistory(this.shownIn.get(route)));\n this.forgetOnDestroy((handle as StoredHandle).componentRef);\n return;\n }\n // The router has re-attached the one `retrieve` answered with.\n const attached = this.answered.get(route) ?? kept.at(-1);\n // Its other entries are still in history, behind or ahead of the one it is back at.\n if (attached) {\n const before = this.entryOf.get(attached) ?? [];\n this.shownIn.set(route, [...before, ...(this.shownIn.get(route) ?? [])]);\n }\n const left = kept.filter((one) => one !== attached);\n if (left.length) this.handles.set(key, left);\n else this.handles.delete(key);\n }\n\n /**\n * The navigations that put each route's screen on screen, by the snapshot the last one built,\n * and so the ids in that screen's history entries: Angular writes the id of the navigation into\n * the entry it pushes or replaces, a back included. More than one where the screen changed in\n * place, a query set on it, which gives it an entry of its own.\n */\n private readonly shownIn = new WeakMap<ActivatedRouteSnapshot, readonly (number | undefined)[]>();\n /** Each kept screen's history entries, by those navigations' ids. */\n private readonly entryOf = new WeakMap<DetachedRouteHandle, readonly (number | undefined)[]>();\n /** The screen `retrieve` answered with for a route, for `store` to take out once attached. */\n private readonly answered = new WeakMap<ActivatedRouteSnapshot, DetachedRouteHandle>();\n\n private showing(route: ActivatedRouteSnapshot, from?: ActivatedRouteSnapshot): void {\n const navigation = this.injector?.get(Router).currentNavigation();\n // Added to the ones it was shown in before, for a screen kept as it is. A navigation that skips\n // the location change writes no entry, so its id is in none and goes at the next.\n this.shownIn.set(route, [...this.inHistory(from && this.shownIn.get(from)), navigation?.id]);\n }\n\n /**\n * The ids an entry in history still holds: one a navigation replaced, skipped, or left ahead of\n * a push is in none, and matches nothing again. All of them where the history is not ours.\n */\n private inHistory(ids: readonly (number | undefined)[] | undefined): (number | undefined)[] {\n const history = this.injector?.get(PlatformLocation, null);\n if (!(history instanceof NativePlatformLocation)) return [...(ids ?? [])];\n const held = history.ɵnavigationIds();\n return (ids ?? []).filter((id) => id !== undefined && held.has(id));\n }\n\n /**\n * The screens kept before the navigation in flight first stored or took one, to put back if it\n * fails: the router leaves the screens it detached and attached as they were then, and a screen\n * a stack takes off to go back to one kept below is back on top.\n */\n private beforeNavigation: {\n navigation: number;\n handles: Map<string, DetachedRouteHandle[]>;\n } | null = null;\n private rollsBack = false;\n\n private keepForRollBack(): void {\n const router = this.injector?.get(Router);\n const navigation = router?.currentNavigation()?.id;\n if (navigation === undefined || this.beforeNavigation?.navigation === navigation) return;\n const handles = new Map([...this.handles].map(([key, kept]) => [key, [...kept]]));\n this.beforeNavigation = { navigation, handles };\n if (this.rollsBack) return;\n // Subscribed on first use: the router is built with this strategy, so not yet there before.\n this.rollsBack = true;\n router!.events.subscribe((event) => {\n const before = this.beforeNavigation;\n if (!isNavigationEnding(event) || before?.navigation !== event.id) return;\n this.beforeNavigation = null;\n if (event instanceof NavigationError) this.rollBack(before.handles);\n });\n }\n\n private rollBack(handles: Map<string, DetachedRouteHandle[]>): void {\n this.handles.clear();\n for (const [key, kept] of handles) {\n const live = kept.filter(\n (handle) => !(handle as StoredHandle).componentRef?.hostView.destroyed,\n );\n if (live.length) this.handles.set(key, live);\n }\n }\n\n private readonly watched = new WeakSet<ComponentRef<unknown>>();\n\n /**\n * Drop a screen's handles the moment its component is destroyed.\n *\n * The router stores a handle for every screen it navigates away from, the one being popped\n * included, and the outlet then destroys that screen. A handle outlives its component, and holds\n * the component's whole view and every native node in it; `retrieve` notices only when the same\n * url is asked for again, so a url never revisited kept its last screen for as long as the app\n * ran.\n */\n private forgetOnDestroy(ref: ComponentRef<unknown> | undefined): void {\n if (!ref || this.watched.has(ref)) return;\n this.watched.add(ref);\n ref.onDestroy(() => {\n for (const [key, kept] of this.handles) {\n const left = kept.filter((handle) => (handle as StoredHandle).componentRef !== ref);\n if (left.length) this.handles.set(key, left);\n else this.handles.delete(key);\n }\n });\n }\n\n /**\n * Angular reuses a route whenever its config is the same, so on the web `/user/1` to `/user/2`\n * keeps the one component and feeds it the new params. On a native stack that turns a push into\n * an update in place: no push animation, one screen, and back skipping past `/user/1`. A screen\n * a stack put on screen is reused only when its url is the same too, so a different parameter\n * is a different screen, which the router detaches and stores as it does any screen pushed\n * away. A query or fragment change is not part of the url that identifies a screen, and a\n * parent that is only layout is reused as before, so its stack keeps what is in it.\n */\n override shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {\n if (future.routeConfig !== curr.routeConfig) return false;\n const config = curr.routeConfig;\n const reuse =\n !isScreenRoute(config) ||\n config?.data?.[REUSE_SCREEN] === true ||\n keyOf(future) === keyOf(curr);\n if (reuse) {\n this.reused.add(future);\n this.showing(future, curr);\n }\n return reuse;\n }\n\n /** The routes the navigation in flight keeps as they are, by the snapshot it is building. */\n private readonly reused = new WeakSet<ActivatedRouteSnapshot>();\n\n /**\n * Whether the router goes back to a kept screen for this url. Not for a push: a push to a url\n * already on the stack is a new screen over it, as a native stack makes one, and Back returns\n * to where the push came from. Going back to the kept one is a back, or `popTo`.\n *\n * Never for a route with no component, which is never kept: the router asks for every route,\n * and a group at path `''` has the same url as a page at `''` beside it, whose screen it would\n * otherwise be handed.\n *\n * A tab is attached for a push too: the push is into the tab's own stack, which is kept with it,\n * and building the tab again would leave a second stack in the tab's screen. Only into the bar\n * already showing, though: a push that builds another bar over it builds its tabs too, and the\n * one kept at the same url is the bar beneath's.\n */\n override shouldAttach(route: ActivatedRouteSnapshot): boolean {\n if (route.component === null) return false;\n this.showing(route);\n if (this.pushing() && !(isTabRoute(route.routeConfig) && this.inKeptBar(route))) return false;\n return this.retrieve(route) !== null;\n }\n\n /** Whether the tab bar above a tab's route is one the navigation keeps rather than builds. */\n private inKeptBar(route: ActivatedRouteSnapshot): boolean {\n let bar = route.parent;\n while (bar && bar.component === null) bar = bar.parent;\n return bar !== null && this.reused.has(bar);\n }\n\n private pushing(): boolean {\n const router = this.injector?.get(Router);\n const navigation = router?.currentNavigation();\n // A back restores the state its history entry was pushed with, intent and all: that is the\n // screen being returned to, not a push.\n if (!router || !navigation || navigation.trigger === 'popstate') return false;\n return navigationIntent(router, navigation)?.stack === 'push';\n }\n\n override retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {\n const key = keyOf(route);\n const kept = (this.handles.get(key) ?? []).filter(\n (handle) => !(handle as StoredHandle).componentRef?.hostView.destroyed,\n );\n if (kept.length) this.handles.set(key, kept);\n else this.handles.delete(key);\n // Asked again for the same route as the router attaches it, by which time the router has\n // written its own id into the entry: the same answer.\n const before = this.answered.get(route);\n if (before && kept.includes(before)) return before;\n const handle = this.pick(kept);\n if (handle) this.answered.set(route, handle);\n return handle;\n }\n\n /**\n * The one at the history entry a back returns to, where two screens share the url: a back of\n * three screens from C over A, B, A is the first A. Or the one a pop the history could not make\n * goes down to. Otherwise the newest, the one a back from the top of the stack returns to.\n */\n private pick(kept: readonly DetachedRouteHandle[]): DetachedRouteHandle | null {\n const entry = this.backTo();\n const router = this.injector?.get(Router);\n const target = router && poppingTo.get(router);\n return (\n (entry !== undefined && kept.find((one) => this.entryOf.get(one)?.includes(entry))) ||\n (target && kept.filter((one) => (one as StoredHandle).componentRef === target).at(-1)) ||\n kept.at(-1) ||\n null\n );\n }\n\n /** The id in the history entry a back is returning to, which names the screen shown there. */\n private backTo(): number | undefined {\n const router = this.injector?.get(Router);\n if (router?.currentNavigation()?.trigger !== 'popstate') return undefined;\n const state = this.injector?.get(PlatformLocation, null)?.getState();\n const id = (state as { navigationId?: unknown } | null)?.navigationId;\n return typeof id === 'number' ? id : undefined;\n }\n}\n"]}
@@ -131,6 +131,11 @@ export declare function tabIconProps(icon: TabIconProps, selectedIcon: TabIconPr
131
131
  selectedDrawableIconResourceName?: string;
132
132
  selectedImageIconResource?: unknown;
133
133
  };
134
+ /** Every icon prop a tab commits. */
135
+ type TabIconSet = ReturnType<typeof tabIconProps> & {
136
+ iconImageRenderingMode?: string;
137
+ selectedIconImageRenderingMode?: string;
138
+ };
134
139
  /**
135
140
  * The key native identifies a tab by: its path, or `/` for the tab at path `''`, since iOS reads an
136
141
  * empty key as none and fails on the tap that selects it. No route path starts with `/`.
@@ -143,6 +148,7 @@ export declare class NativeTab implements OnInit {
143
148
  private readonly svgRenderer;
144
149
  private readonly svgHost;
145
150
  private readonly errors;
151
+ private readonly readsRenderingModes;
146
152
  /**
147
153
  * The `RNSTabsScreen` this tab is. The outlet creates the activated route's component inside
148
154
  * it, which is why it is public: a tab is a slot as well as a bar item.
@@ -198,12 +204,7 @@ export declare class NativeTab implements OnInit {
198
204
  /** `icon` and `selectedIcon` as drawn, when they are SVG. */
199
205
  private readonly drawnIcon;
200
206
  private readonly drawnSelectedIcon;
201
- protected readonly icons: Signal<TabIconProps & {
202
- selectedIconResourceName?: string;
203
- selectedIconImageSource?: unknown;
204
- selectedDrawableIconResourceName?: string;
205
- selectedImageIconResource?: unknown;
206
- }>;
207
+ protected readonly icons: Signal<TabIconSet>;
207
208
  /**
208
209
  * An SVG icon as the renderer drew it, undefined until it has. Markup that changes is drawn
209
210
  * again, and a drawing that finishes after newer markup arrived is dropped.
@@ -227,3 +228,4 @@ export declare class NativeTab implements OnInit {
227
228
  static ɵfac: i0.ɵɵFactoryDeclaration<NativeTab, never>;
228
229
  static ɵcmp: i0.ɵɵComponentDeclaration<NativeTab, "native-tab", never, { "path": { "alias": "path"; "required": true; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "sfSymbol": { "alias": "sfSymbol"; "required": false; "isSignal": true; }; "drawable": { "alias": "drawable"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "selectedIcon": { "alias": "selectedIcon"; "required": false; "isSignal": true; }; "systemItem": { "alias": "systemItem"; "required": false; "isSignal": true; }; "role": { "alias": "role"; "required": false; "isSignal": true; }; "automaticallyActivatesSearch": { "alias": "automaticallyActivatesSearch"; "required": false; "isSignal": true; }; "badge": { "alias": "badge"; "required": false; "isSignal": true; }; "accessibilityLabel": { "alias": "accessibilityLabel"; "required": false; "isSignal": true; }; "standardAppearance": { "alias": "standardAppearance"; "required": false; "isSignal": true; }; "scrollEdgeAppearance": { "alias": "scrollEdgeAppearance"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
229
230
  }
231
+ export {};
@@ -32,6 +32,7 @@ import { NATIVE_TAB_DEFAULTS } from "./native-bar-defaults.js";
32
32
  import { ownHost } from "./own-host.js";
33
33
  import { optionalBoolean } from "./transforms.js";
34
34
  import { SVG_ICON_HOST, SVG_ICON_RENDERER } from "./svg-icons.js";
35
+ import { SCREENS_VERSION, screensReadsRenderingModes } from "./screens-version.js";
35
36
  import * as i0 from "@angular/core";
36
37
  /**
37
38
  * An icon and its selected counterpart, as one set of props.
@@ -59,6 +60,22 @@ export function tabIconProps(icon, selectedIcon) {
59
60
  selectedImageIconResource: selectedIcon.imageIconResource,
60
61
  };
61
62
  }
63
+ /**
64
+ * iOS: a template icon in the form react-native-screens 4.29 and later read, an `image` with a
65
+ * `template` rendering mode per state. Those releases dropped `iconType: 'template'`, and native
66
+ * aborts the app on an `iconType` it does not know, so the older form cannot be sent to them. A
67
+ * selected icon is a template too, since `tabIconProps` pairs only icons of one kind.
68
+ */
69
+ function withRenderingModes(icons) {
70
+ if (icons.iconType !== 'template')
71
+ return icons;
72
+ return {
73
+ ...icons,
74
+ iconType: 'image',
75
+ iconImageRenderingMode: 'template',
76
+ selectedIconImageRenderingMode: 'template',
77
+ };
78
+ }
62
79
  function isSvg(icon) {
63
80
  return icon !== undefined && 'svg' in icon;
64
81
  }
@@ -119,6 +136,7 @@ export class NativeTab {
119
136
  svgRenderer = inject(SVG_ICON_RENDERER);
120
137
  svgHost = inject(SVG_ICON_HOST, { optional: true });
121
138
  errors = inject(ErrorHandler);
139
+ readsRenderingModes = screensReadsRenderingModes(inject(SCREENS_VERSION));
122
140
  /**
123
141
  * The `RNSTabsScreen` this tab is. The outlet creates the activated route's component inside
124
142
  * it, which is why it is public: a tab is a slot as well as a bar item.
@@ -199,7 +217,8 @@ export class NativeTab {
199
217
  // selected icon and none.
200
218
  const undrawn = isSvg(this.icon()) && this.drawnIcon() === undefined;
201
219
  const selected = undrawn ? {} : this.iconProps(this.selectedIcon(), this.drawnSelectedIcon());
202
- return tabIconProps(icon, selected);
220
+ const icons = tabIconProps(icon, selected);
221
+ return this.readsRenderingModes ? withRenderingModes(icons) : icons;
203
222
  }, /* @ts-ignore */
204
223
  ...(ngDevMode ? [{ debugName: "icons" }] : /* istanbul ignore next */ []));
205
224
  /**
@@ -302,7 +321,7 @@ export class NativeTab {
302
321
  };
303
322
  }
304
323
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: NativeTab, deps: [], target: i0.ɵɵFactoryTarget.Component });
305
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.2.0", type: NativeTab, isStandalone: true, selector: "native-tab", inputs: { path: { classPropertyName: "path", publicName: "path", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, sfSymbol: { classPropertyName: "sfSymbol", publicName: "sfSymbol", isSignal: true, isRequired: false, transformFunction: null }, drawable: { classPropertyName: "drawable", publicName: "drawable", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, selectedIcon: { classPropertyName: "selectedIcon", publicName: "selectedIcon", isSignal: true, isRequired: false, transformFunction: null }, systemItem: { classPropertyName: "systemItem", publicName: "systemItem", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null }, automaticallyActivatesSearch: { classPropertyName: "automaticallyActivatesSearch", publicName: "automaticallyActivatesSearch", isSignal: true, isRequired: false, transformFunction: null }, badge: { classPropertyName: "badge", publicName: "badge", isSignal: true, isRequired: false, transformFunction: null }, accessibilityLabel: { classPropertyName: "accessibilityLabel", publicName: "accessibilityLabel", isSignal: true, isRequired: false, transformFunction: null }, standardAppearance: { classPropertyName: "standardAppearance", publicName: "standardAppearance", isSignal: true, isRequired: false, transformFunction: null }, scrollEdgeAppearance: { classPropertyName: "scrollEdgeAppearance", publicName: "scrollEdgeAppearance", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "screenKey": "screenKey()", "title": "title()", "badgeValue": "badge()", "tabBarItemAccessibilityLabel": "accessibilityLabel()", "systemItem": "systemItem()", "tabRole": "role()", "automaticallyActivatesSearch": "automaticallyActivatesSearch()", "isTitleUndefined": "title() === undefined", "iconType": "icons().iconType", "iconResourceName": "icons().iconResourceName", "iconImageSource": "icons().iconImageSource", "selectedIconResourceName": "icons().selectedIconResourceName", "selectedIconImageSource": "icons().selectedIconImageSource", "drawableIconResourceName": "icons().drawableIconResourceName", "imageIconResource": "icons().imageIconResource", "selectedDrawableIconResourceName": "icons().selectedDrawableIconResourceName", "selectedImageIconResource": "icons().selectedImageIconResource", "standardAppearance": "standard()", "scrollEdgeAppearance": "scrollEdge()" } }, ngImport: i0, template: '', isInline: true });
324
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.2.0", type: NativeTab, isStandalone: true, selector: "native-tab", inputs: { path: { classPropertyName: "path", publicName: "path", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, sfSymbol: { classPropertyName: "sfSymbol", publicName: "sfSymbol", isSignal: true, isRequired: false, transformFunction: null }, drawable: { classPropertyName: "drawable", publicName: "drawable", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, selectedIcon: { classPropertyName: "selectedIcon", publicName: "selectedIcon", isSignal: true, isRequired: false, transformFunction: null }, systemItem: { classPropertyName: "systemItem", publicName: "systemItem", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null }, automaticallyActivatesSearch: { classPropertyName: "automaticallyActivatesSearch", publicName: "automaticallyActivatesSearch", isSignal: true, isRequired: false, transformFunction: null }, badge: { classPropertyName: "badge", publicName: "badge", isSignal: true, isRequired: false, transformFunction: null }, accessibilityLabel: { classPropertyName: "accessibilityLabel", publicName: "accessibilityLabel", isSignal: true, isRequired: false, transformFunction: null }, standardAppearance: { classPropertyName: "standardAppearance", publicName: "standardAppearance", isSignal: true, isRequired: false, transformFunction: null }, scrollEdgeAppearance: { classPropertyName: "scrollEdgeAppearance", publicName: "scrollEdgeAppearance", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "screenKey": "screenKey()", "title": "title()", "badgeValue": "badge()", "tabBarItemAccessibilityLabel": "accessibilityLabel()", "systemItem": "systemItem()", "tabRole": "role()", "automaticallyActivatesSearch": "automaticallyActivatesSearch()", "isTitleUndefined": "title() === undefined", "iconType": "icons().iconType", "iconImageRenderingMode": "icons().iconImageRenderingMode", "selectedIconImageRenderingMode": "icons().selectedIconImageRenderingMode", "iconResourceName": "icons().iconResourceName", "iconImageSource": "icons().iconImageSource", "selectedIconResourceName": "icons().selectedIconResourceName", "selectedIconImageSource": "icons().selectedIconImageSource", "drawableIconResourceName": "icons().drawableIconResourceName", "imageIconResource": "icons().imageIconResource", "selectedDrawableIconResourceName": "icons().selectedDrawableIconResourceName", "selectedImageIconResource": "icons().selectedImageIconResource", "standardAppearance": "standard()", "scrollEdgeAppearance": "scrollEdge()" } }, ngImport: i0, template: '', isInline: true });
306
325
  }
307
326
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: NativeTab, decorators: [{
308
327
  type: Component,
@@ -322,6 +341,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
322
341
  // an icon with a gap where the label belongs.
323
342
  '[isTitleUndefined]': 'title() === undefined',
324
343
  '[iconType]': 'icons().iconType',
344
+ '[iconImageRenderingMode]': 'icons().iconImageRenderingMode',
345
+ '[selectedIconImageRenderingMode]': 'icons().selectedIconImageRenderingMode',
325
346
  '[iconResourceName]': 'icons().iconResourceName',
326
347
  '[iconImageSource]': 'icons().iconImageSource',
327
348
  '[selectedIconResourceName]': 'icons().selectedIconResourceName',
@@ -1 +1 @@
1
- {"version":3,"file":"native-tab.js","sourceRoot":"","sources":["../src/native-tab.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * One item in a native tab bar, and the screen behind it.\n *\n * Declared in the tabs outlet's template, the way a `<native-header>` is declared in a page's:\n *\n * ```html\n * <native-tabs-outlet>\n * <native-tab path=\"library\" title=\"Library\" sfSymbol=\"books.vertical.fill\" />\n * <native-tab path=\"inbox\" title=\"Inbox\" sfSymbol=\"tray\" [badge]=\"unread()\" />\n * </native-tabs-outlet>\n * ```\n *\n * `path` names the child route this tab selects, the same way a `routerLink` names one, and is\n * what native identifies the tab by. Everything else is an ordinary input, which is the point of\n * declaring tabs here rather than in the route config: a badge is a count that changes, a title\n * may be translated, and a tab may not exist at all until a feature flag says so. Route data\n * cannot bind to any of that.\n *\n * **A bar item is not a view.** `UITabBarItem` is a model object - a title, an image and a badge\n * string - and UIKit has no way to put a view in its place; Android's bottom-navigation item is\n * the same. That is why this takes no content, while `<native-header-item>` does: a navigation\n * bar really does hold subviews. What customisation exists is here as inputs: images instead of\n * symbols, a different icon when selected, and the per-state appearance below.\n *\n * The host element *is* the `RNSTabsScreen`. The outlet keeps the screen mounted and creates\n * each activated route's component on a child view, so destroying a route cannot remove this\n * tab item from the bar.\n */\nimport {\n Component,\n ElementRef,\n ErrorHandler,\n computed,\n effect,\n inject,\n input,\n signal,\n type OnInit,\n type Signal,\n} from '@angular/core';\nimport { nativePlatform, type EngineNode, HostEngine } from '@ng-native/fabric';\nimport { NATIVE_TAB_DEFAULTS } from './native-bar-defaults.ts';\nimport { ownHost } from './own-host.ts';\nimport { optionalBoolean } from './transforms.ts';\nimport { SVG_ICON_HOST, SVG_ICON_RENDERER } from './svg-icons.ts';\n\n/**\n * Where a tab's picture comes from.\n *\n * `template` is the one worth knowing about: the image is drawn as a mask and tinted to the bar's\n * colour, so it follows selection the way a symbol does. `image` renders as authored, which is\n * what a multi-colour logo wants and what a monochrome icon almost never does.\n */\nexport type TabIcon =\n | { readonly sfSymbol: string }\n /** An image in the iOS asset catalogue, by name. */\n | { readonly xcasset: string }\n /** A `require()`d asset or a `{ uri }`, drawn as authored. */\n | { readonly image: unknown }\n /** The same, drawn as a mask and tinted. */\n | { readonly template: unknown }\n /** Android: a drawable resource name. */\n | { readonly drawable: string }\n /**\n * SVG markup, such as an `@ng-icons` icon, drawn as a mask and tinted like `template`. Native\n * cannot draw SVG, so it is drawn once by the renderer `withSvgIcons` provides, `size` points\n * square: 25 on iOS and 24 on Android unless it says. The tab has no icon until it has been.\n */\n | { readonly svg: string; readonly size?: number };\n\n/** One of Apple's standard items, which brings its own icon and title. */\nexport type TabSystemItem =\n | 'none'\n | 'bookmarks'\n | 'contacts'\n | 'downloads'\n | 'favorites'\n | 'featured'\n | 'history'\n | 'more'\n | 'mostRecent'\n | 'mostViewed'\n | 'recents'\n | 'search'\n | 'topRated';\n\n/**\n * iOS: what a tab is for, beyond its bar item. `search` makes it a `UISearchTab`, which iOS 26\n * draws apart from the others: a circular button at the trailing end of the bar.\n */\nexport type TabRole = 'none' | 'search';\n\nexport type TabBarBlurEffect =\n | 'none'\n | 'systemDefault'\n | 'extraLight'\n | 'light'\n | 'dark'\n | 'regular'\n | 'prominent'\n | 'systemUltraThinMaterial'\n | 'systemThinMaterial'\n | 'systemMaterial'\n | 'systemThickMaterial'\n | 'systemChromeMaterial';\n\n/**\n * How an item looks in one state. The names are the native ones, spelled as the codegen spec\n * spells them, so this forwards rather than translates and Apple's own documentation still reads\n * across.\n */\nexport interface TabStateAppearance {\n tabBarItemTitleFontFamily?: string;\n tabBarItemTitleFontSize?: number;\n tabBarItemTitleFontWeight?: string | number;\n tabBarItemTitleFontStyle?: string;\n tabBarItemTitleFontColor?: string | number;\n tabBarItemTitlePositionAdjustment?: { horizontal?: number; vertical?: number };\n tabBarItemIconColor?: string | number;\n tabBarItemBadgeBackgroundColor?: string | number;\n}\n\n/** The four states an item can be in. Anything absent falls back to the platform's own. */\nexport interface TabItemAppearance {\n normal?: TabStateAppearance;\n selected?: TabStateAppearance;\n focused?: TabStateAppearance;\n disabled?: TabStateAppearance;\n}\n\n/**\n * How the bar looks, per layout. `stacked` is the usual icon-over-title item; `inline` and\n * `compactInline` are the side-by-side layouts iPad and a compact height use.\n */\nexport interface TabAppearance {\n stacked?: TabItemAppearance;\n inline?: TabItemAppearance;\n compactInline?: TabItemAppearance;\n tabBarBackgroundColor?: string | number;\n tabBarShadowColor?: string | number;\n tabBarBlurEffect?: TabBarBlurEffect;\n}\n\n/** One icon, as the props native reads it through. */\nexport interface TabIconProps {\n iconType?: string;\n iconResourceName?: string;\n iconImageSource?: unknown;\n drawableIconResourceName?: string;\n imageIconResource?: unknown;\n}\n\n/**\n * An icon and its selected counterpart, as one set of props.\n *\n * Native carries a single `iconType` for both states, so the two have to be the same kind of\n * thing: a template image cannot become a symbol when selected. React Native Screens throws on\n * that pairing and so does this, because the alternative - what happened before this checked - is\n * that native quietly keeps the unselected icon and nothing anywhere says why.\n */\nexport function tabIconProps(\n icon: TabIconProps,\n selectedIcon: TabIconProps,\n): TabIconProps & {\n selectedIconResourceName?: string;\n selectedIconImageSource?: unknown;\n selectedDrawableIconResourceName?: string;\n selectedImageIconResource?: unknown;\n} {\n const hasBase = icon.iconType !== undefined || icon.drawableIconResourceName !== undefined;\n const hasSelected =\n selectedIcon.iconType !== undefined || selectedIcon.drawableIconResourceName !== undefined;\n\n if (hasSelected && !hasBase) {\n throw new Error('[angular-native] <native-tab> has a selectedIcon but no icon to select from');\n }\n if (hasSelected && icon.iconType !== selectedIcon.iconType) {\n throw new Error(\n `[angular-native] <native-tab> icon and selectedIcon must be the same kind: native has ` +\n `one iconType for both, so '${icon.iconType}' and '${selectedIcon.iconType}' cannot pair.`,\n );\n }\n\n return {\n ...icon,\n selectedIconResourceName: selectedIcon.iconResourceName,\n selectedIconImageSource: selectedIcon.iconImageSource,\n selectedDrawableIconResourceName: selectedIcon.drawableIconResourceName,\n selectedImageIconResource: selectedIcon.imageIconResource,\n };\n}\n\ndeclare const ngDevMode: unknown;\n\nfunction isSvg(icon: TabIcon | undefined): icon is Extract<TabIcon, { svg: string }> {\n return icon !== undefined && 'svg' in icon;\n}\n\n/** The paths already warned about, so a tab bar rebuilt by a navigation says it once. */\nconst warnedTabs = new Set<string>();\n\n/**\n * Says, once per path and in development only, that a tab has no icon on the platform running it\n * because it names only the other platform's shorthand. A tab written against the iOS simulator\n * with `sfSymbol` shows a title and nothing above it on Android.\n */\nfunction warnIfIconOnOnePlatform(tab: NativeTab): void {\n if (typeof ngDevMode !== 'undefined' && !ngDevMode) return;\n if (tab.icon() || tab.systemItem()) return;\n const [own, other, missing, platform] =\n nativePlatform() === 'android'\n ? [tab.drawable(), tab.sfSymbol(), 'drawable', 'Android']\n : nativePlatform() === 'ios'\n ? [tab.sfSymbol(), tab.drawable(), 'sfSymbol', 'iOS']\n : [];\n if (own || !other) return;\n const path = tab.path();\n if (warnedTabs.has(path)) return;\n warnedTabs.add(path);\n console.warn(\n `[angular-native] <native-tab path=\"${path}\"> has no icon on ${platform}: ${platform} reads ` +\n `only ${missing}. Add ${missing}=\"...\", or bind [icon] for a tab meant for one platform.`,\n );\n}\n\n/**\n * Says, once per path and in development only, that a tab's icon is SVG and the app gave nothing\n * to draw it, so the tab shows no icon.\n */\nfunction warnNoSvgRenderer(path: string): void {\n if (typeof ngDevMode !== 'undefined' && !ngDevMode) return;\n if (warnedTabs.has(`svg:${path}`)) return;\n warnedTabs.add(`svg:${path}`);\n console.warn(\n `[angular-native] <native-tab path=\"${path}\"> has an SVG icon and nothing to draw it, so it ` +\n `shows none. Add withSvgIcons(SvgImages) from @ng-native/icons to provideNativeRouter.`,\n );\n}\n\n/** A tab bar icon's size in points when an SVG icon gives none, as each platform draws one. */\nfunction svgIconSize(): number {\n return nativePlatform() === 'android' ? 24 : 25;\n}\n\n/**\n * The key native identifies a tab by: its path, or `/` for the tab at path `''`, since iOS reads an\n * empty key as none and fails on the tap that selects it. No route path starts with `/`.\n */\nexport function screenKeyOf(path: string): string {\n return path || '/';\n}\n\n@Component({\n selector: 'native-tab',\n template: '',\n host: {\n '[screenKey]': 'screenKey()',\n '[title]': 'title()',\n '[badgeValue]': 'badge()',\n '[tabBarItemAccessibilityLabel]': 'accessibilityLabel()',\n '[systemItem]': 'systemItem()',\n '[tabRole]': 'role()',\n '[automaticallyActivatesSearch]': 'automaticallyActivatesSearch()',\n // `isTitleUndefined` is what `TabsScreen.ios.tsx` derives from the title, and it is not a\n // synonym for \"no title\": with a title set and this left at its default, the item renders as\n // an icon with a gap where the label belongs.\n '[isTitleUndefined]': 'title() === undefined',\n '[iconType]': 'icons().iconType',\n '[iconResourceName]': 'icons().iconResourceName',\n '[iconImageSource]': 'icons().iconImageSource',\n '[selectedIconResourceName]': 'icons().selectedIconResourceName',\n '[selectedIconImageSource]': 'icons().selectedIconImageSource',\n '[drawableIconResourceName]': 'icons().drawableIconResourceName',\n '[imageIconResource]': 'icons().imageIconResource',\n '[selectedDrawableIconResourceName]': 'icons().selectedDrawableIconResourceName',\n '[selectedImageIconResource]': 'icons().selectedImageIconResource',\n '[standardAppearance]': 'standard()',\n '[scrollEdgeAppearance]': 'scrollEdge()',\n },\n})\nexport class NativeTab implements OnInit {\n private readonly engine = inject(HostEngine);\n /** The app's `withTabDefaults`, for an appearance this tab does not bind itself. */\n private readonly defaults = inject(NATIVE_TAB_DEFAULTS);\n private readonly svgRenderer = inject(SVG_ICON_RENDERER);\n private readonly svgHost = inject(SVG_ICON_HOST, { optional: true });\n private readonly errors = inject(ErrorHandler);\n\n /**\n * The `RNSTabsScreen` this tab is. The outlet creates the activated route's component inside\n * it, which is why it is public: a tab is a slot as well as a bar item.\n */\n readonly screen: EngineNode;\n\n constructor() {\n this.screen = ownHost(inject(ElementRef).nativeElement as EngineNode, this.constructor);\n }\n\n /**\n * The child route this tab selects, as a path segment: `library` for `/tabs/library`. Native\n * identifies the tab by it too, so it must be unique in the bar.\n */\n readonly path = input.required<string>();\n\n protected readonly screenKey = computed(() => screenKeyOf(this.path()));\n\n /** The label under the icon. Absent gives an icon-only item. */\n readonly title = input<string>();\n\n /** iOS: an SF Symbol name, e.g. `books.vertical.fill`. Shorthand for `[icon]`. */\n readonly sfSymbol = input<string>();\n\n /** Android: a drawable resource name. Shorthand for `[icon]`. */\n readonly drawable = input<string>();\n\n /** Anything a symbol name cannot say: an image, a template image, an asset-catalogue name. */\n readonly icon = input<TabIcon>();\n\n /** Shown while this tab is the selected one. Absent leaves the platform to tint `icon`. */\n readonly selectedIcon = input<TabIcon>();\n\n /** One of Apple's standard items, which supplies its own icon and title. */\n readonly systemItem = input<TabSystemItem>();\n\n /**\n * iOS 26.1 and later: `search` makes this the bar's search tab, a `UISearchTab`, set apart at the\n * trailing end. Needs react-native-screens 4.29 or later; an older one ignores it.\n *\n * Native reads it once, when the tab is created, and asserts in a debug build if it changes\n * afterwards, so bind a value that does not. A bar has at most one search tab. Built with the\n * iOS 26 SDK, as Expo Go is, `systemItem=\"search\"` already gets the detached button; an app\n * built with the iOS 27 SDK needs this, and on iOS 27 `automaticallyActivatesSearch` as well.\n */\n readonly role = input<TabRole>();\n\n /**\n * iOS 26.1 and later, for a `role=\"search\"` tab: selecting the tab focuses the search field of\n * the `<native-search-bar>` in the header of the stack inside it, which that stack has to have.\n * On iOS 27 the tab is detached only while this is on, and the tab's first visit does not focus\n * the field. Expo Go's react-native-screens is older and ignores it.\n */\n readonly automaticallyActivatesSearch = input(undefined, { transform: optionalBoolean });\n\n /** The badge on the item: a count, or a single character for a dot. */\n readonly badge = input<string>();\n\n /** Announced instead of the title. */\n readonly accessibilityLabel = input<string>();\n\n /** How the item looks. Colours are processed here, because native never sees the object's keys. */\n readonly standardAppearance = input<TabAppearance>();\n\n /** The same, for when the scroll view behind the bar is at its edge. */\n readonly scrollEdgeAppearance = input<TabAppearance>();\n\n ngOnInit(): void {\n warnIfIconOnOnePlatform(this);\n }\n\n protected readonly standard = computed(() =>\n this.processAppearance(this.standardAppearance() ?? this.defaults().standardAppearance),\n );\n protected readonly scrollEdge = computed(() =>\n this.processAppearance(this.scrollEdgeAppearance() ?? this.defaults().scrollEdgeAppearance),\n );\n\n /** `icon` and `selectedIcon` as drawn, when they are SVG. */\n private readonly drawnIcon = this.drawn(this.icon);\n private readonly drawnSelectedIcon = this.drawn(this.selectedIcon);\n\n protected readonly icons = computed(() => {\n const icon = this.iconProps(this.icon() ?? this.shorthand(), this.drawnIcon());\n // A selected icon drawn before the icon it replaces waits for it: native takes no pair of a\n // selected icon and none.\n const undrawn = isSvg(this.icon()) && this.drawnIcon() === undefined;\n const selected = undrawn ? {} : this.iconProps(this.selectedIcon(), this.drawnSelectedIcon());\n return tabIconProps(icon, selected);\n });\n\n /**\n * An SVG icon as the renderer drew it, undefined until it has. Markup that changes is drawn\n * again, and a drawing that finishes after newer markup arrived is dropped.\n */\n private drawn(icon: Signal<TabIcon | undefined>): Signal<unknown> {\n const markup = computed(\n () => {\n const svg = icon();\n return isSvg(svg) ? { svg: svg.svg, size: svg.size ?? svgIconSize() } : undefined;\n },\n { equal: (a, b) => a?.svg === b?.svg && a?.size === b?.size },\n );\n const drawn = signal<unknown>(undefined);\n effect((onCleanup) => {\n const wanted = markup();\n drawn.set(undefined);\n if (!wanted || !this.svgHost) return;\n if (!this.svgRenderer) return warnNoSvgRenderer(this.path());\n let current = true;\n onCleanup(() => (current = false));\n this.svgRenderer.render(wanted.svg, wanted.size, this.svgHost).then(\n (source) => current && drawn.set(source ?? undefined),\n (error: unknown) => this.errors.handleError(error),\n );\n });\n return drawn;\n }\n\n /**\n * `sfSymbol` and `drawable` say the same thing as `icon`, in the form most tabs want. A tab\n * names both to have an icon on both platforms, so the running platform's own comes first:\n * Android reads only a drawable, and iOS only a symbol.\n */\n private shorthand(): TabIcon | undefined {\n const symbol = this.sfSymbol();\n const drawable = this.drawable();\n const icons = [symbol && { sfSymbol: symbol }, drawable && { drawable }];\n if (nativePlatform() === 'android') icons.reverse();\n return icons.find((icon) => icon) || undefined;\n }\n\n /**\n * One icon, as the four props native reads it through. A `require()`d asset is an id until the\n * host resolves it, which is the same thing an `<image src>` needs and the engine only does for\n * props it knows by name.\n */\n private iconProps(icon: TabIcon | undefined, drawn: unknown): TabIconProps {\n if (!icon) return {};\n if ('sfSymbol' in icon) return { iconType: 'sfSymbol', iconResourceName: icon.sfSymbol };\n if ('xcasset' in icon) return { iconType: 'xcasset', iconResourceName: icon.xcasset };\n if ('drawable' in icon) return { drawableIconResourceName: icon.drawable };\n if ('svg' in icon) {\n if (drawn === undefined) return {};\n return nativePlatform() === 'android'\n ? { imageIconResource: drawn }\n : { iconType: 'template', iconImageSource: drawn };\n }\n\n const source = this.engine.resolveAsset('image' in icon ? icon.image : icon.template);\n return nativePlatform() === 'android'\n ? { imageIconResource: source }\n : { iconType: 'image' in icon ? 'image' : 'template', iconImageSource: source };\n }\n\n private processAppearance(appearance: TabAppearance | undefined): object | undefined {\n if (!appearance) return undefined;\n return {\n ...appearance,\n stacked: this.processItem(appearance.stacked),\n inline: this.processItem(appearance.inline),\n compactInline: this.processItem(appearance.compactInline),\n tabBarBackgroundColor: this.engine.color(appearance.tabBarBackgroundColor),\n tabBarShadowColor: this.engine.color(appearance.tabBarShadowColor),\n };\n }\n\n private processItem(item: TabItemAppearance | undefined): object | undefined {\n if (!item) return undefined;\n return {\n normal: this.processState(item.normal),\n selected: this.processState(item.selected),\n focused: this.processState(item.focused),\n disabled: this.processState(item.disabled),\n };\n }\n\n private processState(state: TabStateAppearance | undefined): object | undefined {\n if (!state) return undefined;\n return {\n ...state,\n // Native declares the weight as a string, and `600` is the natural way to write one.\n tabBarItemTitleFontWeight:\n state.tabBarItemTitleFontWeight === undefined\n ? undefined\n : String(state.tabBarItemTitleFontWeight),\n tabBarItemTitleFontColor: this.engine.color(state.tabBarItemTitleFontColor),\n tabBarItemIconColor: this.engine.color(state.tabBarItemIconColor),\n tabBarItemBadgeBackgroundColor: this.engine.color(state.tabBarItemBadgeBackgroundColor),\n };\n }\n}\n"]}
1
+ {"version":3,"file":"native-tab.js","sourceRoot":"","sources":["../src/native-tab.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * One item in a native tab bar, and the screen behind it.\n *\n * Declared in the tabs outlet's template, the way a `<native-header>` is declared in a page's:\n *\n * ```html\n * <native-tabs-outlet>\n * <native-tab path=\"library\" title=\"Library\" sfSymbol=\"books.vertical.fill\" />\n * <native-tab path=\"inbox\" title=\"Inbox\" sfSymbol=\"tray\" [badge]=\"unread()\" />\n * </native-tabs-outlet>\n * ```\n *\n * `path` names the child route this tab selects, the same way a `routerLink` names one, and is\n * what native identifies the tab by. Everything else is an ordinary input, which is the point of\n * declaring tabs here rather than in the route config: a badge is a count that changes, a title\n * may be translated, and a tab may not exist at all until a feature flag says so. Route data\n * cannot bind to any of that.\n *\n * **A bar item is not a view.** `UITabBarItem` is a model object - a title, an image and a badge\n * string - and UIKit has no way to put a view in its place; Android's bottom-navigation item is\n * the same. That is why this takes no content, while `<native-header-item>` does: a navigation\n * bar really does hold subviews. What customisation exists is here as inputs: images instead of\n * symbols, a different icon when selected, and the per-state appearance below.\n *\n * The host element *is* the `RNSTabsScreen`. The outlet keeps the screen mounted and creates\n * each activated route's component on a child view, so destroying a route cannot remove this\n * tab item from the bar.\n */\nimport {\n Component,\n ElementRef,\n ErrorHandler,\n computed,\n effect,\n inject,\n input,\n signal,\n type OnInit,\n type Signal,\n} from '@angular/core';\nimport { nativePlatform, type EngineNode, HostEngine } from '@ng-native/fabric';\nimport { NATIVE_TAB_DEFAULTS } from './native-bar-defaults.ts';\nimport { ownHost } from './own-host.ts';\nimport { optionalBoolean } from './transforms.ts';\nimport { SVG_ICON_HOST, SVG_ICON_RENDERER } from './svg-icons.ts';\nimport { SCREENS_VERSION, screensReadsRenderingModes } from './screens-version.ts';\n\n/**\n * Where a tab's picture comes from.\n *\n * `template` is the one worth knowing about: the image is drawn as a mask and tinted to the bar's\n * colour, so it follows selection the way a symbol does. `image` renders as authored, which is\n * what a multi-colour logo wants and what a monochrome icon almost never does.\n */\nexport type TabIcon =\n | { readonly sfSymbol: string }\n /** An image in the iOS asset catalogue, by name. */\n | { readonly xcasset: string }\n /** A `require()`d asset or a `{ uri }`, drawn as authored. */\n | { readonly image: unknown }\n /** The same, drawn as a mask and tinted. */\n | { readonly template: unknown }\n /** Android: a drawable resource name. */\n | { readonly drawable: string }\n /**\n * SVG markup, such as an `@ng-icons` icon, drawn as a mask and tinted like `template`. Native\n * cannot draw SVG, so it is drawn once by the renderer `withSvgIcons` provides, `size` points\n * square: 25 on iOS and 24 on Android unless it says. The tab has no icon until it has been.\n */\n | { readonly svg: string; readonly size?: number };\n\n/** One of Apple's standard items, which brings its own icon and title. */\nexport type TabSystemItem =\n | 'none'\n | 'bookmarks'\n | 'contacts'\n | 'downloads'\n | 'favorites'\n | 'featured'\n | 'history'\n | 'more'\n | 'mostRecent'\n | 'mostViewed'\n | 'recents'\n | 'search'\n | 'topRated';\n\n/**\n * iOS: what a tab is for, beyond its bar item. `search` makes it a `UISearchTab`, which iOS 26\n * draws apart from the others: a circular button at the trailing end of the bar.\n */\nexport type TabRole = 'none' | 'search';\n\nexport type TabBarBlurEffect =\n | 'none'\n | 'systemDefault'\n | 'extraLight'\n | 'light'\n | 'dark'\n | 'regular'\n | 'prominent'\n | 'systemUltraThinMaterial'\n | 'systemThinMaterial'\n | 'systemMaterial'\n | 'systemThickMaterial'\n | 'systemChromeMaterial';\n\n/**\n * How an item looks in one state. The names are the native ones, spelled as the codegen spec\n * spells them, so this forwards rather than translates and Apple's own documentation still reads\n * across.\n */\nexport interface TabStateAppearance {\n tabBarItemTitleFontFamily?: string;\n tabBarItemTitleFontSize?: number;\n tabBarItemTitleFontWeight?: string | number;\n tabBarItemTitleFontStyle?: string;\n tabBarItemTitleFontColor?: string | number;\n tabBarItemTitlePositionAdjustment?: { horizontal?: number; vertical?: number };\n tabBarItemIconColor?: string | number;\n tabBarItemBadgeBackgroundColor?: string | number;\n}\n\n/** The four states an item can be in. Anything absent falls back to the platform's own. */\nexport interface TabItemAppearance {\n normal?: TabStateAppearance;\n selected?: TabStateAppearance;\n focused?: TabStateAppearance;\n disabled?: TabStateAppearance;\n}\n\n/**\n * How the bar looks, per layout. `stacked` is the usual icon-over-title item; `inline` and\n * `compactInline` are the side-by-side layouts iPad and a compact height use.\n */\nexport interface TabAppearance {\n stacked?: TabItemAppearance;\n inline?: TabItemAppearance;\n compactInline?: TabItemAppearance;\n tabBarBackgroundColor?: string | number;\n tabBarShadowColor?: string | number;\n tabBarBlurEffect?: TabBarBlurEffect;\n}\n\n/** One icon, as the props native reads it through. */\nexport interface TabIconProps {\n iconType?: string;\n iconResourceName?: string;\n iconImageSource?: unknown;\n drawableIconResourceName?: string;\n imageIconResource?: unknown;\n}\n\n/**\n * An icon and its selected counterpart, as one set of props.\n *\n * Native carries a single `iconType` for both states, so the two have to be the same kind of\n * thing: a template image cannot become a symbol when selected. React Native Screens throws on\n * that pairing and so does this, because the alternative - what happened before this checked - is\n * that native quietly keeps the unselected icon and nothing anywhere says why.\n */\nexport function tabIconProps(\n icon: TabIconProps,\n selectedIcon: TabIconProps,\n): TabIconProps & {\n selectedIconResourceName?: string;\n selectedIconImageSource?: unknown;\n selectedDrawableIconResourceName?: string;\n selectedImageIconResource?: unknown;\n} {\n const hasBase = icon.iconType !== undefined || icon.drawableIconResourceName !== undefined;\n const hasSelected =\n selectedIcon.iconType !== undefined || selectedIcon.drawableIconResourceName !== undefined;\n\n if (hasSelected && !hasBase) {\n throw new Error('[angular-native] <native-tab> has a selectedIcon but no icon to select from');\n }\n if (hasSelected && icon.iconType !== selectedIcon.iconType) {\n throw new Error(\n `[angular-native] <native-tab> icon and selectedIcon must be the same kind: native has ` +\n `one iconType for both, so '${icon.iconType}' and '${selectedIcon.iconType}' cannot pair.`,\n );\n }\n\n return {\n ...icon,\n selectedIconResourceName: selectedIcon.iconResourceName,\n selectedIconImageSource: selectedIcon.iconImageSource,\n selectedDrawableIconResourceName: selectedIcon.drawableIconResourceName,\n selectedImageIconResource: selectedIcon.imageIconResource,\n };\n}\n\n/** Every icon prop a tab commits. */\ntype TabIconSet = ReturnType<typeof tabIconProps> & {\n iconImageRenderingMode?: string;\n selectedIconImageRenderingMode?: string;\n};\n\n/**\n * iOS: a template icon in the form react-native-screens 4.29 and later read, an `image` with a\n * `template` rendering mode per state. Those releases dropped `iconType: 'template'`, and native\n * aborts the app on an `iconType` it does not know, so the older form cannot be sent to them. A\n * selected icon is a template too, since `tabIconProps` pairs only icons of one kind.\n */\nfunction withRenderingModes(icons: TabIconSet): TabIconSet {\n if (icons.iconType !== 'template') return icons;\n return {\n ...icons,\n iconType: 'image',\n iconImageRenderingMode: 'template',\n selectedIconImageRenderingMode: 'template',\n };\n}\n\ndeclare const ngDevMode: unknown;\n\nfunction isSvg(icon: TabIcon | undefined): icon is Extract<TabIcon, { svg: string }> {\n return icon !== undefined && 'svg' in icon;\n}\n\n/** The paths already warned about, so a tab bar rebuilt by a navigation says it once. */\nconst warnedTabs = new Set<string>();\n\n/**\n * Says, once per path and in development only, that a tab has no icon on the platform running it\n * because it names only the other platform's shorthand. A tab written against the iOS simulator\n * with `sfSymbol` shows a title and nothing above it on Android.\n */\nfunction warnIfIconOnOnePlatform(tab: NativeTab): void {\n if (typeof ngDevMode !== 'undefined' && !ngDevMode) return;\n if (tab.icon() || tab.systemItem()) return;\n const [own, other, missing, platform] =\n nativePlatform() === 'android'\n ? [tab.drawable(), tab.sfSymbol(), 'drawable', 'Android']\n : nativePlatform() === 'ios'\n ? [tab.sfSymbol(), tab.drawable(), 'sfSymbol', 'iOS']\n : [];\n if (own || !other) return;\n const path = tab.path();\n if (warnedTabs.has(path)) return;\n warnedTabs.add(path);\n console.warn(\n `[angular-native] <native-tab path=\"${path}\"> has no icon on ${platform}: ${platform} reads ` +\n `only ${missing}. Add ${missing}=\"...\", or bind [icon] for a tab meant for one platform.`,\n );\n}\n\n/**\n * Says, once per path and in development only, that a tab's icon is SVG and the app gave nothing\n * to draw it, so the tab shows no icon.\n */\nfunction warnNoSvgRenderer(path: string): void {\n if (typeof ngDevMode !== 'undefined' && !ngDevMode) return;\n if (warnedTabs.has(`svg:${path}`)) return;\n warnedTabs.add(`svg:${path}`);\n console.warn(\n `[angular-native] <native-tab path=\"${path}\"> has an SVG icon and nothing to draw it, so it ` +\n `shows none. Add withSvgIcons(SvgImages) from @ng-native/icons to provideNativeRouter.`,\n );\n}\n\n/** A tab bar icon's size in points when an SVG icon gives none, as each platform draws one. */\nfunction svgIconSize(): number {\n return nativePlatform() === 'android' ? 24 : 25;\n}\n\n/**\n * The key native identifies a tab by: its path, or `/` for the tab at path `''`, since iOS reads an\n * empty key as none and fails on the tap that selects it. No route path starts with `/`.\n */\nexport function screenKeyOf(path: string): string {\n return path || '/';\n}\n\n@Component({\n selector: 'native-tab',\n template: '',\n host: {\n '[screenKey]': 'screenKey()',\n '[title]': 'title()',\n '[badgeValue]': 'badge()',\n '[tabBarItemAccessibilityLabel]': 'accessibilityLabel()',\n '[systemItem]': 'systemItem()',\n '[tabRole]': 'role()',\n '[automaticallyActivatesSearch]': 'automaticallyActivatesSearch()',\n // `isTitleUndefined` is what `TabsScreen.ios.tsx` derives from the title, and it is not a\n // synonym for \"no title\": with a title set and this left at its default, the item renders as\n // an icon with a gap where the label belongs.\n '[isTitleUndefined]': 'title() === undefined',\n '[iconType]': 'icons().iconType',\n '[iconImageRenderingMode]': 'icons().iconImageRenderingMode',\n '[selectedIconImageRenderingMode]': 'icons().selectedIconImageRenderingMode',\n '[iconResourceName]': 'icons().iconResourceName',\n '[iconImageSource]': 'icons().iconImageSource',\n '[selectedIconResourceName]': 'icons().selectedIconResourceName',\n '[selectedIconImageSource]': 'icons().selectedIconImageSource',\n '[drawableIconResourceName]': 'icons().drawableIconResourceName',\n '[imageIconResource]': 'icons().imageIconResource',\n '[selectedDrawableIconResourceName]': 'icons().selectedDrawableIconResourceName',\n '[selectedImageIconResource]': 'icons().selectedImageIconResource',\n '[standardAppearance]': 'standard()',\n '[scrollEdgeAppearance]': 'scrollEdge()',\n },\n})\nexport class NativeTab implements OnInit {\n private readonly engine = inject(HostEngine);\n /** The app's `withTabDefaults`, for an appearance this tab does not bind itself. */\n private readonly defaults = inject(NATIVE_TAB_DEFAULTS);\n private readonly svgRenderer = inject(SVG_ICON_RENDERER);\n private readonly svgHost = inject(SVG_ICON_HOST, { optional: true });\n private readonly errors = inject(ErrorHandler);\n private readonly readsRenderingModes = screensReadsRenderingModes(inject(SCREENS_VERSION));\n\n /**\n * The `RNSTabsScreen` this tab is. The outlet creates the activated route's component inside\n * it, which is why it is public: a tab is a slot as well as a bar item.\n */\n readonly screen: EngineNode;\n\n constructor() {\n this.screen = ownHost(inject(ElementRef).nativeElement as EngineNode, this.constructor);\n }\n\n /**\n * The child route this tab selects, as a path segment: `library` for `/tabs/library`. Native\n * identifies the tab by it too, so it must be unique in the bar.\n */\n readonly path = input.required<string>();\n\n protected readonly screenKey = computed(() => screenKeyOf(this.path()));\n\n /** The label under the icon. Absent gives an icon-only item. */\n readonly title = input<string>();\n\n /** iOS: an SF Symbol name, e.g. `books.vertical.fill`. Shorthand for `[icon]`. */\n readonly sfSymbol = input<string>();\n\n /** Android: a drawable resource name. Shorthand for `[icon]`. */\n readonly drawable = input<string>();\n\n /** Anything a symbol name cannot say: an image, a template image, an asset-catalogue name. */\n readonly icon = input<TabIcon>();\n\n /** Shown while this tab is the selected one. Absent leaves the platform to tint `icon`. */\n readonly selectedIcon = input<TabIcon>();\n\n /** One of Apple's standard items, which supplies its own icon and title. */\n readonly systemItem = input<TabSystemItem>();\n\n /**\n * iOS 26.1 and later: `search` makes this the bar's search tab, a `UISearchTab`, set apart at the\n * trailing end. Needs react-native-screens 4.29 or later; an older one ignores it.\n *\n * Native reads it once, when the tab is created, and asserts in a debug build if it changes\n * afterwards, so bind a value that does not. A bar has at most one search tab. Built with the\n * iOS 26 SDK, as Expo Go is, `systemItem=\"search\"` already gets the detached button; an app\n * built with the iOS 27 SDK needs this, and on iOS 27 `automaticallyActivatesSearch` as well.\n */\n readonly role = input<TabRole>();\n\n /**\n * iOS 26.1 and later, for a `role=\"search\"` tab: selecting the tab focuses the search field of\n * the `<native-search-bar>` in the header of the stack inside it, which that stack has to have.\n * On iOS 27 the tab is detached only while this is on, and the tab's first visit does not focus\n * the field. Expo Go's react-native-screens is older and ignores it.\n */\n readonly automaticallyActivatesSearch = input(undefined, { transform: optionalBoolean });\n\n /** The badge on the item: a count, or a single character for a dot. */\n readonly badge = input<string>();\n\n /** Announced instead of the title. */\n readonly accessibilityLabel = input<string>();\n\n /** How the item looks. Colours are processed here, because native never sees the object's keys. */\n readonly standardAppearance = input<TabAppearance>();\n\n /** The same, for when the scroll view behind the bar is at its edge. */\n readonly scrollEdgeAppearance = input<TabAppearance>();\n\n ngOnInit(): void {\n warnIfIconOnOnePlatform(this);\n }\n\n protected readonly standard = computed(() =>\n this.processAppearance(this.standardAppearance() ?? this.defaults().standardAppearance),\n );\n protected readonly scrollEdge = computed(() =>\n this.processAppearance(this.scrollEdgeAppearance() ?? this.defaults().scrollEdgeAppearance),\n );\n\n /** `icon` and `selectedIcon` as drawn, when they are SVG. */\n private readonly drawnIcon = this.drawn(this.icon);\n private readonly drawnSelectedIcon = this.drawn(this.selectedIcon);\n\n protected readonly icons = computed((): TabIconSet => {\n const icon = this.iconProps(this.icon() ?? this.shorthand(), this.drawnIcon());\n // A selected icon drawn before the icon it replaces waits for it: native takes no pair of a\n // selected icon and none.\n const undrawn = isSvg(this.icon()) && this.drawnIcon() === undefined;\n const selected = undrawn ? {} : this.iconProps(this.selectedIcon(), this.drawnSelectedIcon());\n const icons = tabIconProps(icon, selected);\n return this.readsRenderingModes ? withRenderingModes(icons) : icons;\n });\n\n /**\n * An SVG icon as the renderer drew it, undefined until it has. Markup that changes is drawn\n * again, and a drawing that finishes after newer markup arrived is dropped.\n */\n private drawn(icon: Signal<TabIcon | undefined>): Signal<unknown> {\n const markup = computed(\n () => {\n const svg = icon();\n return isSvg(svg) ? { svg: svg.svg, size: svg.size ?? svgIconSize() } : undefined;\n },\n { equal: (a, b) => a?.svg === b?.svg && a?.size === b?.size },\n );\n const drawn = signal<unknown>(undefined);\n effect((onCleanup) => {\n const wanted = markup();\n drawn.set(undefined);\n if (!wanted || !this.svgHost) return;\n if (!this.svgRenderer) return warnNoSvgRenderer(this.path());\n let current = true;\n onCleanup(() => (current = false));\n this.svgRenderer.render(wanted.svg, wanted.size, this.svgHost).then(\n (source) => current && drawn.set(source ?? undefined),\n (error: unknown) => this.errors.handleError(error),\n );\n });\n return drawn;\n }\n\n /**\n * `sfSymbol` and `drawable` say the same thing as `icon`, in the form most tabs want. A tab\n * names both to have an icon on both platforms, so the running platform's own comes first:\n * Android reads only a drawable, and iOS only a symbol.\n */\n private shorthand(): TabIcon | undefined {\n const symbol = this.sfSymbol();\n const drawable = this.drawable();\n const icons = [symbol && { sfSymbol: symbol }, drawable && { drawable }];\n if (nativePlatform() === 'android') icons.reverse();\n return icons.find((icon) => icon) || undefined;\n }\n\n /**\n * One icon, as the four props native reads it through. A `require()`d asset is an id until the\n * host resolves it, which is the same thing an `<image src>` needs and the engine only does for\n * props it knows by name.\n */\n private iconProps(icon: TabIcon | undefined, drawn: unknown): TabIconProps {\n if (!icon) return {};\n if ('sfSymbol' in icon) return { iconType: 'sfSymbol', iconResourceName: icon.sfSymbol };\n if ('xcasset' in icon) return { iconType: 'xcasset', iconResourceName: icon.xcasset };\n if ('drawable' in icon) return { drawableIconResourceName: icon.drawable };\n if ('svg' in icon) {\n if (drawn === undefined) return {};\n return nativePlatform() === 'android'\n ? { imageIconResource: drawn }\n : { iconType: 'template', iconImageSource: drawn };\n }\n\n const source = this.engine.resolveAsset('image' in icon ? icon.image : icon.template);\n return nativePlatform() === 'android'\n ? { imageIconResource: source }\n : { iconType: 'image' in icon ? 'image' : 'template', iconImageSource: source };\n }\n\n private processAppearance(appearance: TabAppearance | undefined): object | undefined {\n if (!appearance) return undefined;\n return {\n ...appearance,\n stacked: this.processItem(appearance.stacked),\n inline: this.processItem(appearance.inline),\n compactInline: this.processItem(appearance.compactInline),\n tabBarBackgroundColor: this.engine.color(appearance.tabBarBackgroundColor),\n tabBarShadowColor: this.engine.color(appearance.tabBarShadowColor),\n };\n }\n\n private processItem(item: TabItemAppearance | undefined): object | undefined {\n if (!item) return undefined;\n return {\n normal: this.processState(item.normal),\n selected: this.processState(item.selected),\n focused: this.processState(item.focused),\n disabled: this.processState(item.disabled),\n };\n }\n\n private processState(state: TabStateAppearance | undefined): object | undefined {\n if (!state) return undefined;\n return {\n ...state,\n // Native declares the weight as a string, and `600` is the natural way to write one.\n tabBarItemTitleFontWeight:\n state.tabBarItemTitleFontWeight === undefined\n ? undefined\n : String(state.tabBarItemTitleFontWeight),\n tabBarItemTitleFontColor: this.engine.color(state.tabBarItemTitleFontColor),\n tabBarItemIconColor: this.engine.color(state.tabBarItemIconColor),\n tabBarItemBadgeBackgroundColor: this.engine.color(state.tabBarItemBadgeBackgroundColor),\n };\n }\n}\n"]}
@@ -25,7 +25,7 @@
25
25
  * was: its scroll offset, its text, and its own stack if it has one. That is the reuse strategy
26
26
  * detaching the tab's whole subtree rather than only its leaf.
27
27
  */
28
- import { type AfterContentInit, type ComponentRef, type EnvironmentInjector } from '@angular/core';
28
+ import { type AfterContentInit, type ComponentRef, type EnvironmentInjector, type Signal } from '@angular/core';
29
29
  import { ActivatedRoute, type Data, type RouterOutletContract } from '@angular/router';
30
30
  import * as i0 from "@angular/core";
31
31
  export declare class NativeTabsOutlet implements RouterOutletContract, AfterContentInit {
@@ -44,7 +44,7 @@ export declare class NativeTabsOutlet implements RouterOutletContract, AfterCont
44
44
  /** What activation has reported already, so the failed navigation it causes is not reported again. */
45
45
  private readonly reported;
46
46
  /** The app's `withTabDefaults`, for whatever the outlet does not bind itself. */
47
- protected readonly defaults: import("@angular/core").Signal<import("./native-bar-defaults.ts").TabDefaults>;
47
+ protected readonly defaults: Signal<import("./native-bar-defaults.ts").TabDefaults>;
48
48
  private readonly declared;
49
49
  private readonly entries;
50
50
  private selected;
@@ -53,8 +53,14 @@ export declare class NativeTabsOutlet implements RouterOutletContract, AfterCont
53
53
  protected readonly fill: {
54
54
  flex: number;
55
55
  };
56
- /** Hide the bar without unmounting the tabs, for a screen that wants the whole window. */
56
+ /**
57
+ * Hide the bar without unmounting the tabs, for a screen that wants the whole window. Unset, the
58
+ * bar is hidden while the page in front of the tab in front has `<native-header tabBarHidden>`.
59
+ */
57
60
  readonly barHidden: import("@angular/core").InputSignalWithTransform<boolean | undefined, unknown>;
61
+ /** What pages have asked of the bar: see `InTab.hideBar`. */
62
+ private readonly barRequests;
63
+ protected readonly hidesBar: Signal<boolean>;
58
64
  /** The colour of the selected item. iOS. */
59
65
  readonly tintColor: import("@angular/core").InputSignal<string | number | undefined>;
60
66
  /** Behind the tabs, where a screen does not paint. */
@@ -85,8 +85,16 @@ export class NativeTabsOutlet {
85
85
  provenance = 0;
86
86
  fill = { flex: 1 };
87
87
  // --- the bar itself -----------------------------------------------------
88
- /** Hide the bar without unmounting the tabs, for a screen that wants the whole window. */
88
+ /**
89
+ * Hide the bar without unmounting the tabs, for a screen that wants the whole window. Unset, the
90
+ * bar is hidden while the page in front of the tab in front has `<native-header tabBarHidden>`.
91
+ */
89
92
  barHidden = input(undefined, { ...(ngDevMode ? { debugName: "barHidden" } : /* istanbul ignore next */ {}), transform: optionalBoolean });
93
+ /** What pages have asked of the bar: see `InTab.hideBar`. */
94
+ barRequests = signal(new Set(), /* @ts-ignore */
95
+ ...(ngDevMode ? [{ debugName: "barRequests" }] : /* istanbul ignore next */ []));
96
+ hidesBar = computed(() => this.barHidden() ?? [...this.barRequests()].some((hidden) => hidden()), /* @ts-ignore */
97
+ ...(ngDevMode ? [{ debugName: "hidesBar" }] : /* istanbul ignore next */ []));
90
98
  /** The colour of the selected item. iOS. */
91
99
  tintColor = input(/* @ts-ignore */
92
100
  ...(ngDevMode ? [undefined, { debugName: "tintColor" }] : /* istanbul ignore next */ []));
@@ -421,7 +429,8 @@ export class NativeTabsOutlet {
421
429
  * screen's stack answers instead.
422
430
  */
423
431
  goBack() {
424
- const first = this.entries[0];
432
+ const key = this.declared()[0]?.path();
433
+ const first = this.entries.find((entry) => entry.key === key);
425
434
  const selected = this.selected;
426
435
  if (!first || !selected || selected === first || !this.router)
427
436
  return false;
@@ -567,6 +576,14 @@ export class NativeTabsOutlet {
567
576
  const outer = this.injector.get(SCREEN_IN_FRONT);
568
577
  const tab = {
569
578
  onLeave: (leave) => (entry.leaving.add(leave), () => entry.leaving.delete(leave)),
579
+ hideBar: (hidden) => {
580
+ this.barRequests.update((requests) => new Set(requests).add(hidden));
581
+ return () => this.barRequests.update((requests) => {
582
+ const rest = new Set(requests);
583
+ rest.delete(hidden);
584
+ return rest;
585
+ });
586
+ },
570
587
  };
571
588
  return Injector.create({
572
589
  parent: this.injector,
@@ -582,7 +599,7 @@ export class NativeTabsOutlet {
582
599
  });
583
600
  }
584
601
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: NativeTabsOutlet, deps: [], target: i0.ɵɵFactoryTarget.Component });
585
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.2.0", type: NativeTabsOutlet, isStandalone: true, selector: "native-tabs-outlet", inputs: { barHidden: { classPropertyName: "barHidden", publicName: "barHidden", isSignal: true, isRequired: false, transformFunction: null }, tintColor: { classPropertyName: "tintColor", publicName: "tintColor", isSignal: true, isRequired: false, transformFunction: null }, backgroundColor: { classPropertyName: "backgroundColor", publicName: "backgroundColor", isSignal: true, isRequired: false, transformFunction: null }, colorScheme: { classPropertyName: "colorScheme", publicName: "colorScheme", isSignal: true, isRequired: false, transformFunction: null }, minimizeBehavior: { classPropertyName: "minimizeBehavior", publicName: "minimizeBehavior", isSignal: true, isRequired: false, transformFunction: null }, controllerMode: { classPropertyName: "controllerMode", publicName: "controllerMode", isSignal: true, isRequired: false, transformFunction: null }, respectsKeyboard: { classPropertyName: "respectsKeyboard", publicName: "respectsKeyboard", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style": "fill", "tabBarHidden": "barHidden()", "tabBarTintColor": "tintColor() ?? defaults().tintColor", "nativeContainerBackgroundColor": "backgroundColor() ?? defaults().backgroundColor", "colorScheme": "colorScheme() ?? defaults().colorScheme", "tabBarMinimizeBehavior": "minimizeBehavior()", "tabBarControllerMode": "controllerMode()", "tabBarRespectsIMEInsets": "respectsKeyboard()" } }, providers: [{ provide: SVG_ICON_HOST, useFactory: () => inject(ViewContainerRef) }], queries: [{ propertyName: "declared", predicate: NativeTab, isSignal: true }], ngImport: i0, template: '<ng-content />', isInline: true });
602
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.2.0", type: NativeTabsOutlet, isStandalone: true, selector: "native-tabs-outlet", inputs: { barHidden: { classPropertyName: "barHidden", publicName: "barHidden", isSignal: true, isRequired: false, transformFunction: null }, tintColor: { classPropertyName: "tintColor", publicName: "tintColor", isSignal: true, isRequired: false, transformFunction: null }, backgroundColor: { classPropertyName: "backgroundColor", publicName: "backgroundColor", isSignal: true, isRequired: false, transformFunction: null }, colorScheme: { classPropertyName: "colorScheme", publicName: "colorScheme", isSignal: true, isRequired: false, transformFunction: null }, minimizeBehavior: { classPropertyName: "minimizeBehavior", publicName: "minimizeBehavior", isSignal: true, isRequired: false, transformFunction: null }, controllerMode: { classPropertyName: "controllerMode", publicName: "controllerMode", isSignal: true, isRequired: false, transformFunction: null }, respectsKeyboard: { classPropertyName: "respectsKeyboard", publicName: "respectsKeyboard", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style": "fill", "tabBarHidden": "hidesBar()", "tabBarTintColor": "tintColor() ?? defaults().tintColor", "nativeContainerBackgroundColor": "backgroundColor() ?? defaults().backgroundColor", "colorScheme": "colorScheme() ?? defaults().colorScheme", "tabBarMinimizeBehavior": "minimizeBehavior()", "tabBarControllerMode": "controllerMode()", "tabBarRespectsIMEInsets": "respectsKeyboard()" } }, providers: [{ provide: SVG_ICON_HOST, useFactory: () => inject(ViewContainerRef) }], queries: [{ propertyName: "declared", predicate: NativeTab, isSignal: true }], ngImport: i0, template: '<ng-content />', isInline: true });
586
603
  }
587
604
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: NativeTabsOutlet, decorators: [{
588
605
  type: Component,
@@ -592,7 +609,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
592
609
  providers: [{ provide: SVG_ICON_HOST, useFactory: () => inject(ViewContainerRef) }],
593
610
  host: {
594
611
  '[style]': 'fill',
595
- '[tabBarHidden]': 'barHidden()',
612
+ '[tabBarHidden]': 'hidesBar()',
596
613
  '[tabBarTintColor]': 'tintColor() ?? defaults().tintColor',
597
614
  '[nativeContainerBackgroundColor]': 'backgroundColor() ?? defaults().backgroundColor',
598
615
  '[colorScheme]': 'colorScheme() ?? defaults().colorScheme',