@evolve.ui/core-components 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (509) hide show
  1. package/evolve-ui.entries.json +556 -0
  2. package/fileUpload/testUtils/mockFilesAndImages.d.cts +3 -3
  3. package/fileUpload/testUtils/mockFilesAndImages.d.cts.map +1 -1
  4. package/fileUpload/testUtils/mockFilesAndImages.d.mts +3 -3
  5. package/fileUpload/testUtils/mockFilesAndImages.d.mts.map +1 -1
  6. package/fileUpload/testUtils/testUtils.d.cts +1 -1
  7. package/fileUpload/testUtils/testUtils.d.cts.map +1 -1
  8. package/fileUpload/testUtils/testUtils.d.mts +1 -1
  9. package/fileUpload/testUtils/testUtils.d.mts.map +1 -1
  10. package/package.json +2 -2
  11. package/src/Accordion/Accordion.tsx +233 -0
  12. package/src/AddressDisplay/AddressDisplay.tsx +43 -0
  13. package/src/AddressDisplay/components/addressComponents.tsx +111 -0
  14. package/src/AddressDisplay/components/addressField.tsx +25 -0
  15. package/src/AddressDisplay/components/addressSection.tsx +8 -0
  16. package/src/AddressDisplay/components/getCountryValue.tsx +31 -0
  17. package/src/AddressDisplay/types.ts +26 -0
  18. package/src/AutomatedCarousel/AutomatedCarousel.tsx +163 -0
  19. package/src/AutomatedCarousel/automatedCarousel.types.ts +7 -0
  20. package/src/AutomatedCarousel/components/CarouselProgressBar/CarouselProgressBar.tsx +139 -0
  21. package/src/AutomatedCarousel/components/CarouselProgressBar/components/CarouselProgressBarUnit/CarouselProgressBarUnit.tsx +165 -0
  22. package/src/Badge/Badge.tsx +104 -0
  23. package/src/Badge/Badge.types.ts +58 -0
  24. package/src/Badge/ItemBadge.tsx +97 -0
  25. package/src/Badge/LiveStatusBadge.tsx +93 -0
  26. package/src/BannerNotification/BannerNotification.tsx +157 -0
  27. package/src/BannerNotification/components/BannerNotificationSkeleton.tsx +39 -0
  28. package/src/BannerNotification/components/CalloutIcon/BannerIcon.tsx +48 -0
  29. package/src/BannerNotification/utils/getRandomTooltipId.ts +3 -0
  30. package/src/BottomSheet/BottomSheet.tsx +476 -0
  31. package/src/BottomSheet/components/BottomSheetBackdrop/BottomSheetBackdrop.tsx +47 -0
  32. package/src/BottomSheet/components/BottomSheetContentArea/BottomSheetContentArea.tsx +92 -0
  33. package/src/BottomSheet/components/BottomSheetOverlay/BottomSheetOverlayTranslate3d.tsx +196 -0
  34. package/src/BottomSheet/components/SheetDescription/SheetDescription.tsx +22 -0
  35. package/src/BottomSheet/components/SheetTitle/SheetTitle.tsx +21 -0
  36. package/src/BottomSheet/components/index.tsx +5 -0
  37. package/src/BottomSheet/hooks/index.tsx +13 -0
  38. package/src/BottomSheet/hooks/useAriaHider.tsx +91 -0
  39. package/src/BottomSheet/hooks/useBottomSheetServices.tsx +224 -0
  40. package/src/BottomSheet/hooks/useDragHandler.tsx +282 -0
  41. package/src/BottomSheet/hooks/useFocusTrap.tsx +113 -0
  42. package/src/BottomSheet/hooks/useLayoutEffect.tsx +4 -0
  43. package/src/BottomSheet/hooks/useOptimizedResizeObserver.tsx +94 -0
  44. package/src/BottomSheet/hooks/useOptimizedScrollState.tsx +87 -0
  45. package/src/BottomSheet/hooks/useReady.tsx +34 -0
  46. package/src/BottomSheet/hooks/useReducedMotion.tsx +22 -0
  47. package/src/BottomSheet/hooks/useScrollLock.tsx +143 -0
  48. package/src/BottomSheet/hooks/useSnapPoints.tsx +355 -0
  49. package/src/BottomSheet/hooks/useSpring.tsx +47 -0
  50. package/src/BottomSheet/hooks/useSpringInterpolationsTranslate3d.tsx +101 -0
  51. package/src/BottomSheet/index.tsx +237 -0
  52. package/src/BottomSheet/state/atoms.ts +147 -0
  53. package/src/BottomSheet/state/useBottomSheetStateMachine.ts +246 -0
  54. package/src/BottomSheet/types.ts +172 -0
  55. package/src/BottomSheet/utils.ts +65 -0
  56. package/src/Breadcrumbs/Breadcrumbs.tsx +126 -0
  57. package/src/Button/Button.tsx +164 -0
  58. package/src/Button/Button.types.ts +80 -0
  59. package/src/Button/buttonColorClasses.ts +53 -0
  60. package/src/Callout/Callout.tsx +136 -0
  61. package/src/Callout/Callout.types.ts +29 -0
  62. package/src/Callout/components/CalloutIcon/CalloutIcon.tsx +56 -0
  63. package/src/Card/CardGrid.tsx +263 -0
  64. package/src/Card/SingleCard.tsx +22 -0
  65. package/src/Card/cardFactory.tsx +176 -0
  66. package/src/Card/components/createBadge.tsx +34 -0
  67. package/src/Card/components/createFavoriteButton.tsx +40 -0
  68. package/src/Card/components/createImage.tsx +64 -0
  69. package/src/Card/components/createInfo.tsx +84 -0
  70. package/src/Card/components/createName.tsx +63 -0
  71. package/src/Card/components/createPriceStatus.tsx +100 -0
  72. package/src/Card/components/types.ts +4 -0
  73. package/src/Card/hooks/useCardVisibilityTracking.ts +82 -0
  74. package/src/Card/sharedProps.ts +12 -0
  75. package/src/Card/types.ts +62 -0
  76. package/src/Carousel/Carousel.tsx +513 -0
  77. package/src/Carousel/Carousel.types.ts +43 -0
  78. package/src/Carousel/Carousel.utils.ts +63 -0
  79. package/src/Carousel/components/DotButton/DotButton.tsx +42 -0
  80. package/src/Carousel/components/NavigationButtons/NavigationButtons.tsx +77 -0
  81. package/src/Carousel/components/TitleSection/TitleSection.tsx +61 -0
  82. package/src/Carousel/components/TitleSection/components/SubHeaderLeft/SubHeaderLeft.tsx +53 -0
  83. package/src/Carousel/components/TitleSection/components/Title/Title.tsx +46 -0
  84. package/src/Carousel/index.ts +2 -0
  85. package/src/Carousel/testUtils.ts +10 -0
  86. package/src/Chips/Chip.tsx +153 -0
  87. package/src/Chips/ChipGroup.tsx +173 -0
  88. package/src/Chips/SuggestionChip.tsx +15 -0
  89. package/src/Chips/chipTypes.ts +113 -0
  90. package/src/Chips/index.ts +4 -0
  91. package/src/ChoiceListItem/Checkbox.tsx +69 -0
  92. package/src/ChoiceListItem/Radio.tsx +61 -0
  93. package/src/ChoiceListItem/choiceListItem.tsx +99 -0
  94. package/src/ChoiceListItem/common.tsx +148 -0
  95. package/src/ChoiceListItem/index.ts +3 -0
  96. package/src/Collapsible/Collapsible.tsx +58 -0
  97. package/src/Confetti/Confetti.tsx +270 -0
  98. package/src/Confetti/index.ts +2 -0
  99. package/src/ContentPager/ContentPager.tsx +189 -0
  100. package/src/ContentPager/components/Page.tsx +24 -0
  101. package/src/CookieConsent/components/CookieCategoryRow/CookieCategoryRow.tsx +30 -0
  102. package/src/CookieConsent/components/CookieConsent/CookieConsent.tsx +74 -0
  103. package/src/CookieConsent/components/CookieConsentBanner/CookieConsentBanner.tsx +51 -0
  104. package/src/CookieConsent/components/CookieConsentModal/CookieConsentModal.tsx +64 -0
  105. package/src/CookieConsent/hooks/useCookieConsent.ts +170 -0
  106. package/src/CookieConsent/hooks/useCookieConsentState.ts +142 -0
  107. package/src/CookieConsent/index.ts +16 -0
  108. package/src/CookieConsent/types/cookieConsent.types.ts +79 -0
  109. package/src/CookieConsent/types/index.ts +7 -0
  110. package/src/Countdown/Countdown.tsx +161 -0
  111. package/src/Countdown/Countdown.types.ts +4 -0
  112. package/src/Countdown/hooks/useGetCountdown.ts +103 -0
  113. package/src/DateTimeInput/dateInput/DateInput.tsx +199 -0
  114. package/src/DateTimeInput/datePicker/DatePicker.tsx +138 -0
  115. package/src/DateTimeInput/datePicker/components/calendar/Calendar.tsx +72 -0
  116. package/src/DateTimeInput/datePicker/index.ts +2 -0
  117. package/src/DateTimeInput/timeInput/TimeInput.tsx +128 -0
  118. package/src/DateTimeInput/timePicker/TimePicker.tsx +118 -0
  119. package/src/DateTimeInput/timePicker/components/TimePopover/AmPmSwitch.tsx +103 -0
  120. package/src/DateTimeInput/timePicker/components/TimePopover/TimeFieldInput.tsx +26 -0
  121. package/src/DateTimeInput/timePicker/components/TimePopover/TimePopover.tsx +84 -0
  122. package/src/DateTimeInput/timePicker/components/TimePopover/TimePopover.utils.ts +67 -0
  123. package/src/DateTimeInput/timePicker/components/TimePopover/TimePopoverActions.tsx +26 -0
  124. package/src/DateTimeInput/timePicker/index.ts +2 -0
  125. package/src/DateTimeInput/utils/getDisplayDate.ts +15 -0
  126. package/src/DateTimeInput/utils/getDisplayTime.ts +15 -0
  127. package/src/DateTimeInput/utils/index.ts +2 -0
  128. package/src/DateTimeInput/utils/parseTimeValue.ts +54 -0
  129. package/src/Drawer/Drawer.tsx +446 -0
  130. package/src/Drawer/atoms.ts +4 -0
  131. package/src/Drawer/components/DialogActions/DialogActions.tsx +33 -0
  132. package/src/Drawer/components/DialogContent/DialogContent.tsx +80 -0
  133. package/src/Drawer/components/DialogHeader/DialogHeader.tsx +68 -0
  134. package/src/EducationalPopover/EducationalPopover.tsx +174 -0
  135. package/src/FavoriteButton/FavoriteButton.tsx +64 -0
  136. package/src/FavoriteButton/components/IconOnlyFavoriteButton/IconOnlyFavoriteButton.tsx +80 -0
  137. package/src/FavoriteButton/components/LabeledAnimatedFavoriteButton/LabeledAnimatedFavoriteButton.tsx +179 -0
  138. package/src/FavoriteButton/components/LabeledFavoriteButton/LabeledFavoriteButton.tsx +71 -0
  139. package/src/FavoriteButton/components/SmallHeartStraightIcon/SmallHeartStraightIcon.tsx +14 -0
  140. package/src/FavoriteButton/hooks/useFavoriteButtonState.ts +30 -0
  141. package/src/FavoriteButton/index.ts +2 -0
  142. package/src/FavoriteButton/types/favoriteButton.ts +87 -0
  143. package/src/FeatureFlags/devTools/FeatureFlagDevToolsUI.tsx +226 -0
  144. package/src/FeatureFlags/devTools/getFeatureFlagCookieOverrides.ts +30 -0
  145. package/src/FeatureFlags/devTools/utils/cookies.ts +169 -0
  146. package/src/FeatureFlags/hooks/index.ts +2 -0
  147. package/src/FeatureFlags/hooks/useFeatureFlag.tsx +19 -0
  148. package/src/FeatureFlags/hooks/useFeatureFlags.tsx +15 -0
  149. package/src/FileUpload/components/FileCard/FileCard.tsx +50 -0
  150. package/src/FileUpload/components/FileDropzone/FileDropzone.tsx +221 -0
  151. package/src/FileUpload/components/FileDropzone/components/DropzoneContent/DropzoneContent.tsx +28 -0
  152. package/src/FileUpload/components/FileDropzone/components/DropzoneContent/DropzoneText.tsx +81 -0
  153. package/src/FileUpload/components/FileDropzone/components/FileDropzoneDebugger/FileDropzoneDebugger.tsx +40 -0
  154. package/src/FileUpload/components/FileDropzone/components/FileDropzoneDebugger/FileRejectionsDisplay.tsx +110 -0
  155. package/src/FileUpload/components/FileDropzoneOverlay/FileDropzoneOverlay.tsx +183 -0
  156. package/src/FileUpload/components/FileDropzoneOverlay/components/OverlayDropzoneContent.tsx +146 -0
  157. package/src/FileUpload/components/FileDropzoneOverlay/components/OverlayDropzoneDragText.tsx +42 -0
  158. package/src/FileUpload/components/FileDropzoneOverlay/styles.ts +79 -0
  159. package/src/FileUpload/components/FilePreviewList/FilePreviewList.tsx +251 -0
  160. package/src/FileUpload/components/FilePreviewList/virtualizerComponents/FilePreviewVirtualizedList/FilePreviewVirtualizedList.tsx +88 -0
  161. package/src/FileUpload/components/FileUpload/FileUpload.tsx +63 -0
  162. package/src/FileUpload/components/FileUploadCanvas/FileUploadCanvas.tsx +125 -0
  163. package/src/FileUpload/components/GridFileCard/GridFileCard.tsx +364 -0
  164. package/src/FileUpload/components/GridFileCard/utils/sortable.ts +48 -0
  165. package/src/FileUpload/components/ListFileCard/ListFileCard.tsx +259 -0
  166. package/src/FileUpload/components/types.ts +78 -0
  167. package/src/FileUpload/hooks/filePreview/useImageFilePreviewUrl.ts +62 -0
  168. package/src/FileUpload/hooks/index.ts +11 -0
  169. package/src/FileUpload/hooks/upload/useHandleDragEnter/useHandleDragEnter.ts +154 -0
  170. package/src/FileUpload/hooks/upload/useHandleDrop/createFileRejectionHelpers.ts +273 -0
  171. package/src/FileUpload/hooks/upload/useHandleDrop/useHandleDrop.ts +153 -0
  172. package/src/FileUpload/hooks/upload/useUploadAvailability/useUploadAvailability.ts +44 -0
  173. package/src/FileUpload/hooks/validation/createDropzoneValidator.ts +41 -0
  174. package/src/FileUpload/hooks/validation/useFileValidation.ts +25 -0
  175. package/src/FileUpload/hooks/validation/useFileValidationLogic.ts +107 -0
  176. package/src/FileUpload/hooks/validation/useValidationMessages.ts +92 -0
  177. package/src/FileUpload/hooks/validation/useValidationState.ts +171 -0
  178. package/src/FileUpload/index.ts +57 -0
  179. package/src/FileUpload/providers/FileUploadProvider.tsx +219 -0
  180. package/src/FileUpload/providers/UploadValidationProvider.tsx +159 -0
  181. package/src/FileUpload/testUtils/mockFilesAndImages.ts +64 -0
  182. package/src/FileUpload/testUtils/testUtils.ts +111 -0
  183. package/src/FileUpload/types/commonTypes.ts +267 -0
  184. package/src/FileUpload/types/index.ts +31 -0
  185. package/src/FileUpload/types/sharedTypes.ts +159 -0
  186. package/src/FileUpload/utils/constants.ts +79 -0
  187. package/src/FileUpload/utils/createMessageContext.ts +180 -0
  188. package/src/FileUpload/utils/getFileExtensionsFromAcceptedTypes.ts +73 -0
  189. package/src/FileUpload/utils/getFilePluralizationText.ts +68 -0
  190. package/src/FileUpload/utils/getMimeTypes.ts +26 -0
  191. package/src/FileUpload/utils/messageUtils.ts +41 -0
  192. package/src/FileUpload/utils/styles.ts +68 -0
  193. package/src/FormLabel/FormLabel.tsx +212 -0
  194. package/src/IconButton/IconButton.tsx +154 -0
  195. package/src/Icons/CreditCardIcon/CreditCardIcon.tsx +73 -0
  196. package/src/Icons/CreditCardIcon/cardIcons.tsx +270 -0
  197. package/src/Icons/IconBase.tsx +133 -0
  198. package/src/Icons/anyIcon.ts +3 -0
  199. package/src/Icons/generatedIcons/Archive.tsx +48 -0
  200. package/src/Icons/generatedIcons/ArrowClockwise.tsx +48 -0
  201. package/src/Icons/generatedIcons/ArrowDown.tsx +48 -0
  202. package/src/Icons/generatedIcons/ArrowLeft.tsx +48 -0
  203. package/src/Icons/generatedIcons/ArrowRight.tsx +48 -0
  204. package/src/Icons/generatedIcons/ArrowSquareOut.tsx +51 -0
  205. package/src/Icons/generatedIcons/ArrowSquareRight.tsx +51 -0
  206. package/src/Icons/generatedIcons/ArrowUp.tsx +48 -0
  207. package/src/Icons/generatedIcons/ArrowsCounterClockwise.tsx +48 -0
  208. package/src/Icons/generatedIcons/ArrowsLeftRight.tsx +48 -0
  209. package/src/Icons/generatedIcons/ArrowsOutCardinal.tsx +48 -0
  210. package/src/Icons/generatedIcons/Bank.tsx +48 -0
  211. package/src/Icons/generatedIcons/Bell.tsx +51 -0
  212. package/src/Icons/generatedIcons/BookBookmark.tsx +51 -0
  213. package/src/Icons/generatedIcons/BookmarksSimple.tsx +51 -0
  214. package/src/Icons/generatedIcons/Broadcast.tsx +48 -0
  215. package/src/Icons/generatedIcons/CalendarBlank.tsx +48 -0
  216. package/src/Icons/generatedIcons/CalendarStar.tsx +51 -0
  217. package/src/Icons/generatedIcons/Camera.tsx +51 -0
  218. package/src/Icons/generatedIcons/CaretDown.tsx +48 -0
  219. package/src/Icons/generatedIcons/CaretLeft.tsx +48 -0
  220. package/src/Icons/generatedIcons/CaretRight.tsx +48 -0
  221. package/src/Icons/generatedIcons/CaretUp.tsx +48 -0
  222. package/src/Icons/generatedIcons/Certificate.tsx +51 -0
  223. package/src/Icons/generatedIcons/ChartBar.tsx +48 -0
  224. package/src/Icons/generatedIcons/Check.tsx +51 -0
  225. package/src/Icons/generatedIcons/CheckCircle.tsx +48 -0
  226. package/src/Icons/generatedIcons/CirclesFour.tsx +51 -0
  227. package/src/Icons/generatedIcons/Clock.tsx +48 -0
  228. package/src/Icons/generatedIcons/ClockCountdown.tsx +48 -0
  229. package/src/Icons/generatedIcons/Close.tsx +51 -0
  230. package/src/Icons/generatedIcons/CloudArrowUp.tsx +51 -0
  231. package/src/Icons/generatedIcons/CloudWarning.tsx +51 -0
  232. package/src/Icons/generatedIcons/Code.tsx +48 -0
  233. package/src/Icons/generatedIcons/Compass.tsx +51 -0
  234. package/src/Icons/generatedIcons/Confetti.tsx +51 -0
  235. package/src/Icons/generatedIcons/Copy.tsx +48 -0
  236. package/src/Icons/generatedIcons/CornersOut.tsx +48 -0
  237. package/src/Icons/generatedIcons/CreditCard.tsx +48 -0
  238. package/src/Icons/generatedIcons/Crown.tsx +51 -0
  239. package/src/Icons/generatedIcons/CrownSimple.tsx +51 -0
  240. package/src/Icons/generatedIcons/CurrencyCircleDollar.tsx +48 -0
  241. package/src/Icons/generatedIcons/CurrencyDollarSimple.tsx +51 -0
  242. package/src/Icons/generatedIcons/Desktop.tsx +51 -0
  243. package/src/Icons/generatedIcons/Detective.tsx +51 -0
  244. package/src/Icons/generatedIcons/DotOutline.tsx +46 -0
  245. package/src/Icons/generatedIcons/DotsSixVertical.tsx +51 -0
  246. package/src/Icons/generatedIcons/DotsThreeOutline.tsx +51 -0
  247. package/src/Icons/generatedIcons/DotsThreeOutlineVertical.tsx +51 -0
  248. package/src/Icons/generatedIcons/DownloadSimple.tsx +51 -0
  249. package/src/Icons/generatedIcons/EnvelopeSimple.tsx +48 -0
  250. package/src/Icons/generatedIcons/Eraser.tsx +51 -0
  251. package/src/Icons/generatedIcons/Eye.tsx +51 -0
  252. package/src/Icons/generatedIcons/EyeSlash.tsx +51 -0
  253. package/src/Icons/generatedIcons/FacebookLogo.tsx +48 -0
  254. package/src/Icons/generatedIcons/FileArchive.tsx +48 -0
  255. package/src/Icons/generatedIcons/FileArrowDown.tsx +48 -0
  256. package/src/Icons/generatedIcons/FileCsv.tsx +48 -0
  257. package/src/Icons/generatedIcons/FilePdf.tsx +48 -0
  258. package/src/Icons/generatedIcons/FileText.tsx +48 -0
  259. package/src/Icons/generatedIcons/Files.tsx +51 -0
  260. package/src/Icons/generatedIcons/Fire.tsx +51 -0
  261. package/src/Icons/generatedIcons/Flag.tsx +51 -0
  262. package/src/Icons/generatedIcons/FlagBannerFold.tsx +48 -0
  263. package/src/Icons/generatedIcons/FloppyDisk.tsx +51 -0
  264. package/src/Icons/generatedIcons/Gauge.tsx +51 -0
  265. package/src/Icons/generatedIcons/Gavel.tsx +51 -0
  266. package/src/Icons/generatedIcons/Gear.tsx +51 -0
  267. package/src/Icons/generatedIcons/GlobeHemisphereWest.tsx +51 -0
  268. package/src/Icons/generatedIcons/GoogleLogo.tsx +48 -0
  269. package/src/Icons/generatedIcons/GridNine.tsx +51 -0
  270. package/src/Icons/generatedIcons/HandCoins.tsx +51 -0
  271. package/src/Icons/generatedIcons/HandbagSimple.tsx +51 -0
  272. package/src/Icons/generatedIcons/Headset.tsx +51 -0
  273. package/src/Icons/generatedIcons/HeartStraight.tsx +51 -0
  274. package/src/Icons/generatedIcons/HourglassLow.tsx +48 -0
  275. package/src/Icons/generatedIcons/House.tsx +51 -0
  276. package/src/Icons/generatedIcons/Image.tsx +51 -0
  277. package/src/Icons/generatedIcons/ImageSquare.tsx +51 -0
  278. package/src/Icons/generatedIcons/ImagesSquare.tsx +51 -0
  279. package/src/Icons/generatedIcons/Info.tsx +48 -0
  280. package/src/Icons/generatedIcons/InstagramLogo.tsx +51 -0
  281. package/src/Icons/generatedIcons/Lightning.tsx +48 -0
  282. package/src/Icons/generatedIcons/Link.tsx +51 -0
  283. package/src/Icons/generatedIcons/LinkedinLogo.tsx +51 -0
  284. package/src/Icons/generatedIcons/List.tsx +48 -0
  285. package/src/Icons/generatedIcons/Lock.tsx +51 -0
  286. package/src/Icons/generatedIcons/LockOpen.tsx +51 -0
  287. package/src/Icons/generatedIcons/MagnifyingGlass.tsx +48 -0
  288. package/src/Icons/generatedIcons/MapPin.tsx +51 -0
  289. package/src/Icons/generatedIcons/MapPinSimpleArea.tsx +48 -0
  290. package/src/Icons/generatedIcons/Medal.tsx +48 -0
  291. package/src/Icons/generatedIcons/Megaphone.tsx +48 -0
  292. package/src/Icons/generatedIcons/Minus.tsx +45 -0
  293. package/src/Icons/generatedIcons/Money.tsx +51 -0
  294. package/src/Icons/generatedIcons/Notches.tsx +48 -0
  295. package/src/Icons/generatedIcons/NotePencil.tsx +48 -0
  296. package/src/Icons/generatedIcons/Package.tsx +51 -0
  297. package/src/Icons/generatedIcons/PaintBrush.tsx +51 -0
  298. package/src/Icons/generatedIcons/PaperPlaneTilt.tsx +51 -0
  299. package/src/Icons/generatedIcons/Paperclip.tsx +51 -0
  300. package/src/Icons/generatedIcons/Pause.tsx +51 -0
  301. package/src/Icons/generatedIcons/PencilLine.tsx +51 -0
  302. package/src/Icons/generatedIcons/PencilRuler.tsx +51 -0
  303. package/src/Icons/generatedIcons/PencilSimple.tsx +51 -0
  304. package/src/Icons/generatedIcons/Phone.tsx +51 -0
  305. package/src/Icons/generatedIcons/PinterestLogo.tsx +51 -0
  306. package/src/Icons/generatedIcons/Play.tsx +51 -0
  307. package/src/Icons/generatedIcons/Plus.tsx +51 -0
  308. package/src/Icons/generatedIcons/PlusCircle.tsx +48 -0
  309. package/src/Icons/generatedIcons/Printer.tsx +51 -0
  310. package/src/Icons/generatedIcons/Question.tsx +48 -0
  311. package/src/Icons/generatedIcons/Receipt.tsx +51 -0
  312. package/src/Icons/generatedIcons/Rows.tsx +51 -0
  313. package/src/Icons/generatedIcons/SealCheck.tsx +51 -0
  314. package/src/Icons/generatedIcons/SelectionSlash.tsx +48 -0
  315. package/src/Icons/generatedIcons/ShareNetwork.tsx +51 -0
  316. package/src/Icons/generatedIcons/ShieldCheck.tsx +51 -0
  317. package/src/Icons/generatedIcons/ShieldStar.tsx +51 -0
  318. package/src/Icons/generatedIcons/ShoppingCart.tsx +48 -0
  319. package/src/Icons/generatedIcons/ShuffleAngular.tsx +48 -0
  320. package/src/Icons/generatedIcons/SidebarSimple.tsx +48 -0
  321. package/src/Icons/generatedIcons/SlidersHorizontal.tsx +51 -0
  322. package/src/Icons/generatedIcons/Smiley.tsx +48 -0
  323. package/src/Icons/generatedIcons/Sparkle.tsx +51 -0
  324. package/src/Icons/generatedIcons/SpinnerGap.tsx +48 -0
  325. package/src/Icons/generatedIcons/StackPlus.tsx +48 -0
  326. package/src/Icons/generatedIcons/Star.tsx +51 -0
  327. package/src/Icons/generatedIcons/Storefront.tsx +51 -0
  328. package/src/Icons/generatedIcons/Swap.tsx +51 -0
  329. package/src/Icons/generatedIcons/Tag.tsx +51 -0
  330. package/src/Icons/generatedIcons/ThumbsDown.tsx +48 -0
  331. package/src/Icons/generatedIcons/ThumbsUp.tsx +48 -0
  332. package/src/Icons/generatedIcons/Toolbox.tsx +48 -0
  333. package/src/Icons/generatedIcons/Trash.tsx +48 -0
  334. package/src/Icons/generatedIcons/TrendUp.tsx +48 -0
  335. package/src/Icons/generatedIcons/Trophy.tsx +51 -0
  336. package/src/Icons/generatedIcons/Truck.tsx +51 -0
  337. package/src/Icons/generatedIcons/UploadSimple.tsx +51 -0
  338. package/src/Icons/generatedIcons/User.tsx +48 -0
  339. package/src/Icons/generatedIcons/Users.tsx +48 -0
  340. package/src/Icons/generatedIcons/UsersThree.tsx +51 -0
  341. package/src/Icons/generatedIcons/VideoCamera.tsx +51 -0
  342. package/src/Icons/generatedIcons/Warning.tsx +51 -0
  343. package/src/Icons/generatedIcons/WarningCircle.tsx +48 -0
  344. package/src/Icons/generatedIcons/WifiHigh.tsx +51 -0
  345. package/src/Icons/generatedIcons/XCircle.tsx +48 -0
  346. package/src/Icons/generatedIcons/XLogo.tsx +48 -0
  347. package/src/Icons/generatedIcons/YoutubeLogo.tsx +51 -0
  348. package/src/Icons/importedIcons.ts +152 -0
  349. package/src/Icons/index.ts +149 -0
  350. package/src/Icons/socialIcons/appleSocialIcon.tsx +50 -0
  351. package/src/Icons/socialIcons/facebookSocialIcon.tsx +41 -0
  352. package/src/Icons/socialIcons/googleSocialIcon.tsx +134 -0
  353. package/src/ImageCluster/ImageCluster.tsx +125 -0
  354. package/src/ImageSlider/ImageSlider.tsx +582 -0
  355. package/src/ImageSlider/ImageSlider.types.ts +90 -0
  356. package/src/ImageSlider/components/IndexIndicator/IndexIndicator.tsx +21 -0
  357. package/src/ImageSlider/components/NavigationButtons/NavigationButtons.tsx +113 -0
  358. package/src/ImageSlider/components/ResponsiveImage/ResponsiveImage.tsx +114 -0
  359. package/src/ImageSlider/components/ResponsiveImage/index.ts +1 -0
  360. package/src/ImageSlider/components/Thumbnails/Thumbnails.tsx +184 -0
  361. package/src/ImageSlider/constants.ts +59 -0
  362. package/src/ImageSlider/hooks/index.ts +3 -0
  363. package/src/ImageSlider/hooks/useImageSlider.ts +57 -0
  364. package/src/ImageSlider/hooks/useImageSliderNavigation.ts +133 -0
  365. package/src/ImageSlider/hooks/useImageSliderScrollHandler.ts +171 -0
  366. package/src/ImageSlider/index.ts +3 -0
  367. package/src/ImageSlider/utils/imageOptimization.ts +97 -0
  368. package/src/ImageSlider/utils/index.ts +1 -0
  369. package/src/InlineNotification/InlineNotification.tsx +95 -0
  370. package/src/JumpMenu/JumpMenu.tsx +395 -0
  371. package/src/JumpMenu/components/JumpMenuItem/JumpMenuItem.tsx +62 -0
  372. package/src/JumpMenu/hooks/useContainerTracking.ts +171 -0
  373. package/src/JumpMenu/hooks/useIntersectionObserver.ts +77 -0
  374. package/src/JumpMenu/hooks/useKeyboardNavigation.ts +102 -0
  375. package/src/JumpMenu/hooks/useResizeObserver.ts +53 -0
  376. package/src/JumpMenu/hooks/useSectionObserver.ts +102 -0
  377. package/src/JumpMenu/index.ts +2 -0
  378. package/src/JumpMenu/types/index.ts +19 -0
  379. package/src/Loading/Loading.tsx +39 -0
  380. package/src/Loading/components/LoadingDot/LoadingDot.tsx +16 -0
  381. package/src/LoadingSpinner/LoadingSpinner.tsx +20 -0
  382. package/src/Menu/Menu.tsx +372 -0
  383. package/src/Menu/components/MenuDivider/MenuDivider.tsx +5 -0
  384. package/src/Menu/components/MenuItem/MenuItem.tsx +298 -0
  385. package/src/Menu/context/menuContext.tsx +20 -0
  386. package/src/Menu/hooks/useMenu.tsx +18 -0
  387. package/src/Menu/index.ts +3 -0
  388. package/src/Modal/ComposableModal.tsx +313 -0
  389. package/src/Modal/Modal.tsx +231 -0
  390. package/src/Modal/components/BackButton/BackButton.tsx +43 -0
  391. package/src/Modal/components/Backdrop/Backdrop.tsx +62 -0
  392. package/src/Modal/components/CloseButton/CloseButton.tsx +55 -0
  393. package/src/Modal/components/ModalActions/ModalActions.tsx +135 -0
  394. package/src/Modal/components/ModalContent/ModalContent.tsx +163 -0
  395. package/src/Modal/components/ModalHeader/ModalHeader.tsx +84 -0
  396. package/src/Modal/components/ModalHeader/hooks/useHeaderAnimation.tsx +49 -0
  397. package/src/Modal/components/ModalProgressSteps/ModalProgressSteps.tsx +26 -0
  398. package/src/Modal/components/ModalSubTitle/ModalSubTitle.tsx +29 -0
  399. package/src/Modal/components/ModalTitle/ModalTitle.tsx +22 -0
  400. package/src/Modal/components/PreventModalScroll/PreventModalScroll.tsx +106 -0
  401. package/src/Modal/components/index.ts +12 -0
  402. package/src/Modal/context.ts +33 -0
  403. package/src/Modal/hooks/useCloseModal.ts +133 -0
  404. package/src/NotificationBadge/NotificationBadge.tsx +34 -0
  405. package/src/Pagination/AdvancedPagination.tsx +48 -0
  406. package/src/Pagination/Pagination.tsx +216 -0
  407. package/src/Pagination/components/AdvancedPaginator/AdvancedPaginator.tsx +52 -0
  408. package/src/Pagination/components/AdvancedPaginator/components/PageSelect/PageSelect.tsx +43 -0
  409. package/src/Pagination/components/ItemCountDisplay/ItemCountDisplay.tsx +32 -0
  410. package/src/Pagination/components/ItemCountSelect/ItemCountSelect.tsx +33 -0
  411. package/src/Pagination/index.tsx +3 -0
  412. package/src/Pagination/paginationProvider.tsx +234 -0
  413. package/src/Pagination/utils.tsx +36 -0
  414. package/src/PhoneInput/PhoneInput.tsx +509 -0
  415. package/src/PhoneInput/useDropdownLogic.tsx +163 -0
  416. package/src/ProgressCircle/ProgressCircle.tsx +246 -0
  417. package/src/ProgressCircle/hooks/useProgressStatusTransitions.ts +49 -0
  418. package/src/ProgressCircle/utils/progressCircle.constants.ts +27 -0
  419. package/src/ProgressSteps/ProgressSteps.tsx +160 -0
  420. package/src/SaveConfetti/SaveConfetti.tsx +277 -0
  421. package/src/SaveConfetti/index.ts +2 -0
  422. package/src/SearchInput/SearchInput.tsx +236 -0
  423. package/src/SegmentedControl/SegmentedControl.tsx +111 -0
  424. package/src/SegmentedControl/SegmentedControlGroup.tsx +94 -0
  425. package/src/SegmentedControl/index.ts +4 -0
  426. package/src/Select/Select.tsx +154 -0
  427. package/src/Select/SelectAsync.tsx +13 -0
  428. package/src/Select/SelectAsyncCreatable.tsx +14 -0
  429. package/src/Select/SelectCreatable.tsx +12 -0
  430. package/src/Select/reexportedComponents.tsx +5 -0
  431. package/src/Select/selectComponents.tsx +306 -0
  432. package/src/Skeleton/Skeleton.tsx +13 -0
  433. package/src/SplitButton/SplitButton.tsx +298 -0
  434. package/src/SplitButton/SplitButtonTrigger.tsx +55 -0
  435. package/src/StarRating/StarRating.tsx +165 -0
  436. package/src/StarRating/components/StarComponent/StarComponent.tsx +44 -0
  437. package/src/Table/Table.tsx +474 -0
  438. package/src/Table/components/TableHeader/TableHeader.tsx +166 -0
  439. package/src/Table/components/TablePagination/TablePagination.tsx +18 -0
  440. package/src/Table/components/TablePagination/components/ItemCountDisplay/ItemCountDisplay.tsx +17 -0
  441. package/src/Table/components/TablePagination/components/ItemCountSelect/ItemCountSelect.tsx +31 -0
  442. package/src/Table/components/TablePagination/components/TablePaginator/TablePaginator.tsx +37 -0
  443. package/src/Table/components/TablePagination/components/TablePaginator/components/PageSelect/PageSelect.tsx +32 -0
  444. package/src/Table/components/TableRow/TableRows.tsx +147 -0
  445. package/src/Table/components/TableRow/components/TableRowCell/TableRowCell.tsx +49 -0
  446. package/src/Table/components/TableShadow/TableShadow.tsx +46 -0
  447. package/src/Table/index.ts +2 -0
  448. package/src/Table/sharedState.ts +30 -0
  449. package/src/Table/sharedStyles.ts +1 -0
  450. package/src/Table/types.ts +55 -0
  451. package/src/Tabs/Tabs.tsx +358 -0
  452. package/src/TextArea/TextArea.tsx +157 -0
  453. package/src/TextInput/TextInput.tsx +173 -0
  454. package/src/Toast/Toast.tsx +64 -0
  455. package/src/Toast/components/ToastContainer/ToastContainer.tsx +48 -0
  456. package/src/Toast/index.ts +2 -0
  457. package/src/Toast/types/role.ts +1 -0
  458. package/src/Toast/utils/getIcon.tsx +41 -0
  459. package/src/ToggleSwitch/ToggleSwitch.tsx +188 -0
  460. package/src/Tooltip/InfoIconTooltip.tsx +47 -0
  461. package/src/Tooltip/Tooltip.tsx +41 -0
  462. package/src/Typography/InlineButton/InlineButton.tsx +166 -0
  463. package/src/Typography/Links/Links.tsx +113 -0
  464. package/src/Typography/Text/Text.tsx +239 -0
  465. package/src/ViewMore/ViewMore.tsx +226 -0
  466. package/src/WebRTCPlayer/WebRTCPlayer.tsx +325 -0
  467. package/src/WebRTCPlayer/adaptor/NativeWebRTCAdaptor.ts +588 -0
  468. package/src/WebRTCPlayer/hooks/useWebRTCStream.ts +571 -0
  469. package/src/WebRTCPlayer/index.ts +22 -0
  470. package/src/WebRTCPlayer/types.ts +95 -0
  471. package/src/breakpoints/index.tsx +1 -0
  472. package/src/breakpoints/utils.tsx +50 -0
  473. package/src/declarations.d.ts +7 -0
  474. package/src/grid/gridHighlighter.tsx +83 -0
  475. package/src/grid/index.ts +3 -0
  476. package/src/grid/pageGrid.tsx +37 -0
  477. package/src/grid/useSubGridCSS.tsx +214 -0
  478. package/src/hooks/useHorizontalScrollFade.ts +44 -0
  479. package/src/hooks/usePrevious.ts +14 -0
  480. package/src/index.ts +351 -0
  481. package/src/intl/index.ts +4 -0
  482. package/src/intl/utils.ts +67 -0
  483. package/src/mixins/horizontalScrollFadeMixin.ts +56 -0
  484. package/src/mixins/index.ts +18 -0
  485. package/src/mixins/propMixins.ts +389 -0
  486. package/src/providers/createContextProvider.ts +22 -0
  487. package/src/providers/designSystemProvider.tsx +218 -0
  488. package/src/providers/errorBoundaryProvider.tsx +179 -0
  489. package/src/providers/featureFlagProvider.tsx +18 -0
  490. package/src/providers/gridSizeProvider.tsx +23 -0
  491. package/src/providers/index.ts +12 -0
  492. package/src/providers/linkProvider.tsx +32 -0
  493. package/src/providers/normalize.tsx +93 -0
  494. package/src/providers/targets/DatePickerTarget.tsx +10 -0
  495. package/src/providers/targets/ModalTarget.tsx +14 -0
  496. package/src/providers/targets/TimePickerTarget.tsx +10 -0
  497. package/src/providers/themeContext.tsx +24 -0
  498. package/src/providers/windowSizeProvider.tsx +125 -0
  499. package/src/spacing/index.ts +1 -0
  500. package/src/spacing/spacing.ts +11 -0
  501. package/src/utils/countriesWithISOCodes.ts +1419 -0
  502. package/src/utils/dateTimeFormat.ts +257 -0
  503. package/src/utils/effectEventListener.ts +11 -0
  504. package/src/utils/formatFileSize.ts +18 -0
  505. package/src/utils/isClientSide.ts +1 -0
  506. package/src/utils/keepTransition.ts +15 -0
  507. package/src/utils/nodeEnv.ts +9 -0
  508. package/src/utils/smoothScrollTo.ts +47 -0
  509. package/src/utils/utilityTypes.ts +13 -0
