@thefittingroom/shop-ui 5.0.26 → 5.0.27
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/index.js +296 -105
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14100,6 +14100,40 @@ function _init$7() {
|
|
|
14100
14100
|
useMainStore.setState({
|
|
14101
14101
|
fittingRoom: items
|
|
14102
14102
|
});
|
|
14103
|
+
if (typeof window !== "undefined") {
|
|
14104
|
+
window.addEventListener("storage", (e) => {
|
|
14105
|
+
if (e.key !== STORAGE_KEY) {
|
|
14106
|
+
return;
|
|
14107
|
+
}
|
|
14108
|
+
useMainStore.setState({
|
|
14109
|
+
fittingRoom: readFittingRoom(brandId)
|
|
14110
|
+
});
|
|
14111
|
+
});
|
|
14112
|
+
}
|
|
14113
|
+
}
|
|
14114
|
+
function resolveCurrentProductCsaId(productId, size, color) {
|
|
14115
|
+
if (size == null) {
|
|
14116
|
+
return null;
|
|
14117
|
+
}
|
|
14118
|
+
const {
|
|
14119
|
+
currentProduct
|
|
14120
|
+
} = getStaticData();
|
|
14121
|
+
if (!currentProduct) {
|
|
14122
|
+
return null;
|
|
14123
|
+
}
|
|
14124
|
+
const stored = useMainStore.getState().productData[productId];
|
|
14125
|
+
if (!stored || "error" in stored) {
|
|
14126
|
+
return null;
|
|
14127
|
+
}
|
|
14128
|
+
const sizeRec = stored.sizeFitRecommendation.available_sizes.find((s) => getSizeLabelFromSize(s) === size);
|
|
14129
|
+
if (!sizeRec) {
|
|
14130
|
+
return null;
|
|
14131
|
+
}
|
|
14132
|
+
const csa = sizeRec.colorway_size_assets.find((c) => {
|
|
14133
|
+
const variant = currentProduct.variants.find((v) => v.sku === c.sku);
|
|
14134
|
+
return variant?.color === color;
|
|
14135
|
+
});
|
|
14136
|
+
return csa?.id ?? null;
|
|
14103
14137
|
}
|
|
14104
14138
|
async function addFittingRoomItem(productId, handle, isPdp) {
|
|
14105
14139
|
const state = useMainStore.getState();
|
|
@@ -14108,9 +14142,7 @@ async function addFittingRoomItem(productId, handle, isPdp) {
|
|
|
14108
14142
|
handle,
|
|
14109
14143
|
isPdp
|
|
14110
14144
|
});
|
|
14111
|
-
let size = null;
|
|
14112
14145
|
let color = null;
|
|
14113
|
-
let colorwaySizeAssetId = null;
|
|
14114
14146
|
let resolvedHandle = handle;
|
|
14115
14147
|
if (isPdp) {
|
|
14116
14148
|
const {
|
|
@@ -14122,37 +14154,59 @@ async function addFittingRoomItem(productId, handle, isPdp) {
|
|
|
14122
14154
|
}
|
|
14123
14155
|
try {
|
|
14124
14156
|
const selection = await currentProduct.getSelectedOptions();
|
|
14125
|
-
size = selection.size || null;
|
|
14126
14157
|
color = selection.color;
|
|
14127
14158
|
} catch (error) {
|
|
14128
14159
|
logger$g.logWarn("Failed to read selected options from currentProduct", {
|
|
14129
14160
|
error
|
|
14130
14161
|
});
|
|
14131
14162
|
}
|
|
14132
|
-
const stored = state.productData[productId];
|
|
14133
|
-
if (stored && !("error" in stored) && size != null) {
|
|
14134
|
-
const sizeRec = stored.sizeFitRecommendation.available_sizes.find((s) => getSizeLabelFromSize(s) === size);
|
|
14135
|
-
if (sizeRec) {
|
|
14136
|
-
const csa = sizeRec.colorway_size_assets.find((c) => {
|
|
14137
|
-
const variant = currentProduct.variants.find((v) => v.sku === c.sku);
|
|
14138
|
-
return variant?.color === color;
|
|
14139
|
-
});
|
|
14140
|
-
if (csa) {
|
|
14141
|
-
colorwaySizeAssetId = csa.id;
|
|
14142
|
-
}
|
|
14143
|
-
}
|
|
14144
|
-
}
|
|
14145
14163
|
}
|
|
14146
14164
|
}
|
|
14147
14165
|
state.addToFittingRoom({
|
|
14148
14166
|
externalId: productId,
|
|
14149
14167
|
handle: resolvedHandle,
|
|
14150
|
-
size,
|
|
14168
|
+
size: null,
|
|
14151
14169
|
color,
|
|
14152
|
-
colorwaySizeAssetId,
|
|
14170
|
+
colorwaySizeAssetId: null,
|
|
14153
14171
|
addedAt: Date.now()
|
|
14154
14172
|
});
|
|
14155
14173
|
}
|
|
14174
|
+
async function syncCurrentProductSelection() {
|
|
14175
|
+
const {
|
|
14176
|
+
currentProduct
|
|
14177
|
+
} = getStaticData();
|
|
14178
|
+
if (!currentProduct) {
|
|
14179
|
+
return;
|
|
14180
|
+
}
|
|
14181
|
+
const state = useMainStore.getState();
|
|
14182
|
+
const existing = state.fittingRoom.find((item) => item.externalId === currentProduct.externalId);
|
|
14183
|
+
if (!existing) {
|
|
14184
|
+
return;
|
|
14185
|
+
}
|
|
14186
|
+
let color = null;
|
|
14187
|
+
try {
|
|
14188
|
+
const selection = await currentProduct.getSelectedOptions();
|
|
14189
|
+
color = selection.color;
|
|
14190
|
+
} catch (error) {
|
|
14191
|
+
logger$g.logWarn("syncCurrentProductSelection: failed to read selected options", {
|
|
14192
|
+
error
|
|
14193
|
+
});
|
|
14194
|
+
return;
|
|
14195
|
+
}
|
|
14196
|
+
if (color === existing.color) {
|
|
14197
|
+
return;
|
|
14198
|
+
}
|
|
14199
|
+
const colorwaySizeAssetId = resolveCurrentProductCsaId(currentProduct.externalId, existing.size, color);
|
|
14200
|
+
state.updateFittingRoomItem(currentProduct.externalId, {
|
|
14201
|
+
color,
|
|
14202
|
+
colorwaySizeAssetId
|
|
14203
|
+
});
|
|
14204
|
+
logger$g.logDebug("{{ts}} - Synced PDP color into fitting-room", {
|
|
14205
|
+
externalId: currentProduct.externalId,
|
|
14206
|
+
color,
|
|
14207
|
+
colorwaySizeAssetId
|
|
14208
|
+
});
|
|
14209
|
+
}
|
|
14156
14210
|
async function toggleFittingRoomItem(productId, handle, isPdp) {
|
|
14157
14211
|
const state = useMainStore.getState();
|
|
14158
14212
|
const isInFittingRoom = state.fittingRoom.some((item) => item.externalId === productId);
|
|
@@ -42201,7 +42255,12 @@ function AvatarControls({
|
|
|
42201
42255
|
// clip rendered the text at fractional opacity while it reflowed each
|
|
42202
42256
|
// frame, which subpixel-shimmered. The max-width clip alone reveals
|
|
42203
42257
|
// the label cleanly at full opacity.
|
|
42204
|
-
transition: "max-width 500ms cubic-bezier(0.22, 1, 0.36, 1)"
|
|
42258
|
+
transition: "max-width 500ms cubic-bezier(0.22, 1, 0.36, 1)",
|
|
42259
|
+
// Belt-and-suspenders with pillBaseStyle on the parent — rapid clicks
|
|
42260
|
+
// on the avatar's rotation chevrons can otherwise extend a triple-
|
|
42261
|
+
// click selection into these labels.
|
|
42262
|
+
userSelect: "none",
|
|
42263
|
+
WebkitUserSelect: "none"
|
|
42205
42264
|
},
|
|
42206
42265
|
pillLabelCollapsed: {
|
|
42207
42266
|
maxWidth: 0
|
|
@@ -42317,37 +42376,43 @@ function MobileTuckControl({
|
|
|
42317
42376
|
] }) });
|
|
42318
42377
|
}
|
|
42319
42378
|
const DRAG_STEP_PX = 50;
|
|
42320
|
-
|
|
42379
|
+
const AXIS_LOCK_PX$1 = 8;
|
|
42380
|
+
function applyDragSteps(deltaX, rotateLeft, rotateRight) {
|
|
42381
|
+
const steps = Math.floor(Math.abs(deltaX) / DRAG_STEP_PX);
|
|
42382
|
+
if (steps === 0) {
|
|
42383
|
+
return 0;
|
|
42384
|
+
}
|
|
42385
|
+
const fn = deltaX > 0 ? rotateRight : rotateLeft;
|
|
42386
|
+
for (let i = 0; i < steps; i++) {
|
|
42387
|
+
fn();
|
|
42388
|
+
}
|
|
42389
|
+
return (deltaX > 0 ? 1 : -1) * steps * DRAG_STEP_PX;
|
|
42390
|
+
}
|
|
42391
|
+
function useFrameRotation(frameUrls, setSelectedFrameIndex, onUserInteract) {
|
|
42321
42392
|
const frameCount = frameUrls?.length ?? 0;
|
|
42322
42393
|
const rotateLeft = reactExports.useCallback(() => {
|
|
42394
|
+
onUserInteract?.();
|
|
42323
42395
|
setSelectedFrameIndex((prev2) => {
|
|
42324
42396
|
if (prev2 == null || frameCount === 0) {
|
|
42325
42397
|
return prev2;
|
|
42326
42398
|
}
|
|
42327
42399
|
return prev2 === 0 ? frameCount - 1 : prev2 - 1;
|
|
42328
42400
|
});
|
|
42329
|
-
}, [frameCount, setSelectedFrameIndex]);
|
|
42401
|
+
}, [frameCount, onUserInteract, setSelectedFrameIndex]);
|
|
42330
42402
|
const rotateRight = reactExports.useCallback(() => {
|
|
42403
|
+
onUserInteract?.();
|
|
42331
42404
|
setSelectedFrameIndex((prev2) => {
|
|
42332
42405
|
if (prev2 == null || frameCount === 0) {
|
|
42333
42406
|
return prev2;
|
|
42334
42407
|
}
|
|
42335
42408
|
return prev2 === frameCount - 1 ? 0 : prev2 + 1;
|
|
42336
42409
|
});
|
|
42337
|
-
}, [frameCount, setSelectedFrameIndex]);
|
|
42410
|
+
}, [frameCount, onUserInteract, setSelectedFrameIndex]);
|
|
42338
42411
|
const handleMouseDragStart = reactExports.useCallback((e) => {
|
|
42339
42412
|
e.preventDefault();
|
|
42340
42413
|
let startX = e.clientX;
|
|
42341
42414
|
const onMove = (move) => {
|
|
42342
|
-
|
|
42343
|
-
if (Math.abs(deltaX) >= DRAG_STEP_PX) {
|
|
42344
|
-
if (deltaX > 0) {
|
|
42345
|
-
rotateRight();
|
|
42346
|
-
} else {
|
|
42347
|
-
rotateLeft();
|
|
42348
|
-
}
|
|
42349
|
-
startX = move.clientX;
|
|
42350
|
-
}
|
|
42415
|
+
startX += applyDragSteps(move.clientX - startX, rotateLeft, rotateRight);
|
|
42351
42416
|
};
|
|
42352
42417
|
const onUp = () => {
|
|
42353
42418
|
window.removeEventListener("mousemove", onMove);
|
|
@@ -42357,25 +42422,37 @@ function useFrameRotation(frameUrls, setSelectedFrameIndex) {
|
|
|
42357
42422
|
window.addEventListener("mouseup", onUp);
|
|
42358
42423
|
}, [rotateLeft, rotateRight]);
|
|
42359
42424
|
const handleTouchDragStart = reactExports.useCallback((e) => {
|
|
42360
|
-
e.preventDefault();
|
|
42361
42425
|
let startX = e.touches[0].clientX;
|
|
42426
|
+
const startY = e.touches[0].clientY;
|
|
42427
|
+
let mode = "unknown";
|
|
42362
42428
|
const onMove = (move) => {
|
|
42363
|
-
const
|
|
42364
|
-
|
|
42365
|
-
|
|
42366
|
-
|
|
42367
|
-
|
|
42368
|
-
|
|
42429
|
+
const currentX = move.touches[0].clientX;
|
|
42430
|
+
const currentY = move.touches[0].clientY;
|
|
42431
|
+
if (mode === "unknown") {
|
|
42432
|
+
const absDx = Math.abs(currentX - startX);
|
|
42433
|
+
const absDy = Math.abs(currentY - startY);
|
|
42434
|
+
if (absDx < AXIS_LOCK_PX$1 && absDy < AXIS_LOCK_PX$1) {
|
|
42435
|
+
return;
|
|
42369
42436
|
}
|
|
42370
|
-
|
|
42437
|
+
mode = absDx >= absDy ? "horizontal" : "vertical";
|
|
42438
|
+
startX = currentX;
|
|
42371
42439
|
}
|
|
42440
|
+
if (mode !== "horizontal") {
|
|
42441
|
+
return;
|
|
42442
|
+
}
|
|
42443
|
+
move.preventDefault();
|
|
42444
|
+
startX += applyDragSteps(currentX - startX, rotateLeft, rotateRight);
|
|
42372
42445
|
};
|
|
42373
42446
|
const onEnd = () => {
|
|
42374
42447
|
window.removeEventListener("touchmove", onMove);
|
|
42375
42448
|
window.removeEventListener("touchend", onEnd);
|
|
42449
|
+
window.removeEventListener("touchcancel", onEnd);
|
|
42376
42450
|
};
|
|
42377
|
-
window.addEventListener("touchmove", onMove
|
|
42451
|
+
window.addEventListener("touchmove", onMove, {
|
|
42452
|
+
passive: false
|
|
42453
|
+
});
|
|
42378
42454
|
window.addEventListener("touchend", onEnd);
|
|
42455
|
+
window.addEventListener("touchcancel", onEnd);
|
|
42379
42456
|
}, [rotateLeft, rotateRight]);
|
|
42380
42457
|
return {
|
|
42381
42458
|
rotateLeft,
|
|
@@ -42390,7 +42467,8 @@ function AvatarFrameViewer({
|
|
|
42390
42467
|
setSelectedFrameIndex,
|
|
42391
42468
|
imageContainerStyle,
|
|
42392
42469
|
imageStyle,
|
|
42393
|
-
loadingT = "quick-view.avatar_loading"
|
|
42470
|
+
loadingT = "quick-view.avatar_loading",
|
|
42471
|
+
onUserInteract
|
|
42394
42472
|
}) {
|
|
42395
42473
|
const css2 = useCss((_theme) => ({
|
|
42396
42474
|
imageContainer: {
|
|
@@ -42398,21 +42476,31 @@ function AvatarFrameViewer({
|
|
|
42398
42476
|
},
|
|
42399
42477
|
image: {
|
|
42400
42478
|
objectFit: "contain",
|
|
42401
|
-
cursor: "grab"
|
|
42479
|
+
cursor: "grab",
|
|
42480
|
+
// Reserve horizontal touch gestures for our rotation handler — the
|
|
42481
|
+
// browser can still pan vertically natively. Without this, the
|
|
42482
|
+
// browser may start consuming a horizontal swipe as a scroll/zoom
|
|
42483
|
+
// before our touchmove listener can preventDefault, which produced
|
|
42484
|
+
// the "janky first swipe" reports.
|
|
42485
|
+
touchAction: "pan-y"
|
|
42402
42486
|
},
|
|
42403
42487
|
chevronLeftContainer: {
|
|
42404
42488
|
position: "absolute",
|
|
42405
42489
|
top: "50%",
|
|
42406
42490
|
left: "0",
|
|
42407
42491
|
transform: "translateY(-50%)",
|
|
42408
|
-
cursor: "pointer"
|
|
42492
|
+
cursor: "pointer",
|
|
42493
|
+
userSelect: "none",
|
|
42494
|
+
WebkitUserSelect: "none"
|
|
42409
42495
|
},
|
|
42410
42496
|
chevronRightContainer: {
|
|
42411
42497
|
position: "absolute",
|
|
42412
42498
|
top: "50%",
|
|
42413
42499
|
right: "0",
|
|
42414
42500
|
transform: "translateY(-50%)",
|
|
42415
|
-
cursor: "pointer"
|
|
42501
|
+
cursor: "pointer",
|
|
42502
|
+
userSelect: "none",
|
|
42503
|
+
WebkitUserSelect: "none"
|
|
42416
42504
|
},
|
|
42417
42505
|
chevronIcon: {
|
|
42418
42506
|
width: "48px",
|
|
@@ -42420,46 +42508,83 @@ function AvatarFrameViewer({
|
|
|
42420
42508
|
}
|
|
42421
42509
|
}));
|
|
42422
42510
|
reactExports.useEffect(() => {
|
|
42423
|
-
if (
|
|
42424
|
-
|
|
42511
|
+
if (frameUrls && frameUrls.length > 0 && selectedFrameIndex == null) {
|
|
42512
|
+
setSelectedFrameIndex(0);
|
|
42425
42513
|
}
|
|
42426
|
-
let currentFrameIndex = 0;
|
|
42427
|
-
setSelectedFrameIndex(currentFrameIndex);
|
|
42428
|
-
const intervalId = setInterval(() => {
|
|
42429
|
-
currentFrameIndex = (currentFrameIndex + 1) % frameUrls.length;
|
|
42430
|
-
setSelectedFrameIndex(currentFrameIndex);
|
|
42431
|
-
if (currentFrameIndex === 0) {
|
|
42432
|
-
clearInterval(intervalId);
|
|
42433
|
-
}
|
|
42434
|
-
}, 500);
|
|
42435
|
-
return () => clearInterval(intervalId);
|
|
42436
42514
|
}, [frameUrls, selectedFrameIndex, setSelectedFrameIndex]);
|
|
42437
42515
|
const {
|
|
42438
42516
|
rotateLeft,
|
|
42439
42517
|
rotateRight,
|
|
42440
42518
|
handleMouseDragStart,
|
|
42441
42519
|
handleTouchDragStart
|
|
42442
|
-
} = useFrameRotation(frameUrls, setSelectedFrameIndex);
|
|
42520
|
+
} = useFrameRotation(frameUrls, setSelectedFrameIndex, onUserInteract);
|
|
42443
42521
|
if (!frameUrls || selectedFrameIndex == null) {
|
|
42444
42522
|
return /* @__PURE__ */ jsx$1(Loading, { t: loadingT });
|
|
42445
42523
|
}
|
|
42446
42524
|
return /* @__PURE__ */ jsxs("div", { css: css2.imageContainer, style: imageContainerStyle, children: [
|
|
42447
42525
|
/* @__PURE__ */ jsx$1("img", { src: frameUrls[selectedFrameIndex], css: css2.image, style: imageStyle, onMouseDown: handleMouseDragStart, onTouchStart: handleTouchDragStart }),
|
|
42448
|
-
/* @__PURE__ */ jsx$1("div", { css: css2.chevronLeftContainer, onClick: rotateLeft, children: /* @__PURE__ */ jsx$1(SvgChevronLeft, { css: css2.chevronIcon }) }),
|
|
42449
|
-
/* @__PURE__ */ jsx$1("div", { css: css2.chevronRightContainer, onClick: rotateRight, children: /* @__PURE__ */ jsx$1(SvgChevronRight, { css: css2.chevronIcon }) })
|
|
42526
|
+
/* @__PURE__ */ jsx$1("div", { role: "button", "aria-label": "Rotate left", css: css2.chevronLeftContainer, onMouseDown: (e) => e.preventDefault(), onClick: rotateLeft, children: /* @__PURE__ */ jsx$1(SvgChevronLeft, { css: css2.chevronIcon }) }),
|
|
42527
|
+
/* @__PURE__ */ jsx$1("div", { role: "button", "aria-label": "Rotate right", css: css2.chevronRightContainer, onMouseDown: (e) => e.preventDefault(), onClick: rotateRight, children: /* @__PURE__ */ jsx$1(SvgChevronRight, { css: css2.chevronIcon }) })
|
|
42450
42528
|
] });
|
|
42451
42529
|
}
|
|
42530
|
+
const AUTO_ROTATE_DURATION_MS = 4e3;
|
|
42531
|
+
function useAutoRotate(trigger, frameUrls, selectedFrameIndex, setSelectedFrameIndex) {
|
|
42532
|
+
const lastFiredRef = reactExports.useRef(void 0);
|
|
42533
|
+
const intervalIdRef = reactExports.useRef(null);
|
|
42534
|
+
const indexRef = reactExports.useRef(selectedFrameIndex);
|
|
42535
|
+
reactExports.useEffect(() => {
|
|
42536
|
+
indexRef.current = selectedFrameIndex;
|
|
42537
|
+
}, [selectedFrameIndex]);
|
|
42538
|
+
const cancelAutoRotate = reactExports.useCallback(() => {
|
|
42539
|
+
if (intervalIdRef.current !== null) {
|
|
42540
|
+
clearInterval(intervalIdRef.current);
|
|
42541
|
+
intervalIdRef.current = null;
|
|
42542
|
+
}
|
|
42543
|
+
}, []);
|
|
42544
|
+
const frameCount = frameUrls?.length ?? 0;
|
|
42545
|
+
reactExports.useEffect(() => {
|
|
42546
|
+
if (trigger === void 0) {
|
|
42547
|
+
return;
|
|
42548
|
+
}
|
|
42549
|
+
if (frameCount === 0) {
|
|
42550
|
+
return;
|
|
42551
|
+
}
|
|
42552
|
+
if (trigger === lastFiredRef.current) {
|
|
42553
|
+
return;
|
|
42554
|
+
}
|
|
42555
|
+
const tickMs = Math.round(AUTO_ROTATE_DURATION_MS / frameCount);
|
|
42556
|
+
const startFrameIndex = (indexRef.current ?? 0) % frameCount;
|
|
42557
|
+
let currentFrameIndex = startFrameIndex;
|
|
42558
|
+
let didFirstTick = false;
|
|
42559
|
+
intervalIdRef.current = setInterval(() => {
|
|
42560
|
+
if (!didFirstTick) {
|
|
42561
|
+
didFirstTick = true;
|
|
42562
|
+
lastFiredRef.current = trigger;
|
|
42563
|
+
}
|
|
42564
|
+
const nextFrameIndex = (currentFrameIndex + 1) % frameCount;
|
|
42565
|
+
currentFrameIndex = nextFrameIndex;
|
|
42566
|
+
setSelectedFrameIndex(nextFrameIndex);
|
|
42567
|
+
if (nextFrameIndex === startFrameIndex) {
|
|
42568
|
+
cancelAutoRotate();
|
|
42569
|
+
}
|
|
42570
|
+
}, tickMs);
|
|
42571
|
+
return cancelAutoRotate;
|
|
42572
|
+
}, [trigger, frameCount, setSelectedFrameIndex, cancelAutoRotate]);
|
|
42573
|
+
return cancelAutoRotate;
|
|
42574
|
+
}
|
|
42452
42575
|
function AvatarPane({
|
|
42453
42576
|
frameUrls,
|
|
42454
42577
|
hasSelection,
|
|
42455
42578
|
controls,
|
|
42456
42579
|
mobileFullscreen,
|
|
42457
42580
|
selectedFrameIndex: indexProp,
|
|
42458
|
-
setSelectedFrameIndex: setIndexProp
|
|
42581
|
+
setSelectedFrameIndex: setIndexProp,
|
|
42582
|
+
autoRotateTrigger
|
|
42459
42583
|
}) {
|
|
42460
42584
|
const [localFrameIndex, setLocalFrameIndex] = reactExports.useState(null);
|
|
42461
42585
|
const selectedFrameIndex = indexProp !== void 0 ? indexProp : localFrameIndex;
|
|
42462
42586
|
const setSelectedFrameIndex = setIndexProp ?? setLocalFrameIndex;
|
|
42587
|
+
const cancelAutoRotate = useAutoRotate(autoRotateTrigger, frameUrls, selectedFrameIndex, setSelectedFrameIndex);
|
|
42463
42588
|
const css2 = useCss((theme) => ({
|
|
42464
42589
|
container: {
|
|
42465
42590
|
width: "100%",
|
|
@@ -42517,7 +42642,7 @@ function AvatarPane({
|
|
|
42517
42642
|
}
|
|
42518
42643
|
}));
|
|
42519
42644
|
if (frameUrls && frameUrls.length > 0) {
|
|
42520
|
-
const viewer = /* @__PURE__ */ jsx$1(AvatarFrameViewer, { frameUrls, selectedFrameIndex, setSelectedFrameIndex, imageContainerStyle: css2.frameContainer, imageStyle: css2.frameImage, loadingT: "quick-view.avatar_loading" });
|
|
42645
|
+
const viewer = /* @__PURE__ */ jsx$1(AvatarFrameViewer, { frameUrls, selectedFrameIndex, setSelectedFrameIndex, imageContainerStyle: css2.frameContainer, imageStyle: css2.frameImage, loadingT: "quick-view.avatar_loading", onUserInteract: cancelAutoRotate });
|
|
42521
42646
|
if (mobileFullscreen) {
|
|
42522
42647
|
return /* @__PURE__ */ jsxs("div", { css: css2.mobileContainer, children: [
|
|
42523
42648
|
/* @__PURE__ */ jsxs("div", { css: css2.mobileFrameSlot, children: [
|
|
@@ -42644,8 +42769,9 @@ function ProductCard({
|
|
|
42644
42769
|
onClick();
|
|
42645
42770
|
};
|
|
42646
42771
|
const name2 = item.merchantProduct?.productName ?? item.externalId;
|
|
42647
|
-
const
|
|
42648
|
-
const
|
|
42772
|
+
const selectedVariant = item.merchantProduct?.variants.find((v) => v.color === item.storage.color && (!item.storage.size || v.size === item.storage.size));
|
|
42773
|
+
const imageUrl = selectedVariant?.imageUrl ?? item.merchantProduct?.imageUrl ?? null;
|
|
42774
|
+
const price = selectedVariant?.priceFormatted ?? item.merchantProduct?.variants[0]?.priceFormatted ?? null;
|
|
42649
42775
|
return /* @__PURE__ */ jsxs("div", { css: /* @__PURE__ */ css$1({
|
|
42650
42776
|
...css2.container,
|
|
42651
42777
|
...selected && css2.containerSelected,
|
|
@@ -43353,7 +43479,6 @@ function DetailAccordion({
|
|
|
43353
43479
|
}) });
|
|
43354
43480
|
}
|
|
43355
43481
|
const AXIS_LOCK_PX = 8;
|
|
43356
|
-
const ROTATE_STEP_PX = 50;
|
|
43357
43482
|
function ZoomModal({
|
|
43358
43483
|
frameUrls,
|
|
43359
43484
|
selectedFrameIndex,
|
|
@@ -43399,15 +43524,7 @@ function ZoomModal({
|
|
|
43399
43524
|
if (mode === "scroll" && scrollArea) {
|
|
43400
43525
|
scrollArea.scrollTop = startScrollTop - deltaY;
|
|
43401
43526
|
} else if (mode === "rotate") {
|
|
43402
|
-
|
|
43403
|
-
if (Math.abs(rotateDelta) >= ROTATE_STEP_PX) {
|
|
43404
|
-
if (rotateDelta > 0) {
|
|
43405
|
-
rotateRight();
|
|
43406
|
-
} else {
|
|
43407
|
-
rotateLeft();
|
|
43408
|
-
}
|
|
43409
|
-
lastRotateX = move.clientX;
|
|
43410
|
-
}
|
|
43527
|
+
lastRotateX += applyDragSteps(move.clientX - lastRotateX, rotateLeft, rotateRight);
|
|
43411
43528
|
}
|
|
43412
43529
|
};
|
|
43413
43530
|
const onUp = () => {
|
|
@@ -43453,7 +43570,11 @@ function ZoomModal({
|
|
|
43453
43570
|
transform: "translateY(-50%)",
|
|
43454
43571
|
display: "flex",
|
|
43455
43572
|
cursor: "pointer",
|
|
43456
|
-
zIndex: 1
|
|
43573
|
+
zIndex: 1,
|
|
43574
|
+
// Rapid clicks shouldn't initiate a text-selection drag into the
|
|
43575
|
+
// close-button glyph or any other overlay text.
|
|
43576
|
+
userSelect: "none",
|
|
43577
|
+
WebkitUserSelect: "none"
|
|
43457
43578
|
},
|
|
43458
43579
|
chevronLeft: {
|
|
43459
43580
|
left: "8px"
|
|
@@ -43499,11 +43620,11 @@ function ZoomModal({
|
|
|
43499
43620
|
/* @__PURE__ */ jsx$1("div", { css: /* @__PURE__ */ css$1({
|
|
43500
43621
|
...css2.chevron,
|
|
43501
43622
|
...css2.chevronLeft
|
|
43502
|
-
}, "", ""), onClick: rotateLeft, children: /* @__PURE__ */ jsx$1(SvgChevronLeft, { css: css2.chevronIcon }) }),
|
|
43623
|
+
}, "", ""), onMouseDown: (e) => e.preventDefault(), onClick: rotateLeft, children: /* @__PURE__ */ jsx$1(SvgChevronLeft, { css: css2.chevronIcon }) }),
|
|
43503
43624
|
/* @__PURE__ */ jsx$1("div", { css: /* @__PURE__ */ css$1({
|
|
43504
43625
|
...css2.chevron,
|
|
43505
43626
|
...css2.chevronRight
|
|
43506
|
-
}, "", ""), onClick: rotateRight, children: /* @__PURE__ */ jsx$1(SvgChevronRight, { css: css2.chevronIcon }) }),
|
|
43627
|
+
}, "", ""), onMouseDown: (e) => e.preventDefault(), onClick: rotateRight, children: /* @__PURE__ */ jsx$1(SvgChevronRight, { css: css2.chevronIcon }) }),
|
|
43507
43628
|
/* @__PURE__ */ jsx$1("button", { css: css2.close, onClick: onClose, "aria-label": "Close zoom", children: "×" })
|
|
43508
43629
|
] });
|
|
43509
43630
|
}
|
|
@@ -43523,6 +43644,7 @@ function DesktopLayout$1({
|
|
|
43523
43644
|
forceUntuck,
|
|
43524
43645
|
canTuck,
|
|
43525
43646
|
frameUrls,
|
|
43647
|
+
autoRotateTrigger,
|
|
43526
43648
|
onSelectItem,
|
|
43527
43649
|
onRemoveItem,
|
|
43528
43650
|
onOpenAccordionItem,
|
|
@@ -43624,7 +43746,7 @@ function DesktopLayout$1({
|
|
|
43624
43746
|
return /* @__PURE__ */ jsxs("div", { ref: containerRef, css: css2.container, style: {
|
|
43625
43747
|
gridTemplateColumns
|
|
43626
43748
|
}, children: [
|
|
43627
|
-
/* @__PURE__ */ jsx$1("div", { css: css2.avatarColumn, onMouseEnter: () => setAvatarHovered(true), onMouseLeave: () => setAvatarHovered(false), children: /* @__PURE__ */ jsx$1(AvatarPane, { hasSelection, frameUrls, controls, selectedFrameIndex, setSelectedFrameIndex }) }),
|
|
43749
|
+
/* @__PURE__ */ jsx$1("div", { css: css2.avatarColumn, onMouseEnter: () => setAvatarHovered(true), onMouseLeave: () => setAvatarHovered(false), children: /* @__PURE__ */ jsx$1(AvatarPane, { hasSelection, frameUrls, controls, selectedFrameIndex, setSelectedFrameIndex, autoRotateTrigger }) }),
|
|
43628
43750
|
hasSelection ? /* @__PURE__ */ jsx$1("div", { css: css2.detailColumn, children: /* @__PURE__ */ jsx$1(DetailAccordion, { items: selectedItems, openItemExternalId: openAccordionItemId, platform: "desktop", detailMode, isMobileQuickRow: false, forceUntuck, canTuck, onOpenItem: onOpenAccordionItem, onChangeDetailMode, onChangeSize, onChangeColor, onAddToCart, onToggleUntuck }) }) : null,
|
|
43629
43751
|
/* @__PURE__ */ jsxs("div", { css: css2.railsColumn, children: [
|
|
43630
43752
|
/* @__PURE__ */ jsxs("span", { css: css2.signOutWrapper, onClick: onSignOut, children: [
|
|
@@ -43751,6 +43873,7 @@ function MobileLayout$1({
|
|
|
43751
43873
|
forceUntuck,
|
|
43752
43874
|
canTuck,
|
|
43753
43875
|
frameUrls,
|
|
43876
|
+
autoRotateTrigger,
|
|
43754
43877
|
sheetSnap,
|
|
43755
43878
|
sheetTouchStart,
|
|
43756
43879
|
onSelectItem,
|
|
@@ -43767,7 +43890,7 @@ function MobileLayout$1({
|
|
|
43767
43890
|
if (mode === "browse") {
|
|
43768
43891
|
return /* @__PURE__ */ jsx$1(BrowseView, { resolved, availabilityByExternalId, selectedCount: selectedItems.length, onSelectItem, onRemoveItem, onTryItOn });
|
|
43769
43892
|
}
|
|
43770
|
-
return /* @__PURE__ */ jsx$1(TryOnView, { selectedItems, openAccordionItemId, detailMode, forceUntuck, canTuck, frameUrls, sheetSnap, sheetTouchStart, onBackToBrowse, onOpenAccordionItem, onChangeDetailMode, onChangeSize, onChangeColor, onAddToCart, onToggleUntuck });
|
|
43893
|
+
return /* @__PURE__ */ jsx$1(TryOnView, { selectedItems, openAccordionItemId, detailMode, forceUntuck, canTuck, frameUrls, autoRotateTrigger, sheetSnap, sheetTouchStart, onBackToBrowse, onOpenAccordionItem, onChangeDetailMode, onChangeSize, onChangeColor, onAddToCart, onToggleUntuck });
|
|
43771
43894
|
}
|
|
43772
43895
|
function BrowseView({
|
|
43773
43896
|
resolved,
|
|
@@ -43861,6 +43984,7 @@ function TryOnView({
|
|
|
43861
43984
|
forceUntuck,
|
|
43862
43985
|
canTuck,
|
|
43863
43986
|
frameUrls,
|
|
43987
|
+
autoRotateTrigger,
|
|
43864
43988
|
sheetSnap,
|
|
43865
43989
|
sheetTouchStart,
|
|
43866
43990
|
onBackToBrowse,
|
|
@@ -43961,7 +44085,7 @@ function TryOnView({
|
|
|
43961
44085
|
}
|
|
43962
44086
|
}));
|
|
43963
44087
|
return /* @__PURE__ */ jsxs("div", { css: css2.container, children: [
|
|
43964
|
-
/* @__PURE__ */ jsx$1(AvatarPane, { hasSelection: selectedItems.length > 0, frameUrls, mobileFullscreen: true, controls: /* @__PURE__ */ jsx$1(MobileTuckControl, { canTuck, forceUntuck, onToggleUntuck }) }),
|
|
44088
|
+
/* @__PURE__ */ jsx$1(AvatarPane, { hasSelection: selectedItems.length > 0, frameUrls, autoRotateTrigger, mobileFullscreen: true, controls: /* @__PURE__ */ jsx$1(MobileTuckControl, { canTuck, forceUntuck, onToggleUntuck }) }),
|
|
43965
44089
|
/* @__PURE__ */ jsx$1(Button, { variant: "base", css: css2.backButton, onClick: onBackToBrowse, "aria-label": "Back to browse", children: /* @__PURE__ */ jsx$1(SvgIconLeftArrow, { css: css2.backArrow }) }),
|
|
43966
44090
|
/* @__PURE__ */ jsx$1("div", { css: css2.sheetOuter, style: sheetStyle, children: /* @__PURE__ */ jsxs("div", { ref: innerRef, css: css2.sheetInner, style: sheetStyle, children: [
|
|
43967
44091
|
/* @__PURE__ */ jsxs("div", { css: css2.sheetHandleRow, onTouchStart: sheetTouchStart, children: [
|
|
@@ -44106,9 +44230,11 @@ function FittingRoomOverlay({
|
|
|
44106
44230
|
const closeOverlay = useMainStore((state) => state.closeOverlay);
|
|
44107
44231
|
const openOverlay = useMainStore((state) => state.openOverlay);
|
|
44108
44232
|
const updateFittingRoomItem = useMainStore((state) => state.updateFittingRoomItem);
|
|
44233
|
+
const removeFromFittingRoom = useMainStore((state) => state.removeFromFittingRoom);
|
|
44109
44234
|
const resolved = useResolvedFittingRoom();
|
|
44110
44235
|
const [topOffset, setTopOffset] = reactExports.useState(0);
|
|
44111
44236
|
const [selectedExternalIds, setSelectedExternalIds] = reactExports.useState(() => /* @__PURE__ */ new Set());
|
|
44237
|
+
const [autoRotateTrigger, setAutoRotateTrigger] = reactExports.useState(void 0);
|
|
44112
44238
|
const [openAccordionItemId, setOpenAccordionItemId] = reactExports.useState(null);
|
|
44113
44239
|
const [detailMode, setDetailMode] = reactExports.useState("compact");
|
|
44114
44240
|
const [forceUntuck, setForceUntuck] = reactExports.useState(false);
|
|
@@ -44215,6 +44341,7 @@ function FittingRoomOverlay({
|
|
|
44215
44341
|
nextSelected.add(externalId);
|
|
44216
44342
|
ensureSizeForItem(item);
|
|
44217
44343
|
setLastAddedExternalId(externalId);
|
|
44344
|
+
setAutoRotateTrigger((n) => (n ?? 0) + 1);
|
|
44218
44345
|
if (!isMobileLayout) {
|
|
44219
44346
|
setOpenAccordionItemId(externalId);
|
|
44220
44347
|
setDetailMode("compact");
|
|
@@ -44307,7 +44434,8 @@ function FittingRoomOverlay({
|
|
|
44307
44434
|
if (openAccordionItemId === externalId) {
|
|
44308
44435
|
setOpenAccordionItemId(null);
|
|
44309
44436
|
}
|
|
44310
|
-
|
|
44437
|
+
removeFromFittingRoom(externalId);
|
|
44438
|
+
}, [openAccordionItemId, removeFromFittingRoom]);
|
|
44311
44439
|
const handleTryItOn = reactExports.useCallback(() => {
|
|
44312
44440
|
setMobileMode("try-on");
|
|
44313
44441
|
setSheetSnap("collapsed");
|
|
@@ -44325,7 +44453,8 @@ function FittingRoomOverlay({
|
|
|
44325
44453
|
if (preselectAppliedRef.current || !preselectExternalId) {
|
|
44326
44454
|
return;
|
|
44327
44455
|
}
|
|
44328
|
-
|
|
44456
|
+
const item = resolved.items.find((i) => i.externalId === preselectExternalId);
|
|
44457
|
+
if (!item || !item.merchantProduct || !item.loadedProduct) {
|
|
44329
44458
|
return;
|
|
44330
44459
|
}
|
|
44331
44460
|
preselectAppliedRef.current = true;
|
|
@@ -44452,7 +44581,7 @@ function FittingRoomOverlay({
|
|
|
44452
44581
|
/* @__PURE__ */ jsx$1(TextT, { variant: "base", css: css2.emptyTagline, t: "landing.description" }),
|
|
44453
44582
|
/* @__PURE__ */ jsx$1("div", { css: css2.emptyShopNow, children: /* @__PURE__ */ jsx$1(ButtonT, { variant: "primary", t: "fitting_room.shop_now", onClick: handleShopNow }) }),
|
|
44454
44583
|
userIsLoggedIn ? /* @__PURE__ */ jsx$1(LinkT, { variant: "underline", css: css2.emptySignOut, t: "fitting_room.sign_out", onClick: handleSignOut }) : null
|
|
44455
|
-
] }) }) : isMobileLayout ? /* @__PURE__ */ jsx$1(MobileLayout$1, { mode: mobileMode, resolved, selectedItems, availabilityByExternalId, openAccordionItemId, detailMode, forceUntuck, canTuck, frameUrls, sheetSnap, sheetTouchStart, onSelectItem: handleSelectItem, onRemoveItem: handleRemoveItem, onTryItOn: handleTryItOn, onBackToBrowse: handleBackToBrowse, onOpenAccordionItem: setOpenAccordionItemId, onChangeDetailMode: setDetailMode, onChangeSize: handleChangeSize, onChangeColor: handleChangeColor, onAddToCart: handleAddToCart, onToggleUntuck: handleToggleUntuck }) : /* @__PURE__ */ jsx$1(DesktopLayout$1, { resolved, selectedItems, availabilityByExternalId, openAccordionItemId, detailMode, forceUntuck, canTuck, frameUrls, onSelectItem: handleSelectItem, onRemoveItem: handleRemoveItem, onOpenAccordionItem: setOpenAccordionItemId, onChangeDetailMode: setDetailMode, onChangeSize: handleChangeSize, onChangeColor: handleChangeColor, onAddToCart: handleAddToCart, onToggleUntuck: handleToggleUntuck, onSignOut: handleSignOut }),
|
|
44584
|
+
] }) }) : isMobileLayout ? /* @__PURE__ */ jsx$1(MobileLayout$1, { mode: mobileMode, resolved, selectedItems, availabilityByExternalId, openAccordionItemId, detailMode, forceUntuck, canTuck, frameUrls, autoRotateTrigger, sheetSnap, sheetTouchStart, onSelectItem: handleSelectItem, onRemoveItem: handleRemoveItem, onTryItOn: handleTryItOn, onBackToBrowse: handleBackToBrowse, onOpenAccordionItem: setOpenAccordionItemId, onChangeDetailMode: setDetailMode, onChangeSize: handleChangeSize, onChangeColor: handleChangeColor, onAddToCart: handleAddToCart, onToggleUntuck: handleToggleUntuck }) : /* @__PURE__ */ jsx$1(DesktopLayout$1, { resolved, selectedItems, availabilityByExternalId, openAccordionItemId, detailMode, forceUntuck, canTuck, frameUrls, autoRotateTrigger, onSelectItem: handleSelectItem, onRemoveItem: handleRemoveItem, onOpenAccordionItem: setOpenAccordionItemId, onChangeDetailMode: setDetailMode, onChangeSize: handleChangeSize, onChangeColor: handleChangeColor, onAddToCart: handleAddToCart, onToggleUntuck: handleToggleUntuck, onSignOut: handleSignOut }),
|
|
44456
44585
|
vtoError ? /* @__PURE__ */ jsx$1(Snackbar, { messageKey: "fitting_room.vto_error", onDismiss: clearVtoError }) : null
|
|
44457
44586
|
] }) });
|
|
44458
44587
|
}
|
|
@@ -45179,6 +45308,8 @@ function FitChart({
|
|
|
45179
45308
|
const AVATAR_IMAGE_ASPECT_RATIO = 2 / 3;
|
|
45180
45309
|
const AVATAR_GUTTER_HEIGHT_PX = 100;
|
|
45181
45310
|
const CONTENT_AREA_WIDTH_PX = 550;
|
|
45311
|
+
const SHOW_ROTATION_SLIDER = false;
|
|
45312
|
+
const DESKTOP_AVATAR_GUTTER_HEIGHT_PX = 0;
|
|
45182
45313
|
const logger$5 = getLogger("overlays/quick-view");
|
|
45183
45314
|
function QuickViewOverlay() {
|
|
45184
45315
|
const userIsLoggedIn = useMainStore((state) => state.userIsLoggedIn);
|
|
@@ -45188,6 +45319,8 @@ function QuickViewOverlay() {
|
|
|
45188
45319
|
const deviceLayout = useMainStore((state) => state.deviceLayout);
|
|
45189
45320
|
const openOverlay = useMainStore((state) => state.openOverlay);
|
|
45190
45321
|
const closeOverlay = useMainStore((state) => state.closeOverlay);
|
|
45322
|
+
const updateFittingRoomItem = useMainStore((state) => state.updateFittingRoomItem);
|
|
45323
|
+
const fittingRoomItems = useMainStore((state) => state.fittingRoom);
|
|
45191
45324
|
const [vtoProductData, setVtoProductData] = reactExports.useState(null);
|
|
45192
45325
|
const [selectedSizeLabel, setSelectedSizeLabel] = reactExports.useState(null);
|
|
45193
45326
|
const [selectedColorLabel, setSelectedColorLabel] = reactExports.useState(null);
|
|
@@ -45422,6 +45555,27 @@ function QuickViewOverlay() {
|
|
|
45422
45555
|
});
|
|
45423
45556
|
});
|
|
45424
45557
|
}, [closeOverlay]);
|
|
45558
|
+
const handleChangeColor = reactExports.useCallback((newColorLabel) => {
|
|
45559
|
+
setSelectedColorLabel(newColorLabel);
|
|
45560
|
+
const currentProduct = getStaticData().currentProduct;
|
|
45561
|
+
if (!currentProduct) {
|
|
45562
|
+
return;
|
|
45563
|
+
}
|
|
45564
|
+
const inRoom = fittingRoomItems.some((item) => item.externalId === currentProduct.externalId);
|
|
45565
|
+
if (!inRoom || !vtoProductData || !selectedSizeLabel) {
|
|
45566
|
+
return;
|
|
45567
|
+
}
|
|
45568
|
+
const sizeRec = vtoProductData.sizes.find((s) => s.sizeLabel === selectedSizeLabel);
|
|
45569
|
+
const csa = sizeRec?.colors.find((c) => c.colorLabel === newColorLabel);
|
|
45570
|
+
if (!csa) {
|
|
45571
|
+
return;
|
|
45572
|
+
}
|
|
45573
|
+
updateFittingRoomItem(currentProduct.externalId, {
|
|
45574
|
+
colorwaySizeAssetId: csa.colorwaySizeAssetId,
|
|
45575
|
+
size: selectedSizeLabel,
|
|
45576
|
+
color: csa.colorLabel
|
|
45577
|
+
});
|
|
45578
|
+
}, [fittingRoomItems, selectedSizeLabel, updateFittingRoomItem, vtoProductData]);
|
|
45425
45579
|
const handleAddToCartClick = reactExports.useCallback(async () => {
|
|
45426
45580
|
try {
|
|
45427
45581
|
if (!selectedSizeLabel) {
|
|
@@ -45457,7 +45611,7 @@ function QuickViewOverlay() {
|
|
|
45457
45611
|
Layout = DesktopLayout;
|
|
45458
45612
|
}
|
|
45459
45613
|
return /* @__PURE__ */ jsxs(SidecarModalFrame, { onRequestClose: closeOverlay, contentStyle: modalStyle, children: [
|
|
45460
|
-
/* @__PURE__ */ jsx$1(Layout, { loadedProductData: vtoProductData, selectedColorSizeRecord, availableColorLabels, selectedColorLabel, selectedSizeLabel, frameUrls, setModalStyle, onClose: closeOverlay, onChangeColor:
|
|
45614
|
+
/* @__PURE__ */ jsx$1(Layout, { loadedProductData: vtoProductData, selectedColorSizeRecord, availableColorLabels, selectedColorLabel, selectedSizeLabel, frameUrls, setModalStyle, onClose: closeOverlay, onChangeColor: handleChangeColor, onChangeSize: setSelectedSizeLabel, onAddToCart: handleAddToCartClick, onSignOut: handleSignOutClick }),
|
|
45461
45615
|
vtoError ? /* @__PURE__ */ jsx$1(Snackbar, { messageKey: "quick-view.vto_error", onDismiss: clearVtoError }) : null
|
|
45462
45616
|
] });
|
|
45463
45617
|
}
|
|
@@ -45695,7 +45849,10 @@ function MobileLayout({
|
|
|
45695
45849
|
}
|
|
45696
45850
|
function MobileContentCollapsed({
|
|
45697
45851
|
loadedProductData,
|
|
45852
|
+
availableColorLabels,
|
|
45853
|
+
selectedColorLabel,
|
|
45698
45854
|
selectedSizeLabel,
|
|
45855
|
+
onChangeColor,
|
|
45699
45856
|
onChangeSize
|
|
45700
45857
|
}) {
|
|
45701
45858
|
const css2 = useCss((_theme) => ({
|
|
@@ -45705,17 +45862,24 @@ function MobileContentCollapsed({
|
|
|
45705
45862
|
selectSizeLabelText: {},
|
|
45706
45863
|
sizeSelectorContainer: {
|
|
45707
45864
|
marginTop: "8px"
|
|
45865
|
+
},
|
|
45866
|
+
colorSelectorContainer: {
|
|
45867
|
+
marginTop: "8px"
|
|
45708
45868
|
}
|
|
45709
45869
|
}));
|
|
45710
45870
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
45711
45871
|
/* @__PURE__ */ jsx$1("div", { css: css2.selectSizeLabelContainer, children: /* @__PURE__ */ jsx$1(TextT, { variant: "base", css: css2.selectSizeLabelText, t: "size-rec.select_size" }) }),
|
|
45712
|
-
/* @__PURE__ */ jsx$1("div", { css: css2.sizeSelectorContainer, children: /* @__PURE__ */ jsx$1(SizeSelector, { loadedProductData, selectedSizeLabel, onChangeSize }) })
|
|
45872
|
+
/* @__PURE__ */ jsx$1("div", { css: css2.sizeSelectorContainer, children: /* @__PURE__ */ jsx$1(SizeSelector, { loadedProductData, selectedSizeLabel, onChangeSize }) }),
|
|
45873
|
+
/* @__PURE__ */ jsx$1("div", { css: css2.colorSelectorContainer, children: /* @__PURE__ */ jsx$1(ColorSelector, { availableColorLabels, selectedColorLabel, onChangeColor }) })
|
|
45713
45874
|
] });
|
|
45714
45875
|
}
|
|
45715
45876
|
function MobileContentExpanded({
|
|
45716
45877
|
loadedProductData,
|
|
45878
|
+
availableColorLabels,
|
|
45879
|
+
selectedColorLabel,
|
|
45717
45880
|
selectedSizeLabel,
|
|
45718
45881
|
onChangeContentView,
|
|
45882
|
+
onChangeColor,
|
|
45719
45883
|
onChangeSize,
|
|
45720
45884
|
onAddToCart
|
|
45721
45885
|
}) {
|
|
@@ -45727,6 +45891,9 @@ function MobileContentExpanded({
|
|
|
45727
45891
|
sizeSelectorContainer: {
|
|
45728
45892
|
marginTop: "8px"
|
|
45729
45893
|
},
|
|
45894
|
+
colorSelectorContainer: {
|
|
45895
|
+
marginTop: "8px"
|
|
45896
|
+
},
|
|
45730
45897
|
itemFitTextContainer: {
|
|
45731
45898
|
marginTop: "8px"
|
|
45732
45899
|
},
|
|
@@ -45756,6 +45923,7 @@ function MobileContentExpanded({
|
|
|
45756
45923
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
45757
45924
|
/* @__PURE__ */ jsx$1("div", { css: css2.selectSizeLabelContainer, children: /* @__PURE__ */ jsx$1(TextT, { variant: "base", css: css2.selectSizeLabelText, t: "size-rec.select_size" }) }),
|
|
45758
45925
|
/* @__PURE__ */ jsx$1("div", { css: css2.sizeSelectorContainer, children: /* @__PURE__ */ jsx$1(SizeSelector, { loadedProductData, selectedSizeLabel, onChangeSize }) }),
|
|
45926
|
+
/* @__PURE__ */ jsx$1("div", { css: css2.colorSelectorContainer, children: /* @__PURE__ */ jsx$1(ColorSelector, { availableColorLabels, selectedColorLabel, onChangeColor }) }),
|
|
45759
45927
|
/* @__PURE__ */ jsx$1("div", { css: css2.itemFitTextContainer, children: /* @__PURE__ */ jsx$1(ItemFitText, { loadedProductData }) }),
|
|
45760
45928
|
/* @__PURE__ */ jsx$1("div", { css: css2.itemFitDetailsContainer, children: /* @__PURE__ */ jsx$1(ItemFitDetails, { loadedProductData, selectedSizeLabel }) }),
|
|
45761
45929
|
/* @__PURE__ */ jsxs("div", { css: css2.buttonContainer, children: [
|
|
@@ -45909,7 +46077,7 @@ function DesktopLayout({
|
|
|
45909
46077
|
productNameContainer: {},
|
|
45910
46078
|
productNameText: {
|
|
45911
46079
|
fontFamily: "'Inter', sans-serif",
|
|
45912
|
-
fontSize: "
|
|
46080
|
+
fontSize: "24px",
|
|
45913
46081
|
fontWeight: 300
|
|
45914
46082
|
},
|
|
45915
46083
|
priceContainer: {
|
|
@@ -46029,6 +46197,7 @@ function Avatar({
|
|
|
46029
46197
|
});
|
|
46030
46198
|
const [selectedFrameIndex, setSelectedFrameIndex] = reactExports.useState(null);
|
|
46031
46199
|
const [zoomOpen, setZoomOpen] = reactExports.useState(false);
|
|
46200
|
+
const cancelAutoRotate = useAutoRotate(1, frameUrls, selectedFrameIndex, setSelectedFrameIndex);
|
|
46032
46201
|
const css2 = useCss((theme) => ({
|
|
46033
46202
|
topContainer: {
|
|
46034
46203
|
flex: "none",
|
|
@@ -46038,8 +46207,11 @@ function Avatar({
|
|
|
46038
46207
|
},
|
|
46039
46208
|
zoomPill: {
|
|
46040
46209
|
position: "absolute",
|
|
46041
|
-
// Bottom-right of the avatar image,
|
|
46042
|
-
|
|
46210
|
+
// Bottom-right of the avatar image, 16px above the image's bottom edge.
|
|
46211
|
+
// When the rotation slider is on, that's also `clear of the gutter` —
|
|
46212
|
+
// when the slider is hidden, the gutter collapses to 0 and the 16px
|
|
46213
|
+
// offset alone keeps the pill inset from the image's true bottom.
|
|
46214
|
+
bottom: `${DESKTOP_AVATAR_GUTTER_HEIGHT_PX + 16}px`,
|
|
46043
46215
|
right: "16px",
|
|
46044
46216
|
display: "inline-flex",
|
|
46045
46217
|
alignItems: "center",
|
|
@@ -46053,6 +46225,10 @@ function Avatar({
|
|
|
46053
46225
|
letterSpacing: "0.5px",
|
|
46054
46226
|
textTransform: "uppercase",
|
|
46055
46227
|
cursor: "pointer",
|
|
46228
|
+
// Rapid clicks on the rotation chevrons can otherwise spill a triple-
|
|
46229
|
+
// click selection into this label.
|
|
46230
|
+
userSelect: "none",
|
|
46231
|
+
WebkitUserSelect: "none",
|
|
46056
46232
|
zIndex: 2
|
|
46057
46233
|
},
|
|
46058
46234
|
zoomPillIcon: {
|
|
@@ -46129,7 +46305,7 @@ function Avatar({
|
|
|
46129
46305
|
}
|
|
46130
46306
|
} else {
|
|
46131
46307
|
const screenHeightPx = window.innerHeight;
|
|
46132
|
-
const bottomContainerHeightPx =
|
|
46308
|
+
const bottomContainerHeightPx = DESKTOP_AVATAR_GUTTER_HEIGHT_PX;
|
|
46133
46309
|
const imageHeightPx = screenHeightPx - bottomContainerHeightPx;
|
|
46134
46310
|
const imageWidthPx = Math.floor(imageHeightPx * AVATAR_IMAGE_ASPECT_RATIO);
|
|
46135
46311
|
const modalWidthPx = imageWidthPx + CONTENT_AREA_WIDTH_PX;
|
|
@@ -46172,13 +46348,13 @@ function Avatar({
|
|
|
46172
46348
|
}, [isMobileLayout, setModalStyle]);
|
|
46173
46349
|
const isReady = !!frameUrls && selectedFrameIndex != null;
|
|
46174
46350
|
return /* @__PURE__ */ jsxs("div", { css: css2.topContainer, style: layoutData.topContainerStyle, children: [
|
|
46175
|
-
/* @__PURE__ */ jsx$1(AvatarFrameViewer, { frameUrls, selectedFrameIndex, setSelectedFrameIndex, imageContainerStyle: layoutData.imageContainerStyle, imageStyle: layoutData.imageStyle, loadingT: "quick-view.avatar_loading" }),
|
|
46351
|
+
/* @__PURE__ */ jsx$1(AvatarFrameViewer, { frameUrls, selectedFrameIndex, setSelectedFrameIndex, imageContainerStyle: layoutData.imageContainerStyle, imageStyle: layoutData.imageStyle, loadingT: "quick-view.avatar_loading", onUserInteract: cancelAutoRotate }),
|
|
46176
46352
|
isReady && !isMobileLayout ? /* @__PURE__ */ jsxs(Button, { variant: "base", css: css2.zoomPill, onClick: () => setZoomOpen(true), children: [
|
|
46177
46353
|
/* @__PURE__ */ jsx$1(SvgIconZoom, { css: css2.zoomPillIcon }),
|
|
46178
46354
|
/* @__PURE__ */ jsx$1(TextT, { variant: "base", t: "quick-view.zoom_in" })
|
|
46179
46355
|
] }) : null,
|
|
46180
46356
|
zoomOpen && frameUrls && frameUrls.length > 0 ? /* @__PURE__ */ jsx$1(ZoomModal, { frameUrls, selectedFrameIndex, setSelectedFrameIndex, onClose: () => setZoomOpen(false) }) : null,
|
|
46181
|
-
frameUrls && selectedFrameIndex != null ? /* @__PURE__ */ jsx$1("div", { css: css2.bottomContainer, style: layoutData.bottomContainerStyle, children: isMobileLayout ? /* @__PURE__ */ jsx$1(Fragment, { children: " " }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
46357
|
+
frameUrls && selectedFrameIndex != null && (isMobileLayout || SHOW_ROTATION_SLIDER) ? /* @__PURE__ */ jsx$1("div", { css: css2.bottomContainer, style: layoutData.bottomContainerStyle, children: isMobileLayout ? /* @__PURE__ */ jsx$1(Fragment, { children: " " }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
46182
46358
|
/* @__PURE__ */ jsx$1("input", { type: "range", min: 0, max: frameUrls.length - 1, step: 1, value: selectedFrameIndex, onChange: (e) => setSelectedFrameIndex(Number(e.target.value)), css: css2.sliderInput }),
|
|
46183
46359
|
/* @__PURE__ */ jsx$1(TextT, { variant: "base", t: "quick-view.slide_to_rotate", css: css2.sliderText })
|
|
46184
46360
|
] }) }) : null
|
|
@@ -46706,28 +46882,41 @@ const useMainStore = create((set) => ({
|
|
|
46706
46882
|
}
|
|
46707
46883
|
})),
|
|
46708
46884
|
// Fitting room:
|
|
46885
|
+
//
|
|
46886
|
+
// Each mutation reads the latest localStorage state before applying the
|
|
46887
|
+
// change, so two tabs adding different products at the same time merge
|
|
46888
|
+
// instead of last-write-wins. The in-memory Zustand value is just a
|
|
46889
|
+
// cache of "what was in localStorage the last time we touched it".
|
|
46890
|
+
// Cross-tab UI freshness (Tab B's open fitting-room sees Tab A's add
|
|
46891
|
+
// without a mutation of its own) is handled by the `storage` event
|
|
46892
|
+
// listener registered in fitting-room-storage.ts::_init.
|
|
46709
46893
|
fittingRoom: [],
|
|
46710
|
-
addToFittingRoom: (item) => set((
|
|
46711
|
-
const
|
|
46712
|
-
const
|
|
46713
|
-
|
|
46894
|
+
addToFittingRoom: (item) => set(() => {
|
|
46895
|
+
const brandId = getStaticData().brandId;
|
|
46896
|
+
const fresh = readFittingRoom(brandId);
|
|
46897
|
+
const next2 = [...fresh.filter((existing) => existing.externalId !== item.externalId), item];
|
|
46898
|
+
writeFittingRoom(brandId, next2);
|
|
46714
46899
|
return {
|
|
46715
46900
|
fittingRoom: next2
|
|
46716
46901
|
};
|
|
46717
46902
|
}),
|
|
46718
|
-
removeFromFittingRoom: (externalId) => set((
|
|
46719
|
-
const
|
|
46720
|
-
|
|
46903
|
+
removeFromFittingRoom: (externalId) => set(() => {
|
|
46904
|
+
const brandId = getStaticData().brandId;
|
|
46905
|
+
const fresh = readFittingRoom(brandId);
|
|
46906
|
+
const next2 = fresh.filter((existing) => existing.externalId !== externalId);
|
|
46907
|
+
writeFittingRoom(brandId, next2);
|
|
46721
46908
|
return {
|
|
46722
46909
|
fittingRoom: next2
|
|
46723
46910
|
};
|
|
46724
46911
|
}),
|
|
46725
|
-
updateFittingRoomItem: (externalId, patch) => set((
|
|
46726
|
-
const
|
|
46912
|
+
updateFittingRoomItem: (externalId, patch) => set(() => {
|
|
46913
|
+
const brandId = getStaticData().brandId;
|
|
46914
|
+
const fresh = readFittingRoom(brandId);
|
|
46915
|
+
const next2 = fresh.map((existing) => existing.externalId === externalId ? {
|
|
46727
46916
|
...existing,
|
|
46728
46917
|
...patch
|
|
46729
46918
|
} : existing);
|
|
46730
|
-
writeFittingRoom(
|
|
46919
|
+
writeFittingRoom(brandId, next2);
|
|
46731
46920
|
return {
|
|
46732
46921
|
fittingRoom: next2
|
|
46733
46922
|
};
|
|
@@ -46794,9 +46983,9 @@ const SHARED_CONFIG = {
|
|
|
46794
46983
|
appGooglePlayUrl: "https://play.google.com/store/apps/details?id=com.thefittingroom.marketplace"
|
|
46795
46984
|
},
|
|
46796
46985
|
build: {
|
|
46797
|
-
version: `${"5.0.
|
|
46798
|
-
commitHash: `${"
|
|
46799
|
-
date: `${"2026-05-
|
|
46986
|
+
version: `${"5.0.27"}`,
|
|
46987
|
+
commitHash: `${"9e3e717"}`,
|
|
46988
|
+
date: `${"2026-05-24T21:00:26.048Z"}`
|
|
46800
46989
|
}
|
|
46801
46990
|
};
|
|
46802
46991
|
const CONFIGS = {
|
|
@@ -47016,10 +47205,12 @@ async function logout() {
|
|
|
47016
47205
|
}
|
|
47017
47206
|
const TFR = {
|
|
47018
47207
|
init,
|
|
47019
|
-
logout
|
|
47208
|
+
logout,
|
|
47209
|
+
syncCurrentProductSelection
|
|
47020
47210
|
};
|
|
47021
47211
|
export {
|
|
47022
47212
|
TFR as default,
|
|
47023
47213
|
init,
|
|
47024
|
-
logout
|
|
47214
|
+
logout,
|
|
47215
|
+
syncCurrentProductSelection
|
|
47025
47216
|
};
|