@thefittingroom/shop-ui 5.0.29 → 5.0.31
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 +174 -17
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -42073,14 +42073,38 @@ function pairCompatible(a, b, group) {
|
|
|
42073
42073
|
}
|
|
42074
42074
|
return aIncl.includes(bName) || bIncl.includes(aName);
|
|
42075
42075
|
}
|
|
42076
|
+
function getSameCategoryConflicts(item, selectedExternalIds, resolved) {
|
|
42077
|
+
if (!item.styleCategory) {
|
|
42078
|
+
return [];
|
|
42079
|
+
}
|
|
42080
|
+
const itemName = catName(item.styleCategory);
|
|
42081
|
+
const out = [];
|
|
42082
|
+
for (const sel of resolved.items) {
|
|
42083
|
+
if (sel.externalId === item.externalId) {
|
|
42084
|
+
continue;
|
|
42085
|
+
}
|
|
42086
|
+
if (!selectedExternalIds.has(sel.externalId)) {
|
|
42087
|
+
continue;
|
|
42088
|
+
}
|
|
42089
|
+
if (!sel.styleCategory) {
|
|
42090
|
+
continue;
|
|
42091
|
+
}
|
|
42092
|
+
if (catName(sel.styleCategory) === itemName) {
|
|
42093
|
+
out.push(sel.externalId);
|
|
42094
|
+
}
|
|
42095
|
+
}
|
|
42096
|
+
return out;
|
|
42097
|
+
}
|
|
42076
42098
|
function computeAvailability(item, selectedExternalIds, resolved) {
|
|
42077
42099
|
if (selectedExternalIds.has(item.externalId)) {
|
|
42078
42100
|
return "selected";
|
|
42079
42101
|
}
|
|
42080
|
-
if (
|
|
42102
|
+
if (!item.styleCategory) {
|
|
42081
42103
|
return "disabled";
|
|
42082
42104
|
}
|
|
42083
|
-
|
|
42105
|
+
const sameCategoryEvictions = new Set(getSameCategoryConflicts(item, selectedExternalIds, resolved));
|
|
42106
|
+
const effectiveSize = selectedExternalIds.size - sameCategoryEvictions.size + 1;
|
|
42107
|
+
if (effectiveSize > MAX_OUTFIT_ITEMS) {
|
|
42084
42108
|
return "disabled";
|
|
42085
42109
|
}
|
|
42086
42110
|
const itemCat = item.styleCategory;
|
|
@@ -42088,6 +42112,9 @@ function computeAvailability(item, selectedExternalIds, resolved) {
|
|
|
42088
42112
|
if (!selectedExternalIds.has(sel.externalId)) {
|
|
42089
42113
|
continue;
|
|
42090
42114
|
}
|
|
42115
|
+
if (sameCategoryEvictions.has(sel.externalId)) {
|
|
42116
|
+
continue;
|
|
42117
|
+
}
|
|
42091
42118
|
if (!sel.styleCategory) {
|
|
42092
42119
|
continue;
|
|
42093
42120
|
}
|
|
@@ -42680,11 +42707,77 @@ function Chevron({
|
|
|
42680
42707
|
transform: `rotate(${ROTATION_DEG[direction]}deg)`
|
|
42681
42708
|
}, children: /* @__PURE__ */ jsx$1("path", { d: "M6 9L12 15L18 9", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
42682
42709
|
}
|
|
42710
|
+
function ColorSwatchRow({
|
|
42711
|
+
colors,
|
|
42712
|
+
selectedLabel,
|
|
42713
|
+
onSelect
|
|
42714
|
+
}) {
|
|
42715
|
+
const css2 = useCss((theme) => ({
|
|
42716
|
+
row: {
|
|
42717
|
+
display: "flex",
|
|
42718
|
+
flexWrap: "wrap",
|
|
42719
|
+
gap: "6px"
|
|
42720
|
+
},
|
|
42721
|
+
swatch: {
|
|
42722
|
+
width: "24px",
|
|
42723
|
+
height: "24px",
|
|
42724
|
+
borderRadius: "50%",
|
|
42725
|
+
padding: 0,
|
|
42726
|
+
border: "1px solid rgba(0, 0, 0, 0.15)",
|
|
42727
|
+
backgroundColor: "#FFFFFF",
|
|
42728
|
+
cursor: "pointer",
|
|
42729
|
+
overflow: "hidden",
|
|
42730
|
+
display: "inline-flex",
|
|
42731
|
+
alignItems: "center",
|
|
42732
|
+
justifyContent: "center",
|
|
42733
|
+
// Reset native button chrome so the circle renders crisply.
|
|
42734
|
+
appearance: "none",
|
|
42735
|
+
WebkitAppearance: "none"
|
|
42736
|
+
},
|
|
42737
|
+
swatchSelected: {
|
|
42738
|
+
outline: `2px solid ${theme.color_fg_text}`,
|
|
42739
|
+
outlineOffset: "1px",
|
|
42740
|
+
borderColor: "transparent"
|
|
42741
|
+
},
|
|
42742
|
+
swatchImage: {
|
|
42743
|
+
width: "100%",
|
|
42744
|
+
height: "100%",
|
|
42745
|
+
objectFit: "cover"
|
|
42746
|
+
},
|
|
42747
|
+
// Tiny text label, used only as a last-resort fallback when neither an
|
|
42748
|
+
// image nor a hex is available. Truncates so a long colour name
|
|
42749
|
+
// doesn't break the swatch shape.
|
|
42750
|
+
swatchTextLabel: {
|
|
42751
|
+
fontSize: "9px",
|
|
42752
|
+
lineHeight: 1,
|
|
42753
|
+
color: theme.color_fg_text,
|
|
42754
|
+
padding: "0 2px",
|
|
42755
|
+
overflow: "hidden",
|
|
42756
|
+
textOverflow: "ellipsis",
|
|
42757
|
+
whiteSpace: "nowrap",
|
|
42758
|
+
maxWidth: "100%"
|
|
42759
|
+
}
|
|
42760
|
+
}));
|
|
42761
|
+
if (colors.length < 2) {
|
|
42762
|
+
return null;
|
|
42763
|
+
}
|
|
42764
|
+
return /* @__PURE__ */ jsx$1("div", { css: css2.row, children: colors.map((c) => {
|
|
42765
|
+
const isSelected = c.label === selectedLabel;
|
|
42766
|
+
const fillStyle = c.imageUrl ? void 0 : c.hex ? {
|
|
42767
|
+
backgroundColor: c.hex
|
|
42768
|
+
} : void 0;
|
|
42769
|
+
return /* @__PURE__ */ jsx$1(Button, { variant: "base", css: isSelected ? {
|
|
42770
|
+
...css2.swatch,
|
|
42771
|
+
...css2.swatchSelected
|
|
42772
|
+
} : css2.swatch, style: fillStyle, onClick: () => onSelect(c.label), "aria-label": `Pick colour ${c.label}`, "aria-pressed": isSelected, children: c.imageUrl ? /* @__PURE__ */ jsx$1("img", { src: c.imageUrl, alt: "", css: css2.swatchImage }) : c.hex ? null : /* @__PURE__ */ jsx$1("span", { css: css2.swatchTextLabel, children: c.label.slice(0, 3) }) }, c.label);
|
|
42773
|
+
}) });
|
|
42774
|
+
}
|
|
42683
42775
|
function ProductCard({
|
|
42684
42776
|
item,
|
|
42685
42777
|
availability,
|
|
42686
42778
|
onClick,
|
|
42687
|
-
onRemove
|
|
42779
|
+
onRemove,
|
|
42780
|
+
onChangeColor
|
|
42688
42781
|
}) {
|
|
42689
42782
|
const css2 = useCss((theme) => ({
|
|
42690
42783
|
container: {
|
|
@@ -42758,6 +42851,24 @@ function ProductCard({
|
|
|
42758
42851
|
removeIcon: {
|
|
42759
42852
|
width: "12px",
|
|
42760
42853
|
height: "12px"
|
|
42854
|
+
},
|
|
42855
|
+
// Selected badge — mirrors the X button at the top-right, green-filled
|
|
42856
|
+
// circle at top-left with an inline white checkmark. Only rendered when
|
|
42857
|
+
// availability === 'selected'. Decorative: pointer-events: none so the
|
|
42858
|
+
// shopper still taps the card body underneath to toggle off.
|
|
42859
|
+
selectedBadge: {
|
|
42860
|
+
position: "absolute",
|
|
42861
|
+
top: "4px",
|
|
42862
|
+
left: "4px",
|
|
42863
|
+
width: "24px",
|
|
42864
|
+
height: "24px",
|
|
42865
|
+
borderRadius: "12px",
|
|
42866
|
+
backgroundColor: "#22C55E",
|
|
42867
|
+
display: "flex",
|
|
42868
|
+
alignItems: "center",
|
|
42869
|
+
justifyContent: "center",
|
|
42870
|
+
pointerEvents: "none",
|
|
42871
|
+
zIndex: 1
|
|
42761
42872
|
}
|
|
42762
42873
|
}));
|
|
42763
42874
|
const disabled = availability === "disabled";
|
|
@@ -42782,6 +42893,29 @@ function ProductCard({
|
|
|
42782
42893
|
const selectedVariant = item.merchantProduct?.variants.find((v) => v.color === effectiveColor && (!item.storage.size || v.size === item.storage.size));
|
|
42783
42894
|
const imageUrl = selectedVariant?.imageUrl ?? item.merchantProduct?.imageUrl ?? null;
|
|
42784
42895
|
const price = selectedVariant?.priceFormatted ?? item.merchantProduct?.variants[0]?.priceFormatted ?? null;
|
|
42896
|
+
const swatchColors = reactExports.useMemo(() => {
|
|
42897
|
+
const variants = item.merchantProduct?.variants;
|
|
42898
|
+
if (!variants) {
|
|
42899
|
+
return [];
|
|
42900
|
+
}
|
|
42901
|
+
const seen = /* @__PURE__ */ new Set();
|
|
42902
|
+
const out = [];
|
|
42903
|
+
for (const v of variants) {
|
|
42904
|
+
if (!v.color || seen.has(v.color)) {
|
|
42905
|
+
continue;
|
|
42906
|
+
}
|
|
42907
|
+
seen.add(v.color);
|
|
42908
|
+
out.push({
|
|
42909
|
+
label: v.color,
|
|
42910
|
+
imageUrl: v.swatchImageUrl ?? null,
|
|
42911
|
+
hex: v.swatchHex ?? null
|
|
42912
|
+
});
|
|
42913
|
+
}
|
|
42914
|
+
return out;
|
|
42915
|
+
}, [item.merchantProduct?.variants]);
|
|
42916
|
+
const handleSwatchSelect = (label) => {
|
|
42917
|
+
onChangeColor?.(item.externalId, label);
|
|
42918
|
+
};
|
|
42785
42919
|
return /* @__PURE__ */ jsxs("div", { css: /* @__PURE__ */ css$1({
|
|
42786
42920
|
...css2.container,
|
|
42787
42921
|
...selected && css2.containerSelected,
|
|
@@ -42791,6 +42925,7 @@ function ProductCard({
|
|
|
42791
42925
|
e.stopPropagation();
|
|
42792
42926
|
onRemove();
|
|
42793
42927
|
}, "aria-label": "Remove from fitting room", children: /* @__PURE__ */ jsx$1(SvgCloseIcon, { css: css2.removeIcon }) }),
|
|
42928
|
+
selected ? /* @__PURE__ */ jsx$1("div", { css: css2.selectedBadge, "aria-hidden": "true", children: /* @__PURE__ */ jsx$1("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx$1("path", { d: "M3 8.5L6.5 12L13 4.5", stroke: "#FFFFFF", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }) : null,
|
|
42794
42929
|
/* @__PURE__ */ jsxs(Button, { variant: "base", css: /* @__PURE__ */ css$1({
|
|
42795
42930
|
...css2.cardBody,
|
|
42796
42931
|
...disabled && css2.cardBodyDisabled
|
|
@@ -42798,14 +42933,17 @@ function ProductCard({
|
|
|
42798
42933
|
/* @__PURE__ */ jsx$1("div", { css: css2.imageContainer, children: imageUrl ? /* @__PURE__ */ jsx$1("img", { src: imageUrl, css: css2.image, alt: name2 }) : null }),
|
|
42799
42934
|
/* @__PURE__ */ jsx$1(Text, { variant: "base", css: css2.nameText, children: name2 }),
|
|
42800
42935
|
price ? /* @__PURE__ */ jsx$1(Text, { variant: "base", css: css2.priceText, children: price }) : null
|
|
42801
|
-
] })
|
|
42936
|
+
] }),
|
|
42937
|
+
onChangeColor ? /* @__PURE__ */ jsx$1(ColorSwatchRow, { colors: swatchColors, selectedLabel: effectiveColor, onSelect: handleSwatchSelect }) : null
|
|
42802
42938
|
] });
|
|
42803
42939
|
}
|
|
42804
42940
|
function CardRail({
|
|
42805
42941
|
group,
|
|
42806
42942
|
availabilityByExternalId,
|
|
42807
42943
|
onSelectItem,
|
|
42808
|
-
onRemoveItem
|
|
42944
|
+
onRemoveItem,
|
|
42945
|
+
onChangeColor,
|
|
42946
|
+
sortSelectedFirst
|
|
42809
42947
|
}) {
|
|
42810
42948
|
const [collapsed, setCollapsed] = reactExports.useState(false);
|
|
42811
42949
|
const scrollRef = reactExports.useRef(null);
|
|
@@ -42909,7 +43047,12 @@ function CardRail({
|
|
|
42909
43047
|
right: 0
|
|
42910
43048
|
}
|
|
42911
43049
|
}));
|
|
42912
|
-
const
|
|
43050
|
+
const orderedItems = sortSelectedFirst ? [...group.items].sort((a, b) => {
|
|
43051
|
+
const aSel = availabilityByExternalId[a.externalId] === "selected" ? 0 : 1;
|
|
43052
|
+
const bSel = availabilityByExternalId[b.externalId] === "selected" ? 0 : 1;
|
|
43053
|
+
return aSel - bSel;
|
|
43054
|
+
}) : group.items;
|
|
43055
|
+
const cards = orderedItems.map((item) => /* @__PURE__ */ jsx$1(ProductCard, { item, availability: availabilityByExternalId[item.externalId] ?? "disabled", onClick: () => onSelectItem(item.externalId), onRemove: () => onRemoveItem(item.externalId), onChangeColor }, item.externalId));
|
|
42913
43056
|
return /* @__PURE__ */ jsxs("div", { css: css2.container, children: [
|
|
42914
43057
|
/* @__PURE__ */ jsxs(Button, { variant: "base", css: css2.header, onClick: () => setCollapsed((c) => !c), children: [
|
|
42915
43058
|
/* @__PURE__ */ jsx$1(Text, { variant: "base", css: css2.headerLabel, children: group.group.label }),
|
|
@@ -43776,7 +43919,7 @@ function DesktopLayout$1({
|
|
|
43776
43919
|
...css2.utilityLink,
|
|
43777
43920
|
...css2.clearAllWrapper
|
|
43778
43921
|
}, "", ""), onClick: onClearAll, children: /* @__PURE__ */ jsx$1(LinkT, { variant: "underline", css: css2.utilityText, t: "fitting_room.clear_all" }) }),
|
|
43779
|
-
resolved.groups.map((group) => /* @__PURE__ */ jsx$1(CardRail, { group, availabilityByExternalId, onSelectItem, onRemoveItem }, group.group.name)),
|
|
43922
|
+
resolved.groups.map((group) => /* @__PURE__ */ jsx$1(CardRail, { group, availabilityByExternalId, onSelectItem, onRemoveItem, onChangeColor, sortSelectedFirst: true }, group.group.name)),
|
|
43780
43923
|
/* @__PURE__ */ jsxs("span", { css: /* @__PURE__ */ css$1({
|
|
43781
43924
|
...css2.utilityLink,
|
|
43782
43925
|
...css2.signOutWrapper
|
|
@@ -43920,7 +44063,7 @@ function MobileLayout$1({
|
|
|
43920
44063
|
onClearAll
|
|
43921
44064
|
}) {
|
|
43922
44065
|
if (mode === "browse") {
|
|
43923
|
-
return /* @__PURE__ */ jsx$1(BrowseView, { resolved, availabilityByExternalId, selectedCount: selectedItems.length, onSelectItem, onRemoveItem, onTryItOn, onSignOut, onClearAll });
|
|
44066
|
+
return /* @__PURE__ */ jsx$1(BrowseView, { resolved, availabilityByExternalId, selectedCount: selectedItems.length, onSelectItem, onRemoveItem, onChangeColor, onTryItOn, onSignOut, onClearAll });
|
|
43924
44067
|
}
|
|
43925
44068
|
return /* @__PURE__ */ jsx$1(TryOnView, { selectedItems, openAccordionItemId, detailMode, forceUntuck, canTuck, frameUrls, autoRotateTrigger, sheetSnap, sheetTouchStart, onBackToBrowse, onOpenAccordionItem, onChangeDetailMode, onChangeSize, onChangeColor, onAddToCart, onToggleUntuck });
|
|
43926
44069
|
}
|
|
@@ -43930,6 +44073,7 @@ function BrowseView({
|
|
|
43930
44073
|
selectedCount,
|
|
43931
44074
|
onSelectItem,
|
|
43932
44075
|
onRemoveItem,
|
|
44076
|
+
onChangeColor,
|
|
43933
44077
|
onTryItOn,
|
|
43934
44078
|
onSignOut,
|
|
43935
44079
|
onClearAll
|
|
@@ -44056,7 +44200,7 @@ function BrowseView({
|
|
|
44056
44200
|
}
|
|
44057
44201
|
}));
|
|
44058
44202
|
return /* @__PURE__ */ jsxs("div", { css: css2.container, children: [
|
|
44059
|
-
!resolved.isLoading && resolved.groups.length >
|
|
44203
|
+
!resolved.isLoading && resolved.groups.length > 1 ? /* @__PURE__ */ jsx$1(SectionNav, { sections, activeName: activeSectionName, onSelect: scrollToSection }) : null,
|
|
44060
44204
|
/* @__PURE__ */ jsxs("div", { ref: railsAreaRef, css: css2.railsArea, onScroll: recomputeActiveSection, children: [
|
|
44061
44205
|
resolved.groups.map((group) => /* @__PURE__ */ jsx$1("div", { ref: (el) => {
|
|
44062
44206
|
if (el) {
|
|
@@ -44064,7 +44208,7 @@ function BrowseView({
|
|
|
44064
44208
|
} else {
|
|
44065
44209
|
sectionRefs.current.delete(group.group.name);
|
|
44066
44210
|
}
|
|
44067
|
-
}, children: /* @__PURE__ */ jsx$1(CardRail, { group, availabilityByExternalId, onSelectItem, onRemoveItem }) }, group.group.name)),
|
|
44211
|
+
}, children: /* @__PURE__ */ jsx$1(CardRail, { group, availabilityByExternalId, onSelectItem, onRemoveItem, onChangeColor }) }, group.group.name)),
|
|
44068
44212
|
/* @__PURE__ */ jsxs("span", { css: css2.signOutWrapper, onClick: onSignOut, children: [
|
|
44069
44213
|
/* @__PURE__ */ jsx$1(SvgTfrIcon, { css: css2.signOutIcon }),
|
|
44070
44214
|
/* @__PURE__ */ jsx$1(LinkT, { variant: "underline", css: css2.signOutText, t: "fitting_room.sign_out" })
|
|
@@ -44439,6 +44583,12 @@ function FittingRoomOverlay({
|
|
|
44439
44583
|
setOpenAccordionItemId(null);
|
|
44440
44584
|
}
|
|
44441
44585
|
} else {
|
|
44586
|
+
for (const evictedId of getSameCategoryConflicts(item, selectedExternalIds, resolved)) {
|
|
44587
|
+
nextSelected.delete(evictedId);
|
|
44588
|
+
if (openAccordionItemId === evictedId) {
|
|
44589
|
+
setOpenAccordionItemId(null);
|
|
44590
|
+
}
|
|
44591
|
+
}
|
|
44442
44592
|
nextSelected.add(externalId);
|
|
44443
44593
|
ensureSizeForItem(item);
|
|
44444
44594
|
setLastAddedExternalId(externalId);
|
|
@@ -44471,20 +44621,24 @@ function FittingRoomOverlay({
|
|
|
44471
44621
|
}, [resolved.items, updateFittingRoomItem]);
|
|
44472
44622
|
const handleChangeColor = reactExports.useCallback((externalId, colorLabel) => {
|
|
44473
44623
|
const item = resolved.items.find((i) => i.externalId === externalId);
|
|
44474
|
-
if (!item
|
|
44624
|
+
if (!item) {
|
|
44475
44625
|
return;
|
|
44476
44626
|
}
|
|
44477
44627
|
const productData = buildVtoProductDataFromResolved(item);
|
|
44478
44628
|
if (!productData) {
|
|
44479
44629
|
return;
|
|
44480
44630
|
}
|
|
44481
|
-
const
|
|
44631
|
+
const effectiveSize = item.storage.size ?? productData.recommendedSizeLabel;
|
|
44632
|
+
if (!effectiveSize) {
|
|
44633
|
+
return;
|
|
44634
|
+
}
|
|
44635
|
+
const csa = findCsaByLabel(productData, effectiveSize, colorLabel);
|
|
44482
44636
|
if (!csa) {
|
|
44483
44637
|
return;
|
|
44484
44638
|
}
|
|
44485
44639
|
updateFittingRoomItem(externalId, {
|
|
44486
44640
|
colorwaySizeAssetId: csa.colorwaySizeAssetId,
|
|
44487
|
-
size:
|
|
44641
|
+
size: effectiveSize,
|
|
44488
44642
|
color: csa.colorLabel
|
|
44489
44643
|
});
|
|
44490
44644
|
}, [resolved.items, updateFittingRoomItem]);
|
|
@@ -44576,13 +44730,16 @@ function FittingRoomOverlay({
|
|
|
44576
44730
|
if (outfit.items.length === 0) {
|
|
44577
44731
|
return;
|
|
44578
44732
|
}
|
|
44733
|
+
if (isMobileLayout && mobileMode === "browse") {
|
|
44734
|
+
return;
|
|
44735
|
+
}
|
|
44579
44736
|
requestVtoComposition(toWireItems(outfit.items), true);
|
|
44580
44737
|
if (getStaticData().config.features.vtoPrefetch) {
|
|
44581
44738
|
for (const alt of outfit.alternates) {
|
|
44582
44739
|
requestVtoComposition(toWireItems(alt), false);
|
|
44583
44740
|
}
|
|
44584
44741
|
}
|
|
44585
|
-
}, [userIsLoggedIn, userHasAvatar, outfit, requestVtoComposition]);
|
|
44742
|
+
}, [userIsLoggedIn, userHasAvatar, isMobileLayout, mobileMode, outfit, requestVtoComposition]);
|
|
44586
44743
|
const frameUrls = reactExports.useMemo(() => {
|
|
44587
44744
|
if (outfit.items.length === 0) {
|
|
44588
44745
|
const bareFrames = userProfile?.avatar_frames;
|
|
@@ -47103,9 +47260,9 @@ const SHARED_CONFIG = {
|
|
|
47103
47260
|
appGooglePlayUrl: "https://play.google.com/store/apps/details?id=com.thefittingroom.marketplace"
|
|
47104
47261
|
},
|
|
47105
47262
|
build: {
|
|
47106
|
-
version: `${"5.0.
|
|
47107
|
-
commitHash: `${"
|
|
47108
|
-
date: `${"2026-
|
|
47263
|
+
version: `${"5.0.31"}`,
|
|
47264
|
+
commitHash: `${"992c5c6"}`,
|
|
47265
|
+
date: `${"2026-06-07T14:43:50.848Z"}`
|
|
47109
47266
|
}
|
|
47110
47267
|
};
|
|
47111
47268
|
const CONFIGS = {
|