@react-ui-org/react-ui 0.47.0 → 0.48.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. package/dist/lib.development.js +330 -54
  2. package/dist/lib.js +1 -1
  3. package/package.json +1 -1
  4. package/src/lib/components/Alert/README.mdx +4 -2
  5. package/src/lib/components/Alert/index.js +1 -1
  6. package/src/lib/components/Badge/README.mdx +1 -1
  7. package/src/lib/components/Badge/index.js +1 -1
  8. package/src/lib/components/Button/Button.jsx +31 -31
  9. package/src/lib/components/Button/README.mdx +4 -2
  10. package/src/lib/components/Button/index.js +1 -1
  11. package/src/lib/components/ButtonGroup/ButtonGroup.jsx +2 -1
  12. package/src/lib/components/ButtonGroup/README.mdx +4 -2
  13. package/src/lib/components/Card/README.mdx +7 -5
  14. package/src/lib/components/CheckboxField/CheckboxField.jsx +27 -28
  15. package/src/lib/components/CheckboxField/README.mdx +1 -1
  16. package/src/lib/components/CheckboxField/index.js +1 -1
  17. package/src/lib/components/FileInputField/FileInputField.jsx +27 -27
  18. package/src/lib/components/FileInputField/README.mdx +1 -1
  19. package/src/lib/components/FileInputField/index.js +1 -1
  20. package/src/lib/components/FormLayout/README.mdx +15 -13
  21. package/src/lib/components/Grid/Grid.jsx +31 -28
  22. package/src/lib/components/Grid/Grid.scss +10 -15
  23. package/src/lib/components/Grid/GridSpan.jsx +5 -4
  24. package/src/lib/components/Grid/README.mdx +34 -36
  25. package/src/lib/components/Grid/_helpers/generateResponsiveCustomProperties.js +11 -3
  26. package/src/lib/components/Grid/_settings.scss +18 -0
  27. package/src/lib/components/Grid/_tools.scss +5 -5
  28. package/src/lib/components/Modal/Modal.jsx +147 -250
  29. package/src/lib/components/Modal/Modal.scss +7 -55
  30. package/src/lib/components/Modal/ModalBody.jsx +64 -0
  31. package/src/lib/components/Modal/ModalBody.scss +18 -0
  32. package/src/lib/components/Modal/ModalCloseButton.jsx +61 -0
  33. package/src/lib/components/Modal/ModalCloseButton.scss +18 -0
  34. package/src/lib/components/Modal/ModalContent.jsx +43 -0
  35. package/src/lib/components/Modal/ModalContent.scss +5 -0
  36. package/src/lib/components/Modal/ModalFooter.jsx +46 -0
  37. package/src/lib/components/Modal/ModalFooter.scss +35 -0
  38. package/src/lib/components/Modal/ModalHeader.jsx +48 -0
  39. package/src/lib/components/Modal/ModalHeader.scss +30 -0
  40. package/src/lib/components/Modal/ModalTitle.jsx +45 -0
  41. package/src/lib/components/Modal/ModalTitle.scss +10 -0
  42. package/src/lib/components/Modal/README.mdx +842 -197
  43. package/src/lib/components/Modal/_helpers/getJustifyClassName.js +19 -0
  44. package/src/lib/components/Modal/_helpers/getScrollingClassName.js +11 -0
  45. package/src/lib/components/Modal/_settings.scss +1 -5
  46. package/src/lib/components/Modal/_theme.scss +6 -0
  47. package/src/lib/components/Modal/index.js +7 -1
  48. package/src/lib/components/Paper/README.mdx +1 -1
  49. package/src/lib/components/Paper/index.js +1 -1
  50. package/src/lib/components/Popover/Popover.jsx +24 -24
  51. package/src/lib/components/Popover/Popover.scss +7 -6
  52. package/src/lib/components/Popover/PopoverWrapper.jsx +5 -5
  53. package/src/lib/components/Popover/PopoverWrapper.scss +3 -0
  54. package/src/lib/components/Popover/README.mdx +13 -11
  55. package/src/lib/components/Popover/_theme.scss +1 -1
  56. package/src/lib/components/Radio/README.mdx +1 -1
  57. package/src/lib/components/Radio/Radio.jsx +37 -27
  58. package/src/lib/components/Radio/index.js +1 -1
  59. package/src/lib/components/ScrollView/README.mdx +146 -84
  60. package/src/lib/components/ScrollView/ScrollView.jsx +104 -113
  61. package/src/lib/components/ScrollView/ScrollView.scss +18 -16
  62. package/src/lib/components/ScrollView/index.js +1 -1
  63. package/src/lib/components/SelectField/README.mdx +66 -2
  64. package/src/lib/components/SelectField/SelectField.jsx +93 -49
  65. package/src/lib/components/SelectField/_components/Option/Option.jsx +46 -0
  66. package/src/lib/components/SelectField/_components/Option/index.js +1 -0
  67. package/src/lib/components/SelectField/index.js +1 -1
  68. package/src/lib/components/Table/README.mdx +4 -2
  69. package/src/lib/components/Table/Table.jsx +1 -1
  70. package/src/lib/components/Table/index.js +1 -1
  71. package/src/lib/components/Tabs/README.mdx +5 -3
  72. package/src/lib/components/Tabs/TabsItem.scss +1 -2
  73. package/src/lib/components/Text/README.mdx +9 -7
  74. package/src/lib/components/Text/index.js +1 -1
  75. package/src/lib/components/TextArea/README.mdx +1 -1
  76. package/src/lib/components/TextArea/TextArea.jsx +33 -33
  77. package/src/lib/components/TextArea/index.js +1 -1
  78. package/src/lib/components/TextField/README.mdx +3 -3
  79. package/src/lib/components/TextField/TextField.jsx +33 -34
  80. package/src/lib/components/TextField/index.js +1 -1
  81. package/src/lib/components/TextLink/README.mdx +1 -1
  82. package/src/lib/components/TextLink/index.js +1 -1
  83. package/src/lib/components/Toggle/README.mdx +1 -1
  84. package/src/lib/components/Toggle/Toggle.jsx +28 -28
  85. package/src/lib/components/Toggle/index.js +1 -1
  86. package/src/lib/components/Toolbar/README.mdx +8 -6
  87. package/src/lib/components/_helpers/transferProps.js +1 -1
  88. package/src/lib/index.js +24 -16
  89. package/src/lib/provider/withGlobalProps.jsx +20 -3
  90. package/src/lib/theme.scss +18 -26
  91. package/src/lib/translations/en.js +1 -1
  92. package/src/lib/components/Grid/_theme.scss +0 -11
  93. package/src/lib/components/ScrollView/_theme.scss +0 -2
  94. package/src/lib/components/withForwardedRef.jsx +0 -11
