@primestyleai/tryon 5.10.0 → 5.10.2

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.
@@ -10265,12 +10265,15 @@ const STYLES$1 = `
10265
10265
  .ps-tryon-logo-img { height: var(--ps-logo-height); width: auto; }
10266
10266
  .ps-tryon-header-actions { display: flex; align-items: center; gap: 0.42vw; }
10267
10267
  .ps-tryon-header-icon {
10268
- width: 2.2vw; height: 2.2vw; display: flex; align-items: center; justify-content: center;
10269
- border: 1.5px solid var(--ps-border-color); border-radius: 0.52vw; background: transparent;
10268
+ /* Pure vw sizing collapsed to ~8 px on 375 px mobile. Clamp so the icon
10269
+ stays finger-tappable (min 30 px) while scaling up on large screens. */
10270
+ width: clamp(30px, 2.2vw, 34px); height: clamp(30px, 2.2vw, 34px);
10271
+ display: flex; align-items: center; justify-content: center;
10272
+ border: 1.5px solid var(--ps-border-color); border-radius: clamp(6px, 0.52vw, 10px); background: transparent;
10270
10273
  cursor: pointer; color: var(--ps-text-secondary); transition: all 0.2s;
10271
10274
  }
10272
10275
  .ps-tryon-header-icon:hover { border-color: var(--ps-accent); color: var(--ps-accent); }
10273
- .ps-tryon-header-icon svg { stroke: currentColor; fill: none; width: 0.9vw; height: 0.9vw; }
10276
+ .ps-tryon-header-icon svg { stroke: currentColor; fill: none; width: clamp(14px, 0.9vw, 16px); height: clamp(14px, 0.9vw, 16px); }
10274
10277
  .ps-tryon-close {
10275
10278
  width: 2.2vw; height: 2.2vw; display: flex; align-items: center; justify-content: center;
10276
10279
  background: none; border: none; color: var(--ps-modal-close-color, #999);
@@ -10318,7 +10321,10 @@ const STYLES$1 = `
10318
10321
  }
10319
10322
 
10320
10323
  .ps-tryon-lang-list {
10321
- max-height: min(18vw, 280px); overflow-y: auto; padding: clamp(3px, 0.31vw, 5px);
10324
+ /* max(...) picks the larger of the two values so the dropdown is tall
10325
+ enough to scroll through a handful of languages on any viewport.
10326
+ Pure min(18vw, 280px) collapsed to ~67 px on 375 px mobile. */
10327
+ max-height: max(260px, min(18vw, 280px)); overflow-y: auto; padding: clamp(3px, 0.31vw, 5px);
10322
10328
  scrollbar-width: thin; scrollbar-color: rgba(0,0,0,0.15) transparent;
10323
10329
  }
