@react-ui-org/react-ui 0.58.0 → 0.59.1
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/README.md +2 -11
- package/dist/react-ui.css +17 -17
- package/dist/react-ui.development.css +1230 -1053
- package/dist/react-ui.development.js +126 -66
- package/dist/react-ui.js +1 -1
- package/package.json +5 -5
- package/src/components/Alert/Alert.jsx +4 -4
- package/src/components/Alert/README.md +1 -27
- package/src/components/Alert/_settings.scss +1 -2
- package/src/components/Badge/Badge.jsx +2 -2
- package/src/components/Button/Button.jsx +2 -2
- package/src/components/ButtonGroup/ButtonGroup.jsx +2 -2
- package/src/components/Card/Card.jsx +6 -6
- package/src/components/Card/Card.module.scss +2 -2
- package/src/components/Card/CardBody.jsx +1 -1
- package/src/components/Card/CardFooter.jsx +1 -1
- package/src/components/Card/README.md +12 -30
- package/src/components/Card/_settings.scss +1 -2
- package/src/components/Card/_theme.scss +2 -0
- package/src/components/CheckboxField/CheckboxField.jsx +2 -2
- package/src/components/FileInputField/FileInputField.jsx +147 -21
- package/src/components/FileInputField/FileInputField.module.scss +87 -1
- package/src/components/FileInputField/README.md +83 -2
- package/src/components/FileInputField/_settings.scss +15 -0
- package/src/components/FormLayout/FormLayout.jsx +2 -2
- package/src/components/FormLayout/FormLayoutCustomField.jsx +2 -2
- package/src/components/FormLayout/README.md +8 -6
- package/src/components/Grid/Grid.jsx +1 -1
- package/src/components/Grid/Grid.module.scss +2 -2
- package/src/components/Grid/GridSpan.jsx +1 -1
- package/src/components/InputGroup/InputGroup.jsx +2 -2
- package/src/components/InputGroup/InputGroup.module.scss +3 -3
- package/src/components/InputGroup/README.md +1 -1
- package/src/components/Modal/Modal.jsx +117 -45
- package/src/components/Modal/Modal.module.scss +34 -18
- package/src/components/Modal/ModalBody.jsx +2 -2
- package/src/components/Modal/ModalBody.module.scss +18 -0
- package/src/components/Modal/ModalCloseButton.jsx +1 -1
- package/src/components/Modal/ModalContent.jsx +1 -1
- package/src/components/Modal/ModalFooter.jsx +2 -2
- package/src/components/Modal/ModalFooter.module.scss +6 -2
- package/src/components/Modal/ModalHeader.jsx +2 -2
- package/src/components/Modal/ModalHeader.module.scss +8 -1
- package/src/components/Modal/ModalTitle.jsx +1 -1
- package/src/components/Modal/README.md +391 -171
- package/src/components/Modal/_animations.scss +9 -0
- package/src/components/Modal/_helpers/dialogOnCancelHandler.js +28 -0
- package/src/components/Modal/_helpers/dialogOnClickHandler.js +46 -0
- package/src/components/Modal/_helpers/dialogOnCloseHandler.js +28 -0
- package/src/components/Modal/_helpers/dialogOnKeyDownHandler.js +62 -0
- package/src/components/Modal/_helpers/getPositionClassName.js +1 -1
- package/src/components/Modal/_hooks/useModalFocus.js +24 -91
- package/src/components/Modal/_settings.scss +4 -3
- package/src/components/Modal/_theme.scss +1 -0
- package/src/components/Paper/Paper.jsx +2 -2
- package/src/components/Popover/Popover.jsx +2 -2
- package/src/components/Popover/PopoverWrapper.jsx +1 -1
- package/src/components/Radio/Radio.jsx +2 -2
- package/src/components/ScrollView/ScrollView.jsx +2 -2
- package/src/components/SelectField/SelectField.jsx +2 -2
- package/src/components/Table/Table.jsx +1 -1
- package/src/components/Tabs/Tabs.jsx +1 -1
- package/src/components/Tabs/TabsItem.jsx +2 -2
- package/src/components/Text/Text.jsx +2 -2
- package/src/components/TextArea/TextArea.jsx +2 -2
- package/src/components/TextField/TextField.jsx +2 -2
- package/src/components/TextLink/TextLink.jsx +1 -1
- package/src/components/Toggle/Toggle.jsx +2 -2
- package/src/components/Toolbar/Toolbar.jsx +2 -2
- package/src/components/Toolbar/ToolbarGroup.jsx +2 -2
- package/src/components/Toolbar/ToolbarItem.jsx +2 -2
- package/src/helpers/classNames/README.md +65 -0
- package/src/helpers/classNames/classNames.js +11 -0
- package/src/helpers/classNames/index.js +1 -0
- package/src/helpers/transferProps/README.md +46 -0
- package/src/helpers/transferProps/index.js +1 -0
- package/src/index.js +3 -3
- package/src/styles/elements/_links.scss +2 -14
- package/src/styles/generic/_focus.scss +1 -1
- package/src/styles/theme/_form-fields.scss +5 -5
- package/src/styles/tools/_accessibility.scss +3 -5
- package/src/styles/tools/_collections.scss +3 -20
- package/src/styles/tools/_links.scss +17 -0
- package/src/styles/tools/form-fields/_box-field-elements.scss +21 -9
- package/src/styles/tools/form-fields/_box-field-layout.scss +2 -2
- package/src/styles/tools/form-fields/_box-field-sizes.scss +6 -10
- package/src/styles/tools/form-fields/_variants.scss +10 -10
- package/src/theme.scss +53 -3
- package/src/translations/en.js +5 -0
- package/src/styles/settings/_z-indexes.scss +0 -2
- package/src/utils/classNames.js +0 -8
- /package/src/{utils → helpers/transferProps}/transferProps.js +0 -0
@@ -1,8 +1,16 @@
|
|
1
|
+
// 1. The drop zone is constructed as a button to support keyboard operation.
|
2
|
+
// 2. Prevent pointer events on all children of the root element to not to trigger drag events on children.
|
3
|
+
|
1
4
|
@use "../../styles/tools/form-fields/box-field-elements";
|
2
5
|
@use "../../styles/tools/form-fields/box-field-layout";
|
6
|
+
@use "../../styles/tools/form-fields/box-field-sizes";
|
3
7
|
@use "../../styles/tools/form-fields/foundation";
|
4
8
|
@use "../../styles/tools/form-fields/variants";
|
5
9
|
@use "../../styles/tools/accessibility";
|
10
|
+
@use "../../styles/tools/links";
|
11
|
+
@use "../../styles/tools/transition";
|
12
|
+
@use "../../styles/tools/reset";
|
13
|
+
@use "settings";
|
6
14
|
|
7
15
|
@layer components.file-input-field {
|
8
16
|
// Foundation
|
@@ -18,6 +26,54 @@
|
|
18
26
|
@include box-field-elements.input-container();
|
19
27
|
}
|
20
28
|
|
29
|
+
.input {
|
30
|
+
@include accessibility.hide-text();
|
31
|
+
}
|
32
|
+
|
33
|
+
.dropZone {
|
34
|
+
--rui-local-color: #{settings.$drop-zone-color};
|
35
|
+
--rui-local-border-color: #{settings.$drop-zone-border-color};
|
36
|
+
--rui-local-background: #{settings.$drop-zone-background-color};
|
37
|
+
|
38
|
+
@include reset.button(); // 1.
|
39
|
+
@include box-field-elements.base();
|
40
|
+
|
41
|
+
display: flex;
|
42
|
+
align-items: center;
|
43
|
+
justify-content: start;
|
44
|
+
font-weight: settings.$drop-zone-font-weight;
|
45
|
+
font-size: var(--rui-local-font-size);
|
46
|
+
line-height: settings.$drop-zone-line-height;
|
47
|
+
font-family: settings.$drop-zone-font-family;
|
48
|
+
border-style: dashed;
|
49
|
+
}
|
50
|
+
|
51
|
+
.isRootDragging .dropZone {
|
52
|
+
--rui-local-border-color: #{settings.$drop-zone-dragging-border-color};
|
53
|
+
}
|
54
|
+
|
55
|
+
.isRootDisabled .dropZone {
|
56
|
+
cursor: settings.$drop-zone-disabled-cursor;
|
57
|
+
}
|
58
|
+
|
59
|
+
.root:not(.isRootDisabled, .isRootDragging) .dropZone:hover {
|
60
|
+
--rui-local-border-color: #{settings.$drop-zone-hover-border-color};
|
61
|
+
}
|
62
|
+
|
63
|
+
.root:not(.isRootDisabled, .isRootDragging) .dropZone:active {
|
64
|
+
--rui-local-border-color: #{settings.$drop-zone-active-border-color};
|
65
|
+
}
|
66
|
+
|
67
|
+
.dropZoneLink {
|
68
|
+
@include links.base();
|
69
|
+
|
70
|
+
&::before {
|
71
|
+
content: "";
|
72
|
+
position: absolute;
|
73
|
+
inset: 0;
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
21
77
|
.helpText,
|
22
78
|
.validationText {
|
23
79
|
@include foundation.help-text();
|
@@ -28,6 +84,18 @@
|
|
28
84
|
}
|
29
85
|
|
30
86
|
// States
|
87
|
+
.isRootDisabled {
|
88
|
+
--rui-local-color: #{settings.$drop-zone-disabled-color};
|
89
|
+
--rui-local-border-color: #{settings.$drop-zone-disabled-border-color};
|
90
|
+
--rui-local-background: #{settings.$drop-zone-disabled-background-color};
|
91
|
+
|
92
|
+
@include variants.disabled-state();
|
93
|
+
}
|
94
|
+
|
95
|
+
.isRootDisabled .dropZoneLink {
|
96
|
+
cursor: inherit;
|
97
|
+
}
|
98
|
+
|
31
99
|
.isRootStateInvalid {
|
32
100
|
@include variants.validation(invalid);
|
33
101
|
}
|
@@ -56,10 +124,28 @@
|
|
56
124
|
}
|
57
125
|
|
58
126
|
.isRootFullWidth {
|
59
|
-
@include box-field-layout.full-width();
|
127
|
+
@include box-field-layout.full-width($input-element-selector: ".dropZone");
|
60
128
|
}
|
61
129
|
|
62
130
|
.isRootInFormLayout {
|
63
131
|
@include box-field-layout.in-form-layout();
|
64
132
|
}
|
133
|
+
|
134
|
+
// Sizes
|
135
|
+
.isRootSizeSmall {
|
136
|
+
@include box-field-sizes.size(small);
|
137
|
+
}
|
138
|
+
|
139
|
+
.isRootSizeMedium {
|
140
|
+
@include box-field-sizes.size(medium);
|
141
|
+
}
|
142
|
+
|
143
|
+
.isRootSizeLarge {
|
144
|
+
@include box-field-sizes.size(large);
|
145
|
+
}
|
146
|
+
|
147
|
+
// Groups
|
148
|
+
.isRootGrouped {
|
149
|
+
@include box-field-elements.in-group-layout($input-element-selector: ".dropZone");
|
150
|
+
}
|
65
151
|
}
|
@@ -13,7 +13,7 @@ import { FileInputField } from '@react-ui-org/react-ui';
|
|
13
13
|
And use it:
|
14
14
|
|
15
15
|
```docoff-react-preview
|
16
|
-
<FileInputField label="Attachment" />
|
16
|
+
<FileInputField id="my-file" label="Attachment" onFilesChanged={() => {}} />
|
17
17
|
```
|
18
18
|
|
19
19
|
See [API](#api) for all available options.
|
@@ -48,12 +48,37 @@ layout perspective, FileInputFields work just like any other form fields.
|
|
48
48
|
|
49
49
|
## Sizes
|
50
50
|
|
51
|
+
Aside from the default (medium) size, two additional sizes are available: small
|
52
|
+
and large.
|
53
|
+
|
54
|
+
```docoff-react-preview
|
55
|
+
<FileInputField
|
56
|
+
id="my-file-small"
|
57
|
+
label="Attachment"
|
58
|
+
onFilesChanged={() => {}}
|
59
|
+
size="small"
|
60
|
+
/>
|
61
|
+
<FileInputField
|
62
|
+
id="my-file-medium"
|
63
|
+
label="Attachment"
|
64
|
+
onFilesChanged={() => {}}
|
65
|
+
/>
|
66
|
+
<FileInputField
|
67
|
+
id="my-file-large"
|
68
|
+
label="Attachment"
|
69
|
+
onFilesChanged={() => {}}
|
70
|
+
size="large"
|
71
|
+
/>
|
72
|
+
```
|
73
|
+
|
51
74
|
Full-width fields span the full width of a parent:
|
52
75
|
|
53
76
|
```docoff-react-preview
|
54
77
|
<FileInputField
|
55
78
|
fullWidth
|
79
|
+
id="my-file"
|
56
80
|
label="First name"
|
81
|
+
onFilesChanged={() => {}}
|
57
82
|
/>
|
58
83
|
```
|
59
84
|
|
@@ -68,8 +93,10 @@ dangerous to hide labels from users in most cases. Keep in mind you should
|
|
68
93
|
|
69
94
|
```docoff-react-preview
|
70
95
|
<FileInputField
|
96
|
+
id="my-file"
|
71
97
|
isLabelVisible={false}
|
72
98
|
label="Attachment"
|
99
|
+
onFilesChanged={() => {}}
|
73
100
|
/>
|
74
101
|
```
|
75
102
|
|
@@ -81,14 +108,18 @@ supports this kind of layout as well.
|
|
81
108
|
|
82
109
|
```docoff-react-preview
|
83
110
|
<FileInputField
|
111
|
+
id="my-file-horizontal"
|
84
112
|
label="Attachment"
|
85
113
|
layout="horizontal"
|
114
|
+
onFilesChanged={() => {}}
|
86
115
|
/>
|
87
116
|
<FileInputField
|
88
117
|
fullWidth
|
118
|
+
id="my-file-horizontal-full-width"
|
89
119
|
isLabelVisible={false}
|
90
120
|
label="Attachment"
|
91
121
|
layout="horizontal"
|
122
|
+
onFilesChanged={() => {}}
|
92
123
|
/>
|
93
124
|
```
|
94
125
|
|
@@ -100,18 +131,24 @@ filled.
|
|
100
131
|
```docoff-react-preview
|
101
132
|
<FileInputField
|
102
133
|
helpText="Choose one or more files to upload."
|
134
|
+
id="my-file-help-text"
|
103
135
|
label="Attachment"
|
136
|
+
onFilesChanged={() => {}}
|
104
137
|
/>
|
105
138
|
<FileInputField
|
106
139
|
helpText="Choose one or more files to upload."
|
140
|
+
id="my-file-help-text-horizontal"
|
107
141
|
label="Attachment"
|
108
142
|
layout="horizontal"
|
143
|
+
onFilesChanged={() => {}}
|
109
144
|
/>
|
110
145
|
<FileInputField
|
111
146
|
fullWidth
|
112
147
|
helpText="Choose one or more files to upload."
|
148
|
+
id="my-file-help-text-horizontal-full-width"
|
113
149
|
label="Attachment"
|
114
150
|
layout="horizontal"
|
151
|
+
onFilesChanged={() => {}}
|
115
152
|
/>
|
116
153
|
```
|
117
154
|
|
@@ -126,17 +163,23 @@ have.
|
|
126
163
|
|
127
164
|
```docoff-react-preview
|
128
165
|
<FileInputField
|
166
|
+
id="my-file-valid"
|
129
167
|
label="Attachment"
|
168
|
+
onFilesChanged={() => {}}
|
130
169
|
validationState="valid"
|
131
170
|
validationText="Looks good!"
|
132
171
|
/>
|
133
172
|
<FileInputField
|
173
|
+
id="my-file-invalid"
|
134
174
|
label="Attachment"
|
175
|
+
onFilesChanged={() => {}}
|
135
176
|
validationState="invalid"
|
136
177
|
validationText="Your file is too big. Please select something smaller."
|
137
178
|
/>
|
138
179
|
<FileInputField
|
180
|
+
id="my-file-warning"
|
139
181
|
label="Attachment"
|
182
|
+
onFilesChanged={() => {}}
|
140
183
|
validationState="warning"
|
141
184
|
validationText={`
|
142
185
|
You selected more than 10 files.
|
@@ -152,7 +195,44 @@ It's possible to disable the whole input.
|
|
152
195
|
```docoff-react-preview
|
153
196
|
<FileInputField
|
154
197
|
disabled
|
198
|
+
id="my-file"
|
155
199
|
label="Attachment"
|
200
|
+
onFilesChanged={() => {}}
|
201
|
+
/>
|
202
|
+
```
|
203
|
+
|
204
|
+
## Handling Files
|
205
|
+
|
206
|
+
Files selected by the user are handled by providing a custom function to the
|
207
|
+
`onFilesChanged` prop. The `onFilesChanged` function is then called on the
|
208
|
+
`change` event of the `input` element and on the `drop` event of the root
|
209
|
+
`div` element.
|
210
|
+
|
211
|
+
```docoff-react-preview
|
212
|
+
<FileInputField
|
213
|
+
id="my-file"
|
214
|
+
label="Attachment"
|
215
|
+
onFilesChanged={(files, event) => {
|
216
|
+
// Do something with the files…
|
217
|
+
console.log('Files selected:', files);
|
218
|
+
}}
|
219
|
+
/>
|
220
|
+
```
|
221
|
+
|
222
|
+
### Multiple Files
|
223
|
+
|
224
|
+
By default, users can select only one file. To allow selecting multiple files,
|
225
|
+
set the `multiple` prop to `true`.
|
226
|
+
|
227
|
+
```docoff-react-preview
|
228
|
+
<FileInputField
|
229
|
+
id="my-files"
|
230
|
+
label="Attachment"
|
231
|
+
multiple
|
232
|
+
onFilesChanged={(files, event) => {
|
233
|
+
// Do something with the files…
|
234
|
+
console.log('Files selected:', files);
|
235
|
+
}}
|
156
236
|
/>
|
157
237
|
```
|
158
238
|
|
@@ -172,8 +252,9 @@ to improve its accessibility.
|
|
172
252
|
Choose up to 10 files. Allowed extensions are .pdf, .jpg, .jpeg, or .png.
|
173
253
|
Size limit is 10 MB.
|
174
254
|
`}
|
255
|
+
id="my-file"
|
175
256
|
label="Attachment"
|
176
|
-
|
257
|
+
onFilesChanged={() => {}}
|
177
258
|
/>
|
178
259
|
```
|
179
260
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
@use "../../styles/theme/typography";
|
2
|
+
|
3
|
+
$drop-zone-color: var(--rui-color-text-primary);
|
4
|
+
$drop-zone-disabled-color: var(--rui-color-text-primary-disabled);
|
5
|
+
$drop-zone-border-color: var(--rui-color-border-primary);
|
6
|
+
$drop-zone-hover-border-color: var(--rui-color-border-primary-hover);
|
7
|
+
$drop-zone-active-border-color: var(--rui-color-border-primary-active);
|
8
|
+
$drop-zone-dragging-border-color: var(--rui-color-border-primary-active);
|
9
|
+
$drop-zone-disabled-border-color: var(--rui-color-border-primary);
|
10
|
+
$drop-zone-background-color: var(--rui-color-background-basic);
|
11
|
+
$drop-zone-disabled-background-color: var(--rui-color-background-disabled);
|
12
|
+
$drop-zone-disabled-cursor: var(--rui-cursor-not-allowed);
|
13
|
+
$drop-zone-font-weight: typography.$font-weight-base;
|
14
|
+
$drop-zone-line-height: typography.$line-height-base;
|
15
|
+
$drop-zone-font-family: typography.$font-family-base;
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import PropTypes from 'prop-types';
|
2
2
|
import React, { useMemo } from 'react';
|
3
3
|
import { withGlobalProps } from '../../providers/globalProps';
|
4
|
-
import { classNames } from '../../
|
5
|
-
import { transferProps } from '../../
|
4
|
+
import { classNames } from '../../helpers/classNames/classNames';
|
5
|
+
import { transferProps } from '../../helpers/transferProps';
|
6
6
|
import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
|
7
7
|
import { FormLayoutContext } from './FormLayoutContext';
|
8
8
|
import styles from './FormLayout.module.scss';
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import PropTypes from 'prop-types';
|
2
2
|
import React, { useContext } from 'react';
|
3
3
|
import { withGlobalProps } from '../../providers/globalProps';
|
4
|
-
import { classNames } from '../../
|
5
|
-
import { transferProps } from '../../
|
4
|
+
import { classNames } from '../../helpers/classNames/classNames';
|
5
|
+
import { transferProps } from '../../helpers/transferProps';
|
6
6
|
import { getRootSizeClassName } from '../_helpers/getRootSizeClassName';
|
7
7
|
import { getRootValidationStateClassName } from '../_helpers/getRootValidationStateClassName';
|
8
8
|
import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
|
@@ -300,7 +300,7 @@ This is a demo of all components supported by FormLayout.
|
|
300
300
|
|
301
301
|
```docoff-react-preview
|
302
302
|
React.createElement(() => {
|
303
|
-
const [fieldLayout, setFieldLayout] = React.useState('
|
303
|
+
const [fieldLayout, setFieldLayout] = React.useState('horizontal');
|
304
304
|
const [fruit, setFruit] = React.useState('apple');
|
305
305
|
const [isDeliveryAddress, setIsDeliveryAddress] = React.useState(true);
|
306
306
|
const [receiveNewsletter, setReceiveNewsletter] = React.useState(true);
|
@@ -323,16 +323,16 @@ React.createElement(() => {
|
|
323
323
|
<Toolbar>
|
324
324
|
<ToolbarItem>
|
325
325
|
<ButtonGroup>
|
326
|
-
<Button
|
327
|
-
color={fieldLayout === 'vertical' ? 'selected' : 'secondary'}
|
328
|
-
label="Vertical layout"
|
329
|
-
onClick={() => setFieldLayout('vertical')}
|
330
|
-
/>
|
331
326
|
<Button
|
332
327
|
color={fieldLayout === 'horizontal' ? 'selected' : 'secondary'}
|
333
328
|
label="Horizontal layout"
|
334
329
|
onClick={() => setFieldLayout('horizontal')}
|
335
330
|
/>
|
331
|
+
<Button
|
332
|
+
color={fieldLayout === 'vertical' ? 'selected' : 'secondary'}
|
333
|
+
label="Vertical layout"
|
334
|
+
onClick={() => setFieldLayout('vertical')}
|
335
|
+
/>
|
336
336
|
</ButtonGroup>
|
337
337
|
</ToolbarItem>
|
338
338
|
</Toolbar>
|
@@ -388,7 +388,9 @@ React.createElement(() => {
|
|
388
388
|
rows={3}
|
389
389
|
/>
|
390
390
|
<FileInputField
|
391
|
+
id="my-file"
|
391
392
|
label="Attachment"
|
393
|
+
onFilesChanged={() => {}}
|
392
394
|
/>
|
393
395
|
<Toggle
|
394
396
|
checked={receiveNewsletter}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import PropTypes from 'prop-types';
|
2
2
|
import React from 'react';
|
3
3
|
import { withGlobalProps } from '../../providers/globalProps';
|
4
|
-
import { transferProps } from '../../
|
4
|
+
import { transferProps } from '../../helpers/transferProps';
|
5
5
|
import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
|
6
6
|
import { generateResponsiveCustomProperties } from './_helpers/generateResponsiveCustomProperties';
|
7
7
|
import styles from './Grid.module.scss';
|
@@ -20,8 +20,8 @@
|
|
20
20
|
//
|
21
21
|
// 2. Apply custom property value that is defined within current breakpoint, see 1.
|
22
22
|
//
|
23
|
-
// 3. Intentionally use longhand properties because the custom property fallback mechanism evaluates `initial` values
|
24
|
-
// empty. That makes the other value of the shorthand property unexpectedly used for both axes.
|
23
|
+
// 3. Intentionally use longhand properties because the custom property fallback mechanism evaluates `initial` values
|
24
|
+
// as empty. That makes the other value of the shorthand property unexpectedly used for both axes.
|
25
25
|
|
26
26
|
@use "sass:map";
|
27
27
|
@use "../../styles/tools/spacing";
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import PropTypes from 'prop-types';
|
2
2
|
import React from 'react';
|
3
3
|
import { withGlobalProps } from '../../providers/globalProps';
|
4
|
-
import { transferProps } from '../../
|
4
|
+
import { transferProps } from '../../helpers/transferProps';
|
5
5
|
import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
|
6
6
|
import { generateResponsiveCustomProperties } from './_helpers/generateResponsiveCustomProperties';
|
7
7
|
import styles from './Grid.module.scss';
|
@@ -4,8 +4,8 @@ import React, {
|
|
4
4
|
useMemo,
|
5
5
|
} from 'react';
|
6
6
|
import { withGlobalProps } from '../../providers/globalProps';
|
7
|
-
import { classNames } from '../../
|
8
|
-
import { transferProps } from '../../
|
7
|
+
import { classNames } from '../../helpers/classNames/classNames';
|
8
|
+
import { transferProps } from '../../helpers/transferProps';
|
9
9
|
import { getRootSizeClassName } from '../_helpers/getRootSizeClassName';
|
10
10
|
import { getRootValidationStateClassName } from '../_helpers/getRootValidationStateClassName';
|
11
11
|
import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
|
@@ -84,14 +84,14 @@
|
|
84
84
|
|
85
85
|
// Sizes
|
86
86
|
.isRootSizeSmall {
|
87
|
-
@include box-field-sizes.size(small
|
87
|
+
@include box-field-sizes.size(small);
|
88
88
|
}
|
89
89
|
|
90
90
|
.isRootSizeMedium {
|
91
|
-
@include box-field-sizes.size(medium
|
91
|
+
@include box-field-sizes.size(medium);
|
92
92
|
}
|
93
93
|
|
94
94
|
.isRootSizeLarge {
|
95
|
-
@include box-field-sizes.size(large
|
95
|
+
@include box-field-sizes.size(large);
|
96
96
|
}
|
97
97
|
}
|
@@ -145,7 +145,7 @@ supports this kind of layout as well.
|
|
145
145
|
label="Horizontal layout"
|
146
146
|
layout="horizontal"
|
147
147
|
>
|
148
|
-
<
|
148
|
+
<FileInputField id="my-file" label="Attachment" onFilesChanged={() => {}} />
|
149
149
|
<Button label="Submit" />
|
150
150
|
</InputGroup>
|
151
151
|
```
|
@@ -1,9 +1,19 @@
|
|
1
1
|
import PropTypes from 'prop-types';
|
2
|
-
import React, {
|
2
|
+
import React, {
|
3
|
+
useCallback,
|
4
|
+
useEffect,
|
5
|
+
useImperativeHandle,
|
6
|
+
useRef,
|
7
|
+
} from 'react';
|
3
8
|
import { createPortal } from 'react-dom';
|
9
|
+
import { classNames } from '../../helpers/classNames';
|
10
|
+
import { transferProps } from '../../helpers/transferProps';
|
4
11
|
import { withGlobalProps } from '../../providers/globalProps';
|
5
|
-
import {
|
6
|
-
import {
|
12
|
+
import { getRootColorClassName } from '../_helpers/getRootColorClassName';
|
13
|
+
import { dialogOnCancelHandler } from './_helpers/dialogOnCancelHandler';
|
14
|
+
import { dialogOnClickHandler } from './_helpers/dialogOnClickHandler';
|
15
|
+
import { dialogOnCloseHandler } from './_helpers/dialogOnCloseHandler';
|
16
|
+
import { dialogOnKeyDownHandler } from './_helpers/dialogOnKeyDownHandler';
|
7
17
|
import { getPositionClassName } from './_helpers/getPositionClassName';
|
8
18
|
import { getSizeClassName } from './_helpers/getSizeClassName';
|
9
19
|
import { useModalFocus } from './_hooks/useModalFocus';
|
@@ -12,44 +22,37 @@ import styles from './Modal.module.scss';
|
|
12
22
|
|
13
23
|
const preRender = (
|
14
24
|
children,
|
15
|
-
|
16
|
-
|
25
|
+
color,
|
26
|
+
dialogRef,
|
17
27
|
position,
|
18
|
-
restProps,
|
19
28
|
size,
|
29
|
+
events,
|
30
|
+
restProps,
|
20
31
|
) => (
|
21
|
-
<
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
32
|
+
<dialog
|
33
|
+
{...transferProps(restProps)}
|
34
|
+
{...transferProps(events)}
|
35
|
+
className={classNames(
|
36
|
+
styles.root,
|
37
|
+
color && getRootColorClassName(color, styles),
|
38
|
+
getSizeClassName(size, styles),
|
39
|
+
getPositionClassName(position, styles),
|
40
|
+
)}
|
41
|
+
ref={dialogRef}
|
30
42
|
>
|
31
|
-
|
32
|
-
|
33
|
-
className={classNames(
|
34
|
-
styles.root,
|
35
|
-
getSizeClassName(size, styles),
|
36
|
-
getPositionClassName(position, styles),
|
37
|
-
)}
|
38
|
-
onClick={(e) => {
|
39
|
-
e.stopPropagation();
|
40
|
-
}}
|
41
|
-
ref={childrenWrapperRef}
|
42
|
-
role="presentation"
|
43
|
-
>
|
44
|
-
{children}
|
45
|
-
</div>
|
46
|
-
</div>
|
43
|
+
{children}
|
44
|
+
</dialog>
|
47
45
|
);
|
48
46
|
|
49
47
|
export const Modal = ({
|
48
|
+
allowCloseOnBackdropClick,
|
49
|
+
allowCloseOnEscapeKey,
|
50
|
+
allowPrimaryActionOnEnterKey,
|
50
51
|
autoFocus,
|
51
52
|
children,
|
52
53
|
closeButtonRef,
|
54
|
+
color,
|
55
|
+
dialogRef,
|
53
56
|
portalId,
|
54
57
|
position,
|
55
58
|
preventScrollUnderneath,
|
@@ -57,45 +60,89 @@ export const Modal = ({
|
|
57
60
|
size,
|
58
61
|
...restProps
|
59
62
|
}) => {
|
60
|
-
const
|
63
|
+
const internalDialogRef = useRef();
|
61
64
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
primaryButtonRef,
|
66
|
-
closeButtonRef,
|
67
|
-
);
|
65
|
+
useEffect(() => {
|
66
|
+
internalDialogRef.current.showModal();
|
67
|
+
}, []);
|
68
68
|
|
69
|
+
// We need to have a reference to the dialog element to be able to call its methods,
|
70
|
+
// but at the same time we want to expose this reference to the parent component for
|
71
|
+
// case someone wants to call dialog methods from outside the component.
|
72
|
+
useImperativeHandle(dialogRef, () => internalDialogRef.current);
|
73
|
+
|
74
|
+
useModalFocus(autoFocus, internalDialogRef, primaryButtonRef);
|
69
75
|
useModalScrollPrevention(preventScrollUnderneath);
|
70
76
|
|
77
|
+
const onCancel = useCallback(
|
78
|
+
(e) => dialogOnCancelHandler(e, closeButtonRef, restProps.onCancel),
|
79
|
+
[closeButtonRef, restProps.onCancel],
|
80
|
+
);
|
81
|
+
const onClick = useCallback(
|
82
|
+
(e) => dialogOnClickHandler(e, closeButtonRef, internalDialogRef, allowCloseOnBackdropClick),
|
83
|
+
[allowCloseOnBackdropClick, closeButtonRef, internalDialogRef],
|
84
|
+
);
|
85
|
+
const onClose = useCallback(
|
86
|
+
(e) => dialogOnCloseHandler(e, closeButtonRef, restProps.onClose),
|
87
|
+
[closeButtonRef, restProps.onClose],
|
88
|
+
);
|
89
|
+
const onKeyDown = useCallback(
|
90
|
+
(e) => dialogOnKeyDownHandler(
|
91
|
+
e,
|
92
|
+
closeButtonRef,
|
93
|
+
primaryButtonRef,
|
94
|
+
allowCloseOnEscapeKey,
|
95
|
+
allowPrimaryActionOnEnterKey,
|
96
|
+
),
|
97
|
+
[
|
98
|
+
allowCloseOnEscapeKey,
|
99
|
+
allowPrimaryActionOnEnterKey,
|
100
|
+
closeButtonRef,
|
101
|
+
primaryButtonRef,
|
102
|
+
],
|
103
|
+
);
|
104
|
+
const events = {
|
105
|
+
onCancel,
|
106
|
+
onClick,
|
107
|
+
onClose,
|
108
|
+
onKeyDown,
|
109
|
+
};
|
110
|
+
|
71
111
|
if (portalId === null) {
|
72
112
|
return preRender(
|
73
113
|
children,
|
74
|
-
|
75
|
-
|
114
|
+
color,
|
115
|
+
internalDialogRef,
|
76
116
|
position,
|
77
|
-
restProps,
|
78
117
|
size,
|
118
|
+
events,
|
119
|
+
restProps,
|
79
120
|
);
|
80
121
|
}
|
81
122
|
|
82
123
|
return createPortal(
|
83
124
|
preRender(
|
84
125
|
children,
|
85
|
-
|
86
|
-
|
126
|
+
color,
|
127
|
+
internalDialogRef,
|
87
128
|
position,
|
88
|
-
restProps,
|
89
129
|
size,
|
130
|
+
events,
|
131
|
+
restProps,
|
90
132
|
),
|
91
133
|
document.getElementById(portalId),
|
92
134
|
);
|
93
135
|
};
|
94
136
|
|
95
137
|
Modal.defaultProps = {
|
138
|
+
allowCloseOnBackdropClick: true,
|
139
|
+
allowCloseOnEscapeKey: true,
|
140
|
+
allowPrimaryActionOnEnterKey: true,
|
96
141
|
autoFocus: true,
|
97
142
|
children: null,
|
98
143
|
closeButtonRef: null,
|
144
|
+
color: undefined,
|
145
|
+
dialogRef: null,
|
99
146
|
portalId: null,
|
100
147
|
position: 'center',
|
101
148
|
preventScrollUnderneath: window.document.body,
|
@@ -104,6 +151,18 @@ Modal.defaultProps = {
|
|
104
151
|
};
|
105
152
|
|
106
153
|
Modal.propTypes = {
|
154
|
+
/**
|
155
|
+
* If `true`, the `Modal` can be closed by clicking on the backdrop.
|
156
|
+
*/
|
157
|
+
allowCloseOnBackdropClick: PropTypes.bool,
|
158
|
+
/**
|
159
|
+
* If `true`, the `Modal` can be closed by pressing the Escape key.
|
160
|
+
*/
|
161
|
+
allowCloseOnEscapeKey: PropTypes.bool,
|
162
|
+
/**
|
163
|
+
* If `true`, the `Modal` can be submitted by pressing the Enter key.
|
164
|
+
*/
|
165
|
+
allowPrimaryActionOnEnterKey: PropTypes.bool,
|
107
166
|
/**
|
108
167
|
* If `true`, focus the first input element in the `Modal`, or primary button (referenced by the `primaryButtonRef`
|
109
168
|
* prop), or other focusable element when the `Modal` is opened. If there are none or `autoFocus` is set to `false`,
|
@@ -121,12 +180,25 @@ Modal.propTypes = {
|
|
121
180
|
*/
|
122
181
|
children: PropTypes.node,
|
123
182
|
/**
|
124
|
-
* Reference to close button element. It is used to close modal when Escape key is pressed
|
183
|
+
* Reference to close button element. It is used to close modal when Escape key is pressed
|
184
|
+
* or the backdrop is clicked.
|
125
185
|
*/
|
126
186
|
closeButtonRef: PropTypes.shape({
|
127
187
|
// eslint-disable-next-line react/forbid-prop-types
|
128
188
|
current: PropTypes.any,
|
129
189
|
}),
|
190
|
+
/**
|
191
|
+
* Color to clarify importance and meaning of the modal. Implements
|
192
|
+
* [Feedback color collection](/docs/foundation/collections#colors).
|
193
|
+
*/
|
194
|
+
color: PropTypes.oneOf(['success', 'warning', 'danger', 'help', 'info', 'note']),
|
195
|
+
/**
|
196
|
+
* Reference to dialog element
|
197
|
+
*/
|
198
|
+
dialogRef: PropTypes.shape({
|
199
|
+
// eslint-disable-next-line react/forbid-prop-types
|
200
|
+
current: PropTypes.any,
|
201
|
+
}),
|
130
202
|
/**
|
131
203
|
* If set, modal is rendered in the React Portal with that ID.
|
132
204
|
*/
|