@primestyleai/tryon 4.1.2 → 4.2.0

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.
@@ -314,6 +314,8 @@ const en = {
314
314
  "Edit values": "Edit values",
315
315
  "Based on your updated measurements, size": "Based on your updated measurements, size",
316
316
  "may be a better fit": "may be a better fit",
317
+ "Updated to": "Updated to",
318
+ "Your Measurements": "Your Measurements",
317
319
  "Fit Analysis": "Fit Analysis",
318
320
  "Show more": "Show more",
319
321
  "Done": "Done",
@@ -1,5 +1,5 @@
1
- import { c as createT, A as ApiClient, S as SseClient, i as isValidImageFile, a as compressImage } from "./index-aIBOmApE.js";
2
- import { P, b, T, d, r } from "./index-aIBOmApE.js";
1
+ import { c as createT, A as ApiClient, S as SseClient, i as isValidImageFile, a as compressImage } from "./index-CILUifQv.js";
2
+ import { P, b, T, d, r } from "./index-CILUifQv.js";
3
3
  function detectProductImage() {
4
4
  const ogImage = document.querySelector(
5
5
  'meta[property="og:image"]'
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
3
3
  import { useState, useEffect, useMemo, useRef, useCallback } from "react";
4
- import { c as createT, A as ApiClient, S as SseClient, i as isValidImageFile, a as compressImage, P as PrimeStyleError, L as LOCALE_LABELS, b as SUPPORTED_LOCALES } from "../index-aIBOmApE.js";
4
+ import { c as createT, A as ApiClient, S as SseClient, i as isValidImageFile, a as compressImage, P as PrimeStyleError, L as LOCALE_LABELS, b as SUPPORTED_LOCALES } from "../index-CILUifQv.js";
5
5
  const HEADER_ALIASES = {
6
6
  // ── Size label columns (skipped during field derivation) ──
7
7
  size: "__size__",
@@ -453,22 +453,6 @@ function lbsToKg(lbs) {
453
453
  function ftInToCm(ft, inch) {
454
454
  return +(ft * 30.48 + inch * 2.54).toFixed(1);
455
455
  }
456
- function SvgIcon({ d, size = 18, strokeWidth = 2 }) {
457
- return /* @__PURE__ */ jsx(
458
- "svg",
459
- {
460
- width: size,
461
- height: size,
462
- viewBox: "0 0 24 24",
463
- fill: "none",
464
- stroke: "currentColor",
465
- strokeWidth,
466
- strokeLinecap: "round",
467
- strokeLinejoin: "round",
468
- children: /* @__PURE__ */ jsx("path", { d })
469
- }
470
- );
471
- }
472
456
  function CameraIcon({ size = 18 }) {
473
457
  return /* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
474
458
  /* @__PURE__ */ jsx("path", { d: "M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z" }),
@@ -1510,28 +1494,19 @@ function PrimeStyleTryonInner({
1510
1494
  }
1511
1495
  function SizeResultView() {
1512
1496
  const unitLbl = sizingUnit === "cm" ? t("cm") : t("in");
1513
- const [editing, setEditing] = useState(false);
1514
1497
  const [editVals, setEditVals] = useState({});
1515
- const [compareSize, setCompareSize] = useState("");
1516
- const cleanChart = (s) => {
1517
- const nums = s.replace(/[^\d.\-–]/g, " ").trim().split(/[\s\-–]+/).filter(Boolean).map((n) => parseFloat(n)).filter((n) => !isNaN(n));
1518
- if (nums.length === 0) return s;
1519
- if (nums.length === 1) return `${nums[0]}`;
1520
- return `${nums[0]}–${nums[1]}`;
1498
+ const cleanNum = (s) => {
1499
+ const ns = s.replace(/[^\d.\-–]/g, " ").trim().split(/[\s\-–]+/).filter(Boolean).map((n) => parseFloat(n)).filter((n) => !isNaN(n));
1500
+ return ns.length === 1 ? `${ns[0]}` : ns.length > 1 ? `${ns[0]}–${ns[1]}` : s;
1501
+ };
1502
+ const pNum = (s) => {
1503
+ const n = parseFloat(s.replace(/[^\d.]/g, ""));
1504
+ return isNaN(n) ? 0 : n;
1505
+ };
1506
+ const pRange = (s) => {
1507
+ const ns = s.replace(/[^\d.\-–]/g, " ").trim().split(/[\s\-–]+/).filter(Boolean).map(Number).filter((n) => !isNaN(n));
1508
+ return ns.length ? { min: Math.min(...ns), max: Math.max(...ns) } : { min: 0, max: 0 };
1521
1509
  };
1522
- const recSize = useMemo(() => {
1523
- if (sizingResult?.recommendedSize) return sizingResult.recommendedSize;
1524
- if (sizeGuide?.rows && sizeGuide.headers) {
1525
- const sc = sizeGuide.headers.findIndex((h) => /size|taglia|größe|taille/i.test(h.trim()));
1526
- const idx = sc >= 0 ? sc : 0;
1527
- for (const row of sizeGuide.rows) {
1528
- const label = row[idx]?.trim();
1529
- if (label && /^(XXS|XS|S|M|L|XL|XXL|XXXL|\d{1,3})$/i.test(label)) return label;
1530
- }
1531
- }
1532
- return "";
1533
- }, [sizingResult, sizeGuide]);
1534
- const selSize = compareSize || recSize;
1535
1510
  const sizeColIdx = useMemo(() => {
1536
1511
  if (!sizeGuide?.headers || !sizeGuide?.rows) return -1;
1537
1512
  const byName = sizeGuide.headers.findIndex((h) => /size|taglia|größe|taille/i.test(h.trim()));
@@ -1545,14 +1520,6 @@ function PrimeStyleTryonInner({
1545
1520
  if (sizeColIdx < 0 || !sizeGuide?.rows) return [];
1546
1521
  return sizeGuide.rows.map((r) => r[sizeColIdx]?.trim()).filter(Boolean);
1547
1522
  }, [sizeGuide, sizeColIdx]);
1548
- const pNum = (s) => {
1549
- const n = parseFloat(s.replace(/[^\d.]/g, ""));
1550
- return isNaN(n) ? 0 : n;
1551
- };
1552
- const pRange = (s) => {
1553
- const ns = s.replace(/[^\d.\-–]/g, " ").trim().split(/[\s\-–]+/).filter(Boolean).map(Number).filter((n) => !isNaN(n));
1554
- return ns.length ? { min: Math.min(...ns), max: Math.max(...ns) } : { min: 0, max: 0 };
1555
- };
1556
1523
  const chartRangeFor = useCallback((measurement, size) => {
1557
1524
  if (!sizeGuide?.headers || !sizeGuide?.rows || sizeColIdx < 0) return null;
1558
1525
  const mc = sizeGuide.headers.findIndex((h) => {
@@ -1563,6 +1530,29 @@ function PrimeStyleTryonInner({
1563
1530
  const row = sizeGuide.rows.find((r) => r[sizeColIdx]?.trim() === size);
1564
1531
  return row?.[mc] ? { range: row[mc], ...pRange(row[mc]) } : null;
1565
1532
  }, [sizeGuide, sizeColIdx]);
1533
+ const bestSize = useMemo(() => {
1534
+ if (!sizingResult?.matchDetails?.length || !allSizes.length) return sizingResult?.recommendedSize || "";
1535
+ if (!Object.keys(editVals).length) return sizingResult?.recommendedSize || "";
1536
+ let best = "";
1537
+ let bestScore = -1;
1538
+ for (const size of allSizes) {
1539
+ let score = 0;
1540
+ for (const m of sizingResult.matchDetails) {
1541
+ const edited = editVals[m.measurement];
1542
+ const userNum = edited !== void 0 && edited !== "" ? parseFloat(edited) : pNum(m.userValue);
1543
+ const alt = chartRangeFor(m.measurement, size);
1544
+ if (alt && userNum >= alt.min && userNum <= alt.max) score++;
1545
+ }
1546
+ if (score > bestScore) {
1547
+ bestScore = score;
1548
+ best = size;
1549
+ }
1550
+ }
1551
+ return best || sizingResult?.recommendedSize || "";
1552
+ }, [editVals, sizingResult, allSizes, chartRangeFor]);
1553
+ const origSize = sizingResult?.recommendedSize || "";
1554
+ const activeSize = bestSize || origSize;
1555
+ const sizeChanged = Object.keys(editVals).length > 0 && bestSize !== origSize;
1566
1556
  const fitRows = useMemo(() => {
1567
1557
  if (!sizingResult?.matchDetails?.length) return [];
1568
1558
  return sizingResult.matchDetails.map((m) => {
@@ -1571,8 +1561,8 @@ function PrimeStyleTryonInner({
1571
1561
  const userNum = edited !== void 0 && edited !== "" ? parseFloat(edited) : origNum;
1572
1562
  let { min: rMin, max: rMax } = pRange(m.chartRange);
1573
1563
  let chartLabel = m.chartRange;
1574
- if (compareSize && compareSize !== recSize) {
1575
- const alt = chartRangeFor(m.measurement, compareSize);
1564
+ if (activeSize !== origSize) {
1565
+ const alt = chartRangeFor(m.measurement, activeSize);
1576
1566
  if (alt) {
1577
1567
  chartLabel = alt.range;
1578
1568
  rMin = alt.min;
@@ -1580,129 +1570,88 @@ function PrimeStyleTryonInner({
1580
1570
  }
1581
1571
  }
1582
1572
  const fit = userNum >= rMin && userNum <= rMax ? "good" : userNum < rMin ? "tight" : "loose";
1583
- return { area: m.measurement, userNum, chartLabel: cleanChart(chartLabel), fit };
1573
+ return { area: m.measurement, userNum, chartLabel: cleanNum(chartLabel), fit };
1584
1574
  });
1585
- }, [sizingResult, compareSize, editVals, chartRangeFor, recSize]);
1586
- const suggestedSize = useMemo(() => {
1587
- if (!Object.keys(editVals).length || !sizingResult?.matchDetails?.length || !allSizes.length) return null;
1588
- let bestSize = "";
1589
- let bestScore = -1;
1590
- for (const size of allSizes) {
1591
- let score = 0;
1592
- for (const m of sizingResult.matchDetails) {
1593
- const edited = editVals[m.measurement];
1594
- const userNum = edited !== void 0 && edited !== "" ? parseFloat(edited) : pNum(m.userValue);
1595
- const alt = chartRangeFor(m.measurement, size);
1596
- if (alt && userNum >= alt.min && userNum <= alt.max) score++;
1597
- }
1598
- if (score > bestScore) {
1599
- bestScore = score;
1600
- bestSize = size;
1601
- }
1602
- }
1603
- return bestSize && bestSize !== recSize ? bestSize : null;
1604
- }, [editVals, sizingResult, allSizes, recSize, chartRangeFor]);
1575
+ }, [sizingResult, editVals, chartRangeFor, activeSize, origSize]);
1605
1576
  const allIntlSizes = useMemo(() => {
1606
1577
  const backendIntl = sizingResult?.internationalSizes || {};
1607
- const upper = recSize.toUpperCase().trim();
1608
- const fromTable = SIZE_CONVERSIONS[upper] || SIZE_CONVERSIONS[recSize] || {};
1578
+ const upper = activeSize.toUpperCase().trim();
1579
+ const fromTable = SIZE_CONVERSIONS[upper] || SIZE_CONVERSIONS[activeSize] || {};
1609
1580
  return { ...fromTable, ...backendIntl };
1610
- }, [sizingResult, recSize]);
1611
- const confLabel = sizingResult?.confidence === "high" ? t("High Confidence") : sizingResult?.confidence === "medium" ? t("Medium Confidence") : t("Low Confidence");
1581
+ }, [sizingResult, activeSize]);
1612
1582
  return /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr", children: [
1613
1583
  sizingLoading && !sizingResult && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-loading", children: [
1614
1584
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner" }),
1615
1585
  /* @__PURE__ */ jsx("p", { children: t("Analyzing your size...") })
1616
1586
  ] }),
1617
1587
  sizingResult && /* @__PURE__ */ jsxs(Fragment, { children: [
1618
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-hero", children: [
1619
- recSize ? /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-hero-badge", children: recSize }) : /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-hero-badge ps-tryon-sr-hero-badge-icon", children: /* @__PURE__ */ jsx(RulerIcon, { size: 22 }) }),
1620
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-hero-info", children: [
1621
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-hero-title", children: t("Your Size") }),
1622
- /* @__PURE__ */ jsx("div", { className: `ps-tryon-sr-hero-conf ps-conf-${sizingResult.confidence}`, children: confLabel })
1623
- ] })
1624
- ] }),
1625
- suggestedSize && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-suggestion", onClick: () => {
1626
- setCompareSize(suggestedSize);
1588
+ /* @__PURE__ */ jsxs("button", { className: "ps-tryon-back", onClick: () => {
1589
+ setView("sizing-form");
1590
+ setEditVals({});
1627
1591
  }, children: [
1628
- /* @__PURE__ */ jsx(SparkleIcon, { size: 14 }),
1629
- /* @__PURE__ */ jsxs("span", { children: [
1630
- t("Based on your updated measurements, size"),
1631
- " ",
1632
- /* @__PURE__ */ jsx("strong", { children: suggestedSize }),
1633
- " ",
1634
- t("may be a better fit")
1635
- ] }),
1636
- /* @__PURE__ */ jsx(ArrowRightIcon, {})
1637
- ] }),
1638
- Object.keys(allIntlSizes).length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-intl", children: [
1639
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-section-title", children: t("Your size in other countries") }),
1640
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-intl-grid", children: Object.entries(allIntlSizes).map(([code, val]) => /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-intl-card", children: [
1641
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-intl-card-val", children: val }),
1642
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-intl-card-code", children: code })
1643
- ] }, code)) })
1592
+ /* @__PURE__ */ jsx(ArrowLeftIcon, {}),
1593
+ " ",
1594
+ t("Back")
1644
1595
  ] }),
