@react-ui-org/react-ui 0.47.0 → 0.48.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.
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;