@primestyleai/tryon 5.10.122 → 5.10.124

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.
@@ -116,6 +116,11 @@ export interface HistoryEntry {
116
116
  * IndexedDB rather than in this localStorage object to avoid the ~5–10 MB
117
117
  * quota. Old entries without a photo set this false/undefined. */
118
118
  hasPhoto?: boolean;
119
+ /** True when the try-on RESULT image is stored as a Blob in IndexedDB
120
+ * (key = `result-<entry.id>`). Restored as an object URL on history
121
+ * click so the result survives even if the original URL (Cloudinary
122
+ * / data:) expired or was lost. */
123
+ hasResult?: boolean;
119
124
  /** What the user actually selected when they ran the try-on (per section). */
120
125
  selectedSizes?: Array<{
121
126
  sectionName: string;
@@ -15,5 +15,11 @@ export declare function savePhoto(id: string, blob: Blob): Promise<boolean>;
15
15
  export declare function getPhoto(id: string): Promise<Blob | null>;
16
16
  /** Delete a photo by historyEntryId. */
17
17
  export declare function deletePhoto(id: string): Promise<boolean>;
18
- /** Garbage-collect: keep only photos whose id is in `keepIds`. */
18
+ /** Save a try-on result Blob keyed by historyEntryId. Replaces if exists. */
19
+ export declare function saveResult(id: string, blob: Blob): Promise<boolean>;
20
+ /** Load a try-on result Blob by historyEntryId, or null if not stored. */
21
+ export declare function getResult(id: string): Promise<Blob | null>;
22
+ /** Garbage-collect: keep only photos (and results) whose id is in `keepIds`.
23
+ * Uses a value cursor (openCursor) so records can be deleted during
24
+ * iteration — openKeyCursor's cursor.delete() throws InvalidStateError. */
19
25
  export declare function pruneToIds(keepIds: Set<string>): Promise<void>;
@@ -9624,6 +9624,7 @@ function openDb() {
9624
9624
  });
9625
9625
  return _dbPromise;
9626
9626
  }
9627
+ const RESULT_PREFIX = "result-";
9627
9628
  async function savePhoto(id2, blob) {
9628
9629
  const db2 = await openDb();
9629
9630
  if (!db2) return false;
@@ -9653,19 +9654,30 @@ async function getPhoto(id2) {
9653
9654
  }
9654
9655
  });
9655
9656
  }
