@primestyleai/tryon 5.8.53 → 5.8.55

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.
@@ -67,7 +67,15 @@ export interface BodyLandmarks {
67
67
  y: number;
68
68
  };
69
69
  }
70
+ /** Pixel dimensions of the image the landmarks were detected on. Sent to
71
+ * the backend alongside the landmarks so it can convert normalized x/y
72
+ * into pixels — without this, horizontal and vertical distances on a
73
+ * non-square image are skewed by the aspect ratio. */
74
+ export interface BodyLandmarksWithDims extends BodyLandmarks {
75
+ imageWidth: number;
76
+ imageHeight: number;
77
+ }
70
78
  export declare function detectMeasurementLines(imageSrc: string): Promise<MeasurementLines | null>;
71
79
  /** Detect full body landmarks for per-field measurement guides.
72
80
  * Accepts a URL string OR an already-loaded HTMLImageElement to avoid CORS issues. */
73
- export declare function detectBodyLandmarks(imageSrc: string | HTMLImageElement): Promise<BodyLandmarks | null>;
81
+ export declare function detectBodyLandmarks(imageSrc: string | HTMLImageElement): Promise<BodyLandmarksWithDims | null>;
@@ -121,7 +121,9 @@ async function detectBodyLandmarks(imageSrc) {
121
121
  rightKnee: { x: lm[RIGHT_KNEE].x, y: lm[RIGHT_KNEE].y },
122
122
  leftAnkle: { x: lm[LEFT_ANKLE].x, y: lm[LEFT_ANKLE].y },
123
123
  rightAnkle: { x: lm[RIGHT_ANKLE].x, y: lm[RIGHT_ANKLE].y },
124
- nose: { x: lm[NOSE].x, y: lm[NOSE].y }
124
+ nose: { x: lm[NOSE].x, y: lm[NOSE].y },
125
+ imageWidth: img.naturalWidth || img.width,
126
+ imageHeight: img.naturalHeight || img.height
125
127
  };
126
128
  } catch (err) {
127
129
  console.error("[PS-SDK] Body landmark detection failed:", err);
@@ -7760,36 +7762,57 @@ function FaceOverlay({
7760
7762
  ] }, key))
7761
7763
  ] });
7762
7764
  }
7763
- function AccessoryStageCycler({
7765
+ function StageCycler({
7764
7766
  category,
7765
7767
  sizingDone,
7768
+ tryOnProcessing,
7769
+ tryOnDone,
7766
7770
  t
7767
7771
  }) {
7768
- const stages = category === "head" ? [
7772
+ const sizingStages = category === "head" ? [
7769
7773
  { title: t("DETECTING HEAD"), desc: t("Reading head landmarks from your photo.") },
7770
7774
  { title: t("MAPPING CIRCUMFERENCE"), desc: t("Estimating head width and depth.") },
7771
7775
  { title: t("MATCHING HAT SIZE"), desc: t("Comparing your circumference to the size chart.") },
7772
7776
  { title: t("FINALIZING RESULT"), desc: t("Almost done — preparing your recommendation.") }
7773
- ] : [
7777
+ ] : category === "face" ? [
7774
7778
  { title: t("DETECTING FACE"), desc: t("Identifying 478 face landmarks in your photo.") },
7775
7779
  { title: t("CALIBRATING SCALE"), desc: t("Using iris size as the pixel-to-mm anchor.") },
7776
7780
  { title: t("MEASURING FRAME"), desc: t("Mapping bridge, lens width and temple length.") },
7777
7781
  { title: t("MATCHING FRAME SIZE"), desc: t("Comparing your measurements to the size chart.") },
7778
7782
  { title: t("FINALIZING RESULT"), desc: t("Almost done — preparing your recommendation.") }
7783
+ ] : [
7784
+ // Body + foot fall through here — broadest set of stages so long
7785
+ // Gemini estimates still have fresh text to cycle through.
7786
+ { title: t("DETECTING POSE"), desc: t("Identifying body landmarks from your photo.") },
7787
+ { title: t("SCANNING FRAME"), desc: t("Our AI is mapping your proportions.") },
7788
+ { title: t("ANALYZING BODY"), desc: t("Measuring shoulders, chest, waist and hips.") },
7789
+ { title: t("MATCHING SIZE"), desc: t("Comparing your measurements to the size guide.") },
7790
+ { title: t("FINALIZING RESULT"), desc: t("Almost done — preparing your recommendation.") }
7791
+ ];
7792
+ const tryOnStages = [
7793
+ { title: t("GENERATING TRY-ON"), desc: t("Rendering the garment on your photo.") },
7794
+ { title: t("REFINING DETAILS"), desc: t("Fine-tuning fit, drape and shadows.") },
7795
+ { title: t("ALMOST THERE"), desc: t("Final compositing in progress.") },
7796
+ { title: t("FINISHING TOUCHES"), desc: t("Polishing the result.") }
7779
7797
  ];
7798
+ const active = tryOnProcessing ? tryOnStages : sizingStages;
7799
+ const isDone = tryOnProcessing ? !!tryOnDone : sizingDone;
7780
7800
  const [idx, setIdx] = useState(0);
7781
7801
  useEffect(() => {
7782
- if (sizingDone) return;
7802
+ setIdx(0);
7803
+ }, [tryOnProcessing]);
7804
+ useEffect(() => {
7805
+ if (isDone) return;
7783
7806
  const id = setInterval(() => {
7784
- setIdx((i) => Math.min(i + 1, stages.length - 1));
7807
+ setIdx((i) => Math.min(i + 1, active.length - 1));
7785
7808
  }, 900);
7786
7809
  return () => clearInterval(id);
7787
- }, [sizingDone, stages.length]);
7788
- const current = stages[idx] ?? stages[0];
7810
+ }, [isDone, active.length]);
7811
+ const current = active[idx] ?? active[0];
7789
7812
  return /* @__PURE__ */ jsx("div", { className: "ps-msc-stage", style: { alignSelf: "center", marginTop: "auto", marginBottom: "auto" }, children: /* @__PURE__ */ jsxs("div", { className: "ps-msc-stage-slot", children: [
7790
7813
  /* @__PURE__ */ jsx("div", { className: "ps-msc-stage-title", children: current.title }),
7791
7814
  /* @__PURE__ */ jsx("div", { className: "ps-msc-stage-desc", children: current.desc })
7792
- ] }, idx) });
7815
+ ] }, `${tryOnProcessing ? "t" : "s"}-${idx}`) });
7793
7816
  }
