@webview-native-ui/engine 0.0.6 → 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.
Files changed (45) hide show
  1. package/README.md +19 -12
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.js +3 -0
  4. package/dist/native/session.d.ts +5 -0
  5. package/dist/native/session.js +83 -14
  6. package/dist/native/updates.d.ts +16 -0
  7. package/dist/native/updates.js +108 -0
  8. package/dist/native/values.d.ts +5 -0
  9. package/dist/native/values.js +27 -0
  10. package/dist/projection/surface.d.ts +35 -0
  11. package/dist/projection/surface.js +81 -0
  12. package/dist/projection/surfaces.d.ts +20 -0
  13. package/dist/projection/surfaces.js +116 -0
  14. package/docs/README.md +70 -0
  15. package/docs/advanced/README.md +20 -0
  16. package/docs/advanced/android-placement.md +48 -0
  17. package/docs/advanced/native-handoff.md +89 -0
  18. package/docs/advanced/renderer.md +148 -0
  19. package/docs/advanced/update-queue.md +58 -0
  20. package/docs/advanced/web-projection.md +88 -0
  21. package/docs/assets/ios-native-capture-comparison.png +0 -0
  22. package/docs/concepts.md +97 -0
  23. package/docs/configuration/README.md +29 -0
  24. package/docs/configuration/capture.md +27 -0
  25. package/docs/configuration/events.md +35 -0
  26. package/docs/configuration/ionic-overlays.md +65 -0
  27. package/docs/configuration/values.md +125 -0
  28. package/docs/cordova.md +1 -1
  29. package/docs/{capacitor-plugin.md → getting-started/capacitor.md} +45 -47
  30. package/docs/{cordova-plugin.md → getting-started/cordova.md} +32 -15
  31. package/docs/getting-started/initialization.md +79 -0
  32. package/docs/maintenance.md +14 -2
  33. package/docs/{projection-containers.md → reference/containers.md} +6 -2
  34. package/docs/reference/platforms.md +137 -0
  35. package/docs/reference/projection.md +134 -0
  36. package/docs/reference/state.md +39 -0
  37. package/ios/Sources/WebViewNativeUIEngine/ClippedView.swift +12 -12
  38. package/ios/Sources/WebViewNativeUIEngine/CoveredSnapshots.swift +68 -7
  39. package/ios/Sources/WebViewNativeUIEngine/Frame.swift +10 -10
  40. package/ios/Sources/WebViewNativeUIEngine/NativeUIProjection.swift +74 -39
  41. package/ios/Sources/WebViewNativeUIEngine/Resources/native-ui-engine.js +3 -3
  42. package/ios/Sources/WebViewNativeUIEngine/ScrollBindings.swift +2 -0
  43. package/ios/Sources/WebViewNativeUIEngine/ScrollTracker.swift +9 -7
  44. package/package.json +9 -2
  45. package/docs/projection.md +0 -368
