@primestyleai/tryon 5.6.10 → 5.6.12

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.
@@ -4002,40 +4002,18 @@ const STYLES = `
4002
4002
  .ps-msp-avatar { color: var(--ps-accent); border-color: var(--ps-accent); }
4003
4003
  .ps-msp-avatar-tag { background: var(--ps-accent); }
4004
4004
 
4005
- .ps-msp-card-thumb {
4006
- position: relative;
4007
- height: 90px;
4008
- background: var(--ps-bg-secondary);
4009
- border-radius: 8px;
4010
- display: flex; align-items: center; justify-content: center;
4011
- margin-bottom: 22px;
4012
- color: var(--ps-text-secondary);
4013
- overflow: visible;
4014
- }
4015
- .ps-msp-card-thumb::after {
4016
- /* Clip the rectangle photo only, not the circle overlay */
4017
- content: ""; display: block;
4018
- }
4019
- .ps-msp-card-photo {
4020
- width: 100%; height: 100%; object-fit: cover; display: block;
4021
- border-radius: 8px;
4022
- /* Same head-bias crop as the profile detail avatar */
4023
- object-position: 50% 12%;
4024
- }
4025
- /* Circular profile avatar overlay — sits on the bottom-left of the
4026
- rectangular thumb, social-card style. Shows the head crop. */
4005
+ /* Big circular profile avatar — only chrome on the card, no
4006
+ rectangular hero. Shows the head crop via object-position 12%. */
4027
4007
  .ps-msp-card-circle {
4028
- position: absolute;
4029
- left: 12px; bottom: -18px;
4030
- width: 44px; height: 44px;
4008
+ width: 110px; height: 110px;
4031
4009
  border-radius: 50%;
4032
- background: var(--ps-bg-primary);
4033
- border: 3px solid var(--ps-bg-primary);
4034
- box-shadow: 0 4px 12px rgba(0,0,0,0.12);
4010
+ background: var(--ps-bg-secondary);
4011
+ border: 3px solid var(--ps-accent);
4012
+ box-shadow: 0 6px 18px rgba(33, 84, 239, 0.18);
4035
4013
  overflow: hidden;
4036
4014
  display: flex; align-items: center; justify-content: center;
4037
4015
  color: var(--ps-accent);
4038
- z-index: 2;
4016
+ margin: 6px auto 14px;
4039
4017
  }
4040
4018
  .ps-msp-card-circle img {
4041
4019
  width: 100%; height: 100%; object-fit: cover;
@@ -4681,7 +4659,32 @@ const STYLES = `
4681
4659
  100% { background-position: -200% 0; }
4682
4660
  }
4683
4661
 
4684
- /* Saved sizes history (per-product cache) */
4662
+ /* Inline measurement edit inputs */
4663
+ .ps-pmv-measure.ps-editing {
4664
+ border-color: var(--ps-accent);
4665
+ background: rgba(33, 84, 239, 0.04);
4666
+ }
4667
+ .ps-pmv-measure-edit {
4668
+ display: flex; align-items: baseline; gap: 4px;
4669
+ }
4670
+ .ps-pmv-measure-input {
4671
+ flex: 1; min-width: 0;
4672
+ background: transparent; border: none; outline: none;
4673
+ font-family: inherit;
4674
+ font-size: 18px; font-weight: 700;
4675
+ color: var(--ps-text-primary);
4676
+ padding: 0;
4677
+ font-feature-settings: "tnum" 1;
4678
+ }
4679
+ .ps-pmv-measure-input::-webkit-outer-spin-button,
4680
+ .ps-pmv-measure-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
4681
+ .ps-pmv-measure-input[type="number"] { -moz-appearance: textfield; }
4682
+ .ps-pmv-measure-input-unit {
4683
+ font-size: 11px; color: var(--ps-text-muted); font-weight: 500;
4684
+ }
4685
+
4686
+ /* Saved sizes history (per-product cache) — kept for backwards compat,
4687
+ no longer rendered inside ProfileMeasurementsView */
4685
4688
  .ps-pmv-history {
4686
4689
  display: flex; flex-direction: column; gap: 8px;
4687
4690
  }
