@react-ui-org/react-ui 0.47.0 → 0.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib.development.js +465 -93
- package/dist/lib.js +1 -1
- package/package.json +1 -1
- package/src/lib/components/Alert/Alert.jsx +3 -0
- package/src/lib/components/Alert/Alert.scss +10 -10
- package/src/lib/components/Alert/README.mdx +18 -2
- package/src/lib/components/Alert/index.js +1 -1
- package/src/lib/components/Badge/Badge.jsx +4 -8
- package/src/lib/components/Badge/Badge.scss +21 -21
- package/src/lib/components/Badge/README.mdx +15 -1
- package/src/lib/components/Badge/index.js +1 -1
- package/src/lib/components/Button/Button.jsx +23 -34
- package/src/lib/components/Button/README.mdx +21 -7
- package/src/lib/components/Button/_base.scss +20 -20
- package/src/lib/components/Button/_priorities.scss +35 -35
- package/src/lib/components/Button/helpers/getRootLabelVisibilityClassName.js +7 -7
- package/src/lib/components/Button/helpers/getRootPriorityClassName.js +3 -3
- package/src/lib/components/Button/index.js +1 -1
- package/src/lib/components/ButtonGroup/ButtonGroup.jsx +2 -8
- package/src/lib/components/ButtonGroup/README.mdx +18 -2
- package/src/lib/components/Card/Card.jsx +6 -10
- package/src/lib/components/Card/Card.scss +13 -13
- package/src/lib/components/Card/CardBody.jsx +6 -10
- package/src/lib/components/Card/CardFooter.jsx +6 -7
- package/src/lib/components/Card/README.mdx +21 -5
- package/src/lib/components/CheckboxField/CheckboxField.jsx +17 -44
- package/src/lib/components/CheckboxField/README.mdx +18 -6
- package/src/lib/components/CheckboxField/index.js +1 -1
- package/src/lib/components/FileInputField/FileInputField.jsx +20 -29
- package/src/lib/components/FileInputField/FileInputField.scss +3 -3
- package/src/lib/components/FileInputField/README.mdx +30 -28
- package/src/lib/components/FileInputField/index.js +1 -1
- package/src/lib/components/FormLayout/FormLayout.jsx +5 -9
- package/src/lib/components/FormLayout/FormLayout.scss +3 -3
- package/src/lib/components/FormLayout/FormLayoutCustomField.jsx +4 -1
- package/src/lib/components/FormLayout/FormLayoutCustomField.scss +8 -8
- package/src/lib/components/FormLayout/README.mdx +28 -13
- package/src/lib/components/Grid/Grid.jsx +31 -35
- package/src/lib/components/Grid/Grid.scss +10 -15
- package/src/lib/components/Grid/GridSpan.jsx +5 -11
- package/src/lib/components/Grid/README.mdx +48 -36
- package/src/lib/components/Grid/_helpers/generateResponsiveCustomProperties.js +11 -3
- package/src/lib/components/Grid/_settings.scss +18 -0
- package/src/lib/components/Grid/_tools.scss +5 -5
- package/src/lib/components/Modal/Modal.jsx +147 -254
- package/src/lib/components/Modal/Modal.scss +7 -55
- package/src/lib/components/Modal/ModalBody.jsx +60 -0
- package/src/lib/components/Modal/ModalBody.scss +18 -0
- package/src/lib/components/Modal/ModalCloseButton.jsx +45 -0
- package/src/lib/components/Modal/ModalCloseButton.scss +18 -0
- package/src/lib/components/Modal/ModalContent.jsx +39 -0
- package/src/lib/components/Modal/ModalContent.scss +5 -0
- package/src/lib/components/Modal/ModalFooter.jsx +42 -0
- package/src/lib/components/Modal/ModalFooter.scss +35 -0
- package/src/lib/components/Modal/ModalHeader.jsx +44 -0
- package/src/lib/components/Modal/ModalHeader.scss +30 -0
- package/src/lib/components/Modal/ModalTitle.jsx +44 -0
- package/src/lib/components/Modal/ModalTitle.scss +10 -0
- package/src/lib/components/Modal/README.mdx +865 -195
- package/src/lib/components/Modal/_helpers/getJustifyClassName.js +19 -0
- package/src/lib/components/Modal/_helpers/getScrollingClassName.js +11 -0
- package/src/lib/components/Modal/_settings.scss +1 -5
- package/src/lib/components/Modal/_theme.scss +6 -0
- package/src/lib/components/Modal/index.js +7 -1
- package/src/lib/components/Paper/Paper.jsx +5 -9
- package/src/lib/components/Paper/Paper.scss +2 -2
- package/src/lib/components/Paper/README.mdx +15 -1
- package/src/lib/components/Paper/index.js +1 -1
- package/src/lib/components/Popover/Popover.jsx +14 -30
- package/src/lib/components/Popover/Popover.scss +7 -6
- package/src/lib/components/Popover/PopoverWrapper.jsx +5 -12
- package/src/lib/components/Popover/PopoverWrapper.scss +3 -0
- package/src/lib/components/Popover/README.mdx +32 -11
- package/src/lib/components/Popover/_theme.scss +1 -1
- package/src/lib/components/Radio/README.mdx +13 -6
- package/src/lib/components/Radio/Radio.jsx +39 -29
- package/src/lib/components/Radio/Radio.scss +3 -3
- package/src/lib/components/Radio/index.js +1 -1
- package/src/lib/components/ScrollView/README.mdx +165 -84
- package/src/lib/components/ScrollView/ScrollView.jsx +115 -117
- package/src/lib/components/ScrollView/ScrollView.scss +18 -16
- package/src/lib/components/ScrollView/index.js +1 -1
- package/src/lib/components/SelectField/README.mdx +83 -7
- package/src/lib/components/SelectField/SelectField.jsx +86 -61
- package/src/lib/components/SelectField/SelectField.scss +8 -8
- package/src/lib/components/SelectField/_components/Option/Option.jsx +46 -0
- package/src/lib/components/SelectField/_components/Option/index.js +1 -0
- package/src/lib/components/SelectField/index.js +1 -1
- package/src/lib/components/Table/README.mdx +25 -9
- package/src/lib/components/Table/Table.jsx +43 -101
- package/src/lib/components/Table/Table.scss +0 -24
- package/src/lib/components/Table/_components/TableBodyCell/TableBodyCell.jsx +46 -0
- package/src/lib/components/Table/_components/TableBodyCell/index.js +1 -0
- package/src/lib/components/Table/_components/TableCell.scss +25 -0
- package/src/lib/components/Table/_components/TableHeaderCell/TableHeaderCell.jsx +71 -0
- package/src/lib/components/Table/_components/TableHeaderCell/index.js +1 -0
- package/src/lib/components/Table/index.js +1 -1
- package/src/lib/components/Tabs/README.mdx +21 -3
- package/src/lib/components/Tabs/Tabs.jsx +6 -1
- package/src/lib/components/Tabs/TabsItem.jsx +3 -0
- package/src/lib/components/Tabs/TabsItem.scss +1 -2
- package/src/lib/components/Text/README.mdx +25 -7
- package/src/lib/components/Text/Text.jsx +3 -7
- package/src/lib/components/Text/Text.scss +6 -6
- package/src/lib/components/Text/_helpers/getRootClampClassName.js +2 -2
- package/src/lib/components/Text/_helpers/getRootHyphensClassName.js +2 -2
- package/src/lib/components/Text/_helpers/getRootWordWrappingClassName.js +2 -2
- package/src/lib/components/Text/index.js +1 -1
- package/src/lib/components/TextArea/README.mdx +34 -31
- package/src/lib/components/TextArea/TextArea.jsx +23 -63
- package/src/lib/components/TextArea/TextArea.scss +8 -8
- package/src/lib/components/TextArea/index.js +1 -1
- package/src/lib/components/TextField/README.mdx +56 -54
- package/src/lib/components/TextField/TextField.jsx +25 -52
- package/src/lib/components/TextField/TextField.scss +9 -9
- package/src/lib/components/TextField/index.js +1 -1
- package/src/lib/components/TextLink/README.mdx +13 -6
- package/src/lib/components/TextLink/TextLink.jsx +0 -10
- package/src/lib/components/TextLink/index.js +1 -1
- package/src/lib/components/Toggle/README.mdx +18 -6
- package/src/lib/components/Toggle/Toggle.jsx +18 -44
- package/src/lib/components/Toggle/index.js +1 -1
- package/src/lib/components/Toolbar/README.mdx +21 -6
- package/src/lib/components/Toolbar/Toolbar.jsx +9 -43
- package/src/lib/components/Toolbar/Toolbar.scss +24 -12
- package/src/lib/components/Toolbar/ToolbarGroup.jsx +7 -26
- package/src/lib/components/Toolbar/ToolbarItem.jsx +3 -7
- package/src/lib/components/Toolbar/_helpers/getAlignClassName.js +19 -0
- package/src/lib/components/Toolbar/_helpers/getJustifyClassName.js +16 -0
- package/src/lib/components/_helpers/getRootColorClassName.js +10 -10
- package/src/lib/components/_helpers/getRootSizeClassName.js +3 -3
- package/src/lib/components/_helpers/transferProps.js +1 -1
- package/src/lib/index.js +24 -16
- package/src/lib/provider/withGlobalProps.jsx +20 -3
- package/src/lib/styles/tools/form-fields/_box-field-layout.scss +15 -15
- package/src/lib/styles/tools/form-fields/_inline-field-elements.scss +1 -1
- package/src/lib/styles/tools/form-fields/_inline-field-layout.scss +9 -9
- package/src/lib/theme.scss +18 -26
- package/src/lib/translations/en.js +1 -1
- package/src/lib/components/Grid/_theme.scss +0 -11
- package/src/lib/components/ScrollView/_theme.scss +0 -2
- package/src/lib/components/withForwardedRef.jsx +0 -11
|
@@ -1,294 +1,189 @@
|
|
|
1
1
|
import PropTypes from 'prop-types';
|
|
2
|
-
import 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';
|
|
8
|
-
import { classNames } from '../../utils/classNames';
|
|
7
|
+
import { withGlobalProps } from '../../provider';
|
|
9
8
|
import { transferProps } from '../_helpers/transferProps';
|
|
10
|
-
import {
|
|
11
|
-
Toolbar,
|
|
12
|
-
ToolbarItem,
|
|
13
|
-
} from '../Toolbar';
|
|
14
|
-
import Button from '../Button';
|
|
15
|
-
import ScrollView from '../ScrollView';
|
|
9
|
+
import { classNames } from '../../utils/classNames';
|
|
16
10
|
import styles from './Modal.scss';
|
|
17
11
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const { autoFocus } = this.props;
|
|
30
|
-
|
|
31
|
-
window.document.addEventListener('keydown', this.keyPressHandler, false);
|
|
32
|
-
|
|
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
|
-
);
|
|
42
|
-
|
|
43
|
-
if (formFieldEl) {
|
|
44
|
-
formFieldEl.focus();
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (this.submitButtonRef && this.submitButtonRef.current) {
|
|
49
|
-
this.submitButtonRef.current.focus();
|
|
50
|
-
}
|
|
12
|
+
const preRender = (
|
|
13
|
+
children,
|
|
14
|
+
childrenWrapperRef,
|
|
15
|
+
closeButtonRef,
|
|
16
|
+
position,
|
|
17
|
+
restProps,
|
|
18
|
+
size,
|
|
19
|
+
) => {
|
|
20
|
+
const sizeClass = (modalSize) => {
|
|
21
|
+
if (modalSize === 'small') {
|
|
22
|
+
return styles.isRootSizeSmall;
|
|
51
23
|
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
componentWillUnmount() {
|
|
55
|
-
window.document.removeEventListener('keydown', this.keyPressHandler, false);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
keyPressHandler(e) {
|
|
59
|
-
const {
|
|
60
|
-
actions,
|
|
61
|
-
onClose,
|
|
62
|
-
} = this.props;
|
|
63
24
|
|
|
64
|
-
if (
|
|
65
|
-
|
|
25
|
+
if (modalSize === 'medium') {
|
|
26
|
+
return styles.isRootSizeMedium;
|
|
66
27
|
}
|
|
67
28
|
|
|
68
|
-
if (
|
|
69
|
-
|
|
29
|
+
if (modalSize === 'large') {
|
|
30
|
+
return styles.isRootSizeLarge;
|
|
31
|
+
}
|
|
70
32
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
33
|
+
if (modalSize === 'fullscreen') {
|
|
34
|
+
return styles.isRootSizeFullscreen;
|
|
74
35
|
}
|
|
75
|
-
}
|
|
76
36
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
actions,
|
|
80
|
-
children,
|
|
81
|
-
id,
|
|
82
|
-
onClose,
|
|
83
|
-
position,
|
|
84
|
-
scrollView,
|
|
85
|
-
size,
|
|
86
|
-
title,
|
|
87
|
-
} = this.props;
|
|
37
|
+
return styles.isRootSizeAuto;
|
|
38
|
+
};
|
|
88
39
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
40
|
+
const positionClass = (modalPosition) => {
|
|
41
|
+
if (modalPosition === 'top') {
|
|
42
|
+
return styles.isRootPositionTop;
|
|
43
|
+
}
|
|
93
44
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
45
|
+
return styles.isRootPositionCenter;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div
|
|
50
|
+
className={styles.backdrop}
|
|
51
|
+
onClick={() => {
|
|
52
|
+
if (closeButtonRef?.current != null) {
|
|
53
|
+
closeButtonRef.current.click();
|
|
54
|
+
}
|
|
55
|
+
}}
|
|
56
|
+
role="presentation"
|
|
57
|
+
>
|
|
58
|
+
<div
|
|
59
|
+
{...transferProps(restProps)}
|
|
60
|
+
className={classNames(
|
|
61
|
+
styles.root,
|
|
62
|
+
sizeClass(size),
|
|
63
|
+
positionClass(position),
|
|
64
|
+
)}
|
|
65
|
+
onClick={(e) => {
|
|
66
|
+
e.stopPropagation();
|
|
67
|
+
}}
|
|
68
|
+
role="presentation"
|
|
69
|
+
ref={childrenWrapperRef}
|
|
70
|
+
>
|
|
71
|
+
{children}
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
);
|
|
75
|
+
};
|
|
97
76
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
77
|
+
export const Modal = ({
|
|
78
|
+
autoFocus,
|
|
79
|
+
children,
|
|
80
|
+
closeButtonRef,
|
|
81
|
+
portalId,
|
|
82
|
+
position,
|
|
83
|
+
primaryButtonRef,
|
|
84
|
+
size,
|
|
85
|
+
...restProps
|
|
86
|
+
}) => {
|
|
87
|
+
const childrenWrapperRef = useRef();
|
|
88
|
+
|
|
89
|
+
const keyPressHandler = (e) => {
|
|
90
|
+
if (e.key === 'Escape' && closeButtonRef?.current != null) {
|
|
91
|
+
closeButtonRef.current.click();
|
|
92
|
+
}
|
|
101
93
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
94
|
+
if (e.key === 'Enter' && e.target.nodeName !== 'BUTTON' && primaryButtonRef?.current != null) {
|
|
95
|
+
primaryButtonRef.current.click();
|
|
96
|
+
}
|
|
97
|
+
};
|
|
105
98
|
|
|
106
|
-
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
window.document.addEventListener('keydown', keyPressHandler, false);
|
|
101
|
+
const removeKeyPressHandler = () => {
|
|
102
|
+
window.document.removeEventListener('keydown', keyPressHandler, false);
|
|
107
103
|
};
|
|
108
104
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
105
|
+
// If `autoFocus` is set to `true`, following code finds first form field element
|
|
106
|
+
// (input, textarea or select) or primary button and auto focuses it. This is necessary
|
|
107
|
+
// to have focus on one of those elements to be able to submit form by pressing Enter key.
|
|
108
|
+
if (autoFocus) {
|
|
109
|
+
if (childrenWrapperRef?.current != null) {
|
|
110
|
+
const childrenWrapperElement = childrenWrapperRef.current;
|
|
111
|
+
const childrenElements = childrenWrapperElement.querySelectorAll('*');
|
|
112
|
+
const formFieldEl = Array.from(childrenElements).find(
|
|
113
|
+
(element) => ['INPUT', 'TEXTAREA', 'SELECT'].includes(element.nodeName),
|
|
114
|
+
);
|
|
116
115
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
{...(id && { id: `${id}__content` })}
|
|
123
|
-
>
|
|
124
|
-
{children}
|
|
125
|
-
</div>
|
|
126
|
-
);
|
|
116
|
+
if (formFieldEl) {
|
|
117
|
+
formFieldEl.focus();
|
|
118
|
+
return removeKeyPressHandler;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
127
121
|
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
<div
|
|
131
|
-
className={classNames(
|
|
132
|
-
styles.body,
|
|
133
|
-
styles.isBodyScrollable,
|
|
134
|
-
)}
|
|
135
|
-
>
|
|
136
|
-
{React.cloneElement(scrollView, scrollView.props, content)}
|
|
137
|
-
</div>
|
|
138
|
-
);
|
|
122
|
+
if (primaryButtonRef?.current != null) {
|
|
123
|
+
primaryButtonRef.current.focus();
|
|
139
124
|
}
|
|
125
|
+
}
|
|
140
126
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
{content}
|
|
144
|
-
</div>
|
|
145
|
-
);
|
|
146
|
-
};
|
|
127
|
+
return removeKeyPressHandler;
|
|
128
|
+
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
147
129
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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>
|
|
130
|
+
if (portalId === null) {
|
|
131
|
+
return preRender(
|
|
132
|
+
children,
|
|
133
|
+
childrenWrapperRef,
|
|
134
|
+
closeButtonRef,
|
|
135
|
+
position,
|
|
136
|
+
restProps,
|
|
137
|
+
size,
|
|
231
138
|
);
|
|
232
139
|
}
|
|
233
140
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
141
|
+
return createPortal(
|
|
142
|
+
preRender(
|
|
143
|
+
children,
|
|
144
|
+
childrenWrapperRef,
|
|
145
|
+
closeButtonRef,
|
|
146
|
+
position,
|
|
147
|
+
restProps,
|
|
148
|
+
size,
|
|
149
|
+
),
|
|
150
|
+
document.getElementById(portalId),
|
|
151
|
+
);
|
|
152
|
+
};
|
|
244
153
|
|
|
245
154
|
Modal.defaultProps = {
|
|
246
|
-
actions: [],
|
|
247
155
|
autoFocus: true,
|
|
248
156
|
children: null,
|
|
249
|
-
|
|
250
|
-
onClose: null,
|
|
157
|
+
closeButtonRef: null,
|
|
251
158
|
portalId: null,
|
|
252
159
|
position: 'center',
|
|
253
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
onClose: PropTypes.func,
|
|
183
|
+
closeButtonRef: PropTypes.shape({
|
|
184
|
+
// eslint-disable-next-line react/forbid-prop-types
|
|
185
|
+
current: PropTypes.any,
|
|
186
|
+
}),
|
|
292
187
|
/**
|
|
293
188
|
* If set, modal is rendered in the React Portal with that ID.
|
|
294
189
|
*/
|
|
@@ -298,19 +193,17 @@ Modal.propTypes = {
|
|
|
298
193
|
*/
|
|
299
194
|
position: PropTypes.oneOf(['top', 'center']),
|
|
300
195
|
/**
|
|
301
|
-
*
|
|
302
|
-
*
|
|
303
|
-
* If set to `null` the entire modal including header and footer will be scrollable.
|
|
196
|
+
* Reference to primary button element. It is used to submit modal when Enter key is pressed and as fallback
|
|
197
|
+
* when `autoFocus` functionality does not find any input element to be focused.
|
|
304
198
|
*/
|
|
305
|
-
|
|
199
|
+
primaryButtonRef: PropTypes.shape({
|
|
200
|
+
// eslint-disable-next-line react/forbid-prop-types
|
|
201
|
+
current: PropTypes.any,
|
|
202
|
+
}),
|
|
306
203
|
/**
|
|
307
204
|
* Size of the modal.
|
|
308
205
|
*/
|
|
309
206
|
size: PropTypes.oneOf(['small', 'medium', 'large', 'fullscreen', 'auto']),
|
|
310
|
-
/**
|
|
311
|
-
* Title displayed in modal header.
|
|
312
|
-
*/
|
|
313
|
-
title: PropTypes.string.isRequired,
|
|
314
207
|
};
|
|
315
208
|
|
|
316
209
|
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:
|
|
19
|
-
max-height:
|
|
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,60 @@
|
|
|
1
|
+
import PropTypes from 'prop-types';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { withGlobalProps } from '../../provider';
|
|
4
|
+
import { transferProps } from '../_helpers/transferProps';
|
|
5
|
+
import { classNames } from '../../utils/classNames';
|
|
6
|
+
import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
|
|
7
|
+
import { getScrollingClassName } from './_helpers/getScrollingClassName';
|
|
8
|
+
import styles from './ModalBody.scss';
|
|
9
|
+
|
|
10
|
+
export const ModalBody = ({
|
|
11
|
+
children,
|
|
12
|
+
scrolling,
|
|
13
|
+
...restProps
|
|
14
|
+
}) => {
|
|
15
|
+
if (isChildrenEmpty(children)) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div
|
|
21
|
+
{...transferProps(restProps)}
|
|
22
|
+
className={classNames(
|
|
23
|
+
styles.root,
|
|
24
|
+
getScrollingClassName(scrolling, styles),
|
|
25
|
+
)}
|
|
26
|
+
>
|
|
27
|
+
{children}
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
ModalBody.defaultProps = {
|
|
33
|
+
children: null,
|
|
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
|
+
* Scrolling mode:
|
|
50
|
+
*
|
|
51
|
+
* - `auto`: scrolling is enabled on ModalBody.
|
|
52
|
+
* - `custom`: use if providing a custom scrolling component, e.g. an instance of `ScrollView`.
|
|
53
|
+
* - `none`: scrolling is disabled on ModalBody and the entire Modal is scrollable instead.
|
|
54
|
+
*/
|
|
55
|
+
scrolling: PropTypes.oneOf(['auto', 'custom', 'none']),
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const ModalBodyWithGlobalProps = withGlobalProps(ModalBody, 'ModalBody');
|
|
59
|
+
|
|
60
|
+
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,45 @@
|
|
|
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
|
+
...restProps
|
|
14
|
+
} = props;
|
|
15
|
+
|
|
16
|
+
const { translations } = useContext(RUIContext);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<button
|
|
20
|
+
{...transferProps(restProps)}
|
|
21
|
+
type="button"
|
|
22
|
+
className={styles.root}
|
|
23
|
+
disabled={disabled}
|
|
24
|
+
ref={ref}
|
|
25
|
+
title={translations.ModalCloseButton.close}
|
|
26
|
+
>
|
|
27
|
+
×
|
|
28
|
+
</button>
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
ModalCloseButton.defaultProps = {
|
|
33
|
+
disabled: false,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
ModalCloseButton.propTypes = {
|
|
37
|
+
/**
|
|
38
|
+
* If `true`, close button will be disabled.
|
|
39
|
+
*/
|
|
40
|
+
disabled: PropTypes.bool,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const ModalCloseButtonWithGlobalProps = withGlobalProps(ModalCloseButton, 'ModalCloseButton');
|
|
44
|
+
|
|
45
|
+
export default ModalCloseButtonWithGlobalProps;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
@use "sass:map";
|
|
2
|
+
@use "../../styles/theme/typography";
|
|
3
|
+
@use "../../styles/tools/accessibility";
|
|
4
|
+
@use "../../styles/tools/reset";
|
|
5
|
+
@use "../../styles/tools/spacing";
|
|
6
|
+
|
|
7
|
+
.root {
|
|
8
|
+
@include reset.button();
|
|
9
|
+
@include accessibility.min-tap-target();
|
|
10
|
+
|
|
11
|
+
font-size: map.get(typography.$size-values, 3);
|
|
12
|
+
line-height: 1;
|
|
13
|
+
color: inherit;
|
|
14
|
+
|
|
15
|
+
&:disabled {
|
|
16
|
+
cursor: var(--rui-disabled-cursor);
|
|
17
|
+
}
|
|
18
|
+
}
|