@primestyleai/tryon 5.10.134 → 5.10.136

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.
@@ -24,6 +24,9 @@ export interface MultiSectionMobileProps {
24
24
  onSelectSection: (name: string) => void;
25
25
  onTryOn: () => void;
26
26
  tryOnProcessing?: boolean;
27
+ /** Epoch ms timestamp the try-on request started — drives the
28
+ * TryOnGenerationBadge's progress + ETA copy. */
29
+ tryOnStartedAt?: number | null;
27
30
  /** When set, the image area shows the try-on result instead of productImage. */
28
31
  resultImageUrl?: string | null;
29
32
  /** Try-on has finished and result is ready. Switches the bottom CTA into
@@ -44,4 +47,4 @@ export interface MultiSectionMobileProps {
44
47
  onImageLoad?: (e: React.SyntheticEvent<HTMLImageElement>) => void;
45
48
  t: TranslateFn;
46
49
  }
47
- export declare function MultiSectionMobile({ productImage, productTitle, sizingResult, sizeGuide, sectionEntries, pendingCustomSizes, onSelectSection, onTryOn, tryOnProcessing, resultImageUrl, tryOnDone, onTryAgain, onClose, overlayNode, showLines, onToggleLines, onImageLoad, t, }: MultiSectionMobileProps): import("react/jsx-runtime").JSX.Element;
50
+ export declare function MultiSectionMobile({ productImage, productTitle, sizingResult, sizeGuide, sectionEntries, pendingCustomSizes, onSelectSection, onTryOn, tryOnProcessing, tryOnStartedAt, resultImageUrl, tryOnDone, onTryAgain, onClose, overlayNode, showLines, onToggleLines, onImageLoad, t, }: MultiSectionMobileProps): import("react/jsx-runtime").JSX.Element;
@@ -11563,6 +11563,22 @@ const STYLES$1 = `
11563
11563
  @keyframes ps-tryon-badge-spin {
11564
11564
  to { transform: rotate(360deg); }
11565
11565
  }
11566
+ /* Mobile sizing for the try-on badge — desktop's max-width: 420px lives
11567
+ inside a roughly 360 px image hero, leaving the pill awkwardly clipped.
11568
+ Stretch it edge-to-edge with smaller text so it always fits. */
11569
+ @media (max-width: 768px) {
11570
+ .ps-tryon-badge {
11571
+ left: 12px; right: 12px; bottom: 12px;
11572
+ max-width: none;
11573
+ padding: 12px 14px;
11574
+ gap: 8px;
11575
+ border-radius: 12px;
11576
+ }
11577
+ .ps-tryon-badge-row { gap: 10px; }
11578
+ .ps-tryon-badge-title { font-size: 13px; }
11579
+ .ps-tryon-badge-pct { font-size: 11px; padding: 3px 9px; }
11580
+ .ps-tryon-badge-foot { font-size: 11px; gap: 8px; }
11581
+ }
11566
11582
 
11567
11583
  /* ── Product photo strip (single-garment, below the size card) ──
11568
11584
  Three thumbnails per slide, evenly spaced, auto-advances. Lives at
@@ -15316,9 +15332,12 @@ const STYLES$1 = `
15316
15332
  text-align: center; padding: 4px 12px;
15317
15333
  min-height: 64px;
15318
15334
  /* Lock width so the cycling stage text (shorter/longer strings every
15319
- ~2s) doesn't reflow the sibling TryOnProgress bar. */
15335
+ ~2s) doesn't reflow the sibling TryOnProgress bar. align-self:
15336
+ center centers the 320px container inside the flex column — without
15337
+ it the container sat at the left edge of the screen on mobile. */
15320
15338
  width: 320px;
15321
15339
  max-width: 100%;
15340
+ align-self: center;
15322
15341
  overflow: hidden;
15323
15342
  }