@@ -27,6 +27,66 @@ public final class NativeUICoveredSnapshots {
27
27
  private var observer: SnapshotTouchObserver?
28
28
  private let directory = FileManager.default.temporaryDirectory.appendingPathComponent("native-ui-snapshots-\(UUID().uuidString)")
29
29
  public private(set) var coveringToken: String?
30
+ /// Dispatch the renderer's existing ordered image-handoff transport on the main thread.
31
+ /// The renderer supplies eligible native bounds and the complete views that may be hidden.
32
+ public func handle(_ request: [String: Any], in webView: UIView,
33
+ frames: @escaping (Set<String>, Int) -> [String: CGRect],
34
+ views: (Set<String>) -> [UIView]?, complete: @escaping ([String: Any]) -> Void) {
35
+ let token = request["token"] as? String ?? ""
36
+ switch request["action"] as? String {
37
+ case "prepare":
38
+ guard let ids = request["ids"] as? [String], !ids.isEmpty, !ids.contains(""), Set(ids).count == ids.count,
39
+ let revision = request["revision"] as? Int,
40
+ let width = request["viewportWidth"] as? Double, width.isFinite, width > 0 else { complete([:]); return }
41
+ let expected = Set(ids)
42
+ let firstFrames = frames(expected, revision)
43
+ guard Set(firstFrames.keys) == expected else { complete([:]); return }
44
+ var initial: [String: CGRect]? = firstFrames
45
+ prepare(frames: {
46
+ let measured = initial ?? frames(expected, revision)
47
+ initial = nil
48
+ return Set(measured.keys) == expected ? measured : [:]
49
+ }, in: webView, viewportWidth: width, complete: complete)
50
+ case "cover":
51
+ let ids = identifiers(for: token)
52
+ let destination = request["parts"] == nil ? nil : projectionFrames(request, in: webView)
53
+ guard !ids.isEmpty, let selected = views(ids), !selected.isEmpty,
54
+ request["parts"] == nil || destination != nil else { complete(["shown": false]); return }
55
+ var seen = Set<ObjectIdentifier>()
56
+ complete(["shown": cover(token, in: webView, views: selected.filter { seen.insert(ObjectIdentifier($0)).inserted },
57
+ transient: request["transient"] as? Bool == true, frames: destination)])
58
+ case "restore":
59
+ guard let destination = projectionFrames(request, in: webView) else { complete(["shown": false]); return }
60
+ complete(["shown": restore(in: webView, token: token, frames: destination)])
61
+ case "painted", "restored":
62
+ retireCopy(token, entry: request["action"] as? String == "painted")
63
+ complete([:])
64
+ case "release": release(token); complete([:])
65
+ case "reset": reset(); complete([:])
66
+ default: complete([:])
67
+ }
68
+ }
69
+
70
+ /// Convert Web viewport CSS pixels to native points, rejecting partial or malformed destinations.
71
+ func projectionFrames(_ request: [String: Any], in webView: UIView) -> [String: CGRect]? {
72
+ guard let token = request["token"] as? String,
73
+ let width = request["viewportWidth"] as? Double, width.isFinite, width > 0,
74
+ webView.bounds.width > 0, let parts = request["parts"] as? [[String: Any]], !parts.isEmpty else { return nil }
75
+ let scale = webView.bounds.width / width
76
+ var result: [String: CGRect] = [:]
77
+ for part in parts {
78
+ guard let ids = part["ids"] as? [String], !ids.isEmpty,
79
+ let x = part["x"] as? Double, let y = part["y"] as? Double,
80
+ let w = part["width"] as? Double, let h = part["height"] as? Double,
81
+ [x, y, w, h, x * scale, y * scale, w * scale, h * scale].allSatisfy({ $0.isFinite }), w > 0, h > 0 else { return nil }
82
+ for id in ids {
83
+ guard !id.isEmpty, result[id] == nil else { return nil }
84
+ result[id] = CGRect(x: x * scale, y: y * scale, width: w * scale, height: h * scale)
85
+ }
86
+ }
87
+ return !result.isEmpty && Set(result.keys) == identifiers(for: token) ? result : nil
88
+ }
89
+
30
90
  public var covering: Bool { coveringToken != nil }
31
91
 
32
92
  public func observe(_ window: UIWindow, changed: @escaping (Bool) -> Void) {
@@ -46,7 +106,7 @@ public final class NativeUICoveredSnapshots {
46
106
  // Gesture release can keep changing SwiftUI button bounds after touchesEnded.
47
107
  // Wait off the presentation path for unchanged rendered geometry, not a guessed delay.
48
108
  public func prepare(frames: @escaping () -> [String: CGRect], in webView: UIView, viewportWidth: CGFloat,
49
- complete: @escaping ([String: Any]) -> Void) {
109
+ complete: @escaping ([String: Any]) -> Void) {
50
110
  let stamp = generation
51
111
  let start = CACurrentMediaTime()
52
112
  func sample(_ previous: [String: CGRect], _ stable: Int) {
@@ -63,7 +123,7 @@ public final class NativeUICoveredSnapshots {
63
123
  }
64
124
 
65
125
  private func capture(frames: [String: CGRect], in webView: UIView, viewportWidth: CGFloat,
66
- complete: @escaping ([String: Any]) -> Void) {
126
+ complete: @escaping ([String: Any]) -> Void) {
67
127
  guard !touching, let window = webView.window, !frames.isEmpty,
68
128
  viewportWidth > 0, webView.bounds.width > 0 else { complete([:]); return }
69
129
  let stamp = generation
@@ -88,8 +148,9 @@ public final class NativeUICoveredSnapshots {
88
148
  guard let space = CGColorSpace(name: CGColorSpace.extendedDisplayP3),
89
149
  let outputSpace = CGColorSpace(name: CGColorSpace.displayP3),
90
150
  let context = CGContext(data: nil, width: Int(bounds.width * scale), height: Int(bounds.height * scale),
91
- bitsPerComponent: 16, bytesPerRow: 0, space: space,
92
- bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.floatComponents.rawValue | CGBitmapInfo.byteOrder16Little.rawValue)
151
+ bitsPerComponent: 16, bytesPerRow: 0, space: space,
152
+ bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue |
153
+ CGBitmapInfo.floatComponents.rawValue | CGBitmapInfo.byteOrder16Little.rawValue)
93
154
  else { complete([:]); return }
94
155
  context.translateBy(x: 0, y: bounds.height * scale)
95
156
  context.scaleBy(x: scale, y: -scale)
@@ -116,12 +177,12 @@ public final class NativeUICoveredSnapshots {
116
177
  for (index, crop) in crops.enumerated() {
117
178
  guard let pixels = crop.image.cgImage,
118
179
  let png = imageContext.pngRepresentation(of: CIImage(cgImage: pixels), format: .RGBA16,
119
- colorSpace: outputSpace, options: [:]) else { throw CocoaError(.fileWriteUnknown) }
180
+ colorSpace: outputSpace, options: [:]) else { throw CocoaError(.fileWriteUnknown) }
120
181
  // Native entry/return copies must use the same encoded pixels as Web,
121
182
  // including gamut clipping performed by integer PNG conversion.
122
183
  guard let source = CGImageSourceCreateWithData(png as CFData, nil),
123
184
  let decoded = CGImageSourceCreateImageAtIndex(source, 0,
124
- [kCGImageSourceShouldCacheImmediately: true] as CFDictionary)
185
+ [kCGImageSourceShouldCacheImmediately: true] as CFDictionary)
125
186
  else { throw CocoaError(.fileWriteUnknown) }
126
187
  let image = UIImage(cgImage: decoded, scale: scale, orientation: .up)
127
188
  let file = directory.appendingPathComponent("\(token)-\(index).png")
@@ -238,7 +299,7 @@ public final class NativeUICoveredSnapshots {
238
299
  }
239
300
  }
240
301
 
241
- /// Observes the start of interaction without recognizing or delaying the app's gestures.
302
+ // Observes the start of interaction without recognizing or delaying the app's gestures.
242
303
  private final class SnapshotTouchObserver: UIGestureRecognizer {
243
304
  private let changed: (Bool) -> Void
244
305
  private var touches = Set<UITouch>()
@@ -1,15 +1,15 @@
1
1
  import CoreGraphics
2
2
  public struct NativeUIFrame: Codable, Equatable {
3
- public let x: Double
4
- public let y: Double
5
- public let width: Double
6
- public let height: Double
7
- public init(x: Double, y: Double, width: Double, height: Double) { self.x = x; self.y = y; self.width = width; self.height = height }
8
- public var rect: CGRect { CGRect(x: x, y: y, width: width, height: height) }
9
- public var isValid: Bool { [x, y, width, height].allSatisfy(\.isFinite) && width > 0 && height > 0 }
3
+ public let x: Double
4
+ public let y: Double
5
+ public let width: Double
6
+ public let height: Double
7
+ public init(x: Double, y: Double, width: Double, height: Double) { self.x = x; self.y = y; self.width = width; self.height = height }
8
+ public var rect: CGRect { CGRect(x: x, y: y, width: width, height: height) }
9
+ public var isValid: Bool { [x, y, width, height].allSatisfy(\.isFinite) && width > 0 && height > 0 }
10
10
  }
11
11
  public struct NativeUIScrollNode: Decodable {
12
- public let id: String
13
- public let scroll: NativeUIScrollPlacement?
14
- public init(id: String, scroll: NativeUIScrollPlacement?) { self.id = id; self.scroll = scroll }
12
+ public let id: String
13
+ public let scroll: NativeUIScrollPlacement?
14
+ public init(id: String, scroll: NativeUIScrollPlacement?) { self.id = id; self.scroll = scroll }
15
15
  }
@@ -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]
@@ -46,6 +56,7 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
46
56
  private let origins: Set<String>
47
57
  private let allowedOriginsJSON: String
48
58
  private let canCapture: () -> Bool
59
+ private let readValues: (() -> [String: Any])?
49
60
  private let runtime: Runtime
50
61
  private let receiveListeners: ReceiveListeners
51
62
  private let notificationLock = NSLock()
@@ -67,34 +78,44 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
67
78
  private var captured: [String: [String: UIView]] = [:]
68
79
 
69
80
  public convenience init(webView: WKWebView?, plugin: String, projectionSelector: String,
70
- receiveListeners: ReceiveListeners = .init(),
71
- allowedOrigins: Set<String> = ["capacitor://localhost", "app://localhost", "https://localhost", "http://localhost"],
72
- failedFallback: FailedFallback = .web, runtime: Runtime = .capacitor,
73
- captureDelayMs: Double = 50,
74
- canCapture: @escaping () -> Bool = { true }, view: @escaping () -> UIView?) throws {
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 {
75
87
  try self.init(webView: webView, plugin: plugin, projectionSelector: projectionSelector,
76
88
  receiveListeners: receiveListeners, allowedOrigins: allowedOrigins, failedFallback: failedFallback, runtime: runtime,
77
- captureDelayMs: captureDelayMs, canCapture: canCapture, snapshots: NativeUICoveredSnapshots(), view: view)
89
+ captureDelayMs: captureDelayMs, values: values, readValues: readValues, canCapture: canCapture,
90
+ snapshots: NativeUICoveredSnapshots(), view: view)
78
91
  }
79
92
  init(webView: WKWebView?, plugin: String, projectionSelector: String,
80
93
  receiveListeners: ReceiveListeners = .init(),
81
94
  allowedOrigins: Set<String> = ["capacitor://localhost", "app://localhost", "https://localhost", "http://localhost"],
82
95
  failedFallback: FailedFallback = .web, runtime: Runtime = .capacitor,
83
96
  captureDelayMs: Double = 50,
97
+ values: [String: ValueBinding] = [:], readValues: (() -> [String: Any])? = nil,
84
98
  canCapture: @escaping () -> Bool = { true }, snapshots: NativeUICoveredSnapshots,
85
99
  view: @escaping () -> UIView?) throws {
100
+ // JSONSerialization produces valid UTF-8.
101
+ // swiftlint:disable:next force_unwrapping
86
102
  self.allowedOriginsJSON = String(data: try JSONSerialization.data(withJSONObject: Array(allowedOrigins)), encoding: .utf8)!
87
103
  self.runtime = runtime
88
104
  self.snapshots = snapshots
89
105
  self.receiveListeners = receiveListeners
106
+ self.readValues = readValues
90
107
  guard let webView else { throw ProjectionError.missingWebView }
91
108
  self.webView = webView; self.views = { view().map { ["view": $0] } ?? [:] }; self.origins = allowedOrigins; self.canCapture = canCapture
92
109
  super.init()
93
110
  precondition(Thread.isMainThread)
94
111
  guard captureDelayMs.isFinite, captureDelayMs >= 0, captureDelayMs <= 2147483647,
95
112
  !projectionSelector.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { throw ProjectionError.invalidConfiguration }
96
- let config: [String: Any] = ["id": id, "plugin": plugin, "projectionSelector": projectionSelector,
97
- "captureDelayMs": captureDelayMs, "receiveListeners": receiveListeners.configuration, "failedFallback": failedFallback.rawValue, "runtime": runtime.rawValue]
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
98
119
  let json = String(data: try JSONSerialization.data(withJSONObject: config), encoding: .utf8)!
99
120
  let allowed = allowedOriginsJSON
100
121
  let runtime = try Self.runtime()
@@ -110,8 +131,8 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
110
131
  public func receive(_ eventName: String, data: [String: Any]? = nil) {
111
132
  guard receiveListeners.match.allSatisfy({ key, expected in
112
133
  guard let actual = data?[key] else { return false }
113
- if let a = actual as? NSNumber, let b = expected as? NSNumber {
114
- return CFGetTypeID(a) == CFGetTypeID(b) && a == b
134
+ if let actualNumber = actual as? NSNumber, let expectedNumber = expected as? NSNumber {
135
+ return CFGetTypeID(actualNumber) == CFGetTypeID(expectedNumber) && actualNumber == expectedNumber
115
136
  }
116
137
  return (actual as? String).map { $0 == expected as? String } ?? false
117
138
  }) else { return }
@@ -162,21 +183,11 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
162
183
  self.reply(key, value)
163
184
  }
164
185
  let token = request["token"] as? String ?? ""
165
- func projectionFrames() -> [String: CGRect]? {
166
- guard let width = request["viewportWidth"] as? Double, width.isFinite, width > 0,
167
- let parts = request["parts"] as? [[String: Any]] else { return nil }
168
- var frames: [String: CGRect] = [:]
169
- let scale = webView.bounds.width / width
170
- for part in parts {
171
- guard let ids = part["ids"] as? [String], let x = part["x"] as? Double, let y = part["y"] as? Double,
172
- let w = part["width"] as? Double, let h = part["height"] as? Double,
173
- [x,y,w,h].allSatisfy({ $0.isFinite }), w > 0, h > 0 else { return nil }
174
- for id in ids { frames[id] = CGRect(x: x*scale, y: y*scale, width: w*scale, height: h*scale) }
175
- }
176
- guard Set(frames.keys) == snapshots.identifiers(for: token), !frames.isEmpty else { return nil }
177
- return frames
178
- }
179
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])
180
191
  case "connect":
181
192
  if !connected { destination = (views().values.contains(where: { !$0.isHidden }) ? "native" : "none"); connected = true }
182
193
  complete(["destination": recordedDestination ?? destination])
@@ -195,11 +206,19 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
195
206
  guard !current.isEmpty, current.values.allSatisfy({ $0.layer.mask == nil }) else { complete(["tracked": false]); return }
196
207
  let nodes = current.map { id, view -> NativeUIScrollNode in
197
208
  let frame = view.convert(view.bounds, to: webView)
198
- return NativeUIScrollNode(id: id, scroll: NativeUIScrollPlacement(id: placement.id,
199
- offsetX: placement.offsetX, offsetY: placement.offsetY, viewport: placement.viewport, clip: placement.clip,
200
- contentWidth: placement.contentWidth, contentHeight: placement.contentHeight,
201
- frame: NativeUIFrame(x: frame.minX/scale-placement.viewport.x+placement.offsetX,
202
- y: frame.minY/scale-placement.viewport.y+placement.offsetY, width: frame.width/scale, height: frame.height/scale)))
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
+ )
203
222
  }
204
223
  let rejected = scrolling.replace(nodes, in: webView, scale: scale) { [weak self, weak webView] id, frame, clip in
205
224
  guard let self, let webView, self.visible, !self.snapshots.hidesNativeControls,
@@ -216,7 +235,8 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
216
235
  }
217
236
  complete(["tracked": rejected.isEmpty])
218
237
  case "prepare":
219
- guard visible, canCapture(), let ids = request["ids"] as? [String], let width = request["viewportWidth"] as? Double, width.isFinite, width > 0,
238
+ guard visible, canCapture(), let ids = request["ids"] as? [String],
239
+ let width = request["viewportWidth"] as? Double, width.isFinite, width > 0,
220
240
  let window = webView.window else { complete([:]); return }
221
241
  let selected = views().filter { ids.contains($0.key) }
222
242
  guard selected.count == ids.count else { complete([:]); return }
@@ -235,7 +255,11 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
235
255
  guard let ids = part["ids"] as? [String], let x = part["x"] as? CGFloat, let y = part["y"] as? CGFloat,
236
256
  let w = part["width"] as? CGFloat, let h = part["height"] as? CGFloat else { continue }
237
257
  let image = CGRect(x: x*scale, y: y*scale, width: w*scale, height: h*scale)
238
- for id in ids { if let view = selected[id] { entries[id] = Anchor(native: view.convert(view.bounds, to: webView), image: image) } }
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
+ }
239
263
  }
240
264
  self.anchors[token] = entries
241
265
  }
@@ -244,27 +268,33 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
244
268
  case "cover":
245
269
  let selected = captured[token] ?? [:], current = views()
246
270
  let valid = visible && canCapture() && !selected.isEmpty && selected.allSatisfy { current[$0.key] === $0.value }
247
- let frames = request["parts"] == nil ? nil : projectionFrames()
271
+ let frames = request["parts"] == nil ? nil : snapshots.projectionFrames(request, in: webView)
248
272
  guard request["parts"] == nil || frames != nil else { complete(["shown": false]); return }
249
273
  restoreAccepted = true
250
- complete(["shown": valid && snapshots.cover(token, in: webView, views: Array(Dictionary(grouping: selected.values, by: { ObjectIdentifier($0) }).values.compactMap { $0.first }), transient: true, frames: frames)])
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
+ )])
251
279
  case "restore":
