@primestyleai/tryon 1.1.0 → 1.2.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 CHANGED
@@ -87,8 +87,9 @@ That's it. No API key prop needed — the component reads it from your environme
87
87
  | `buttonText` | `string` | `"Virtual Try-On"` | Text on the trigger button |
88
88
  | `apiUrl` | `string` | `NEXT_PUBLIC_PRIMESTYLE_API_URL` or production | API endpoint override |
89
89
  | `showPoweredBy` | `boolean` | `true` | Show "Powered by PrimeStyle AI" in modal |
90
- | `buttonStyles` | `ButtonStyles` | `{}` | Customize button appearance |
91
- | `modalStyles` | `ModalStyles` | `{}` | Customize modal appearance |
90
+ | `buttonStyles` | `ButtonStyles` | `{}` | Customize button via style props |
91
+ | `modalStyles` | `ModalStyles` | `{}` | Customize modal via style props |
92
+ | `classNames` | `PrimeStyleClassNames` | `{}` | Override element classes (Tailwind, CSS) |
92
93
  | `className` | `string` | — | Additional CSS class on wrapper |
93
94
  | `style` | `CSSProperties` | — | Inline styles on wrapper |
94
95
  | `onOpen` | `() => void` | — | Modal opened |
@@ -186,6 +187,104 @@ That's it. No API key prop needed — the component reads it from your environme
186
187
  | `loaderColor` | Loading spinner color |
187
188
  | `resultBorderRadius` | Result image corner rounding |
188
189
 
190
+ ### Tailwind CSS / Custom Classes
191
+
192
+ Use the `classNames` prop to style any element with Tailwind utilities or your own CSS classes:
193
+
194
+ ```jsx
195
+ <PrimeStyleTryon
196
+ productImage={product.image}
197
+ classNames={{
198
+ button: "bg-black text-white rounded-full px-8 py-4 hover:bg-gray-800",
199
+ modal: "bg-white rounded-2xl shadow-2xl",
200
+ header: "bg-gray-50 border-b border-gray-200",
201
+ title: "text-gray-900 text-lg",
202
+ closeButton: "text-gray-400 hover:text-gray-600",
203
+ body: "p-6",
204
+ uploadZone: "border-2 border-dashed border-gray-300 rounded-xl p-10 hover:border-blue-400",
205
+ uploadText: "text-gray-700",
206
+ submitButton: "bg-blue-600 text-white rounded-lg hover:bg-blue-700",
207
+ downloadButton: "bg-green-600 text-white rounded-lg",
208
+ retryButton: "bg-gray-100 text-gray-700 border border-gray-300",
209
+ }}
210
+ />
211
+ ```
212
+
213
+ **All classNames keys:**
214
+
215
+ | Key | Element |
216
+ |-----|---------|
217
+ | `root` | Root wrapper `<div>` |
218
+ | `button` | Trigger button |
219
+ | `overlay` | Modal backdrop overlay |
220
+ | `modal` | Modal container |
221
+ | `header` | Modal header bar |
222
+ | `title` | Modal title text |
223
+ | `closeButton` | Close (X) button |
224
+ | `body` | Modal body area |
225
+ | `uploadZone` | Upload drop zone |
226
+ | `uploadText` | "Drop your photo..." text |
227
+ | `uploadHint` | File type hint text |
228
+ | `preview` | Preview image container |
229
+ | `previewImage` | Preview `<img>` element |
230
+ | `removeButton` | Remove preview button |
231
+ | `submitButton` | "Try It On" / "Try Again" button |
232
+ | `spinner` | Loading spinner |
233
+ | `processingText` | "Generating..." text |
234
+ | `processingSubText` | "This usually takes..." text |
235
+ | `result` | Result container |
236
+ | `resultImage` | Result `<img>` element |
237
+ | `resultActions` | Download/retry button row |
238
+ | `downloadButton` | Download button |
239
+ | `retryButton` | "Try Another" button |
240
+ | `error` | Error container |
241
+ | `errorText` | Error message text |
242
+ | `poweredBy` | Footer text |
243
+
244
+ ### Normal CSS
245
+
246
+ All elements use `ps-tryon-*` class names that you can target directly in your CSS:
247
+
248
+ ```css
249
+ /* Override the trigger button */
250
+ .ps-tryon-btn {
251
+ background: #000;
252
+ color: #fff;
253
+ border-radius: 50px;
254
+ padding: 16px 32px;
255
+ }
256
+
257
+ /* Override the modal */
258
+ .ps-tryon-modal {
259
+ background: #fff;
260
+ color: #111;
261
+ border-radius: 16px;
262
+ }
263
+
264
+ /* Override the submit button */
265
+ .ps-tryon-submit {
266
+ background: #2563eb;
267
+ color: #fff;
268
+ }
269
+ ```
270
+
271
+ ### Combining Approaches
272
+
273
+ You can mix all three styling methods — they layer on top of each other:
274
+
275
+ ```jsx
276
+ <PrimeStyleTryon
277
+ productImage={product.image}
278
+ // 1. Style props (CSS variables)
279
+ buttonStyles={{ width: '100%' }}
280
+ // 2. Tailwind classes
281
+ classNames={{ button: "rounded-full font-bold" }}
282
+ // 3. Normal CSS targets .ps-tryon-btn automatically
283
+ />
284
+ ```
285
+
286
+ Priority: Tailwind/classNames classes > CSS variables (buttonStyles/modalStyles) > default styles.
287
+
189
288
  ---
