Skip to content

Commit

Permalink
Allow the Modal component to block scrolling on any HTML element in…
Browse files Browse the repository at this point in the history
…stead of just the `<body>` element (#472)
  • Loading branch information
mbohal committed Aug 28, 2023
1 parent 1bcf673 commit c7b944b
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 31 deletions.
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
54 changes: 36 additions & 18 deletions src/components/Modal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ React.createElement(() => {
const modalPrimaryButtonRef = React.useRef();
const modalCloseButtonRef = React.useRef();
return (
<>
<RUIProvider globalProps={{
Modal: { preventScrollUnderneath: window.document.documentElement }
}}>
<Button
label="Launch modal"
onClick={() => setModalOpen(true)}
Expand Down Expand Up @@ -66,7 +68,7 @@ React.createElement(() => {
</Modal>
)}
</div>
</>
</RUIProvider>
);
});
```
Expand Down Expand Up @@ -116,7 +118,9 @@ React.createElement(() => {
const modalPrimaryButtonRef = React.useRef();
const modalCloseButtonRef = React.useRef();
return (
<>
<RUIProvider globalProps={{
Modal: { preventScrollUnderneath: window.document.documentElement }
}}>
<Button
label="Launch blocking modal without title"
onClick={() => {
Expand Down Expand Up @@ -235,7 +239,7 @@ React.createElement(() => {
</Modal>
)}
</div>
</>
</RUIProvider>
);
});
```
Expand Down Expand Up @@ -265,7 +269,9 @@ React.createElement(() => {
const modalPrimaryButtonRef = React.useRef();
const modalCloseButtonRef = React.useRef();
return (
<>
<RUIProvider globalProps={{
Modal: { preventScrollUnderneath: window.document.documentElement }
}}>
<Button
label="Launch with close button"
onClick={() => {
Expand Down Expand Up @@ -356,7 +362,7 @@ React.createElement(() => {
</Modal>
)}
</div>
</>
</RUIProvider>
);
});
```
Expand Down Expand Up @@ -393,7 +399,9 @@ React.createElement(() => {
const modalPrimaryButtonRef = React.useRef();
const modalCloseButtonRef = React.useRef();
return (
<>
<RUIProvider globalProps={{
Modal: { preventScrollUnderneath: window.document.documentElement }
}}>
<Button
label="Launch modal with footer variants"
onClick={() => setModalOpen(true)}
Expand Down Expand Up @@ -493,7 +501,7 @@ React.createElement(() => {
</Modal>
)}
</div>
</>
</RUIProvider>
);
});
```
Expand All @@ -510,7 +518,9 @@ React.createElement(() => {
const modalPrimaryButtonRef = React.useRef();
const modalCloseButtonRef = React.useRef();
return (
<>
<RUIProvider globalProps={{
Modal: { preventScrollUnderneath: window.document.documentElement }
}}>
<Button
label="Launch small modal"
onClick={() => {
Expand Down Expand Up @@ -575,7 +585,7 @@ React.createElement(() => {
</Modal>
)}
</div>
</>
</RUIProvider>
);
});
```
Expand All @@ -588,7 +598,9 @@ React.createElement(() => {
const modalPrimaryButtonRef = React.useRef();
const modalCloseButtonRef = React.useRef();
return (
<>
<RUIProvider globalProps={{
Modal: { preventScrollUnderneath: window.document.documentElement }
}}>
<Button
label="Launch auto-width modal"
onClick={() => setModalOpen(true)}
Expand Down Expand Up @@ -629,7 +641,7 @@ React.createElement(() => {
</Modal>
)}
</div>
</>
</RUIProvider>
);
});
```
Expand All @@ -650,7 +662,9 @@ React.createElement(() => {
const modalPrimaryButtonRef = React.useRef();
const modalCloseButtonRef = React.useRef();
return (
<>
<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 +706,7 @@ React.createElement(() => {
</Modal>
)}
</div>
</>
</RUIProvider>
);
});
```
Expand All @@ -708,7 +722,9 @@ React.createElement(() => {
const modalPrimaryButtonRef = React.useRef();
const modalCloseButtonRef = React.useRef();
return (
<>
<RUIProvider globalProps={{
Modal: { preventScrollUnderneath: window.document.documentElement }
}}>
<Button
label="Launch modal at center"
onClick={() => {
Expand Down Expand Up @@ -759,7 +775,7 @@ React.createElement(() => {
</Modal>
)}
</div>
</>
</RUIProvider>
);
});
```
Expand Down Expand Up @@ -884,7 +900,9 @@ React.createElement(() => {
</ModalContent>
)
return (
<>
<RUIProvider globalProps={{
Modal: { preventScrollUnderneath: window.document.documentElement }
}}>
<Button
label="Launch modal with scrolling body"
onClick={() => {
Expand Down Expand Up @@ -945,7 +963,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

0 comments on commit c7b944b

Please sign in to comment.