@instructure/ui-modal 11.6.0 → 11.6.1-snapshot-129
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/CHANGELOG.md +49 -311
- package/es/Modal/{ModalBody → v1/ModalBody}/index.js +2 -2
- package/es/Modal/{ModalFooter → v1/ModalFooter}/index.js +1 -1
- package/es/Modal/{ModalHeader → v1/ModalHeader}/index.js +2 -2
- package/es/Modal/{index.js → v1/index.js} +2 -2
- package/es/Modal/v2/ModalBody/index.js +132 -0
- package/es/Modal/v2/ModalBody/props.js +26 -0
- package/es/Modal/v2/ModalBody/styles.js +68 -0
- package/es/Modal/v2/ModalContext.js +34 -0
- package/es/Modal/v2/ModalFooter/index.js +73 -0
- package/es/{index.js → Modal/v2/ModalFooter/props.js} +3 -1
- package/es/Modal/v2/ModalFooter/styles.js +60 -0
- package/es/Modal/v2/ModalHeader/index.js +112 -0
- package/es/Modal/v2/ModalHeader/props.js +26 -0
- package/es/Modal/v2/ModalHeader/styles.js +76 -0
- package/es/Modal/v2/index.js +259 -0
- package/es/Modal/v2/props.js +26 -0
- package/es/Modal/v2/styles.js +119 -0
- package/es/exports/a.js +24 -0
- package/es/exports/b.js +24 -0
- package/lib/Modal/{ModalBody → v1/ModalBody}/index.js +4 -4
- package/lib/Modal/{ModalFooter → v1/ModalFooter}/index.js +1 -1
- package/lib/Modal/{ModalHeader → v1/ModalHeader}/index.js +3 -3
- package/lib/Modal/v1/index.js +285 -0
- package/lib/Modal/v2/ModalBody/index.js +137 -0
- package/lib/Modal/v2/ModalBody/props.js +31 -0
- package/lib/Modal/v2/ModalBody/styles.js +74 -0
- package/lib/Modal/v2/ModalContext.js +39 -0
- package/lib/Modal/v2/ModalFooter/index.js +78 -0
- package/lib/Modal/v2/ModalFooter/props.js +31 -0
- package/lib/Modal/v2/ModalFooter/styles.js +66 -0
- package/lib/Modal/v2/ModalHeader/index.js +118 -0
- package/lib/Modal/v2/ModalHeader/props.js +31 -0
- package/lib/Modal/v2/ModalHeader/styles.js +82 -0
- package/lib/Modal/{index.js → v2/index.js} +3 -4
- package/lib/Modal/v2/props.js +31 -0
- package/lib/Modal/v2/styles.js +125 -0
- package/lib/{index.js → exports/a.js} +5 -5
- package/lib/exports/b.js +30 -0
- package/package.json +46 -24
- package/src/Modal/{ModalBody → v1/ModalBody}/index.tsx +2 -2
- package/src/Modal/{ModalFooter → v1/ModalFooter}/index.tsx +1 -1
- package/src/Modal/{ModalHeader → v1/ModalHeader}/index.tsx +3 -3
- package/src/Modal/{index.tsx → v1/index.tsx} +2 -2
- package/src/Modal/v2/ModalBody/index.tsx +164 -0
- package/src/Modal/v2/ModalBody/props.ts +72 -0
- package/src/Modal/v2/ModalBody/styles.ts +76 -0
- package/src/Modal/v2/ModalContext.ts +46 -0
- package/src/Modal/v2/ModalFooter/index.tsx +80 -0
- package/src/Modal/v2/ModalFooter/props.ts +50 -0
- package/src/Modal/v2/ModalFooter/styles.ts +74 -0
- package/src/Modal/v2/ModalHeader/index.tsx +138 -0
- package/src/Modal/v2/ModalHeader/props.ts +54 -0
- package/src/Modal/v2/ModalHeader/styles.ts +99 -0
- package/src/Modal/v2/README.md +673 -0
- package/src/Modal/v2/index.tsx +326 -0
- package/src/Modal/v2/props.ts +235 -0
- package/src/Modal/v2/styles.ts +130 -0
- package/src/{index.ts → exports/a.ts} +5 -5
- package/src/exports/b.ts +29 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/Modal/v1/ModalBody/index.d.ts.map +1 -0
- package/types/Modal/v1/ModalBody/props.d.ts.map +1 -0
- package/types/Modal/v1/ModalBody/styles.d.ts.map +1 -0
- package/types/Modal/v1/ModalBody/theme.d.ts.map +1 -0
- package/types/Modal/v1/ModalContext.d.ts.map +1 -0
- package/types/Modal/v1/ModalFooter/index.d.ts.map +1 -0
- package/types/Modal/v1/ModalFooter/props.d.ts.map +1 -0
- package/types/Modal/v1/ModalFooter/styles.d.ts.map +1 -0
- package/types/Modal/v1/ModalFooter/theme.d.ts.map +1 -0
- package/types/Modal/v1/ModalHeader/index.d.ts.map +1 -0
- package/types/Modal/v1/ModalHeader/props.d.ts.map +1 -0
- package/types/Modal/v1/ModalHeader/styles.d.ts.map +1 -0
- package/types/Modal/v1/ModalHeader/theme.d.ts.map +1 -0
- package/types/Modal/v1/index.d.ts.map +1 -0
- package/types/Modal/v1/props.d.ts.map +1 -0
- package/types/Modal/v1/styles.d.ts.map +1 -0
- package/types/Modal/v1/theme.d.ts.map +1 -0
- package/types/Modal/v2/ModalBody/index.d.ts +36 -0
- package/types/Modal/v2/ModalBody/index.d.ts.map +1 -0
- package/types/Modal/v2/ModalBody/props.d.ts +23 -0
- package/types/Modal/v2/ModalBody/props.d.ts.map +1 -0
- package/types/Modal/v2/ModalBody/styles.d.ts +16 -0
- package/types/Modal/v2/ModalBody/styles.d.ts.map +1 -0
- package/types/Modal/v2/ModalContext.d.ts +17 -0
- package/types/Modal/v2/ModalContext.d.ts.map +1 -0
- package/types/Modal/v2/ModalFooter/index.d.ts +27 -0
- package/types/Modal/v2/ModalFooter/index.d.ts.map +1 -0
- package/types/Modal/v2/ModalFooter/props.d.ts +16 -0
- package/types/Modal/v2/ModalFooter/props.d.ts.map +1 -0
- package/types/Modal/v2/ModalFooter/styles.d.ts +16 -0
- package/types/Modal/v2/ModalFooter/styles.d.ts.map +1 -0
- package/types/Modal/v2/ModalHeader/index.d.ts +37 -0
- package/types/Modal/v2/ModalHeader/index.d.ts.map +1 -0
- package/types/Modal/v2/ModalHeader/props.d.ts +19 -0
- package/types/Modal/v2/ModalHeader/props.d.ts.map +1 -0
- package/types/Modal/v2/ModalHeader/styles.d.ts +16 -0
- package/types/Modal/v2/ModalHeader/styles.d.ts.map +1 -0
- package/types/Modal/v2/index.d.ts +54 -0
- package/types/Modal/v2/index.d.ts.map +1 -0
- package/types/Modal/v2/props.d.ts +132 -0
- package/types/Modal/v2/props.d.ts.map +1 -0
- package/types/Modal/v2/styles.d.ts +16 -0
- package/types/Modal/v2/styles.d.ts.map +1 -0
- package/types/exports/a.d.ts +6 -0
- package/types/exports/a.d.ts.map +1 -0
- package/types/exports/b.d.ts +6 -0
- package/types/exports/b.d.ts.map +1 -0
- package/types/Modal/ModalBody/index.d.ts.map +0 -1
- package/types/Modal/ModalBody/props.d.ts.map +0 -1
- package/types/Modal/ModalBody/styles.d.ts.map +0 -1
- package/types/Modal/ModalBody/theme.d.ts.map +0 -1
- package/types/Modal/ModalContext.d.ts.map +0 -1
- package/types/Modal/ModalFooter/index.d.ts.map +0 -1
- package/types/Modal/ModalFooter/props.d.ts.map +0 -1
- package/types/Modal/ModalFooter/styles.d.ts.map +0 -1
- package/types/Modal/ModalFooter/theme.d.ts.map +0 -1
- package/types/Modal/ModalHeader/index.d.ts.map +0 -1
- package/types/Modal/ModalHeader/props.d.ts.map +0 -1
- package/types/Modal/ModalHeader/styles.d.ts.map +0 -1
- package/types/Modal/ModalHeader/theme.d.ts.map +0 -1
- package/types/Modal/index.d.ts.map +0 -1
- package/types/Modal/props.d.ts.map +0 -1
- package/types/Modal/styles.d.ts.map +0 -1
- package/types/Modal/theme.d.ts.map +0 -1
- package/types/index.d.ts +0 -6
- package/types/index.d.ts.map +0 -1
- /package/es/Modal/{ModalBody → v1/ModalBody}/props.js +0 -0
- /package/es/Modal/{ModalBody → v1/ModalBody}/styles.js +0 -0
- /package/es/Modal/{ModalBody → v1/ModalBody}/theme.js +0 -0
- /package/es/Modal/{ModalContext.js → v1/ModalContext.js} +0 -0
- /package/es/Modal/{ModalFooter → v1/ModalFooter}/props.js +0 -0
- /package/es/Modal/{ModalFooter → v1/ModalFooter}/styles.js +0 -0
- /package/es/Modal/{ModalFooter → v1/ModalFooter}/theme.js +0 -0
- /package/es/Modal/{ModalHeader → v1/ModalHeader}/props.js +0 -0
- /package/es/Modal/{ModalHeader → v1/ModalHeader}/styles.js +0 -0
- /package/es/Modal/{ModalHeader → v1/ModalHeader}/theme.js +0 -0
- /package/es/Modal/{props.js → v1/props.js} +0 -0
- /package/es/Modal/{styles.js → v1/styles.js} +0 -0
- /package/es/Modal/{theme.js → v1/theme.js} +0 -0
- /package/lib/Modal/{ModalBody → v1/ModalBody}/props.js +0 -0
- /package/lib/Modal/{ModalBody → v1/ModalBody}/styles.js +0 -0
- /package/lib/Modal/{ModalBody → v1/ModalBody}/theme.js +0 -0
- /package/lib/Modal/{ModalContext.js → v1/ModalContext.js} +0 -0
- /package/lib/Modal/{ModalFooter → v1/ModalFooter}/props.js +0 -0
- /package/lib/Modal/{ModalFooter → v1/ModalFooter}/styles.js +0 -0
- /package/lib/Modal/{ModalFooter → v1/ModalFooter}/theme.js +0 -0
- /package/lib/Modal/{ModalHeader → v1/ModalHeader}/props.js +0 -0
- /package/lib/Modal/{ModalHeader → v1/ModalHeader}/styles.js +0 -0
- /package/lib/Modal/{ModalHeader → v1/ModalHeader}/theme.js +0 -0
- /package/lib/Modal/{props.js → v1/props.js} +0 -0
- /package/lib/Modal/{styles.js → v1/styles.js} +0 -0
- /package/lib/Modal/{theme.js → v1/theme.js} +0 -0
- /package/src/Modal/{ModalBody → v1/ModalBody}/props.ts +0 -0
- /package/src/Modal/{ModalBody → v1/ModalBody}/styles.ts +0 -0
- /package/src/Modal/{ModalBody → v1/ModalBody}/theme.ts +0 -0
- /package/src/Modal/{ModalContext.ts → v1/ModalContext.ts} +0 -0
- /package/src/Modal/{ModalFooter → v1/ModalFooter}/props.ts +0 -0
- /package/src/Modal/{ModalFooter → v1/ModalFooter}/styles.ts +0 -0
- /package/src/Modal/{ModalFooter → v1/ModalFooter}/theme.ts +0 -0
- /package/src/Modal/{ModalHeader → v1/ModalHeader}/props.ts +0 -0
- /package/src/Modal/{ModalHeader → v1/ModalHeader}/styles.ts +0 -0
- /package/src/Modal/{ModalHeader → v1/ModalHeader}/theme.ts +0 -0
- /package/src/Modal/{README.md → v1/README.md} +0 -0
- /package/src/Modal/{props.ts → v1/props.ts} +0 -0
- /package/src/Modal/{styles.ts → v1/styles.ts} +0 -0
- /package/src/Modal/{theme.ts → v1/theme.ts} +0 -0
- /package/types/Modal/{ModalBody → v1/ModalBody}/index.d.ts +0 -0
- /package/types/Modal/{ModalBody → v1/ModalBody}/props.d.ts +0 -0
- /package/types/Modal/{ModalBody → v1/ModalBody}/styles.d.ts +0 -0
- /package/types/Modal/{ModalBody → v1/ModalBody}/theme.d.ts +0 -0
- /package/types/Modal/{ModalContext.d.ts → v1/ModalContext.d.ts} +0 -0
- /package/types/Modal/{ModalFooter → v1/ModalFooter}/index.d.ts +0 -0
- /package/types/Modal/{ModalFooter → v1/ModalFooter}/props.d.ts +0 -0
- /package/types/Modal/{ModalFooter → v1/ModalFooter}/styles.d.ts +0 -0
- /package/types/Modal/{ModalFooter → v1/ModalFooter}/theme.d.ts +0 -0
- /package/types/Modal/{ModalHeader → v1/ModalHeader}/index.d.ts +0 -0
- /package/types/Modal/{ModalHeader → v1/ModalHeader}/props.d.ts +0 -0
- /package/types/Modal/{ModalHeader → v1/ModalHeader}/styles.d.ts +0 -0
- /package/types/Modal/{ModalHeader → v1/ModalHeader}/theme.d.ts +0 -0
- /package/types/Modal/{index.d.ts → v1/index.d.ts} +0 -0
- /package/types/Modal/{props.d.ts → v1/props.d.ts} +0 -0
- /package/types/Modal/{styles.d.ts → v1/styles.d.ts} +0 -0
- /package/types/Modal/{theme.d.ts → v1/theme.d.ts} +0 -0
|
@@ -0,0 +1,673 @@
|
|
|
1
|
+
---
|
|
2
|
+
describes: Modal
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
The Modal is a dialog component that is centered in the viewport. The Modal
|
|
6
|
+
overlays the application content and applies a mask to it.
|
|
7
|
+
|
|
8
|
+
The default `padding` of the Modal content is `medium` but can be overridden
|
|
9
|
+
by using the `padding` prop on the `<Modal.Body/>` if the use case requires it.
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
---
|
|
13
|
+
type: example
|
|
14
|
+
---
|
|
15
|
+
const fpo = lorem.paragraphs(5)
|
|
16
|
+
const Example = () => {
|
|
17
|
+
const [open, setOpen] = useState(false)
|
|
18
|
+
|
|
19
|
+
const handleButtonClick = () => {
|
|
20
|
+
setOpen((state) => !state)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const handleFormSubmit = (e) => {
|
|
24
|
+
e.preventDefault()
|
|
25
|
+
console.log('form submitted')
|
|
26
|
+
setOpen(false)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const renderCloseButton = () => {
|
|
30
|
+
return (
|
|
31
|
+
<CloseButton
|
|
32
|
+
placement="end"
|
|
33
|
+
offset="small"
|
|
34
|
+
onClick={handleButtonClick}
|
|
35
|
+
screenReaderLabel="Close"
|
|
36
|
+
/>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div style={{ padding: '0 0 11rem 0', margin: '0 auto' }}>
|
|
42
|
+
<Button onClick={handleButtonClick}>
|
|
43
|
+
{open ? 'Close' : 'Open'} the Modal
|
|
44
|
+
</Button>
|
|
45
|
+
<Modal
|
|
46
|
+
as="form"
|
|
47
|
+
open={open}
|
|
48
|
+
onDismiss={() => {
|
|
49
|
+
setOpen(false)
|
|
50
|
+
}}
|
|
51
|
+
onSubmit={handleFormSubmit}
|
|
52
|
+
size="auto"
|
|
53
|
+
label="Hello World"
|
|
54
|
+
shouldCloseOnDocumentClick
|
|
55
|
+
>
|
|
56
|
+
<Modal.Header>
|
|
57
|
+
{renderCloseButton()}
|
|
58
|
+
<Heading>Hello World</Heading>
|
|
59
|
+
</Modal.Header>
|
|
60
|
+
<Modal.Body>
|
|
61
|
+
<TextInput
|
|
62
|
+
renderLabel="Example"
|
|
63
|
+
placeholder="if you hit enter here, it should submit the form"
|
|
64
|
+
/>
|
|
65
|
+
<Text lineHeight="double">{fpo}</Text>
|
|
66
|
+
</Modal.Body>
|
|
67
|
+
<Modal.Footer>
|
|
68
|
+
<Button onClick={handleButtonClick} margin="0 x-small 0 0">
|
|
69
|
+
Close
|
|
70
|
+
</Button>
|
|
71
|
+
<Button color="primary" type="submit">
|
|
72
|
+
Submit
|
|
73
|
+
</Button>
|
|
74
|
+
</Modal.Footer>
|
|
75
|
+
</Modal>
|
|
76
|
+
</div>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
render(<Example />)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Constraining Modal to a parent element
|
|
84
|
+
|
|
85
|
+
By default, Modals are positioned relative to the document body.
|
|
86
|
+
|
|
87
|
+
Setting the `constrain` property to `parent` will constrain the Modal within the element it is mounted from (specified via the `mountNode` property). Note: in these cases, the `mountNode` element should have an explicit `height` set: Because Modal is absolutely positioned, it has no height of its own.
|
|
88
|
+
|
|
89
|
+
```js
|
|
90
|
+
---
|
|
91
|
+
type: example
|
|
92
|
+
---
|
|
93
|
+
const fpo = lorem.paragraphs(1)
|
|
94
|
+
const Example = () => {
|
|
95
|
+
const [open, setOpen] = useState(false)
|
|
96
|
+
const [size, setSize] = useState('auto')
|
|
97
|
+
|
|
98
|
+
const handleButtonClick = () => {
|
|
99
|
+
setOpen((state) => !state)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const renderCloseButton = () => {
|
|
103
|
+
return (
|
|
104
|
+
<CloseButton
|
|
105
|
+
placement="end"
|
|
106
|
+
offset="small"
|
|
107
|
+
onClick={handleButtonClick}
|
|
108
|
+
screenReaderLabel="Close"
|
|
109
|
+
/>
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
return (
|
|
113
|
+
<div>
|
|
114
|
+
<Button onClick={handleButtonClick}>
|
|
115
|
+
{open ? 'Close' : 'Open'} the Modal
|
|
116
|
+
</Button>
|
|
117
|
+
<Modal
|
|
118
|
+
open={open}
|
|
119
|
+
onDismiss={() => {
|
|
120
|
+
setOpen(false)
|
|
121
|
+
}}
|
|
122
|
+
size="fullscreen"
|
|
123
|
+
label="Hello World"
|
|
124
|
+
shouldCloseOnDocumentClick
|
|
125
|
+
mountNode={() => document.getElementById('constrainExample')}
|
|
126
|
+
constrain="parent"
|
|
127
|
+
>
|
|
128
|
+
<Modal.Header>
|
|
129
|
+
{renderCloseButton()}
|
|
130
|
+
<Heading>This Modal is constrained to a parent</Heading>
|
|
131
|
+
</Modal.Header>
|
|
132
|
+
<Modal.Body>
|
|
133
|
+
<View as="p" margin="none none small">
|
|
134
|
+
<Text>{fpo}</Text>
|
|
135
|
+
</View>
|
|
136
|
+
<ModalAutoCompleteExample renderLabel="Choose a state" />
|
|
137
|
+
</Modal.Body>
|
|
138
|
+
<Modal.Footer spacing="compact">
|
|
139
|
+
<Button onClick={handleButtonClick} margin="0 x-small 0 0">
|
|
140
|
+
Close
|
|
141
|
+
</Button>
|
|
142
|
+
<Button onClick={handleButtonClick} color="primary" type="submit">
|
|
143
|
+
Submit
|
|
144
|
+
</Button>
|
|
145
|
+
</Modal.Footer>
|
|
146
|
+
</Modal>
|
|
147
|
+
<View
|
|
148
|
+
background="primary-inverse"
|
|
149
|
+
margin="medium auto none"
|
|
150
|
+
display="block"
|
|
151
|
+
width="25rem"
|
|
152
|
+
height="25rem"
|
|
153
|
+
borderWidth="large"
|
|
154
|
+
id="constrainExample"
|
|
155
|
+
></View>
|
|
156
|
+
</div>
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const ModalAutoCompleteExample = (props) => {
|
|
161
|
+
const [isShowingOptions, setIsShowingOptions] = useState(false)
|
|
162
|
+
|
|
163
|
+
const handleShowOptions = () => {
|
|
164
|
+
setIsShowingOptions(true)
|
|
165
|
+
}
|
|
166
|
+
const handleHideOptions = () => {
|
|
167
|
+
setIsShowingOptions(false)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const options = [
|
|
171
|
+
'Alabama',
|
|
172
|
+
'Alaska',
|
|
173
|
+
'American Samoa',
|
|
174
|
+
'Arizona',
|
|
175
|
+
'Arkansas',
|
|
176
|
+
'California',
|
|
177
|
+
'Colorado',
|
|
178
|
+
'Connecticut',
|
|
179
|
+
'Delaware',
|
|
180
|
+
'District Of Columbia',
|
|
181
|
+
'Federated States Of Micronesia',
|
|
182
|
+
'Florida',
|
|
183
|
+
'Georgia',
|
|
184
|
+
'Guam',
|
|
185
|
+
'Hawaii',
|
|
186
|
+
'Idaho',
|
|
187
|
+
'Illinois'
|
|
188
|
+
]
|
|
189
|
+
return (
|
|
190
|
+
<Select
|
|
191
|
+
{...props}
|
|
192
|
+
isShowingOptions={isShowingOptions}
|
|
193
|
+
onRequestShowOptions={handleShowOptions}
|
|
194
|
+
onRequestHideOptions={handleHideOptions}
|
|
195
|
+
>
|
|
196
|
+
{options.map((label, index) => (
|
|
197
|
+
<Select.Option key={label} id={'' + index}>
|
|
198
|
+
{label}
|
|
199
|
+
</Select.Option>
|
|
200
|
+
))}
|
|
201
|
+
</Select>
|
|
202
|
+
)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
render(<Example />)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Media (images, etc.) inside Modals
|
|
209
|
+
|
|
210
|
+
> Setting the `variant` prop to `"inverse"` will result in a dark version of Modal, useful for displaying media. _Note that the `inverse` Modal does not currently support text or form input content._
|
|
211
|
+
|
|
212
|
+
**If you are displaying small, relatively uniform images or videos inside Modal, the default settings should work well.** Modal.Body will expand to the height of the media you're displaying. If there is overflow, scrollbars will be available.
|
|
213
|
+
|
|
214
|
+
```js
|
|
215
|
+
---
|
|
216
|
+
type: example
|
|
217
|
+
---
|
|
218
|
+
const Example = () => {
|
|
219
|
+
const [open, setOpen] = useState(false)
|
|
220
|
+
|
|
221
|
+
const handleButtonClick = () => {
|
|
222
|
+
setOpen((state) => !state)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return (
|
|
226
|
+
<div>
|
|
227
|
+
<Button onClick={handleButtonClick}>
|
|
228
|
+
{open ? 'Close' : 'Open'} the Modal
|
|
229
|
+
</Button>
|
|
230
|
+
<Modal
|
|
231
|
+
open={open}
|
|
232
|
+
onDismiss={() => {
|
|
233
|
+
setOpen(false)
|
|
234
|
+
}}
|
|
235
|
+
size="auto"
|
|
236
|
+
label="Hello Media"
|
|
237
|
+
shouldCloseOnDocumentClick
|
|
238
|
+
variant="inverse"
|
|
239
|
+
>
|
|
240
|
+
<Modal.Header>
|
|
241
|
+
<Flex>
|
|
242
|
+
<Flex.Item shouldGrow shouldShrink>
|
|
243
|
+
<Heading color="inverse" level="h2">
|
|
244
|
+
<TruncateText>A small image</TruncateText>
|
|
245
|
+
</Heading>
|
|
246
|
+
</Flex.Item>
|
|
247
|
+
<Flex.Item>
|
|
248
|
+
<CloseButton
|
|
249
|
+
color="primary-inverse"
|
|
250
|
+
placement="end"
|
|
251
|
+
offset="small"
|
|
252
|
+
onClick={handleButtonClick}
|
|
253
|
+
screenReaderLabel="Close"
|
|
254
|
+
/>
|
|
255
|
+
</Flex.Item>
|
|
256
|
+
</Flex>
|
|
257
|
+
</Modal.Header>
|
|
258
|
+
<Modal.Body padding="none">
|
|
259
|
+
<Img
|
|
260
|
+
src={placeholderImage(500, 250)}
|
|
261
|
+
display="block"
|
|
262
|
+
margin="0 auto"
|
|
263
|
+
/>
|
|
264
|
+
</Modal.Body>
|
|
265
|
+
<Modal.Footer spacing="compact">
|
|
266
|
+
<Button
|
|
267
|
+
onClick={handleButtonClick}
|
|
268
|
+
withBackground={false}
|
|
269
|
+
color="primary-inverse"
|
|
270
|
+
type="submit"
|
|
271
|
+
>
|
|
272
|
+
Submit
|
|
273
|
+
</Button>
|
|
274
|
+
</Modal.Footer>
|
|
275
|
+
</Modal>
|
|
276
|
+
</div>
|
|
277
|
+
)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
render(<Example />)
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**When you have to display large media inside the Modal (or have no control over the size of the media)**, set `overflow` to `fit`. Doing so makes Modal.Body fill 100% of the available width and height, enabling you to
|
|
284
|
+
use the [Img](Img) component's `constrain` property to fit the image inside Modal.Body.
|
|
285
|
+
|
|
286
|
+
> `<Img />` uses CSS's [`object-fit`](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) for its constrain property. If you're not using `<Img />`, add an `object-fit` rule to your media, and it will work with `overflow="fit"`.
|
|
287
|
+
|
|
288
|
+
```js
|
|
289
|
+
---
|
|
290
|
+
type: example
|
|
291
|
+
---
|
|
292
|
+
const Example = () => {
|
|
293
|
+
const [open, setOpen] = useState(false)
|
|
294
|
+
const [imageFit, setImageFit] = useState('cover')
|
|
295
|
+
const [modalSize, setModalSize] = useState('fullscreen')
|
|
296
|
+
|
|
297
|
+
const handleButtonClick = () => {
|
|
298
|
+
setOpen((state) => !state)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const handleImageFitChange = (event, value) => {
|
|
302
|
+
setImageFit(value)
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const handleModalSizeChange = (event, value) => {
|
|
306
|
+
setModalSize(value)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return (
|
|
310
|
+
<div>
|
|
311
|
+
<FormFieldGroup
|
|
312
|
+
description={
|
|
313
|
+
<Heading level="h3" as="h3">
|
|
314
|
+
Media Modal
|
|
315
|
+
</Heading>
|
|
316
|
+
}
|
|
317
|
+
rowSpacing="medium"
|
|
318
|
+
>
|
|
319
|
+
<RadioInputGroup
|
|
320
|
+
onChange={handleImageFitChange}
|
|
321
|
+
name="imageFit"
|
|
322
|
+
defaultValue="cover"
|
|
323
|
+
description="Img component's `constrain` prop"
|
|
324
|
+
variant="toggle"
|
|
325
|
+
>
|
|
326
|
+
<RadioInput label="Cover" value="cover" />
|
|
327
|
+
<RadioInput label="Contain" value="contain" />
|
|
328
|
+
</RadioInputGroup>
|
|
329
|
+
<RadioInputGroup
|
|
330
|
+
onChange={handleModalSizeChange}
|
|
331
|
+
name="modalSize"
|
|
332
|
+
defaultValue="fullscreen"
|
|
333
|
+
description="Modal size"
|
|
334
|
+
variant="toggle"
|
|
335
|
+
>
|
|
336
|
+
<RadioInput label="fullscreen" value="fullscreen" />
|
|
337
|
+
<RadioInput label="small" value="small" />
|
|
338
|
+
<RadioInput label="medium" value="medium" />
|
|
339
|
+
<RadioInput label="large" value="large" />
|
|
340
|
+
<RadioInput label="auto" value="auto" />
|
|
341
|
+
</RadioInputGroup>
|
|
342
|
+
</FormFieldGroup>
|
|
343
|
+
<Button onClick={handleButtonClick} margin="medium 0 0">
|
|
344
|
+
{open ? 'Close' : 'Open'} the Modal
|
|
345
|
+
</Button>
|
|
346
|
+
<Modal
|
|
347
|
+
open={open}
|
|
348
|
+
onDismiss={() => {
|
|
349
|
+
setOpen(false)
|
|
350
|
+
}}
|
|
351
|
+
size={modalSize}
|
|
352
|
+
label="Hello Media"
|
|
353
|
+
shouldCloseOnDocumentClick
|
|
354
|
+
variant="inverse"
|
|
355
|
+
overflow="fit"
|
|
356
|
+
>
|
|
357
|
+
<Modal.Header>
|
|
358
|
+
<Flex>
|
|
359
|
+
<Flex.Item shouldGrow shouldShrink>
|
|
360
|
+
<Flex alignItems="center">
|
|
361
|
+
<Flex.Item margin="0 x-small 0 0">
|
|
362
|
+
<HeartInstUIIcon size={'xl'} />
|
|
363
|
+
</Flex.Item>
|
|
364
|
+
<Flex.Item shouldGrow shouldShrink>
|
|
365
|
+
<Heading color="inverse" level="h2">
|
|
366
|
+
<TruncateText>This Modal Contains Media</TruncateText>
|
|
367
|
+
</Heading>
|
|
368
|
+
</Flex.Item>
|
|
369
|
+
</Flex>
|
|
370
|
+
</Flex.Item>
|
|
371
|
+
<Flex.Item>
|
|
372
|
+
<IconButton
|
|
373
|
+
color="primary-inverse"
|
|
374
|
+
withBackground={false}
|
|
375
|
+
withBorder={false}
|
|
376
|
+
renderIcon={<PrinterInstUIIcon/>}
|
|
377
|
+
screenReaderLabel="Print This Image"
|
|
378
|
+
margin="0 x-small 0 0"
|
|
379
|
+
/>
|
|
380
|
+
<IconButton
|
|
381
|
+
color="primary-inverse"
|
|
382
|
+
withBackground={false}
|
|
383
|
+
withBorder={false}
|
|
384
|
+
renderIcon={<DownloadInstUIIcon/>}
|
|
385
|
+
screenReaderLabel="Download This Image"
|
|
386
|
+
margin="0 x-small 0 0"
|
|
387
|
+
/>
|
|
388
|
+
<IconButton
|
|
389
|
+
color="primary-inverse"
|
|
390
|
+
withBackground={false}
|
|
391
|
+
withBorder={false}
|
|
392
|
+
renderIcon={<XInstUIIcon/>}
|
|
393
|
+
screenReaderLabel="Close"
|
|
394
|
+
onClick={handleButtonClick}
|
|
395
|
+
/>
|
|
396
|
+
</Flex.Item>
|
|
397
|
+
</Flex>
|
|
398
|
+
</Modal.Header>
|
|
399
|
+
<Modal.Body padding="none">
|
|
400
|
+
<Img src={avatarSquare} constrain={imageFit} display="block" />
|
|
401
|
+
</Modal.Body>
|
|
402
|
+
<Modal.Footer spacing={modalSize === 'small' ? 'compact' : 'default'}>
|
|
403
|
+
<Button
|
|
404
|
+
onClick={handleButtonClick}
|
|
405
|
+
withBackground={false}
|
|
406
|
+
color="primary-inverse"
|
|
407
|
+
type="submit"
|
|
408
|
+
>
|
|
409
|
+
Close
|
|
410
|
+
</Button>
|
|
411
|
+
</Modal.Footer>
|
|
412
|
+
</Modal>
|
|
413
|
+
</div>
|
|
414
|
+
)
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
render(<Example />)
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Small viewports
|
|
421
|
+
|
|
422
|
+
On smaller viewports (like mobile devices or scaled-up UI), we don't want to lose space because of padding and margins. In order to achieve that, use `size="fullscreen"` on the Modal and set the `spacing` property of Modal.Header to `compact`.
|
|
423
|
+
|
|
424
|
+
```js
|
|
425
|
+
---
|
|
426
|
+
type: example
|
|
427
|
+
---
|
|
428
|
+
const fpo = lorem.paragraphs(1)
|
|
429
|
+
const Example = () => {
|
|
430
|
+
const [open, setOpen] = useState(false)
|
|
431
|
+
const [smallViewport, setSmallViewport] = useState(true)
|
|
432
|
+
|
|
433
|
+
const toggleOpen = () => {
|
|
434
|
+
setOpen((state) => !state)
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const toggleViewport = () => {
|
|
438
|
+
setSmallViewport((state) => !state)
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const renderCloseButton = () => {
|
|
442
|
+
return (
|
|
443
|
+
<CloseButton
|
|
444
|
+
placement="end"
|
|
445
|
+
offset="small"
|
|
446
|
+
onClick={toggleOpen}
|
|
447
|
+
screenReaderLabel="Close"
|
|
448
|
+
/>
|
|
449
|
+
)
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return (
|
|
453
|
+
<div>
|
|
454
|
+
<Button onClick={toggleOpen}>
|
|
455
|
+
{open ? 'Close' : 'Open'} the Modal
|
|
456
|
+
</Button>
|
|
457
|
+
<Button
|
|
458
|
+
onClick={toggleViewport}
|
|
459
|
+
margin="0 0 0 small"
|
|
460
|
+
id="toggleViewportButton"
|
|
461
|
+
>
|
|
462
|
+
Toggle viewport
|
|
463
|
+
</Button>
|
|
464
|
+
<Modal
|
|
465
|
+
open={open}
|
|
466
|
+
size={smallViewport ? 'fullscreen' : 'small'}
|
|
467
|
+
onDismiss={(event) => {
|
|
468
|
+
if (event.target.id !== 'toggleViewportButton') {
|
|
469
|
+
setOpen(false)
|
|
470
|
+
}
|
|
471
|
+
}}
|
|
472
|
+
label="Hello World"
|
|
473
|
+
shouldCloseOnDocumentClick
|
|
474
|
+
mountNode={() => document.getElementById('viewportExample')}
|
|
475
|
+
constrain="parent"
|
|
476
|
+
>
|
|
477
|
+
<Modal.Header spacing={smallViewport ? 'compact' : 'default'}>
|
|
478
|
+
{renderCloseButton()}
|
|
479
|
+
{smallViewport ? (
|
|
480
|
+
<Heading as="h2" level="h3" themeOverride={{ h3FontWeight: 400 }}>
|
|
481
|
+
This Modal is optimized for small viewport
|
|
482
|
+
</Heading>
|
|
483
|
+
) : (
|
|
484
|
+
<Heading as="h2">This is a default size Modal</Heading>
|
|
485
|
+
)}
|
|
486
|
+
</Modal.Header>
|
|
487
|
+
<Modal.Body>
|
|
488
|
+
<View as="p" margin="none none small">
|
|
489
|
+
<Text>{fpo}</Text>
|
|
490
|
+
</View>
|
|
491
|
+
</Modal.Body>
|
|
492
|
+
<Modal.Footer spacing={smallViewport ? 'compact' : 'default'}>
|
|
493
|
+
<Button onClick={toggleOpen} margin="0 x-small 0 0">
|
|
494
|
+
Close
|
|
495
|
+
</Button>
|
|
496
|
+
<Button onClick={toggleOpen} color="primary" type="submit">
|
|
497
|
+
Submit
|
|
498
|
+
</Button>
|
|
499
|
+
</Modal.Footer>
|
|
500
|
+
</Modal>
|
|
501
|
+
|
|
502
|
+
<View
|
|
503
|
+
background="primary-inverse"
|
|
504
|
+
margin="medium auto none"
|
|
505
|
+
display="block"
|
|
506
|
+
width={smallViewport ? '20rem' : '50rem'}
|
|
507
|
+
height="37.5rem"
|
|
508
|
+
borderWidth="large"
|
|
509
|
+
id="viewportExample"
|
|
510
|
+
></View>
|
|
511
|
+
</div>
|
|
512
|
+
)
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
render(<Example />)
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### Using custom children
|
|
519
|
+
|
|
520
|
+
Occasionally, you might find it useful to incorporate custom components within a `Modal`, such as a higher-order component for `Modal.Header` or `Modal.Body` or not using built in child components at all. Although this approach is typically not advised, it can sometimes aid in code splitting or achieving more streamlined code, especially for more intricate and sizable `Modal`s.
|
|
521
|
+
|
|
522
|
+
Below example demonstrates how to use a higher-order component for `Modal.Body`. `Modal` consists of a `Modal.Header`, a custom `WrappedModalBody` component, and a `View` component. Properties `variant` and `overflow` are passed down to child components. While the original `Modal.Header`, `Modal.Body` and `Modal.Footer` components use these properties, please note that these might cause unpredictable side effects for custom components.
|
|
523
|
+
|
|
524
|
+
```js
|
|
525
|
+
---
|
|
526
|
+
type: example
|
|
527
|
+
---
|
|
528
|
+
|
|
529
|
+
class Example extends React.Component {
|
|
530
|
+
constructor (props) {
|
|
531
|
+
super(props)
|
|
532
|
+
|
|
533
|
+
this.state = {
|
|
534
|
+
open: false
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
handleButtonClick = () => {
|
|
539
|
+
this.setState(function (state) {
|
|
540
|
+
return { open: !state.open }
|
|
541
|
+
})
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
renderCloseButton () {
|
|
545
|
+
return (
|
|
546
|
+
<CloseButton
|
|
547
|
+
color="primary-inverse"
|
|
548
|
+
placement="end"
|
|
549
|
+
offset="small"
|
|
550
|
+
onClick={this.handleButtonClick}
|
|
551
|
+
screenReaderLabel="Close"
|
|
552
|
+
/>
|
|
553
|
+
)
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
render () {
|
|
557
|
+
return (
|
|
558
|
+
<div style={{ padding: '0 0 11rem 0', margin: '0 auto' }}>
|
|
559
|
+
<Button onClick={this.handleButtonClick}>
|
|
560
|
+
{this.state.open ? 'Close' : 'Open'} the Modal
|
|
561
|
+
</Button>
|
|
562
|
+
<Modal
|
|
563
|
+
as="form"
|
|
564
|
+
open={this.state.open}
|
|
565
|
+
onDismiss={() => { this.setState({ open: false }) }}
|
|
566
|
+
size="large"
|
|
567
|
+
label="Hello World"
|
|
568
|
+
shouldCloseOnDocumentClick
|
|
569
|
+
variant='inverse'
|
|
570
|
+
overflow='scroll'
|
|
571
|
+
>
|
|
572
|
+
<Modal.Header>
|
|
573
|
+
{this.renderCloseButton()}
|
|
574
|
+
<Heading color="inverse">This is a Modal with a Modal.Body wrapped in to a HOC</Heading>
|
|
575
|
+
</Modal.Header>
|
|
576
|
+
<WrappedModalBody>
|
|
577
|
+
<Heading color="inverse" level='h3'>WrappedModalBody inherits the variant and overflow properties automatically</Heading>
|
|
578
|
+
<Text color="inverse" lineHeight="double">{lorem.paragraphs(5)}</Text>
|
|
579
|
+
</WrappedModalBody>
|
|
580
|
+
<View
|
|
581
|
+
as="div"
|
|
582
|
+
margin="small"
|
|
583
|
+
padding="large"
|
|
584
|
+
background="primary">
|
|
585
|
+
<Heading level='h3'>This View child does not inherit the variant and overflow properties</Heading>
|
|
586
|
+
<Text>{lorem.paragraphs(5)}</Text>
|
|
587
|
+
</View>
|
|
588
|
+
</Modal>
|
|
589
|
+
</div>
|
|
590
|
+
)
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
const withLogger = (WrappedComponent) => {
|
|
595
|
+
class WithLogger extends React.Component {
|
|
596
|
+
componentDidMount() {
|
|
597
|
+
console.log('WrappedModelBody mounted');
|
|
598
|
+
}
|
|
599
|
+
render() {
|
|
600
|
+
return <WrappedComponent {...this.props} />;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
return WithLogger;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
const WrappedModalBody = withLogger(Modal.Body)
|
|
608
|
+
|
|
609
|
+
render(<Example />)
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
### Changing the Modal's z-index
|
|
613
|
+
|
|
614
|
+
You can do this with the `insertAt` prop or a theme override:
|
|
615
|
+
|
|
616
|
+
```jsx
|
|
617
|
+
---
|
|
618
|
+
type: code
|
|
619
|
+
---
|
|
620
|
+
<InstUISettingsProvider
|
|
621
|
+
theme={{
|
|
622
|
+
themeOverrides: {
|
|
623
|
+
componentOverrides: {
|
|
624
|
+
Mask: {
|
|
625
|
+
zIndex: 555,
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}}
|
|
630
|
+
>
|
|
631
|
+
<Modal />
|
|
632
|
+
</InstUISettingsProvider>
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
### Guidelines
|
|
636
|
+
|
|
637
|
+
```js
|
|
638
|
+
---
|
|
639
|
+
type: embed
|
|
640
|
+
---
|
|
641
|
+
<Guidelines>
|
|
642
|
+
<Figure recommendation="yes" title="Do">
|
|
643
|
+
<Figure.Item>Use it to validate user decisions or to gain secondary confirmation</Figure.Item>
|
|
644
|
+
<Figure.Item>Provide input areas that the user may interact with such as Forms, Dropdowns, Selectors, and Links</Figure.Item>
|
|
645
|
+
<Figure.Item>Provide a way to dismiss the Modal: the "x" close button, the ESC key, clicking outside the modal, alternative response button (done, etc...)</Figure.Item>
|
|
646
|
+
<Figure.Item>Place optional response button(s) on the right side within the Modal.Footer</Figure.Item>
|
|
647
|
+
<Figure.Item>Place primary button on the far right with secondary response buttons to the left of the primary</Figure.Item>
|
|
648
|
+
<Figure.Item>Use size="fullscreen" when setting Modal.Body to overflow="contain" to support media fitting within its container</Figure.Item>
|
|
649
|
+
</Figure>
|
|
650
|
+
<Figure recommendation="no" title="Don't">
|
|
651
|
+
<Figure.Item>Use when the workflow should NOT be interrupted</Figure.Item>
|
|
652
|
+
<Figure.Item>Use to show error, success, or warning messages/notifications (see Alert)</Figure.Item>
|
|
653
|
+
<Figure.Item>Add content to a modal that would be better suited in its own page</Figure.Item>
|
|
654
|
+
<Figure.Item>Use "inverse" variant for anything other than media</Figure.Item>
|
|
655
|
+
</Figure>
|
|
656
|
+
</Guidelines>
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
```js
|
|
660
|
+
---
|
|
661
|
+
type: embed
|
|
662
|
+
---
|
|
663
|
+
<Guidelines>
|
|
664
|
+
<Figure recommendation="a11y" title="Accessibility">
|
|
665
|
+
<Figure.Item>Keyboard focus must be set in the modal when it appears; usually on the first interactive element</Figure.Item>
|
|
666
|
+
<Figure.Item>Modals must contain keyboard focus until they’re closed. This is to ensure that keyboard or screen reader users won't mistakenly interact with background content that is meant to be hidden or inaccessible</Figure.Item>
|
|
667
|
+
<Figure.Item>When a user closes a modal, focus must return to a logical place within the page. This is usually the element that triggered opening the modal</Figure.Item>
|
|
668
|
+
<Figure.Item>Modals should be able to be closed by clicking away, esc key and/or a close button</Figure.Item>
|
|
669
|
+
<Figure.Item>We recommend that modals begin with a heading (typically H2)</Figure.Item>
|
|
670
|
+
<Figure.Item>The Modal's header currently becomes non-sticky when the window height is too small, improving navigation of the Modal.Body, e.g., at higher zoom levels</Figure.Item>
|
|
671
|
+
</Figure>
|
|
672
|
+
</Guidelines>
|
|
673
|
+
```
|