190
289
 
191
290
  ## Callbacks
@@ -1,5 +1,5 @@
1
1
  import { type CSSProperties } from "react";
2
- import type { ButtonStyles, ModalStyles } from "../types";
2
+ import type { ButtonStyles, ModalStyles, PrimeStyleClassNames } from "../types";
3
3
  export interface PrimeStyleTryonProps {
4
4
  /** Product image URL to try on */
5
5
  productImage: string;
@@ -9,10 +9,16 @@ export interface PrimeStyleTryonProps {
9
9
  apiUrl?: string;
10
10
  /** Show "Powered by PrimeStyle" in modal footer (defaults to true) */
11
11
  showPoweredBy?: boolean;
12
- /** Button appearance customization */
12
+ /** Button appearance customization via CSS variables */
13
13
  buttonStyles?: ButtonStyles;
14
- /** Modal appearance customization */
14
+ /** Modal appearance customization via CSS variables */
15
15
  modalStyles?: ModalStyles;
16
+ /**
17
+ * Override any element's className with Tailwind classes or custom CSS classes.
18
+ * These are appended to the default `ps-tryon-*` classes, so you can either
19
+ * add onto the defaults or fully replace them with your own styles.
20
+ */
21
+ classNames?: PrimeStyleClassNames;
16
22
  /** Additional className on the root wrapper */
17
23
  className?: string;
18
24
  /** Additional inline styles on the root wrapper */
@@ -30,4 +36,4 @@ export interface PrimeStyleTryonProps {
30
36
  code?: string;
31
37
  }) => void;
32
38
  }
33
- export declare function PrimeStyleTryon({ productImage, buttonText, apiUrl, showPoweredBy, buttonStyles: btnS, modalStyles: mdlS, className, style, onOpen, onClose, onUpload, onProcessing, onComplete, onError, }: PrimeStyleTryonProps): import("react/jsx-runtime").JSX.Element;
39
+ export declare function PrimeStyleTryon({ productImage, buttonText, apiUrl, showPoweredBy, buttonStyles: btnS, modalStyles: mdlS, classNames: cn, className, style, onOpen, onClose, onUpload, onProcessing, onComplete, onError, }: PrimeStyleTryonProps): import("react/jsx-runtime").JSX.Element;
@@ -2,6 +2,9 @@
2
2
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
3
3
  import { useState, useRef, useEffect, useCallback } from "react";
4
4
  import { A as ApiClient, S as SseClient, i as isValidImageFile, c as compressImage, P as PrimeStyleError } from "../image-utils-usff6Qu8.js";