@@ -8250,7 +8253,7 @@ function ProfileMeasurementsView({
8250
8253
  profile,
8251
8254
  isActive,
8252
8255
  onSelect,
8253
- onEdit,
8256
+ onSaveMeasurements,
8254
8257
  onDelete,
8255
8258
  onBack,
8256
8259
  onSave,
@@ -8260,6 +8263,33 @@ function ProfileMeasurementsView({
8260
8263
  const measurements = profile.measurements || {};
8261
8264
  const unit = profile.measurementsUnit || "cm";
8262
8265
  const hasMeasurements = Object.keys(measurements).some((k) => measurements[k] != null);
8266
+ const [editing, setEditing] = useState(false);
8267
+ const [draft, setDraft] = useState({});
8268
+ useEffect(() => {
8269
+ if (!editing) return;
8270
+ const next = {};
8271
+ for (const f of fields) {
8272
+ const v = measurements[f.key];
8273
+ if (v != null) next[f.key] = String(Math.round(v * 10) / 10);
8274
+ }
8275
+ setDraft(next);
8276
+ }, [editing]);
8277
+ const handleDraftChange = (key, value) => {
8278
+ setDraft((prev) => ({ ...prev, [key]: value }));
8279
+ };
8280
+ const handleEditSave = () => {
8281
+ const updated = { ...measurements };
8282
+ for (const [key, raw] of Object.entries(draft)) {
8283
+ const v = parseFloat(raw);
8284
+ if (!isNaN(v) && v > 0) updated[key] = v;
8285
+ }
8286
+ onSaveMeasurements(updated);
8287
+ setEditing(false);
8288
+ };
8289
+ const handleEditCancel = () => {
8290
+ setEditing(false);
8291
+ setDraft({});
8292
+ };
8263
8293
  const heightDisplay = (() => {
8264
8294
  const h = profile.height ?? profile.heightCm;
8265
8295
  if (!h) return "—";
@@ -8310,44 +8340,45 @@ function ProfileMeasurementsView({
8310
8340
  /* @__PURE__ */ jsx("span", { children: t("Calculating...") })
8311
8341
  ] })
8312
8342
  ] }),
8313
- /* @__PURE__ */ jsx("div", { className: "ps-pmv-section-sub", children: hasMeasurements ? t("Calculated from your basics. Used to recommend the perfect size for any product.") : t("Our AI is computing your full body proportions — this usually takes a few seconds.") })
8343
+ /* @__PURE__ */ jsx("div", { className: "ps-pmv-section-sub", children: hasMeasurements ? editing ? t("Tap any value to edit. Save when you're done.") : t("Calculated from your basics. Used to recommend the perfect size for any product.") : t("Our AI is computing your full body proportions — this usually takes a few seconds.") })
8314
8344
  ] }),
8315
8345
  /* @__PURE__ */ jsx("div", { className: "ps-pmv-measure-grid", children: fields.map((f) => {
8316
8346
  const v = measurements[f.key];
8317
- return /* @__PURE__ */ jsxs("div", { className: `ps-pmv-measure${v == null ? " ps-loading" : ""}`, children: [
8347
+ return /* @__PURE__ */ jsxs("div", { className: `ps-pmv-measure${v == null && !editing ? " ps-loading" : ""}${editing ? " ps-editing" : ""}`, children: [
8318
8348
  /* @__PURE__ */ jsx("div", { className: "ps-pmv-measure-label", children: t(f.label) }),
8319
- /* @__PURE__ */ jsx("div", { className: `ps-pmv-measure-value${v == null ? " ps-loading" : ""}`, children: v != null ? `${Math.round(v * 10) / 10} ${unit}` : "—" })
8349
+ editing ? /* @__PURE__ */ jsxs("div", { className: "ps-pmv-measure-edit", children: [
8350
+ /* @__PURE__ */ jsx(
8351
+ "input",
8352
+ {
8353
+ type: "number",
8354
+ inputMode: "decimal",
8355
+ className: "ps-pmv-measure-input",
8356
+ value: draft[f.key] ?? "",
8357
+ placeholder: "—",
8358
+ onChange: (e) => handleDraftChange(f.key, e.target.value)
8359
+ }
8360
+ ),
8361
+ /* @__PURE__ */ jsx("span", { className: "ps-pmv-measure-input-unit", children: unit })
8362
+ ] }) : /* @__PURE__ */ jsx("div", { className: `ps-pmv-measure-value${v == null ? " ps-loading" : ""}`, children: v != null ? `${Math.round(v * 10) / 10} ${unit}` : "—" })
8320
8363
  ] }, f.key);
8321
8364
  }) })
8322
8365
  ] }),
