@webview-native-ui/engine 0.0.2 → 0.0.4

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.
@@ -1,5 +1,5 @@
1
1
  import { type ProjectionDestination } from '../projection/events.js';
2
- import type { ScrollPlacement, ListenerHandle, WebProjectionRequest } from '../types.js';
2
+ import type { Frame, ScrollPlacement, ListenerHandle, WebProjectionRequest } from '../types.js';
3
3
  /** Serialized by the native library. One registration owns one fixed fallback container. */
4
4
  export interface NativeSessionConfiguration {
5
5
  id: string;
@@ -12,6 +12,8 @@ export interface NativeSessionConfiguration {
12
12
  captureMode?: 'composited' | 'view';
13
13
  /** Native registration accepts a final placement in its reveal request. */
14
14
  placementHandoff?: boolean;
15
+ /** Android can cover prepared pixels before a Web scroll event arrives. */
16
+ nativeDragHandoff?: boolean;
15
17
  receiveListeners?: {
16
18
  update?: string[];
17
19
  projection?: Partial<Record<ProjectionDestination, string[]>>;
@@ -29,6 +31,13 @@ export interface NativeSessionBridge {
29
31
  action: 'track';
30
32
  viewportWidth: number;
31
33
  scroll?: ScrollPlacement;
34
+ gesture?: {
35
+ viewport: Frame;
36
+ offsetX: number;
37
+ offsetY: number;
38
+ rangeX: number;
39
+ rangeY: number;
40
+ };
32
41
  } | {
33
42
  action: 'connect';
34
43
  } | {
@@ -37,6 +46,7 @@ export interface NativeSessionBridge {
37
46
  }): Promise<any>;
38
47
  listen(listener: (event: {
39
48
  active: boolean;
49
+ precovered?: string;
40
50
  }) => void): Promise<ListenerHandle>;
41
51
  }
42
52
  /** Native startup calls this; application code does not initialize or wrap the plugin. */
@@ -21,6 +21,7 @@ export const startNativeSession = async (config, nativeBridge, plugin = {
21
21
  const overlays = getOverlayCoordinator(document);
22
22
  const effectiveDestination = () => requestedDestination === 'native' && target && overlays.isCovered(target) ? 'web' : requestedDestination;
23
23
  let automaticMotion = false;
24
+ let nativeDragging = false;
24
25
  let placementPending = false;
25
26
  let nativeScroll = false;
26
27
  let scrollOwner;
@@ -51,17 +52,26 @@ export const startNativeSession = async (config, nativeBridge, plugin = {
51
52
  }
52
53
  };
53
54
  const bridge = {
54
- listen: (listener) => nativeBridge.listen(listener),
55
+ listen: (listener) => nativeBridge.listen((event) => {
56
+ listener(event);
57
+ if (!event.active && nativeDragging) {
58
+ nativeDragging = false;
59
+ endAutomaticMotionLater();
60
+ }
61
+ if (event.precovered)
62
+ adoptNativeCover(event.precovered);
63
+ }),
55
64
  send: (request) => {
56
65
  if (!config.placementHandoff)
57
66
  return nativeBridge.send(request);
58
67
  const binding = projectionPlacement(target);
59
68
  if (request.action === 'cover') {
69
+ const alreadyCovered = coveredToken === request.token && binding?.owner === placementOwner && binding.projected;
60
70
  const epoch = ++placementEpoch;
61
71
  coveredToken = request.token;
62
72
  if (binding) {
63
73
  binding.owner = placementOwner;
64
- binding.projected = false;
74
+ binding.projected = !!alreadyCovered;
65
75
  }
66
76
  return nativeBridge
67
77
  .send(request)
@@ -97,7 +107,18 @@ export const startNativeSession = async (config, nativeBridge, plugin = {
97
107
  : request;
98
108
  return nativeBridge
99
109
  .send(payload)
100
- .then((result) => {
110
+ .then(async (result) => {
111
+ // A native drag can race retirement before its notification reaches JS.
112
+ // Keep the prepared underlay until native has applied a fresh return placement.
113
+ if (request.action === 'release' && result?.requiresPlacement) {
114
+ if (binding && (!binding.owner || binding.owner === placementOwner)) {
115
+ result = await nativeBridge.send({ ...request, placement: binding.measure() });
116
+ }
117
+ else {
118
+ await nativeBridge.send({ action: 'visibility', visible: false });
119
+ result = await nativeBridge.send(request);
120
+ }
121
+ }
101
122
  if (epoch === placementEpoch &&
102
123
  (request.action === 'resume' || releasing || request.action === 'reset' || request.action === 'visibility'))
103
124
  clearPlacement();
@@ -247,6 +268,7 @@ export const startNativeSession = async (config, nativeBridge, plugin = {
247
268
  const created = await createWebProjection(createWebProjectionScope(target, config.id), bridge, {
248
269
  wake,
249
270
  captureDelayMs: config.captureDelayMs,
271
+ retainPreparedUntilRelease: config.nativeDragHandoff,
250
272
  blocked: () => destination !== 'native' || automaticMotion || (placementPending && !manager?.token),
251
273
  revision: () => revision,
252
274
  captureRevision: config.captureMode === 'view' ? () => contentRevision : undefined,
@@ -282,7 +304,23 @@ export const startNativeSession = async (config, nativeBridge, plugin = {
282
304
  (element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth));
283
305
  });
284
306
  const scroll = scrollOwner && readScrollPlacement(target, scrollOwner, () => config.id);
285
- const tracking = await bridge.send({ action: 'track', viewportWidth: innerWidth, ...(scroll ? { scroll } : {}) });
307
+ // Gesture gating needs a hit region, not native compositor scroll eligibility.
308
+ // Rounded/clipped Ionic hosts can reject readScrollPlacement while still scrolling in Web.
309
+ const gesture = config.nativeDragHandoff && config.captureMode === 'view' && scrollOwner
310
+ ? {
311
+ viewport: scrollOwner.getBoundingClientRect(),
312
+ offsetX: scrollOwner.scrollLeft,
313
+ offsetY: scrollOwner.scrollTop,
314
+ rangeX: Math.max(0, scrollOwner.scrollWidth - scrollOwner.clientWidth),
315
+ rangeY: Math.max(0, scrollOwner.scrollHeight - scrollOwner.clientHeight),
316
+ }
317
+ : undefined;
318
+ const tracking = await bridge.send({
319
+ action: 'track',
320
+ viewportWidth: innerWidth,
321
+ ...(scroll ? { scroll } : {}),
322
+ ...(gesture ? { gesture } : {}),
323
+ });
286
324
  if (stopped || version !== generation)
287
325
  return;
288
326
  nativeScroll = tracking?.tracked === true;
@@ -356,8 +394,13 @@ export const startNativeSession = async (config, nativeBridge, plugin = {
356
394
  manager?.moved();
357
395
  else
358
396
  manager?.changed();
397
+ endAutomaticMotionLater();
398
+ };
399
+ function endAutomaticMotionLater() {
359
400
  clearTimeout(scrollTimer);
360
401
  scrollTimer = setTimeout(() => {
402
+ if (nativeDragging)
403
+ return;
361
404
  automaticMotion = false;
362
405
  if (stopped || destination !== 'native')
363
406
  return;
@@ -365,7 +408,31 @@ export const startNativeSession = async (config, nativeBridge, plugin = {
365
408
  if (!manager?.restoring)
366
409
  schedule();
367
410
  }, 100);
368
- };
411
+ }
412
+ function adoptNativeCover(token) {
413
+ if (stopped || destination !== 'native' || !target?.isConnected || !manager)
414
+ return;
415
+ nativeDragging = true;
416
+ // A scroll handler may have adopted the same native cover before its notification arrives.
417
+ if (manager.token)
418
+ return;
419
+ if (restoring || manager.restoring)
420
+ generation++;
421
+ coveredToken = token;
422
+ const binding = projectionPlacement(target);
423
+ if (binding) {
424
+ binding.owner = placementOwner;
425
+ binding.projected = true;
426
+ }
427
+ automaticMotion = true;
428
+ beginProjection();
429
+ if (!manager.token) {
430
+ automaticMotion = false;
431
+ void recoverFailedProjection();
432
+ return;
433
+ }
434
+ endAutomaticMotionLater();
435
+ }
369
436
  // Listen on composed-tree ancestors themselves: non-composed scroll events inside
370
437
  // Ionic's shadow tree never reach document, and Node.contains excludes slotted children.
371
438
  const refreshScrollListeners = () => {
@@ -408,6 +475,7 @@ export const startNativeSession = async (config, nativeBridge, plugin = {
408
475
  if (stopped || (!force && next === destination))
409
476
  return;
410
477
  automaticMotion = false;
478
+ nativeDragging = false;
411
479
  clearTimeout(scrollTimer);
412
480
  destination = next;
413
481
  generation++;
@@ -419,13 +487,13 @@ export const startNativeSession = async (config, nativeBridge, plugin = {
419
487
  .then(() => {
420
488
  if (destination !== 'none' || version !== generation || stopped)
421
489
  return;
422
- manager?.invalidate();
490
+ manager?.invalidate(true);
423
491
  setVisibility();
424
492
  })
425
493
  .catch(() => {
426
494
  if (destination !== 'none' || version !== generation || stopped)
427
495
  return;
428
- manager?.invalidate();
496
+ manager?.invalidate(true);
429
497
  setVisibility();
430
498
  });
431
499
  }
@@ -507,8 +575,9 @@ export const startNativeSession = async (config, nativeBridge, plugin = {
507
575
  requestedDestination = destination = 'none';
508
576
  generation++;
509
577
  automaticMotion = false;
578
+ nativeDragging = false;
510
579
  clearTimeout(scrollTimer);
511
- manager?.invalidate();
580
+ manager?.invalidate(true);
512
581
  setVisibility();
513
582
  },
514
583
  };
@@ -6,6 +6,8 @@ export interface WebProjectionOptions {
6
6
  events?: ProjectionEvents;
7
7
  /** Debounce before preparing replacement pixels, in milliseconds. Defaults to 50; never delays handoff. */
8
8
  captureDelayMs?: number;
9
+ /** Preserve an idle underlay while native disarms a possible early drag cover. */
10
+ retainPreparedUntilRelease?: boolean;
9
11
  wake(): void;
10
12
  blocked(): boolean;
11
13
  revision?(): number;
@@ -35,7 +37,7 @@ declare const createProjectionEngine: (scope: WebProjectionScope, transport: Web
35
37
  retireRestoration: () => void;
36
38
  end: () => void;
37
39
  updated: (token: string | undefined, restoredIDs?: string[], revision?: number) => void;
38
- invalidate: () => void;
40
+ invalidate: (nativeHidden?: boolean) => void;
39
41
  destroy(): Promise<void>;
40
42
  }>;
41
43
  type Engine = Awaited<ReturnType<typeof createProjectionEngine>>;
@@ -96,6 +96,7 @@ const createProjectionEngine = async (scope, transport, callbacks) => {
96
96
  let paintFrame = 0;
97
97
  let presentation = 0;
98
98
  let cached;
99
+ let retiring;
99
100
  let active;
100
101
  let touching = false;
101
102
  let ending = false;
@@ -672,12 +673,44 @@ const createProjectionEngine = async (scope, transport, callbacks) => {
672
673
  finishRestoration();
673
674
  schedule();
674
675
  };
675
- const invalidate = () => {
676
+ const invalidate = (nativeHidden = false) => {
676
677
  pendingCleanup.forEach((run) => run());
677
678
  generation++;
678
679
  win.clearTimeout(timer);
679
680
  const previous = cached;
680
681
  cached = undefined;
682
+ if (nativeHidden || stopped)
683
+ retiring = undefined;
684
+ if (callbacks.retainPreparedUntilRelease && !active && !nativeHidden && !stopped) {
685
+ if (previous) {
686
+ const pending = {};
687
+ retiring = pending;
688
+ void bounded(call({ action: 'release', token: previous.data.token }))
689
+ .catch(() => { })
690
+ .finally(() => {
691
+ previous.images.forEach((image) => {
692
+ image.src = '';
693
+ });
694
+ if (retiring !== pending)
695
+ return;
696
+ retiring = undefined;
697
+ if (cached || active)
698
+ return;
699
+ // Another session can already own the same host; retire only our own DOM markers.
700
+ for (const target of rendered) {
701
+ if (target.getAttribute(imageMarker) !== preparedKeys.get(target)) {
702
+ rendered.delete(target);
703
+ preparedTargets.delete(target);
704
+ }
705
+ }
706
+ detach();
707
+ preparedKeys.clear();
708
+ win.dispatchEvent(new Event(sourcesChangedEvent));
709
+ });
710
+ }
711
+ if (retiring)
712
+ return;
713
+ }
681
714
  dispose(previous);
682
715
  if (active)
683
716
  abandon(active, false);
@@ -828,7 +861,7 @@ export const createWebProjectionBatch = async (transport, options) => {
828
861
  end: () => engine?.end(),
829
862
  updated: (token, ids, revision) => engine?.updated(token, ids, revision),
830
863
  retireRestoration: () => engine?.retireRestoration(),
831
- invalidate: () => engine?.invalidate(),
864
+ invalidate: (nativeHidden) => engine?.invalidate(nativeHidden),
832
865
  async destroy() {
833
866
  stopped = true;
834
867
  await initializing;
@@ -25,13 +25,13 @@ xcodebuild -scheme WebViewNativeUIEngine -destination 'platform=iOS Simulator,id
25
25
 
26
26
  Lint combines strict TypeScript checking, the standard ESLint/TypeScript recommended rules, and typed Promise checks for `src`. Scripts and tests receive syntax-level linting; Prettier owns formatting. `npm run format` applies formatting only. Bridge payloads and test doubles may use explicit `any`; production boundary validation remains necessary. An explicit `void` marks background work, but does not handle a rejected Promise. Android uses `lintRelease` with warnings treated as errors in CI; Swift is compiled and tested on an iOS simulator.
27
27
 
28
- The engine is versioned independently of its consumers. Publish order is the native Maven artifact → npm engine; consumers upgrade separately. npm releases verify that the matching POM and AAR exist on Maven Central before publication. No publication is performed by build or test commands. Tests cover plain DOM, fractional/RTL geometry, stale ACKs, image ownership and native WKWebView scroll tracking; consumer tests remain responsible for Ionic/SDK integration.
28
+ The engine is versioned independently of its consumers. Publish order is Maven publication acceptance → npm engine; consumers upgrade separately. npm releases require a successful Maven publication workflow for the exact tagged commit. Maven Central distribution may still be pending: Android consumers must wait until the matching POM and AAR are downloadable, while iOS and Web consumers can upgrade immediately. No publication is performed by build or test commands. Tests cover plain DOM, fractional/RTL geometry, stale ACKs, image ownership and native WKWebView scroll tracking; consumer tests remain responsible for Ionic/SDK integration.
29
29
 
30
30
  CI-only setup, packaging commands and GitHub outputs are defined in `.github/workflows/`. Scripts retain the runtime build, reusable consumer/package verification, and tested publication logic (Central state handling and npm artifact comparison).
31
31
 
32
32
  ## Maven publication
33
33
 
34
- The `Native UI Engine Maven Release` workflow is manually dispatched on `main` with the exact engine package version. That commit must first pass `Native UI Engine` CI. It signs an AAR, source archive, generated Kotlin API documentation and Maven metadata, uploads once, and completes when Central reports `PUBLISHING` or `PUBLISHED`. The deployment ID and state changes are recorded in the run summary. `PUBLISHING` means validation passed and Central accepted publication; it does not guarantee that artifacts can already be downloaded. This workflow does not wait for distribution. The npm release still requires the matching POM and AAR to be available on Maven Central. Existing coordinates are never overwritten; if an upload times out, inspect the recorded deployment in Central before taking further action.
34
+ The `Native UI Engine Maven Release` workflow is manually dispatched on `main` with the exact engine package version. That commit must first pass `Native UI Engine` CI. It signs an AAR, source archive, generated Kotlin API documentation and Maven metadata, uploads once, and completes when Central reports `PUBLISHING` or `PUBLISHED`. The deployment ID and state changes are recorded in the run summary. `PUBLISHING` means validation passed and Central accepted publication; it does not guarantee that artifacts can already be downloaded. This workflow does not wait for distribution. The npm release checks that this workflow succeeded for the exact release commit; it does not wait for Maven Central distribution. Existing coordinates are never overwritten; if an upload times out, inspect the recorded deployment in Central before taking further action.
35
35
 
36
36
  Configure the repository's Actions secrets with `CENTRAL_USERNAME`, `CENTRAL_PASSWORD` (a Central user token), `MAVEN_SIGNING_KEY` (ASCII-armored private key) and `MAVEN_SIGNING_PASSWORD`. The signing public key must be available to Central. GitHub secrets are scoped to this repository.
37
37
 
@@ -43,9 +43,9 @@ This repository starts from the merged Engine implementation at [ionic-theme-ios
43
43
 
44
44
  The npm organization `webview-native-ui` and Maven Central namespace `io.github.webview-native-ui` are registered. Maintain npm trusted publishing for `webview-native-ui/engine`, workflow `release.yml`, and provision the Maven secrets above in this repository. Credentials are not copied by moving source files.
45
45
 
46
- 1. Prepare the next version and release notes on `main`; use `npm run release` to create a standard `vX.Y.Z` tag/GitHub release. Keep the GitHub release as a draft until Maven is downloadable.
46
+ 1. Prepare the next version and release notes on `main`; use `npm run release` to create a standard `vX.Y.Z` tag/GitHub release. Keep the GitHub release as a draft until the Maven publication workflow succeeds.
47
47
  2. After that main commit passes CI, dispatch `native-ui-engine-release.yml` with the exact package version.
48
- 3. Central `PUBLISHING` is an accepted upload, not download readiness. Once the POM and AAR are available, publish the prepared GitHub release. `release.yml` verifies the tag, package version, CI and Maven artifacts before npm publication (`next` for prereleases, `latest` otherwise).
48
+ 3. Central `PUBLISHING` is an accepted upload, not download readiness. Once the Maven publication workflow succeeds, publish the prepared GitHub release. Note any pending Android artifact distribution in the release notes. `release.yml` verifies the tag, package version, CI and Maven publication acceptance before npm publication (`next` for prereleases, `latest` otherwise).
49
49
 
50
50
  No build or test command publishes a package. Existing npm/Maven versions are never overwritten.
51
51
 
@@ -244,7 +244,7 @@ The image transport accepts `WebProjectionRequest` and returns prepared token/pa
244
244
  | `release` | Release the named token, files and associated temporary views. |
245
245
  | `reset` | Owner teardown only; release all native capture resources. |
246
246
 
247
- Use `NativeUICoveredSnapshots.observe` to notify the JS listener when interaction starts/ends. Captures use composited pixels so blur/refraction is preserved; they include the background under the clipped native component. Cache validity therefore includes layout and the plugin's visual-change notifications. The engine does not capture continuously or guarantee every possible renderer can be captured.
247
+ Use `NativeUICoveredSnapshots.observe` to notify the JS listener when interaction starts/ends. On iOS, captures rasterize the visible window with `drawHierarchy(in:afterScreenUpdates:)`, including the background under the clipped native component. Screen snapshot views are display replicas and are not used as bitmap sources. UIKit rasterization can differ from the live compositor for materials such as Liquid Glass; validate the appearance on physical devices with the backgrounds your plugin supports. Cache validity therefore includes layout and the plugin's visual-change notifications. The engine does not capture continuously or guarantee every possible renderer can be captured.
248
248
 
249
249
  ### Temporary storage and application permissions
250
250
 
@@ -338,3 +338,17 @@ appearance observed at 1000 ms. This is a recommendation for that interaction, n
338
338
  Apple timing contract or a universal Liquid Glass duration. Measure your control's
339
339
  selection, reselection and successive updates before choosing a value. Continuously
340
340
  changing content has no guaranteed settled snapshot.
341
+
342
+ ## Image color precision on iOS
343
+
344
+ Prepared window snapshots use an extended Display P3 Float16 bitmap during capture
345
+ and are encoded as 16-bit Display P3 PNGs on a background queue. The Web projection
346
+ displays the prepared image directly, without a Canvas or WebGPU conversion. Native
347
+ entry and return copies also use the decoded PNG, so both sides share the same
348
+ prepared pixels after color conversion. Encoding and decoding
349
+ stay outside the overlay handoff; consumers do not need a new setting or dependency.
350
+
351
+ This reduces color loss in wide-gamut content but does not guarantee identical Liquid
352
+ Glass appearance: native compositing and conversion to integer PNG can still change
353
+ pixels. Higher precision also increases capture memory and image size. The existing
354
+ fallback policy applies if preparation fails. Android retains its platform capture path.
@@ -1,4 +1,6 @@
1
1
  import UIKit
2
+ import CoreImage
3
+ import ImageIO
2
4
 
3
5
  /// Immutable, locally served images of controls that will be covered by a Web overlay.
4
6
  /// Native interaction invalidates in-flight captures before Web receives the activation.
@@ -14,13 +16,8 @@ public final class NativeUICoveredSnapshots {
14
16
  let webFrame: CGRect
15
17
  let parts: [Part]
16
18
  }
17
- private let snapshotView: (UIWindow) -> UIView
18
- public convenience init() {
19
- self.init(snapshotView: { $0.screen.snapshotView(afterScreenUpdates: false) })
20
- }
21
- init(snapshotView: @escaping (UIWindow) -> UIView) {
22
- self.snapshotView = snapshotView
23
- }
19
+ public init() {}
20
+ private let imageContext = CIContext()
24
21
  private var captures: [String: Capture] = [:]
25
22
  private var restoration: (token: String, views: [UIImageView], entry: Bool)?
26
23
  private var hiddenControls: (token: String, restore: [() -> Void])?
@@ -86,20 +83,22 @@ public final class NativeUICoveredSnapshots {
86
83
  regions.append(([id], rect))
87
84
  }
88
85
  let bounds = regions.reduce(CGRect.null) { $0.union($1.rect) }
89
- let format = UIGraphicsImageRendererFormat()
90
- format.scale = scale
91
- format.opaque = true
92
- // Render the compositor's frozen screen, not UIKit's reconstruction of
93
- // the hierarchy: the latter loses Liquid Glass background refraction.
94
- // The replica remains detached and never changes visible UI or input.
95
- let replica = snapshotView(window)
96
- let screenBounds = window.convert(bounds, to: window.screen.coordinateSpace)
97
- var drawn = false
98
- let image = UIGraphicsImageRenderer(size: bounds.size, format: format).image { context in
99
- context.cgContext.translateBy(x: -screenBounds.minX, y: -screenBounds.minY)
100
- drawn = replica.drawHierarchy(in: window.screen.bounds, afterScreenUpdates: true)
101
- }
102
- guard drawn, let pixels = image.cgImage else { complete([:]); return }
86
+ // Preserve wide-gamut precision during capture. Encode to integer 16-bit
87
+ // Display P3 only off the presentation path, without a Canvas conversion.
88
+ guard let space = CGColorSpace(name: CGColorSpace.extendedDisplayP3),
89
+ let outputSpace = CGColorSpace(name: CGColorSpace.displayP3),
90
+ 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)
93
+ else { complete([:]); return }
94
+ context.translateBy(x: 0, y: bounds.height * scale)
95
+ context.scaleBy(x: scale, y: -scale)
96
+ context.translateBy(x: -bounds.minX, y: -bounds.minY)
97
+ // Capture the window itself: display-replica views can rasterize as black on devices.
98
+ UIGraphicsPushContext(context)
99
+ let drawn = window.drawHierarchy(in: window.bounds, afterScreenUpdates: true)
100
+ UIGraphicsPopContext()
101
+ guard drawn, let pixels = context.makeImage() else { complete([:]); return }
103
102
  let token = UUID().uuidString
104
103
  let directory = self.directory
105
104
  let crops = regions.compactMap { region -> (ids: [String], frame: CGRect, image: UIImage)? in
@@ -109,15 +108,25 @@ public final class NativeUICoveredSnapshots {
109
108
  return (region.ids, window.convert(region.rect, to: webView), UIImage(cgImage: part, scale: scale, orientation: .up))
110
109
  }
111
110
  guard crops.count == regions.count else { complete([:]); return }
111
+ let imageContext = self.imageContext
112
112
  DispatchQueue.global(qos: .userInitiated).async { [weak self] in
113
113
  var parts: [Part] = []
114
114
  do {
115
115
  try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
116
116
  for (index, crop) in crops.enumerated() {
117
- guard let png = crop.image.pngData() else { throw CocoaError(.fileWriteUnknown) }
117
+ guard let pixels = crop.image.cgImage,
118
+ let png = imageContext.pngRepresentation(of: CIImage(cgImage: pixels), format: .RGBA16,
119
+ colorSpace: outputSpace, options: [:]) else { throw CocoaError(.fileWriteUnknown) }
120
+ // Native entry/return copies must use the same encoded pixels as Web,
121
+ // including gamut clipping performed by integer PNG conversion.
122
+ guard let source = CGImageSourceCreateWithData(png as CFData, nil),
123
+ let decoded = CGImageSourceCreateImageAtIndex(source, 0,
124
+ [kCGImageSourceShouldCacheImmediately: true] as CFDictionary)
125
+ else { throw CocoaError(.fileWriteUnknown) }
126
+ let image = UIImage(cgImage: decoded, scale: scale, orientation: .up)
118
127
  let file = directory.appendingPathComponent("\(token)-\(index).png")
119
128
  try png.write(to: file, options: .atomic)
120
- parts.append(Part(ids: crop.ids, frame: crop.frame, image: crop.image, file: file))
129
+ parts.append(Part(ids: crop.ids, frame: crop.frame, image: image, file: file))
121
130
  }
122
131
  } catch {
123
132
  parts.forEach { try? FileManager.default.removeItem(at: $0.file) }
@@ -1,4 +1,4 @@
1
- "use strict";var WebViewNativeUIEngineRuntime=(()=>{var ze=Object.defineProperty;var it=Object.getOwnPropertyDescriptor;var st=Object.getOwnPropertyNames;var at=Object.prototype.hasOwnProperty;var ct=(e,o)=>{for(var n in o)ze(e,n,{get:o[n],enumerable:!0})},lt=(e,o,n,f)=>{if(o&&typeof o=="object"||typeof o=="function")for(let v of st(o))!at.call(e,v)&&v!==n&&ze(e,v,{get:()=>o[v],enumerable:!(f=it(o,v))||f.enumerable});return e};var dt=e=>lt(ze({},"__esModule",{value:!0}),e);var jt={};ct(jt,{hide:()=>Lt,notify:()=>wt,receive:()=>Pt,show:()=>Tt,start:()=>St,stop:()=>Mt});var ut=Symbol.for("webview-native-ui-engine.projection-placement");var $e=e=>e?.[ut];var pt=(e,o)=>{if(e.matches("ion-toast, ion-menu"))return!1;let n=e;if(n.showBackdrop===!1)return!1;if(!e.matches("ion-modal"))return!0;let f=o??n.initialBreakpoint;return f===void 0||f>(n.backdropBreakpoint??0)},ft=Symbol.for("@webview-native-ui/engine/overlays/v1"),mt=e=>{let o=new Set,n=new Set,f=new Set,v=new WeakMap,c=new WeakSet,l=new Map,w=[],u={},S=new Map,j,M=m=>{for(let p of[...f])try{p(m)}catch(i){console.error("Native UI overlay listener failed",i)}},O=(m,p,i)=>{p==="willPresent"||p==="didPresent"?(c.delete(m),o.add(m)):p==="didDismiss"&&(c.add(m),o.delete(m),n.delete(m),v.delete(m));let T=i?.detail?.breakpoint;typeof T=="number"&&T>0&&v.set(m,T),M({element:m,phase:p,event:i})},R=(m=!1)=>{let p=!1;for(let i of o)(!i.isConnected||i.ownerDocument!==e||!w.some(({selector:T})=>i.matches(T)))&&(o.delete(i),n.delete(i),p=!0);for(let i of e.querySelectorAll(w.map(({selector:T})=>T).join(",")))!o.has(i)&&!c.has(i)&&(m||!i.matches("ion-popover"))&&(i.presented||i.classList.contains("show-menu"))&&(o.add(i),p=!0);p&&M({phase:"change"})};return{get active(){return o},subscribe(m){return f.add(m),()=>{f.delete(m)}},setNative(m,p){n.has(m)!==p&&(p?n.add(m):n.delete(m),M({element:m,phase:"change"}))},isExcluded(m){return!!u.exclude&&m.matches(u.exclude)},isNative(m){return n.has(m)},get stack(){let m=[...o].filter(i=>i.isConnected&&i.ownerDocument===e),p=i=>{let T=Number.parseFloat(e.defaultView.getComputedStyle(i).zIndex);return Number.isFinite(T)?T:i.overlayIndex??0};return m.sort((i,T)=>p(i)-p(T)),m},isCovered(m){let p=this.stack,i=p.reduce((T,N,d)=>N.contains(m)?d:T,-1);return p.some((T,N)=>{if(n.has(T)||u.exclude&&T.matches(u.exclude))return!1;let d=u.covers?.(T,m);return d!==void 0?d:N>i&&!T.contains(m)&&(T.matches("ion-menu")||pt(T,v.get(T)))})},enable(m,p){let i={...u,...p},T=[...m,...i.additional??[]];i.exclude&&e.querySelector(i.exclude);let N=new Map;for(let W of T){e.querySelector(W.selector);for(let[$,A]of Object.entries(W.events)){let F=N.get(A);if(F&&F.phase!==$)throw new TypeError(`Overlay event "${A}" has conflicting phases`);N.set(A,{phase:$,selector:F?`${F.selector}, ${W.selector}`:W.selector})}}u=i,w=T,S=N;for(let W of S.keys()){if(l.has(W))continue;let $=A=>{let F=S.get(W),C=A.composedPath().find(X=>X instanceof e.defaultView.HTMLElement&&X.matches(F.selector));C&&O(C,F.phase,A)};e.addEventListener(W,$,!0),l.set(W,()=>e.removeEventListener(W,$,!0))}for(let[W,$]of l)S.has(W)||($(),l.delete(W));let d=!j;j||(j=new MutationObserver(()=>R()),j.observe(e.documentElement,{childList:!0,subtree:!0}),e.addEventListener("nativeUIOverlayAdopted",W=>{let $=W.detail;$?.ownerDocument===e&&O($,"willPresent",W)})),R(d),(d||p)&&M({phase:"change"})}}},_e=e=>{let o=e;return o[ft]??=mt(e)};function*ae(e){let o=e;for(;o;){let n=o.getRootNode();o=o.assignedSlot??o.parentElement??(n instanceof ShadowRoot?n.host:null),o&&(yield o)}}var vt=({x:e,y:o,width:n,height:f})=>({x:e,y:o,width:n,height:f}),Ke=e=>{let o=e.getBoundingClientRect(),n=getComputedStyle(e),f=parseFloat(n.borderLeftWidth)||0,v=parseFloat(n.borderTopWidth)||0;return{x:o.left+f,y:o.top+v,width:o.width-f-(parseFloat(n.borderRightWidth)||0),height:o.height-v-(parseFloat(n.borderBottomWidth)||0)}},Ve=(e,o,n)=>{let f=[e,...ae(e)],v=f.indexOf(o);if(v<=0||o===e.ownerDocument.scrollingElement)return;let c=e.ownerDocument.defaultView;if(c.visualViewport&&(c.visualViewport.scale!==1||c.visualViewport.offsetLeft||c.visualViewport.offsetTop))return;let l=0,w=0,u=c.innerWidth,S=c.innerHeight;for(let[R,m]of f.entries()){let p=getComputedStyle(m);if(p.transform!=="none"&&!new DOMMatrixReadOnly(p.transform).isIdentity||p.zoom&&p.zoom!=="normal"&&Number(p.zoom)!==1||[p.translate,p.rotate,p.scale,p.perspective].some(d=>d&&d!=="none")||p.writingMode&&p.writingMode!=="horizontal-tb"||R<v&&/^(fixed|sticky)$/.test(p.position))return;if(R===0)continue;if(p.scrollbarGutter&&p.scrollbarGutter!=="auto")return;let i=/^(auto|scroll|hidden|clip)$/.test(p.overflowX),T=/^(auto|scroll|hidden|clip)$/.test(p.overflowY);if(R<v&&(i||T))return;let N=m===e.ownerDocument.scrollingElement;if(R>v&&((i||N)&&m.scrollWidth>m.clientWidth||(T||N)&&m.scrollHeight>m.clientHeight)||(i||T)&&[p.borderTopLeftRadius,p.borderTopRightRadius,p.borderBottomLeftRadius,p.borderBottomRightRadius].some(d=>parseFloat(d)>0)||p.clipPath&&p.clipPath!=="none"||p.maskImage&&p.maskImage!=="none")return;if(R>=v){let d=Ke(m);i&&(l=Math.max(l,d.x),u=Math.min(u,d.x+d.width)),T&&(w=Math.max(w,d.y),S=Math.min(S,d.y+d.height))}}let j=getComputedStyle(o);if(!/^(auto|scroll)$/.test(j.overflowX)&&!/^(auto|scroll)$/.test(j.overflowY))return;let M=Ke(o);if(u<=l||S<=w||!M.width||!M.height)return;let O=vt(e.getBoundingClientRect());return{id:n(o),offsetX:o.scrollLeft,offsetY:o.scrollTop,viewport:M,clip:{x:l,y:w,width:u-l,height:S-w},contentWidth:o.scrollWidth,contentHeight:o.scrollHeight,frame:{...O,x:O.x-M.x+o.scrollLeft,y:O.y-M.y+o.scrollTop}}};var Ge=e=>{let o=globalThis;if(o.Capacitor?.convertFileSrc)return o.Capacitor.convertFileSrc(e);if(!e.startsWith("file:"))return e;if(o.WkWebView?.convertFilePath)return o.WkWebView.convertFilePath(e);throw new Error("Native UI file URL requires a host resource handler")};var ce=e=>new Promise((o,n)=>{let f=setTimeout(()=>n(new Error("Native UI bridge timed out")),5e3);e.then(o,n).finally(()=>clearTimeout(f))}),Ne=async e=>{try{return await ce(e)}catch(o){throw e.then(n=>n.remove()).catch(()=>{}),o}};var Ue=async(e,o)=>{let n=new Map;for(let w of e.update??[])n.set(w,{updated:!0});for(let w of["native","web","none"])for(let u of e.projection?.[w]??[]){let S=n.get(u)??{updated:!1};if(S.destination&&S.destination!==w)throw new TypeError(`Projection event "${u}" has conflicting destinations`);n.set(u,{...S,destination:w})}let f=!1,v=[],c=async()=>{f=!0;let u=(await Promise.allSettled(v.splice(0).map(S=>Promise.resolve().then(()=>S.remove())))).find(S=>S.status==="rejected");if(u?.status==="rejected")throw u.reason},l=[...n].map(async([w,u])=>{let S=await Ne(Promise.resolve().then(()=>e.addListener(w,j=>{!f&&(!e.accepts||e.accepts(j))&&o(u.destination,u.updated)})));f?await S.remove():v.push(S)});try{return await Promise.all(l),{remove:c}}catch(w){throw await c().catch(()=>{}),w}};var Je=`
1
+ "use strict";var WebViewNativeUIEngineRuntime=(()=>{var Ve=Object.defineProperty;var st=Object.getOwnPropertyDescriptor;var at=Object.getOwnPropertyNames;var ct=Object.prototype.hasOwnProperty;var lt=(e,o)=>{for(var n in o)Ve(e,n,{get:o[n],enumerable:!0})},dt=(e,o,n,p)=>{if(o&&typeof o=="object"||typeof o=="function")for(let v of at(o))!ct.call(e,v)&&v!==n&&Ve(e,v,{get:()=>o[v],enumerable:!(p=st(o,v))||p.enumerable});return e};var ut=e=>dt(Ve({},"__esModule",{value:!0}),e);var xt={};lt(xt,{hide:()=>Mt,notify:()=>bt,receive:()=>Tt,show:()=>Lt,start:()=>jt,stop:()=>St});var ft=Symbol.for("webview-native-ui-engine.projection-placement");var De=e=>e?.[ft];var pt=(e,o)=>{if(e.matches("ion-toast, ion-menu"))return!1;let n=e;if(n.showBackdrop===!1)return!1;if(!e.matches("ion-modal"))return!0;let p=o??n.initialBreakpoint;return p===void 0||p>(n.backdropBreakpoint??0)},mt=Symbol.for("@webview-native-ui/engine/overlays/v1"),vt=e=>{let o=new Set,n=new Set,p=new Set,v=new WeakMap,l=new WeakSet,d=new Map,E=[],u={},S=new Map,M,T=h=>{for(let c of[...p])try{c(h)}catch(y){console.error("Native UI overlay listener failed",y)}},N=(h,c,y)=>{c==="willPresent"||c==="didPresent"?(l.delete(h),o.add(h)):c==="didDismiss"&&(l.add(h),o.delete(h),n.delete(h),v.delete(h));let a=y?.detail?.breakpoint;typeof a=="number"&&a>0&&v.set(h,a),T({element:h,phase:c,event:y})},O=(h=!1)=>{let c=!1;for(let y of o)(!y.isConnected||y.ownerDocument!==e||!E.some(({selector:a})=>y.matches(a)))&&(o.delete(y),n.delete(y),c=!0);for(let y of e.querySelectorAll(E.map(({selector:a})=>a).join(",")))!o.has(y)&&!l.has(y)&&(h||!y.matches("ion-popover"))&&(y.presented||y.classList.contains("show-menu"))&&(o.add(y),c=!0);c&&T({phase:"change"})};return{get active(){return o},subscribe(h){return p.add(h),()=>{p.delete(h)}},setNative(h,c){n.has(h)!==c&&(c?n.add(h):n.delete(h),T({element:h,phase:"change"}))},isExcluded(h){return!!u.exclude&&h.matches(u.exclude)},isNative(h){return n.has(h)},get stack(){let h=[...o].filter(y=>y.isConnected&&y.ownerDocument===e),c=y=>{let a=Number.parseFloat(e.defaultView.getComputedStyle(y).zIndex);return Number.isFinite(a)?a:y.overlayIndex??0};return h.sort((y,a)=>c(y)-c(a)),h},isCovered(h){let c=this.stack,y=c.reduce((a,U,j)=>U.contains(h)?j:a,-1);return c.some((a,U)=>{if(n.has(a)||u.exclude&&a.matches(u.exclude))return!1;let j=u.covers?.(a,h);return j!==void 0?j:U>y&&!a.contains(h)&&(a.matches("ion-menu")||pt(a,v.get(a)))})},enable(h,c){let y={...u,...c},a=[...h,...y.additional??[]];y.exclude&&e.querySelector(y.exclude);let U=new Map;for(let m of a){e.querySelector(m.selector);for(let[A,I]of Object.entries(m.events)){let F=U.get(I);if(F&&F.phase!==A)throw new TypeError(`Overlay event "${I}" has conflicting phases`);U.set(I,{phase:A,selector:F?`${F.selector}, ${m.selector}`:m.selector})}}u=y,E=a,S=U;for(let m of S.keys()){if(d.has(m))continue;let A=I=>{let F=S.get(m),q=I.composedPath().find(W=>W instanceof e.defaultView.HTMLElement&&W.matches(F.selector));q&&N(q,F.phase,I)};e.addEventListener(m,A,!0),d.set(m,()=>e.removeEventListener(m,A,!0))}for(let[m,A]of d)S.has(m)||(A(),d.delete(m));let j=!M;M||(M=new MutationObserver(()=>O()),M.observe(e.documentElement,{childList:!0,subtree:!0}),e.addEventListener("nativeUIOverlayAdopted",m=>{let A=m.detail;A?.ownerDocument===e&&N(A,"willPresent",m)})),O(j),(j||c)&&T({phase:"change"})}}},Ke=e=>{let o=e;return o[mt]??=vt(e)};function*fe(e){let o=e;for(;o;){let n=o.getRootNode();o=o.assignedSlot??o.parentElement??(n instanceof ShadowRoot?n.host:null),o&&(yield o)}}var ht=({x:e,y:o,width:n,height:p})=>({x:e,y:o,width:n,height:p}),Ge=e=>{let o=e.getBoundingClientRect(),n=getComputedStyle(e),p=parseFloat(n.borderLeftWidth)||0,v=parseFloat(n.borderTopWidth)||0;return{x:o.left+p,y:o.top+v,width:o.width-p-(parseFloat(n.borderRightWidth)||0),height:o.height-v-(parseFloat(n.borderBottomWidth)||0)}},Xe=(e,o,n)=>{let p=[e,...fe(e)],v=p.indexOf(o);if(v<=0||o===e.ownerDocument.scrollingElement)return;let l=e.ownerDocument.defaultView;if(l.visualViewport&&(l.visualViewport.scale!==1||l.visualViewport.offsetLeft||l.visualViewport.offsetTop))return;let d=0,E=0,u=l.innerWidth,S=l.innerHeight;for(let[O,h]of p.entries()){let c=getComputedStyle(h);if(c.transform!=="none"&&!new DOMMatrixReadOnly(c.transform).isIdentity||c.zoom&&c.zoom!=="normal"&&Number(c.zoom)!==1||[c.translate,c.rotate,c.scale,c.perspective].some(j=>j&&j!=="none")||c.writingMode&&c.writingMode!=="horizontal-tb"||O<v&&/^(fixed|sticky)$/.test(c.position))return;if(O===0)continue;if(c.scrollbarGutter&&c.scrollbarGutter!=="auto")return;let y=/^(auto|scroll|hidden|clip)$/.test(c.overflowX),a=/^(auto|scroll|hidden|clip)$/.test(c.overflowY);if(O<v&&(y||a))return;let U=h===e.ownerDocument.scrollingElement;if(O>v&&((y||U)&&h.scrollWidth>h.clientWidth||(a||U)&&h.scrollHeight>h.clientHeight)||(y||a)&&[c.borderTopLeftRadius,c.borderTopRightRadius,c.borderBottomLeftRadius,c.borderBottomRightRadius].some(j=>parseFloat(j)>0)||c.clipPath&&c.clipPath!=="none"||c.maskImage&&c.maskImage!=="none")return;if(O>=v){let j=Ge(h);y&&(d=Math.max(d,j.x),u=Math.min(u,j.x+j.width)),a&&(E=Math.max(E,j.y),S=Math.min(S,j.y+j.height))}}let M=getComputedStyle(o);if(!/^(auto|scroll)$/.test(M.overflowX)&&!/^(auto|scroll)$/.test(M.overflowY))return;let T=Ge(o);if(u<=d||S<=E||!T.width||!T.height)return;let N=ht(e.getBoundingClientRect());return{id:n(o),offsetX:o.scrollLeft,offsetY:o.scrollTop,viewport:T,clip:{x:d,y:E,width:u-d,height:S-E},contentWidth:o.scrollWidth,contentHeight:o.scrollHeight,frame:{...N,x:N.x-T.x+o.scrollLeft,y:N.y-T.y+o.scrollTop}}};var Je=e=>{let o=globalThis;if(o.Capacitor?.convertFileSrc)return o.Capacitor.convertFileSrc(e);if(!e.startsWith("file:"))return e;if(o.WkWebView?.convertFilePath)return o.WkWebView.convertFilePath(e);throw new Error("Native UI file URL requires a host resource handler")};var ce=e=>new Promise((o,n)=>{let p=setTimeout(()=>n(new Error("Native UI bridge timed out")),5e3);e.then(o,n).finally(()=>clearTimeout(p))}),Ue=async e=>{try{return await ce(e)}catch(o){throw e.then(n=>n.remove()).catch(()=>{}),o}};var Ie=async(e,o)=>{let n=new Map;for(let E of e.update??[])n.set(E,{updated:!0});for(let E of["native","web","none"])for(let u of e.projection?.[E]??[]){let S=n.get(u)??{updated:!1};if(S.destination&&S.destination!==E)throw new TypeError(`Projection event "${u}" has conflicting destinations`);n.set(u,{...S,destination:E})}let p=!1,v=[],l=async()=>{p=!0;let u=(await Promise.allSettled(v.splice(0).map(S=>Promise.resolve().then(()=>S.remove())))).find(S=>S.status==="rejected");if(u?.status==="rejected")throw u.reason},d=[...n].map(async([E,u])=>{let S=await Ue(Promise.resolve().then(()=>e.addListener(E,M=>{!p&&(!e.accepts||e.accepts(M))&&o(u.destination,u.updated)})));p?await S.remove():v.push(S)});try{return await Promise.all(d),{remove:l}}catch(E){throw await l().catch(()=>{}),E}};var Ze=`
2
2
  :is([data-native-ui-snapshot-source], [data-native-ui-snapshot-prepared]),
3
3
  :is([data-native-ui-snapshot-source], [data-native-ui-snapshot-prepared]) *,
4
4
  :is([data-native-ui-snapshot-source], [data-native-ui-snapshot-prepared])::after,
@@ -10,5 +10,5 @@
10
10
  }
11
11
  [data-native-ui-snapshot-visible] { opacity:1!important;overflow:visible!important; }
12
12
  [data-native-ui-snapshot-visible][data-native-ui-snapshot][data-native-ui-snapshot]::before { opacity:1!important; }
13
- `;var ht=(e,o=!1)=>JSON.stringify(e.map(({control:n})=>[n.id,n.kind,n.placement,o?0:n.x,o?0:n.y,n.width,n.height,n.dark,n.rtl])),Ze=(e,o,n=o.getComputedStyle(e))=>{let f=e.getBoundingClientRect(),v=(j,M)=>{let O=parseFloat(j);return n.display!=="inline"&&Number.isFinite(O)?O+(n.boxSizing==="border-box"?0:M.reduce((R,m)=>R+(parseFloat(n.getPropertyValue(m))||0),0)):NaN},c=v(n.width,["padding-left","padding-right","border-left-width","border-right-width"]),l=v(n.height,["padding-top","padding-bottom","border-top-width","border-bottom-width"]),w=1;if(!(c>0&&l>0))for(let j of[e,...ae(e)]){let M=(j===e?n:o.getComputedStyle(j)).getPropertyValue("zoom");w*=(parseFloat(M)||1)/(M.endsWith("%")?100:1)}let u=c>0?f.width/c:w,S=l>0?f.height/l:w;return{x:f.x,y:f.y,scaleX:u||1,scaleY:S||1,left:(parseFloat(n.borderLeftWidth)||0)-e.scrollLeft,top:(parseFloat(n.borderTopWidth)||0)-e.scrollTop,position:n.position}},yt=async(e,o,n)=>{let f=n.captureDelayMs??50;if(!Number.isFinite(f)||f<0||f>2147483647)throw new RangeError("captureDelayMs must be a finite, nonnegative timer interval");let v="native",c=e.element.ownerDocument,l=c.defaultView,w=Array.from(l.crypto.getRandomValues(new Uint32Array(4)),t=>t.toString(16)).join("-"),u=t=>t.isConnected&&t.ownerDocument===c,S=t=>!!t?.isConnected&&t.ownerDocument===c,j=o.send.bind(o),M="data-native-ui-snapshot",O=`${e.namespace}:sources-change`,R=new Set,m=new Set,p=new Set,i=new WeakMap,T=0,N=t=>JSON.stringify(t.map(a=>(i.has(a.scope)||i.set(a.scope,++T),[i.get(a.scope),ht([a],!!n.opaqueUnderlay)]))),d=new Map,W=t=>{let a=t.getRootNode();return a.nodeType===11&&"host"in a?a:c},$=t=>{let a=d.get(t);if(!a){let y=c.createElement("style"),r=c.createElement("style");y.setAttribute("data-native-ui-snapshot-base",""),r.setAttribute(M,""),y.textContent=Je,(t.nodeType===11?t:t.head).append(y,r),a={base:y,image:r},d.set(t,a)}return a.image},A=()=>`${l.innerWidth}:${l.innerHeight}:${l.devicePixelRatio}`,F=!1,C=!1,X=0,ue=0,P,g,ie=!1,U=!1,pe=0,ge=0,D=0,re=0,B=0,Me=-1,J=!1,we=!1,Y,be=new Set,_=(t,a,y)=>{let r=()=>{be.delete(r)&&j({action:t,token:a}).catch(()=>{})};be.add(r),y&&!J?l.requestAnimationFrame(()=>l.requestAnimationFrame(r)):r()},se=new Set,Ee=()=>{se.forEach(t=>p.delete(t)),se.clear()},Z=(t,a=!1)=>{!t||t===P||t===g||(t.images.forEach(y=>{y.src=""}),_("release",t.data.token,a))},Se=t=>t.filter(a=>{if(!S(a.scope.element)||![a.element,...a.sources??[]].every(u))return!1;if(a.control.scroll){let y=a.element.getBoundingClientRect(),r=a.control.scroll.clip;if(y.right<=r.x||y.bottom<=r.y||y.left>=r.x+r.width||y.top>=r.y+r.height)return!1}return n.eligible?.(a)??!0}),fe=async()=>{if(re=0,J||v!=="native"||we||ie||g||n.blocked()||!Y||P?.revision===Y.revision&&Me===B)return;let{revision:t,candidates:a}=Y,y=D,r=B,L=A(),x=Se(a);if(!x.length)return;we=!0;let k,G=!1,ee=[];try{let te=!1,he=j({action:"prepare",revision:n.captureRevision?.()??t,viewportWidth:l.innerWidth,ids:x.map(b=>b.control.id)});he.then(b=>{te&&b.token&&j({action:"release",token:b.token}).catch(()=>{})}).catch(()=>{});try{k=await ce(he)}finally{te=!0}if(!k.token||!k.parts?.length)return;let ye=new Set(x.map(b=>b.control.id));if(k.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(V=>!ye.has(V))||![b.x,b.y,b.width,b.height].every(Number.isFinite)||b.width<=0||b.height<=0)||new Set(k.parts.flatMap(b=>b.ids)).size!==ye.size||k.parts.some(b=>new Set(b.ids.map(V=>x.find(Ie=>Ie.control.id===V).scope)).size!==1)||(await ce(Promise.all(k.parts.map(async b=>{let V=c.createElement("img");return ee.push(V),V.src=Ge(b.url),await V.decode(),V}))),J||v!=="native"||ie||g||n.blocked()||D!==y||A()!==L||Y?.revision!==t||x.some(b=>!S(b.scope.element)||![b.element,...b.sources??[]].every(u))))return;let Le=P;P={data:k,images:ee,sources:Array.from(new Set(x.flatMap(b=>[b.element,...b.sources??[]]))),targets:k.parts.map(b=>x.find(V=>b.ids.includes(V.control.id)).element),scopes:k.parts.map(b=>x.find(V=>b.ids.includes(V.control.id)).scope),parents:k.parts.map(b=>x.find(V=>b.ids.includes(V.control.id)).scope.element.parentNode),frames:[],viewport:L,revision:t,layout:N(x)},Ee(),P.sources.forEach(b=>{p.add(b),se.add(b)}),Re(),n.opaqueUnderlay&&j({action:"prepared",token:k.token}).catch(()=>{}),l.dispatchEvent(new Event(O)),Me=r,G=!0,Z(Le)}catch{}finally{G||ee.forEach(te=>{te.src=""}),k?.token&&!G&&j({action:"release",token:k.token}).catch(()=>{}),we=!1,Y&&(Y.revision!==t||B!==r)&&ne()}},ne=()=>{l.clearTimeout(re),!J&&v==="native"&&!g&&!ie&&!n.blocked()&&(re=l.setTimeout(()=>{fe()},f))},Pe,Ce=(t,a)=>{if(a.some(r=>r.scope.element.ownerDocument!==c||[r.element,...r.sources??[]].some(L=>L.ownerDocument!==c)))throw new TypeError("All projection sources and fallback scopes must share one Document");if(n.blocked())return;!g&&P&&P.layout!==N(Se(a))&&ve();let y=N(a);Pe!==y&&(Pe=y,B++,D++),Y?.revision!==t&&D++,Y={revision:t,candidates:a},(P?.revision!==t||Me!==B)&&ne()},me=t=>{!g&&P&&t&&Y?.candidates.some(a=>a.scrollElement===t&&P.sources.includes(a.element))&&ve(),g&&(He(),De()),B++,D++,ne()},Oe=await Ne(o.listen(({active:t})=>{ie=t,D++,l.clearTimeout(re),t||ne()})),je=new Set,Te=t=>{je.delete(t)&&t.removeAttribute("data-native-ui-snapshot-prepared"),t.removeAttribute("data-native-ui-snapshot-visible"),t.removeAttribute(M),t.removeAttribute("data-native-ui-snapshot-source")},s=()=>{ue++,l.cancelAnimationFrame(X),l.cancelAnimationFrame(xe),xe=0,q.clear(),X=0,F=!1,C=!1,Ee(),g?.sources.forEach(t=>{R.delete(t),m.delete(t)}),z.forEach(Te),z.clear(),d.forEach(({base:t,image:a})=>{t.remove(),a.remove()}),d.clear()},h=(t=g,a=U)=>{if(g!==t)return;let y=new Set([g,P]);s(),g=void 0,P=void 0,U=!1,l.clearTimeout(pe),y.forEach(r=>Z(r,a)),n.wake()},E=()=>{if(!g)return;if(P!==g){h();return}let t=g;s(),g=void 0,U=!1,l.clearTimeout(pe),_("restored",t.data.token,!0),t.sources.forEach(a=>{p.add(a),se.add(a)}),Re(),n.wake()},K=()=>{U&&E(),be.forEach(t=>t())},I=t=>t.scopes.map(a=>S(a.element)?a.element:void 0),z=new Set,Q=new Map,q=new Map,xe=0,He=()=>{for(let[t,a]of q){if(!t.isConnected)continue;let y=l.getComputedStyle(t),r=`${a.x-(parseFloat(y.borderLeftWidth)||0)+t.scrollLeft}px`,L=`${a.y-(parseFloat(y.borderTopWidth)||0)+t.scrollTop}px`;a.style.left!==r&&a.style.setProperty("left",r,"important"),a.style.top!==L&&a.style.setProperty("top",L,"important")}},De=()=>{if(xe||!g)return;[...q.keys()].some(a=>a.getAnimations?.().some(y=>y.playState==="running"&&y.effect?.getKeyframes().some(r=>["borderLeftWidth","borderTopWidth","borderWidth"].some(L=>L in r))))&&(xe=l.requestAnimationFrame(()=>{xe=0,He(),De()}))},Re=()=>{let t=g??P;if(!t||U)return;if(!t.sources.every(u)||I(t).some(r=>!r)){ve();return}let a=I(t);if(g){if(a.some(L=>!L?.isConnected||!d.has(W(L)))){h(g,!1);return}let r=new Set;for(let[L,x]of t.targets.entries()){let k=Q.get(x),G=a[L];!k||!G?.isConnected||(G.setAttribute(M,k),G.setAttribute("data-native-ui-snapshot-source",""),G.toggleAttribute("data-native-ui-snapshot-visible",C),r.add(G))}for(let L of z)r.has(L)||Te(L);z.clear(),r.forEach(L=>z.add(L));return}Q.clear(),q.clear(),z.forEach(Te),z.clear();let y=new Map;for(let r of new Set(a)){if(!r)continue;z.add(r);let L=$(W(r)),x=y.get(L);x||(x={rules:[],positions:[]},y.set(L,x));let{rules:k,positions:G}=x;r!==t.targets[a.indexOf(r)]&&!r.hasAttribute("data-native-ui-snapshot-prepared")&&(r.setAttribute("data-native-ui-snapshot-prepared",""),je.add(r)),r.toggleAttribute("data-native-ui-snapshot-visible",!!g||!!n.opaqueUnderlay),g&&r.setAttribute("data-native-ui-snapshot-source","");let ee=a.flatMap((H,oe)=>H===r?[oe]:[]),te=l.getComputedStyle(r);{let H=Ze(r,l,te);ee.forEach(oe=>{let Fe=t.data.parts[oe];n.opaqueUnderlay&&t.frames[oe]||(t.frames[oe]={x:n.opaqueUnderlay?0:(Fe.x-H.x)/H.scaleX,y:n.opaqueUnderlay?0:(Fe.y-H.y)/H.scaleY,width:Fe.width/H.scaleX,height:Fe.height/H.scaleY})})}let he=ee.map(H=>t.frames[H]),ye=Math.min(...he.map(H=>H.x)),Le=Math.min(...he.map(H=>H.y)),b=Math.max(...he.map(H=>H.x+H.width)),V=Math.max(...he.map(H=>H.y+H.height)),Ie=(parseFloat(te.borderLeftWidth)||0)-r.scrollLeft,ot=(parseFloat(te.borderTopWidth)||0)-r.scrollTop,Ae=`${w}-${ee[0]}`;ee.forEach(H=>Q.set(t.targets[H],Ae)),r.setAttribute(M,Ae),k.push(`[${M}="${Ae}"][data-native-ui-snapshot-visible] { ${te.position==="static"?"position:relative!important;":""} }`);let rt=ee.map(H=>{let oe=t.frames[H];return`url(${JSON.stringify(t.images[H].src)}) ${oe.x-ye}px ${oe.y-Le}px / ${oe.width}px ${oe.height}px no-repeat`}),ke=c.createElement("span").style;ke.cssText=`left:${ye-Ie}px;top:${Le-ot}px;width:${b-ye}px;height:${V-Le}px;background:${rt.join(",")};`;for(let H of Array.from(ke))ke.setProperty(H,ke.getPropertyValue(H),"important");k.push(`[${M}="${Ae}"][${M}][${M}]::before { ${ke.cssText} }`),G.push({target:r,x:ye,y:Le})}t.parents=t.scopes.map(r=>r.element.parentNode);for(let[r,{rules:L,positions:x}]of y)r.textContent=L.join(`
14
- `),x.forEach(({target:k,x:G,y:ee},te)=>q.set(k,{x:G,y:ee,style:r.sheet.cssRules[te*2+1].style}))},Xe=()=>{if(K(),J||v==="none"||g)return;let t=P;if(!t||t.viewport!==A()||!t.sources.every(u)||n.current&&!n.current(t.targets)||t.targets.some(r=>!Q.has(r))||I(t).some(r=>!r?.isConnected)||[...z].some(r=>!r.isConnected))return;t.scopes.some((r,L)=>r.element.parentNode!==t.parents[L])&&Re(),He();let a=++ue,y=()=>ue===a;F=!0,C=!!n.opaqueUnderlay,g=t,D++,l.clearTimeout(re),t.sources.forEach(r=>{R.add(r)}),z.forEach(r=>{r.setAttribute("data-native-ui-snapshot-source",""),r.toggleAttribute("data-native-ui-snapshot-visible",C)}),X=l.requestAnimationFrame(()=>{X=0,y()&&(F=!1,n.wake())}),ce(j({action:"cover",token:t.data.token,...n.transient?{transient:!0}:{}})).then(r=>{if(y()){if(F=!1,r?.shown!==!0){h(t,!1);return}U||(C=!0,t.sources.forEach(L=>m.add(L)),Re(),He(),De()),l.cancelAnimationFrame(X),X=l.requestAnimationFrame(()=>{X=0,y()&&j({action:"painted",token:t.data.token}).catch(()=>{y()&&h(t,!1)})}),n.wake()}}).catch(()=>{y()&&h(t,!1)})},Ye=()=>{if(!(!g||J||U)){if(!g.sources.every(u)||I(g).some(t=>!t)||n.current&&!n.current(g.targets)){h(g,!1);return}if(!n.blocked()){if(n.transient){let t=g,a=I(t);if(a.some(r=>!r?.isConnected)){h(t,!1);return}let y=a.map((r,L)=>{let x=Ze(r,l),k=t.frames[L];return{...t.data.parts[L],x:x.x+k.x*x.scaleX,y:x.y+k.y*x.scaleY,width:k.width*x.scaleX,height:k.height*x.scaleY}});y.some((r,L)=>["x","y","width","height"].some(x=>r[x]!==t.data.parts[L][x]))&&(n.opaqueUnderlay?t.data={...t.data,parts:y}:P=void 0),j({action:"restore",token:t.data.token,viewportWidth:l.innerWidth,parts:y}).catch(()=>{})}ge=n.revision?.()??Y?.revision??0,U=!0,g.sources.forEach(t=>R.delete(t)),pe=l.setTimeout(()=>{U&&h(g,!1)},250),n.wake()}}},nt=(t,a,y)=>{!U||!g||y===void 0||y<=ge||!n.transient&&t||g.data.parts.every(r=>r.ids.every(L=>a?.includes(L)))&&(E(),ne())},ve=()=>{be.forEach(a=>a()),D++,l.clearTimeout(re);let t=P;P=void 0,Z(t),g?h(g,!1):(s(),Q.clear(),l.dispatchEvent(new Event(O)))},qe;try{n.events&&(qe=await Ue(n.events,(t,a)=>{if(!J){if(t&&(v=t),v==="none"){ve();return}t==="web"&&Xe(),t==="native"&&(Ye(),ne()),a&&me()}}))}catch(t){throw J=!0,ve(),await ce(Promise.resolve(Oe.remove())).catch(()=>{}),t}return{get owners(){return[...R]},get visibleOwners(){return[...m]},get preparedOwners(){return[...p]},consider:Ce,changed:me,moved:()=>{He(),De()},get token(){return U?void 0:g?.data.token},begin:Xe,get restoring(){return U},get handoffPending(){return F},retireRestoration:K,end:Ye,updated:nt,invalidate:ve,async destroy(){J=!0,ve(),await Promise.allSettled([ce(Promise.resolve().then(()=>Oe?.remove())),ce(Promise.resolve().then(()=>qe?.remove()))])}}},Qe=async(e,o,n)=>{let f=await yt(e,o,n),v=f.consider;return Object.assign(f,{consider:(c,l)=>v(c,l.map(w=>({...w,scope:e})))})};var et=(e,o)=>{if(e.nodeType!==1||e.namespaceURI!=="http://www.w3.org/1999/xhtml"||!e.ownerDocument||!("style"in e))throw new TypeError("A Web projection scope requires an HTMLElement fallback");if(e.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 support ::before; use its existing container element");return Object.freeze({element:e,namespace:o})};var tt=async(e,o,n={addListener:async(f,v)=>globalThis.Capacitor.addListener(e.plugin,f,v)})=>{let f="view",v=e.receiveListeners,c=!1,l=!1,w="native",u="native",S=_e(document),j=()=>w==="native"&&d&&S.isCovered(d)?"web":w,M=!1,O=!1,R=!1,m,p,i,T=!1,N=()=>{let s=T;T=!0;try{i?.begin()}finally{T=s}},d,W={},$,A=0,F=()=>{A++,$=void 0;let s=$e(d);s?.owner===W&&(s.projected=!1,s.owner=void 0)},C={listen:s=>o.listen(s),send:s=>{if(!e.placementHandoff)return o.send(s);let h=$e(d);if(s.action==="cover"){let Q=++A;return $=s.token,h&&(h.owner=W,h.projected=!1),o.send(s).then(q=>(Q===A&&h===$e(d)&&h?.owner===W&&(h.projected=q?.shown===!0),q)).catch(q=>{throw Q===A&&h?.owner===W&&(F(),h.invalidate()),q})}let E=s.action==="release"&&s.token===$,K=$&&(s.action==="restore"||E||s.action==="reset"||s.action==="visibility"&&s.visible);K&&A++;let I=A,z=()=>{I!==A||h?.owner!==W||(F(),h.invalidate())};try{let Q=K&&h?.owner===W?{...s,token:"token"in s?s.token:$,placement:h.measure()}:s;return o.send(Q).then(q=>(I===A&&(s.action==="resume"||E||s.action==="reset"||s.action==="visibility")&&F(),q)).catch(q=>{throw z(),q})}catch(Q){return z(),Promise.reject(Q)}}},X=0,ue=0,P=0,g=!1,ie=!1,U=!1,pe=!1,ge=document.createElement("style"),D=`data-native-ui-session-${e.id.replace(/[^a-zA-Z0-9-]/g,"")}`;ge.textContent=`[${D}="native"], [${D}="native"] *, [${D}="none"], [${D}="none"] * {visibility:hidden!important}`,document.documentElement.append(ge);let re=()=>{let s=document.querySelectorAll(e.projectionSelector);return s.length===1&&s[0]instanceof HTMLElement?s[0]:void 0},B=()=>{d&&(u==="web"||u==="native"&&O?d.removeAttribute(D):d.setAttribute(D,u))},Me=()=>{if(!d?.isConnected)return[];let s=d.getBoundingClientRect(),h={x:s.x,y:s.y,width:s.width,height:s.height},E=m&&Ve(d,m,()=>e.id);return[{element:d,scrollElement:m,control:{id:f,...h,...E?{scroll:E}:{}}}]},J=async()=>{if(c)return;let s=P,h=e.failedFallback==="native"&&j()==="native"&&!!d?.isConnected;await C.send({action:"visibility",visible:h}).catch(()=>{}),!(c||s!==P)&&(h||u==="none"?B():d?.removeAttribute(D))},we=()=>{if(!M||u!=="native"||!d?.isConnected||i?.token||i?.restoring)return;let s=e.failedFallback==="native";C.send({action:"visibility",visible:s}).catch(()=>{}),s?B():d.removeAttribute(D)},Y=()=>{if(c||T)return;if(we(),u==="web"&&i&&!i.token&&!i.restoring){C.send({action:"visibility",visible:!1}).catch(()=>{}),d?.removeAttribute(D);return}if(g||!i?.restoring||u!=="native")return;g=!0;let s=P,h=i;C.send({action:"resume"}).then(()=>{c||s!==P||h!==i||(O=!1,h.updated(void 0,[f],++X),B(),_())}).catch(()=>{s!==P||c||(h.invalidate(),J())}).finally(()=>{g=!1,Y()})},be=async()=>{if(c||ie||M)return;if(i?.restoring){Y();return}let s=re();if(s!==d){if(P++,F(),d?.removeAttribute(D),await i?.destroy(),i=void 0,c)return;d=s,O=!1,Ee.disconnect(),d&&Ee.observe(d)}if(ne(),u=j(),!d){await C.send({action:"visibility",visible:!1});return}if(!i){ie=!0;let h=P;try{let E=await Qe(et(d,e.id),C,{wake:Y,captureDelayMs:e.captureDelayMs,blocked:()=>u!=="native"||M||O&&!i?.token,revision:()=>X,captureRevision:e.captureMode==="view"?()=>ue:void 0,transient:!0,opaqueUnderlay:e.captureMode==="view"});if(c||h!==P){await E.destroy();return}i=E}finally{ie=!1}}if(!c){if(u==="native"&&O){await C.send({action:"visibility",visible:!1}),B();return}if(u==="native"){let h=P;if(await C.send({action:"visibility",visible:!0}),c||h!==P||u!=="native")return;B(),m=[...ae(d)].find(I=>{let z=getComputedStyle(I);return/auto|scroll/.test(z.overflowX+z.overflowY)&&(I.scrollHeight>I.clientHeight||I.scrollWidth>I.clientWidth)});let E=m&&Ve(d,m,()=>e.id),K=await C.send({action:"track",viewportWidth:innerWidth,...E?{scroll:E}:{}});if(c||h!==P)return;R=K?.tracked===!0,i.consider(e.captureMode==="view"?ue:++X,Me())}else await C.send({action:"visibility",visible:!1}),B()}},_=()=>{c||(U=!0,!(!l||pe)&&(pe=!0,Promise.resolve().then(async()=>{try{for(;U&&!c;)U=!1,await be()}catch{await J()}finally{pe=!1,U&&_()}})))},se=()=>{i?.invalidate(),_()},Ee=new ResizeObserver(se);window.addEventListener("resize",se);let Z=new Set,Se=new WeakSet,fe=s=>{let h=s.composedPath()[0]??s.target;if(!(c||u!=="native"||!d||Se.has(s)||h!==document&&![...ae(d)].includes(h))){if(Se.add(s),R&&h===m){i?.changed(h);return}M?e.captureMode==="view"?i?.moved():i?.changed():((g||i?.restoring)&&P++,M=!0,N(),O=e.failedFallback!=="native",i?.token?d.removeAttribute(D):we()),clearTimeout(p),p=setTimeout(()=>{M=!1,!(c||u!=="native")&&(i?.end(),i?.restoring||_())},100)}},ne=()=>{let s=new Set(d?ae(d):[]),h=s.size!==Z.size||[...s].some(E=>!Z.has(E));for(let E of Z)s.has(E)||(E.removeEventListener("scroll",fe),E.removeEventListener("slotchange",Pe),Z.delete(E));for(let E of s)Z.has(E)||(E.addEventListener("scroll",fe,{passive:!0}),E.addEventListener("slotchange",Pe),Z.add(E));h&&(R=!1,m=void 0,i?.invalidate(),_())},Pe=()=>{ne(),_()};document.addEventListener("scroll",fe,!0);let Ce=new MutationObserver(s=>{ne(),re()!==d?_():d&&s.some(h=>h.type==="childList")&&me(j())});Ce.observe(document.documentElement,{childList:!0,attributes:!0,subtree:!0});let me=(s,h=!1)=>{if(c||!h&&s===u)return;M=!1,clearTimeout(p),u=s,P++;let E=P;u==="none"?C.send({action:"visibility",visible:!1}).then(()=>{u!=="none"||E!==P||c||(i?.invalidate(),B())}).catch(()=>{u!=="none"||E!==P||c||(i?.invalidate(),B())}):u==="web"?(N(),i?.token||C.send({action:"visibility",visible:!1}).catch(()=>{}),B()):u==="native"&&(i?.end(),i?.restoring||_())},Oe=S.subscribe(()=>queueMicrotask(()=>me(j()))),je,Te=async()=>{if(!c){c=!0,F(),P++,Oe(),Ce.disconnect(),Ee.disconnect(),window.removeEventListener("resize",se),document.removeEventListener("scroll",fe,!0);for(let s of Z)s.removeEventListener("scroll",fe),s.removeEventListener("slotchange",Pe);Z.clear(),clearTimeout(p),d?.removeAttribute(D),ge.remove(),await Promise.allSettled([Promise.resolve(je?.remove()),i?.destroy()])}};try{let s=P;je=await Ue({addListener:(E,K)=>n.addListener(E,K),update:v?.update,projection:v?.projection,accepts:E=>!v?.match||Object.entries(v?.match).every(([K,I])=>typeof E=="object"&&E!==null&&E[K]===I)},(E,K)=>{c||(E&&(E==="native"&&(O=!1),w=E,C.send({action:"destination",destination:E}).catch(()=>{}),me(j(),!0)),K&&(ue++,i?.changed(),u==="native"&&_()))});let h=await C.send({action:"connect"});return P===s&&["native","web","none"].includes(h?.destination)&&(w=h.destination),u=j(),l=!0,_(),{destroy:Te,show:()=>{O=!1,w="native",me(j(),!0)},hide:()=>{w=u="none",P++,M=!1,clearTimeout(p),i?.invalidate(),B()}}}catch(s){throw await Te(),s}};var le=new Map,de=new Map,We=new Map,gt=Array.from(crypto.getRandomValues(new Uint32Array(4)),e=>e.toString(16)).join("-"),Be=new Map,wt=(e,o,n)=>Be.get(e)?.get(o)?.(n),bt=0,Et=(e,o)=>new Promise((n,f)=>{let v=`${e}:${gt}:${++bt}`,c=setTimeout(()=>{de.delete(v),f(new Error("Native UI session timed out"))},5e3);de.set(v,{resolve:n,reject:f,timer:c});let l=JSON.stringify({key:v,request:o}),w=globalThis,u=w.webkit?.messageHandlers?.[e]??w[e]??w.nativeUIEngine;if(!u){clearTimeout(c),de.delete(v),f(new Error("Native UI session unavailable"));return}try{u.postMessage(l)}catch(S){clearTimeout(c),de.delete(v),f(S)}}),Pt=(e,o,n,f)=>{if(o===null){We.get(e)?.(n);return}let v=de.get(o);!v||!o.startsWith(`${e}:`)||(de.delete(o),clearTimeout(v.timer),f?v.reject(new Error(f)):v.resolve(n))},Tt=e=>{le.get(e)?.show()},Lt=e=>(le.get(e)?.hide(),!0),Mt=async e=>{let o=le.get(e);le.delete(e),Be.delete(e),We.delete(e);for(let[n,f]of de)n.startsWith(`${e}:`)&&(de.delete(n),clearTimeout(f.timer),f.reject(new Error("Native UI session closed")));await o?.destroy()},St=async e=>{if(le.has(e.id))return;let o,n=!1,f,v={show:()=>{f="native",o?.show()},hide:()=>{f="none",o?.hide()},destroy:async()=>{n=!0,await o?.destroy()}};le.set(e.id,v);try{if(document.readyState==="loading"&&await new Promise(l=>document.addEventListener("DOMContentLoaded",()=>l(),{once:!0})),n)return;let c=new Map;e.runtime==="cordova"&&Be.set(e.id,c),o=await tt(e,{send:l=>Et(e.id,l),listen:async l=>(We.set(e.id,l),{remove:()=>{We.get(e.id)===l&&We.delete(e.id)}})},e.runtime==="cordova"?{addListener:async(l,w)=>(c.set(l,w),{remove:()=>{c.delete(l)}})}:void 0),f==="none"?o.hide():f==="native"&&o.show(),n&&await o.destroy()}catch(c){throw le.get(e.id)===v&&(le.delete(e.id),Be.delete(e.id)),c}};return dt(jt);})();
13
+ `;var gt=(e,o=!1)=>JSON.stringify(e.map(({control:n})=>[n.id,n.kind,n.placement,o?0:n.x,o?0:n.y,n.width,n.height,n.dark,n.rtl])),Qe=(e,o,n=o.getComputedStyle(e))=>{let p=e.getBoundingClientRect(),v=(M,T)=>{let N=parseFloat(M);return n.display!=="inline"&&Number.isFinite(N)?N+(n.boxSizing==="border-box"?0:T.reduce((O,h)=>O+(parseFloat(n.getPropertyValue(h))||0),0)):NaN},l=v(n.width,["padding-left","padding-right","border-left-width","border-right-width"]),d=v(n.height,["padding-top","padding-bottom","border-top-width","border-bottom-width"]),E=1;if(!(l>0&&d>0))for(let M of[e,...fe(e)]){let T=(M===e?n:o.getComputedStyle(M)).getPropertyValue("zoom");E*=(parseFloat(T)||1)/(T.endsWith("%")?100:1)}let u=l>0?p.width/l:E,S=d>0?p.height/d:E;return{x:p.x,y:p.y,scaleX:u||1,scaleY:S||1,left:(parseFloat(n.borderLeftWidth)||0)-e.scrollLeft,top:(parseFloat(n.borderTopWidth)||0)-e.scrollTop,position:n.position}},yt=async(e,o,n)=>{let p=n.captureDelayMs??50;if(!Number.isFinite(p)||p<0||p>2147483647)throw new RangeError("captureDelayMs must be a finite, nonnegative timer interval");let v="native",l=e.element.ownerDocument,d=l.defaultView,E=Array.from(d.crypto.getRandomValues(new Uint32Array(4)),t=>t.toString(16)).join("-"),u=t=>t.isConnected&&t.ownerDocument===l,S=t=>!!t?.isConnected&&t.ownerDocument===l,M=o.send.bind(o),T="data-native-ui-snapshot",N=`${e.namespace}:sources-change`,O=new Set,h=new Set,c=new Set,y=new WeakMap,a=0,U=t=>JSON.stringify(t.map(s=>(y.has(s.scope)||y.set(s.scope,++a),[y.get(s.scope),gt([s],!!n.opaqueUnderlay)]))),j=new Map,m=t=>{let s=t.getRootNode();return s.nodeType===11&&"host"in s?s:l},A=t=>{let s=j.get(t);if(!s){let g=l.createElement("style"),r=l.createElement("style");g.setAttribute("data-native-ui-snapshot-base",""),r.setAttribute(T,""),g.textContent=Ze,(t.nodeType===11?t:t.head).append(g,r),s={base:g,image:r},j.set(t,s)}return s.image},I=()=>`${d.innerWidth}:${d.innerHeight}:${d.devicePixelRatio}`,F=!1,q=!1,W=0,ve=0,R,k,w,le=!1,z=!1,he=0,Pe=0,$=0,se=0,B=0,xe=-1,X=!1,Te=!1,_,Le=new Set,Z=(t,s,g)=>{let r=()=>{Le.delete(r)&&M({action:t,token:s}).catch(()=>{})};Le.add(r),g&&!X?d.requestAnimationFrame(()=>d.requestAnimationFrame(r)):r()},de=new Set,Me=()=>{de.forEach(t=>c.delete(t)),de.clear()},ee=(t,s=!1)=>{!t||t===R||t===w||(t.images.forEach(g=>{g.src=""}),Z("release",t.data.token,s))},He=t=>t.filter(s=>{if(!S(s.scope.element)||![s.element,...s.sources??[]].every(u))return!1;if(s.control.scroll){let g=s.element.getBoundingClientRect(),r=s.control.scroll.clip;if(g.right<=r.x||g.bottom<=r.y||g.left>=r.x+r.width||g.top>=r.y+r.height)return!1}return n.eligible?.(s)??!0}),ge=async()=>{if(se=0,X||v!=="native"||Te||le||w||n.blocked()||!_||R?.revision===_.revision&&xe===B)return;let{revision:t,candidates:s}=_,g=$,r=B,L=I(),x=He(s);if(!x.length)return;Te=!0;let C,Q=!1,ne=[];try{let oe=!1,be=M({action:"prepare",revision:n.captureRevision?.()??t,viewportWidth:d.innerWidth,ids:x.map(P=>P.control.id)});be.then(P=>{oe&&P.token&&M({action:"release",token:P.token}).catch(()=>{})}).catch(()=>{});try{C=await ce(be)}finally{oe=!0}if(!C.token||!C.parts?.length)return;let Ee=new Set(x.map(P=>P.control.id));if(C.parts.some(P=>!P.url.startsWith("file:")&&!/^\/__native_ui_engine__\/nativeUI[a-fA-F0-9]+\/[a-fA-F0-9-]+-[0-9]+\.png$/.test(P.url)||!P.ids.length||P.ids.some(V=>!Ee.has(V))||![P.x,P.y,P.width,P.height].every(Number.isFinite)||P.width<=0||P.height<=0)||new Set(C.parts.flatMap(P=>P.ids)).size!==Ee.size||C.parts.some(P=>new Set(P.ids.map(V=>x.find(Be=>Be.control.id===V).scope)).size!==1)||(await ce(Promise.all(C.parts.map(async P=>{let V=l.createElement("img");return ne.push(V),V.src=Je(P.url),await V.decode(),V}))),X||v!=="native"||le||w||n.blocked()||$!==g||I()!==L||_?.revision!==t||x.some(P=>!S(P.scope.element)||![P.element,...P.sources??[]].every(u))))return;let je=R;R={data:C,images:ne,sources:Array.from(new Set(x.flatMap(P=>[P.element,...P.sources??[]]))),targets:C.parts.map(P=>x.find(V=>P.ids.includes(V.control.id)).element),scopes:C.parts.map(P=>x.find(V=>P.ids.includes(V.control.id)).scope),parents:C.parts.map(P=>x.find(V=>P.ids.includes(V.control.id)).scope.element.parentNode),frames:[],viewport:L,revision:t,layout:U(x)},Me(),R.sources.forEach(P=>{c.add(P),de.add(P)}),Fe(),n.opaqueUnderlay&&M({action:"prepared",token:C.token}).catch(()=>{}),d.dispatchEvent(new Event(N)),xe=r,Q=!0,ee(je)}catch{}finally{Q||ne.forEach(oe=>{oe.src=""}),C?.token&&!Q&&M({action:"release",token:C.token}).catch(()=>{}),Te=!1,_&&(_.revision!==t||B!==r)&&re()}},re=()=>{d.clearTimeout(se),!X&&v==="native"&&!w&&!le&&!n.blocked()&&(se=d.setTimeout(()=>{ge()},p))},Ae,ke=(t,s)=>{if(s.some(r=>r.scope.element.ownerDocument!==l||[r.element,...r.sources??[]].some(L=>L.ownerDocument!==l)))throw new TypeError("All projection sources and fallback scopes must share one Document");if(n.blocked())return;!w&&R&&R.layout!==U(He(s))&&we();let g=U(s);Ae!==g&&(Ae=g,B++,$++),_?.revision!==t&&$++,_={revision:t,candidates:s},(R?.revision!==t||xe!==B)&&re()},Se=t=>{!w&&R&&t&&_?.candidates.some(s=>s.scrollElement===t&&R.sources.includes(s.element))&&we(),w&&(Y(),ae()),B++,$++,re()},Ce=await Ue(o.listen(({active:t})=>{le=t,$++,d.clearTimeout(se),t||re()})),ue=new Set,We=t=>{ue.delete(t)&&t.removeAttribute("data-native-ui-snapshot-prepared"),t.removeAttribute("data-native-ui-snapshot-visible"),t.removeAttribute(T),t.removeAttribute("data-native-ui-snapshot-source")},ye=()=>{ve++,d.cancelAnimationFrame(W),d.cancelAnimationFrame(J),J=0,G.clear(),W=0,F=!1,q=!1,Me(),w?.sources.forEach(t=>{O.delete(t),h.delete(t)}),D.forEach(We),D.clear(),j.forEach(({base:t,image:s})=>{t.remove(),s.remove()}),j.clear()},te=(t=w,s=z)=>{if(w!==t)return;let g=new Set([w,R]);ye(),w=void 0,R=void 0,z=!1,d.clearTimeout(he),g.forEach(r=>ee(r,s)),n.wake()},i=()=>{if(!w)return;if(R!==w){te();return}let t=w;ye(),w=void 0,z=!1,d.clearTimeout(he),Z("restored",t.data.token,!0),t.sources.forEach(s=>{c.add(s),de.add(s)}),Fe(),n.wake()},f=()=>{z&&i(),Le.forEach(t=>t())},b=t=>t.scopes.map(s=>S(s.element)?s.element:void 0),D=new Set,K=new Map,G=new Map,J=0,Y=()=>{for(let[t,s]of G){if(!t.isConnected)continue;let g=d.getComputedStyle(t),r=`${s.x-(parseFloat(g.borderLeftWidth)||0)+t.scrollLeft}px`,L=`${s.y-(parseFloat(g.borderTopWidth)||0)+t.scrollTop}px`;s.style.left!==r&&s.style.setProperty("left",r,"important"),s.style.top!==L&&s.style.setProperty("top",L,"important")}},ae=()=>{if(J||!w)return;[...G.keys()].some(s=>s.getAnimations?.().some(g=>g.playState==="running"&&g.effect?.getKeyframes().some(r=>["borderLeftWidth","borderTopWidth","borderWidth"].some(L=>L in r))))&&(J=d.requestAnimationFrame(()=>{J=0,Y(),ae()}))},Fe=()=>{let t=w??R;if(!t||z)return;if(!t.sources.every(u)||b(t).some(r=>!r)){we();return}let s=b(t);if(w){if(s.some(L=>!L?.isConnected||!j.has(m(L)))){te(w,!1);return}let r=new Set;for(let[L,x]of t.targets.entries()){let C=K.get(x),Q=s[L];!C||!Q?.isConnected||(Q.setAttribute(T,C),Q.setAttribute("data-native-ui-snapshot-source",""),Q.toggleAttribute("data-native-ui-snapshot-visible",q),r.add(Q))}for(let L of D)r.has(L)||We(L);D.clear(),r.forEach(L=>D.add(L));return}K.clear(),G.clear(),D.forEach(We),D.clear();let g=new Map;for(let r of new Set(s)){if(!r)continue;D.add(r);let L=A(m(r)),x=g.get(L);x||(x={rules:[],positions:[]},g.set(L,x));let{rules:C,positions:Q}=x;r!==t.targets[s.indexOf(r)]&&!r.hasAttribute("data-native-ui-snapshot-prepared")&&(r.setAttribute("data-native-ui-snapshot-prepared",""),ue.add(r)),r.toggleAttribute("data-native-ui-snapshot-visible",!!w||!!n.opaqueUnderlay),w&&r.setAttribute("data-native-ui-snapshot-source","");let ne=s.flatMap((H,ie)=>H===r?[ie]:[]),oe=d.getComputedStyle(r);{let H=Qe(r,d,oe);ne.forEach(ie=>{let Ne=t.data.parts[ie];n.opaqueUnderlay&&t.frames[ie]||(t.frames[ie]={x:n.opaqueUnderlay?0:(Ne.x-H.x)/H.scaleX,y:n.opaqueUnderlay?0:(Ne.y-H.y)/H.scaleY,width:Ne.width/H.scaleX,height:Ne.height/H.scaleY})})}let be=ne.map(H=>t.frames[H]),Ee=Math.min(...be.map(H=>H.x)),je=Math.min(...be.map(H=>H.y)),P=Math.max(...be.map(H=>H.x+H.width)),V=Math.max(...be.map(H=>H.y+H.height)),Be=(parseFloat(oe.borderLeftWidth)||0)-r.scrollLeft,rt=(parseFloat(oe.borderTopWidth)||0)-r.scrollTop,$e=`${E}-${ne[0]}`;ne.forEach(H=>K.set(t.targets[H],$e)),r.setAttribute(T,$e),C.push(`[${T}="${$e}"][data-native-ui-snapshot-visible] { ${oe.position==="static"?"position:relative!important;":""} }`);let it=ne.map(H=>{let ie=t.frames[H];return`url(${JSON.stringify(t.images[H].src)}) ${ie.x-Ee}px ${ie.y-je}px / ${ie.width}px ${ie.height}px no-repeat`}),Oe=l.createElement("span").style;Oe.cssText=`left:${Ee-Be}px;top:${je-rt}px;width:${P-Ee}px;height:${V-je}px;background:${it.join(",")};`;for(let H of Array.from(Oe))Oe.setProperty(H,Oe.getPropertyValue(H),"important");C.push(`[${T}="${$e}"][${T}][${T}]::before { ${Oe.cssText} }`),Q.push({target:r,x:Ee,y:je})}t.parents=t.scopes.map(r=>r.element.parentNode);for(let[r,{rules:L,positions:x}]of g)r.textContent=L.join(`
14
+ `),x.forEach(({target:C,x:Q,y:ne},oe)=>G.set(C,{x:Q,y:ne,style:r.sheet.cssRules[oe*2+1].style}))},Ye=()=>{if(f(),X||v==="none"||w)return;let t=R;if(!t||t.viewport!==I()||!t.sources.every(u)||n.current&&!n.current(t.targets)||t.targets.some(r=>!K.has(r))||b(t).some(r=>!r?.isConnected)||[...D].some(r=>!r.isConnected))return;t.scopes.some((r,L)=>r.element.parentNode!==t.parents[L])&&Fe(),Y();let s=++ve,g=()=>ve===s;F=!0,q=!!n.opaqueUnderlay,w=t,$++,d.clearTimeout(se),t.sources.forEach(r=>{O.add(r)}),D.forEach(r=>{r.setAttribute("data-native-ui-snapshot-source",""),r.toggleAttribute("data-native-ui-snapshot-visible",q)}),W=d.requestAnimationFrame(()=>{W=0,g()&&(F=!1,n.wake())}),ce(M({action:"cover",token:t.data.token,...n.transient?{transient:!0}:{}})).then(r=>{if(g()){if(F=!1,r?.shown!==!0){te(t,!1);return}z||(q=!0,t.sources.forEach(L=>h.add(L)),Fe(),Y(),ae()),d.cancelAnimationFrame(W),W=d.requestAnimationFrame(()=>{W=0,g()&&M({action:"painted",token:t.data.token}).catch(()=>{g()&&te(t,!1)})}),n.wake()}}).catch(()=>{g()&&te(t,!1)})},qe=()=>{if(!(!w||X||z)){if(!w.sources.every(u)||b(w).some(t=>!t)||n.current&&!n.current(w.targets)){te(w,!1);return}if(!n.blocked()){if(n.transient){let t=w,s=b(t);if(s.some(r=>!r?.isConnected)){te(t,!1);return}let g=s.map((r,L)=>{let x=Qe(r,d),C=t.frames[L];return{...t.data.parts[L],x:x.x+C.x*x.scaleX,y:x.y+C.y*x.scaleY,width:C.width*x.scaleX,height:C.height*x.scaleY}});g.some((r,L)=>["x","y","width","height"].some(x=>r[x]!==t.data.parts[L][x]))&&(n.opaqueUnderlay?t.data={...t.data,parts:g}:R=void 0),M({action:"restore",token:t.data.token,viewportWidth:d.innerWidth,parts:g}).catch(()=>{})}Pe=n.revision?.()??_?.revision??0,z=!0,w.sources.forEach(t=>O.delete(t)),he=d.setTimeout(()=>{z&&te(w,!1)},250),n.wake()}}},ot=(t,s,g)=>{!z||!w||g===void 0||g<=Pe||!n.transient&&t||w.data.parts.every(r=>r.ids.every(L=>s?.includes(L)))&&(i(),re())},we=(t=!1)=>{Le.forEach(g=>g()),$++,d.clearTimeout(se);let s=R;if(R=void 0,(t||X)&&(k=void 0),n.retainPreparedUntilRelease&&!w&&!t&&!X){if(s){let g={};k=g,ce(M({action:"release",token:s.data.token})).catch(()=>{}).finally(()=>{if(s.images.forEach(r=>{r.src=""}),k===g&&(k=void 0,!(R||w))){for(let r of D)r.getAttribute(T)!==K.get(r)&&(D.delete(r),ue.delete(r));ye(),K.clear(),d.dispatchEvent(new Event(N))}})}if(k)return}ee(s),w?te(w,!1):(ye(),K.clear(),d.dispatchEvent(new Event(N)))},_e;try{n.events&&(_e=await Ie(n.events,(t,s)=>{if(!X){if(t&&(v=t),v==="none"){we();return}t==="web"&&Ye(),t==="native"&&(qe(),re()),s&&Se()}}))}catch(t){throw X=!0,we(),await ce(Promise.resolve(Ce.remove())).catch(()=>{}),t}return{get owners(){return[...O]},get visibleOwners(){return[...h]},get preparedOwners(){return[...c]},consider:ke,changed:Se,moved:()=>{Y(),ae()},get token(){return z?void 0:w?.data.token},begin:Ye,get restoring(){return z},get handoffPending(){return F},retireRestoration:f,end:qe,updated:ot,invalidate:we,async destroy(){X=!0,we(),await Promise.allSettled([ce(Promise.resolve().then(()=>Ce?.remove())),ce(Promise.resolve().then(()=>_e?.remove()))])}}},et=async(e,o,n)=>{let p=await yt(e,o,n),v=p.consider;return Object.assign(p,{consider:(l,d)=>v(l,d.map(E=>({...E,scope:e})))})};var tt=(e,o)=>{if(e.nodeType!==1||e.namespaceURI!=="http://www.w3.org/1999/xhtml"||!e.ownerDocument||!("style"in e))throw new TypeError("A Web projection scope requires an HTMLElement fallback");if(e.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 support ::before; use its existing container element");return Object.freeze({element:e,namespace:o})};var nt=async(e,o,n={addListener:async(p,v)=>globalThis.Capacitor.addListener(e.plugin,p,v)})=>{let p="view",v=e.receiveListeners,l=!1,d=!1,E="native",u="native",S=Ke(document),M=()=>E==="native"&&m&&S.isCovered(m)?"web":E,T=!1,N=!1,O=!1,h=!1,c,y,a,U=!1,j=()=>{let i=U;U=!0;try{a?.begin()}finally{U=i}},m,A={},I,F=0,q=()=>{F++,I=void 0;let i=De(m);i?.owner===A&&(i.projected=!1,i.owner=void 0)},W={listen:i=>o.listen(f=>{i(f),!f.active&&N&&(N=!1,re()),f.precovered&&Ae(f.precovered)}),send:i=>{if(!e.placementHandoff)return o.send(i);let f=De(m);if(i.action==="cover"){let J=I===i.token&&f?.owner===A&&f.projected,Y=++F;return I=i.token,f&&(f.owner=A,f.projected=!!J),o.send(i).then(ae=>(Y===F&&f===De(m)&&f?.owner===A&&(f.projected=ae?.shown===!0),ae)).catch(ae=>{throw Y===F&&f?.owner===A&&(q(),f.invalidate()),ae})}let b=i.action==="release"&&i.token===I,D=I&&(i.action==="restore"||b||i.action==="reset"||i.action==="visibility"&&i.visible);D&&F++;let K=F,G=()=>{K!==F||f?.owner!==A||(q(),f.invalidate())};try{let J=D&&f?.owner===A?{...i,token:"token"in i?i.token:I,placement:f.measure()}:i;return o.send(J).then(async Y=>(i.action==="release"&&Y?.requiresPlacement&&(f&&(!f.owner||f.owner===A)?Y=await o.send({...i,placement:f.measure()}):(await o.send({action:"visibility",visible:!1}),Y=await o.send(i))),K===F&&(i.action==="resume"||b||i.action==="reset"||i.action==="visibility")&&q(),Y)).catch(Y=>{throw G(),Y})}catch(J){return G(),Promise.reject(J)}}},ve=0,R=0,k=0,w=!1,le=!1,z=!1,he=!1,Pe=document.createElement("style"),$=`data-native-ui-session-${e.id.replace(/[^a-zA-Z0-9-]/g,"")}`;Pe.textContent=`[${$}="native"], [${$}="native"] *, [${$}="none"], [${$}="none"] * {visibility:hidden!important}`,document.documentElement.append(Pe);let se=()=>{let i=document.querySelectorAll(e.projectionSelector);return i.length===1&&i[0]instanceof HTMLElement?i[0]:void 0},B=()=>{m&&(u==="web"||u==="native"&&O?m.removeAttribute($):m.setAttribute($,u))},xe=()=>{if(!m?.isConnected)return[];let i=m.getBoundingClientRect(),f={x:i.x,y:i.y,width:i.width,height:i.height},b=c&&Xe(m,c,()=>e.id);return[{element:m,scrollElement:c,control:{id:p,...f,...b?{scroll:b}:{}}}]},X=async()=>{if(l)return;let i=k,f=e.failedFallback==="native"&&M()==="native"&&!!m?.isConnected;await W.send({action:"visibility",visible:f}).catch(()=>{}),!(l||i!==k)&&(f||u==="none"?B():m?.removeAttribute($))},Te=()=>{if(!T||u!=="native"||!m?.isConnected||a?.token||a?.restoring)return;let i=e.failedFallback==="native";W.send({action:"visibility",visible:i}).catch(()=>{}),i?B():m.removeAttribute($)},_=()=>{if(l||U)return;if(Te(),u==="web"&&a&&!a.token&&!a.restoring){W.send({action:"visibility",visible:!1}).catch(()=>{}),m?.removeAttribute($);return}if(w||!a?.restoring||u!=="native")return;w=!0;let i=k,f=a;W.send({action:"resume"}).then(()=>{l||i!==k||f!==a||(O=!1,f.updated(void 0,[p],++ve),B(),Z())}).catch(()=>{i!==k||l||(f.invalidate(),X())}).finally(()=>{w=!1,_()})},Le=async()=>{if(l||le||T)return;if(a?.restoring){_();return}let i=se();if(i!==m){if(k++,q(),m?.removeAttribute($),await a?.destroy(),a=void 0,l)return;m=i,O=!1,Me.disconnect(),m&&Me.observe(m)}if(ke(),u=M(),!m){await W.send({action:"visibility",visible:!1});return}if(!a){le=!0;let f=k;try{let b=await et(tt(m,e.id),W,{wake:_,captureDelayMs:e.captureDelayMs,retainPreparedUntilRelease:e.nativeDragHandoff,blocked:()=>u!=="native"||T||O&&!a?.token,revision:()=>ve,captureRevision:e.captureMode==="view"?()=>R:void 0,transient:!0,opaqueUnderlay:e.captureMode==="view"});if(l||f!==k){await b.destroy();return}a=b}finally{le=!1}}if(!l){if(u==="native"&&O){await W.send({action:"visibility",visible:!1}),B();return}if(u==="native"){let f=k;if(await W.send({action:"visibility",visible:!0}),l||f!==k||u!=="native")return;B(),c=[...fe(m)].find(G=>{let J=getComputedStyle(G);return/auto|scroll/.test(J.overflowX+J.overflowY)&&(G.scrollHeight>G.clientHeight||G.scrollWidth>G.clientWidth)});let b=c&&Xe(m,c,()=>e.id),D=e.nativeDragHandoff&&e.captureMode==="view"&&c?{viewport:c.getBoundingClientRect(),offsetX:c.scrollLeft,offsetY:c.scrollTop,rangeX:Math.max(0,c.scrollWidth-c.clientWidth),rangeY:Math.max(0,c.scrollHeight-c.clientHeight)}:void 0,K=await W.send({action:"track",viewportWidth:innerWidth,...b?{scroll:b}:{},...D?{gesture:D}:{}});if(l||f!==k)return;h=K?.tracked===!0,a.consider(e.captureMode==="view"?R:++ve,xe())}else await W.send({action:"visibility",visible:!1}),B()}},Z=()=>{l||(z=!0,!(!d||he)&&(he=!0,Promise.resolve().then(async()=>{try{for(;z&&!l;)z=!1,await Le()}catch{await X()}finally{he=!1,z&&Z()}})))},de=()=>{a?.invalidate(),Z()},Me=new ResizeObserver(de);window.addEventListener("resize",de);let ee=new Set,He=new WeakSet,ge=i=>{let f=i.composedPath()[0]??i.target;if(!(l||u!=="native"||!m||He.has(i)||f!==document&&![...fe(m)].includes(f))){if(He.add(i),h&&f===c){a?.changed(f);return}T?e.captureMode==="view"?a?.moved():a?.changed():((w||a?.restoring)&&k++,T=!0,j(),O=e.failedFallback!=="native",a?.token?m.removeAttribute($):Te()),re()}};function re(){clearTimeout(y),y=setTimeout(()=>{N||(T=!1,!(l||u!=="native")&&(a?.end(),a?.restoring||Z()))},100)}function Ae(i){if(l||u!=="native"||!m?.isConnected||!a||(N=!0,a.token))return;(w||a.restoring)&&k++,I=i;let f=De(m);if(f&&(f.owner=A,f.projected=!0),T=!0,j(),!a.token){T=!1,X();return}re()}let ke=()=>{let i=new Set(m?fe(m):[]),f=i.size!==ee.size||[...i].some(b=>!ee.has(b));for(let b of ee)i.has(b)||(b.removeEventListener("scroll",ge),b.removeEventListener("slotchange",Se),ee.delete(b));for(let b of i)ee.has(b)||(b.addEventListener("scroll",ge,{passive:!0}),b.addEventListener("slotchange",Se),ee.add(b));f&&(h=!1,c=void 0,a?.invalidate(),Z())},Se=()=>{ke(),Z()};document.addEventListener("scroll",ge,!0);let Ce=new MutationObserver(i=>{ke(),se()!==m?Z():m&&i.some(f=>f.type==="childList")&&ue(M())});Ce.observe(document.documentElement,{childList:!0,attributes:!0,subtree:!0});let ue=(i,f=!1)=>{if(l||!f&&i===u)return;T=!1,N=!1,clearTimeout(y),u=i,k++;let b=k;u==="none"?W.send({action:"visibility",visible:!1}).then(()=>{u!=="none"||b!==k||l||(a?.invalidate(!0),B())}).catch(()=>{u!=="none"||b!==k||l||(a?.invalidate(!0),B())}):u==="web"?(j(),a?.token||W.send({action:"visibility",visible:!1}).catch(()=>{}),B()):u==="native"&&(a?.end(),a?.restoring||Z())},We=S.subscribe(()=>queueMicrotask(()=>ue(M()))),ye,te=async()=>{if(!l){l=!0,q(),k++,We(),Ce.disconnect(),Me.disconnect(),window.removeEventListener("resize",de),document.removeEventListener("scroll",ge,!0);for(let i of ee)i.removeEventListener("scroll",ge),i.removeEventListener("slotchange",Se);ee.clear(),clearTimeout(y),m?.removeAttribute($),Pe.remove(),await Promise.allSettled([Promise.resolve(ye?.remove()),a?.destroy()])}};try{let i=k;ye=await Ie({addListener:(b,D)=>n.addListener(b,D),update:v?.update,projection:v?.projection,accepts:b=>!v?.match||Object.entries(v?.match).every(([D,K])=>typeof b=="object"&&b!==null&&b[D]===K)},(b,D)=>{l||(b&&(b==="native"&&(O=!1),E=b,W.send({action:"destination",destination:b}).catch(()=>{}),ue(M(),!0)),D&&(R++,a?.changed(),u==="native"&&Z()))});let f=await W.send({action:"connect"});return k===i&&["native","web","none"].includes(f?.destination)&&(E=f.destination),u=M(),d=!0,Z(),{destroy:te,show:()=>{O=!1,E="native",ue(M(),!0)},hide:()=>{E=u="none",k++,T=!1,N=!1,clearTimeout(y),a?.invalidate(!0),B()}}}catch(i){throw await te(),i}};var pe=new Map,me=new Map,Re=new Map,wt=Array.from(crypto.getRandomValues(new Uint32Array(4)),e=>e.toString(16)).join("-"),ze=new Map,bt=(e,o,n)=>ze.get(e)?.get(o)?.(n),Et=0,Pt=(e,o)=>new Promise((n,p)=>{let v=`${e}:${wt}:${++Et}`,l=setTimeout(()=>{me.delete(v),p(new Error("Native UI session timed out"))},5e3);me.set(v,{resolve:n,reject:p,timer:l});let d=JSON.stringify({key:v,request:o}),E=globalThis,u=E.webkit?.messageHandlers?.[e]??E[e]??E.nativeUIEngine;if(!u){clearTimeout(l),me.delete(v),p(new Error("Native UI session unavailable"));return}try{u.postMessage(d)}catch(S){clearTimeout(l),me.delete(v),p(S)}}),Tt=(e,o,n,p)=>{if(o===null){Re.get(e)?.(n);return}let v=me.get(o);!v||!o.startsWith(`${e}:`)||(me.delete(o),clearTimeout(v.timer),p?v.reject(new Error(p)):v.resolve(n))},Lt=e=>{pe.get(e)?.show()},Mt=e=>(pe.get(e)?.hide(),!0),St=async e=>{let o=pe.get(e);pe.delete(e),ze.delete(e),Re.delete(e);for(let[n,p]of me)n.startsWith(`${e}:`)&&(me.delete(n),clearTimeout(p.timer),p.reject(new Error("Native UI session closed")));await o?.destroy()},jt=async e=>{if(pe.has(e.id))return;let o,n=!1,p,v={show:()=>{p="native",o?.show()},hide:()=>{p="none",o?.hide()},destroy:async()=>{n=!0,await o?.destroy()}};pe.set(e.id,v);try{if(document.readyState==="loading"&&await new Promise(d=>document.addEventListener("DOMContentLoaded",()=>d(),{once:!0})),n)return;let l=new Map;e.runtime==="cordova"&&ze.set(e.id,l),o=await nt(e,{send:d=>Pt(e.id,d),listen:async d=>(Re.set(e.id,d),{remove:()=>{Re.get(e.id)===d&&Re.delete(e.id)}})},e.runtime==="cordova"?{addListener:async(d,E)=>(l.set(d,E),{remove:()=>{l.delete(d)}})}:void 0),p==="none"?o.hide():p==="native"&&o.show(),n&&await o.destroy()}catch(l){throw pe.get(e.id)===v&&(pe.delete(e.id),ze.delete(e.id)),l}};return ut(xt);})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webview-native-ui/engine",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
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",