@react-ui-org/react-ui 0.50.2 → 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 +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
|
/>
|