@wewear/virtual-try-on 1.4.27 → 1.4.29
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 -1
- package/dist/index.esm.js +131 -36
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +131 -35
- package/dist/index.js.map +1 -1
- package/dist/installer.d.ts +1 -0
- package/dist/widget.d.ts +7 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -3,10 +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
10
|
outfitID: string;
|
|
11
|
+
singleton?: boolean;
|
|
10
12
|
}
|
|
11
13
|
export interface VirtualTryOnResult {
|
|
12
14
|
imageUrl: string | null;
|
|
@@ -15,5 +17,5 @@ export interface VirtualTryOnResult {
|
|
|
15
17
|
type: "error" | "warning";
|
|
16
18
|
};
|
|
17
19
|
}
|
|
18
|
-
export { getWidgetInstance, initVirtualTryOn, } from "./installer.js";
|
|
20
|
+
export { getWidgetInstance, getWidgetInstances, initVirtualTryOn, } from "./installer.js";
|
|
19
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,
|
|
@@ -404,8 +400,18 @@ class VirtualTryOnWidget {
|
|
|
404
400
|
buttonPosition: config.buttonPosition,
|
|
405
401
|
modelTier: config.modelTier,
|
|
406
402
|
outfitID: config.outfitID,
|
|
403
|
+
singleton: config.singleton,
|
|
404
|
+
galleryElement: config.galleryElement,
|
|
407
405
|
};
|
|
408
406
|
}
|
|
407
|
+
getContainer() {
|
|
408
|
+
const configContainer = this.config.galleryElement;
|
|
409
|
+
if (configContainer === null || configContainer === void 0 ? void 0 : configContainer.isConnected) {
|
|
410
|
+
return configContainer;
|
|
411
|
+
}
|
|
412
|
+
const queriedContainer = document.querySelector(this.config.gallerySelector);
|
|
413
|
+
return queriedContainer instanceof HTMLElement ? queriedContainer : null;
|
|
414
|
+
}
|
|
409
415
|
async init() {
|
|
410
416
|
try {
|
|
411
417
|
const selectors = this.config.productPageSelector;
|
|
@@ -414,8 +420,8 @@ class VirtualTryOnWidget {
|
|
|
414
420
|
if (!matches) {
|
|
415
421
|
return;
|
|
416
422
|
}
|
|
417
|
-
const container =
|
|
418
|
-
if (!container
|
|
423
|
+
const container = this.getContainer();
|
|
424
|
+
if (!container) {
|
|
419
425
|
console.warn("[WeWear VTO] Gallery container not found:", this.config.gallerySelector);
|
|
420
426
|
return;
|
|
421
427
|
}
|
|
@@ -462,7 +468,10 @@ class VirtualTryOnWidget {
|
|
|
462
468
|
}
|
|
463
469
|
}
|
|
464
470
|
getAllProductImages() {
|
|
465
|
-
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);
|
|
466
475
|
const images = [];
|
|
467
476
|
productImageElements.forEach((img) => {
|
|
468
477
|
const imageUrl = img.src ||
|
|
@@ -478,7 +487,8 @@ class VirtualTryOnWidget {
|
|
|
478
487
|
return images;
|
|
479
488
|
}
|
|
480
489
|
showPhotoUploadModal(url) {
|
|
481
|
-
|
|
490
|
+
this.closeModal();
|
|
491
|
+
VirtualTryOnWidget.activeWidgetId = this.instanceId;
|
|
482
492
|
const modal = document.createElement("div");
|
|
483
493
|
modal.className = CSS_CLASSES.MODAL;
|
|
484
494
|
modal.style.cssText = `
|
|
@@ -572,7 +582,7 @@ class VirtualTryOnWidget {
|
|
|
572
582
|
modal.style.opacity = "0";
|
|
573
583
|
iframeContainer.style.transform = "scale(0.95)";
|
|
574
584
|
iframeContainer.style.opacity = "0";
|
|
575
|
-
setTimeout(() =>
|
|
585
|
+
setTimeout(() => this.closeModal(), 300);
|
|
576
586
|
};
|
|
577
587
|
iframeContainer.appendChild(iframe);
|
|
578
588
|
iframeContainer.appendChild(closeButton);
|
|
@@ -583,12 +593,25 @@ class VirtualTryOnWidget {
|
|
|
583
593
|
closeButton.click();
|
|
584
594
|
}
|
|
585
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
|
+
}
|
|
586
606
|
}
|
|
587
607
|
setupIframeListener() {
|
|
588
608
|
if (this.iframeMessageListener) {
|
|
589
609
|
window.removeEventListener("message", this.iframeMessageListener);
|
|
590
610
|
}
|
|
591
611
|
this.iframeMessageListener = (event) => {
|
|
612
|
+
if (VirtualTryOnWidget.activeWidgetId !== this.instanceId) {
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
592
615
|
if (event.origin !== new URL(this.config.baseUrl).origin) {
|
|
593
616
|
return;
|
|
594
617
|
}
|
|
@@ -600,7 +623,7 @@ class VirtualTryOnWidget {
|
|
|
600
623
|
}
|
|
601
624
|
break;
|
|
602
625
|
case "CLOSE_MODAL":
|
|
603
|
-
|
|
626
|
+
this.closeModal();
|
|
604
627
|
break;
|
|
605
628
|
}
|
|
606
629
|
};
|
|
@@ -625,8 +648,8 @@ class VirtualTryOnWidget {
|
|
|
625
648
|
if (modal && modal instanceof HTMLElement) {
|
|
626
649
|
modal.style.display = "none";
|
|
627
650
|
}
|
|
628
|
-
const container =
|
|
629
|
-
if (container
|
|
651
|
+
const container = this.getContainer();
|
|
652
|
+
if (container) {
|
|
630
653
|
showProductLoading(container, "Preparing your personalized look");
|
|
631
654
|
}
|
|
632
655
|
try {
|
|
@@ -671,17 +694,62 @@ class VirtualTryOnWidget {
|
|
|
671
694
|
removeStatusBadge(container);
|
|
672
695
|
this.showButtonContainer(container);
|
|
673
696
|
}
|
|
674
|
-
|
|
697
|
+
this.closeModal();
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
async fetchVtoData(outfitId, userBrand) {
|
|
701
|
+
try {
|
|
702
|
+
const vtoDataUrl = new URL("/api/vto/data", this.config.baseUrl);
|
|
703
|
+
vtoDataUrl.searchParams.set("outfit_id", outfitId);
|
|
704
|
+
vtoDataUrl.searchParams.set("user_brand", userBrand);
|
|
705
|
+
const response = await fetch(vtoDataUrl.toString());
|
|
706
|
+
if (response.status === 404)
|
|
707
|
+
return null;
|
|
708
|
+
if (!response.ok) {
|
|
709
|
+
const errorText = await response.text();
|
|
710
|
+
console.warn(`[WeWear VTO] Failed to retrieve VTO data (${response.status}): ${errorText}`);
|
|
711
|
+
return null;
|
|
712
|
+
}
|
|
713
|
+
return (await response.json());
|
|
714
|
+
}
|
|
715
|
+
catch (error) {
|
|
716
|
+
console.warn("[WeWear VTO] Error retrieving VTO data:", error);
|
|
717
|
+
return null;
|
|
675
718
|
}
|
|
676
719
|
}
|
|
677
720
|
async callVtoApi(modelImage, productImages) {
|
|
678
721
|
var _a;
|
|
722
|
+
const outfitID = (_a = this.config.outfitID) === null || _a === void 0 ? void 0 : _a.trim();
|
|
723
|
+
let resolvedProductImages = productImages;
|
|
724
|
+
let resolvedGeminiModel = null;
|
|
725
|
+
let resolvedAdditionalPrompt = null;
|
|
726
|
+
if (outfitID) {
|
|
727
|
+
const userBrand = window.location.href.split("#")[0];
|
|
728
|
+
const vtoData = await this.fetchVtoData(outfitID, userBrand);
|
|
729
|
+
if (vtoData) {
|
|
730
|
+
if (Array.isArray(vtoData.images) && vtoData.images.length > 0) {
|
|
731
|
+
resolvedProductImages = vtoData.images;
|
|
732
|
+
}
|
|
733
|
+
if (typeof vtoData.gemini_model === "string" && vtoData.gemini_model) {
|
|
734
|
+
resolvedGeminiModel = vtoData.gemini_model;
|
|
735
|
+
}
|
|
736
|
+
if (typeof vtoData.additional_prompt === "string" &&
|
|
737
|
+
vtoData.additional_prompt) {
|
|
738
|
+
resolvedAdditionalPrompt = vtoData.additional_prompt;
|
|
739
|
+
}
|
|
740
|
+
console.log(`[WeWear VTO] Using stored VTO data for outfit_id=${outfitID}, user_brand=${userBrand}`);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
679
743
|
const formData = new FormData();
|
|
680
744
|
formData.append("model_image", modelImage, "model_image.png");
|
|
681
|
-
formData.append("product_image_urls", JSON.stringify(
|
|
745
|
+
formData.append("product_image_urls", JSON.stringify(resolvedProductImages));
|
|
682
746
|
formData.append("page_url", window.location.href);
|
|
683
747
|
formData.append("model_tier", this.config.modelTier);
|
|
684
|
-
|
|
748
|
+
if (resolvedGeminiModel)
|
|
749
|
+
formData.append("gemini_model", resolvedGeminiModel);
|
|
750
|
+
if (resolvedAdditionalPrompt) {
|
|
751
|
+
formData.append("additional_prompt", resolvedAdditionalPrompt);
|
|
752
|
+
}
|
|
685
753
|
if (outfitID)
|
|
686
754
|
formData.append("outfit_id", outfitID);
|
|
687
755
|
const res = await fetch(`${this.config.baseUrl}/api/vto`, {
|
|
@@ -717,8 +785,8 @@ class VirtualTryOnWidget {
|
|
|
717
785
|
replaceProductImage(imageUrl) {
|
|
718
786
|
try {
|
|
719
787
|
this.virtualTryOnImageUrl = imageUrl;
|
|
720
|
-
const container =
|
|
721
|
-
if (!container
|
|
788
|
+
const container = this.getContainer();
|
|
789
|
+
if (!container) {
|
|
722
790
|
console.warn("[WeWear VTO] Gallery container not found for image replacement:", this.config.gallerySelector);
|
|
723
791
|
return;
|
|
724
792
|
}
|
|
@@ -843,8 +911,14 @@ class VirtualTryOnWidget {
|
|
|
843
911
|
}
|
|
844
912
|
destroy() {
|
|
845
913
|
try {
|
|
846
|
-
|
|
847
|
-
|
|
914
|
+
const container = this.getContainer();
|
|
915
|
+
if (container) {
|
|
916
|
+
const existingButtons = container.querySelectorAll(`.${CSS_CLASSES.BUTTON_CONTAINER}`);
|
|
917
|
+
existingButtons.forEach((btn) => {
|
|
918
|
+
btn.remove();
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
this.closeModal();
|
|
848
922
|
this.cameraButton = null;
|
|
849
923
|
if (this.iframeMessageListener) {
|
|
850
924
|
window.removeEventListener("message", this.iframeMessageListener);
|
|
@@ -862,42 +936,63 @@ class VirtualTryOnWidget {
|
|
|
862
936
|
}
|
|
863
937
|
}
|
|
864
938
|
}
|
|
939
|
+
VirtualTryOnWidget.instanceCounter = 0;
|
|
940
|
+
VirtualTryOnWidget.activeWidgetId = null;
|
|
865
941
|
|
|
866
|
-
let
|
|
942
|
+
let widgetInstances = [];
|
|
867
943
|
function initVirtualTryOn(config) {
|
|
868
944
|
try {
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
945
|
+
widgetInstances.forEach((instance) => {
|
|
946
|
+
instance.destroy();
|
|
947
|
+
});
|
|
948
|
+
widgetInstances = [];
|
|
873
949
|
if (!config) {
|
|
874
950
|
console.log("[WeWear VTO] Missing configuration. Widget not initialized.");
|
|
875
951
|
return;
|
|
876
952
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
});
|
|
953
|
+
const allContainers = Array.from(document.querySelectorAll(config.gallerySelector)).filter((container) => container instanceof HTMLElement);
|
|
954
|
+
const shouldUseSingleton = config.singleton !== false;
|
|
955
|
+
if (allContainers.length > 1 && !shouldUseSingleton) {
|
|
956
|
+
widgetInstances = allContainers.map((galleryElement) => {
|
|
957
|
+
return new VirtualTryOnWidget(Object.assign(Object.assign({}, config), { galleryElement }));
|
|
883
958
|
});
|
|
884
959
|
}
|
|
885
960
|
else {
|
|
886
|
-
|
|
887
|
-
|
|
961
|
+
const firstContainer = allContainers[0];
|
|
962
|
+
widgetInstances = [
|
|
963
|
+
new VirtualTryOnWidget(Object.assign(Object.assign({}, config), { galleryElement: firstContainer })),
|
|
964
|
+
];
|
|
965
|
+
}
|
|
966
|
+
const initializeWidgets = () => {
|
|
967
|
+
widgetInstances.forEach((widget) => {
|
|
968
|
+
widget.init().catch((error) => {
|
|
969
|
+
console.error("[WeWear VTO] Failed to initialize:", error);
|
|
970
|
+
});
|
|
971
|
+
});
|
|
972
|
+
};
|
|
973
|
+
if (document.readyState === "loading") {
|
|
974
|
+
document.addEventListener("DOMContentLoaded", initializeWidgets, {
|
|
975
|
+
once: true,
|
|
888
976
|
});
|
|
889
977
|
}
|
|
978
|
+
else {
|
|
979
|
+
initializeWidgets();
|
|
980
|
+
}
|
|
890
981
|
}
|
|
891
982
|
catch (error) {
|
|
892
983
|
console.error("[WeWear VTO] Initialization error:", error);
|
|
893
984
|
}
|
|
894
985
|
}
|
|
895
986
|
function getWidgetInstance() {
|
|
896
|
-
|
|
987
|
+
var _a;
|
|
988
|
+
return (_a = widgetInstances[0]) !== null && _a !== void 0 ? _a : null;
|
|
989
|
+
}
|
|
990
|
+
function getWidgetInstances() {
|
|
991
|
+
return [...widgetInstances];
|
|
897
992
|
}
|
|
898
993
|
if (typeof window !== "undefined") {
|
|
899
994
|
initVirtualTryOn();
|
|
900
995
|
}
|
|
901
996
|
|
|
902
|
-
export { VirtualTryOnWidget, getWidgetInstance, initVirtualTryOn };
|
|
997
|
+
export { VirtualTryOnWidget, getWidgetInstance, getWidgetInstances, initVirtualTryOn };
|
|
903
998
|
//# sourceMappingURL=index.esm.js.map
|