@thorprovider/blocks 3.0.2 → 4.1.0

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 (234) hide show
  1. package/README.md +61 -21
  2. package/dist/blocks/designs/checkout-commerce-v1/block.d.ts +49 -0
  3. package/dist/blocks/designs/checkout-commerce-v1/block.d.ts.map +1 -0
  4. package/dist/blocks/designs/checkout-commerce-v1/block.js +2487 -0
  5. package/dist/blocks/designs/checkout-commerce-v1/block.js.map +1 -0
  6. package/dist/blocks/designs/checkout-commerce-v1/block.mjs +2467 -0
  7. package/dist/blocks/designs/checkout-commerce-v1/block.mjs.map +1 -0
  8. package/dist/blocks/designs/checkout-commerce-v1/data-context.d.ts +8 -0
  9. package/dist/blocks/designs/checkout-commerce-v1/data-context.d.ts.map +1 -0
  10. package/dist/blocks/designs/checkout-commerce-v1/data-context.js +44 -0
  11. package/dist/blocks/designs/checkout-commerce-v1/data-context.js.map +1 -0
  12. package/dist/blocks/designs/checkout-commerce-v1/data-context.mjs +19 -0
  13. package/dist/blocks/designs/checkout-commerce-v1/data-context.mjs.map +1 -0
  14. package/dist/blocks/designs/checkout-commerce-v1/index.d.ts +3 -0
  15. package/dist/blocks/designs/checkout-commerce-v1/index.d.ts.map +1 -0
  16. package/dist/blocks/designs/checkout-commerce-v1/index.js +36 -0
  17. package/dist/blocks/designs/checkout-commerce-v1/index.js.map +1 -0
  18. package/dist/blocks/designs/checkout-commerce-v1/index.mjs +6 -0
  19. package/dist/blocks/designs/checkout-commerce-v1/index.mjs.map +1 -0
  20. package/dist/blocks/designs/marketplace-product-card/block.d.ts +12 -0
  21. package/dist/blocks/designs/marketplace-product-card/block.d.ts.map +1 -0
  22. package/dist/blocks/designs/marketplace-product-card/block.js +243 -0
  23. package/dist/blocks/designs/marketplace-product-card/block.js.map +1 -0
  24. package/dist/blocks/designs/marketplace-product-card/block.mjs +233 -0
  25. package/dist/blocks/designs/marketplace-product-card/block.mjs.map +1 -0
  26. package/dist/blocks/designs/marketplace-product-card/index.d.ts +3 -0
  27. package/dist/blocks/designs/marketplace-product-card/index.d.ts.map +1 -0
  28. package/dist/blocks/designs/marketplace-product-card/index.js +36 -0
  29. package/dist/blocks/designs/marketplace-product-card/index.js.map +1 -0
  30. package/dist/blocks/designs/marketplace-product-card/index.mjs +6 -0
  31. package/dist/blocks/designs/marketplace-product-card/index.mjs.map +1 -0
  32. package/dist/blocks/designs/marketplace-product-card/normalize.d.ts +13 -0
  33. package/dist/blocks/designs/marketplace-product-card/normalize.d.ts.map +1 -0
  34. package/dist/blocks/designs/marketplace-product-card/normalize.js +36 -0
  35. package/dist/blocks/designs/marketplace-product-card/normalize.js.map +1 -0
  36. package/dist/blocks/designs/marketplace-product-card/normalize.mjs +12 -0
  37. package/dist/blocks/designs/marketplace-product-card/normalize.mjs.map +1 -0
  38. package/dist/blocks/designs/marketplace-product-card/variants.d.ts +72 -0
  39. package/dist/blocks/designs/marketplace-product-card/variants.d.ts.map +1 -0
  40. package/dist/blocks/designs/marketplace-product-card/variants.js +123 -0
  41. package/dist/blocks/designs/marketplace-product-card/variants.js.map +1 -0
  42. package/dist/blocks/designs/marketplace-product-card/variants.mjs +89 -0
  43. package/dist/blocks/designs/marketplace-product-card/variants.mjs.map +1 -0
  44. package/dist/blocks/e-commerce/account/account-frame.d.ts +38 -0
  45. package/dist/blocks/e-commerce/account/account-frame.d.ts.map +1 -0
  46. package/dist/blocks/e-commerce/account/account-frame.js +102 -0
  47. package/dist/blocks/e-commerce/account/account-frame.js.map +1 -0
  48. package/dist/blocks/e-commerce/account/account-frame.mjs +78 -0
  49. package/dist/blocks/e-commerce/account/account-frame.mjs.map +1 -0
  50. package/dist/blocks/e-commerce/account/address-book.d.ts +79 -0
  51. package/dist/blocks/e-commerce/account/address-book.d.ts.map +1 -0
  52. package/dist/blocks/e-commerce/account/address-book.js +250 -0
  53. package/dist/blocks/e-commerce/account/address-book.js.map +1 -0
  54. package/dist/blocks/e-commerce/account/address-book.mjs +225 -0
  55. package/dist/blocks/e-commerce/account/address-book.mjs.map +1 -0
  56. package/dist/blocks/e-commerce/account/profile-form.d.ts +35 -0
  57. package/dist/blocks/e-commerce/account/profile-form.d.ts.map +1 -0
  58. package/dist/blocks/e-commerce/account/profile-form.js +100 -0
  59. package/dist/blocks/e-commerce/account/profile-form.js.map +1 -0
  60. package/dist/blocks/e-commerce/account/profile-form.mjs +76 -0
  61. package/dist/blocks/e-commerce/account/profile-form.mjs.map +1 -0
  62. package/dist/blocks/e-commerce/checkout-forms/checkbox-check.js +1 -1
  63. package/dist/blocks/e-commerce/checkout-forms/checkbox-check.js.map +1 -1
  64. package/dist/blocks/e-commerce/checkout-forms/checkbox-check.mjs +1 -1
  65. package/dist/blocks/e-commerce/checkout-forms/checkbox-check.mjs.map +1 -1
  66. package/dist/blocks/e-commerce/checkout-forms/checkout-address-equality.d.ts +11 -0
  67. package/dist/blocks/e-commerce/checkout-forms/checkout-address-equality.d.ts.map +1 -0
  68. package/dist/blocks/e-commerce/checkout-forms/checkout-address-equality.js +46 -0
  69. package/dist/blocks/e-commerce/checkout-forms/checkout-address-equality.js.map +1 -0
  70. package/dist/blocks/e-commerce/checkout-forms/checkout-address-equality.mjs +22 -0
  71. package/dist/blocks/e-commerce/checkout-forms/checkout-address-equality.mjs.map +1 -0
  72. package/dist/blocks/e-commerce/checkout-forms/checkout-address-fields.d.ts +28 -0
  73. package/dist/blocks/e-commerce/checkout-forms/checkout-address-fields.d.ts.map +1 -0
  74. package/dist/blocks/e-commerce/checkout-forms/checkout-address-fields.js +278 -0
  75. package/dist/blocks/e-commerce/checkout-forms/checkout-address-fields.js.map +1 -0
  76. package/dist/blocks/e-commerce/checkout-forms/checkout-address-fields.mjs +260 -0
  77. package/dist/blocks/e-commerce/checkout-forms/checkout-address-fields.mjs.map +1 -0
  78. package/dist/blocks/e-commerce/checkout-forms/checkout-contact-step.d.ts +12 -9
  79. package/dist/blocks/e-commerce/checkout-forms/checkout-contact-step.d.ts.map +1 -1
  80. package/dist/blocks/e-commerce/checkout-forms/checkout-contact-step.js +49 -71
  81. package/dist/blocks/e-commerce/checkout-forms/checkout-contact-step.js.map +1 -1
  82. package/dist/blocks/e-commerce/checkout-forms/checkout-contact-step.mjs +50 -72
  83. package/dist/blocks/e-commerce/checkout-forms/checkout-contact-step.mjs.map +1 -1
  84. package/dist/blocks/e-commerce/checkout-forms/checkout-country-field.d.ts.map +1 -1
  85. package/dist/blocks/e-commerce/checkout-forms/checkout-country-field.js +6 -3
  86. package/dist/blocks/e-commerce/checkout-forms/checkout-country-field.js.map +1 -1
  87. package/dist/blocks/e-commerce/checkout-forms/checkout-country-field.mjs +6 -3
  88. package/dist/blocks/e-commerce/checkout-forms/checkout-country-field.mjs.map +1 -1
  89. package/dist/blocks/e-commerce/checkout-forms/checkout-id-context.d.ts +7 -0
  90. package/dist/blocks/e-commerce/checkout-forms/checkout-id-context.d.ts.map +1 -0
  91. package/dist/blocks/e-commerce/checkout-forms/checkout-id-context.js +41 -0
  92. package/dist/blocks/e-commerce/checkout-forms/checkout-id-context.js.map +1 -0
  93. package/dist/blocks/e-commerce/checkout-forms/checkout-id-context.mjs +16 -0
  94. package/dist/blocks/e-commerce/checkout-forms/checkout-id-context.mjs.map +1 -0
  95. package/dist/blocks/e-commerce/checkout-forms/checkout-location-select.d.ts +24 -0
  96. package/dist/blocks/e-commerce/checkout-forms/checkout-location-select.d.ts.map +1 -0
  97. package/dist/blocks/e-commerce/checkout-forms/checkout-location-select.js +75 -0
  98. package/dist/blocks/e-commerce/checkout-forms/checkout-location-select.js.map +1 -0
  99. package/dist/blocks/e-commerce/checkout-forms/checkout-location-select.mjs +58 -0
  100. package/dist/blocks/e-commerce/checkout-forms/checkout-location-select.mjs.map +1 -0
  101. package/dist/blocks/e-commerce/checkout-forms/checkout-order-summary.d.ts +3 -2
  102. package/dist/blocks/e-commerce/checkout-forms/checkout-order-summary.d.ts.map +1 -1
  103. package/dist/blocks/e-commerce/checkout-forms/checkout-order-summary.js +9 -2
  104. package/dist/blocks/e-commerce/checkout-forms/checkout-order-summary.js.map +1 -1
  105. package/dist/blocks/e-commerce/checkout-forms/checkout-order-summary.mjs +9 -2
  106. package/dist/blocks/e-commerce/checkout-forms/checkout-order-summary.mjs.map +1 -1
  107. package/dist/blocks/e-commerce/checkout-forms/checkout-payment-step.d.ts +23 -8
  108. package/dist/blocks/e-commerce/checkout-forms/checkout-payment-step.d.ts.map +1 -1
  109. package/dist/blocks/e-commerce/checkout-forms/checkout-payment-step.js +136 -31
  110. package/dist/blocks/e-commerce/checkout-forms/checkout-payment-step.js.map +1 -1
  111. package/dist/blocks/e-commerce/checkout-forms/checkout-payment-step.mjs +143 -32
  112. package/dist/blocks/e-commerce/checkout-forms/checkout-payment-step.mjs.map +1 -1
  113. package/dist/blocks/e-commerce/checkout-forms/checkout-review-step.d.ts +13 -7
  114. package/dist/blocks/e-commerce/checkout-forms/checkout-review-step.d.ts.map +1 -1
  115. package/dist/blocks/e-commerce/checkout-forms/checkout-review-step.js +179 -28
  116. package/dist/blocks/e-commerce/checkout-forms/checkout-review-step.js.map +1 -1
  117. package/dist/blocks/e-commerce/checkout-forms/checkout-review-step.mjs +180 -29
  118. package/dist/blocks/e-commerce/checkout-forms/checkout-review-step.mjs.map +1 -1
  119. package/dist/blocks/e-commerce/checkout-forms/checkout-saved-addresses.d.ts +20 -0
  120. package/dist/blocks/e-commerce/checkout-forms/checkout-saved-addresses.d.ts.map +1 -0
  121. package/dist/blocks/e-commerce/checkout-forms/checkout-saved-addresses.js +199 -0
  122. package/dist/blocks/e-commerce/checkout-forms/checkout-saved-addresses.js.map +1 -0
  123. package/dist/blocks/e-commerce/checkout-forms/checkout-saved-addresses.mjs +175 -0
  124. package/dist/blocks/e-commerce/checkout-forms/checkout-saved-addresses.mjs.map +1 -0
  125. package/dist/blocks/e-commerce/checkout-forms/checkout-section-nav.d.ts +14 -0
  126. package/dist/blocks/e-commerce/checkout-forms/checkout-section-nav.d.ts.map +1 -0
  127. package/dist/blocks/e-commerce/checkout-forms/checkout-section-nav.js +136 -0
  128. package/dist/blocks/e-commerce/checkout-forms/checkout-section-nav.js.map +1 -0
  129. package/dist/blocks/e-commerce/checkout-forms/checkout-section-nav.mjs +109 -0
  130. package/dist/blocks/e-commerce/checkout-forms/checkout-section-nav.mjs.map +1 -0
  131. package/dist/blocks/e-commerce/checkout-forms/checkout-shipping-step.d.ts +32 -10
  132. package/dist/blocks/e-commerce/checkout-forms/checkout-shipping-step.d.ts.map +1 -1
  133. package/dist/blocks/e-commerce/checkout-forms/checkout-shipping-step.js +265 -147
  134. package/dist/blocks/e-commerce/checkout-forms/checkout-shipping-step.js.map +1 -1
  135. package/dist/blocks/e-commerce/checkout-forms/checkout-shipping-step.mjs +272 -148
  136. package/dist/blocks/e-commerce/checkout-forms/checkout-shipping-step.mjs.map +1 -1
  137. package/dist/blocks/e-commerce/checkout-forms/checkout-step-header.d.ts +13 -0
  138. package/dist/blocks/e-commerce/checkout-forms/checkout-step-header.d.ts.map +1 -0
  139. package/dist/blocks/e-commerce/checkout-forms/checkout-step-header.js +74 -0
  140. package/dist/blocks/e-commerce/checkout-forms/checkout-step-header.js.map +1 -0
  141. package/dist/blocks/e-commerce/checkout-forms/checkout-step-header.mjs +50 -0
  142. package/dist/blocks/e-commerce/checkout-forms/checkout-step-header.mjs.map +1 -0
  143. package/dist/blocks/e-commerce/checkout-forms/checkout-step-summary.d.ts +7 -0
  144. package/dist/blocks/e-commerce/checkout-forms/checkout-step-summary.d.ts.map +1 -0
  145. package/dist/blocks/e-commerce/checkout-forms/checkout-step-summary.js +91 -0
  146. package/dist/blocks/e-commerce/checkout-forms/checkout-step-summary.js.map +1 -0
  147. package/dist/blocks/e-commerce/checkout-forms/checkout-step-summary.mjs +65 -0
  148. package/dist/blocks/e-commerce/checkout-forms/checkout-step-summary.mjs.map +1 -0
  149. package/dist/blocks/e-commerce/checkout-forms/checkout.d.ts +174 -44
  150. package/dist/blocks/e-commerce/checkout-forms/checkout.d.ts.map +1 -1
  151. package/dist/blocks/e-commerce/checkout-forms/checkout.js +532 -108
  152. package/dist/blocks/e-commerce/checkout-forms/checkout.js.map +1 -1
  153. package/dist/blocks/e-commerce/checkout-forms/checkout.mjs +542 -109
  154. package/dist/blocks/e-commerce/checkout-forms/checkout.mjs.map +1 -1
  155. package/dist/blocks/e-commerce/navigation/storefront-navbar-cart-sheet.d.ts.map +1 -1
  156. package/dist/blocks/e-commerce/navigation/storefront-navbar-cart-sheet.js +44 -20
  157. package/dist/blocks/e-commerce/navigation/storefront-navbar-cart-sheet.js.map +1 -1
  158. package/dist/blocks/e-commerce/navigation/storefront-navbar-cart-sheet.mjs +44 -20
  159. package/dist/blocks/e-commerce/navigation/storefront-navbar-cart-sheet.mjs.map +1 -1
  160. package/dist/blocks/e-commerce/navigation/storefront-navbar.d.ts.map +1 -1
  161. package/dist/blocks/e-commerce/navigation/storefront-navbar.js +21 -10
  162. package/dist/blocks/e-commerce/navigation/storefront-navbar.js.map +1 -1
  163. package/dist/blocks/e-commerce/navigation/storefront-navbar.mjs +21 -10
  164. package/dist/blocks/e-commerce/navigation/storefront-navbar.mjs.map +1 -1
  165. package/dist/blocks/e-commerce/product-list/product-card.d.ts.map +1 -1
  166. package/dist/blocks/e-commerce/product-list/product-card.js +36 -9
  167. package/dist/blocks/e-commerce/product-list/product-card.js.map +1 -1
  168. package/dist/blocks/e-commerce/product-list/product-card.mjs +36 -9
  169. package/dist/blocks/e-commerce/product-list/product-card.mjs.map +1 -1
  170. package/dist/blocks/e-commerce/product-list/product-showcase-1.d.ts.map +1 -1
  171. package/dist/blocks/e-commerce/product-list/product-showcase-1.js +7 -2
  172. package/dist/blocks/e-commerce/product-list/product-showcase-1.js.map +1 -1
  173. package/dist/blocks/e-commerce/product-list/product-showcase-1.mjs +7 -2
  174. package/dist/blocks/e-commerce/product-list/product-showcase-1.mjs.map +1 -1
  175. package/dist/blocks/e-commerce/product-overview/product-quick-view-dialog.d.ts.map +1 -1
  176. package/dist/blocks/e-commerce/product-overview/product-quick-view-dialog.js +5 -1
  177. package/dist/blocks/e-commerce/product-overview/product-quick-view-dialog.js.map +1 -1
  178. package/dist/blocks/e-commerce/product-overview/product-quick-view-dialog.mjs +5 -1
  179. package/dist/blocks/e-commerce/product-overview/product-quick-view-dialog.mjs.map +1 -1
  180. package/dist/blocks/e-commerce/storefront-hero/storefront-hero.d.ts.map +1 -1
  181. package/dist/blocks/e-commerce/storefront-hero/storefront-hero.js +71 -51
  182. package/dist/blocks/e-commerce/storefront-hero/storefront-hero.js.map +1 -1
  183. package/dist/blocks/e-commerce/storefront-hero/storefront-hero.mjs +71 -51
  184. package/dist/blocks/e-commerce/storefront-hero/storefront-hero.mjs.map +1 -1
  185. package/dist/blocks/marketing/banners/banner-1.d.ts.map +1 -1
  186. package/dist/blocks/marketing/banners/banner-1.js +15 -27
  187. package/dist/blocks/marketing/banners/banner-1.js.map +1 -1
  188. package/dist/blocks/marketing/banners/banner-1.mjs +16 -28
  189. package/dist/blocks/marketing/banners/banner-1.mjs.map +1 -1
  190. package/dist/index.d.ts +16 -4
  191. package/dist/index.d.ts.map +1 -1
  192. package/dist/index.js +19 -0
  193. package/dist/index.js.map +1 -1
  194. package/dist/index.mjs +13 -0
  195. package/dist/index.mjs.map +1 -1
  196. package/dist/lib/contracts/checkout-commerce-v1.d.ts +2350 -0
  197. package/dist/lib/contracts/checkout-commerce-v1.d.ts.map +1 -0
  198. package/dist/lib/contracts/checkout-commerce-v1.js +417 -0
  199. package/dist/lib/contracts/checkout-commerce-v1.js.map +1 -0
  200. package/dist/lib/contracts/checkout-commerce-v1.mjs +392 -0
  201. package/dist/lib/contracts/checkout-commerce-v1.mjs.map +1 -0
  202. package/dist/lib/contracts/marketplace-product-card.d.ts +324 -0
  203. package/dist/lib/contracts/marketplace-product-card.d.ts.map +1 -0
  204. package/dist/lib/contracts/marketplace-product-card.js +85 -0
  205. package/dist/lib/contracts/marketplace-product-card.js.map +1 -0
  206. package/dist/lib/contracts/marketplace-product-card.mjs +61 -0
  207. package/dist/lib/contracts/marketplace-product-card.mjs.map +1 -0
  208. package/dist/lib/contracts.d.ts +2289 -178
  209. package/dist/lib/contracts.d.ts.map +1 -1
  210. package/dist/lib/contracts.js +332 -25
  211. package/dist/lib/contracts.js.map +1 -1
  212. package/dist/lib/contracts.mjs +278 -5
  213. package/dist/lib/contracts.mjs.map +1 -1
  214. package/dist/lib/money-schema.d.ts +19 -0
  215. package/dist/lib/money-schema.d.ts.map +1 -0
  216. package/dist/lib/money-schema.js +33 -0
  217. package/dist/lib/money-schema.js.map +1 -0
  218. package/dist/lib/money-schema.mjs +9 -0
  219. package/dist/lib/money-schema.mjs.map +1 -0
  220. package/dist/lib/motion.d.ts +29 -0
  221. package/dist/lib/motion.d.ts.map +1 -0
  222. package/dist/lib/motion.js +65 -0
  223. package/dist/lib/motion.js.map +1 -0
  224. package/dist/lib/motion.mjs +41 -0
  225. package/dist/lib/motion.mjs.map +1 -0
  226. package/dist/ui/accordion.d.ts +3 -1
  227. package/dist/ui/accordion.d.ts.map +1 -1
  228. package/dist/ui/accordion.js +21 -5
  229. package/dist/ui/accordion.js.map +1 -1
  230. package/dist/ui/accordion.mjs +21 -5
  231. package/dist/ui/accordion.mjs.map +1 -1
  232. package/dist/ui/input-group.d.ts +1 -1
  233. package/package.json +18 -3
  234. package/dist/.tsbuildinfo +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/blocks/e-commerce/storefront-hero/storefront-hero.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useState } from 'react'\nimport { motion, useReducedMotion } from 'motion/react'\nimport { ArrowRight, MapPin, Search, ShoppingBag, Star } from 'lucide-react'\nimport type { ComponentProps, ReactNode } from 'react'\n\nimport { Badge } from '../../../ui/badge'\nimport { Button } from '../../../ui/button'\nimport { Card, CardContent } from '../../../ui/card'\nimport { Carousel, CarouselContent, CarouselItem, type CarouselApi } from '../../../ui/carousel'\nimport { Input } from '../../../ui/input'\nimport { cn } from '../../../lib/utils'\nimport type { CTA } from '../../../lib/types'\n\n/**\n * Display contract for products featured in the hero. Every popularity,\n * review, or availability field is host-supplied evidence: omitted fields\n * render nothing (honest omission) instead of fabricated defaults.\n */\nexport interface FeaturedProduct {\n id: string\n name: string\n /** Current selling price. */\n price: number\n /** Real compare-at price. Discount treatments render only from a real `originalPrice > price` pair. */\n originalPrice?: number\n /** Image URL or path; omitted entirely when absent or blank (never an empty `src`). */\n image?: string\n /** Accessible image description (falls back to `name`). */\n imageAlt?: string\n /** Host-supplied brand label; the row renders only when supplied. */\n brand?: string\n /** Host-supplied swatch colors; the row renders only when supplied. */\n colors?: string[]\n /** Host-supplied rating (0–5); rendered only when supplied. */\n rating?: number\n /** Host-supplied review count; rendered only when supplied. */\n reviewCount?: number\n /** Host-supplied availability. Absence makes no stock claim; an explicit `false` disables purchase. */\n inStock?: boolean\n /** Host-supplied \"new\" flag; the badge renders only when true. */\n isNew?: boolean\n /** Host-supplied badge label for showcase slides (e.g. a category); rendered only when supplied. */\n tag?: string\n}\n\nexport interface HeroImage {\n src: string\n alt: string\n}\n\nexport interface HeroDepartment {\n id: string\n name: string\n /** Image URL; omitted entirely when absent or blank. */\n image?: string\n /** Accessible image description (falls back to `name`). */\n imageAlt?: string\n /** Host-supplied count label; rendered only when supplied. */\n count?: string\n /** Link destination; renders the chip as a link when present. */\n href?: string\n}\n\nexport interface HeroFeaturedDeal {\n id: string\n name: string\n /** Host-supplied supporting description; rendered only when supplied. */\n description?: string\n /** Image URL; omitted entirely when absent or blank. */\n image?: string\n /** Accessible image description (falls back to `name`). */\n imageAlt?: string\n price: number\n /** Real compare-at price; rendered struck-through only when greater than `price`. */\n originalPrice?: number\n /** Optional call to action shown on the card. */\n cta?: CTA\n}\n\nexport interface HeroStoreLocator {\n title: string\n description: string\n ctaLabel: string\n /** Link destination for the locator button; falls back to `onLocateStores`. */\n ctaHref?: string\n}\n\nexport interface HeroDeal {\n id: string\n /** Deal name shown in the deals bar badge, e.g. a campaign name. */\n title: string\n /** Host-supplied discount label (from a real compare-at price); rendered only when supplied. */\n discount?: string\n /** Host-supplied countdown text; rendered only when supplied — the block never invents one. */\n endTime?: string\n}\n\nexport interface HeroCategory {\n id: string\n name: string\n /** Image URL; omitted entirely when absent or blank. */\n image?: string\n /** Accessible image description (falls back to `name`). */\n imageAlt?: string\n /** Host-supplied count label; rendered only when supplied. */\n count?: string\n /** Link destination; renders the card arrow as a link when present. */\n href?: string\n}\n\n/**\n * The bounded presentation surface, reusing the registry's archetype intent\n * vocabulary: `compact` (text-forward hero + product grid), `showcase`\n * (search affordance + rotating product carousel), `editorial` (department\n * navigation + optional deals/locator), `promotional` (deals bar + category\n * grid). The value changes structure, never the data contract.\n */\nexport type StorefrontHeroPresentation = 'compact' | 'showcase' | 'editorial' | 'promotional'\n\nexport interface StorefrontHeroProps {\n title: string\n description: string\n /** Bounded presentation option; defaults to `compact`. */\n presentation?: StorefrontHeroPresentation\n /** ISO 4217 code used to format prices via `Intl.NumberFormat`; never hardcoded. */\n currency?: string\n /** Featured products. An empty list renders the hero text-forward with no empty grid chrome. */\n products: FeaturedProduct[]\n badge?: string\n titleAccent?: string\n primaryCta?: CTA\n secondaryCta?: CTA\n /**\n * Optional editorial image. Rendered as a native `<img>` when `src` is a\n * non-empty string; omitted entirely when absent or blank (never an empty\n * `src`).\n */\n heroImage?: HeroImage\n /** `showcase` only. The search input renders only when a handler is supplied. */\n onSearch?: (query: string) => void\n /** `editorial` only: department navigation grid. */\n departments?: HeroDepartment[]\n /** `editorial` only: featured deal cards. */\n featuredDeals?: HeroFeaturedDeal[]\n /** `editorial` only: store locator strip. */\n storeLocator?: HeroStoreLocator\n /** `editorial` only: shipping banner text under the CTAs. */\n shippingInfo?: string\n /** `promotional` only: rotating deals bar. */\n deals?: HeroDeal[]\n /** `promotional` only: category card grid. */\n categories?: HeroCategory[]\n /** Milliseconds between rotations (showcase carousel and promotional deals bar; default 3000). */\n rotationInterval?: number\n onAddToCart?: (product: FeaturedProduct) => void\n onBuyNow?: (product: FeaturedProduct) => void\n onSelectColor?: (product: FeaturedProduct, index: number, color: string) => void\n onDepartmentClick?: (department: HeroDepartment) => void\n onShopNow?: (item: HeroFeaturedDeal | HeroDeal) => void\n onLocateStores?: () => void\n onCategoryClick?: (category: HeroCategory) => void\n /** Detail/purchase affordance on product cards and showcase slides. */\n addToCartLabel?: string\n buyNowLabel?: string\n newLabel?: string\n outOfStockLabel?: string\n colorsLabel?: string\n /** Suffix appended to the computed discount percentage (default `% OFF`). */\n discountSuffixLabel?: string\n /** `showcase` labels. */\n searchPlaceholder?: string\n searchLabel?: string\n /** `showcase` copy under each slide's product name. */\n featuredDescription?: string\n /** `editorial`/`promotional` labels. */\n shopNowLabel?: string\n endsInLabel?: string\n productsLabel?: string\n viewLabel?: string\n}\n\nfunction hasRealDiscount(item: Pick<FeaturedProduct, 'price' | 'originalPrice'>): boolean {\n return (\n typeof item.originalPrice === 'number' &&\n Number.isFinite(item.originalPrice) &&\n item.originalPrice > item.price &&\n item.price >= 0\n )\n}\n\nfunction discountPercent(price: number, originalPrice: number): number {\n return Math.round(((originalPrice - price) / originalPrice) * 100)\n}\n\nfunction formatAmount(amount: number, currency?: string): string {\n if (currency) {\n return new Intl.NumberFormat(undefined, { style: 'currency', currency }).format(amount)\n }\n return new Intl.NumberFormat(undefined, { maximumFractionDigits: 2 }).format(amount)\n}\n\nfunction CtaButton({\n cta,\n variant,\n className = 'group relative cursor-pointer overflow-hidden px-8 py-6 text-base font-medium',\n children,\n}: {\n cta: CTA\n variant?: ComponentProps<typeof Button>['variant']\n className?: string\n children: ReactNode\n}) {\n if (cta.href) {\n return (\n <Button variant={variant} size='lg' className={className} asChild>\n <a href={cta.href}>{children}</a>\n </Button>\n )\n }\n\n return (\n <Button variant={variant} size='lg' className={className}>\n {children}\n </Button>\n )\n}\n\nfunction HeroHeading({\n title,\n titleAccent,\n badge,\n}: {\n title: string\n titleAccent?: string\n badge?: string\n}) {\n return (\n <>\n {badge && (\n <div className='border-primary/20 bg-primary/5 text-primary inline-flex items-center rounded-full border px-4 py-1.5 text-sm font-medium backdrop-blur-sm'>\n {badge}\n </div>\n )}\n <h1 className='text-foreground mt-8 text-4xl font-bold tracking-tight sm:text-5xl md:text-7xl'>\n {title}{' '}\n {titleAccent && (\n <span className='from-primary to-primary/70 bg-gradient-to-r bg-clip-text text-transparent'>\n {titleAccent}\n </span>\n )}\n </h1>\n </>\n )\n}\n\nfunction EditorialHeading({\n title,\n titleAccent,\n badge,\n}: {\n title: string\n titleAccent?: string\n badge?: string\n}) {\n return (\n <>\n {badge && (\n <div className='border-primary/20 bg-primary/5 text-primary inline-flex items-center justify-center rounded-md border px-4 py-1.5 text-sm'>\n {badge}\n </div>\n )}\n <h1 className='mt-6 text-4xl font-bold tracking-tight text-balance sm:text-5xl md:text-6xl'>\n {title} {titleAccent && <span className='text-primary'>{titleAccent}</span>}\n </h1>\n </>\n )\n}\n\ninterface HeroLabels {\n addToCartLabel: string\n buyNowLabel: string\n newLabel: string\n outOfStockLabel: string\n colorsLabel: string\n discountSuffixLabel: string\n searchPlaceholder: string\n searchLabel: string\n featuredDescription?: string\n shopNowLabel: string\n endsInLabel: string\n productsLabel: string\n viewLabel: string\n}\n\nfunction CompactProductCard({\n product,\n currency,\n labels,\n onAddToCart,\n onBuyNow,\n onSelectColor,\n hasCustomBuyNowLabel,\n}: {\n product: FeaturedProduct\n currency?: string\n labels: HeroLabels\n onAddToCart?: (product: FeaturedProduct) => void\n onBuyNow?: (product: FeaturedProduct) => void\n onSelectColor?: (product: FeaturedProduct, index: number, color: string) => void\n hasCustomBuyNowLabel: boolean\n}) {\n const outOfStock = product.inStock === false\n const onSale = hasRealDiscount(product)\n // A host-supplied custom action label is a purchase affordance and requires\n // its handler; the block's default label is a detail affordance that may\n // render without one. Never infer this from the label's language.\n const showBuyNow = Boolean(onBuyNow) || !hasCustomBuyNowLabel\n\n return (\n <div className='bg-card relative h-full overflow-hidden rounded-lg border shadow-sm transition-shadow hover:shadow-md'>\n <div className='absolute top-4 left-4 z-10 flex flex-col gap-2'>\n {product.isNew && (\n <Badge variant='secondary' className='rounded-full'>{labels.newLabel}</Badge>\n )}\n {onSale && (\n <Badge variant='destructive' className='rounded-full'>\n {discountPercent(product.price, product.originalPrice as number)}\n {labels.discountSuffixLabel}\n </Badge>\n )}\n </div>\n\n <div className='relative aspect-square overflow-hidden'>\n {product.image && product.image.trim().length > 0 ? (\n <img\n src={product.image}\n alt={product.imageAlt ?? product.name}\n className='size-full object-cover'\n loading='lazy'\n />\n ) : null}\n {outOfStock && (\n <div className='absolute inset-0 flex items-center justify-center bg-black/50'>\n <span className='rounded bg-white/90 px-3 py-1 text-sm font-medium'>{labels.outOfStockLabel}</span>\n </div>\n )}\n </div>\n\n <div className='p-4'>\n {product.brand && product.brand.trim().length > 0 && (\n <div className='text-muted-foreground mb-1 text-sm font-medium'>{product.brand}</div>\n )}\n <h3 className='mb-2 font-medium'>{product.name}</h3>\n\n <div className='mb-3'>\n <span className='text-lg font-bold'>{formatAmount(product.price, currency)}</span>\n {onSale && (\n <span className='text-muted-foreground ms-2 text-sm line-through'>\n {formatAmount(product.originalPrice as number, currency)}\n </span>\n )}\n </div>\n\n {product.colors && product.colors.length > 0 && (\n <div className='mb-4 flex items-center'>\n <span className='text-muted-foreground me-2 text-sm'>{labels.colorsLabel}</span>\n <div className='flex gap-1'>\n {product.colors.map((color, i) => (\n <button\n key={i}\n className='size-5 rounded-full border'\n style={{ backgroundColor: color }}\n aria-label={`Opción de color ${i + 1}`}\n onClick={onSelectColor ? () => onSelectColor(product, i, color) : undefined}\n />\n ))}\n </div>\n </div>\n )}\n\n {typeof product.rating === 'number' && (\n <div className='mb-4 flex items-center'>\n <div className='flex'>\n {[...Array(5)].map((_, i) => (\n <Star\n key={i}\n className={`size-4 ${i < Math.floor(product.rating ?? 0) ? 'fill-foreground text-foreground' : 'text-muted-foreground'}`}\n />\n ))}\n </div>\n {typeof product.reviewCount === 'number' && (\n <span className='text-muted-foreground ms-2 text-sm'>({product.reviewCount.toLocaleString()})</span>\n )}\n </div>\n )}\n\n <div className='flex flex-col gap-2'>\n {onAddToCart && (\n <Button\n variant='outline'\n className='h-9 cursor-pointer px-4 py-2'\n disabled={outOfStock}\n onClick={() => onAddToCart(product)}\n >\n <ShoppingBag />\n {labels.addToCartLabel}\n </Button>\n )}\n {showBuyNow && (\n <Button\n className='h-9 cursor-pointer px-4 py-2'\n disabled={outOfStock}\n onClick={onBuyNow ? () => onBuyNow(product) : undefined}\n >\n {labels.buyNowLabel}\n </Button>\n )}\n </div>\n </div>\n </div>\n )\n}\n\nfunction CompactPresentation({\n title,\n description,\n products,\n badge,\n titleAccent,\n primaryCta,\n secondaryCta,\n heroImage,\n currency,\n labels,\n onAddToCart,\n onBuyNow,\n onSelectColor,\n hasCustomBuyNowLabel,\n}: {\n title: string\n description: string\n products: FeaturedProduct[]\n badge?: string\n titleAccent?: string\n primaryCta?: CTA\n secondaryCta?: CTA\n heroImage?: HeroImage\n currency?: string\n labels: HeroLabels\n onAddToCart?: (product: FeaturedProduct) => void\n onBuyNow?: (product: FeaturedProduct) => void\n onSelectColor?: (product: FeaturedProduct, index: number, color: string) => void\n hasCustomBuyNowLabel: boolean\n}) {\n const reduceMotion = useReducedMotion()\n\n return (\n <div className='from-primary/5 to-background relative overflow-hidden bg-gradient-to-br'>\n <div className='relative z-10 mx-auto w-full max-w-7xl flex flex-col items-center justify-between gap-12 px-4 sm:px-6 lg:px-8 py-16 lg:py-20 xl:flex-row xl:items-start'>\n <motion.div\n initial={reduceMotion ? false : { opacity: 0, y: 24 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: 0.5, ease: 'easeOut' }}\n className='mx-auto max-w-xl text-center lg:mx-0 xl:text-left'\n >\n <HeroHeading title={title} titleAccent={titleAccent} badge={badge} />\n <p className='text-muted-foreground mt-8 text-lg'>{description}</p>\n {(primaryCta || secondaryCta) && (\n <div className='mt-10 flex flex-col gap-4 sm:flex-row sm:justify-center xl:justify-start'>\n {primaryCta && (\n <CtaButton cta={primaryCta}>\n <span className='relative z-10 flex items-center gap-2'>\n {primaryCta.label}\n <ArrowRight className='transition-transform group-hover:translate-x-1' />\n </span>\n <span className='bg-primary/5 absolute inset-0 -z-0 opacity-0 transition-opacity group-hover:opacity-100'></span>\n </CtaButton>\n )}\n {secondaryCta && (\n <CtaButton cta={secondaryCta} variant='outline'>\n <span className='relative z-10 flex items-center gap-2'>\n <ShoppingBag />\n {secondaryCta.label}\n </span>\n </CtaButton>\n )}\n </div>\n )}\n {heroImage && heroImage.src.trim().length > 0 ? (\n <img\n src={heroImage.src}\n alt={heroImage.alt}\n className='mt-10 aspect-video w-full rounded-lg object-cover'\n />\n ) : null}\n </motion.div>\n\n {products.length > 0 && (\n <div className='w-full max-w-2xl lg:mt-0'>\n <div className='grid gap-6 sm:grid-cols-2'>\n {products.map((product, index) => (\n <motion.div\n key={product.id}\n initial={reduceMotion ? false : { opacity: 0, y: 24 }}\n whileInView={{ opacity: 1, y: 0 }}\n viewport={{ once: true, margin: '-40px' }}\n transition={{\n duration: 0.45,\n delay: reduceMotion ? 0 : index * 0.1,\n ease: 'easeOut',\n }}\n >\n <CompactProductCard\n product={product}\n currency={currency}\n labels={labels}\n onAddToCart={onAddToCart}\n onBuyNow={onBuyNow}\n onSelectColor={onSelectColor}\n hasCustomBuyNowLabel={hasCustomBuyNowLabel}\n />\n </motion.div>\n ))}\n </div>\n </div>\n )}\n </div>\n\n <div className='bg-primary/10 absolute -top-32 -right-32 size-96 rounded-full blur-3xl' />\n <div className='bg-secondary/30 absolute -bottom-32 -left-32 size-96 rounded-full blur-3xl' />\n </div>\n )\n}\n\nfunction ShowcaseSlide({\n product,\n currency,\n labels,\n onBuyNow,\n}: {\n product: FeaturedProduct\n currency?: string\n labels: HeroLabels\n onBuyNow?: (product: FeaturedProduct) => void\n}) {\n const outOfStock = product.inStock === false\n\n return (\n <Card className='relative size-full overflow-hidden border-1 py-4'>\n <CardContent className='px-4'>\n <div className='relative size-full overflow-hidden rounded-md'>\n {product.image && product.image.trim().length > 0 ? (\n <img\n src={product.image}\n alt={product.imageAlt ?? product.name}\n className='h-[500px] w-full object-cover'\n loading='lazy'\n />\n ) : null}\n </div>\n <div className='from-background/90 via-background/30 absolute inset-0 bg-linear-to-t to-transparent' />\n\n <div className='text-background-foreground absolute inset-0 flex flex-col justify-end p-8'>\n <div className='relative z-10 flex max-w-md flex-col gap-4'>\n {product.tag && (\n <Badge className='w-fit rounded-full px-2.5 py-0.5 font-semibold'>{product.tag}</Badge>\n )}\n <h2 className='text-4xl font-bold'>{product.name}</h2>\n {labels.featuredDescription && (\n <p className='text-background-foreground/80 text-lg'>{labels.featuredDescription}</p>\n )}\n <span className='text-3xl font-bold'>{formatAmount(product.price, currency)}</span>\n <div className='flex items-center gap-4 pt-2'>\n {onBuyNow && (\n <Button\n size='lg'\n className='h-10 cursor-pointer rounded-full px-8'\n disabled={outOfStock}\n onClick={() => onBuyNow(product)}\n >\n {labels.buyNowLabel}\n </Button>\n )}\n {typeof product.rating === 'number' && (\n <div className='text-foreground flex items-center gap-1'>\n <Star className='fill-foreground size-5' />\n <span className='font-medium'>{product.rating}</span>\n {typeof product.reviewCount === 'number' && (\n <span className='text-foreground/80'>({product.reviewCount})</span>\n )}\n </div>\n )}\n </div>\n </div>\n </div>\n </CardContent>\n </Card>\n )\n}\n\nfunction ShowcasePresentation({\n title,\n description,\n products,\n badge,\n primaryCta,\n secondaryCta,\n currency,\n labels,\n onSearch,\n onBuyNow,\n rotationInterval,\n}: {\n title: string\n description: string\n products: FeaturedProduct[]\n badge?: string\n primaryCta?: CTA\n secondaryCta?: CTA\n currency?: string\n labels: HeroLabels\n onSearch?: (query: string) => void\n onBuyNow?: (product: FeaturedProduct) => void\n rotationInterval: number\n}) {\n const reduceMotion = useReducedMotion()\n const [searchQuery, setSearchQuery] = useState('')\n const [api, setApi] = useState<CarouselApi>()\n const [currentSlide, setCurrentSlide] = useState(0)\n\n useEffect(() => {\n if (!api || products.length <= 1 || reduceMotion) return\n\n const interval = setInterval(() => {\n const nextSlide = (currentSlide + 1) % products.length\n api.scrollTo(nextSlide)\n setCurrentSlide(nextSlide)\n }, rotationInterval)\n\n return () => clearInterval(interval)\n }, [api, currentSlide, products.length, reduceMotion, rotationInterval])\n\n const handleSearch = () => {\n if (onSearch) onSearch(searchQuery)\n }\n\n return (\n <section className='from-background to-accent/20 relative bg-linear-to-b'>\n <div className='relative mx-auto w-full max-w-7xl px-4 py-16 sm:px-6 lg:px-8 lg:py-20'>\n <div className='grid grid-cols-1 items-center gap-12 lg:grid-cols-2'>\n <header className='flex flex-col gap-8'>\n {badge && (\n <Badge variant='outline' className='flex h-auto w-fit items-center rounded-full px-4 py-2 font-semibold'>\n {badge}\n </Badge>\n )}\n\n <h1 className='text-5xl leading-tight font-bold text-balance md:text-6xl lg:text-7xl'>{title}</h1>\n\n <p className='text-muted-foreground max-w-lg text-xl text-balance'>{description}</p>\n\n {onSearch && (\n <div className='relative max-w-md'>\n <Input\n type='search'\n placeholder={labels.searchPlaceholder}\n value={searchQuery}\n onChange={e => setSearchQuery(e.target.value)}\n onKeyDown={e => {\n if (e.key === 'Enter') handleSearch()\n }}\n className='h-14 rounded-full pe-4 pl-12 text-lg'\n aria-label={labels.searchPlaceholder}\n />\n <Search className='text-muted-foreground absolute top-1/2 start-4 size-5 -translate-y-1/2' />\n <Button\n size='lg'\n className='absolute top-1/2 end-2 h-10 -translate-y-1/2 cursor-pointer rounded-full px-6'\n onClick={handleSearch}\n >\n {labels.searchLabel}\n </Button>\n </div>\n )}\n\n {(primaryCta || secondaryCta) && (\n <div className='flex items-center gap-4'>\n {primaryCta && (\n <CtaButton cta={primaryCta} className='h-10 cursor-pointer rounded-full px-4'>\n <span className='flex items-center gap-2'>\n {primaryCta.label}\n <ArrowRight />\n </span>\n </CtaButton>\n )}\n {secondaryCta && (\n <CtaButton cta={secondaryCta} variant='outline' className='h-10 cursor-pointer rounded-full px-4'>\n <span className='flex items-center gap-2'>\n <ShoppingBag />\n {secondaryCta.label}\n </span>\n </CtaButton>\n )}\n </div>\n )}\n </header>\n\n {products.length > 0 && (\n <div className='flex flex-col gap-4'>\n <div className='relative h-[500px] w-full border-0'>\n <Carousel\n className='group size-full'\n setApi={setApi}\n opts={{\n align: 'start',\n loop: true,\n duration: 20,\n skipSnaps: true,\n }}\n >\n <CarouselContent className='h-full'>\n {products.map(product => (\n <CarouselItem key={product.id} className='h-full'>\n <ShowcaseSlide product={product} currency={currency} labels={labels} onBuyNow={onBuyNow} />\n </CarouselItem>\n ))}\n </CarouselContent>\n </Carousel>\n </div>\n\n <div className='relative mt-8 flex justify-center gap-3'>\n {products.map((product, index) => (\n <button\n key={product.id}\n type='button'\n onClick={() => {\n api?.scrollTo(index)\n setCurrentSlide(index)\n }}\n className={cn(\n 'relative size-3 rounded-full transition-all',\n currentSlide === index ? 'bg-primary' : 'bg-foreground/20 hover:bg-foreground/40'\n )}\n aria-label={`Ir a la diapositiva ${index + 1}`}\n aria-current={currentSlide === index ? 'step' : undefined}\n />\n ))}\n </div>\n </div>\n )}\n </div>\n </div>\n </section>\n )\n}\n\nfunction EditorialPresentation({\n title,\n description,\n badge,\n titleAccent,\n primaryCta,\n secondaryCta,\n shippingInfo,\n departments,\n featuredDeals,\n storeLocator,\n currency,\n labels,\n onDepartmentClick,\n onShopNow,\n onLocateStores,\n}: {\n title: string\n description: string\n badge?: string\n titleAccent?: string\n primaryCta?: CTA\n secondaryCta?: CTA\n shippingInfo?: string\n departments: HeroDepartment[]\n featuredDeals: HeroFeaturedDeal[]\n storeLocator?: HeroStoreLocator\n currency?: string\n labels: HeroLabels\n onDepartmentClick?: (department: HeroDepartment) => void\n onShopNow?: (item: HeroFeaturedDeal | HeroDeal) => void\n onLocateStores?: () => void\n}) {\n const departmentChipClasses = cn(\n 'flex flex-col items-center gap-4 rounded-lg p-2 text-center outline-none',\n 'transition-opacity hover:opacity-90 focus-visible:ring-2 focus-visible:ring-ring',\n )\n\n return (\n <div className='bg-background relative overflow-hidden'>\n <div className='relative z-10'>\n <div className='mx-auto w-full max-w-7xl px-4 py-16 sm:px-6 lg:px-8 lg:py-20'>\n <div className='mx-auto max-w-4xl text-center'>\n <EditorialHeading title={title} titleAccent={titleAccent} badge={badge} />\n\n <p className='text-muted-foreground mx-auto mt-6 max-w-2xl text-lg'>{description}</p>\n\n {(primaryCta || secondaryCta) && (\n <div className='mt-8 flex flex-wrap justify-center gap-4'>\n {primaryCta && (\n <CtaButton cta={primaryCta} className='group h-10 cursor-pointer px-4 text-base'>\n {primaryCta.label}\n <ArrowRight className='transition-transform group-hover:translate-x-1' />\n </CtaButton>\n )}\n {secondaryCta && (\n <CtaButton cta={secondaryCta} variant='outline' className='group h-10 cursor-pointer px-4 text-base'>\n {secondaryCta.label}\n </CtaButton>\n )}\n </div>\n )}\n\n {shippingInfo && (\n <div className='mt-6'>\n <div className='bg-background/80 text-muted-foreground inline-flex items-center gap-2 rounded-full px-4 py-1.5 text-sm backdrop-blur-sm'>\n <MapPin className='text-primary size-4' aria-hidden='true' />\n <span>{shippingInfo}</span>\n </div>\n </div>\n )}\n\n {departments.length > 0 && (\n <div className='mt-12 grid grid-cols-3 gap-8'>\n {departments.map(department => {\n const chip = (\n <>\n {department.image && department.image.trim().length > 0 ? (\n <img\n src={department.image}\n alt={department.imageAlt ?? department.name}\n className='bg-card border-border size-16 rounded-full border object-cover'\n loading='lazy'\n />\n ) : null}\n <div>\n <div className='text-lg font-medium'>{department.name}</div>\n {department.count && (\n <div className='text-muted-foreground mt-1 text-sm'>{department.count}</div>\n )}\n </div>\n </>\n )\n\n if (department.href) {\n return (\n <a\n key={department.id}\n href={department.href}\n className={cn(departmentChipClasses, 'cursor-pointer')}\n >\n {chip}\n </a>\n )\n }\n\n return (\n <button\n key={department.id}\n type='button'\n onClick={onDepartmentClick ? () => onDepartmentClick(department) : undefined}\n className={cn(departmentChipClasses, 'cursor-pointer')}\n >\n {chip}\n </button>\n )\n })}\n </div>\n )}\n\n {featuredDeals.length > 0 && (\n <div className='mt-16 grid gap-6 sm:grid-cols-2'>\n {featuredDeals.map(deal => {\n const onSale = hasRealDiscount(deal)\n\n return (\n <Card key={deal.id} className='mx-auto h-full w-full overflow-hidden border-0 py-0 shadow-lg'>\n <CardContent className='p-0'>\n <div className='relative aspect-[3/2] overflow-hidden'>\n {deal.image && deal.image.trim().length > 0 ? (\n <img\n src={deal.image}\n alt={deal.imageAlt ?? deal.name}\n className='size-full object-cover object-center transition-transform duration-700 hover:scale-105'\n loading='lazy'\n />\n ) : null}\n <div className='from-background/90 via-background/30 absolute inset-0 bg-gradient-to-t to-transparent' />\n <div className='absolute inset-0 flex items-end p-8'>\n <div className='w-full'>\n <div className='bg-background/80 flex flex-col items-center justify-between gap-6 rounded-lg p-6 backdrop-blur-sm sm:flex-row sm:gap-8'>\n <div className='text-center sm:text-left'>\n <h3 className='text-2xl font-bold tracking-tight sm:text-3xl'>{deal.name}</h3>\n {deal.description && (\n <p className='text-muted-foreground mt-1'>{deal.description}</p>\n )}\n <div className='mt-2 flex items-baseline justify-center gap-2 sm:justify-start'>\n <span className='text-lg font-bold'>{formatAmount(deal.price, currency)}</span>\n {onSale && (\n <span className='text-muted-foreground text-sm line-through'>\n {formatAmount(deal.originalPrice as number, currency)}\n </span>\n )}\n </div>\n </div>\n {(deal.cta?.href || onShopNow) && (\n <div className='flex-shrink-0'>\n {deal.cta?.href ? (\n <Button size='lg' className='group h-10 cursor-pointer px-4' asChild>\n <a href={deal.cta.href}>\n {deal.cta.label}\n <ArrowRight className='transition-transform group-hover:translate-x-1' />\n </a>\n </Button>\n ) : (\n <Button\n size='lg'\n className='group h-10 cursor-pointer px-4'\n onClick={() => onShopNow?.(deal)}\n >\n {deal.cta?.label ?? labels.shopNowLabel}\n <ArrowRight className='transition-transform group-hover:translate-x-1' />\n </Button>\n )}\n </div>\n )}\n </div>\n </div>\n </div>\n </div>\n </CardContent>\n </Card>\n )\n })}\n </div>\n )}\n\n {storeLocator && (\n <div className='border-border/50 bg-background/50 mt-8 rounded-lg border p-6 backdrop-blur-sm'>\n <div className='flex flex-col items-center gap-6 sm:flex-row sm:justify-between'>\n <div className='flex items-center gap-4'>\n <div className='bg-primary/10 text-primary flex size-12 items-center justify-center rounded-full'>\n <MapPin className='size-6' aria-hidden='true' />\n </div>\n <div className='text-start'>\n <h4 className='text-lg font-medium'>{storeLocator.title}</h4>\n <p className='text-muted-foreground'>{storeLocator.description}</p>\n </div>\n </div>\n {(storeLocator.ctaHref || onLocateStores) && (\n <div>\n {storeLocator.ctaHref ? (\n <Button variant='outline' className='h-9 cursor-pointer px-4 py-2 whitespace-nowrap' asChild>\n <a href={storeLocator.ctaHref}>{storeLocator.ctaLabel}</a>\n </Button>\n ) : (\n <Button\n variant='outline'\n className='h-9 cursor-pointer px-4 py-2 whitespace-nowrap'\n onClick={onLocateStores}\n >\n {storeLocator.ctaLabel}\n </Button>\n )}\n </div>\n )}\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n </div>\n )\n}\n\nfunction PromotionalPresentation({\n title,\n description,\n badge,\n titleAccent,\n deals,\n categories,\n rotationInterval,\n labels,\n onShopNow,\n onCategoryClick,\n}: {\n title: string\n description: string\n badge?: string\n titleAccent?: string\n deals: HeroDeal[]\n categories: HeroCategory[]\n rotationInterval: number\n labels: HeroLabels\n onShopNow?: (item: HeroFeaturedDeal | HeroDeal) => void\n onCategoryClick?: (category: HeroCategory) => void\n}) {\n const reduceMotion = useReducedMotion()\n const [currentDeal, setCurrentDeal] = useState(0)\n\n useEffect(() => {\n if (deals.length <= 1 || reduceMotion) return\n\n const interval = setInterval(() => {\n setCurrentDeal(prev => (prev + 1) % deals.length)\n }, rotationInterval)\n\n return () => clearInterval(interval)\n }, [deals.length, reduceMotion, rotationInterval])\n\n const deal = deals[currentDeal]\n\n return (\n <div className='relative'>\n {deal && (\n <header className='bg-primary text-primary-foreground sticky top-0 z-50 shadow-md'>\n <div className='mx-auto w-full max-w-7xl px-4 py-2 sm:px-6 lg:px-8'>\n <div className='flex items-center justify-center'>\n <div className='flex w-full max-w-3xl items-center justify-center gap-4'>\n <div className='flex items-center gap-2'>\n <Badge\n variant='secondary'\n className='bg-primary-foreground text-primary px-2.5 py-0.5 font-semibold'\n >\n {deal.title}\n </Badge>\n {deal.discount && <span className='font-semibold'>{deal.discount}</span>}\n </div>\n {deal.endTime && (\n <span className='hidden sm:inline'>\n {labels.endsInLabel} {deal.endTime}\n </span>\n )}\n {onShopNow && (\n <Button\n variant='link'\n size='sm'\n className='text-primary-foreground hover:text-primary-foreground/80 ml-auto h-8 cursor-pointer px-3 text-xs'\n onClick={() => onShopNow(deal)}\n >\n {labels.shopNowLabel} <ArrowRight />\n </Button>\n )}\n </div>\n </div>\n </div>\n </header>\n )}\n\n <main className='mx-auto w-full max-w-7xl px-4 py-8 sm:px-6 lg:px-8'>\n <div className='mb-12 text-center'>\n {badge && (\n <div className='relative inline-block'>\n <Badge\n variant='outline'\n className='mb-4 flex h-auto items-center rounded-full px-3.5 py-1.5 text-sm font-normal'\n >\n {badge}\n </Badge>\n </div>\n )}\n <h1 className='text-4xl font-bold tracking-tight text-balance sm:text-5xl md:text-6xl'>\n {title}\n {titleAccent && (\n <>\n <br />\n {titleAccent}\n </>\n )}\n </h1>\n <p className='text-muted-foreground mx-auto mt-4 max-w-2xl text-lg'>{description}</p>\n </div>\n\n {categories.length > 0 && (\n <div className='grid gap-4 sm:grid-cols-2 lg:grid-cols-4'>\n {categories.map(category => (\n <Card key={category.id} className='group relative overflow-hidden py-0 transition-all duration-500'>\n {category.image && category.image.trim().length > 0 ? (\n <img\n src={category.image}\n alt={category.imageAlt ?? category.name}\n className='aspect-4/5 size-full object-cover grayscale transition-all duration-500 hover:grayscale-0'\n width={400}\n height={500}\n loading='lazy'\n />\n ) : (\n <div className='bg-muted aspect-4/5 size-full' />\n )}\n <CardContent className='absolute inset-x-0 bottom-0 p-4'>\n <div className='mt-1 flex items-center justify-between'>\n <div>\n <h2 className='text-background dark:text-foreground text-lg font-medium'>{category.name}</h2>\n {category.count && (\n <span className='text-background/80 dark:text-foreground/80 text-sm'>\n {category.count} {labels.productsLabel}\n </span>\n )}\n </div>\n {category.href ? (\n <Button\n variant='secondary'\n size='icon'\n className='h-9 w-9 cursor-pointer rounded-full backdrop-blur-xs'\n aria-label={`${labels.viewLabel} ${category.name}`}\n asChild\n >\n <a href={category.href}>\n <ArrowRight />\n </a>\n </Button>\n ) : onCategoryClick ? (\n <Button\n variant='secondary'\n size='icon'\n className='h-9 w-9 cursor-pointer rounded-full backdrop-blur-xs'\n aria-label={`${labels.viewLabel} ${category.name}`}\n onClick={() => onCategoryClick(category)}\n >\n <ArrowRight />\n </Button>\n ) : null}\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n </main>\n </div>\n )\n}\n\nexport function StorefrontHero({\n title,\n description,\n presentation = 'compact',\n currency,\n products,\n badge,\n titleAccent,\n primaryCta,\n secondaryCta,\n heroImage,\n onSearch,\n departments = [],\n featuredDeals = [],\n storeLocator,\n shippingInfo,\n deals = [],\n categories = [],\n rotationInterval = 3000,\n onAddToCart,\n onBuyNow,\n onSelectColor,\n onDepartmentClick,\n onShopNow,\n onLocateStores,\n onCategoryClick,\n addToCartLabel = 'Agregar al carrito',\n buyNowLabel,\n newLabel = 'Nuevo',\n outOfStockLabel = 'Agotado',\n colorsLabel = 'Colores:',\n discountSuffixLabel = '% OFF',\n searchPlaceholder = 'Buscar productos...',\n searchLabel = 'Buscar',\n featuredDescription,\n shopNowLabel = 'Comprar ahora',\n endsInLabel = 'Termina en',\n productsLabel = 'productos',\n viewLabel = 'Ver',\n}: StorefrontHeroProps) {\n // Presence-based, never label-language based: a host-supplied custom action\n // label is a purchase affordance that must be handler-gated, while the\n // block's own default label is a non-purchase detail affordance that may\n // render without a handler (preserving the accepted default detail).\n const resolvedBuyNowLabel = buyNowLabel ?? 'Ver producto'\n const hasCustomBuyNowLabel = buyNowLabel !== undefined\n const labels: HeroLabels = {\n addToCartLabel,\n buyNowLabel: resolvedBuyNowLabel,\n newLabel,\n outOfStockLabel,\n colorsLabel,\n discountSuffixLabel,\n searchPlaceholder,\n searchLabel,\n featuredDescription,\n shopNowLabel,\n endsInLabel,\n productsLabel,\n viewLabel,\n }\n\n if (presentation === 'showcase') {\n return (\n <ShowcasePresentation\n title={title}\n description={description}\n products={products}\n badge={badge}\n primaryCta={primaryCta}\n secondaryCta={secondaryCta}\n currency={currency}\n labels={labels}\n onSearch={onSearch}\n onBuyNow={onBuyNow}\n rotationInterval={rotationInterval}\n />\n )\n }\n\n if (presentation === 'editorial') {\n return (\n <EditorialPresentation\n title={title}\n description={description}\n badge={badge}\n titleAccent={titleAccent}\n primaryCta={primaryCta}\n secondaryCta={secondaryCta}\n shippingInfo={shippingInfo}\n departments={departments}\n featuredDeals={featuredDeals}\n storeLocator={storeLocator}\n currency={currency}\n labels={labels}\n onDepartmentClick={onDepartmentClick}\n onShopNow={onShopNow}\n onLocateStores={onLocateStores}\n />\n )\n }\n\n if (presentation === 'promotional') {\n return (\n <PromotionalPresentation\n title={title}\n description={description}\n badge={badge}\n titleAccent={titleAccent}\n deals={deals}\n categories={categories}\n rotationInterval={rotationInterval}\n labels={labels}\n onShopNow={onShopNow}\n onCategoryClick={onCategoryClick}\n />\n )\n }\n\n return (\n <CompactPresentation\n title={title}\n description={description}\n products={products}\n badge={badge}\n titleAccent={titleAccent}\n primaryCta={primaryCta}\n secondaryCta={secondaryCta}\n heroImage={heroImage}\n currency={currency}\n labels={labels}\n onAddToCart={onAddToCart}\n onBuyNow={onBuyNow}\n onSelectColor={onSelectColor}\n hasCustomBuyNowLabel={hasCustomBuyNowLabel}\n />\n )\n}\n\nexport default StorefrontHero\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/blocks/e-commerce/storefront-hero/storefront-hero.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useState } from 'react'\nimport { motion, useReducedMotion } from 'motion/react'\nimport { ArrowRight, MapPin, Search, ShoppingBag, Star } from 'lucide-react'\nimport type { ComponentProps, ReactNode } from 'react'\n\nimport { Badge } from '../../../ui/badge'\nimport { Button } from '../../../ui/button'\nimport { Card, CardContent } from '../../../ui/card'\nimport { Carousel, CarouselContent, CarouselItem, type CarouselApi } from '../../../ui/carousel'\nimport { Input } from '../../../ui/input'\nimport { MOTION } from '../../../lib/motion'\nimport { cn } from '../../../lib/utils'\nimport type { CTA } from '../../../lib/types'\n\n/**\n * Display contract for products featured in the hero. Every popularity,\n * review, or availability field is host-supplied evidence: omitted fields\n * render nothing (honest omission) instead of fabricated defaults.\n */\nexport interface FeaturedProduct {\n id: string\n name: string\n /** Current selling price. */\n price: number\n /** Real compare-at price. Discount treatments render only from a real `originalPrice > price` pair. */\n originalPrice?: number\n /** Image URL or path; omitted entirely when absent or blank (never an empty `src`). */\n image?: string\n /** Accessible image description (falls back to `name`). */\n imageAlt?: string\n /** Host-supplied brand label; the row renders only when supplied. */\n brand?: string\n /** Host-supplied swatch colors; the row renders only when supplied. */\n colors?: string[]\n /** Host-supplied rating (0–5); rendered only when supplied. */\n rating?: number\n /** Host-supplied review count; rendered only when supplied. */\n reviewCount?: number\n /** Host-supplied availability. Absence makes no stock claim; an explicit `false` disables purchase. */\n inStock?: boolean\n /** Host-supplied \"new\" flag; the badge renders only when true. */\n isNew?: boolean\n /** Host-supplied badge label for showcase slides (e.g. a category); rendered only when supplied. */\n tag?: string\n}\n\nexport interface HeroImage {\n src: string\n alt: string\n}\n\nexport interface HeroDepartment {\n id: string\n name: string\n /** Image URL; omitted entirely when absent or blank. */\n image?: string\n /** Accessible image description (falls back to `name`). */\n imageAlt?: string\n /** Host-supplied count label; rendered only when supplied. */\n count?: string\n /** Link destination; renders the chip as a link when present. */\n href?: string\n}\n\nexport interface HeroFeaturedDeal {\n id: string\n name: string\n /** Host-supplied supporting description; rendered only when supplied. */\n description?: string\n /** Image URL; omitted entirely when absent or blank. */\n image?: string\n /** Accessible image description (falls back to `name`). */\n imageAlt?: string\n price: number\n /** Real compare-at price; rendered struck-through only when greater than `price`. */\n originalPrice?: number\n /** Optional call to action shown on the card. */\n cta?: CTA\n}\n\nexport interface HeroStoreLocator {\n title: string\n description: string\n ctaLabel: string\n /** Link destination for the locator button; falls back to `onLocateStores`. */\n ctaHref?: string\n}\n\nexport interface HeroDeal {\n id: string\n /** Deal name shown in the deals bar badge, e.g. a campaign name. */\n title: string\n /** Host-supplied discount label (from a real compare-at price); rendered only when supplied. */\n discount?: string\n /** Host-supplied countdown text; rendered only when supplied — the block never invents one. */\n endTime?: string\n}\n\nexport interface HeroCategory {\n id: string\n name: string\n /** Image URL; omitted entirely when absent or blank. */\n image?: string\n /** Accessible image description (falls back to `name`). */\n imageAlt?: string\n /** Host-supplied count label; rendered only when supplied. */\n count?: string\n /** Link destination; renders the card arrow as a link when present. */\n href?: string\n}\n\n/**\n * The bounded presentation surface, reusing the registry's archetype intent\n * vocabulary: `compact` (text-forward hero + product grid), `showcase`\n * (search affordance + rotating product carousel), `editorial` (department\n * navigation + optional deals/locator), `promotional` (deals bar + category\n * grid). The value changes structure, never the data contract.\n */\nexport type StorefrontHeroPresentation = 'compact' | 'showcase' | 'editorial' | 'promotional'\n\nexport interface StorefrontHeroProps {\n title: string\n description: string\n /** Bounded presentation option; defaults to `compact`. */\n presentation?: StorefrontHeroPresentation\n /** ISO 4217 code used to format prices via `Intl.NumberFormat`; never hardcoded. */\n currency?: string\n /** Featured products. An empty list renders the hero text-forward with no empty grid chrome. */\n products: FeaturedProduct[]\n badge?: string\n titleAccent?: string\n primaryCta?: CTA\n secondaryCta?: CTA\n /**\n * Optional editorial image. Rendered as a native `<img>` when `src` is a\n * non-empty string; omitted entirely when absent or blank (never an empty\n * `src`).\n */\n heroImage?: HeroImage\n /** `showcase` only. The search input renders only when a handler is supplied. */\n onSearch?: (query: string) => void\n /** `editorial` only: department navigation grid. */\n departments?: HeroDepartment[]\n /** `editorial` only: featured deal cards. */\n featuredDeals?: HeroFeaturedDeal[]\n /** `editorial` only: store locator strip. */\n storeLocator?: HeroStoreLocator\n /** `editorial` only: shipping banner text under the CTAs. */\n shippingInfo?: string\n /** `promotional` only: rotating deals bar. */\n deals?: HeroDeal[]\n /** `promotional` only: category card grid. */\n categories?: HeroCategory[]\n /** Milliseconds between rotations (showcase carousel and promotional deals bar; default 3000). */\n rotationInterval?: number\n onAddToCart?: (product: FeaturedProduct) => void\n onBuyNow?: (product: FeaturedProduct) => void\n onSelectColor?: (product: FeaturedProduct, index: number, color: string) => void\n onDepartmentClick?: (department: HeroDepartment) => void\n onShopNow?: (item: HeroFeaturedDeal | HeroDeal) => void\n onLocateStores?: () => void\n onCategoryClick?: (category: HeroCategory) => void\n /** Detail/purchase affordance on product cards and showcase slides. */\n addToCartLabel?: string\n buyNowLabel?: string\n newLabel?: string\n outOfStockLabel?: string\n colorsLabel?: string\n /** Suffix appended to the computed discount percentage (default `% OFF`). */\n discountSuffixLabel?: string\n /** `showcase` labels. */\n searchPlaceholder?: string\n searchLabel?: string\n /** `showcase` copy under each slide's product name. */\n featuredDescription?: string\n /** `editorial`/`promotional` labels. */\n shopNowLabel?: string\n endsInLabel?: string\n productsLabel?: string\n viewLabel?: string\n}\n\nfunction hasRealDiscount(item: Pick<FeaturedProduct, 'price' | 'originalPrice'>): boolean {\n return (\n typeof item.originalPrice === 'number' &&\n Number.isFinite(item.originalPrice) &&\n item.originalPrice > item.price &&\n item.price >= 0\n )\n}\n\nfunction discountPercent(price: number, originalPrice: number): number {\n return Math.round(((originalPrice - price) / originalPrice) * 100)\n}\n\nfunction formatAmount(amount: number, currency?: string): string {\n if (currency) {\n return new Intl.NumberFormat(undefined, { style: 'currency', currency }).format(amount)\n }\n return new Intl.NumberFormat(undefined, { maximumFractionDigits: 2 }).format(amount)\n}\n\nfunction CtaButton({\n cta,\n variant,\n className = 'group relative cursor-pointer overflow-hidden px-8 py-6 text-base font-medium',\n children,\n}: {\n cta: CTA\n variant?: ComponentProps<typeof Button>['variant']\n className?: string\n children: ReactNode\n}) {\n if (cta.href) {\n return (\n <Button variant={variant} size='lg' className={className} asChild>\n <a href={cta.href}>{children}</a>\n </Button>\n )\n }\n\n return (\n <Button variant={variant} size='lg' className={className}>\n {children}\n </Button>\n )\n}\n\nfunction HeroHeading({\n title,\n titleAccent,\n badge,\n}: {\n title: string\n titleAccent?: string\n badge?: string\n}) {\n return (\n <>\n {badge && (\n <div className='border-primary/20 bg-primary/5 text-primary inline-flex items-center rounded-full border px-4 py-1.5 text-sm font-medium backdrop-blur-sm'>\n {badge}\n </div>\n )}\n <h1 className='text-foreground mt-8 text-4xl font-bold tracking-tight sm:text-5xl md:text-7xl'>\n {title}{' '}\n {titleAccent && (\n <span className='from-primary to-primary/70 bg-gradient-to-r bg-clip-text text-transparent'>\n {titleAccent}\n </span>\n )}\n </h1>\n </>\n )\n}\n\nfunction EditorialHeading({\n title,\n titleAccent,\n badge,\n}: {\n title: string\n titleAccent?: string\n badge?: string\n}) {\n return (\n <>\n {badge && (\n <div className='border-primary/20 bg-primary/5 text-primary inline-flex items-center justify-center rounded-md border px-4 py-1.5 text-sm'>\n {badge}\n </div>\n )}\n <h1 className='mt-6 text-4xl font-bold tracking-tight text-balance sm:text-5xl md:text-6xl'>\n {title} {titleAccent && <span className='text-primary'>{titleAccent}</span>}\n </h1>\n </>\n )\n}\n\ninterface HeroLabels {\n addToCartLabel: string\n buyNowLabel: string\n newLabel: string\n outOfStockLabel: string\n colorsLabel: string\n discountSuffixLabel: string\n searchPlaceholder: string\n searchLabel: string\n featuredDescription?: string\n shopNowLabel: string\n endsInLabel: string\n productsLabel: string\n viewLabel: string\n}\n\nfunction CompactProductCard({\n product,\n currency,\n labels,\n onAddToCart,\n onBuyNow,\n onSelectColor,\n hasCustomBuyNowLabel,\n}: {\n product: FeaturedProduct\n currency?: string\n labels: HeroLabels\n onAddToCart?: (product: FeaturedProduct) => void\n onBuyNow?: (product: FeaturedProduct) => void\n onSelectColor?: (product: FeaturedProduct, index: number, color: string) => void\n hasCustomBuyNowLabel: boolean\n}) {\n const outOfStock = product.inStock === false\n const onSale = hasRealDiscount(product)\n // A host-supplied custom action label is a purchase affordance and requires\n // its handler; the block's default label is a detail affordance that may\n // render without one. Never infer this from the label's language.\n const showBuyNow = Boolean(onBuyNow) || !hasCustomBuyNowLabel\n\n return (\n <div className='bg-card relative h-full overflow-hidden rounded-lg border shadow-sm transition-shadow hover:shadow-md'>\n <div className='absolute top-4 left-4 z-10 flex flex-col gap-2'>\n {product.isNew && (\n <Badge variant='secondary' className='rounded-full'>{labels.newLabel}</Badge>\n )}\n {onSale && (\n <Badge variant='destructive' className='rounded-full'>\n {discountPercent(product.price, product.originalPrice as number)}\n {labels.discountSuffixLabel}\n </Badge>\n )}\n </div>\n\n <div className='relative aspect-square overflow-hidden'>\n {product.image && product.image.trim().length > 0 ? (\n <img\n src={product.image}\n alt={product.imageAlt ?? product.name}\n className='size-full object-cover'\n loading='lazy'\n />\n ) : null}\n {outOfStock && (\n <div className='absolute inset-0 flex items-center justify-center bg-black/50'>\n <span className='rounded bg-white/90 px-3 py-1 text-sm font-medium'>{labels.outOfStockLabel}</span>\n </div>\n )}\n </div>\n\n <div className='p-4'>\n {product.brand && product.brand.trim().length > 0 && (\n <div className='text-muted-foreground mb-1 text-sm font-medium'>{product.brand}</div>\n )}\n <h3 className='mb-2 font-medium'>{product.name}</h3>\n\n <div className='mb-3'>\n <span className='text-lg font-bold'>{formatAmount(product.price, currency)}</span>\n {onSale && (\n <span className='text-muted-foreground ms-2 text-sm line-through'>\n {formatAmount(product.originalPrice as number, currency)}\n </span>\n )}\n </div>\n\n {product.colors && product.colors.length > 0 && (\n <div className='mb-4 flex items-center'>\n <span className='text-muted-foreground me-2 text-sm'>{labels.colorsLabel}</span>\n <div className='flex gap-1'>\n {product.colors.map((color, i) => (\n <button\n key={i}\n className='size-5 rounded-full border'\n style={{ backgroundColor: color }}\n aria-label={`Opción de color ${i + 1}`}\n onClick={onSelectColor ? () => onSelectColor(product, i, color) : undefined}\n />\n ))}\n </div>\n </div>\n )}\n\n {typeof product.rating === 'number' && (\n <div className='mb-4 flex items-center'>\n <div className='flex'>\n {[...Array(5)].map((_, i) => (\n <Star\n key={i}\n className={`size-4 ${i < Math.floor(product.rating ?? 0) ? 'fill-foreground text-foreground' : 'text-muted-foreground'}`}\n />\n ))}\n </div>\n {typeof product.reviewCount === 'number' && (\n <span className='text-muted-foreground ms-2 text-sm'>({product.reviewCount.toLocaleString()})</span>\n )}\n </div>\n )}\n\n <div className='flex flex-col gap-2'>\n {onAddToCart && (\n <Button\n variant='outline'\n className='h-9 cursor-pointer px-4 py-2'\n disabled={outOfStock}\n onClick={() => onAddToCart(product)}\n >\n <ShoppingBag />\n {labels.addToCartLabel}\n </Button>\n )}\n {showBuyNow && (\n <Button\n className='h-9 cursor-pointer px-4 py-2'\n disabled={outOfStock}\n onClick={onBuyNow ? () => onBuyNow(product) : undefined}\n >\n {labels.buyNowLabel}\n </Button>\n )}\n </div>\n </div>\n </div>\n )\n}\n\nfunction CompactPresentation({\n title,\n description,\n products,\n badge,\n titleAccent,\n primaryCta,\n secondaryCta,\n heroImage,\n currency,\n labels,\n onAddToCart,\n onBuyNow,\n onSelectColor,\n hasCustomBuyNowLabel,\n}: {\n title: string\n description: string\n products: FeaturedProduct[]\n badge?: string\n titleAccent?: string\n primaryCta?: CTA\n secondaryCta?: CTA\n heroImage?: HeroImage\n currency?: string\n labels: HeroLabels\n onAddToCart?: (product: FeaturedProduct) => void\n onBuyNow?: (product: FeaturedProduct) => void\n onSelectColor?: (product: FeaturedProduct, index: number, color: string) => void\n hasCustomBuyNowLabel: boolean\n}) {\n const reduceMotion = useReducedMotion()\n\n return (\n <div className='from-primary/5 to-background relative overflow-hidden bg-gradient-to-br'>\n <div className='relative z-10 mx-auto w-full max-w-7xl flex flex-col items-center justify-between gap-12 px-4 sm:px-6 lg:px-8 py-16 lg:py-20 xl:flex-row xl:items-start'>\n <motion.div\n initial={reduceMotion ? false : { opacity: 0, y: MOTION.distancePx.entrance }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: MOTION.durationSeconds.entrance, ease: MOTION.easing.standard }}\n className='mx-auto max-w-xl text-center lg:mx-0 xl:text-left'\n >\n <HeroHeading title={title} titleAccent={titleAccent} badge={badge} />\n <p className='text-muted-foreground mt-8 text-lg'>{description}</p>\n {(primaryCta || secondaryCta) && (\n <div className='mt-10 flex flex-col gap-4 sm:flex-row sm:justify-center xl:justify-start'>\n {primaryCta && (\n <CtaButton cta={primaryCta}>\n <span className='relative z-10 flex items-center gap-2'>\n {primaryCta.label}\n <ArrowRight className='transition-transform group-hover:translate-x-1' />\n </span>\n <span className='bg-primary/5 absolute inset-0 -z-0 opacity-0 transition-opacity group-hover:opacity-100'></span>\n </CtaButton>\n )}\n {secondaryCta && (\n <CtaButton cta={secondaryCta} variant='outline'>\n <span className='relative z-10 flex items-center gap-2'>\n <ShoppingBag />\n {secondaryCta.label}\n </span>\n </CtaButton>\n )}\n </div>\n )}\n {heroImage && heroImage.src.trim().length > 0 ? (\n <img\n src={heroImage.src}\n alt={heroImage.alt}\n className='mt-10 aspect-video w-full rounded-lg object-cover'\n />\n ) : null}\n </motion.div>\n\n {products.length > 0 && (\n <div className='w-full max-w-2xl lg:mt-0'>\n <div className='grid gap-6 sm:grid-cols-2'>\n {products.map((product, index) => (\n <motion.div\n key={product.id}\n initial={reduceMotion ? false : { opacity: 0, y: MOTION.distancePx.entrance }}\n whileInView={{ opacity: 1, y: 0 }}\n viewport={{ once: true, margin: '-40px' }}\n transition={{\n duration: MOTION.durationSeconds.entrance,\n delay: reduceMotion ? 0 : MOTION.stagger(index),\n ease: MOTION.easing.standard,\n }}\n >\n <CompactProductCard\n product={product}\n currency={currency}\n labels={labels}\n onAddToCart={onAddToCart}\n onBuyNow={onBuyNow}\n onSelectColor={onSelectColor}\n hasCustomBuyNowLabel={hasCustomBuyNowLabel}\n />\n </motion.div>\n ))}\n </div>\n </div>\n )}\n </div>\n\n <div className='bg-primary/10 absolute -top-32 -right-32 size-96 rounded-full blur-3xl' />\n <div className='bg-secondary/30 absolute -bottom-32 -left-32 size-96 rounded-full blur-3xl' />\n </div>\n )\n}\n\nfunction ShowcaseSlide({\n product,\n currency,\n labels,\n onBuyNow,\n}: {\n product: FeaturedProduct\n currency?: string\n labels: HeroLabels\n onBuyNow?: (product: FeaturedProduct) => void\n}) {\n const outOfStock = product.inStock === false\n\n return (\n <Card className='relative size-full overflow-hidden border-1 py-4'>\n <CardContent className='px-4'>\n <div className='relative size-full overflow-hidden rounded-md'>\n {product.image && product.image.trim().length > 0 ? (\n <img\n src={product.image}\n alt={product.imageAlt ?? product.name}\n className='h-[500px] w-full object-cover'\n loading='lazy'\n />\n ) : null}\n </div>\n <div className='from-background/90 via-background/30 absolute inset-0 bg-linear-to-t to-transparent' />\n\n <div className='text-background-foreground absolute inset-0 flex flex-col justify-end p-8'>\n <div className='relative z-10 flex max-w-md flex-col gap-4'>\n {product.tag && (\n <Badge className='w-fit rounded-full px-2.5 py-0.5 font-semibold'>{product.tag}</Badge>\n )}\n <h2 className='text-4xl font-bold'>{product.name}</h2>\n {labels.featuredDescription && (\n <p className='text-background-foreground/80 text-lg'>{labels.featuredDescription}</p>\n )}\n <span className='text-3xl font-bold'>{formatAmount(product.price, currency)}</span>\n <div className='flex items-center gap-4 pt-2'>\n {onBuyNow && (\n <Button\n size='lg'\n className='h-10 cursor-pointer rounded-full px-8'\n disabled={outOfStock}\n onClick={() => onBuyNow(product)}\n >\n {labels.buyNowLabel}\n </Button>\n )}\n {typeof product.rating === 'number' && (\n <div className='text-foreground flex items-center gap-1'>\n <Star className='fill-foreground size-5' />\n <span className='font-medium'>{product.rating}</span>\n {typeof product.reviewCount === 'number' && (\n <span className='text-foreground/80'>({product.reviewCount})</span>\n )}\n </div>\n )}\n </div>\n </div>\n </div>\n </CardContent>\n </Card>\n )\n}\n\nfunction ShowcasePresentation({\n title,\n description,\n products,\n badge,\n primaryCta,\n secondaryCta,\n currency,\n labels,\n onSearch,\n onBuyNow,\n rotationInterval,\n}: {\n title: string\n description: string\n products: FeaturedProduct[]\n badge?: string\n primaryCta?: CTA\n secondaryCta?: CTA\n currency?: string\n labels: HeroLabels\n onSearch?: (query: string) => void\n onBuyNow?: (product: FeaturedProduct) => void\n rotationInterval: number\n}) {\n const reduceMotion = useReducedMotion()\n const [searchQuery, setSearchQuery] = useState('')\n const [api, setApi] = useState<CarouselApi>()\n const [currentSlide, setCurrentSlide] = useState(0)\n\n useEffect(() => {\n if (!api || products.length <= 1 || reduceMotion) return\n\n const interval = setInterval(() => {\n const nextSlide = (currentSlide + 1) % products.length\n api.scrollTo(nextSlide)\n setCurrentSlide(nextSlide)\n }, rotationInterval)\n\n return () => clearInterval(interval)\n }, [api, currentSlide, products.length, reduceMotion, rotationInterval])\n\n const handleSearch = () => {\n if (onSearch) onSearch(searchQuery)\n }\n\n return (\n <section className='from-background to-accent/20 relative bg-linear-to-b'>\n <div className='relative mx-auto w-full max-w-7xl px-4 py-16 sm:px-6 lg:px-8 lg:py-20'>\n <div className='grid grid-cols-1 items-center gap-12 lg:grid-cols-2'>\n <header className='flex flex-col gap-8'>\n {badge && (\n <Badge variant='outline' className='flex h-auto w-fit items-center rounded-full px-4 py-2 font-semibold'>\n {badge}\n </Badge>\n )}\n\n <h1 className='text-5xl leading-tight font-bold text-balance md:text-6xl lg:text-7xl'>{title}</h1>\n\n <p className='text-muted-foreground max-w-lg text-xl text-balance'>{description}</p>\n\n {onSearch && (\n <div className='relative max-w-md'>\n <Input\n type='search'\n placeholder={labels.searchPlaceholder}\n value={searchQuery}\n onChange={e => setSearchQuery(e.target.value)}\n onKeyDown={e => {\n if (e.key === 'Enter') handleSearch()\n }}\n className='h-14 rounded-full pe-4 pl-12 text-lg'\n aria-label={labels.searchPlaceholder}\n />\n <Search className='text-muted-foreground absolute top-1/2 start-4 size-5 -translate-y-1/2' />\n <Button\n size='lg'\n className='absolute top-1/2 end-2 h-10 -translate-y-1/2 cursor-pointer rounded-full px-6'\n onClick={handleSearch}\n >\n {labels.searchLabel}\n </Button>\n </div>\n )}\n\n {(primaryCta || secondaryCta) && (\n <div className='flex items-center gap-4'>\n {primaryCta && (\n <CtaButton cta={primaryCta} className='h-10 cursor-pointer rounded-full px-4'>\n <span className='flex items-center gap-2'>\n {primaryCta.label}\n <ArrowRight />\n </span>\n </CtaButton>\n )}\n {secondaryCta && (\n <CtaButton cta={secondaryCta} variant='outline' className='h-10 cursor-pointer rounded-full px-4'>\n <span className='flex items-center gap-2'>\n <ShoppingBag />\n {secondaryCta.label}\n </span>\n </CtaButton>\n )}\n </div>\n )}\n </header>\n\n {products.length > 0 && (\n <div className='flex flex-col gap-4'>\n <div className='relative h-[500px] w-full border-0'>\n <Carousel\n className='group size-full'\n setApi={setApi}\n opts={{\n align: 'start',\n loop: true,\n duration: 20,\n skipSnaps: true,\n }}\n >\n <CarouselContent className='h-full'>\n {products.map(product => (\n <CarouselItem key={product.id} className='h-full'>\n <ShowcaseSlide product={product} currency={currency} labels={labels} onBuyNow={onBuyNow} />\n </CarouselItem>\n ))}\n </CarouselContent>\n </Carousel>\n </div>\n\n <div className='relative mt-8 flex justify-center gap-3'>\n {products.map((product, index) => (\n <button\n key={product.id}\n type='button'\n onClick={() => {\n api?.scrollTo(index)\n setCurrentSlide(index)\n }}\n className={cn(\n 'relative size-3 rounded-full transition-colors',\n currentSlide === index ? 'bg-primary' : 'bg-foreground/20 hover:bg-foreground/40'\n )}\n style={{\n transitionDuration: `${MOTION.durationMilliseconds.feedback}ms`,\n transitionTimingFunction: MOTION.cssEasing.standard,\n }}\n aria-label={`Ir a la diapositiva ${index + 1}`}\n aria-current={currentSlide === index ? 'step' : undefined}\n />\n ))}\n </div>\n </div>\n )}\n </div>\n </div>\n </section>\n )\n}\n\nfunction EditorialPresentation({\n title,\n description,\n badge,\n titleAccent,\n primaryCta,\n secondaryCta,\n shippingInfo,\n departments,\n featuredDeals,\n storeLocator,\n currency,\n labels,\n onDepartmentClick,\n onShopNow,\n onLocateStores,\n}: {\n title: string\n description: string\n badge?: string\n titleAccent?: string\n primaryCta?: CTA\n secondaryCta?: CTA\n shippingInfo?: string\n departments: HeroDepartment[]\n featuredDeals: HeroFeaturedDeal[]\n storeLocator?: HeroStoreLocator\n currency?: string\n labels: HeroLabels\n onDepartmentClick?: (department: HeroDepartment) => void\n onShopNow?: (item: HeroFeaturedDeal | HeroDeal) => void\n onLocateStores?: () => void\n}) {\n const departmentChipClasses = cn(\n 'flex flex-col items-center gap-4 rounded-lg p-2 text-center outline-none',\n 'transition-opacity hover:opacity-90 focus-visible:ring-2 focus-visible:ring-ring',\n )\n\n return (\n <div className='bg-background relative overflow-hidden'>\n <div className='relative z-10'>\n <div className='mx-auto w-full max-w-7xl px-4 py-16 sm:px-6 lg:px-8 lg:py-20'>\n <div className='mx-auto max-w-4xl text-center'>\n <EditorialHeading title={title} titleAccent={titleAccent} badge={badge} />\n\n <p className='text-muted-foreground mx-auto mt-6 max-w-2xl text-lg'>{description}</p>\n\n {(primaryCta || secondaryCta) && (\n <div className='mt-8 flex flex-wrap justify-center gap-4'>\n {primaryCta && (\n <CtaButton cta={primaryCta} className='group h-10 cursor-pointer px-4 text-base'>\n {primaryCta.label}\n <ArrowRight className='transition-transform group-hover:translate-x-1' />\n </CtaButton>\n )}\n {secondaryCta && (\n <CtaButton cta={secondaryCta} variant='outline' className='group h-10 cursor-pointer px-4 text-base'>\n {secondaryCta.label}\n </CtaButton>\n )}\n </div>\n )}\n\n {shippingInfo && (\n <div className='mt-6'>\n <div className='bg-background/80 text-muted-foreground inline-flex items-center gap-2 rounded-full px-4 py-1.5 text-sm backdrop-blur-sm'>\n <MapPin className='text-primary size-4' aria-hidden='true' />\n <span>{shippingInfo}</span>\n </div>\n </div>\n )}\n\n {departments.length > 0 && (\n <div className='mt-12 grid grid-cols-3 gap-8'>\n {departments.map(department => {\n const chip = (\n <>\n {department.image && department.image.trim().length > 0 ? (\n <img\n src={department.image}\n alt={department.imageAlt ?? department.name}\n className='bg-card border-border size-16 rounded-full border object-cover'\n loading='lazy'\n />\n ) : null}\n <div>\n <div className='text-lg font-medium'>{department.name}</div>\n {department.count && (\n <div className='text-muted-foreground mt-1 text-sm'>{department.count}</div>\n )}\n </div>\n </>\n )\n\n if (department.href) {\n return (\n <a\n key={department.id}\n href={department.href}\n className={cn(departmentChipClasses, 'cursor-pointer')}\n >\n {chip}\n </a>\n )\n }\n\n return (\n <button\n key={department.id}\n type='button'\n onClick={onDepartmentClick ? () => onDepartmentClick(department) : undefined}\n className={cn(departmentChipClasses, 'cursor-pointer')}\n >\n {chip}\n </button>\n )\n })}\n </div>\n )}\n\n {featuredDeals.length > 0 && (\n <div className='mt-16 grid gap-6 sm:grid-cols-2'>\n {featuredDeals.map(deal => {\n const onSale = hasRealDiscount(deal)\n\n return (\n <Card key={deal.id} className='mx-auto h-full w-full overflow-hidden border-0 py-0 shadow-lg'>\n <CardContent className='p-0'>\n <div className='relative aspect-[3/2] overflow-hidden'>\n {deal.image && deal.image.trim().length > 0 ? (\n <img\n src={deal.image}\n alt={deal.imageAlt ?? deal.name}\n className='size-full object-cover object-center transition-transform duration-700 hover:scale-105'\n loading='lazy'\n />\n ) : null}\n <div className='from-background/90 via-background/30 absolute inset-0 bg-gradient-to-t to-transparent' />\n <div className='absolute inset-0 flex items-end p-8'>\n <div className='w-full'>\n <div className='bg-background/80 flex flex-col items-center justify-between gap-6 rounded-lg p-6 backdrop-blur-sm sm:flex-row sm:gap-8'>\n <div className='text-center sm:text-left'>\n <h3 className='text-2xl font-bold tracking-tight sm:text-3xl'>{deal.name}</h3>\n {deal.description && (\n <p className='text-muted-foreground mt-1'>{deal.description}</p>\n )}\n <div className='mt-2 flex items-baseline justify-center gap-2 sm:justify-start'>\n <span className='text-lg font-bold'>{formatAmount(deal.price, currency)}</span>\n {onSale && (\n <span className='text-muted-foreground text-sm line-through'>\n {formatAmount(deal.originalPrice as number, currency)}\n </span>\n )}\n </div>\n </div>\n {(deal.cta?.href || onShopNow) && (\n <div className='flex-shrink-0'>\n {deal.cta?.href ? (\n <Button size='lg' className='group h-10 cursor-pointer px-4' asChild>\n <a href={deal.cta.href}>\n {deal.cta.label}\n <ArrowRight className='transition-transform group-hover:translate-x-1' />\n </a>\n </Button>\n ) : (\n <Button\n size='lg'\n className='group h-10 cursor-pointer px-4'\n onClick={() => onShopNow?.(deal)}\n >\n {deal.cta?.label ?? labels.shopNowLabel}\n <ArrowRight className='transition-transform group-hover:translate-x-1' />\n </Button>\n )}\n </div>\n )}\n </div>\n </div>\n </div>\n </div>\n </CardContent>\n </Card>\n )\n })}\n </div>\n )}\n\n {storeLocator && (\n <div className='border-border/50 bg-background/50 mt-8 rounded-lg border p-6 backdrop-blur-sm'>\n <div className='flex flex-col items-center gap-6 sm:flex-row sm:justify-between'>\n <div className='flex items-center gap-4'>\n <div className='bg-primary/10 text-primary flex size-12 items-center justify-center rounded-full'>\n <MapPin className='size-6' aria-hidden='true' />\n </div>\n <div className='text-start'>\n <h4 className='text-lg font-medium'>{storeLocator.title}</h4>\n <p className='text-muted-foreground'>{storeLocator.description}</p>\n </div>\n </div>\n {(storeLocator.ctaHref || onLocateStores) && (\n <div>\n {storeLocator.ctaHref ? (\n <Button variant='outline' className='h-9 cursor-pointer px-4 py-2 whitespace-nowrap' asChild>\n <a href={storeLocator.ctaHref}>{storeLocator.ctaLabel}</a>\n </Button>\n ) : (\n <Button\n variant='outline'\n className='h-9 cursor-pointer px-4 py-2 whitespace-nowrap'\n onClick={onLocateStores}\n >\n {storeLocator.ctaLabel}\n </Button>\n )}\n </div>\n )}\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n </div>\n )\n}\n\nfunction PromotionalPresentation({\n title,\n description,\n badge,\n titleAccent,\n deals,\n categories,\n rotationInterval,\n labels,\n onShopNow,\n onCategoryClick,\n}: {\n title: string\n description: string\n badge?: string\n titleAccent?: string\n deals: HeroDeal[]\n categories: HeroCategory[]\n rotationInterval: number\n labels: HeroLabels\n onShopNow?: (item: HeroFeaturedDeal | HeroDeal) => void\n onCategoryClick?: (category: HeroCategory) => void\n}) {\n const reduceMotion = useReducedMotion()\n const [currentDeal, setCurrentDeal] = useState(0)\n\n useEffect(() => {\n if (deals.length <= 1 || reduceMotion) return\n\n const interval = setInterval(() => {\n setCurrentDeal(prev => (prev + 1) % deals.length)\n }, rotationInterval)\n\n return () => clearInterval(interval)\n }, [deals.length, reduceMotion, rotationInterval])\n\n const deal = deals[currentDeal]\n\n return (\n <div className='relative'>\n {deal && (\n <header className='bg-primary text-primary-foreground sticky top-0 z-50 shadow-md'>\n <div className='mx-auto w-full max-w-7xl px-4 py-2 sm:px-6 lg:px-8'>\n <div className='flex items-center justify-center'>\n <div className='flex w-full max-w-3xl items-center justify-center gap-4'>\n <div className='flex items-center gap-2'>\n <Badge\n variant='secondary'\n className='bg-primary-foreground text-primary px-2.5 py-0.5 font-semibold'\n >\n {deal.title}\n </Badge>\n {deal.discount && <span className='font-semibold'>{deal.discount}</span>}\n </div>\n {deal.endTime && (\n <span className='hidden sm:inline'>\n {labels.endsInLabel} {deal.endTime}\n </span>\n )}\n {onShopNow && (\n <Button\n variant='link'\n size='sm'\n className='text-primary-foreground hover:text-primary-foreground/80 ml-auto h-8 cursor-pointer px-3 text-xs'\n onClick={() => onShopNow(deal)}\n >\n {labels.shopNowLabel} <ArrowRight />\n </Button>\n )}\n </div>\n </div>\n </div>\n </header>\n )}\n\n <main className='mx-auto w-full max-w-7xl px-4 py-8 sm:px-6 lg:px-8'>\n <div className='mb-12 text-center'>\n {badge && (\n <div className='relative inline-block'>\n <Badge\n variant='outline'\n className='mb-4 flex h-auto items-center rounded-full px-3.5 py-1.5 text-sm font-normal'\n >\n {badge}\n </Badge>\n </div>\n )}\n <h1 className='text-4xl font-bold tracking-tight text-balance sm:text-5xl md:text-6xl'>\n {title}\n {titleAccent && (\n <>\n <br />\n {titleAccent}\n </>\n )}\n </h1>\n <p className='text-muted-foreground mx-auto mt-4 max-w-2xl text-lg'>{description}</p>\n </div>\n\n {categories.length > 0 && (\n <div className='grid gap-4 sm:grid-cols-2 lg:grid-cols-4'>\n {categories.map(category => (\n <Card\n key={category.id}\n className='group relative overflow-hidden py-0 transition-shadow'\n style={{\n transitionDuration: `${MOTION.durationMilliseconds.feedback}ms`,\n transitionTimingFunction: MOTION.cssEasing.standard,\n }}\n >\n {category.image && category.image.trim().length > 0 ? (\n <img\n src={category.image}\n alt={category.imageAlt ?? category.name}\n className='aspect-4/5 size-full object-cover grayscale transition-[filter] hover:grayscale-0'\n width={400}\n height={500}\n loading='lazy'\n style={{\n transitionDuration: `${MOTION.durationMilliseconds.feedback}ms`,\n transitionTimingFunction: MOTION.cssEasing.standard,\n }}\n />\n ) : (\n <div className='bg-muted aspect-4/5 size-full' />\n )}\n <CardContent className='absolute inset-x-0 bottom-0 p-4'>\n <div className='mt-1 flex items-center justify-between'>\n <div>\n <h2 className='text-background dark:text-foreground text-lg font-medium'>{category.name}</h2>\n {category.count && (\n <span className='text-background/80 dark:text-foreground/80 text-sm'>\n {category.count} {labels.productsLabel}\n </span>\n )}\n </div>\n {category.href ? (\n <Button\n variant='secondary'\n size='icon'\n className='h-9 w-9 cursor-pointer rounded-full backdrop-blur-xs'\n aria-label={`${labels.viewLabel} ${category.name}`}\n asChild\n >\n <a href={category.href}>\n <ArrowRight />\n </a>\n </Button>\n ) : onCategoryClick ? (\n <Button\n variant='secondary'\n size='icon'\n className='h-9 w-9 cursor-pointer rounded-full backdrop-blur-xs'\n aria-label={`${labels.viewLabel} ${category.name}`}\n onClick={() => onCategoryClick(category)}\n >\n <ArrowRight />\n </Button>\n ) : null}\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n </main>\n </div>\n )\n}\n\nexport function StorefrontHero({\n title,\n description,\n presentation = 'compact',\n currency,\n products,\n badge,\n titleAccent,\n primaryCta,\n secondaryCta,\n heroImage,\n onSearch,\n departments = [],\n featuredDeals = [],\n storeLocator,\n shippingInfo,\n deals = [],\n categories = [],\n rotationInterval = 3000,\n onAddToCart,\n onBuyNow,\n onSelectColor,\n onDepartmentClick,\n onShopNow,\n onLocateStores,\n onCategoryClick,\n addToCartLabel = 'Agregar al carrito',\n buyNowLabel,\n newLabel = 'Nuevo',\n outOfStockLabel = 'Agotado',\n colorsLabel = 'Colores:',\n discountSuffixLabel = '% OFF',\n searchPlaceholder = 'Buscar productos...',\n searchLabel = 'Buscar',\n featuredDescription,\n shopNowLabel = 'Comprar ahora',\n endsInLabel = 'Termina en',\n productsLabel = 'productos',\n viewLabel = 'Ver',\n}: StorefrontHeroProps) {\n // Presence-based, never label-language based: a host-supplied custom action\n // label is a purchase affordance that must be handler-gated, while the\n // block's own default label is a non-purchase detail affordance that may\n // render without a handler (preserving the accepted default detail).\n const resolvedBuyNowLabel = buyNowLabel ?? 'Ver producto'\n const hasCustomBuyNowLabel = buyNowLabel !== undefined\n const labels: HeroLabels = {\n addToCartLabel,\n buyNowLabel: resolvedBuyNowLabel,\n newLabel,\n outOfStockLabel,\n colorsLabel,\n discountSuffixLabel,\n searchPlaceholder,\n searchLabel,\n featuredDescription,\n shopNowLabel,\n endsInLabel,\n productsLabel,\n viewLabel,\n }\n\n if (presentation === 'showcase') {\n return (\n <ShowcasePresentation\n title={title}\n description={description}\n products={products}\n badge={badge}\n primaryCta={primaryCta}\n secondaryCta={secondaryCta}\n currency={currency}\n labels={labels}\n onSearch={onSearch}\n onBuyNow={onBuyNow}\n rotationInterval={rotationInterval}\n />\n )\n }\n\n if (presentation === 'editorial') {\n return (\n <EditorialPresentation\n title={title}\n description={description}\n badge={badge}\n titleAccent={titleAccent}\n primaryCta={primaryCta}\n secondaryCta={secondaryCta}\n shippingInfo={shippingInfo}\n departments={departments}\n featuredDeals={featuredDeals}\n storeLocator={storeLocator}\n currency={currency}\n labels={labels}\n onDepartmentClick={onDepartmentClick}\n onShopNow={onShopNow}\n onLocateStores={onLocateStores}\n />\n )\n }\n\n if (presentation === 'promotional') {\n return (\n <PromotionalPresentation\n title={title}\n description={description}\n badge={badge}\n titleAccent={titleAccent}\n deals={deals}\n categories={categories}\n rotationInterval={rotationInterval}\n labels={labels}\n onShopNow={onShopNow}\n onCategoryClick={onCategoryClick}\n />\n )\n }\n\n return (\n <CompactPresentation\n title={title}\n description={description}\n products={products}\n badge={badge}\n titleAccent={titleAccent}\n primaryCta={primaryCta}\n secondaryCta={secondaryCta}\n heroImage={heroImage}\n currency={currency}\n labels={labels}\n onAddToCart={onAddToCart}\n onBuyNow={onBuyNow}\n onSelectColor={onSelectColor}\n hasCustomBuyNowLabel={hasCustomBuyNowLabel}\n />\n )\n}\n\nexport default StorefrontHero\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"banner-1.d.ts","sourceRoot":"","sources":["../../../../src/blocks/marketing/banners/banner-1.tsx"],"names":[],"mappings":"AAUA,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,MAAM,CAAA;AAEzC,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,KAAK,CAAC,EAAE,YAAY,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,uFAAuF;IACvF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,+GAA+G;IAC/G,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;IACvB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAID,wBAAgB,OAAO,CAAC,EACtB,KAAa,EACb,KAAK,EACL,OAAO,EACP,IAAI,EACJ,SAAS,EACT,OAAO,EACP,SAAS,EACT,UAAU,EACV,SAAS,GACV,EAAE,YAAY,sCA0Id;AAED,eAAe,OAAO,CAAA"}
1
+ {"version":3,"file":"banner-1.d.ts","sourceRoot":"","sources":["../../../../src/blocks/marketing/banners/banner-1.tsx"],"names":[],"mappings":"AAUA,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,MAAM,CAAA;AAEzC,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,KAAK,CAAC,EAAE,YAAY,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,uFAAuF;IACvF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,+GAA+G;IAC/G,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;IACvB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAID,wBAAgB,OAAO,CAAC,EACtB,KAAa,EACb,KAAK,EACL,OAAO,EACP,IAAI,EACJ,SAAS,EACT,OAAO,EACP,SAAS,EACT,UAAU,EACV,SAAS,GACV,EAAE,YAAY,sCA+Hd;AAED,eAAe,OAAO,CAAA"}
@@ -114,33 +114,21 @@ function Banner1({
114
114
  }
115
115
  ) : null,
116
116
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "min-w-0 flex-1 truncate text-sm", children: message }),
117
- onCtaClick ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "relative inline-flex", children: [
118
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
119
- import_react2.motion.span,
120
- {
121
- "aria-hidden": "true",
122
- className: "pointer-events-none absolute inset-0 rounded-md ring-2 ring-background/70",
123
- initial: { scale: 1, opacity: 0.7 },
124
- animate: reduceMotion ? { scale: 1, opacity: 0 } : { scale: [1, 1.35], opacity: [0.7, 0] },
125
- transition: { duration: 1.8, repeat: Infinity, ease: "easeOut", repeatDelay: 0.4 }
126
- }
127
- ),
128
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
129
- import_button.Button,
130
- {
131
- type: "button",
132
- variant: "secondary",
133
- size: "sm",
134
- onClick: onCtaClick,
135
- className: "shrink-0",
136
- children: [
137
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "hidden sm:inline", children: linkLabel }),
138
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sr-only sm:hidden", children: linkLabel }),
139
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowRight, { className: "size-3.5", "aria-hidden": "true" })
140
- ]
141
- }
142
- )
143
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
117
+ onCtaClick ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "relative inline-flex", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
118
+ import_button.Button,
119
+ {
120
+ type: "button",
121
+ variant: "secondary",
122
+ size: "sm",
123
+ onClick: onCtaClick,
124
+ className: "shrink-0",
125
+ children: [
126
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "hidden sm:inline", children: linkLabel }),
127
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sr-only sm:hidden", children: linkLabel }),
128
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowRight, { className: "size-3.5", "aria-hidden": "true" })
129
+ ]
130
+ }
131
+ ) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
144
132
  "a",
