-
Notifications
You must be signed in to change notification settings - Fork 153
/
index.tsx
112 lines (104 loc) · 3.71 KB
/
index.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import React, { DialogHTMLAttributes } from 'react';
import { BsX } from 'react-icons/bs';
import * as Dialog from '@radix-ui/react-dialog';
import { AccessibleIcon } from '@radix-ui/react-accessible-icon';
import { useIntl } from 'react-intl';
import { IsModalContextProvider } from 'app/contexts/ModalContext';
import { HeaderSettings } from 'app/contexts/LayoutSettingsContext';
import useReturnToFn from 'app/hooks/useReturnToFn';
import styles from './styles.module.css';
const PageModal: React.FC<DialogHTMLAttributes<HTMLDialogElement>> = function ({
children,
className,
...args
}) {
const goBack = useReturnToFn();
const { formatMessage } = useIntl();
return (
<IsModalContextProvider>
<HeaderSettings background="opaque" scrollBackground="opaque" />
<div
className={styles.pageContainer}
onPointerDown={goBack}
data-testid="scrim">
<dialog
data-testid="modal"
open
onPointerDown={(e) => e.stopPropagation()}
className={[className, styles.modal].join(' ')}
{...args}>
<button className={styles.closeButton} onPointerDown={goBack}>
<AccessibleIcon
label={formatMessage({
defaultMessage: 'Close',
description: 'Accessibility label for modal close button',
})}>
<BsX />
</AccessibleIcon>
</button>
{children}
</dialog>
</div>
</IsModalContextProvider>
);
};
const OverlayModal: React.FC<DialogHTMLAttributes<HTMLDialogElement>> =
function ({ children, className }) {
const goBack = useReturnToFn();
const { formatMessage } = useIntl();
return (
<IsModalContextProvider>
<Dialog.Root defaultOpen onOpenChange={(isOpen) => isOpen || goBack()}>
<Dialog.Overlay asChild>
<div
onPointerDown={goBack}
data-testid="scrim"
className={styles.modalContainer}>
<Dialog.Content
asChild
onEscapeKeyDown={() => goBack()}
onPointerDownOutside={(e) => e.preventDefault()}>
<dialog
data-testid="modal"
open
onPointerDown={(e) => e.stopPropagation()}
className={[className, styles.modal].join(' ')}>
<Dialog.Close className={styles.closeButton}>
<AccessibleIcon
label={formatMessage({
defaultMessage: 'Close',
description:
'Accessibility label for modal close button',
})}>
<BsX />
</AccessibleIcon>
</Dialog.Close>
{children}
</dialog>
</Dialog.Content>
</div>
</Dialog.Overlay>
</Dialog.Root>
</IsModalContextProvider>
);
};
/**
* A Modal or dialog box component
*
* Modals can be displayed in either "modal" or "page" mode, depending on how they were navigated
* to. In "modal" mode, it displays a scrim over the current page, while in "page" mode it displays
* the modal on top of a generic background. There are also minor behavioral differences between the
* two modes, primarily in how the modal behaves when it is closed.
*
* @param {string} displayMode - which style the modal should be displayed in
*/
const Modal: React.FC<
{ displayMode: 'modal' | 'page' } & DialogHTMLAttributes<HTMLDialogElement>
> = function ({ displayMode, ...args }) {
return displayMode === 'modal' ? (
<OverlayModal {...args} />
) : (
<PageModal {...args} />
);
};
export default Modal;