@react-ui-org/react-ui 0.50.2 → 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 +157 -49
- package/dist/lib.js +1 -1
- package/package.json +1 -1
- package/src/lib/components/Alert/Alert.jsx +1 -3
- package/src/lib/components/Alert/Alert.scss +1 -9
- package/src/lib/components/Alert/README.mdx +0 -20
- package/src/lib/components/Alert/_settings.scss +1 -1
- package/src/lib/components/Alert/_theme.scss +0 -10
- package/src/lib/components/Badge/Badge.jsx +1 -3
- package/src/lib/components/Badge/Badge.scss +25 -44
- package/src/lib/components/Badge/README.mdx +6 -14
- package/src/lib/components/Button/Button.jsx +20 -10
- package/src/lib/components/Button/README.mdx +8 -3
- package/src/lib/components/Button/_base.scss +21 -12
- package/src/lib/components/Button/_priorities.scss +13 -18
- package/src/lib/components/Button/_settings.scss +1 -1
- 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 +85 -59
- package/src/lib/components/ButtonGroup/_theme.scss +13 -0
- package/src/lib/components/Card/Card.jsx +1 -3
- package/src/lib/components/Card/Card.scss +0 -9
- package/src/lib/components/Card/README.mdx +0 -16
- package/src/lib/components/Card/_theme.scss +0 -10
- package/src/lib/components/FormLayout/README.mdx +22 -8
- package/src/lib/components/Grid/_helpers/generateResponsiveCustomProperties.js +1 -1
- 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/ModalCloseButton.scss +2 -2
- package/src/lib/components/Modal/README.mdx +392 -128
- 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 +2 -2
- package/src/lib/components/Popover/README.mdx +7 -4
- 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/ScrollView/README.mdx +2 -2
- package/src/lib/components/SelectField/SelectField.jsx +21 -8
- package/src/lib/components/SelectField/SelectField.scss +5 -0
- package/src/lib/components/Table/_components/TableCell.scss +6 -5
- package/src/lib/components/Table/_components/TableHeaderCell/TableHeaderCell.jsx +8 -5
- package/src/lib/components/Table/_settings.scss +5 -6
- package/src/lib/components/Text/README.mdx +14 -8
- package/src/lib/components/TextField/TextField.jsx +21 -8
- package/src/lib/components/TextField/TextField.scss +5 -0
- package/src/lib/components/TextLink/README.mdx +8 -6
- package/src/lib/components/TextLink/TextLink.scss +5 -0
- package/src/lib/components/TextLink/_theme.scss +2 -0
- package/src/lib/components/Toolbar/README.mdx +19 -11
- package/src/lib/components/_helpers/getRootColorClassName.js +4 -0
- package/src/lib/index.js +1 -0
- package/src/lib/styles/elements/_code.scss +1 -3
- package/src/lib/styles/elements/_page.scss +1 -0
- package/src/lib/styles/elements/_rulers.scss +1 -3
- package/src/lib/styles/elements/_small.scss +1 -1
- package/src/lib/styles/settings/_form-fields.scss +1 -1
- package/src/lib/styles/settings/_utilities.scss +46 -14
- package/src/lib/styles/theme/_accessibility.scss +4 -4
- package/src/lib/styles/theme/_borders.scss +3 -2
- package/src/lib/styles/theme/_code.scss +2 -2
- package/src/lib/styles/theme/_links.scss +6 -4
- package/src/lib/styles/theme/_lists.scss +1 -1
- package/src/lib/styles/theme/_page.scss +2 -2
- package/src/lib/styles/theme/_spacing.scss +11 -11
- package/src/lib/styles/theme/_typography.scss +19 -18
- package/src/lib/styles/theme-constants/_colors.scss +23 -23
- package/src/lib/styles/tools/_spacing.scss +1 -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 +650 -567
- package/src/lib/styles/theme/_colors.scss +0 -65
- /package/src/lib/components/{Button/helpers → _helpers}/getRootPriorityClassName.js +0 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
export const getSizeClassName = (modalSize, styles) => {
|
2
|
+
if (modalSize === 'small') {
|
3
|
+
return styles.isRootSizeSmall;
|
4
|
+
}
|
5
|
+
|
6
|
+
if (modalSize === 'medium') {
|
7
|
+
return styles.isRootSizeMedium;
|
8
|
+
}
|
9
|
+
|
10
|
+
if (modalSize === 'large') {
|
11
|
+
return styles.isRootSizeLarge;
|
12
|
+
}
|
13
|
+
|
14
|
+
if (modalSize === 'fullscreen') {
|
15
|
+
return styles.isRootSizeFullscreen;
|
16
|
+
}
|
17
|
+
|
18
|
+
return styles.isRootSizeAuto;
|
19
|
+
};
|
@@ -0,0 +1,126 @@
|
|
1
|
+
import { useEffect } from 'react';
|
2
|
+
|
3
|
+
export const useModalFocus = (
|
4
|
+
autoFocus,
|
5
|
+
childrenWrapperRef,
|
6
|
+
primaryButtonRef,
|
7
|
+
closeButtonRef,
|
8
|
+
) => {
|
9
|
+
useEffect(
|
10
|
+
() => {
|
11
|
+
// Following code finds all focusable elements and among them first not disabled form
|
12
|
+
// field element (input, textarea or select) or primary button and focuses it. This is
|
13
|
+
// necessary to have focus on one of those elements to be able to submit the form
|
14
|
+
// by pressing Enter key. If there are neither, it tries to focus any other focusable
|
15
|
+
// elements. In case there are none or `autoFocus` is disabled, childrenWrapperElement
|
16
|
+
// (Modal itself) is focused.
|
17
|
+
|
18
|
+
const childrenWrapperElement = childrenWrapperRef.current;
|
19
|
+
|
20
|
+
if (childrenWrapperElement == null) {
|
21
|
+
return () => {};
|
22
|
+
}
|
23
|
+
|
24
|
+
const childrenFocusableElements = Array.from(
|
25
|
+
childrenWrapperElement.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'),
|
26
|
+
);
|
27
|
+
|
28
|
+
const firstFocusableElement = childrenFocusableElements[0];
|
29
|
+
const lastFocusableElement = childrenFocusableElements[childrenFocusableElements.length - 1];
|
30
|
+
|
31
|
+
const resolveFocusBeforeListener = () => {
|
32
|
+
if (!autoFocus || childrenFocusableElements.length === 0) {
|
33
|
+
childrenWrapperElement.tabIndex = -1;
|
34
|
+
childrenWrapperElement.focus();
|
35
|
+
return;
|
36
|
+
}
|
37
|
+
|
38
|
+
const firstFormFieldEl = childrenFocusableElements.find(
|
39
|
+
(element) => ['INPUT', 'TEXTAREA', 'SELECT'].includes(element.nodeName) && !element.disabled,
|
40
|
+
);
|
41
|
+
|
42
|
+
if (firstFormFieldEl) {
|
43
|
+
firstFormFieldEl.focus();
|
44
|
+
return;
|
45
|
+
}
|
46
|
+
|
47
|
+
if (primaryButtonRef?.current != null) {
|
48
|
+
primaryButtonRef.current.focus();
|
49
|
+
return;
|
50
|
+
}
|
51
|
+
|
52
|
+
firstFocusableElement.focus();
|
53
|
+
};
|
54
|
+
|
55
|
+
const keyPressHandler = (e) => {
|
56
|
+
if (e.key === 'Escape' && closeButtonRef?.current != null) {
|
57
|
+
closeButtonRef.current.click();
|
58
|
+
return;
|
59
|
+
}
|
60
|
+
|
61
|
+
if (
|
62
|
+
e.key === 'Enter'
|
63
|
+
&& e.target.nodeName !== 'BUTTON'
|
64
|
+
&& e.target.nodeName !== 'TEXTAREA'
|
65
|
+
&& e.target.nodeName !== 'A'
|
66
|
+
&& primaryButtonRef?.current != null
|
67
|
+
) {
|
68
|
+
primaryButtonRef.current.click();
|
69
|
+
return;
|
70
|
+
}
|
71
|
+
|
72
|
+
// Following code traps focus inside Modal
|
73
|
+
|
74
|
+
if (e.key !== 'Tab') {
|
75
|
+
return;
|
76
|
+
}
|
77
|
+
|
78
|
+
if (childrenFocusableElements.length === 0) {
|
79
|
+
childrenWrapperElement.focus();
|
80
|
+
e.preventDefault();
|
81
|
+
return;
|
82
|
+
}
|
83
|
+
|
84
|
+
if (
|
85
|
+
![
|
86
|
+
...childrenFocusableElements,
|
87
|
+
childrenWrapperElement,
|
88
|
+
]
|
89
|
+
.includes(window.document.activeElement)
|
90
|
+
) {
|
91
|
+
firstFocusableElement.focus();
|
92
|
+
e.preventDefault();
|
93
|
+
return;
|
94
|
+
}
|
95
|
+
|
96
|
+
if (!e.shiftKey && window.document.activeElement === lastFocusableElement) {
|
97
|
+
firstFocusableElement.focus();
|
98
|
+
e.preventDefault();
|
99
|
+
return;
|
100
|
+
}
|
101
|
+
|
102
|
+
if (e.shiftKey
|
103
|
+
&& (
|
104
|
+
window.document.activeElement === firstFocusableElement
|
105
|
+
|| window.document.activeElement === childrenWrapperElement
|
106
|
+
)
|
107
|
+
) {
|
108
|
+
lastFocusableElement.focus();
|
109
|
+
e.preventDefault();
|
110
|
+
}
|
111
|
+
};
|
112
|
+
|
113
|
+
resolveFocusBeforeListener();
|
114
|
+
|
115
|
+
window.document.addEventListener('keydown', keyPressHandler, false);
|
116
|
+
|
117
|
+
return () => window.document.removeEventListener('keydown', keyPressHandler, false);
|
118
|
+
},
|
119
|
+
[
|
120
|
+
autoFocus,
|
121
|
+
childrenWrapperRef,
|
122
|
+
primaryButtonRef,
|
123
|
+
closeButtonRef,
|
124
|
+
],
|
125
|
+
);
|
126
|
+
};
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import { useLayoutEffect } from 'react';
|
2
|
+
|
3
|
+
export const useModalScrollPrevention = (preventScrollUnderneath) => {
|
4
|
+
useLayoutEffect(
|
5
|
+
() => {
|
6
|
+
if (preventScrollUnderneath === 'off') {
|
7
|
+
return () => {};
|
8
|
+
}
|
9
|
+
|
10
|
+
if (preventScrollUnderneath === 'default') {
|
11
|
+
const scrollbarWidth = Math.abs(window.innerWidth - window.document.documentElement.clientWidth);
|
12
|
+
const prevOverflow = window.document.body.style.overflow;
|
13
|
+
const prevPaddingRight = window.document.body.style.paddingRight;
|
14
|
+
|
15
|
+
window.document.body.style.overflow = 'hidden';
|
16
|
+
|
17
|
+
if (Number.isNaN(parseInt(prevPaddingRight, 10))) {
|
18
|
+
window.document.body.style.paddingRight = `${scrollbarWidth}px`;
|
19
|
+
} else {
|
20
|
+
window.document.body.style.paddingRight = `calc(${prevPaddingRight} + ${scrollbarWidth}px)`;
|
21
|
+
}
|
22
|
+
|
23
|
+
return () => {
|
24
|
+
window.document.body.style.overflow = prevOverflow;
|
25
|
+
window.document.body.style.paddingRight = prevPaddingRight;
|
26
|
+
};
|
27
|
+
}
|
28
|
+
|
29
|
+
preventScrollUnderneath?.start();
|
30
|
+
|
31
|
+
return preventScrollUnderneath?.reset;
|
32
|
+
},
|
33
|
+
[preventScrollUnderneath],
|
34
|
+
);
|
35
|
+
};
|
@@ -3,7 +3,7 @@
|
|
3
3
|
@use "../../styles/theme/borders";
|
4
4
|
@use "../../styles/theme/typography";
|
5
5
|
|
6
|
-
$border-radius: borders.$radius;
|
6
|
+
$border-radius: borders.$radius-2;
|
7
7
|
$z-index: z-indexes.$modal;
|
8
8
|
$backdrop-z-index: z-indexes.$modal-backdrop;
|
9
|
-
$title-font-size: map.get(typography.$size-values,
|
9
|
+
$title-font-size: map.get(typography.$font-size-values, 2);
|
@@ -88,19 +88,22 @@ complete list of accepted values.
|
|
88
88
|
<span id="alignment-options-label">Alignment:</span>
|
89
89
|
</ToolbarItem>
|
90
90
|
<ToolbarItem>
|
91
|
-
<ButtonGroup aria-labelledby="alignment-options-label">
|
91
|
+
<ButtonGroup aria-labelledby="alignment-options-label" priority="outline">
|
92
92
|
<Button
|
93
|
-
|
93
|
+
aria-pressed={align === '-start'}
|
94
|
+
color={align === '-start' ? 'selected' : 'secondary'}
|
94
95
|
label="start"
|
95
96
|
onClick={() => setAlign('-start')}
|
96
97
|
/>
|
97
98
|
<Button
|
98
|
-
|
99
|
+
aria-pressed={align === ''}
|
100
|
+
color={align === '' ? 'selected' : 'secondary'}
|
99
101
|
label="center"
|
100
102
|
onClick={() => setAlign('')}
|
101
103
|
/>
|
102
104
|
<Button
|
103
|
-
|
105
|
+
aria-pressed={align === '-end'}
|
106
|
+
color={align === '-end' ? 'selected' : 'secondary'}
|
104
107
|
label="end"
|
105
108
|
onClick={() => setAlign('-end')}
|
106
109
|
/>
|
@@ -77,7 +77,12 @@ See [API](#api) for all available options.
|
|
77
77
|
- Use **clear, calm error messages** when there's a problem with what they
|
78
78
|
entered.
|
79
79
|
|
80
|
-
|
80
|
+
- In the background, Radio uses the [`fieldset`][fieldset] element. Not only it
|
81
|
+
improves the [accessibility] of the group, it also allows you to make use of
|
82
|
+
its built-in features like disabling all nested inputs or pairing the group
|
83
|
+
with a form outside. Consult [the MDN docs][fieldset] to learn more.
|
84
|
+
|
85
|
+
📖 [Read more about checkboxes and radios at Nielsen Norman Group.][nng-radio]
|
81
86
|
|
82
87
|
## Invisible Label
|
83
88
|
|
@@ -308,5 +313,8 @@ options. On top of that, the following options are available for Radio.
|
|
308
313
|
| `--rui-FormField--check__input--radio__border-radius` | Input corner radius |
|
309
314
|
| `--rui-FormField--check__input--radio--checked__background-image` | Checked input background image (inline, URL, …) |
|
310
315
|
|
316
|
+
[nng-radio]: https://www.nngroup.com/articles/checkboxes-vs-radio-buttons/
|
317
|
+
[fieldset]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset
|
318
|
+
[accessibility]: https://www.w3.org/WAI/tutorials/forms/grouping/
|
311
319
|
[React synthetic events]: https://reactjs.org/docs/events.html
|
312
320
|
[radio]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/radio#additional_attributes
|
@@ -25,7 +25,8 @@ export const Radio = ({
|
|
25
25
|
const context = useContext(FormLayoutContext);
|
26
26
|
|
27
27
|
return (
|
28
|
-
<
|
28
|
+
<fieldset
|
29
|
+
{...transferProps(restProps)}
|
29
30
|
className={classNames(
|
30
31
|
styles.root,
|
31
32
|
context && styles.isRootInFormLayout,
|
@@ -36,53 +37,59 @@ export const Radio = ({
|
|
36
37
|
required && styles.isRootRequired,
|
37
38
|
getRootValidationStateClassName(validationState, styles),
|
38
39
|
)}
|
40
|
+
disabled={disabled}
|
39
41
|
id={id}
|
40
42
|
>
|
43
|
+
<legend
|
44
|
+
className={styles.legend}
|
45
|
+
id={id && `${id}__label`}
|
46
|
+
>
|
47
|
+
{label}
|
48
|
+
</legend>
|
41
49
|
<div
|
50
|
+
aria-hidden
|
42
51
|
className={classNames(
|
43
52
|
styles.label,
|
44
53
|
!isLabelVisible && styles.isLabelHidden,
|
45
54
|
)}
|
46
|
-
id={id && `${id}
|
55
|
+
id={id && `${id}__displayLabel`}
|
47
56
|
>
|
48
57
|
{label}
|
49
58
|
</div>
|
50
59
|
<div className={styles.field}>
|
51
|
-
<
|
60
|
+
<div className={styles.options}>
|
52
61
|
{
|
53
62
|
options.map((option) => {
|
54
63
|
const key = option.key ?? option.value;
|
55
64
|
return (
|
56
|
-
<
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
65
|
+
<label
|
66
|
+
className={styles.option}
|
67
|
+
htmlFor={id && `${id}__item__${key}`}
|
68
|
+
id={id && `${id}__item__${key}__label`}
|
69
|
+
key={key}
|
70
|
+
>
|
71
|
+
<input
|
72
|
+
className={styles.input}
|
73
|
+
checked={restProps.onChange
|
74
|
+
? (value === option.value) || false
|
75
|
+
: undefined}
|
76
|
+
disabled={disabled || option.disabled}
|
77
|
+
id={id && `${id}__item__${key}`}
|
78
|
+
name={id}
|
79
|
+
type="radio"
|
80
|
+
value={option.value}
|
81
|
+
/>
|
82
|
+
<span
|
83
|
+
className={styles.optionLabel}
|
84
|
+
id={id && `${id}__item__${key}__labelText`}
|
61
85
|
>
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
checked={restProps.onChange
|
66
|
-
? (value === option.value) || false
|
67
|
-
: undefined}
|
68
|
-
disabled={disabled || option.disabled}
|
69
|
-
id={id && `${id}__item__${key}`}
|
70
|
-
name={id}
|
71
|
-
type="radio"
|
72
|
-
value={option.value}
|
73
|
-
/>
|
74
|
-
<span
|
75
|
-
className={styles.optionLabel}
|
76
|
-
id={id && `${id}__item__${key}__labelText`}
|
77
|
-
>
|
78
|
-
{ option.label }
|
79
|
-
</span>
|
80
|
-
</label>
|
81
|
-
</li>
|
86
|
+
{ option.label }
|
87
|
+
</span>
|
88
|
+
</label>
|
82
89
|
);
|
83
90
|
})
|
84
91
|
}
|
85
|
-
</
|
92
|
+
</div>
|
86
93
|
{helpText && (
|
87
94
|
<div
|
88
95
|
className={styles.helpText}
|
@@ -100,7 +107,7 @@ export const Radio = ({
|
|
100
107
|
</div>
|
101
108
|
)}
|
102
109
|
</div>
|
103
|
-
</
|
110
|
+
</fieldset>
|
104
111
|
);
|
105
112
|
};
|
106
113
|
|
@@ -129,7 +136,8 @@ Radio.propTypes = {
|
|
129
136
|
* ID of the root HTML element.
|
130
137
|
*
|
131
138
|
* Also serves as base for ids of nested elements:
|
132
|
-
* * `<ID>
|
139
|
+
* * `<ID>__label`
|
140
|
+
* * `<ID>__displayLabel`
|
133
141
|
* * `<ID>__helpText`
|
134
142
|
* * `<ID>__validationText`
|
135
143
|
*
|
@@ -1,3 +1,6 @@
|
|
1
|
+
// 1. Legends are tricky to style, let's use a `div` instead.
|
2
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset#styling_with_css
|
3
|
+
|
1
4
|
@use "../../styles/tools/form-fields/box-field-elements";
|
2
5
|
@use "../../styles/tools/form-fields/box-field-layout";
|
3
6
|
@use "../../styles/tools/form-fields/foundation";
|
@@ -11,15 +14,22 @@
|
|
11
14
|
// Foundation
|
12
15
|
.root {
|
13
16
|
@include foundation.root();
|
17
|
+
@include foundation.fieldset();
|
14
18
|
@include variants.visual(check);
|
15
19
|
}
|
16
20
|
|
21
|
+
// 1.
|
22
|
+
.legend {
|
23
|
+
@include accessibility.hide-text();
|
24
|
+
}
|
25
|
+
|
26
|
+
// 1.
|
17
27
|
.label,
|
18
28
|
.optionLabel {
|
19
29
|
@include foundation.label();
|
20
30
|
}
|
21
31
|
|
22
|
-
.
|
32
|
+
.options {
|
23
33
|
@include reset.list();
|
24
34
|
}
|
25
35
|
|
@@ -297,8 +297,8 @@ by smaller or bigger portions.
|
|
297
297
|
arrows
|
298
298
|
arrowsScrollStep={300}
|
299
299
|
direction="horizontal"
|
300
|
-
nextArrowElement={(<span class="
|
301
|
-
prevArrowElement={(<span class="
|
300
|
+
nextArrowElement={(<span class="font-size-3">➡️</span>)}
|
301
|
+
prevArrowElement={(<span class="font-size-3">⬅️</span>)}
|
302
302
|
scrollbar={false}
|
303
303
|
>
|
304
304
|
<Placeholder>
|
@@ -7,6 +7,7 @@ import { getRootValidationStateClassName } from '../_helpers/getRootValidationSt
|
|
7
7
|
import { resolveContextOrProp } from '../_helpers/resolveContextOrProp';
|
8
8
|
import { transferProps } from '../_helpers/transferProps';
|
9
9
|
import { FormLayoutContext } from '../FormLayout';
|
10
|
+
import { InputGroupContext } from '../InputGroup/InputGroupContext';
|
10
11
|
import { Option } from './_components/Option';
|
11
12
|
import styles from './SelectField.scss';
|
12
13
|
|
@@ -28,20 +29,25 @@ export const SelectField = React.forwardRef((props, ref) => {
|
|
28
29
|
...restProps
|
29
30
|
} = props;
|
30
31
|
|
31
|
-
const
|
32
|
+
const formLayoutContext = useContext(FormLayoutContext);
|
33
|
+
const inputGroupContext = useContext(InputGroupContext);
|
32
34
|
|
33
35
|
return (
|
34
36
|
<label
|
35
37
|
className={classNames(
|
36
38
|
styles.root,
|
37
39
|
fullWidth && styles.isRootFullWidth,
|
38
|
-
|
39
|
-
resolveContextOrProp(
|
40
|
+
formLayoutContext && styles.isRootInFormLayout,
|
41
|
+
resolveContextOrProp(inputGroupContext && inputGroupContext.disabled, disabled) && styles.isRootDisabled,
|
42
|
+
resolveContextOrProp(formLayoutContext && formLayoutContext.layout, layout) === 'horizontal'
|
40
43
|
? styles.isRootLayoutHorizontal
|
41
44
|
: styles.isRootLayoutVertical,
|
42
|
-
|
45
|
+
inputGroupContext && styles.isRootGrouped,
|
43
46
|
required && styles.isRootRequired,
|
44
|
-
getRootSizeClassName(
|
47
|
+
getRootSizeClassName(
|
48
|
+
resolveContextOrProp(inputGroupContext && inputGroupContext.size, size),
|
49
|
+
styles,
|
50
|
+
),
|
45
51
|
getRootValidationStateClassName(validationState, styles),
|
46
52
|
variant === 'filled' ? styles.isRootVariantFilled : styles.isRootVariantOutline,
|
47
53
|
)}
|
@@ -51,7 +57,7 @@ export const SelectField = React.forwardRef((props, ref) => {
|
|
51
57
|
<div
|
52
58
|
className={classNames(
|
53
59
|
styles.label,
|
54
|
-
!isLabelVisible && styles.isLabelHidden,
|
60
|
+
(!isLabelVisible || inputGroupContext) && styles.isLabelHidden,
|
55
61
|
)}
|
56
62
|
id={id && `${id}__labelText`}
|
57
63
|
>
|
@@ -62,7 +68,7 @@ export const SelectField = React.forwardRef((props, ref) => {
|
|
62
68
|
<select
|
63
69
|
{...transferProps(restProps)}
|
64
70
|
className={styles.input}
|
65
|
-
disabled={disabled}
|
71
|
+
disabled={resolveContextOrProp(inputGroupContext && inputGroupContext.disabled, disabled)}
|
66
72
|
id={id}
|
67
73
|
ref={ref}
|
68
74
|
required={required}
|
@@ -110,7 +116,7 @@ export const SelectField = React.forwardRef((props, ref) => {
|
|
110
116
|
{helpText}
|
111
117
|
</div>
|
112
118
|
)}
|
113
|
-
{validationText && (
|
119
|
+
{(validationText && !inputGroupContext) && (
|
114
120
|
<div
|
115
121
|
className={styles.validationText}
|
116
122
|
id={id && `${id}__validationText`}
|
@@ -169,6 +175,8 @@ SelectField.propTypes = {
|
|
169
175
|
/**
|
170
176
|
* If `false`, the label will be visually hidden (but remains accessible by assistive
|
171
177
|
* technologies).
|
178
|
+
*
|
179
|
+
* Automatically set to `false` when the component is rendered within `InputGroup` component.
|
172
180
|
*/
|
173
181
|
isLabelVisible: PropTypes.bool,
|
174
182
|
/**
|
@@ -224,6 +232,8 @@ SelectField.propTypes = {
|
|
224
232
|
required: PropTypes.bool,
|
225
233
|
/**
|
226
234
|
* Size of the field.
|
235
|
+
*
|
236
|
+
* Ignored if the component is rendered within `InputGroup` component as the value is inherited in such case.
|
227
237
|
*/
|
228
238
|
size: PropTypes.oneOf(['small', 'medium', 'large']),
|
229
239
|
/**
|
@@ -232,6 +242,9 @@ SelectField.propTypes = {
|
|
232
242
|
validationState: PropTypes.oneOf(['invalid', 'valid', 'warning']),
|
233
243
|
/**
|
234
244
|
* Validation message to be displayed.
|
245
|
+
*
|
246
|
+
* Validation text is never rendered when the component is placed into `InputGroup`. Instead, the `InputGroup`
|
247
|
+
* component itself renders all validation texts of its nested components.
|
235
248
|
*/
|
236
249
|
validationText: PropTypes.node,
|
237
250
|
/**
|
@@ -14,12 +14,13 @@
|
|
14
14
|
border-bottom-width: 2px;
|
15
15
|
}
|
16
16
|
|
17
|
+
.tableHeadCellLayout {
|
18
|
+
display: flex;
|
19
|
+
gap: settings.$cell-padding-x;
|
20
|
+
align-items: center;
|
21
|
+
}
|
22
|
+
|
17
23
|
.isTableCellSortingActive,
|
18
24
|
.isTableHeadCellSortingActive {
|
19
25
|
background-color: settings.$sorted-background-color;
|
20
26
|
}
|
21
|
-
|
22
|
-
.sortButton {
|
23
|
-
display: inline-block;
|
24
|
-
margin-right: settings.$cell-padding-x;
|
25
|
-
}
|
@@ -16,23 +16,26 @@ export const TableHeaderCell = ({
|
|
16
16
|
className={isSortingActive ? styles.isTableHeadCellSortingActive : styles.tableHeadCell}
|
17
17
|
id={id}
|
18
18
|
>
|
19
|
-
{
|
20
|
-
|
19
|
+
<span className={styles.tableHeadCellLayout}>
|
20
|
+
{sort && column.isSortable && (
|
21
21
|
<Button
|
22
|
+
aria-pressed={isSortingActive}
|
22
23
|
beforeLabel={
|
23
24
|
sortDirection === 'asc'
|
24
25
|
? sort.ascendingIcon
|
25
26
|
: sort.descendingIcon
|
26
27
|
}
|
28
|
+
color={isSortingActive ? 'selected' : 'secondary'}
|
27
29
|
id={id && `${id}__sortButton`}
|
28
30
|
label={sortDirection}
|
29
31
|
labelVisibility="none"
|
30
32
|
onClick={() => sort.onClick(column.name, sortDirection)}
|
31
33
|
priority="flat"
|
34
|
+
size="small"
|
32
35
|
/>
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
+
)}
|
37
|
+
{column.label}
|
38
|
+
</span>
|
36
39
|
</th>
|
37
40
|
);
|
38
41
|
};
|
@@ -1,15 +1,14 @@
|
|
1
1
|
@use "sass:map";
|
2
2
|
@use "../../styles/theme/borders";
|
3
|
-
@use "../../styles/theme/colors";
|
4
3
|
@use "../../styles/theme/typography";
|
5
4
|
@use "../../styles/tools/spacing";
|
6
5
|
|
7
6
|
$cell-padding-x: spacing.of(3);
|
8
7
|
$cell-padding-y: spacing.of(1);
|
9
8
|
$border-width: borders.$width;
|
10
|
-
$border-color:
|
11
|
-
$background-color:
|
12
|
-
$head-background-color:
|
9
|
+
$border-color: var(--rui-color-border-secondary);
|
10
|
+
$background-color: var(--rui-color-background-basic);
|
11
|
+
$head-background-color: var(--rui-color-background-basic);
|
13
12
|
$head-font-weight: map.get(typography.$font-weight-values, bold);
|
14
|
-
$hover-background-color:
|
15
|
-
$sorted-background-color:
|
13
|
+
$hover-background-color: var(--rui-color-background-interactive-hover);
|
14
|
+
$sorted-background-color: var(--rui-color-background-selected);
|
@@ -156,19 +156,22 @@ will override automatic break point selection in `auto` mode when present.
|
|
156
156
|
<span id="word-wrapping-options-label">Word wrapping:</span>
|
157
157
|
</ToolbarItem>
|
158
158
|
<ToolbarItem>
|
159
|
-
<ButtonGroup aria-labelledby="word-wrapping-options-label">
|
159
|
+
<ButtonGroup aria-labelledby="word-wrapping-options-label" priority="outline">
|
160
160
|
<Button
|
161
|
-
|
161
|
+
aria-pressed={wordWrapping === 'normal'}
|
162
|
+
color={wordWrapping === 'normal' ? 'selected' : 'secondary'}
|
162
163
|
label="normal"
|
163
164
|
onClick={() => setWordWrapping('normal')}
|
164
165
|
/>
|
165
166
|
<Button
|
166
|
-
|
167
|
+
aria-pressed={wordWrapping === 'long-words'}
|
168
|
+
color={wordWrapping === 'long-words' ? 'selected' : 'secondary'}
|
167
169
|
label="long-words"
|
168
170
|
onClick={() => setWordWrapping('long-words')}
|
169
171
|
/>
|
170
172
|
<Button
|
171
|
-
|
173
|
+
aria-pressed={wordWrapping === 'anywhere'}
|
174
|
+
color={wordWrapping === 'anywhere' ? 'selected' : 'secondary'}
|
172
175
|
label="anywhere"
|
173
176
|
onClick={() => setWordWrapping('anywhere')}
|
174
177
|
/>
|
@@ -180,19 +183,22 @@ will override automatic break point selection in `auto` mode when present.
|
|
180
183
|
<span id="hyphens-options-label">Hyphens:</span>
|
181
184
|
</ToolbarItem>
|
182
185
|
<ToolbarItem>
|
183
|
-
<ButtonGroup aria-labelledby="hyphens-options-label">
|
186
|
+
<ButtonGroup aria-labelledby="hyphens-options-label" priority="outline">
|
184
187
|
<Button
|
185
|
-
|
188
|
+
aria-pressed={hyphens === 'none'}
|
189
|
+
color={hyphens === 'none' ? 'selected' : 'secondary'}
|
186
190
|
label="none"
|
187
191
|
onClick={() => setHyphens('none')}
|
188
192
|
/>
|
189
193
|
<Button
|
190
|
-
|
194
|
+
aria-pressed={hyphens === 'auto'}
|
195
|
+
color={hyphens === 'auto' ? 'selected' : 'secondary'}
|
191
196
|
label="auto"
|
192
197
|
onClick={() => setHyphens('auto')}
|
193
198
|
/>
|
194
199
|
<Button
|
195
|
-
|
200
|
+
aria-pressed={hyphens === 'manual'}
|
201
|
+
color={hyphens === 'manual' ? 'selected' : 'secondary'}
|
196
202
|
label="manual"
|
197
203
|
onClick={() => setHyphens('manual')}
|
198
204
|
/>
|