145
133
  {
146
134
  href,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/blocks/marketing/banners/banner-1.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useState } from 'react'\nimport { motion, useReducedMotion } from 'motion/react'\nimport { ArrowRight, X } from 'lucide-react'\nimport { Avatar, AvatarFallback, AvatarImage } from '../../../ui/avatar'\nimport { Badge } from '../../../ui/badge'\nimport { Button } from '../../../ui/button'\nimport { AvatarGroup } from './avatar-group'\n\nexport type Banner1Shape = 'bar' | 'pill'\n\nexport interface Banner1Props {\n /**\n * 'bar' — full-width strip above the header (the default).\n * 'pill' — floating rounded card pinned to the bottom of the viewport, with an avatar stack.\n */\n shape?: Banner1Shape\n badge?: string\n message: string\n href: string\n linkLabel: string\n /** Used by the 'pill' shape only; decorative avatars of the announcement's authors. */\n avatars?: string[]\n /**\n * 'bar' only. When true, the inner content spans the full width of its parent\n * (skips the centered `max-w-7xl` container) so badge/message/CTA reach the edges.\n */\n fullWidth?: boolean\n /** Fired when the user clicks the banner CTA. When provided, the CTA renders as a button instead of a link. */\n onCtaClick?: () => void\n /** Fired when the user dismisses the banner. */\n onDismiss?: () => void\n}\n\ntype Visibility = 'visible' | 'closing' | 'closed'\n\nexport function Banner1({\n shape = 'bar',\n badge,\n message,\n href,\n linkLabel,\n avatars,\n fullWidth,\n onCtaClick,\n onDismiss,\n}: Banner1Props) {\n const [visibility, setVisibility] = useState<Visibility>('visible')\n const reduceMotion = useReducedMotion()\n\n useEffect(() => {\n if (visibility !== 'closing') {\n return\n }\n\n const timer = window.setTimeout(() => setVisibility('closed'), 200)\n return () => window.clearTimeout(timer)\n }, [visibility])\n\n const dismiss = () => {\n onDismiss?.()\n setVisibility(reduceMotion ? 'closed' : 'closing')\n }\n\n if (visibility === 'closed') {\n return null\n }\n\n const closing = visibility === 'closing'\n\n if (shape === 'pill') {\n return (\n <div\n className={`fixed inset-x-4 bottom-4 z-50 transition-all duration-200 ease-out motion-reduce:transition-none sm:inset-x-auto sm:left-1/2 sm:-translate-x-1/2 ${\n closing ? 'translate-y-2 opacity-0' : 'opacity-100'\n }`}\n >\n <div className='bg-background/95 border-border flex items-center gap-3 rounded-full border py-2 pr-2 pl-3 shadow-lg backdrop-blur sm:pl-4'>\n {avatars && avatars.length > 0 && (\n <AvatarGroup aria-hidden='true'>\n {avatars.map(src => (\n <Avatar key={src} className='ring-background size-6 ring-2'>\n <AvatarImage src={src || undefined} alt='' />\n <AvatarFallback />\n </Avatar>\n ))}\n </AvatarGroup>\n )}\n <p className='truncate text-sm'>{message}</p>\n <a\n href={href}\n className='hover:text-foreground text-muted-foreground focus-visible:ring-ring hidden shrink-0 items-center gap-1 rounded-sm text-sm font-medium transition-colors duration-150 focus-visible:ring-2 focus-visible:outline-none sm:inline-flex'\n >\n {linkLabel}\n <ArrowRight className='size-3.5' />\n </a>\n <Button\n variant='ghost'\n size='icon'\n className='size-8 shrink-0 rounded-full'\n aria-label='Dismiss announcement'\n onClick={dismiss}\n >\n <X className='size-4' />\n </Button>\n </div>\n </div>\n )\n }\n\n return (\n <div\n className={`grid transition-all duration-200 ease-out motion-reduce:transition-none ${\n closing ? 'grid-rows-[0fr] opacity-0' : 'grid-rows-[1fr] opacity-100'\n }`}\n >\n <div className='overflow-hidden'>\n <div className='bg-primary text-primary-foreground'>\n <div\n className={`flex w-full items-center gap-3 px-4 py-2.5 sm:px-6 lg:px-8 ${\n fullWidth ? '' : 'mx-auto max-w-7xl'\n }`}\n >\n {badge ? (\n <Badge\n variant='secondary'\n className='hidden shrink-0 rounded-full px-2 py-0 text-xs font-semibold sm:inline-flex'\n >\n {badge}\n </Badge>\n ) : null}\n\n <p className='min-w-0 flex-1 truncate text-sm'>{message}</p>\n\n {onCtaClick ? (\n <span className='relative inline-flex'>\n <motion.span\n aria-hidden='true'\n className='pointer-events-none absolute inset-0 rounded-md ring-2 ring-background/70'\n initial={{ scale: 1, opacity: 0.7 }}\n animate={\n reduceMotion\n ? { scale: 1, opacity: 0 }\n : { scale: [1, 1.35], opacity: [0.7, 0] }\n }\n transition={{ duration: 1.8, repeat: Infinity, ease: 'easeOut', repeatDelay: 0.4 }}\n />\n <Button\n type='button'\n variant='secondary'\n size='sm'\n onClick={onCtaClick}\n className='shrink-0'\n >\n <span className='hidden sm:inline'>{linkLabel}</span>\n <span className='sr-only sm:hidden'>{linkLabel}</span>\n <ArrowRight className='size-3.5' aria-hidden='true' />\n </Button>\n </span>\n ) : (\n <a\n href={href}\n className='focus-visible:ring-ring inline-flex shrink-0 items-center gap-1 rounded-sm text-sm font-medium underline-offset-4 transition-opacity duration-150 hover:opacity-80 hover:underline focus-visible:ring-2 focus-visible:outline-none'\n >\n <span className='hidden sm:inline'>{linkLabel}</span>\n <span className='sr-only sm:hidden'>{linkLabel}</span>\n <ArrowRight className='size-3.5' aria-hidden='true' />\n </a>\n )}\n\n <Button\n variant='ghost'\n size='icon'\n className='hover:bg-primary-foreground/10 hover:text-primary-foreground size-8 shrink-0'\n aria-label='Dismiss announcement'\n onClick={dismiss}\n >\n <X className='size-4' />\n </Button>\n </div>\n </div>\n </div>\n </div>\n )\n}\n\nexport default Banner1"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkFgB;AAhFhB,mBAAoC;AACpC,IAAAA,gBAAyC;AACzC,0BAA8B;AAC9B,oBAAoD;AACpD,mBAAsB;AACtB,oBAAuB;AACvB,0BAA4B;AA6BrB,SAAS,QAAQ;AAAA,EACtB,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiB;AACf,QAAM,CAAC,YAAY,aAAa,QAAI,uBAAqB,SAAS;AAClE,QAAM,mBAAe,gCAAiB;AAEtC,8BAAU,MAAM;AACd,QAAI,eAAe,WAAW;AAC5B;AAAA,IACF;AAEA,UAAM,QAAQ,OAAO,WAAW,MAAM,cAAc,QAAQ,GAAG,GAAG;AAClE,WAAO,MAAM,OAAO,aAAa,KAAK;AAAA,EACxC,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,UAAU,MAAM;AACpB,gBAAY;AACZ,kBAAc,eAAe,WAAW,SAAS;AAAA,EACnD;AAEA,MAAI,eAAe,UAAU;AAC3B,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,eAAe;AAE/B,MAAI,UAAU,QAAQ;AACpB,WACE;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,oJACT,UAAU,4BAA4B,aACxC;AAAA,QAEA,uDAAC,SAAI,WAAU,6HACZ;AAAA,qBAAW,QAAQ,SAAS,KAC3B,4CAAC,mCAAY,eAAY,QACtB,kBAAQ,IAAI,SACX,6CAAC,wBAAiB,WAAU,iCAC1B;AAAA,wDAAC,6BAAY,KAAK,OAAO,QAAW,KAAI,IAAG;AAAA,YAC3C,4CAAC,gCAAe;AAAA,eAFL,GAGb,CACD,GACH;AAAA,UAEF,4CAAC,OAAE,WAAU,oBAAoB,mBAAQ;AAAA,UACzC;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cACA,WAAU;AAAA,cAET;AAAA;AAAA,gBACD,4CAAC,kCAAW,WAAU,YAAW;AAAA;AAAA;AAAA,UACnC;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,WAAU;AAAA,cACV,cAAW;AAAA,cACX,SAAS;AAAA,cAET,sDAAC,yBAAE,WAAU,UAAS;AAAA;AAAA,UACxB;AAAA,WACF;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,2EACT,UAAU,8BAA8B,6BAC1C;AAAA,MAEA,sDAAC,SAAI,WAAU,mBACb,sDAAC,SAAI,WAAU,sCACb;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,8DACT,YAAY,KAAK,mBACnB;AAAA,UAEC;AAAA,oBACC;AAAA,cAAC;AAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,WAAU;AAAA,gBAET;AAAA;AAAA,YACH,IACE;AAAA,YAEJ,4CAAC,OAAE,WAAU,mCAAmC,mBAAQ;AAAA,YAEvD,aACC,6CAAC,UAAK,WAAU,wBACd;AAAA;AAAA,gBAAC,qBAAO;AAAA,gBAAP;AAAA,kBACC,eAAY;AAAA,kBACZ,WAAU;AAAA,kBACV,SAAS,EAAE,OAAO,GAAG,SAAS,IAAI;AAAA,kBAClC,SACE,eACI,EAAE,OAAO,GAAG,SAAS,EAAE,IACvB,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE;AAAA,kBAE5C,YAAY,EAAE,UAAU,KAAK,QAAQ,UAAU,MAAM,WAAW,aAAa,IAAI;AAAA;AAAA,cACnF;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,SAAQ;AAAA,kBACR,MAAK;AAAA,kBACL,SAAS;AAAA,kBACT,WAAU;AAAA,kBAEV;AAAA,gEAAC,UAAK,WAAU,oBAAoB,qBAAU;AAAA,oBAC9C,4CAAC,UAAK,WAAU,qBAAqB,qBAAU;AAAA,oBAC/C,4CAAC,kCAAW,WAAU,YAAW,eAAY,QAAO;AAAA;AAAA;AAAA,cACtD;AAAA,eACF,IAEA;AAAA,cAAC;AAAA;AAAA,gBACC;AAAA,gBACA,WAAU;AAAA,gBAEV;AAAA,8DAAC,UAAK,WAAU,oBAAoB,qBAAU;AAAA,kBAC9C,4CAAC,UAAK,WAAU,qBAAqB,qBAAU;AAAA,kBAC/C,4CAAC,kCAAW,WAAU,YAAW,eAAY,QAAO;AAAA;AAAA;AAAA,YACtD;AAAA,YAGF;AAAA,cAAC;AAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,cAAW;AAAA,gBACX,SAAS;AAAA,gBAET,sDAAC,yBAAE,WAAU,UAAS;AAAA;AAAA,YACxB;AAAA;AAAA;AAAA,MACF,GACF,GACF;AAAA;AAAA,EACF;AAEJ;AAEA,IAAO,mBAAQ;","names":["import_react"]}
