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