@primestyleai/tryon 5.10.178 → 5.10.179
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.
- package/dist/api-client.d.ts +4 -0
- package/dist/index-CYT0nGWX.js.map +1 -1
- package/dist/react/PrimeStyleTryonInner.d.ts +1 -1
- package/dist/react/index.js +5316 -5234
- package/dist/react/index.js.map +1 -1
- package/dist/react/styles.d.ts +1 -1
- package/dist/react/types.d.ts +2 -0
- package/dist/sizing/fit-compute.d.ts +3 -4
- package/dist/storefront/primestyle-tryon.js +300 -47
- package/dist/storefront/size-guide-modal.d.ts +1 -0
- package/dist/types.d.ts +2 -2
- package/package.json +1 -1
package/dist/react/types.d.ts
CHANGED
|
@@ -228,6 +228,8 @@ export interface PrimeStyleTryonProps {
|
|
|
228
228
|
* the fabric correctly without guessing from the image alone. */
|
|
229
229
|
productMaterial?: string;
|
|
230
230
|
buttonText?: string;
|
|
231
|
+
/** When true, a completed try-on for this product turns the storefront button into a saved fit result. */
|
|
232
|
+
limitOneColorTryOnPerProduct?: boolean;
|
|
231
233
|
apiUrl?: string;
|
|
232
234
|
showPoweredBy?: boolean;
|
|
233
235
|
/** Show the default camera icon in the button. Defaults to true. Set to false to hide it. */
|
|
@@ -24,9 +24,9 @@ export declare function buildFitInfo(matchDetails: Array<{
|
|
|
24
24
|
}>, poseLines?: MeasurementLines | null, unit?: "in" | "cm" | "mm"): FitAreaInfo[];
|
|
25
25
|
/**
|
|
26
26
|
* Build silhouette-prompt context forwarded to the backend try-on Gemini
|
|
27
|
-
* call. Returns the
|
|
28
|
-
*
|
|
29
|
-
*
|
|
27
|
+
* call. Returns only the selected fit context Gemini needs: user raw
|
|
28
|
+
* measurements, recommended size, and the chosen size's measurement row.
|
|
29
|
+
* The full product size guide is intentionally not forwarded to try-on.
|
|
30
30
|
*
|
|
31
31
|
* All fields optional — returns `undefined` when there's nothing useful
|
|
32
32
|
* to add (e.g. accessory flow, no sizingResult).
|
|
@@ -70,7 +70,6 @@ selectedSizeOverride?: string,
|
|
|
70
70
|
userHeight?: string, userWeight?: string): {
|
|
71
71
|
recommendedSize?: string;
|
|
72
72
|
recommendedSizeMeasurements?: string;
|
|
73
|
-
sizeChartSummary?: string;
|
|
74
73
|
userMeasurementsText?: string;
|
|
75
74
|
userHeight?: string;
|
|
76
75
|
userWeight?: string;
|
|
@@ -10225,6 +10225,52 @@ function parseNum(s) {
|
|
|
10225
10225
|
const n2 = parseFloat(s.replace(/[^\d.]/g, ""));
|
|
10226
10226
|
return isNaN(n2) ? 0 : n2;
|
|
10227
10227
|
}
|
|
10228
|
+
function normalizeUnit(unit) {
|
|
10229
|
+
const u2 = (unit || "").toLowerCase();
|
|
10230
|
+
if (u2 === "in" || u2 === "inch" || u2 === "inches") return "in";
|
|
10231
|
+
if (u2 === "cm") return "cm";
|
|
10232
|
+
if (u2 === "mm") return "mm";
|
|
10233
|
+
return null;
|
|
10234
|
+
}
|
|
10235
|
+
function detectUnitFromText(text) {
|
|
10236
|
+
const t2 = String(text || "");
|
|
10237
|
+
if (/\bmm\b/i.test(t2)) return "mm";
|
|
10238
|
+
if (/\bcm\b/i.test(t2)) return "cm";
|
|
10239
|
+
if (/\bin\b|inch|inches|["”]/i.test(t2)) return "in";
|
|
10240
|
+
return null;
|
|
10241
|
+
}
|
|
10242
|
+
function convertValue(value, from, to) {
|
|
10243
|
+
if (from === to) return value;
|
|
10244
|
+
const inMm = from === "mm" ? value : from === "cm" ? value * 10 : value * 25.4;
|
|
10245
|
+
if (to === "mm") return inMm;
|
|
10246
|
+
if (to === "cm") return inMm / 10;
|
|
10247
|
+
return inMm / 25.4;
|
|
10248
|
+
}
|
|
10249
|
+
function formatUnitNumber(value, unit) {
|
|
10250
|
+
const precision = unit === "mm" ? 0 : 1;
|
|
10251
|
+
const rounded = Number(value.toFixed(precision));
|
|
10252
|
+
return Number.isInteger(rounded) ? String(rounded) : String(rounded);
|
|
10253
|
+
}
|
|
10254
|
+
function convertNumberTextToUnit(text, from, to) {
|
|
10255
|
+
if (from === to) return text;
|
|
10256
|
+
const converted = text.replace(/\s*(cm|mm|in|inch|inches)\b/ig, "").replace(/(\d+(?:\.\d+)?)/g, (raw) => formatUnitNumber(convertValue(Number(raw), from, to), to)).trim();
|
|
10257
|
+
return converted ? `${converted} ${to}` : text;
|
|
10258
|
+
}
|
|
10259
|
+
function normalizeMeasurementValueText(measurement, value, targetUnit) {
|
|
10260
|
+
if (isUnitlessShoeSizeMeasurement(measurement)) return formatUserMeasurementValue(measurement, value);
|
|
10261
|
+
const sourceUnit = detectUnitFromText(value);
|
|
10262
|
+
if (sourceUnit) return convertNumberTextToUnit(value, sourceUnit, targetUnit);
|
|
10263
|
+
const trimmed = String(value || "").trim();
|
|
10264
|
+
return /\d/.test(trimmed) ? `${trimmed} ${targetUnit}` : trimmed;
|
|
10265
|
+
}
|
|
10266
|
+
function normalizeRangeText(range, targetUnit, header) {
|
|
10267
|
+
const sourceUnit = detectUnitFromText(range) || detectUnitFromText(header);
|
|
10268
|
+
if (!sourceUnit) return String(range || "").trim();
|
|
10269
|
+
return convertNumberTextToUnit(range, sourceUnit, targetUnit);
|
|
10270
|
+
}
|
|
10271
|
+
function promptHeaderLabel(header) {
|
|
10272
|
+
return String(header || "").replace(/\s*\((?:cm|mm|in|inch|inches)\)\s*/ig, "").trim();
|
|
10273
|
+
}
|
|
10228
10274
|
function isUnitlessShoeSizeMeasurement(measurement) {
|
|
10229
10275
|
const normalized = measurement.toLowerCase().replace(/\s*\(.*?\)\s*/g, " ").trim();
|
|
10230
10276
|
if (/foot\s*length|length\s*\(cm\)|cm\s*\/\s*jp|mondo|mondopoint/i.test(normalized)) return false;
|
|
@@ -10235,11 +10281,15 @@ function formatUserMeasurementValue(measurement, value) {
|
|
|
10235
10281
|
return value.replace(/\s*(cm|mm|in|inch|inches)\b/ig, "").trim();
|
|
10236
10282
|
}
|
|
10237
10283
|
function computeFit(userValue, chartRange, unit) {
|
|
10238
|
-
const
|
|
10284
|
+
const targetUnit = normalizeUnit(unit) || detectUnitFromText(chartRange) || "in";
|
|
10285
|
+
const chartUnit = detectUnitFromText(chartRange);
|
|
10286
|
+
const parsed = parseRange(chartRange);
|
|
10287
|
+
const rMin = chartUnit && chartUnit !== targetUnit ? convertValue(parsed.min, chartUnit, targetUnit) : parsed.min;
|
|
10288
|
+
const rMax = chartUnit && chartUnit !== targetUnit ? convertValue(parsed.max, chartUnit, targetUnit) : parsed.max;
|
|
10239
10289
|
if (rMin === 0 && rMax === 0) return "good";
|
|
10240
|
-
const perfectTol =
|
|
10241
|
-
const aBitTol =
|
|
10242
|
-
const tooFarTol =
|
|
10290
|
+
const perfectTol = targetUnit === "cm" ? 1.27 : targetUnit === "mm" ? 12.7 : 0.5;
|
|
10291
|
+
const aBitTol = targetUnit === "cm" ? 2.54 : targetUnit === "mm" ? 25.4 : 1;
|
|
10292
|
+
const tooFarTol = targetUnit === "cm" ? 5.08 : targetUnit === "mm" ? 50.8 : 2;
|
|
10243
10293
|
const inRange = userValue >= rMin && userValue <= rMax;
|
|
10244
10294
|
const overEdge = inRange ? 0 : userValue > rMax ? userValue - rMax : rMin - userValue;
|
|
10245
10295
|
if (inRange || overEdge <= perfectTol) return "good";
|
|
@@ -10262,14 +10312,17 @@ const SKIP_AREAS_FOR_FIT = /* @__PURE__ */ new Set([
|
|
|
10262
10312
|
]);
|
|
10263
10313
|
function buildFitInfo(matchDetails, poseLines, unit) {
|
|
10264
10314
|
return matchDetails.filter((m2) => !SKIP_AREAS_FOR_FIT.has(m2.measurement.toLowerCase().replace(/\s*\(.*?\)\s*/g, "").trim())).map((m2) => {
|
|
10265
|
-
const
|
|
10266
|
-
const
|
|
10315
|
+
const targetUnit = normalizeUnit(unit) || detectUnitFromText(m2.userValue) || detectUnitFromText(m2.chartRange) || "in";
|
|
10316
|
+
const userValueText = normalizeMeasurementValueText(m2.measurement, m2.userValue, targetUnit);
|
|
10317
|
+
const chartRangeText = normalizeRangeText(m2.chartRange, targetUnit);
|
|
10318
|
+
const userNum = parseNum(userValueText);
|
|
10319
|
+
const fit = computeFit(userNum, chartRangeText, targetUnit);
|
|
10267
10320
|
const info = {
|
|
10268
10321
|
area: m2.measurement,
|
|
10269
10322
|
section: m2.section || void 0,
|
|
10270
10323
|
fit,
|
|
10271
10324
|
userValue: userNum || void 0,
|
|
10272
|
-
garmentRange:
|
|
10325
|
+
garmentRange: chartRangeText || void 0
|
|
10273
10326
|
};
|
|
10274
10327
|
if (poseLines) {
|
|
10275
10328
|
const poseKey = AREA_TO_POSE_KEY[m2.measurement.toLowerCase()];
|
|
@@ -10286,6 +10339,7 @@ function buildFitInfo(matchDetails, poseLines, unit) {
|
|
|
10286
10339
|
function buildSilhouetteContext(sizingResult, sizeGuide, selectedSizeOverride, userHeight, userWeight) {
|
|
10287
10340
|
if (!sizingResult && !sizeGuide && !userHeight && !userWeight) return void 0;
|
|
10288
10341
|
const out = {};
|
|
10342
|
+
const promptUnit = normalizeUnit(sizingResult?.unit) || detectUnitFromText(sizingResult?.matchDetails?.[0]?.userValue) || detectUnitFromText(Object.values(sizingResult?.sections || {})[0]?.matchDetails?.[0]?.userValue) || "in";
|
|
10289
10343
|
const baseSize = (selectedSizeOverride || sizingResult?.recommendedSize || "").toString().trim();
|
|
10290
10344
|
if (userHeight) out.userHeight = userHeight;
|
|
10291
10345
|
if (userWeight) out.userWeight = userWeight;
|
|
@@ -10311,7 +10365,7 @@ function buildSilhouetteContext(sizingResult, sizeGuide, selectedSizeOverride, u
|
|
|
10311
10365
|
chartRowFit = vStr;
|
|
10312
10366
|
continue;
|
|
10313
10367
|
}
|
|
10314
|
-
if (vStr) bits.push(`${h} ${vStr}`);
|
|
10368
|
+
if (vStr) bits.push(`${promptHeaderLabel(h) || h} ${normalizeRangeText(vStr, promptUnit, h)}`);
|
|
10315
10369
|
if (chartRowLength == null && /^length\b|inseam/i.test(h) && vStr) {
|
|
10316
10370
|
chartRowLength = vStr;
|
|
10317
10371
|
}
|
|
@@ -10360,7 +10414,7 @@ function buildSilhouetteContext(sizingResult, sizeGuide, selectedSizeOverride, u
|
|
|
10360
10414
|
const h = (secChart.headers[i] || "").trim();
|
|
10361
10415
|
const baseHeader = h.replace(/\s*\(.*?\)\s*/g, "").trim();
|
|
10362
10416
|
if (vStr && !/^(size|standard|country|fit|silhouette|category|body[\s_]?type|eu|uk|us|it|jp|cn|kr|ru|br|au)$/i.test(baseHeader)) {
|
|
10363
|
-
bits.push(`${h} ${vStr}`);
|
|
10417
|
+
bits.push(`${promptHeaderLabel(h) || h} ${normalizeRangeText(vStr, promptUnit, h)}`);
|
|
10364
10418
|
}
|
|
10365
10419
|
}
|
|
10366
10420
|
if (bits.length) measurementParts.push(`${cleanSec} ${secSize}: ${bits.join(", ")}`);
|
|
@@ -10370,29 +10424,33 @@ function buildSilhouetteContext(sizingResult, sizeGuide, selectedSizeOverride, u
|
|
|
10370
10424
|
if (labelParts.length) out.recommendedSize = labelParts.join(", ");
|
|
10371
10425
|
if (measurementParts.length) out.recommendedSizeMeasurements = measurementParts.join(" | ");
|
|
10372
10426
|
}
|
|
10373
|
-
const
|
|
10427
|
+
const seenUserMeasurements = /* @__PURE__ */ new Set();
|
|
10428
|
+
const seenSelectedMeasurements = /* @__PURE__ */ new Set();
|
|
10374
10429
|
const userLines = [];
|
|
10375
|
-
const
|
|
10430
|
+
const selectedMeasurementLines = [];
|
|
10431
|
+
const push = (md2, sectionName) => {
|
|
10376
10432
|
if (!md2) return;
|
|
10377
10433
|
for (const m2 of md2) {
|
|
10378
|
-
const
|
|
10379
|
-
if (
|
|
10380
|
-
|
|
10381
|
-
if (m2.userValue
|
|
10434
|
+
const normalizedMeasurement = m2.measurement.toLowerCase().replace(/\s*\(.*?\)\s*/g, "").trim();
|
|
10435
|
+
if (SKIP_AREAS_FOR_FIT.has(normalizedMeasurement)) continue;
|
|
10436
|
+
const selectedKey = sectionName ? `${sectionName.toLowerCase()}:${normalizedMeasurement}` : normalizedMeasurement;
|
|
10437
|
+
if (m2.userValue && !seenUserMeasurements.has(normalizedMeasurement)) {
|
|
10438
|
+
seenUserMeasurements.add(normalizedMeasurement);
|
|
10439
|
+
userLines.push(`${m2.measurement} ${normalizeMeasurementValueText(m2.measurement, m2.userValue, promptUnit)}`);
|
|
10440
|
+
}
|
|
10441
|
+
if (m2.chartRange && !seenSelectedMeasurements.has(selectedKey)) {
|
|
10442
|
+
seenSelectedMeasurements.add(selectedKey);
|
|
10443
|
+
const prefix = sectionName ? `${sectionName} ${m2.measurement}` : m2.measurement;
|
|
10444
|
+
selectedMeasurementLines.push(`${prefix} ${normalizeRangeText(m2.chartRange, promptUnit)}`);
|
|
10445
|
+
}
|
|
10382
10446
|
}
|
|
10383
10447
|
};
|
|
10384
10448
|
push(sizingResult?.matchDetails);
|
|
10385
10449
|
if (sizingResult?.sections) {
|
|
10386
|
-
for (const sec of Object.
|
|
10450
|
+
for (const [secName, sec] of Object.entries(sizingResult.sections)) push(sec.matchDetails, secName);
|
|
10387
10451
|
}
|
|
10388
10452
|
if (userLines.length) out.userMeasurementsText = userLines.join(", ");
|
|
10389
|
-
if (
|
|
10390
|
-
const hdrs = sizeGuide.headers;
|
|
10391
|
-
const rowStrings = sizeGuide.rows.slice(0, 20).map(
|
|
10392
|
-
(row) => hdrs.map((h, i) => `${h} ${row[i] ?? "—"}`).join(", ")
|
|
10393
|
-
);
|
|
10394
|
-
out.sizeChartSummary = rowStrings.join(" | ");
|
|
10395
|
-
}
|
|
10453
|
+
if (selectedMeasurementLines.length) out.recommendedSizeMeasurements = selectedMeasurementLines.join(", ");
|
|
10396
10454
|
return Object.keys(out).length ? out : void 0;
|
|
10397
10455
|
}
|
|
10398
10456
|
const FALLBACK_FIELDS_FEMALE = [
|
|
@@ -11627,7 +11685,7 @@ function productFitTypeToMeasurementType(fitType) {
|
|
|
11627
11685
|
}
|
|
11628
11686
|
return "body";
|
|
11629
11687
|
}
|
|
11630
|
-
const STYLES
|
|
11688
|
+
const STYLES = `
|
|
11631
11689
|
/* Variable defaults must live on BOTH the root (for the trigger button)
|
|
11632
11690
|
and the overlay (which is React-portaled to <body> and therefore not
|
|
11633
11691
|
a descendant of .ps-tryon-root, so the cascade is broken). Without
|
|
@@ -11694,6 +11752,7 @@ const STYLES$1 = `
|
|
|
11694
11752
|
position: fixed; inset: 0; background: var(--ps-modal-overlay, rgba(0,0,0,0.6));
|
|
11695
11753
|
display: flex; align-items: center; justify-content: center;
|
|
11696
11754
|
z-index: 2147483647;
|
|
11755
|
+
pointer-events: auto;
|
|
11697
11756
|
isolation: isolate;
|
|
11698
11757
|
contain: layout style;
|
|
11699
11758
|
padding: 0.83vw;
|
|
@@ -12183,11 +12242,20 @@ const STYLES$1 = `
|
|
|
12183
12242
|
min-height: 0;
|
|
12184
12243
|
}
|
|
12185
12244
|
.ps-tryon-v2-result-panel .ps-tryon-photo-strip {
|
|
12186
|
-
flex: 0
|
|
12245
|
+
flex: 0 0 auto;
|
|
12187
12246
|
min-height: 0;
|
|
12247
|
+
margin-top: clamp(10px, 0.75vw, 14px);
|
|
12248
|
+
margin-bottom: clamp(8px, 0.7vw, 12px);
|
|
12188
12249
|
}
|
|
12189
12250
|
.ps-tryon-v2-result-panel .ps-tryon-sr-card-v2 {
|
|
12190
|
-
min-height: 10.5vw;
|
|
12251
|
+
min-height: clamp(140px, 10.5vw, 165px);
|
|
12252
|
+
}
|
|
12253
|
+
.ps-tryon-v2-result-panel .ps-tryon-sr-card-v2.ps-full {
|
|
12254
|
+
min-height: clamp(140px, 10.5vw, 165px);
|
|
12255
|
+
}
|
|
12256
|
+
.ps-tryon-v2-result-panel .ps-tryon-photo-strip-cell {
|
|
12257
|
+
aspect-ratio: 1 / 1;
|
|
12258
|
+
height: auto;
|
|
12191
12259
|
}
|
|
12192
12260
|
.ps-tryon-v2-result-actions {
|
|
12193
12261
|
display: flex;
|
|
@@ -12682,9 +12750,12 @@ const STYLES$1 = `
|
|
|
12682
12750
|
.ps-tryon-photo-strip-row {
|
|
12683
12751
|
display: grid;
|
|
12684
12752
|
grid-template-columns: repeat(3, 1fr);
|
|
12685
|
-
gap: 0.
|
|
12753
|
+
gap: 0.45vw;
|
|
12686
12754
|
animation: ps-tryon-photo-strip-fade 0.5s ease;
|
|
12687
12755
|
}
|
|
12756
|
+
.ps-tryon-photo-strip-row.ps-count-1 .ps-tryon-photo-strip-cell {
|
|
12757
|
+
grid-column: 2;
|
|
12758
|
+
}
|
|
12688
12759
|
.ps-tryon-photo-strip-cell {
|
|
12689
12760
|
position: relative;
|
|
12690
12761
|
display: block;
|
|
@@ -12707,7 +12778,7 @@ const STYLES$1 = `
|
|
|
12707
12778
|
object-position: center center;
|
|
12708
12779
|
padding: 0;
|
|
12709
12780
|
box-sizing: border-box;
|
|
12710
|
-
transform:
|
|
12781
|
+
transform: none;
|
|
12711
12782
|
transform-origin: center center;
|
|
12712
12783
|
user-select: none;
|
|
12713
12784
|
pointer-events: none;
|
|
@@ -12748,7 +12819,7 @@ const STYLES$1 = `
|
|
|
12748
12819
|
}
|
|
12749
12820
|
.ps-tryon-photo-strip-cell > img {
|
|
12750
12821
|
object-position: center center;
|
|
12751
|
-
transform:
|
|
12822
|
+
transform: none;
|
|
12752
12823
|
}
|
|
12753
12824
|
}
|
|
12754
12825
|
|
|
@@ -22269,7 +22340,7 @@ function ProductPhotoCarouselCard({
|
|
|
22269
22340
|
const slide = entries.slice(start, start + PER_SLIDE);
|
|
22270
22341
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-photo-strip", role: "group", "aria-label": t2("Product photos"), children: [
|
|
22271
22342
|
isCompleteLook && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-photo-strip-head", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-photo-strip-badge", children: t2("Complete the look") }) }),
|
|
22272
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className:
|
|
22343
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `ps-tryon-photo-strip-row ps-count-${slide.length}`, children: slide.map((item, i) => {
|
|
22273
22344
|
const content = /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: item.image, alt: item.title || productTitle || "", draggable: false });
|
|
22274
22345
|
return item.href ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22275
22346
|
"a",
|
|
@@ -32102,7 +32173,7 @@ if (typeof document !== "undefined") {
|
|
|
32102
32173
|
if (!document.getElementById(id2)) {
|
|
32103
32174
|
const el2 = document.createElement("style");
|
|
32104
32175
|
el2.id = id2;
|
|
32105
|
-
el2.textContent = STYLES
|
|
32176
|
+
el2.textContent = STYLES;
|
|
32106
32177
|
document.head.appendChild(el2);
|
|
32107
32178
|
}
|
|
32108
32179
|
}
|
|
@@ -32154,6 +32225,27 @@ function sanitizeHistoryEntry(entry) {
|
|
|
32154
32225
|
hasResult: entry.hasResult || !!entry.resultImageUrl || void 0
|
|
32155
32226
|
};
|
|
32156
32227
|
}
|
|
32228
|
+
function comparableProductId(value) {
|
|
32229
|
+
return String(value || "").trim().replace(/^gid:\/\/shopify\/Product\//i, "").replace(/^Product\//i, "");
|
|
32230
|
+
}
|
|
32231
|
+
function historyEntryMatchesProduct(entry, productId, productTitle) {
|
|
32232
|
+
const currentId = comparableProductId(productId);
|
|
32233
|
+
const entryId = comparableProductId(entry.productId);
|
|
32234
|
+
if (currentId && entryId) return currentId === entryId;
|
|
32235
|
+
const currentTitle = String(productTitle || "").trim().toLowerCase();
|
|
32236
|
+
const entryTitle = String(entry.productTitle || "").trim().toLowerCase();
|
|
32237
|
+
return !!currentTitle && !!entryTitle && currentTitle === entryTitle;
|
|
32238
|
+
}
|
|
32239
|
+
function hasCompletedTryOnResult(entry) {
|
|
32240
|
+
return !!(entry.resultImageUrl || entry.hasResult);
|
|
32241
|
+
}
|
|
32242
|
+
function dispatchTryOnCompleteEvent(detail) {
|
|
32243
|
+
if (typeof window === "undefined") return;
|
|
32244
|
+
try {
|
|
32245
|
+
window.dispatchEvent(new CustomEvent("primestyle:tryon-complete", { detail }));
|
|
32246
|
+
} catch {
|
|
32247
|
+
}
|
|
32248
|
+
}
|
|
32157
32249
|
function computeMatchScore(recData) {
|
|
32158
32250
|
if (!recData) return null;
|
|
32159
32251
|
const all = [];
|
|
@@ -32209,6 +32301,7 @@ function PrimeStyleTryonInner({
|
|
|
32209
32301
|
productDescription,
|
|
32210
32302
|
productMaterial,
|
|
32211
32303
|
buttonText,
|
|
32304
|
+
limitOneColorTryOnPerProduct = false,
|
|
32212
32305
|
apiUrl,
|
|
32213
32306
|
showPoweredBy = true,
|
|
32214
32307
|
showIcon = true,
|
|
@@ -33201,6 +33294,14 @@ function PrimeStyleTryonInner({
|
|
|
33201
33294
|
cleanupJob();
|
|
33202
33295
|
setTryOnProcessing(false);
|
|
33203
33296
|
setTryOnStartedAt(null);
|
|
33297
|
+
dispatchTryOnCompleteEvent({
|
|
33298
|
+
jobId: update.galleryId,
|
|
33299
|
+
historyEntryId: currentHistoryEntryIdRef.current,
|
|
33300
|
+
productId: effectiveProductId,
|
|
33301
|
+
productTitle,
|
|
33302
|
+
recommendedSize: sizingResultRef.current?.recommendedSize,
|
|
33303
|
+
resultImageUrl: update.imageUrl
|
|
33304
|
+
});
|
|
33204
33305
|
onComplete?.({ jobId: update.galleryId, imageUrl: update.imageUrl });
|
|
33205
33306
|
}
|
|
33206
33307
|
} else if (update.status === "failed") {
|
|
@@ -34404,6 +34505,21 @@ function PrimeStyleTryonInner({
|
|
|
34404
34505
|
setDrawer(null);
|
|
34405
34506
|
setView("size-result");
|
|
34406
34507
|
}, [cleanupJob, productId, productTitle, effectiveProductImages, effectiveProductCarouselItems]);
|
|
34508
|
+
const savedOneColorFitEntry = reactExports.useMemo(() => {
|
|
34509
|
+
if (!limitOneColorTryOnPerProduct) return null;
|
|
34510
|
+
return history.find(
|
|
34511
|
+
(entry) => hasCompletedTryOnResult(entry) && !!entry.recommendedSize && historyEntryMatchesProduct(entry, effectiveProductId, productTitle)
|
|
34512
|
+
) || null;
|
|
34513
|
+
}, [limitOneColorTryOnPerProduct, history, effectiveProductId, productTitle]);
|
|
34514
|
+
const storefrontButtonText = savedOneColorFitEntry?.recommendedSize ? `${t2("Your size is")} ${savedOneColorFitEntry.recommendedSize}` : resolvedButtonText;
|
|
34515
|
+
const handleStorefrontButtonClick = reactExports.useCallback(() => {
|
|
34516
|
+
if (savedOneColorFitEntry) {
|
|
34517
|
+
onOpen?.();
|
|
34518
|
+
restoreHistory(savedOneColorFitEntry);
|
|
34519
|
+
return;
|
|
34520
|
+
}
|
|
34521
|
+
handleOpen();
|
|
34522
|
+
}, [handleOpen, onOpen, restoreHistory, savedOneColorFitEntry]);
|
|
34407
34523
|
const updateField = reactExports.useCallback((key, val) => {
|
|
34408
34524
|
formRef.current[key] = val;
|
|
34409
34525
|
}, []);
|
|
@@ -34873,15 +34989,12 @@ function PrimeStyleTryonInner({
|
|
|
34873
34989
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
34874
34990
|
"button",
|
|
34875
34991
|
{
|
|
34876
|
-
onClick:
|
|
34877
|
-
console.log("[ps-sdk] button click event fired", e);
|
|
34878
|
-
handleOpen();
|
|
34879
|
-
},
|
|
34992
|
+
onClick: handleStorefrontButtonClick,
|
|
34880
34993
|
className: cx(cx("ps-tryon-btn", isTextTrigger ? "ps-tryon-btn--text" : void 0), cn.button),
|
|
34881
34994
|
type: "button",
|
|
34882
34995
|
children: [
|
|
34883
34996
|
!isTextTrigger && showIcon !== false && (buttonIcon || /* @__PURE__ */ jsxRuntimeExports.jsx(CameraIcon$1, {})),
|
|
34884
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children:
|
|
34997
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: storefrontButtonText })
|
|
34885
34998
|
]
|
|
34886
34999
|
}
|
|
34887
35000
|
),
|
|
@@ -35159,7 +35272,7 @@ class PrimeStyleTryonErrorBoundary extends reactExports.Component {
|
|
|
35159
35272
|
function PrimeStyleTryon(props) {
|
|
35160
35273
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(PrimeStyleTryonErrorBoundary, { ...props });
|
|
35161
35274
|
}
|
|
35162
|
-
const
|
|
35275
|
+
const SIZE_GUIDE_STYLES = `
|
|
35163
35276
|
.ps-sg-btn {
|
|
35164
35277
|
display: inline-flex;
|
|
35165
35278
|
align-items: center;
|
|
@@ -35322,7 +35435,7 @@ function injectStyles() {
|
|
|
35322
35435
|
if (stylesInjected) return;
|
|
35323
35436
|
const tag = document.createElement("style");
|
|
35324
35437
|
tag.id = "ps-sg-styles";
|
|
35325
|
-
tag.textContent =
|
|
35438
|
+
tag.textContent = SIZE_GUIDE_STYLES;
|
|
35326
35439
|
document.head.appendChild(tag);
|
|
35327
35440
|
stylesInjected = true;
|
|
35328
35441
|
}
|
|
@@ -35514,10 +35627,112 @@ function installProductViewTracking() {
|
|
|
35514
35627
|
roots.forEach((r2) => maybeFireProductView(r2));
|
|
35515
35628
|
}
|
|
35516
35629
|
const TAG = "[primestyle-tryon]";
|
|
35517
|
-
|
|
35630
|
+
const SHADOW_STYLE_ATTR = "data-primestyle-sdk";
|
|
35631
|
+
const DOCUMENT_STYLE_ATTR = "data-primestyle-sdk-document";
|
|
35632
|
+
const SHADOW_MOUNT_ATTR = "data-primestyle-mount";
|
|
35633
|
+
const PORTAL_HOST_ATTR = "data-primestyle-portal-host";
|
|
35634
|
+
const PORTAL_MOUNT_ATTR = "data-primestyle-portal-mount";
|
|
35635
|
+
const SDK_CSS = `${STYLES}
|
|
35636
|
+
|
|
35637
|
+
${SIZE_GUIDE_STYLES}`;
|
|
35638
|
+
console.log(`${TAG} storefront bundle loaded`);
|
|
35518
35639
|
installCartHook();
|
|
35519
35640
|
installProductViewTracking();
|
|
35520
35641
|
const MOUNTED = /* @__PURE__ */ new WeakMap();
|
|
35642
|
+
const MOUNT_SIGNATURES = /* @__PURE__ */ new WeakMap();
|
|
35643
|
+
const MOUNTING = /* @__PURE__ */ new WeakSet();
|
|
35644
|
+
function ensureDocumentStyles() {
|
|
35645
|
+
if (typeof document === "undefined" || !document.head) return;
|
|
35646
|
+
let styleTag = document.head.querySelector(`style[${DOCUMENT_STYLE_ATTR}]`);
|
|
35647
|
+
if (!styleTag) {
|
|
35648
|
+
styleTag = document.createElement("style");
|
|
35649
|
+
styleTag.setAttribute(DOCUMENT_STYLE_ATTR, "true");
|
|
35650
|
+
document.head.appendChild(styleTag);
|
|
35651
|
+
}
|
|
35652
|
+
if (styleTag.textContent !== SDK_CSS) {
|
|
35653
|
+
styleTag.textContent = SDK_CSS;
|
|
35654
|
+
}
|
|
35655
|
+
}
|
|
35656
|
+
function getPortalHost() {
|
|
35657
|
+
if (typeof document === "undefined" || !document.body) return void 0;
|
|
35658
|
+
let portalHost = document.querySelector(`[${PORTAL_HOST_ATTR}]`);
|
|
35659
|
+
if (!portalHost) {
|
|
35660
|
+
portalHost = document.createElement("div");
|
|
35661
|
+
portalHost.setAttribute(PORTAL_HOST_ATTR, "true");
|
|
35662
|
+
document.body.appendChild(portalHost);
|
|
35663
|
+
}
|
|
35664
|
+
portalHost.style.setProperty("display", "block", "important");
|
|
35665
|
+
portalHost.style.setProperty("position", "fixed", "important");
|
|
35666
|
+
portalHost.style.setProperty("inset", "0", "important");
|
|
35667
|
+
portalHost.style.setProperty("width", "100vw", "important");
|
|
35668
|
+
portalHost.style.setProperty("height", "100vh", "important");
|
|
35669
|
+
portalHost.style.setProperty("z-index", "2147483647", "important");
|
|
35670
|
+
portalHost.style.setProperty("visibility", "visible", "important");
|
|
35671
|
+
portalHost.style.setProperty("opacity", "1", "important");
|
|
35672
|
+
portalHost.style.setProperty("pointer-events", "none", "important");
|
|
35673
|
+
portalHost.style.setProperty("transform", "none", "important");
|
|
35674
|
+
portalHost.style.setProperty("margin", "0", "important");
|
|
35675
|
+
portalHost.style.setProperty("padding", "0", "important");
|
|
35676
|
+
if (typeof portalHost.attachShadow === "function") {
|
|
35677
|
+
try {
|
|
35678
|
+
const shadow = portalHost.shadowRoot || portalHost.attachShadow({ mode: "open" });
|
|
35679
|
+
let styleTag = shadow.querySelector(`style[${SHADOW_STYLE_ATTR}]`);
|
|
35680
|
+
if (!styleTag) {
|
|
35681
|
+
styleTag = document.createElement("style");
|
|
35682
|
+
styleTag.setAttribute(SHADOW_STYLE_ATTR, "true");
|
|
35683
|
+
shadow.appendChild(styleTag);
|
|
35684
|
+
}
|
|
35685
|
+
if (styleTag.textContent !== SDK_CSS) {
|
|
35686
|
+
styleTag.textContent = SDK_CSS;
|
|
35687
|
+
}
|
|
35688
|
+
let portalMount = shadow.querySelector(`[${PORTAL_MOUNT_ATTR}]`);
|
|
35689
|
+
if (!portalMount) {
|
|
35690
|
+
portalMount = document.createElement("div");
|
|
35691
|
+
portalMount.setAttribute(PORTAL_MOUNT_ATTR, "true");
|
|
35692
|
+
portalMount.className = "ps-tryon-portal-mount";
|
|
35693
|
+
shadow.appendChild(portalMount);
|
|
35694
|
+
}
|
|
35695
|
+
portalMount.style.setProperty("display", "block", "important");
|
|
35696
|
+
portalMount.style.setProperty("width", "100%", "important");
|
|
35697
|
+
portalMount.style.setProperty("height", "100%", "important");
|
|
35698
|
+
portalMount.style.setProperty("pointer-events", "none", "important");
|
|
35699
|
+
return portalMount;
|
|
35700
|
+
} catch (err) {
|
|
35701
|
+
console.warn(`${TAG} portal shadow DOM mount failed; falling back to page DOM`, err);
|
|
35702
|
+
}
|
|
35703
|
+
}
|
|
35704
|
+
ensureDocumentStyles();
|
|
35705
|
+
return portalHost;
|
|
35706
|
+
}
|
|
35707
|
+
function createShadowMountTarget(el2) {
|
|
35708
|
+
if (!(el2 instanceof HTMLElement) || typeof el2.attachShadow !== "function") {
|
|
35709
|
+
return { mountTarget: el2 };
|
|
35710
|
+
}
|
|
35711
|
+
try {
|
|
35712
|
+
const shadow = el2.shadowRoot || el2.attachShadow({ mode: "open" });
|
|
35713
|
+
let styleTag = shadow.querySelector(`style[${SHADOW_STYLE_ATTR}]`);
|
|
35714
|
+
if (!styleTag) {
|
|
35715
|
+
styleTag = document.createElement("style");
|
|
35716
|
+
styleTag.setAttribute(SHADOW_STYLE_ATTR, "true");
|
|
35717
|
+
shadow.appendChild(styleTag);
|
|
35718
|
+
}
|
|
35719
|
+
if (styleTag.textContent !== SDK_CSS) {
|
|
35720
|
+
styleTag.textContent = SDK_CSS;
|
|
35721
|
+
}
|
|
35722
|
+
let mountTarget = shadow.querySelector(`[${SHADOW_MOUNT_ATTR}]`);
|
|
35723
|
+
if (!mountTarget) {
|
|
35724
|
+
mountTarget = document.createElement("div");
|
|
35725
|
+
mountTarget.setAttribute(SHADOW_MOUNT_ATTR, "true");
|
|
35726
|
+
mountTarget.className = "ps-tryon-shadow-mount";
|
|
35727
|
+
shadow.appendChild(mountTarget);
|
|
35728
|
+
}
|
|
35729
|
+
el2.setAttribute("data-primestyle-shadow", "true");
|
|
35730
|
+
return { mountTarget, portalContainer: getPortalHost() ?? document.body };
|
|
35731
|
+
} catch (err) {
|
|
35732
|
+
console.warn(`${TAG} shadow DOM mount failed; falling back to page DOM`, err);
|
|
35733
|
+
return { mountTarget: el2 };
|
|
35734
|
+
}
|
|
35735
|
+
}
|
|
35521
35736
|
function readDataAttrs(el2) {
|
|
35522
35737
|
const out = {};
|
|
35523
35738
|
for (const attr of Array.from(el2.attributes)) {
|
|
@@ -35536,6 +35751,13 @@ function parseJsonAttr(raw, fallback) {
|
|
|
35536
35751
|
return fallback;
|
|
35537
35752
|
}
|
|
35538
35753
|
}
|
|
35754
|
+
function buildMountSignature(data) {
|
|
35755
|
+
const relevant = {};
|
|
35756
|
+
for (const key of Object.keys(data).sort()) {
|
|
35757
|
+
relevant[key] = data[key];
|
|
35758
|
+
}
|
|
35759
|
+
return JSON.stringify(relevant);
|
|
35760
|
+
}
|
|
35539
35761
|
function resolveProductUrl(raw) {
|
|
35540
35762
|
const source = raw || (typeof window !== "undefined" ? window.location.href : "");
|
|
35541
35763
|
if (!source) return void 0;
|
|
@@ -35556,13 +35778,18 @@ function buildPropsFromDataAttrs(data) {
|
|
|
35556
35778
|
productTitle: data.productTitle,
|
|
35557
35779
|
productUrl: resolveProductUrl(data.productUrl),
|
|
35558
35780
|
productImage: data.productImage,
|
|
35559
|
-
|
|
35781
|
+
productImages: parseJsonAttr(data.productImages, void 0),
|
|
35782
|
+
productCarouselItems: parseJsonAttr(
|
|
35783
|
+
data.productCarouselItems,
|
|
35784
|
+
void 0
|
|
35785
|
+
),
|
|
35560
35786
|
productDescription: data.productDescription,
|
|
35561
35787
|
productGender: data.productGender,
|
|
35562
35788
|
productType: data.productType,
|
|
35563
35789
|
productVendor: data.productVendor,
|
|
35564
35790
|
productTags: data.productTags ? data.productTags.split(",").map((t2) => t2.trim()).filter(Boolean) : void 0,
|
|
35565
35791
|
buttonText: data.buttonText || "Find Your Size",
|
|
35792
|
+
limitOneColorTryOnPerProduct: data.limitOneColorTryOnPerProduct === "true",
|
|
35566
35793
|
locale: data.locale,
|
|
35567
35794
|
sizeGuideData: parseJsonAttr(data.cachedSizeguide, void 0),
|
|
35568
35795
|
sizingCountry: data.sizingCountry,
|
|
@@ -35599,22 +35826,39 @@ async function fetchSizeGuideForProduct(proxyUrl, productId) {
|
|
|
35599
35826
|
}
|
|
35600
35827
|
}
|
|
35601
35828
|
async function mount(el2) {
|
|
35602
|
-
|
|
35603
|
-
|
|
35829
|
+
const data = readDataAttrs(el2);
|
|
35830
|
+
const signature = buildMountSignature(data);
|
|
35831
|
+
const existingRoot = MOUNTED.get(el2);
|
|
35832
|
+
if (existingRoot) {
|
|
35833
|
+
if (MOUNT_SIGNATURES.get(el2) === signature) {
|
|
35834
|
+
console.log(`${TAG} already mounted on`, el2);
|
|
35835
|
+
return;
|
|
35836
|
+
}
|
|
35837
|
+
console.log(`${TAG} data changed; remounting on`, el2);
|
|
35838
|
+
try {
|
|
35839
|
+
existingRoot.unmount();
|
|
35840
|
+
} catch (err) {
|
|
35841
|
+
console.warn(`${TAG} previous React root failed to unmount`, err);
|
|
35842
|
+
}
|
|
35843
|
+
MOUNTED.delete(el2);
|
|
35844
|
+
MOUNT_SIGNATURES.delete(el2);
|
|
35845
|
+
}
|
|
35846
|
+
if (MOUNTING.has(el2)) {
|
|
35847
|
+
console.log(`${TAG} mount already in progress on`, el2);
|
|
35604
35848
|
return;
|
|
35605
35849
|
}
|
|
35850
|
+
MOUNTING.add(el2);
|
|
35606
35851
|
console.log(`${TAG} mounting on element`, el2);
|
|
35607
|
-
const data = readDataAttrs(el2);
|
|
35608
35852
|
console.log(`${TAG} read data attributes`, data);
|
|
35609
35853
|
const props = buildPropsFromDataAttrs(data);
|
|
35610
|
-
const
|
|
35854
|
+
const shouldRenderStandaloneSizeGuide = !!data.cachedSizeguide && data.disableSizeGuideButton !== "true";
|
|
35611
35855
|
if (!props.sizeGuideData && props.productId && props.apiUrl) {
|
|
35612
35856
|
const fetched = await fetchSizeGuideForProduct(props.apiUrl, props.productId);
|
|
35613
35857
|
if (fetched) {
|
|
35614
35858
|
props.sizeGuideData = fetched;
|
|
35615
35859
|
}
|
|
35616
35860
|
}
|
|
35617
|
-
if (
|
|
35861
|
+
if (shouldRenderStandaloneSizeGuide && props.sizeGuideData) {
|
|
35618
35862
|
try {
|
|
35619
35863
|
const buttonStyles = props.buttonStyles;
|
|
35620
35864
|
createSizeGuideButton(el2, props.sizeGuideData, {
|
|
@@ -35626,13 +35870,22 @@ async function mount(el2) {
|
|
|
35626
35870
|
}
|
|
35627
35871
|
}
|
|
35628
35872
|
try {
|
|
35629
|
-
const
|
|
35630
|
-
root
|
|
35873
|
+
const { mountTarget, portalContainer } = createShadowMountTarget(el2);
|
|
35874
|
+
const root = createRoot(mountTarget);
|
|
35875
|
+
root.render(
|
|
35876
|
+
reactExports.createElement(PrimeStyleTryon, {
|
|
35877
|
+
...props,
|
|
35878
|
+
portalContainer
|
|
35879
|
+
})
|
|
35880
|
+
);
|
|
35631
35881
|
MOUNTED.set(el2, root);
|
|
35882
|
+
MOUNT_SIGNATURES.set(el2, signature);
|
|
35632
35883
|
console.log(`${TAG} ✓ mounted React component`);
|
|
35633
35884
|
maybeFireProductView(el2);
|
|
35634
35885
|
} catch (err) {
|
|
35635
35886
|
console.error(`${TAG} ✗ React mount failed`, err);
|
|
35887
|
+
} finally {
|
|
35888
|
+
MOUNTING.delete(el2);
|
|
35636
35889
|
}
|
|
35637
35890
|
}
|
|
35638
35891
|
function mountAll() {
|
|
@@ -29,6 +29,7 @@ interface ButtonOptions {
|
|
|
29
29
|
label?: string;
|
|
30
30
|
accentColor?: string;
|
|
31
31
|
}
|
|
32
|
+
export declare const SIZE_GUIDE_STYLES = "\n .ps-sg-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 14px;\n margin: 0 0 10px 0;\n background: transparent;\n border: 1px solid rgba(0, 0, 0, 0.12);\n border-radius: 8px;\n color: var(--ps-sg-accent, #2154EF);\n font-size: 13px;\n font-weight: 600;\n font-family: inherit;\n cursor: pointer;\n transition: background 0.15s, border-color 0.15s;\n }\n .ps-sg-btn:hover {\n background: rgba(33, 84, 239, 0.04);\n border-color: var(--ps-sg-accent, #2154EF);\n }\n .ps-sg-btn svg { width: 14px; height: 14px; }\n .ps-sg-overlay {\n position: fixed; inset: 0;\n background: rgba(15, 23, 42, 0.55);\n display: flex; align-items: center; justify-content: center;\n z-index: 99999;\n padding: 16px;\n opacity: 0;\n animation: ps-sg-fadein 0.18s ease forwards;\n }\n @keyframes ps-sg-fadein { to { opacity: 1; } }\n .ps-sg-modal {\n background: #FFFFFF;\n border-radius: 14px;\n width: 100%;\n max-width: 720px;\n max-height: 88vh;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n box-shadow: 0 24px 60px rgba(15, 23, 42, 0.25);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n color: #1f2937;\n }\n .ps-sg-header {\n display: flex; align-items: center; justify-content: space-between;\n padding: 18px 22px 14px;\n border-bottom: 1px solid rgba(15, 23, 42, 0.08);\n }\n .ps-sg-title {\n margin: 0;\n font-size: 17px;\n font-weight: 700;\n }\n .ps-sg-toggle {\n display: inline-flex;\n background: rgba(15, 23, 42, 0.06);\n border-radius: 8px;\n padding: 3px;\n margin-right: 12px;\n }\n .ps-sg-toggle button {\n padding: 5px 14px;\n background: transparent;\n border: none;\n border-radius: 6px;\n font-size: 11px;\n font-weight: 700;\n cursor: pointer;\n color: rgba(15, 23, 42, 0.55);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n font-family: inherit;\n }\n .ps-sg-toggle button.ps-sg-active {\n background: #FFFFFF;\n color: #1f2937;\n box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08);\n }\n .ps-sg-close {\n background: transparent;\n border: none;\n color: rgba(15, 23, 42, 0.55);\n cursor: pointer;\n padding: 4px;\n border-radius: 6px;\n font-family: inherit;\n }\n .ps-sg-close:hover { background: rgba(15, 23, 42, 0.06); }\n .ps-sg-close svg { width: 18px; height: 18px; }\n .ps-sg-body {\n padding: 18px 22px 22px;\n overflow-y: auto;\n flex: 1;\n }\n .ps-sg-section { margin-bottom: 22px; }\n .ps-sg-section:last-child { margin-bottom: 0; }\n .ps-sg-section-title {\n margin: 0 0 6px;\n font-size: 14px;\n font-weight: 700;\n color: #0f172a;\n }\n .ps-sg-section-desc {\n margin: 0 0 10px;\n font-size: 12px;\n color: rgba(15, 23, 42, 0.6);\n }\n .ps-sg-table-wrap {\n overflow-x: auto;\n border: 1px solid rgba(15, 23, 42, 0.08);\n border-radius: 10px;\n }\n .ps-sg-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 13px;\n }\n .ps-sg-table thead th {\n background: rgba(15, 23, 42, 0.04);\n padding: 10px 12px;\n text-align: left;\n font-weight: 700;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: rgba(15, 23, 42, 0.6);\n border-bottom: 1px solid rgba(15, 23, 42, 0.08);\n }\n .ps-sg-table tbody td {\n padding: 10px 12px;\n border-bottom: 1px solid rgba(15, 23, 42, 0.05);\n }\n .ps-sg-table tbody tr:last-child td { border-bottom: none; }\n .ps-sg-htm {\n margin-top: 18px;\n padding: 14px 16px;\n background: rgba(33, 84, 239, 0.05);\n border-radius: 10px;\n border: 1px solid rgba(33, 84, 239, 0.12);\n }\n .ps-sg-htm-title {\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--ps-sg-accent, #2154EF);\n margin-bottom: 8px;\n }\n .ps-sg-htm ul {\n margin: 0;\n padding-left: 18px;\n font-size: 12px;\n line-height: 1.6;\n color: #1f2937;\n }\n";
|
|
32
33
|
/**
|
|
33
34
|
* Create a "Size Guide" button and insert it as a sibling above the
|
|
34
35
|
* given parent element. Returns a teardown function that removes the
|
package/dist/types.d.ts
CHANGED
|
@@ -260,9 +260,9 @@ export interface FitAreaInfo {
|
|
|
260
260
|
section?: string;
|
|
261
261
|
/** Fit classification */
|
|
262
262
|
fit: "good" | "tight" | "loose" | "a-bit-tight" | "a-bit-loose" | "too-tight" | "too-loose";
|
|
263
|
-
/** User's measurement value in
|
|
263
|
+
/** User's measurement value in the same unit as garmentRange */
|
|
264
264
|
userValue?: number;
|
|
265
|
-
/** Garment's size
|
|
265
|
+
/** Garment's selected-size range for this area (e.g. "37-38 in") */
|
|
266
266
|
garmentRange?: string;
|
|
267
267
|
/** Normalised body coordinate — vertical position (0 = top, 1 = bottom) */
|
|
268
268
|
y?: number;
|