@fluid-app/portal-sdk 0.1.217 → 0.1.219

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 (81) hide show
  1. package/dist/{ContactsScreen-D-g7XEB-.cjs → ContactsScreen-DYVR-UvO.cjs} +1 -1
  2. package/dist/{FluidProvider-02beRTpR.mjs → FluidProvider-DTttgSXi.mjs} +8 -8
  3. package/dist/{FluidProvider-02beRTpR.mjs.map → FluidProvider-DTttgSXi.mjs.map} +1 -1
  4. package/dist/{FluidProvider-BgFmXtHo.cjs → FluidProvider-Dm4BhF_t.cjs} +8 -8
  5. package/dist/{FluidProvider-BgFmXtHo.cjs.map → FluidProvider-Dm4BhF_t.cjs.map} +1 -1
  6. package/dist/{ListWidget-C0ltFhxE.cjs → ListWidget-BE7uA4W4.cjs} +1 -2
  7. package/dist/{ListWidget-Ct8IDkio.mjs → ListWidget-D7y8bfvT.mjs} +252 -120
  8. package/dist/ListWidget-D7y8bfvT.mjs.map +1 -0
  9. package/dist/{ListWidget-C7ouNpEo.cjs → ListWidget-DJ-_dMOK.cjs} +251 -119
  10. package/dist/ListWidget-DJ-_dMOK.cjs.map +1 -0
  11. package/dist/{MessagingScreen-CJlVOY5R.mjs → MessagingScreen-CwEXQJlW.mjs} +2 -2
  12. package/dist/{MessagingScreen-CJlVOY5R.mjs.map → MessagingScreen-CwEXQJlW.mjs.map} +1 -1
  13. package/dist/{MessagingScreen-BkLcqJbs.cjs → MessagingScreen-DLQ5V0m4.cjs} +2 -2
  14. package/dist/{MessagingScreen-BkLcqJbs.cjs.map → MessagingScreen-DLQ5V0m4.cjs.map} +1 -1
  15. package/dist/{MessagingScreen-sN7aBvGk.cjs → MessagingScreen-YBXJL7a9.cjs} +6 -6
  16. package/dist/{MySiteScreen-DUN5TTvU.mjs → MySiteScreen-CyzM9hX3.mjs} +11 -30
  17. package/dist/{MySiteScreen-DUN5TTvU.mjs.map → MySiteScreen-CyzM9hX3.mjs.map} +1 -1
  18. package/dist/{MySiteScreen-B0aOIzU4.cjs → MySiteScreen-DPQ66oRs.cjs} +2 -2
  19. package/dist/{MySiteScreen-B1L8coGs.cjs → MySiteScreen-DxLcG3-S.cjs} +11 -30
  20. package/dist/MySiteScreen-DxLcG3-S.cjs.map +1 -0
  21. package/dist/{MySiteWidget-CDQjyrRA.cjs → MySiteWidget-8UsfEK-w.cjs} +1 -1
  22. package/dist/{MySiteWidget-CDQjyrRA.cjs.map → MySiteWidget-8UsfEK-w.cjs.map} +1 -1
  23. package/dist/{MySiteWidget-BlUbduit.mjs → MySiteWidget-D46TVWnf.mjs} +1 -1
  24. package/dist/{MySiteWidget-BlUbduit.mjs.map → MySiteWidget-D46TVWnf.mjs.map} +1 -1
  25. package/dist/{NestedWidget-ChAWwsRP.cjs → NestedWidget-BjT-UrSi.cjs} +2 -2
  26. package/dist/{NestedWidget-ChAWwsRP.cjs.map → NestedWidget-BjT-UrSi.cjs.map} +1 -1
  27. package/dist/{NestedWidget-Dw0QHoqw.mjs → NestedWidget-CEeQeCq0.mjs} +2 -2
  28. package/dist/{NestedWidget-Dw0QHoqw.mjs.map → NestedWidget-CEeQeCq0.mjs.map} +1 -1
  29. package/dist/{NestedWidget--suTLM6l.cjs → NestedWidget-D4amXykk.cjs} +2 -2
  30. package/dist/{PortalContentApiProvider-RXBp8FNj.cjs → PortalContentApiProvider-DXnplIOD.cjs} +273 -82
  31. package/dist/PortalContentApiProvider-DXnplIOD.cjs.map +1 -0
  32. package/dist/{PortalContentApiProvider-C9FeVwRb.mjs → PortalContentApiProvider-x81DXmOR.mjs} +273 -82
  33. package/dist/PortalContentApiProvider-x81DXmOR.mjs.map +1 -0
  34. package/dist/{ProductsScreen-DNpzJ6lh.cjs → ProductsScreen-3yjIMjYY.cjs} +2 -2
  35. package/dist/{ProductsScreen-pkOeOW8M.mjs → ProductsScreen-BVyLOe2K.mjs} +2 -2
  36. package/dist/{ProductsScreen-BD53vh6Y.cjs → ProductsScreen-R0MfWYZJ.cjs} +2 -2
  37. package/dist/{ProductsScreen-BD53vh6Y.cjs.map → ProductsScreen-R0MfWYZJ.cjs.map} +1 -1
  38. package/dist/{ProductsScreen-BtUZxJCt.mjs → ProductsScreen-z9hXfFeJ.mjs} +2 -2
  39. package/dist/{ProductsScreen-BtUZxJCt.mjs.map → ProductsScreen-z9hXfFeJ.mjs.map} +1 -1
  40. package/dist/{ProfileScreen-rPqgsNCc.cjs → ProfileScreen-B0WRifk_.cjs} +2 -2
  41. package/dist/{ProfileScreen-rPqgsNCc.cjs.map → ProfileScreen-B0WRifk_.cjs.map} +1 -1
  42. package/dist/{ProfileScreen-CNYqUDNB.mjs → ProfileScreen-BuejQU_V.mjs} +2 -2
  43. package/dist/{ProfileScreen-CNYqUDNB.mjs.map → ProfileScreen-BuejQU_V.mjs.map} +1 -1
  44. package/dist/{ProfileScreen-Bgo6iTKe.cjs → ProfileScreen-g3se9Jw-.cjs} +6 -6
  45. package/dist/{ShareablesScreen-DC8xXUo4.cjs → ShareablesScreen-Co_gFZva.cjs} +3 -3
  46. package/dist/{ShareablesScreen-DC8xXUo4.cjs.map → ShareablesScreen-Co_gFZva.cjs.map} +1 -1
  47. package/dist/{ShareablesScreen-D1J2Kljk.mjs → ShareablesScreen-DpwFh0ky.mjs} +3 -3
  48. package/dist/{ShareablesScreen-smU5pGyH.cjs → ShareablesScreen-YlMqyP-B.cjs} +3 -3
  49. package/dist/{ShareablesScreen-CW1e9x4K.mjs → ShareablesScreen-tkaf9R5N.mjs} +3 -3
  50. package/dist/{ShareablesScreen-CW1e9x4K.mjs.map → ShareablesScreen-tkaf9R5N.mjs.map} +1 -1
  51. package/dist/{ShopScreen-B9lHJ8L2.mjs → ShopScreen-B4afB5sE.mjs} +2 -2
  52. package/dist/{ShopScreen-B9lHJ8L2.mjs.map → ShopScreen-B4afB5sE.mjs.map} +1 -1
  53. package/dist/{ShopScreen-g6FQ4R1_.cjs → ShopScreen-BOjri6Dm.cjs} +6 -6
  54. package/dist/{ShopScreen-DUHzufCU.cjs → ShopScreen-Untg6XBY.cjs} +2 -2
  55. package/dist/{ShopScreen-DUHzufCU.cjs.map → ShopScreen-Untg6XBY.cjs.map} +1 -1
  56. package/dist/index.cjs +27 -27
  57. package/dist/index.d.cts.map +1 -1
  58. package/dist/index.d.mts.map +1 -1
  59. package/dist/index.mjs +25 -25
  60. package/dist/{portal_tenant_content-0zpnjBot.cjs → portal_tenant_content-BvYxmADB.cjs} +18 -1
  61. package/dist/portal_tenant_content-BvYxmADB.cjs.map +1 -0
  62. package/dist/{portal_tenant_content-DzIQtSLE.mjs → portal_tenant_content-nHEI2qEY.mjs} +13 -2
  63. package/dist/portal_tenant_content-nHEI2qEY.mjs.map +1 -0
  64. package/dist/{scroll-arrows-fK_MFlSX.mjs → scroll-arrows-COrfvJk9.mjs} +1 -1
  65. package/dist/{scroll-arrows-fK_MFlSX.mjs.map → scroll-arrows-COrfvJk9.mjs.map} +1 -1
  66. package/dist/{scroll-arrows-DVwMDTt3.cjs → scroll-arrows-i0E2N-ct.cjs} +1 -1
  67. package/dist/{scroll-arrows-DVwMDTt3.cjs.map → scroll-arrows-i0E2N-ct.cjs.map} +1 -1
  68. package/dist/{use-mysite-portal-BV-BP3CE.mjs → use-mysite-portal-D29HLD1z.mjs} +3 -2
  69. package/dist/use-mysite-portal-D29HLD1z.mjs.map +1 -0
  70. package/dist/{use-mysite-portal-DzDYRU0u.cjs → use-mysite-portal-DxNQ3uTi.cjs} +3 -2
  71. package/dist/use-mysite-portal-DxNQ3uTi.cjs.map +1 -0
  72. package/package.json +9 -9
  73. package/dist/ListWidget-C7ouNpEo.cjs.map +0 -1
  74. package/dist/ListWidget-Ct8IDkio.mjs.map +0 -1
  75. package/dist/MySiteScreen-B1L8coGs.cjs.map +0 -1
  76. package/dist/PortalContentApiProvider-C9FeVwRb.mjs.map +0 -1
  77. package/dist/PortalContentApiProvider-RXBp8FNj.cjs.map +0 -1
  78. package/dist/portal_tenant_content-0zpnjBot.cjs.map +0 -1
  79. package/dist/portal_tenant_content-DzIQtSLE.mjs.map +0 -1
  80. package/dist/use-mysite-portal-BV-BP3CE.mjs.map +0 -1
  81. package/dist/use-mysite-portal-DzDYRU0u.cjs.map +0 -1