1645
- fitRows.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit", children: [
1646
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit-top", children: [
1647
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-section-title", children: t("Fit Analysis") }),
1648
- /* @__PURE__ */ jsxs("button", { className: "ps-tryon-sr-edit-btn", onClick: () => setEditing(!editing), children: [
1649
- /* @__PURE__ */ jsx(SvgIcon, { d: "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7", size: 12 }),
1650
- editing ? t("Done") : t("Edit values")
1596
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-split", children: [
1597
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-left", children: [
1598
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-hero", children: [
1599
+ activeSize ? /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-hero-badge", children: activeSize }) : /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-hero-badge ps-tryon-sr-hero-badge-icon", children: /* @__PURE__ */ jsx(RulerIcon, { size: 22 }) }),
1600
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-hero-info", children: [
1601
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-hero-title", children: t("Your Size") }),
1602
+ /* @__PURE__ */ jsx("div", { className: `ps-tryon-sr-hero-conf ps-conf-${sizingResult.confidence}`, children: sizingResult.confidence === "high" ? t("High Confidence") : sizingResult.confidence === "medium" ? t("Medium Confidence") : t("Low Confidence") })
1603
+ ] })
1604
+ ] }),
1605
+ sizeChanged && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-size-changed", children: [
1606
+ /* @__PURE__ */ jsx(SparkleIcon, { size: 13 }),
1607
+ " ",
1608
+ t("Updated to"),
1609
+ " ",
1610
+ /* @__PURE__ */ jsx("strong", { children: activeSize })
1611
+ ] }),
1612
+ Object.keys(allIntlSizes).length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-intl", children: [
1613
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-section-title", children: t("Your size in other countries") }),
1614
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-intl-grid", children: Object.entries(allIntlSizes).map(([code, val]) => /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-intl-card", children: [
1615
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-intl-card-val", children: val }),
1616
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-intl-card-code", children: code })
1617
+ ] }, code)) })
1651
1618
  ] })