9657
+ async function saveResult(id2, blob) {
9658
+ return savePhoto(RESULT_PREFIX + id2, blob);
9659
+ }
9660
+ async function getResult(id2) {
9661
+ return getPhoto(RESULT_PREFIX + id2);
9662
+ }
9656
9663
  async function pruneToIds(keepIds) {
9657
9664
  const db2 = await openDb();
9658
9665
  if (!db2) return;
9666
+ const expected = /* @__PURE__ */ new Set();
9667
+ for (const id2 of keepIds) {
9668
+ expected.add(id2);
9669
+ expected.add(RESULT_PREFIX + id2);
9670
+ }
9659
9671
  return new Promise((resolve) => {
9660
9672
  try {
9661
9673
  const tx = db2.transaction(STORE, "readwrite");
9662
9674
  const store = tx.objectStore(STORE);
9663
- const cursorReq = store.openKeyCursor();
9675
+ const cursorReq = store.openCursor();
9664
9676
  cursorReq.onsuccess = () => {
9665
9677
  const cursor = cursorReq.result;
9666
9678
  if (!cursor) return;
9667
9679
  const key = String(cursor.key);
9668
- if (!keepIds.has(key)) cursor.delete();
9680
+ if (!expected.has(key)) cursor.delete();
9669
9681
  cursor.continue();
9670
9682
  };
9671
9683
  tx.oncomplete = () => resolve();
@@ -20101,10 +20113,15 @@ function SectionDetailView({
20101
20113
  if (!details.length) return [];
20102
20114
  const isFromLength = new Set(lengthDetails.map((m2) => m2.measurement));
20103
20115
  if (hasLengthSource) isFromLength.add("Height");
20116
+ const activeLengthLabel = selectedLength || effectiveRecLength;
20104
20117
  return details.map((m2) => {
20105
20118
  if (isFromLength.has(m2.measurement)) {
20106
20119
  const userNum2 = userMeasurements[m2.measurement.toLowerCase()] || pNumFn(m2.userValue);
20107
- const lookup2 = allSizes?.[displaySize]?.[m2.measurement];
20120
+ const lengthAllSizes = lengthEntry?.secResult?.allSizes;
20121
+ const lookupByLengthEntry = activeLengthLabel ? lengthAllSizes?.[activeLengthLabel]?.[m2.measurement] : void 0;
20122
+ const lookupByLength = activeLengthLabel ? allSizes?.[activeLengthLabel]?.[m2.measurement] : void 0;
20123
+ const lookupBySize = allSizes?.[displaySize]?.[m2.measurement];
20124
+ const lookup2 = lookupByLengthEntry ?? lookupByLength ?? lookupBySize;
20108
20125
  const chartRange2 = lookup2?.chartRange ?? m2.chartRange;
20109
20126
  const fit2 = lookup2?.fit ?? m2.fit ?? "good";
20110
20127
  return {
@@ -20129,7 +20146,7 @@ function SectionDetailView({
20129
20146
  isLength: isDirectional
20130
20147
  };
20131
20148
  });
20132
- }, [sectionResult, lengthEntry, userMeasurements, renderRaw, allSizes, displaySize]);
20149
+ }, [sectionResult, lengthEntry, userMeasurements, renderRaw, allSizes, displaySize, selectedLength]);
20133
20150
  const goodCount = fitRows.filter(
20134
20151
  (r2) => r2.fit === "good" || r2.fit === "a-bit-tight" || r2.fit === "a-bit-loose"
20135
20152
  ).length;
@@ -21145,14 +21162,19 @@ function SizeResultView({
21145
21162
  })(),
21146
21163
  onBack: () => setActiveSection(null),
21147
21164
  internationalSizes: entry.secResult?.internationalSizes,
21148
- productImage: resultImageUrl || productImage,
21165
+ productImage: tryOnProcessing && previewUrl ? previewUrl : resultImageUrl || productImage,
21149
21166
  productTitle,
21150
21167
  isMobile: true,
21151
- isTryOnImage: !!resultImageUrl,
21168
+ isTryOnImage: !!resultImageUrl && !tryOnProcessing,
21169
+ tryOnProcessing,
21170
+ tryOnStartedAt,
21152
21171
  showLines,
21153
21172
  onToggleLines: isAccessory ? void 0 : () => setShowLines(!showLines),
21154
21173
  onImageLoad: handleImgLoad,
21155
- overlayNode: resultImageUrl && poseReady && poseLines ? /* @__PURE__ */ jsxRuntimeExports.jsx(
21174
+ overlayNode: tryOnProcessing ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
21175
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt: tryOnStartedAt ?? null, t: t2 }),
21176
+ /* @__PURE__ */ jsxRuntimeExports.jsx(RegenScanOverlay, { active: true })
21177
+ ] }) : resultImageUrl && poseReady && poseLines ? /* @__PURE__ */ jsxRuntimeExports.jsx(
21156
21178
  MeasurementOverlay,
21157
21179
  {
21158
21180
  lines: poseLines,
@@ -21183,7 +21205,19 @@ function SizeResultView({
21183
21205
  ] });
21184
21206
  }
21185
21207
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2", children: [
21186
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-v2-bg", style: { position: "relative" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: resultImageUrl || productImage, alt: productTitle, className: "ps-tryon-v2-bg-img" }) }),
21208
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-bg", style: { position: "relative" }, children: [
21209
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
21210
+ "img",
21211
+ {
21212
+ src: tryOnProcessing && previewUrl ? previewUrl : resultImageUrl || productImage,
21213
+ alt: productTitle,
21214
+ className: "ps-tryon-v2-bg-img",
21215
+ onLoad: handleImgLoad
21216
+ }
21217
+ ),
21218
+ tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt: tryOnStartedAt ?? null, t: t2 }),
21219
+ /* @__PURE__ */ jsxRuntimeExports.jsx(RegenScanOverlay, { active: !!tryOnProcessing })
21220
+ ] }),
21187
21221
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-panel", children: [
21188
21222
  mismatchNotice,
21189
21223
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -21205,6 +21239,8 @@ function SizeResultView({
21205
21239
  })(),
21206
21240
  onBack: () => setActiveSection(null),
21207
21241
  internationalSizes: entry.secResult?.internationalSizes,
