pixelize-design-library 2.4.2-beta.56 → 2.4.2-beta.57

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 (354) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/COMPONENT-GOTCHAS.md +48 -20
  3. package/DESIGN-GUIDE.md +18 -1
  4. package/dist/Components/AddressCard/AddressCard.d.ts +4 -0
  5. package/dist/Components/AddressCard/AddressCard.js +25 -0
  6. package/dist/Components/AddressCard/AddressCardGroup.d.ts +4 -0
  7. package/dist/Components/AddressCard/AddressCardGroup.js +7 -0
  8. package/dist/Components/AddressCard/AddressCardProps.d.ts +43 -0
  9. package/dist/Components/AddressCard/AddressCardProps.js +2 -0
  10. package/dist/Components/BagBar/BagBar.d.ts +4 -0
  11. package/dist/Components/BagBar/BagBar.js +32 -0
  12. package/dist/Components/BagBar/BagBarProps.d.ts +30 -0
  13. package/dist/Components/BagBar/BagBarProps.js +2 -0
  14. package/dist/Components/CartItem/CartItem.d.ts +4 -0
  15. package/dist/Components/CartItem/CartItem.js +60 -0
  16. package/dist/Components/CartItem/CartItemProps.d.ts +64 -0
  17. package/dist/Components/CartItem/CartItemProps.js +2 -0
  18. package/dist/Components/CartItem/cartItemOptions.d.ts +3 -0
  19. package/dist/Components/CartItem/cartItemOptions.js +13 -0
  20. package/dist/Components/CheckoutKit/selectable.d.ts +58 -0
  21. package/dist/Components/CheckoutKit/selectable.js +120 -0
  22. package/dist/Components/Commerce/commerceTypes.d.ts +52 -0
  23. package/dist/Components/Commerce/commerceTypes.js +2 -0
  24. package/dist/Components/Commerce/commerceVariants.d.ts +13 -0
  25. package/dist/Components/Commerce/commerceVariants.js +51 -0
  26. package/dist/Components/Commerce/index.d.ts +2 -0
  27. package/dist/Components/Commerce/index.js +18 -0
  28. package/dist/Components/Commerce/useContainerWidth.d.ts +3 -0
  29. package/dist/Components/Commerce/useContainerWidth.js +25 -0
  30. package/dist/Components/CouponField/CouponField.d.ts +4 -0
  31. package/dist/Components/CouponField/CouponField.js +72 -0
  32. package/dist/Components/CouponField/CouponFieldProps.d.ts +49 -0
  33. package/dist/Components/CouponField/CouponFieldProps.js +2 -0
  34. package/dist/Components/DatePicker/PickerPortal.d.ts +11 -0
  35. package/dist/Components/DatePicker/PickerPortal.js +26 -0
  36. package/dist/Components/DatePicker/RangeDatePicker.d.ts +1 -1
  37. package/dist/Components/DatePicker/RangeDatePicker.js +67 -32
  38. package/dist/Components/DatePicker/SingleDatePicker.js +49 -13
  39. package/dist/Components/DatePicker/TimeOnlyPicker.js +39 -4
  40. package/dist/Components/DetailSections/DetailSections.d.ts +4 -0
  41. package/dist/Components/DetailSections/DetailSections.js +112 -0
  42. package/dist/Components/DetailSections/DetailSectionsProps.d.ts +58 -0
  43. package/dist/Components/DetailSections/DetailSectionsProps.js +2 -0
  44. package/dist/Components/MediaGallery/MediaFrame.d.ts +31 -0
  45. package/dist/Components/MediaGallery/MediaFrame.js +55 -0
  46. package/dist/Components/MediaGallery/MediaGallery.d.ts +4 -0
  47. package/dist/Components/MediaGallery/MediaGallery.js +206 -0
  48. package/dist/Components/MediaGallery/MediaGalleryProps.d.ts +76 -0
  49. package/dist/Components/MediaGallery/MediaGalleryProps.js +20 -0
  50. package/dist/Components/MediaGallery/MediaLightbox.d.ts +4 -0
  51. package/dist/Components/MediaGallery/MediaLightbox.js +116 -0
  52. package/dist/Components/MediaGallery/MediaLightboxProps.d.ts +40 -0
  53. package/dist/Components/MediaGallery/MediaLightboxProps.js +15 -0
  54. package/dist/Components/MediaGallery/MediaThumb.d.ts +18 -0
  55. package/dist/Components/MediaGallery/MediaThumb.js +25 -0
  56. package/dist/Components/MediaGallery/glass.d.ts +31 -0
  57. package/dist/Components/MediaGallery/glass.js +47 -0
  58. package/dist/Components/MediaGallery/mediaGalleryModel.d.ts +22 -0
  59. package/dist/Components/MediaGallery/mediaGalleryModel.js +83 -0
  60. package/dist/Components/MediaGallery/motion.d.ts +5 -0
  61. package/dist/Components/MediaGallery/motion.js +12 -0
  62. package/dist/Components/MediaGallery/useMatchMedia.d.ts +2 -0
  63. package/dist/Components/MediaGallery/useMatchMedia.js +20 -0
  64. package/dist/Components/OffersList/OffersList.d.ts +4 -0
  65. package/dist/Components/OffersList/OffersList.js +83 -0
  66. package/dist/Components/OffersList/OffersListProps.d.ts +34 -0
  67. package/dist/Components/OffersList/OffersListProps.js +2 -0
  68. package/dist/Components/OptionChip/OptionChip.d.ts +4 -0
  69. package/dist/Components/OptionChip/OptionChip.js +97 -0
  70. package/dist/Components/OptionChip/OptionChipProps.d.ts +33 -0
  71. package/dist/Components/OptionChip/OptionChipProps.js +2 -0
  72. package/dist/Components/OptionChip/optionInk.d.ts +12 -0
  73. package/dist/Components/OptionChip/optionInk.js +25 -0
  74. package/dist/Components/OrderStatusTimeline/OrderStatusTimeline.d.ts +4 -0
  75. package/dist/Components/OrderStatusTimeline/OrderStatusTimeline.js +57 -0
  76. package/dist/Components/OrderStatusTimeline/OrderStatusTimelineProps.d.ts +29 -0
  77. package/dist/Components/OrderStatusTimeline/OrderStatusTimelineProps.js +2 -0
  78. package/dist/Components/OrderSummary/OrderSummary.d.ts +4 -0
  79. package/dist/Components/OrderSummary/OrderSummary.js +63 -0
  80. package/dist/Components/OrderSummary/OrderSummaryProps.d.ts +53 -0
  81. package/dist/Components/OrderSummary/OrderSummaryProps.js +2 -0
  82. package/dist/Components/PaymentOption/PaymentOption.d.ts +4 -0
  83. package/dist/Components/PaymentOption/PaymentOption.js +24 -0
  84. package/dist/Components/PaymentOption/PaymentOptionGroup.d.ts +4 -0
  85. package/dist/Components/PaymentOption/PaymentOptionGroup.js +7 -0
  86. package/dist/Components/PaymentOption/PaymentOptionProps.d.ts +32 -0
  87. package/dist/Components/PaymentOption/PaymentOptionProps.js +2 -0
  88. package/dist/Components/PincodeChecker/PincodeChecker.d.ts +4 -0
  89. package/dist/Components/PincodeChecker/PincodeChecker.js +175 -0
  90. package/dist/Components/PincodeChecker/PincodeCheckerProps.d.ts +57 -0
  91. package/dist/Components/PincodeChecker/PincodeCheckerProps.js +2 -0
  92. package/dist/Components/PriceBlock/PriceBlock.d.ts +4 -0
  93. package/dist/Components/PriceBlock/PriceBlock.js +41 -0
  94. package/dist/Components/PriceBlock/PriceBlockProps.d.ts +39 -0
  95. package/dist/Components/PriceBlock/PriceBlockProps.js +2 -0
  96. package/dist/Components/ProductBadges/ProductBadges.d.ts +4 -0
  97. package/dist/Components/ProductBadges/ProductBadges.js +61 -0
  98. package/dist/Components/ProductBadges/ProductBadgesProps.d.ts +18 -0
  99. package/dist/Components/ProductBadges/ProductBadgesProps.js +2 -0
  100. package/dist/Components/ProductCard/ProductCard.d.ts +3 -2
  101. package/dist/Components/ProductCard/ProductCard.js +103 -52
  102. package/dist/Components/ProductCard/ProductCardAction.d.ts +17 -0
  103. package/dist/Components/ProductCard/ProductCardAction.js +65 -0
  104. package/dist/Components/ProductCard/ProductCardGrid.d.ts +4 -0
  105. package/dist/Components/ProductCard/ProductCardGrid.js +20 -0
  106. package/dist/Components/ProductCard/ProductCardMedia.d.ts +18 -0
  107. package/dist/Components/ProductCard/ProductCardMedia.js +35 -0
  108. package/dist/Components/ProductCard/ProductCardProps.d.ts +138 -56
  109. package/dist/Components/ProductCard/ProductCardSkeleton.d.ts +4 -0
  110. package/dist/Components/ProductCard/ProductCardSkeleton.js +17 -0
  111. package/dist/Components/ProductCard/ProductCardSwatches.d.ts +15 -0
  112. package/dist/Components/ProductCard/ProductCardSwatches.js +37 -0
  113. package/dist/Components/ProductCard/QuickAddSheet.d.ts +4 -0
  114. package/dist/Components/ProductCard/QuickAddSheet.js +109 -0
  115. package/dist/Components/ProductCard/QuickAddSheetProps.d.ts +38 -0
  116. package/dist/Components/ProductCard/QuickAddSheetProps.js +2 -0
  117. package/dist/Components/ProductCard/cardLabels.d.ts +2 -0
  118. package/dist/Components/ProductCard/cardLabels.js +16 -0
  119. package/dist/Components/ProductCard/cardMetrics.d.ts +27 -0
  120. package/dist/Components/ProductCard/cardMetrics.js +55 -0
  121. package/dist/Components/ProductCard/productCardFixtures.d.ts +7 -0
  122. package/dist/Components/ProductCard/productCardFixtures.js +61 -0
  123. package/dist/Components/ProductCard/productCardModel.d.ts +22 -0
  124. package/dist/Components/ProductCard/productCardModel.js +79 -0
  125. package/dist/Components/ProductCard/useMinWidth.d.ts +2 -0
  126. package/dist/Components/ProductCard/useMinWidth.js +20 -0
  127. package/dist/Components/ProductDetails/ProductDetails.d.ts +3 -2
  128. package/dist/Components/ProductDetails/ProductDetails.js +209 -33
  129. package/dist/Components/ProductDetails/ProductDetailsProps.d.ts +143 -41
  130. package/dist/Components/ProductDetails/productDetailsModel.d.ts +14 -0
  131. package/dist/Components/ProductDetails/productDetailsModel.js +45 -0
  132. package/dist/Components/ProductDetails/useInViewport.d.ts +3 -0
  133. package/dist/Components/ProductDetails/useInViewport.js +18 -0
  134. package/dist/Components/QuantityStepper/QuantityStepper.d.ts +4 -0
  135. package/dist/Components/QuantityStepper/QuantityStepper.js +59 -0
  136. package/dist/Components/QuantityStepper/QuantityStepperProps.d.ts +24 -0
  137. package/dist/Components/QuantityStepper/QuantityStepperProps.js +2 -0
  138. package/dist/Components/Rating/Rating.d.ts +4 -0
  139. package/dist/Components/Rating/Rating.js +81 -0
  140. package/dist/Components/Rating/RatingProps.d.ts +27 -0
  141. package/dist/Components/Rating/RatingProps.js +2 -0
  142. package/dist/Components/ReviewList/ReviewList.d.ts +4 -0
  143. package/dist/Components/ReviewList/ReviewList.js +94 -0
  144. package/dist/Components/ReviewList/ReviewListProps.d.ts +68 -0
  145. package/dist/Components/ReviewList/ReviewListProps.js +2 -0
  146. package/dist/Components/ReviewSummary/ReviewSummary.d.ts +4 -0
  147. package/dist/Components/ReviewSummary/ReviewSummary.js +47 -0
  148. package/dist/Components/ReviewSummary/ReviewSummaryProps.d.ts +31 -0
  149. package/dist/Components/ReviewSummary/ReviewSummaryProps.js +2 -0
  150. package/dist/Components/SegmentedControl/SegmentedControl.d.ts +1 -1
  151. package/dist/Components/SegmentedControl/SegmentedControl.js +17 -5
  152. package/dist/Components/SegmentedControl/SegmentedControlProps.d.ts +6 -0
  153. package/dist/Components/SegmentedControl/segmentedInk.d.ts +2 -0
  154. package/dist/Components/SegmentedControl/segmentedInk.js +4 -1
  155. package/dist/Components/SegmentedControl/useSlidingPill.d.ts +2 -0
  156. package/dist/Components/SegmentedControl/useSlidingPill.js +6 -1
  157. package/dist/Components/SideBar/SecondaryBar.js +13 -8
  158. package/dist/Components/SideBar/SideBarProps.d.ts +3 -1
  159. package/dist/Components/SideBar/components/MenuItemBox.js +47 -10
  160. package/dist/Components/SideBar/components/MenuPopoverContent.js +4 -3
  161. package/dist/Components/SpecTable/SpecTable.d.ts +4 -0
  162. package/dist/Components/SpecTable/SpecTable.js +39 -0
  163. package/dist/Components/SpecTable/SpecTableProps.d.ts +25 -0
  164. package/dist/Components/SpecTable/SpecTableProps.js +2 -0
  165. package/dist/Components/Spinner/Spinner.d.ts +1 -1
  166. package/dist/Components/Spinner/Spinner.js +2 -2
  167. package/dist/Components/Spinner/SpinnerProps.d.ts +2 -0
  168. package/dist/Components/StageProgress/StepperStage.js +2 -1
  169. package/dist/Components/StatCard/StatCard.d.ts +1 -1
  170. package/dist/Components/StatCard/StatCard.js +2 -2
  171. package/dist/Components/StatCard/StatCardProps.d.ts +4 -0
  172. package/dist/Components/StickyBuyBar/StickyBuyBar.d.ts +3 -0
  173. package/dist/Components/StickyBuyBar/StickyBuyBar.js +85 -0
  174. package/dist/Components/StickyBuyBar/StickyBuyBarProps.d.ts +54 -0
  175. package/dist/Components/StickyBuyBar/StickyBuyBarProps.js +2 -0
  176. package/dist/Components/StockStatus/StockStatus.d.ts +4 -0
  177. package/dist/Components/StockStatus/StockStatus.js +31 -0
  178. package/dist/Components/StockStatus/StockStatusProps.d.ts +14 -0
  179. package/dist/Components/StockStatus/StockStatusProps.js +2 -0
  180. package/dist/Components/Table/Table.js +2 -1
  181. package/dist/Components/Table/TableProps.d.ts +5 -2
  182. package/dist/Components/Table/columnLabel.d.ts +6 -0
  183. package/dist/Components/Table/columnLabel.js +27 -0
  184. package/dist/Components/Table/components/TableBody.js +5 -1
  185. package/dist/Components/Table/components/TableHeader.js +3 -2
  186. package/dist/Components/Table/filters/ActiveFilters.js +2 -1
  187. package/dist/Components/Table/filters/TableFilters.js +2 -1
  188. package/dist/Components/Table/hooks/useTable.js +3 -2
  189. package/dist/Components/Table/settings/ManageColumns.js +4 -3
  190. package/dist/Components/Table/settings/TableSettings.js +2 -1
  191. package/dist/Components/TrustBadges/TrustBadges.d.ts +4 -0
  192. package/dist/Components/TrustBadges/TrustBadges.js +24 -0
  193. package/dist/Components/TrustBadges/TrustBadgesProps.d.ts +20 -0
  194. package/dist/Components/TrustBadges/TrustBadgesProps.js +2 -0
  195. package/dist/Components/VariantSelector/VariantSelector.d.ts +4 -0
  196. package/dist/Components/VariantSelector/VariantSelector.js +123 -0
  197. package/dist/Components/VariantSelector/VariantSelectorProps.d.ts +27 -0
  198. package/dist/Components/VariantSelector/VariantSelectorProps.js +2 -0
  199. package/dist/Components/VariantSelector/variantSelection.d.ts +6 -0
  200. package/dist/Components/VariantSelector/variantSelection.js +25 -0
  201. package/dist/Components/WishlistToggle/WishlistToggle.d.ts +4 -0
  202. package/dist/Components/WishlistToggle/WishlistToggle.js +65 -0
  203. package/dist/Components/WishlistToggle/WishlistToggleProps.d.ts +19 -0
  204. package/dist/Components/WishlistToggle/WishlistToggleProps.js +2 -0
  205. package/dist/Theme/assertPalette.d.ts +1 -1
  206. package/dist/Theme/assertPalette.js +1 -1
  207. package/dist/Theme/tokens/brands/index.js +2 -0
  208. package/dist/Theme/tokens/brands/zinc/palette.dark.d.ts +1 -0
  209. package/dist/Theme/tokens/builders/buildDarkPalette.js +2 -0
  210. package/dist/Theme/tokens/builders/index.d.ts +1 -0
  211. package/dist/Theme/tokens/builders/index.js +1 -0
  212. package/dist/Theme/tokens/builders/rechartsTheme.d.ts +56 -0
  213. package/dist/Theme/tokens/builders/rechartsTheme.js +43 -0
  214. package/dist/Theme/tokens/builders/star.d.ts +3 -0
  215. package/dist/Theme/tokens/builders/star.js +8 -0
  216. package/dist/Theme/tokens/types.d.ts +3 -1
  217. package/dist/Theme/useChartTheme.d.ts +4 -0
  218. package/dist/Theme/useChartTheme.js +12 -0
  219. package/dist/Utils/price.d.ts +16 -0
  220. package/dist/Utils/price.js +34 -0
  221. package/dist/esm/Components/AddressCard/AddressCard.js +20 -0
  222. package/dist/esm/Components/AddressCard/AddressCardGroup.js +5 -0
  223. package/dist/esm/Components/AddressCard/AddressCardProps.js +1 -0
  224. package/dist/esm/Components/BagBar/BagBar.js +27 -0
  225. package/dist/esm/Components/BagBar/BagBarProps.js +1 -0
  226. package/dist/esm/Components/CartItem/CartItem.js +55 -0
  227. package/dist/esm/Components/CartItem/CartItemProps.js +1 -0
  228. package/dist/esm/Components/CartItem/cartItemOptions.js +9 -0
  229. package/dist/esm/Components/CheckoutKit/selectable.js +112 -0
  230. package/dist/esm/Components/Commerce/commerceTypes.js +1 -0
  231. package/dist/esm/Components/Commerce/commerceVariants.js +41 -0
  232. package/dist/esm/Components/Commerce/index.js +2 -0
  233. package/dist/esm/Components/Commerce/useContainerWidth.js +21 -0
  234. package/dist/esm/Components/CouponField/CouponField.js +67 -0
  235. package/dist/esm/Components/CouponField/CouponFieldProps.js +1 -0
  236. package/dist/esm/Components/DatePicker/PickerPortal.js +21 -0
  237. package/dist/esm/Components/DatePicker/RangeDatePicker.js +34 -32
  238. package/dist/esm/Components/DatePicker/SingleDatePicker.js +16 -13
  239. package/dist/esm/Components/DatePicker/TimeOnlyPicker.js +6 -4
  240. package/dist/esm/Components/DetailSections/DetailSections.js +107 -0
  241. package/dist/esm/Components/DetailSections/DetailSectionsProps.js +1 -0
  242. package/dist/esm/Components/MediaGallery/MediaFrame.js +48 -0
  243. package/dist/esm/Components/MediaGallery/MediaGallery.js +201 -0
  244. package/dist/esm/Components/MediaGallery/MediaGalleryProps.js +17 -0
  245. package/dist/esm/Components/MediaGallery/MediaLightbox.js +78 -0
  246. package/dist/esm/Components/MediaGallery/MediaLightboxProps.js +12 -0
  247. package/dist/esm/Components/MediaGallery/MediaThumb.js +23 -0
  248. package/dist/esm/Components/MediaGallery/glass.js +42 -0
  249. package/dist/esm/Components/MediaGallery/mediaGalleryModel.js +71 -0
  250. package/dist/esm/Components/MediaGallery/motion.js +8 -0
  251. package/dist/esm/Components/MediaGallery/useMatchMedia.js +16 -0
  252. package/dist/esm/Components/OffersList/OffersList.js +81 -0
  253. package/dist/esm/Components/OffersList/OffersListProps.js +1 -0
  254. package/dist/esm/Components/OptionChip/OptionChip.js +95 -0
  255. package/dist/esm/Components/OptionChip/OptionChipProps.js +1 -0
  256. package/dist/esm/Components/OptionChip/optionInk.js +21 -0
  257. package/dist/esm/Components/OrderStatusTimeline/OrderStatusTimeline.js +55 -0
  258. package/dist/esm/Components/OrderStatusTimeline/OrderStatusTimelineProps.js +1 -0
  259. package/dist/esm/Components/OrderSummary/OrderSummary.js +58 -0
  260. package/dist/esm/Components/OrderSummary/OrderSummaryProps.js +1 -0
  261. package/dist/esm/Components/PaymentOption/PaymentOption.js +19 -0
  262. package/dist/esm/Components/PaymentOption/PaymentOptionGroup.js +5 -0
  263. package/dist/esm/Components/PaymentOption/PaymentOptionProps.js +1 -0
  264. package/dist/esm/Components/PincodeChecker/PincodeChecker.js +170 -0
  265. package/dist/esm/Components/PincodeChecker/PincodeCheckerProps.js +1 -0
  266. package/dist/esm/Components/PriceBlock/PriceBlock.js +39 -0
  267. package/dist/esm/Components/PriceBlock/PriceBlockProps.js +1 -0
  268. package/dist/esm/Components/ProductBadges/ProductBadges.js +59 -0
  269. package/dist/esm/Components/ProductBadges/ProductBadgesProps.js +1 -0
  270. package/dist/esm/Components/ProductCard/ProductCard.js +105 -54
  271. package/dist/esm/Components/ProductCard/ProductCardAction.js +60 -0
  272. package/dist/esm/Components/ProductCard/ProductCardGrid.js +18 -0
  273. package/dist/esm/Components/ProductCard/ProductCardMedia.js +33 -0
  274. package/dist/esm/Components/ProductCard/ProductCardSkeleton.js +12 -0
  275. package/dist/esm/Components/ProductCard/ProductCardSwatches.js +35 -0
  276. package/dist/esm/Components/ProductCard/QuickAddSheet.js +71 -0
  277. package/dist/esm/Components/ProductCard/QuickAddSheetProps.js +1 -0
  278. package/dist/esm/Components/ProductCard/cardLabels.js +13 -0
  279. package/dist/esm/Components/ProductCard/cardMetrics.js +52 -0
  280. package/dist/esm/Components/ProductCard/productCardFixtures.js +58 -0
  281. package/dist/esm/Components/ProductCard/productCardModel.js +65 -0
  282. package/dist/esm/Components/ProductCard/useMinWidth.js +16 -0
  283. package/dist/esm/Components/ProductDetails/ProductDetails.js +210 -34
  284. package/dist/esm/Components/ProductDetails/productDetailsModel.js +35 -0
  285. package/dist/esm/Components/ProductDetails/useInViewport.js +14 -0
  286. package/dist/esm/Components/QuantityStepper/QuantityStepper.js +57 -0
  287. package/dist/esm/Components/QuantityStepper/QuantityStepperProps.js +1 -0
  288. package/dist/esm/Components/Rating/Rating.js +79 -0
  289. package/dist/esm/Components/Rating/RatingProps.js +1 -0
  290. package/dist/esm/Components/ReviewList/ReviewList.js +89 -0
  291. package/dist/esm/Components/ReviewList/ReviewListProps.js +1 -0
  292. package/dist/esm/Components/ReviewSummary/ReviewSummary.js +42 -0
  293. package/dist/esm/Components/ReviewSummary/ReviewSummaryProps.js +1 -0
  294. package/dist/esm/Components/SegmentedControl/SegmentedControl.js +19 -7
  295. package/dist/esm/Components/SegmentedControl/segmentedInk.js +2 -0
  296. package/dist/esm/Components/SegmentedControl/useSlidingPill.js +6 -1
  297. package/dist/esm/Components/SideBar/SecondaryBar.js +14 -9
  298. package/dist/esm/Components/SideBar/components/MenuItemBox.js +14 -10
  299. package/dist/esm/Components/SideBar/components/MenuPopoverContent.js +4 -3
  300. package/dist/esm/Components/SpecTable/SpecTable.js +34 -0
  301. package/dist/esm/Components/SpecTable/SpecTableProps.js +1 -0
  302. package/dist/esm/Components/Spinner/Spinner.js +2 -2
  303. package/dist/esm/Components/StageProgress/StepperStage.js +2 -1
  304. package/dist/esm/Components/StatCard/StatCard.js +2 -2
  305. package/dist/esm/Components/StickyBuyBar/StickyBuyBar.js +80 -0
  306. package/dist/esm/Components/StickyBuyBar/StickyBuyBarProps.js +1 -0
  307. package/dist/esm/Components/StockStatus/StockStatus.js +29 -0
  308. package/dist/esm/Components/StockStatus/StockStatusProps.js +1 -0
  309. package/dist/esm/Components/Table/Table.js +2 -1
  310. package/dist/esm/Components/Table/columnLabel.js +21 -0
  311. package/dist/esm/Components/Table/components/TableBody.js +5 -1
  312. package/dist/esm/Components/Table/components/TableHeader.js +3 -2
  313. package/dist/esm/Components/Table/filters/ActiveFilters.js +2 -1
  314. package/dist/esm/Components/Table/filters/TableFilters.js +2 -1
  315. package/dist/esm/Components/Table/hooks/useTable.js +3 -2
  316. package/dist/esm/Components/Table/settings/ManageColumns.js +4 -3
  317. package/dist/esm/Components/Table/settings/TableSettings.js +2 -1
  318. package/dist/esm/Components/TrustBadges/TrustBadges.js +22 -0
  319. package/dist/esm/Components/TrustBadges/TrustBadgesProps.js +1 -0
  320. package/dist/esm/Components/VariantSelector/VariantSelector.js +118 -0
  321. package/dist/esm/Components/VariantSelector/VariantSelectorProps.js +1 -0
  322. package/dist/esm/Components/VariantSelector/variantSelection.js +19 -0
  323. package/dist/esm/Components/WishlistToggle/WishlistToggle.js +63 -0
  324. package/dist/esm/Components/WishlistToggle/WishlistToggleProps.js +1 -0
  325. package/dist/esm/Theme/assertPalette.js +1 -1
  326. package/dist/esm/Theme/tokens/brands/index.js +2 -0
  327. package/dist/esm/Theme/tokens/builders/buildDarkPalette.js +2 -0
  328. package/dist/esm/Theme/tokens/builders/index.js +1 -0
  329. package/dist/esm/Theme/tokens/builders/rechartsTheme.js +37 -0
  330. package/dist/esm/Theme/tokens/builders/star.js +4 -0
  331. package/dist/esm/Theme/useChartTheme.js +8 -0
  332. package/dist/esm/Utils/price.js +27 -0
  333. package/dist/esm/index.js +36 -0
  334. package/dist/index.d.ts +66 -0
  335. package/dist/index.js +86 -4
  336. package/package.json +1 -1
  337. package/dist/Components/ProductCard/ProductLabel.d.ts +0 -7
  338. package/dist/Components/ProductCard/ProductLabel.js +0 -20
  339. package/dist/Components/ProductCard/ProductPrice.d.ts +0 -10
  340. package/dist/Components/ProductCard/ProductPrice.js +0 -126
  341. package/dist/Components/ProductCard/ProductReview.d.ts +0 -8
  342. package/dist/Components/ProductCard/ProductReview.js +0 -30
  343. package/dist/Components/ProductCard/ProductTags.d.ts +0 -8
  344. package/dist/Components/ProductCard/ProductTags.js +0 -53
  345. package/dist/Components/ProductDetails/ProductDtlPrice.d.ts +0 -7
  346. package/dist/Components/ProductDetails/ProductDtlPrice.js +0 -24
  347. package/dist/Components/ProductDetails/ProductImageSlider.d.ts +0 -13
  348. package/dist/Components/ProductDetails/ProductImageSlider.js +0 -240
  349. package/dist/esm/Components/ProductCard/ProductLabel.js +0 -18
  350. package/dist/esm/Components/ProductCard/ProductPrice.js +0 -121
  351. package/dist/esm/Components/ProductCard/ProductReview.js +0 -28
  352. package/dist/esm/Components/ProductCard/ProductTags.js +0 -48
  353. package/dist/esm/Components/ProductDetails/ProductDtlPrice.js +0 -22
  354. package/dist/esm/Components/ProductDetails/ProductImageSlider.js +0 -204
