@react-ui-org/react-ui 0.51.0 → 0.52.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 +140 -32
- package/dist/lib.js +1 -1
- package/package.json +1 -1
- package/src/lib/components/Button/Button.jsx +17 -9
- package/src/lib/components/Button/_base.scss +21 -12
- package/src/lib/components/Button/_priorities.scss +1 -18
- package/src/lib/components/Button/_theme.scss +0 -10
- package/src/lib/components/ButtonGroup/ButtonGroup.jsx +5 -3
- package/src/lib/components/ButtonGroup/ButtonGroup.scss +26 -1
- package/src/lib/components/ButtonGroup/README.mdx +11 -1
- package/src/lib/components/ButtonGroup/_theme.scss +13 -0
- package/src/lib/components/FormLayout/README.mdx +5 -0
- package/src/lib/components/InputGroup/InputGroup.jsx +170 -0
- package/src/lib/components/InputGroup/InputGroup.scss +92 -0
- package/src/lib/components/InputGroup/InputGroupContext.js +3 -0
- package/src/lib/components/InputGroup/README.mdx +278 -0
- package/src/lib/components/InputGroup/_theme.scss +2 -0
- package/src/lib/components/InputGroup/index.js +2 -0
- package/src/lib/components/Modal/Modal.jsx +58 -97
- package/src/lib/components/Modal/README.mdx +288 -15
- package/src/lib/components/Modal/_helpers/getPositionClassName.js +7 -0
- package/src/lib/components/Modal/_helpers/getSizeClassName.js +19 -0
- package/src/lib/components/Modal/_hooks/useModalFocus.js +126 -0
- package/src/lib/components/Modal/_hooks/useModalScrollPrevention.js +35 -0
- package/src/lib/components/Modal/_settings.scss +1 -1
- package/src/lib/components/Radio/README.mdx +9 -1
- package/src/lib/components/Radio/Radio.jsx +39 -31
- package/src/lib/components/Radio/Radio.scss +11 -1
- package/src/lib/components/SelectField/SelectField.jsx +21 -8
- package/src/lib/components/SelectField/SelectField.scss +5 -0
- package/src/lib/components/TextField/TextField.jsx +21 -8
- package/src/lib/components/TextField/TextField.scss +5 -0
- package/src/lib/index.js +1 -0
- package/src/lib/styles/theme/_borders.scss +2 -1
- package/src/lib/styles/tools/form-fields/_box-field-elements.scss +19 -2
- package/src/lib/styles/tools/form-fields/_box-field-sizes.scss +11 -8
- package/src/lib/styles/tools/form-fields/_foundation.scss +7 -0
- package/src/lib/theme.scss +23 -11
- /package/src/lib/components/{Button/helpers → _helpers}/getRootPriorityClassName.js +0 -0
package/package.json
CHANGED
@@ -7,8 +7,9 @@ import { getRootSizeClassName } from '../_helpers/getRootSizeClassName';
|
|
7
7
|
import { resolveContextOrProp } from '../_helpers/resolveContextOrProp';
|
8
8
|
import { transferProps } from '../_helpers/transferProps';
|
9
9
|
import { ButtonGroupContext } from '../ButtonGroup';
|
10
|
+
import { InputGroupContext } from '../InputGroup/InputGroupContext';
|
11
|
+
import getRootPriorityClassName from '../_helpers/getRootPriorityClassName';
|
10
12
|
import getRootLabelVisibilityClassName from './helpers/getRootLabelVisibilityClassName';
|
11
|
-
import getRootPriorityClassName from './helpers/getRootPriorityClassName';
|
12
13
|
import styles from './Button.scss';
|
13
14
|
|
14
15
|
export const Button = React.forwardRef((props, ref) => {
|
@@ -28,8 +29,14 @@ export const Button = React.forwardRef((props, ref) => {
|
|
28
29
|
color,
|
29
30
|
...restProps
|
30
31
|
} = props;
|
32
|
+
const buttonGroupContext = useContext(ButtonGroupContext);
|
33
|
+
const inputGroupContext = useContext(InputGroupContext);
|
31
34
|
|
32
|
-
|
35
|
+
if (buttonGroupContext && inputGroupContext) {
|
36
|
+
throw new Error('Button cannot be placed both in `ButtonGroup` and `InputGroup`.');
|
37
|
+
}
|
38
|
+
|
39
|
+
const primaryContext = buttonGroupContext ?? inputGroupContext;
|
33
40
|
|
34
41
|
return (
|
35
42
|
/* No worries, `type` is always assigned correctly through props. */
|
@@ -39,20 +46,21 @@ export const Button = React.forwardRef((props, ref) => {
|
|
39
46
|
className={classNames(
|
40
47
|
styles.root,
|
41
48
|
getRootPriorityClassName(
|
42
|
-
resolveContextOrProp(
|
49
|
+
resolveContextOrProp(buttonGroupContext && buttonGroupContext.priority, priority),
|
43
50
|
styles,
|
44
51
|
),
|
45
52
|
getRootColorClassName(color, styles),
|
46
53
|
getRootSizeClassName(
|
47
|
-
resolveContextOrProp(
|
54
|
+
resolveContextOrProp(primaryContext && primaryContext.size, size),
|
48
55
|
styles,
|
49
56
|
),
|
50
57
|
getRootLabelVisibilityClassName(labelVisibility, styles),
|
51
|
-
resolveContextOrProp(
|
52
|
-
|
58
|
+
resolveContextOrProp(buttonGroupContext && buttonGroupContext.block, block) && styles.isRootBlock,
|
59
|
+
buttonGroupContext && styles.isRootInButtonGroup,
|
60
|
+
inputGroupContext && styles.isRootInInputGroup,
|
53
61
|
feedbackIcon && styles.hasRootFeedback,
|
54
62
|
)}
|
55
|
-
disabled={resolveContextOrProp(
|
63
|
+
disabled={resolveContextOrProp(primaryContext && primaryContext.disabled, disabled) || !!feedbackIcon}
|
56
64
|
id={id}
|
57
65
|
ref={ref}
|
58
66
|
>
|
@@ -171,8 +179,8 @@ Button.propTypes = {
|
|
171
179
|
/**
|
172
180
|
* Size of the button.
|
173
181
|
*
|
174
|
-
* Ignored if the component is rendered within `ButtonGroup` component
|
175
|
-
*
|
182
|
+
* Ignored if the component is rendered within `ButtonGroup` or `InputGroup` component as the value is inherited in
|
183
|
+
* such case.
|
176
184
|
*/
|
177
185
|
size: PropTypes.oneOf(['small', 'medium', 'large']),
|
178
186
|
/**
|
@@ -1,3 +1,6 @@
|
|
1
|
+
// 1. ButtonGroup gap is implemented using the `margin` property so the buttons can overlap and reduce duplicate
|
2
|
+
// borders.
|
3
|
+
|
1
4
|
@use "sass:map";
|
2
5
|
@use "../../styles/tools/breakpoint";
|
3
6
|
@use "settings";
|
@@ -76,28 +79,34 @@
|
|
76
79
|
color: transparent;
|
77
80
|
}
|
78
81
|
|
79
|
-
.
|
82
|
+
.isRootInButtonGroup,
|
83
|
+
.isRootInInputGroup {
|
80
84
|
z-index: map.get(settings.$group-z-indexes, button);
|
81
85
|
|
82
86
|
&:not(:first-child) {
|
83
|
-
|
84
|
-
border-
|
85
|
-
border-bottom-left-radius: 0;
|
87
|
+
border-start-start-radius: var(--rui-local-inner-border-radius);
|
88
|
+
border-end-start-radius: var(--rui-local-inner-border-radius);
|
86
89
|
}
|
87
90
|
|
88
91
|
&:not(:last-child) {
|
89
|
-
border-
|
90
|
-
border-
|
92
|
+
border-start-end-radius: var(--rui-local-inner-border-radius);
|
93
|
+
border-end-end-radius: var(--rui-local-inner-border-radius);
|
91
94
|
}
|
95
|
+
}
|
92
96
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
+
.isRootInButtonGroup:not(:first-child) {
|
98
|
+
margin-inline-start: var(--rui-local-gap); // 1.
|
99
|
+
}
|
100
|
+
|
101
|
+
.isRootInButtonGroup:focus,
|
102
|
+
.isRootInButtonGroup:not(:disabled):hover {
|
103
|
+
z-index: map.get(settings.$group-z-indexes, button-hover);
|
97
104
|
}
|
98
105
|
|
99
|
-
.
|
100
|
-
.
|
106
|
+
.isRootInButtonGroup .startCorner,
|
107
|
+
.isRootInInputGroup .startCorner,
|
108
|
+
.isRootInButtonGroup .endCorner,
|
109
|
+
.isRootInInputGroup .endCorner {
|
101
110
|
z-index: map.get(settings.$group-z-indexes, button-overflowing-elements);
|
102
111
|
}
|
103
112
|
|
@@ -135,8 +135,7 @@
|
|
135
135
|
@include tools.button-color(flat, dark);
|
136
136
|
}
|
137
137
|
|
138
|
-
.
|
139
|
-
.isRootPriorityFlat.isRootGrouped:not(:first-child)::before {
|
138
|
+
.isRootInButtonGroup:not(:first-child)::before {
|
140
139
|
content: "";
|
141
140
|
position: absolute;
|
142
141
|
top: calc(-1 * #{theme.$border-width});
|
@@ -146,19 +145,3 @@
|
|
146
145
|
border-left: var(--rui-local-separator-width) solid var(--rui-local-separator-color);
|
147
146
|
transform: translateX(calc(-0.5 * var(--rui-local-gap) - 50%));
|
148
147
|
}
|
149
|
-
|
150
|
-
.isRootPriorityFilled.isRootGrouped:not(:first-child) {
|
151
|
-
--rui-local-gap: #{theme.$group-filled-gap};
|
152
|
-
--rui-local-separator-width: #{theme.$group-filled-separator-width};
|
153
|
-
--rui-local-separator-color: #{theme.$group-filled-separator-color};
|
154
|
-
}
|
155
|
-
|
156
|
-
.isRootPriorityFlat.isRootGrouped:not(:first-child) {
|
157
|
-
--rui-local-gap: #{theme.$group-flat-gap};
|
158
|
-
--rui-local-separator-width: #{theme.$group-flat-separator-width};
|
159
|
-
--rui-local-separator-color: #{theme.$group-flat-separator-color};
|
160
|
-
}
|
161
|
-
|
162
|
-
.isRootPriorityOutline.isRootGrouped:not(:first-child) {
|
163
|
-
--rui-local-gap: #{theme.$group-outline-gap};
|
164
|
-
}
|
@@ -12,16 +12,6 @@ $disabled-cursor: var(--rui-Button--disabled__cursor);
|
|
12
12
|
$feedback-opacity: var(--rui-Button--feedback__opacity);
|
13
13
|
$feedback-cursor: var(--rui-Button--feedback__cursor);
|
14
14
|
|
15
|
-
$group-filled-gap: var(--rui-ButtonGroup--filled__gap);
|
16
|
-
$group-filled-separator-width: var(--rui-ButtonGroup--filled__separator__width);
|
17
|
-
$group-filled-separator-color: var(--rui-ButtonGroup--filled__separator__color);
|
18
|
-
|
19
|
-
$group-flat-gap: var(--rui-ButtonGroup--flat__gap);
|
20
|
-
$group-flat-separator-width: var(--rui-ButtonGroup--flat__separator__width);
|
21
|
-
$group-flat-separator-color: var(--rui-ButtonGroup--flat__separator__color);
|
22
|
-
|
23
|
-
$group-outline-gap: var(--rui-ButtonGroup--outline__gap);
|
24
|
-
|
25
15
|
$sizes: (
|
26
16
|
small: (
|
27
17
|
height: var(--rui-Button--small__height),
|
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
|
|
2
2
|
import React from 'react';
|
3
3
|
import { withGlobalProps } from '../../provider';
|
4
4
|
import { classNames } from '../../utils/classNames';
|
5
|
+
import getRootPriorityClassName from '../_helpers/getRootPriorityClassName';
|
5
6
|
import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
|
6
7
|
import { transferProps } from '../_helpers/transferProps';
|
7
8
|
import styles from './ButtonGroup.scss';
|
@@ -20,13 +21,14 @@ export const ButtonGroup = ({
|
|
20
21
|
}
|
21
22
|
|
22
23
|
return (
|
23
|
-
<
|
24
|
+
<fieldset
|
24
25
|
{...transferProps(restProps)}
|
25
26
|
className={classNames(
|
26
27
|
styles.root,
|
27
28
|
block && styles.isRootBlock,
|
29
|
+
getRootPriorityClassName(priority, styles),
|
28
30
|
)}
|
29
|
-
|
31
|
+
disabled={disabled}
|
30
32
|
>
|
31
33
|
<ButtonGroupContext.Provider
|
32
34
|
value={{
|
@@ -38,7 +40,7 @@ export const ButtonGroup = ({
|
|
38
40
|
>
|
39
41
|
{children}
|
40
42
|
</ButtonGroupContext.Provider>
|
41
|
-
</
|
43
|
+
</fieldset>
|
42
44
|
);
|
43
45
|
};
|
44
46
|
|
@@ -1,5 +1,30 @@
|
|
1
|
+
// 1. ButtonGroup gap is implemented using the `margin` property on buttons so the buttons can overlap and reduce
|
2
|
+
// duplicate borders.
|
3
|
+
|
4
|
+
@use "theme";
|
5
|
+
|
1
6
|
.root {
|
2
|
-
|
7
|
+
--rui-local-inner-border-radius: #{theme.$inner-border-radius};
|
8
|
+
|
9
|
+
display: inline-flex; // 1.
|
10
|
+
}
|
11
|
+
|
12
|
+
.isRootPriorityFilled {
|
13
|
+
--rui-local-gap: #{theme.$filled-gap};
|
14
|
+
--rui-local-separator-width: #{theme.$filled-separator-width};
|
15
|
+
--rui-local-separator-color: #{theme.$filled-separator-color};
|
16
|
+
}
|
17
|
+
|
18
|
+
.isRootPriorityOutline {
|
19
|
+
--rui-local-gap: #{theme.$outline-gap};
|
20
|
+
--rui-local-separator-width: #{theme.$outline-separator-width};
|
21
|
+
--rui-local-separator-color: #{theme.$outline-separator-color};
|
22
|
+
}
|
23
|
+
|
24
|
+
.isRootPriorityFlat {
|
25
|
+
--rui-local-gap: #{theme.$flat-gap};
|
26
|
+
--rui-local-separator-width: #{theme.$flat-separator-width};
|
27
|
+
--rui-local-separator-color: #{theme.$flat-separator-color};
|
3
28
|
}
|
4
29
|
|
5
30
|
.isRootBlock {
|
@@ -59,6 +59,11 @@ See [API](#api) for all available options.
|
|
59
59
|
the [SelectField](/components/select-field) or
|
60
60
|
[Radio](/components/radio) components.
|
61
61
|
|
62
|
+
- In the background, ButtonGroup uses the [`fieldset`][fieldset] element. Not
|
63
|
+
only it improves the [accessibility] of the group, it also allows you to make
|
64
|
+
use of its built-in features like disabling all nested inputs or pairing the
|
65
|
+
group with a form outside. Consult [the MDN docs][fieldset] to learn more.
|
66
|
+
|
62
67
|
- Be careful with using `startCorner` and `endCorner` options for grouped
|
63
68
|
buttons. Overflowing elements may cause undesired interaction problems.
|
64
69
|
|
@@ -266,13 +271,18 @@ its accessibility.
|
|
266
271
|
|
267
272
|
| Custom Property | Description |
|
268
273
|
|--------------------------------------------------------------------|------------------------------------------------|
|
274
|
+
| `--rui-ButtonGroup__inner-border-radius` | Inner border radius of buttons |
|
269
275
|
| `--rui-ButtonGroup--filled__gap` | Gap between `filled` buttons |
|
270
276
|
| `--rui-ButtonGroup--filled__separator__width` | Separator width for `filled` buttons |
|
271
277
|
| `--rui-ButtonGroup--filled__separator__color` | Separator color for `filled` buttons |
|
278
|
+
| `--rui-ButtonGroup--outline__gap` | Gap between `outline` buttons |
|
279
|
+
| `--rui-ButtonGroup--outline__separator__width` | Separator width for `outline` buttons |
|
280
|
+
| `--rui-ButtonGroup--outline__separator__color` | Separator color for `outline` buttons |
|
272
281
|
| `--rui-ButtonGroup--flat__gap` | Gap between `flat` buttons |
|
273
282
|
| `--rui-ButtonGroup--flat__separator__width` | Separator width for `flat` buttons |
|
274
283
|
| `--rui-ButtonGroup--flat__separator__color` | Separator color for `flat` buttons |
|
275
|
-
| `--rui-ButtonGroup--outline__gap` | Gap between `outline` buttons |
|
276
284
|
|
285
|
+
[fieldset]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset
|
286
|
+
[accessibility]: https://www.w3.org/WAI/tutorials/forms/grouping/
|
277
287
|
[React synthetic events]: https://reactjs.org/docs/events.html
|
278
288
|
[div]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div#attributes
|
@@ -0,0 +1,13 @@
|
|
1
|
+
$inner-border-radius: var(--rui-ButtonGroup__inner-border-radius);
|
2
|
+
|
3
|
+
$filled-gap: var(--rui-ButtonGroup--filled__gap);
|
4
|
+
$filled-separator-width: var(--rui-ButtonGroup--filled__separator__width);
|
5
|
+
$filled-separator-color: var(--rui-ButtonGroup--filled__separator__color);
|
6
|
+
|
7
|
+
$outline-gap: var(--rui-ButtonGroup--outline__gap);
|
8
|
+
$outline-separator-width: var(--rui-ButtonGroup--outline__separator__width);
|
9
|
+
$outline-separator-color: var(--rui-ButtonGroup--outline__separator__color);
|
10
|
+
|
11
|
+
$flat-gap: var(--rui-ButtonGroup--flat__gap);
|
12
|
+
$flat-separator-width: var(--rui-ButtonGroup--flat__separator__width);
|
13
|
+
$flat-separator-color: var(--rui-ButtonGroup--flat__separator__color);
|
@@ -27,6 +27,7 @@ import {
|
|
27
27
|
ToolbarItem,
|
28
28
|
FormLayout,
|
29
29
|
FormLayoutCustomField,
|
30
|
+
InputGroup,
|
30
31
|
} from '../..'
|
31
32
|
|
32
33
|
## Basic Usage
|
@@ -441,6 +442,10 @@ This is a demo of all components supported by FormLayout.
|
|
441
442
|
options={options}
|
442
443
|
value={fruit}
|
443
444
|
/>
|
445
|
+
<InputGroup label="Promo code">
|
446
|
+
<TextField label="Code" />
|
447
|
+
<Button label="Apply" color="secondary" priority="outline" />
|
448
|
+
</InputGroup>
|
444
449
|
</FormLayout>
|
445
450
|
</div>
|
446
451
|
)
|
@@ -0,0 +1,170 @@
|
|
1
|
+
import PropTypes from 'prop-types';
|
2
|
+
import React, { useContext } from 'react';
|
3
|
+
import { Text } from '../Text';
|
4
|
+
import { withGlobalProps } from '../../provider';
|
5
|
+
import { classNames } from '../../utils/classNames';
|
6
|
+
import { getRootSizeClassName } from '../_helpers/getRootSizeClassName';
|
7
|
+
import { getRootValidationStateClassName } from '../_helpers/getRootValidationStateClassName';
|
8
|
+
import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
|
9
|
+
import { resolveContextOrProp } from '../_helpers/resolveContextOrProp';
|
10
|
+
import { transferProps } from '../_helpers/transferProps';
|
11
|
+
import { FormLayoutContext } from '../FormLayout';
|
12
|
+
import { InputGroupContext } from './InputGroupContext';
|
13
|
+
import styles from './InputGroup.scss';
|
14
|
+
|
15
|
+
export const InputGroup = ({
|
16
|
+
children,
|
17
|
+
disabled,
|
18
|
+
id,
|
19
|
+
isLabelVisible,
|
20
|
+
label,
|
21
|
+
layout,
|
22
|
+
size,
|
23
|
+
validationTexts,
|
24
|
+
...restProps
|
25
|
+
}) => {
|
26
|
+
const formLayoutContext = useContext(FormLayoutContext);
|
27
|
+
|
28
|
+
if (isChildrenEmpty(children)) {
|
29
|
+
return null;
|
30
|
+
}
|
31
|
+
|
32
|
+
const validationState = children.reduce(
|
33
|
+
(state, child) => {
|
34
|
+
if (state === 'invalid' || (state === 'warning' && child.props.validationState === 'valid')) {
|
35
|
+
return state;
|
36
|
+
}
|
37
|
+
return child.props.validationState ?? state;
|
38
|
+
},
|
39
|
+
null,
|
40
|
+
);
|
41
|
+
|
42
|
+
return (
|
43
|
+
<fieldset
|
44
|
+
{...transferProps(restProps)}
|
45
|
+
id={id}
|
46
|
+
className={classNames(
|
47
|
+
styles.root,
|
48
|
+
formLayoutContext && styles.isRootInFormLayout,
|
49
|
+
resolveContextOrProp(formLayoutContext && formLayoutContext.layout, layout) === 'horizontal'
|
50
|
+
? styles.isRootLayoutHorizontal
|
51
|
+
: styles.isRootLayoutVertical,
|
52
|
+
disabled && styles.isRootDisabled,
|
53
|
+
getRootSizeClassName(size, styles),
|
54
|
+
getRootValidationStateClassName(validationState, styles),
|
55
|
+
)}
|
56
|
+
disabled={disabled}
|
57
|
+
>
|
58
|
+
<legend
|
59
|
+
className={styles.legend}
|
60
|
+
id={id && `${id}__label`}
|
61
|
+
>
|
62
|
+
{label}
|
63
|
+
</legend>
|
64
|
+
<div
|
65
|
+
aria-hidden
|
66
|
+
className={classNames(
|
67
|
+
styles.label,
|
68
|
+
!isLabelVisible && styles.isLabelHidden,
|
69
|
+
)}
|
70
|
+
id={id && `${id}__displayLabel`}
|
71
|
+
>
|
72
|
+
{label}
|
73
|
+
</div>
|
74
|
+
<div className={styles.field}>
|
75
|
+
<div
|
76
|
+
className={styles.inputGroup}
|
77
|
+
id={id && `${id}__group`}
|
78
|
+
>
|
79
|
+
<InputGroupContext.Provider
|
80
|
+
value={{
|
81
|
+
disabled,
|
82
|
+
layout,
|
83
|
+
size,
|
84
|
+
}}
|
85
|
+
>
|
86
|
+
{children}
|
87
|
+
</InputGroupContext.Provider>
|
88
|
+
</div>
|
89
|
+
{validationTexts && (
|
90
|
+
<ul
|
91
|
+
className={styles.validationText}
|
92
|
+
id={id && `${id}__validationTexts`}
|
93
|
+
>
|
94
|
+
{validationTexts.map((validationText) => (
|
95
|
+
<li key={validationText}>
|
96
|
+
<Text blockLevel>
|
97
|
+
{validationText}
|
98
|
+
</Text>
|
99
|
+
</li>
|
100
|
+
))}
|
101
|
+
</ul>
|
102
|
+
)}
|
103
|
+
</div>
|
104
|
+
</fieldset>
|
105
|
+
);
|
106
|
+
};
|
107
|
+
|
108
|
+
InputGroup.defaultProps = {
|
109
|
+
children: null,
|
110
|
+
disabled: false,
|
111
|
+
id: undefined,
|
112
|
+
isLabelVisible: true,
|
113
|
+
layout: 'vertical',
|
114
|
+
size: 'medium',
|
115
|
+
validationTexts: null,
|
116
|
+
};
|
117
|
+
|
118
|
+
InputGroup.propTypes = {
|
119
|
+
/**
|
120
|
+
* Supported elements to be grouped:
|
121
|
+
* * `Button`
|
122
|
+
* * `SelectField`
|
123
|
+
* * `TextField`
|
124
|
+
*
|
125
|
+
* If none are provided nothing is rendered.
|
126
|
+
*/
|
127
|
+
children: PropTypes.node,
|
128
|
+
/**
|
129
|
+
* If `true`, the whole input group with all nested inputs and buttons will be disabled.
|
130
|
+
*/
|
131
|
+
disabled: PropTypes.bool,
|
132
|
+
/**
|
133
|
+
* ID of the root HTML element.
|
134
|
+
*
|
135
|
+
* Also serves as base for ids of nested elements:
|
136
|
+
* * `<ID>__label`
|
137
|
+
* * `<ID>__displayLabel`
|
138
|
+
* * `<ID>__group`
|
139
|
+
* * `<ID>__validationTexts`
|
140
|
+
*/
|
141
|
+
id: PropTypes.string,
|
142
|
+
/**
|
143
|
+
* If `false`, the label will be visually hidden (but remains accessible by assistive
|
144
|
+
* technologies).
|
145
|
+
*/
|
146
|
+
isLabelVisible: PropTypes.bool,
|
147
|
+
/**
|
148
|
+
* Input group label.
|
149
|
+
*/
|
150
|
+
label: PropTypes.string.isRequired,
|
151
|
+
/**
|
152
|
+
* Layout of the group.
|
153
|
+
*
|
154
|
+
* Ignored if the component is rendered within `FormLayout` component
|
155
|
+
* as the value is inherited in such case.
|
156
|
+
*/
|
157
|
+
layout: PropTypes.oneOf(['horizontal', 'vertical']),
|
158
|
+
/**
|
159
|
+
* Size of the `children` elements.
|
160
|
+
*/
|
161
|
+
size: PropTypes.oneOf(['small', 'medium', 'large']),
|
162
|
+
/**
|
163
|
+
* An array of validation messages to be displayed.
|
164
|
+
*/
|
165
|
+
validationTexts: PropTypes.node,
|
166
|
+
};
|
167
|
+
|
168
|
+
export const InputGroupWithGlobalProps = withGlobalProps(InputGroup, 'InputGroup');
|
169
|
+
|
170
|
+
export default InputGroupWithGlobalProps;
|
@@ -0,0 +1,92 @@
|
|
1
|
+
// 1. The class name is intentionally singular because it's targeted by other mixins too.
|
2
|
+
// 2. Use a block-level display mode to prevent extra white space below grouped inputs in Safari.
|
3
|
+
// 3. Prevent individual inputs from overlapping inside narrow containers.
|
4
|
+
// 4. Legends are tricky to style, let's use a `div` instead.
|
5
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset#styling_with_css
|
6
|
+
|
7
|
+
@use "../../styles/tools/form-fields/box-field-elements";
|
8
|
+
@use "../../styles/tools/form-fields/box-field-layout";
|
9
|
+
@use "../../styles/tools/form-fields/box-field-sizes";
|
10
|
+
@use "../../styles/tools/form-fields/foundation";
|
11
|
+
@use "../../styles/tools/form-fields/variants";
|
12
|
+
@use "../../styles/tools/accessibility";
|
13
|
+
@use "../../styles/tools/reset";
|
14
|
+
@use "theme";
|
15
|
+
|
16
|
+
.root {
|
17
|
+
@include foundation.root();
|
18
|
+
@include foundation.fieldset();
|
19
|
+
}
|
20
|
+
|
21
|
+
// 4.
|
22
|
+
.legend {
|
23
|
+
@include accessibility.hide-text();
|
24
|
+
}
|
25
|
+
|
26
|
+
// 4.
|
27
|
+
.label {
|
28
|
+
@include foundation.label();
|
29
|
+
}
|
30
|
+
|
31
|
+
.inputGroup {
|
32
|
+
--rui-local-inner-border-radius: #{theme.$inner-border-radius};
|
33
|
+
|
34
|
+
display: flex; // 2.
|
35
|
+
gap: theme.$gap;
|
36
|
+
}
|
37
|
+
|
38
|
+
// 1.
|
39
|
+
.validationText {
|
40
|
+
@include reset.list();
|
41
|
+
@include foundation.help-text();
|
42
|
+
}
|
43
|
+
|
44
|
+
// States
|
45
|
+
.isRootStateInvalid {
|
46
|
+
@include variants.validation(invalid);
|
47
|
+
}
|
48
|
+
|
49
|
+
.isRootStateValid {
|
50
|
+
@include variants.validation(valid);
|
51
|
+
}
|
52
|
+
|
53
|
+
.isRootStateWarning {
|
54
|
+
@include variants.validation(warning);
|
55
|
+
}
|
56
|
+
|
57
|
+
// Invisible label
|
58
|
+
.isLabelHidden {
|
59
|
+
@include accessibility.hide-text();
|
60
|
+
}
|
61
|
+
|
62
|
+
// Layouts
|
63
|
+
.isRootLayoutVertical,
|
64
|
+
.isRootLayoutHorizontal {
|
65
|
+
@include box-field-layout.vertical();
|
66
|
+
}
|
67
|
+
|
68
|
+
.isRootLayoutVertical .field,
|
69
|
+
.isRootLayoutHorizontal .field {
|
70
|
+
max-width: none; // 3.
|
71
|
+
}
|
72
|
+
|
73
|
+
.isRootLayoutHorizontal {
|
74
|
+
@include box-field-layout.horizontal();
|
75
|
+
}
|
76
|
+
|
77
|
+
.isRootInFormLayout {
|
78
|
+
@include box-field-layout.in-form-layout();
|
79
|
+
}
|
80
|
+
|
81
|
+
// Sizes
|
82
|
+
.isRootSizeSmall {
|
83
|
+
@include box-field-sizes.size(small, $has-input: false);
|
84
|
+
}
|
85
|
+
|
86
|
+
.isRootSizeMedium {
|
87
|
+
@include box-field-sizes.size(medium, $has-input: false);
|
88
|
+
}
|
89
|
+
|
90
|
+
.isRootSizeLarge {
|
91
|
+
@include box-field-sizes.size(large, $has-input: false);
|
92
|
+
}
|