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