1
+ {"version":3,"sources":["../../../../src/blocks/marketing/banners/banner-1.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useState } from 'react'\nimport { useReducedMotion } from 'motion/react'\nimport { ArrowRight, X } from 'lucide-react'\nimport { Avatar, AvatarFallback, AvatarImage } from '../../../ui/avatar'\nimport { Badge } from '../../../ui/badge'\nimport { Button } from '../../../ui/button'\nimport { AvatarGroup } from './avatar-group'\n\nexport type Banner1Shape = 'bar' | 'pill'\n\nexport interface Banner1Props {\n /**\n * 'bar' — full-width strip above the header (the default).\n * 'pill' — floating rounded card pinned to the bottom of the viewport, with an avatar stack.\n */\n shape?: Banner1Shape\n badge?: string\n message: string\n href: string\n linkLabel: string\n /** Used by the 'pill' shape only; decorative avatars of the announcement's authors. */\n avatars?: string[]\n /**\n * 'bar' only. When true, the inner content spans the full width of its parent\n * (skips the centered `max-w-7xl` container) so badge/message/CTA reach the edges.\n */\n fullWidth?: boolean\n /** Fired when the user clicks the banner CTA. When provided, the CTA renders as a button instead of a link. */\n onCtaClick?: () => void\n /** Fired when the user dismisses the banner. */\n onDismiss?: () => void\n}\n\ntype Visibility = 'visible' | 'closing' | 'closed'\n\nexport function Banner1({\n shape = 'bar',\n badge,\n message,\n href,\n linkLabel,\n avatars,\n fullWidth,\n onCtaClick,\n onDismiss,\n}: Banner1Props) {\n const [visibility, setVisibility] = useState<Visibility>('visible')\n const reduceMotion = useReducedMotion()\n\n useEffect(() => {\n if (visibility !== 'closing') {\n return\n }\n\n const timer = window.setTimeout(() => setVisibility('closed'), 200)\n return () => window.clearTimeout(timer)\n }, [visibility])\n\n const dismiss = () => {\n onDismiss?.()\n setVisibility(reduceMotion ? 'closed' : 'closing')\n }\n\n if (visibility === 'closed') {\n return null\n }\n\n const closing = visibility === 'closing'\n\n if (shape === 'pill') {\n return (\n <div\n className={`fixed inset-x-4 bottom-4 z-50 transition-all duration-200 ease-out motion-reduce:transition-none sm:inset-x-auto sm:left-1/2 sm:-translate-x-1/2 ${\n closing ? 'translate-y-2 opacity-0' : 'opacity-100'\n }`}\n >\n <div className='bg-background/95 border-border flex items-center gap-3 rounded-full border py-2 pr-2 pl-3 shadow-lg backdrop-blur sm:pl-4'>\n {avatars && avatars.length > 0 && (\n <AvatarGroup aria-hidden='true'>\n {avatars.map(src => (\n <Avatar key={src} className='ring-background size-6 ring-2'>\n <AvatarImage src={src || undefined} alt='' />\n <AvatarFallback />\n </Avatar>\n ))}\n </AvatarGroup>\n )}\n <p className='truncate text-sm'>{message}</p>\n <a\n href={href}\n className='hover:text-foreground text-muted-foreground focus-visible:ring-ring hidden shrink-0 items-center gap-1 rounded-sm text-sm font-medium transition-colors duration-150 focus-visible:ring-2 focus-visible:outline-none sm:inline-flex'\n >\n {linkLabel}\n <ArrowRight className='size-3.5' />\n </a>\n <Button\n variant='ghost'\n size='icon'\n className='size-8 shrink-0 rounded-full'\n aria-label='Dismiss announcement'\n onClick={dismiss}\n >\n <X className='size-4' />\n </Button>\n </div>\n </div>\n )\n }\n\n return (\n <div\n className={`grid transition-all duration-200 ease-out motion-reduce:transition-none ${\n closing ? 'grid-rows-[0fr] opacity-0' : 'grid-rows-[1fr] opacity-100'\n }`}\n >\n <div className='overflow-hidden'>\n <div className='bg-primary text-primary-foreground'>\n <div\n className={`flex w-full items-center gap-3 px-4 py-2.5 sm:px-6 lg:px-8 ${\n fullWidth ? '' : 'mx-auto max-w-7xl'\n }`}\n >\n {badge ? (\n <Badge\n variant='secondary'\n className='hidden shrink-0 rounded-full px-2 py-0 text-xs font-semibold sm:inline-flex'\n >\n {badge}\n </Badge>\n ) : null}\n\n <p className='min-w-0 flex-1 truncate text-sm'>{message}</p>\n\n {onCtaClick ? (\n <span className='relative inline-flex'>\n <Button\n type='button'\n variant='secondary'\n size='sm'\n onClick={onCtaClick}\n className='shrink-0'\n >\n <span className='hidden sm:inline'>{linkLabel}</span>\n <span className='sr-only sm:hidden'>{linkLabel}</span>\n <ArrowRight className='size-3.5' aria-hidden='true' />\n </Button>\n </span>\n ) : (\n <a\n href={href}\n className='focus-visible:ring-ring inline-flex shrink-0 items-center gap-1 rounded-sm text-sm font-medium underline-offset-4 transition-opacity duration-150 hover:opacity-80 hover:underline focus-visible:ring-2 focus-visible:outline-none'\n >\n <span className='hidden sm:inline'>{linkLabel}</span>\n <span className='sr-only sm:hidden'>{linkLabel}</span>\n <ArrowRight className='size-3.5' aria-hidden='true' />\n </a>\n )}\n\n <Button\n variant='ghost'\n size='icon'\n className='hover:bg-primary-foreground/10 hover:text-primary-foreground size-8 shrink-0'\n aria-label='Dismiss announcement'\n onClick={dismiss}\n >\n <X className='size-4' />\n </Button>\n </div>\n </div>\n </div>\n </div>\n )\n}\n\nexport default Banner1\n"],"mappings":"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","names":["import_react"]}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useState } from "react";
4
- import { motion, useReducedMotion } from "motion/react";
4
+ import { useReducedMotion } from "motion/react";
5
5
  import { ArrowRight, X } from "lucide-react";
