Skip to content

Commit 313341d

Browse files
committed
feat(Modal): added noUnmount prop to disable modal unmount when closed
1 parent 2dd6028 commit 313341d

File tree

3 files changed

+52
-5
lines changed

3 files changed

+52
-5
lines changed

src/components/Modal/Modal.stories.tsx

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { boolean, text } from '@storybook/addon-knobs';
2-
import React from 'react';
2+
import React, { useEffect, useState } from 'react';
33
import { action } from '../../storybook-helpers/action/action';
44
import { Button } from '../Button';
55
import { Modal } from '../Modal';
@@ -88,3 +88,33 @@ export const Scrolling = () => (
8888
<p style={{ whiteSpace: 'pre-wrap' }}>{lorem}</p>
8989
</Modal>
9090
);
91+
92+
const Timer = () => {
93+
const [seconds, setSeconds] = useState(0);
94+
useEffect(() => {
95+
const increment = () => setSeconds(prev => prev + 1);
96+
const timer = window.setInterval(increment, 1000);
97+
return () => {
98+
window.clearInterval(timer);
99+
};
100+
}, []);
101+
return (
102+
<p>
103+
Time passed: {seconds} second{seconds === 1 ? '' : 's'}
104+
</p>
105+
);
106+
};
107+
108+
export const UnmountExample = () => {
109+
const noUnmount = boolean('noUnmount', false);
110+
return (
111+
<Modal
112+
open={boolean('open', true)}
113+
onClose={action('onClose')}
114+
noUnmount={noUnmount}
115+
heading={noUnmount ? 'noUnmount true, time will persist' : 'noUnmount false, time will reset'}
116+
>
117+
<Timer />
118+
</Modal>
119+
);
120+
};

src/components/Modal/Modal.tsx

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ export interface ModalProps extends HTMLAttributes<HTMLDivElement> {
4747
* Modal does not have a max width.
4848
*/
4949
fullWidth?: boolean;
50+
/**
51+
* Do not unmount the modal when it is closed.
52+
*/
53+
noUnmount?: boolean;
5054
/**
5155
* Class for the outermost wrapper
5256
*/
@@ -71,6 +75,7 @@ export const Modal: FC<ModalProps> = ({
7175
open,
7276
onClose,
7377
fullWidth,
78+
noUnmount,
7479
wrapperClassName,
7580
closeLabel = 'Close',
7681
children,
@@ -82,6 +87,8 @@ export const Modal: FC<ModalProps> = ({
8287
}) => {
8388
const { mounted } = useUnmountDelay(open);
8489

90+
const unlocked = noUnmount && !mounted;
91+
8592
const headingId = useMemo(() => getStringId('modal_heading'), []);
8693
const bodyId = useMemo(() => getStringId('modal_body'), []);
8794

@@ -96,7 +103,7 @@ export const Modal: FC<ModalProps> = ({
96103
return;
97104
}, [closeOnEscape, onClose, open]);
98105

99-
const backgroundIsButton = !!(closeOnBackgroundClick && onClose);
106+
const backgroundIsButton = !!(open && closeOnBackgroundClick && onClose);
100107

101108
const modalWrapperClass = classnames(
102109
'ui__base ui__modal__wrapper',
@@ -107,7 +114,13 @@ export const Modal: FC<ModalProps> = ({
107114
wrapperClassName,
108115
);
109116

110-
const modalClass = classnames('ui__modal', className);
117+
const modalClass = classnames(
118+
'ui__modal',
119+
{
120+
'ui__modal--hidden': unlocked,
121+
},
122+
className,
123+
);
111124

112125
const bodyClass = classnames('ui__modal__body', {
113126
'ui__modal__body--noButton': !buttonGroup,
@@ -120,9 +133,9 @@ export const Modal: FC<ModalProps> = ({
120133
className={modalWrapperClass}
121134
onClick={backgroundIsButton ? onClose : undefined}
122135
>
123-
{mounted ? (
136+
{noUnmount || mounted ? (
124137
<div className="ui__modal__paddingFix">
125-
<FocusTrap focusLastOnUnlock locked>
138+
<FocusTrap focusLastOnUnlock locked={!unlocked}>
126139
<div
127140
aria-labelledby={heading ? headingId : undefined}
128141
aria-describedby={bodyId}

src/components/Modal/_Modal.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@
4242
overflow: hidden;
4343
width: 100%;
4444

45+
&--hidden {
46+
display: none;
47+
}
48+
4549
&__top {
4650
display: flex;
4751

0 commit comments

Comments
 (0)