15324
15343
  .ps-msc-stage-slot {
@@ -15403,11 +15422,23 @@ const STYLES$1 = `
15403
15422
  .ps-msr-fit-toggle[aria-pressed="true"] {
15404
15423
  background: var(--ps-accent); color: #FFFFFF;
15405
15424
  }
15406
- /* Bottom action row when try-on finished — Try Again + Continue Shopping */
15425
+ /* Bottom action row when try-on finished — Try Again + Continue Shopping.
15426
+ min-width: 0 lets each button actually shrink to share the row equally
15427
+ on narrow viewports; white-space: nowrap stops "Continue Shopping"
15428
+ from wrapping to a second line. */
15407
15429
  .ps-msr-bottom-row {
15408
- display: flex; gap: 10px; align-items: stretch;
15430
+ display: flex; gap: 8px; align-items: stretch;
15431
+ }
15432
+ .ps-msr-bottom-row .ps-msr-tryon-cta {
15433
+ flex: 1 1 0; min-width: 0;
15434
+ padding: 14px 12px; font-size: 13px;
15435
+ white-space: nowrap;
15436
+ }
15437
+ @media (max-width: 360px) {
15438
+ .ps-msr-bottom-row .ps-msr-tryon-cta {
15439
+ padding: 12px 10px; font-size: 12px;
15440
+ }
15409
15441
  }
15410
- .ps-msr-bottom-row .ps-msr-tryon-cta { flex: 1; }
15411
15442
  .ps-msr-tryon-cta.ps-secondary {
15412
15443
  background: transparent;
15413
15444
  color: var(--ps-text-primary);
@@ -17477,6 +17508,11 @@ const STYLES$1 = `
17477
17508
 
17478
17509
  /* Big product / try-on image */
17479
17510
  .ps-msd-image {
17511
+ /* position: relative is required so the absolute children
17512
+ (.ps-msr-fit-toggle, .ps-tryon-badge) anchor to the image instead of
17513
+ the viewport. Without it the Show Fit pill rendered bottom-left of
17514
+ the screen on mobile. */
17515
+ position: relative;
17480
17516
  width: 100%; height: 420px;
17481
17517
  border-radius: 12px; overflow: hidden;
17482
17518
  background: var(--ps-bg-secondary);
@@ -17517,6 +17553,12 @@ const STYLES$1 = `
17517
17553
  letter-spacing: 0.05em;
17518
17554
  color: var(--ps-text-muted);
17519
17555
  }
17556
+ /* Mobile: 56 px overflows for compound labels like
17557
+ "MISSY 12 / Standard / Length 61". Cap at 36 px. */
17558
+ @media (max-width: 768px) {
17559
+ .ps-msd-card-size { font-size: 36px; letter-spacing: -0.015em; }
17560
+ .ps-msd-card-size-meta { font-size: 11px; }
17561
+ }
17520
17562
  .ps-msd-card-divider {
17521
17563
  height: 1px; background: var(--ps-border-subtle);
17522
17564
  margin: 6px 0;
@@ -17885,6 +17927,34 @@ const STYLES$1 = `
17885
17927
  color: var(--ps-accent);
17886
17928
  }
17887
17929
 
17930
+ /* Mobile px-based override — desktop rules use vw units which collapse
17931
+ to 1–4 px on a 375 px viewport. */
17932
+ @media (max-width: 768px) {
17933
+ .ps-bp-mini-select-trigger {
17934
+ padding: 10px 14px;
17935
+ font-size: 14px;
17936
+ border-radius: 8px;
17937
+ gap: 8px;
17938
+ min-width: 0;
17939
+ }
17940
+ .ps-bp-mini-select-arrow { font-size: 10px; }
17941
+ .ps-bp-mini-select-panel {
17942
+ max-height: 240px;
17943
+ border-radius: 10px;
17944
+ padding: 4px;
17945
+ box-shadow:
17946
+ 0 4px 12px rgba(15, 23, 42, 0.10),
17947
+ 0 12px 32px rgba(15, 23, 42, 0.16);
17948
+ }
17949
+ .ps-bp-mini-select[data-dir="down"] .ps-bp-mini-select-panel { top: calc(100% + 6px); }
17950
+ .ps-bp-mini-select[data-dir="up"] .ps-bp-mini-select-panel { bottom: calc(100% + 6px); }
17951
+ .ps-bp-mini-select-item {
17952
+ padding: 10px 12px;
17953
+ font-size: 14px;
17954
+ border-radius: 6px;
17955
+ }
17956
+ }
17957
+
17888
17958
  .ps-bp-bra-region-wrap { position: relative; z-index: 100; }
17889
17959
  .ps-bp-bra-region-trigger {
17890
17960
  display: flex; align-items: center; gap: 0.35vw;
@@ -19039,6 +19109,10 @@ function MobileBottomTabs({ mode, onSwitchToManual, onSwitchToScan, t: t2 }) {
19039
19109
  ] });