21242
+ tryOnProcessing,
21243
+ tryOnStartedAt,
21208
21244
  t: t2,
21209
21245
  allSizes: entry.secResult?.allSizes ?? sizingResult?.allSizes
21210
21246
  }
@@ -26775,7 +26811,7 @@ function CameraUploadIcon() {
26775
26811
  function AccessorySizeView({
26776
26812
  title,
26777
26813
  fields,
26778
- unitOptions = [{ label: "Centimeters", value: "cm" }, { label: "Inches", value: "in" }],
26814
+ unitOptions,
26779
26815
  photoVariant = "full-body",
26780
26816
  disablePhotoUpload = false,
26781
26817
  productImage,
@@ -26803,6 +26839,10 @@ function AccessorySizeView({
26803
26839
  });
26804
26840
  return init;
26805
26841
  });
26842
+ const resolvedUnitOptions = unitOptions ?? [
26843
+ { label: t2("Centimeters"), value: "cm" },
26844
+ { label: t2("Inches"), value: "in" }
26845
+ ];
26806
26846
  const [error, setError] = reactExports.useState("");
26807
26847
  const fileInputRef = reactExports.useRef(null);
26808
26848
  const [photoPreview, setPhotoPreview] = reactExports.useState(null);
@@ -26889,7 +26929,7 @@ function AccessorySizeView({
26889
26929
  gender: formRef.current.gender || "male"
26890
26930
  });
26891
26931
  };
26892
- const activeUnitLabel = unitOptions.find((o) => o.value === sizingUnit)?.label || unitOptions[0].label;
26932
+ const activeUnitLabel = resolvedUnitOptions.find((o) => o.value === sizingUnit)?.label || resolvedUnitOptions[0].label;
26893
26933
  if (isMobile && step === "photo") {
26894
26934
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-wrapper", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
26895
26935
  PhotoStepMobile,
@@ -26913,7 +26953,7 @@ function AccessorySizeView({
26913
26953
  if (isMobile) {
26914
26954
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-wrapper", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bpm-root", children: [
26915
26955
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bpm-header", children: /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "ps-bpm-title", children: t2(title) }) }),
26916
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bpm-toggle", style: { padding: "0 4%" }, children: unitOptions.map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx(
26956
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bpm-toggle", style: { padding: "0 4%" }, children: resolvedUnitOptions.map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx(
26917
26957
  "button",
26918
26958
  {
26919
26959
  type: "button",
@@ -26985,7 +27025,7 @@ function AccessorySizeView({
26985
27025
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-image", style: { position: "relative" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: productImage, alt: productTitle, className: "ps-bp-image-img" }) }),
26986
27026
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-root", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-step ps-bp-step-enter", children: [
26987
27027
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: "0.6vw", marginBottom: "0.3vw" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "ps-bp-title", style: { margin: 0 }, children: t2(title) }) }),
26988
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-system-toggle", children: unitOptions.map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx(
27028
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-system-toggle", children: resolvedUnitOptions.map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx(
26989
27029
  "button",
26990
27030
  {
26991
27031
  type: "button",
@@ -27352,7 +27392,7 @@ function AccessorySizeView({
27352
27392
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { style: { margin: "0.2vw 0 0", fontSize: "0.65vw", color: "var(--ps-text-muted)" }, children: t2("Enter your measurements OR upload a photo — we'll use whichever you provide.") })
27353
27393
  ] }),
27354
27394
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.7vw" }, children: [
27355
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-system-toggle", style: { alignSelf: "center" }, children: unitOptions.map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx(
27395
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-system-toggle", style: { alignSelf: "center" }, children: resolvedUnitOptions.map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx(
27356
27396
  "button",
27357
27397
  {
27358
27398
  type: "button",
@@ -27525,130 +27565,141 @@ function AccessorySizeView({
27525
27565
  ] })
27526
27566
  ] }) }) });
27527
27567
  }