7794
7817
  function SkeletonOverlay({ landmarks, imgWidth, imgHeight }) {
7795
7818
  const W = imgWidth;
@@ -8025,7 +8048,8 @@ function SectionDetailView({
8025
8048
  tryOnProcessing,
8026
8049
  backLabel,
8027
8050
  internationalSizes,
8028
- continueLabel
8051
+ continueLabel,
8052
+ renderRaw = false
8029
8053
  }) {
8030
8054
  const recSize = sectionResult?.recommendedSize || "";
8031
8055
  const [selectedSize, setSelectedSize] = useState(null);
@@ -8143,6 +8167,18 @@ function SectionDetailView({
8143
8167
  return { range: val, ...parsed };
8144
8168
  }, [section, sizeColIdx, sizeHeader, unitLbl, columnUnits]);
8145
8169
  const fitRows = useMemo(() => {
8170
+ if (renderRaw) {
8171
+ const raw = sectionResult?.matchDetails || [];
8172
+ return raw.map((m) => ({
8173
+ area: m.measurement.replace(/\s*\(.*?\)\s*$/, "").trim() || m.measurement,
8174
+ rawUserValue: m.userValue,
8175
+ rawChartRange: m.chartRange,
8176
+ fit: m.fit,
8177
+ userNum: 0,
8178
+ chartLabel: "",
8179
+ isLength: false
8180
+ }));
8181
+ }
8146
8182
  const mainDetails = sectionResult?.matchDetails || [];
8147
8183
  const lengthDetails = lengthEntry?.secResult?.matchDetails || [];
8148
8184
  const details = [...mainDetails, ...lengthDetails];
@@ -8212,11 +8248,12 @@ function SectionDetailView({
8212
8248
  }
8213
8249
  return { area: m.measurement, userNum, chartLabel: cleanNumFn(chartLabel), fit, isLength: false };
8214
8250
  });
8215
- }, [sectionResult, lengthEntry, userMeasurements, displaySize, recSize, chartRangeFor, selectedLength, recLength]);
8251
+ }, [sectionResult, lengthEntry, userMeasurements, displaySize, recSize, chartRangeFor, selectedLength, recLength, renderRaw]);
8216
8252
  const goodCount = fitRows.filter(
8217
8253
  (r) => r.fit === "good" || r.fit === "a-bit-tight" || r.fit === "a-bit-loose"
8218
8254
  ).length;
8219
8255
  const matchPercent = fitRows.length > 0 ? Math.round(goodCount / fitRows.length * 100) : 0;
