@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.
Files changed (184) hide show
  1. package/CHANGELOG.md +49 -311
  2. package/es/Modal/{ModalBody → v1/ModalBody}/index.js +2 -2
  3. package/es/Modal/{ModalFooter → v1/ModalFooter}/index.js +1 -1
  4. package/es/Modal/{ModalHeader → v1/ModalHeader}/index.js +2 -2
  5. package/es/Modal/{index.js → v1/index.js} +2 -2
  6. package/es/Modal/v2/ModalBody/index.js +132 -0
  7. package/es/Modal/v2/ModalBody/props.js +26 -0
  8. package/es/Modal/v2/ModalBody/styles.js +68 -0
  9. package/es/Modal/v2/ModalContext.js +34 -0
  10. package/es/Modal/v2/ModalFooter/index.js +73 -0
  11. package/es/{index.js → Modal/v2/ModalFooter/props.js} +3 -1
  12. package/es/Modal/v2/ModalFooter/styles.js +60 -0
  13. package/es/Modal/v2/ModalHeader/index.js +112 -0
  14. package/es/Modal/v2/ModalHeader/props.js +26 -0
  15. package/es/Modal/v2/ModalHeader/styles.js +76 -0
  16. package/es/Modal/v2/index.js +259 -0
  17. package/es/Modal/v2/props.js +26 -0
  18. package/es/Modal/v2/styles.js +119 -0
  19. package/es/exports/a.js +24 -0
  20. package/es/exports/b.js +24 -0
  21. package/lib/Modal/{ModalBody → v1/ModalBody}/index.js +4 -4
  22. package/lib/Modal/{ModalFooter → v1/ModalFooter}/index.js +1 -1
  23. package/lib/Modal/{ModalHeader → v1/ModalHeader}/index.js +3 -3
  24. package/lib/Modal/v1/index.js +285 -0
  25. package/lib/Modal/v2/ModalBody/index.js +137 -0
  26. package/lib/Modal/v2/ModalBody/props.js +31 -0
  27. package/lib/Modal/v2/ModalBody/styles.js +74 -0
  28. package/lib/Modal/v2/ModalContext.js +39 -0
  29. package/lib/Modal/v2/ModalFooter/index.js +78 -0
  30. package/lib/Modal/v2/ModalFooter/props.js +31 -0
  31. package/lib/Modal/v2/ModalFooter/styles.js +66 -0
  32. package/lib/Modal/v2/ModalHeader/index.js +118 -0
  33. package/lib/Modal/v2/ModalHeader/props.js +31 -0
  34. package/lib/Modal/v2/ModalHeader/styles.js +82 -0
  35. package/lib/Modal/{index.js → v2/index.js} +3 -4
  36. package/lib/Modal/v2/props.js +31 -0
  37. package/lib/Modal/v2/styles.js +125 -0
  38. package/lib/{index.js → exports/a.js} +5 -5
  39. package/lib/exports/b.js +30 -0
  40. package/package.json +46 -24
  41. package/src/Modal/{ModalBody → v1/ModalBody}/index.tsx +2 -2
  42. package/src/Modal/{ModalFooter → v1/ModalFooter}/index.tsx +1 -1
  43. package/src/Modal/{ModalHeader → v1/ModalHeader}/index.tsx +3 -3
  44. package/src/Modal/{index.tsx → v1/index.tsx} +2 -2
  45. package/src/Modal/v2/ModalBody/index.tsx +164 -0
  46. package/src/Modal/v2/ModalBody/props.ts +72 -0
  47. package/src/Modal/v2/ModalBody/styles.ts +76 -0
  48. package/src/Modal/v2/ModalContext.ts +46 -0
  49. package/src/Modal/v2/ModalFooter/index.tsx +80 -0
  50. package/src/Modal/v2/ModalFooter/props.ts +50 -0
  51. package/src/Modal/v2/ModalFooter/styles.ts +74 -0
  52. package/src/Modal/v2/ModalHeader/index.tsx +138 -0
  53. package/src/Modal/v2/ModalHeader/props.ts +54 -0
  54. package/src/Modal/v2/ModalHeader/styles.ts +99 -0
  55. package/src/Modal/v2/README.md +673 -0
  56. package/src/Modal/v2/index.tsx +326 -0
  57. package/src/Modal/v2/props.ts +235 -0
  58. package/src/Modal/v2/styles.ts +130 -0
  59. package/src/{index.ts → exports/a.ts} +5 -5
  60. package/src/exports/b.ts +29 -0
  61. package/tsconfig.build.tsbuildinfo +1 -1
  62. package/types/Modal/v1/ModalBody/index.d.ts.map +1 -0
  63. package/types/Modal/v1/ModalBody/props.d.ts.map +1 -0
  64. package/types/Modal/v1/ModalBody/styles.d.ts.map +1 -0
  65. package/types/Modal/v1/ModalBody/theme.d.ts.map +1 -0
  66. package/types/Modal/v1/ModalContext.d.ts.map +1 -0
  67. package/types/Modal/v1/ModalFooter/index.d.ts.map +1 -0
  68. package/types/Modal/v1/ModalFooter/props.d.ts.map +1 -0
  69. package/types/Modal/v1/ModalFooter/styles.d.ts.map +1 -0
  70. package/types/Modal/v1/ModalFooter/theme.d.ts.map +1 -0
  71. package/types/Modal/v1/ModalHeader/index.d.ts.map +1 -0
  72. package/types/Modal/v1/ModalHeader/props.d.ts.map +1 -0
  73. package/types/Modal/v1/ModalHeader/styles.d.ts.map +1 -0
  74. package/types/Modal/v1/ModalHeader/theme.d.ts.map +1 -0
  75. package/types/Modal/v1/index.d.ts.map +1 -0
  76. package/types/Modal/v1/props.d.ts.map +1 -0
  77. package/types/Modal/v1/styles.d.ts.map +1 -0
  78. package/types/Modal/v1/theme.d.ts.map +1 -0
  79. package/types/Modal/v2/ModalBody/index.d.ts +36 -0
  80. package/types/Modal/v2/ModalBody/index.d.ts.map +1 -0
  81. package/types/Modal/v2/ModalBody/props.d.ts +23 -0
  82. package/types/Modal/v2/ModalBody/props.d.ts.map +1 -0
  83. package/types/Modal/v2/ModalBody/styles.d.ts +16 -0
  84. package/types/Modal/v2/ModalBody/styles.d.ts.map +1 -0
  85. package/types/Modal/v2/ModalContext.d.ts +17 -0
  86. package/types/Modal/v2/ModalContext.d.ts.map +1 -0
  87. package/types/Modal/v2/ModalFooter/index.d.ts +27 -0
  88. package/types/Modal/v2/ModalFooter/index.d.ts.map +1 -0
  89. package/types/Modal/v2/ModalFooter/props.d.ts +16 -0
  90. package/types/Modal/v2/ModalFooter/props.d.ts.map +1 -0
  91. package/types/Modal/v2/ModalFooter/styles.d.ts +16 -0
  92. package/types/Modal/v2/ModalFooter/styles.d.ts.map +1 -0
  93. package/types/Modal/v2/ModalHeader/index.d.ts +37 -0
  94. package/types/Modal/v2/ModalHeader/index.d.ts.map +1 -0
  95. package/types/Modal/v2/ModalHeader/props.d.ts +19 -0
  96. package/types/Modal/v2/ModalHeader/props.d.ts.map +1 -0
  97. package/types/Modal/v2/ModalHeader/styles.d.ts +16 -0
  98. package/types/Modal/v2/ModalHeader/styles.d.ts.map +1 -0
  99. package/types/Modal/v2/index.d.ts +54 -0
  100. package/types/Modal/v2/index.d.ts.map +1 -0
  101. package/types/Modal/v2/props.d.ts +132 -0
  102. package/types/Modal/v2/props.d.ts.map +1 -0
  103. package/types/Modal/v2/styles.d.ts +16 -0
  104. package/types/Modal/v2/styles.d.ts.map +1 -0
  105. package/types/exports/a.d.ts +6 -0
  106. package/types/exports/a.d.ts.map +1 -0
  107. package/types/exports/b.d.ts +6 -0
  108. package/types/exports/b.d.ts.map +1 -0
  109. package/types/Modal/ModalBody/index.d.ts.map +0 -1
  110. package/types/Modal/ModalBody/props.d.ts.map +0 -1
  111. package/types/Modal/ModalBody/styles.d.ts.map +0 -1
  112. package/types/Modal/ModalBody/theme.d.ts.map +0 -1
  113. package/types/Modal/ModalContext.d.ts.map +0 -1
  114. package/types/Modal/ModalFooter/index.d.ts.map +0 -1
  115. package/types/Modal/ModalFooter/props.d.ts.map +0 -1
  116. package/types/Modal/ModalFooter/styles.d.ts.map +0 -1
  117. package/types/Modal/ModalFooter/theme.d.ts.map +0 -1
  118. package/types/Modal/ModalHeader/index.d.ts.map +0 -1
  119. package/types/Modal/ModalHeader/props.d.ts.map +0 -1
  120. package/types/Modal/ModalHeader/styles.d.ts.map +0 -1
  121. package/types/Modal/ModalHeader/theme.d.ts.map +0 -1
  122. package/types/Modal/index.d.ts.map +0 -1
  123. package/types/Modal/props.d.ts.map +0 -1
  124. package/types/Modal/styles.d.ts.map +0 -1
  125. package/types/Modal/theme.d.ts.map +0 -1
  126. package/types/index.d.ts +0 -6
  127. package/types/index.d.ts.map +0 -1
  128. /package/es/Modal/{ModalBody → v1/ModalBody}/props.js +0 -0
  129. /package/es/Modal/{ModalBody → v1/ModalBody}/styles.js +0 -0
  130. /package/es/Modal/{ModalBody → v1/ModalBody}/theme.js +0 -0
  131. /package/es/Modal/{ModalContext.js → v1/ModalContext.js} +0 -0
  132. /package/es/Modal/{ModalFooter → v1/ModalFooter}/props.js +0 -0
  133. /package/es/Modal/{ModalFooter → v1/ModalFooter}/styles.js +0 -0
  134. /package/es/Modal/{ModalFooter → v1/ModalFooter}/theme.js +0 -0
  135. /package/es/Modal/{ModalHeader → v1/ModalHeader}/props.js +0 -0
  136. /package/es/Modal/{ModalHeader → v1/ModalHeader}/styles.js +0 -0
  137. /package/es/Modal/{ModalHeader → v1/ModalHeader}/theme.js +0 -0
  138. /package/es/Modal/{props.js → v1/props.js} +0 -0
  139. /package/es/Modal/{styles.js → v1/styles.js} +0 -0
  140. /package/es/Modal/{theme.js → v1/theme.js} +0 -0
  141. /package/lib/Modal/{ModalBody → v1/ModalBody}/props.js +0 -0
  142. /package/lib/Modal/{ModalBody → v1/ModalBody}/styles.js +0 -0
  143. /package/lib/Modal/{ModalBody → v1/ModalBody}/theme.js +0 -0
  144. /package/lib/Modal/{ModalContext.js → v1/ModalContext.js} +0 -0
  145. /package/lib/Modal/{ModalFooter → v1/ModalFooter}/props.js +0 -0
  146. /package/lib/Modal/{ModalFooter → v1/ModalFooter}/styles.js +0 -0
  147. /package/lib/Modal/{ModalFooter → v1/ModalFooter}/theme.js +0 -0
  148. /package/lib/Modal/{ModalHeader → v1/ModalHeader}/props.js +0 -0
  149. /package/lib/Modal/{ModalHeader → v1/ModalHeader}/styles.js +0 -0
  150. /package/lib/Modal/{ModalHeader → v1/ModalHeader}/theme.js +0 -0
  151. /package/lib/Modal/{props.js → v1/props.js} +0 -0
  152. /package/lib/Modal/{styles.js → v1/styles.js} +0 -0
  153. /package/lib/Modal/{theme.js → v1/theme.js} +0 -0
  154. /package/src/Modal/{ModalBody → v1/ModalBody}/props.ts +0 -0
  155. /package/src/Modal/{ModalBody → v1/ModalBody}/styles.ts +0 -0
  156. /package/src/Modal/{ModalBody → v1/ModalBody}/theme.ts +0 -0
  157. /package/src/Modal/{ModalContext.ts → v1/ModalContext.ts} +0 -0
  158. /package/src/Modal/{ModalFooter → v1/ModalFooter}/props.ts +0 -0
  159. /package/src/Modal/{ModalFooter → v1/ModalFooter}/styles.ts +0 -0
  160. /package/src/Modal/{ModalFooter → v1/ModalFooter}/theme.ts +0 -0
  161. /package/src/Modal/{ModalHeader → v1/ModalHeader}/props.ts +0 -0
  162. /package/src/Modal/{ModalHeader → v1/ModalHeader}/styles.ts +0 -0
  163. /package/src/Modal/{ModalHeader → v1/ModalHeader}/theme.ts +0 -0
  164. /package/src/Modal/{README.md → v1/README.md} +0 -0
  165. /package/src/Modal/{props.ts → v1/props.ts} +0 -0
  166. /package/src/Modal/{styles.ts → v1/styles.ts} +0 -0
  167. /package/src/Modal/{theme.ts → v1/theme.ts} +0 -0
  168. /package/types/Modal/{ModalBody → v1/ModalBody}/index.d.ts +0 -0
  169. /package/types/Modal/{ModalBody → v1/ModalBody}/props.d.ts +0 -0
  170. /package/types/Modal/{ModalBody → v1/ModalBody}/styles.d.ts +0 -0
  171. /package/types/Modal/{ModalBody → v1/ModalBody}/theme.d.ts +0 -0
  172. /package/types/Modal/{ModalContext.d.ts → v1/ModalContext.d.ts} +0 -0
  173. /package/types/Modal/{ModalFooter → v1/ModalFooter}/index.d.ts +0 -0
  174. /package/types/Modal/{ModalFooter → v1/ModalFooter}/props.d.ts +0 -0
  175. /package/types/Modal/{ModalFooter → v1/ModalFooter}/styles.d.ts +0 -0
  176. /package/types/Modal/{ModalFooter → v1/ModalFooter}/theme.d.ts +0 -0
  177. /package/types/Modal/{ModalHeader → v1/ModalHeader}/index.d.ts +0 -0
  178. /package/types/Modal/{ModalHeader → v1/ModalHeader}/props.d.ts +0 -0
  179. /package/types/Modal/{ModalHeader → v1/ModalHeader}/styles.d.ts +0 -0
  180. /package/types/Modal/{ModalHeader → v1/ModalHeader}/theme.d.ts +0 -0
  181. /package/types/Modal/{index.d.ts → v1/index.d.ts} +0 -0
  182. /package/types/Modal/{props.d.ts → v1/props.d.ts} +0 -0
  183. /package/types/Modal/{styles.d.ts → v1/styles.d.ts} +0 -0
  184. /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
+ ```