@webview-native-ui/engine 0.0.5 → 0.0.7
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 +19 -12
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/native/session.d.ts +5 -0
- package/dist/native/session.js +83 -14
- package/dist/native/updates.d.ts +16 -0
- package/dist/native/updates.js +108 -0
- package/dist/native/values.d.ts +5 -0
- package/dist/native/values.js +27 -0
- package/dist/projection/surface.d.ts +35 -0
- package/dist/projection/surface.js +81 -0
- package/dist/projection/surfaces.d.ts +20 -0
- package/dist/projection/surfaces.js +116 -0
- package/dist/projection/web.js +22 -12
- package/dist/types.d.ts +4 -0
- package/docs/README.md +70 -0
- package/docs/advanced/README.md +20 -0
- package/docs/advanced/android-placement.md +48 -0
- package/docs/advanced/native-handoff.md +89 -0
- package/docs/advanced/renderer.md +148 -0
- package/docs/advanced/update-queue.md +58 -0
- package/docs/advanced/web-projection.md +88 -0
- package/docs/assets/ios-native-capture-comparison.png +0 -0
- package/docs/concepts.md +97 -0
- package/docs/configuration/README.md +29 -0
- package/docs/configuration/capture.md +27 -0
- package/docs/configuration/events.md +35 -0
- package/docs/configuration/ionic-overlays.md +65 -0
- package/docs/configuration/values.md +125 -0
- package/docs/cordova.md +1 -1
- package/docs/{capacitor-plugin.md → getting-started/capacitor.md} +45 -47
- package/docs/{cordova-plugin.md → getting-started/cordova.md} +32 -15
- package/docs/getting-started/initialization.md +79 -0
- package/docs/maintenance.md +14 -2
- package/docs/{projection-containers.md → reference/containers.md} +6 -2
- package/docs/reference/platforms.md +137 -0
- package/docs/reference/projection.md +134 -0
- package/docs/reference/state.md +39 -0
- package/ios/Sources/WebViewNativeUIEngine/ClippedView.swift +12 -12
- package/ios/Sources/WebViewNativeUIEngine/CoveredSnapshots.swift +70 -9
- package/ios/Sources/WebViewNativeUIEngine/Frame.swift +10 -10
- package/ios/Sources/WebViewNativeUIEngine/NativeUIProjection.swift +92 -44
- package/ios/Sources/WebViewNativeUIEngine/Resources/native-ui-engine.js +3 -3
- package/ios/Sources/WebViewNativeUIEngine/ScrollBindings.swift +3 -0
- package/ios/Sources/WebViewNativeUIEngine/ScrollTracker.swift +10 -8
- package/package.json +10 -3
- package/docs/projection.md +0 -364
|
@@ -7,6 +7,16 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
|
|
|
7
7
|
public enum Runtime: String { case capacitor, cordova }
|
|
8
8
|
public enum FailedFallback: String { case web, native }
|
|
9
9
|
|
|
10
|
+
public struct ValueBinding {
|
|
11
|
+
public let property: String?
|
|
12
|
+
public init(property: String? = nil) { self.property = property }
|
|
13
|
+
fileprivate var configuration: [String: Any] {
|
|
14
|
+
var value: [String: Any] = [:]
|
|
15
|
+
if let property { value["property"] = property }
|
|
16
|
+
return value
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
10
20
|
public struct ReceiveListeners {
|
|
11
21
|
public struct Projection {
|
|
12
22
|
public let native: [String]
|
|
@@ -30,11 +40,23 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
|
|
|
30
40
|
private let views: () -> [String: UIView]
|
|
31
41
|
private let snapshots: NativeUICoveredSnapshots
|
|
32
42
|
private let scrolling = NativeUIScrollBindings()
|
|
33
|
-
private
|
|
43
|
+
private struct ScrollMask {
|
|
44
|
+
weak var view: UIView?
|
|
45
|
+
let layer: CAShapeLayer
|
|
46
|
+
}
|
|
47
|
+
private var masks: [String: ScrollMask] = [:]
|
|
48
|
+
private func resetScrolling() {
|
|
49
|
+
scrolling.reset()
|
|
50
|
+
for mask in masks.values where mask.view?.layer.mask === mask.layer {
|
|
51
|
+
mask.view?.layer.mask = nil
|
|
52
|
+
}
|
|
53
|
+
masks.removeAll()
|
|
54
|
+
}
|
|
34
55
|
private let id = "nativeUI" + UUID().uuidString.replacingOccurrences(of: "-", with: "")
|
|
35
56
|
private let origins: Set<String>
|
|
36
57
|
private let allowedOriginsJSON: String
|
|
37
58
|
private let canCapture: () -> Bool
|
|
59
|
+
private let readValues: (() -> [String: Any])?
|
|
38
60
|
private let runtime: Runtime
|
|
39
61
|
private let receiveListeners: ReceiveListeners
|
|
40
62
|
private let notificationLock = NSLock()
|
|
@@ -56,34 +78,44 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
|
|
|
56
78
|
private var captured: [String: [String: UIView]] = [:]
|
|
57
79
|
|
|
58
80
|
public convenience init(webView: WKWebView?, plugin: String, projectionSelector: String,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
81
|
+
receiveListeners: ReceiveListeners = .init(),
|
|
82
|
+
allowedOrigins: Set<String> = ["capacitor://localhost", "app://localhost", "https://localhost", "http://localhost"],
|
|
83
|
+
failedFallback: FailedFallback = .web, runtime: Runtime = .capacitor,
|
|
84
|
+
captureDelayMs: Double = 50,
|
|
85
|
+
values: [String: ValueBinding] = [:], readValues: (() -> [String: Any])? = nil,
|
|
86
|
+
canCapture: @escaping () -> Bool = { true }, view: @escaping () -> UIView?) throws {
|
|
64
87
|
try self.init(webView: webView, plugin: plugin, projectionSelector: projectionSelector,
|
|
65
88
|
receiveListeners: receiveListeners, allowedOrigins: allowedOrigins, failedFallback: failedFallback, runtime: runtime,
|
|
66
|
-
captureDelayMs: captureDelayMs,
|
|
89
|
+
captureDelayMs: captureDelayMs, values: values, readValues: readValues, canCapture: canCapture,
|
|
90
|
+
snapshots: NativeUICoveredSnapshots(), view: view)
|
|
67
91
|
}
|
|
68
92
|
init(webView: WKWebView?, plugin: String, projectionSelector: String,
|
|
69
93
|
receiveListeners: ReceiveListeners = .init(),
|
|
70
94
|
allowedOrigins: Set<String> = ["capacitor://localhost", "app://localhost", "https://localhost", "http://localhost"],
|
|
71
95
|
failedFallback: FailedFallback = .web, runtime: Runtime = .capacitor,
|
|
72
96
|
captureDelayMs: Double = 50,
|
|
97
|
+
values: [String: ValueBinding] = [:], readValues: (() -> [String: Any])? = nil,
|
|
73
98
|
canCapture: @escaping () -> Bool = { true }, snapshots: NativeUICoveredSnapshots,
|
|
74
99
|
view: @escaping () -> UIView?) throws {
|
|
100
|
+
// JSONSerialization produces valid UTF-8.
|
|
101
|
+
// swiftlint:disable:next force_unwrapping
|
|
75
102
|
self.allowedOriginsJSON = String(data: try JSONSerialization.data(withJSONObject: Array(allowedOrigins)), encoding: .utf8)!
|
|
76
103
|
self.runtime = runtime
|
|
77
104
|
self.snapshots = snapshots
|
|
78
105
|
self.receiveListeners = receiveListeners
|
|
106
|
+
self.readValues = readValues
|
|
79
107
|
guard let webView else { throw ProjectionError.missingWebView }
|
|
80
108
|
self.webView = webView; self.views = { view().map { ["view": $0] } ?? [:] }; self.origins = allowedOrigins; self.canCapture = canCapture
|
|
81
109
|
super.init()
|
|
82
110
|
precondition(Thread.isMainThread)
|
|
83
111
|
guard captureDelayMs.isFinite, captureDelayMs >= 0, captureDelayMs <= 2147483647,
|
|
84
112
|
!projectionSelector.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { throw ProjectionError.invalidConfiguration }
|
|
85
|
-
|
|
86
|
-
"captureDelayMs": captureDelayMs, "receiveListeners": receiveListeners.configuration,
|
|
113
|
+
var config: [String: Any] = ["id": id, "plugin": plugin, "projectionSelector": projectionSelector,
|
|
114
|
+
"captureDelayMs": captureDelayMs, "receiveListeners": receiveListeners.configuration,
|
|
115
|
+
"failedFallback": failedFallback.rawValue, "runtime": runtime.rawValue]
|
|
116
|
+
if readValues != nil { config["values"] = values.mapValues { $0.configuration } }
|
|
117
|
+
// JSONSerialization produces valid UTF-8.
|
|
118
|
+
// swiftlint:disable:next force_unwrapping
|
|
87
119
|
let json = String(data: try JSONSerialization.data(withJSONObject: config), encoding: .utf8)!
|
|
88
120
|
let allowed = allowedOriginsJSON
|
|
89
121
|
let runtime = try Self.runtime()
|
|
@@ -99,8 +131,8 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
|
|
|
99
131
|
public func receive(_ eventName: String, data: [String: Any]? = nil) {
|
|
100
132
|
guard receiveListeners.match.allSatisfy({ key, expected in
|
|
101
133
|
guard let actual = data?[key] else { return false }
|
|
102
|
-
if let
|
|
103
|
-
return CFGetTypeID(
|
|
134
|
+
if let actualNumber = actual as? NSNumber, let expectedNumber = expected as? NSNumber {
|
|
135
|
+
return CFGetTypeID(actualNumber) == CFGetTypeID(expectedNumber) && actualNumber == expectedNumber
|
|
104
136
|
}
|
|
105
137
|
return (actual as? String).map { $0 == expected as? String } ?? false
|
|
106
138
|
}) else { return }
|
|
@@ -145,13 +177,17 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
|
|
|
145
177
|
let key = message["key"] as? String, key.hasPrefix(id + ":"),
|
|
146
178
|
let request = message["request"] as? [String: Any] else { return }
|
|
147
179
|
let page = key.split(separator: ":").dropFirst().first.map(String.init)
|
|
148
|
-
if documentID != page { snapshots.reset();
|
|
180
|
+
if documentID != page { snapshots.reset(); resetScrolling(); captured.removeAll(); anchors.removeAll(); documentID = page }
|
|
149
181
|
let complete: ([String: Any]) -> Void = { [weak self] value in
|
|
150
182
|
guard let self, !self.closed, self.documentID == page else { return }
|
|
151
183
|
self.reply(key, value)
|
|
152
184
|
}
|
|
153
185
|
let token = request["token"] as? String ?? ""
|
|
154
186
|
switch request["action"] as? String {
|
|
187
|
+
case "values":
|
|
188
|
+
let values = readValues?() ?? [:]
|
|
189
|
+
guard JSONSerialization.isValidJSONObject(values) else { self.reply(key, [:], error: "Native values must be JSON values"); return }
|
|
190
|
+
complete(["values": values])
|
|
155
191
|
case "connect":
|
|
156
192
|
if !connected { destination = (views().values.contains(where: { !$0.isHidden }) ? "native" : "none"); connected = true }
|
|
157
193
|
complete(["destination": recordedDestination ?? destination])
|
|
@@ -159,9 +195,7 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
|
|
|
159
195
|
if let next = request["destination"] as? String, ["native", "web", "none"].contains(next) { destination = next; connected = true }
|
|
160
196
|
complete([:])
|
|
161
197
|
case "track":
|
|
162
|
-
|
|
163
|
-
for (id, mask) in masks { if views()[id]?.layer.mask === mask { views()[id]?.layer.mask = nil } }
|
|
164
|
-
masks.removeAll()
|
|
198
|
+
resetScrolling()
|
|
165
199
|
guard let raw = request["scroll"] as? [String: Any], let width = request["viewportWidth"] as? Double, width.isFinite, width > 0,
|
|
166
200
|
let data = try? JSONSerialization.data(withJSONObject: raw),
|
|
167
201
|
let placement = try? JSONDecoder().decode(NativeUIScrollPlacement.self, from: data), placement.isValid else {
|
|
@@ -172,11 +206,19 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
|
|
|
172
206
|
guard !current.isEmpty, current.values.allSatisfy({ $0.layer.mask == nil }) else { complete(["tracked": false]); return }
|
|
173
207
|
let nodes = current.map { id, view -> NativeUIScrollNode in
|
|
174
208
|
let frame = view.convert(view.bounds, to: webView)
|
|
175
|
-
return NativeUIScrollNode(
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
209
|
+
return NativeUIScrollNode(
|
|
210
|
+
id: id,
|
|
211
|
+
scroll: NativeUIScrollPlacement(
|
|
212
|
+
id: placement.id, offsetX: placement.offsetX, offsetY: placement.offsetY,
|
|
213
|
+
viewport: placement.viewport, clip: placement.clip,
|
|
214
|
+
contentWidth: placement.contentWidth, contentHeight: placement.contentHeight,
|
|
215
|
+
frame: NativeUIFrame(
|
|
216
|
+
x: frame.minX/scale-placement.viewport.x+placement.offsetX,
|
|
217
|
+
y: frame.minY/scale-placement.viewport.y+placement.offsetY,
|
|
218
|
+
width: frame.width/scale, height: frame.height/scale
|
|
219
|
+
)
|
|
220
|
+
)
|
|
221
|
+
)
|
|
180
222
|
}
|
|
181
223
|
let rejected = scrolling.replace(nodes, in: webView, scale: scale) { [weak self, weak webView] id, frame, clip in
|
|
182
224
|
guard let self, let webView, self.visible, !self.snapshots.hidesNativeControls,
|
|
@@ -185,15 +227,16 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
|
|
|
185
227
|
let from = parent.convert(CGPoint(x: old.midX, y: old.midY), from: webView)
|
|
186
228
|
let to = parent.convert(CGPoint(x: frame.midX, y: frame.midY), from: webView)
|
|
187
229
|
view.transform.tx += to.x-from.x; view.transform.ty += to.y-from.y
|
|
188
|
-
let mask = self.masks[id] ?? CAShapeLayer()
|
|
189
|
-
self.masks[id] = mask
|
|
230
|
+
let mask = self.masks[id]?.layer ?? CAShapeLayer()
|
|
231
|
+
self.masks[id] = ScrollMask(view: view, layer: mask)
|
|
190
232
|
mask.frame = view.bounds
|
|
191
233
|
mask.path = UIBezierPath(rect: clip.isNull ? .zero : view.convert(clip, from: webView).intersection(view.bounds)).cgPath
|
|
192
234
|
view.layer.mask = mask
|
|
193
235
|
}
|
|
194
236
|
complete(["tracked": rejected.isEmpty])
|
|
195
237
|
case "prepare":
|
|
196
|
-
guard visible, canCapture(), let ids = request["ids"] as? [String],
|
|
238
|
+
guard visible, canCapture(), let ids = request["ids"] as? [String],
|
|
239
|
+
let width = request["viewportWidth"] as? Double, width.isFinite, width > 0,
|
|
197
240
|
let window = webView.window else { complete([:]); return }
|
|
198
241
|
let selected = views().filter { ids.contains($0.key) }
|
|
199
242
|
guard selected.count == ids.count else { complete([:]); return }
|
|
@@ -212,7 +255,11 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
|
|
|
212
255
|
guard let ids = part["ids"] as? [String], let x = part["x"] as? CGFloat, let y = part["y"] as? CGFloat,
|
|
213
256
|
let w = part["width"] as? CGFloat, let h = part["height"] as? CGFloat else { continue }
|
|
214
257
|
let image = CGRect(x: x*scale, y: y*scale, width: w*scale, height: h*scale)
|
|
215
|
-
for id in ids {
|
|
258
|
+
for id in ids {
|
|
259
|
+
if let view = selected[id] {
|
|
260
|
+
entries[id] = Anchor(native: view.convert(view.bounds, to: webView), image: image)
|
|
261
|
+
}
|
|
262
|
+
}
|
|
216
263
|
}
|
|
217
264
|
self.anchors[token] = entries
|
|
218
265
|
}
|
|
@@ -221,35 +268,33 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
|
|
|
221
268
|
case "cover":
|
|
222
269
|
let selected = captured[token] ?? [:], current = views()
|
|
223
270
|
let valid = visible && canCapture() && !selected.isEmpty && selected.allSatisfy { current[$0.key] === $0.value }
|
|
271
|
+
let frames = request["parts"] == nil ? nil : snapshots.projectionFrames(request, in: webView)
|
|
272
|
+
guard request["parts"] == nil || frames != nil else { complete(["shown": false]); return }
|
|
224
273
|
restoreAccepted = true
|
|
225
|
-
complete(["shown": valid && snapshots.cover(
|
|
274
|
+
complete(["shown": valid && snapshots.cover(
|
|
275
|
+
token, in: webView,
|
|
276
|
+
views: Array(Dictionary(grouping: selected.values, by: { ObjectIdentifier($0) }).values.compactMap { $0.first }),
|
|
277
|
+
transient: true, frames: frames
|
|
278
|
+
)])
|
|
226
279
|
case "restore":
|
|
227
280
|
restoreAccepted = false
|
|
228
|
-
guard let
|
|
229
|
-
let parts = request["parts"] as? [[String: Any]] else { complete(["shown": false]); return }
|
|
230
|
-
var frames: [String: CGRect] = [:]
|
|
231
|
-
let scale = webView.bounds.width / width
|
|
232
|
-
for part in parts {
|
|
233
|
-
guard let ids = part["ids"] as? [String], let x = part["x"] as? Double, let y = part["y"] as? Double,
|
|
234
|
-
let w = part["width"] as? Double, let h = part["height"] as? Double,
|
|
235
|
-
[x,y,w,h].allSatisfy({ $0.isFinite }), w > 0, h > 0 else { complete(["shown": false]); return }
|
|
236
|
-
for id in ids { frames[id] = CGRect(x: x*scale, y: y*scale, width: w*scale, height: h*scale) }
|
|
237
|
-
}
|
|
238
|
-
guard Set(frames.keys) == snapshots.identifiers(for: token), !frames.isEmpty else { complete(["shown": false]); return }
|
|
281
|
+
guard let frames = snapshots.projectionFrames(request, in: webView) else { complete(["shown": false]); return }
|
|
239
282
|
let current = views()
|
|
240
283
|
// Preserve renderer-owned constraints. Translation follows the corresponding DOM's movement.
|
|
241
284
|
for (id, frame) in frames {
|
|
242
|
-
guard let view = current[id], captured[token]?[id] === view, let anchor = anchors[token]?[id]
|
|
285
|
+
guard let view = current[id], captured[token]?[id] === view, let anchor = anchors[token]?[id]
|
|
286
|
+
else { complete(["shown": false]); return }
|
|
243
287
|
let old = view.convert(view.bounds, to: webView)
|
|
244
288
|
guard abs(old.width-anchor.native.width) < 0.1, abs(old.height-anchor.native.height) < 0.1,
|
|
245
|
-
abs(frame.width-anchor.image.width) < 0.1, abs(frame.height-anchor.image.height) < 0.1
|
|
289
|
+
abs(frame.width-anchor.image.width) < 0.1, abs(frame.height-anchor.image.height) < 0.1
|
|
290
|
+
else { complete(["shown": false]); return }
|
|
246
291
|
}
|
|
247
292
|
for (id, frame) in frames {
|
|
248
293
|
guard let view = current[id], let parent = view.superview, let anchor = anchors[token]?[id] else { continue }
|
|
249
294
|
let old = view.convert(view.bounds, to: webView)
|
|
250
295
|
let from = parent.convert(CGPoint(x: old.midX, y: old.midY), from: webView)
|
|
251
296
|
let to = parent.convert(CGPoint(x: anchor.native.midX+frame.minX-anchor.image.minX,
|
|
252
|
-
|
|
297
|
+
y: anchor.native.midY+frame.minY-anchor.image.minY), from: webView)
|
|
253
298
|
view.transform.tx += to.x-from.x; view.transform.ty += to.y-from.y
|
|
254
299
|
}
|
|
255
300
|
restoreAccepted = snapshots.restore(in: webView, token: token, frames: frames)
|
|
@@ -286,8 +331,8 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
|
|
|
286
331
|
guard let data = try? JSONSerialization.data(withJSONObject: values), let json = String(data: data, encoding: .utf8) else { return }
|
|
287
332
|
evaluate("globalThis.WebViewNativeUIEngineRuntime?.receive(...\(json))")
|
|
288
333
|
}
|
|
289
|
-
/// Call with the plugin's teardown. Does not destroy the renderer's views or DOM.
|
|
290
334
|
deinit { destroy() }
|
|
335
|
+
/// Call with the plugin's teardown. Does not destroy the renderer's views or DOM.
|
|
291
336
|
public func destroy() {
|
|
292
337
|
guard !closed else { return }
|
|
293
338
|
closed = true
|
|
@@ -298,11 +343,14 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
|
|
|
298
343
|
controller.removeAllUserScripts()
|
|
299
344
|
remaining.forEach { controller.addUserScript($0) }
|
|
300
345
|
}
|
|
301
|
-
|
|
302
|
-
|
|
346
|
+
// A successful hide notification can precede its Web acknowledgement and teardown.
|
|
347
|
+
let keepHidden = (recordedDestination ?? destination) == "none"
|
|
348
|
+
let visibility = keepHidden
|
|
349
|
+
? (Array(views().values) + hiddenByProjection + captured.values.flatMap { $0.values }).map { ($0, $0.isHidden) }
|
|
350
|
+
: []
|
|
351
|
+
snapshots.reset(); resetScrolling(); captured.removeAll(); anchors.removeAll()
|
|
352
|
+
if keepHidden { visibility.forEach { $0.0.isHidden = $0.1 } } else { hiddenByProjection.forEach { $0.isHidden = false } }
|
|
303
353
|
hiddenByProjection.removeAll()
|
|
304
|
-
for (id, mask) in masks { if views()[id]?.layer.mask === mask { views()[id]?.layer.mask = nil } }
|
|
305
|
-
masks.removeAll()
|
|
306
354
|
}
|
|
307
355
|
}
|
|
308
356
|
private final class WeakProjectionHandler: NSObject, WKScriptMessageHandler {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var WebViewNativeUIEngineRuntime=(()=>{var
|
|
1
|
+
"use strict";var WebViewNativeUIEngineRuntime=(()=>{var Je=Object.defineProperty;var ut=Object.getOwnPropertyDescriptor;var ft=Object.getOwnPropertyNames;var pt=Object.prototype.hasOwnProperty;var mt=(t,r)=>{for(var o in r)Je(t,o,{get:r[o],enumerable:!0})},vt=(t,r,o,v)=>{if(r&&typeof r=="object"||typeof r=="function")for(let h of ft(r))!pt.call(t,h)&&h!==o&&Je(t,h,{get:()=>r[h],enumerable:!(v=ut(r,h))||v.enumerable});return t};var ht=t=>vt(Je({},"__esModule",{value:!0}),t);var Ot={};mt(Ot,{hide:()=>kt,notify:()=>Mt,receive:()=>xt,show:()=>Ht,start:()=>Ct,stop:()=>Rt});var tt=(t,r,o)=>{for(let[v,h]of Object.entries(r)){if(!/^[a-z][a-z0-9-]*$/.test(v))throw new TypeError("Native value keys must be lowercase attribute names");let f=(Object.hasOwn(o,v)?o[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(h);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]=h)}else{let p=`data-native-ui-value-${v}`,L=typeof h=="string"?h:P;t.getAttribute(p)!==L&&t.setAttribute(p,L)}}};var yt=Symbol.for("webview-native-ui-engine.projection-placement");var $e=t=>t?.[yt];var gt=(t,r)=>{if(t.matches("ion-toast, ion-menu"))return!1;let o=t;if(o.showBackdrop===!1)return!1;if(!t.matches("ion-modal"))return!0;let v=r??o.initialBreakpoint;return v===void 0||v>(o.backdropBreakpoint??0)},wt=Symbol.for("@webview-native-ui/engine/overlays/v1"),bt=t=>{let r=new Set,o=new Set,v=new Set,h=new WeakMap,m=new WeakSet,f=new Map,P=[],p={},L=new Map,x,M=g=>{for(let l of[...v])try{l(g)}catch(w){console.error("Native UI overlay listener failed",w)}},B=(g,l,w)=>{l==="willPresent"||l==="didPresent"?(m.delete(g),r.add(g)):l==="didDismiss"&&(m.add(g),r.delete(g),o.delete(g),h.delete(g));let c=w?.detail?.breakpoint;typeof c=="number"&&c>0&&h.set(g,c),M({element:g,phase:l,event:w})},H=(g=!1)=>{let l=!1;for(let w of r)(!w.isConnected||w.ownerDocument!==t||!P.some(({selector:c})=>w.matches(c)))&&(r.delete(w),o.delete(w),l=!0);for(let w of t.querySelectorAll(P.map(({selector:c})=>c).join(",")))!r.has(w)&&!m.has(w)&&(g||!w.matches("ion-popover"))&&(w.presented||w.classList.contains("show-menu"))&&(r.add(w),l=!0);l&&M({phase:"change"})};return{get active(){return r},subscribe(g){return v.add(g),()=>{v.delete(g)}},setNative(g,l){o.has(g)!==l&&(l?o.add(g):o.delete(g),M({element:g,phase:"change"}))},isExcluded(g){return!!p.exclude&&g.matches(p.exclude)},isNative(g){return o.has(g)},get stack(){let g=[...r].filter(w=>w.isConnected&&w.ownerDocument===t),l=w=>{let c=Number.parseFloat(t.defaultView.getComputedStyle(w).zIndex);return Number.isFinite(c)?c:w.overlayIndex??0};return g.sort((w,c)=>l(w)-l(c)),g},isCovered(g){let l=this.stack,w=l.reduce((c,N,k)=>N.contains(g)?k:c,-1);return l.some((c,N)=>{if(o.has(c)||p.exclude&&c.matches(p.exclude))return!1;let k=p.covers?.(c,g);return k!==void 0?k:N>w&&!c.contains(g)&&(c.matches("ion-menu")||gt(c,h.get(c)))})},enable(g,l){let w={...p,...l},c=[...g,...w.additional??[]];w.exclude&&t.querySelector(w.exclude);let N=new Map;for(let d of c){t.querySelector(d.selector);for(let[V,F]of Object.entries(d.events)){let G=N.get(F);if(G&&G.phase!==V)throw new TypeError(`Overlay event "${F}" has conflicting phases`);N.set(F,{phase:V,selector:G?`${G.selector}, ${d.selector}`:d.selector})}}p=w,P=c,L=N;for(let d of L.keys()){if(f.has(d))continue;let V=F=>{let G=L.get(d),pe=F.composedPath().find(Y=>Y instanceof t.defaultView.HTMLElement&&Y.matches(G.selector));pe&&B(pe,G.phase,F)};t.addEventListener(d,V,!0),f.set(d,()=>t.removeEventListener(d,V,!0))}for(let[d,V]of f)L.has(d)||(V(),f.delete(d));let k=!x;x||(x=new MutationObserver(()=>H()),x.observe(t.documentElement,{childList:!0,subtree:!0}),t.addEventListener("nativeUIOverlayAdopted",d=>{let V=d.detail;V?.ownerDocument===t&&B(V,"willPresent",d)})),H(k),(k||l)&&M({phase:"change"})}}},nt=t=>{let r=t;return r[wt]??=bt(t)};function*Ae(t){let r=t;for(;r;){let o=r.getRootNode();r=r.assignedSlot??r.parentElement??(o instanceof ShadowRoot?o.host:null),r&&(yield r)}}var Et=({x:t,y:r,width:o,height:v})=>({x:t,y:r,width:o,height:v}),ot=t=>{let r=t.getBoundingClientRect(),o=getComputedStyle(t),v=parseFloat(o.borderLeftWidth)||0,h=parseFloat(o.borderTopWidth)||0;return{x:r.left+v,y:r.top+h,width:r.width-v-(parseFloat(o.borderRightWidth)||0),height:r.height-h-(parseFloat(o.borderBottomWidth)||0)}},_e=(t,r,o)=>{let v=[t,...Ae(t)],h=v.indexOf(r);if(h<=0||r===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,L=m.innerHeight;for(let[H,g]of v.entries()){let l=getComputedStyle(g);if(l.transform!=="none"&&!new DOMMatrixReadOnly(l.transform).isIdentity||l.zoom&&l.zoom!=="normal"&&Number(l.zoom)!==1||[l.translate,l.rotate,l.scale,l.perspective].some(k=>k&&k!=="none")||l.writingMode&&l.writingMode!=="horizontal-tb"||H<h&&/^(fixed|sticky)$/.test(l.position))return;if(H===0)continue;if(l.scrollbarGutter&&l.scrollbarGutter!=="auto")return;let w=/^(auto|scroll|hidden|clip)$/.test(l.overflowX),c=/^(auto|scroll|hidden|clip)$/.test(l.overflowY);if(H<h&&(w||c))return;let N=g===t.ownerDocument.scrollingElement;if(H>h&&((w||N)&&g.scrollWidth>g.clientWidth||(c||N)&&g.scrollHeight>g.clientHeight)||(w||c)&&[l.borderTopLeftRadius,l.borderTopRightRadius,l.borderBottomLeftRadius,l.borderBottomRightRadius].some(k=>parseFloat(k)>0)||l.clipPath&&l.clipPath!=="none"||l.maskImage&&l.maskImage!=="none")return;if(H>=h){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),L=Math.min(L,k.y+k.height))}}let x=getComputedStyle(r);if(!/^(auto|scroll)$/.test(x.overflowX)&&!/^(auto|scroll)$/.test(x.overflowY))return;let M=ot(r);if(p<=f||L<=P||!M.width||!M.height)return;let B=Et(t.getBoundingClientRect());return{id:o(r),offsetX:r.scrollLeft,offsetY:r.scrollTop,viewport:M,clip:{x:f,y:P,width:p-f,height:L-P},contentWidth:r.scrollWidth,contentHeight:r.scrollHeight,frame:{...B,x:B.x-M.x+r.scrollLeft,y:B.y-M.y+r.scrollTop}}};var it=t=>{let r=globalThis;if(r.Capacitor?.convertFileSrc)return r.Capacitor.convertFileSrc(t);if(!t.startsWith("file:"))return t;if(r.WkWebView?.convertFilePath)return r.WkWebView.convertFilePath(t);throw new Error("Native UI file URL requires a host resource handler")};var fe=t=>new Promise((r,o)=>{let v=setTimeout(()=>o(new Error("Native UI bridge timed out")),5e3);t.then(r,o).finally(()=>clearTimeout(v))}),ze=async t=>{try{return await fe(t)}catch(r){throw t.then(o=>o.remove()).catch(()=>{}),r}};var qe=async(t,r)=>{let o=new Map;for(let P of t.update??[])o.set(P,{updated:!0});for(let P of["native","web","none"])for(let p of t.projection?.[P]??[]){let L=o.get(p)??{updated:!1};if(L.destination&&L.destination!==P)throw new TypeError(`Projection event "${p}" has conflicting destinations`);o.set(p,{...L,destination:P})}let v=!1,h=[],m=async()=>{v=!0;let p=(await Promise.allSettled(h.splice(0).map(L=>Promise.resolve().then(()=>L.remove())))).find(L=>L.status==="rejected");if(p?.status==="rejected")throw p.reason},f=[...o].map(async([P,p])=>{let L=await ze(Promise.resolve().then(()=>t.addListener(P,x=>{!v&&(!t.accepts||t.accepts(x))&&r(p.destination,p.updated)})));v?await L.remove():h.push(L)});try{return await Promise.all(f),{remove:m}}catch(P){throw await m().catch(()=>{}),P}};var je=":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
|
${je}, ${je} *, ${je}::part(native) { visibility: hidden !important; }
|
|
4
4
|
${je}::before, ${je}::after,
|
|
@@ -8,7 +8,7 @@ ${je} *::before, ${je} *::after {
|
|
|
8
8
|
}
|
|
9
9
|
[data-native-ui-snapshot-visible] { opacity:1!important;overflow:visible!important; }
|
|
10
10
|
[data-native-ui-snapshot-visible][data-native-ui-snapshot-positioned] { position:relative!important; }
|
|
11
|
-
`,
|
|
11
|
+
`,st=`
|
|
12
12
|
@layer native-ui-projection {
|
|
13
13
|
:host([data-native-ui-snapshot-content]),
|
|
14
14
|
:host([data-native-ui-snapshot-content])::before,
|
|
@@ -19,4 +19,4 @@ ${je} *::before, ${je} *::after {
|
|
|
19
19
|
visibility: hidden !important;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
-
`;var bt=(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])),Et=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 h="native",d=t.element.ownerDocument,p=d.defaultView,T=Array.from(p.crypto.getRandomValues(new Uint32Array(4)),e=>e.toString(16)).join("-"),f=e=>e.isConnected&&e.ownerDocument===d,M=e=>!!e?.isConnected&&e.ownerDocument===d,C=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"),le()},S=r.send.bind(r),y="data-native-ui-snapshot",l=`${t.namespace}:sources-change`,g=new Set,c=new Set,D=new Set,H=new WeakMap,m=0,W=e=>JSON.stringify(e.map(i=>(H.has(i.scope)||H.set(i.scope,++m),[H.get(i.scope),bt([i],!!o.opaqueUnderlay)]))),A=new Map,N=e=>{let i=e.getRootNode();return i.nodeType===11&&"host"in i?i:d},oe=e=>{if(A.has(e))return;let i=d.createElement("style");i.setAttribute("data-native-ui-snapshot-base",""),i.textContent=ot+(e.nodeType===11?it:""),(e.nodeType===11?e:e.head).append(i),A.set(e,i)},F=e=>{let i=[...e.getAnimations({subtree:!0}),...[...se.get(e)??[]].flatMap(n=>n.shadowRoot?.getAnimations()??[])];for(let n of i)"transitionProperty"in n&&n.transitionProperty==="visibility"&&n.cancel()},se=new Map,Se=e=>{let i=se.get(e)??new Set;se.set(e,i);let n=e.hasAttribute("data-native-ui-snapshot-source")||e.hasAttribute("data-native-ui-snapshot-prepared"),s=w=>{if(!w.hasAttribute("data-native-ui-projection-node")){if(w.shadowRoot){i.add(w),oe(w.shadowRoot);for(let L of w.shadowRoot.children)s(L)}for(let L of w.children)s(L)}};s(e);for(let w of i)w.toggleAttribute("data-native-ui-snapshot-content",n);F(e)},O=()=>`${p.innerWidth}:${p.innerHeight}:${p.devicePixelRatio}`,Z=!1,ae=!1,J=0,me=0,R,U,E,X=!1,Y=!1,we=0,We=0,ee=0,ve=0,z=0,be=-1,V=!1,te=!1,q,le=()=>{let e=new Set(q?.candidates.map(n=>n.scope.element));for(let[n,s]of C){let w=!V&&n.isConnected&&e.has(n);if(w&&(E||Y||Z))continue;let L=w?2*Math.max(1,R?.scopes.filter(k=>k.element===n).length??0):0,x=Math.max(0,L-s.filter(k=>j.has(k)).length),I=s.filter(k=>j.has(k)||x-- >0?!0:(k.remove(),!1));I.length?C.set(n,I):C.delete(n)}let i=new Set([...q?.candidates.map(n=>n.scope.element.getRootNode())??[],...E?.scopes.map(n=>n.element.getRootNode())??[],...R?.scopes.map(n=>n.element.getRootNode())??[],...[...j].map(n=>n.getRootNode()),...[...se.values()].flatMap(n=>[...n].map(s=>s.shadowRoot))]);for(let[n,s]of A)n.nodeType===11&&!i.has(n)&&(s.remove(),A.delete(n))},he=new Set,Ie=(e,i,n)=>{let s=()=>{he.delete(s)&&(S({action:e,token:i}).catch(()=>{}),e==="restored"&&le())};he.add(s),n&&!V?p.requestAnimationFrame(()=>p.requestAnimationFrame(s)):s()},de=new Set,He=()=>{de.forEach(e=>D.delete(e)),de.clear()},xe=(e,i=!1)=>{!e||e===R||e===E||(e.images.forEach(n=>{B(n)}),Ie("release",e.data.token,i))},Ee=e=>e.filter(i=>{if(!M(i.scope.element)||![i.element,...i.sources??[]].every(f))return!1;if(i.control.scroll){let n=i.element.getBoundingClientRect(),s=i.control.scroll.clip;if(n.right<=s.x||n.bottom<=s.y||n.left>=s.x+s.width||n.top>=s.y+s.height)return!1}return o.eligible?.(i)??!0}),Xe=async()=>{if(ve=0,V||h!=="native"||te||X||E||o.blocked()||!q||R?.revision===q.revision&&be===z)return;let{revision:e,candidates:i}=q,n=ee,s=z,w=O(),L=Ee(i);if(!L.length)return;te=!0;let x,I=!1,k=[];try{let ie=!1,re=S({action:"prepare",revision:o.captureRevision?.()??e,viewportWidth:p.innerWidth,ids:L.map(b=>b.control.id)});re.then(b=>{ie&&b.token&&S({action:"release",token:b.token}).catch(()=>{})}).catch(()=>{});try{x=await pe(re)}finally{ie=!0}if(!x.token||!x.parts?.length)return;let Ce=new Set(L.map(b=>b.control.id));if(x.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(G=>!Ce.has(G))||![b.x,b.y,b.width,b.height].every(Number.isFinite)||b.width<=0||b.height<=0)||new Set(x.parts.flatMap(b=>b.ids)).size!==Ce.size||x.parts.some(b=>new Set(b.ids.map(G=>L.find(Me=>Me.control.id===G).scope)).size!==1)||(await pe(Promise.all(x.parts.map(async b=>{let G=L.find(qe=>b.ids.includes(qe.control.id)).scope.element,Me=C.get(G);Me||(Me=[],C.set(G,Me));let fe=Me.find(qe=>!j.has(qe));return fe||(fe=d.createElement("img"),fe.setAttribute("data-native-ui-projection-node",""),Me.push(fe)),j.add(fe),k.push(fe),fe.src=nt(b.url),await fe.decode(),fe}))),V||h!=="native"||X||E||o.blocked()||ee!==n||O()!==w||q?.revision!==e||L.some(b=>!M(b.scope.element)||![b.element,...b.sources??[]].every(f))))return;let Re=R,Qe={data:x,images:k,sources:Array.from(new Set(L.flatMap(b=>[b.element,...b.sources??[]]))),targets:x.parts.map(b=>L.find(G=>b.ids.includes(G.control.id)).element),scopes:x.parts.map(b=>L.find(G=>b.ids.includes(G.control.id)).scope),parents:x.parts.map(b=>L.find(G=>b.ids.includes(G.control.id)).scope.element.parentNode),frames:[],viewport:w,revision:e,layout:W(L)};try{if(!Ue(Qe))throw new Error("Projection destination is unavailable")}catch(b){Q();try{Ue(),R?.sources.forEach(G=>{D.add(G),de.add(G)})}catch{$()}throw b}R=Qe,He(),R.sources.forEach(b=>{D.add(b),de.add(b)}),o.opaqueUnderlay&&S({action:"prepared",token:x.token}).catch(()=>{}),p.dispatchEvent(new Event(l)),be=s,I=!0,xe(Re)}catch{}finally{I||k.forEach(ie=>{B(ie)}),x?.token&&!I&&S({action:"release",token:x.token}).catch(()=>{}),te=!1,q&&(q.revision!==e||z!==s)&&ue()}},ue=()=>{p.clearTimeout(ve),!V&&h==="native"&&!E&&!X&&!o.blocked()&&(ve=p.setTimeout(()=>{Xe()},v))},Ae,a=(e,i)=>{if(i.some(s=>s.scope.element.ownerDocument!==d||[s.element,...s.sources??[]].some(w=>w.ownerDocument!==d)))throw new TypeError("All projection sources and fallback scopes must share one Document");if(o.blocked())return;!E&&R&&R.layout!==W(Ee(i))&&Le();let n=W(i);Ae!==n&&(Ae=n,z++,ee++),q?.revision!==e&&ee++,q={revision:e,candidates:i},le(),(R?.revision!==e||be!==z)&&ue()},u=e=>{!E&&R&&e&&q?.candidates.some(i=>i.scrollElement===e&&R.sources.includes(i.element))&&Le(),E&&ke(),z++,ee++,ue()},P=await Be(r.listen(({active:e})=>{X=e,ee++,p.clearTimeout(ve),e||ue()})),_=new Set,ce=e=>{se.get(e)?.forEach(i=>i.removeAttribute("data-native-ui-snapshot-content")),_.delete(e)&&e.removeAttribute("data-native-ui-snapshot-prepared"),e.removeAttribute("data-native-ui-snapshot-visible"),e.removeAttribute(y),e.removeAttribute("data-native-ui-snapshot-positioned"),e.removeAttribute("data-native-ui-snapshot-source"),F(e),se.delete(e)},Q=()=>{me++,p.cancelAnimationFrame(J);for(let e of Fe.keys())e.style.setProperty("opacity","0","important");Fe.clear(),J=0,Z=!1,ae=!1,He(),E?.sources.forEach(e=>{g.delete(e),c.delete(e)}),K.forEach(ce),K.clear(),A.forEach((e,i)=>{(V||i.nodeType===11&&!i.host.isConnected)&&(e.remove(),A.delete(i))})},$=(e=E,i=Y)=>{if(E!==e)return;let n=new Set([E,R]);Q(),E=void 0,R=void 0,Y=!1,p.clearTimeout(we),n.forEach(s=>xe(s,i)),o.wake()},ne=()=>{if(!E)return;if(R!==E){$();return}let e=E;me++,p.cancelAnimationFrame(J),J=0,Z=ae=!1,e.sources.forEach(i=>{g.delete(i),c.delete(i)}),K.forEach(i=>i.removeAttribute("data-native-ui-snapshot-source")),Ye(e,!!o.opaqueUnderlay),E=void 0,Y=!1,p.clearTimeout(we),Ie("restored",e.data.token,!0),e.sources.forEach(i=>{D.add(i),de.add(i)}),o.wake()},Pe=()=>{Y&&ne(),he.forEach(e=>e())},De=e=>e.scopes.map(i=>M(i.element)?i.element:void 0),K=new Set,Ye=(e,i)=>{for(let n of K)n.toggleAttribute("data-native-ui-snapshot-visible",i),Se(n);e.images.forEach(n=>n.style.setProperty("opacity",i?"1":"0","important"))},Te=new Map,Fe=new Map,ke=()=>{let e=[];for(let[i,n]of Fe){let{target:s,frame:w}=n;if(!s.isConnected){i.remove();continue}let L=s.shadowRoot??s;i.parentNode!==L&&L.insertBefore(i,null);let x=s.getBoundingClientRect(),I=i.getBoundingClientRect(),k=parseFloat(i.style.width)||w.width,ie=parseFloat(i.style.height)||w.height,re=I.width/k||1,Ce=I.height/ie||1,Re=n.scale??(n.scale={x:re,y:Ce});e.push({element:i,left:(parseFloat(i.style.left)||0)+(x.x+w.x*re/Re.x-I.x)/re,top:(parseFloat(i.style.top)||0)+(x.y+w.y*Ce/Re.y-I.y)/Ce,width:w.width/Re.x,height:w.height/Re.y})}for(let{element:i,...n}of e)for(let[s,w]of Object.entries(n)){let L=`${w}px`;i.style.getPropertyValue(s)!==L&&i.style.setProperty(s,L,"important")}},Ue=(e=E??R)=>{if(!e||Y)return!1;if(!e.sources.every(f)||De(e).some(n=>!n))return Le(),!1;let i=De(e);if(E){if(i.some(s=>!s?.isConnected||!A.has(N(s))))return $(E,!1),!1;let n=new Set;for(let[s,w]of e.targets.entries()){let L=Te.get(w),x=i[s];!L||!x?.isConnected||(x.setAttribute(y,L),x.setAttribute("data-native-ui-snapshot-source",""),n.add(x))}for(let s of K)n.has(s)||ce(s);return K.clear(),n.forEach(s=>K.add(s)),Ye(e,ae),!0}C.forEach(n=>n.forEach(s=>{e.images.includes(s)||(s.style.setProperty("display","none","important"),s.removeAttribute("data-native-ui-projection-image"))})),Te.clear(),Fe.clear(),K.forEach(ce),K.clear();for(let n of new Set(i)){if(!n)continue;K.add(n),oe(N(n));let s=i.flatMap((I,k)=>I===n?[k]:[]),w=`${T}-${s[0]}`;n.setAttribute(y,w),n!==e.targets[s[0]]&&(n.setAttribute("data-native-ui-snapshot-prepared",""),_.add(n)),n.toggleAttribute("data-native-ui-snapshot-visible",!!o.opaqueUnderlay),Se(n);let L=n.getBoundingClientRect();n.toggleAttribute("data-native-ui-snapshot-positioned",p.getComputedStyle(n).position==="static");let x=n.shadowRoot??n;for(let I of[...s].reverse()){let k=e.images[I],ie=e.data.parts[I],re=e.frames[I]??{x:o.opaqueUnderlay?0:ie.x-L.x,y:o.opaqueUnderlay?0:ie.y-L.y,width:ie.width,height:ie.height};e.frames[I]=re,Te.set(e.targets[I],w),k.inert=!0,k.setAttribute("aria-hidden","true"),k.setAttribute("data-native-ui-projection-image",w),k.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;",k.style.setProperty("width",`${re.width}px`,"important"),k.style.setProperty("height",`${re.height}px`,"important"),k.style.setProperty("left","0px","important"),k.style.setProperty("top","0px","important"),k.style.setProperty("opacity",o.opaqueUnderlay?"1":"0","important"),k.parentNode!==x&&x.insertBefore(k,null),Fe.set(k,{target:n,frame:re})}}return e.parents=e.scopes.map(n=>n.element.parentNode),ke(),!0},Je=()=>{if(Pe(),V||h==="none"||E)return;let e=R;if(!e||e.viewport!==O()||!e.sources.every(f)||o.current&&!o.current(e.targets)||e.targets.some(s=>!Te.has(s))||De(e).some(s=>!s?.isConnected)||[...K].some(s=>!s.isConnected))return;e.scopes.some((s,w)=>s.element.parentNode!==e.parents[w])&&Ue(),ke();let i=++me,n=()=>me===i;Z=!0,ae=!!o.opaqueUnderlay,E=e,ee++,p.clearTimeout(ve),e.sources.forEach(s=>{g.add(s)}),K.forEach(s=>s.setAttribute("data-native-ui-snapshot-source","")),Ye(e,ae),J=p.requestAnimationFrame(()=>{J=0,n()&&(Z=!1,o.wake())}),pe(S({action:"cover",token:e.data.token,...o.transient?{transient:!0}:{}})).then(s=>{if(n()){if(Z=!1,s?.shown!==!0){$(e,!1);return}Y||(ae=!0,e.sources.forEach(w=>c.add(w)),Ue(),ke()),p.cancelAnimationFrame(J),J=p.requestAnimationFrame(()=>{J=0,n()&&S({action:"painted",token:e.data.token}).catch(()=>{n()&&$(e,!1)})}),o.wake()}}).catch(()=>{n()&&$(e,!1)})},Ke=()=>{if(!(!E||V||Y)){if(!E.sources.every(f)||De(E).some(e=>!e)||o.current&&!o.current(E.targets)){$(E,!1);return}if(!o.blocked()){if(ke(),o.transient){let e=E,i=De(e);if(i.some(s=>!s?.isConnected)){$(e,!1);return}let n=i.map((s,w)=>{let L=e.images[w].getBoundingClientRect();return{...e.data.parts[w],x:L.x,y:L.y,width:L.width,height:L.height}});n.some((s,w)=>["x","y","width","height"].some(L=>s[L]!==e.data.parts[w][L]))&&(o.opaqueUnderlay?e.data={...e.data,parts:n}:R=void 0),S({action:"restore",token:e.data.token,viewportWidth:p.innerWidth,parts:n}).catch(()=>{})}We=o.revision?.()??q?.revision??0,Y=!0,E.sources.forEach(e=>g.delete(e)),we=p.setTimeout(()=>{Y&&$(E,!1)},250),o.wake()}}},ct=(e,i,n)=>{!Y||!E||n===void 0||n<=We||!o.transient&&e||E.data.parts.every(s=>s.ids.every(w=>i?.includes(w)))&&(ne(),ue())},Le=(e=!1)=>{he.forEach(n=>n()),ee++,p.clearTimeout(ve);let i=R;if(R=void 0,(e||V)&&(U=void 0),o.retainPreparedUntilRelease&&!E&&!e&&!V){if(i){let n={};U=n,pe(S({action:"release",token:i.data.token})).catch(()=>{}).finally(()=>{if(i.images.forEach(s=>{B(s)}),U===n&&(U=void 0,!(R||E))){for(let s of K)s.getAttribute(y)!==Te.get(s)&&(K.delete(s),_.delete(s));Q(),Te.clear(),p.dispatchEvent(new Event(l))}})}if(U)return}xe(i),E?$(E,!1):(Q(),Te.clear(),p.dispatchEvent(new Event(l)))},Ze;try{o.events&&(Ze=await ze(o.events,(e,i)=>{if(!V){if(e&&(h=e),h==="none"){Le();return}e==="web"&&Je(),e==="native"&&(Ke(),ue()),i&&u()}}))}catch(e){throw V=!0,Le(),await pe(Promise.resolve(P.remove())).catch(()=>{}),e}return{get owners(){return[...g]},get visibleOwners(){return[...c]},get preparedOwners(){return[...D]},consider:a,changed:u,moved:ke,get token(){return Y?void 0:E?.data.token},begin:Je,get restoring(){return Y},get handoffPending(){return Z},retireRestoration:Pe,end:Ke,updated:ct,invalidate:Le,async destroy(){V=!0,Le(),C.forEach(e=>e.forEach(i=>i.remove())),C.clear(),await Promise.allSettled([pe(Promise.resolve().then(()=>P?.remove())),pe(Promise.resolve().then(()=>Ze?.remove()))])}}},rt=async(t,r,o)=>{let v=await Et(t,r,o),h=v.consider;return Object.assign(v,{consider:(d,p)=>h(d,p.map(T=>({...T,scope:t})))})};var st=(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 at=async(t,r,o={addListener:async(v,h)=>globalThis.Capacitor.addListener(t.plugin,v,h)})=>{let v="view",h=t.receiveListeners,d=!1,p=!1,T="native",f="native",M=et(document),C=()=>T==="native"&&m&&M.isCovered(m)?"web":T,j=!1,B=!1,S=!1,y=!1,l,g,c,D=!1,H=()=>{let a=D;D=!0;try{c?.begin()}finally{D=a}},m,W={},A,N=0,oe=()=>{N++,A=void 0;let a=Ne(m);a?.owner===W&&(a.projected=!1,a.owner=void 0)},F={listen:a=>r.listen(u=>{a(u),!u.active&&B&&(B=!1,he()),u.precovered&&Ie(u.precovered)}),send:a=>{if(!t.placementHandoff)return r.send(a);let u=Ne(m);if(a.action==="cover"){let $=A===a.token&&u?.owner===W&&u.projected,ne=++N;return A=a.token,u&&(u.owner=W,u.projected=!!$),r.send(a).then(Pe=>(ne===N&&u===Ne(m)&&u?.owner===W&&(u.projected=Pe?.shown===!0),Pe)).catch(Pe=>{throw ne===N&&u?.owner===W&&(oe(),u.invalidate()),Pe})}let P=a.action==="release"&&a.token===A,_=A&&(a.action==="restore"||P||a.action==="reset"||a.action==="visibility"&&a.visible);_&&N++;let ce=N,Q=()=>{ce!==N||u?.owner!==W||(oe(),u.invalidate())};try{let $=_&&u?.owner===W?{...a,token:"token"in a?a.token:A,placement:u.measure()}:a;return r.send($).then(async ne=>(a.action==="release"&&ne?.requiresPlacement&&(u&&(!u.owner||u.owner===W)?ne=await r.send({...a,placement:u.measure()}):(await r.send({action:"visibility",visible:!1}),ne=await r.send(a))),ce===N&&(a.action==="resume"||P||a.action==="reset"||a.action==="visibility")&&oe(),ne)).catch(ne=>{throw Q(),ne})}catch($){return Q(),Promise.reject($)}}},se=0,Se=0,O=0,Z=!1,ae=!1,J=!1,me=!1,R=document.createElement("style"),U=`data-native-ui-session-${t.id.replace(/[^a-zA-Z0-9-]/g,"")}`;R.textContent=`[${U}="native"], [${U}="native"] *, [${U}="none"], [${U}="none"] * {visibility:hidden!important}`,document.documentElement.append(R);let E=()=>{let a=document.querySelectorAll(t.projectionSelector);return a.length===1&&a[0]instanceof HTMLElement?a[0]:void 0},X=()=>{m&&(f==="web"||f==="native"&&S?m.removeAttribute(U):m.setAttribute(U,f))},Y=()=>{if(!m?.isConnected)return[];let a=m.getBoundingClientRect(),u={x:a.x,y:a.y,width:a.width,height:a.height},P=l&&Ge(m,l,()=>t.id);return[{element:m,scrollElement:l,control:{id:v,...u,...P?{scroll:P}:{}}}]},we=async()=>{if(d)return;let a=O,u=t.failedFallback==="native"&&C()==="native"&&!!m?.isConnected;await F.send({action:"visibility",visible:u}).catch(()=>{}),!(d||a!==O)&&(u||f==="none"?X():m?.removeAttribute(U))},We=()=>{if(!j||f!=="native"||!m?.isConnected||c?.token||c?.restoring)return;let a=t.failedFallback==="native";F.send({action:"visibility",visible:a}).catch(()=>{}),a?X():m.removeAttribute(U)},ee=()=>{if(d||D)return;if(We(),f==="web"&&c&&!c.token&&!c.restoring){F.send({action:"visibility",visible:!1}).catch(()=>{}),m?.removeAttribute(U);return}if(Z||!c?.restoring||f!=="native")return;Z=!0;let a=O,u=c;F.send({action:"resume"}).then(()=>{d||a!==O||u!==c||(S=!1,u.updated(void 0,[v],++se),X(),z())}).catch(()=>{a!==O||d||(u.invalidate(),we())}).finally(()=>{Z=!1,ee()})},ve=async()=>{if(d||ae||j)return;if(c?.restoring){ee();return}let a=E();if(a!==m){if(O++,oe(),m?.removeAttribute(U),await c?.destroy(),c=void 0,d)return;m=a,S=!1,V.disconnect(),m&&V.observe(m)}if(de(),f=C(),!m){await F.send({action:"visibility",visible:!1});return}if(!c){ae=!0;let u=O;try{let P=await rt(st(m,t.id),F,{wake:ee,captureDelayMs:t.captureDelayMs,retainPreparedUntilRelease:t.nativeDragHandoff,blocked:()=>f!=="native"||j||S&&!c?.token,revision:()=>se,captureRevision:t.captureMode==="view"?()=>Se:void 0,transient:!0,opaqueUnderlay:t.captureMode==="view"});if(d||u!==O){await P.destroy();return}c=P}finally{ae=!1}}if(!d){if(f==="native"&&S){await F.send({action:"visibility",visible:!1}),X();return}if(f==="native"){let u=O;if(await F.send({action:"visibility",visible:!0}),d||u!==O||f!=="native")return;X(),l=[...Oe(m)].find(Q=>{let $=getComputedStyle(Q);return/auto|scroll/.test($.overflowX+$.overflowY)&&(Q.scrollHeight>Q.clientHeight||Q.scrollWidth>Q.clientWidth)});let P=l&&Ge(m,l,()=>t.id),_=t.nativeDragHandoff&&t.captureMode==="view"&&l?{viewport:l.getBoundingClientRect(),offsetX:l.scrollLeft,offsetY:l.scrollTop,rangeX:Math.max(0,l.scrollWidth-l.clientWidth),rangeY:Math.max(0,l.scrollHeight-l.clientHeight)}:void 0,ce=await F.send({action:"track",viewportWidth:innerWidth,...P?{scroll:P}:{},..._?{gesture:_}:{}});if(d||u!==O)return;y=ce?.tracked===!0,c.consider(t.captureMode==="view"?Se:++se,Y())}else await F.send({action:"visibility",visible:!1}),X()}},z=()=>{d||(J=!0,!(!p||me)&&(me=!0,Promise.resolve().then(async()=>{try{for(;J&&!d;)J=!1,await ve()}catch{await we()}finally{me=!1,J&&z()}})))},be=()=>{c?.invalidate(),z()},V=new ResizeObserver(be);window.addEventListener("resize",be);let te=new Set,q=new WeakSet,le=a=>{let u=a.composedPath()[0]??a.target;if(!(d||f!=="native"||!m||q.has(a)||u!==document&&![...Oe(m)].includes(u))){if(q.add(a),y&&u===l){c?.changed(u);return}j?t.captureMode==="view"?c?.moved():c?.changed():((Z||c?.restoring)&&O++,j=!0,H(),S=t.failedFallback!=="native",c?.token?m.removeAttribute(U):We()),he()}};function he(){clearTimeout(g),g=setTimeout(()=>{B||(j=!1,!(d||f!=="native")&&(c?.end(),c?.restoring||z()))},100)}function Ie(a){if(d||f!=="native"||!m?.isConnected||!c||(B=!0,c.token))return;(Z||c.restoring)&&O++,A=a;let u=Ne(m);if(u&&(u.owner=W,u.projected=!0),j=!0,H(),!c.token){j=!1,we();return}he()}let de=()=>{let a=new Set(m?Oe(m):[]),u=a.size!==te.size||[...a].some(P=>!te.has(P));for(let P of te)a.has(P)||(P.removeEventListener("scroll",le),P.removeEventListener("slotchange",He),te.delete(P));for(let P of a)te.has(P)||(P.addEventListener("scroll",le,{passive:!0}),P.addEventListener("slotchange",He),te.add(P));u&&(y=!1,l=void 0,c?.invalidate(),z())},He=()=>{de(),z()};document.addEventListener("scroll",le,!0);let xe=new MutationObserver(a=>{de(),E()!==m?z():m&&a.some(u=>u.type==="childList")&&Ee(C())});xe.observe(document.documentElement,{childList:!0,attributes:!0,subtree:!0});let Ee=(a,u=!1)=>{if(d||!u&&a===f)return;j=!1,B=!1,clearTimeout(g),f=a,O++;let P=O;f==="none"?F.send({action:"visibility",visible:!1}).then(()=>{f!=="none"||P!==O||d||(c?.invalidate(!0),X())}).catch(()=>{f!=="none"||P!==O||d||(c?.invalidate(!0),X())}):f==="web"?(H(),c?.token||F.send({action:"visibility",visible:!1}).catch(()=>{}),X()):f==="native"&&(c?.end(),c?.restoring||z())},Xe=M.subscribe(()=>queueMicrotask(()=>Ee(C()))),ue,Ae=async()=>{if(!d){d=!0,oe(),O++,Xe(),xe.disconnect(),V.disconnect(),window.removeEventListener("resize",be),document.removeEventListener("scroll",le,!0);for(let a of te)a.removeEventListener("scroll",le),a.removeEventListener("slotchange",He);te.clear(),clearTimeout(g),m?.removeAttribute(U),R.remove(),await Promise.allSettled([Promise.resolve(ue?.remove()),c?.destroy()])}};try{let a=O;ue=await ze({addListener:(P,_)=>o.addListener(P,_),update:h?.update,projection:h?.projection,accepts:P=>!h?.match||Object.entries(h?.match).every(([_,ce])=>typeof P=="object"&&P!==null&&P[_]===ce)},(P,_)=>{d||(P&&(P==="native"&&(S=!1),T=P,F.send({action:"destination",destination:P}).catch(()=>{}),Ee(C(),!0)),_&&(Se++,c?.changed(),f==="native"&&z()))});let u=await F.send({action:"connect"});return O===a&&["native","web","none"].includes(u?.destination)&&(T=u.destination),f=C(),p=!0,z(),{destroy:Ae,show:()=>{S=!1,T="native",Ee(C(),!0)},hide:()=>{T=f="none",O++,j=!1,B=!1,clearTimeout(g),c?.invalidate(!0),X()}}}catch(a){throw await Ae(),a}};var ye=new Map,ge=new Map,$e=new Map,Pt=Array.from(crypto.getRandomValues(new Uint32Array(4)),t=>t.toString(16)).join("-"),Ve=new Map,Tt=(t,r,o)=>Ve.get(t)?.get(r)?.(o),Lt=0,Mt=(t,r)=>new Promise((o,v)=>{let h=`${t}:${Pt}:${++Lt}`,d=setTimeout(()=>{ge.delete(h),v(new Error("Native UI session timed out"))},5e3);ge.set(h,{resolve:o,reject:v,timer:d});let p=JSON.stringify({key:h,request:r}),T=globalThis,f=T.webkit?.messageHandlers?.[t]??T[t]??T.nativeUIEngine;if(!f){clearTimeout(d),ge.delete(h),v(new Error("Native UI session unavailable"));return}try{f.postMessage(p)}catch(M){clearTimeout(d),ge.delete(h),v(M)}}),jt=(t,r,o,v)=>{if(r===null){$e.get(t)?.(o);return}let h=ge.get(r);!h||!r.startsWith(`${t}:`)||(ge.delete(r),clearTimeout(h.timer),v?h.reject(new Error(v)):h.resolve(o))},St=t=>{ye.get(t)?.show()},Ht=t=>(ye.get(t)?.hide(),!0),xt=async t=>{let r=ye.get(t);ye.delete(t),Ve.delete(t),$e.delete(t);for(let[o,v]of ge)o.startsWith(`${t}:`)&&(ge.delete(o),clearTimeout(v.timer),v.reject(new Error("Native UI session closed")));await r?.destroy()},kt=async t=>{if(ye.has(t.id))return;let r,o=!1,v,h={show:()=>{v="native",r?.show()},hide:()=>{v="none",r?.hide()},destroy:async()=>{o=!0,await r?.destroy()}};ye.set(t.id,h);try{if(document.readyState==="loading"&&await new Promise(p=>document.addEventListener("DOMContentLoaded",()=>p(),{once:!0})),o)return;let d=new Map;t.runtime==="cordova"&&Ve.set(t.id,d),r=await at(t,{send:p=>Mt(t.id,p),listen:async p=>($e.set(t.id,p),{remove:()=>{$e.get(t.id)===p&&$e.delete(t.id)}})},t.runtime==="cordova"?{addListener:async(p,T)=>(d.set(p,T),{remove:()=>{d.delete(p)}})}:void 0),v==="none"?r.hide():v==="native"&&r.show(),o&&await r.destroy()}catch(d){throw ye.get(t.id)===h&&(ye.delete(t.id),Ve.delete(t.id)),d}};return mt(Ct);})();
|
|
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 h="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,L=e=>!!e?.isConnected&&e.ownerDocument===m,x=new Map,M=new Set,B=e=>{M.delete(e),e.style.setProperty("display","none","important"),e.removeAttribute("data-native-ui-projection-image"),e.removeAttribute("src"),Pe()},H=r.send.bind(r),g="data-native-ui-snapshot",l=`${t.namespace}:sources-change`,w=new Set,c=new Set,N=new Set,k=new WeakMap,d=0,V=e=>JSON.stringify(e.map(i=>{k.has(i.scope)||k.set(i.scope,++d);let n=o.transient&&!o.opaqueUnderlay?i.scope.element.getBoundingClientRect():void 0,s=n?{...i,control:{...i.control,x:i.control.x-n.x,y:i.control.y-n.y}}:i;return[k.get(i.scope),Pt([s],!!o.opaqueUnderlay)]})),F=new Map,G=e=>{let i=e.getRootNode();return i.nodeType===11&&"host"in i?i:m},pe=e=>{if(F.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),F.set(e,i)},Y=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,ne=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"),s=T=>{if(!T.hasAttribute("data-native-ui-projection-node")){if(T.shadowRoot){i.add(T),pe(T.shadowRoot);for(let S of T.shadowRoot.children)s(S)}for(let S of T.children)s(S)}};s(e);for(let T of i)T.toggleAttribute("data-native-ui-snapshot-content",n);Y(e)},le=()=>`${f.innerWidth}:${f.innerHeight}:${f.devicePixelRatio}`,A=!1,se=!1,Q=0,O=0,j,de,b,me=!1,z=!1,X=0,ve=0,$=0,he=0,ae=0,Se=-1,q=!1,We=!1,W,Pe=()=>{let e=new Set(W?.candidates.map(n=>n.scope.element));for(let[n,s]of x){let T=!q&&n.isConnected&&e.has(n);if(T&&(b||z||A))continue;let S=T?2*Math.max(1,j?.scopes.filter(C=>C.element===n).length??0):0,R=Math.max(0,S-s.filter(C=>M.has(C)).length),U=s.filter(C=>M.has(C)||R-- >0?!0:(C.remove(),!1));U.length?x.set(n,U):x.delete(n)}let i=new Set([...W?.candidates.map(n=>n.scope.element.getRootNode())??[],...b?.scopes.map(n=>n.element.getRootNode())??[],...j?.scopes.map(n=>n.element.getRootNode())??[],...[...M].map(n=>n.getRootNode()),...[...K.values()].flatMap(n=>[...n].map(s=>s.shadowRoot))]);for(let[n,s]of F)n.nodeType===11&&!i.has(n)&&(s.remove(),F.delete(n))},ye=new Set,oe=(e,i,n)=>{let s=()=>{ye.delete(s)&&(H({action:e,token:i}).catch(()=>{}),e==="restored"&&Pe())};ye.add(s),n&&!q?f.requestAnimationFrame(()=>f.requestAnimationFrame(s)):s()},ge=new Set,we=()=>{ge.forEach(e=>N.delete(e)),ge.clear()},Te=(e,i=!1)=>{!e||e===j||e===b||(e.images.forEach(n=>{B(n)}),oe("release",e.data.token,i))},Ue=e=>e.filter(i=>{if(!L(i.scope.element)||![i.element,...i.sources??[]].every(p))return!1;if(i.control.scroll){let n=i.element.getBoundingClientRect(),s=i.control.scroll.clip;if(n.right<=s.x||n.bottom<=s.y||n.left>=s.x+s.width||n.top>=s.y+s.height)return!1}return o.eligible?.(i)??!0}),xe=async()=>{if(he=0,q||h!=="native"||We||me||b||o.blocked()||!W||j?.revision===W.revision&&Se===ae)return;let{revision:e,candidates:i}=W,n=$,s=ae,T=le(),S=Ue(i);if(!S.length)return;We=!0;let R,U=!1,C=[];try{let ie=!1,re=H({action:"prepare",revision:o.captureRevision?.()??e,viewportWidth:f.innerWidth,ids:S.map(E=>E.control.id)});re.then(E=>{ie&&E.token&&H({action:"release",token:E.token}).catch(()=>{})}).catch(()=>{});try{R=await fe(re)}finally{ie=!0}if(!R.token||!R.parts?.length)return;let Ce=new Set(S.map(E=>E.control.id));if(R.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(_=>!Ce.has(_))||![E.x,E.y,E.width,E.height].every(Number.isFinite)||E.width<=0||E.height<=0)||new Set(R.parts.flatMap(E=>E.ids)).size!==Ce.size||R.parts.some(E=>new Set(E.ids.map(_=>S.find(Me=>Me.control.id===_).scope)).size!==1)||(await fe(Promise.all(R.parts.map(async E=>{let _=S.find(Ye=>E.ids.includes(Ye.control.id)).scope.element,Me=x.get(_);Me||(Me=[],x.set(_,Me));let ue=Me.find(Ye=>!M.has(Ye));return ue||(ue=m.createElement("img"),ue.setAttribute("data-native-ui-projection-node",""),Me.push(ue)),M.add(ue),C.push(ue),ue.src=it(E.url),await ue.decode(),ue}))),q||h!=="native"||me||b||o.blocked()||$!==n||le()!==T||W?.revision!==e||S.some(E=>!L(E.scope.element)||![E.element,...E.sources??[]].every(p))))return;let Oe=j,et={data:R,images:C,sources:Array.from(new Set(S.flatMap(E=>[E.element,...E.sources??[]]))),targets:R.parts.map(E=>S.find(_=>E.ids.includes(_.control.id)).element),scopes:R.parts.map(E=>S.find(_=>E.ids.includes(_.control.id)).scope),parents:R.parts.map(E=>S.find(_=>E.ids.includes(_.control.id)).scope.element.parentNode),frames:[],viewport:T,revision:e,layout:V(S)};try{if(!Ve(et))throw new Error("Projection destination is unavailable")}catch(E){u();try{Ve(),j?.sources.forEach(_=>{N.add(_),ge.add(_)})}catch{y()}throw E}j=et,we(),j.sources.forEach(E=>{N.add(E),ge.add(E)}),o.opaqueUnderlay&&H({action:"prepared",token:R.token}).catch(()=>{}),f.dispatchEvent(new Event(l)),Se=s,U=!0,Te(Oe)}catch{}finally{U||C.forEach(ie=>{B(ie)}),R?.token&&!U&&H({action:"release",token:R.token}).catch(()=>{}),We=!1,W&&(W.revision!==e||ae!==s)&&ce()}},ce=()=>{f.clearTimeout(he),!q&&h==="native"&&!b&&!me&&!o.blocked()&&(he=f.setTimeout(()=>{xe()},v))},De,He=(e,i)=>{if(i.some(s=>s.scope.element.ownerDocument!==m||[s.element,...s.sources??[]].some(T=>T.ownerDocument!==m)))throw new TypeError("All projection sources and fallback scopes must share one Document");if(o.blocked())return;!b&&j&&j.layout!==V(Ue(i))&&Le();let n=V(i);De!==n&&(De=n,ae++,$++),W?.revision!==e&&$++,W={revision:e,candidates:i},Pe(),(j?.revision!==e||Se!==ae)&&ce()},Be=e=>{!b&&j&&e&&W?.candidates.some(i=>i.scrollElement===e&&j.sources.includes(i.element))&&Le(),b&&Re(),ae++,$++,ce()},Ne=await ze(r.listen(({active:e})=>{me=e,$++,f.clearTimeout(he),e||ce()})),ke=new Set,a=e=>{K.get(e)?.forEach(i=>i.removeAttribute("data-native-ui-snapshot-content")),ke.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"),Y(e),K.delete(e)},u=()=>{O++,f.cancelAnimationFrame(Q);for(let e of Fe.keys())e.style.setProperty("opacity","0","important");Fe.clear(),Q=0,A=!1,se=!1,we(),b?.sources.forEach(e=>{w.delete(e),c.delete(e)}),D.forEach(a),D.clear(),F.forEach((e,i)=>{(q||i.nodeType===11&&!i.host.isConnected)&&(e.remove(),F.delete(i))})},y=(e=b,i=z)=>{if(b!==e)return;let n=new Set([b,j]);u(),b=void 0,j=void 0,z=!1,f.clearTimeout(X),n.forEach(s=>Te(s,i)),o.wake()},I=()=>{if(!b)return;if(j!==b){y();return}let e=b;O++,f.cancelAnimationFrame(Q),Q=0,A=se=!1,e.sources.forEach(i=>{w.delete(i),c.delete(i)}),D.forEach(i=>i.removeAttribute("data-native-ui-snapshot-source")),ee(e,!!o.opaqueUnderlay),b=void 0,z=!1,f.clearTimeout(X),oe("restored",e.data.token,!0),e.sources.forEach(i=>{N.add(i),ge.add(i)}),o.wake()},J=()=>{z&&I(),ye.forEach(e=>e())},Z=e=>e.scopes.map(i=>L(i.element)?i.element:void 0),D=new Set,ee=(e,i)=>{for(let n of D)n.toggleAttribute("data-native-ui-snapshot-visible",i),ne(n);e.images.forEach(n=>n.style.setProperty("opacity",i?"1":"0","important"))},te=new Map,Fe=new Map,Re=()=>{let e=[];for(let[i,n]of Fe){let{target:s,frame:T}=n;if(!s.isConnected){i.remove();continue}let S=s.shadowRoot??s;i.parentNode!==S&&S.insertBefore(i,null);let R=s.getBoundingClientRect(),U=i.getBoundingClientRect(),C=parseFloat(i.style.width)||T.width,ie=parseFloat(i.style.height)||T.height,re=U.width/C||1,Ce=U.height/ie||1,Oe=n.scale??(n.scale={x:re,y:Ce});e.push({element:i,left:(parseFloat(i.style.left)||0)+(R.x+T.x*re/Oe.x-U.x)/re,top:(parseFloat(i.style.top)||0)+(R.y+T.y*Ce/Oe.y-U.y)/Ce,width:T.width/Oe.x,height:T.height/Oe.y})}for(let{element:i,...n}of e)for(let[s,T]of Object.entries(n)){let S=`${T}px`;i.style.getPropertyValue(s)!==S&&i.style.setProperty(s,S,"important")}},Ve=(e=b??j)=>{if(!e||z)return!1;if(!e.sources.every(p)||Z(e).some(n=>!n))return Le(),!1;let i=Z(e);if(b){if(i.some(s=>!s?.isConnected||!F.has(G(s))))return y(b,!1),!1;let n=new Set;for(let[s,T]of e.targets.entries()){let S=te.get(T),R=i[s];!S||!R?.isConnected||(R.setAttribute(g,S),R.setAttribute("data-native-ui-snapshot-source",""),n.add(R))}for(let s of D)n.has(s)||a(s);return D.clear(),n.forEach(s=>D.add(s)),ee(e,se),!0}x.forEach(n=>n.forEach(s=>{e.images.includes(s)||(s.style.setProperty("display","none","important"),s.removeAttribute("data-native-ui-projection-image"))})),te.clear(),Fe.clear(),D.forEach(a),D.clear();for(let n of new Set(i)){if(!n)continue;D.add(n),pe(G(n));let s=i.flatMap((U,C)=>U===n?[C]:[]),T=`${P}-${s[0]}`;n.setAttribute(g,T),n!==e.targets[s[0]]&&(n.setAttribute("data-native-ui-snapshot-prepared",""),ke.add(n)),n.toggleAttribute("data-native-ui-snapshot-visible",!!o.opaqueUnderlay),ne(n);let S=n.getBoundingClientRect();n.toggleAttribute("data-native-ui-snapshot-positioned",f.getComputedStyle(n).position==="static");let R=n.shadowRoot??n;for(let U of[...s].reverse()){let C=e.images[U],ie=e.data.parts[U],re=e.frames[U]??{x:o.opaqueUnderlay?0:ie.x-S.x,y:o.opaqueUnderlay?0:ie.y-S.y,width:ie.width,height:ie.height};e.frames[U]=re,te.set(e.targets[U],T),C.inert=!0,C.setAttribute("aria-hidden","true"),C.setAttribute("data-native-ui-projection-image",T),C.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;",C.style.setProperty("width",`${re.width}px`,"important"),C.style.setProperty("height",`${re.height}px`,"important"),C.style.setProperty("left","0px","important"),C.style.setProperty("top","0px","important"),C.style.setProperty("opacity",o.opaqueUnderlay?"1":"0","important"),C.parentNode!==R&&R.insertBefore(C,null),Fe.set(C,{target:n,frame:re})}}return e.parents=e.scopes.map(n=>n.element.parentNode),Re(),!0},Ge=e=>e.images.map((i,n)=>{let s=i.getBoundingClientRect();return{...e.data.parts[n],x:s.x,y:s.y,width:s.width,height:s.height}}),Ke=()=>{if(J(),q||h==="none"||b)return;let e=j;if(!e||e.viewport!==le()||!e.sources.every(p)||o.current&&!o.current(e.targets)||e.targets.some(s=>!te.has(s))||Z(e).some(s=>!s?.isConnected)||[...D].some(s=>!s.isConnected))return;e.scopes.some((s,T)=>s.element.parentNode!==e.parents[T])&&Ve(),Re();let i=++O,n=()=>O===i;A=!0,se=!!o.opaqueUnderlay,b=e,$++,f.clearTimeout(he),e.sources.forEach(s=>{w.add(s)}),D.forEach(s=>s.setAttribute("data-native-ui-snapshot-source","")),ee(e,se),Q=f.requestAnimationFrame(()=>{Q=0,n()&&(A=!1,o.wake())}),fe(H({action:"cover",token:e.data.token,...o.transient?{transient:!0,viewportWidth:f.innerWidth,parts:Ge(e)}:{}})).then(s=>{if(n()){if(A=!1,s?.shown!==!0){y(e,!1);return}z||(se=!0,e.sources.forEach(T=>c.add(T)),Ve(),Re()),f.cancelAnimationFrame(Q),Q=f.requestAnimationFrame(()=>{Q=0,n()&&H({action:"painted",token:e.data.token}).catch(()=>{n()&&y(e,!1)})}),o.wake()}}).catch(()=>{n()&&y(e,!1)})},Ze=()=>{if(!(!b||q||z)){if(!b.sources.every(p)||Z(b).some(e=>!e)||o.current&&!o.current(b.targets)){y(b,!1);return}if(!o.blocked()){if(Re(),o.transient){let e=b;if(Z(e).some(s=>!s?.isConnected)){y(e,!1);return}let n=Ge(e);o.opaqueUnderlay||n.every((s,T)=>s.width===e.data.parts[T].width&&s.height===e.data.parts[T].height)?e.data={...e.data,parts:n}:j=void 0,H({action:"restore",token:e.data.token,viewportWidth:f.innerWidth,parts:n}).catch(()=>{})}ve=o.revision?.()??W?.revision??0,z=!0,b.sources.forEach(e=>w.delete(e)),X=f.setTimeout(()=>{z&&y(b,!1)},250),o.wake()}}},dt=(e,i,n)=>{!z||!b||n===void 0||n<=ve||!o.transient&&e||b.data.parts.every(s=>s.ids.every(T=>i?.includes(T)))&&(I(),ce())},Le=(e=!1)=>{ye.forEach(n=>n()),$++,f.clearTimeout(he);let i=j;if(j=void 0,(e||q)&&(de=void 0),o.retainPreparedUntilRelease&&!b&&!e&&!q){if(i){let n={};de=n,fe(H({action:"release",token:i.data.token})).catch(()=>{}).finally(()=>{if(i.images.forEach(s=>{B(s)}),de===n&&(de=void 0,!(j||b))){for(let s of D)s.getAttribute(g)!==te.get(s)&&(D.delete(s),ke.delete(s));u(),te.clear(),f.dispatchEvent(new Event(l))}})}if(de)return}Te(i),b?y(b,!1):(u(),te.clear(),f.dispatchEvent(new Event(l)))},Qe;try{o.events&&(Qe=await qe(o.events,(e,i)=>{if(!q){if(e&&(h=e),h==="none"){Le();return}e==="web"&&Ke(),e==="native"&&(Ze(),ce()),i&&Be()}}))}catch(e){throw q=!0,Le(),await fe(Promise.resolve(Ne.remove())).catch(()=>{}),e}return{get owners(){return[...w]},get visibleOwners(){return[...c]},get preparedOwners(){return[...N]},consider:He,changed:Be,moved:Re,get token(){return z?void 0:b?.data.token},begin:Ke,get restoring(){return z},get handoffPending(){return A},retireRestoration:J,end:Ze,updated:dt,invalidate:Le,async destroy(){q=!0,Le(),x.forEach(e=>e.forEach(i=>i.remove())),x.clear(),await Promise.allSettled([fe(Promise.resolve().then(()=>Ne?.remove())),fe(Promise.resolve().then(()=>Qe?.remove()))])}}},at=async(t,r,o)=>{let v=await Tt(t,r,o),h=v.consider;return Object.assign(v,{consider:(m,f)=>h(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,h)=>globalThis.Capacitor.addListener(t.plugin,v,h)})=>{let v="view",h=t.receiveListeners,m=!1,f=!1,P="native",p="native",L=nt(document),x=()=>P==="native"&&d&&L.isCovered(d)?"web":P,M=!1,B=!1,H=!1,g=!1,l,w,c,N=!1,k=()=>{let a=N;N=!0;try{c?.begin()}finally{N=a}},d,V=0,F,G=()=>{V++,F?.(),F=void 0},pe=async()=>{if(!t.values||!d||m)return;let a=d;G();let u=V,y=()=>!m&&u===V&&d===a&&ve()===a&&a.isConnected;if(a.localName.includes("-")&&!a.matches(":defined")&&Object.values(t.values).some(J=>J.property)){if(await Promise.race([a.ownerDocument.defaultView.customElements.whenDefined(a.localName),new Promise(J=>{F=J})]),!y())return;F=void 0}let I=await r.send({action:"values"}).catch(()=>{});if(y()&&I?.values&&typeof I.values=="object"&&!Array.isArray(I.values))try{tt(a,I.values,t.values)}catch(J){console.warn("[Native UI Engine] Cannot reflect values",J)}},Y={},K,ne=0,le=()=>{ne++,K=void 0;let a=$e(d);a?.owner===Y&&(a.projected=!1,a.owner=void 0)},A={listen:a=>r.listen(u=>{a(u),!u.active&&B&&(B=!1,Te()),u.precovered&&Ue(u.precovered)}),send:a=>{if(!t.placementHandoff)return r.send(a);let u=$e(d);if(a.action==="cover"){let D=K===a.token&&u?.owner===Y&&u.projected,ee=++ne;return K=a.token,u&&(u.owner=Y,u.projected=!!D),r.send(a).then(te=>(ee===ne&&u===$e(d)&&u?.owner===Y&&(u.projected=te?.shown===!0),te)).catch(te=>{throw ee===ne&&u?.owner===Y&&(le(),u.invalidate()),te})}let y=a.action==="release"&&a.token===K,I=K&&(a.action==="restore"||y||a.action==="reset"||a.action==="visibility"&&a.visible);I&&ne++;let J=ne,Z=()=>{J!==ne||u?.owner!==Y||(le(),u.invalidate())};try{let D=I&&u?.owner===Y?{...a,token:"token"in a?a.token:K,placement:u.measure()}:a;return r.send(D).then(async ee=>(a.action==="release"&&ee?.requiresPlacement&&(u&&(!u.owner||u.owner===Y)?ee=await r.send({...a,placement:u.measure()}):(await r.send({action:"visibility",visible:!1}),ee=await r.send(a))),J===ne&&(a.action==="resume"||y||a.action==="reset"||a.action==="visibility")&&le(),ee)).catch(ee=>{throw Z(),ee})}catch(D){return Z(),Promise.reject(D)}}},se=0,Q=0,O=0,j,de=!1,b=!1,me=!1,z=document.createElement("style"),X=`data-native-ui-session-${t.id.replace(/[^a-zA-Z0-9-]/g,"")}`;z.textContent=`[${X}="native"], [${X}="native"] *, [${X}="none"], [${X}="none"] * {visibility:hidden!important}`,document.documentElement.append(z);let ve=()=>{let a=document.querySelectorAll(t.projectionSelector);return a.length===1&&a[0]instanceof HTMLElement?a[0]:void 0},$=()=>{let a=x();d&&d.getAttribute("data-native-ui-destination")!==a&&d.setAttribute("data-native-ui-destination",a),d&&(p==="web"||p==="native"&&H?d.removeAttribute(X):d.setAttribute(X,p))},he=()=>{if(!d?.isConnected)return[];let a=d.getBoundingClientRect(),u={x:a.x,y:a.y,width:a.width,height:a.height},y=l&&_e(d,l,()=>t.id);return[{element:d,scrollElement:l,control:{id:v,...u,...y?{scroll:y}:{}}}]},ae=async()=>{if(m)return;let a=O,u=t.failedFallback==="native"&&x()==="native"&&!!d?.isConnected;await A.send({action:"visibility",visible:u}).catch(()=>{}),!(m||a!==O)&&(u||p==="none"?$():d?.removeAttribute(X))},Se=()=>{if(!M||p!=="native"||!d?.isConnected||c?.token||c?.restoring)return;let a=t.failedFallback==="native";A.send({action:"visibility",visible:a}).catch(()=>{}),a?$():d.removeAttribute(X)},q=()=>{if(m||N)return;if(Se(),p==="web"&&c&&!c.token&&!c.restoring){A.send({action:"visibility",visible:!1}).catch(()=>{}),d?.removeAttribute(X);return}if(!c?.restoring||j===c||p!=="native")return;j=c;let a=O,u=c;A.send({action:"resume"}).then(()=>{m||a!==O||u!==c||ve()!==d||(H=!1,u.updated(void 0,[v],++se),$(),W())}).catch(()=>{a!==O||m||(u.invalidate(),ae())}).finally(()=>{j===u&&(j=void 0),q()})},We=async()=>{if(m||de)return;if(ve()!==d){O++,M=!1,B=!1,clearTimeout(w),le(),d?.removeAttribute(X),d?.removeAttribute("data-native-ui-destination"),G();let u=c,y=d;c=void 0,d=void 0,ye.disconnect(),xe();try{y&&await A.send({action:"visibility",visible:!1})}finally{await u?.destroy()}if(m)return;d=ve(),H=!1,d&&(ye.observe(d),pe())}if(xe(),!M){if(c?.restoring){q();return}if(p=x(),!d){await A.send({action:"visibility",visible:!1});return}if(!c){de=!0;let u=O;try{let y=await at(ct(d,t.id),A,{wake:q,captureDelayMs:t.captureDelayMs,retainPreparedUntilRelease:t.nativeDragHandoff,blocked:()=>p!=="native"||M||H&&!c?.token,revision:()=>se,captureRevision:t.captureMode==="view"?()=>Q:void 0,transient:!0,opaqueUnderlay:t.captureMode==="view"});if(m||u!==O){await y.destroy();return}c=y}finally{de=!1}}if(!m){if(p==="native"&&H){await A.send({action:"visibility",visible:!1}),$();return}if(p==="native"){let u=O;if(await A.send({action:"visibility",visible:!0}),m||u!==O||p!=="native")return;$(),l=[...Ae(d)].find(Z=>{let D=getComputedStyle(Z);return/auto|scroll/.test(D.overflowX+D.overflowY)&&(Z.scrollHeight>Z.clientHeight||Z.scrollWidth>Z.clientWidth)});let y=l&&_e(d,l,()=>t.id),I=t.nativeDragHandoff&&t.captureMode==="view"&&l?{viewport:l.getBoundingClientRect(),offsetX:l.scrollLeft,offsetY:l.scrollTop,rangeX:Math.max(0,l.scrollWidth-l.clientWidth),rangeY:Math.max(0,l.scrollHeight-l.clientHeight)}:void 0,J=await A.send({action:"track",viewportWidth:innerWidth,...y?{scroll:y}:{},...I?{gesture:I}:{}});if(m||u!==O)return;g=J?.tracked===!0,c.consider(t.captureMode==="view"?Q:++se,he())}else await A.send({action:"visibility",visible:!1}),$()}}},W=()=>{m||(b=!0,!(!f||me)&&(me=!0,Promise.resolve().then(async()=>{try{for(;b&&!m;)b=!1,await We()}catch{await ae()}finally{me=!1,b&&W()}})))},Pe=()=>{c?.invalidate(),W()},ye=new ResizeObserver(Pe);window.addEventListener("resize",Pe);let oe=new Set,ge=new WeakSet,we=a=>{let u=a.composedPath()[0]??a.target;if(!(m||p!=="native"||!d||ge.has(a)||u!==document&&![...Ae(d)].includes(u))){if(ge.add(a),g&&u===l){c?.changed(u);return}M?t.captureMode==="view"?c?.moved():c?.changed():((j||c?.restoring)&&O++,M=!0,k(),H=t.failedFallback!=="native",c?.token?d.removeAttribute(X):Se()),Te()}};function Te(){clearTimeout(w),w=setTimeout(()=>{B||(M=!1,!(m||p!=="native")&&(c?.end(),c?.restoring||W()))},100)}function Ue(a){if(m||p!=="native"||!d?.isConnected||!c||(B=!0,c.token))return;(j||c.restoring)&&O++,K=a;let u=$e(d);if(u&&(u.owner=Y,u.projected=!0),M=!0,k(),!c.token){M=!1,ae();return}Te()}let xe=()=>{let a=new Set(d?Ae(d):[]),u=a.size!==oe.size||[...a].some(y=>!oe.has(y));for(let y of oe)a.has(y)||(y.removeEventListener("scroll",we),y.removeEventListener("slotchange",ce),oe.delete(y));for(let y of a)oe.has(y)||(y.addEventListener("scroll",we,{passive:!0}),y.addEventListener("slotchange",ce),oe.add(y));u&&(g=!1,l=void 0,c?.invalidate(),W())},ce=()=>{xe(),W()};document.addEventListener("scroll",we,!0);let De=new MutationObserver(a=>{xe(),ve()!==d?W():d&&a.some(u=>u.type==="childList")&&He(x())});De.observe(document.documentElement,{childList:!0,attributes:!0,subtree:!0});let He=(a,u=!1)=>{if(m||!u&&a===p)return;M=!1,B=!1,clearTimeout(w),p=a,O++;let y=O;p==="none"?A.send({action:"visibility",visible:!1}).then(()=>{p!=="none"||y!==O||m||(c?.invalidate(!0),$())}).catch(()=>{p!=="none"||y!==O||m||(c?.invalidate(!0),$())}):p==="web"?(k(),c?.token||A.send({action:"visibility",visible:!1}).catch(()=>{}),$()):p==="native"&&(c?.end(),c?.restoring||W())},Be=L.subscribe(()=>queueMicrotask(()=>He(x()))),Ne,ke=async()=>{if(!m){m=!0,G(),le(),O++,Be(),De.disconnect(),ye.disconnect(),window.removeEventListener("resize",Pe),document.removeEventListener("scroll",we,!0);for(let a of oe)a.removeEventListener("scroll",we),a.removeEventListener("slotchange",ce);oe.clear(),clearTimeout(w),d?.removeAttribute(X),d?.removeAttribute("data-native-ui-destination"),z.remove(),await Promise.allSettled([Promise.resolve(Ne?.remove()),c?.destroy()])}};try{let a=O;Ne=await qe({addListener:(y,I)=>o.addListener(y,I),update:h?.update,projection:h?.projection,accepts:y=>!h?.match||Object.entries(h?.match).every(([I,J])=>typeof y=="object"&&y!==null&&y[I]===J)},(y,I)=>{m||(y&&(y==="native"&&(H=!1),P=y,A.send({action:"destination",destination:y}).catch(()=>{}),He(x(),!0)),I&&(pe(),Q++,c?.changed(),p==="native"&&W()))});let u=await A.send({action:"connect"});return O===a&&["native","web","none"].includes(u?.destination)&&(P=u.destination),p=x(),f=!0,W(),{destroy:ke,show:()=>{H=!1,P="native",He(x(),!0)},hide:()=>{P=p="none",O++,M=!1,B=!1,clearTimeout(w),c?.invalidate(!0),$()}}}catch(a){throw await ke(),a}};var be=new Map,Ee=new Map,Ie=new Map,Lt=Array.from(crypto.getRandomValues(new Uint32Array(4)),t=>t.toString(16)).join("-"),Xe=new Map,Mt=(t,r,o)=>Xe.get(t)?.get(r)?.(o),jt=0,St=(t,r)=>new Promise((o,v)=>{let h=`${t}:${Lt}:${++jt}`,m=setTimeout(()=>{Ee.delete(h),v(new Error("Native UI session timed out"))},5e3);Ee.set(h,{resolve:o,reject:v,timer:m});let f=JSON.stringify({key:h,request:r}),P=globalThis,p=P.webkit?.messageHandlers?.[t]??P[t]??P.nativeUIEngine;if(!p){clearTimeout(m),Ee.delete(h),v(new Error("Native UI session unavailable"));return}try{p.postMessage(f)}catch(L){clearTimeout(m),Ee.delete(h),v(L)}}),xt=(t,r,o,v)=>{if(r===null){Ie.get(t)?.(o);return}let h=Ee.get(r);!h||!r.startsWith(`${t}:`)||(Ee.delete(r),clearTimeout(h.timer),v?h.reject(new Error(v)):h.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),Xe.delete(t),Ie.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,h={show:()=>{v="native",r?.show()},hide:()=>{v="none",r?.hide()},destroy:async()=>{o=!0,await r?.destroy()}};be.set(t.id,h);try{if(document.readyState==="loading"&&await new Promise(f=>document.addEventListener("DOMContentLoaded",()=>f(),{once:!0})),o)return;let m=new Map;t.runtime==="cordova"&&Xe.set(t.id,m),r=await lt(t,{send:f=>St(t.id,f),listen:async f=>(Ie.set(t.id,f),{remove:()=>{Ie.get(t.id)===f&&Ie.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)===h&&(be.delete(t.id),Xe.delete(t.id)),m}};return ht(Ot);})();
|
|
@@ -11,9 +11,12 @@ public final class NativeUIScrollBindings {
|
|
|
11
11
|
let previous = trackers
|
|
12
12
|
trackers.removeAll()
|
|
13
13
|
var rejected: [String] = []
|
|
14
|
+
// The filter guarantees every grouped node has a scroll placement.
|
|
15
|
+
// swiftlint:disable:next force_unwrapping
|
|
14
16
|
for (id, group) in Dictionary(grouping: nodes.filter { $0.scroll != nil }, by: { $0.scroll!.id }) {
|
|
15
17
|
if group.contains(where: { $0.scroll?.reuse == true }) {
|
|
16
18
|
if let tracker = previous[id], tracker.replace(group, webView: webView, scale: scale) {
|
|
19
|
+
tracker.render = render
|
|
17
20
|
trackers[id] = tracker
|
|
18
21
|
} else { rejected.append(contentsOf: group.map(\.id)) }
|
|
19
22
|
} else if let tracker = NativeUIScrollTracker(webView: webView, nodes: group, scale: scale, render: render) {
|
|
@@ -20,7 +20,7 @@ public struct NativeUIScrollPlacement: Decodable, Equatable {
|
|
|
20
20
|
|
|
21
21
|
public var isValid: Bool {
|
|
22
22
|
!id.isEmpty && viewport.isValid && clip.isValid && frame.isValid &&
|
|
23
|
-
|
|
23
|
+
offsetX.isFinite && offsetY.isFinite && contentWidth.isFinite && contentHeight.isFinite && contentWidth > 0 && contentHeight > 0
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -34,15 +34,15 @@ public final class NativeUIScrollTracker {
|
|
|
34
34
|
private let contentOrigin: CGPoint
|
|
35
35
|
private let viewportCorrection: CGPoint
|
|
36
36
|
private var frames: [String: CGRect] = [:]
|
|
37
|
-
|
|
37
|
+
var render: (String, CGRect, CGRect) -> Void
|
|
38
38
|
private var observation: NSKeyValueObservation?
|
|
39
39
|
|
|
40
40
|
public init?(webView: WKWebView, nodes: [NativeUIScrollNode], scale: CGFloat,
|
|
41
|
-
|
|
41
|
+
render: @escaping (String, CGRect, CGRect) -> Void) {
|
|
42
42
|
guard let placement = nodes.first?.scroll, placement.isValid,
|
|
43
43
|
nodes.allSatisfy({ $0.scroll?.id == placement.id && $0.scroll?.viewport == placement.viewport &&
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
$0.scroll?.clip == placement.clip && $0.scroll?.contentWidth == placement.contentWidth &&
|
|
45
|
+
$0.scroll?.contentHeight == placement.contentHeight }), scale.isFinite, scale > 0 else { return nil }
|
|
46
46
|
let transform = CGAffineTransform(scaleX: scale, y: scale)
|
|
47
47
|
let viewport = placement.viewport.rect.applying(transform)
|
|
48
48
|
let candidates = Self.scrollViews(in: webView).filter { scroll in
|
|
@@ -76,9 +76,9 @@ public final class NativeUIScrollTracker {
|
|
|
76
76
|
guard self.webView === webView, let scrollView, scrollView.isDescendant(of: webView),
|
|
77
77
|
!scrollView.isHidden, scrollView.window != nil, self.scale == scale,
|
|
78
78
|
nodes.allSatisfy({ node in
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
guard let next = node.scroll else { return false }
|
|
80
|
+
return next.id == placement.id && next.viewport == placement.viewport && next.clip == placement.clip &&
|
|
81
|
+
next.contentWidth == placement.contentWidth && next.contentHeight == placement.contentHeight
|
|
82
82
|
}) else { return false }
|
|
83
83
|
setFrames(nodes)
|
|
84
84
|
return true
|
|
@@ -86,6 +86,8 @@ public final class NativeUIScrollTracker {
|
|
|
86
86
|
|
|
87
87
|
private func setFrames(_ nodes: [NativeUIScrollNode]) {
|
|
88
88
|
frames = Dictionary(uniqueKeysWithValues: nodes.map {
|
|
89
|
+
// init and replace validate every scroll placement before reaching here.
|
|
90
|
+
// swiftlint:disable:next force_unwrapping
|
|
89
91
|
($0.id, $0.scroll!.frame.rect.applying(CGAffineTransform(scaleX: scale, y: scale))
|
|
90
92
|
.offsetBy(dx: contentOrigin.x, dy: contentOrigin.y))
|
|
91
93
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webview-native-ui/engine",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "Native UI placement, scroll tracking, and Web projection for Capacitor and Cordova plugin maintainers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,20 +33,27 @@
|
|
|
33
33
|
"lint": "npm run typecheck && eslint . --max-warnings 0 && npm run format:check",
|
|
34
34
|
"format": "prettier --write \"**/*.{ts,js,mjs,cjs,json,md,yml,yaml,html}\"",
|
|
35
35
|
"prepublishOnly": "npm run build",
|
|
36
|
-
"test:release": "node --test scripts/native-ui-engine-release
|
|
36
|
+
"test:release": "node --test scripts/native-ui-engine-release/*.test.mjs",
|
|
37
37
|
"test:package": "node scripts/verify-package.mjs",
|
|
38
38
|
"release": "np --no-publish --no-tests --branch main",
|
|
39
39
|
"test:cordova": "node scripts/verify-cordova.mjs",
|
|
40
|
-
"format:check": "prettier --check \"**/*.{ts,js,mjs,cjs,json,md,yml,yaml,html}\""
|
|
40
|
+
"format:check": "prettier --check \"**/*.{ts,js,mjs,cjs,json,md,yml,yaml,html}\"",
|
|
41
|
+
"swiftlint": "node-swiftlint",
|
|
42
|
+
"lint:swift": "swiftlint version && node-swiftlint lint --strict --no-cache",
|
|
43
|
+
"format:swift": "swiftlint version && node-swiftlint --fix --format --no-cache",
|
|
44
|
+
"lint:android": "android/gradlew -p android ktfmtCheck lintRelease",
|
|
45
|
+
"format:kotlin": "android/gradlew -p android ktfmtFormat"
|
|
41
46
|
},
|
|
42
47
|
"devDependencies": {
|
|
43
48
|
"@eslint/js": "^10.0.1",
|
|
49
|
+
"@ionic/swiftlint-config": "^2.0.0",
|
|
44
50
|
"@playwright/test": "^1.58.0",
|
|
45
51
|
"esbuild": "^0.27.0",
|
|
46
52
|
"eslint": "^10.13.0",
|
|
47
53
|
"globals": "^17.13.0",
|
|
48
54
|
"np": "^10.2.0",
|
|
49
55
|
"prettier": "^3.6.2",
|
|
56
|
+
"swiftlint": "^2.0.0",
|
|
50
57
|
"typescript": "^5.9.3",
|
|
51
58
|
"typescript-eslint": "^8.72.1"
|
|
52
59
|
},
|