@ng-native/router 0.0.1 → 0.1.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.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +74 -1
  3. package/dist/bind-route-inputs.d.ts +20 -0
  4. package/dist/bind-route-inputs.js +52 -0
  5. package/dist/bind-route-inputs.js.map +1 -0
  6. package/dist/full-window-overlay.d.ts +16 -0
  7. package/dist/full-window-overlay.js +52 -0
  8. package/dist/full-window-overlay.js.map +1 -0
  9. package/dist/index.d.ts +26 -0
  10. package/dist/index.js +27 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/native-back.d.ts +38 -0
  13. package/dist/native-back.js +88 -0
  14. package/dist/native-back.js.map +1 -0
  15. package/dist/native-bar-defaults.d.ts +50 -0
  16. package/dist/native-bar-defaults.js +17 -0
  17. package/dist/native-bar-defaults.js.map +1 -0
  18. package/dist/native-header-item.d.ts +12 -0
  19. package/dist/native-header-item.js +40 -0
  20. package/dist/native-header-item.js.map +1 -0
  21. package/dist/native-header-palette.d.ts +45 -0
  22. package/dist/native-header-palette.js +42 -0
  23. package/dist/native-header-palette.js.map +1 -0
  24. package/dist/native-header.d.ts +103 -0
  25. package/dist/native-header.js +204 -0
  26. package/dist/native-header.js.map +1 -0
  27. package/dist/native-links.d.ts +30 -0
  28. package/dist/native-links.js +40 -0
  29. package/dist/native-links.js.map +1 -0
  30. package/dist/native-navigation.d.ts +84 -0
  31. package/dist/native-navigation.js +153 -0
  32. package/dist/native-navigation.js.map +1 -0
  33. package/dist/native-platform-location.d.ts +62 -0
  34. package/dist/native-platform-location.js +110 -0
  35. package/dist/native-platform-location.js.map +1 -0
  36. package/dist/native-router-link.d.ts +14 -0
  37. package/dist/native-router-link.js +51 -0
  38. package/dist/native-router-link.js.map +1 -0
  39. package/dist/native-search-bar.d.ts +44 -0
  40. package/dist/native-search-bar.js +132 -0
  41. package/dist/native-search-bar.js.map +1 -0
  42. package/dist/native-stack-outlet.d.ts +195 -0
  43. package/dist/native-stack-outlet.js +564 -0
  44. package/dist/native-stack-outlet.js.map +1 -0
  45. package/dist/native-stack-reuse-strategy.d.ts +57 -0
  46. package/dist/native-stack-reuse-strategy.js +126 -0
  47. package/dist/native-stack-reuse-strategy.js.map +1 -0
  48. package/dist/native-tab.d.ts +147 -0
  49. package/dist/native-tab.js +209 -0
  50. package/dist/native-tab.js.map +1 -0
  51. package/dist/native-tabs-outlet.d.ts +138 -0
  52. package/dist/native-tabs-outlet.js +408 -0
  53. package/dist/native-tabs-outlet.js.map +1 -0
  54. package/dist/own-host.d.ts +6 -0
  55. package/dist/own-host.js +28 -0
  56. package/dist/own-host.js.map +1 -0
  57. package/dist/provide-native-router.d.ts +41 -0
  58. package/dist/provide-native-router.js +151 -0
  59. package/dist/provide-native-router.js.map +1 -0
  60. package/dist/screen-presentation.d.ts +69 -0
  61. package/dist/screen-presentation.js +10 -0
  62. package/dist/screen-presentation.js.map +1 -0
  63. package/dist/screens.d.ts +37 -0
  64. package/dist/screens.js +108 -0
  65. package/dist/screens.js.map +1 -0
  66. package/dist/tab-routes.d.ts +16 -0
  67. package/dist/tab-routes.js +24 -0
  68. package/dist/tab-routes.js.map +1 -0
  69. package/dist/tab-safe-area-view.d.ts +15 -0
  70. package/dist/tab-safe-area-view.js +63 -0
  71. package/dist/tab-safe-area-view.js.map +1 -0
  72. package/dist/transforms.d.ts +2 -0
  73. package/dist/transforms.js +13 -0
  74. package/dist/transforms.js.map +1 -0
  75. package/package.json +59 -3
