Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow the Modal component to block scrolling on any HTML element instead of just the <body> element (#472) #482

Merged
merged 1 commit into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/components/Modal/Modal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ Modal.defaultProps = {
closeButtonRef: null,
portalId: null,
position: 'center',
preventScrollUnderneath: 'default',
preventScrollUnderneath: window.document.body,
primaryButtonRef: null,
size: 'medium',
};
Expand Down Expand Up @@ -137,15 +137,15 @@ Modal.propTypes = {
position: PropTypes.oneOf(['top', 'center']),
/**
* Mode in which Modal prevents scroll of elements bellow:
* * `default` - Modal prevents scroll on the `body` element
* * `off` - Modal does not prevent any scroll
* * [HTMLElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement) - Modal prevents scroll on this HTML element
* * object
* * * `reset` - method called on Modal's unmount to reset scroll prevention
* * * `start` - method called on Modal's mount to custom scroll prevention
* * `reset` - method called on Modal's unmount to reset scroll prevention
* * `start` - method called on Modal's mount to custom scroll prevention
*/
preventScrollUnderneath: PropTypes.oneOfType([
PropTypes.oneOf([
'default',
HTMLElement,
'off',
]),
PropTypes.shape({
Expand Down
90 changes: 72 additions & 18 deletions src/components/Modal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ React.createElement(() => {
const modalPrimaryButtonRef = React.useRef();
const modalCloseButtonRef = React.useRef();
return (
<>
{/*
The `preventScrollUnderneath` feature is necessary for Modals to work in
React UI docs. You may not need it in your application.
*/}
<RUIProvider globalProps={{
Modal: { preventScrollUnderneath: window.document.documentElement }
bedrich-schindler marked this conversation as resolved.
Show resolved Hide resolved
}}>
adamkudrna marked this conversation as resolved.
Show resolved Hide resolved
<Button
label="Launch modal"
onClick={() => setModalOpen(true)}
Expand Down Expand Up @@ -66,7 +72,7 @@ React.createElement(() => {
</Modal>
)}
</div>
</>
</RUIProvider>
);
});
```
Expand Down Expand Up @@ -116,7 +122,13 @@ React.createElement(() => {
const modalPrimaryButtonRef = React.useRef();
const modalCloseButtonRef = React.useRef();
return (
<>
{/*
The `preventScrollUnderneath` feature is necessary for Modals to work in
React UI docs. You may not need it in your application.
*/}
<RUIProvider globalProps={{
Modal: { preventScrollUnderneath: window.document.documentElement }
}}>
<Button
label="Launch blocking modal without title"
onClick={() => {
Expand Down Expand Up @@ -235,7 +247,7 @@ React.createElement(() => {
</Modal>
)}
</div>
</>
</RUIProvider>
);
});
```
Expand Down Expand Up @@ -265,7 +277,13 @@ React.createElement(() => {
const modalPrimaryButtonRef = React.useRef();
const modalCloseButtonRef = React.useRef();
return (
<>
{/*
The `preventScrollUnderneath` feature is necessary for Modals to work in
React UI docs. You may not need it in your application.
*/}
<RUIProvider globalProps={{
Modal: { preventScrollUnderneath: window.document.documentElement }
}}>
<Button
label="Launch with close button"
onClick={() => {
Expand Down Expand Up @@ -356,7 +374,7 @@ React.createElement(() => {
</Modal>
)}
</div>
</>
</RUIProvider>
);
});
```
Expand Down Expand Up @@ -393,7 +411,13 @@ React.createElement(() => {
const modalPrimaryButtonRef = React.useRef();
const modalCloseButtonRef = React.useRef();
return (
<>
{/*
The `preventScrollUnderneath` feature is necessary for Modals to work in
React UI docs. You may not need it in your application.
*/}
<RUIProvider globalProps={{
Modal: { preventScrollUnderneath: window.document.documentElement }
}}>
<Button
label="Launch modal with footer variants"
onClick={() => setModalOpen(true)}
Expand Down Expand Up @@ -493,7 +517,7 @@ React.createElement(() => {
</Modal>
)}
</div>
</>
</RUIProvider>
);
});
```
Expand All @@ -510,7 +534,13 @@ React.createElement(() => {
const modalPrimaryButtonRef = React.useRef();
const modalCloseButtonRef = React.useRef();
return (
<>
{/*
The `preventScrollUnderneath` feature is necessary for Modals to work in
React UI docs. You may not need it in your application.
*/}
<RUIProvider globalProps={{
Modal: { preventScrollUnderneath: window.document.documentElement }
}}>
<Button
label="Launch small modal"
onClick={() => {
Expand Down Expand Up @@ -575,7 +605,7 @@ React.createElement(() => {
</Modal>
)}
</div>
</>
</RUIProvider>
);
});
```
Expand All @@ -588,7 +618,13 @@ React.createElement(() => {
const modalPrimaryButtonRef = React.useRef();
const modalCloseButtonRef = React.useRef();
return (
<>
{/*
The `preventScrollUnderneath` feature is necessary for Modals to work in
React UI docs. You may not need it in your application.
*/}
<RUIProvider globalProps={{
Modal: { preventScrollUnderneath: window.document.documentElement }
}}>
<Button
label="Launch auto-width modal"
onClick={() => setModalOpen(true)}
Expand Down Expand Up @@ -629,7 +665,7 @@ React.createElement(() => {
</Modal>
)}
</div>
</>
</RUIProvider>
);
});
```
Expand All @@ -650,7 +686,13 @@ React.createElement(() => {
const modalPrimaryButtonRef = React.useRef();
const modalCloseButtonRef = React.useRef();
return (
<>
{/*
The `preventScrollUnderneath` feature is necessary for Modals to work in
React UI docs. You may not need it in your application.
*/}
<RUIProvider globalProps={{
Modal: { preventScrollUnderneath: window.document.documentElement }
}}>
<Button
label="Launch auto-with modal with a form"
onClick={() => setModalOpen(true)}
Expand Down Expand Up @@ -692,7 +734,7 @@ React.createElement(() => {
</Modal>
)}
</div>
</>
</RUIProvider>
);
});
```
Expand All @@ -708,7 +750,13 @@ React.createElement(() => {
const modalPrimaryButtonRef = React.useRef();
const modalCloseButtonRef = React.useRef();
return (
<>
{/*
The `preventScrollUnderneath` feature is necessary for Modals to work in
React UI docs. You may not need it in your application.
*/}
<RUIProvider globalProps={{
Modal: { preventScrollUnderneath: window.document.documentElement }
}}>
<Button
label="Launch modal at center"
onClick={() => {
Expand Down Expand Up @@ -759,7 +807,7 @@ React.createElement(() => {
</Modal>
)}
</div>
</>
</RUIProvider>
);
});
```
Expand Down Expand Up @@ -884,7 +932,13 @@ React.createElement(() => {
</ModalContent>
)
return (
<>
{/*
The `preventScrollUnderneath` feature is necessary for Modals to work in
React UI docs. You may not need it in your application.
*/}
<RUIProvider globalProps={{
Modal: { preventScrollUnderneath: window.document.documentElement }
}}>
<Button
label="Launch modal with scrolling body"
onClick={() => {
Expand Down Expand Up @@ -945,7 +999,7 @@ React.createElement(() => {
</Modal>
)}
</div>
</>
</RUIProvider>
);
});
```
Expand Down
18 changes: 10 additions & 8 deletions src/components/Modal/_hooks/useModalScrollPrevention.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,24 @@ export const useModalScrollPrevention = (preventScrollUnderneath) => {
return () => {};
}

if (preventScrollUnderneath === 'default') {
if (preventScrollUnderneath instanceof HTMLElement) {
const scrollableElement = preventScrollUnderneath;

const scrollbarWidth = Math.abs(window.innerWidth - window.document.documentElement.clientWidth);
const prevOverflow = window.document.body.style.overflow;
const prevPaddingRight = window.document.body.style.paddingRight;
const prevOverflow = scrollableElement.style.overflow;
const prevPaddingRight = scrollableElement.style.paddingRight;

window.document.body.style.overflow = 'hidden';
scrollableElement.style.overflow = 'hidden';

if (Number.isNaN(parseInt(prevPaddingRight, 10))) {
window.document.body.style.paddingRight = `${scrollbarWidth}px`;
scrollableElement.style.paddingRight = `${scrollbarWidth}px`;
} else {
window.document.body.style.paddingRight = `calc(${prevPaddingRight} + ${scrollbarWidth}px)`;
scrollableElement.style.paddingRight = `calc(${prevPaddingRight} + ${scrollbarWidth}px)`;
}

return () => {
window.document.body.style.overflow = prevOverflow;
window.document.body.style.paddingRight = prevPaddingRight;
scrollableElement.style.overflow = prevOverflow;
scrollableElement.style.paddingRight = prevPaddingRight;
};
}

Expand Down