8256
+ const showMatchPercent = !renderRaw;
8220
8257
  const secAny = sectionResult;
8221
8258
  const backendSize = secAny?.size || recSize;
8222
8259
  const backendLength = secAny?.length || recLength;
@@ -8343,7 +8380,10 @@ function SectionDetailView({
8343
8380
  borderRadius: "8px",
8344
8381
  padding: "4px 12px"
8345
8382
  }, children: [
8346
- /* @__PURE__ */ jsx("span", { className: "ps-msd-card-size", children: displaySizeLabel }),
8383
+ /* @__PURE__ */ jsxs("span", { className: "ps-msd-card-size", children: [
8384
+ displaySizeLabel,
8385
+ !selectedCountry && finalDisplayLength ? ` / ${finalDisplayLength}` : ""
8386
+ ] }),
8347
8387
  finalDisplayLength && /* @__PURE__ */ jsx("span", { className: "ps-msd-card-size-meta", children: finalDisplayLength }),
8348
8388
  selectedCountry && isRecommended && /* @__PURE__ */ jsxs("span", { className: "ps-msd-card-size-meta", style: { fontSize: "11px", opacity: 0.7 }, children: [
8349
8389
  "(",
@@ -8380,7 +8420,7 @@ function SectionDetailView({
8380
8420
  /* @__PURE__ */ jsxs("div", { className: "ps-msd-row-cells", children: [
8381
8421
  /* @__PURE__ */ jsxs("div", { className: "ps-msd-row-cell", children: [
8382
8422
  /* @__PURE__ */ jsx("span", { className: "ps-msd-cell-label", children: t("USER") }),
8383
- /* @__PURE__ */ jsx("span", { className: "ps-msd-cell-value", children: isNaN(row.userNum) || row.userNum === 0 ? "—" : `${dNum(row.userNum)} ${unitLbl}` })
8423
+ /* @__PURE__ */ jsx("span", { className: "ps-msd-cell-value", children: renderRaw ? row.rawUserValue || "—" : isNaN(row.userNum) || row.userNum === 0 ? "—" : `${dNum(row.userNum)} ${unitLbl}` })
8384
8424
  ] }),
8385
8425
  /* @__PURE__ */ jsxs("div", { className: "ps-msd-row-cell ps-right", children: [
8386
8426
  /* @__PURE__ */ jsxs("span", { className: "ps-msd-cell-label", children: [
@@ -8388,7 +8428,7 @@ function SectionDetailView({
8388
8428
  " ",
8389
8429
  displaySize
8390
8430
  ] }),
8391
- /* @__PURE__ */ jsx("span", { className: "ps-msd-cell-value", children: dLabel(row.chartLabel) })
8431
+ /* @__PURE__ */ jsx("span", { className: "ps-msd-cell-value", children: renderRaw ? row.rawChartRange || "—" : dLabel(row.chartLabel) })
8392
8432
  ] })
8393
8433
  ] }),
8394
8434
  /* @__PURE__ */ jsxs("div", { className: `ps-msd-row-badge ${fitClass}`, children: [
@@ -8487,7 +8527,7 @@ function SectionDetailView({
8487
8527
  ] })
8488
8528
  ] })
8489
8529
  ] }),
8490
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.4vw", marginBottom: "1.2vw" }, children: [
8530
+ showMatchPercent && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.4vw", marginBottom: "1.2vw" }, children: [
8491
8531
  /* @__PURE__ */ jsxs("svg", { width: "1vw", height: "1vw", viewBox: "0 0 16 16", fill: "none", children: [
8492
8532
  /* @__PURE__ */ jsx("circle", { cx: "8", cy: "8", r: "8", fill: "var(--ps-accent)" }),
8493
8533
  /* @__PURE__ */ jsx("path", { d: "M4.5 8L7 10.5L11.5 5.5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
@@ -8510,8 +8550,8 @@ function SectionDetailView({
8510
8550
  const fitBg = row.fit === "good" ? "rgba(33,84,239,0.08)" : row.fit.includes("tight") ? "rgba(220,38,38,0.08)" : "rgba(217,119,6,0.08)";
8511
8551
  return /* @__PURE__ */ jsxs("tr", { style: { borderBottom: i < fitRows.length - 1 ? "1px solid rgba(0,0,0,0.04)" : "none" }, children: [
8512
8552
  /* @__PURE__ */ jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", fontWeight: 500, color: "var(--ps-text-primary)" }, children: row.area }),
8513
- /* @__PURE__ */ jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", color: "var(--ps-text-secondary)" }, children: isNaN(row.userNum) || row.userNum === 0 ? "—" : `${dNum(row.userNum)} ${unitLbl}` }),
8514
- /* @__PURE__ */ jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", color: "var(--ps-text-secondary)" }, children: dLabel(row.chartLabel) }),
8553
+ /* @__PURE__ */ jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", color: "var(--ps-text-secondary)" }, children: renderRaw ? row.rawUserValue || "—" : isNaN(row.userNum) || row.userNum === 0 ? "—" : `${dNum(row.userNum)} ${unitLbl}` }),
8554
+ /* @__PURE__ */ jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", color: "var(--ps-text-secondary)" }, children: renderRaw ? row.rawChartRange || "—" : dLabel(row.chartLabel) }),
8515
8555
  /* @__PURE__ */ jsx("td", { style: { padding: "0.55vw 0.6vw", textAlign: "right" }, children: /* @__PURE__ */ jsx("span", { style: { fontSize: "0.6vw", fontWeight: 600, color: fitColor, background: fitBg, borderRadius: "1vw", padding: "0.15vw 0.5vw", whiteSpace: "nowrap" }, children: row.isLength ? lengthFitLabelFn(row.fit, t) : fitLabelFn(row.fit, t) }) })
8516
8556
  ] }, i);
8517
8557
  }) })
@@ -8776,7 +8816,6 @@ function SizeResultView({
8776
8816
  const [poseLines, setPoseLines] = useState(null);
8777
8817
  const [poseReady, setPoseReady] = useState(false);
8778
8818
  const [imgDims, setImgDims] = useState({ w: 800, h: 1200 });
8779
- const analyzingDone = estimationDone;
8780
8819
  const handleImgLoad = useCallback((e) => {
8781
8820
  const el = e.currentTarget;
8782
8821
  if (el.naturalWidth && el.naturalHeight) {
@@ -8958,31 +8997,17 @@ function SizeResultView({
8958
8997
  ] }),
8959
8998
  (() => {
8960
8999
  const isFaceCategory = measurementType === "face" || measurementType === "head";
8961
- const detectionDone = isFaceCategory ? !!faceLandmarks : !!bodyLandmarks;
8962
- const detectLabel = isFaceCategory ? measurementType === "head" ? t("Detecting head") : t("Detecting face") : t("Detecting body pose");
8963
- if (isFaceCategory) {
8964
- return /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-right-col", style: { display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx(AccessoryStageCycler, { category: measurementType, sizingDone, t }) });
8965
- }
8966
- return /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-right-col ps-tryon-snap-steps", children: [
8967
- /* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step${detectionDone ? " ps-done" : " ps-active"}`, children: [
8968
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: detectionDone ? /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) : /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
8969
- /* @__PURE__ */ jsx("span", { children: detectLabel })
8970
- ] }),
8971
- !sizingDone && /* @__PURE__ */ jsxs(Fragment, { children: [
8972
- /* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step${analyzingDone ? " ps-done" : detectionDone ? " ps-active" : ""}`, children: [
8973
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: !detectionDone ? /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-num", children: "2" }) : !analyzingDone ? /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) : /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) }),
8974
- /* @__PURE__ */ jsx("span", { children: t("Analyzing your size") })
8975
- ] }),
8976
- /* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step${analyzingDone ? " ps-active" : ""}`, children: [
8977
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: !analyzingDone ? /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-num", children: "3" }) : /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
8978
- /* @__PURE__ */ jsx("span", { children: t("Finding best fit for you") })
8979
- ] })
8980
- ] }),
8981
- tryOnProcessing && /* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step${tryOnDone ? " ps-done" : " ps-active"}`, children: [
8982
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: tryOnDone ? /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) : /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
8983
- /* @__PURE__ */ jsx("span", { children: t("Generating virtual try-on") })
8984
- ] })
8985
- ] });
9000
+ isFaceCategory ? measurementType === "head" ? t("Detecting head") : t("Detecting face") : t("Detecting body pose");
9001
+ return /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-right-col", style: { display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx(
9002
+ StageCycler,
9003
+ {
9004
+ category: isFaceCategory ? measurementType : "body",
9005
+ sizingDone,
9006
+ tryOnProcessing,
9007
+ tryOnDone,
9008
+ t
9009
+ }
9010
+ ) });
8986
9011
  })()