27528
- const FALLBACK_FOOT_FIELDS = [
27529
- {
27530
- key: "footLengthCm",
27531
- label: "Foot Length",
27532
- placeholder: { cm: "e.g. 26.5", in: "e.g. 10.5" },
27533
- hint: "Measure from heel to longest toe",
27534
- min: 10,
27535
- max: 35,
27536
- step: 0.5
27537
- }
27538
- ];
27539
- function buildFieldsFromSizeGuide$2(sizeGuide) {
27568
+ function buildFallbackFootFields(t2) {
27569
+ return [
27570
+ {
27571
+ key: "footLengthCm",
27572
+ label: t2("Foot Length"),
27573
+ placeholder: { cm: "e.g. 26.5", in: "e.g. 10.5" },
27574
+ hint: t2("Measure from heel to longest toe"),
27575
+ min: 10,
27576
+ max: 35,
27577
+ step: 0.5
27578
+ }
27579
+ ];
27580
+ }
27581
+ function buildFieldsFromSizeGuide$2(sizeGuide, t2) {
27582
+ const fallback = buildFallbackFootFields(t2);
27540
27583
  const req = sizeGuide?.requiredFields;
27541
- if (!req || req.length === 0) return FALLBACK_FOOT_FIELDS;
27584
+ if (!req || req.length === 0) return fallback;
27542
27585
  const SIZE_CODE_KEYS = /* @__PURE__ */ new Set(["size", "country", "eu", "__skip__", "shoeEU", "shoeUS", "shoeUK", "shoeJP"]);
27543
27586
  const defaultPlaceholderFor = (key, label) => {
27544
- const exact = FALLBACK_FOOT_FIELDS.find((f2) => f2.key === key);
27587
+ const exact = fallback.find((f2) => f2.key === key);
27545
27588
  if (exact) return exact.placeholder;
27546
27589
  const looksLikeFoot = /foot|length/i.test(key) || /foot|length/i.test(label);
27547
- if (looksLikeFoot) return FALLBACK_FOOT_FIELDS[0].placeholder;
27590
+ if (looksLikeFoot) return fallback[0].placeholder;
27548
27591
  return { cm: "", in: "" };
27549
27592
  };
27550
27593
  const out = req.filter((f2) => !SIZE_CODE_KEYS.has(f2.key) && f2.unit !== "size").map((f2) => {
27551
- const fallback = defaultPlaceholderFor(f2.key, f2.label || "");
27594
+ const ph2 = defaultPlaceholderFor(f2.key, f2.label || "");
27552
27595
  return {
27553
27596
  key: f2.key,
27554
- label: f2.label || f2.key,
27597
+ label: t2(f2.label || f2.key),
27555
27598
  placeholder: {
27556
- cm: f2.placeholder || fallback.cm,
27557
- in: f2.placeholder || fallback.in
27599
+ cm: f2.placeholder || ph2.cm,
27600
+ in: f2.placeholder || ph2.in
27558
27601
  },
27559
27602
  min: 0,
27560
27603
  step: 0.5
27561
27604
  };
27562
27605
  });
27563
- return out.length > 0 ? out : FALLBACK_FOOT_FIELDS;
27606
+ return out.length > 0 ? out : fallback;
27564
27607
  }
27565
27608
  function FootSizeView(props) {
27566
- const { sizeGuide, ...rest } = props;
27567
- const fields = buildFieldsFromSizeGuide$2(sizeGuide);
27609
+ const { sizeGuide, t: t2, ...rest } = props;
27610
+ const fields = buildFieldsFromSizeGuide$2(sizeGuide, t2);
27568
27611
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
27569
27612
  AccessorySizeView,
27570
27613
  {
27571
- title: "Shoe Size",
27614
+ title: t2("Shoe Size"),
27572
27615
  fields,
27573
27616
  disablePhotoUpload: true,
27617
+ t: t2,
27574
27618
  ...rest
27575
27619
  }
27576
27620
  );
27577
27621
  }
