@ng-native/router 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +10 -0
  2. package/dist/file-routes.d.ts +83 -0
  3. package/dist/file-routes.js +359 -0
  4. package/dist/file-routes.js.map +1 -0
  5. package/dist/in-tab.d.ts +20 -0
  6. package/dist/in-tab.js +13 -0
  7. package/dist/in-tab.js.map +1 -0
  8. package/dist/index.d.ts +3 -0
  9. package/dist/index.js +3 -0
  10. package/dist/index.js.map +1 -1
  11. package/dist/markdown-page.d.ts +39 -0
  12. package/dist/markdown-page.js +56 -0
  13. package/dist/markdown-page.js.map +1 -0
  14. package/dist/native-header.d.ts +4 -0
  15. package/dist/native-header.js +17 -4
  16. package/dist/native-header.js.map +1 -1
  17. package/dist/native-platform-location.d.ts +5 -0
  18. package/dist/native-platform-location.js +4 -0
  19. package/dist/native-platform-location.js.map +1 -1
  20. package/dist/native-stack-outlet.d.ts +6 -0
  21. package/dist/native-stack-outlet.js +18 -0
  22. package/dist/native-stack-outlet.js.map +1 -1
  23. package/dist/native-stack-reuse-strategy.d.ts +9 -0
  24. package/dist/native-stack-reuse-strategy.js +23 -4
  25. package/dist/native-stack-reuse-strategy.js.map +1 -1
  26. package/dist/native-tab.d.ts +6 -0
  27. package/dist/native-tab.js +11 -2
  28. package/dist/native-tab.js.map +1 -1
  29. package/dist/native-tabs-outlet.d.ts +29 -1
  30. package/dist/native-tabs-outlet.js +113 -28
  31. package/dist/native-tabs-outlet.js.map +1 -1
  32. package/dist/presented-route.d.ts +9 -1
  33. package/dist/presented-route.js +1 -1
  34. package/dist/presented-route.js.map +1 -1
  35. package/dist/provide-native-router.js +85 -2
  36. package/dist/provide-native-router.js.map +1 -1
  37. package/dist/route-parking.d.ts +30 -0
  38. package/dist/route-parking.js +60 -0
  39. package/dist/route-parking.js.map +1 -0
  40. package/dist/screen-header.d.ts +10 -0
  41. package/dist/screen-header.js +11 -0
  42. package/dist/screen-header.js.map +1 -0
  43. package/dist/screen-safe-area-view.d.ts +18 -0
  44. package/dist/screen-safe-area-view.js +74 -0
  45. package/dist/screen-safe-area-view.js.map +1 -0
  46. package/dist/screens.js +3 -2
  47. package/dist/screens.js.map +1 -1
  48. package/dist/tab-safe-area-view.d.ts +4 -11
  49. package/dist/tab-safe-area-view.js +8 -43
  50. package/dist/tab-safe-area-view.js.map +1 -1
  51. package/package.json +3 -3
