@wewear/virtual-try-on 1.4.26 → 1.4.28
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/index.d.ts +3 -2
- package/dist/index.esm.js +84 -96
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +84 -95
- package/dist/index.js.map +1 -1
- package/dist/installer.d.ts +1 -0
- package/dist/widget.d.ts +6 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -3,11 +3,12 @@ export interface VirtualTryOnConfig {
|
|
|
3
3
|
baseUrl: string;
|
|
4
4
|
productPageSelector: string[];
|
|
5
5
|
gallerySelector: string;
|
|
6
|
+
galleryElement?: HTMLElement;
|
|
6
7
|
productImageSelector: string;
|
|
7
8
|
buttonPosition: ButtonPosition;
|
|
8
9
|
modelTier: string;
|
|
9
|
-
greenSuit: string;
|
|
10
10
|
outfitID: string;
|
|
11
|
+
singleton?: boolean;
|
|
11
12
|
}
|
|
12
13
|
export interface VirtualTryOnResult {
|
|
13
14
|
imageUrl: string | null;
|
|
@@ -16,5 +17,5 @@ export interface VirtualTryOnResult {
|
|
|
16
17
|
type: "error" | "warning";
|
|
17
18
|
};
|
|
18
19
|
}
|
|
19
|
-
export { getWidgetInstance, initVirtualTryOn, } from "./installer.js";
|
|
20
|
+
export { getWidgetInstance, getWidgetInstances, initVirtualTryOn, } from "./installer.js";
|
|
20
21
|
export { VirtualTryOnWidget } from "./widget.js";
|
package/dist/index.esm.js
CHANGED
|
@@ -20,12 +20,6 @@ function getPositionStyles(position) {
|
|
|
20
20
|
return "right: 20px; bottom: 20px;";
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
function removeElements(selector) {
|
|
24
|
-
const elements = document.querySelectorAll(selector);
|
|
25
|
-
elements.forEach((element) => {
|
|
26
|
-
element.remove();
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
23
|
|
|
30
24
|
function createButtonContainer(buttonPosition, hasVirtualTryOn = false, onCameraClick, onRefreshClick, onToggleClick, isShowingVirtualTryOn = false) {
|
|
31
25
|
const container = document.createElement("div");
|
|
@@ -395,7 +389,9 @@ class VirtualTryOnWidget {
|
|
|
395
389
|
this.isShowingVirtualTryOn = false;
|
|
396
390
|
this.lastModelImage = null;
|
|
397
391
|
this.cameraButton = null;
|
|
392
|
+
this.modalElement = null;
|
|
398
393
|
this.iframeMessageListener = null;
|
|
394
|
+
this.instanceId = ++VirtualTryOnWidget.instanceCounter;
|
|
399
395
|
this.config = {
|
|
400
396
|
baseUrl: config.baseUrl,
|
|
401
397
|
productPageSelector: config.productPageSelector,
|
|
@@ -403,10 +399,19 @@ class VirtualTryOnWidget {
|
|
|
403
399
|
productImageSelector: config.productImageSelector,
|
|
404
400
|
buttonPosition: config.buttonPosition,
|
|
405
401
|
modelTier: config.modelTier,
|
|
406
|
-
greenSuit: config.greenSuit,
|
|
407
402
|
outfitID: config.outfitID,
|
|
403
|
+
singleton: config.singleton,
|
|
404
|
+
galleryElement: config.galleryElement,
|
|
408
405
|
};
|
|
409
406
|
}
|
|
407
|
+
getContainer() {
|
|
408
|
+
const configContainer = this.config.galleryElement;
|
|
409
|
+
if (configContainer && configContainer.isConnected) {
|
|
410
|
+
return configContainer;
|
|
411
|
+
}
|
|
412
|
+
const queriedContainer = document.querySelector(this.config.gallerySelector);
|
|
413
|
+
return queriedContainer instanceof HTMLElement ? queriedContainer : null;
|
|
414
|
+
}
|
|
410
415
|
async init() {
|
|
411
416
|
try {
|
|
412
417
|
const selectors = this.config.productPageSelector;
|
|
@@ -415,8 +420,8 @@ class VirtualTryOnWidget {
|
|
|
415
420
|
if (!matches) {
|
|
416
421
|
return;
|
|
417
422
|
}
|
|
418
|
-
const container =
|
|
419
|
-
if (!container
|
|
423
|
+
const container = this.getContainer();
|
|
424
|
+
if (!container) {
|
|
420
425
|
console.warn("[WeWear VTO] Gallery container not found:", this.config.gallerySelector);
|
|
421
426
|
return;
|
|
422
427
|
}
|
|
@@ -463,7 +468,10 @@ class VirtualTryOnWidget {
|
|
|
463
468
|
}
|
|
464
469
|
}
|
|
465
470
|
getAllProductImages() {
|
|
466
|
-
const
|
|
471
|
+
const container = this.getContainer();
|
|
472
|
+
const scopedElements = container === null || container === void 0 ? void 0 : container.querySelectorAll(this.config.productImageSelector);
|
|
473
|
+
const fallbackElements = document.querySelectorAll(this.config.productImageSelector);
|
|
474
|
+
const productImageElements = ((scopedElements === null || scopedElements === void 0 ? void 0 : scopedElements.length) ? scopedElements : fallbackElements);
|
|
467
475
|
const images = [];
|
|
468
476
|
productImageElements.forEach((img) => {
|
|
469
477
|
const imageUrl = img.src ||
|
|
@@ -479,7 +487,8 @@ class VirtualTryOnWidget {
|
|
|
479
487
|
return images;
|
|
480
488
|
}
|
|
481
489
|
showPhotoUploadModal(url) {
|
|
482
|
-
|
|
490
|
+
this.closeModal();
|
|
491
|
+
VirtualTryOnWidget.activeWidgetId = this.instanceId;
|
|
483
492
|
const modal = document.createElement("div");
|
|
484
493
|
modal.className = CSS_CLASSES.MODAL;
|
|
485
494
|
modal.style.cssText = `
|
|
@@ -573,7 +582,7 @@ class VirtualTryOnWidget {
|
|
|
573
582
|
modal.style.opacity = "0";
|
|
574
583
|
iframeContainer.style.transform = "scale(0.95)";
|
|
575
584
|
iframeContainer.style.opacity = "0";
|
|
576
|
-
setTimeout(() =>
|
|
585
|
+
setTimeout(() => this.closeModal(), 300);
|
|
577
586
|
};
|
|
578
587
|
iframeContainer.appendChild(iframe);
|
|
579
588
|
iframeContainer.appendChild(closeButton);
|
|
@@ -584,12 +593,25 @@ class VirtualTryOnWidget {
|
|
|
584
593
|
closeButton.click();
|
|
585
594
|
}
|
|
586
595
|
};
|
|
596
|
+
this.modalElement = modal;
|
|
597
|
+
}
|
|
598
|
+
closeModal() {
|
|
599
|
+
if (this.modalElement) {
|
|
600
|
+
this.modalElement.remove();
|
|
601
|
+
this.modalElement = null;
|
|
602
|
+
}
|
|
603
|
+
if (VirtualTryOnWidget.activeWidgetId === this.instanceId) {
|
|
604
|
+
VirtualTryOnWidget.activeWidgetId = null;
|
|
605
|
+
}
|
|
587
606
|
}
|
|
588
607
|
setupIframeListener() {
|
|
589
608
|
if (this.iframeMessageListener) {
|
|
590
609
|
window.removeEventListener("message", this.iframeMessageListener);
|
|
591
610
|
}
|
|
592
611
|
this.iframeMessageListener = (event) => {
|
|
612
|
+
if (VirtualTryOnWidget.activeWidgetId !== this.instanceId) {
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
593
615
|
if (event.origin !== new URL(this.config.baseUrl).origin) {
|
|
594
616
|
return;
|
|
595
617
|
}
|
|
@@ -601,7 +623,7 @@ class VirtualTryOnWidget {
|
|
|
601
623
|
}
|
|
602
624
|
break;
|
|
603
625
|
case "CLOSE_MODAL":
|
|
604
|
-
|
|
626
|
+
this.closeModal();
|
|
605
627
|
break;
|
|
606
628
|
}
|
|
607
629
|
};
|
|
@@ -626,58 +648,18 @@ class VirtualTryOnWidget {
|
|
|
626
648
|
if (modal && modal instanceof HTMLElement) {
|
|
627
649
|
modal.style.display = "none";
|
|
628
650
|
}
|
|
629
|
-
const container =
|
|
630
|
-
if (container
|
|
651
|
+
const container = this.getContainer();
|
|
652
|
+
if (container) {
|
|
631
653
|
showProductLoading(container, "Preparing your personalized look");
|
|
632
654
|
}
|
|
633
|
-
let hasPreview = false;
|
|
634
655
|
try {
|
|
635
656
|
const submitResponse = await this.callVtoApi(this.lastModelImage, this.originalProductImages);
|
|
636
657
|
let status = await this.fetchJobStatus(submitResponse.job_id);
|
|
637
|
-
let lastPreviewCount = 0;
|
|
638
658
|
while (status.status !== "COMPLETED" && status.status !== "FAILED") {
|
|
639
|
-
if (
|
|
640
|
-
|
|
641
|
-
if (status.current_iteration === 1) {
|
|
642
|
-
statusMessage = "Refining your look";
|
|
643
|
-
}
|
|
644
|
-
else if (status.current_iteration && status.current_iteration > 1) {
|
|
645
|
-
statusMessage = "Finalizing your look";
|
|
646
|
-
}
|
|
659
|
+
if (container instanceof HTMLElement) {
|
|
660
|
+
const statusMessage = "Preparing your personalized look";
|
|
647
661
|
showProductLoading(container, statusMessage);
|
|
648
662
|
}
|
|
649
|
-
else if (hasPreview && container instanceof HTMLElement) {
|
|
650
|
-
let statusMessage = "Refining your look";
|
|
651
|
-
if (status.current_iteration && status.current_iteration > 1) {
|
|
652
|
-
statusMessage = "Finalizing your look";
|
|
653
|
-
}
|
|
654
|
-
showStatusBadge(container, statusMessage);
|
|
655
|
-
this.hideButtonContainer(container);
|
|
656
|
-
}
|
|
657
|
-
if (status.preview_count > lastPreviewCount) {
|
|
658
|
-
try {
|
|
659
|
-
const previewUrl = await this.fetchJobImage(submitResponse.job_id);
|
|
660
|
-
if (!hasPreview && container instanceof HTMLElement) {
|
|
661
|
-
this.replaceProductImage(previewUrl);
|
|
662
|
-
let statusMessage = "Refining your look";
|
|
663
|
-
if (status.current_iteration && status.current_iteration > 1) {
|
|
664
|
-
statusMessage = "Finalizing your look";
|
|
665
|
-
}
|
|
666
|
-
showStatusBadge(container, statusMessage);
|
|
667
|
-
this.hideButtonContainer(container);
|
|
668
|
-
removeProductLoading(container);
|
|
669
|
-
hasPreview = true;
|
|
670
|
-
}
|
|
671
|
-
else if (hasPreview) {
|
|
672
|
-
this.replaceProductImage(previewUrl);
|
|
673
|
-
}
|
|
674
|
-
lastPreviewCount = status.preview_count;
|
|
675
|
-
}
|
|
676
|
-
catch (e) {
|
|
677
|
-
if (!(e instanceof Error && e.message === "202_PROCESSING"))
|
|
678
|
-
throw e;
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
663
|
await new Promise((r) => setTimeout(r, 3000));
|
|
682
664
|
status = await this.fetchJobStatus(submitResponse.job_id);
|
|
683
665
|
}
|
|
@@ -694,12 +676,7 @@ class VirtualTryOnWidget {
|
|
|
694
676
|
if (status.status === "FAILED") {
|
|
695
677
|
console.error("[WeWear VTO] VTO process failed:", status.message);
|
|
696
678
|
if (container instanceof HTMLElement) {
|
|
697
|
-
|
|
698
|
-
showProductLoading(container, "We are experiencing some technical issues and apologise for any inconvenience caused. Please come back later again");
|
|
699
|
-
}
|
|
700
|
-
else {
|
|
701
|
-
showStatusBadge(container, "We are experiencing some technical issues and apologise for any inconvenience caused. Please come back later again");
|
|
702
|
-
}
|
|
679
|
+
showStatusBadge(container, "We are experiencing some technical issues and apologise for any inconvenience caused. Please come back later again");
|
|
703
680
|
}
|
|
704
681
|
await new Promise((r) => setTimeout(r, 5000));
|
|
705
682
|
}
|
|
@@ -707,12 +684,7 @@ class VirtualTryOnWidget {
|
|
|
707
684
|
catch (error) {
|
|
708
685
|
console.error("[WeWear VTO] Error during virtual try-on process:", error);
|
|
709
686
|
if (container instanceof HTMLElement) {
|
|
710
|
-
|
|
711
|
-
showProductLoading(container, "We are experiencing technical issues and apologise for any inconvenience caused. Please come back later again");
|
|
712
|
-
}
|
|
713
|
-
else {
|
|
714
|
-
showStatusBadge(container, "We are experiencing technical issues. Please try again later.");
|
|
715
|
-
}
|
|
687
|
+
showProductLoading(container, "We are experiencing technical issues and apologise for any inconvenience caused. Please come back later again");
|
|
716
688
|
}
|
|
717
689
|
await new Promise((r) => setTimeout(r, 5000));
|
|
718
690
|
}
|
|
@@ -722,7 +694,7 @@ class VirtualTryOnWidget {
|
|
|
722
694
|
removeStatusBadge(container);
|
|
723
695
|
this.showButtonContainer(container);
|
|
724
696
|
}
|
|
725
|
-
|
|
697
|
+
this.closeModal();
|
|
726
698
|
}
|
|
727
699
|
}
|
|
728
700
|
async callVtoApi(modelImage, productImages) {
|
|
@@ -732,7 +704,6 @@ class VirtualTryOnWidget {
|
|
|
732
704
|
formData.append("product_image_urls", JSON.stringify(productImages));
|
|
733
705
|
formData.append("page_url", window.location.href);
|
|
734
706
|
formData.append("model_tier", this.config.modelTier);
|
|
735
|
-
formData.append("green_suit", this.config.greenSuit);
|
|
736
707
|
const outfitID = (_a = this.config.outfitID) === null || _a === void 0 ? void 0 : _a.trim();
|
|
737
708
|
if (outfitID)
|
|
738
709
|
formData.append("outfit_id", outfitID);
|
|
@@ -769,8 +740,8 @@ class VirtualTryOnWidget {
|
|
|
769
740
|
replaceProductImage(imageUrl) {
|
|
770
741
|
try {
|
|
771
742
|
this.virtualTryOnImageUrl = imageUrl;
|
|
772
|
-
const container =
|
|
773
|
-
if (!container
|
|
743
|
+
const container = this.getContainer();
|
|
744
|
+
if (!container) {
|
|
774
745
|
console.warn("[WeWear VTO] Gallery container not found for image replacement:", this.config.gallerySelector);
|
|
775
746
|
return;
|
|
776
747
|
}
|
|
@@ -807,12 +778,6 @@ class VirtualTryOnWidget {
|
|
|
807
778
|
console.error("[WeWear VTO] Error replacing product image:", error);
|
|
808
779
|
}
|
|
809
780
|
}
|
|
810
|
-
hideButtonContainer(container) {
|
|
811
|
-
const buttonContainer = container.querySelector(`.${CSS_CLASSES.BUTTON_CONTAINER}`);
|
|
812
|
-
if (buttonContainer) {
|
|
813
|
-
buttonContainer.style.display = "none";
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
781
|
showButtonContainer(container) {
|
|
817
782
|
const buttonContainer = container.querySelector(`.${CSS_CLASSES.BUTTON_CONTAINER}`);
|
|
818
783
|
if (buttonContainer) {
|
|
@@ -901,8 +866,12 @@ class VirtualTryOnWidget {
|
|
|
901
866
|
}
|
|
902
867
|
destroy() {
|
|
903
868
|
try {
|
|
904
|
-
|
|
905
|
-
|
|
869
|
+
const container = this.getContainer();
|
|
870
|
+
if (container) {
|
|
871
|
+
const existingButtons = container.querySelectorAll(`.${CSS_CLASSES.BUTTON_CONTAINER}`);
|
|
872
|
+
existingButtons.forEach((btn) => btn.remove());
|
|
873
|
+
}
|
|
874
|
+
this.closeModal();
|
|
906
875
|
this.cameraButton = null;
|
|
907
876
|
if (this.iframeMessageListener) {
|
|
908
877
|
window.removeEventListener("message", this.iframeMessageListener);
|
|
@@ -920,30 +889,45 @@ class VirtualTryOnWidget {
|
|
|
920
889
|
}
|
|
921
890
|
}
|
|
922
891
|
}
|
|
892
|
+
VirtualTryOnWidget.instanceCounter = 0;
|
|
893
|
+
VirtualTryOnWidget.activeWidgetId = null;
|
|
923
894
|
|
|
924
|
-
let
|
|
895
|
+
let widgetInstances = [];
|
|
925
896
|
function initVirtualTryOn(config) {
|
|
926
897
|
try {
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
widgetInstance = null;
|
|
930
|
-
}
|
|
898
|
+
widgetInstances.forEach((instance) => instance.destroy());
|
|
899
|
+
widgetInstances = [];
|
|
931
900
|
if (!config) {
|
|
932
901
|
console.log("[WeWear VTO] Missing configuration. Widget not initialized.");
|
|
933
902
|
return;
|
|
934
903
|
}
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
});
|
|
904
|
+
const allContainers = Array.from(document.querySelectorAll(config.gallerySelector)).filter((container) => container instanceof HTMLElement);
|
|
905
|
+
const shouldUseSingleton = config.singleton !== false;
|
|
906
|
+
if (allContainers.length > 1 && !shouldUseSingleton) {
|
|
907
|
+
widgetInstances = allContainers.map((galleryElement) => {
|
|
908
|
+
return new VirtualTryOnWidget(Object.assign(Object.assign({}, config), { galleryElement }));
|
|
941
909
|
});
|
|
942
910
|
}
|
|
943
911
|
else {
|
|
944
|
-
|
|
945
|
-
|
|
912
|
+
const firstContainer = allContainers[0];
|
|
913
|
+
widgetInstances = [
|
|
914
|
+
new VirtualTryOnWidget(Object.assign(Object.assign({}, config), { galleryElement: firstContainer })),
|
|
915
|
+
];
|
|
916
|
+
}
|
|
917
|
+
const initializeWidgets = () => {
|
|
918
|
+
widgetInstances.forEach((widget) => {
|
|
919
|
+
widget.init().catch((error) => {
|
|
920
|
+
console.error("[WeWear VTO] Failed to initialize:", error);
|
|
921
|
+
});
|
|
946
922
|
});
|
|
923
|
+
};
|
|
924
|
+
if (document.readyState === "loading") {
|
|
925
|
+
document.addEventListener("DOMContentLoaded", initializeWidgets, {
|
|
926
|
+
once: true,
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
else {
|
|
930
|
+
initializeWidgets();
|
|
947
931
|
}
|
|
948
932
|
}
|
|
949
933
|
catch (error) {
|
|
@@ -951,11 +935,15 @@ function initVirtualTryOn(config) {
|
|
|
951
935
|
}
|
|
952
936
|
}
|
|
953
937
|
function getWidgetInstance() {
|
|
954
|
-
|
|
938
|
+
var _a;
|
|
939
|
+
return (_a = widgetInstances[0]) !== null && _a !== void 0 ? _a : null;
|
|
940
|
+
}
|
|
941
|
+
function getWidgetInstances() {
|
|
942
|
+
return [...widgetInstances];
|
|
955
943
|
}
|
|
956
944
|
if (typeof window !== "undefined") {
|
|
957
945
|
initVirtualTryOn();
|
|
958
946
|
}
|
|
959
947
|
|
|
960
|
-
export { VirtualTryOnWidget, getWidgetInstance, initVirtualTryOn };
|
|
948
|
+
export { VirtualTryOnWidget, getWidgetInstance, getWidgetInstances, initVirtualTryOn };
|
|
961
949
|
//# sourceMappingURL=index.esm.js.map
|