@primestyleai/tryon 3.1.1 → 3.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.
Files changed (2) hide show
  1. package/dist/react/index.js +94 -70
  2. package/package.json +1 -1
@@ -446,9 +446,16 @@ function PrimeStyleTryonInner({
446
446
  if (formRef.current.fitPreference) m.fitPreference = formRef.current.fitPreference;
447
447
  payload.measurements = m;
448
448
  } else {
449
+ const qHeight = heightUnit === "ft" ? ftInToCm(parseFloat(formRef.current.heightFeet || "0"), parseFloat(formRef.current.heightInches || "0")) : parseFloat(formRef.current.height || "0");
450
+ const qWeight = weightUnit === "lbs" ? lbsToKg(parseFloat(formRef.current.weight || "0")) : parseFloat(formRef.current.weight || "0");
451
+ if (!qHeight || qHeight < 100 || !qWeight || qWeight < 30) {
452
+ console.warn("[PrimeStyle] Skipping sizing — invalid height/weight:", { qHeight, qWeight });
453
+ setSizingLoading(false);
454
+ return;
455
+ }
449
456
  payload.quickEstimate = {
450
- heightCm: heightUnit === "ft" ? ftInToCm(parseFloat(formRef.current.heightFeet || "0"), parseFloat(formRef.current.heightInches || "0")) : parseFloat(formRef.current.height || "0"),
451
- weightKg: weightUnit === "lbs" ? lbsToKg(parseFloat(formRef.current.weight || "0")) : parseFloat(formRef.current.weight || "0"),
457
+ heightCm: qHeight,
458
+ weightKg: qWeight,
452
459
  gender: formRef.current.gender || "male"
453
460
  };
454
461
  }
@@ -744,75 +751,71 @@ function PrimeStyleTryonInner({
744
751
  ] });
745
752
  }
746
753
  function UploadView() {
747
- return /* @__PURE__ */ jsxs(Fragment, { children: [
748
- profiles.length > 0 && /* @__PURE__ */ jsx("div", { className: "ps-tryon-profile-bar", children: /* @__PURE__ */ jsxs("select", { className: "ps-tryon-profile-select", value: activeProfileId || "", onChange: (e) => {
749
- if (e.target.value) applyProfile(e.target.value);
750
- }, children: [
751
- /* @__PURE__ */ jsx("option", { value: "", children: "Auto-fill from saved profile..." }),
752
- profiles.map((p) => /* @__PURE__ */ jsxs("option", { value: p.id, children: [
753
- p.name,
754
- " (",
755
- p.gender === "female" ? "Women's" : "Men's",
756
- ")"
757
- ] }, p.id))
758
- ] }) }),
759
- selectedFile && previewUrl ? /* @__PURE__ */ jsxs(Fragment, { children: [
760
- /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-preview", cn.preview), children: [
761
- /* @__PURE__ */ jsx("img", { src: previewUrl, alt: "Your photo", className: cn.previewImage }),
762
- /* @__PURE__ */ jsx("button", { onClick: handleRemovePreview, className: cx("ps-tryon-preview-remove", cn.removeButton), children: "×" })
763
- ] }),
764
- /* @__PURE__ */ jsxs("button", { onClick: () => setView("sizing-choice"), className: cx("ps-tryon-submit", cn.submitButton), children: [
765
- "Continue to Sizing ",
766
- /* @__PURE__ */ jsx(ArrowRightIcon, {})
767
- ] })
768
- ] }) : /* @__PURE__ */ jsxs(
769
- "div",
770
- {
771
- className: cx(`ps-tryon-upload${dragOver ? " ps-tryon-drag-over" : ""}`, cn.uploadZone),
772
- onClick: () => fileInputRef.current?.click(),
773
- onDragOver: (e) => {
774
- e.preventDefault();
775
- setDragOver(true);
776
- },
777
- onDragLeave: () => setDragOver(false),
778
- onDrop: (e) => {
779
- e.preventDefault();
780
- setDragOver(false);
781
- const f = e.dataTransfer?.files?.[0];
782
- if (f) handleFileSelect(f);
783
- },
784
- children: [
785
- /* @__PURE__ */ jsx(
786
- "input",
787
- {
788
- ref: fileInputRef,
789
- type: "file",
790
- accept: "image/jpeg,image/png,image/webp",
791
- style: { display: "none" },
792
- onChange: (e) => {
793
- const f = e.target.files?.[0];
794
- if (f) handleFileSelect(f);
795
- }
754
+ return /* @__PURE__ */ jsx(Fragment, { children: selectedFile && previewUrl ? /* @__PURE__ */ jsxs(Fragment, { children: [
755
+ /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-preview", cn.preview), children: [
756
+ /* @__PURE__ */ jsx("img", { src: previewUrl, alt: "Your photo", className: cn.previewImage }),
757
+ /* @__PURE__ */ jsx("button", { onClick: handleRemovePreview, className: cx("ps-tryon-preview-remove", cn.removeButton), children: "×" })
758
+ ] }),
759
+ /* @__PURE__ */ jsxs("button", { onClick: () => setView("sizing-choice"), className: cx("ps-tryon-submit", cn.submitButton), children: [
760
+ "Continue to Sizing ",
761
+ /* @__PURE__ */ jsx(ArrowRightIcon, {})
762
+ ] })
763
+ ] }) : /* @__PURE__ */ jsxs(
764
+ "div",
765
+ {
766
+ className: cx(`ps-tryon-upload${dragOver ? " ps-tryon-drag-over" : ""}`, cn.uploadZone),
767
+ onClick: () => fileInputRef.current?.click(),
768
+ onDragOver: (e) => {
769
+ e.preventDefault();
770
+ setDragOver(true);
771
+ },
772
+ onDragLeave: () => setDragOver(false),
773
+ onDrop: (e) => {
774
+ e.preventDefault();
775
+ setDragOver(false);
776
+ const f = e.dataTransfer?.files?.[0];
777
+ if (f) handleFileSelect(f);
778
+ },
779
+ children: [
780
+ /* @__PURE__ */ jsx(
781
+ "input",
782
+ {
783
+ ref: fileInputRef,
784
+ type: "file",
785
+ accept: "image/jpeg,image/png,image/webp",
786
+ style: { display: "none" },
787
+ onChange: (e) => {
788
+ const f = e.target.files?.[0];
789
+ if (f) handleFileSelect(f);
796
790
  }
797
- ),
798
- /* @__PURE__ */ jsx(UploadIcon, {}),
799
- /* @__PURE__ */ jsx("p", { className: cx("ps-tryon-upload-text", cn.uploadText), children: "Drop or upload your full body photo!" }),
800
- /* @__PURE__ */ jsx("p", { className: cx("ps-tryon-upload-hint", cn.uploadHint), children: "JPEG, PNG or WebP (max 10MB)" })
801
- ]
802
- }
803
- )
804
- ] });
791
+ }
792
+ ),
793
+ /* @__PURE__ */ jsx(UploadIcon, {}),
794
+ /* @__PURE__ */ jsx("p", { className: cx("ps-tryon-upload-text", cn.uploadText), children: "Drop or upload your full body photo!" }),
795
+ /* @__PURE__ */ jsx("p", { className: cx("ps-tryon-upload-hint", cn.uploadHint), children: "JPEG, PNG or WebP (max 10MB)" })
796
+ ]
797
+ }
798
+ ) });
805
799
  }
