@ng-native/router 0.18.2 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -136,6 +136,13 @@ export declare class NativeTabsOutlet implements RouterOutletContract, AfterCont
136
136
  */
137
137
  private entryFor;
138
138
  /** Remember where this tab is, and tell native to show it. */
139
+ /**
140
+ * Whether native selects a tab on a tap or leaves that to the router. A tab kept from a visit
141
+ * behind a guard is left to it: native would show the page it holds before the guard has run,
142
+ * and only take it back once the guard said no. One in front, or with no guard, native selects.
143
+ * react-native-screens before 4.30 has no such prop, and selects as before.
144
+ */
145
+ private guardSelection;
139
146
  private select;
140
147
  /**
141
148
  * Another tab came in front of `entry`: its stacks dismiss what they presented, and it is
@@ -168,7 +175,16 @@ export declare class NativeTabsOutlet implements RouterOutletContract, AfterCont
168
175
  * followed, as `taken` follows neither: a page only one of them shows is in no tab.
169
176
  */
170
177
  private tabOf;
171
- /** Whether the routes of the tab at `''` lead to `rest`, the path under the bar's own url. */
178
+ /**
179
+ * The segments of `url` under the tab, or null when `url` is not inside it. The bar's own
180
+ * segments are compared as the router writes them, matrix parameters included; the tab's own by
181
+ * path alone, as a url can give them matrix parameters of their own, `library;sort=a`. Parsed,
182
+ * and only the primary outlet's segments read, so a named outlet open beside the tab,
183
+ * `library(popup:compose)`, is not taken for part of its path. A url with a page presented over
184
+ * the app is that page's, which is in no tab.
185
+ */
186
+ private under;
187
+ /** Whether the routes of the tab at `''` lead to `rest`, the segments under the bar's own url. */
172
188
  private leadsInto;
173
189
  private request;
174
190
  /**
@@ -193,8 +209,14 @@ export declare class NativeTabsOutlet implements RouterOutletContract, AfterCont
193
209
  */
194
210
  private revertUnless;
195
211
  private urlOf;
196
- /** A tab's own url, from the outlet's route down. */
212
+ /**
213
+ * A tab's own url, from the outlet's route down. Each segment as the router writes it in a url,
214
+ * escaped and with its matrix parameters, `s%C3%A3o-paulo;lang=pt`, which is what it is
215
+ * compared with.
216
+ */
197
217
  private pathOf;