8987
9012
  ] }),
8988
9013
  (allDone || sizingResult && !isSnapProcessing) && /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -9255,6 +9280,7 @@ function SizeResultView({
9255
9280
  productImage: resultImageUrl || productImage,
9256
9281
  productTitle,
9257
9282
  isMobile: true,
9283
+ renderRaw: isAccessory,
9258
9284
  isTryOnImage: !!resultImageUrl,
9259
9285
  showLines,
9260
9286
  onToggleLines: () => setShowLines(!showLines),
@@ -9298,7 +9324,8 @@ function SizeResultView({
9298
9324
  onTryOn: resultImageUrl || isAccessory ? void 0 : handleSingleTryOn,
9299
9325
  continueLabel: resultImageUrl ? t("Continue Shopping") : void 0,
9300
9326
  tryOnProcessing,
9301
- t
9327
+ t,
9328
+ renderRaw: isAccessory
9302
9329
  }
9303
9330
  ) }, "panel-single")
9304
9331
  ] });
@@ -13030,6 +13057,7 @@ function FootSizeView(props) {
13030
13057
  {
13031
13058
  title: "Shoe Size",
13032
13059
  fields,
13060
+ disablePhotoUpload: true,
13033
13061
  ...rest
13034
13062
  }
13035
13063
  );
