@react-ui-org/react-ui 0.51.0 → 0.52.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|