@@ -0,0 +1,395 @@
1
+ import { cn } from '@evolve.ui/theme-system';
2
+ import { HTMLProps, MouseEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
+
4
+ import { useHorizontalScrollFadeMixin } from '../mixins/horizontalScrollFadeMixin';
5
+ import { useWindowIsMobile } from '../providers/windowSizeProvider';
6
+ import { Caption } from '../Typography/Text/Text';
7
+ import { isClientSide } from '../utils/isClientSide';
8
+ import { JumpMenuItem } from './components/JumpMenuItem/JumpMenuItem';
9
+ import { useContainerTracking } from './hooks/useContainerTracking';
10
+ import { useKeyboardNavigation } from './hooks/useKeyboardNavigation';
11
+ import { useSectionObserver } from './hooks/useSectionObserver';
12
+ import { JumpMenuItem as JumpMenuItemType } from './types';
13
+
14
+ /**
15
+ * Props for the JumpMenu component
16
+ */
17
+ type Props = HTMLProps<HTMLElement> & {
18
+ /** Custom aria-label for the navigation (defaults to 'Jump to section') */
19
+ ariaLabel?: string;
20
+ /** Additional CSS classes for the menu container */
21
+ className?: string;
22
+ /** CSS selector for the container element that defines the scope of fixed positioning behavior */
23
+ containerSelector?: string;
24
+ /** Array of menu items to display in the jump navigation */
25
+ items: JumpMenuItemType[];
26
+ /** Callback when active section changes via scroll or user interaction */
27
+ onActiveChange?: (activeId: string | null) => void;
28
+ /** Additional CSS classes for the outer container of the menu */
29
+ outerContainerClassName?: string;
30
+ /** Scroll offset in pixels to account for sticky headers when navigating to sections (defaults to 0) */
31
+ scrollOffset?: number;
32
+ /** Scroll offset in pixels for mobile viewports (overrides scrollOffset on mobile, defaults to scrollOffset value) */
33
+ scrollOffsetMobile?: number;
34
+ };
35
+
36
+ /**
37
+ * JumpMenu component for horizontal scrollable navigation between page sections
38
+ *
39
+ * Features:
40
+ * - Horizontal scrolling with fade indicators on overflow
41
+ * - Automatic section highlighting based on scroll position
42
+ * - Keyboard navigation (Arrow keys, Home, End)
43
+ * - Smooth scrolling to target sections
44
+ * - Accessibility compliant with ARIA labels and roles
45
+ * - Fixed positioning with container visibility tracking
46
+ *
47
+ * @param ariaLabel - Custom aria-label for the navigation (defaults to 'Jump to section')
48
+ * @param className - Additional CSS classes for the menu container
49
+ * @param containerSelector - CSS selector for the container element that defines the scope of fixed positioning behavior
50
+ * @param items - Array of menu items to display - each item should have an id and either target or href
51
+ * @param onActiveChange - Callback when active section changes via scroll or user interaction
52
+ * @param outerContainerClassName - Additional CSS classes for the outer container of the menu
53
+ * @param scrollOffset - Scroll offset in pixels to account for sticky headers when navigating to sections (defaults to 0)
54
+ * @param scrollOffsetMobile - Scroll offset in pixels for mobile viewports (overrides scrollOffset on mobile, defaults to scrollOffset value)
55
+ *
56
+ *
57
+ * @example
58
+ * ```tsx
59
+ * const menuItems = [
60
+ * { id: 'overview', label: 'Overview', href: '#overview-section' },
61
+ * { id: 'details', label: 'Details', href: '#details-section' },
62
+ * ];
63
+ *
64
+ * <div id="container">
65
+ * <JumpMenu
66
+ * items={menuItems}
67
+ * containerSelector="#container"
68
+ * onActiveChange={(activeId) => console.log('Active section:', activeId)}
69
+ * scrollOffset={80} // Optional: Account for 80px sticky header
70
+ * scrollOffsetMobile={120} // Optional: Account for larger mobile header
71
+ * />
72
+ * <section id="overview-section">Overview content</section>
73
+ * <section id="details-section">Details content</section>
74
+ * </div>
75
+ * ```
76
+ */
77
+ export const JumpMenu = ({
78
+ ariaLabel = 'Jump to section',
79
+ className,
80
+ containerSelector,
81
+ items,
82
+ onActiveChange,
83
+ outerContainerClassName = '',
84
+ scrollOffset = 0,
85
+ scrollOffsetMobile,
86
+ ...htmlProps
87
+ }: Props) => {
88
+ // Track user-initiated actions with timestamp to ignore subsequent intersection observer events
89
+ const userActionIgnoreDuration = 1000;
90
+ const lastUserActionRef = useRef<number>(0);
91
+
92
+ const [activeItemId, setActiveItemId] = useState<string | null>(
93
+ items.find((item) => item.isActive)?.id || items[0]?.id || null
94
+ );
95
+ const menuRef = useRef<HTMLDivElement>(null);
96
+ const scrollContainerRef = useRef<HTMLDivElement>(null);
97
+ const horizontalScrollFadeProps = useHorizontalScrollFadeMixin(0);
98
+ const [navBackgroundColor, setNavBackgroundColor] = useState<string>('rgb(255, 255, 255)');
99
+
100
+ // Use the container tracking hook for visibility and width management
101
+ const { isContainerVisible, menuHeight, menuWidth } = useContainerTracking({
102
+ containerSelector,
103
+ menuRef,
104
+ });
105
+
106
+ // Determine if container top has passed viewport top (need to check position separately from visibility)
107
+ const [containerTopPassed, setContainerTopPassed] = useState(false);
108
+
109
+ // Track pending scroll when clicking item before menu becomes fixed
110
+ const pendingScrollItemRef = useRef<string | null>(null);
111
+
112
+ useEffect(() => {
113
+ if (!containerSelector || !isClientSide) {
114
+ return;
115
+ }
116
+
117
+ const containerElement = document.querySelector(containerSelector);
118
+ if (!containerElement) {
119
+ return;
120
+ }
121
+
122
+ const checkPosition = () => {
123
+ const rect = containerElement.getBoundingClientRect();
124
+ setContainerTopPassed(rect.top <= 0);
125
+ };
126
+
127
+ checkPosition();
128
+ window.addEventListener('scroll', checkPosition, { passive: true });
129
+ return () => window.removeEventListener('scroll', checkPosition);
130
+ }, [containerSelector]);
131
+
132
+ const isMobile = useWindowIsMobile();
133
+
134
+ /**
135
+ * Gets the appropriate scroll offset based on viewport size
136
+ * @returns The scroll offset to use for the current viewport
137
+ */
138
+ const getScrollOffset = useCallback(() => {
139
+ return isMobile && scrollOffsetMobile !== undefined ? scrollOffsetMobile : scrollOffset;
140
+ }, [scrollOffset, scrollOffsetMobile, isMobile]);
141
+
142
+ /**
143
+ * Scrolls the specified menu item into view within the horizontal scroll container
144
+ * Only scrolls when menu is in fixed position to prevent viewport shifts
145
+ * @param itemId - The ID of the menu item to scroll into view
146
+ * @param inline - Scroll alignment: 'center' shows neighbors, 'nearest' minimal scroll
147
+ */
148
+ const scrollActiveItemIntoView = useCallback((itemId: string, inline: 'center' | 'nearest' = 'nearest') => {
149
+ const activeElement = scrollContainerRef.current?.querySelector(
150
+ `[data-item-id="${itemId}"]`
151
+ ) as HTMLElement | null;
152
+
153
+ if (activeElement) {
154
+ activeElement.scrollIntoView({
155
+ behavior: 'smooth',
156
+ block: 'nearest',
157
+ inline,
158
+ });
159
+ }
160
+ }, []);
161
+
162
+ // When menu becomes fixed and we have a pending scroll, execute it
163
+ useEffect(() => {
164
+ if (containerTopPassed && pendingScrollItemRef.current) {
165
+ scrollActiveItemIntoView(pendingScrollItemRef.current, 'center');
166
+ pendingScrollItemRef.current = null;
167
+ }
168
+ }, [containerTopPassed, scrollActiveItemIntoView]);
169
+
170
+ // Update active item when external state changes
171
+ useEffect(() => {
172
+ const externalActiveItem = items.find((item) => item.isActive);
173
+ if (externalActiveItem && externalActiveItem.id !== activeItemId) {
174
+ setActiveItemId(externalActiveItem.id);
175
+ }
176
+ }, [items, activeItemId]);
177
+
178
+ /**
179
+ * Handles active section changes from the intersection observer
180
+ * Ignores updates that occur shortly after user interactions to prevent conflicts
181
+ * @param sectionId - The ID of the section that became active
182
+ */
183
+ const handleActiveChange = useCallback(
184
+ (sectionId: string) => {
185
+ // Skip if this is a scroll-based update and we recently had a user action
186
+ const timeSinceLastUserAction = Date.now() - lastUserActionRef.current;
187
+ if (timeSinceLastUserAction < userActionIgnoreDuration) {
188
+ return;
189
+ }
190
+
191
+ if (sectionId !== activeItemId) {
192
+ setActiveItemId(sectionId);
193
+ onActiveChange?.(sectionId);
194
+ // Auto-scroll with 'center' to show neighboring items (only when fixed)
195
+ if (containerTopPassed) {
196
+ scrollActiveItemIntoView(sectionId, 'center');
197
+ }
198
+ }
199
+ },
200
+ [activeItemId, onActiveChange, userActionIgnoreDuration, scrollActiveItemIntoView, containerTopPassed]
201
+ );
202
+
203
+ // Prepare sections for the observer
204
+ const sections = useMemo(
205
+ () =>
206
+ items
207
+ .filter((item) => item.target || item.href)
208
+ .map((item) => ({
209
+ id: item.id,
210
+ selector: item.target ? `#${item.target}` : item.href!,
211
+ })),
212
+ [items]
213
+ );
214
+
215
+ // Use modern IntersectionObserver for section detection
216
+ useSectionObserver(sections, handleActiveChange);
217
+
218
+ // Handle keyboard navigation with the dedicated hook
219
+ const { handleKeyDown } = useKeyboardNavigation({
220
+ activeItemId,
221
+ containerRef: menuRef,
222
+ getItemId: (item: JumpMenuItemType) => item.id,
223
+ items,
224
+ lastUserActionRef,
225
+ onActiveChange: (itemId: string) => {
226
+ setActiveItemId(itemId);
227
+ onActiveChange?.(itemId);
228
+ },
229
+ scrollItemIntoView: scrollActiveItemIntoView,
230
+ });
231
+
232
+ /**
233
+ * Handles menu item click events
234
+ * Updates active state, calls custom onClick handler, and navigates to target section
235
+ * @param item - The clicked menu item
236
+ * @param event - The mouse event
237
+ */
238
+ const handleItemClick = useCallback(
239
+ (item: JumpMenuItemType, event: MouseEvent) => {
240
+ // Mark this as a user-initiated action
241
+ lastUserActionRef.current = Date.now();
242
+
243
+ // Scroll the clicked menu item into view FIRST, using 'center' to show neighbors
244
+ // Only scroll horizontally when menu is in fixed position to prevent viewport shifts
245
+ if (containerTopPassed) {
246
+ scrollActiveItemIntoView(item.id, 'center');
247
+ } else {
248
+ // Store pending scroll to execute once menu becomes fixed
249
+ pendingScrollItemRef.current = item.id;
250
+ }
251
+
252
+ setActiveItemId(item.id);
253
+ onActiveChange?.(item.id);
254
+ item.onClick?.(item.id);
255
+
256
+ // Navigate to section if target or href is provided
257
+ const targetSelector = item.target ? `#${item.target}` : item.href;
258
+
259
+ if (targetSelector) {
260
+ // Always prevent default since we're using buttons now
261
+ event.preventDefault();
262
+
263
+ // Handle navigation manually
264
+ const targetElement = document.querySelector(targetSelector);
265
+ if (targetElement) {
266
+ const offset = getScrollOffset();
267
+
268
+ if (offset > 0) {
269
+ // Calculate position with offset
270
+ const elementPosition = targetElement.getBoundingClientRect().top + window.pageYOffset;
271
+ const offsetPosition = elementPosition - offset;
272
+
273
+ window.scrollTo({
274
+ behavior: 'smooth',
275
+ top: offsetPosition,
276
+ });
277
+ } else {
278
+ // Use default scroll behavior when no offset
279
+ targetElement.scrollIntoView({
280
+ behavior: 'smooth',
281
+ block: 'start',
282
+ });
283
+ }
284
+ }
285
+ }
286
+ },
287
+ [onActiveChange, getScrollOffset, scrollActiveItemIntoView, containerTopPassed]
288
+ );
289
+
290
+ // Simple positioning logic - no complex state management needed
291
+ // Fixed when we've scrolled past container top AND container hasn't scrolled past bottom
292
+ const shouldUseFixedPosition = containerSelector && containerTopPassed && isContainerVisible;
293
+
294
+ // Extract background color from nav element for dynamic gradient overlays
295
+ useEffect(() => {
296
+ if (menuRef.current && isClientSide) {
297
+ const computedStyle = window.getComputedStyle(menuRef.current);
298
+ const backgroundColor = computedStyle.backgroundColor;
299
+ if (backgroundColor && backgroundColor !== 'rgba(0, 0, 0, 0)' && backgroundColor !== 'transparent') {
300
+ setNavBackgroundColor(backgroundColor);
301
+ }
302
+ }
303
+ }, []);
304
+
305
+ return (
306
+ <div className={cn(outerContainerClassName)}>
307
+ {/* Simple placeholder to maintain layout when menu becomes fixed or is fading out */}
308
+ {(shouldUseFixedPosition || !isContainerVisible) && (
309
+ <div
310
+ aria-hidden="true"
311
+ style={{
312
+ height: menuHeight,
313
+ }}
314
+ />
315
+ )}
316
+
317
+ <nav
318
+ aria-label={ariaLabel}
319
+ className={cn(
320
+ 'z-10 w-full bg-background-primary transition-opacity duration-300',
321
+ {
322
+ 'fixed top-0': shouldUseFixedPosition || !isContainerVisible, // Keep fixed during fade-out
323
+ 'pointer-events-none': !isContainerVisible, // Disable interaction when hidden
324
+ relative: !shouldUseFixedPosition && isContainerVisible,
325
+ },
326
+ className
327
+ )}
328
+ ref={menuRef}
329
+ style={{
330
+ opacity: isContainerVisible ? 1 : 0,
331
+ width: shouldUseFixedPosition || !isContainerVisible ? `${menuWidth}px` : undefined,
332
+ ...htmlProps.style,
333
+ }}
334
+ {...htmlProps}
335
+ >
336
+ <div className="flex w-full flex-col gap-xs py-xs">
337
+ <Caption
338
+ // z-[11] is to prevent the caption from being hidden by fade
339
+ className="z-[11] w-full px-xs"
340
+ color="secondary"
341
+ >
342
+ {ariaLabel}
343
+ </Caption>
344
+ {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions -- Keyboard events bubble from focusable menu items */}
345
+ <div
346
+ className="scrollbar-hide flex w-full overflow-x-auto px-xs py-3xs"
347
+ onKeyDown={handleKeyDown}
348
+ ref={(element) => {
349
+ horizontalScrollFadeProps.ref(element);
350
+ scrollContainerRef.current = element;
351
+ menuRef.current = element;
352
+ }}
353
+ >
354
+ {/* Left fade overlay */}
355
+ <div
356
+ className={cn(
357
+ 'pointer-events-none absolute bottom-0 left-0 top-0 z-10 w-[48px] transition-opacity duration-300 ease-in-out',
358
+ {
359
+ 'opacity-0': !horizontalScrollFadeProps.shouldShowLeftFade,
360
+ 'opacity-100': horizontalScrollFadeProps.shouldShowLeftFade,
361
+ }
362
+ )}
363
+ style={{
364
+ background: `linear-gradient(to right, ${navBackgroundColor}, transparent)`,
365
+ }}
366
+ />
367
+
368
+ {/* Right fade overlay */}
369
+ <div
370
+ className={cn(
371
+ 'pointer-events-none absolute bottom-0 right-0 top-0 z-10 w-[48px] transition-opacity duration-300 ease-in-out',
372
+ {
373
+ 'opacity-0': !horizontalScrollFadeProps.shouldShowRightFade,
374
+ 'opacity-100': horizontalScrollFadeProps.shouldShowRightFade,
375
+ }
376
+ )}
377
+ style={{
378
+ background: `linear-gradient(to left, ${navBackgroundColor}, transparent)`,
379
+ }}
380
+ />
381
+
382
+ {items.map((item) => (
383
+ <JumpMenuItem
384
+ {...item}
385
+ activeItemId={activeItemId}
386
+ handleItemClick={handleItemClick}
387
+ key={item.id}
388
+ />
389
+ ))}
390
+ </div>
391
+ </div>
392
+ </nav>
393
+ </div>
394
+ );
395
+ };
@@ -0,0 +1,62 @@
1
+ import { cn } from '@evolve.ui/theme-system';
2
+
3
+ import { JumpMenuItem as JumpMenuItemData } from '../../types';
4
+
5
+ /**
6
+ * Single jump menu item configuration with click handler
7
+ */
8
+ export type Props<T extends JumpMenuItemData = JumpMenuItemData> = T & {
9
+ /** Unique identifier for the menu item */
10
+ activeItemId: string | null;
11
+ /** Additional CSS classes for the individual item */
12
+ className?: string;
13
+ /** Handle item click function */
14
+ handleItemClick: (item: T, event: React.MouseEvent) => void;
15
+ };
16
+
17
+ export const JumpMenuItem = ({
18
+ activeItemId,
19
+ className,
20
+ handleItemClick,
21
+ href,
22
+ id,
23
+ isActive: isActiveProp,
24
+ label,
25
+ target,
26
+ ...restProps
27
+ }: Props) => {
28
+ const isActive = isActiveProp || id === activeItemId;
29
+
30
+ return (
31
+ <button
32
+ aria-current={isActive ? 'page' : undefined}
33
+ className={cn(
34
+ // Base styles - use consistent typography class for both states
35
+ 'hui-text-body-secondary relative whitespace-nowrap rounded-md px-xs py-2xs last:mr-sm [&:not(:last-child)]:mr-xs',
36
+ // Default state (Selected=Off, Hover=Off, Focused=Off)
37
+ 'text-text-secondary',
38
+ // Focus styles - inset focus ring to stay within button dimensions
39
+ 'focus-visible:shadow-[inset_0_0_0_4px_rgb(var(--color-focus-primary)/0.50)] focus-visible:outline-none',
40
+ // Interactive states
41
+ 'cursor-pointer',
42
+ // Hover states - completely remove hover on touch devices, only show on pointer devices
43
+ '[&:hover]:[@media(pointer:fine)]:bg-background-hover',
44
+ !isActive && '[&:hover]:[@media(pointer:fine)]:text-text-primary',
45
+ // Touch/Active states for mobile - brief visual feedback on tap
46
+ !isActive && 'active:bg-background-hover active:text-text-primary active:duration-75',
47
+ // Selected states (Selected=On) - using ring for border without affecting dimensions
48
+ isActive && 'bg-background-primary font-bold text-text-primary ring-1 ring-inset ring-border-selected',
49
+ className
50
+ )}
51
+ data-item-id={id}
52
+ data-target={target || href?.replace('#', '')}
53
+ key={id}
54
+ onClick={(event) => {
55
+ handleItemClick({ href, id, isActive: isActiveProp, label, target, ...restProps }, event);
56
+ }}
57
+ type="button"
58
+ >
59
+ {label}
60
+ </button>
61
+ );
62
+ };
@@ -0,0 +1,171 @@
1
+ import { useEffect, useMemo, useRef, useState } from 'react';
2
+
3
+ import { isClientSide } from '../../utils/isClientSide';
4
+
5
+ /**
6
+ * Configuration for container tracking
7
+ */
8
+ type ContainerTrackingConfig = {
9
+ /** CSS selector for the container element */
10
+ containerSelector?: string;
11
+ /** Reference to the menu element for height tracking */
12
+ menuRef?: React.RefObject<HTMLElement | null>;
13
+ };
14
+
15
+ /**
16
+ * Return type for the container tracking hook
17
+ */
18
+ type UseContainerTrackingReturn = {
19
+ /** Whether the container is currently visible */
20
+ isContainerVisible: boolean;
21
+ /** Current height of the menu element in pixels */
22
+ menuHeight: number;
23
+ /** Current width of the container in pixels */
24
+ menuWidth: number;
25
+ };
26
+
27
+ /**
28
+ * Hook that tracks container visibility and dimensions for fixed positioning behavior
29
+ *
30
+ * This hook provides:
31
+ * - Simple container visibility tracking via scroll detection
32
+ * - Container width tracking for maintaining consistent sizing when position changes
33
+ * - Menu height tracking for placeholder div
34
+ * - Automatic event listener management with cleanup
35
+ * - SSR safety by checking client-side rendering
36
+ *
37
+ * @param config - Configuration object for container tracking
38
+ * @returns Object containing visibility state and dimensions
39
+ *
40
+ * @example
41
+ * ```tsx
42
+ * const { isContainerVisible, menuWidth, menuHeight } = useContainerTracking({
43
+ * containerSelector: '#main-container',
44
+ * menuRef
45
+ * });
46
+ * ```
47
+ */
48
+ export const useContainerTracking = ({
49
+ containerSelector,
50
+ menuRef,
51
+ }: ContainerTrackingConfig): UseContainerTrackingReturn => {
52
+ const [isContainerVisible, setIsContainerVisible] = useState<boolean>(true);
53
+ const [menuWidth, setMenuWidth] = useState<number>(0);
54
+ const [menuHeight, setMenuHeight] = useState<number>(0);
55
+ const resizeObserverRef = useRef<ResizeObserver | null>(null);
56
+
57
+ /**
58
+ * Sets up simple scroll-based visibility tracking for the container
59
+ * Menu becomes fixed when container top reaches viewport top and stays fixed until container scrolls past
60
+ */
61
+ useEffect(() => {
62
+ // We don't want to run this in SSR since we are using the window object
63
+ if (!isClientSide) {
64
+ return;
65
+ }
66
+
67
+ if (!containerSelector) {
68
+ setIsContainerVisible(true);
69
+ return;
70
+ }
71
+
72
+ const containerElement = document.querySelector(containerSelector);
73
+ if (!containerElement) {
74
+ setIsContainerVisible(true);
75
+ return;
76
+ }
77
+
78
+ const onScroll = () => {
79
+ const rect = containerElement.getBoundingClientRect();
80
+
81
+ // Menu should be visible when:
82
+ // 1. Before we scroll to container (rect.top > 0) - show in relative position
83
+ // 2. While scrolling through container (rect.top <= 0 && rect.bottom > 0) - show in fixed position
84
+ // 3. After scrolling past container (rect.bottom <= 0) - hide completely
85
+ const shouldBeVisible = rect.bottom > 0; // Visible as long as container hasn't scrolled completely past
86
+
87
+ setIsContainerVisible(shouldBeVisible);
88
+ };
89
+
90
+ // Initial check
91
+ onScroll();
92
+
93
+ // Listen to scroll events with passive flag for performance
94
+ window.addEventListener('scroll', onScroll, { passive: true });
95
+
96
+ return () => {
97
+ window.removeEventListener('scroll', onScroll);
98
+ };
99
+ }, [containerSelector]);
100
+
101
+ /**
102
+ * Updates menu width and height for fixed positioning
103
+ * This ensures the fixed menu maintains the same dimensions as its static position
104
+ * Uses ResizeObserver for precise, real-time dimension tracking
105
+ */
106
+ useEffect(() => {
107
+ // We don't want to run this in SSR since we are using the window object
108
+ if (!isClientSide) {
109
+ return;
110
+ }
111
+
112
+ const updateContainerWidth = () => {
113
+ if (containerSelector) {
114
+ const containerElement = document.querySelector(containerSelector);
115
+ if (containerElement) {
116
+ const containerRect = containerElement.getBoundingClientRect();
117
+ setMenuWidth(containerRect.width);
118
+ }
119
+ }
120
+ };
121
+
122
+ const updateMenuHeight = () => {
123
+ if (menuRef?.current) {
124
+ // Use offsetHeight for more accurate measurement including borders and padding
125
+ const height = menuRef.current.offsetHeight;
126
+ if (height > 0) {
127
+ setMenuHeight(height);
128
+ }
129
+ }
130
+ };
131
+
132
+ // Set up ResizeObserver for menu element height tracking
133
+ if (menuRef?.current && 'ResizeObserver' in window) {
134
+ resizeObserverRef.current = new ResizeObserver((entries) => {
135
+ for (const entry of entries) {
136
+ // Use contentRect height for reliable measurement
137
+ const height = entry.contentRect.height;
138
+ if (height > 0) {
139
+ setMenuHeight(height);
140
+ }
141
+ }
142
+ });
143
+
144
+ resizeObserverRef.current.observe(menuRef.current);
145
+ }
146
+
147
+ // Initial measurements
148
+ updateContainerWidth();
149
+ updateMenuHeight();
150
+
151
+ // Listen for window resize for container width updates
152
+ window.addEventListener('resize', updateContainerWidth);
153
+
154
+ return () => {
155
+ window.removeEventListener('resize', updateContainerWidth);
156
+ if (resizeObserverRef.current) {
157
+ resizeObserverRef.current.disconnect();
158
+ resizeObserverRef.current = null;
159
+ }
160
+ };
161
+ }, [containerSelector, menuRef]);
162
+
163
+ return useMemo(
164
+ () => ({
165
+ isContainerVisible,
166
+ menuHeight,
167
+ menuWidth,
168
+ }),
169
+ [isContainerVisible, menuHeight, menuWidth]
170
+ );
171
+ };