@webview-native-ui/engine 1.0.0 → 1.0.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/README.md +34 -35
- package/dist/native/bootstrap.js +1 -1
- package/dist/projection/surfaces.js +9 -7
- package/dist/projection/web.js +9 -8
- package/docs/README.md +16 -10
- package/docs/concepts.md +39 -14
- package/docs/configuration/README.md +1 -1
- package/docs/getting-started/capacitor.md +3 -3
- package/docs/getting-started/cordova.md +3 -1
- package/docs/getting-started/initialization.md +18 -2
- package/docs/reference/platforms.md +2 -2
- package/docs/reference/projection.md +1 -1
- package/ios/Sources/WebViewNativeUIEngine/NativeUIProjection.swift +5 -3
- package/ios/Sources/WebViewNativeUIEngine/ProjectionOrigins.swift +31 -0
- package/ios/Sources/WebViewNativeUIEngine/Resources/native-ui-engine.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,59 +1,58 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Beyond the WebView.
|
|
2
2
|
|
|
3
|
-
**Bring
|
|
3
|
+
**Bring Native UI seamlessly into Web apps.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Build your screens with the flexibility of the Web and the controls and capabilities of native platforms. WebView Native UI Engine helps them work together as one experience, while keeping your Web layouts and navigation.
|
|
6
|
+
|
|
7
|
+
## Web UI. Native UI. One experience.
|
|
8
|
+
|
|
9
|
+
A native component should feel like part of the screen around it. For example:
|
|
10
|
+
|
|
11
|
+
- **Scroll together.** A native ad moves with the surrounding Web content as the reader scrolls through a feed.
|
|
12
|
+
- **Layer together.** A Web alert appears over native navigation controls. Close it, and those controls are ready for native interaction again.
|
|
13
|
+
|
|
14
|
+
Scrolling and overlays are examples of a broader goal: letting Web UI and Native UI coexist throughout the screen's lifecycle.
|
|
6
15
|
|
|
7
16
|