@@ -9583,7 +9583,9 @@ async function detectBodyLandmarks(imageSrc) {
9583
9583
  rightKnee: { x: lm[RIGHT_KNEE].x, y: lm[RIGHT_KNEE].y },
9584
9584
  leftAnkle: { x: lm[LEFT_ANKLE].x, y: lm[LEFT_ANKLE].y },
9585
9585
  rightAnkle: { x: lm[RIGHT_ANKLE].x, y: lm[RIGHT_ANKLE].y },
9586
- nose: { x: lm[NOSE].x, y: lm[NOSE].y }
9586
+ nose: { x: lm[NOSE].x, y: lm[NOSE].y },
9587
+ imageWidth: img.naturalWidth || img.width,
9588
+ imageHeight: img.naturalHeight || img.height
9587
9589
  };
9588
9590
  } catch (err) {
9589
9591
  console.error("[PS-SDK] Body landmark detection failed:", err);
@@ -17184,36 +17186,57 @@ function FaceOverlay({
17184
17186
  ] }, key))
17185
17187
  ] });
17186
17188
  }
17187
- function AccessoryStageCycler({
17189
+ function StageCycler({
17188
17190
  category,
17189
17191
  sizingDone,
17192
+ tryOnProcessing,
17193
+ tryOnDone,
17190
17194
  t: t2
17191
17195
  }) {
17192
- const stages = category === "head" ? [
17196
+ const sizingStages = category === "head" ? [
17193
17197
  { title: t2("DETECTING HEAD"), desc: t2("Reading head landmarks from your photo.") },
17194
17198
  { title: t2("MAPPING CIRCUMFERENCE"), desc: t2("Estimating head width and depth.") },
17195
17199
  { title: t2("MATCHING HAT SIZE"), desc: t2("Comparing your circumference to the size chart.") },
17196
17200
  { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation.") }
17197
- ] : [
17201
+ ] : category === "face" ? [
17198
17202
  { title: t2("DETECTING FACE"), desc: t2("Identifying 478 face landmarks in your photo.") },
17199
17203
  { title: t2("CALIBRATING SCALE"), desc: t2("Using iris size as the pixel-to-mm anchor.") },
17200
17204
  { title: t2("MEASURING FRAME"), desc: t2("Mapping bridge, lens width and temple length.") },
17201
17205
  { title: t2("MATCHING FRAME SIZE"), desc: t2("Comparing your measurements to the size chart.") },
17202
17206
  { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation.") }
17207
+ ] : [
17208
+ // Body + foot fall through here — broadest set of stages so long
17209
+ // Gemini estimates still have fresh text to cycle through.
17210
+ { title: t2("DETECTING POSE"), desc: t2("Identifying body landmarks from your photo.") },
17211
+ { title: t2("SCANNING FRAME"), desc: t2("Our AI is mapping your proportions.") },
17212
+ { title: t2("ANALYZING BODY"), desc: t2("Measuring shoulders, chest, waist and hips.") },
17213
+ { title: t2("MATCHING SIZE"), desc: t2("Comparing your measurements to the size guide.") },
17214
+ { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation.") }
17215
+ ];
17216
+ const tryOnStages = [
17217
+ { title: t2("GENERATING TRY-ON"), desc: t2("Rendering the garment on your photo.") },
17218
+ { title: t2("REFINING DETAILS"), desc: t2("Fine-tuning fit, drape and shadows.") },
17219
+ { title: t2("ALMOST THERE"), desc: t2("Final compositing in progress.") },
17220
+ { title: t2("FINISHING TOUCHES"), desc: t2("Polishing the result.") }
17203
17221
  ];
17222
+ const active = tryOnProcessing ? tryOnStages : sizingStages;
17223
+ const isDone = tryOnProcessing ? !!tryOnDone : sizingDone;
17204
17224
  const [idx, setIdx] = reactExports.useState(0);
17205
17225
  reactExports.useEffect(() => {
17206
- if (sizingDone) return;
17226
+ setIdx(0);
17227
+ }, [tryOnProcessing]);
17228
+ reactExports.useEffect(() => {
17229
+ if (isDone) return;
17207
17230
  const id2 = setInterval(() => {
17208
- setIdx((i) => Math.min(i + 1, stages.length - 1));
17231
+ setIdx((i) => Math.min(i + 1, active.length - 1));
17209
17232
  }, 900);
17210
17233
  return () => clearInterval(id2);
17211
- }, [sizingDone, stages.length]);
17212
- const current = stages[idx] ?? stages[0];
17234
+ }, [isDone, active.length]);
17235
+ const current = active[idx] ?? active[0];
17213
17236
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msc-stage", style: { alignSelf: "center", marginTop: "auto", marginBottom: "auto" }, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msc-stage-slot", children: [
17214
17237
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msc-stage-title", children: current.title }),
17215
17238
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msc-stage-desc", children: current.desc })
17216
- ] }, idx) });
17239
+ ] }, `${tryOnProcessing ? "t" : "s"}-${idx}`) });
17217
17240
  }
