@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,408 @@
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 { ApplicationRef, ChangeDetectionStrategy, Component, DestroyRef, ElementRef, ErrorHandler, Injector, Renderer2, computed, contentChildren, createComponent, inject, input, signal, } from '@angular/core';
29
+ import { SCREEN_IN_FRONT } from '@ng-native/device';
30
+ import { ActivatedRoute, ChildrenOutletContexts, NavigationEnd, PRIMARY_OUTLET, Router, } from '@angular/router';
31
+ import { bindRouteInputs } from "./bind-route-inputs.js";
32
+ import { NATIVE_TAB_DEFAULTS } from "./native-bar-defaults.js";
33
+ import { NativeBack, isShowing } from "./native-back.js";
34
+ import { optionalBoolean } from "./transforms.js";
35
+ import { NativeTab } from "./native-tab.js";
36
+ import { ownHost } from "./own-host.js";
37
+ import { markTabRoute } from "./tab-routes.js";
38
+ import * as i0 from "@angular/core";
39
+ export class NativeTabsOutlet {
40
+ name = PRIMARY_OUTLET;
41
+ supportsBindingToComponentInputs = true;
42
+ parentContexts = inject(ChildrenOutletContexts);
43
+ renderer = inject(Renderer2);
44
+ applicationRef = inject(ApplicationRef);
45
+ injector = inject(Injector);
46
+ host = inject(ElementRef);
47
+ route = inject(ActivatedRoute);
48
+ /** Optional so the outlet can be driven through `RouterOutletContract` directly, as tests do. */
49
+ router = inject(Router, { optional: true });
50
+ errors = inject(ErrorHandler);
51
+ /** What activation has reported already, so the failed navigation it causes is not reported again. */
52
+ reported = new WeakSet();
53
+ /** The app's `withTabDefaults`, for whatever the outlet does not bind itself. */
54
+ defaults = inject(NATIVE_TAB_DEFAULTS);
55
+ declared = contentChildren(NativeTab, /* @ts-ignore */
56
+ ...(ngDevMode ? [{ debugName: "declared" }] : /* istanbul ignore next */ []));
57
+ entries = [];
58
+ selected = null;
59
+ /** The provenance of the last state native told us about. Starts before native's first. */
60
+ provenance = 0;
61
+ fill = { flex: 1 };
62
+ // --- the bar itself -----------------------------------------------------
63
+ /** Hide the bar without unmounting the tabs, for a screen that wants the whole window. */
64
+ barHidden = input(undefined, { ...(ngDevMode ? { debugName: "barHidden" } : /* istanbul ignore next */ {}), transform: optionalBoolean });
65
+ /** The colour of the selected item. iOS. */
66
+ tintColor = input(/* @ts-ignore */
67
+ ...(ngDevMode ? [undefined, { debugName: "tintColor" }] : /* istanbul ignore next */ []));
68
+ /** Behind the tabs, where a screen does not paint. */
69
+ backgroundColor = input(/* @ts-ignore */
70
+ ...(ngDevMode ? [undefined, { debugName: "backgroundColor" }] : /* istanbul ignore next */ []));
71
+ /** Force the bar's light or dark appearance, whatever the app's is. */
72
+ colorScheme = input(/* @ts-ignore */
73
+ ...(ngDevMode ? [undefined, { debugName: "colorScheme" }] : /* istanbul ignore next */ []));
74
+ /** iOS 26: let the bar shrink out of the way as content scrolls. */
75
+ minimizeBehavior = input(/* @ts-ignore */
76
+ ...(ngDevMode ? [undefined, { debugName: "minimizeBehavior" }] : /* istanbul ignore next */ []));
77
+ /** iOS: `tabSidebar` is the iPad layout, with the tabs down the side. */
78
+ controllerMode = input(/* @ts-ignore */
79
+ ...(ngDevMode ? [undefined, { debugName: "controllerMode" }] : /* istanbul ignore next */ []));
80
+ /** Android: keep the bar above the keyboard rather than behind it. */
81
+ respectsKeyboard = input(undefined, { ...(ngDevMode ? { debugName: "respectsKeyboard" } : /* istanbul ignore next */ {}), transform: optionalBoolean });
82
+ constructor() {
83
+ ownHost(this.host.nativeElement);
84
+ // In the constructor rather than a lifecycle hook: the router activates a child route as soon
85
+ // as this component exists, which is before any hook has run.
86
+ this.parentContexts.onChildOutletCreated(this.name, this);
87
+ this.renderer.listen(this.host.nativeElement, 'tabSelected', (event) => this.onNativeSelect(event?.nativeEvent));
88
+ // A push inside a tab's own stack reuses the tab's route, so this outlet is never activated
89
+ // for it; the router's navigation is the only sign. Without this, coming back to the tab
90
+ // returns it to its root and pops the screens the user left it on.
91
+ const following = this.router?.events?.subscribe((event) => {
92
+ if (event instanceof NavigationEnd)
93
+ this.follow(event.urlAfterRedirects);
94
+ });
95
+ // Android's back button, and `NativeNavigation.back()`, once the stack in front, if the tab
96
+ // has one, is at its root. Subscribed before any tab's own stack, so it is asked after them.
97
+ const unsubscribeBack = inject(NativeBack).handle(() => this.goBack());
98
+ inject(DestroyRef).onDestroy(() => {
99
+ unsubscribeBack();
100
+ following?.unsubscribe();
101
+ for (const entry of this.entries) {
102
+ entry.unbind();
103
+ entry.ref?.destroy();
104
+ }
105
+ this.entries.length = 0;
106
+ this.parentContexts.onChildOutletDestroyed(this.name);
107
+ });
108
+ }
109
+ /** A bar nobody has navigated into yet still has to show a selected item. */
110
+ ngAfterContentInit() {
111
+ this.readTabs();
112
+ }
113
+ /** The tabs in the bar, in template order. Exposed for tests. */
114
+ get tabKeys() {
115
+ return this.readTabs().map((entry) => entry.key);
116
+ }
117
+ /** Which tab native is showing. Exposed for tests. */
118
+ get selectedKey() {
119
+ return this.selected?.key ?? null;
120
+ }
121
+ // --- RouterOutletContract ----------------------------------------------
122
+ get isActivated() {
123
+ return this.selected?.ref != null && !this.selected.detached;
124
+ }
125
+ get component() {
126
+ return this.isActivated ? this.selected.ref.instance : null;
127
+ }
128
+ get activatedRoute() {
129
+ return this.isActivated ? this.selected.route : null;
130
+ }
131
+ get activatedRouteData() {
132
+ return this.activatedRoute?.snapshot.data ?? {};
133
+ }
134
+ /** The input binder reads this to bind route params to component inputs. */
135
+ get activatedComponentRef() {
136
+ return this.selected?.ref ?? null;
137
+ }
138
+ activateWith(route, environmentInjector) {
139
+ const component = (route.component ?? route.snapshot.component);
140
+ if (!component) {
141
+ throw new Error('[angular-native] route has no component to activate');
142
+ }
143
+ const entry = this.entryFor(route);
144
+ // The tab screen is owned by <native-tab>, not by this route component. If the route uses
145
+ // deactivate() rather than detach(), Angular removes the component host on destroy. Giving
146
+ // the component its own child host keeps that removal from taking the tab bar item with it.
147
+ const content = ownHost(this.renderer.createElement('view'));
148
+ this.renderer.setStyle(content, 'flex', 1);
149
+ this.renderer.appendChild(entry.tab.screen, content);
150
+ let ref;
151
+ try {
152
+ ref = createComponent(component, {
153
+ environmentInjector,
154
+ elementInjector: this.outletInjector(route, entry.inFront),
155
+ hostElement: content,
156
+ });
157
+ this.applicationRef.attachView(ref.hostView);
158
+ // Route params onto inputs before the first change detection, as the stack outlet does: a
159
+ // required input still unset when the page first renders throws NG0950.
160
+ entry.unbind = this.bindInputs(ref, route);
161
+ // Before anything can commit. Creating the page's nodes dirties the tree, which schedules a
162
+ // commit of its own - and that commit would capture the page with its elements created and
163
+ // its bindings not yet applied. On iOS the props catch up a frame later and nobody sees it;
164
+ // on Android the flattening decision is made from the props a view is created with, so a
165
+ // content wrapper that arrives without its `collapsable: false` is flattened for good and
166
+ // its children end up parented to a scroll view that allows exactly one.
167
+ ref.changeDetectorRef.detectChanges();
168
+ }
169
+ catch (error) {
170
+ this.abandon(entry, ref, content);
171
+ this.errors.handleError(error);
172
+ if (error !== null && typeof error === 'object')
173
+ this.reported.add(error);
174
+ throw error;
175
+ }
176
+ entry.ref = ref;
177
+ entry.route = route;
178
+ entry.detached = false;
179
+ this.select(entry);
180
+ }
181
+ deactivate() {
182
+ const entry = this.selected;
183
+ if (!entry?.ref)
184
+ return;
185
+ entry.unbind();
186
+ entry.unbind = () => { };
187
+ entry.ref.destroy();
188
+ entry.ref = null;
189
+ entry.route = null;
190
+ }
191
+ /**
192
+ * Hand the live `ComponentRef` back to the router. The tab's screen stays where it is with the
193
+ * component still inside it, so the tab keeps running while another one is in front.
194
+ */
195
+ detach() {
196
+ const entry = this.selected;
197
+ if (!entry?.ref)
198
+ throw new Error('[angular-native] outlet is not activated, nothing to detach');
199
+ entry.detached = true;
200
+ entry.inFront.set(false);
201
+ // As in the stack outlet: stop change detection without unmounting the views.
202
+ entry.ref.hostView.detach();
203
+ return entry.ref;
204
+ }
205
+ attach(ref, route) {
206
+ const entry = this.entryFor(route);
207
+ // A ref from a previous instance of this outlet still lives on its old tab screen, which is
208
+ // gone; re-parent it onto this one's rather than rebuild the tab.
209
+ if (entry.ref !== ref) {
210
+ this.renderer.appendChild(entry.tab.screen, ref.location.nativeElement);
211
+ this.applicationRef.attachView(ref.hostView);
212
+ entry.ref = ref;
213
+ }
214
+ entry.route = route;
215
+ entry.detached = false;
216
+ // The route object is new even when the url is not, so the inputs follow the new one.
217
+ entry.unbind();
218
+ entry.unbind = this.bindInputs(ref, route);
219
+ ref.hostView.reattach();
220
+ this.select(entry);
221
+ }
222
+ // --- native tabs --------------------------------------------------------
223
+ /**
224
+ * Undo a tab page that threw on its first render, which fails the navigation: its component
225
+ * and its content view go, and the tab that was showing carries on, change detection and all.
226
+ */
227
+ abandon(entry, ref, content) {
228
+ entry.unbind();
229
+ entry.unbind = () => { };
230
+ ref?.destroy();
231
+ this.renderer.removeChild(entry.tab.screen, content);
232
+ const showing = this.selected;
233
+ if (showing?.detached && showing.ref) {
234
+ showing.detached = false;
235
+ showing.ref.hostView.reattach();
236
+ }
237
+ }
238
+ /** Route params onto inputs only under `withComponentInputBinding()`, as in the stack outlet. */
239
+ bindInputs(ref, route) {
240
+ return this.router?.componentInputBindingEnabled ? bindRouteInputs(ref, route) : () => { };
241
+ }
242
+ /**
243
+ * Take the bar from the `<native-tab>` elements in the content, once.
244
+ *
245
+ * On demand rather than in a lifecycle hook, because the router activates a child route during
246
+ * this component's creation, before any hook has run - but after the content nodes themselves
247
+ * exist, which is all this needs.
248
+ */
249
+ readTabs() {
250
+ if (this.entries.length > 0)
251
+ return this.entries;
252
+ const children = this.route.routeConfig?.children ?? [];
253
+ for (const tab of this.declared()) {
254
+ const key = tab.path();
255
+ this.entries.push({
256
+ tab,
257
+ key,
258
+ url: '',
259
+ ref: null,
260
+ route: null,
261
+ detached: false,
262
+ unbind: () => { },
263
+ inFront: signal(false),
264
+ });
265
+ // The reuse strategy detaches a tab whole, and has only the route to go on.
266
+ // A path can have multiple route configs selected by canMatch (for example an iPad split
267
+ // layout and an iPhone stack). Mark every variant: the reuse strategy sees the config
268
+ // Angular actually matched, which may not be the first one in the route array.
269
+ for (const config of children) {
270
+ if (config.path === key)
271
+ markTabRoute(config);
272
+ }
273
+ }
274
+ if (this.entries.length === 0) {
275
+ throw new Error('[angular-native] <native-tabs-outlet> has no tabs. Put a <native-tab path="..."> ' +
276
+ 'inside it for each child route the bar should reach.');
277
+ }
278
+ // Before the first navigation nothing is selected, which is not a state a tab bar has.
279
+ this.request(this.entries[0]);
280
+ return this.entries;
281
+ }
282
+ entryFor(route) {
283
+ const path = (route.routeConfig ?? route.snapshot.routeConfig)?.path;
284
+ const entry = this.readTabs().find((candidate) => candidate.key === path);
285
+ if (!entry) {
286
+ throw new Error(`[angular-native] no <native-tab> has path="${path}". Every child route the bar can ` +
287
+ `reach needs one, and its path is what native identifies the tab by.`);
288
+ }
289
+ return entry;
290
+ }
291
+ /** Remember where this tab is, and tell native to show it. */
292
+ select(entry) {
293
+ this.selected = entry;
294
+ for (const other of this.entries)
295
+ other.inFront.set(other === entry);
296
+ entry.url = this.router?.url ?? entry.url;
297
+ this.request(entry);
298
+ }
299
+ /**
300
+ * A back with nothing left to pop inside the tab: go to the first tab, where it was left, which
301
+ * is what a bottom navigation bar does on Android. From the first tab, decline, so the platform
302
+ * leaves the app. The order tabs were visited in is not retraced, so a back never lands on a
303
+ * tab the user did not expect. Not while the bar is covered by a screen pushed over it: that
304
+ * screen's stack answers instead.
305
+ */
306
+ goBack() {
307
+ const first = this.entries[0];
308
+ const selected = this.selected;
309
+ if (!first || !selected || selected === first || !this.router)
310
+ return false;
311
+ if (!this.isActivated || !isShowing(this.router, selected.route))
312
+ return false;
313
+ void this.router.navigateByUrl(first.url || this.pathOf(first));
314
+ return true;
315
+ }
316
+ /** Keep the tab in front on the url it has reached, as long as the url is still inside it. */
317
+ follow(url) {
318
+ const entry = this.selected;
319
+ if (!entry)
320
+ return;
321
+ const root = this.pathOf(entry);
322
+ if (url === root || url.startsWith(`${root}/`) || url.startsWith(`${root}?`))
323
+ entry.url = url;
324
+ }
325
+ request(entry) {
326
+ this.renderer.setProperty(this.host.nativeElement, 'navStateRequest', {
327
+ selectedScreenKey: entry.key,
328
+ baseProvenance: this.provenance,
329
+ });
330
+ }
331
+ /**
332
+ * Native switched tab. Acknowledge the new state, then navigate: the router is authoritative
333
+ * about what is on screen (ADR 0003), so the tap becomes a navigation to where that tab was,
334
+ * and the activation that follows is what fills the tab in.
335
+ */
336
+ onNativeSelect(selection) {
337
+ if (!selection)
338
+ return;
339
+ this.provenance = selection.provenance;
340
+ const entry = this.readTabs().find((tab) => tab.key === selection.selectedScreenKey);
341
+ if (!entry || entry === this.selected)
342
+ return;
343
+ // Returning to a tab returns to the url it was last on, which is the whole point of keeping
344
+ // it mounted. A tab never visited starts at its own path.
345
+ // A navigation that fails is reported, unless activation reported it already: a page that
346
+ // does not load, caught here, would otherwise leave nothing but a tab that will not open.
347
+ void this.router?.navigateByUrl(entry.url || this.pathOf(entry)).then((arrived) => this.revertUnless(arrived), (error) => {
348
+ if (error === null || typeof error !== 'object' || !this.reported.has(error)) {
349
+ this.errors.handleError(error);
350
+ }
351
+ this.revertUnless(false);
352
+ });
353
+ }
354
+ /**
355
+ * Native switched tab before the router agreed to. When a guard refuses, or the navigation
356
+ * fails, the router stays where it was and so must the bar, or it shows a tab nobody is on.
357
+ * Not while another navigation is under way: that one superseded this, and its own activation
358
+ * selects the tab it lands on.
359
+ */
360
+ revertUnless(arrived) {
361
+ if (arrived || !this.selected || this.router?.getCurrentNavigation())
362
+ return;
363
+ this.request(this.selected);
364
+ }
365
+ /** A tab's own url, from the outlet's route down. */
366
+ pathOf(entry) {
367
+ const parent = this.route.snapshot.pathFromRoot
368
+ .flatMap((snapshot) => snapshot.url.map((segment) => segment.path))
369
+ .join('/');
370
+ return `/${[parent, entry.key].filter(Boolean).join('/')}`;
371
+ }
372
+ /** As the stack outlet's: the route, the outlet contexts, and whether the tab is showing. */
373
+ outletInjector(route, inFront) {
374
+ const outer = this.injector.get(SCREEN_IN_FRONT);
375
+ return Injector.create({
376
+ parent: this.injector,
377
+ providers: [
378
+ { provide: SCREEN_IN_FRONT, useValue: computed(() => outer() && inFront()) },
379
+ { provide: ActivatedRoute, useValue: route },
380
+ {
381
+ provide: ChildrenOutletContexts,
382
+ useValue: this.parentContexts.getOrCreateContext(this.name).children,
383
+ },
384
+ ],
385
+ });
386
+ }
387
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: NativeTabsOutlet, deps: [], target: i0.ɵɵFactoryTarget.Component });
388
+ 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()" } }, queries: [{ propertyName: "declared", predicate: NativeTab, isSignal: true }], ngImport: i0, template: '<ng-content />', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
389
+ }
390
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: NativeTabsOutlet, decorators: [{
391
+ type: Component,
392
+ args: [{
393
+ selector: 'native-tabs-outlet',
394
+ template: '<ng-content />',
395
+ changeDetection: ChangeDetectionStrategy.OnPush,
396
+ host: {
397
+ '[style]': 'fill',
398
+ '[tabBarHidden]': 'barHidden()',
399
+ '[tabBarTintColor]': 'tintColor() ?? defaults().tintColor',
400
+ '[nativeContainerBackgroundColor]': 'backgroundColor() ?? defaults().backgroundColor',
401
+ '[colorScheme]': 'colorScheme() ?? defaults().colorScheme',
402
+ '[tabBarMinimizeBehavior]': 'minimizeBehavior()',
403
+ '[tabBarControllerMode]': 'controllerMode()',
404
+ '[tabBarRespectsIMEInsets]': 'respectsKeyboard()',
405
+ },
406
+ }]
407
+ }], ctorParameters: () => [], propDecorators: { declared: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => NativeTab), { isSignal: true }] }], barHidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "barHidden", required: false }] }], tintColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "tintColor", required: false }] }], backgroundColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "backgroundColor", required: false }] }], colorScheme: [{ type: i0.Input, args: [{ isSignal: true, alias: "colorScheme", required: false }] }], minimizeBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "minimizeBehavior", required: false }] }], controllerMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "controllerMode", required: false }] }], respectsKeyboard: [{ type: i0.Input, args: [{ isSignal: true, alias: "respectsKeyboard", required: false }] }] } });
408
+ //# sourceMappingURL=native-tabs-outlet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-tabs-outlet.js","sourceRoot":"","sources":["../src/native-tabs-outlet.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A `RouterOutlet` that renders a native tab bar: a `UITabBarController` on iOS, a bottom\n * navigation bar on Android.\n *\n * The outlet's host element *is* the tabs host, and each `<native-tab>` in its content is one\n * item and the screen behind it. An activated route's component is created on a child view of\n * the matching tab screen. The screen belongs to the tab declaration and must survive the route\n * component being destroyed; Angular removes a component's host node when it destroys the ref.\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 * **Native holds the selection, not us.** The tabs host owns its navigation state and reports\n * every change - a tap, or one we asked for - through `tabSelected`, carrying a `provenance`\n * number that increments per change. We send `navStateRequest` with the provenance of the last\n * state we acknowledged, which is how native tells a stale request from a current one when a tap\n * and a navigation cross in flight. The alternative, holding the selection in JS, means a tap is\n * only reflected after a round trip, and the bar lags the finger. See ADR 0006.\n *\n * **Each tab keeps its own screen mounted**, so switching away and back finds a tab exactly as it\n * was: its scroll offset, its text, and its own stack if it has one. That is the reuse strategy\n * detaching the tab's whole subtree rather than only its leaf.\n */\nimport {\n ApplicationRef,\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n ErrorHandler,\n Injector,\n Renderer2,\n computed,\n contentChildren,\n createComponent,\n inject,\n input,\n signal,\n type AfterContentInit,\n type ComponentRef,\n type EnvironmentInjector,\n type Type,\n type WritableSignal,\n} from '@angular/core';\nimport { SCREEN_IN_FRONT } from '@ng-native/device';\nimport {\n ActivatedRoute,\n ChildrenOutletContexts,\n NavigationEnd,\n PRIMARY_OUTLET,\n Router,\n type Data,\n type RouterOutletContract,\n} from '@angular/router';\nimport { bindRouteInputs } from './bind-route-inputs.ts';\nimport { NATIVE_TAB_DEFAULTS } from './native-bar-defaults.ts';\nimport { NativeBack, isShowing } from './native-back.ts';\nimport { optionalBoolean } from './transforms.ts';\nimport { NativeTab } from './native-tab.ts';\nimport { ownHost } from './own-host.ts';\nimport { markTabRoute } from './tab-routes.ts';\n\ninterface TabEntry {\n readonly tab: NativeTab;\n /** The key native identifies this tab by: its path, unique among the bar's items. */\n readonly key: string;\n /** The url this tab was last on, so returning to it returns where the user left. */\n url: string;\n ref: ComponentRef<unknown> | null;\n route: ActivatedRoute | null;\n detached: boolean;\n /** Stops feeding route params into the component's inputs. */\n unbind: () => void;\n /** Whether this tab is the one showing, for what its screens hold: see `SCREEN_IN_FRONT`. */\n readonly inFront: WritableSignal<boolean>;\n}\n\n/** What `tabSelected` carries. Only two fields matter here; the rest is diagnostics. */\ninterface TabSelection {\n readonly selectedScreenKey: string;\n readonly provenance: number;\n}\n\n@Component({\n selector: 'native-tabs-outlet',\n template: '<ng-content />',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[style]': 'fill',\n '[tabBarHidden]': 'barHidden()',\n '[tabBarTintColor]': 'tintColor() ?? defaults().tintColor',\n '[nativeContainerBackgroundColor]': 'backgroundColor() ?? defaults().backgroundColor',\n '[colorScheme]': 'colorScheme() ?? defaults().colorScheme',\n '[tabBarMinimizeBehavior]': 'minimizeBehavior()',\n '[tabBarControllerMode]': 'controllerMode()',\n '[tabBarRespectsIMEInsets]': 'respectsKeyboard()',\n },\n})\nexport class NativeTabsOutlet implements RouterOutletContract, AfterContentInit {\n name = PRIMARY_OUTLET;\n\n readonly supportsBindingToComponentInputs = true;\n\n private readonly parentContexts = inject(ChildrenOutletContexts);\n private readonly renderer = inject(Renderer2);\n private readonly applicationRef = inject(ApplicationRef);\n private readonly injector = inject(Injector);\n private readonly host = inject(ElementRef);\n private readonly route = inject(ActivatedRoute);\n /** Optional so the outlet can be driven through `RouterOutletContract` directly, as tests do. */\n private readonly router = inject(Router, { optional: true });\n private readonly errors = inject(ErrorHandler);\n /** What activation has reported already, so the failed navigation it causes is not reported again. */\n private readonly reported = new WeakSet<object>();\n /** The app's `withTabDefaults`, for whatever the outlet does not bind itself. */\n protected readonly defaults = inject(NATIVE_TAB_DEFAULTS);\n\n private readonly declared = contentChildren(NativeTab);\n private readonly entries: TabEntry[] = [];\n private selected: TabEntry | null = null;\n /** The provenance of the last state native told us about. Starts before native's first. */\n private provenance = 0;\n\n protected readonly fill = { flex: 1 };\n\n // --- the bar itself -----------------------------------------------------\n\n /** Hide the bar without unmounting the tabs, for a screen that wants the whole window. */\n readonly barHidden = input(undefined, { transform: optionalBoolean });\n /** The colour of the selected item. iOS. */\n readonly tintColor = input<string | number>();\n /** Behind the tabs, where a screen does not paint. */\n readonly backgroundColor = input<string | number>();\n /** Force the bar's light or dark appearance, whatever the app's is. */\n readonly colorScheme = input<'inherit' | 'light' | 'dark'>();\n /** iOS 26: let the bar shrink out of the way as content scrolls. */\n readonly minimizeBehavior = input<'automatic' | 'never' | 'onScrollDown' | 'onScrollUp'>();\n /** iOS: `tabSidebar` is the iPad layout, with the tabs down the side. */\n readonly controllerMode = input<'automatic' | 'tabBar' | 'tabSidebar'>();\n /** Android: keep the bar above the keyboard rather than behind it. */\n readonly respectsKeyboard = input(undefined, { transform: optionalBoolean });\n\n constructor() {\n ownHost(this.host.nativeElement);\n // In the constructor rather than a lifecycle hook: the router activates a child route as soon\n // as this component exists, which is before any hook has run.\n this.parentContexts.onChildOutletCreated(this.name, this);\n\n this.renderer.listen(\n this.host.nativeElement,\n 'tabSelected',\n (event: { nativeEvent?: TabSelection }) => this.onNativeSelect(event?.nativeEvent),\n );\n\n // A push inside a tab's own stack reuses the tab's route, so this outlet is never activated\n // for it; the router's navigation is the only sign. Without this, coming back to the tab\n // returns it to its root and pops the screens the user left it on.\n const following = this.router?.events?.subscribe((event) => {\n if (event instanceof NavigationEnd) this.follow(event.urlAfterRedirects);\n });\n\n // Android's back button, and `NativeNavigation.back()`, once the stack in front, if the tab\n // has one, is at its root. Subscribed before any tab's own stack, so it is asked after them.\n const unsubscribeBack = inject(NativeBack).handle(() => this.goBack());\n\n inject(DestroyRef).onDestroy(() => {\n unsubscribeBack();\n following?.unsubscribe();\n for (const entry of this.entries) {\n entry.unbind();\n entry.ref?.destroy();\n }\n this.entries.length = 0;\n this.parentContexts.onChildOutletDestroyed(this.name);\n });\n }\n\n /** A bar nobody has navigated into yet still has to show a selected item. */\n ngAfterContentInit(): void {\n this.readTabs();\n }\n\n /** The tabs in the bar, in template order. Exposed for tests. */\n get tabKeys(): string[] {\n return this.readTabs().map((entry) => entry.key);\n }\n\n /** Which tab native is showing. Exposed for tests. */\n get selectedKey(): string | null {\n return this.selected?.key ?? null;\n }\n\n // --- RouterOutletContract ----------------------------------------------\n\n get isActivated(): boolean {\n return this.selected?.ref != null && !this.selected.detached;\n }\n\n get component(): Object | null {\n return this.isActivated ? (this.selected!.ref!.instance as Object) : null;\n }\n\n get activatedRoute(): ActivatedRoute | null {\n return this.isActivated ? this.selected!.route : null;\n }\n\n get activatedRouteData(): Data {\n return this.activatedRoute?.snapshot.data ?? {};\n }\n\n /** The input binder reads this to bind route params to component inputs. */\n get activatedComponentRef(): ComponentRef<unknown> | null {\n return this.selected?.ref ?? null;\n }\n\n activateWith(route: ActivatedRoute, environmentInjector: EnvironmentInjector): void {\n const component = (route.component ?? route.snapshot.component) as Type<unknown> | null;\n if (!component) {\n throw new Error('[angular-native] route has no component to activate');\n }\n const entry = this.entryFor(route);\n\n // The tab screen is owned by <native-tab>, not by this route component. If the route uses\n // deactivate() rather than detach(), Angular removes the component host on destroy. Giving\n // the component its own child host keeps that removal from taking the tab bar item with it.\n const content = ownHost(this.renderer.createElement('view'));\n this.renderer.setStyle(content, 'flex', 1);\n this.renderer.appendChild(entry.tab.screen, content);\n\n let ref: ComponentRef<unknown> | undefined;\n try {\n ref = createComponent(component, {\n environmentInjector,\n elementInjector: this.outletInjector(route, entry.inFront),\n hostElement: content as Element,\n });\n this.applicationRef.attachView(ref.hostView);\n // Route params onto inputs before the first change detection, as the stack outlet does: a\n // required input still unset when the page first renders throws NG0950.\n entry.unbind = this.bindInputs(ref, route);\n // Before anything can commit. Creating the page's nodes dirties the tree, which schedules a\n // commit of its own - and that commit would capture the page with its elements created and\n // its bindings not yet applied. On iOS the props catch up a frame later and nobody sees it;\n // on Android the flattening decision is made from the props a view is created with, so a\n // content wrapper that arrives without its `collapsable: false` is flattened for good and\n // its children end up parented to a scroll view that allows exactly one.\n ref.changeDetectorRef.detectChanges();\n } catch (error) {\n this.abandon(entry, ref, content);\n this.errors.handleError(error);\n if (error !== null && typeof error === 'object') this.reported.add(error);\n throw error;\n }\n\n entry.ref = ref;\n entry.route = route;\n entry.detached = false;\n this.select(entry);\n }\n\n deactivate(): void {\n const entry = this.selected;\n if (!entry?.ref) return;\n entry.unbind();\n entry.unbind = () => {};\n entry.ref.destroy();\n entry.ref = null;\n entry.route = null;\n }\n\n /**\n * Hand the live `ComponentRef` back to the router. The tab's screen stays where it is with the\n * component still inside it, so the tab keeps running while another one is in front.\n */\n detach(): ComponentRef<unknown> {\n const entry = this.selected;\n if (!entry?.ref) throw new Error('[angular-native] outlet is not activated, nothing to detach');\n entry.detached = true;\n entry.inFront.set(false);\n // As in the stack outlet: stop change detection without unmounting the views.\n entry.ref.hostView.detach();\n return entry.ref;\n }\n\n attach(ref: ComponentRef<unknown>, route: ActivatedRoute): void {\n const entry = this.entryFor(route);\n\n // A ref from a previous instance of this outlet still lives on its old tab screen, which is\n // gone; re-parent it onto this one's rather than rebuild the tab.\n if (entry.ref !== ref) {\n this.renderer.appendChild(entry.tab.screen, ref.location.nativeElement);\n this.applicationRef.attachView(ref.hostView);\n entry.ref = ref;\n }\n\n entry.route = route;\n entry.detached = false;\n // The route object is new even when the url is not, so the inputs follow the new one.\n entry.unbind();\n entry.unbind = this.bindInputs(ref, route);\n ref.hostView.reattach();\n this.select(entry);\n }\n\n // --- native tabs --------------------------------------------------------\n\n /**\n * Undo a tab page that threw on its first render, which fails the navigation: its component\n * and its content view go, and the tab that was showing carries on, change detection and all.\n */\n private abandon(entry: TabEntry, ref: ComponentRef<unknown> | undefined, content: unknown): void {\n entry.unbind();\n entry.unbind = () => {};\n ref?.destroy();\n this.renderer.removeChild(entry.tab.screen, content);\n const showing = this.selected;\n if (showing?.detached && showing.ref) {\n showing.detached = false;\n showing.ref.hostView.reattach();\n }\n }\n\n /** Route params onto inputs only under `withComponentInputBinding()`, as in the stack outlet. */\n private bindInputs(ref: ComponentRef<unknown>, route: ActivatedRoute): () => void {\n return this.router?.componentInputBindingEnabled ? bindRouteInputs(ref, route) : () => {};\n }\n\n /**\n * Take the bar from the `<native-tab>` elements in the content, once.\n *\n * On demand rather than in a lifecycle hook, because the router activates a child route during\n * this component's creation, before any hook has run - but after the content nodes themselves\n * exist, which is all this needs.\n */\n private readTabs(): TabEntry[] {\n if (this.entries.length > 0) return this.entries;\n\n const children = this.route.routeConfig?.children ?? [];\n for (const tab of this.declared()) {\n const key = tab.path();\n this.entries.push({\n tab,\n key,\n url: '',\n ref: null,\n route: null,\n detached: false,\n unbind: () => {},\n inFront: signal(false),\n });\n // The reuse strategy detaches a tab whole, and has only the route to go on.\n // A path can have multiple route configs selected by canMatch (for example an iPad split\n // layout and an iPhone stack). Mark every variant: the reuse strategy sees the config\n // Angular actually matched, which may not be the first one in the route array.\n for (const config of children) {\n if (config.path === key) markTabRoute(config);\n }\n }\n\n if (this.entries.length === 0) {\n throw new Error(\n '[angular-native] <native-tabs-outlet> has no tabs. Put a <native-tab path=\"...\"> ' +\n 'inside it for each child route the bar should reach.',\n );\n }\n // Before the first navigation nothing is selected, which is not a state a tab bar has.\n this.request(this.entries[0]!);\n return this.entries;\n }\n\n private entryFor(route: ActivatedRoute): TabEntry {\n const path = (route.routeConfig ?? route.snapshot.routeConfig)?.path;\n const entry = this.readTabs().find((candidate) => candidate.key === path);\n if (!entry) {\n throw new Error(\n `[angular-native] no <native-tab> has path=\"${path}\". Every child route the bar can ` +\n `reach needs one, and its path is what native identifies the tab by.`,\n );\n }\n return entry;\n }\n\n /** Remember where this tab is, and tell native to show it. */\n private select(entry: TabEntry): void {\n this.selected = entry;\n for (const other of this.entries) other.inFront.set(other === entry);\n entry.url = this.router?.url ?? entry.url;\n this.request(entry);\n }\n\n /**\n * A back with nothing left to pop inside the tab: go to the first tab, where it was left, which\n * is what a bottom navigation bar does on Android. From the first tab, decline, so the platform\n * leaves the app. The order tabs were visited in is not retraced, so a back never lands on a\n * tab the user did not expect. Not while the bar is covered by a screen pushed over it: that\n * screen's stack answers instead.\n */\n private goBack(): boolean {\n const first = this.entries[0];\n const selected = this.selected;\n if (!first || !selected || selected === first || !this.router) return false;\n if (!this.isActivated || !isShowing(this.router, selected.route)) return false;\n void this.router.navigateByUrl(first.url || this.pathOf(first));\n return true;\n }\n\n /** Keep the tab in front on the url it has reached, as long as the url is still inside it. */\n private follow(url: string): void {\n const entry = this.selected;\n if (!entry) return;\n const root = this.pathOf(entry);\n if (url === root || url.startsWith(`${root}/`) || url.startsWith(`${root}?`)) entry.url = url;\n }\n\n private request(entry: TabEntry): void {\n this.renderer.setProperty(this.host.nativeElement, 'navStateRequest', {\n selectedScreenKey: entry.key,\n baseProvenance: this.provenance,\n });\n }\n\n /**\n * Native switched tab. Acknowledge the new state, then navigate: the router is authoritative\n * about what is on screen (ADR 0003), so the tap becomes a navigation to where that tab was,\n * and the activation that follows is what fills the tab in.\n */\n private onNativeSelect(selection: TabSelection | undefined): void {\n if (!selection) return;\n this.provenance = selection.provenance;\n\n const entry = this.readTabs().find((tab) => tab.key === selection.selectedScreenKey);\n if (!entry || entry === this.selected) return;\n\n // Returning to a tab returns to the url it was last on, which is the whole point of keeping\n // it mounted. A tab never visited starts at its own path.\n // A navigation that fails is reported, unless activation reported it already: a page that\n // does not load, caught here, would otherwise leave nothing but a tab that will not open.\n void this.router?.navigateByUrl(entry.url || this.pathOf(entry)).then(\n (arrived) => this.revertUnless(arrived),\n (error: unknown) => {\n if (error === null || typeof error !== 'object' || !this.reported.has(error)) {\n this.errors.handleError(error);\n }\n this.revertUnless(false);\n },\n );\n }\n\n /**\n * Native switched tab before the router agreed to. When a guard refuses, or the navigation\n * fails, the router stays where it was and so must the bar, or it shows a tab nobody is on.\n * Not while another navigation is under way: that one superseded this, and its own activation\n * selects the tab it lands on.\n */\n private revertUnless(arrived: boolean): void {\n if (arrived || !this.selected || this.router?.getCurrentNavigation()) return;\n this.request(this.selected);\n }\n\n /** A tab's own url, from the outlet's route down. */\n private pathOf(entry: TabEntry): string {\n const parent = this.route.snapshot.pathFromRoot\n .flatMap((snapshot) => snapshot.url.map((segment) => segment.path))\n .join('/');\n return `/${[parent, entry.key].filter(Boolean).join('/')}`;\n }\n\n /** As the stack outlet's: the route, the outlet contexts, and whether the tab is showing. */\n private outletInjector(route: ActivatedRoute, inFront: WritableSignal<boolean>): Injector {\n const outer = this.injector.get(SCREEN_IN_FRONT);\n return Injector.create({\n parent: this.injector,\n providers: [\n { provide: SCREEN_IN_FRONT, useValue: computed(() => outer() && inFront()) },\n { provide: ActivatedRoute, useValue: route },\n {\n provide: ChildrenOutletContexts,\n useValue: this.parentContexts.getOrCreateContext(this.name).children,\n },\n ],\n });\n }\n}\n"]}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Mark `node` as owned, and take off any prop Angular wrote there from a static attribute that
3
+ * one of `directive`'s inputs already consumed: `<native-header title="Settings">` feeds the
4
+ * input *and* writes a `title` attribute, and only the input's value should survive.
5
+ */
6
+ export declare function ownHost<T>(node: T, directive?: unknown): T;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Claiming a host node, for the elements navigation owns.
3
+ *
4
+ * The engine reports any registered element name that reaches a commit without a component
5
+ * behind it, which is how a template that forgot an import is caught. Navigation's elements need
6
+ * the same treatment for the opposite reason: the outlet creates a `screen` itself, and the
7
+ * header components own theirs, so both are accounted for rather than reported.
8
+ *
9
+ * This duplicates a few lines of the components package on purpose. `@nx/enforce-module-boundaries`
10
+ * keeps the Angular-facing packages from reaching into each other, and a package dependency is a
11
+ * heavier price than the copy.
12
+ */
13
+ import { claimHost } from '@ng-native/fabric';
14
+ /**
15
+ * Mark `node` as owned, and take off any prop Angular wrote there from a static attribute that
16
+ * one of `directive`'s inputs already consumed: `<native-header title="Settings">` feeds the
17
+ * input *and* writes a `title` attribute, and only the input's value should survive.
18
+ */
19
+ export function ownHost(node, directive) {
20
+ claimHost(node);
21
+ if (directive) {
22
+ const def = directive.ɵcmp;
23
+ for (const name of Object.keys(def?.inputs ?? {}))
24
+ delete node.props[name];
25
+ }
26
+ return node;
27
+ }
28
+ //# sourceMappingURL=own-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"own-host.js","sourceRoot":"","sources":["../src/own-host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,SAAS,EAAmB,MAAM,mBAAmB,CAAC;AAE/D;;;;GAIG;AACH,MAAM,UAAU,OAAO,CAAI,IAAO,EAAE,SAAmB;IACrD,SAAS,CAAC,IAAkB,CAAC,CAAC;IAC9B,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,GAAG,GAAI,SAA4C,CAAC,IAAI,CAAC;QAC/D,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,IAAI,EAAE,CAAC;YAAE,OAAQ,IAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7F,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["/**\n * Claiming a host node, for the elements navigation owns.\n *\n * The engine reports any registered element name that reaches a commit without a component\n * behind it, which is how a template that forgot an import is caught. Navigation's elements need\n * the same treatment for the opposite reason: the outlet creates a `screen` itself, and the\n * header components own theirs, so both are accounted for rather than reported.\n *\n * This duplicates a few lines of the components package on purpose. `@nx/enforce-module-boundaries`\n * keeps the Angular-facing packages from reaching into each other, and a package dependency is a\n * heavier price than the copy.\n */\nimport { claimHost, type EngineNode } from '@ng-native/fabric';\n\n/**\n * Mark `node` as owned, and take off any prop Angular wrote there from a static attribute that\n * one of `directive`'s inputs already consumed: `<native-header title=\"Settings\">` feeds the\n * input *and* writes a `title` attribute, and only the input's value should survive.\n */\nexport function ownHost<T>(node: T, directive?: unknown): T {\n claimHost(node as EngineNode);\n if (directive) {\n const def = (directive as { ɵcmp?: { inputs?: object } }).ɵcmp;\n for (const name of Object.keys(def?.inputs ?? {})) delete (node as EngineNode).props[name];\n }\n return node;\n}\n"]}
@@ -0,0 +1,41 @@
1
+ import { type RouterFeatures, type Routes } from '@angular/router';
2
+ import { type EnvironmentProviders, type Provider } from '@angular/core';
3
+ import { type HeaderDefaults, type SchemeDefaults, type TabDefaults } from './native-bar-defaults.ts';
4
+ import { type LinkParent } from './native-links.ts';
5
+ /** A native-only router option, passed to `provideNativeRouter` beside Angular's own features. */
6
+ export interface NativeRouterFeature {
7
+ readonly ɵnativeRouter: {
8
+ readonly linkParent?: LinkParent;
9
+ readonly providers?: Provider[];
10
+ };
11
+ }
12
+ /**
13
+ * The page a deep link opens on top of, or null to open it alone. Without it a link to
14
+ * `/settings/notifications` opens that page with no Back. See native-links.ts.
15
+ */
16
+ export declare function withLinkParent(parentOf: LinkParent): NativeRouterFeature;
17
+ /**
18
+ * How every `<native-header>` looks when it does not say: its colours, blur, shadow, fonts and
19
+ * light or dark style. A header's own binding always wins.
20
+ *
21
+ * ```ts
22
+ * provideNativeRouter(
23
+ * routes,
24
+ * withHeaderDefaults((scheme) => ({
25
+ * backgroundColor: scheme === 'dark' ? '#101014' : '#f4f4f7',
26
+ * titleColor: scheme === 'dark' ? '#ffffff' : '#101014',
27
+ * color: '#3b6ef5',
28
+ * })),
29
+ * );
30
+ * ```
31
+ *
32
+ * Colours it leaves out still come from `NATIVE_HEADER_PALETTE`.
33
+ */
34
+ export declare function withHeaderDefaults(defaults: SchemeDefaults<HeaderDefaults>): NativeRouterFeature;
35
+ /**
36
+ * How every `<native-tabs-outlet>` and `<native-tab>` looks when it does not say: the tint, the
37
+ * background behind the tabs, the light or dark style, and each tab's bar appearance. An outlet's
38
+ * or a tab's own binding always wins.
39
+ */
40
+ export declare function withTabDefaults(defaults: SchemeDefaults<TabDefaults>): NativeRouterFeature;
41
+ export declare function provideNativeRouter(routes: Routes, ...features: (RouterFeatures | NativeRouterFeature)[]): EnvironmentProviders;