|
|
8
17
|
|
|
9
|
-
_Conceptual view.
|
|
18
|
+
_Conceptual view of overlay presentation. The Engine projects native appearance into the Web layer; it does not reorder the actual native view within the DOM._
|
|
10
19
|
|
|
11
|
-
|
|
20
|
+
https://github.com/user-attachments/assets/2768f014-7325-49c7-b848-25052756c36d
|
|
12
21
|
|
|
13
|
-
|
|
22
|
+
native controls beneath a Web alert, followed by a native ad scrolling with Web content. Recorded on iOS Simulator.
|
|
14
23
|
|
|
15
|
-
|
|
24
|
+
## Built for plugin developers
|
|
16
25
|
|
|
17
|
-
|
|
26
|
+
WebView Native UI Engine is a library for **Capacitor and Cordova plugin developers**. Integrate it into a plugin to bring native components into Web-driven screens, without making each application build its own coordination between rendering layers.
|
|
18
27
|
|
|
19
|
-
|
|
28
|
+
A native view above a WebView does not automatically participate in DOM scrolling, clipping or stacking order. A Web modal cannot simply cover it with a higher `z-index`. The Engine coordinates presentation across that boundary, so you can focus on the controls and native capabilities your plugin provides.
|
|
20
29
|
|
|
21
|
-
|
|
30
|
+
Use it for toolbars, tab bars, controls and capturable SDK views. Keep your existing plugin API and business logic; applications gain these capabilities through the plugins they use.
|
|
22
31
|
|
|
23
|
-
|
|
24
|
-
- **Web overlays that coexist with native content.** Present modals and other overlays over native surfaces, then return to the interactive native UI when they close.
|
|
25
|
-
- **Scrolling and transitions that retain native appearance.** Carry the native surface's captured appearance through Web-layer movement, without recreating its styling in CSS.
|
|
26
|
-
- **Shared infrastructure across components and platforms.** Reuse the same projection and restoration lifecycle on iOS and Android instead of implementing it independently in every integration.
|
|
32
|
+
## How it works
|
|
27
33
|
|
|
28
|
-
|
|
34
|
+
The plugin supplies a native view and a DOM container that defines its place in the Web layout. The Engine coordinates DOM measurement, supported native scroll tracking and the handoff between native and Web presentation.
|
|
29
35
|
|
|
30
|
-
|
|
36
|
+
When the Web layer needs to own presentation, the Engine displays a prepared image of the native component in that container. When native presentation can resume, it coordinates placement and restoration of the interactive view.
|
|
31
37
|
|
|
32
|
-
The
|
|
38
|
+
The image is a temporary visual projection, not a second interactive control. It does not forward clicks or play live video. Capture eligibility and platform rendering limits still apply, including differences in Liquid Glass highlights. When a suitable image is unavailable, the integration uses its configured Web fallback. See [concepts and limits](docs/concepts.md) and [platform support](docs/reference/platforms.md) before choosing a component.
|
|
33
39
|
|
|
34
|
-
##
|
|
40
|
+
## Start building
|
|
35
41
|
|
|
36
|
-
|
|
37
|
-
Plugin authors retain their existing native controls and public APIs; the Engine
|
|
38
|
-
supplies the coordination between native and Web presentation. It supports iOS
|
|
39
|
-
and Android with Capacitor or Cordova. Ionic and Angular are not required.
|
|
42
|
+
The Engine supports **iOS and Android**. Ionic and Angular are optional. Start with a native view and its DOM container, then connect the lifecycle notifications your UI needs. The integration guides cover runtime startup and optional framework support.
|
|
40
43
|
|
|
41
|
-
| Start here |
|
|
42
|
-
| -------------------------------------------------------------- |
|
|
43
|
-
| [
|
|
44
|
-
| [
|
|
45
|
-
| [
|
|
44
|
+
| Start here | Why |
|
|
45
|
+
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
46
|
+
| [Basic initialization](docs/getting-started/initialization.md) | Register a native view and its DOM container with the minimum required setup. |
|
|
47
|
+
| [Capacitor plugin guide](docs/getting-started/capacitor.md) | Connect the Engine to an existing Capacitor plugin. |
|
|
48
|
+
| [Cordova plugin guide](docs/getting-started/cordova.md) | Use the same lifecycle through Cordova's native hooks. |
|
|
49
|
+
| [Documentation](docs/README.md) | Find optional settings, renderer APIs and reference by the problem you need to solve. |
|
|
46
50
|
|
|
47
|
-
|
|
48
|
-
application-side Engine initializer. The API is pre-1.0: pin matching Engine
|
|
49
|
-
versions across npm and native dependencies. Android placement requires API 23+,
|
|
50
|
-
with composited snapshots available from API 26+.
|
|
51
|
+
Use matching Engine versions across npm and native dependencies, and retain dependency lockfiles for reproducible builds. Android placement requires API 23+, with composited snapshots available from API 26+.
|
|
51
52
|
|
|
52
|
-
##
|
|
53
|
+
## Contributing
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
container support and platform contracts. For repository development and publishing,
|
|
56
|
-
see [development and releases](docs/maintenance.md).
|
|
55
|
+
For repository development, verification and publishing, see [development and releases](docs/maintenance.md).
|
|
57
56
|
|
|
58
57
|
## License
|
|
59
58
|
|
package/dist/native/bootstrap.js
CHANGED
|
@@ -16,7 +16,7 @@ const send = (id, request) => new Promise((resolve, reject) => {
|
|
|
16
16
|
pending.set(key, { resolve, reject, timer });
|
|
17
17
|
const message = JSON.stringify({ key, request });
|
|
18
18
|
const host = globalThis;
|
|
19
|
-
const channel = host.webkit?.messageHandlers?.[id] ?? host
|
|
19
|
+
const channel = host.webkit?.messageHandlers?.[id] ?? host.nativeUIEngine;
|
|
20
20
|
if (!channel) {
|
|
21
21
|
clearTimeout(timer);
|
|
22
22
|
pending.delete(key);
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/** Owns asynchronous projection creation and disposal for DOM-backed surfaces. */
|
|
2
2
|
export const createWebProjectionSurfaces = (options = {}) => {
|
|
3
3
|
const entries = new Map();
|
|
4
|
+
const retiring = new Set();
|
|
5
|
+
const retire = (disposal) => {
|
|
6
|
+
const pending = disposal.finally(() => retiring.delete(pending));
|
|
7
|
+
retiring.add(pending);
|
|
8
|
+
return pending;
|
|
9
|
+
};
|
|
4
10
|
let stopped = false;
|
|
5
11
|
const values = () => [...entries.values()].flatMap((entry) => (entry.surface ? [entry.surface] : []));
|
|
6
12
|
let doc;
|
|
@@ -53,11 +59,7 @@ export const createWebProjectionSurfaces = (options = {}) => {
|
|
|
53
59
|
if (!entry)
|
|
54
60
|
return;
|
|
55
61
|
entries.delete(owner);
|
|
56
|
-
|
|
57
|
-
await entry.surface.destroy();
|
|
58
|
-
// A failed creation has nothing to dispose; ensure() reports that error.
|
|
59
|
-
else
|
|
60
|
-
await entry.ready.catch(() => { });
|
|
62
|
+
await retire(entry.surface ? entry.surface.destroy() : entry.ready.catch(() => { }));
|
|
61
63
|
};
|
|
62
64
|
return {
|
|
63
65
|
get: (owner) => entries.get(owner)?.surface,
|
|
@@ -89,7 +91,7 @@ export const createWebProjectionSurfaces = (options = {}) => {
|
|
|
89
91
|
if (stopped || entries.get(owner) !== entry || !owner.isConnected) {
|
|
90
92
|
if (entries.get(owner) === entry)
|
|
91
93
|
entries.delete(owner);
|
|
92
|
-
await surface.destroy();
|
|
94
|
+
await retire(surface.destroy());
|
|
93
95
|
return undefined;
|
|
94
96
|
}
|
|
95
97
|
entry.surface = surface;
|
|
@@ -110,7 +112,7 @@ export const createWebProjectionSurfaces = (options = {}) => {
|
|
|
110
112
|
listeners?.abort();
|
|
111
113
|
if (motionFrame)
|
|
112
114
|
doc?.defaultView?.cancelAnimationFrame(motionFrame);
|
|
113
|
-
await Promise.all([...entries.keys()].map(remove));
|
|
115
|
+
await Promise.all([...retiring, ...[...entries.keys()].map(remove)]);
|
|
114
116
|
},
|
|
115
117
|
};
|
|
116
118
|
};
|
package/dist/projection/web.js
CHANGED
|
@@ -2,7 +2,7 @@ import { projectionURL } from '../native/resource-url.js';
|
|
|
2
2
|
import { bounded, boundedListener } from '../native/bridge.js';
|
|
3
3
|
import { bindProjectionEvents } from './events.js';
|
|
4
4
|
import { snapshotStyles, snapshotShadowStyles } from './styles.js';
|
|
5
|
-
const layout = (
|
|
5
|
+
const layout = ({ control: c }, positionIndependent = false) => [
|
|
6
6
|
c.id,
|
|
7
7
|
c.kind,
|
|
8
8
|
c.placement,
|
|
@@ -12,7 +12,7 @@ const layout = (candidates, positionIndependent = false) => JSON.stringify(candi
|
|
|
12
12
|
c.height,
|
|
13
13
|
c.dark,
|
|
14
14
|
c.rtl,
|
|
15
|
-
]
|
|
15
|
+
];
|
|
16
16
|
/** Images are prepared after accepted native updates, never on the overlay's critical path. */
|
|
17
17
|
const createProjectionEngine = async (scope, transport, callbacks) => {
|
|
18
18
|
const captureDelayMs = callbacks.captureDelayMs ?? 50;
|
|
@@ -48,7 +48,7 @@ const createProjectionEngine = async (scope, transport, callbacks) => {
|
|
|
48
48
|
const relative = origin
|
|
49
49
|
? { ...candidate, control: { ...candidate.control, x: candidate.control.x - origin.x, y: candidate.control.y - origin.y } }
|
|
50
50
|
: candidate;
|
|
51
|
-
return [scopeIDs.get(candidate.scope), layout(
|
|
51
|
+
return [scopeIDs.get(candidate.scope), layout(relative, !!callbacks.opaqueUnderlay)];
|
|
52
52
|
}));
|
|
53
53
|
const sheets = new Map();
|
|
54
54
|
const rootFor = (element) => {
|
|
@@ -249,8 +249,9 @@ const createProjectionEngine = async (scope, transport, callbacks) => {
|
|
|
249
249
|
// One crop may cover a button group, but must have one fixed fallback destination.
|
|
250
250
|
if (result.parts.some((part) => new Set(part.ids.map((id) => selected.find((candidate) => candidate.control.id === id).scope)).size !== 1))
|
|
251
251
|
return;
|
|
252
|
-
|
|
253
|
-
|
|
252
|
+
const partSources = result.parts.map((part) => selected.find((candidate) => part.ids.includes(candidate.control.id)));
|
|
253
|
+
await bounded(Promise.all(result.parts.map(async (part, index) => {
|
|
254
|
+
const target = partSources[index].scope.element;
|
|
254
255
|
let pool = imagePool.get(target);
|
|
255
256
|
if (!pool) {
|
|
256
257
|
pool = [];
|
|
@@ -283,9 +284,9 @@ const createProjectionEngine = async (scope, transport, callbacks) => {
|
|
|
283
284
|
data: result,
|
|
284
285
|
images,
|
|
285
286
|
sources: Array.from(new Set(selected.flatMap((item) => [item.element, ...(item.sources ?? [])]))),
|
|
286
|
-
targets:
|
|
287
|
-
scopes:
|
|
288
|
-
parents:
|
|
287
|
+
targets: partSources.map((source) => source.element),
|
|
288
|
+
scopes: partSources.map((source) => source.scope),
|
|
289
|
+
parents: partSources.map((source) => source.scope.element.parentNode),
|
|
289
290
|
frames: [],
|
|
290
291
|
viewport: size,
|
|
291
292
|
revision,
|
package/docs/README.md
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
# Documentation
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Build Web-driven screens with native controls and capabilities. These guides
|
|
4
|
+
explain how to integrate the Engine into a plugin so Web UI and Native UI can
|
|
5
|
+
coexist. Start with [the shared model](concepts.md): how a native component belongs in a Web layout,
|
|
6
|
+
which layer presents it, and how interaction returns to the live view. Scrolling
|
|
7
|
+
and overlays are examples of that coordination, not separate integration models.
|
|
8
|
+
|
|
9
|
+
Then choose the smallest integration that fits your ownership model. Register a
|
|
10
|
+
native view and its DOM container, connect the lifecycle notifications your UI
|
|
11
|
+
needs, and add advanced APIs only if you already own a renderer's batching or placement.
|
|
7
12
|
|
|
8
13
|
## Choose by the problem you need to solve
|
|
9
14
|
|
|
10
|
-
| Case | Start here
|
|
11
|
-
| ---------------------------------------------------------------------------------------- |
|
|
12
|
-
|
|
|
13
|
-
| A
|
|
14
|
-
|
|
|
15
|
-
|
|
|
15
|
+
| Case | Start here | Why |
|
|
16
|
+
| ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
17
|
+
| An eligible native SDK view belongs in a scrolling Web feed | [Basic registration](getting-started/initialization.md) and [platform limits](reference/platforms.md) | Bind it to its DOM container; native tracking or temporary image presentation depends on the platform and layout. |
|
|
18
|
+
| A Web modal must cover a plugin's native tab bar | [Basic registration](getting-started/initialization.md), then the framework integration guide | Register the view and its DOM host, then connect overlay lifecycle; the Engine coordinates handoff and restoration. |
|
|
19
|
+
| A hidden fallback returns with the old toggle selection | [Value bindings](configuration/values.md) | Reflect current native data on the fallback host, independently of where it is displayed. |
|
|
20
|
+
| Background toolbar buttons and foreground modal buttons need different handoff lifetimes | [Renderer surfaces](advanced/renderer.md) | Separate owners so closing one surface cannot restore another's controls. |
|
|
21
|
+
| An existing renderer overlaps updates or loses a native acknowledgement | [Update queue](advanced/update-queue.md) | Serialize fresh-state passes and reconcile the connection without replaying user actions. |
|
|
16
22
|
|
|
17
23
|
The full reading order follows. Skip advanced APIs unless your renderer owns the
|
|
18
24
|
work described in their cases.
|
package/docs/concepts.md
CHANGED
|
@@ -1,21 +1,46 @@
|
|
|
1
1
|
# Native UI in Web-driven screens
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
The goal is to combine the flexibility of Web layouts and navigation with native
|
|
4
|
+
controls and capabilities in one screen. Applications keep their Web-driven UI;
|
|
5
|
+
plugins supply native components. The Engine coordinates presentation between
|
|
6
|
+
them so each component can coexist with the surrounding screen throughout layout
|
|
7
|
+
changes, interaction and navigation.
|
|
7
8
|
|
|
8
9
|
## Why a bridge call is not enough
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
Creating a native view does not give it a place in the DOM. A view above the
|
|
12
|
+
WebView does not automatically follow a scrolling container or participate in
|
|
13
|
+
its clipping and stacking order. A higher Web `z-index` cannot cover it. Simply
|
|
14
|
+
hiding and showing it can reveal a different appearance or restore it at an
|
|
15
|
+
outdated position.
|
|
14
16
|
|
|
15
|
-
The
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
The shared integration model is a native view paired with a DOM container. The
|
|
18
|
+
container identifies where the component belongs in the Web screen. The plugin
|
|
19
|
+
provides native content and reports changes; the Engine coordinates measurement,
|
|
20
|
+
prepared appearance and the handoff between presentation layers.
|
|
21
|
+
|
|
22
|
+
## What coexistence looks like
|
|
23
|
+
|
|
24
|
+
These situations share the same presentation model. Each integration connects the lifecycle and value notifications it needs:
|
|
25
|
+
|
|
26
|
+
| Situation | Desired experience | How the shared model helps |
|
|
27
|
+
| -------------------------------------------------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
28
|
+
| An eligible native advertisement sits in a Web feed | It stays aligned with the content as the reader scrolls. | The DOM container supplies geometry; supported native tracking or temporary Web projection follows the movement. |
|
|
29
|
+
| A Web alert opens over native navigation controls | The alert covers their appearance, then native interaction returns when it closes. | Lifecycle notifications or the Ionic adapter request coverage; the Engine coordinates image handoff and restoration. |
|
|
30
|
+
| A page or modal changes layout | Its native controls return at the current location rather than an old rectangle. | Geometry and restoration are coordinated with the owning container's lifetime. |
|
|
31
|
+
| A native toggle changes while its Web fallback is hidden | Returning to HTML does not reveal the old value. | Optional value bindings reflect component data independently of presentation. |
|
|
32
|
+
|
|
33
|
+
Scrolling does not always mean moving a live native view. Supported iOS overflow
|
|
34
|
+
layouts can use native scroll bindings; Android uses temporary image presentation,
|
|
35
|
+
and unsupported layouts follow the configured fallback policy. Images do not
|
|
36
|
+
provide live SDK interaction. See [platform limits](reference/platforms.md) and
|
|
37
|
+
[scroll binding constraints](advanced/native-handoff.md#native-scroll-tracking).
|
|
38
|
+
|
|
39
|
+
The Engine prepares images while native content is available and retains them
|
|
40
|
+
through the handoff until native restoration is acknowledged. Preparation is
|
|
41
|
+
separate from presentation so opening an overlay does not wait for capture.
|
|
42
|
+
Application-specific lifecycle decisions still need notifications; registering a
|
|
43
|
+
view does not automatically detect every framework's overlays.
|
|
19
44
|
|
|
20
45
|
## Three presentations, with different purposes
|
|
21
46
|
|
|
@@ -91,7 +116,7 @@ does not promise pixel-identical capture of every native view.
|
|
|
91
116
|
|
|
92
117
|
Validate your actual backgrounds, overlay transitions and restoration on supported
|
|
93
118
|
devices. If capture is unavailable, decide what the user should see in the Web
|
|
94
|
-
fallback before integrating. Read the [capture and platform reference](reference/
|
|
95
|
-
for eligibility
|
|
119
|
+
fallback before integrating. Read the [capture and platform reference](reference/platforms.md)
|
|
120
|
+
and [projection contract](reference/projection.md) for eligibility and failure policies.
|
|
96
121
|
|
|
97
122
|
[Documentation overview](README.md)
|
|
@@ -17,7 +17,7 @@ same position: include that successful selection notification in `receiveListene
|
|
|
17
17
|
| `captureDelayMs` | Prepare images after a 50 ms debounce. | A tab highlight is still animating when its selection event arrives: wait for settled pixels. See [capture timing](capture.md); this does not delay overlay opening. |
|
|
18
18
|
| `canCapture` | Returns true; Engine geometry and platform checks still apply. | An SDK switches from capturable static content to restricted video: prevent an ineligible capture. Return eligibility for the current content. |
|
|
19
19
|
| `failedFallback` | Use the ordinary Web fallback when no suitable image is available. | An SDK view has no usable Web replacement: keep it native during automatic motion only if the renderer maintains its placement. Explicit Web coverage and `none` still take precedence. See [failure policy](../reference/projection.md#native-surface-requirements). |
|
|
20
|
-
| `allowedOrigins` |
|
|
20
|
+
| `allowedOrigins` | Capacitor: bundled `server.url` or local hostname/scheme; localhost defaults when no app server config exists. Cordova: localhost defaults. | Override for programmatic configuration or a narrower trusted origin. On Android set `install` before navigation; registrations inherit it. See [origin matching](../reference/projection.md). |
|
|
21
21
|
| `runtime` | Capacitor. | **Required for Cordova integrations**: select Cordova so notifications and resource URLs use its transport. |
|
|
22
22
|
| `captureMode` (Android) | `COMPOSITED`, including the visible background. | An opaque card scrolls past adjacent content: `VIEW` captures the card alone instead of surrounding window pixels. Do not use it for translucent content, video or SurfaceView. See [capture eligibility](../reference/platforms.md#android-capture-modes). |
|
|
23
23
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Capacitor plugin integration
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Let an existing Capacitor plugin's native components coexist with Web layouts, navigation and overlays without changing its public `registerPlugin()` export. The plugin keeps its native renderer and application API; registration connects each native view to its DOM container using the [shared presentation model](../concepts.md).
|
|
4
4
|
|
|
5
5
|
This guide covers dependencies, registration, notifications and teardown. Start with
|
|
6
6
|
[native initialization](initialization.md) for the minimal call, required inputs
|
|
@@ -40,9 +40,9 @@ The primary native distribution is Swift Package Manager. Depend on the reposito
|
|
|
40
40
|
.product(name: "WebViewNativeUIEngine", package: "engine")
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
Use the same Engine release across npm, SwiftPM, Gradle and CocoaPods, and upgrade deliberately. Applications should retain their dependency lockfiles for reproducible builds.
|
|
44
44
|
|
|
45
|
-
SwiftPM resolves this repository's version tags such as `
|
|
45
|
+
SwiftPM resolves this repository's version tags such as `v1.0.0`. For unreleased integration tests, use a local checkout or an explicit tested commit.
|
|
46
46
|
|
|
47
47
|
`import WebViewNativeUIEngine` requires no Capacitor registration. The npm companion supplies DOM measurement and Web image handoff; SwiftPM resolves the native dependency independently of npm hoisting.
|
|
48
48
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Cordova plugin integration
|
|
2
2
|
|
|
3
|
+
Let a Cordova plugin's native components coexist with Web layouts, navigation and overlays using the [same presentation model](../concepts.md) as Capacitor.
|
|
4
|
+
|
|
3
5
|
The same npm package, Swift library and Android AAR support Capacitor and Cordova. Engine is a library used by plugin maintainers, not a separately registered Cordova plugin. A Cordova application does not need `@capacitor/core` or a Capacitor native SDK.
|
|
4
6
|
|
|
5
7
|
The consuming plugin still owns its native view and the corresponding DOM, including placement, size and stacking order. Supply an existing selector such as `native-ad` or `#player`. The DOM may be added after initialization. Image preparation, scroll handling, overlays and restoration use the common Engine implementation.
|
|
@@ -32,7 +34,7 @@ frameworks report their own transition lifecycle through notifications.
|
|
|
32
34
|
Replace `<engine-version>` in every dependency below with the same published
|
|
33
35
|
release. Read that release tag’s documentation so the examples match its APIs.
|
|
34
36
|
|
|
35
|
-
Use the same Engine release for the Web package and native libraries.
|
|
37
|
+
Use the same Engine release for the Web package and native libraries. Pin matching versions and retain dependency lockfiles for reproducible builds.
|
|
36
38
|
|
|
37
39
|
```sh
|
|
38
40
|
npm install --save-exact '@webview-native-ui/engine@<engine-version>'
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
Start with `NativeUIProjection` when a plugin owns a native view and a corresponding
|
|
4
4
|
Web container. Registration starts the runtime, binds that container and coordinates
|
|
5
|
-
|
|
5
|
+
presentation between the native view and the Web layout. This is the same starting
|
|
6
|
+
point for a component in a scrolling feed or beneath a Web overlay. You do not need
|
|
7
|
+
the renderer APIs for this route. See [the shared model](../concepts.md) for how
|
|
8
|
+
these situations relate and where platform limits apply.
|
|
6
9
|
|
|
7
10
|
Use the [Capacitor](capacitor.md) or [Cordova](cordova.md) guide for
|
|
8
11
|
dependency installation, plugin lifecycle hooks and notification forwarding.
|
|
@@ -46,7 +49,20 @@ projection = NativeUIProjection(
|
|
|
46
49
|
)
|
|
47
50
|
```
|
|
48
51
|
|
|
49
|
-
|
|
52
|
+
Java can use the same defaults without supplying every optional argument:
|
|
53
|
+
|
|
54
|
+
```java
|
|
55
|
+
NativeUIProjection.install(getBridge().getWebView());
|
|
56
|
+
projection = new NativeUIProjection(
|
|
57
|
+
getActivity().getWindow(),
|
|
58
|
+
getBridge().getWebView(),
|
|
59
|
+
getPluginHandle().getId(),
|
|
60
|
+
"#native-ui-fallback",
|
|
61
|
+
() -> nativeView
|
|
62
|
+
);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
These snippets belong inside the integration guide's error boundary; retain the
|
|
50
66
|
existing Web fallback if initialization fails. `projection` and `nativeView` are
|
|
51
67
|
properties of your plugin. Dispose the registration with `destroy()` on iOS or
|
|
52
68
|
`close()` on Android when that renderer is retired. All native lifecycle calls
|
|
@@ -100,8 +100,8 @@ precision alone does not resolve this difference.
|
|
|
100
100
|
Left: **iPhone 15 Pro Max, iOS 27.2**. Right: **iPad mini (6th generation),
|
|
101
101
|
iPadOS 27.2**. Each device screenshot shows the captured **16-bit Display P3 PNG
|
|
102
102
|
in WKWebView above** and the **live UIKit tab bar below**, at the same size within
|
|
103
|
-
that device.
|
|
104
|
-
their shared color profile. These are physical-device results, not Simulator captures.
|
|
103
|
+
that device. For this comparison, the iPhone screenshot was resized to match the iPad
|
|
104
|
+
screenshot's height; their shared color profile was preserved. These are physical-device results, not Simulator captures.
|
|
105
105
|
|
|
106
106
|
The system screenshot preserves the live appearance, but the application-level
|
|
107
107
|
capture does not reproduce it completely. On the tested iPhone, the difference was
|
|
@@ -125,7 +125,7 @@ Listeners follow host reparenting and slot reassignment and are removed on teard
|
|
|
125
125
|
|
|
126
126
|
Scrolling is internal: iOS uses a uniquely matched native scroll binding when available; otherwise, including Android, scrolling temporarily uses the prepared image and restores native content after motion settles. Automatic scroll handling never overrides explicit `web` or `none`. Unsupported capture or geometry keeps the normal DOM fallback; it does not wait for a new capture on the transition path. The latest explicit destination survives WebView reload, and old-document replies cannot complete a new document's requests.
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
The internal channel is limited to the main frame. Capacitor origins come from the bundled `capacitor.config.json`: `server.url` takes precedence over the local hostname/scheme. To override them, pass exact `allowedOrigins` (on Android, to `install` before navigation; registrations inherit them). Neither `allowNavigation` nor the current WebView URL expands this set. Android requires WebView's `WEB_MESSAGE_LISTENER` and `DOCUMENT_START_SCRIPT` features; registration fails explicitly on unsupported WebView implementations. Do not use wildcard origins for remotely navigable WebViews.
|
|
129
129
|
|
|
130
130
|
For capture modes, translucent surfaces, image color and private storage, see
|
|
131
131
|
[capture and platform limits](platforms.md). Custom renderer bridge and scroll
|
|
@@ -79,7 +79,7 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
|
|
|
79
79
|
|
|
80
80
|
public convenience init(webView: WKWebView?, plugin: String, projectionSelector: String,
|
|
81
81
|
receiveListeners: ReceiveListeners = .init(),
|
|
82
|
-
allowedOrigins: Set<String
|
|
82
|
+
allowedOrigins: Set<String>? = nil,
|
|
83
83
|
failedFallback: FailedFallback = .web, runtime: Runtime = .capacitor,
|
|
84
84
|
captureDelayMs: Double = 50,
|
|
85
85
|
values: [String: ValueBinding] = [:], readValues: (() -> [String: Any])? = nil,
|
|
@@ -91,12 +91,14 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
|
|
|
91
91
|
}
|
|
92
92
|
init(webView: WKWebView?, plugin: String, projectionSelector: String,
|
|
93
93
|
receiveListeners: ReceiveListeners = .init(),
|
|
94
|
-
allowedOrigins: Set<String
|
|
94
|
+
allowedOrigins: Set<String>? = nil,
|
|
95
95
|
failedFallback: FailedFallback = .web, runtime: Runtime = .capacitor,
|
|
96
96
|
captureDelayMs: Double = 50,
|
|
97
97
|
values: [String: ValueBinding] = [:], readValues: (() -> [String: Any])? = nil,
|
|
98
98
|
canCapture: @escaping () -> Bool = { true }, snapshots: NativeUICoveredSnapshots,
|
|
99
99
|
view: @escaping () -> UIView?) throws {
|
|
100
|
+
let allowedOrigins = try allowedOrigins
|
|
101
|
+
?? (runtime == .capacitor ? ProjectionOrigins.configured() : ProjectionOrigins.defaults)
|
|
100
102
|
// JSONSerialization produces valid UTF-8.
|
|
101
103
|
// swiftlint:disable:next force_unwrapping
|
|
102
104
|
self.allowedOriginsJSON = String(data: try JSONSerialization.data(withJSONObject: Array(allowedOrigins)), encoding: .utf8)!
|
|
@@ -273,7 +275,7 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
|
|
|
273
275
|
restoreAccepted = true
|
|
274
276
|
complete(["shown": valid && snapshots.cover(
|
|
275
277
|
token, in: webView,
|
|
276
|
-
views: Array(
|
|
278
|
+
views: Array(selected.values),
|
|
277
279
|
transient: true, frames: frames
|
|
278
280
|
)])
|
|
279
281
|
case "restore":
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import WebKit
|
|
3
|
+
|
|
4
|
+
enum ProjectionOrigins {
|
|
5
|
+
static let defaults: Set<String> = ["capacitor://localhost", "app://localhost", "https://localhost", "http://localhost"]
|
|
6
|
+
|
|
7
|
+
static func configured(in bundle: Bundle = .main) throws -> Set<String> {
|
|
8
|
+
guard let url = bundle.url(forResource: "capacitor.config", withExtension: "json") else { return defaults }
|
|
9
|
+
guard let configuration = try JSONSerialization.jsonObject(with: Data(contentsOf: url)) as? [String: Any] else { throw URLError(.badURL) }
|
|
10
|
+
return try configured(configuration)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static func configured(_ configuration: [String: Any]) throws -> Set<String> {
|
|
14
|
+
guard let server = configuration["server"] as? [String: Any] else { return defaults }
|
|
15
|
+
var scheme = server["iosScheme"] as? String ?? "capacitor"
|
|
16
|
+
if WKWebView.handlesURLScheme(scheme) || scheme.range(of: "^[a-z][a-z0-9.+-]*$", options: [.caseInsensitive, .regularExpression]) == nil {
|
|
17
|
+
scheme = "capacitor"
|
|
18
|
+
}
|
|
19
|
+
let host = server["hostname"] as? String ?? "localhost"
|
|
20
|
+
guard let url = URLComponents(string: server["url"] as? String ?? "\(scheme)://\(host)"),
|
|
21
|
+
let scheme = url.scheme?.lowercased(), let host = url.host?.lowercased(),
|
|
22
|
+
!host.isEmpty, !host.contains("*") else { throw URLError(.badURL) }
|
|
23
|
+
var origin = URLComponents()
|
|
24
|
+
origin.scheme = scheme
|
|
25
|
+
origin.host = host
|
|
26
|
+
origin.port = url.port
|
|
27
|
+
if (scheme == "https" && url.port == 443) || (scheme == "http" && url.port == 80) { origin.port = nil }
|
|
28
|
+
guard let value = origin.string else { throw URLError(.badURL) }
|
|
29
|
+
return [value]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var WebViewNativeUIEngineRuntime=(()=>{var Ge=Object.defineProperty;var
|
|
1
|
+
"use strict";var WebViewNativeUIEngineRuntime=(()=>{var Ge=Object.defineProperty;var pt=Object.getOwnPropertyDescriptor;var mt=Object.getOwnPropertyNames;var vt=Object.prototype.hasOwnProperty;var ht=(t,i)=>{for(var s in i)Ge(t,s,{get:i[s],enumerable:!0})},yt=(t,i,s,v)=>{if(i&&typeof i=="object"||typeof i=="function")for(let y of mt(i))!vt.call(t,y)&&y!==s&&Ge(t,y,{get:()=>i[y],enumerable:!(v=pt(i,y))||v.enumerable});return t};var gt=t=>yt(Ge({},"__esModule",{value:!0}),t);var Wt={};ht(Wt,{hide:()=>Ct,notify:()=>St,receive:()=>kt,show:()=>Rt,start:()=>At,stop:()=>Ot});var tt=(t,i,s)=>{for(let[v,y]of Object.entries(i)){if(!/^[a-z][a-z0-9-]*$/.test(v))throw new TypeError("Native value keys must be lowercase attribute names");let f=(Object.hasOwn(s,v)?s[v]:void 0)?.property;if(f&&(!/^[a-zA-Z][\w]*$/.test(f)||/^on/i.test(f)||["innerHTML","outerHTML","textContent","innerText","style","constructor","prototype"].includes(f)))throw new TypeError("Native value binding requires a data property");let P=JSON.stringify(y);if(P===void 0)throw new TypeError("Native values must be JSON values");if(f){let p=t;JSON.stringify(p[f])!==P&&(p[f]=y)}else{let p=`data-native-ui-value-${v}`,M=typeof y=="string"?y:P;t.getAttribute(p)!==M&&t.setAttribute(p,M)}}};var wt=Symbol.for("webview-native-ui-engine.projection-placement");var Ue=t=>t?.[wt];var bt=(t,i)=>{if(t.matches("ion-toast, ion-menu"))return!1;let s=t;if(s.showBackdrop===!1)return!1;if(!t.matches("ion-modal"))return!0;let v=i??s.initialBreakpoint;return v===void 0||v>(s.backdropBreakpoint??0)},Et=Symbol.for("@webview-native-ui/engine/overlays/v1"),Pt=t=>{let i=new Set,s=new Set,v=new Set,y=new WeakMap,m=new WeakSet,f=new Map,P=[],p={},M=new Map,S,j=g=>{for(let d of[...v])try{d(g)}catch(w){console.error("Native UI overlay listener failed",w)}},B=(g,d,w)=>{d==="willPresent"||d==="didPresent"?(m.delete(g),i.add(g)):d==="didDismiss"&&(m.add(g),i.delete(g),s.delete(g),y.delete(g));let c=w?.detail?.breakpoint;typeof c=="number"&&c>0&&y.set(g,c),j({element:g,phase:d,event:w})},H=(g=!1)=>{let d=!1;for(let w of i)(!w.isConnected||w.ownerDocument!==t||!P.some(({selector:c})=>w.matches(c)))&&(i.delete(w),s.delete(w),d=!0);for(let w of t.querySelectorAll(P.map(({selector:c})=>c).join(",")))!i.has(w)&&!m.has(w)&&(g||!w.matches("ion-popover"))&&(w.presented||w.classList.contains("show-menu"))&&(i.add(w),d=!0);d&&j({phase:"change"})};return{get active(){return i},subscribe(g){return v.add(g),()=>{v.delete(g)}},setNative(g,d){s.has(g)!==d&&(d?s.add(g):s.delete(g),j({element:g,phase:"change"}))},isExcluded(g){return!!p.exclude&&g.matches(p.exclude)},isNative(g){return s.has(g)},get stack(){let g=[...i].filter(w=>w.isConnected&&w.ownerDocument===t),d=w=>{let c=Number.parseFloat(t.defaultView.getComputedStyle(w).zIndex);return Number.isFinite(c)?c:w.overlayIndex??0};return g.sort((w,c)=>d(w)-d(c)),g},isCovered(g){let d=this.stack,w=d.reduce((c,W,k)=>W.contains(g)?k:c,-1);return d.some((c,W)=>{if(s.has(c)||p.exclude&&c.matches(p.exclude))return!1;let k=p.covers?.(c,g);return k!==void 0?k:W>w&&!c.contains(g)&&(c.matches("ion-menu")||bt(c,y.get(c)))})},enable(g,d){let w={...p,...d},c=[...g,...w.additional??[]];w.exclude&&t.querySelector(w.exclude);let W=new Map;for(let l of c){t.querySelector(l.selector);for(let[V,$]of Object.entries(l.events)){let J=W.get($);if(J&&J.phase!==V)throw new TypeError(`Overlay event "${$}" has conflicting phases`);W.set($,{phase:V,selector:J?`${J.selector}, ${l.selector}`:l.selector})}}p=w,P=c,M=W;for(let l of M.keys()){if(f.has(l))continue;let V=$=>{let J=M.get(l),ge=$.composedPath().find(_=>_ instanceof t.defaultView.HTMLElement&&_.matches(J.selector));ge&&B(ge,J.phase,$)};t.addEventListener(l,V,!0),f.set(l,()=>t.removeEventListener(l,V,!0))}for(let[l,V]of f)M.has(l)||(V(),f.delete(l));let k=!S;S||(S=new MutationObserver(()=>H()),S.observe(t.documentElement,{childList:!0,subtree:!0}),t.addEventListener("nativeUIOverlayAdopted",l=>{let V=l.detail;V?.ownerDocument===t&&B(V,"willPresent",l)})),H(k),(k||d)&&j({phase:"change"})}}},nt=t=>{let i=t;return i[Et]??=Pt(t)};function*De(t){let i=t;for(;i;){let s=i.getRootNode();i=i.assignedSlot??i.parentElement??(s instanceof ShadowRoot?s.host:null),i&&(yield i)}}var Tt=({x:t,y:i,width:s,height:v})=>({x:t,y:i,width:s,height:v}),ot=t=>{let i=t.getBoundingClientRect(),s=getComputedStyle(t),v=parseFloat(s.borderLeftWidth)||0,y=parseFloat(s.borderTopWidth)||0;return{x:i.left+v,y:i.top+y,width:i.width-v-(parseFloat(s.borderRightWidth)||0),height:i.height-y-(parseFloat(s.borderBottomWidth)||0)}},Ke=(t,i,s)=>{let v=[t,...De(t)],y=v.indexOf(i);if(y<=0||i===t.ownerDocument.scrollingElement)return;let m=t.ownerDocument.defaultView;if(m.visualViewport&&(m.visualViewport.scale!==1||m.visualViewport.offsetLeft||m.visualViewport.offsetTop))return;let f=0,P=0,p=m.innerWidth,M=m.innerHeight;for(let[H,g]of v.entries()){let d=getComputedStyle(g);if(d.transform!=="none"&&!new DOMMatrixReadOnly(d.transform).isIdentity||d.zoom&&d.zoom!=="normal"&&Number(d.zoom)!==1||[d.translate,d.rotate,d.scale,d.perspective].some(k=>k&&k!=="none")||d.writingMode&&d.writingMode!=="horizontal-tb"||H<y&&/^(fixed|sticky)$/.test(d.position))return;if(H===0)continue;if(d.scrollbarGutter&&d.scrollbarGutter!=="auto")return;let w=/^(auto|scroll|hidden|clip)$/.test(d.overflowX),c=/^(auto|scroll|hidden|clip)$/.test(d.overflowY);if(H<y&&(w||c))return;let W=g===t.ownerDocument.scrollingElement;if(H>y&&((w||W)&&g.scrollWidth>g.clientWidth||(c||W)&&g.scrollHeight>g.clientHeight)||(w||c)&&[d.borderTopLeftRadius,d.borderTopRightRadius,d.borderBottomLeftRadius,d.borderBottomRightRadius].some(k=>parseFloat(k)>0)||d.clipPath&&d.clipPath!=="none"||d.maskImage&&d.maskImage!=="none")return;if(H>=y){let k=ot(g);w&&(f=Math.max(f,k.x),p=Math.min(p,k.x+k.width)),c&&(P=Math.max(P,k.y),M=Math.min(M,k.y+k.height))}}let S=getComputedStyle(i);if(!/^(auto|scroll)$/.test(S.overflowX)&&!/^(auto|scroll)$/.test(S.overflowY))return;let j=ot(i);if(p<=f||M<=P||!j.width||!j.height)return;let B=Tt(t.getBoundingClientRect());return{id:s(i),offsetX:i.scrollLeft,offsetY:i.scrollTop,viewport:j,clip:{x:f,y:P,width:p-f,height:M-P},contentWidth:i.scrollWidth,contentHeight:i.scrollHeight,frame:{...B,x:B.x-j.x+i.scrollLeft,y:B.y-j.y+i.scrollTop}}};var it=t=>{let i=globalThis;if(i.Capacitor?.convertFileSrc)return i.Capacitor.convertFileSrc(t);if(!t.startsWith("file:"))return t;if(i.WkWebView?.convertFilePath)return i.WkWebView.convertFilePath(t);throw new Error("Native UI file URL requires a host resource handler")};var ye=t=>new Promise((i,s)=>{let v=setTimeout(()=>s(new Error("Native UI bridge timed out")),5e3);t.then(i,s).finally(()=>clearTimeout(v))}),Ye=async t=>{try{return await ye(t)}catch(i){throw t.then(s=>s.remove()).catch(()=>{}),i}};var qe=async(t,i)=>{let s=new Map;for(let P of t.update??[])s.set(P,{updated:!0});for(let P of["native","web","none"])for(let p of t.projection?.[P]??[]){let M=s.get(p)??{updated:!1};if(M.destination&&M.destination!==P)throw new TypeError(`Projection event "${p}" has conflicting destinations`);s.set(p,{...M,destination:P})}let v=!1,y=[],m=async()=>{v=!0;let p=(await Promise.allSettled(y.splice(0).map(M=>Promise.resolve().then(()=>M.remove())))).find(M=>M.status==="rejected");if(p?.status==="rejected")throw p.reason},f=[...s].map(async([P,p])=>{let M=await Ye(Promise.resolve().then(()=>t.addListener(P,S=>{!v&&(!t.accepts||t.accepts(S))&&i(p.destination,p.updated)})));v?await M.remove():y.push(M)});try{return await Promise.all(f),{remove:m}}catch(P){throw await m().catch(()=>{}),P}};var xe=":is([data-native-ui-snapshot-source], [data-native-ui-snapshot-prepared], [data-native-ui-snapshot-content])",rt=`
|
|
2
2
|
@layer native-ui-projection {
|
|
3
3
|
${xe}, ${xe} *, ${xe}::part(native) { visibility: hidden !important; }
|
|
4
4
|
${xe}::before, ${xe}::after,
|
|
@@ -19,4 +19,4 @@ ${xe} *::before, ${xe} *::after {
|
|
|
19
19
|
visibility: hidden !important;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
-
`;var Pt=(t,r=!1)=>JSON.stringify(t.map(({control:o})=>[o.id,o.kind,o.placement,r?0:o.x,r?0:o.y,o.width,o.height,o.dark,o.rtl])),Tt=async(t,r,o)=>{let v=o.captureDelayMs??50;if(!Number.isFinite(v)||v<0||v>2147483647)throw new RangeError("captureDelayMs must be a finite, nonnegative timer interval");let y="native",m=t.element.ownerDocument,f=m.defaultView,P=Array.from(f.crypto.getRandomValues(new Uint32Array(4)),e=>e.toString(16)).join("-"),p=e=>e.isConnected&&e.ownerDocument===m,M=e=>!!e?.isConnected&&e.ownerDocument===m,x=new Map,j=new Set,B=e=>{j.delete(e),e.style.setProperty("display","none","important"),e.removeAttribute("data-native-ui-projection-image"),e.removeAttribute("src"),He()},k=r.send.bind(r),g="data-native-ui-snapshot",d=`${t.namespace}:sources-change`,w=new Set,c=new Set,W=new Set,R=new WeakMap,l=0,V=e=>JSON.stringify(e.map(i=>{R.has(i.scope)||R.set(i.scope,++l);let n=o.transient&&!o.opaqueUnderlay?i.scope.element.getBoundingClientRect():void 0,a=n?{...i,control:{...i.control,x:i.control.x-n.x,y:i.control.y-n.y}}:i;return[R.get(i.scope),Pt([a],!!o.opaqueUnderlay)]})),$=new Map,G=e=>{let i=e.getRootNode();return i.nodeType===11&&"host"in i?i:m},ye=e=>{if($.has(e))return;let i=m.createElement("style");i.setAttribute("data-native-ui-snapshot-base",""),i.textContent=rt+(e.nodeType===11?st:""),(e.nodeType===11?e:e.head).append(i),$.set(e,i)},J=e=>{let i=[...e.getAnimations({subtree:!0}),...[...K.get(e)??[]].flatMap(n=>n.shadowRoot?.getAnimations()??[])];for(let n of i)"transitionProperty"in n&&n.transitionProperty==="visibility"&&n.cancel()},K=new Map,ee=e=>{let i=K.get(e)??new Set;K.set(e,i);let n=e.hasAttribute("data-native-ui-snapshot-source")||e.hasAttribute("data-native-ui-snapshot-prepared"),a=T=>{if(!T.hasAttribute("data-native-ui-projection-node")){if(T.shadowRoot){i.add(T),ye(T.shadowRoot);for(let S of T.shadowRoot.children)a(S)}for(let S of T.children)a(S)}};a(e);for(let T of i)T.toggleAttribute("data-native-ui-snapshot-content",n);J(e)},pe=()=>`${f.innerWidth}:${f.innerHeight}:${f.devicePixelRatio}`,re=!1,le=!1,te=0,de=0,L,me,b,H=!1,D=!1,Pe=0,Te=0,oe=0,ue=0,I=0,fe=-1,A=!1,Fe=!1,Y,He=()=>{let e=new Set(Y?.candidates.map(n=>n.scope.element));for(let[n,a]of x){let T=!A&&n.isConnected&&e.has(n);if(T&&(b||D||re))continue;let S=T?2*Math.max(1,L?.scopes.filter(O=>O.element===n).length??0):0,C=Math.max(0,S-a.filter(O=>j.has(O)).length),U=a.filter(O=>j.has(O)||C-- >0?!0:(O.remove(),!1));U.length?x.set(n,U):x.delete(n)}let i=new Set([...Y?.candidates.map(n=>n.scope.element.getRootNode())??[],...b?.scopes.map(n=>n.element.getRootNode())??[],...L?.scopes.map(n=>n.element.getRootNode())??[],...[...j].map(n=>n.getRootNode()),...[...K.values()].flatMap(n=>[...n].map(a=>a.shadowRoot))]);for(let[n,a]of $)n.nodeType===11&&!i.has(n)&&(a.remove(),$.delete(n))},ge=new Set,Ve=(e,i,n)=>{let a=()=>{ge.delete(a)&&(k({action:e,token:i}).catch(()=>{}),e==="restored"&&He())};ge.add(a),n&&!A?f.requestAnimationFrame(()=>f.requestAnimationFrame(a)):a()},q=new Set,ke=()=>{q.forEach(e=>W.delete(e)),q.clear()},Le=(e,i=!1)=>{!e||e===L||e===b||(e.images.forEach(n=>{B(n)}),Ve("release",e.data.token,i))},se=e=>e.filter(i=>{if(!M(i.scope.element)||![i.element,...i.sources??[]].every(p))return!1;if(i.control.scroll){let n=i.element.getBoundingClientRect(),a=i.control.scroll.clip;if(n.right<=a.x||n.bottom<=a.y||n.left>=a.x+a.width||n.top>=a.y+a.height)return!1}return o.eligible?.(i)??!0}),ze=async()=>{if(ue=0,A||y!=="native"||Fe||H||b||o.blocked()||!Y||L?.revision===Y.revision&&fe===I)return;let{revision:e,candidates:i}=Y,n=oe,a=I,T=pe(),S=se(i);if(!S.length)return;Fe=!0;let C,U=!1,O=[];try{let ae=!1,ce=k({action:"prepare",revision:o.captureRevision?.()??e,viewportWidth:f.innerWidth,ids:S.map(E=>E.control.id)});ce.then(E=>{ae&&E.token&&k({action:"release",token:E.token}).catch(()=>{})}).catch(()=>{});try{C=await he(ce)}finally{ae=!0}if(!C.token||!C.parts?.length)return;let We=new Set(S.map(E=>E.control.id));if(C.parts.some(E=>!E.url.startsWith("file:")&&!/^\/__native_ui_engine__\/nativeUI[a-fA-F0-9]+\/[a-fA-F0-9-]+-[0-9]+\.png$/.test(E.url)||!E.ids.length||E.ids.some(_=>!We.has(_))||![E.x,E.y,E.width,E.height].every(Number.isFinite)||E.width<=0||E.height<=0)||new Set(C.parts.flatMap(E=>E.ids)).size!==We.size||C.parts.some(E=>new Set(E.ids.map(_=>S.find(Se=>Se.control.id===_).scope)).size!==1)||(await he(Promise.all(C.parts.map(async E=>{let _=S.find(_e=>E.ids.includes(_e.control.id)).scope.element,Se=x.get(_);Se||(Se=[],x.set(_,Se));let ve=Se.find(_e=>!j.has(_e));return ve||(ve=m.createElement("img"),ve.setAttribute("data-native-ui-projection-node",""),Se.push(ve)),j.add(ve),O.push(ve),ve.src=it(E.url),await ve.decode(),ve}))),A||y!=="native"||H||b||o.blocked()||oe!==n||pe()!==T||Y?.revision!==e||S.some(E=>!M(E.scope.element)||![E.element,...E.sources??[]].every(p))))return;let De=L,et={data:C,images:O,sources:Array.from(new Set(S.flatMap(E=>[E.element,...E.sources??[]]))),targets:C.parts.map(E=>S.find(_=>E.ids.includes(_.control.id)).element),scopes:C.parts.map(E=>S.find(_=>E.ids.includes(_.control.id)).scope),parents:C.parts.map(E=>S.find(_=>E.ids.includes(_.control.id)).scope.element.parentNode),frames:[],viewport:T,revision:e,layout:V(S)};try{if(!Q(et))throw new Error("Projection destination is unavailable")}catch(E){Ae();try{Q(),L?.sources.forEach(_=>{W.add(_),q.add(_)})}catch{ne()}throw E}L=et,ke(),L.sources.forEach(E=>{W.add(E),q.add(E)}),o.opaqueUnderlay&&k({action:"prepared",token:C.token}).catch(()=>{}),f.dispatchEvent(new Event(d)),fe=a,U=!0,Le(De)}catch{}finally{U||O.forEach(ae=>{B(ae)}),C?.token&&!U&&k({action:"release",token:C.token}).catch(()=>{}),Fe=!1,Y&&(Y.revision!==e||I!==a)&&ie()}},ie=()=>{f.clearTimeout(ue),!A&&y==="native"&&!b&&!H&&!o.blocked()&&(ue=f.setTimeout(()=>{ze()},v))},Re,Je=(e,i)=>{if(i.some(a=>a.scope.element.ownerDocument!==m||[a.element,...a.sources??[]].some(T=>T.ownerDocument!==m)))throw new TypeError("All projection sources and fallback scopes must share one Document");if(o.blocked())return;!b&&L&&L.layout!==V(se(i))&&je();let n=V(i);Re!==n&&(Re=n,I++,oe++),Y?.revision!==e&&oe++,Y={revision:e,candidates:i},He(),(L?.revision!==e||fe!==I)&&ie()},Me=e=>{!b&&L&&e&&Y?.candidates.some(i=>i.scrollElement===e&&L.sources.includes(i.element))&&je(),b&&z(),I++,oe++,ie()},Ce=await Xe(r.listen(({active:e})=>{H=e,oe++,f.clearTimeout(ue),e||ie()})),Oe=new Set,we=e=>{K.get(e)?.forEach(i=>i.removeAttribute("data-native-ui-snapshot-content")),Oe.delete(e)&&e.removeAttribute("data-native-ui-snapshot-prepared"),e.removeAttribute("data-native-ui-snapshot-visible"),e.removeAttribute(g),e.removeAttribute("data-native-ui-snapshot-positioned"),e.removeAttribute("data-native-ui-snapshot-source"),J(e),K.delete(e)},Ae=()=>{de++,f.cancelAnimationFrame(te);for(let e of Z.keys())e.style.setProperty("opacity","0","important");Z.clear(),te=0,re=!1,le=!1,ke(),b?.sources.forEach(e=>{w.delete(e),c.delete(e)}),h.forEach(we),h.clear(),$.forEach((e,i)=>{(A||i.nodeType===11&&!i.host.isConnected)&&(e.remove(),$.delete(i))})},ne=(e=b,i=D)=>{if(b!==e)return;let n=new Set([b,L]);Ae(),b=void 0,L=void 0,D=!1,f.clearTimeout(Pe),n.forEach(a=>Le(a,i)),o.wake()},$e=()=>{if(!b)return;if(L!==b){ne();return}let e=b;de++,f.cancelAnimationFrame(te),te=0,re=le=!1,e.sources.forEach(i=>{w.delete(i),c.delete(i)}),h.forEach(i=>i.removeAttribute("data-native-ui-snapshot-source")),N(e,!!o.opaqueUnderlay),b=void 0,D=!1,f.clearTimeout(Pe),Ve("restored",e.data.token,!0),e.sources.forEach(i=>{W.add(i),q.add(i)}),o.wake()},s=()=>{D&&$e(),ge.forEach(e=>e())},u=e=>e.scopes.map(i=>M(i.element)?i.element:void 0),h=new Set,N=(e,i)=>{for(let n of h)n.toggleAttribute("data-native-ui-snapshot-visible",i),ee(n);e.images.forEach(n=>n.style.setProperty("opacity",i?"1":"0","important"))},F=new Map,Z=new Map,z=()=>{let e=[];for(let[i,n]of Z){let{target:a,frame:T}=n;if(!a.isConnected){i.remove();continue}let S=a.shadowRoot??a;i.parentNode!==S&&S.insertBefore(i,null);let C=a.getBoundingClientRect(),U=i.getBoundingClientRect(),O=parseFloat(i.style.width)||T.width,ae=parseFloat(i.style.height)||T.height,ce=U.width/O||1,We=U.height/ae||1,De=n.scale??(n.scale={x:ce,y:We});e.push({element:i,left:(parseFloat(i.style.left)||0)+(C.x+T.x*ce/De.x-U.x)/ce,top:(parseFloat(i.style.top)||0)+(C.y+T.y*We/De.y-U.y)/We,width:T.width/De.x,height:T.height/De.y})}for(let{element:i,...n}of e)for(let[a,T]of Object.entries(n)){let S=`${T}px`;i.style.getPropertyValue(a)!==S&&i.style.setProperty(a,S,"important")}},Q=(e=b??L)=>{if(!e||D)return!1;if(!e.sources.every(p)||u(e).some(n=>!n))return je(),!1;let i=u(e);if(b){if(i.some(a=>!a?.isConnected||!$.has(G(a))))return ne(b,!1),!1;let n=new Set;for(let[a,T]of e.targets.entries()){let S=F.get(T),C=i[a];!S||!C?.isConnected||(C.setAttribute(g,S),C.setAttribute("data-native-ui-snapshot-source",""),n.add(C))}for(let a of h)n.has(a)||we(a);return h.clear(),n.forEach(a=>h.add(a)),N(e,le),!0}x.forEach(n=>n.forEach(a=>{e.images.includes(a)||(a.style.setProperty("display","none","important"),a.removeAttribute("data-native-ui-projection-image"))})),F.clear(),Z.clear(),h.forEach(we),h.clear();for(let n of new Set(i)){if(!n)continue;h.add(n),ye(G(n));let a=i.flatMap((U,O)=>U===n?[O]:[]),T=`${P}-${a[0]}`;n.setAttribute(g,T),n!==e.targets[a[0]]&&(n.setAttribute("data-native-ui-snapshot-prepared",""),Oe.add(n)),n.toggleAttribute("data-native-ui-snapshot-visible",!!o.opaqueUnderlay),ee(n);let S=n.getBoundingClientRect();n.toggleAttribute("data-native-ui-snapshot-positioned",f.getComputedStyle(n).position==="static");let C=n.shadowRoot??n;for(let U of[...a].reverse()){let O=e.images[U],ae=e.data.parts[U],ce=e.frames[U]??{x:o.opaqueUnderlay?0:ae.x-S.x,y:o.opaqueUnderlay?0:ae.y-S.y,width:ae.width,height:ae.height};e.frames[U]=ce,F.set(e.targets[U],T),O.inert=!0,O.setAttribute("aria-hidden","true"),O.setAttribute("data-native-ui-projection-image",T),O.style.cssText="all:initial!important;position:absolute!important;display:block!important;visibility:visible!important;pointer-events:none!important;image-rendering:pixelated!important;will-change:opacity!important;opacity:0!important;",O.style.setProperty("width",`${ce.width}px`,"important"),O.style.setProperty("height",`${ce.height}px`,"important"),O.style.setProperty("left","0px","important"),O.style.setProperty("top","0px","important"),O.style.setProperty("opacity",o.opaqueUnderlay?"1":"0","important"),O.parentNode!==C&&C.insertBefore(O,null),Z.set(O,{target:n,frame:ce})}}return e.parents=e.scopes.map(n=>n.element.parentNode),z(),!0},X=e=>e.images.map((i,n)=>{let a=i.getBoundingClientRect();return{...e.data.parts[n],x:a.x,y:a.y,width:a.width,height:a.height}}),Ie=()=>{if(s(),A||y==="none"||b)return;let e=L;if(!e||e.viewport!==pe()||!e.sources.every(p)||o.current&&!o.current(e.targets)||e.targets.some(a=>!F.has(a))||u(e).some(a=>!a?.isConnected)||[...h].some(a=>!a.isConnected))return;e.scopes.some((a,T)=>a.element.parentNode!==e.parents[T])&&Q(),z();let i=++de,n=()=>de===i;re=!0,le=!!o.opaqueUnderlay,b=e,oe++,f.clearTimeout(ue),e.sources.forEach(a=>{w.add(a)}),h.forEach(a=>a.setAttribute("data-native-ui-snapshot-source","")),N(e,le),te=f.requestAnimationFrame(()=>{te=0,n()&&(re=!1,o.wake())}),he(k({action:"cover",token:e.data.token,...o.transient?{transient:!0,viewportWidth:f.innerWidth,parts:X(e)}:{}})).then(a=>{if(n()){if(re=!1,a?.shown!==!0){ne(e,!1);return}D||(le=!0,e.sources.forEach(T=>c.add(T)),Q(),z()),f.cancelAnimationFrame(te),te=f.requestAnimationFrame(()=>{te=0,n()&&k({action:"painted",token:e.data.token}).catch(()=>{n()&&ne(e,!1)})}),o.wake()}}).catch(()=>{n()&&ne(e,!1)})},Ze=()=>{if(!(!b||A||D)){if(!b.sources.every(p)||u(b).some(e=>!e)||o.current&&!o.current(b.targets)){ne(b,!1);return}if(!o.blocked()){if(z(),o.transient){let e=b;if(u(e).some(a=>!a?.isConnected)){ne(e,!1);return}let n=X(e);o.opaqueUnderlay||n.every((a,T)=>a.width===e.data.parts[T].width&&a.height===e.data.parts[T].height)?e.data={...e.data,parts:n}:L=void 0,k({action:"restore",token:e.data.token,viewportWidth:f.innerWidth,parts:n}).catch(()=>{})}Te=o.revision?.()??Y?.revision??0,D=!0,b.sources.forEach(e=>w.delete(e)),Pe=f.setTimeout(()=>{D&&ne(b,!1)},250),o.wake()}}},dt=(e,i,n)=>{!D||!b||n===void 0||n<=Te||!o.transient&&e||b.data.parts.every(a=>a.ids.every(T=>i?.includes(T)))&&($e(),ie())},je=(e=!1)=>{ge.forEach(n=>n()),oe++,f.clearTimeout(ue);let i=L;if(L=void 0,(e||A)&&(me=void 0),o.retainPreparedUntilRelease&&!b&&!e&&!A){if(i){let n={};me=n,he(k({action:"release",token:i.data.token})).catch(()=>{}).finally(()=>{if(i.images.forEach(a=>{B(a)}),me===n&&(me=void 0,!(L||b))){for(let a of h)a.getAttribute(g)!==F.get(a)&&(h.delete(a),Oe.delete(a));Ae(),F.clear(),f.dispatchEvent(new Event(d))}})}if(me)return}Le(i),b?ne(b,!1):(Ae(),F.clear(),f.dispatchEvent(new Event(d)))},Qe;try{o.events&&(Qe=await Ye(o.events,(e,i)=>{if(!A){if(e&&(y=e),y==="none"){je();return}e==="web"&&Ie(),e==="native"&&(Ze(),ie()),i&&Me()}}))}catch(e){throw A=!0,je(),await he(Promise.resolve(Ce.remove())).catch(()=>{}),e}return{get owners(){return[...w]},get visibleOwners(){return[...c]},get preparedOwners(){return[...W]},consider:Je,changed:Me,moved:z,get token(){return D?void 0:b?.data.token},begin:Ie,get restoring(){return D},get handoffPending(){return re},retireRestoration:s,end:Ze,updated:dt,invalidate:je,async destroy(){A=!0,je(),x.forEach(e=>e.forEach(i=>i.remove())),x.clear(),await Promise.allSettled([he(Promise.resolve().then(()=>Ce?.remove())),he(Promise.resolve().then(()=>Qe?.remove()))])}}},at=async(t,r,o)=>{let v=await Tt(t,r,o),y=v.consider;return Object.assign(v,{consider:(m,f)=>y(m,f.map(P=>({...P,scope:t})))})};var ct=(t,r)=>{if(t.nodeType!==1||t.namespaceURI!=="http://www.w3.org/1999/xhtml"||!t.ownerDocument||!("style"in t))throw new TypeError("A Web projection scope requires an HTMLElement fallback");if(t.matches("img, input, textarea, select, video, audio, canvas, iframe, embed, object, br, hr, area, base, link, meta, source, track, wbr"))throw new TypeError("A Web projection fallback must be a container element; use the existing fallback container");return Object.freeze({element:t,namespace:r})};var lt=async(t,r,o={addListener:async(v,y)=>globalThis.Capacitor.addListener(t.plugin,v,y)})=>{let v="view",y=t.receiveListeners,m=!1,f=!1,P="native",p="native",M=nt(document),x=()=>P==="native"&&l&&M.isCovered(l)?"web":P,j=!1,B=!1,k=!1,g=!1,d,w,c,W=!1,R=()=>{let s=W;W=!0;try{c?.begin()}finally{W=s}},l,V=0,$,G=()=>{V++,$?.(),$=void 0},ye=async()=>{if(!t.values||!l||m)return;let s=l;G();let u=V,h=()=>!m&&u===V&&l===s&&fe()===s&&s.isConnected;if(s.localName.includes("-")&&!s.matches(":defined")&&Object.values(t.values).some(F=>F.property)){if(await Promise.race([s.ownerDocument.defaultView.customElements.whenDefined(s.localName),new Promise(F=>{$=F})]),!h())return;$=void 0}let N=await r.send({action:"values"}).catch(()=>{});if(h()&&N?.values&&typeof N.values=="object"&&!Array.isArray(N.values))try{tt(s,N.values,t.values)}catch(F){console.warn("[Native UI Engine] Cannot reflect values",F)}},J={},K,ee=0,pe=new Set,re=()=>{},le=new Promise(s=>{re=s}),te=()=>{pe.clear(),re(),le=new Promise(s=>{re=s})},de=()=>{ee++,K=void 0;let s=Ue(l);s?.owner===J&&(s.projected=!1,s.owner=void 0)},L={listen:s=>r.listen(u=>{s(u),!u.active&&B&&(B=!1,Re()),u.precovered&&Je(u.precovered)}),send:s=>{if(!t.placementHandoff)return r.send(s);if(s.action==="visibility"&&!s.visible&&te(),s.action==="visibility"&&s.visible&&pe.size){let z=H,Q=ee,X=l,Ie=le;return Promise.race([Promise.allSettled([...pe]),Ie]).then(()=>m||Ie!==le||z!==H||Q!==ee||X!==l||!X?.isConnected||fe()!==l||x()!=="native"?{}:L.send(s))}let u=Ue(l);if(s.action==="cover"){let z=K===s.token&&u?.owner===J&&u.projected,Q=++ee;return K=s.token,u&&(u.owner=J,u.projected=!!z),r.send(s).then(X=>(Q===ee&&u===Ue(l)&&u?.owner===J&&(u.projected=X?.shown===!0),X)).catch(X=>{throw Q===ee&&u?.owner===J&&(de(),u.invalidate()),X})}let h=s.action==="release"&&s.token===K,N=K&&(s.action==="restore"||h||s.action==="reset"||s.action==="visibility"&&s.visible);N&&ee++;let F=ee,Z=()=>{F!==ee||u?.owner!==J||(de(),u.invalidate())};try{let z=N&&u?.owner===J?{...s,token:"token"in s?s.token:K,placement:u.measure()}:s,Q=r.send(z).then(async X=>(s.action==="release"&&X?.requiresPlacement&&(u&&(!u.owner||u.owner===J)?X=await r.send({...s,placement:u.measure()}):(await r.send({action:"visibility",visible:!1}),X=await r.send(s))),F===ee&&(s.action==="resume"||h||s.action==="reset"||s.action==="visibility")&&de(),X)).catch(X=>{throw Z(),X});return s.action!=="release"||!t.nativeDragHandoff?Q:(pe.add(Q),Q.finally(()=>pe.delete(Q)))}catch(z){return Z(),Promise.reject(z)}}},me=0,b=0,H=0,D,Pe=!1,Te=!1,oe=!1,ue=document.createElement("style"),I=`data-native-ui-session-${t.id.replace(/[^a-zA-Z0-9-]/g,"")}`;ue.textContent=`[${I}="native"], [${I}="native"] *, [${I}="none"], [${I}="none"] * {visibility:hidden!important}`,document.documentElement.append(ue);let fe=()=>{let s=document.querySelectorAll(t.projectionSelector);return s.length===1&&s[0]instanceof HTMLElement?s[0]:void 0},A=()=>{let s=x();l&&l.getAttribute("data-native-ui-destination")!==s&&l.setAttribute("data-native-ui-destination",s),l&&(p==="web"||p==="native"&&k?l.removeAttribute(I):l.setAttribute(I,p))},Fe=()=>{if(!l?.isConnected)return[];let s=l.getBoundingClientRect(),u={x:s.x,y:s.y,width:s.width,height:s.height},h=d&&Ke(l,d,()=>t.id);return[{element:l,scrollElement:d,control:{id:v,...u,...h?{scroll:h}:{}}}]},Y=async()=>{if(m)return;let s=H,u=t.failedFallback==="native"&&x()==="native"&&!!l?.isConnected;await L.send({action:"visibility",visible:u}).catch(()=>{}),!(m||s!==H)&&(u||p==="none"?A():l?.removeAttribute(I))},He=()=>{if(!j||p!=="native"||!l?.isConnected||c?.token||c?.restoring)return;let s=t.failedFallback==="native";L.send({action:"visibility",visible:s}).catch(()=>{}),s?A():l.removeAttribute(I)},ge=()=>{if(m||W)return;if(He(),p==="web"&&c&&!c.token&&!c.restoring){L.send({action:"visibility",visible:!1}).catch(()=>{}),l?.removeAttribute(I);return}if(!c?.restoring||D===c||p!=="native")return;D=c;let s=H,u=c;L.send({action:"resume"}).then(()=>{m||s!==H||u!==c||fe()!==l||(k=!1,u.updated(void 0,[v],++me),A(),q())}).catch(()=>{s!==H||m||(u.invalidate(),Y())}).finally(()=>{D===u&&(D=void 0),ge()})},Ve=async()=>{if(m||Pe)return;if(fe()!==l){H++,j=!1,B=!1,clearTimeout(w),de(),l?.removeAttribute(I),l?.removeAttribute("data-native-ui-destination"),G();let u=c,h=l;c=void 0,l=void 0,Le.disconnect(),Me();try{h&&await L.send({action:"visibility",visible:!1})}finally{await u?.destroy()}if(m)return;l=fe(),k=!1,l&&(Le.observe(l),ye())}if(Me(),!j){if(c?.restoring){ge();return}if(p=x(),!l){await L.send({action:"visibility",visible:!1});return}if(!c){Pe=!0;let u=H;try{let h=await at(ct(l,t.id),L,{wake:ge,captureDelayMs:t.captureDelayMs,retainPreparedUntilRelease:t.nativeDragHandoff,blocked:()=>p!=="native"||j||k&&!c?.token,revision:()=>me,captureRevision:t.captureMode==="view"?()=>b:void 0,transient:!0,opaqueUnderlay:t.captureMode==="view"});if(m||u!==H){await h.destroy();return}c=h}finally{Pe=!1}}if(!m){if(p==="native"&&k){await L.send({action:"visibility",visible:!1}),A();return}if(p==="native"){let u=H;if(await L.send({action:"visibility",visible:!0}),m||u!==H||p!=="native"||j)return;A(),d=[...Ne(l)].find(Z=>{let z=getComputedStyle(Z);return/auto|scroll/.test(z.overflowX+z.overflowY)&&(Z.scrollHeight>Z.clientHeight||Z.scrollWidth>Z.clientWidth)});let h=d&&Ke(l,d,()=>t.id),N=t.nativeDragHandoff&&t.captureMode==="view"&&d?{viewport:d.getBoundingClientRect(),offsetX:d.scrollLeft,offsetY:d.scrollTop,rangeX:Math.max(0,d.scrollWidth-d.clientWidth),rangeY:Math.max(0,d.scrollHeight-d.clientHeight)}:void 0,F=await L.send({action:"track",viewportWidth:innerWidth,...h?{scroll:h}:{},...N?{gesture:N}:{}});if(m||u!==H)return;g=F?.tracked===!0,c.consider(t.captureMode==="view"?b:++me,Fe())}else await L.send({action:"visibility",visible:!1}),A()}}},q=()=>{m||(Te=!0,!(!f||oe)&&(oe=!0,Promise.resolve().then(async()=>{try{for(;Te&&!m;)Te=!1,await Ve()}catch{await Y()}finally{oe=!1,Te&&q()}})))},ke=()=>{c?.invalidate(),q()},Le=new ResizeObserver(ke);window.addEventListener("resize",ke);let se=new Set,ze=new WeakSet,ie=s=>{let u=s.composedPath()[0]??s.target;if(!(m||p!=="native"||!l||ze.has(s)||u!==document&&![...Ne(l)].includes(u))){if(ze.add(s),g&&u===d){c?.changed(u);return}j?t.captureMode==="view"?c?.moved():c?.changed():((D||c?.restoring)&&H++,j=!0,R(),k=t.failedFallback!=="native",c?.token?l.removeAttribute(I):He()),Re()}};function Re(){clearTimeout(w),w=setTimeout(()=>{B||(j=!1,!(m||p!=="native")&&(c?.end(),c?.restoring||q()))},100)}function Je(s){if(m||p!=="native"||!l?.isConnected||!c||(B=!0,c.token))return;(D||c.restoring)&&H++,K=s;let u=Ue(l);if(u&&(u.owner=J,u.projected=!0),j=!0,R(),!c.token){j=!1,Y();return}Re()}let Me=()=>{let s=new Set(l?Ne(l):[]),u=s.size!==se.size||[...s].some(h=>!se.has(h));for(let h of se)s.has(h)||(h.removeEventListener("scroll",ie),h.removeEventListener("slotchange",Ce),se.delete(h));for(let h of s)se.has(h)||(h.addEventListener("scroll",ie,{passive:!0}),h.addEventListener("slotchange",Ce),se.add(h));u&&(g=!1,d=void 0,c?.invalidate(),q())},Ce=()=>{Me(),q()};document.addEventListener("scroll",ie,!0);let Oe=new MutationObserver(s=>{Me(),fe()!==l?q():l&&s.some(u=>u.type==="childList")&&we(x())});Oe.observe(document.documentElement,{childList:!0,attributes:!0,subtree:!0});let we=(s,u=!1)=>{if(m||!u&&s===p)return;j=!1,B=!1,clearTimeout(w),p=s,H++;let h=H;p==="none"?L.send({action:"visibility",visible:!1}).then(()=>{p!=="none"||h!==H||m||(c?.invalidate(!0),A())}).catch(()=>{p!=="none"||h!==H||m||(c?.invalidate(!0),A())}):p==="web"?(R(),c?.token||L.send({action:"visibility",visible:!1}).catch(()=>{}),A()):p==="native"&&(c?.end(),c?.restoring||q())},Ae=M.subscribe(()=>queueMicrotask(()=>we(x()))),ne,$e=async()=>{if(!m){m=!0,te(),G(),de(),H++,Ae(),Oe.disconnect(),Le.disconnect(),window.removeEventListener("resize",ke),document.removeEventListener("scroll",ie,!0);for(let s of se)s.removeEventListener("scroll",ie),s.removeEventListener("slotchange",Ce);se.clear(),clearTimeout(w),l?.removeAttribute(I),l?.removeAttribute("data-native-ui-destination"),ue.remove(),await Promise.allSettled([Promise.resolve(ne?.remove()),c?.destroy()])}};try{let s=H;ne=await Ye({addListener:(h,N)=>o.addListener(h,N),update:y?.update,projection:y?.projection,accepts:h=>!y?.match||Object.entries(y?.match).every(([N,F])=>typeof h=="object"&&h!==null&&h[N]===F)},(h,N)=>{m||(h&&(h==="native"&&(k=!1),P=h,L.send({action:"destination",destination:h}).catch(()=>{}),we(x(),!0)),N&&(ye(),b++,c?.changed(),p==="native"&&q()))});let u=await L.send({action:"connect"});return H===s&&["native","web","none"].includes(u?.destination)&&(P=u.destination),p=x(),f=!0,q(),{destroy:$e,show:()=>{k=!1,P="native",we(x(),!0)},hide:()=>{P=p="none",H++,te(),j=!1,B=!1,clearTimeout(w),c?.invalidate(!0),A()}}}catch(s){throw await $e(),s}};var be=new Map,Ee=new Map,Be=new Map,Lt=Array.from(crypto.getRandomValues(new Uint32Array(4)),t=>t.toString(16)).join("-"),qe=new Map,Mt=(t,r,o)=>qe.get(t)?.get(r)?.(o),jt=0,St=(t,r)=>new Promise((o,v)=>{let y=`${t}:${Lt}:${++jt}`,m=setTimeout(()=>{Ee.delete(y),v(new Error("Native UI session timed out"))},5e3);Ee.set(y,{resolve:o,reject:v,timer:m});let f=JSON.stringify({key:y,request:r}),P=globalThis,p=P.webkit?.messageHandlers?.[t]??P[t]??P.nativeUIEngine;if(!p){clearTimeout(m),Ee.delete(y),v(new Error("Native UI session unavailable"));return}try{p.postMessage(f)}catch(M){clearTimeout(m),Ee.delete(y),v(M)}}),xt=(t,r,o,v)=>{if(r===null){Be.get(t)?.(o);return}let y=Ee.get(r);!y||!r.startsWith(`${t}:`)||(Ee.delete(r),clearTimeout(y.timer),v?y.reject(new Error(v)):y.resolve(o))},Ht=t=>{be.get(t)?.show()},kt=t=>(be.get(t)?.hide(),!0),Rt=async t=>{let r=be.get(t);be.delete(t),qe.delete(t),Be.delete(t);for(let[o,v]of Ee)o.startsWith(`${t}:`)&&(Ee.delete(o),clearTimeout(v.timer),v.reject(new Error("Native UI session closed")));await r?.destroy()},Ct=async t=>{if(be.has(t.id))return;let r,o=!1,v,y={show:()=>{v="native",r?.show()},hide:()=>{v="none",r?.hide()},destroy:async()=>{o=!0,await r?.destroy()}};be.set(t.id,y);try{if(document.readyState==="loading"&&await new Promise(f=>document.addEventListener("DOMContentLoaded",()=>f(),{once:!0})),o)return;let m=new Map;t.runtime==="cordova"&&qe.set(t.id,m),r=await lt(t,{send:f=>St(t.id,f),listen:async f=>(Be.set(t.id,f),{remove:()=>{Be.get(t.id)===f&&Be.delete(t.id)}})},t.runtime==="cordova"?{addListener:async(f,P)=>(m.set(f,P),{remove:()=>{m.delete(f)}})}:void 0),v==="none"?r.hide():v==="native"&&r.show(),o&&await r.destroy()}catch(m){throw be.get(t.id)===y&&(be.delete(t.id),qe.delete(t.id)),m}};return ht(Ot);})();
|
|
22
|
+
`;var Lt=({control:t},i=!1)=>[t.id,t.kind,t.placement,i?0:t.x,i?0:t.y,t.width,t.height,t.dark,t.rtl],Mt=async(t,i,s)=>{let v=s.captureDelayMs??50;if(!Number.isFinite(v)||v<0||v>2147483647)throw new RangeError("captureDelayMs must be a finite, nonnegative timer interval");let y="native",m=t.element.ownerDocument,f=m.defaultView,P=Array.from(f.crypto.getRandomValues(new Uint32Array(4)),e=>e.toString(16)).join("-"),p=e=>e.isConnected&&e.ownerDocument===m,M=e=>!!e?.isConnected&&e.ownerDocument===m,S=new Map,j=new Set,B=e=>{j.delete(e),e.style.setProperty("display","none","important"),e.removeAttribute("data-native-ui-projection-image"),e.removeAttribute("src"),He()},H=i.send.bind(i),g="data-native-ui-snapshot",d=`${t.namespace}:sources-change`,w=new Set,c=new Set,W=new Set,k=new WeakMap,l=0,V=e=>JSON.stringify(e.map(o=>{k.has(o.scope)||k.set(o.scope,++l);let n=s.transient&&!s.opaqueUnderlay?o.scope.element.getBoundingClientRect():void 0,a=n?{...o,control:{...o.control,x:o.control.x-n.x,y:o.control.y-n.y}}:o;return[k.get(o.scope),Lt(a,!!s.opaqueUnderlay)]})),$=new Map,J=e=>{let o=e.getRootNode();return o.nodeType===11&&"host"in o?o:m},ge=e=>{if($.has(e))return;let o=m.createElement("style");o.setAttribute("data-native-ui-snapshot-base",""),o.textContent=rt+(e.nodeType===11?st:""),(e.nodeType===11?e:e.head).append(o),$.set(e,o)},_=e=>{let o=[...e.getAnimations({subtree:!0}),...[...G.get(e)??[]].flatMap(n=>n.shadowRoot?.getAnimations()??[])];for(let n of o)"transitionProperty"in n&&n.transitionProperty==="visibility"&&n.cancel()},G=new Map,Q=e=>{let o=G.get(e)??new Set;G.set(e,o);let n=e.hasAttribute("data-native-ui-snapshot-source")||e.hasAttribute("data-native-ui-snapshot-prepared"),a=T=>{if(!T.hasAttribute("data-native-ui-projection-node")){if(T.shadowRoot){o.add(T),ge(T.shadowRoot);for(let C of T.shadowRoot.children)a(C)}for(let C of T.children)a(C)}};a(e);for(let T of o)T.toggleAttribute("data-native-ui-snapshot-content",n);_(e)},pe=()=>`${f.innerWidth}:${f.innerHeight}:${f.devicePixelRatio}`,ie=!1,ce=!1,ee=0,le=0,L,me,E,x=!1,D=!1,Te=0,Le=0,ne=0,de=0,I=0,ue=-1,A=!1,Ne=!1,Y,He=()=>{let e=new Set(Y?.candidates.map(n=>n.scope.element));for(let[n,a]of S){let T=!A&&n.isConnected&&e.has(n);if(T&&(E||D||ie))continue;let C=T?2*Math.max(1,L?.scopes.filter(R=>R.element===n).length??0):0,O=Math.max(0,C-a.filter(R=>j.has(R)).length),U=a.filter(R=>j.has(R)||O-- >0?!0:(R.remove(),!1));U.length?S.set(n,U):S.delete(n)}let o=new Set([...Y?.candidates.map(n=>n.scope.element.getRootNode())??[],...E?.scopes.map(n=>n.element.getRootNode())??[],...L?.scopes.map(n=>n.element.getRootNode())??[],...[...j].map(n=>n.getRootNode()),...[...G.values()].flatMap(n=>[...n].map(a=>a.shadowRoot))]);for(let[n,a]of $)n.nodeType===11&&!o.has(n)&&(a.remove(),$.delete(n))},we=new Set,Ve=(e,o,n)=>{let a=()=>{we.delete(a)&&(H({action:e,token:o}).catch(()=>{}),e==="restored"&&He())};we.add(a),n&&!A?f.requestAnimationFrame(()=>f.requestAnimationFrame(a)):a()},q=new Set,ke=()=>{q.forEach(e=>W.delete(e)),q.clear()},Me=(e,o=!1)=>{!e||e===L||e===E||(e.images.forEach(n=>{B(n)}),Ve("release",e.data.token,o))},re=e=>e.filter(o=>{if(!M(o.scope.element)||![o.element,...o.sources??[]].every(p))return!1;if(o.control.scroll){let n=o.element.getBoundingClientRect(),a=o.control.scroll.clip;if(n.right<=a.x||n.bottom<=a.y||n.left>=a.x+a.width||n.top>=a.y+a.height)return!1}return s.eligible?.(o)??!0}),ze=async()=>{if(de=0,A||y!=="native"||Ne||x||E||s.blocked()||!Y||L?.revision===Y.revision&&ue===I)return;let{revision:e,candidates:o}=Y,n=ne,a=I,T=pe(),C=re(o);if(!C.length)return;Ne=!0;let O,U=!1,R=[];try{let se=!1,ae=H({action:"prepare",revision:s.captureRevision?.()??e,viewportWidth:f.innerWidth,ids:C.map(b=>b.control.id)});ae.then(b=>{se&&b.token&&H({action:"release",token:b.token}).catch(()=>{})}).catch(()=>{});try{O=await ye(ae)}finally{se=!0}if(!O.token||!O.parts?.length)return;let We=new Set(C.map(b=>b.control.id));if(O.parts.some(b=>!b.url.startsWith("file:")&&!/^\/__native_ui_engine__\/nativeUI[a-fA-F0-9]+\/[a-fA-F0-9-]+-[0-9]+\.png$/.test(b.url)||!b.ids.length||b.ids.some(fe=>!We.has(fe))||![b.x,b.y,b.width,b.height].every(Number.isFinite)||b.width<=0||b.height<=0)||new Set(O.parts.flatMap(b=>b.ids)).size!==We.size||O.parts.some(b=>new Set(b.ids.map(fe=>C.find(Xe=>Xe.control.id===fe).scope)).size!==1))return;let ve=O.parts.map(b=>C.find(fe=>b.ids.includes(fe.control.id)));if(await ye(Promise.all(O.parts.map(async(b,fe)=>{let Xe=ve[fe].scope.element,Ie=S.get(Xe);Ie||(Ie=[],S.set(Xe,Ie));let he=Ie.find(ft=>!j.has(ft));return he||(he=m.createElement("img"),he.setAttribute("data-native-ui-projection-node",""),Ie.push(he)),j.add(he),R.push(he),he.src=it(b.url),await he.decode(),he}))),A||y!=="native"||x||E||s.blocked()||ne!==n||pe()!==T||Y?.revision!==e||C.some(b=>!M(b.scope.element)||![b.element,...b.sources??[]].every(p)))return;let ut=L,et={data:O,images:R,sources:Array.from(new Set(C.flatMap(b=>[b.element,...b.sources??[]]))),targets:ve.map(b=>b.element),scopes:ve.map(b=>b.scope),parents:ve.map(b=>b.scope.element.parentNode),frames:[],viewport:T,revision:e,layout:V(C)};try{if(!Z(et))throw new Error("Projection destination is unavailable")}catch(b){Ae();try{Z(),L?.sources.forEach(fe=>{W.add(fe),q.add(fe)})}catch{te()}throw b}L=et,ke(),L.sources.forEach(b=>{W.add(b),q.add(b)}),s.opaqueUnderlay&&H({action:"prepared",token:O.token}).catch(()=>{}),f.dispatchEvent(new Event(d)),ue=a,U=!0,Me(ut)}catch{}finally{U||R.forEach(se=>{B(se)}),O?.token&&!U&&H({action:"release",token:O.token}).catch(()=>{}),Ne=!1,Y&&(Y.revision!==e||I!==a)&&oe()}},oe=()=>{f.clearTimeout(de),!A&&y==="native"&&!E&&!x&&!s.blocked()&&(de=f.setTimeout(()=>{ze()},v))},Re,Je=(e,o)=>{if(o.some(a=>a.scope.element.ownerDocument!==m||[a.element,...a.sources??[]].some(T=>T.ownerDocument!==m)))throw new TypeError("All projection sources and fallback scopes must share one Document");if(s.blocked())return;!E&&L&&L.layout!==V(re(o))&&Se();let n=V(o);Re!==n&&(Re=n,I++,ne++),Y?.revision!==e&&ne++,Y={revision:e,candidates:o},He(),(L?.revision!==e||ue!==I)&&oe()},je=e=>{!E&&L&&e&&Y?.candidates.some(o=>o.scrollElement===e&&L.sources.includes(o.element))&&Se(),E&&z(),I++,ne++,oe()},Ce=await Ye(i.listen(({active:e})=>{x=e,ne++,f.clearTimeout(de),e||oe()})),Oe=new Set,be=e=>{G.get(e)?.forEach(o=>o.removeAttribute("data-native-ui-snapshot-content")),Oe.delete(e)&&e.removeAttribute("data-native-ui-snapshot-prepared"),e.removeAttribute("data-native-ui-snapshot-visible"),e.removeAttribute(g),e.removeAttribute("data-native-ui-snapshot-positioned"),e.removeAttribute("data-native-ui-snapshot-source"),_(e),G.delete(e)},Ae=()=>{le++,f.cancelAnimationFrame(ee);for(let e of K.keys())e.style.setProperty("opacity","0","important");K.clear(),ee=0,ie=!1,ce=!1,ke(),E?.sources.forEach(e=>{w.delete(e),c.delete(e)}),h.forEach(be),h.clear(),$.forEach((e,o)=>{(A||o.nodeType===11&&!o.host.isConnected)&&(e.remove(),$.delete(o))})},te=(e=E,o=D)=>{if(E!==e)return;let n=new Set([E,L]);Ae(),E=void 0,L=void 0,D=!1,f.clearTimeout(Te),n.forEach(a=>Me(a,o)),s.wake()},Fe=()=>{if(!E)return;if(L!==E){te();return}let e=E;le++,f.cancelAnimationFrame(ee),ee=0,ie=ce=!1,e.sources.forEach(o=>{w.delete(o),c.delete(o)}),h.forEach(o=>o.removeAttribute("data-native-ui-snapshot-source")),N(e,!!s.opaqueUnderlay),E=void 0,D=!1,f.clearTimeout(Te),Ve("restored",e.data.token,!0),e.sources.forEach(o=>{W.add(o),q.add(o)}),s.wake()},r=()=>{D&&Fe(),we.forEach(e=>e())},u=e=>e.scopes.map(o=>M(o.element)?o.element:void 0),h=new Set,N=(e,o)=>{for(let n of h)n.toggleAttribute("data-native-ui-snapshot-visible",o),Q(n);e.images.forEach(n=>n.style.setProperty("opacity",o?"1":"0","important"))},F=new Map,K=new Map,z=()=>{let e=[];for(let[o,n]of K){let{target:a,frame:T}=n;if(!a.isConnected){o.remove();continue}let C=a.shadowRoot??a;o.parentNode!==C&&C.insertBefore(o,null);let O=a.getBoundingClientRect(),U=o.getBoundingClientRect(),R=parseFloat(o.style.width)||T.width,se=parseFloat(o.style.height)||T.height,ae=U.width/R||1,We=U.height/se||1,ve=n.scale??(n.scale={x:ae,y:We});e.push({element:o,left:(parseFloat(o.style.left)||0)+(O.x+T.x*ae/ve.x-U.x)/ae,top:(parseFloat(o.style.top)||0)+(O.y+T.y*We/ve.y-U.y)/We,width:T.width/ve.x,height:T.height/ve.y})}for(let{element:o,...n}of e)for(let[a,T]of Object.entries(n)){let C=`${T}px`;o.style.getPropertyValue(a)!==C&&o.style.setProperty(a,C,"important")}},Z=(e=E??L)=>{if(!e||D)return!1;if(!e.sources.every(p)||u(e).some(n=>!n))return Se(),!1;let o=u(e);if(E){if(o.some(a=>!a?.isConnected||!$.has(J(a))))return te(E,!1),!1;let n=new Set;for(let[a,T]of e.targets.entries()){let C=F.get(T),O=o[a];!C||!O?.isConnected||(O.setAttribute(g,C),O.setAttribute("data-native-ui-snapshot-source",""),n.add(O))}for(let a of h)n.has(a)||be(a);return h.clear(),n.forEach(a=>h.add(a)),N(e,ce),!0}S.forEach(n=>n.forEach(a=>{e.images.includes(a)||(a.style.setProperty("display","none","important"),a.removeAttribute("data-native-ui-projection-image"))})),F.clear(),K.clear(),h.forEach(be),h.clear();for(let n of new Set(o)){if(!n)continue;h.add(n),ge(J(n));let a=o.flatMap((U,R)=>U===n?[R]:[]),T=`${P}-${a[0]}`;n.setAttribute(g,T),n!==e.targets[a[0]]&&(n.setAttribute("data-native-ui-snapshot-prepared",""),Oe.add(n)),n.toggleAttribute("data-native-ui-snapshot-visible",!!s.opaqueUnderlay),Q(n);let C=n.getBoundingClientRect();n.toggleAttribute("data-native-ui-snapshot-positioned",f.getComputedStyle(n).position==="static");let O=n.shadowRoot??n;for(let U of[...a].reverse()){let R=e.images[U],se=e.data.parts[U],ae=e.frames[U]??{x:s.opaqueUnderlay?0:se.x-C.x,y:s.opaqueUnderlay?0:se.y-C.y,width:se.width,height:se.height};e.frames[U]=ae,F.set(e.targets[U],T),R.inert=!0,R.setAttribute("aria-hidden","true"),R.setAttribute("data-native-ui-projection-image",T),R.style.cssText="all:initial!important;position:absolute!important;display:block!important;visibility:visible!important;pointer-events:none!important;image-rendering:pixelated!important;will-change:opacity!important;opacity:0!important;",R.style.setProperty("width",`${ae.width}px`,"important"),R.style.setProperty("height",`${ae.height}px`,"important"),R.style.setProperty("left","0px","important"),R.style.setProperty("top","0px","important"),R.style.setProperty("opacity",s.opaqueUnderlay?"1":"0","important"),R.parentNode!==O&&O.insertBefore(R,null),K.set(R,{target:n,frame:ae})}}return e.parents=e.scopes.map(n=>n.element.parentNode),z(),!0},X=e=>e.images.map((o,n)=>{let a=o.getBoundingClientRect();return{...e.data.parts[n],x:a.x,y:a.y,width:a.width,height:a.height}}),$e=()=>{if(r(),A||y==="none"||E)return;let e=L;if(!e||e.viewport!==pe()||!e.sources.every(p)||s.current&&!s.current(e.targets)||e.targets.some(a=>!F.has(a))||u(e).some(a=>!a?.isConnected)||[...h].some(a=>!a.isConnected))return;e.scopes.some((a,T)=>a.element.parentNode!==e.parents[T])&&Z(),z();let o=++le,n=()=>le===o;ie=!0,ce=!!s.opaqueUnderlay,E=e,ne++,f.clearTimeout(de),e.sources.forEach(a=>{w.add(a)}),h.forEach(a=>a.setAttribute("data-native-ui-snapshot-source","")),N(e,ce),ee=f.requestAnimationFrame(()=>{ee=0,n()&&(ie=!1,s.wake())}),ye(H({action:"cover",token:e.data.token,...s.transient?{transient:!0,viewportWidth:f.innerWidth,parts:X(e)}:{}})).then(a=>{if(n()){if(ie=!1,a?.shown!==!0){te(e,!1);return}D||(ce=!0,e.sources.forEach(T=>c.add(T)),Z(),z()),f.cancelAnimationFrame(ee),ee=f.requestAnimationFrame(()=>{ee=0,n()&&H({action:"painted",token:e.data.token}).catch(()=>{n()&&te(e,!1)})}),s.wake()}}).catch(()=>{n()&&te(e,!1)})},Ze=()=>{if(!(!E||A||D)){if(!E.sources.every(p)||u(E).some(e=>!e)||s.current&&!s.current(E.targets)){te(E,!1);return}if(!s.blocked()){if(z(),s.transient){let e=E;if(u(e).some(a=>!a?.isConnected)){te(e,!1);return}let n=X(e);s.opaqueUnderlay||n.every((a,T)=>a.width===e.data.parts[T].width&&a.height===e.data.parts[T].height)?e.data={...e.data,parts:n}:L=void 0,H({action:"restore",token:e.data.token,viewportWidth:f.innerWidth,parts:n}).catch(()=>{})}Le=s.revision?.()??Y?.revision??0,D=!0,E.sources.forEach(e=>w.delete(e)),Te=f.setTimeout(()=>{D&&te(E,!1)},250),s.wake()}}},dt=(e,o,n)=>{!D||!E||n===void 0||n<=Le||!s.transient&&e||E.data.parts.every(a=>a.ids.every(T=>o?.includes(T)))&&(Fe(),oe())},Se=(e=!1)=>{we.forEach(n=>n()),ne++,f.clearTimeout(de);let o=L;if(L=void 0,(e||A)&&(me=void 0),s.retainPreparedUntilRelease&&!E&&!e&&!A){if(o){let n={};me=n,ye(H({action:"release",token:o.data.token})).catch(()=>{}).finally(()=>{if(o.images.forEach(a=>{B(a)}),me===n&&(me=void 0,!(L||E))){for(let a of h)a.getAttribute(g)!==F.get(a)&&(h.delete(a),Oe.delete(a));Ae(),F.clear(),f.dispatchEvent(new Event(d))}})}if(me)return}Me(o),E?te(E,!1):(Ae(),F.clear(),f.dispatchEvent(new Event(d)))},Qe;try{s.events&&(Qe=await qe(s.events,(e,o)=>{if(!A){if(e&&(y=e),y==="none"){Se();return}e==="web"&&$e(),e==="native"&&(Ze(),oe()),o&&je()}}))}catch(e){throw A=!0,Se(),await ye(Promise.resolve(Ce.remove())).catch(()=>{}),e}return{get owners(){return[...w]},get visibleOwners(){return[...c]},get preparedOwners(){return[...W]},consider:Je,changed:je,moved:z,get token(){return D?void 0:E?.data.token},begin:$e,get restoring(){return D},get handoffPending(){return ie},retireRestoration:r,end:Ze,updated:dt,invalidate:Se,async destroy(){A=!0,Se(),S.forEach(e=>e.forEach(o=>o.remove())),S.clear(),await Promise.allSettled([ye(Promise.resolve().then(()=>Ce?.remove())),ye(Promise.resolve().then(()=>Qe?.remove()))])}}},at=async(t,i,s)=>{let v=await Mt(t,i,s),y=v.consider;return Object.assign(v,{consider:(m,f)=>y(m,f.map(P=>({...P,scope:t})))})};var ct=(t,i)=>{if(t.nodeType!==1||t.namespaceURI!=="http://www.w3.org/1999/xhtml"||!t.ownerDocument||!("style"in t))throw new TypeError("A Web projection scope requires an HTMLElement fallback");if(t.matches("img, input, textarea, select, video, audio, canvas, iframe, embed, object, br, hr, area, base, link, meta, source, track, wbr"))throw new TypeError("A Web projection fallback must be a container element; use the existing fallback container");return Object.freeze({element:t,namespace:i})};var lt=async(t,i,s={addListener:async(v,y)=>globalThis.Capacitor.addListener(t.plugin,v,y)})=>{let v="view",y=t.receiveListeners,m=!1,f=!1,P="native",p="native",M=nt(document),S=()=>P==="native"&&l&&M.isCovered(l)?"web":P,j=!1,B=!1,H=!1,g=!1,d,w,c,W=!1,k=()=>{let r=W;W=!0;try{c?.begin()}finally{W=r}},l,V=0,$,J=()=>{V++,$?.(),$=void 0},ge=async()=>{if(!t.values||!l||m)return;let r=l;J();let u=V,h=()=>!m&&u===V&&l===r&&ue()===r&&r.isConnected;if(r.localName.includes("-")&&!r.matches(":defined")&&Object.values(t.values).some(F=>F.property)){if(await Promise.race([r.ownerDocument.defaultView.customElements.whenDefined(r.localName),new Promise(F=>{$=F})]),!h())return;$=void 0}let N=await i.send({action:"values"}).catch(()=>{});if(h()&&N?.values&&typeof N.values=="object"&&!Array.isArray(N.values))try{tt(r,N.values,t.values)}catch(F){console.warn("[Native UI Engine] Cannot reflect values",F)}},_={},G,Q=0,pe=new Set,ie=()=>{},ce=new Promise(r=>{ie=r}),ee=()=>{pe.clear(),ie(),ce=new Promise(r=>{ie=r})},le=()=>{Q++,G=void 0;let r=Ue(l);r?.owner===_&&(r.projected=!1,r.owner=void 0)},L={listen:r=>i.listen(u=>{r(u),!u.active&&B&&(B=!1,Re()),u.precovered&&Je(u.precovered)}),send:r=>{if(!t.placementHandoff)return i.send(r);if(r.action==="visibility"&&!r.visible&&ee(),r.action==="visibility"&&r.visible&&pe.size){let z=x,Z=Q,X=l,$e=ce;return Promise.race([Promise.allSettled([...pe]),$e]).then(()=>m||$e!==ce||z!==x||Z!==Q||X!==l||!X?.isConnected||ue()!==l||S()!=="native"?{}:L.send(r))}let u=Ue(l);if(r.action==="cover"){let z=G===r.token&&u?.owner===_&&u.projected,Z=++Q;return G=r.token,u&&(u.owner=_,u.projected=!!z),i.send(r).then(X=>(Z===Q&&u===Ue(l)&&u?.owner===_&&(u.projected=X?.shown===!0),X)).catch(X=>{throw Z===Q&&u?.owner===_&&(le(),u.invalidate()),X})}let h=r.action==="release"&&r.token===G,N=G&&(r.action==="restore"||h||r.action==="reset"||r.action==="visibility"&&r.visible);N&&Q++;let F=Q,K=()=>{F!==Q||u?.owner!==_||(le(),u.invalidate())};try{let z=N&&u?.owner===_?{...r,token:"token"in r?r.token:G,placement:u.measure()}:r,Z=i.send(z).then(async X=>(r.action==="release"&&X?.requiresPlacement&&(u&&(!u.owner||u.owner===_)?X=await i.send({...r,placement:u.measure()}):(await i.send({action:"visibility",visible:!1}),X=await i.send(r))),F===Q&&(r.action==="resume"||h||r.action==="reset"||r.action==="visibility")&&le(),X)).catch(X=>{throw K(),X});return r.action!=="release"||!t.nativeDragHandoff?Z:(pe.add(Z),Z.finally(()=>pe.delete(Z)))}catch(z){return K(),Promise.reject(z)}}},me=0,E=0,x=0,D,Te=!1,Le=!1,ne=!1,de=document.createElement("style"),I=`data-native-ui-session-${t.id.replace(/[^a-zA-Z0-9-]/g,"")}`;de.textContent=`[${I}="native"], [${I}="native"] *, [${I}="none"], [${I}="none"] * {visibility:hidden!important}`,document.documentElement.append(de);let ue=()=>{let r=document.querySelectorAll(t.projectionSelector);return r.length===1&&r[0]instanceof HTMLElement?r[0]:void 0},A=()=>{let r=S();l&&l.getAttribute("data-native-ui-destination")!==r&&l.setAttribute("data-native-ui-destination",r),l&&(p==="web"||p==="native"&&H?l.removeAttribute(I):l.setAttribute(I,p))},Ne=()=>{if(!l?.isConnected)return[];let r=l.getBoundingClientRect(),u={x:r.x,y:r.y,width:r.width,height:r.height},h=d&&Ke(l,d,()=>t.id);return[{element:l,scrollElement:d,control:{id:v,...u,...h?{scroll:h}:{}}}]},Y=async()=>{if(m)return;let r=x,u=t.failedFallback==="native"&&S()==="native"&&!!l?.isConnected;await L.send({action:"visibility",visible:u}).catch(()=>{}),!(m||r!==x)&&(u||p==="none"?A():l?.removeAttribute(I))},He=()=>{if(!j||p!=="native"||!l?.isConnected||c?.token||c?.restoring)return;let r=t.failedFallback==="native";L.send({action:"visibility",visible:r}).catch(()=>{}),r?A():l.removeAttribute(I)},we=()=>{if(m||W)return;if(He(),p==="web"&&c&&!c.token&&!c.restoring){L.send({action:"visibility",visible:!1}).catch(()=>{}),l?.removeAttribute(I);return}if(!c?.restoring||D===c||p!=="native")return;D=c;let r=x,u=c;L.send({action:"resume"}).then(()=>{m||r!==x||u!==c||ue()!==l||(H=!1,u.updated(void 0,[v],++me),A(),q())}).catch(()=>{r!==x||m||(u.invalidate(),Y())}).finally(()=>{D===u&&(D=void 0),we()})},Ve=async()=>{if(m||Te)return;if(ue()!==l){x++,j=!1,B=!1,clearTimeout(w),le(),l?.removeAttribute(I),l?.removeAttribute("data-native-ui-destination"),J();let u=c,h=l;c=void 0,l=void 0,Me.disconnect(),je();try{h&&await L.send({action:"visibility",visible:!1})}finally{await u?.destroy()}if(m)return;l=ue(),H=!1,l&&(Me.observe(l),ge())}if(je(),!j){if(c?.restoring){we();return}if(p=S(),!l){await L.send({action:"visibility",visible:!1});return}if(!c){Te=!0;let u=x;try{let h=await at(ct(l,t.id),L,{wake:we,captureDelayMs:t.captureDelayMs,retainPreparedUntilRelease:t.nativeDragHandoff,blocked:()=>p!=="native"||j||H&&!c?.token,revision:()=>me,captureRevision:t.captureMode==="view"?()=>E:void 0,transient:!0,opaqueUnderlay:t.captureMode==="view"});if(m||u!==x){await h.destroy();return}c=h}finally{Te=!1}}if(!m){if(p==="native"&&H){await L.send({action:"visibility",visible:!1}),A();return}if(p==="native"){let u=x;if(await L.send({action:"visibility",visible:!0}),m||u!==x||p!=="native"||j)return;A(),d=[...De(l)].find(K=>{let z=getComputedStyle(K);return/auto|scroll/.test(z.overflowX+z.overflowY)&&(K.scrollHeight>K.clientHeight||K.scrollWidth>K.clientWidth)});let h=d&&Ke(l,d,()=>t.id),N=t.nativeDragHandoff&&t.captureMode==="view"&&d?{viewport:d.getBoundingClientRect(),offsetX:d.scrollLeft,offsetY:d.scrollTop,rangeX:Math.max(0,d.scrollWidth-d.clientWidth),rangeY:Math.max(0,d.scrollHeight-d.clientHeight)}:void 0,F=await L.send({action:"track",viewportWidth:innerWidth,...h?{scroll:h}:{},...N?{gesture:N}:{}});if(m||u!==x)return;g=F?.tracked===!0,c.consider(t.captureMode==="view"?E:++me,Ne())}else await L.send({action:"visibility",visible:!1}),A()}}},q=()=>{m||(Le=!0,!(!f||ne)&&(ne=!0,Promise.resolve().then(async()=>{try{for(;Le&&!m;)Le=!1,await Ve()}catch{await Y()}finally{ne=!1,Le&&q()}})))},ke=()=>{c?.invalidate(),q()},Me=new ResizeObserver(ke);window.addEventListener("resize",ke);let re=new Set,ze=new WeakSet,oe=r=>{let u=r.composedPath()[0]??r.target;if(!(m||p!=="native"||!l||ze.has(r)||u!==document&&![...De(l)].includes(u))){if(ze.add(r),g&&u===d){c?.changed(u);return}j?t.captureMode==="view"?c?.moved():c?.changed():((D||c?.restoring)&&x++,j=!0,k(),H=t.failedFallback!=="native",c?.token?l.removeAttribute(I):He()),Re()}};function Re(){clearTimeout(w),w=setTimeout(()=>{B||(j=!1,!(m||p!=="native")&&(c?.end(),c?.restoring||q()))},100)}function Je(r){if(m||p!=="native"||!l?.isConnected||!c||(B=!0,c.token))return;(D||c.restoring)&&x++,G=r;let u=Ue(l);if(u&&(u.owner=_,u.projected=!0),j=!0,k(),!c.token){j=!1,Y();return}Re()}let je=()=>{let r=new Set(l?De(l):[]),u=r.size!==re.size||[...r].some(h=>!re.has(h));for(let h of re)r.has(h)||(h.removeEventListener("scroll",oe),h.removeEventListener("slotchange",Ce),re.delete(h));for(let h of r)re.has(h)||(h.addEventListener("scroll",oe,{passive:!0}),h.addEventListener("slotchange",Ce),re.add(h));u&&(g=!1,d=void 0,c?.invalidate(),q())},Ce=()=>{je(),q()};document.addEventListener("scroll",oe,!0);let Oe=new MutationObserver(r=>{je(),ue()!==l?q():l&&r.some(u=>u.type==="childList")&&be(S())});Oe.observe(document.documentElement,{childList:!0,attributes:!0,subtree:!0});let be=(r,u=!1)=>{if(m||!u&&r===p)return;j=!1,B=!1,clearTimeout(w),p=r,x++;let h=x;p==="none"?L.send({action:"visibility",visible:!1}).then(()=>{p!=="none"||h!==x||m||(c?.invalidate(!0),A())}).catch(()=>{p!=="none"||h!==x||m||(c?.invalidate(!0),A())}):p==="web"?(k(),c?.token||L.send({action:"visibility",visible:!1}).catch(()=>{}),A()):p==="native"&&(c?.end(),c?.restoring||q())},Ae=M.subscribe(()=>queueMicrotask(()=>be(S()))),te,Fe=async()=>{if(!m){m=!0,ee(),J(),le(),x++,Ae(),Oe.disconnect(),Me.disconnect(),window.removeEventListener("resize",ke),document.removeEventListener("scroll",oe,!0);for(let r of re)r.removeEventListener("scroll",oe),r.removeEventListener("slotchange",Ce);re.clear(),clearTimeout(w),l?.removeAttribute(I),l?.removeAttribute("data-native-ui-destination"),de.remove(),await Promise.allSettled([Promise.resolve(te?.remove()),c?.destroy()])}};try{let r=x;te=await qe({addListener:(h,N)=>s.addListener(h,N),update:y?.update,projection:y?.projection,accepts:h=>!y?.match||Object.entries(y?.match).every(([N,F])=>typeof h=="object"&&h!==null&&h[N]===F)},(h,N)=>{m||(h&&(h==="native"&&(H=!1),P=h,L.send({action:"destination",destination:h}).catch(()=>{}),be(S(),!0)),N&&(ge(),E++,c?.changed(),p==="native"&&q()))});let u=await L.send({action:"connect"});return x===r&&["native","web","none"].includes(u?.destination)&&(P=u.destination),p=S(),f=!0,q(),{destroy:Fe,show:()=>{H=!1,P="native",be(S(),!0)},hide:()=>{P=p="none",x++,ee(),j=!1,B=!1,clearTimeout(w),c?.invalidate(!0),A()}}}catch(r){throw await Fe(),r}};var Ee=new Map,Pe=new Map,Be=new Map,jt=Array.from(crypto.getRandomValues(new Uint32Array(4)),t=>t.toString(16)).join("-"),_e=new Map,St=(t,i,s)=>_e.get(t)?.get(i)?.(s),xt=0,Ht=(t,i)=>new Promise((s,v)=>{let y=`${t}:${jt}:${++xt}`,m=setTimeout(()=>{Pe.delete(y),v(new Error("Native UI session timed out"))},5e3);Pe.set(y,{resolve:s,reject:v,timer:m});let f=JSON.stringify({key:y,request:i}),P=globalThis,p=P.webkit?.messageHandlers?.[t]??P.nativeUIEngine;if(!p){clearTimeout(m),Pe.delete(y),v(new Error("Native UI session unavailable"));return}try{p.postMessage(f)}catch(M){clearTimeout(m),Pe.delete(y),v(M)}}),kt=(t,i,s,v)=>{if(i===null){Be.get(t)?.(s);return}let y=Pe.get(i);!y||!i.startsWith(`${t}:`)||(Pe.delete(i),clearTimeout(y.timer),v?y.reject(new Error(v)):y.resolve(s))},Rt=t=>{Ee.get(t)?.show()},Ct=t=>(Ee.get(t)?.hide(),!0),Ot=async t=>{let i=Ee.get(t);Ee.delete(t),_e.delete(t),Be.delete(t);for(let[s,v]of Pe)s.startsWith(`${t}:`)&&(Pe.delete(s),clearTimeout(v.timer),v.reject(new Error("Native UI session closed")));await i?.destroy()},At=async t=>{if(Ee.has(t.id))return;let i,s=!1,v,y={show:()=>{v="native",i?.show()},hide:()=>{v="none",i?.hide()},destroy:async()=>{s=!0,await i?.destroy()}};Ee.set(t.id,y);try{if(document.readyState==="loading"&&await new Promise(f=>document.addEventListener("DOMContentLoaded",()=>f(),{once:!0})),s)return;let m=new Map;t.runtime==="cordova"&&_e.set(t.id,m),i=await lt(t,{send:f=>Ht(t.id,f),listen:async f=>(Be.set(t.id,f),{remove:()=>{Be.get(t.id)===f&&Be.delete(t.id)}})},t.runtime==="cordova"?{addListener:async(f,P)=>(m.set(f,P),{remove:()=>{m.delete(f)}})}:void 0),v==="none"?i.hide():v==="native"&&i.show(),s&&await i.destroy()}catch(m){throw Ee.get(t.id)===y&&(Ee.delete(t.id),_e.delete(t.id)),m}};return gt(Wt);})();
|
package/package.json
CHANGED