@@ -4,6 +4,5 @@ require("./registries-CpUM406S.cjs");
4
4
  require("./fields-C8gY9GlT.cjs");
5
5
  require("./purify.es-BQcWWtgQ.cjs");
6
6
  require("./MediaRenderer-D4HnIAbN.cjs");
7
- const require_ListWidget = require("./ListWidget-C7ouNpEo.cjs");
8
- require("./scroll-arrows-DVwMDTt3.cjs");
7
+ const require_ListWidget = require("./ListWidget-DJ-_dMOK.cjs");
9
8
  exports.listWidgetPropertySchema = require_ListWidget.listWidgetPropertySchema;
@@ -3,13 +3,22 @@ import { t as useWidgetInteraction } from "./WidgetInteractionContext-CS5--u84.m
3
3
  import { f as getGapField, i as getBorderColorField, l as getColorField, m as getPaddingField, n as borderWidthClasses, o as getBorderRadiusField, r as gapValues, s as getBorderWidthField, t as borderColorClasses, u as getFontSizeField } from "./registries-DT36l-bR.mjs";
4
4
  import { t as purify } from "./purify.es-Bl6SBkmi.mjs";
5
5
  import { t as MediaRenderer } from "./MediaRenderer-C-cxsqLq.mjs";
6
- import { t as ScrollArrows } from "./scroll-arrows-fK_MFlSX.mjs";
7
- import { useRef } from "react";
6
+ import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
8
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
+ import { ChevronLeft, ChevronRight } from "lucide-react";
9
+ //#region ../widgets/src/widgets/list-widget/helpers.ts
10
+ /**
11
+ * Maps the schema's BorderRadiusOptions to a Tailwind `rounded-*` class.
12
+ * `"full"` is converted to `rounded-2xl` because the list item cards and
13
+ * featured section read better as large-radius rectangles than as
14
+ * pill-shaped containers.
15
+ */
16
+ const cardRadiusClass = (radius) => radius === "full" ? "rounded-2xl" : `rounded-${radius}`;
17
+ //#endregion
9
18
  //#region ../widgets/src/widgets/list-widget/FeaturedSection.tsx
