@primestyleai/tryon 5.8.44 → 5.8.46

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.
@@ -238,7 +238,8 @@ function computeMeasurements(lm, imageWidth, imageHeight) {
238
238
  return pxDist * pxToMm;
239
239
  };
240
240
  const pd = mmBetween(lm.leftIrisCenter, lm.rightIrisCenter);
241
- const bridgeWidth = mmBetween(lm.leftInnerEye, lm.rightInnerEye);
241
+ const innerEyeGap = mmBetween(lm.leftInnerEye, lm.rightInnerEye);
242
+ const bridgeWidth = innerEyeGap / 1.6;
242
243
  const faceWidth = mmBetween(lm.leftTragus, lm.rightTragus);
243
244
  const templeLengthLeft = mmBetween(lm.leftTragus, lm.leftOuterEye);
244
245
  const templeLengthRight = mmBetween(lm.rightTragus, lm.rightOuterEye);
@@ -7950,10 +7951,12 @@ const fitLabelFn = (fit, t) => fit === "good" ? t("perfect fit") : fit === "too-
7950
7951
  const lengthFitLabelFn = (fit, t) => fit === "good" ? t("perfect fit") : fit === "too-tight" ? t("too short") : fit === "tight" ? t("short") : fit === "a-bit-tight" ? t("a bit short") : fit === "too-loose" ? t("too long") : fit === "loose" ? t("long") : t("a bit long");
7951
7952
  function convertNum(n, from, to) {
7952
7953
  if (from === to || !n || isNaN(n)) return n;
7954
+ if (from === "mm" || to === "mm") return n;
7953
7955
  return from === "cm" ? Math.round(n / 2.54 * 10) / 10 : Math.round(n * 2.54 * 10) / 10;
7954
7956
  }