19040
19110
  }
19041
19111
  const SKELETON_CONNECTIONS$1 = [
19112
+ // Head → torso. Bridges the gap between the nose dot and the shoulder
19113
+ // line — without these the head reads as floating above the body.
19114
+ ["nose", "leftShoulder"],
19115
+ ["nose", "rightShoulder"],
19042
19116
  ["leftShoulder", "rightShoulder"],
19043
19117
  ["leftShoulder", "leftElbow"],
19044
19118
  ["leftElbow", "leftWrist"],
@@ -19052,6 +19126,14 @@ const SKELETON_CONNECTIONS$1 = [
19052
19126
  ["rightHip", "rightKnee"],
19053
19127
  ["rightKnee", "rightAnkle"]
19054
19128
  ];
19129
+ function isVisible(p2) {
19130
+ if (!p2 || typeof p2 !== "object") return false;
19131
+ const pt2 = p2;
19132
+ if (typeof pt2.x !== "number" || typeof pt2.y !== "number") return false;
19133
+ if (typeof pt2.visibility === "number" && pt2.visibility < 0.3) return false;
19134
+ if (pt2.x < 1e-3 && pt2.y < 1e-3) return false;
19135
+ return true;
19136
+ }
19055
19137
  function MobileSkeleton({ landmarks, w: w2, h }) {
19056
19138
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
19057
19139
  "svg",
@@ -19063,7 +19145,7 @@ function MobileSkeleton({ landmarks, w: w2, h }) {
19063
19145
  SKELETON_CONNECTIONS$1.map(([a, b], i) => {
19064
19146
  const pa2 = landmarks[a];
19065
19147
  const pb2 = landmarks[b];
19066
- if (!pa2 || !pb2) return null;
19148
+ if (!isVisible(pa2) || !isVisible(pb2)) return null;
19067
19149
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
19068
19150
  "line",
19069
19151
  {
@@ -19073,14 +19155,12 @@ function MobileSkeleton({ landmarks, w: w2, h }) {
19073
19155
  y2: pb2.y * h,
19074
19156
  stroke: "rgba(100,210,255,0.9)",
19075
19157
  strokeWidth: "4",
19076
- strokeLinecap: "round",
19077
- opacity: 0,
19078
- style: { animation: `ps-msc-fade 0.4s ease ${i * 0.05}s forwards` }
19158
+ strokeLinecap: "round"
19079
19159
  },
19080
19160
  `l-${i}`
19081
19161
  );
19082
19162
  }),
19083
- Object.entries(landmarks).filter(([, v2]) => v2 && typeof v2 === "object" && typeof v2.x === "number" && typeof v2.y === "number").map(([key, v2], i) => {
19163
+ Object.entries(landmarks).filter(([, v2]) => isVisible(v2)).map(([key, v2]) => {
19084
19164
  const p2 = v2;
19085
19165
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { children: [
19086
19166
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -19088,10 +19168,8 @@ function MobileSkeleton({ landmarks, w: w2, h }) {
19088
19168
  {
19089
19169
  cx: p2.x * w2,
19090
19170
  cy: p2.y * h,
19091
- r: 10,
19092
- fill: "rgba(100,210,255,0.25)",
19093
- opacity: 0,
19094
- style: { animation: `ps-msc-fade 0.3s ease ${i * 0.04}s forwards` }
19171
+ r: 14,
19172
+ fill: "rgba(100,210,255,0.30)"
19095
19173
  }
19096
19174
  ),
19097
19175
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -19099,10 +19177,8 @@ function MobileSkeleton({ landmarks, w: w2, h }) {
19099
19177
  {
19100
19178
  cx: p2.x * w2,
19101
19179
  cy: p2.y * h,
19102
- r: 6,
19103
- fill: "rgba(100,210,255,0.95)",
19104
- opacity: 0,
19105
- style: { animation: `ps-msc-fade 0.3s ease ${i * 0.04}s forwards` }
19180
+ r: 9,
19181
+ fill: "rgba(100,210,255,0.95)"
19106
19182
  }
19107
19183
  )
19108
19184
  ] }, key);
@@ -19192,6 +19268,99 @@ function MobileScanningView({
19192
19268
  ) })
19193
19269
  ] });
19194
19270
  }
19271
+ const TARGET_SECONDS = 22;
19272
+ function TryOnGenerationBadge({
19273
+ tryOnStartedAt,
19274
+ t: t2
19275
+ }) {
19276
+ const [, force] = reactExports.useState(0);
19277
+ reactExports.useEffect(() => {
19278
+ if (tryOnStartedAt == null) return;
19279
+ const id2 = setInterval(() => force((v2) => v2 + 1), 200);
19280
+ return () => clearInterval(id2);
19281
+ }, [tryOnStartedAt]);
19282
+ if (tryOnStartedAt == null) return null;
19283
+ const elapsed = (Date.now() - tryOnStartedAt) / 1e3;
19284
+ const pct = Math.min(95, elapsed / TARGET_SECONDS * 100);
19285
+ const pctRounded = Math.round(pct);
19286
+ const remaining = Math.max(0, TARGET_SECONDS - Math.floor(elapsed));
19287
+ const etaText = elapsed >= TARGET_SECONDS ? t2("almost done") : `~${remaining}s ${t2("left")}`;
19288
+ const statuses = [
19289
+ t2("Preparing your image"),
19290
+ t2("Analyzing body proportions"),
19291
+ t2("Mapping garment to body"),
19292
+ t2("Refining drape and shadows"),
19293
+ t2("Almost done")
19294
+ ];
19295
+ const stepIdx = Math.min(
19296
+ statuses.length - 1,
19297
+ Math.floor(elapsed / TARGET_SECONDS * statuses.length)
19298
+ );
19299
+ const status = statuses[stepIdx];
19300
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-badge", role: "status", "aria-live": "polite", children: [
19301
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-badge-row", children: [
19302
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-badge-spinner", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 24 24", width: "22", height: "22", children: [
19303
+ /* @__PURE__ */ jsxRuntimeExports.jsx("defs", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("linearGradient", { id: "ps-tryon-badge-grad", x1: "0", y1: "0", x2: "1", y2: "1", children: [
19304
+ /* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "0%", stopColor: "#3B82F6" }),
19305
+ /* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "100%", stopColor: "#2563EB" })
19306
+ ] }) }),
19307
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "9", fill: "none", stroke: "rgba(59,130,246,0.18)", strokeWidth: "2.4" }),
19308
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
19309
+ "circle",
19310
+ {
19311
+ cx: "12",
19312
+ cy: "12",
19313
+ r: "9",
19314
+ fill: "none",
19315
+ stroke: "url(#ps-tryon-badge-grad)",
19316
+ strokeWidth: "2.4",
19317
+ strokeLinecap: "round",
19318
+ strokeDasharray: "56.5",
19319
+ strokeDashoffset: "38"
19320
+ }
19321
+ )
19322
+ ] }) }),
19323
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-badge-title", children: t2("Generating your look...") }),
19324
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-badge-pct", children: [
19325
+ pctRounded,
19326
+ "%"
19327
+ ] })
19328
+ ] }),
19329
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-badge-bar", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-badge-bar-fill", style: { width: `${pctRounded}%` } }) }),
19330
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-badge-foot", children: [
19331
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-badge-status", children: [
19332
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-badge-status-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
19333
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "6", y1: "10", x2: "6", y2: "14" }),
19334
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "6", x2: "10", y2: "18" }),
19335
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "9", x2: "14", y2: "15" }),
19336
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "18", y1: "11", x2: "18", y2: "13" })
19337
+ ] }) }),
19338
+ status
19339
+ ] }),
19340
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-badge-eta", children: [
19341
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
19342
+ "svg",
19343
+ {
19344
+ width: "11",
19345
+ height: "11",
19346
+ viewBox: "0 0 24 24",
19347
+ fill: "none",
19348
+ stroke: "currentColor",
19349
+ strokeWidth: "2",
19350
+ strokeLinecap: "round",
19351
+ strokeLinejoin: "round",
19352
+ "aria-hidden": "true",
19353
+ children: [
19354
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "10" }),
19355
+ /* @__PURE__ */ jsxRuntimeExports.jsx("polyline", { points: "12 6 12 12 16 14" })
19356
+ ]
19357
+ }
19358
+ ),
19359
+ etaText
19360
+ ] })
19361
+ ] })
19362
+ ] });
19363
+ }
19195
19364
  function garmentIconForSection$1(name) {
19196
19365
  const n2 = name.toLowerCase();
19197
19366
  if (n2.includes("jacket") || n2.includes("blazer") || n2.includes("coat")) return garmentJacketImg;
@@ -19223,6 +19392,7 @@ function MultiSectionMobile({
19223
19392
  onSelectSection,
19224
19393
  onTryOn,
19225
19394
  tryOnProcessing,
19395
+ tryOnStartedAt,
19226
19396
  resultImageUrl,
19227
19397
  tryOnDone,
19228
19398
  onTryAgain,
@@ -19268,6 +19438,7 @@ function MultiSectionMobile({
19268
19438
  }
19269
19439
  ),
19270
19440
  showLines && overlayNode,
19441
+ tryOnProcessing && tryOnStartedAt != null && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt, t: t2 }),
19271
19442
  showingTryOn && onToggleLines && /* @__PURE__ */ jsxRuntimeExports.jsxs(
19272
19443
  "button",
19273
19444
  {
@@ -19388,99 +19559,6 @@ function MultiSectionMobile({
19388
19559
  sizeGuide ? null : null
19389
19560
  ] });
19390
19561
  }
19391
- const TARGET_SECONDS = 22;
19392
- function TryOnGenerationBadge({
19393
- tryOnStartedAt,
19394
- t: t2
19395
- }) {
19396
- const [, force] = reactExports.useState(0);
19397
- reactExports.useEffect(() => {
19398
- if (tryOnStartedAt == null) return;
19399
- const id2 = setInterval(() => force((v2) => v2 + 1), 200);
19400
- return () => clearInterval(id2);
19401
- }, [tryOnStartedAt]);
19402
- if (tryOnStartedAt == null) return null;
19403
- const elapsed = (Date.now() - tryOnStartedAt) / 1e3;
19404
- const pct = Math.min(95, elapsed / TARGET_SECONDS * 100);
19405
- const pctRounded = Math.round(pct);
19406
- const remaining = Math.max(0, TARGET_SECONDS - Math.floor(elapsed));
19407
- const etaText = elapsed >= TARGET_SECONDS ? t2("almost done") : `~${remaining}s ${t2("left")}`;
19408
- const statuses = [
19409
- t2("Preparing your image"),
19410
- t2("Analyzing body proportions"),
19411
- t2("Mapping garment to body"),
19412
- t2("Refining drape and shadows"),
19413
- t2("Almost done")
19414
- ];
19415
- const stepIdx = Math.min(
19416
- statuses.length - 1,
19417
- Math.floor(elapsed / TARGET_SECONDS * statuses.length)
19418
- );
19419
- const status = statuses[stepIdx];
19420
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-badge", role: "status", "aria-live": "polite", children: [
19421
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-badge-row", children: [
19422
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-badge-spinner", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 24 24", width: "22", height: "22", children: [
19423
- /* @__PURE__ */ jsxRuntimeExports.jsx("defs", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("linearGradient", { id: "ps-tryon-badge-grad", x1: "0", y1: "0", x2: "1", y2: "1", children: [
19424
- /* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "0%", stopColor: "#3B82F6" }),
19425
- /* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "100%", stopColor: "#2563EB" })
19426
- ] }) }),
19427
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "9", fill: "none", stroke: "rgba(59,130,246,0.18)", strokeWidth: "2.4" }),
19428
- /* @__PURE__ */ jsxRuntimeExports.jsx(
19429
- "circle",
19430
- {
19431
- cx: "12",
19432
- cy: "12",
19433
- r: "9",
19434
- fill: "none",
19435
- stroke: "url(#ps-tryon-badge-grad)",
19436
- strokeWidth: "2.4",
19437
- strokeLinecap: "round",
19438
- strokeDasharray: "56.5",
19439
- strokeDashoffset: "38"
19440
- }
19441
- )
19442
- ] }) }),
19443
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-badge-title", children: t2("Generating your look...") }),
19444
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-badge-pct", children: [
19445
- pctRounded,
19446
- "%"
19447
- ] })
19448
- ] }),
19449
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-badge-bar", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-badge-bar-fill", style: { width: `${pctRounded}%` } }) }),
19450
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-badge-foot", children: [
19451
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-badge-status", children: [
19452
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-badge-status-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
19453
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "6", y1: "10", x2: "6", y2: "14" }),
19454
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "6", x2: "10", y2: "18" }),
19455
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "9", x2: "14", y2: "15" }),
19456
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "18", y1: "11", x2: "18", y2: "13" })
19457
- ] }) }),
19458
- status
19459
- ] }),
19460
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-badge-eta", children: [
19461
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
19462
- "svg",
19463
- {
19464
- width: "11",
19465
- height: "11",
19466
- viewBox: "0 0 24 24",
19467
- fill: "none",
19468
- stroke: "currentColor",
19469
- strokeWidth: "2",
19470
- strokeLinecap: "round",
19471
- strokeLinejoin: "round",
19472
- "aria-hidden": "true",
19473
- children: [
19474
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "10" }),
19475
- /* @__PURE__ */ jsxRuntimeExports.jsx("polyline", { points: "12 6 12 12 16 14" })
19476
- ]
19477
- }
19478
- ),
19479
- etaText
19480
- ] })
19481
- ] })
19482
- ] });
19483
- }
19484
19562
  const PER_SLIDE = 3;