5
+ function cx(base, override) {
6
+ return override ? `${base} ${override}` : base;
7
+ }
5
8
  function CameraIcon({ size = 18 }) {
6
9
  return /* @__PURE__ */ jsxs(
7
10
  "svg",
@@ -100,6 +103,7 @@ function PrimeStyleTryon({
100
103
  showPoweredBy = true,
101
104
  buttonStyles: btnS = {},
102
105
  modalStyles: mdlS = {},
106
+ classNames: cn = {},
103
107
  className,
104
108
  style,
105
109
  onOpen,
@@ -322,108 +326,207 @@ function PrimeStyleTryon({
322
326
  const cssVars = Object.fromEntries(
323
327
  Object.entries(rootVars).filter(([, v]) => v !== void 0)
324
328
  );
325
- return /* @__PURE__ */ jsxs("div", { className, style: { ...cssVars, ...style, display: "inline-block" }, children: [
326
- /* @__PURE__ */ jsxs("button", { onClick: handleOpen, className: "ps-tryon-btn", children: [
327
- /* @__PURE__ */ jsx(CameraIcon, { size: parseInt(btnS.iconSize || "18") }),
328
- /* @__PURE__ */ jsx("span", { children: buttonText })
329
- ] }),
330
- view !== "idle" && /* @__PURE__ */ jsx(
331
- "div",
332
- {
333
- className: "ps-tryon-overlay",
334
- onClick: (e) => {
335
- if (e.target === e.currentTarget) handleClose();
336
- },
337
- children: /* @__PURE__ */ jsxs("div", { className: "ps-tryon-modal", onClick: (e) => e.stopPropagation(), children: [
338
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-header", children: [
339
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-title", children: "Virtual Try-On" }),
340
- /* @__PURE__ */ jsx("button", { onClick: handleClose, className: "ps-tryon-close", children: /* @__PURE__ */ jsx(XIcon, {}) })
341
- ] }),
342
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-body", children: [
343
- view === "upload" && /* @__PURE__ */ jsx(Fragment, { children: selectedFile && previewUrl ? /* @__PURE__ */ jsxs(Fragment, { children: [
344
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-preview", children: [
345
- /* @__PURE__ */ jsx("img", { src: previewUrl, alt: "Your photo" }),
346
- /* @__PURE__ */ jsx(
347
- "button",
348
- {
349
- onClick: handleRemovePreview,
350
- className: "ps-tryon-preview-remove",
351
- children: "×"
352
- }
353
- )
354
- ] }),
355
- /* @__PURE__ */ jsx("button", { onClick: handleSubmit, className: "ps-tryon-submit", children: "Try It On" })
356
- ] }) : /* @__PURE__ */ jsxs(
329
+ return /* @__PURE__ */ jsxs(
330
+ "div",
331
+ {
332
+ className: cx("ps-tryon-root", cn.root || className),
333
+ style: { ...cssVars, ...style },
334
+ "data-ps-tryon": true,
335
+ children: [
336
+ /* @__PURE__ */ jsxs("button", { onClick: handleOpen, className: cx("ps-tryon-btn", cn.button), children: [
337
+ /* @__PURE__ */ jsx(CameraIcon, { size: parseInt(btnS.iconSize || "18") }),
338
+ /* @__PURE__ */ jsx("span", { children: buttonText })
339
+ ] }),
340
+ view !== "idle" && /* @__PURE__ */ jsx(
341
+ "div",
342
+ {
343
+ className: cx("ps-tryon-overlay", cn.overlay),
344
+ onClick: (e) => {
345
+ if (e.target === e.currentTarget) handleClose();
346
+ },
347
+ children: /* @__PURE__ */ jsxs(
357
348
  "div",
358
349
  {
359
- className: `ps-tryon-upload ${dragOver ? "ps-tryon-drag-over" : ""}`,
360
- onClick: () => fileInputRef.current?.click(),
361
- onDragOver: (e) => {
362
- e.preventDefault();
363
- setDragOver(true);
364
- },
365
- onDragLeave: () => setDragOver(false),
366
- onDrop: (e) => {
367
- e.preventDefault();
368
- setDragOver(false);
369
- const file = e.dataTransfer?.files?.[0];
370
- if (file) handleFileSelect(file);
371
- },
350
+ className: cx("ps-tryon-modal", cn.modal),
351
+ onClick: (e) => e.stopPropagation(),
372
352
  children: [
373
- /* @__PURE__ */ jsx(
374
- "input",
375
- {
376
- ref: fileInputRef,
377
- type: "file",
378
- accept: "image/jpeg,image/png,image/webp",
379
- style: { display: "none" },
380
- onChange: (e) => {
381
- const file = e.target.files?.[0];
382
- if (file) handleFileSelect(file);
353
+ /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-header", cn.header), children: [
354
+ /* @__PURE__ */ jsx("span", { className: cx("ps-tryon-title", cn.title), children: "Virtual Try-On" }),
355
+ /* @__PURE__ */ jsx(
356
+ "button",
357
+ {
358
+ onClick: handleClose,
359
+ className: cx("ps-tryon-close", cn.closeButton),
360
+ children: /* @__PURE__ */ jsx(XIcon, {})
383
361
  }
384
- }
385
- ),
386
- /* @__PURE__ */ jsx(UploadIcon, {}),
387
- /* @__PURE__ */ jsx("p", { className: "ps-tryon-upload-text", children: "Drop your photo here or click to upload" }),
388
- /* @__PURE__ */ jsx("p", { className: "ps-tryon-upload-hint", children: "JPEG, PNG or WebP (max 10MB)" })
362
+ )
363
+ ] }),
364
+ /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-body", cn.body), children: [
365
+ view === "upload" && /* @__PURE__ */ jsx(Fragment, { children: selectedFile && previewUrl ? /* @__PURE__ */ jsxs(Fragment, { children: [
366
+ /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-preview", cn.preview), children: [
367
+ /* @__PURE__ */ jsx(
368
+ "img",
369
+ {
370
+ src: previewUrl,
371
+ alt: "Your photo",
372
+ className: cn.previewImage
373
+ }
374
+ ),
375
+ /* @__PURE__ */ jsx(
376
+ "button",
377
+ {
378
+ onClick: handleRemovePreview,
379
+ className: cx(
380
+ "ps-tryon-preview-remove",
381
+ cn.removeButton
382
+ ),
383
+ children: "×"
384
+ }
385
+ )
386
+ ] }),
387
+ /* @__PURE__ */ jsx(
388
+ "button",
389
+ {
390
+ onClick: handleSubmit,
391
+ className: cx("ps-tryon-submit", cn.submitButton),
392
+ children: "Try It On"
393
+ }
394
+ )
395
+ ] }) : /* @__PURE__ */ jsxs(
396
+ "div",
397
+ {
398
+ className: cx(
399
+ `ps-tryon-upload${dragOver ? " ps-tryon-drag-over" : ""}`,
400
+ cn.uploadZone
401
+ ),
402
+ onClick: () => fileInputRef.current?.click(),
403
+ onDragOver: (e) => {
404
+ e.preventDefault();
405
+ setDragOver(true);
406
+ },
407
+ onDragLeave: () => setDragOver(false),
408
+ onDrop: (e) => {
409
+ e.preventDefault();
410
+ setDragOver(false);
411
+ const file = e.dataTransfer?.files?.[0];
412
+ if (file) handleFileSelect(file);
413
+ },
414
+ children: [
415
+ /* @__PURE__ */ jsx(
416
+ "input",
417
+ {
418
+ ref: fileInputRef,
419
+ type: "file",
420
+ accept: "image/jpeg,image/png,image/webp",
421
+ style: { display: "none" },
422
+ onChange: (e) => {
423
+ const file = e.target.files?.[0];
424
+ if (file) handleFileSelect(file);
425
+ }
426
+ }
427
+ ),
428
+ /* @__PURE__ */ jsx(UploadIcon, {}),
429
+ /* @__PURE__ */ jsx("p", { className: cx("ps-tryon-upload-text", cn.uploadText), children: "Drop your photo here or click to upload" }),
430
+ /* @__PURE__ */ jsx("p", { className: cx("ps-tryon-upload-hint", cn.uploadHint), children: "JPEG, PNG or WebP (max 10MB)" })
431
+ ]
432
+ }
433
+ ) }),
434
+ view === "processing" && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-processing", children: [
435
+ /* @__PURE__ */ jsx("div", { className: cx("ps-tryon-spinner", cn.spinner) }),
436
+ /* @__PURE__ */ jsx(
437
+ "p",
438
+ {
439
+ className: cx(
440
+ "ps-tryon-processing-text",
441
+ cn.processingText
442
+ ),
443
+ children: "Generating your try-on..."
444
+ }
445
+ ),
446
+ /* @__PURE__ */ jsx(
447
+ "p",
448
+ {
449
+ className: cx(
450
+ "ps-tryon-processing-sub",
451
+ cn.processingSubText
452
+ ),
453
+ children: "This usually takes 15-20 seconds"
454
+ }
455
+ )
456
+ ] }),
457
+ view === "result" && resultImageUrl && /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-result", cn.result), children: [
458
+ /* @__PURE__ */ jsx(
459
+ "img",
460
+ {
461
+ src: resultImageUrl,
462
+ alt: "Try-on result",
463
+ className: cn.resultImage
464
+ }
465
+ ),
466
+ /* @__PURE__ */ jsxs(
467
+ "div",
468
+ {
469
+ className: cx(
470
+ "ps-tryon-result-actions",
471
+ cn.resultActions
472
+ ),
473
+ children: [
474
+ /* @__PURE__ */ jsx(
475
+ "button",
476
+ {
477
+ onClick: handleDownload,
478
+ className: cx("ps-tryon-btn-download", cn.downloadButton),
479
+ children: "Download"
480
+ }
481
+ ),
482
+ /* @__PURE__ */ jsx(
483
+ "button",
484
+ {
485
+ onClick: handleRetry,
486
+ className: cx("ps-tryon-btn-retry", cn.retryButton),
487
+ children: "Try Another"
488
+ }
489
+ )
490
+ ]
491
+ }
492
+ )
493
+ ] }),
494
+ view === "error" && /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-error", cn.error), children: [
495
+ /* @__PURE__ */ jsx(AlertIcon, {}),
496
+ /* @__PURE__ */ jsx("p", { className: cx("ps-tryon-error-text", cn.errorText), children: errorMessage || "Something went wrong" }),
497
+ /* @__PURE__ */ jsx(
498
+ "button",
499
+ {
500
+ onClick: handleRetry,
501
+ className: cx("ps-tryon-submit", cn.submitButton),
502
+ children: "Try Again"
503
+ }
504
+ )
505
+ ] })
506
+ ] }),
507
+ showPoweredBy && /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-powered", cn.poweredBy), children: [
508
+ "Powered by",
509
+ " ",
510
+ /* @__PURE__ */ jsx(
511
+ "a",
512
+ {
513
+ href: "https://primestyleai.com",
514
+ target: "_blank",
515
+ rel: "noopener noreferrer",
516
+ children: "PrimeStyle AI"
517
+ }
518
+ )
519
+ ] })
389
520
  ]