252
280
  restoreAccepted = false
253
- guard let frames = projectionFrames() else { complete(["shown": false]); return }
281
+ guard let frames = snapshots.projectionFrames(request, in: webView) else { complete(["shown": false]); return }
254
282
  let current = views()
255
283
  // Preserve renderer-owned constraints. Translation follows the corresponding DOM's movement.
256
284
  for (id, frame) in frames {
257
- guard let view = current[id], captured[token]?[id] === view, let anchor = anchors[token]?[id] else { complete(["shown": false]); return }
285
+ guard let view = current[id], captured[token]?[id] === view, let anchor = anchors[token]?[id]
286
+ else { complete(["shown": false]); return }
258
287
  let old = view.convert(view.bounds, to: webView)
259
288
  guard abs(old.width-anchor.native.width) < 0.1, abs(old.height-anchor.native.height) < 0.1,
260
- abs(frame.width-anchor.image.width) < 0.1, abs(frame.height-anchor.image.height) < 0.1 else { complete(["shown": false]); return }
289
+ abs(frame.width-anchor.image.width) < 0.1, abs(frame.height-anchor.image.height) < 0.1
290
+ else { complete(["shown": false]); return }
261
291
  }
262
292
  for (id, frame) in frames {
263
293
  guard let view = current[id], let parent = view.superview, let anchor = anchors[token]?[id] else { continue }
264
294
  let old = view.convert(view.bounds, to: webView)
265
295
  let from = parent.convert(CGPoint(x: old.midX, y: old.midY), from: webView)
266
296
  let to = parent.convert(CGPoint(x: anchor.native.midX+frame.minX-anchor.image.minX,
267
- y: anchor.native.midY+frame.minY-anchor.image.minY), from: webView)
297
+ y: anchor.native.midY+frame.minY-anchor.image.minY), from: webView)
268
298
  view.transform.tx += to.x-from.x; view.transform.ty += to.y-from.y
