@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,55 @@
|
|
|
1
|
+
import { cn } from '@evolve.ui/theme-system';
|
|
2
|
+
|
|
3
|
+
import { IconButton } from '../../../IconButton/IconButton';
|
|
4
|
+
import { Close } from '../../../Icons';
|
|
5
|
+
import { useWindowIsMobile } from '../../../providers';
|
|
6
|
+
import { nodeEnv } from '../../../utils/nodeEnv';
|
|
7
|
+
import { useCloseModal, useForceCloseModal } from '../../hooks/useCloseModal';
|
|
8
|
+
|
|
9
|
+
type Props = {
|
|
10
|
+
/**
|
|
11
|
+
* @default 'Close'
|
|
12
|
+
*/
|
|
13
|
+
'aria-label'?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Optional class name for the component.
|
|
16
|
+
*/
|
|
17
|
+
className?: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
let useCloseModalHook = useCloseModal;
|
|
21
|
+
|
|
22
|
+
if (nodeEnv === 'test') {
|
|
23
|
+
useCloseModalHook = useForceCloseModal as typeof useCloseModal;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Component used in modal windows to close them.
|
|
28
|
+
*
|
|
29
|
+
* You can access this same functionality (no need for the component to be a child of `Modal`)
|
|
30
|
+
* with `useCloseModal` (subpath `modal/useCloseModal`).
|
|
31
|
+
*
|
|
32
|
+
* If you need to add a callback, you likely want to modify `handleClose` on the `Modal` component.
|
|
33
|
+
*/
|
|
34
|
+
export const CloseButton = ({ 'aria-label': ariaLabel = 'Close', className }: Props) => {
|
|
35
|
+
const closeModal = useCloseModalHook('close');
|
|
36
|
+
const isMobile = useWindowIsMobile();
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<IconButton
|
|
40
|
+
aria-label={ariaLabel}
|
|
41
|
+
className={cn(
|
|
42
|
+
// GENERAL
|
|
43
|
+
'absolute right-sm top-sm z-[2] cursor-pointer',
|
|
44
|
+
// MOBILE
|
|
45
|
+
'xsMax:right-[12px] xsMax:top-[13px]',
|
|
46
|
+
className
|
|
47
|
+
)}
|
|
48
|
+
hideTooltip
|
|
49
|
+
icon={Close}
|
|
50
|
+
onClick={closeModal}
|
|
51
|
+
size={isMobile ? 'sm' : 'md'}
|
|
52
|
+
type="button"
|
|
53
|
+
/>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { cn } from '@evolve.ui/theme-system';
|
|
2
|
+
import { useAtomValue, useSetAtom } from 'jotai';
|
|
3
|
+
import { Children, ReactNode, useContext, useEffect, useId, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { createPortal } from 'react-dom';
|
|
5
|
+
|
|
6
|
+
import { currentPageAtom } from '../../../ContentPager/ContentPager';
|
|
7
|
+
import { ModalContext } from '../../context';
|
|
8
|
+
|
|
9
|
+
type Props = {
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
className?: string;
|
|
12
|
+
usePortalActions?: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A styled container for buttons or other actions.
|
|
17
|
+
*
|
|
18
|
+
* Automatically adds scroll hint above when `ModalContent` is scrollable.
|
|
19
|
+
* During page transitions, only the first set of portal actions are shown.
|
|
20
|
+
*/
|
|
21
|
+
export const ModalActions = ({ children, className, usePortalActions }: Props) => {
|
|
22
|
+
const { modalHasFooterAtom, showBottomScrollHintAtom } = useContext(ModalContext);
|
|
23
|
+
const showBottomScrollHint = useAtomValue(showBottomScrollHintAtom);
|
|
24
|
+
const setModalHasFooter = useSetAtom(modalHasFooterAtom);
|
|
25
|
+
const modalActionsRef = useRef<HTMLDivElement | null>(null);
|
|
26
|
+
|
|
27
|
+
const modalPortalKey = useId();
|
|
28
|
+
const amountOfChildren = useMemo(() => Children.toArray(children).length, [children]);
|
|
29
|
+
const currentPage = useAtomValue(currentPageAtom);
|
|
30
|
+
|
|
31
|
+
// Track which page this ModalActions belongs to
|
|
32
|
+
const [modalActionsPageName, setModalActionsPageName] = useState<string | null>(null);
|
|
33
|
+
|
|
34
|
+
// Find the page name by checking the DOM when the ref is available
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (modalActionsRef.current && modalActionsPageName === null) {
|
|
37
|
+
// For non-portal actions, traverse up the DOM to find the page
|
|
38
|
+
if (!usePortalActions) {
|
|
39
|
+
const pageElement = modalActionsRef.current.closest('[data-page-name]');
|
|
40
|
+
if (pageElement) {
|
|
41
|
+
const pageName = pageElement.getAttribute('data-page-name');
|
|
42
|
+
if (pageName) {
|
|
43
|
+
setModalActionsPageName(pageName);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// For portal actions, find which page is currently active in the DOM
|
|
50
|
+
// Since portal actions are rendered outside the page structure, we check
|
|
51
|
+
// which page element exists and use the last one (most recently rendered)
|
|
52
|
+
const pageElements = document.querySelectorAll('[data-page-name]');
|
|
53
|
+
if (pageElements.length > 0) {
|
|
54
|
+
const lastPageElement = pageElements[pageElements.length - 1];
|
|
55
|
+
const pageName = lastPageElement.getAttribute('data-page-name');
|
|
56
|
+
if (pageName) {
|
|
57
|
+
setModalActionsPageName(pageName);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}, [modalActionsPageName, usePortalActions]);
|
|
62
|
+
|
|
63
|
+
const isModalActionsInCurrentPage = useMemo(() => {
|
|
64
|
+
return modalActionsPageName === currentPage;
|
|
65
|
+
}, [modalActionsPageName, currentPage]);
|
|
66
|
+
|
|
67
|
+
// Update modalHasFooter based on visibility
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
if (modalActionsPageName !== null) {
|
|
70
|
+
// If this ModalActions is visible, set modalHasFooter to true
|
|
71
|
+
if (isModalActionsInCurrentPage) {
|
|
72
|
+
setModalHasFooter(true);
|
|
73
|
+
} else {
|
|
74
|
+
// If this ModalActions is hidden, only set modalHasFooter to false
|
|
75
|
+
// if there are no other visible ModalActions (i.e., we're on a page without actions)
|
|
76
|
+
const hasVisibleModalActions = document.querySelector('[data-testid="modal-footer"]:not(.hidden)');
|
|
77
|
+
if (!hasVisibleModalActions) {
|
|
78
|
+
setModalHasFooter(false);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}, [isModalActionsInCurrentPage, modalActionsPageName, setModalHasFooter]);
|
|
83
|
+
|
|
84
|
+
const modalActionsContent = (
|
|
85
|
+
<div
|
|
86
|
+
className={cn(
|
|
87
|
+
// GENERAL
|
|
88
|
+
'relative z-[1] flex items-center justify-center gap-sm p-[32px_64px_64px_64px] [&>button]:min-w-[158px]',
|
|
89
|
+
// ANIMATION
|
|
90
|
+
'transition-all duration-200 ease-in [animation-play-state:paused] [scrollbar-gutter:stable-both-edges]',
|
|
91
|
+
// SHADOW
|
|
92
|
+
{ 'shadow-04': showBottomScrollHint },
|
|
93
|
+
// If there are 2 buttons, make them take up the full width
|
|
94
|
+
{ '[&>button]:flex-1': amountOfChildren === 2 },
|
|
95
|
+
// PORTAL ACTIONS - absolute on desktop and mobile fullscreen, relative on tablet
|
|
96
|
+
{
|
|
97
|
+
'mobile:group-only/fullscreen:absolute mobile:group-only/fullscreen:bottom-0 mobile:group-only/fullscreen:h-[74px] mobile:group-only/fullscreen:w-full':
|
|
98
|
+
usePortalActions,
|
|
99
|
+
'smMin:absolute smMin:bottom-0 smMin:h-[138px] smMin:w-full': usePortalActions,
|
|
100
|
+
},
|
|
101
|
+
// MOBILE
|
|
102
|
+
'xsMax:p-[24px_32px_32px_32px] xsMax:[&>button]:min-w-fit xsMax:[&>button]:flex-1',
|
|
103
|
+
// MOBILE FULLSCREEN
|
|
104
|
+
'mobile:group-only/fullscreen:gap-sm mobile:group-only/fullscreen:p-sm',
|
|
105
|
+
// HIDE MODAL ACTIONS: Hide if this ModalActions belongs to a page that's NOT the current page
|
|
106
|
+
{
|
|
107
|
+
'hidden duration-0':
|
|
108
|
+
usePortalActions && !isModalActionsInCurrentPage && modalActionsPageName !== null,
|
|
109
|
+
},
|
|
110
|
+
className
|
|
111
|
+
)}
|
|
112
|
+
data-testid="modal-footer"
|
|
113
|
+
id="modal-footer"
|
|
114
|
+
ref={(ref) => {
|
|
115
|
+
// Only set modalHasFooter based on ref existence, not visibility
|
|
116
|
+
// Visibility is handled by the useEffect above
|
|
117
|
+
modalActionsRef.current = ref;
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
{children}
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
if (usePortalActions && typeof window !== 'undefined') {
|
|
125
|
+
const portalTarget = document.getElementById('modal-actions-portal');
|
|
126
|
+
|
|
127
|
+
if (!portalTarget) {
|
|
128
|
+
return modalActionsContent;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return createPortal(modalActionsContent, portalTarget, modalPortalKey.toString());
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return modalActionsContent;
|
|
135
|
+
};
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { cn } from '@evolve.ui/theme-system';
|
|
2
|
+
import { useAtomValue, useSetAtom } from 'jotai';
|
|
3
|
+
import { ReactNode, useCallback, useContext, useEffect, useRef, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
import { currentPageAtom } from '../../../ContentPager/ContentPager';
|
|
6
|
+
import { effectEventListener } from '../../../utils/effectEventListener';
|
|
7
|
+
import { ModalContext } from '../../context';
|
|
8
|
+
|
|
9
|
+
type Props = {
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
className?: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The main content area of the modal.
|
|
16
|
+
*
|
|
17
|
+
* It automatically adds scroll hints to `ModalHeader` (above) and `ModalActions` (below).
|
|
18
|
+
* It automatically moves the `ModalTitle` farther into the header if scrolled.
|
|
19
|
+
*/
|
|
20
|
+
export const ModalContent = ({ children, className }: Props) => {
|
|
21
|
+
const { scrollTopAtom, showBottomScrollHintAtom, showTopScrollHintAtom } = useContext(ModalContext);
|
|
22
|
+
const contentRef = useRef<HTMLDivElement>(null);
|
|
23
|
+
const currentPage = useAtomValue(currentPageAtom);
|
|
24
|
+
|
|
25
|
+
const setScrollTop = useSetAtom(scrollTopAtom);
|
|
26
|
+
const setShowBottomScrollHint = useSetAtom(showBottomScrollHintAtom);
|
|
27
|
+
const setShowTopScrollHint = useSetAtom(showTopScrollHintAtom);
|
|
28
|
+
const [hasModalSubTitle, setHasModalSubTitle] = useState(
|
|
29
|
+
Boolean(contentRef.current?.querySelector('#modal-sub-title'))
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
/* istanbul ignore next */
|
|
33
|
+
const handleScroll = useCallback(
|
|
34
|
+
(contentRef: HTMLDivElement) => () => {
|
|
35
|
+
if (contentRef.scrollHeight > contentRef.clientHeight + 32) {
|
|
36
|
+
const atTheBottom =
|
|
37
|
+
Math.round(contentRef.scrollHeight - contentRef.scrollTop) - 5 < contentRef.clientHeight;
|
|
38
|
+
const atTheTop = contentRef.scrollTop < 10;
|
|
39
|
+
|
|
40
|
+
setShowBottomScrollHint(!atTheBottom);
|
|
41
|
+
setShowTopScrollHint(!atTheTop);
|
|
42
|
+
setScrollTop(contentRef.scrollTop);
|
|
43
|
+
} else if (contentRef.scrollTop === 0) {
|
|
44
|
+
setShowBottomScrollHint(false);
|
|
45
|
+
setShowTopScrollHint(false);
|
|
46
|
+
setScrollTop(0);
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
[setShowBottomScrollHint, setShowTopScrollHint, setScrollTop]
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const onScrollRef = useRef<ReturnType<typeof handleScroll>>(null);
|
|
53
|
+
|
|
54
|
+
// Trigger handleScroll on window resize
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
return effectEventListener(window, 'resize', () => onScrollRef.current?.());
|
|
57
|
+
}, [handleScroll]);
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Effect to detect presence of modal subtitle and adjust padding accordingly.
|
|
61
|
+
* Uses MutationObserver to handle dynamic content changes, particularly when
|
|
62
|
+
* content is loaded through a ContentPager component.
|
|
63
|
+
* Also triggers scroll hint updates when content changes.
|
|
64
|
+
*/
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (!contentRef.current) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Initial check for subtitle in the current content
|
|
71
|
+
const subTitle = contentRef.current.querySelector('#modal-sub-title');
|
|
72
|
+
|
|
73
|
+
setHasModalSubTitle(Boolean(subTitle));
|
|
74
|
+
|
|
75
|
+
// Set up MutationObserver to watch for changes in the modal content
|
|
76
|
+
const observer = new MutationObserver(() => {
|
|
77
|
+
// Get all content pager pages
|
|
78
|
+
const allPages = contentRef.current?.querySelectorAll('[data-page-name]');
|
|
79
|
+
|
|
80
|
+
// During transition, check the second page (incoming page)
|
|
81
|
+
// Otherwise check the first/only page
|
|
82
|
+
const targetPage = allPages && allPages.length > 1 ? allPages[1] : allPages?.[0];
|
|
83
|
+
const modalSubtitle = targetPage?.querySelector('#modal-sub-title');
|
|
84
|
+
|
|
85
|
+
setHasModalSubTitle(Boolean(modalSubtitle));
|
|
86
|
+
|
|
87
|
+
// Trigger scroll check when content changes (e.g., page navigation)
|
|
88
|
+
// This ensures scroll hints update immediately when switching to a page with different scroll state
|
|
89
|
+
onScrollRef.current?.();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Observe changes to the modal content structure
|
|
93
|
+
observer.observe(contentRef.current, {
|
|
94
|
+
childList: true,
|
|
95
|
+
subtree: true,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return () => observer.disconnect();
|
|
99
|
+
}, []);
|
|
100
|
+
|
|
101
|
+
// Reset scroll position when page changes in ContentPager
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (Boolean(currentPage) && contentRef.current && contentRef.current.scrollTop !== 0) {
|
|
104
|
+
contentRef.current.scrollTo({ behavior: 'smooth', top: 0 });
|
|
105
|
+
}
|
|
106
|
+
}, [currentPage]);
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<div
|
|
110
|
+
className={cn(
|
|
111
|
+
// GENERAL
|
|
112
|
+
'relative mb-2xl flex justify-center overflow-y-auto px-xl py-sm pt-md [scrollbar-gutter:stable-both-edges]',
|
|
113
|
+
|
|
114
|
+
// GROUP CLASSES FOR CONDITIONAL MARGIN BASED OFF FOOTER
|
|
115
|
+
'group-has-[#modal-footer.flex]:mb-0',
|
|
116
|
+
// ANIMATION
|
|
117
|
+
'transition-all duration-200 ease-in',
|
|
118
|
+
// MOBILE
|
|
119
|
+
'xsMax:px-sm xsMax:pb-xs',
|
|
120
|
+
// WITH SUBTITLE
|
|
121
|
+
{ '!pt-0': hasModalSubTitle },
|
|
122
|
+
// FULLSCREEN
|
|
123
|
+
'mobile:group-only/fullscreen:h-full',
|
|
124
|
+
// MOBILE FULLSCREEN
|
|
125
|
+
'mobile:group-only/fullscreen:mb-0 mobile:group-only/fullscreen:px-sm',
|
|
126
|
+
className
|
|
127
|
+
)}
|
|
128
|
+
data-testid="modal-content"
|
|
129
|
+
id="modal-content"
|
|
130
|
+
onTransitionEnd={() => {
|
|
131
|
+
// Check scroll hints after transitions complete (accordion animations, etc.)
|
|
132
|
+
onScrollRef.current?.();
|
|
133
|
+
}}
|
|
134
|
+
ref={(ref) => {
|
|
135
|
+
if (!ref) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
contentRef.current = ref;
|
|
139
|
+
|
|
140
|
+
const onScroll = handleScroll(ref);
|
|
141
|
+
onScrollRef.current = onScroll;
|
|
142
|
+
|
|
143
|
+
ref.addEventListener('scroll', onScroll);
|
|
144
|
+
|
|
145
|
+
// Initial scroll hint check
|
|
146
|
+
requestAnimationFrame(() => {
|
|
147
|
+
onScroll();
|
|
148
|
+
});
|
|
149
|
+
}}
|
|
150
|
+
style={{ scrollbarGutter: 'stable both-edges' }}
|
|
151
|
+
>
|
|
152
|
+
<div
|
|
153
|
+
className={cn(
|
|
154
|
+
'w-[460px] xsMax:w-[311px]',
|
|
155
|
+
// MOBILE FULLSCREEN
|
|
156
|
+
'mobile:group-only/fullscreen:w-full'
|
|
157
|
+
)}
|
|
158
|
+
>
|
|
159
|
+
{children}
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
);
|
|
163
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { cn } from '@evolve.ui/theme-system';
|
|
2
|
+
import { useAtomValue } from 'jotai';
|
|
3
|
+
import { ReactNode, useContext, useEffect, useMemo } from 'react';
|
|
4
|
+
|
|
5
|
+
import { useWindowIsMobile } from '../../../providers';
|
|
6
|
+
import { effectEventListener } from '../../../utils/effectEventListener';
|
|
7
|
+
import { ModalContext } from '../../context';
|
|
8
|
+
import { useCloseModal } from '../../hooks/useCloseModal';
|
|
9
|
+
import { useHeaderAnimation } from './hooks/useHeaderAnimation';
|
|
10
|
+
|
|
11
|
+
type Props = {
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
className?: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A styled container for the header of the modal.
|
|
18
|
+
*
|
|
19
|
+
* Automatically moves the `ModalTitle` farther into the header if scrolled.
|
|
20
|
+
* Automatically adds scroll hint below when `ModalContent` is scrollable.
|
|
21
|
+
*/
|
|
22
|
+
export const ModalHeader = ({ children, className }: Props) => {
|
|
23
|
+
const { scrollTopAtom, showTopScrollHintAtom } = useContext(ModalContext);
|
|
24
|
+
const scrollTop = useAtomValue(scrollTopAtom);
|
|
25
|
+
const showTopScrollHint = useAtomValue(showTopScrollHintAtom);
|
|
26
|
+
const { headerAnimations, setAnimationPercentage, storedAnimation } = useHeaderAnimation();
|
|
27
|
+
|
|
28
|
+
const isMobile = useWindowIsMobile();
|
|
29
|
+
const closeModal = useCloseModal('escape');
|
|
30
|
+
|
|
31
|
+
useMemo(() => {
|
|
32
|
+
if (Boolean(isMobile)) {
|
|
33
|
+
setAnimationPercentage(Math.max(1 - (Math.max(scrollTop, 32) - scrollTop) / 32, 0));
|
|
34
|
+
} else {
|
|
35
|
+
setAnimationPercentage(Math.max(1 - (Math.max(scrollTop, 48) - scrollTop) / 48, 0));
|
|
36
|
+
}
|
|
37
|
+
}, [isMobile, scrollTop, setAnimationPercentage]);
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const handleEsc = (event: Event) => {
|
|
41
|
+
if ((event as KeyboardEvent).key === 'Escape') {
|
|
42
|
+
closeModal();
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return effectEventListener(window, 'keydown', handleEsc);
|
|
47
|
+
}, [closeModal]);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<div
|
|
51
|
+
className={cn(
|
|
52
|
+
// GENERAL
|
|
53
|
+
'relative z-[1] mb-xs flex flex-col items-center justify-center px-2xl',
|
|
54
|
+
// ANIMATION
|
|
55
|
+
'transition-all duration-200 ease-in [animation-play-state:paused] [scrollbar-gutter:stable-both-edges]',
|
|
56
|
+
// SHADOW
|
|
57
|
+
{ 'shadow-01': showTopScrollHint },
|
|
58
|
+
// MOBILE
|
|
59
|
+
'xsMax:px-xs',
|
|
60
|
+
// MOBILE FULLSCREEN
|
|
61
|
+
'mobile:group-only/fullscreen:px-sm',
|
|
62
|
+
className
|
|
63
|
+
)}
|
|
64
|
+
ref={(ref) => {
|
|
65
|
+
if (!ref) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Needed for tests to pass
|
|
70
|
+
if (ref.getAnimations?.().length === 0) {
|
|
71
|
+
const animation = ref.animate(headerAnimations, {
|
|
72
|
+
duration: 1000,
|
|
73
|
+
fill: 'both',
|
|
74
|
+
iterations: Infinity,
|
|
75
|
+
});
|
|
76
|
+
animation.pause();
|
|
77
|
+
storedAnimation.current = animation;
|
|
78
|
+
}
|
|
79
|
+
}}
|
|
80
|
+
>
|
|
81
|
+
{children}
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
84
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { useAtomValue } from 'jotai';
|
|
2
|
+
import { useContext, useRef } from 'react';
|
|
3
|
+
|
|
4
|
+
import { useWindowIsMobile } from '../../../../providers';
|
|
5
|
+
import { useTheme } from '../../../../providers/themeContext';
|
|
6
|
+
import { ModalContext } from '../../../context';
|
|
7
|
+
|
|
8
|
+
export const useHeaderAnimation = () => {
|
|
9
|
+
const storedAnimation = useRef<Animation | undefined>(undefined);
|
|
10
|
+
const theme = useTheme();
|
|
11
|
+
const isMobile = useWindowIsMobile();
|
|
12
|
+
const { modalHasProgressStepsAtom } = useContext(ModalContext);
|
|
13
|
+
const modalHasProgressSteps = useAtomValue(modalHasProgressStepsAtom);
|
|
14
|
+
|
|
15
|
+
const headerAnimations = [
|
|
16
|
+
{
|
|
17
|
+
color: theme.color.text.standard,
|
|
18
|
+
fontFamily: theme.typography.heading['200'].family,
|
|
19
|
+
fontSize: theme.typography.heading['200'].size,
|
|
20
|
+
fontStyle: theme.typography.heading['200'].style,
|
|
21
|
+
fontWeight: theme.typography.heading['200'].weight,
|
|
22
|
+
letterSpacing: theme.typography.heading['200'].spacing,
|
|
23
|
+
lineHeight: theme.typography.heading['200'].height,
|
|
24
|
+
marginTop: isMobile ? '38px' : '48px',
|
|
25
|
+
paddingBottom: '0px',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
color: theme.color.text.standard,
|
|
29
|
+
fontFamily: theme.typography.heading['300'].family,
|
|
30
|
+
fontSize: theme.typography.heading['300'].size,
|
|
31
|
+
fontStyle: theme.typography.heading['300'].style,
|
|
32
|
+
fontWeight: theme.typography.heading['300'].weight,
|
|
33
|
+
letterSpacing: theme.typography.heading['300'].spacing,
|
|
34
|
+
lineHeight: theme.typography.heading['300'].height,
|
|
35
|
+
marginTop: isMobile ? '14px' : '22px',
|
|
36
|
+
paddingBottom: modalHasProgressSteps ? '8px' : isMobile ? '14px' : '22px',
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
const setAnimationPercentage = (percentage: number) => {
|
|
41
|
+
if (!storedAnimation.current) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
storedAnimation.current.currentTime = percentage * 999;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return { headerAnimations, setAnimationPercentage, storedAnimation };
|
|
49
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { cn } from '@evolve.ui/theme-system';
|
|
2
|
+
import { useSetAtom } from 'jotai';
|
|
3
|
+
import { ComponentProps, useContext, useEffect } from 'react';
|
|
4
|
+
|
|
5
|
+
import { ProgressSteps } from '../../../ProgressSteps/ProgressSteps';
|
|
6
|
+
import { ModalContext } from '../../context';
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
className?: string;
|
|
10
|
+
} & ComponentProps<typeof ProgressSteps>;
|
|
11
|
+
|
|
12
|
+
export const ModalProgressSteps = ({ className, ...props }: Props) => {
|
|
13
|
+
const { modalHasProgressStepsAtom } = useContext(ModalContext);
|
|
14
|
+
const setModalHasProgressSteps = useSetAtom(modalHasProgressStepsAtom);
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
setModalHasProgressSteps(true);
|
|
18
|
+
}, [setModalHasProgressSteps]);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<ProgressSteps
|
|
22
|
+
className={cn('pb-0 pt-xs', className)}
|
|
23
|
+
{...props}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { cn } from '@evolve.ui/theme-system';
|
|
2
|
+
|
|
3
|
+
import { BodyPrimary } from '../../../Typography/Text/Text';
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
className?: string;
|
|
8
|
+
['data-testid']?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Styled subtitle for modal.
|
|
13
|
+
*/
|
|
14
|
+
export const ModalSubTitle = ({ children, className, 'data-testid': dataTestId = 'modalSubTitle' }: Props) => {
|
|
15
|
+
return (
|
|
16
|
+
<div className={cn('-pt-sm mb-lg block w-full text-center', className)}>
|
|
17
|
+
<BodyPrimary
|
|
18
|
+
className={className}
|
|
19
|
+
color="secondary"
|
|
20
|
+
data-testid={dataTestId}
|
|
21
|
+
// `id` used in ModalContent
|
|
22
|
+
id="modal-sub-title"
|
|
23
|
+
>
|
|
24
|
+
{children}
|
|
25
|
+
</BodyPrimary>
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
ModalSubTitle.displayName = 'ModalSubTitle';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Styled title for modal.
|
|
5
|
+
*
|
|
6
|
+
* Automatically moves the `ModalTitle` farther into the header if `ModalContent` scrolled.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export const ModalTitle = ({
|
|
10
|
+
children,
|
|
11
|
+
'data-testid': dataTestId = 'modalTitle',
|
|
12
|
+
}: {
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
'data-testid'?: string;
|
|
15
|
+
}) => (
|
|
16
|
+
<span
|
|
17
|
+
className="px-md text-center xsMax:pt-[1px]"
|
|
18
|
+
data-testid={dataTestId}
|
|
19
|
+
>
|
|
20
|
+
{children}
|
|
21
|
+
</span>
|
|
22
|
+
);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
// Open modals share a single body scroll-lock. Module-scoped and ref-counted
|
|
4
|
+
// (local deviation from hammer — mirrors Drawer's lock): hammer's per-instance
|
|
5
|
+
// save/restore leaves the body locked forever when two instances overlap
|
|
6
|
+
// (docs pages embedding multiple open modals, auto-reopening stories), because
|
|
7
|
+
// the later instance saves the earlier one's `overflow: hidden` as "original".
|
|
8
|
+
// The first instance to mount captures the body's real styles + scroll
|
|
9
|
+
// position; the last to unmount restores them.
|
|
10
|
+
let openLockCount = 0;
|
|
11
|
+
let previousBodyStyles: {
|
|
12
|
+
overflow: string;
|
|
13
|
+
paddingRight: string;
|
|
14
|
+
position: string;
|
|
15
|
+
top: string;
|
|
16
|
+
width: string;
|
|
17
|
+
} | null = null;
|
|
18
|
+
let savedScrollPosition = 0;
|
|
19
|
+
let iosTouchCleanup: (() => void) | undefined;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Prevents scrolling of the page while the modal is open.
|
|
23
|
+
* Uses a unified approach with additional touch event handling for iOS Safari.
|
|
24
|
+
*
|
|
25
|
+
* Can be disabled with `preventScrollWhileOpen={false}` on the `Modal`.
|
|
26
|
+
*/
|
|
27
|
+
export const PreventModalScroll = () => {
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
const body = document.body;
|
|
30
|
+
|
|
31
|
+
if (openLockCount === 0) {
|
|
32
|
+
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
|
|
33
|
+
|
|
34
|
+
// Store current scroll position and original styles
|
|
35
|
+
savedScrollPosition = window.pageYOffset || document.documentElement.scrollTop;
|
|
36
|
+
previousBodyStyles = {
|
|
37
|
+
overflow: body.style.overflow,
|
|
38
|
+
paddingRight: body.style.paddingRight,
|
|
39
|
+
position: body.style.position,
|
|
40
|
+
top: body.style.top,
|
|
41
|
+
width: body.style.width,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Calculate scrollbar width and add padding to prevent content shift
|
|
45
|
+
const scrollBarWidth = window.innerWidth - document.documentElement.clientWidth;
|
|
46
|
+
if (scrollBarWidth > 0) {
|
|
47
|
+
body.style.paddingRight = `${scrollBarWidth}px`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Apply scroll prevention
|
|
51
|
+
body.style.overflow = 'hidden';
|
|
52
|
+
body.style.position = 'fixed';
|
|
53
|
+
body.style.top = `-${savedScrollPosition}px`;
|
|
54
|
+
body.style.width = '100%';
|
|
55
|
+
|
|
56
|
+
// iOS-specific touch event handling
|
|
57
|
+
if (isIOS) {
|
|
58
|
+
const preventDefault = (e: TouchEvent) => {
|
|
59
|
+
// Allow touch events on modal content but prevent on backdrop
|
|
60
|
+
const target = e.target as Element;
|
|
61
|
+
const isModalContent =
|
|
62
|
+
target.closest('[data-testid="modal-content"]') || target.closest('.hui-modal-container');
|
|
63
|
+
|
|
64
|
+
if (!isModalContent) {
|
|
65
|
+
e.preventDefault();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Add touch event listeners for iOS
|
|
70
|
+
document.addEventListener('touchstart', preventDefault, { passive: false });
|
|
71
|
+
document.addEventListener('touchmove', preventDefault, { passive: false });
|
|
72
|
+
|
|
73
|
+
iosTouchCleanup = () => {
|
|
74
|
+
document.removeEventListener('touchstart', preventDefault);
|
|
75
|
+
document.removeEventListener('touchmove', preventDefault);
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
openLockCount += 1;
|
|
81
|
+
|
|
82
|
+
// Cleanup function
|
|
83
|
+
return () => {
|
|
84
|
+
openLockCount -= 1;
|
|
85
|
+
|
|
86
|
+
if (openLockCount === 0) {
|
|
87
|
+
// Remove iOS touch event listeners if they exist
|
|
88
|
+
iosTouchCleanup?.();
|
|
89
|
+
iosTouchCleanup = undefined;
|
|
90
|
+
|
|
91
|
+
// Restore original styles
|
|
92
|
+
body.style.overflow = previousBodyStyles?.overflow ?? '';
|
|
93
|
+
body.style.position = previousBodyStyles?.position ?? '';
|
|
94
|
+
body.style.top = previousBodyStyles?.top ?? '';
|
|
95
|
+
body.style.width = previousBodyStyles?.width ?? '';
|
|
96
|
+
body.style.paddingRight = previousBodyStyles?.paddingRight ?? '';
|
|
97
|
+
previousBodyStyles = null;
|
|
98
|
+
|
|
99
|
+
// Restore scroll position
|
|
100
|
+
window.scrollTo(0, savedScrollPosition);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}, []);
|
|
104
|
+
|
|
105
|
+
return null;
|
|
106
|
+
};
|