390
521
  }
391
- ) }),
392
- view === "processing" && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-processing", children: [
393
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-spinner" }),
394
- /* @__PURE__ */ jsx("p", { className: "ps-tryon-processing-text", children: "Generating your try-on..." }),
395
- /* @__PURE__ */ jsx("p", { className: "ps-tryon-processing-sub", children: "This usually takes 15-20 seconds" })
396
- ] }),
397
- view === "result" && resultImageUrl && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-result", children: [
398
- /* @__PURE__ */ jsx("img", { src: resultImageUrl, alt: "Try-on result" }),
399
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-result-actions", children: [
400
- /* @__PURE__ */ jsx("button", { onClick: handleDownload, className: "ps-tryon-btn-download", children: "Download" }),
401
- /* @__PURE__ */ jsx("button", { onClick: handleRetry, className: "ps-tryon-btn-retry", children: "Try Another" })
402
- ] })
403
- ] }),
404
- view === "error" && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-error", children: [
405
- /* @__PURE__ */ jsx(AlertIcon, {}),
406
- /* @__PURE__ */ jsx("p", { className: "ps-tryon-error-text", children: errorMessage || "Something went wrong" }),
407
- /* @__PURE__ */ jsx("button", { onClick: handleRetry, className: "ps-tryon-submit", children: "Try Again" })
408
- ] })
409
- ] }),
410
- showPoweredBy && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-powered", children: [
411
- "Powered by",
412
- " ",
413
- /* @__PURE__ */ jsx(
414
- "a",
415
- {
416
- href: "https://primestyleai.com",
417
- target: "_blank",
418
- rel: "noopener noreferrer",
419
- children: "PrimeStyle AI"
420
- }
421
522
  )