19485
19563
  const CYCLE_MS = 4e3;
19486
19564
  function ProductPhotoCarouselCard({
@@ -20253,6 +20331,7 @@ function SectionDetailView({
20253
20331
  }
20254
20332
  ),
20255
20333
  showLines && overlayNode,
20334
+ tryOnProcessing && tryOnStartedAt != null && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt, t: t2 }),
20256
20335
  isTryOnImage && onToggleLines && /* @__PURE__ */ jsxRuntimeExports.jsxs(
20257
20336
  "button",
20258
20337
  {
@@ -21295,6 +21374,7 @@ function SizeResultView({
21295
21374
  setShowPhotoGuide(true);
21296
21375
  },
21297
21376
  tryOnProcessing,
21377
+ tryOnStartedAt,
21298
21378
  resultImageUrl,
21299
21379
  tryOnDone: !!resultImageUrl && !tryOnProcessing,
21300
21380
  onTryAgain: () => {
@@ -22885,7 +22965,7 @@ function CreateProfileWizard({ onSave, onCancel, apiUrl, apiKey, onPhotoPreview,
22885
22965
  const CUP_OPTIONS_US2 = ["AA", "A", "B", "C", "D", "DD/E", "DDD/F", "G", "H", "I", "J"];
22886
22966
  const isWomen = gender === "female";
22887
22967
  const imgs = isWomen ? BODY_IMAGES.female : BODY_IMAGES.male;
22888
- const manualStepOrder = isWomen ? ["identity", "stomach", "seat", "hips", "bra"] : ["identity", "chest", "stomach", "seat"];
22968
+ const manualStepOrder = isWomen ? ["identity", "stomach", "seat", "hips"] : ["identity", "chest", "stomach", "seat"];
22889
22969
  const manualStepIdx = manualStepOrder.indexOf(manualStep);
22890
22970
  const manualStepCount = manualStepOrder.length;
22891
22971
  const isLastManualStep = manualStepIdx === manualStepCount - 1;
@@ -22937,6 +23017,10 @@ function CreateProfileWizard({ onSave, onCancel, apiUrl, apiKey, onPhotoPreview,
22937
23017
  setError(t2("Please enter a valid age"));
22938
23018
  return false;
22939
23019
  }
23020
+ if (isWomen && (!bandSize || !cupSize)) {
23021
+ setError(t2("Please select your bra band and cup size"));
23022
+ return false;
23023
+ }
22940
23024
  setError("");
22941
23025
  return true;
22942
23026
  };
@@ -23327,6 +23411,63 @@ function CreateProfileWizard({ onSave, onCancel, apiUrl, apiKey, onPhotoPreview,
23327
23411
  ),
23328
23412
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-inline-unit", children: t2("years") })
23329
23413
  ] })
23414
+ ] }),
23415
+ isWomen && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { ref: inlineBraWrapRef, children: [
23416
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-inline-row", children: [
23417
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-inline-label", children: t2("BRA REGION") }),
23418
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-inline-input-group", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
23419
+ MiniSelect$1,
23420
+ {
23421
+ value: braSizeRegion,
23422
+ options: Object.keys(BAND_SIZES$1),
23423
+ isOpen: inlineBraOpen === "region",
23424
+ onToggle: () => setInlineBraOpen(inlineBraOpen === "region" ? null : "region"),
23425
+ onSelect: (v2) => {
23426
+ setBraSizeRegion(v2);
23427
+ setBandSize(null);
23428
+ setCupSize(null);
23429
+ setInlineBraOpen(null);
23430
+ setError("");
23431
+ }
23432
+ }
23433
+ ) })
23434
+ ] }),
23435
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-inline-row", children: [
23436
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-inline-label", children: t2("BAND") }),
23437
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-inline-input-group", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
23438
+ MiniSelect$1,
23439
+ {
23440
+ value: bandSize,
23441
+ options: BAND_SIZES$1[braSizeRegion] || BAND_SIZES$1.US,
23442
+ placeholder: "—",
23443
+ isOpen: inlineBraOpen === "band",
23444
+ onToggle: () => setInlineBraOpen(inlineBraOpen === "band" ? null : "band"),
23445
+ onSelect: (v2) => {
23446
+ setBandSize(v2);
23447
+ setInlineBraOpen(null);
23448
+ setError("");
23449
+ }
23450
+ }
23451
+ ) })
23452
+ ] }),
23453
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-inline-row", children: [
23454
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-inline-label", children: t2("CUP") }),
23455
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-inline-input-group", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
23456
+ MiniSelect$1,
23457
+ {
23458
+ value: cupSize,
23459
+ options: CUP_OPTIONS_US2,
23460
+ placeholder: "—",
23461
+ isOpen: inlineBraOpen === "cup",
23462
+ onToggle: () => setInlineBraOpen(inlineBraOpen === "cup" ? null : "cup"),
23463
+ onSelect: (v2) => {
23464
+ setCupSize(v2);
23465
+ setInlineBraOpen(null);
23466
+ setError("");
23467
+ }
23468
+ }
23469
+ ) })
23470
+ ] })
23330
23471
  ] })
