@octane-xplat/ui 0.2.1 → 0.4.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 (126) hide show
  1. package/README.md +46 -0
  2. package/dist/native/octane-client-build.json +1 -1
  3. package/dist/native/ui.js +52 -19
  4. package/dist/native/ui10.js +25 -45
  5. package/dist/native/ui11.js +52 -57
  6. package/dist/native/ui12.js +47 -16
  7. package/dist/native/ui13.js +24 -18
  8. package/dist/native/ui14.js +117 -12
  9. package/dist/native/ui15.js +78 -17
  10. package/dist/native/ui16.js +88 -115
  11. package/dist/native/ui17.js +29 -19
  12. package/dist/native/ui18.js +34 -12
  13. package/dist/native/ui19.js +244 -8
  14. package/dist/native/ui2.js +10 -48
  15. package/dist/native/ui20.js +28 -0
  16. package/dist/native/ui21.js +383 -0
  17. package/dist/native/ui22.js +36 -0
  18. package/dist/native/ui23.js +55 -0
  19. package/dist/native/ui24.js +83 -0
  20. package/dist/native/ui25.js +141 -0
  21. package/dist/native/ui26.js +12 -0
  22. package/dist/native/ui27.js +61 -0
  23. package/dist/native/ui28.js +40 -0
  24. package/dist/native/ui29.js +108 -0
  25. package/dist/native/ui3.js +17 -20
  26. package/dist/native/ui30.js +18 -0
  27. package/dist/native/ui31.js +58 -0
  28. package/dist/native/ui32.js +58 -0
  29. package/dist/native/ui33.js +38 -0
  30. package/dist/native/ui34.js +53 -0
  31. package/dist/native/ui35.js +105 -0
  32. package/dist/native/ui36.js +10 -0
  33. package/dist/native/ui37.js +44 -0
  34. package/dist/native/ui38.js +197 -0
  35. package/dist/native/ui39.js +105 -0
  36. package/dist/native/ui4.js +23 -48
  37. package/dist/native/ui40.js +58 -0
  38. package/dist/native/ui41.js +19 -0
  39. package/dist/native/ui42.js +8 -0
  40. package/dist/native/ui43.js +38 -0
  41. package/dist/native/ui44.js +267 -0
  42. package/dist/native/ui45.js +28 -0
  43. package/dist/native/ui46.js +35 -0
  44. package/dist/native/ui47.js +41 -0
  45. package/dist/native/ui48.js +72 -0
  46. package/dist/native/ui49.js +66 -0
  47. package/dist/native/ui5.js +37 -34
  48. package/dist/native/ui50.js +27 -0
  49. package/dist/native/ui51.js +13 -0
  50. package/dist/native/ui52.js +92 -0
  51. package/dist/native/ui53.js +34 -0
  52. package/dist/native/ui54.js +17 -0
  53. package/dist/native/ui55.js +156 -0
  54. package/dist/native/ui56.js +33 -0
  55. package/dist/native/ui57.js +14 -0
  56. package/dist/native/ui58.js +22 -0
  57. package/dist/native/ui59.js +8 -0
  58. package/dist/native/ui6.js +79 -20
  59. package/dist/native/ui60.js +108 -0
  60. package/dist/native/ui61.js +76 -0
  61. package/dist/native/ui7.js +44 -65
  62. package/dist/native/ui8.js +25 -17
  63. package/dist/native/ui9.js +24 -12
  64. package/dist/web/octane-client-build.json +1 -1
  65. package/dist/web/ui.js +51 -19
  66. package/dist/web/ui10.js +33 -30
  67. package/dist/web/ui11.js +40 -55
  68. package/dist/web/ui12.js +36 -15
  69. package/dist/web/ui13.js +212 -20
  70. package/dist/web/ui14.js +84 -14
  71. package/dist/web/ui15.js +425 -46
  72. package/dist/web/ui16.js +12 -93
  73. package/dist/web/ui17.js +246 -28
  74. package/dist/web/ui18.js +238 -15
  75. package/dist/web/ui19.js +36 -8
  76. package/dist/web/ui2.js +15 -103
  77. package/dist/web/ui20.js +85 -0
  78. package/dist/web/ui21.js +111 -0
  79. package/dist/web/ui22.js +108 -0
  80. package/dist/web/ui23.js +96 -0
  81. package/dist/web/ui24.js +32 -0
  82. package/dist/web/ui25.js +108 -0
  83. package/dist/web/ui26.js +45 -0
  84. package/dist/web/ui27.js +16 -0
  85. package/dist/web/ui28.js +11 -0
  86. package/dist/web/ui29.js +58 -0
  87. package/dist/web/ui3.js +30 -27
  88. package/dist/web/ui30.js +34 -0
  89. package/dist/web/ui31.js +123 -0
  90. package/dist/web/ui32.js +44 -0
  91. package/dist/web/ui33.js +159 -0
  92. package/dist/web/ui34.js +70 -0
  93. package/dist/web/ui35.js +57 -0
  94. package/dist/web/ui36.js +22 -0
  95. package/dist/web/ui37.js +7 -0
  96. package/dist/web/ui38.js +38 -0
  97. package/dist/web/ui39.js +154 -0
  98. package/dist/web/ui4.js +46 -24
  99. package/dist/web/ui40.js +43 -0
  100. package/dist/web/ui41.js +42 -0
  101. package/dist/web/ui42.js +76 -0
  102. package/dist/web/ui43.js +42 -0
  103. package/dist/web/ui44.js +62 -0
  104. package/dist/web/ui45.js +9 -0
  105. package/dist/web/ui46.js +45 -0
  106. package/dist/web/ui47.js +13 -0
  107. package/dist/web/ui48.js +63 -0
  108. package/dist/web/ui49.js +47 -0
  109. package/dist/web/ui5.js +158 -52
  110. package/dist/web/ui50.js +17 -0
  111. package/dist/web/ui51.js +149 -0
  112. package/dist/web/ui52.js +42 -0
  113. package/dist/web/ui53.js +17 -0
  114. package/dist/web/ui54.js +9 -0
  115. package/dist/web/ui55.js +22 -0
  116. package/dist/web/ui56.js +8 -0
  117. package/dist/web/ui57.js +44 -0
  118. package/dist/web/ui58.js +46 -0
  119. package/dist/web/ui6.js +85 -22
  120. package/dist/web/ui7.js +46 -41
  121. package/dist/web/ui8.js +28 -11
  122. package/dist/web/ui9.js +32 -13
  123. package/package.json +18 -6
  124. package/src/theme/tokens.css +444 -47
  125. package/types/index.d.ts +180 -29
  126. package/types/props.d.ts +553 -8