6
6
  import { Avatar, AvatarFallback, AvatarImage } from "../../../ui/avatar.mjs";
7
7
  import { Badge } from "../../../ui/badge.mjs";
@@ -90,33 +90,21 @@ function Banner1({
90
90
  }
91
91
  ) : null,
92
92
  /* @__PURE__ */ jsx("p", { className: "min-w-0 flex-1 truncate text-sm", children: message }),
93
- onCtaClick ? /* @__PURE__ */ jsxs("span", { className: "relative inline-flex", children: [
94
- /* @__PURE__ */ jsx(
95
- motion.span,
96
- {
97
- "aria-hidden": "true",
98
- className: "pointer-events-none absolute inset-0 rounded-md ring-2 ring-background/70",
99
- initial: { scale: 1, opacity: 0.7 },
100
- animate: reduceMotion ? { scale: 1, opacity: 0 } : { scale: [1, 1.35], opacity: [0.7, 0] },
101
- transition: { duration: 1.8, repeat: Infinity, ease: "easeOut", repeatDelay: 0.4 }
102
- }
103
- ),
104
- /* @__PURE__ */ jsxs(
105
- Button,
106
- {
107
- type: "button",
108
- variant: "secondary",
109
- size: "sm",
110
- onClick: onCtaClick,
111
- className: "shrink-0",
112
- children: [
113
- /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: linkLabel }),
114
- /* @__PURE__ */ jsx("span", { className: "sr-only sm:hidden", children: linkLabel }),
115
- /* @__PURE__ */ jsx(ArrowRight, { className: "size-3.5", "aria-hidden": "true" })
116
- ]
117
- }
118
- )
119
- ] }) : /* @__PURE__ */ jsxs(
93
+ onCtaClick ? /* @__PURE__ */ jsx("span", { className: "relative inline-flex", children: /* @__PURE__ */ jsxs(
94
+ Button,
95
+ {
96
+ type: "button",
97
+ variant: "secondary",
98
+ size: "sm",
99
+ onClick: onCtaClick,
100
+ className: "shrink-0",
101
+ children: [
102
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: linkLabel }),
103
+ /* @__PURE__ */ jsx("span", { className: "sr-only sm:hidden", children: linkLabel }),
104
+ /* @__PURE__ */ jsx(ArrowRight, { className: "size-3.5", "aria-hidden": "true" })
105
+ ]
106
+ }
107
+ ) }) : /* @__PURE__ */ jsxs(
120
108
  "a",
121
109
  {
122
110
  href,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/blocks/marketing/banners/banner-1.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useState } from 'react'\nimport { motion, useReducedMotion } from 'motion/react'\nimport { ArrowRight, X } from 'lucide-react'\nimport { Avatar, AvatarFallback, AvatarImage } from '../../../ui/avatar'\nimport { Badge } from '../../../ui/badge'\nimport { Button } from '../../../ui/button'\nimport { AvatarGroup } from './avatar-group'\n\nexport type Banner1Shape = 'bar' | 'pill'\n\nexport interface Banner1Props {\n /**\n * 'bar' — full-width strip above the header (the default).\n * 'pill' — floating rounded card pinned to the bottom of the viewport, with an avatar stack.\n */\n shape?: Banner1Shape\n badge?: string\n message: string\n href: string\n linkLabel: string\n /** Used by the 'pill' shape only; decorative avatars of the announcement's authors. */\n avatars?: string[]\n /**\n * 'bar' only. When true, the inner content spans the full width of its parent\n * (skips the centered `max-w-7xl` container) so badge/message/CTA reach the edges.\n */\n fullWidth?: boolean\n /** Fired when the user clicks the banner CTA. When provided, the CTA renders as a button instead of a link. */\n onCtaClick?: () => void\n /** Fired when the user dismisses the banner. */\n onDismiss?: () => void\n}\n\ntype Visibility = 'visible' | 'closing' | 'closed'\n\nexport function Banner1({\n shape = 'bar',\n badge,\n message,\n href,\n linkLabel,\n avatars,\n fullWidth,\n onCtaClick,\n onDismiss,\n}: Banner1Props) {\n const [visibility, setVisibility] = useState<Visibility>('visible')\n const reduceMotion = useReducedMotion()\n\n useEffect(() => {\n if (visibility !== 'closing') {\n return\n }\n\n const timer = window.setTimeout(() => setVisibility('closed'), 200)\n return () => window.clearTimeout(timer)\n }, [visibility])\n\n const dismiss = () => {\n onDismiss?.()\n setVisibility(reduceMotion ? 'closed' : 'closing')\n }\n\n if (visibility === 'closed') {\n return null\n }\n\n const closing = visibility === 'closing'\n\n if (shape === 'pill') {\n return (\n <div\n className={`fixed inset-x-4 bottom-4 z-50 transition-all duration-200 ease-out motion-reduce:transition-none sm:inset-x-auto sm:left-1/2 sm:-translate-x-1/2 ${\n closing ? 'translate-y-2 opacity-0' : 'opacity-100'\n }`}\n >\n <div className='bg-background/95 border-border flex items-center gap-3 rounded-full border py-2 pr-2 pl-3 shadow-lg backdrop-blur sm:pl-4'>\n {avatars && avatars.length > 0 && (\n <AvatarGroup aria-hidden='true'>\n {avatars.map(src => (\n <Avatar key={src} className='ring-background size-6 ring-2'>\n <AvatarImage src={src || undefined} alt='' />\n <AvatarFallback />\n </Avatar>\n ))}\n </AvatarGroup>\n )}\n <p className='truncate text-sm'>{message}</p>\n <a\n href={href}\n className='hover:text-foreground text-muted-foreground focus-visible:ring-ring hidden shrink-0 items-center gap-1 rounded-sm text-sm font-medium transition-colors duration-150 focus-visible:ring-2 focus-visible:outline-none sm:inline-flex'\n >\n {linkLabel}\n <ArrowRight className='size-3.5' />\n </a>\n <Button\n variant='ghost'\n size='icon'\n className='size-8 shrink-0 rounded-full'\n aria-label='Dismiss announcement'\n onClick={dismiss}\n >\n <X className='size-4' />\n </Button>\n </div>\n </div>\n )\n }\n\n return (\n <div\n className={`grid transition-all duration-200 ease-out motion-reduce:transition-none ${\n closing ? 'grid-rows-[0fr] opacity-0' : 'grid-rows-[1fr] opacity-100'\n }`}\n >\n <div className='overflow-hidden'>\n <div className='bg-primary text-primary-foreground'>\n <div\n className={`flex w-full items-center gap-3 px-4 py-2.5 sm:px-6 lg:px-8 ${\n fullWidth ? '' : 'mx-auto max-w-7xl'\n }`}\n >\n {badge ? (\n <Badge\n variant='secondary'\n className='hidden shrink-0 rounded-full px-2 py-0 text-xs font-semibold sm:inline-flex'\n >\n {badge}\n </Badge>\n ) : null}\n\n <p className='min-w-0 flex-1 truncate text-sm'>{message}</p>\n\n {onCtaClick ? (\n <span className='relative inline-flex'>\n <motion.span\n aria-hidden='true'\n className='pointer-events-none absolute inset-0 rounded-md ring-2 ring-background/70'\n initial={{ scale: 1, opacity: 0.7 }}\n animate={\n reduceMotion\n ? { scale: 1, opacity: 0 }\n : { scale: [1, 1.35], opacity: [0.7, 0] }\n }\n transition={{ duration: 1.8, repeat: Infinity, ease: 'easeOut', repeatDelay: 0.4 }}\n />\n <Button\n type='button'\n variant='secondary'\n size='sm'\n onClick={onCtaClick}\n className='shrink-0'\n >\n <span className='hidden sm:inline'>{linkLabel}</span>\n <span className='sr-only sm:hidden'>{linkLabel}</span>\n <ArrowRight className='size-3.5' aria-hidden='true' />\n </Button>\n </span>\n ) : (\n <a\n href={href}\n className='focus-visible:ring-ring inline-flex shrink-0 items-center gap-1 rounded-sm text-sm font-medium underline-offset-4 transition-opacity duration-150 hover:opacity-80 hover:underline focus-visible:ring-2 focus-visible:outline-none'\n >\n <span className='hidden sm:inline'>{linkLabel}</span>\n <span className='sr-only sm:hidden'>{linkLabel}</span>\n <ArrowRight className='size-3.5' aria-hidden='true' />\n </a>\n )}\n\n <Button\n variant='ghost'\n size='icon'\n className='hover:bg-primary-foreground/10 hover:text-primary-foreground size-8 shrink-0'\n aria-label='Dismiss announcement'\n onClick={dismiss}\n >\n <X className='size-4' />\n </Button>\n </div>\n </div>\n </div>\n </div>\n )\n}\n\nexport default Banner1"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/blocks/marketing/banners/banner-1.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useState } from 'react'\nimport { useReducedMotion } from 'motion/react'\nimport { ArrowRight, X } from 'lucide-react'\nimport { Avatar, AvatarFallback, AvatarImage } from '../../../ui/avatar'\nimport { Badge } from '../../../ui/badge'\nimport { Button } from '../../../ui/button'\nimport { AvatarGroup } from './avatar-group'\n\nexport type Banner1Shape = 'bar' | 'pill'\n\nexport interface Banner1Props {\n /**\n * 'bar' — full-width strip above the header (the default).\n * 'pill' — floating rounded card pinned to the bottom of the viewport, with an avatar stack.\n */\n shape?: Banner1Shape\n badge?: string\n message: string\n href: string\n linkLabel: string\n /** Used by the 'pill' shape only; decorative avatars of the announcement's authors. */\n avatars?: string[]\n /**\n * 'bar' only. When true, the inner content spans the full width of its parent\n * (skips the centered `max-w-7xl` container) so badge/message/CTA reach the edges.\n */\n fullWidth?: boolean\n /** Fired when the user clicks the banner CTA. When provided, the CTA renders as a button instead of a link. */\n onCtaClick?: () => void\n /** Fired when the user dismisses the banner. */\n onDismiss?: () => void\n}\n\ntype Visibility = 'visible' | 'closing' | 'closed'\n\nexport function Banner1({\n shape = 'bar',\n badge,\n message,\n href,\n linkLabel,\n avatars,\n fullWidth,\n onCtaClick,\n onDismiss,\n}: Banner1Props) {\n const [visibility, setVisibility] = useState<Visibility>('visible')\n const reduceMotion = useReducedMotion()\n\n useEffect(() => {\n if (visibility !== 'closing') {\n return\n }\n\n const timer = window.setTimeout(() => setVisibility('closed'), 200)\n return () => window.clearTimeout(timer)\n }, [visibility])\n\n const dismiss = () => {\n onDismiss?.()\n setVisibility(reduceMotion ? 'closed' : 'closing')\n }\n\n if (visibility === 'closed') {\n return null\n }\n\n const closing = visibility === 'closing'\n\n if (shape === 'pill') {\n return (\n <div\n className={`fixed inset-x-4 bottom-4 z-50 transition-all duration-200 ease-out motion-reduce:transition-none sm:inset-x-auto sm:left-1/2 sm:-translate-x-1/2 ${\n closing ? 'translate-y-2 opacity-0' : 'opacity-100'\n }`}\n >\n <div className='bg-background/95 border-border flex items-center gap-3 rounded-full border py-2 pr-2 pl-3 shadow-lg backdrop-blur sm:pl-4'>\n {avatars && avatars.length > 0 && (\n <AvatarGroup aria-hidden='true'>\n {avatars.map(src => (\n <Avatar key={src} className='ring-background size-6 ring-2'>\n <AvatarImage src={src || undefined} alt='' />\n <AvatarFallback />\n </Avatar>\n ))}\n </AvatarGroup>\n )}\n <p className='truncate text-sm'>{message}</p>\n <a\n href={href}\n className='hover:text-foreground text-muted-foreground focus-visible:ring-ring hidden shrink-0 items-center gap-1 rounded-sm text-sm font-medium transition-colors duration-150 focus-visible:ring-2 focus-visible:outline-none sm:inline-flex'\n >\n {linkLabel}\n <ArrowRight className='size-3.5' />\n </a>\n <Button\n variant='ghost'\n size='icon'\n className='size-8 shrink-0 rounded-full'\n aria-label='Dismiss announcement'\n onClick={dismiss}\n >\n <X className='size-4' />\n </Button>\n </div>\n </div>\n )\n }\n\n return (\n <div\n className={`grid transition-all duration-200 ease-out motion-reduce:transition-none ${\n closing ? 'grid-rows-[0fr] opacity-0' : 'grid-rows-[1fr] opacity-100'\n }`}\n >\n <div className='overflow-hidden'>\n <div className='bg-primary text-primary-foreground'>\n <div\n className={`flex w-full items-center gap-3 px-4 py-2.5 sm:px-6 lg:px-8 ${\n fullWidth ? '' : 'mx-auto max-w-7xl'\n }`}\n >\n {badge ? (\n <Badge\n variant='secondary'\n className='hidden shrink-0 rounded-full px-2 py-0 text-xs font-semibold sm:inline-flex'\n >\n {badge}\n </Badge>\n ) : null}\n\n <p className='min-w-0 flex-1 truncate text-sm'>{message}</p>\n\n {onCtaClick ? (\n <span className='relative inline-flex'>\n <Button\n type='button'\n variant='secondary'\n size='sm'\n onClick={onCtaClick}\n className='shrink-0'\n >\n <span className='hidden sm:inline'>{linkLabel}</span>\n <span className='sr-only sm:hidden'>{linkLabel}</span>\n <ArrowRight className='size-3.5' aria-hidden='true' />\n </Button>\n </span>\n ) : (\n <a\n href={href}\n className='focus-visible:ring-ring inline-flex shrink-0 items-center gap-1 rounded-sm text-sm font-medium underline-offset-4 transition-opacity duration-150 hover:opacity-80 hover:underline focus-visible:ring-2 focus-visible:outline-none'\n >\n <span className='hidden sm:inline'>{linkLabel}</span>\n <span className='sr-only sm:hidden'>{linkLabel}</span>\n <ArrowRight className='size-3.5' aria-hidden='true' />\n </a>\n )}\n\n <Button\n variant='ghost'\n size='icon'\n className='hover:bg-primary-foreground/10 hover:text-primary-foreground size-8 shrink-0'\n aria-label='Dismiss announcement'\n onClick={dismiss}\n >\n <X className='size-4' />\n </Button>\n </div>\n </div>\n </div>\n </div>\n )\n}\n\nexport default Banner1\n"],"mappings":";AAkFgB,SACE,KADF;AAhFhB,SAAS,WAAW,gBAAgB;AACpC,SAAS,wBAAwB;AACjC,SAAS,YAAY,SAAS;AAC9B,SAAS,QAAQ,gBAAgB,mBAAmB;AACpD,SAAS,aAAa;AACtB,SAAS,cAAc;AACvB,SAAS,mBAAmB;AA6BrB,SAAS,QAAQ;AAAA,EACtB,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiB;AACf,QAAM,CAAC,YAAY,aAAa,IAAI,SAAqB,SAAS;AAClE,QAAM,eAAe,iBAAiB;AAEtC,YAAU,MAAM;AACd,QAAI,eAAe,WAAW;AAC5B;AAAA,IACF;AAEA,UAAM,QAAQ,OAAO,WAAW,MAAM,cAAc,QAAQ,GAAG,GAAG;AAClE,WAAO,MAAM,OAAO,aAAa,KAAK;AAAA,EACxC,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,UAAU,MAAM;AACpB,gBAAY;AACZ,kBAAc,eAAe,WAAW,SAAS;AAAA,EACnD;AAEA,MAAI,eAAe,UAAU;AAC3B,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,eAAe;AAE/B,MAAI,UAAU,QAAQ;AACpB,WACE;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,oJACT,UAAU,4BAA4B,aACxC;AAAA,QAEA,+BAAC,SAAI,WAAU,6HACZ;AAAA,qBAAW,QAAQ,SAAS,KAC3B,oBAAC,eAAY,eAAY,QACtB,kBAAQ,IAAI,SACX,qBAAC,UAAiB,WAAU,iCAC1B;AAAA,gCAAC,eAAY,KAAK,OAAO,QAAW,KAAI,IAAG;AAAA,YAC3C,oBAAC,kBAAe;AAAA,eAFL,GAGb,CACD,GACH;AAAA,UAEF,oBAAC,OAAE,WAAU,oBAAoB,mBAAQ;AAAA,UACzC;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cACA,WAAU;AAAA,cAET;AAAA;AAAA,gBACD,oBAAC,cAAW,WAAU,YAAW;AAAA;AAAA;AAAA,UACnC;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,WAAU;AAAA,cACV,cAAW;AAAA,cACX,SAAS;AAAA,cAET,8BAAC,KAAE,WAAU,UAAS;AAAA;AAAA,UACxB;AAAA,WACF;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,2EACT,UAAU,8BAA8B,6BAC1C;AAAA,MAEA,8BAAC,SAAI,WAAU,mBACb,8BAAC,SAAI,WAAU,sCACb;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,8DACT,YAAY,KAAK,mBACnB;AAAA,UAEC;AAAA,oBACC;AAAA,cAAC;AAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,WAAU;AAAA,gBAET;AAAA;AAAA,YACH,IACE;AAAA,YAEJ,oBAAC,OAAE,WAAU,mCAAmC,mBAAQ;AAAA,YAEvD,aACC,oBAAC,UAAK,WAAU,wBACd;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAQ;AAAA,gBACR,MAAK;AAAA,gBACL,SAAS;AAAA,gBACT,WAAU;AAAA,gBAEV;AAAA,sCAAC,UAAK,WAAU,oBAAoB,qBAAU;AAAA,kBAC9C,oBAAC,UAAK,WAAU,qBAAqB,qBAAU;AAAA,kBAC/C,oBAAC,cAAW,WAAU,YAAW,eAAY,QAAO;AAAA;AAAA;AAAA,YACtD,GACF,IAEA;AAAA,cAAC;AAAA;AAAA,gBACC;AAAA,gBACA,WAAU;AAAA,gBAEV;AAAA,sCAAC,UAAK,WAAU,oBAAoB,qBAAU;AAAA,kBAC9C,oBAAC,UAAK,WAAU,qBAAqB,qBAAU;AAAA,kBAC/C,oBAAC,cAAW,WAAU,YAAW,eAAY,QAAO;AAAA;AAAA;AAAA,YACtD;AAAA,YAGF;AAAA,cAAC;AAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,cAAW;AAAA,gBACX,SAAS;AAAA,gBAET,8BAAC,KAAE,WAAU,UAAS;AAAA;AAAA,YACxB;AAAA;AAAA;AAAA,MACF,GACF,GACF;AAAA;AAAA,EACF;AAEJ;AAEA,IAAO,mBAAQ;","names":[]}