@@ -0,0 +1,209 @@
1
+ /**
2
+ * One item in a native tab bar, and the screen behind it.
3
+ *
4
+ * Declared in the tabs outlet's template, the way a `<native-header>` is declared in a page's:
5
+ *
6
+ * ```html
7
+ * <native-tabs-outlet>
8
+ * <native-tab path="library" title="Library" sfSymbol="books.vertical.fill" />
9
+ * <native-tab path="inbox" title="Inbox" sfSymbol="tray" [badge]="unread()" />
10
+ * </native-tabs-outlet>
11
+ * ```
12
+ *
13
+ * `path` names the child route this tab selects, the same way a `routerLink` names one, and is
14
+ * what native identifies the tab by. Everything else is an ordinary input, which is the point of
15
+ * declaring tabs here rather than in the route config: a badge is a count that changes, a title
16
+ * may be translated, and a tab may not exist at all until a feature flag says so. Route data
17
+ * cannot bind to any of that.
18
+ *
19
+ * **A bar item is not a view.** `UITabBarItem` is a model object - a title, an image and a badge
20
+ * string - and UIKit has no way to put a view in its place; Android's bottom-navigation item is
21
+ * the same. That is why this takes no content, while `<native-header-item>` does: a navigation
22
+ * bar really does hold subviews. What customisation exists is here as inputs: images instead of
23
+ * symbols, a different icon when selected, and the per-state appearance below.
24
+ *
25
+ * The host element *is* the `RNSTabsScreen`. The outlet keeps the screen mounted and creates
26
+ * each activated route's component on a child view, so destroying a route cannot remove this
27
+ * tab item from the bar.
28
+ */
29
+ import { Component, ElementRef, computed, inject, input } from '@angular/core';
30
+ import { nativePlatform, HostEngine } from '@ng-native/fabric';
31
+ import { NATIVE_TAB_DEFAULTS } from "./native-bar-defaults.js";
32
+ import { ownHost } from "./own-host.js";
33
+ import * as i0 from "@angular/core";
34
+ /**
35
+ * An icon and its selected counterpart, as one set of props.
36
+ *
37
+ * Native carries a single `iconType` for both states, so the two have to be the same kind of
38
+ * thing: a template image cannot become a symbol when selected. React Native Screens throws on
39
+ * that pairing and so does this, because the alternative - what happened before this checked - is
40
+ * that native quietly keeps the unselected icon and nothing anywhere says why.
41
+ */
42
+ export function tabIconProps(icon, selectedIcon) {
43
+ const hasBase = icon.iconType !== undefined || icon.drawableIconResourceName !== undefined;
44
+ const hasSelected = selectedIcon.iconType !== undefined || selectedIcon.drawableIconResourceName !== undefined;
45
+ if (hasSelected && !hasBase) {
46
+ throw new Error('[angular-native] <native-tab> has a selectedIcon but no icon to select from');
47
+ }
48
+ if (hasSelected && icon.iconType !== selectedIcon.iconType) {
49
+ throw new Error(`[angular-native] <native-tab> icon and selectedIcon must be the same kind: native has ` +
50
+ `one iconType for both, so '${icon.iconType}' and '${selectedIcon.iconType}' cannot pair.`);
51
+ }
52
+ return {
53
+ ...icon,
54
+ selectedIconResourceName: selectedIcon.iconResourceName,
55
+ selectedIconImageSource: selectedIcon.iconImageSource,
56
+ selectedDrawableIconResourceName: selectedIcon.drawableIconResourceName,
57
+ selectedImageIconResource: selectedIcon.imageIconResource,
58
+ };
59
+ }
60
+ export class NativeTab {
61
+ engine = inject(HostEngine);
62
+ /** The app's `withTabDefaults`, for an appearance this tab does not bind itself. */
63
+ defaults = inject(NATIVE_TAB_DEFAULTS);
64
+ /**
65
+ * The `RNSTabsScreen` this tab is. The outlet creates the activated route's component inside
66
+ * it, which is why it is public: a tab is a slot as well as a bar item.
67
+ */
68
+ screen;
69
+ constructor() {
70
+ this.screen = ownHost(inject(ElementRef).nativeElement, this.constructor);
71
+ }
72
+ /**
73
+ * The child route this tab selects, as a path segment: `library` for `/tabs/library`. Native
74
+ * identifies the tab by it too, so it must be unique in the bar.
75
+ */
76
+ path = input.required(/* @ts-ignore */
77
+ ...(ngDevMode ? [{ debugName: "path" }] : /* istanbul ignore next */ []));
78
+ /** The label under the icon. Absent gives an icon-only item. */
79
+ title = input(/* @ts-ignore */
80
+ ...(ngDevMode ? [undefined, { debugName: "title" }] : /* istanbul ignore next */ []));
81
+ /** iOS: an SF Symbol name, e.g. `books.vertical.fill`. Shorthand for `[icon]`. */
82
+ sfSymbol = input(/* @ts-ignore */
83
+ ...(ngDevMode ? [undefined, { debugName: "sfSymbol" }] : /* istanbul ignore next */ []));
84
+ /** Android: a drawable resource name. Shorthand for `[icon]`. */
85
+ drawable = input(/* @ts-ignore */
86
+ ...(ngDevMode ? [undefined, { debugName: "drawable" }] : /* istanbul ignore next */ []));
87
+ /** Anything a symbol name cannot say: an image, a template image, an asset-catalogue name. */
88
+ icon = input(/* @ts-ignore */
89
+ ...(ngDevMode ? [undefined, { debugName: "icon" }] : /* istanbul ignore next */ []));
90
+ /** Shown while this tab is the selected one. Absent leaves the platform to tint `icon`. */
91
+ selectedIcon = input(/* @ts-ignore */
92
+ ...(ngDevMode ? [undefined, { debugName: "selectedIcon" }] : /* istanbul ignore next */ []));
93
+ /** One of Apple's standard items, which supplies its own icon and title. */
94
+ systemItem = input(/* @ts-ignore */
95
+ ...(ngDevMode ? [undefined, { debugName: "systemItem" }] : /* istanbul ignore next */ []));
96
+ /** The badge on the item: a count, or a single character for a dot. */
97
+ badge = input(/* @ts-ignore */
98
+ ...(ngDevMode ? [undefined, { debugName: "badge" }] : /* istanbul ignore next */ []));
99
+ /** Announced instead of the title. */
100
+ accessibilityLabel = input(/* @ts-ignore */
101
+ ...(ngDevMode ? [undefined, { debugName: "accessibilityLabel" }] : /* istanbul ignore next */ []));
102
+ /** How the item looks. Colours are processed here, because native never sees the object's keys. */
103
+ standardAppearance = input(/* @ts-ignore */
104
+ ...(ngDevMode ? [undefined, { debugName: "standardAppearance" }] : /* istanbul ignore next */ []));
105
+ /** The same, for when the scroll view behind the bar is at its edge. */
106
+ scrollEdgeAppearance = input(/* @ts-ignore */
107
+ ...(ngDevMode ? [undefined, { debugName: "scrollEdgeAppearance" }] : /* istanbul ignore next */ []));
108
+ standard = computed(() => this.processAppearance(this.standardAppearance() ?? this.defaults().standardAppearance), /* @ts-ignore */
109
+ ...(ngDevMode ? [{ debugName: "standard" }] : /* istanbul ignore next */ []));
110
+ scrollEdge = computed(() => this.processAppearance(this.scrollEdgeAppearance() ?? this.defaults().scrollEdgeAppearance), /* @ts-ignore */
111
+ ...(ngDevMode ? [{ debugName: "scrollEdge" }] : /* istanbul ignore next */ []));
112
+ icons = computed(() => tabIconProps(this.iconProps(this.icon() ?? this.shorthand()), this.iconProps(this.selectedIcon())), /* @ts-ignore */
113
+ ...(ngDevMode ? [{ debugName: "icons" }] : /* istanbul ignore next */ []));
114
+ /** `sfSymbol` and `drawable` say the same thing as `icon`, in the form most tabs want. */
115
+ shorthand() {
116
+ const symbol = this.sfSymbol();
117
+ if (symbol)
118
+ return { sfSymbol: symbol };
119
+ const drawable = this.drawable();
120
+ return drawable ? { drawable } : undefined;
121
+ }
122
+ /**
123
+ * One icon, as the four props native reads it through. A `require()`d asset is an id until the
124
+ * host resolves it, which is the same thing an `<image src>` needs and the engine only does for
125
+ * props it knows by name.
126
+ */
127
+ iconProps(icon) {
128
+ if (!icon)
129
+ return {};
130
+ if ('sfSymbol' in icon)
131
+ return { iconType: 'sfSymbol', iconResourceName: icon.sfSymbol };
132
+ if ('xcasset' in icon)
133
+ return { iconType: 'xcasset', iconResourceName: icon.xcasset };
134
+ if ('drawable' in icon)
135
+ return { drawableIconResourceName: icon.drawable };
136
+ const source = this.engine.resolveAsset('image' in icon ? icon.image : icon.template);
137
+ return nativePlatform() === 'android'
138
+ ? { imageIconResource: source }
139
+ : { iconType: 'image' in icon ? 'image' : 'template', iconImageSource: source };
140
+ }
141
+ processAppearance(appearance) {
142
+ if (!appearance)
143
+ return undefined;
144
+ return {
145
+ ...appearance,
146
+ stacked: this.processItem(appearance.stacked),
147
+ inline: this.processItem(appearance.inline),
148
+ compactInline: this.processItem(appearance.compactInline),
149
+ tabBarBackgroundColor: this.engine.color(appearance.tabBarBackgroundColor),
150
+ tabBarShadowColor: this.engine.color(appearance.tabBarShadowColor),
151
+ };
152
+ }
153
+ processItem(item) {
154
+ if (!item)
155
+ return undefined;
156
+ return {
157
+ normal: this.processState(item.normal),
158
+ selected: this.processState(item.selected),
159
+ focused: this.processState(item.focused),
160
+ disabled: this.processState(item.disabled),
161
+ };
162
+ }
163
+ processState(state) {
164
+ if (!state)
165
+ return undefined;
166
+ return {
167
+ ...state,
168
+ // Native declares the weight as a string, and `600` is the natural way to write one.
169
+ tabBarItemTitleFontWeight: state.tabBarItemTitleFontWeight === undefined
170
+ ? undefined
171
+ : String(state.tabBarItemTitleFontWeight),
172
+ tabBarItemTitleFontColor: this.engine.color(state.tabBarItemTitleFontColor),
173
+ tabBarItemIconColor: this.engine.color(state.tabBarItemIconColor),
174
+ tabBarItemBadgeBackgroundColor: this.engine.color(state.tabBarItemBadgeBackgroundColor),
175
+ };
176
+ }
177
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: NativeTab, deps: [], target: i0.ɵɵFactoryTarget.Component });
178
+ 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 }, 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": "path()", "title": "title()", "badgeValue": "badge()", "tabBarItemAccessibilityLabel": "accessibilityLabel()", "systemItem": "systemItem()", "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 });
179
+ }
180
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: NativeTab, decorators: [{
181
+ type: Component,
182
+ args: [{
183
+ selector: 'native-tab',
184
+ template: '',
185
+ host: {
186
+ '[screenKey]': 'path()',
187
+ '[title]': 'title()',
188
+ '[badgeValue]': 'badge()',
189
+ '[tabBarItemAccessibilityLabel]': 'accessibilityLabel()',
190
+ '[systemItem]': 'systemItem()',
191
+ // `isTitleUndefined` is what `TabsScreen.ios.tsx` derives from the title, and it is not a
192
+ // synonym for "no title": with a title set and this left at its default, the item renders as
193
+ // an icon with a gap where the label belongs.
194
+ '[isTitleUndefined]': 'title() === undefined',
195
+ '[iconType]': 'icons().iconType',
196
+ '[iconResourceName]': 'icons().iconResourceName',
197
+ '[iconImageSource]': 'icons().iconImageSource',
198
+ '[selectedIconResourceName]': 'icons().selectedIconResourceName',
199
+ '[selectedIconImageSource]': 'icons().selectedIconImageSource',
200
+ '[drawableIconResourceName]': 'icons().drawableIconResourceName',
201
+ '[imageIconResource]': 'icons().imageIconResource',
202
+ '[selectedDrawableIconResourceName]': 'icons().selectedDrawableIconResourceName',
203
+ '[selectedImageIconResource]': 'icons().selectedImageIconResource',
204
+ '[standardAppearance]': 'standard()',
205
+ '[scrollEdgeAppearance]': 'scrollEdge()',
206
+ },
207
+ }]
208
+ }], ctorParameters: () => [], propDecorators: { path: [{ type: i0.Input, args: [{ isSignal: true, alias: "path", required: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], sfSymbol: [{ type: i0.Input, args: [{ isSignal: true, alias: "sfSymbol", required: false }] }], drawable: [{ type: i0.Input, args: [{ isSignal: true, alias: "drawable", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], selectedIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedIcon", required: false }] }], systemItem: [{ type: i0.Input, args: [{ isSignal: true, alias: "systemItem", required: false }] }], badge: [{ type: i0.Input, args: [{ isSignal: true, alias: "badge", required: false }] }], accessibilityLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "accessibilityLabel", required: false }] }], standardAppearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "standardAppearance", required: false }] }], scrollEdgeAppearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollEdgeAppearance", required: false }] }] } });
209
+ //# sourceMappingURL=native-tab.js.map
@@ -0,0 +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 { Component, ElementRef, computed, inject, input } 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';\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/** 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\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@Component({\n selector: 'native-tab',\n template: '',\n host: {\n '[screenKey]': 'path()',\n '[title]': 'title()',\n '[badgeValue]': 'badge()',\n '[tabBarItemAccessibilityLabel]': 'accessibilityLabel()',\n '[systemItem]': 'systemItem()',\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 {\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\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 /** 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 /** 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 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 protected readonly icons = computed(() =>\n tabIconProps(\n this.iconProps(this.icon() ?? this.shorthand()),\n this.iconProps(this.selectedIcon()),\n ),\n );\n\n /** `sfSymbol` and `drawable` say the same thing as `icon`, in the form most tabs want. */\n private shorthand(): TabIcon | undefined {\n const symbol = this.sfSymbol();\n if (symbol) return { sfSymbol: symbol };\n const drawable = this.drawable();\n return drawable ? { drawable } : 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): 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\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"]}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * A `RouterOutlet` that renders a native tab bar: a `UITabBarController` on iOS, a bottom
3
+ * navigation bar on Android.
4
+ *
5
+ * The outlet's host element *is* the tabs host, and each `<native-tab>` in its content is one
6
+ * item and the screen behind it. An activated route's component is created on a child view of
7
+ * the matching tab screen. The screen belongs to the tab declaration and must survive the route
8
+ * component being destroyed; Angular removes a component's host node when it destroys the ref.
9
+ *
10
+ * ```html
11
+ * <native-tabs-outlet>
12
+ * <native-tab path="library" title="Library" sfSymbol="books.vertical.fill" />
13
+ * <native-tab path="inbox" title="Inbox" sfSymbol="tray" [badge]="unread()" />
14
+ * </native-tabs-outlet>
15
+ * ```
16
+ *
17
+ * **Native holds the selection, not us.** The tabs host owns its navigation state and reports
18
+ * every change - a tap, or one we asked for - through `tabSelected`, carrying a `provenance`
19
+ * number that increments per change. We send `navStateRequest` with the provenance of the last
20
+ * state we acknowledged, which is how native tells a stale request from a current one when a tap
21
+ * and a navigation cross in flight. The alternative, holding the selection in JS, means a tap is
22
+ * only reflected after a round trip, and the bar lags the finger. See ADR 0006.
23
+ *
24
+ * **Each tab keeps its own screen mounted**, so switching away and back finds a tab exactly as it
25
+ * was: its scroll offset, its text, and its own stack if it has one. That is the reuse strategy
26
+ * detaching the tab's whole subtree rather than only its leaf.
27
+ */
28
+ import { type AfterContentInit, type ComponentRef, type EnvironmentInjector } from '@angular/core';
29
+ import { ActivatedRoute, type Data, type RouterOutletContract } from '@angular/router';
30
+ import * as i0 from "@angular/core";
31
+ export declare class NativeTabsOutlet implements RouterOutletContract, AfterContentInit {
32
+ name: string;
33
+ readonly supportsBindingToComponentInputs = true;
34
+ private readonly parentContexts;
35
+ private readonly renderer;
36
+ private readonly applicationRef;
37
+ private readonly injector;
38
+ private readonly host;
39
+ private readonly route;
40
+ /** Optional so the outlet can be driven through `RouterOutletContract` directly, as tests do. */
41
+ private readonly router;
42
+ private readonly errors;
43
+ /** What activation has reported already, so the failed navigation it causes is not reported again. */
44
+ private readonly reported;
45
+ /** The app's `withTabDefaults`, for whatever the outlet does not bind itself. */
46
+ protected readonly defaults: import("@angular/core").Signal<import("./native-bar-defaults.ts").TabDefaults>;
47
+ private readonly declared;
48
+ private readonly entries;
49
+ private selected;
50
+ /** The provenance of the last state native told us about. Starts before native's first. */
51
+ private provenance;
52
+ protected readonly fill: {
53
+ flex: number;
54
+ };
55
+ /** Hide the bar without unmounting the tabs, for a screen that wants the whole window. */
56
+ readonly barHidden: import("@angular/core").InputSignalWithTransform<boolean | undefined, unknown>;
57
+ /** The colour of the selected item. iOS. */
58
+ readonly tintColor: import("@angular/core").InputSignal<string | number | undefined>;
59
+ /** Behind the tabs, where a screen does not paint. */
60
+ readonly backgroundColor: import("@angular/core").InputSignal<string | number | undefined>;
61
+ /** Force the bar's light or dark appearance, whatever the app's is. */
62
+ readonly colorScheme: import("@angular/core").InputSignal<"light" | "dark" | "inherit" | undefined>;
63
+ /** iOS 26: let the bar shrink out of the way as content scrolls. */
64
+ readonly minimizeBehavior: import("@angular/core").InputSignal<"automatic" | "never" | "onScrollDown" | "onScrollUp" | undefined>;
65
+ /** iOS: `tabSidebar` is the iPad layout, with the tabs down the side. */
66
+ readonly controllerMode: import("@angular/core").InputSignal<"automatic" | "tabBar" | "tabSidebar" | undefined>;
67
+ /** Android: keep the bar above the keyboard rather than behind it. */
68
+ readonly respectsKeyboard: import("@angular/core").InputSignalWithTransform<boolean | undefined, unknown>;
69
+ constructor();
70
+ /** A bar nobody has navigated into yet still has to show a selected item. */
71
+ ngAfterContentInit(): void;
72
+ /** The tabs in the bar, in template order. Exposed for tests. */
73
+ get tabKeys(): string[];
74
+ /** Which tab native is showing. Exposed for tests. */
75
+ get selectedKey(): string | null;
76
+ get isActivated(): boolean;
77
+ get component(): Object | null;
78
+ get activatedRoute(): ActivatedRoute | null;
79
+ get activatedRouteData(): Data;
80
+ /** The input binder reads this to bind route params to component inputs. */
81
+ get activatedComponentRef(): ComponentRef<unknown> | null;
82
+ activateWith(route: ActivatedRoute, environmentInjector: EnvironmentInjector): void;
83
+ deactivate(): void;
84
+ /**
85
+ * Hand the live `ComponentRef` back to the router. The tab's screen stays where it is with the
86
+ * component still inside it, so the tab keeps running while another one is in front.
87
+ */
88
+ detach(): ComponentRef<unknown>;
89
+ attach(ref: ComponentRef<unknown>, route: ActivatedRoute): void;
90
+ /**
91
+ * Undo a tab page that threw on its first render, which fails the navigation: its component
92
+ * and its content view go, and the tab that was showing carries on, change detection and all.
93
+ */
94
+ private abandon;
95
+ /** Route params onto inputs only under `withComponentInputBinding()`, as in the stack outlet. */
96
+ private bindInputs;
97
+ /**
98
+ * Take the bar from the `<native-tab>` elements in the content, once.
99
+ *
100
+ * On demand rather than in a lifecycle hook, because the router activates a child route during
101
+ * this component's creation, before any hook has run - but after the content nodes themselves
102
+ * exist, which is all this needs.
103
+ */
104
+ private readTabs;
105
+ private entryFor;
106
+ /** Remember where this tab is, and tell native to show it. */
107
+ private select;
108
+ /**
109
+ * A back with nothing left to pop inside the tab: go to the first tab, where it was left, which
110
+ * is what a bottom navigation bar does on Android. From the first tab, decline, so the platform
111
+ * leaves the app. The order tabs were visited in is not retraced, so a back never lands on a
112
+ * tab the user did not expect. Not while the bar is covered by a screen pushed over it: that
113
+ * screen's stack answers instead.
114
+ */
115
+ private goBack;
116
+ /** Keep the tab in front on the url it has reached, as long as the url is still inside it. */
117
+ private follow;
118
+ private request;
119
+ /**
120
+ * Native switched tab. Acknowledge the new state, then navigate: the router is authoritative
121
+ * about what is on screen (ADR 0003), so the tap becomes a navigation to where that tab was,
122
+ * and the activation that follows is what fills the tab in.
123
+ */
124
+ private onNativeSelect;
125
+ /**
126
+ * Native switched tab before the router agreed to. When a guard refuses, or the navigation
127
+ * fails, the router stays where it was and so must the bar, or it shows a tab nobody is on.
128
+ * Not while another navigation is under way: that one superseded this, and its own activation
129
+ * selects the tab it lands on.
130
+ */
131
+ private revertUnless;
132
+ /** A tab's own url, from the outlet's route down. */
133
+ private pathOf;
134
+ /** As the stack outlet's: the route, the outlet contexts, and whether the tab is showing. */
135
+ private outletInjector;
136
+ static ɵfac: i0.ɵɵFactoryDeclaration<NativeTabsOutlet, never>;
137
+ static ɵcmp: i0.ɵɵComponentDeclaration<NativeTabsOutlet, "native-tabs-outlet", never, { "barHidden": { "alias": "barHidden"; "required": false; "isSignal": true; }; "tintColor": { "alias": "tintColor"; "required": false; "isSignal": true; }; "backgroundColor": { "alias": "backgroundColor"; "required": false; "isSignal": true; }; "colorScheme": { "alias": "colorScheme"; "required": false; "isSignal": true; }; "minimizeBehavior": { "alias": "minimizeBehavior"; "required": false; "isSignal": true; }; "controllerMode": { "alias": "controllerMode"; "required": false; "isSignal": true; }; "respectsKeyboard": { "alias": "respectsKeyboard"; "required": false; "isSignal": true; }; }, {}, ["declared"], ["*"], true, never>;
138
+ }