Skip to content

Commit

Permalink
feat: POC for isHidden prop on ModalDialog
Browse files Browse the repository at this point in the history
  • Loading branch information
adamstankiewicz committed Jul 11, 2023
1 parent 3b42102 commit 713934d
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 14 deletions.
6 changes: 3 additions & 3 deletions src/Modal/ModalContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ const ModalContext = React.createContext({
});

function ModalContextProvider({
onClose, isOpen, isBlocking, children,
onClose, isOpen, isHidden, isBlocking, children,

Check failure on line 9 in src/Modal/ModalContext.jsx

View workflow job for this annotation

GitHub Actions / tests

'isHidden' is missing in props validation
}) {
const modalContextValue = useMemo(
() => ({ onClose, isOpen, isBlocking }),
[onClose, isOpen, isBlocking],
() => ({ onClose, isOpen, isHidden, isBlocking }),

Check failure on line 12 in src/Modal/ModalContext.jsx

View workflow job for this annotation

GitHub Actions / tests

Expected a line break after this opening brace

Check failure on line 12 in src/Modal/ModalContext.jsx

View workflow job for this annotation

GitHub Actions / tests

Expected a line break before this closing brace
[onClose, isOpen, isHidden, isBlocking],
);

return (
Expand Down
3 changes: 2 additions & 1 deletion src/Modal/ModalDialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ function ModalDialog({
children,
title,
isOpen,
isHidden,

Check failure on line 23 in src/Modal/ModalDialog.jsx

View workflow job for this annotation

GitHub Actions / tests

'isHidden' is missing in props validation
onClose,
size,
variant,
Expand All @@ -34,7 +35,7 @@ function ModalDialog({
const isMobile = useMediaQuery({ query: '(max-width: 767.98px)' });
const showFullScreen = (isFullscreenOnMobile && isMobile);
return (
<ModalLayer isOpen={isOpen} onClose={onClose} isBlocking={isBlocking} zIndex={zIndex}>
<ModalLayer isOpen={isOpen} isHidden={isHidden} onClose={onClose} isBlocking={isBlocking} zIndex={zIndex}>
<div
role="dialog"
aria-label={title}
Expand Down
22 changes: 12 additions & 10 deletions src/Modal/ModalLayer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ ModalContentContainer.defaultProps = {
* component is that if a modal object is visible then it is "enabled"
*/
function ModalLayer({
children, onClose, isOpen, isBlocking, zIndex,
children, onClose, isOpen, isHidden, isBlocking, zIndex,

Check failure on line 42 in src/Modal/ModalLayer.jsx

View workflow job for this annotation

GitHub Actions / tests

'isHidden' is missing in props validation
}) {
useEffect(() => {
if (isOpen) {
Expand All @@ -52,29 +52,31 @@ function ModalLayer({
};
}, [isOpen]);

if (!isOpen) {
if (!isOpen && !isHidden) {
return null;
}

const onClickOutside = !isBlocking ? onClose : null;

return (
<ModalContextProvider onClose={onClose} isOpen={isOpen} isBlocking={isBlocking}>
<ModalContextProvider onClose={onClose} isOpen={isOpen} isHidden={isHidden} isBlocking={isBlocking}>
<Portal>
<FocusOn
allowPinchZoom
scrollLock
enabled={isOpen}
enabled={isOpen && !isHidden}
onEscapeKey={onClose}
onClickOutside={onClickOutside}
className={classNames(
'pgn__modal-layer',
zIndex ? `zindex-${zIndex}` : '',
)}
className={classNames({
'pgn__modal-layer': isOpen && !isHidden,
[`zindex-${zIndex}`]: !!zIndex,
})}
>
<ModalContentContainer>
<ModalBackdrop onClick={onClickOutside} />
{children}
{!isHidden && <ModalBackdrop onClick={onClickOutside} />}
<div className={classNames({ 'd-none': isHidden })}>
{children}
</div>
</ModalContentContainer>
</FocusOn>
</Portal>
Expand Down
50 changes: 50 additions & 0 deletions src/Modal/modal-dialog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,53 @@ label for the dialog element.
)
}
```

## With hidden modal contents

By default, ``ModalDialog`` only render its modal contents to the DOM when the modal is explicitly marked as open via the `isOpen` prop. However, in some cases, needing to re-render the contents of the modal body each and every time the modal closes and re-opens can be expensive and/or a poor user experience (UX), e.g. if the modal contents are dynamic and loaded from an external source like some iframed content or a slow loading API request.

To mitigate these performance concerns, ``ModalDialog`` supports an optional ``isHidden`` prop that when used in conjunction with ``isOpen``, would result in the modal contents and the backdrop still being kept in the React Portal DOM, but visually hidden in the UI.

```jsx live
() => {
const [isHidden, hideModal, showModal] = useToggle(true);
return (
<>
<div className="d-flex">
<Button variant="outline-primary" onClick={showModal}>Open standard modal dialog</Button>
</div>
<ModalDialog
title="My dialog"
isOpen /* always "open" */
isHidden={isHidden}
onClose={hideModal}
hasCloseButton
isFullscreenOnMobile
>
<ModalDialog.Header>
<ModalDialog.Title>
I'm a dialog box
</ModalDialog.Title>
</ModalDialog.Header>
<ModalDialog.Body>
<p>
I'm baby palo santo ugh celiac fashion axe. La croix lo-fi venmo whatever. Beard man braid migas single-origin coffee forage ramps. Tumeric messenger bag bicycle rights wayfarers, try-hard cronut blue bottle health goth. Sriracha tumblr cardigan, cloud bread succulents tumeric copper mug marfa semiotics woke next level organic roof party +1 try-hard.
</p>
</ModalDialog.Body>

<ModalDialog.Footer>
<ActionRow>
<ModalDialog.CloseButton variant="tertiary">
Cancel
</ModalDialog.CloseButton>
<Button variant="primary">
Continue
</Button>
</ActionRow>
</ModalDialog.Footer>
</ModalDialog>
</>
)
}
```

0 comments on commit 713934d

Please sign in to comment.