fix(modal): inside and outside scroll (#2739)

This commit is contained in:
Junior Garcia 2024-04-16 13:31:35 -03:00 committed by GitHub
parent fdbfa1f299
commit 60c61aaf0c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 34 additions and 28 deletions

View File

@ -0,0 +1,6 @@
---
"@nextui-org/modal": patch
"@nextui-org/use-aria-modal-overlay": patch
---
Fix modal inside and outside scroll

View File

@ -54,8 +54,7 @@
"@react-aria/overlays": "^3.21.1",
"@react-aria/utils": "^3.23.2",
"@react-stately/overlays": "^3.6.5",
"@react-types/overlays": "^3.8.5",
"react-remove-scroll": "^2.5.6"
"@react-types/overlays": "^3.8.5"
},
"devDependencies": {
"@nextui-org/theme": "workspace:*",

View File

@ -1,12 +1,11 @@
import type {AriaDialogProps} from "@react-aria/dialog";
import type {HTMLMotionProps} from "framer-motion";
import {cloneElement, isValidElement, ReactNode, useMemo, useCallback, ReactElement} from "react";
import {cloneElement, isValidElement, ReactNode, useMemo, useCallback} from "react";
import {forwardRef} from "@nextui-org/system";
import {DismissButton} from "@react-aria/overlays";
import {TRANSITION_VARIANTS} from "@nextui-org/framer-utils";
import {CloseIcon} from "@nextui-org/shared-icons";
import {RemoveScroll} from "react-remove-scroll";
import {domAnimation, LazyMotion, m} from "framer-motion";
import {useDialog} from "@react-aria/dialog";
import {chain, mergeProps} from "@react-aria/utils";
@ -29,14 +28,12 @@ const ModalContent = forwardRef<"div", ModalContentProps, KeysToOmit>((props, _)
Component: DialogComponent,
domRef,
slots,
isOpen,
classNames,
motionProps,
backdrop,
closeButton,
hideCloseButton,
disableAnimation,
shouldBlockScroll,
getDialogProps,
getBackdropProps,
getCloseButtonProps,
@ -100,32 +97,22 @@ const ModalContent = forwardRef<"div", ModalContentProps, KeysToOmit>((props, _)
);
}, [backdrop, disableAnimation, getBackdropProps]);
const RemoveScrollWrapper = useCallback(
({children}: {children: ReactElement}) => {
return (
<RemoveScroll enabled={shouldBlockScroll && isOpen} removeScrollBar={false}>
{children}
</RemoveScroll>
);
},
[shouldBlockScroll, isOpen],
);
const contents = disableAnimation ? (
<RemoveScrollWrapper>
<div className={slots.wrapper({class: classNames?.wrapper})}>{content}</div>
</RemoveScrollWrapper>
<div className={slots.wrapper({class: classNames?.wrapper})} data-slot="wrapper">
{content}
</div>
) : (
<LazyMotion features={domAnimation}>
<m.div
animate="enter"
className={slots.wrapper({class: classNames?.wrapper})}
data-slot="wrapper"
exit="exit"
initial="exit"
variants={scaleInOut}
{...motionProps}
>
<RemoveScrollWrapper>{content}</RemoveScrollWrapper>
{content}
</m.div>
</LazyMotion>
);

View File

@ -122,6 +122,7 @@ export function useModal(originalProps: UseModalProps) {
const {modalProps, underlayProps} = useAriaModalOverlay(
{
isDismissable,
shouldBlockScroll,
isKeyboardDismissDisabled,
},
state,

View File

@ -65,7 +65,7 @@ export default {
},
decorators: [
(Story) => (
<div className="flex items-center justify-center w-screen h-screen">
<div className="flex justify-center items-center w-screen h-screen">
<Story />
</div>
),
@ -152,7 +152,7 @@ const InsideScrollTemplate = (args: ModalProps) => {
<ModalContent>
<ModalHeader>Modal Title</ModalHeader>
<ModalBody>
<Lorem count={5} />
<Lorem count={10} />
</ModalBody>
<ModalFooter>
<Button onPress={onClose}>Close</Button>
@ -173,7 +173,7 @@ const OutsideScrollTemplate = (args: ModalProps) => {
<ModalContent>
<ModalHeader>Modal Title</ModalHeader>
<ModalBody>
<Lorem count={5} />
<Lorem count={10} />
</ModalBody>
<ModalFooter>
<Button onPress={onClose}>Close</Button>

View File

@ -3,6 +3,7 @@ import {
AriaModalOverlayProps,
ModalOverlayAria,
useOverlay,
usePreventScroll,
useOverlayFocusContain,
} from "@react-aria/overlays";
import {mergeProps} from "@react-aria/utils";
@ -12,7 +13,11 @@ import {RefObject, useEffect} from "react";
export interface UseAriaModalOverlayProps extends AriaModalOverlayProps {}
export function useAriaModalOverlay(
props: UseAriaModalOverlayProps = {},
props: UseAriaModalOverlayProps & {
shouldBlockScroll?: boolean;
} = {
shouldBlockScroll: true,
},
state: OverlayTriggerState,
ref: RefObject<HTMLElement>,
): ModalOverlayAria {
@ -25,6 +30,10 @@ export function useAriaModalOverlay(
ref,
);
usePreventScroll({
isDisabled: !state.isOpen || !props.shouldBlockScroll,
});
useOverlayFocusContain();
useEffect(() => {

10
pnpm-lock.yaml generated
View File

@ -1801,9 +1801,6 @@ importers:
'@react-types/overlays':
specifier: ^3.8.5
version: 3.8.5(react@18.2.0)
react-remove-scroll:
specifier: ^2.5.6
version: 2.5.9(@types/react@18.2.8)(react@18.2.0)
devDependencies:
'@nextui-org/button':
specifier: workspace:*
@ -5888,6 +5885,10 @@ packages:
peerDependencies:
'@effect-ts/otel-node': '*'
peerDependenciesMeta:
'@effect-ts/core':
optional: true
'@effect-ts/otel':
optional: true
'@effect-ts/otel-node':
optional: true
dependencies:
@ -22381,6 +22382,9 @@ packages:
resolution: {integrity: sha512-W+gxAq7aQ9dJIg/XLKGcRT0cvnStFAQHPaI0pvD0U2l6IVLueUAm3nwN7lkY62zZNmlvNx6jNtE4wlbS+CyqSg==}
engines: {node: '>= 12.0.0'}
hasBin: true
peerDependenciesMeta:
'@parcel/core':
optional: true
dependencies:
'@parcel/config-default': 2.12.0(@parcel/core@2.12.0)(typescript@4.9.5)
'@parcel/core': 2.12.0