23331
23472
  ] }),
23332
23473
  error && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-cpw-error", children: error })
@@ -25490,7 +25631,8 @@ function BodyProfileView({
25490
25631
  setAge("");
25491
25632
  setBandSize(null);
25492
25633
  setCupSize(null);
25493
- }, [handleRemovePhoto]);
25634
+ onStartFresh?.();
25635
+ }, [handleRemovePhoto, onStartFresh]);
25494
25636
  reactExports.useEffect(() => {
25495
25637
  const profilePhoto = activeProfile?.photoBase64;
25496
25638
  const profileId = activeProfile?.id ?? null;
@@ -26313,6 +26455,15 @@ function BodyProfileView({
26313
26455
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-loaded-pill-text", children: t2("Loaded from profile") }),
26314
26456
  /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-bp-loaded-pill-clear", onClick: handleClearFromProfile, children: t2("Clear") })
26315
26457
  ] }) }),
26458
+ hasActiveProfileWithMeasurements && activeProfileName && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "ps-bp-profile-hint", style: { textAlign: "center", margin: "0 0 0.5vw" }, children: [
26459
+ t2("Using"),
26460
+ " ",
26461
+ /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: activeProfileName }),
26462
+ onStartFresh && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
26463
+ " · ",
26464
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-bp-profile-hint-link", onClick: handleClearFromProfile, children: t2("start fresh") })
26465
+ ] })
26466
+ ] }),
26316
26467
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-inline-fields", children: [
26317
26468
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-inline-row", children: [
26318
26469
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-inline-label", children: t2("HEIGHT") }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primestyleai/tryon",
3
- "version": "5.10.134",
3
+ "version": "5.10.136",
4
4
  "description": "PrimeStyle Virtual Try-On SDK — React component & Web Component",
5
5
  "type": "module",
6
6
  "main": "dist/primestyle-tryon.js",