@@ -0,0 +1,39 @@
1
+ /**
2
+ * A token `marked.lexer` made, as `<markdown [tokens]>` takes it. Typed here rather than imported
3
+ * from `marked`, so an app's types never need it.
4
+ */
5
+ interface MarkdownToken {
6
+ type: string;
7
+ raw: string;
8
+ [key: string]: any;
9
+ }
10
+ /** A Markdown page's file, for the component given to `fileRoutes` as `markdownPage`. */
11
+ export interface MarkdownPageFile<Attributes extends Record<string, any> = Record<string, any>> {
12
+ /** Its path from the pages folder: `about.md`, `guides/install.md`. */
13
+ readonly filename: string;
14
+ /** Its file name without `.md`; `index.md` is `''`. */
15
+ readonly slug: string;
16
+ /** The front matter. A date in it is its ISO string. */
17
+ readonly attributes: Attributes;
18
+ /** The Markdown after the front matter. */
19
+ readonly content: string;
20
+ /** `content` lexed by `marked`, for `<markdown [tokens]>`. */
21
+ readonly tokens: MarkdownToken[];
22
+ }
23
+ /**
24
+ * The route data key a Markdown page's file is under, for a package that routes `.md` pages itself,
25
+ * as `pageRoutes` from `@ng-native/analog` does: an app reads the file with `injectMarkdownPage()`.
26
+ */
27
+ export declare const MARKDOWN_PAGE = "ngNativeMarkdownPage";
28
+ /**
29
+ * The file of the Markdown page this component draws, in the component given to `fileRoutes`, or
30
+ * to `pageRoutes` from `@ng-native/analog`, as `markdownPage`:
31
+ * `{ filename, slug, attributes, content, tokens }`.
32
+ */
33
+ export declare function injectMarkdownPage<Attributes extends Record<string, any> = Record<string, any>>(): MarkdownPageFile<Attributes>;
34
+ /**
35
+ * A Markdown page's file, from the module Metro made of it, or that module's namespace, with
36
+ * `filename` its path from the pages folder. Throws, naming the file, for anything else.
37
+ */
38
+ export declare function markdownPageFile(filename: string, loaded: unknown): MarkdownPageFile;
39
+ export {};
@@ -0,0 +1,56 @@
1
+ /**
2
+ * A `.md` file routed as a page by `fileRoutes`: the file, as Metro made it a module, handed to the
3
+ * component the app gave as `markdownPage` through its route's data.
4
+ *
5
+ * The router does not draw Markdown, and does not import the package that does, so the app's
6
+ * component draws `tokens` with `<markdown>` from `@ng-native/components/markdown`. `pageRoutes`
7
+ * from `@ng-native/analog` routes a `.md` page with this file and this key too, so one
8
+ * `markdownPage` component draws it under either.
9
+ */
10
+ import { inject } from '@angular/core';
11
+ import { ActivatedRoute } from '@angular/router';
12
+ /**
13
+ * The route data key a Markdown page's file is under, for a package that routes `.md` pages itself,
14
+ * as `pageRoutes` from `@ng-native/analog` does: an app reads the file with `injectMarkdownPage()`.
15
+ */
16
+ export const MARKDOWN_PAGE = 'ngNativeMarkdownPage';
17
+ /**
18
+ * The file of the Markdown page this component draws, in the component given to `fileRoutes`, or
19
+ * to `pageRoutes` from `@ng-native/analog`, as `markdownPage`:
20
+ * `{ filename, slug, attributes, content, tokens }`.
21
+ */
22
+ export function injectMarkdownPage() {
23
+ const file = inject(ActivatedRoute).snapshot.data[MARKDOWN_PAGE];
24
+ if (!file) {
25
+ throw new Error('injectMarkdownPage() is for the markdownPage component fileRoutes or pageRoutes routes a ' +
26
+ '.md page to, and this route is not one.');
27
+ }
28
+ return file;
29
+ }
30
+ /**
31
+ * A Markdown page's file, from the module Metro made of it, or that module's namespace, with
32
+ * `filename` its path from the pages folder. Throws, naming the file, for anything else.
33
+ */
34
+ export function markdownPageFile(filename, loaded) {
35
+ const module = isMarkdownModule(loaded) ? loaded : loaded?.default;
36
+ if (!isMarkdownModule(module)) {
37
+ throw new Error(`${filename} is not the module @ng-native/metro makes of a .md file. Bundle the app with ` +
38
+ "withAngularNative from '@ng-native/metro/config.cjs', and test it with ngNative() from " +
39
+ "'@ng-native/testing/vitest'.");
40
+ }
41
+ const base = filename.split('/').pop().replace(/\.md$/, '');
42
+ return {
43
+ filename,
44
+ slug: base === 'index' ? '' : base,
45
+ attributes: module.attributes,
46
+ content: module.content,
47
+ tokens: module.tokens,
48
+ };
49
+ }
50
+ function isMarkdownModule(value) {
51
+ return (typeof value === 'object' &&
52
+ value !== null &&
53
+ typeof value.content === 'string' &&
54
+ Array.isArray(value.tokens));
55
+ }
56
+ //# sourceMappingURL=markdown-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-page.js","sourceRoot":"","sources":["../src/markdown-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AA0BjD;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,sBAAsB,CAAC;AAEpD;;;;GAIG;AACH,MAAM,UAAU,kBAAkB;IAGhC,MAAM,IAAI,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CACrB,CAAC;IAC3C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CACb,2FAA2F;YACzF,yCAAyC,CAC5C,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB,EAAE,MAAe;IAChE,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAE,MAAgC,EAAE,OAAO,CAAC;IAC9F,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,GAAG,QAAQ,+EAA+E;YACxF,yFAAyF;YACzF,8BAA8B,CACjC,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAG,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC7D,OAAO;QACL,QAAQ;QACR,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;QAClC,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,MAAM,EAAE,MAAM,CAAC,MAAM;KACtB,CAAC;AACJ,CAAC;AAQD,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,OAAQ,KAAwB,CAAC,OAAO,KAAK,QAAQ;QACrD,KAAK,CAAC,OAAO,CAAE,KAAwB,CAAC,MAAM,CAAC,CAChD,CAAC;AACJ,CAAC","sourcesContent":["/**\n * A `.md` file routed as a page by `fileRoutes`: the file, as Metro made it a module, handed to the\n * component the app gave as `markdownPage` through its route's data.\n *\n * The router does not draw Markdown, and does not import the package that does, so the app's\n * component draws `tokens` with `<markdown>` from `@ng-native/components/markdown`. `pageRoutes`\n * from `@ng-native/analog` routes a `.md` page with this file and this key too, so one\n * `markdownPage` component draws it under either.\n */\nimport { inject } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\n\n/**\n * A token `marked.lexer` made, as `<markdown [tokens]>` takes it. Typed here rather than imported\n * from `marked`, so an app's types never need it.\n */\ninterface MarkdownToken {\n type: string;\n raw: string;\n [key: string]: any;\n}\n\n/** A Markdown page's file, for the component given to `fileRoutes` as `markdownPage`. */\nexport interface MarkdownPageFile<Attributes extends Record<string, any> = Record<string, any>> {\n /** Its path from the pages folder: `about.md`, `guides/install.md`. */\n readonly filename: string;\n /** Its file name without `.md`; `index.md` is `''`. */\n readonly slug: string;\n /** The front matter. A date in it is its ISO string. */\n readonly attributes: Attributes;\n /** The Markdown after the front matter. */\n readonly content: string;\n /** `content` lexed by `marked`, for `<markdown [tokens]>`. */\n readonly tokens: MarkdownToken[];\n}\n\n/**\n * The route data key a Markdown page's file is under, for a package that routes `.md` pages itself,\n * as `pageRoutes` from `@ng-native/analog` does: an app reads the file with `injectMarkdownPage()`.\n */\nexport const MARKDOWN_PAGE = 'ngNativeMarkdownPage';\n\n/**\n * The file of the Markdown page this component draws, in the component given to `fileRoutes`, or\n * to `pageRoutes` from `@ng-native/analog`, as `markdownPage`:\n * `{ filename, slug, attributes, content, tokens }`.\n */\nexport function injectMarkdownPage<\n Attributes extends Record<string, any> = Record<string, any>,\n>(): MarkdownPageFile<Attributes> {\n const file = inject(ActivatedRoute).snapshot.data[MARKDOWN_PAGE] as\n MarkdownPageFile<Attributes> | undefined;\n if (!file) {\n throw new Error(\n 'injectMarkdownPage() is for the markdownPage component fileRoutes or pageRoutes routes a ' +\n '.md page to, and this route is not one.',\n );\n }\n return file;\n}\n\n/**\n * A Markdown page's file, from the module Metro made of it, or that module's namespace, with\n * `filename` its path from the pages folder. Throws, naming the file, for anything else.\n */\nexport function markdownPageFile(filename: string, loaded: unknown): MarkdownPageFile {\n const module = isMarkdownModule(loaded) ? loaded : (loaded as { default?: unknown })?.default;\n if (!isMarkdownModule(module)) {\n throw new Error(\n `${filename} is not the module @ng-native/metro makes of a .md file. Bundle the app with ` +\n \"withAngularNative from '@ng-native/metro/config.cjs', and test it with ngNative() from \" +\n \"'@ng-native/testing/vitest'.\",\n );\n }\n const base = filename.split('/').pop()!.replace(/\\.md$/, '');\n return {\n filename,\n slug: base === 'index' ? '' : base,\n attributes: module.attributes,\n content: module.content,\n tokens: module.tokens,\n };\n}\n\ninterface MarkdownModule {\n readonly attributes: Record<string, unknown>;\n readonly content: string;\n readonly tokens: MarkdownToken[];\n}\n\nfunction isMarkdownModule(value: unknown): value is MarkdownModule {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as MarkdownModule).content === 'string' &&\n Array.isArray((value as MarkdownModule).tokens)\n );\n}\n"]}
@@ -12,6 +12,8 @@ export declare class NativeHeader {
12
12
  private readonly palette;
13
13
  /** The app's `withHeaderDefaults`, for whatever this header does not bind itself. */
14
14
  protected readonly defaults: import("@angular/core").Signal<import("./native-bar-defaults.ts").HeaderDefaults>;
15
+ /** Told whether this is a bar the page starts below. See `screen-header.ts`. */
16
+ private readonly above;
15
17
  constructor();
16
18
  /**
17
19
  * The palette for the scheme the app is wearing, for whichever colours were not bound.
@@ -41,6 +43,8 @@ export declare class NativeHeader {
41
43
  * iOS 26 the large title sits in the scroll view, above its content, where a bar with a
42
44
  * background paints over it; and over an opaque bar the inline title never fades in.
43
45
  */
46
+ /** Whether the page runs under the bar rather than starting below it. */
47
+ protected readonly isTranslucent: import("@angular/core").Signal<boolean | undefined>;
44
48
  protected readonly iosLargeTitle: import("@angular/core").Signal<true | undefined>;
45
49
  protected readonly resolvedLargeTitleBackgroundColor: import("@angular/core").Signal<string | number | undefined>;
46
50
  /** The bar's title. Absent leaves whatever the platform would show, which is nothing. */
@@ -25,12 +25,12 @@
25
25
  * `headerRightBarButtonItems` are deliberately absent: native bar button items are data rather
26
26
  * than views, and they are a later opt-in rather than the primary API.
27
27
  */
28
- import { Component, computed, input } from '@angular/core';
29
- import { ElementRef, inject } from '@angular/core';
28
+ import { Component, DestroyRef, ElementRef, computed, effect, inject, input } from '@angular/core';
30
29
  import { ColorScheme, OS_VERSION } from '@ng-native/device';
31
30
  import { NATIVE_HEADER_DEFAULTS } from "./native-bar-defaults.js";
32
31
  import { NATIVE_HEADER_PALETTE } from "./native-header-palette.js";
33
32
  import { ownHost } from "./own-host.js";
33
+ import { SCREEN_HEADER } from "./screen-header.js";
34
34
  import { nativePlatform } from '@ng-native/fabric';
35
35
  import { optionalBoolean, optionalNumber } from "./transforms.js";
36
36
  import * as i0 from "@angular/core";
@@ -39,8 +39,15 @@ export class NativeHeader {
39
39
  palette = inject(NATIVE_HEADER_PALETTE);
40
40
  /** The app's `withHeaderDefaults`, for whatever this header does not bind itself. */
41
41
  defaults = inject(NATIVE_HEADER_DEFAULTS);
42
+ /** Told whether this is a bar the page starts below. See `screen-header.ts`. */
43
+ above = inject(SCREEN_HEADER, { optional: true });
42
44
  constructor() {
43
45
  ownHost(inject(ElementRef).nativeElement, this.constructor);
46
+ const above = this.above;
47
+ if (!above)
48
+ return;
49
+ effect(() => above.set(!this.hidden() && !this.isTranslucent()));
50
+ inject(DestroyRef).onDestroy(() => above.set(false));
44
51
  }
45
52
  /**
46
53
  * The palette for the scheme the app is wearing, for whichever colours were not bound.
@@ -82,6 +89,12 @@ export class NativeHeader {
82
89
  * iOS 26 the large title sits in the scroll view, above its content, where a bar with a
83
90
  * background paints over it; and over an opaque bar the inline title never fades in.
84
91
  */
92
+ /** Whether the page runs under the bar rather than starting below it. */
93
+ isTranslucent = computed(() => this.translucent() ??
94
+ this.defaults().translucent ??
95
+ this.iosLargeTitle() ??
96
+ this.isLiquidGlass(), /* @ts-ignore */
97
+ ...(ngDevMode ? [{ debugName: "isTranslucent" }] : /* istanbul ignore next */ []));
85
98
  iosLargeTitle = computed(() => this.largeTitle() && nativePlatform() === 'ios' ? true : undefined, /* @ts-ignore */
86
99
  ...(ngDevMode ? [{ debugName: "iosLargeTitle" }] : /* istanbul ignore next */ []));
87
100
  resolvedLargeTitleBackgroundColor = computed(() => this.largeTitleBackgroundColor() ??
@@ -181,7 +194,7 @@ export class NativeHeader {
181
194
  consumeRightInset = input(undefined, { ...(ngDevMode ? { debugName: "consumeRightInset" } : /* istanbul ignore next */ {}), transform: optionalBoolean });
182
195
  consumeBottomInset = input(undefined, { ...(ngDevMode ? { debugName: "consumeBottomInset" } : /* istanbul ignore next */ {}), transform: optionalBoolean });
183
196
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: NativeHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
184
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.2.0", type: NativeHeader, isStandalone: true, selector: "native-header", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, titleColor: { classPropertyName: "titleColor", publicName: "titleColor", isSignal: true, isRequired: false, transformFunction: null }, titleFontFamily: { classPropertyName: "titleFontFamily", publicName: "titleFontFamily", isSignal: true, isRequired: false, transformFunction: null }, titleFontSize: { classPropertyName: "titleFontSize", publicName: "titleFontSize", isSignal: true, isRequired: false, transformFunction: null }, titleFontWeight: { classPropertyName: "titleFontWeight", publicName: "titleFontWeight", isSignal: true, isRequired: false, transformFunction: null }, liquidGlass: { classPropertyName: "liquidGlass", publicName: "liquidGlass", isSignal: true, isRequired: false, transformFunction: null }, backgroundColor: { classPropertyName: "backgroundColor", publicName: "backgroundColor", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, blurEffect: { classPropertyName: "blurEffect", publicName: "blurEffect", isSignal: true, isRequired: false, transformFunction: null }, hidden: { classPropertyName: "hidden", publicName: "hidden", isSignal: true, isRequired: false, transformFunction: null }, hideShadow: { classPropertyName: "hideShadow", publicName: "hideShadow", isSignal: true, isRequired: false, transformFunction: null }, translucent: { classPropertyName: "translucent", publicName: "translucent", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, topInsetEnabled: { classPropertyName: "topInsetEnabled", publicName: "topInsetEnabled", isSignal: true, isRequired: false, transformFunction: null }, userInterfaceStyle: { classPropertyName: "userInterfaceStyle", publicName: "userInterfaceStyle", isSignal: true, isRequired: false, transformFunction: null }, largeTitle: { classPropertyName: "largeTitle", publicName: "largeTitle", isSignal: true, isRequired: false, transformFunction: null }, largeTitleColor: { classPropertyName: "largeTitleColor", publicName: "largeTitleColor", isSignal: true, isRequired: false, transformFunction: null }, largeTitleBackgroundColor: { classPropertyName: "largeTitleBackgroundColor", publicName: "largeTitleBackgroundColor", isSignal: true, isRequired: false, transformFunction: null }, largeTitleFontFamily: { classPropertyName: "largeTitleFontFamily", publicName: "largeTitleFontFamily", isSignal: true, isRequired: false, transformFunction: null }, largeTitleFontSize: { classPropertyName: "largeTitleFontSize", publicName: "largeTitleFontSize", isSignal: true, isRequired: false, transformFunction: null }, largeTitleFontWeight: { classPropertyName: "largeTitleFontWeight", publicName: "largeTitleFontWeight", isSignal: true, isRequired: false, transformFunction: null }, largeTitleHideShadow: { classPropertyName: "largeTitleHideShadow", publicName: "largeTitleHideShadow", isSignal: true, isRequired: false, transformFunction: null }, backTitle: { classPropertyName: "backTitle", publicName: "backTitle", isSignal: true, isRequired: false, transformFunction: null }, backTitleFontFamily: { classPropertyName: "backTitleFontFamily", publicName: "backTitleFontFamily", isSignal: true, isRequired: false, transformFunction: null }, backTitleFontSize: { classPropertyName: "backTitleFontSize", publicName: "backTitleFontSize", isSignal: true, isRequired: false, transformFunction: null }, backTitleVisible: { classPropertyName: "backTitleVisible", publicName: "backTitleVisible", isSignal: true, isRequired: false, transformFunction: null }, backButtonDisplayMode: { classPropertyName: "backButtonDisplayMode", publicName: "backButtonDisplayMode", isSignal: true, isRequired: false, transformFunction: null }, backButtonInCustomView: { classPropertyName: "backButtonInCustomView", publicName: "backButtonInCustomView", isSignal: true, isRequired: false, transformFunction: null }, disableBackButtonMenu: { classPropertyName: "disableBackButtonMenu", publicName: "disableBackButtonMenu", isSignal: true, isRequired: false, transformFunction: null }, hideBackButton: { classPropertyName: "hideBackButton", publicName: "hideBackButton", isSignal: true, isRequired: false, transformFunction: null }, consumeTopInset: { classPropertyName: "consumeTopInset", publicName: "consumeTopInset", isSignal: true, isRequired: false, transformFunction: null }, consumeLeftInset: { classPropertyName: "consumeLeftInset", publicName: "consumeLeftInset", isSignal: true, isRequired: false, transformFunction: null }, consumeRightInset: { classPropertyName: "consumeRightInset", publicName: "consumeRightInset", isSignal: true, isRequired: false, transformFunction: null }, consumeBottomInset: { classPropertyName: "consumeBottomInset", publicName: "consumeBottomInset", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "title": "title()", "titleColor": "resolvedTitleColor()", "titleFontFamily": "titleFontFamily() ?? defaults().titleFontFamily", "titleFontSize": "titleFontSize() ?? defaults().titleFontSize", "titleFontWeight": "titleFontWeight() ?? defaults().titleFontWeight", "backgroundColor": "resolvedBackgroundColor()", "color": "resolvedColor()", "blurEffect": "blurEffect() ?? defaults().blurEffect", "hidden": "hidden()", "hideShadow": "hideShadow() ?? defaults().hideShadow ?? isLiquidGlass()", "translucent": "translucent() ?? defaults().translucent ?? iosLargeTitle() ?? isLiquidGlass()", "direction": "direction()", "topInsetEnabled": "topInsetEnabled()", "userInterfaceStyle": "userInterfaceStyle() ?? defaults().userInterfaceStyle", "largeTitle": "largeTitle()", "largeTitleColor": "largeTitleColor() ?? defaults().largeTitleColor", "largeTitleBackgroundColor": "resolvedLargeTitleBackgroundColor()", "largeTitleFontFamily": "largeTitleFontFamily() ?? defaults().largeTitleFontFamily", "largeTitleFontSize": "largeTitleFontSize() ?? defaults().largeTitleFontSize", "largeTitleFontWeight": "largeTitleFontWeight() ?? defaults().largeTitleFontWeight", "largeTitleHideShadow": "largeTitleHideShadow() ?? defaults().largeTitleHideShadow ?? iosLargeTitle()", "backTitle": "backTitle()", "backTitleFontFamily": "backTitleFontFamily() ?? defaults().backTitleFontFamily", "backTitleFontSize": "backTitleFontSize() ?? defaults().backTitleFontSize", "backTitleVisible": "backTitleVisible()", "backButtonDisplayMode": "backButtonDisplayMode() ?? defaults().backButtonDisplayMode", "backButtonInCustomView": "backButtonInCustomView()", "disableBackButtonMenu": "disableBackButtonMenu()", "hideBackButton": "hideBackButton()", "consumeTopInset": "consumeTopInset()", "consumeLeftInset": "consumeLeftInset()", "consumeRightInset": "consumeRightInset()", "consumeBottomInset": "consumeBottomInset()" } }, ngImport: i0, template: '<ng-content />', isInline: true });
197
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.2.0", type: NativeHeader, isStandalone: true, selector: "native-header", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, titleColor: { classPropertyName: "titleColor", publicName: "titleColor", isSignal: true, isRequired: false, transformFunction: null }, titleFontFamily: { classPropertyName: "titleFontFamily", publicName: "titleFontFamily", isSignal: true, isRequired: false, transformFunction: null }, titleFontSize: { classPropertyName: "titleFontSize", publicName: "titleFontSize", isSignal: true, isRequired: false, transformFunction: null }, titleFontWeight: { classPropertyName: "titleFontWeight", publicName: "titleFontWeight", isSignal: true, isRequired: false, transformFunction: null }, liquidGlass: { classPropertyName: "liquidGlass", publicName: "liquidGlass", isSignal: true, isRequired: false, transformFunction: null }, backgroundColor: { classPropertyName: "backgroundColor", publicName: "backgroundColor", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, blurEffect: { classPropertyName: "blurEffect", publicName: "blurEffect", isSignal: true, isRequired: false, transformFunction: null }, hidden: { classPropertyName: "hidden", publicName: "hidden", isSignal: true, isRequired: false, transformFunction: null }, hideShadow: { classPropertyName: "hideShadow", publicName: "hideShadow", isSignal: true, isRequired: false, transformFunction: null }, translucent: { classPropertyName: "translucent", publicName: "translucent", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, topInsetEnabled: { classPropertyName: "topInsetEnabled", publicName: "topInsetEnabled", isSignal: true, isRequired: false, transformFunction: null }, userInterfaceStyle: { classPropertyName: "userInterfaceStyle", publicName: "userInterfaceStyle", isSignal: true, isRequired: false, transformFunction: null }, largeTitle: { classPropertyName: "largeTitle", publicName: "largeTitle", isSignal: true, isRequired: false, transformFunction: null }, largeTitleColor: { classPropertyName: "largeTitleColor", publicName: "largeTitleColor", isSignal: true, isRequired: false, transformFunction: null }, largeTitleBackgroundColor: { classPropertyName: "largeTitleBackgroundColor", publicName: "largeTitleBackgroundColor", isSignal: true, isRequired: false, transformFunction: null }, largeTitleFontFamily: { classPropertyName: "largeTitleFontFamily", publicName: "largeTitleFontFamily", isSignal: true, isRequired: false, transformFunction: null }, largeTitleFontSize: { classPropertyName: "largeTitleFontSize", publicName: "largeTitleFontSize", isSignal: true, isRequired: false, transformFunction: null }, largeTitleFontWeight: { classPropertyName: "largeTitleFontWeight", publicName: "largeTitleFontWeight", isSignal: true, isRequired: false, transformFunction: null }, largeTitleHideShadow: { classPropertyName: "largeTitleHideShadow", publicName: "largeTitleHideShadow", isSignal: true, isRequired: false, transformFunction: null }, backTitle: { classPropertyName: "backTitle", publicName: "backTitle", isSignal: true, isRequired: false, transformFunction: null }, backTitleFontFamily: { classPropertyName: "backTitleFontFamily", publicName: "backTitleFontFamily", isSignal: true, isRequired: false, transformFunction: null }, backTitleFontSize: { classPropertyName: "backTitleFontSize", publicName: "backTitleFontSize", isSignal: true, isRequired: false, transformFunction: null }, backTitleVisible: { classPropertyName: "backTitleVisible", publicName: "backTitleVisible", isSignal: true, isRequired: false, transformFunction: null }, backButtonDisplayMode: { classPropertyName: "backButtonDisplayMode", publicName: "backButtonDisplayMode", isSignal: true, isRequired: false, transformFunction: null }, backButtonInCustomView: { classPropertyName: "backButtonInCustomView", publicName: "backButtonInCustomView", isSignal: true, isRequired: false, transformFunction: null }, disableBackButtonMenu: { classPropertyName: "disableBackButtonMenu", publicName: "disableBackButtonMenu", isSignal: true, isRequired: false, transformFunction: null }, hideBackButton: { classPropertyName: "hideBackButton", publicName: "hideBackButton", isSignal: true, isRequired: false, transformFunction: null }, consumeTopInset: { classPropertyName: "consumeTopInset", publicName: "consumeTopInset", isSignal: true, isRequired: false, transformFunction: null }, consumeLeftInset: { classPropertyName: "consumeLeftInset", publicName: "consumeLeftInset", isSignal: true, isRequired: false, transformFunction: null }, consumeRightInset: { classPropertyName: "consumeRightInset", publicName: "consumeRightInset", isSignal: true, isRequired: false, transformFunction: null }, consumeBottomInset: { classPropertyName: "consumeBottomInset", publicName: "consumeBottomInset", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "title": "title()", "titleColor": "resolvedTitleColor()", "titleFontFamily": "titleFontFamily() ?? defaults().titleFontFamily", "titleFontSize": "titleFontSize() ?? defaults().titleFontSize", "titleFontWeight": "titleFontWeight() ?? defaults().titleFontWeight", "backgroundColor": "resolvedBackgroundColor()", "color": "resolvedColor()", "blurEffect": "blurEffect() ?? defaults().blurEffect", "hidden": "hidden()", "hideShadow": "hideShadow() ?? defaults().hideShadow ?? isLiquidGlass()", "translucent": "isTranslucent()", "direction": "direction()", "topInsetEnabled": "topInsetEnabled()", "userInterfaceStyle": "userInterfaceStyle() ?? defaults().userInterfaceStyle", "largeTitle": "largeTitle()", "largeTitleColor": "largeTitleColor() ?? defaults().largeTitleColor", "largeTitleBackgroundColor": "resolvedLargeTitleBackgroundColor()", "largeTitleFontFamily": "largeTitleFontFamily() ?? defaults().largeTitleFontFamily", "largeTitleFontSize": "largeTitleFontSize() ?? defaults().largeTitleFontSize", "largeTitleFontWeight": "largeTitleFontWeight() ?? defaults().largeTitleFontWeight", "largeTitleHideShadow": "largeTitleHideShadow() ?? defaults().largeTitleHideShadow ?? iosLargeTitle()", "backTitle": "backTitle()", "backTitleFontFamily": "backTitleFontFamily() ?? defaults().backTitleFontFamily", "backTitleFontSize": "backTitleFontSize() ?? defaults().backTitleFontSize", "backTitleVisible": "backTitleVisible()", "backButtonDisplayMode": "backButtonDisplayMode() ?? defaults().backButtonDisplayMode", "backButtonInCustomView": "backButtonInCustomView()", "disableBackButtonMenu": "disableBackButtonMenu()", "hideBackButton": "hideBackButton()", "consumeTopInset": "consumeTopInset()", "consumeLeftInset": "consumeLeftInset()", "consumeRightInset": "consumeRightInset()", "consumeBottomInset": "consumeBottomInset()" } }, ngImport: i0, template: '<ng-content />', isInline: true });
185
198
  }
186
199
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImport: i0, type: NativeHeader, decorators: [{
187
200
  type: Component,
@@ -199,7 +212,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.0", ngImpor
199
212
  '[blurEffect]': 'blurEffect() ?? defaults().blurEffect',
200
213
  '[hidden]': 'hidden()',
201
214
  '[hideShadow]': 'hideShadow() ?? defaults().hideShadow ?? isLiquidGlass()',
202
- '[translucent]': 'translucent() ?? defaults().translucent ?? iosLargeTitle() ?? isLiquidGlass()',
215
+ '[translucent]': 'isTranslucent()',
203
216
  '[direction]': 'direction()',
204
217
  '[topInsetEnabled]': 'topInsetEnabled()',
205
218
  '[userInterfaceStyle]': 'userInterfaceStyle() ?? defaults().userInterfaceStyle',
@@ -1 +1 @@
1
- {"version":3,"file":"native-header.js","sourceRoot":"","sources":["../src/native-header.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The screen's navigation bar, as a component you write inside a page's template.\n *\n * Commits as `RNSScreenStackHeaderConfig`. It is a configuration node rather than a view: the\n * native side reads its props and builds a `UINavigationItem` from them, and the only children\n * that mean anything are `native-header-item`s. `findHeaderConfig` in `RNSScreen.mm` scans the\n * screen's direct `reactSubviews` without recursing, which is why a page's host element is the\n * screen itself (ADR 0004). It can still be written anywhere in the page, inside a `safe-area-view`\n * or a layout component: `registerScreenComponents` has the engine commit it as a direct child of\n * the screen, just after the part of the page it was written in (`registerHoist`). Keep the page's\n * scroll view ahead of it. UIKit then finds that scroll view and collapses a large title into the\n * inline title as the content scrolls.\n *\n * A header owns the top inset. A page that has one should not also wrap itself in a\n * `safe-area-view`, or the content clears the notch twice.\n *\n * **A presented screen has no header.** `RNSScreenStack.mm` presents a modal or a sheet with\n * `presentViewController:`, outside the stack's `UINavigationController`, so there is no\n * navigation bar for this to configure and nothing adjusting the screen's insets either. A page\n * opened with `present()` owns its own chrome: its title, its way out, and its `safe-area-view`.\n * react-navigation has the same shape, which is why a modal there needs a stack nested inside it\n * before it has a header.\n *\n * Props are the `RNSScreenStackHeaderConfig` codegen spec. `headerLeftBarButtonItems` and\n * `headerRightBarButtonItems` are deliberately absent: native bar button items are data rather\n * than views, and they are a later opt-in rather than the primary API.\n */\nimport { Component, computed, input } from '@angular/core';\nimport { ElementRef, inject } from '@angular/core';\nimport { ColorScheme, OS_VERSION } from '@ng-native/device';\nimport { NATIVE_HEADER_DEFAULTS } from './native-bar-defaults.ts';\nimport { NATIVE_HEADER_PALETTE } from './native-header-palette.ts';\nimport type { EngineNode } from '@ng-native/fabric';\nimport { ownHost } from './own-host.ts';\nimport { nativePlatform } from '@ng-native/fabric';\nimport { optionalBoolean, optionalNumber } from './transforms.ts';\n\n/** Where the back button's title comes from, on iOS 14+. */\nexport type BackButtonDisplayMode = 'minimal' | 'default' | 'generic';\n\n/** Direction the bar lays out in, for right-to-left languages. */\nexport type HeaderDirection = 'ltr' | 'rtl';\n\n/** How the bar blurs what scrolls under it. `none` paints `backgroundColor` instead. */\nexport type BlurEffect =\n | 'none'\n | 'extraLight'\n | 'light'\n | 'dark'\n | 'regular'\n | 'prominent'\n | 'systemUltraThinMaterial'\n | 'systemThinMaterial'\n | 'systemMaterial'\n | 'systemThickMaterial'\n | 'systemChromeMaterial'\n | 'systemUltraThinMaterialLight'\n | 'systemThinMaterialLight'\n | 'systemMaterialLight'\n | 'systemThickMaterialLight'\n | 'systemChromeMaterialLight'\n | 'systemUltraThinMaterialDark'\n | 'systemThinMaterialDark'\n | 'systemMaterialDark'\n | 'systemThickMaterialDark'\n | 'systemChromeMaterialDark';\n\n/** Overrides the bar's light/dark appearance independently of the app's. */\nexport type HeaderInterfaceStyle = 'unspecified' | 'light' | 'dark';\n\n@Component({\n selector: 'native-header',\n template: '<ng-content />',\n host: {\n '[title]': 'title()',\n '[titleColor]': 'resolvedTitleColor()',\n '[titleFontFamily]': 'titleFontFamily() ?? defaults().titleFontFamily',\n '[titleFontSize]': 'titleFontSize() ?? defaults().titleFontSize',\n '[titleFontWeight]': 'titleFontWeight() ?? defaults().titleFontWeight',\n '[backgroundColor]': 'resolvedBackgroundColor()',\n '[color]': 'resolvedColor()',\n '[blurEffect]': 'blurEffect() ?? defaults().blurEffect',\n '[hidden]': 'hidden()',\n '[hideShadow]': 'hideShadow() ?? defaults().hideShadow ?? isLiquidGlass()',\n '[translucent]':\n 'translucent() ?? defaults().translucent ?? iosLargeTitle() ?? isLiquidGlass()',\n '[direction]': 'direction()',\n '[topInsetEnabled]': 'topInsetEnabled()',\n '[userInterfaceStyle]': 'userInterfaceStyle() ?? defaults().userInterfaceStyle',\n '[largeTitle]': 'largeTitle()',\n '[largeTitleColor]': 'largeTitleColor() ?? defaults().largeTitleColor',\n '[largeTitleBackgroundColor]': 'resolvedLargeTitleBackgroundColor()',\n '[largeTitleFontFamily]': 'largeTitleFontFamily() ?? defaults().largeTitleFontFamily',\n '[largeTitleFontSize]': 'largeTitleFontSize() ?? defaults().largeTitleFontSize',\n '[largeTitleFontWeight]': 'largeTitleFontWeight() ?? defaults().largeTitleFontWeight',\n '[largeTitleHideShadow]':\n 'largeTitleHideShadow() ?? defaults().largeTitleHideShadow ?? iosLargeTitle()',\n '[backTitle]': 'backTitle()',\n '[backTitleFontFamily]': 'backTitleFontFamily() ?? defaults().backTitleFontFamily',\n '[backTitleFontSize]': 'backTitleFontSize() ?? defaults().backTitleFontSize',\n '[backTitleVisible]': 'backTitleVisible()',\n '[backButtonDisplayMode]': 'backButtonDisplayMode() ?? defaults().backButtonDisplayMode',\n '[backButtonInCustomView]': 'backButtonInCustomView()',\n '[disableBackButtonMenu]': 'disableBackButtonMenu()',\n '[hideBackButton]': 'hideBackButton()',\n '[consumeTopInset]': 'consumeTopInset()',\n '[consumeLeftInset]': 'consumeLeftInset()',\n '[consumeRightInset]': 'consumeRightInset()',\n '[consumeBottomInset]': 'consumeBottomInset()',\n },\n})\nexport class NativeHeader {\n private readonly scheme = inject(ColorScheme);\n private readonly palette = inject(NATIVE_HEADER_PALETTE);\n /** The app's `withHeaderDefaults`, for whatever this header does not bind itself. */\n protected readonly defaults = inject(NATIVE_HEADER_DEFAULTS);\n\n constructor() {\n ownHost(inject(ElementRef).nativeElement as EngineNode, this.constructor);\n }\n\n /**\n * The palette for the scheme the app is wearing, for whichever colours were not bound.\n *\n * A header prop cannot read the cascade, so left alone each platform chooses: iOS follows the\n * system appearance and looks about right, Android takes the app theme's `colorPrimary` and is\n * the framework blue on every screen. These fill the gap without overriding anything a call site\n * or `withHeaderDefaults` did say. See `native-header-palette.ts` for retuning them.\n */\n private readonly colours = computed(() => this.palette[this.scheme.current()]);\n\n /** iOS 26 and later, where the system's own bar is clear and floats over the content. */\n private readonly glass = nativePlatform() === 'ios' && (inject(OS_VERSION) ?? 0) >= 26;\n\n /**\n * Whether the bar is iOS 26's Liquid Glass one, which `liquidGlass` asks for here or through\n * `withHeaderDefaults`: clear, over the content, with no line under it, where the system blurs\n * what scrolls beneath and floats the buttons. Only on iOS 26 and later, and only while nothing\n * gave the bar a background of its own.\n */\n protected readonly isLiquidGlass = computed(() =>\n this.glass &&\n (this.liquidGlass() ?? this.defaults().liquidGlass) &&\n this.backgroundColor() === undefined &&\n this.defaults().backgroundColor === undefined\n ? true\n : undefined,\n );\n\n protected readonly resolvedBackgroundColor = computed(\n () =>\n this.backgroundColor() ??\n this.defaults().backgroundColor ??\n (this.isLiquidGlass() ? 'transparent' : this.colours().background),\n );\n protected readonly resolvedColor = computed(\n () => this.color() ?? this.defaults().color ?? this.colours().foreground,\n );\n protected readonly resolvedTitleColor = computed(\n () => this.titleColor() ?? this.defaults().titleColor ?? this.colours().foreground,\n );\n\n /**\n * A large title on iOS, drawn as UIKit draws one unless the call site says otherwise: over the\n * content with the bar clear and unlined at the top, so the page's scroll view (with\n * `contentInsetAdjustmentBehavior=\"automatic\"`) collapses it into the bar as it scrolls. Since\n * iOS 26 the large title sits in the scroll view, above its content, where a bar with a\n * background paints over it; and over an opaque bar the inline title never fades in.\n */\n protected readonly iosLargeTitle = computed(() =>\n this.largeTitle() && nativePlatform() === 'ios' ? true : undefined,\n );\n protected readonly resolvedLargeTitleBackgroundColor = computed(\n () =>\n this.largeTitleBackgroundColor() ??\n this.defaults().largeTitleBackgroundColor ??\n (this.iosLargeTitle() ? 'transparent' : undefined),\n );\n\n // --- title ---------------------------------------------------------------------------\n\n /** The bar's title. Absent leaves whatever the platform would show, which is nothing. */\n readonly title = input<string>();\n /** Title colour. */\n readonly titleColor = input<string | number>();\n readonly titleFontFamily = input<string>();\n readonly titleFontSize = input(undefined, { transform: optionalNumber });\n /** A CSS font weight, `'600'` or `'bold'`. */\n readonly titleFontWeight = input<string>();\n\n // --- the bar itself ------------------------------------------------------------------\n\n /**\n * On iOS 26 and later, the Liquid Glass navigation bar for this header, where it has no\n * background of its own: clear and unlined, with the content scrolling under it. `false` keeps\n * the neutral bar on a page of an app whose `withHeaderDefaults` asks for the glass one. The\n * bar is over the page, so its scroll view takes `contentInsetAdjustmentBehavior=\"automatic\"`.\n */\n readonly liquidGlass = input(undefined, { transform: optionalBoolean });\n /** The bar's background. Ignored unless `blurEffect` is `none`. */\n readonly backgroundColor = input<string | number>();\n /** Tint colour: the back chevron, and any header item that does not set its own. */\n readonly color = input<string | number>();\n /** iOS blur material behind the bar. */\n readonly blurEffect = input<BlurEffect>();\n /** Hide the bar entirely, keeping the screen's gestures and safe areas. */\n readonly hidden = input(undefined, { transform: optionalBoolean });\n /** Drop the hairline under the bar. */\n readonly hideShadow = input(undefined, { transform: optionalBoolean });\n /** Let content scroll under the bar rather than starting below it. */\n readonly translucent = input(undefined, { transform: optionalBoolean });\n /** Lay the bar out right to left. */\n readonly direction = input<HeaderDirection>();\n /** Android: add the status bar inset to the bar's height. */\n readonly topInsetEnabled = input(undefined, { transform: optionalBoolean });\n /** Force the bar light or dark regardless of the app's appearance. */\n readonly userInterfaceStyle = input<HeaderInterfaceStyle>();\n\n // --- large title (iOS) ---------------------------------------------------------------\n\n /** iOS large title, which collapses into the bar as content scrolls. */\n readonly largeTitle = input(undefined, { transform: optionalBoolean });\n readonly largeTitleColor = input<string | number>();\n readonly largeTitleBackgroundColor = input<string | number>();\n readonly largeTitleFontFamily = input<string>();\n readonly largeTitleFontSize = input(undefined, { transform: optionalNumber });\n readonly largeTitleFontWeight = input<string>();\n readonly largeTitleHideShadow = input(undefined, { transform: optionalBoolean });\n\n // --- the back button -----------------------------------------------------------------\n\n /**\n * What *this* screen's back button says. `RNSScreenStackHeaderConfig.mm` writes it onto the\n * previous screen's navigation item, falling back to that screen's title, which is why an\n * unset back title reads as the title of the screen you came from.\n */\n readonly backTitle = input<string>();\n readonly backTitleFontFamily = input<string>();\n readonly backTitleFontSize = input(undefined, { transform: optionalNumber });\n /** Show the back button's title at all. Native defaults this to true. */\n readonly backTitleVisible = input(undefined, { transform: optionalBoolean });\n /** iOS 14+: how aggressively the back title is shortened when space is tight. */\n readonly backButtonDisplayMode = input<BackButtonDisplayMode>();\n /** Put the back button in the custom view slot, so a `back` header item can replace it. */\n readonly backButtonInCustomView = input(undefined, { transform: optionalBoolean });\n /** Drop the long-press menu of the screens below. */\n readonly disableBackButtonMenu = input(undefined, { transform: optionalBoolean });\n /** Hide the back button without disabling the swipe-back gesture. */\n readonly hideBackButton = input(undefined, { transform: optionalBoolean });\n\n // --- insets (experimental in react-native-screens) -------------------------------------\n\n /**\n * Android: whether the bar takes the status bar's height as padding, so its title sits below\n * it rather than under it.\n *\n * Defaulted per platform because getting it wrong is invisible in a screenshot until you look\n * for it: react-native-screens leaves it false, Android 15 draws every app edge to edge, and\n * the result is a title behind the clock. iOS has a navigation controller doing this itself.\n */\n readonly consumeTopInset = input(nativePlatform() === 'android', {\n transform: optionalBoolean,\n });\n readonly consumeLeftInset = input(undefined, { transform: optionalBoolean });\n readonly consumeRightInset = input(undefined, { transform: optionalBoolean });\n readonly consumeBottomInset = input(undefined, { transform: optionalBoolean });\n}\n"]}
1
+ {"version":3,"file":"native-header.js","sourceRoot":"","sources":["../src/native-header.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The screen's navigation bar, as a component you write inside a page's template.\n *\n * Commits as `RNSScreenStackHeaderConfig`. It is a configuration node rather than a view: the\n * native side reads its props and builds a `UINavigationItem` from them, and the only children\n * that mean anything are `native-header-item`s. `findHeaderConfig` in `RNSScreen.mm` scans the\n * screen's direct `reactSubviews` without recursing, which is why a page's host element is the\n * screen itself (ADR 0004). It can still be written anywhere in the page, inside a `safe-area-view`\n * or a layout component: `registerScreenComponents` has the engine commit it as a direct child of\n * the screen, just after the part of the page it was written in (`registerHoist`). Keep the page's\n * scroll view ahead of it. UIKit then finds that scroll view and collapses a large title into the\n * inline title as the content scrolls.\n *\n * A header owns the top inset. A page that has one should not also wrap itself in a\n * `safe-area-view`, or the content clears the notch twice.\n *\n * **A presented screen has no header.** `RNSScreenStack.mm` presents a modal or a sheet with\n * `presentViewController:`, outside the stack's `UINavigationController`, so there is no\n * navigation bar for this to configure and nothing adjusting the screen's insets either. A page\n * opened with `present()` owns its own chrome: its title, its way out, and its `safe-area-view`.\n * react-navigation has the same shape, which is why a modal there needs a stack nested inside it\n * before it has a header.\n *\n * Props are the `RNSScreenStackHeaderConfig` codegen spec. `headerLeftBarButtonItems` and\n * `headerRightBarButtonItems` are deliberately absent: native bar button items are data rather\n * than views, and they are a later opt-in rather than the primary API.\n */\nimport { Component, DestroyRef, ElementRef, computed, effect, inject, input } from '@angular/core';\nimport { ColorScheme, OS_VERSION } from '@ng-native/device';\nimport { NATIVE_HEADER_DEFAULTS } from './native-bar-defaults.ts';\nimport { NATIVE_HEADER_PALETTE } from './native-header-palette.ts';\nimport type { EngineNode } from '@ng-native/fabric';\nimport { ownHost } from './own-host.ts';\nimport { SCREEN_HEADER } from './screen-header.ts';\nimport { nativePlatform } from '@ng-native/fabric';\nimport { optionalBoolean, optionalNumber } from './transforms.ts';\n\n/** Where the back button's title comes from, on iOS 14+. */\nexport type BackButtonDisplayMode = 'minimal' | 'default' | 'generic';\n\n/** Direction the bar lays out in, for right-to-left languages. */\nexport type HeaderDirection = 'ltr' | 'rtl';\n\n/** How the bar blurs what scrolls under it. `none` paints `backgroundColor` instead. */\nexport type BlurEffect =\n | 'none'\n | 'extraLight'\n | 'light'\n | 'dark'\n | 'regular'\n | 'prominent'\n | 'systemUltraThinMaterial'\n | 'systemThinMaterial'\n | 'systemMaterial'\n | 'systemThickMaterial'\n | 'systemChromeMaterial'\n | 'systemUltraThinMaterialLight'\n | 'systemThinMaterialLight'\n | 'systemMaterialLight'\n | 'systemThickMaterialLight'\n | 'systemChromeMaterialLight'\n | 'systemUltraThinMaterialDark'\n | 'systemThinMaterialDark'\n | 'systemMaterialDark'\n | 'systemThickMaterialDark'\n | 'systemChromeMaterialDark';\n\n/** Overrides the bar's light/dark appearance independently of the app's. */\nexport type HeaderInterfaceStyle = 'unspecified' | 'light' | 'dark';\n\n@Component({\n selector: 'native-header',\n template: '<ng-content />',\n host: {\n '[title]': 'title()',\n '[titleColor]': 'resolvedTitleColor()',\n '[titleFontFamily]': 'titleFontFamily() ?? defaults().titleFontFamily',\n '[titleFontSize]': 'titleFontSize() ?? defaults().titleFontSize',\n '[titleFontWeight]': 'titleFontWeight() ?? defaults().titleFontWeight',\n '[backgroundColor]': 'resolvedBackgroundColor()',\n '[color]': 'resolvedColor()',\n '[blurEffect]': 'blurEffect() ?? defaults().blurEffect',\n '[hidden]': 'hidden()',\n '[hideShadow]': 'hideShadow() ?? defaults().hideShadow ?? isLiquidGlass()',\n '[translucent]': 'isTranslucent()',\n '[direction]': 'direction()',\n '[topInsetEnabled]': 'topInsetEnabled()',\n '[userInterfaceStyle]': 'userInterfaceStyle() ?? defaults().userInterfaceStyle',\n '[largeTitle]': 'largeTitle()',\n '[largeTitleColor]': 'largeTitleColor() ?? defaults().largeTitleColor',\n '[largeTitleBackgroundColor]': 'resolvedLargeTitleBackgroundColor()',\n '[largeTitleFontFamily]': 'largeTitleFontFamily() ?? defaults().largeTitleFontFamily',\n '[largeTitleFontSize]': 'largeTitleFontSize() ?? defaults().largeTitleFontSize',\n '[largeTitleFontWeight]': 'largeTitleFontWeight() ?? defaults().largeTitleFontWeight',\n '[largeTitleHideShadow]':\n 'largeTitleHideShadow() ?? defaults().largeTitleHideShadow ?? iosLargeTitle()',\n '[backTitle]': 'backTitle()',\n '[backTitleFontFamily]': 'backTitleFontFamily() ?? defaults().backTitleFontFamily',\n '[backTitleFontSize]': 'backTitleFontSize() ?? defaults().backTitleFontSize',\n '[backTitleVisible]': 'backTitleVisible()',\n '[backButtonDisplayMode]': 'backButtonDisplayMode() ?? defaults().backButtonDisplayMode',\n '[backButtonInCustomView]': 'backButtonInCustomView()',\n '[disableBackButtonMenu]': 'disableBackButtonMenu()',\n '[hideBackButton]': 'hideBackButton()',\n '[consumeTopInset]': 'consumeTopInset()',\n '[consumeLeftInset]': 'consumeLeftInset()',\n '[consumeRightInset]': 'consumeRightInset()',\n '[consumeBottomInset]': 'consumeBottomInset()',\n },\n})\nexport class NativeHeader {\n private readonly scheme = inject(ColorScheme);\n private readonly palette = inject(NATIVE_HEADER_PALETTE);\n /** The app's `withHeaderDefaults`, for whatever this header does not bind itself. */\n protected readonly defaults = inject(NATIVE_HEADER_DEFAULTS);\n\n /** Told whether this is a bar the page starts below. See `screen-header.ts`. */\n private readonly above = inject(SCREEN_HEADER, { optional: true });\n\n constructor() {\n ownHost(inject(ElementRef).nativeElement as EngineNode, this.constructor);\n const above = this.above;\n if (!above) return;\n effect(() => above.set(!this.hidden() && !this.isTranslucent()));\n inject(DestroyRef).onDestroy(() => above.set(false));\n }\n\n /**\n * The palette for the scheme the app is wearing, for whichever colours were not bound.\n *\n * A header prop cannot read the cascade, so left alone each platform chooses: iOS follows the\n * system appearance and looks about right, Android takes the app theme's `colorPrimary` and is\n * the framework blue on every screen. These fill the gap without overriding anything a call site\n * or `withHeaderDefaults` did say. See `native-header-palette.ts` for retuning them.\n */\n private readonly colours = computed(() => this.palette[this.scheme.current()]);\n\n /** iOS 26 and later, where the system's own bar is clear and floats over the content. */\n private readonly glass = nativePlatform() === 'ios' && (inject(OS_VERSION) ?? 0) >= 26;\n\n /**\n * Whether the bar is iOS 26's Liquid Glass one, which `liquidGlass` asks for here or through\n * `withHeaderDefaults`: clear, over the content, with no line under it, where the system blurs\n * what scrolls beneath and floats the buttons. Only on iOS 26 and later, and only while nothing\n * gave the bar a background of its own.\n */\n protected readonly isLiquidGlass = computed(() =>\n this.glass &&\n (this.liquidGlass() ?? this.defaults().liquidGlass) &&\n this.backgroundColor() === undefined &&\n this.defaults().backgroundColor === undefined\n ? true\n : undefined,\n );\n\n protected readonly resolvedBackgroundColor = computed(\n () =>\n this.backgroundColor() ??\n this.defaults().backgroundColor ??\n (this.isLiquidGlass() ? 'transparent' : this.colours().background),\n );\n protected readonly resolvedColor = computed(\n () => this.color() ?? this.defaults().color ?? this.colours().foreground,\n );\n protected readonly resolvedTitleColor = computed(\n () => this.titleColor() ?? this.defaults().titleColor ?? this.colours().foreground,\n );\n\n /**\n * A large title on iOS, drawn as UIKit draws one unless the call site says otherwise: over the\n * content with the bar clear and unlined at the top, so the page's scroll view (with\n * `contentInsetAdjustmentBehavior=\"automatic\"`) collapses it into the bar as it scrolls. Since\n * iOS 26 the large title sits in the scroll view, above its content, where a bar with a\n * background paints over it; and over an opaque bar the inline title never fades in.\n */\n /** Whether the page runs under the bar rather than starting below it. */\n protected readonly isTranslucent = computed(\n () =>\n this.translucent() ??\n this.defaults().translucent ??\n this.iosLargeTitle() ??\n this.isLiquidGlass(),\n );\n\n protected readonly iosLargeTitle = computed(() =>\n this.largeTitle() && nativePlatform() === 'ios' ? true : undefined,\n );\n protected readonly resolvedLargeTitleBackgroundColor = computed(\n () =>\n this.largeTitleBackgroundColor() ??\n this.defaults().largeTitleBackgroundColor ??\n (this.iosLargeTitle() ? 'transparent' : undefined),\n );\n\n // --- title ---------------------------------------------------------------------------\n\n /** The bar's title. Absent leaves whatever the platform would show, which is nothing. */\n readonly title = input<string>();\n /** Title colour. */\n readonly titleColor = input<string | number>();\n readonly titleFontFamily = input<string>();\n readonly titleFontSize = input(undefined, { transform: optionalNumber });\n /** A CSS font weight, `'600'` or `'bold'`. */\n readonly titleFontWeight = input<string>();\n\n // --- the bar itself ------------------------------------------------------------------\n\n /**\n * On iOS 26 and later, the Liquid Glass navigation bar for this header, where it has no\n * background of its own: clear and unlined, with the content scrolling under it. `false` keeps\n * the neutral bar on a page of an app whose `withHeaderDefaults` asks for the glass one. The\n * bar is over the page, so its scroll view takes `contentInsetAdjustmentBehavior=\"automatic\"`.\n */\n readonly liquidGlass = input(undefined, { transform: optionalBoolean });\n /** The bar's background. Ignored unless `blurEffect` is `none`. */\n readonly backgroundColor = input<string | number>();\n /** Tint colour: the back chevron, and any header item that does not set its own. */\n readonly color = input<string | number>();\n /** iOS blur material behind the bar. */\n readonly blurEffect = input<BlurEffect>();\n /** Hide the bar entirely, keeping the screen's gestures and safe areas. */\n readonly hidden = input(undefined, { transform: optionalBoolean });\n /** Drop the hairline under the bar. */\n readonly hideShadow = input(undefined, { transform: optionalBoolean });\n /** Let content scroll under the bar rather than starting below it. */\n readonly translucent = input(undefined, { transform: optionalBoolean });\n /** Lay the bar out right to left. */\n readonly direction = input<HeaderDirection>();\n /** Android: add the status bar inset to the bar's height. */\n readonly topInsetEnabled = input(undefined, { transform: optionalBoolean });\n /** Force the bar light or dark regardless of the app's appearance. */\n readonly userInterfaceStyle = input<HeaderInterfaceStyle>();\n\n // --- large title (iOS) ---------------------------------------------------------------\n\n /** iOS large title, which collapses into the bar as content scrolls. */\n readonly largeTitle = input(undefined, { transform: optionalBoolean });\n readonly largeTitleColor = input<string | number>();\n readonly largeTitleBackgroundColor = input<string | number>();\n readonly largeTitleFontFamily = input<string>();\n readonly largeTitleFontSize = input(undefined, { transform: optionalNumber });\n readonly largeTitleFontWeight = input<string>();\n readonly largeTitleHideShadow = input(undefined, { transform: optionalBoolean });\n\n // --- the back button -----------------------------------------------------------------\n\n /**\n * What *this* screen's back button says. `RNSScreenStackHeaderConfig.mm` writes it onto the\n * previous screen's navigation item, falling back to that screen's title, which is why an\n * unset back title reads as the title of the screen you came from.\n */\n readonly backTitle = input<string>();\n readonly backTitleFontFamily = input<string>();\n readonly backTitleFontSize = input(undefined, { transform: optionalNumber });\n /** Show the back button's title at all. Native defaults this to true. */\n readonly backTitleVisible = input(undefined, { transform: optionalBoolean });\n /** iOS 14+: how aggressively the back title is shortened when space is tight. */\n readonly backButtonDisplayMode = input<BackButtonDisplayMode>();\n /** Put the back button in the custom view slot, so a `back` header item can replace it. */\n readonly backButtonInCustomView = input(undefined, { transform: optionalBoolean });\n /** Drop the long-press menu of the screens below. */\n readonly disableBackButtonMenu = input(undefined, { transform: optionalBoolean });\n /** Hide the back button without disabling the swipe-back gesture. */\n readonly hideBackButton = input(undefined, { transform: optionalBoolean });\n\n // --- insets (experimental in react-native-screens) -------------------------------------\n\n /**\n * Android: whether the bar takes the status bar's height as padding, so its title sits below\n * it rather than under it.\n *\n * Defaulted per platform because getting it wrong is invisible in a screenshot until you look\n * for it: react-native-screens leaves it false, Android 15 draws every app edge to edge, and\n * the result is a title behind the clock. iOS has a navigation controller doing this itself.\n */\n readonly consumeTopInset = input(nativePlatform() === 'android', {\n transform: optionalBoolean,\n });\n readonly consumeLeftInset = input(undefined, { transform: optionalBoolean });\n readonly consumeRightInset = input(undefined, { transform: optionalBoolean });\n readonly consumeBottomInset = input(undefined, { transform: optionalBoolean });\n}\n"]}
@@ -40,6 +40,11 @@ export declare class NativePlatformLocation implements PlatformLocation {
40
40
  * stack outlet, which has to know whether going back reaches the screen a native pop revealed.
41
41
  */
42
42
  ɵurlAt(offset: number): string | null;
43
+ /** The history up to the page showing, oldest first. For parking it across a reload. */
44
+ ɵpages(): readonly {
45
+ readonly url: string;
46
+ readonly state: unknown;
47
+ }[];
43
48
  private get current();
44
49
  getBaseHrefFromDOM(): string;
45
50
  getState(): unknown;
@@ -38,6 +38,10 @@ export class NativePlatformLocation {
38
38
  ɵurlAt(offset) {
39
39
  return this.entries[this.cursor + offset]?.url ?? null;
40
40
  }
41
+ /** The history up to the page showing, oldest first. For parking it across a reload. */
42
+ ɵpages() {
43
+ return this.entries.slice(0, this.cursor + 1);
44
+ }
41
45
  get current() {
42
46
  return this.entries[this.cursor];
43
47
  }
@@ -1 +1 @@
1
- {"version":3,"file":"native-platform-location.js","sourceRoot":"","sources":["../src/native-platform-location.ts"],"names":[],"mappings":"AA8BA,8DAA8D;AAC9D,SAAS,KAAK,CAAC,GAAW;IACxB,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACpD,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAE/D,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAClE,MAAM,QAAQ,GAAG,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAEhF,OAAO,EAAE,QAAQ,EAAE,QAAQ,IAAI,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACrD,CAAC;AAED,MAAM,OAAO,sBAAsB;IAChB,OAAO,GAAmB,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/D,MAAM,GAAG,CAAC,CAAC;IAEF,iBAAiB,GAAG,IAAI,GAAG,EAA0B,CAAC;IACtD,mBAAmB,GAAG,IAAI,GAAG,EAA0B,CAAC;IAEzE;;;;OAIG;IACH,YAAY,QAA2B,IAAI;QACzC,MAAM,OAAO,GAAG,KAAK,EAAE,UAAU,EAAE,CAAC;QACpC,IAAI,OAAO;YAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAC7D,KAAK,EAAE,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,4DAA4D;IAC5D,IAAI,CAAC,GAAW;QACd,IAAI,GAAG,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG;YAAE,OAAO;QACrC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;QAC9B,IAAI,CAAC,YAAY,EAAE,CAAC;IACtB,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,MAAc;QACnB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,IAAI,IAAI,CAAC;IACzD,CAAC;IAED,IAAY,OAAO;QACjB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAE,CAAC;IACpC,CAAC;IAED,2EAA2E;IAE3E,kBAAkB;QAChB,OAAO,GAAG,CAAC;IACb,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;IAC5B,CAAC;IAED,UAAU,CAAC,EAA0B;QACnC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,YAAY,CAAC,EAA0B;QACrC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACjC,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;IAC1B,CAAC;IAED,6FAA6F;IAC7F,IAAI,QAAQ;QACV,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,IAAI;QACN,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;IAC1C,CAAC;IAED,IAAI,MAAM;QACR,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,CAAC;IAED,IAAI,IAAI;QACN,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;IACtC,CAAC;IAED,SAAS,CAAC,KAAc,EAAE,MAAc,EAAE,GAAW;QACnD,2EAA2E;QAC3E,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QACtC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;QAClC,IAAI,CAAC,MAAM,EAAE,CAAC;IAChB,CAAC;IAED,YAAY,CAAC,KAAc,EAAE,MAAc,EAAE,GAAW;QACtD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;IAC7C,CAAC;IAED,OAAO;QACL,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,IAAI;QACF,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;IAED,SAAS,CAAC,gBAAgB,GAAG,CAAC;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,gBAAgB,CAAC;QAC9C,sEAAsE;QACtE,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM;YAAE,OAAO;QACxD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,YAAY,EAAE,CAAC;IACtB,CAAC;IAEO,YAAY;QAClB,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC9D,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,iBAAiB,CAAC;YAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtE,CAAC;CACF","sourcesContent":["/**\n * `PlatformLocation` over an in-memory history.\n *\n * Angular's `Location` reads and writes the URL through this. On the web the browser owns the\n * history stack; here nothing does, so we keep it ourselves and the URL tree stays the source of\n * truth in both directions: `router.navigate()` pushes an entry, and a swipe-back reaches the\n * outlet as the screen's `dismissed` event, which usually calls `historyGo(-1)` here and emits\n * `popstate` so the router follows. Not always: see the stack outlet's `popBy` for when the entry\n * behind is another tab.\n *\n * No decorators, so tests can import it at runtime and so it can be provided with `useClass`.\n */\nimport type { LocationChangeListener, PlatformLocation } from '@angular/common';\n/**\n * What the history needs of a deep-link source, which `DeepLinks` from\n * `@ng-native/device` satisfies. Structural rather than the class itself: the router has no\n * use for the rest of it, and a test has no use for a real one.\n */\nexport interface LinkSource {\n /** The path the app was launched with, or null for a normal launch. */\n initialUrl(): string | null;\n /** Links that arrive while the app is running. Returns an unsubscribe. */\n subscribe(listener: (url: string) => void): () => void;\n}\n\ninterface HistoryEntry {\n url: string;\n state: unknown;\n}\n\n/** Split a url into its path, `?search` and `#hash` parts. */\nfunction parse(url: string): { pathname: string; search: string; hash: string } {\n const hashAt = url.indexOf('#');\n const hash = hashAt === -1 ? '' : url.slice(hashAt);\n const withoutHash = hashAt === -1 ? url : url.slice(0, hashAt);\n\n const searchAt = withoutHash.indexOf('?');\n const search = searchAt === -1 ? '' : withoutHash.slice(searchAt);\n const pathname = searchAt === -1 ? withoutHash : withoutHash.slice(0, searchAt);\n\n return { pathname: pathname || '/', search, hash };\n}\n\nexport class NativePlatformLocation implements PlatformLocation {\n private readonly entries: HistoryEntry[] = [{ url: '/', state: null }];\n private cursor = 0;\n\n private readonly popStateListeners = new Set<LocationChangeListener>();\n private readonly hashChangeListeners = new Set<LocationChangeListener>();\n\n /**\n * A deep link is history, not a navigation of its own: the launch url *is* the first entry,\n * and one that arrives later is pushed and announced as a popstate, which is the only thing\n * the router listens to. `links` is null in a test that has no interest in either.\n */\n constructor(links: LinkSource | null = null) {\n const initial = links?.initialUrl();\n if (initial) this.entries[0] = { url: initial, state: null };\n links?.subscribe((url) => this.open(url));\n }\n\n /** Follow a link that arrived while the app was running. */\n open(url: string): void {\n if (url === this.current.url) return;\n this.pushState(null, '', url);\n this.emitPopState();\n }\n\n /**\n * The url of the entry `offset` away from the current one, or null past either end. For the\n * stack outlet, which has to know whether going back reaches the screen a native pop revealed.\n */\n ɵurlAt(offset: number): string | null {\n return this.entries[this.cursor + offset]?.url ?? null;\n }\n\n private get current(): HistoryEntry {\n return this.entries[this.cursor]!;\n }\n\n // --- PlatformLocation ---------------------------------------------------\n\n getBaseHrefFromDOM(): string {\n return '/';\n }\n\n getState(): unknown {\n return this.current.state;\n }\n\n onPopState(fn: LocationChangeListener): VoidFunction {\n this.popStateListeners.add(fn);\n return () => this.popStateListeners.delete(fn);\n }\n\n onHashChange(fn: LocationChangeListener): VoidFunction {\n this.hashChangeListeners.add(fn);\n return () => this.hashChangeListeners.delete(fn);\n }\n\n get href(): string {\n return this.current.url;\n }\n\n /** There is no origin on a device. Angular only ever compares these, never resolves them. */\n get protocol(): string {\n return 'app:';\n }\n\n get hostname(): string {\n return '';\n }\n\n get port(): string {\n return '';\n }\n\n get pathname(): string {\n return parse(this.current.url).pathname;\n }\n\n get search(): string {\n return parse(this.current.url).search;\n }\n\n get hash(): string {\n return parse(this.current.url).hash;\n }\n\n pushState(state: unknown, _title: string, url: string): void {\n // A push after going back discards the forward entries, as a browser does.\n this.entries.length = this.cursor + 1;\n this.entries.push({ url, state });\n this.cursor++;\n }\n\n replaceState(state: unknown, _title: string, url: string): void {\n this.entries[this.cursor] = { url, state };\n }\n\n forward(): void {\n this.historyGo(1);\n }\n\n back(): void {\n this.historyGo(-1);\n }\n\n historyGo(relativePosition = 0): void {\n const target = this.cursor + relativePosition;\n // Out of range is a no-op, matching the browser rather than throwing.\n if (target < 0 || target >= this.entries.length) return;\n this.cursor = target;\n this.emitPopState();\n }\n\n private emitPopState(): void {\n const event = { type: 'popstate', state: this.current.state };\n for (const listener of [...this.popStateListeners]) listener(event);\n }\n}\n"]}
1
+ {"version":3,"file":"native-platform-location.js","sourceRoot":"","sources":["../src/native-platform-location.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `PlatformLocation` over an in-memory history.\n *\n * Angular's `Location` reads and writes the URL through this. On the web the browser owns the\n * history stack; here nothing does, so we keep it ourselves and the URL tree stays the source of\n * truth in both directions: `router.navigate()` pushes an entry, and a swipe-back reaches the\n * outlet as the screen's `dismissed` event, which usually calls `historyGo(-1)` here and emits\n * `popstate` so the router follows. Not always: see the stack outlet's `popBy` for when the entry\n * behind is another tab.\n *\n * No decorators, so tests can import it at runtime and so it can be provided with `useClass`.\n */\nimport type { LocationChangeListener, PlatformLocation } from '@angular/common';\n/**\n * What the history needs of a deep-link source, which `DeepLinks` from\n * `@ng-native/device` satisfies. Structural rather than the class itself: the router has no\n * use for the rest of it, and a test has no use for a real one.\n */\nexport interface LinkSource {\n /** The path the app was launched with, or null for a normal launch. */\n initialUrl(): string | null;\n /** Links that arrive while the app is running. Returns an unsubscribe. */\n subscribe(listener: (url: string) => void): () => void;\n}\n\ninterface HistoryEntry {\n url: string;\n state: unknown;\n}\n\n/** Split a url into its path, `?search` and `#hash` parts. */\nfunction parse(url: string): { pathname: string; search: string; hash: string } {\n const hashAt = url.indexOf('#');\n const hash = hashAt === -1 ? '' : url.slice(hashAt);\n const withoutHash = hashAt === -1 ? url : url.slice(0, hashAt);\n\n const searchAt = withoutHash.indexOf('?');\n const search = searchAt === -1 ? '' : withoutHash.slice(searchAt);\n const pathname = searchAt === -1 ? withoutHash : withoutHash.slice(0, searchAt);\n\n return { pathname: pathname || '/', search, hash };\n}\n\nexport class NativePlatformLocation implements PlatformLocation {\n private readonly entries: HistoryEntry[] = [{ url: '/', state: null }];\n private cursor = 0;\n\n private readonly popStateListeners = new Set<LocationChangeListener>();\n private readonly hashChangeListeners = new Set<LocationChangeListener>();\n\n /**\n * A deep link is history, not a navigation of its own: the launch url *is* the first entry,\n * and one that arrives later is pushed and announced as a popstate, which is the only thing\n * the router listens to. `links` is null in a test that has no interest in either.\n */\n constructor(links: LinkSource | null = null) {\n const initial = links?.initialUrl();\n if (initial) this.entries[0] = { url: initial, state: null };\n links?.subscribe((url) => this.open(url));\n }\n\n /** Follow a link that arrived while the app was running. */\n open(url: string): void {\n if (url === this.current.url) return;\n this.pushState(null, '', url);\n this.emitPopState();\n }\n\n /**\n * The url of the entry `offset` away from the current one, or null past either end. For the\n * stack outlet, which has to know whether going back reaches the screen a native pop revealed.\n */\n ɵurlAt(offset: number): string | null {\n return this.entries[this.cursor + offset]?.url ?? null;\n }\n\n /** The history up to the page showing, oldest first. For parking it across a reload. */\n ɵpages(): readonly { readonly url: string; readonly state: unknown }[] {\n return this.entries.slice(0, this.cursor + 1);\n }\n\n private get current(): HistoryEntry {\n return this.entries[this.cursor]!;\n }\n\n // --- PlatformLocation ---------------------------------------------------\n\n getBaseHrefFromDOM(): string {\n return '/';\n }\n\n getState(): unknown {\n return this.current.state;\n }\n\n onPopState(fn: LocationChangeListener): VoidFunction {\n this.popStateListeners.add(fn);\n return () => this.popStateListeners.delete(fn);\n }\n\n onHashChange(fn: LocationChangeListener): VoidFunction {\n this.hashChangeListeners.add(fn);\n return () => this.hashChangeListeners.delete(fn);\n }\n\n get href(): string {\n return this.current.url;\n }\n\n /** There is no origin on a device. Angular only ever compares these, never resolves them. */\n get protocol(): string {\n return 'app:';\n }\n\n get hostname(): string {\n return '';\n }\n\n get port(): string {\n return '';\n }\n\n get pathname(): string {\n return parse(this.current.url).pathname;\n }\n\n get search(): string {\n return parse(this.current.url).search;\n }\n\n get hash(): string {\n return parse(this.current.url).hash;\n }\n\n pushState(state: unknown, _title: string, url: string): void {\n // A push after going back discards the forward entries, as a browser does.\n this.entries.length = this.cursor + 1;\n this.entries.push({ url, state });\n this.cursor++;\n }\n\n replaceState(state: unknown, _title: string, url: string): void {\n this.entries[this.cursor] = { url, state };\n }\n\n forward(): void {\n this.historyGo(1);\n }\n\n back(): void {\n this.historyGo(-1);\n }\n\n historyGo(relativePosition = 0): void {\n const target = this.cursor + relativePosition;\n // Out of range is a no-op, matching the browser rather than throwing.\n if (target < 0 || target >= this.entries.length) return;\n this.cursor = target;\n this.emitPopState();\n }\n\n private emitPopState(): void {\n const event = { type: 'popstate', state: this.current.state };\n for (const listener of [...this.popStateListeners]) listener(event);\n }\n}\n"]}
@@ -144,6 +144,12 @@ export declare class NativeStackOutlet implements RouterOutletContract, OnInit {
144
144
  private claimPresentation;
145
145
  /** Take a screen out for good: its bindings, its component, and its native view. */
146
146
  private drop;
147
+ /**
148
+ * Take off the lowest screen presented rather than pushed, and every screen over it, for a tab
149
+ * that has gone behind another: see `IN_TAB`. Answers the url of the screen left on top, or null
150
+ * when nothing was presented.
151
+ */
152
+ private dismissPresented;
147
153
  /** Take one entry out of the stack, wherever it is, and drop it. */
148
154
  private remove;
149
155
  /** The id of the navigation in progress, when there is a router to say. */
@@ -26,7 +26,9 @@ import { intentOf } from "./native-navigation.js";
26
26
  import { NativePlatformLocation } from "./native-platform-location.js";
27
27
  import { PRESENTED, withoutPresented } from "./presented-route.js";
28
28
  import { markScreenRoute } from "./tab-routes.js";
29
+ import { IN_TAB } from "./in-tab.js";
29
30
  import { ownHost } from "./own-host.js";
31
+ import { SCREEN_HEADER } from "./screen-header.js";
30
32
  import { HostEngine } from '@ng-native/fabric';
31
33
  import { ActivityState } from "./screens.js";
32
34
  import * as i0 from "@angular/core";
@@ -117,7 +119,9 @@ export class NativeStackOutlet {
117
119
  });
118
120
  const unhold = this.holder ? this.holdRefusals(this.holder) : undefined;
119
121
  const unpresent = this.takePresentedPages(back);
122
+ const unleave = inject(IN_TAB, { optional: true })?.onLeave(() => this.dismissPresented());
120
123
  inject(DestroyRef).onDestroy(() => {
124
+ unleave?.();
121
125
  unhold?.();
122
126
  unpresent?.();
123
127
  unsubscribeBack();
@@ -472,6 +476,19 @@ export class NativeStackOutlet {
472
476
  entry.ref.destroy();
473
477
  this.removeScreen(entry.screen);
474
478
  }
479
+ /**
480
+ * Take off the lowest screen presented rather than pushed, and every screen over it, for a tab
481
+ * that has gone behind another: see `IN_TAB`. Answers the url of the screen left on top, or null
482
+ * when nothing was presented.
483
+ */
484
+ dismissPresented() {
485
+ const index = this.entries.findIndex((entry, at) => at > 0 && (entry.presentation?.stackPresentation ?? 'push') !== 'push');
486
+ if (index === -1)
487
+ return null;
488
+ for (const entry of this.entries.splice(index))
489
+ this.drop(entry);
490
+ return this.router ? this.urlOf(this.entries[index - 1]) : null;
491
+ }
475
492
  /** Take one entry out of the stack, wherever it is, and drop it. */
476
493
  remove(entry) {
477
494
  const index = this.entries.indexOf(entry);
@@ -760,6 +777,7 @@ export class NativeStackOutlet {
760
777
  },
761
778
  },
762
779
  { provide: ActivatedRoute, useValue: route },
780
+ { provide: SCREEN_HEADER, useValue: signal(false) },
763
781
  {
764
782
  provide: ChildrenOutletContexts,
765
783
  useValue: this.parentContexts.getOrCreateContext(outlet).children,