422
- ] })
423
- ] })
424
- }
425
- ),
426
- /* @__PURE__ */ jsx("style", { children: `
523
+ }
524
+ ),
525
+ /* @__PURE__ */ jsx("style", { children: `
526
+ .ps-tryon-root {
527
+ display: inline-block;
528
+ }
529
+
427
530
  .ps-tryon-btn {
428
531
  display: inline-flex;
429
532
  align-items: center;
@@ -659,7 +762,9 @@ function PrimeStyleTryon({
659
762
  .ps-tryon-powered a { color: #bb945c; text-decoration: none; }
660
763
  .ps-tryon-powered a:hover { text-decoration: underline; }
661
764
  ` })
662
- ] });
765
+ ]
766
+ }
767
+ );
663
768
  }
664
769
  export {
665
770
  PrimeStyleTryon
package/dist/types.d.ts CHANGED
@@ -75,6 +75,61 @@ export interface TryOnStatus {
75
75
  imageUrl: string | null;
76
76
  message: string;
77
77
  }
78
+ /** Class name overrides for styling with Tailwind or custom CSS */
79
+ export interface PrimeStyleClassNames {
80
+ /** Root wrapper element */
81
+ root?: string;
82
+ /** Trigger button */
83
+ button?: string;
84
+ /** Modal overlay backdrop */
85
+ overlay?: string;
86
+ /** Modal container */
87
+ modal?: string;
88
+ /** Modal header bar */
89
+ header?: string;
90
+ /** Modal title text */
91
+ title?: string;
92
+ /** Close (X) button */
93
+ closeButton?: string;
94
+ /** Modal body area */
95
+ body?: string;
96
+ /** Upload drop zone */
97
+ uploadZone?: string;
98
+ /** Upload primary text */
99
+ uploadText?: string;
100
+ /** Upload hint text (file types) */
101
+ uploadHint?: string;
102
+ /** Preview image container */
103
+ preview?: string;
104
+ /** Preview image element */
105
+ previewImage?: string;
106
+ /** Remove preview button */
107
+ removeButton?: string;
108
+ /** Submit / "Try It On" button */
109
+ submitButton?: string;
110
+ /** Processing spinner element */
111
+ spinner?: string;
112
+ /** Processing main text */
113
+ processingText?: string;
114
+ /** Processing sub text */
115
+ processingSubText?: string;
116
+ /** Result container */
117
+ result?: string;
118
+ /** Result image element */
119
+ resultImage?: string;
120
+ /** Result actions container */
121
+ resultActions?: string;
122
+ /** Download button */
123
+ downloadButton?: string;
124
+ /** Retry / "Try Another" button */
125
+ retryButton?: string;
126
+ /** Error container */
127
+ error?: string;
128
+ /** Error text */
129
+ errorText?: string;
130
+ /** Powered by footer */
131
+ poweredBy?: string;
132
+ }
78
133
  /** Custom events emitted by the component */
79
134
  export interface PrimeStyleEvents {
80
135
  "ps:open": CustomEvent<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primestyleai/tryon",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "PrimeStyle Virtual Try-On SDK — React component & Web Component",
5
5
  "type": "module",
6
6
  "main": "dist/primestyle-tryon.js",