@@ -0,0 +1,12 @@
1
+ import { View } from "./ui6.js";
2
+ import { defineUniversalComponent, universalComponent, universalPlan, universalProps, universalValue } from "@nativescript-community/octane";
3
+ //#region src/ScrollBox.native.tsrx
4
+ var __octaneUniversalPlan0 = universalPlan("nativescript", {
5
+ "kind": "slot",
6
+ "slot": 0
7
+ });
8
+ var ScrollBox = defineUniversalComponent("nativescript", function ScrollBox(props) {
9
+ return universalValue(__octaneUniversalPlan0, [universalComponent("nativescript", View, universalProps([["spread", props]], props.children))]);
10
+ }, { "module": "@nativescript-community/octane" });
11
+ //#endregion
12
+ export { ScrollBox };
@@ -0,0 +1,61 @@
1
+ import { cx } from "./ui2.js";
2
+ import { applyEscapeProps } from "./ui3.js";
3
+ import { glassClassOf, glassConfigOf } from "./ui4.js";
4
+ import { layoutChildProps } from "./ui5.js";
5
+ import { defineUniversalComponent, universalPlan, universalProps, universalValue } from "@nativescript-community/octane";
6
+ //#region src/ScrollView.native.tsrx
7
+ var __octaneUniversalPlan0 = universalPlan("nativescript", {
8
+ "kind": "host",
9
+ "type": "scrollview",
10
+ "propsSlot": 0,
11
+ "children": [{
12
+ "kind": "host",
13
+ "type": "flexboxlayout",
14
+ "bindings": [["flexDirection", 1]],
15
+ "children": [{
16
+ "kind": "slot",
17
+ "slot": 2
18
+ }]
19
+ }]
20
+ });
21
+ var ScrollView = defineUniversalComponent("nativescript", function ScrollView(props) {
22
+ return universalValue(__octaneUniversalPlan0, [
23
+ universalProps([
24
+ [
25
+ "set",
26
+ "ref",
27
+ (v) => applyEscapeProps(v, props)
28
+ ],
29
+ [
30
+ "set",
31
+ "id",
32
+ props.id
33
+ ],
34
+ ["spread", layoutChildProps(props)],
35
+ [
36
+ "set",
37
+ "className",
38
+ cx(glassClassOf(props.glass), props.className)
39
+ ],
40
+ [
41
+ "set",
42
+ "style",
43
+ props.style
44
+ ],
45
+ [
46
+ "set",
47
+ "iosGlassEffect",
48
+ glassConfigOf(props.glass)
49
+ ],
50
+ [
51
+ "set",
52
+ "orientation",
53
+ props.horizontal ? "horizontal" : "vertical"
54
+ ]
55
+ ]),
56
+ props.horizontal ? "row" : "column",
57
+ props.children
58
+ ]);
59
+ }, { "module": "@nativescript-community/octane" });
60
+ //#endregion
61
+ export { ScrollView };
@@ -0,0 +1,40 @@
1
+ import { registerElement } from "@nativescript-community/octane";
2
+ import { SVGView } from "@nativescript-community/ui-svg";
3
+ //#region src/svg.native.ts
4
+ registerElement("svgview", SVGView);
5
+ var SVG_DATA_URI = /^data:image\/svg\+xml[;,]/i;
6
+ var SVG_PATH = /\.svg([?#].*)?$/i;
7
+ var EMPTY_SVG = "<svg xmlns=\"http://www.w3.org/2000/svg\"/>";
8
+ /** True when an `src` carries SVG: inline markup, an svg data URI, or an
9
+ * .svg path/URL. Anything else stays on the raster <image> path. */
10
+ function isSvgSrc(src) {
11
+ return src.trimStart().startsWith("<svg") || SVG_DATA_URI.test(src) || SVG_PATH.test(src);
12
+ }
13
+ /** Normalize an svg-shaped src into SVGView's grammar: file/resource paths and
14
+ * markup pass through, data URIs decode to markup, remote URLs fetch to
15
+ * markup (SVGView has no fetch of its own — it awaits promise srcs). */
16
+ function svgSource(src) {
17
+ if (SVG_DATA_URI.test(src)) {
18
+ const comma = src.indexOf(",");
19
+ const body = src.slice(comma + 1);
20
+ if (src.slice(0, comma).endsWith(";base64")) {
21
+ const atob = globalThis.atob;
22
+ if (!atob) return EMPTY_SVG;
23
+ return atob(body);
24
+ }
25
+ return decodeURIComponent(body);
26
+ }
27
+ if (/^https?:\/\//.test(src)) return fetch(src).then((r) => r.ok ? r.text() : EMPTY_SVG).catch(() => EMPTY_SVG);
28
+ return src;
29
+ }
30
+ /** IconGlyph → a full `<svg>` string for SVGView. `svg` path data gets a
31
+ * `<path>` with the requested fill; `markup` wraps inside a viewBox shell
32
+ * with `color`/`fill` set on the root so `currentColor` and default-fill
33
+ * children pick up the tint. */
34
+ function glyphSvgMarkup(glyph, color) {
35
+ const viewBox = glyph.viewBox ?? "0 0 24 24";
36
+ if (glyph.markup) return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${viewBox}"${color ? ` color="${color}" fill="${color}"` : ""}>${glyph.markup}</svg>`;
37
+ if (glyph.svg) return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${viewBox}"><path d="${glyph.svg}" fill="${color ?? "currentColor"}"/></svg>`;
38
+ }
39
+ //#endregion
40
+ export { glyphSvgMarkup, isSvgSrc, svgSource };
@@ -0,0 +1,108 @@
1
+ import { cx } from "./ui2.js";
2
+ import { applyEscapeProps } from "./ui3.js";
3
+ import { layoutChildProps } from "./ui5.js";
4
+ import { isSvgSrc, svgSource } from "./ui28.js";
5
+ import { defineUniversalComponent, hookSlots, universalIf, universalPlan, universalProps, universalValue, useMemo } from "@nativescript-community/octane";
6
+ import { ImageSource } from "@nativescript/core";
7
+ //#region src/Image.native.tsrx
8
+ var _hs$ = /* @__PURE__ */ hookSlots(2);
9
+ var _h$0 = /* @__PURE__ */ Symbol(_hs$);
10
+ var _h$1 = /* @__PURE__ */ Symbol(_hs$ + 1);
11
+ var __octaneUniversalPlan0 = universalPlan("nativescript", {
12
+ "kind": "host",
13
+ "type": "svgview",
14
+ "propsSlot": 0
15
+ });
16
+ var __octaneUniversalPlan1 = universalPlan("nativescript", {
17
+ "kind": "host",
18
+ "type": "image",
19
+ "propsSlot": 0
20
+ });
21
+ var __octaneUniversalPlan2 = universalPlan("nativescript", {
22
+ "kind": "slot",
23
+ "slot": 0
24
+ });
25
+ var Image = defineUniversalComponent("nativescript", function Image(props) {
26
+ const svg = useMemo(() => isSvgSrc(props.src) ? svgSource(props.src) : null, [props.src], _h$0);
27
+ const source = useMemo(() => {
28
+ const comma = props.src.indexOf(",");
29
+ if (props.src.startsWith("data:") && comma > 0 && props.src.slice(0, comma).endsWith(";base64")) return ImageSource.fromBase64Sync(props.src.slice(comma + 1));
30
+ return props.src;
31
+ }, [props.src], _h$1);
32
+ return universalValue(__octaneUniversalPlan2, [universalIf(svg != null, () => {
33
+ return universalValue(__octaneUniversalPlan0, [universalProps([
34
+ [
35
+ "set",
36
+ "ref",
37
+ (v) => applyEscapeProps(v, props)
38
+ ],
39
+ [
40
+ "set",
41
+ "id",
42
+ props.id
43
+ ],
44
+ ["spread", layoutChildProps(props)],
45
+ [
46
+ "set",
47
+ "className",
48
+ cx(props.className)
49
+ ],
50
+ [
51
+ "set",
52
+ "style",
53
+ props.style
54
+ ],
55
+ [
56
+ "set",
57
+ "src",
58
+ svg
59
+ ],
60
+ [
61
+ "set",
62
+ "stretch",
63
+ "aspectFit"
64
+ ],
65
+ [
66
+ "set",
67
+ "accessibilityLabel",
68
+ props.alt
69
+ ]
70
+ ])]);
71
+ }, () => {
72
+ return universalValue(__octaneUniversalPlan1, [universalProps([
73
+ [
74
+ "set",
75
+ "ref",
76
+ (v) => applyEscapeProps(v, props)
77
+ ],
78
+ [
79
+ "set",
80
+ "id",
81
+ props.id
82
+ ],
83
+ ["spread", layoutChildProps(props)],
84
+ [
85
+ "set",
86
+ "className",
87
+ cx(props.className)
88
+ ],
89
+ [
90
+ "set",
91
+ "style",
92
+ props.style
93
+ ],
94
+ [
95
+ "set",
96
+ "src",
97
+ source
98
+ ],
99
+ [
100
+ "set",
101
+ "accessibilityLabel",
102
+ props.alt
103
+ ]
104
+ ])]);
105
+ })]);
106
+ }, { "module": "@nativescript-community/octane" });
107
+ //#endregion
108
+ export { Image };
@@ -1,21 +1,18 @@
1
- import { defineUniversalComponent, universalPlan, universalValue } from "@nativescript-community/octane";
2
- //#region src/Row.native.tsrx
3
- var __octaneUniversalPlan0 = universalPlan("nativescript", {
4
- "kind": "host",
5
- "type": "flexboxlayout",
6
- "props": { "flexDirection": "row" },
7
- "bindings": [["className", 0], ["style", 1]],
8
- "children": [{
9
- "kind": "slot",
10
- "slot": 2
11
- }]
12
- });
13
- var Row = defineUniversalComponent("nativescript", function Row(props) {
14
- return universalValue(__octaneUniversalPlan0, [
15
- props.className,
16
- props.style,
17
- props.children
18
- ]);
19
- }, { "module": "@nativescript-community/octane" });
1
+ import { isAndroid, isIOS } from "@nativescript/core";
2
+ //#region src/escape-props.native.ts
3
+ /** Apply only the active device's escape bag after the primitive's own props. */
4
+ function applyEscapeProps(view, props) {
5
+ if (!view) return;
6
+ const bag = isIOS ? props.ios : isAndroid ? props.android : void 0;
7
+ if (bag) Object.assign(view, bag);
8
+ }
9
+ /** NativeScript's AccessibilityState is a single enum value, unlike the
10
+ * web's independent ARIA booleans. Priority follows the strongest state. */
11
+ function nativeAccessibilityState(state) {
12
+ if (state?.disabled) return "disabled";
13
+ if (state?.selected) return "selected";
14
+ if (state?.checked === true) return "checked";
15
+ if (state?.checked === false) return "unchecked";
16
+ }
20
17
  //#endregion
21
- export { Row };
18
+ export { applyEscapeProps, nativeAccessibilityState };
@@ -0,0 +1,18 @@
1
+ import { Application } from "@nativescript/core";
2
+ import { hookSlots, useSyncExternalStore } from "octane";
3
+ //#region src/theme/colorScheme.native.ts
4
+ function getColorScheme() {
5
+ return Application.primaryWindow?.systemAppearance?.() ?? Application.systemAppearance?.() ?? "light";
6
+ }
7
+ function subscribeSystemScheme(cb) {
8
+ const h = () => cb();
9
+ Application.on("systemAppearanceChanged", h);
10
+ return () => Application.off("systemAppearanceChanged", h);
11
+ }
12
+ /** Reactive system appearance — 'light' | 'dark', re-renders on OS change. */
13
+ function useColorScheme() {
14
+ return useSyncExternalStore(subscribeSystemScheme, getColorScheme, _h$0);
15
+ }
16
+ var _h$0 = /* @__PURE__ */ Symbol(/* @__PURE__ */ hookSlots(1));
17
+ //#endregion
18
+ export { getColorScheme, subscribeSystemScheme, useColorScheme };
@@ -0,0 +1,58 @@
1
+ import { cx } from "./ui2.js";
2
+ import { getColorScheme, subscribeSystemScheme } from "./ui30.js";
3
+ import { hookSlots, useSyncExternalStore } from "octane";
4
+ //#region src/theme/theme-scheme.ts
5
+ var preference = "system";
6
+ var listeners = /* @__PURE__ */ new Set();
7
+ var emit = () => listeners.forEach((l) => l());
8
+ /** App-level theme override. 'system' clears the override and follows the OS. */
9
+ function setThemePreference(p) {
10
+ if (p !== preference) {
11
+ preference = p;
12
+ emit();
13
+ }
14
+ }
15
+ function getThemePreference() {
16
+ return preference;
17
+ }
18
+ /** The effective scheme: explicit override if set, else system appearance. */
19
+ function getThemeScheme() {
20
+ return preference === "system" ? getColorScheme() : preference;
21
+ }
22
+ function subscribe(cb) {
23
+ listeners.add(cb);
24
+ const offSystem = subscribeSystemScheme(cb);
25
+ return () => {
26
+ listeners.delete(cb);
27
+ offSystem();
28
+ };
29
+ }
30
+ /** Reactive effective scheme — re-renders on override or OS change. */
31
+ function useThemeScheme() {
32
+ return useSyncExternalStore(subscribe, getThemeScheme, _h$0);
33
+ }
34
+ /** Class string to stamp on independently-mounted roots (portal hosts,
35
+ * overlay/sheet/modal/toast containers): 'ns-dark dark' when effective
36
+ * dark, '' otherwise. Both names because tokens.css publishes both
37
+ * selectors and hosts may render either vocabulary. */
38
+ function themeSchemeClasses() {
39
+ return getThemeScheme() === "dark" ? "ns-dark dark" : "";
40
+ }
41
+ /** Subscribe imperative hosts to effective-scheme changes; returns an
42
+ * unsubscribe. Use for hosts that live outside any render cycle. */
43
+ function onThemeSchemeChange(cb) {
44
+ return subscribe(cb);
45
+ }
46
+ /** Stamp `base + themeSchemeClasses()` onto an imperative host (NS view or
47
+ * DOM element) and keep it live — returns an unsubscribe to call when the
48
+ * host closes. Works on both leaves since both honor `.className`. */
49
+ function applyThemeClasses(view, base) {
50
+ const apply = () => {
51
+ view.className = cx(base, themeSchemeClasses());
52
+ };
53
+ apply();
54
+ return onThemeSchemeChange(apply);
55
+ }
56
+ var _h$0 = /* @__PURE__ */ Symbol(/* @__PURE__ */ hookSlots(1));
57
+ //#endregion
58
+ export { applyThemeClasses, getThemePreference, getThemeScheme, onThemeSchemeChange, setThemePreference, themeSchemeClasses, useThemeScheme };
@@ -0,0 +1,58 @@
1
+ import { applyThemeClasses } from "./ui31.js";
2
+ import { createNativeScriptRoot, defineUniversalComponent, hookSlots, universalPlan, universalValue, useEffect, useRef } from "@nativescript-community/octane";
3
+ import { Frame, GridLayout } from "@nativescript/core";
4
+ //#region src/Modal.native.tsrx
5
+ var _hs$ = /* @__PURE__ */ hookSlots(2);
6
+ var _h$0 = /* @__PURE__ */ Symbol(_hs$);
7
+ var _h$1 = /* @__PURE__ */ Symbol(_hs$ + 1);
8
+ var __octaneUniversalPlan0 = universalPlan("nativescript", {
9
+ "kind": "range",
10
+ "children": [{
11
+ "kind": "slot",
12
+ "slot": 0
13
+ }]
14
+ });
15
+ var __octaneUniversalPlan1 = universalPlan("nativescript", {
16
+ "kind": "range",
17
+ "children": []
18
+ });
19
+ var Panel = defineUniversalComponent("nativescript", function Panel(props) {
20
+ return universalValue(__octaneUniversalPlan0, [props.children]);
21
+ }, { "module": "@nativescript-community/octane" });
22
+ var Modal = defineUniversalComponent("nativescript", function Modal(props) {
23
+ const shown = useRef(null, _h$0);
24
+ useEffect(() => {
25
+ if (props.open && !shown.current) {
26
+ const presenter = Frame.topmost()?.currentPage ?? Frame.topmost();
27
+ if (!presenter) return;
28
+ const host = new GridLayout();
29
+ const unbindTheme = applyThemeClasses(host, "vx-modal-host");
30
+ const root = createNativeScriptRoot(host);
31
+ shown.current = {
32
+ host,
33
+ root,
34
+ unbindTheme
35
+ };
36
+ if (props.component) root.render(props.component, props.params ?? {});
37
+ else root.render(Panel, { children: props.children });
38
+ const fullscreen = props.presentation ? props.presentation === "fullscreen" : props.fullscreen ?? true;
39
+ presenter.showModal(host, {
40
+ context: {},
41
+ closeCallback: (result) => {
42
+ shown.current?.unbindTheme?.();
43
+ shown.current = null;
44
+ props.onClose?.(result);
45
+ },
46
+ fullscreen,
47
+ animated: true
48
+ });
49
+ } else if (!props.open && shown.current) {
50
+ const { host } = shown.current;
51
+ shown.current = null;
52
+ host.closeModal();
53
+ }
54
+ }, [props.open], _h$1);
55
+ return universalValue(__octaneUniversalPlan1, []);
56
+ }, { "module": "@nativescript-community/octane" });
57
+ //#endregion
58
+ export { Modal };
@@ -0,0 +1,38 @@
1
+ import { applyThemeClasses } from "./ui31.js";
2
+ import { createNativeScriptRoot } from "@nativescript-community/octane";
3
+ import { Frame, GridLayout } from "@nativescript/core";
4
+ //#region src/modal-service.native.ts
5
+ /** Open a component in its own NativeScript modal root and resolve on close. */
6
+ var openModal = (Component, params, options = {}) => new Promise((resolve, reject) => {
7
+ const presenter = Frame.topmost()?.currentPage ?? Frame.topmost();
8
+ if (!presenter) {
9
+ reject(/* @__PURE__ */ new Error("Cannot open modal before a NativeScript page is active"));
10
+ return;
11
+ }
12
+ const host = new GridLayout();
13
+ const unbindTheme = applyThemeClasses(host, "vx-modal-host");
14
+ const root = createNativeScriptRoot(host);
15
+ let finished = false;
16
+ const finish = (result) => {
17
+ if (finished) return;
18
+ finished = true;
19
+ unbindTheme();
20
+ root.unmount?.();
21
+ host.removeChildren?.();
22
+ resolve(result);
23
+ };
24
+ const close = (result) => host.closeModal(result);
25
+ root.render(Component, {
26
+ params,
27
+ close
28
+ });
29
+ const fullscreen = options.presentation ? options.presentation === "fullscreen" : options.fullscreen ?? true;
30
+ presenter.showModal(host, {
31
+ context: {},
32
+ closeCallback: finish,
33
+ fullscreen,
34
+ animated: options.animated ?? true
35
+ });
36
+ });
37
+ //#endregion
38
+ export { openModal };
@@ -0,0 +1,53 @@
1
+ import { RootLayout, getRootLayout } from "@nativescript/core";
2
+ //#region src/root-layout.native.ts
3
+ var registry = [];
4
+ /** Called by the Screen leaf's <rootlayout> onLoaded/onUnloaded. */
5
+ function registerRootLayout(rl) {
6
+ if (rl && !registry.includes(rl)) registry.push(rl);
7
+ }
8
+ function unregisterRootLayout(rl) {
9
+ const i = rl ? registry.indexOf(rl) : -1;
10
+ if (i >= 0) registry.splice(i, 1);
11
+ }
12
+ /** The most recently mounted rootlayout — the top of the push stack. For
13
+ * imperative services (toast, sheet) there is no invoking component to
14
+ * walk from; last-mounted is the pushed page when one exists. Caveat: tabs
15
+ * keep visited panes mounted — last is the newest, not the visible tab. */
16
+ function topRootLayout() {
17
+ return registry[registry.length - 1] ?? getRootLayout();
18
+ }
19
+ /** Resolve the RootLayout enclosing `view` by walking the native parent
20
+ * chain — the screen shell is a RootLayout (Screen.native), so the first
21
+ * RootLayout ancestor IS the current page's overlay host. Falls back to
22
+ * the top registry entry when the component renders outside any Screen. */
23
+ function rootLayoutFor(view) {
24
+ for (let v = view?.parent; v; v = v.parent) if (v instanceof RootLayout) return v;
25
+ return topRootLayout();
26
+ }
27
+ /** Search every registered rootlayout for a view by id — overlays/sheets/
28
+ * toasts land on different rootlayouts depending on which screen's shell
29
+ * mounted last. */
30
+ function findInRootLayouts(id) {
31
+ const walk = (view) => {
32
+ if (!view) return null;
33
+ if (view.id === id) return view;
34
+ let hit = null;
35
+ view.eachChildView?.((c) => {
36
+ const found = walk(c);
37
+ if (found) {
38
+ hit = found;
39
+ return false;
40
+ }
41
+ return true;
42
+ });
43
+ return hit;
44
+ };
45
+ for (let i = registry.length - 1; i >= 0; i--) {
46
+ const hit = walk(registry[i]);
47
+ if (hit) return hit;
48
+ }
49
+ const rl = getRootLayout();
50
+ return rl ? walk(rl) : null;
51
+ }
52
+ //#endregion
53
+ export { findInRootLayouts, registerRootLayout, rootLayoutFor, topRootLayout, unregisterRootLayout };
@@ -0,0 +1,105 @@
1
+ import { cx } from "./ui2.js";
2
+ import { applyThemeClasses } from "./ui31.js";
3
+ import { rootLayoutFor } from "./ui34.js";
4
+ import { createNativeScriptRoot, defineUniversalComponent, hookSlots, universalPlan, universalValue, useEffect, useRef } from "@nativescript-community/octane";
5
+ import { GridLayout, isAndroid, isIOS } from "@nativescript/core";
6
+ //#region src/Overlay.native.tsrx
7
+ var _hs$ = /* @__PURE__ */ hookSlots(4);
8
+ var _h$0 = /* @__PURE__ */ Symbol(_hs$);
9
+ var _h$1 = /* @__PURE__ */ Symbol(_hs$ + 1);
10
+ var _h$2 = /* @__PURE__ */ Symbol(_hs$ + 2);
11
+ var _h$3 = /* @__PURE__ */ Symbol(_hs$ + 3);
12
+ var __octaneUniversalPlan0 = universalPlan("nativescript", {
13
+ "kind": "range",
14
+ "children": [{
15
+ "kind": "slot",
16
+ "slot": 0
17
+ }]
18
+ });
19
+ var __octaneUniversalPlan1 = universalPlan("nativescript", {
20
+ "kind": "host",
21
+ "type": "stacklayout",
22
+ "bindings": [["ref", 0], ["style", 1]]
23
+ });
24
+ var OverlayBody = defineUniversalComponent("nativescript", function OverlayBody(props) {
25
+ return universalValue(__octaneUniversalPlan0, [props.children]);
26
+ }, { "module": "@nativescript-community/octane" });
27
+ var Overlay = defineUniversalComponent("nativescript", function Overlay(props) {
28
+ const shown = useRef(null, _h$0);
29
+ const hostView = useRef(null, _h$1);
30
+ const dismiss = useRef(props.onDismiss, _h$2);
31
+ dismiss.current = props.onDismiss;
32
+ const rootLayout = () => rootLayoutFor(hostView.current);
33
+ useEffect(() => {
34
+ const current = shown.current;
35
+ if (!props.open) {
36
+ if (!current) return;
37
+ current.dismissOnClose = false;
38
+ shown.current = null;
39
+ const rl = rootLayout();
40
+ if (rl && rl?.hasChild?.(current.host)) rl.close(current.host).then(() => current.root.unmount?.(), (error) => {
41
+ console.error("[Overlay] close failed", error);
42
+ current.root.unmount?.();
43
+ });
44
+ else current.root.unmount?.();
45
+ return;
46
+ }
47
+ if (current) {
48
+ current.root.render(OverlayBody, { children: props.children });
49
+ current.unbindTheme = applyThemeClasses(current.host, cx("vx-overlay-host", props.className));
50
+ if (props.style) Object.assign(current.host.style, props.style);
51
+ Object.assign(current.host, isIOS ? props.ios : isAndroid ? props.android : void 0);
52
+ return;
53
+ }
54
+ const rl = rootLayout();
55
+ if (!rl) return;
56
+ const host = new GridLayout();
57
+ const unbindTheme = applyThemeClasses(host, cx("vx-overlay-host", props.className));
58
+ host.horizontalAlignment = "stretch";
59
+ host.verticalAlignment = "stretch";
60
+ if (props.style) Object.assign(host.style, props.style);
61
+ Object.assign(host, isIOS ? props.ios : isAndroid ? props.android : void 0);
62
+ const root = createNativeScriptRoot(host);
63
+ const opened = {
64
+ host,
65
+ root,
66
+ dismissOnClose: true,
67
+ unbindTheme
68
+ };
69
+ shown.current = opened;
70
+ root.render(OverlayBody, { children: props.children });
71
+ host.on("closed", () => {
72
+ if (shown.current === opened) shown.current = null;
73
+ opened.unbindTheme?.();
74
+ root.unmount?.();
75
+ if (opened.dismissOnClose) dismiss.current?.();
76
+ });
77
+ const open = () => rl.open(host, props.shadeCover ? { shadeCover: {
78
+ opacity: .45,
79
+ color: "#000000",
80
+ tapToClose: true
81
+ } } : {}).catch((error) => {
82
+ if (shown.current === opened) shown.current = null;
83
+ console.error("[Overlay] open failed", error);
84
+ root.unmount?.();
85
+ });
86
+ if (rl.hasChild?.(host)) rl.close(host).then(open, (error) => console.error("[Overlay] stale host close failed", error));
87
+ else open();
88
+ }, [
89
+ props.open,
90
+ props.children,
91
+ props.shadeCover,
92
+ props.className,
93
+ props.style,
94
+ props.ios,
95
+ props.android
96
+ ], _h$3);
97
+ return universalValue(__octaneUniversalPlan1, [(v) => {
98
+ hostView.current = v;
99
+ }, {
100
+ width: 0,
101
+ height: 0
102
+ }]);
103
+ }, { "module": "@nativescript-community/octane" });
104
+ //#endregion
105
+ export { Overlay };
@@ -0,0 +1,10 @@
1
+ import { isAndroid, isIOS } from "@nativescript/core";
2
+ //#region src/platformProps.native.ts
3
+ /** Apply the matching native escape-hatch bag after the primitive's props. */
4
+ function applyNativeProps(el, props) {
5
+ if (!el) return;
6
+ const bag = isIOS ? props.ios : isAndroid ? props.android : void 0;
7
+ if (bag) Object.assign(el, bag);
8
+ }
9
+ //#endregion
10
+ export { applyNativeProps };
@@ -0,0 +1,44 @@
1
+ //#region src/popover-position.ts
2
+ var opposite = {
3
+ top: "bottom",
4
+ bottom: "top",
5
+ left: "right",
6
+ right: "left"
7
+ };
8
+ /** Place beside the anchor, flip once when the requested side overflows, then clamp. */
9
+ function positionPopover(anchor, panel, viewport, requested = "bottom", gap = 8) {
10
+ const at = (placement) => {
11
+ switch (placement) {
12
+ case "top": return {
13
+ left: anchor.left,
14
+ top: anchor.top - panel.height - gap
15
+ };
16
+ case "bottom": return {
17
+ left: anchor.left,
18
+ top: anchor.top + anchor.height + gap
19
+ };
20
+ case "left": return {
21
+ left: anchor.left - panel.width - gap,
22
+ top: anchor.top
23
+ };
24
+ case "right": return {
25
+ left: anchor.left + anchor.width + gap,
26
+ top: anchor.top
27
+ };
28
+ }
29
+ throw new Error(`Unknown popover placement: ${placement}`);
30
+ };
31
+ const fits = (position) => position.left >= viewport.left && position.top >= viewport.top && position.left + panel.width <= viewport.left + viewport.width && position.top + panel.height <= viewport.top + viewport.height;
32
+ const preferred = at(requested);
33
+ const placement = fits(preferred) ? requested : opposite[requested];
34
+ const raw = placement === requested ? preferred : at(placement);
35
+ const maxLeft = Math.max(viewport.left, viewport.left + viewport.width - panel.width);
36
+ const maxTop = Math.max(viewport.top, viewport.top + viewport.height - panel.height);
37
+ return {
38
+ left: Math.min(maxLeft, Math.max(viewport.left, raw.left)),
39
+ top: Math.min(maxTop, Math.max(viewport.top, raw.top)),
40
+ placement
41
+ };
42
+ }
43
+ //#endregion
44
+ export { positionPopover };