806
800
  function SizingChoiceView() {
807
801
  const sgAvailable = sizeGuide?.found === true;
808
- const sgDisabled = !sizeGuideFetching && !sgAvailable;
809
- const disabledClass = sgDisabled ? " ps-tryon-choice-disabled" : sizeGuideFetching ? " ps-tryon-choice-loading" : "";
802
+ const sgChecked = !sizeGuideFetching && sizeGuide !== null;
803
+ if (sizeGuideFetching) {
804
+ return /* @__PURE__ */ jsx("div", { className: "ps-tryon-sizing-choice", children: /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sg-checking", children: [
805
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sg-checking-spinner" }),
806
+ /* @__PURE__ */ jsx("h3", { className: "ps-tryon-section-title", children: "Checking size guide..." }),
807
+ /* @__PURE__ */ jsx("p", { className: "ps-tryon-sg-checking-sub", children: "Looking for size chart data for this product" })
808
+ ] }) });
809
+ }
810
810
  return /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sizing-choice", children: [
811
811
  /* @__PURE__ */ jsx("h3", { className: "ps-tryon-section-title", children: "How would you like to find your size?" }),
812
- sgDisabled && /* @__PURE__ */ jsx("div", { className: "ps-tryon-sg-notice", children: "Size guide is not available for this product" }),
813
- sizeGuideFetching && /* @__PURE__ */ jsx("div", { className: "ps-tryon-sg-notice ps-tryon-sg-loading", children: "Checking size guide availability..." }),
812
+ sgChecked && !sgAvailable && /* @__PURE__ */ jsx("div", { className: "ps-tryon-sg-notice", children: "Size guide is not available for this product — sizing will use standard measurements" }),
813
+ sgChecked && sgAvailable && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sg-notice ps-tryon-sg-found", children: [
814
+ /* @__PURE__ */ jsx(CheckIcon, { size: 14 }),
815
+ " Size guide found for this product"
816
+ ] }),
814
817
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-choice-cards", children: [
815
- /* @__PURE__ */ jsxs("button", { className: `ps-tryon-choice-card${disabledClass}`, disabled: sgDisabled || sizeGuideFetching, onClick: () => {
818
+ /* @__PURE__ */ jsxs("button", { className: "ps-tryon-choice-card", onClick: () => {
816
819
  setSizingMethod("exact");
817
820
  setView("sizing-form");
818
821
  }, children: [
@@ -823,7 +826,7 @@ function PrimeStyleTryonInner({
823
826
  ] }),
824
827
  /* @__PURE__ */ jsx("span", { className: "ps-tryon-choice-badge", children: "Best accuracy" })
825
828
  ] }),
826
- /* @__PURE__ */ jsxs("button", { className: `ps-tryon-choice-card${disabledClass}`, disabled: sgDisabled || sizeGuideFetching, onClick: () => {
829
+ /* @__PURE__ */ jsxs("button", { className: "ps-tryon-choice-card", onClick: () => {
827
830
  setSizingMethod("quick");
828
831
  setView("sizing-form");
829
832
  }, children: [
@@ -850,6 +853,17 @@ function PrimeStyleTryonInner({
850
853
  const isFemale = formGender === "female";
851
854
  const isCm = sizingUnit === "cm";
852
855
  return /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sizing-form", children: [
856
+ profiles.length > 0 && /* @__PURE__ */ jsx("div", { className: "ps-tryon-profile-bar", children: /* @__PURE__ */ jsxs("select", { className: "ps-tryon-profile-select", value: activeProfileId || "", onChange: (e) => {
857
+ if (e.target.value) applyProfile(e.target.value);
858
+ }, children: [
859
+ /* @__PURE__ */ jsx("option", { value: "", children: "Auto-fill from saved profile..." }),
860
+ profiles.map((p) => /* @__PURE__ */ jsxs("option", { value: p.id, children: [
861
+ p.name,
862
+ " (",
863
+ p.gender === "female" ? "Women's" : "Men's",
864
+ ")"
865
+ ] }, p.id))
866
+ ] }) }),
853
867
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-input-row", children: [
854
868
  /* @__PURE__ */ jsx("label", { children: "I'm shopping for" }),
855
869
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-unit-toggle", children: [
@@ -1328,15 +1342,25 @@ const STYLES = `
1328
1342
  padding: 3px 10px; border-radius: 20px; flex-shrink: 0;
1329
1343
  background: rgba(187,148,92,0.12); color: #bb945c; font-size: 10px; font-weight: 600;
1330
1344
  }
1331
- .ps-tryon-choice-disabled { opacity: 0.4; cursor: not-allowed !important; pointer-events: none; }
1332
- .ps-tryon-choice-disabled:hover { border-color: #333; transform: none; box-shadow: none; }
1333
- .ps-tryon-choice-disabled::before { display: none; }
1334
- .ps-tryon-choice-loading { opacity: 0.5; cursor: wait !important; pointer-events: none; }
1335
1345
  .ps-tryon-sg-notice {
1336
1346
  font-size: 12px; color: #999; text-align: center; padding: 10px 14px;
1337
1347
  margin-bottom: 12px; border: 1px solid #333; border-radius: 10px; background: #1a1b1a;
1338
1348
  }
1339
- .ps-tryon-sg-loading { border-style: dashed; }
1349
+ .ps-tryon-sg-found {
1350
+ color: #4ade80; border-color: rgba(74,222,128,0.2); background: rgba(74,222,128,0.05);
1351
+ display: flex; align-items: center; justify-content: center; gap: 6px;
1352
+ }
1353
+ .ps-tryon-sg-found svg { stroke: #4ade80; }
1354
+ .ps-tryon-sg-checking {
1355
+ display: flex; flex-direction: column; align-items: center; padding: 40px 20px; text-align: center;
1356
+ }
1357
+ .ps-tryon-sg-checking-spinner {
1358
+ width: 40px; height: 40px; border: 3px solid #333;
1359
+ border-top-color: #bb945c; border-radius: 50%;
1360
+ animation: ps-spin 0.8s linear infinite; margin-bottom: 20px;
1361
+ }
1362
+ .ps-tryon-sg-checking .ps-tryon-section-title { margin-bottom: 6px; }
1363
+ .ps-tryon-sg-checking-sub { font-size: 13px; color: #999; margin: 0; }
1340
1364
 
1341
1365
  /* Sizing form */
1342
1366
  .ps-tryon-sizing-form { display: flex; flex-direction: column; gap: 12px; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primestyleai/tryon",
3
- "version": "3.1.1",
3
+ "version": "3.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",