mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
fix(modal): inside and outside scroll (#2739)
This commit is contained in:
parent
fdbfa1f299
commit
60c61aaf0c
6
.changeset/clever-ties-glow.md
Normal file
6
.changeset/clever-ties-glow.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"@nextui-org/modal": patch
|
||||
"@nextui-org/use-aria-modal-overlay": patch
|
||||
---
|
||||
|
||||
Fix modal inside and outside scroll
|
||||
@ -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:*",
|
||||
|
||||
@ -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>
|
||||
);
|
||||
|
||||
@ -122,6 +122,7 @@ export function useModal(originalProps: UseModalProps) {
|
||||
const {modalProps, underlayProps} = useAriaModalOverlay(
|
||||
{
|
||||
isDismissable,
|
||||
shouldBlockScroll,
|
||||
isKeyboardDismissDisabled,
|
||||
},
|
||||
state,
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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
10
pnpm-lock.yaml
generated
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user