1652
1619
  ] }),
1653
- allSizes.length > 1 && /* @__PURE__ */ jsx("select", { className: "ps-tryon-sr-compare-select", value: selSize, onChange: (e) => setCompareSize(e.target.value), children: allSizes.map((s) => /* @__PURE__ */ jsxs("option", { value: s, children: [
1654
- s,
1655
- s === recSize ? ` ${t("recommended")}` : ""
1656
- ] }, s)) }),
1657
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-fit-cards", children: fitRows.map((row, i) => /* @__PURE__ */ jsxs("div", { className: `ps-tryon-sr-fc ps-fit-${row.fit}`, children: [
1658
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-head", children: [
1659
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fc-area", children: row.area }),
1660
- /* @__PURE__ */ jsx("span", { className: `ps-tryon-sr-fc-badge ps-fit-${row.fit}`, children: row.fit === "good" ? `✓ ${t("within range")}` : row.fit === "tight" ? `↑ ${t("may be snug")}` : `↓ ${t("may be loose")}` })
1661
- ] }),
1662
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-body", children: [
1663
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-col", children: [
1664
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-fc-label", children: t("You") }),
1665
- editing ? /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-edit", children: [
1620
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-right", children: [
1621
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-section-title", children: t("Your Measurements") }),
1622
+ fitRows.map((row, i) => /* @__PURE__ */ jsxs("div", { className: `ps-tryon-sr-meas ps-fit-${row.fit}`, children: [
1623
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-meas-head", children: [
1624
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-meas-area", children: row.area }),
1625
+ /* @__PURE__ */ jsx("span", { className: `ps-tryon-sr-meas-badge ps-fit-${row.fit}`, children: row.fit === "good" ? `✓ ${t("within range")}` : row.fit === "tight" ? `↑ ${t("may be snug")}` : `↓ ${t("may be loose")}` })
1626
+ ] }),
1627
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-meas-row", children: [
1628
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-meas-input-wrap", children: [
1666
1629
  /* @__PURE__ */ jsx(
1667
1630
  "input",
1668
1631
  {
1669
1632
  type: "number",
1670
- className: "ps-tryon-sr-fc-input",
1633
+ className: "ps-tryon-sr-meas-input",
1671
1634
  value: editVals[row.area] !== void 0 ? editVals[row.area] : row.userNum,
1672
1635
  onChange: (e) => setEditVals((prev) => ({ ...prev, [row.area]: e.target.value }))
1673
1636
  }
1674
1637
  ),
1675
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fc-unit", children: unitLbl })
1676
- ] }) : /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-value", children: [
1677
- row.userNum,
1678
- " ",
1679
- unitLbl
1680
- ] })
1681
- ] }),
1682
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-col", children: [
1683
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-label", children: [
1684
- t("Chart"),
1685
- " (",
1686
- selSize,
1687
- ")"
1638
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-meas-unit", children: unitLbl })
1688
1639
  ] }),