218
+ /** The outlet's route's segments, from the root down, as `pathOf` writes them. */
219
+ private parentSegments;
198
220
  /**
199
221
  * As the stack outlet's: the route, the outlet contexts, and whether the tab is showing. And the
200
222
  * tab itself, for its stacks to hear when another comes in front.
@@ -36,11 +36,11 @@ import { NativeTab, screenKeyOf } from "./native-tab.js";
36
36
  import { ownHost } from "./own-host.js";
37
37
  import { markTabRoute } from "./tab-routes.js";
38
38
  import { IN_TAB } from "./in-tab.js";
39
- import { taken, withoutPresented } from "./presented-route.js";
39
+ import { PRESENTED, taken, withoutPresented } from "./presented-route.js";
40
40
  import { SVG_ICON_HOST } from "./svg-icons.js";
41
+ import { primarySegments } from "./url-commands.js";
41
42
  import * as i0 from "@angular/core";
42
- /** A url without its query or fragment. */
43
- const pathOnly = (url) => url.split(/[?#]/, 1)[0];
43
+ const segmentsOf = (path) => path.split('/').filter(Boolean);
44
44
  /**
45
45
  * Whether one of `routes` matches `segments`, whole or up to lazy children not loaded yet, which a
46
46
  * route that took a static segment of its own is taken to lead to. A parameter alone is not: it
@@ -60,6 +60,21 @@ function reaches(routes, segments) {
60
60
  return named && route.loadChildren !== undefined;
61
61
  });
62
62
  }
63
+ /** Whether matching or activating a route, or a page under it, runs a guard. */
64
+ function guardedAt(route) {
65
+ if (!route)
66
+ return false;
67
+ const guards = (config) => !!config &&
68
+ !!(config.canActivate?.length || config.canActivateChild?.length || config.canMatch?.length);
69
+ const snapshot = route.snapshot;
70
+ if (snapshot?.pathFromRoot?.some((each) => guards(each.routeConfig)))
71
+ return true;
72
+ for (let below = snapshot?.firstChild; below; below = below.firstChild) {
73
+ if (guards(below.routeConfig))
74
+ return true;
75
+ }
76
+ return false;
77
+ }
63
78
  export class NativeTabsOutlet {
64
79
  name = PRIMARY_OUTLET;
65
80
  supportsBindingToComponentInputs = true;
@@ -118,6 +133,17 @@ export class NativeTabsOutlet {
118
133
  // as this component exists, which is before any hook has run.
119
134
  this.parentContexts.onChildOutletCreated(this.name, this);
120
135
  this.renderer.listen(this.host.nativeElement, 'tabSelected', (event) => this.onNativeSelect(event?.nativeEvent));
136
+ // A tap on a tab native was told not to select: see `guardSelection`. The router decides.
137
+ this.renderer.listen(this.host.nativeElement, 'tabSelectionPrevented', (event) => {
138
+ const prevented = event?.nativeEvent;
139
+ if (!prevented)
140
+ return;
141
+ this.onNativeSelect({
142
+ selectedScreenKey: prevented.preventedScreenKey,
143
+ provenance: prevented.provenance,
144
+ actionOrigin: 'user',
145
+ });
146
+ });
121
147
  // An `@if` that takes a tab away and brings it back makes a new element: its page follows it
122
148
  // at once, since the tab may be the one showing, with no tap or navigation to read them on.
123
149
  effect(() => {
@@ -273,6 +299,7 @@ export class NativeTabsOutlet {
273
299
  throw new Error('[angular-native] outlet is not activated, nothing to detach');
274
300
  entry.detached = true;
275
301
  entry.inFront.set(false);
302
+ this.guardSelection(entry, guardedAt(entry.route));
276
303
  // As in the stack outlet: stop change detection without unmounting the views.
277
304
  entry.ref.hostView.detach();
278
305
  return entry.ref;
@@ -371,6 +398,7 @@ export class NativeTabsOutlet {
371
398
  if (entry.tab === tab)
372
399
  return;
373
400
  entry.tab = tab;
401
+ this.guardSelection(entry, entry.detached && guardedAt(entry.route));
374
402
  if (entry.ref)
375
403
  this.renderer.appendChild(tab.screen, entry.ref.location.nativeElement);
376
404
  }
@@ -398,11 +426,21 @@ export class NativeTabsOutlet {
398
426
  return entry;
399
427
  }
400
428
  /** Remember where this tab is, and tell native to show it. */
429
+ /**
430
+ * Whether native selects a tab on a tap or leaves that to the router. A tab kept from a visit
431
+ * behind a guard is left to it: native would show the page it holds before the guard has run,
432
+ * and only take it back once the guard said no. One in front, or with no guard, native selects.
433
+ * react-native-screens before 4.30 has no such prop, and selects as before.
434
+ */
435
+ guardSelection(entry, guarded) {
436
+ this.renderer.setProperty(entry.tab.screen, 'preventNativeSelection', guarded);
437
+ }
401
438
  select(entry) {
402
439
  const left = this.selected;
403
440
  if (left && left !== entry)
404
441
  this.leave(left);
405
442
  this.selected = entry;
443
+ this.guardSelection(entry, false);
406
444
  for (const other of this.entries)
407
445
  other.inFront.set(other === entry);
408
446
  entry.url = this.router?.url ?? entry.url;
@@ -453,8 +491,7 @@ export class NativeTabsOutlet {
453
491
  const entry = this.tabOf(url);
454
492
  if (!entry || entry.ref)
455
493
  return null;
456
- const root = this.pathOf(entry);
457
- return pathOnly(url) === root ? null : root;
494
+ return this.under(entry, url)?.length === 0 ? null : this.pathOf(entry);
458
495
  }
459
496
  /** Where the tab `url` is in was left, while a screen over the bar covers it. */
460
497
  coveredAt(url) {
@@ -475,27 +512,50 @@ export class NativeTabsOutlet {
475
512
  * followed, as `taken` follows neither: a page only one of them shows is in no tab.
476
513
  */
477
514
  tabOf(url) {
478
- const path = pathOnly(url);
479
515
  let found = null;
516
+ let depth = -1;
480
517
  for (const entry of this.entries) {
481
- const root = this.pathOf(entry);
482
- const inside = path === root || path.startsWith(root.endsWith('/') ? root : `${root}/`);
483
- if (!inside || (found && this.pathOf(found).length >= root.length))
518
+ const rest = this.under(entry, url);
519
+ const own = segmentsOf(entry.key).length;
520
+ if (!rest || own <= depth)
484
521
  continue;
485
- if (!entry.key && !this.leadsInto(entry, path.slice(root.length)))
522
+ if (!entry.key && !this.leadsInto(entry, rest))
486
523
  continue;
487
524
  found = entry;
525
+ depth = own;
488
526
  }
489
527
  return found;
490
528
  }
491
- /** Whether the routes of the tab at `''` lead to `rest`, the path under the bar's own url. */
529
+ /**
530
+ * The segments of `url` under the tab, or null when `url` is not inside it. The bar's own
531
+ * segments are compared as the router writes them, matrix parameters included; the tab's own by
532
+ * path alone, as a url can give them matrix parameters of their own, `library;sort=a`. Parsed,
533
+ * and only the primary outlet's segments read, so a named outlet open beside the tab,
534
+ * `library(popup:compose)`, is not taken for part of its path. A url with a page presented over
535
+ * the app is that page's, which is in no tab.
536
+ */
537
+ under(entry, url) {
538
+ if (!this.router || this.router.parseUrl(url).root.children[PRESENTED])
539
+ return null;
540
+ const segments = primarySegments(this.router, url);
541
+ const parent = this.parentSegments();
542
+ const own = segmentsOf(entry.key);
543
+ if (segments.length < parent.length + own.length)
544
+ return null;
545
+ if (parent.some((segment, index) => segments[index].toString() !== segment))
546
+ return null;
547
+ if (own.some((segment, index) => segments[parent.length + index].path !== segment)) {
548
+ return null;
549
+ }
550
+ return segments.slice(parent.length + own.length).map((segment) => segment.path);
551
+ }
552
+ /** Whether the routes of the tab at `''` lead to `rest`, the segments under the bar's own url. */
492
553
  leadsInto(entry, rest) {
493
- const segments = rest.split('/').filter(Boolean);
494
554
  const own = entry.route?.snapshot.routeConfig;
495
555
  const routes = own
496
556
  ? [own]
497
557
  : (this.route.routeConfig?.children ?? []).filter((config) => config.path === '');
498
- return segments.length === 0 || reaches(routes, segments);
558
+ return rest.length === 0 || reaches(routes, rest);
499
559
  }
500
560
  request(entry) {
501
561
  this.renderer.setProperty(this.host.nativeElement, 'navStateRequest', {
@@ -561,12 +621,17 @@ export class NativeTabsOutlet {
561
621
  urlOf(entry) {
562
622
  return entry.url && this.tabOf(entry.url) === entry ? entry.url : this.pathOf(entry);
563
623
  }
564
- /** A tab's own url, from the outlet's route down. */
624
+ /**
625
+ * A tab's own url, from the outlet's route down. Each segment as the router writes it in a url,
626
+ * escaped and with its matrix parameters, `s%C3%A3o-paulo;lang=pt`, which is what it is
627
+ * compared with.
628
+ */
565
629
  pathOf(entry) {
566
- const parent = this.route.snapshot.pathFromRoot
567
- .flatMap((snapshot) => snapshot.url.map((segment) => segment.path))
568
- .join('/');
569
- return `/${[parent, entry.key].filter(Boolean).join('/')}`;
630
+ return `/${[...this.parentSegments(), entry.key].filter(Boolean).join('/')}`;
631
+ }
632
+ /** The outlet's route's segments, from the root down, as `pathOf` writes them. */
633
+ parentSegments() {
634
+ return this.route.snapshot.pathFromRoot.flatMap((snapshot) => snapshot.url.map((segment) => segment.toString()));
570
635
  }
571
636
  /**
572
637
  * As the stack outlet's: the route, the outlet contexts, and whether the tab is showing. And the
@@ -1 +1 @@
1
- {"version":3,"file":"native-tabs-outlet.js","sourceRoot":"","sources":["../src/native-tabs-outlet.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,SAAS,EACT,UAAU,EACV,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,eAAe,EACf,eAAe,EACf,MAAM,EACN,MAAM,EACN,KAAK,EACL,MAAM,EACN,SAAS,EACT,gBAAgB,GAOjB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,aAAa,EACb,cAAc,EACd,MAAM,GAIP,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAc,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;;AAE/C,2CAA2C;AAC3C,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC;AAEnE;;;;GAIG;AACH,SAAS,OAAO,CAAC,MAAwB,EAAE,QAA2B;IACpE,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;QAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACrC,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QACjC,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,IAAI,KAAK,CAAC,QAAQ;YAAE,OAAO,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACzD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;QACnF,OAAO,KAAK,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS,CAAC;IACnD,CAAC,CAAC,CAAC;AACL,CAAC;AA6CD,MAAM,OAAO,gBAAgB;IAC3B,IAAI,GAAG,cAAc,CAAC;IAEb,gCAAgC,GAAG,IAAI,CAAC;IAEhC,cAAc,GAAG,MAAM,CAAC,sBAAsB,CAAC,CAAC;IAChD,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAC7B,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;IACxC,cAAc,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAC3C,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC5B,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IAC1B,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;IAChD,iGAAiG;IAChF,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IAC/C,sGAAsG;IACrF,QAAQ,GAAG,IAAI,OAAO,EAAU,CAAC;IAClD,iFAAiF;IAC9D,QAAQ,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAEzC,QAAQ,GAAG,eAAe,CAAC,SAAS;iFAAC,CAAC;IACtC,OAAO,GAAe,EAAE,CAAC;IAClC,QAAQ,GAAoB,IAAI,CAAC;IACzC,2FAA2F;IACnF,UAAU,GAAG,CAAC,CAAC;IAEJ,IAAI,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAEtC,2EAA2E;IAE3E;;;OAGG;IACM,SAAS,GAAG,KAAK,CAAC,SAAS,iFAAI,SAAS,EAAE,eAAe,GAAG,CAAC;IACtE,6DAA6D;IAC5C,WAAW,GAAG,MAAM,CAA+B,IAAI,GAAG,EAAE;oFAAC,CAAC;IAC5D,QAAQ,GAAG,QAAQ,CACpC,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC;iFAC7E,CAAC;IACF,4CAA4C;IACnC,SAAS,GAAG,KAAK;6FAAmB,CAAC;IAC9C,sDAAsD;IAC7C,eAAe,GAAG,KAAK;mGAAmB,CAAC;IACpD,uEAAuE;IAC9D,WAAW,GAAG,KAAK;+FAAgC,CAAC;IAC7D,oEAAoE;IAC3D,gBAAgB,GAAG,KAAK;oGAAyD,CAAC;IAC3F,yEAAyE;IAChE,cAAc,GAAG,KAAK;kGAAyC,CAAC;IACzE,sEAAsE;IAC7D,gBAAgB,GAAG,KAAK,CAAC,SAAS,wFAAI,SAAS,EAAE,eAAe,GAAG,CAAC;IAE7E;QACE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACjC,8FAA8F;QAC9F,8DAA8D;QAC9D,IAAI,CAAC,cAAc,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAE1D,IAAI,CAAC,QAAQ,CAAC,MAAM,CAClB,IAAI,CAAC,IAAI,CAAC,aAAa,EACvB,aAAa,EACb,CAAC,KAAqC,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,WAAW,CAAC,CACnF,CAAC;QAEF,6FAA6F;QAC7F,4FAA4F;QAC5F,MAAM,CAAC,GAAG,EAAE;YACV,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChB,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;gBAAE,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;QAEH,4FAA4F;QAC5F,yFAAyF;QACzF,mEAAmE;QACnE,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;YACzD,+EAA+E;YAC/E,IAAI,KAAK,YAAY,aAAa,EAAE,CAAC;gBACnC,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAO,EAAE,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC;YACvE,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,4FAA4F;QAC5F,6FAA6F;QAC7F,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;QAChC,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACzD,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC;YACpC,aAAa,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;YAC/C,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;YACjC,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;SACxC,CAAC,CAAC;QAEH,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE;YAChC,eAAe,EAAE,CAAC;YAClB,cAAc,EAAE,CAAC;YACjB,SAAS,EAAE,WAAW,EAAE,CAAC;YACzB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACjC,KAAK,CAAC,MAAM,EAAE,CAAC;gBACf,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC;YACvB,CAAC;YACD,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;YACxB,2EAA2E;YAC3E,IAAI,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,EAAE,CAAC;gBAC/D,IAAI,CAAC,cAAc,CAAC,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxD,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,6EAA6E;IAC7E,kBAAkB;QAChB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,oBAAoB,EAAE,CAAC;IAC9B,CAAC;IAED;;;;OAIG;IACK,oBAAoB;QAC1B,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO;QAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1D,IAAI,CAAC,OAAO,EAAE,KAAK;YAAE,OAAO;QAC5B,IAAI,OAAO,CAAC,SAAS;YAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;;YAChE,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC1D,CAAC;IAED,kFAAkF;IAClF,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnD,CAAC;IAED,sDAAsD;IACtD,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,IAAI,CAAC;IACpC,CAAC;IAED,0EAA0E;IAE1E,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAC/D,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,WAAW,CAAC,CAAC,CAAE,IAAI,CAAC,QAAS,CAAC,GAAI,CAAC,QAAmB,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5E,CAAC;IAED,IAAI,cAAc;QAChB,OAAO,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,QAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACxD,CAAC;IAED,IAAI,kBAAkB;QACpB,OAAO,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC;IAClD,CAAC;IAED,4EAA4E;IAC5E,IAAI,qBAAqB;QACvB,OAAO,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,IAAI,CAAC;IACpC,CAAC;IAED,YAAY,CAAC,KAAqB,EAAE,mBAAwC;QAC1E,MAAM,SAAS,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAyB,CAAC;QACxF,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACzE,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAEnC,0FAA0F;QAC1F,2FAA2F;QAC3F,4FAA4F;QAC5F,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7D,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QAC3C,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAErD,IAAI,GAAsC,CAAC;QAC3C,IAAI,CAAC;YACH,GAAG,GAAG,eAAe,CAAC,SAAS,EAAE;gBAC/B,mBAAmB;gBACnB,eAAe,EAAE,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC;gBAClD,WAAW,EAAE,OAAkB;aAChC,CAAC,CAAC;YACH,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC7C,0FAA0F;YAC1F,wEAAwE;YACxE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC3C,4FAA4F;YAC5F,2FAA2F;YAC3F,4FAA4F;YAC5F,yFAAyF;YACzF,0FAA0F;YAC1F,yEAAyE;YACzE,GAAG,CAAC,iBAAiB,CAAC,aAAa,EAAE,CAAC;QACxC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;YAClC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAC/B,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;gBAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAC1E,MAAM,KAAK,CAAC;QACd,CAAC;QAED,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC;QAChB,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;QACpB,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC;QACvB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IAED;;;;;OAKG;IACH,UAAU;QACR,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO;QAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAS,CAAC;QAC7B,KAAK,CAAC,MAAM,EAAE,CAAC;QACf,KAAK,CAAC,MAAM,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;QACxB,KAAK,CAAC,GAAI,CAAC,OAAO,EAAE,CAAC;QACrB,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC;QACjB,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC;IACrB,CAAC;IAED;;;OAGG;IACH,MAAM;QACJ,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC5B,IAAI,CAAC,KAAK,EAAE,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;QAChG,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;QACtB,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACzB,8EAA8E;QAC9E,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC,GAAG,CAAC;IACnB,CAAC;IAED,MAAM,CAAC,GAA0B,EAAE,KAAqB;QACtD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAEnC,4FAA4F;QAC5F,kEAAkE;QAClE,IAAI,KAAK,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;YACtB,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;YACxE,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC7C,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC;QAClB,CAAC;QAED,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;QACpB,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC;QACvB,sFAAsF;QACtF,KAAK,CAAC,MAAM,EAAE,CAAC;QACf,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC3C,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACxB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IAED,2EAA2E;IAE3E;;;OAGG;IACK,OAAO,CAAC,KAAe,EAAE,GAAsC,EAAE,OAAgB;QACvF,KAAK,CAAC,MAAM,EAAE,CAAC;QACf,KAAK,CAAC,MAAM,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;QACxB,GAAG,EAAE,OAAO,EAAE,CAAC;QACf,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACrD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,OAAO,EAAE,QAAQ,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;YACrC,OAAO,CAAC,QAAQ,GAAG,KAAK,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QAClC,CAAC;IACH,CAAC;IAED,iGAAiG;IACzF,UAAU,CAAC,GAA0B,EAAE,KAAqB;QAClE,OAAO,IAAI,CAAC,MAAM,EAAE,4BAA4B,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC;IAC5F,CAAC;IAED;;;;;;;;OAQG;IACK,QAAQ;QACd,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,QAAQ,IAAI,EAAE,CAAC;QACxD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;YAClC,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;YAC9D,IAAI,KAAK,EAAE,CAAC;gBACV,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;gBACtB,SAAS;YACX,CAAC;YACD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;gBAChB,GAAG;gBACH,GAAG;gBACH,GAAG,EAAE,EAAE;gBACP,GAAG,EAAE,IAAI;gBACT,KAAK,EAAE,IAAI;gBACX,QAAQ,EAAE,KAAK;gBACf,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC;gBAChB,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC;gBACtB,OAAO,EAAE,IAAI,GAAG,EAAE;aACnB,CAAC,CAAC;YACH,4EAA4E;YAC5E,yFAAyF;YACzF,sFAAsF;YACtF,+EAA+E;YAC/E,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;gBAC9B,IAAI,MAAM,CAAC,IAAI,KAAK,GAAG;oBAAE,YAAY,CAAC,MAAM,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;QAED,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CACb,mFAAmF;gBACjF,sDAAsD,CACzD,CAAC;QACJ,CAAC;QACD,uFAAuF;QACvF,IAAI,KAAK;YAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED;;;;OAIG;IACK,IAAI,CAAC,KAAe,EAAE,GAAc;QAC1C,IAAI,KAAK,CAAC,GAAG,KAAK,GAAG;YAAE,OAAO;QAC9B,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC;QAChB,IAAI,KAAK,CAAC,GAAG;YAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IACzF,CAAC;IAED;;;;OAIG;IACK,QAAQ,CAAC,KAAqB;QACpC,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC;QAC/D,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC7B,KAAK,IAAI,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YAC/E,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QACzC,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;QAC1E,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CACb,8CAA8C,IAAI,mCAAmC;gBACnF,qEAAqE,CACxE,CAAC;QACJ,CAAC;QACD,4FAA4F;QAC5F,uDAAuD;QACvD,IAAI,MAAM;YAAE,YAAY,CAAC,MAAM,CAAC,CAAC;QACjC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,8DAA8D;IACtD,MAAM,CAAC,KAAe;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC3B,IAAI,IAAI,IAAI,IAAI,KAAK,KAAK;YAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO;YAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;QACrE,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,KAAK,CAAC,GAAG,CAAC;QAC1C,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,KAAe;QAC3B,IAAI,GAAG,GAAkB,IAAI,CAAC;QAC9B,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACpC,MAAM,OAAO,GAAG,OAAO,EAAE,CAAC;YAC1B,GAAG,KAAK,OAAO,CAAC;QAClB,CAAC;QACD,IAAI,GAAG,KAAK,IAAI;YAAE,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC;IACpC,CAAC;IAED;;;;;;OAMG;IACK,MAAM;QACZ,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;QAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC/B,IAAI,CAAC,KAAK,IAAI,CAAC,QAAQ,IAAI,QAAQ,KAAK,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC5E,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QAC/E,KAAK,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,8FAA8F;IACtF,MAAM,CAAC,GAAW;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC5B,IAAI,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,KAAK;YAAE,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC;IAC1D,CAAC;IAED;;;OAGG;IACK,aAAa,CAAC,GAAW;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAChC,OAAO,QAAQ,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9C,CAAC;IAED,iFAAiF;IACzE,SAAS,CAAC,GAAW;QAC3B,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QACtD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1C,CAAC;IAED,gFAAgF;IACxE,MAAM,CAAC,GAAW;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,CAAC,QAAQ,CAAC;IACnD,CAAC;IAED;;;;;OAKG;IACK,KAAK,CAAC,GAAW;QACvB,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC3B,IAAI,KAAK,GAAoB,IAAI,CAAC;QAClC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAChC,MAAM,MAAM,GAAG,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC;YACxF,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC;gBAAE,SAAS;YAC7E,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAAE,SAAS;YAC5E,KAAK,GAAG,KAAK,CAAC;QAChB,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,8FAA8F;IACtF,SAAS,CAAC,KAAe,EAAE,IAAY;QAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC;QAC9C,MAAM,MAAM,GAAG,GAAG;YAChB,CAAC,CAAC,CAAC,GAAG,CAAC;YACP,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,QAAQ,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;QACpF,OAAO,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC5D,CAAC;IAEO,OAAO,CAAC,KAAe;QAC7B,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,iBAAiB,EAAE;YACpE,iBAAiB,EAAE,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC;YACzC,cAAc,EAAE,IAAI,CAAC,UAAU;SAChC,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACK,cAAc,CAAC,SAAmC;QACxD,IAAI,CAAC,SAAS;YAAE,OAAO;QACvB,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC;QAEvC,6FAA6F;QAC7F,6FAA6F;QAC7F,+BAA+B;QAC/B,IAAI,SAAS,CAAC,YAAY,KAAK,iBAAiB;YAAE,OAAO;QAEzD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,CAChC,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC,iBAAiB,CAC9D,CAAC;QACF,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;YAAE,OAAO;QAE/E,4FAA4F;QAC5F,0DAA0D;QAC1D,0FAA0F;QAC1F,0FAA0F;QAC1F,KAAK,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CACrD,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EACvC,CAAC,KAAc,EAAE,EAAE;YACjB,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC7E,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YACjC,CAAC;YACD,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC,CACF,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACK,UAAU,CAAC,SAAuB;QACxC,OAAO,CACL,SAAS,CAAC,YAAY,KAAK,MAAM;YACjC,CAAC,SAAS,CAAC,UAAU;YACrB,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,oBAAoB,EAAE,CACtC,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACK,YAAY,CAAC,OAAgB;QACnC,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,EAAE,oBAAoB,EAAE;YAAE,OAAO;QAC7E,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC5B,6FAA6F;QAC7F,4FAA4F;QAC5F,kEAAkE;QAClE,IAAI,CAAC,cAAc,CAAC,YAAY,EAAE,CAAC;IACrC,CAAC;IAEO,KAAK,CAAC,KAAe;QAC3B,OAAO,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvF,CAAC;IAED,qDAAqD;IAC7C,MAAM,CAAC,KAAe;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY;aAC5C,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;aAClE,IAAI,CAAC,GAAG,CAAC,CAAC;QACb,OAAO,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IAC7D,CAAC;IAED;;;OAGG;IACK,cAAc,CAAC,KAAqB,EAAE,KAAe;QAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QACjD,MAAM,GAAG,GAAU;YACjB,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACjF,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE;gBAClB,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;gBACrE,OAAO,GAAG,EAAE,CACV,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE;oBACnC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;oBAC/B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;oBACpB,OAAO,IAAI,CAAC;gBACd,CAAC,CAAC,CAAC;YACP,CAAC;SACF,CAAC;QACF,OAAO,QAAQ,CAAC,MAAM,CAAC;YACrB,MAAM,EAAE,IAAI,CAAC,QAAQ;YACrB,SAAS,EAAE;gBACT,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE;gBAClF,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE;gBAClC,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,KAAK,EAAE;gBAC5C;oBACE,OAAO,EAAE,sBAAsB;oBAC/B,QAAQ,EAAE,IAAI,CAAC,cAAc,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ;iBACrE;aACF;SACF,CAAC,CAAC;IACL,CAAC;uGAhkBU,gBAAgB;2FAAhB,gBAAgB,y9CAZhB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,mDAgCvC,SAAS,6CAjC3C,gBAAgB;;2FAaf,gBAAgB;kBAf5B,SAAS;mBAAC;oBACT,QAAQ,EAAE,oBAAoB;oBAC9B,QAAQ,EAAE,gBAAgB;oBAC1B,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC;oBACnF,IAAI,EAAE;wBACJ,SAAS,EAAE,MAAM;wBACjB,gBAAgB,EAAE,YAAY;wBAC9B,mBAAmB,EAAE,qCAAqC;wBAC1D,kCAAkC,EAAE,iDAAiD;wBACrF,eAAe,EAAE,yCAAyC;wBAC1D,0BAA0B,EAAE,oBAAoB;wBAChD,wBAAwB,EAAE,kBAAkB;wBAC5C,2BAA2B,EAAE,oBAAoB;qBAClD;iBACF;0HAqB6C,SAAS","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 ChangeDetectorRef,\n Component,\n DestroyRef,\n ElementRef,\n ErrorHandler,\n Injector,\n Renderer2,\n computed,\n contentChildren,\n createComponent,\n effect,\n inject,\n input,\n signal,\n untracked,\n ViewContainerRef,\n type AfterContentInit,\n type ComponentRef,\n type EnvironmentInjector,\n type Type,\n type Signal,\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 Route,\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, screenKeyOf } from './native-tab.ts';\nimport { ownHost } from './own-host.ts';\nimport { markTabRoute } from './tab-routes.ts';\nimport { IN_TAB, type InTab } from './in-tab.ts';\nimport { taken, withoutPresented } from './presented-route.ts';\nimport { SVG_ICON_HOST } from './svg-icons.ts';\n\n/** A url without its query or fragment. */\nconst pathOnly = (url: string): string => url.split(/[?#]/, 1)[0]!;\n\n/**\n * Whether one of `routes` matches `segments`, whole or up to lazy children not loaded yet, which a\n * route that took a static segment of its own is taken to lead to. A parameter alone is not: it\n * takes any segment, pages outside the bar included, and its children may match none of the rest.\n */\nfunction reaches(routes: readonly Route[], segments: readonly string[]): boolean {\n return routes.some((route) => {\n const count = taken(route, segments);\n if (count === null) return false;\n const rest = segments.slice(count);\n if (rest.length === 0) return true;\n if (route.children) return reaches(route.children, rest);\n const named = route.path!.split('/').some((part) => part && !part.startsWith(':'));\n return named && route.loadChildren !== undefined;\n });\n}\n\ninterface TabEntry {\n /** The element in the bar now: an `@if` can take it away and bring another back. */\n 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 /** What the tab's stacks dismiss when another tab comes in front: see `IN_TAB`. */\n readonly leaving: Set<() => string | null>;\n}\n\n/** What `tabSelected` carries. Only these fields matter here; the rest is diagnostics. */\ninterface TabSelection {\n readonly selectedScreenKey: string;\n readonly provenance: number;\n /** `'user'` for a tap. Native reports the changes it was asked for too, under other names. */\n readonly actionOrigin?: string;\n /** Set when the user tapped the tab already in front, which is not a tap back. */\n readonly isRepeated?: boolean;\n}\n\n@Component({\n selector: 'native-tabs-outlet',\n template: '<ng-content />',\n providers: [{ provide: SVG_ICON_HOST, useFactory: () => inject(ViewContainerRef) }],\n host: {\n '[style]': 'fill',\n '[tabBarHidden]': 'hidesBar()',\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 changeDetector = inject(ChangeDetectorRef);\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 /**\n * Hide the bar without unmounting the tabs, for a screen that wants the whole window. Unset, the\n * bar is hidden while the page in front of the tab in front has `<native-header tabBarHidden>`.\n */\n readonly barHidden = input(undefined, { transform: optionalBoolean });\n /** What pages have asked of the bar: see `InTab.hideBar`. */\n private readonly barRequests = signal<ReadonlySet<Signal<boolean>>>(new Set());\n protected readonly hidesBar = computed(\n () => this.barHidden() ?? [...this.barRequests()].some((hidden) => hidden()),\n );\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 // An `@if` that takes a tab away and brings it back makes a new element: its page follows it\n // at once, since the tab may be the one showing, with no tap or navigation to read them on.\n effect(() => {\n this.declared();\n if (this.entries.length > 0) untracked(() => this.readTabs());\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 // Without a page presented over the bar, which is no part of where the tab is.\n if (event instanceof NavigationEnd) {\n this.follow(withoutPresented(this.router!, event.urlAfterRedirects));\n }\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 back = inject(NativeBack);\n const unsubscribeBack = back.handle(() => this.goBack());\n const unsubscribeBar = back.addTabBar({\n unopenedTabOf: (url) => this.unopenedTabOf(url),\n behind: (url) => this.behind(url),\n coveredAt: (url) => this.coveredAt(url),\n });\n\n inject(DestroyRef).onDestroy(() => {\n unsubscribeBack();\n unsubscribeBar();\n following?.unsubscribe();\n for (const entry of this.entries) {\n entry.unbind();\n entry.ref?.destroy();\n }\n this.entries.length = 0;\n // Only while it is this outlet's, as for a stack: see `NativeStackOutlet`.\n if (this.parentContexts.getContext(this.name)?.outlet === this) {\n this.parentContexts.onChildOutletDestroyed(this.name);\n }\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 this.activateCurrentRoute();\n }\n\n /**\n * The route the router is already on, for an outlet created after the navigation that reached\n * it, as `NativeStackOutlet` takes its own: a tab bar held behind a condition until a session\n * is ready. Once the tabs are read, since activating one needs to know which they are.\n */\n private activateCurrentRoute(): void {\n if (this.isActivated) return;\n const context = this.parentContexts.getContext(this.name);\n if (!context?.route) return;\n if (context.attachRef) this.attach(context.attachRef, context.route);\n else this.activateWith(context.route, context.injector);\n }\n\n /** The tabs in the bar, in the order they were first in it. 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),\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 /**\n * Destroy the tab page in front: nothing once the router has detached it, as Angular's own\n * outlet does nothing then. A tab under a route with no component of its own, a `loadChildren`\n * wrapper or a group, has the router detach the page and then deactivate this same outlet, and\n * that page is the tab, kept for when it is selected again.\n */\n deactivate(): void {\n if (!this.isActivated) return;\n const entry = this.selected!;\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, adding any that appeared since\n * the last read, as one an `@if` shows once a feature flag turns on, and following one that was\n * taken away and brought back.\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 const first = this.entries.length === 0;\n const children = this.route.routeConfig?.children ?? [];\n for (const tab of this.declared()) {\n const key = tab.path();\n const known = this.entries.find((entry) => entry.key === key);\n if (known) {\n this.move(known, tab);\n continue;\n }\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 leaving: new Set(),\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 if (first) this.request(this.entries[0]!);\n return this.entries;\n }\n\n /**\n * Give an entry the `<native-tab>` now declared for its path, when that is not the one it was\n * read with: an `@if` that took the tab away and brought it back made a new element, with a new\n * screen. The page goes over to that screen as it is, so the tab comes back where it was left.\n */\n private move(entry: TabEntry, tab: NativeTab): void {\n if (entry.tab === tab) return;\n entry.tab = tab;\n if (entry.ref) this.renderer.appendChild(tab.screen, entry.ref.location.nativeElement);\n }\n\n /**\n * The tab `route` is the page of, by its path from this outlet's route down to it. A route with\n * no component above the page is part of that path: a `loadChildren` wrapper takes the tab's\n * path and leaves `''` to the page under it, and a group is a `''` of its own.\n */\n private entryFor(route: ActivatedRoute): TabEntry {\n const config = route.routeConfig ?? route.snapshot.routeConfig;\n const paths = [config?.path];\n for (let above = route.parent; above && !above.component; above = above.parent) {\n paths.unshift(above.routeConfig?.path);\n }\n const path = paths.filter(Boolean).join('/');\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 // Under a wrapper the page's config is not one of the children `readTabs` marked, and it is\n // the one the reuse strategy is asked to detach whole.\n if (config) markTabRoute(config);\n return entry;\n }\n\n /** Remember where this tab is, and tell native to show it. */\n private select(entry: TabEntry): void {\n const left = this.selected;\n if (left && left !== entry) this.leave(left);\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 * Another tab came in front of `entry`: its stacks dismiss what they presented, and it is\n * remembered at the page beneath, where the outermost stack that dismissed something is left.\n */\n private leave(entry: TabEntry): void {\n let url: string | null = null;\n for (const dismiss of entry.leaving) {\n const beneath = dismiss();\n url ??= beneath;\n }\n if (url !== null) entry.url = url;\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 key = this.declared()[0]?.path();\n const first = this.entries.find((entry) => entry.key === key);\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(this.urlOf(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 && this.tabOf(url) === entry) entry.url = url;\n }\n\n /**\n * The url of the tab `url` is a page inside, when nothing has opened that tab: the tab's own\n * first screen, which a push into the tab from outside it shows first.\n */\n private unopenedTabOf(url: string): string | null {\n const entry = this.tabOf(url);\n if (!entry || entry.ref) return null;\n const root = this.pathOf(entry);\n return pathOnly(url) === root ? null : root;\n }\n\n /** Where the tab `url` is in was left, while a screen over the bar covers it. */\n private coveredAt(url: string): string | null {\n if (this.injector.get(SCREEN_IN_FRONT)()) return null;\n const entry = this.tabOf(url);\n return entry ? this.urlOf(entry) : null;\n }\n\n /** Whether `url` is a tab other than the one in front, or a page inside one. */\n private behind(url: string): boolean {\n const entry = this.tabOf(url);\n return entry !== null && entry !== this.selected;\n }\n\n /**\n * The tab `url` is in: the one with the longest url that starts it. A tab at `''` has the bar's\n * own url, which at the root starts every url, pages outside the bar included, so it takes only\n * a url its routes lead to, as far as they are loaded. A wildcard or a custom matcher is not\n * followed, as `taken` follows neither: a page only one of them shows is in no tab.\n */\n private tabOf(url: string): TabEntry | null {\n const path = pathOnly(url);\n let found: TabEntry | null = null;\n for (const entry of this.entries) {\n const root = this.pathOf(entry);\n const inside = path === root || path.startsWith(root.endsWith('/') ? root : `${root}/`);\n if (!inside || (found && this.pathOf(found).length >= root.length)) continue;\n if (!entry.key && !this.leadsInto(entry, path.slice(root.length))) continue;\n found = entry;\n }\n return found;\n }\n\n /** Whether the routes of the tab at `''` lead to `rest`, the path under the bar's own url. */\n private leadsInto(entry: TabEntry, rest: string): boolean {\n const segments = rest.split('/').filter(Boolean);\n const own = entry.route?.snapshot.routeConfig;\n const routes = own\n ? [own]\n : (this.route.routeConfig?.children ?? []).filter((config) => config.path === '');\n return segments.length === 0 || reaches(routes, segments);\n }\n\n private request(entry: TabEntry): void {\n this.renderer.setProperty(this.host.nativeElement, 'navStateRequest', {\n selectedScreenKey: screenKeyOf(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 // Native answering a request of ours is not a switch to follow. The router made the request,\n // and an answer that arrives after a later request, such as a cold-start link's, names a tab\n // the router has already left.\n if (selection.actionOrigin === 'programmatic-js') return;\n\n const entry = this.readTabs().find(\n (tab) => screenKeyOf(tab.key) === selection.selectedScreenKey,\n );\n if (!entry || (entry === this.selected && !this.tappedBack(selection))) 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(this.urlOf(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 * Whether the user tapped the tab in front while a navigation is running: back from the tab that\n * navigation is still loading, so the tab in front is where it is to end. A selection native\n * reports because the outlet asked for it is not a tap, and cancels nothing. Nor does a tap on\n * the tab already in front (native reports it as repeated): no other tab was tapped first, so a\n * navigation running then is one from code, or a push inside the tab, and is left to finish.\n */\n private tappedBack(selection: TabSelection): boolean {\n return (\n selection.actionOrigin === 'user' &&\n !selection.isRepeated &&\n !!this.router?.getCurrentNavigation()\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 // A failed navigation ends in a promise callback, which schedules no change detection, and a\n // prop reaches native only with the commit at the end of a pass. Without one the bar stayed\n // on the tab that failed until something else happened to render.\n this.changeDetector.markForCheck();\n }\n\n private urlOf(entry: TabEntry): string {\n return entry.url && this.tabOf(entry.url) === entry ? entry.url : this.pathOf(entry);\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 /**\n * As the stack outlet's: the route, the outlet contexts, and whether the tab is showing. And the\n * tab itself, for its stacks to hear when another comes in front.\n */\n private outletInjector(route: ActivatedRoute, entry: TabEntry): Injector {\n const outer = this.injector.get(SCREEN_IN_FRONT);\n const tab: InTab = {\n onLeave: (leave) => (entry.leaving.add(leave), () => entry.leaving.delete(leave)),\n hideBar: (hidden) => {\n this.barRequests.update((requests) => new Set(requests).add(hidden));\n return () =>\n this.barRequests.update((requests) => {\n const rest = new Set(requests);\n rest.delete(hidden);\n return rest;\n });\n },\n };\n return Injector.create({\n parent: this.injector,\n providers: [\n { provide: SCREEN_IN_FRONT, useValue: computed(() => outer() && entry.inFront()) },\n { provide: IN_TAB, useValue: tab },\n { provide: ActivatedRoute, useValue: route },\n {\n provide: ChildrenOutletContexts,\n useValue: this.parentContexts.getOrCreateContext(this.name).children,\n },\n ],\n });\n }\n}\n"]}
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 ChangeDetectorRef,\n Component,\n DestroyRef,\n ElementRef,\n ErrorHandler,\n Injector,\n Renderer2,\n computed,\n contentChildren,\n createComponent,\n effect,\n inject,\n input,\n signal,\n untracked,\n ViewContainerRef,\n type AfterContentInit,\n type ComponentRef,\n type EnvironmentInjector,\n type Type,\n type Signal,\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 Route,\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, screenKeyOf } from './native-tab.ts';\nimport { ownHost } from './own-host.ts';\nimport { markTabRoute } from './tab-routes.ts';\nimport { IN_TAB, type InTab } from './in-tab.ts';\nimport { PRESENTED, taken, withoutPresented } from './presented-route.ts';\nimport { SVG_ICON_HOST } from './svg-icons.ts';\nimport { primarySegments } from './url-commands.ts';\n\nconst segmentsOf = (path: string): string[] => path.split('/').filter(Boolean);\n\n/**\n * Whether one of `routes` matches `segments`, whole or up to lazy children not loaded yet, which a\n * route that took a static segment of its own is taken to lead to. A parameter alone is not: it\n * takes any segment, pages outside the bar included, and its children may match none of the rest.\n */\nfunction reaches(routes: readonly Route[], segments: readonly string[]): boolean {\n return routes.some((route) => {\n const count = taken(route, segments);\n if (count === null) return false;\n const rest = segments.slice(count);\n if (rest.length === 0) return true;\n if (route.children) return reaches(route.children, rest);\n const named = route.path!.split('/').some((part) => part && !part.startsWith(':'));\n return named && route.loadChildren !== undefined;\n });\n}\n\ninterface TabEntry {\n /** The element in the bar now: an `@if` can take it away and bring another back. */\n 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 /** What the tab's stacks dismiss when another tab comes in front: see `IN_TAB`. */\n readonly leaving: Set<() => string | null>;\n}\n\n/** What `tabSelectionPrevented` carries: the tab tapped, which native left unselected. */\ninterface TabSelectionPrevented {\n readonly preventedScreenKey: string;\n readonly provenance: number;\n}\n\n/** Whether matching or activating a route, or a page under it, runs a guard. */\nfunction guardedAt(route: ActivatedRoute | null): boolean {\n if (!route) return false;\n const guards = (config: Route | null) =>\n !!config &&\n !!(config.canActivate?.length || config.canActivateChild?.length || config.canMatch?.length);\n const snapshot = route.snapshot as Partial<ActivatedRoute['snapshot']> | undefined;\n if (snapshot?.pathFromRoot?.some((each) => guards(each.routeConfig))) return true;\n for (let below = snapshot?.firstChild; below; below = below.firstChild) {\n if (guards(below.routeConfig)) return true;\n }\n return false;\n}\n\n/** What `tabSelected` carries. Only these fields matter here; the rest is diagnostics. */\ninterface TabSelection {\n readonly selectedScreenKey: string;\n readonly provenance: number;\n /** `'user'` for a tap. Native reports the changes it was asked for too, under other names. */\n readonly actionOrigin?: string;\n /** Set when the user tapped the tab already in front, which is not a tap back. */\n readonly isRepeated?: boolean;\n}\n\n@Component({\n selector: 'native-tabs-outlet',\n template: '<ng-content />',\n providers: [{ provide: SVG_ICON_HOST, useFactory: () => inject(ViewContainerRef) }],\n host: {\n '[style]': 'fill',\n '[tabBarHidden]': 'hidesBar()',\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 changeDetector = inject(ChangeDetectorRef);\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 /**\n * Hide the bar without unmounting the tabs, for a screen that wants the whole window. Unset, the\n * bar is hidden while the page in front of the tab in front has `<native-header tabBarHidden>`.\n */\n readonly barHidden = input(undefined, { transform: optionalBoolean });\n /** What pages have asked of the bar: see `InTab.hideBar`. */\n private readonly barRequests = signal<ReadonlySet<Signal<boolean>>>(new Set());\n protected readonly hidesBar = computed(\n () => this.barHidden() ?? [...this.barRequests()].some((hidden) => hidden()),\n );\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 // A tap on a tab native was told not to select: see `guardSelection`. The router decides.\n this.renderer.listen(\n this.host.nativeElement,\n 'tabSelectionPrevented',\n (event: { nativeEvent?: TabSelectionPrevented }) => {\n const prevented = event?.nativeEvent;\n if (!prevented) return;\n this.onNativeSelect({\n selectedScreenKey: prevented.preventedScreenKey,\n provenance: prevented.provenance,\n actionOrigin: 'user',\n });\n },\n );\n\n // An `@if` that takes a tab away and brings it back makes a new element: its page follows it\n // at once, since the tab may be the one showing, with no tap or navigation to read them on.\n effect(() => {\n this.declared();\n if (this.entries.length > 0) untracked(() => this.readTabs());\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 // Without a page presented over the bar, which is no part of where the tab is.\n if (event instanceof NavigationEnd) {\n this.follow(withoutPresented(this.router!, event.urlAfterRedirects));\n }\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 back = inject(NativeBack);\n const unsubscribeBack = back.handle(() => this.goBack());\n const unsubscribeBar = back.addTabBar({\n unopenedTabOf: (url) => this.unopenedTabOf(url),\n behind: (url) => this.behind(url),\n coveredAt: (url) => this.coveredAt(url),\n });\n\n inject(DestroyRef).onDestroy(() => {\n unsubscribeBack();\n unsubscribeBar();\n following?.unsubscribe();\n for (const entry of this.entries) {\n entry.unbind();\n entry.ref?.destroy();\n }\n this.entries.length = 0;\n // Only while it is this outlet's, as for a stack: see `NativeStackOutlet`.\n if (this.parentContexts.getContext(this.name)?.outlet === this) {\n this.parentContexts.onChildOutletDestroyed(this.name);\n }\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 this.activateCurrentRoute();\n }\n\n /**\n * The route the router is already on, for an outlet created after the navigation that reached\n * it, as `NativeStackOutlet` takes its own: a tab bar held behind a condition until a session\n * is ready. Once the tabs are read, since activating one needs to know which they are.\n */\n private activateCurrentRoute(): void {\n if (this.isActivated) return;\n const context = this.parentContexts.getContext(this.name);\n if (!context?.route) return;\n if (context.attachRef) this.attach(context.attachRef, context.route);\n else this.activateWith(context.route, context.injector);\n }\n\n /** The tabs in the bar, in the order they were first in it. 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),\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 /**\n * Destroy the tab page in front: nothing once the router has detached it, as Angular's own\n * outlet does nothing then. A tab under a route with no component of its own, a `loadChildren`\n * wrapper or a group, has the router detach the page and then deactivate this same outlet, and\n * that page is the tab, kept for when it is selected again.\n */\n deactivate(): void {\n if (!this.isActivated) return;\n const entry = this.selected!;\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 this.guardSelection(entry, guardedAt(entry.route));\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, adding any that appeared since\n * the last read, as one an `@if` shows once a feature flag turns on, and following one that was\n * taken away and brought back.\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 const first = this.entries.length === 0;\n const children = this.route.routeConfig?.children ?? [];\n for (const tab of this.declared()) {\n const key = tab.path();\n const known = this.entries.find((entry) => entry.key === key);\n if (known) {\n this.move(known, tab);\n continue;\n }\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 leaving: new Set(),\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 if (first) this.request(this.entries[0]!);\n return this.entries;\n }\n\n /**\n * Give an entry the `<native-tab>` now declared for its path, when that is not the one it was\n * read with: an `@if` that took the tab away and brought it back made a new element, with a new\n * screen. The page goes over to that screen as it is, so the tab comes back where it was left.\n */\n private move(entry: TabEntry, tab: NativeTab): void {\n if (entry.tab === tab) return;\n entry.tab = tab;\n this.guardSelection(entry, entry.detached && guardedAt(entry.route));\n if (entry.ref) this.renderer.appendChild(tab.screen, entry.ref.location.nativeElement);\n }\n\n /**\n * The tab `route` is the page of, by its path from this outlet's route down to it. A route with\n * no component above the page is part of that path: a `loadChildren` wrapper takes the tab's\n * path and leaves `''` to the page under it, and a group is a `''` of its own.\n */\n private entryFor(route: ActivatedRoute): TabEntry {\n const config = route.routeConfig ?? route.snapshot.routeConfig;\n const paths = [config?.path];\n for (let above = route.parent; above && !above.component; above = above.parent) {\n paths.unshift(above.routeConfig?.path);\n }\n const path = paths.filter(Boolean).join('/');\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 // Under a wrapper the page's config is not one of the children `readTabs` marked, and it is\n // the one the reuse strategy is asked to detach whole.\n if (config) markTabRoute(config);\n return entry;\n }\n\n /** Remember where this tab is, and tell native to show it. */\n /**\n * Whether native selects a tab on a tap or leaves that to the router. A tab kept from a visit\n * behind a guard is left to it: native would show the page it holds before the guard has run,\n * and only take it back once the guard said no. One in front, or with no guard, native selects.\n * react-native-screens before 4.30 has no such prop, and selects as before.\n */\n private guardSelection(entry: TabEntry, guarded: boolean): void {\n this.renderer.setProperty(entry.tab.screen, 'preventNativeSelection', guarded);\n }\n\n private select(entry: TabEntry): void {\n const left = this.selected;\n if (left && left !== entry) this.leave(left);\n this.selected = entry;\n this.guardSelection(entry, false);\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 * Another tab came in front of `entry`: its stacks dismiss what they presented, and it is\n * remembered at the page beneath, where the outermost stack that dismissed something is left.\n */\n private leave(entry: TabEntry): void {\n let url: string | null = null;\n for (const dismiss of entry.leaving) {\n const beneath = dismiss();\n url ??= beneath;\n }\n if (url !== null) entry.url = url;\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 key = this.declared()[0]?.path();\n const first = this.entries.find((entry) => entry.key === key);\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(this.urlOf(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 && this.tabOf(url) === entry) entry.url = url;\n }\n\n /**\n * The url of the tab `url` is a page inside, when nothing has opened that tab: the tab's own\n * first screen, which a push into the tab from outside it shows first.\n */\n private unopenedTabOf(url: string): string | null {\n const entry = this.tabOf(url);\n if (!entry || entry.ref) return null;\n return this.under(entry, url)?.length === 0 ? null : this.pathOf(entry);\n }\n\n /** Where the tab `url` is in was left, while a screen over the bar covers it. */\n private coveredAt(url: string): string | null {\n if (this.injector.get(SCREEN_IN_FRONT)()) return null;\n const entry = this.tabOf(url);\n return entry ? this.urlOf(entry) : null;\n }\n\n /** Whether `url` is a tab other than the one in front, or a page inside one. */\n private behind(url: string): boolean {\n const entry = this.tabOf(url);\n return entry !== null && entry !== this.selected;\n }\n\n /**\n * The tab `url` is in: the one with the longest url that starts it. A tab at `''` has the bar's\n * own url, which at the root starts every url, pages outside the bar included, so it takes only\n * a url its routes lead to, as far as they are loaded. A wildcard or a custom matcher is not\n * followed, as `taken` follows neither: a page only one of them shows is in no tab.\n */\n private tabOf(url: string): TabEntry | null {\n let found: TabEntry | null = null;\n let depth = -1;\n for (const entry of this.entries) {\n const rest = this.under(entry, url);\n const own = segmentsOf(entry.key).length;\n if (!rest || own <= depth) continue;\n if (!entry.key && !this.leadsInto(entry, rest)) continue;\n found = entry;\n depth = own;\n }\n return found;\n }\n\n /**\n * The segments of `url` under the tab, or null when `url` is not inside it. The bar's own\n * segments are compared as the router writes them, matrix parameters included; the tab's own by\n * path alone, as a url can give them matrix parameters of their own, `library;sort=a`. Parsed,\n * and only the primary outlet's segments read, so a named outlet open beside the tab,\n * `library(popup:compose)`, is not taken for part of its path. A url with a page presented over\n * the app is that page's, which is in no tab.\n */\n private under(entry: TabEntry, url: string): string[] | null {\n if (!this.router || this.router.parseUrl(url).root.children[PRESENTED]) return null;\n const segments = primarySegments(this.router, url);\n const parent = this.parentSegments();\n const own = segmentsOf(entry.key);\n if (segments.length < parent.length + own.length) return null;\n if (parent.some((segment, index) => segments[index]!.toString() !== segment)) return null;\n if (own.some((segment, index) => segments[parent.length + index]!.path !== segment)) {\n return null;\n }\n return segments.slice(parent.length + own.length).map((segment) => segment.path);\n }\n\n /** Whether the routes of the tab at `''` lead to `rest`, the segments under the bar's own url. */\n private leadsInto(entry: TabEntry, rest: string[]): boolean {\n const own = entry.route?.snapshot.routeConfig;\n const routes = own\n ? [own]\n : (this.route.routeConfig?.children ?? []).filter((config) => config.path === '');\n return rest.length === 0 || reaches(routes, rest);\n }\n\n private request(entry: TabEntry): void {\n this.renderer.setProperty(this.host.nativeElement, 'navStateRequest', {\n selectedScreenKey: screenKeyOf(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 // Native answering a request of ours is not a switch to follow. The router made the request,\n // and an answer that arrives after a later request, such as a cold-start link's, names a tab\n // the router has already left.\n if (selection.actionOrigin === 'programmatic-js') return;\n\n const entry = this.readTabs().find(\n (tab) => screenKeyOf(tab.key) === selection.selectedScreenKey,\n );\n if (!entry || (entry === this.selected && !this.tappedBack(selection))) 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(this.urlOf(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 * Whether the user tapped the tab in front while a navigation is running: back from the tab that\n * navigation is still loading, so the tab in front is where it is to end. A selection native\n * reports because the outlet asked for it is not a tap, and cancels nothing. Nor does a tap on\n * the tab already in front (native reports it as repeated): no other tab was tapped first, so a\n * navigation running then is one from code, or a push inside the tab, and is left to finish.\n */\n private tappedBack(selection: TabSelection): boolean {\n return (\n selection.actionOrigin === 'user' &&\n !selection.isRepeated &&\n !!this.router?.getCurrentNavigation()\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 // A failed navigation ends in a promise callback, which schedules no change detection, and a\n // prop reaches native only with the commit at the end of a pass. Without one the bar stayed\n // on the tab that failed until something else happened to render.\n this.changeDetector.markForCheck();\n }\n\n private urlOf(entry: TabEntry): string {\n return entry.url && this.tabOf(entry.url) === entry ? entry.url : this.pathOf(entry);\n }\n\n /**\n * A tab's own url, from the outlet's route down. Each segment as the router writes it in a url,\n * escaped and with its matrix parameters, `s%C3%A3o-paulo;lang=pt`, which is what it is\n * compared with.\n */\n private pathOf(entry: TabEntry): string {\n return `/${[...this.parentSegments(), entry.key].filter(Boolean).join('/')}`;\n }\n\n /** The outlet's route's segments, from the root down, as `pathOf` writes them. */\n private parentSegments(): string[] {\n return this.route.snapshot.pathFromRoot.flatMap((snapshot) =>\n snapshot.url.map((segment) => segment.toString()),\n );\n }\n\n /**\n * As the stack outlet's: the route, the outlet contexts, and whether the tab is showing. And the\n * tab itself, for its stacks to hear when another comes in front.\n */\n private outletInjector(route: ActivatedRoute, entry: TabEntry): Injector {\n const outer = this.injector.get(SCREEN_IN_FRONT);\n const tab: InTab = {\n onLeave: (leave) => (entry.leaving.add(leave), () => entry.leaving.delete(leave)),\n hideBar: (hidden) => {\n this.barRequests.update((requests) => new Set(requests).add(hidden));\n return () =>\n this.barRequests.update((requests) => {\n const rest = new Set(requests);\n rest.delete(hidden);\n return rest;\n });\n },\n };\n return Injector.create({\n parent: this.injector,\n providers: [\n { provide: SCREEN_IN_FRONT, useValue: computed(() => outer() && entry.inFront()) },\n { provide: IN_TAB, useValue: tab },\n { provide: ActivatedRoute, useValue: route },\n {\n provide: ChildrenOutletContexts,\n useValue: this.parentContexts.getOrCreateContext(this.name).children,\n },\n ],\n });\n }\n}\n"]}
@@ -9,6 +9,7 @@
9
9
  * navigation, so the page's guards, resolvers, lazy component and params are what they are in its
10
10
  * tab, and a back goes through history as any other does.
11
11
  */
12
+ import { type EnvironmentInjector } from '@angular/core';
12
13
  import { type NavigationExtras, type Route, type Router, type UrlTree } from '@angular/router';
13
14
  /** The root outlet a page of another tab is presented in. */
14
15
  export declare const PRESENTED = "presented";
@@ -24,7 +25,7 @@ export declare function taken(route: Route, segments: readonly string[]): number
24
25
  * The commands that present the page at `path` in the root's presented outlet, having given its
25
26
  * route a copy there, or null when the config is not one this follows.
26
27
  */
27
- export declare function presentedCommands(router: Router, path: string): Promise<unknown[] | null>;
28
+ export declare function presentedCommands(router: Router, path: string, root?: EnvironmentInjector): Promise<unknown[] | null>;
28
29
  /** `url` without the page presented over it: where the app is, under the page. */
29
30
  export declare function withoutPresented(router: Router, url: string): string;
30
31
  /**
@@ -9,6 +9,7 @@
9
9
  * navigation, so the page's guards, resolvers, lazy component and params are what they are in its
10
10
  * tab, and a back goes through history as any other does.
11
11
  */
12
+ import { createEnvironmentInjector, runInInjectionContext, } from '@angular/core';
12
13
  import { PRIMARY_OUTLET, } from '@angular/router';
13
14
  import { primarySegments, segmentCommands } from "./url-commands.js";
14
15
  /** The root outlet a page of another tab is presented in. */
@@ -97,9 +98,15 @@ async function chainTo(routes, segments) {
97
98
  * resolvers, under the whole path, with the guards and providers of the routes it sat inside.
98
99
  * Their components are left out: the tab bar and the tab's stack are not what is presented.
99
100
  */
100
- function presentedCopy(chain) {
101
+ function presentedCopy(chain, root) {
101
102
  const page = chain.at(-1);
102
103
  const above = chain.slice(0, -1);
104
+ const scopeOf = root ? scopes(above, root) : undefined;
105
+ // An ancestor's guard is run where it was: the copy has the providers of every route, and a
106
+ // page's override of one that guard reads would otherwise decide it.
107
+ const guarded = (route, level, kind) => (route[kind] ?? []).map((guard) => root && chain.slice(level + 1).some((below) => below.providers?.length)
108
+ ? scoped(guard, kind, () => scopeOf(level))
109
+ : guard);
103
110
  return {
104
111
  ...page,
105
112
  // Its own children are in the copy by now, where they were lazy.
@@ -111,9 +118,9 @@ function presentedCopy(chain) {
111
118
  pathMatch: undefined,
112
119
  outlet: PRESENTED,
113
120
  canActivate: [
114
- ...above.flatMap((route) => [
115
- ...(route.canActivate ?? []),
116
- ...(route.canActivateChild ?? []),
121
+ ...above.flatMap((route, level) => [
122
+ ...guarded(route, level, 'canActivate'),
123
+ ...guarded(route, level, 'canActivateChild'),
117
124
  ]),
118
125
  ...(page.canActivate ?? []),
119
126
  ],
@@ -122,11 +129,45 @@ function presentedCopy(chain) {
122
129
  data: Object.assign({}, ...above.map((route) => route.data), page.data),
123
130
  };
124
131
  }
132
+ /**
133
+ * The injector each route above the page made, made when one of their guards first asks: its own
134
+ * providers over those above it, the first over `root`.
135
+ * ponytail: `root` stands for what a root route's injector is under; an ancestor inside a lazily
136
+ * loaded NgModule leaves that module's providers out.
137
+ */
138
+ function scopes(above, root) {
139
+ const made = [];
140
+ const scopeOf = (level) => {
141
+ if (level < 0)
142
+ return root;
143
+ const providers = above[level].providers;
144
+ return (made[level] ??= providers?.length
145
+ ? createEnvironmentInjector(providers, scopeOf(level - 1))
146
+ : scopeOf(level - 1));
147
+ };
148
+ return scopeOf;
149
+ }
150
+ const NOT_FOUND = {};
151
+ /**
152
+ * A guard run in `scope` as Angular runs one: a class or token as what `scope` gives for it, a
153
+ * function in its injection context.
154
+ */
155
+ function scoped(guard, kind, scope) {
156
+ return (...args) => {
157
+ const injector = scope();
158
+ const found = injector.get(guard, NOT_FOUND);
159
+ const value = (found === NOT_FOUND ? guard : found);
160
+ const method = value[kind];
161
+ return typeof method === 'function'
162
+ ? method.apply(value, args)
163
+ : runInInjectionContext(injector, () => value(...args));
164
+ };
165
+ }
125
166
  /**
126
167
  * The commands that present the page at `path` in the root's presented outlet, having given its
127
168
  * route a copy there, or null when the config is not one this follows.
128
169
  */
129
- export async function presentedCommands(router, path) {
170
+ export async function presentedCommands(router, path, root) {
130
171
  // Parsed, so the routes are matched against decoded segments and the escapes are written once.
131
172
  const parsed = primarySegments(router, path);
132
173
  const segments = parsed.map((segment) => segment.path);
@@ -134,10 +175,10 @@ export async function presentedCommands(router, path) {
134
175
  const chain = await chainTo(config, segments);
135
176
  // Routes reset while lazy children loaded: the copy is made from the routes the router has.
136
177
  if (router.config !== config)
137
- return presentedCommands(router, path);
178
+ return presentedCommands(router, path, root);
138
179
  if (!chain || chain === STOP)
139
180
  return null;
140
- const copy = presentedCopy(chain);
181
+ const copy = presentedCopy(chain, root);
141
182
  const copied = router.config.some((route) => route.outlet === PRESENTED && route.path === copy.path);
142
183
  if (!copied)
143
184
  router.config.push(copy);