@limrun/ui 0.17.0-rc.2 → 0.17.0-rc.3

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,2883 +0,0 @@
1
- import { jsxs as V, jsx as v, Fragment as nr } from "react/jsx-runtime";
2
- import Yn, { useId as Kn, useRef as D, useState as q, useEffect as le, memo as or, useMemo as Ye, useCallback as kn, lazy as Pn, forwardRef as Un, useImperativeHandle as Ln, Suspense as xn } from "react";
3
- import { createPortal as Fn } from "react-dom";
4
- import './index.css';function Hr(r) {
5
- var e, i, c = "";
6
- if (typeof r == "string" || typeof r == "number") c += r;
7
- else if (typeof r == "object") if (Array.isArray(r)) {
8
- var l = r.length;
9
- for (e = 0; e < l; e++) r[e] && (i = Hr(r[e])) && (c && (c += " "), c += i);
10
- } else for (i in r) r[i] && (c && (c += " "), c += i);
11
- return c;
12
- }
13
- function Ke() {
14
- for (var r, e, i = 0, c = "", l = arguments.length; i < l; i++) (r = arguments[i]) && (e = Hr(r)) && (c && (c += " "), c += e);
15
- return c;
16
- }
17
- function er(r, e, i, c, l, u) {
18
- return "M" + (r + l) + "," + e + "H" + (r + i - u) + "a" + u + "," + u + " 0 0 1 " + u + "," + u + "V" + (e + c - u) + "a" + u + "," + u + " 0 0 1 " + -u + "," + u + "H" + (r + l) + "a" + l + "," + l + " 0 0 1 " + -l + "," + -l + "V" + (e + l) + "a" + l + "," + l + " 0 0 1 " + l + "," + -l + "Z";
19
- }
20
- function Wn({ inner: r, width: e, height: i }) {
21
- const c = Kn().replace(/:/g, ""), l = r ? 8.4 : 1.25, u = 8.4;
22
- return /* @__PURE__ */ V("svg", { className: "rc-duo-flat-frame", viewBox: "0 0 " + e + " " + i, "aria-hidden": "true", children: [
23
- /* @__PURE__ */ V("defs", { children: [
24
- /* @__PURE__ */ V("linearGradient", { id: c + "-silver", x1: "0", y1: "0", x2: "1", y2: "1", children: [
25
- /* @__PURE__ */ v("stop", { offset: "0", stopColor: "#62676b" }),
26
- /* @__PURE__ */ v("stop", { offset: "0.035", stopColor: "#f9faf9" }),
27
- /* @__PURE__ */ v("stop", { offset: "0.11", stopColor: "#b0b4b6" }),
28
- /* @__PURE__ */ v("stop", { offset: "0.31", stopColor: "#fdfefd" }),
29
- /* @__PURE__ */ v("stop", { offset: "0.43", stopColor: "#797f84" }),
30
- /* @__PURE__ */ v("stop", { offset: "0.51", stopColor: "#e8eaea" }),
31
- /* @__PURE__ */ v("stop", { offset: "0.7", stopColor: "#979da1" }),
32
- /* @__PURE__ */ v("stop", { offset: "0.87", stopColor: "#fafbf9" }),
33
- /* @__PURE__ */ v("stop", { offset: "1", stopColor: "#5f676c" })
34
- ] }),
35
- /* @__PURE__ */ V("linearGradient", { id: c + "-spine", children: [
36
- /* @__PURE__ */ v("stop", { stopColor: "#4a5154" }),
37
- /* @__PURE__ */ v("stop", { offset: "0.16", stopColor: "#d6d9d9" }),
38
- /* @__PURE__ */ v("stop", { offset: "0.4", stopColor: "#f8f9f7" }),
39
- /* @__PURE__ */ v("stop", { offset: "0.62", stopColor: "#a2a8ab" }),
40
- /* @__PURE__ */ v("stop", { offset: "0.83", stopColor: "#e4e7e5" }),
41
- /* @__PURE__ */ v("stop", { offset: "1", stopColor: "#666e72" })
42
- ] })
43
- ] }),
44
- !r && /* @__PURE__ */ V(nr, { children: [
45
- /* @__PURE__ */ v(
46
- "rect",
47
- {
48
- x: "-2.3",
49
- y: "0.7",
50
- width: "3.3",
51
- height: i - 1.4,
52
- rx: "0.85",
53
- fill: "url(#" + c + "-spine)",
54
- stroke: "#8b9296",
55
- strokeWidth: "0.15"
56
- }
57
- ),
58
- /* @__PURE__ */ v("path", { d: "M-.6 2V" + (i - 2), stroke: "#f5f6f4", strokeWidth: "0.22" })
59
- ] }),
60
- /* @__PURE__ */ v(
61
- "path",
62
- {
63
- d: er(0, 0, e, i, l, u),
64
- fill: "url(#" + c + "-silver)",
65
- stroke: "#696f72",
66
- strokeWidth: "0.24"
67
- }
68
- ),
69
- /* @__PURE__ */ v(
70
- "path",
71
- {
72
- d: er(0.48, 0.48, e - 0.96, i - 0.96, Math.max(0.5, l - 0.48), u - 0.48),
73
- fill: "none",
74
- stroke: "#ffffff",
75
- strokeOpacity: "0.85",
76
- strokeWidth: "0.2"
77
- }
78
- ),
79
- /* @__PURE__ */ v(
80
- "path",
81
- {
82
- d: er(1.12, 1.12, e - 2.24, i - 2.24, r ? 7.15 : 0.65, 7.15),
83
- fill: "#090b0d",
84
- stroke: "#34393c",
85
- strokeWidth: "0.2"
86
- }
87
- ),
88
- [e - 16, r ? 19 : 16].map((E) => /* @__PURE__ */ v(Yn.Fragment, { children: /* @__PURE__ */ v(
89
- "path",
90
- {
91
- d: "M" + E + ",0.17v0.82M" + E + "," + (i - 1) + "v0.82",
92
- stroke: "#b1b2ac",
93
- strokeWidth: "1.1"
94
- }
95
- ) }, E)),
96
- r && [0, i - 0.6].map((E) => /* @__PURE__ */ v(
97
- "rect",
98
- {
99
- x: e / 2 - 2.2,
100
- y: E,
101
- width: "4.4",
102
- height: "0.6",
103
- rx: "0.18",
104
- fill: "url(#" + c + "-spine)",
105
- stroke: "#697074",
106
- strokeWidth: "0.14"
107
- },
108
- E
109
- )),
110
- /* @__PURE__ */ v(
111
- "path",
112
- {
113
- d: "M" + (e - 0.1) + ",20h-.9m.9," + (i - 40) + "h-.9",
114
- stroke: "#b1b2ac",
115
- strokeWidth: "1.05"
116
- }
117
- )
118
- ] });
119
- }
120
- const kr = { width: 164.6, height: 117.8, depth: 5.2 };
121
- function Ho(r, e, i) {
122
- return r = Math.max(0, Math.min(1, r)), e = Math.max(0, Math.min(1, e)), i === 1 ? { x: e, y: 1 - r } : i === 2 ? { x: 1 - r, y: 1 - e } : i === 3 ? { x: 1 - e, y: r } : { x: r, y: e };
123
- }
124
- function Hn(r) {
125
- return Number.isFinite(r) && r >= 0 && r <= 180;
126
- }
127
- function $o(r, e) {
128
- return { x: Math.max(0, Math.min(1, r)), y: Math.max(0, Math.min(1, 1 - e)) };
129
- }
130
- function Xo(r, e, i) {
131
- return e && (r || !i) ? "touch" : r ? "ignore" : "orbit";
132
- }
133
- function $n(r, e, i, c) {
134
- if (!Number.isInteger(r) || r < 0 || r > 3 || !Number.isInteger(e) || e < 1 || e > 255 || !Number.isFinite(i) || !Number.isFinite(c) || i < 0 || i > 1 || c < 0 || c > 1)
135
- throw new RangeError("Invalid display touch coordinates");
136
- const l = new ArrayBuffer(12), u = new DataView(l);
137
- return u.setUint8(0, 19), u.setUint8(1, r), u.setUint8(2, e), u.setFloat32(4, i, !0), u.setFloat32(8, c, !0), l;
138
- }
139
- class Bo {
140
- constructor(e, i) {
141
- this.send = e, this.failed = i;
142
- }
143
- send;
144
- failed;
145
- latest;
146
- running = !1;
147
- stopped = !1;
148
- set(e) {
149
- this.stopped || !Hn(e) || (this.latest = e, this.flush());
150
- }
151
- stop() {
152
- this.stopped = !0, this.latest = void 0;
153
- }
154
- async flush() {
155
- if (!(this.running || this.stopped)) {
156
- this.running = !0;
157
- try {
158
- for (; this.latest !== void 0 && !this.stopped; ) {
159
- const e = this.latest;
160
- this.latest = void 0, await this.send(e);
161
- }
162
- } catch (e) {
163
- this.latest = void 0, this.stopped || this.failed(e);
164
- } finally {
165
- this.running = !1;
166
- }
167
- }
168
- }
169
- }
170
- const qo = {
171
- side: "Sleep/Wake",
172
- volumeUp: "Volume Up",
173
- volumeDown: "Volume Down"
174
- };
175
- class Vo {
176
- constructor(e, i) {
177
- this.send = e, this.failed = i;
178
- }
179
- send;
180
- failed;
181
- held;
182
- tail = Promise.resolve();
183
- timeout;
184
- press(e) {
185
- this.held || (this.held = e, this.enqueue(e, !0), this.timeout = setTimeout(() => this.release(), 1e4));
186
- }
187
- release() {
188
- if (!this.held) return;
189
- clearTimeout(this.timeout);
190
- const e = this.held;
191
- this.held = void 0, this.enqueue(e, !1);
192
- }
193
- enqueue(e, i) {
194
- this.tail = this.tail.then(() => this.send(e, i)).catch(this.failed);
195
- }
196
- }
197
- function Xn(r, e, i, c) {
198
- const l = kr.width / (r ? 1 : 2), u = kr.height, E = r ? 157.5 : 77.1, y = r ? 110.8 : 112.2, w = (e + (r ? 3 : 0)) % 4, O = Math.max(
199
- 0,
200
- Math.min(
201
- (i - 120) / (w % 2 ? u : l),
202
- (c - 120) / (w % 2 ? l : u)
203
- )
204
- ), R = (S, F) => {
205
- S = (S - l / 2) * O, F = (F - u / 2) * O;
206
- const re = w === 1 ? { x: -F, y: S } : w === 2 ? { x: -S, y: -F } : w === 3 ? { x: F, y: -S } : { x: S, y: F };
207
- return { x: re.x + i / 2, y: re.y + c / 2 };
208
- }, N = (w % 2 ? u : l) * O, j = (w % 2 ? l : u) * O, ee = {
209
- min: { x: (i - N) / 2, y: (c - j) / 2 },
210
- max: { x: (i + N) / 2, y: (c + j) / 2 }
211
- }, fe = [
212
- { button: "volumeDown", x: l - 37, y: -0.32, width: 9.5, height: 0.65, edge: "top" },
213
- { button: "volumeUp", x: l - 25, y: -0.32, width: 9.5, height: 0.65, edge: "top" },
214
- { button: "side", x: l + 0.35, y: u / 2 - 21, width: 0.7, height: 13, edge: "right" }
215
- ], Oe = ["top", "right", "bottom", "left"], ge = fe.map((S) => {
216
- const F = Oe[(Oe.indexOf(S.edge) + w) % 4], re = R(S.x, S.y);
217
- return F === "top" && (re.y = ee.min.y - 28), F === "bottom" && (re.y = ee.max.y + 28), F === "left" && (re.x = ee.min.x - 28), F === "right" && (re.x = ee.max.x + 28), { button: S.button, edge: F, ...re, targetX: re.x, targetY: re.y };
218
- }), U = ge.filter((S) => S.button !== "side"), Q = w % 2 ? "y" : "x";
219
- U.sort((S, F) => S[Q] - F[Q]);
220
- const te = w % 2 ? "targetY" : "targetX";
221
- if (U[1][Q] - U[0][Q] < 44) {
222
- const S = (U[0][Q] + U[1][Q]) / 2;
223
- U[0][te] = S - 22, U[1][te] = S + 22;
224
- }
225
- return {
226
- bodyWidth: l,
227
- bodyHeight: u,
228
- screenWidth: E,
229
- screenHeight: y,
230
- scale: O,
231
- turns: w,
232
- buttons: fe,
233
- guides: ge,
234
- rect: ee,
235
- iconSize: Math.min(Bn(ee), 12 * O)
236
- };
237
- }
238
- function Bn(r) {
239
- return Math.max(12, Math.min(24, Math.max(r.max.x - r.min.x, r.max.y - r.min.y) / 24));
240
- }
241
- function Go(r, e, i) {
242
- return [
243
- ["top", i.min.y - e, r, i.min.x, i.max.x],
244
- ["bottom", e - i.max.y, r, i.min.x, i.max.x],
245
- ["left", i.min.x - r, e, i.min.y, i.max.y],
246
- ["right", r - i.max.x, e, i.min.y, i.max.y]
247
- ].filter(
248
- ([, l, u, E, y]) => l >= -7 && l <= 52 && u >= E - 12 && u <= y + 12
249
- ).sort((l, u) => Math.abs(l[1]) - Math.abs(u[1]))[0]?.[0];
250
- }
251
- function qn({ logo: r }) {
252
- return /* @__PURE__ */ v("div", { className: "rc-duo-loading-screen", role: "status", "aria-label": "Connecting to iPhone Duo", children: r && /* @__PURE__ */ v("img", { src: r, alt: "" }) });
253
- }
254
- function Pr({ logo: r, showFrame: e }) {
255
- const i = D(null), [c, l] = q({ width: 0, height: 0 });
256
- le(() => {
257
- const O = new ResizeObserver(([R]) => {
258
- R && l({ width: R.contentRect.width, height: R.contentRect.height });
259
- });
260
- return i.current && O.observe(i.current), () => O.disconnect();
261
- }, []);
262
- const u = Xn(!1, 0, c.width, c.height), E = e ? u.scale : Math.min(c.width / u.screenWidth, c.height / u.screenHeight), y = e ? u.bodyWidth : u.screenWidth, w = e ? u.bodyHeight : u.screenHeight;
263
- return /* @__PURE__ */ v("div", { className: "rc-duo-view", children: /* @__PURE__ */ V("div", { className: e ? "rc-duo" : "rc-duo rc-duo-frameless", children: [
264
- /* @__PURE__ */ v("div", { ref: i, className: "rc-duo-flat-stage", children: /* @__PURE__ */ V(
265
- "div",
266
- {
267
- className: "rc-duo-flat-device",
268
- style: { width: y * E, height: w * E, transform: "translate(-50%, -50%)" },
269
- children: [
270
- e && /* @__PURE__ */ v(Wn, { inner: !1, width: y, height: w }),
271
- /* @__PURE__ */ v(
272
- "div",
273
- {
274
- className: "rc-duo-flat-screen",
275
- style: {
276
- width: u.screenWidth * E,
277
- height: u.screenHeight * E,
278
- left: (y - u.screenWidth) / 2 * E,
279
- top: (w - u.screenHeight) / 2 * E,
280
- borderRadius: e ? [0.8, 6.6, 6.6, 0.8].map((O) => O * E + "px").join(" ") : 0
281
- },
282
- children: /* @__PURE__ */ v(qn, { logo: r })
283
- }
284
- )
285
- ]
286
- }
287
- ) }),
288
- e && /* @__PURE__ */ v("div", { className: "rc-duo-loading-controls", "aria-hidden": "true" })
289
- ] }) });
290
- }
291
- const Ut = {
292
- INJECT_KEYCODE: 0,
293
- INJECT_TOUCH_EVENT: 2,
294
- // iOS-specific: send two touch points in one message (Option/Alt+drag pinch)
295
- INJECT_TWO_FINGER_TOUCH_EVENT: 18,
296
- SET_CLIPBOARD: 9
297
- }, x = {
298
- ACTION_DOWN: 0,
299
- ACTION_UP: 1,
300
- ACTION_MOVE: 2,
301
- ACTION_CANCEL: 3,
302
- ACTION_POINTER_DOWN: 5,
303
- ACTION_POINTER_UP: 6,
304
- BUTTON_PRIMARY: 1,
305
- BUTTON_SECONDARY: 2,
306
- BUTTON_TERTIARY: 4
307
- }, a = {
308
- // Actions
309
- ACTION_DOWN: 0,
310
- ACTION_UP: 1,
311
- // Meta state flags (from android.view.KeyEvent)
312
- META_NONE: 0,
313
- META_SHIFT_ON: 1,
314
- META_ALT_ON: 2,
315
- META_CTRL_ON: 4096,
316
- // META_CTRL_LEFT_ON | META_CTRL_RIGHT_ON
317
- META_META_ON: 65536,
318
- KEYCODE_0: 7,
319
- KEYCODE_1: 8,
320
- KEYCODE_2: 9,
321
- KEYCODE_3: 10,
322
- KEYCODE_4: 11,
323
- KEYCODE_5: 12,
324
- KEYCODE_6: 13,
325
- KEYCODE_7: 14,
326
- KEYCODE_8: 15,
327
- KEYCODE_9: 16,
328
- DPAD_UP: 19,
329
- // KEYCODE_DPAD_UP
330
- DPAD_DOWN: 20,
331
- // KEYCODE_DPAD_DOWN
332
- DPAD_LEFT: 21,
333
- // KEYCODE_DPAD_LEFT
334
- DPAD_RIGHT: 22,
335
- KEYCODE_A: 29,
336
- KEYCODE_B: 30,
337
- KEYCODE_C: 31,
338
- KEYCODE_D: 32,
339
- KEYCODE_E: 33,
340
- KEYCODE_F: 34,
341
- KEYCODE_G: 35,
342
- KEYCODE_H: 36,
343
- KEYCODE_I: 37,
344
- KEYCODE_J: 38,
345
- KEYCODE_K: 39,
346
- KEYCODE_L: 40,
347
- KEYCODE_M: 41,
348
- KEYCODE_N: 42,
349
- KEYCODE_O: 43,
350
- KEYCODE_P: 44,
351
- KEYCODE_Q: 45,
352
- KEYCODE_R: 46,
353
- KEYCODE_S: 47,
354
- KEYCODE_T: 48,
355
- KEYCODE_U: 49,
356
- KEYCODE_V: 50,
357
- KEYCODE_W: 51,
358
- KEYCODE_X: 52,
359
- KEYCODE_Y: 53,
360
- KEYCODE_Z: 54,
361
- KEYCODE_COMMA: 55,
362
- KEYCODE_PERIOD: 56,
363
- KEYCODE_ALT_LEFT: 57,
364
- KEYCODE_ALT_RIGHT: 58,
365
- KEYCODE_SHIFT_LEFT: 59,
366
- KEYCODE_SHIFT_RIGHT: 60,
367
- KEYCODE_TAB: 61,
368
- KEYCODE_SPACE: 62,
369
- ENTER: 66,
370
- // KEYCODE_ENTER
371
- DEL: 67,
372
- // KEYCODE_DEL (Backspace)
373
- KEYCODE_GRAVE: 68,
374
- // `
375
- KEYCODE_MINUS: 69,
376
- // -
377
- KEYCODE_EQUALS: 70,
378
- // =
379
- KEYCODE_LEFT_BRACKET: 71,
380
- // [
381
- KEYCODE_RIGHT_BRACKET: 72,
382
- // ]
383
- KEYCODE_BACKSLASH: 73,
384
- // \
385
- KEYCODE_SEMICOLON: 74,
386
- // ;
387
- KEYCODE_APOSTROPHE: 75,
388
- // '
389
- KEYCODE_SLASH: 76,
390
- MENU: 82,
391
- KEYCODE_PAGE_UP: 92,
392
- KEYCODE_PAGE_DOWN: 93,
393
- KEYCODE_ESCAPE: 111,
394
- FORWARD_DEL: 112,
395
- // KEYCODE_FORWARD_DEL (Delete key)
396
- KEYCODE_CTRL_LEFT: 113,
397
- KEYCODE_CTRL_RIGHT: 114,
398
- KEYCODE_META_LEFT: 117,
399
- KEYCODE_META_RIGHT: 118,
400
- KEYCODE_MOVE_HOME: 122,
401
- KEYCODE_MOVE_END: 123,
402
- KEYCODE_INSERT: 124,
403
- KEYCODE_F1: 131,
404
- KEYCODE_F2: 132,
405
- KEYCODE_F3: 133,
406
- KEYCODE_F4: 134,
407
- KEYCODE_F5: 135,
408
- KEYCODE_F6: 136,
409
- KEYCODE_F7: 137,
410
- KEYCODE_F8: 138,
411
- KEYCODE_F9: 139,
412
- KEYCODE_F10: 140,
413
- KEYCODE_F11: 141,
414
- KEYCODE_F12: 142,
415
- KEYCODE_NUMPAD_0: 144,
416
- KEYCODE_NUMPAD_1: 145,
417
- KEYCODE_NUMPAD_2: 146,
418
- KEYCODE_NUMPAD_3: 147,
419
- KEYCODE_NUMPAD_4: 148,
420
- KEYCODE_NUMPAD_5: 149,
421
- KEYCODE_NUMPAD_6: 150,
422
- KEYCODE_NUMPAD_7: 151,
423
- KEYCODE_NUMPAD_8: 152,
424
- KEYCODE_NUMPAD_9: 153,
425
- KEYCODE_NUMPAD_DIVIDE: 154,
426
- KEYCODE_NUMPAD_MULTIPLY: 155,
427
- KEYCODE_NUMPAD_SUBTRACT: 156,
428
- KEYCODE_NUMPAD_ADD: 157,
429
- KEYCODE_NUMPAD_DOT: 158,
430
- KEYCODE_NUMPAD_COMMA: 159,
431
- KEYCODE_NUMPAD_ENTER: 160,
432
- KEYCODE_NUMPAD_EQUALS: 161
433
- }, $r = {
434
- KeyA: a.KEYCODE_A,
435
- KeyB: a.KEYCODE_B,
436
- KeyC: a.KEYCODE_C,
437
- KeyD: a.KEYCODE_D,
438
- KeyE: a.KEYCODE_E,
439
- KeyF: a.KEYCODE_F,
440
- KeyG: a.KEYCODE_G,
441
- KeyH: a.KEYCODE_H,
442
- KeyI: a.KEYCODE_I,
443
- KeyJ: a.KEYCODE_J,
444
- KeyK: a.KEYCODE_K,
445
- KeyL: a.KEYCODE_L,
446
- KeyM: a.KEYCODE_M,
447
- KeyN: a.KEYCODE_N,
448
- KeyO: a.KEYCODE_O,
449
- KeyP: a.KEYCODE_P,
450
- KeyQ: a.KEYCODE_Q,
451
- KeyR: a.KEYCODE_R,
452
- KeyS: a.KEYCODE_S,
453
- KeyT: a.KEYCODE_T,
454
- KeyU: a.KEYCODE_U,
455
- KeyV: a.KEYCODE_V,
456
- KeyW: a.KEYCODE_W,
457
- KeyX: a.KEYCODE_X,
458
- KeyY: a.KEYCODE_Y,
459
- KeyZ: a.KEYCODE_Z,
460
- Digit0: a.KEYCODE_0,
461
- Digit1: a.KEYCODE_1,
462
- Digit2: a.KEYCODE_2,
463
- Digit3: a.KEYCODE_3,
464
- Digit4: a.KEYCODE_4,
465
- Digit5: a.KEYCODE_5,
466
- Digit6: a.KEYCODE_6,
467
- Digit7: a.KEYCODE_7,
468
- Digit8: a.KEYCODE_8,
469
- Digit9: a.KEYCODE_9,
470
- Backquote: a.KEYCODE_GRAVE,
471
- Minus: a.KEYCODE_MINUS,
472
- Equal: a.KEYCODE_EQUALS,
473
- BracketLeft: a.KEYCODE_LEFT_BRACKET,
474
- BracketRight: a.KEYCODE_RIGHT_BRACKET,
475
- Backslash: a.KEYCODE_BACKSLASH,
476
- Semicolon: a.KEYCODE_SEMICOLON,
477
- Quote: a.KEYCODE_APOSTROPHE,
478
- Comma: a.KEYCODE_COMMA,
479
- Period: a.KEYCODE_PERIOD,
480
- Slash: a.KEYCODE_SLASH,
481
- Space: a.KEYCODE_SPACE,
482
- Tab: a.KEYCODE_TAB,
483
- Escape: a.KEYCODE_ESCAPE,
484
- ArrowUp: a.DPAD_UP,
485
- ArrowDown: a.DPAD_DOWN,
486
- ArrowLeft: a.DPAD_LEFT,
487
- ArrowRight: a.DPAD_RIGHT,
488
- Enter: a.ENTER,
489
- Backspace: a.DEL,
490
- Delete: a.FORWARD_DEL,
491
- Home: a.KEYCODE_MOVE_HOME,
492
- End: a.KEYCODE_MOVE_END,
493
- PageUp: a.KEYCODE_PAGE_UP,
494
- PageDown: a.KEYCODE_PAGE_DOWN,
495
- Insert: a.KEYCODE_INSERT,
496
- F1: a.KEYCODE_F1,
497
- F2: a.KEYCODE_F2,
498
- F3: a.KEYCODE_F3,
499
- F4: a.KEYCODE_F4,
500
- F5: a.KEYCODE_F5,
501
- F6: a.KEYCODE_F6,
502
- F7: a.KEYCODE_F7,
503
- F8: a.KEYCODE_F8,
504
- F9: a.KEYCODE_F9,
505
- F10: a.KEYCODE_F10,
506
- F11: a.KEYCODE_F11,
507
- F12: a.KEYCODE_F12,
508
- ShiftLeft: a.KEYCODE_SHIFT_LEFT,
509
- ShiftRight: a.KEYCODE_SHIFT_RIGHT,
510
- ControlLeft: a.KEYCODE_CTRL_LEFT,
511
- ControlRight: a.KEYCODE_CTRL_RIGHT,
512
- AltLeft: a.KEYCODE_ALT_LEFT,
513
- AltRight: a.KEYCODE_ALT_RIGHT,
514
- MetaLeft: a.KEYCODE_META_LEFT,
515
- MetaRight: a.KEYCODE_META_RIGHT,
516
- // Windows/Command key
517
- ContextMenu: a.MENU,
518
- // Often the Menu key
519
- // Numpad mappings
520
- Numpad0: a.KEYCODE_NUMPAD_0,
521
- Numpad1: a.KEYCODE_NUMPAD_1,
522
- Numpad2: a.KEYCODE_NUMPAD_2,
523
- Numpad3: a.KEYCODE_NUMPAD_3,
524
- Numpad4: a.KEYCODE_NUMPAD_4,
525
- Numpad5: a.KEYCODE_NUMPAD_5,
526
- Numpad6: a.KEYCODE_NUMPAD_6,
527
- Numpad7: a.KEYCODE_NUMPAD_7,
528
- Numpad8: a.KEYCODE_NUMPAD_8,
529
- Numpad9: a.KEYCODE_NUMPAD_9,
530
- NumpadDivide: a.KEYCODE_NUMPAD_DIVIDE,
531
- NumpadMultiply: a.KEYCODE_NUMPAD_MULTIPLY,
532
- NumpadSubtract: a.KEYCODE_NUMPAD_SUBTRACT,
533
- NumpadAdd: a.KEYCODE_NUMPAD_ADD,
534
- NumpadDecimal: a.KEYCODE_NUMPAD_DOT,
535
- NumpadComma: a.KEYCODE_NUMPAD_COMMA,
536
- // Some numpads have comma
537
- NumpadEnter: a.KEYCODE_NUMPAD_ENTER,
538
- NumpadEqual: a.KEYCODE_NUMPAD_EQUALS
539
- };
540
- function Kt(r, e, i, c, l, u, E = 1, y = 0, w = 0) {
541
- const O = new ArrayBuffer(32), R = new DataView(O);
542
- let N = 0;
543
- return R.setUint8(N, Ut.INJECT_TOUCH_EVENT), N += 1, R.setUint8(N, r), N += 1, R.setBigInt64(N, BigInt(e), !0), N += 8, R.setInt32(N, Math.round(l), !0), N += 4, R.setInt32(N, Math.round(u), !0), N += 4, R.setUint16(N, i, !0), N += 2, R.setUint16(N, c, !0), N += 2, R.setInt16(N, Math.round(E * 65535), !0), N += 2, R.setInt32(N, y, !0), N += 4, R.setInt32(N, w, !0), O;
544
- }
545
- function Vn(r, e, i, c, l, u, E) {
546
- const y = new ArrayBuffer(24), w = new DataView(y);
547
- let O = 0;
548
- return w.setUint8(O, Ut.INJECT_TWO_FINGER_TOUCH_EVENT), O += 1, w.setUint8(O, r), O += 1, w.setInt32(O, Math.round(c), !0), O += 4, w.setInt32(O, Math.round(l), !0), O += 4, w.setInt32(O, Math.round(u), !0), O += 4, w.setInt32(O, Math.round(E), !0), O += 4, w.setUint16(O, e, !0), O += 2, w.setUint16(O, i, !0), O += 2, w.setUint16(O, 0, !0), y;
549
- }
550
- function Gn(r, e = !0) {
551
- const c = new TextEncoder().encode(r), l = new ArrayBuffer(14 + c.length), u = new DataView(l);
552
- let E = 0;
553
- return u.setUint8(E, Ut.SET_CLIPBOARD), E += 1, u.setBigInt64(E, BigInt(0), !1), E += 8, u.setUint8(E, e ? 1 : 0), E += 1, u.setUint32(E, c.length, !1), E += 4, new Uint8Array(l, E).set(c), l;
554
- }
555
- function Et(r, e, i = 0, c = 0) {
556
- const l = new ArrayBuffer(14), u = new DataView(l);
557
- let E = 0;
558
- return u.setUint8(E, Ut.INJECT_KEYCODE), E += 1, u.setUint8(E, r), E += 1, u.setInt32(E, e, !0), E += 4, u.setInt32(E, i, !0), E += 4, u.setInt32(E, c, !0), l;
559
- }
560
- const tr = "Accessibility unavailable on this device.", Pt = 500, Xr = (r, e) => Math.abs(r.x - e.x) < 0.5 && Math.abs(r.y - e.y) < 0.5 && Math.abs(r.width - e.width) < 0.5 && Math.abs(r.height - e.height) < 0.5, Jn = (r) => Math.max(0, r.width) * Math.max(0, r.height), zn = (r) => {
561
- const e = r.find((i) => i.frame && i.frame.width > 0 && i.frame.height > 0);
562
- return e?.frame ? ((Math.abs(e.frame.x) > 0.5 || Math.abs(e.frame.y) > 0.5) && console.warn(
563
- `[ax-tree] iOS root frame is not anchored at (0,0): (${e.frame.x},${e.frame.y}). Element positions may be slightly off from the rendered video.`
564
- ), { x: 0, y: 0, width: e.frame.width, height: e.frame.height }) : { x: 0, y: 0, width: 1, height: 1 };
565
- }, jn = (r) => {
566
- const e = {};
567
- return typeof r.AXUniqueId == "string" && r.AXUniqueId.length > 0 && (e.AXUniqueId = r.AXUniqueId), typeof r.AXLabel == "string" && r.AXLabel.length > 0 && (e.AXLabel = r.AXLabel), typeof r.type == "string" && r.type.length > 0 && (e.className = r.type), e;
568
- }, Qn = (r) => {
569
- const e = {};
570
- for (const [i, c] of Object.entries(r))
571
- i !== "children" && (e[i] = c);
572
- return e;
573
- };
574
- function Zn(r) {
575
- const e = Array.isArray(r) ? r : [r], i = zn(e), c = [], l = (u, E) => {
576
- if (c.length >= Pt) return;
577
- const y = u.frame;
578
- if (y && y.width > 0 && y.height > 0 && !Xr(y, i)) {
579
- const O = u.role_description || u.role || "", R = (typeof u.AXLabel == "string" ? u.AXLabel : "") || (typeof u.title == "string" ? u.title : "") || "";
580
- c.push({
581
- id: typeof u.AXUniqueId == "string" && u.AXUniqueId.length > 0 ? u.AXUniqueId : E,
582
- path: E,
583
- label: R,
584
- value: typeof u.AXValue == "string" ? u.AXValue : "",
585
- role: O,
586
- type: typeof u.type == "string" ? u.type : "",
587
- enabled: u.enabled !== !1,
588
- focused: u.focused === !0,
589
- frame: { x: y.x, y: y.y, width: y.width, height: y.height },
590
- selectors: jn(u),
591
- raw: Qn(u)
592
- });
593
- }
594
- const w = Array.isArray(u.children) ? u.children : [];
595
- for (let O = 0; O < w.length && c.length < Pt; O++)
596
- l(w[O], `${E}.${O}`);
597
- };
598
- for (let u = 0; u < e.length && c.length < Pt; u++)
599
- l(e[u], String(u));
600
- return {
601
- platform: "ios",
602
- screen: { width: i.width, height: i.height },
603
- elements: c,
604
- capturedAt: Date.now()
605
- };
606
- }
607
- const eo = (r) => {
608
- let e = { x: 0, y: 0, width: 1, height: 1 }, i = 0;
609
- for (const c of r) {
610
- const l = c.parsedBounds;
611
- if (!l) continue;
612
- const u = l.right - l.left, E = l.bottom - l.top, y = Math.max(0, u) * Math.max(0, E);
613
- y > i && (i = y, e = { x: 0, y: 0, width: u, height: E });
614
- }
615
- return e;
616
- }, to = (r) => {
617
- const e = {};
618
- return typeof r.resourceId == "string" && r.resourceId.length > 0 && (e.resourceId = r.resourceId), typeof r.contentDesc == "string" && r.contentDesc.length > 0 && (e.contentDesc = r.contentDesc), typeof r.text == "string" && r.text.length > 0 && (e.text = r.text), typeof r.className == "string" && r.className.length > 0 && (e.className = r.className), e;
619
- };
620
- function ro(r) {
621
- const e = eo(r), i = [];
622
- for (let c = 0; c < r.length && i.length < Pt; c++) {
623
- const l = r[c], u = l.parsedBounds;
624
- if (!u) continue;
625
- const E = Math.max(0, u.right - u.left), y = Math.max(0, u.bottom - u.top);
626
- if (E <= 0 || y <= 0) continue;
627
- const w = { x: u.left, y: u.top, width: E, height: y };
628
- if (Xr(w, { x: 0, y: 0, width: e.width, height: e.height })) continue;
629
- const O = l.contentDesc || l.text || "", R = l.className || "";
630
- i.push({
631
- id: l.resourceId && l.resourceId.length > 0 ? l.resourceId : l.contentDesc && l.contentDesc.length > 0 ? `cd:${l.contentDesc}` : String(c),
632
- path: String(c),
633
- label: O,
634
- value: typeof l.text == "string" ? l.text : "",
635
- role: R,
636
- type: R,
637
- enabled: l.enabled !== !1,
638
- focused: l.focused === !0,
639
- frame: w,
640
- selectors: to(l),
641
- raw: { ...l }
642
- });
643
- }
644
- return {
645
- platform: "android",
646
- screen: { width: e.width, height: e.height },
647
- elements: i,
648
- capturedAt: Date.now()
649
- };
650
- }
651
- function no(r, e) {
652
- const i = Math.max(0, r.x), c = Math.max(0, r.y), l = Math.min(e.width, r.x + r.width), u = Math.min(e.height, r.y + r.height), E = Math.max(0, l - i), y = Math.max(0, u - c);
653
- return E > 0 && y > 0 ? { x: i, y: c, width: E, height: y } : null;
654
- }
655
- function Br(r, e) {
656
- if (r === e) return !0;
657
- if (r.id !== e.id || r.path !== e.path || r.label !== e.label || r.value !== e.value || r.role !== e.role || r.type !== e.type || r.enabled !== e.enabled || r.focused !== e.focused) return !1;
658
- const i = r.frame, c = e.frame;
659
- return i.x === c.x && i.y === c.y && i.width === c.width && i.height === c.height;
660
- }
661
- function qr(r, e) {
662
- if (r === e) return !0;
663
- if (!r || !e || r.platform !== e.platform || r.screen.width !== e.screen.width || r.screen.height !== e.screen.height || r.elements.length !== e.elements.length) return !1;
664
- for (let i = 0; i < r.elements.length; i++)
665
- if (!Br(r.elements[i], e.elements[i])) return !1;
666
- return !0;
667
- }
668
- function oo(r, e, i) {
669
- let c = null, l = 1 / 0;
670
- for (const u of r.elements) {
671
- const E = u.frame;
672
- if (e < E.x || i < E.y || e > E.x + E.width || i > E.y + E.height) continue;
673
- const y = Jn(E);
674
- y < l && (l = y, c = u);
675
- }
676
- return c;
677
- }
678
- function io(r, e) {
679
- if (e === "ios") {
680
- if (r.selectors.AXUniqueId)
681
- return `client.tapElement({ AXUniqueId: ${JSON.stringify(r.selectors.AXUniqueId)} })`;
682
- if (r.selectors.AXLabel) {
683
- const i = r.selectors.className ? `, type: ${JSON.stringify(r.selectors.className)}` : "";
684
- return `client.tapElement({ AXLabel: ${JSON.stringify(r.selectors.AXLabel)}${i} })`;
685
- }
686
- return null;
687
- }
688
- return r.selectors.resourceId ? `client.tap({ selector: { resourceId: ${JSON.stringify(r.selectors.resourceId)} } })` : r.selectors.contentDesc ? `client.tap({ selector: { contentDesc: ${JSON.stringify(r.selectors.contentDesc)} } })` : r.selectors.text ? `client.tap({ selector: { text: ${JSON.stringify(r.selectors.text)} } })` : null;
689
- }
690
- function Vr(r) {
691
- const e = r.role || r.type || "";
692
- if (!e) return "element";
693
- let i = e.replace(/^AX/, "");
694
- return i.includes(".") && (i = i.split(".").pop()), i === "GenericElement" ? "Element" : (i = i.replace(/([a-z])([A-Z])/g, "$1 $2"), i);
695
- }
696
- const Ur = 80;
697
- function Gr(r) {
698
- const e = Vr(r), i = r.label || r.value || "";
699
- if (!i) return e;
700
- const c = i.length > Ur ? i.slice(0, Ur).trimEnd() + "…" : i;
701
- return `${e} · ${c}`;
702
- }
703
- const so = 500, co = 2e3, Lr = 5e3, ao = 8e3, uo = 1200, lo = 250, fo = () => `ax-rc-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
704
- class ho {
705
- platform;
706
- send;
707
- onSnapshot;
708
- onStatusChange;
709
- baseIntervalMs;
710
- maxBackoffMs;
711
- androidElementTreeOptions;
712
- pending = /* @__PURE__ */ new Map();
713
- running = !1;
714
- timer;
715
- currentInterval;
716
- lastSnapshot = null;
717
- // Single-flight: only one outstanding request at a time. Avoids piling
718
- // identical requests on a slow server.
719
- inflight = !1;
720
- // Rate-limit floor for bumpActivity so high-frequency input (drags,
721
- // typing) doesn't trigger a request storm.
722
- lastBumpAtMs = 0;
723
- // Wall-clock timestamp until which we're in "activity boost" mode and
724
- // schedule fetches at ACTIVITY_BOOST_INTERVAL_MS instead of the normal
725
- // backed-off interval. Set by bumpActivity().
726
- boostUntilMs = 0;
727
- // Coarse-grained current status; deduplicated before emission so
728
- // identical-to-current transitions are no-ops.
729
- status = "idle";
730
- constructor(e) {
731
- this.platform = e.platform, this.send = e.send, this.onSnapshot = e.onSnapshot, this.onStatusChange = e.onStatusChange, this.baseIntervalMs = e.baseIntervalMs ?? so, this.maxBackoffMs = e.maxBackoffMs ?? co, this.androidElementTreeOptions = e.androidElementTreeOptions, this.currentInterval = this.baseIntervalMs;
732
- }
733
- start() {
734
- this.running || (this.running = !0, this.currentInterval = this.baseIntervalMs, this.boostUntilMs = 0, this.setStatus("starting"), this.runOnce());
735
- }
736
- stop() {
737
- this.running && (this.running = !1, this.timer !== void 0 && (window.clearTimeout(this.timer), this.timer = void 0), this.failAllPending("Inspector stopped"), this.lastSnapshot = null, this.setStatus("idle"), this.onSnapshot(null));
738
- }
739
- getStatus() {
740
- return this.status;
741
- }
742
- setStatus(e, i) {
743
- if (this.status !== e && (this.status = e, !!this.onStatusChange))
744
- try {
745
- this.onStatusChange(e, i);
746
- } catch (c) {
747
- console.error("[AxFetcher] onStatusChange threw:", c);
748
- }
749
- }
750
- // Called after any user-driven action that's likely to change the UI
751
- // (taps, scrolls, key events, openUrl, app termination, orientation
752
- // change, etc.). Has two effects:
753
- //
754
- // 1. Resets the polling interval to base and triggers an immediate
755
- // fetch (rate-limited so drags / rapid typing don't request-storm).
756
- // 2. Enters a brief "boost" window during which scheduleNext() uses a
757
- // shorter interval (ACTIVITY_BOOST_INTERVAL_MS), so we capture the
758
- // mid- and post-animation tree without waiting for the next
759
- // back-off cycle.
760
- bumpActivity() {
761
- if (!this.running) return;
762
- const e = Date.now();
763
- this.boostUntilMs = e + uo;
764
- const i = Math.max(150, Math.floor(this.baseIntervalMs / 2));
765
- if (e - this.lastBumpAtMs < i) {
766
- this.currentInterval = this.baseIntervalMs;
767
- return;
768
- }
769
- this.lastBumpAtMs = e, this.currentInterval = this.baseIntervalMs, this.timer !== void 0 && (window.clearTimeout(this.timer), this.timer = void 0), this.inflight || this.runOnce();
770
- }
771
- // Fire a one-shot fetch independent of the poll loop. Useful for the
772
- // imperative refresh() ref method customers may call.
773
- //
774
- // Goes through the same change-detect path as the regular poll loop —
775
- // identical-to-last-snapshot responses do NOT re-emit via onSnapshot, so
776
- // a customer calling refresh() in a tight loop doesn't see a stream of
777
- // duplicate snapshots. The returned promise still resolves with the
778
- // (possibly identical) snapshot for the caller's own use.
779
- async refresh() {
780
- const e = await this.requestOnce();
781
- return this.running && this.deliver(e), e;
782
- }
783
- // Returns the latest snapshot delivered to onSnapshot. May be stale.
784
- getLatest() {
785
- return this.lastSnapshot;
786
- }
787
- // Called by RemoteControl's ws.onmessage when it sees a message type we own.
788
- // Returns true when the message was a response we were waiting for.
789
- handleMessage(e) {
790
- if (!e || typeof e.id != "string") return !1;
791
- const i = e.id;
792
- if (!this.pending.get(i)) return !1;
793
- if (this.platform === "ios") {
794
- if (e.type !== "elementTreeResult") return !1;
795
- const y = typeof e.error == "string" ? e.error : null;
796
- if (y)
797
- return this.settleReject(i, new Error(y)), !0;
798
- const w = typeof e.json == "string" ? e.json : "";
799
- try {
800
- const O = JSON.parse(w), R = Zn(O);
801
- this.settleResolve(i, R);
802
- } catch (O) {
803
- this.settleReject(i, O instanceof Error ? O : new Error(String(O)));
804
- }
805
- return !0;
806
- }
807
- if (e.type !== "getElementTreeResult") return !1;
808
- const l = e.error;
809
- if (l && typeof l == "object") {
810
- const y = typeof l.message == "string" ? l.message : "getElementTree failed";
811
- return this.settleReject(i, new Error(y)), !0;
812
- }
813
- const u = e.payload, E = Array.isArray(u?.nodes) ? u.nodes : [];
814
- try {
815
- const y = ro(E);
816
- this.settleResolve(i, y);
817
- } catch (y) {
818
- this.settleReject(i, y instanceof Error ? y : new Error(String(y)));
819
- }
820
- return !0;
821
- }
822
- buildRequest(e) {
823
- return this.platform === "ios" ? { type: "elementTree", id: e } : { type: "getElementTree", id: e, ...this.androidElementTreeOptions };
824
- }
825
- async requestOnce() {
826
- const e = fo();
827
- return new Promise((i, c) => {
828
- const l = window.setTimeout(
829
- () => {
830
- this.pending.delete(e), c(new Error("elementTree request timed out"));
831
- },
832
- ao + (this.androidElementTreeOptions?.waitForIdleTimeoutMs ?? 0)
833
- );
834
- this.pending.set(e, { resolve: i, reject: c, timer: l }), this.send(this.buildRequest(e)) || (window.clearTimeout(l), this.pending.delete(e), c(new Error("elementTree send failed (WebSocket not open)")));
835
- });
836
- }
837
- async runOnce() {
838
- if (this.running && !this.inflight) {
839
- this.inflight = !0;
840
- try {
841
- const e = await this.requestOnce();
842
- if (!this.running) return;
843
- this.deliver(e);
844
- } catch (e) {
845
- if (!this.running) return;
846
- const i = e instanceof Error ? e.message : String(e), c = /unavailable|not (yet )?running|failed|timeout/i.test(i);
847
- this.currentInterval = c ? Lr : Math.min(this.currentInterval * 2, this.maxBackoffMs), this.setStatus(c ? "unavailable" : "error", i);
848
- } finally {
849
- this.inflight = !1, this.scheduleNext();
850
- }
851
- }
852
- }
853
- deliver(e) {
854
- const i = this.lastSnapshot;
855
- if (qr(i, e)) {
856
- this.currentInterval = Math.min(this.currentInterval * 2, this.maxBackoffMs), this.lastSnapshot = e, e.errors?.includes(tr) || this.setStatus("ready");
857
- return;
858
- }
859
- this.lastSnapshot = e, this.currentInterval = this.baseIntervalMs, e.errors?.includes(tr) ? (this.currentInterval = Lr, this.setStatus("unavailable", tr)) : this.setStatus("ready"), this.onSnapshot(e);
860
- }
861
- scheduleNext() {
862
- if (!this.running) return;
863
- this.timer !== void 0 && window.clearTimeout(this.timer);
864
- const e = Date.now() < this.boostUntilMs ? Math.min(lo, this.currentInterval) : this.currentInterval;
865
- this.timer = window.setTimeout(() => {
866
- this.timer = void 0, this.runOnce();
867
- }, e);
868
- }
869
- settleResolve(e, i) {
870
- const c = this.pending.get(e);
871
- c && (window.clearTimeout(c.timer), this.pending.delete(e), c.resolve(i));
872
- }
873
- settleReject(e, i) {
874
- const c = this.pending.get(e);
875
- c && (window.clearTimeout(c.timer), this.pending.delete(e), c.reject(i));
876
- }
877
- failAllPending(e) {
878
- for (const [i, c] of this.pending.entries())
879
- window.clearTimeout(c.timer), c.reject(new Error(e)), this.pending.delete(i);
880
- }
881
- }
882
- class po {
883
- generation = 0;
884
- tail = Promise.resolve();
885
- get currentGeneration() {
886
- return this.generation;
887
- }
888
- enqueue(e) {
889
- const i = ++this.generation;
890
- return this.append(i, e);
891
- }
892
- /**
893
- * Queues related work without superseding an already queued request.
894
- *
895
- * The operation retains the generation current at enqueue time and becomes
896
- * stale if a later camera request increments it before this work starts.
897
- */
898
- enqueueCurrent(e) {
899
- return this.append(this.generation, e);
900
- }
901
- append(e, i) {
902
- const c = {
903
- generation: e,
904
- isCurrent: () => e === this.generation
905
- }, l = this.tail.then(() => i(c));
906
- return this.tail = l.catch(() => {
907
- }), l;
908
- }
909
- invalidate() {
910
- ++this.generation;
911
- }
912
- }
913
- function mo(r) {
914
- if (!r || typeof r != "object") return null;
915
- const e = r;
916
- if (e.type !== "cameraRequest" || typeof e.active != "boolean") return null;
917
- const i = { active: e.active };
918
- return (e.facingMode === "user" || e.facingMode === "environment") && (i.facingMode = e.facingMode), i;
919
- }
920
- function Eo(r) {
921
- const e = {
922
- frameRate: { ideal: 30, max: 30 }
923
- };
924
- return r?.facingMode && (e.facingMode = { ideal: r.facingMode }), e;
925
- }
926
- function go(r, e) {
927
- return !r || r.facingMode !== e.facingMode;
928
- }
929
- function Co(r) {
930
- const e = r.getSettings();
931
- return {
932
- width: e.width,
933
- height: e.height,
934
- frameRate: e.frameRate,
935
- deviceId: e.deviceId,
936
- label: r.label || void 0,
937
- facingMode: e.facingMode
938
- };
939
- }
940
- function yo(r) {
941
- return {
942
- type: "cameraResult",
943
- granted: !0,
944
- camera: Co(r)
945
- };
946
- }
947
- const vo = async (r) => {
948
- if (!r) return !1;
949
- try {
950
- if (typeof navigator < "u" && navigator.clipboard?.writeText)
951
- return await navigator.clipboard.writeText(r), !0;
952
- } catch {
953
- }
954
- try {
955
- const e = document.createElement("textarea");
956
- e.value = r, e.style.position = "fixed", e.style.opacity = "0", document.body.appendChild(e), e.select();
957
- const i = document.execCommand("copy");
958
- return document.body.removeChild(e), i;
959
- } catch {
960
- return !1;
961
- }
962
- }, Oo = or(
963
- function({ element: e, screen: i, highlighted: c, selected: l, selectable: u, onClick: E }) {
964
- const y = no(e.frame, i);
965
- if (!y) return null;
966
- const w = Gr(e);
967
- return /* @__PURE__ */ v(
968
- "button",
969
- {
970
- type: "button",
971
- className: Ke("rc-inspect-box", !e.enabled && "rc-inspect-box-disabled"),
972
- "data-ax-id": e.id,
973
- "data-ax-path": e.path,
974
- "data-ax-label": e.label || void 0,
975
- "data-ax-role": e.role || void 0,
976
- "data-highlighted": c ? "true" : "false",
977
- "data-selected": l ? "true" : "false",
978
- "aria-label": w,
979
- onClick: (O) => {
980
- u && (O.preventDefault(), O.stopPropagation(), E(e, { x: O.clientX, y: O.clientY }));
981
- },
982
- style: {
983
- left: `${y.x / i.width * 100}%`,
984
- top: `${y.y / i.height * 100}%`,
985
- width: `${y.width / i.width * 100}%`,
986
- height: `${y.height / i.height * 100}%`
987
- }
988
- }
989
- );
990
- },
991
- (r, e) => r.highlighted === e.highlighted && r.selected === e.selected && r.selectable === e.selectable && r.screen.width === e.screen.width && r.screen.height === e.screen.height && r.onClick === e.onClick && Br(r.element, e.element)
992
- ), _o = 260, Do = 220, To = 6, wo = 8, bo = or(function({
993
- element: e,
994
- platform: i,
995
- anchor: c,
996
- cursorAnchored: l,
997
- showActions: u,
998
- onTap: E
999
- }) {
1000
- const [y, w] = q(null);
1001
- le(() => {
1002
- if (!y) return;
1003
- const U = window.setTimeout(() => w(null), 1100);
1004
- return () => window.clearTimeout(U);
1005
- }, [y]);
1006
- const O = Ye(() => {
1007
- const U = _o, Q = Do, te = To, S = wo, F = typeof window < "u" ? window.innerWidth : 1024, re = typeof window < "u" ? window.innerHeight : 768, ke = c.x + te + U <= F - S, Ce = c.y - te - Q >= S;
1008
- let $ = ke ? c.x + te : c.x - te, Pe = Ce ? c.y - te : c.y + te;
1009
- const se = `translate(${ke ? "0" : "-100%"}, ${Ce ? "-100%" : "0"})`;
1010
- return $ = Math.max(S + (ke ? 0 : U), Math.min(F - S - (ke ? U : 0), $)), Pe = Math.max(S + (Ce ? Q : 0), Math.min(re - S - (Ce ? 0 : Q), Pe)), { left: `${$}px`, top: `${Pe}px`, transform: se };
1011
- }, [c.x, c.y]), R = Ye(() => io(e, i), [e, i]), N = i === "ios" ? e.selectors.AXUniqueId : e.selectors.resourceId, j = i === "ios" ? "AXUniqueId" : "resourceId", ee = kn(async (U, Q) => {
1012
- if (!U) return;
1013
- await vo(U) && w(Q);
1014
- }, []), fe = Vr(e), Oe = e.label || e.value || fe, ge = Gr(e);
1015
- return Fn(
1016
- /* @__PURE__ */ V(
1017
- "div",
1018
- {
1019
- className: "rc-inspect-card",
1020
- "data-cursor-anchored": l ? "true" : "false",
1021
- style: O,
1022
- onClick: (U) => U.stopPropagation(),
1023
- onMouseDown: (U) => U.stopPropagation(),
1024
- onMouseMove: (U) => U.stopPropagation(),
1025
- children: [
1026
- /* @__PURE__ */ V("div", { className: "rc-inspect-card-header", children: [
1027
- /* @__PURE__ */ v("span", { className: "rc-inspect-card-role", children: fe }),
1028
- !e.enabled && /* @__PURE__ */ v("span", { className: "rc-inspect-card-tag", children: "disabled" }),
1029
- e.focused && /* @__PURE__ */ v("span", { className: "rc-inspect-card-tag rc-inspect-card-tag-blue", children: "focused" })
1030
- ] }),
1031
- /* @__PURE__ */ v("p", { className: "rc-inspect-card-title", title: ge, children: Oe }),
1032
- N && /* @__PURE__ */ V("div", { className: "rc-inspect-card-row", children: [
1033
- /* @__PURE__ */ V("span", { className: "rc-inspect-card-row-label", children: [
1034
- j,
1035
- ":"
1036
- ] }),
1037
- /* @__PURE__ */ v("span", { className: "rc-inspect-card-row-value", children: N })
1038
- ] }),
1039
- e.value && e.value !== e.label && /* @__PURE__ */ V("div", { className: "rc-inspect-card-row", children: [
1040
- /* @__PURE__ */ v("span", { className: "rc-inspect-card-row-label", children: "value:" }),
1041
- /* @__PURE__ */ v("span", { className: "rc-inspect-card-row-value", children: e.value })
1042
- ] }),
1043
- /* @__PURE__ */ V("div", { className: "rc-inspect-card-row", children: [
1044
- /* @__PURE__ */ v("span", { className: "rc-inspect-card-row-label", children: "frame:" }),
1045
- /* @__PURE__ */ V("span", { className: "rc-inspect-card-row-value", children: [
1046
- Math.round(e.frame.width),
1047
- "×",
1048
- Math.round(e.frame.height),
1049
- " @ ",
1050
- Math.round(e.frame.x),
1051
- ",",
1052
- Math.round(e.frame.y)
1053
- ] })
1054
- ] }),
1055
- u && /* @__PURE__ */ V("div", { className: "rc-inspect-card-actions", children: [
1056
- /* @__PURE__ */ v(
1057
- "button",
1058
- {
1059
- type: "button",
1060
- className: "rc-inspect-card-btn rc-inspect-card-btn-primary",
1061
- onClick: () => E(e, c),
1062
- children: "Tap"
1063
- }
1064
- ),
1065
- /* @__PURE__ */ v(
1066
- "button",
1067
- {
1068
- type: "button",
1069
- className: Ke("rc-inspect-card-btn", y === "selector" && "rc-inspect-card-btn-copied"),
1070
- disabled: !R,
1071
- title: R ?? "No usable selector for this element",
1072
- onClick: () => ee(R ?? void 0, "selector"),
1073
- children: y === "selector" ? "Copied!" : "Copy selector"
1074
- }
1075
- ),
1076
- /* @__PURE__ */ v(
1077
- "button",
1078
- {
1079
- type: "button",
1080
- className: Ke("rc-inspect-card-btn", y === "id" && "rc-inspect-card-btn-copied"),
1081
- disabled: !N,
1082
- title: N ?? `No ${j}`,
1083
- onClick: () => ee(N, "id"),
1084
- children: y === "id" ? "Copied!" : `Copy ${j}`
1085
- }
1086
- )
1087
- ] })
1088
- ]
1089
- }
1090
- ),
1091
- document.body
1092
- );
1093
- }), Ao = or(function({
1094
- snapshot: e,
1095
- geometry: i,
1096
- highlightedId: c,
1097
- selectedId: l,
1098
- mode: u,
1099
- cursorPosition: E,
1100
- frozenCursorPosition: y,
1101
- onSelectChange: w,
1102
- onTapElement: O
1103
- }) {
1104
- const R = u === "select", N = R ? c !== null && c !== l : c !== null, j = R ? c ?? l : c, ee = Ye(() => {
1105
- const S = /* @__PURE__ */ new Map();
1106
- if (!e) return S;
1107
- for (const F of e.elements) S.set(F.id, F);
1108
- return S;
1109
- }, [e]), fe = Ye(() => j ? ee.get(j) ?? null : null, [j, ee]);
1110
- if (!(!!e && !!i && e.screen.width > 0 && e.screen.height > 0 && e.elements.length > 0)) return null;
1111
- const ge = N ? E : y ?? E, U = N, Q = R && !N && l !== null, te = (S) => {
1112
- R && S.target === S.currentTarget && w(null, null);
1113
- };
1114
- return /* @__PURE__ */ V(nr, { children: [
1115
- /* @__PURE__ */ v(
1116
- "div",
1117
- {
1118
- className: Ke("rc-inspect-overlay", R && "rc-inspect-overlay-select"),
1119
- style: {
1120
- left: `${i.left}px`,
1121
- top: `${i.top}px`,
1122
- width: `${i.width}px`,
1123
- height: `${i.height}px`
1124
- },
1125
- onClick: te,
1126
- children: e.elements.map((S) => /* @__PURE__ */ v(
1127
- Oo,
1128
- {
1129
- element: S,
1130
- screen: e.screen,
1131
- highlighted: S.id === c,
1132
- selected: S.id === l,
1133
- selectable: R,
1134
- onClick: w
1135
- },
1136
- S.id
1137
- ))
1138
- }
1139
- ),
1140
- fe && ge && /* @__PURE__ */ v(
1141
- bo,
1142
- {
1143
- element: fe,
1144
- platform: e.platform,
1145
- anchor: ge,
1146
- cursorAnchored: U,
1147
- showActions: Q,
1148
- onTap: O
1149
- }
1150
- )
1151
- ] });
1152
- }), Jr = () => import("./duo-view-D9Ae00rj.mjs").then((r) => r.d), Mo = Pn(Jr), H = (...r) => {
1153
- window.debugRemoteControl && console.log(...r);
1154
- }, A = (...r) => {
1155
- window.debugRemoteControl && console.warn(...r);
1156
- }, W = (r, e, ...i) => {
1157
- if (e)
1158
- try {
1159
- e(...i);
1160
- } catch (c) {
1161
- console.error(`[RemoteControl] customer callback "${r}" threw:`, c);
1162
- }
1163
- }, kt = (r) => Object.entries(x).find(
1164
- ([i, c]) => i.startsWith("ACTION_") && c === r
1165
- )?.[0] ?? String(r), So = (r) => r.includes("/android_") ? "android" : "ios", xr = (r, e) => {
1166
- const i = new URL(r);
1167
- return i.searchParams.set("token", e), i.toString();
1168
- }, Fr = 1920, Wr = 1200, rr = 3, Ro = 1e3, No = 15e3, Io = 3e3, Yo = 4e3, Ko = (r, e) => r === Fr && e === Wr || r === Wr && e === Fr, ko = {
1169
- ios: {
1170
- videoBorderRadiusMultiplier: 0.15,
1171
- loadingLogoSize: "20%",
1172
- // Video position as percentage of frame dimensions
1173
- videoPosition: {
1174
- portrait: { heightMultiplier: 0.9678 },
1175
- landscape: { widthMultiplier: 0.9678 }
1176
- }
1177
- },
1178
- android: {
1179
- videoBorderRadiusMultiplier: 0.13,
1180
- loadingLogoSize: "40%",
1181
- // Video position as percentage of frame dimensions
1182
- videoPosition: {
1183
- portrait: { heightMultiplier: 0.967 },
1184
- landscape: { widthMultiplier: 0.962 }
1185
- }
1186
- }
1187
- };
1188
- function Po(r) {
1189
- const e = r.code, i = $r[e];
1190
- if (!i)
1191
- return A(`Unknown event.code: ${e}, key: ${r.key}`), null;
1192
- let c = a.META_NONE;
1193
- const l = e >= "KeyA" && e <= "KeyZ", u = r.getModifierState("CapsLock"), E = r.shiftKey;
1194
- let y = E;
1195
- return l && (y = E !== u), y && (c |= a.META_SHIFT_ON), r.ctrlKey && (c |= a.META_CTRL_ON), r.altKey && (c |= a.META_ALT_ON), r.metaKey && (c |= a.META_META_ON), { keycode: i, metaState: c };
1196
- }
1197
- const Jo = Un(
1198
- ({
1199
- className: r,
1200
- url: e,
1201
- token: i,
1202
- sessionId: c,
1203
- openUrl: l,
1204
- showFrame: u = !0,
1205
- deviceModel: E,
1206
- duoModelUrl: y,
1207
- autoReconnect: w = !1,
1208
- onTerminated: O,
1209
- assets: R,
1210
- onConnectionStateChange: N,
1211
- inspectMode: j,
1212
- onAxSnapshotChange: ee,
1213
- onInspectSelectionChange: fe,
1214
- onAxStatusChange: Oe,
1215
- axPollIntervalMs: ge,
1216
- axMaxBackoffMs: U,
1217
- androidElementTreeOptions: Q,
1218
- onCameraDemandChange: te,
1219
- onCameraStats: S,
1220
- microphoneEnabled: F = !1,
1221
- onMicrophoneStateChange: re
1222
- }, ke) => {
1223
- const Ce = D(null), $ = D(null), Pe = D(null), [ir, sr] = q(!1), se = E === "iphone-duo" || ir;
1224
- le(() => {
1225
- se && Jr().catch(() => {
1226
- });
1227
- }, [se]);
1228
- const tt = D(null), [Lt, cr] = q(null), [ar, ur] = q(), Ue = D(
1229
- /* @__PURE__ */ new Map()
1230
- ), xt = (t, s) => new Promise((o, n) => {
1231
- const f = b.current;
1232
- if (!f || f.readyState !== WebSocket.OPEN) {
1233
- n(new Error("Simulator disconnected"));
1234
- return;
1235
- }
1236
- const d = crypto.randomUUID(), p = setTimeout(() => {
1237
- Ue.current.delete(d), n(new Error("Device control timed out"));
1238
- }, 5e3);
1239
- Ue.current.set(d, { resolve: o, reject: n, timer: p }), f.send(JSON.stringify({ type: t, id: d, ...s }));
1240
- }), [zr, Ft] = q(!1), [jr, gt] = q(!1), [Qr, dr] = q(!1), Le = D(!1), Wt = D(!1), [lr, Zr] = q(!1), [en, tn] = q(!1), [rn, fr] = q({}), b = D(null), X = D(null), L = D(null), xe = D(void 0), rt = D(void 0), nt = D(void 0), Ct = D(void 0), Fe = D(void 0), Te = D(0), yt = D(0), We = D(!1), Ht = D(w);
1241
- Ht.current = w;
1242
- const we = D(null), ce = D(null), be = D(void 0), $t = Ye(() => new po(), []), ye = D(te);
1243
- ye.current = te;
1244
- const vt = D(S);
1245
- vt.current = S;
1246
- const ot = D(null), Ot = D(null), Xt = D(F);
1247
- Xt.current = F;
1248
- const Bt = D(!1), it = D(re);
1249
- it.current = re;
1250
- const st = D(null), me = D(null), _t = D(0), hr = D(Promise.resolve()), He = D(null), ct = D(!1), _e = D(/* @__PURE__ */ new Map()), ve = D(/* @__PURE__ */ new Map()), Ae = D(/* @__PURE__ */ new Map()), Me = D(/* @__PURE__ */ new Map()), Z = D(/* @__PURE__ */ new Map()), Se = D(!1), [nn, on] = q(!1), G = D(null), $e = D(null), at = D({
1251
- handle: () => {
1252
- },
1253
- end: () => {
1254
- }
1255
- }), [Re, Dt] = q(null), ne = D(null), [pr, mr] = q(null), [qt, ut] = q(null), [Vt, Tt] = q(null), [sn, Er] = q(null), [cn, gr] = q(null), wt = D(null), de = D(void 0), Cr = (t) => {
1256
- wt.current = t, de.current === void 0 && (de.current = window.requestAnimationFrame(() => {
1257
- de.current = void 0, gr(wt.current);
1258
- }));
1259
- }, [an, Xe] = q(null), Be = D(j);
1260
- Be.current = j;
1261
- const qe = D(null);
1262
- qe.current = pr;
1263
- const Gt = D(ee);
1264
- Gt.current = ee;
1265
- const Ve = D(fe);
1266
- Ve.current = fe;
1267
- const yr = D(Oe);
1268
- yr.current = Oe;
1269
- const vr = D(O);
1270
- vr.current = O;
1271
- const Or = D(N);
1272
- Or.current = N;
1273
- const Jt = D(null), Ge = (t) => {
1274
- Jt.current !== t && (Jt.current = t, W("onConnectionStateChange", Or.current, t));
1275
- }, dt = j === !0 || j === "hover-only", un = j === "hover-only" ? "hover-only" : "select", he = Ye(
1276
- () => c || Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15),
1277
- [c]
1278
- ), Ee = Ye(() => So(e), [e]), Je = ko[Ee], lt = R?.[Ee], _r = Ee === "android" && en ? lr ? lt?.tabletFrameLandscape : lt?.tabletFrame : lr ? lt?.frameLandscape : lt?.frame, ft = lt?.loadingLogo, bt = !se && u && !!_r, k = (t) => {
1279
- H(t);
1280
- }, pe = (t) => {
1281
- !L.current || L.current.readyState !== "open" || (L.current.send(t), ne.current?.bumpActivity());
1282
- }, Dr = -10, Tr = (t, s) => {
1283
- const o = ht();
1284
- if (!o) return;
1285
- const n = je(o, t, s);
1286
- if (!n) return;
1287
- const { videoX: f, videoY: d, videoWidth: p, videoHeight: g } = n, C = Kt(
1288
- x.ACTION_DOWN,
1289
- Dr,
1290
- p,
1291
- g,
1292
- f,
1293
- d,
1294
- 1,
1295
- x.BUTTON_PRIMARY,
1296
- x.BUTTON_PRIMARY
1297
- );
1298
- C && pe(C), window.setTimeout(() => {
1299
- const m = Kt(
1300
- x.ACTION_UP,
1301
- Dr,
1302
- p,
1303
- g,
1304
- f,
1305
- d,
1306
- 0,
1307
- x.BUTTON_PRIMARY,
1308
- x.BUTTON_PRIMARY
1309
- );
1310
- m && pe(m);
1311
- }, 60);
1312
- }, dn = (t, s) => {
1313
- const o = ht();
1314
- if (!o || s.screen.width <= 0 || s.screen.height <= 0) return;
1315
- const n = t.frame.x + t.frame.width / 2, f = t.frame.y + t.frame.height / 2, d = n / s.screen.width * o.actualWidth, p = f / s.screen.height * o.actualHeight, g = o.videoRect.left + o.offsetX + d, C = o.videoRect.top + o.offsetY + p;
1316
- Tr(g, C);
1317
- }, At = -1, Mt = -2, Ne = -3, ze = (t, s, o, n, f, d) => {
1318
- const p = Kt(
1319
- t,
1320
- s,
1321
- o,
1322
- n,
1323
- f,
1324
- d,
1325
- 1,
1326
- // pressure
1327
- x.BUTTON_PRIMARY,
1328
- x.BUTTON_PRIMARY
1329
- );
1330
- p && (H("[rc-touch] sendSingleTouch", {
1331
- action: t,
1332
- actionName: kt(t),
1333
- pointerId: s,
1334
- x: f,
1335
- y: d,
1336
- video: { width: o, height: n }
1337
- }), pe(p));
1338
- }, Ie = (t, s, o) => {
1339
- if (!o) return;
1340
- const { videoX: n, videoY: f, videoWidth: d, videoHeight: p } = o;
1341
- let g = null, C = null, m = 1;
1342
- const I = x.BUTTON_PRIMARY;
1343
- switch (s) {
1344
- case "down":
1345
- t !== Ne && at.current.end(), g = Z.current.size === 0 ? x.ACTION_DOWN : x.ACTION_POINTER_DOWN, C = { x: n, y: f }, Z.current.set(t, C), t === -1 && $.current?.focus();
1346
- break;
1347
- case "move":
1348
- Z.current.has(t) && (g = x.ACTION_MOVE, C = { x: n, y: f }, Z.current.set(t, C));
1349
- break;
1350
- case "up":
1351
- case "cancel":
1352
- Z.current.has(t) && (C = Z.current.get(t), Z.current.delete(t), s === "cancel" ? g = x.ACTION_CANCEL : g = Z.current.size === 0 ? x.ACTION_UP : x.ACTION_POINTER_UP);
1353
- break;
1354
- }
1355
- if (g !== null && C !== null) {
1356
- H("[rc-touch][mouse->touch] sending", {
1357
- pointerId: t,
1358
- eventType: s,
1359
- action: g,
1360
- actionName: kt(g),
1361
- positionToSend: C,
1362
- video: { width: d, height: p },
1363
- altHeld: Se.current,
1364
- activePointersAfter: Array.from(Z.current.entries()).map(([Y, B]) => ({
1365
- id: Y,
1366
- x: B.x,
1367
- y: B.y
1368
- }))
1369
- });
1370
- const T = Kt(
1371
- g,
1372
- t,
1373
- d,
1374
- p,
1375
- C.x,
1376
- C.y,
1377
- m,
1378
- I,
1379
- I
1380
- );
1381
- T && (H("[rc-touch][mouse->touch] buffer", {
1382
- pointerId: t,
1383
- actionName: kt(g),
1384
- byteLength: T.byteLength
1385
- }), pe(T));
1386
- } else (s === "up" || s === "cancel") && Z.current.delete(t);
1387
- }, zt = (t) => {
1388
- if (Se.current !== t && (Se.current = t, on(t), t || Dt(null), H("[rc-touch][alt] updateAltHeld", {
1389
- nextHeld: t,
1390
- activePointerIds: Array.from(Z.current.keys())
1391
- }), Ee === "ios" && L.current && L.current.readyState === "open")) {
1392
- const s = t ? a.ACTION_DOWN : a.ACTION_UP, o = Et(
1393
- s,
1394
- a.KEYCODE_ALT_LEFT,
1395
- 0,
1396
- a.META_NONE
1397
- );
1398
- H("[rc-touch][alt] sending Indigo modifier keycode", {
1399
- action: s,
1400
- keycode: a.KEYCODE_ALT_LEFT
1401
- }), o && pe(o);
1402
- }
1403
- }, ht = () => {
1404
- const t = $.current, s = Ce.current;
1405
- if (!t || !s) return null;
1406
- const o = t.videoWidth, n = t.videoHeight;
1407
- if (!o || !n) return null;
1408
- const f = t.getBoundingClientRect(), d = s.getBoundingClientRect(), p = f.width, g = f.height, C = o / n, m = p / g;
1409
- let I = p, T = g;
1410
- C > m ? T = p / C : I = g * C;
1411
- const Y = (p - I) / 2, B = (g - T) / 2;
1412
- return {
1413
- videoWidth: o,
1414
- videoHeight: n,
1415
- videoRect: f,
1416
- containerRect: d,
1417
- actualWidth: I,
1418
- actualHeight: T,
1419
- offsetX: Y,
1420
- offsetY: B
1421
- };
1422
- }, je = (t, s, o) => {
1423
- const n = s - t.videoRect.left - t.offsetX, f = o - t.videoRect.top - t.offsetY, d = Math.max(0, Math.min(t.actualWidth, n)), p = Math.max(0, Math.min(t.actualHeight, f)), g = Math.max(
1424
- 0,
1425
- Math.min(t.videoWidth, d / t.actualWidth * t.videoWidth)
1426
- ), C = Math.max(
1427
- 0,
1428
- Math.min(t.videoHeight, p / t.actualHeight * t.videoHeight)
1429
- );
1430
- return {
1431
- videoX: g,
1432
- videoY: C,
1433
- videoWidth: t.videoWidth,
1434
- videoHeight: t.videoHeight
1435
- };
1436
- }, ln = (t, s, o) => {
1437
- const n = s - t.videoRect.left - t.offsetX, f = o - t.videoRect.top - t.offsetY, d = Math.max(0, Math.min(t.actualWidth, n)), p = Math.max(0, Math.min(t.actualHeight, f)), g = Math.max(
1438
- 0,
1439
- Math.min(t.videoWidth, d / t.actualWidth * t.videoWidth)
1440
- ), C = Math.max(
1441
- 0,
1442
- Math.min(t.videoHeight, p / t.actualHeight * t.videoHeight)
1443
- ), m = t.videoWidth - g, I = t.videoHeight - C, T = t.videoRect.left + t.offsetX, Y = t.videoRect.top + t.offsetY, B = T - t.containerRect.left + d, ae = Y - t.containerRect.top + p, z = T - t.containerRect.left + (t.actualWidth - d), _ = Y - t.containerRect.top + (t.actualHeight - p);
1444
- return {
1445
- containerX: B,
1446
- containerY: ae,
1447
- mirrorContainerX: z,
1448
- mirrorContainerY: _,
1449
- videoX: g,
1450
- videoY: C,
1451
- mirrorVideoX: m,
1452
- mirrorVideoY: I,
1453
- videoWidth: t.videoWidth,
1454
- videoHeight: t.videoHeight
1455
- };
1456
- }, fn = (t, s, o, n, f, d, p) => {
1457
- const g = Vn(t, s, o, n, f, d, p);
1458
- H("[rc-touch2] sendTwoFingerMessage (iOS)", {
1459
- actionName: kt(t),
1460
- video: { width: s, height: o },
1461
- p0: { x: n, y: f },
1462
- p1: { x: d, y: p },
1463
- byteLength: g.byteLength
1464
- }), pe(g);
1465
- }, Qe = (t, s, o, n, f, d, p, g, C) => {
1466
- if (H("[rc-touch2] applyTwoFingerEvent", {
1467
- platform: Ee,
1468
- eventType: t,
1469
- video: { width: s, height: o },
1470
- p0: { x: n, y: f, id: g },
1471
- p1: { x: d, y: p, id: C }
1472
- }), t === "down" && at.current.end(), Ee === "ios") {
1473
- const m = t === "down" ? x.ACTION_DOWN : t === "move" ? x.ACTION_MOVE : x.ACTION_UP;
1474
- fn(m, s, o, n, f, d, p);
1475
- } else
1476
- t === "down" ? (ze(x.ACTION_DOWN, g, s, o, n, f), ze(x.ACTION_POINTER_DOWN, C, s, o, d, p)) : t === "move" ? (ze(x.ACTION_MOVE, g, s, o, n, f), ze(x.ACTION_MOVE, C, s, o, d, p)) : (ze(x.ACTION_POINTER_UP, C, s, o, d, p), ze(x.ACTION_UP, g, s, o, n, f));
1477
- }, hn = (t, s, o) => {
1478
- if (!Se.current) {
1479
- Re !== null && Dt(null);
1480
- return;
1481
- }
1482
- const n = ln(t, s, o);
1483
- Dt(n);
1484
- }, pn = (t, s, o) => {
1485
- const n = qe.current;
1486
- if (!n || n.screen.width <= 0 || n.screen.height <= 0) return null;
1487
- const f = s - t.videoRect.left - t.offsetX, d = o - t.videoRect.top - t.offsetY;
1488
- if (f < 0 || d < 0 || f > t.actualWidth || d > t.actualHeight) return null;
1489
- const p = f / t.actualWidth * n.screen.width, g = d / t.actualHeight * n.screen.height;
1490
- return oo(n, p, g);
1491
- }, De = (t) => {
1492
- if (se) return;
1493
- t.preventDefault(), t.stopPropagation();
1494
- const s = ht();
1495
- if ((Be.current === !0 || Be.current === "hover-only") && !("touches" in t))
1496
- if (t.type === "mousemove") {
1497
- if (Cr({ x: t.clientX, y: t.clientY }), s) {
1498
- const n = pn(s, t.clientX, t.clientY);
1499
- ut(n?.id ?? null);
1500
- }
1501
- } else t.type === "mouseleave" && (Cr(null), ut(null));
1502
- if (Be.current !== !0 && (!("touches" in t) && s && (t.type === "mousemove" ? hn(s, t.clientX, t.clientY) : t.type === "mouseleave" && Dt(null)), !(!L.current || L.current.readyState !== "open" || !$.current || !s)))
1503
- if ("touches" in t) {
1504
- const n = t.touches, f = t.changedTouches;
1505
- let d;
1506
- switch (t.type) {
1507
- case "touchstart":
1508
- d = "down";
1509
- break;
1510
- case "touchmove":
1511
- d = "move";
1512
- break;
1513
- case "touchend":
1514
- d = "up";
1515
- break;
1516
- case "touchcancel":
1517
- d = "cancel";
1518
- break;
1519
- default:
1520
- return;
1521
- }
1522
- if (n.length === 2) {
1523
- const p = n[0], g = n[1], C = je(s, p.clientX, p.clientY), m = je(s, g.clientX, g.clientY);
1524
- if (!C || !m) return;
1525
- G.current ? G.current.source === "real-touch" && (G.current.finger0 = { x: C.videoX, y: C.videoY }, G.current.finger1 = { x: m.videoX, y: m.videoY }, Qe(
1526
- "move",
1527
- C.videoWidth,
1528
- C.videoHeight,
1529
- C.videoX,
1530
- C.videoY,
1531
- m.videoX,
1532
- m.videoY,
1533
- G.current.pointerId0,
1534
- G.current.pointerId1
1535
- )) : (G.current = {
1536
- finger0: { x: C.videoX, y: C.videoY },
1537
- finger1: { x: m.videoX, y: m.videoY },
1538
- videoSize: { width: C.videoWidth, height: C.videoHeight },
1539
- source: "real-touch",
1540
- pointerId0: p.identifier,
1541
- pointerId1: g.identifier
1542
- }, Qe(
1543
- "down",
1544
- C.videoWidth,
1545
- C.videoHeight,
1546
- C.videoX,
1547
- C.videoY,
1548
- m.videoX,
1549
- m.videoY,
1550
- p.identifier,
1551
- g.identifier
1552
- ));
1553
- } else if (n.length < 2 && G.current?.source === "real-touch") {
1554
- const p = G.current;
1555
- Qe(
1556
- "up",
1557
- p.videoSize.width,
1558
- p.videoSize.height,
1559
- p.finger0.x,
1560
- p.finger0.y,
1561
- p.finger1.x,
1562
- p.finger1.y,
1563
- p.pointerId0,
1564
- p.pointerId1
1565
- ), G.current = null;
1566
- return;
1567
- } else {
1568
- if (n.length > 2)
1569
- return;
1570
- {
1571
- const p = f[0];
1572
- if (p) {
1573
- const g = je(s, p.clientX, p.clientY);
1574
- Ie(p.identifier, d, g);
1575
- }
1576
- }
1577
- }
1578
- } else {
1579
- let f = null;
1580
- const d = G.current?.source === "alt-mouse";
1581
- switch (t.type) {
1582
- case "mousedown":
1583
- t.button === 0 && (f = "down");
1584
- break;
1585
- case "mousemove":
1586
- (d || Z.current.has(-1)) && (f = "move");
1587
- break;
1588
- case "mouseup":
1589
- t.button === 0 && (f = "up");
1590
- break;
1591
- case "mouseleave":
1592
- (d || Z.current.has(-1)) && (f = "up");
1593
- break;
1594
- }
1595
- if (f) {
1596
- const p = je(s, t.clientX, t.clientY);
1597
- if (!p)
1598
- return;
1599
- H("[rc-touch][mouse] event", {
1600
- domType: t.type,
1601
- eventType: f,
1602
- button: t.button,
1603
- buttons: t.buttons,
1604
- client: { x: t.clientX, y: t.clientY },
1605
- altHeldRef: Se.current,
1606
- inTwoFingerMode: d,
1607
- geometry: {
1608
- videoX: p.videoX,
1609
- videoY: p.videoY,
1610
- videoWidth: p.videoWidth,
1611
- videoHeight: p.videoHeight
1612
- },
1613
- activePointerIds: Array.from(Z.current.keys())
1614
- }), Se.current || d ? mn(f, p) : Ie(-1, f, p);
1615
- }
1616
- }
1617
- }, mn = (t, s) => {
1618
- const { videoX: o, videoY: n, videoWidth: f, videoHeight: d } = s, p = f - o, g = d - n;
1619
- if (t === "down") {
1620
- G.current = {
1621
- finger0: { x: o, y: n },
1622
- finger1: { x: p, y: g },
1623
- videoSize: { width: f, height: d },
1624
- source: "alt-mouse",
1625
- pointerId0: At,
1626
- pointerId1: Mt
1627
- }, $.current?.focus(), Qe(
1628
- "down",
1629
- f,
1630
- d,
1631
- o,
1632
- n,
1633
- p,
1634
- g,
1635
- At,
1636
- Mt
1637
- );
1638
- return;
1639
- }
1640
- if (t === "move") {
1641
- G.current?.source === "alt-mouse" && (G.current.finger0 = { x: o, y: n }, G.current.finger1 = { x: p, y: g }, Qe(
1642
- "move",
1643
- f,
1644
- d,
1645
- o,
1646
- n,
1647
- p,
1648
- g,
1649
- At,
1650
- Mt
1651
- ));
1652
- return;
1653
- }
1654
- if (t === "up" || t === "cancel") {
1655
- const C = G.current;
1656
- if (C?.source === "alt-mouse") {
1657
- const { finger0: m, finger1: I, videoSize: T } = C;
1658
- Qe(
1659
- "up",
1660
- T.width,
1661
- T.height,
1662
- m.x,
1663
- m.y,
1664
- I.x,
1665
- I.y,
1666
- At,
1667
- Mt
1668
- ), G.current = null;
1669
- }
1670
- return;
1671
- }
1672
- }, En = 150, wr = () => {
1673
- const t = $e.current;
1674
- t && (window.clearTimeout(t.endTimer), Ie(Ne, "up", t.pos), $e.current = null);
1675
- }, gn = (t) => {
1676
- if (t.ctrlKey || Se.current || G.current) return;
1677
- const s = Z.current.size;
1678
- if (s > 1 || s === 1 && !Z.current.has(Ne)) return;
1679
- const o = ht();
1680
- if (!o) return;
1681
- const n = t.clientX - o.videoRect.left - o.offsetX, f = t.clientY - o.videoRect.top - o.offsetY;
1682
- if (n < 0 || n > o.actualWidth || f < 0 || f > o.actualHeight)
1683
- return;
1684
- const d = je(o, t.clientX, t.clientY);
1685
- if (!d) return;
1686
- t.preventDefault();
1687
- const p = (t.deltaMode === 1 ? 16 : t.deltaMode === 2 ? o.actualWidth : 1) * (o.videoWidth / o.actualWidth), g = (t.deltaMode === 1 ? 16 : t.deltaMode === 2 ? o.actualHeight : 1) * (o.videoHeight / o.actualHeight), C = -t.deltaX * p, m = -t.deltaY * g, I = (_) => {
1688
- window.clearTimeout(_.endTimer), _.endTimer = window.setTimeout(wr, En);
1689
- };
1690
- if (C === 0 && m === 0) {
1691
- $e.current && I($e.current);
1692
- return;
1693
- }
1694
- const T = () => ({
1695
- videoWidth: d.videoWidth,
1696
- videoHeight: d.videoHeight,
1697
- videoX: Math.abs(C) > Math.abs(m) ? Math.min(Math.max(d.videoX, d.videoWidth * 0.2), d.videoWidth * 0.8) : d.videoX,
1698
- videoY: Math.abs(m) >= Math.abs(C) ? Math.min(Math.max(d.videoY, d.videoHeight * 0.2), d.videoHeight * 0.8) : d.videoY
1699
- }), Y = (_) => ({
1700
- ..._,
1701
- videoX: Math.min(Math.max(_.videoX + C, 0), _.videoWidth),
1702
- videoY: Math.min(Math.max(_.videoY + m, 0), _.videoHeight)
1703
- });
1704
- let B = $e.current;
1705
- if (B)
1706
- window.clearTimeout(B.endTimer);
1707
- else {
1708
- const _ = T();
1709
- Ie(Ne, "down", _), B = { pos: _, endTimer: 0 }, $e.current = B;
1710
- }
1711
- let ae = B.pos, z = Y(ae);
1712
- z.videoX === ae.videoX && z.videoY === ae.videoY && (Ie(Ne, "up", ae), ae = T(), Ie(Ne, "down", ae), z = Y(ae)), Ie(Ne, "move", z), B.pos = z, I(B);
1713
- };
1714
- le(() => {
1715
- at.current = { handle: gn, end: wr };
1716
- }), le(() => {
1717
- const t = Ce.current;
1718
- if (!t) return;
1719
- const s = (o) => at.current.handle(o);
1720
- return t.addEventListener("wheel", s, { passive: !1 }), () => {
1721
- at.current.end(), t.removeEventListener("wheel", s);
1722
- };
1723
- }, []), le(() => {
1724
- const t = (n) => {
1725
- n.key === "Alt" && zt(!0);
1726
- }, s = (n) => {
1727
- n.key === "Alt" && zt(!1);
1728
- }, o = () => {
1729
- zt(!1);
1730
- };
1731
- return window.addEventListener("keydown", t, !0), window.addEventListener("keyup", s, !0), window.addEventListener("blur", o), () => {
1732
- window.removeEventListener("keydown", t, !0), window.removeEventListener("keyup", s, !0), window.removeEventListener("blur", o);
1733
- };
1734
- }, []);
1735
- const St = (t) => {
1736
- t.preventDefault(), t.stopPropagation();
1737
- const s = document.activeElement === $.current || se && document.activeElement === t.currentTarget;
1738
- if (H("Keyboard event:", {
1739
- type: t.type,
1740
- key: t.key,
1741
- keyCode: t.keyCode,
1742
- code: t.code,
1743
- target: t.target.tagName,
1744
- focused: s
1745
- }), !s) {
1746
- A("Simulator input not focused, skipping keyboard event");
1747
- return;
1748
- }
1749
- if (!L.current || L.current.readyState !== "open") {
1750
- A("Data channel not ready for keyboard event:", L.current?.readyState);
1751
- return;
1752
- }
1753
- if (t.type === "keydown") {
1754
- if (t.key.toLowerCase() === "v" && (t.metaKey || t.ctrlKey)) {
1755
- H("Paste shortcut detected"), navigator.clipboard.readText().then((n) => {
1756
- if (n) {
1757
- H(
1758
- "Pasting text via SET_CLIPBOARD:",
1759
- n.substring(0, 20) + (n.length > 20 ? "..." : "")
1760
- );
1761
- const f = Gn(n, !0);
1762
- pe(f);
1763
- }
1764
- }).catch((n) => {
1765
- console.error("Failed to read clipboard contents: ", n);
1766
- });
1767
- return;
1768
- }
1769
- if (t.key.toLowerCase() === "m" && (t.metaKey || t.ctrlKey)) {
1770
- H("Menu shortcut detected");
1771
- const n = Et(
1772
- a.ACTION_DOWN,
1773
- a.MENU,
1774
- 0,
1775
- a.META_NONE
1776
- // Modifiers are handled by the shortcut check, not passed down
1777
- );
1778
- pe(n);
1779
- const f = Et(
1780
- a.ACTION_UP,
1781
- a.MENU,
1782
- 0,
1783
- a.META_NONE
1784
- );
1785
- pe(f);
1786
- return;
1787
- }
1788
- }
1789
- const o = Po(t);
1790
- if (o) {
1791
- const { keycode: n, metaState: f } = o, d = t.type === "keydown" ? a.ACTION_DOWN : a.ACTION_UP;
1792
- H(`Sending Keycode: key=${t.key}, code=${n}, action=${d}, meta=${f}`);
1793
- const p = Et(
1794
- d,
1795
- n,
1796
- 0,
1797
- // repeat count, typically 0 for single presses
1798
- f
1799
- );
1800
- pe(p);
1801
- } else
1802
- H(`Ignoring unhandled key event: type=${t.type}, key=${t.key}`);
1803
- }, Cn = () => {
1804
- b.current && b.current.readyState === WebSocket.OPEN && b.current.send(
1805
- JSON.stringify({
1806
- type: "keepAlive",
1807
- sessionId: he
1808
- })
1809
- );
1810
- }, br = () => {
1811
- xe.current && window.clearInterval(xe.current), xe.current = window.setInterval(Cn, 1e4);
1812
- }, Ar = () => {
1813
- xe.current && (window.clearInterval(xe.current), xe.current = void 0);
1814
- }, Rt = () => {
1815
- rt.current && (window.clearTimeout(rt.current), rt.current = void 0);
1816
- }, Nt = () => {
1817
- nt.current && (window.clearTimeout(nt.current), nt.current = void 0);
1818
- }, pt = () => {
1819
- Ct.current && (window.clearInterval(Ct.current), Ct.current = void 0);
1820
- }, mt = () => {
1821
- Fe.current !== void 0 && (window.clearTimeout(Fe.current), Fe.current = void 0);
1822
- }, yn = () => {
1823
- ct.current || (ct.current = !0, pt(), Ft(!0), Ge("connected"));
1824
- }, oe = (t) => {
1825
- for (const s of t.getTracks())
1826
- try {
1827
- s.stop();
1828
- } catch (o) {
1829
- A("track.stop() failed:", o);
1830
- }
1831
- }, vn = () => {
1832
- const t = ce.current;
1833
- t && (ce.current = null, oe(t));
1834
- }, Mr = (t) => {
1835
- const s = hr.current.then(t).catch((o) => {
1836
- A("microphone operation failed:", o);
1837
- });
1838
- return hr.current = s, s;
1839
- }, jt = () => Xt.current || Bt.current, Sr = (t) => {
1840
- const s = `ui-mic-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
1841
- He.current = s, t.send(JSON.stringify({ type: "microphoneStart", id: s }));
1842
- }, Qt = () => Mr(() => On()), On = async () => {
1843
- const t = _t.current, s = () => t === _t.current && jt(), o = (g) => {
1844
- W("onMicrophoneStateChange", it.current, {
1845
- active: !1,
1846
- error: g
1847
- });
1848
- };
1849
- if (!s()) return;
1850
- const n = b.current, f = st.current;
1851
- if (!n || n.readyState !== WebSocket.OPEN || !f || me.current) return;
1852
- if (!navigator.mediaDevices || typeof navigator.mediaDevices.getUserMedia != "function") {
1853
- console.warn(
1854
- "[RemoteControl] navigator.mediaDevices.getUserMedia unavailable. getUserMedia requires a secure context (https or http://localhost)."
1855
- ), o("Microphone capture requires a secure context (https)");
1856
- return;
1857
- }
1858
- let d = null;
1859
- try {
1860
- d = await navigator.mediaDevices.getUserMedia({ audio: !0, video: !1 });
1861
- } catch (g) {
1862
- console.warn("[RemoteControl] microphone getUserMedia denied/failed:", g);
1863
- }
1864
- if (!s()) {
1865
- d && oe(d);
1866
- return;
1867
- }
1868
- if (!d) {
1869
- o("Microphone permission denied or no device available");
1870
- return;
1871
- }
1872
- const p = d.getAudioTracks()[0] ?? null;
1873
- if (!p) {
1874
- oe(d), o("Captured stream has no audio track");
1875
- return;
1876
- }
1877
- try {
1878
- await f.replaceTrack(p);
1879
- } catch (g) {
1880
- A("replaceTrack(audioTrack) failed:", g), oe(d), o("Failed to attach the microphone track to the connection");
1881
- return;
1882
- }
1883
- if (!s()) {
1884
- try {
1885
- await f.replaceTrack(null);
1886
- } catch (g) {
1887
- A("replaceTrack(null) on stale mic attach failed:", g);
1888
- }
1889
- oe(d);
1890
- return;
1891
- }
1892
- me.current = d, p.onended = () => {
1893
- me.current === d && It("microphone capture ended by the browser");
1894
- }, Sr(n), W("onMicrophoneStateChange", it.current, {
1895
- active: !0,
1896
- label: p.label || void 0
1897
- });
1898
- }, It = (t) => (++_t.current, He.current = null, Mr(async () => {
1899
- const s = st.current, o = me.current;
1900
- if (me.current = null, s && o)
1901
- try {
1902
- await s.replaceTrack(null);
1903
- } catch (f) {
1904
- A("replaceTrack(null) on mic detach failed:", f);
1905
- }
1906
- o && oe(o);
1907
- const n = b.current;
1908
- if (o && n && n.readyState === WebSocket.OPEN) {
1909
- const f = `ui-mic-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
1910
- n.send(JSON.stringify({ type: "microphoneStop", id: f }));
1911
- }
1912
- (o || t) && W("onMicrophoneStateChange", it.current, {
1913
- active: !1,
1914
- ...t !== void 0 && { error: t }
1915
- });
1916
- })), Rr = (t, s) => {
1917
- let o;
1918
- try {
1919
- o = yo(s), console.info(
1920
- `[RemoteControl] camera capture: ${o.camera?.width}x${o.camera?.height} @ ${o.camera?.frameRate ?? "?"}fps` + (o.camera?.label ? ` — ${o.camera.label}` : "")
1921
- );
1922
- } catch (n) {
1923
- A("getSettings() on outbound camera track failed:", n), o = {
1924
- type: "cameraResult",
1925
- granted: !0,
1926
- camera: {
1927
- label: s.label || void 0
1928
- }
1929
- };
1930
- }
1931
- t.send(JSON.stringify(o)), W("onCameraDemandChange", ye.current, !0, !0, o.camera);
1932
- }, _n = (t) => {
1933
- if (!t) return;
1934
- const s = t.indexOf("/"), n = (s >= 0 ? t.slice(s + 1) : t).toUpperCase();
1935
- return n === "HEVC" ? "H265" : n;
1936
- }, Dn = async () => {
1937
- const t = we.current, s = vt.current;
1938
- if (!t || !s) return;
1939
- let o;
1940
- try {
1941
- o = await t.getStats();
1942
- } catch {
1943
- return;
1944
- }
1945
- let n, f, d;
1946
- if (o.forEach((Y) => {
1947
- Y.type === "outbound-rtp" && Y.kind === "video" ? n = Y : Y.type === "remote-inbound-rtp" && Y.kind === "video" && (d = Y);
1948
- }), n?.codecId) {
1949
- const Y = o.get(n.codecId);
1950
- Y && (f = Y.mimeType);
1951
- }
1952
- if (!n) return;
1953
- const p = n.timestamp ?? Date.now(), g = Ot.current;
1954
- let C, m, I;
1955
- if (g && p > g.timestamp) {
1956
- const Y = (p - g.timestamp) / 1e3;
1957
- if (typeof n.framesEncoded == "number" && typeof g.framesEncoded == "number" && (C = Math.max(0, (n.framesEncoded - g.framesEncoded) / Y)), typeof n.bytesSent == "number" && typeof g.bytesSent == "number" && (m = Math.max(0, (n.bytesSent - g.bytesSent) * 8 / Y)), typeof n.packetsSent == "number" && typeof g.packetsSent == "number" && d && typeof d.packetsLost == "number" && typeof g.packetsLost == "number") {
1958
- const B = n.packetsSent - g.packetsSent, ae = d.packetsLost - g.packetsLost;
1959
- B > 0 && (I = Math.max(0, Math.min(100, ae / B * 100)));
1960
- }
1961
- }
1962
- Ot.current = {
1963
- timestamp: p,
1964
- framesEncoded: n.framesEncoded,
1965
- bytesSent: n.bytesSent,
1966
- packetsSent: n.packetsSent,
1967
- packetsLost: d?.packetsLost
1968
- };
1969
- const T = {
1970
- codec: _n(f),
1971
- encoderImplementation: n.encoderImplementation,
1972
- hardwareAccelerated: typeof n.powerEfficientEncoder == "boolean" ? n.powerEfficientEncoder : void 0,
1973
- framesPerSecond: C,
1974
- framesEncoded: n.framesEncoded,
1975
- bitrateBps: m,
1976
- width: n.frameWidth,
1977
- height: n.frameHeight,
1978
- qualityLimitationReason: n.qualityLimitationReason,
1979
- rttMs: typeof d?.roundTripTime == "number" ? d.roundTripTime * 1e3 : void 0,
1980
- packetsLostPct: I
1981
- };
1982
- W("onCameraStats", vt.current, T);
1983
- }, Nr = () => {
1984
- ot.current === null && (Ot.current = null, ot.current = setInterval(() => {
1985
- Dn();
1986
- }, 1e3));
1987
- }, Yt = () => {
1988
- ot.current !== null && (clearInterval(ot.current), ot.current = null), Ot.current = null, W("onCameraStats", vt.current, null);
1989
- }, Tn = (t, s, o, n) => $t.enqueue(async ({ isCurrent: f }) => {
1990
- const d = () => f() && n() && b.current === s && we.current === o;
1991
- if (!d()) return;
1992
- if (!t.active) {
1993
- const T = ce.current;
1994
- try {
1995
- await o.replaceTrack(null);
1996
- } catch (Y) {
1997
- A("replaceTrack(null) on camera detach failed:", Y);
1998
- }
1999
- if (ce.current === T && (ce.current = null, be.current = void 0, T && oe(T)), Yt(), !d()) return;
2000
- W("onCameraDemandChange", ye.current, !1);
2001
- return;
2002
- }
2003
- W("onCameraDemandChange", ye.current, !0);
2004
- const p = ce.current, g = p?.getVideoTracks()[0], C = be.current;
2005
- if (g?.readyState === "live" && C && !go(C, t)) {
2006
- be.current = t, Rr(s, g), Nr();
2007
- return;
2008
- }
2009
- if (p) {
2010
- try {
2011
- await o.replaceTrack(null);
2012
- } catch (T) {
2013
- A("replaceTrack(null) before camera switch failed:", T);
2014
- }
2015
- if (ce.current === p && (ce.current = null, be.current = void 0, oe(p)), Yt(), !d()) return;
2016
- }
2017
- if (!navigator.mediaDevices || typeof navigator.mediaDevices.getUserMedia != "function") {
2018
- if (console.warn(
2019
- "[RemoteControl] navigator.mediaDevices.getUserMedia unavailable. getUserMedia requires a secure context (https or http://localhost). Replying cameraResult granted=false so limulator falls back to black frames."
2020
- ), !d()) return;
2021
- s.send(JSON.stringify({ type: "cameraResult", granted: !1 })), W("onCameraDemandChange", ye.current, !0, !1);
2022
- return;
2023
- }
2024
- let m = null;
2025
- try {
2026
- m = await navigator.mediaDevices.getUserMedia({
2027
- video: Eo(t),
2028
- audio: !1
2029
- });
2030
- } catch (T) {
2031
- console.warn("[RemoteControl] getUserMedia denied/failed:", T);
2032
- }
2033
- if (!d()) {
2034
- m && oe(m);
2035
- return;
2036
- }
2037
- if (!m) {
2038
- s.send(JSON.stringify({ type: "cameraResult", granted: !1 })), W("onCameraDemandChange", ye.current, !0, !1);
2039
- return;
2040
- }
2041
- const I = m.getVideoTracks()[0] ?? null;
2042
- if (!I) {
2043
- if (oe(m), !d()) return;
2044
- s.send(JSON.stringify({ type: "cameraResult", granted: !1 })), W("onCameraDemandChange", ye.current, !0, !1);
2045
- return;
2046
- }
2047
- try {
2048
- I.contentHint = "motion";
2049
- } catch {
2050
- }
2051
- try {
2052
- await o.replaceTrack(I);
2053
- } catch (T) {
2054
- if (A("replaceTrack(videoTrack) failed:", T), oe(m), !d()) return;
2055
- s.send(JSON.stringify({ type: "cameraResult", granted: !1 })), W("onCameraDemandChange", ye.current, !0, !1);
2056
- return;
2057
- }
2058
- if (!d()) {
2059
- try {
2060
- await o.replaceTrack(null);
2061
- } catch (T) {
2062
- A("replaceTrack(null) for stale camera attach failed:", T);
2063
- }
2064
- oe(m);
2065
- return;
2066
- }
2067
- try {
2068
- const T = o.getParameters();
2069
- (!T.encodings || T.encodings.length === 0) && (T.encodings = [{}]), T.encodings[0].maxBitrate = 8e6, T.encodings[0].maxFramerate = 30, T.degradationPreference = "maintain-framerate", await o.setParameters(T);
2070
- } catch (T) {
2071
- A("setParameters on outbound camera failed:", T);
2072
- }
2073
- if (!d()) {
2074
- try {
2075
- await o.replaceTrack(null);
2076
- } catch (T) {
2077
- A("replaceTrack(null) for stale camera finalize failed:", T);
2078
- }
2079
- oe(m);
2080
- return;
2081
- }
2082
- ce.current = m, be.current = t, I.onended = () => {
2083
- ce.current === m && $t.enqueueCurrent(async ({ isCurrent: T }) => {
2084
- if (!(!T() || ce.current !== m || !n() || b.current !== s || we.current !== o)) {
2085
- try {
2086
- await o.replaceTrack(null);
2087
- } catch (Y) {
2088
- A("replaceTrack(null) after camera ended failed:", Y);
2089
- }
2090
- !T() || ce.current !== m || !n() || b.current !== s || we.current !== o || (ce.current = null, be.current = void 0, oe(m), Yt(), s.send(JSON.stringify({ type: "cameraResult", granted: !1 })), W("onCameraDemandChange", ye.current, !0, !1));
2091
- }
2092
- }).catch((T) => A("camera ended cleanup failed:", T));
2093
- }, d() && (Rr(s, I), Nr());
2094
- }), Ze = () => {
2095
- for (const t of Ue.current.values())
2096
- clearTimeout(t.timer), t.reject(new Error("Simulator disconnected"));
2097
- Ue.current.clear(), cr(null), tt.current && (tt.current.srcObject = null), Nt(), mt(), pt(), ne.current && (ne.current.stop(), ne.current = null), $t.invalidate(), Yt(), vn(), be.current = void 0, we.current = null, ++_t.current, Bt.current = !1, He.current = null, me.current && (oe(me.current), me.current = null, W("onMicrophoneStateChange", it.current, {
2098
- active: !1
2099
- })), st.current = null, de.current !== void 0 && (window.cancelAnimationFrame(de.current), de.current = void 0), b.current && (b.current.onopen = null, b.current.onmessage = null, b.current.onerror = null, b.current.onclose = null, b.current.close(), b.current = null), X.current && (X.current.onconnectionstatechange = null, X.current.oniceconnectionstatechange = null, X.current.ontrack = null, X.current.onicecandidate = null, X.current.close(), X.current = null), $.current && ($.current.srcObject = null), L.current && (L.current.onopen = null, L.current.onclose = null, L.current.onerror = null, L.current.close(), L.current = null);
2100
- }, Ir = () => {
2101
- document.hidden ? Ar() : br();
2102
- }, wn = async () => {
2103
- if (typeof navigator < "u" && navigator.onLine === !1)
2104
- return !1;
2105
- let t;
2106
- try {
2107
- const n = new URL(e);
2108
- n.protocol = n.protocol === "wss:" ? "https:" : n.protocol === "ws:" ? "http:" : n.protocol, t = xr(n.toString(), i);
2109
- } catch {
2110
- return !1;
2111
- }
2112
- const s = new AbortController(), o = window.setTimeout(() => s.abort(), Yo);
2113
- try {
2114
- return (await fetch(t, { method: "GET", cache: "no-store", signal: s.signal })).status === 404;
2115
- } catch {
2116
- return !1;
2117
- } finally {
2118
- window.clearTimeout(o);
2119
- }
2120
- }, bn = () => {
2121
- Le.current || (Le.current = !0, dr(!0), gt(!1), Te.current += 1, Rt(), Nt(), mt(), Ze(), k("Instance terminated"), Ge("terminated"), W("onTerminated", vr.current));
2122
- }, An = () => {
2123
- Le.current || Wt.current || (Wt.current = !0, wn().then((t) => {
2124
- Wt.current = !1, t && bn();
2125
- }));
2126
- }, et = (t, s) => {
2127
- if (Le.current || s !== Te.current)
2128
- return;
2129
- if (An(), We.current) {
2130
- if (!Ht.current) {
2131
- k(`Connection failed after it was established: ${t}`), gt(!0), Ge("failed"), Ze();
2132
- return;
2133
- }
2134
- k(`Reconnecting after established session dropped: ${t}`), We.current = !1, yt.current = -1;
2135
- }
2136
- Rt();
2137
- const o = yt.current + 1;
2138
- if (o >= rr) {
2139
- k(`Connection failed after ${rr} attempts: ${t}`), gt(!0), Ge("failed"), Ze();
2140
- return;
2141
- }
2142
- k(`Retrying connection (${o + 1}/${rr})`), Ge("reconnecting"), Ze(), rt.current = window.setTimeout(() => {
2143
- rt.current = void 0, s === Te.current && Yr(o);
2144
- }, Ro);
2145
- }, Yr = async (t = 0) => {
2146
- if (Le.current) return;
2147
- const s = Te.current + 1;
2148
- Te.current = s, yt.current = t, We.current = !1, gt(!1), t === 0 && Jt.current !== "reconnecting" && Ge("connecting"), Rt(), Nt(), pt(), ct.current = !1, Ft(!1), Ze();
2149
- const o = () => s === Te.current;
2150
- nt.current = window.setTimeout(() => {
2151
- nt.current = void 0, !(!o() || We.current) && et("Connection did not succeed within 15 seconds", s);
2152
- }, No);
2153
- try {
2154
- const n = new WebSocket(xr(e, i));
2155
- if (b.current = n, await new Promise((_, h) => {
2156
- let P = !1;
2157
- const ie = window.setTimeout(() => h(new Error("WebSocket connection timeout")), 3e4), M = (K) => {
2158
- P || (P = !0, window.clearTimeout(ie), K());
2159
- };
2160
- n.onopen = () => {
2161
- !o() || b.current !== n || M(_);
2162
- }, n.onerror = (K) => {
2163
- !o() || b.current !== n || (k("WebSocket error: " + K), M(() => h(new Error("WebSocket connection failed"))));
2164
- }, n.onclose = () => {
2165
- !o() || b.current !== n || (k("WebSocket closed"), M(() => h(new Error("WebSocket closed before connection was established"))));
2166
- };
2167
- }), !o() || b.current !== n)
2168
- return;
2169
- n.onerror = (_) => {
2170
- !o() || b.current !== n || k("WebSocket error: " + _);
2171
- }, n.onclose = () => {
2172
- !o() || b.current !== n || k("WebSocket closed");
2173
- };
2174
- const f = new Promise((_, h) => {
2175
- const P = (K) => {
2176
- window.clearTimeout(ie), n.removeEventListener("message", M), K();
2177
- }, ie = window.setTimeout(
2178
- () => P(() => h(new Error("RTCConfiguration timeout"))),
2179
- 3e4
2180
- ), M = (K) => {
2181
- if (!(!o() || b.current !== n))
2182
- try {
2183
- const J = JSON.parse(K.data);
2184
- if (J.type === "signalingError" && J.requestType === "requestRtcConfiguration" && J.sessionId === he) {
2185
- const ue = typeof J.error == "string" ? J.error : "Unable to load streaming configuration";
2186
- P(() => h(new Error(ue)));
2187
- } else J.type === "rtcConfiguration" && P(
2188
- () => _({
2189
- rtcConfiguration: J.rtcConfiguration,
2190
- cameraSupported: J.cameraSupported === !0,
2191
- foldSupported: J.foldSupported === !0
2192
- })
2193
- );
2194
- } catch (J) {
2195
- console.error("Error handling RTC configuration:", J), P(() => h(J));
2196
- }
2197
- };
2198
- n.addEventListener("message", M), n.send(
2199
- JSON.stringify({
2200
- type: "requestRtcConfiguration",
2201
- sessionId: he
2202
- })
2203
- );
2204
- }), {
2205
- rtcConfiguration: d,
2206
- cameraSupported: p,
2207
- foldSupported: g
2208
- } = await f;
2209
- if (!o() || b.current !== n)
2210
- return;
2211
- const C = E === "iphone-duo" || g;
2212
- sr(C);
2213
- const m = new RTCPeerConnection(d);
2214
- X.current = m, m.addTransceiver("audio", { direction: "recvonly" });
2215
- const I = m.addTransceiver("video", { direction: "recvonly" }), T = C ? m.addTransceiver("video", { direction: "recvonly" }) : null, Y = Ee === "ios" || p, B = Y ? m.addTransceiver("video", {
2216
- direction: "sendonly"
2217
- }) : null;
2218
- we.current = B?.sender ?? null;
2219
- const ae = Y ? m.addTransceiver("audio", {
2220
- direction: "sendonly"
2221
- }) : null;
2222
- if (st.current = ae?.sender ?? null, RTCRtpReceiver.getCapabilities) {
2223
- const _ = RTCRtpReceiver.getCapabilities("video");
2224
- if (_ && _.codecs) {
2225
- const P = _.codecs.sort((ie, M) => {
2226
- const K = (J) => {
2227
- const ue = J.mimeType.toLowerCase();
2228
- return ue.includes("vp9") ? 1 : ue.includes("h265") || ue.includes("hevc") ? 2 : ue.includes("h264") || ue.includes("avc") ? 3 : 4;
2229
- };
2230
- return K(ie) - K(M);
2231
- });
2232
- I.setCodecPreferences(P), T?.setCodecPreferences(P), H("Set codec preferences:", P.map((ie) => ie.mimeType).join(", "));
2233
- }
2234
- }
2235
- if (B && RTCRtpSender.getCapabilities) {
2236
- const _ = RTCRtpSender.getCapabilities("video");
2237
- if (_ && _.codecs) {
2238
- const h = /* @__PURE__ */ new Set(["42e01f", "42e028", "640c1f"]), P = (M) => {
2239
- const K = M.mimeType.toLowerCase(), ue = (M.sdpFmtpLine || "").toLowerCase().match(/profile-level-id=([0-9a-f]{6})/), In = ue ? ue[1] : "";
2240
- return K === "video/h265" || K === "video/hevc" ? 1 : K === "video/h264" && h.has(In) ? 2 : K === "video/h264" ? 3 : K === "video/vp9" ? 4 : K === "video/vp8" ? 5 : K === "video/rtx" || K === "video/red" || K === "video/ulpfec" ? 0 : 6;
2241
- }, ie = [..._.codecs].sort((M, K) => P(M) - P(K));
2242
- try {
2243
- B.setCodecPreferences(ie), H(
2244
- "Outbound camera codec preferences:",
2245
- ie.map((M) => `${M.mimeType}${M.sdpFmtpLine ? `[${M.sdpFmtpLine}]` : ""}`).join(", ")
2246
- );
2247
- } catch (M) {
2248
- A("Failed to set outbound camera codec preferences:", M);
2249
- }
2250
- }
2251
- }
2252
- const z = m.createDataChannel("control", {
2253
- ordered: !0,
2254
- negotiated: !0,
2255
- id: 1
2256
- });
2257
- if (L.current = z, z.onopen = () => {
2258
- if (!o() || L.current !== z || b.current !== n)
2259
- return;
2260
- We.current = !0, Nt(), k("Control channel opened"), ne.current || (ne.current = new ho({
2261
- platform: Ee,
2262
- baseIntervalMs: ge,
2263
- maxBackoffMs: U,
2264
- androidElementTreeOptions: Q,
2265
- send: (h) => {
2266
- if (!b.current || b.current.readyState !== WebSocket.OPEN) return !1;
2267
- try {
2268
- return b.current.send(JSON.stringify(h)), !0;
2269
- } catch {
2270
- return !1;
2271
- }
2272
- },
2273
- onSnapshot: (h) => {
2274
- mr((P) => qr(P, h) ? P : h), queueMicrotask(() => {
2275
- W("onAxSnapshotChange", Gt.current, h);
2276
- });
2277
- },
2278
- onStatusChange: (h, P) => {
2279
- W("onAxStatusChange", yr.current, h, P);
2280
- }
2281
- }), (Be.current === !0 || Be.current === "hover-only") && ne.current.start());
2282
- const _ = () => {
2283
- !o() || ct.current || L.current !== z || b.current !== n || n.readyState !== WebSocket.OPEN || n.send(JSON.stringify({ type: "requestFrame", sessionId: he }));
2284
- };
2285
- if (_(), pt(), Ct.current = window.setInterval(() => {
2286
- if (!o() || ct.current || L.current !== z || b.current !== n || n.readyState !== WebSocket.OPEN) {
2287
- pt();
2288
- return;
2289
- }
2290
- _();
2291
- }, 250), l) {
2292
- try {
2293
- const h = decodeURIComponent(l);
2294
- k("Opening URL"), n.send(
2295
- JSON.stringify({
2296
- type: "openUrl",
2297
- url: h,
2298
- sessionId: he
2299
- })
2300
- );
2301
- } catch (h) {
2302
- console.error({ error: h }, "Error decoding URL, falling back to the original URL"), n.send(
2303
- JSON.stringify({
2304
- type: "openUrl",
2305
- url: l,
2306
- sessionId: he
2307
- })
2308
- );
2309
- }
2310
- ne.current?.bumpActivity();
2311
- }
2312
- }, z.onclose = () => {
2313
- !o() || L.current !== z || k("Control channel closed");
2314
- }, z.onerror = (_) => {
2315
- !o() || L.current !== z || (console.error("Control channel error:", _), k("Control channel error: " + _));
2316
- }, m.onconnectionstatechange = () => {
2317
- !o() || X.current !== m || (k("Connection state: " + m.connectionState), m.connectionState === "failed" && et("WebRTC connection entered failed state", s));
2318
- }, m.oniceconnectionstatechange = () => {
2319
- if (!o() || X.current !== m)
2320
- return;
2321
- const _ = m.iceConnectionState;
2322
- if (k("ICE state: " + _), _ === "connected" || _ === "completed") {
2323
- mt(), jt() && !me.current && Qt();
2324
- return;
2325
- }
2326
- if (_ === "failed") {
2327
- mt(), et("ICE connection entered failed state", s);
2328
- return;
2329
- }
2330
- _ === "disconnected" && Ht.current && Fe.current === void 0 && (Fe.current = window.setTimeout(() => {
2331
- Fe.current = void 0, !(!o() || X.current !== m) && m.iceConnectionState === "disconnected" && et("ICE stayed disconnected past grace period", s);
2332
- }, Io));
2333
- }, m.ontrack = (_) => {
2334
- if (!(!o() || X.current !== m) && (k("Received remote track: " + _.track.kind), _.track.kind === "video" && $.current)) {
2335
- H(`[${(/* @__PURE__ */ new Date()).toISOString()}] Video track received:`, _.track);
2336
- const P = _.track.id === "duo-inner" || _.streams.some((ie) => ie.id === "duo-inner") ? tt.current : $.current;
2337
- P && (P.srcObject = C ? new MediaStream([_.track]) : _.streams[0] ?? new MediaStream([_.track]), P.play().catch(() => {
2338
- }));
2339
- }
2340
- }, m.onicecandidate = (_) => {
2341
- if (!(!o() || X.current !== m || b.current !== n))
2342
- if (_.candidate && n.readyState === WebSocket.OPEN) {
2343
- const h = {
2344
- type: "candidate",
2345
- candidate: _.candidate.candidate,
2346
- sdpMid: _.candidate.sdpMid,
2347
- sdpMLineIndex: _.candidate.sdpMLineIndex,
2348
- sessionId: he
2349
- };
2350
- n.send(JSON.stringify(h)), k("Sent ICE candidate");
2351
- } else
2352
- k("ICE candidate gathering completed");
2353
- }, n.onmessage = async (_) => {
2354
- if (!o() || b.current !== n)
2355
- return;
2356
- let h;
2357
- try {
2358
- h = JSON.parse(_.data);
2359
- } catch (P) {
2360
- A("Error parsing message:", P);
2361
- return;
2362
- }
2363
- if (!ne.current?.handleMessage(h))
2364
- switch (k("Received: " + h.type), h.type) {
2365
- case "performActionsResult":
2366
- case "foldStateResult":
2367
- case "foldStateChanged": {
2368
- if (!C) break;
2369
- h.state ? (cr(h.state), ur(void 0)) : h.id === "duo-capabilities" && ur(h.error || "This instance does not support native iPhone Duo displays.");
2370
- const M = Ue.current.get(h.id);
2371
- M && (clearTimeout(M.timer), Ue.current.delete(h.id), h.error ? M.reject(new Error(h.error)) : M.resolve());
2372
- break;
2373
- }
2374
- case "signalingError": {
2375
- if (h.requestType !== "offer" || h.sessionId !== he)
2376
- break;
2377
- const M = typeof h.error == "string" ? h.error : "Unable to establish the streaming connection";
2378
- k("Error: " + M), et(M, s);
2379
- break;
2380
- }
2381
- case "answer":
2382
- if (!X.current || X.current !== m) {
2383
- k("No peer connection, skipping answer");
2384
- break;
2385
- }
2386
- if (await m.setRemoteDescription(
2387
- new RTCSessionDescription({
2388
- type: "answer",
2389
- sdp: h.sdp
2390
- })
2391
- ), !o() || X.current !== m)
2392
- return;
2393
- k("Set remote description");
2394
- break;
2395
- case "candidate":
2396
- if (!X.current || X.current !== m) {
2397
- k("No peer connection, skipping candidate");
2398
- break;
2399
- }
2400
- if (await m.addIceCandidate(
2401
- new RTCIceCandidate({
2402
- candidate: h.candidate,
2403
- sdpMid: h.sdpMid,
2404
- sdpMLineIndex: h.sdpMLineIndex
2405
- })
2406
- ), !o() || X.current !== m)
2407
- return;
2408
- k("Added ICE candidate");
2409
- break;
2410
- case "screenshot":
2411
- case "screenshotResult": {
2412
- if (typeof h.id != "string") {
2413
- A("Received invalid screenshot success message:", h);
2414
- break;
2415
- }
2416
- const M = Uo(h);
2417
- if (M) {
2418
- const ue = ve.current.get(h.id);
2419
- if (!ue) {
2420
- A(`Received screenshot error for unknown or handled id: ${h.id}`);
2421
- break;
2422
- }
2423
- A(`Received screenshot error for id ${h.id}: ${M}`), ue(new Error(M)), _e.current.delete(h.id), ve.current.delete(h.id);
2424
- break;
2425
- }
2426
- const K = Lo(h);
2427
- if (!K) {
2428
- A("Received screenshot message without image data:", h);
2429
- break;
2430
- }
2431
- const J = _e.current.get(h.id);
2432
- if (!J) {
2433
- A(`Received screenshot data for unknown or handled id: ${h.id}`);
2434
- break;
2435
- }
2436
- H(`Received screenshot data for id ${h.id}`), J(K), _e.current.delete(h.id), ve.current.delete(h.id);
2437
- break;
2438
- }
2439
- case "screenshotError":
2440
- if (typeof h.id != "string" || typeof h.message != "string") {
2441
- A("Received invalid screenshot error message:", h);
2442
- break;
2443
- }
2444
- const P = ve.current.get(h.id);
2445
- if (!P) {
2446
- A(`Received screenshot error for unknown or handled id: ${h.id}`);
2447
- break;
2448
- }
2449
- A(`Received screenshot error for id ${h.id}: ${h.message}`), P(new Error(h.message)), _e.current.delete(h.id), ve.current.delete(h.id);
2450
- break;
2451
- case "cameraRequest": {
2452
- const M = we.current;
2453
- if (!M)
2454
- break;
2455
- const K = mo(h);
2456
- if (!K) {
2457
- A("Received invalid cameraRequest:", h);
2458
- break;
2459
- }
2460
- console.info("[RemoteControl] cameraRequest received:", K.active, K.facingMode), await Tn(K, n, M, o);
2461
- break;
2462
- }
2463
- case "microphoneRequest": {
2464
- if (!st.current)
2465
- break;
2466
- const M = h.active === !0;
2467
- if (Bt.current = M, console.info("[RemoteControl] microphoneRequest received, active=", M), !M) {
2468
- Xt.current || await It();
2469
- break;
2470
- }
2471
- if (me.current) {
2472
- Sr(n);
2473
- break;
2474
- }
2475
- await Qt();
2476
- break;
2477
- }
2478
- case "microphoneStartResult": {
2479
- if (He.current === null || h.id !== He.current)
2480
- break;
2481
- He.current = null, typeof h.error == "string" && (console.warn("[RemoteControl] microphoneStart rejected by host:", h.error), It(h.error));
2482
- break;
2483
- }
2484
- case "terminateAppResult":
2485
- if (typeof h.id != "string") {
2486
- A("Received invalid terminateApp result message:", h);
2487
- break;
2488
- }
2489
- if (typeof h.error == "string") {
2490
- const M = Me.current.get(h.id);
2491
- if (!M) {
2492
- A(`Received terminateApp error for unknown or handled id: ${h.id}`);
2493
- break;
2494
- }
2495
- A(`Received terminateApp error for id ${h.id}: ${h.error}`), M(new Error(h.error)), Ae.current.delete(h.id), Me.current.delete(h.id);
2496
- break;
2497
- }
2498
- const ie = Ae.current.get(h.id);
2499
- if (!ie) {
2500
- A(`Received terminateApp result for unknown or handled id: ${h.id}`);
2501
- break;
2502
- }
2503
- H(`Received terminateApp success for id ${h.id}`), ie(), Ae.current.delete(h.id), Me.current.delete(h.id);
2504
- break;
2505
- default:
2506
- A(`Received unhandled message type: ${h.type}`, h);
2507
- break;
2508
- }
2509
- }, C && n.send(JSON.stringify({ type: "getFoldState", id: "duo-capabilities" })), X.current === m) {
2510
- const _ = await m.createOffer({
2511
- offerToReceiveVideo: !0,
2512
- offerToReceiveAudio: !1
2513
- });
2514
- if (!o() || X.current !== m || (await m.setLocalDescription(_), !o() || X.current !== m))
2515
- return;
2516
- o() && b.current === n && n.readyState === WebSocket.OPEN && n.send(
2517
- JSON.stringify({
2518
- type: "offer",
2519
- ...C ? { displayStreams: !0 } : {},
2520
- sdp: _.sdp,
2521
- sessionId: he
2522
- })
2523
- ), k("Sent offer");
2524
- }
2525
- } catch (n) {
2526
- if (!o())
2527
- return;
2528
- const f = n instanceof Error ? n.message : String(n);
2529
- k("Error: " + f), et(f, s);
2530
- }
2531
- }, Zt = () => {
2532
- Le.current = !1, dr(!1), Yr(0);
2533
- }, Mn = () => {
2534
- Te.current += 1, yt.current = 0, We.current = !1, Rt(), mt(), Ze(), k("Stopped");
2535
- }, Sn = (t) => {
2536
- t.stopPropagation(), Zt();
2537
- };
2538
- le(() => {
2539
- jt() ? Qt() : It();
2540
- }, [F]), le(() => (Ft(!1), Zt(), document.hidden || br(), document.addEventListener("visibilitychange", Ir), () => {
2541
- Ar(), Mn(), document.removeEventListener("visibilitychange", Ir);
2542
- }), [e, i, c, E]);
2543
- const Kr = () => {
2544
- const t = ht();
2545
- if (!t) {
2546
- Er(null);
2547
- return;
2548
- }
2549
- const s = {
2550
- left: t.videoRect.left - t.containerRect.left + t.offsetX,
2551
- top: t.videoRect.top - t.containerRect.top + t.offsetY,
2552
- width: t.actualWidth,
2553
- height: t.actualHeight
2554
- };
2555
- Er(
2556
- (o) => o && o.left === s.left && o.top === s.top && o.width === s.width && o.height === s.height ? o : s
2557
- );
2558
- };
2559
- le(() => {
2560
- const t = $.current, s = Pe.current, o = Ce.current;
2561
- if (!t) return;
2562
- const n = () => {
2563
- if (!bt || !s) {
2564
- fr({}), Kr();
2565
- return;
2566
- }
2567
- const p = s.clientWidth, g = s.clientHeight;
2568
- if (p === 0 || g === 0) return;
2569
- const C = t.videoWidth > t.videoHeight;
2570
- Zr(C), tn(
2571
- Ee === "android" && Ko(t.videoWidth, t.videoHeight)
2572
- );
2573
- const m = C ? Je.videoPosition.landscape : Je.videoPosition.portrait;
2574
- let I = {};
2575
- m.heightMultiplier ? (I.height = `${g * m.heightMultiplier}px`, I.width = "auto") : m.widthMultiplier && (I.width = `${p * m.widthMultiplier}px`, I.height = "auto"), I.borderRadius = `${C ? g * Je.videoBorderRadiusMultiplier : p * Je.videoBorderRadiusMultiplier}px`, fr(I), Kr();
2576
- }, f = new ResizeObserver(() => {
2577
- n();
2578
- });
2579
- s && f.observe(s), f.observe(t), o && f.observe(o), s && s.addEventListener("load", n), t.addEventListener("loadedmetadata", n), t.addEventListener("resize", n);
2580
- const d = () => ne.current?.bumpActivity();
2581
- return t.addEventListener("resize", d), n(), () => {
2582
- f.disconnect(), t.removeEventListener("loadedmetadata", n), t.removeEventListener("resize", n), t.removeEventListener("resize", d), s && s.removeEventListener("load", n);
2583
- };
2584
- }, [Je, bt]), le(() => {
2585
- const t = ne.current;
2586
- dt ? t?.start() : (t?.stop(), mr(null), ut(null), Tt(null), gr(null), Xe(null), wt.current = null, de.current !== void 0 && (window.cancelAnimationFrame(de.current), de.current = void 0), W("onAxSnapshotChange", Gt.current, null));
2587
- }, [dt]), le(() => () => {
2588
- de.current !== void 0 && (window.cancelAnimationFrame(de.current), de.current = void 0);
2589
- }, []), le(() => {
2590
- if (!dt) return;
2591
- const t = (s) => {
2592
- s.key === "Escape" && (Vt || qt) && (Tt(null), ut(null), Xe(null), W("onInspectSelectionChange", Ve.current, null));
2593
- };
2594
- return window.addEventListener("keydown", t), () => window.removeEventListener("keydown", t);
2595
- }, [dt, Vt, qt]);
2596
- const Rn = () => {
2597
- $.current && $.current.focus();
2598
- };
2599
- Ln(ke, () => ({
2600
- openUrl: (t) => {
2601
- if (!b.current || b.current.readyState !== WebSocket.OPEN) {
2602
- A("WebSocket not open, cannot send open_url command via ref.");
2603
- return;
2604
- }
2605
- try {
2606
- const s = decodeURIComponent(t);
2607
- k("Opening URL"), b.current.send(
2608
- JSON.stringify({
2609
- type: "openUrl",
2610
- url: s,
2611
- sessionId: he
2612
- })
2613
- );
2614
- } catch (s) {
2615
- A("Error decoding or sending URL via ref:", { error: s, url: t }), b.current.send(
2616
- JSON.stringify({
2617
- type: "openUrl",
2618
- url: t,
2619
- sessionId: he
2620
- })
2621
- );
2622
- }
2623
- ne.current?.bumpActivity();
2624
- },
2625
- sendKeyEvent: (t) => {
2626
- if (!L.current || L.current.readyState !== "open") {
2627
- A("Data channel not ready for imperative key command:", L.current?.readyState);
2628
- return;
2629
- }
2630
- const s = $r[t.code];
2631
- if (!s) {
2632
- A(`Unknown event.code for imperative command: ${t.code}`);
2633
- return;
2634
- }
2635
- let o = a.META_NONE;
2636
- t.shiftKey && (o |= a.META_SHIFT_ON), t.altKey && (o |= a.META_ALT_ON), t.ctrlKey && (o |= a.META_CTRL_ON), t.metaKey && (o |= a.META_META_ON);
2637
- const n = t.type === "keydown" ? a.ACTION_DOWN : a.ACTION_UP;
2638
- H(
2639
- `Sending Imperative Key Command: code=${t.code}, keycode=${s}, action=${n}, meta=${o}`
2640
- );
2641
- const f = Et(
2642
- n,
2643
- s,
2644
- 0,
2645
- // repeat count, typically 0 for single presses
2646
- o
2647
- );
2648
- f && pe(f);
2649
- },
2650
- screenshot: (t) => new Promise((s, o) => {
2651
- if (!b.current || b.current.readyState !== WebSocket.OPEN)
2652
- return A("WebSocket not open, cannot send screenshot command."), o(new Error("WebSocket is not connected or connection is not open."));
2653
- const n = `ui-ss-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`, f = {
2654
- type: t ? "screenshotDisplay" : "screenshot",
2655
- ...t ? { display: t } : {},
2656
- id: n
2657
- };
2658
- _e.current.set(n, s), ve.current.set(n, o), H("Sending screenshot request:", f);
2659
- try {
2660
- b.current.send(JSON.stringify(f));
2661
- } catch (d) {
2662
- A("Failed to send screenshot request immediately:", d), _e.current.delete(n), ve.current.delete(n), o(d);
2663
- return;
2664
- }
2665
- setTimeout(() => {
2666
- _e.current.has(n) && (A(`Screenshot request timed out for id ${n}`), ve.current.get(n)?.(new Error("Screenshot request timed out")), _e.current.delete(n), ve.current.delete(n));
2667
- }, 3e4);
2668
- }),
2669
- terminateApp: (t) => new Promise((s, o) => {
2670
- if (!b.current || b.current.readyState !== WebSocket.OPEN)
2671
- return A("WebSocket not open, cannot send terminateApp command."), o(new Error("WebSocket is not connected or connection is not open."));
2672
- const n = `ui-term-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`, f = {
2673
- type: "terminateApp",
2674
- id: n,
2675
- bundleId: t
2676
- };
2677
- Ae.current.set(n, s), Me.current.set(n, o), H("Sending terminateApp request:", f);
2678
- try {
2679
- b.current.send(JSON.stringify(f));
2680
- } catch (d) {
2681
- A("Failed to send terminateApp request immediately:", d), Ae.current.delete(n), Me.current.delete(n), o(d);
2682
- return;
2683
- }
2684
- ne.current?.bumpActivity(), setTimeout(() => {
2685
- Ae.current.has(n) && (A(`terminateApp request timed out for id ${n}`), Me.current.get(n)?.(new Error("terminateApp request timed out")), Ae.current.delete(n), Me.current.delete(n));
2686
- }, 3e4);
2687
- }),
2688
- reconnect: () => Zt(),
2689
- refreshAxTree: async () => {
2690
- const t = ne.current;
2691
- if (!t)
2692
- throw new Error("Inspect mode is not active");
2693
- return t.refresh();
2694
- },
2695
- getAxSnapshot: () => qe.current,
2696
- setInspectHighlight: (t) => {
2697
- ut(t?.id ?? null);
2698
- },
2699
- setInspectSelection: (t) => {
2700
- Tt(t?.id ?? null), Xe(t ? wt.current : null);
2701
- const s = qe.current;
2702
- t && s ? W("onInspectSelectionChange", Ve.current, { element: t, snapshot: s }) : W("onInspectSelectionChange", Ve.current, null);
2703
- },
2704
- getAxStatus: () => ne.current?.getStatus() ?? "idle"
2705
- }));
2706
- const Nn = nn && Re !== null;
2707
- return /* @__PURE__ */ V(
2708
- "div",
2709
- {
2710
- ref: Ce,
2711
- className: Ke("rc-container", r),
2712
- style: { touchAction: "none" },
2713
- onMouseDown: De,
2714
- onMouseMove: De,
2715
- onMouseUp: De,
2716
- onMouseLeave: De,
2717
- onTouchStart: De,
2718
- onTouchMove: De,
2719
- onTouchEnd: De,
2720
- onTouchCancel: De,
2721
- children: [
2722
- Nn && Re && /* @__PURE__ */ V(nr, { children: [
2723
- /* @__PURE__ */ v(
2724
- "div",
2725
- {
2726
- className: "rc-touch-indicator",
2727
- style: {
2728
- left: `${Re.containerX}px`,
2729
- top: `${Re.containerY}px`
2730
- }
2731
- }
2732
- ),
2733
- /* @__PURE__ */ v(
2734
- "div",
2735
- {
2736
- className: "rc-touch-indicator",
2737
- style: {
2738
- left: `${Re.mirrorContainerX}px`,
2739
- top: `${Re.mirrorContainerY}px`
2740
- }
2741
- }
2742
- )
2743
- ] }),
2744
- bt && /* @__PURE__ */ v(
2745
- "img",
2746
- {
2747
- ref: Pe,
2748
- src: _r,
2749
- alt: "",
2750
- className: Ee === "ios" ? Ke("rc-phone-frame", "rc-phone-frame-ios") : "rc-phone-frame",
2751
- draggable: !1
2752
- }
2753
- ),
2754
- /* @__PURE__ */ v(
2755
- "video",
2756
- {
2757
- ref: $,
2758
- className: Ke(
2759
- "rc-video",
2760
- !bt && "rc-video-frameless",
2761
- !zr && "rc-video-loading"
2762
- ),
2763
- style: {
2764
- ...rn,
2765
- ...se ? { opacity: 0, width: 1, height: 1, pointerEvents: "none" } : {},
2766
- ...ft ? {
2767
- backgroundImage: `url("${ft}")`,
2768
- backgroundRepeat: "no-repeat",
2769
- backgroundPosition: "center",
2770
- backgroundSize: Je.loadingLogoSize
2771
- } : {}
2772
- },
2773
- autoPlay: !0,
2774
- playsInline: !0,
2775
- muted: !0,
2776
- tabIndex: se ? -1 : 0,
2777
- onKeyDown: St,
2778
- onKeyUp: St,
2779
- onClick: Rn,
2780
- onLoadedData: yn,
2781
- onFocus: () => {
2782
- $.current && ($.current.style.outline = "none");
2783
- },
2784
- onBlur: () => {
2785
- $.current && ($.current.style.outline = "none");
2786
- }
2787
- }
2788
- ),
2789
- se && /* @__PURE__ */ v(
2790
- "video",
2791
- {
2792
- ref: tt,
2793
- autoPlay: !0,
2794
- playsInline: !0,
2795
- muted: !0,
2796
- style: { position: "absolute", width: 1, height: 1, opacity: 0, pointerEvents: "none" }
2797
- }
2798
- ),
2799
- se && !Lt && /* @__PURE__ */ v(Pr, { logo: ft, showFrame: u }),
2800
- se && Lt && /* @__PURE__ */ v(xn, { fallback: /* @__PURE__ */ v(Pr, { logo: ft, showFrame: u }), children: /* @__PURE__ */ v(
2801
- Mo,
2802
- {
2803
- loadingLogo: ft,
2804
- showFrame: u,
2805
- modelUrl: y,
2806
- outer: $.current,
2807
- inner: tt.current,
2808
- state: Lt,
2809
- setAngle: (t) => xt("setHingeAngle", { angleDegrees: t }),
2810
- setOrientation: (t) => xt("setDuoOrientation", { orientation: t }),
2811
- button: (t, s) => xt("performActions", {
2812
- actions: [{ type: s ? "buttonDown" : "buttonUp", button: t }]
2813
- }),
2814
- touch: (t, s, o, n) => {
2815
- const f = L.current;
2816
- f?.readyState === "open" && f.send($n(t, s, o, n));
2817
- },
2818
- onKeyDown: St,
2819
- onKeyUp: St
2820
- }
2821
- ) }),
2822
- se && ar && /* @__PURE__ */ v("div", { role: "alert", className: "rc-duo-error", children: ar }),
2823
- !se && dt && /* @__PURE__ */ v(
2824
- Ao,
2825
- {
2826
- snapshot: pr,
2827
- geometry: sn,
2828
- highlightedId: qt,
2829
- selectedId: Vt,
2830
- mode: un,
2831
- cursorPosition: cn,
2832
- frozenCursorPosition: an,
2833
- onSelectChange: (t, s) => {
2834
- Tt(t?.id ?? null), t && s ? Xe(s) : t || Xe(null);
2835
- const o = qe.current;
2836
- t && o ? W("onInspectSelectionChange", Ve.current, {
2837
- element: t,
2838
- snapshot: o
2839
- }) : W("onInspectSelectionChange", Ve.current, null);
2840
- },
2841
- onTapElement: (t, s) => {
2842
- if (s) {
2843
- Tr(s.x, s.y);
2844
- return;
2845
- }
2846
- const o = qe.current;
2847
- o && dn(t, o);
2848
- }
2849
- }
2850
- ),
2851
- Qr ? /* @__PURE__ */ V("div", { className: "rc-terminated", role: "status", children: [
2852
- /* @__PURE__ */ v("div", { className: "rc-terminated-title", children: "Instance terminated" }),
2853
- /* @__PURE__ */ v("div", { className: "rc-terminated-message", children: "This instance no longer exists and can't be reconnected." })
2854
- ] }) : jr && /* @__PURE__ */ v("button", { type: "button", className: "rc-retry-button", onClick: Sn, children: "Retry" })
2855
- ]
2856
- }
2857
- );
2858
- }
2859
- ), Uo = (r) => typeof r.message == "string" ? r.message : typeof r.error == "string" ? r.error : null, Lo = (r) => typeof r.dataUri == "string" ? { dataUri: r.dataUri } : typeof r.base64 == "string" ? r.base64.startsWith("data:") ? { dataUri: r.base64 } : { dataUri: `data:${r.base64.startsWith("/9j/") ? "image/jpeg" : "image/png"};base64,${r.base64}` } : null;
2860
- export {
2861
- tr as A,
2862
- Wn as D,
2863
- Bo as H,
2864
- Jo as R,
2865
- oo as a,
2866
- io as b,
2867
- Gr as c,
2868
- Br as d,
2869
- qr as e,
2870
- no as f,
2871
- Zn as g,
2872
- Xn as h,
2873
- Vo as i,
2874
- qn as j,
2875
- qo as k,
2876
- Go as l,
2877
- Ho as m,
2878
- ro as n,
2879
- kr as o,
2880
- Bn as p,
2881
- Xo as q,
2882
- $o as r
2883
- };