1689
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-value", children: [
1640
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-meas-vs", children: "vs" }),
1641
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-meas-chart", children: [
1690
1642
  row.chartLabel,
1691
1643
  " ",
1692
1644
  unitLbl
1693
1645
  ] })
1694
1646
  ] })
1695
- ] })
1696
- ] }, i)) })
1647
+ ] }, i)),
1648
+ fitRows.length === 0 && sizingResult.reasoning && /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-reasoning", children: /* @__PURE__ */ jsx("p", { children: sizingResult.reasoning }) })
1649
+ ] })
1697
1650
  ] }),
1698
- fitRows.length === 0 && sizingResult.reasoning && /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-reasoning", children: /* @__PURE__ */ jsx("p", { children: sizingResult.reasoning }) }),
1699
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-ctas", children: [
1700
- /* @__PURE__ */ jsxs("button", { className: "ps-tryon-cta", onClick: () => setView("upload"), children: [
1701
- t("See how it looks on you"),
1702
- " ",
1703
- /* @__PURE__ */ jsx(ArrowRightIcon, {})
1704
- ] }),
1705
- /* @__PURE__ */ jsx("button", { className: "ps-tryon-btn-secondary", onClick: handleClose, children: t("Done") })
1651
+ /* @__PURE__ */ jsxs("button", { className: "ps-tryon-cta", onClick: () => setView("upload"), children: [
1652
+ t("See how it looks on you"),
1653
+ " ",
1654
+ /* @__PURE__ */ jsx(ArrowRightIcon, {})
1706
1655
  ] })