27578
- const FALLBACK_HEAD_FIELDS = [
27579
- {
27580
- key: "headCircumference",
27581
- label: "Head Circumference",
27582
- placeholder: { cm: "e.g. 57", in: "e.g. 22.5" },
27583
- hint: "Wrap a tape around the widest part of your head",
27584
- min: 48,
27585
- max: 65,
27586
- step: 0.5
27587
- }
27588
- ];
27589
- function buildFieldsFromSizeGuide$1(sizeGuide) {
27622
+ function buildFallbackHeadFields(t2) {
27623
+ return [
27624
+ {
27625
+ key: "headCircumference",
27626
+ label: t2("Head Circumference"),
27627
+ placeholder: { cm: "e.g. 57", in: "e.g. 22.5" },
27628
+ hint: t2("Wrap a tape around the widest part of your head"),
27629
+ min: 48,
27630
+ max: 65,
27631
+ step: 0.5
27632
+ }
27633
+ ];
27634
+ }
27635
+ function buildFieldsFromSizeGuide$1(sizeGuide, t2) {
27590
27636
  const req = sizeGuide?.requiredFields;
27591
- if (!req || req.length === 0) return FALLBACK_HEAD_FIELDS;
27637
+ if (!req || req.length === 0) return buildFallbackHeadFields(t2);
27592
27638
  const SIZE_CODE_KEYS = /* @__PURE__ */ new Set(["size", "country", "eu", "__skip__"]);
27593
27639
  return req.filter((f2) => !SIZE_CODE_KEYS.has(f2.key) && f2.unit !== "size").map((f2) => ({
27594
27640
  key: f2.key,
27595
- label: f2.label || f2.key,
27641
+ label: t2(f2.label || f2.key),
27596
27642
  placeholder: { cm: f2.placeholder || "", in: f2.placeholder || "" },
27597
27643
  min: 0,
27598
27644
  step: 0.5
27599
27645
  }));
27600
27646
  }
27601
27647
  function HeadSizeView(props) {
27602
- const { sizeGuide, ...rest } = props;
27603
- const fields = buildFieldsFromSizeGuide$1(sizeGuide);
27648
+ const { sizeGuide, t: t2, ...rest } = props;
27649
+ const fields = buildFieldsFromSizeGuide$1(sizeGuide, t2);
27604
27650
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
27605
27651
  AccessorySizeView,
27606
27652
  {
27607
- title: "Headwear Measurements",
27653
+ title: t2("Headwear Measurements"),
27608
27654
  fields,
27609
27655
  photoVariant: "close-up",
27656
+ t: t2,
27610
27657
  ...rest
27611
27658
  }
27612
27659
  );
27613
27660
  }
