@thefittingroom/shop-ui 5.0.29 → 5.0.30

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.
Files changed (2) hide show
  1. package/dist/index.js +114 -15
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -42680,11 +42680,77 @@ function Chevron({
42680
42680
  transform: `rotate(${ROTATION_DEG[direction]}deg)`
42681
42681
  }, children: /* @__PURE__ */ jsx$1("path", { d: "M6 9L12 15L18 9", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
42682
42682
  }
42683
+ function ColorSwatchRow({
42684
+ colors,
42685
+ selectedLabel,
42686
+ onSelect
42687
+ }) {
42688
+ const css2 = useCss((theme) => ({
42689
+ row: {
42690
+ display: "flex",
42691
+ flexWrap: "wrap",
42692
+ gap: "6px"
42693
+ },
42694
+ swatch: {
42695
+ width: "24px",
42696
+ height: "24px",
42697
+ borderRadius: "50%",
42698
+ padding: 0,
42699
+ border: "1px solid rgba(0, 0, 0, 0.15)",
42700
+ backgroundColor: "#FFFFFF",
42701
+ cursor: "pointer",
42702
+ overflow: "hidden",
42703
+ display: "inline-flex",
42704
+ alignItems: "center",
42705
+ justifyContent: "center",
42706
+ // Reset native button chrome so the circle renders crisply.
42707
+ appearance: "none",
42708
+ WebkitAppearance: "none"
42709
+ },
42710
+ swatchSelected: {
42711
+ outline: `2px solid ${theme.color_fg_text}`,
42712
+ outlineOffset: "1px",
42713
+ borderColor: "transparent"
42714
+ },
42715
+ swatchImage: {
42716
+ width: "100%",
42717
+ height: "100%",
42718
+ objectFit: "cover"
42719
+ },
42720
+ // Tiny text label, used only as a last-resort fallback when neither an
42721
+ // image nor a hex is available. Truncates so a long colour name
42722
+ // doesn't break the swatch shape.
42723
+ swatchTextLabel: {
42724
+ fontSize: "9px",
42725
+ lineHeight: 1,
42726
+ color: theme.color_fg_text,
42727
+ padding: "0 2px",
42728
+ overflow: "hidden",
42729
+ textOverflow: "ellipsis",
42730
+ whiteSpace: "nowrap",
42731
+ maxWidth: "100%"
42732
+ }
42733
+ }));
42734
+ if (colors.length < 2) {
42735
+ return null;
42736
+ }
42737
+ return /* @__PURE__ */ jsx$1("div", { css: css2.row, children: colors.map((c) => {
42738
+ const isSelected = c.label === selectedLabel;
42739
+ const fillStyle = c.imageUrl ? void 0 : c.hex ? {
42740
+ backgroundColor: c.hex
42741
+ } : void 0;
42742
+ return /* @__PURE__ */ jsx$1(Button, { variant: "base", css: isSelected ? {
42743
+ ...css2.swatch,
42744
+ ...css2.swatchSelected
42745
+ } : 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);
42746
+ }) });
42747
+ }
42683
42748
  function ProductCard({
42684
42749
  item,
42685
42750
  availability,
42686
42751
  onClick,
42687
- onRemove
42752
+ onRemove,
42753
+ onChangeColor
42688
42754
  }) {
42689
42755
  const css2 = useCss((theme) => ({
42690
42756
  container: {
@@ -42782,6 +42848,29 @@ function ProductCard({
42782
42848
  const selectedVariant = item.merchantProduct?.variants.find((v) => v.color === effectiveColor && (!item.storage.size || v.size === item.storage.size));
42783
42849
  const imageUrl = selectedVariant?.imageUrl ?? item.merchantProduct?.imageUrl ?? null;
42784
42850
  const price = selectedVariant?.priceFormatted ?? item.merchantProduct?.variants[0]?.priceFormatted ?? null;
42851
+ const swatchColors = reactExports.useMemo(() => {
42852
+ const variants = item.merchantProduct?.variants;
42853
+ if (!variants) {
42854
+ return [];
42855
+ }
42856
+ const seen = /* @__PURE__ */ new Set();
42857
+ const out = [];
42858
+ for (const v of variants) {
42859
+ if (!v.color || seen.has(v.color)) {
42860
+ continue;
42861
+ }
42862
+ seen.add(v.color);
42863
+ out.push({
42864
+ label: v.color,
42865
+ imageUrl: v.swatchImageUrl ?? null,
42866
+ hex: v.swatchHex ?? null
42867
+ });
42868
+ }
42869
+ return out;
42870
+ }, [item.merchantProduct?.variants]);
42871
+ const handleSwatchSelect = (label) => {
42872
+ onChangeColor?.(item.externalId, label);
42873
+ };
42785
42874
  return /* @__PURE__ */ jsxs("div", { css: /* @__PURE__ */ css$1({
42786
42875
  ...css2.container,
42787
42876
  ...selected && css2.containerSelected,
@@ -42798,14 +42887,16 @@ function ProductCard({
42798
42887
  /* @__PURE__ */ jsx$1("div", { css: css2.imageContainer, children: imageUrl ? /* @__PURE__ */ jsx$1("img", { src: imageUrl, css: css2.image, alt: name2 }) : null }),
42799
42888
  /* @__PURE__ */ jsx$1(Text, { variant: "base", css: css2.nameText, children: name2 }),
42800
42889
  price ? /* @__PURE__ */ jsx$1(Text, { variant: "base", css: css2.priceText, children: price }) : null
42801
- ] })
42890
+ ] }),
42891
+ onChangeColor ? /* @__PURE__ */ jsx$1(ColorSwatchRow, { colors: swatchColors, selectedLabel: effectiveColor, onSelect: handleSwatchSelect }) : null
42802
42892
  ] });
42803
42893
  }
42804
42894
  function CardRail({
42805
42895
  group,
42806
42896
  availabilityByExternalId,
42807
42897
  onSelectItem,
42808
- onRemoveItem
42898
+ onRemoveItem,
42899
+ onChangeColor
42809
42900
  }) {
42810
42901
  const [collapsed, setCollapsed] = reactExports.useState(false);
42811
42902
  const scrollRef = reactExports.useRef(null);
@@ -42909,7 +43000,7 @@ function CardRail({
42909
43000
  right: 0
42910
43001
  }
42911
43002
  }));
42912
- const cards = group.items.map((item) => /* @__PURE__ */ jsx$1(ProductCard, { item, availability: availabilityByExternalId[item.externalId] ?? "disabled", onClick: () => onSelectItem(item.externalId), onRemove: () => onRemoveItem(item.externalId) }, item.externalId));
43003
+ const cards = group.items.map((item) => /* @__PURE__ */ jsx$1(ProductCard, { item, availability: availabilityByExternalId[item.externalId] ?? "disabled", onClick: () => onSelectItem(item.externalId), onRemove: () => onRemoveItem(item.externalId), onChangeColor }, item.externalId));
42913
43004
  return /* @__PURE__ */ jsxs("div", { css: css2.container, children: [
42914
43005
  /* @__PURE__ */ jsxs(Button, { variant: "base", css: css2.header, onClick: () => setCollapsed((c) => !c), children: [
42915
43006
  /* @__PURE__ */ jsx$1(Text, { variant: "base", css: css2.headerLabel, children: group.group.label }),
@@ -43776,7 +43867,7 @@ function DesktopLayout$1({
43776
43867
  ...css2.utilityLink,
43777
43868
  ...css2.clearAllWrapper
43778
43869
  }, "", ""), 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)),
43870
+ resolved.groups.map((group) => /* @__PURE__ */ jsx$1(CardRail, { group, availabilityByExternalId, onSelectItem, onRemoveItem, onChangeColor }, group.group.name)),
43780
43871
  /* @__PURE__ */ jsxs("span", { css: /* @__PURE__ */ css$1({
43781
43872
  ...css2.utilityLink,
43782
43873
  ...css2.signOutWrapper
@@ -43920,7 +44011,7 @@ function MobileLayout$1({
43920
44011
  onClearAll
43921
44012
  }) {
43922
44013
  if (mode === "browse") {
43923
- return /* @__PURE__ */ jsx$1(BrowseView, { resolved, availabilityByExternalId, selectedCount: selectedItems.length, onSelectItem, onRemoveItem, onTryItOn, onSignOut, onClearAll });
44014
+ return /* @__PURE__ */ jsx$1(BrowseView, { resolved, availabilityByExternalId, selectedCount: selectedItems.length, onSelectItem, onRemoveItem, onChangeColor, onTryItOn, onSignOut, onClearAll });
43924
44015
  }
43925
44016
  return /* @__PURE__ */ jsx$1(TryOnView, { selectedItems, openAccordionItemId, detailMode, forceUntuck, canTuck, frameUrls, autoRotateTrigger, sheetSnap, sheetTouchStart, onBackToBrowse, onOpenAccordionItem, onChangeDetailMode, onChangeSize, onChangeColor, onAddToCart, onToggleUntuck });
43926
44017
  }
@@ -43930,6 +44021,7 @@ function BrowseView({
43930
44021
  selectedCount,
43931
44022
  onSelectItem,
43932
44023
  onRemoveItem,
44024
+ onChangeColor,
43933
44025
  onTryItOn,
43934
44026
  onSignOut,
43935
44027
  onClearAll
@@ -44056,7 +44148,7 @@ function BrowseView({
44056
44148
  }
44057
44149
  }));
44058
44150
  return /* @__PURE__ */ jsxs("div", { css: css2.container, children: [
44059
- !resolved.isLoading && resolved.groups.length > 0 ? /* @__PURE__ */ jsx$1(SectionNav, { sections, activeName: activeSectionName, onSelect: scrollToSection }) : null,
44151
+ !resolved.isLoading && resolved.groups.length > 1 ? /* @__PURE__ */ jsx$1(SectionNav, { sections, activeName: activeSectionName, onSelect: scrollToSection }) : null,
44060
44152
  /* @__PURE__ */ jsxs("div", { ref: railsAreaRef, css: css2.railsArea, onScroll: recomputeActiveSection, children: [
44061
44153
  resolved.groups.map((group) => /* @__PURE__ */ jsx$1("div", { ref: (el) => {
44062
44154
  if (el) {
@@ -44064,7 +44156,7 @@ function BrowseView({
44064
44156
  } else {
44065
44157
  sectionRefs.current.delete(group.group.name);
44066
44158
  }
44067
- }, children: /* @__PURE__ */ jsx$1(CardRail, { group, availabilityByExternalId, onSelectItem, onRemoveItem }) }, group.group.name)),
44159
+ }, children: /* @__PURE__ */ jsx$1(CardRail, { group, availabilityByExternalId, onSelectItem, onRemoveItem, onChangeColor }) }, group.group.name)),
44068
44160
  /* @__PURE__ */ jsxs("span", { css: css2.signOutWrapper, onClick: onSignOut, children: [
44069
44161
  /* @__PURE__ */ jsx$1(SvgTfrIcon, { css: css2.signOutIcon }),
44070
44162
  /* @__PURE__ */ jsx$1(LinkT, { variant: "underline", css: css2.signOutText, t: "fitting_room.sign_out" })
@@ -44471,20 +44563,24 @@ function FittingRoomOverlay({
44471
44563
  }, [resolved.items, updateFittingRoomItem]);
44472
44564
  const handleChangeColor = reactExports.useCallback((externalId, colorLabel) => {
44473
44565
  const item = resolved.items.find((i) => i.externalId === externalId);
44474
- if (!item || !item.storage.size) {
44566
+ if (!item) {
44475
44567
  return;
44476
44568
  }
44477
44569
  const productData = buildVtoProductDataFromResolved(item);
44478
44570
  if (!productData) {
44479
44571
  return;
44480
44572
  }
44481
- const csa = findCsaByLabel(productData, item.storage.size, colorLabel);
44573
+ const effectiveSize = item.storage.size ?? productData.recommendedSizeLabel;
44574
+ if (!effectiveSize) {
44575
+ return;
44576
+ }
44577
+ const csa = findCsaByLabel(productData, effectiveSize, colorLabel);
44482
44578
  if (!csa) {
44483
44579
  return;
44484
44580
  }
44485
44581
  updateFittingRoomItem(externalId, {
44486
44582
  colorwaySizeAssetId: csa.colorwaySizeAssetId,
44487
- size: item.storage.size,
44583
+ size: effectiveSize,
44488
44584
  color: csa.colorLabel
44489
44585
  });
44490
44586
  }, [resolved.items, updateFittingRoomItem]);
@@ -44576,13 +44672,16 @@ function FittingRoomOverlay({
44576
44672
  if (outfit.items.length === 0) {
44577
44673
  return;
44578
44674
  }
44675
+ if (isMobileLayout && mobileMode === "browse") {
44676
+ return;
44677
+ }
44579
44678
  requestVtoComposition(toWireItems(outfit.items), true);
44580
44679
  if (getStaticData().config.features.vtoPrefetch) {
44581
44680
  for (const alt of outfit.alternates) {
44582
44681
  requestVtoComposition(toWireItems(alt), false);
44583
44682
  }
44584
44683
  }
44585
- }, [userIsLoggedIn, userHasAvatar, outfit, requestVtoComposition]);
44684
+ }, [userIsLoggedIn, userHasAvatar, isMobileLayout, mobileMode, outfit, requestVtoComposition]);
44586
44685
  const frameUrls = reactExports.useMemo(() => {
44587
44686
  if (outfit.items.length === 0) {
44588
44687
  const bareFrames = userProfile?.avatar_frames;
@@ -47103,9 +47202,9 @@ const SHARED_CONFIG = {
47103
47202
  appGooglePlayUrl: "https://play.google.com/store/apps/details?id=com.thefittingroom.marketplace"
47104
47203
  },
47105
47204
  build: {
47106
- version: `${"5.0.29"}`,
47107
- commitHash: `${"538bbd3"}`,
47108
- date: `${"2026-05-25T01:10:21.610Z"}`
47205
+ version: `${"5.0.30"}`,
47206
+ commitHash: `${"e4427c3"}`,
47207
+ date: `${"2026-06-07T13:46:16.711Z"}`
47109
47208
  }
47110
47209
  };
47111
47210
  const CONFIGS = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thefittingroom/shop-ui",
3
- "version": "5.0.29",
3
+ "version": "5.0.30",
4
4
  "description": "the fitting room UI library",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",