17218
17241
  function SkeletonOverlay({ landmarks, imgWidth, imgHeight }) {
17219
17242
  const W2 = imgWidth;
@@ -17449,7 +17472,8 @@ function SectionDetailView({
17449
17472
  tryOnProcessing,
17450
17473
  backLabel,
17451
17474
  internationalSizes,
17452
- continueLabel
17475
+ continueLabel,
17476
+ renderRaw = false
17453
17477
  }) {
17454
17478
  const recSize = sectionResult?.recommendedSize || "";
17455
17479
  const [selectedSize, setSelectedSize] = reactExports.useState(null);
@@ -17567,6 +17591,18 @@ function SectionDetailView({
17567
17591
  return { range: val, ...parsed };
17568
17592
  }, [section, sizeColIdx, sizeHeader, unitLbl, columnUnits]);
17569
17593
  const fitRows = reactExports.useMemo(() => {
17594
+ if (renderRaw) {
17595
+ const raw = sectionResult?.matchDetails || [];
17596
+ return raw.map((m2) => ({
17597
+ area: m2.measurement.replace(/\s*\(.*?\)\s*$/, "").trim() || m2.measurement,
17598
+ rawUserValue: m2.userValue,
17599
+ rawChartRange: m2.chartRange,
17600
+ fit: m2.fit,
17601
+ userNum: 0,
17602
+ chartLabel: "",
17603
+ isLength: false
17604
+ }));
17605
+ }
17570
17606
  const mainDetails = sectionResult?.matchDetails || [];
17571
17607
  const lengthDetails = lengthEntry?.secResult?.matchDetails || [];
17572
17608
  const details = [...mainDetails, ...lengthDetails];
@@ -17636,11 +17672,12 @@ function SectionDetailView({
17636
17672
  }
17637
17673
  return { area: m2.measurement, userNum, chartLabel: cleanNumFn(chartLabel), fit, isLength: false };
17638
17674
  });
17639
- }, [sectionResult, lengthEntry, userMeasurements, displaySize, recSize, chartRangeFor, selectedLength, recLength]);
17675
+ }, [sectionResult, lengthEntry, userMeasurements, displaySize, recSize, chartRangeFor, selectedLength, recLength, renderRaw]);
17640
17676
  const goodCount = fitRows.filter(
17641
17677
  (r2) => r2.fit === "good" || r2.fit === "a-bit-tight" || r2.fit === "a-bit-loose"
17642
17678
  ).length;
17643
17679
  const matchPercent = fitRows.length > 0 ? Math.round(goodCount / fitRows.length * 100) : 0;
17680
+ const showMatchPercent = !renderRaw;
17644
17681
  const secAny = sectionResult;
17645
17682
  const backendSize = secAny?.size || recSize;
17646
17683
  const backendLength = secAny?.length || recLength;
