@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
@@ -3,13 +3,22 @@ const require_WidgetInteractionContext = require("./WidgetInteractionContext-Bd1
3
3
  const require_registries = require("./registries-CpUM406S.cjs");
4
4
  const require_purify_es = require("./purify.es-BQcWWtgQ.cjs");
5
5
  const require_MediaRenderer = require("./MediaRenderer-D4HnIAbN.cjs");
6
- const require_scroll_arrows = require("./scroll-arrows-DVwMDTt3.cjs");
7
6
  let react = require("react");
8
7
  let react_jsx_runtime = require("react/jsx-runtime");
8
+ let lucide_react = require("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__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsx)("div", { className: "pointer-events-none absolute inset-0 bg-black/40" }),
36
+ /* @__PURE__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsx)("a", {
51
+ featuredButtonText && /* @__PURE__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsxs)("div", {
92
100
  className: `flex flex-1 flex-col p-${padding}`,
93
101
  children: [
94
102
  item.title && /* @__PURE__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.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: require_purify_es.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__ */ (0, react_jsx_runtime.jsxs)("div", {
116
- className: "flex items-center gap-2",
117
- children: [(item.display_price || item.price) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
118
- className: `text-${priceColor} text-${priceSize === "md" ? "base" : priceSize} font-bold`,
123
+ (hasPrice || hasOriginal) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
124
+ className: "mt-auto flex items-baseline gap-2",
125
+ children: [hasPrice && /* @__PURE__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsx)("span", {
121
- className: `text-${originalPriceColor} text-${descriptionSize === "md" ? "base" : descriptionSize} line-through`,
128
+ }), hasOriginal && /* @__PURE__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsxs)("div", {
126
- className: `mt-2 flex gap-3 text-${metaTextColor} text-${metaTextSize === "md" ? "base" : metaTextSize}`,
127
- children: [item.qv && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["QV: ", getStringValue(item.qv)] }), item.cv && /* @__PURE__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
136
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
137
+ className: "opacity-50",
138
+ children: "QV"
139
+ }),
140
+ " ",
141
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
142
+ className: "tabular-nums",
143
+ children: getStringValue(item.qv)
144
+ })
145
+ ] }), item.cv && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
146
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
147
+ className: "opacity-50",
148
+ children: "CV"
149
+ }),
150
+ " ",
151
+ /* @__PURE__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.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-${require_registries.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__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsx)(DiscountBadge, { discount: item.discount }),
183
- imageUrl && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
184
- className: `w-full ${aspectRatioClass} overflow-hidden`,
185
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
186
- src: imageUrl,
187
- alt: item.title || "Product",
188
- className: "h-full w-full object-cover"
189
- })
190
- }),
191
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ListItemCardContent, {
209
+ children: [imageUrl && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
210
+ className: `relative w-full ${aspectRatioClass} bg-muted/30 overflow-hidden ${cardRadiusClass(borderRadius)}`,
211
+ children: [showBadge && item.discount && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DiscountBadge, { discount: item.discount }), /* @__PURE__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsx)("div", {
217
+ className: "mt-4",
218
+ children: /* @__PURE__ */ (0, react_jsx_runtime.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 = (0, react.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 = (0, react.useRef)(null);
245
+ const scrollContainerRef = externalScrollRef ?? internalScrollRef;
242
246
  const { onItemClick } = require_WidgetInteractionContext.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__ */ (0, react_jsx_runtime.jsxs)("div", {
268
- className: "relative overflow-hidden",
269
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
271
+ if (scrollAxis === "horizontal") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
272
+ className: "relative",
273
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
270
274
  ref: scrollContainerRef,
271
- className: `flex gap-${require_registries.gapValues[gap]} scrollbar-hide overflow-x-auto overflow-y-hidden scroll-smooth pb-2`,
275
+ className: `flex gap-${require_registries.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__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsxs)("div", {
283
+ className: "flex items-end",
284
284
  children: [
285
- showBadge && item.discount && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DiscountBadge, { discount: item.discount }),
286
- imageUrl && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
287
- className: `w-full ${aspectRatioClass} overflow-hidden`,
288
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
285
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
286
+ className: "sr-only",
287
+ children: [
288
+ "Rank ",
289
+ rank,
290
+ ": "
291
+ ]
292
+ }),
293
+ /* @__PURE__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsx)(DiscountBadge, { discount: item.discount }), /* @__PURE__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsx)(ListItemCardContent, {
295
- item,
296
- ...contentProps
309
+ })]
297
310
  })
298
311
  ]
312
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
313
+ className: "mt-5 ml-auto w-[200px]",
314
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ListItemCardContent, {
315
+ item,
316
+ ...contentProps
317
+ })
299
318
  })]
300
319
  }, item.id);
301
320
  })
302
- }), /* @__PURE__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsx)(require_scroll_arrows.ScrollArrows, {
305
- onPrevious: () => scrollByAmount("prev"),
306
- onNext: () => scrollByAmount("next")
307
- })
308
- })]
321
+ })
309
322
  });
310
323
  if (scrollAxis === "vertical") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
311
324
  className: `flex flex-col gap-${require_registries.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__ */ (0, react_jsx_runtime.jsxs)("div", {
315
- className: `relative flex gap-${require_registries.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-${require_registries.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__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsxs)("span", {
335
+ className: "sr-only",
336
+ children: [
337
+ "Rank ",
338
+ rank,
339
+ ": "
340
+ ]
341
+ }),
342
+ /* @__PURE__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsx)("div", {
331
- className: "flex-1",
356
+ className: "min-w-0 flex-1",
332
357
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ListItemCardContent, {
333
358
  item,
334
359
  ...contentProps
335
360
  })
336
361
  }),
337
- showBadge && item.discount && /* @__PURE__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.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
  ]
@@ -393,17 +418,53 @@ function ListWidget({ listType = "unordered", scrollAxis = "horizontal", titleEn
393
418
  const shouldShowFeaturedSection = showFeaturedSection && hasFeaturedAsset;
394
419
  const backgroundColor = background.color || "background";
395
420
  const backgroundImage = (background.resource?.image_url || background.resource?.imageUrl) && background.type === "image" ? `url(${background.resource.image_url || background.resource.imageUrl})` : "none";
421
+ const isOrderedHorizontal = listType === "ordered" && scrollAxis === "horizontal";
422
+ const showScrollArrows = isOrderedHorizontal && hasItems && displayItems.length > 1;
423
+ const { scrollContainerRef, canScrollPrev, canScrollNext, scrollByAmount } = useHorizontalScrollState({
424
+ enabled: showScrollArrows,
425
+ contentLength: displayItems.length
426
+ });
427
+ const hasTitle = titleEnabled && title;
428
+ const showTitleRow = hasTitle || showScrollArrows;
396
429
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
397
430
  className: `@container bg-${backgroundColor} p-${padding} rounded-${borderRadius} ${require_registries.borderWidthClasses[borderWidth]} ${borderWidth !== "none" ? require_registries.borderColorClasses[borderColor] : ""} ${className}`,
398
431
  style: { backgroundImage },
399
432
  ...props,
400
- children: [titleEnabled && title && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
401
- className: `text-${titleColor} text-${titleSize === "md" ? "base" : titleSize} font-header mb-6 font-bold`,
402
- children: title
433
+ children: [showTitleRow && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
434
+ className: "mb-8 flex items-center justify-between gap-4",
435
+ children: [hasTitle ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
436
+ className: `text-${titleColor} text-${titleSize === "md" ? "base" : titleSize} font-header leading-tight font-medium tracking-tight`,
437
+ children: title
438
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {}), showScrollArrows && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
439
+ className: "flex shrink-0 items-center gap-2",
440
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
441
+ type: "button",
442
+ onClick: () => scrollByAmount("prev"),
443
+ disabled: !canScrollPrev,
444
+ "aria-label": "Previous items",
445
+ className: `text-${numberColor} flex size-9 items-center justify-center rounded-full transition-opacity hover:opacity-60 disabled:cursor-not-allowed disabled:opacity-20`,
446
+ style: { boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${numberColor}) 25%, transparent)` },
447
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronLeft, {
448
+ "aria-hidden": "true",
449
+ className: "size-4"
450
+ })
451
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
452
+ type: "button",
453
+ onClick: () => scrollByAmount("next"),
454
+ disabled: !canScrollNext,
455
+ "aria-label": "Next items",
456
+ className: `text-${numberColor} flex size-9 items-center justify-center rounded-full transition-opacity hover:opacity-60 disabled:cursor-not-allowed disabled:opacity-20`,
457
+ style: { boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${numberColor}) 25%, transparent)` },
458
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronRight, {
459
+ "aria-hidden": "true",
460
+ className: "size-4"
461
+ })
462
+ })]
463
+ })]
403
464
  }), !hasItems ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
404
- className: "border-border bg-muted flex items-center justify-center rounded-md border-2 border-dashed py-12 text-center",
465
+ className: "flex items-center justify-center py-20 text-center",
405
466
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
406
- className: "text-muted",
467
+ className: "text-muted/70 text-sm tracking-tight",
407
468
  children: "No items to display"
408
469
  })
409
470
  }) : shouldShowFeaturedSection ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -432,6 +493,7 @@ function ListWidget({ listType = "unordered", scrollAxis = "horizontal", titleEn
432
493
  scrollAxis,
433
494
  numberColor,
434
495
  numberSize,
496
+ scrollContainerRef: isOrderedHorizontal ? scrollContainerRef : void 0,
435
497
  ...itemStyleProps
436
498
  })
437
499
  })]
@@ -444,10 +506,73 @@ function ListWidget({ listType = "unordered", scrollAxis = "horizontal", titleEn
444
506
  scrollAxis,
445
507
  numberColor,
446
508
  numberSize,
509
+ scrollContainerRef: isOrderedHorizontal ? scrollContainerRef : void 0,
447
510
  ...itemStyleProps
448
511
  })]
449
512
  });
450
513
  }
514
+ const SCROLL_BUTTON_AMOUNT = 300;
515
+ const SCROLL_EDGE_TOLERANCE = 4;
516
+ const useIsomorphicLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
517
+ function useHorizontalScrollState({ enabled, contentLength }) {
518
+ const scrollContainerRef = (0, react.useRef)(null);
519
+ const [canScrollPrev, setCanScrollPrev] = (0, react.useState)(false);
520
+ const [canScrollNext, setCanScrollNext] = (0, react.useState)(false);
521
+ const resetScrollState = (0, react.useCallback)(() => {
522
+ setCanScrollPrev(false);
523
+ setCanScrollNext(false);
524
+ }, []);
525
+ const updateScrollState = (0, react.useCallback)(() => {
526
+ const el = scrollContainerRef.current;
527
+ if (!enabled || !el) {
528
+ resetScrollState();
529
+ return;
530
+ }
531
+ setCanScrollPrev(el.scrollLeft > SCROLL_EDGE_TOLERANCE);
532
+ setCanScrollNext(el.scrollLeft + el.clientWidth < el.scrollWidth - SCROLL_EDGE_TOLERANCE);
533
+ }, [enabled, resetScrollState]);
534
+ useIsomorphicLayoutEffect(() => {
535
+ updateScrollState();
536
+ }, [updateScrollState]);
537
+ (0, react.useEffect)(() => {
538
+ if (!enabled) {
539
+ resetScrollState();
540
+ return;
541
+ }
542
+ const el = scrollContainerRef.current;
543
+ if (!el) {
544
+ resetScrollState();
545
+ return;
546
+ }
547
+ updateScrollState();
548
+ el.addEventListener("scroll", updateScrollState, { passive: true });
549
+ const resize = typeof ResizeObserver !== "undefined" ? new ResizeObserver(updateScrollState) : void 0;
550
+ resize?.observe(el);
551
+ return () => {
552
+ el.removeEventListener("scroll", updateScrollState);
553
+ resize?.disconnect();
554
+ };
555
+ }, [
556
+ enabled,
557
+ resetScrollState,
558
+ updateScrollState,
559
+ contentLength
560
+ ]);
561
+ return {
562
+ scrollContainerRef,
563
+ canScrollPrev,
564
+ canScrollNext,
565
+ scrollByAmount: (0, react.useCallback)((direction) => {
566
+ const el = scrollContainerRef.current;
567
+ if (!el) return;
568
+ const amount = SCROLL_BUTTON_AMOUNT + (parseFloat(getComputedStyle(el).gap) || 0);
569
+ el.scrollTo({
570
+ left: el.scrollLeft + (direction === "next" ? amount : -amount),
571
+ behavior: "smooth"
572
+ });
573
+ }, [])
574
+ };
575
+ }
451
576
  const listWidgetPropertySchema = {
452
577
  widgetType: "ListWidget",
453
578
  displayName: "List",
@@ -578,7 +703,7 @@ const listWidgetPropertySchema = {
578
703
  key: "imageAspectRatio",
579
704
  label: "Image Aspect Ratio",
580
705
  type: "buttonGroup",
581
- description: "Aspect ratio for item images",
706
+ description: "Aspect ratio for item images (unordered list — ordered layouts use a fixed ratio per axis)",
582
707
  defaultValue: "square",
583
708
  options: [
584
709
  {
@@ -595,7 +720,11 @@ const listWidgetPropertySchema = {
595
720
  }
596
721
  ],
597
722
  tab: "styling",
598
- group: "List Configuration"
723
+ group: "List Configuration",
724
+ requiresKeyValue: {
725
+ key: "listType",
726
+ value: "unordered"
727
+ }
599
728
  },
600
729
  {
601
730
  key: "showBadge",
@@ -666,14 +795,17 @@ const listWidgetPropertySchema = {
666
795
  require_registries.getFontSizeField({
667
796
  key: "numberSize",
668
797
  label: "Number Font Size",
669
- description: "Size of ordered list numbers",
798
+ description: "Size of ordered list numbers (vertical scroll only — horizontal uses a fixed editorial size)",
670
799
  defaultValue: "2xl",
671
800
  tab: "styling",
672
801
  group: "Ordered List Configuration",
673
- requiresKeyValue: {
802
+ requiresKeyValue: [{
674
803
  key: "listType",
675
804
  value: "ordered"
676
- }
805
+ }, {
806
+ key: "scrollAxis",
807
+ value: "vertical"
808
+ }]
677
809
  }),
678
810
  require_registries.getColorField({
679
811
  key: "itemTitleColor",
@@ -919,4 +1051,4 @@ Object.defineProperty(exports, "listWidgetPropertySchema", {
919
1051
  }
920
1052
  });
921
1053
 
922
- //# sourceMappingURL=ListWidget-C7ouNpEo.cjs.map
1054
+ //# sourceMappingURL=ListWidget-DJ-_dMOK.cjs.map