@@ -0,0 +1,201 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
3
+ import { Box, Flex, Text } from "@chakra-ui/react";
4
+ import { ChevronLeft, ChevronRight, ZoomIn } from "lucide-react";
5
+ import { useCustomTheme } from "../../Theme/useCustomTheme.js";
6
+ import { transitionFor } from "../../Theme/tokens/primitives/motion.js";
7
+ import { scrollbarStyles } from "../../Theme/tokens/builders/scrollbar.js";
8
+ import { reducedMotionSx, usePrefersReducedMotion } from "../../Theme/chakra/motion.js";
9
+ import { focusVisibleStyles } from "../../Theme/chakra/focusRing.styles.js";
10
+ import Skeletons from "../Skeletons/Skeletons.js";
11
+ import MediaFrame from "./MediaFrame.js";
12
+ import MediaThumb from "./MediaThumb.js";
13
+ import MediaLightbox from "./MediaLightbox.js";
14
+ import { GlassIconButton, GlassPill, glassStyles } from "./glass.js";
15
+ import { CROSSFADE_MS, fadeIn } from "./motion.js";
16
+ import { useContainerWidth } from "../Commerce/useContainerWidth.js";
17
+ import { useMatchMedia } from "./useMatchMedia.js";
18
+ import { clampIndex, frameKind, frameSignature, indexForKey, keyBelongsToTarget, resolveFrames } from "./mediaGalleryModel.js";
19
+ import { defaultMediaGalleryLabels } from "./MediaGalleryProps.js";
20
+ const WIDE_QUERY = "(min-width: 768px)";
21
+ const WIDE_MIN_WIDTH = 560;
22
+ const FINE_POINTER_QUERY = "(hover: hover) and (pointer: fine)";
23
+ const MAX_DOTS = 8;
24
+ const INNER_ZOOM = 2;
25
+ const SETTLE_MS = 700;
26
+ const HIDDEN_SCROLLBAR = { scrollbarWidth: "none", "&::-webkit-scrollbar": { display: "none" } };
27
+ const revealWithin = (container, child, axis) => {
28
+ const [start, size, view] = axis === "x"
29
+ ? [child.offsetLeft, child.offsetWidth, container.clientWidth]
30
+ : [child.offsetTop, child.offsetHeight, container.clientHeight];
31
+ const key = axis === "x" ? "scrollLeft" : "scrollTop";
32
+ const at = container[key];
33
+ if (start < at)
34
+ container[key] = start;
35
+ else if (start + size > at + view)
36
+ container[key] = start + size - view;
37
+ };
38
+ const GallerySkeleton = ({ arrangement, aspectRatio, rounded, label }) => {
39
+ const rail = arrangement !== "swipe";
40
+ const vertical = arrangement === "thumbs-left";
41
+ return (_jsxs(Flex, { role: "status", "aria-label": label, direction: vertical ? "row" : "column", gap: 4, w: "100%", "data-testid": "media-gallery-skeleton", children: [rail && vertical && (_jsx(Flex, { direction: "column", gap: 3, w: "72px", flexShrink: 0, children: [0, 1, 2, 3].map((n) => (_jsx(Skeletons, { type: "skeleton", height: "90px", width: "72px", borderRadius: "xl" }, n))) })), _jsx(Box, { flex: 1, minW: 0, sx: { aspectRatio }, borderRadius: rounded ? "2xl" : 0, overflow: "hidden", children: _jsx(Skeletons, { type: "skeleton", height: "100%", width: "100%", borderRadius: "0" }) }), rail && !vertical && (_jsx(Flex, { gap: 3, children: [0, 1, 2, 3].map((n) => (_jsx(Skeletons, { type: "skeleton", height: "80px", width: "64px", borderRadius: "xl" }, n))) }))] }));
42
+ };
43
+ /** Product media carousel: scroll-snap track, thumbnail rail or dots, lightbox, colour-linked frame sets. */
44
+ const MediaGallery = ({ media, layout = "auto", aspectRatio = "4/5", zoom = "lightbox", index, defaultIndex = 0, onIndexChange, activeMediaIds, badges, actions, sticky = false, stickyTop = 24, rounded, isLoading = false, labels: labelOverrides, lightboxLabels, "aria-label": ariaLabel, "data-testid": testId, }) => {
45
+ const { colors } = useCustomTheme();
46
+ const reduced = usePrefersReducedMotion();
47
+ const rootRef = useRef(null);
48
+ const containerWidth = useContainerWidth(rootRef);
49
+ const windowWide = useMatchMedia(WIDE_QUERY, false);
50
+ const wide = containerWidth === undefined ? windowWide : containerWidth >= WIDE_MIN_WIDTH;
51
+ const finePointer = useMatchMedia(FINE_POINTER_QUERY, false);
52
+ const labels = { ...defaultMediaGalleryLabels, ...labelOverrides };
53
+ const arrangement = layout === "auto" ? (wide ? "thumbs-left" : "swipe") : layout;
54
+ const isSwipe = arrangement === "swipe";
55
+ const squared = rounded === undefined ? isSwipe : !rounded;
56
+ const activeKey = JSON.stringify(activeMediaIds !== null && activeMediaIds !== void 0 ? activeMediaIds : null);
57
+ const frames = useMemo(() => { var _a; return resolveFrames(media, (_a = JSON.parse(activeKey)) !== null && _a !== void 0 ? _a : undefined); }, [media, activeKey]);
58
+ const signature = frameSignature(frames);
59
+ const count = frames.length;
60
+ const isControlled = index !== undefined;
61
+ const [ownIndex, setOwnIndex] = useState(defaultIndex);
62
+ const current = clampIndex(isControlled ? index : ownIndex, count);
63
+ const latest = useRef(current);
64
+ latest.current = current;
65
+ const onChangeRef = useRef(onIndexChange);
66
+ onChangeRef.current = onIndexChange;
67
+ const commit = (next) => {
68
+ var _a;
69
+ const target = clampIndex(next, count);
70
+ if (target === latest.current)
71
+ return;
72
+ latest.current = target;
73
+ if (!isControlled)
74
+ setOwnIndex(target);
75
+ (_a = onChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onChangeRef, target);
76
+ };
77
+ const commitRef = useRef(commit);
78
+ commitRef.current = commit;
79
+ const trackRef = useRef(null);
80
+ const railRef = useRef(null);
81
+ const settling = useRef(null);
82
+ const settleTimer = useRef();
83
+ const alignedTrack = useRef(null);
84
+ const lightboxReturn = useRef(null);
85
+ const [lightboxOpen, setLightboxOpen] = useState(false);
86
+ const [inner, setInner] = useState({ on: false, x: 50, y: 50 });
87
+ const [fadeKey, setFadeKey] = useState(0);
88
+ const seenSignature = useRef(signature);
89
+ useEffect(() => {
90
+ if (seenSignature.current === signature)
91
+ return;
92
+ seenSignature.current = signature;
93
+ setFadeKey((key) => key + 1);
94
+ commitRef.current(0);
95
+ }, [signature]);
96
+ useEffect(() => setInner((state) => (state.on ? { ...state, on: false } : state)), [current, signature]);
97
+ useEffect(() => () => window.clearTimeout(settleTimer.current), []);
98
+ useLayoutEffect(() => {
99
+ var _a;
100
+ const track = trackRef.current;
101
+ const width = (_a = track === null || track === void 0 ? void 0 : track.clientWidth) !== null && _a !== void 0 ? _a : 0;
102
+ if (!track || !width)
103
+ return;
104
+ const firstPass = alignedTrack.current !== track;
105
+ alignedTrack.current = track;
106
+ const left = current * width;
107
+ if (Math.abs(track.scrollLeft - left) < 2)
108
+ return;
109
+ settling.current = current;
110
+ window.clearTimeout(settleTimer.current);
111
+ settleTimer.current = window.setTimeout(() => {
112
+ settling.current = null;
113
+ }, SETTLE_MS);
114
+ if (firstPass || reduced || typeof track.scrollTo !== "function")
115
+ track.scrollLeft = left;
116
+ else
117
+ track.scrollTo({ left, behavior: "smooth" });
118
+ }, [current, fadeKey, arrangement, reduced]);
119
+ useEffect(() => {
120
+ const rail = railRef.current;
121
+ const selected = rail === null || rail === void 0 ? void 0 : rail.querySelector('[aria-current="true"]');
122
+ if (rail && selected)
123
+ revealWithin(rail, selected, arrangement === "thumbs-left" ? "y" : "x");
124
+ }, [current, fadeKey, arrangement]);
125
+ const onScroll = () => {
126
+ const track = trackRef.current;
127
+ if (!track || !track.clientWidth)
128
+ return;
129
+ const at = clampIndex(Math.round(track.scrollLeft / track.clientWidth), count);
130
+ if (settling.current !== null) {
131
+ if (at === settling.current)
132
+ settling.current = null;
133
+ return;
134
+ }
135
+ commit(at);
136
+ };
137
+ const onKeyDown = (event) => {
138
+ if (event.ctrlKey || event.metaKey || event.altKey || keyBelongsToTarget(event.target))
139
+ return;
140
+ const next = indexForKey(event.key, latest.current, count);
141
+ if (next === undefined)
142
+ return;
143
+ event.preventDefault();
144
+ commit(next);
145
+ };
146
+ const openLightbox = (event) => {
147
+ lightboxReturn.current = event.currentTarget;
148
+ setLightboxOpen(true);
149
+ };
150
+ const toggleInner = (event) => {
151
+ const box = event.currentTarget.getBoundingClientRect();
152
+ const x = box.width ? ((event.clientX - box.left) / box.width) * 100 : 50;
153
+ const y = box.height ? ((event.clientY - box.top) / box.height) * 100 : 50;
154
+ setInner((state) => ({ on: !state.on, x, y }));
155
+ };
156
+ const panInner = (event) => {
157
+ if (!inner.on || event.pointerType !== "mouse")
158
+ return;
159
+ const box = event.currentTarget.getBoundingClientRect();
160
+ if (!box.width || !box.height)
161
+ return;
162
+ setInner({ on: true, x: ((event.clientX - box.left) / box.width) * 100, y: ((event.clientY - box.top) / box.height) * 100 });
163
+ };
164
+ const ratio = aspectRatio.replace("/", " / ");
165
+ const radius = squared ? 0 : "2xl";
166
+ const showArrows = count > 1 && (finePointer || !isSwipe);
167
+ const showRail = count > 1 && !isSwipe;
168
+ const arrowSize = isSwipe ? 36 : 44;
169
+ const arrowInset = isSwipe ? 12 : 16;
170
+ const currentFrame = frames[current];
171
+ const zoomable = zoom !== "none" && currentFrame !== undefined && frameKind(currentFrame) === "image";
172
+ if (isLoading)
173
+ return _jsx(GallerySkeleton, { arrangement: arrangement, aspectRatio: ratio, rounded: !squared, label: labels.loading });
174
+ const thumbRing = { gap: colors.background[50], ink: colors.header[900] };
175
+ const thumbs = (width, height) => frames.map((frame, position) => (_jsx(MediaThumb, { media: frame, label: labels.frame(position + 1, count, frame.alt), selected: position === current, onSelect: () => commit(position), width: width, height: height, ring: thumbRing }, frame.id)));
176
+ const glassDots = glassStyles(colors);
177
+ const focusInset = { outline: "2px solid transparent", boxShadow: `inset 0 0 0 2px ${colors.focusRing.halo}, inset 0 0 0 4px ${colors.focusRing.ring}` };
178
+ const well = (_jsxs(Box, { position: "relative", flex: 1, minW: 0, overflow: "hidden", isolation: "isolate", borderRadius: radius, bg: colors.background[100], sx: { aspectRatio: ratio }, "data-testid": "media-gallery-well", children: [_jsxs(Flex, { ref: trackRef, position: "absolute", inset: 0, tabIndex: 0, role: "group", "aria-label": labels.region, overflowX: "auto", overflowY: "hidden", animation: fadeKey > 0 ? fadeIn(CROSSFADE_MS) : undefined, onScroll: onScroll, onPointerDown: () => {
179
+ settling.current = null;
180
+ }, outline: "none", _focusVisible: focusInset, sx: {
181
+ scrollSnapType: "x mandatory",
182
+ overscrollBehaviorX: "contain",
183
+ ...HIDDEN_SCROLLBAR,
184
+ ...reducedMotionSx(),
185
+ }, "data-testid": "media-gallery-track", children: [frames.map((frame, position) => {
186
+ var _a;
187
+ const isCurrent = position === current;
188
+ const kind = frameKind(frame);
189
+ const alt = (_a = frame.alt) !== null && _a !== void 0 ? _a : labels.image(position + 1, count);
190
+ const view = (_jsx(MediaFrame, { media: frame, alt: alt, active: isCurrent, eager: Math.abs(position - current) <= 1, zoom: zoom === "inner" && isCurrent && inner.on ? { scale: INNER_ZOOM, x: inner.x, y: inner.y } : undefined, playLabel: labels.playVideo, unavailableLabel: labels.imageUnavailable }));
191
+ const interactive = zoom !== "none" && kind === "image";
192
+ return (_jsx(Box, { role: "group", "aria-roledescription": "slide", "aria-label": labels.slide(position + 1, count), "aria-hidden": isCurrent ? undefined : true, flex: "0 0 100%", h: "100%", position: "relative", opacity: reduced && !isCurrent ? 0 : 1, transition: reduced ? transitionFor(["opacity"], "fast") : undefined, sx: { scrollSnapAlign: "start", scrollSnapStop: "always" }, children: interactive ? (_jsx(Box, { as: "button", type: "button", w: "100%", h: "100%", p: 0, border: "0", bg: "transparent", display: "block", overflow: "hidden", cursor: "zoom-in", tabIndex: isCurrent ? 0 : -1, "aria-label": zoom === "lightbox" ? labels.openLightbox(position + 1, count) : labels.zoomImage(position + 1, count), "aria-haspopup": zoom === "lightbox" ? "dialog" : undefined, "aria-pressed": zoom === "inner" ? isCurrent && inner.on : undefined, onClick: zoom === "lightbox" ? openLightbox : toggleInner, onPointerMove: zoom === "inner" ? panInner : undefined, outline: "none", _focusVisible: focusInset, sx: { cursor: zoom === "inner" && inner.on ? "zoom-out" : "zoom-in" }, children: view })) : (view) }, frame.id));
193
+ }), count === 0 && _jsx(Box, { flex: "0 0 100%", bg: colors.background[100] })] }, fadeKey), badges && (_jsx(Box, { position: "absolute", top: 3, left: 3, zIndex: 2, pointerEvents: "none", "data-testid": "media-gallery-badges", children: badges })), actions && (_jsx(Box, { position: "absolute", top: 3, right: 3, zIndex: 3, "data-testid": "media-gallery-actions", children: actions })), showArrows && (_jsxs(_Fragment, { children: [_jsx(GlassIconButton, { label: labels.previous, icon: _jsx(ChevronLeft, { size: arrowSize / 2, "aria-hidden": true }), onClick: () => commit(current - 1), isDisabled: current === 0, size: arrowSize, left: `${arrowInset}px`, top: `calc(50% - ${arrowSize / 2}px)`, zIndex: 2 }), _jsx(GlassIconButton, { label: labels.next, icon: _jsx(ChevronRight, { size: arrowSize / 2, "aria-hidden": true }), onClick: () => commit(current + 1), isDisabled: current === count - 1, size: arrowSize, right: `${arrowInset}px`, top: `calc(50% - ${arrowSize / 2}px)`, zIndex: 2 })] })), count > 1 && isSwipe && count <= MAX_DOTS && (_jsx(Flex, { role: "group", "aria-label": labels.dots, position: "absolute", left: "50%", bottom: 4, transform: "translateX(-50%)", zIndex: 2, h: "28px", px: 1.5, align: "center", borderRadius: "full", ...glassDots, "data-testid": "media-gallery-dots", children: frames.map((frame, position) => {
194
+ const selected = position === current;
195
+ return (_jsx(Box, { as: "button", type: "button", onClick: () => commit(position), "aria-label": labels.image(position + 1, count), "aria-current": selected ? "true" : undefined, display: "inline-flex", alignItems: "center", justifyContent: "center", h: "28px", w: selected ? "30px" : "20px", p: 0, border: "0", bg: "transparent", cursor: "pointer", transition: transitionFor(["width"]), borderRadius: "full", sx: { ...focusVisibleStyles(colors), ...reducedMotionSx() }, children: _jsx(Box, { as: "span", boxSize: "6px", borderRadius: "full", bg: "currentColor", opacity: selected ? 0.92 : 0.3, transform: selected ? "scaleX(2.4)" : "scaleX(1)", transition: transitionFor(["transform", "opacity"]) }) }, frame.id));
196
+ }) })), count > 1 && (_jsx(GlassPill, { ...(isSwipe ? { right: 4, bottom: "19px", height: 22 } : { left: 4, bottom: 4, height: 32 }), zIndex: 2, children: _jsx("span", { "aria-live": "polite", "data-testid": "media-gallery-counter", children: labels.counter(current + 1, count) }) })), !isSwipe && finePointer && zoomable && zoom === "lightbox" && (_jsxs(GlassPill, { right: 4, bottom: 4, height: 32, zIndex: 2, children: [_jsx(ZoomIn, { size: 14, "aria-hidden": true }), _jsx(Text, { as: "span", children: labels.zoomHint })] }))] }));
197
+ const rail = showRail &&
198
+ (arrangement === "thumbs-left" ? (_jsx(Box, { position: "relative", w: "72px", flexShrink: 0, alignSelf: "stretch", "data-testid": "media-gallery-rail", children: _jsx(Flex, { ref: railRef, role: "group", "aria-label": labels.thumbnails, position: "absolute", inset: "-4px", p: "4px", direction: "column", gap: 3, overflowY: "auto", overflowX: "hidden", animation: fadeKey > 0 ? fadeIn(CROSSFADE_MS) : undefined, sx: { ...scrollbarStyles(colors, "hover"), ...reducedMotionSx() }, children: thumbs(72, 90) }, fadeKey) })) : (_jsx(Flex, { ref: railRef, role: "group", "aria-label": labels.thumbnails, gap: 3, m: "-4px", p: "4px", overflowX: "auto", animation: fadeKey > 0 ? fadeIn(CROSSFADE_MS) : undefined, sx: { ...scrollbarStyles(colors, "hover"), ...reducedMotionSx() }, "data-testid": "media-gallery-rail", children: thumbs(64, 80) }, fadeKey)));
199
+ return (_jsxs(_Fragment, { children: [_jsx(Box, { ref: rootRef, role: "region", "aria-roledescription": "carousel", "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : labels.region, onKeyDown: onKeyDown, w: "100%", position: sticky ? "sticky" : "relative", top: sticky ? `${stickyTop}px` : undefined, alignSelf: sticky ? "flex-start" : undefined, "data-testid": testId, children: _jsxs(Flex, { direction: arrangement === "thumbs-left" ? "row" : "column", gap: 4, align: arrangement === "thumbs-left" ? "stretch" : undefined, children: [arrangement === "thumbs-left" && rail, well, arrangement === "thumbs-below" && rail] }) }), _jsx(MediaLightbox, { isOpen: lightboxOpen, onClose: () => setLightboxOpen(false), items: frames, index: current, onIndexChange: commit, finalFocusRef: lightboxReturn, labels: lightboxLabels })] }));
200
+ };
201
+ export default MediaGallery;
@@ -0,0 +1,17 @@
1
+ export const defaultMediaGalleryLabels = {
2
+ region: "Product images",
3
+ slide: (position, total) => `${position} of ${total}`,
4
+ image: (position, total) => `Image ${position} of ${total}`,
5
+ frame: (position, total, alt) => `Image ${position} of ${total}${alt ? `: ${alt}` : ""}`,
6
+ previous: "Previous image",
7
+ next: "Next image",
8
+ dots: "Choose an image",
9
+ thumbnails: "Image thumbnails",
10
+ counter: (position, total) => `${position} / ${total}`,
11
+ zoomHint: "Click to zoom",
12
+ openLightbox: (position, total) => `View image ${position} of ${total} full screen`,
13
+ zoomImage: (position, total) => `Zoom image ${position} of ${total}`,
14
+ playVideo: "Play video",
15
+ imageUnavailable: "Image unavailable",
16
+ loading: "Loading product images",
17
+ };
@@ -0,0 +1,78 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { Box, Flex, Text } from "@chakra-ui/react";
4
+ import { ChevronLeft, ChevronRight, X } from "lucide-react";
5
+ import Modal, { ModalBody } from "../Modal/Modal.js";
6
+ import ViewerIconButton from "../MediaViewer/components/ViewerIconButton.js";
7
+ import { useViewerChrome } from "../MediaViewer/useViewerChrome.js";
8
+ import { useCustomTheme } from "../../Theme/useCustomTheme.js";
9
+ import { overlayScrim } from "../../Theme/tokens/builders/scrim.js";
10
+ import { fullViewportHeight } from "../../Theme/tokens/builders/viewportHeight.js";
11
+ import { reducedMotionSx, usePrefersReducedMotion } from "../../Theme/chakra/motion.js";
12
+ import MediaFrame from "./MediaFrame.js";
13
+ import MediaThumb from "./MediaThumb.js";
14
+ import { fadeIn } from "./motion.js";
15
+ import { clampIndex, indexForKey, keyBelongsToTarget } from "./mediaGalleryModel.js";
16
+ import { defaultMediaLightboxLabels } from "./MediaLightboxProps.js";
17
+ const SWIPE_MIN_PX = 50;
18
+ /** Full-screen product media viewer: counter and close on top, arrows, thumbnail row, Esc and arrow keys. */
19
+ const MediaLightbox = ({ isOpen, onClose, items, index, defaultIndex = 0, onIndexChange, finalFocusRef, labels: labelOverrides, }) => {
20
+ var _a;
21
+ const { colors } = useCustomTheme();
22
+ const chrome = useViewerChrome();
23
+ const reduced = usePrefersReducedMotion();
24
+ const labels = { ...defaultMediaLightboxLabels, ...labelOverrides };
25
+ const isControlled = index !== undefined;
26
+ const [own, setOwn] = useState(defaultIndex);
27
+ const total = items.length;
28
+ const current = clampIndex(isControlled ? index : own, total);
29
+ const latest = useRef(current);
30
+ latest.current = current;
31
+ const stageRef = useRef(null);
32
+ const stripRef = useRef(null);
33
+ const touchStartX = useRef(null);
34
+ const go = (next) => {
35
+ const target = clampIndex(next, total);
36
+ if (target === latest.current)
37
+ return;
38
+ latest.current = target;
39
+ if (!isControlled)
40
+ setOwn(target);
41
+ onIndexChange === null || onIndexChange === void 0 ? void 0 : onIndexChange(target);
42
+ };
43
+ useEffect(() => {
44
+ const strip = stripRef.current;
45
+ const selected = strip === null || strip === void 0 ? void 0 : strip.querySelector('[aria-current="true"]');
46
+ if (!strip || !selected)
47
+ return;
48
+ const left = selected.offsetLeft - strip.clientWidth / 2 + selected.offsetWidth / 2;
49
+ strip.scrollLeft = Math.max(0, left);
50
+ }, [current, isOpen]);
51
+ const onKeyDown = (event) => {
52
+ if (event.ctrlKey || event.metaKey || event.altKey || keyBelongsToTarget(event.target))
53
+ return;
54
+ const next = indexForKey(event.key, latest.current, total);
55
+ if (next === undefined)
56
+ return;
57
+ event.preventDefault();
58
+ go(next);
59
+ };
60
+ const onTouchEnd = (event) => {
61
+ const start = touchStartX.current;
62
+ touchStartX.current = null;
63
+ if (start === null)
64
+ return;
65
+ const dx = event.changedTouches[0].clientX - start;
66
+ if (Math.abs(dx) > SWIPE_MIN_PX)
67
+ go(latest.current + (dx < 0 ? 1 : -1));
68
+ };
69
+ const item = items[current];
70
+ if (!item)
71
+ return null;
72
+ const alt = (_a = item.alt) !== null && _a !== void 0 ? _a : labels.image(current + 1, total);
73
+ const bar = { bg: overlayScrim(colors), color: chrome.ink };
74
+ return (_jsx(Modal, { isOpen: isOpen, onClose: onClose, size: "full", hideCloseButton: true, motionPreset: reduced ? "none" : "scale", initialFocusRef: stageRef, finalFocusRef: finalFocusRef, overlaybg: overlayScrim(colors), contentProps: { bg: chrome.stage, m: 0, borderRadius: 0, "aria-label": labels.dialog }, children: _jsxs(ModalBody, { p: 0, display: "flex", flexDirection: "column", sx: fullViewportHeight, children: [_jsxs(Flex, { align: "center", justify: "space-between", gap: 2, px: 4, py: 2, ...bar, "data-testid": "media-lightbox-bar", children: [_jsx(Text, { as: "span", fontSize: "sm", fontWeight: 600, "aria-live": "polite", sx: { fontVariantNumeric: "tabular-nums" }, children: labels.counter(current + 1, total) }), _jsx(ViewerIconButton, { label: labels.close, icon: _jsx(X, { size: 20, "aria-hidden": true }), onClick: onClose, testId: "media-lightbox-close" })] }), _jsxs(Box, { ref: stageRef, tabIndex: -1, flex: 1, minH: 0, position: "relative", outline: "none", onKeyDown: onKeyDown, onTouchStart: (event) => {
75
+ touchStartX.current = event.touches.length === 1 ? event.touches[0].clientX : null;
76
+ }, onTouchEnd: onTouchEnd, "data-testid": "media-lightbox-stage", children: [_jsx(Box, { position: "absolute", inset: { base: 0, md: 6 }, animation: fadeIn(), sx: reducedMotionSx(), children: _jsx(MediaFrame, { media: item, alt: alt, fit: "contain", autoPlay: true, surface: "transparent", playLabel: labels.playVideo, unavailableLabel: labels.imageUnavailable }) }, item.id), total > 1 && (_jsxs(_Fragment, { children: [_jsx(Box, { position: "absolute", left: { base: 2, md: 4 }, top: "calc(50% - 20px)", zIndex: 2, children: _jsx(ViewerIconButton, { label: labels.previous, icon: _jsx(ChevronLeft, { size: 24, "aria-hidden": true }), onClick: () => go(current - 1), isDisabled: current === 0, round: true, testId: "media-lightbox-prev" }) }), _jsx(Box, { position: "absolute", right: { base: 2, md: 4 }, top: "calc(50% - 20px)", zIndex: 2, children: _jsx(ViewerIconButton, { label: labels.next, icon: _jsx(ChevronRight, { size: 24, "aria-hidden": true }), onClick: () => go(current + 1), isDisabled: current === total - 1, round: true, testId: "media-lightbox-next" }) })] }))] }), total > 1 && (_jsx(Flex, { as: "nav", "aria-label": labels.thumbnails, ...bar, py: 3, px: 4, justify: "center", children: _jsx(Flex, { ref: stripRef, gap: 3, p: "4px", maxW: "100%", overflowX: "auto", onKeyDown: onKeyDown, "data-testid": "media-lightbox-thumbs", children: items.map((frame, position) => (_jsx(MediaThumb, { media: frame, label: labels.frame(position + 1, total, frame.alt), selected: position === current, onSelect: () => go(position), width: 56, height: 70, ring: { gap: chrome.stage, ink: chrome.ink }, surface: chrome.raised }, frame.id))) }) }))] }) }));
77
+ };
78
+ export default MediaLightbox;
@@ -0,0 +1,12 @@
1
+ export const defaultMediaLightboxLabels = {
2
+ dialog: "Product images",
3
+ close: "Close",
4
+ previous: "Previous image",
5
+ next: "Next image",
6
+ counter: (position, total) => `${position} / ${total}`,
7
+ thumbnails: "Image thumbnails",
8
+ frame: (position, total, alt) => `Image ${position} of ${total}${alt ? `: ${alt}` : ""}`,
9
+ image: (position, total) => `Image ${position} of ${total}`,
10
+ playVideo: "Play video",
11
+ imageUnavailable: "Image unavailable",
12
+ };
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useState } from "react";
3
+ import { Box, Flex } from "@chakra-ui/react";
4
+ import { Play, Video } from "lucide-react";
5
+ import { useCustomTheme } from "../../Theme/useCustomTheme.js";
6
+ import { overlayScrim } from "../../Theme/tokens/builders/scrim.js";
7
+ import { transitionFor } from "../../Theme/tokens/primitives/motion.js";
8
+ import { reducedMotionSx } from "../../Theme/chakra/motion.js";
9
+ import { focusVisibleStyles } from "../../Theme/chakra/focusRing.styles.js";
10
+ import { frameThumb } from "./mediaGalleryModel.js";
11
+ /** Selectable thumbnail: ring and full opacity when current, `aria-current` for assistive tech. */
12
+ const MediaThumb = ({ media, label, selected, onSelect, width, height, ring, surface }) => {
13
+ const { colors } = useCustomTheme();
14
+ const [loaded, setLoaded] = useState(false);
15
+ const [failed, setFailed] = useState(false);
16
+ const src = frameThumb(media);
17
+ const settle = useCallback((node) => {
18
+ if (node && node.complete && node.naturalWidth > 0)
19
+ setLoaded(true);
20
+ }, []);
21
+ return (_jsxs(Box, { as: "button", type: "button", onClick: onSelect, "aria-label": label, "aria-current": selected ? "true" : undefined, position: "relative", flexShrink: 0, w: `${width}px`, h: `${height}px`, p: 0, border: "0", borderRadius: "xl", overflow: "hidden", cursor: "pointer", bg: surface !== null && surface !== void 0 ? surface : colors.background[100], opacity: selected ? 1 : 0.72, boxShadow: selected ? `0 0 0 2px ${ring.gap}, 0 0 0 4px ${ring.ink}` : "none", transition: transitionFor(["box-shadow", "opacity", "transform"]), _hover: { opacity: 1, transform: "translateY(-1px)" }, sx: { ...focusVisibleStyles(colors), ...reducedMotionSx({ transform: "none" }) }, children: [src && !failed ? (_jsx(Box, { as: "img", ref: settle, src: src, alt: "", loading: "lazy", decoding: "async", draggable: false, onLoad: () => setLoaded(true), onError: () => setFailed(true), position: "absolute", inset: 0, w: "100%", h: "100%", objectFit: "cover", opacity: loaded ? 1 : 0, transition: transitionFor(["opacity"], "base") })) : (_jsx(Flex, { position: "absolute", inset: 0, align: "center", justify: "center", color: colors.textMuted, "aria-hidden": true, children: _jsx(Video, { size: 20 }) })), media.type === "video" && (_jsx(Flex, { position: "absolute", inset: 0, align: "center", justify: "center", color: colors.white, "aria-hidden": true, children: _jsx(Flex, { boxSize: 6, align: "center", justify: "center", borderRadius: "full", bg: overlayScrim(colors), children: _jsx(Play, { size: 12, fill: "currentColor" }) }) }))] }));
22
+ };
23
+ export default MediaThumb;
@@ -0,0 +1,42 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import { Box, Flex } from "@chakra-ui/react";
4
+ import { useCustomTheme } from "../../Theme/useCustomTheme.js";
5
+ import { hexToRgb } from "../../Theme/tokens/builders/color.js";
6
+ import { transitionFor } from "../../Theme/tokens/primitives/motion.js";
7
+ import { reducedMotionSx } from "../../Theme/chakra/motion.js";
8
+ import { focusVisibleStyles } from "../../Theme/chakra/focusRing.styles.js";
9
+ const GLASS_ALPHA = 0.72;
10
+ const GLASS_ALPHA_HOVER = 0.9;
11
+ const BLUR = "blur(20px) saturate(180%)";
12
+ const NO_BLUR_SUPPORT = "@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)))";
13
+ const tint = (colors, alpha) => {
14
+ const { r, g, b } = hexToRgb(colors.background[50]);
15
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
16
+ };
17
+ /** Translucent surface over a photo: the page canvas at 72%, blurred, opaque where blur is unsupported. */
18
+ export const glassStyles = (colors, hover = false) => ({
19
+ bg: tint(colors, hover ? GLASS_ALPHA_HOVER : GLASS_ALPHA),
20
+ color: colors.header[900],
21
+ backdropFilter: BLUR,
22
+ sx: { WebkitBackdropFilter: BLUR, [NO_BLUR_SUPPORT]: { backgroundColor: colors.background[50] } },
23
+ });
24
+ /** 36 or 44 px glass circle with a 44 px hit area; fades out instead of unmounting when disabled. */
25
+ export const GlassIconButton = forwardRef(({ label, icon, onClick, size = 36, isDisabled = false, tabIndex, ...placement }, ref) => {
26
+ const { colors } = useCustomTheme();
27
+ const glass = glassStyles(colors);
28
+ const reach = Math.max(0, (44 - size) / 2);
29
+ return (_jsx(Box, { as: "button", ref: ref, type: "button", "aria-label": label, onClick: onClick, disabled: isDisabled, tabIndex: tabIndex, display: "inline-flex", alignItems: "center", justifyContent: "center", w: `${size}px`, h: `${size}px`, borderRadius: "full", position: "absolute", flexShrink: 0, cursor: "pointer", opacity: isDisabled ? 0 : 1, pointerEvents: isDisabled ? "none" : "auto", transition: transitionFor(["opacity", "background-color"]), _hover: { bg: tint(colors, GLASS_ALPHA_HOVER) }, ...glass, sx: {
30
+ ...glass.sx,
31
+ ...focusVisibleStyles(colors),
32
+ "&::after": { content: '""', position: "absolute", inset: `-${reach}px` },
33
+ ...reducedMotionSx(),
34
+ }, ...placement, children: icon }));
35
+ });
36
+ GlassIconButton.displayName = "GlassIconButton";
37
+ /** Non-interactive glass capsule for the counter and zoom hint. */
38
+ export const GlassPill = ({ children, height = 28, ...placement }) => {
39
+ const { colors } = useCustomTheme();
40
+ const glass = glassStyles(colors);
41
+ return (_jsx(Flex, { align: "center", gap: 1.5, h: `${height}px`, px: 3, borderRadius: "full", position: "absolute", fontSize: "xs", fontWeight: 600, pointerEvents: "none", whiteSpace: "nowrap", ...glass, sx: { ...glass.sx, fontVariantNumeric: "tabular-nums" }, ...placement, children: children }));
42
+ };
@@ -0,0 +1,71 @@
1
+ const YOUTUBE = [
2
+ /youtube\.com\/watch\?[^#]*v=([A-Za-z0-9_-]{6,})/i,
3
+ /youtube\.com\/(?:embed|shorts|live)\/([A-Za-z0-9_-]{6,})/i,
4
+ /youtu\.be\/([A-Za-z0-9_-]{6,})/i,
5
+ ];
6
+ const VIMEO = [/vimeo\.com\/(?:video\/)?(\d+)/i];
7
+ const firstMatch = (patterns, url) => {
8
+ for (const pattern of patterns) {
9
+ const found = pattern.exec(url);
10
+ if (found)
11
+ return found[1];
12
+ }
13
+ return undefined;
14
+ };
15
+ /** Only whitelisted ids reach an iframe `src`, so a product feed can never inject an arbitrary frame URL. */
16
+ export const parseEmbed = (url) => {
17
+ const youtube = firstMatch(YOUTUBE, url);
18
+ if (youtube) {
19
+ return {
20
+ provider: "youtube",
21
+ id: youtube,
22
+ src: `https://www.youtube.com/embed/${youtube}?rel=0&autoplay=1`,
23
+ poster: `https://img.youtube.com/vi/${youtube}/hqdefault.jpg`,
24
+ };
25
+ }
26
+ const vimeo = firstMatch(VIMEO, url);
27
+ if (vimeo)
28
+ return { provider: "vimeo", id: vimeo, src: `https://player.vimeo.com/video/${vimeo}?autoplay=1` };
29
+ return undefined;
30
+ };
31
+ export const frameKind = (media) => {
32
+ if (media.type !== "video")
33
+ return "image";
34
+ return parseEmbed(media.src) ? "embed" : "video";
35
+ };
36
+ /** Still image to show for a frame before it plays, if the data offers one. */
37
+ export const framePoster = (media) => {
38
+ var _a, _b;
39
+ if (media.type !== "video")
40
+ return media.src;
41
+ return (_a = media.poster) !== null && _a !== void 0 ? _a : (_b = parseEmbed(media.src)) === null || _b === void 0 ? void 0 : _b.poster;
42
+ };
43
+ export const frameThumb = (media) => { var _a; return (_a = media.thumb) !== null && _a !== void 0 ? _a : (media.type === "video" ? framePoster(media) : media.src); };
44
+ /** `activeMediaIds` order wins; unknown ids are dropped; an empty result falls back to every frame. */
45
+ export const resolveFrames = (media, activeMediaIds) => {
46
+ if (!activeMediaIds)
47
+ return media;
48
+ const byId = new Map(media.map((item) => [item.id, item]));
49
+ const picked = activeMediaIds.flatMap((id) => {
50
+ const found = byId.get(id);
51
+ return found ? [found] : [];
52
+ });
53
+ return picked.length > 0 ? picked : media;
54
+ };
55
+ export const clampIndex = (index, count) => count <= 0 ? 0 : Math.min(Math.max(Math.trunc(index) || 0, 0), count - 1);
56
+ /** Where a navigation key lands, or undefined when the key is not navigation. */
57
+ export const indexForKey = (key, index, count) => {
58
+ if (key === "ArrowLeft")
59
+ return clampIndex(index - 1, count);
60
+ if (key === "ArrowRight")
61
+ return clampIndex(index + 1, count);
62
+ if (key === "Home")
63
+ return 0;
64
+ if (key === "End")
65
+ return clampIndex(count - 1, count);
66
+ return undefined;
67
+ };
68
+ const OWN_KEYS = "video, iframe, input, textarea, select, [contenteditable='true']";
69
+ /** Arrow keys belong to a focused video, iframe or field, never to the carousel. */
70
+ export const keyBelongsToTarget = (target) => target instanceof Element && target.closest(OWN_KEYS) !== null;
71
+ export const frameSignature = (frames) => frames.map((frame) => frame.id).join("|");
@@ -0,0 +1,8 @@
1
+ import { keyframes } from "@emotion/react";
2
+ import { MOTION_EASE } from "../../Theme/tokens/primitives/motion.js";
3
+ /** Frame change: one slide per gesture, `transform` only. */
4
+ export const SLIDE_MS = 320;
5
+ /** Colour-linked frame set swap and the lightbox frame change. */
6
+ export const CROSSFADE_MS = 160;
7
+ const fade = keyframes `from { opacity: 0; } to { opacity: 1; }`;
8
+ export const fadeIn = (ms = CROSSFADE_MS) => `${fade} ${ms}ms ${MOTION_EASE} both`;
@@ -0,0 +1,16 @@
1
+ import { useEffect, useState } from "react";
2
+ const supported = () => typeof window !== "undefined" && typeof window.matchMedia === "function";
3
+ /** `matches` for a media query, or `fallback` where matchMedia does not exist (SSR, jsdom). */
4
+ export const useMatchMedia = (query, fallback) => {
5
+ const [matches, setMatches] = useState(() => (supported() ? window.matchMedia(query).matches : fallback));
6
+ useEffect(() => {
7
+ if (!supported())
8
+ return undefined;
9
+ const list = window.matchMedia(query);
10
+ const onChange = () => setMatches(list.matches);
11
+ onChange();
12
+ list.addEventListener("change", onChange);
13
+ return () => list.removeEventListener("change", onChange);
14
+ }, [query]);
15
+ return matches;
16
+ };
@@ -0,0 +1,81 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useId, useRef, useState } from "react";
3
+ import { Box, Flex, Text, VisuallyHidden } from "@chakra-ui/react";
4
+ import { Check, ChevronDown, Tag } from "lucide-react";
5
+ import { useCustomTheme } from "../../Theme/useCustomTheme.js";
6
+ import { transitionFor } from "../../Theme/tokens/primitives/motion.js";
7
+ import { reducedMotionSx } from "../../Theme/chakra/motion.js";
8
+ import { focusVisibleStyles } from "../../Theme/chakra/focusRing.styles.js";
9
+ const COPIED_MS = 1600;
10
+ const DEFAULT_LABELS = {
11
+ summary: (count, best) => `Offers (${count}) · Best: ${best}`,
12
+ summaryCount: (count) => `Offers (${count})`,
13
+ copy: "Copy",
14
+ copied: "Copied",
15
+ copyCode: (code) => `Copy code ${code}`,
16
+ copiedMessage: (code) => `Code ${code} copied`,
17
+ };
18
+ const writeToClipboard = (code) => {
19
+ var _a;
20
+ try {
21
+ const pending = (_a = navigator.clipboard) === null || _a === void 0 ? void 0 : _a.writeText(code);
22
+ pending === null || pending === void 0 ? void 0 : pending.catch(() => undefined);
23
+ }
24
+ catch {
25
+ return;
26
+ }
27
+ };
28
+ /** One collapsed tonal row ("Offers (3) · Best: ...") that opens into the full list with copy-code buttons; renders nothing for no offers. */
29
+ const OffersList = ({ offers, bestOfferId, isOpen, defaultOpen = false, onOpenChange, onCopy, labels, "data-testid": testId, }) => {
30
+ var _a;
31
+ const { colors } = useCustomTheme();
32
+ const panelId = useId();
33
+ const [innerOpen, setInnerOpen] = useState(defaultOpen);
34
+ const [copiedId, setCopiedId] = useState(null);
35
+ const [message, setMessage] = useState("");
36
+ const timer = useRef();
37
+ const copy = { ...DEFAULT_LABELS, ...labels };
38
+ const open = isOpen !== null && isOpen !== void 0 ? isOpen : innerOpen;
39
+ useEffect(() => () => clearTimeout(timer.current), []);
40
+ if (offers.length === 0)
41
+ return null;
42
+ const best = (_a = offers.find((offer) => offer.id === bestOfferId)) !== null && _a !== void 0 ? _a : offers[0];
43
+ const summary = offers.length === 1
44
+ ? `${best.title} · ${best.detail}`
45
+ : best.title
46
+ ? copy.summary(offers.length, best.title)
47
+ : copy.summaryCount(offers.length);
48
+ const toggle = () => {
49
+ const next = !open;
50
+ if (isOpen === undefined)
51
+ setInnerOpen(next);
52
+ onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(next);
53
+ };
54
+ const copyCode = (offer, code) => {
55
+ writeToClipboard(code);
56
+ setCopiedId(offer.id);
57
+ setMessage(copy.copiedMessage(code));
58
+ clearTimeout(timer.current);
59
+ timer.current = setTimeout(() => {
60
+ setCopiedId(null);
61
+ setMessage("");
62
+ }, COPIED_MS);
63
+ onCopy === null || onCopy === void 0 ? void 0 : onCopy(offer);
64
+ };
65
+ return (_jsxs(Box, { bg: colors.background[100], borderRadius: "xl", overflow: "hidden", "data-testid": testId, children: [_jsxs(Flex, { as: "button", type: "button", w: "100%", minH: "3rem", px: 4, py: 3, align: "center", gap: 3, textAlign: "left", borderRadius: "xl", color: colors.header[900], "aria-expanded": open, "aria-controls": panelId, onClick: toggle, transition: transitionFor(["background-color"]), _hover: { bg: colors.background[200] }, sx: { ...focusVisibleStyles(colors), ...reducedMotionSx() }, children: [_jsx(Box, { as: "span", "aria-hidden": true, display: "inline-flex", flexShrink: 0, color: colors.accentText, children: _jsx(Tag, { size: 18 }) }), _jsx(Text, { as: "span", flex: "1", minW: 0, fontSize: "sm", fontWeight: 600, noOfLines: open ? undefined : 1, children: summary }), _jsx(Box, { as: "span", "aria-hidden": true, display: "inline-flex", flexShrink: 0, color: colors.textMuted, transform: open ? "rotate(180deg)" : "rotate(0deg)", transition: transitionFor(["transform"]), sx: reducedMotionSx(), children: _jsx(ChevronDown, { size: 18 }) })] }), _jsx(Box, { id: panelId, hidden: !open, children: _jsx(Box, { as: "ul", listStyleType: "none", m: 0, px: 4, pb: 2, children: offers.map((offer) => {
66
+ const copied = copiedId === offer.id;
67
+ const { code } = offer;
68
+ return (_jsxs(Flex, { as: "li", position: "relative", align: "center", justify: "space-between", gap: 3, py: 3, sx: {
69
+ "&:not(:first-of-type)::before": {
70
+ content: '""',
71
+ position: "absolute",
72
+ top: 0,
73
+ left: 0,
74
+ right: 0,
75
+ height: "1px",
76
+ background: colors.background[200],
77
+ },
78
+ }, children: [_jsxs(Box, { minW: 0, children: [_jsx(Text, { fontSize: "sm", fontWeight: 600, color: colors.header[900], children: offer.title }), _jsx(Text, { mt: 0.5, fontSize: "sm", lineHeight: 1.45, color: colors.textMuted, children: offer.detail })] }), code ? (_jsxs(Flex, { align: "center", gap: 1, flexShrink: 0, children: [_jsx(Text, { as: "span", px: 2.5, py: 1, borderRadius: "md", bg: colors.background[200], color: colors.header[900], fontSize: "xs", fontWeight: 700, letterSpacing: "0.06em", sx: { fontVariantNumeric: "tabular-nums" }, children: code }), _jsxs(Flex, { as: "button", type: "button", align: "center", gap: 1.5, minH: "2.75rem", px: 3, borderRadius: "lg", fontSize: "sm", fontWeight: 600, color: colors.accentText, "aria-label": copied ? undefined : copy.copyCode(code), onClick: () => copyCode(offer, code), transition: transitionFor(["background-color"]), _hover: { bg: colors.background[200] }, sx: { ...focusVisibleStyles(colors), ...reducedMotionSx() }, children: [copied ? _jsx(Check, { size: 16, "aria-hidden": true }) : null, _jsx("span", { children: copied ? copy.copied : copy.copy })] })] })) : null] }, offer.id));
79
+ }) }) }), _jsx(VisuallyHidden, { "aria-live": "polite", children: message })] }));
80
+ };
81
+ export default OffersList;
@@ -0,0 +1 @@
1
+ export {};