@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.
- package/evolve-ui.entries.json +556 -0
- package/fileUpload/testUtils/mockFilesAndImages.d.cts +3 -3
- package/fileUpload/testUtils/mockFilesAndImages.d.cts.map +1 -1
- package/fileUpload/testUtils/mockFilesAndImages.d.mts +3 -3
- package/fileUpload/testUtils/mockFilesAndImages.d.mts.map +1 -1
- package/fileUpload/testUtils/testUtils.d.cts +1 -1
- package/fileUpload/testUtils/testUtils.d.cts.map +1 -1
- package/fileUpload/testUtils/testUtils.d.mts +1 -1
- package/fileUpload/testUtils/testUtils.d.mts.map +1 -1
- package/package.json +2 -2
- package/src/Accordion/Accordion.tsx +233 -0
- package/src/AddressDisplay/AddressDisplay.tsx +43 -0
- package/src/AddressDisplay/components/addressComponents.tsx +111 -0
- package/src/AddressDisplay/components/addressField.tsx +25 -0
- package/src/AddressDisplay/components/addressSection.tsx +8 -0
- package/src/AddressDisplay/components/getCountryValue.tsx +31 -0
- package/src/AddressDisplay/types.ts +26 -0
- package/src/AutomatedCarousel/AutomatedCarousel.tsx +163 -0
- package/src/AutomatedCarousel/automatedCarousel.types.ts +7 -0
- package/src/AutomatedCarousel/components/CarouselProgressBar/CarouselProgressBar.tsx +139 -0
- package/src/AutomatedCarousel/components/CarouselProgressBar/components/CarouselProgressBarUnit/CarouselProgressBarUnit.tsx +165 -0
- package/src/Badge/Badge.tsx +104 -0
- package/src/Badge/Badge.types.ts +58 -0
- package/src/Badge/ItemBadge.tsx +97 -0
- package/src/Badge/LiveStatusBadge.tsx +93 -0
- package/src/BannerNotification/BannerNotification.tsx +157 -0
- package/src/BannerNotification/components/BannerNotificationSkeleton.tsx +39 -0
- package/src/BannerNotification/components/CalloutIcon/BannerIcon.tsx +48 -0
- package/src/BannerNotification/utils/getRandomTooltipId.ts +3 -0
- package/src/BottomSheet/BottomSheet.tsx +476 -0
- package/src/BottomSheet/components/BottomSheetBackdrop/BottomSheetBackdrop.tsx +47 -0
- package/src/BottomSheet/components/BottomSheetContentArea/BottomSheetContentArea.tsx +92 -0
- package/src/BottomSheet/components/BottomSheetOverlay/BottomSheetOverlayTranslate3d.tsx +196 -0
- package/src/BottomSheet/components/SheetDescription/SheetDescription.tsx +22 -0
- package/src/BottomSheet/components/SheetTitle/SheetTitle.tsx +21 -0
- package/src/BottomSheet/components/index.tsx +5 -0
- package/src/BottomSheet/hooks/index.tsx +13 -0
- package/src/BottomSheet/hooks/useAriaHider.tsx +91 -0
- package/src/BottomSheet/hooks/useBottomSheetServices.tsx +224 -0
- package/src/BottomSheet/hooks/useDragHandler.tsx +282 -0
- package/src/BottomSheet/hooks/useFocusTrap.tsx +113 -0
- package/src/BottomSheet/hooks/useLayoutEffect.tsx +4 -0
- package/src/BottomSheet/hooks/useOptimizedResizeObserver.tsx +94 -0
- package/src/BottomSheet/hooks/useOptimizedScrollState.tsx +87 -0
- package/src/BottomSheet/hooks/useReady.tsx +34 -0
- package/src/BottomSheet/hooks/useReducedMotion.tsx +22 -0
- package/src/BottomSheet/hooks/useScrollLock.tsx +143 -0
- package/src/BottomSheet/hooks/useSnapPoints.tsx +355 -0
- package/src/BottomSheet/hooks/useSpring.tsx +47 -0
- package/src/BottomSheet/hooks/useSpringInterpolationsTranslate3d.tsx +101 -0
- package/src/BottomSheet/index.tsx +237 -0
- package/src/BottomSheet/state/atoms.ts +147 -0
- package/src/BottomSheet/state/useBottomSheetStateMachine.ts +246 -0
- package/src/BottomSheet/types.ts +172 -0
- package/src/BottomSheet/utils.ts +65 -0
- package/src/Breadcrumbs/Breadcrumbs.tsx +126 -0
- package/src/Button/Button.tsx +164 -0
- package/src/Button/Button.types.ts +80 -0
- package/src/Button/buttonColorClasses.ts +53 -0
- package/src/Callout/Callout.tsx +136 -0
- package/src/Callout/Callout.types.ts +29 -0
- package/src/Callout/components/CalloutIcon/CalloutIcon.tsx +56 -0
- package/src/Card/CardGrid.tsx +263 -0
- package/src/Card/SingleCard.tsx +22 -0
- package/src/Card/cardFactory.tsx +176 -0
- package/src/Card/components/createBadge.tsx +34 -0
- package/src/Card/components/createFavoriteButton.tsx +40 -0
- package/src/Card/components/createImage.tsx +64 -0
- package/src/Card/components/createInfo.tsx +84 -0
- package/src/Card/components/createName.tsx +63 -0
- package/src/Card/components/createPriceStatus.tsx +100 -0
- package/src/Card/components/types.ts +4 -0
- package/src/Card/hooks/useCardVisibilityTracking.ts +82 -0
- package/src/Card/sharedProps.ts +12 -0
- package/src/Card/types.ts +62 -0
- package/src/Carousel/Carousel.tsx +513 -0
- package/src/Carousel/Carousel.types.ts +43 -0
- package/src/Carousel/Carousel.utils.ts +63 -0
- package/src/Carousel/components/DotButton/DotButton.tsx +42 -0
- package/src/Carousel/components/NavigationButtons/NavigationButtons.tsx +77 -0
- package/src/Carousel/components/TitleSection/TitleSection.tsx +61 -0
- package/src/Carousel/components/TitleSection/components/SubHeaderLeft/SubHeaderLeft.tsx +53 -0
- package/src/Carousel/components/TitleSection/components/Title/Title.tsx +46 -0
- package/src/Carousel/index.ts +2 -0
- package/src/Carousel/testUtils.ts +10 -0
- package/src/Chips/Chip.tsx +153 -0
- package/src/Chips/ChipGroup.tsx +173 -0
- package/src/Chips/SuggestionChip.tsx +15 -0
- package/src/Chips/chipTypes.ts +113 -0
- package/src/Chips/index.ts +4 -0
- package/src/ChoiceListItem/Checkbox.tsx +69 -0
- package/src/ChoiceListItem/Radio.tsx +61 -0
- package/src/ChoiceListItem/choiceListItem.tsx +99 -0
- package/src/ChoiceListItem/common.tsx +148 -0
- package/src/ChoiceListItem/index.ts +3 -0
- package/src/Collapsible/Collapsible.tsx +58 -0
- package/src/Confetti/Confetti.tsx +270 -0
- package/src/Confetti/index.ts +2 -0
- package/src/ContentPager/ContentPager.tsx +189 -0
- package/src/ContentPager/components/Page.tsx +24 -0
- package/src/CookieConsent/components/CookieCategoryRow/CookieCategoryRow.tsx +30 -0
- package/src/CookieConsent/components/CookieConsent/CookieConsent.tsx +74 -0
- package/src/CookieConsent/components/CookieConsentBanner/CookieConsentBanner.tsx +51 -0
- package/src/CookieConsent/components/CookieConsentModal/CookieConsentModal.tsx +64 -0
- package/src/CookieConsent/hooks/useCookieConsent.ts +170 -0
- package/src/CookieConsent/hooks/useCookieConsentState.ts +142 -0
- package/src/CookieConsent/index.ts +16 -0
- package/src/CookieConsent/types/cookieConsent.types.ts +79 -0
- package/src/CookieConsent/types/index.ts +7 -0
- package/src/Countdown/Countdown.tsx +161 -0
- package/src/Countdown/Countdown.types.ts +4 -0
- package/src/Countdown/hooks/useGetCountdown.ts +103 -0
- package/src/DateTimeInput/dateInput/DateInput.tsx +199 -0
- package/src/DateTimeInput/datePicker/DatePicker.tsx +138 -0
- package/src/DateTimeInput/datePicker/components/calendar/Calendar.tsx +72 -0
- package/src/DateTimeInput/datePicker/index.ts +2 -0
- package/src/DateTimeInput/timeInput/TimeInput.tsx +128 -0
- package/src/DateTimeInput/timePicker/TimePicker.tsx +118 -0
- package/src/DateTimeInput/timePicker/components/TimePopover/AmPmSwitch.tsx +103 -0
- package/src/DateTimeInput/timePicker/components/TimePopover/TimeFieldInput.tsx +26 -0
- package/src/DateTimeInput/timePicker/components/TimePopover/TimePopover.tsx +84 -0
- package/src/DateTimeInput/timePicker/components/TimePopover/TimePopover.utils.ts +67 -0
- package/src/DateTimeInput/timePicker/components/TimePopover/TimePopoverActions.tsx +26 -0
- package/src/DateTimeInput/timePicker/index.ts +2 -0
- package/src/DateTimeInput/utils/getDisplayDate.ts +15 -0
- package/src/DateTimeInput/utils/getDisplayTime.ts +15 -0
- package/src/DateTimeInput/utils/index.ts +2 -0
- package/src/DateTimeInput/utils/parseTimeValue.ts +54 -0
- package/src/Drawer/Drawer.tsx +446 -0
- package/src/Drawer/atoms.ts +4 -0
- package/src/Drawer/components/DialogActions/DialogActions.tsx +33 -0
- package/src/Drawer/components/DialogContent/DialogContent.tsx +80 -0
- package/src/Drawer/components/DialogHeader/DialogHeader.tsx +68 -0
- package/src/EducationalPopover/EducationalPopover.tsx +174 -0
- package/src/FavoriteButton/FavoriteButton.tsx +64 -0
- package/src/FavoriteButton/components/IconOnlyFavoriteButton/IconOnlyFavoriteButton.tsx +80 -0
- package/src/FavoriteButton/components/LabeledAnimatedFavoriteButton/LabeledAnimatedFavoriteButton.tsx +179 -0
- package/src/FavoriteButton/components/LabeledFavoriteButton/LabeledFavoriteButton.tsx +71 -0
- package/src/FavoriteButton/components/SmallHeartStraightIcon/SmallHeartStraightIcon.tsx +14 -0
- package/src/FavoriteButton/hooks/useFavoriteButtonState.ts +30 -0
- package/src/FavoriteButton/index.ts +2 -0
- package/src/FavoriteButton/types/favoriteButton.ts +87 -0
- package/src/FeatureFlags/devTools/FeatureFlagDevToolsUI.tsx +226 -0
- package/src/FeatureFlags/devTools/getFeatureFlagCookieOverrides.ts +30 -0
- package/src/FeatureFlags/devTools/utils/cookies.ts +169 -0
- package/src/FeatureFlags/hooks/index.ts +2 -0
- package/src/FeatureFlags/hooks/useFeatureFlag.tsx +19 -0
- package/src/FeatureFlags/hooks/useFeatureFlags.tsx +15 -0
- package/src/FileUpload/components/FileCard/FileCard.tsx +50 -0
- package/src/FileUpload/components/FileDropzone/FileDropzone.tsx +221 -0
- package/src/FileUpload/components/FileDropzone/components/DropzoneContent/DropzoneContent.tsx +28 -0
- package/src/FileUpload/components/FileDropzone/components/DropzoneContent/DropzoneText.tsx +81 -0
- package/src/FileUpload/components/FileDropzone/components/FileDropzoneDebugger/FileDropzoneDebugger.tsx +40 -0
- package/src/FileUpload/components/FileDropzone/components/FileDropzoneDebugger/FileRejectionsDisplay.tsx +110 -0
- package/src/FileUpload/components/FileDropzoneOverlay/FileDropzoneOverlay.tsx +183 -0
- package/src/FileUpload/components/FileDropzoneOverlay/components/OverlayDropzoneContent.tsx +146 -0
- package/src/FileUpload/components/FileDropzoneOverlay/components/OverlayDropzoneDragText.tsx +42 -0
- package/src/FileUpload/components/FileDropzoneOverlay/styles.ts +79 -0
- package/src/FileUpload/components/FilePreviewList/FilePreviewList.tsx +251 -0
- package/src/FileUpload/components/FilePreviewList/virtualizerComponents/FilePreviewVirtualizedList/FilePreviewVirtualizedList.tsx +88 -0
- package/src/FileUpload/components/FileUpload/FileUpload.tsx +63 -0
- package/src/FileUpload/components/FileUploadCanvas/FileUploadCanvas.tsx +125 -0
- package/src/FileUpload/components/GridFileCard/GridFileCard.tsx +364 -0
- package/src/FileUpload/components/GridFileCard/utils/sortable.ts +48 -0
- package/src/FileUpload/components/ListFileCard/ListFileCard.tsx +259 -0
- package/src/FileUpload/components/types.ts +78 -0
- package/src/FileUpload/hooks/filePreview/useImageFilePreviewUrl.ts +62 -0
- package/src/FileUpload/hooks/index.ts +11 -0
- package/src/FileUpload/hooks/upload/useHandleDragEnter/useHandleDragEnter.ts +154 -0
- package/src/FileUpload/hooks/upload/useHandleDrop/createFileRejectionHelpers.ts +273 -0
- package/src/FileUpload/hooks/upload/useHandleDrop/useHandleDrop.ts +153 -0
- package/src/FileUpload/hooks/upload/useUploadAvailability/useUploadAvailability.ts +44 -0
- package/src/FileUpload/hooks/validation/createDropzoneValidator.ts +41 -0
- package/src/FileUpload/hooks/validation/useFileValidation.ts +25 -0
- package/src/FileUpload/hooks/validation/useFileValidationLogic.ts +107 -0
- package/src/FileUpload/hooks/validation/useValidationMessages.ts +92 -0
- package/src/FileUpload/hooks/validation/useValidationState.ts +171 -0
- package/src/FileUpload/index.ts +57 -0
- package/src/FileUpload/providers/FileUploadProvider.tsx +219 -0
- package/src/FileUpload/providers/UploadValidationProvider.tsx +159 -0
- package/src/FileUpload/testUtils/mockFilesAndImages.ts +64 -0
- package/src/FileUpload/testUtils/testUtils.ts +111 -0
- package/src/FileUpload/types/commonTypes.ts +267 -0
- package/src/FileUpload/types/index.ts +31 -0
- package/src/FileUpload/types/sharedTypes.ts +159 -0
- package/src/FileUpload/utils/constants.ts +79 -0
- package/src/FileUpload/utils/createMessageContext.ts +180 -0
- package/src/FileUpload/utils/getFileExtensionsFromAcceptedTypes.ts +73 -0
- package/src/FileUpload/utils/getFilePluralizationText.ts +68 -0
- package/src/FileUpload/utils/getMimeTypes.ts +26 -0
- package/src/FileUpload/utils/messageUtils.ts +41 -0
- package/src/FileUpload/utils/styles.ts +68 -0
- package/src/FormLabel/FormLabel.tsx +212 -0
- package/src/IconButton/IconButton.tsx +154 -0
- package/src/Icons/CreditCardIcon/CreditCardIcon.tsx +73 -0
- package/src/Icons/CreditCardIcon/cardIcons.tsx +270 -0
- package/src/Icons/IconBase.tsx +133 -0
- package/src/Icons/anyIcon.ts +3 -0
- package/src/Icons/generatedIcons/Archive.tsx +48 -0
- package/src/Icons/generatedIcons/ArrowClockwise.tsx +48 -0
- package/src/Icons/generatedIcons/ArrowDown.tsx +48 -0
- package/src/Icons/generatedIcons/ArrowLeft.tsx +48 -0
- package/src/Icons/generatedIcons/ArrowRight.tsx +48 -0
- package/src/Icons/generatedIcons/ArrowSquareOut.tsx +51 -0
- package/src/Icons/generatedIcons/ArrowSquareRight.tsx +51 -0
- package/src/Icons/generatedIcons/ArrowUp.tsx +48 -0
- package/src/Icons/generatedIcons/ArrowsCounterClockwise.tsx +48 -0
- package/src/Icons/generatedIcons/ArrowsLeftRight.tsx +48 -0
- package/src/Icons/generatedIcons/ArrowsOutCardinal.tsx +48 -0
- package/src/Icons/generatedIcons/Bank.tsx +48 -0
- package/src/Icons/generatedIcons/Bell.tsx +51 -0
- package/src/Icons/generatedIcons/BookBookmark.tsx +51 -0
- package/src/Icons/generatedIcons/BookmarksSimple.tsx +51 -0
- package/src/Icons/generatedIcons/Broadcast.tsx +48 -0
- package/src/Icons/generatedIcons/CalendarBlank.tsx +48 -0
- package/src/Icons/generatedIcons/CalendarStar.tsx +51 -0
- package/src/Icons/generatedIcons/Camera.tsx +51 -0
- package/src/Icons/generatedIcons/CaretDown.tsx +48 -0
- package/src/Icons/generatedIcons/CaretLeft.tsx +48 -0
- package/src/Icons/generatedIcons/CaretRight.tsx +48 -0
- package/src/Icons/generatedIcons/CaretUp.tsx +48 -0
- package/src/Icons/generatedIcons/Certificate.tsx +51 -0
- package/src/Icons/generatedIcons/ChartBar.tsx +48 -0
- package/src/Icons/generatedIcons/Check.tsx +51 -0
- package/src/Icons/generatedIcons/CheckCircle.tsx +48 -0
- package/src/Icons/generatedIcons/CirclesFour.tsx +51 -0
- package/src/Icons/generatedIcons/Clock.tsx +48 -0
- package/src/Icons/generatedIcons/ClockCountdown.tsx +48 -0
- package/src/Icons/generatedIcons/Close.tsx +51 -0
- package/src/Icons/generatedIcons/CloudArrowUp.tsx +51 -0
- package/src/Icons/generatedIcons/CloudWarning.tsx +51 -0
- package/src/Icons/generatedIcons/Code.tsx +48 -0
- package/src/Icons/generatedIcons/Compass.tsx +51 -0
- package/src/Icons/generatedIcons/Confetti.tsx +51 -0
- package/src/Icons/generatedIcons/Copy.tsx +48 -0
- package/src/Icons/generatedIcons/CornersOut.tsx +48 -0
- package/src/Icons/generatedIcons/CreditCard.tsx +48 -0
- package/src/Icons/generatedIcons/Crown.tsx +51 -0
- package/src/Icons/generatedIcons/CrownSimple.tsx +51 -0
- package/src/Icons/generatedIcons/CurrencyCircleDollar.tsx +48 -0
- package/src/Icons/generatedIcons/CurrencyDollarSimple.tsx +51 -0
- package/src/Icons/generatedIcons/Desktop.tsx +51 -0
- package/src/Icons/generatedIcons/Detective.tsx +51 -0
- package/src/Icons/generatedIcons/DotOutline.tsx +46 -0
- package/src/Icons/generatedIcons/DotsSixVertical.tsx +51 -0
- package/src/Icons/generatedIcons/DotsThreeOutline.tsx +51 -0
- package/src/Icons/generatedIcons/DotsThreeOutlineVertical.tsx +51 -0
- package/src/Icons/generatedIcons/DownloadSimple.tsx +51 -0
- package/src/Icons/generatedIcons/EnvelopeSimple.tsx +48 -0
- package/src/Icons/generatedIcons/Eraser.tsx +51 -0
- package/src/Icons/generatedIcons/Eye.tsx +51 -0
- package/src/Icons/generatedIcons/EyeSlash.tsx +51 -0
- package/src/Icons/generatedIcons/FacebookLogo.tsx +48 -0
- package/src/Icons/generatedIcons/FileArchive.tsx +48 -0
- package/src/Icons/generatedIcons/FileArrowDown.tsx +48 -0
- package/src/Icons/generatedIcons/FileCsv.tsx +48 -0
- package/src/Icons/generatedIcons/FilePdf.tsx +48 -0
- package/src/Icons/generatedIcons/FileText.tsx +48 -0
- package/src/Icons/generatedIcons/Files.tsx +51 -0
- package/src/Icons/generatedIcons/Fire.tsx +51 -0
- package/src/Icons/generatedIcons/Flag.tsx +51 -0
- package/src/Icons/generatedIcons/FlagBannerFold.tsx +48 -0
- package/src/Icons/generatedIcons/FloppyDisk.tsx +51 -0
- package/src/Icons/generatedIcons/Gauge.tsx +51 -0
- package/src/Icons/generatedIcons/Gavel.tsx +51 -0
- package/src/Icons/generatedIcons/Gear.tsx +51 -0
- package/src/Icons/generatedIcons/GlobeHemisphereWest.tsx +51 -0
- package/src/Icons/generatedIcons/GoogleLogo.tsx +48 -0
- package/src/Icons/generatedIcons/GridNine.tsx +51 -0
- package/src/Icons/generatedIcons/HandCoins.tsx +51 -0
- package/src/Icons/generatedIcons/HandbagSimple.tsx +51 -0
- package/src/Icons/generatedIcons/Headset.tsx +51 -0
- package/src/Icons/generatedIcons/HeartStraight.tsx +51 -0
- package/src/Icons/generatedIcons/HourglassLow.tsx +48 -0
- package/src/Icons/generatedIcons/House.tsx +51 -0
- package/src/Icons/generatedIcons/Image.tsx +51 -0
- package/src/Icons/generatedIcons/ImageSquare.tsx +51 -0
- package/src/Icons/generatedIcons/ImagesSquare.tsx +51 -0
- package/src/Icons/generatedIcons/Info.tsx +48 -0
- package/src/Icons/generatedIcons/InstagramLogo.tsx +51 -0
- package/src/Icons/generatedIcons/Lightning.tsx +48 -0
- package/src/Icons/generatedIcons/Link.tsx +51 -0
- package/src/Icons/generatedIcons/LinkedinLogo.tsx +51 -0
- package/src/Icons/generatedIcons/List.tsx +48 -0
- package/src/Icons/generatedIcons/Lock.tsx +51 -0
- package/src/Icons/generatedIcons/LockOpen.tsx +51 -0
- package/src/Icons/generatedIcons/MagnifyingGlass.tsx +48 -0
- package/src/Icons/generatedIcons/MapPin.tsx +51 -0
- package/src/Icons/generatedIcons/MapPinSimpleArea.tsx +48 -0
- package/src/Icons/generatedIcons/Medal.tsx +48 -0
- package/src/Icons/generatedIcons/Megaphone.tsx +48 -0
- package/src/Icons/generatedIcons/Minus.tsx +45 -0
- package/src/Icons/generatedIcons/Money.tsx +51 -0
- package/src/Icons/generatedIcons/Notches.tsx +48 -0
- package/src/Icons/generatedIcons/NotePencil.tsx +48 -0
- package/src/Icons/generatedIcons/Package.tsx +51 -0
- package/src/Icons/generatedIcons/PaintBrush.tsx +51 -0
- package/src/Icons/generatedIcons/PaperPlaneTilt.tsx +51 -0
- package/src/Icons/generatedIcons/Paperclip.tsx +51 -0
- package/src/Icons/generatedIcons/Pause.tsx +51 -0
- package/src/Icons/generatedIcons/PencilLine.tsx +51 -0
- package/src/Icons/generatedIcons/PencilRuler.tsx +51 -0
- package/src/Icons/generatedIcons/PencilSimple.tsx +51 -0
- package/src/Icons/generatedIcons/Phone.tsx +51 -0
- package/src/Icons/generatedIcons/PinterestLogo.tsx +51 -0
- package/src/Icons/generatedIcons/Play.tsx +51 -0
- package/src/Icons/generatedIcons/Plus.tsx +51 -0
- package/src/Icons/generatedIcons/PlusCircle.tsx +48 -0
- package/src/Icons/generatedIcons/Printer.tsx +51 -0
- package/src/Icons/generatedIcons/Question.tsx +48 -0
- package/src/Icons/generatedIcons/Receipt.tsx +51 -0
- package/src/Icons/generatedIcons/Rows.tsx +51 -0
- package/src/Icons/generatedIcons/SealCheck.tsx +51 -0
- package/src/Icons/generatedIcons/SelectionSlash.tsx +48 -0
- package/src/Icons/generatedIcons/ShareNetwork.tsx +51 -0
- package/src/Icons/generatedIcons/ShieldCheck.tsx +51 -0
- package/src/Icons/generatedIcons/ShieldStar.tsx +51 -0
- package/src/Icons/generatedIcons/ShoppingCart.tsx +48 -0
- package/src/Icons/generatedIcons/ShuffleAngular.tsx +48 -0
- package/src/Icons/generatedIcons/SidebarSimple.tsx +48 -0
- package/src/Icons/generatedIcons/SlidersHorizontal.tsx +51 -0
- package/src/Icons/generatedIcons/Smiley.tsx +48 -0
- package/src/Icons/generatedIcons/Sparkle.tsx +51 -0
- package/src/Icons/generatedIcons/SpinnerGap.tsx +48 -0
- package/src/Icons/generatedIcons/StackPlus.tsx +48 -0
- package/src/Icons/generatedIcons/Star.tsx +51 -0
- package/src/Icons/generatedIcons/Storefront.tsx +51 -0
- package/src/Icons/generatedIcons/Swap.tsx +51 -0
- package/src/Icons/generatedIcons/Tag.tsx +51 -0
- package/src/Icons/generatedIcons/ThumbsDown.tsx +48 -0
- package/src/Icons/generatedIcons/ThumbsUp.tsx +48 -0
- package/src/Icons/generatedIcons/Toolbox.tsx +48 -0
- package/src/Icons/generatedIcons/Trash.tsx +48 -0
- package/src/Icons/generatedIcons/TrendUp.tsx +48 -0
- package/src/Icons/generatedIcons/Trophy.tsx +51 -0
- package/src/Icons/generatedIcons/Truck.tsx +51 -0
- package/src/Icons/generatedIcons/UploadSimple.tsx +51 -0
- package/src/Icons/generatedIcons/User.tsx +48 -0
- package/src/Icons/generatedIcons/Users.tsx +48 -0
- package/src/Icons/generatedIcons/UsersThree.tsx +51 -0
- package/src/Icons/generatedIcons/VideoCamera.tsx +51 -0
- package/src/Icons/generatedIcons/Warning.tsx +51 -0
- package/src/Icons/generatedIcons/WarningCircle.tsx +48 -0
- package/src/Icons/generatedIcons/WifiHigh.tsx +51 -0
- package/src/Icons/generatedIcons/XCircle.tsx +48 -0
- package/src/Icons/generatedIcons/XLogo.tsx +48 -0
- package/src/Icons/generatedIcons/YoutubeLogo.tsx +51 -0
- package/src/Icons/importedIcons.ts +152 -0
- package/src/Icons/index.ts +149 -0
- package/src/Icons/socialIcons/appleSocialIcon.tsx +50 -0
- package/src/Icons/socialIcons/facebookSocialIcon.tsx +41 -0
- package/src/Icons/socialIcons/googleSocialIcon.tsx +134 -0
- package/src/ImageCluster/ImageCluster.tsx +125 -0
- package/src/ImageSlider/ImageSlider.tsx +582 -0
- package/src/ImageSlider/ImageSlider.types.ts +90 -0
- package/src/ImageSlider/components/IndexIndicator/IndexIndicator.tsx +21 -0
- package/src/ImageSlider/components/NavigationButtons/NavigationButtons.tsx +113 -0
- package/src/ImageSlider/components/ResponsiveImage/ResponsiveImage.tsx +114 -0
- package/src/ImageSlider/components/ResponsiveImage/index.ts +1 -0
- package/src/ImageSlider/components/Thumbnails/Thumbnails.tsx +184 -0
- package/src/ImageSlider/constants.ts +59 -0
- package/src/ImageSlider/hooks/index.ts +3 -0
- package/src/ImageSlider/hooks/useImageSlider.ts +57 -0
- package/src/ImageSlider/hooks/useImageSliderNavigation.ts +133 -0
- package/src/ImageSlider/hooks/useImageSliderScrollHandler.ts +171 -0
- package/src/ImageSlider/index.ts +3 -0
- package/src/ImageSlider/utils/imageOptimization.ts +97 -0
- package/src/ImageSlider/utils/index.ts +1 -0
- package/src/InlineNotification/InlineNotification.tsx +95 -0
- package/src/JumpMenu/JumpMenu.tsx +395 -0
- package/src/JumpMenu/components/JumpMenuItem/JumpMenuItem.tsx +62 -0
- package/src/JumpMenu/hooks/useContainerTracking.ts +171 -0
- package/src/JumpMenu/hooks/useIntersectionObserver.ts +77 -0
- package/src/JumpMenu/hooks/useKeyboardNavigation.ts +102 -0
- package/src/JumpMenu/hooks/useResizeObserver.ts +53 -0
- package/src/JumpMenu/hooks/useSectionObserver.ts +102 -0
- package/src/JumpMenu/index.ts +2 -0
- package/src/JumpMenu/types/index.ts +19 -0
- package/src/Loading/Loading.tsx +39 -0
- package/src/Loading/components/LoadingDot/LoadingDot.tsx +16 -0
- package/src/LoadingSpinner/LoadingSpinner.tsx +20 -0
- package/src/Menu/Menu.tsx +372 -0
- package/src/Menu/components/MenuDivider/MenuDivider.tsx +5 -0
- package/src/Menu/components/MenuItem/MenuItem.tsx +298 -0
- package/src/Menu/context/menuContext.tsx +20 -0
- package/src/Menu/hooks/useMenu.tsx +18 -0
- package/src/Menu/index.ts +3 -0
- package/src/Modal/ComposableModal.tsx +313 -0
- package/src/Modal/Modal.tsx +231 -0
- package/src/Modal/components/BackButton/BackButton.tsx +43 -0
- package/src/Modal/components/Backdrop/Backdrop.tsx +62 -0
- package/src/Modal/components/CloseButton/CloseButton.tsx +55 -0
- package/src/Modal/components/ModalActions/ModalActions.tsx +135 -0
- package/src/Modal/components/ModalContent/ModalContent.tsx +163 -0
- package/src/Modal/components/ModalHeader/ModalHeader.tsx +84 -0
- package/src/Modal/components/ModalHeader/hooks/useHeaderAnimation.tsx +49 -0
- package/src/Modal/components/ModalProgressSteps/ModalProgressSteps.tsx +26 -0
- package/src/Modal/components/ModalSubTitle/ModalSubTitle.tsx +29 -0
- package/src/Modal/components/ModalTitle/ModalTitle.tsx +22 -0
- package/src/Modal/components/PreventModalScroll/PreventModalScroll.tsx +106 -0
- package/src/Modal/components/index.ts +12 -0
- package/src/Modal/context.ts +33 -0
- package/src/Modal/hooks/useCloseModal.ts +133 -0
- package/src/NotificationBadge/NotificationBadge.tsx +34 -0
- package/src/Pagination/AdvancedPagination.tsx +48 -0
- package/src/Pagination/Pagination.tsx +216 -0
- package/src/Pagination/components/AdvancedPaginator/AdvancedPaginator.tsx +52 -0
- package/src/Pagination/components/AdvancedPaginator/components/PageSelect/PageSelect.tsx +43 -0
- package/src/Pagination/components/ItemCountDisplay/ItemCountDisplay.tsx +32 -0
- package/src/Pagination/components/ItemCountSelect/ItemCountSelect.tsx +33 -0
- package/src/Pagination/index.tsx +3 -0
- package/src/Pagination/paginationProvider.tsx +234 -0
- package/src/Pagination/utils.tsx +36 -0
- package/src/PhoneInput/PhoneInput.tsx +509 -0
- package/src/PhoneInput/useDropdownLogic.tsx +163 -0
- package/src/ProgressCircle/ProgressCircle.tsx +246 -0
- package/src/ProgressCircle/hooks/useProgressStatusTransitions.ts +49 -0
- package/src/ProgressCircle/utils/progressCircle.constants.ts +27 -0
- package/src/ProgressSteps/ProgressSteps.tsx +160 -0
- package/src/SaveConfetti/SaveConfetti.tsx +277 -0
- package/src/SaveConfetti/index.ts +2 -0
- package/src/SearchInput/SearchInput.tsx +236 -0
- package/src/SegmentedControl/SegmentedControl.tsx +111 -0
- package/src/SegmentedControl/SegmentedControlGroup.tsx +94 -0
- package/src/SegmentedControl/index.ts +4 -0
- package/src/Select/Select.tsx +154 -0
- package/src/Select/SelectAsync.tsx +13 -0
- package/src/Select/SelectAsyncCreatable.tsx +14 -0
- package/src/Select/SelectCreatable.tsx +12 -0
- package/src/Select/reexportedComponents.tsx +5 -0
- package/src/Select/selectComponents.tsx +306 -0
- package/src/Skeleton/Skeleton.tsx +13 -0
- package/src/SplitButton/SplitButton.tsx +298 -0
- package/src/SplitButton/SplitButtonTrigger.tsx +55 -0
- package/src/StarRating/StarRating.tsx +165 -0
- package/src/StarRating/components/StarComponent/StarComponent.tsx +44 -0
- package/src/Table/Table.tsx +474 -0
- package/src/Table/components/TableHeader/TableHeader.tsx +166 -0
- package/src/Table/components/TablePagination/TablePagination.tsx +18 -0
- package/src/Table/components/TablePagination/components/ItemCountDisplay/ItemCountDisplay.tsx +17 -0
- package/src/Table/components/TablePagination/components/ItemCountSelect/ItemCountSelect.tsx +31 -0
- package/src/Table/components/TablePagination/components/TablePaginator/TablePaginator.tsx +37 -0
- package/src/Table/components/TablePagination/components/TablePaginator/components/PageSelect/PageSelect.tsx +32 -0
- package/src/Table/components/TableRow/TableRows.tsx +147 -0
- package/src/Table/components/TableRow/components/TableRowCell/TableRowCell.tsx +49 -0
- package/src/Table/components/TableShadow/TableShadow.tsx +46 -0
- package/src/Table/index.ts +2 -0
- package/src/Table/sharedState.ts +30 -0
- package/src/Table/sharedStyles.ts +1 -0
- package/src/Table/types.ts +55 -0
- package/src/Tabs/Tabs.tsx +358 -0
- package/src/TextArea/TextArea.tsx +157 -0
- package/src/TextInput/TextInput.tsx +173 -0
- package/src/Toast/Toast.tsx +64 -0
- package/src/Toast/components/ToastContainer/ToastContainer.tsx +48 -0
- package/src/Toast/index.ts +2 -0
- package/src/Toast/types/role.ts +1 -0
- package/src/Toast/utils/getIcon.tsx +41 -0
- package/src/ToggleSwitch/ToggleSwitch.tsx +188 -0
- package/src/Tooltip/InfoIconTooltip.tsx +47 -0
- package/src/Tooltip/Tooltip.tsx +41 -0
- package/src/Typography/InlineButton/InlineButton.tsx +166 -0
- package/src/Typography/Links/Links.tsx +113 -0
- package/src/Typography/Text/Text.tsx +239 -0
- package/src/ViewMore/ViewMore.tsx +226 -0
- package/src/WebRTCPlayer/WebRTCPlayer.tsx +325 -0
- package/src/WebRTCPlayer/adaptor/NativeWebRTCAdaptor.ts +588 -0
- package/src/WebRTCPlayer/hooks/useWebRTCStream.ts +571 -0
- package/src/WebRTCPlayer/index.ts +22 -0
- package/src/WebRTCPlayer/types.ts +95 -0
- package/src/breakpoints/index.tsx +1 -0
- package/src/breakpoints/utils.tsx +50 -0
- package/src/declarations.d.ts +7 -0
- package/src/grid/gridHighlighter.tsx +83 -0
- package/src/grid/index.ts +3 -0
- package/src/grid/pageGrid.tsx +37 -0
- package/src/grid/useSubGridCSS.tsx +214 -0
- package/src/hooks/useHorizontalScrollFade.ts +44 -0
- package/src/hooks/usePrevious.ts +14 -0
- package/src/index.ts +351 -0
- package/src/intl/index.ts +4 -0
- package/src/intl/utils.ts +67 -0
- package/src/mixins/horizontalScrollFadeMixin.ts +56 -0
- package/src/mixins/index.ts +18 -0
- package/src/mixins/propMixins.ts +389 -0
- package/src/providers/createContextProvider.ts +22 -0
- package/src/providers/designSystemProvider.tsx +218 -0
- package/src/providers/errorBoundaryProvider.tsx +179 -0
- package/src/providers/featureFlagProvider.tsx +18 -0
- package/src/providers/gridSizeProvider.tsx +23 -0
- package/src/providers/index.ts +12 -0
- package/src/providers/linkProvider.tsx +32 -0
- package/src/providers/normalize.tsx +93 -0
- package/src/providers/targets/DatePickerTarget.tsx +10 -0
- package/src/providers/targets/ModalTarget.tsx +14 -0
- package/src/providers/targets/TimePickerTarget.tsx +10 -0
- package/src/providers/themeContext.tsx +24 -0
- package/src/providers/windowSizeProvider.tsx +125 -0
- package/src/spacing/index.ts +1 -0
- package/src/spacing/spacing.ts +11 -0
- package/src/utils/countriesWithISOCodes.ts +1419 -0
- package/src/utils/dateTimeFormat.ts +257 -0
- package/src/utils/effectEventListener.ts +11 -0
- package/src/utils/formatFileSize.ts +18 -0
- package/src/utils/isClientSide.ts +1 -0
- package/src/utils/keepTransition.ts +15 -0
- package/src/utils/nodeEnv.ts +9 -0
- package/src/utils/smoothScrollTo.ts +47 -0
- package/src/utils/utilityTypes.ts +13 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
|
2
|
+
import { createPortal } from 'react-dom';
|
|
3
|
+
|
|
4
|
+
// Physics constants are authored at 60 fps; frameScale normalizes them to any refresh rate.
|
|
5
|
+
const TARGET_FRAME_MS = 1000 / 60;
|
|
6
|
+
const DEFAULT_PARTICLE_COUNT = 150;
|
|
7
|
+
const GRAVITY = 0.28; // downward acceleration (CSS px / frame² at 60fps)
|
|
8
|
+
const LAUNCH_SPEED_MIN = 10; // minimum initial upward velocity (CSS px / frame at 60fps)
|
|
9
|
+
const LAUNCH_SPEED_MAX = 22; // maximum initial upward velocity (CSS px / frame at 60fps)
|
|
10
|
+
const LATERAL_SPREAD = 10; // horizontal velocity range (±5 CSS px / frame at 60fps)
|
|
11
|
+
const SIZE_MIN = 6; // minimum particle size in CSS px
|
|
12
|
+
const SIZE_MAX = 12; // maximum particle size in CSS px
|
|
13
|
+
const FADE_DESCENT_THRESHOLD = 0.5; // vy at which opacity begins to drop (px/frame at 60fps)
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Brand color palette drawn from the Default theme's generated token steps.
|
|
17
|
+
* Matches success, warning, surface, primary, and critical token families
|
|
18
|
+
* (`--color-*` step values from `@evolve.ui/theme-system` Default brand).
|
|
19
|
+
*/
|
|
20
|
+
const DEFAULT_COLORS = {
|
|
21
|
+
success800: '#0B5125',
|
|
22
|
+
success600: '#12823B',
|
|
23
|
+
warning600: '#AE5F05',
|
|
24
|
+
warning300: '#FAAF57',
|
|
25
|
+
surface50: '#FFFFFF',
|
|
26
|
+
primary200: '#B8C3D8',
|
|
27
|
+
critical200: '#F4BDBD',
|
|
28
|
+
} as const;
|
|
29
|
+
|
|
30
|
+
type DefaultColorPalette = typeof DEFAULT_COLORS;
|
|
31
|
+
type ColorKeys = keyof DefaultColorPalette;
|
|
32
|
+
|
|
33
|
+
export type ConfettiHandle = {
|
|
34
|
+
/** Trigger a confetti burst across the bottom of the viewport. Re-calling while animating adds particles to the existing burst. */
|
|
35
|
+
fire: () => void;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Props for the Confetti component
|
|
40
|
+
*/
|
|
41
|
+
type Props = {
|
|
42
|
+
/** Override the default brand color palette
|
|
43
|
+
Allows passing a partial set of default colors, OR any custom string map.*/
|
|
44
|
+
colors?: Partial<Record<ColorKeys, string>> & Record<string, string>;
|
|
45
|
+
/** Called when the animation loop completes */
|
|
46
|
+
onComplete?: () => void;
|
|
47
|
+
/** Number of particles per burst. Default: 150 */
|
|
48
|
+
particleCount?: number;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
type Particle = {
|
|
52
|
+
color: string;
|
|
53
|
+
/** Per-particle air resistance coefficient (0.94–0.98) for organic scattering */
|
|
54
|
+
drag: number;
|
|
55
|
+
/** Per-particle opacity reduction rate for varied fadeout timing */
|
|
56
|
+
fadeSpeed: number;
|
|
57
|
+
opacity: number;
|
|
58
|
+
rotation: number;
|
|
59
|
+
rotationSpeed: number;
|
|
60
|
+
/** Oscillation frequency for the 3D tumble effect (radians per ms) */
|
|
61
|
+
tumbleFrequency: number;
|
|
62
|
+
shape: 'circle' | 'rect';
|
|
63
|
+
size: number;
|
|
64
|
+
vx: number;
|
|
65
|
+
vy: number;
|
|
66
|
+
x: number;
|
|
67
|
+
y: number;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Resizes the canvas buffer to match physical device pixels and returns the
|
|
72
|
+
* scaled context. Setting canvas.width/height resets all transforms, so the
|
|
73
|
+
* Device Pixel Ratio (DPR) scale is safe to reapply immediately after.
|
|
74
|
+
*/
|
|
75
|
+
const setupCanvas = (canvas: HTMLCanvasElement): CanvasRenderingContext2D | null => {
|
|
76
|
+
const devicePixelRatio = window.devicePixelRatio ?? 1;
|
|
77
|
+
canvas.width = window.innerWidth * devicePixelRatio;
|
|
78
|
+
canvas.height = window.innerHeight * devicePixelRatio;
|
|
79
|
+
const canvasContext = canvas.getContext('2d');
|
|
80
|
+
canvasContext?.scale(devicePixelRatio, devicePixelRatio);
|
|
81
|
+
return canvasContext;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const createParticle = (colors: Record<string, string> = DEFAULT_COLORS): Particle => {
|
|
85
|
+
const palette = Object.values(colors);
|
|
86
|
+
// Fallback to default colors if someone passed an empty object {}
|
|
87
|
+
const activePalette = palette.length > 0 ? palette : Object.values(DEFAULT_COLORS);
|
|
88
|
+
const chosenColor = activePalette[Math.floor(Math.random() * activePalette.length)];
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
color: chosenColor,
|
|
92
|
+
drag: Math.random() * 0.04 + 0.94,
|
|
93
|
+
fadeSpeed: Math.random() * 0.008 + 0.006,
|
|
94
|
+
opacity: 1,
|
|
95
|
+
rotation: Math.random() * Math.PI,
|
|
96
|
+
rotationSpeed: (Math.random() - 0.5) * 0.15,
|
|
97
|
+
tumbleFrequency: Math.random() * 0.08 + 0.04,
|
|
98
|
+
shape: Math.random() < 0.5 ? 'rect' : 'circle',
|
|
99
|
+
size: Math.random() * (SIZE_MAX - SIZE_MIN) + SIZE_MIN,
|
|
100
|
+
vx: (Math.random() - 0.5) * LATERAL_SPREAD,
|
|
101
|
+
vy: -(Math.random() * (LAUNCH_SPEED_MAX - LAUNCH_SPEED_MIN) + LAUNCH_SPEED_MIN),
|
|
102
|
+
x: Math.random() * window.innerWidth,
|
|
103
|
+
y: window.innerHeight + 10,
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Canvas-based confetti burst component with an imperative `fire()` API.
|
|
109
|
+
*
|
|
110
|
+
* Renders a fixed, pointer-events-none overlay canvas and fires a branded
|
|
111
|
+
* particle burst from across the bottom of the viewport on demand. Re-triggerable
|
|
112
|
+
* while animating (accumulates particles). Cleans up the Request Animation Frame (RAF) loop and resize
|
|
113
|
+
* listener on unmount.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```tsx
|
|
117
|
+
* const ref = useRef<ConfettiHandle>(null);
|
|
118
|
+
* ref.current?.fire();
|
|
119
|
+
* return <Confetti ref={ref} />;
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export const Confetti = forwardRef<ConfettiHandle, Props>(
|
|
123
|
+
({ colors = DEFAULT_COLORS, onComplete, particleCount = DEFAULT_PARTICLE_COUNT }, ref) => {
|
|
124
|
+
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
125
|
+
const canvasContextRef = useRef<CanvasRenderingContext2D | null>(null);
|
|
126
|
+
const particlesRef = useRef<Particle[]>([]);
|
|
127
|
+
const animationFrameRef = useRef<number | null>(null);
|
|
128
|
+
const lastTimestampRef = useRef<number>(0);
|
|
129
|
+
|
|
130
|
+
// Clean SSR Guard: Component returns null on server evaluation, flips safely on client mount.
|
|
131
|
+
const [mounted, setMounted] = useState(false);
|
|
132
|
+
|
|
133
|
+
const onCompleteRef = useRef(onComplete);
|
|
134
|
+
onCompleteRef.current = onComplete;
|
|
135
|
+
|
|
136
|
+
// tickRef holds the animation loop function in a ref so that:
|
|
137
|
+
// 1. The loop can call itself recursively via requestAnimationFrame.
|
|
138
|
+
// 2. If props change mid-animation, the loop automatically uses the
|
|
139
|
+
// latest values on the next frame without needing to restart.
|
|
140
|
+
const tickRef = useRef<(timestamp: number) => void>(() => {});
|
|
141
|
+
tickRef.current = (timestamp: number) => {
|
|
142
|
+
const canvasContext = canvasContextRef.current;
|
|
143
|
+
if (!canvasContext) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// How many "60fps frames worth" of time has passed since the last tick.
|
|
148
|
+
// At 60Hz this is ~1.0; at 120Hz it's ~0.5 — physics are scaled accordingly
|
|
149
|
+
// so the animation runs at the same real-world speed on any display.
|
|
150
|
+
// Capped at 2.0 so a long tab-switch pause doesn't make particles jump.
|
|
151
|
+
const frameScale =
|
|
152
|
+
lastTimestampRef.current === 0
|
|
153
|
+
? 1
|
|
154
|
+
: Math.min((timestamp - lastTimestampRef.current) / TARGET_FRAME_MS, 2);
|
|
155
|
+
lastTimestampRef.current = timestamp;
|
|
156
|
+
|
|
157
|
+
canvasContext.clearRect(0, 0, window.innerWidth, window.innerHeight);
|
|
158
|
+
|
|
159
|
+
particlesRef.current = particlesRef.current.filter((p) => p.opacity > 0 && p.y < window.innerHeight + 50);
|
|
160
|
+
|
|
161
|
+
for (const particle of particlesRef.current) {
|
|
162
|
+
// Move the particle: apply drag, gravity, then update position.
|
|
163
|
+
// Math.pow(drag, frameScale) keeps drag rate consistent at any refresh rate.
|
|
164
|
+
const dragFactor = Math.pow(particle.drag, frameScale);
|
|
165
|
+
particle.vx *= dragFactor;
|
|
166
|
+
particle.vy *= dragFactor;
|
|
167
|
+
particle.vy += GRAVITY * frameScale;
|
|
168
|
+
particle.x += particle.vx * frameScale;
|
|
169
|
+
particle.y += particle.vy * frameScale;
|
|
170
|
+
particle.rotation += particle.rotationSpeed * frameScale;
|
|
171
|
+
|
|
172
|
+
// Only start fading once the particle has peaked and is falling.
|
|
173
|
+
if (particle.vy > FADE_DESCENT_THRESHOLD) {
|
|
174
|
+
particle.opacity -= particle.fadeSpeed * frameScale;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Squash the shape along one or both axes using sin/cos of real time.
|
|
178
|
+
// This fakes a 3D tumbling look. Using real time (not frame count)
|
|
179
|
+
// keeps the tumble speed the same on any display refresh rate.
|
|
180
|
+
const tumbleY = Math.sin(timestamp * particle.tumbleFrequency * 0.05);
|
|
181
|
+
|
|
182
|
+
canvasContext.save();
|
|
183
|
+
canvasContext.translate(particle.x, particle.y);
|
|
184
|
+
canvasContext.rotate(particle.rotation);
|
|
185
|
+
canvasContext.globalAlpha = Math.max(0, particle.opacity);
|
|
186
|
+
canvasContext.fillStyle = particle.color;
|
|
187
|
+
|
|
188
|
+
if (particle.shape === 'circle') {
|
|
189
|
+
canvasContext.scale(1, tumbleY); // squash on Y only — looks like a spinning coin
|
|
190
|
+
canvasContext.beginPath();
|
|
191
|
+
canvasContext.arc(0, 0, particle.size / 2, 0, Math.PI * 2);
|
|
192
|
+
canvasContext.fill();
|
|
193
|
+
} else {
|
|
194
|
+
const tumbleX = Math.cos(timestamp * particle.tumbleFrequency * 0.03);
|
|
195
|
+
canvasContext.scale(tumbleX, tumbleY); // squash on both axes — looks like fluttering paper
|
|
196
|
+
canvasContext.fillRect(-particle.size / 2, -particle.size / 2, particle.size, particle.size);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
canvasContext.restore();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (particlesRef.current.length > 0) {
|
|
203
|
+
animationFrameRef.current = requestAnimationFrame(tickRef.current);
|
|
204
|
+
} else {
|
|
205
|
+
animationFrameRef.current = null;
|
|
206
|
+
lastTimestampRef.current = 0;
|
|
207
|
+
onCompleteRef.current?.();
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
useImperativeHandle(ref, () => ({
|
|
212
|
+
fire() {
|
|
213
|
+
if (!canvasRef.current) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
for (let i = 0; i < particleCount; i++) {
|
|
218
|
+
particlesRef.current.push(createParticle(colors));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (animationFrameRef.current === null) {
|
|
222
|
+
lastTimestampRef.current = 0;
|
|
223
|
+
animationFrameRef.current = requestAnimationFrame(tickRef.current);
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
}));
|
|
227
|
+
|
|
228
|
+
useEffect(() => {
|
|
229
|
+
setMounted(true);
|
|
230
|
+
|
|
231
|
+
const canvas = canvasRef.current;
|
|
232
|
+
if (!canvas) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
canvasContextRef.current = setupCanvas(canvas);
|
|
237
|
+
|
|
238
|
+
const handleResize = () => {
|
|
239
|
+
if (canvasRef.current) {
|
|
240
|
+
canvasContextRef.current = setupCanvas(canvasRef.current);
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
window.addEventListener('resize', handleResize);
|
|
245
|
+
return () => {
|
|
246
|
+
window.removeEventListener('resize', handleResize);
|
|
247
|
+
if (animationFrameRef.current !== null) {
|
|
248
|
+
window.cancelAnimationFrame(animationFrameRef.current);
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
}, [mounted]); // Depend on mounted initialization so it properly captures the canvas element once attached to the DOM
|
|
252
|
+
|
|
253
|
+
if (!mounted) {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return createPortal(
|
|
258
|
+
<canvas
|
|
259
|
+
aria-hidden="true"
|
|
260
|
+
className="pointer-events-none fixed inset-0 z-[9999] h-screen w-screen"
|
|
261
|
+
data-hui-id="Confetti"
|
|
262
|
+
data-testid="confetti"
|
|
263
|
+
ref={canvasRef}
|
|
264
|
+
/>,
|
|
265
|
+
document.body
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
Confetti.displayName = 'Confetti';
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { cn } from '@evolve.ui/theme-system';
|
|
2
|
+
import { animated, useSpring, useTransition } from '@react-spring/web';
|
|
3
|
+
import { atom, useSetAtom } from 'jotai';
|
|
4
|
+
import { ComponentProps, FC, HTMLProps, ReactElement, useEffect, useMemo, useRef, useState } from 'react';
|
|
5
|
+
import useMeasure from 'react-use-measure';
|
|
6
|
+
|
|
7
|
+
import { nodeEnv } from '../utils/nodeEnv';
|
|
8
|
+
import { Page } from './components/Page';
|
|
9
|
+
|
|
10
|
+
// react-spring 9.7.5's AnimatedComponent props drop `children` under TypeScript 6;
|
|
11
|
+
// runtime behavior is unchanged — re-widen with a typed alias.
|
|
12
|
+
type AnimatedDivProps = Omit<HTMLProps<HTMLDivElement>, 'style'> & { style?: object };
|
|
13
|
+
const AnimatedDiv = animated.div as unknown as FC<AnimatedDivProps>;
|
|
14
|
+
|
|
15
|
+
export const currentPageAtom = atom<string>('');
|
|
16
|
+
|
|
17
|
+
type PagerProps = {
|
|
18
|
+
/** Page components */
|
|
19
|
+
children: ReactElement<ComponentProps<typeof Page>>[];
|
|
20
|
+
/** Custom styling for the outermost ContentPager containing element */
|
|
21
|
+
className?: string;
|
|
22
|
+
/** The currently visible page */
|
|
23
|
+
currentPage: string;
|
|
24
|
+
/** Adds a data-testid attribute to the dom element, used for end to end testing. */
|
|
25
|
+
'data-testid'?: string;
|
|
26
|
+
/** A callback to run when animation has completed. Useful for focusing.*/
|
|
27
|
+
onTransitionEnd?: () => void;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const ContentPager = ({
|
|
31
|
+
children,
|
|
32
|
+
className,
|
|
33
|
+
currentPage,
|
|
34
|
+
'data-testid': testId = 'content-pager',
|
|
35
|
+
onTransitionEnd,
|
|
36
|
+
}: PagerProps) => {
|
|
37
|
+
// Add state for modal content height detection
|
|
38
|
+
const [initialPage, setInitialPage] = useState<string>(currentPage);
|
|
39
|
+
const [modalContentHeight, setModalContentHeight] = useState(0);
|
|
40
|
+
const isTestEnv = nodeEnv === 'test';
|
|
41
|
+
const isInitialRender = useRef(true);
|
|
42
|
+
|
|
43
|
+
const setCurrentPage = useSetAtom(currentPageAtom);
|
|
44
|
+
|
|
45
|
+
const [ref, { height, width }] = useMeasure();
|
|
46
|
+
|
|
47
|
+
const currentPageIndex = useMemo(
|
|
48
|
+
() => children.findIndex((page) => page.props.name === currentPage),
|
|
49
|
+
[children, currentPage]
|
|
50
|
+
);
|
|
51
|
+
const currentPageComponent = useMemo(() => children[currentPageIndex], [children, currentPageIndex]);
|
|
52
|
+
|
|
53
|
+
const [previousPageIndex, setPreviousPageIndex] = useState(currentPageIndex);
|
|
54
|
+
|
|
55
|
+
const containerAnimatedStyles = useSpring({
|
|
56
|
+
config: {
|
|
57
|
+
// Increase friction for less oscillation
|
|
58
|
+
friction: 32,
|
|
59
|
+
// Prevent spring from overshooting its target, eliminating final bounce
|
|
60
|
+
overshootClamping: true,
|
|
61
|
+
// End animation sooner when displacement is below this threshold (increased from 0.01)
|
|
62
|
+
restDisplacementThreshold: 0.1,
|
|
63
|
+
// End animation sooner when speed drops below this threshold (increased from 2)
|
|
64
|
+
restSpeedThreshold: 10,
|
|
65
|
+
// Increase tension slightly for snappier animations
|
|
66
|
+
tension: 280,
|
|
67
|
+
},
|
|
68
|
+
height: isInitialRender.current
|
|
69
|
+
? modalContentHeight
|
|
70
|
+
: initialPage === currentPage && modalContentHeight !== 0
|
|
71
|
+
? modalContentHeight
|
|
72
|
+
: height,
|
|
73
|
+
immediate: isTestEnv || isInitialRender.current,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const { fromTransform, leaveTransform } = useMemo(() => {
|
|
77
|
+
const rightTransform = `translate(${width}px)`;
|
|
78
|
+
const leftTransform = `translate(-${width}px)`;
|
|
79
|
+
const fromTransform = currentPageIndex > previousPageIndex ? rightTransform : leftTransform;
|
|
80
|
+
const leaveTransform = currentPageIndex > previousPageIndex ? leftTransform : rightTransform;
|
|
81
|
+
|
|
82
|
+
return { fromTransform, leaveTransform };
|
|
83
|
+
}, [currentPageIndex, previousPageIndex, width]);
|
|
84
|
+
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
if (initialPage === '') {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (initialPage !== currentPage) {
|
|
91
|
+
setInitialPage('');
|
|
92
|
+
setModalContentHeight(0);
|
|
93
|
+
}
|
|
94
|
+
if (isInitialRender.current) {
|
|
95
|
+
window.requestAnimationFrame(() => {
|
|
96
|
+
isInitialRender.current = false;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}, [currentPage, currentPageIndex, initialPage]);
|
|
100
|
+
|
|
101
|
+
// Ensure that modal content height is detected as it has issues with the transition
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (currentPage === initialPage) {
|
|
104
|
+
const modalElement = document.querySelector('[data-hui-id="Modal"]');
|
|
105
|
+
const pageElement = document.querySelector(
|
|
106
|
+
'[data-hui-id="ContentPager"] [data-page-name]'
|
|
107
|
+
) as HTMLElement | null;
|
|
108
|
+
|
|
109
|
+
if (modalElement && pageElement) {
|
|
110
|
+
setModalContentHeight(pageElement.scrollHeight + 1);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}, [currentPage, initialPage, height]);
|
|
114
|
+
|
|
115
|
+
// Keep the current page atom in sync immediately, so portal actions can resolve visibility on first render
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
setCurrentPage(currentPage);
|
|
118
|
+
}, [currentPage, setCurrentPage]);
|
|
119
|
+
|
|
120
|
+
const transitions = useTransition(
|
|
121
|
+
[
|
|
122
|
+
{
|
|
123
|
+
currentPage,
|
|
124
|
+
currentPageComponent,
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
{
|
|
128
|
+
enter: {
|
|
129
|
+
opacity: 1,
|
|
130
|
+
transform: 'translate(0px)',
|
|
131
|
+
},
|
|
132
|
+
from: {
|
|
133
|
+
opacity: 0,
|
|
134
|
+
transform: fromTransform,
|
|
135
|
+
},
|
|
136
|
+
immediate: isInitialRender.current,
|
|
137
|
+
initial: {
|
|
138
|
+
opacity: 1,
|
|
139
|
+
transform: 'translate(0px)',
|
|
140
|
+
},
|
|
141
|
+
keys: (page) => page.currentPage,
|
|
142
|
+
leave: {
|
|
143
|
+
opacity: 0,
|
|
144
|
+
transform: leaveTransform,
|
|
145
|
+
},
|
|
146
|
+
onRest: () => {
|
|
147
|
+
setPreviousPageIndex(currentPageIndex);
|
|
148
|
+
if (onTransitionEnd) {
|
|
149
|
+
onTransitionEnd();
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
onStart: () => {
|
|
153
|
+
setCurrentPage(currentPage);
|
|
154
|
+
},
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
<AnimatedDiv
|
|
160
|
+
className={cn('relative w-full overflow-hidden', className)}
|
|
161
|
+
data-hui-id="ContentPager"
|
|
162
|
+
data-testid={testId}
|
|
163
|
+
style={{
|
|
164
|
+
...containerAnimatedStyles,
|
|
165
|
+
height: containerAnimatedStyles.height,
|
|
166
|
+
}}
|
|
167
|
+
>
|
|
168
|
+
{transitions(({ ...style }, page) => (
|
|
169
|
+
<AnimatedDiv
|
|
170
|
+
className={cn('absolute left-0 right-0 h-full')}
|
|
171
|
+
style={{
|
|
172
|
+
...style,
|
|
173
|
+
opacity: style.opacity,
|
|
174
|
+
position: 'absolute',
|
|
175
|
+
}}
|
|
176
|
+
>
|
|
177
|
+
<div
|
|
178
|
+
data-page-name={page.currentPage}
|
|
179
|
+
ref={ref}
|
|
180
|
+
>
|
|
181
|
+
{page.currentPageComponent}
|
|
182
|
+
</div>
|
|
183
|
+
</AnimatedDiv>
|
|
184
|
+
))}
|
|
185
|
+
</AnimatedDiv>
|
|
186
|
+
);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
export { Page };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type PageProps = {
|
|
4
|
+
/** Page content */
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
/** className __ALL__ exported components pass through a classname to the outermost component */
|
|
7
|
+
className?: string;
|
|
8
|
+
/** Adds a data-testid attribute to the dom element, used for end to end testing. */
|
|
9
|
+
'data-testid'?: string;
|
|
10
|
+
/** A unique page name, used by the parent <ContentPager /> for moving between pages */
|
|
11
|
+
name: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const Page = ({ children, className, 'data-testid': testId = 'pager-content-page' }: PageProps) => {
|
|
15
|
+
return (
|
|
16
|
+
<div
|
|
17
|
+
className={className}
|
|
18
|
+
data-testid={testId}
|
|
19
|
+
id="content-pager-page"
|
|
20
|
+
>
|
|
21
|
+
{children}
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { memo } from 'react';
|
|
2
|
+
|
|
3
|
+
import { ToggleSwitch } from '../../../ToggleSwitch/ToggleSwitch';
|
|
4
|
+
import { BodySecondary, Caption, LabelStrong } from '../../../Typography/Text/Text';
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
description: string;
|
|
8
|
+
isToggled: boolean;
|
|
9
|
+
label: string;
|
|
10
|
+
onToggleChange?: () => void;
|
|
11
|
+
required?: boolean;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const CookieCategoryRow = memo(({ description, isToggled, label, onToggleChange, required }: Props) => (
|
|
15
|
+
<div className="flex flex-col gap-2xs border-b border-border-secondary py-sm">
|
|
16
|
+
<div className="flex h-[22px] items-center justify-between">
|
|
17
|
+
<LabelStrong>{label}</LabelStrong>
|
|
18
|
+
{required ? (
|
|
19
|
+
<BodySecondary className="text-text-primary">Required</BodySecondary>
|
|
20
|
+
) : (
|
|
21
|
+
<ToggleSwitch
|
|
22
|
+
aria-label={label}
|
|
23
|
+
isToggled={isToggled}
|
|
24
|
+
onToggleChange={onToggleChange}
|
|
25
|
+
/>
|
|
26
|
+
)}
|
|
27
|
+
</div>
|
|
28
|
+
<Caption className="text-text-secondary">{description}</Caption>
|
|
29
|
+
</div>
|
|
30
|
+
));
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { forwardRef, useImperativeHandle } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { ConsentCategories, CookieCategoryConfig, CookieConsentTracking } from '../../types/cookieConsent.types';
|
|
4
|
+
|
|
5
|
+
import { useCookieConsentState } from '../../hooks/useCookieConsentState';
|
|
6
|
+
import { CookieConsentBanner } from '../CookieConsentBanner/CookieConsentBanner';
|
|
7
|
+
import { CookieConsentModal } from '../CookieConsentModal/CookieConsentModal';
|
|
8
|
+
|
|
9
|
+
const DEFAULT_TOAST_MESSAGE = 'Your privacy preferences have been saved.';
|
|
10
|
+
|
|
11
|
+
type Props = {
|
|
12
|
+
categories?: CookieCategoryConfig[];
|
|
13
|
+
/**
|
|
14
|
+
* Controlled consent state. When provided, an external consent-management
|
|
15
|
+
* platform (CMP) owns the consent state: internal localStorage persistence
|
|
16
|
+
* is bypassed and the banner is never auto-shown. Sync user changes back to
|
|
17
|
+
* the CMP via `onConsentChange`.
|
|
18
|
+
*/
|
|
19
|
+
consent?: ConsentCategories;
|
|
20
|
+
onConsentChange?: (consent: ConsentCategories) => void;
|
|
21
|
+
/** localStorage key used to persist consent in uncontrolled mode (default `'hui-cookie-consent'`). */
|
|
22
|
+
storageKey?: string;
|
|
23
|
+
toastMessage?: string;
|
|
24
|
+
tracking?: CookieConsentTracking;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type CookieConsentHandle = {
|
|
28
|
+
openModal: () => void;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Custom cookie consent UI (banner + preferences modal).
|
|
33
|
+
*
|
|
34
|
+
* Renders the consent banner and modal. By default consent is persisted to
|
|
35
|
+
* localStorage via `useCookieConsentState`; pass the `consent` prop to let an
|
|
36
|
+
* external consent-management platform own the state instead. Exposes
|
|
37
|
+
* `openModal()` through a ref for programmatic access (e.g. footer
|
|
38
|
+
* "Cookie Preferences" link).
|
|
39
|
+
*/
|
|
40
|
+
export const CookieConsent = forwardRef<CookieConsentHandle, Props>(
|
|
41
|
+
(
|
|
42
|
+
{ categories, consent, onConsentChange, storageKey, toastMessage = DEFAULT_TOAST_MESSAGE, tracking } = {},
|
|
43
|
+
ref
|
|
44
|
+
) => {
|
|
45
|
+
const state = useCookieConsentState({ consent, onConsentChange, storageKey, toastMessage, tracking });
|
|
46
|
+
|
|
47
|
+
useImperativeHandle(ref, () => ({ openModal: state.openModal }), [state.openModal]);
|
|
48
|
+
|
|
49
|
+
if (!state.showBanner && !state.showDialog) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<>
|
|
55
|
+
{state.showBanner && (
|
|
56
|
+
<CookieConsentBanner
|
|
57
|
+
isExiting={state.bannerExiting}
|
|
58
|
+
onAnimationEnd={state.handleBannerAnimationEnd}
|
|
59
|
+
onDismiss={state.handleOk}
|
|
60
|
+
onOpenPreferences={state.openDialog}
|
|
61
|
+
/>
|
|
62
|
+
)}
|
|
63
|
+
<CookieConsentModal
|
|
64
|
+
categories={categories}
|
|
65
|
+
localConsent={state.localConsent}
|
|
66
|
+
onClose={state.closeDialog}
|
|
67
|
+
onSave={state.handleSavePreferences}
|
|
68
|
+
onToggle={state.handleToggle}
|
|
69
|
+
show={state.showDialog}
|
|
70
|
+
/>
|
|
71
|
+
</>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { cn } from '@evolve.ui/theme-system';
|
|
2
|
+
import { AnimationEvent, memo } from 'react';
|
|
3
|
+
|
|
4
|
+
import { Button } from '../../../Button/Button';
|
|
5
|
+
import { InlineButton } from '../../../Typography/InlineButton/InlineButton';
|
|
6
|
+
import { BodySecondary } from '../../../Typography/Text/Text';
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
isExiting: boolean;
|
|
10
|
+
onAnimationEnd: (e: AnimationEvent<HTMLDivElement>) => void;
|
|
11
|
+
onDismiss: () => void;
|
|
12
|
+
onOpenPreferences: () => void;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const CookieConsentBanner = memo(({ isExiting, onAnimationEnd, onDismiss, onOpenPreferences }: Props) => (
|
|
16
|
+
<div
|
|
17
|
+
aria-label="Cookie consent"
|
|
18
|
+
className={cn(
|
|
19
|
+
'fixed inset-x-0 bottom-md z-[10300] mx-auto w-[calc(100%-48px)] max-w-[1200px] rounded-md border border-border-secondary bg-background-tertiary shadow-01',
|
|
20
|
+
isExiting ? 'animate-slideDown' : 'animate-slideUp'
|
|
21
|
+
)}
|
|
22
|
+
onAnimationEnd={onAnimationEnd}
|
|
23
|
+
role="region"
|
|
24
|
+
>
|
|
25
|
+
<div className="flex flex-col gap-xs p-sm smMin:flex-row smMin:items-center smMin:gap-md smMin:p-md">
|
|
26
|
+
<div className="min-w-0 flex-1">
|
|
27
|
+
<BodySecondary className="inline">
|
|
28
|
+
We use cookies to improve your experience, to analyze website usage, and for marketing purposes.
|
|
29
|
+
</BodySecondary>
|
|
30
|
+
<InlineButton
|
|
31
|
+
className="ml-2xs inline text-text-primary underline"
|
|
32
|
+
onClick={onOpenPreferences}
|
|
33
|
+
size="sm"
|
|
34
|
+
>
|
|
35
|
+
Cookie preferences
|
|
36
|
+
</InlineButton>
|
|
37
|
+
</div>
|
|
38
|
+
<div className="shrink-0 self-end smMin:self-auto">
|
|
39
|
+
<Button
|
|
40
|
+
className="min-w-[96px]"
|
|
41
|
+
onClick={onDismiss}
|
|
42
|
+
size="sm"
|
|
43
|
+
style="neutral"
|
|
44
|
+
variant="outlined"
|
|
45
|
+
>
|
|
46
|
+
OK
|
|
47
|
+
</Button>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
));
|