@neurodyn/core-ar 0.2.10 → 0.3.1
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/dist/core-ar.chunk.09fa4463.min.js +987 -0
- package/dist/core-ar.chunk.09fa4463.min.js.LICENSE.txt +165 -0
- package/dist/core-ar.chunk.3e37d1f5.min.js +5335 -0
- package/dist/core-ar.chunk.c15d19d9.min.js +2 -0
- package/dist/core-ar.chunk.c15d19d9.min.js.LICENSE.txt +19 -0
- package/dist/core-ar.chunk.c3761997.min.js +2 -0
- package/dist/core-ar.chunk.c3761997.min.js.LICENSE.txt +19 -0
- package/dist/core-ar.chunk.f57ba10e.min.js +2 -0
- package/dist/core-ar.chunk.f57ba10e.min.js.LICENSE.txt +9 -0
- package/dist/core-ar.embed.min.js +27 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +138 -177
- package/package.json +8 -4
package/dist/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { disableBodyScroll, enableBodyScroll } from "body-scroll-lock";
|
|
2
1
|
let config_runtimeConfig;
|
|
3
2
|
function normalizeHttpOrigin(value, name) {
|
|
4
3
|
let url;
|
|
@@ -10,11 +9,6 @@ function normalizeHttpOrigin(value, name) {
|
|
|
10
9
|
if ('http:' !== url.protocol && 'https:' !== url.protocol) throw new TypeError(`${name} must be an absolute HTTP(S) URL`);
|
|
11
10
|
return url.origin;
|
|
12
11
|
}
|
|
13
|
-
function normalizeHttpBaseUrl(value, name) {
|
|
14
|
-
const origin = normalizeHttpOrigin(value, name);
|
|
15
|
-
const pathname = new URL(value).pathname.replace(/\/+$/, '');
|
|
16
|
-
return pathname ? `${origin}${pathname}` : origin;
|
|
17
|
-
}
|
|
18
12
|
function deriveModelViewerOrigin(viewerOrigin) {
|
|
19
13
|
const url = new URL(viewerOrigin);
|
|
20
14
|
const match = url.hostname.match(/^viewer(-dev)?\.(vizbl\.com|arizo\.ru)$/);
|
|
@@ -25,13 +19,11 @@ function resolveCoreArWidgetRuntimeConfig(config) {
|
|
|
25
19
|
const apiOrigin = normalizeHttpOrigin(config.apiOrigin, 'apiOrigin');
|
|
26
20
|
const viewerOrigin = normalizeHttpOrigin(config.viewerOrigin, 'viewerOrigin');
|
|
27
21
|
const modelViewerOrigin = config.modelViewerOrigin ? normalizeHttpOrigin(config.modelViewerOrigin, 'modelViewerOrigin') : deriveModelViewerOrigin(viewerOrigin);
|
|
28
|
-
const legacyApiOrigin = config.legacyApiOrigin ? normalizeHttpBaseUrl(config.legacyApiOrigin, 'legacyApiOrigin') : `${apiOrigin}/v1`;
|
|
29
22
|
const brand = new URL(viewerOrigin).hostname.endsWith('arizo.ru') ? 'arizo' : 'vizbl';
|
|
30
23
|
return {
|
|
31
24
|
apiOrigin,
|
|
32
25
|
brand,
|
|
33
26
|
fetchImpl: config.fetchImpl ?? fetch,
|
|
34
|
-
legacyApiOrigin,
|
|
35
27
|
modelViewerOrigin,
|
|
36
28
|
qrCodeScriptUrl: config.qrCodeScriptUrl ?? `${viewerOrigin}/vendor/qrcode.min.js`,
|
|
37
29
|
viewerOrigin
|
|
@@ -61,6 +53,7 @@ function isIOS() {
|
|
|
61
53
|
}
|
|
62
54
|
function isMobile() {
|
|
63
55
|
if ("u" < typeof window || "u" < typeof navigator) return false;
|
|
56
|
+
if (isIOS()) return true;
|
|
64
57
|
const hasMultiTouch = navigator.maxTouchPoints > 1;
|
|
65
58
|
const isCoarsePointer = window.matchMedia?.('(pointer: coarse)').matches ?? false;
|
|
66
59
|
const isMobileByUserAgent = /Android|iPhone|iPad|iPod|webOS|BlackBerry|Windows Phone|Opera Mini|IEMobile|Mobile/i.test(getUserAgent());
|
|
@@ -612,10 +605,10 @@ async function sendWidgetEvent(event, sessionToken, objectUuid, options = {}) {
|
|
|
612
605
|
const data = await parseSuccessJson(response);
|
|
613
606
|
if (!data || 'object' != typeof data || Array.isArray(data) || 'boolean' != typeof data.ok) throw new WidgetRuntimeError('INVALID_RESPONSE');
|
|
614
607
|
}
|
|
615
|
-
async function
|
|
608
|
+
async function fetchPublicObject(objectId, signal, runtimeConfig) {
|
|
616
609
|
const resolvedConfig = runtimeConfig ?? getCoreArWidgetRuntimeConfig();
|
|
617
|
-
const {
|
|
618
|
-
const response = await runtimeFetch(`${
|
|
610
|
+
const { apiOrigin, fetchImpl } = resolvedConfig;
|
|
611
|
+
const response = await runtimeFetch(`${apiOrigin}/catalog/object`, {
|
|
619
612
|
body: JSON.stringify({
|
|
620
613
|
tinuuid: objectId
|
|
621
614
|
}),
|
|
@@ -633,9 +626,9 @@ async function fetchLegacyObject(objectId, signal, runtimeConfig) {
|
|
|
633
626
|
if (!data || 'object' != typeof data || Array.isArray(data)) throw new WidgetRuntimeError('INVALID_RESPONSE');
|
|
634
627
|
return data;
|
|
635
628
|
}
|
|
636
|
-
async function
|
|
637
|
-
const {
|
|
638
|
-
await fetchImpl(`${
|
|
629
|
+
async function incrementObjectViews(objectId, runtimeConfig) {
|
|
630
|
+
const { apiOrigin, fetchImpl } = runtimeConfig ?? getCoreArWidgetRuntimeConfig();
|
|
631
|
+
await fetchImpl(`${apiOrigin}/catalog/object/incr-views`, {
|
|
639
632
|
body: JSON.stringify({
|
|
640
633
|
tinuuid: objectId
|
|
641
634
|
}),
|
|
@@ -662,7 +655,7 @@ async function initializeAdvancedArTrigger(trigger, options = {}) {
|
|
|
662
655
|
const variantId = trigger.dataset.objectHid?.trim() || void 0;
|
|
663
656
|
if (!objectId) throw new Error('Object ID is required');
|
|
664
657
|
abortIfNeeded(options.signal);
|
|
665
|
-
const loadObject = options.loadObject ?? ((id, signal)=>
|
|
658
|
+
const loadObject = options.loadObject ?? ((id, signal)=>fetchPublicObject(id, signal, options.runtimeConfig));
|
|
666
659
|
const object = options.object ?? await loadObject(objectId, options.signal);
|
|
667
660
|
abortIfNeeded(options.signal);
|
|
668
661
|
if (!initialization.isCurrent()) return ()=>void 0;
|
|
@@ -680,7 +673,7 @@ async function initializeAdvancedArTrigger(trigger, options = {}) {
|
|
|
680
673
|
createdImage.hidden = true;
|
|
681
674
|
trigger.appendChild(createdImage);
|
|
682
675
|
}
|
|
683
|
-
const trackView = ()=>options.trackView ? options.trackView() :
|
|
676
|
+
const trackView = ()=>options.trackView ? options.trackView() : incrementObjectViews(objectId, options.runtimeConfig);
|
|
684
677
|
const handleDesktopClick = (event)=>{
|
|
685
678
|
event.preventDefault();
|
|
686
679
|
const revision = ++qrRevision;
|
|
@@ -732,6 +725,52 @@ async function initializeAdvancedArTrigger(trigger, options = {}) {
|
|
|
732
725
|
else trigger.setAttribute('data-native-link', originalNativeLink);
|
|
733
726
|
});
|
|
734
727
|
}
|
|
728
|
+
const DIALOG_EXIT_MS = 300;
|
|
729
|
+
let pendingLoad;
|
|
730
|
+
async function importModelViewerDialog() {
|
|
731
|
+
const [{ ModelViewerDialog }, { createElement }, { createRoot }] = await Promise.all([
|
|
732
|
+
import("@neurodyn/react-model-viewer"),
|
|
733
|
+
import("react"),
|
|
734
|
+
import("react-dom/client")
|
|
735
|
+
]);
|
|
736
|
+
return {
|
|
737
|
+
open: ({ onClose, ...props })=>{
|
|
738
|
+
const container = document.createElement('div');
|
|
739
|
+
container.setAttribute('data-core-ar-model-viewer', '');
|
|
740
|
+
document.body.appendChild(container);
|
|
741
|
+
const root = createRoot(container);
|
|
742
|
+
let closed = false;
|
|
743
|
+
const render = (open)=>root.render(createElement(ModelViewerDialog, {
|
|
744
|
+
...props,
|
|
745
|
+
onOpenChange: (next)=>{
|
|
746
|
+
if (!next) close();
|
|
747
|
+
},
|
|
748
|
+
open
|
|
749
|
+
}));
|
|
750
|
+
function close() {
|
|
751
|
+
if (closed) return;
|
|
752
|
+
closed = true;
|
|
753
|
+
render(false);
|
|
754
|
+
setTimeout(()=>{
|
|
755
|
+
root.unmount();
|
|
756
|
+
container.remove();
|
|
757
|
+
}, DIALOG_EXIT_MS);
|
|
758
|
+
onClose?.();
|
|
759
|
+
}
|
|
760
|
+
render(true);
|
|
761
|
+
return close;
|
|
762
|
+
}
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
function loadModelViewerDialog() {
|
|
766
|
+
if (pendingLoad) return pendingLoad;
|
|
767
|
+
const promise = importModelViewerDialog();
|
|
768
|
+
pendingLoad = promise;
|
|
769
|
+
promise.catch(()=>{
|
|
770
|
+
if (pendingLoad === promise) pendingLoad = void 0;
|
|
771
|
+
});
|
|
772
|
+
return promise;
|
|
773
|
+
}
|
|
735
774
|
const SIZE_TYPES = [
|
|
736
775
|
'cm',
|
|
737
776
|
'inch'
|
|
@@ -745,7 +784,6 @@ const DEFAULT_SIZE_TYPE = 'inch';
|
|
|
745
784
|
const ALL_DIMENSION_AXES = [
|
|
746
785
|
...DIMENSION_AXES
|
|
747
786
|
];
|
|
748
|
-
const VIEWER_CONTAINER_ID = 'vizbl_viewer';
|
|
749
787
|
const modal_trigger_beginInitialization = createElementInitializerRegistry();
|
|
750
788
|
function resolveSizeType(value) {
|
|
751
789
|
return value && SIZE_TYPES.includes(value) ? value : DEFAULT_SIZE_TYPE;
|
|
@@ -774,177 +812,60 @@ function createModalViewerUrl(params) {
|
|
|
774
812
|
url.hash = fragment.toString();
|
|
775
813
|
return url.toString();
|
|
776
814
|
}
|
|
777
|
-
function
|
|
778
|
-
const frame = document.createElement('iframe');
|
|
779
|
-
frame.src = src;
|
|
780
|
-
frame.title = '3D model viewer';
|
|
781
|
-
frame.allow = 'fullscreen; xr-spatial-tracking';
|
|
782
|
-
Object.assign(frame.style, {
|
|
783
|
-
backgroundColor: backgroundColor ?? 'white',
|
|
784
|
-
border: 'none',
|
|
785
|
-
height: '100%',
|
|
786
|
-
inset: '0',
|
|
787
|
-
position: 'absolute',
|
|
788
|
-
width: '100%',
|
|
789
|
-
zIndex: '11112'
|
|
790
|
-
});
|
|
791
|
-
return frame;
|
|
792
|
-
}
|
|
793
|
-
function createCloseButton(className, close, lang = 'en') {
|
|
794
|
-
const button = document.createElement('button');
|
|
795
|
-
button.type = 'button';
|
|
796
|
-
button.setAttribute('aria-label', 'ru' === lang ? 'Закрыть просмотр 3D-модели' : 'Close 3D model viewer');
|
|
797
|
-
if (className) button.className = className;
|
|
798
|
-
Object.assign(button.style, {
|
|
799
|
-
alignItems: 'center',
|
|
800
|
-
background: '#fff',
|
|
801
|
-
border: '1px solid #E3E7E7',
|
|
802
|
-
borderRadius: '4px',
|
|
803
|
-
boxSizing: 'border-box',
|
|
804
|
-
cursor: 'pointer',
|
|
805
|
-
display: 'flex',
|
|
806
|
-
height: '40px',
|
|
807
|
-
inset: '24px 24px auto auto',
|
|
808
|
-
justifyContent: 'center',
|
|
809
|
-
padding: '8px 16px',
|
|
810
|
-
position: 'absolute',
|
|
811
|
-
width: '56px',
|
|
812
|
-
zIndex: '11113'
|
|
813
|
-
});
|
|
814
|
-
button.innerHTML = '<svg aria-hidden="true" style="flex-shrink:0" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41Z" fill="#484D50"/></svg>';
|
|
815
|
-
button.addEventListener('click', close);
|
|
816
|
-
return button;
|
|
817
|
-
}
|
|
818
|
-
function openModal(options) {
|
|
819
|
-
if (document.getElementById(VIEWER_CONTAINER_ID)) return null;
|
|
820
|
-
const root = document.createElement('div');
|
|
821
|
-
const viewer = document.createElement('div');
|
|
822
|
-
const overlay = document.createElement('div');
|
|
823
|
-
const targetContainer = options.containerClassName ? document.getElementsByClassName(options.containerClassName)[0] : null;
|
|
824
|
-
const isInlineContainer = Boolean(targetContainer);
|
|
825
|
-
const lockTarget = isInlineContainer ? viewer : root;
|
|
826
|
-
let closed = false;
|
|
827
|
-
let close;
|
|
828
|
-
const handleKeydown = (event)=>{
|
|
829
|
-
if ('Escape' === event.key) close();
|
|
830
|
-
};
|
|
831
|
-
close = ()=>{
|
|
832
|
-
if (closed) return;
|
|
833
|
-
closed = true;
|
|
834
|
-
document.removeEventListener('keydown', handleKeydown);
|
|
835
|
-
enableBodyScroll(lockTarget);
|
|
836
|
-
(isInlineContainer ? viewer : root).remove();
|
|
837
|
-
options.onClose?.();
|
|
838
|
-
options.restoreFocusTo?.focus({
|
|
839
|
-
preventScroll: true
|
|
840
|
-
});
|
|
841
|
-
};
|
|
842
|
-
root.id = VIEWER_CONTAINER_ID;
|
|
843
|
-
Object.assign(root.style, {
|
|
844
|
-
inset: '0',
|
|
845
|
-
overflow: 'auto',
|
|
846
|
-
position: 'fixed',
|
|
847
|
-
zIndex: '2147483647'
|
|
848
|
-
});
|
|
849
|
-
root.style.webkitOverflowScrolling = 'touch';
|
|
850
|
-
viewer.setAttribute('role', 'dialog');
|
|
851
|
-
viewer.setAttribute('aria-modal', 'true');
|
|
852
|
-
viewer.setAttribute('aria-label', 'ru' === options.lang ? 'Просмотр 3D-модели' : '3D model viewer');
|
|
853
|
-
Object.assign(overlay.style, {
|
|
854
|
-
animation: 'vex-fadein 0.5s',
|
|
855
|
-
background: '#fff',
|
|
856
|
-
inset: '0',
|
|
857
|
-
position: 'fixed',
|
|
858
|
-
zIndex: '11111'
|
|
859
|
-
});
|
|
860
|
-
overlay.addEventListener('click', close);
|
|
861
|
-
if (options.width || options.height) {
|
|
862
|
-
overlay.style.background = 'rgba(0, 0, 0, 0.8)';
|
|
863
|
-
Object.assign(viewer.style, {
|
|
864
|
-
borderRadius: '12px',
|
|
865
|
-
height: options.height ?? '100%',
|
|
866
|
-
left: '50%',
|
|
867
|
-
overflow: 'hidden',
|
|
868
|
-
position: 'absolute',
|
|
869
|
-
top: '50%',
|
|
870
|
-
transform: 'translate(-50%, -50%)',
|
|
871
|
-
width: options.width ?? '100%',
|
|
872
|
-
zIndex: '11112'
|
|
873
|
-
});
|
|
874
|
-
}
|
|
875
|
-
const closeButton = createCloseButton(options.crossClassName, close, options.lang);
|
|
876
|
-
viewer.append(createFrame(createModalViewerUrl(options), options.backgroundColor), closeButton);
|
|
877
|
-
if (targetContainer) {
|
|
878
|
-
viewer.id = VIEWER_CONTAINER_ID;
|
|
879
|
-
targetContainer.appendChild(viewer);
|
|
880
|
-
} else {
|
|
881
|
-
root.append(overlay, viewer);
|
|
882
|
-
document.body.appendChild(root);
|
|
883
|
-
}
|
|
884
|
-
document.addEventListener('keydown', handleKeydown);
|
|
885
|
-
disableBodyScroll(lockTarget);
|
|
886
|
-
closeButton.focus({
|
|
887
|
-
preventScroll: true
|
|
888
|
-
});
|
|
889
|
-
return close;
|
|
890
|
-
}
|
|
891
|
-
function initializeModalTrigger(trigger, options = {}) {
|
|
815
|
+
function initializeModalTrigger(trigger, options) {
|
|
892
816
|
const initialization = modal_trigger_beginInitialization(trigger);
|
|
893
|
-
let
|
|
817
|
+
let closeOwnedViewer;
|
|
894
818
|
let pendingOpen = false;
|
|
895
819
|
const handleClick = async ()=>{
|
|
896
|
-
if (
|
|
820
|
+
if (closeOwnedViewer || pendingOpen) return;
|
|
897
821
|
const objectId = trigger.dataset.objectTinuuid?.trim();
|
|
898
822
|
if (!objectId) return;
|
|
899
823
|
pendingOpen = true;
|
|
900
|
-
|
|
824
|
+
runSafely(()=>options.onLoading?.());
|
|
901
825
|
try {
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
826
|
+
const widgetSessionToken = options.getWidgetSessionToken ? await options.getWidgetSessionToken() : options.widgetSessionToken;
|
|
827
|
+
const viewer = await loadModelViewerDialog();
|
|
828
|
+
if (closeOwnedViewer || !initialization.isCurrent()) return;
|
|
829
|
+
const modelViewerOrigin = options.modelViewerOrigin ?? getCoreArWidgetRuntimeConfig().modelViewerOrigin;
|
|
830
|
+
let closed = false;
|
|
831
|
+
closeOwnedViewer = viewer.open({
|
|
832
|
+
apiBaseUrl: options.viewer.apiBaseUrl,
|
|
833
|
+
apiKey: options.apiKey,
|
|
834
|
+
cameraOrbit: trigger.dataset.cameraOrbit,
|
|
835
|
+
dimensionAxes: resolveDimensionAxes(trigger.dataset.dimensionAxes),
|
|
836
|
+
handoffUrl: new URL('/model-viewer', modelViewerOrigin).toString(),
|
|
837
|
+
hid: trigger.dataset.objectHid,
|
|
838
|
+
initialWidgetSessionToken: widgetSessionToken,
|
|
839
|
+
lang: options.lang,
|
|
840
|
+
maxCameraOrbit: trigger.dataset.maxCameraOrbit,
|
|
841
|
+
minCameraOrbit: trigger.dataset.minCameraOrbit,
|
|
842
|
+
mode: options.mode,
|
|
843
|
+
onClose: ()=>{
|
|
844
|
+
if (closed) return;
|
|
845
|
+
closed = true;
|
|
846
|
+
closeOwnedViewer = void 0;
|
|
847
|
+
options.onClose?.();
|
|
848
|
+
trigger.focus({
|
|
849
|
+
preventScroll: true
|
|
850
|
+
});
|
|
851
|
+
},
|
|
852
|
+
sizeType: resolveSizeType(trigger.dataset.sizeType),
|
|
853
|
+
tinuuid: objectId
|
|
854
|
+
});
|
|
855
|
+
} catch (error) {
|
|
856
|
+
if (initialization.isCurrent()) runSafely(()=>options.onError?.(error));
|
|
905
857
|
return;
|
|
858
|
+
} finally{
|
|
859
|
+
pendingOpen = false;
|
|
906
860
|
}
|
|
907
|
-
pendingOpen = false;
|
|
908
|
-
if (closeOwnedModal || !initialization.isCurrent()) return;
|
|
909
|
-
const opened = openModal({
|
|
910
|
-
apiKey: options.apiKey,
|
|
911
|
-
backgroundColor: trigger.dataset.background,
|
|
912
|
-
buttonBgColor: trigger.dataset.buttonBgColor,
|
|
913
|
-
buttonBorderColor: trigger.dataset.buttonBorderColor,
|
|
914
|
-
buttonTextColor: trigger.dataset.buttonTextColor,
|
|
915
|
-
cameraOrbit: trigger.dataset.cameraOrbit,
|
|
916
|
-
containerClassName: trigger.dataset.container,
|
|
917
|
-
crossClassName: trigger.dataset.crossClassName,
|
|
918
|
-
dimensionAxes: resolveDimensionAxes(trigger.dataset.dimensionAxes),
|
|
919
|
-
height: trigger.dataset.height?.trim(),
|
|
920
|
-
hid: trigger.dataset.objectHid,
|
|
921
|
-
hidePreview: trigger.dataset.hidePreview,
|
|
922
|
-
hideTitle: trigger.dataset.hideTitle,
|
|
923
|
-
lang: options.lang,
|
|
924
|
-
maxCameraOrbit: trigger.dataset.maxCameraOrbit,
|
|
925
|
-
minCameraOrbit: trigger.dataset.minCameraOrbit,
|
|
926
|
-
mode: options.mode,
|
|
927
|
-
modelViewerOrigin: options.modelViewerOrigin,
|
|
928
|
-
onClose: ()=>{
|
|
929
|
-
closeOwnedModal = void 0;
|
|
930
|
-
options.onClose?.();
|
|
931
|
-
},
|
|
932
|
-
restoreFocusTo: trigger,
|
|
933
|
-
sizeType: resolveSizeType(trigger.dataset.sizeType),
|
|
934
|
-
tinuuid: objectId,
|
|
935
|
-
widgetSessionToken,
|
|
936
|
-
width: trigger.dataset.width?.trim()
|
|
937
|
-
});
|
|
938
|
-
if (!opened) return;
|
|
939
|
-
closeOwnedModal = opened;
|
|
940
861
|
options.onOpen?.();
|
|
941
862
|
runSafely(()=>options.onAction?.('widget_opened'));
|
|
942
863
|
};
|
|
943
864
|
trigger.addEventListener('click', handleClick);
|
|
944
865
|
return initialization.register(()=>{
|
|
945
866
|
trigger.removeEventListener('click', handleClick);
|
|
946
|
-
|
|
947
|
-
|
|
867
|
+
closeOwnedViewer?.();
|
|
868
|
+
closeOwnedViewer = void 0;
|
|
948
869
|
});
|
|
949
870
|
}
|
|
950
871
|
const native_ar_anchor_beginInitialization = createElementInitializerRegistry();
|
|
@@ -959,7 +880,7 @@ async function initializeNativeArAnchor(link, options = {}) {
|
|
|
959
880
|
const variantId = link.dataset.objectHid?.trim() || void 0;
|
|
960
881
|
if (!objectId) throw new Error('Object ID is required');
|
|
961
882
|
native_ar_anchor_abortIfNeeded(options.signal);
|
|
962
|
-
const loadObject = options.loadObject ?? ((id, signal)=>
|
|
883
|
+
const loadObject = options.loadObject ?? ((id, signal)=>fetchPublicObject(id, signal, options.runtimeConfig));
|
|
963
884
|
const object = options.object ?? await loadObject(objectId, options.signal);
|
|
964
885
|
native_ar_anchor_abortIfNeeded(options.signal);
|
|
965
886
|
if (!initialization.isCurrent()) return ()=>void 0;
|
|
@@ -993,7 +914,7 @@ async function initializeNativeArAnchor(link, options = {}) {
|
|
|
993
914
|
}).catch(()=>void 0);
|
|
994
915
|
};
|
|
995
916
|
const handleMobileClick = ()=>{
|
|
996
|
-
runSafely(options.trackView ?? (()=>
|
|
917
|
+
runSafely(options.trackView ?? (()=>incrementObjectViews(objectId, options.runtimeConfig)));
|
|
997
918
|
runSafely(()=>options.onAction?.('ar_launched'));
|
|
998
919
|
};
|
|
999
920
|
if (mobile) {
|
|
@@ -1148,6 +1069,31 @@ function installScopedStyles() {
|
|
|
1148
1069
|
:where(vizbl-core, arizo-core)[data-state="error"] [data-core-ar-widget-trigger] {
|
|
1149
1070
|
cursor: not-allowed;
|
|
1150
1071
|
}
|
|
1072
|
+
|
|
1073
|
+
:where(vizbl-core, arizo-core):not([unstyled])[data-state="loading"] [data-core-ar-widget-trigger] {
|
|
1074
|
+
color: transparent;
|
|
1075
|
+
position: relative;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
:where(vizbl-core, arizo-core):not([unstyled])[data-state="loading"] [data-core-ar-widget-trigger]::after {
|
|
1079
|
+
animation: core-ar-widget-spin 700ms linear infinite;
|
|
1080
|
+
border: 2px solid var(--core-ar-widget-color);
|
|
1081
|
+
border-radius: 50%;
|
|
1082
|
+
border-right-color: transparent;
|
|
1083
|
+
box-sizing: border-box;
|
|
1084
|
+
content: "";
|
|
1085
|
+
height: 1em;
|
|
1086
|
+
inset: 0;
|
|
1087
|
+
margin: auto;
|
|
1088
|
+
position: absolute;
|
|
1089
|
+
width: 1em;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
@keyframes core-ar-widget-spin {
|
|
1093
|
+
to {
|
|
1094
|
+
transform: rotate(360deg);
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1151
1097
|
`;
|
|
1152
1098
|
document.head.appendChild(style);
|
|
1153
1099
|
}
|
|
@@ -1275,13 +1221,13 @@ class CoreArWidgetElement extends HTMLElementBase {
|
|
|
1275
1221
|
this.applyIntegrationData(objectId, variantId, sizeType, dimensionAxes, cameraOrbit, minCameraOrbit, maxCameraOrbit);
|
|
1276
1222
|
let object;
|
|
1277
1223
|
if ('ar-viewer' === rawType) {
|
|
1278
|
-
object = await
|
|
1224
|
+
object = await fetchPublicObject(objectId, abortController.signal, runtimeConfig);
|
|
1279
1225
|
this.assertCurrent(revision, abortController.signal);
|
|
1280
1226
|
getSelectedMaterial(object, variantId);
|
|
1281
1227
|
assertPolicy(rawType, object);
|
|
1282
1228
|
this.object = object;
|
|
1283
1229
|
} else {
|
|
1284
|
-
object = isMobile() ? await this.fetchObjectWithSession(objectId, publicKey, session, runtimeConfig, abortController.signal, variantId) : await
|
|
1230
|
+
object = isMobile() ? await this.fetchObjectWithSession(objectId, publicKey, session, runtimeConfig, abortController.signal, variantId) : await fetchPublicObject(objectId, abortController.signal, runtimeConfig);
|
|
1285
1231
|
this.assertCurrent(revision, abortController.signal);
|
|
1286
1232
|
const material = getSelectedMaterial(object, variantId);
|
|
1287
1233
|
assertPolicy(rawType, object);
|
|
@@ -1313,6 +1259,16 @@ class CoreArWidgetElement extends HTMLElementBase {
|
|
|
1313
1259
|
});
|
|
1314
1260
|
}
|
|
1315
1261
|
}
|
|
1262
|
+
failInteraction(code, type) {
|
|
1263
|
+
if (!this.isConnected) return;
|
|
1264
|
+
this.setAttribute('data-error-code', code);
|
|
1265
|
+
this.setState('error');
|
|
1266
|
+
this.dispatchWidgetEvent('core-ar-error', {
|
|
1267
|
+
code,
|
|
1268
|
+
objectId: this.getAttribute('object-id')?.trim() ?? '',
|
|
1269
|
+
type
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1316
1272
|
async ensureSession(publicKey, runtimeConfig, mode, signal, forceRefresh = false) {
|
|
1317
1273
|
const runtimeKey = `${runtimeConfig.apiOrigin}|${runtimeConfig.viewerOrigin}|${runtimeConfig.modelViewerOrigin}|${mode}`;
|
|
1318
1274
|
const existing = this.session?.publicKey === publicKey && this.session.runtimeKey === runtimeKey ? this.session : void 0;
|
|
@@ -1440,7 +1396,12 @@ class CoreArWidgetElement extends HTMLElementBase {
|
|
|
1440
1396
|
onClose: ()=>{
|
|
1441
1397
|
if (this.isConnected) this.setState('ready');
|
|
1442
1398
|
},
|
|
1399
|
+
onError: ()=>this.failInteraction('VIEWER_UNAVAILABLE', type),
|
|
1400
|
+
onLoading: ()=>this.setState('loading'),
|
|
1443
1401
|
onOpen: ()=>this.setState('opening'),
|
|
1402
|
+
viewer: {
|
|
1403
|
+
apiBaseUrl: runtimeConfig.apiOrigin
|
|
1404
|
+
},
|
|
1444
1405
|
widgetSessionToken: session.token
|
|
1445
1406
|
});
|
|
1446
1407
|
if (!object) throw new CoreArWidgetComponentError('INITIALIZATION_FAILED');
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neurodyn/core-ar",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.1",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -20,18 +20,22 @@
|
|
|
20
20
|
"dist"
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"
|
|
23
|
+
"react": "^19.2.0",
|
|
24
|
+
"react-dom": "^19.2.0",
|
|
25
|
+
"@neurodyn/react-model-viewer": "0.1.1"
|
|
24
26
|
},
|
|
25
27
|
"devDependencies": {
|
|
28
|
+
"@rsbuild/core": "1.7.1",
|
|
26
29
|
"@rslib/core": "^0.18.6",
|
|
27
|
-
"@types/
|
|
30
|
+
"@types/react": "^19.2.4",
|
|
31
|
+
"@types/react-dom": "19.2.3",
|
|
28
32
|
"eslint": "9.39.1",
|
|
29
33
|
"happy-dom": "^17.6.3",
|
|
30
34
|
"typescript": "^5.9.3",
|
|
31
35
|
"vitest": "^3.0.5"
|
|
32
36
|
},
|
|
33
37
|
"scripts": {
|
|
34
|
-
"build": "rslib build",
|
|
38
|
+
"build": "rslib build && rsbuild build",
|
|
35
39
|
"dev": "rslib build --watch",
|
|
36
40
|
"test": "vitest run",
|
|
37
41
|
"lint": "eslint .",
|