8323
- profile.sizeHistory && profile.sizeHistory.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-pmv-section", children: [
8324
- /* @__PURE__ */ jsxs("div", { className: "ps-pmv-section-head", children: [
8325
- /* @__PURE__ */ jsx("div", { className: "ps-pmv-section-title", children: t("SAVED SIZES") }),
8326
- /* @__PURE__ */ jsx("div", { className: "ps-pmv-section-sub", children: t("Recommendations from this profile across products") })
8327
- ] }),
8328
- /* @__PURE__ */ jsx("div", { className: "ps-pmv-history", children: profile.sizeHistory.slice(0, 6).map((entry) => /* @__PURE__ */ jsxs("div", { className: "ps-pmv-history-card", children: [
8329
- entry.productImage && /* @__PURE__ */ jsx("div", { className: "ps-pmv-history-thumb", children: /* @__PURE__ */ jsx("img", { src: entry.productImage, alt: entry.productTitle }) }),
8330
- /* @__PURE__ */ jsxs("div", { className: "ps-pmv-history-info", children: [
8331
- /* @__PURE__ */ jsx("div", { className: "ps-pmv-history-name", children: entry.productTitle }),
8332
- /* @__PURE__ */ jsx("div", { className: "ps-pmv-history-meta", children: new Date(entry.savedAt).toLocaleDateString(void 0, { month: "short", day: "numeric" }) })
8333
- ] }),
8334
- /* @__PURE__ */ jsx("div", { className: "ps-pmv-history-size", children: entry.recommendedSize })
8335
- ] }, `${entry.productId}-${entry.savedAt}`)) })
8336
- ] }),
8337
8366
  /* @__PURE__ */ jsxs("div", { className: "ps-pmv-actions", children: [
8338
- /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pmv-btn-secondary", onClick: onBack, children: t("Back") }),
8367
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pmv-btn-secondary", onClick: editing ? handleEditCancel : onBack, children: editing ? t("Cancel") : t("Back") }),
8339
8368
  /* @__PURE__ */ jsxs("div", { className: "ps-pmv-actions-right", children: [
8340
- /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pmv-btn-edit", onClick: onEdit, children: t("Edit") }),
8341
- /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pmv-btn-delete", onClick: onDelete, children: t("Delete") }),
8342
- !isActive && /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pmv-btn-secondary", onClick: onSelect, children: t("USE THIS PROFILE") }),
8369
+ !editing && /* @__PURE__ */ jsxs(Fragment, { children: [
8370
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pmv-btn-edit", onClick: () => setEditing(true), children: t("Edit") }),
8371
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pmv-btn-delete", onClick: onDelete, children: t("Delete") }),
8372
+ !isActive && /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pmv-btn-secondary", onClick: onSelect, children: t("USE THIS PROFILE") })
8373
+ ] }),
8343
8374
  /* @__PURE__ */ jsx(
8344
8375
  "button",
8345
8376
  {
8346
8377
  type: "button",
8347
8378
  className: "ps-pmv-btn-primary",
8348
- onClick: onSave,
8379
+ onClick: editing ? handleEditSave : onSave,
8349
8380
  disabled: !hasMeasurements,
8350
- children: hasMeasurements ? t("SAVE") : /* @__PURE__ */ jsxs(Fragment, { children: [
8381
+ children: hasMeasurements ? editing ? t("SAVE CHANGES") : t("SAVE") : /* @__PURE__ */ jsxs(Fragment, { children: [
8351
8382
  /* @__PURE__ */ jsx("span", { className: "ps-pmv-btn-spinner" }),
8352
8383
  t("CALCULATING")
8353
8384
  ] })
@@ -8357,12 +8388,6 @@ function ProfileMeasurementsView({
8357
8388
  ] })
8358
8389
  ] });
8359
8390
  }
8360
- function ProfileAvatar({ gender }) {
8361
- return /* @__PURE__ */ jsxs("div", { className: "ps-msp-avatar", children: [
8362
- /* @__PURE__ */ jsx(UserIcon, { size: 28 }),
8363
- gender && /* @__PURE__ */ jsx("span", { className: `ps-msp-avatar-tag ps-${gender}`, children: gender === "female" ? "♀" : "♂" })
8364
- ] });
8365
- }
8366
8391
  function ProfileCard({
8367
8392
  profile,
8368
8393
  isActive,
@@ -8400,10 +8425,7 @@ function ProfileCard({
8400
8425
  tabIndex: 0,
8401
8426
  children: [
8402
8427
  /* @__PURE__ */ jsx("div", { className: "ps-msp-card-header", children: /* @__PURE__ */ jsx("span", { className: "ps-msp-card-tag", children: isActive ? t("DEFAULT PROFILE") : profile.gender === "female" ? t("WOMEN'S FIT") : t("MEN'S FIT") }) }),
8403
- /* @__PURE__ */ jsxs("div", { className: "ps-msp-card-thumb", children: [
8404
- profile.photoBase64 ? /* @__PURE__ */ jsx("img", { src: profile.photoBase64, alt: profile.name, className: "ps-msp-card-photo" }) : /* @__PURE__ */ jsx(ProfileAvatar, { gender: profile.gender }),
8405
- /* @__PURE__ */ jsx("div", { className: "ps-msp-card-circle", children: profile.photoBase64 ? /* @__PURE__ */ jsx("img", { src: profile.photoBase64, alt: "" }) : /* @__PURE__ */ jsx(UserIcon, { size: 18 }) })
8406
- ] }),
8428
+ /* @__PURE__ */ jsx("div", { className: "ps-msp-card-circle", children: profile.photoBase64 ? /* @__PURE__ */ jsx("img", { src: profile.photoBase64, alt: profile.name }) : /* @__PURE__ */ jsx(UserIcon, { size: 32 }) }),
8407
8429
  /* @__PURE__ */ jsx("div", { className: "ps-msp-card-name", children: profile.name }),
8408
8430
  /* @__PURE__ */ jsxs("div", { className: "ps-msp-card-meta", children: [
8409
8431
  heightDisplay && /* @__PURE__ */ jsxs("div", { className: "ps-msp-meta-row", children: [
@@ -8473,6 +8495,7 @@ function MySizingProfilesView({
8473
8495
  onSelectProfile,
8474
8496
  onEditProfile,
8475
8497
  onSaveNewProfile,
8498
+ onSaveProfileMeasurements,
8476
8499
  onDeleteProfile,
8477
8500
  onClose,
8478
8501
  t
@@ -8504,9 +8527,7 @@ function MySizingProfilesView({
8504
8527
  onSelectProfile(viewingProfile.id);
8505
8528
  setViewingId(null);
8506
8529
  },
8507
- onEdit: () => {
8508
- onEditProfile(viewingProfile);
8509
- },
8530
+ onSaveMeasurements: (m) => onSaveProfileMeasurements(viewingProfile.id, m),
8510
8531
  onDelete: () => {
8511
8532
  onDeleteProfile(viewingProfile.id);
8512
8533
  setViewingId(null);
@@ -8612,6 +8633,7 @@ function BasicsStepMobile({
8612
8633
  onSwitchToScan,
8613
8634
  onNext,
8614
8635
  canProceed,
8636
+ fastPathLabel,
8615
8637
  error,
8616
8638
  t
8617
8639
  }) {
@@ -8787,7 +8809,7 @@ function BasicsStepMobile({
8787
8809
  className: "ps-bpm-next-btn",
8788
8810
  onClick: onNext,
8789
8811
  disabled: !canProceed,
8790
- children: t("Next")
8812
+ children: fastPathLabel || t("Next")
8791
8813
  }
8792
8814
  ),
8793
8815
  /* @__PURE__ */ jsx(
@@ -9058,6 +9080,8 @@ function BodyProfileView({
9058
9080
  setSizingUnit,
9059
9081
  onComplete,
9060
9082
  onSnapSubmit,
9083
+ hasActiveProfileWithMeasurements = false,
9084
+ onUseActiveProfile,
9061
9085
  onBack,
9062
9086
  t
9063
9087
  }) {
@@ -9469,8 +9493,9 @@ function BodyProfileView({
9469
9493
  switchToImperial,
9470
9494
  onUploadPhoto: () => setStep("photo"),
9471
9495
  onSwitchToScan: () => setStep("photo"),
9472
- onNext: handleNext,
9496
+ onNext: hasActiveProfileWithMeasurements && onUseActiveProfile ? onUseActiveProfile : handleNext,
9473
9497
  canProceed: true,
9498
+ fastPathLabel: hasActiveProfileWithMeasurements ? t("Find My Best Fit") : void 0,
9474
9499
  error,
9475
9500
  t
9476
9501
  },
@@ -9720,23 +9745,28 @@ function BodyProfileView({
9720
9745
  })(),
9721
9746
  error && /* @__PURE__ */ jsx("p", { className: "ps-bp-error", children: error })
9722
9747
  ] }, "step-bra"),
9723
- !(isMobile && step === "basics") && /* @__PURE__ */ jsxs("div", { className: "ps-bp-nav", children: [
9724
- step !== "basics" ? /* @__PURE__ */ jsxs("button", { className: "ps-bp-back-btn", onClick: handleBackStep, type: "button", children: [
9725
- /* @__PURE__ */ jsx("span", { className: "ps-bp-back-arrow", children: "←" }),
9726
- " ",
9727
- t("Back")
9728
- ] }) : /* @__PURE__ */ jsx("span", {}),
9729
- /* @__PURE__ */ jsx(
9730
- "button",
9731
- {
9732
- className: `ps-bp-next-btn${!canProceed ? " ps-bp-btn-disabled" : ""}`,
9733
- onClick: handleNext,
9734
- disabled: !canProceed,
9735
- type: "button",
9736
- children: isLastStep ? t("Find My Size") : t("Next")
9737
- }
9738
- )
9739
- ] })
9748
+ !(isMobile && step === "basics") && (() => {
9749
+ const useProfileFast = step === "basics" && hasActiveProfileWithMeasurements && !!onUseActiveProfile;
9750
+ const handleClick = useProfileFast ? onUseActiveProfile : handleNext;
9751
+ const label = useProfileFast ? t("Find My Best Fit") : isLastStep ? t("Find My Size") : t("Next");
9752
+ return /* @__PURE__ */ jsxs("div", { className: "ps-bp-nav", children: [
9753
+ step !== "basics" ? /* @__PURE__ */ jsxs("button", { className: "ps-bp-back-btn", onClick: handleBackStep, type: "button", children: [
9754
+ /* @__PURE__ */ jsx("span", { className: "ps-bp-back-arrow", children: "←" }),
9755
+ " ",
9756
+ t("Back")
9757
+ ] }) : /* @__PURE__ */ jsx("span", {}),
9758
+ /* @__PURE__ */ jsx(
9759
+ "button",
9760
+ {
9761
+ className: `ps-bp-next-btn${!useProfileFast && !canProceed ? " ps-bp-btn-disabled" : ""}`,
9762
+ onClick: handleClick,
9763
+ disabled: !useProfileFast && !canProceed,
9764
+ type: "button",
9765
+ children: label
9766
+ }
9767
+ )
9768
+ ] });
9769
+ })()
9740
9770
  ] })
9741
9771
  ] }) });
9742
9772
  }
@@ -10013,6 +10043,26 @@ function PrimeStyleTryonInner({
10013
10043
  },
10014
10044
  [activeProfileId, profiles, apiUrl, productImage, productTitle, effectiveProductId, setActiveProfileId$1]
10015
10045
  );
10046
+ const handleUseActiveProfile = useCallback(() => {
10047
+ const p = profiles.find((x) => x.id === activeProfileId);
10048
+ if (!p || !p.measurements || Object.keys(p.measurements).length === 0) return;
10049
+ setSizingResult(null);
10050
+ setSizingLoading(true);
10051
+ setEstimationDone(true);
10052
+ setView("size-result");
10053
+ recommendForProduct({
10054
+ productId: effectiveProductId,
10055
+ productTitle,
10056
+ productImage,
10057
+ sizeGuideData,
10058
+ profile: p,
10059
+ apiUrl,
10060
+ skipCache: true
10061
+ }).then((res) => {
10062
+ if (res?.raw) setSizingResult(res.raw);
10063
+ }).catch(() => {
10064
+ }).finally(() => setSizingLoading(false));
10065
+ }, [profiles, activeProfileId, effectiveProductId, productTitle, productImage, sizeGuideData, apiUrl]);
10016
10066
  const applyProfileRef = useRef(() => {
10017
10067
  });
10018
10068
  const handleOpen = useCallback(() => {
@@ -10840,6 +10890,11 @@ function PrimeStyleTryonInner({
10840
10890
  setWeightUnit,
10841
10891
  sizingUnit,
10842
10892
  setSizingUnit,
10893
+ hasActiveProfileWithMeasurements: (() => {
10894
+ const p = profiles.find((x) => x.id === activeProfileId);
10895
+ return !!(p && p.measurements && Object.keys(p.measurements).length > 0);
10896
+ })(),
10897
+ onUseActiveProfile: handleUseActiveProfile,
10843
10898
  onComplete: (data) => {
10844
10899
  formRef.current.gender = data.gender;
10845
10900
  if (data.bandSize) formRef.current.bandSize = data.bandSize;
@@ -10956,6 +11011,10 @@ function PrimeStyleTryonInner({
10956
11011
  setActiveProfileId$1(id);
10957
11012
  setView("body-profile");
10958
11013
  },
11014
+ onSaveProfileMeasurements: (id, measurements) => {
11015
+ updateProfileMeasurements(id, measurements, profiles.find((x) => x.id === id)?.measurementsUnit || "cm");
11016
+ setProfiles(lsGet("profiles", []));
11017
+ },
10959
11018
  onEditProfile: (p) => {
10960
11019
  setProfileDetail(p);
10961
11020
  },