10324
10330
  .ps-tryon-lang-item {
@@ -12711,6 +12717,33 @@ const STYLES$1 = `
12711
12717
 
12712
12718
  /* ── Preserve existing previews and modal-wide overrides ── */
12713
12719
  .ps-tryon-preview { height: 320px; }
12720
+
12721
+ /* ── Drawer list (history / profiles / settings) ── */
12722
+ /* Pure vw gap (0.52vw = ~2 px on mobile) crushed list rows together. */
12723
+ .ps-tryon-drawer-list { gap: 12px !important; padding: 0 !important; }
12724
+ .ps-tryon-drawer { padding: 16px !important; }
12725
+
12726
+ /* ── Profile cards inside the sizing-profiles drawer ── */
12727
+ .ps-msp-card {
12728
+ padding: 16px !important;
12729
+ border-radius: 14px !important;
12730
+ }
12731
+ .ps-msp-card-tag { font-size: 11px !important; padding: 4px 8px !important; border-radius: 999px !important; }
12732
+ .ps-msp-card-circle { width: 72px !important; height: 72px !important; margin: 8px auto 12px !important; }
12733
+ .ps-msp-card-name { font-size: 16px !important; margin-bottom: 6px !important; }
12734
+ .ps-msp-meta-row { padding: 6px 0 !important; gap: 8px !important; }
12735
+ .ps-msp-card-meta { font-size: 12px !important; }
12736
+ .ps-msp-card-actions { gap: 8px !important; margin-top: 10px !important; }
12737
+ .ps-msp-card-select { font-size: 13px !important; padding: 10px 12px !important; border-radius: 8px !important; }
12738
+ .ps-msp-card-edit, .ps-msp-card-delete { width: 36px !important; height: 36px !important; border-radius: 8px !important; }
12739
+ .ps-msp-card-create { min-height: 120px !important; font-size: 14px !important; }
12740
+
12741
+ /* ── Language switcher dropdown ── */
12742
+ /* Default min(18vw, 280px) collapsed to ~67 px on mobile — unusable. */
12743
+ .ps-tryon-lang-list { max-height: 320px !important; }
12744
+ .ps-tryon-lang-item { padding: 10px 14px !important; gap: 10px !important; }
12745
+ .ps-tryon-lang-name { font-size: 14px !important; }
12746
+ .ps-tryon-lang-code { font-size: 11px !important; }
12714
12747
  }
12715
12748
 
12716
12749
  @keyframes ps-mobile-slide-up {
@@ -17279,30 +17312,22 @@ function MultiSectionMobile({
17279
17312
  children: t2("Continue Shopping")
17280
17313
  }
17281
17314
  )
17282
- ] }) : sizingResult?.found === false ? (
17283
- // Backend couldn't find a size that fits Try-On is meaningless
17284
- // without a recommendation, so surface a clear terminal action.
17285
- /* @__PURE__ */ jsxRuntimeExports.jsx(
17315
+ ] }) : (
17316
+ // Try-On stays enabled even when the backend couldn't find a size —
17317
+ // it's a visual preview, independent of the recommendation.
17318
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
17286
17319
  "button",
17287
17320
  {
17288
17321
  type: "button",
17289
17322
  className: "ps-msr-tryon-cta",
17290
- onClick: onClose,
17291
- children: t2("Continue Shopping")
17323
+ onClick: onTryOn,
17324
+ disabled: tryOnProcessing,
17325
+ children: [
17326
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CameraIcon, {}),
17327
+ tryOnProcessing ? t2("Processing...") : t2("See how it looks on yourself")
17328
+ ]
17292
17329
  }
17293
17330
  )
17294
- ) : /* @__PURE__ */ jsxRuntimeExports.jsxs(
17295
- "button",
17296
- {
17297
- type: "button",
17298
- className: "ps-msr-tryon-cta",
17299
- onClick: onTryOn,
17300
- disabled: tryOnProcessing,
17301
- children: [
17302
- /* @__PURE__ */ jsxRuntimeExports.jsx(CameraIcon, {}),
17303
- tryOnProcessing ? t2("Processing...") : t2("See how it looks on yourself")
17304
- ]
17305
- }
17306
17331
  ) }),
17307
17332
  sizeGuide ? null : null
17308
17333
  ] });
@@ -17814,8 +17839,7 @@ function SectionDetailView({
17814
17839
  const hasBadFit = details.some((d) => BAD_FIT.test(d.fit || ""));
17815
17840
  return hasBadFit ? t2("Not Recommended") : t2("Your Selection");
17816
17841
  }, [isRecommended, sectionResult, t2]);
17817
- const noFitMessage = t2("We couldn't find a size that fits for this product");
17818
- const displaySizeLabel = sectionFound === false ? noFitMessage : selectedCountry && isRecommended && internationalSizes && internationalSizes[selectedCountry] ? internationalSizes[selectedCountry] : displaySize;
17842
+ const displaySizeLabel = selectedCountry && isRecommended && internationalSizes && internationalSizes[selectedCountry] ? internationalSizes[selectedCountry] : displaySize;
17819
17843
  const columnUnits = reactExports.useMemo(() => {
17820
17844
  const units = [];
17821
17845
  for (let i = 0; i < section.headers.length; i++) {
@@ -17984,7 +18008,11 @@ function SectionDetailView({
17984
18008
  const showMatchPercent = !renderRaw;
17985
18009
  const secAny = sectionResult;
17986
18010
  const backendSize = secAny?.size || recSize;
17987
- const backendLength = secAny?.length || recLength;
18011
+ const lengthFromDetails = (sectionResult?.matchDetails || []).find(
18012
+ (m2) => /inseam|length/i.test(m2.measurement) && !/neck|arm|sleeve|back|shoulder/i.test(m2.measurement)
18013
+ );
18014
+ const inseamFallback = lengthFromDetails ? (lengthFromDetails.chartRange || "").replace(/\s*(cm|in|inches)\s*/i, "").trim() : "";
18015
+ const backendLength = secAny?.length || recLength || inseamFallback;
17988
18016
  const backendAvailableSizes = secAny?.availableSizes || [];
17989
18017
  const backendAvailableLengths = secAny?.availableLengths || [];
17990
18018
  const finalDisplayLength = selectedLength || backendLength;
@@ -18071,7 +18099,12 @@ function SectionDetailView({
18071
18099
  }
18072
18100
  )
18073
18101
  ] }),
18074
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msd-card", children: [
18102
+ sectionFound === false && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msd-card", style: { textAlign: "center" }, children: [
18103
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-card-eyebrow", children: t2("NO MATCHING SIZE") }),
18104
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { style: { fontSize: "15px", fontWeight: 600, color: "var(--ps-text-primary)", margin: "10px 0 4px" }, children: t2("We couldn't find a size that fits for this product.") }),
18105
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-msd-card-note", children: t2("Your measurements are outside this product's size range — the chart doesn't include a close match. You can still try it on visually below.") })
18106
+ ] }),
18107
+ sectionFound !== false && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msd-card", children: [
18075
18108
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-card-eyebrow", children: displaySize === backendSize ? t2("RECOMMENDED SIZE") : t2("TRYING SIZE") }),
18076
18109
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "10px", marginTop: "6px", marginBottom: "4px" }, children: [
18077
18110
  countryOptions.length > 1 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
@@ -18131,7 +18164,7 @@ function SectionDetailView({
18131
18164
  ] }),
18132
18165
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-msd-card-note", children: t2("Based on your measurements and the garment's tailoring chart.") })
18133
18166
  ] }),
18134
- fitRows.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msd-blueprint", children: [
18167
+ sectionFound !== false && fitRows.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msd-blueprint", children: [
18135
18168
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-blueprint-title", children: t2("MEASUREMENT BLUEPRINT") }),
18136
18169
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msd-blueprint-underline" }),
18137
18170
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msd-rows", children: fitRows.map((row, i) => {
@@ -18166,7 +18199,7 @@ function SectionDetailView({
18166
18199
  ] }, i);
18167
18200
  }) })
18168
18201
  ] }),
18169
- visibleSizes.length > 1 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msd-sizes", children: [
18202
+ sectionFound !== false && visibleSizes.length > 1 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msd-sizes", children: [
18170
18203
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-sizes-label", children: t2("TRY ANOTHER SIZE") }),
18171
18204
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msd-sizes-pills", children: visibleSizes.map((s) => {
18172
18205
  const isActive = s === displaySize;
@@ -18182,7 +18215,7 @@ function SectionDetailView({
18182
18215
  );
18183
18216
  }) })
18184
18217
  ] }),
18185
- visibleLengths.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msd-sizes", children: [
18218
+ sectionFound !== false && visibleLengths.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msd-sizes", children: [
18186
18219
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-sizes-label", children: t2("LENGTH ADJUSTMENT") }),
18187
18220
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msd-sizes-pills", children: visibleLengths.map((s) => {
18188
18221
  const isActive = finalDisplayLength === s;
@@ -18198,7 +18231,7 @@ function SectionDetailView({
18198
18231
  );
18199
18232
  }) })
18200
18233
  ] }),
18201
- /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "ps-msd-footer-note", children: [
18234
+ sectionFound !== false && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "ps-msd-footer-note", children: [
18202
18235
  t2("*Our sizing engine recommends"),
18203
18236
  " ",
18204
18237
  backendSize,
@@ -18209,7 +18242,19 @@ function SectionDetailView({
18209
18242
  ] }) });
18210
18243
  }
18211
18244
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sec-detail", style: { padding: "1.5vw", display: "flex", flexDirection: "column", height: "100%", background: "#F8F9FA" }, children: [
18212
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { flex: 1, minHeight: 0, overflowY: "auto", scrollbarWidth: "thin", scrollbarColor: "rgba(0,0,0,0.04) transparent" }, children: [
18245
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { flex: 1, minHeight: 0, overflowY: "auto", scrollbarWidth: "thin", scrollbarColor: "rgba(0,0,0,0.04) transparent" }, children: sectionFound === false ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: {
18246
+ background: "white",
18247
+ borderRadius: "0.7vw",
18248
+ border: "1px solid rgba(0,0,0,0.06)",
18249
+ padding: "1.4vw 1.6vw",
18250
+ textAlign: "center",
18251
+ marginTop: "0.4vw",
18252
+ marginBottom: "1vw"
18253
+ }, children: [
18254
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontSize: "0.7vw", fontWeight: 700, color: "var(--ps-accent)", textTransform: "uppercase", letterSpacing: "0.12em" }, children: t2("No matching size") }),
18255
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { style: { fontSize: "1vw", fontWeight: 600, color: "var(--ps-text-primary)", margin: "0.6vw 0 0.4vw" }, children: t2("We couldn't find a size that fits for this product.") }),
18256
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { style: { fontSize: "0.7vw", color: "var(--ps-text-secondary)", lineHeight: 1.55, margin: 0, maxWidth: "26vw", marginLeft: "auto", marginRight: "auto" }, children: t2("Your measurements are outside this product's size range. You can still try it on visually below.") })
18257
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
18213
18258
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontSize: "0.75vw", fontWeight: 700, color: "var(--ps-accent)", textTransform: "uppercase", letterSpacing: "0.12em" }, children: isRecommended ? t2("Recommended Size") : altSizeLabel ?? t2("Your Selection") }),
18214
18259
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.5vw", marginTop: "0.35vw", marginBottom: "0.4vw" }, children: [
18215
18260
  countryOptions.length > 1 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
@@ -18344,7 +18389,7 @@ function SectionDetailView({
18344
18389
  );
18345
18390
  }) })
18346
18391
  ] })
18347
- ] }),
18392
+ ] }) }),
18348
18393
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", paddingTop: "0.6vw", borderTop: "1px solid rgba(0,0,0,0.06)", flexShrink: 0 }, children: [
18349
18394
  /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-bp-back-btn", onClick: onBack, type: "button", style: { fontSize: "0.7vw" }, children: [
18350
18395
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-back-arrow", children: "←" }),
@@ -18669,7 +18714,7 @@ function SizeResultView({
18669
18714
  const allDone = hasPhoto ? sizingDone && tryOnDone : sizingDone;
18670
18715
  const isMobile = useIsMobile();
18671
18716
  const isAccessory = measurementType === "face" || measurementType === "head";
18672
- const noFit = sizingResult?.found === false;
18717
+ sizingResult?.found === false;
18673
18718
  const vtoExcluded = measurementType === "foot";
18674
18719
  console.log("[PS-SDK] SizeResultView render:", {
18675
18720
  hasPhoto,
@@ -18950,7 +18995,7 @@ function SizeResultView({
18950
18995
  " →"
18951
18996
  ]
18952
18997
  }
18953
- ) : vtoExcluded || noFit ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
18998
+ ) : vtoExcluded ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
18954
18999
  "button",
18955
19000
  {
18956
19001
  className: "ps-tryon-v2-cta",
@@ -19011,7 +19056,7 @@ function SizeResultView({
19011
19056
  onBack: resultImageUrl ? onClose || (() => setView("body-profile")) : () => setView("body-profile"),
19012
19057
  backLabel: t2("Back"),
19013
19058
  internationalSizes: sizingResult?.internationalSizes,
19014
- onTryOn: resultImageUrl || vtoExcluded || noFit ? void 0 : handleSingleTryOn,
19059
+ onTryOn: resultImageUrl || vtoExcluded ? void 0 : handleSingleTryOn,
19015
19060
  continueLabel: resultImageUrl ? t2("Continue Shopping") : void 0,
19016
19061
  tryOnProcessing,
19017
19062
  productImage: resultImageUrl || productImage,
@@ -19059,7 +19104,7 @@ function SizeResultView({
19059
19104
  onBack: resultImageUrl ? onClose || (() => setView("body-profile")) : () => setView("body-profile"),
19060
19105
  backLabel: t2("Back"),
19061
19106
  internationalSizes: sizingResult?.internationalSizes,
19062
- onTryOn: resultImageUrl || vtoExcluded || noFit ? void 0 : handleSingleTryOn,
19107
+ onTryOn: resultImageUrl || vtoExcluded ? void 0 : handleSingleTryOn,
19063
19108
  continueLabel: resultImageUrl ? t2("Continue Shopping") : void 0,
19064
19109
  tryOnProcessing,
19065
19110
  t: t2,
@@ -23755,7 +23800,14 @@ function PrimeStyleTryonInner({
23755
23800
  }
23756
23801
  }, [apiUrl, sizingMethod, sizingCountry, heightUnit, weightUnit, sizingUnit, sizeGuide, productTitle, dynamicFields, persistResultToProfile]);
23757
23802
  const handleQuickEstimate = reactExports.useCallback(async (height, weight, heightUnit2, weightUnit2, gender, age, bodyType, chestProfile, midsectionProfile, hipProfile, bodyImage) => {
23758
- if (!apiRef.current) return;
23803
+ if (!apiRef.current) {
23804
+ const msg = t2("SDK not configured. Please refresh and try again.");
23805
+ console.warn("[ps-sdk] handleQuickEstimate BAILED — apiRef is null. API key not loaded.");
23806
+ setErrorMessage(msg);
23807
+ setView("error");
23808
+ onError?.({ message: msg, code: "SDK_NOT_CONFIGURED" });
23809
+ return;
23810
+ }
23759
23811
  getApiUrl(apiUrl);
23760
23812
  getApiKey();
23761
23813
  const SKIP_ESTIMATE_KEYS = /* @__PURE__ */ new Set(["weight", "weightKg", "height", "heightCm"]);
@@ -23812,7 +23864,11 @@ function PrimeStyleTryonInner({
23812
23864
  apiUrl
23813
23865
  });
23814
23866
  if (!apiRef.current || !sseRef.current) {
23867
+ const msg = t2("SDK not configured. Please refresh and try again.");
23815
23868
  console.warn("[ps-sdk] handleSnapSubmit BAILED — apiRef or sseRef is null. Check api init.");
23869
+ setErrorMessage(msg);
23870
+ setView("error");
23871
+ onError?.({ message: msg, code: "SDK_NOT_CONFIGURED" });
23816
23872
  return;
23817
23873
  }
23818
23874
  const baseUrl = getApiUrl(apiUrl);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primestyleai/tryon",
3
- "version": "5.10.0",
3
+ "version": "5.10.2",
4
4
  "description": "PrimeStyle Virtual Try-On SDK — React component & Web Component",
5
5
  "type": "module",
6
6
  "main": "dist/primestyle-tryon.js",