@sproutsocial/seeds-react-modal 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +6 -0
- package/.eslintrc.js +4 -0
- package/.turbo/turbo-build.log +21 -0
- package/CHANGELOG.md +7 -0
- package/dist/esm/index.js +237 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/index.d.mts +76 -0
- package/dist/index.d.ts +76 -0
- package/dist/index.js +274 -0
- package/dist/index.js.map +1 -0
- package/jest.config.js +9 -0
- package/package.json +52 -0
- package/src/Modal.stories.tsx +420 -0
- package/src/Modal.tsx +160 -0
- package/src/ModalTypes.ts +67 -0
- package/src/__tests__/Modal.test.tsx +134 -0
- package/src/__tests__/Modal.typetest.tsx +209 -0
- package/src/index.ts +5 -0
- package/src/styled.d.ts +7 -0
- package/src/styles.tsx +141 -0
- package/tsconfig.json +9 -0
- package/tsup.config.ts +12 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { COLOR_PURPLE_300 } from "@sproutsocial/seeds-color";
|
|
4
|
+
import {
|
|
5
|
+
render,
|
|
6
|
+
fireEvent,
|
|
7
|
+
cleanup,
|
|
8
|
+
screen,
|
|
9
|
+
} from "@sproutsocial/seeds-react-testing-library";
|
|
10
|
+
import Modal from "../Modal";
|
|
11
|
+
|
|
12
|
+
afterEach(() => cleanup());
|
|
13
|
+
|
|
14
|
+
describe("Modal", () => {
|
|
15
|
+
it("renders a custom background color", () => {
|
|
16
|
+
// Use baseElement since it renders in a Portal
|
|
17
|
+
render(
|
|
18
|
+
<Modal
|
|
19
|
+
isOpen={true}
|
|
20
|
+
label="Label"
|
|
21
|
+
bg={COLOR_PURPLE_300}
|
|
22
|
+
onClose={() => {}}
|
|
23
|
+
closeButtonLabel="Close this dialog"
|
|
24
|
+
>
|
|
25
|
+
ajdsfljasdlfjlasdjf
|
|
26
|
+
</Modal>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
expect(screen.getByRole("dialog")).toHaveStyleRule(
|
|
30
|
+
"background-color",
|
|
31
|
+
COLOR_PURPLE_300
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("should close on overlay click and esc", () => {
|
|
36
|
+
const onClose = jest.fn();
|
|
37
|
+
render(
|
|
38
|
+
<Modal
|
|
39
|
+
isOpen={true}
|
|
40
|
+
label="Label"
|
|
41
|
+
bg={COLOR_PURPLE_300}
|
|
42
|
+
onClose={onClose}
|
|
43
|
+
closeButtonLabel="Close this dialog"
|
|
44
|
+
>
|
|
45
|
+
<Modal.Header>
|
|
46
|
+
<Modal.CloseButton />
|
|
47
|
+
</Modal.Header>
|
|
48
|
+
ajdsfljasdlfjlasdjf
|
|
49
|
+
</Modal>
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
fireEvent.click(screen.getByRole("dialog").parentElement as HTMLElement);
|
|
53
|
+
expect(onClose).toHaveBeenCalled();
|
|
54
|
+
|
|
55
|
+
onClose.mockClear();
|
|
56
|
+
fireEvent.keyDown(screen.getByText("ajdsfljasdlfjlasdjf"), {
|
|
57
|
+
key: "Escape",
|
|
58
|
+
keyCode: 27,
|
|
59
|
+
});
|
|
60
|
+
expect(onClose).toHaveBeenCalled();
|
|
61
|
+
|
|
62
|
+
onClose.mockClear();
|
|
63
|
+
fireEvent.click(screen.getByLabelText("Close this dialog"));
|
|
64
|
+
expect(onClose).toHaveBeenCalled();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should NOT close on overlay click and esc if onClick is not provided", () => {
|
|
68
|
+
const onClose = jest.fn();
|
|
69
|
+
const { baseElement, getByText, queryByLabelText } = render(
|
|
70
|
+
<Modal
|
|
71
|
+
isOpen={true}
|
|
72
|
+
label="Label"
|
|
73
|
+
bg={COLOR_PURPLE_300}
|
|
74
|
+
closeButtonLabel="Close this dialog"
|
|
75
|
+
>
|
|
76
|
+
ajdsfljasdlfjlasdjf
|
|
77
|
+
</Modal>
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
expect(queryByLabelText("Close this dialog")).not.toBeInTheDocument();
|
|
81
|
+
|
|
82
|
+
fireEvent.click(screen.getByRole("dialog").parentElement as HTMLElement);
|
|
83
|
+
expect(onClose).not.toHaveBeenCalled();
|
|
84
|
+
|
|
85
|
+
onClose.mockClear();
|
|
86
|
+
fireEvent.keyDown(screen.getByText("ajdsfljasdlfjlasdjf"), {
|
|
87
|
+
key: "Escape",
|
|
88
|
+
keyCode: 27,
|
|
89
|
+
});
|
|
90
|
+
expect(onClose).not.toHaveBeenCalled();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe("Modal.Header", () => {
|
|
94
|
+
it("should have an aria-label on the close button", () => {
|
|
95
|
+
render(
|
|
96
|
+
<Modal
|
|
97
|
+
isOpen={true}
|
|
98
|
+
label="Label"
|
|
99
|
+
bg={COLOR_PURPLE_300}
|
|
100
|
+
onClose={() => {}}
|
|
101
|
+
closeButtonLabel="Close this dialog"
|
|
102
|
+
>
|
|
103
|
+
<Modal.Header>
|
|
104
|
+
<Modal.CloseButton />
|
|
105
|
+
</Modal.Header>
|
|
106
|
+
ajdsfljasdlfjlasdjf
|
|
107
|
+
</Modal>
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
expect(screen.getByLabelText("Close this dialog")).toBeInTheDocument();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("should accept the onClose handler from ModalContext", () => {
|
|
114
|
+
const onClose = jest.fn();
|
|
115
|
+
render(
|
|
116
|
+
<Modal
|
|
117
|
+
isOpen={true}
|
|
118
|
+
label="Label"
|
|
119
|
+
bg={COLOR_PURPLE_300}
|
|
120
|
+
onClose={onClose}
|
|
121
|
+
closeButtonLabel="Close this dialog"
|
|
122
|
+
>
|
|
123
|
+
<Modal.Header>
|
|
124
|
+
<Modal.CloseButton />
|
|
125
|
+
</Modal.Header>
|
|
126
|
+
ajdsfljasdlfjlasdjf
|
|
127
|
+
</Modal>
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
fireEvent.click(screen.getByLabelText("Close this dialog"));
|
|
131
|
+
expect(onClose).toHaveBeenCalled();
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
});
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Box } from "@sproutsocial/seeds-react-box";
|
|
3
|
+
import { Button } from "@sproutsocial/seeds-react-button";
|
|
4
|
+
import { Input } from "@sproutsocial/seeds-react-input";
|
|
5
|
+
import { Text } from "@sproutsocial/seeds-react-text";
|
|
6
|
+
import Modal from "../Modal";
|
|
7
|
+
import FormField from "@sproutsocial/seeds-react-form-field";
|
|
8
|
+
|
|
9
|
+
const longContent = `
|
|
10
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
|
11
|
+
eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem
|
|
12
|
+
ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
|
13
|
+
tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum
|
|
14
|
+
dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
15
|
+
incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit
|
|
16
|
+
amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
17
|
+
incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit
|
|
18
|
+
amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
19
|
+
incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit
|
|
20
|
+
amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
21
|
+
incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit
|
|
22
|
+
amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
23
|
+
incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit
|
|
24
|
+
amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
25
|
+
incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit
|
|
26
|
+
amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
27
|
+
incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit
|
|
28
|
+
amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
29
|
+
incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit
|
|
30
|
+
amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
31
|
+
incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit
|
|
32
|
+
amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
33
|
+
incididunt ut labore et dolore magna aliqua.`;
|
|
34
|
+
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
36
|
+
function ModalTypeTest() {
|
|
37
|
+
return (
|
|
38
|
+
<>
|
|
39
|
+
<Modal
|
|
40
|
+
appElementSelector="#root"
|
|
41
|
+
isOpen={true}
|
|
42
|
+
onClose={jest.fn()}
|
|
43
|
+
closeButtonLabel="Close this dialog"
|
|
44
|
+
label="Example Modal"
|
|
45
|
+
>
|
|
46
|
+
<React.Fragment>
|
|
47
|
+
<Modal.Header
|
|
48
|
+
title="Assign Chatbot"
|
|
49
|
+
subtitle="The chatbot will respond to customers from this profile."
|
|
50
|
+
/>
|
|
51
|
+
<Modal.Content>{longContent}</Modal.Content>
|
|
52
|
+
<Modal.Footer>
|
|
53
|
+
<Button appearance="primary" width={1}>
|
|
54
|
+
Full-Width Button
|
|
55
|
+
</Button>
|
|
56
|
+
</Modal.Footer>
|
|
57
|
+
</React.Fragment>
|
|
58
|
+
</Modal>
|
|
59
|
+
<Modal
|
|
60
|
+
appElementSelector="#root"
|
|
61
|
+
isOpen={false}
|
|
62
|
+
closeButtonLabel="n/a"
|
|
63
|
+
label="Example Modal"
|
|
64
|
+
>
|
|
65
|
+
<React.Fragment>
|
|
66
|
+
<Modal.Content>{longContent}</Modal.Content>
|
|
67
|
+
<Modal.Footer>
|
|
68
|
+
<Button appearance="primary" width={1} onClick={jest.fn()}>
|
|
69
|
+
Must click to close
|
|
70
|
+
</Button>
|
|
71
|
+
</Modal.Footer>
|
|
72
|
+
</React.Fragment>
|
|
73
|
+
</Modal>
|
|
74
|
+
<Modal
|
|
75
|
+
appElementSelector="#root"
|
|
76
|
+
isOpen={true}
|
|
77
|
+
onClose={jest.fn()}
|
|
78
|
+
closeButtonLabel="Close this dialog"
|
|
79
|
+
label="Example Modal"
|
|
80
|
+
>
|
|
81
|
+
<React.Fragment>
|
|
82
|
+
<Modal.Header title="" subtitle="" bordered>
|
|
83
|
+
<Box width="100%" bg="purple.400">
|
|
84
|
+
Custom header
|
|
85
|
+
</Box>
|
|
86
|
+
</Modal.Header>
|
|
87
|
+
<Modal.Content>{longContent}</Modal.Content>
|
|
88
|
+
<Modal.Footer>
|
|
89
|
+
<Button appearance="primary" width={1}>
|
|
90
|
+
Full-Width Button
|
|
91
|
+
</Button>
|
|
92
|
+
</Modal.Footer>
|
|
93
|
+
</React.Fragment>
|
|
94
|
+
</Modal>
|
|
95
|
+
<Modal
|
|
96
|
+
appElementSelector="#root"
|
|
97
|
+
isOpen={false}
|
|
98
|
+
onClose={jest.fn()}
|
|
99
|
+
closeButtonLabel="Close this dialog"
|
|
100
|
+
label="Example Modal"
|
|
101
|
+
>
|
|
102
|
+
<React.Fragment>
|
|
103
|
+
<Modal.Header bordered>
|
|
104
|
+
<Box>
|
|
105
|
+
<Text as="h1" fontSize={400} fontWeight="semibold">
|
|
106
|
+
Assign Chatbot
|
|
107
|
+
</Text>
|
|
108
|
+
<Text as="div" fontSize={200}>
|
|
109
|
+
The chatbot will respond to customers from this profile.
|
|
110
|
+
</Text>
|
|
111
|
+
</Box>
|
|
112
|
+
<Box>
|
|
113
|
+
<button>dummy button 1</button>
|
|
114
|
+
<button>dummy button 2</button>
|
|
115
|
+
<Modal.CloseButton />
|
|
116
|
+
</Box>
|
|
117
|
+
</Modal.Header>
|
|
118
|
+
<Modal.Content>{longContent}</Modal.Content>
|
|
119
|
+
</React.Fragment>
|
|
120
|
+
</Modal>
|
|
121
|
+
<Modal
|
|
122
|
+
appElementSelector="#root"
|
|
123
|
+
isOpen={true}
|
|
124
|
+
onClose={jest.fn()}
|
|
125
|
+
closeButtonLabel="Close this dialog"
|
|
126
|
+
label="Example Modal"
|
|
127
|
+
>
|
|
128
|
+
<React.Fragment>
|
|
129
|
+
<Modal.Header />
|
|
130
|
+
<Modal.Content>{longContent}</Modal.Content>
|
|
131
|
+
<Modal.Footer>
|
|
132
|
+
<Button appearance="primary" width={1}>
|
|
133
|
+
Full-Width Button
|
|
134
|
+
</Button>
|
|
135
|
+
</Modal.Footer>
|
|
136
|
+
</React.Fragment>
|
|
137
|
+
</Modal>
|
|
138
|
+
<Modal
|
|
139
|
+
width="500px"
|
|
140
|
+
appElementSelector="#root"
|
|
141
|
+
isOpen={true}
|
|
142
|
+
onClose={jest.fn()}
|
|
143
|
+
closeButtonLabel="Close this dialog"
|
|
144
|
+
label="Example Modal"
|
|
145
|
+
>
|
|
146
|
+
<React.Fragment>
|
|
147
|
+
<Modal.Header
|
|
148
|
+
title="Create Share Link"
|
|
149
|
+
subtitle="Anyone with this link will be able to view its contents."
|
|
150
|
+
/>
|
|
151
|
+
<Modal.Content>
|
|
152
|
+
<FormField
|
|
153
|
+
label="Label"
|
|
154
|
+
helperText="This is some helpful helper text"
|
|
155
|
+
>
|
|
156
|
+
{
|
|
157
|
+
// is there a reason that the props are not passed to the input?
|
|
158
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
159
|
+
(props) => (
|
|
160
|
+
<Input
|
|
161
|
+
placeholder="Type the things..."
|
|
162
|
+
name="title"
|
|
163
|
+
id="title"
|
|
164
|
+
/>
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
</FormField>
|
|
168
|
+
</Modal.Content>
|
|
169
|
+
<Modal.Footer>
|
|
170
|
+
<Box display="flex" justifyContent="flex-end">
|
|
171
|
+
<Button appearance="primary">Create Link</Button>
|
|
172
|
+
</Box>
|
|
173
|
+
</Modal.Footer>
|
|
174
|
+
</React.Fragment>
|
|
175
|
+
</Modal>
|
|
176
|
+
<Modal
|
|
177
|
+
bg="container.background.decorative.purple"
|
|
178
|
+
width="500px"
|
|
179
|
+
appElementSelector="#root"
|
|
180
|
+
isOpen={true}
|
|
181
|
+
onClose={jest.fn()}
|
|
182
|
+
closeButtonLabel="Close this dialog"
|
|
183
|
+
label="Example Modal"
|
|
184
|
+
>
|
|
185
|
+
<React.Fragment>
|
|
186
|
+
<Modal.Header
|
|
187
|
+
title="Create Share Link"
|
|
188
|
+
subtitle="Anyone with this link will be able to view its contents."
|
|
189
|
+
/>
|
|
190
|
+
<Modal.Content>
|
|
191
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
|
192
|
+
eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem
|
|
193
|
+
ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
|
194
|
+
tempor incididunt ut labore et dolore magna aliqua.
|
|
195
|
+
</Modal.Content>
|
|
196
|
+
<Modal.Footer>
|
|
197
|
+
<Box display="flex" justifyContent="flex-end">
|
|
198
|
+
<Button appearance="primary">Create Link</Button>
|
|
199
|
+
</Box>
|
|
200
|
+
</Modal.Footer>
|
|
201
|
+
</React.Fragment>
|
|
202
|
+
</Modal>
|
|
203
|
+
{/* @ts-expect-error - test that missing required props is rejected */}
|
|
204
|
+
<Modal />
|
|
205
|
+
</>
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export default ModalTypeTest;
|
package/src/index.ts
ADDED
package/src/styled.d.ts
ADDED
package/src/styles.tsx
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import styled, { createGlobalStyle } from "styled-components";
|
|
3
|
+
import { width, zIndex } from "styled-system";
|
|
4
|
+
import ReactModal from "react-modal";
|
|
5
|
+
import { COMMON } from "@sproutsocial/seeds-react-system-props";
|
|
6
|
+
import Box, { type TypeContainerProps } from "@sproutsocial/seeds-react-box";
|
|
7
|
+
|
|
8
|
+
// This is the max space allowed between the modal and the edge of the browser
|
|
9
|
+
const BODY_PADDING = "64px";
|
|
10
|
+
|
|
11
|
+
const ReactModalAdapter = ({
|
|
12
|
+
className = "",
|
|
13
|
+
...props
|
|
14
|
+
}: { className?: string } & Omit<
|
|
15
|
+
ReactModal.Props,
|
|
16
|
+
"portalClassName" | "className" | "overlayClassName"
|
|
17
|
+
>) => {
|
|
18
|
+
// We want to create *__Content and *__Overlay class names on the subcomponents.
|
|
19
|
+
// Because `className` could be a space-separated list of class names, we make
|
|
20
|
+
// sure that we append `__Content` and `__Overlay` to every class name.
|
|
21
|
+
const contentClassName = className
|
|
22
|
+
.split(" ")
|
|
23
|
+
.map((className) => `${className} ${className}__Content`)
|
|
24
|
+
.join(" ");
|
|
25
|
+
|
|
26
|
+
const overlayClassName = className
|
|
27
|
+
.split(" ")
|
|
28
|
+
.map((className) => `${className} ${className}__Overlay`)
|
|
29
|
+
.join(" ");
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<ReactModal
|
|
33
|
+
portalClassName={className}
|
|
34
|
+
className={contentClassName}
|
|
35
|
+
overlayClassName={overlayClassName}
|
|
36
|
+
{...props}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const Body = createGlobalStyle`
|
|
42
|
+
.ReactModal__Body--open {
|
|
43
|
+
overflow: hidden;
|
|
44
|
+
}
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
export const Container = styled(ReactModalAdapter)<TypeContainerProps>`
|
|
48
|
+
&__Overlay {
|
|
49
|
+
position: fixed;
|
|
50
|
+
top: 0px;
|
|
51
|
+
left: 0px;
|
|
52
|
+
right: 0px;
|
|
53
|
+
bottom: 0px;
|
|
54
|
+
display: flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
justify-content: center;
|
|
57
|
+
background-color: ${(props) => props.theme.colors.overlay.background.base};
|
|
58
|
+
opacity: 0;
|
|
59
|
+
will-change: opacity;
|
|
60
|
+
transition: opacity ${(props) => props.theme.duration.medium}
|
|
61
|
+
${(props) => props.theme.easing.ease_inout};
|
|
62
|
+
|
|
63
|
+
${zIndex}
|
|
64
|
+
|
|
65
|
+
&.ReactModal__Overlay--after-open {
|
|
66
|
+
opacity: 1;
|
|
67
|
+
}
|
|
68
|
+
&.ReactModal__Overlay--before-close {
|
|
69
|
+
opacity: 0;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
&__Content {
|
|
74
|
+
display: flex;
|
|
75
|
+
flex-direction: column;
|
|
76
|
+
background: ${(props) => props.theme.colors.container.background.base};
|
|
77
|
+
border-radius: ${(props) => props.theme.radii[600]};
|
|
78
|
+
box-shadow: ${(props) => props.theme.shadows.medium};
|
|
79
|
+
filter: blur(0);
|
|
80
|
+
color: ${(props) => props.theme.colors.text.body};
|
|
81
|
+
|
|
82
|
+
outline: none;
|
|
83
|
+
max-width: calc(100vw - ${BODY_PADDING});
|
|
84
|
+
max-height: calc(100vh - ${BODY_PADDING});
|
|
85
|
+
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
|
|
86
|
+
/**
|
|
87
|
+
* This prevents the modal from being very short in IE11. Better too big
|
|
88
|
+
* than too small.
|
|
89
|
+
*/
|
|
90
|
+
height: calc(100vh - ${BODY_PADDING});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
${width}
|
|
94
|
+
|
|
95
|
+
${COMMON}
|
|
96
|
+
}
|
|
97
|
+
`;
|
|
98
|
+
|
|
99
|
+
export const Content = styled(Box)`
|
|
100
|
+
font-family: ${(props) => props.theme.fontFamily};
|
|
101
|
+
min-height: 80px;
|
|
102
|
+
overflow-y: auto;
|
|
103
|
+
flex: 1 1 auto;
|
|
104
|
+
padding: ${(props) => props.theme.space[400]}
|
|
105
|
+
${(props) => props.theme.space[450]};
|
|
106
|
+
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
|
|
107
|
+
/* 'flex-basis: auto' breaks overflow in IE11 */
|
|
108
|
+
flex-basis: 100%;
|
|
109
|
+
}
|
|
110
|
+
`;
|
|
111
|
+
|
|
112
|
+
export const HeaderContainer = styled(Box)`
|
|
113
|
+
font-family: ${(props) => props.theme.fontFamily};
|
|
114
|
+
padding: ${(props) => props.theme.space[400]}
|
|
115
|
+
${(props) => props.theme.space[450]};
|
|
116
|
+
`;
|
|
117
|
+
|
|
118
|
+
export const Header = styled(HeaderContainer)<{ bordered?: boolean }>`
|
|
119
|
+
display: flex;
|
|
120
|
+
align-items: center;
|
|
121
|
+
justify-content: space-between;
|
|
122
|
+
flex: 0 0 auto;
|
|
123
|
+
border-bottom-width: ${(props) => props.theme.borderWidths[500]};
|
|
124
|
+
border-bottom-color: ${(props) =>
|
|
125
|
+
props.bordered ? props.theme.colors.container.border.base : "transparent"};
|
|
126
|
+
border-bottom-style: solid;
|
|
127
|
+
`;
|
|
128
|
+
|
|
129
|
+
export const Footer = styled(Box)`
|
|
130
|
+
flex: 0 0 auto;
|
|
131
|
+
font-family: ${(props) => props.theme.fontFamily};
|
|
132
|
+
padding: ${(props) => props.theme.space[400]}
|
|
133
|
+
${(props) => props.theme.space[450]};
|
|
134
|
+
border-bottom-right-radius: ${(props) => props.theme.radii[500]};
|
|
135
|
+
border-bottom-left-radius: ${(props) => props.theme.radii[500]};
|
|
136
|
+
`;
|
|
137
|
+
|
|
138
|
+
Container.displayName = "ModalContainer";
|
|
139
|
+
Content.displayName = "Content";
|
|
140
|
+
Header.displayName = "Modal.Header";
|
|
141
|
+
Footer.displayName = "Modal.Footer";
|
package/tsconfig.json
ADDED
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { defineConfig } from "tsup";
|
|
2
|
+
|
|
3
|
+
export default defineConfig((options) => ({
|
|
4
|
+
entry: ["src/index.ts"],
|
|
5
|
+
format: ["cjs", "esm"],
|
|
6
|
+
clean: true,
|
|
7
|
+
legacyOutput: true,
|
|
8
|
+
dts: options.dts,
|
|
9
|
+
external: ["react"],
|
|
10
|
+
sourcemap: true,
|
|
11
|
+
metafile: options.metafile,
|
|
12
|
+
}));
|