@rdlabo/capacitor-native-ui 0.0.0-stage → 1.2.1
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.
- package/LICENSE +21 -0
- package/Package.swift +23 -0
- package/README.md +53 -2
- package/RdlaboCapacitorNativeUi.podspec +17 -0
- package/android/build.gradle +69 -0
- package/android/proguard-rules.pro +0 -0
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/java/dev/rdlabo/capacitor/nativeui/NativeUI.kt +51 -0
- package/android/src/main/java/dev/rdlabo/capacitor/nativeui/NativeUIPlugin.kt +192 -0
- package/android/src/main/java/dev/rdlabo/capacitor/nativeui/NativeUISnapshot.kt +57 -0
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/core.d.ts +4 -0
- package/dist/core.js +3 -0
- package/dist/native/activation.d.ts +14 -0
- package/dist/native/activation.d.ts.map +1 -0
- package/dist/native/activation.js +305 -0
- package/dist/native/activation.js.map +1 -0
- package/dist/native/components/index.d.ts +19 -0
- package/dist/native/components/index.d.ts.map +1 -0
- package/dist/native/components/index.js +38 -0
- package/dist/native/components/index.js.map +1 -0
- package/dist/native/components/ion-back-button.d.ts +10 -0
- package/dist/native/components/ion-back-button.d.ts.map +1 -0
- package/dist/native/components/ion-back-button.js +21 -0
- package/dist/native/components/ion-back-button.js.map +1 -0
- package/dist/native/components/ion-button.d.ts +10 -0
- package/dist/native/components/ion-button.d.ts.map +1 -0
- package/dist/native/components/ion-button.js +25 -0
- package/dist/native/components/ion-button.js.map +1 -0
- package/dist/native/components/ion-buttons.d.ts +11 -0
- package/dist/native/components/ion-buttons.d.ts.map +1 -0
- package/dist/native/components/ion-buttons.js +30 -0
- package/dist/native/components/ion-buttons.js.map +1 -0
- package/dist/native/components/ion-fab.d.ts +10 -0
- package/dist/native/components/ion-fab.d.ts.map +1 -0
- package/dist/native/components/ion-fab.js +132 -0
- package/dist/native/components/ion-fab.js.map +1 -0
- package/dist/native/components/ion-menu-button.d.ts +13 -0
- package/dist/native/components/ion-menu-button.d.ts.map +1 -0
- package/dist/native/components/ion-menu-button.js +44 -0
- package/dist/native/components/ion-menu-button.js.map +1 -0
- package/dist/native/components/ion-segment.d.ts +11 -0
- package/dist/native/components/ion-segment.d.ts.map +1 -0
- package/dist/native/components/ion-segment.js +30 -0
- package/dist/native/components/ion-segment.js.map +1 -0
- package/dist/native/components/ion-tab-bar.d.ts +11 -0
- package/dist/native/components/ion-tab-bar.d.ts.map +1 -0
- package/dist/native/components/ion-tab-bar.js +50 -0
- package/dist/native/components/ion-tab-bar.js.map +1 -0
- package/dist/native/components/searchable-tabs.d.ts +20 -0
- package/dist/native/components/searchable-tabs.d.ts.map +1 -0
- package/dist/native/components/searchable-tabs.js +413 -0
- package/dist/native/components/searchable-tabs.js.map +1 -0
- package/dist/native/definitions.d.ts +255 -0
- package/dist/native/definitions.d.ts.map +1 -0
- package/dist/native/definitions.js +0 -0
- package/dist/native/extensions.d.ts +31 -0
- package/dist/native/extensions.d.ts.map +1 -0
- package/dist/native/extensions.js +122 -0
- package/dist/native/extensions.js.map +1 -0
- package/dist/native/foldable/fold-state.d.ts +5 -0
- package/dist/native/foldable/fold-state.d.ts.map +1 -0
- package/dist/native/foldable/fold-state.js +15 -0
- package/dist/native/foldable/fold-state.js.map +1 -0
- package/dist/native/foldable/types.d.ts +12 -0
- package/dist/native/foldable/types.d.ts.map +1 -0
- package/dist/native/foldable/types.js +0 -0
- package/dist/native/html.d.ts +9 -0
- package/dist/native/html.d.ts.map +1 -0
- package/dist/native/html.js +188 -0
- package/dist/native/html.js.map +1 -0
- package/dist/native/index.d.ts +10 -0
- package/dist/native/index.d.ts.map +1 -0
- package/dist/native/index.js +28 -0
- package/dist/native/index.js.map +1 -0
- package/dist/native/legacy-layout.d.ts +5 -0
- package/dist/native/legacy-layout.d.ts.map +1 -0
- package/dist/native/legacy-layout.js +27 -0
- package/dist/native/legacy-layout.js.map +1 -0
- package/dist/native/overlays/content.d.ts +4 -0
- package/dist/native/overlays/content.d.ts.map +1 -0
- package/dist/native/overlays/content.js +51 -0
- package/dist/native/overlays/content.js.map +1 -0
- package/dist/native/overlays/controller.d.ts +8 -0
- package/dist/native/overlays/controller.d.ts.map +1 -0
- package/dist/native/overlays/controller.js +285 -0
- package/dist/native/overlays/controller.js.map +1 -0
- package/dist/native/overlays/dialog-animation.d.ts +9 -0
- package/dist/native/overlays/dialog-animation.d.ts.map +1 -0
- package/dist/native/overlays/dialog-animation.js +53 -0
- package/dist/native/overlays/dialog-animation.js.map +1 -0
- package/dist/native/overlays/dismiss-animation.d.ts +4 -0
- package/dist/native/overlays/dismiss-animation.d.ts.map +1 -0
- package/dist/native/overlays/dismiss-animation.js +18 -0
- package/dist/native/overlays/dismiss-animation.js.map +1 -0
- package/dist/native/overlays/focus.d.ts +5 -0
- package/dist/native/overlays/focus.d.ts.map +1 -0
- package/dist/native/overlays/focus.js +59 -0
- package/dist/native/overlays/focus.js.map +1 -0
- package/dist/native/overlays/popover.d.ts +12 -0
- package/dist/native/overlays/popover.d.ts.map +1 -0
- package/dist/native/overlays/popover.js +110 -0
- package/dist/native/overlays/popover.js.map +1 -0
- package/dist/native/overlays/styles.d.ts +11 -0
- package/dist/native/overlays/styles.d.ts.map +1 -0
- package/dist/native/overlays/styles.js +167 -0
- package/dist/native/overlays/styles.js.map +1 -0
- package/dist/native/prehide.d.ts +8 -0
- package/dist/native/prehide.d.ts.map +1 -0
- package/dist/native/prehide.js +238 -0
- package/dist/native/prehide.js.map +1 -0
- package/dist/native/runtime.d.ts +7 -0
- package/dist/native/runtime.d.ts.map +1 -0
- package/dist/native/runtime.js +788 -0
- package/dist/native/runtime.js.map +1 -0
- package/dist/native/shared/bridge.d.ts +6 -0
- package/dist/native/shared/bridge.d.ts.map +1 -0
- package/dist/native/shared/bridge.js +18 -0
- package/dist/native/shared/bridge.js.map +1 -0
- package/dist/native/shared/candidate.d.ts +25 -0
- package/dist/native/shared/candidate.d.ts.map +1 -0
- package/dist/native/shared/candidate.js +106 -0
- package/dist/native/shared/candidate.js.map +1 -0
- package/dist/native/shared/clipping.d.ts +5 -0
- package/dist/native/shared/clipping.d.ts.map +1 -0
- package/dist/native/shared/clipping.js +26 -0
- package/dist/native/shared/clipping.js.map +1 -0
- package/dist/native/shared/crossfade.d.ts +12 -0
- package/dist/native/shared/crossfade.d.ts.map +1 -0
- package/dist/native/shared/crossfade.js +67 -0
- package/dist/native/shared/crossfade.js.map +1 -0
- package/dist/native/shared/diagnostics.d.ts +4 -0
- package/dist/native/shared/diagnostics.d.ts.map +1 -0
- package/dist/native/shared/diagnostics.js +18 -0
- package/dist/native/shared/diagnostics.js.map +1 -0
- package/dist/native/shared/dom.d.ts +46 -0
- package/dist/native/shared/dom.d.ts.map +1 -0
- package/dist/native/shared/dom.js +180 -0
- package/dist/native/shared/dom.js.map +1 -0
- package/dist/native/shared/events.d.ts +15 -0
- package/dist/native/shared/events.d.ts.map +1 -0
- package/dist/native/shared/events.js +17 -0
- package/dist/native/shared/events.js.map +1 -0
- package/dist/native/shared/icons.d.ts +8 -0
- package/dist/native/shared/icons.d.ts.map +1 -0
- package/dist/native/shared/icons.js +61 -0
- package/dist/native/shared/icons.js.map +1 -0
- package/dist/native/shared/modal.d.ts +10 -0
- package/dist/native/shared/modal.d.ts.map +1 -0
- package/dist/native/shared/modal.js +160 -0
- package/dist/native/shared/modal.js.map +1 -0
- package/dist/native/shared/projection-id.d.ts +4 -0
- package/dist/native/shared/projection-id.d.ts.map +1 -0
- package/dist/native/shared/projection-id.js +7 -0
- package/dist/native/shared/projection-id.js.map +1 -0
- package/dist/native/shared/toolbar-options.d.ts +9 -0
- package/dist/native/shared/toolbar-options.d.ts.map +1 -0
- package/dist/native/shared/toolbar-options.js +36 -0
- package/dist/native/shared/toolbar-options.js.map +1 -0
- package/dist/native/shared/vertical-bars-geometry.d.ts +10 -0
- package/dist/native/shared/vertical-bars-geometry.d.ts.map +1 -0
- package/dist/native/shared/vertical-bars-geometry.js +85 -0
- package/dist/native/shared/vertical-bars-geometry.js.map +1 -0
- package/dist/native/startup.d.ts +8 -0
- package/dist/native/startup.d.ts.map +1 -0
- package/dist/native/startup.js +86 -0
- package/dist/native/startup.js.map +1 -0
- package/dist/native/vertical-bars-web-search.d.ts +10 -0
- package/dist/native/vertical-bars-web-search.d.ts.map +1 -0
- package/dist/native/vertical-bars-web-search.js +90 -0
- package/dist/native/vertical-bars-web-search.js.map +1 -0
- package/dist/native/vertical-bars-web.d.ts +5 -0
- package/dist/native/vertical-bars-web.d.ts.map +1 -0
- package/dist/native/vertical-bars-web.js +421 -0
- package/dist/native/vertical-bars-web.js.map +1 -0
- package/dist/native-integration/index.d.ts +25 -0
- package/dist/native-integration/index.d.ts.map +1 -0
- package/dist/native-integration/index.js +33 -0
- package/dist/native-integration/index.js.map +1 -0
- package/dist/vertical-bars.d.ts +6 -0
- package/dist/vertical-bars.js +5 -0
- package/docs/configuration.md +187 -0
- package/docs/framework-independent.md +82 -0
- package/docs/migration.md +206 -0
- package/docs/native-mini-player.md +47 -0
- package/docs/native-ui-extensions.md +365 -0
- package/docs/native-ui.md +409 -0
- package/docs/setup.md +205 -0
- package/docs/vertical-bars.md +379 -0
- package/ios/Sources/NativeUIPlugin/Components/NativeUIButton.swift +71 -0
- package/ios/Sources/NativeUIPlugin/Components/NativeUIButtons.swift +24 -0
- package/ios/Sources/NativeUIPlugin/Components/NativeUIComponents.swift +19 -0
- package/ios/Sources/NativeUIPlugin/Components/NativeUIFab.swift +80 -0
- package/ios/Sources/NativeUIPlugin/Components/NativeUISearchController.swift +439 -0
- package/ios/Sources/NativeUIPlugin/Components/NativeUISegment.swift +91 -0
- package/ios/Sources/NativeUIPlugin/Components/NativeUITabBar.swift +218 -0
- package/ios/Sources/NativeUIPlugin/Components/NativeUIVerticalBars.swift +590 -0
- package/ios/Sources/NativeUIPlugin/Components/NativeUIVerticalSearch.swift +118 -0
- package/ios/Sources/NativeUIPlugin/Extensions/NativeUI.swift +178 -0
- package/ios/Sources/NativeUIPlugin/Extensions/NativeUIRendering.swift +38 -0
- package/ios/Sources/NativeUIPlugin/NativeUIPlugin.swift +615 -0
- package/ios/Sources/NativeUIPlugin/Overlays/NativeUIOverlayController.swift +119 -0
- package/ios/Sources/NativeUIPlugin/Overlays/NativeUIOverlayHost.swift +75 -0
- package/ios/Sources/NativeUIPlugin/Shared/NativeUIControlRendering.swift +21 -0
- package/ios/Sources/NativeUIPlugin/Shared/NativeUICrossfade.swift +35 -0
- package/ios/Sources/NativeUIPlugin/Shared/NativeUIHost.swift +8 -0
- package/ios/Sources/NativeUIPlugin/Shared/NativeUISnapshot.swift +161 -0
- package/ios/Sources/NativeUIPlugin/Shared/NativeUIVerticalBarsGeometry.swift +52 -0
- package/ios/Tests/NativeUIPluginTests/NativeUIExtensionTests.swift +165 -0
- package/ios/Tests/NativeUIPluginTests/NativeUISnapshotTests.swift +805 -0
- package/package.json +89 -4
- package/src/core.ts +15 -0
- package/src/native/activation.ts +394 -0
- package/src/native/components/index.ts +45 -0
- package/src/native/components/ion-back-button.ts +22 -0
- package/src/native/components/ion-button.ts +25 -0
- package/src/native/components/ion-buttons.ts +37 -0
- package/src/native/components/ion-fab.ts +151 -0
- package/src/native/components/ion-menu-button.ts +37 -0
- package/src/native/components/ion-segment.ts +27 -0
- package/src/native/components/ion-tab-bar.ts +50 -0
- package/src/native/components/searchable-tabs.ts +499 -0
- package/src/native/definitions.ts +324 -0
- package/src/native/extensions.ts +176 -0
- package/src/native/foldable/fold-state.ts +10 -0
- package/src/native/foldable/types.ts +4 -0
- package/src/native/html.ts +193 -0
- package/src/native/index.ts +41 -0
- package/src/native/legacy-layout.ts +21 -0
- package/src/native/overlays/content.ts +51 -0
- package/src/native/overlays/controller.ts +349 -0
- package/src/native/overlays/dialog-animation.ts +53 -0
- package/src/native/overlays/dismiss-animation.ts +15 -0
- package/src/native/overlays/focus.ts +64 -0
- package/src/native/overlays/popover.ts +120 -0
- package/src/native/overlays/styles.ts +181 -0
- package/src/native/prehide.ts +285 -0
- package/src/native/runtime.ts +988 -0
- package/src/native/shared/bridge.ts +18 -0
- package/src/native/shared/candidate.ts +162 -0
- package/src/native/shared/clipping.ts +24 -0
- package/src/native/shared/crossfade.ts +67 -0
- package/src/native/shared/diagnostics.ts +13 -0
- package/src/native/shared/dom.ts +304 -0
- package/src/native/shared/events.ts +14 -0
- package/src/native/shared/icons.ts +57 -0
- package/src/native/shared/modal.ts +157 -0
- package/src/native/shared/projection-id.ts +2 -0
- package/src/native/shared/toolbar-options.ts +53 -0
- package/src/native/shared/vertical-bars-geometry.ts +80 -0
- package/src/native/startup.ts +84 -0
- package/src/native/vertical-bars-web-search.ts +86 -0
- package/src/native/vertical-bars-web.ts +498 -0
- package/src/native-integration/index.ts +49 -0
- package/src/vertical-bars.ts +11 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { unprojected, visible } from "./shared/dom.js";
|
|
2
|
+
import { fitsClip } from "./shared/clipping.js";
|
|
3
|
+
import { appendItem, createCandidate } from "./shared/candidate.js";
|
|
4
|
+
//#region src/native/html.ts
|
|
5
|
+
/** Standard HTML sources use standard native renderers, not app-local Swift extensions. */
|
|
6
|
+
const htmlSelector = "[data-native-ui=\"button\"], [data-native-ui=\"back-button\"]";
|
|
7
|
+
const htmlRailSource = (element) => element.matches("[data-native-ui=\"button\"], [data-native-ui=\"back-button\"]") && element.getAttribute("data-native-ui-placement") === "rail";
|
|
8
|
+
const readHTMLControl = (element, id, options) => {
|
|
9
|
+
if (!(options.root ?? element.ownerDocument.body).contains(element) || !element.matches("[data-native-ui=\"button\"], [data-native-ui=\"back-button\"]") || element.closest("[data-native-ui-proxy]")) return;
|
|
10
|
+
if (!element.matches("button, ion-button, [role=\"button\"]") || !visible(element, htmlRailSource(element))) return;
|
|
11
|
+
if (element.contains(element.ownerDocument.activeElement)) return;
|
|
12
|
+
if (!htmlRailSource(element) && !fitsClip(element)) return;
|
|
13
|
+
if (options.explicitControls === false || options.explicitControls === void 0 && (options.controls?.toolbar === false || options.controls?.buttons === false)) return;
|
|
14
|
+
if (htmlRailSource(element) && options.verticalBars?.enabled === false) return;
|
|
15
|
+
const kind = element.getAttribute("data-native-ui") === "back-button" ? "back-button" : "button";
|
|
16
|
+
const candidate = createCandidate(element, kind, id, options);
|
|
17
|
+
const item = appendItem(candidate, element, id);
|
|
18
|
+
if (!item) return;
|
|
19
|
+
item.accessibilityLabel = element.getAttribute("aria-labelledby")?.trim().split(/\s+/).map((key) => element.ownerDocument.getElementById(key)?.textContent?.trim() ?? "").filter(Boolean).join(" ") || element.getAttribute("aria-label") || item.label;
|
|
20
|
+
if (!item.accessibilityLabel) return;
|
|
21
|
+
item.disabled || (item.disabled = element.matches(":disabled, [disabled]") || !!element.closest("[aria-disabled=\"true\"]"));
|
|
22
|
+
if (htmlRailSource(element)) candidate.control.placement = "vertical-bars";
|
|
23
|
+
return candidate;
|
|
24
|
+
};
|
|
25
|
+
/** A rail host is supplied and styled by the application, never by the plugin. */
|
|
26
|
+
const createHTMLWebProjection = (doc, options) => {
|
|
27
|
+
const host = options.rail?.host;
|
|
28
|
+
if (!host) {
|
|
29
|
+
let stopped = false;
|
|
30
|
+
return {
|
|
31
|
+
markForCheck: () => {},
|
|
32
|
+
getStatus: () => ({
|
|
33
|
+
state: stopped ? "stopped" : "web",
|
|
34
|
+
projected: 0,
|
|
35
|
+
updates: 0
|
|
36
|
+
}),
|
|
37
|
+
suspend: async () => ({ resume: async () => {} }),
|
|
38
|
+
destroy: async () => {
|
|
39
|
+
stopped = true;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const win = doc.defaultView;
|
|
44
|
+
const owned = /* @__PURE__ */ new Map();
|
|
45
|
+
const style = doc.createElement("style");
|
|
46
|
+
style.textContent = `[data-native-ui-web-source] { visibility: hidden !important; pointer-events: none !important; }`;
|
|
47
|
+
doc.head.append(style);
|
|
48
|
+
let frame = 0;
|
|
49
|
+
let stopped = false;
|
|
50
|
+
let suspended = 0;
|
|
51
|
+
let updates = 0;
|
|
52
|
+
const restore = (source) => {
|
|
53
|
+
const state = owned.get(source);
|
|
54
|
+
if (!state) return;
|
|
55
|
+
const focused = state.clone.contains(doc.activeElement);
|
|
56
|
+
state.clone.remove();
|
|
57
|
+
source.removeAttribute("data-native-ui-web-source");
|
|
58
|
+
if (focused && source.isConnected && !source.hasAttribute("data-native-ui-projected")) source.focus();
|
|
59
|
+
owned.delete(source);
|
|
60
|
+
};
|
|
61
|
+
const measure = (source, read) => {
|
|
62
|
+
const hidden = source.hasAttribute("data-native-ui-web-source");
|
|
63
|
+
if (hidden) source.removeAttribute("data-native-ui-web-source");
|
|
64
|
+
try {
|
|
65
|
+
return unprojected([source], read);
|
|
66
|
+
} finally {
|
|
67
|
+
if (hidden) source.setAttribute("data-native-ui-web-source", "");
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const render = () => {
|
|
71
|
+
frame = 0;
|
|
72
|
+
if (stopped) return;
|
|
73
|
+
observer.disconnect();
|
|
74
|
+
observer.observe(doc.documentElement, {
|
|
75
|
+
subtree: true,
|
|
76
|
+
childList: true,
|
|
77
|
+
attributes: true,
|
|
78
|
+
characterData: true
|
|
79
|
+
});
|
|
80
|
+
const wanted = /* @__PURE__ */ new Set();
|
|
81
|
+
if (!suspended && options.verticalBars?.enabled !== false && host?.isConnected && options.root?.isConnected) {
|
|
82
|
+
const sources = Array.from(options.root.querySelectorAll(htmlSelector));
|
|
83
|
+
let back = false;
|
|
84
|
+
for (const source of sources) {
|
|
85
|
+
if (!htmlRailSource(source) || host.contains(source) || source.closest(`[data-native-ui-projected]`)) continue;
|
|
86
|
+
const iconRoot = source.querySelector("ion-icon")?.shadowRoot;
|
|
87
|
+
if (iconRoot) observer.observe(iconRoot, {
|
|
88
|
+
subtree: true,
|
|
89
|
+
childList: true,
|
|
90
|
+
attributes: true,
|
|
91
|
+
characterData: true
|
|
92
|
+
});
|
|
93
|
+
const candidate = measure(source, () => readHTMLControl(source, () => "web", options));
|
|
94
|
+
if (!candidate) continue;
|
|
95
|
+
if (candidate.control.kind === "back-button") {
|
|
96
|
+
if (back) continue;
|
|
97
|
+
back = true;
|
|
98
|
+
}
|
|
99
|
+
wanted.add(source);
|
|
100
|
+
const item = candidate.control.items[0];
|
|
101
|
+
const svg = source.querySelector("svg") ?? iconRoot?.querySelector("svg");
|
|
102
|
+
const signature = JSON.stringify([
|
|
103
|
+
item,
|
|
104
|
+
source.innerHTML,
|
|
105
|
+
svg?.outerHTML
|
|
106
|
+
]);
|
|
107
|
+
let state = owned.get(source);
|
|
108
|
+
if (!state) {
|
|
109
|
+
const clone = doc.createElement("button");
|
|
110
|
+
clone.type = "button";
|
|
111
|
+
clone.setAttribute("data-native-ui-proxy", candidate.control.kind);
|
|
112
|
+
state = {
|
|
113
|
+
clone,
|
|
114
|
+
aria: source.getAttribute("aria-hidden"),
|
|
115
|
+
signature: ""
|
|
116
|
+
};
|
|
117
|
+
owned.set(source, state);
|
|
118
|
+
clone.addEventListener("click", () => {
|
|
119
|
+
const current = !stopped && !suspended && measure(source, () => readHTMLControl(source, () => "web", options));
|
|
120
|
+
if (options.verticalBars?.enabled === false || !current || !htmlRailSource(source) || !host.isConnected || current.control.items[0].disabled || source.closest(`[data-native-ui-projected]`)) return;
|
|
121
|
+
source.click();
|
|
122
|
+
schedule();
|
|
123
|
+
});
|
|
124
|
+
host.append(clone);
|
|
125
|
+
}
|
|
126
|
+
if (state.signature !== signature) {
|
|
127
|
+
state.signature = signature;
|
|
128
|
+
state.clone.replaceChildren();
|
|
129
|
+
if (svg) {
|
|
130
|
+
const icon = svg.cloneNode(true);
|
|
131
|
+
icon.querySelectorAll("[id]").forEach((node) => node.removeAttribute("id"));
|
|
132
|
+
icon.removeAttribute("id");
|
|
133
|
+
for (const node of [icon, ...Array.from(icon.querySelectorAll("*"))]) for (const attr of Array.from(node.attributes)) if (attr.name.startsWith("on")) node.removeAttribute(attr.name);
|
|
134
|
+
state.clone.append(icon);
|
|
135
|
+
}
|
|
136
|
+
state.clone.append(doc.createTextNode(item.label));
|
|
137
|
+
state.clone.setAttribute("aria-label", item.accessibilityLabel);
|
|
138
|
+
state.clone.disabled = item.disabled;
|
|
139
|
+
updates++;
|
|
140
|
+
}
|
|
141
|
+
if (!source.hasAttribute("data-native-ui-web-source")) source.setAttribute("data-native-ui-web-source", "");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
for (const source of owned.keys()) if (!wanted.has(source)) restore(source);
|
|
145
|
+
observer.takeRecords();
|
|
146
|
+
};
|
|
147
|
+
const schedule = () => {
|
|
148
|
+
if (!stopped && !frame) frame = win.requestAnimationFrame(render);
|
|
149
|
+
};
|
|
150
|
+
const observer = new MutationObserver(schedule);
|
|
151
|
+
win.addEventListener("resize", schedule);
|
|
152
|
+
win.addEventListener("nativeUIRefresh", schedule);
|
|
153
|
+
render();
|
|
154
|
+
return {
|
|
155
|
+
markForCheck: schedule,
|
|
156
|
+
getStatus: () => ({
|
|
157
|
+
state: stopped ? "stopped" : "web",
|
|
158
|
+
projected: owned.size,
|
|
159
|
+
updates
|
|
160
|
+
}),
|
|
161
|
+
async suspend() {
|
|
162
|
+
suspended++;
|
|
163
|
+
for (const source of owned.keys()) restore(source);
|
|
164
|
+
let resumed = false;
|
|
165
|
+
return { async resume() {
|
|
166
|
+
if (!resumed) {
|
|
167
|
+
resumed = true;
|
|
168
|
+
suspended--;
|
|
169
|
+
render();
|
|
170
|
+
}
|
|
171
|
+
} };
|
|
172
|
+
},
|
|
173
|
+
async destroy() {
|
|
174
|
+
if (stopped) return;
|
|
175
|
+
stopped = true;
|
|
176
|
+
observer.disconnect();
|
|
177
|
+
win.cancelAnimationFrame(frame);
|
|
178
|
+
win.removeEventListener("resize", schedule);
|
|
179
|
+
win.removeEventListener("nativeUIRefresh", schedule);
|
|
180
|
+
for (const source of owned.keys()) restore(source);
|
|
181
|
+
style.remove();
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
//#endregion
|
|
186
|
+
export { createHTMLWebProjection, htmlRailSource, htmlSelector, readHTMLControl };
|
|
187
|
+
|
|
188
|
+
//# sourceMappingURL=html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.js","names":[],"sources":["../../src/native/html.ts"],"sourcesContent":["import { fitsClip } from './shared/clipping';\nimport type { NativeUIRuntimeOptions, NativeUIRuntimeHandle } from './definitions';\nimport { appendItem, createCandidate, type Candidate, type Identify } from './shared/candidate';\nimport { marker, unprojected, visible } from './shared/dom';\n\n/** Standard HTML sources use standard native renderers, not app-local Swift extensions. */\nexport const htmlSelector = '[data-native-ui=\"button\"], [data-native-ui=\"back-button\"]';\nexport const htmlRailSource = (element: Element) =>\n element.matches(htmlSelector) && element.getAttribute('data-native-ui-placement') === 'rail';\n\nexport const readHTMLControl = (element: HTMLElement, id: Identify, options: NativeUIRuntimeOptions): Candidate | undefined => {\n if (\n !(options.root ?? element.ownerDocument.body).contains(element) ||\n !element.matches(htmlSelector) ||\n element.closest('[data-native-ui-proxy]')\n )\n return;\n // Explicit opt-in; custom elements can implement click() and expose role=button.\n if (!element.matches('button, ion-button, [role=\"button\"]') || !visible(element, htmlRailSource(element))) return;\n if (element.contains(element.ownerDocument.activeElement)) return;\n if (!htmlRailSource(element) && !fitsClip(element)) return;\n if (\n options.explicitControls === false ||\n (options.explicitControls === undefined && (options.controls?.toolbar === false || options.controls?.buttons === false))\n )\n return;\n if (htmlRailSource(element) && options.verticalBars?.enabled === false) return;\n const kind = element.getAttribute('data-native-ui') === 'back-button' ? 'back-button' : 'button';\n const candidate = createCandidate(element, kind, id, options);\n const item = appendItem(candidate, element, id);\n if (!item) return;\n const labelledBy = element\n .getAttribute('aria-labelledby')\n ?.trim()\n .split(/\\s+/)\n .map((key) => element.ownerDocument.getElementById(key)?.textContent?.trim() ?? '')\n .filter(Boolean)\n .join(' ');\n item.accessibilityLabel = labelledBy || element.getAttribute('aria-label') || item.label;\n if (!item.accessibilityLabel) return;\n item.disabled ||= element.matches(':disabled, [disabled]') || !!element.closest('[aria-disabled=\"true\"]');\n if (htmlRailSource(element)) candidate.control.placement = 'vertical-bars';\n return candidate;\n};\n\n/** A rail host is supplied and styled by the application, never by the plugin. */\nexport const createHTMLWebProjection = (doc: Document, options: NativeUIRuntimeOptions): NativeUIRuntimeHandle => {\n const host = options.rail?.host;\n if (!host) {\n let stopped = false;\n return {\n markForCheck: () => {},\n getStatus: () => ({ state: stopped ? 'stopped' : 'web', projected: 0, updates: 0 }),\n suspend: async () => ({ resume: async () => {} }),\n destroy: async () => {\n stopped = true;\n },\n };\n }\n const win = doc.defaultView!;\n const owned = new Map<HTMLElement, { clone: HTMLButtonElement; aria: string | null; signature: string }>();\n const style = doc.createElement('style');\n style.textContent = `[data-native-ui-web-source] { visibility: hidden !important; pointer-events: none !important; }`;\n doc.head.append(style);\n let frame = 0;\n let stopped = false;\n let suspended = 0;\n let updates = 0;\n const restore = (source: HTMLElement) => {\n const state = owned.get(source);\n if (!state) return;\n const focused = state.clone.contains(doc.activeElement);\n state.clone.remove();\n source.removeAttribute('data-native-ui-web-source');\n if (focused && source.isConnected && !source.hasAttribute(marker)) source.focus();\n owned.delete(source);\n };\n const measure = <T>(source: HTMLElement, read: () => T): T => {\n const hidden = source.hasAttribute('data-native-ui-web-source');\n if (hidden) source.removeAttribute('data-native-ui-web-source');\n try {\n return unprojected([source], read);\n } finally {\n if (hidden) source.setAttribute('data-native-ui-web-source', '');\n }\n };\n const render = () => {\n frame = 0;\n if (stopped) return;\n observer.disconnect();\n observer.observe(doc.documentElement, { subtree: true, childList: true, attributes: true, characterData: true });\n const wanted = new Set<HTMLElement>();\n if (!suspended && options.verticalBars?.enabled !== false && host?.isConnected && options.root?.isConnected) {\n const sources = Array.from(options.root.querySelectorAll<HTMLElement>(htmlSelector));\n let back = false;\n for (const source of sources) {\n // An accepted native surface owns its source and descendants. Rejected sources\n // lose the marker and can return to the Web rail on the next render.\n if (!htmlRailSource(source) || host.contains(source) || source.closest(`[${marker}]`)) continue;\n const iconRoot = source.querySelector('ion-icon')?.shadowRoot;\n if (iconRoot) observer.observe(iconRoot, { subtree: true, childList: true, attributes: true, characterData: true });\n const candidate = measure(source, () => readHTMLControl(source, () => 'web', options));\n if (!candidate) continue;\n if (candidate.control.kind === 'back-button') {\n if (back) continue;\n back = true;\n }\n wanted.add(source);\n const item = candidate.control.items[0];\n const svg = source.querySelector('svg') ?? iconRoot?.querySelector('svg');\n const signature = JSON.stringify([item, source.innerHTML, svg?.outerHTML]);\n let state = owned.get(source);\n if (!state) {\n const clone = doc.createElement('button');\n clone.type = 'button';\n clone.setAttribute('data-native-ui-proxy', candidate.control.kind);\n state = { clone, aria: source.getAttribute('aria-hidden'), signature: '' };\n owned.set(source, state);\n clone.addEventListener('click', () => {\n const current = !stopped && !suspended && measure(source, () => readHTMLControl(source, () => 'web', options));\n if (\n options.verticalBars?.enabled === false ||\n !current ||\n !htmlRailSource(source) ||\n !host.isConnected ||\n current.control.items[0].disabled ||\n source.closest(`[${marker}]`)\n )\n return;\n source.click(); // Source owns submission, custom handlers and back navigation.\n schedule();\n });\n host.append(clone);\n }\n if (state.signature !== signature) {\n state.signature = signature;\n state.clone.replaceChildren();\n if (svg) {\n const icon = svg.cloneNode(true) as SVGElement;\n icon.querySelectorAll('[id]').forEach((node) => node.removeAttribute('id'));\n icon.removeAttribute('id');\n for (const node of [icon, ...Array.from(icon.querySelectorAll('*'))])\n for (const attr of Array.from(node.attributes)) if (attr.name.startsWith('on')) node.removeAttribute(attr.name);\n state.clone.append(icon);\n }\n state.clone.append(doc.createTextNode(item.label));\n state.clone.setAttribute('aria-label', item.accessibilityLabel);\n state.clone.disabled = item.disabled;\n updates++;\n }\n if (!source.hasAttribute('data-native-ui-web-source')) source.setAttribute('data-native-ui-web-source', '');\n }\n }\n for (const source of owned.keys()) if (!wanted.has(source)) restore(source);\n // Ignore our own synchronous DOM writes; later application mutations still schedule a refresh.\n observer.takeRecords();\n };\n const schedule = () => {\n if (!stopped && !frame) frame = win.requestAnimationFrame(render);\n };\n const observer = new MutationObserver(schedule);\n win.addEventListener('resize', schedule);\n win.addEventListener('nativeUIRefresh', schedule);\n render();\n return {\n markForCheck: schedule,\n getStatus: () => ({ state: stopped ? 'stopped' : 'web', projected: owned.size, updates }),\n async suspend() {\n suspended++;\n for (const source of owned.keys()) restore(source);\n let resumed = false;\n return {\n async resume() {\n if (!resumed) {\n resumed = true;\n suspended--;\n render();\n }\n },\n };\n },\n async destroy() {\n if (stopped) return;\n stopped = true;\n observer.disconnect();\n win.cancelAnimationFrame(frame);\n win.removeEventListener('resize', schedule);\n win.removeEventListener('nativeUIRefresh', schedule);\n for (const source of owned.keys()) restore(source);\n style.remove();\n },\n };\n};\n"],"mappings":";;;;;AAMA,MAAa,eAAe;AAC5B,MAAa,kBAAkB,YAC7B,QAAQ,QAAA,+DAAoB,KAAK,QAAQ,aAAa,0BAA0B,MAAM;AAExF,MAAa,mBAAmB,SAAsB,IAAc,YAA2D;CAC7H,IACE,EAAE,QAAQ,QAAQ,QAAQ,cAAc,KAAA,CAAM,SAAS,OAAO,KAC9D,CAAC,QAAQ,QAAA,+DAAoB,KAC7B,QAAQ,QAAQ,wBAAwB,GAExC;CAEF,IAAI,CAAC,QAAQ,QAAQ,uCAAqC,KAAK,CAAC,QAAQ,SAAS,eAAe,OAAO,CAAC,GAAG;CAC3G,IAAI,QAAQ,SAAS,QAAQ,cAAc,aAAa,GAAG;CAC3D,IAAI,CAAC,eAAe,OAAO,KAAK,CAAC,SAAS,OAAO,GAAG;CACpD,IACE,QAAQ,qBAAqB,SAC5B,QAAQ,qBAAqB,KAAA,MAAc,QAAQ,UAAU,YAAY,SAAS,QAAQ,UAAU,YAAY,QAEjH;CACF,IAAI,eAAe,OAAO,KAAK,QAAQ,cAAc,YAAY,OAAO;CACxE,MAAM,OAAO,QAAQ,aAAa,gBAAgB,MAAM,gBAAgB,gBAAgB;CACxF,MAAM,YAAY,gBAAgB,SAAS,MAAM,IAAI,OAAO;CAC5D,MAAM,OAAO,WAAW,WAAW,SAAS,EAAE;CAC9C,IAAI,CAAC,MAAM;CAQX,KAAK,qBAPc,QAChB,aAAa,iBAAiB,CAAC,EAC9B,KAAK,CAAC,CACP,MAAM,KAAK,CAAC,CACZ,KAAK,QAAQ,QAAQ,cAAc,eAAe,GAAG,CAAC,EAAE,aAAa,KAAK,KAAK,EAAE,CAAC,CAClF,OAAO,OAAO,CAAC,CACf,KAAK,GAAG,KAC6B,QAAQ,aAAa,YAAY,KAAK,KAAK;CACnF,IAAI,CAAC,KAAK,oBAAoB;CAC9B,KAAK,aAAL,KAAK,WAAa,QAAQ,QAAQ,uBAAuB,KAAK,CAAC,CAAC,QAAQ,QAAQ,0BAAwB;CACxG,IAAI,eAAe,OAAO,GAAG,UAAU,QAAQ,YAAY;CAC3D,OAAO;AACT;;AAGA,MAAa,2BAA2B,KAAe,YAA2D;CAChH,MAAM,OAAO,QAAQ,MAAM;CAC3B,IAAI,CAAC,MAAM;EACT,IAAI,UAAU;EACd,OAAO;GACL,oBAAoB,CAAC;GACrB,kBAAkB;IAAE,OAAO,UAAU,YAAY;IAAO,WAAW;IAAG,SAAS;GAAE;GACjF,SAAS,aAAa,EAAE,QAAQ,YAAY,CAAC,EAAE;GAC/C,SAAS,YAAY;IACnB,UAAU;GACZ;EACF;CACF;CACA,MAAM,MAAM,IAAI;CAChB,MAAM,wBAAQ,IAAI,IAAuF;CACzG,MAAM,QAAQ,IAAI,cAAc,OAAO;CACvC,MAAM,cAAc;CACpB,IAAI,KAAK,OAAO,KAAK;CACrB,IAAI,QAAQ;CACZ,IAAI,UAAU;CACd,IAAI,YAAY;CAChB,IAAI,UAAU;CACd,MAAM,WAAW,WAAwB;EACvC,MAAM,QAAQ,MAAM,IAAI,MAAM;EAC9B,IAAI,CAAC,OAAO;EACZ,MAAM,UAAU,MAAM,MAAM,SAAS,IAAI,aAAa;EACtD,MAAM,MAAM,OAAO;EACnB,OAAO,gBAAgB,2BAA2B;EAClD,IAAI,WAAW,OAAO,eAAe,CAAC,OAAO,aAAA,0BAAmB,GAAG,OAAO,MAAM;EAChF,MAAM,OAAO,MAAM;CACrB;CACA,MAAM,WAAc,QAAqB,SAAqB;EAC5D,MAAM,SAAS,OAAO,aAAa,2BAA2B;EAC9D,IAAI,QAAQ,OAAO,gBAAgB,2BAA2B;EAC9D,IAAI;GACF,OAAO,YAAY,CAAC,MAAM,GAAG,IAAI;EACnC,UAAU;GACR,IAAI,QAAQ,OAAO,aAAa,6BAA6B,EAAE;EACjE;CACF;CACA,MAAM,eAAe;EACnB,QAAQ;EACR,IAAI,SAAS;EACb,SAAS,WAAW;EACpB,SAAS,QAAQ,IAAI,iBAAiB;GAAE,SAAS;GAAM,WAAW;GAAM,YAAY;GAAM,eAAe;EAAK,CAAC;EAC/G,MAAM,yBAAS,IAAI,IAAiB;EACpC,IAAI,CAAC,aAAa,QAAQ,cAAc,YAAY,SAAS,MAAM,eAAe,QAAQ,MAAM,aAAa;GAC3G,MAAM,UAAU,MAAM,KAAK,QAAQ,KAAK,iBAA8B,YAAY,CAAC;GACnF,IAAI,OAAO;GACX,KAAK,MAAM,UAAU,SAAS;IAG5B,IAAI,CAAC,eAAe,MAAM,KAAK,KAAK,SAAS,MAAM,KAAK,OAAO,QAAQ,4BAAa,GAAG;IACvF,MAAM,WAAW,OAAO,cAAc,UAAU,CAAC,EAAE;IACnD,IAAI,UAAU,SAAS,QAAQ,UAAU;KAAE,SAAS;KAAM,WAAW;KAAM,YAAY;KAAM,eAAe;IAAK,CAAC;IAClH,MAAM,YAAY,QAAQ,cAAc,gBAAgB,cAAc,OAAO,OAAO,CAAC;IACrF,IAAI,CAAC,WAAW;IAChB,IAAI,UAAU,QAAQ,SAAS,eAAe;KAC5C,IAAI,MAAM;KACV,OAAO;IACT;IACA,OAAO,IAAI,MAAM;IACjB,MAAM,OAAO,UAAU,QAAQ,MAAM;IACrC,MAAM,MAAM,OAAO,cAAc,KAAK,KAAK,UAAU,cAAc,KAAK;IACxE,MAAM,YAAY,KAAK,UAAU;KAAC;KAAM,OAAO;KAAW,KAAK;IAAS,CAAC;IACzE,IAAI,QAAQ,MAAM,IAAI,MAAM;IAC5B,IAAI,CAAC,OAAO;KACV,MAAM,QAAQ,IAAI,cAAc,QAAQ;KACxC,MAAM,OAAO;KACb,MAAM,aAAa,wBAAwB,UAAU,QAAQ,IAAI;KACjE,QAAQ;MAAE;MAAO,MAAM,OAAO,aAAa,aAAa;MAAG,WAAW;KAAG;KACzE,MAAM,IAAI,QAAQ,KAAK;KACvB,MAAM,iBAAiB,eAAe;MACpC,MAAM,UAAU,CAAC,WAAW,CAAC,aAAa,QAAQ,cAAc,gBAAgB,cAAc,OAAO,OAAO,CAAC;MAC7G,IACE,QAAQ,cAAc,YAAY,SAClC,CAAC,WACD,CAAC,eAAe,MAAM,KACtB,CAAC,KAAK,eACN,QAAQ,QAAQ,MAAM,EAAE,CAAC,YACzB,OAAO,QAAQ,4BAAa,GAE5B;MACF,OAAO,MAAM;MACb,SAAS;KACX,CAAC;KACD,KAAK,OAAO,KAAK;IACnB;IACA,IAAI,MAAM,cAAc,WAAW;KACjC,MAAM,YAAY;KAClB,MAAM,MAAM,gBAAgB;KAC5B,IAAI,KAAK;MACP,MAAM,OAAO,IAAI,UAAU,IAAI;MAC/B,KAAK,iBAAiB,MAAM,CAAC,CAAC,SAAS,SAAS,KAAK,gBAAgB,IAAI,CAAC;MAC1E,KAAK,gBAAgB,IAAI;MACzB,KAAK,MAAM,QAAQ,CAAC,MAAM,GAAG,MAAM,KAAK,KAAK,iBAAiB,GAAG,CAAC,CAAC,GACjE,KAAK,MAAM,QAAQ,MAAM,KAAK,KAAK,UAAU,GAAG,IAAI,KAAK,KAAK,WAAW,IAAI,GAAG,KAAK,gBAAgB,KAAK,IAAI;MAChH,MAAM,MAAM,OAAO,IAAI;KACzB;KACA,MAAM,MAAM,OAAO,IAAI,eAAe,KAAK,KAAK,CAAC;KACjD,MAAM,MAAM,aAAa,cAAc,KAAK,kBAAkB;KAC9D,MAAM,MAAM,WAAW,KAAK;KAC5B;IACF;IACA,IAAI,CAAC,OAAO,aAAa,2BAA2B,GAAG,OAAO,aAAa,6BAA6B,EAAE;GAC5G;EACF;EACA,KAAK,MAAM,UAAU,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,IAAI,MAAM,GAAG,QAAQ,MAAM;EAE1E,SAAS,YAAY;CACvB;CACA,MAAM,iBAAiB;EACrB,IAAI,CAAC,WAAW,CAAC,OAAO,QAAQ,IAAI,sBAAsB,MAAM;CAClE;CACA,MAAM,WAAW,IAAI,iBAAiB,QAAQ;CAC9C,IAAI,iBAAiB,UAAU,QAAQ;CACvC,IAAI,iBAAiB,mBAAmB,QAAQ;CAChD,OAAO;CACP,OAAO;EACL,cAAc;EACd,kBAAkB;GAAE,OAAO,UAAU,YAAY;GAAO,WAAW,MAAM;GAAM;EAAQ;EACvF,MAAM,UAAU;GACd;GACA,KAAK,MAAM,UAAU,MAAM,KAAK,GAAG,QAAQ,MAAM;GACjD,IAAI,UAAU;GACd,OAAO,EACL,MAAM,SAAS;IACb,IAAI,CAAC,SAAS;KACZ,UAAU;KACV;KACA,OAAO;IACT;GACF,EACF;EACF;EACA,MAAM,UAAU;GACd,IAAI,SAAS;GACb,UAAU;GACV,SAAS,WAAW;GACpB,IAAI,qBAAqB,KAAK;GAC9B,IAAI,oBAAoB,UAAU,QAAQ;GAC1C,IAAI,oBAAoB,mBAAmB,QAAQ;GACnD,KAAK,MAAM,UAAU,MAAM,KAAK,GAAG,QAAQ,MAAM;GACjD,MAAM,OAAO;EACf;CACF;AACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { NativeUIExtension, NativeUIImageReference, NativeUIReadContext, NativeUIValue, defineNativeUI } from "./extensions.js";
|
|
2
|
+
import { AutoIonicControls, IonicProjectionOptions, NativeUIComponent, NativeUIControls, NativeUIHandle, NativeUIOptions, NativeUIStatus, NativeUISuspension, NativeUIVerticalBarsOptions, ToolbarProjectionOptions, VerticalBarEdge, VerticalBarPlacement, VerticalControlAreaHandle, VerticalControlAreaOptions, WebViewMetrics } from "./definitions.js";
|
|
3
|
+
import { NativeUI, configureNativeTransition } from "./activation.js";
|
|
4
|
+
import { setVerticalControlAreaPlacement } from "./legacy-layout.js";
|
|
5
|
+
//#region src/native/index.d.ts
|
|
6
|
+
export declare const enableNativeUI: (options?: NativeUIOptions) => Promise<NativeUIHandle>;
|
|
7
|
+
export declare const enableVerticalControlArea: (options?: VerticalControlAreaOptions) => Promise<VerticalControlAreaHandle>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { type AutoIonicControls, type IonicProjectionOptions, NativeUI, type NativeUIComponent, type NativeUIControls, type NativeUIExtension, type NativeUIHandle, type NativeUIImageReference, type NativeUIOptions, type NativeUIReadContext, type NativeUIStatus, type NativeUISuspension, type NativeUIValue, type NativeUIVerticalBarsOptions, type ToolbarProjectionOptions, type VerticalBarEdge, type VerticalBarPlacement, type VerticalControlAreaHandle, type VerticalControlAreaOptions, type WebViewMetrics, configureNativeTransition, defineNativeUI, setVerticalControlAreaPlacement };
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":["_$__definitions0.NativeUIHandle"],"sources":["../../src/native/index.ts"],"mappings":";;;;;qBA0Ba,iBAAkB,UAAS,oBAAoB,QAApBA;qBAG3B,4BAAmC,UAAS,+BAAkC,QAAQ"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { defineNativeUI } from "./extensions.js";
|
|
2
|
+
import { NativeUI, configureNativeTransition } from "./activation.js";
|
|
3
|
+
import { startNativeUI } from "./startup.js";
|
|
4
|
+
import { setVerticalControlAreaPlacement } from "./legacy-layout.js";
|
|
5
|
+
//#region src/native/index.ts
|
|
6
|
+
const enableNativeUI = (options = {}) => startNativeUI(options, async (...args) => (await import("./overlays/controller.js")).createOverlayController(...args));
|
|
7
|
+
const enableVerticalControlArea = async (options = {}) => {
|
|
8
|
+
return {
|
|
9
|
+
...await enableNativeUI({
|
|
10
|
+
extensions: options.extensions,
|
|
11
|
+
horizontal: options.horizontal,
|
|
12
|
+
vertical: options.vertical,
|
|
13
|
+
buttonProjection: options.buttonProjection,
|
|
14
|
+
buttonDefaultFill: options.buttonDefaultFill,
|
|
15
|
+
controls: {
|
|
16
|
+
tabs: true,
|
|
17
|
+
toolbar: true,
|
|
18
|
+
popover: options.controls?.popover === true
|
|
19
|
+
},
|
|
20
|
+
verticalBarsOnly: true
|
|
21
|
+
}),
|
|
22
|
+
setPlacement: setVerticalControlAreaPlacement
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
//#endregion
|
|
26
|
+
export { NativeUI, configureNativeTransition, defineNativeUI, enableNativeUI, enableVerticalControlArea, setVerticalControlAreaPlacement };
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["activate"],"sources":["../../src/native/index.ts"],"sourcesContent":["// Compatibility Ionic entrypoint. Standard HTML consumers can import /core without Ionic.\nimport { startNativeUI as activate } from './startup';\nimport type { NativeUIOptions, VerticalControlAreaOptions, VerticalControlAreaHandle } from './definitions';\nimport { setVerticalControlAreaPlacement } from './legacy-layout';\nexport { setVerticalControlAreaPlacement } from './legacy-layout';\nexport { configureNativeTransition, NativeUI } from './activation';\nexport { defineNativeUI } from './extensions';\nexport type { NativeUIExtension, NativeUIValue, NativeUIReadContext, NativeUIImageReference } from './extensions';\nexport type {\n NativeUIVerticalBarsOptions,\n NativeUIComponent,\n NativeUIControls,\n AutoIonicControls,\n IonicProjectionOptions,\n NativeUIHandle,\n NativeUIOptions,\n NativeUIStatus,\n NativeUISuspension,\n VerticalBarEdge,\n VerticalBarPlacement,\n VerticalControlAreaHandle,\n ToolbarProjectionOptions,\n VerticalControlAreaOptions,\n WebViewMetrics,\n} from './definitions';\n\nexport const enableNativeUI = (options: NativeUIOptions = {}) =>\n activate(options, async (...args) => (await import('./overlays/controller')).createOverlayController(...args));\n\nexport const enableVerticalControlArea = async (options: VerticalControlAreaOptions = {}): Promise<VerticalControlAreaHandle> => {\n const handle = await enableNativeUI({\n extensions: options.extensions,\n horizontal: options.horizontal,\n vertical: options.vertical,\n buttonProjection: options.buttonProjection,\n buttonDefaultFill: options.buttonDefaultFill,\n controls: { tabs: true, toolbar: true, popover: options.controls?.popover === true },\n verticalBarsOnly: true,\n });\n return { ...handle, setPlacement: setVerticalControlAreaPlacement };\n};\n"],"mappings":";;;;;AA0BA,MAAa,kBAAkB,UAA2B,CAAC,MACzDA,cAAS,SAAS,OAAO,GAAG,UAAU,MAAM,OAAO,4BAAA,CAA0B,wBAAwB,GAAG,IAAI,CAAC;AAE/G,MAAa,4BAA4B,OAAO,UAAsC,CAAC,MAA0C;CAU/H,OAAO;EAAE,GAAG,MATS,eAAe;GAClC,YAAY,QAAQ;GACpB,YAAY,QAAQ;GACpB,UAAU,QAAQ;GAClB,kBAAkB,QAAQ;GAC1B,mBAAmB,QAAQ;GAC3B,UAAU;IAAE,MAAM;IAAM,SAAS;IAAM,SAAS,QAAQ,UAAU,YAAY;GAAK;GACnF,kBAAkB;EACpB,CAAC;EACmB,cAAc;CAAgC;AACpE"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { VerticalBarEdge, VerticalBarPlacement } from "./definitions.js";
|
|
2
|
+
//#region src/native/legacy-layout.d.ts
|
|
3
|
+
export declare const setVerticalControlAreaPlacement: (placement: VerticalBarEdge | VerticalBarPlacement, rtl?: boolean) => void;
|
|
4
|
+
//#endregion
|
|
5
|
+
//# sourceMappingURL=legacy-layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy-layout.d.ts","names":[],"sources":["../../src/native/legacy-layout.ts"],"mappings":";;qBASa,kCAAmC,WAAW,kBAAkB,sBAAsB"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/native/legacy-layout.ts
|
|
2
|
+
const physicalVerticalBarEdge = (edge, rtl) => edge === "leading" !== rtl ? "left" : "right";
|
|
3
|
+
const elementRtl = (element) => element.closest("[dir]")?.getAttribute("dir") === "rtl";
|
|
4
|
+
/**
|
|
5
|
+
* @deprecated Use the theme setVerticalBarsLayout helper. nativeEdge is ignored; device metrics determine availability.
|
|
6
|
+
* Legacy Web layout adapter; does not report native availability.
|
|
7
|
+
* Pass `rtl` when the document direction is known; otherwise the nearest `dir` attribute is used.
|
|
8
|
+
*/
|
|
9
|
+
const setVerticalControlAreaPlacement = (placement, rtl) => {
|
|
10
|
+
if (typeof document === "undefined") return;
|
|
11
|
+
const app = document.querySelector("ion-app");
|
|
12
|
+
if (!app) throw new Error("Vertical Control Area requires ion-app");
|
|
13
|
+
const { edge, inset = 0 } = placement && typeof placement === "object" ? placement : {
|
|
14
|
+
edge: placement,
|
|
15
|
+
inset: 0
|
|
16
|
+
};
|
|
17
|
+
app.removeAttribute("data-native-ui-vertical-bars-suspended");
|
|
18
|
+
app.classList.toggle("ios-theme-vertical-bars", edge !== null);
|
|
19
|
+
app.classList.toggle("ios-theme-vertical-bars-left", edge !== null && physicalVerticalBarEdge(edge, rtl ?? elementRtl(app)) === "left");
|
|
20
|
+
if (edge && Number.isFinite(inset) && inset > 0) app.style.setProperty("--ios-theme-vertical-bars-native-inset", `${inset}px`);
|
|
21
|
+
else app.style.removeProperty("--ios-theme-vertical-bars-native-inset");
|
|
22
|
+
document.defaultView?.dispatchEvent(new Event("nativeUIRefresh"));
|
|
23
|
+
};
|
|
24
|
+
//#endregion
|
|
25
|
+
export { setVerticalControlAreaPlacement };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=legacy-layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy-layout.js","names":[],"sources":["../../src/native/legacy-layout.ts"],"sourcesContent":["import type { VerticalBarEdge, VerticalBarPlacement } from './definitions';\nconst physicalVerticalBarEdge = (edge: Exclude<VerticalBarEdge, null>, rtl: boolean) => ((edge === 'leading') !== rtl ? 'left' : 'right');\nconst elementRtl = (element: Element): boolean => element.closest('[dir]')?.getAttribute('dir') === 'rtl';\n\n/**\n * @deprecated Use the theme setVerticalBarsLayout helper. nativeEdge is ignored; device metrics determine availability.\n * Legacy Web layout adapter; does not report native availability.\n * Pass `rtl` when the document direction is known; otherwise the nearest `dir` attribute is used.\n */\nexport const setVerticalControlAreaPlacement = (placement: VerticalBarEdge | VerticalBarPlacement, rtl?: boolean): void => {\n if (typeof document === 'undefined') return;\n const app = document.querySelector<HTMLElement>('ion-app');\n if (!app) throw new Error('Vertical Control Area requires ion-app');\n const { edge, inset = 0 } = placement && typeof placement === 'object' ? placement : { edge: placement, inset: 0 };\n app.removeAttribute('data-native-ui-vertical-bars-suspended');\n app.classList.toggle('ios-theme-vertical-bars', edge !== null);\n app.classList.toggle('ios-theme-vertical-bars-left', edge !== null && physicalVerticalBarEdge(edge, rtl ?? elementRtl(app)) === 'left');\n if (edge && Number.isFinite(inset) && inset > 0) app.style.setProperty('--ios-theme-vertical-bars-native-inset', `${inset}px`);\n else app.style.removeProperty('--ios-theme-vertical-bars-native-inset');\n document.defaultView?.dispatchEvent(new Event('nativeUIRefresh'));\n};\n"],"mappings":";AACA,MAAM,2BAA2B,MAAsC,QAAmB,SAAS,cAAe,MAAM,SAAS;AACjI,MAAM,cAAc,YAA8B,QAAQ,QAAQ,OAAO,CAAC,EAAE,aAAa,KAAK,MAAM;;;;;;AAOpG,MAAa,mCAAmC,WAAmD,QAAwB;CACzH,IAAI,OAAO,aAAa,aAAa;CACrC,MAAM,MAAM,SAAS,cAA2B,SAAS;CACzD,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,wCAAwC;CAClE,MAAM,EAAE,MAAM,QAAQ,MAAM,aAAa,OAAO,cAAc,WAAW,YAAY;EAAE,MAAM;EAAW,OAAO;CAAE;CACjH,IAAI,gBAAgB,wCAAwC;CAC5D,IAAI,UAAU,OAAO,2BAA2B,SAAS,IAAI;CAC7D,IAAI,UAAU,OAAO,gCAAgC,SAAS,QAAQ,wBAAwB,MAAM,OAAO,WAAW,GAAG,CAAC,MAAM,MAAM;CACtI,IAAI,QAAQ,OAAO,SAAS,KAAK,KAAK,QAAQ,GAAG,IAAI,MAAM,YAAY,0CAA0C,GAAG,MAAM,GAAG;MACxH,IAAI,MAAM,eAAe,wCAAwC;CACtE,SAAS,aAAa,cAAc,IAAI,MAAM,iBAAiB,CAAC;AAClE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.d.ts","names":[],"sources":["../../../src/native/overlays/content.ts"],"mappings":";qBAGa,cAAe,SAAS,eAAe,aAAa"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { sheetText } from "./styles.js";
|
|
2
|
+
//#region src/native/overlays/content.ts
|
|
3
|
+
/** Constructed stylesheets cannot cross documents with their nodes. */
|
|
4
|
+
const moveContent = (content, destination) => {
|
|
5
|
+
const home = content.map((element) => ({
|
|
6
|
+
element,
|
|
7
|
+
parent: element.parentNode,
|
|
8
|
+
next: element.nextSibling
|
|
9
|
+
}));
|
|
10
|
+
const roots = [];
|
|
11
|
+
const collect = (node) => {
|
|
12
|
+
if (node.shadowRoot) {
|
|
13
|
+
roots.push({
|
|
14
|
+
root: node.shadowRoot,
|
|
15
|
+
css: sheetText(node.shadowRoot.adoptedStyleSheets),
|
|
16
|
+
sheets: [...node.shadowRoot.adoptedStyleSheets]
|
|
17
|
+
});
|
|
18
|
+
for (const child of Array.from(node.shadowRoot.children)) collect(child);
|
|
19
|
+
}
|
|
20
|
+
for (const child of Array.from(node.children)) collect(child);
|
|
21
|
+
};
|
|
22
|
+
content.forEach(collect);
|
|
23
|
+
for (const element of content) destination.append(destination.ownerDocument.adoptNode(element));
|
|
24
|
+
const styles = roots.filter(({ css }) => css).map(({ root, css }) => {
|
|
25
|
+
const style = destination.ownerDocument.createElement("style");
|
|
26
|
+
style.textContent = css;
|
|
27
|
+
root.append(style);
|
|
28
|
+
return style;
|
|
29
|
+
});
|
|
30
|
+
return () => {
|
|
31
|
+
styles.forEach((style) => style.remove());
|
|
32
|
+
for (const { element, parent, next } of home) {
|
|
33
|
+
const connected = element.isConnected;
|
|
34
|
+
parent.ownerDocument.adoptNode(element);
|
|
35
|
+
if (connected) parent.insertBefore(element, next?.parentNode === parent ? next : null);
|
|
36
|
+
}
|
|
37
|
+
for (const { root, css, sheets } of roots) try {
|
|
38
|
+
root.adoptedStyleSheets = sheets;
|
|
39
|
+
} catch {
|
|
40
|
+
if (css) {
|
|
41
|
+
const style = root.ownerDocument.createElement("style");
|
|
42
|
+
style.textContent = css;
|
|
43
|
+
root.append(style);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
//#endregion
|
|
49
|
+
export { moveContent };
|
|
50
|
+
|
|
51
|
+
//# sourceMappingURL=content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.js","names":[],"sources":["../../../src/native/overlays/content.ts"],"sourcesContent":["import { sheetText } from './styles';\n\n/** Constructed stylesheets cannot cross documents with their nodes. */\nexport const moveContent = (content: HTMLElement[], destination: HTMLElement): (() => void) => {\n const home = content.map((element) => ({ element, parent: element.parentNode!, next: element.nextSibling }));\n const roots: { root: ShadowRoot; css: string; sheets: CSSStyleSheet[] }[] = [];\n const collect = (node: Element) => {\n if (node.shadowRoot) {\n roots.push({\n root: node.shadowRoot,\n css: sheetText(node.shadowRoot.adoptedStyleSheets),\n sheets: [...node.shadowRoot.adoptedStyleSheets],\n });\n for (const child of Array.from(node.shadowRoot.children)) collect(child);\n }\n for (const child of Array.from(node.children)) collect(child);\n };\n content.forEach(collect);\n for (const element of content) destination.append(destination.ownerDocument.adoptNode(element));\n const styles = roots\n .filter(({ css }) => css)\n .map(({ root, css }) => {\n const style = destination.ownerDocument.createElement('style');\n style.textContent = css;\n root.append(style);\n return style;\n });\n return () => {\n styles.forEach((style) => style.remove());\n for (const { element, parent, next } of home) {\n const connected = element.isConnected;\n parent.ownerDocument!.adoptNode(element);\n // Ionic may already have destroyed the Angular component on dismiss.\n if (connected) parent.insertBefore(element, next?.parentNode === parent ? next : null);\n }\n for (const { root, css, sheets } of roots) {\n // WebKit re-associates adopted sheets with the new document across\n // adoptNode, so they may no longer match this root; fall back to the\n // inline copy instead of aborting the remaining restore.\n try {\n root.adoptedStyleSheets = sheets;\n } catch {\n if (css) {\n const style = root.ownerDocument.createElement('style');\n style.textContent = css;\n root.append(style);\n }\n }\n }\n };\n};\n"],"mappings":";;;AAGA,MAAa,eAAe,SAAwB,gBAA2C;CAC7F,MAAM,OAAO,QAAQ,KAAK,aAAa;EAAE;EAAS,QAAQ,QAAQ;EAAa,MAAM,QAAQ;CAAY,EAAE;CAC3G,MAAM,QAAsE,CAAC;CAC7E,MAAM,WAAW,SAAkB;EACjC,IAAI,KAAK,YAAY;GACnB,MAAM,KAAK;IACT,MAAM,KAAK;IACX,KAAK,UAAU,KAAK,WAAW,kBAAkB;IACjD,QAAQ,CAAC,GAAG,KAAK,WAAW,kBAAkB;GAChD,CAAC;GACD,KAAK,MAAM,SAAS,MAAM,KAAK,KAAK,WAAW,QAAQ,GAAG,QAAQ,KAAK;EACzE;EACA,KAAK,MAAM,SAAS,MAAM,KAAK,KAAK,QAAQ,GAAG,QAAQ,KAAK;CAC9D;CACA,QAAQ,QAAQ,OAAO;CACvB,KAAK,MAAM,WAAW,SAAS,YAAY,OAAO,YAAY,cAAc,UAAU,OAAO,CAAC;CAC9F,MAAM,SAAS,MACZ,QAAQ,EAAE,UAAU,GAAG,CAAC,CACxB,KAAK,EAAE,MAAM,UAAU;EACtB,MAAM,QAAQ,YAAY,cAAc,cAAc,OAAO;EAC7D,MAAM,cAAc;EACpB,KAAK,OAAO,KAAK;EACjB,OAAO;CACT,CAAC;CACH,aAAa;EACX,OAAO,SAAS,UAAU,MAAM,OAAO,CAAC;EACxC,KAAK,MAAM,EAAE,SAAS,QAAQ,UAAU,MAAM;GAC5C,MAAM,YAAY,QAAQ;GAC1B,OAAO,cAAe,UAAU,OAAO;GAEvC,IAAI,WAAW,OAAO,aAAa,SAAS,MAAM,eAAe,SAAS,OAAO,IAAI;EACvF;EACA,KAAK,MAAM,EAAE,MAAM,KAAK,YAAY,OAIlC,IAAI;GACF,KAAK,qBAAqB;EAC5B,QAAQ;GACN,IAAI,KAAK;IACP,MAAM,QAAQ,KAAK,cAAc,cAAc,OAAO;IACtD,MAAM,cAAc;IACpB,KAAK,OAAO,KAAK;GACnB;EACF;CAEJ;AACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { NativeUIOptions, NativeUIPlugin } from "../definitions.js";
|
|
2
|
+
//#region src/native/overlays/controller.d.ts
|
|
3
|
+
export declare const createOverlayController: (doc: Document, plugin: NativeUIPlugin, options: NativeUIOptions, retainProjection: (deferActivation?: (id: string) => boolean) => () => void, nativeVerticalBars: () => boolean) => Promise<{
|
|
4
|
+
suspend(): Promise<() => void>;
|
|
5
|
+
destroy(): Promise<void>;
|
|
6
|
+
}>;
|
|
7
|
+
//#endregion
|
|
8
|
+
//# sourceMappingURL=controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.d.ts","names":[],"sources":["../../../src/native/overlays/controller.ts"],"mappings":";;qBAoCa,0BACX,KAAK,UACL,QAAQ,gBACR,SAAS,iBACT,mBAAmB,mBAAmB,uCACtC,sCAAiC"}
|