269
299
  }
270
300
  restoreAccepted = snapshots.restore(in: webView, token: token, frames: frames)
@@ -301,8 +331,8 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
301
331
  guard let data = try? JSONSerialization.data(withJSONObject: values), let json = String(data: data, encoding: .utf8) else { return }
302
332
  evaluate("globalThis.WebViewNativeUIEngineRuntime?.receive(...\(json))")
303
333
  }
304
- /// Call with the plugin's teardown. Does not destroy the renderer's views or DOM.
305
334
  deinit { destroy() }
335
+ /// Call with the plugin's teardown. Does not destroy the renderer's views or DOM.
306
336
  public func destroy() {
307
337
  guard !closed else { return }
308
338
  closed = true
@@ -313,8 +343,13 @@ public final class NativeUIProjection: NSObject, WKScriptMessageHandler {
313
343
  controller.removeAllUserScripts()
314
344
  remaining.forEach { controller.addUserScript($0) }
315
345
  }
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
+ : []
316
351
  snapshots.reset(); resetScrolling(); captured.removeAll(); anchors.removeAll()
317
- if destination != "none" { hiddenByProjection.forEach { $0.isHidden = false } }
352
+ if keepHidden { visibility.forEach { $0.0.isHidden = $0.1 } } else { hiddenByProjection.forEach { $0.isHidden = false } }
318
353
  hiddenByProjection.removeAll()
319
354
  }
320
355
  }
