@wewear/virtual-try-on 1.0.0

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/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # @wewear/virtual-try-on
2
+
3
+ A lightweight virtual try-on widget for WooCommerce integration.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @wewear/virtual-try-on
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Basic Usage (Auto-initialization)
14
+
15
+ Simply include the script in your page and it will automatically initialize:
16
+
17
+ ```html
18
+ <script src="node_modules/@wewear/virtual-try-on/dist/index.js"></script>
19
+ ```
20
+
21
+ ### Manual Initialization
22
+
23
+ ```javascript
24
+ import { initVirtualTryOn } from '@wewear/virtual-try-on';
25
+
26
+ // Initialize with default configuration
27
+ initVirtualTryOn();
28
+
29
+ // Or with custom configuration
30
+ initVirtualTryOn({
31
+ baseUrl: 'https://your-custom-api.com',
32
+ buttonPosition: 'top-right',
33
+ gallerySelector: '.custom-gallery-selector'
34
+ });
35
+ ```
36
+
37
+ ### Using the Widget Class
38
+
39
+ ```javascript
40
+ import { VirtualTryOnWidget } from '@wewear/virtual-try-on';
41
+
42
+ const widget = new VirtualTryOnWidget({
43
+ baseUrl: 'https://your-api.com',
44
+ buttonPosition: 'bottom-left'
45
+ });
46
+
47
+ widget.init();
48
+
49
+ // Later, destroy the widget
50
+ widget.destroy();
51
+ ```
52
+
53
+ ## Configuration Options
54
+
55
+ | Option | Type | Default | Description |
56
+ |--------|------|---------|-------------|
57
+ | `baseUrl` | string | `'https://virtual-try-on-widget.vercel.app'` | Base URL for the virtual try-on API |
58
+ | `productPageSelector` | string | `'/product/'` | URL path pattern to identify product pages |
59
+ | `gallerySelector` | string | `'.woocommerce-product-gallery__image'` | CSS selector for the product gallery container |
60
+ | `skuSelector` | string | `'.sku'` | CSS selector for the product SKU element |
61
+ | `buttonPosition` | string | `'bottom-right'` | Position of the try-on button (`'bottom-right'`, `'bottom-left'`, `'top-right'`, `'top-left'`) |
62
+
63
+ ## Requirements
64
+
65
+ - The page must have cookies set for `ww_user_id` (required) and `ww_access_token` (optional)
66
+ - The product page must contain an element matching the `skuSelector` with the product SKU
67
+ - The product gallery must contain an element matching the `gallerySelector`
68
+
69
+ ## API
70
+
71
+ ### Functions
72
+
73
+ - `initVirtualTryOn(config?: VirtualTryOnConfig)` - Initialize the virtual try-on widget
74
+ - `destroyVirtualTryOn()` - Destroy the current widget instance
75
+
76
+ ### Classes
77
+
78
+ - `VirtualTryOnWidget` - Main widget class for advanced usage
79
+
80
+ ## License
81
+
82
+ MIT
@@ -0,0 +1,37 @@
1
+ /**
2
+ * WeWear Virtual Try-On Widget
3
+ *
4
+ * A professional virtual try-on widget for e-commerce integration.
5
+ * Provides seamless virtual try-on experiences for product pages.
6
+ *
7
+ * @version 1.0.0
8
+ * @author WeWear
9
+ */
10
+ export interface VirtualTryOnConfig {
11
+ /** Base URL for the virtual try-on API service */
12
+ baseUrl?: string;
13
+ /** URL pattern to identify product pages (default: '/product/') */
14
+ productPageSelector?: string;
15
+ /** CSS selector for the product gallery container */
16
+ gallerySelector?: string;
17
+ /** CSS selector for the product SKU element */
18
+ skuSelector?: string;
19
+ /** Position of the virtual try-on button */
20
+ buttonPosition?: "bottom-right" | "bottom-left" | "top-right" | "top-left";
21
+ }
22
+ export interface VirtualTryOnResult {
23
+ /** URL of the generated virtual try-on image */
24
+ imageUrl?: string;
25
+ /** Error message if the operation failed */
26
+ error?: string;
27
+ }
28
+ export interface VirtualTryOnAPIRequest {
29
+ /** Authentication token (optional) */
30
+ ww_access_token?: string;
31
+ /** User identifier (required) */
32
+ ww_user_id: string;
33
+ /** Product identifier (required) */
34
+ ww_product_id: string;
35
+ }
36
+ export { destroyVirtualTryOn, initVirtualTryOn } from "./installer.js";
37
+ export { VirtualTryOnWidget } from "./widget.js";
@@ -0,0 +1,431 @@
1
+ /**
2
+ * WeWear Virtual Try-On Widget Implementation
3
+ *
4
+ * Core widget class that handles virtual try-on functionality integration.
5
+ * Manages button creation, API communication, and modal display.
6
+ */
7
+ /** Default configuration constants */
8
+ const DEFAULT_CONFIG = {
9
+ BASE_URL: "https://virtual-try-on-widget.vercel.app",
10
+ PRODUCT_PAGE_SELECTOR: "/product/",
11
+ GALLERY_SELECTOR: ".woocommerce-product-gallery__image",
12
+ SKU_SELECTOR: ".sku",
13
+ BUTTON_POSITION: "bottom-right",
14
+ };
15
+ /** CSS class names for consistent styling */
16
+ const CSS_CLASSES = {
17
+ BUTTON_CONTAINER: "wewear-vto-button-container",
18
+ BUTTON: "wewear-vto-button",
19
+ MODAL: "wewear-vto-modal",
20
+ };
21
+ /** Z-index values for proper layering */
22
+ const Z_INDEX = {
23
+ BUTTON: 10,
24
+ MODAL: 99999,
25
+ };
26
+ class VirtualTryOnWidget {
27
+ constructor(config = {}) {
28
+ this.config = {
29
+ baseUrl: config.baseUrl || DEFAULT_CONFIG.BASE_URL,
30
+ productPageSelector: config.productPageSelector || DEFAULT_CONFIG.PRODUCT_PAGE_SELECTOR,
31
+ gallerySelector: config.gallerySelector || DEFAULT_CONFIG.GALLERY_SELECTOR,
32
+ skuSelector: config.skuSelector || DEFAULT_CONFIG.SKU_SELECTOR,
33
+ buttonPosition: config.buttonPosition || DEFAULT_CONFIG.BUTTON_POSITION,
34
+ };
35
+ }
36
+ /**
37
+ * Retrieves a cookie value by name
38
+ * @param name - Cookie name to retrieve
39
+ * @returns Cookie value or null if not found
40
+ */
41
+ getCookie(name) {
42
+ var _a;
43
+ if (typeof document === "undefined")
44
+ return null;
45
+ const value = `; ${document.cookie}`;
46
+ const parts = value.split(`; ${name}=`);
47
+ if (parts.length === 2) {
48
+ const part = parts.pop();
49
+ return part ? ((_a = part.split(";").shift()) === null || _a === void 0 ? void 0 : _a.trim()) || null : null;
50
+ }
51
+ return null;
52
+ }
53
+ /**
54
+ * Makes API call to virtual try-on service
55
+ * @param ww_access_token - Optional authentication token
56
+ * @param ww_user_id - User identifier
57
+ * @param ww_product_id - Product identifier
58
+ * @returns Promise with virtual try-on result or null if failed
59
+ */
60
+ async callVirtualTryOnApi(ww_access_token, ww_user_id, ww_product_id) {
61
+ try {
62
+ const response = await fetch(`${this.config.baseUrl}/api/virtual-try-on`, {
63
+ method: "POST",
64
+ headers: {
65
+ "Content-Type": "application/json",
66
+ Accept: "application/json",
67
+ },
68
+ body: JSON.stringify({
69
+ ww_access_token,
70
+ ww_user_id,
71
+ ww_product_id,
72
+ }),
73
+ });
74
+ if (!response.ok) {
75
+ throw new Error(`API responded with status ${response.status}: ${response.statusText}`);
76
+ }
77
+ const result = await response.json();
78
+ if (!result.imageUrl) {
79
+ throw new Error("API response missing imageUrl");
80
+ }
81
+ return result;
82
+ }
83
+ catch (error) {
84
+ console.error("[WeWear VTO] API call failed:", error);
85
+ return null;
86
+ }
87
+ }
88
+ /**
89
+ * Creates the virtual try-on button element
90
+ * @param onClick - Click handler function
91
+ * @returns Button container element
92
+ */
93
+ createButton(onClick) {
94
+ const container = document.createElement("div");
95
+ container.className = CSS_CLASSES.BUTTON_CONTAINER;
96
+ const positionStyles = this.getPositionStyles();
97
+ container.style.cssText = `
98
+ position: absolute;
99
+ ${positionStyles}
100
+ display: flex;
101
+ border-radius: 50%;
102
+ background: #000000;
103
+ padding: 4px;
104
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
105
+ z-index: ${Z_INDEX.BUTTON};
106
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
107
+ `;
108
+ const button = document.createElement("button");
109
+ button.type = "button";
110
+ button.className = CSS_CLASSES.BUTTON;
111
+ button.setAttribute("aria-label", "Virtual Try-On");
112
+ button.setAttribute("title", "Try this product virtually");
113
+ button.style.cssText = `
114
+ display: flex;
115
+ width: 36px;
116
+ height: 36px;
117
+ cursor: pointer;
118
+ align-items: center;
119
+ justify-content: center;
120
+ border-radius: 50%;
121
+ padding: 10px;
122
+ border: none;
123
+ background: transparent;
124
+ color: #ffffff;
125
+ `;
126
+ // Add hover effects
127
+ container.addEventListener("mouseenter", () => {
128
+ container.style.transform = "scale(1.05)";
129
+ container.style.boxShadow = "0 30px 60px -12px rgba(0, 0, 0, 0.35)";
130
+ });
131
+ container.addEventListener("mouseleave", () => {
132
+ container.style.transform = "scale(1)";
133
+ container.style.boxShadow = "0 25px 50px -12px rgba(0, 0, 0, 0.25)";
134
+ });
135
+ button.innerHTML = `
136
+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
137
+ <path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"></path>
138
+ <circle cx="12" cy="13" r="3"></circle>
139
+ </svg>
140
+ `;
141
+ button.onclick = onClick;
142
+ container.appendChild(button);
143
+ return container;
144
+ }
145
+ /**
146
+ * Gets CSS position styles based on button position configuration
147
+ * @returns CSS position string
148
+ */
149
+ getPositionStyles() {
150
+ switch (this.config.buttonPosition) {
151
+ case "bottom-left":
152
+ return "left: 20px; bottom: 20px;";
153
+ case "top-right":
154
+ return "right: 20px; top: 20px;";
155
+ case "top-left":
156
+ return "left: 20px; top: 20px;";
157
+ default:
158
+ return "right: 20px; bottom: 20px;";
159
+ }
160
+ }
161
+ /**
162
+ * Displays the virtual try-on result in a modal
163
+ * @param imageUrl - URL of the virtual try-on image
164
+ */
165
+ showImageModal(imageUrl) {
166
+ // Remove any existing modals first
167
+ const existingModals = document.querySelectorAll(`.${CSS_CLASSES.MODAL}`);
168
+ existingModals.forEach((modal) => {
169
+ modal.remove();
170
+ });
171
+ const modal = document.createElement("div");
172
+ modal.className = CSS_CLASSES.MODAL;
173
+ modal.setAttribute("role", "dialog");
174
+ modal.setAttribute("aria-modal", "true");
175
+ modal.setAttribute("aria-label", "Virtual Try-On Result");
176
+ modal.style.cssText = `
177
+ position: fixed;
178
+ top: 0;
179
+ left: 0;
180
+ width: 100%;
181
+ height: 100%;
182
+ background: rgba(0, 0, 0, 0.8);
183
+ display: flex;
184
+ align-items: center;
185
+ justify-content: center;
186
+ z-index: ${Z_INDEX.MODAL};
187
+ animation: fadeIn 0.3s ease;
188
+ `;
189
+ modal.innerHTML = `
190
+ <div style="
191
+ background: #ffffff;
192
+ padding: 20px;
193
+ border-radius: 12px;
194
+ max-width: 90vw;
195
+ max-height: 90vh;
196
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
197
+ animation: slideIn 0.3s ease;
198
+ ">
199
+ <img
200
+ src="${imageUrl}"
201
+ alt="Virtual Try-On Result"
202
+ style="
203
+ max-width: 100%;
204
+ max-height: 80vh;
205
+ border-radius: 8px;
206
+ display: block;
207
+ "
208
+ />
209
+ <div style="
210
+ text-align: right;
211
+ margin-top: 15px;
212
+ ">
213
+ <button
214
+ type="button"
215
+ style="
216
+ padding: 8px 16px;
217
+ border: none;
218
+ background: #000000;
219
+ color: #ffffff;
220
+ border-radius: 6px;
221
+ cursor: pointer;
222
+ font-size: 14px;
223
+ font-weight: 500;
224
+ transition: background-color 0.2s ease;
225
+ "
226
+ onmouseover="this.style.backgroundColor='#333333'"
227
+ onmouseout="this.style.backgroundColor='#000000'"
228
+ >
229
+ Close
230
+ </button>
231
+ </div>
232
+ </div>
233
+ <style>
234
+ @keyframes fadeIn {
235
+ from { opacity: 0; }
236
+ to { opacity: 1; }
237
+ }
238
+ @keyframes slideIn {
239
+ from { transform: scale(0.9) translateY(20px); opacity: 0; }
240
+ to { transform: scale(1) translateY(0); opacity: 1; }
241
+ }
242
+ </style>
243
+ `;
244
+ const closeButton = modal.querySelector("button");
245
+ const modalContent = modal.querySelector("div");
246
+ // Close on button click
247
+ if (closeButton) {
248
+ closeButton.onclick = () => modal.remove();
249
+ }
250
+ // Close on backdrop click
251
+ modal.onclick = (e) => {
252
+ if (e.target === modal) {
253
+ modal.remove();
254
+ }
255
+ };
256
+ // Prevent content clicks from closing modal
257
+ if (modalContent) {
258
+ modalContent.onclick = (e) => e.stopPropagation();
259
+ }
260
+ // Close on Escape key
261
+ const handleEscape = (e) => {
262
+ if (e.key === "Escape") {
263
+ modal.remove();
264
+ document.removeEventListener("keydown", handleEscape);
265
+ }
266
+ };
267
+ document.addEventListener("keydown", handleEscape);
268
+ document.body.appendChild(modal);
269
+ }
270
+ /**
271
+ * Initializes the virtual try-on widget on the current page
272
+ * @returns Promise that resolves when initialization is complete
273
+ */
274
+ async init() {
275
+ try {
276
+ // Check if we're on a product page
277
+ if (!window.location.pathname.includes(this.config.productPageSelector)) {
278
+ return;
279
+ }
280
+ // Find the gallery container
281
+ const container = document.querySelector(this.config.gallerySelector);
282
+ if (!container || !(container instanceof HTMLElement)) {
283
+ console.warn("[WeWear VTO] Gallery container not found:", this.config.gallerySelector);
284
+ return;
285
+ }
286
+ // Ensure container has relative positioning for button placement
287
+ if (getComputedStyle(container).position === "static") {
288
+ container.style.position = "relative";
289
+ }
290
+ // Create and add the virtual try-on button
291
+ const button = this.createButton(async () => {
292
+ await this.handleTryOnClick();
293
+ });
294
+ container.appendChild(button);
295
+ console.log("[WeWear VTO] Widget initialized successfully");
296
+ }
297
+ catch (error) {
298
+ console.error("[WeWear VTO] Initialization failed:", error);
299
+ }
300
+ }
301
+ /**
302
+ * Handles virtual try-on button click
303
+ * @private
304
+ */
305
+ async handleTryOnClick() {
306
+ var _a;
307
+ try {
308
+ // Get required data
309
+ const ww_access_token = this.getCookie("ww_access_token");
310
+ const ww_user_id = this.getCookie("ww_user_id");
311
+ const skuElement = document.querySelector(this.config.skuSelector);
312
+ const ww_product_id = (_a = skuElement === null || skuElement === void 0 ? void 0 : skuElement.textContent) === null || _a === void 0 ? void 0 : _a.trim();
313
+ // Validate required data
314
+ if (!ww_user_id) {
315
+ console.warn("[WeWear VTO] Missing required cookie: ww_user_id");
316
+ this.showError("Please sign in to use virtual try-on");
317
+ return;
318
+ }
319
+ if (!ww_product_id) {
320
+ console.warn("[WeWear VTO] Product SKU not found:", this.config.skuSelector);
321
+ this.showError("Product information not available");
322
+ return;
323
+ }
324
+ // Show loading state (could be implemented)
325
+ console.log("[WeWear VTO] Processing virtual try-on request...");
326
+ // Make API call
327
+ const result = await this.callVirtualTryOnApi(ww_access_token, ww_user_id, ww_product_id);
328
+ if (result === null || result === void 0 ? void 0 : result.imageUrl) {
329
+ this.showImageModal(result.imageUrl);
330
+ }
331
+ else {
332
+ this.showError("Virtual try-on service is currently unavailable. Please try again later.");
333
+ }
334
+ }
335
+ catch (error) {
336
+ console.error("[WeWear VTO] Try-on request failed:", error);
337
+ this.showError("An unexpected error occurred. Please try again.");
338
+ }
339
+ }
340
+ /**
341
+ * Shows an error message to the user
342
+ * @param message - Error message to display
343
+ * @private
344
+ */
345
+ showError(message) {
346
+ // Simple alert for now - could be enhanced with a custom modal
347
+ alert(`WeWear Virtual Try-On: ${message}`);
348
+ }
349
+ /**
350
+ * Destroys the widget and cleans up resources
351
+ */
352
+ destroy() {
353
+ try {
354
+ // Remove all buttons
355
+ const buttons = document.querySelectorAll(`.${CSS_CLASSES.BUTTON_CONTAINER}`);
356
+ buttons.forEach((button) => {
357
+ button.remove();
358
+ });
359
+ // Remove all modals
360
+ const modals = document.querySelectorAll(`.${CSS_CLASSES.MODAL}`);
361
+ modals.forEach((modal) => {
362
+ modal.remove();
363
+ });
364
+ console.log("[WeWear VTO] Widget destroyed successfully");
365
+ }
366
+ catch (error) {
367
+ console.error("[WeWear VTO] Error during widget destruction:", error);
368
+ }
369
+ }
370
+ }
371
+
372
+ /**
373
+ * WeWear Virtual Try-On Widget Auto-Installer
374
+ *
375
+ * Provides automatic initialization and management of the virtual try-on widget.
376
+ * Handles DOM ready states and widget lifecycle management.
377
+ */
378
+ let widgetInstance = null;
379
+ /**
380
+ * Initializes the virtual try-on widget with optional configuration
381
+ * @param config - Widget configuration options
382
+ */
383
+ function initVirtualTryOn(config) {
384
+ try {
385
+ // Clean up any existing instance
386
+ if (widgetInstance) {
387
+ widgetInstance.destroy();
388
+ widgetInstance = null;
389
+ }
390
+ // Create and initialize new instance
391
+ widgetInstance = new VirtualTryOnWidget(config);
392
+ // Initialize immediately if DOM is ready, otherwise wait for it
393
+ if (document.readyState === "loading") {
394
+ document.addEventListener("DOMContentLoaded", () => {
395
+ widgetInstance === null || widgetInstance === void 0 ? void 0 : widgetInstance.init().catch((error) => {
396
+ console.error("[WeWear VTO] Failed to initialize after DOM ready:", error);
397
+ });
398
+ });
399
+ }
400
+ else {
401
+ widgetInstance.init().catch((error) => {
402
+ console.error("[WeWear VTO] Failed to initialize:", error);
403
+ });
404
+ }
405
+ }
406
+ catch (error) {
407
+ console.error("[WeWear VTO] Initialization error:", error);
408
+ }
409
+ }
410
+ /**
411
+ * Destroys the current widget instance and cleans up resources
412
+ */
413
+ function destroyVirtualTryOn() {
414
+ try {
415
+ if (widgetInstance) {
416
+ widgetInstance.destroy();
417
+ widgetInstance = null;
418
+ console.log("[WeWear VTO] Widget instance destroyed");
419
+ }
420
+ }
421
+ catch (error) {
422
+ console.error("[WeWear VTO] Error destroying widget:", error);
423
+ }
424
+ }
425
+ // Auto-initialize if window object exists (browser environment)
426
+ if (typeof window !== "undefined") {
427
+ initVirtualTryOn();
428
+ }
429
+
430
+ export { VirtualTryOnWidget, destroyVirtualTryOn, initVirtualTryOn };
431
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":["../src/widget.ts","../src/installer.ts"],"sourcesContent":["/**\n * WeWear Virtual Try-On Widget Implementation\n *\n * Core widget class that handles virtual try-on functionality integration.\n * Manages button creation, API communication, and modal display.\n */\n\nimport type { VirtualTryOnConfig, VirtualTryOnResult } from \"./index.js\";\n\n/** Default configuration constants */\nconst DEFAULT_CONFIG = {\n BASE_URL: \"https://virtual-try-on-widget.vercel.app\",\n PRODUCT_PAGE_SELECTOR: \"/product/\",\n GALLERY_SELECTOR: \".woocommerce-product-gallery__image\",\n SKU_SELECTOR: \".sku\",\n BUTTON_POSITION: \"bottom-right\" as const,\n} as const;\n\n/** CSS class names for consistent styling */\nconst CSS_CLASSES = {\n BUTTON_CONTAINER: \"wewear-vto-button-container\",\n BUTTON: \"wewear-vto-button\",\n MODAL: \"wewear-vto-modal\",\n} as const;\n\n/** Z-index values for proper layering */\nconst Z_INDEX = {\n BUTTON: 10,\n MODAL: 99999,\n} as const;\n\nexport class VirtualTryOnWidget {\n private readonly config: Required<VirtualTryOnConfig>;\n\n constructor(config: VirtualTryOnConfig = {}) {\n this.config = {\n baseUrl: config.baseUrl || DEFAULT_CONFIG.BASE_URL,\n productPageSelector:\n config.productPageSelector || DEFAULT_CONFIG.PRODUCT_PAGE_SELECTOR,\n gallerySelector:\n config.gallerySelector || DEFAULT_CONFIG.GALLERY_SELECTOR,\n skuSelector: config.skuSelector || DEFAULT_CONFIG.SKU_SELECTOR,\n buttonPosition: config.buttonPosition || DEFAULT_CONFIG.BUTTON_POSITION,\n };\n }\n\n /**\n * Retrieves a cookie value by name\n * @param name - Cookie name to retrieve\n * @returns Cookie value or null if not found\n */\n private getCookie(name: string): string | null {\n if (typeof document === \"undefined\") return null;\n\n const value = `; ${document.cookie}`;\n const parts = value.split(`; ${name}=`);\n\n if (parts.length === 2) {\n const part = parts.pop();\n return part ? part.split(\";\").shift()?.trim() || null : null;\n }\n\n return null;\n }\n\n /**\n * Makes API call to virtual try-on service\n * @param ww_access_token - Optional authentication token\n * @param ww_user_id - User identifier\n * @param ww_product_id - Product identifier\n * @returns Promise with virtual try-on result or null if failed\n */\n private async callVirtualTryOnApi(\n ww_access_token: string | null,\n ww_user_id: string,\n ww_product_id: string,\n ): Promise<VirtualTryOnResult | null> {\n try {\n const response = await fetch(\n `${this.config.baseUrl}/api/virtual-try-on`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify({\n ww_access_token,\n ww_user_id,\n ww_product_id,\n }),\n },\n );\n\n if (!response.ok) {\n throw new Error(\n `API responded with status ${response.status}: ${response.statusText}`,\n );\n }\n\n const result = await response.json();\n\n if (!result.imageUrl) {\n throw new Error(\"API response missing imageUrl\");\n }\n\n return result;\n } catch (error) {\n console.error(\"[WeWear VTO] API call failed:\", error);\n return null;\n }\n }\n\n /**\n * Creates the virtual try-on button element\n * @param onClick - Click handler function\n * @returns Button container element\n */\n private createButton(onClick: () => void): HTMLElement {\n const container = document.createElement(\"div\");\n container.className = CSS_CLASSES.BUTTON_CONTAINER;\n\n const positionStyles = this.getPositionStyles();\n container.style.cssText = `\n position: absolute;\n ${positionStyles}\n display: flex;\n border-radius: 50%;\n background: #000000;\n padding: 4px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n z-index: ${Z_INDEX.BUTTON};\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n `;\n\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.className = CSS_CLASSES.BUTTON;\n button.setAttribute(\"aria-label\", \"Virtual Try-On\");\n button.setAttribute(\"title\", \"Try this product virtually\");\n button.style.cssText = `\n display: flex;\n width: 36px;\n height: 36px;\n cursor: pointer;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n padding: 10px;\n border: none;\n background: transparent;\n color: #ffffff;\n `;\n\n // Add hover effects\n container.addEventListener(\"mouseenter\", () => {\n container.style.transform = \"scale(1.05)\";\n container.style.boxShadow = \"0 30px 60px -12px rgba(0, 0, 0, 0.35)\";\n });\n\n container.addEventListener(\"mouseleave\", () => {\n container.style.transform = \"scale(1)\";\n container.style.boxShadow = \"0 25px 50px -12px rgba(0, 0, 0, 0.25)\";\n });\n\n button.innerHTML = `\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z\"></path>\n <circle cx=\"12\" cy=\"13\" r=\"3\"></circle>\n </svg>\n `;\n\n button.onclick = onClick;\n container.appendChild(button);\n return container;\n }\n\n /**\n * Gets CSS position styles based on button position configuration\n * @returns CSS position string\n */\n private getPositionStyles(): string {\n switch (this.config.buttonPosition) {\n case \"bottom-left\":\n return \"left: 20px; bottom: 20px;\";\n case \"top-right\":\n return \"right: 20px; top: 20px;\";\n case \"top-left\":\n return \"left: 20px; top: 20px;\";\n default:\n return \"right: 20px; bottom: 20px;\";\n }\n }\n\n /**\n * Displays the virtual try-on result in a modal\n * @param imageUrl - URL of the virtual try-on image\n */\n private showImageModal(imageUrl: string): void {\n // Remove any existing modals first\n const existingModals = document.querySelectorAll(`.${CSS_CLASSES.MODAL}`);\n existingModals.forEach((modal) => {\n modal.remove();\n });\n\n const modal = document.createElement(\"div\");\n modal.className = CSS_CLASSES.MODAL;\n modal.setAttribute(\"role\", \"dialog\");\n modal.setAttribute(\"aria-modal\", \"true\");\n modal.setAttribute(\"aria-label\", \"Virtual Try-On Result\");\n modal.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: ${Z_INDEX.MODAL};\n animation: fadeIn 0.3s ease;\n `;\n\n modal.innerHTML = `\n <div style=\"\n background: #ffffff;\n padding: 20px;\n border-radius: 12px;\n max-width: 90vw;\n max-height: 90vh;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);\n animation: slideIn 0.3s ease;\n \">\n <img \n src=\"${imageUrl}\" \n alt=\"Virtual Try-On Result\"\n style=\"\n max-width: 100%;\n max-height: 80vh;\n border-radius: 8px;\n display: block;\n \" \n />\n <div style=\"\n text-align: right;\n margin-top: 15px;\n \">\n <button \n type=\"button\"\n style=\"\n padding: 8px 16px;\n border: none;\n background: #000000;\n color: #ffffff;\n border-radius: 6px;\n cursor: pointer;\n font-size: 14px;\n font-weight: 500;\n transition: background-color 0.2s ease;\n \"\n onmouseover=\"this.style.backgroundColor='#333333'\"\n onmouseout=\"this.style.backgroundColor='#000000'\"\n >\n Close\n </button>\n </div>\n </div>\n <style>\n @keyframes fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n @keyframes slideIn {\n from { transform: scale(0.9) translateY(20px); opacity: 0; }\n to { transform: scale(1) translateY(0); opacity: 1; }\n }\n </style>\n `;\n\n const closeButton = modal.querySelector(\"button\");\n const modalContent = modal.querySelector(\"div\");\n\n // Close on button click\n if (closeButton) {\n closeButton.onclick = () => modal.remove();\n }\n\n // Close on backdrop click\n modal.onclick = (e) => {\n if (e.target === modal) {\n modal.remove();\n }\n };\n\n // Prevent content clicks from closing modal\n if (modalContent) {\n modalContent.onclick = (e) => e.stopPropagation();\n }\n\n // Close on Escape key\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n modal.remove();\n document.removeEventListener(\"keydown\", handleEscape);\n }\n };\n document.addEventListener(\"keydown\", handleEscape);\n\n document.body.appendChild(modal);\n }\n\n /**\n * Initializes the virtual try-on widget on the current page\n * @returns Promise that resolves when initialization is complete\n */\n public async init(): Promise<void> {\n try {\n // Check if we're on a product page\n if (!window.location.pathname.includes(this.config.productPageSelector)) {\n return;\n }\n\n // Find the gallery container\n const container = document.querySelector(this.config.gallerySelector);\n if (!container || !(container instanceof HTMLElement)) {\n console.warn(\n \"[WeWear VTO] Gallery container not found:\",\n this.config.gallerySelector,\n );\n return;\n }\n\n // Ensure container has relative positioning for button placement\n if (getComputedStyle(container).position === \"static\") {\n container.style.position = \"relative\";\n }\n\n // Create and add the virtual try-on button\n const button = this.createButton(async () => {\n await this.handleTryOnClick();\n });\n\n container.appendChild(button);\n console.log(\"[WeWear VTO] Widget initialized successfully\");\n } catch (error) {\n console.error(\"[WeWear VTO] Initialization failed:\", error);\n }\n }\n\n /**\n * Handles virtual try-on button click\n * @private\n */\n private async handleTryOnClick(): Promise<void> {\n try {\n // Get required data\n const ww_access_token = this.getCookie(\"ww_access_token\");\n const ww_user_id = this.getCookie(\"ww_user_id\");\n const skuElement = document.querySelector(this.config.skuSelector);\n const ww_product_id = skuElement?.textContent?.trim();\n\n // Validate required data\n if (!ww_user_id) {\n console.warn(\"[WeWear VTO] Missing required cookie: ww_user_id\");\n this.showError(\"Please sign in to use virtual try-on\");\n return;\n }\n\n if (!ww_product_id) {\n console.warn(\n \"[WeWear VTO] Product SKU not found:\",\n this.config.skuSelector,\n );\n this.showError(\"Product information not available\");\n return;\n }\n\n // Show loading state (could be implemented)\n console.log(\"[WeWear VTO] Processing virtual try-on request...\");\n\n // Make API call\n const result = await this.callVirtualTryOnApi(\n ww_access_token,\n ww_user_id,\n ww_product_id,\n );\n\n if (result?.imageUrl) {\n this.showImageModal(result.imageUrl);\n } else {\n this.showError(\n \"Virtual try-on service is currently unavailable. Please try again later.\",\n );\n }\n } catch (error) {\n console.error(\"[WeWear VTO] Try-on request failed:\", error);\n this.showError(\"An unexpected error occurred. Please try again.\");\n }\n }\n\n /**\n * Shows an error message to the user\n * @param message - Error message to display\n * @private\n */\n private showError(message: string): void {\n // Simple alert for now - could be enhanced with a custom modal\n alert(`WeWear Virtual Try-On: ${message}`);\n }\n\n /**\n * Destroys the widget and cleans up resources\n */\n public destroy(): void {\n try {\n // Remove all buttons\n const buttons = document.querySelectorAll(\n `.${CSS_CLASSES.BUTTON_CONTAINER}`,\n );\n buttons.forEach((button) => {\n button.remove();\n });\n\n // Remove all modals\n const modals = document.querySelectorAll(`.${CSS_CLASSES.MODAL}`);\n modals.forEach((modal) => {\n modal.remove();\n });\n\n console.log(\"[WeWear VTO] Widget destroyed successfully\");\n } catch (error) {\n console.error(\"[WeWear VTO] Error during widget destruction:\", error);\n }\n }\n}\n","/**\n * WeWear Virtual Try-On Widget Auto-Installer\n *\n * Provides automatic initialization and management of the virtual try-on widget.\n * Handles DOM ready states and widget lifecycle management.\n */\n\nimport type { VirtualTryOnConfig } from \"./index.js\";\nimport { VirtualTryOnWidget } from \"./widget.js\";\n\nlet widgetInstance: VirtualTryOnWidget | null = null;\n\n/**\n * Initializes the virtual try-on widget with optional configuration\n * @param config - Widget configuration options\n */\nexport function initVirtualTryOn(config?: VirtualTryOnConfig): void {\n try {\n // Clean up any existing instance\n if (widgetInstance) {\n widgetInstance.destroy();\n widgetInstance = null;\n }\n\n // Create and initialize new instance\n widgetInstance = new VirtualTryOnWidget(config);\n\n // Initialize immediately if DOM is ready, otherwise wait for it\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", () => {\n widgetInstance?.init().catch((error) => {\n console.error(\n \"[WeWear VTO] Failed to initialize after DOM ready:\",\n error,\n );\n });\n });\n } else {\n widgetInstance.init().catch((error) => {\n console.error(\"[WeWear VTO] Failed to initialize:\", error);\n });\n }\n } catch (error) {\n console.error(\"[WeWear VTO] Initialization error:\", error);\n }\n}\n\n/**\n * Destroys the current widget instance and cleans up resources\n */\nexport function destroyVirtualTryOn(): void {\n try {\n if (widgetInstance) {\n widgetInstance.destroy();\n widgetInstance = null;\n console.log(\"[WeWear VTO] Widget instance destroyed\");\n }\n } catch (error) {\n console.error(\"[WeWear VTO] Error destroying widget:\", error);\n }\n}\n\n/**\n * Gets the current widget instance (for debugging purposes)\n * @returns Current widget instance or null\n */\nexport function getWidgetInstance(): VirtualTryOnWidget | null {\n return widgetInstance;\n}\n\n// Auto-initialize if window object exists (browser environment)\nif (typeof window !== \"undefined\") {\n initVirtualTryOn();\n}\n"],"names":[],"mappings":"AAAA;;;;;AAKG;AAIH;AACA,MAAM,cAAc,GAAG;AACrB,IAAA,QAAQ,EAAE,0CAA0C;AACpD,IAAA,qBAAqB,EAAE,WAAW;AAClC,IAAA,gBAAgB,EAAE,qCAAqC;AACvD,IAAA,YAAY,EAAE,MAAM;AACpB,IAAA,eAAe,EAAE,cAAuB;CAChC;AAEV;AACA,MAAM,WAAW,GAAG;AAClB,IAAA,gBAAgB,EAAE,6BAA6B;AAC/C,IAAA,MAAM,EAAE,mBAAmB;AAC3B,IAAA,KAAK,EAAE,kBAAkB;CACjB;AAEV;AACA,MAAM,OAAO,GAAG;AACd,IAAA,MAAM,EAAE,EAAE;AACV,IAAA,KAAK,EAAE,KAAK;CACJ;MAEG,kBAAkB,CAAA;AAG7B,IAAA,WAAA,CAAY,SAA6B,EAAE,EAAA;QACzC,IAAI,CAAC,MAAM,GAAG;AACZ,YAAA,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,cAAc,CAAC,QAAQ;AAClD,YAAA,mBAAmB,EACjB,MAAM,CAAC,mBAAmB,IAAI,cAAc,CAAC,qBAAqB;AACpE,YAAA,eAAe,EACb,MAAM,CAAC,eAAe,IAAI,cAAc,CAAC,gBAAgB;AAC3D,YAAA,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,cAAc,CAAC,YAAY;AAC9D,YAAA,cAAc,EAAE,MAAM,CAAC,cAAc,IAAI,cAAc,CAAC,eAAe;SACxE;IACH;AAEA;;;;AAIG;AACK,IAAA,SAAS,CAAC,IAAY,EAAA;;QAC5B,IAAI,OAAO,QAAQ,KAAK,WAAW;AAAE,YAAA,OAAO,IAAI;AAEhD,QAAA,MAAM,KAAK,GAAG,CAAA,EAAA,EAAK,QAAQ,CAAC,MAAM,EAAE;QACpC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAA,EAAA,EAAK,IAAI,CAAA,CAAA,CAAG,CAAC;AAEvC,QAAA,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;AACtB,YAAA,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE;YACxB,OAAO,IAAI,GAAG,CAAA,MAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,MAAA,GAAA,EAAA,CAAE,IAAI,EAAE,KAAI,IAAI,GAAG,IAAI;QAC9D;AAEA,QAAA,OAAO,IAAI;IACb;AAEA;;;;;;AAMG;AACK,IAAA,MAAM,mBAAmB,CAC/B,eAA8B,EAC9B,UAAkB,EAClB,aAAqB,EAAA;AAErB,QAAA,IAAI;AACF,YAAA,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC1B,CAAA,EAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAA,mBAAA,CAAqB,EAC3C;AACE,gBAAA,MAAM,EAAE,MAAM;AACd,gBAAA,OAAO,EAAE;AACP,oBAAA,cAAc,EAAE,kBAAkB;AAClC,oBAAA,MAAM,EAAE,kBAAkB;AAC3B,iBAAA;AACD,gBAAA,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,eAAe;oBACf,UAAU;oBACV,aAAa;iBACd,CAAC;AACH,aAAA,CACF;AAED,YAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;AAChB,gBAAA,MAAM,IAAI,KAAK,CACb,CAAA,0BAAA,EAA6B,QAAQ,CAAC,MAAM,CAAA,EAAA,EAAK,QAAQ,CAAC,UAAU,CAAA,CAAE,CACvE;YACH;AAEA,YAAA,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE;AAEpC,YAAA,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;AACpB,gBAAA,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC;YAClD;AAEA,YAAA,OAAO,MAAM;QACf;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,KAAK,CAAC;AACrD,YAAA,OAAO,IAAI;QACb;IACF;AAEA;;;;AAIG;AACK,IAAA,YAAY,CAAC,OAAmB,EAAA;QACtC,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC;AAC/C,QAAA,SAAS,CAAC,SAAS,GAAG,WAAW,CAAC,gBAAgB;AAElD,QAAA,MAAM,cAAc,GAAG,IAAI,CAAC,iBAAiB,EAAE;AAC/C,QAAA,SAAS,CAAC,KAAK,CAAC,OAAO,GAAG;;QAEtB,cAAc;;;;;;AAML,eAAA,EAAA,OAAO,CAAC,MAAM,CAAA;;KAE1B;QAED,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC;AAC/C,QAAA,MAAM,CAAC,IAAI,GAAG,QAAQ;AACtB,QAAA,MAAM,CAAC,SAAS,GAAG,WAAW,CAAC,MAAM;AACrC,QAAA,MAAM,CAAC,YAAY,CAAC,YAAY,EAAE,gBAAgB,CAAC;AACnD,QAAA,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,4BAA4B,CAAC;AAC1D,QAAA,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG;;;;;;;;;;;;KAYtB;;AAGD,QAAA,SAAS,CAAC,gBAAgB,CAAC,YAAY,EAAE,MAAK;AAC5C,YAAA,SAAS,CAAC,KAAK,CAAC,SAAS,GAAG,aAAa;AACzC,YAAA,SAAS,CAAC,KAAK,CAAC,SAAS,GAAG,uCAAuC;AACrE,QAAA,CAAC,CAAC;AAEF,QAAA,SAAS,CAAC,gBAAgB,CAAC,YAAY,EAAE,MAAK;AAC5C,YAAA,SAAS,CAAC,KAAK,CAAC,SAAS,GAAG,UAAU;AACtC,YAAA,SAAS,CAAC,KAAK,CAAC,SAAS,GAAG,uCAAuC;AACrE,QAAA,CAAC,CAAC;QAEF,MAAM,CAAC,SAAS,GAAG;;;;;KAKlB;AAED,QAAA,MAAM,CAAC,OAAO,GAAG,OAAO;AACxB,QAAA,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC;AAC7B,QAAA,OAAO,SAAS;IAClB;AAEA;;;AAGG;IACK,iBAAiB,GAAA;AACvB,QAAA,QAAQ,IAAI,CAAC,MAAM,CAAC,cAAc;AAChC,YAAA,KAAK,aAAa;AAChB,gBAAA,OAAO,2BAA2B;AACpC,YAAA,KAAK,WAAW;AACd,gBAAA,OAAO,yBAAyB;AAClC,YAAA,KAAK,UAAU;AACb,gBAAA,OAAO,wBAAwB;AACjC,YAAA;AACE,gBAAA,OAAO,4BAA4B;;IAEzC;AAEA;;;AAGG;AACK,IAAA,cAAc,CAAC,QAAgB,EAAA;;AAErC,QAAA,MAAM,cAAc,GAAG,QAAQ,CAAC,gBAAgB,CAAC,CAAA,CAAA,EAAI,WAAW,CAAC,KAAK,CAAA,CAAE,CAAC;AACzE,QAAA,cAAc,CAAC,OAAO,CAAC,CAAC,KAAK,KAAI;YAC/B,KAAK,CAAC,MAAM,EAAE;AAChB,QAAA,CAAC,CAAC;QAEF,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC;AAC3C,QAAA,KAAK,CAAC,SAAS,GAAG,WAAW,CAAC,KAAK;AACnC,QAAA,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC;AACpC,QAAA,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC;AACxC,QAAA,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,uBAAuB,CAAC;AACzD,QAAA,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG;;;;;;;;;;AAUT,eAAA,EAAA,OAAO,CAAC,KAAK,CAAA;;KAEzB;QAED,KAAK,CAAC,SAAS,GAAG;;;;;;;;;;;iBAWL,QAAQ,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA2CpB;QAED,MAAM,WAAW,GAAG,KAAK,CAAC,aAAa,CAAC,QAAQ,CAAC;QACjD,MAAM,YAAY,GAAG,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC;;QAG/C,IAAI,WAAW,EAAE;YACf,WAAW,CAAC,OAAO,GAAG,MAAM,KAAK,CAAC,MAAM,EAAE;QAC5C;;AAGA,QAAA,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,KAAI;AACpB,YAAA,IAAI,CAAC,CAAC,MAAM,KAAK,KAAK,EAAE;gBACtB,KAAK,CAAC,MAAM,EAAE;YAChB;AACF,QAAA,CAAC;;QAGD,IAAI,YAAY,EAAE;AAChB,YAAA,YAAY,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,eAAe,EAAE;QACnD;;AAGA,QAAA,MAAM,YAAY,GAAG,CAAC,CAAgB,KAAI;AACxC,YAAA,IAAI,CAAC,CAAC,GAAG,KAAK,QAAQ,EAAE;gBACtB,KAAK,CAAC,MAAM,EAAE;AACd,gBAAA,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,YAAY,CAAC;YACvD;AACF,QAAA,CAAC;AACD,QAAA,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,YAAY,CAAC;AAElD,QAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;IAClC;AAEA;;;AAGG;AACI,IAAA,MAAM,IAAI,GAAA;AACf,QAAA,IAAI;;AAEF,YAAA,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE;gBACvE;YACF;;AAGA,YAAA,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC;YACrE,IAAI,CAAC,SAAS,IAAI,EAAE,SAAS,YAAY,WAAW,CAAC,EAAE;gBACrD,OAAO,CAAC,IAAI,CACV,2CAA2C,EAC3C,IAAI,CAAC,MAAM,CAAC,eAAe,CAC5B;gBACD;YACF;;YAGA,IAAI,gBAAgB,CAAC,SAAS,CAAC,CAAC,QAAQ,KAAK,QAAQ,EAAE;AACrD,gBAAA,SAAS,CAAC,KAAK,CAAC,QAAQ,GAAG,UAAU;YACvC;;YAGA,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,YAAW;AAC1C,gBAAA,MAAM,IAAI,CAAC,gBAAgB,EAAE;AAC/B,YAAA,CAAC,CAAC;AAEF,YAAA,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC;AAC7B,YAAA,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC;QAC7D;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,KAAK,CAAC;QAC7D;IACF;AAEA;;;AAGG;AACK,IAAA,MAAM,gBAAgB,GAAA;;AAC5B,QAAA,IAAI;;YAEF,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC;YACzD,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC;AAC/C,YAAA,MAAM,UAAU,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;AAClE,YAAA,MAAM,aAAa,GAAG,CAAA,EAAA,GAAA,UAAU,KAAA,IAAA,IAAV,UAAU,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAV,UAAU,CAAE,WAAW,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAE,IAAI,EAAE;;YAGrD,IAAI,CAAC,UAAU,EAAE;AACf,gBAAA,OAAO,CAAC,IAAI,CAAC,kDAAkD,CAAC;AAChE,gBAAA,IAAI,CAAC,SAAS,CAAC,sCAAsC,CAAC;gBACtD;YACF;YAEA,IAAI,CAAC,aAAa,EAAE;gBAClB,OAAO,CAAC,IAAI,CACV,qCAAqC,EACrC,IAAI,CAAC,MAAM,CAAC,WAAW,CACxB;AACD,gBAAA,IAAI,CAAC,SAAS,CAAC,mCAAmC,CAAC;gBACnD;YACF;;AAGA,YAAA,OAAO,CAAC,GAAG,CAAC,mDAAmD,CAAC;;AAGhE,YAAA,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAC3C,eAAe,EACf,UAAU,EACV,aAAa,CACd;YAED,IAAI,MAAM,aAAN,MAAM,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAN,MAAM,CAAE,QAAQ,EAAE;AACpB,gBAAA,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC;YACtC;iBAAO;AACL,gBAAA,IAAI,CAAC,SAAS,CACZ,0EAA0E,CAC3E;YACH;QACF;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,KAAK,CAAC;AAC3D,YAAA,IAAI,CAAC,SAAS,CAAC,iDAAiD,CAAC;QACnE;IACF;AAEA;;;;AAIG;AACK,IAAA,SAAS,CAAC,OAAe,EAAA;;AAE/B,QAAA,KAAK,CAAC,CAAA,uBAAA,EAA0B,OAAO,CAAA,CAAE,CAAC;IAC5C;AAEA;;AAEG;IACI,OAAO,GAAA;AACZ,QAAA,IAAI;;AAEF,YAAA,MAAM,OAAO,GAAG,QAAQ,CAAC,gBAAgB,CACvC,CAAA,CAAA,EAAI,WAAW,CAAC,gBAAgB,CAAA,CAAE,CACnC;AACD,YAAA,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,KAAI;gBACzB,MAAM,CAAC,MAAM,EAAE;AACjB,YAAA,CAAC,CAAC;;AAGF,YAAA,MAAM,MAAM,GAAG,QAAQ,CAAC,gBAAgB,CAAC,CAAA,CAAA,EAAI,WAAW,CAAC,KAAK,CAAA,CAAE,CAAC;AACjE,YAAA,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,KAAI;gBACvB,KAAK,CAAC,MAAM,EAAE;AAChB,YAAA,CAAC,CAAC;AAEF,YAAA,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC;QAC3D;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,OAAO,CAAC,KAAK,CAAC,+CAA+C,EAAE,KAAK,CAAC;QACvE;IACF;AACD;;ACnbD;;;;;AAKG;AAKH,IAAI,cAAc,GAA8B,IAAI;AAEpD;;;AAGG;AACG,SAAU,gBAAgB,CAAC,MAA2B,EAAA;AAC1D,IAAA,IAAI;;QAEF,IAAI,cAAc,EAAE;YAClB,cAAc,CAAC,OAAO,EAAE;YACxB,cAAc,GAAG,IAAI;QACvB;;AAGA,QAAA,cAAc,GAAG,IAAI,kBAAkB,CAAC,MAAM,CAAC;;AAG/C,QAAA,IAAI,QAAQ,CAAC,UAAU,KAAK,SAAS,EAAE;AACrC,YAAA,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,MAAK;AACjD,gBAAA,cAAc,KAAA,IAAA,IAAd,cAAc,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAd,cAAc,CAAE,IAAI,EAAA,CAAG,KAAK,CAAC,CAAC,KAAK,KAAI;AACrC,oBAAA,OAAO,CAAC,KAAK,CACX,oDAAoD,EACpD,KAAK,CACN;AACH,gBAAA,CAAC,CAAC;AACJ,YAAA,CAAC,CAAC;QACJ;aAAO;YACL,cAAc,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,KAAI;AACpC,gBAAA,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC;AAC5D,YAAA,CAAC,CAAC;QACJ;IACF;IAAE,OAAO,KAAK,EAAE;AACd,QAAA,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC;IAC5D;AACF;AAEA;;AAEG;SACa,mBAAmB,GAAA;AACjC,IAAA,IAAI;QACF,IAAI,cAAc,EAAE;YAClB,cAAc,CAAC,OAAO,EAAE;YACxB,cAAc,GAAG,IAAI;AACrB,YAAA,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC;QACvD;IACF;IAAE,OAAO,KAAK,EAAE;AACd,QAAA,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,KAAK,CAAC;IAC/D;AACF;AAUA;AACA,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;AACjC,IAAA,gBAAgB,EAAE;AACpB;;;;"}
package/dist/index.js ADDED
@@ -0,0 +1,441 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.WeWearVirtualTryOn = {}));
5
+ })(this, (function (exports) { 'use strict';
6
+
7
+ /**
8
+ * WeWear Virtual Try-On Widget Implementation
9
+ *
10
+ * Core widget class that handles virtual try-on functionality integration.
11
+ * Manages button creation, API communication, and modal display.
12
+ */
13
+ /** Default configuration constants */
14
+ const DEFAULT_CONFIG = {
15
+ BASE_URL: "https://virtual-try-on-widget.vercel.app",
16
+ PRODUCT_PAGE_SELECTOR: "/product/",
17
+ GALLERY_SELECTOR: ".woocommerce-product-gallery__image",
18
+ SKU_SELECTOR: ".sku",
19
+ BUTTON_POSITION: "bottom-right",
20
+ };
21
+ /** CSS class names for consistent styling */
22
+ const CSS_CLASSES = {
23
+ BUTTON_CONTAINER: "wewear-vto-button-container",
24
+ BUTTON: "wewear-vto-button",
25
+ MODAL: "wewear-vto-modal",
26
+ };
27
+ /** Z-index values for proper layering */
28
+ const Z_INDEX = {
29
+ BUTTON: 10,
30
+ MODAL: 99999,
31
+ };
32
+ class VirtualTryOnWidget {
33
+ constructor(config = {}) {
34
+ this.config = {
35
+ baseUrl: config.baseUrl || DEFAULT_CONFIG.BASE_URL,
36
+ productPageSelector: config.productPageSelector || DEFAULT_CONFIG.PRODUCT_PAGE_SELECTOR,
37
+ gallerySelector: config.gallerySelector || DEFAULT_CONFIG.GALLERY_SELECTOR,
38
+ skuSelector: config.skuSelector || DEFAULT_CONFIG.SKU_SELECTOR,
39
+ buttonPosition: config.buttonPosition || DEFAULT_CONFIG.BUTTON_POSITION,
40
+ };
41
+ }
42
+ /**
43
+ * Retrieves a cookie value by name
44
+ * @param name - Cookie name to retrieve
45
+ * @returns Cookie value or null if not found
46
+ */
47
+ getCookie(name) {
48
+ var _a;
49
+ if (typeof document === "undefined")
50
+ return null;
51
+ const value = `; ${document.cookie}`;
52
+ const parts = value.split(`; ${name}=`);
53
+ if (parts.length === 2) {
54
+ const part = parts.pop();
55
+ return part ? ((_a = part.split(";").shift()) === null || _a === void 0 ? void 0 : _a.trim()) || null : null;
56
+ }
57
+ return null;
58
+ }
59
+ /**
60
+ * Makes API call to virtual try-on service
61
+ * @param ww_access_token - Optional authentication token
62
+ * @param ww_user_id - User identifier
63
+ * @param ww_product_id - Product identifier
64
+ * @returns Promise with virtual try-on result or null if failed
65
+ */
66
+ async callVirtualTryOnApi(ww_access_token, ww_user_id, ww_product_id) {
67
+ try {
68
+ const response = await fetch(`${this.config.baseUrl}/api/virtual-try-on`, {
69
+ method: "POST",
70
+ headers: {
71
+ "Content-Type": "application/json",
72
+ Accept: "application/json",
73
+ },
74
+ body: JSON.stringify({
75
+ ww_access_token,
76
+ ww_user_id,
77
+ ww_product_id,
78
+ }),
79
+ });
80
+ if (!response.ok) {
81
+ throw new Error(`API responded with status ${response.status}: ${response.statusText}`);
82
+ }
83
+ const result = await response.json();
84
+ if (!result.imageUrl) {
85
+ throw new Error("API response missing imageUrl");
86
+ }
87
+ return result;
88
+ }
89
+ catch (error) {
90
+ console.error("[WeWear VTO] API call failed:", error);
91
+ return null;
92
+ }
93
+ }
94
+ /**
95
+ * Creates the virtual try-on button element
96
+ * @param onClick - Click handler function
97
+ * @returns Button container element
98
+ */
99
+ createButton(onClick) {
100
+ const container = document.createElement("div");
101
+ container.className = CSS_CLASSES.BUTTON_CONTAINER;
102
+ const positionStyles = this.getPositionStyles();
103
+ container.style.cssText = `
104
+ position: absolute;
105
+ ${positionStyles}
106
+ display: flex;
107
+ border-radius: 50%;
108
+ background: #000000;
109
+ padding: 4px;
110
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
111
+ z-index: ${Z_INDEX.BUTTON};
112
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
113
+ `;
114
+ const button = document.createElement("button");
115
+ button.type = "button";
116
+ button.className = CSS_CLASSES.BUTTON;
117
+ button.setAttribute("aria-label", "Virtual Try-On");
118
+ button.setAttribute("title", "Try this product virtually");
119
+ button.style.cssText = `
120
+ display: flex;
121
+ width: 36px;
122
+ height: 36px;
123
+ cursor: pointer;
124
+ align-items: center;
125
+ justify-content: center;
126
+ border-radius: 50%;
127
+ padding: 10px;
128
+ border: none;
129
+ background: transparent;
130
+ color: #ffffff;
131
+ `;
132
+ // Add hover effects
133
+ container.addEventListener("mouseenter", () => {
134
+ container.style.transform = "scale(1.05)";
135
+ container.style.boxShadow = "0 30px 60px -12px rgba(0, 0, 0, 0.35)";
136
+ });
137
+ container.addEventListener("mouseleave", () => {
138
+ container.style.transform = "scale(1)";
139
+ container.style.boxShadow = "0 25px 50px -12px rgba(0, 0, 0, 0.25)";
140
+ });
141
+ button.innerHTML = `
142
+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
143
+ <path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"></path>
144
+ <circle cx="12" cy="13" r="3"></circle>
145
+ </svg>
146
+ `;
147
+ button.onclick = onClick;
148
+ container.appendChild(button);
149
+ return container;
150
+ }
151
+ /**
152
+ * Gets CSS position styles based on button position configuration
153
+ * @returns CSS position string
154
+ */
155
+ getPositionStyles() {
156
+ switch (this.config.buttonPosition) {
157
+ case "bottom-left":
158
+ return "left: 20px; bottom: 20px;";
159
+ case "top-right":
160
+ return "right: 20px; top: 20px;";
161
+ case "top-left":
162
+ return "left: 20px; top: 20px;";
163
+ default:
164
+ return "right: 20px; bottom: 20px;";
165
+ }
166
+ }
167
+ /**
168
+ * Displays the virtual try-on result in a modal
169
+ * @param imageUrl - URL of the virtual try-on image
170
+ */
171
+ showImageModal(imageUrl) {
172
+ // Remove any existing modals first
173
+ const existingModals = document.querySelectorAll(`.${CSS_CLASSES.MODAL}`);
174
+ existingModals.forEach((modal) => {
175
+ modal.remove();
176
+ });
177
+ const modal = document.createElement("div");
178
+ modal.className = CSS_CLASSES.MODAL;
179
+ modal.setAttribute("role", "dialog");
180
+ modal.setAttribute("aria-modal", "true");
181
+ modal.setAttribute("aria-label", "Virtual Try-On Result");
182
+ modal.style.cssText = `
183
+ position: fixed;
184
+ top: 0;
185
+ left: 0;
186
+ width: 100%;
187
+ height: 100%;
188
+ background: rgba(0, 0, 0, 0.8);
189
+ display: flex;
190
+ align-items: center;
191
+ justify-content: center;
192
+ z-index: ${Z_INDEX.MODAL};
193
+ animation: fadeIn 0.3s ease;
194
+ `;
195
+ modal.innerHTML = `
196
+ <div style="
197
+ background: #ffffff;
198
+ padding: 20px;
199
+ border-radius: 12px;
200
+ max-width: 90vw;
201
+ max-height: 90vh;
202
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
203
+ animation: slideIn 0.3s ease;
204
+ ">
205
+ <img
206
+ src="${imageUrl}"
207
+ alt="Virtual Try-On Result"
208
+ style="
209
+ max-width: 100%;
210
+ max-height: 80vh;
211
+ border-radius: 8px;
212
+ display: block;
213
+ "
214
+ />
215
+ <div style="
216
+ text-align: right;
217
+ margin-top: 15px;
218
+ ">
219
+ <button
220
+ type="button"
221
+ style="
222
+ padding: 8px 16px;
223
+ border: none;
224
+ background: #000000;
225
+ color: #ffffff;
226
+ border-radius: 6px;
227
+ cursor: pointer;
228
+ font-size: 14px;
229
+ font-weight: 500;
230
+ transition: background-color 0.2s ease;
231
+ "
232
+ onmouseover="this.style.backgroundColor='#333333'"
233
+ onmouseout="this.style.backgroundColor='#000000'"
234
+ >
235
+ Close
236
+ </button>
237
+ </div>
238
+ </div>
239
+ <style>
240
+ @keyframes fadeIn {
241
+ from { opacity: 0; }
242
+ to { opacity: 1; }
243
+ }
244
+ @keyframes slideIn {
245
+ from { transform: scale(0.9) translateY(20px); opacity: 0; }
246
+ to { transform: scale(1) translateY(0); opacity: 1; }
247
+ }
248
+ </style>
249
+ `;
250
+ const closeButton = modal.querySelector("button");
251
+ const modalContent = modal.querySelector("div");
252
+ // Close on button click
253
+ if (closeButton) {
254
+ closeButton.onclick = () => modal.remove();
255
+ }
256
+ // Close on backdrop click
257
+ modal.onclick = (e) => {
258
+ if (e.target === modal) {
259
+ modal.remove();
260
+ }
261
+ };
262
+ // Prevent content clicks from closing modal
263
+ if (modalContent) {
264
+ modalContent.onclick = (e) => e.stopPropagation();
265
+ }
266
+ // Close on Escape key
267
+ const handleEscape = (e) => {
268
+ if (e.key === "Escape") {
269
+ modal.remove();
270
+ document.removeEventListener("keydown", handleEscape);
271
+ }
272
+ };
273
+ document.addEventListener("keydown", handleEscape);
274
+ document.body.appendChild(modal);
275
+ }
276
+ /**
277
+ * Initializes the virtual try-on widget on the current page
278
+ * @returns Promise that resolves when initialization is complete
279
+ */
280
+ async init() {
281
+ try {
282
+ // Check if we're on a product page
283
+ if (!window.location.pathname.includes(this.config.productPageSelector)) {
284
+ return;
285
+ }
286
+ // Find the gallery container
287
+ const container = document.querySelector(this.config.gallerySelector);
288
+ if (!container || !(container instanceof HTMLElement)) {
289
+ console.warn("[WeWear VTO] Gallery container not found:", this.config.gallerySelector);
290
+ return;
291
+ }
292
+ // Ensure container has relative positioning for button placement
293
+ if (getComputedStyle(container).position === "static") {
294
+ container.style.position = "relative";
295
+ }
296
+ // Create and add the virtual try-on button
297
+ const button = this.createButton(async () => {
298
+ await this.handleTryOnClick();
299
+ });
300
+ container.appendChild(button);
301
+ console.log("[WeWear VTO] Widget initialized successfully");
302
+ }
303
+ catch (error) {
304
+ console.error("[WeWear VTO] Initialization failed:", error);
305
+ }
306
+ }
307
+ /**
308
+ * Handles virtual try-on button click
309
+ * @private
310
+ */
311
+ async handleTryOnClick() {
312
+ var _a;
313
+ try {
314
+ // Get required data
315
+ const ww_access_token = this.getCookie("ww_access_token");
316
+ const ww_user_id = this.getCookie("ww_user_id");
317
+ const skuElement = document.querySelector(this.config.skuSelector);
318
+ const ww_product_id = (_a = skuElement === null || skuElement === void 0 ? void 0 : skuElement.textContent) === null || _a === void 0 ? void 0 : _a.trim();
319
+ // Validate required data
320
+ if (!ww_user_id) {
321
+ console.warn("[WeWear VTO] Missing required cookie: ww_user_id");
322
+ this.showError("Please sign in to use virtual try-on");
323
+ return;
324
+ }
325
+ if (!ww_product_id) {
326
+ console.warn("[WeWear VTO] Product SKU not found:", this.config.skuSelector);
327
+ this.showError("Product information not available");
328
+ return;
329
+ }
330
+ // Show loading state (could be implemented)
331
+ console.log("[WeWear VTO] Processing virtual try-on request...");
332
+ // Make API call
333
+ const result = await this.callVirtualTryOnApi(ww_access_token, ww_user_id, ww_product_id);
334
+ if (result === null || result === void 0 ? void 0 : result.imageUrl) {
335
+ this.showImageModal(result.imageUrl);
336
+ }
337
+ else {
338
+ this.showError("Virtual try-on service is currently unavailable. Please try again later.");
339
+ }
340
+ }
341
+ catch (error) {
342
+ console.error("[WeWear VTO] Try-on request failed:", error);
343
+ this.showError("An unexpected error occurred. Please try again.");
344
+ }
345
+ }
346
+ /**
347
+ * Shows an error message to the user
348
+ * @param message - Error message to display
349
+ * @private
350
+ */
351
+ showError(message) {
352
+ // Simple alert for now - could be enhanced with a custom modal
353
+ alert(`WeWear Virtual Try-On: ${message}`);
354
+ }
355
+ /**
356
+ * Destroys the widget and cleans up resources
357
+ */
358
+ destroy() {
359
+ try {
360
+ // Remove all buttons
361
+ const buttons = document.querySelectorAll(`.${CSS_CLASSES.BUTTON_CONTAINER}`);
362
+ buttons.forEach((button) => {
363
+ button.remove();
364
+ });
365
+ // Remove all modals
366
+ const modals = document.querySelectorAll(`.${CSS_CLASSES.MODAL}`);
367
+ modals.forEach((modal) => {
368
+ modal.remove();
369
+ });
370
+ console.log("[WeWear VTO] Widget destroyed successfully");
371
+ }
372
+ catch (error) {
373
+ console.error("[WeWear VTO] Error during widget destruction:", error);
374
+ }
375
+ }
376
+ }
377
+
378
+ /**
379
+ * WeWear Virtual Try-On Widget Auto-Installer
380
+ *
381
+ * Provides automatic initialization and management of the virtual try-on widget.
382
+ * Handles DOM ready states and widget lifecycle management.
383
+ */
384
+ let widgetInstance = null;
385
+ /**
386
+ * Initializes the virtual try-on widget with optional configuration
387
+ * @param config - Widget configuration options
388
+ */
389
+ function initVirtualTryOn(config) {
390
+ try {
391
+ // Clean up any existing instance
392
+ if (widgetInstance) {
393
+ widgetInstance.destroy();
394
+ widgetInstance = null;
395
+ }
396
+ // Create and initialize new instance
397
+ widgetInstance = new VirtualTryOnWidget(config);
398
+ // Initialize immediately if DOM is ready, otherwise wait for it
399
+ if (document.readyState === "loading") {
400
+ document.addEventListener("DOMContentLoaded", () => {
401
+ widgetInstance === null || widgetInstance === void 0 ? void 0 : widgetInstance.init().catch((error) => {
402
+ console.error("[WeWear VTO] Failed to initialize after DOM ready:", error);
403
+ });
404
+ });
405
+ }
406
+ else {
407
+ widgetInstance.init().catch((error) => {
408
+ console.error("[WeWear VTO] Failed to initialize:", error);
409
+ });
410
+ }
411
+ }
412
+ catch (error) {
413
+ console.error("[WeWear VTO] Initialization error:", error);
414
+ }
415
+ }
416
+ /**
417
+ * Destroys the current widget instance and cleans up resources
418
+ */
419
+ function destroyVirtualTryOn() {
420
+ try {
421
+ if (widgetInstance) {
422
+ widgetInstance.destroy();
423
+ widgetInstance = null;
424
+ console.log("[WeWear VTO] Widget instance destroyed");
425
+ }
426
+ }
427
+ catch (error) {
428
+ console.error("[WeWear VTO] Error destroying widget:", error);
429
+ }
430
+ }
431
+ // Auto-initialize if window object exists (browser environment)
432
+ if (typeof window !== "undefined") {
433
+ initVirtualTryOn();
434
+ }
435
+
436
+ exports.VirtualTryOnWidget = VirtualTryOnWidget;
437
+ exports.destroyVirtualTryOn = destroyVirtualTryOn;
438
+ exports.initVirtualTryOn = initVirtualTryOn;
439
+
440
+ }));
441
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/widget.ts","../src/installer.ts"],"sourcesContent":["/**\n * WeWear Virtual Try-On Widget Implementation\n *\n * Core widget class that handles virtual try-on functionality integration.\n * Manages button creation, API communication, and modal display.\n */\n\nimport type { VirtualTryOnConfig, VirtualTryOnResult } from \"./index.js\";\n\n/** Default configuration constants */\nconst DEFAULT_CONFIG = {\n BASE_URL: \"https://virtual-try-on-widget.vercel.app\",\n PRODUCT_PAGE_SELECTOR: \"/product/\",\n GALLERY_SELECTOR: \".woocommerce-product-gallery__image\",\n SKU_SELECTOR: \".sku\",\n BUTTON_POSITION: \"bottom-right\" as const,\n} as const;\n\n/** CSS class names for consistent styling */\nconst CSS_CLASSES = {\n BUTTON_CONTAINER: \"wewear-vto-button-container\",\n BUTTON: \"wewear-vto-button\",\n MODAL: \"wewear-vto-modal\",\n} as const;\n\n/** Z-index values for proper layering */\nconst Z_INDEX = {\n BUTTON: 10,\n MODAL: 99999,\n} as const;\n\nexport class VirtualTryOnWidget {\n private readonly config: Required<VirtualTryOnConfig>;\n\n constructor(config: VirtualTryOnConfig = {}) {\n this.config = {\n baseUrl: config.baseUrl || DEFAULT_CONFIG.BASE_URL,\n productPageSelector:\n config.productPageSelector || DEFAULT_CONFIG.PRODUCT_PAGE_SELECTOR,\n gallerySelector:\n config.gallerySelector || DEFAULT_CONFIG.GALLERY_SELECTOR,\n skuSelector: config.skuSelector || DEFAULT_CONFIG.SKU_SELECTOR,\n buttonPosition: config.buttonPosition || DEFAULT_CONFIG.BUTTON_POSITION,\n };\n }\n\n /**\n * Retrieves a cookie value by name\n * @param name - Cookie name to retrieve\n * @returns Cookie value or null if not found\n */\n private getCookie(name: string): string | null {\n if (typeof document === \"undefined\") return null;\n\n const value = `; ${document.cookie}`;\n const parts = value.split(`; ${name}=`);\n\n if (parts.length === 2) {\n const part = parts.pop();\n return part ? part.split(\";\").shift()?.trim() || null : null;\n }\n\n return null;\n }\n\n /**\n * Makes API call to virtual try-on service\n * @param ww_access_token - Optional authentication token\n * @param ww_user_id - User identifier\n * @param ww_product_id - Product identifier\n * @returns Promise with virtual try-on result or null if failed\n */\n private async callVirtualTryOnApi(\n ww_access_token: string | null,\n ww_user_id: string,\n ww_product_id: string,\n ): Promise<VirtualTryOnResult | null> {\n try {\n const response = await fetch(\n `${this.config.baseUrl}/api/virtual-try-on`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify({\n ww_access_token,\n ww_user_id,\n ww_product_id,\n }),\n },\n );\n\n if (!response.ok) {\n throw new Error(\n `API responded with status ${response.status}: ${response.statusText}`,\n );\n }\n\n const result = await response.json();\n\n if (!result.imageUrl) {\n throw new Error(\"API response missing imageUrl\");\n }\n\n return result;\n } catch (error) {\n console.error(\"[WeWear VTO] API call failed:\", error);\n return null;\n }\n }\n\n /**\n * Creates the virtual try-on button element\n * @param onClick - Click handler function\n * @returns Button container element\n */\n private createButton(onClick: () => void): HTMLElement {\n const container = document.createElement(\"div\");\n container.className = CSS_CLASSES.BUTTON_CONTAINER;\n\n const positionStyles = this.getPositionStyles();\n container.style.cssText = `\n position: absolute;\n ${positionStyles}\n display: flex;\n border-radius: 50%;\n background: #000000;\n padding: 4px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n z-index: ${Z_INDEX.BUTTON};\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n `;\n\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.className = CSS_CLASSES.BUTTON;\n button.setAttribute(\"aria-label\", \"Virtual Try-On\");\n button.setAttribute(\"title\", \"Try this product virtually\");\n button.style.cssText = `\n display: flex;\n width: 36px;\n height: 36px;\n cursor: pointer;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n padding: 10px;\n border: none;\n background: transparent;\n color: #ffffff;\n `;\n\n // Add hover effects\n container.addEventListener(\"mouseenter\", () => {\n container.style.transform = \"scale(1.05)\";\n container.style.boxShadow = \"0 30px 60px -12px rgba(0, 0, 0, 0.35)\";\n });\n\n container.addEventListener(\"mouseleave\", () => {\n container.style.transform = \"scale(1)\";\n container.style.boxShadow = \"0 25px 50px -12px rgba(0, 0, 0, 0.25)\";\n });\n\n button.innerHTML = `\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z\"></path>\n <circle cx=\"12\" cy=\"13\" r=\"3\"></circle>\n </svg>\n `;\n\n button.onclick = onClick;\n container.appendChild(button);\n return container;\n }\n\n /**\n * Gets CSS position styles based on button position configuration\n * @returns CSS position string\n */\n private getPositionStyles(): string {\n switch (this.config.buttonPosition) {\n case \"bottom-left\":\n return \"left: 20px; bottom: 20px;\";\n case \"top-right\":\n return \"right: 20px; top: 20px;\";\n case \"top-left\":\n return \"left: 20px; top: 20px;\";\n default:\n return \"right: 20px; bottom: 20px;\";\n }\n }\n\n /**\n * Displays the virtual try-on result in a modal\n * @param imageUrl - URL of the virtual try-on image\n */\n private showImageModal(imageUrl: string): void {\n // Remove any existing modals first\n const existingModals = document.querySelectorAll(`.${CSS_CLASSES.MODAL}`);\n existingModals.forEach((modal) => {\n modal.remove();\n });\n\n const modal = document.createElement(\"div\");\n modal.className = CSS_CLASSES.MODAL;\n modal.setAttribute(\"role\", \"dialog\");\n modal.setAttribute(\"aria-modal\", \"true\");\n modal.setAttribute(\"aria-label\", \"Virtual Try-On Result\");\n modal.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: ${Z_INDEX.MODAL};\n animation: fadeIn 0.3s ease;\n `;\n\n modal.innerHTML = `\n <div style=\"\n background: #ffffff;\n padding: 20px;\n border-radius: 12px;\n max-width: 90vw;\n max-height: 90vh;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);\n animation: slideIn 0.3s ease;\n \">\n <img \n src=\"${imageUrl}\" \n alt=\"Virtual Try-On Result\"\n style=\"\n max-width: 100%;\n max-height: 80vh;\n border-radius: 8px;\n display: block;\n \" \n />\n <div style=\"\n text-align: right;\n margin-top: 15px;\n \">\n <button \n type=\"button\"\n style=\"\n padding: 8px 16px;\n border: none;\n background: #000000;\n color: #ffffff;\n border-radius: 6px;\n cursor: pointer;\n font-size: 14px;\n font-weight: 500;\n transition: background-color 0.2s ease;\n \"\n onmouseover=\"this.style.backgroundColor='#333333'\"\n onmouseout=\"this.style.backgroundColor='#000000'\"\n >\n Close\n </button>\n </div>\n </div>\n <style>\n @keyframes fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n @keyframes slideIn {\n from { transform: scale(0.9) translateY(20px); opacity: 0; }\n to { transform: scale(1) translateY(0); opacity: 1; }\n }\n </style>\n `;\n\n const closeButton = modal.querySelector(\"button\");\n const modalContent = modal.querySelector(\"div\");\n\n // Close on button click\n if (closeButton) {\n closeButton.onclick = () => modal.remove();\n }\n\n // Close on backdrop click\n modal.onclick = (e) => {\n if (e.target === modal) {\n modal.remove();\n }\n };\n\n // Prevent content clicks from closing modal\n if (modalContent) {\n modalContent.onclick = (e) => e.stopPropagation();\n }\n\n // Close on Escape key\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n modal.remove();\n document.removeEventListener(\"keydown\", handleEscape);\n }\n };\n document.addEventListener(\"keydown\", handleEscape);\n\n document.body.appendChild(modal);\n }\n\n /**\n * Initializes the virtual try-on widget on the current page\n * @returns Promise that resolves when initialization is complete\n */\n public async init(): Promise<void> {\n try {\n // Check if we're on a product page\n if (!window.location.pathname.includes(this.config.productPageSelector)) {\n return;\n }\n\n // Find the gallery container\n const container = document.querySelector(this.config.gallerySelector);\n if (!container || !(container instanceof HTMLElement)) {\n console.warn(\n \"[WeWear VTO] Gallery container not found:\",\n this.config.gallerySelector,\n );\n return;\n }\n\n // Ensure container has relative positioning for button placement\n if (getComputedStyle(container).position === \"static\") {\n container.style.position = \"relative\";\n }\n\n // Create and add the virtual try-on button\n const button = this.createButton(async () => {\n await this.handleTryOnClick();\n });\n\n container.appendChild(button);\n console.log(\"[WeWear VTO] Widget initialized successfully\");\n } catch (error) {\n console.error(\"[WeWear VTO] Initialization failed:\", error);\n }\n }\n\n /**\n * Handles virtual try-on button click\n * @private\n */\n private async handleTryOnClick(): Promise<void> {\n try {\n // Get required data\n const ww_access_token = this.getCookie(\"ww_access_token\");\n const ww_user_id = this.getCookie(\"ww_user_id\");\n const skuElement = document.querySelector(this.config.skuSelector);\n const ww_product_id = skuElement?.textContent?.trim();\n\n // Validate required data\n if (!ww_user_id) {\n console.warn(\"[WeWear VTO] Missing required cookie: ww_user_id\");\n this.showError(\"Please sign in to use virtual try-on\");\n return;\n }\n\n if (!ww_product_id) {\n console.warn(\n \"[WeWear VTO] Product SKU not found:\",\n this.config.skuSelector,\n );\n this.showError(\"Product information not available\");\n return;\n }\n\n // Show loading state (could be implemented)\n console.log(\"[WeWear VTO] Processing virtual try-on request...\");\n\n // Make API call\n const result = await this.callVirtualTryOnApi(\n ww_access_token,\n ww_user_id,\n ww_product_id,\n );\n\n if (result?.imageUrl) {\n this.showImageModal(result.imageUrl);\n } else {\n this.showError(\n \"Virtual try-on service is currently unavailable. Please try again later.\",\n );\n }\n } catch (error) {\n console.error(\"[WeWear VTO] Try-on request failed:\", error);\n this.showError(\"An unexpected error occurred. Please try again.\");\n }\n }\n\n /**\n * Shows an error message to the user\n * @param message - Error message to display\n * @private\n */\n private showError(message: string): void {\n // Simple alert for now - could be enhanced with a custom modal\n alert(`WeWear Virtual Try-On: ${message}`);\n }\n\n /**\n * Destroys the widget and cleans up resources\n */\n public destroy(): void {\n try {\n // Remove all buttons\n const buttons = document.querySelectorAll(\n `.${CSS_CLASSES.BUTTON_CONTAINER}`,\n );\n buttons.forEach((button) => {\n button.remove();\n });\n\n // Remove all modals\n const modals = document.querySelectorAll(`.${CSS_CLASSES.MODAL}`);\n modals.forEach((modal) => {\n modal.remove();\n });\n\n console.log(\"[WeWear VTO] Widget destroyed successfully\");\n } catch (error) {\n console.error(\"[WeWear VTO] Error during widget destruction:\", error);\n }\n }\n}\n","/**\n * WeWear Virtual Try-On Widget Auto-Installer\n *\n * Provides automatic initialization and management of the virtual try-on widget.\n * Handles DOM ready states and widget lifecycle management.\n */\n\nimport type { VirtualTryOnConfig } from \"./index.js\";\nimport { VirtualTryOnWidget } from \"./widget.js\";\n\nlet widgetInstance: VirtualTryOnWidget | null = null;\n\n/**\n * Initializes the virtual try-on widget with optional configuration\n * @param config - Widget configuration options\n */\nexport function initVirtualTryOn(config?: VirtualTryOnConfig): void {\n try {\n // Clean up any existing instance\n if (widgetInstance) {\n widgetInstance.destroy();\n widgetInstance = null;\n }\n\n // Create and initialize new instance\n widgetInstance = new VirtualTryOnWidget(config);\n\n // Initialize immediately if DOM is ready, otherwise wait for it\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", () => {\n widgetInstance?.init().catch((error) => {\n console.error(\n \"[WeWear VTO] Failed to initialize after DOM ready:\",\n error,\n );\n });\n });\n } else {\n widgetInstance.init().catch((error) => {\n console.error(\"[WeWear VTO] Failed to initialize:\", error);\n });\n }\n } catch (error) {\n console.error(\"[WeWear VTO] Initialization error:\", error);\n }\n}\n\n/**\n * Destroys the current widget instance and cleans up resources\n */\nexport function destroyVirtualTryOn(): void {\n try {\n if (widgetInstance) {\n widgetInstance.destroy();\n widgetInstance = null;\n console.log(\"[WeWear VTO] Widget instance destroyed\");\n }\n } catch (error) {\n console.error(\"[WeWear VTO] Error destroying widget:\", error);\n }\n}\n\n/**\n * Gets the current widget instance (for debugging purposes)\n * @returns Current widget instance or null\n */\nexport function getWidgetInstance(): VirtualTryOnWidget | null {\n return widgetInstance;\n}\n\n// Auto-initialize if window object exists (browser environment)\nif (typeof window !== \"undefined\") {\n initVirtualTryOn();\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * WeWear Virtual Try-On Widget Auto-Installer
3
+ *
4
+ * Provides automatic initialization and management of the virtual try-on widget.
5
+ * Handles DOM ready states and widget lifecycle management.
6
+ */
7
+ import type { VirtualTryOnConfig } from "./index.js";
8
+ import { VirtualTryOnWidget } from "./widget.js";
9
+ /**
10
+ * Initializes the virtual try-on widget with optional configuration
11
+ * @param config - Widget configuration options
12
+ */
13
+ export declare function initVirtualTryOn(config?: VirtualTryOnConfig): void;
14
+ /**
15
+ * Destroys the current widget instance and cleans up resources
16
+ */
17
+ export declare function destroyVirtualTryOn(): void;
18
+ /**
19
+ * Gets the current widget instance (for debugging purposes)
20
+ * @returns Current widget instance or null
21
+ */
22
+ export declare function getWidgetInstance(): VirtualTryOnWidget | null;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * WeWear Virtual Try-On Widget Implementation
3
+ *
4
+ * Core widget class that handles virtual try-on functionality integration.
5
+ * Manages button creation, API communication, and modal display.
6
+ */
7
+ import type { VirtualTryOnConfig } from "./index.js";
8
+ export declare class VirtualTryOnWidget {
9
+ private readonly config;
10
+ constructor(config?: VirtualTryOnConfig);
11
+ /**
12
+ * Retrieves a cookie value by name
13
+ * @param name - Cookie name to retrieve
14
+ * @returns Cookie value or null if not found
15
+ */
16
+ private getCookie;
17
+ /**
18
+ * Makes API call to virtual try-on service
19
+ * @param ww_access_token - Optional authentication token
20
+ * @param ww_user_id - User identifier
21
+ * @param ww_product_id - Product identifier
22
+ * @returns Promise with virtual try-on result or null if failed
23
+ */
24
+ private callVirtualTryOnApi;
25
+ /**
26
+ * Creates the virtual try-on button element
27
+ * @param onClick - Click handler function
28
+ * @returns Button container element
29
+ */
30
+ private createButton;
31
+ /**
32
+ * Gets CSS position styles based on button position configuration
33
+ * @returns CSS position string
34
+ */
35
+ private getPositionStyles;
36
+ /**
37
+ * Displays the virtual try-on result in a modal
38
+ * @param imageUrl - URL of the virtual try-on image
39
+ */
40
+ private showImageModal;
41
+ /**
42
+ * Initializes the virtual try-on widget on the current page
43
+ * @returns Promise that resolves when initialization is complete
44
+ */
45
+ init(): Promise<void>;
46
+ /**
47
+ * Handles virtual try-on button click
48
+ * @private
49
+ */
50
+ private handleTryOnClick;
51
+ /**
52
+ * Shows an error message to the user
53
+ * @param message - Error message to display
54
+ * @private
55
+ */
56
+ private showError;
57
+ /**
58
+ * Destroys the widget and cleans up resources
59
+ */
60
+ destroy(): void;
61
+ }
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@wewear/virtual-try-on",
3
+ "version": "1.0.0",
4
+ "description": "Virtual Try-On widget for e-commerce integration",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.esm.js",
8
+ "types": "dist/index.d.ts",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "rollup -c",
14
+ "dev": "rollup -c -w",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "keywords": [
18
+ "virtual-try-on",
19
+ "e-commerce",
20
+ "widget",
21
+ "wewear"
22
+ ],
23
+ "author": "WeWear",
24
+ "license": "MIT",
25
+ "devDependencies": {
26
+ "@rollup/plugin-node-resolve": "^15.2.3",
27
+ "@rollup/plugin-typescript": "^11.1.5",
28
+ "rollup": "^4.6.1",
29
+ "typescript": "^5.3.2"
30
+ },
31
+ "peerDependencies": {},
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/wewearita/virtual-try-on-widget.git",
35
+ "directory": "packages/wewear-virtual-try-on"
36
+ }
37
+ }