@@ -1,294 +1,193 @@
1
1
  import PropTypes from 'prop-types';
2
- import React from 'react';
2
+ import React, {
3
+ useEffect,
4
+ useRef,
5
+ } from 'react';
3
6
  import { createPortal } from 'react-dom';
4
- import {
5
- RUIContext,
6
- withGlobalProps,
7
- } from '../../provider';
7
+ import { withGlobalProps } from '../../provider';
8
8
  import { classNames } from '../../utils/classNames';
9
- import { transferProps } from '../_helpers/transferProps';
10
- import {
11
- Toolbar,
12
- ToolbarItem,
13
- } from '../Toolbar';
14
- import Button from '../Button';
15
- import ScrollView from '../ScrollView';
16
9
  import styles from './Modal.scss';
17
10
 
18
- export class Modal extends React.Component {
19
- constructor(props) {
20
- super(props);
11
+ const preRender = (
12
+ children,
13
+ childrenWrapperRef,
14
+ id,
15
+ closeButtonRef,
16
+ position,
17
+ size,
18
+ ) => {
19
+ const sizeClass = (modalSize) => {
20
+ if (modalSize === 'small') {
21
+ return styles.isRootSizeSmall;
22
+ }
21
23
 
22
- this.childrenWrapperRef = React.createRef();
23
- this.submitButtonRef = React.createRef();
24
+ if (modalSize === 'medium') {
25
+ return styles.isRootSizeMedium;
26
+ }
24
27
 
25
- this.keyPressHandler = this.keyPressHandler.bind(this);
26
- }
28
+ if (modalSize === 'large') {
29
+ return styles.isRootSizeLarge;
30
+ }
27
31
 
28
- componentDidMount() {
29
- const { autoFocus } = this.props;
32
+ if (modalSize === 'fullscreen') {
33
+ return styles.isRootSizeFullscreen;
34
+ }
30
35
 
31
- window.document.addEventListener('keydown', this.keyPressHandler, false);
36
+ return styles.isRootSizeAuto;
37
+ };
32
38
 
33
- // If `autoFocus` is set to `true`, following code finds first form field element
34
- // (input, textarea or select) or submit button and auto focuses it. This is necessary
35
- // to have focus on one of those elements to be able to submit form by pressing Enter key.
36
- if (autoFocus && this.childrenWrapperRef && this.childrenWrapperRef.current) {
37
- const childrenWrapperElement = this.childrenWrapperRef.current;
38
- const childrenElements = childrenWrapperElement.querySelectorAll('*');
39
- const formFieldEl = Array.from(childrenElements).find(
40
- (element) => ['INPUT', 'TEXTAREA', 'SELECT'].includes(element.nodeName),
41
- );
39
+ const positionClass = (modalPosition) => {
40
+ if (modalPosition === 'top') {
41
+ return styles.isRootPositionTop;
42
+ }
42
43
 
43
- if (formFieldEl) {
44
- formFieldEl.focus();
45
- return;
46
- }
44
+ return styles.isRootPositionCenter;
45
+ };
46
+
47
+ return (
48
+ <div
49
+ className={styles.backdrop}
50
+ id={id}
51
+ onClick={() => {
52
+ if (closeButtonRef?.current != null) {
53
+ closeButtonRef.current.click();
54
+ }
55
+ }}
56
+ role="presentation"
57
+ >
58
+ <div
59
+ className={classNames(
60
+ styles.root,
61
+ sizeClass(size),
62
+ positionClass(position),
63
+ )}
64
+ onClick={(e) => {
65
+ e.stopPropagation();
66
+ }}
67
+ role="presentation"
68
+ ref={childrenWrapperRef}
69
+ >
70
+ {children}
71
+ </div>
72
+ </div>
73
+ );
74
+ };
47
75
 
48
- if (this.submitButtonRef && this.submitButtonRef.current) {
49
- this.submitButtonRef.current.focus();
50
- }
76
+ export const Modal = ({
77
+ autoFocus,
78
+ children,
79
+ closeButtonRef,
80
+ id,
81
+ portalId,
82
+ position,
83
+ primaryButtonRef,
84
+ size,
85
+ }) => {
86
+ const childrenWrapperRef = useRef();
87
+
88
+ const keyPressHandler = (e) => {
89
+ if (e.key === 'Escape' && closeButtonRef?.current != null) {
90
+ closeButtonRef.current.click();
51
91
  }
52
- }
53
92
 
54
- componentWillUnmount() {
55
- window.document.removeEventListener('keydown', this.keyPressHandler, false);
56
- }
93
+ if (e.key === 'Enter' && e.target.nodeName !== 'BUTTON' && primaryButtonRef?.current != null) {
94
+ primaryButtonRef.current.click();
95
+ }
96
+ };
57
97
 
58
- keyPressHandler(e) {
59
- const {
60
- actions,
61
- onClose,
62
- } = this.props;
98
+ useEffect(() => {
99
+ window.document.addEventListener('keydown', keyPressHandler, false);
100
+ const removeKeyPressHandler = () => {
101
+ window.document.removeEventListener('keydown', keyPressHandler, false);
102
+ };
63
103
 
64
- if (e.keyCode === 27 && onClose) {
65
- onClose();
66
- }
104
+ // If `autoFocus` is set to `true`, following code finds first form field element
105
+ // (input, textarea or select) or primary button and auto focuses it. This is necessary
106
+ // to have focus on one of those elements to be able to submit form by pressing Enter key.
107
+ if (autoFocus) {
108
+ if (childrenWrapperRef?.current != null) {
109
+ const childrenWrapperElement = childrenWrapperRef.current;
110
+ const childrenElements = childrenWrapperElement.querySelectorAll('*');
111
+ const formFieldEl = Array.from(childrenElements).find(
112
+ (element) => ['INPUT', 'TEXTAREA', 'SELECT'].includes(element.nodeName),
113
+ );
67
114
 
68
- if (e.keyCode === 13 && e.target.nodeName !== 'BUTTON') {
69
- const submitAction = actions.find((action) => action.type === 'submit');
115
+ if (formFieldEl) {
116
+ formFieldEl.focus();
117
+ return removeKeyPressHandler;
118
+ }
119
+ }
70
120
 
71
- if (submitAction && !submitAction.disabled) {
72
- submitAction.onClick(e);
121
+ if (primaryButtonRef?.current != null) {
122
+ primaryButtonRef.current.focus();
73
123
  }
74
124
  }
75
- }
76
125
 
77
- preRender() {
78
- const {
79
- actions,
126
+ return removeKeyPressHandler;
127
+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
128
+
129
+ if (portalId === null) {
130
+ return preRender(
80
131
  children,
132
+ childrenWrapperRef,
81
133
  id,
82
- onClose,
134
+ closeButtonRef,
83
135
  position,
84
- scrollView,
85
136
  size,
86
- title,
87
- } = this.props;
88
-
89
- const sizeClass = (modalSize) => {
90
- if (modalSize === 'small') {
91
- return styles.isRootSizeSmall;
92
- }
93
-
94
- if (modalSize === 'medium') {
95
- return styles.isRootSizeMedium;
96
- }
97
-
98
- if (modalSize === 'large') {
99
- return styles.isRootSizeLarge;
100
- }
101
-
102
- if (modalSize === 'fullscreen') {
103
- return styles.isRootSizeFullscreen;
104
- }
105
-
106
- return styles.isRootSizeAuto;
107
- };
108
-
109
- const positionClass = (modalPosition) => {
110
- if (modalPosition === 'top') {
111
- return styles.isRootPositionTop;
112
- }
113
-
114
- return styles.isRootPositionCenter;
115
- };
116
-
117
- const modalBody = () => {
118
- const content = (
119
- <div
120
- ref={this.childrenWrapperRef}
121
- className={styles.content}
122
- {...(id && { id: `${id}__content` })}
123
- >
124
- {children}
125
- </div>
126
- );
127
-
128
- if (scrollView) {
129
- return (
130
- <div
131
- className={classNames(
132
- styles.body,
133
- styles.isBodyScrollable,
134
- )}
135
- >
136
- {React.cloneElement(scrollView, scrollView.props, content)}
137
- </div>
138
- );
139
- }
140
-
141
- return (
142
- <div className={styles.body}>
143
- {content}
144
- </div>
145
- );
146
- };
147
-
148
- return (
149
- <div
150
- className={styles.backdrop}
151
- id={id}
152
- onClick={(e) => {
153
- if (onClose) {
154
- onClose(e);
155
- }
156
- }}
157
- role="presentation"
158
- >
159
- <div
160
- className={classNames(
161
- styles.root,
162
- sizeClass(size),
163
- positionClass(position),
164
- )}
165
- onClick={(e) => {
166
- e.stopPropagation();
167
- }}
168
- role="presentation"
169
- >
170
- <div className={styles.head}>
171
- <h3
172
- className={styles.headTitle}
173
- {...(id && { id: `${id}__title` })}
174
- >
175
- {title}
176
- </h3>
177
- {onClose && (
178
- <RUIContext.Consumer>
179
- {({ translations }) => (
180
- <button
181
- type="button"
182
- className={styles.close}
183
- onClick={onClose}
184
- title={translations.Modal.close}
185
- {...(id && { id: `${id}__closeModalHeaderButton` })}
186
- >
187
- ×
188
- </button>
189
- )}
190
- </RUIContext.Consumer>
191
- )}
192
- </div>
193
- {modalBody()}
194
- {(actions.length || onClose) && (
195
- <div className={styles.footer}>
196
- <Toolbar justify="center" dense>
197
- {actions.map((action) => (
198
- <ToolbarItem key={action.label}>
199
- <Button
200
- {...transferProps(action)}
201
- color={action.color}
202
- disabled={action.disabled}
203
- feedbackIcon={action.feedbackIcon}
204
- forwardedRef={this.submitButtonRef}
205
- id={action.id || undefined}
206
- label={action.label}
207
- onClick={action.onClick}
208
- type="button"
209
- />
210
- </ToolbarItem>
211
- ))}
212
- {onClose && (
213
- <ToolbarItem>
214
- <RUIContext.Consumer>
215
- {({ translations }) => (
216
- <Button
217
- label={translations.Modal.close}
218
- onClick={onClose}
219
- priority="flat"
220
- {...(id && { id: `${id}__closeModalFooterButton` })}
221
- />
222
- )}
223
- </RUIContext.Consumer>
224
- </ToolbarItem>
225
- )}
226
- </Toolbar>
227
- </div>
228
- )}
229
- </div>
230
- </div>
231
137
  );
232
138
  }
233
139
 
234
- render() {
235
- const { portalId } = this.props;
236
-
237
- if (portalId === null) {
238
- return this.preRender();
239
- }
240
-
241
- return createPortal(this.preRender(), document.getElementById(portalId));
242
- }
243
- }
140
+ return createPortal(
141
+ preRender(
142
+ children,
143
+ childrenWrapperRef,
144
+ id,
145
+ closeButtonRef,
146
+ position,
147
+ size,
148
+ ),
149
+ document.getElementById(portalId),
150
+ );
151
+ };
244
152
 
245
153
  Modal.defaultProps = {
246
- actions: [],
247
154
  autoFocus: true,
248
155
  children: null,
156
+ closeButtonRef: null,
249
157
  id: undefined,
250
- onClose: null,
251
158
  portalId: null,
252
159
  position: 'center',
253
- scrollView: (<ScrollView
254
- customEndShadowStyle={{ background: 'radial-gradient(farthest-side at center bottom, rgba(0, 0, 0, 0.16) 0%, rgba(0, 0, 0, 0.06) 40%, rgba(0, 0, 0, 0.02) 85%, rgba(0, 0, 0, 0) 100%)' }}
255
- customStartShadowStyle={{ background: 'radial-gradient(farthest-side at center top, rgba(0, 0, 0, 0.15) 0%, rgba(0, 0, 0, 0.05) 60%, rgba(0, 0, 0, 0.02) 85%, rgba(0, 0, 0, 0) 100%)' }}
256
- shadowSize="16px"
257
- />),
160
+ primaryButtonRef: null,
258
161
  size: 'medium',
259
162
  };
260
163
 
261
164
  Modal.propTypes = {
262
165
  /**
263
- * Actions to be rendered in modal footer.
264
- */
265
- actions: PropTypes.arrayOf(PropTypes.shape({
266
- color: PropTypes.oneOf(['primary', 'secondary', 'success', 'warning', 'danger', 'help', 'info', 'note', 'light', 'dark']),
267
- disabled: PropTypes.bool,
268
- feedbackIcon: PropTypes.node,
269
- id: PropTypes.string,
270
- label: PropTypes.string.isRequired,
271
- onClick: PropTypes.func.isRequired,
272
- })),
273
- /**
274
- * If `true`, focus the first action in the footer when the modal is opened.
166
+ * If `true`, focus the first input element in the modal or primary button (referenced by the `primaryButtonRef` prop)
167
+ * when the modal is opened.
275
168
  */
276
169
  autoFocus: PropTypes.bool,
277
170
  /**
278
- * Content of the modal.
171
+ * Nested elements. Supported types are:
172
+ *
173
+ * * `ModalHeader`
174
+ * * `ModalBody`
175
+ * * `ModalFooter`
176
+ *
177
+ * At least `ModalBody` is required.
279
178
  */
280
179
  children: PropTypes.node,
281
180
  /**
282
- * ID of the root HTML element. It also serves as a base for nested elements:
283
- * * `<ID>__content`
284
- * * `<ID>__closeModalHeaderButton`
285
- * * `<ID>__closeModalFooterButton`
181
+ * Reference to close button element. It is used to close modal when Escape key is pressed or the backdrop is clicked.
286
182
  */
287
- id: PropTypes.string,
183
+ closeButtonRef: PropTypes.shape({
184
+ // eslint-disable-next-line react/forbid-prop-types
185
+ current: PropTypes.any,
186
+ }),
288
187
  /**
289
- * If a function is provided, the close buttons will be displayed.
188
+ * ID of the root HTML element.
290
189
  */
291
- onClose: PropTypes.func,
190
+ id: PropTypes.string,
292
191
  /**
293
192
  * If set, modal is rendered in the React Portal with that ID.
294
193
  */
@@ -298,19 +197,17 @@ Modal.propTypes = {
298
197
  */
299
198
  position: PropTypes.oneOf(['top', 'center']),
300
199
  /**
301
- * The `ScrollView` component to be used as a wrapper of the content to provide body scrolling functionality.
302
- * If provided only the modal body will be scrollable.
303
- * If set to `null` the entire modal including header and footer will be scrollable.
200
+ * Reference to primary button element. It is used to submit modal when Enter key is pressed and as fallback
201
+ * when `autoFocus` functionality does not find any input element to be focused.
304
202
  */
305
- scrollView: PropTypes.element,
203
+ primaryButtonRef: PropTypes.shape({
204
+ // eslint-disable-next-line react/forbid-prop-types
205
+ current: PropTypes.any,
206
+ }),
306
207
  /**
307
208
  * Size of the modal.
308
209
  */
309
210
  size: PropTypes.oneOf(['small', 'medium', 'large', 'fullscreen', 'auto']),
310
- /**
311
- * Title displayed in modal header.
312
- */
313
- title: PropTypes.string.isRequired,
314
211
  };
315
212
 
316
213
  export const ModalWithGlobalProps = withGlobalProps(Modal, 'Modal');
@@ -9,15 +9,18 @@
9
9
 
10
10
  .root {
11
11
  --rui-local-outer-spacing: #{theme.$outer-spacing-xs};
12
+ --rui-local-max-width: calc(100% - (2 * var(--rui-local-outer-spacing)));
13
+ --rui-local-max-height: calc(100% - (2 * var(--rui-local-outer-spacing)));
12
14
 
13
15
  position: fixed;
14
16
  left: 50%;
15
17
  z-index: settings.$z-index;
16
18
  display: flex;
17
19
  flex-direction: column;
18
- max-width: calc(100% - (2 * var(--rui-local-outer-spacing)));
19
- max-height: calc(100% - (2 * var(--rui-local-outer-spacing)));
20
+ max-width: var(--rui-local-max-width);
21
+ max-height: var(--rui-local-max-height);
20
22
  overflow-y: auto;
23
+ overscroll-behavior: contain;
21
24
  border-radius: settings.$border-radius;
22
25
  background: theme.$background;
23
26
  box-shadow: theme.$box-shadow;
@@ -28,57 +31,6 @@
28
31
  }
29
32
  }
30
33
 
31
- .head {
32
- display: flex;
33
- flex: none;
34
- align-items: baseline;
35
- justify-content: space-between;
36
- padding: settings.$padding-y spacing.of(4) settings.$padding-y settings.$padding-x;
37
- }
38
-
39
- .headTitle {
40
- font-size: settings.$head-title-font-size;
41
-
42
- &:not(:last-child) {
43
- margin-bottom: 0;
44
- }
45
- }
46
-
47
- .close {
48
- @include reset.button();
49
- @include accessibility.min-tap-target();
50
-
51
- font-size: map.get(typography.$size-values, 3);
52
- line-height: 1;
53
- color: inherit;
54
- }
55
-
56
- .body {
57
- flex: 1 1 auto;
58
- }
59
-
60
- .isBodyScrollable {
61
- display: flex;
62
- flex-direction: column;
63
- min-height: 0;
64
- }
65
-
66
- .content {
67
- padding: settings.$padding-y settings.$padding-x settings.$content-padding-bottom;
68
- }
69
-
70
- .footer {
71
- display: flex;
72
- flex: none;
73
- flex-wrap: wrap;
74
- align-items: center;
75
- justify-content: center;
76
- padding: settings.$padding-y settings.$padding-x;
77
- border-bottom-right-radius: settings.$border-radius;
78
- border-bottom-left-radius: settings.$border-radius;
79
- background: theme.$footer-background;
80
- }
81
-
82
34
  .backdrop {
83
35
  position: fixed;
84
36
  top: 0;
@@ -112,8 +64,8 @@
112
64
 
113
65
  .isRootSizeAuto {
114
66
  width: auto;
115
- min-width: map.get(theme.$sizes, auto, min-width);
116
- max-width: map.get(theme.$sizes, auto, max-width);
67
+ min-width: min(var(--rui-local-max-width), #{map.get(theme.$sizes, auto, min-width)});
68
+ max-width: min(var(--rui-local-max-width), #{map.get(theme.$sizes, auto, max-width)});
117
69
  }
118
70
 
119
71
  .isRootPositionCenter {
@@ -0,0 +1,64 @@
1
+ import PropTypes from 'prop-types';
2
+ import React from 'react';
3
+ import { withGlobalProps } from '../../provider';
4
+ import { classNames } from '../../utils/classNames';
5
+ import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
6
+ import { getScrollingClassName } from './_helpers/getScrollingClassName';
7
+ import styles from './ModalBody.scss';
8
+
9
+ export const ModalBody = ({
10
+ children,
11
+ id,
12
+ scrolling,
13
+ }) => {
14
+ if (isChildrenEmpty(children)) {
15
+ return null;
16
+ }
17
+
18
+ return (
19
+ <div
20
+ className={classNames(
21
+ styles.root,
22
+ getScrollingClassName(scrolling, styles),
23
+ )}
24
+ id={id}
25
+ >
26
+ {children}
27
+ </div>
28
+ );
29
+ };
30
+
31
+ ModalBody.defaultProps = {
32
+ children: null,
33
+ id: undefined,
34
+ scrolling: 'auto',
35
+ };
36
+
37
+ ModalBody.propTypes = {
38
+ /**
39
+ * Nested elements. Supported types are:
40
+ *
41
+ * * `ModalContent`
42
+ * * `ScrollView` (`scrolling: 'custom'` must be set)
43
+ *
44
+ * You can also provide a custom component responsible for scrolling and displaying content correctly.
45
+ * At most one nested element is allowed. If none are provided nothing is rendered.
46
+ */
47
+ children: PropTypes.node,
48
+ /**
49
+ * ID of the root HTML element.
50
+ */
51
+ id: PropTypes.string,
52
+ /**
53
+ * Scrolling mode:
54
+ *
55
+ * - `auto`: scrolling is enabled on ModalBody.
56
+ * - `custom`: use if providing a custom scrolling component, e.g. an instance of `ScrollView`.
57
+ * - `none`: scrolling is disabled on ModalBody and the entire Modal is scrollable instead.
58
+ */
59
+ scrolling: PropTypes.oneOf(['auto', 'custom', 'none']),
60
+ };
61
+
62
+ export const ModalBodyWithGlobalProps = withGlobalProps(ModalBody, 'ModalBody');
63
+
64
+ export default ModalBodyWithGlobalProps;
@@ -0,0 +1,18 @@
1
+ .root {
2
+ flex: 1 1 auto;
3
+ }
4
+
5
+ .isRootScrollingAuto,
6
+ .isRootScrollingCustom {
7
+ min-height: 0;
8
+ }
9
+
10
+ .isRootScrollingAuto {
11
+ overflow-y: auto;
12
+ overscroll-behavior: contain;
13
+ }
14
+
15
+ .isRootScrollingCustom {
16
+ display: flex;
17
+ flex-direction: column;
18
+ }
@@ -0,0 +1,61 @@
1
+ import PropTypes from 'prop-types';
2
+ import React, { useContext } from 'react';
3
+ import {
4
+ RUIContext,
5
+ withGlobalProps,
6
+ } from '../../provider';
7
+ import { transferProps } from '../_helpers/transferProps';
8
+ import styles from './ModalCloseButton.scss';
9
+
10
+ export const ModalCloseButton = React.forwardRef((props, ref) => {
11
+ const {
12
+ disabled,
13
+ id,
14
+ ...restProps
15
+ } = props;
16
+
17
+ const { translations } = useContext(RUIContext);
18
+
19
+ return (
20
+ <button
21
+ {...transferProps(restProps)}
22
+ type="button"
23
+ className={styles.root}
24
+ disabled={disabled}
25
+ id={id}
26
+ ref={ref}
27
+ title={translations.ModalCloseButton.close}
28
+ >
29
+ ×
30
+ </button>
31
+ );
32
+ });
33
+
34
+ ModalCloseButton.defaultProps = {
35
+ disabled: false,
36
+ id: undefined,
37
+ ref: undefined,
38
+ };
39
+
40
+ ModalCloseButton.propTypes = {
41
+ /**
42
+ * If `true`, close button will be disabled.
43
+ */
44
+ disabled: PropTypes.bool,
45
+ /**
46
+ * ID of the root HTML element.
47
+ */
48
+ id: PropTypes.string,
49
+ /**
50
+ * Reference forwarded to the `button` element.
51
+ */
52
+ ref: PropTypes.oneOfType([
53
+ PropTypes.func,
54
+ // eslint-disable-next-line react/forbid-prop-types
55
+ PropTypes.shape({ current: PropTypes.any }),
56
+ ]),
57
+ };
58
+
59
+ export const ModalCloseButtonWithGlobalProps = withGlobalProps(ModalCloseButton, 'ModalCloseButton');
60
+
61
+ export default ModalCloseButtonWithGlobalProps;