@@ -17767,7 +17804,10 @@ function SectionDetailView({
17767
17804
  borderRadius: "8px",
17768
17805
  padding: "4px 12px"
17769
17806
  }, children: [
17770
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-card-size", children: displaySizeLabel }),
17807
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-msd-card-size", children: [
17808
+ displaySizeLabel,
17809
+ !selectedCountry && finalDisplayLength ? ` / ${finalDisplayLength}` : ""
17810
+ ] }),
17771
17811
  finalDisplayLength && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-card-size-meta", children: finalDisplayLength }),
17772
17812
  selectedCountry && isRecommended && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-msd-card-size-meta", style: { fontSize: "11px", opacity: 0.7 }, children: [
17773
17813
  "(",
@@ -17804,7 +17844,7 @@ function SectionDetailView({
17804
17844
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msd-row-cells", children: [
17805
17845
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msd-row-cell", children: [
17806
17846
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-cell-label", children: t2("USER") }),
17807
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-cell-value", children: isNaN(row.userNum) || row.userNum === 0 ? "—" : `${dNum(row.userNum)} ${unitLbl}` })
17847
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-cell-value", children: renderRaw ? row.rawUserValue || "—" : isNaN(row.userNum) || row.userNum === 0 ? "—" : `${dNum(row.userNum)} ${unitLbl}` })
17808
17848
  ] }),
17809
17849
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msd-row-cell ps-right", children: [
17810
17850
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-msd-cell-label", children: [
@@ -17812,7 +17852,7 @@ function SectionDetailView({
17812
17852
  " ",
17813
17853
  displaySize
17814
17854
  ] }),
17815
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-cell-value", children: dLabel(row.chartLabel) })
17855
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-cell-value", children: renderRaw ? row.rawChartRange || "—" : dLabel(row.chartLabel) })
17816
17856
  ] })
17817
17857
  ] }),
