-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathModal.tsx
More file actions
129 lines (120 loc) · 3.51 KB
/
Modal.tsx
File metadata and controls
129 lines (120 loc) · 3.51 KB
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import { Dialog, Transition } from '@headlessui/react';
import classNames from 'classnames';
import React, { PropsWithChildren, Ref, forwardRef } from 'react';
import ReactDOM from 'react-dom';
export interface ModalProps {
isOpen: boolean;
onClose(): void;
maxWidth?: string;
initialFocus?: React.RefObject<HTMLElement>;
}
const Modal = ({
isOpen,
onClose,
maxWidth = 'lg',
children,
initialFocus,
}: PropsWithChildren<ModalProps>) => {
const maxWidthClass = {
sm: 'sm:max-w-sm',
md: 'sm:max-w-md',
lg: 'sm:max-w-lg',
xl: 'sm:max-w-xl',
'2xl': 'sm:max-w-2xl',
}[maxWidth];
if (typeof window === 'undefined') {
return null;
}
return ReactDOM.createPortal(
<Transition.Root show={isOpen} as={React.Fragment}>
<Dialog
as="div"
static
className="fixed z-10 inset-0 overflow-y-auto"
open={isOpen}
onClose={onClose}
initialFocus={initialFocus}
>
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
</Transition.Child>
{/* This element is to trick the browser into centering the modal contents. */}
<span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">
​
</span>
<Transition.Child
as={React.Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<div
className={classNames(
'inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:w-full',
maxWidthClass
)}
>
{children}
</div>
</Transition.Child>
</div>
</Dialog>
</Transition.Root>,
document.body
);
};
const ModalHeader = forwardRef(
(
{ children, className }: PropsWithChildren<{ className?: string }>,
ref?: Ref<HTMLDivElement>
) => {
return (
<div
ref={ref}
className={classNames('text-lg font-medium text-gray-900 mb-4 px-5 pt-5', className)}
>
{children}
</div>
);
}
);
const ModalBody = forwardRef(
(
{ children, className }: PropsWithChildren<{ className?: string }>,
ref?: Ref<HTMLDivElement>
) => {
return (
<div ref={ref} className={classNames('px-5 pt-0', className)}>
{children}
</div>
);
}
);
const ModalActions = forwardRef(
(
{ children, className }: PropsWithChildren<{ className?: string }>,
ref?: Ref<HTMLDivElement>
) => {
return (
<div
ref={ref}
className={classNames('px-5 py-4 mt-4 sm:px-6 sm:flex sm:flex-row-reverse', className)}
>
{children}
</div>
);
}
);
export { Modal, ModalActions, ModalBody, ModalHeader };