27614
- const FALLBACK_FACE_FIELDS = [
27615
- {
27616
- key: "lensWidth",
27617
- label: "Lens Width",
27618
- // `cm` key = mm placeholder (default eyewear unit); `in` key = cm placeholder.
27619
- placeholder: { mm: "e.g. 52", cm: "e.g. 5.2" },
27620
- hint: "Width of one lens",
27621
- min: 0,
27622
- step: 1
27623
- },
27624
- {
27625
- key: "bridgeWidth",
27626
- label: "Bridge",
27627
- placeholder: { mm: "e.g. 18", cm: "e.g. 1.8" },
27628
- hint: "Distance over the nose between lenses",
27629
- min: 0,
27630
- step: 1
27631
- },
27632
- {
27633
- key: "templeLength",
27634
- label: "Arm Length",
27635
- placeholder: { mm: "e.g. 140", cm: "e.g. 14" },
27636
- hint: "Length of the arm from hinge to tip",
27637
- min: 0,
27638
- step: 1
27639
- }
27640
- ];
27641
- const EYEWEAR_UNIT_OPTIONS = [
27642
- { label: "Millimetre", value: "mm" },
27643
- { label: "Centimetre", value: "cm" }
27644
- ];
27645
- function buildFieldsFromSizeGuide(sizeGuide) {
27661
+ function buildFallbackFaceFields(t2) {
27662
+ return [
27663
+ {
27664
+ key: "lensWidth",
27665
+ label: t2("Lens Width"),
27666
+ // `cm` key = mm placeholder (default eyewear unit); `in` key = cm placeholder.
27667
+ placeholder: { mm: "e.g. 52", cm: "e.g. 5.2" },
27668
+ hint: t2("Width of one lens"),
27669
+ min: 0,
27670
+ step: 1
27671
+ },
27672
+ {
27673
+ key: "bridgeWidth",
27674
+ label: t2("Bridge"),
27675
+ placeholder: { mm: "e.g. 18", cm: "e.g. 1.8" },
27676
+ hint: t2("Distance over the nose between lenses"),
27677
+ min: 0,
27678
+ step: 1
27679
+ },
27680
+ {
27681
+ key: "templeLength",
27682
+ label: t2("Arm Length"),
27683
+ placeholder: { mm: "e.g. 140", cm: "e.g. 14" },
27684
+ hint: t2("Length of the arm from hinge to tip"),
27685
+ min: 0,
27686
+ step: 1
27687
+ }
27688
+ ];
27689
+ }
27690
+ function buildEyewearUnitOptions(t2) {
27691
+ return [
27692
+ { label: t2("Millimetre"), value: "mm" },
27693
+ { label: t2("Centimetre"), value: "cm" }
27694
+ ];
27695
+ }
27696
+ function buildFieldsFromSizeGuide(sizeGuide, t2) {
27646
27697
  const req = sizeGuide?.requiredFields;
27647
- if (!req || req.length === 0) return FALLBACK_FACE_FIELDS;
27698
+ if (!req || req.length === 0) return buildFallbackFaceFields(t2);
27648
27699
  const SIZE_CODE_KEYS = /* @__PURE__ */ new Set(["size", "country", "eu", "__skip__"]);
27649
27700
  return req.filter((f2) => !SIZE_CODE_KEYS.has(f2.key) && f2.unit !== "size").map((f2) => ({
27650
27701
  key: f2.key,
27651
- label: f2.label || f2.key,
27702
+ label: t2(f2.label || f2.key),
27652
27703
  placeholder: {
27653
27704
  cm: f2.placeholder || "",
27654
27705
  in: f2.placeholder || ""
@@ -27658,15 +27709,16 @@ function buildFieldsFromSizeGuide(sizeGuide) {
27658
27709
  }));
27659
27710
  }
27660
27711
  function FaceSizeView(props) {
27661
- const { sizeGuide, ...rest } = props;
27662
- const fields = buildFieldsFromSizeGuide(sizeGuide);
27712
+ const { sizeGuide, t: t2, ...rest } = props;
27713
+ const fields = buildFieldsFromSizeGuide(sizeGuide, t2);
27663
27714
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
27664
27715
  AccessorySizeView,
27665
27716
  {
27666
- title: "Frame Measurements",
27717
+ title: t2("Frame Measurements"),
27667
27718
  fields,
27668
- unitOptions: EYEWEAR_UNIT_OPTIONS,
27719
+ unitOptions: buildEyewearUnitOptions(t2),
27669
27720
  photoVariant: "close-up",
27721
+ t: t2,
27670
27722
  ...rest
27671
27723
  }
27672
27724
  );
@@ -29201,15 +29253,30 @@ function PrimeStyleTryonInner({
29201
29253
  displayLabel: o.displayLabel,
29202
29254
  isOverride: !!recommended && o.selectedSize !== recommended
29203
29255
  }));
29256
+ let entryId = null;
29204
29257
  setHistory((prev) => {
29205
29258
  if (prev.length === 0) return prev;
29259
+ entryId = prev[0].id;
29206
29260
  const updated = {
29207
29261
  ...prev[0],
29208
29262
  resultImageUrl,
29263
+ hasResult: true,
29209
29264
  ...selectedSizes.length ? { selectedSizes } : {}
29210
29265
  };
29211
29266
  return [updated, ...prev.slice(1)];
29212
29267
  });
29268
+ if (entryId) {
29269
+ const id2 = entryId;
29270
+ void (async () => {
29271
+ try {
29272
+ const res = await fetch(resultImageUrl);
29273
+ if (!res.ok) return;
29274
+ const blob = await res.blob();
29275
+ await saveResult(id2, blob);
29276
+ } catch {
29277
+ }
29278
+ })();
29279
+ }
29213
29280
  } else if (view === "result" && resultImageUrl && !historySavedRef.current) {
29214
29281
  historySavedRef.current = true;
29215
29282
  saveHistoryEntry().catch(() => {
@@ -29239,6 +29306,13 @@ function PrimeStyleTryonInner({
29239
29306
  setSizeGuideFetching(false);
29240
29307
  }
29241
29308
  setResultImageUrl(entry.resultImageUrl || null);
29309
+ if (entry.hasResult || entry.resultImageUrl) {
29310
+ void getResult(entry.id).then((blob) => {
29311
+ if (!blob) return;
29312
+ const url = URL.createObjectURL(blob);
29313
+ setResultImageUrl(url);
29314
+ });
29315
+ }
29242
29316
  if (entry.hasPhoto) {
29243
29317
  void getPhoto(entry.id).then((blob) => {
29244
29318
  if (!blob) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primestyleai/tryon",
3
- "version": "5.10.122",
3
+ "version": "5.10.124",
4
4
  "description": "PrimeStyle Virtual Try-On SDK — React component & Web Component",
5
5
  "type": "module",
6
6
  "main": "dist/primestyle-tryon.js",