1707
1656
  ] })
1708
1657
  ] });
@@ -1922,7 +1871,7 @@ function PrimeStyleTryonInner({
1922
1871
  ] }),
1923
1872
  view !== "idle" && /* @__PURE__ */ jsx("div", { className: cx("ps-tryon-overlay", cn.overlay), onClick: (e) => {
1924
1873
  if (e.target === e.currentTarget) handleClose();
1925
- }, children: /* @__PURE__ */ jsxs("div", { className: cx(`ps-tryon-modal${view === "result" && resultImageUrl && sizingResult ? " ps-tryon-modal-wide" : ""}`, cn.modal), onClick: (e) => e.stopPropagation(), children: [
1874
+ }, children: /* @__PURE__ */ jsxs("div", { className: cx(`ps-tryon-modal${view === "result" && resultImageUrl && sizingResult || view === "size-result" ? " ps-tryon-modal-wide" : ""}`, cn.modal), onClick: (e) => e.stopPropagation(), children: [
1926
1875
  /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-header", cn.header), children: [
1927
1876
  /* @__PURE__ */ jsx("span", { className: cx("ps-tryon-title", cn.title), children: t("Virtual Try-On") }),
1928
1877
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-header-actions", children: [
@@ -2392,21 +2341,25 @@ const STYLES = `
2392
2341
  .ps-tryon-sr-hero-conf { font-size: 0.73vw; font-weight: 600; }
2393
2342
  .ps-conf-high { color: #4ade80; } .ps-conf-medium { color: #bb945c; } .ps-conf-low { color: #ef4444; }
2394
2343
 
2395
- /* Suggestion banner */
2396
- .ps-tryon-sr-suggestion {
2397
- display: flex; align-items: center; gap: 0.52vw;
2398
- padding: 0.62vw 0.83vw; border-radius: 0.52vw;
2399
- background: linear-gradient(135deg, rgba(187,148,92,0.1), rgba(187,148,92,0.04));
2400
- border: 1px solid rgba(187,148,92,0.25);
2401
- font-size: 0.73vw; color: #d6ba7d; cursor: pointer;
2402
- animation: ps-fade-up 0.3s ease both; transition: background 0.2s;
2403
- }
2404
- .ps-tryon-sr-suggestion:hover { background: rgba(187,148,92,0.14); }
2405
- .ps-tryon-sr-suggestion svg { stroke: #bb945c; flex-shrink: 0; }
2406
- .ps-tryon-sr-suggestion strong { color: #fff; }
2407
2344
  .ps-tryon-sr-hero-badge-icon { background: linear-gradient(135deg, #333, #444); }
2408
2345
  .ps-tryon-sr-hero-badge-icon svg { stroke: #bb945c; }
2409
2346
 
2347
+ /* Size changed notice */
2348
+ .ps-tryon-sr-size-changed {
2349
+ display: flex; align-items: center; gap: 0.36vw;
2350
+ padding: 0.42vw 0.68vw; border-radius: 0.42vw;
2351
+ background: rgba(187,148,92,0.08); border: 1px solid rgba(187,148,92,0.2);
2352
+ font-size: 0.73vw; color: #d6ba7d; margin-top: 0.52vw;
2353
+ animation: ps-fade-up 0.25s ease both;
2354
+ }
2355
+ .ps-tryon-sr-size-changed svg { stroke: #bb945c; }
2356
+ .ps-tryon-sr-size-changed strong { color: #fff; }
2357
+
2358
+ /* Split layout */
2359
+ .ps-tryon-sr-split { display: flex; gap: 1.5vw; min-height: 0; }
2360
+ .ps-tryon-sr-left { flex: 0 0 45%; display: flex; flex-direction: column; gap: 1vw; }
2361
+ .ps-tryon-sr-right { flex: 1; display: flex; flex-direction: column; gap: 0.52vw; }
2362
+
2410
2363
  /* Section titles */
2411
2364
  .ps-tryon-sr-section-title { font-size: 0.73vw; font-weight: 700; color: #666; text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 0.52vw; }
2412
2365
 
@@ -2448,82 +2401,44 @@ const STYLES = `
2448
2401
  .ps-tryon-sr-comparing { font-size: 0.73vw; color: #bb945c; margin-top: 0.42vw; }
2449
2402
  .ps-tryon-sr-comparing strong { color: #d6ba7d; }
2450
2403
 
2451
- /* Fit analysis */
2452
- .ps-tryon-sr-fit { }
2453
- .ps-tryon-sr-fit-top {
2454
- display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.52vw;
2455
- }
2456
- .ps-tryon-sr-edit-btn {
2457
- display: inline-flex; align-items: center; gap: 0.31vw;
2458
- padding: 0.31vw 0.73vw; border: 1px solid rgba(187,148,92,0.4); border-radius: 0.42vw;
2459
- background: rgba(187,148,92,0.06); color: #bb945c; font-size: 0.68vw; font-weight: 600;
2460
- cursor: pointer; font-family: inherit; transition: all 0.2s;
2461
- }
2462
- .ps-tryon-sr-edit-btn:hover { background: rgba(187,148,92,0.12); border-color: #bb945c; }
2463
- .ps-tryon-sr-edit-btn svg { stroke: currentColor; }
2464
-
2465
- .ps-tryon-sr-fit-cards { display: flex; flex-direction: column; gap: 0.42vw; }
2466
-
2467
- .ps-tryon-sr-fc {
2468
- border: 1px solid #282828; border-radius: 0.63vw; overflow: hidden;
2404
+ /* Measurement rows (right column) */
2405
+ .ps-tryon-sr-meas {
2406
+ border: 1px solid #282828; border-radius: 0.57vw; overflow: hidden;
2469
2407
  transition: border-color 0.2s;
2470
2408
  }
2471
- .ps-tryon-sr-fc.ps-fit-good { border-left: 3px solid #4ade80; }
2472
- .ps-tryon-sr-fc.ps-fit-tight { border-left: 3px solid #f59e0b; }
2473
- .ps-tryon-sr-fc.ps-fit-loose { border-left: 3px solid #60a5fa; }
2474
-
2475
- .ps-tryon-sr-fc-head {
2409
+ .ps-tryon-sr-meas.ps-fit-good { border-left: 3px solid #4ade80; }
2410
+ .ps-tryon-sr-meas.ps-fit-tight { border-left: 3px solid #f59e0b; }
2411
+ .ps-tryon-sr-meas.ps-fit-loose { border-left: 3px solid #60a5fa; }
2412
+ .ps-tryon-sr-meas-head {
2476
2413
  display: flex; align-items: center; justify-content: space-between;
2477
- padding: 0.57vw 0.83vw; background: #161616;
2478
- }
2479
- .ps-tryon-sr-fc-area { font-size: 0.83vw; font-weight: 700; color: #fff; }
2480
-
2481
- .ps-tryon-sr-fc-badge {
2482
- display: inline-flex; align-items: center; gap: 0.21vw; padding: 0.21vw 0.52vw;
2483
- border-radius: 0.31vw; font-size: 0.63vw; font-weight: 700; white-space: nowrap;
2484
- }
2485
- .ps-tryon-sr-fc-badge.ps-fit-good { background: rgba(74,222,128,0.08); color: #4ade80; }
2486
- .ps-tryon-sr-fc-badge.ps-fit-tight { background: rgba(245,158,11,0.08); color: #f59e0b; }
2487
- .ps-tryon-sr-fc-badge.ps-fit-loose { background: rgba(96,165,250,0.08); color: #60a5fa; }
2488
-
2489
- .ps-tryon-sr-fc-body {
2490
- display: flex; gap: 1.5vw; padding: 0.52vw 0.83vw 0.62vw;
2491
- }
2492
- .ps-tryon-sr-fc-col { flex: 1; }
2493
- .ps-tryon-sr-fc-label { font-size: 0.52vw; font-weight: 700; color: #555; text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 0.15vw; }
2494
- .ps-tryon-sr-fc-value { font-size: 0.88vw; font-weight: 600; color: #ccc; }
2495
- .ps-tryon-sr-fc-edit { display: flex; align-items: center; gap: 0.26vw; }
2496
- .ps-tryon-sr-fc-input {
2497
- width: 4.2vw; padding: 0.26vw 0.42vw; border: 1.5px solid #444; border-radius: 0.36vw;
2498
- background: #0c0c0d; color: #fff; font-size: 0.88vw; font-weight: 600; font-family: inherit;
2414
+ padding: 0.47vw 0.73vw; background: #161616;
2415
+ }
2416
+ .ps-tryon-sr-meas-area { font-size: 0.78vw; font-weight: 700; color: #fff; }
2417
+ .ps-tryon-sr-meas-badge {
2418
+ display: inline-flex; align-items: center; gap: 0.21vw; padding: 0.16vw 0.47vw;
2419
+ border-radius: 0.26vw; font-size: 0.57vw; font-weight: 700; white-space: nowrap;
2420
+ }
2421
+ .ps-tryon-sr-meas-badge.ps-fit-good { background: rgba(74,222,128,0.08); color: #4ade80; }
2422
+ .ps-tryon-sr-meas-badge.ps-fit-tight { background: rgba(245,158,11,0.08); color: #f59e0b; }
2423
+ .ps-tryon-sr-meas-badge.ps-fit-loose { background: rgba(96,165,250,0.08); color: #60a5fa; }
2424
+ .ps-tryon-sr-meas-row {
2425
+ display: flex; align-items: center; gap: 0.52vw; padding: 0.47vw 0.73vw;
2426
+ }
2427
+ .ps-tryon-sr-meas-input-wrap { display: flex; align-items: center; gap: 0.21vw; }
2428
+ .ps-tryon-sr-meas-input {
2429
+ width: 3.8vw; padding: 0.26vw 0.36vw; border: 1.5px solid #444; border-radius: 0.31vw;
2430
+ background: #0c0c0d; color: #fff; font-size: 0.83vw; font-weight: 600; font-family: inherit;
2499
2431
  outline: none; text-align: center; -moz-appearance: textfield;
2500
2432
  transition: border-color 0.2s, background 0.2s;
2501
2433
  }
2502
- .ps-tryon-sr-fc-input::-webkit-outer-spin-button,
2503
- .ps-tryon-sr-fc-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
2504
- .ps-tryon-sr-fc-input:focus { border-color: #bb945c; background: #1a1a1a; }
2505
- .ps-tryon-sr-fc-unit { font-size: 0.63vw; color: #555; }
2434
+ .ps-tryon-sr-meas-input::-webkit-outer-spin-button,
2435
+ .ps-tryon-sr-meas-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
2436
+ .ps-tryon-sr-meas-input:focus { border-color: #bb945c; background: #1a1a1a; }
2437
+ .ps-tryon-sr-meas-unit { font-size: 0.63vw; color: #555; }
2438
+ .ps-tryon-sr-meas-vs { font-size: 0.63vw; color: #444; font-weight: 700; }
2439
+ .ps-tryon-sr-meas-chart { font-size: 0.83vw; font-weight: 600; color: #888; }
2506
2440
 
2507
- /* Compare dropdown */
2508
- .ps-tryon-sr-compare { }
2509
- .ps-tryon-sr-compare-select {
2510
- width: 100%; padding: 0.57vw 2vw 0.57vw 0.83vw; border: 1.5px solid #333; border-radius: 0.57vw;
2511
- background: #1a1b1a; color: #fff; font-size: 0.83vw; font-weight: 600; font-family: inherit;
2512
- appearance: none; -webkit-appearance: none; cursor: pointer; outline: none;
2513
- background-image: url("data:image/svg+xml,%3Csvg width='12' height='12' viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M2.5 4.5L6 8L9.5 4.5' stroke='%23999' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
2514
- background-repeat: no-repeat; background-position: right 0.73vw center;
2515
- }
2516
- .ps-tryon-sr-compare-select:focus { border-color: #bb945c; }
2517
- .ps-tryon-sr-compare-select option { background: #1a1b1a; color: #fff; }
2518
- .ps-tryon-sr-compare-note {
2519
- font-size: 0.73vw; color: #bb945c; margin-top: 0.42vw; display: flex; align-items: center; gap: 0.52vw;
2520
- }
2521
- .ps-tryon-sr-compare-reset {
2522
- background: none; border: 1px solid #bb945c; color: #bb945c; padding: 0.16vw 0.52vw;
2523
- border-radius: 0.31vw; font-size: 0.63vw; font-weight: 600; cursor: pointer;
2524
- font-family: inherit; transition: all 0.2s;
2525
- }
2526
- .ps-tryon-sr-compare-reset:hover { background: rgba(187,148,92,0.1); }
2441
+ /* (compare dropdown removed — recalculation is automatic) */
2527
2442
 
2528
2443
  .ps-tryon-sr-fit-badge {
2529
2444
  display: inline-flex; align-items: center; gap: 0.26vw; padding: 0.21vw 0.52vw;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primestyleai/tryon",
3
- "version": "4.1.2",
3
+ "version": "4.2.0",
4
4
  "description": "PrimeStyle Virtual Try-On SDK — React component & Web Component",
5
5
  "type": "module",
6
6
  "main": "dist/primestyle-tryon.js",
@@ -53,5 +53,8 @@
53
53
  "terser": "^5.31.0",
54
54
  "typescript": "^5.5.0",
55
55
  "vite": "^5.4.0"
56
+ },
57
+ "dependencies": {
58
+ "@primestyleai/tryon": "^4.1.2"
56
59
  }
57
60
  }