@virtualdisplay.io/client 4.0.0-alpha.2 → 4.0.0-alpha.20

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,798 +1,3374 @@
1
- //#region src/client/error.ts
2
- var e = {
3
- NO_MAPPING: "NO_MAPPING",
4
- ATTRIBUTE_NOT_FOUND: "ATTRIBUTE_NOT_FOUND",
5
- VALUE_NOT_FOUND: "VALUE_NOT_FOUND",
6
- PARENT_NOT_FOUND: "PARENT_NOT_FOUND",
7
- INVALID_PARAMETER: "INVALID_PARAMETER",
8
- SNAPSHOT_FAILED: "SNAPSHOT_FAILED"
9
- }, t = class t extends Error {
10
- code;
11
- constructor(e, n) {
12
- super(e), this.name = "VirtualdisplayError", this.code = n, Error.captureStackTrace !== void 0 && Error.captureStackTrace(this, t);
13
- }
14
- static noMapping() {
15
- return new t("No attributes available. Waiting for server metadata.", e.NO_MAPPING);
16
- }
17
- static attributeNotFound(n) {
18
- return new t(`Attribute "${n}" not found in mapping`, e.ATTRIBUTE_NOT_FOUND);
19
- }
20
- static valueNotFound(n, r) {
21
- return new t(`Value "${r}" not found for attribute "${n}"`, e.VALUE_NOT_FOUND);
22
- }
23
- static parentNotFound(n) {
24
- return new t(`Parent element not found: ${n}`, e.PARENT_NOT_FOUND);
25
- }
26
- static invalidParameter(n) {
27
- return new t(n, e.INVALID_PARAMETER);
28
- }
29
- static snapshotFailed(n, r) {
30
- return new t(`Snapshot failed for "${n}": ${r}`, e.SNAPSHOT_FAILED);
31
- }
32
- }, n = class {
33
- defaultServer = "https://server.virtualdisplay.io";
34
- options;
35
- constructor(e) {
36
- this.options = e;
37
- }
38
- create() {
39
- let e = this.createIframe();
40
- return this.attachToParent(e), e;
41
- }
42
- createIframe() {
43
- let e = document.createElement("iframe");
44
- return e.src = this.buildUrl(), Object.assign(e.style, {
45
- width: "100%",
46
- height: "100%",
47
- border: "none"
48
- }), e.setAttribute("allow", "xr-spatial-tracking; fullscreen"), e;
49
- }
50
- attachToParent(e) {
51
- this.getParentElement().appendChild(e);
52
- }
53
- buildUrl() {
54
- let e = this.getServerUrl(), t = new URL(e);
55
- return t.searchParams.set("license", this.options.license), t.searchParams.set("model", this.options.model), this.options.debug === !0 && t.searchParams.set("debug", "true"), this.options.language !== void 0 && t.searchParams.set("language", this.options.language), t.toString();
56
- }
57
- getServerUrl() {
58
- return this.defaultServer;
59
- }
60
- getParentElement() {
61
- if (typeof this.options.parent != "string") return this.options.parent;
62
- let e = document.querySelector(this.options.parent);
63
- if (e === null) throw t.parentNotFound(this.options.parent);
64
- return e;
65
- }
1
+ const c = {
2
+ HANDSHAKE: "handshake",
3
+ SESSION: "session",
4
+ MUTATION: "mutation",
5
+ STATE: "state",
6
+ LOADING_INDICATOR: "loading_indicator",
7
+ CAMERA: "camera",
8
+ SNAPSHOT: "snapshot",
9
+ MAPPING: "mapping",
10
+ AR_ACTIVATE: "ar_activate",
11
+ FULLSCREEN: "fullscreen",
12
+ CONFIG: "config",
13
+ ANNOTATION_TOGGLE: "annotation_toggle",
14
+ FOCUS: "focus",
15
+ PRICING: "pricing"
16
+ }, Y = {
17
+ FOCUS: "focus",
18
+ UNFOCUS: "unfocus"
19
+ }, kt = {
20
+ FOCUSED: "focused"
21
+ }, St = {
22
+ /** Behaves exactly like an unpriced combination: no price, no button. */
23
+ HIDDEN: "hidden"
24
+ }, Et = new Set(Object.values(c));
25
+ function At(n) {
26
+ if (typeof n != "object" || n === null)
27
+ return !1;
28
+ const t = n;
29
+ return typeof t.target == "string" ? !1 : typeof t.type == "string" && Et.has(t.type);
30
+ }
31
+ function xt(n) {
32
+ const t = k(n);
33
+ return t !== null && t.type === c.HANDSHAKE;
34
+ }
35
+ function Tt(n) {
36
+ const t = k(n);
37
+ return t !== null && t.type === c.SESSION && typeof t.sessionId == "string";
38
+ }
39
+ function Rt(n) {
40
+ const t = k(n);
41
+ return t !== null && t.type === c.MUTATION && Array.isArray(t.results);
42
+ }
43
+ function It(n) {
44
+ const t = k(n);
45
+ return t !== null && t.type === c.SNAPSHOT && ("data" in t || "error" in t);
46
+ }
47
+ function Ot(n) {
48
+ const t = k(n);
49
+ return t !== null && t.type === c.CAMERA && Array.isArray(t.transforms);
50
+ }
51
+ function Nt(n) {
52
+ const t = k(n);
53
+ return t !== null && t.type === c.MAPPING && Array.isArray(t.attributes);
54
+ }
55
+ function Lt(n) {
56
+ const t = k(n);
57
+ return t !== null && t.type === c.LOADING_INDICATOR && typeof t.progress == "number";
58
+ }
59
+ function Mt(n) {
60
+ const t = k(n);
61
+ return t !== null && t.type === c.CONFIG && typeof t.viewerSettings == "object";
62
+ }
63
+ function zt(n) {
64
+ const t = k(n);
65
+ return t !== null && t.type === c.FOCUS && typeof t.state == "string";
66
+ }
67
+ function Ft(n) {
68
+ const t = k(n);
69
+ return t !== null && t.type === c.PRICING && typeof t.pricing == "object" && t.pricing !== null;
70
+ }
71
+ function k(n) {
72
+ return typeof n != "object" || n === null ? null : n;
73
+ }
74
+ class X {
75
+ constructor(t) {
76
+ this.processor = t;
77
+ }
78
+ processor;
79
+ pending = [];
80
+ isReady = !1;
81
+ /**
82
+ * Add a message — processed immediately if ready, queued otherwise
83
+ */
84
+ enqueue(t) {
85
+ if (this.isReady) {
86
+ this.processor(t);
87
+ return;
88
+ }
89
+ this.pending.push(t);
90
+ }
91
+ /**
92
+ * Mark as ready and flush all pending messages
93
+ */
94
+ markReady() {
95
+ if (this.isReady || (this.isReady = !0, this.pending.length === 0))
96
+ return;
97
+ const t = [...this.pending];
98
+ this.pending.length = 0;
99
+ for (const e of t)
100
+ this.processor(e);
101
+ }
102
+ get ready() {
103
+ return this.isReady;
104
+ }
105
+ get pendingCount() {
106
+ return this.pending.length;
107
+ }
108
+ /**
109
+ * Check if a message of a specific type is pending
110
+ */
111
+ hasPending(t) {
112
+ return this.pending.some((e) => e.type === t);
113
+ }
114
+ /**
115
+ * Clear all pending messages
116
+ */
117
+ clear() {
118
+ this.pending.length = 0;
119
+ }
120
+ }
121
+ class Pt {
122
+ constructor(t, e) {
123
+ this.getTarget = t, this.sourceId = `vd-${Math.random().toString(36).slice(2, 8)}`, this.targetOrigin = e?.targetOrigin ?? "*", this.isValid = e?.isValid ?? At, this.publisher = new X((i) => this.post(i)), this.consumer = new X((i) => this.routeToHandler(i)), this.shouldBuffer = e?.shouldBuffer ?? null, e?.bufferIncoming !== !0 && this.consumer.markReady();
124
+ }
125
+ getTarget;
126
+ handlers = /* @__PURE__ */ new Map();
127
+ publisher;
128
+ consumer;
129
+ shouldBuffer;
130
+ listener = null;
131
+ sourceId;
132
+ targetOrigin;
133
+ isValid;
134
+ /**
135
+ * Register a handler for a specific message type
136
+ */
137
+ on(t, e) {
138
+ this.handlers.set(t, e);
139
+ }
140
+ /**
141
+ * Remove a handler for a specific message type
142
+ */
143
+ off(t) {
144
+ this.handlers.delete(t);
145
+ }
146
+ /**
147
+ * Update the target origin for outgoing postMessage calls.
148
+ * Use when the target origin is discovered at runtime (e.g. from the first incoming message).
149
+ */
150
+ setTargetOrigin(t) {
151
+ this.targetOrigin = t;
152
+ }
153
+ /**
154
+ * Send a message to the target window
155
+ * Queued until markReady() is called
156
+ */
157
+ send(t) {
158
+ this.publisher.enqueue(t);
159
+ }
160
+ /**
161
+ * Enable sending and flush queued outgoing messages
162
+ */
163
+ markReady() {
164
+ this.publisher.markReady();
165
+ }
166
+ /**
167
+ * Enable processing of buffered incoming messages
168
+ * Only relevant when constructed with bufferIncoming: true
169
+ */
170
+ markConsumerReady() {
171
+ this.consumer.markReady();
172
+ }
173
+ /**
174
+ * Check if an incoming message of a specific type is pending in the consumer buffer
175
+ */
176
+ consumerHasPending(t) {
177
+ return this.consumer.hasPending(t);
178
+ }
179
+ /**
180
+ * Start listening for incoming messages
181
+ */
182
+ start() {
183
+ this.listener === null && (this.listener = (t) => {
184
+ const { data: e } = t;
185
+ if (!this.isValid(e) || e._source === this.sourceId)
186
+ return;
187
+ const i = this.getTarget();
188
+ if (i !== null && t.source !== null && t.source !== i)
189
+ return;
190
+ const o = e;
191
+ if (this.shouldBuffer !== null && !this.shouldBuffer(o)) {
192
+ this.routeToHandler(o);
193
+ return;
194
+ }
195
+ this.consumer.enqueue(o);
196
+ }, window.addEventListener("message", this.listener));
197
+ }
198
+ /**
199
+ * Stop listening and clean up all state
200
+ */
201
+ destroy() {
202
+ this.listener !== null && (window.removeEventListener("message", this.listener), this.listener = null), this.publisher.clear(), this.consumer.clear(), this.handlers.clear();
203
+ }
204
+ /**
205
+ * Whether the messenger is ready to send
206
+ */
207
+ get ready() {
208
+ return this.publisher.ready;
209
+ }
210
+ /**
211
+ * Number of messages waiting in the outgoing queue
212
+ */
213
+ get pendingCount() {
214
+ return this.publisher.pendingCount;
215
+ }
216
+ post(t) {
217
+ const e = this.getTarget();
218
+ e !== null && e.postMessage({ ...t, _source: this.sourceId }, this.targetOrigin);
219
+ }
220
+ routeToHandler(t) {
221
+ const e = this.handlers.get(t.type);
222
+ if (e === void 0)
223
+ return;
224
+ const i = e(t);
225
+ i instanceof Promise && i.catch((o) => {
226
+ const s = o instanceof Error ? o.message : String(o);
227
+ console.error(`Virtualdisplay: error handling ${t.type}: ${s}`);
228
+ });
229
+ }
230
+ }
231
+ class g {
232
+ element;
233
+ constructor({ variant: t = "default", size: e = "default", label: i, icon: o, onClick: s, disabled: r = !1 } = {}) {
234
+ this.element = document.createElement("button"), this.element.className = `ui-btn ui-btn--${t} ui-btn--size-${e}`, i !== void 0 && (this.element.setAttribute("aria-label", i), this.element.title = i), o !== void 0 ? this.element.appendChild(o) : i !== void 0 && (this.element.textContent = i), s && this.element.addEventListener("click", s), this.element.disabled = r;
235
+ }
236
+ setIcon(t) {
237
+ const e = this.element.querySelector("svg");
238
+ e !== null ? e.replaceWith(t) : this.element.appendChild(t);
239
+ }
240
+ }
241
+ const $t = {
242
+ xmlns: "http://www.w3.org/2000/svg",
243
+ width: 24,
244
+ height: 24,
245
+ viewBox: "0 0 24 24",
246
+ fill: "none",
247
+ stroke: "currentColor",
248
+ "stroke-width": 2,
249
+ "stroke-linecap": "round",
250
+ "stroke-linejoin": "round"
251
+ };
252
+ const lt = ([n, t, e]) => {
253
+ const i = document.createElementNS("http://www.w3.org/2000/svg", n);
254
+ return Object.keys(t).forEach((o) => {
255
+ i.setAttribute(o, String(t[o]));
256
+ }), e?.length && e.forEach((o) => {
257
+ const s = lt(o);
258
+ i.appendChild(s);
259
+ }), i;
260
+ }, ct = (n, t = {}) => {
261
+ const i = {
262
+ ...$t,
263
+ ...t
264
+ };
265
+ return lt(["svg", i, n]);
266
+ };
267
+ const Dt = [
268
+ [
269
+ "path",
270
+ {
271
+ d: "M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"
272
+ }
273
+ ],
274
+ ["path", { d: "m3.3 7 8.7 5 8.7-5" }],
275
+ ["path", { d: "M12 22V12" }]
276
+ ];
277
+ const Bt = [
278
+ [
279
+ "path",
280
+ {
281
+ d: "M13.997 4a2 2 0 0 1 1.76 1.05l.486.9A2 2 0 0 0 18.003 7H20a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h1.997a2 2 0 0 0 1.759-1.048l.489-.904A2 2 0 0 1 10.004 4z"
282
+ }
283
+ ],
284
+ ["circle", { cx: "12", cy: "13", r: "3" }]
285
+ ];
286
+ const ut = [["path", { d: "m6 9 6 6 6-6" }]];
287
+ const Ut = [["path", { d: "m15 18-6-6 6-6" }]];
288
+ const Vt = [["path", { d: "m9 18 6-6-6-6" }]];
289
+ const jt = [["path", { d: "m18 15-6-6-6 6" }]];
290
+ const Ht = [
291
+ ["path", { d: "M15 3h6v6" }],
292
+ ["path", { d: "m21 3-7 7" }],
293
+ ["path", { d: "m3 21 7-7" }],
294
+ ["path", { d: "M9 21H3v-6" }]
295
+ ];
296
+ const Gt = [
297
+ ["path", { d: "m14 10 7-7" }],
298
+ ["path", { d: "M20 10h-6V4" }],
299
+ ["path", { d: "m3 21 7-7" }],
300
+ ["path", { d: "M4 14h6v6" }]
301
+ ];
302
+ const qt = [
303
+ ["path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }],
304
+ ["path", { d: "M3 3v5h5" }]
305
+ ];
306
+ const Zt = [
307
+ ["path", { d: "M10 5H3" }],
308
+ ["path", { d: "M12 19H3" }],
309
+ ["path", { d: "M14 3v4" }],
310
+ ["path", { d: "M16 17v4" }],
311
+ ["path", { d: "M21 12h-9" }],
312
+ ["path", { d: "M21 19h-5" }],
313
+ ["path", { d: "M21 5h-7" }],
314
+ ["path", { d: "M8 10v4" }],
315
+ ["path", { d: "M8 12H3" }]
316
+ ];
317
+ const Wt = [
318
+ ["path", { d: "M18 6 6 18" }],
319
+ ["path", { d: "m6 6 12 12" }]
320
+ ];
321
+ const Yt = [
322
+ ["circle", { cx: "11", cy: "11", r: "8" }],
323
+ ["line", { x1: "21", x2: "16.65", y1: "21", y2: "16.65" }],
324
+ ["line", { x1: "11", x2: "11", y1: "8", y2: "14" }],
325
+ ["line", { x1: "8", x2: "14", y1: "11", y2: "11" }]
326
+ ];
327
+ const Xt = [
328
+ ["circle", { cx: "11", cy: "11", r: "8" }],
329
+ ["line", { x1: "21", x2: "16.65", y1: "21", y2: "16.65" }],
330
+ ["line", { x1: "8", x2: "14", y1: "11", y2: "11" }]
331
+ ], m = {
332
+ semantic: {
333
+ // eslint-disable-next-line vd-custom/enforce-error-codes -- This is a hex color, not an error code
334
+ error: "#dc2626"
335
+ },
336
+ neutral: {
337
+ 500: "#737373",
338
+ 600: "#525252",
339
+ 900: "#171717"
340
+ },
341
+ white: "#ffffff",
342
+ black: "#000000"
343
+ }, a = {
344
+ 0: "0",
345
+ 0.5: "0.125rem",
346
+ // 2px
347
+ 1: "0.25rem",
348
+ // 4px
349
+ 1.5: "0.375rem",
350
+ // 6px
351
+ 2: "0.5rem",
352
+ // 10px
353
+ 3: "0.75rem",
354
+ // 14px
355
+ 4: "1rem",
356
+ // 16px
357
+ 5: "1.25rem",
358
+ // 20px
359
+ 6: "1.5rem",
360
+ // 28px
361
+ 8: "2rem",
362
+ // 32px
363
+ 9: "2.25rem",
364
+ // 80px
365
+ 24: "6rem"
366
+ // 96px
367
+ };
368
+ class Kt {
369
+ element;
370
+ constructor() {
371
+ this.element = document.createElement("div"), Object.assign(this.element.style, {
372
+ background: m.white,
373
+ borderRadius: a[3],
374
+ padding: a[6],
375
+ boxShadow: `0 ${a[2]} ${a[8]} oklch(0% 0 0 / 20%)`,
376
+ maxWidth: "20rem",
377
+ width: "100%"
378
+ });
379
+ }
380
+ }
381
+ class Qt {
382
+ constructor(t = {}) {
383
+ this.options = t, this.card = new Kt(), this.backdrop = this.createBackdrop(), this.backdrop.appendChild(this.card.element);
384
+ }
385
+ options;
386
+ card;
387
+ backdrop;
388
+ keyHandler = null;
389
+ open() {
390
+ document.body.appendChild(this.backdrop), this.keyHandler = (t) => {
391
+ t.key === "Escape" && this.close();
392
+ }, document.addEventListener("keydown", this.keyHandler);
393
+ }
394
+ close() {
395
+ this.backdrop.remove(), this.keyHandler !== null && (document.removeEventListener("keydown", this.keyHandler), this.keyHandler = null), this.options.onClose?.();
396
+ }
397
+ createBackdrop() {
398
+ const t = document.createElement("div");
399
+ return Object.assign(t.style, {
400
+ position: "fixed",
401
+ inset: a[0],
402
+ background: "oklch(0% 0 0 / 50%)",
403
+ zIndex: "9999",
404
+ display: "flex",
405
+ alignItems: "center",
406
+ justifyContent: "center"
407
+ }), t.addEventListener("click", (e) => {
408
+ e.target === t && this.close();
409
+ }), t;
410
+ }
411
+ }
412
+ class Jt {
413
+ element;
414
+ selectCallback = null;
415
+ constructor(t, e, i) {
416
+ this.element = document.createElement("div"), this.element.className = "ui-toggle-group";
417
+ for (let o = 0; o < t.length; o++) {
418
+ const s = t[o], r = document.createElement("button");
419
+ r.className = "ui-toggle-group-item", r.dataset.value = s, r.textContent = i?.[o] ?? s, r.dataset.state = s === e ? "on" : "off", r.setAttribute("aria-pressed", s === e ? "true" : "false"), r.addEventListener("click", () => {
420
+ this.selectCallback?.(s);
421
+ }), this.element.appendChild(r);
422
+ }
423
+ }
424
+ setSelected(t) {
425
+ for (const e of this.element.querySelectorAll(".ui-toggle-group-item")) {
426
+ const i = e.dataset.value === t;
427
+ e.dataset.state = i ? "on" : "off", e.setAttribute("aria-pressed", i ? "true" : "false");
428
+ }
429
+ }
430
+ onSelect(t) {
431
+ this.selectCallback = t;
432
+ }
433
+ }
434
+ class te {
435
+ element;
436
+ select;
437
+ constructor(t, e, i, o, s) {
438
+ this.select = document.createElement("select"), this.select.className = "ui-native-select", this.select.dataset.name = t, this.select.setAttribute("aria-label", i);
439
+ const r = document.createElement("option");
440
+ r.value = "", r.disabled = !0, r.textContent = i, this.select.appendChild(r);
441
+ let l = !1;
442
+ for (let u = 0; u < e.length; u++) {
443
+ const p = e[u], v = document.createElement("option");
444
+ v.value = p, v.textContent = s?.[u] ?? p, p === o && (v.selected = !0, l = !0), this.select.appendChild(v);
445
+ }
446
+ l || (r.selected = !0);
447
+ const d = ct(ut, { width: 16, height: 16, "stroke-width": 2 });
448
+ d.classList.add("ui-native-select-icon"), this.element = document.createElement("div"), this.element.className = "ui-native-select-wrap", this.element.appendChild(this.select), this.element.appendChild(d);
449
+ }
450
+ setSelected(t) {
451
+ this.select.value = t;
452
+ }
453
+ onSelect(t) {
454
+ this.select.addEventListener("change", () => {
455
+ t(this.select.value);
456
+ });
457
+ }
458
+ }
459
+ const ee = {}, ne = "en", dt = (
460
+ /** @type {const} */
461
+ ["en", "nl", "de"]
462
+ ), Z = [
463
+ "baseLocale"
464
+ ], K = [];
465
+ let Q, J;
466
+ function ie(n) {
467
+ if (K.length === 0)
468
+ return;
469
+ const t = typeof n == "string" ? n : n.href;
470
+ if (Q === t)
471
+ return J;
472
+ const e = new URL(t, "http://dummy.com");
473
+ let i;
474
+ for (const o of K)
475
+ if (new ee(o.match, e.href).exec(e.href)) {
476
+ i = o;
477
+ break;
478
+ }
479
+ return Q = t, J = i, i;
480
+ }
481
+ function ht(n) {
482
+ const t = ie(n);
483
+ return t && t.exclude !== !0 && Array.isArray(t.strategy) ? t.strategy : Z;
484
+ }
485
+ const q = typeof window > "u";
486
+ globalThis.__paraglide = /** @type {any} */
487
+ globalThis.__paraglide ?? {};
488
+ globalThis.__paraglide.ssr = /** @type {any} */
489
+ globalThis.__paraglide.ssr ?? {};
490
+ let tt = !1, h = () => {
491
+ let n = Z;
492
+ !q && typeof window < "u" && window.location?.href && (n = ht(window.location.href));
493
+ const t = oe(n);
494
+ if (t)
495
+ return tt || (tt = !0, mt(t, { reload: !1 })), t;
496
+ throw new Error("No locale found. Read the docs https://paraglidejs.com/errors#no-locale-found");
497
+ };
498
+ function oe(n, t) {
499
+ let e;
500
+ for (const i of n) {
501
+ if (i === "baseLocale")
502
+ e = ne;
503
+ else if (ft(i) && N.has(i)) {
504
+ const s = N.get(i);
505
+ if (s) {
506
+ const r = s.getLocale();
507
+ if (r instanceof Promise)
508
+ continue;
509
+ if (r !== void 0)
510
+ return re(r);
511
+ }
512
+ }
513
+ const o = pt(e);
514
+ if (o)
515
+ return o;
516
+ }
517
+ }
518
+ const se = (n) => {
519
+ window.location.reload();
66
520
  };
67
- //#endregion
68
- //#region ../logger/src/format.ts
69
- function r(e) {
70
- let t = new Date(e.timestamp).toLocaleTimeString("en-GB", { hour12: !1 }), n = e.level.toUpperCase().padEnd(5), r = e.trace_id?.slice(0, 8) ?? "--------", i = e.msg, a = [
71
- "timestamp",
72
- "level",
73
- "msg",
74
- "service",
75
- "trace_id",
76
- "span_id"
77
- ], o = Object.entries(e).filter(([e]) => !a.includes(e)).map(([e, t]) => `${e}=${JSON.stringify(t)}`).join(" ");
78
- return `${t} ${n} [${r}] ${i}${o ? " " + o : ""}`;
79
- }
80
- function i(e) {
81
- return JSON.stringify(e);
82
- }
83
- //#endregion
84
- //#region ../logger/src/write.ts
85
- function a(e, t) {
86
- let n = t ? r(e) : i(e);
87
- e.level === "error" ? console.error(n) : e.level === "warn" ? console.warn(n) : console.log(n);
88
- }
89
- //#endregion
90
- //#region ../utils/src/date.ts
91
- function o() {
92
- return /* @__PURE__ */ new Date();
93
- }
94
- function s(e) {
95
- return e.toISOString();
96
- }
97
- //#endregion
98
- //#region ../logger/src/logger.ts
99
- var c = class e {
100
- constructor(e) {
101
- this.config = e;
102
- }
103
- log(e, t, n = {}) {
104
- let r = this.config.traceProvider?.() ?? {};
105
- a({
106
- timestamp: s(o()),
107
- level: e,
108
- msg: t,
109
- service: this.config.service,
110
- ...r,
111
- ...n
112
- }, this.config.isDev);
113
- }
114
- debug(e, t) {
115
- this.config.isDev && this.log("debug", e, t);
116
- }
117
- info(e, t) {
118
- this.log("info", e, t);
119
- }
120
- warn(e, t) {
121
- this.log("warn", e, t);
122
- }
123
- error(e, t) {
124
- this.log("error", e, t);
125
- }
126
- with(t) {
127
- let n = new e(this.config);
128
- return n.log = ((e, n, r = {}) => {
129
- this.log(e, n, {
130
- ...t,
131
- ...r
132
- });
133
- }).bind(this), n;
134
- }
521
+ let mt = (n, t) => {
522
+ const e = {
523
+ reload: !0,
524
+ ...t
525
+ };
526
+ let i;
527
+ try {
528
+ i = h();
529
+ } catch {
530
+ }
531
+ const o = [];
532
+ let s = Z;
533
+ !q && typeof window < "u" && window.location?.href && (s = ht(window.location.href));
534
+ for (const l of s)
535
+ if (l !== "baseLocale" && ft(l) && N.has(l)) {
536
+ const d = N.get(l);
537
+ if (d) {
538
+ let u = d.setLocale(n);
539
+ u instanceof Promise && (u = u.catch((p) => {
540
+ throw new Error(`Custom strategy "${l}" setLocale failed.`, {
541
+ cause: p
542
+ });
543
+ }), o.push(u));
544
+ }
545
+ }
546
+ const r = () => {
547
+ !q && e.reload && window.location && n !== i && se();
548
+ };
549
+ if (o.length)
550
+ return Promise.all(o).then(() => {
551
+ r();
552
+ });
553
+ r();
135
554
  };
136
- function l(e, t) {
137
- return new c({
138
- service: e,
139
- isDev: t?.isDev === void 0 ? typeof process < "u" ? process.env.NODE_ENV !== "production" : !0 : t.isDev,
140
- traceProvider: t?.traceProvider
141
- });
142
- }
143
- //#endregion
144
- //#region src/utils/logger.ts
145
- function u(e) {
146
- if (e !== void 0) return typeof e == "object" && e && !Array.isArray(e) && !(e instanceof Error) ? e : e instanceof Error ? { error: e.message } : { value: e };
147
- }
148
- function d(e) {
149
- return {
150
- debug: (t, n) => e.debug(t, u(n)),
151
- info: (t, n) => e.info(t, u(n)),
152
- warn: (t, n) => e.warn(t, u(n)),
153
- error: (t, n) => e.error(t, u(n))
154
- };
155
- }
156
- var f = !1, p = d(l("client", { isDev: !1 }));
157
- function m() {
158
- f = !0, p = d(l("client", { isDev: !0 }));
159
- }
160
- function h() {
161
- return f;
162
- }
163
- //#endregion
164
- //#region src/client/ready-state-tracker.ts
165
- var g = class {
166
- ready = !1;
167
- onReady;
168
- constructor(e) {
169
- this.onReady = e;
170
- }
171
- handleMappingReceived() {
172
- this.markReady("Mapping received from server");
173
- }
174
- handleMutationResult(e) {
175
- e.isInitial && this.markReady("Initial mutations processed");
176
- }
177
- get isReady() {
178
- return this.ready;
179
- }
180
- clear() {
181
- this.ready = !1;
182
- }
183
- markReady(e) {
184
- this.ready || (this.ready = !0, p.info(`${e} - client is now ready`), this.onReady?.());
185
- }
186
- }, _ = class {
187
- isSelectedValue = !1;
188
- constructor(e, t) {
189
- this.value = e, this.attribute = t;
190
- }
191
- get isSelected() {
192
- return this.isSelectedValue;
193
- }
194
- setSelected(e) {
195
- this.isSelectedValue = e;
196
- }
197
- }, v = class {
198
- name;
199
- defaultValue;
200
- values;
201
- onSelect;
202
- onChangeCallback;
203
- constructor(e) {
204
- this.name = e.name, this.defaultValue = e.defaultValue, this.onSelect = e.onSelect, this.values = this.createValues(e.values);
205
- }
206
- select(e) {
207
- if (!this.values.has(e)) throw t.valueNotFound(this.name, e);
208
- this.onSelect(this.name, e);
209
- }
210
- getValues() {
211
- return Array.from(this.values.values());
212
- }
213
- getValue(e) {
214
- return this.values.get(e);
215
- }
216
- onChange(e) {
217
- this.onChangeCallback = e;
218
- }
219
- handleResult(e) {
220
- let t;
221
- for (let n of this.values.values()) {
222
- let r = n.value === e;
223
- n.setSelected(r), r && (t = n);
224
- }
225
- t !== void 0 && this.onChangeCallback !== void 0 && this.onChangeCallback(t);
226
- }
227
- createValues(e) {
228
- let t = /* @__PURE__ */ new Map();
229
- for (let n of e) {
230
- let e = new _(n, this.name);
231
- n === this.defaultValue && e.setSelected(!0), t.set(n, e);
232
- }
233
- return t;
234
- }
235
- }, y = class {
236
- attributes = /* @__PURE__ */ new Map();
237
- constructor(e, t, n) {
238
- for (let n of e) {
239
- let e = this.buildOptions(n, t);
240
- this.attributes.set(n.name, new v(e));
241
- }
242
- this.onMutationFailed = n;
243
- }
244
- onMutationFailed;
245
- get(e) {
246
- return this.attributes.get(e);
247
- }
248
- defaults() {
249
- let e = [];
250
- for (let t of this.attributes.values()) t.defaultValue !== void 0 && e.push({
251
- name: t.name,
252
- value: t.defaultValue
253
- });
254
- return e;
255
- }
256
- handleResults(e) {
257
- for (let t of e) {
258
- if (!t.success) {
259
- this.onMutationFailed?.(t.name, t.value);
260
- continue;
261
- }
262
- this.get(t.name)?.handleResult(t.value);
263
- }
264
- }
265
- buildOptions(e, t) {
266
- let n = {
267
- name: e.name,
268
- values: e.values,
269
- onSelect: (e, n) => {
270
- t([{
271
- name: e,
272
- value: n
273
- }], !1);
274
- }
275
- };
276
- return e.defaultValue === void 0 ? n : {
277
- ...n,
278
- defaultValue: e.defaultValue
279
- };
280
- }
281
- }, b = {
282
- READY: "ready",
283
- MUTATION: "mutation",
284
- STATE: "state",
285
- CONFIG: "config",
286
- CAMERA: "camera",
287
- SNAPSHOT: "snapshot",
288
- MAPPING: "mapping"
289
- }, x = new Set(Object.values(b));
290
- function S(e) {
291
- if (typeof e != "object" || !e) return !1;
292
- let t = e;
293
- return typeof t.target == "string" ? !1 : typeof t.type == "string" && x.has(t.type);
294
- }
295
- function C(e) {
296
- let t = O(e);
297
- return t !== null && t.type === b.READY;
298
- }
299
- function w(e) {
300
- let t = O(e);
301
- return t !== null && t.type === b.MUTATION && Array.isArray(t.results);
302
- }
303
- function T(e) {
304
- let t = O(e);
305
- return t !== null && t.type === b.SNAPSHOT && ("data" in t || "error" in t);
306
- }
307
- function E(e) {
308
- let t = O(e);
309
- return t !== null && t.type === b.CAMERA && Array.isArray(t.transforms);
310
- }
311
- function D(e) {
312
- let t = O(e);
313
- return t !== null && t.type === b.MAPPING && Array.isArray(t.attributes);
314
- }
315
- function O(e) {
316
- return typeof e != "object" || !e ? null : e;
317
- }
318
- //#endregion
319
- //#region ../messaging/src/queue.ts
320
- var k = class {
321
- pending = [];
322
- isReady = !1;
323
- constructor(e) {
324
- this.processor = e;
325
- }
326
- enqueue(e) {
327
- if (this.isReady) {
328
- this.processor(e);
329
- return;
330
- }
331
- this.pending.push(e);
332
- }
333
- markReady() {
334
- if (this.isReady || (this.isReady = !0, this.pending.length === 0)) return;
335
- let e = [...this.pending];
336
- this.pending.length = 0;
337
- for (let t of e) this.processor(t);
338
- }
339
- get ready() {
340
- return this.isReady;
341
- }
342
- get pendingCount() {
343
- return this.pending.length;
344
- }
345
- hasPending(e) {
346
- return this.pending.some((t) => t.type === e);
347
- }
348
- clear() {
349
- this.pending.length = 0;
350
- }
351
- }, A = class {
352
- handlers = /* @__PURE__ */ new Map();
353
- publisher;
354
- consumer;
355
- shouldBuffer;
356
- listener = null;
357
- sourceId;
358
- constructor(e, t) {
359
- this.getTarget = e, this.sourceId = `vd-${Math.random().toString(36).slice(2, 8)}`, this.publisher = new k((e) => this.post(e)), this.consumer = new k((e) => this.routeToHandler(e)), this.shouldBuffer = t?.shouldBuffer ?? null, t?.bufferIncoming !== !0 && this.consumer.markReady();
360
- }
361
- on(e, t) {
362
- this.handlers.set(e, t);
363
- }
364
- off(e) {
365
- this.handlers.delete(e);
366
- }
367
- send(e) {
368
- this.publisher.enqueue(e);
369
- }
370
- markReady() {
371
- this.publisher.markReady();
372
- }
373
- markConsumerReady() {
374
- this.consumer.markReady();
375
- }
376
- consumerHasPending(e) {
377
- return this.consumer.hasPending(e);
378
- }
379
- start() {
380
- this.listener === null && (this.listener = (e) => {
381
- let { data: t } = e;
382
- if (!S(t) || t._source === this.sourceId) return;
383
- let n = t;
384
- if (this.shouldBuffer !== null && !this.shouldBuffer(n)) {
385
- this.routeToHandler(n);
386
- return;
387
- }
388
- this.consumer.enqueue(n);
389
- }, window.addEventListener("message", this.listener));
390
- }
391
- destroy() {
392
- this.listener !== null && (window.removeEventListener("message", this.listener), this.listener = null), this.publisher.clear(), this.consumer.clear(), this.handlers.clear();
393
- }
394
- get ready() {
395
- return this.publisher.ready;
396
- }
397
- get pendingCount() {
398
- return this.publisher.pendingCount;
399
- }
400
- post(e) {
401
- let t = this.getTarget();
402
- t !== null && t.postMessage({
403
- ...e,
404
- _source: this.sourceId
405
- }, "*");
406
- }
407
- routeToHandler(e) {
408
- let t = this.handlers.get(e.type);
409
- if (t === void 0) return;
410
- let n = t(e);
411
- n instanceof Promise && n.catch((t) => {
412
- let n = t instanceof Error ? t.message : String(t);
413
- console.error(`Virtualdisplay: error handling ${e.type}: ${n}`);
414
- });
415
- }
555
+ function pt(n) {
556
+ if (typeof n != "string")
557
+ return;
558
+ const t = n.toLowerCase();
559
+ for (const e of dt)
560
+ if (e.toLowerCase() === t)
561
+ return e;
562
+ }
563
+ function re(n) {
564
+ const t = pt(n);
565
+ if (t)
566
+ return t;
567
+ throw new Error(`Invalid locale: ${n}. Expected one of: ${dt.join(", ")}`);
568
+ }
569
+ const N = /* @__PURE__ */ new Map();
570
+ function ft(n) {
571
+ return typeof n == "string" && /^custom-[A-Za-z0-9_-]+$/.test(n);
572
+ }
573
+ const ae = (
574
+ /** @type {(inputs: Controls_Ar_Buttonlabel1Inputs) => LocalizedString} */
575
+ () => (
576
+ /** @type {LocalizedString} */
577
+ "Activate AR"
578
+ )
579
+ ), le = (
580
+ /** @type {(inputs: Controls_Ar_Buttonlabel1Inputs) => LocalizedString} */
581
+ () => (
582
+ /** @type {LocalizedString} */
583
+ "AR activeren"
584
+ )
585
+ ), ce = (
586
+ /** @type {(inputs: Controls_Ar_Buttonlabel1Inputs) => LocalizedString} */
587
+ () => (
588
+ /** @type {LocalizedString} */
589
+ "AR aktivieren"
590
+ )
591
+ ), ue = (
592
+ /** @type {((inputs?: Controls_Ar_Buttonlabel1Inputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Controls_Ar_Buttonlabel1Inputs, { locale?: "en" | "nl" | "de" }, {}>} */
593
+ ((n = {}, t = {}) => {
594
+ const e = t.locale ?? h();
595
+ return e === "en" ? ae() : e === "nl" ? le() : ce();
596
+ })
597
+ ), de = (
598
+ /** @type {(inputs: Controls_Qr_Modaltitle1Inputs) => LocalizedString} */
599
+ () => (
600
+ /** @type {LocalizedString} */
601
+ "Scan to view in AR"
602
+ )
603
+ ), he = (
604
+ /** @type {(inputs: Controls_Qr_Modaltitle1Inputs) => LocalizedString} */
605
+ () => (
606
+ /** @type {LocalizedString} */
607
+ "Scan om in AR te bekijken"
608
+ )
609
+ ), me = (
610
+ /** @type {(inputs: Controls_Qr_Modaltitle1Inputs) => LocalizedString} */
611
+ () => (
612
+ /** @type {LocalizedString} */
613
+ "Scannen für AR-Ansicht"
614
+ )
615
+ ), pe = (
616
+ /** @type {((inputs?: Controls_Qr_Modaltitle1Inputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Controls_Qr_Modaltitle1Inputs, { locale?: "en" | "nl" | "de" }, {}>} */
617
+ ((n = {}, t = {}) => {
618
+ const e = t.locale ?? h();
619
+ return e === "en" ? de() : e === "nl" ? he() : me();
620
+ })
621
+ ), fe = (
622
+ /** @type {(inputs: Controls_Qr_Modaldescription1Inputs) => LocalizedString} */
623
+ () => (
624
+ /** @type {LocalizedString} */
625
+ "Use your smartphone camera to scan this QR code"
626
+ )
627
+ ), ge = (
628
+ /** @type {(inputs: Controls_Qr_Modaldescription1Inputs) => LocalizedString} */
629
+ () => (
630
+ /** @type {LocalizedString} */
631
+ "Gebruik de camera van je smartphone om deze QR-code te scannen"
632
+ )
633
+ ), be = (
634
+ /** @type {(inputs: Controls_Qr_Modaldescription1Inputs) => LocalizedString} */
635
+ () => (
636
+ /** @type {LocalizedString} */
637
+ "Verwende die Kamera deines Smartphones, um diesen QR-Code zu scannen"
638
+ )
639
+ ), ve = (
640
+ /** @type {((inputs?: Controls_Qr_Modaldescription1Inputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Controls_Qr_Modaldescription1Inputs, { locale?: "en" | "nl" | "de" }, {}>} */
641
+ ((n = {}, t = {}) => {
642
+ const e = t.locale ?? h();
643
+ return e === "en" ? fe() : e === "nl" ? ge() : be();
644
+ })
645
+ ), ye = (
646
+ /** @type {(inputs: Controls_Qr_Modalinstructions1Inputs) => LocalizedString} */
647
+ () => (
648
+ /** @type {LocalizedString} */
649
+ "Your phone will open the 3D model in AR mode."
650
+ )
651
+ ), _e = (
652
+ /** @type {(inputs: Controls_Qr_Modalinstructions1Inputs) => LocalizedString} */
653
+ () => (
654
+ /** @type {LocalizedString} */
655
+ "Je telefoon opent het 3D-model in AR-modus."
656
+ )
657
+ ), we = (
658
+ /** @type {(inputs: Controls_Qr_Modalinstructions1Inputs) => LocalizedString} */
659
+ () => (
660
+ /** @type {LocalizedString} */
661
+ "Dein Telefon öffnet das 3D-Modell im AR-Modus."
662
+ )
663
+ ), Ce = (
664
+ /** @type {((inputs?: Controls_Qr_Modalinstructions1Inputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Controls_Qr_Modalinstructions1Inputs, { locale?: "en" | "nl" | "de" }, {}>} */
665
+ ((n = {}, t = {}) => {
666
+ const e = t.locale ?? h();
667
+ return e === "en" ? ye() : e === "nl" ? _e() : we();
668
+ })
669
+ ), ke = (
670
+ /** @type {(inputs: Controls_Qr_Closebutton1Inputs) => LocalizedString} */
671
+ () => (
672
+ /** @type {LocalizedString} */
673
+ "Close"
674
+ )
675
+ ), Se = (
676
+ /** @type {(inputs: Controls_Qr_Closebutton1Inputs) => LocalizedString} */
677
+ () => (
678
+ /** @type {LocalizedString} */
679
+ "Sluiten"
680
+ )
681
+ ), Ee = (
682
+ /** @type {(inputs: Controls_Qr_Closebutton1Inputs) => LocalizedString} */
683
+ () => (
684
+ /** @type {LocalizedString} */
685
+ "Schließen"
686
+ )
687
+ ), Ae = (
688
+ /** @type {((inputs?: Controls_Qr_Closebutton1Inputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Controls_Qr_Closebutton1Inputs, { locale?: "en" | "nl" | "de" }, {}>} */
689
+ ((n = {}, t = {}) => {
690
+ const e = t.locale ?? h();
691
+ return e === "en" ? ke() : e === "nl" ? Se() : Ee();
692
+ })
693
+ ), xe = (
694
+ /** @type {(inputs: Controls_Fullscreen_Buttonlabel1Inputs) => LocalizedString} */
695
+ () => (
696
+ /** @type {LocalizedString} */
697
+ "Fullscreen"
698
+ )
699
+ ), Te = (
700
+ /** @type {(inputs: Controls_Fullscreen_Buttonlabel1Inputs) => LocalizedString} */
701
+ () => (
702
+ /** @type {LocalizedString} */
703
+ "Volledig scherm"
704
+ )
705
+ ), Re = (
706
+ /** @type {(inputs: Controls_Fullscreen_Buttonlabel1Inputs) => LocalizedString} */
707
+ () => (
708
+ /** @type {LocalizedString} */
709
+ "Vollbild"
710
+ )
711
+ ), Ie = (
712
+ /** @type {((inputs?: Controls_Fullscreen_Buttonlabel1Inputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Controls_Fullscreen_Buttonlabel1Inputs, { locale?: "en" | "nl" | "de" }, {}>} */
713
+ ((n = {}, t = {}) => {
714
+ const e = t.locale ?? h();
715
+ return e === "en" ? xe() : e === "nl" ? Te() : Re();
716
+ })
717
+ ), Oe = (
718
+ /** @type {(inputs: Loading_Downloadingshort1Inputs) => LocalizedString} */
719
+ () => (
720
+ /** @type {LocalizedString} */
721
+ "Downloading"
722
+ )
723
+ ), Ne = (
724
+ /** @type {(inputs: Loading_Downloadingshort1Inputs) => LocalizedString} */
725
+ () => (
726
+ /** @type {LocalizedString} */
727
+ "Downloaden"
728
+ )
729
+ ), Le = (
730
+ /** @type {(inputs: Loading_Downloadingshort1Inputs) => LocalizedString} */
731
+ () => (
732
+ /** @type {LocalizedString} */
733
+ "Herunterladen"
734
+ )
735
+ ), gt = (
736
+ /** @type {((inputs?: Loading_Downloadingshort1Inputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Loading_Downloadingshort1Inputs, { locale?: "en" | "nl" | "de" }, {}>} */
737
+ ((n = {}, t = {}) => {
738
+ const e = t.locale ?? h();
739
+ return e === "en" ? Oe() : e === "nl" ? Ne() : Le();
740
+ })
741
+ ), Me = (
742
+ /** @type {(inputs: Loading_RenderingInputs) => LocalizedString} */
743
+ () => (
744
+ /** @type {LocalizedString} */
745
+ "Rendering"
746
+ )
747
+ ), ze = (
748
+ /** @type {(inputs: Loading_RenderingInputs) => LocalizedString} */
749
+ () => (
750
+ /** @type {LocalizedString} */
751
+ "Renderen"
752
+ )
753
+ ), Fe = (
754
+ /** @type {(inputs: Loading_RenderingInputs) => LocalizedString} */
755
+ () => (
756
+ /** @type {LocalizedString} */
757
+ "Rendern"
758
+ )
759
+ ), Pe = (
760
+ /** @type {((inputs?: Loading_RenderingInputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Loading_RenderingInputs, { locale?: "en" | "nl" | "de" }, {}>} */
761
+ ((n = {}, t = {}) => {
762
+ const e = t.locale ?? h();
763
+ return e === "en" ? Me() : e === "nl" ? ze() : Fe();
764
+ })
765
+ ), $e = (
766
+ /** @type {(inputs: Controls_Screenshot_Buttonlabel1Inputs) => LocalizedString} */
767
+ () => (
768
+ /** @type {LocalizedString} */
769
+ "Screenshot"
770
+ )
771
+ ), De = (
772
+ /** @type {(inputs: Controls_Screenshot_Buttonlabel1Inputs) => LocalizedString} */
773
+ () => (
774
+ /** @type {LocalizedString} */
775
+ "Screenshot"
776
+ )
777
+ ), Be = (
778
+ /** @type {(inputs: Controls_Screenshot_Buttonlabel1Inputs) => LocalizedString} */
779
+ () => (
780
+ /** @type {LocalizedString} */
781
+ "Screenshot"
782
+ )
783
+ ), Ue = (
784
+ /** @type {((inputs?: Controls_Screenshot_Buttonlabel1Inputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Controls_Screenshot_Buttonlabel1Inputs, { locale?: "en" | "nl" | "de" }, {}>} */
785
+ ((n = {}, t = {}) => {
786
+ const e = t.locale ?? h();
787
+ return e === "en" ? $e() : e === "nl" ? De() : Be();
788
+ })
789
+ ), Ve = (
790
+ /** @type {(inputs: Controls_Configurator_OpenInputs) => LocalizedString} */
791
+ () => (
792
+ /** @type {LocalizedString} */
793
+ "Configure"
794
+ )
795
+ ), je = (
796
+ /** @type {(inputs: Controls_Configurator_OpenInputs) => LocalizedString} */
797
+ () => (
798
+ /** @type {LocalizedString} */
799
+ "Configureren"
800
+ )
801
+ ), He = (
802
+ /** @type {(inputs: Controls_Configurator_OpenInputs) => LocalizedString} */
803
+ () => (
804
+ /** @type {LocalizedString} */
805
+ "Konfigurieren"
806
+ )
807
+ ), Ge = (
808
+ /** @type {((inputs?: Controls_Configurator_OpenInputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Controls_Configurator_OpenInputs, { locale?: "en" | "nl" | "de" }, {}>} */
809
+ ((n = {}, t = {}) => {
810
+ const e = t.locale ?? h();
811
+ return e === "en" ? Ve() : e === "nl" ? je() : He();
812
+ })
813
+ ), qe = (
814
+ /** @type {(inputs: Controls_Configurator_CloseInputs) => LocalizedString} */
815
+ () => (
816
+ /** @type {LocalizedString} */
817
+ "Close"
818
+ )
819
+ ), Ze = (
820
+ /** @type {(inputs: Controls_Configurator_CloseInputs) => LocalizedString} */
821
+ () => (
822
+ /** @type {LocalizedString} */
823
+ "Sluiten"
824
+ )
825
+ ), We = (
826
+ /** @type {(inputs: Controls_Configurator_CloseInputs) => LocalizedString} */
827
+ () => (
828
+ /** @type {LocalizedString} */
829
+ "Schließen"
830
+ )
831
+ ), Ye = (
832
+ /** @type {((inputs?: Controls_Configurator_CloseInputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Controls_Configurator_CloseInputs, { locale?: "en" | "nl" | "de" }, {}>} */
833
+ ((n = {}, t = {}) => {
834
+ const e = t.locale ?? h();
835
+ return e === "en" ? qe() : e === "nl" ? Ze() : We();
836
+ })
837
+ ), Xe = (
838
+ /** @type {(inputs: Controls_Camera_ResetInputs) => LocalizedString} */
839
+ () => (
840
+ /** @type {LocalizedString} */
841
+ "Reset camera"
842
+ )
843
+ ), Ke = (
844
+ /** @type {(inputs: Controls_Camera_ResetInputs) => LocalizedString} */
845
+ () => (
846
+ /** @type {LocalizedString} */
847
+ "Camera resetten"
848
+ )
849
+ ), Qe = (
850
+ /** @type {(inputs: Controls_Camera_ResetInputs) => LocalizedString} */
851
+ () => (
852
+ /** @type {LocalizedString} */
853
+ "Kamera zurücksetzen"
854
+ )
855
+ ), Je = (
856
+ /** @type {((inputs?: Controls_Camera_ResetInputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Controls_Camera_ResetInputs, { locale?: "en" | "nl" | "de" }, {}>} */
857
+ ((n = {}, t = {}) => {
858
+ const e = t.locale ?? h();
859
+ return e === "en" ? Xe() : e === "nl" ? Ke() : Qe();
860
+ })
861
+ ), tn = (
862
+ /** @type {(inputs: Controls_Camera_Zoomin1Inputs) => LocalizedString} */
863
+ () => (
864
+ /** @type {LocalizedString} */
865
+ "Zoom in"
866
+ )
867
+ ), en = (
868
+ /** @type {(inputs: Controls_Camera_Zoomin1Inputs) => LocalizedString} */
869
+ () => (
870
+ /** @type {LocalizedString} */
871
+ "Inzoomen"
872
+ )
873
+ ), nn = (
874
+ /** @type {(inputs: Controls_Camera_Zoomin1Inputs) => LocalizedString} */
875
+ () => (
876
+ /** @type {LocalizedString} */
877
+ "Hineinzoomen"
878
+ )
879
+ ), on = (
880
+ /** @type {((inputs?: Controls_Camera_Zoomin1Inputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Controls_Camera_Zoomin1Inputs, { locale?: "en" | "nl" | "de" }, {}>} */
881
+ ((n = {}, t = {}) => {
882
+ const e = t.locale ?? h();
883
+ return e === "en" ? tn() : e === "nl" ? en() : nn();
884
+ })
885
+ ), sn = (
886
+ /** @type {(inputs: Controls_Camera_Zoomout1Inputs) => LocalizedString} */
887
+ () => (
888
+ /** @type {LocalizedString} */
889
+ "Zoom out"
890
+ )
891
+ ), rn = (
892
+ /** @type {(inputs: Controls_Camera_Zoomout1Inputs) => LocalizedString} */
893
+ () => (
894
+ /** @type {LocalizedString} */
895
+ "Uitzoomen"
896
+ )
897
+ ), an = (
898
+ /** @type {(inputs: Controls_Camera_Zoomout1Inputs) => LocalizedString} */
899
+ () => (
900
+ /** @type {LocalizedString} */
901
+ "Herauszoomen"
902
+ )
903
+ ), ln = (
904
+ /** @type {((inputs?: Controls_Camera_Zoomout1Inputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Controls_Camera_Zoomout1Inputs, { locale?: "en" | "nl" | "de" }, {}>} */
905
+ ((n = {}, t = {}) => {
906
+ const e = t.locale ?? h();
907
+ return e === "en" ? sn() : e === "nl" ? rn() : an();
908
+ })
909
+ ), cn = (
910
+ /** @type {(inputs: Controls_Camera_Rotateleft1Inputs) => LocalizedString} */
911
+ () => (
912
+ /** @type {LocalizedString} */
913
+ "Rotate left"
914
+ )
915
+ ), un = (
916
+ /** @type {(inputs: Controls_Camera_Rotateleft1Inputs) => LocalizedString} */
917
+ () => (
918
+ /** @type {LocalizedString} */
919
+ "Naar links draaien"
920
+ )
921
+ ), dn = (
922
+ /** @type {(inputs: Controls_Camera_Rotateleft1Inputs) => LocalizedString} */
923
+ () => (
924
+ /** @type {LocalizedString} */
925
+ "Nach links drehen"
926
+ )
927
+ ), hn = (
928
+ /** @type {((inputs?: Controls_Camera_Rotateleft1Inputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Controls_Camera_Rotateleft1Inputs, { locale?: "en" | "nl" | "de" }, {}>} */
929
+ ((n = {}, t = {}) => {
930
+ const e = t.locale ?? h();
931
+ return e === "en" ? cn() : e === "nl" ? un() : dn();
932
+ })
933
+ ), mn = (
934
+ /** @type {(inputs: Controls_Camera_Rotateright1Inputs) => LocalizedString} */
935
+ () => (
936
+ /** @type {LocalizedString} */
937
+ "Rotate right"
938
+ )
939
+ ), pn = (
940
+ /** @type {(inputs: Controls_Camera_Rotateright1Inputs) => LocalizedString} */
941
+ () => (
942
+ /** @type {LocalizedString} */
943
+ "Naar rechts draaien"
944
+ )
945
+ ), fn = (
946
+ /** @type {(inputs: Controls_Camera_Rotateright1Inputs) => LocalizedString} */
947
+ () => (
948
+ /** @type {LocalizedString} */
949
+ "Nach rechts drehen"
950
+ )
951
+ ), gn = (
952
+ /** @type {((inputs?: Controls_Camera_Rotateright1Inputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Controls_Camera_Rotateright1Inputs, { locale?: "en" | "nl" | "de" }, {}>} */
953
+ ((n = {}, t = {}) => {
954
+ const e = t.locale ?? h();
955
+ return e === "en" ? mn() : e === "nl" ? pn() : fn();
956
+ })
957
+ ), bn = (
958
+ /** @type {(inputs: Controls_Camera_Tiltup1Inputs) => LocalizedString} */
959
+ () => (
960
+ /** @type {LocalizedString} */
961
+ "Tilt up"
962
+ )
963
+ ), vn = (
964
+ /** @type {(inputs: Controls_Camera_Tiltup1Inputs) => LocalizedString} */
965
+ () => (
966
+ /** @type {LocalizedString} */
967
+ "Omhoog kantelen"
968
+ )
969
+ ), yn = (
970
+ /** @type {(inputs: Controls_Camera_Tiltup1Inputs) => LocalizedString} */
971
+ () => (
972
+ /** @type {LocalizedString} */
973
+ "Nach oben kippen"
974
+ )
975
+ ), _n = (
976
+ /** @type {((inputs?: Controls_Camera_Tiltup1Inputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Controls_Camera_Tiltup1Inputs, { locale?: "en" | "nl" | "de" }, {}>} */
977
+ ((n = {}, t = {}) => {
978
+ const e = t.locale ?? h();
979
+ return e === "en" ? bn() : e === "nl" ? vn() : yn();
980
+ })
981
+ ), wn = (
982
+ /** @type {(inputs: Controls_Camera_Tiltdown1Inputs) => LocalizedString} */
983
+ () => (
984
+ /** @type {LocalizedString} */
985
+ "Tilt down"
986
+ )
987
+ ), Cn = (
988
+ /** @type {(inputs: Controls_Camera_Tiltdown1Inputs) => LocalizedString} */
989
+ () => (
990
+ /** @type {LocalizedString} */
991
+ "Omlaag kantelen"
992
+ )
993
+ ), kn = (
994
+ /** @type {(inputs: Controls_Camera_Tiltdown1Inputs) => LocalizedString} */
995
+ () => (
996
+ /** @type {LocalizedString} */
997
+ "Nach unten kippen"
998
+ )
999
+ ), Sn = (
1000
+ /** @type {((inputs?: Controls_Camera_Tiltdown1Inputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Controls_Camera_Tiltdown1Inputs, { locale?: "en" | "nl" | "de" }, {}>} */
1001
+ ((n = {}, t = {}) => {
1002
+ const e = t.locale ?? h();
1003
+ return e === "en" ? wn() : e === "nl" ? Cn() : kn();
1004
+ })
1005
+ ), En = (
1006
+ /** @type {(inputs: Commerce_Submit_BusyInputs) => LocalizedString} */
1007
+ () => (
1008
+ /** @type {LocalizedString} */
1009
+ "Working…"
1010
+ )
1011
+ ), An = (
1012
+ /** @type {(inputs: Commerce_Submit_BusyInputs) => LocalizedString} */
1013
+ () => (
1014
+ /** @type {LocalizedString} */
1015
+ "Bezig…"
1016
+ )
1017
+ ), xn = (
1018
+ /** @type {(inputs: Commerce_Submit_BusyInputs) => LocalizedString} */
1019
+ () => (
1020
+ /** @type {LocalizedString} */
1021
+ "Läuft…"
1022
+ )
1023
+ ), Tn = (
1024
+ /** @type {((inputs?: Commerce_Submit_BusyInputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Commerce_Submit_BusyInputs, { locale?: "en" | "nl" | "de" }, {}>} */
1025
+ ((n = {}, t = {}) => {
1026
+ const e = t.locale ?? h();
1027
+ return e === "en" ? En() : e === "nl" ? An() : xn();
1028
+ })
1029
+ ), Rn = (
1030
+ /** @type {(inputs: Commerce_Submit_SuccessInputs) => LocalizedString} */
1031
+ () => (
1032
+ /** @type {LocalizedString} */
1033
+ "Done"
1034
+ )
1035
+ ), In = (
1036
+ /** @type {(inputs: Commerce_Submit_SuccessInputs) => LocalizedString} */
1037
+ () => (
1038
+ /** @type {LocalizedString} */
1039
+ "Gelukt"
1040
+ )
1041
+ ), On = (
1042
+ /** @type {(inputs: Commerce_Submit_SuccessInputs) => LocalizedString} */
1043
+ () => (
1044
+ /** @type {LocalizedString} */
1045
+ "Fertig"
1046
+ )
1047
+ ), Nn = (
1048
+ /** @type {((inputs?: Commerce_Submit_SuccessInputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Commerce_Submit_SuccessInputs, { locale?: "en" | "nl" | "de" }, {}>} */
1049
+ ((n = {}, t = {}) => {
1050
+ const e = t.locale ?? h();
1051
+ return e === "en" ? Rn() : e === "nl" ? In() : On();
1052
+ })
1053
+ ), Ln = (
1054
+ /** @type {(inputs: Commerce_Submit_FailedInputs) => LocalizedString} */
1055
+ () => (
1056
+ /** @type {LocalizedString} */
1057
+ "Failed"
1058
+ )
1059
+ ), Mn = (
1060
+ /** @type {(inputs: Commerce_Submit_FailedInputs) => LocalizedString} */
1061
+ () => (
1062
+ /** @type {LocalizedString} */
1063
+ "Mislukt"
1064
+ )
1065
+ ), zn = (
1066
+ /** @type {(inputs: Commerce_Submit_FailedInputs) => LocalizedString} */
1067
+ () => (
1068
+ /** @type {LocalizedString} */
1069
+ "Fehlgeschlagen"
1070
+ )
1071
+ ), Fn = (
1072
+ /** @type {((inputs?: Commerce_Submit_FailedInputs, options?: { locale?: "en" | "nl" | "de" }) => LocalizedString) & import('../runtime.js').MessageMetadata<Commerce_Submit_FailedInputs, { locale?: "en" | "nl" | "de" }, {}>} */
1073
+ ((n = {}, t = {}) => {
1074
+ const e = t.locale ?? h();
1075
+ return e === "en" ? Ln() : e === "nl" ? Mn() : zn();
1076
+ })
1077
+ ), _ = {
1078
+ fontFamily: {
1079
+ sans: ["Mona Sans", "ui-sans-serif", "system-ui", "sans-serif", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"]
1080
+ },
1081
+ fontSize: {
1082
+ xs: "0.75rem",
1083
+ // 12px
1084
+ sm: "0.875rem",
1085
+ // 14px
1086
+ base: "1rem",
1087
+ // 16px
1088
+ lg: "1.125rem"
1089
+ },
1090
+ fontWeight: {
1091
+ medium: "500",
1092
+ semibold: "600"
1093
+ }
1094
+ }, Pn = _.fontFamily.sans.join(", ");
1095
+ class $n {
1096
+ qrLib = null;
1097
+ dialog = null;
1098
+ async show(t) {
1099
+ this.hide(), this.qrLib ??= await import("./browser-ey6Iih3j.js").then((o) => o.b);
1100
+ const e = await this.qrLib.toDataURL(t, {
1101
+ width: 256,
1102
+ margin: 4,
1103
+ errorCorrectionLevel: "M",
1104
+ color: { dark: m.black, light: m.white }
1105
+ });
1106
+ this.dialog = new Qt({ onClose: () => {
1107
+ this.dialog = null;
1108
+ } }), Object.assign(this.dialog.card.element.style, {
1109
+ display: "flex",
1110
+ flexDirection: "column",
1111
+ alignItems: "center",
1112
+ gap: a[3],
1113
+ fontFamily: Pn
1114
+ }), this.dialog.card.element.appendChild(this.createText(pe(), {
1115
+ fontSize: _.fontSize.base,
1116
+ fontWeight: _.fontWeight.semibold,
1117
+ color: m.neutral[900]
1118
+ })), this.dialog.card.element.appendChild(this.createText(ve(), {
1119
+ fontSize: _.fontSize.sm,
1120
+ color: m.neutral[600]
1121
+ })), this.dialog.card.element.appendChild(this.createQrImage(e)), this.dialog.card.element.appendChild(this.createText(Ce(), {
1122
+ fontSize: _.fontSize.xs,
1123
+ color: m.neutral[500]
1124
+ }));
1125
+ const i = new g({
1126
+ variant: "outline",
1127
+ label: Ae(),
1128
+ onClick: () => {
1129
+ this.hide();
1130
+ }
1131
+ });
1132
+ this.dialog.card.element.appendChild(i.element), this.dialog.open();
1133
+ }
1134
+ hide() {
1135
+ this.dialog?.close(), this.dialog = null;
1136
+ }
1137
+ createText(t, e) {
1138
+ const i = document.createElement("p");
1139
+ return i.textContent = t, Object.assign(i.style, { margin: "0", textAlign: "center", ...e }), i;
1140
+ }
1141
+ createQrImage(t) {
1142
+ const e = document.createElement("img");
1143
+ return e.src = t, e.alt = "QR code", Object.assign(e.style, {
1144
+ width: a[24],
1145
+ height: a[24],
1146
+ borderRadius: a[1]
1147
+ }), e;
1148
+ }
1149
+ }
1150
+ const x = _.fontFamily.sans.join(", "), Dn = `
1151
+ --primary: oklch(5% 0 0);
1152
+ --primary-foreground: oklch(100% 0 0);
1153
+ --secondary: oklch(92% 0 0);
1154
+ --secondary-foreground: oklch(5% 0 0);
1155
+ --background: oklch(100% 0 0);
1156
+ --foreground: oklch(5% 0 0);
1157
+ --border: oklch(92% 0 0);
1158
+ --ring: oklch(44% 0 0);
1159
+ --radius: 0.625rem;
1160
+ --accent: oklch(92% 0 0);
1161
+ --accent-foreground: oklch(5% 0 0);
1162
+ --muted-foreground: oklch(44% 0 0);
1163
+ `, Bn = `
1164
+ :root { ${Dn} }
1165
+
1166
+ /* ── Button ──────────────────────────────────────────────── */
1167
+ .ui-btn {
1168
+ display: inline-flex;
1169
+ align-items: center;
1170
+ justify-content: center;
1171
+ gap: 0.5rem;
1172
+ border: 1px solid transparent;
1173
+ border-radius: var(--radius);
1174
+ font-family: ${x};
1175
+ font-size: 0.875rem;
1176
+ font-weight: 600;
1177
+ white-space: nowrap;
1178
+ cursor: pointer;
1179
+ transition: all 200ms;
1180
+ flex-shrink: 0;
1181
+ }
1182
+ .ui-btn:active { transform: scale(0.98); }
1183
+ .ui-btn:disabled { opacity: 0.5; pointer-events: none; }
1184
+ .ui-btn svg { inline-size: 1rem; block-size: 1rem; pointer-events: none; flex-shrink: 0; }
1185
+
1186
+ .ui-btn--default {
1187
+ background: var(--primary);
1188
+ color: var(--primary-foreground);
1189
+ box-shadow: 0 1px 3px oklch(5% 0 0 / 20%);
1190
+ }
1191
+ .ui-btn--default:hover { background: oklch(10% 0 0); }
1192
+
1193
+ .ui-btn--outline {
1194
+ background: var(--background);
1195
+ color: var(--foreground);
1196
+ border-color: var(--border);
1197
+ box-shadow: 0 1px 2px oklch(5% 0 0 / 8%);
1198
+ }
1199
+ .ui-btn--outline:hover { background: var(--accent); border-color: oklch(85% 0 0); }
1200
+
1201
+ .ui-btn--secondary {
1202
+ background: var(--secondary);
1203
+ color: var(--secondary-foreground);
1204
+ box-shadow: 0 1px 2px oklch(5% 0 0 / 8%);
1205
+ }
1206
+ .ui-btn--secondary:hover { background: oklch(88% 0 0); }
1207
+
1208
+ .ui-btn--ghost { background: transparent; color: var(--foreground); }
1209
+ .ui-btn--ghost:hover { background: var(--accent); }
1210
+
1211
+ .ui-btn--size-default { block-size: 2.25rem; padding: 0 1rem; }
1212
+ .ui-btn--size-sm { block-size: 2rem; padding: 0 0.75rem; border-radius: calc(var(--radius) - 0.125rem); }
1213
+ .ui-btn--size-lg { block-size: 2.5rem; padding: 0 1.5rem; }
1214
+ .ui-btn--size-icon { inline-size: 2.25rem; block-size: 2.25rem; padding: 0; }
1215
+ .ui-btn--size-icon-sm { inline-size: 2rem; block-size: 2rem; padding: 0; }
1216
+ .ui-btn--size-icon-lg { inline-size: 2.5rem; block-size: 2.5rem; padding: 0; }
1217
+
1218
+ /* ── Toggle group ────────────────────────────────────────── */
1219
+ .ui-toggle-group { display: inline-flex; flex-wrap: wrap; gap: 0.25rem; }
1220
+
1221
+ .ui-toggle-group-item {
1222
+ display: inline-flex;
1223
+ align-items: center;
1224
+ justify-content: center;
1225
+ block-size: 2rem;
1226
+ padding: 0 0.75rem;
1227
+ border: 1px solid var(--border);
1228
+ border-radius: var(--radius);
1229
+ background: var(--background);
1230
+ color: var(--foreground);
1231
+ font-family: ${x};
1232
+ font-size: 0.875rem;
1233
+ font-weight: 600;
1234
+ cursor: pointer;
1235
+ white-space: nowrap;
1236
+ transition: all 200ms;
1237
+ box-shadow: 0 1px 2px oklch(5% 0 0 / 8%);
1238
+ }
1239
+ .ui-toggle-group-item:hover { background: var(--accent); border-color: oklch(85% 0 0); }
1240
+ .ui-toggle-group-item:active { transform: scale(0.98); }
1241
+ .ui-toggle-group-item:focus-visible {
1242
+ outline: none;
1243
+ border-color: var(--ring);
1244
+ box-shadow: 0 0 0 3px oklch(5% 0 0 / 12%);
1245
+ }
1246
+ .ui-toggle-group-item[data-state="on"] {
1247
+ background: var(--primary);
1248
+ color: var(--primary-foreground);
1249
+ border-color: var(--primary);
1250
+ }
1251
+ .ui-toggle-group-item[data-state="on"]:hover { background: oklch(10% 0 0); }
1252
+
1253
+ /* ── Native select ───────────────────────────────────────── */
1254
+ .ui-native-select-wrap {
1255
+ position: relative;
1256
+ display: inline-flex;
1257
+ min-inline-size: 8rem;
1258
+ }
1259
+
1260
+ .ui-native-select {
1261
+ display: block;
1262
+ inline-size: 100%;
1263
+ block-size: 2.25rem;
1264
+ padding: 0 2.25rem 0 0.75rem;
1265
+ border: 1px solid var(--border);
1266
+ border-radius: var(--radius);
1267
+ background: var(--background);
1268
+ appearance: none;
1269
+ color: var(--foreground);
1270
+ font-family: ${x};
1271
+ font-size: 0.875rem;
1272
+ font-weight: 400;
1273
+ cursor: pointer;
1274
+ transition: color 200ms, box-shadow 200ms, border-color 200ms;
1275
+ box-shadow: 0 1px 2px oklch(5% 0 0 / 8%);
1276
+ }
1277
+ .ui-native-select:hover { border-color: oklch(85% 0 0); }
1278
+ .ui-native-select:focus-visible {
1279
+ outline: none;
1280
+ border-color: var(--ring);
1281
+ box-shadow: 0 0 0 3px oklch(5% 0 0 / 12%);
1282
+ }
1283
+
1284
+ .ui-native-select-icon {
1285
+ position: absolute;
1286
+ inset-block-start: 50%;
1287
+ inset-inline-end: 0.625rem;
1288
+ transform: translateY(-50%);
1289
+ color: var(--muted-foreground);
1290
+ pointer-events: none;
1291
+ }
1292
+
1293
+ /* ── Annotation layer ───────────────────────────────────── */
1294
+ .vd-annotations-layer {
1295
+ position: absolute;
1296
+ inset-block-start: 0;
1297
+ inset-inline-start: 0;
1298
+ inline-size: 100%;
1299
+ block-size: 100%;
1300
+ pointer-events: none;
1301
+ overflow: visible !important; /* override CSS2DRenderer inline style */
1302
+ }
1303
+
1304
+ .vd-annotation-anchor {
1305
+ position: relative;
1306
+ }
1307
+
1308
+ .vd-annotation-marker {
1309
+ display: flex;
1310
+ align-items: center;
1311
+ justify-content: center;
1312
+ inline-size: 1.75rem;
1313
+ block-size: 1.75rem;
1314
+ border-radius: 50%;
1315
+ border: 2px solid oklch(100% 0 0);
1316
+ background: var(--primary);
1317
+ color: var(--primary-foreground);
1318
+ font-family: ${x};
1319
+ font-size: 0.8125rem;
1320
+ font-weight: 600;
1321
+ cursor: pointer;
1322
+ pointer-events: auto;
1323
+ box-shadow: 0 2px 8px oklch(5% 0 0 / 20%);
1324
+ transition: transform 100ms ease;
1325
+ position: relative;
1326
+ }
1327
+ .vd-annotation-marker:hover { transform: scale(1.1); }
1328
+ .vd-annotation-marker:focus-visible {
1329
+ outline: 2px solid var(--ring);
1330
+ outline-offset: 2px;
1331
+ }
1332
+
1333
+ .vd-annotation-popup {
1334
+ position: absolute;
1335
+ inset-block-end: calc(100% + 0.5rem);
1336
+ inset-inline-start: 50%;
1337
+ transform: translateX(-50%);
1338
+ background: var(--background);
1339
+ color: var(--foreground);
1340
+ border: 1px solid var(--border);
1341
+ border-radius: var(--radius);
1342
+ padding: 0.75rem 1rem;
1343
+ max-inline-size: 15rem;
1344
+ box-shadow: 0 4px 6px oklch(5% 0 0 / 8%), 0 2px 4px oklch(5% 0 0 / 6%);
1345
+ pointer-events: auto;
1346
+ white-space: normal;
1347
+ }
1348
+ .vd-annotation-popup:focus { outline: none; }
1349
+
1350
+ .vd-annotation-popup-close {
1351
+ position: absolute;
1352
+ inset-block-start: 0.375rem;
1353
+ inset-inline-end: 0.375rem;
1354
+ display: flex;
1355
+ align-items: center;
1356
+ justify-content: center;
1357
+ inline-size: 1.25rem;
1358
+ block-size: 1.25rem;
1359
+ padding: 0;
1360
+ border: none;
1361
+ border-radius: calc(var(--radius) - 4px);
1362
+ background: transparent;
1363
+ color: var(--muted-foreground);
1364
+ cursor: pointer;
1365
+ pointer-events: auto;
1366
+ }
1367
+ .vd-annotation-popup-close:hover {
1368
+ color: var(--foreground);
1369
+ background: var(--secondary);
1370
+ }
1371
+ .vd-annotation-popup-close:focus-visible {
1372
+ outline: 2px solid var(--ring);
1373
+ outline-offset: 1px;
1374
+ }
1375
+ .vd-annotation-popup-close svg {
1376
+ inline-size: 0.875rem;
1377
+ block-size: 0.875rem;
1378
+ }
1379
+
1380
+ @media (prefers-reduced-motion: no-preference) {
1381
+ .vd-annotation-popup {
1382
+ animation: vd-popup-in 150ms ease;
1383
+ }
1384
+ }
1385
+
1386
+ @keyframes vd-popup-in {
1387
+ from { opacity: 0; transform: translateX(-50%) translateY(4px); }
1388
+ to { opacity: 1; transform: translateX(-50%) translateY(0); }
1389
+ }
1390
+
1391
+ .vd-annotation-popup-title {
1392
+ font-family: ${x};
1393
+ font-size: 0.875rem;
1394
+ font-weight: 600;
1395
+ line-height: 1.25rem;
1396
+ /* Keep the title clear of the absolutely positioned close button. */
1397
+ padding-inline-end: 1.5rem;
1398
+ }
1399
+
1400
+ .vd-annotation-popup-description {
1401
+ font-family: ${x};
1402
+ font-size: 0.8125rem;
1403
+ font-weight: 400;
1404
+ line-height: 1.125rem;
1405
+ color: var(--muted-foreground);
1406
+ margin-block-start: 0.25rem;
1407
+ }
1408
+ `;
1409
+ let et = !1;
1410
+ function Un() {
1411
+ if (et || typeof document > "u")
1412
+ return;
1413
+ et = !0;
1414
+ const n = document.createElement("style");
1415
+ n.id = "vd-ui-vanilla", n.textContent = Bn, document.head.appendChild(n);
1416
+ }
1417
+ function Vn() {
1418
+ return /* @__PURE__ */ new Date();
1419
+ }
1420
+ function jn(n) {
1421
+ return n.toISOString();
1422
+ }
1423
+ function bt() {
1424
+ return typeof navigator > "u" ? "" : navigator.userAgent;
1425
+ }
1426
+ function Hn() {
1427
+ return typeof navigator > "u" ? !1 : navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1;
1428
+ }
1429
+ function Gn() {
1430
+ return /iPhone|iPad|iPod/i.test(bt()) || Hn();
1431
+ }
1432
+ function qn() {
1433
+ return /Android/i.test(bt());
1434
+ }
1435
+ function Zn() {
1436
+ return Gn() || qn();
1437
+ }
1438
+ class Wn {
1439
+ constructor(t) {
1440
+ this.send = t;
1441
+ }
1442
+ send;
1443
+ setEnabled(t) {
1444
+ this.send({
1445
+ type: c.ANNOTATION_TOGGLE,
1446
+ enabled: t
1447
+ });
1448
+ }
1449
+ }
1450
+ class Yn {
1451
+ constructor(t, e) {
1452
+ this.value = t, this.attribute = e;
1453
+ }
1454
+ value;
1455
+ attribute;
1456
+ isSelectedValue = !1;
1457
+ get isSelected() {
1458
+ return this.isSelectedValue;
1459
+ }
1460
+ setSelected(t) {
1461
+ this.isSelectedValue = t;
1462
+ }
1463
+ }
1464
+ const E = {
1465
+ NO_MAPPING: "NO_MAPPING",
1466
+ ATTRIBUTE_NOT_FOUND: "ATTRIBUTE_NOT_FOUND",
1467
+ VALUE_NOT_FOUND: "VALUE_NOT_FOUND",
1468
+ PARENT_NOT_FOUND: "PARENT_NOT_FOUND",
1469
+ INVALID_PARAMETER: "INVALID_PARAMETER",
1470
+ SNAPSHOT_FAILED: "SNAPSHOT_FAILED"
416
1471
  };
417
- new Set([b.CAMERA]);
418
- //#endregion
419
- //#region src/attributes/attributes.ts
420
- var j = class {
421
- registry;
422
- pendingCallbacks = [];
423
- constructor(e, t) {
424
- this.send = e, this.onMutationFailed = t;
425
- }
426
- handleMappingReceived(e) {
427
- p.debug("Initializing from server mapping", { attributeCount: e.attributes.length }), this.registry = new y(e.attributes, (e, t) => this.sendMutation(e, t), this.onMutationFailed);
428
- let t = this.registry.defaults();
429
- t.length > 0 && this.sendMutation(t, !0), this.replayPendingCallbacks();
430
- }
431
- handleMutationResult(e) {
432
- this.registry?.handleResults(e.results);
433
- }
434
- select(e, t) {
435
- this.sendMutation([{
436
- name: e,
437
- value: t
438
- }], !1);
439
- }
440
- getValues(e) {
441
- return this.registry?.get(e)?.getValues() ?? [];
442
- }
443
- getValue(e, t) {
444
- return this.registry?.get(e)?.getValue(t);
445
- }
446
- onChange(e, t) {
447
- if (this.registry === void 0) {
448
- this.pendingCallbacks.push({
449
- name: e,
450
- callback: t
451
- });
452
- return;
453
- }
454
- let n = this.registry.get(e);
455
- if (n === void 0) {
456
- p.warn(`onChange: attribute "${e}" not found — callback will not fire`);
457
- return;
458
- }
459
- n.onChange(t);
460
- }
461
- getAttribute(e) {
462
- return this.registry?.get(e);
463
- }
464
- get hasMapping() {
465
- return this.registry !== void 0;
466
- }
467
- sendMutation(e, t) {
468
- let n = {
469
- type: b.MUTATION,
470
- mutations: e,
471
- isInitial: t
472
- };
473
- this.send(n);
474
- }
475
- replayPendingCallbacks() {
476
- for (let { name: e, callback: t } of this.pendingCallbacks) {
477
- let n = this.registry?.get(e);
478
- n === void 0 && p.warn(`onChange: attribute "${e}" not found — buffered callback will not fire`), n?.onChange(t);
479
- }
480
- this.pendingCallbacks.length = 0;
481
- }
482
- }, M = class {
483
- commands = [];
484
- constructor(e) {
485
- this.send = e;
486
- }
487
- rotate(e) {
488
- return this.validateFiniteNumber(e, "rotate"), this.commands.push({
489
- action: "rotate",
490
- value: e
491
- }), this;
492
- }
493
- tilt(e) {
494
- return this.validateFiniteNumber(e, "tilt"), this.commands.push({
495
- action: "tilt",
496
- value: e
497
- }), this;
498
- }
499
- zoom(e) {
500
- return this.validateFiniteNumber(e, "zoom"), this.commands.push({
501
- action: "zoom",
502
- value: e
503
- }), this;
504
- }
505
- set() {
506
- if (this.commands.length === 0) throw t.invalidParameter("No camera commands to execute. Call rotate(), tilt(), or zoom() before set().");
507
- let e = {
508
- type: b.CAMERA,
509
- commands: this.commands
510
- };
511
- this.send(e), this.commands = [];
512
- }
513
- validateFiniteNumber(e, n) {
514
- if (!Number.isFinite(e)) throw t.invalidParameter(`${n}() requires a finite number, got ${String(e)}`);
515
- }
516
- reset() {
517
- let e = {
518
- type: b.CAMERA,
519
- commands: [{ action: "reset" }]
520
- };
521
- this.send(e);
522
- }
523
- }, N = class {
524
- state;
525
- changeCallbacks = [];
526
- constructor() {
527
- this.state = {
528
- rotation: 0,
529
- tilt: 0,
530
- zoom: 0
531
- };
532
- }
533
- get rotation() {
534
- return this.state.rotation;
535
- }
536
- get tilt() {
537
- return this.state.tilt;
538
- }
539
- get zoom() {
540
- return this.state.zoom;
541
- }
542
- onChange(e) {
543
- this.changeCallbacks.push(e);
544
- }
545
- handlePositionUpdate(e) {
546
- this.update(e.transforms);
547
- }
548
- update(e) {
549
- let t = !1;
550
- for (let n of e) switch (n.type) {
551
- case "rotation":
552
- this.state.rotation = n.value, t = !0;
553
- break;
554
- case "tilt":
555
- this.state.tilt = n.value, t = !0;
556
- break;
557
- case "zoom":
558
- this.state.zoom = n.value, t = !0;
559
- break;
560
- default: break;
561
- }
562
- if (t) {
563
- let e = {
564
- rotation: this.rotation,
565
- tilt: this.tilt,
566
- zoom: this.zoom
567
- };
568
- for (let t of this.changeCallbacks) t(e);
569
- }
570
- }
571
- }, P = class {
572
- developedCallbacks = /* @__PURE__ */ new Set();
573
- errorCallbacks = /* @__PURE__ */ new Set();
574
- developed = !1;
575
- failed = !1;
576
- photoData = null;
577
- constructor(e) {
578
- this.filename = e;
579
- }
580
- onDeveloped(e) {
581
- return this.developed && this.photoData !== null ? (e(this.photoData), this) : (this.developedCallbacks.add(e), this);
582
- }
583
- onError(e) {
584
- return this.errorCallbacks.add(e), this;
585
- }
586
- getFilename() {
587
- return this.filename;
588
- }
589
- develop(e) {
590
- this.developed || this.failed || (this.photoData = e, this.developed = !0, this.developedCallbacks.forEach((e) => {
591
- e(this.photoData);
592
- }), this.developedCallbacks.clear(), this.errorCallbacks.clear());
593
- }
594
- fail(e) {
595
- this.developed || this.failed || (this.failed = !0, this.errorCallbacks.forEach((t) => {
596
- t(e);
597
- }), this.developedCallbacks.clear(), this.errorCallbacks.clear());
598
- }
599
- }, F = class {
600
- validExtensions = [".png"];
601
- pendingPhotos = /* @__PURE__ */ new Map();
602
- constructor(e) {
603
- this.send = e;
604
- }
605
- take(e) {
606
- this.validateFilename(e), p.debug("Taking snapshot", { filename: e });
607
- let t = new P(e);
608
- return this.pendingPhotos.set(t.getFilename(), t), this.send({
609
- type: b.SNAPSHOT,
610
- filename: e
611
- }), t;
612
- }
613
- handleSnapshotResult(n) {
614
- let r = this.pendingPhotos.get(n.filename);
615
- if (r === void 0) {
616
- p.warn("No pending photo found for filename", {
617
- filename: n.filename,
618
- pendingFilenames: Array.from(this.pendingPhotos.keys())
619
- });
620
- return;
621
- }
622
- if (this.pendingPhotos.delete(n.filename), n.error !== void 0) {
623
- r.fail(new t(n.error, e.SNAPSHOT_FAILED));
624
- return;
625
- }
626
- n.data !== void 0 && r.develop({
627
- filename: n.filename,
628
- data: n.data
629
- });
630
- }
631
- validateFilename(n) {
632
- if (n === "" || typeof n != "string") throw new t("Filename must be a non-empty string", e.INVALID_PARAMETER);
633
- if (!this.validExtensions.some((e) => n.toLowerCase().endsWith(e))) throw new t(`Invalid filename: "${n}". Filename must end with one of: ${this.validExtensions.join(", ")}`, e.INVALID_PARAMETER);
634
- if (n.includes("..") || n.includes("/") || n.includes("\\")) throw new t("Filename cannot contain path separators or \"..\"", e.INVALID_PARAMETER);
635
- }
636
- }, I = class {
637
- send;
638
- constructor(e) {
639
- this.send = e;
640
- }
641
- sendInitialConfig(e) {
642
- let t = this.buildUIConfig(e), n = this.buildViewerConfig(t, e.camera);
643
- n !== void 0 && this.sendConfig(n);
644
- }
645
- buildUIConfig(e) {
646
- let t = this.extractUIValues(e);
647
- if (Object.values(t).some((e) => e !== void 0)) return {
648
- ...t.arEnabled !== void 0 && { arEnabled: t.arEnabled },
649
- ...t.fullscreenEnabled !== void 0 && { fullscreenEnabled: t.fullscreenEnabled },
650
- ...t.loadingIndicatorEnabled !== void 0 && { loadingIndicatorEnabled: t.loadingIndicatorEnabled }
651
- };
652
- }
653
- extractUIValues(e) {
654
- return {
655
- arEnabled: e.arEnabled ?? e.ui?.arEnabled,
656
- fullscreenEnabled: e.fullscreenEnabled ?? e.ui?.fullscreenEnabled,
657
- loadingIndicatorEnabled: e.loadingIndicatorEnabled ?? e.ui?.loadingIndicatorEnabled
658
- };
659
- }
660
- buildViewerConfig(e, t) {
661
- if (!(e === void 0 && t === void 0)) return {
662
- ...e !== void 0 && { ui: e },
663
- ...t !== void 0 && { camera: t }
664
- };
665
- }
666
- setArEnabled(e) {
667
- p.debug(`Setting AR button enabled: ${e}`), this.updateUIConfig({ arEnabled: e });
668
- }
669
- setFullscreenEnabled(e) {
670
- p.debug(`Setting fullscreen button enabled: ${e}`), this.updateUIConfig({ fullscreenEnabled: e });
671
- }
672
- setLoadingIndicatorEnabled(e) {
673
- p.debug(`Setting loading indicator enabled: ${e}`), this.updateUIConfig({ loadingIndicatorEnabled: e });
674
- }
675
- updateUIConfig(e) {
676
- p.debug("Updating UI configuration", e), Object.keys(e).length > 0 && this.sendConfig({ ui: e });
677
- }
678
- hideAllUI() {
679
- p.debug("Hiding all UI elements"), this.sendUIConfig({
680
- arEnabled: !1,
681
- fullscreenEnabled: !1,
682
- loadingIndicatorEnabled: !1
683
- });
684
- }
685
- showAllUI() {
686
- p.debug("Showing all UI elements"), this.sendUIConfig({
687
- arEnabled: !0,
688
- fullscreenEnabled: !0,
689
- loadingIndicatorEnabled: !0
690
- });
691
- }
692
- sendUIConfig(e) {
693
- this.sendConfig({ ui: e });
694
- }
695
- sendConfig(e) {
696
- let t = {
697
- type: b.CONFIG,
698
- config: e
699
- };
700
- p.debug("Sending config", t), this.send(t);
701
- }
702
- }, L = class {
703
- attributes;
704
- readyStateTracker;
705
- messenger;
706
- viewerService;
707
- cameraApi;
708
- cameraPositionApi;
709
- snapshotApi;
710
- options;
711
- iframe;
712
- readyCallbacks = [];
713
- mutationFailedCallbacks = [];
714
- constructor(e) {
715
- this.options = e, this.initializeLogging(), this.messenger = new A(() => this.iframe?.contentWindow ?? null);
716
- let t = (e) => {
717
- this.messenger.send(e);
718
- };
719
- this.attributes = new j(t, (e, t) => {
720
- for (let n of this.mutationFailedCallbacks) n({
721
- attribute: e,
722
- value: t
723
- });
724
- }), this.readyStateTracker = new g(() => {
725
- let e = this.readyCallbacks;
726
- this.readyCallbacks = [];
727
- for (let t of e) t(this);
728
- }), this.viewerService = new I(t), this.cameraApi = new M(t), this.cameraPositionApi = new N(), this.snapshotApi = new F(t), this.registerHandlers(), this.messenger.start(), this.createAndConnectIframe();
729
- }
730
- registerHandlers() {
731
- this.messenger.on(b.READY, (e) => {
732
- C(e) && (p.info("Server ready — flushing publisher queue"), this.messenger.markReady(), this.viewerService.sendInitialConfig(this.options));
733
- }), this.messenger.on(b.MUTATION, (e) => {
734
- w(e) && (this.attributes.handleMutationResult(e), this.readyStateTracker.handleMutationResult(e));
735
- }), this.messenger.on(b.SNAPSHOT, (e) => {
736
- T(e) && this.snapshotApi.handleSnapshotResult(e);
737
- }), this.messenger.on(b.CAMERA, (e) => {
738
- E(e) && this.cameraPositionApi.handlePositionUpdate(e);
739
- }), this.messenger.on(b.MAPPING, (e) => {
740
- D(e) && (this.attributes.handleMappingReceived(e), this.readyStateTracker.handleMappingReceived());
741
- });
742
- }
743
- initializeLogging() {
744
- this.options.debug === !0 && m(), p.info("Initializing Virtualdisplay client", {
745
- model: this.options.model,
746
- debug: this.options.debug,
747
- language: this.options.language
748
- });
749
- }
750
- createAndConnectIframe() {
751
- p.debug("Creating iframe for Virtualdisplay viewer"), this.iframe = new n(this.options).create(), p.debug("Iframe created, waiting for server READY");
752
- }
753
- select(e, t) {
754
- this.attributes.select(e, t);
755
- }
756
- getValues(e) {
757
- return this.attributes.getValues(e);
758
- }
759
- getValue(e, t) {
760
- return this.attributes.getValue(e, t);
761
- }
762
- onChange(e, t) {
763
- this.attributes.onChange(e, t);
764
- }
765
- getAttribute(e) {
766
- return this.attributes.getAttribute(e);
767
- }
768
- get isReady() {
769
- return this.readyStateTracker.isReady;
770
- }
771
- onReady(e) {
772
- if (this.readyStateTracker.isReady) {
773
- e(this);
774
- return;
775
- }
776
- this.readyCallbacks.push(e);
777
- }
778
- onMutationFailed(e) {
779
- this.mutationFailedCallbacks.push(e);
780
- }
781
- get viewer() {
782
- return this.viewerService;
783
- }
784
- get camera() {
785
- return this.cameraApi;
786
- }
787
- get cameraPosition() {
788
- return this.cameraPositionApi;
789
- }
790
- get snapshot() {
791
- return this.snapshotApi;
792
- }
793
- destroy() {
794
- p.info("Destroying Virtualdisplay client"), this.readyStateTracker.clear(), this.readyCallbacks = [], this.messenger.destroy(), this.iframe?.parentElement !== null && this.iframe?.parentElement !== void 0 && this.iframe.parentElement.removeChild(this.iframe), this.iframe = void 0, p.debug("Virtualdisplay client destroyed");
795
- }
1472
+ class f extends Error {
1473
+ code;
1474
+ constructor(t, e) {
1475
+ super(t), this.name = "VirtualdisplayError", this.code = e;
1476
+ }
1477
+ static valueNotFound(t, e) {
1478
+ return new f(
1479
+ `Value "${e}" not found for attribute "${t}"`,
1480
+ E.VALUE_NOT_FOUND
1481
+ );
1482
+ }
1483
+ static parentNotFound(t) {
1484
+ return new f(
1485
+ `Parent element not found: ${t}`,
1486
+ E.PARENT_NOT_FOUND
1487
+ );
1488
+ }
1489
+ static invalidParameter(t) {
1490
+ return new f(t, E.INVALID_PARAMETER);
1491
+ }
1492
+ }
1493
+ class Xn {
1494
+ name;
1495
+ defaultValue;
1496
+ values;
1497
+ onSelect;
1498
+ onChangeCallback;
1499
+ constructor(t) {
1500
+ this.name = t.name, this.defaultValue = t.defaultValue, this.onSelect = t.onSelect, this.values = this.createValues(t.values);
1501
+ }
1502
+ /**
1503
+ * Select a value for this attribute
1504
+ * @throws {VirtualdisplayError} When value not found
1505
+ */
1506
+ select(t) {
1507
+ if (!this.values.has(t))
1508
+ throw f.valueNotFound(this.name, t);
1509
+ this.onSelect(this.name, t);
1510
+ }
1511
+ getValues() {
1512
+ return Array.from(this.values.values());
1513
+ }
1514
+ getValue(t) {
1515
+ return this.values.get(t);
1516
+ }
1517
+ /** The currently selected value, or undefined before any selection lands. */
1518
+ get selected() {
1519
+ for (const t of this.values.values())
1520
+ if (t.isSelected)
1521
+ return t.value;
1522
+ }
1523
+ /**
1524
+ * Register callback that fires when selection changes
1525
+ * Receives the newly selected AttributeValue
1526
+ */
1527
+ onChange(t) {
1528
+ this.onChangeCallback = t;
1529
+ }
1530
+ /**
1531
+ * Update selection state from server mutation result
1532
+ * Direct value comparison - no source/target translation
1533
+ */
1534
+ handleResult(t) {
1535
+ let e;
1536
+ for (const i of this.values.values()) {
1537
+ const o = i.value === t;
1538
+ i.setSelected(o), o && (e = i);
1539
+ }
1540
+ e !== void 0 && this.onChangeCallback !== void 0 && this.onChangeCallback(e);
1541
+ }
1542
+ createValues(t) {
1543
+ const e = /* @__PURE__ */ new Map();
1544
+ for (const i of t) {
1545
+ const o = new Yn(i, this.name);
1546
+ i === this.defaultValue && o.setSelected(!0), e.set(i, o);
1547
+ }
1548
+ return e;
1549
+ }
1550
+ }
1551
+ class Kn {
1552
+ attributes = /* @__PURE__ */ new Map();
1553
+ constructor(t, e, i) {
1554
+ for (const o of t) {
1555
+ const s = this.buildOptions(o, e);
1556
+ this.attributes.set(o.name, new Xn(s));
1557
+ }
1558
+ this.onMutationFailed = i;
1559
+ }
1560
+ onMutationFailed;
1561
+ get(t) {
1562
+ return this.attributes.get(t);
1563
+ }
1564
+ /** The current selection as attribute name→value pairs, skipping unset attributes. */
1565
+ getSelection() {
1566
+ const t = {};
1567
+ for (const [e, i] of this.attributes) {
1568
+ const o = i.selected;
1569
+ o !== void 0 && (t[e] = o);
1570
+ }
1571
+ return t;
1572
+ }
1573
+ handleResults(t) {
1574
+ for (const e of t) {
1575
+ if (!e.success) {
1576
+ this.onMutationFailed?.(e.name, e.value);
1577
+ continue;
1578
+ }
1579
+ this.get(e.name)?.handleResult(e.value);
1580
+ }
1581
+ }
1582
+ buildOptions(t, e) {
1583
+ const i = {
1584
+ name: t.name,
1585
+ values: t.values,
1586
+ onSelect: (o, s) => {
1587
+ e([{ name: o, value: s }], !1);
1588
+ }
1589
+ };
1590
+ return t.defaultValue !== void 0 ? { ...i, defaultValue: t.defaultValue } : i;
1591
+ }
1592
+ }
1593
+ function Qn(n) {
1594
+ const t = new Date(n.timestamp).toLocaleTimeString("en-GB", { hour12: !1 }), e = n.level.toUpperCase().padEnd(5), i = n.trace_id?.slice(0, 8) ?? "--------", o = n.msg, s = ["timestamp", "level", "msg", "service", "trace_id", "span_id"], r = Object.entries(n).filter(([l]) => !s.includes(l)).map(([l, d]) => `${l}=${JSON.stringify(d)}`).join(" ");
1595
+ return `${t} ${e} [${i}] ${o}${r ? " " + r : ""}`;
1596
+ }
1597
+ function Jn(n) {
1598
+ return JSON.stringify(n);
1599
+ }
1600
+ function ti(n, t) {
1601
+ const e = t ? Qn(n) : Jn(n);
1602
+ n.level === "error" ? console.error(e) : n.level === "warn" ? console.warn(e) : console.log(e);
1603
+ }
1604
+ function vt(n, t = 0) {
1605
+ const e = {
1606
+ name: n.name,
1607
+ message: n.message
1608
+ };
1609
+ n.stack !== void 0 && (e.stack = n.stack);
1610
+ for (const i of Object.getOwnPropertyNames(n)) {
1611
+ if (i === "name" || i === "message" || i === "stack" || i === "cause")
1612
+ continue;
1613
+ const o = n[i];
1614
+ o !== void 0 && (e[i] = o);
1615
+ }
1616
+ return n.cause !== void 0 && n.cause !== null && (e.cause = n.cause instanceof Error && t < 5 ? vt(n.cause, t + 1) : String(n.cause)), e;
1617
+ }
1618
+ function ei(n) {
1619
+ const t = {};
1620
+ for (const [e, i] of Object.entries(n))
1621
+ t[e] = i instanceof Error ? vt(i) : i;
1622
+ return t;
1623
+ }
1624
+ class ni {
1625
+ constructor(t) {
1626
+ this.config = t;
1627
+ }
1628
+ config;
1629
+ /**
1630
+ * Log at specified level with optional attributes.
1631
+ */
1632
+ log(t, e, i = {}) {
1633
+ const o = this.config.traceProvider?.() ?? {}, s = {
1634
+ timestamp: jn(Vn()),
1635
+ level: t,
1636
+ msg: e,
1637
+ service: this.config.service,
1638
+ ...o,
1639
+ ...ei(i)
1640
+ };
1641
+ ti(s, this.config.isDev);
1642
+ }
1643
+ /**
1644
+ * Log at DEBUG level (development only).
1645
+ */
1646
+ debug(t, e) {
1647
+ this.config.isDev && this.log("debug", t, e);
1648
+ }
1649
+ /**
1650
+ * Log at INFO level.
1651
+ */
1652
+ info(t, e) {
1653
+ this.log("info", t, e);
1654
+ }
1655
+ /**
1656
+ * Log at WARN level.
1657
+ */
1658
+ warn(t, e) {
1659
+ this.log("warn", t, e);
1660
+ }
1661
+ /**
1662
+ * Log at ERROR level.
1663
+ */
1664
+ error(t, e) {
1665
+ this.log("error", t, e);
1666
+ }
1667
+ }
1668
+ function yt(n, t) {
1669
+ const e = t?.isDev !== void 0 ? t.isDev : typeof process < "u" ? process.env.NODE_ENV !== "production" : !0;
1670
+ return new ni({ service: n, isDev: e, traceProvider: t?.traceProvider });
1671
+ }
1672
+ function O(n) {
1673
+ if (n !== void 0)
1674
+ return typeof n == "object" && n !== null && !Array.isArray(n) && !(n instanceof Error) ? n : n instanceof Error ? { error: n.message } : { value: n };
1675
+ }
1676
+ function _t(n) {
1677
+ return {
1678
+ debug: (t, e) => n.debug(t, O(e)),
1679
+ info: (t, e) => n.info(t, O(e)),
1680
+ warn: (t, e) => n.warn(t, O(e)),
1681
+ error: (t, e) => n.error(t, O(e))
1682
+ };
1683
+ }
1684
+ let wt = !1, w = _t(yt("client", { isDev: !1 }));
1685
+ function ii() {
1686
+ wt = !0, w = _t(yt("client", { isDev: !0 }));
1687
+ }
1688
+ function Gi() {
1689
+ return wt;
1690
+ }
1691
+ class oi {
1692
+ constructor(t, e) {
1693
+ this.send = t, this.onMutationFailed = e;
1694
+ }
1695
+ send;
1696
+ onMutationFailed;
1697
+ registry;
1698
+ pendingCallbacks = [];
1699
+ /**
1700
+ * Handle incoming MAPPING message from server
1701
+ */
1702
+ handleMappingReceived(t) {
1703
+ w.debug("Initializing from server mapping", {
1704
+ attributeCount: t.attributes.length
1705
+ }), this.registry = new Kn(
1706
+ t.attributes,
1707
+ (e, i) => this.sendMutation(e, i),
1708
+ this.onMutationFailed
1709
+ ), this.replayPendingCallbacks();
1710
+ }
1711
+ handleMutationResult(t) {
1712
+ this.registry?.handleResults(t.results);
1713
+ }
1714
+ /**
1715
+ * Select a value for an attribute - sends mutation to server.
1716
+ * Can be called before the mapping arrives — the mutation is sent immediately
1717
+ * and the messenger's publisher queue holds it until the iframe is ready.
1718
+ */
1719
+ select(t, e) {
1720
+ this.sendMutation([{ name: t, value: e }], !1);
1721
+ }
1722
+ getValues(t) {
1723
+ return this.registry?.get(t)?.getValues() ?? [];
1724
+ }
1725
+ getValue(t, e) {
1726
+ return this.registry?.get(t)?.getValue(e);
1727
+ }
1728
+ /**
1729
+ * Register onChange callback for an attribute.
1730
+ * Buffers the callback if the mapping hasn't arrived yet.
1731
+ */
1732
+ onChange(t, e) {
1733
+ if (this.registry === void 0) {
1734
+ this.pendingCallbacks.push({ name: t, callback: e });
1735
+ return;
1736
+ }
1737
+ const i = this.registry.get(t);
1738
+ if (i === void 0) {
1739
+ w.warn(`onChange: attribute "${t}" not found — callback will not fire`);
1740
+ return;
1741
+ }
1742
+ i.onChange(e);
1743
+ }
1744
+ getAttribute(t) {
1745
+ return this.registry?.get(t);
1746
+ }
1747
+ /** The current selection as attribute name→value pairs, empty before the mapping arrives. */
1748
+ getSelection() {
1749
+ return this.registry?.getSelection() ?? {};
1750
+ }
1751
+ get hasMapping() {
1752
+ return this.registry !== void 0;
1753
+ }
1754
+ sendMutation(t, e) {
1755
+ const i = {
1756
+ type: c.MUTATION,
1757
+ mutations: t,
1758
+ isInitial: e
1759
+ };
1760
+ this.send(i);
1761
+ }
1762
+ replayPendingCallbacks() {
1763
+ for (const { name: t, callback: e } of this.pendingCallbacks) {
1764
+ const i = this.registry?.get(t);
1765
+ i === void 0 && w.warn(`onChange: attribute "${t}" not found — buffered callback will not fire`), i?.onChange(e);
1766
+ }
1767
+ this.pendingCallbacks.length = 0;
1768
+ }
1769
+ }
1770
+ class si {
1771
+ constructor(t) {
1772
+ this.send = t;
1773
+ }
1774
+ send;
1775
+ commands = [];
1776
+ /**
1777
+ * Rotate camera horizontally
1778
+ * @param degrees - Absolute rotation in degrees (0 = front view)
1779
+ * @throws VirtualdisplayError if value is not a finite number
1780
+ */
1781
+ rotate(t) {
1782
+ return this.validateFiniteNumber(t, "rotate"), this.commands.push({ action: "rotate", value: t }), this;
1783
+ }
1784
+ /**
1785
+ * Tilt camera vertically
1786
+ * @param degrees - Absolute tilt in degrees (0 = top view, 90 = horizontal)
1787
+ * @throws VirtualdisplayError if value is not a finite number
1788
+ */
1789
+ tilt(t) {
1790
+ return this.validateFiniteNumber(t, "tilt"), this.commands.push({ action: "tilt", value: t }), this;
1791
+ }
1792
+ /**
1793
+ * Zoom camera
1794
+ * @param percentage - Zoom percentage (100 = normal, >100 = zoom in, <100 = zoom out)
1795
+ * @throws VirtualdisplayError if value is not a finite number
1796
+ */
1797
+ zoom(t) {
1798
+ return this.validateFiniteNumber(t, "zoom"), this.commands.push({ action: "zoom", value: t }), this;
1799
+ }
1800
+ /**
1801
+ * Execute accumulated camera commands
1802
+ * @throws VirtualdisplayError if no commands have been accumulated
1803
+ */
1804
+ set() {
1805
+ if (this.commands.length === 0)
1806
+ throw f.invalidParameter(
1807
+ "No camera commands to execute. Call rotate(), tilt(), or zoom() before set()."
1808
+ );
1809
+ const t = {
1810
+ type: c.CAMERA,
1811
+ commands: this.commands
1812
+ };
1813
+ this.send(t), this.commands = [];
1814
+ }
1815
+ validateFiniteNumber(t, e) {
1816
+ if (!Number.isFinite(t))
1817
+ throw f.invalidParameter(
1818
+ `${e}() requires a finite number, got ${String(t)}`
1819
+ );
1820
+ }
1821
+ /**
1822
+ * Reset camera to initial position
1823
+ * This is not chainable and executes immediately
1824
+ */
1825
+ reset() {
1826
+ const t = {
1827
+ type: c.CAMERA,
1828
+ commands: [{ action: "reset" }]
1829
+ };
1830
+ this.send(t);
1831
+ }
1832
+ }
1833
+ class ri {
1834
+ state;
1835
+ limitsState;
1836
+ changeCallbacks = [];
1837
+ constructor() {
1838
+ this.state = {
1839
+ rotation: 0,
1840
+ tilt: 0,
1841
+ zoom: 100
1842
+ };
1843
+ }
1844
+ /**
1845
+ * Get current rotation in degrees
1846
+ */
1847
+ get rotation() {
1848
+ return this.state.rotation;
1849
+ }
1850
+ /**
1851
+ * Get current tilt in degrees
1852
+ */
1853
+ get tilt() {
1854
+ return this.state.tilt;
1855
+ }
1856
+ /**
1857
+ * Get current zoom percentage
1858
+ */
1859
+ get zoom() {
1860
+ return this.state.zoom;
1861
+ }
1862
+ /**
1863
+ * Subscribe to camera position changes.
1864
+ * Also fires when limits are applied via applyLimits() so components
1865
+ * can re-evaluate disabled states without a separate callback.
1866
+ */
1867
+ onChange(t) {
1868
+ this.changeCallbacks.push(t);
1869
+ }
1870
+ /**
1871
+ * Current camera movement limits (set from CONFIG message).
1872
+ * Undefined until the server sends limits in its CONFIG payload.
1873
+ */
1874
+ get limits() {
1875
+ return this.limitsState;
1876
+ }
1877
+ /**
1878
+ * Apply camera limits received from the server CONFIG message.
1879
+ * Fires onChange callbacks so button disabled states update immediately.
1880
+ */
1881
+ applyLimits(t) {
1882
+ this.limitsState = t;
1883
+ const e = { rotation: this.rotation, tilt: this.tilt, zoom: this.zoom };
1884
+ for (const i of this.changeCallbacks)
1885
+ i(e);
1886
+ }
1887
+ /**
1888
+ * Handle incoming camera position message from server
1889
+ */
1890
+ handlePositionUpdate(t) {
1891
+ this.update(t.transforms);
1892
+ }
1893
+ /**
1894
+ * Update camera position from server transforms
1895
+ */
1896
+ update(t) {
1897
+ let e = !1;
1898
+ for (const i of t)
1899
+ switch (i.type) {
1900
+ case "rotation":
1901
+ this.state.rotation = i.value, e = !0;
1902
+ break;
1903
+ case "tilt":
1904
+ this.state.tilt = i.value, e = !0;
1905
+ break;
1906
+ case "zoom":
1907
+ this.state.zoom = i.value, e = !0;
1908
+ break;
1909
+ }
1910
+ if (e) {
1911
+ const i = {
1912
+ rotation: this.rotation,
1913
+ tilt: this.tilt,
1914
+ zoom: this.zoom
1915
+ };
1916
+ for (const o of this.changeCallbacks)
1917
+ o(i);
1918
+ }
1919
+ }
1920
+ }
1921
+ function ai(n, t) {
1922
+ const e = n.filter((s) => li(s, t));
1923
+ if (e.length === 0)
1924
+ return;
1925
+ const i = Math.max(...e.map(nt)), o = e.filter((s) => nt(s) === i);
1926
+ return o.length === 1 ? o[0] : void 0;
1927
+ }
1928
+ function li(n, t) {
1929
+ return Object.entries(n.attributes).every(([e, i]) => t[e] === i);
1930
+ }
1931
+ function nt(n) {
1932
+ return Object.keys(n.attributes).length;
1933
+ }
1934
+ class ci {
1935
+ constructor(t, e) {
1936
+ this.dispatchChange = t, this.dispatchSubmit = e;
1937
+ }
1938
+ dispatchChange;
1939
+ dispatchSubmit;
1940
+ pricing;
1941
+ selection = {};
1942
+ resolved;
1943
+ changeCallbacks = [];
1944
+ renderCallbacks = [];
1945
+ submitCallback;
1946
+ submitDefaultLabel;
1947
+ /** The resolved configuration, or undefined when nothing matches. */
1948
+ get current() {
1949
+ return this.resolved;
1950
+ }
1951
+ /** The VAT label for bare embeds (e.g. "incl. btw"), or undefined without pricing. */
1952
+ get vatDisplay() {
1953
+ return this.pricing?.vatDisplay;
1954
+ }
1955
+ /**
1956
+ * The CTA label: the customer's `button_label`, or the adapter's `defaultLabel`
1957
+ * when that is empty. Undefined when neither is set — a button must know what
1958
+ * it says, so the CTA does not render.
1959
+ */
1960
+ get buttonLabel() {
1961
+ const t = this.pricing?.buttonLabel;
1962
+ if (t != null && t !== "")
1963
+ return t;
1964
+ if (this.submitDefaultLabel !== void 0 && this.submitDefaultLabel !== "")
1965
+ return this.submitDefaultLabel;
1966
+ }
1967
+ /**
1968
+ * Whether the current configuration may be submitted: a handler is registered
1969
+ * and the configuration is either price-less or an `available` priced one. The
1970
+ * CTA's visibility ({@link submitEnabled}) layers a label requirement on top of
1971
+ * this; a programmatic `submit()` does not need a label.
1972
+ */
1973
+ get submittable() {
1974
+ return this.submitCallback === void 0 ? !1 : this.pricing === void 0 ? !0 : this.resolved?.availability === "available";
1975
+ }
1976
+ /**
1977
+ * Whether the CTA should render: the configuration is submittable and a label
1978
+ * exists. A button must say something, so an empty label hides the CTA rather
1979
+ * than rendering blank.
1980
+ */
1981
+ get submitEnabled() {
1982
+ return this.submittable && this.buttonLabel !== void 0;
1983
+ }
1984
+ /**
1985
+ * Subscribe to configuration changes. Fires after every selection change with
1986
+ * the resolved configuration, including undefined when nothing matches.
1987
+ */
1988
+ onChange(t) {
1989
+ this.changeCallbacks.push(t);
1990
+ }
1991
+ /**
1992
+ * Register the submit handler the CTA hands the configuration to. Registering
1993
+ * one is what switches the button on (capability driven). `defaultLabel` fills
1994
+ * in when the customer authored no button label.
1995
+ */
1996
+ onSubmit(t, e) {
1997
+ this.submitCallback = t, this.submitDefaultLabel = e?.defaultLabel, this.notifyRender();
1998
+ }
1999
+ /**
2000
+ * Subscribe the built-in UI to re-render the price + CTA. Fires on every
2001
+ * resolve and when a submit handler is registered (which can switch the button
2002
+ * on without a configuration change). Separate from `onChange`, which stays the
2003
+ * host-facing, mutation-driven contract. Returns a disposer.
2004
+ */
2005
+ onRender(t) {
2006
+ return this.renderCallbacks.push(t), () => {
2007
+ const e = this.renderCallbacks.indexOf(t);
2008
+ e !== -1 && this.renderCallbacks.splice(e, 1);
2009
+ };
2010
+ }
2011
+ /**
2012
+ * Hand the current configuration to the registered handler and fire the
2013
+ * bubbling `vd:configuration-submit` event. No-op without a handler or a
2014
+ * resolved configuration. Returns the handler's promise so the caller can
2015
+ * reflect the result (bezig / gelukt / mislukt).
2016
+ */
2017
+ async submit() {
2018
+ if (!this.submittable)
2019
+ return;
2020
+ const t = this.resolved !== void 0 ? { attributes: this.resolved.attributes, reference: this.resolved.reference } : { attributes: { ...this.selection }, reference: "" };
2021
+ this.dispatchSubmit(t), await this.submitCallback?.(t);
2022
+ }
2023
+ /** Called by the client when a PRICING message arrives from the viewer. */
2024
+ handlePricingReceived(t) {
2025
+ this.pricing = t, this.recompute();
2026
+ }
2027
+ /** Called by the client after every mutation result, with the full selection. */
2028
+ handleSelectionChanged(t) {
2029
+ this.selection = t, this.recompute();
2030
+ }
2031
+ recompute() {
2032
+ this.resolved = this.resolve();
2033
+ for (const t of this.changeCallbacks)
2034
+ t(this.resolved);
2035
+ this.dispatchChange(this.resolved), this.notifyRender();
2036
+ }
2037
+ notifyRender() {
2038
+ for (const t of this.renderCallbacks)
2039
+ t();
2040
+ }
2041
+ resolve() {
2042
+ if (this.pricing === void 0)
2043
+ return;
2044
+ const t = ai(this.pricing.rules, this.selection);
2045
+ if (!(t === void 0 || t.availability === St.HIDDEN))
2046
+ return {
2047
+ attributes: { ...this.selection },
2048
+ reference: t.reference,
2049
+ price: t.priceCents,
2050
+ currency: this.pricing.currency,
2051
+ availability: t.availability
2052
+ };
2053
+ }
2054
+ }
2055
+ class ui {
2056
+ constructor(t, e) {
2057
+ this.send = t, this.dispatch = e;
2058
+ }
2059
+ send;
2060
+ dispatch;
2061
+ focused = null;
2062
+ attributes = [];
2063
+ changeCallbacks = [];
2064
+ /** The focused component name, or null in overview. */
2065
+ get current() {
2066
+ return this.focused;
2067
+ }
2068
+ /**
2069
+ * Focus a component by name. Sends a focus message to the viewer.
2070
+ * @throws VirtualdisplayError if component is not a non-empty string
2071
+ */
2072
+ set(t) {
2073
+ if (typeof t != "string" || t.length === 0)
2074
+ throw f.invalidParameter(
2075
+ `set() requires a non-empty component name, got ${String(t)}`
2076
+ );
2077
+ this.send({ type: c.FOCUS, action: Y.FOCUS, component: t });
2078
+ }
2079
+ /** Return to the overview — unfocus the current component. */
2080
+ clear() {
2081
+ this.send({ type: c.FOCUS, action: Y.UNFOCUS });
2082
+ }
2083
+ /**
2084
+ * Subscribe to focus changes. The callback fires with the focus state when a
2085
+ * component is focused, and with null when returning to overview.
2086
+ */
2087
+ onChange(t) {
2088
+ this.changeCallbacks.push(t);
2089
+ }
2090
+ /** Called by the client when a FocusStateMessage is received from the viewer. */
2091
+ handleStateReceived(t) {
2092
+ t.state === kt.FOCUSED && t.component !== void 0 ? (this.focused = t.component, this.attributes = t.attributes ?? []) : (this.focused = null, this.attributes = []);
2093
+ const e = this.focused !== null ? { component: this.focused, attributes: this.attributes } : null;
2094
+ for (const i of this.changeCallbacks)
2095
+ i(e);
2096
+ this.dispatch(e);
2097
+ }
2098
+ }
2099
+ class di {
2100
+ constructor(t) {
2101
+ this.filename = t;
2102
+ }
2103
+ filename;
2104
+ developedCallbacks = /* @__PURE__ */ new Set();
2105
+ errorCallbacks = /* @__PURE__ */ new Set();
2106
+ developed = !1;
2107
+ failed = !1;
2108
+ photoData = null;
2109
+ /**
2110
+ * Register a callback for when the photo is developed
2111
+ * If the photo is already developed, the callback is called immediately
2112
+ *
2113
+ * @param callback Function to call with photo data
2114
+ * @returns This Photo instance for chaining
2115
+ */
2116
+ onDeveloped(t) {
2117
+ return this.developed && this.photoData !== null ? (t(this.photoData), this) : (this.developedCallbacks.add(t), this);
2118
+ }
2119
+ /**
2120
+ * Register a callback for when the photo capture fails
2121
+ *
2122
+ * @param callback Function to call with error
2123
+ * @returns This Photo instance for chaining
2124
+ */
2125
+ onError(t) {
2126
+ return this.errorCallbacks.add(t), this;
2127
+ }
2128
+ /**
2129
+ * Get the filename for this photo
2130
+ */
2131
+ getFilename() {
2132
+ return this.filename;
2133
+ }
2134
+ /**
2135
+ * Mark the photo as developed and notify all callbacks
2136
+ * This method is called by Snapshot when the photo data arrives from the server
2137
+ */
2138
+ develop(t) {
2139
+ this.developed || this.failed || (this.photoData = t, this.developed = !0, this.developedCallbacks.forEach((e) => {
2140
+ e(this.photoData);
2141
+ }), this.developedCallbacks.clear(), this.errorCallbacks.clear());
2142
+ }
2143
+ /**
2144
+ * Mark the photo as failed and notify error callbacks
2145
+ */
2146
+ fail(t) {
2147
+ this.developed || this.failed || (this.failed = !0, this.errorCallbacks.forEach((e) => {
2148
+ e(t);
2149
+ }), this.developedCallbacks.clear(), this.errorCallbacks.clear());
2150
+ }
2151
+ }
2152
+ const it = 3e4;
2153
+ class hi {
2154
+ constructor(t) {
2155
+ this.send = t;
2156
+ }
2157
+ send;
2158
+ validExtensions = [".png"];
2159
+ pendingPhotos = /* @__PURE__ */ new Map();
2160
+ /**
2161
+ * Take a snapshot of the current 3D model view
2162
+ *
2163
+ * @param filename The filename for the snapshot (must include valid extension)
2164
+ * @returns Photo object for registering callbacks
2165
+ * @throws VirtualdisplayError if filename is invalid
2166
+ */
2167
+ take(t) {
2168
+ this.validateFilename(t), w.debug("Taking snapshot", { filename: t });
2169
+ const e = new di(t), i = setTimeout(() => {
2170
+ this.pendingPhotos.delete(t), w.warn("Snapshot timed out", { filename: t }), e.fail(new f(
2171
+ `Snapshot timed out: the viewer did not respond within ${it}ms`,
2172
+ E.SNAPSHOT_FAILED
2173
+ ));
2174
+ }, it);
2175
+ return this.pendingPhotos.set(t, { photo: e, timeout: i }), this.send({
2176
+ type: c.SNAPSHOT,
2177
+ filename: t
2178
+ }), e;
2179
+ }
2180
+ /**
2181
+ * Handle incoming snapshot result from server
2182
+ * Matches the message to a pending photo by filename, then develops or fails it
2183
+ */
2184
+ handleSnapshotResult(t) {
2185
+ const e = this.pendingPhotos.get(t.filename);
2186
+ if (e === void 0) {
2187
+ w.warn("No pending photo found for filename", {
2188
+ filename: t.filename,
2189
+ pendingFilenames: Array.from(this.pendingPhotos.keys())
2190
+ });
2191
+ return;
2192
+ }
2193
+ clearTimeout(e.timeout), this.pendingPhotos.delete(t.filename);
2194
+ const { photo: i } = e;
2195
+ if (t.error !== void 0) {
2196
+ i.fail(new f(t.error, E.SNAPSHOT_FAILED));
2197
+ return;
2198
+ }
2199
+ t.data !== void 0 && i.develop({ filename: t.filename, data: t.data });
2200
+ }
2201
+ /**
2202
+ * Fail any pending photos and forget them. Called from client destroy
2203
+ * so callers awaiting onError() see a deterministic outcome instead of
2204
+ * leaking captures whose results will never arrive.
2205
+ */
2206
+ clear() {
2207
+ if (this.pendingPhotos.size === 0)
2208
+ return;
2209
+ const t = new f(
2210
+ "Client destroyed before snapshot completed",
2211
+ E.SNAPSHOT_FAILED
2212
+ );
2213
+ for (const { photo: e, timeout: i } of this.pendingPhotos.values())
2214
+ clearTimeout(i), e.fail(t);
2215
+ this.pendingPhotos.clear();
2216
+ }
2217
+ /**
2218
+ * Validate filename has a valid image extension
2219
+ */
2220
+ validateFilename(t) {
2221
+ if (t === "" || typeof t != "string")
2222
+ throw new f(
2223
+ "Filename must be a non-empty string",
2224
+ E.INVALID_PARAMETER
2225
+ );
2226
+ if (!this.validExtensions.some(
2227
+ (i) => t.toLowerCase().endsWith(i)
2228
+ ))
2229
+ throw new f(
2230
+ `Invalid filename: "${t}". Filename must end with one of: ${this.validExtensions.join(", ")}`,
2231
+ E.INVALID_PARAMETER
2232
+ );
2233
+ if (t.includes("..") || t.includes("/") || t.includes("\\"))
2234
+ throw new f(
2235
+ 'Filename cannot contain path separators or ".."',
2236
+ E.INVALID_PARAMETER
2237
+ );
2238
+ }
2239
+ }
2240
+ class mi {
2241
+ container = null;
2242
+ attach(t) {
2243
+ this.container = t;
2244
+ }
2245
+ dispatch(t, e, i = !1) {
2246
+ const o = new CustomEvent(t, { detail: e, cancelable: i });
2247
+ return this.container?.dispatchEvent(o), o;
2248
+ }
2249
+ on(t, e) {
2250
+ const i = (o) => {
2251
+ const s = o, r = { ...s.detail, preventDefault: () => {
2252
+ s.preventDefault();
2253
+ } };
2254
+ e(r);
2255
+ };
2256
+ return this.container?.addEventListener(t, i), () => {
2257
+ this.container?.removeEventListener(t, i);
2258
+ };
2259
+ }
2260
+ }
2261
+ function y(n, { size: t = 20, strokeWidth: e = 1.75 } = {}) {
2262
+ return ct(n, { width: t, height: t, "stroke-width": e });
2263
+ }
2264
+ const b = {
2265
+ ar: (n) => y(Dt, n),
2266
+ fullscreen: (n) => y(Ht, n),
2267
+ exitFullscreen: (n) => y(Gt, n),
2268
+ screenshot: (n) => y(Bt, n),
2269
+ tiltUp: (n) => y(jt, n),
2270
+ tiltDown: (n) => y(ut, n),
2271
+ rotateLeft: (n) => y(Ut, n),
2272
+ rotateRight: (n) => y(Vt, n),
2273
+ zoomIn: (n) => y(Yt, n),
2274
+ zoomOut: (n) => y(Xt, n),
2275
+ reset: (n) => y(qt, n),
2276
+ configurator: (n) => y(Zt, n),
2277
+ close: (n) => y(Wt, n)
2278
+ };
2279
+ function ot(n) {
2280
+ const t = Math.max(0, Math.min(1, n));
2281
+ return t * t * (3 - 2 * t);
2282
+ }
2283
+ function pi(n, t, e, i, o, s) {
2284
+ const [r, l, d] = n, u = Math.cos(t), p = Math.sin(t), v = u * r + p * d, A = -p * r + u * d, S = Math.cos(e), C = Math.sin(e), R = S * l - C * A, M = C * l + S * A, W = 0.55;
2285
+ return [i + v * s * W, o - R * s * W, M];
2286
+ }
2287
+ function fi(n, t, e) {
2288
+ n.beginPath(), n.moveTo(t[0], t[1]), n.lineTo(e[0], e[1]), n.strokeStyle = "#000", n.lineWidth = 2, n.stroke();
2289
+ }
2290
+ function gi(n, t, e, i, o) {
2291
+ const s = t(e), r = t(i), l = [
2292
+ s[0] + (r[0] - s[0]) * o,
2293
+ s[1] + (r[1] - s[1]) * o,
2294
+ s[2]
2295
+ ];
2296
+ fi(n, s, l);
2297
+ }
2298
+ const z = [-1, -1, 1], F = [1, -1, 1], P = [1, -1, -1], $ = [-1, -1, -1], D = [-1, 1, 1], B = [1, 1, 1], U = [1, 1, -1], V = [-1, 1, -1], st = [
2299
+ [z, F],
2300
+ [F, P],
2301
+ [P, $],
2302
+ [$, z],
2303
+ [z, D],
2304
+ [F, B],
2305
+ [P, U],
2306
+ [$, V],
2307
+ [D, B],
2308
+ [B, U],
2309
+ [U, V],
2310
+ [V, D]
2311
+ ], bi = 400, rt = '-apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif';
2312
+ function vi() {
2313
+ const n = document.createElement("div");
2314
+ Object.assign(n.style, {
2315
+ position: "absolute",
2316
+ inset: "0",
2317
+ display: "flex",
2318
+ flexDirection: "column",
2319
+ alignItems: "center",
2320
+ justifyContent: "center",
2321
+ background: "#fff",
2322
+ zIndex: "20",
2323
+ opacity: "0",
2324
+ transition: "opacity 0.3s ease-in-out"
2325
+ });
2326
+ const t = document.createElement("canvas");
2327
+ Object.assign(t.style, {
2328
+ width: "100%",
2329
+ height: "100%",
2330
+ position: "absolute",
2331
+ inset: "0"
2332
+ });
2333
+ const e = document.createElement("div");
2334
+ Object.assign(e.style, {
2335
+ position: "absolute",
2336
+ top: "56%",
2337
+ left: "0",
2338
+ right: "0",
2339
+ textAlign: "center",
2340
+ pointerEvents: "none"
2341
+ });
2342
+ const i = document.createElement("span");
2343
+ Object.assign(i.style, {
2344
+ fontSize: "13px",
2345
+ fontWeight: "400",
2346
+ color: "#000",
2347
+ fontVariantNumeric: "tabular-nums",
2348
+ fontFamily: rt
2349
+ });
2350
+ const o = document.createElement("span");
2351
+ return Object.assign(o.style, {
2352
+ fontSize: "13px",
2353
+ color: "#000",
2354
+ fontFamily: rt
2355
+ }), o.textContent = gt(), e.appendChild(i), e.appendChild(o), n.appendChild(t), n.appendChild(e), { overlay: n, canvas: t, pctEl: i, phaseEl: o };
2356
+ }
2357
+ class yi {
2358
+ overlay;
2359
+ canvas;
2360
+ ctx;
2361
+ pctEl;
2362
+ phaseEl;
2363
+ animationId = null;
2364
+ showTimerId = null;
2365
+ startTime;
2366
+ hidden = !1;
2367
+ visible = !1;
2368
+ constructor(t, e = {}) {
2369
+ this.startTime = performance.now();
2370
+ const i = vi();
2371
+ this.overlay = i.overlay, this.canvas = i.canvas, this.pctEl = i.pctEl, this.phaseEl = i.phaseEl, t.appendChild(this.overlay), this.ctx = this.canvas.getContext("2d"), this.ctx !== null && (this.sizeCanvas(), this.tick());
2372
+ const o = e.showDelay ?? bi;
2373
+ this.showTimerId = setTimeout(() => {
2374
+ this.reveal();
2375
+ }, o);
2376
+ }
2377
+ get loadingTexts() {
2378
+ return {
2379
+ downloading: gt(),
2380
+ rendering: Pe()
2381
+ };
2382
+ }
2383
+ updateProgress(t, e) {
2384
+ this.hidden || (this.pctEl.textContent = `${Math.round(t)}%`, this.phaseEl.textContent = e !== "" ? ` · ${e}` : "");
2385
+ }
2386
+ /**
2387
+ * Show an error state — stops animation and displays the error message.
2388
+ * The overlay stays visible so the user knows something went wrong.
2389
+ */
2390
+ showError(t) {
2391
+ if (this.hidden = !1, this.animationId !== null && (cancelAnimationFrame(this.animationId), this.animationId = null), this.ctx !== null) {
2392
+ const e = Math.min(devicePixelRatio, 2), i = this.canvas.width / e, o = this.canvas.height / e;
2393
+ this.ctx.fillStyle = "#fff", this.ctx.fillRect(0, 0, i * e, o * e);
2394
+ }
2395
+ this.pctEl.textContent = "", this.phaseEl.textContent = t, this.phaseEl.style.color = "#b91c1c", this.reveal();
2396
+ }
2397
+ hide() {
2398
+ if (!this.hidden) {
2399
+ if (this.hidden = !0, this.cancelShowTimer(), !this.visible) {
2400
+ this.destroy();
2401
+ return;
2402
+ }
2403
+ this.overlay.style.opacity = "0", this.overlay.addEventListener("transitionend", () => {
2404
+ this.destroy();
2405
+ }, { once: !0 }), setTimeout(() => {
2406
+ this.destroy();
2407
+ }, 500);
2408
+ }
2409
+ }
2410
+ destroy() {
2411
+ this.cancelShowTimer(), this.animationId !== null && (cancelAnimationFrame(this.animationId), this.animationId = null), this.overlay.remove();
2412
+ }
2413
+ reveal() {
2414
+ this.hidden || this.visible || (this.visible = !0, this.overlay.style.opacity = "1");
2415
+ }
2416
+ cancelShowTimer() {
2417
+ this.showTimerId !== null && (clearTimeout(this.showTimerId), this.showTimerId = null);
2418
+ }
2419
+ sizeCanvas() {
2420
+ if (this.ctx === null)
2421
+ return;
2422
+ const t = Math.min(devicePixelRatio, 2), e = this.overlay.clientWidth || 440, i = this.overlay.clientHeight || 360;
2423
+ this.canvas.width = e * t, this.canvas.height = i * t, this.ctx.scale(t, t), this.ctx.lineCap = "round", this.ctx.lineJoin = "round";
2424
+ }
2425
+ tick = () => {
2426
+ this.hidden || (this.drawFrame(), this.animationId = requestAnimationFrame(this.tick));
2427
+ };
2428
+ drawFrame() {
2429
+ if (this.ctx === null)
2430
+ return;
2431
+ const t = this.canvas.width / Math.min(devicePixelRatio, 2), e = this.canvas.height / Math.min(devicePixelRatio, 2), i = (performance.now() - this.startTime) / 1e3;
2432
+ this.ctx.fillStyle = "#fff", this.ctx.fillRect(0, 0, t, e);
2433
+ const o = t / 2, s = e * 0.44, r = Math.min(t, e) * 0.08, l = 0.785, d = 0.615, u = (C) => pi(C, l, d, o, s, r), p = 6, v = i % p / p, A = st.length;
2434
+ let S;
2435
+ v < 0.35 ? S = ot(v / 0.35) * A : v < 0.55 ? S = A : v < 0.9 ? S = (1 - ot((v - 0.55) / 0.35)) * A : S = 0, this.ctx.shadowBlur = 5, this.ctx.shadowColor = "rgba(30,30,30,0.08)";
2436
+ for (let C = 0; C < A && !(C >= S); C++) {
2437
+ const R = st[C];
2438
+ if (R === void 0)
2439
+ continue;
2440
+ const M = Math.min(1, S - C);
2441
+ gi(this.ctx, u, R[0], R[1], M);
2442
+ }
2443
+ this.ctx.shadowBlur = 0;
2444
+ }
2445
+ }
2446
+ class _i {
2447
+ constructor(t) {
2448
+ this.options = t, this.element = document.createElement("div"), Object.assign(this.element.style, { display: "flex", gap: "0.375rem" }), this.onFullscreenChange = () => {
2449
+ this.setFullscreenIcon(document.fullscreenElement !== null);
2450
+ }, document.addEventListener("fullscreenchange", this.onFullscreenChange);
2451
+ }
2452
+ options;
2453
+ element;
2454
+ arBtn = null;
2455
+ fullscreenBtn = null;
2456
+ onFullscreenChange;
2457
+ setFullscreenIcon(t) {
2458
+ this.fullscreenBtn !== null && this.fullscreenBtn.setIcon(t ? b.exitFullscreen() : b.fullscreen());
2459
+ }
2460
+ syncButton(t, e, i) {
2461
+ if (e && t === null) {
2462
+ const o = i();
2463
+ return this.element.appendChild(o.element), o;
2464
+ }
2465
+ return !e && t !== null ? (t.element.remove(), null) : t;
2466
+ }
2467
+ applySettings(t) {
2468
+ this.arBtn = this.syncButton(this.arBtn, t.ar !== !1 && this.options.onAr !== void 0, () => new g({
2469
+ variant: "outline",
2470
+ size: "icon",
2471
+ label: ue(),
2472
+ icon: b.ar(),
2473
+ onClick: () => {
2474
+ this.options.onAr?.();
2475
+ }
2476
+ })), this.fullscreenBtn = this.syncButton(this.fullscreenBtn, t.fullscreen !== !1 && this.options.onFullscreen !== void 0, () => new g({
2477
+ variant: "outline",
2478
+ size: "icon",
2479
+ label: Ie(),
2480
+ icon: b.fullscreen(),
2481
+ onClick: () => {
2482
+ this.options.onFullscreen?.();
2483
+ }
2484
+ }));
2485
+ }
2486
+ destroy() {
2487
+ document.removeEventListener("fullscreenchange", this.onFullscreenChange);
2488
+ }
2489
+ }
2490
+ const T = 0.5;
2491
+ class L {
2492
+ element;
2493
+ constructor(t, e) {
2494
+ this.element = Object.assign(document.createElement("div"), { className: "vd-camera-controls" });
2495
+ const i = {
2496
+ targetRotation: e.rotation,
2497
+ targetTilt: e.tilt,
2498
+ targetZoom: e.zoom,
2499
+ thetaOffset: 0
2500
+ }, o = wi(t, e, i);
2501
+ e.onChange((s) => {
2502
+ i.targetRotation = s.rotation - i.thetaOffset, i.targetTilt = s.tilt, i.targetZoom = s.zoom, Ci(o, e, s);
2503
+ }), this.element.appendChild(L.buildZoom(o.zoomOut, o.zoomIn)), this.element.appendChild(L.buildDpad(o.tiltUp, o.rotateLeft, o.reset, o.rotateRight, o.tiltDown));
2504
+ }
2505
+ static buildZoom(t, e) {
2506
+ const i = document.createElement("div");
2507
+ return i.className = "vd-zoom", i.appendChild(t.element), i.appendChild(e.element), i;
2508
+ }
2509
+ static buildDpad(t, e, i, o, s) {
2510
+ const r = document.createElement("div");
2511
+ r.className = "vd-dpad";
2512
+ for (const [l, d] of [
2513
+ [t, "up"],
2514
+ [e, "left"],
2515
+ [i, "center"],
2516
+ [o, "right"],
2517
+ [s, "down"]
2518
+ ])
2519
+ l.element.classList.add(`vd-dpad-${d}`), r.appendChild(l.element);
2520
+ return r;
2521
+ }
2522
+ }
2523
+ function wi(n, t, e) {
2524
+ const i = (r) => Math.max(t.limits?.minZoom ?? 1, Math.min(t.limits?.maxZoom ?? 1 / 0, r)), o = (r) => {
2525
+ const l = t.limits?.minRotate, d = t.limits?.maxRotate;
2526
+ return l !== void 0 || d !== void 0 ? Math.max(l ?? -1 / 0, Math.min(d ?? 1 / 0, r)) : r;
2527
+ }, s = (r) => {
2528
+ const l = t.limits?.minTilt, d = t.limits?.maxTilt;
2529
+ if (l !== void 0 || d !== void 0) {
2530
+ e.targetTilt = Math.max(l ?? 0, Math.min(d ?? 180, e.targetTilt + r)), n.tilt(e.targetTilt).set();
2531
+ return;
2532
+ }
2533
+ const u = e.targetTilt + r;
2534
+ u > 180 || u < 0 ? (e.targetTilt = u > 180 ? 360 - u : -u, e.thetaOffset = (e.thetaOffset + 180) % 360, n.tilt(e.targetTilt).rotate(e.targetRotation + e.thetaOffset).set()) : (e.targetTilt = u, n.tilt(e.targetTilt).set());
2535
+ };
2536
+ return {
2537
+ zoomOut: new g({ variant: "outline", size: "icon", label: ln(), icon: b.zoomOut(), onClick: () => {
2538
+ e.targetZoom = i(e.targetZoom - 10), n.zoom(e.targetZoom).set();
2539
+ } }),
2540
+ zoomIn: new g({ variant: "outline", size: "icon", label: on(), icon: b.zoomIn(), onClick: () => {
2541
+ e.targetZoom = i(e.targetZoom + 10), n.zoom(e.targetZoom).set();
2542
+ } }),
2543
+ tiltUp: new g({ variant: "outline", size: "icon", label: _n(), icon: b.tiltUp(), onClick: () => {
2544
+ s(-15);
2545
+ } }),
2546
+ rotateLeft: new g({ variant: "outline", size: "icon", label: hn(), icon: b.rotateLeft(), onClick: () => {
2547
+ e.targetRotation = o(e.targetRotation - 15), n.rotate(e.targetRotation + e.thetaOffset).set();
2548
+ } }),
2549
+ reset: new g({ variant: "outline", size: "icon", label: Je(), icon: b.reset(), onClick: () => {
2550
+ e.thetaOffset = 0, n.reset();
2551
+ } }),
2552
+ rotateRight: new g({ variant: "outline", size: "icon", label: gn(), icon: b.rotateRight(), onClick: () => {
2553
+ e.targetRotation = o(e.targetRotation + 15), n.rotate(e.targetRotation + e.thetaOffset).set();
2554
+ } }),
2555
+ tiltDown: new g({ variant: "outline", size: "icon", label: Sn(), icon: b.tiltDown(), onClick: () => {
2556
+ s(15);
2557
+ } })
2558
+ };
2559
+ }
2560
+ function Ci(n, t, e) {
2561
+ const i = t.limits;
2562
+ i !== void 0 && (n.zoomOut.element.disabled = i.minZoom !== void 0 && e.zoom <= i.minZoom + T, n.zoomIn.element.disabled = i.maxZoom !== void 0 && e.zoom >= i.maxZoom - T, n.tiltUp.element.disabled = i.minTilt !== void 0 && e.tilt <= i.minTilt + T, n.tiltDown.element.disabled = i.maxTilt !== void 0 && e.tilt >= i.maxTilt - T, n.rotateLeft.element.disabled = i.minRotate !== void 0 && e.rotation <= i.minRotate + T, n.rotateRight.element.disabled = i.maxRotate !== void 0 && e.rotation >= i.maxRotate - T);
2563
+ }
2564
+ const I = {
2565
+ /** Attribute selection requested (cancelable). `detail`: `{ attribute, value }`. */
2566
+ SELECT: "ui:select",
2567
+ /** Attribute selection applied. `detail`: `{ attribute, value }`. */
2568
+ SELECTED: "ui:selected",
2569
+ /** Focus changed (bubbles). `detail`: `{ component, attributes }`, or `null` for the overview. */
2570
+ FOCUS_CHANGE: "vd:focus-change",
2571
+ /** Resolved configuration changed (bubbles). `detail`: the resolved configuration, or `null` when nothing matches. */
2572
+ CONFIGURATION_CHANGE: "vd:configuration-change",
2573
+ /** Configuration submitted (bubbles). `detail`: the resolved configuration handed to the host. */
2574
+ CONFIGURATION_SUBMIT: "vd:configuration-submit"
2575
+ }, ki = 5;
2576
+ let Si = 0;
2577
+ function j(n) {
2578
+ const t = n.replace(/([A-Z])/g, " $1").trim();
2579
+ return t.charAt(0).toUpperCase() + t.slice(1).toLowerCase();
2580
+ }
2581
+ function Ei(n, t, e, i, o) {
2582
+ const s = document.createElement("div");
2583
+ s.className = "vd-attribute", s.dataset.name = n.name;
2584
+ const r = document.createElement("span");
2585
+ r.className = "vd-attribute-label", r.textContent = j(n.name), r.id = `vd-attribute-label-${Si++}`, s.appendChild(r), s.setAttribute("role", "group"), s.setAttribute("aria-labelledby", r.id);
2586
+ const l = n.values.find((p) => t.getValue(n.name, p)?.isSelected === !0), d = n.values.map(j), u = n.values.length <= ki ? new Jt(n.values, l, d) : new te(n.name, n.values, j(n.name), l, d);
2587
+ return u.onSelect((p) => {
2588
+ e.dispatch(I.SELECT, { attribute: n.name, value: p }, !0).defaultPrevented || i(n.name, p);
2589
+ }), o(n.name, (p) => {
2590
+ u.setSelected(p.value), e.dispatch(I.SELECTED, { attribute: n.name, value: p.value });
2591
+ }), s.appendChild(u.element), s;
2592
+ }
2593
+ const Ai = 80, xi = 2500;
2594
+ class Ti {
2595
+ constructor(t, e = xi) {
2596
+ this.configuration = t, this.resetMs = e, this.element = document.createElement("div"), this.element.className = "vd-commerce vd-hidden";
2597
+ const i = document.createElement("div");
2598
+ i.className = "vd-commerce-price", this.priceEl = document.createElement("span"), this.priceEl.className = "vd-price", this.vatEl = document.createElement("span"), this.vatEl.className = "vd-vat", i.append(this.priceEl, this.vatEl), this.button = new g({ variant: "default", onClick: () => {
2599
+ this.handleSubmit();
2600
+ } }), this.button.element.classList.add("vd-cta", "vd-hidden"), this.element.append(i, this.button.element), this.unsubscribe = this.configuration.onRender(() => {
2601
+ this.update();
2602
+ }), this.update();
2603
+ }
2604
+ configuration;
2605
+ resetMs;
2606
+ element;
2607
+ priceEl;
2608
+ vatEl;
2609
+ button;
2610
+ unsubscribe;
2611
+ state = "idle";
2612
+ resetTimer;
2613
+ /** Re-render from the facade. Called on every resolve and on submit-handler registration. */
2614
+ update() {
2615
+ this.renderPrice(this.configuration.current), this.renderButton();
2616
+ const t = this.configuration.current !== void 0 || this.configuration.submitEnabled;
2617
+ this.element.classList.toggle("vd-hidden", !t);
2618
+ }
2619
+ destroy() {
2620
+ this.unsubscribe(), this.resetTimer !== void 0 && clearTimeout(this.resetTimer), this.element.remove();
2621
+ }
2622
+ renderPrice(t) {
2623
+ if (t === void 0) {
2624
+ this.priceEl.textContent = "", this.vatEl.textContent = "";
2625
+ return;
2626
+ }
2627
+ this.priceEl.textContent = Ri(t.price, t.currency), this.vatEl.textContent = at(this.configuration.vatDisplay);
2628
+ }
2629
+ renderButton() {
2630
+ const t = this.configuration.submitEnabled;
2631
+ this.button.element.classList.toggle("vd-hidden", !t), t && this.state === "idle" && this.setButtonText(at(this.configuration.buttonLabel));
2632
+ }
2633
+ async handleSubmit() {
2634
+ if (this.state !== "busy") {
2635
+ this.setState("busy", Tn());
2636
+ try {
2637
+ await this.configuration.submit(), this.setState("success", Nn());
2638
+ } catch {
2639
+ this.setState("failed", Fn());
2640
+ }
2641
+ this.scheduleReset();
2642
+ }
2643
+ }
2644
+ scheduleReset() {
2645
+ this.resetTimer !== void 0 && clearTimeout(this.resetTimer), this.resetTimer = setTimeout(() => {
2646
+ this.state = "idle", this.update();
2647
+ }, this.resetMs);
2648
+ }
2649
+ setState(t, e) {
2650
+ this.state = t, this.element.dataset.submit = t, this.button.element.disabled = t === "busy", this.setButtonText(e);
2651
+ }
2652
+ setButtonText(t) {
2653
+ this.button.element.textContent = t, this.button.element.setAttribute("aria-label", t);
2654
+ }
2655
+ }
2656
+ function at(n) {
2657
+ return (n ?? "").slice(0, Ai);
2658
+ }
2659
+ function Ri(n, t) {
2660
+ try {
2661
+ const e = new Intl.NumberFormat(h(), { style: "currency", currency: t }), i = e.resolvedOptions().maximumFractionDigits ?? 2;
2662
+ return e.format(n / 10 ** i);
2663
+ } catch {
2664
+ return `${t} ${(n / 100).toFixed(2)}`;
2665
+ }
2666
+ }
2667
+ class Ct {
2668
+ slot = null;
2669
+ panel = null;
2670
+ attach(t, e) {
2671
+ this.panel = e, e.style.display = "none", this.slot = document.createElement("div"), this.slot.className = "vd-slot-bottom-left", this.slot.appendChild(e), t.appendChild(this.slot);
2672
+ }
2673
+ setVisible(t) {
2674
+ this.panel !== null && (this.panel.style.display = t ? "flex" : "none");
2675
+ }
2676
+ destroy() {
2677
+ this.slot?.remove(), this.slot = null, this.panel = null;
2678
+ }
2679
+ }
2680
+ const Ii = 572;
2681
+ class Oi {
2682
+ element = null;
2683
+ body = null;
2684
+ openButton = null;
2685
+ closeButton = null;
2686
+ container = null;
2687
+ observer = null;
2688
+ collapsible = !1;
2689
+ expanded = !0;
2690
+ visible = !1;
2691
+ attach(t, e) {
2692
+ this.container = t, e.classList.add("vd-attributes-sidebar"), this.closeButton = new g({
2693
+ variant: "ghost",
2694
+ size: "icon-sm",
2695
+ label: Ye(),
2696
+ icon: b.close({ size: 18 }),
2697
+ onClick: () => {
2698
+ this.expanded = !1, this.render();
2699
+ }
2700
+ });
2701
+ const i = document.createElement("div");
2702
+ i.className = "vd-sidebar-header", i.appendChild(this.closeButton.element), this.body = document.createElement("div"), this.body.className = "vd-sidebar-body", this.body.appendChild(e), this.element = document.createElement("div"), this.element.className = "vd-sidebar vd-hidden", this.element.append(i, this.body), t.appendChild(this.element), this.openButton = new g({
2703
+ variant: "outline",
2704
+ size: "default",
2705
+ label: Ge(),
2706
+ icon: b.configurator({ size: 18 }),
2707
+ onClick: () => {
2708
+ this.expanded = !0, this.render();
2709
+ }
2710
+ }), this.openButton.element.classList.add("vd-configurator-toggle", "vd-hidden"), t.appendChild(this.openButton.element), this.observe();
2711
+ }
2712
+ setVisible(t) {
2713
+ this.visible = t, this.render();
2714
+ }
2715
+ destroy() {
2716
+ this.observer?.disconnect(), this.observer = null, this.openButton?.element.remove(), this.element?.remove(), this.container?.classList.remove("vd-layout-sidebar-right", "vd-layout-sidebar-collapsed"), this.container = null;
2717
+ }
2718
+ observe() {
2719
+ typeof ResizeObserver > "u" || this.container === null || (this.observer = new ResizeObserver((t) => {
2720
+ const e = t[0]?.contentRect.width ?? 0;
2721
+ this.setCollapsible(e > 0 && e < Ii);
2722
+ }), this.observer.observe(this.container));
2723
+ }
2724
+ setCollapsible(t) {
2725
+ t !== this.collapsible && (this.collapsible = t, this.expanded = !t, this.render());
2726
+ }
2727
+ render() {
2728
+ if (this.element === null || this.openButton === null || this.closeButton === null || this.container === null)
2729
+ return;
2730
+ const t = this.visible && this.expanded, e = this.visible && !this.expanded;
2731
+ this.element.classList.toggle("vd-hidden", !this.visible), this.element.classList.toggle("vd-sidebar-collapsed", e), this.openButton.element.classList.toggle("vd-hidden", !e), this.closeButton.element.style.display = this.collapsible ? "" : "none", this.container.classList.toggle("vd-layout-sidebar-right", t), this.container.classList.toggle("vd-layout-sidebar-collapsed", e);
2732
+ }
2733
+ }
2734
+ class Ni {
2735
+ attach(t, e) {
2736
+ }
2737
+ setVisible(t) {
2738
+ }
2739
+ destroy() {
2740
+ }
2741
+ }
2742
+ const Li = {
2743
+ "inframe-bottom-left": () => new Ct(),
2744
+ "sidebar-right": () => new Oi(),
2745
+ hidden: () => new Ni()
2746
+ };
2747
+ function Mi(n) {
2748
+ return (Li[n ?? ""] ?? (() => new Ct()))();
2749
+ }
2750
+ const H = _.fontFamily.sans.join(", "), G = `
2751
+ position: absolute;
2752
+ display: flex;
2753
+ z-index: 10;
2754
+ transition: inset-inline-end 0.18s ease;
2755
+ `, zi = `
2756
+ /* Override browser's default black fullscreen backdrop */
2757
+ .vd-container:fullscreen {
2758
+ background: oklch(100% 0 0);
2759
+ }
2760
+
2761
+ /* Layout slots — four corners */
2762
+ .vd-slot-top-right {
2763
+ ${G}
2764
+ inset-block-start: ${a[3]};
2765
+ inset-inline-end: ${a[3]};
2766
+ flex-direction: column;
2767
+ align-items: flex-end;
2768
+ gap: ${a[1.5]};
2769
+ }
2770
+
2771
+ .vd-slot-bottom-left {
2772
+ ${G}
2773
+ inset-block-end: ${a[3]};
2774
+ inset-inline-start: ${a[3]};
2775
+ flex-direction: column;
2776
+ align-items: flex-start;
2777
+ gap: ${a[1.5]};
2778
+ }
2779
+
2780
+ .vd-slot-bottom-right {
2781
+ ${G}
2782
+ inset-block-end: ${a[3]};
2783
+ inset-inline-end: ${a[3]};
2784
+ flex-direction: row;
2785
+ gap: ${a[1.5]};
2786
+ }
2787
+
2788
+ /* Component styles — no positioning */
2789
+ .vd-camera-controls {
2790
+ display: flex;
2791
+ flex-direction: column;
2792
+ gap: ${a[1]};
2793
+ background: color-mix(in oklch, ${m.white} 85%, transparent);
2794
+ backdrop-filter: blur(8px);
2795
+ border-radius: ${a[2]};
2796
+ padding: ${a[2]};
2797
+ }
2798
+
2799
+ .vd-zoom {
2800
+ display: flex;
2801
+ gap: ${a[0.5]};
2802
+ }
2803
+
2804
+ .vd-dpad {
2805
+ display: grid;
2806
+ grid-template-columns: repeat(3, ${a[9]});
2807
+ grid-template-rows: repeat(3, ${a[9]});
2808
+ gap: ${a[0.5]};
2809
+ }
2810
+
2811
+ .vd-dpad-up { grid-column: 2; grid-row: 1; }
2812
+ .vd-dpad-left { grid-column: 1; grid-row: 2; }
2813
+ .vd-dpad-center { grid-column: 2; grid-row: 2; }
2814
+ .vd-dpad-right { grid-column: 3; grid-row: 2; }
2815
+ .vd-dpad-down { grid-column: 2; grid-row: 3; }
2816
+
2817
+ .vd-attributes {
2818
+ display: flex;
2819
+ flex-direction: column;
2820
+ gap: ${a[3]};
2821
+ background: color-mix(in oklch, ${m.white} 85%, transparent);
2822
+ backdrop-filter: blur(8px);
2823
+ border: 1px solid color-mix(in oklch, ${m.neutral[900]} 8%, transparent);
2824
+ border-radius: ${a[3]};
2825
+ padding: ${a[3]};
2826
+ box-shadow: 0 ${a[1]} ${a[4]} color-mix(in oklch, ${m.neutral[900]} 6%, transparent);
2827
+ font-family: ${H};
2828
+ }
2829
+
2830
+ .vd-attribute {
2831
+ display: flex;
2832
+ flex-direction: column;
2833
+ gap: ${a[1.5]};
2834
+ }
2835
+
2836
+ /* Micro-label: recedes so the controls lead. */
2837
+ .vd-attribute-label {
2838
+ font-size: ${_.fontSize.xs};
2839
+ font-weight: ${_.fontWeight.medium};
2840
+ color: ${m.neutral[500]};
2841
+ text-transform: uppercase;
2842
+ letter-spacing: 0.05em;
2843
+ font-family: ${H};
2844
+ }
2845
+
2846
+ /* sidebar-right layout — a docked, full-height right panel */
2847
+ .vd-container { --vd-sidebar-width: 300px; }
2848
+
2849
+ .vd-hidden { display: none !important; }
2850
+
2851
+ .vd-sidebar {
2852
+ position: absolute;
2853
+ inset-block: 0;
2854
+ inset-inline-end: 0;
2855
+ inline-size: var(--vd-sidebar-width);
2856
+ z-index: 11;
2857
+ display: flex;
2858
+ flex-direction: column;
2859
+ background: color-mix(in oklch, ${m.white} 90%, transparent);
2860
+ backdrop-filter: blur(10px);
2861
+ border-inline-start: 1px solid color-mix(in oklch, ${m.neutral[900]} 8%, transparent);
2862
+ box-shadow: -${a[1]} 0 ${a[4]} color-mix(in oklch, ${m.neutral[900]} 5%, transparent);
2863
+ }
2864
+
2865
+ @media (prefers-reduced-motion: no-preference) {
2866
+ .vd-sidebar { transition: transform 0.18s ease; }
2867
+ }
2868
+
2869
+ .vd-sidebar-collapsed { transform: translateX(100%); }
2870
+
2871
+ .vd-sidebar-header {
2872
+ display: flex;
2873
+ justify-content: flex-end;
2874
+ padding: ${a[1.5]} ${a[1.5]} 0;
2875
+ }
2876
+
2877
+ .vd-sidebar-body {
2878
+ flex: 1;
2879
+ overflow-y: auto;
2880
+ padding: ${a[4]};
2881
+ }
2882
+
2883
+ /* attributes inside the sidebar: flat and full-width — the panel provides the frosting */
2884
+ .vd-attributes.vd-attributes-sidebar {
2885
+ background: transparent;
2886
+ backdrop-filter: none;
2887
+ border: none;
2888
+ border-radius: 0;
2889
+ padding: 0;
2890
+ box-shadow: none;
2891
+ gap: ${a[5]};
2892
+ }
2893
+
2894
+ /* floating toggle, shown when the sidebar is collapsed on narrow embeds */
2895
+ .vd-configurator-toggle {
2896
+ position: absolute;
2897
+ inset-block-end: ${a[3]};
2898
+ inset-inline-end: ${a[3]};
2899
+ z-index: 12;
2900
+ }
2901
+
2902
+ /* while the panel is open, keep the corner controls clear of it */
2903
+ .vd-layout-sidebar-right .vd-slot-top-right { inset-inline-end: calc(var(--vd-sidebar-width) + ${a[3]}); }
2904
+ .vd-layout-sidebar-right .vd-slot-bottom-right { inset-inline-end: calc(var(--vd-sidebar-width) + ${a[3]}); }
2905
+
2906
+ /* while collapsed on a narrow embed, lift the bottom-right controls above the
2907
+ floating toggle so the AR/fullscreen buttons aren't hidden behind the
2908
+ "open configurator" button (spacing[9] = the default toggle button height) */
2909
+ .vd-layout-sidebar-collapsed .vd-slot-bottom-right {
2910
+ inset-block-end: calc(${a[3]} + ${a[9]} + ${a[1.5]});
2911
+ }
2912
+
2913
+ /* Price + CTA — sit under the attribute controls, separated by a hairline */
2914
+ .vd-commerce {
2915
+ display: flex;
2916
+ flex-direction: column;
2917
+ gap: ${a[2]};
2918
+ padding-block-start: ${a[3]};
2919
+ border-block-start: 1px solid color-mix(in oklch, ${m.neutral[900]} 8%, transparent);
2920
+ font-family: ${H};
2921
+ }
2922
+
2923
+ .vd-commerce-price {
2924
+ display: flex;
2925
+ align-items: baseline;
2926
+ gap: ${a[1.5]};
2927
+ }
2928
+
2929
+ .vd-price {
2930
+ font-size: ${_.fontSize.lg};
2931
+ font-weight: ${_.fontWeight.semibold};
2932
+ color: ${m.neutral[900]};
2933
+ }
2934
+
2935
+ .vd-vat {
2936
+ font-size: ${_.fontSize.xs};
2937
+ color: ${m.neutral[500]};
2938
+ }
2939
+
2940
+ .vd-cta {
2941
+ inline-size: 100%;
2942
+ justify-content: center;
2943
+ }
2944
+
2945
+ /* Failed submit is the one place red belongs: a clear, recoverable error state. */
2946
+ .vd-commerce[data-submit="failed"] .vd-cta {
2947
+ background: ${m.semantic.error};
2948
+ border-color: ${m.semantic.error};
2949
+ color: ${m.white};
2950
+ }
2951
+
2952
+ `;
2953
+ function Fi() {
2954
+ if (Un(), document.getElementById("vd-styles") !== null)
2955
+ return;
2956
+ const n = document.createElement("style");
2957
+ n.id = "vd-styles", n.textContent = zi, document.head.appendChild(n);
2958
+ }
2959
+ function Pi(n, t) {
2960
+ const e = document.createElement("a");
2961
+ e.href = `data:image/png;base64,${n}`, e.download = t, e.click();
2962
+ }
2963
+ class $i {
2964
+ options;
2965
+ settings = {};
2966
+ container = null;
2967
+ loading = null;
2968
+ slots = { topRight: null, bottomRight: null };
2969
+ screenshotBtn = null;
2970
+ actionBar = null;
2971
+ cameraControls = null;
2972
+ attributes = null;
2973
+ layout = null;
2974
+ commerce = null;
2975
+ constructor(t) {
2976
+ this.options = t;
2977
+ }
2978
+ attach(t) {
2979
+ Fi(), this.container = t, this.loading = new yi(t), this.slots.topRight = this.createSlot(t, "vd-slot-top-right"), this.slots.bottomRight = this.createSlot(t, "vd-slot-bottom-right");
2980
+ }
2981
+ onReady() {
2982
+ this.loading?.hide(), this.loading = null, this.mountToolbar(), this.cameraControls !== null && (this.cameraControls.element.style.display = "flex"), this.layout?.setVisible(!0);
2983
+ }
2984
+ mountToolbar() {
2985
+ if (this.actionBar !== null || this.slots.bottomRight === null || this.container === null)
2986
+ return;
2987
+ const t = typeof this.container.requestFullscreen == "function";
2988
+ this.actionBar = new _i({
2989
+ onAr: this.options.onAr,
2990
+ onFullscreen: t ? () => {
2991
+ this.toggleFullscreen();
2992
+ } : void 0
2993
+ }), this.actionBar.applySettings(this.settings), this.slots.bottomRight.appendChild(this.actionBar.element), this.syncScreenshotButton(), this.placeScreenshotButton();
2994
+ }
2995
+ toggleFullscreen() {
2996
+ this.container !== null && (document.fullscreenElement !== null ? document.exitFullscreen() : (this.options.onFullscreenEnter?.(), this.container.requestFullscreen()));
2997
+ }
2998
+ updateProgress(t, e) {
2999
+ this.loading?.updateProgress(t, e);
3000
+ }
3001
+ showError(t) {
3002
+ this.loading?.showError(t);
3003
+ }
3004
+ applyViewerSettings(t) {
3005
+ this.settings = t, t.language !== void 0 && mt(t.language, { reload: !1 }), this.syncScreenshotButton(), this.actionBar?.applySettings(t), this.cameraControls !== null && (this.cameraControls.element.style.display = t.cameraControls === !0 ? "flex" : "none"), this.placeScreenshotButton();
3006
+ }
3007
+ renderAttributeControls(t, e) {
3008
+ if (!(this.container === null || this.slots.topRight === null) && (this.cameraControls?.element.remove(), this.cameraControls = null, this.teardownConfigurator(), this.settings.cameraControls === !0 && (this.cameraControls = new L(this.options.cameraApi, this.options.cameraPositionApi), this.cameraControls.element.style.display = "none", this.slots.topRight.appendChild(this.cameraControls.element)), this.placeScreenshotButton(), e.length !== 0)) {
3009
+ this.attributes = document.createElement("div"), this.attributes.className = "vd-attributes";
3010
+ for (const i of e)
3011
+ this.attributes.appendChild(Ei(
3012
+ i,
3013
+ t,
3014
+ this.options.eventBus,
3015
+ this.options.onSelect,
3016
+ this.options.onSubscribe
3017
+ ));
3018
+ this.commerce = new Ti(this.options.configuration), this.attributes.appendChild(this.commerce.element), this.layout = Mi(this.settings.configuratorLayout), this.layout.attach(this.container, this.attributes);
3019
+ }
3020
+ }
3021
+ get viewerSettings() {
3022
+ return this.settings;
3023
+ }
3024
+ /** Tear down the configurator panel: price + CTA, attribute controls, layout. */
3025
+ teardownConfigurator() {
3026
+ this.commerce?.destroy(), this.commerce = null, this.attributes?.remove(), this.attributes = null, this.layout?.destroy(), this.layout = null;
3027
+ }
3028
+ destroy() {
3029
+ this.loading?.destroy(), this.screenshotBtn?.element.remove(), this.actionBar?.destroy(), this.actionBar?.element.remove(), this.cameraControls?.element.remove(), this.teardownConfigurator();
3030
+ for (const t of Object.values(this.slots))
3031
+ t?.remove();
3032
+ this.container = null;
3033
+ }
3034
+ createSlot(t, e) {
3035
+ const i = document.createElement("div");
3036
+ return i.className = e, t.appendChild(i), i;
3037
+ }
3038
+ syncScreenshotButton() {
3039
+ const t = this.settings.screenshot === !0;
3040
+ t && this.screenshotBtn === null && (this.screenshotBtn = new g({
3041
+ variant: "outline",
3042
+ size: "icon",
3043
+ label: Ue(),
3044
+ icon: b.screenshot(),
3045
+ onClick: () => {
3046
+ this.options.snapshotApi.take("snapshot.png").onDeveloped(({ data: e, filename: i }) => {
3047
+ Pi(e, i);
3048
+ });
3049
+ }
3050
+ })), !t && this.screenshotBtn !== null && (this.screenshotBtn.element.remove(), this.screenshotBtn = null);
3051
+ }
3052
+ placeScreenshotButton() {
3053
+ this.screenshotBtn === null || this.slots.topRight === null || (this.cameraControls !== null ? this.cameraControls.element.appendChild(this.screenshotBtn.element) : this.slots.topRight.appendChild(this.screenshotBtn.element));
3054
+ }
3055
+ }
3056
+ const Di = {};
3057
+ class Bi {
3058
+ defaultServer = "https://server.virtualdisplay.io";
3059
+ options;
3060
+ serverHost;
3061
+ constructor(t, e) {
3062
+ this.options = t, this.serverHost = e;
3063
+ }
3064
+ /**
3065
+ * Create container and iframe, attach to parent element
3066
+ */
3067
+ create() {
3068
+ const t = this.createContainer(), e = this.createIframe();
3069
+ return t.appendChild(e), this.attachToParent(t), { container: t, iframe: e };
3070
+ }
3071
+ createContainer() {
3072
+ const t = document.createElement("div");
3073
+ return t.className = "vd-container", Object.assign(t.style, {
3074
+ position: "relative",
3075
+ width: "100%",
3076
+ height: "100%",
3077
+ overflow: "hidden"
3078
+ }), t;
3079
+ }
3080
+ createIframe() {
3081
+ const t = document.createElement("iframe");
3082
+ return t.src = this.buildUrl(), Object.assign(t.style, {
3083
+ width: "100%",
3084
+ height: "100%",
3085
+ border: "none",
3086
+ display: "block"
3087
+ }), t.setAttribute("allow", "xr-spatial-tracking; fullscreen"), t;
3088
+ }
3089
+ attachToParent(t) {
3090
+ this.getParentElement().appendChild(t);
3091
+ }
3092
+ buildUrl() {
3093
+ const t = this.getServerUrl(), e = new URL(t);
3094
+ return e.searchParams.set("license", this.options.license), e.searchParams.set("model", this.options.model), this.options.language !== void 0 && e.searchParams.set("language", this.options.language), this.options.debug === !0 && e.searchParams.set("debug", "true"), this.options.traceparent !== void 0 && e.searchParams.set("traceparent", this.options.traceparent), e.toString();
3095
+ }
3096
+ getServerUrl() {
3097
+ if (this.serverHost !== void 0)
3098
+ return this.serverHost;
3099
+ if (Di?.VITE_VIRTUALDISPLAY_SERVER_HOST === void 0)
3100
+ return this.defaultServer;
3101
+ }
3102
+ getParentElement() {
3103
+ if (typeof this.options.parent != "string")
3104
+ return this.options.parent;
3105
+ const t = document.querySelector(this.options.parent);
3106
+ if (t === null)
3107
+ throw f.parentNotFound(this.options.parent);
3108
+ return t;
3109
+ }
3110
+ }
3111
+ function Ui(n) {
3112
+ const { messenger: t } = n;
3113
+ t.on(c.HANDSHAKE, (e) => {
3114
+ xt(e) && (w.info("Server handshake received, flushing publisher queue"), t.markReady());
3115
+ }), t.on(c.SESSION, (e) => {
3116
+ Tt(e) && n.onSession(e.sessionId);
3117
+ }), t.on(c.MUTATION, (e) => {
3118
+ Rt(e) && (n.attributes.handleMutationResult(e), n.configuration.handleSelectionChanged(n.attributes.getSelection()));
3119
+ }), t.on(c.SNAPSHOT, (e) => {
3120
+ It(e) && n.snapshot.handleSnapshotResult(e);
3121
+ }), t.on(c.CAMERA, (e) => {
3122
+ Ot(e) && n.cameraPosition.handlePositionUpdate(e);
3123
+ }), t.on(c.LOADING_INDICATOR, (e) => {
3124
+ Lt(e) && (e.error !== void 0 ? n.ui.showError(e.error) : n.ui.updateProgress(e.progress, e.phase));
3125
+ }), t.on(c.CONFIG, (e) => {
3126
+ Mt(e) && n.applyConfig(e);
3127
+ }), t.on(c.MAPPING, (e) => {
3128
+ Nt(e) && (n.attributes.handleMappingReceived(e), n.configuration.handleSelectionChanged(n.attributes.getSelection()), n.ui.renderAttributeControls(n.attributes, e.attributes), n.readyStateTracker.handleMappingReceived());
3129
+ }), Vi(n);
3130
+ }
3131
+ function Vi(n) {
3132
+ const { messenger: t } = n;
3133
+ t.on(c.FOCUS, (e) => {
3134
+ zt(e) && n.focus.handleStateReceived(e);
3135
+ }), t.on(c.PRICING, (e) => {
3136
+ Ft(e) && n.configuration.handlePricingReceived(e.pricing);
3137
+ });
3138
+ }
3139
+ class ji {
3140
+ ready = !1;
3141
+ onReady;
3142
+ constructor(t) {
3143
+ this.onReady = t;
3144
+ }
3145
+ handleMappingReceived() {
3146
+ this.ready || (this.ready = !0, w.info("Mapping received from server, client is now ready"), this.onReady?.());
3147
+ }
3148
+ get isReady() {
3149
+ return this.ready;
3150
+ }
3151
+ clear() {
3152
+ this.ready = !1;
3153
+ }
3154
+ }
3155
+ class Hi {
3156
+ attributes;
3157
+ readyStateTracker;
3158
+ messenger;
3159
+ cameraApi;
3160
+ cameraPositionApi;
3161
+ focusApi;
3162
+ configurationApi;
3163
+ snapshotApi;
3164
+ annotationsApi;
3165
+ eventBus;
3166
+ ui;
3167
+ qrModal;
3168
+ options;
3169
+ serverHost;
3170
+ iframe;
3171
+ container;
3172
+ readyCallbacks = [];
3173
+ mutationFailedCallbacks = [];
3174
+ /** The viewer's tracking session id, once the server announces it (SESSION). */
3175
+ viewerSessionId;
3176
+ constructor(t, e) {
3177
+ this.options = t, this.serverHost = e?.serverHost, this.initializeLogging(), this.messenger = new Pt(
3178
+ () => this.iframe?.contentWindow ?? null,
3179
+ e?.messengerOptions
3180
+ );
3181
+ const i = (o) => {
3182
+ this.messenger.send(o);
3183
+ };
3184
+ this.attributes = new oi(i, (o, s) => {
3185
+ for (const r of this.mutationFailedCallbacks)
3186
+ r({ attribute: o, value: s });
3187
+ }), this.snapshotApi = new hi(i), this.annotationsApi = new Wn(i), this.cameraApi = new si(i), this.cameraPositionApi = new ri(), this.focusApi = new ui(i, (o) => {
3188
+ this.dispatchFocusChange(o);
3189
+ }), this.configurationApi = new ci(
3190
+ (o) => {
3191
+ this.dispatchConfigurationChange(o);
3192
+ },
3193
+ (o) => {
3194
+ this.dispatchConfigurationSubmit(o);
3195
+ }
3196
+ ), this.eventBus = new mi(), this.qrModal = new $n(), this.readyStateTracker = new ji(() => {
3197
+ const o = this.readyCallbacks;
3198
+ this.readyCallbacks = [];
3199
+ for (const s of o)
3200
+ s(this);
3201
+ this.ui.onReady();
3202
+ }), this.ui = new $i({
3203
+ snapshotApi: this.snapshotApi,
3204
+ cameraApi: this.cameraApi,
3205
+ cameraPositionApi: this.cameraPositionApi,
3206
+ eventBus: this.eventBus,
3207
+ configuration: this.configurationApi,
3208
+ onSelect: (o, s) => this.attributes.select(o, s),
3209
+ onSubscribe: (o, s) => this.attributes.onChange(o, s),
3210
+ onAr: () => {
3211
+ this.activateAr();
3212
+ },
3213
+ onFullscreenEnter: () => {
3214
+ this.trackFullscreen();
3215
+ }
3216
+ }), this.wireIncomingMessages(), e?.registerHandlers?.(this.messenger, i), this.messenger.start(), this.createAndConnectIframe();
3217
+ }
3218
+ /** Wire the inbound viewer protocol to the facades. */
3219
+ wireIncomingMessages() {
3220
+ Ui({
3221
+ messenger: this.messenger,
3222
+ attributes: this.attributes,
3223
+ configuration: this.configurationApi,
3224
+ snapshot: this.snapshotApi,
3225
+ cameraPosition: this.cameraPositionApi,
3226
+ focus: this.focusApi,
3227
+ ui: this.ui,
3228
+ readyStateTracker: this.readyStateTracker,
3229
+ applyConfig: (t) => {
3230
+ this.handleConfig(t);
3231
+ },
3232
+ onSession: (t) => {
3233
+ this.viewerSessionId = t;
3234
+ }
3235
+ });
3236
+ }
3237
+ /**
3238
+ * Dispatch a bubbling `vd:focus-change` event on the container so a page can
3239
+ * react to focus without registering an `onChange` callback.
3240
+ */
3241
+ dispatchFocusChange(t) {
3242
+ this.container?.dispatchEvent(
3243
+ new CustomEvent(I.FOCUS_CHANGE, { detail: t, bubbles: !0 })
3244
+ );
3245
+ }
3246
+ /**
3247
+ * Dispatch a bubbling `vd:configuration-change` event on the container so a
3248
+ * page or tag manager can react to price changes without a client callback.
3249
+ */
3250
+ dispatchConfigurationChange(t) {
3251
+ this.container?.dispatchEvent(
3252
+ new CustomEvent(I.CONFIGURATION_CHANGE, { detail: t ?? null, bubbles: !0 })
3253
+ );
3254
+ }
3255
+ /** Dispatch a bubbling `vd:configuration-submit` event when the CTA is used. */
3256
+ dispatchConfigurationSubmit(t) {
3257
+ this.container?.dispatchEvent(
3258
+ new CustomEvent(I.CONFIGURATION_SUBMIT, { detail: t, bubbles: !0 })
3259
+ );
3260
+ }
3261
+ handleConfig(t) {
3262
+ const e = t.viewerSettings, i = this.options.viewerSettings;
3263
+ if (e !== void 0 || i !== void 0) {
3264
+ const o = i !== void 0 ? { ...e ?? {}, ...i } : e;
3265
+ if (i !== void 0 && e !== void 0) {
3266
+ const s = Object.entries(i).filter(([r, l]) => e[r] !== l).map(([r, l]) => `${r} (metadata: ${e[r] ?? "undefined"}, override: ${l})`);
3267
+ s.length > 0 && w.warn(`Viewer settings override active: ${s.join(", ")}`);
3268
+ }
3269
+ this.ui.applyViewerSettings(o), this.annotationsApi.setEnabled(o.annotations !== !1);
3270
+ }
3271
+ this.cameraPositionApi.applyLimits(t.cameraLimits);
3272
+ }
3273
+ activateAr() {
3274
+ if (Zn()) {
3275
+ this.messenger.send({ type: c.AR_ACTIVATE });
3276
+ return;
3277
+ }
3278
+ this.qrModal.show(this.iframe?.src ?? "");
3279
+ }
3280
+ /** Tell the viewer the user entered fullscreen, so it records the engagement. */
3281
+ trackFullscreen() {
3282
+ this.messenger.send({ type: c.FULLSCREEN });
3283
+ }
3284
+ initializeLogging() {
3285
+ this.options.debug === !0 && ii(), w.info("Initializing Virtualdisplay client", { model: this.options.model });
3286
+ }
3287
+ createAndConnectIframe() {
3288
+ const e = new Bi(this.options, this.serverHost).create();
3289
+ this.container = e.container, this.iframe = e.iframe, this.eventBus.attach(this.container), this.ui.attach(this.container);
3290
+ try {
3291
+ const i = new URL(this.iframe.src).origin;
3292
+ this.messenger.setTargetOrigin(i);
3293
+ } catch {
3294
+ }
3295
+ }
3296
+ select(t, e) {
3297
+ this.attributes.select(t, e);
3298
+ }
3299
+ getValues(t) {
3300
+ return this.attributes.getValues(t);
3301
+ }
3302
+ getValue(t, e) {
3303
+ return this.attributes.getValue(t, e);
3304
+ }
3305
+ onChange(t, e) {
3306
+ this.attributes.onChange(t, e);
3307
+ }
3308
+ getAttribute(t) {
3309
+ return this.attributes.getAttribute(t);
3310
+ }
3311
+ get isReady() {
3312
+ return this.readyStateTracker.isReady;
3313
+ }
3314
+ onReady(t) {
3315
+ if (this.readyStateTracker.isReady) {
3316
+ t(this);
3317
+ return;
3318
+ }
3319
+ this.readyCallbacks.push(t);
3320
+ }
3321
+ onMutationFailed(t) {
3322
+ this.mutationFailedCallbacks.push(t);
3323
+ }
3324
+ on(t, e) {
3325
+ this.eventBus.on(t, e);
3326
+ }
3327
+ get annotations() {
3328
+ return this.annotationsApi;
3329
+ }
3330
+ get camera() {
3331
+ return this.cameraApi;
3332
+ }
3333
+ get focus() {
3334
+ return this.focusApi;
3335
+ }
3336
+ get configuration() {
3337
+ return this.configurationApi;
3338
+ }
3339
+ get cameraPosition() {
3340
+ return this.cameraPositionApi;
3341
+ }
3342
+ get snapshot() {
3343
+ return this.snapshotApi;
3344
+ }
3345
+ /** The viewer's tracking session id, for a host page to correlate its own actions. */
3346
+ get sessionId() {
3347
+ return this.viewerSessionId;
3348
+ }
3349
+ get viewerSettings() {
3350
+ return this.ui.viewerSettings;
3351
+ }
3352
+ destroy() {
3353
+ this.readyStateTracker.clear(), this.readyCallbacks = [], this.mutationFailedCallbacks.length = 0, this.snapshotApi.clear(), this.messenger.destroy(), this.qrModal.hide(), this.ui.destroy(), this.container?.parentElement !== null && this.container?.parentElement !== void 0 && this.container.parentElement.removeChild(this.container), this.container = void 0, this.iframe = void 0;
3354
+ }
3355
+ }
3356
+ class qi extends Hi {
3357
+ }
3358
+ export {
3359
+ Wn as Annotations,
3360
+ Xn as Attribute,
3361
+ Yn as AttributeValue,
3362
+ si as Camera,
3363
+ ci as Configuration,
3364
+ E as ERROR_CODES,
3365
+ ui as Focus,
3366
+ di as Photo,
3367
+ hi as Snapshot,
3368
+ I as VD_EVENTS,
3369
+ qi as VirtualdisplayClient,
3370
+ f as VirtualdisplayError,
3371
+ ii as enableDebugMode,
3372
+ Gi as isDebugMode,
3373
+ w as logger
796
3374
  };
797
- //#endregion
798
- export { v as Attribute, _ as AttributeValue, M as Camera, e as ERROR_CODES, P as Photo, F as Snapshot, L as VirtualdisplayClient, t as VirtualdisplayError, I as VirtualdisplayViewerService, m as enableDebugMode, h as isDebugMode, p as logger };