@virtualdisplay.io/client 4.0.0-alpha.2 → 4.0.0-alpha.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +150 -0
- package/README.md +85 -158
- package/dist/browser-DfB_An57.cjs +8 -0
- package/dist/browser-ey6Iih3j.js +1540 -0
- package/dist/index.d.ts +1158 -1
- package/dist/virtualdisplay.client.cjs.js +493 -1
- package/dist/virtualdisplay.client.es.js +3570 -794
- package/dist/virtualdisplay.client.umd.js +500 -1
- package/package.json +1 -1
|
@@ -1 +1,493 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e={NO_MAPPING:`NO_MAPPING`,ATTRIBUTE_NOT_FOUND:`ATTRIBUTE_NOT_FOUND`,VALUE_NOT_FOUND:`VALUE_NOT_FOUND`,PARENT_NOT_FOUND:`PARENT_NOT_FOUND`,INVALID_PARAMETER:`INVALID_PARAMETER`,SNAPSHOT_FAILED:`SNAPSHOT_FAILED`},t=class t extends Error{code;constructor(e,n){super(e),this.name=`VirtualdisplayError`,this.code=n,Error.captureStackTrace!==void 0&&Error.captureStackTrace(this,t)}static noMapping(){return new t(`No attributes available. Waiting for server metadata.`,e.NO_MAPPING)}static attributeNotFound(n){return new t(`Attribute "${n}" not found in mapping`,e.ATTRIBUTE_NOT_FOUND)}static valueNotFound(n,r){return new t(`Value "${r}" not found for attribute "${n}"`,e.VALUE_NOT_FOUND)}static parentNotFound(n){return new t(`Parent element not found: ${n}`,e.PARENT_NOT_FOUND)}static invalidParameter(n){return new t(n,e.INVALID_PARAMETER)}static snapshotFailed(n,r){return new t(`Snapshot failed for "${n}": ${r}`,e.SNAPSHOT_FAILED)}},n=class{defaultServer=`https://server.virtualdisplay.io`;options;constructor(e){this.options=e}create(){let e=this.createIframe();return this.attachToParent(e),e}createIframe(){let e=document.createElement(`iframe`);return e.src=this.buildUrl(),Object.assign(e.style,{width:`100%`,height:`100%`,border:`none`}),e.setAttribute(`allow`,`xr-spatial-tracking; fullscreen`),e}attachToParent(e){this.getParentElement().appendChild(e)}buildUrl(){let e=this.getServerUrl(),t=new URL(e);return t.searchParams.set(`license`,this.options.license),t.searchParams.set(`model`,this.options.model),this.options.debug===!0&&t.searchParams.set(`debug`,`true`),this.options.language!==void 0&&t.searchParams.set(`language`,this.options.language),t.toString()}getServerUrl(){return this.defaultServer}getParentElement(){if(typeof this.options.parent!=`string`)return this.options.parent;let e=document.querySelector(this.options.parent);if(e===null)throw t.parentNotFound(this.options.parent);return e}};function r(e){let t=new Date(e.timestamp).toLocaleTimeString(`en-GB`,{hour12:!1}),n=e.level.toUpperCase().padEnd(5),r=e.trace_id?.slice(0,8)??`--------`,i=e.msg,a=[`timestamp`,`level`,`msg`,`service`,`trace_id`,`span_id`],o=Object.entries(e).filter(([e])=>!a.includes(e)).map(([e,t])=>`${e}=${JSON.stringify(t)}`).join(` `);return`${t} ${n} [${r}] ${i}${o?` `+o:``}`}function i(e){return JSON.stringify(e)}function a(e,t){let n=t?r(e):i(e);e.level===`error`?console.error(n):e.level===`warn`?console.warn(n):console.log(n)}function o(){return new Date}function s(e){return e.toISOString()}var c=class e{constructor(e){this.config=e}log(e,t,n={}){let r=this.config.traceProvider?.()??{};a({timestamp:s(o()),level:e,msg:t,service:this.config.service,...r,...n},this.config.isDev)}debug(e,t){this.config.isDev&&this.log(`debug`,e,t)}info(e,t){this.log(`info`,e,t)}warn(e,t){this.log(`warn`,e,t)}error(e,t){this.log(`error`,e,t)}with(t){let n=new e(this.config);return n.log=((e,n,r={})=>{this.log(e,n,{...t,...r})}).bind(this),n}};function l(e,t){return new c({service:e,isDev:t?.isDev===void 0?typeof process<`u`?process.env.NODE_ENV!==`production`:!0:t.isDev,traceProvider:t?.traceProvider})}function u(e){if(e!==void 0)return typeof e==`object`&&e&&!Array.isArray(e)&&!(e instanceof Error)?e:e instanceof Error?{error:e.message}:{value:e}}function d(e){return{debug:(t,n)=>e.debug(t,u(n)),info:(t,n)=>e.info(t,u(n)),warn:(t,n)=>e.warn(t,u(n)),error:(t,n)=>e.error(t,u(n))}}var f=!1,p=d(l(`client`,{isDev:!1}));function m(){f=!0,p=d(l(`client`,{isDev:!0}))}function h(){return f}var g=class{ready=!1;onReady;constructor(e){this.onReady=e}handleMappingReceived(){this.markReady(`Mapping received from server`)}handleMutationResult(e){e.isInitial&&this.markReady(`Initial mutations processed`)}get isReady(){return this.ready}clear(){this.ready=!1}markReady(e){this.ready||(this.ready=!0,p.info(`${e} - client is now ready`),this.onReady?.())}},_=class{isSelectedValue=!1;constructor(e,t){this.value=e,this.attribute=t}get isSelected(){return this.isSelectedValue}setSelected(e){this.isSelectedValue=e}},v=class{name;defaultValue;values;onSelect;onChangeCallback;constructor(e){this.name=e.name,this.defaultValue=e.defaultValue,this.onSelect=e.onSelect,this.values=this.createValues(e.values)}select(e){if(!this.values.has(e))throw t.valueNotFound(this.name,e);this.onSelect(this.name,e)}getValues(){return Array.from(this.values.values())}getValue(e){return this.values.get(e)}onChange(e){this.onChangeCallback=e}handleResult(e){let t;for(let n of this.values.values()){let r=n.value===e;n.setSelected(r),r&&(t=n)}t!==void 0&&this.onChangeCallback!==void 0&&this.onChangeCallback(t)}createValues(e){let t=new Map;for(let n of e){let e=new _(n,this.name);n===this.defaultValue&&e.setSelected(!0),t.set(n,e)}return t}},y=class{attributes=new Map;constructor(e,t,n){for(let n of e){let e=this.buildOptions(n,t);this.attributes.set(n.name,new v(e))}this.onMutationFailed=n}onMutationFailed;get(e){return this.attributes.get(e)}defaults(){let e=[];for(let t of this.attributes.values())t.defaultValue!==void 0&&e.push({name:t.name,value:t.defaultValue});return e}handleResults(e){for(let t of e){if(!t.success){this.onMutationFailed?.(t.name,t.value);continue}this.get(t.name)?.handleResult(t.value)}}buildOptions(e,t){let n={name:e.name,values:e.values,onSelect:(e,n)=>{t([{name:e,value:n}],!1)}};return e.defaultValue===void 0?n:{...n,defaultValue:e.defaultValue}}},b={READY:`ready`,MUTATION:`mutation`,STATE:`state`,CONFIG:`config`,CAMERA:`camera`,SNAPSHOT:`snapshot`,MAPPING:`mapping`},x=new Set(Object.values(b));function S(e){if(typeof e!=`object`||!e)return!1;let t=e;return typeof t.target==`string`?!1:typeof t.type==`string`&&x.has(t.type)}function C(e){let t=O(e);return t!==null&&t.type===b.READY}function w(e){let t=O(e);return t!==null&&t.type===b.MUTATION&&Array.isArray(t.results)}function T(e){let t=O(e);return t!==null&&t.type===b.SNAPSHOT&&(`data`in t||`error`in t)}function E(e){let t=O(e);return t!==null&&t.type===b.CAMERA&&Array.isArray(t.transforms)}function D(e){let t=O(e);return t!==null&&t.type===b.MAPPING&&Array.isArray(t.attributes)}function O(e){return typeof e!=`object`||!e?null:e}var k=class{pending=[];isReady=!1;constructor(e){this.processor=e}enqueue(e){if(this.isReady){this.processor(e);return}this.pending.push(e)}markReady(){if(this.isReady||(this.isReady=!0,this.pending.length===0))return;let e=[...this.pending];this.pending.length=0;for(let t of e)this.processor(t)}get ready(){return this.isReady}get pendingCount(){return this.pending.length}hasPending(e){return this.pending.some(t=>t.type===e)}clear(){this.pending.length=0}},A=class{handlers=new Map;publisher;consumer;shouldBuffer;listener=null;sourceId;constructor(e,t){this.getTarget=e,this.sourceId=`vd-${Math.random().toString(36).slice(2,8)}`,this.publisher=new k(e=>this.post(e)),this.consumer=new k(e=>this.routeToHandler(e)),this.shouldBuffer=t?.shouldBuffer??null,t?.bufferIncoming!==!0&&this.consumer.markReady()}on(e,t){this.handlers.set(e,t)}off(e){this.handlers.delete(e)}send(e){this.publisher.enqueue(e)}markReady(){this.publisher.markReady()}markConsumerReady(){this.consumer.markReady()}consumerHasPending(e){return this.consumer.hasPending(e)}start(){this.listener===null&&(this.listener=e=>{let{data:t}=e;if(!S(t)||t._source===this.sourceId)return;let n=t;if(this.shouldBuffer!==null&&!this.shouldBuffer(n)){this.routeToHandler(n);return}this.consumer.enqueue(n)},window.addEventListener(`message`,this.listener))}destroy(){this.listener!==null&&(window.removeEventListener(`message`,this.listener),this.listener=null),this.publisher.clear(),this.consumer.clear(),this.handlers.clear()}get ready(){return this.publisher.ready}get pendingCount(){return this.publisher.pendingCount}post(e){let t=this.getTarget();t!==null&&t.postMessage({...e,_source:this.sourceId},`*`)}routeToHandler(e){let t=this.handlers.get(e.type);if(t===void 0)return;let n=t(e);n instanceof Promise&&n.catch(t=>{let n=t instanceof Error?t.message:String(t);console.error(`Virtualdisplay: error handling ${e.type}: ${n}`)})}};new Set([b.CAMERA]);var j=class{registry;pendingCallbacks=[];constructor(e,t){this.send=e,this.onMutationFailed=t}handleMappingReceived(e){p.debug(`Initializing from server mapping`,{attributeCount:e.attributes.length}),this.registry=new y(e.attributes,(e,t)=>this.sendMutation(e,t),this.onMutationFailed);let t=this.registry.defaults();t.length>0&&this.sendMutation(t,!0),this.replayPendingCallbacks()}handleMutationResult(e){this.registry?.handleResults(e.results)}select(e,t){this.sendMutation([{name:e,value:t}],!1)}getValues(e){return this.registry?.get(e)?.getValues()??[]}getValue(e,t){return this.registry?.get(e)?.getValue(t)}onChange(e,t){if(this.registry===void 0){this.pendingCallbacks.push({name:e,callback:t});return}let n=this.registry.get(e);if(n===void 0){p.warn(`onChange: attribute "${e}" not found — callback will not fire`);return}n.onChange(t)}getAttribute(e){return this.registry?.get(e)}get hasMapping(){return this.registry!==void 0}sendMutation(e,t){let n={type:b.MUTATION,mutations:e,isInitial:t};this.send(n)}replayPendingCallbacks(){for(let{name:e,callback:t}of this.pendingCallbacks){let n=this.registry?.get(e);n===void 0&&p.warn(`onChange: attribute "${e}" not found — buffered callback will not fire`),n?.onChange(t)}this.pendingCallbacks.length=0}},M=class{commands=[];constructor(e){this.send=e}rotate(e){return this.validateFiniteNumber(e,`rotate`),this.commands.push({action:`rotate`,value:e}),this}tilt(e){return this.validateFiniteNumber(e,`tilt`),this.commands.push({action:`tilt`,value:e}),this}zoom(e){return this.validateFiniteNumber(e,`zoom`),this.commands.push({action:`zoom`,value:e}),this}set(){if(this.commands.length===0)throw t.invalidParameter(`No camera commands to execute. Call rotate(), tilt(), or zoom() before set().`);let e={type:b.CAMERA,commands:this.commands};this.send(e),this.commands=[]}validateFiniteNumber(e,n){if(!Number.isFinite(e))throw t.invalidParameter(`${n}() requires a finite number, got ${String(e)}`)}reset(){let e={type:b.CAMERA,commands:[{action:`reset`}]};this.send(e)}},N=class{state;changeCallbacks=[];constructor(){this.state={rotation:0,tilt:0,zoom:0}}get rotation(){return this.state.rotation}get tilt(){return this.state.tilt}get zoom(){return this.state.zoom}onChange(e){this.changeCallbacks.push(e)}handlePositionUpdate(e){this.update(e.transforms)}update(e){let t=!1;for(let n of e)switch(n.type){case`rotation`:this.state.rotation=n.value,t=!0;break;case`tilt`:this.state.tilt=n.value,t=!0;break;case`zoom`:this.state.zoom=n.value,t=!0;break;default:break}if(t){let e={rotation:this.rotation,tilt:this.tilt,zoom:this.zoom};for(let t of this.changeCallbacks)t(e)}}},P=class{developedCallbacks=new Set;errorCallbacks=new Set;developed=!1;failed=!1;photoData=null;constructor(e){this.filename=e}onDeveloped(e){return this.developed&&this.photoData!==null?(e(this.photoData),this):(this.developedCallbacks.add(e),this)}onError(e){return this.errorCallbacks.add(e),this}getFilename(){return this.filename}develop(e){this.developed||this.failed||(this.photoData=e,this.developed=!0,this.developedCallbacks.forEach(e=>{e(this.photoData)}),this.developedCallbacks.clear(),this.errorCallbacks.clear())}fail(e){this.developed||this.failed||(this.failed=!0,this.errorCallbacks.forEach(t=>{t(e)}),this.developedCallbacks.clear(),this.errorCallbacks.clear())}},F=class{validExtensions=[`.png`];pendingPhotos=new Map;constructor(e){this.send=e}take(e){this.validateFilename(e),p.debug(`Taking snapshot`,{filename:e});let t=new P(e);return this.pendingPhotos.set(t.getFilename(),t),this.send({type:b.SNAPSHOT,filename:e}),t}handleSnapshotResult(n){let r=this.pendingPhotos.get(n.filename);if(r===void 0){p.warn(`No pending photo found for filename`,{filename:n.filename,pendingFilenames:Array.from(this.pendingPhotos.keys())});return}if(this.pendingPhotos.delete(n.filename),n.error!==void 0){r.fail(new t(n.error,e.SNAPSHOT_FAILED));return}n.data!==void 0&&r.develop({filename:n.filename,data:n.data})}validateFilename(n){if(n===``||typeof n!=`string`)throw new t(`Filename must be a non-empty string`,e.INVALID_PARAMETER);if(!this.validExtensions.some(e=>n.toLowerCase().endsWith(e)))throw new t(`Invalid filename: "${n}". Filename must end with one of: ${this.validExtensions.join(`, `)}`,e.INVALID_PARAMETER);if(n.includes(`..`)||n.includes(`/`)||n.includes(`\\`))throw new t(`Filename cannot contain path separators or ".."`,e.INVALID_PARAMETER)}},I=class{send;constructor(e){this.send=e}sendInitialConfig(e){let t=this.buildUIConfig(e),n=this.buildViewerConfig(t,e.camera);n!==void 0&&this.sendConfig(n)}buildUIConfig(e){let t=this.extractUIValues(e);if(Object.values(t).some(e=>e!==void 0))return{...t.arEnabled!==void 0&&{arEnabled:t.arEnabled},...t.fullscreenEnabled!==void 0&&{fullscreenEnabled:t.fullscreenEnabled},...t.loadingIndicatorEnabled!==void 0&&{loadingIndicatorEnabled:t.loadingIndicatorEnabled}}}extractUIValues(e){return{arEnabled:e.arEnabled??e.ui?.arEnabled,fullscreenEnabled:e.fullscreenEnabled??e.ui?.fullscreenEnabled,loadingIndicatorEnabled:e.loadingIndicatorEnabled??e.ui?.loadingIndicatorEnabled}}buildViewerConfig(e,t){if(!(e===void 0&&t===void 0))return{...e!==void 0&&{ui:e},...t!==void 0&&{camera:t}}}setArEnabled(e){p.debug(`Setting AR button enabled: ${e}`),this.updateUIConfig({arEnabled:e})}setFullscreenEnabled(e){p.debug(`Setting fullscreen button enabled: ${e}`),this.updateUIConfig({fullscreenEnabled:e})}setLoadingIndicatorEnabled(e){p.debug(`Setting loading indicator enabled: ${e}`),this.updateUIConfig({loadingIndicatorEnabled:e})}updateUIConfig(e){p.debug(`Updating UI configuration`,e),Object.keys(e).length>0&&this.sendConfig({ui:e})}hideAllUI(){p.debug(`Hiding all UI elements`),this.sendUIConfig({arEnabled:!1,fullscreenEnabled:!1,loadingIndicatorEnabled:!1})}showAllUI(){p.debug(`Showing all UI elements`),this.sendUIConfig({arEnabled:!0,fullscreenEnabled:!0,loadingIndicatorEnabled:!0})}sendUIConfig(e){this.sendConfig({ui:e})}sendConfig(e){let t={type:b.CONFIG,config:e};p.debug(`Sending config`,t),this.send(t)}},L=class{attributes;readyStateTracker;messenger;viewerService;cameraApi;cameraPositionApi;snapshotApi;options;iframe;readyCallbacks=[];mutationFailedCallbacks=[];constructor(e){this.options=e,this.initializeLogging(),this.messenger=new A(()=>this.iframe?.contentWindow??null);let t=e=>{this.messenger.send(e)};this.attributes=new j(t,(e,t)=>{for(let n of this.mutationFailedCallbacks)n({attribute:e,value:t})}),this.readyStateTracker=new g(()=>{let e=this.readyCallbacks;this.readyCallbacks=[];for(let t of e)t(this)}),this.viewerService=new I(t),this.cameraApi=new M(t),this.cameraPositionApi=new N,this.snapshotApi=new F(t),this.registerHandlers(),this.messenger.start(),this.createAndConnectIframe()}registerHandlers(){this.messenger.on(b.READY,e=>{C(e)&&(p.info(`Server ready — flushing publisher queue`),this.messenger.markReady(),this.viewerService.sendInitialConfig(this.options))}),this.messenger.on(b.MUTATION,e=>{w(e)&&(this.attributes.handleMutationResult(e),this.readyStateTracker.handleMutationResult(e))}),this.messenger.on(b.SNAPSHOT,e=>{T(e)&&this.snapshotApi.handleSnapshotResult(e)}),this.messenger.on(b.CAMERA,e=>{E(e)&&this.cameraPositionApi.handlePositionUpdate(e)}),this.messenger.on(b.MAPPING,e=>{D(e)&&(this.attributes.handleMappingReceived(e),this.readyStateTracker.handleMappingReceived())})}initializeLogging(){this.options.debug===!0&&m(),p.info(`Initializing Virtualdisplay client`,{model:this.options.model,debug:this.options.debug,language:this.options.language})}createAndConnectIframe(){p.debug(`Creating iframe for Virtualdisplay viewer`),this.iframe=new n(this.options).create(),p.debug(`Iframe created, waiting for server READY`)}select(e,t){this.attributes.select(e,t)}getValues(e){return this.attributes.getValues(e)}getValue(e,t){return this.attributes.getValue(e,t)}onChange(e,t){this.attributes.onChange(e,t)}getAttribute(e){return this.attributes.getAttribute(e)}get isReady(){return this.readyStateTracker.isReady}onReady(e){if(this.readyStateTracker.isReady){e(this);return}this.readyCallbacks.push(e)}onMutationFailed(e){this.mutationFailedCallbacks.push(e)}get viewer(){return this.viewerService}get camera(){return this.cameraApi}get cameraPosition(){return this.cameraPositionApi}get snapshot(){return this.snapshotApi}destroy(){p.info(`Destroying Virtualdisplay client`),this.readyStateTracker.clear(),this.readyCallbacks=[],this.messenger.destroy(),this.iframe?.parentElement!==null&&this.iframe?.parentElement!==void 0&&this.iframe.parentElement.removeChild(this.iframe),this.iframe=void 0,p.debug(`Virtualdisplay client destroyed`)}};exports.Attribute=v,exports.AttributeValue=_,exports.Camera=M,exports.ERROR_CODES=e,exports.Photo=P,exports.Snapshot=F,exports.VirtualdisplayClient=L,exports.VirtualdisplayError=t,exports.VirtualdisplayViewerService=I,exports.enableDebugMode=m,exports.isDebugMode=h,Object.defineProperty(exports,`logger`,{enumerable:!0,get:function(){return p}});
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c={HANDSHAKE:"handshake",SESSION:"session",MUTATION:"mutation",STATE:"state",LOADING_INDICATOR:"loading_indicator",CAMERA:"camera",SNAPSHOT:"snapshot",MAPPING:"mapping",AR_ACTIVATE:"ar_activate",FULLSCREEN:"fullscreen",CONFIG:"config",ANNOTATION_TOGGLE:"annotation_toggle",FOCUS:"focus",PRICING:"pricing",QR_SHOWN:"qr_shown",SYNC:"sync"},W={FOCUS:"focus",UNFOCUS:"unfocus"},Nt={FOCUSED:"focused"},Mt={HIDDEN:"hidden"},Lt=new Set(Object.values(c));function zt(n){if(typeof n!="object"||n===null)return!1;const t=n;return typeof t.target=="string"?!1:typeof t.type=="string"&&Lt.has(t.type)}function Pt(n){const t=_(n);return t!==null&&t.type===c.HANDSHAKE}function Ft(n){const t=_(n);return t!==null&&t.type===c.SESSION&&typeof t.sessionId=="string"}function $t(n){const t=_(n);return t!==null&&t.type===c.MUTATION&&Array.isArray(t.results)}function Dt(n){const t=_(n);return t!==null&&t.type===c.SNAPSHOT&&("data"in t||"error"in t)}function Bt(n){const t=_(n);return t!==null&&t.type===c.CAMERA&&Array.isArray(t.transforms)}function Ut(n){const t=_(n);return t!==null&&t.type===c.MAPPING&&Array.isArray(t.attributes)}function Vt(n){const t=_(n);return t!==null&&t.type===c.LOADING_INDICATOR&&typeof t.progress=="number"}function jt(n){const t=_(n);return t!==null&&t.type===c.SYNC&&typeof t.connected=="boolean"}function Ht(n){const t=_(n);return t!==null&&t.type===c.CONFIG&&typeof t.viewerSettings=="object"}function qt(n){const t=_(n);return t!==null&&t.type===c.FOCUS&&typeof t.state=="string"}function Gt(n){const t=_(n);return t!==null&&t.type===c.PRICING&&typeof t.pricing=="object"&&t.pricing!==null}function _(n){return typeof n!="object"||n===null?null:n}class Q{constructor(t){this.processor=t}processor;pending=[];isReady=!1;enqueue(t){if(this.isReady){this.processor(t);return}this.pending.push(t)}markReady(){if(this.isReady||(this.isReady=!0,this.pending.length===0))return;const t=[...this.pending];this.pending.length=0;for(const e of t)this.processor(e)}get ready(){return this.isReady}get pendingCount(){return this.pending.length}hasPending(t){return this.pending.some(e=>e.type===t)}clear(){this.pending.length=0}}class Zt{constructor(t,e){this.getTarget=t,this.sourceId=`vd-${Math.random().toString(36).slice(2,8)}`,this.targetOrigin=e?.targetOrigin??"*",this.isValid=e?.isValid??zt,this.publisher=new Q(i=>this.post(i)),this.consumer=new Q(i=>this.routeToHandler(i)),this.shouldBuffer=e?.shouldBuffer??null,e?.bufferIncoming!==!0&&this.consumer.markReady()}getTarget;handlers=new Map;publisher;consumer;shouldBuffer;listener=null;sourceId;targetOrigin;isValid;on(t,e){this.handlers.set(t,e)}off(t){this.handlers.delete(t)}setTargetOrigin(t){this.targetOrigin=t}send(t){this.publisher.enqueue(t)}receive(t){if(this.isValid(t)){if(this.shouldBuffer!==null&&!this.shouldBuffer(t)){this.routeToHandler(t);return}this.consumer.enqueue(t)}}markReady(){this.publisher.markReady()}markConsumerReady(){this.consumer.markReady()}consumerHasPending(t){return this.consumer.hasPending(t)}start(){this.listener===null&&(this.listener=t=>{const{data:e}=t;if(!this.isValid(e)||e._source===this.sourceId)return;const i=this.getTarget();if(i!==null&&t.source!==null&&t.source!==i)return;const o=e;if(this.shouldBuffer!==null&&!this.shouldBuffer(o)){this.routeToHandler(o);return}this.consumer.enqueue(o)},window.addEventListener("message",this.listener))}destroy(){this.listener!==null&&(window.removeEventListener("message",this.listener),this.listener=null),this.publisher.clear(),this.consumer.clear(),this.handlers.clear()}get ready(){return this.publisher.ready}get pendingCount(){return this.publisher.pendingCount}post(t){const e=this.getTarget();e!==null&&e.postMessage({...t,_source:this.sourceId},this.targetOrigin)}routeToHandler(t){const e=this.handlers.get(t.type);if(e===void 0)return;const i=e(t);i instanceof Promise&&i.catch(o=>{const s=o instanceof Error?o.message:String(o);console.error(`Virtualdisplay: error handling ${t.type}: ${s}`)})}}class at{constructor(t){this.send=t}send;setEnabled(t){this.send({type:c.ANNOTATION_TOGGLE,enabled:t})}}class lt{constructor(t,e){this.value=t,this.attribute=e}value;attribute;isSelectedValue=!1;get isSelected(){return this.isSelectedValue}setSelected(t){this.isSelectedValue=t}}const S={NO_MAPPING:"NO_MAPPING",ATTRIBUTE_NOT_FOUND:"ATTRIBUTE_NOT_FOUND",VALUE_NOT_FOUND:"VALUE_NOT_FOUND",PARENT_NOT_FOUND:"PARENT_NOT_FOUND",INVALID_PARAMETER:"INVALID_PARAMETER",SNAPSHOT_FAILED:"SNAPSHOT_FAILED"};class f extends Error{code;constructor(t,e){super(t),this.name="VirtualdisplayError",this.code=e}static valueNotFound(t,e){return new f(`Value "${e}" not found for attribute "${t}"`,S.VALUE_NOT_FOUND)}static parentNotFound(t){return new f(`Parent element not found: ${t}`,S.PARENT_NOT_FOUND)}static invalidParameter(t){return new f(t,S.INVALID_PARAMETER)}}class ct{name;defaultValue;values;onSelect;onChangeCallback;constructor(t){this.name=t.name,this.defaultValue=t.defaultValue,this.onSelect=t.onSelect,this.values=this.createValues(t.values)}select(t){if(!this.values.has(t))throw f.valueNotFound(this.name,t);this.onSelect(this.name,t)}getValues(){return Array.from(this.values.values())}getValue(t){return this.values.get(t)}get selected(){for(const t of this.values.values())if(t.isSelected)return t.value}onChange(t){this.onChangeCallback=t}handleResult(t){let e;for(const i of this.values.values()){const o=i.value===t;i.setSelected(o),o&&(e=i)}e!==void 0&&this.onChangeCallback!==void 0&&this.onChangeCallback(e)}createValues(t){const e=new Map;for(const i of t){const o=new lt(i,this.name);i===this.defaultValue&&o.setSelected(!0),e.set(i,o)}return e}}class Wt{attributes=new Map;constructor(t,e,i){for(const o of t){const s=this.buildOptions(o,e);this.attributes.set(o.name,new ct(s))}this.onMutationFailed=i}onMutationFailed;get(t){return this.attributes.get(t)}getSelection(){const t={};for(const[e,i]of this.attributes){const o=i.selected;o!==void 0&&(t[e]=o)}return t}handleResults(t){for(const e of t){if(!e.success){this.onMutationFailed?.(e.name,e.value);continue}this.get(e.name)?.handleResult(e.value)}}buildOptions(t,e){const i={name:t.name,values:t.values,onSelect:(o,s)=>{e([{name:o,value:s}],!1)}};return t.defaultValue!==void 0?{...i,defaultValue:t.defaultValue}:i}}function Qt(n){const t=new Date(n.timestamp).toLocaleTimeString("en-GB",{hour12:!1}),e=n.level.toUpperCase().padEnd(5),i=n.trace_id?.slice(0,8)??"--------",o=n.msg,s=["timestamp","level","msg","service","trace_id","span_id"],r=Object.entries(n).filter(([l])=>!s.includes(l)).map(([l,d])=>`${l}=${JSON.stringify(d)}`).join(" ");return`${t} ${e} [${i}] ${o}${r?" "+r:""}`}function Yt(n){return JSON.stringify(n)}function Kt(n,t){const e=t?Qt(n):Yt(n);n.level==="error"?console.error(e):n.level==="warn"?console.warn(e):console.log(e)}function ut(n,t=0){const e={name:n.name,message:n.message};n.stack!==void 0&&(e.stack=n.stack);for(const i of Object.getOwnPropertyNames(n)){if(i==="name"||i==="message"||i==="stack"||i==="cause")continue;const o=n[i];o!==void 0&&(e[i]=o)}return n.cause!==void 0&&n.cause!==null&&(e.cause=n.cause instanceof Error&&t<5?ut(n.cause,t+1):String(n.cause)),e}function Xt(n){const t={};for(const[e,i]of Object.entries(n))t[e]=i instanceof Error?ut(i):i;return t}function Jt(){return new Date}function te(n){return n.toISOString()}function dt(){return typeof navigator>"u"?"":navigator.userAgent}function ee(){return typeof navigator>"u"?!1:navigator.platform==="MacIntel"&&navigator.maxTouchPoints>1}function ne(){return/iPhone|iPad|iPod/i.test(dt())||ee()}function ie(){return/Android/i.test(dt())}function oe(){return ne()||ie()}class se{constructor(t){this.config=t}config;log(t,e,i={}){const o=this.config.traceProvider?.()??{},s={timestamp:te(Jt()),level:t,msg:e,service:this.config.service,...o,...Xt(i)};Kt(s,this.config.isDev)}debug(t,e){this.config.isDev&&this.log("debug",t,e)}info(t,e){this.log("info",t,e)}warn(t,e){this.log("warn",t,e)}error(t,e){this.log("error",t,e)}}function ht(n,t){const e=t?.isDev!==void 0?t.isDev:typeof process<"u"?process.env.NODE_ENV!=="production":!0;return new se({service:n,isDev:e,traceProvider:t?.traceProvider})}function I(n){if(n!==void 0)return typeof n=="object"&&n!==null&&!Array.isArray(n)&&!(n instanceof Error)?n:n instanceof Error?{error:n.message}:{value:n}}function mt(n){return{debug:(t,e)=>n.debug(t,I(e)),info:(t,e)=>n.info(t,I(e)),warn:(t,e)=>n.warn(t,I(e)),error:(t,e)=>n.error(t,I(e))}}let pt=!1;exports.logger=mt(ht("client",{isDev:!1}));function ft(){pt=!0,exports.logger=mt(ht("client",{isDev:!0}))}function re(){return pt}class ae{constructor(t,e){this.send=t,this.onMutationFailed=e}send;onMutationFailed;registry;pendingCallbacks=[];handleMappingReceived(t){exports.logger.debug("Initializing from server mapping",{attributeCount:t.attributes.length}),this.registry=new Wt(t.attributes,(e,i)=>this.sendMutation(e,i),this.onMutationFailed),this.replayPendingCallbacks()}handleMutationResult(t){this.registry?.handleResults(t.results)}select(t,e){this.sendMutation([{name:t,value:e}],!1)}getValues(t){return this.registry?.get(t)?.getValues()??[]}getValue(t,e){return this.registry?.get(t)?.getValue(e)}onChange(t,e){if(this.registry===void 0){this.pendingCallbacks.push({name:t,callback:e});return}const i=this.registry.get(t);if(i===void 0){exports.logger.warn(`onChange: attribute "${t}" not found — callback will not fire`);return}i.onChange(e)}getAttribute(t){return this.registry?.get(t)}getSelection(){return this.registry?.getSelection()??{}}get hasMapping(){return this.registry!==void 0}sendMutation(t,e){const i={type:c.MUTATION,mutations:t,isInitial:e};this.send(i)}replayPendingCallbacks(){for(const{name:t,callback:e}of this.pendingCallbacks){const i=this.registry?.get(t);i===void 0&&exports.logger.warn(`onChange: attribute "${t}" not found — buffered callback will not fire`),i?.onChange(e)}this.pendingCallbacks.length=0}}let gt=class{constructor(t){this.send=t}send;commands=[];rotate(t){return this.validateFiniteNumber(t,"rotate"),this.commands.push({action:"rotate",value:t}),this}tilt(t){return this.validateFiniteNumber(t,"tilt"),this.commands.push({action:"tilt",value:t}),this}zoom(t){return this.validateFiniteNumber(t,"zoom"),this.commands.push({action:"zoom",value:t}),this}set(){if(this.commands.length===0)throw f.invalidParameter("No camera commands to execute. Call rotate(), tilt(), or zoom() before set().");const t={type:c.CAMERA,commands:this.commands};this.send(t),this.commands=[]}validateFiniteNumber(t,e){if(!Number.isFinite(t))throw f.invalidParameter(`${e}() requires a finite number, got ${String(t)}`)}reset(){const t={type:c.CAMERA,commands:[{action:"reset"}]};this.send(t)}};class le{state;limitsState;changeCallbacks=[];constructor(){this.state={rotation:0,tilt:0,zoom:100}}get rotation(){return this.state.rotation}get tilt(){return this.state.tilt}get zoom(){return this.state.zoom}onChange(t){this.changeCallbacks.push(t)}get limits(){return this.limitsState}applyLimits(t){this.limitsState=t;const e={rotation:this.rotation,tilt:this.tilt,zoom:this.zoom};for(const i of this.changeCallbacks)i(e)}handlePositionUpdate(t){this.update(t.transforms)}update(t){let e=!1;for(const i of t)switch(i.type){case"rotation":this.state.rotation=i.value,e=!0;break;case"tilt":this.state.tilt=i.value,e=!0;break;case"zoom":this.state.zoom=i.value,e=!0;break}if(e){const i={rotation:this.rotation,tilt:this.tilt,zoom:this.zoom};for(const o of this.changeCallbacks)o(i)}}}function ce(n,t){const e=n.filter(s=>ue(s,t));if(e.length===0)return;const i=Math.max(...e.map(Y)),o=e.filter(s=>Y(s)===i);return o.length===1?o[0]:void 0}function ue(n,t){return Object.entries(n.attributes).every(([e,i])=>t[e]===i)}function Y(n){return Object.keys(n.attributes).length}class bt{constructor(t,e){this.dispatchChange=t,this.dispatchSubmit=e}dispatchChange;dispatchSubmit;pricing;selection={};resolved;changeCallbacks=[];renderCallbacks=[];submitCallback;submitDefaultLabel;get current(){return this.resolved}get vatDisplay(){return this.pricing?.vatDisplay}get buttonLabel(){const t=this.pricing?.buttonLabel;if(t!=null&&t!=="")return t;if(this.submitDefaultLabel!==void 0&&this.submitDefaultLabel!=="")return this.submitDefaultLabel}get submittable(){return this.submitCallback===void 0?!1:this.pricing===void 0?!0:this.resolved?.availability==="available"}get submitEnabled(){return this.submittable&&this.buttonLabel!==void 0}onChange(t){this.changeCallbacks.push(t)}onSubmit(t,e){this.submitCallback=t,this.submitDefaultLabel=e?.defaultLabel,this.notifyRender()}onRender(t){return this.renderCallbacks.push(t),()=>{const e=this.renderCallbacks.indexOf(t);e!==-1&&this.renderCallbacks.splice(e,1)}}async submit(){if(!this.submittable)return;const t=this.resolved!==void 0?{attributes:this.resolved.attributes,reference:this.resolved.reference}:{attributes:{...this.selection},reference:""};this.dispatchSubmit(t),await this.submitCallback?.(t)}handlePricingReceived(t){this.pricing=t,this.recompute()}handleSelectionChanged(t){this.selection=t,this.recompute()}recompute(){this.resolved=this.resolve();for(const t of this.changeCallbacks)t(this.resolved);this.dispatchChange(this.resolved),this.notifyRender()}notifyRender(){for(const t of this.renderCallbacks)t()}resolve(){if(this.pricing===void 0)return;const t=ce(this.pricing.rules,this.selection);if(!(t===void 0||t.availability===Mt.HIDDEN))return{attributes:{...this.selection},reference:t.reference,price:t.priceCents,currency:this.pricing.currency,availability:t.availability}}}class vt{constructor(t,e){this.send=t,this.dispatch=e}send;dispatch;focused=null;attributes=[];changeCallbacks=[];get current(){return this.focused}set(t){if(typeof t!="string"||t.length===0)throw f.invalidParameter(`set() requires a non-empty component name, got ${String(t)}`);this.send({type:c.FOCUS,action:W.FOCUS,component:t})}clear(){this.send({type:c.FOCUS,action:W.UNFOCUS})}onChange(t){this.changeCallbacks.push(t)}handleStateReceived(t){t.state===Nt.FOCUSED&&t.component!==void 0?(this.focused=t.component,this.attributes=t.attributes??[]):(this.focused=null,this.attributes=[]);const e=this.focused!==null?{component:this.focused,attributes:this.attributes}:null;for(const i of this.changeCallbacks)i(e);this.dispatch(e)}}class yt{constructor(t){this.filename=t}filename;developedCallbacks=new Set;errorCallbacks=new Set;developed=!1;failed=!1;photoData=null;onDeveloped(t){return this.developed&&this.photoData!==null?(t(this.photoData),this):(this.developedCallbacks.add(t),this)}onError(t){return this.errorCallbacks.add(t),this}getFilename(){return this.filename}develop(t){this.developed||this.failed||(this.photoData=t,this.developed=!0,this.developedCallbacks.forEach(e=>{e(this.photoData)}),this.developedCallbacks.clear(),this.errorCallbacks.clear())}fail(t){this.developed||this.failed||(this.failed=!0,this.errorCallbacks.forEach(e=>{e(t)}),this.developedCallbacks.clear(),this.errorCallbacks.clear())}}const K=3e4;class wt{constructor(t){this.send=t}send;validExtensions=[".png"];pendingPhotos=new Map;take(t){this.validateFilename(t),exports.logger.debug("Taking snapshot",{filename:t});const e=new yt(t),i=setTimeout(()=>{this.pendingPhotos.delete(t),exports.logger.warn("Snapshot timed out",{filename:t}),e.fail(new f(`Snapshot timed out: the viewer did not respond within ${K}ms`,S.SNAPSHOT_FAILED))},K);return this.pendingPhotos.set(t,{photo:e,timeout:i}),this.send({type:c.SNAPSHOT,filename:t}),e}handleSnapshotResult(t){const e=this.pendingPhotos.get(t.filename);if(e===void 0){exports.logger.warn("No pending photo found for filename",{filename:t.filename,pendingFilenames:Array.from(this.pendingPhotos.keys())});return}clearTimeout(e.timeout),this.pendingPhotos.delete(t.filename);const{photo:i}=e;if(t.error!==void 0){i.fail(new f(t.error,S.SNAPSHOT_FAILED));return}t.data!==void 0&&i.develop({filename:t.filename,data:t.data})}clear(){if(this.pendingPhotos.size===0)return;const t=new f("Client destroyed before snapshot completed",S.SNAPSHOT_FAILED);for(const{photo:e,timeout:i}of this.pendingPhotos.values())clearTimeout(i),e.fail(t);this.pendingPhotos.clear()}validateFilename(t){if(t===""||typeof t!="string")throw new f("Filename must be a non-empty string",S.INVALID_PARAMETER);if(!this.validExtensions.some(i=>t.toLowerCase().endsWith(i)))throw new f(`Invalid filename: "${t}". Filename must end with one of: ${this.validExtensions.join(", ")}`,S.INVALID_PARAMETER);if(t.includes("..")||t.includes("/")||t.includes("\\"))throw new f('Filename cannot contain path separators or ".."',S.INVALID_PARAMETER)}}class de{container=null;attach(t){this.container=t}dispatch(t,e,i=!1){const o=new CustomEvent(t,{detail:e,cancelable:i});return this.container?.dispatchEvent(o),o}on(t,e){const i=o=>{const s=o,r={...s.detail,preventDefault:()=>{s.preventDefault()}};e(r)};return this.container?.addEventListener(t,i),()=>{this.container?.removeEventListener(t,i)}}}const he={},me="en",_t=["en","nl","de"],G=["baseLocale"],X=[];let J,tt;function pe(n){if(X.length===0)return;const t=typeof n=="string"?n:n.href;if(J===t)return tt;const e=new URL(t,"http://dummy.com");let i;for(const o of X)if(new he(o.match,e.href).exec(e.href)){i=o;break}return J=t,tt=i,i}function Ct(n){const t=pe(n);return t&&t.exclude!==!0&&Array.isArray(t.strategy)?t.strategy:G}const q=typeof window>"u";globalThis.__paraglide=globalThis.__paraglide??{};globalThis.__paraglide.ssr=globalThis.__paraglide.ssr??{};let et=!1,h=()=>{let n=G;!q&&typeof window<"u"&&window.location?.href&&(n=Ct(window.location.href));const t=fe(n);if(t)return et||(et=!0,St(t,{reload:!1})),t;throw new Error("No locale found. Read the docs https://paraglidejs.com/errors#no-locale-found")};function fe(n,t){let e;for(const i of n){if(i==="baseLocale")e=me;else if(At(i)&&O.has(i)){const s=O.get(i);if(s){const r=s.getLocale();if(r instanceof Promise)continue;if(r!==void 0)return be(r)}}const o=kt(e);if(o)return o}}const ge=n=>{window.location.reload()};let St=(n,t)=>{const e={reload:!0,...t};let i;try{i=h()}catch{}const o=[];let s=G;!q&&typeof window<"u"&&window.location?.href&&(s=Ct(window.location.href));for(const l of s)if(l!=="baseLocale"&&At(l)&&O.has(l)){const d=O.get(l);if(d){let u=d.setLocale(n);u instanceof Promise&&(u=u.catch(p=>{throw new Error(`Custom strategy "${l}" setLocale failed.`,{cause:p})}),o.push(u))}}const r=()=>{!q&&e.reload&&window.location&&n!==i&&ge()};if(o.length)return Promise.all(o).then(()=>{r()});r()};function kt(n){if(typeof n!="string")return;const t=n.toLowerCase();for(const e of _t)if(e.toLowerCase()===t)return e}function be(n){const t=kt(n);if(t)return t;throw new Error(`Invalid locale: ${n}. Expected one of: ${_t.join(", ")}`)}const O=new Map;function At(n){return typeof n=="string"&&/^custom-[A-Za-z0-9_-]+$/.test(n)}const ve=()=>"Activate AR",ye=()=>"AR activeren",we=()=>"AR aktivieren",_e=((n={},t={})=>{const e=t.locale??h();return e==="en"?ve():e==="nl"?ye():we()}),Ce=()=>"Scan to view in AR",Se=()=>"Scan om in AR te bekijken",ke=()=>"Scannen für AR-Ansicht",Ae=((n={},t={})=>{const e=t.locale??h();return e==="en"?Ce():e==="nl"?Se():ke()}),Ee=()=>"Use your smartphone camera to scan this QR code",xe=()=>"Gebruik de camera van je smartphone om deze QR-code te scannen",Te=()=>"Verwende die Kamera deines Smartphones, um diesen QR-Code zu scannen",Re=((n={},t={})=>{const e=t.locale??h();return e==="en"?Ee():e==="nl"?xe():Te()}),Ie=()=>"Your phone will open the 3D model in AR mode.",Oe=()=>"Je telefoon opent het 3D-model in AR-modus.",Ne=()=>"Dein Telefon öffnet das 3D-Modell im AR-Modus.",Me=((n={},t={})=>{const e=t.locale??h();return e==="en"?Ie():e==="nl"?Oe():Ne()}),Le=()=>"Close",ze=()=>"Sluiten",Pe=()=>"Schließen",Fe=((n={},t={})=>{const e=t.locale??h();return e==="en"?Le():e==="nl"?ze():Pe()}),$e=()=>"Fullscreen",De=()=>"Volledig scherm",Be=()=>"Vollbild",Ue=((n={},t={})=>{const e=t.locale??h();return e==="en"?$e():e==="nl"?De():Be()}),Ve=()=>"Downloading",je=()=>"Downloaden",He=()=>"Herunterladen",Et=((n={},t={})=>{const e=t.locale??h();return e==="en"?Ve():e==="nl"?je():He()}),qe=()=>"Rendering",Ge=()=>"Renderen",Ze=()=>"Rendern",We=((n={},t={})=>{const e=t.locale??h();return e==="en"?qe():e==="nl"?Ge():Ze()}),Qe=()=>"Screenshot",Ye=()=>"Screenshot",Ke=()=>"Screenshot",Xe=((n={},t={})=>{const e=t.locale??h();return e==="en"?Qe():e==="nl"?Ye():Ke()}),Je=()=>"Configure",tn=()=>"Configureren",en=()=>"Konfigurieren",nn=((n={},t={})=>{const e=t.locale??h();return e==="en"?Je():e==="nl"?tn():en()}),on=()=>"Close",sn=()=>"Sluiten",rn=()=>"Schließen",an=((n={},t={})=>{const e=t.locale??h();return e==="en"?on():e==="nl"?sn():rn()}),ln=()=>"Reset camera",cn=()=>"Camera resetten",un=()=>"Kamera zurücksetzen",dn=((n={},t={})=>{const e=t.locale??h();return e==="en"?ln():e==="nl"?cn():un()}),hn=()=>"Zoom in",mn=()=>"Inzoomen",pn=()=>"Hineinzoomen",fn=((n={},t={})=>{const e=t.locale??h();return e==="en"?hn():e==="nl"?mn():pn()}),gn=()=>"Zoom out",bn=()=>"Uitzoomen",vn=()=>"Herauszoomen",yn=((n={},t={})=>{const e=t.locale??h();return e==="en"?gn():e==="nl"?bn():vn()}),wn=()=>"Rotate left",_n=()=>"Naar links draaien",Cn=()=>"Nach links drehen",Sn=((n={},t={})=>{const e=t.locale??h();return e==="en"?wn():e==="nl"?_n():Cn()}),kn=()=>"Rotate right",An=()=>"Naar rechts draaien",En=()=>"Nach rechts drehen",xn=((n={},t={})=>{const e=t.locale??h();return e==="en"?kn():e==="nl"?An():En()}),Tn=()=>"Tilt up",Rn=()=>"Omhoog kantelen",In=()=>"Nach oben kippen",On=((n={},t={})=>{const e=t.locale??h();return e==="en"?Tn():e==="nl"?Rn():In()}),Nn=()=>"Tilt down",Mn=()=>"Omlaag kantelen",Ln=()=>"Nach unten kippen",zn=((n={},t={})=>{const e=t.locale??h();return e==="en"?Nn():e==="nl"?Mn():Ln()}),Pn=()=>"Working…",Fn=()=>"Bezig…",$n=()=>"Läuft…",Dn=((n={},t={})=>{const e=t.locale??h();return e==="en"?Pn():e==="nl"?Fn():$n()}),Bn=()=>"Done",Un=()=>"Gelukt",Vn=()=>"Fertig",jn=((n={},t={})=>{const e=t.locale??h();return e==="en"?Bn():e==="nl"?Un():Vn()}),Hn=()=>"Failed",qn=()=>"Mislukt",Gn=()=>"Fehlgeschlagen",Zn=((n={},t={})=>{const e=t.locale??h();return e==="en"?Hn():e==="nl"?qn():Gn()});const Wn={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":2,"stroke-linecap":"round","stroke-linejoin":"round"};const xt=([n,t,e])=>{const i=document.createElementNS("http://www.w3.org/2000/svg",n);return Object.keys(t).forEach(o=>{i.setAttribute(o,String(t[o]))}),e?.length&&e.forEach(o=>{const s=xt(o);i.appendChild(s)}),i},Tt=(n,t={})=>{const i={...Wn,...t};return xt(["svg",i,n])};const Qn=[["path",{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"}],["path",{d:"m3.3 7 8.7 5 8.7-5"}],["path",{d:"M12 22V12"}]];const Yn=[["path",{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"}],["circle",{cx:"12",cy:"13",r:"3"}]];const Rt=[["path",{d:"m6 9 6 6 6-6"}]];const Kn=[["path",{d:"m15 18-6-6 6-6"}]];const Xn=[["path",{d:"m9 18 6-6-6-6"}]];const Jn=[["path",{d:"m18 15-6-6-6 6"}]];const ti=[["path",{d:"M15 3h6v6"}],["path",{d:"m21 3-7 7"}],["path",{d:"m3 21 7-7"}],["path",{d:"M9 21H3v-6"}]];const ei=[["path",{d:"m14 10 7-7"}],["path",{d:"M20 10h-6V4"}],["path",{d:"m3 21 7-7"}],["path",{d:"M4 14h6v6"}]];const ni=[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"}],["path",{d:"M3 3v5h5"}]];const ii=[["path",{d:"M10 5H3"}],["path",{d:"M12 19H3"}],["path",{d:"M14 3v4"}],["path",{d:"M16 17v4"}],["path",{d:"M21 12h-9"}],["path",{d:"M21 19h-5"}],["path",{d:"M21 5h-7"}],["path",{d:"M8 10v4"}],["path",{d:"M8 12H3"}]];const oi=[["path",{d:"M18 6 6 18"}],["path",{d:"m6 6 12 12"}]];const si=[["circle",{cx:"11",cy:"11",r:"8"}],["line",{x1:"21",x2:"16.65",y1:"21",y2:"16.65"}],["line",{x1:"11",x2:"11",y1:"8",y2:"14"}],["line",{x1:"8",x2:"14",y1:"11",y2:"11"}]];const ri=[["circle",{cx:"11",cy:"11",r:"8"}],["line",{x1:"21",x2:"16.65",y1:"21",y2:"16.65"}],["line",{x1:"8",x2:"14",y1:"11",y2:"11"}]];function y(n,{size:t=20,strokeWidth:e=1.75}={}){return Tt(n,{width:t,height:t,"stroke-width":e})}const g={ar:n=>y(Qn,n),fullscreen:n=>y(ti,n),exitFullscreen:n=>y(ei,n),screenshot:n=>y(Yn,n),tiltUp:n=>y(Jn,n),tiltDown:n=>y(Rt,n),rotateLeft:n=>y(Kn,n),rotateRight:n=>y(Xn,n),zoomIn:n=>y(si,n),zoomOut:n=>y(ri,n),reset:n=>y(ni,n),configurator:n=>y(ii,n),close:n=>y(oi,n)};class b{element;constructor({variant:t="default",size:e="default",label:i,icon:o,onClick:s,disabled:r=!1}={}){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}setIcon(t){const e=this.element.querySelector("svg");e!==null?e.replaceWith(t):this.element.appendChild(t)}}const m={semantic:{error:"#dc2626"},neutral:{500:"#737373",600:"#525252",900:"#171717"},white:"#ffffff",black:"#000000"},a={0:"0",.5:"0.125rem",1:"0.25rem",1.5:"0.375rem",2:"0.5rem",3:"0.75rem",4:"1rem",5:"1.25rem",6:"1.5rem",8:"2rem",9:"2.25rem"};class ai{element;constructor(){this.element=document.createElement("div"),Object.assign(this.element.style,{background:m.white,borderRadius:a[3],padding:a[6],boxShadow:`0 ${a[2]} ${a[8]} oklch(0% 0 0 / 20%)`,maxWidth:"20rem",width:"100%"})}}class li{constructor(t={}){this.options=t,this.card=new ai,this.backdrop=this.createBackdrop(),this.backdrop.appendChild(this.card.element)}options;card;backdrop;keyHandler=null;open(){document.body.appendChild(this.backdrop),this.keyHandler=t=>{t.key==="Escape"&&this.close()},document.addEventListener("keydown",this.keyHandler)}close(){this.backdrop.remove(),this.keyHandler!==null&&(document.removeEventListener("keydown",this.keyHandler),this.keyHandler=null),this.options.onClose?.()}createBackdrop(){const t=document.createElement("div");return Object.assign(t.style,{position:"fixed",inset:a[0],background:"oklch(0% 0 0 / 50%)",zIndex:"9999",display:"flex",alignItems:"center",justifyContent:"center"}),t.addEventListener("click",e=>{e.target===t&&this.close()}),t}}class ci{element;selectCallback=null;constructor(t,e,i){this.element=document.createElement("div"),this.element.className="ui-toggle-group";for(let o=0;o<t.length;o++){const s=t[o],r=document.createElement("button");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",()=>{this.selectCallback?.(s)}),this.element.appendChild(r)}}setSelected(t){for(const e of this.element.querySelectorAll(".ui-toggle-group-item")){const i=e.dataset.value===t;e.dataset.state=i?"on":"off",e.setAttribute("aria-pressed",i?"true":"false")}}onSelect(t){this.selectCallback=t}}class ui{element;select;constructor(t,e,i,o,s){this.select=document.createElement("select"),this.select.className="ui-native-select",this.select.dataset.name=t,this.select.setAttribute("aria-label",i);const r=document.createElement("option");r.value="",r.disabled=!0,r.textContent=i,this.select.appendChild(r);let l=!1;for(let u=0;u<e.length;u++){const p=e[u],v=document.createElement("option");v.value=p,v.textContent=s?.[u]??p,p===o&&(v.selected=!0,l=!0),this.select.appendChild(v)}l||(r.selected=!0);const d=Tt(Rt,{width:16,height:16,"stroke-width":2});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)}setSelected(t){this.select.value=t}onSelect(t){this.select.addEventListener("change",()=>{t(this.select.value)})}}const w={fontFamily:{sans:["Mona Sans","ui-sans-serif","system-ui","sans-serif","Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"]},fontSize:{xs:"0.75rem",sm:"0.875rem",base:"1rem",lg:"1.125rem"},fontWeight:{medium:"500",semibold:"600"}},E=w.fontFamily.sans.join(", "),di=`
|
|
2
|
+
--primary: oklch(5% 0 0);
|
|
3
|
+
--primary-foreground: oklch(100% 0 0);
|
|
4
|
+
--secondary: oklch(92% 0 0);
|
|
5
|
+
--secondary-foreground: oklch(5% 0 0);
|
|
6
|
+
--background: oklch(100% 0 0);
|
|
7
|
+
--foreground: oklch(5% 0 0);
|
|
8
|
+
--border: oklch(92% 0 0);
|
|
9
|
+
--ring: oklch(44% 0 0);
|
|
10
|
+
--radius: 0.625rem;
|
|
11
|
+
--accent: oklch(92% 0 0);
|
|
12
|
+
--accent-foreground: oklch(5% 0 0);
|
|
13
|
+
--muted-foreground: oklch(44% 0 0);
|
|
14
|
+
`,hi=`
|
|
15
|
+
:root { ${di} }
|
|
16
|
+
|
|
17
|
+
/* ── Button ──────────────────────────────────────────────── */
|
|
18
|
+
.ui-btn {
|
|
19
|
+
display: inline-flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
justify-content: center;
|
|
22
|
+
gap: 0.5rem;
|
|
23
|
+
border: 1px solid transparent;
|
|
24
|
+
border-radius: var(--radius);
|
|
25
|
+
font-family: ${E};
|
|
26
|
+
font-size: 0.875rem;
|
|
27
|
+
font-weight: 600;
|
|
28
|
+
white-space: nowrap;
|
|
29
|
+
cursor: pointer;
|
|
30
|
+
transition: all 200ms;
|
|
31
|
+
flex-shrink: 0;
|
|
32
|
+
}
|
|
33
|
+
.ui-btn:active { transform: scale(0.98); }
|
|
34
|
+
.ui-btn:disabled { opacity: 0.5; pointer-events: none; }
|
|
35
|
+
.ui-btn svg { inline-size: 1rem; block-size: 1rem; pointer-events: none; flex-shrink: 0; }
|
|
36
|
+
|
|
37
|
+
.ui-btn--default {
|
|
38
|
+
background: var(--primary);
|
|
39
|
+
color: var(--primary-foreground);
|
|
40
|
+
box-shadow: 0 1px 3px oklch(5% 0 0 / 20%);
|
|
41
|
+
}
|
|
42
|
+
.ui-btn--default:hover { background: oklch(10% 0 0); }
|
|
43
|
+
|
|
44
|
+
.ui-btn--outline {
|
|
45
|
+
background: var(--background);
|
|
46
|
+
color: var(--foreground);
|
|
47
|
+
border-color: var(--border);
|
|
48
|
+
box-shadow: 0 1px 2px oklch(5% 0 0 / 8%);
|
|
49
|
+
}
|
|
50
|
+
.ui-btn--outline:hover { background: var(--accent); border-color: oklch(85% 0 0); }
|
|
51
|
+
|
|
52
|
+
.ui-btn--secondary {
|
|
53
|
+
background: var(--secondary);
|
|
54
|
+
color: var(--secondary-foreground);
|
|
55
|
+
box-shadow: 0 1px 2px oklch(5% 0 0 / 8%);
|
|
56
|
+
}
|
|
57
|
+
.ui-btn--secondary:hover { background: oklch(88% 0 0); }
|
|
58
|
+
|
|
59
|
+
.ui-btn--ghost { background: transparent; color: var(--foreground); }
|
|
60
|
+
.ui-btn--ghost:hover { background: var(--accent); }
|
|
61
|
+
|
|
62
|
+
.ui-btn--size-default { block-size: 2.25rem; padding: 0 1rem; }
|
|
63
|
+
.ui-btn--size-sm { block-size: 2rem; padding: 0 0.75rem; border-radius: calc(var(--radius) - 0.125rem); }
|
|
64
|
+
.ui-btn--size-lg { block-size: 2.5rem; padding: 0 1.5rem; }
|
|
65
|
+
.ui-btn--size-icon { inline-size: 2.25rem; block-size: 2.25rem; padding: 0; }
|
|
66
|
+
.ui-btn--size-icon-sm { inline-size: 2rem; block-size: 2rem; padding: 0; }
|
|
67
|
+
.ui-btn--size-icon-lg { inline-size: 2.5rem; block-size: 2.5rem; padding: 0; }
|
|
68
|
+
|
|
69
|
+
/* ── Toggle group ────────────────────────────────────────── */
|
|
70
|
+
.ui-toggle-group { display: inline-flex; flex-wrap: wrap; gap: 0.25rem; }
|
|
71
|
+
|
|
72
|
+
.ui-toggle-group-item {
|
|
73
|
+
display: inline-flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
justify-content: center;
|
|
76
|
+
block-size: 2rem;
|
|
77
|
+
padding: 0 0.75rem;
|
|
78
|
+
border: 1px solid var(--border);
|
|
79
|
+
border-radius: var(--radius);
|
|
80
|
+
background: var(--background);
|
|
81
|
+
color: var(--foreground);
|
|
82
|
+
font-family: ${E};
|
|
83
|
+
font-size: 0.875rem;
|
|
84
|
+
font-weight: 600;
|
|
85
|
+
cursor: pointer;
|
|
86
|
+
white-space: nowrap;
|
|
87
|
+
transition: all 200ms;
|
|
88
|
+
box-shadow: 0 1px 2px oklch(5% 0 0 / 8%);
|
|
89
|
+
}
|
|
90
|
+
.ui-toggle-group-item:hover { background: var(--accent); border-color: oklch(85% 0 0); }
|
|
91
|
+
.ui-toggle-group-item:active { transform: scale(0.98); }
|
|
92
|
+
.ui-toggle-group-item:focus-visible {
|
|
93
|
+
outline: none;
|
|
94
|
+
border-color: var(--ring);
|
|
95
|
+
box-shadow: 0 0 0 3px oklch(5% 0 0 / 12%);
|
|
96
|
+
}
|
|
97
|
+
.ui-toggle-group-item[data-state="on"] {
|
|
98
|
+
background: var(--primary);
|
|
99
|
+
color: var(--primary-foreground);
|
|
100
|
+
border-color: var(--primary);
|
|
101
|
+
}
|
|
102
|
+
.ui-toggle-group-item[data-state="on"]:hover { background: oklch(10% 0 0); }
|
|
103
|
+
|
|
104
|
+
/* ── Native select ───────────────────────────────────────── */
|
|
105
|
+
.ui-native-select-wrap {
|
|
106
|
+
position: relative;
|
|
107
|
+
display: inline-flex;
|
|
108
|
+
min-inline-size: 8rem;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.ui-native-select {
|
|
112
|
+
display: block;
|
|
113
|
+
inline-size: 100%;
|
|
114
|
+
block-size: 2.25rem;
|
|
115
|
+
padding: 0 2.25rem 0 0.75rem;
|
|
116
|
+
border: 1px solid var(--border);
|
|
117
|
+
border-radius: var(--radius);
|
|
118
|
+
background: var(--background);
|
|
119
|
+
appearance: none;
|
|
120
|
+
color: var(--foreground);
|
|
121
|
+
font-family: ${E};
|
|
122
|
+
font-size: 0.875rem;
|
|
123
|
+
font-weight: 400;
|
|
124
|
+
cursor: pointer;
|
|
125
|
+
transition: color 200ms, box-shadow 200ms, border-color 200ms;
|
|
126
|
+
box-shadow: 0 1px 2px oklch(5% 0 0 / 8%);
|
|
127
|
+
}
|
|
128
|
+
.ui-native-select:hover { border-color: oklch(85% 0 0); }
|
|
129
|
+
.ui-native-select:focus-visible {
|
|
130
|
+
outline: none;
|
|
131
|
+
border-color: var(--ring);
|
|
132
|
+
box-shadow: 0 0 0 3px oklch(5% 0 0 / 12%);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.ui-native-select-icon {
|
|
136
|
+
position: absolute;
|
|
137
|
+
inset-block-start: 50%;
|
|
138
|
+
inset-inline-end: 0.625rem;
|
|
139
|
+
transform: translateY(-50%);
|
|
140
|
+
color: var(--muted-foreground);
|
|
141
|
+
pointer-events: none;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* ── Annotation layer ───────────────────────────────────── */
|
|
145
|
+
.vd-annotations-layer {
|
|
146
|
+
position: absolute;
|
|
147
|
+
inset-block-start: 0;
|
|
148
|
+
inset-inline-start: 0;
|
|
149
|
+
inline-size: 100%;
|
|
150
|
+
block-size: 100%;
|
|
151
|
+
pointer-events: none;
|
|
152
|
+
overflow: visible !important; /* override CSS2DRenderer inline style */
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.vd-annotation-anchor {
|
|
156
|
+
position: relative;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.vd-annotation-marker {
|
|
160
|
+
display: flex;
|
|
161
|
+
align-items: center;
|
|
162
|
+
justify-content: center;
|
|
163
|
+
inline-size: 1.75rem;
|
|
164
|
+
block-size: 1.75rem;
|
|
165
|
+
border-radius: 50%;
|
|
166
|
+
border: 2px solid oklch(100% 0 0);
|
|
167
|
+
background: var(--primary);
|
|
168
|
+
color: var(--primary-foreground);
|
|
169
|
+
font-family: ${E};
|
|
170
|
+
font-size: 0.8125rem;
|
|
171
|
+
font-weight: 600;
|
|
172
|
+
cursor: pointer;
|
|
173
|
+
pointer-events: auto;
|
|
174
|
+
box-shadow: 0 2px 8px oklch(5% 0 0 / 20%);
|
|
175
|
+
transition: transform 100ms ease;
|
|
176
|
+
position: relative;
|
|
177
|
+
}
|
|
178
|
+
.vd-annotation-marker:hover { transform: scale(1.1); }
|
|
179
|
+
.vd-annotation-marker:focus-visible {
|
|
180
|
+
outline: 2px solid var(--ring);
|
|
181
|
+
outline-offset: 2px;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.vd-annotation-popup {
|
|
185
|
+
position: absolute;
|
|
186
|
+
inset-block-end: calc(100% + 0.5rem);
|
|
187
|
+
inset-inline-start: 50%;
|
|
188
|
+
transform: translateX(-50%);
|
|
189
|
+
background: var(--background);
|
|
190
|
+
color: var(--foreground);
|
|
191
|
+
border: 1px solid var(--border);
|
|
192
|
+
border-radius: var(--radius);
|
|
193
|
+
padding: 0.75rem 1rem;
|
|
194
|
+
max-inline-size: 15rem;
|
|
195
|
+
box-shadow: 0 4px 6px oklch(5% 0 0 / 8%), 0 2px 4px oklch(5% 0 0 / 6%);
|
|
196
|
+
pointer-events: auto;
|
|
197
|
+
white-space: normal;
|
|
198
|
+
}
|
|
199
|
+
.vd-annotation-popup:focus { outline: none; }
|
|
200
|
+
|
|
201
|
+
.vd-annotation-popup-close {
|
|
202
|
+
position: absolute;
|
|
203
|
+
inset-block-start: 0.375rem;
|
|
204
|
+
inset-inline-end: 0.375rem;
|
|
205
|
+
display: flex;
|
|
206
|
+
align-items: center;
|
|
207
|
+
justify-content: center;
|
|
208
|
+
inline-size: 1.25rem;
|
|
209
|
+
block-size: 1.25rem;
|
|
210
|
+
padding: 0;
|
|
211
|
+
border: none;
|
|
212
|
+
border-radius: calc(var(--radius) - 4px);
|
|
213
|
+
background: transparent;
|
|
214
|
+
color: var(--muted-foreground);
|
|
215
|
+
cursor: pointer;
|
|
216
|
+
pointer-events: auto;
|
|
217
|
+
}
|
|
218
|
+
.vd-annotation-popup-close:hover {
|
|
219
|
+
color: var(--foreground);
|
|
220
|
+
background: var(--secondary);
|
|
221
|
+
}
|
|
222
|
+
.vd-annotation-popup-close:focus-visible {
|
|
223
|
+
outline: 2px solid var(--ring);
|
|
224
|
+
outline-offset: 1px;
|
|
225
|
+
}
|
|
226
|
+
.vd-annotation-popup-close svg {
|
|
227
|
+
inline-size: 0.875rem;
|
|
228
|
+
block-size: 0.875rem;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
232
|
+
.vd-annotation-popup {
|
|
233
|
+
animation: vd-popup-in 150ms ease;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
@keyframes vd-popup-in {
|
|
238
|
+
from { opacity: 0; transform: translateX(-50%) translateY(4px); }
|
|
239
|
+
to { opacity: 1; transform: translateX(-50%) translateY(0); }
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.vd-annotation-popup-title {
|
|
243
|
+
font-family: ${E};
|
|
244
|
+
font-size: 0.875rem;
|
|
245
|
+
font-weight: 600;
|
|
246
|
+
line-height: 1.25rem;
|
|
247
|
+
/* Keep the title clear of the absolutely positioned close button. */
|
|
248
|
+
padding-inline-end: 1.5rem;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.vd-annotation-popup-description {
|
|
252
|
+
font-family: ${E};
|
|
253
|
+
font-size: 0.8125rem;
|
|
254
|
+
font-weight: 400;
|
|
255
|
+
line-height: 1.125rem;
|
|
256
|
+
color: var(--muted-foreground);
|
|
257
|
+
margin-block-start: 0.25rem;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/* ── QR modal ────────────────────────────────────────────── */
|
|
261
|
+
/* The slot the QR renders into. While loading it is a calm pulsing
|
|
262
|
+
placeholder of the same size, so the modal opens instantly and the QR
|
|
263
|
+
swaps in without any layout shift. */
|
|
264
|
+
.ui-qr-slot {
|
|
265
|
+
inline-size: 6rem;
|
|
266
|
+
block-size: 6rem;
|
|
267
|
+
border-radius: 0.25rem;
|
|
268
|
+
overflow: hidden;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.ui-qr-slot img {
|
|
272
|
+
inline-size: 100%;
|
|
273
|
+
block-size: 100%;
|
|
274
|
+
display: block;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.ui-qr-slot--loading {
|
|
278
|
+
background: var(--secondary);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
282
|
+
.ui-qr-slot--loading {
|
|
283
|
+
animation: vd-qr-pulse 1.6s ease-in-out infinite;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
@keyframes vd-qr-pulse {
|
|
288
|
+
0%, 100% { opacity: 1; }
|
|
289
|
+
50% { opacity: 0.55; }
|
|
290
|
+
}
|
|
291
|
+
`;let nt=!1;function It(){if(nt||typeof document>"u")return;nt=!0;const n=document.createElement("style");n.id="vd-ui-vanilla",n.textContent=hi,document.head.appendChild(n)}const mi=w.fontFamily.sans.join(", ");class pi{qrLib=null;dialog=null;qrSlot=null;show(){this.hide(),It(),this.dialog=new li({onClose:()=>{this.dialog=null,this.qrSlot=null}}),Object.assign(this.dialog.card.element.style,{display:"flex",flexDirection:"column",alignItems:"center",gap:a[3],fontFamily:mi}),this.dialog.card.element.appendChild(this.createText(Ae(),{fontSize:w.fontSize.base,fontWeight:w.fontWeight.semibold,color:m.neutral[900]})),this.dialog.card.element.appendChild(this.createText(Re(),{fontSize:w.fontSize.sm,color:m.neutral[600]})),this.qrSlot=this.createQrSlot(),this.dialog.card.element.appendChild(this.qrSlot),this.dialog.card.element.appendChild(this.createText(Me(),{fontSize:w.fontSize.xs,color:m.neutral[500]}));const t=new b({variant:"outline",label:Fe(),onClick:()=>{this.hide()}});this.dialog.card.element.appendChild(t.element),this.dialog.open()}async update(t){this.qrLib??=await Promise.resolve().then(()=>require("./browser-DfB_An57.cjs")).then(i=>i.browser);const e=await this.qrLib.toDataURL(t,{width:256,margin:4,errorCorrectionLevel:"M",color:{dark:m.black,light:m.white}});return this.qrSlot===null?!1:(this.qrSlot.classList.remove("ui-qr-slot--loading"),this.qrSlot.replaceChildren(this.createQrImage(e)),!0)}hide(){this.dialog?.close(),this.dialog=null,this.qrSlot=null}createText(t,e){const i=document.createElement("p");return i.textContent=t,Object.assign(i.style,{margin:"0",textAlign:"center",...e}),i}createQrSlot(){const t=document.createElement("div");return t.className="ui-qr-slot ui-qr-slot--loading",t}createQrImage(t){const e=document.createElement("img");return e.src=t,e.alt="QR code",e}}function it(n){const t=Math.max(0,Math.min(1,n));return t*t*(3-2*t)}function fi(n,t,e,i,o,s){const[r,l,d]=n,u=Math.cos(t),p=Math.sin(t),v=u*r+p*d,A=-p*r+u*d,k=Math.cos(e),C=Math.sin(e),R=k*l-C*A,M=C*l+k*A,Z=.55;return[i+v*s*Z,o-R*s*Z,M]}function gi(n,t,e){n.beginPath(),n.moveTo(t[0],t[1]),n.lineTo(e[0],e[1]),n.strokeStyle="#000",n.lineWidth=2,n.stroke()}function bi(n,t,e,i,o){const s=t(e),r=t(i),l=[s[0]+(r[0]-s[0])*o,s[1]+(r[1]-s[1])*o,s[2]];gi(n,s,l)}const L=[-1,-1,1],z=[1,-1,1],P=[1,-1,-1],F=[-1,-1,-1],$=[-1,1,1],D=[1,1,1],B=[1,1,-1],U=[-1,1,-1],ot=[[L,z],[z,P],[P,F],[F,L],[L,$],[z,D],[P,B],[F,U],[$,D],[D,B],[B,U],[U,$]],vi=400,st='-apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif';function yi(){const n=document.createElement("div");Object.assign(n.style,{position:"absolute",inset:"0",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",background:"#fff",zIndex:"20",opacity:"0",transition:"opacity 0.3s ease-in-out"});const t=document.createElement("canvas");Object.assign(t.style,{width:"100%",height:"100%",position:"absolute",inset:"0"});const e=document.createElement("div");Object.assign(e.style,{position:"absolute",top:"56%",left:"0",right:"0",textAlign:"center",pointerEvents:"none"});const i=document.createElement("span");Object.assign(i.style,{fontSize:"13px",fontWeight:"400",color:"#000",fontVariantNumeric:"tabular-nums",fontFamily:st});const o=document.createElement("span");return Object.assign(o.style,{fontSize:"13px",color:"#000",fontFamily:st}),o.textContent=Et(),e.appendChild(i),e.appendChild(o),n.appendChild(t),n.appendChild(e),{overlay:n,canvas:t,pctEl:i,phaseEl:o}}class wi{overlay;canvas;ctx;pctEl;phaseEl;animationId=null;showTimerId=null;startTime;hidden=!1;visible=!1;constructor(t,e={}){this.startTime=performance.now();const i=yi();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());const o=e.showDelay??vi;this.showTimerId=setTimeout(()=>{this.reveal()},o)}get loadingTexts(){return{downloading:Et(),rendering:We()}}updateProgress(t,e){this.hidden||(this.pctEl.textContent=`${Math.round(t)}%`,this.phaseEl.textContent=e!==""?` · ${e}`:"")}showError(t){if(this.hidden=!1,this.animationId!==null&&(cancelAnimationFrame(this.animationId),this.animationId=null),this.ctx!==null){const e=Math.min(devicePixelRatio,2),i=this.canvas.width/e,o=this.canvas.height/e;this.ctx.fillStyle="#fff",this.ctx.fillRect(0,0,i*e,o*e)}this.pctEl.textContent="",this.phaseEl.textContent=t,this.phaseEl.style.color="#b91c1c",this.reveal()}hide(){if(!this.hidden){if(this.hidden=!0,this.cancelShowTimer(),!this.visible){this.destroy();return}this.overlay.style.opacity="0",this.overlay.addEventListener("transitionend",()=>{this.destroy()},{once:!0}),setTimeout(()=>{this.destroy()},500)}}destroy(){this.cancelShowTimer(),this.animationId!==null&&(cancelAnimationFrame(this.animationId),this.animationId=null),this.overlay.remove()}reveal(){this.hidden||this.visible||(this.visible=!0,this.overlay.style.opacity="1")}cancelShowTimer(){this.showTimerId!==null&&(clearTimeout(this.showTimerId),this.showTimerId=null)}sizeCanvas(){if(this.ctx===null)return;const t=Math.min(devicePixelRatio,2),e=this.overlay.clientWidth||440,i=this.overlay.clientHeight||360;this.canvas.width=e*t,this.canvas.height=i*t,this.ctx.scale(t,t),this.ctx.lineCap="round",this.ctx.lineJoin="round"}tick=()=>{this.hidden||(this.drawFrame(),this.animationId=requestAnimationFrame(this.tick))};drawFrame(){if(this.ctx===null)return;const t=this.canvas.width/Math.min(devicePixelRatio,2),e=this.canvas.height/Math.min(devicePixelRatio,2),i=(performance.now()-this.startTime)/1e3;this.ctx.fillStyle="#fff",this.ctx.fillRect(0,0,t,e);const o=t/2,s=e*.44,r=Math.min(t,e)*.08,l=.785,d=.615,u=C=>fi(C,l,d,o,s,r),p=6,v=i%p/p,A=ot.length;let k;v<.35?k=it(v/.35)*A:v<.55?k=A:v<.9?k=(1-it((v-.55)/.35))*A:k=0,this.ctx.shadowBlur=5,this.ctx.shadowColor="rgba(30,30,30,0.08)";for(let C=0;C<A&&!(C>=k);C++){const R=ot[C];if(R===void 0)continue;const M=Math.min(1,k-C);bi(this.ctx,u,R[0],R[1],M)}this.ctx.shadowBlur=0}}class _i{constructor(t){this.options=t,this.element=document.createElement("div"),Object.assign(this.element.style,{display:"flex",gap:"0.375rem"}),this.onFullscreenChange=()=>{this.setFullscreenIcon(document.fullscreenElement!==null)},document.addEventListener("fullscreenchange",this.onFullscreenChange)}options;element;arBtn=null;fullscreenBtn=null;onFullscreenChange;setFullscreenIcon(t){this.fullscreenBtn!==null&&this.fullscreenBtn.setIcon(t?g.exitFullscreen():g.fullscreen())}syncButton(t,e,i){if(e&&t===null){const o=i();return this.element.appendChild(o.element),o}return!e&&t!==null?(t.element.remove(),null):t}applySettings(t){this.arBtn=this.syncButton(this.arBtn,t.ar!==!1&&this.options.onAr!==void 0,()=>new b({variant:"outline",size:"icon",label:_e(),icon:g.ar(),onClick:()=>{this.options.onAr?.()}})),this.fullscreenBtn=this.syncButton(this.fullscreenBtn,t.fullscreen!==!1&&this.options.onFullscreen!==void 0,()=>new b({variant:"outline",size:"icon",label:Ue(),icon:g.fullscreen(),onClick:()=>{this.options.onFullscreen?.()}}))}destroy(){document.removeEventListener("fullscreenchange",this.onFullscreenChange)}}const x=.5;class N{element;constructor(t,e){this.element=Object.assign(document.createElement("div"),{className:"vd-camera-controls"});const i={targetRotation:e.rotation,targetTilt:e.tilt,targetZoom:e.zoom,thetaOffset:0},o=Ci(t,e,i);e.onChange(s=>{i.targetRotation=s.rotation-i.thetaOffset,i.targetTilt=s.tilt,i.targetZoom=s.zoom,Si(o,e,s)}),this.element.appendChild(N.buildZoom(o.zoomOut,o.zoomIn)),this.element.appendChild(N.buildDpad(o.tiltUp,o.rotateLeft,o.reset,o.rotateRight,o.tiltDown))}static buildZoom(t,e){const i=document.createElement("div");return i.className="vd-zoom",i.appendChild(t.element),i.appendChild(e.element),i}static buildDpad(t,e,i,o,s){const r=document.createElement("div");r.className="vd-dpad";for(const[l,d]of[[t,"up"],[e,"left"],[i,"center"],[o,"right"],[s,"down"]])l.element.classList.add(`vd-dpad-${d}`),r.appendChild(l.element);return r}}function Ci(n,t,e){const i=r=>Math.max(t.limits?.minZoom??1,Math.min(t.limits?.maxZoom??1/0,r)),o=r=>{const l=t.limits?.minRotate,d=t.limits?.maxRotate;return l!==void 0||d!==void 0?Math.max(l??-1/0,Math.min(d??1/0,r)):r},s=r=>{const l=t.limits?.minTilt,d=t.limits?.maxTilt;if(l!==void 0||d!==void 0){e.targetTilt=Math.max(l??0,Math.min(d??180,e.targetTilt+r)),n.tilt(e.targetTilt).set();return}const u=e.targetTilt+r;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())};return{zoomOut:new b({variant:"outline",size:"icon",label:yn(),icon:g.zoomOut(),onClick:()=>{e.targetZoom=i(e.targetZoom-10),n.zoom(e.targetZoom).set()}}),zoomIn:new b({variant:"outline",size:"icon",label:fn(),icon:g.zoomIn(),onClick:()=>{e.targetZoom=i(e.targetZoom+10),n.zoom(e.targetZoom).set()}}),tiltUp:new b({variant:"outline",size:"icon",label:On(),icon:g.tiltUp(),onClick:()=>{s(-15)}}),rotateLeft:new b({variant:"outline",size:"icon",label:Sn(),icon:g.rotateLeft(),onClick:()=>{e.targetRotation=o(e.targetRotation-15),n.rotate(e.targetRotation+e.thetaOffset).set()}}),reset:new b({variant:"outline",size:"icon",label:dn(),icon:g.reset(),onClick:()=>{e.thetaOffset=0,n.reset()}}),rotateRight:new b({variant:"outline",size:"icon",label:xn(),icon:g.rotateRight(),onClick:()=>{e.targetRotation=o(e.targetRotation+15),n.rotate(e.targetRotation+e.thetaOffset).set()}}),tiltDown:new b({variant:"outline",size:"icon",label:zn(),icon:g.tiltDown(),onClick:()=>{s(15)}})}}function Si(n,t,e){const i=t.limits;i!==void 0&&(n.zoomOut.element.disabled=i.minZoom!==void 0&&e.zoom<=i.minZoom+x,n.zoomIn.element.disabled=i.maxZoom!==void 0&&e.zoom>=i.maxZoom-x,n.tiltUp.element.disabled=i.minTilt!==void 0&&e.tilt<=i.minTilt+x,n.tiltDown.element.disabled=i.maxTilt!==void 0&&e.tilt>=i.maxTilt-x,n.rotateLeft.element.disabled=i.minRotate!==void 0&&e.rotation<=i.minRotate+x,n.rotateRight.element.disabled=i.maxRotate!==void 0&&e.rotation>=i.maxRotate-x)}const T={SELECT:"ui:select",SELECTED:"ui:selected",FOCUS_CHANGE:"vd:focus-change",CONFIGURATION_CHANGE:"vd:configuration-change",CONFIGURATION_SUBMIT:"vd:configuration-submit"},ki=5;let Ai=0;function V(n){const t=n.replace(/([A-Z])/g," $1").trim();return t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()}function Ei(n,t,e,i,o){const s=document.createElement("div");s.className="vd-attribute",s.dataset.name=n.name;const r=document.createElement("span");r.className="vd-attribute-label",r.textContent=V(n.name),r.id=`vd-attribute-label-${Ai++}`,s.appendChild(r),s.setAttribute("role","group"),s.setAttribute("aria-labelledby",r.id);const l=n.values.find(p=>t.getValue(n.name,p)?.isSelected===!0),d=n.values.map(V),u=n.values.length<=ki?new ci(n.values,l,d):new ui(n.name,n.values,V(n.name),l,d);return u.onSelect(p=>{e.dispatch(T.SELECT,{attribute:n.name,value:p},!0).defaultPrevented||i(n.name,p)}),o(n.name,p=>{u.setSelected(p.value),e.dispatch(T.SELECTED,{attribute:n.name,value:p.value})}),s.appendChild(u.element),s}const xi=80,Ti=2500;class Ri{constructor(t,e=Ti){this.configuration=t,this.resetMs=e,this.element=document.createElement("div"),this.element.className="vd-commerce vd-hidden";const i=document.createElement("div");i.className="vd-commerce-price",this.priceEl=document.createElement("span"),this.priceEl.className="vd-price",this.vatEl=document.createElement("span"),this.vatEl.className="vd-vat",i.append(this.priceEl,this.vatEl),this.button=new b({variant:"default",onClick:()=>{this.handleSubmit()}}),this.button.element.classList.add("vd-cta","vd-hidden"),this.element.append(i,this.button.element),this.unsubscribe=this.configuration.onRender(()=>{this.update()}),this.update()}configuration;resetMs;element;priceEl;vatEl;button;unsubscribe;state="idle";resetTimer;update(){this.renderPrice(this.configuration.current),this.renderButton();const t=this.configuration.current!==void 0||this.configuration.submitEnabled;this.element.classList.toggle("vd-hidden",!t)}destroy(){this.unsubscribe(),this.resetTimer!==void 0&&clearTimeout(this.resetTimer),this.element.remove()}renderPrice(t){if(t===void 0){this.priceEl.textContent="",this.vatEl.textContent="";return}this.priceEl.textContent=Ii(t.price,t.currency),this.vatEl.textContent=rt(this.configuration.vatDisplay)}renderButton(){const t=this.configuration.submitEnabled;this.button.element.classList.toggle("vd-hidden",!t),t&&this.state==="idle"&&this.setButtonText(rt(this.configuration.buttonLabel))}async handleSubmit(){if(this.state!=="busy"){this.setState("busy",Dn());try{await this.configuration.submit(),this.setState("success",jn())}catch{this.setState("failed",Zn())}this.scheduleReset()}}scheduleReset(){this.resetTimer!==void 0&&clearTimeout(this.resetTimer),this.resetTimer=setTimeout(()=>{this.state="idle",this.update()},this.resetMs)}setState(t,e){this.state=t,this.element.dataset.submit=t,this.button.element.disabled=t==="busy",this.setButtonText(e)}setButtonText(t){this.button.element.textContent=t,this.button.element.setAttribute("aria-label",t)}}function rt(n){return(n??"").slice(0,xi)}function Ii(n,t){try{const e=new Intl.NumberFormat(h(),{style:"currency",currency:t}),i=e.resolvedOptions().maximumFractionDigits??2;return e.format(n/10**i)}catch{return`${t} ${(n/100).toFixed(2)}`}}class Ot{slot=null;panel=null;attach(t,e){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)}setVisible(t){this.panel!==null&&(this.panel.style.display=t?"flex":"none")}destroy(){this.slot?.remove(),this.slot=null,this.panel=null}}const Oi=572;class Ni{element=null;body=null;openButton=null;closeButton=null;container=null;observer=null;collapsible=!1;expanded=!0;visible=!1;attach(t,e){this.container=t,e.classList.add("vd-attributes-sidebar"),this.closeButton=new b({variant:"ghost",size:"icon-sm",label:an(),icon:g.close({size:18}),onClick:()=>{this.expanded=!1,this.render()}});const i=document.createElement("div");i.className="vd-sidebar-header",i.appendChild(this.closeButton.element),this.body=document.createElement("div"),this.body.className="vd-sidebar-body",this.body.appendChild(e),this.element=document.createElement("div"),this.element.className="vd-sidebar vd-hidden",this.element.append(i,this.body),t.appendChild(this.element),this.openButton=new b({variant:"outline",size:"default",label:nn(),icon:g.configurator({size:18}),onClick:()=>{this.expanded=!0,this.render()}}),this.openButton.element.classList.add("vd-configurator-toggle","vd-hidden"),t.appendChild(this.openButton.element),this.observe()}setVisible(t){this.visible=t,this.render()}destroy(){this.observer?.disconnect(),this.observer=null,this.openButton?.element.remove(),this.element?.remove(),this.container?.classList.remove("vd-layout-sidebar-right","vd-layout-sidebar-collapsed"),this.container=null}observe(){typeof ResizeObserver>"u"||this.container===null||(this.observer=new ResizeObserver(t=>{const e=t[0]?.contentRect.width??0;this.setCollapsible(e>0&&e<Oi)}),this.observer.observe(this.container))}setCollapsible(t){t!==this.collapsible&&(this.collapsible=t,this.expanded=!t,this.render())}render(){if(this.element===null||this.openButton===null||this.closeButton===null||this.container===null)return;const t=this.visible&&this.expanded,e=this.visible&&!this.expanded;this.element.classList.toggle("vd-hidden",!this.visible),this.element.classList.toggle("vd-sidebar-collapsed",e),this.openButton.element.classList.toggle("vd-hidden",!e),this.closeButton.element.style.display=this.collapsible?"":"none",this.container.classList.toggle("vd-layout-sidebar-right",t),this.container.classList.toggle("vd-layout-sidebar-collapsed",e)}}class Mi{attach(t,e){}setVisible(t){}destroy(){}}const Li={"inframe-bottom-left":()=>new Ot,"sidebar-right":()=>new Ni,hidden:()=>new Mi};function zi(n){return(Li[n??""]??(()=>new Ot))()}const j=w.fontFamily.sans.join(", "),H=`
|
|
292
|
+
position: absolute;
|
|
293
|
+
display: flex;
|
|
294
|
+
z-index: 10;
|
|
295
|
+
transition: inset-inline-end 0.18s ease;
|
|
296
|
+
`,Pi=`
|
|
297
|
+
/* Override browser's default black fullscreen backdrop */
|
|
298
|
+
.vd-container:fullscreen {
|
|
299
|
+
background: oklch(100% 0 0);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/* Layout slots — four corners */
|
|
303
|
+
.vd-slot-top-right {
|
|
304
|
+
${H}
|
|
305
|
+
inset-block-start: ${a[3]};
|
|
306
|
+
inset-inline-end: ${a[3]};
|
|
307
|
+
flex-direction: column;
|
|
308
|
+
align-items: flex-end;
|
|
309
|
+
gap: ${a[1.5]};
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.vd-slot-bottom-left {
|
|
313
|
+
${H}
|
|
314
|
+
inset-block-end: ${a[3]};
|
|
315
|
+
inset-inline-start: ${a[3]};
|
|
316
|
+
flex-direction: column;
|
|
317
|
+
align-items: flex-start;
|
|
318
|
+
gap: ${a[1.5]};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.vd-slot-bottom-right {
|
|
322
|
+
${H}
|
|
323
|
+
inset-block-end: ${a[3]};
|
|
324
|
+
inset-inline-end: ${a[3]};
|
|
325
|
+
flex-direction: row;
|
|
326
|
+
gap: ${a[1.5]};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* Component styles — no positioning */
|
|
330
|
+
.vd-camera-controls {
|
|
331
|
+
display: flex;
|
|
332
|
+
flex-direction: column;
|
|
333
|
+
gap: ${a[1]};
|
|
334
|
+
background: color-mix(in oklch, ${m.white} 85%, transparent);
|
|
335
|
+
backdrop-filter: blur(8px);
|
|
336
|
+
border-radius: ${a[2]};
|
|
337
|
+
padding: ${a[2]};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.vd-zoom {
|
|
341
|
+
display: flex;
|
|
342
|
+
gap: ${a[.5]};
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.vd-dpad {
|
|
346
|
+
display: grid;
|
|
347
|
+
grid-template-columns: repeat(3, ${a[9]});
|
|
348
|
+
grid-template-rows: repeat(3, ${a[9]});
|
|
349
|
+
gap: ${a[.5]};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.vd-dpad-up { grid-column: 2; grid-row: 1; }
|
|
353
|
+
.vd-dpad-left { grid-column: 1; grid-row: 2; }
|
|
354
|
+
.vd-dpad-center { grid-column: 2; grid-row: 2; }
|
|
355
|
+
.vd-dpad-right { grid-column: 3; grid-row: 2; }
|
|
356
|
+
.vd-dpad-down { grid-column: 2; grid-row: 3; }
|
|
357
|
+
|
|
358
|
+
.vd-attributes {
|
|
359
|
+
display: flex;
|
|
360
|
+
flex-direction: column;
|
|
361
|
+
gap: ${a[3]};
|
|
362
|
+
background: color-mix(in oklch, ${m.white} 85%, transparent);
|
|
363
|
+
backdrop-filter: blur(8px);
|
|
364
|
+
border: 1px solid color-mix(in oklch, ${m.neutral[900]} 8%, transparent);
|
|
365
|
+
border-radius: ${a[3]};
|
|
366
|
+
padding: ${a[3]};
|
|
367
|
+
box-shadow: 0 ${a[1]} ${a[4]} color-mix(in oklch, ${m.neutral[900]} 6%, transparent);
|
|
368
|
+
font-family: ${j};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.vd-attribute {
|
|
372
|
+
display: flex;
|
|
373
|
+
flex-direction: column;
|
|
374
|
+
gap: ${a[1.5]};
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/* Micro-label: recedes so the controls lead. */
|
|
378
|
+
.vd-attribute-label {
|
|
379
|
+
font-size: ${w.fontSize.xs};
|
|
380
|
+
font-weight: ${w.fontWeight.medium};
|
|
381
|
+
color: ${m.neutral[500]};
|
|
382
|
+
text-transform: uppercase;
|
|
383
|
+
letter-spacing: 0.05em;
|
|
384
|
+
font-family: ${j};
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/* sidebar-right layout — a docked, full-height right panel */
|
|
388
|
+
.vd-container { --vd-sidebar-width: 300px; }
|
|
389
|
+
|
|
390
|
+
.vd-hidden { display: none !important; }
|
|
391
|
+
|
|
392
|
+
.vd-sidebar {
|
|
393
|
+
position: absolute;
|
|
394
|
+
inset-block: 0;
|
|
395
|
+
inset-inline-end: 0;
|
|
396
|
+
inline-size: var(--vd-sidebar-width);
|
|
397
|
+
z-index: 11;
|
|
398
|
+
display: flex;
|
|
399
|
+
flex-direction: column;
|
|
400
|
+
background: color-mix(in oklch, ${m.white} 90%, transparent);
|
|
401
|
+
backdrop-filter: blur(10px);
|
|
402
|
+
border-inline-start: 1px solid color-mix(in oklch, ${m.neutral[900]} 8%, transparent);
|
|
403
|
+
box-shadow: -${a[1]} 0 ${a[4]} color-mix(in oklch, ${m.neutral[900]} 5%, transparent);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
407
|
+
.vd-sidebar { transition: transform 0.18s ease; }
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.vd-sidebar-collapsed { transform: translateX(100%); }
|
|
411
|
+
|
|
412
|
+
.vd-sidebar-header {
|
|
413
|
+
display: flex;
|
|
414
|
+
justify-content: flex-end;
|
|
415
|
+
padding: ${a[1.5]} ${a[1.5]} 0;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.vd-sidebar-body {
|
|
419
|
+
flex: 1;
|
|
420
|
+
overflow-y: auto;
|
|
421
|
+
padding: ${a[4]};
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/* attributes inside the sidebar: flat and full-width — the panel provides the frosting */
|
|
425
|
+
.vd-attributes.vd-attributes-sidebar {
|
|
426
|
+
background: transparent;
|
|
427
|
+
backdrop-filter: none;
|
|
428
|
+
border: none;
|
|
429
|
+
border-radius: 0;
|
|
430
|
+
padding: 0;
|
|
431
|
+
box-shadow: none;
|
|
432
|
+
gap: ${a[5]};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/* floating toggle, shown when the sidebar is collapsed on narrow embeds */
|
|
436
|
+
.vd-configurator-toggle {
|
|
437
|
+
position: absolute;
|
|
438
|
+
inset-block-end: ${a[3]};
|
|
439
|
+
inset-inline-end: ${a[3]};
|
|
440
|
+
z-index: 12;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/* while the panel is open, keep the corner controls clear of it */
|
|
444
|
+
.vd-layout-sidebar-right .vd-slot-top-right { inset-inline-end: calc(var(--vd-sidebar-width) + ${a[3]}); }
|
|
445
|
+
.vd-layout-sidebar-right .vd-slot-bottom-right { inset-inline-end: calc(var(--vd-sidebar-width) + ${a[3]}); }
|
|
446
|
+
|
|
447
|
+
/* while collapsed on a narrow embed, lift the bottom-right controls above the
|
|
448
|
+
floating toggle so the AR/fullscreen buttons aren't hidden behind the
|
|
449
|
+
"open configurator" button (spacing[9] = the default toggle button height) */
|
|
450
|
+
.vd-layout-sidebar-collapsed .vd-slot-bottom-right {
|
|
451
|
+
inset-block-end: calc(${a[3]} + ${a[9]} + ${a[1.5]});
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/* Price + CTA — sit under the attribute controls, separated by a hairline */
|
|
455
|
+
.vd-commerce {
|
|
456
|
+
display: flex;
|
|
457
|
+
flex-direction: column;
|
|
458
|
+
gap: ${a[2]};
|
|
459
|
+
padding-block-start: ${a[3]};
|
|
460
|
+
border-block-start: 1px solid color-mix(in oklch, ${m.neutral[900]} 8%, transparent);
|
|
461
|
+
font-family: ${j};
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.vd-commerce-price {
|
|
465
|
+
display: flex;
|
|
466
|
+
align-items: baseline;
|
|
467
|
+
gap: ${a[1.5]};
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.vd-price {
|
|
471
|
+
font-size: ${w.fontSize.lg};
|
|
472
|
+
font-weight: ${w.fontWeight.semibold};
|
|
473
|
+
color: ${m.neutral[900]};
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
.vd-vat {
|
|
477
|
+
font-size: ${w.fontSize.xs};
|
|
478
|
+
color: ${m.neutral[500]};
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
.vd-cta {
|
|
482
|
+
inline-size: 100%;
|
|
483
|
+
justify-content: center;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/* Failed submit is the one place red belongs: a clear, recoverable error state. */
|
|
487
|
+
.vd-commerce[data-submit="failed"] .vd-cta {
|
|
488
|
+
background: ${m.semantic.error};
|
|
489
|
+
border-color: ${m.semantic.error};
|
|
490
|
+
color: ${m.white};
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
`;function Fi(){if(It(),document.getElementById("vd-styles")!==null)return;const n=document.createElement("style");n.id="vd-styles",n.textContent=Pi,document.head.appendChild(n)}function $i(n,t){const e=document.createElement("a");e.href=`data:image/png;base64,${n}`,e.download=t,e.click()}class Di{options;settings={};container=null;loading=null;slots={topRight:null,bottomRight:null};screenshotBtn=null;actionBar=null;cameraControls=null;attributes=null;layout=null;commerce=null;constructor(t){this.options=t}attach(t){Fi(),this.container=t,this.loading=new wi(t),this.slots.topRight=this.createSlot(t,"vd-slot-top-right"),this.slots.bottomRight=this.createSlot(t,"vd-slot-bottom-right")}onReady(){this.loading?.hide(),this.loading=null,this.mountToolbar(),this.cameraControls!==null&&(this.cameraControls.element.style.display="flex"),this.layout?.setVisible(!0)}mountToolbar(){if(this.actionBar!==null||this.slots.bottomRight===null||this.container===null)return;const t=typeof this.container.requestFullscreen=="function";this.actionBar=new _i({onAr:this.options.onAr,onFullscreen:t?()=>{this.toggleFullscreen()}:void 0}),this.actionBar.applySettings(this.settings),this.slots.bottomRight.appendChild(this.actionBar.element),this.syncScreenshotButton(),this.placeScreenshotButton()}toggleFullscreen(){this.container!==null&&(document.fullscreenElement!==null?document.exitFullscreen():(this.options.onFullscreenEnter?.(),this.container.requestFullscreen()))}updateProgress(t,e){this.loading?.updateProgress(t,e)}showError(t){this.loading?.showError(t)}applyViewerSettings(t){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()}renderAttributeControls(t,e){if(!(this.container===null||this.slots.topRight===null)&&(this.cameraControls?.element.remove(),this.cameraControls=null,this.teardownConfigurator(),this.settings.cameraControls===!0&&(this.cameraControls=new N(this.options.cameraApi,this.options.cameraPositionApi),this.cameraControls.element.style.display="none",this.slots.topRight.appendChild(this.cameraControls.element)),this.placeScreenshotButton(),e.length!==0)){this.attributes=document.createElement("div"),this.attributes.className="vd-attributes";for(const i of e)this.attributes.appendChild(Ei(i,t,this.options.eventBus,this.options.onSelect,this.options.onSubscribe));this.commerce=new Ri(this.options.configuration),this.attributes.appendChild(this.commerce.element),this.layout=zi(this.settings.configuratorLayout),this.layout.attach(this.container,this.attributes)}}get viewerSettings(){return this.settings}teardownConfigurator(){this.commerce?.destroy(),this.commerce=null,this.attributes?.remove(),this.attributes=null,this.layout?.destroy(),this.layout=null}destroy(){this.loading?.destroy(),this.screenshotBtn?.element.remove(),this.actionBar?.destroy(),this.actionBar?.element.remove(),this.cameraControls?.element.remove(),this.teardownConfigurator();for(const t of Object.values(this.slots))t?.remove();this.container=null}createSlot(t,e){const i=document.createElement("div");return i.className=e,t.appendChild(i),i}syncScreenshotButton(){const t=this.settings.screenshot===!0;t&&this.screenshotBtn===null&&(this.screenshotBtn=new b({variant:"outline",size:"icon",label:Xe(),icon:g.screenshot(),onClick:()=>{this.options.snapshotApi.take("snapshot.png").onDeveloped(({data:e,filename:i})=>{$i(e,i)})}})),!t&&this.screenshotBtn!==null&&(this.screenshotBtn.element.remove(),this.screenshotBtn=null)}placeScreenshotButton(){this.screenshotBtn===null||this.slots.topRight===null||(this.cameraControls!==null?this.cameraControls.element.appendChild(this.screenshotBtn.element):this.slots.topRight.appendChild(this.screenshotBtn.element))}}const Bi={};class Ui{defaultServer="https://server.virtualdisplay.io";options;serverHost;constructor(t,e){this.options=t,this.serverHost=e}create(){const t=this.createContainer(),e=this.createIframe();return t.appendChild(e),this.attachToParent(t),{container:t,iframe:e}}createContainer(){const t=document.createElement("div");return t.className="vd-container",Object.assign(t.style,{position:"relative",width:"100%",height:"100%",overflow:"hidden"}),t}createIframe(){const t=document.createElement("iframe");return t.src=this.buildUrl(),Object.assign(t.style,{width:"100%",height:"100%",border:"none",display:"block"}),t.setAttribute("allow","xr-spatial-tracking; fullscreen"),t}attachToParent(t){this.getParentElement().appendChild(t)}buildUrl(){const t=this.getServerUrl(),e=new URL(t);return e.searchParams.set("license",this.options.license),e.searchParams.set("model",this.options.model),this.options.language!==void 0&&e.searchParams.set("language",this.options.language),this.options.session!==void 0&&e.searchParams.set("session",this.options.session),this.options.debug===!0&&e.searchParams.set("debug","true"),this.options.traceparent!==void 0&&e.searchParams.set("traceparent",this.options.traceparent),e.toString()}getServerUrl(){if(this.serverHost!==void 0)return this.serverHost;if(Bi?.VITE_VIRTUALDISPLAY_SERVER_HOST===void 0)return this.defaultServer}getParentElement(){if(typeof this.options.parent!="string")return this.options.parent;const t=document.querySelector(this.options.parent);if(t===null)throw f.parentNotFound(this.options.parent);return t}}function Vi(n){const{messenger:t}=n;t.on(c.HANDSHAKE,e=>{Pt(e)&&(exports.logger.info("Server handshake received, flushing publisher queue"),t.markReady())}),t.on(c.SESSION,e=>{Ft(e)&&n.onSession(e.sessionId)}),t.on(c.MUTATION,e=>{$t(e)&&(n.attributes.handleMutationResult(e),n.configuration.handleSelectionChanged(n.attributes.getSelection()))}),t.on(c.SNAPSHOT,e=>{Dt(e)&&n.snapshot.handleSnapshotResult(e)}),t.on(c.CAMERA,e=>{Bt(e)&&n.cameraPosition.handlePositionUpdate(e)}),t.on(c.LOADING_INDICATOR,e=>{Vt(e)&&(e.error!==void 0?n.ui.showError(e.error):n.ui.updateProgress(e.progress,e.phase))}),t.on(c.CONFIG,e=>{Ht(e)&&n.applyConfig(e)}),t.on(c.MAPPING,e=>{Ut(e)&&(n.attributes.handleMappingReceived(e),n.configuration.handleSelectionChanged(n.attributes.getSelection()),n.ui.renderAttributeControls(n.attributes,e.attributes),n.readyStateTracker.handleMappingReceived())}),ji(n)}function ji(n){const{messenger:t}=n;t.on(c.FOCUS,e=>{qt(e)&&n.focus.handleStateReceived(e)}),t.on(c.PRICING,e=>{Gt(e)&&n.configuration.handlePricingReceived(e.pricing)}),t.on(c.SYNC,e=>{jt(e)&&n.onSync(e.connected)})}class Hi{ready=!1;onReady;constructor(t){this.onReady=t}handleMappingReceived(){this.ready||(this.ready=!0,exports.logger.info("Mapping received from server, client is now ready"),this.onReady?.())}get isReady(){return this.ready}clear(){this.ready=!1}}class qi{attributes;readyStateTracker;messenger;cameraApi;cameraPositionApi;focusApi;configurationApi;snapshotApi;annotationsApi;eventBus;ui;options;serverHost;arActivation;syncTracker;iframe;container;readyCallbacks=[];mutationFailedCallbacks=[];viewerSessionId;constructor(t,e){this.options=t,this.serverHost=e?.serverHost,this.initializeLogging(),this.messenger=new Zt(()=>this.iframe?.contentWindow??null,e?.messengerOptions);const i=s=>{this.messenger.send(s)};this.attributes=new ae(i,(s,r)=>{this.notifyMutationFailed(s,r)}),this.snapshotApi=new wt(i),this.annotationsApi=new at(i),this.cameraApi=new gt(i),this.cameraPositionApi=new le,this.focusApi=new vt(i,s=>{this.dispatchFocusChange(s)}),this.configurationApi=new bt(s=>{this.dispatchConfigurationChange(s)},s=>{this.dispatchConfigurationSubmit(s)}),this.eventBus=new de,this.arActivation=e?.createArActivation?.(i),this.syncTracker=e?.createSyncTracker?.(),this.readyStateTracker=new Hi(()=>{this.notifyReady()});const o=this.arActivation;this.ui=new Di({snapshotApi:this.snapshotApi,cameraApi:this.cameraApi,cameraPositionApi:this.cameraPositionApi,eventBus:this.eventBus,configuration:this.configurationApi,onSelect:(s,r)=>this.attributes.select(s,r),onSubscribe:(s,r)=>this.attributes.onChange(s,r),...o!==void 0&&{onAr:()=>{o.activate()}},onFullscreenEnter:()=>{this.trackFullscreen()}}),this.wireIncomingMessages(),e?.registerHandlers?.(this.messenger,i),this.messenger.start(),this.createAndConnectIframe()}wireIncomingMessages(){Vi({messenger:this.messenger,attributes:this.attributes,configuration:this.configurationApi,snapshot:this.snapshotApi,cameraPosition:this.cameraPositionApi,focus:this.focusApi,ui:this.ui,readyStateTracker:this.readyStateTracker,applyConfig:t=>{this.handleConfig(t)},onSession:t=>{this.handleSession(t)},onSync:t=>{this.syncTracker?.handleSync(t)}})}handleSession(t){this.viewerSessionId=t,this.arActivation?.onSession(t)}notifyMutationFailed(t,e){for(const i of this.mutationFailedCallbacks)i({attribute:t,value:e})}notifyReady(){const t=this.readyCallbacks;this.readyCallbacks=[];for(const e of t)e(this);this.ui.onReady()}dispatchFocusChange(t){this.container?.dispatchEvent(new CustomEvent(T.FOCUS_CHANGE,{detail:t,bubbles:!0}))}dispatchConfigurationChange(t){this.container?.dispatchEvent(new CustomEvent(T.CONFIGURATION_CHANGE,{detail:t??null,bubbles:!0}))}dispatchConfigurationSubmit(t){this.container?.dispatchEvent(new CustomEvent(T.CONFIGURATION_SUBMIT,{detail:t,bubbles:!0}))}handleConfig(t){const e=t.viewerSettings,i=this.options.viewerSettings;if(e!==void 0||i!==void 0){const o=i!==void 0?{...e??{},...i}:e;if(i!==void 0&&e!==void 0){const s=Object.entries(i).filter(([r,l])=>e[r]!==l).map(([r,l])=>`${r} (metadata: ${e[r]??"undefined"}, override: ${l})`);s.length>0&&exports.logger.warn(`Viewer settings override active: ${s.join(", ")}`)}this.ui.applyViewerSettings(o),this.annotationsApi.setEnabled(o.annotations!==!1)}this.cameraPositionApi.applyLimits(t.cameraLimits)}trackFullscreen(){this.messenger.send({type:c.FULLSCREEN})}initializeLogging(){this.options.debug===!0&&ft(),exports.logger.info("Initializing Virtualdisplay client",{model:this.options.model})}createAndConnectIframe(){const e=new Ui(this.options,this.serverHost).create();this.container=e.container,this.iframe=e.iframe,this.eventBus.attach(this.container),this.ui.attach(this.container);try{const i=new URL(this.iframe.src).origin;this.messenger.setTargetOrigin(i)}catch{}}select(t,e){this.attributes.select(t,e)}getValues(t){return this.attributes.getValues(t)}getValue(t,e){return this.attributes.getValue(t,e)}onChange(t,e){this.attributes.onChange(t,e)}getAttribute(t){return this.attributes.getAttribute(t)}get isReady(){return this.readyStateTracker.isReady}onReady(t){if(this.readyStateTracker.isReady){t(this);return}this.readyCallbacks.push(t)}onMutationFailed(t){this.mutationFailedCallbacks.push(t)}activateAr(){this.arActivation?.activate()}on(t,e){this.eventBus.on(t,e)}get annotations(){return this.annotationsApi}get camera(){return this.cameraApi}get focus(){return this.focusApi}get configuration(){return this.configurationApi}get cameraPosition(){return this.cameraPositionApi}get snapshot(){return this.snapshotApi}get sessionId(){return this.viewerSessionId}get viewerSettings(){return this.ui.viewerSettings}destroy(){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}}const Gi="ar.virtualdisplay.io";function Zi(n){const t=new URL(`https://${Gi}/go`);return n.sessionId!==void 0?t.searchParams.set("session",n.sessionId):(t.searchParams.set("license",n.license),t.searchParams.set("model",n.model)),t.toString()}const Wi=1500;class Qi{options;qrModal=new pi;sessionId;waiters=[];pendingTimers=new Set;destroyed=!1;constructor(t){this.options=t}onSession(t){this.sessionId=t;const e=this.waiters;this.waiters=[];for(const i of e)i(t)}activate(){if(oe()){this.options.send({type:c.AR_ACTIVATE});return}this.showQrCode()}destroy(){this.destroyed=!0;for(const t of this.pendingTimers)clearTimeout(t);this.pendingTimers.clear(),this.waiters=[],this.qrModal.hide()}async showQrCode(){this.qrModal.show();const t=await this.waitForSessionId();if(this.destroyed)return;const e=Zi({sessionId:t,license:this.options.license,model:this.options.model}),i=await this.qrModal.update(e);if(this.destroyed){this.qrModal.hide();return}i&&this.options.send({type:c.QR_SHOWN})}waitForSessionId(){return this.sessionId!==void 0?Promise.resolve(this.sessionId):new Promise(t=>{const e=setTimeout(()=>{this.pendingTimers.delete(e),t(void 0)},Wi);this.pendingTimers.add(e),this.waiters.push(i=>{this.pendingTimers.delete(e),clearTimeout(e),t(i)})})}}class Yi{callbacks=[];lastKnown;handleSync(t){this.lastKnown=t;for(const e of this.callbacks)e(t)}onChange(t){this.callbacks.push(t),this.lastKnown!==void 0&&t(this.lastKnown)}}class Ki extends qi{syncStatusTracker;constructor(t){const e=new Yi;super(t,{createArActivation:i=>new Qi({license:t.license,model:t.model,send:i}),createSyncTracker:()=>e}),this.syncStatusTracker=e}onSyncChange(t){this.syncStatusTracker.onChange(t)}}exports.Annotations=at;exports.Attribute=ct;exports.AttributeValue=lt;exports.Camera=gt;exports.Configuration=bt;exports.ERROR_CODES=S;exports.Focus=vt;exports.Photo=yt;exports.Snapshot=wt;exports.VD_EVENTS=T;exports.VirtualdisplayClient=Ki;exports.VirtualdisplayError=f;exports.enableDebugMode=ft;exports.isDebugMode=re;
|