package/dist/index.d.ts CHANGED
@@ -72,14 +72,20 @@ export type { ShoppingCartProps, ShoppingCartPromotion, ShoppingCartPresentation
72
72
  export { default as StoreContainer1 } from './blocks/e-commerce/store-containers/store-container-1';
73
73
  export type { StoreContainer1Props } from './blocks/e-commerce/store-containers/store-container-1';
74
74
  export { default as Checkout } from './blocks/e-commerce/checkout-forms/checkout';
75
- export type { CheckoutProps, CheckoutValues, CheckoutPresentation, CheckoutStepId, CheckoutLabels, CheckoutValuesFieldErrors, CheckoutFieldDescriptions, CheckoutChangeHandler, CheckoutOrderSummary, CheckoutOrderLine, CheckoutTotals, CheckoutTotalsState, CheckoutCountryOption, CheckoutShippingOption, } from './blocks/e-commerce/checkout-forms/checkout';
75
+ export type { CheckoutProps, CheckoutPresentation, CheckoutStepId, CheckoutLabels, CheckoutFieldErrors, CheckoutFieldDescriptions, CheckoutContactChangeHandler, CheckoutAddressChangeHandler, CheckoutAvailability, CheckoutAvailabilityStatus, CheckoutOrderSummary, CheckoutOrderLine, CheckoutTotals, CheckoutTotalsState, CheckoutCountryOption, CheckoutAddressOption, CheckoutAddressLevel, CheckoutAddressValues, CheckoutContactValues, CheckoutCustomerIdentity, CheckoutSavedAddress, CheckoutSavedAddressState, CheckoutLocationOptions, CheckoutReadState, CheckoutShippingOption, CheckoutShippingGroup, CheckoutShippingGroupItem, CheckoutAdjustmentPayment, CheckoutInterruption, CheckoutInterruptionAction, CheckoutInterruptionKind, CheckoutSubmission, } from './blocks/e-commerce/checkout-forms/checkout';
76
76
  export { default as CheckoutConfirmation } from './blocks/e-commerce/checkout-forms/checkout-confirmation';
77
77
  export type { CheckoutConfirmationProps, FulfilmentStage, FulfilmentStageDetail, Order, OrderLine as CheckoutConfirmationOrderLine, OrderAddress, OrderTotals, } from './blocks/e-commerce/checkout-forms/checkout-confirmation';
78
- export type { CheckoutFieldError, CheckoutFieldErrors } from './blocks/e-commerce/checkout-forms/checkout-form-types';
78
+ export type { CheckoutFieldError } from './blocks/e-commerce/checkout-forms/checkout-form-types';
79
79
  export { OrderHistory } from './blocks/e-commerce/order-history/order-history';
80
80
  export { OrderLine } from './blocks/e-commerce/order-history/order-line';
81
81
  export type { OrderHistoryLabels, OrderHistoryOrder, OrderHistoryPresentation, OrderHistoryProps, OrderHistoryStatus, OrderHistoryStatusTone, } from './blocks/e-commerce/order-history/order-history';
82
82
  export type { OrderLineData, OrderLineProps } from './blocks/e-commerce/order-history/order-line';
83
+ export { AccountFrame } from './blocks/e-commerce/account/account-frame';
84
+ export type { AccountFrameLabels, AccountFramePresentation, AccountFrameProps, AccountModule, } from './blocks/e-commerce/account/account-frame';
85
+ export { ProfileForm } from './blocks/e-commerce/account/profile-form';
86
+ export type { ProfileField, ProfileFormLabels, ProfileFormProps, } from './blocks/e-commerce/account/profile-form';
87
+ export { AddressBook, AddressForm } from './blocks/e-commerce/account/address-book';
88
+ export type { AccountAddress, AddressBookLabels, AddressBookProps, AddressFormField, AddressFormLabels, AddressFormProps, } from './blocks/e-commerce/account/address-book';
83
89
  export { default as StorefrontHero } from './blocks/e-commerce/storefront-hero/storefront-hero';
84
90
  export type { FeaturedProduct, HeroImage, HeroDepartment, HeroFeaturedDeal, HeroStoreLocator, HeroDeal, HeroCategory, StorefrontHeroPresentation, StorefrontHeroProps, } from './blocks/e-commerce/storefront-hero/storefront-hero';
85
91
  export { default as AppShell1 } from './blocks/application/app-shells/app-shell-1';
@@ -95,6 +101,12 @@ export type { CanonMoney, CanonProduct } from './lib/contracts';
95
101
  export { PRODUCT_IMAGE_FALLBACK } from './lib/contracts';
96
102
  export { isCompleteFiniteDecimal, isAvailableMoney, formatMoney, } from './lib/money';
97
103
  export { resolveAbsoluteQuantity } from './lib/cart';
98
- export { moneySchema, cartTotalsSchema, productDetailProductSchema, productDetailVariantSchema, productOverviewPropsSchema, storefrontHeroPropsSchema, storefrontHeroProductSchema, buttonPropsSchema, storeContainer1PropsSchema, productCardPropsSchema, productGridPropsSchema, productPresentationSchema, productShowcase1PropsSchema, shoppingCartPropsSchema, shoppingCartItemSchema, shoppingCartSuggestionSchema, navbarPresentationSchema, navbarItemSchema, navbarGroupSchema, navbarLinkSchema, navbarFeaturedSchema, navbarPropsSchema, storefrontNavbarPropsSchema, paymentMethodSchema, cardProductSchema, cartItemSchema, promotionSchema, storeCategorySchema, utilityLinkSchema, navCartItemSchema, storeUserSchema, accountMenuItemSchema, featurePropsSchema, featureCardsSpecSchema, featureSplitSpecSchema, productCategoryItemSchema, productCategoryPropsSchema, orderHistoryPresentationSchema, orderHistoryStatusSchema, orderLineDataSchema, orderHistoryOrderSchema, orderHistoryPropsSchema, orderLinePropsSchema, } from './lib/contracts';
99
- export type { ProductDetailProductSpec, ProductDetailVariantSpec, StorefrontHeroProduct, StorefrontHeroSpecProps, CartTotals, ButtonSpecProps, StoreContainer1SpecProps, ProductCardSpecProps, ProductGridSpecProps, ProductPresentation, ProductShowcase1SpecProps, ShoppingCartItem, ShoppingCartSuggestion, ShoppingCartSpecProps, NavbarPresentationSpec, NavbarItemSpec, NavbarGroupSpec, NavbarLinkSpec, NavbarFeaturedSpec, NavbarSpecProps, StorefrontNavbarSpecProps, CardProduct, CartItem, Promotion, StoreCategory, UtilityLink, NavCartItem, StoreUser, AccountMenuItem, FeatureSpecProps, FeatureCardsSpecProps, FeatureSplitSpecProps, ProductCategoryItem, ProductCategorySpecProps, CategoryCardSpecProps, CategoryGridSpecProps, OrderHistoryPresentationSpec, OrderHistoryStatusSpec, OrderLineDataSpec, OrderHistoryOrderSpec, OrderHistorySpecProps, OrderLineSpecProps, } from './lib/contracts';
104
+ export { moneySchema, cartTotalsSchema, productDetailProductSchema, productDetailVariantSchema, productOverviewPropsSchema, storefrontHeroPropsSchema, storefrontHeroProductSchema, buttonPropsSchema, storeContainer1PropsSchema, productCardPropsSchema, productGridPropsSchema, productPresentationSchema, productShowcase1PropsSchema, shoppingCartPropsSchema, shoppingCartItemSchema, shoppingCartSuggestionSchema, navbarPresentationSchema, navbarItemSchema, navbarGroupSchema, navbarLinkSchema, navbarFeaturedSchema, navbarPropsSchema, storefrontNavbarPropsSchema, paymentMethodSchema, checkoutPropsSchema, cardProductSchema, cartItemSchema, promotionSchema, storeCategorySchema, utilityLinkSchema, navCartItemSchema, storeUserSchema, accountMenuItemSchema, featurePropsSchema, featureCardsSpecSchema, featureSplitSpecSchema, productCategoryItemSchema, productCategoryPropsSchema, orderHistoryPresentationSchema, orderHistoryStatusSchema, orderLineDataSchema, orderHistoryOrderSchema, orderHistoryPropsSchema, orderLinePropsSchema, } from './lib/contracts';
105
+ export type { ProductDetailProductSpec, ProductDetailVariantSpec, StorefrontHeroProduct, StorefrontHeroSpecProps, CartTotals, ButtonSpecProps, StoreContainer1SpecProps, ProductCardSpecProps, ProductGridSpecProps, ProductPresentation, ProductShowcase1SpecProps, ShoppingCartItem, ShoppingCartSuggestion, ShoppingCartSpecProps, NavbarPresentationSpec, NavbarItemSpec, NavbarGroupSpec, NavbarLinkSpec, NavbarFeaturedSpec, NavbarSpecProps, StorefrontNavbarSpecProps, CardProduct, CartItem, Promotion, StoreCategory, UtilityLink, NavCartItem, StoreUser, AccountMenuItem, FeatureSpecProps, FeatureCardsSpecProps, FeatureSplitSpecProps, ProductCategoryItem, ProductCategorySpecProps, CategoryCardSpecProps, CategoryGridSpecProps, OrderHistoryPresentationSpec, OrderHistoryStatusSpec, OrderLineDataSpec, OrderHistoryOrderSpec, OrderHistorySpecProps, OrderLineSpecProps, AccountFramePresentationSpec, AccountFrameSpecProps, AccountModuleSpec, ProfileFieldSpec, ProfileFormSpecProps, AccountAddressSpec, AddressBookSpecProps, AddressFormFieldSpec, AddressFormSpecProps, } from './lib/contracts';
106
+ export { default as MarketplaceProductCard } from './blocks/designs/marketplace-product-card/index';
107
+ export type { MarketplaceProductCardProps } from './blocks/designs/marketplace-product-card/index';
108
+ export type { MarketplaceProductCardData } from './lib/contracts/marketplace-product-card';
109
+ export { default as CheckoutCommerceV1 } from './blocks/designs/checkout-commerce-v1/index';
110
+ export type { CheckoutCommerceV1Props } from './blocks/designs/checkout-commerce-v1/index';
111
+ export type { CheckoutCommerceV1Item, CheckoutCommerceV1Data } from './lib/contracts/checkout-commerce-v1';
100
112
  //# sourceMappingURL=index.d.ts.map