7955
7957
  function convertLabel(label, from, to) {
7956
7958
  if (from === to) return label;
7959
+ if (from === "mm" || to === "mm") return label;
7957
7960
  const conv = (n) => convertNum(n, from, to);
7958
7961
  const rangeMatch = label.match(/^(\d+\.?\d*)\s*[-–]\s*(\d+\.?\d*)$/);
7959
7962
  if (rangeMatch) return `${conv(parseFloat(rangeMatch[1]))}-${conv(parseFloat(rangeMatch[2]))}`;
@@ -7994,7 +7997,8 @@ function SectionDetailView({
7994
7997
  }) {
7995
7998
  const recSize = sectionResult?.recommendedSize || "";
7996
7999
  const [selectedSize, setSelectedSize] = useState(null);
7997
- const displayUnitId = unitLbl.toLowerCase().includes("cm") ? "cm" : "in";
8000
+ const unitLblLower = unitLbl.toLowerCase();
8001
+ const displayUnitId = unitLblLower.includes("mm") ? "mm" : unitLblLower.includes("cm") ? "cm" : "in";
7998
8002
  const fromUnit = chartUnit || displayUnitId;
7999
8003
  const dNum = (n) => convertNum(n, fromUnit, displayUnitId);
8000
8004
  const dLabel = (s) => convertLabel(s, fromUnit, displayUnitId);
@@ -8632,8 +8636,9 @@ function SizeResultView({
8632
8636
  userHeightCm,
8633
8637
  t
8634
8638
  }) {
8635
- const resultUnit = sizingResult?.unit || sizingUnit;
8636
- const unitLbl = sizingUnit === "cm" ? t("cm") : t("in");
8639
+ const resultUnitRaw = (sizingResult?.unit || sizingUnit || "").toString().toLowerCase();
8640
+ const resultUnit = resultUnitRaw === "mm" ? "mm" : resultUnitRaw === "cm" ? "cm" : "in";
8641
+ const unitLbl = resultUnit === "mm" ? t("mm") : sizingUnit === "cm" ? t("cm") : t("in");
8637
8642
  const [editVals, setEditVals] = useState({});
8638
8643
  const pRange = pRangeFn;
8639
8644
  const cellVal = useCallback((row, colIdx, header) => {
@@ -13422,6 +13427,69 @@ function PrimeStyleTryonInner({
13422
13427
  const method = methodOverride || sizingMethod;
13423
13428
  const baseUrl = getApiUrl(apiUrl);
13424
13429
  const key = getApiKey();
13430
+ const measurementType = detectMeasurementType(productTitle);
13431
+ if (measurementType === "face" || measurementType === "head") {
13432
+ const f = formRef.current;
13433
+ const toNum = (v) => {
13434
+ if (!v) return void 0;
13435
+ const n = parseFloat(v);
13436
+ return Number.isFinite(n) && n > 0 ? n : void 0;
13437
+ };
13438
+ const inputUnit = f.sizingUnit || sizingUnit || (measurementType === "head" ? "cm" : "mm");
13439
+ const toMm = (n) => {
13440
+ if (n == null) return void 0;
13441
+ if (inputUnit === "mm") return n;
13442
+ if (inputUnit === "cm") return n * 10;
13443
+ if (inputUnit === "in") return n * 25.4;
13444
+ return n;
13445
+ };
13446
+ const faceMm = {};
13447
+ const src = {
13448
+ bridgeWidth: toMm(toNum(f.bridgeWidth)),
13449
+ templeLength: toMm(toNum(f.templeLength) ?? toNum(f.armLength)),
13450
+ lensWidth: toMm(toNum(f.lensWidth)),
13451
+ lensHeight: toMm(toNum(f.lensHeight)),
13452
+ faceWidth: toMm(toNum(f.faceWidth) ?? toNum(f.frameWidth)),
13453
+ pd: toMm(toNum(f.pd)),
13454
+ // Headwear — circumference usually typed in cm; keep as mm internally.
13455
+ headCircumference: toMm(toNum(f.headCircumference)),
13456
+ headWidth: toMm(toNum(f.headWidth))
13457
+ };
13458
+ for (const [k, v] of Object.entries(src)) if (typeof v === "number") faceMm[k] = v;
13459
+ const facePayload = {
13460
+ product: { title: productTitle, productId },
13461
+ sizeGuide: sizeGuide?.found ? sizeGuide : { found: false },
13462
+ sizingUnit: measurementType === "head" ? "cm" : "mm",
13463
+ category: measurementType,
13464
+ ...Object.keys(faceMm).length > 0 && { faceMeasurementsMm: faceMm, irisConfidence: 1 }
13465
+ };
13466
+ try {
13467
+ const resp = await fetch(`${baseUrl}/api/v1/sizing/face-recommend`, {
13468
+ method: "POST",
13469
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${key}` },
13470
+ body: JSON.stringify(facePayload)
13471
+ });
13472
+ if (resp.ok) {
13473
+ const data = await resp.json();
13474
+ setSizingResult(data);
13475
+ onComplete?.(data);
13476
+ } else {
13477
+ const body = await resp.text().catch(() => "");
13478
+ console.error("[PS-SDK] face-recommend failed:", resp.status, body);
13479
+ setErrorMessage(t("Unable to get size recommendation. Please try again."));
13480
+ setView("error");
13481
+ setEstimationDone(true);
13482
+ }
13483
+ } catch (err) {
13484
+ console.error("[PS-SDK] face-recommend network error:", err);
13485
+ setErrorMessage(t("Unable to connect to sizing service. Please try again."));
13486
+ setView("error");
13487
+ setEstimationDone(true);
13488
+ } finally {
13489
+ setSizingLoading(false);
13490
+ }
13491
+ return;
13492
+ }
13425
13493
  const payload = {
13426
13494
  method,
13427
13495
  locale: sizingCountry,
@@ -9700,7 +9700,8 @@ function computeMeasurements(lm, imageWidth, imageHeight) {
9700
9700
  return pxDist * pxToMm;
9701
9701
  };
9702
9702
  const pd2 = mmBetween(lm.leftIrisCenter, lm.rightIrisCenter);
9703
- const bridgeWidth = mmBetween(lm.leftInnerEye, lm.rightInnerEye);
9703
+ const innerEyeGap = mmBetween(lm.leftInnerEye, lm.rightInnerEye);
9704
+ const bridgeWidth = innerEyeGap / 1.6;
9704
9705
  const faceWidth = mmBetween(lm.leftTragus, lm.rightTragus);
9705
9706
  const templeLengthLeft = mmBetween(lm.leftTragus, lm.leftOuterEye);
9706
9707
  const templeLengthRight = mmBetween(lm.rightTragus, lm.rightOuterEye);
@@ -17374,10 +17375,12 @@ const fitLabelFn = (fit, t2) => fit === "good" ? t2("perfect fit") : fit === "to
17374
17375
  const lengthFitLabelFn = (fit, t2) => fit === "good" ? t2("perfect fit") : fit === "too-tight" ? t2("too short") : fit === "tight" ? t2("short") : fit === "a-bit-tight" ? t2("a bit short") : fit === "too-loose" ? t2("too long") : fit === "loose" ? t2("long") : t2("a bit long");
17375
17376
  function convertNum(n2, from, to) {
17376
17377
  if (from === to || !n2 || isNaN(n2)) return n2;
17378
+ if (from === "mm" || to === "mm") return n2;
17377
17379
  return from === "cm" ? Math.round(n2 / 2.54 * 10) / 10 : Math.round(n2 * 2.54 * 10) / 10;
17378
17380
  }
17379
17381
  function convertLabel(label, from, to) {
17380
17382
  if (from === to) return label;
17383
+ if (from === "mm" || to === "mm") return label;
17381
17384
  const conv = (n2) => convertNum(n2, from, to);
17382
17385
  const rangeMatch = label.match(/^(\d+\.?\d*)\s*[-–]\s*(\d+\.?\d*)$/);
17383
17386
  if (rangeMatch) return `${conv(parseFloat(rangeMatch[1]))}-${conv(parseFloat(rangeMatch[2]))}`;
@@ -17418,7 +17421,8 @@ function SectionDetailView({
17418
17421
  }) {
17419
17422
  const recSize = sectionResult?.recommendedSize || "";
17420
17423
  const [selectedSize, setSelectedSize] = reactExports.useState(null);
17421
- const displayUnitId = unitLbl.toLowerCase().includes("cm") ? "cm" : "in";
17424
+ const unitLblLower = unitLbl.toLowerCase();
17425
+ const displayUnitId = unitLblLower.includes("mm") ? "mm" : unitLblLower.includes("cm") ? "cm" : "in";
17422
17426
  const fromUnit = chartUnit || displayUnitId;
17423
17427
  const dNum = (n2) => convertNum(n2, fromUnit, displayUnitId);
17424
17428
  const dLabel = (s) => convertLabel(s, fromUnit, displayUnitId);
@@ -18056,8 +18060,9 @@ function SizeResultView({
18056
18060
  userHeightCm,
18057
18061
  t: t2
18058
18062
  }) {
18059
- const resultUnit = sizingResult?.unit || sizingUnit;
18060
- const unitLbl = sizingUnit === "cm" ? t2("cm") : t2("in");
18063
+ const resultUnitRaw = (sizingResult?.unit || sizingUnit || "").toString().toLowerCase();
18064
+ const resultUnit = resultUnitRaw === "mm" ? "mm" : resultUnitRaw === "cm" ? "cm" : "in";
18065
+ const unitLbl = resultUnit === "mm" ? t2("mm") : sizingUnit === "cm" ? t2("cm") : t2("in");
18061
18066
  const [editVals, setEditVals] = reactExports.useState({});
18062
18067
  const pRange = pRangeFn;
18063
18068
  const cellVal = reactExports.useCallback((row, colIdx, header) => {
@@ -22846,6 +22851,69 @@ function PrimeStyleTryonInner({
22846
22851
  const method = methodOverride || sizingMethod;
22847
22852
  const baseUrl = getApiUrl(apiUrl);
22848
22853
  const key = getApiKey();
22854
+ const measurementType = detectMeasurementType(productTitle);
22855
+ if (measurementType === "face" || measurementType === "head") {
22856
+ const f2 = formRef.current;
22857
+ const toNum = (v2) => {
22858
+ if (!v2) return void 0;
22859
+ const n2 = parseFloat(v2);
22860
+ return Number.isFinite(n2) && n2 > 0 ? n2 : void 0;
22861
+ };
22862
+ const inputUnit = f2.sizingUnit || sizingUnit || (measurementType === "head" ? "cm" : "mm");
22863
+ const toMm = (n2) => {
22864
+ if (n2 == null) return void 0;
22865
+ if (inputUnit === "mm") return n2;
22866
+ if (inputUnit === "cm") return n2 * 10;
22867
+ if (inputUnit === "in") return n2 * 25.4;
22868
+ return n2;
22869
+ };
22870
+ const faceMm = {};
22871
+ const src = {
22872
+ bridgeWidth: toMm(toNum(f2.bridgeWidth)),
22873
+ templeLength: toMm(toNum(f2.templeLength) ?? toNum(f2.armLength)),
22874
+ lensWidth: toMm(toNum(f2.lensWidth)),
22875
+ lensHeight: toMm(toNum(f2.lensHeight)),
22876
+ faceWidth: toMm(toNum(f2.faceWidth) ?? toNum(f2.frameWidth)),
22877
+ pd: toMm(toNum(f2.pd)),
22878
+ // Headwear — circumference usually typed in cm; keep as mm internally.
22879
+ headCircumference: toMm(toNum(f2.headCircumference)),
22880
+ headWidth: toMm(toNum(f2.headWidth))
22881
+ };
22882
+ for (const [k2, v2] of Object.entries(src)) if (typeof v2 === "number") faceMm[k2] = v2;
22883
+ const facePayload = {
22884
+ product: { title: productTitle, productId },
22885
+ sizeGuide: sizeGuide?.found ? sizeGuide : { found: false },
22886
+ sizingUnit: measurementType === "head" ? "cm" : "mm",
22887
+ category: measurementType,
22888
+ ...Object.keys(faceMm).length > 0 && { faceMeasurementsMm: faceMm, irisConfidence: 1 }
22889
+ };
22890
+ try {
22891
+ const resp = await fetch(`${baseUrl}/api/v1/sizing/face-recommend`, {
22892
+ method: "POST",
22893
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${key}` },
22894
+ body: JSON.stringify(facePayload)
22895
+ });
22896
+ if (resp.ok) {
22897
+ const data = await resp.json();
22898
+ setSizingResult(data);
22899
+ onComplete?.(data);
22900
+ } else {
22901
+ const body = await resp.text().catch(() => "");
22902
+ console.error("[PS-SDK] face-recommend failed:", resp.status, body);
22903
+ setErrorMessage(t2("Unable to get size recommendation. Please try again."));
22904
+ setView("error");
22905
+ setEstimationDone(true);
22906
+ }
22907
+ } catch (err) {
22908
+ console.error("[PS-SDK] face-recommend network error:", err);
22909
+ setErrorMessage(t2("Unable to connect to sizing service. Please try again."));
22910
+ setView("error");
22911
+ setEstimationDone(true);
22912
+ } finally {
22913
+ setSizingLoading(false);
22914
+ }
22915
+ return;
22916
+ }
22849
22917
  const payload = {
22850
22918
  method,
22851
22919
  locale: sizingCountry,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primestyleai/tryon",
3
- "version": "5.8.44",
3
+ "version": "5.8.46",
4
4
  "description": "PrimeStyle Virtual Try-On SDK — React component & Web Component",
5
5
  "type": "module",
6
6
  "main": "dist/primestyle-tryon.js",