@rdlabo/ionic-theme-ios27 1.2.1-beta.pr273.shae866fb1dca9f → 1.2.1-beta.pr275.shad339e7688db7
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/dist/native/definitions.d.ts +7 -0
- package/dist/native/definitions.d.ts.map +1 -1
- package/dist/native/index.d.ts.map +1 -1
- package/dist/native/index.js +57 -49
- package/dist/native/index.js.map +1 -1
- package/dist/native/overlays/controller.d.ts.map +1 -1
- package/dist/native/overlays/controller.js +30 -11
- package/dist/native/overlays/controller.js.map +1 -1
- package/dist/native/overlays/dialog-animation.d.ts +2 -1
- package/dist/native/overlays/dialog-animation.d.ts.map +1 -1
- package/dist/native/overlays/dialog-animation.js +25 -3
- package/dist/native/overlays/dialog-animation.js.map +1 -1
- package/dist/native/overlays/popover.d.ts +1 -0
- package/dist/native/overlays/popover.d.ts.map +1 -1
- package/dist/native/overlays/popover.js +33 -1
- package/dist/native/overlays/popover.js.map +1 -1
- package/dist/native/overlays/styles.d.ts +3 -1
- package/dist/native/overlays/styles.d.ts.map +1 -1
- package/dist/native/overlays/styles.js +89 -4
- package/dist/native/overlays/styles.js.map +1 -1
- package/dist/native/runtime.d.ts +0 -1
- package/dist/native/runtime.d.ts.map +1 -1
- package/dist/native/runtime.js +107 -57
- package/dist/native/runtime.js.map +1 -1
- 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/crossfade.d.ts +3 -1
- package/dist/native/shared/crossfade.d.ts.map +1 -1
- package/dist/native/shared/crossfade.js +19 -2
- package/dist/native/shared/crossfade.js.map +1 -1
- package/dist/native/shared/dom.js +1 -1
- 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/vertical-bars-web-search.d.ts +2 -1
- package/dist/native/vertical-bars-web-search.d.ts.map +1 -1
- package/dist/native/vertical-bars-web-search.js +8 -2
- package/dist/native/vertical-bars-web-search.js.map +1 -1
- package/dist/native/vertical-bars-web.d.ts.map +1 -1
- package/dist/native/vertical-bars-web.js +76 -6
- package/dist/native/vertical-bars-web.js.map +1 -1
- package/docs/native-ui-shell.md +27 -3
- package/docs/vertical-bars.md +15 -0
- package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellFab.swift +0 -3
- package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellTabBar.swift +0 -3
- package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellVerticalBars.swift +75 -21
- package/ios/Sources/IonicNativeUIShellPlugin/IonicNativeUIShellPlugin.swift +70 -20
- package/ios/Sources/IonicNativeUIShellPlugin/Overlays/ShellOverlayController.swift +18 -15
- package/ios/Sources/IonicNativeUIShellPlugin/Overlays/ShellOverlayHost.swift +40 -1
- package/ios/Sources/IonicNativeUIShellPlugin/Shared/ShellVerticalBarsGeometry.swift +52 -0
- package/ios/Tests/IonicNativeUIShellPluginTests/ShellSnapshotTests.swift +111 -0
- package/package.json +1 -1
- package/src/native/definitions.ts +1 -0
- package/src/native/index.ts +74 -57
- package/src/native/overlays/controller.ts +36 -9
- package/src/native/overlays/dialog-animation.ts +27 -4
- package/src/native/overlays/popover.ts +42 -2
- package/src/native/overlays/styles.ts +103 -2
- package/src/native/runtime.ts +147 -63
- package/src/native/shared/bridge.ts +18 -0
- package/src/native/shared/crossfade.ts +20 -3
- package/src/native/shared/vertical-bars-geometry.ts +80 -0
- package/src/native/vertical-bars-web-search.ts +8 -2
- package/src/native/vertical-bars-web.ts +80 -6
|
@@ -137,6 +137,13 @@ export interface NativeUIShellPlugin {
|
|
|
137
137
|
supported: boolean;
|
|
138
138
|
}>;
|
|
139
139
|
getWebViewMetrics(): Promise<WebViewMetrics>;
|
|
140
|
+
getVerticalBarsGeometry(options: {
|
|
141
|
+
viewportWidth: number;
|
|
142
|
+
ids: string[];
|
|
143
|
+
}): Promise<{
|
|
144
|
+
revision?: number;
|
|
145
|
+
items: Record<string, Frame>;
|
|
146
|
+
}>;
|
|
140
147
|
prepareOverlay(options: {
|
|
141
148
|
id: string;
|
|
142
149
|
}): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.d.ts","names":[],"sources":["../../src/native/definitions.ts"],"mappings":";;;iBAKiB;EACf;EACA;EACA;EACA;;iBAGe;EAEf,WAAW,KAAK;EAShB;EAOA;;iBAGe,6BAA6B;EAE5C;EAEA,WAAW;EAEX;;iBAGe;EAEf;EAEA;EAEA;EAEA;EAEA;;iBAGe;EAEf,aAAa;EAEb,WAAW,QAAQ;EAEnB,WAAW;;YAID;iBAEK;EACf,MAAM;EAEN;EAEA,aAAa;;iBAGE,kCAAkC;EAEjD,aAAa,WAAW,kBAAkB,sBAAsB;;iBAGjD;EAEf,UAAU;;iBAGK;EACf;EACA;EACA;EACA;;iBAGe;EACf;EACA;EACA;;iBAGe,kBAAkB;EACjC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA,QAAQ;EACR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;iBAGe,qBAAqB;EACpC;EACA,MAAM;EAEN;EAEA;EACA,OAAO;EACP;EACA;EACA;IAAiB;IAAgB;;EACjC,SAAS;;iBAGM;EACf;EACA,OAAO;EACP,SAAS;EACT;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;iBAGe,yBAAyB;EACxC;EACA;EACA;EACA;;iBAGe;EACf;EACA;EACA;EAEA;EAEA,mBAAmB;EACnB,UAAU;;iBAGK;EACf;EACA;EACA;;iBAGe;EAEf;;iBAGe;EACf,UAAU;IAAY;MAA+B;IAAU;;EAC/D,qBAAqB,QAAQ;EAC7B,eAAe;IAAW;MAAe;EACzC,eAAe;IAAW;IAAY,eAAe;MAA6B;EAClF,eAAe;IAAW;IAAY;MAAsB;EAC5D,aAAa;IAAW;MAAe;EACvC,gBAAgB;EAChB,OAAO,UAAU,gBAAgB;IAAU;IAAkB;IAA6B;;EAC1F,MAAM;IAAW;MAAqB;EACtC,YAAY,kBAAkB,WAAW,OAAO,2BAA2B,QAAQ;EACnF,YAAY,gBAAgB,WAAW,OAAO,4BAA4B,QAAQ;EAClF,YAAY,8BAA8B,WAAW,OAAO,0BAA0B,QAAQ;EAC9F,YAAY,iBAAiB,WAAW,OAAO,6BAA6B,QAAQ;;iBAGrE;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;iBAGe;EACf;EACA"}
|
|
1
|
+
{"version":3,"file":"definitions.d.ts","names":[],"sources":["../../src/native/definitions.ts"],"mappings":";;;iBAKiB;EACf;EACA;EACA;EACA;;iBAGe;EAEf,WAAW,KAAK;EAShB;EAOA;;iBAGe,6BAA6B;EAE5C;EAEA,WAAW;EAEX;;iBAGe;EAEf;EAEA;EAEA;EAEA;EAEA;;iBAGe;EAEf,aAAa;EAEb,WAAW,QAAQ;EAEnB,WAAW;;YAID;iBAEK;EACf,MAAM;EAEN;EAEA,aAAa;;iBAGE,kCAAkC;EAEjD,aAAa,WAAW,kBAAkB,sBAAsB;;iBAGjD;EAEf,UAAU;;iBAGK;EACf;EACA;EACA;EACA;;iBAGe;EACf;EACA;EACA;;iBAGe,kBAAkB;EACjC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA,QAAQ;EACR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;iBAGe,qBAAqB;EACpC;EACA,MAAM;EAEN;EAEA;EACA,OAAO;EACP;EACA;EACA;IAAiB;IAAgB;;EACjC,SAAS;;iBAGM;EACf;EACA,OAAO;EACP,SAAS;EACT;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;iBAGe,yBAAyB;EACxC;EACA;EACA;EACA;;iBAGe;EACf;EACA;EACA;EAEA;EAEA,mBAAmB;EACnB,UAAU;;iBAGK;EACf;EACA;EACA;;iBAGe;EAEf;;iBAGe;EACf,UAAU;IAAY;MAA+B;IAAU;;EAC/D,qBAAqB,QAAQ;EAC7B,wBAAwB;IAAW;IAAuB;MAAkB;IAAU;IAAmB,OAAO,eAAe;;EAC/H,eAAe;IAAW;MAAe;EACzC,eAAe;IAAW;IAAY,eAAe;MAA6B;EAClF,eAAe;IAAW;IAAY;MAAsB;EAC5D,aAAa;IAAW;MAAe;EACvC,gBAAgB;EAChB,OAAO,UAAU,gBAAgB;IAAU;IAAkB;IAA6B;;EAC1F,MAAM;IAAW;MAAqB;EACtC,YAAY,kBAAkB,WAAW,OAAO,2BAA2B,QAAQ;EACnF,YAAY,gBAAgB,WAAW,OAAO,4BAA4B,QAAQ;EAClF,YAAY,8BAA8B,WAAW,OAAO,0BAA0B,QAAQ;EAC9F,YAAY,iBAAiB,WAAW,OAAO,6BAA6B,QAAQ;;iBAGrE;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;iBAGe;EACf;EACA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/native/index.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/native/index.ts"],"mappings":";;;qBAiCa,oBAAkB;qBAqFlB,iCAAsC,QAAQ;qBAkD9C,kCAAmC,WAAW,kBAAkB,sBAAsB;qBAqBtF,4BAAmC,UAAS,+BAAkC,QAAQ;qBAgBtF,sBAAuB,UAAS,yBAA4B,QAAQ"}
|
package/dist/native/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { setConfig } from "../transition/ios.transition.js";
|
|
2
|
+
import { bounded, boundedListener } from "./shared/bridge.js";
|
|
2
3
|
import { observeVerticalBarsModals } from "./shared/modal.js";
|
|
3
4
|
import { createRuntime } from "./runtime.js";
|
|
4
5
|
import { createOverlayController } from "./overlays/controller.js";
|
|
@@ -10,6 +11,17 @@ const plugin = registerPlugin("IonicNativeUIShell");
|
|
|
10
11
|
const IonicNativeUIShell = plugin;
|
|
11
12
|
let active;
|
|
12
13
|
let activeConfiguration;
|
|
14
|
+
let stopping;
|
|
15
|
+
const stopActivation = (owner, destruction) => {
|
|
16
|
+
if (active !== owner) return;
|
|
17
|
+
active = void 0;
|
|
18
|
+
activeConfiguration = void 0;
|
|
19
|
+
stopping = destruction;
|
|
20
|
+
const release = () => {
|
|
21
|
+
if (stopping === destruction) stopping = void 0;
|
|
22
|
+
};
|
|
23
|
+
destruction.then(release, release);
|
|
24
|
+
};
|
|
13
25
|
const web = (reason) => ({
|
|
14
26
|
getStatus: () => ({
|
|
15
27
|
state: "web",
|
|
@@ -41,7 +53,7 @@ const combine = (native, fallback) => ({
|
|
|
41
53
|
});
|
|
42
54
|
/** Wraps a runtime handle with the shared enable-lifecycle: reason, suspend hooks and idempotent destroy. */
|
|
43
55
|
const manage = (handle, lifecycle = {}) => {
|
|
44
|
-
let
|
|
56
|
+
let destruction;
|
|
45
57
|
return {
|
|
46
58
|
getStatus: () => lifecycle.reason ? {
|
|
47
59
|
...handle.getStatus(),
|
|
@@ -55,24 +67,24 @@ const manage = (handle, lifecycle = {}) => {
|
|
|
55
67
|
resume?.();
|
|
56
68
|
} };
|
|
57
69
|
},
|
|
58
|
-
|
|
59
|
-
if (
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
}
|
|
70
|
+
destroy() {
|
|
71
|
+
if (!destruction) {
|
|
72
|
+
destruction = Promise.resolve().then(async () => {
|
|
73
|
+
try {
|
|
74
|
+
await handle.destroy();
|
|
75
|
+
} finally {
|
|
76
|
+
await lifecycle.destroy?.();
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
lifecycle.stopping?.(destruction);
|
|
69
80
|
}
|
|
81
|
+
return destruction;
|
|
70
82
|
}
|
|
71
83
|
};
|
|
72
84
|
};
|
|
73
85
|
/** Reads the current native WebView geometry and applies it to page transitions. */
|
|
74
86
|
const configureNativeTransition = async () => {
|
|
75
|
-
const metrics = typeof document !== "undefined" && Capacitor.getPlatform() === "ios" ? await plugin.getWebViewMetrics() : { radius: 0 };
|
|
87
|
+
const metrics = typeof document !== "undefined" && Capacitor.getPlatform() === "ios" ? await bounded(plugin.getWebViewMetrics()) : { radius: 0 };
|
|
76
88
|
setConfig({ radius: metrics.radius });
|
|
77
89
|
return metrics;
|
|
78
90
|
};
|
|
@@ -159,12 +171,8 @@ const enableVerticalControlArea = async (options = {}) => {
|
|
|
159
171
|
const enableNativeUIShell = (options = {}) => {
|
|
160
172
|
if (options.enabled === false) {
|
|
161
173
|
const current = active;
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
return current ? current.then(async (handle) => {
|
|
165
|
-
await handle.destroy();
|
|
166
|
-
return web("Disabled");
|
|
167
|
-
}) : Promise.resolve(web("Disabled"));
|
|
174
|
+
if (current) stopActivation(current, current.then((handle) => handle.destroy()));
|
|
175
|
+
return (stopping ?? Promise.resolve()).then(() => web("Disabled"));
|
|
168
176
|
}
|
|
169
177
|
if (typeof document === "undefined") return Promise.resolve(web("Requires a document"));
|
|
170
178
|
const controls = options.controls;
|
|
@@ -183,32 +191,29 @@ const enableNativeUIShell = (options = {}) => {
|
|
|
183
191
|
if (active && activeConfiguration !== configuration) return Promise.reject(/* @__PURE__ */ new Error("Native UI Shell is already running with different controls; destroy it before changing configuration."));
|
|
184
192
|
if (active) return active;
|
|
185
193
|
activeConfiguration = configuration;
|
|
186
|
-
const
|
|
187
|
-
const prehide = options.controls === void 0 || options.controls.toolbar === true ? prehideVerticalBarsToolbarSources(document) : void 0;
|
|
194
|
+
const previousStop = stopping;
|
|
188
195
|
let start;
|
|
189
|
-
const
|
|
190
|
-
if (active === start) {
|
|
191
|
-
active = void 0;
|
|
192
|
-
activeConfiguration = void 0;
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
const fallback = (reason) => manage(createVerticalBarsWebProjection(document, options), {
|
|
196
|
-
reason,
|
|
197
|
-
suspend: () => prehide?.suspend(),
|
|
198
|
-
destroy: () => {
|
|
199
|
-
prehide?.stop();
|
|
200
|
-
stopModals();
|
|
201
|
-
},
|
|
202
|
-
release
|
|
203
|
-
});
|
|
196
|
+
const stop = (destruction) => stopActivation(start, destruction);
|
|
204
197
|
return start = active = (async () => {
|
|
198
|
+
if (previousStop) await previousStop.catch(() => {});
|
|
199
|
+
const stopModals = observeVerticalBarsModals(document);
|
|
200
|
+
const prehide = options.controls === void 0 || options.controls.toolbar === true ? prehideVerticalBarsToolbarSources(document) : void 0;
|
|
201
|
+
const fallback = (reason) => manage(createVerticalBarsWebProjection(document, options), {
|
|
202
|
+
reason,
|
|
203
|
+
suspend: () => prehide?.suspend(),
|
|
204
|
+
destroy: () => {
|
|
205
|
+
prehide?.stop();
|
|
206
|
+
stopModals();
|
|
207
|
+
},
|
|
208
|
+
stopping: stop
|
|
209
|
+
});
|
|
205
210
|
if (Capacitor.getPlatform() !== "ios") return fallback("Requires Capacitor iOS");
|
|
206
211
|
let runtime;
|
|
207
212
|
let overlays;
|
|
208
213
|
let metricsListener;
|
|
209
214
|
let stopVerticalBarsLayout;
|
|
210
215
|
try {
|
|
211
|
-
if (!(await plugin.configure({ verticalBarsOnly: options.verticalBarsOnly === true })).supported) return fallback("Requires iOS 26 or later");
|
|
216
|
+
if (!(await bounded(plugin.configure({ verticalBarsOnly: options.verticalBarsOnly === true }))).supported) return fallback("Requires iOS 26 or later");
|
|
212
217
|
if (!options.verticalBarsOnly) stopVerticalBarsLayout = observeNativeVerticalBarsLayout(document);
|
|
213
218
|
const nativeVerticalBars = () => {
|
|
214
219
|
const app = document.querySelector("ion-app.ios-theme-vertical-bars");
|
|
@@ -218,13 +223,13 @@ const enableNativeUIShell = (options = {}) => {
|
|
|
218
223
|
return (app.classList.contains("ios-theme-vertical-bars-left") ? "left" : "right") === physicalVerticalBarEdge(reported.edge, reported.rtl ?? elementRtl(app));
|
|
219
224
|
};
|
|
220
225
|
if (!options.verticalBarsOnly) {
|
|
221
|
-
metricsListener = await plugin.addListener("webViewMetricsChange", (metrics) => {
|
|
226
|
+
metricsListener = await boundedListener(plugin.addListener("webViewMetricsChange", (metrics) => {
|
|
222
227
|
setConfig({ radius: metrics.radius });
|
|
223
|
-
});
|
|
228
|
+
}));
|
|
224
229
|
await configureNativeTransition().catch(() => void 0);
|
|
225
230
|
}
|
|
226
231
|
const native = await createRuntime(document, plugin, options, nativeVerticalBars, options.verticalBarsOnly === true);
|
|
227
|
-
runtime = combine(native, createVerticalBarsWebProjection(document, options, () => !nativeVerticalBars() || native.getStatus().
|
|
232
|
+
runtime = combine(native, createVerticalBarsWebProjection(document, options, () => !nativeVerticalBars() || native.getStatus().projected === 0));
|
|
228
233
|
if (controls?.popover === true) overlays = await createOverlayController(document, plugin, options, native.retain, nativeVerticalBars);
|
|
229
234
|
return manage(runtime, {
|
|
230
235
|
suspend: async () => {
|
|
@@ -235,19 +240,22 @@ const enableNativeUIShell = (options = {}) => {
|
|
|
235
240
|
resumeOverlays?.();
|
|
236
241
|
};
|
|
237
242
|
},
|
|
238
|
-
|
|
243
|
+
stopping: stop,
|
|
239
244
|
destroy: async () => {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
+
try {
|
|
246
|
+
await overlays?.destroy();
|
|
247
|
+
} finally {
|
|
248
|
+
if (metricsListener) await bounded(metricsListener.remove()).catch(() => {});
|
|
249
|
+
stopVerticalBarsLayout?.();
|
|
250
|
+
prehide?.stop();
|
|
251
|
+
stopModals();
|
|
252
|
+
}
|
|
245
253
|
}
|
|
246
254
|
});
|
|
247
255
|
} catch (error) {
|
|
248
|
-
await overlays?.destroy();
|
|
249
|
-
await runtime?.destroy();
|
|
250
|
-
await metricsListener
|
|
256
|
+
await overlays?.destroy().catch(() => {});
|
|
257
|
+
await runtime?.destroy().catch(() => {});
|
|
258
|
+
if (metricsListener) await bounded(metricsListener.remove()).catch(() => {});
|
|
251
259
|
stopVerticalBarsLayout?.();
|
|
252
260
|
return fallback(error instanceof Error ? error.message : String(error));
|
|
253
261
|
}
|
package/dist/native/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/native/index.ts"],"sourcesContent":["import { Capacitor, registerPlugin } from '@capacitor/core';\nimport { setConfig } from '../transition/ios.transition';\nimport type {\n NativeUIShellHandle,\n NativeUIShellOptions,\n NativeUIShellPlugin,\n VerticalBarEdge,\n VerticalBarPlacement,\n VerticalControlAreaHandle,\n VerticalControlAreaOptions,\n WebViewMetrics,\n} from './definitions';\nimport { createRuntime } from './runtime';\nimport { createOverlayController } from './overlays/controller';\nimport { createVerticalBarsWebProjection } from './vertical-bars-web';\nimport { prehideVerticalBarsToolbarSources } from './prehide';\nimport { observeVerticalBarsModals } from './shared/modal';\nexport type {\n NativeUIShellComponent,\n NativeUIShellControls,\n NativeUIShellHandle,\n NativeUIShellOptions,\n NativeUIShellStatus,\n NativeUIShellSuspension,\n VerticalBarEdge,\n VerticalBarPlacement,\n VerticalControlAreaHandle,\n VerticalControlAreaOptions,\n WebViewMetrics,\n} from './definitions';\n\nconst plugin = registerPlugin<NativeUIShellPlugin>('IonicNativeUIShell');\nexport const IonicNativeUIShell = plugin;\nlet active: Promise<NativeUIShellHandle> | undefined;\nlet activeConfiguration: string | undefined;\nconst web = (reason: string): NativeUIShellHandle => ({\n getStatus: () => ({ state: 'web', projected: 0, updates: 0, reason }),\n suspend: async () => ({ resume: async () => {} }),\n destroy: async () => {},\n});\n\nconst combine = (native: NativeUIShellHandle, fallback: NativeUIShellHandle): NativeUIShellHandle => ({\n getStatus() {\n const nativeStatus = native.getStatus();\n const fallbackStatus = fallback.getStatus();\n return {\n ...nativeStatus,\n state:\n nativeStatus.state === 'stopped' && fallbackStatus.state === 'stopped' ? 'stopped' : nativeStatus.projected > 0 ? 'native' : 'web',\n projected: nativeStatus.projected + fallbackStatus.projected,\n updates: nativeStatus.updates + fallbackStatus.updates,\n };\n },\n async suspend() {\n const [nativeLease, fallbackLease] = await Promise.all([native.suspend(), fallback.suspend()]);\n return { resume: async () => void (await Promise.all([nativeLease.resume(), fallbackLease.resume()])) };\n },\n async destroy() {\n await Promise.all([native.destroy(), fallback.destroy()]);\n },\n});\n\n/** Wraps a runtime handle with the shared enable-lifecycle: reason, suspend hooks and idempotent destroy. */\nconst manage = (\n handle: NativeUIShellHandle,\n lifecycle: {\n reason?: string;\n suspend?: () => (() => void) | undefined | Promise<(() => void) | undefined>;\n /** Runs after teardown; clears the shared slot only while this activation owns it. */\n release?: () => void;\n destroy?: () => void | Promise<void>;\n } = {},\n): NativeUIShellHandle => {\n let destroyed = false;\n return {\n getStatus: () => (lifecycle.reason ? { ...handle.getStatus(), reason: lifecycle.reason } : handle.getStatus()),\n async suspend() {\n const lease = await handle.suspend();\n const resume = await lifecycle.suspend?.();\n return {\n async resume() {\n await lease.resume();\n resume?.();\n },\n };\n },\n async destroy() {\n if (destroyed) return;\n destroyed = true;\n try {\n await handle.destroy();\n } finally {\n try {\n await lifecycle.destroy?.();\n } finally {\n lifecycle.release?.();\n }\n }\n },\n };\n};\n\n/** Reads the current native WebView geometry and applies it to page transitions. */\nexport const configureNativeTransition = async (): Promise<WebViewMetrics> => {\n const metrics = typeof document !== 'undefined' && Capacitor.getPlatform() === 'ios' ? await plugin.getWebViewMetrics() : { radius: 0 };\n setConfig({ radius: metrics.radius });\n return metrics;\n};\n\n/** Resolves a logical vertical-bar edge to the physical side for the given direction. */\nconst physicalVerticalBarEdge = (edge: Exclude<VerticalBarEdge, null>, rtl: boolean): 'left' | 'right' =>\n (edge === 'leading') !== rtl ? 'left' : 'right';\n\nconst elementRtl = (element: Element): boolean => element.closest('[dir]')?.getAttribute('dir') === 'rtl';\n\n// Device facts are supplied by the application; the theme only compares placement.\nconst nativePlacements = new WeakMap<HTMLElement, { edge: VerticalBarEdge; rtl?: boolean }>();\nconst horizontalFallbackAttribute = 'data-native-ui-shell-vertical-bars-suspended';\n\n// Keep the requested rail while ordinary Native UI Shell temporarily uses its\n// horizontal layout. Removing the effective class restores normal measurements,\n// toolbar ownership and safe areas throughout the existing rendering pipeline.\nconst observeNativeVerticalBarsLayout = (doc: Document): (() => void) => {\n const reconcile = () => {\n const app = doc.querySelector<HTMLElement>('ion-app');\n if (!app) return;\n const requested = app.classList.contains('ios-theme-vertical-bars') || app.hasAttribute(horizontalFallbackAttribute);\n const suspended = requested && nativePlacements.get(app)?.edge == null;\n if (app.hasAttribute(horizontalFallbackAttribute) !== suspended) app.toggleAttribute(horizontalFallbackAttribute, suspended);\n if (app.classList.contains('ios-theme-vertical-bars') !== (requested && !suspended)) {\n app.classList.toggle('ios-theme-vertical-bars', requested && !suspended);\n }\n };\n const observer = new MutationObserver(reconcile);\n observer.observe(doc.documentElement, { childList: true, subtree: true, attributes: true, attributeFilter: ['class'] });\n doc.defaultView?.addEventListener('nativeUIShellRefresh', reconcile);\n reconcile();\n return () => {\n observer.disconnect();\n doc.defaultView?.removeEventListener('nativeUIShellRefresh', reconcile);\n const app = doc.querySelector<HTMLElement>(`ion-app[${horizontalFallbackAttribute}]`);\n if (app) {\n app.removeAttribute(horizontalFallbackAttribute);\n app.classList.add('ios-theme-vertical-bars');\n }\n };\n};\n\n/**\n * Applies one placement to the CSS layout and both Web/native projections.\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 if (placement && typeof placement === 'object' && placement.nativeEdge !== undefined) {\n nativePlacements.set(app, { edge: placement.nativeEdge, rtl });\n }\n app.removeAttribute(horizontalFallbackAttribute);\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('nativeUIShellRefresh'));\n};\n\n/**\n * Call once after ion-app is mounted. Ionic markup remains the source of truth.\n * Native vertical buttons default to SwiftUI appearance.\n * See VerticalControlAreaOptions for source styling and local overrides.\n */\nexport const enableVerticalControlArea = async (options: VerticalControlAreaOptions = {}): Promise<VerticalControlAreaHandle> => {\n const handle = await enableNativeUIShell({\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 {\n getStatus: () => handle.getStatus(),\n suspend: () => handle.suspend(),\n destroy: () => handle.destroy(),\n setPlacement: setVerticalControlAreaPlacement,\n };\n};\n\n/** Call once at application startup. Ionic markup remains the source of truth. */\nexport const enableNativeUIShell = (options: NativeUIShellOptions = {}): Promise<NativeUIShellHandle> => {\n if (options.enabled === false) {\n const current = active;\n active = undefined;\n activeConfiguration = undefined;\n return current\n ? current.then(async (handle) => {\n await handle.destroy();\n return web('Disabled');\n })\n : Promise.resolve(web('Disabled'));\n }\n if (typeof document === 'undefined') return Promise.resolve(web('Requires a document'));\n const controls = options.controls;\n const configuration = JSON.stringify([\n options.verticalBarsOnly === true,\n options.buttonProjection ?? 'system',\n // Local source overrides can use this even when the startup projection is system.\n options.buttonDefaultFill ?? null,\n ...(['tabs', 'toolbar', 'segment', 'fab'] as const).map((component) => !controls || controls[component] === true),\n controls?.popover === true,\n ]);\n if (active && activeConfiguration !== configuration)\n return Promise.reject(\n new Error('Native UI Shell is already running with different controls; destroy it before changing configuration.'),\n );\n if (active) return active;\n activeConfiguration = configuration;\n const stopModals = observeVerticalBarsModals(document);\n const prehide =\n options.controls === undefined || options.controls.toolbar === true ? prehideVerticalBarsToolbarSources(document) : undefined;\n // A slow destroy of a superseded activation must not release a newer one.\n let start: Promise<NativeUIShellHandle>;\n const release = () => {\n if (active === start) {\n active = undefined;\n activeConfiguration = undefined;\n }\n };\n const fallback = (reason: string) =>\n manage(createVerticalBarsWebProjection(document, options), {\n reason,\n suspend: () => prehide?.suspend(),\n destroy: () => {\n prehide?.stop();\n stopModals();\n },\n release,\n });\n return (start = active =\n (async () => {\n if (Capacitor.getPlatform() !== 'ios') return fallback('Requires Capacitor iOS');\n let runtime: NativeUIShellHandle | undefined;\n let overlays: Awaited<ReturnType<typeof createOverlayController>> | undefined;\n let metricsListener: Awaited<ReturnType<typeof plugin.addListener>> | undefined;\n let stopVerticalBarsLayout: (() => void) | undefined;\n try {\n const capabilities = await plugin.configure({ verticalBarsOnly: options.verticalBarsOnly === true });\n if (!capabilities.supported) return fallback('Requires iOS 26 or later');\n if (!options.verticalBarsOnly) stopVerticalBarsLayout = observeNativeVerticalBarsLayout(document);\n // The application owns device state and selects the rail through placement classes.\n const nativeVerticalBars = () => {\n const app = document.querySelector<HTMLElement>('ion-app.ios-theme-vertical-bars');\n if (!app) return false;\n const reported = nativePlacements.get(app);\n if (!reported?.edge) return false;\n const physicalEdge = app.classList.contains('ios-theme-vertical-bars-left') ? 'left' : 'right';\n return physicalEdge === physicalVerticalBarEdge(reported.edge, reported.rtl ?? elementRtl(app));\n };\n if (!options.verticalBarsOnly) {\n metricsListener = await plugin.addListener('webViewMetricsChange', (metrics) => {\n setConfig({ radius: metrics.radius });\n });\n await configureNativeTransition().catch(() => undefined);\n }\n const native = await createRuntime(document, plugin, options, nativeVerticalBars, options.verticalBarsOnly === true);\n runtime = combine(\n native,\n createVerticalBarsWebProjection(document, options, () => !nativeVerticalBars() || native.getStatus().state === 'stopped'),\n );\n if (controls?.popover === true)\n overlays = await createOverlayController(document, plugin, options, native.retain, nativeVerticalBars);\n return manage(runtime, {\n suspend: async () => {\n const restorePrehide = prehide?.suspend();\n const resumeOverlays = await overlays?.suspend();\n return () => {\n restorePrehide?.();\n resumeOverlays?.();\n };\n },\n release,\n destroy: async () => {\n await overlays?.destroy();\n await metricsListener?.remove().catch(() => {});\n stopVerticalBarsLayout?.();\n prehide?.stop();\n stopModals();\n },\n });\n } catch (error) {\n await overlays?.destroy();\n await runtime?.destroy();\n await metricsListener?.remove().catch(() => {});\n stopVerticalBarsLayout?.();\n return fallback(error instanceof Error ? error.message : String(error));\n }\n })());\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/native/index.ts"],"sourcesContent":["import { Capacitor, registerPlugin } from '@capacitor/core';\nimport { setConfig } from '../transition/ios.transition';\nimport type {\n NativeUIShellHandle,\n NativeUIShellOptions,\n NativeUIShellPlugin,\n VerticalBarEdge,\n VerticalBarPlacement,\n VerticalControlAreaHandle,\n VerticalControlAreaOptions,\n WebViewMetrics,\n} from './definitions';\nimport { createRuntime } from './runtime';\nimport { bounded, boundedListener } from './shared/bridge';\nimport { createOverlayController } from './overlays/controller';\nimport { createVerticalBarsWebProjection } from './vertical-bars-web';\nimport { prehideVerticalBarsToolbarSources } from './prehide';\nimport { observeVerticalBarsModals } from './shared/modal';\nexport type {\n NativeUIShellComponent,\n NativeUIShellControls,\n NativeUIShellHandle,\n NativeUIShellOptions,\n NativeUIShellStatus,\n NativeUIShellSuspension,\n VerticalBarEdge,\n VerticalBarPlacement,\n VerticalControlAreaHandle,\n VerticalControlAreaOptions,\n WebViewMetrics,\n} from './definitions';\n\nconst plugin = registerPlugin<NativeUIShellPlugin>('IonicNativeUIShell');\nexport const IonicNativeUIShell = plugin;\nlet active: Promise<NativeUIShellHandle> | undefined;\nlet activeConfiguration: string | undefined;\nlet stopping: Promise<void> | undefined;\n\n// Every stop entry point releases the activation immediately but reserves the\n// shared native/DOM resources until its teardown has settled.\nconst stopActivation = (owner: Promise<NativeUIShellHandle>, destruction: Promise<void>) => {\n if (active !== owner) return;\n active = undefined;\n activeConfiguration = undefined;\n stopping = destruction;\n const release = () => {\n if (stopping === destruction) stopping = undefined;\n };\n void destruction.then(release, release);\n};\nconst web = (reason: string): NativeUIShellHandle => ({\n getStatus: () => ({ state: 'web', projected: 0, updates: 0, reason }),\n suspend: async () => ({ resume: async () => {} }),\n destroy: async () => {},\n});\n\nconst combine = (native: NativeUIShellHandle, fallback: NativeUIShellHandle): NativeUIShellHandle => ({\n getStatus() {\n const nativeStatus = native.getStatus();\n const fallbackStatus = fallback.getStatus();\n return {\n ...nativeStatus,\n state:\n nativeStatus.state === 'stopped' && fallbackStatus.state === 'stopped' ? 'stopped' : nativeStatus.projected > 0 ? 'native' : 'web',\n projected: nativeStatus.projected + fallbackStatus.projected,\n updates: nativeStatus.updates + fallbackStatus.updates,\n };\n },\n async suspend() {\n const [nativeLease, fallbackLease] = await Promise.all([native.suspend(), fallback.suspend()]);\n return { resume: async () => void (await Promise.all([nativeLease.resume(), fallbackLease.resume()])) };\n },\n async destroy() {\n await Promise.all([native.destroy(), fallback.destroy()]);\n },\n});\n\n/** Wraps a runtime handle with the shared enable-lifecycle: reason, suspend hooks and idempotent destroy. */\nconst manage = (\n handle: NativeUIShellHandle,\n lifecycle: {\n reason?: string;\n suspend?: () => (() => void) | undefined | Promise<(() => void) | undefined>;\n /** Registers teardown before it starts so direct destroy and disable share the same queue. */\n stopping?: (destruction: Promise<void>) => void;\n destroy?: () => void | Promise<void>;\n } = {},\n): NativeUIShellHandle => {\n let destruction: Promise<void> | undefined;\n return {\n getStatus: () => (lifecycle.reason ? { ...handle.getStatus(), reason: lifecycle.reason } : handle.getStatus()),\n async suspend() {\n const lease = await handle.suspend();\n const resume = await lifecycle.suspend?.();\n return {\n async resume() {\n await lease.resume();\n resume?.();\n },\n };\n },\n destroy() {\n if (!destruction) {\n destruction = Promise.resolve().then(async () => {\n try {\n await handle.destroy();\n } finally {\n await lifecycle.destroy?.();\n }\n });\n lifecycle.stopping?.(destruction);\n }\n return destruction;\n },\n };\n};\n\n/** Reads the current native WebView geometry and applies it to page transitions. */\nexport const configureNativeTransition = async (): Promise<WebViewMetrics> => {\n const metrics =\n typeof document !== 'undefined' && Capacitor.getPlatform() === 'ios' ? await bounded(plugin.getWebViewMetrics()) : { radius: 0 };\n setConfig({ radius: metrics.radius });\n return metrics;\n};\n\n/** Resolves a logical vertical-bar edge to the physical side for the given direction. */\nconst physicalVerticalBarEdge = (edge: Exclude<VerticalBarEdge, null>, rtl: boolean): 'left' | 'right' =>\n (edge === 'leading') !== rtl ? 'left' : 'right';\n\nconst elementRtl = (element: Element): boolean => element.closest('[dir]')?.getAttribute('dir') === 'rtl';\n\n// Device facts are supplied by the application; the theme only compares placement.\nconst nativePlacements = new WeakMap<HTMLElement, { edge: VerticalBarEdge; rtl?: boolean }>();\nconst horizontalFallbackAttribute = 'data-native-ui-shell-vertical-bars-suspended';\n\n// Keep the requested rail while ordinary Native UI Shell temporarily uses its\n// horizontal layout. Removing the effective class restores normal measurements,\n// toolbar ownership and safe areas throughout the existing rendering pipeline.\nconst observeNativeVerticalBarsLayout = (doc: Document): (() => void) => {\n const reconcile = () => {\n const app = doc.querySelector<HTMLElement>('ion-app');\n if (!app) return;\n const requested = app.classList.contains('ios-theme-vertical-bars') || app.hasAttribute(horizontalFallbackAttribute);\n const suspended = requested && nativePlacements.get(app)?.edge == null;\n if (app.hasAttribute(horizontalFallbackAttribute) !== suspended) app.toggleAttribute(horizontalFallbackAttribute, suspended);\n if (app.classList.contains('ios-theme-vertical-bars') !== (requested && !suspended)) {\n app.classList.toggle('ios-theme-vertical-bars', requested && !suspended);\n }\n };\n const observer = new MutationObserver(reconcile);\n observer.observe(doc.documentElement, { childList: true, subtree: true, attributes: true, attributeFilter: ['class'] });\n doc.defaultView?.addEventListener('nativeUIShellRefresh', reconcile);\n reconcile();\n return () => {\n observer.disconnect();\n doc.defaultView?.removeEventListener('nativeUIShellRefresh', reconcile);\n const app = doc.querySelector<HTMLElement>(`ion-app[${horizontalFallbackAttribute}]`);\n if (app) {\n app.removeAttribute(horizontalFallbackAttribute);\n app.classList.add('ios-theme-vertical-bars');\n }\n };\n};\n\n/**\n * Applies one placement to the CSS layout and both Web/native projections.\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 if (placement && typeof placement === 'object' && placement.nativeEdge !== undefined) {\n nativePlacements.set(app, { edge: placement.nativeEdge, rtl });\n }\n app.removeAttribute(horizontalFallbackAttribute);\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('nativeUIShellRefresh'));\n};\n\n/**\n * Call once after ion-app is mounted. Ionic markup remains the source of truth.\n * Native vertical buttons default to SwiftUI appearance.\n * See VerticalControlAreaOptions for source styling and local overrides.\n */\nexport const enableVerticalControlArea = async (options: VerticalControlAreaOptions = {}): Promise<VerticalControlAreaHandle> => {\n const handle = await enableNativeUIShell({\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 {\n getStatus: () => handle.getStatus(),\n suspend: () => handle.suspend(),\n destroy: () => handle.destroy(),\n setPlacement: setVerticalControlAreaPlacement,\n };\n};\n\n/** Call once at application startup. Ionic markup remains the source of truth. */\nexport const enableNativeUIShell = (options: NativeUIShellOptions = {}): Promise<NativeUIShellHandle> => {\n if (options.enabled === false) {\n const current = active;\n if (current)\n stopActivation(\n current,\n current.then((handle) => handle.destroy()),\n );\n return (stopping ?? Promise.resolve()).then(() => web('Disabled'));\n }\n if (typeof document === 'undefined') return Promise.resolve(web('Requires a document'));\n const controls = options.controls;\n const configuration = JSON.stringify([\n options.verticalBarsOnly === true,\n options.buttonProjection ?? 'system',\n // Local source overrides can use this even when the startup projection is system.\n options.buttonDefaultFill ?? null,\n ...(['tabs', 'toolbar', 'segment', 'fab'] as const).map((component) => !controls || controls[component] === true),\n controls?.popover === true,\n ]);\n if (active && activeConfiguration !== configuration)\n return Promise.reject(\n new Error('Native UI Shell is already running with different controls; destroy it before changing configuration.'),\n );\n if (active) return active;\n activeConfiguration = configuration;\n const previousStop = stopping;\n let start: Promise<NativeUIShellHandle>;\n const stop = (destruction: Promise<void>) => stopActivation(start, destruction);\n return (start = active =\n (async () => {\n // Native controls and DOM ownership are shared. A replacement activation\n // must wait until the old handle has finished clearing both surfaces.\n if (previousStop) await previousStop.catch(() => {});\n const stopModals = observeVerticalBarsModals(document);\n const prehide =\n options.controls === undefined || options.controls.toolbar === true ? prehideVerticalBarsToolbarSources(document) : undefined;\n const fallback = (reason: string) =>\n manage(createVerticalBarsWebProjection(document, options), {\n reason,\n suspend: () => prehide?.suspend(),\n destroy: () => {\n prehide?.stop();\n stopModals();\n },\n stopping: stop,\n });\n if (Capacitor.getPlatform() !== 'ios') return fallback('Requires Capacitor iOS');\n let runtime: NativeUIShellHandle | undefined;\n let overlays: Awaited<ReturnType<typeof createOverlayController>> | undefined;\n let metricsListener: Awaited<ReturnType<typeof plugin.addListener>> | undefined;\n let stopVerticalBarsLayout: (() => void) | undefined;\n try {\n const capabilities = await bounded(plugin.configure({ verticalBarsOnly: options.verticalBarsOnly === true }));\n if (!capabilities.supported) return fallback('Requires iOS 26 or later');\n if (!options.verticalBarsOnly) stopVerticalBarsLayout = observeNativeVerticalBarsLayout(document);\n // The application owns device state and selects the rail through placement classes.\n const nativeVerticalBars = () => {\n const app = document.querySelector<HTMLElement>('ion-app.ios-theme-vertical-bars');\n if (!app) return false;\n const reported = nativePlacements.get(app);\n if (!reported?.edge) return false;\n const physicalEdge = app.classList.contains('ios-theme-vertical-bars-left') ? 'left' : 'right';\n return physicalEdge === physicalVerticalBarEdge(reported.edge, reported.rtl ?? elementRtl(app));\n };\n if (!options.verticalBarsOnly) {\n metricsListener = await boundedListener(\n plugin.addListener('webViewMetricsChange', (metrics) => {\n setConfig({ radius: metrics.radius });\n }),\n );\n await configureNativeTransition().catch(() => undefined);\n }\n const native = await createRuntime(document, plugin, options, nativeVerticalBars, options.verticalBarsOnly === true);\n runtime = combine(\n native,\n createVerticalBarsWebProjection(document, options, () => !nativeVerticalBars() || native.getStatus().projected === 0),\n );\n if (controls?.popover === true)\n overlays = await createOverlayController(document, plugin, options, native.retain, nativeVerticalBars);\n return manage(runtime, {\n suspend: async () => {\n const restorePrehide = prehide?.suspend();\n const resumeOverlays = await overlays?.suspend();\n return () => {\n restorePrehide?.();\n resumeOverlays?.();\n };\n },\n stopping: stop,\n destroy: async () => {\n try {\n await overlays?.destroy();\n } finally {\n if (metricsListener) await bounded(metricsListener.remove()).catch(() => {});\n stopVerticalBarsLayout?.();\n prehide?.stop();\n stopModals();\n }\n },\n });\n } catch (error) {\n await overlays?.destroy().catch(() => {});\n await runtime?.destroy().catch(() => {});\n if (metricsListener) await bounded(metricsListener.remove()).catch(() => {});\n stopVerticalBarsLayout?.();\n return fallback(error instanceof Error ? error.message : String(error));\n }\n })());\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.d.ts","names":[],"sources":["../../../src/native/overlays/controller.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"controller.d.ts","names":[],"sources":["../../../src/native/overlays/controller.ts"],"mappings":";;qBAoCa,0BACX,KAAK,UACL,QAAQ,qBACR,SAAS,sBACT,mBAAmB,mBAAmB,uCACtC,sCAAiC"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { bounded, boundedListener } from "../shared/bridge.js";
|
|
1
2
|
import { isExcluded, isPermanentlyExcluded, isShellDisabled } from "../shared/dom.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { relayStyles } from "./styles.js";
|
|
3
|
+
import { relayLayoutSupported, relayStyles } from "./styles.js";
|
|
4
|
+
import { moveContent } from "./content.js";
|
|
5
5
|
import { popoverPresentation, relayPopover, verticalBarsPopoverAnchor } from "./popover.js";
|
|
6
|
+
import { validVerticalBarFrame } from "../shared/vertical-bars-geometry.js";
|
|
7
|
+
import { activeElement, trapFocus } from "./focus.js";
|
|
6
8
|
import { nativeDialogAnimation } from "./dialog-animation.js";
|
|
7
9
|
//#region src/native/overlays/controller.ts
|
|
8
10
|
const lifecycle = (overlay, phase) => `ion${overlay.localName.slice(4, 5).toUpperCase()}${overlay.localName.slice(5)}${phase}`;
|
|
@@ -78,7 +80,9 @@ const createOverlayController = async (doc, plugin, options, retainProjection, n
|
|
|
78
80
|
win.document.write("<!doctype html><html><head></head><body></body></html>");
|
|
79
81
|
win.document.close();
|
|
80
82
|
connection.stopChildEvents = observe(win.document);
|
|
81
|
-
const environment = relayStyles(doc, win.document, overlay)
|
|
83
|
+
const environment = relayStyles(doc, win.document, overlay, () => {
|
|
84
|
+
if (connection.stopContent) release(connection).catch(console.error);
|
|
85
|
+
});
|
|
82
86
|
connection.stopStyles = environment.stop;
|
|
83
87
|
await bounded(environment.ready);
|
|
84
88
|
if (gone()) return void 0;
|
|
@@ -99,6 +103,10 @@ const createOverlayController = async (doc, plugin, options, retainProjection, n
|
|
|
99
103
|
const nativePresentation = popoverPresentation(overlay);
|
|
100
104
|
const content = relayPopover(overlay, staged.destination);
|
|
101
105
|
connection.stopContent = content.stop;
|
|
106
|
+
if (!relayLayoutSupported(overlay) || !content.matchesSourceAppearance()) {
|
|
107
|
+
await release(connection);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
102
110
|
connection.hideAnimation?.();
|
|
103
111
|
const exclusions = new MutationObserver(() => {
|
|
104
112
|
if (!overlay.isConnected || !nativeVerticalBars() || excluded(overlay) || isShellDisabled(content.root)) release(connection).catch(console.error);
|
|
@@ -151,13 +159,16 @@ const createOverlayController = async (doc, plugin, options, retainProjection, n
|
|
|
151
159
|
const overlay = event.target;
|
|
152
160
|
if (current) {
|
|
153
161
|
const connection = current;
|
|
162
|
+
const fromChild = overlay.ownerDocument === connection.win?.document;
|
|
163
|
+
if (fromChild) moveContent([overlay], doc.querySelector("ion-app") ?? doc.body);
|
|
154
164
|
current = void 0;
|
|
155
165
|
opening = opening.then(() => release(connection)).catch(console.error);
|
|
166
|
+
if (fromChild) doc.dispatchEvent(new CustomEvent("nativeUIShellOverlayAdopted", { detail: overlay }));
|
|
156
167
|
if (!connection.dismissed) return;
|
|
157
168
|
connection.stopAnimation?.();
|
|
158
169
|
connection.stopAnimation = void 0;
|
|
159
170
|
}
|
|
160
|
-
const enabled = overlay.localName === "ion-popover" && options.controls?.popover === true && nativeVerticalBars() && verticalBarsPopoverAnchor(overlay) !== void 0;
|
|
171
|
+
const enabled = overlay.localName === "ion-popover" && overlay.mode !== "md" && !overlay.classList.contains("md") && options.controls?.popover === true && nativeVerticalBars() && verticalBarsPopoverAnchor(overlay) !== void 0;
|
|
161
172
|
if (stopped || suspensions.size || !enabled || excluded(overlay)) {
|
|
162
173
|
opening = opening.then(restoreWeb).catch(console.error);
|
|
163
174
|
return;
|
|
@@ -190,7 +201,15 @@ const createOverlayController = async (doc, plugin, options, retainProjection, n
|
|
|
190
201
|
id: connection.id,
|
|
191
202
|
animated: presentation.animated
|
|
192
203
|
})));
|
|
193
|
-
const
|
|
204
|
+
const viewport = `${win.innerWidth}:${win.innerHeight}`;
|
|
205
|
+
const anchor = bounded(plugin.getVerticalBarsGeometry({
|
|
206
|
+
viewportWidth: win.innerWidth,
|
|
207
|
+
ids: [anchorId]
|
|
208
|
+
})).then(({ items }) => {
|
|
209
|
+
const frame = items[anchorId];
|
|
210
|
+
return frame && validVerticalBarFrame(frame) && viewport === `${win.innerWidth}:${win.innerHeight}` ? frame : void 0;
|
|
211
|
+
}).catch(() => void 0);
|
|
212
|
+
const animation = nativeDialogAnimation(overlay, closeNative, anchor);
|
|
194
213
|
connection.stopAnimation = animation.stop;
|
|
195
214
|
connection.hideAnimation = animation.hide;
|
|
196
215
|
animation.hide();
|
|
@@ -220,16 +239,16 @@ const createOverlayController = async (doc, plugin, options, retainProjection, n
|
|
|
220
239
|
if (connection) opening = opening.then(() => release(connection)).catch(console.error);
|
|
221
240
|
};
|
|
222
241
|
const win = doc.defaultView;
|
|
223
|
-
win.addEventListener("resize", invalidate);
|
|
224
|
-
doc.addEventListener("ionViewWillLeave", invalidate);
|
|
225
242
|
const visibility = () => {
|
|
226
243
|
if (doc.hidden) invalidate();
|
|
227
244
|
};
|
|
228
|
-
|
|
229
|
-
const listener = await bounded(plugin.addListener("overlay", (event) => {
|
|
245
|
+
const listener = await boundedListener(plugin.addListener("overlay", (event) => {
|
|
230
246
|
if (event.id !== current?.id) return;
|
|
231
247
|
if (event.action === "dismiss" && current.overlay.backdropDismiss) current.overlay.dismiss(void 0, "backdrop").catch(console.error);
|
|
232
248
|
}));
|
|
249
|
+
win.addEventListener("resize", invalidate);
|
|
250
|
+
doc.addEventListener("ionViewWillLeave", invalidate);
|
|
251
|
+
doc.addEventListener("visibilitychange", visibility);
|
|
233
252
|
const stopEvents = observe(doc);
|
|
234
253
|
return {
|
|
235
254
|
async suspend() {
|
|
@@ -254,7 +273,7 @@ const createOverlayController = async (doc, plugin, options, retainProjection, n
|
|
|
254
273
|
try {
|
|
255
274
|
await bounded(plugin.stopOverlays());
|
|
256
275
|
} finally {
|
|
257
|
-
await listener.remove();
|
|
276
|
+
await bounded(listener.remove());
|
|
258
277
|
}
|
|
259
278
|
}
|
|
260
279
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.js","names":[],"sources":["../../../src/native/overlays/controller.ts"],"sourcesContent":["import type { NativeUIShellOptions, NativeUIShellPlugin } from '../definitions';\nimport { bounded } from '../runtime';\nimport { isExcluded, isPermanentlyExcluded, isShellDisabled } from '../shared/dom';\nimport { activeElement, trapFocus } from './focus';\nimport { relayPopover, popoverPresentation, verticalBarsPopoverAnchor } from './popover';\nimport { nativeDialogAnimation } from './dialog-animation';\nimport { relayStyles } from './styles';\n\ntype Presentation = { kind: 'popover'; animated: boolean };\ntype Overlay = HTMLIonPopoverElement;\nconst lifecycle = (overlay: Overlay, phase: string) =>\n `ion${overlay.localName.slice(4, 5).toUpperCase()}${overlay.localName.slice(5)}${phase}`;\n\ninterface Connection {\n id: string;\n overlay: Overlay;\n dismissed: boolean;\n win?: Window;\n focus: Element | null;\n stopStyles?: () => void;\n releaseProjection?: () => void;\n stopContent?: () => void;\n stopFocus?: () => void;\n stopEvents?: () => void;\n stopChildEvents?: () => void;\n stopExclusions?: () => void;\n closing?: Promise<void>;\n nativeClosing?: Promise<void>;\n stopAnimation?: () => void;\n hideAnimation?: () => void;\n stopLifecycle?: () => void;\n}\n\n/** Ionic owns lifecycle and dismissal; only one overlay is relayed at a time. */\nexport const createOverlayController = async (\n doc: Document,\n plugin: NativeUIShellPlugin,\n options: NativeUIShellOptions,\n retainProjection: (deferActivation?: (id: string) => boolean) => () => void,\n nativeVerticalBars: () => boolean,\n) => {\n let current: Connection | undefined;\n let opening = Promise.resolve();\n let sequence = 0;\n let stopped = false;\n const suspensions = new Set<symbol>();\n const events = ['Modal', 'Popover', 'Alert', 'ActionSheet', 'Loading', 'Picker', 'Toast'].map((name) => `ion${name}WillPresent`);\n const cleanup = async (connection: Connection) => {\n // Every teardown step is isolated and bounded: a throwing or hanging step\n // must not strand the retained page projections or the child window.\n const stage = async (label: string, run?: () => void | Promise<void>) => {\n try {\n await bounded(Promise.resolve(run?.()));\n } catch (error) {\n console.error(`Native overlay teardown failed at ${label}; continuing cleanup anyway.`, error);\n }\n };\n try {\n await stage('events', connection.stopEvents);\n await stage('lifecycle', connection.stopLifecycle);\n await stage('childEvents', connection.stopChildEvents);\n await stage('exclusions', connection.stopExclusions);\n await stage('focus', connection.stopFocus);\n // A timed-out dismissal must not strand the relayed content in the child window.\n await connection.nativeClosing?.catch((error) => {\n console.error('Native overlay dismissal did not complete; restoring the Web content anyway.', error);\n });\n await stage('content', connection.stopContent);\n await stage('animation', connection.stopAnimation);\n await stage('styles', connection.stopStyles);\n await stage('close', () => bounded(plugin.closeOverlay({ id: connection.id })));\n } finally {\n // The page projections must be released even if teardown throws above.\n connection.releaseProjection?.();\n connection.releaseProjection = undefined;\n try {\n connection.win?.close();\n } catch (error) {\n console.error('Native overlay window was already gone.', error);\n }\n if (current === connection) current = undefined;\n const focus = connection.focus as HTMLElement | null;\n if (focus?.isConnected && focus.tabIndex >= 0) focus.focus({ preventScroll: true });\n }\n };\n const release = (connection: Connection): Promise<void> => (connection.closing ??= cleanup(connection));\n const restoreWeb = async () => {\n if (current) await release(current);\n };\n const excluded = (overlay: HTMLElement) => isPermanentlyExcluded(overlay) || isExcluded(overlay) || isShellDisabled(overlay);\n const connect = async (connection: Connection, ready: Promise<void>, presentation: Presentation) => {\n const { overlay } = connection;\n const gone = () =>\n current !== connection ||\n stopped ||\n suspensions.size ||\n connection.dismissed ||\n !overlay.isConnected ||\n !nativeVerticalBars() ||\n excluded(overlay);\n // Keep the source invisible while the native toolbar prepares its popover.\n connection.hideAnimation?.();\n try {\n // Prepare the child window concurrently with Ionic's content initialization.\n const staging = (async () => {\n await bounded(\n plugin.prepareOverlay({\n id: connection.id,\n }),\n );\n if (gone()) return undefined;\n const win = doc.defaultView!.open(`about:blank#${connection.id}`, '_blank');\n if (!win) throw new Error('Native overlay window unavailable');\n connection.win = win;\n // The requested blank page replaces the initial document created by window.open.\n // WebKit percent-encodes the '#' marker in the popup URL; compare decoded.\n // Adopt nodes only after that navigation; otherwise WebKit discards the relay.\n if (decodeURIComponent(win.document.URL) !== `about:blank#${connection.id}` || win.document.readyState !== 'complete')\n await bounded(new Promise<void>((resolve) => win.addEventListener('load', () => resolve(), { once: true })));\n if (gone()) return undefined;\n // about:blank is a quirks-mode document in WebKit. Initialize standards\n // mode before adopting live content: otherwise percentage button heights\n // can resolve against the entire popover viewport.\n win.document.open();\n win.document.write('<!doctype html><html><head></head><body></body></html>');\n win.document.close();\n connection.stopChildEvents = observe(win.document);\n const environment = relayStyles(doc, win.document, overlay);\n connection.stopStyles = environment.stop;\n await bounded(environment.ready);\n if (gone()) return undefined;\n return { destination: environment.destination, win };\n })();\n // The staging join is awaited below; settle early rejections quietly.\n staging.catch(() => {});\n // Ionic initializes its gestures after didPresent. Let that turn finish before adopting their content.\n // A stalled presentation must not park the opening queue forever.\n await bounded(ready);\n // Placement is captured after Ionic has laid out the overlay.\n await bounded(new Promise<void>((resolve) => doc.defaultView!.requestAnimationFrame(() => resolve())));\n const staged = await staging;\n if (gone() || !staged) {\n await release(connection);\n return;\n }\n const focused = activeElement(doc) as HTMLElement | null;\n const nativePresentation = popoverPresentation(overlay);\n const content = relayPopover(overlay, staged.destination);\n connection.stopContent = content.stop;\n connection.hideAnimation?.();\n // Ionic does not dismiss a presented overlay when its page is hidden or\n // destroyed; without this a popover could retain the page projections\n // forever and freeze every later control update.\n const exclusions = new MutationObserver(() => {\n if (!overlay.isConnected || !nativeVerticalBars() || excluded(overlay) || isShellDisabled(content.root))\n void release(connection).catch(console.error);\n });\n const attributes = { attributes: true, attributeFilter: ['class', 'data-shell', 'hidden', 'inert'] };\n for (let node: HTMLElement | null = overlay; node; node = node.parentElement) {\n exclusions.observe(node, attributes);\n exclusions.observe(node, { childList: true });\n }\n exclusions.observe(content.root, { ...attributes, subtree: true });\n connection.stopExclusions = () => exclusions.disconnect();\n connection.stopFocus = trapFocus(\n content.root,\n () =>\n !connection.dismissed &&\n (!('focusTrap' in overlay) || overlay.focusTrap !== false) &&\n !overlay.classList.contains('ion-disable-focus-trap'),\n );\n const close = () => {\n void release(connection).catch(console.error);\n };\n const escape = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && overlay.backdropDismiss) void overlay.dismiss(undefined, 'backdrop');\n };\n staged.win.document.addEventListener('keydown', escape);\n overlay.addEventListener(lifecycle(overlay, 'DidDismiss'), close, { once: true });\n connection.stopEvents = () => {\n staged.win.document.removeEventListener('keydown', escape);\n overlay.removeEventListener(lifecycle(overlay, 'DidDismiss'), close);\n };\n // SwiftUI owns the only visible presentation animation.\n await bounded(\n plugin.presentOverlay({\n id: connection.id,\n presentation: { ...nativePresentation, animated: presentation.animated },\n }),\n );\n (focused?.isConnected && focused.ownerDocument === staged.win.document ? focused : content.root).focus({ preventScroll: true });\n } catch (error) {\n await release(connection);\n console.error('Native overlay projection failed; keeping Ionic content in the source WebView.', error);\n }\n };\n const present = (event: Event) => {\n const overlay = event.target as Overlay;\n if (current) {\n const connection = current;\n current = undefined;\n opening = opening.then(() => release(connection)).catch(console.error);\n if (!connection.dismissed) return;\n // A didDismiss handler may immediately open the next popover while SwiftUI is still closing this one.\n connection.stopAnimation?.();\n connection.stopAnimation = undefined;\n }\n const enabled =\n overlay.localName === 'ion-popover' &&\n options.controls?.popover === true &&\n nativeVerticalBars() &&\n verticalBarsPopoverAnchor(overlay) !== undefined;\n if (stopped || suspensions.size || !enabled || excluded(overlay)) {\n opening = opening.then(restoreWeb).catch(console.error);\n return;\n }\n const connection: Connection = { id: `ios-theme-overlay-${++sequence}`, overlay, dismissed: false, focus: activeElement(doc) };\n const presentation: Presentation = { kind: 'popover', animated: overlay.animated };\n current = connection;\n // Retain synchronously, before the scheduled projection update can retire the rail.\n const anchorId = verticalBarsPopoverAnchor(overlay);\n connection.releaseProjection = retainProjection(\n (id) =>\n id === anchorId &&\n current === connection &&\n !!connection.nativeClosing &&\n !stopped &&\n !suspensions.size &&\n nativeVerticalBars() &&\n !excluded(overlay),\n );\n const closed = () => {\n connection.dismissed = true;\n };\n overlay.addEventListener(lifecycle(overlay, 'DidDismiss'), closed, { once: true });\n let resolveReady!: () => void;\n const readyPromise = new Promise<void>((resolve) => {\n resolveReady = resolve;\n });\n const ready = () => {\n resolveReady();\n };\n const closeNative = () =>\n (connection.nativeClosing ??= bounded(plugin.dismissOverlay({ id: connection.id, animated: presentation.animated })));\n const animation = nativeDialogAnimation(overlay, closeNative);\n connection.stopAnimation = animation.stop;\n connection.hideAnimation = animation.hide;\n animation.hide();\n overlay.addEventListener(lifecycle(overlay, 'DidPresent'), ready, { once: true });\n connection.stopLifecycle = () => overlay.removeEventListener(lifecycle(overlay, 'DidDismiss'), closed);\n opening = opening\n .then(() => connect(connection, readyPromise, presentation))\n .catch(console.error)\n .finally(() => {\n overlay.removeEventListener(lifecycle(overlay, 'DidPresent'), ready);\n });\n };\n const menuOpen = (event: Event) => {\n if (!event.composedPath().some((node): node is HTMLElement => node instanceof HTMLElement && node.matches('ion-menu'))) return;\n // Menus render in the source document below the native overlay; release the relay.\n const connection = current;\n current = undefined;\n if (connection) opening = opening.then(() => release(connection)).catch(console.error);\n };\n const observe = (target: Document) => {\n for (const name of events) target.addEventListener(name, present);\n target.addEventListener('ionWillOpen', menuOpen);\n return () => {\n for (const name of events) target.removeEventListener(name, present);\n target.removeEventListener('ionWillOpen', menuOpen);\n };\n };\n const invalidate = () => {\n const connection = current;\n current = undefined;\n if (connection) opening = opening.then(() => release(connection)).catch(console.error);\n };\n // Retention must not freeze an obsolete layout or a departed page.\n const win = doc.defaultView!;\n win.addEventListener('resize', invalidate);\n doc.addEventListener('ionViewWillLeave', invalidate);\n const visibility = () => {\n if (doc.hidden) invalidate();\n };\n doc.addEventListener('visibilitychange', visibility);\n const listener = await bounded(\n plugin.addListener('overlay', (event) => {\n if (event.id !== current?.id) return;\n if (event.action === 'dismiss' && current.overlay.backdropDismiss)\n void current.overlay.dismiss(undefined, 'backdrop').catch(console.error);\n }),\n );\n const stopEvents = observe(doc);\n return {\n async suspend() {\n const lease = Symbol();\n suspensions.add(lease);\n await opening;\n await restoreWeb();\n return () => {\n suspensions.delete(lease);\n };\n },\n async destroy() {\n stopped = true;\n stopEvents();\n win.removeEventListener('resize', invalidate);\n doc.removeEventListener('ionViewWillLeave', invalidate);\n doc.removeEventListener('visibilitychange', visibility);\n try {\n await opening;\n await restoreWeb();\n } finally {\n try {\n await bounded(plugin.stopOverlays());\n } finally {\n await listener.remove();\n }\n }\n },\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"controller.js","names":[],"sources":["../../../src/native/overlays/controller.ts"],"sourcesContent":["import type { NativeUIShellOptions, NativeUIShellPlugin } from '../definitions';\nimport { bounded, boundedListener } from '../shared/bridge';\nimport { isExcluded, isPermanentlyExcluded, isShellDisabled } from '../shared/dom';\nimport { activeElement, trapFocus } from './focus';\nimport { relayPopover, popoverPresentation, verticalBarsPopoverAnchor } from './popover';\nimport { nativeDialogAnimation } from './dialog-animation';\nimport { relayLayoutSupported, relayStyles } from './styles';\nimport { moveContent } from './content';\nimport { validVerticalBarFrame } from '../shared/vertical-bars-geometry';\n\ntype Presentation = { kind: 'popover'; animated: boolean };\ntype Overlay = HTMLIonPopoverElement;\nconst lifecycle = (overlay: Overlay, phase: string) =>\n `ion${overlay.localName.slice(4, 5).toUpperCase()}${overlay.localName.slice(5)}${phase}`;\n\ninterface Connection {\n id: string;\n overlay: Overlay;\n dismissed: boolean;\n win?: Window;\n focus: Element | null;\n stopStyles?: () => void;\n releaseProjection?: () => void;\n stopContent?: () => void;\n stopFocus?: () => void;\n stopEvents?: () => void;\n stopChildEvents?: () => void;\n stopExclusions?: () => void;\n closing?: Promise<void>;\n nativeClosing?: Promise<void>;\n stopAnimation?: () => void;\n hideAnimation?: () => void;\n stopLifecycle?: () => void;\n}\n\n/** Ionic owns lifecycle and dismissal; only one overlay is relayed at a time. */\nexport const createOverlayController = async (\n doc: Document,\n plugin: NativeUIShellPlugin,\n options: NativeUIShellOptions,\n retainProjection: (deferActivation?: (id: string) => boolean) => () => void,\n nativeVerticalBars: () => boolean,\n) => {\n let current: Connection | undefined;\n let opening = Promise.resolve();\n let sequence = 0;\n let stopped = false;\n const suspensions = new Set<symbol>();\n const events = ['Modal', 'Popover', 'Alert', 'ActionSheet', 'Loading', 'Picker', 'Toast'].map((name) => `ion${name}WillPresent`);\n const cleanup = async (connection: Connection) => {\n // Every teardown step is isolated and bounded: a throwing or hanging step\n // must not strand the retained page projections or the child window.\n const stage = async (label: string, run?: () => void | Promise<void>) => {\n try {\n await bounded(Promise.resolve(run?.()));\n } catch (error) {\n console.error(`Native overlay teardown failed at ${label}; continuing cleanup anyway.`, error);\n }\n };\n try {\n await stage('events', connection.stopEvents);\n await stage('lifecycle', connection.stopLifecycle);\n await stage('childEvents', connection.stopChildEvents);\n await stage('exclusions', connection.stopExclusions);\n await stage('focus', connection.stopFocus);\n // A timed-out dismissal must not strand the relayed content in the child window.\n await connection.nativeClosing?.catch((error) => {\n console.error('Native overlay dismissal did not complete; restoring the Web content anyway.', error);\n });\n await stage('content', connection.stopContent);\n await stage('animation', connection.stopAnimation);\n await stage('styles', connection.stopStyles);\n await stage('close', () => bounded(plugin.closeOverlay({ id: connection.id })));\n } finally {\n // The page projections must be released even if teardown throws above.\n connection.releaseProjection?.();\n connection.releaseProjection = undefined;\n try {\n connection.win?.close();\n } catch (error) {\n console.error('Native overlay window was already gone.', error);\n }\n if (current === connection) current = undefined;\n const focus = connection.focus as HTMLElement | null;\n if (focus?.isConnected && focus.tabIndex >= 0) focus.focus({ preventScroll: true });\n }\n };\n const release = (connection: Connection): Promise<void> => (connection.closing ??= cleanup(connection));\n const restoreWeb = async () => {\n if (current) await release(current);\n };\n const excluded = (overlay: HTMLElement) => isPermanentlyExcluded(overlay) || isExcluded(overlay) || isShellDisabled(overlay);\n const connect = async (connection: Connection, ready: Promise<void>, presentation: Presentation) => {\n const { overlay } = connection;\n const gone = () =>\n current !== connection ||\n stopped ||\n suspensions.size ||\n connection.dismissed ||\n !overlay.isConnected ||\n !nativeVerticalBars() ||\n excluded(overlay);\n // Keep the source invisible while the native toolbar prepares its popover.\n connection.hideAnimation?.();\n try {\n // Prepare the child window concurrently with Ionic's content initialization.\n const staging = (async () => {\n await bounded(\n plugin.prepareOverlay({\n id: connection.id,\n }),\n );\n if (gone()) return undefined;\n const win = doc.defaultView!.open(`about:blank#${connection.id}`, '_blank');\n if (!win) throw new Error('Native overlay window unavailable');\n connection.win = win;\n // The requested blank page replaces the initial document created by window.open.\n // WebKit percent-encodes the '#' marker in the popup URL; compare decoded.\n // Adopt nodes only after that navigation; otherwise WebKit discards the relay.\n if (decodeURIComponent(win.document.URL) !== `about:blank#${connection.id}` || win.document.readyState !== 'complete')\n await bounded(new Promise<void>((resolve) => win.addEventListener('load', () => resolve(), { once: true })));\n if (gone()) return undefined;\n // about:blank is a quirks-mode document in WebKit. Initialize standards\n // mode before adopting live content: otherwise percentage button heights\n // can resolve against the entire popover viewport.\n win.document.open();\n win.document.write('<!doctype html><html><head></head><body></body></html>');\n win.document.close();\n connection.stopChildEvents = observe(win.document);\n const environment = relayStyles(doc, win.document, overlay, () => {\n if (connection.stopContent) void release(connection).catch(console.error);\n });\n connection.stopStyles = environment.stop;\n await bounded(environment.ready);\n if (gone()) return undefined;\n return { destination: environment.destination, win };\n })();\n // The staging join is awaited below; settle early rejections quietly.\n staging.catch(() => {});\n // Ionic initializes its gestures after didPresent. Let that turn finish before adopting their content.\n // A stalled presentation must not park the opening queue forever.\n await bounded(ready);\n // Placement is captured after Ionic has laid out the overlay.\n await bounded(new Promise<void>((resolve) => doc.defaultView!.requestAnimationFrame(() => resolve())));\n const staged = await staging;\n if (gone() || !staged) {\n await release(connection);\n return;\n }\n const focused = activeElement(doc) as HTMLElement | null;\n const nativePresentation = popoverPresentation(overlay);\n const content = relayPopover(overlay, staged.destination);\n connection.stopContent = content.stop;\n if (!relayLayoutSupported(overlay) || !content.matchesSourceAppearance()) {\n await release(connection);\n return;\n }\n connection.hideAnimation?.();\n // Ionic does not dismiss a presented overlay when its page is hidden or\n // destroyed; without this a popover could retain the page projections\n // forever and freeze every later control update.\n const exclusions = new MutationObserver(() => {\n if (!overlay.isConnected || !nativeVerticalBars() || excluded(overlay) || isShellDisabled(content.root))\n void release(connection).catch(console.error);\n });\n const attributes = { attributes: true, attributeFilter: ['class', 'data-shell', 'hidden', 'inert'] };\n for (let node: HTMLElement | null = overlay; node; node = node.parentElement) {\n exclusions.observe(node, attributes);\n exclusions.observe(node, { childList: true });\n }\n exclusions.observe(content.root, { ...attributes, subtree: true });\n connection.stopExclusions = () => exclusions.disconnect();\n connection.stopFocus = trapFocus(\n content.root,\n () =>\n !connection.dismissed &&\n (!('focusTrap' in overlay) || overlay.focusTrap !== false) &&\n !overlay.classList.contains('ion-disable-focus-trap'),\n );\n const close = () => {\n void release(connection).catch(console.error);\n };\n const escape = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && overlay.backdropDismiss) void overlay.dismiss(undefined, 'backdrop');\n };\n staged.win.document.addEventListener('keydown', escape);\n overlay.addEventListener(lifecycle(overlay, 'DidDismiss'), close, { once: true });\n connection.stopEvents = () => {\n staged.win.document.removeEventListener('keydown', escape);\n overlay.removeEventListener(lifecycle(overlay, 'DidDismiss'), close);\n };\n // SwiftUI owns the only visible presentation animation.\n await bounded(\n plugin.presentOverlay({\n id: connection.id,\n presentation: { ...nativePresentation, animated: presentation.animated },\n }),\n );\n (focused?.isConnected && focused.ownerDocument === staged.win.document ? focused : content.root).focus({ preventScroll: true });\n } catch (error) {\n await release(connection);\n console.error('Native overlay projection failed; keeping Ionic content in the source WebView.', error);\n }\n };\n const present = (event: Event) => {\n const overlay = event.target as Overlay;\n if (current) {\n const connection = current;\n const fromChild = overlay.ownerDocument === connection.win?.document;\n if (fromChild) {\n // A child-document overlay may be a sibling of the relayed content.\n // Move it before cleanup closes that document; keep the live node,\n // component handlers and adopted shadow styles in the source WebView.\n moveContent([overlay], doc.querySelector<HTMLElement>('ion-app') ?? doc.body);\n }\n current = undefined;\n opening = opening.then(() => release(connection)).catch(console.error);\n // The original event path still belongs to the child document. Let the\n // source runtime observe presentation before releasing retained controls.\n if (fromChild) doc.dispatchEvent(new CustomEvent('nativeUIShellOverlayAdopted', { detail: overlay }));\n if (!connection.dismissed) return;\n // A didDismiss handler may immediately open the next popover while SwiftUI is still closing this one.\n connection.stopAnimation?.();\n connection.stopAnimation = undefined;\n }\n const enabled =\n overlay.localName === 'ion-popover' &&\n overlay.mode !== 'md' &&\n !overlay.classList.contains('md') &&\n options.controls?.popover === true &&\n nativeVerticalBars() &&\n verticalBarsPopoverAnchor(overlay) !== undefined;\n if (stopped || suspensions.size || !enabled || excluded(overlay)) {\n opening = opening.then(restoreWeb).catch(console.error);\n return;\n }\n const connection: Connection = { id: `ios-theme-overlay-${++sequence}`, overlay, dismissed: false, focus: activeElement(doc) };\n const presentation: Presentation = { kind: 'popover', animated: overlay.animated };\n current = connection;\n // Retain synchronously, before the scheduled projection update can retire the rail.\n const anchorId = verticalBarsPopoverAnchor(overlay);\n connection.releaseProjection = retainProjection(\n (id) =>\n id === anchorId &&\n current === connection &&\n !!connection.nativeClosing &&\n !stopped &&\n !suspensions.size &&\n nativeVerticalBars() &&\n !excluded(overlay),\n );\n const closed = () => {\n connection.dismissed = true;\n };\n overlay.addEventListener(lifecycle(overlay, 'DidDismiss'), closed, { once: true });\n let resolveReady!: () => void;\n const readyPromise = new Promise<void>((resolve) => {\n resolveReady = resolve;\n });\n const ready = () => {\n resolveReady();\n };\n const closeNative = () =>\n (connection.nativeClosing ??= bounded(plugin.dismissOverlay({ id: connection.id, animated: presentation.animated })));\n const viewport = `${win.innerWidth}:${win.innerHeight}`;\n const anchor = bounded(plugin.getVerticalBarsGeometry({ viewportWidth: win.innerWidth, ids: [anchorId!] }))\n .then(({ items }) => {\n const frame = items[anchorId!];\n return frame && validVerticalBarFrame(frame) && viewport === `${win.innerWidth}:${win.innerHeight}` ? frame : undefined;\n })\n .catch(() => undefined);\n const animation = nativeDialogAnimation(overlay, closeNative, anchor);\n connection.stopAnimation = animation.stop;\n connection.hideAnimation = animation.hide;\n animation.hide();\n overlay.addEventListener(lifecycle(overlay, 'DidPresent'), ready, { once: true });\n connection.stopLifecycle = () => overlay.removeEventListener(lifecycle(overlay, 'DidDismiss'), closed);\n opening = opening\n .then(() => connect(connection, readyPromise, presentation))\n .catch(console.error)\n .finally(() => {\n overlay.removeEventListener(lifecycle(overlay, 'DidPresent'), ready);\n });\n };\n const menuOpen = (event: Event) => {\n if (!event.composedPath().some((node): node is HTMLElement => node instanceof HTMLElement && node.matches('ion-menu'))) return;\n // Menus render in the source document below the native overlay; release the relay.\n const connection = current;\n current = undefined;\n if (connection) opening = opening.then(() => release(connection)).catch(console.error);\n };\n const observe = (target: Document) => {\n for (const name of events) target.addEventListener(name, present);\n target.addEventListener('ionWillOpen', menuOpen);\n return () => {\n for (const name of events) target.removeEventListener(name, present);\n target.removeEventListener('ionWillOpen', menuOpen);\n };\n };\n const invalidate = () => {\n const connection = current;\n current = undefined;\n if (connection) opening = opening.then(() => release(connection)).catch(console.error);\n };\n // Retention must not freeze an obsolete layout or a departed page.\n const win = doc.defaultView!;\n const visibility = () => {\n if (doc.hidden) invalidate();\n };\n const listener = await boundedListener(\n plugin.addListener('overlay', (event) => {\n if (event.id !== current?.id) return;\n if (event.action === 'dismiss' && current.overlay.backdropDismiss)\n void current.overlay.dismiss(undefined, 'backdrop').catch(console.error);\n }),\n );\n win.addEventListener('resize', invalidate);\n doc.addEventListener('ionViewWillLeave', invalidate);\n doc.addEventListener('visibilitychange', visibility);\n const stopEvents = observe(doc);\n return {\n async suspend() {\n const lease = Symbol();\n suspensions.add(lease);\n await opening;\n await restoreWeb();\n return () => {\n suspensions.delete(lease);\n };\n },\n async destroy() {\n stopped = true;\n stopEvents();\n win.removeEventListener('resize', invalidate);\n doc.removeEventListener('ionViewWillLeave', invalidate);\n doc.removeEventListener('visibilitychange', visibility);\n try {\n await opening;\n await restoreWeb();\n } finally {\n try {\n await bounded(plugin.stopOverlays());\n } finally {\n await bounded(listener.remove());\n }\n }\n },\n };\n};\n"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { Frame } from "../definitions.js";
|
|
1
2
|
//#region src/native/overlays/dialog-animation.d.ts
|
|
2
3
|
export type Dialog = HTMLIonPopoverElement;
|
|
3
|
-
export declare const nativeDialogAnimation: (overlay: Dialog, close: () => Promise<void>) => {
|
|
4
|
+
export declare const nativeDialogAnimation: (overlay: Dialog, close: () => Promise<void>, anchor: Promise<Frame | undefined>) => {
|
|
4
5
|
hide(): void;
|
|
5
6
|
stop(): void;
|
|
6
7
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog-animation.d.ts","names":[],"sources":["../../../src/native/overlays/dialog-animation.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"dialog-animation.d.ts","names":[],"sources":["../../../src/native/overlays/dialog-animation.ts"],"mappings":";;YAMY,SAAS;qBAGR,wBAAyB,SAAS,QAAQ,aAAa,eAAe,QAAQ,QAAQ"}
|
|
@@ -1,10 +1,32 @@
|
|
|
1
1
|
import { dismissAnimation } from "./dismiss-animation.js";
|
|
2
2
|
import { createAnimation } from "@ionic/core/components/index.js";
|
|
3
|
+
import { iosPopoverEnterAnimation } from "@rdlabo/ionic-theme-utils";
|
|
3
4
|
//#region src/native/overlays/dialog-animation.ts
|
|
4
|
-
/**
|
|
5
|
-
const nativeDialogAnimation = (overlay, close) => {
|
|
5
|
+
/** Prepare the source's final layout while SwiftUI owns visible motion. */
|
|
6
|
+
const nativeDialogAnimation = (overlay, close, anchor) => {
|
|
6
7
|
const enterAnimation = overlay.enterAnimation;
|
|
7
|
-
|
|
8
|
+
const builder = enterAnimation ?? iosPopoverEnterAnimation;
|
|
9
|
+
overlay.enterAnimation = (base, options) => {
|
|
10
|
+
const animation = createAnimation();
|
|
11
|
+
const play = animation.play;
|
|
12
|
+
animation.play = async () => {
|
|
13
|
+
const frame = await anchor;
|
|
14
|
+
const proxy = overlay.ownerDocument.createElement("ion-button");
|
|
15
|
+
if (frame) proxy.getBoundingClientRect = () => new DOMRect(frame.x, frame.y, frame.width, frame.height);
|
|
16
|
+
const positioned = frame ? {
|
|
17
|
+
...options,
|
|
18
|
+
trigger: proxy
|
|
19
|
+
} : options;
|
|
20
|
+
animation.addAnimation(builder(base, positioned));
|
|
21
|
+
const finishWithoutMotion = (item) => {
|
|
22
|
+
item.duration(0).delay(0);
|
|
23
|
+
item.childAnimations.forEach(finishWithoutMotion);
|
|
24
|
+
};
|
|
25
|
+
finishWithoutMotion(animation);
|
|
26
|
+
await play({ sync: true });
|
|
27
|
+
};
|
|
28
|
+
return animation;
|
|
29
|
+
};
|
|
8
30
|
const leaveAnimation = overlay.leaveAnimation;
|
|
9
31
|
const opacity = overlay.style.opacity;
|
|
10
32
|
const event = "ionPopoverWillDismiss";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog-animation.js","names":[],"sources":["../../../src/native/overlays/dialog-animation.ts"],"sourcesContent":["import { createAnimation } from '@ionic/core/components/index.js';\nimport { dismissAnimation } from './dismiss-animation';\n\nexport type Dialog = HTMLIonPopoverElement;\n\n/**
|
|
1
|
+
{"version":3,"file":"dialog-animation.js","names":[],"sources":["../../../src/native/overlays/dialog-animation.ts"],"sourcesContent":["import type { Animation } from '@ionic/core';\nimport { createAnimation } from '@ionic/core/components/index.js';\nimport { iosPopoverEnterAnimation } from '@rdlabo/ionic-theme-utils';\nimport type { Frame } from '../definitions';\nimport { dismissAnimation } from './dismiss-animation';\n\nexport type Dialog = HTMLIonPopoverElement;\n\n/** Prepare the source's final layout while SwiftUI owns visible motion. */\nexport const nativeDialogAnimation = (overlay: Dialog, close: () => Promise<void>, anchor: Promise<Frame | undefined>) => {\n const enterAnimation = overlay.enterAnimation;\n const builder = enterAnimation ?? iosPopoverEnterAnimation;\n overlay.enterAnimation = (base, options) => {\n const animation = createAnimation();\n const play = animation.play;\n animation.play = async () => {\n const frame = await anchor;\n const proxy = overlay.ownerDocument.createElement('ion-button');\n if (frame) proxy.getBoundingClientRect = () => new DOMRect(frame.x, frame.y, frame.width, frame.height);\n // The real trigger is display:none while projected. Use only a detached\n // measurement proxy; never replace or mutate the application's button.\n const positioned = frame ? { ...options, trigger: proxy } : options;\n animation.addAnimation(builder(base, positioned));\n const finishWithoutMotion = (item: Animation) => {\n item.duration(0).delay(0);\n item.childAnimations.forEach(finishWithoutMotion);\n };\n finishWithoutMotion(animation);\n // Ionic owns this wrapper and destroys its children on dismissal.\n await play({ sync: true });\n };\n return animation;\n };\n const leaveAnimation = overlay.leaveAnimation;\n const opacity = overlay.style.opacity;\n const event = 'ionPopoverWillDismiss';\n const dismiss = () => {\n const closing = close();\n overlay.leaveAnimation = () => dismissAnimation(closing);\n };\n overlay.addEventListener(event, dismiss);\n return {\n hide() {\n overlay.style.opacity = '0';\n },\n stop() {\n overlay.removeEventListener(event, dismiss);\n overlay.enterAnimation = enterAnimation;\n overlay.leaveAnimation = leaveAnimation;\n overlay.style.opacity = opacity;\n },\n };\n};\n"],"mappings":";;;;;AASA,MAAa,yBAAyB,SAAiB,OAA4B,WAAuC;CACxH,MAAM,iBAAiB,QAAQ;CAC/B,MAAM,UAAU,kBAAkB;CAClC,QAAQ,kBAAkB,MAAM,YAAY;EAC1C,MAAM,YAAY,gBAAgB;EAClC,MAAM,OAAO,UAAU;EACvB,UAAU,OAAO,YAAY;GAC3B,MAAM,QAAQ,MAAM;GACpB,MAAM,QAAQ,QAAQ,cAAc,cAAc,YAAY;GAC9D,IAAI,OAAO,MAAM,8BAA8B,IAAI,QAAQ,MAAM,GAAG,MAAM,GAAG,MAAM,OAAO,MAAM,MAAM;GAGtG,MAAM,aAAa,QAAQ;IAAE,GAAG;IAAS,SAAS;GAAM,IAAI;GAC5D,UAAU,aAAa,QAAQ,MAAM,UAAU,CAAC;GAChD,MAAM,uBAAuB,SAAoB;IAC/C,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;IACxB,KAAK,gBAAgB,QAAQ,mBAAmB;GAClD;GACA,oBAAoB,SAAS;GAE7B,MAAM,KAAK,EAAE,MAAM,KAAK,CAAC;EAC3B;EACA,OAAO;CACT;CACA,MAAM,iBAAiB,QAAQ;CAC/B,MAAM,UAAU,QAAQ,MAAM;CAC9B,MAAM,QAAQ;CACd,MAAM,gBAAgB;EACpB,MAAM,UAAU,MAAM;EACtB,QAAQ,uBAAuB,iBAAiB,OAAO;CACzD;CACA,QAAQ,iBAAiB,OAAO,OAAO;CACvC,OAAO;EACL,OAAO;GACL,QAAQ,MAAM,UAAU;EAC1B;EACA,OAAO;GACL,QAAQ,oBAAoB,OAAO,OAAO;GAC1C,QAAQ,iBAAiB;GACzB,QAAQ,iBAAiB;GACzB,QAAQ,MAAM,UAAU;EAC1B;CACF;AACF"}
|
|
@@ -5,6 +5,7 @@ export declare const verticalBarsPopoverAnchor: (overlay: HTMLIonPopoverElement)
|
|
|
5
5
|
export declare const popoverPresentation: (overlay: HTMLIonPopoverElement) => ShellPopoverPresentation;
|
|
6
6
|
export declare const relayPopover: (overlay: HTMLIonPopoverElement, destination: HTMLElement) => {
|
|
7
7
|
root: HTMLIonPopoverElement;
|
|
8
|
+
matchesSourceAppearance(): boolean;
|
|
8
9
|
stop(): void;
|
|
9
10
|
};
|
|
10
11
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"popover.d.ts","names":[],"sources":["../../../src/native/overlays/popover.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"popover.d.ts","names":[],"sources":["../../../src/native/overlays/popover.ts"],"mappings":";;qBAMa,iBAAkB,SAAS,0BAAwB;qBAOnD,4BAA6B,SAAS;qBAWtC,sBAAuB,SAAS,0BAAwB;qBAiBxD,eAAgB,SAAS,uBAAuB,aAAa"}
|