10
19
  function FeaturedSection({ borderRadius, titleSize, featuredTitle, featuredSubtitle, featuredButtonText, featuredButtonUrl, featuredSubtitleColor, featuredSubtitleSize, asset }) {
11
20
  return /* @__PURE__ */ jsxs("div", {
12
- className: `relative h-full min-h-[300px] w-full overflow-hidden rounded-${borderRadius}`,
21
+ className: `group relative h-full min-h-[320px] w-full overflow-hidden ${cardRadiusClass(borderRadius)}`,
13
22
  children: [
14
23
  /* @__PURE__ */ jsx("div", {
15
24
  className: "absolute inset-0 h-full w-full",
@@ -24,22 +33,29 @@ function FeaturedSection({ borderRadius, titleSize, featuredTitle, featuredSubti
24
33
  controls: false
25
34
  })
26
35
  }),
27
- /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0 bg-black/40" }),
36
+ /* @__PURE__ */ jsx("div", {
37
+ className: "pointer-events-none absolute inset-0",
38
+ style: { background: "linear-gradient(180deg, rgba(0,0,0,0) 45%, rgba(0,0,0,0.55) 100%)" }
39
+ }),
28
40
  /* @__PURE__ */ jsxs("div", {
29
- className: "absolute inset-0 flex flex-col items-start justify-end p-8",
41
+ className: "absolute inset-0 flex flex-col items-start justify-end p-10",
30
42
  children: [
31
43
  featuredTitle && /* @__PURE__ */ jsx("h3", {
32
- className: `font-header mb-2 font-bold text-white text-${titleSize === "md" ? "base" : titleSize}`,
44
+ className: `font-header mb-3 font-medium tracking-tight text-white text-${titleSize === "md" ? "base" : titleSize}`,
33
45
  children: featuredTitle
34
46
  }),
35
47
  featuredSubtitle && /* @__PURE__ */ jsx("p", {
36
- className: `mb-4 text-${featuredSubtitleColor} text-${featuredSubtitleSize === "md" ? "base" : featuredSubtitleSize}`,
48
+ className: `mb-6 max-w-md text-${featuredSubtitleColor}/80 text-${featuredSubtitleSize === "md" ? "base" : featuredSubtitleSize} leading-relaxed`,
37
49
  children: featuredSubtitle
38
50
  }),
39
- featuredButtonText && /* @__PURE__ */ jsx("a", {
51
+ featuredButtonText && /* @__PURE__ */ jsxs("a", {
40
52
  href: featuredButtonUrl || "#",
41
- className: `text-foreground bg-white px-6 py-2 font-medium transition-opacity hover:opacity-90 rounded-${borderRadius}`,
42
- children: featuredButtonText
53
+ className: `text-foreground inline-flex items-center gap-2 bg-white px-6 py-3 text-sm font-medium tracking-tight transition-opacity hover:opacity-90 ${cardRadiusClass(borderRadius)}`,
54
+ children: [featuredButtonText, /* @__PURE__ */ jsx("span", {
55
+ "aria-hidden": "true",
56
+ className: "transition-transform group-hover:translate-x-0.5",
57
+ children: "→"
58
+ })]
43
59
  })
44
60
  ]
45
61
  })
@@ -69,34 +85,26 @@ function getStringValue(value) {
69
85
  }
70
86
  return "";
71
87
  }
72
- /**
73
- * Strips parenthetical text like "(USD)" from price strings.
74
- * Matches the shop page's stripParentheticalText pattern.
75
- */
76
88
  function stripParentheticalText(text) {
77
89
  return text.replace(/\s*\([^)]*\)/g, "").trim();
78
90
  }
79
- /**
80
- * Formats a price for display. Follows the shop page pattern:
81
- * prices arrive pre-formatted from the API via display_price
82
- * (e.g. "$19.99", "€15.00 (EUR)") so we just extract the string
83
- * and strip parenthetical suffixes.
84
- */
85
91
  function formatPrice(value) {
86
92
  const str = getStringValue(value);
87
93
  if (!str) return "";
88
94
  return stripParentheticalText(str);
89
95
  }
90
96
  function ListItemCardContent({ item, padding, itemTitleColor, itemTitleSize, descriptionColor, descriptionSize, priceColor, priceSize, originalPriceColor, metaTextColor, metaTextSize, showMetaText }) {
97
+ const hasPrice = Boolean(item.display_price || item.price);
98
+ const hasOriginal = Boolean(item.originalPrice);
91
99
  return /* @__PURE__ */ jsxs("div", {
92
100
  className: `flex flex-1 flex-col p-${padding}`,
93
101
  children: [
94
102
  item.title && /* @__PURE__ */ jsx("h3", {
95
- className: `text-${itemTitleColor} text-${itemTitleSize === "md" ? "base" : itemTitleSize} font-header mb-1 font-semibold`,
103
+ className: `text-${itemTitleColor} text-${itemTitleSize === "md" ? "base" : itemTitleSize} font-header mb-1.5 leading-snug font-medium tracking-tight`,
96
104
  children: getStringValue(item.title)
97
105
  }),
98
106
  item.description && /* @__PURE__ */ jsx("div", {
99
- className: `text-${descriptionColor} text-${descriptionSize === "md" ? "base" : descriptionSize} mb-2 line-clamp-2 overflow-hidden`,
107
+ className: `text-${descriptionColor}/60 text-${descriptionSize === "md" ? "base" : descriptionSize} mb-3 line-clamp-2 overflow-hidden leading-relaxed`,
100
108
  dangerouslySetInnerHTML: { __html: purify.sanitize(item.description ?? "", {
101
109
  ALLOWED_TAGS: [
102
110
  "br",
@@ -112,26 +120,46 @@ function ListItemCardContent({ item, padding, itemTitleColor, itemTitleSize, des
112
120
  ALLOWED_ATTR: []
113
121
  }) }
114
122
  }),
115
- /* @__PURE__ */ jsxs("div", {
116
- className: "flex items-center gap-2",
117
- children: [(item.display_price || item.price) && /* @__PURE__ */ jsx("span", {
118
- className: `text-${priceColor} text-${priceSize === "md" ? "base" : priceSize} font-bold`,
123
+ (hasPrice || hasOriginal) && /* @__PURE__ */ jsxs("div", {
124
+ className: "mt-auto flex items-baseline gap-2",
125
+ children: [hasPrice && /* @__PURE__ */ jsx("span", {
126
+ className: `text-${priceColor} text-${priceSize === "md" ? "base" : priceSize} font-semibold tracking-tight tabular-nums`,
119
127
  children: formatPrice(item.display_price || item.price)
120
- }), item.originalPrice && /* @__PURE__ */ jsx("span", {
121
- className: `text-${originalPriceColor} text-${descriptionSize === "md" ? "base" : descriptionSize} line-through`,
128
+ }), hasOriginal && /* @__PURE__ */ jsx("span", {
129
+ className: `text-${originalPriceColor}/50 text-${descriptionSize === "md" ? "base" : descriptionSize} tabular-nums line-through`,
122
130
  children: formatPrice(item.originalPrice)
123
131
  })]
124
132
  }),
125
133
  showMetaText && (item.qv || item.cv) && /* @__PURE__ */ jsxs("div", {
126
- className: `mt-2 flex gap-3 text-${metaTextColor} text-${metaTextSize === "md" ? "base" : metaTextSize}`,
127
- children: [item.qv && /* @__PURE__ */ jsxs("span", { children: ["QV: ", getStringValue(item.qv)] }), item.cv && /* @__PURE__ */ jsxs("span", { children: ["CV: ", getStringValue(item.cv)] })]
134
+ className: `mt-2 flex gap-4 text-${metaTextColor}/70 text-${metaTextSize === "md" ? "base" : metaTextSize} font-medium tracking-wide uppercase`,
135
+ children: [item.qv && /* @__PURE__ */ jsxs("span", { children: [
136
+ /* @__PURE__ */ jsx("span", {
137
+ className: "opacity-50",
138
+ children: "QV"
139
+ }),
140
+ " ",
141
+ /* @__PURE__ */ jsx("span", {
142
+ className: "tabular-nums",
143
+ children: getStringValue(item.qv)
144
+ })
145
+ ] }), item.cv && /* @__PURE__ */ jsxs("span", { children: [
146
+ /* @__PURE__ */ jsx("span", {
147
+ className: "opacity-50",
148
+ children: "CV"
149
+ }),
150
+ " ",
151
+ /* @__PURE__ */ jsx("span", {
152
+ className: "tabular-nums",
153
+ children: getStringValue(item.cv)
154
+ })
155
+ ] })]
128
156
  })
129
157
  ]
130
158
  });
131
159
  }
132
160
  function DiscountBadge({ discount }) {
133
161
  return /* @__PURE__ */ jsx("div", {
134
- className: "bg-destructive text-destructive-foreground absolute top-2 right-2 z-10 rounded-md px-2 py-1 text-xs font-bold",
162
+ className: "bg-background text-foreground absolute top-3 left-3 z-10 rounded-full px-2.5 py-1 text-[10px] font-semibold tracking-[0.08em] uppercase",
135
163
  children: getStringValue(discount)
136
164
  });
137
165
  }
@@ -140,7 +168,7 @@ function DiscountBadge({ discount }) {
140
168
  const getImageUrl$1 = (item) => {
141
169
  return item.imageUrl || item.image;
142
170
  };
143
- const getAspectRatioClass$1 = (ratio) => {
171
+ const getAspectRatioClass = (ratio) => {
144
172
  return {
145
173
  square: "aspect-square",
146
174
  landscape: "aspect-video",
@@ -164,9 +192,9 @@ function UnorderedList({ items, columns, gap, borderRadius, imageAspectRatio, sh
164
192
  className: `grid ${gridClass} gap-${gapValues[gap]}`,
165
193
  children: items.map((item) => {
166
194
  const imageUrl = getImageUrl$1(item);
167
- const aspectRatioClass = getAspectRatioClass$1(imageAspectRatio);
195
+ const aspectRatioClass = getAspectRatioClass(imageAspectRatio);
168
196
  return /* @__PURE__ */ jsxs("div", {
169
- className: `relative flex flex-col rounded-${borderRadius === "full" ? "2xl" : borderRadius} bg-background overflow-hidden shadow-sm transition-shadow hover:shadow-md ${onItemClick ? "cursor-pointer" : ""}`,
197
+ className: `group relative flex flex-col ${onItemClick ? "cursor-pointer" : ""}`,
170
198
  ...onItemClick ? {
171
199
  role: "button",
172
200
  tabIndex: 0,
@@ -178,17 +206,16 @@ function UnorderedList({ items, columns, gap, borderRadius, imageAspectRatio, sh
178
206
  }
179
207
  }
180
208
  } : {},
181
- children: [
182
- showBadge && item.discount && /* @__PURE__ */ jsx(DiscountBadge, { discount: item.discount }),
183
- imageUrl && /* @__PURE__ */ jsx("div", {
184
- className: `w-full ${aspectRatioClass} overflow-hidden`,
185
- children: /* @__PURE__ */ jsx("img", {
186
- src: imageUrl,
187
- alt: item.title || "Product",
188
- className: "h-full w-full object-cover"
189
- })
190
- }),
191
- /* @__PURE__ */ jsx(ListItemCardContent, {
209
+ children: [imageUrl && /* @__PURE__ */ jsxs("div", {
210
+ className: `relative w-full ${aspectRatioClass} bg-muted/30 overflow-hidden ${cardRadiusClass(borderRadius)}`,
211
+ children: [showBadge && item.discount && /* @__PURE__ */ jsx(DiscountBadge, { discount: item.discount }), /* @__PURE__ */ jsx("img", {
212
+ src: imageUrl,
213
+ alt: item.title || "Product",
214
+ className: "h-full w-full object-cover transition-opacity duration-300 group-hover:opacity-90"
215
+ })]
216
+ }), /* @__PURE__ */ jsx("div", {
217
+ className: "mt-4",
218
+ children: /* @__PURE__ */ jsx(ListItemCardContent, {
192
219
  item,
193
220
  padding,
194
221
  itemTitleColor,
@@ -202,43 +229,20 @@ function UnorderedList({ items, columns, gap, borderRadius, imageAspectRatio, sh
202
229
  metaTextSize,
203
230
  showMetaText
204
231
  })
205
- ]
232
+ })]
206
233
  }, item.id);
207
234
  })
208
235
  });
209
236
  }
210
237
  //#endregion
211
238
  //#region ../widgets/src/widgets/list-widget/OrderedList.tsx
212
- const SCROLL_ITEM_WIDTH = 300;
213
239
  const getImageUrl = (item) => {
214
240
  return item.imageUrl || item.image;
215
241
  };
216
- const getAspectRatioClass = (ratio) => {
217
- return {
218
- square: "aspect-square",
219
- landscape: "aspect-video",
220
- portrait: "aspect-[3/4]"
221
- }[ratio];
222
- };
223
- const largeNumberSizes = {
224
- xs: "8rem",
225
- sm: "10rem",
226
- md: "12rem",
227
- lg: "14rem",
228
- xl: "16rem",
229
- "2xl": "20rem"
230
- };
231
- function OrderedList({ items, scrollAxis, gap, borderRadius, imageAspectRatio, showBadge, padding, itemTitleColor, itemTitleSize, descriptionColor, descriptionSize, priceColor, priceSize, originalPriceColor, metaTextColor, metaTextSize, numberColor, numberSize, showMetaText }) {
232
- const scrollContainerRef = useRef(null);
233
- const scrollByAmount = (direction) => {
234
- const container = scrollContainerRef.current;
235
- if (!container) return;
236
- const scrollAmount = SCROLL_ITEM_WIDTH + (parseFloat(getComputedStyle(container).gap) || 0);
237
- container.scrollTo({
238
- left: container.scrollLeft + (direction === "next" ? scrollAmount : -scrollAmount),
239
- behavior: "smooth"
240
- });
241
- };
242
+ const formatRank = (n) => n < 10 ? `0${n}` : String(n);
243
+ function OrderedList({ items, scrollAxis, gap, borderRadius, imageAspectRatio: _imageAspectRatio, showBadge, padding, itemTitleColor, itemTitleSize, descriptionColor, descriptionSize, priceColor, priceSize, originalPriceColor, metaTextColor, metaTextSize, numberColor, numberSize, showMetaText, scrollContainerRef: externalScrollRef }) {
244
+ const internalScrollRef = useRef(null);
245
+ const scrollContainerRef = externalScrollRef ?? internalScrollRef;
242
246
  const { onItemClick } = useWidgetInteraction();
243
247
  const interactionProps = (item) => onItemClick ? {
244
248
  role: "button",
@@ -264,63 +268,84 @@ function OrderedList({ items, scrollAxis, gap, borderRadius, imageAspectRatio, s
264
268
  metaTextSize,
265
269
  showMetaText
266
270
  };
267
- if (scrollAxis === "horizontal") return /* @__PURE__ */ jsxs("div", {
268
- className: "relative overflow-hidden",
269
- children: [/* @__PURE__ */ jsx("div", {
271
+ if (scrollAxis === "horizontal") return /* @__PURE__ */ jsx("div", {
272
+ className: "relative",
273
+ children: /* @__PURE__ */ jsx("div", {
270
274
  ref: scrollContainerRef,
271
- className: `flex gap-${gapValues[gap]} scrollbar-hide overflow-x-auto overflow-y-hidden scroll-smooth pb-2`,
275
+ className: `flex gap-${gapValues[gap]} scrollbar-hide overflow-x-auto overflow-y-hidden scroll-smooth`,
272
276
  children: items.map((item, index) => {
273
277
  const imageUrl = getImageUrl(item);
274
- const aspectRatioClass = getAspectRatioClass(imageAspectRatio);
278
+ const rank = index + 1;
275
279
  return /* @__PURE__ */ jsxs("div", {
276
- className: `relative flex w-[300px] flex-shrink-0 flex-col ${onItemClick ? "cursor-pointer" : ""}`,
280
+ className: `group relative flex flex-shrink-0 flex-col ${onItemClick ? "cursor-pointer" : ""}`,
277
281
  ...interactionProps(item),
278
- children: [/* @__PURE__ */ jsx("div", {
279
- className: `absolute top-0 left-0 text-${numberColor} z-0 leading-none font-bold opacity-20`,
280
- style: { fontSize: largeNumberSizes[numberSize] },
281
- children: index + 1
282
- }), /* @__PURE__ */ jsxs("div", {
283
- className: `relative z-10 ml-20 flex flex-1 flex-col rounded-${borderRadius === "full" ? "2xl" : borderRadius} bg-background overflow-hidden shadow-sm transition-shadow hover:shadow-md`,
282
+ children: [/* @__PURE__ */ jsxs("div", {
283
+ className: "flex items-end",
284
284
  children: [
285
- showBadge && item.discount && /* @__PURE__ */ jsx(DiscountBadge, { discount: item.discount }),
286
- imageUrl && /* @__PURE__ */ jsx("div", {
287
- className: `w-full ${aspectRatioClass} overflow-hidden`,
288
- children: /* @__PURE__ */ jsx("img", {
285
+ /* @__PURE__ */ jsxs("span", {
286
+ className: "sr-only",
287
+ children: [
288
+ "Rank ",
289
+ rank,
290
+ ": "
291
+ ]
292
+ }),
293
+ /* @__PURE__ */ jsx("span", {
294
+ className: `text-${numberColor} pointer-events-none flex-shrink-0 font-black italic tabular-nums select-none`,
295
+ style: {
296
+ fontSize: "11rem",
297
+ lineHeight: "0.82",
298
+ letterSpacing: "-0.06em"
299
+ },
300
+ "aria-hidden": "true",
301
+ children: rank
302
+ }),
303
+ imageUrl && /* @__PURE__ */ jsxs("div", {
304
+ className: `relative aspect-[3/4] w-[200px] flex-shrink-0 ${cardRadiusClass(borderRadius)} bg-muted/30 overflow-hidden`,
305
+ children: [showBadge && item.discount && /* @__PURE__ */ jsx(DiscountBadge, { discount: item.discount }), /* @__PURE__ */ jsx("img", {
289
306
  src: imageUrl,
290
307
  alt: item.title || "Product",
291
308
  className: "h-full w-full object-cover"
292
- })
293
- }),
294
- /* @__PURE__ */ jsx(ListItemCardContent, {
295
- item,
296
- ...contentProps
309
+ })]
297
310
  })
298
311
  ]
312
+ }), /* @__PURE__ */ jsx("div", {
313
+ className: "mt-5 ml-auto w-[200px]",
314
+ children: /* @__PURE__ */ jsx(ListItemCardContent, {
315
+ item,
316
+ ...contentProps
317
+ })
299
318
  })]
300
319
  }, item.id);
301
320
  })
302
- }), /* @__PURE__ */ jsx("div", {
303
- className: "absolute inset-x-0 top-1/2 z-20 flex w-full -translate-y-1/2 items-center justify-between px-8",
304
- children: /* @__PURE__ */ jsx(ScrollArrows, {
305
- onPrevious: () => scrollByAmount("prev"),
306
- onNext: () => scrollByAmount("next")
307
- })
308
- })]
321
+ })
309
322
  });
310
323
  if (scrollAxis === "vertical") return /* @__PURE__ */ jsx("div", {
311
324
  className: `flex flex-col gap-${gapValues[gap]}`,
312
325
  children: items.map((item, index) => {
313
326
  const imageUrl = getImageUrl(item);
327
+ const rank = index + 1;
328
+ const isLast = index === items.length - 1;
314
329
  return /* @__PURE__ */ jsxs("div", {
315
- className: `relative flex gap-${gapValues[gap]} rounded-${borderRadius === "full" ? "2xl" : borderRadius} bg-background overflow-hidden shadow-sm transition-shadow hover:shadow-md ${`p-${padding}`} ${onItemClick ? "cursor-pointer" : ""}`,
330
+ className: `group relative flex items-center gap-${gapValues[gap]} py-6 ${!isLast ? "border-b" : ""} ${onItemClick ? "cursor-pointer" : ""}`,
331
+ style: !isLast ? { borderColor: "color-mix(in oklch, var(--color-foreground) 8%, transparent)" } : void 0,
316
332
  ...interactionProps(item),
317
333
  children: [
318
- /* @__PURE__ */ jsx("div", {
319
- className: `flex-shrink-0 text-${numberColor} text-${numberSize === "md" ? "base" : numberSize} flex w-16 items-center justify-center font-bold`,
320
- children: index + 1
334
+ /* @__PURE__ */ jsxs("span", {
335
+ className: "sr-only",
336
+ children: [
337
+ "Rank ",
338
+ rank,
339
+ ": "
340
+ ]
341
+ }),
342
+ /* @__PURE__ */ jsx("span", {
343
+ className: `text-${numberColor} font-header w-14 flex-shrink-0 text-${numberSize === "md" ? "base" : numberSize} leading-none font-light tracking-tight italic`,
344
+ "aria-hidden": "true",
345
+ children: formatRank(rank)
321
346
  }),
322
347
  imageUrl && /* @__PURE__ */ jsx("div", {
323
- className: "h-24 w-24 flex-shrink-0 overflow-hidden rounded-md",
348
+ className: `relative h-16 w-16 flex-shrink-0 overflow-hidden ${cardRadiusClass(borderRadius)} bg-muted/30`,
324
349
  children: /* @__PURE__ */ jsx("img", {
325
350
  src: imageUrl,
326
351
  alt: item.title || "Product",
@@ -328,14 +353,14 @@ function OrderedList({ items, scrollAxis, gap, borderRadius, imageAspectRatio, s
328
353
  })
329
354
  }),
330
355
  /* @__PURE__ */ jsx("div", {
331
- className: "flex-1",
356
+ className: "min-w-0 flex-1",
332
357
  children: /* @__PURE__ */ jsx(ListItemCardContent, {
333
358
  item,
334
359
  ...contentProps
335
360
  })
336
361
  }),
337
- showBadge && item.discount && /* @__PURE__ */ jsx("div", {
338
- className: "bg-destructive text-destructive-foreground absolute top-2 right-2 rounded-md px-2 py-1 text-xs font-bold",
362
+ showBadge && item.discount && /* @__PURE__ */ jsx("span", {
363
+ className: "text-muted ml-2 flex-shrink-0 text-[10px] font-semibold tracking-[0.08em] uppercase",
339
364
  children: getStringValue(item.discount)
340
365
  })
341
366
  ]
@@ -397,17 +422,53 @@ function ListWidget({ listType = "unordered", scrollAxis = "horizontal", titleEn
397
422
  const shouldShowFeaturedSection = showFeaturedSection && hasFeaturedAsset;
398
423
  const backgroundColor = background.color || "background";
399
424
  const backgroundImage = (background.resource?.image_url || background.resource?.imageUrl) && background.type === "image" ? `url(${background.resource.image_url || background.resource.imageUrl})` : "none";
425
+ const isOrderedHorizontal = listType === "ordered" && scrollAxis === "horizontal";
426
+ const showScrollArrows = isOrderedHorizontal && hasItems && displayItems.length > 1;
427
+ const { scrollContainerRef, canScrollPrev, canScrollNext, scrollByAmount } = useHorizontalScrollState({
428
+ enabled: showScrollArrows,
429
+ contentLength: displayItems.length
430
+ });
431
+ const hasTitle = titleEnabled && title;
432
+ const showTitleRow = hasTitle || showScrollArrows;
400
433
  return /* @__PURE__ */ jsxs("div", {
401
434
  className: `@container bg-${backgroundColor} p-${padding} rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== "none" ? borderColorClasses[borderColor] : ""} ${className}`,
402
435
  style: { backgroundImage },
403
436
  ...props,
404
- children: [titleEnabled && title && /* @__PURE__ */ jsx("h2", {
405
- className: `text-${titleColor} text-${titleSize === "md" ? "base" : titleSize} font-header mb-6 font-bold`,
406
- children: title
437
+ children: [showTitleRow && /* @__PURE__ */ jsxs("div", {
438
+ className: "mb-8 flex items-center justify-between gap-4",
439
+ children: [hasTitle ? /* @__PURE__ */ jsx("h2", {
440
+ className: `text-${titleColor} text-${titleSize === "md" ? "base" : titleSize} font-header leading-tight font-medium tracking-tight`,
441
+ children: title
442
+ }) : /* @__PURE__ */ jsx("span", {}), showScrollArrows && /* @__PURE__ */ jsxs("div", {
443
+ className: "flex shrink-0 items-center gap-2",
444
+ children: [/* @__PURE__ */ jsx("button", {
445
+ type: "button",
446
+ onClick: () => scrollByAmount("prev"),
447
+ disabled: !canScrollPrev,
448
+ "aria-label": "Previous items",
449
+ className: `text-${numberColor} flex size-9 items-center justify-center rounded-full transition-opacity hover:opacity-60 disabled:cursor-not-allowed disabled:opacity-20`,
450
+ style: { boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${numberColor}) 25%, transparent)` },
451
+ children: /* @__PURE__ */ jsx(ChevronLeft, {
452
+ "aria-hidden": "true",
453
+ className: "size-4"
454
+ })
455
+ }), /* @__PURE__ */ jsx("button", {
456
+ type: "button",
457
+ onClick: () => scrollByAmount("next"),
458
+ disabled: !canScrollNext,
459
+ "aria-label": "Next items",
460
+ className: `text-${numberColor} flex size-9 items-center justify-center rounded-full transition-opacity hover:opacity-60 disabled:cursor-not-allowed disabled:opacity-20`,
461
+ style: { boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${numberColor}) 25%, transparent)` },
462
+ children: /* @__PURE__ */ jsx(ChevronRight, {
463
+ "aria-hidden": "true",
464
+ className: "size-4"
465
+ })
466
+ })]
467
+ })]
407
468
  }), !hasItems ? /* @__PURE__ */ jsx("div", {
408
- className: "border-border bg-muted flex items-center justify-center rounded-md border-2 border-dashed py-12 text-center",
469
+ className: "flex items-center justify-center py-20 text-center",
409
470
  children: /* @__PURE__ */ jsx("p", {
410
- className: "text-muted",
471
+ className: "text-muted/70 text-sm tracking-tight",
411
472
  children: "No items to display"
412
473
  })
413
474
  }) : shouldShowFeaturedSection ? /* @__PURE__ */ jsxs("div", {
@@ -436,6 +497,7 @@ function ListWidget({ listType = "unordered", scrollAxis = "horizontal", titleEn
436
497
  scrollAxis,
437
498
  numberColor,
438
499
  numberSize,
500
+ scrollContainerRef: isOrderedHorizontal ? scrollContainerRef : void 0,
439
501
  ...itemStyleProps
440
502
  })
441
503
  })]
@@ -448,10 +510,73 @@ function ListWidget({ listType = "unordered", scrollAxis = "horizontal", titleEn
448
510
  scrollAxis,
449
511
  numberColor,
450
512
  numberSize,
513
+ scrollContainerRef: isOrderedHorizontal ? scrollContainerRef : void 0,
451
514
  ...itemStyleProps
452
515
  })]
453
516
  });
454
517
  }
518
+ const SCROLL_BUTTON_AMOUNT = 300;
519
+ const SCROLL_EDGE_TOLERANCE = 4;
520
+ const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
521
+ function useHorizontalScrollState({ enabled, contentLength }) {
522
+ const scrollContainerRef = useRef(null);
523
+ const [canScrollPrev, setCanScrollPrev] = useState(false);
524
+ const [canScrollNext, setCanScrollNext] = useState(false);
525
+ const resetScrollState = useCallback(() => {
526
+ setCanScrollPrev(false);
527
+ setCanScrollNext(false);
528
+ }, []);
529
+ const updateScrollState = useCallback(() => {
530
+ const el = scrollContainerRef.current;
531
+ if (!enabled || !el) {
532
+ resetScrollState();
533
+ return;
534
+ }
535
+ setCanScrollPrev(el.scrollLeft > SCROLL_EDGE_TOLERANCE);
536
+ setCanScrollNext(el.scrollLeft + el.clientWidth < el.scrollWidth - SCROLL_EDGE_TOLERANCE);
537
+ }, [enabled, resetScrollState]);
538
+ useIsomorphicLayoutEffect(() => {
539
+ updateScrollState();
540
+ }, [updateScrollState]);
541
+ useEffect(() => {
542
+ if (!enabled) {
543
+ resetScrollState();
544
+ return;
545
+ }
546
+ const el = scrollContainerRef.current;
547
+ if (!el) {
548
+ resetScrollState();
549
+ return;
550
+ }
551
+ updateScrollState();
552
+ el.addEventListener("scroll", updateScrollState, { passive: true });
553
+ const resize = typeof ResizeObserver !== "undefined" ? new ResizeObserver(updateScrollState) : void 0;
554
+ resize?.observe(el);
555
+ return () => {
556
+ el.removeEventListener("scroll", updateScrollState);
557
+ resize?.disconnect();
558
+ };
559
+ }, [
560
+ enabled,
561
+ resetScrollState,
562
+ updateScrollState,
563
+ contentLength
564
+ ]);
565
+ return {
566
+ scrollContainerRef,
567
+ canScrollPrev,
568
+ canScrollNext,
569
+ scrollByAmount: useCallback((direction) => {
570
+ const el = scrollContainerRef.current;
571
+ if (!el) return;
572
+ const amount = SCROLL_BUTTON_AMOUNT + (parseFloat(getComputedStyle(el).gap) || 0);
573
+ el.scrollTo({
574
+ left: el.scrollLeft + (direction === "next" ? amount : -amount),
575
+ behavior: "smooth"
576
+ });
577
+ }, [])
578
+ };
579
+ }
455
580
  const listWidgetPropertySchema = {
456
581
  widgetType: "ListWidget",
457
582
  displayName: "List",
@@ -582,7 +707,7 @@ const listWidgetPropertySchema = {
582
707
  key: "imageAspectRatio",
583
708
  label: "Image Aspect Ratio",
584
709
  type: "buttonGroup",
585
- description: "Aspect ratio for item images",
710
+ description: "Aspect ratio for item images (unordered list — ordered layouts use a fixed ratio per axis)",
586
711
  defaultValue: "square",
587
712
  options: [
588
713
  {
@@ -599,7 +724,11 @@ const listWidgetPropertySchema = {
599
724
  }
600
725
  ],
601
726
  tab: "styling",
602
- group: "List Configuration"
727
+ group: "List Configuration",
728
+ requiresKeyValue: {
729
+ key: "listType",
730
+ value: "unordered"
731
+ }
603
732
  },
604
733
  {
605
734
  key: "showBadge",
@@ -670,14 +799,17 @@ const listWidgetPropertySchema = {
670
799
  getFontSizeField({
671
800
  key: "numberSize",
672
801
  label: "Number Font Size",
673
- description: "Size of ordered list numbers",
802
+ description: "Size of ordered list numbers (vertical scroll only — horizontal uses a fixed editorial size)",
674
803
  defaultValue: "2xl",
675
804
  tab: "styling",
676
805
  group: "Ordered List Configuration",
677
- requiresKeyValue: {
806
+ requiresKeyValue: [{
678
807
  key: "listType",
679
808
  value: "ordered"
680
- }
809
+ }, {
810
+ key: "scrollAxis",
811
+ value: "vertical"
812
+ }]
681
813
  }),
682
814
  getColorField({
683
815
  key: "itemTitleColor",
@@ -912,4 +1044,4 @@ const listWidgetPropertySchema = {
912
1044
  //#endregion
913
1045
  export { ListWidget_exports as n, listWidgetPropertySchema as r, ListWidget as t };
914
1046
 
915
- //# sourceMappingURL=ListWidget-Ct8IDkio.mjs.map
1047
+ //# sourceMappingURL=ListWidget-D7y8bfvT.mjs.map