@@ -1,4 +1,4 @@
1
- "use strict";var WebViewNativeUIEngineRuntime=(()=>{var _e=Object.defineProperty;var dt=Object.getOwnPropertyDescriptor;var ut=Object.getOwnPropertyNames;var ft=Object.prototype.hasOwnProperty;var pt=(t,i)=>{for(var r in i)_e(t,r,{get:i[r],enumerable:!0})},mt=(t,i,r,v)=>{if(i&&typeof i=="object"||typeof i=="function")for(let h of ut(i))!ft.call(t,h)&&h!==r&&_e(t,h,{get:()=>i[h],enumerable:!(v=dt(i,h))||v.enumerable});return t};var vt=t=>mt(_e({},"__esModule",{value:!0}),t);var Rt={};pt(Rt,{hide:()=>Ht,notify:()=>Lt,receive:()=>St,show:()=>xt,start:()=>Ct,stop:()=>kt});var ht=Symbol.for("webview-native-ui-engine.projection-placement");var Ne=t=>t?.[ht];var yt=(t,i)=>{if(t.matches("ion-toast, ion-menu"))return!1;let r=t;if(r.showBackdrop===!1)return!1;if(!t.matches("ion-modal"))return!0;let v=i??r.initialBreakpoint;return v===void 0||v>(r.backdropBreakpoint??0)},gt=Symbol.for("@webview-native-ui/engine/overlays/v1"),wt=t=>{let i=new Set,r=new Set,v=new Set,h=new WeakMap,d=new WeakSet,p=new Map,T=[],f={},L=new Map,C,j=y=>{for(let l of[...v])try{l(y)}catch(g){console.error("Native UI overlay listener failed",g)}},B=(y,l,g)=>{l==="willPresent"||l==="didPresent"?(d.delete(y),i.add(y)):l==="didDismiss"&&(d.add(y),i.delete(y),r.delete(y),h.delete(y));let c=g?.detail?.breakpoint;typeof c=="number"&&c>0&&h.set(y,c),j({element:y,phase:l,event:g})},S=(y=!1)=>{let l=!1;for(let g of i)(!g.isConnected||g.ownerDocument!==t||!T.some(({selector:c})=>g.matches(c)))&&(i.delete(g),r.delete(g),l=!0);for(let g of t.querySelectorAll(T.map(({selector:c})=>c).join(",")))!i.has(g)&&!d.has(g)&&(y||!g.matches("ion-popover"))&&(g.presented||g.classList.contains("show-menu"))&&(i.add(g),l=!0);l&&j({phase:"change"})};return{get active(){return i},subscribe(y){return v.add(y),()=>{v.delete(y)}},setNative(y,l){r.has(y)!==l&&(l?r.add(y):r.delete(y),j({element:y,phase:"change"}))},isExcluded(y){return!!f.exclude&&y.matches(f.exclude)},isNative(y){return r.has(y)},get stack(){let y=[...i].filter(g=>g.isConnected&&g.ownerDocument===t),l=g=>{let c=Number.parseFloat(t.defaultView.getComputedStyle(g).zIndex);return Number.isFinite(c)?c:g.overlayIndex??0};return y.sort((g,c)=>l(g)-l(c)),y},isCovered(y){let l=this.stack,g=l.reduce((c,D,x)=>D.contains(y)?x:c,-1);return l.some((c,D)=>{if(r.has(c)||f.exclude&&c.matches(f.exclude))return!1;let x=f.covers?.(c,y);return x!==void 0?x:D>g&&!c.contains(y)&&(c.matches("ion-menu")||yt(c,h.get(c)))})},enable(y,l){let g={...f,...l},c=[...y,...g.additional??[]];g.exclude&&t.querySelector(g.exclude);let D=new Map;for(let m of c){t.querySelector(m.selector);for(let[O,A]of Object.entries(m.events)){let N=D.get(A);if(N&&N.phase!==O)throw new TypeError(`Overlay event "${A}" has conflicting phases`);D.set(A,{phase:O,selector:N?`${N.selector}, ${m.selector}`:m.selector})}}f=g,T=c,L=D;for(let m of L.keys()){if(p.has(m))continue;let O=A=>{let N=L.get(m),oe=A.composedPath().find(F=>F instanceof t.defaultView.HTMLElement&&F.matches(N.selector));oe&&B(oe,N.phase,A)};t.addEventListener(m,O,!0),p.set(m,()=>t.removeEventListener(m,O,!0))}for(let[m,O]of p)L.has(m)||(O(),p.delete(m));let x=!C;C||(C=new MutationObserver(()=>S()),C.observe(t.documentElement,{childList:!0,subtree:!0}),t.addEventListener("nativeUIOverlayAdopted",m=>{let O=m.detail;O?.ownerDocument===t&&B(O,"willPresent",m)})),S(x),(x||l)&&j({phase:"change"})}}},tt=t=>{let i=t;return i[gt]??=wt(t)};function*We(t){let i=t;for(;i;){let r=i.getRootNode();i=i.assignedSlot??i.parentElement??(r instanceof ShadowRoot?r.host:null),i&&(yield i)}}var bt=({x:t,y:i,width:r,height:v})=>({x:t,y:i,width:r,height:v}),nt=t=>{let i=t.getBoundingClientRect(),r=getComputedStyle(t),v=parseFloat(r.borderLeftWidth)||0,h=parseFloat(r.borderTopWidth)||0;return{x:i.left+v,y:i.top+h,width:i.width-v-(parseFloat(r.borderRightWidth)||0),height:i.height-h-(parseFloat(r.borderBottomWidth)||0)}},Ge=(t,i,r)=>{let v=[t,...We(t)],h=v.indexOf(i);if(h<=0||i===t.ownerDocument.scrollingElement)return;let d=t.ownerDocument.defaultView;if(d.visualViewport&&(d.visualViewport.scale!==1||d.visualViewport.offsetLeft||d.visualViewport.offsetTop))return;let p=0,T=0,f=d.innerWidth,L=d.innerHeight;for(let[S,y]of v.entries()){let l=getComputedStyle(y);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(x=>x&&x!=="none")||l.writingMode&&l.writingMode!=="horizontal-tb"||S<h&&/^(fixed|sticky)$/.test(l.position))return;if(S===0)continue;if(l.scrollbarGutter&&l.scrollbarGutter!=="auto")return;let g=/^(auto|scroll|hidden|clip)$/.test(l.overflowX),c=/^(auto|scroll|hidden|clip)$/.test(l.overflowY);if(S<h&&(g||c))return;let D=y===t.ownerDocument.scrollingElement;if(S>h&&((g||D)&&y.scrollWidth>y.clientWidth||(c||D)&&y.scrollHeight>y.clientHeight)||(g||c)&&[l.borderTopLeftRadius,l.borderTopRightRadius,l.borderBottomLeftRadius,l.borderBottomRightRadius].some(x=>parseFloat(x)>0)||l.clipPath&&l.clipPath!=="none"||l.maskImage&&l.maskImage!=="none")return;if(S>=h){let x=nt(y);g&&(p=Math.max(p,x.x),f=Math.min(f,x.x+x.width)),c&&(T=Math.max(T,x.y),L=Math.min(L,x.y+x.height))}}let C=getComputedStyle(i);if(!/^(auto|scroll)$/.test(C.overflowX)&&!/^(auto|scroll)$/.test(C.overflowY))return;let j=nt(i);if(f<=p||L<=T||!j.width||!j.height)return;let B=bt(t.getBoundingClientRect());return{id:r(i),offsetX:i.scrollLeft,offsetY:i.scrollTop,viewport:j,clip:{x:p,y:T,width:f-p,height:L-T},contentWidth:i.scrollWidth,contentHeight:i.scrollHeight,frame:{...B,x:B.x-j.x+i.scrollLeft,y:B.y-j.y+i.scrollTop}}};var ot=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 pe=t=>new Promise((i,r)=>{let v=setTimeout(()=>r(new Error("Native UI bridge timed out")),5e3);t.then(i,r).finally(()=>clearTimeout(v))}),Be=async t=>{try{return await pe(t)}catch(i){throw t.then(r=>r.remove()).catch(()=>{}),i}};var ze=async(t,i)=>{let r=new Map;for(let T of t.update??[])r.set(T,{updated:!0});for(let T of["native","web","none"])for(let f of t.projection?.[T]??[]){let L=r.get(f)??{updated:!1};if(L.destination&&L.destination!==T)throw new TypeError(`Projection event "${f}" has conflicting destinations`);r.set(f,{...L,destination:T})}let v=!1,h=[],d=async()=>{v=!0;let f=(await Promise.allSettled(h.splice(0).map(L=>Promise.resolve().then(()=>L.remove())))).find(L=>L.status==="rejected");if(f?.status==="rejected")throw f.reason},p=[...r].map(async([T,f])=>{let L=await Be(Promise.resolve().then(()=>t.addListener(T,C=>{!v&&(!t.accepts||t.accepts(C))&&i(f.destination,f.updated)})));v?await L.remove():h.push(L)});try{return await Promise.all(p),{remove:d}}catch(T){throw await d().catch(()=>{}),T}};var je=":is([data-native-ui-snapshot-source], [data-native-ui-snapshot-prepared], [data-native-ui-snapshot-content])",rt=`
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
- `,it=`
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 Et=(t,i=!1)=>JSON.stringify(t.map(({control:r})=>[r.id,r.kind,r.placement,i?0:r.x,i?0:r.y,r.width,r.height,r.dark,r.rtl])),Pt=async(t,i,r)=>{let v=r.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,L=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=i.send.bind(i),y="data-native-ui-snapshot",l=`${t.namespace}:sources-change`,g=new Set,c=new Set,D=new Set,x=new WeakMap,m=0,O=e=>JSON.stringify(e.map(o=>{x.has(o.scope)||x.set(o.scope,++m);let n=r.transient&&!r.opaqueUnderlay?o.scope.element.getBoundingClientRect():void 0,s=n?{...o,control:{...o.control,x:o.control.x-n.x,y:o.control.y-n.y}}:o;return[x.get(o.scope),Et([s],!!r.opaqueUnderlay)]})),A=new Map,N=e=>{let o=e.getRootNode();return o.nodeType===11&&"host"in o?o:d},oe=e=>{if(A.has(e))return;let o=d.createElement("style");o.setAttribute("data-native-ui-snapshot-base",""),o.textContent=rt+(e.nodeType===11?it:""),(e.nodeType===11?e:e.head).append(o),A.set(e,o)},F=e=>{let o=[...e.getAnimations({subtree:!0}),...[...se.get(e)??[]].flatMap(n=>n.shadowRoot?.getAnimations()??[])];for(let n of o)"transitionProperty"in n&&n.transitionProperty==="visibility"&&n.cancel()},se=new Map,Se=e=>{let o=se.get(e)??new Set;se.set(e,o);let n=e.hasAttribute("data-native-ui-snapshot-source")||e.hasAttribute("data-native-ui-snapshot-prepared"),s=P=>{if(!P.hasAttribute("data-native-ui-projection-node")){if(P.shadowRoot){o.add(P),oe(P.shadowRoot);for(let M of P.shadowRoot.children)s(M)}for(let M of P.children)s(M)}};s(e);for(let P of o)P.toggleAttribute("data-native-ui-snapshot-content",n);F(e)},W=()=>`${p.innerWidth}:${p.innerHeight}:${p.devicePixelRatio}`,Z=!1,ae=!1,J=0,me=0,R,U,b,q=!1,X=!1,we=0,Oe=0,ee=0,ve=0,z=0,be=-1,V=!1,te=!1,Y,le=()=>{let e=new Set(Y?.candidates.map(n=>n.scope.element));for(let[n,s]of C){let P=!V&&n.isConnected&&e.has(n);if(P&&(b||X||Z))continue;let M=P?2*Math.max(1,R?.scopes.filter(k=>k.element===n).length??0):0,H=Math.max(0,M-s.filter(k=>j.has(k)).length),I=s.filter(k=>j.has(k)||H-- >0?!0:(k.remove(),!1));I.length?C.set(n,I):C.delete(n)}let o=new Set([...Y?.candidates.map(n=>n.scope.element.getRootNode())??[],...b?.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&&!o.has(n)&&(s.remove(),A.delete(n))},he=new Set,Ie=(e,o,n)=>{let s=()=>{he.delete(s)&&(S({action:e,token:o}).catch(()=>{}),e==="restored"&&le())};he.add(s),n&&!V?p.requestAnimationFrame(()=>p.requestAnimationFrame(s)):s()},de=new Set,xe=()=>{de.forEach(e=>D.delete(e)),de.clear()},He=(e,o=!1)=>{!e||e===R||e===b||(e.images.forEach(n=>{B(n)}),Ie("release",e.data.token,o))},Ee=e=>e.filter(o=>{if(!L(o.scope.element)||![o.element,...o.sources??[]].every(f))return!1;if(o.control.scroll){let n=o.element.getBoundingClientRect(),s=o.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 r.eligible?.(o)??!0}),qe=async()=>{if(ve=0,V||h!=="native"||te||q||b||r.blocked()||!Y||R?.revision===Y.revision&&be===z)return;let{revision:e,candidates:o}=Y,n=ee,s=z,P=W(),M=Ee(o);if(!M.length)return;te=!0;let H,I=!1,k=[];try{let re=!1,ie=S({action:"prepare",revision:r.captureRevision?.()??e,viewportWidth:p.innerWidth,ids:M.map(w=>w.control.id)});ie.then(w=>{re&&w.token&&S({action:"release",token:w.token}).catch(()=>{})}).catch(()=>{});try{H=await pe(ie)}finally{re=!0}if(!H.token||!H.parts?.length)return;let Ce=new Set(M.map(w=>w.control.id));if(H.parts.some(w=>!w.url.startsWith("file:")&&!/^\/__native_ui_engine__\/nativeUI[a-fA-F0-9]+\/[a-fA-F0-9-]+-[0-9]+\.png$/.test(w.url)||!w.ids.length||w.ids.some(G=>!Ce.has(G))||![w.x,w.y,w.width,w.height].every(Number.isFinite)||w.width<=0||w.height<=0)||new Set(H.parts.flatMap(w=>w.ids)).size!==Ce.size||H.parts.some(w=>new Set(w.ids.map(G=>M.find(Me=>Me.control.id===G).scope)).size!==1)||(await pe(Promise.all(H.parts.map(async w=>{let G=M.find(Ye=>w.ids.includes(Ye.control.id)).scope.element,Me=C.get(G);Me||(Me=[],C.set(G,Me));let fe=Me.find(Ye=>!j.has(Ye));return fe||(fe=d.createElement("img"),fe.setAttribute("data-native-ui-projection-node",""),Me.push(fe)),j.add(fe),k.push(fe),fe.src=ot(w.url),await fe.decode(),fe}))),V||h!=="native"||q||b||r.blocked()||ee!==n||W()!==P||Y?.revision!==e||M.some(w=>!L(w.scope.element)||![w.element,...w.sources??[]].every(f))))return;let Re=R,et={data:H,images:k,sources:Array.from(new Set(M.flatMap(w=>[w.element,...w.sources??[]]))),targets:H.parts.map(w=>M.find(G=>w.ids.includes(G.control.id)).element),scopes:H.parts.map(w=>M.find(G=>w.ids.includes(G.control.id)).scope),parents:H.parts.map(w=>M.find(G=>w.ids.includes(G.control.id)).scope.element.parentNode),frames:[],viewport:P,revision:e,layout:O(M)};try{if(!Ue(et))throw new Error("Projection destination is unavailable")}catch(w){Q();try{Ue(),R?.sources.forEach(G=>{D.add(G),de.add(G)})}catch{$()}throw w}R=et,xe(),R.sources.forEach(w=>{D.add(w),de.add(w)}),r.opaqueUnderlay&&S({action:"prepared",token:H.token}).catch(()=>{}),p.dispatchEvent(new Event(l)),be=s,I=!0,He(Re)}catch{}finally{I||k.forEach(re=>{B(re)}),H?.token&&!I&&S({action:"release",token:H.token}).catch(()=>{}),te=!1,Y&&(Y.revision!==e||z!==s)&&ue()}},ue=()=>{p.clearTimeout(ve),!V&&h==="native"&&!b&&!q&&!r.blocked()&&(ve=p.setTimeout(()=>{qe()},v))},Ae,a=(e,o)=>{if(o.some(s=>s.scope.element.ownerDocument!==d||[s.element,...s.sources??[]].some(P=>P.ownerDocument!==d)))throw new TypeError("All projection sources and fallback scopes must share one Document");if(r.blocked())return;!b&&R&&R.layout!==O(Ee(o))&&Le();let n=O(o);Ae!==n&&(Ae=n,z++,ee++),Y?.revision!==e&&ee++,Y={revision:e,candidates:o},le(),(R?.revision!==e||be!==z)&&ue()},u=e=>{!b&&R&&e&&Y?.candidates.some(o=>o.scrollElement===e&&R.sources.includes(o.element))&&Le(),b&&ke(),z++,ee++,ue()},E=await Be(i.listen(({active:e})=>{q=e,ee++,p.clearTimeout(ve),e||ue()})),_=new Set,ce=e=>{se.get(e)?.forEach(o=>o.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,xe(),b?.sources.forEach(e=>{g.delete(e),c.delete(e)}),K.forEach(ce),K.clear(),A.forEach((e,o)=>{(V||o.nodeType===11&&!o.host.isConnected)&&(e.remove(),A.delete(o))})},$=(e=b,o=X)=>{if(b!==e)return;let n=new Set([b,R]);Q(),b=void 0,R=void 0,X=!1,p.clearTimeout(we),n.forEach(s=>He(s,o)),r.wake()},ne=()=>{if(!b)return;if(R!==b){$();return}let e=b;me++,p.cancelAnimationFrame(J),J=0,Z=ae=!1,e.sources.forEach(o=>{g.delete(o),c.delete(o)}),K.forEach(o=>o.removeAttribute("data-native-ui-snapshot-source")),Xe(e,!!r.opaqueUnderlay),b=void 0,X=!1,p.clearTimeout(we),Ie("restored",e.data.token,!0),e.sources.forEach(o=>{D.add(o),de.add(o)}),r.wake()},Pe=()=>{X&&ne(),he.forEach(e=>e())},De=e=>e.scopes.map(o=>L(o.element)?o.element:void 0),K=new Set,Xe=(e,o)=>{for(let n of K)n.toggleAttribute("data-native-ui-snapshot-visible",o),Se(n);e.images.forEach(n=>n.style.setProperty("opacity",o?"1":"0","important"))},Te=new Map,Fe=new Map,ke=()=>{let e=[];for(let[o,n]of Fe){let{target:s,frame:P}=n;if(!s.isConnected){o.remove();continue}let M=s.shadowRoot??s;o.parentNode!==M&&M.insertBefore(o,null);let H=s.getBoundingClientRect(),I=o.getBoundingClientRect(),k=parseFloat(o.style.width)||P.width,re=parseFloat(o.style.height)||P.height,ie=I.width/k||1,Ce=I.height/re||1,Re=n.scale??(n.scale={x:ie,y:Ce});e.push({element:o,left:(parseFloat(o.style.left)||0)+(H.x+P.x*ie/Re.x-I.x)/ie,top:(parseFloat(o.style.top)||0)+(H.y+P.y*Ce/Re.y-I.y)/Ce,width:P.width/Re.x,height:P.height/Re.y})}for(let{element:o,...n}of e)for(let[s,P]of Object.entries(n)){let M=`${P}px`;o.style.getPropertyValue(s)!==M&&o.style.setProperty(s,M,"important")}},Ue=(e=b??R)=>{if(!e||X)return!1;if(!e.sources.every(f)||De(e).some(n=>!n))return Le(),!1;let o=De(e);if(b){if(o.some(s=>!s?.isConnected||!A.has(N(s))))return $(b,!1),!1;let n=new Set;for(let[s,P]of e.targets.entries()){let M=Te.get(P),H=o[s];!M||!H?.isConnected||(H.setAttribute(y,M),H.setAttribute("data-native-ui-snapshot-source",""),n.add(H))}for(let s of K)n.has(s)||ce(s);return K.clear(),n.forEach(s=>K.add(s)),Xe(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(o)){if(!n)continue;K.add(n),oe(N(n));let s=o.flatMap((I,k)=>I===n?[k]:[]),P=`${T}-${s[0]}`;n.setAttribute(y,P),n!==e.targets[s[0]]&&(n.setAttribute("data-native-ui-snapshot-prepared",""),_.add(n)),n.toggleAttribute("data-native-ui-snapshot-visible",!!r.opaqueUnderlay),Se(n);let M=n.getBoundingClientRect();n.toggleAttribute("data-native-ui-snapshot-positioned",p.getComputedStyle(n).position==="static");let H=n.shadowRoot??n;for(let I of[...s].reverse()){let k=e.images[I],re=e.data.parts[I],ie=e.frames[I]??{x:r.opaqueUnderlay?0:re.x-M.x,y:r.opaqueUnderlay?0:re.y-M.y,width:re.width,height:re.height};e.frames[I]=ie,Te.set(e.targets[I],P),k.inert=!0,k.setAttribute("aria-hidden","true"),k.setAttribute("data-native-ui-projection-image",P),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",`${ie.width}px`,"important"),k.style.setProperty("height",`${ie.height}px`,"important"),k.style.setProperty("left","0px","important"),k.style.setProperty("top","0px","important"),k.style.setProperty("opacity",r.opaqueUnderlay?"1":"0","important"),k.parentNode!==H&&H.insertBefore(k,null),Fe.set(k,{target:n,frame:ie})}}return e.parents=e.scopes.map(n=>n.element.parentNode),ke(),!0},Je=e=>e.images.map((o,n)=>{let s=o.getBoundingClientRect();return{...e.data.parts[n],x:s.x,y:s.y,width:s.width,height:s.height}}),Ke=()=>{if(Pe(),V||h==="none"||b)return;let e=R;if(!e||e.viewport!==W()||!e.sources.every(f)||r.current&&!r.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,P)=>s.element.parentNode!==e.parents[P])&&Ue(),ke();let o=++me,n=()=>me===o;Z=!0,ae=!!r.opaqueUnderlay,b=e,ee++,p.clearTimeout(ve),e.sources.forEach(s=>{g.add(s)}),K.forEach(s=>s.setAttribute("data-native-ui-snapshot-source","")),Xe(e,ae),J=p.requestAnimationFrame(()=>{J=0,n()&&(Z=!1,r.wake())}),pe(S({action:"cover",token:e.data.token,...r.transient?{transient:!0,viewportWidth:p.innerWidth,parts:Je(e)}:{}})).then(s=>{if(n()){if(Z=!1,s?.shown!==!0){$(e,!1);return}X||(ae=!0,e.sources.forEach(P=>c.add(P)),Ue(),ke()),p.cancelAnimationFrame(J),J=p.requestAnimationFrame(()=>{J=0,n()&&S({action:"painted",token:e.data.token}).catch(()=>{n()&&$(e,!1)})}),r.wake()}}).catch(()=>{n()&&$(e,!1)})},Ze=()=>{if(!(!b||V||X)){if(!b.sources.every(f)||De(b).some(e=>!e)||r.current&&!r.current(b.targets)){$(b,!1);return}if(!r.blocked()){if(ke(),r.transient){let e=b;if(De(e).some(s=>!s?.isConnected)){$(e,!1);return}let n=Je(e);r.opaqueUnderlay||n.every((s,P)=>s.width===e.data.parts[P].width&&s.height===e.data.parts[P].height)?e.data={...e.data,parts:n}:R=void 0,S({action:"restore",token:e.data.token,viewportWidth:p.innerWidth,parts:n}).catch(()=>{})}Oe=r.revision?.()??Y?.revision??0,X=!0,b.sources.forEach(e=>g.delete(e)),we=p.setTimeout(()=>{X&&$(b,!1)},250),r.wake()}}},lt=(e,o,n)=>{!X||!b||n===void 0||n<=Oe||!r.transient&&e||b.data.parts.every(s=>s.ids.every(P=>o?.includes(P)))&&(ne(),ue())},Le=(e=!1)=>{he.forEach(n=>n()),ee++,p.clearTimeout(ve);let o=R;if(R=void 0,(e||V)&&(U=void 0),r.retainPreparedUntilRelease&&!b&&!e&&!V){if(o){let n={};U=n,pe(S({action:"release",token:o.data.token})).catch(()=>{}).finally(()=>{if(o.images.forEach(s=>{B(s)}),U===n&&(U=void 0,!(R||b))){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}He(o),b?$(b,!1):(Q(),Te.clear(),p.dispatchEvent(new Event(l)))},Qe;try{r.events&&(Qe=await ze(r.events,(e,o)=>{if(!V){if(e&&(h=e),h==="none"){Le();return}e==="web"&&Ke(),e==="native"&&(Ze(),ue()),o&&u()}}))}catch(e){throw V=!0,Le(),await pe(Promise.resolve(E.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 X?void 0:b?.data.token},begin:Ke,get restoring(){return X},get handoffPending(){return Z},retireRestoration:Pe,end:Ze,updated:lt,invalidate:Le,async destroy(){V=!0,Le(),C.forEach(e=>e.forEach(o=>o.remove())),C.clear(),await Promise.allSettled([pe(Promise.resolve().then(()=>E?.remove())),pe(Promise.resolve().then(()=>Qe?.remove()))])}}},st=async(t,i,r)=>{let v=await Pt(t,i,r),h=v.consider;return Object.assign(v,{consider:(d,p)=>h(d,p.map(T=>({...T,scope:t})))})};var at=(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 ct=async(t,i,r={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",L=tt(document),C=()=>T==="native"&&m&&L.isCovered(m)?"web":T,j=!1,B=!1,S=!1,y=!1,l,g,c,D=!1,x=()=>{let a=D;D=!0;try{c?.begin()}finally{D=a}},m,O={},A,N=0,oe=()=>{N++,A=void 0;let a=Ne(m);a?.owner===O&&(a.projected=!1,a.owner=void 0)},F={listen:a=>i.listen(u=>{a(u),!u.active&&B&&(B=!1,he()),u.precovered&&Ie(u.precovered)}),send:a=>{if(!t.placementHandoff)return i.send(a);let u=Ne(m);if(a.action==="cover"){let $=A===a.token&&u?.owner===O&&u.projected,ne=++N;return A=a.token,u&&(u.owner=O,u.projected=!!$),i.send(a).then(Pe=>(ne===N&&u===Ne(m)&&u?.owner===O&&(u.projected=Pe?.shown===!0),Pe)).catch(Pe=>{throw ne===N&&u?.owner===O&&(oe(),u.invalidate()),Pe})}let E=a.action==="release"&&a.token===A,_=A&&(a.action==="restore"||E||a.action==="reset"||a.action==="visibility"&&a.visible);_&&N++;let ce=N,Q=()=>{ce!==N||u?.owner!==O||(oe(),u.invalidate())};try{let $=_&&u?.owner===O?{...a,token:"token"in a?a.token:A,placement:u.measure()}:a;return i.send($).then(async ne=>(a.action==="release"&&ne?.requiresPlacement&&(u&&(!u.owner||u.owner===O)?ne=await i.send({...a,placement:u.measure()}):(await i.send({action:"visibility",visible:!1}),ne=await i.send(a))),ce===N&&(a.action==="resume"||E||a.action==="reset"||a.action==="visibility")&&oe(),ne)).catch(ne=>{throw Q(),ne})}catch($){return Q(),Promise.reject($)}}},se=0,Se=0,W=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 b=()=>{let a=document.querySelectorAll(t.projectionSelector);return a.length===1&&a[0]instanceof HTMLElement?a[0]:void 0},q=()=>{m&&(f==="web"||f==="native"&&S?m.removeAttribute(U):m.setAttribute(U,f))},X=()=>{if(!m?.isConnected)return[];let a=m.getBoundingClientRect(),u={x:a.x,y:a.y,width:a.width,height:a.height},E=l&&Ge(m,l,()=>t.id);return[{element:m,scrollElement:l,control:{id:v,...u,...E?{scroll:E}:{}}}]},we=async()=>{if(d)return;let a=W,u=t.failedFallback==="native"&&C()==="native"&&!!m?.isConnected;await F.send({action:"visibility",visible:u}).catch(()=>{}),!(d||a!==W)&&(u||f==="none"?q():m?.removeAttribute(U))},Oe=()=>{if(!j||f!=="native"||!m?.isConnected||c?.token||c?.restoring)return;let a=t.failedFallback==="native";F.send({action:"visibility",visible:a}).catch(()=>{}),a?q():m.removeAttribute(U)},ee=()=>{if(d||D)return;if(Oe(),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=W,u=c;F.send({action:"resume"}).then(()=>{d||a!==W||u!==c||(S=!1,u.updated(void 0,[v],++se),q(),z())}).catch(()=>{a!==W||d||(u.invalidate(),we())}).finally(()=>{Z=!1,ee()})},ve=async()=>{if(d||ae||j)return;if(c?.restoring){ee();return}let a=b();if(a!==m){if(W++,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=W;try{let E=await st(at(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!==W){await E.destroy();return}c=E}finally{ae=!1}}if(!d){if(f==="native"&&S){await F.send({action:"visibility",visible:!1}),q();return}if(f==="native"){let u=W;if(await F.send({action:"visibility",visible:!0}),d||u!==W||f!=="native")return;q(),l=[...We(m)].find(Q=>{let $=getComputedStyle(Q);return/auto|scroll/.test($.overflowX+$.overflowY)&&(Q.scrollHeight>Q.clientHeight||Q.scrollWidth>Q.clientWidth)});let E=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,...E?{scroll:E}:{},..._?{gesture:_}:{}});if(d||u!==W)return;y=ce?.tracked===!0,c.consider(t.captureMode==="view"?Se:++se,X())}else await F.send({action:"visibility",visible:!1}),q()}},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,Y=new WeakSet,le=a=>{let u=a.composedPath()[0]??a.target;if(!(d||f!=="native"||!m||Y.has(a)||u!==document&&![...We(m)].includes(u))){if(Y.add(a),y&&u===l){c?.changed(u);return}j?t.captureMode==="view"?c?.moved():c?.changed():((Z||c?.restoring)&&W++,j=!0,x(),S=t.failedFallback!=="native",c?.token?m.removeAttribute(U):Oe()),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)&&W++,A=a;let u=Ne(m);if(u&&(u.owner=O,u.projected=!0),j=!0,x(),!c.token){j=!1,we();return}he()}let de=()=>{let a=new Set(m?We(m):[]),u=a.size!==te.size||[...a].some(E=>!te.has(E));for(let E of te)a.has(E)||(E.removeEventListener("scroll",le),E.removeEventListener("slotchange",xe),te.delete(E));for(let E of a)te.has(E)||(E.addEventListener("scroll",le,{passive:!0}),E.addEventListener("slotchange",xe),te.add(E));u&&(y=!1,l=void 0,c?.invalidate(),z())},xe=()=>{de(),z()};document.addEventListener("scroll",le,!0);let He=new MutationObserver(a=>{de(),b()!==m?z():m&&a.some(u=>u.type==="childList")&&Ee(C())});He.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,W++;let E=W;f==="none"?F.send({action:"visibility",visible:!1}).then(()=>{f!=="none"||E!==W||d||(c?.invalidate(!0),q())}).catch(()=>{f!=="none"||E!==W||d||(c?.invalidate(!0),q())}):f==="web"?(x(),c?.token||F.send({action:"visibility",visible:!1}).catch(()=>{}),q()):f==="native"&&(c?.end(),c?.restoring||z())},qe=L.subscribe(()=>queueMicrotask(()=>Ee(C()))),ue,Ae=async()=>{if(!d){d=!0,oe(),W++,qe(),He.disconnect(),V.disconnect(),window.removeEventListener("resize",be),document.removeEventListener("scroll",le,!0);for(let a of te)a.removeEventListener("scroll",le),a.removeEventListener("slotchange",xe);te.clear(),clearTimeout(g),m?.removeAttribute(U),R.remove(),await Promise.allSettled([Promise.resolve(ue?.remove()),c?.destroy()])}};try{let a=W;ue=await ze({addListener:(E,_)=>r.addListener(E,_),update:h?.update,projection:h?.projection,accepts:E=>!h?.match||Object.entries(h?.match).every(([_,ce])=>typeof E=="object"&&E!==null&&E[_]===ce)},(E,_)=>{d||(E&&(E==="native"&&(S=!1),T=E,F.send({action:"destination",destination:E}).catch(()=>{}),Ee(C(),!0)),_&&(Se++,c?.changed(),f==="native"&&z()))});let u=await F.send({action:"connect"});return W===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",W++,j=!1,B=!1,clearTimeout(g),c?.invalidate(!0),q()}}}catch(a){throw await Ae(),a}};var ye=new Map,ge=new Map,$e=new Map,Tt=Array.from(crypto.getRandomValues(new Uint32Array(4)),t=>t.toString(16)).join("-"),Ve=new Map,Lt=(t,i,r)=>Ve.get(t)?.get(i)?.(r),Mt=0,jt=(t,i)=>new Promise((r,v)=>{let h=`${t}:${Tt}:${++Mt}`,d=setTimeout(()=>{ge.delete(h),v(new Error("Native UI session timed out"))},5e3);ge.set(h,{resolve:r,reject:v,timer:d});let p=JSON.stringify({key:h,request:i}),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(L){clearTimeout(d),ge.delete(h),v(L)}}),St=(t,i,r,v)=>{if(i===null){$e.get(t)?.(r);return}let h=ge.get(i);!h||!i.startsWith(`${t}:`)||(ge.delete(i),clearTimeout(h.timer),v?h.reject(new Error(v)):h.resolve(r))},xt=t=>{ye.get(t)?.show()},Ht=t=>(ye.get(t)?.hide(),!0),kt=async t=>{let i=ye.get(t);ye.delete(t),Ve.delete(t),$e.delete(t);for(let[r,v]of ge)r.startsWith(`${t}:`)&&(ge.delete(r),clearTimeout(v.timer),v.reject(new Error("Native UI session closed")));await i?.destroy()},Ct=async t=>{if(ye.has(t.id))return;let i,r=!1,v,h={show:()=>{v="native",i?.show()},hide:()=>{v="none",i?.hide()},destroy:async()=>{r=!0,await i?.destroy()}};ye.set(t.id,h);try{if(document.readyState==="loading"&&await new Promise(p=>document.addEventListener("DOMContentLoaded",()=>p(),{once:!0})),r)return;let d=new Map;t.runtime==="cordova"&&Ve.set(t.id,d),i=await ct(t,{send:p=>jt(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"?i.hide():v==="native"&&i.show(),r&&await i.destroy()}catch(d){throw ye.get(t.id)===h&&(ye.delete(t.id),Ve.delete(t.id)),d}};return vt(Rt);})();
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,6 +11,8 @@ 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) {