17818
17858
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-msd-row-badge ${fitClass}`, children: [
@@ -17911,7 +17951,7 @@ function SectionDetailView({
17911
17951
  ] })
17912
17952
  ] })
17913
17953
  ] }),
17914
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.4vw", marginBottom: "1.2vw" }, children: [
17954
+ showMatchPercent && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.4vw", marginBottom: "1.2vw" }, children: [
17915
17955
  /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "1vw", height: "1vw", viewBox: "0 0 16 16", fill: "none", children: [
17916
17956
  /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "8", cy: "8", r: "8", fill: "var(--ps-accent)" }),
17917
17957
  /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M4.5 8L7 10.5L11.5 5.5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
@@ -17934,8 +17974,8 @@ function SectionDetailView({
17934
17974
  const fitBg = row.fit === "good" ? "rgba(33,84,239,0.08)" : row.fit.includes("tight") ? "rgba(220,38,38,0.08)" : "rgba(217,119,6,0.08)";
17935
17975
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { style: { borderBottom: i < fitRows.length - 1 ? "1px solid rgba(0,0,0,0.04)" : "none" }, children: [
17936
17976
  /* @__PURE__ */ jsxRuntimeExports.jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", fontWeight: 500, color: "var(--ps-text-primary)" }, children: row.area }),
17937
- /* @__PURE__ */ jsxRuntimeExports.jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", color: "var(--ps-text-secondary)" }, children: isNaN(row.userNum) || row.userNum === 0 ? "—" : `${dNum(row.userNum)} ${unitLbl}` }),
17938
- /* @__PURE__ */ jsxRuntimeExports.jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", color: "var(--ps-text-secondary)" }, children: dLabel(row.chartLabel) }),
17977
+ /* @__PURE__ */ jsxRuntimeExports.jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", color: "var(--ps-text-secondary)" }, children: renderRaw ? row.rawUserValue || "—" : isNaN(row.userNum) || row.userNum === 0 ? "—" : `${dNum(row.userNum)} ${unitLbl}` }),
17978
+ /* @__PURE__ */ jsxRuntimeExports.jsx("td", { style: { padding: "0.55vw 0.6vw", fontSize: "0.75vw", color: "var(--ps-text-secondary)" }, children: renderRaw ? row.rawChartRange || "—" : dLabel(row.chartLabel) }),
17939
17979
  /* @__PURE__ */ jsxRuntimeExports.jsx("td", { style: { padding: "0.55vw 0.6vw", textAlign: "right" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontSize: "0.6vw", fontWeight: 600, color: fitColor, background: fitBg, borderRadius: "1vw", padding: "0.15vw 0.5vw", whiteSpace: "nowrap" }, children: row.isLength ? lengthFitLabelFn(row.fit, t2) : fitLabelFn(row.fit, t2) }) })
17940
17980
  ] }, i);
17941
17981
  }) })
@@ -18200,7 +18240,6 @@ function SizeResultView({
18200
18240
  const [poseLines, setPoseLines] = reactExports.useState(null);
18201
18241
  const [poseReady, setPoseReady] = reactExports.useState(false);
18202
18242
  const [imgDims, setImgDims] = reactExports.useState({ w: 800, h: 1200 });
18203
- const analyzingDone = estimationDone;
18204
18243
  const handleImgLoad = reactExports.useCallback((e) => {
18205
18244
  const el2 = e.currentTarget;
18206
18245
  if (el2.naturalWidth && el2.naturalHeight) {
@@ -18382,31 +18421,17 @@ function SizeResultView({
18382
18421
  ] }),
18383
18422
  (() => {
18384
18423
  const isFaceCategory = measurementType === "face" || measurementType === "head";
18385
- const detectionDone = isFaceCategory ? !!faceLandmarks : !!bodyLandmarks;
18386
- const detectLabel = isFaceCategory ? measurementType === "head" ? t2("Detecting head") : t2("Detecting face") : t2("Detecting body pose");
18387
- if (isFaceCategory) {
18388
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-right-col", style: { display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(AccessoryStageCycler, { category: measurementType, sizingDone, t: t2 }) });
18389
- }
18390
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sr-right-col ps-tryon-snap-steps", children: [
18391
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-snap-step${detectionDone ? " ps-done" : " ps-active"}`, children: [
18392
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-snap-step-icon", children: detectionDone ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
18393
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: detectLabel })
18394
- ] }),
18395
- !sizingDone && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
18396
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-snap-step${analyzingDone ? " ps-done" : detectionDone ? " ps-active" : ""}`, children: [
18397
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-snap-step-icon", children: !detectionDone ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-num", children: "2" }) : !analyzingDone ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) }),
18398
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Analyzing your size") })
18399
- ] }),
18400
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-snap-step${analyzingDone ? " ps-active" : ""}`, children: [
18401
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-snap-step-icon", children: !analyzingDone ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-num", children: "3" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
18402
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Finding best fit for you") })
18403
- ] })
18404
- ] }),
18405
- tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-snap-step${tryOnDone ? " ps-done" : " ps-active"}`, children: [
18406
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-snap-step-icon", children: tryOnDone ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
18407
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Generating virtual try-on") })
18408
- ] })
18409
- ] });
18424
+ isFaceCategory ? measurementType === "head" ? t2("Detecting head") : t2("Detecting face") : t2("Detecting body pose");
18425
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-right-col", style: { display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
18426
+ StageCycler,
18427
+ {
18428
+ category: isFaceCategory ? measurementType : "body",
18429
+ sizingDone,
18430
+ tryOnProcessing,
18431
+ tryOnDone,
18432
+ t: t2
18433
+ }
18434
+ ) });
18410
18435
  })()
18411
18436
  ] }),
18412
18437
  (allDone || sizingResult && !isSnapProcessing) && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
@@ -18679,6 +18704,7 @@ function SizeResultView({
18679
18704
  productImage: resultImageUrl || productImage,
18680
18705
  productTitle,
18681
18706
  isMobile: true,
18707
+ renderRaw: isAccessory,
18682
18708
  isTryOnImage: !!resultImageUrl,
18683
18709
  showLines,
18684
18710
  onToggleLines: () => setShowLines(!showLines),
@@ -18722,7 +18748,8 @@ function SizeResultView({
18722
18748
  onTryOn: resultImageUrl || isAccessory ? void 0 : handleSingleTryOn,
18723
18749
  continueLabel: resultImageUrl ? t2("Continue Shopping") : void 0,
18724
18750
  tryOnProcessing,
18725
- t: t2
18751
+ t: t2,
18752
+ renderRaw: isAccessory
18726
18753
  }
18727
18754
  ) }, "panel-single")
18728
18755
  ] });
@@ -22454,6 +22481,7 @@ function FootSizeView(props) {
22454
22481
  {
22455
22482
  title: "Shoe Size",
22456
22483
  fields,
22484
+ disablePhotoUpload: true,
22457
22485
  ...rest
22458
22486
  }
22459
22487
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primestyleai/tryon",
3
- "version": "5.8.53",
3
+ "version": "5.8.55",
4
4
  "description": "PrimeStyle Virtual Try-On SDK — React component & Web Component",
5
5
  "type": "module",
6
6
  "main": "dist/primestyle-tryon.js",