@evolve.ui/core-components 1.0.1 → 1.2.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 (670) hide show
  1. package/{BottomSheet-ZV_eq3xt.mjs → BottomSheet-CNVLnEoD.mjs} +3 -3
  2. package/BottomSheet-CNVLnEoD.mjs.map +1 -0
  3. package/{BottomSheet-emWP9Fct.cjs → BottomSheet-D5w0WZDl.cjs} +3 -3
  4. package/BottomSheet-D5w0WZDl.cjs.map +1 -0
  5. package/Button.cjs +1 -1
  6. package/Button.mjs +1 -1
  7. package/{CookieConsent-CIwm0bTz.mjs → CookieConsent-B9dg9WdC.mjs} +2 -2
  8. package/{CookieConsent-CIwm0bTz.mjs.map → CookieConsent-B9dg9WdC.mjs.map} +1 -1
  9. package/{CookieConsent-PIglB_bb.cjs → CookieConsent-BSXJHMwX.cjs} +2 -2
  10. package/{CookieConsent-PIglB_bb.cjs.map → CookieConsent-BSXJHMwX.cjs.map} +1 -1
  11. package/{Drawer-9HFG45OA.cjs → Drawer-3rA9dGCl.cjs} +2 -2
  12. package/{Drawer-9HFG45OA.cjs.map → Drawer-3rA9dGCl.cjs.map} +1 -1
  13. package/Drawer-CFZbwg0R.d.cts.map +1 -1
  14. package/Drawer-CFZbwg0R.d.mts.map +1 -1
  15. package/{Drawer-BkCPfK6P.mjs → Drawer-DzKEmewj.mjs} +2 -2
  16. package/{Drawer-BkCPfK6P.mjs.map → Drawer-DzKEmewj.mjs.map} +1 -1
  17. package/{FavoriteButton-CC3qL0lR.mjs → FavoriteButton-7nK77lQP.mjs} +6 -6
  18. package/FavoriteButton-7nK77lQP.mjs.map +1 -0
  19. package/{FavoriteButton-BGF-3dze.d.cts → FavoriteButton-B8r_qtlj.d.cts} +2 -2
  20. package/{FavoriteButton-BGF-3dze.d.cts.map → FavoriteButton-B8r_qtlj.d.cts.map} +1 -1
  21. package/{FavoriteButton-DliYzkfu.cjs → FavoriteButton-BkIaWfgD.cjs} +6 -6
  22. package/FavoriteButton-BkIaWfgD.cjs.map +1 -0
  23. package/{FavoriteButton-BZEGWrRo.d.mts → FavoriteButton-hIkGjcKH.d.mts} +2 -2
  24. package/{FavoriteButton-BZEGWrRo.d.mts.map → FavoriteButton-hIkGjcKH.d.mts.map} +1 -1
  25. package/{FileUpload-p_pl9NXr.mjs → FileUpload-BfZOMsLs.mjs} +6 -6
  26. package/FileUpload-BfZOMsLs.mjs.map +1 -0
  27. package/{FileUpload--e_UJ_ek.cjs → FileUpload-gjRbkgrL.cjs} +6 -6
  28. package/FileUpload-gjRbkgrL.cjs.map +1 -0
  29. package/IconButton.cjs +1 -1
  30. package/IconButton.mjs +1 -1
  31. package/{ImageSlider-BidXfnLj.cjs → ImageSlider-CAgxQffP.cjs} +3 -3
  32. package/ImageSlider-CAgxQffP.cjs.map +1 -0
  33. package/{ImageSlider-CDrg_TbL.mjs → ImageSlider-fdrJ6lIJ.mjs} +3 -3
  34. package/ImageSlider-fdrJ6lIJ.mjs.map +1 -0
  35. package/InfoIconTooltip.cjs +1 -1
  36. package/InfoIconTooltip.cjs.map +1 -1
  37. package/InfoIconTooltip.mjs +1 -1
  38. package/InfoIconTooltip.mjs.map +1 -1
  39. package/InlineButton-CRLbNJZ3.d.mts.map +1 -1
  40. package/InlineButton-DoXGLiSE.d.cts.map +1 -1
  41. package/Input.cjs +1 -1
  42. package/Input.cjs.map +1 -1
  43. package/Input.mjs +1 -1
  44. package/Input.mjs.map +1 -1
  45. package/JumpMenu-BXYZnPIH.cjs.map +1 -1
  46. package/JumpMenu-DcZjAiej.mjs.map +1 -1
  47. package/{Menu-Cxu8CaX1.mjs → Menu-Bn4smlEe.mjs} +2 -2
  48. package/Menu-Bn4smlEe.mjs.map +1 -0
  49. package/{Menu-ClUogmwE.cjs → Menu-DuDhtoNP.cjs} +2 -2
  50. package/Menu-DuDhtoNP.cjs.map +1 -0
  51. package/Modal-DM0aXJZ5.d.cts.map +1 -1
  52. package/Modal-DM0aXJZ5.d.mts.map +1 -1
  53. package/{Modal-C6gatdtT.mjs → Modal-DtxWd7Le.mjs} +3 -2
  54. package/{Modal-C6gatdtT.mjs.map → Modal-DtxWd7Le.mjs.map} +1 -1
  55. package/{Modal-CiBqXyiK.cjs → Modal-q4HhBAQU.cjs} +3 -2
  56. package/Modal-q4HhBAQU.cjs.map +1 -0
  57. package/{Pagination-bAtbN478.cjs → Pagination-Denb9_zB.cjs} +2 -2
  58. package/{Pagination-bAtbN478.cjs.map → Pagination-Denb9_zB.cjs.map} +1 -1
  59. package/{Pagination-DIpGKMLz.mjs → Pagination-Dyfeys4B.mjs} +2 -2
  60. package/{Pagination-DIpGKMLz.mjs.map → Pagination-Dyfeys4B.mjs.map} +1 -1
  61. package/PhoneInput-B5pkpkdt.mjs.map +1 -1
  62. package/PhoneInput-BXnkBME4.d.mts.map +1 -1
  63. package/PhoneInput-Bkrbrins.d.cts.map +1 -1
  64. package/PhoneInput-CUMPOSxJ.cjs.map +1 -1
  65. package/{ProgressCircle-BC81D9sU.cjs → ProgressCircle-B6R4dxoV.cjs} +2 -2
  66. package/{ProgressCircle-BC81D9sU.cjs.map → ProgressCircle-B6R4dxoV.cjs.map} +1 -1
  67. package/{ProgressCircle-ae8cvZhe.mjs → ProgressCircle-zSai1HTT.mjs} +2 -2
  68. package/{ProgressCircle-ae8cvZhe.mjs.map → ProgressCircle-zSai1HTT.mjs.map} +1 -1
  69. package/SearchInput-DYIPC8Cd.d.cts.map +1 -1
  70. package/SearchInput-IfEWePDQ.d.mts.map +1 -1
  71. package/{Select-BkZu8OLs.mjs → Select-CH_ZN88G.mjs} +2 -2
  72. package/Select-CH_ZN88G.mjs.map +1 -0
  73. package/{Select-BXDjzyDs.cjs → Select-DCCcyLT4.cjs} +2 -2
  74. package/Select-DCCcyLT4.cjs.map +1 -0
  75. package/{SplitButton-DcmmLW8j.cjs → SplitButton-B_Y253RU.cjs} +2 -2
  76. package/{SplitButton-DcmmLW8j.cjs.map → SplitButton-B_Y253RU.cjs.map} +1 -1
  77. package/{SplitButton-WE5ymwCQ.mjs → SplitButton-_poP9Ykq.mjs} +2 -2
  78. package/{SplitButton-WE5ymwCQ.mjs.map → SplitButton-_poP9Ykq.mjs.map} +1 -1
  79. package/{Table-M-rANdMt.mjs → Table-CQGtDpvH.mjs} +3 -3
  80. package/{Table-M-rANdMt.mjs.map → Table-CQGtDpvH.mjs.map} +1 -1
  81. package/{Table-CLlDragJ.cjs → Table-D4UYosb1.cjs} +3 -3
  82. package/{Table-CLlDragJ.cjs.map → Table-D4UYosb1.cjs.map} +1 -1
  83. package/Typography/InlineButton.cjs +1 -1
  84. package/Typography/InlineButton.cjs.map +1 -1
  85. package/Typography/InlineButton.mjs +1 -1
  86. package/Typography/InlineButton.mjs.map +1 -1
  87. package/{ViewMore-BBoUvo7p.cjs → ViewMore-BcoSRZSl.cjs} +14 -1
  88. package/ViewMore-BcoSRZSl.cjs.map +1 -0
  89. package/{ViewMore-BrZPuE4E.mjs → ViewMore-Be0TQZ_2.mjs} +14 -1
  90. package/ViewMore-Be0TQZ_2.mjs.map +1 -0
  91. package/bottomSheet.cjs +1 -1
  92. package/bottomSheet.mjs +1 -1
  93. package/{buttonColorClasses-C3hg1at8.cjs → buttonColorClasses-CQQmLYfk.cjs} +4 -4
  94. package/buttonColorClasses-CQQmLYfk.cjs.map +1 -0
  95. package/{buttonColorClasses-B7OU4aQA.mjs → buttonColorClasses-CQnqAJXl.mjs} +4 -4
  96. package/buttonColorClasses-CQnqAJXl.mjs.map +1 -0
  97. package/card/components/createFavoriteButton.cjs +1 -1
  98. package/card/components/createFavoriteButton.mjs +1 -1
  99. package/cookieConsent.cjs +1 -1
  100. package/cookieConsent.mjs +1 -1
  101. package/drawer.cjs +1 -1
  102. package/drawer.mjs +1 -1
  103. package/evolve-ui.entries.json +556 -0
  104. package/favoriteButton.cjs +1 -1
  105. package/favoriteButton.d.cts +1 -1
  106. package/favoriteButton.d.mts +1 -1
  107. package/favoriteButton.mjs +1 -1
  108. package/featureFlags/hooks.d.cts +1 -1
  109. package/featureFlags/hooks.d.mts +1 -1
  110. package/fileUpload.cjs +1 -1
  111. package/fileUpload.mjs +1 -1
  112. package/imageSlider.cjs +1 -1
  113. package/imageSlider.mjs +1 -1
  114. package/index.cjs +14 -14
  115. package/index.d.cts +1 -1
  116. package/index.d.mts +1 -1
  117. package/index.mjs +14 -14
  118. package/menu.cjs +1 -1
  119. package/menu.mjs +1 -1
  120. package/modal/useCloseModal.cjs +2 -1
  121. package/modal/useCloseModal.cjs.map +1 -1
  122. package/modal/useCloseModal.mjs +2 -1
  123. package/modal/useCloseModal.mjs.map +1 -1
  124. package/modal.cjs +1 -1
  125. package/modal.mjs +1 -1
  126. package/package.json +2 -4
  127. package/pagination.cjs +1 -1
  128. package/pagination.mjs +1 -1
  129. package/progressCircle.cjs +1 -1
  130. package/progressCircle.mjs +1 -1
  131. package/searchInput.cjs +4 -4
  132. package/searchInput.cjs.map +1 -1
  133. package/searchInput.mjs +4 -4
  134. package/searchInput.mjs.map +1 -1
  135. package/select.cjs +1 -1
  136. package/select.mjs +1 -1
  137. package/selectAsync.cjs +1 -1
  138. package/selectAsync.mjs +1 -1
  139. package/selectAsyncCreatable.cjs +1 -1
  140. package/selectAsyncCreatable.mjs +1 -1
  141. package/selectCreatable.cjs +1 -1
  142. package/selectCreatable.mjs +1 -1
  143. package/splitButton.cjs +1 -1
  144. package/splitButton.mjs +1 -1
  145. package/src/Accordion/Accordion.tsx +233 -0
  146. package/src/AddressDisplay/AddressDisplay.tsx +43 -0
  147. package/src/AddressDisplay/components/addressComponents.tsx +111 -0
  148. package/src/AddressDisplay/components/addressField.tsx +25 -0
  149. package/src/AddressDisplay/components/addressSection.tsx +8 -0
  150. package/src/AddressDisplay/components/getCountryValue.tsx +31 -0
  151. package/src/AddressDisplay/types.ts +26 -0
  152. package/src/AutomatedCarousel/AutomatedCarousel.tsx +163 -0
  153. package/src/AutomatedCarousel/automatedCarousel.types.ts +7 -0
  154. package/src/AutomatedCarousel/components/CarouselProgressBar/CarouselProgressBar.tsx +139 -0
  155. package/src/AutomatedCarousel/components/CarouselProgressBar/components/CarouselProgressBarUnit/CarouselProgressBarUnit.tsx +165 -0
  156. package/src/Badge/Badge.tsx +104 -0
  157. package/src/Badge/Badge.types.ts +58 -0
  158. package/src/Badge/ItemBadge.tsx +97 -0
  159. package/src/Badge/LiveStatusBadge.tsx +93 -0
  160. package/src/BannerNotification/BannerNotification.tsx +157 -0
  161. package/src/BannerNotification/components/BannerNotificationSkeleton.tsx +39 -0
  162. package/src/BannerNotification/components/CalloutIcon/BannerIcon.tsx +48 -0
  163. package/src/BannerNotification/utils/getRandomTooltipId.ts +3 -0
  164. package/src/BottomSheet/BottomSheet.tsx +476 -0
  165. package/src/BottomSheet/components/BottomSheetBackdrop/BottomSheetBackdrop.tsx +47 -0
  166. package/src/BottomSheet/components/BottomSheetContentArea/BottomSheetContentArea.tsx +93 -0
  167. package/src/BottomSheet/components/BottomSheetOverlay/BottomSheetOverlayTranslate3d.tsx +199 -0
  168. package/src/BottomSheet/components/SheetDescription/SheetDescription.tsx +22 -0
  169. package/src/BottomSheet/components/SheetTitle/SheetTitle.tsx +21 -0
  170. package/src/BottomSheet/components/index.tsx +5 -0
  171. package/src/BottomSheet/hooks/index.tsx +13 -0
  172. package/src/BottomSheet/hooks/useAriaHider.tsx +91 -0
  173. package/src/BottomSheet/hooks/useBottomSheetServices.tsx +224 -0
  174. package/src/BottomSheet/hooks/useDragHandler.tsx +282 -0
  175. package/src/BottomSheet/hooks/useFocusTrap.tsx +113 -0
  176. package/src/BottomSheet/hooks/useLayoutEffect.tsx +4 -0
  177. package/src/BottomSheet/hooks/useOptimizedResizeObserver.tsx +94 -0
  178. package/src/BottomSheet/hooks/useOptimizedScrollState.tsx +87 -0
  179. package/src/BottomSheet/hooks/useReady.tsx +34 -0
  180. package/src/BottomSheet/hooks/useReducedMotion.tsx +22 -0
  181. package/src/BottomSheet/hooks/useScrollLock.tsx +143 -0
  182. package/src/BottomSheet/hooks/useSnapPoints.tsx +355 -0
  183. package/src/BottomSheet/hooks/useSpring.tsx +47 -0
  184. package/src/BottomSheet/hooks/useSpringInterpolationsTranslate3d.tsx +101 -0
  185. package/src/BottomSheet/index.tsx +237 -0
  186. package/src/BottomSheet/state/atoms.ts +147 -0
  187. package/src/BottomSheet/state/useBottomSheetStateMachine.ts +246 -0
  188. package/src/BottomSheet/types.ts +172 -0
  189. package/src/BottomSheet/utils.ts +65 -0
  190. package/src/Breadcrumbs/Breadcrumbs.tsx +126 -0
  191. package/src/Button/Button.tsx +164 -0
  192. package/src/Button/Button.types.ts +80 -0
  193. package/src/Button/buttonColorClasses.ts +58 -0
  194. package/src/Callout/Callout.tsx +136 -0
  195. package/src/Callout/Callout.types.ts +29 -0
  196. package/src/Callout/components/CalloutIcon/CalloutIcon.tsx +56 -0
  197. package/src/Card/CardGrid.tsx +263 -0
  198. package/src/Card/SingleCard.tsx +22 -0
  199. package/src/Card/cardFactory.tsx +176 -0
  200. package/src/Card/components/createBadge.tsx +34 -0
  201. package/src/Card/components/createFavoriteButton.tsx +40 -0
  202. package/src/Card/components/createImage.tsx +64 -0
  203. package/src/Card/components/createInfo.tsx +84 -0
  204. package/src/Card/components/createName.tsx +63 -0
  205. package/src/Card/components/createPriceStatus.tsx +100 -0
  206. package/src/Card/components/types.ts +4 -0
  207. package/src/Card/hooks/useCardVisibilityTracking.ts +82 -0
  208. package/src/Card/sharedProps.ts +12 -0
  209. package/src/Card/types.ts +62 -0
  210. package/src/Carousel/Carousel.tsx +513 -0
  211. package/src/Carousel/Carousel.types.ts +43 -0
  212. package/src/Carousel/Carousel.utils.ts +63 -0
  213. package/src/Carousel/components/DotButton/DotButton.tsx +42 -0
  214. package/src/Carousel/components/NavigationButtons/NavigationButtons.tsx +77 -0
  215. package/src/Carousel/components/TitleSection/TitleSection.tsx +61 -0
  216. package/src/Carousel/components/TitleSection/components/SubHeaderLeft/SubHeaderLeft.tsx +53 -0
  217. package/src/Carousel/components/TitleSection/components/Title/Title.tsx +46 -0
  218. package/src/Carousel/index.ts +2 -0
  219. package/src/Carousel/testUtils.ts +10 -0
  220. package/src/Chips/Chip.tsx +153 -0
  221. package/src/Chips/ChipGroup.tsx +173 -0
  222. package/src/Chips/SuggestionChip.tsx +15 -0
  223. package/src/Chips/chipTypes.ts +113 -0
  224. package/src/Chips/index.ts +4 -0
  225. package/src/ChoiceListItem/Checkbox.tsx +69 -0
  226. package/src/ChoiceListItem/Radio.tsx +61 -0
  227. package/src/ChoiceListItem/choiceListItem.tsx +99 -0
  228. package/src/ChoiceListItem/common.tsx +148 -0
  229. package/src/ChoiceListItem/index.ts +3 -0
  230. package/src/Collapsible/Collapsible.tsx +58 -0
  231. package/src/Confetti/Confetti.tsx +270 -0
  232. package/src/Confetti/index.ts +2 -0
  233. package/src/ContentPager/ContentPager.tsx +189 -0
  234. package/src/ContentPager/components/Page.tsx +24 -0
  235. package/src/CookieConsent/components/CookieCategoryRow/CookieCategoryRow.tsx +30 -0
  236. package/src/CookieConsent/components/CookieConsent/CookieConsent.tsx +74 -0
  237. package/src/CookieConsent/components/CookieConsentBanner/CookieConsentBanner.tsx +51 -0
  238. package/src/CookieConsent/components/CookieConsentModal/CookieConsentModal.tsx +64 -0
  239. package/src/CookieConsent/hooks/useCookieConsent.ts +170 -0
  240. package/src/CookieConsent/hooks/useCookieConsentState.ts +142 -0
  241. package/src/CookieConsent/index.ts +16 -0
  242. package/src/CookieConsent/types/cookieConsent.types.ts +79 -0
  243. package/src/CookieConsent/types/index.ts +7 -0
  244. package/src/Countdown/Countdown.tsx +161 -0
  245. package/src/Countdown/Countdown.types.ts +4 -0
  246. package/src/Countdown/hooks/useGetCountdown.ts +103 -0
  247. package/src/DateTimeInput/dateInput/DateInput.tsx +199 -0
  248. package/src/DateTimeInput/datePicker/DatePicker.tsx +138 -0
  249. package/src/DateTimeInput/datePicker/components/calendar/Calendar.tsx +72 -0
  250. package/src/DateTimeInput/datePicker/index.ts +2 -0
  251. package/src/DateTimeInput/timeInput/TimeInput.tsx +128 -0
  252. package/src/DateTimeInput/timePicker/TimePicker.tsx +118 -0
  253. package/src/DateTimeInput/timePicker/components/TimePopover/AmPmSwitch.tsx +103 -0
  254. package/src/DateTimeInput/timePicker/components/TimePopover/TimeFieldInput.tsx +26 -0
  255. package/src/DateTimeInput/timePicker/components/TimePopover/TimePopover.tsx +84 -0
  256. package/src/DateTimeInput/timePicker/components/TimePopover/TimePopover.utils.ts +67 -0
  257. package/src/DateTimeInput/timePicker/components/TimePopover/TimePopoverActions.tsx +26 -0
  258. package/src/DateTimeInput/timePicker/index.ts +2 -0
  259. package/src/DateTimeInput/utils/getDisplayDate.ts +15 -0
  260. package/src/DateTimeInput/utils/getDisplayTime.ts +15 -0
  261. package/src/DateTimeInput/utils/index.ts +2 -0
  262. package/src/DateTimeInput/utils/parseTimeValue.ts +54 -0
  263. package/src/Drawer/Drawer.tsx +443 -0
  264. package/src/Drawer/atoms.ts +4 -0
  265. package/src/Drawer/components/DialogActions/DialogActions.tsx +33 -0
  266. package/src/Drawer/components/DialogContent/DialogContent.tsx +80 -0
  267. package/src/Drawer/components/DialogHeader/DialogHeader.tsx +68 -0
  268. package/src/EducationalPopover/EducationalPopover.tsx +174 -0
  269. package/src/FavoriteButton/FavoriteButton.tsx +64 -0
  270. package/src/FavoriteButton/components/IconOnlyFavoriteButton/IconOnlyFavoriteButton.tsx +83 -0
  271. package/src/FavoriteButton/components/LabeledAnimatedFavoriteButton/LabeledAnimatedFavoriteButton.tsx +186 -0
  272. package/src/FavoriteButton/components/LabeledFavoriteButton/LabeledFavoriteButton.tsx +71 -0
  273. package/src/FavoriteButton/components/SmallHeartStraightIcon/SmallHeartStraightIcon.tsx +14 -0
  274. package/src/FavoriteButton/hooks/useFavoriteButtonState.ts +30 -0
  275. package/src/FavoriteButton/index.ts +2 -0
  276. package/src/FavoriteButton/types/favoriteButton.ts +87 -0
  277. package/src/FeatureFlags/devTools/FeatureFlagDevToolsUI.tsx +226 -0
  278. package/src/FeatureFlags/devTools/getFeatureFlagCookieOverrides.ts +30 -0
  279. package/src/FeatureFlags/devTools/utils/cookies.ts +169 -0
  280. package/src/FeatureFlags/hooks/index.ts +2 -0
  281. package/src/FeatureFlags/hooks/useFeatureFlag.tsx +19 -0
  282. package/src/FeatureFlags/hooks/useFeatureFlags.tsx +15 -0
  283. package/src/FileUpload/components/FileCard/FileCard.tsx +50 -0
  284. package/src/FileUpload/components/FileDropzone/FileDropzone.tsx +221 -0
  285. package/src/FileUpload/components/FileDropzone/components/DropzoneContent/DropzoneContent.tsx +28 -0
  286. package/src/FileUpload/components/FileDropzone/components/DropzoneContent/DropzoneText.tsx +81 -0
  287. package/src/FileUpload/components/FileDropzone/components/FileDropzoneDebugger/FileDropzoneDebugger.tsx +40 -0
  288. package/src/FileUpload/components/FileDropzone/components/FileDropzoneDebugger/FileRejectionsDisplay.tsx +110 -0
  289. package/src/FileUpload/components/FileDropzoneOverlay/FileDropzoneOverlay.tsx +183 -0
  290. package/src/FileUpload/components/FileDropzoneOverlay/components/OverlayDropzoneContent.tsx +146 -0
  291. package/src/FileUpload/components/FileDropzoneOverlay/components/OverlayDropzoneDragText.tsx +42 -0
  292. package/src/FileUpload/components/FileDropzoneOverlay/styles.ts +79 -0
  293. package/src/FileUpload/components/FilePreviewList/FilePreviewList.tsx +251 -0
  294. package/src/FileUpload/components/FilePreviewList/virtualizerComponents/FilePreviewVirtualizedList/FilePreviewVirtualizedList.tsx +88 -0
  295. package/src/FileUpload/components/FileUpload/FileUpload.tsx +63 -0
  296. package/src/FileUpload/components/FileUploadCanvas/FileUploadCanvas.tsx +125 -0
  297. package/src/FileUpload/components/GridFileCard/GridFileCard.tsx +364 -0
  298. package/src/FileUpload/components/GridFileCard/utils/sortable.ts +48 -0
  299. package/src/FileUpload/components/ListFileCard/ListFileCard.tsx +259 -0
  300. package/src/FileUpload/components/types.ts +78 -0
  301. package/src/FileUpload/hooks/filePreview/useImageFilePreviewUrl.ts +62 -0
  302. package/src/FileUpload/hooks/index.ts +11 -0
  303. package/src/FileUpload/hooks/upload/useHandleDragEnter/useHandleDragEnter.ts +154 -0
  304. package/src/FileUpload/hooks/upload/useHandleDrop/createFileRejectionHelpers.ts +273 -0
  305. package/src/FileUpload/hooks/upload/useHandleDrop/useHandleDrop.ts +153 -0
  306. package/src/FileUpload/hooks/upload/useUploadAvailability/useUploadAvailability.ts +44 -0
  307. package/src/FileUpload/hooks/validation/createDropzoneValidator.ts +41 -0
  308. package/src/FileUpload/hooks/validation/useFileValidation.ts +25 -0
  309. package/src/FileUpload/hooks/validation/useFileValidationLogic.ts +107 -0
  310. package/src/FileUpload/hooks/validation/useValidationMessages.ts +92 -0
  311. package/src/FileUpload/hooks/validation/useValidationState.ts +171 -0
  312. package/src/FileUpload/index.ts +57 -0
  313. package/src/FileUpload/providers/FileUploadProvider.tsx +219 -0
  314. package/src/FileUpload/providers/UploadValidationProvider.tsx +159 -0
  315. package/src/FileUpload/testUtils/mockFilesAndImages.ts +64 -0
  316. package/src/FileUpload/testUtils/testUtils.ts +111 -0
  317. package/src/FileUpload/types/commonTypes.ts +267 -0
  318. package/src/FileUpload/types/index.ts +31 -0
  319. package/src/FileUpload/types/sharedTypes.ts +159 -0
  320. package/src/FileUpload/utils/constants.ts +79 -0
  321. package/src/FileUpload/utils/createMessageContext.ts +180 -0
  322. package/src/FileUpload/utils/getFileExtensionsFromAcceptedTypes.ts +73 -0
  323. package/src/FileUpload/utils/getFilePluralizationText.ts +68 -0
  324. package/src/FileUpload/utils/getMimeTypes.ts +26 -0
  325. package/src/FileUpload/utils/messageUtils.ts +41 -0
  326. package/src/FileUpload/utils/styles.ts +68 -0
  327. package/src/FormLabel/FormLabel.tsx +212 -0
  328. package/src/IconButton/IconButton.tsx +154 -0
  329. package/src/Icons/CreditCardIcon/CreditCardIcon.tsx +73 -0
  330. package/src/Icons/CreditCardIcon/cardIcons.tsx +270 -0
  331. package/src/Icons/IconBase.tsx +133 -0
  332. package/src/Icons/anyIcon.ts +3 -0
  333. package/src/Icons/generatedIcons/Archive.tsx +48 -0
  334. package/src/Icons/generatedIcons/ArrowClockwise.tsx +48 -0
  335. package/src/Icons/generatedIcons/ArrowDown.tsx +48 -0
  336. package/src/Icons/generatedIcons/ArrowLeft.tsx +48 -0
  337. package/src/Icons/generatedIcons/ArrowRight.tsx +48 -0
  338. package/src/Icons/generatedIcons/ArrowSquareOut.tsx +51 -0
  339. package/src/Icons/generatedIcons/ArrowSquareRight.tsx +51 -0
  340. package/src/Icons/generatedIcons/ArrowUp.tsx +48 -0
  341. package/src/Icons/generatedIcons/ArrowsCounterClockwise.tsx +48 -0
  342. package/src/Icons/generatedIcons/ArrowsLeftRight.tsx +48 -0
  343. package/src/Icons/generatedIcons/ArrowsOutCardinal.tsx +48 -0
  344. package/src/Icons/generatedIcons/Bank.tsx +48 -0
  345. package/src/Icons/generatedIcons/Bell.tsx +51 -0
  346. package/src/Icons/generatedIcons/BookBookmark.tsx +51 -0
  347. package/src/Icons/generatedIcons/BookmarksSimple.tsx +51 -0
  348. package/src/Icons/generatedIcons/Broadcast.tsx +48 -0
  349. package/src/Icons/generatedIcons/CalendarBlank.tsx +48 -0
  350. package/src/Icons/generatedIcons/CalendarStar.tsx +51 -0
  351. package/src/Icons/generatedIcons/Camera.tsx +51 -0
  352. package/src/Icons/generatedIcons/CaretDown.tsx +48 -0
  353. package/src/Icons/generatedIcons/CaretLeft.tsx +48 -0
  354. package/src/Icons/generatedIcons/CaretRight.tsx +48 -0
  355. package/src/Icons/generatedIcons/CaretUp.tsx +48 -0
  356. package/src/Icons/generatedIcons/Certificate.tsx +51 -0
  357. package/src/Icons/generatedIcons/ChartBar.tsx +48 -0
  358. package/src/Icons/generatedIcons/Check.tsx +51 -0
  359. package/src/Icons/generatedIcons/CheckCircle.tsx +48 -0
  360. package/src/Icons/generatedIcons/CirclesFour.tsx +51 -0
  361. package/src/Icons/generatedIcons/Clock.tsx +48 -0
  362. package/src/Icons/generatedIcons/ClockCountdown.tsx +48 -0
  363. package/src/Icons/generatedIcons/Close.tsx +51 -0
  364. package/src/Icons/generatedIcons/CloudArrowUp.tsx +51 -0
  365. package/src/Icons/generatedIcons/CloudWarning.tsx +51 -0
  366. package/src/Icons/generatedIcons/Code.tsx +48 -0
  367. package/src/Icons/generatedIcons/Compass.tsx +51 -0
  368. package/src/Icons/generatedIcons/Confetti.tsx +51 -0
  369. package/src/Icons/generatedIcons/Copy.tsx +48 -0
  370. package/src/Icons/generatedIcons/CornersOut.tsx +48 -0
  371. package/src/Icons/generatedIcons/CreditCard.tsx +48 -0
  372. package/src/Icons/generatedIcons/Crown.tsx +51 -0
  373. package/src/Icons/generatedIcons/CrownSimple.tsx +51 -0
  374. package/src/Icons/generatedIcons/CurrencyCircleDollar.tsx +48 -0
  375. package/src/Icons/generatedIcons/CurrencyDollarSimple.tsx +51 -0
  376. package/src/Icons/generatedIcons/Desktop.tsx +51 -0
  377. package/src/Icons/generatedIcons/Detective.tsx +51 -0
  378. package/src/Icons/generatedIcons/DotOutline.tsx +46 -0
  379. package/src/Icons/generatedIcons/DotsSixVertical.tsx +51 -0
  380. package/src/Icons/generatedIcons/DotsThreeOutline.tsx +51 -0
  381. package/src/Icons/generatedIcons/DotsThreeOutlineVertical.tsx +51 -0
  382. package/src/Icons/generatedIcons/DownloadSimple.tsx +51 -0
  383. package/src/Icons/generatedIcons/EnvelopeSimple.tsx +48 -0
  384. package/src/Icons/generatedIcons/Eraser.tsx +51 -0
  385. package/src/Icons/generatedIcons/Eye.tsx +51 -0
  386. package/src/Icons/generatedIcons/EyeSlash.tsx +51 -0
  387. package/src/Icons/generatedIcons/FacebookLogo.tsx +48 -0
  388. package/src/Icons/generatedIcons/FileArchive.tsx +48 -0
  389. package/src/Icons/generatedIcons/FileArrowDown.tsx +48 -0
  390. package/src/Icons/generatedIcons/FileCsv.tsx +48 -0
  391. package/src/Icons/generatedIcons/FilePdf.tsx +48 -0
  392. package/src/Icons/generatedIcons/FileText.tsx +48 -0
  393. package/src/Icons/generatedIcons/Files.tsx +51 -0
  394. package/src/Icons/generatedIcons/Fire.tsx +51 -0
  395. package/src/Icons/generatedIcons/Flag.tsx +51 -0
  396. package/src/Icons/generatedIcons/FlagBannerFold.tsx +48 -0
  397. package/src/Icons/generatedIcons/FloppyDisk.tsx +51 -0
  398. package/src/Icons/generatedIcons/Gauge.tsx +51 -0
  399. package/src/Icons/generatedIcons/Gavel.tsx +51 -0
  400. package/src/Icons/generatedIcons/Gear.tsx +51 -0
  401. package/src/Icons/generatedIcons/GlobeHemisphereWest.tsx +51 -0
  402. package/src/Icons/generatedIcons/GoogleLogo.tsx +48 -0
  403. package/src/Icons/generatedIcons/GridNine.tsx +51 -0
  404. package/src/Icons/generatedIcons/HandCoins.tsx +51 -0
  405. package/src/Icons/generatedIcons/HandbagSimple.tsx +51 -0
  406. package/src/Icons/generatedIcons/Headset.tsx +51 -0
  407. package/src/Icons/generatedIcons/HeartStraight.tsx +51 -0
  408. package/src/Icons/generatedIcons/HourglassLow.tsx +48 -0
  409. package/src/Icons/generatedIcons/House.tsx +51 -0
  410. package/src/Icons/generatedIcons/Image.tsx +51 -0
  411. package/src/Icons/generatedIcons/ImageSquare.tsx +51 -0
  412. package/src/Icons/generatedIcons/ImagesSquare.tsx +51 -0
  413. package/src/Icons/generatedIcons/Info.tsx +48 -0
  414. package/src/Icons/generatedIcons/InstagramLogo.tsx +51 -0
  415. package/src/Icons/generatedIcons/Lightning.tsx +48 -0
  416. package/src/Icons/generatedIcons/Link.tsx +51 -0
  417. package/src/Icons/generatedIcons/LinkedinLogo.tsx +51 -0
  418. package/src/Icons/generatedIcons/List.tsx +48 -0
  419. package/src/Icons/generatedIcons/Lock.tsx +51 -0
  420. package/src/Icons/generatedIcons/LockOpen.tsx +51 -0
  421. package/src/Icons/generatedIcons/MagnifyingGlass.tsx +48 -0
  422. package/src/Icons/generatedIcons/MapPin.tsx +51 -0
  423. package/src/Icons/generatedIcons/MapPinSimpleArea.tsx +48 -0
  424. package/src/Icons/generatedIcons/Medal.tsx +48 -0
  425. package/src/Icons/generatedIcons/Megaphone.tsx +48 -0
  426. package/src/Icons/generatedIcons/Minus.tsx +45 -0
  427. package/src/Icons/generatedIcons/Money.tsx +51 -0
  428. package/src/Icons/generatedIcons/Notches.tsx +48 -0
  429. package/src/Icons/generatedIcons/NotePencil.tsx +48 -0
  430. package/src/Icons/generatedIcons/Package.tsx +51 -0
  431. package/src/Icons/generatedIcons/PaintBrush.tsx +51 -0
  432. package/src/Icons/generatedIcons/PaperPlaneTilt.tsx +51 -0
  433. package/src/Icons/generatedIcons/Paperclip.tsx +51 -0
  434. package/src/Icons/generatedIcons/Pause.tsx +51 -0
  435. package/src/Icons/generatedIcons/PencilLine.tsx +51 -0
  436. package/src/Icons/generatedIcons/PencilRuler.tsx +51 -0
  437. package/src/Icons/generatedIcons/PencilSimple.tsx +51 -0
  438. package/src/Icons/generatedIcons/Phone.tsx +51 -0
  439. package/src/Icons/generatedIcons/PinterestLogo.tsx +51 -0
  440. package/src/Icons/generatedIcons/Play.tsx +51 -0
  441. package/src/Icons/generatedIcons/Plus.tsx +51 -0
  442. package/src/Icons/generatedIcons/PlusCircle.tsx +48 -0
  443. package/src/Icons/generatedIcons/Printer.tsx +51 -0
  444. package/src/Icons/generatedIcons/Question.tsx +48 -0
  445. package/src/Icons/generatedIcons/Receipt.tsx +51 -0
  446. package/src/Icons/generatedIcons/Rows.tsx +51 -0
  447. package/src/Icons/generatedIcons/SealCheck.tsx +51 -0
  448. package/src/Icons/generatedIcons/SelectionSlash.tsx +48 -0
  449. package/src/Icons/generatedIcons/ShareNetwork.tsx +51 -0
  450. package/src/Icons/generatedIcons/ShieldCheck.tsx +51 -0
  451. package/src/Icons/generatedIcons/ShieldStar.tsx +51 -0
  452. package/src/Icons/generatedIcons/ShoppingCart.tsx +48 -0
  453. package/src/Icons/generatedIcons/ShuffleAngular.tsx +48 -0
  454. package/src/Icons/generatedIcons/SidebarSimple.tsx +48 -0
  455. package/src/Icons/generatedIcons/SlidersHorizontal.tsx +51 -0
  456. package/src/Icons/generatedIcons/Smiley.tsx +48 -0
  457. package/src/Icons/generatedIcons/Sparkle.tsx +51 -0
  458. package/src/Icons/generatedIcons/SpinnerGap.tsx +48 -0
  459. package/src/Icons/generatedIcons/StackPlus.tsx +48 -0
  460. package/src/Icons/generatedIcons/Star.tsx +51 -0
  461. package/src/Icons/generatedIcons/Storefront.tsx +51 -0
  462. package/src/Icons/generatedIcons/Swap.tsx +51 -0
  463. package/src/Icons/generatedIcons/Tag.tsx +51 -0
  464. package/src/Icons/generatedIcons/ThumbsDown.tsx +48 -0
  465. package/src/Icons/generatedIcons/ThumbsUp.tsx +48 -0
  466. package/src/Icons/generatedIcons/Toolbox.tsx +48 -0
  467. package/src/Icons/generatedIcons/Trash.tsx +48 -0
  468. package/src/Icons/generatedIcons/TrendUp.tsx +48 -0
  469. package/src/Icons/generatedIcons/Trophy.tsx +51 -0
  470. package/src/Icons/generatedIcons/Truck.tsx +51 -0
  471. package/src/Icons/generatedIcons/UploadSimple.tsx +51 -0
  472. package/src/Icons/generatedIcons/User.tsx +48 -0
  473. package/src/Icons/generatedIcons/Users.tsx +48 -0
  474. package/src/Icons/generatedIcons/UsersThree.tsx +51 -0
  475. package/src/Icons/generatedIcons/VideoCamera.tsx +51 -0
  476. package/src/Icons/generatedIcons/Warning.tsx +51 -0
  477. package/src/Icons/generatedIcons/WarningCircle.tsx +48 -0
  478. package/src/Icons/generatedIcons/WifiHigh.tsx +51 -0
  479. package/src/Icons/generatedIcons/XCircle.tsx +48 -0
  480. package/src/Icons/generatedIcons/XLogo.tsx +48 -0
  481. package/src/Icons/generatedIcons/YoutubeLogo.tsx +51 -0
  482. package/src/Icons/importedIcons.ts +152 -0
  483. package/src/Icons/index.ts +149 -0
  484. package/src/Icons/socialIcons/appleSocialIcon.tsx +50 -0
  485. package/src/Icons/socialIcons/facebookSocialIcon.tsx +41 -0
  486. package/src/Icons/socialIcons/googleSocialIcon.tsx +134 -0
  487. package/src/ImageCluster/ImageCluster.tsx +125 -0
  488. package/src/ImageSlider/ImageSlider.tsx +584 -0
  489. package/src/ImageSlider/ImageSlider.types.ts +90 -0
  490. package/src/ImageSlider/components/IndexIndicator/IndexIndicator.tsx +21 -0
  491. package/src/ImageSlider/components/NavigationButtons/NavigationButtons.tsx +113 -0
  492. package/src/ImageSlider/components/ResponsiveImage/ResponsiveImage.tsx +114 -0
  493. package/src/ImageSlider/components/ResponsiveImage/index.ts +1 -0
  494. package/src/ImageSlider/components/Thumbnails/Thumbnails.tsx +184 -0
  495. package/src/ImageSlider/constants.ts +59 -0
  496. package/src/ImageSlider/hooks/index.ts +3 -0
  497. package/src/ImageSlider/hooks/useImageSlider.ts +57 -0
  498. package/src/ImageSlider/hooks/useImageSliderNavigation.ts +133 -0
  499. package/src/ImageSlider/hooks/useImageSliderScrollHandler.ts +171 -0
  500. package/src/ImageSlider/index.ts +3 -0
  501. package/src/ImageSlider/utils/imageOptimization.ts +97 -0
  502. package/src/ImageSlider/utils/index.ts +1 -0
  503. package/src/InlineNotification/InlineNotification.tsx +95 -0
  504. package/src/JumpMenu/JumpMenu.tsx +395 -0
  505. package/src/JumpMenu/components/JumpMenuItem/JumpMenuItem.tsx +65 -0
  506. package/src/JumpMenu/hooks/useContainerTracking.ts +171 -0
  507. package/src/JumpMenu/hooks/useIntersectionObserver.ts +77 -0
  508. package/src/JumpMenu/hooks/useKeyboardNavigation.ts +102 -0
  509. package/src/JumpMenu/hooks/useResizeObserver.ts +53 -0
  510. package/src/JumpMenu/hooks/useSectionObserver.ts +102 -0
  511. package/src/JumpMenu/index.ts +2 -0
  512. package/src/JumpMenu/types/index.ts +19 -0
  513. package/src/Loading/Loading.tsx +39 -0
  514. package/src/Loading/components/LoadingDot/LoadingDot.tsx +16 -0
  515. package/src/LoadingSpinner/LoadingSpinner.tsx +20 -0
  516. package/src/Menu/Menu.tsx +372 -0
  517. package/src/Menu/components/MenuDivider/MenuDivider.tsx +5 -0
  518. package/src/Menu/components/MenuItem/MenuItem.tsx +298 -0
  519. package/src/Menu/context/menuContext.tsx +20 -0
  520. package/src/Menu/hooks/useMenu.tsx +18 -0
  521. package/src/Menu/index.ts +3 -0
  522. package/src/Modal/ComposableModal.tsx +321 -0
  523. package/src/Modal/Modal.tsx +231 -0
  524. package/src/Modal/components/BackButton/BackButton.tsx +43 -0
  525. package/src/Modal/components/Backdrop/Backdrop.tsx +62 -0
  526. package/src/Modal/components/CloseButton/CloseButton.tsx +55 -0
  527. package/src/Modal/components/ModalActions/ModalActions.tsx +135 -0
  528. package/src/Modal/components/ModalContent/ModalContent.tsx +163 -0
  529. package/src/Modal/components/ModalHeader/ModalHeader.tsx +84 -0
  530. package/src/Modal/components/ModalHeader/hooks/useHeaderAnimation.tsx +49 -0
  531. package/src/Modal/components/ModalProgressSteps/ModalProgressSteps.tsx +26 -0
  532. package/src/Modal/components/ModalSubTitle/ModalSubTitle.tsx +29 -0
  533. package/src/Modal/components/ModalTitle/ModalTitle.tsx +22 -0
  534. package/src/Modal/components/PreventModalScroll/PreventModalScroll.tsx +106 -0
  535. package/src/Modal/components/index.ts +12 -0
  536. package/src/Modal/context.ts +33 -0
  537. package/src/Modal/hooks/useCloseModal.ts +140 -0
  538. package/src/NotificationBadge/NotificationBadge.tsx +34 -0
  539. package/src/Pagination/AdvancedPagination.tsx +48 -0
  540. package/src/Pagination/Pagination.tsx +216 -0
  541. package/src/Pagination/components/AdvancedPaginator/AdvancedPaginator.tsx +52 -0
  542. package/src/Pagination/components/AdvancedPaginator/components/PageSelect/PageSelect.tsx +43 -0
  543. package/src/Pagination/components/ItemCountDisplay/ItemCountDisplay.tsx +32 -0
  544. package/src/Pagination/components/ItemCountSelect/ItemCountSelect.tsx +33 -0
  545. package/src/Pagination/index.tsx +3 -0
  546. package/src/Pagination/paginationProvider.tsx +234 -0
  547. package/src/Pagination/utils.tsx +36 -0
  548. package/src/PhoneInput/PhoneInput.tsx +515 -0
  549. package/src/PhoneInput/useDropdownLogic.tsx +163 -0
  550. package/src/ProgressCircle/ProgressCircle.tsx +246 -0
  551. package/src/ProgressCircle/hooks/useProgressStatusTransitions.ts +49 -0
  552. package/src/ProgressCircle/utils/progressCircle.constants.ts +27 -0
  553. package/src/ProgressSteps/ProgressSteps.tsx +160 -0
  554. package/src/SaveConfetti/SaveConfetti.tsx +277 -0
  555. package/src/SaveConfetti/index.ts +2 -0
  556. package/src/SearchInput/SearchInput.tsx +237 -0
  557. package/src/SegmentedControl/SegmentedControl.tsx +111 -0
  558. package/src/SegmentedControl/SegmentedControlGroup.tsx +94 -0
  559. package/src/SegmentedControl/index.ts +4 -0
  560. package/src/Select/Select.tsx +154 -0
  561. package/src/Select/SelectAsync.tsx +13 -0
  562. package/src/Select/SelectAsyncCreatable.tsx +14 -0
  563. package/src/Select/SelectCreatable.tsx +12 -0
  564. package/src/Select/reexportedComponents.tsx +5 -0
  565. package/src/Select/selectComponents.tsx +305 -0
  566. package/src/Skeleton/Skeleton.tsx +13 -0
  567. package/src/SplitButton/SplitButton.tsx +298 -0
  568. package/src/SplitButton/SplitButtonTrigger.tsx +55 -0
  569. package/src/StarRating/StarRating.tsx +165 -0
  570. package/src/StarRating/components/StarComponent/StarComponent.tsx +44 -0
  571. package/src/Table/Table.tsx +474 -0
  572. package/src/Table/components/TableHeader/TableHeader.tsx +166 -0
  573. package/src/Table/components/TablePagination/TablePagination.tsx +18 -0
  574. package/src/Table/components/TablePagination/components/ItemCountDisplay/ItemCountDisplay.tsx +17 -0
  575. package/src/Table/components/TablePagination/components/ItemCountSelect/ItemCountSelect.tsx +31 -0
  576. package/src/Table/components/TablePagination/components/TablePaginator/TablePaginator.tsx +37 -0
  577. package/src/Table/components/TablePagination/components/TablePaginator/components/PageSelect/PageSelect.tsx +32 -0
  578. package/src/Table/components/TableRow/TableRows.tsx +147 -0
  579. package/src/Table/components/TableRow/components/TableRowCell/TableRowCell.tsx +49 -0
  580. package/src/Table/components/TableShadow/TableShadow.tsx +46 -0
  581. package/src/Table/index.ts +2 -0
  582. package/src/Table/sharedState.ts +30 -0
  583. package/src/Table/sharedStyles.ts +1 -0
  584. package/src/Table/types.ts +55 -0
  585. package/src/Tabs/Tabs.tsx +358 -0
  586. package/src/TextArea/TextArea.tsx +159 -0
  587. package/src/TextInput/TextInput.tsx +173 -0
  588. package/src/Toast/Toast.tsx +64 -0
  589. package/src/Toast/components/ToastContainer/ToastContainer.tsx +48 -0
  590. package/src/Toast/index.ts +2 -0
  591. package/src/Toast/types/role.ts +1 -0
  592. package/src/Toast/utils/getIcon.tsx +41 -0
  593. package/src/ToggleSwitch/ToggleSwitch.tsx +188 -0
  594. package/src/Tooltip/InfoIconTooltip.tsx +47 -0
  595. package/src/Tooltip/Tooltip.tsx +41 -0
  596. package/src/Typography/InlineButton/InlineButton.tsx +167 -0
  597. package/src/Typography/Links/Links.tsx +113 -0
  598. package/src/Typography/Text/Text.tsx +239 -0
  599. package/src/ViewMore/ViewMore.tsx +226 -0
  600. package/src/WebRTCPlayer/WebRTCPlayer.tsx +325 -0
  601. package/src/WebRTCPlayer/adaptor/NativeWebRTCAdaptor.ts +588 -0
  602. package/src/WebRTCPlayer/hooks/useWebRTCStream.ts +571 -0
  603. package/src/WebRTCPlayer/index.ts +22 -0
  604. package/src/WebRTCPlayer/types.ts +95 -0
  605. package/src/breakpoints/index.tsx +1 -0
  606. package/src/breakpoints/utils.tsx +50 -0
  607. package/src/declarations.d.ts +7 -0
  608. package/src/grid/gridHighlighter.tsx +83 -0
  609. package/src/grid/index.ts +3 -0
  610. package/src/grid/pageGrid.tsx +37 -0
  611. package/src/grid/useSubGridCSS.tsx +214 -0
  612. package/src/hooks/useHorizontalScrollFade.ts +44 -0
  613. package/src/hooks/usePrevious.ts +14 -0
  614. package/src/index.ts +351 -0
  615. package/src/intl/index.ts +4 -0
  616. package/src/intl/utils.ts +67 -0
  617. package/src/mixins/horizontalScrollFadeMixin.ts +56 -0
  618. package/src/mixins/index.ts +18 -0
  619. package/src/mixins/propMixins.ts +389 -0
  620. package/src/providers/createContextProvider.ts +22 -0
  621. package/src/providers/designSystemProvider.tsx +218 -0
  622. package/src/providers/errorBoundaryProvider.tsx +179 -0
  623. package/src/providers/featureFlagProvider.tsx +18 -0
  624. package/src/providers/gridSizeProvider.tsx +23 -0
  625. package/src/providers/index.ts +12 -0
  626. package/src/providers/linkProvider.tsx +32 -0
  627. package/src/providers/normalize.tsx +93 -0
  628. package/src/providers/targets/DatePickerTarget.tsx +10 -0
  629. package/src/providers/targets/ModalTarget.tsx +14 -0
  630. package/src/providers/targets/TimePickerTarget.tsx +10 -0
  631. package/src/providers/themeContext.tsx +24 -0
  632. package/src/providers/windowSizeProvider.tsx +125 -0
  633. package/src/spacing/index.ts +1 -0
  634. package/src/spacing/spacing.ts +11 -0
  635. package/src/utils/countriesWithISOCodes.ts +1419 -0
  636. package/src/utils/dateTimeFormat.ts +257 -0
  637. package/src/utils/effectEventListener.ts +11 -0
  638. package/src/utils/formatFileSize.ts +18 -0
  639. package/src/utils/isClientSide.ts +1 -0
  640. package/src/utils/keepTransition.ts +15 -0
  641. package/src/utils/nodeEnv.ts +9 -0
  642. package/src/utils/smoothScrollTo.ts +65 -0
  643. package/src/utils/utilityTypes.ts +13 -0
  644. package/table.cjs +1 -1
  645. package/table.mjs +1 -1
  646. package/tabs.cjs +1 -1
  647. package/tabs.cjs.map +1 -1
  648. package/tabs.mjs +1 -1
  649. package/tabs.mjs.map +1 -1
  650. package/textArea.cjs.map +1 -1
  651. package/textArea.mjs.map +1 -1
  652. package/viewMore.cjs +1 -1
  653. package/viewMore.mjs +1 -1
  654. package/BottomSheet-ZV_eq3xt.mjs.map +0 -1
  655. package/BottomSheet-emWP9Fct.cjs.map +0 -1
  656. package/FavoriteButton-CC3qL0lR.mjs.map +0 -1
  657. package/FavoriteButton-DliYzkfu.cjs.map +0 -1
  658. package/FileUpload--e_UJ_ek.cjs.map +0 -1
  659. package/FileUpload-p_pl9NXr.mjs.map +0 -1
  660. package/ImageSlider-BidXfnLj.cjs.map +0 -1
  661. package/ImageSlider-CDrg_TbL.mjs.map +0 -1
  662. package/Menu-ClUogmwE.cjs.map +0 -1
  663. package/Menu-Cxu8CaX1.mjs.map +0 -1
  664. package/Modal-CiBqXyiK.cjs.map +0 -1
  665. package/Select-BXDjzyDs.cjs.map +0 -1
  666. package/Select-BkZu8OLs.mjs.map +0 -1
  667. package/ViewMore-BBoUvo7p.cjs.map +0 -1
  668. package/ViewMore-BrZPuE4E.mjs.map +0 -1
  669. package/buttonColorClasses-B7OU4aQA.mjs.map +0 -1
  670. package/buttonColorClasses-C3hg1at8.cjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"FileUpload-p_pl9NXr.mjs","names":[],"sources":["../src/FileUpload/providers/FileUploadProvider.tsx","../src/FileUpload/hooks/upload/useHandleDragEnter/useHandleDragEnter.ts","../src/FileUpload/hooks/upload/useHandleDrop/createFileRejectionHelpers.ts","../src/FileUpload/hooks/upload/useHandleDrop/useHandleDrop.ts","../src/FileUpload/hooks/upload/useUploadAvailability/useUploadAvailability.ts","../src/FileUpload/hooks/validation/createDropzoneValidator.ts","../src/FileUpload/utils/getMimeTypes.ts","../src/FileUpload/utils/styles.ts","../src/FileUpload/components/FileDropzone/components/DropzoneContent/DropzoneText.tsx","../src/FileUpload/components/FileDropzone/components/DropzoneContent/DropzoneContent.tsx","../src/FileUpload/components/FileDropzone/components/FileDropzoneDebugger/FileRejectionsDisplay.tsx","../src/FileUpload/components/FileDropzone/components/FileDropzoneDebugger/FileDropzoneDebugger.tsx","../src/FileUpload/components/FileDropzone/FileDropzone.tsx","../src/FileUpload/components/GridFileCard/utils/sortable.ts","../src/FileUpload/components/GridFileCard/GridFileCard.tsx","../src/FileUpload/components/ListFileCard/ListFileCard.tsx","../src/FileUpload/components/FileCard/FileCard.tsx","../src/FileUpload/components/FilePreviewList/virtualizerComponents/FilePreviewVirtualizedList/FilePreviewVirtualizedList.tsx","../src/FileUpload/components/FilePreviewList/FilePreviewList.tsx","../src/FileUpload/components/FileUpload/FileUpload.tsx","../src/FileUpload/components/FileDropzoneOverlay/components/OverlayDropzoneDragText.tsx","../src/FileUpload/components/FileDropzoneOverlay/components/OverlayDropzoneContent.tsx","../src/FileUpload/components/FileDropzoneOverlay/styles.ts","../src/FileUpload/components/FileDropzoneOverlay/FileDropzoneOverlay.tsx","../src/FileUpload/components/FileUploadCanvas/FileUploadCanvas.tsx"],"sourcesContent":["import { createContext, useContext, useState } from 'react';\n\nimport { FileResource } from '../types';\nimport { CommonFileTypes, FileError, FileRejection, FileValidator } from '../types/commonTypes';\nimport { UploadValidationProvider } from './UploadValidationProvider';\n\n/**\n * Context type for the FileUploadProvider\n * Contains both file state management and callback handlers for file operations.\n * This context makes file upload state and operations available to all child components.\n *\n * @property disabled - Whether the file upload functionality is disabled\n * @property files - Array of currently selected/uploaded files\n * @property onDrop - Callback triggered when files are dropped, with both accepted and rejected files\n * @property onDropAccepted - Callback triggered when files pass validation\n * @property onDropRejected - Callback triggered when files fail validation\n * @property onFileDelete - Callback triggered when a file is deleted from the preview\n * @property setFiles - State setter function to update the files array\n */\nexport type FileUploadContextType = {\n disabled: boolean;\n files: FileResource[];\n onDrop?: (acceptedFiles: File[], rejectedFiles: FileRejection[]) => void;\n onDropAccepted?: (files: File[]) => void;\n onDropRejected?: (rejectedFiles: FileRejection[]) => void;\n onFileDelete?: (fileResource: FileResource) => void;\n setFiles: (files: FileResource[] | ((prev: FileResource[]) => FileResource[])) => void;\n};\n\n/**\n * React context for file upload state and operations\n * Used by the useFileUploadContext hook\n */\nexport const FileUploadContext = createContext<FileUploadContextType | undefined>(undefined);\n\n/**\n * Configuration props for the FileUploadProvider\n * These props control both file upload behavior and validation rules.\n * Many of these properties are passed to the underlying ValidationProvider.\n */\nexport type FileUploadProviderConfigProps = {\n /**\n * Allowed file types - either preset categories ('images', 'pdfs', 'documents')\n * or an array of MIME types/extensions (e.g., ['image/jpeg', '.png'])\n */\n accept?: CommonFileTypes | string[];\n\n /**\n * Whether the upload is disabled\n * When true, prevents any interaction with the upload components\n */\n disabled?: boolean;\n\n /**\n * Error object to display custom validation errors\n * Overrides any validation errors with this custom error\n */\n error?: FileError;\n\n /**\n * Initial files to populate the uploader with\n * These files will be present when the component first mounts\n */\n initialFiles?: FileResource[];\n\n /**\n * Maximum number of files allowed\n * Set to 1 for single file upload, undefined for unlimited\n */\n maxFiles?: number;\n\n /**\n * Maximum allowed file size in bytes\n * Example: 5 * 1024 * 1024 for 5MB\n */\n maxSize?: number;\n\n /**\n * Callback when files are dropped (regardless of validation result)\n * Provides both accepted and rejected files for handling\n */\n onDrop?: (acceptedFiles: File[], rejectedFiles: FileRejection[]) => void;\n\n /**\n * Callback when files pass validation and are accepted\n * Useful for immediately processing valid files\n */\n onDropAccepted?: (files: File[]) => void;\n\n /**\n * Callback when files fail validation\n * Provides detailed rejection reasons for each file\n */\n onDropRejected?: (rejectedFiles: FileRejection[]) => void;\n\n /**\n * Callback when user clicks delete button on a file preview\n * Used to remove files from state or external storage\n */\n onFileDelete?: (fileResource: FileResource) => void;\n\n /**\n * When true, if any file fails validation, all files are rejected\n * When false (default), valid files are accepted even if others are rejected\n */\n strictValidation?: boolean;\n\n /**\n * Custom validator function for additional validation rules\n * Allows you to implement validation beyond the built-in type/size checks\n */\n validator?: FileValidator;\n};\n\n/**\n * Props for the FileUploadProvider component\n * Extends the config props with React children\n */\ntype FileUploadProviderProps = FileUploadProviderConfigProps & {\n /** React children */\n children: React.ReactNode;\n};\n\n/**\n * Provider component for file upload functionality\n *\n * This provider manages both file state and validation rules:\n * 1. Maintains file state (selected/uploaded files)\n * 2. Provides context for drag/drop operations and file management\n * 3. Wraps children with validation context for enforcing file rules\n *\n * While FileDropzone and FilePreviewList can function as standalone components,\n * using this provider offers coordinated state management when using multiple\n * file upload components together.\n *\n * @example\n * ```tsx\n * <FileUploadProvider\n * accept=\"images\"\n * maxFiles={5}\n * maxSize={2 * 1024 * 1024}\n * onDropAccepted={(files) => console.log('Accepted:', files)}\n * >\n * <FileDropzone />\n * <FilePreviewList />\n * </FileUploadProvider>\n * ```\n */\nexport const FileUploadProvider = ({\n accept,\n children,\n disabled = false,\n error,\n initialFiles = [],\n maxFiles,\n maxSize,\n onDrop,\n onDropAccepted,\n onDropRejected,\n onFileDelete,\n strictValidation,\n validator,\n}: FileUploadProviderProps) => {\n const [files, setFiles] = useState<FileResource[]>(initialFiles);\n\n const value = {\n accept,\n disabled,\n files,\n onDrop,\n onDropAccepted,\n onDropRejected,\n onFileDelete,\n setFiles,\n };\n\n return (\n <UploadValidationProvider\n accept={accept}\n error={error}\n maxFiles={maxFiles}\n maxSize={maxSize}\n strictValidation={strictValidation}\n validator={validator}\n >\n <FileUploadContext.Provider value={value}>{children}</FileUploadContext.Provider>\n </UploadValidationProvider>\n );\n};\n\nFileUploadProvider.displayName = 'FileUploadProvider';\n\n/**\n * Hook to access the file upload context\n *\n * Provides access to the current files array and operations for\n * managing file uploads within the FileUploadProvider.\n *\n * @throws Error if used outside of a FileUploadProvider\n * @returns The FileUploadContextType object with files array and handlers\n *\n * @example\n * ```tsx\n * const { files, setFiles, onFileDelete } = useFileUploadContext();\n *\n * // Remove a file\n * const handleDelete = (fileToDelete) => {\n * onFileDelete?.(fileToDelete);\n * setFiles(files.filter(file => file.name !== fileToDelete.name));\n * };\n * ```\n */\nexport const useFileUploadContext = () => {\n const context = useContext<FileUploadContextType | undefined>(FileUploadContext);\n if (!context) {\n throw new Error('useFileUploadContext must be used within FileUploadProvider');\n }\n return context;\n};\n","import { useCallback } from 'react';\n\nimport { UploadValidationContextType } from '../../../providers/UploadValidationProvider';\nimport { FileResource, FileValidator } from '../../../types/commonTypes';\nimport { createMessageContext } from '../../../utils/createMessageContext';\nimport { resolveContextAwareMessage } from '../../../utils/messageUtils';\n\n/**\n * Hook that handles file validation during drag events over a drop zone\n * @param props Object containing:\n * - files: Currently selected files in the uploader\n * - mimeTypes: Optional mapping of accepted file types to their MIME type arrays\n * - validation: Validation context (from either UploadValidationProvider\n * or local useFileValidationLogic hook)\n * - validator: Optional custom validation function to perform additional checks\n * @returns Callback function for handling dragenter events with early validation feedback\n * @remarks\n * - Provides immediate validation feedback while files are being dragged over the drop zone\n * - File size validation is not possible during drag events as file data is not yet available\n * - Validates in a specific priority order: custom validator → file count → file type\n * - Clears all validation state when drag starts\n * - Sets appropriate validation error messages for display in the UI\n * - Works with the ValidationContext to maintain validation state\n */\n\ntype UseHandleDragEnterProps = {\n /** Current files in the upload area */\n files: FileResource[];\n /** MIME types to accept */\n mimeTypes?: Record<string, string[]>;\n /** Validation context */\n validation: UploadValidationContextType;\n /** Custom validator function */\n validator?: FileValidator;\n};\n\n// Fires when a user drags files over the upload zone - provides early feedback on file type and max file limit\n// Note: We cannot early-validate file size here since we don't have access to the file content during drag events, only after drop.\nexport const useHandleDragEnter = ({ files, mimeTypes, validation, validator }: UseHandleDragEnterProps) => {\n const {\n accept,\n clearAllValidation,\n formattedMaxSize,\n getValidationMessage,\n maxFiles,\n maxSize,\n setDragValidationError,\n validateCustomRules,\n validateFileCount,\n validateFileType,\n } = validation;\n\n return useCallback(\n (event: React.DragEvent<HTMLElement>) => {\n // Clear all previous validation errors when a new drag event occurs\n clearAllValidation();\n\n const items = event.dataTransfer.items;\n if (items.length === 0) {\n return;\n }\n\n // Validation priority follows a specific order with early returns:\n // 1. Custom validator (highest priority)\n if (validator) {\n // Drag validation for custom validator uses the first dragged item\n const file = items[0];\n const validationResult = validateCustomRules(file);\n if (validationResult) {\n // Use the first error in the array\n const result = validationResult[0];\n\n // Create context with all necessary data for the error message\n const messageContext = createMessageContext({\n accept,\n code: result.code,\n count: items.length,\n dragItems: items,\n formattedMaxSize,\n maxFiles,\n maxSize,\n messageType: 'drag',\n });\n\n // Set the error with a properly formatted message\n setDragValidationError({\n code: result.code,\n message: resolveContextAwareMessage(result.message, messageContext),\n });\n return;\n }\n }\n\n // 2. File count validation (second priority)\n if (!validateFileCount(files.length, items.length)) {\n const overflowCount = files.length + items.length - (maxFiles ?? Infinity);\n\n const errorCode = 'too-many-files';\n const errorMessage = getValidationMessage({\n code: errorCode,\n count: overflowCount,\n messageType: 'drag',\n });\n\n setDragValidationError({\n code: errorCode,\n message: errorMessage,\n });\n return;\n }\n\n // 3. File type validation (lowest priority)\n const invalidTypeFiles = Array.from(items).filter((item) => {\n // Skip directories in validation (no type or kind is 'directory')\n if (!item.type || item.kind === 'directory') {\n return false;\n }\n return !validateFileType(item.type, mimeTypes);\n });\n\n if (invalidTypeFiles.length > 0) {\n const errorCode = 'file-invalid-type';\n const errorMessage = getValidationMessage({\n code: errorCode,\n count: invalidTypeFiles.length,\n messageType: 'drag',\n });\n\n setDragValidationError({\n code: errorCode,\n message: errorMessage,\n });\n return;\n }\n\n // If we reach here, all validation passed - no error is set\n },\n [\n files.length,\n mimeTypes,\n clearAllValidation,\n setDragValidationError,\n getValidationMessage,\n validateFileCount,\n maxFiles,\n validateFileType,\n validateCustomRules,\n validator,\n accept,\n formattedMaxSize,\n maxSize,\n ]\n );\n};\n","import { UploadValidationContextType } from '../../../providers/UploadValidationProvider';\nimport {\n ContextAwareMessage,\n DynamicMessageContext,\n FileError,\n FileRejection,\n FileResource,\n ValidationError,\n} from '../../../types/commonTypes';\nimport { builtInErrorCodes } from '../../../utils/constants';\nimport { createMessageContext } from '../../../utils/createMessageContext';\nimport { resolveContextAwareMessage } from '../../../utils/messageUtils';\n\n// Type for tracking error groups\nexport type ErrorGroup = {\n count: number;\n files: File[];\n message: ContextAwareMessage<DynamicMessageContext>;\n};\n\n/**\n * Creates helper functions for processing file rejections and formatting error messages\n * @param validation Validation context containing message formatters and validation rules\n * @returns Object with helper functions for processing file rejections\n */\nexport const createRejectionHelpers = (validation: UploadValidationContextType) => {\n const { accept, formattedMaxSize, getValidationMessage, maxFiles, maxSize, strictValidation, validateFileCount } =\n validation;\n\n /**\n * Ensures an error group exists for the given code, creating one if necessary\n *\n * @param errorGroups - Record of existing error groups indexed by error code\n * @param code - The error code to get or create a group for\n * @param message - Optional error message to use when creating a new group\n * @returns The existing or newly created error group for the specified code\n * @remarks\n * - Error groups track files that failed with the same error code\n * - Each group maintains a count of files, file references, and a shared message\n * - New groups are initialized with empty arrays and zero counts\n */\n const getOrCreateErrorGroup = (\n errorGroups: Record<string, ErrorGroup>,\n code: string,\n message?: ContextAwareMessage<DynamicMessageContext>\n ): ErrorGroup => {\n if (!(code in errorGroups)) {\n errorGroups[code] = {\n count: 0,\n files: [],\n message: message ?? '',\n };\n }\n return errorGroups[code];\n };\n\n return {\n /**\n * Formats a human-readable error message for display based on error code and grouped files\n *\n * This function handles two types of validation errors:\n *\n * 1. System errors (built-in): For standard error codes like 'file-too-large' or 'too-many-files',\n * it uses the built-in message system with appropriate pluralization and formatting.\n *\n * 2. Custom validator errors: For custom error codes from user-defined validators,\n * it enriches the message with context about the rejected files (count, names, etc.).\n *\n * Used in two key scenarios:\n * - Creating consolidated error messages for the UI (one message per error type)\n * - Formatting individual file rejection messages for callbacks\n *\n * @param code - The error code identifying the validation failure\n * @param error - The error object containing the message (string or function)\n * @param errorGroups - Record of grouped errors with counts and file references\n * @returns A formatted, human-readable error message ready for display\n */\n getFormattedErrorGroupMessage: (\n code: string,\n error: ValidationError,\n errorGroups: Record<string, ErrorGroup>\n ) => {\n const isSystemError = builtInErrorCodes.includes(code);\n const errorGroup = errorGroups[code];\n\n // For system errors, use getValidationMessage directly\n if (isSystemError) {\n return getValidationMessage({\n code,\n count: errorGroup.count,\n messageType: 'drop',\n });\n }\n\n // For custom errors, we need to provide context about the rejected files\n const messageContext = createMessageContext({\n accept,\n code,\n count: errorGroup.count,\n dropFiles: errorGroup.files,\n formattedMaxSize,\n maxFiles,\n maxSize,\n messageType: 'drop',\n });\n\n // Resolve the message function with proper context containing all grouped files\n return resolveContextAwareMessage(error.message, messageContext);\n },\n\n getOrCreateErrorGroup,\n\n /**\n * Handles file count limits and returns updated accepted/rejected files\n *\n * This function enforces the maxFiles constraint by calculating whether adding\n * new files would exceed the configured limit.\n *\n * @param currentFiles - Existing files already uploaded or selected\n * @param droppedAcceptedFiles - New files that passed initial type/size validation\n * @param droppedRejectedFiles - New files that already failed validation for other reasons\n * @returns Object containing the final accepted and rejected files after limit checks\n * @remarks\n * - Considers both existing files and newly dropped files when checking limits\n * - Handles two validation modes:\n * 1. Strict validation (strictValidation: true):\n * If adding any files would exceed the limit, ALL files are rejected\n * 2. Partial upload (strictValidation: false):\n * Accepts files up to the remaining limit, rejecting only overflow files\n * - Calculates remaining slots as (maxFiles - currentFiles.length)\n * - When no maxFiles is defined, accepts all files (Infinity limit)\n * - Adds appropriate error metadata to the rejected files for UI feedback\n */\n handleFileCountLimits: (\n currentFiles: FileResource[],\n droppedAcceptedFiles: File[],\n droppedRejectedFiles: FileRejection[]\n ) => {\n let acceptedResult = droppedAcceptedFiles;\n let rejectionsResult = [...droppedRejectedFiles];\n\n // Check if the total number of files (including both accepted and rejected) would exceed the limit\n // This ensures users see the maxFiles error even if some files are rejected for other reasons\n const totalDroppedFiles = droppedAcceptedFiles.length + droppedRejectedFiles.length;\n const wouldExceedLimit = !validateFileCount(currentFiles.length, totalDroppedFiles);\n const remainingSlots = maxFiles ? maxFiles - currentFiles.length : Infinity;\n\n if (wouldExceedLimit) {\n // Calculate how many files exceed the limit, considering all dropped files\n const overflowCount = currentFiles.length + totalDroppedFiles - (maxFiles ?? Infinity);\n const errorCode = 'too-many-files';\n const errorMessage = getValidationMessage({\n code: errorCode,\n count: overflowCount,\n messageType: 'drop',\n });\n\n const maxFilesError: FileError = {\n code: errorCode,\n message: errorMessage,\n };\n\n // Add the error to all files that exceed the limit\n // Start with files that were already accepted (they passed other validations)\n const fileCountRejections = acceptedResult.slice(remainingSlots).map((file) => ({\n errors: [maxFilesError],\n file,\n }));\n\n // Add these new rejections to the existing ones\n rejectionsResult = [...rejectionsResult, ...fileCountRejections];\n\n if (!strictValidation) {\n // In partial upload mode, only accept files up to the max file limit\n acceptedResult = acceptedResult.slice(0, remainingSlots);\n } else {\n // In strict mode, reject all files if the total count exceeds the limit\n acceptedResult = [];\n }\n }\n\n return { allAcceptedFiles: acceptedResult, allRejections: rejectionsResult };\n },\n\n /**\n * Handles file size validation and returns updated accepted/rejected files\n *\n * This function checks if files exceed the maximum allowed size (maxSize)\n * and updates accept/reject lists accordingly.\n *\n * @param acceptedFiles - Files that have passed previous validation steps\n * @returns Object containing validated files and size-related rejections\n * @remarks\n * - Files exceeding maxSize are identified and grouped with a 'file-too-large' error\n * - Handles two validation modes:\n * 1. Strict validation (strictValidation: true):\n * If ANY file exceeds the size limit, ALL files are rejected\n * 2. Partial upload (strictValidation: false):\n * Only oversized files are rejected, others proceed normally\n * - When maxSize is undefined, all files pass size validation\n * - Adds appropriate error metadata to rejected files for UI feedback\n * - The returned object has separate lists for valid files and size rejections\n */\n handleFileSizeValidation: (acceptedFiles: File[]) => {\n let validFiles = [...acceptedFiles];\n let sizeRejections: FileRejection[] = [];\n\n // Check for oversized files\n const oversizedFiles = acceptedFiles.filter((file) => maxSize && file.size > maxSize);\n\n if (oversizedFiles.length > 0) {\n const errorCode = 'file-too-large';\n const errorMessage = getValidationMessage({\n code: errorCode,\n count: oversizedFiles.length,\n messageType: 'drop',\n });\n\n const fileSizeError: FileError = {\n code: errorCode,\n message: errorMessage,\n };\n\n // Add to rejections\n sizeRejections = oversizedFiles.map((file) => ({\n errors: [fileSizeError],\n file,\n }));\n\n if (!strictValidation) {\n // In partial upload mode, filter out oversized files\n validFiles = acceptedFiles.filter((file) => !maxSize || file.size <= maxSize);\n } else {\n // In strict mode, reject all files if any are oversized\n validFiles = [];\n }\n }\n\n return { sizeRejections, validFiles };\n },\n\n /**\n * Processes file rejections and groups them by error code\n *\n * This function takes an array of file rejections and organizes them into\n * error groups based on the error codes. Each group tracks a count of affected\n * files and the file references.\n *\n * @param rejections - Array of file rejections to process\n * @returns A record of error groups indexed by error code\n * @remarks\n * - Multiple files with the same error code are consolidated into a single group\n * - A file can appear in multiple groups if it has multiple error codes\n * - Each group tracks:\n * - count: Number of files affected by this error\n * - files: References to the affected files\n * - message: The error message (shared across the group)\n * - Used for generating consolidated error messages and UI summaries\n */\n processRejections: (rejections: FileRejection[]): Record<string, ErrorGroup> => {\n const groups: Record<string, ErrorGroup> = {};\n rejections.forEach((rejection) => {\n rejection.errors.forEach((error) => {\n const group = getOrCreateErrorGroup(groups, error.code, error.message);\n group.count++;\n group.files.push(rejection.file);\n });\n });\n\n return groups;\n },\n };\n};\n","import { useCallback } from 'react';\n\nimport { UploadValidationContextType } from '../../../providers/UploadValidationProvider';\nimport { FileRejection, FileResource } from '../../../types/commonTypes';\nimport { createRejectionHelpers } from './createFileRejectionHelpers';\n\n/**\n * Hook that handles file validation and processing when files are dropped\n * @param props Object containing:\n * - files: Currently selected files in the uploader\n * - onDrop: Optional callback triggered for both accepted and rejected files\n * - onDropAccepted: Optional callback triggered only for accepted files\n * - onDropRejected: Optional callback triggered only for rejected files\n * - setFiles: Function to update the files state with newly accepted files\n * - validation: Validation context (from either provider or local validation)\n * @returns Callback function for handling file drop events from react-dropzone\n * @remarks\n * - Performs validation in a specific sequence: file types → file sizes → file count\n * - Groups and formats error messages for consistent UI display\n * - Handles strict vs. partial validation modes differently:\n * - Strict: Rejects all files if any would be invalid\n * - Partial: Accepts valid files while rejecting invalid ones\n * - Updates file state only for valid files\n * - Clears validation state on completely successful drops\n * - Calls appropriate callbacks with processed files\n * - Sets validation errors in the validation context for UI display\n */\n\nexport type UseHandleDropProps = {\n /** Current files in the upload area */\n files: FileResource[];\n /** Callback when files are dropped */\n onDrop?: (acceptedFiles: File[], rejectedFiles: FileRejection[]) => void;\n /** Callback when files are accepted */\n onDropAccepted?: (acceptedFiles: File[]) => void;\n /** Callback when files are rejected */\n onDropRejected?: (rejectedFiles: FileRejection[]) => void;\n /** Function to update the files state */\n setFiles: (files: FileResource[]) => void;\n /** Validation context */\n validation: UploadValidationContextType;\n};\n\nexport const useHandleDrop = ({\n files,\n onDrop,\n onDropAccepted,\n onDropRejected,\n setFiles,\n validation,\n}: UseHandleDropProps) => {\n const { clearAllValidation, setDropValidationErrors, setFileRejections, strictValidation } = validation;\n\n return useCallback(\n (acceptedFiles: File[], rejectedFiles: FileRejection[]) => {\n const {\n getFormattedErrorGroupMessage,\n handleFileCountLimits,\n handleFileSizeValidation,\n processRejections,\n } = createRejectionHelpers(validation);\n\n // Step 1: Validate file sizes\n // Note: acceptedFiles have already passed type validation by react-dropzone\n const { sizeRejections, validFiles } = handleFileSizeValidation(acceptedFiles);\n\n // Filter out only File objects from current files for validation\n // This is needed because FileResource can include RemoteFile objects\n const currentFileObjects = files.filter((file): file is File => file instanceof File);\n\n // Step 2: Handle file count limits with all validated files\n // This combines all rejections from previous validation steps, including custom validator errors\n const { allAcceptedFiles, allRejections } = handleFileCountLimits(currentFileObjects, validFiles, [\n ...rejectedFiles, // Already includes custom validation errors\n ...sizeRejections,\n ]);\n\n // Step 3: Process all rejections and group by error code\n // This creates a dictionary of error groups for better UI presentation\n // Message functions are preserved at this stage for proper grouping\n const errorGroups = processRejections(allRejections);\n\n // Step 4: Extract errors for UI display, now resolving messages with proper context\n // We need one error message per error type for the UI\n const errors = Object.entries(errorGroups).map(([code]) => ({\n code,\n message: getFormattedErrorGroupMessage(code, { code, message: errorGroups[code].message }, errorGroups),\n }));\n\n // Step 5: Format rejections for callbacks - maintain file-to-errors relationship\n // These preserve the connection between each file and its specific rejection reasons\n const processedRejections = allRejections.map((rejection) => ({\n errors: rejection.errors.map((error) => ({\n code: error.code,\n message: getFormattedErrorGroupMessage(error.code, error, errorGroups),\n })),\n file: rejection.file,\n }));\n\n const hasRejections = processedRejections.length > 0;\n\n // Step 6: Handle strict validation - reject all files if there are any rejections\n if (strictValidation && hasRejections) {\n // In strict mode, even valid files are rejected if any file has issues\n const strictRejections = [\n ...processedRejections,\n ...allAcceptedFiles.map((file) => ({\n errors,\n file,\n })),\n ];\n\n setFileRejections(strictRejections);\n setDropValidationErrors(errors);\n onDropRejected?.(strictRejections);\n onDrop?.([], strictRejections);\n return;\n }\n\n // Step 7: Handle partial upload mode (OR no rejections)\n setFileRejections(processedRejections);\n setDropValidationErrors(errors);\n onDropRejected?.(processedRejections);\n\n // Step 8: Handle successful file uploads\n if (allAcceptedFiles.length > 0) {\n if (!hasRejections) {\n // Clear validation only if there are no rejections\n clearAllValidation();\n }\n // Update file state with new files (as FileResource[])\n const newFileResources: FileResource[] = [...files, ...allAcceptedFiles];\n setFiles(newFileResources);\n onDropAccepted?.(allAcceptedFiles);\n }\n\n // Always call onDrop with both sets of files\n onDrop?.(allAcceptedFiles, processedRejections);\n },\n [\n files,\n clearAllValidation,\n setDropValidationErrors,\n setFiles,\n onDrop,\n onDropAccepted,\n onDropRejected,\n setFileRejections,\n strictValidation,\n validation,\n ]\n );\n};\n","import { FileResource } from '../../../types/commonTypes';\n\n/**\n * Hook that determines if file uploads are currently available/disabled\n * @param props Object containing:\n * - disabled: Optional flag to manually disable uploads\n * - files: Currently selected files\n * - maxFiles: Optional maximum number of files allowed\n * @returns Object containing:\n * - hasReachedFileLimit: Whether max file count has been reached\n * - isDisabled: Whether uploads are currently disabled\n * @remarks\n * - Combines both manual disable state and file limit restrictions\n * - Used to prevent uploads when either condition is met\n */\nexport type UploadAvailabilityParams = {\n /** Whether the upload is disabled */\n disabled?: boolean;\n /** Current files in the upload area */\n files: FileResource[];\n /** Maximum number of files allowed */\n maxFiles?: number;\n};\n\ntype UploadAvailability = {\n hasReachedFileLimit: boolean;\n isDisabled: boolean;\n};\n\nexport const useUploadAvailability = ({\n disabled = false,\n files,\n maxFiles,\n}: UploadAvailabilityParams): UploadAvailability => {\n // Calculate if we've reached the file limit\n const hasReachedFileLimit = maxFiles !== undefined && files.length >= maxFiles;\n // Consider both local and provider disabled states\n const isDisabled = disabled || hasReachedFileLimit;\n\n return {\n hasReachedFileLimit,\n isDisabled,\n };\n};\n","import { UploadValidationContextType } from '../../providers/UploadValidationProvider';\n\n/**\n * Creates an optimized validator function for React-Dropzone that preserves\n * function-based validation messages for later resolution\n *\n * @param validationContext - The validation context containing the custom validator\n * @returns A validator function compatible with React-Dropzone\n */\nexport const createDropzoneValidator = (validationContext: UploadValidationContextType) => {\n // Extract the custom validator function\n const { validateCustomRules } = validationContext;\n\n // Return undefined if no custom validator exists\n if (typeof validateCustomRules !== 'function') {\n return undefined;\n }\n\n // Return the actual validator function\n return (file: File) => {\n // Run the custom validator\n const validationResult = validateCustomRules(file);\n\n // If no errors, return null (valid)\n if (!validationResult) {\n return null;\n }\n\n // If no errors in array, return null\n if (validationResult.length === 0) {\n return null;\n }\n\n // Return errors with message functions preserved\n // This allows for proper error grouping before message resolution\n return validationResult.map((error) => ({\n code: error.code,\n message: error.message,\n }));\n };\n};\n","import { CommonFileTypes } from '../types/commonTypes';\nimport { ACCEPTED_MIME_TYPES } from './constants';\n\n/**\n * Utility function that converts file type restrictions into MIME type format for react-dropzone\n * @param accept - Optional file type restrictions, can be either:\n * - A preset category from CommonFileTypes (e.g., 'images', 'pdfs', 'documents')\n * - An array of specific MIME types (e.g., ['image/jpeg', 'image/png'])\n * @returns Object mapping MIME types to empty arrays for react-dropzone's accept prop\n * @remarks\n * - Returns undefined when no restrictions are provided (accepts all file types)\n * - Handles both preset categories and custom MIME type arrays\n * - Formats MIME types to match react-dropzone's expected structure\n */\n\nexport const getMimeTypes = (accept?: CommonFileTypes | string[]) => {\n if (!accept) {\n return undefined; // No restrictions\n }\n\n if (Array.isArray(accept)) {\n return accept.reduce((acc, curr) => ({ ...acc, [curr]: [] }), {}); // Custom MIME types\n }\n\n return ACCEPTED_MIME_TYPES[accept].reduce((acc, curr) => ({ ...acc, [curr]: [] }), {}); // Preset category\n};\n","import { cn } from '@evolve.ui/theme-system';\n\nimport { FileError } from '../types';\n\ntype DropzoneState = {\n disableDragValidation: boolean;\n disabled: boolean;\n isDragActive: boolean;\n validationError?: FileError | null;\n};\n\nexport const getUploadZoneStyles = ({\n disabled,\n disableDragValidation,\n isDragActive,\n validationError,\n}: DropzoneState) => {\n const isInvalid = Boolean(validationError);\n const isErrorState = disableDragValidation ? false : isInvalid;\n const isDefaultState = !isDragActive && !isErrorState;\n const isDraggedOver = isDragActive && (disableDragValidation || !isInvalid);\n const isDefaultAppearance = isDefaultState && !disabled;\n\n return cn(\n // Layout & Container\n [\n 'relative',\n 'flex flex-col',\n 'h-full w-full',\n 'items-center justify-center',\n 'rounded-container',\n 'outline-dashed outline-1 -outline-offset-1',\n 'p-sm',\n 'transition-colors',\n 'hover:bg-background-hover hover:outline-border-hover', // Hover (when not dragging)\n ],\n\n // Focus & Interactive Base\n ['hui-focus-visible-outline'],\n\n // Interactive States\n {\n // Disabled\n 'cursor-not-allowed bg-background-disabled outline-border-disabled hover:bg-background-disabled hover:outline-border-disabled':\n disabled,\n\n // Enabled\n 'cursor-pointer active:bg-background-pressed active:outline active:outline-4 active:outline-focus-primary':\n !disabled,\n\n // Drag Active (only when not disabled)\n 'outline outline-4 outline-offset-0 outline-focus-primary': isDragActive && !disabled,\n },\n\n // Visual States\n {\n // Error (only when not disabled)\n 'bg-background-critical-light outline-dashed outline-1 -outline-offset-1 outline-border-critical':\n isErrorState && !disabled,\n\n // Drag Over\n 'bg-background-hover': isDraggedOver && !isErrorState && !disabled,\n\n // Default\n 'bg-background-primary outline-border-secondary': isDefaultAppearance,\n }\n );\n};\n","import { useMemo } from 'react';\n\nimport { useWindowIsMobile } from '../../../../../providers';\nimport { SubtleLink } from '../../../../../Typography/Links/Links';\nimport { UploadValidationContextType } from '../../../../providers/UploadValidationProvider';\n\ntype DropzoneTextProps = {\n disableDragValidation: boolean;\n filePluralizationText: string;\n hasReachedFileLimit: boolean;\n isDisabled: boolean;\n isDragActive: boolean;\n isDragReject: boolean;\n maxFiles?: number;\n validation: UploadValidationContextType;\n};\n\nexport const DropzoneText = ({\n disableDragValidation,\n filePluralizationText,\n hasReachedFileLimit,\n isDisabled,\n isDragActive,\n isDragReject,\n maxFiles,\n validation,\n}: DropzoneTextProps) => {\n const isMobile = useWindowIsMobile();\n const { dragValidationError } = validation;\n\n const dropzoneText = useMemo(() => {\n // Static states (before any drag)\n if (hasReachedFileLimit) {\n return <>{`${maxFiles} file limit reached. Remove files to upload more.`}</>;\n }\n\n // Show validation messages during drag\n if (isDragActive && dragValidationError?.code) {\n return <>{dragValidationError.message}</>;\n }\n\n // Show \"Drop files here\" during valid drag\n if (isDragActive && (disableDragValidation || !isDragReject)) {\n return <>Drop files here to upload</>;\n }\n\n // Default states (no drag)\n if (isMobile) {\n return <>{`Click to browse and add ${filePluralizationText}`}</>;\n }\n\n // Desktop default\n return (\n <>\n <SubtleLink\n className=\"group-hover:underline\"\n disabled={isDisabled}\n href=\"#\"\n onClick={(e) => e.preventDefault()}\n >\n Browse\n </SubtleLink>{' '}\n or drag {filePluralizationText} here to upload\n </>\n );\n }, [\n filePluralizationText,\n hasReachedFileLimit,\n isDisabled,\n isDragActive,\n isDragReject,\n disableDragValidation,\n maxFiles,\n isMobile,\n dragValidationError,\n ]);\n\n return <>{dropzoneText}</>;\n};\n\nDropzoneText.displayName = 'DropzoneText';\n","import { TextColorAliases } from '@evolve.ui/theme-system';\n\nimport { UploadSimple } from '../../../../../Icons';\nimport { BodyPrimary } from '../../../../../Typography/Text/Text';\nimport { DropzoneText } from './DropzoneText';\n\ntype DropzoneContentProps = {\n dropzoneTextProps: React.ComponentProps<typeof DropzoneText>;\n isDisabled: boolean;\n};\n\nexport const DropzoneContent = ({ dropzoneTextProps, isDisabled }: DropzoneContentProps) => {\n const dropzoneTextColor: TextColorAliases = isDisabled ? 'disabled' : 'primary';\n\n return (\n <div className=\"flex w-full flex-col items-center gap-xs\">\n <UploadSimple color={dropzoneTextColor} />\n <BodyPrimary\n className=\"text-center\"\n color={dropzoneTextColor}\n >\n <DropzoneText {...dropzoneTextProps} />\n </BodyPrimary>\n </div>\n );\n};\n\nDropzoneContent.displayName = 'DropzoneContent';\n","import { Badge } from '../../../../../Badge/Badge';\nimport { ColumnType, Table } from '../../../../../Table';\nimport { BodyPrimary, H4 } from '../../../../../Typography/Text/Text';\nimport { FileErrorCode, FileRejection } from '../../../../types';\nimport { builtInErrorCodes } from '../../../../utils/constants';\n\ntype DisplayMode = 'by-error' | 'by-file';\n\ntype Props = {\n displayMode: DisplayMode;\n fileRejections: FileRejection[];\n};\n\ntype TableData = {\n col1: string;\n col2: string | string[];\n col3: string | string[];\n key: string;\n};\n\nconst BadgeCell = ({ codes }: { codes: string | string[] }) => {\n const codeArray = Array.isArray(codes) ? codes : [codes];\n\n return (\n <div className=\"flex flex-col justify-start gap-[4px]\">\n {codeArray.map((code, index) => (\n <Badge\n className=\"my-[2px]\"\n color=\"critical\"\n data-testid={`badge-${code}`}\n emphasis={builtInErrorCodes.includes(code as FileErrorCode) ? 'subtle' : 'bold'}\n key={`${code}-${index}`}\n size=\"xs\"\n >\n {code}\n </Badge>\n ))}\n </div>\n );\n};\n\nexport const FileRejectionsDisplay = ({ displayMode, fileRejections = [] }: Props) => {\n const totalErrors = fileRejections.reduce((sum, rejection) => sum + rejection.errors.length, 0);\n\n const tableData =\n displayMode === 'by-error'\n ? fileRejections.flatMap((rejection, fileIndex) =>\n rejection.errors.map((error, errorIndex) => ({\n col1: rejection.file.name,\n col2: error.code,\n col3: error.message,\n key: `${rejection.file.name}-${fileIndex}-${errorIndex}`,\n }))\n )\n : fileRejections.map((rejection, index) => ({\n col1: rejection.file.name,\n col2: rejection.errors.map((error) => error.code),\n col3: rejection.errors.map((error) => error.message),\n key: `${rejection.file.name}-${index}`,\n }));\n\n const columns: ColumnType<TableData>[] = [\n {\n align: 'left',\n header: 'File Name',\n key: 'col1',\n },\n {\n header: displayMode === 'by-error' ? 'Error Code' : 'Error Codes',\n key: 'col2',\n renderItem: (data: TableData) => <BadgeCell codes={data.col2} />,\n },\n {\n header: displayMode === 'by-error' ? 'Message' : 'Messages',\n key: 'col3',\n renderItem:\n displayMode === 'by-file'\n ? (data: TableData) => (\n <div className=\"flex flex-col gap-[2px]\">\n {(data.col3 as string[]).map((message, index) => (\n <span key={index}>{message}</span>\n ))}\n </div>\n )\n : undefined,\n },\n ];\n\n return (\n <>\n <div className=\"mb-xs mt-sm flex items-center justify-between px-[2px]\">\n <H4>File Rejections {displayMode === 'by-error' ? '(by Error)' : '(by File)'}</H4>\n <BodyPrimary>\n {fileRejections.length} files ({totalErrors} errors)\n </BodyPrimary>\n </div>\n <Table\n columns={columns}\n data={tableData}\n emptyStateHeaderText=\"No files rejected\"\n emptyStateSupportingText=\"Upload files to monitor rejections\"\n fillHorizontal\n hideBorder\n rowDensity=\"sm\"\n />\n </>\n );\n};\n\nFileRejectionsDisplay.displayName = 'FileRejectionsDisplay';\n","import { Tabs } from '../../../../../Tabs/Tabs';\nimport { FileRejection } from '../../../../types/commonTypes';\nimport { FileRejectionsDisplay } from './FileRejectionsDisplay';\n\ntype Props = {\n fileRejections: FileRejection[];\n};\n\nexport const FileDropzoneDebugger = ({ fileRejections = [] }: Props) => {\n return (\n <div className=\"mt-md rounded-container p-sm outline-dashed outline-1 -outline-offset-1 outline-border-secondary\">\n <Tabs\n tabs={[\n {\n content: (\n <FileRejectionsDisplay\n displayMode=\"by-error\"\n fileRejections={fileRejections}\n />\n ),\n contentId: 'rejections-by-error',\n label: 'Errors',\n },\n {\n content: (\n <FileRejectionsDisplay\n displayMode=\"by-file\"\n fileRejections={fileRejections}\n />\n ),\n contentId: 'rejections-by-file',\n label: 'Files',\n },\n ]}\n />\n </div>\n );\n};\n\nFileDropzoneDebugger.displayName = 'FileDropzoneDebugger';\n","import { cn } from '@evolve.ui/theme-system';\nimport { useContext } from 'react';\nimport { useDropzone } from 'react-dropzone';\n\nimport { Caption, LabelMini } from '../../../Typography/Text/Text';\nimport { formatFileSize } from '../../../utils/formatFileSize';\nimport { useFileValidation } from '../../hooks';\nimport { useHandleDragEnter } from '../../hooks/upload/useHandleDragEnter/useHandleDragEnter';\nimport { useHandleDrop } from '../../hooks/upload/useHandleDrop/useHandleDrop';\nimport { useUploadAvailability } from '../../hooks/upload/useUploadAvailability/useUploadAvailability';\nimport { createDropzoneValidator } from '../../hooks/validation/createDropzoneValidator';\nimport { FileUploadContext, FileUploadContextType } from '../../providers/FileUploadProvider';\nimport { FileDropzoneProps } from '../../types/sharedTypes';\nimport { getMimeTypes } from '../../utils/getMimeTypes';\nimport { getUploadZoneStyles } from '../../utils/styles';\nimport { DropzoneContent } from './components/DropzoneContent/DropzoneContent';\nimport { FileDropzoneDebugger } from './components/FileDropzoneDebugger/FileDropzoneDebugger';\n\n/**\n * FileDropzone component for handling file uploads with drag and drop support.\n * This is a versatile file input component that can work both as a standalone\n * component or as part of the FileUpload system.\n */\n\n/**\n * Handles the dual-mode functionality of the FileDropzone component, supporting both standalone usage\n * and provider-wrapped usage.\n *\n * ## Validation Modes\n * - **Provider Mode**: Uses validation context from FileUploadProvider for coordinated validation across components\n * - **Standalone Mode**: Creates local validation instance for independent operation\n *\n * ## Props & Context Resolution\n * The component follows a specific precedence order for each property:\n * 1. Direct props take highest priority (for granular control)\n * 2. Context values serve as fallbacks (for coordinated state)\n * 3. Default values as final fallbacks (for safety)\n *\n * This enables two key use cases:\n * 1. Standalone Usage: <FileDropzone maxFiles={5} onDrop={handleDrop} />\n * 2. Provider Usage:\n * <FileUploadProvider maxFiles={5}>\n * <FileDropzone /> // Inherits provider config\n * <FileDropzone maxFiles={1} /> // Overrides specific provider values\n * </FileUploadProvider>\n */\nexport const FileDropzone = ({\n accept: acceptProp,\n ariaLabel = 'Browse or drag files here to upload.',\n className,\n 'data-testid': dataTestId = 'file-dropzone',\n disabled: disabledProp = false,\n disableDragValidation = false,\n error,\n files: filesProp,\n helpText,\n helpTextAlignCenter,\n hideErrors = false,\n hideHelpText = false,\n labelText,\n maxFiles: maxFilesProp,\n maxSize: maxSizeProp,\n onDrop: onDropProp,\n onDropAccepted: onDropAcceptedProp,\n onDropRejected: onDropRejectedProp,\n onFilesChange: onFilesChangeProp,\n showDebugger,\n strictValidation,\n validator,\n}: FileDropzoneProps) => {\n const uploadContext = useContext<FileUploadContextType | undefined>(FileUploadContext);\n\n const validationConfig = {\n accept: acceptProp,\n error,\n maxFiles: maxFilesProp,\n maxSize: maxSizeProp,\n strictValidation,\n validator,\n };\n\n /* IMPORTANT: This component supports both standalone usage and provider usage */\n // useFileValidation automatically detects if we're in a provider context\n // If not in provider, create local validation for standalone usage\n const validation = useFileValidation(validationConfig);\n\n // Determine whether to use context or local state for files and setFiles\n const files = filesProp ?? uploadContext?.files ?? [];\n const setFiles = onFilesChangeProp ?? uploadContext?.setFiles ?? (() => {});\n\n // Intentionally check both props and context with precedence order\n const disabled = disabledProp || uploadContext?.disabled;\n const onDrop = onDropProp ?? uploadContext?.onDrop;\n const onDropAccepted = onDropAcceptedProp ?? uploadContext?.onDropAccepted;\n const onDropRejected = onDropRejectedProp ?? uploadContext?.onDropRejected;\n const maxFiles = maxFilesProp ?? validation.maxFiles;\n const maxSize = maxSizeProp ?? validation.maxSize;\n const accept = acceptProp ?? validation.accept;\n /* END IMPORTANT */\n\n // Check if upload is disabled based on current state\n const { hasReachedFileLimit, isDisabled } = useUploadAvailability({\n disabled,\n files,\n maxFiles,\n });\n\n const formattedMaxSize = maxSize ? formatFileSize(maxSize) : undefined;\n\n const defaultHelpText = formattedMaxSize ? `File size must be smaller than ${formattedMaxSize}` : undefined;\n\n // If custom help text is provided, use it. Otherwise, use the default help text, or hide it.\n const helpTextToDisplay = hideHelpText ? undefined : (helpText ?? defaultHelpText);\n\n // Configure text based on multiple vs single file mode\n const allowMultipleFiles = maxFiles === undefined || maxFiles > 1;\n const filePluralizationText = allowMultipleFiles ? 'files' : 'a file';\n const mimeTypes = getMimeTypes(accept);\n\n // Set up drag and drop handlers\n const handleDrop = useHandleDrop({\n files,\n onDrop,\n onDropAccepted,\n onDropRejected,\n setFiles,\n validation,\n });\n\n const handleDragEnter = useHandleDragEnter({\n files,\n mimeTypes,\n validation,\n validator,\n });\n\n // Configure the dropzone\n const { getInputProps, getRootProps, isDragActive, isDragReject } = useDropzone({\n accept: mimeTypes,\n disabled: isDisabled,\n maxSize,\n multiple: allowMultipleFiles,\n onDragEnter: disableDragValidation ? validation.clearAllValidation : handleDragEnter,\n onDragLeave: validation.clearAllValidation,\n onDrop: handleDrop,\n // @ts-expect-error Our validator returns potentially function-based messages, React-Dropzone expects strings.\n // This is intentional and allows us to resolve dynamic messages later with proper file counts.\n validator: createDropzoneValidator(validation),\n });\n\n // Determine Dropzone styles based on interaction state\n const activeCode = isDragActive ? validation.dragValidationError : validation.dropValidationErrors[0];\n const uploadZoneStyles = getUploadZoneStyles({\n disabled: isDisabled,\n disableDragValidation,\n isDragActive,\n validationError: activeCode,\n });\n\n return (\n <div\n aria-label={ariaLabel}\n className={cn('flex h-full w-full flex-col gap-[4px]', className)}\n role=\"region\"\n >\n {labelText && <LabelMini color={isDisabled ? 'disabled' : 'secondary'}>{labelText}</LabelMini>}\n <div\n {...getRootProps({\n 'aria-disabled': isDisabled,\n className: cn('group min-h-[88px] w-full', uploadZoneStyles),\n 'data-testid': `${dataTestId}-container`,\n onClick: validation.clearAllValidation,\n role: 'button',\n })}\n >\n <input\n {...getInputProps({\n 'aria-label': `Upload ${filePluralizationText}`,\n 'data-testid': `${dataTestId}-input`,\n })}\n />\n <DropzoneContent\n dropzoneTextProps={{\n disableDragValidation,\n filePluralizationText,\n hasReachedFileLimit,\n isDisabled,\n isDragActive,\n isDragReject,\n maxFiles,\n validation,\n }}\n isDisabled={isDisabled}\n />\n </div>\n <div\n className={cn('relative flex flex-col gap-[4px]', {\n 'items-center': helpTextAlignCenter,\n })}\n >\n {helpTextToDisplay && (\n <Caption color={isDisabled ? 'disabled' : 'secondary'}>{helpTextToDisplay}</Caption>\n )}\n {!hideErrors &&\n validation.dropValidationErrors.map((error, index) => (\n <Caption\n color=\"critical\"\n key={`${error.code}-${index}`}\n role=\"alert\"\n >\n {error.message}\n </Caption>\n ))}\n </div>\n {/* Display debug information around fileRejections when showDebugger is true */}\n {showDebugger && <FileDropzoneDebugger fileRejections={validation.fileRejections} />}\n </div>\n );\n};\n\nFileDropzone.displayName = 'FileDropzone';\n","import { BaseFileCardProps } from '../../../components/types';\n\n/**\n * Helper function to check if an element or its parents have the data-no-drag attribute\n * Exported for testing, you should probably be using the `dataNoDragSortable` function instead\n * @param element - The element to check\n * @returns Whether the element or any of its parents have the data-no-drag attribute\n */\nexport const hasDataNoDragOrParent = (element: HTMLElement | null): boolean => {\n if (!element) {\n return false;\n }\n if (element.hasAttribute('data-no-drag')) {\n return true;\n }\n if (element.parentElement) {\n return hasDataNoDragOrParent(element.parentElement);\n }\n return false;\n};\n\n/**\n * Modified sortable object that stops propagation if the parent element has the data-no-drag attribute\n * @param sortable - The sortable object to modify\n * @returns The modified sortable object\n */\nexport const dataNoDragSortable = (sortable: BaseFileCardProps['sortable'] | undefined | null) => {\n if (!sortable) {\n return null;\n }\n return {\n ...sortable,\n attributes: {\n ...sortable.attributes,\n },\n listeners: {\n ...sortable.listeners,\n onPointerDown: (e: React.PointerEvent) => {\n if (hasDataNoDragOrParent(e.target as HTMLElement)) {\n e.stopPropagation();\n return;\n }\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n sortable.listeners?.onPointerDown?.(e);\n },\n },\n };\n};\n","import { cn } from '@evolve.ui/theme-system';\n\nimport { Badge } from '../../../Badge/Badge';\nimport { Checkbox } from '../../../ChoiceListItem';\nimport { IconButton } from '../../../IconButton/IconButton';\nimport { DotsSixVertical, DotsThreeOutlineVertical, Paperclip, Trash } from '../../../Icons';\nimport { Menu, MenuItem } from '../../../Menu';\nimport { ProgressCircle } from '../../../ProgressCircle/ProgressCircle';\nimport { BodyPrimary, BodySecondary } from '../../../Typography/Text/Text';\nimport { formatFileSize } from '../../../utils/formatFileSize';\nimport { dataNoDragSortable } from '../../components/GridFileCard/utils/sortable';\nimport { useImageFilePreviewUrl } from '../../hooks/filePreview/useImageFilePreviewUrl';\nimport { FileResource } from '../../types';\nimport { BaseFileCardProps } from '../types';\n\ntype GridViewProps = BaseFileCardProps & {\n badge?: string;\n 'data-testid'?: string;\n statusText?: string;\n};\n\n/**\n * Actions to render. First 3 actions will be visible buttons,\n * remaining will appear in overflow menu.\n */\nconst MAX_VISIBLE_ACTIONS = 3;\n\nexport const GridFileCard = ({\n actions = [],\n badge,\n className,\n 'data-testid': dataTestId = 'grid-file-card',\n draggable,\n errorMessage,\n fileName,\n hideFileName = false,\n hideFileSize = false,\n hideFileStatus = false,\n imageSource,\n isSelected,\n onDelete,\n onImageError,\n onSelect,\n progress,\n selectable,\n sortable,\n status = 'default',\n statusIcon,\n statusText,\n}: GridViewProps) => {\n const previewUrl = useImageFilePreviewUrl(imageSource);\n\n const isRemoteFile = 'url' in imageSource;\n const fileSize = isRemoteFile ? '' : formatFileSize(imageSource.size);\n\n // Automatically hide file size for URLs, respect the prop for Files\n const shouldHideFileSize = hideFileSize || isRemoteFile;\n\n const defaultFileName = isRemoteFile ? (imageSource.url.split('/').pop() ?? 'image') : imageSource.name;\n const fileDisplayName = fileName ?? defaultFileName;\n\n // Status checks\n const isError = status === 'error';\n const isPending = status === 'pending';\n const isProgressing = status === 'progressing';\n const isComplete = status === 'complete';\n const isDragging = sortable?.isDragging ?? false;\n\n // Determine when to auto-render ProgressCircle\n // Only when statusIcon is not provided AND status is pending/progressing/complete\n const shouldShowProgressCircle = !statusIcon && (isPending || isProgressing || isComplete);\n\n // Determine what to show below the file name (priority: error > progressing > size)\n let fileStatusText = null;\n\n if (isError && errorMessage && !hideFileStatus) {\n fileStatusText = (\n <BodySecondary\n className=\"text-text-critical\"\n data-no-drag\n >\n {errorMessage}\n </BodySecondary>\n );\n } else if ((isProgressing || isPending) && !hideFileStatus) {\n // Use custom statusText if provided, otherwise use default\n const defaultStatusText = isPending ? 'Pending' : 'Uploading';\n const displayStatusText = statusText ?? defaultStatusText;\n fileStatusText = (\n <BodySecondary\n color=\"secondary\"\n data-no-drag\n >\n {displayStatusText}\n </BodySecondary>\n );\n } else if (!shouldHideFileSize) {\n fileStatusText = (\n <BodySecondary\n color={isError ? 'critical' : 'secondary'}\n data-no-drag\n >\n {fileSize}\n </BodySecondary>\n );\n }\n\n const actionsWithDelete = [\n ...actions,\n ...(onDelete\n ? [\n {\n icon: Trash,\n iconStyle: 'regular',\n name: 'Delete',\n onClick: (_: React.MouseEvent<HTMLElement>, fileResource: FileResource) => onDelete(fileResource),\n },\n ]\n : []),\n ];\n\n // Modified sortable object that prevents drag events if the parent element has the data-no-drag attribute\n const modifiedSortable = dataNoDragSortable(sortable);\n\n // Handle visible actions\n const visibleActions = actionsWithDelete.slice(0, MAX_VISIBLE_ACTIONS);\n\n // Handle overflow actions - only used when we have 4+ actions\n const overflowActions = actionsWithDelete.slice(MAX_VISIBLE_ACTIONS);\n\n // Map status to ProgressCircle-compatible status (only needed when shouldShowProgressCircle is true)\n let progressCircleStatus: 'pending' | 'progressing' | 'complete';\n if (isPending) {\n progressCircleStatus = 'pending';\n } else if (isProgressing) {\n progressCircleStatus = 'progressing';\n } else {\n progressCircleStatus = 'complete';\n }\n\n const isProcessing = isPending || isProgressing;\n\n return (\n <div\n aria-busy={isProcessing || undefined}\n className={cn(\n 'group/grid-file-card relative flex w-full min-w-0 cursor-pointer flex-col gap-xs',\n 'rounded-container p-xs',\n 'ring-1',\n 'transition-all duration-200',\n 'hover:z-10',\n 'focus-within:z-10',\n {\n // Error state\n 'bg-background-critical-light ring-border-critical focus-within:bg-background-critical-light focus-within:ring-border-critical hover:bg-background-critical-light hover:ring-border-critical':\n isError && !isDragging,\n // Default state\n 'bg-background-primary ring-transparent focus-within:bg-background-subdued focus-within:ring-border-secondary hover:bg-background-subdued hover:ring-border-secondary':\n !isError && !isDragging,\n // Drag state\n 'z-50 scale-105 border-border-selected bg-background-secondary shadow-01': isDragging,\n },\n className\n )}\n data-testid={dataTestId}\n ref={modifiedSortable?.setNodeRef}\n style={modifiedSortable?.styles}\n {...modifiedSortable?.attributes}\n {...modifiedSortable?.listeners}\n >\n <div className=\"relative aspect-square min-w-0 items-center justify-center rounded-container bg-background-subdued\">\n <div className=\"absolute left-0 top-0 z-10 flex items-center gap-[2px] p-xs\">\n {selectable && (\n <div data-no-drag>\n <Checkbox.Option\n checked={isSelected}\n className=\"![grid-template-columns:24px_0px_1fr]\"\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n e.stopPropagation();\n onSelect?.(imageSource, e.target.checked);\n }}\n />\n </div>\n )}\n {badge && (\n <Badge\n className=\"mt-[3px]\"\n color=\"neutral\"\n emphasis=\"bold\"\n round\n size=\"xs\"\n >\n {badge}\n </Badge>\n )}\n </div>\n {draggable && (\n <div className=\"absolute right-[4.4px] top-[8px] z-10 p-[2px]\">\n <DotsSixVertical\n className=\"flex-shrink-0 cursor-grab\"\n color=\"inverse\"\n size=\"sm\"\n style=\"bold\"\n />\n </div>\n )}\n {previewUrl ? (\n <img\n alt={fileDisplayName}\n className=\"absolute inset-0 h-full w-full rounded-container object-cover\"\n onError={() => onImageError?.(imageSource)}\n src={previewUrl}\n />\n ) : (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <Paperclip\n color=\"primary\"\n size=\"md\"\n />\n </div>\n )}\n <div\n className={cn(\n // positioning\n 'absolute inset-0',\n // children element positioning\n 'flex items-end justify-center',\n // styling\n 'rounded-container bg-background-overlay/20 p-xs',\n // transitions\n 'opacity-0 transition-opacity duration-200',\n // group focus/hover states\n 'group-focus-within/grid-file-card:opacity-100 group-hover/grid-file-card:opacity-100',\n // mouse pointer\n 'cursor-pointer',\n {\n 'cursor-grab': draggable,\n }\n )}\n >\n <div className=\"flex items-center gap-xs\">\n {/* Visible Actions (max of 4) */}\n {visibleActions.map((action, index) => (\n <IconButton\n aria-label={action.name}\n data-no-drag\n disabled={isProcessing}\n hideTooltip\n icon={action.icon}\n // @ts-expect-error - Look into this\n iconStyle={action.iconStyle}\n key={`${action.name}-${index}`}\n onClick={(e) => {\n e.stopPropagation();\n action.onClick(e, imageSource);\n }}\n shape=\"circle\"\n size=\"xs\"\n style=\"inverse\"\n type=\"button\"\n variant=\"transparent\"\n />\n ))}\n\n {/* Overflow Menu */}\n {overflowActions.length > 0 && (\n <Menu\n data-no-drag\n hasRoundedBorders\n menuPlacement=\"bottom-start\"\n menuSize=\"sm\"\n numberOfColumns={3}\n trigger={\n <IconButton\n data-no-drag\n disabled={isProcessing}\n hideTooltip\n icon={DotsThreeOutlineVertical}\n iconStyle=\"fill\"\n onClick={() => {}}\n shape=\"circle\"\n size=\"xs\"\n style=\"inverse\"\n type=\"button\"\n variant=\"transparent\"\n />\n }\n >\n {overflowActions.map((action, index) => (\n <MenuItem\n color={action.name === 'Delete' ? 'critical' : undefined}\n data-no-drag\n id={`${action.name}-${fileDisplayName}`}\n key={`${action.name}-${index}`}\n leftIcon={action.icon}\n onClick={() => {\n action.onClick({} as React.MouseEvent<HTMLDivElement>, imageSource);\n }}\n primaryLabel={action.name}\n />\n ))}\n </Menu>\n )}\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-[2px]\">\n <div className=\"flex min-w-0 flex-1 cursor-auto flex-col gap-[2px]\">\n {!hideFileName && (\n <BodyPrimary\n className=\"truncate\"\n color={isError ? 'critical' : 'primary'}\n data-no-drag\n >\n {fileDisplayName}\n </BodyPrimary>\n )}\n {fileStatusText}\n </div>\n {shouldShowProgressCircle ? (\n <div\n className=\"flex items-center\"\n data-testid=\"grid-file-card-progress-circle\"\n >\n <ProgressCircle\n progress={progress}\n size=\"sm\"\n status={progressCircleStatus}\n />\n </div>\n ) : statusIcon ? (\n statusIcon.type === 'progressCircle' ? (\n <div\n className=\"flex items-center\"\n data-testid=\"grid-file-card-progress-circle\"\n >\n <ProgressCircle\n centerIcon={statusIcon.centerIcon}\n color={statusIcon.color}\n indeterminateAnimation={statusIcon.indeterminateAnimation}\n progress={progress}\n size=\"sm\"\n status={progressCircleStatus}\n />\n </div>\n ) : (\n <div\n className=\"flex items-center\"\n data-testid=\"grid-file-card-status-icon\"\n >\n <statusIcon.icon\n color={statusIcon.color}\n size=\"sm\"\n style={statusIcon.style}\n />\n </div>\n )\n ) : null}\n </div>\n </div>\n );\n};\n\nGridFileCard.displayName = 'GridFileCard';\n","import { cn } from '@evolve.ui/theme-system';\nimport { ChangeEvent } from 'react';\n\nimport { Checkbox } from '../../../ChoiceListItem';\nimport { IconButton } from '../../../IconButton/IconButton';\nimport { DotsSixVertical, Paperclip, Trash } from '../../../Icons';\nimport { ProgressCircle } from '../../../ProgressCircle/ProgressCircle';\nimport { BodyPrimary, BodySecondary } from '../../../Typography/Text/Text';\nimport { formatFileSize } from '../../../utils/formatFileSize';\nimport { useImageFilePreviewUrl } from '../../hooks/filePreview/useImageFilePreviewUrl';\nimport { BaseFileCardProps, ListFileCardStyle } from '../types';\n\nexport type ListFileCardProps = BaseFileCardProps & {\n cardStyle?: ListFileCardStyle;\n 'data-testid'?: string;\n showActionsOnHover?: boolean;\n statusText?: string;\n};\n\nexport const ListFileCard = ({\n actions,\n cardStyle,\n className,\n 'data-testid': dataTestId = 'list-file-card',\n draggable,\n errorMessage,\n fileName,\n hideFileName = false,\n hideFileSize = false,\n hideFileStatus = false,\n imageSource,\n isSelected,\n onDelete,\n onImageError,\n onSelect,\n progress,\n selectable,\n showActionsOnHover,\n status = 'default',\n statusIcon,\n statusText,\n}: ListFileCardProps) => {\n const previewUrl = useImageFilePreviewUrl(imageSource);\n\n const isRemoteFile = 'url' in imageSource;\n const fileSize = isRemoteFile ? '' : formatFileSize(imageSource.size);\n\n // Automatically hide file size for URLs, respect the prop for Files\n const shouldHideFileSize = hideFileSize || isRemoteFile;\n\n const defaultFileName = isRemoteFile ? (imageSource.url.split('/').pop() ?? 'image') : imageSource.name;\n const fileDisplayName = fileName ?? defaultFileName;\n\n // Status checks\n const isError = status === 'error';\n const isPending = status === 'pending';\n const isProgressing = status === 'progressing';\n const isComplete = status === 'complete';\n const isDragging = false; // ListFileCard doesn't currently support sortable YET, but adding for consistency with GridFileCard\n\n // Determine when to auto-render ProgressCircle\n // Only when statusIcon is not provided AND status is pending/progressing/complete\n const shouldShowProgressCircle = !statusIcon && (isPending || isProgressing || isComplete);\n\n // Determine what to show below the file name (priority: error > progressing > size)\n let fileStatusText = null;\n\n if (isError && errorMessage && !hideFileStatus) {\n fileStatusText = <BodySecondary className=\"text-text-critical\">{errorMessage}</BodySecondary>;\n } else if ((isProgressing || isPending) && !hideFileStatus) {\n // Use custom statusText if provided, otherwise use default\n const defaultStatusText = isPending ? 'Pending' : 'Uploading';\n const displayStatusText = statusText ?? defaultStatusText;\n fileStatusText = <BodySecondary color=\"secondary\">{displayStatusText}</BodySecondary>;\n } else if (!shouldHideFileSize) {\n fileStatusText = <BodySecondary color={isError ? 'critical' : 'secondary'}>{fileSize}</BodySecondary>;\n }\n\n const actionBtnClasses = showActionsOnHover\n ? cn(\n 'opacity-0 group-focus-within/list-file-card:opacity-100 group-hover/list-file-card:opacity-100',\n 'focus:opacity-100',\n 'transition-opacity duration-200'\n )\n : '';\n\n const isProcessing = isPending || isProgressing;\n\n // Map status to ProgressCircle-compatible status (only needed when shouldShowProgressCircle is true)\n let progressCircleStatus: 'pending' | 'progressing' | 'complete';\n if (isPending) {\n progressCircleStatus = 'pending';\n } else if (isProgressing) {\n progressCircleStatus = 'progressing';\n } else {\n progressCircleStatus = 'complete';\n }\n\n return (\n <div\n aria-busy={isProcessing || undefined}\n className={cn(\n 'group/list-file-card flex w-full min-w-0 cursor-pointer items-center justify-between p-xs',\n 'transition-all duration-200',\n {\n // Error state\n 'bg-background-critical-light': isError && !isDragging,\n // Default state\n 'bg-background-primary': !isError && !isDragging,\n // Drag state\n 'z-50 scale-105 border-border-selected bg-background-secondary shadow-01': isDragging,\n },\n // List View (BorderContained) vs Table View (Single Border)\n cardStyle === 'contained'\n ? cn('rounded-container border', {\n // Error state\n 'border-border-critical hover:border-border-critical hover:bg-background-critical-light':\n isError && !isDragging,\n // Default state\n 'border-border-secondary hover:border-border-secondary hover:bg-background-hover':\n !isError && !isDragging,\n })\n : cn('rounded-b-none border-b', {\n // Error state\n 'border-b-border-critical focus-within:border-b-border-critical hover:bg-background-critical-light':\n isError && !isDragging,\n // Default state\n 'border-b-border-secondary hover:bg-background-hover': !isError && !isDragging,\n }),\n className\n )}\n data-testid={dataTestId}\n >\n <div className=\"flex min-w-0 flex-1 items-center gap-xs\">\n <div className=\"flex items-center gap-[4px]\">\n {/* Show either Checkbox or DragHandle, not both */}\n {selectable ? (\n <Checkbox.Option\n checked={isSelected}\n className=\"![grid-template-columns:24px_0px_1fr]\"\n data-testid=\"list-file-card-select-checkbox\"\n onChange={(e: ChangeEvent<HTMLInputElement>) => {\n e.stopPropagation();\n onSelect?.(imageSource, e.target.checked);\n }}\n />\n ) : draggable ? (\n <DotsSixVertical\n color=\"primary\"\n size=\"sm\"\n style=\"bold\"\n />\n ) : null}\n {previewUrl ? (\n <div className=\"relative h-xl w-xl items-center justify-center overflow-hidden rounded-container bg-background-subdued\">\n <img\n alt={fileDisplayName}\n className=\"absolute inset-0 h-full w-full object-cover\"\n onError={() => {\n onImageError?.(imageSource);\n }}\n src={previewUrl}\n />\n </div>\n ) : (\n <div className=\"flex aspect-square min-w-xl items-center justify-center rounded-container bg-background-subdued\">\n <Paperclip\n color=\"primary\"\n size=\"sm\"\n />\n </div>\n )}\n </div>\n <div className=\"flex min-w-0 flex-1 flex-col gap-[2px]\">\n {!hideFileName && (\n <BodyPrimary\n className=\"truncate\"\n color={isError ? 'critical' : 'primary'}\n >\n {fileDisplayName}\n </BodyPrimary>\n )}\n {fileStatusText}\n </div>\n </div>\n {/* Actions */}\n <div className=\"flex items-center gap-[4px]\">\n {actions?.map((action, index) => (\n <IconButton\n aria-label={action.name}\n className={actionBtnClasses}\n disabled={isProcessing}\n icon={action.icon}\n key={`${action.name}-${index}`}\n onClick={(e) => {\n e.stopPropagation();\n action.onClick(e, imageSource);\n }}\n size=\"sm\"\n type=\"button\"\n />\n ))}\n {onDelete && (\n <IconButton\n aria-label=\"Remove file\"\n className={actionBtnClasses}\n data-testid=\"remove-file-button\"\n disabled={isProcessing}\n icon={Trash}\n onClick={() => onDelete(imageSource)}\n size=\"sm\"\n type=\"button\"\n />\n )}\n {shouldShowProgressCircle ? (\n <div\n className=\"flex items-center\"\n data-testid=\"list-file-card-progress-circle\"\n >\n <ProgressCircle\n progress={progress}\n size=\"sm\"\n status={progressCircleStatus}\n />\n </div>\n ) : statusIcon ? (\n statusIcon.type === 'progressCircle' ? (\n <div\n className=\"flex items-center\"\n data-testid=\"list-file-card-progress-circle\"\n >\n <ProgressCircle\n centerIcon={statusIcon.centerIcon}\n color={statusIcon.color}\n indeterminateAnimation={statusIcon.indeterminateAnimation}\n progress={progress}\n size=\"sm\"\n status={progressCircleStatus}\n />\n </div>\n ) : (\n <div\n className=\"flex items-center\"\n data-testid=\"list-file-card-status-icon\"\n >\n <statusIcon.icon\n color={statusIcon.color}\n size=\"md\"\n style={statusIcon.style}\n />\n </div>\n )\n ) : null}\n </div>\n </div>\n );\n};\n\nListFileCard.displayName = 'ListFileCard';\n","import { GridFileCard } from '../GridFileCard/GridFileCard';\nimport { ListFileCard } from '../ListFileCard/ListFileCard';\nimport { BaseFileCardProps, BaseFileCardStyle } from '../types';\n\nexport type FileCardProps = BaseFileCardProps & {\n badge?: string;\n cardStyle?: BaseFileCardStyle;\n 'data-testid'?: string;\n showActionsOnHover?: boolean;\n statusText?: string;\n};\n\nexport const FileCard = ({\n badge,\n cardStyle = 'contained',\n 'data-testid': dataTestId,\n errorMessage,\n progress,\n showActionsOnHover = false,\n status,\n statusIcon,\n statusText,\n ...props\n}: FileCardProps) =>\n cardStyle === 'card' ? (\n <GridFileCard\n {...props}\n badge={badge}\n data-testid={dataTestId}\n errorMessage={errorMessage}\n progress={progress}\n status={status}\n statusIcon={statusIcon}\n statusText={statusText}\n />\n ) : (\n <ListFileCard\n {...props}\n cardStyle={cardStyle}\n data-testid={dataTestId}\n errorMessage={errorMessage}\n progress={progress}\n showActionsOnHover={showActionsOnHover}\n status={status}\n statusIcon={statusIcon}\n statusText={statusText}\n />\n );\n\nFileCard.displayName = 'FileCard';\n","import { cn } from '@evolve.ui/theme-system';\nimport { useVirtualizer, VirtualItem } from '@tanstack/react-virtual';\nimport { useRef } from 'react';\n\nimport { FileCard, FileCardProps } from '../../../../components/FileCard/FileCard';\nimport { PreviewStyle } from '../../../../components/types';\nimport { FileResource } from '../../../../types';\n\n/**\n * Props for the virtualized list component\n */\ntype VirtualizedListProps = {\n // Common props passed from parent\n bulkSelectionEnabled?: boolean;\n createFileCardProps: (fileResource: FileResource, index: number) => FileCardProps;\n draggable?: boolean;\n files: FileResource[];\n hideDeleteAction?: boolean;\n hideFileNames?: boolean;\n hideFileSizes?: boolean;\n previewStyle: PreviewStyle;\n selectedFiles: string[];\n showActionsOnHover?: boolean;\n};\n\n/**\n * A virtualized list component for efficiently rendering large lists of file previews\n * Only renders items that are currently visible in the viewport\n */\nexport const FilePreviewVirtualizedList = ({ createFileCardProps, files, previewStyle }: VirtualizedListProps) => {\n const scrollRef = useRef<HTMLDivElement>(null);\n\n const listItemHeight = previewStyle === 'list' ? 66 : 65;\n const listItemGap = previewStyle === 'list' ? 8 : 0;\n\n const virtualizer = useVirtualizer({\n count: files.length,\n estimateSize: () => listItemHeight,\n gap: listItemGap,\n getScrollElement: () => scrollRef.current,\n overscan: 5,\n });\n\n const virtualItems = virtualizer.getVirtualItems();\n return (\n <div\n className=\"relative h-full overflow-y-auto\"\n ref={scrollRef}\n >\n <ul\n className={cn('flex flex-col', previewStyle === 'list' && 'gap-xs')}\n data-testid=\"file-preview-virtualized-list-element\"\n style={{\n height: `${virtualizer.getTotalSize()}px`,\n position: 'relative',\n width: '100%',\n }}\n >\n {virtualItems.map((virtualItem: VirtualItem) => {\n const file = files[virtualItem.index];\n\n return (\n <li\n data-index={virtualItem.index}\n data-testid={`file-preview-virtualized-list-item-${virtualItem.index}`}\n key={virtualItem.key}\n style={{\n height: `${virtualItem.size}px`,\n left: 0,\n position: 'absolute',\n top: 0,\n transform: `translateY(${virtualItem.start}px)`,\n width: '100%',\n }}\n >\n <FileCard\n data-testid={`file-preview-virtualized-list-card-${virtualItem.index}`}\n {...createFileCardProps(file, virtualItem.index)}\n />\n </li>\n );\n })}\n </ul>\n </div>\n );\n};\n\nFilePreviewVirtualizedList.displayName = 'FilePreviewVirtualizedList';\n","import { cn } from '@evolve.ui/theme-system';\nimport { breakpoints } from '@evolve.ui/theme-system/themes/common';\nimport { useCallback, useContext, useMemo, useState } from 'react';\n\nimport { useWindowWidth } from '../../../providers';\nimport { FileUploadContext, FileUploadContextType } from '../../providers/FileUploadProvider';\nimport { FileResource } from '../../types/commonTypes';\nimport { FileCard, FileCardProps } from '../FileCard/FileCard';\n/* eslint-disable curly */\nimport { BaseFileCardStyle, FileStatusConfig, PreviewStyle } from '../types';\nimport { FilePreviewVirtualizedList } from './virtualizerComponents/FilePreviewVirtualizedList/FilePreviewVirtualizedList';\n\ntype ColsByBreakpoint = {\n xs: number;\n} & { [key in 'sm' | 'md' | 'lg' | 'xl']?: number };\n\nexport type FilePreviewListProps = {\n /** Whether files in the list can be selected (or checked) */\n bulkSelectionEnabled?: boolean;\n /** Additional CSS classes */\n className?: string;\n /** Number of columns to display at each breakpoint, allowing you to create a custom grid layout. (grid view only) */\n colsByBreakpoint?: ColsByBreakpoint;\n /** Test ID for the component */\n 'data-testid'?: string;\n /** Whether files can be dragged and sorted */\n draggable?: boolean;\n /** Array of Files or RemoteFile Objects (typically with URLs) to display in the preview list */\n files?: FileResource[];\n /** Callback to configure status display (status, progress, error, icon, text) for each file */\n getFileStatusConfig?: (file: FileResource, index: number) => FileStatusConfig | undefined;\n /** Whether to hide the delete action on the file cards */\n hideDeleteAction?: boolean;\n /** Whether to hide the file names on the file cards */\n hideFileNames?: boolean;\n /** Whether to hide the file sizes on the file cards */\n hideFileSizes?: boolean;\n /** Whether to hide status messages on the file cards (error messages, \"Pending\", \"Uploading\", and custom statusText) */\n hideFileStatuses?: boolean;\n /** Called when user clicks delete button on a file preview */\n onDelete?: (fileResource: FileResource) => void;\n /** Called when user selects or deselects a file */\n onSelect?: (fileResource: FileResource, isSelected: boolean) => void;\n /** Determines the view style for the file preview list */\n previewStyle?: PreviewStyle;\n /** Whether to show delete button or other actions on hover (list view only) */\n showActionsOnHover?: boolean;\n /** Whether to use a virtualized list (Only used if previewStyle is list or compactList) */\n virtualized?: boolean;\n};\n\nconst VIEW_TO_CARD_STYLE: Record<PreviewStyle, BaseFileCardStyle> = {\n compactList: 'compact',\n grid: 'card',\n list: 'contained',\n};\n\nexport const FilePreviewList = ({\n bulkSelectionEnabled = false,\n className,\n colsByBreakpoint = { lg: 5, md: 4, sm: 3, xl: 5, xs: 3 },\n 'data-testid': dataTestId = 'file-preview-list',\n draggable = false,\n files: filesProp,\n getFileStatusConfig,\n hideDeleteAction = false,\n hideFileNames = false,\n hideFileSizes = false,\n hideFileStatuses = false,\n onDelete,\n onSelect,\n previewStyle = 'list',\n showActionsOnHover = false,\n virtualized = false,\n}: FilePreviewListProps) => {\n const uploadContext = useContext<FileUploadContextType | undefined>(FileUploadContext);\n // Check if we're in a provider by checking if files exist in context\n\n // Props should take precedence over context values (consistent with FileDropzone)\n // If files are provided as props, use those. Otherwise, fallback to context if available.\n const files = filesProp ?? uploadContext?.files ?? [];\n\n const handleDeleteFile = useCallback(\n (fileToDelete: FileResource) => {\n if (uploadContext && !onDelete) {\n // No onDelete handler, use automatic deletion from context state\n const fileToDeleteId = getItemIdentifier(fileToDelete);\n uploadContext.setFiles((prevFiles) =>\n prevFiles.filter((file) => getItemIdentifier(file) !== fileToDeleteId)\n );\n }\n onDelete?.(fileToDelete);\n },\n [uploadContext, onDelete]\n );\n\n const width = useWindowWidth();\n const [selectedFiles, setSelectedFiles] = useState<string[]>([]);\n\n const { lgMinValue, mdMinValue, smMinValue, xlMinValue } = breakpoints;\n\n const gridColumns = useMemo(() => {\n let columns = colsByBreakpoint.xs;\n // Start with mobile (xs) as default\n // Override with larger breakpoints if they exist and width matches\n if (width >= smMinValue && colsByBreakpoint.sm) columns = colsByBreakpoint.sm;\n if (width >= mdMinValue && colsByBreakpoint.md) columns = colsByBreakpoint.md;\n if (width >= lgMinValue && colsByBreakpoint.lg) columns = colsByBreakpoint.lg;\n if (width >= xlMinValue && colsByBreakpoint.xl) columns = colsByBreakpoint.xl;\n return columns;\n }, [width, colsByBreakpoint, lgMinValue, mdMinValue, smMinValue, xlMinValue]);\n\n const handleSelect = useCallback(\n (file: FileResource, isSelected: boolean) => {\n setSelectedFiles((prev) => {\n const name = file.name; // Both File and RemoteFile have name property\n\n if (isSelected) {\n return [...prev, name];\n }\n return prev.filter((n) => n !== name);\n });\n onSelect?.(file, isSelected);\n },\n [onSelect]\n );\n\n const containerClasses = cn(\n // Grid layout\n previewStyle === 'grid' && ['grid', gridColumns && `grid-cols-${gridColumns}`],\n // List/Table layout - only include gap-xs if viewStyle is list\n previewStyle !== 'grid' && ['flex flex-col', previewStyle === 'list' && 'gap-xs']\n );\n\n const cardStyle = VIEW_TO_CARD_STYLE[previewStyle];\n\n // Determine if we should use the virtualized list based on previewStyle and virtualized prop\n const shouldUseVirtualizedList = virtualized && (previewStyle === 'list' || previewStyle === 'compactList');\n\n // Common props used by both rendering paths\n const commonProps = {\n bulkSelectionEnabled,\n draggable,\n hideDeleteAction,\n hideFileNames,\n hideFileSizes,\n hideFileStatuses,\n showActionsOnHover,\n };\n\n // Helper to get a unique identifier for a file or URL\n const getItemIdentifier = (item: FileResource): string => {\n if ('url' in item) {\n // RemoteFile: id should be unique if provided, otherwise use url as fallback\n return item.id ?? item.url;\n }\n // File: use traditional properties for uniqueness\n return `${item.name}-${item.size}-${item.lastModified}`;\n };\n\n // Create shared FileCard props with common conditional logic\n const createFileCardProps = useCallback(\n (fileResource: FileResource, index: number): FileCardProps => {\n const name = fileResource.name;\n\n const isSelected = selectedFiles.includes(name);\n\n // FileCards hide the delete button when onDelete is not provided,\n // so we pass undefined when hideDeleteAction is true,\n // otherwise we pass the handleDeleteFile function\n const deleteHandler = hideDeleteAction ? undefined : handleDeleteFile;\n\n // Get status configuration from callback if provided\n const statusConfig = getFileStatusConfig?.(fileResource, index);\n\n return {\n cardStyle,\n draggable,\n errorMessage: statusConfig?.errorMessage,\n hideFileName: hideFileNames,\n hideFileSize: hideFileSizes,\n hideFileStatus: hideFileStatuses,\n imageSource: fileResource,\n onDelete: deleteHandler,\n onSelect: bulkSelectionEnabled ? handleSelect : undefined,\n ...(bulkSelectionEnabled ? { isSelected, selectable: true } : { selectable: false }),\n progress: statusConfig?.progress,\n showActionsOnHover,\n status: statusConfig?.status,\n statusIcon: statusConfig?.statusIcon,\n statusText: statusConfig?.statusText,\n };\n },\n [\n bulkSelectionEnabled,\n cardStyle,\n draggable,\n getFileStatusConfig,\n handleDeleteFile,\n handleSelect,\n hideDeleteAction,\n hideFileNames,\n hideFileSizes,\n hideFileStatuses,\n selectedFiles,\n showActionsOnHover,\n ]\n );\n\n return (\n <section\n aria-label=\"File preview list\"\n className={cn(\n 'flex w-full flex-col',\n {\n 'h-full': previewStyle !== 'grid',\n },\n className\n )}\n >\n {shouldUseVirtualizedList ? (\n <FilePreviewVirtualizedList\n {...commonProps}\n createFileCardProps={createFileCardProps}\n files={files}\n previewStyle={previewStyle}\n selectedFiles={selectedFiles}\n />\n ) : (\n <ul\n className={containerClasses}\n data-testid={dataTestId}\n >\n {files.map((fileResource, index) => (\n <li\n data-testid={`${dataTestId}-item-${index}`}\n key={`${getItemIdentifier(fileResource)}-${index}`}\n >\n <FileCard\n data-testid={`${dataTestId}-card-${index}`}\n {...createFileCardProps(fileResource, index)}\n />\n </li>\n ))}\n </ul>\n )}\n </section>\n );\n};\n\nFilePreviewList.displayName = 'FilePreviewList';\n","import { FileUploadProvider, FileUploadProviderConfigProps } from '../../providers/FileUploadProvider';\nimport { FileUploadProps } from '../../types/sharedTypes';\n/* eslint-disable curly */\nimport { FileDropzone } from '../FileDropzone/FileDropzone';\nimport { FilePreviewList } from '../FilePreviewList/FilePreviewList';\n\n/**\n * FileUpload component for handling single or multiple file uploads\n * with built-in validation and preview capabilities.\n *\n * This is the main container component that combines the drag-and-drop area (FileDropzone)\n * and the file preview list (FilePreviewList) into a single, cohesive interface.\n * It handles the file validation, upload state management, and preview display through\n * the FileUploadProvider context.\n *\n */\nexport const FileUpload = ({\n disabled,\n error,\n hideFilePreview = false,\n initialFiles,\n maxFiles,\n maxSize,\n onDrop,\n onDropAccepted,\n onDropRejected,\n onFileDelete,\n previewConfig,\n previewStyle = 'list',\n ...dropzoneProps\n}: FileUploadProps) => {\n const providerProps: FileUploadProviderConfigProps = {\n accept: dropzoneProps.accept,\n disabled,\n error,\n initialFiles,\n maxFiles,\n maxSize,\n onDrop,\n onDropAccepted,\n onDropRejected,\n onFileDelete,\n strictValidation: dropzoneProps.strictValidation,\n validator: dropzoneProps.validator,\n };\n\n return (\n <FileUploadProvider {...providerProps}>\n <div className=\"flex flex-col gap-md\">\n <FileDropzone {...dropzoneProps} />\n {!hideFilePreview && (\n <FilePreviewList\n {...previewConfig}\n onDelete={onFileDelete}\n previewStyle={previewStyle}\n />\n )}\n </div>\n </FileUploadProvider>\n );\n};\n\nFileUpload.displayName = 'FileUpload';\n","import { cn } from '@evolve.ui/theme-system';\nimport { useMemo } from 'react';\n\nimport { UploadValidationContextType } from '../../../providers/UploadValidationProvider';\n\ntype OverlayDropzoneDragTextProps = {\n dragText: string;\n isDragActive: boolean;\n validation: UploadValidationContextType;\n};\n\nexport const OverlayDropzoneDragText = ({ dragText, isDragActive, validation }: OverlayDropzoneDragTextProps) => {\n // Determine overlay text based on drag state and validation\n const overlayText = useMemo(() => {\n if (!isDragActive) {\n return null;\n }\n\n // Show validation error if present\n if (validation.dragValidationError?.message) {\n return validation.dragValidationError.message;\n }\n\n // Show success message for valid drag\n return dragText;\n }, [isDragActive, validation.dragValidationError, dragText]);\n\n if (!overlayText) {\n return null;\n }\n\n return (\n <div\n className={cn(\n 'text-xl font-medium',\n validation.dragValidationError ? 'text-text-critical' : 'text-blue-600'\n )}\n >\n {overlayText}\n </div>\n );\n};\n","import { useMemo } from 'react';\n\nimport { FileArchive, FileCsv, FilePdf, Files, FileText, ImageSquare, ImagesSquare } from '../../../../Icons';\nimport { UploadValidationContextType } from '../../../providers/UploadValidationProvider';\nimport { CommonFileTypes } from '../../../types/commonTypes';\nimport { OverlayDropzoneDragText } from './OverlayDropzoneDragText';\n\ntype OverlayContentProps = {\n accept?: CommonFileTypes | string[];\n customIcon?: React.ReactNode;\n dragText: string;\n isDragActive: boolean;\n maxFiles?: number;\n validation: UploadValidationContextType;\n};\n\nexport const OverlayDropzoneContent = ({\n accept,\n customIcon,\n dragText,\n isDragActive,\n maxFiles,\n validation,\n}: OverlayContentProps) => {\n // Determine icon color based on validation state\n const iconColor = validation.dragValidationError ? 'critical' : 'secondary';\n\n // Determine which icon to show based on accept and maxFiles\n const icon = useMemo(() => {\n // 1. Custom icon takes precedence\n if (customIcon) {\n return customIcon;\n }\n\n const isSingleFile = maxFiles === 1;\n\n // 2. Images\n if (accept === 'images' || (Array.isArray(accept) && accept.some((type) => type.startsWith('image/')))) {\n if (isSingleFile) {\n return (\n <ImageSquare\n color={iconColor}\n size=\"lg\"\n style=\"duotone\"\n />\n );\n }\n return (\n <ImagesSquare\n color={iconColor}\n size=\"lg\"\n style=\"duotone\"\n />\n );\n }\n\n // 3. Documents\n if (accept === 'documents') {\n if (isSingleFile) {\n return (\n <FileText\n color={iconColor}\n size=\"lg\"\n style=\"duotone\"\n />\n );\n }\n return (\n <Files\n color={iconColor}\n size=\"lg\"\n style=\"duotone\"\n />\n );\n }\n\n // 4. PDFs\n if (accept === 'pdfs' || (Array.isArray(accept) && accept.some((type) => type === 'application/pdf'))) {\n return (\n <FilePdf\n color={iconColor}\n size=\"lg\"\n style=\"duotone\"\n />\n );\n }\n\n // 5. CSV files\n if (\n Array.isArray(accept) &&\n accept.some((type) => type === 'text/csv' || type === '.csv' || type.includes('csv'))\n ) {\n return (\n <FileCsv\n color={iconColor}\n size=\"lg\"\n style=\"duotone\"\n />\n );\n }\n\n // 6. Archive files (zip, rar, 7z, tar, gz, etc.)\n if (\n Array.isArray(accept) &&\n accept.some(\n (type) =>\n type.includes('zip') ||\n type.includes('rar') ||\n type.includes('7z') ||\n type.includes('tar') ||\n type.includes('gzip') ||\n type === 'application/x-zip-compressed' ||\n type === 'application/x-rar-compressed' ||\n type === 'application/x-7z-compressed'\n )\n ) {\n return (\n <FileArchive\n color={iconColor}\n size=\"lg\"\n style=\"duotone\"\n />\n );\n }\n\n // 7. Default: general files icon\n return (\n <Files\n color={iconColor}\n size=\"lg\"\n style=\"duotone\"\n />\n );\n }, [customIcon, accept, maxFiles, iconColor]);\n\n return (\n <div className=\"text-center\">\n <div className=\"mb-xs flex justify-center\">{icon}</div>\n <OverlayDropzoneDragText\n dragText={dragText}\n isDragActive={isDragActive}\n validation={validation}\n />\n </div>\n );\n};\n","import { cn } from '@evolve.ui/theme-system';\n\nimport { FileError } from '../../types';\nimport { OverlayStyleOptions } from '../../types/sharedTypes';\n\ntype DropzoneState = {\n disableClickThrough: boolean;\n disableDragValidation: boolean;\n disabled: boolean;\n isDragActive: boolean;\n styleOptions?: OverlayStyleOptions;\n validationError?: FileError | null;\n};\n\nexport const getUploadOverlayStyles = ({\n disableClickThrough,\n disabled,\n disableDragValidation,\n isDragActive,\n styleOptions = {},\n validationError,\n}: DropzoneState) => {\n const { blurOnDrag = false, showDashedBorder = true } = styleOptions;\n\n const isInvalid = Boolean(validationError);\n const isErrorState = disableDragValidation ? false : isInvalid;\n const isDraggedOver = isDragActive && (disableDragValidation || !isInvalid);\n\n return cn(\n // Layout & Container\n [\n 'absolute inset-0',\n 'flex flex-col',\n 'h-full w-full',\n 'items-center justify-center',\n 'rounded-[var(--container-border-radius)]',\n showDashedBorder && 'outline-dashed outline-1 -outline-offset-1',\n 'transition-colors',\n disableClickThrough &&\n 'cursor-pointer group-hover/dropzone:bg-background-hover group-hover/dropzone:outline-border-hover',\n ],\n\n // Pointer Events Strategy:\n // - Only apply pointer-events-none when click-through is not disabled\n // - When disableClickThrough is true, the overlay captures all events\n // - The parent container (with getRootProps) captures drag events\n !disableClickThrough && 'pointer-events-none',\n\n // Z-Index: Always on top to be visible when drag is active\n 'z-10',\n\n // Focus & Interactive Base\n ['hui-focus-visible-outline'],\n\n // Interactive States\n {\n // Drag Active - thick blue outline when dragging\n 'outline outline-4 outline-offset-0 outline-focus-primary': isDragActive,\n },\n\n // Visual States\n {\n // Apply blur when enabled and dragging (success state)\n 'backdrop-blur-[2px]': blurOnDrag && isDraggedOver && !isErrorState && !disabled,\n\n // Apply blur when enabled and dragging (error state)\n 'backdrop-blur-sm': blurOnDrag && isDragActive && isErrorState,\n\n // Error (only when not disabled and dragging)\n 'bg-background-critical-light/50 outline-border-critical': isErrorState && !disabled && isDragActive,\n\n // Drag Over - show background when dragging\n 'bg-background-hover bg-background-secondary/90': isDraggedOver && !isErrorState && !disabled,\n\n // Default - transparent when not dragging\n 'bg-transparent outline-border-secondary': !isDragActive,\n }\n );\n};\n","import { cn } from '@evolve.ui/theme-system';\nimport { useContext } from 'react';\nimport { useDropzone } from 'react-dropzone';\n\nimport { useFileValidation } from '../../hooks';\nimport { useHandleDragEnter } from '../../hooks/upload/useHandleDragEnter/useHandleDragEnter';\nimport { useHandleDrop } from '../../hooks/upload/useHandleDrop/useHandleDrop';\nimport { useUploadAvailability } from '../../hooks/upload/useUploadAvailability/useUploadAvailability';\nimport { createDropzoneValidator } from '../../hooks/validation/createDropzoneValidator';\nimport { FileUploadContext, FileUploadContextType } from '../../providers/FileUploadProvider';\nimport { FileDropzoneOverlayProps } from '../../types/sharedTypes';\nimport { getMimeTypes } from '../../utils/getMimeTypes';\nimport { FileDropzoneDebugger } from '../FileDropzone/components/FileDropzoneDebugger/FileDropzoneDebugger';\nimport { OverlayDropzoneContent } from './components/OverlayDropzoneContent';\nimport { getUploadOverlayStyles } from './styles';\n\nexport const FileDropzoneOverlay = ({\n accept: acceptProp,\n ariaLabel,\n children,\n className,\n 'data-testid': dataTestId = 'file-dropzone-overlay',\n disableClickThrough = false,\n disabled: disabledProp = false,\n disableDragValidation = false,\n dragText = 'Drop files to upload',\n error,\n files: filesProp,\n icon,\n maxFiles: maxFilesProp,\n maxSize: maxSizeProp,\n onDrop: onDropProp,\n onDropAccepted: onDropAcceptedProp,\n onDropRejected: onDropRejectedProp,\n onFilesChange: onFilesChangeProp,\n showDebugger,\n strictValidation,\n styleOptions,\n validator,\n}: FileDropzoneOverlayProps) => {\n const uploadContext = useContext<FileUploadContextType | undefined>(FileUploadContext);\n\n const validationConfig = {\n accept: acceptProp,\n error,\n maxFiles: maxFilesProp,\n maxSize: maxSizeProp,\n strictValidation,\n validator,\n };\n\n /* IMPORTANT: This component supports both standalone usage and provider usage */\n // useFileValidation automatically detects if we're in a provider context\n // If not in provider, create local validation for standalone usage\n const validation = useFileValidation(validationConfig);\n\n // Determine whether to use context or local state for files and setFiles\n const files = filesProp ?? uploadContext?.files ?? [];\n const setFiles = onFilesChangeProp ?? uploadContext?.setFiles ?? (() => {});\n\n // Intentionally check both props and context with precedence order\n const disabled = disabledProp || uploadContext?.disabled;\n const onDrop = onDropProp ?? uploadContext?.onDrop;\n const onDropAccepted = onDropAcceptedProp ?? uploadContext?.onDropAccepted;\n const onDropRejected = onDropRejectedProp ?? uploadContext?.onDropRejected;\n const maxFiles = maxFilesProp ?? validation.maxFiles;\n const maxSize = maxSizeProp ?? validation.maxSize;\n const accept = acceptProp ?? validation.accept;\n /* END IMPORTANT */\n\n // Check if upload is disabled based on current state\n const { isDisabled } = useUploadAvailability({\n disabled,\n files,\n maxFiles,\n });\n\n // Configure text based on multiple vs single file mode\n const allowMultipleFiles = maxFiles === undefined || maxFiles > 1;\n const filePluralizationText = allowMultipleFiles ? 'files' : 'a file';\n const mimeTypes = getMimeTypes(accept);\n\n // Set up drag and drop handlers\n const handleDrop = useHandleDrop({\n files,\n onDrop,\n onDropAccepted,\n onDropRejected,\n setFiles,\n validation,\n });\n\n const handleDragEnter = useHandleDragEnter({\n files,\n mimeTypes,\n validation,\n validator,\n });\n\n // Configure the dropzone\n const { getInputProps, getRootProps, isDragActive } = useDropzone({\n accept: mimeTypes,\n disabled: isDisabled,\n maxSize,\n multiple: allowMultipleFiles,\n noClick: !disableClickThrough, // When clickThrough is not disabled, prevent file picker dialog\n noKeyboard: !disableClickThrough, // When clickThrough is not disabled, prevent keyboard interactions\n onDragEnter: disableDragValidation ? validation.clearAllValidation : handleDragEnter,\n onDragLeave: validation.clearAllValidation,\n onDrop: handleDrop,\n // @ts-expect-error Our validator returns potentially function-based messages, React-Dropzone expects strings.\n // This is intentional and allows us to resolve dynamic messages later with proper file counts.\n validator: createDropzoneValidator(validation),\n });\n\n // Determine Dropzone styles based on interaction state\n const activeCode = isDragActive ? validation.dragValidationError : validation.dropValidationErrors[0];\n const uploadZoneStyles = getUploadOverlayStyles({\n disableClickThrough,\n disabled: isDisabled,\n disableDragValidation,\n isDragActive,\n styleOptions,\n validationError: activeCode,\n });\n\n // Map innerPadding to Tailwind padding classes\n const paddingMap = {\n '2xl': 'p-2xl',\n lg: 'p-lg',\n md: 'p-md',\n sm: 'p-sm',\n xl: 'p-xl',\n xs: 'p-xs',\n } as const;\n const innerPaddingClass = styleOptions?.innerPadding ? paddingMap[styleOptions.innerPadding] : undefined;\n const fillParentClass = styleOptions?.fillParent ? 'h-full' : 'relative';\n\n return (\n <>\n <div\n {...getRootProps({\n 'aria-disabled': isDisabled,\n 'aria-label': ariaLabel ?? (isDragActive ? dragText : undefined),\n className: cn('group/dropzone', fillParentClass, className),\n 'data-testid': `${dataTestId}-root`,\n })}\n >\n <input\n {...getInputProps({\n 'aria-label': `Upload ${filePluralizationText}`,\n 'data-testid': `${dataTestId}-input`,\n })}\n />\n\n {/* Child content - isolation-isolate scopes children's z-indices so the overlay can sit above them */}\n <div className={cn('isolate', fillParentClass, innerPaddingClass)}>{children}</div>\n\n {/* Visual overlay - only appears when dragging */}\n <div\n className={cn('w-full', uploadZoneStyles)}\n data-testid={`${dataTestId}-container`}\n >\n {/* Only show visual feedback when actively dragging */}\n {isDragActive && (\n <OverlayDropzoneContent\n accept={accept}\n customIcon={icon}\n dragText={dragText}\n isDragActive={isDragActive}\n maxFiles={maxFiles}\n validation={validation}\n />\n )}\n </div>\n </div>\n {/* Display debug information around fileRejections when showDebugger is true */}\n {showDebugger && <FileDropzoneDebugger fileRejections={validation.fileRejections} />}\n </>\n );\n};\n\nFileDropzoneOverlay.displayName = 'FileDropzoneOverlay';\n","import { cn } from '@evolve.ui/theme-system';\nimport { useContext } from 'react';\n\nimport { UploadSimple } from '../../../Icons';\n/* eslint-disable curly */\nimport { BodyPrimary } from '../../../Typography/Text/Text';\nimport {\n FileUploadContext,\n FileUploadProvider,\n FileUploadProviderConfigProps,\n} from '../../providers/FileUploadProvider';\nimport { FileUploadCanvasProps } from '../../types/sharedTypes';\nimport { FileDropzoneOverlay } from '../FileDropzoneOverlay/FileDropzoneOverlay';\nimport { FilePreviewList } from '../FilePreviewList/FilePreviewList';\n\n/**\n * Empty state component displayed when no files are present\n */\nconst EmptyState = () => {\n return (\n <div className={cn('flex h-full flex-col items-center justify-center gap-xs', 'bg-gray-50 px-md py-2xl')}>\n <UploadSimple color=\"secondary\" />\n <BodyPrimary\n className=\"text-center\"\n color=\"secondary\"\n >\n Drag files here to upload\n </BodyPrimary>\n </div>\n );\n};\n\n/**\n * Canvas content that shows either FilePreviewList or empty state\n */\nconst CanvasContent = ({\n onFileDelete,\n previewConfig,\n previewStyle,\n}: {\n onFileDelete?: FileUploadCanvasProps['onFileDelete'];\n previewConfig?: FileUploadCanvasProps['previewConfig'];\n previewStyle: FileUploadCanvasProps['previewStyle'];\n}) => {\n const uploadContext = useContext(FileUploadContext);\n const files = uploadContext?.files ?? [];\n\n // Show empty state when no files\n if (files.length === 0) {\n return <EmptyState />;\n }\n\n // Show file preview list when files exist\n return (\n <FilePreviewList\n {...previewConfig}\n onDelete={onFileDelete}\n previewStyle={previewStyle}\n />\n );\n};\n\n/**\n * FileUploadCanvas component - An out-of-the-box solution for drag-and-drop file uploads\n * with overlay-based interaction.\n *\n * This component wraps FilePreviewList with FileDropzoneOverlay, allowing users to drag\n * files over existing content. The overlay appears during drag operations and provides\n * visual feedback. It uses FileUploadProvider for state management.\n *\n * Key differences from FileUpload:\n * - Uses FileDropzoneOverlay (overlay-based) instead of FileDropzone (dedicated area)\n * - Supports disableClickThrough for interactive content underneath\n * - Always shows FilePreviewList (no hideFilePreview option)\n * - Ideal for gallery views and canvas-style interfaces\n */\nexport const FileUploadCanvas = ({\n className,\n disabled,\n error,\n initialFiles,\n maxFiles,\n maxSize,\n onDrop,\n onDropAccepted,\n onDropRejected,\n onFileDelete,\n previewConfig,\n previewStyle = 'list',\n ...dropzoneOverlayProps\n}: FileUploadCanvasProps) => {\n const providerProps: FileUploadProviderConfigProps = {\n accept: dropzoneOverlayProps.accept,\n disabled,\n error,\n initialFiles,\n maxFiles,\n maxSize,\n onDrop,\n onDropAccepted,\n onDropRejected,\n onFileDelete,\n strictValidation: dropzoneOverlayProps.strictValidation,\n validator: dropzoneOverlayProps.validator,\n };\n\n return (\n <FileUploadProvider {...providerProps}>\n <div className={cn('h-full w-full overflow-y-auto', className)}>\n <FileDropzoneOverlay\n {...dropzoneOverlayProps}\n styleOptions={{ ...dropzoneOverlayProps.styleOptions, fillParent: true }}\n >\n <CanvasContent\n onFileDelete={onFileDelete}\n previewConfig={previewConfig}\n previewStyle={previewStyle}\n />\n </FileDropzoneOverlay>\n </div>\n </FileUploadProvider>\n );\n};\n\nFileUploadCanvas.displayName = 'FileUploadCanvas';\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"ImageSlider-BidXfnLj.cjs","names":["ArrowLeft","CaretLeft","ArrowRight","CaretRight","IconButton","spacing","placeholderImage","useHighQuality","useWindowIsMobile","useWindowIsMobile"],"sources":["../src/ImageSlider/components/IndexIndicator/IndexIndicator.tsx","../src/ImageSlider/components/NavigationButtons/NavigationButtons.tsx","../src/ImageSlider/assets/placeholder.svg","../src/ImageSlider/constants.ts","../src/ImageSlider/utils/imageOptimization.ts","../src/ImageSlider/components/ResponsiveImage/ResponsiveImage.tsx","../src/ImageSlider/components/Thumbnails/Thumbnails.tsx","../src/ImageSlider/hooks/useImageSlider.ts","../src/ImageSlider/ImageSlider.types.ts","../src/ImageSlider/hooks/useImageSliderNavigation.ts","../src/ImageSlider/hooks/useImageSliderScrollHandler.ts","../src/ImageSlider/ImageSlider.tsx"],"sourcesContent":["type Props = {\n /** Currently active page number (1-based) */\n currentPage: number;\n /** Total number of pages/images */\n numberOfPages: number;\n};\n\n/**\n * Displays a numeric index indicator (e.g., \"1 of 11\") for image gallery position.\n * Used when thumbnailDisplay is 'index' instead of image thumbnails.\n */\nexport const IndexIndicator = ({ currentPage, numberOfPages }: Props) => (\n <div\n aria-label={`Image ${currentPage} of ${numberOfPages}`}\n aria-live=\"polite\"\n className=\"hui-text-caption flex justify-center text-text-secondary\"\n role=\"status\"\n >\n {currentPage} of {numberOfPages}\n </div>\n);\n","import { cn } from '@evolve.ui/theme-system';\n\nimport { IconButton } from '../../../IconButton/IconButton';\nimport { ArrowLeft, ArrowRight, CaretLeft, CaretRight } from '../../../Icons';\n\ntype Props = {\n goToNextPage: () => void;\n goToPreviousPage: () => void;\n /** Shape of the navigation icons */\n iconShape?: 'circle' | 'square';\n /** Size of the navigation icons - sm=34px, md=42px, lg=54px */\n iconSize?: 'sm' | 'md' | 'lg';\n /** Type of icons to use for navigation */\n iconType?: 'caret' | 'arrow';\n /** Variant of the navigation icons */\n iconVariant?: 'outlined' | 'transparent';\n /** Whether the next button should be disabled */\n isNextPageDisabled?: boolean;\n /** Whether the previous button should be disabled */\n isPreviousPageDisabled?: boolean;\n /** For grid layout - which position this button should render (left or right) */\n position?: 'left' | 'right';\n showNextPageButton: boolean;\n showPreviousPageButton: boolean;\n};\n\nexport const NavigationButtons = ({\n goToNextPage,\n goToPreviousPage,\n iconShape = 'circle',\n iconSize = 'sm',\n iconType = 'caret',\n iconVariant = 'outlined',\n isNextPageDisabled = false,\n isPreviousPageDisabled = false,\n position,\n showNextPageButton,\n showPreviousPageButton,\n}: Props) => {\n // Choose the correct icons based on iconType prop\n const LeftIcon = iconType === 'arrow' ? ArrowLeft : CaretLeft;\n const RightIcon = iconType === 'arrow' ? ArrowRight : CaretRight;\n\n // For grid layout with outside positioning, render individual buttons\n if (position) {\n if (position === 'left') {\n return showPreviousPageButton ? (\n <IconButton\n aria-label=\"Previous Page\"\n className=\"xsMax:hidden\"\n disabled={isPreviousPageDisabled}\n hideTooltip\n icon={LeftIcon}\n onClick={goToPreviousPage}\n shape={iconShape}\n size={iconSize}\n variant={iconVariant}\n />\n ) : null;\n }\n\n // position === 'right'\n return showNextPageButton ? (\n <IconButton\n aria-label=\"Next Page\"\n className=\"xsMax:hidden\"\n disabled={isNextPageDisabled}\n hideTooltip\n icon={RightIcon}\n onClick={goToNextPage}\n shape={iconShape}\n size={iconSize}\n variant={iconVariant}\n />\n ) : null;\n }\n\n // Original layout for inside positioning or non-grid layouts\n // For inside positioning: calculate from the top to put the button halfway down its parent relative to its own center.\n // this will break if the size of the IconButton is ever changed,\n const positionStyles = cn('absolute top-[calc(50%-21px)] w-full');\n\n return (\n <div className=\"z-10\">\n {showPreviousPageButton && (\n <IconButton\n aria-label=\"Previous Page\"\n className={cn(positionStyles, 'left-sm', 'xsMax:hidden')}\n disabled={isPreviousPageDisabled}\n hideTooltip\n icon={LeftIcon}\n onClick={goToPreviousPage}\n shape={iconShape}\n size={iconSize}\n variant={iconVariant}\n />\n )}\n {showNextPageButton && (\n <IconButton\n aria-label=\"Next Page\"\n className={cn(positionStyles, 'right-sm', 'xsMax:hidden')}\n disabled={isNextPageDisabled}\n hideTooltip\n icon={RightIcon}\n onClick={goToNextPage}\n shape={iconShape}\n size={iconSize}\n variant={iconVariant}\n />\n )}\n </div>\n );\n};\n","\"data:image/svg+xml,<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" viewBox=\\\"0 0 400 400\\\" role=\\\"img\\\" aria-label=\\\"Image unavailable\\\">%0A <rect width=\\\"400\\\" height=\\\"400\\\" fill=\\\"%23ececec\\\"/>%0A <rect x=\\\"10\\\" y=\\\"10\\\" width=\\\"380\\\" height=\\\"380\\\" fill=\\\"none\\\" stroke=\\\"%23c4c4c4\\\" stroke-width=\\\"4\\\"/>%0A <circle cx=\\\"148\\\" cy=\\\"148\\\" r=\\\"32\\\" fill=\\\"%23c4c4c4\\\"/>%0A <path d=\\\"M56 322 L162 204 L232 280 L282 228 L344 322 Z\\\" fill=\\\"%23c4c4c4\\\"/>%0A</svg>%0A\"","import { spacing } from '@evolve.ui/theme-system/themes/common';\n\nimport placeholderImage from './assets/placeholder.svg';\nimport { ImageSliderCard } from './ImageSlider.types';\n\n/**\n * Constants used throughout the ImageSlider component\n */\n\n// Breakpoints\nexport const MOBILE_BREAKPOINT = 768;\nexport const MOBILE_BREAKPOINT_QUERY = `(max-width: ${MOBILE_BREAKPOINT}px)`;\n\n// Spacing values (use design tokens)\nexport const SPACING = {\n GAP_2XS: spacing.xxsValue, // gap-2xs (4px)\n GAP_MD: spacing.mdValue, // gap-md (24px)\n MARGIN_SM: spacing.smValue, // ml-sm, mr-sm (16px)\n} as const;\n\n// Thumbnail dimensions\nexport const THUMBNAIL = {\n QUALITY: 50, // Thumbnail quality setting\n SIZE: 111, // Fixed thumbnail size\n WIDTH_PARAM: 107, // URL width parameter for thumbnails\n} as const;\n\n// Mobile card dimensions\nexport const MOBILE_CARD = {\n MAX_WIDTH: 651, // Max card width\n WIDTH_REDUCTION: 64, // calc(100% - 64px) to match container extension for optimal bleed effect\n} as const;\n\n// Animation timings\nexport const ANIMATION = {\n DEBOUNCE_DELAY: 100, // Scroll handler debounce delay\n SCROLL_TIMEOUT: 300, // Smooth scroll animation duration\n} as const;\n\n// Navigation button positioning\nexport const NAVIGATION = {\n INSIDE_TOP_OFFSET: 21, // top-[calc(50%-21px)]\n OUTSIDE_TOP_OFFSET: 17, // top-[calc(50%-17px)]\n} as const;\n\n// Bundled brand-neutral fallback (inlined as a data URI at build time) — the image-error\n// fallback must never depend on an external CDN.\nexport const PLACEHOLDER_IMAGE_URL = placeholderImage;\n\nexport const PLACEHOLDER_EMPTY_CARDS: ImageSliderCard[] = [\n {\n imageData: {\n alt: 'Placeholder empty card',\n baseUrl: PLACEHOLDER_IMAGE_URL,\n title: 'Placeholder empty card',\n },\n key: 'placeholder-empty-card-1',\n },\n];\n","import { THUMBNAIL } from '../constants';\nimport { ResponsiveImageConfig } from '../ImageSlider.types';\n\n/**\n * Generates a srcSet string for main images with responsive breakpoints\n * @param baseUrl - The base URL of the image\n * @param config - Responsive image configuration\n * @param useHighQuality - Whether to use high quality mode (no width constraints)\n * @returns The srcSet string for the image\n */\nexport const generateMainImageSrcSet = (\n baseUrl: string,\n config: ResponsiveImageConfig,\n useHighQuality: boolean = false\n): string => {\n // If high quality mode is enabled (after hover), return empty string\n // This forces the browser to use only the src attribute (full quality)\n // avoiding intermediate 651px requests\n if (useHighQuality) {\n return '';\n }\n\n const { desktopSize, mobileSize } = config;\n const widths = [mobileSize, desktopSize];\n\n return widths\n .map((width) => {\n return `${baseUrl}&width=${width} ${width}w`;\n })\n .join(', ');\n};\n\n/**\n * Generates a srcSet string for thumbnail images\n * @param baseUrl - The base URL of the image\n * @returns The srcSet string for the thumbnail\n */\nexport const generateThumbnailSrcSet = (baseUrl: string): string => {\n return `${baseUrl}&width=${THUMBNAIL.WIDTH_PARAM} ${THUMBNAIL.WIDTH_PARAM}w`;\n};\n\n/**\n * Generates the sizes attribute for responsive images\n * @param config - Responsive image configuration\n * @param useHighQuality - Whether to use high quality mode\n * @returns The sizes attribute string\n */\nexport const generateSizesAttribute = (config: ResponsiveImageConfig, useHighQuality: boolean = false): string => {\n // If high quality mode is enabled (after hover), sizes attribute is not needed\n // since we're using empty srcSet and relying only on src attribute\n if (useHighQuality) {\n return '';\n }\n\n const { breakpoint, desktopSize, mobileSize } = config;\n // Use a much smaller size on mobile to force selection of 366w image even on high-DPR devices\n const adjustedMobileSize = Math.floor(mobileSize / 3); // ~122px, ensuring 366w is selected even at DPR 3.0\n return `(max-width: ${breakpoint}px) ${adjustedMobileSize}px, ${desktopSize}px`;\n};\n\n// Memoized thumbnail sizes attribute (static value)\nconst THUMBNAIL_SIZES_ATTRIBUTE = `${THUMBNAIL.WIDTH_PARAM}px`;\n\n/**\n * Generates the sizes attribute for thumbnail images\n * @returns The sizes attribute string for thumbnails\n */\nexport const generateThumbnailSizesAttribute = (): string => {\n return THUMBNAIL_SIZES_ATTRIBUTE;\n};\n\n/**\n * Gets the appropriate image source URL based on quality mode\n * @param baseUrl - The base URL of the image\n * @param config - Responsive image configuration\n * @param useHighQuality - Whether to use high quality mode\n * @returns The appropriate source URL\n */\nexport const getImageSrc = (\n baseUrl: string,\n config: ResponsiveImageConfig,\n useHighQuality: boolean = false\n): string => {\n if (useHighQuality) {\n return baseUrl;\n }\n return `${baseUrl}&width=${config.mobileSize}`;\n};\n\n/**\n * Gets the thumbnail image source URL\n * @param baseUrl - The base URL of the image\n * @returns The thumbnail source URL\n */\nexport const getThumbnailSrc = (baseUrl: string): string => {\n return `${baseUrl}&width=${THUMBNAIL.WIDTH_PARAM}`;\n};\n","import { PLACEHOLDER_IMAGE_URL } from '../../constants';\nimport { ResponsiveImageConfig, ResponsiveImageData } from '../../ImageSlider.types';\nimport {\n generateMainImageSrcSet,\n generateSizesAttribute,\n generateThumbnailSizesAttribute,\n generateThumbnailSrcSet,\n getImageSrc,\n getThumbnailSrc,\n} from '../../utils/imageOptimization';\n\n/**\n * Props for the ResponsiveImage component\n */\ntype Props = {\n /** Additional CSS classes */\n className?: string;\n /** Whether the gallery has been hovered (for quality optimization) */\n hasHoveredGallery?: boolean;\n /** Image data containing alt, baseUrl, and title */\n imageData: ResponsiveImageData;\n /** Whether this image is currently active/visible */\n isActiveImage?: boolean;\n /** Whether this is a main image (not a thumbnail) */\n isMainImage?: boolean;\n /** Responsive image configuration */\n responsiveImageConfig?: ResponsiveImageConfig;\n};\n\n/**\n * Renders a responsive image with optimized loading priorities and srcSet\n */\nexport const ResponsiveImage = ({\n className,\n hasHoveredGallery = false,\n imageData,\n isActiveImage = false,\n isMainImage = true,\n responsiveImageConfig,\n}: Props) => {\n const { alt, baseUrl, title } = imageData;\n\n if (!responsiveImageConfig) {\n // Fallback to simple image if no config provided\n return (\n <img\n alt={alt}\n className={className}\n onError={(e) => {\n const target = e.target as HTMLImageElement;\n if (target.src !== PLACEHOLDER_IMAGE_URL) {\n target.src = PLACEHOLDER_IMAGE_URL;\n }\n }}\n src={baseUrl}\n title={title}\n />\n );\n }\n\n if (isMainImage) {\n // Use high quality mode for all images once gallery has been hovered\n const useHighQuality = hasHoveredGallery;\n\n // Only use high quality URLs/srcSet after gallery has been hovered\n // Active images get high priority/eager loading but still use responsive srcSet initially\n const shouldLoadHighQuality = useHighQuality;\n\n return (\n <img\n alt={alt}\n className=\"h-full w-full bg-background-primary object-contain\"\n fetchPriority={isActiveImage || shouldLoadHighQuality ? 'high' : 'low'}\n // Force React to create a new img element when switching to high quality\n // This prevents the browser from loading both constrained and unconstrained versions\n key={shouldLoadHighQuality && !isActiveImage ? 'high-quality' : 'standard-quality'}\n loading={isActiveImage || shouldLoadHighQuality ? 'eager' : 'lazy'}\n onError={(e) => {\n const target = e.target as HTMLImageElement;\n if (target.src !== PLACEHOLDER_IMAGE_URL) {\n target.src = PLACEHOLDER_IMAGE_URL;\n // Clear srcSet to prevent fallback to other sizes that might also fail\n target.srcset = '';\n }\n }}\n sizes={generateSizesAttribute(responsiveImageConfig, shouldLoadHighQuality)}\n src={getImageSrc(baseUrl, responsiveImageConfig, shouldLoadHighQuality)}\n srcSet={generateMainImageSrcSet(baseUrl, responsiveImageConfig, shouldLoadHighQuality)}\n title={title}\n />\n );\n }\n\n // Thumbnail image - responsive sizes\n return (\n <img\n alt={alt}\n className=\"h-full max-h-[111px] w-full max-w-[111px] object-cover\"\n loading=\"lazy\"\n onError={(e) => {\n const target = e.target as HTMLImageElement;\n if (target.src !== PLACEHOLDER_IMAGE_URL) {\n target.src = PLACEHOLDER_IMAGE_URL;\n // Clear srcSet to prevent fallback to other sizes that might also fail\n target.srcset = '';\n }\n }}\n sizes={generateThumbnailSizesAttribute()}\n src={getThumbnailSrc(baseUrl)}\n srcSet={generateThumbnailSrcSet(baseUrl)}\n title={title}\n />\n );\n};\n","import { cn } from '@evolve.ui/theme-system';\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\n\nimport { PLACEHOLDER_IMAGE_URL, THUMBNAIL } from '../../constants';\nimport { ImageSliderCard, ResponsiveImageData } from '../../ImageSlider.types';\n\n/**\n * Props for the Thumbnails component\n */\ntype Props = {\n /** Array of image cards to display as thumbnails */\n cards: ImageSliderCard[];\n /** Currently active page number (1-based) */\n currentPage: number;\n /** Function to generate responsive thumbnail sizes attribute */\n generateThumbnailSizesAttribute: () => string;\n /** Function to generate responsive thumbnail srcSet */\n generateThumbnailSrcSet: (baseUrl: string) => string;\n /** Callback fired when a thumbnail is clicked */\n onThumbnailClick: (pageNumber: number) => void;\n /** Orientation of the thumbnail previews */\n orientation: 'vertical' | 'horizontal';\n};\n\n/**\n * Thumbnails component displays clickable thumbnail previews for image navigation.\n * Supports both vertical and horizontal orientations with consistent 111px sizing across all viewports.\n */\nexport const Thumbnails = ({\n cards,\n currentPage,\n generateThumbnailSizesAttribute,\n generateThumbnailSrcSet,\n onThumbnailClick,\n orientation,\n}: Props) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const thumbnailRefs = useRef<(HTMLButtonElement | null)[]>([]);\n const previousPageRef = useRef<number>(currentPage);\n\n // Initialize refs array to match cards length - more efficient approach\n useEffect(() => {\n // Only resize if length changed, don't create new array unnecessarily\n if (thumbnailRefs.current.length !== cards.length) {\n thumbnailRefs.current.length = cards.length;\n }\n }, [cards.length]);\n\n // Helper function to modify baseUrl query parameters for quality and sharpening\n // Memoized to avoid repeated URL object creation\n const enhanceBaseUrl = useCallback((baseUrl: string) => {\n // Use string manipulation instead of URL constructor for better performance\n const hasParams = baseUrl.includes('?');\n const separator = hasParams ? '&' : '?';\n return `${baseUrl}${separator}quality=${THUMBNAIL.QUALITY}&sharpen=false`;\n }, []);\n\n // Helper function to render thumbnail images with low fetch priority\n const renderThumbnailImage = useCallback(\n (imageData: ResponsiveImageData, index: number, thumbnailSize: number) => {\n const { alt, baseUrl, title } = imageData;\n const enhancedBaseUrl = enhanceBaseUrl(baseUrl);\n return (\n <img\n alt={alt}\n className={`h-full max-h-[${thumbnailSize}px] w-full max-w-[${thumbnailSize}px] bg-background-primary object-contain`}\n fetchPriority={index <= 5 ? 'high' : 'low'}\n loading={index <= 5 ? 'eager' : 'lazy'}\n onError={(e) => {\n const target = e.target as HTMLImageElement;\n if (target.src !== PLACEHOLDER_IMAGE_URL) {\n target.src = PLACEHOLDER_IMAGE_URL;\n // Clear srcSet to prevent fallback to other sizes that might also fail\n target.srcset = '';\n }\n }}\n sizes={generateThumbnailSizesAttribute()}\n src={`${enhancedBaseUrl}&width=${thumbnailSize}`} // Fallback for browsers without srcSet support\n srcSet={generateThumbnailSrcSet(enhancedBaseUrl)}\n title={title}\n />\n );\n },\n [generateThumbnailSrcSet, generateThumbnailSizesAttribute, enhanceBaseUrl]\n );\n\n // Auto-scroll the active thumbnail into view when currentPage changes\n // Only scroll if the page actually changed (not on mount or remount from mobile → desktop)\n useEffect(() => {\n const pageChanged = previousPageRef.current !== currentPage;\n\n // Update the ref for next comparison\n previousPageRef.current = currentPage;\n\n // Only scroll if the page actually changed\n if (!pageChanged) {\n return;\n }\n\n const activeIndex = currentPage - 1;\n const activeThumbnail = thumbnailRefs.current[activeIndex];\n\n if (activeThumbnail && containerRef.current) {\n activeThumbnail.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'center',\n });\n }\n }, [currentPage, orientation]);\n\n /**\n * Creates thumbnail preview images that can be clicked to navigate to specific images.\n * Supports both horizontal and vertical orientations with configurable size and dimming.\n * Supports both custom ReactNode cards and responsive imageData.\n */\n const thumbnailPreviews = useMemo(() => {\n const isHorizontal = orientation === 'horizontal';\n const thumbnailSize = isHorizontal ? 48 : THUMBNAIL.SIZE;\n\n return cards.map(({ card, imageData, key }, index) => {\n const pageNumber = index + 1;\n const isActive = currentPage === pageNumber;\n\n return (\n <button\n aria-current={isActive ? 'true' : 'false'}\n aria-label={`Go to image ${pageNumber}${imageData?.alt ? `: ${imageData.alt}` : ''}`}\n aria-selected={isActive}\n className={cn(\n 'box-border flex-shrink-0 cursor-pointer overflow-hidden rounded-md transition-all duration-100',\n 'hui-focus-visible-outline hover:opacity-80 focus:-outline-offset-4',\n `aspect-square h-[${thumbnailSize}px] w-[${thumbnailSize}px] max-h-[${thumbnailSize}px] max-w-[${thumbnailSize}px]`,\n // Use outline instead of border to avoid affecting box dimensions\n isActive\n ? 'opacity-100 outline outline-2 -outline-offset-2 outline-border-selected'\n : 'opacity-50 outline outline-1 -outline-offset-1 outline-border-secondary'\n )}\n data-active={isActive}\n data-page={pageNumber}\n key={key}\n onClick={() => onThumbnailClick(pageNumber)}\n ref={(el) => {\n thumbnailRefs.current[index] = el;\n }}\n role=\"tab\"\n style={{\n height: `${thumbnailSize}px`,\n maxHeight: `${thumbnailSize}px`,\n maxWidth: `${thumbnailSize}px`,\n width: `${thumbnailSize}px`,\n }}\n type=\"button\"\n >\n <div className=\"h-full w-full bg-background-primary\">\n {/* Render responsive image if imageData is provided, otherwise use custom card */}\n {imageData ? renderThumbnailImage(imageData, index, thumbnailSize) : card}\n </div>\n </button>\n );\n });\n }, [cards, currentPage, onThumbnailClick, renderThumbnailImage, orientation]);\n\n const isHorizontal = orientation === 'horizontal';\n\n return (\n <div\n aria-label=\"Image thumbnails\"\n className={cn(\n 'flex xsMax:hidden',\n isHorizontal\n ? 'w-full flex-row justify-center overflow-x-auto overflow-y-hidden pb-2xs'\n : 'h-full w-[136px] flex-col overflow-y-auto overflow-x-hidden pr-2xs mdMax:w-[128px]'\n )}\n ref={containerRef}\n role=\"tablist\"\n style={{\n scrollbarWidth: 'thin',\n }}\n >\n <div className={cn('flex gap-xs', isHorizontal ? 'flex-row' : 'flex-col')}>{thumbnailPreviews}</div>\n </div>\n );\n};\n","import { useRef, useState } from 'react';\n\nimport { useWindowIsMobile } from '../../providers';\nimport { ResponsiveImageConfig } from '../ImageSlider.types';\n\n/**\n * Props for the useImageSlider hook\n */\ntype UseImageSliderProps = {\n /** Number of cards/images in the slider */\n numberOfPages: number;\n /** Responsive image configuration */\n responsiveImageConfig: ResponsiveImageConfig;\n};\n\n/**\n * Main hook for ImageSlider component that provides basic state and refs\n * Navigation and scroll handling are managed separately to avoid circular dependencies\n * @param props - ImageSlider configuration\n * @returns Basic state and handlers needed for the ImageSlider component\n */\nexport const useImageSlider = ({ numberOfPages, responsiveImageConfig }: UseImageSliderProps) => {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const contentRef = useRef<HTMLDivElement | null>(null);\n\n const [hasHoveredGallery, setHasHoveredGallery] = useState(false);\n const isMobile = useWindowIsMobile();\n\n const handleMouseOver = () => {\n if (!isMobile && !hasHoveredGallery) {\n setHasHoveredGallery(true);\n }\n };\n\n const handleMobileInteraction = () => {\n if (isMobile && !hasHoveredGallery) {\n setHasHoveredGallery(true);\n }\n };\n\n return {\n // Refs\n containerRef,\n contentRef,\n\n // Event handlers\n handleMobileInteraction,\n handleMouseOver,\n\n // State\n hasHoveredGallery,\n isMobile,\n numberOfPages,\n responsiveImageConfig,\n setHasHoveredGallery,\n };\n};\n","import { ReactNode } from 'react';\n\n/**\n * Display mode for thumbnail navigation\n */\nexport enum ThumbnailDisplay {\n Index = 'index',\n Thumbnails = 'thumbnails',\n}\n\n/**\n * Analytics event data for ImageSlider interactions\n */\nexport type ImageSliderAnalyticsEvent = {\n /** Current image position (1-based index) */\n imagePosition: number;\n /** Type of interaction that triggered the event */\n interactionType: 'Thumbnail Click' | 'Next' | 'Prev' | 'Open Lightbox';\n /** Total number of images in the slider */\n totalImages: number;\n};\n\n/**\n * Responsive image data for optimized loading\n */\nexport type ResponsiveImageData = {\n /**\n * Alt text for the image\n */\n alt: string;\n /**\n * Base URL for the image (without width parameters)\n */\n baseUrl: string;\n /**\n * Optional title for the image\n */\n title?: string;\n};\n\n/**\n * Configuration for responsive image sizes and breakpoints\n */\nexport type ResponsiveImageConfig = {\n /**\n * Breakpoint width in pixels where mobile switches to desktop\n * @default 768\n */\n breakpoint: number;\n /**\n * Desktop image width in pixels\n * @default 651\n */\n desktopSize: number;\n /**\n * Mobile image width in pixels\n * @default 366\n */\n mobileSize: number;\n};\n\n/**\n * Card for the ImageSlider - supports both custom ReactNode and responsive images\n */\nexport type ImageSliderCard = {\n /**\n * The rendered content of the card or image.\n * Optional when using imageData.\n */\n card?: ReactNode;\n /**\n * Responsive image data for automatic srcset/sizes optimization.\n * When provided, `card` will be ignored and an optimized <img> will be rendered.\n * Optional when using custom card content.\n */\n imageData?: ResponsiveImageData;\n /**\n * The unique identifier for the card\n */\n key: string;\n};\n\nexport type ImageSliderPageInfo = {\n breakpoints: number[];\n cardsPerPage: number;\n numberOfPages: number;\n};\n\n// this is the px size of the MD gap (kept for potential future use)\nexport const CAROUSEL_CARD_GAP_NUM = 24;\n","import { RefObject, useCallback, useEffect, useState } from 'react';\n\nimport { ImageSliderCard, ThumbnailDisplay } from '../ImageSlider.types';\n\n/**\n * Props for the useImageSliderNavigation hook\n */\ntype UseImageSliderNavigationProps = {\n /** The cards in the slider */\n cards: ImageSliderCard[];\n /** Optional key to identify when content has changed (e.g., an item id) */\n contentKey?: string | number;\n /** Ref to the content container */\n contentRef: RefObject<HTMLDivElement | null>;\n /** Whether the slider is currently scrolling */\n isScrolling: boolean;\n /** Total number of pages/slides */\n numberOfPages: number;\n /** Function to reset the gallery hover state when content changes (new URL/different images) */\n setHasHoveredGallery: (hasHovered: boolean) => void;\n /** Display mode for navigation controls; 'index' uses same button visibility as horizontal */\n thumbnailDisplay?: ThumbnailDisplay;\n /** Orientation of the thumbnail previews */\n thumbnailOrientation?: 'vertical' | 'horizontal';\n};\n\n/**\n * Hook for managing navigation state and handlers in the ImageSlider.\n * Implements wraparound navigation where clicking previous on the first image\n * jumps to the last image, and clicking next on the last image jumps to the first.\n * @param props - Navigation configuration\n * @returns Navigation state and handlers\n */\nexport const useImageSliderNavigation = ({\n contentKey,\n contentRef,\n isScrolling,\n numberOfPages,\n setHasHoveredGallery,\n thumbnailDisplay = ThumbnailDisplay.Thumbnails,\n thumbnailOrientation = 'vertical',\n}: UseImageSliderNavigationProps) => {\n const [currentPage, setCurrentPage] = useState(1);\n\n // For horizontal thumbnails or index display, always show buttons even with single image\n // For vertical thumbnails, hide buttons when there's only one image\n const showNavButtonsWithSingleImage =\n thumbnailOrientation === 'horizontal' || thumbnailDisplay === ThumbnailDisplay.Index;\n const showPreviousPageButton = showNavButtonsWithSingleImage ? true : numberOfPages > 1;\n const showNextPageButton = showNavButtonsWithSingleImage ? true : numberOfPages > 1;\n\n // For horizontal/index with single image, disable buttons\n // For vertical or multiple images, use wraparound navigation (never disabled)\n const isPreviousPageDisabled = showNavButtonsWithSingleImage && numberOfPages <= 1;\n const isNextPageDisabled = showNavButtonsWithSingleImage && numberOfPages <= 1;\n\n const goToPreviousPage = useCallback(() => {\n if (!isScrolling) {\n // Trigger hover state to load all images when navigation is used\n setHasHoveredGallery(true);\n if (currentPage > 1) {\n setCurrentPage(currentPage - 1);\n } else {\n // Wrap to last page when on first page\n setCurrentPage(numberOfPages);\n }\n }\n }, [currentPage, numberOfPages, isScrolling, setCurrentPage, setHasHoveredGallery]);\n\n const goToNextPage = useCallback(() => {\n if (!isScrolling) {\n // Trigger hover state to load all images when navigation is used\n setHasHoveredGallery(true);\n if (currentPage < numberOfPages) {\n setCurrentPage(currentPage + 1);\n } else {\n // Wrap to first page when on last page\n setCurrentPage(1);\n }\n }\n }, [currentPage, numberOfPages, isScrolling, setCurrentPage, setHasHoveredGallery]);\n\n const handleThumbnailClick = useCallback(\n (pageNumber: number) => {\n if (!isScrolling) {\n // Trigger hover state to load all images when thumbnail navigation is used\n setHasHoveredGallery(true);\n setCurrentPage(pageNumber);\n }\n },\n [isScrolling, setCurrentPage, setHasHoveredGallery]\n );\n\n /**\n * Handles keyboard navigation for the slider.\n * Allows using Left and Right arrow keys to navigate between images.\n */\n const onKeyNavigation = useCallback(\n (event: React.KeyboardEvent) => {\n if (event.key === 'ArrowRight') {\n goToNextPage();\n } else if (event.key === 'ArrowLeft') {\n goToPreviousPage();\n }\n },\n [goToNextPage, goToPreviousPage]\n );\n\n useEffect(() => {\n setCurrentPage(1);\n // Reset hover state when content changes (new content key/different images)\n setHasHoveredGallery(false);\n if (contentRef.current && typeof contentRef.current.scrollTo === 'function') {\n contentRef.current.scrollTo({\n behavior: 'instant',\n left: 0,\n });\n }\n }, [contentKey, contentRef, setHasHoveredGallery]);\n\n return {\n currentPage,\n goToNextPage,\n goToPreviousPage,\n handleThumbnailClick,\n isNextPageDisabled,\n isPreviousPageDisabled,\n onKeyNavigation,\n setCurrentPage,\n showNextPageButton,\n showPreviousPageButton,\n };\n};\n","import { debounce } from 'es-toolkit';\nimport { RefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { useWindowIsMobile } from '../../providers';\nimport { ANIMATION, MOBILE_CARD, SPACING } from '../constants';\n\n/**\n * Props for the useImageSliderScrollHandler hook\n */\ntype UseImageSliderScrollHandlerProps = {\n /** Ref to the content container */\n contentRef: RefObject<HTMLDivElement | null>;\n /** Current page number */\n currentPage: number;\n /**\n * Max width in px of each carousel card on mobile (matches `responsiveImageConfig.desktopSize` on the slider).\n * @default MOBILE_CARD.MAX_WIDTH\n */\n maxMobileCardWidth?: number;\n /** Total number of pages */\n numberOfPages: number;\n /** Function to update the current page */\n setCurrentPage: (page: number) => void;\n /** Function to update the scrolling state */\n setIsScrolling?: (isScrolling: boolean) => void;\n};\n\n/**\n * Hook for managing scroll behavior and page tracking in the ImageSlider\n * @param props - Scroll handler configuration\n * @returns Scroll handlers and scrolling state\n */\nexport const useImageSliderScrollHandler = ({\n contentRef,\n currentPage,\n maxMobileCardWidth = MOBILE_CARD.MAX_WIDTH,\n numberOfPages,\n setCurrentPage,\n setIsScrolling,\n}: UseImageSliderScrollHandlerProps) => {\n const [internalIsScrolling, setInternalIsScrolling] = useState(false);\n const isScrollingState = setIsScrolling ? internalIsScrolling : false;\n const isMobile = useWindowIsMobile();\n const previousPageRef = useRef<number>(currentPage);\n\n // Handle programmatic scrolling on page changes (desktop only)\n useEffect(() => {\n if (contentRef.current) {\n // Skip programmatic scrolling on mobile - let natural snap scrolling handle it\n if (isMobile) {\n return;\n }\n\n const pageChanged = previousPageRef.current !== currentPage;\n\n // Set scrolling state to prevent rapid navigation\n if (setIsScrolling) {\n setIsScrolling(true);\n } else {\n setInternalIsScrolling(true);\n }\n\n // Calculate scroll position including gap for desktop\n const containerWidth = contentRef.current.offsetWidth;\n const gap = SPACING.GAP_MD; // md gap in pixels for desktop\n const scrollPosition = (currentPage - 1) * (containerWidth + gap);\n\n // Use 'auto' (instant) instead of 'smooth' if page hasn't changed\n // This prevents page scrolling on resize/mount while keeping smooth scrolling for navigation\n contentRef.current.scrollTo({\n behavior: pageChanged ? 'smooth' : 'auto',\n left: scrollPosition,\n });\n\n // Reset scrolling state after animation completes\n // Smooth scroll animation typically takes ~300-400ms\n const scrollTimeout = setTimeout(() => {\n if (setIsScrolling) {\n setIsScrolling(false);\n } else {\n setInternalIsScrolling(false);\n }\n }, ANIMATION.SCROLL_TIMEOUT);\n\n // Update previous page reference\n previousPageRef.current = currentPage;\n\n return () => {\n clearTimeout(scrollTimeout);\n };\n }\n return undefined;\n }, [currentPage, contentRef, setIsScrolling, isMobile]);\n\n /**\n * Memoized debounced scroll handler for desktop scroll tracking.\n * Updates the current page when user scrolls to reflect active thumbnail.\n */\n const debouncedDesktopScrollHandler = useMemo(\n () =>\n debounce(() => {\n if (contentRef.current && !isMobile) {\n const scrollLeft = contentRef.current.scrollLeft;\n const containerWidth = contentRef.current.offsetWidth;\n const gap = SPACING.GAP_MD; // md gap in pixels for desktop\n const newPage = Math.round(scrollLeft / (containerWidth + gap)) + 1;\n\n if (newPage !== currentPage && newPage >= 1 && newPage <= numberOfPages) {\n setCurrentPage(newPage);\n }\n }\n }, ANIMATION.DEBOUNCE_DELAY),\n [currentPage, numberOfPages, contentRef, setCurrentPage, isMobile]\n );\n\n /**\n * Memoized debounced scroll handler for mobile scroll tracking.\n * Updates the current page based on mobile card layout with gaps and margins.\n */\n const debouncedMobileScrollHandler = useMemo(\n () =>\n debounce(() => {\n if (contentRef.current && isMobile) {\n const { clientWidth, scrollLeft, scrollWidth } = contentRef.current;\n const maxScroll = scrollWidth - clientWidth;\n\n // Prevent scrolling beyond bounds\n if (scrollLeft < 0) {\n contentRef.current.scrollLeft = 0;\n } else if (scrollLeft > maxScroll) {\n contentRef.current.scrollLeft = maxScroll;\n }\n\n // Calculate current page based on scroll position\n // Mobile cards: min(calc(100% - 64px), maxMobileCardWidth) with 4px gaps\n // First card has 16px left margin, last card has 16px right margin\n const gap = SPACING.GAP_2XS;\n const margin = SPACING.MARGIN_SM;\n const cardWidth = Math.min(clientWidth - MOBILE_CARD.WIDTH_REDUCTION, maxMobileCardWidth);\n const cardWithGap = cardWidth + gap;\n\n // Calculate which card is most visible based on scroll position\n // Account for the initial margin offset\n const adjustedScrollLeft = scrollLeft + margin;\n const newPage = Math.round(adjustedScrollLeft / cardWithGap) + 1;\n\n if (newPage !== currentPage && newPage >= 1 && newPage <= numberOfPages) {\n setCurrentPage(newPage);\n }\n }\n }, ANIMATION.DEBOUNCE_DELAY),\n [currentPage, maxMobileCardWidth, numberOfPages, contentRef, setCurrentPage, isMobile]\n );\n\n /**\n * Handles scroll events within the slider content area.\n * Uses debounced handlers for both mobile and desktop to improve performance.\n */\n const onScrollCards = useCallback(() => {\n if (isMobile) {\n debouncedMobileScrollHandler();\n } else {\n debouncedDesktopScrollHandler();\n }\n }, [isMobile, debouncedMobileScrollHandler, debouncedDesktopScrollHandler]);\n\n return {\n isScrolling: isScrollingState,\n onScrollCards,\n };\n};\n","import { cn } from '@evolve.ui/theme-system';\nimport { useCallback, useMemo, useState, type CSSProperties } from 'react';\n\nimport { IndexIndicator } from './components/IndexIndicator/IndexIndicator';\nimport { NavigationButtons } from './components/NavigationButtons/NavigationButtons';\nimport { ResponsiveImage } from './components/ResponsiveImage';\nimport { Thumbnails } from './components/Thumbnails/Thumbnails';\nimport { PLACEHOLDER_EMPTY_CARDS } from './constants';\nimport { useImageSlider } from './hooks/useImageSlider';\nimport { useImageSliderNavigation } from './hooks/useImageSliderNavigation';\nimport { useImageSliderScrollHandler } from './hooks/useImageSliderScrollHandler';\nimport {\n ImageSliderAnalyticsEvent,\n ImageSliderCard,\n ResponsiveImageConfig,\n ThumbnailDisplay,\n} from './ImageSlider.types';\nimport { generateThumbnailSizesAttribute, generateThumbnailSrcSet } from './utils/imageOptimization';\n\ntype Props = {\n /**\n * The scrollable content of the image slider.\n * Should be individual images.\n *\n * @property {ReactNode} card - The rendered image content\n * @property {string} key - A unique identifier for the image\n */\n cards: ImageSliderCard[];\n /**\n * Class name for the image gallery container.\n */\n className?: string;\n /**\n * Optional key to identify when content has changed (e.g., an item id).\n * When this key changes, the slider will reset to the first image.\n * If not provided, will reset whenever the cards array reference changes.\n */\n contentKey?: string | number;\n /**\n * Shape of the navigation icons.\n * 'circle' creates round buttons, 'square' creates square buttons.\n *\n * @default 'circle'\n */\n iconShape?: 'circle' | 'square';\n /**\n * Size of the navigation icons - sm=34px, md=42px, lg=54px.\n * For horizontal thumbnails, 'lg' (54px) is recommended.\n *\n * @default 'sm'\n */\n iconSize?: 'sm' | 'md' | 'lg';\n /**\n * Type of icons to use for navigation.\n * 'caret' uses CaretLeft/CaretRight, 'arrow' uses ArrowLeft/ArrowRight.\n *\n * @default 'caret'\n */\n iconType?: 'caret' | 'arrow';\n /**\n * Variant of the navigation icons.\n * 'outlined' shows buttons with borders, 'transparent' shows borderless buttons.\n *\n * @default 'outlined'\n */\n iconVariant?: 'outlined' | 'transparent';\n /**\n * When thumbnailDisplay is 'index', position of the numeric indicator relative to the main image.\n *\n * @default 'bottom'\n */\n indexPosition?: 'top' | 'bottom';\n /**\n * Callback fired when an analytics event occurs in the image slider.\n * Receives interaction type, current image position (1-based), and total image count.\n * Does not fire for mobile swipe navigation, only for button/thumbnail clicks and lightbox opens.\n */\n onAnalyticsEventTriggered?: (event: ImageSliderAnalyticsEvent) => void;\n /**\n * Callback fired when an image is clicked (mouse) or activated via keyboard (Enter/Space).\n * Receives the index of the image and the mouse or keyboard event.\n */\n onImageClick?: (\n imageIndex: number,\n event: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>\n ) => void;\n /**\n * Callback fired when an image is hovered (mouse) or focused (keyboard/screen reader).\n * Receives the index of the image and the mouse or focus event.\n */\n onImageMouseOver?: (\n imageIndex: number,\n event: React.MouseEvent<HTMLElement> | React.FocusEvent<HTMLElement>\n ) => void;\n /**\n * Configuration for responsive image loading when using imageData in cards.\n * Defines mobile/desktop sizes and breakpoint for optimal image loading.\n */\n responsiveImageConfig?: ResponsiveImageConfig;\n /**\n * Displays thumbnail previews on the left side of the slider.\n * Clicking a thumbnail will navigate to the corresponding image.\n * The current image thumbnail will have a border highlight.\n *\n * @default true\n */\n showThumbnails?: boolean;\n /**\n * Display mode for image navigation controls.\n * 'thumbnails' shows image previews (vertical or horizontal per thumbnailOrientation).\n * 'index' shows a numeric indicator (e.g., \"1 of 11\") above or below the main image per indexPosition.\n *\n * @default ThumbnailDisplay.Thumbnails\n */\n thumbnailDisplay?: ThumbnailDisplay;\n /**\n * Orientation of the thumbnail previews when showThumbnails is true.\n * 'vertical' displays thumbnails on the left side, 'horizontal' displays them below the image.\n *\n * @default 'vertical'\n */\n thumbnailOrientation?: 'vertical' | 'horizontal';\n};\n\n/**\n * Displays a single image at a time with navigation controls.\n * Allows navigation via buttons, dots (pagination), or touch gestures (on mobile).\n */\n// Default responsive image configuration\nconst DEFAULT_RESPONSIVE_CONFIG: ResponsiveImageConfig = {\n breakpoint: 768,\n desktopSize: 651,\n mobileSize: 366,\n};\n\nexport const ImageSlider = ({\n cards: initialCards,\n className,\n contentKey,\n iconShape = 'circle',\n iconSize = 'sm',\n iconType = 'caret',\n iconVariant = 'outlined',\n indexPosition = 'bottom',\n onAnalyticsEventTriggered,\n onImageClick,\n onImageMouseOver,\n responsiveImageConfig = DEFAULT_RESPONSIVE_CONFIG,\n showThumbnails = true,\n thumbnailDisplay = ThumbnailDisplay.Thumbnails,\n thumbnailOrientation = 'vertical',\n}: Props) => {\n // When an item doesn't have images, the cards array will be empty.\n // We need to show a placeholder empty card in this case.\n const cards = useMemo(() => {\n if (initialCards.length === 0) {\n return PLACEHOLDER_EMPTY_CARDS;\n }\n return initialCards;\n }, [initialCards]);\n\n const numberOfPages = cards.length;\n\n // Initialize base slider state and refs\n const {\n containerRef,\n contentRef,\n handleMobileInteraction,\n handleMouseOver,\n hasHoveredGallery,\n isMobile,\n setHasHoveredGallery,\n } = useImageSlider({\n numberOfPages,\n responsiveImageConfig,\n });\n\n // Manage scrolling state locally to avoid circular dependency\n const [isScrolling, setIsScrolling] = useState(false);\n\n // Initialize navigation state and handlers\n const navigation = useImageSliderNavigation({\n cards,\n contentKey,\n contentRef,\n isScrolling,\n numberOfPages,\n setHasHoveredGallery,\n thumbnailDisplay,\n thumbnailOrientation,\n });\n\n // Initialize scroll handling with navigation state and local setIsScrolling\n const { onScrollCards } = useImageSliderScrollHandler({\n contentRef,\n currentPage: navigation.currentPage,\n maxMobileCardWidth: responsiveImageConfig.desktopSize,\n numberOfPages,\n setCurrentPage: navigation.setCurrentPage,\n setIsScrolling,\n });\n\n // Extract all the values we need\n const {\n currentPage,\n goToNextPage,\n goToPreviousPage,\n handleThumbnailClick,\n isNextPageDisabled,\n isPreviousPageDisabled,\n onKeyNavigation,\n showNextPageButton,\n showPreviousPageButton,\n } = navigation;\n\n // Wrap navigation handlers to trigger analytics\n const goToNextPageWithAnalytics = useCallback(() => {\n goToNextPage();\n onAnalyticsEventTriggered?.({\n imagePosition: currentPage < numberOfPages ? currentPage + 1 : 1,\n interactionType: 'Next',\n totalImages: numberOfPages,\n });\n }, [goToNextPage, onAnalyticsEventTriggered, currentPage, numberOfPages]);\n\n const goToPreviousPageWithAnalytics = useCallback(() => {\n goToPreviousPage();\n onAnalyticsEventTriggered?.({\n imagePosition: currentPage > 1 ? currentPage - 1 : numberOfPages,\n interactionType: 'Prev',\n totalImages: numberOfPages,\n });\n }, [goToPreviousPage, onAnalyticsEventTriggered, currentPage, numberOfPages]);\n\n const handleThumbnailClickWithAnalytics = useCallback(\n (pageNumber: number) => {\n // Only trigger analytics if navigating to a different image\n if (pageNumber !== currentPage && onAnalyticsEventTriggered) {\n onAnalyticsEventTriggered({\n imagePosition: pageNumber,\n interactionType: 'Thumbnail Click',\n totalImages: numberOfPages,\n });\n }\n handleThumbnailClick(pageNumber);\n },\n [currentPage, handleThumbnailClick, onAnalyticsEventTriggered, numberOfPages]\n );\n\n /**\n * These images are wrapped in a div and displayed one at a time with proper snap behavior.\n * When showImageOverflow is enabled on mobile, images take partial width to show overflow.\n * Supports both custom ReactNode cards and responsive imageData.\n * Images are re-rendered when currentPage changes to ensure active image gets full quality.\n *\n * On desktop before hover: Only render first image to avoid loading second image unnecessarily.\n * On mobile: Always render all images for swipe functionality.\n * After hover on desktop: Render all images for navigation.\n */\n const carouselCards = useMemo(() => {\n // On desktop before hover, only render the first image to prevent unnecessary loading\n // On mobile or after hover, render all images\n const cardsToRender = !isMobile && !hasHoveredGallery ? cards.slice(0, 1) : cards;\n\n return cardsToRender.map(({ card, imageData, key }, index) => {\n // For the sliced scenario, we need to get the actual index from the original cards array\n const actualIndex = !isMobile && !hasHoveredGallery ? 0 : index;\n const isActive = actualIndex + 1 === currentPage;\n\n return (\n <div\n aria-current={isActive ? 'true' : 'false'}\n aria-label={`Image ${actualIndex + 1} of ${cards.length}${imageData?.alt ? `: ${imageData.alt}` : ''}`}\n className={cn(\n 'flex w-full flex-none snap-center items-center justify-center bg-background-primary',\n onImageClick ? 'cursor-zoom-in' : 'cursor-default',\n // Desktop: full height\n 'smMin:h-full',\n // Mobile-specific styling (xsMax) — max dimensions follow responsiveImageConfig.desktopSize via --slider-size\n 'xsMax:aspect-square xsMax:max-h-[var(--slider-size)] xsMax:max-w-[var(--slider-size)] xsMax:overflow-hidden xsMax:rounded-lg xsMax:border xsMax:border-border-secondary',\n // Apply width reduction only when there are multiple cards for bleed effect\n numberOfPages > 1\n ? 'xsMax:w-[calc(100%-64px)] xsMax:max-w-[var(--slider-size)]'\n : 'xsMax:w-full xsMax:max-w-[var(--slider-size)]',\n {\n 'ml-sm': actualIndex === 0,\n 'mr-sm': actualIndex === cards.length - 1,\n }\n )}\n key={key} // Use stable key to avoid unnecessary DOM recreations\n onClick={(event) => {\n // Trigger mobile interaction for high-quality loading\n handleMobileInteraction();\n // Trigger analytics for lightbox open\n if (onAnalyticsEventTriggered) {\n onAnalyticsEventTriggered({\n imagePosition: actualIndex + 1,\n interactionType: 'Open Lightbox',\n totalImages: numberOfPages,\n });\n }\n // Call optional user-provided handler\n onImageClick?.(actualIndex, event);\n }}\n onFocus={(event) => {\n // Trigger mobile interaction for high-quality loading\n handleMobileInteraction();\n // Call optional user-provided handler\n onImageMouseOver?.(actualIndex, event);\n }}\n onKeyUp={\n onImageClick\n ? (event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n // Trigger analytics for lightbox open via keyboard\n if (onAnalyticsEventTriggered) {\n onAnalyticsEventTriggered({\n imagePosition: actualIndex + 1,\n interactionType: 'Open Lightbox',\n totalImages: numberOfPages,\n });\n }\n if (event.key === 'Enter') {\n onImageClick(actualIndex, event);\n }\n }\n }\n : undefined\n }\n onMouseOver={(event) => {\n // Always trigger gallery hover state for high-quality loading\n handleMouseOver();\n // Call optional user-provided handler\n if (onImageMouseOver) {\n onImageMouseOver(actualIndex, event);\n }\n }}\n onTouchStart={() => {\n // Trigger mobile interaction for high-quality loading on touch/drag\n handleMobileInteraction();\n }}\n role={onImageClick ? 'button' : undefined}\n tabIndex={onImageClick ? 0 : undefined}\n >\n {/* Render responsive image if imageData is provided, otherwise use custom card */}\n {imageData ? (\n <ResponsiveImage\n hasHoveredGallery={hasHoveredGallery}\n imageData={imageData}\n isActiveImage={isActive}\n isMainImage\n responsiveImageConfig={responsiveImageConfig}\n />\n ) : (\n card || null\n )}\n </div>\n );\n });\n }, [\n cards,\n currentPage,\n handleMobileInteraction,\n handleMouseOver,\n hasHoveredGallery,\n isMobile,\n numberOfPages,\n onAnalyticsEventTriggered,\n onImageClick,\n onImageMouseOver,\n responsiveImageConfig,\n ]);\n\n const isIndexDisplay = thumbnailDisplay === ThumbnailDisplay.Index;\n const isHorizontalThumbnailsDisplay =\n thumbnailDisplay === ThumbnailDisplay.Thumbnails && thumbnailOrientation === 'horizontal';\n\n return (\n // eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/mouse-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/tabindex-no-positive\n <section\n aria-label=\"Image gallery\"\n aria-roledescription=\"carousel\"\n className={cn(\n 'relative mx-auto w-full pr-lg outline-none smMax:pr-0',\n // Only extend beyond viewport for bleed effect when there are multiple cards\n { 'xsMax:-ml-sm xsMax:w-[calc(100%+32px)]': numberOfPages > 1 },\n className\n )}\n onClick={() => containerRef.current?.focus()}\n onKeyUp={onKeyNavigation}\n onMouseOver={handleMouseOver}\n ref={containerRef}\n role=\"application\"\n style={\n {\n '--slider-size': `${responsiveImageConfig.desktopSize}px`,\n } as CSSProperties\n }\n // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex\n tabIndex={0}\n >\n <div\n className={cn(\n 'flex flex-col',\n // Dynamic gap that scales smoothly from ~58px down to smaller sizes\n 'gap-[58px] mdMax:gap-xl smMax:gap-[38px] xsMax:gap-[28px]'\n )}\n >\n {/* Image Gallery Container */}\n <div\n className={cn(\n 'flex w-full',\n thumbnailDisplay === ThumbnailDisplay.Index\n ? 'flex-col items-center justify-center gap-2xs'\n : thumbnailOrientation === 'horizontal'\n ? 'flex-col items-center justify-center gap-xs'\n : 'relative items-center justify-center gap-[28px]'\n )}\n >\n {/* Index indicator - above main image when thumbnailDisplay is 'index' and indexPosition is 'top' */}\n {thumbnailDisplay === ThumbnailDisplay.Index && indexPosition === 'top' && (\n <IndexIndicator\n currentPage={currentPage}\n numberOfPages={numberOfPages}\n />\n )}\n\n {/* Vertical Thumbnails Container - Absolutely positioned */}\n {showThumbnails &&\n thumbnailDisplay === ThumbnailDisplay.Thumbnails &&\n thumbnailOrientation === 'vertical' && (\n <div className=\"absolute bottom-0 left-0 top-0 z-10 xsMax:hidden\">\n <Thumbnails\n cards={cards}\n currentPage={currentPage}\n generateThumbnailSizesAttribute={generateThumbnailSizesAttribute}\n generateThumbnailSrcSet={generateThumbnailSrcSet}\n onThumbnailClick={handleThumbnailClickWithAnalytics}\n orientation=\"vertical\"\n />\n </div>\n )}\n\n {/* Main Image Area */}\n <div\n className={cn(\n 'flex items-center',\n isIndexDisplay\n ? 'relative w-full justify-center gap-md smMin:max-w-[780px] xsMax:w-full'\n : isHorizontalThumbnailsDisplay\n ? 'max-w-[606px] gap-md xsMax:w-full'\n : cn(\n 'w-full justify-between gap-sm',\n showThumbnails ? 'pl-[146px] mdMax:pl-[139px] xsMax:pl-0' : ''\n )\n )}\n data-testid=\"image-slider-hero-controls\"\n >\n {/* Desktop navigation buttons (left) - hidden on mobile */}\n <div className=\"hidden smMin:block\">\n <NavigationButtons\n goToNextPage={goToNextPageWithAnalytics}\n goToPreviousPage={goToPreviousPageWithAnalytics}\n iconShape={iconShape}\n iconSize={iconSize}\n iconType={iconType}\n iconVariant={iconVariant}\n isNextPageDisabled={isNextPageDisabled}\n isPreviousPageDisabled={isPreviousPageDisabled}\n position=\"left\"\n showNextPageButton={showNextPageButton}\n showPreviousPageButton={showPreviousPageButton}\n />\n </div>\n\n {/* Main image container - responsive layout */}\n <div\n className={cn(\n // Shared: relative container with consistent max dimensions\n 'relative',\n isIndexDisplay\n ? 'max-h-[var(--slider-size)] smMin:flex smMin:aspect-square smMin:max-w-[var(--slider-size)] smMin:flex-1 smMin:justify-center smMin:overflow-hidden xsMax:w-full'\n : isHorizontalThumbnailsDisplay\n ? 'max-h-[400px] smMin:flex smMin:aspect-square smMin:max-w-[400px] smMin:flex-1 smMin:justify-center smMin:overflow-hidden xsMax:w-full'\n : 'max-h-[var(--slider-size)] smMin:flex smMin:aspect-square smMin:max-w-[var(--slider-size)] smMin:flex-1 smMin:justify-center smMin:overflow-hidden xsMax:w-full'\n )}\n data-testid=\"image-slider-media-frame\"\n >\n {/* Mobile navigation buttons - hidden on desktop */}\n <div className=\"smMin:hidden\">\n <NavigationButtons\n goToNextPage={goToNextPageWithAnalytics}\n goToPreviousPage={goToPreviousPageWithAnalytics}\n iconShape={iconShape}\n iconSize={iconSize}\n iconType={iconType}\n iconVariant={iconVariant}\n isNextPageDisabled={isNextPageDisabled}\n isPreviousPageDisabled={isPreviousPageDisabled}\n showNextPageButton={showNextPageButton}\n showPreviousPageButton={showPreviousPageButton}\n />\n </div>\n\n {/* Responsive scroll container wrapper */}\n <div\n className={cn(\n // Shared: primary background and full width\n 'w-full bg-background-primary',\n // Desktop: full height and hidden overflow\n 'smMin:h-full smMin:overflow-hidden'\n )}\n >\n <div\n aria-atomic=\"false\"\n aria-live=\"polite\"\n className={cn(\n 'flex w-full snap-x snap-mandatory overflow-y-hidden overflow-x-scroll',\n // Desktop: full height and 24px gap\n 'smMin:h-full smMin:gap-md',\n // Mobile: 2xs gap, let aspect-square control height\n 'xsMax:gap-2xs'\n )}\n onScroll={onScrollCards}\n ref={contentRef}\n role=\"region\"\n style={{\n scrollbarWidth: 'none',\n }}\n >\n {carouselCards}\n </div>\n </div>\n </div>\n\n {/* Desktop navigation buttons (right) - hidden on mobile */}\n <div className=\"hidden smMin:block\">\n <NavigationButtons\n goToNextPage={goToNextPageWithAnalytics}\n goToPreviousPage={goToPreviousPageWithAnalytics}\n iconShape={iconShape}\n iconSize={iconSize}\n iconType={iconType}\n iconVariant={iconVariant}\n isNextPageDisabled={isNextPageDisabled}\n isPreviousPageDisabled={isPreviousPageDisabled}\n position=\"right\"\n showNextPageButton={showNextPageButton}\n showPreviousPageButton={showPreviousPageButton}\n />\n </div>\n </div>\n\n {/* Horizontal Thumbnails Container - Below image */}\n {showThumbnails &&\n thumbnailDisplay === ThumbnailDisplay.Thumbnails &&\n thumbnailOrientation === 'horizontal' && (\n <div className=\"w-full xsMax:hidden\">\n <Thumbnails\n cards={cards}\n currentPage={currentPage}\n generateThumbnailSizesAttribute={generateThumbnailSizesAttribute}\n generateThumbnailSrcSet={generateThumbnailSrcSet}\n onThumbnailClick={handleThumbnailClickWithAnalytics}\n orientation=\"horizontal\"\n />\n </div>\n )}\n\n {/* Index indicator - below main image when thumbnailDisplay is 'index' and indexPosition is 'bottom' */}\n {thumbnailDisplay === ThumbnailDisplay.Index && indexPosition === 'bottom' && (\n <IndexIndicator\n currentPage={currentPage}\n numberOfPages={numberOfPages}\n />\n )}\n </div>\n </div>\n </section>\n );\n};\n"],"mappings":"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"}