@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.
Files changed (82) hide show
  1. package/dist/lib.development.js +157 -49
  2. package/dist/lib.js +1 -1
  3. package/package.json +1 -1
  4. package/src/lib/components/Alert/Alert.jsx +1 -3
  5. package/src/lib/components/Alert/Alert.scss +1 -9
  6. package/src/lib/components/Alert/README.mdx +0 -20
  7. package/src/lib/components/Alert/_settings.scss +1 -1
  8. package/src/lib/components/Alert/_theme.scss +0 -10
  9. package/src/lib/components/Badge/Badge.jsx +1 -3
  10. package/src/lib/components/Badge/Badge.scss +25 -44
  11. package/src/lib/components/Badge/README.mdx +6 -14
  12. package/src/lib/components/Button/Button.jsx +20 -10
  13. package/src/lib/components/Button/README.mdx +8 -3
  14. package/src/lib/components/Button/_base.scss +21 -12
  15. package/src/lib/components/Button/_priorities.scss +13 -18
  16. package/src/lib/components/Button/_settings.scss +1 -1
  17. package/src/lib/components/Button/_theme.scss +0 -10
  18. package/src/lib/components/ButtonGroup/ButtonGroup.jsx +5 -3
  19. package/src/lib/components/ButtonGroup/ButtonGroup.scss +26 -1
  20. package/src/lib/components/ButtonGroup/README.mdx +85 -59
  21. package/src/lib/components/ButtonGroup/_theme.scss +13 -0
  22. package/src/lib/components/Card/Card.jsx +1 -3
  23. package/src/lib/components/Card/Card.scss +0 -9
  24. package/src/lib/components/Card/README.mdx +0 -16
  25. package/src/lib/components/Card/_theme.scss +0 -10
  26. package/src/lib/components/FormLayout/README.mdx +22 -8
  27. package/src/lib/components/Grid/_helpers/generateResponsiveCustomProperties.js +1 -1
  28. package/src/lib/components/InputGroup/InputGroup.jsx +170 -0
  29. package/src/lib/components/InputGroup/InputGroup.scss +92 -0
  30. package/src/lib/components/InputGroup/InputGroupContext.js +3 -0
  31. package/src/lib/components/InputGroup/README.mdx +278 -0
  32. package/src/lib/components/InputGroup/_theme.scss +2 -0
  33. package/src/lib/components/InputGroup/index.js +2 -0
  34. package/src/lib/components/Modal/Modal.jsx +58 -97
  35. package/src/lib/components/Modal/ModalCloseButton.scss +2 -2
  36. package/src/lib/components/Modal/README.mdx +392 -128
  37. package/src/lib/components/Modal/_helpers/getPositionClassName.js +7 -0
  38. package/src/lib/components/Modal/_helpers/getSizeClassName.js +19 -0
  39. package/src/lib/components/Modal/_hooks/useModalFocus.js +126 -0
  40. package/src/lib/components/Modal/_hooks/useModalScrollPrevention.js +35 -0
  41. package/src/lib/components/Modal/_settings.scss +2 -2
  42. package/src/lib/components/Popover/README.mdx +7 -4
  43. package/src/lib/components/Radio/README.mdx +9 -1
  44. package/src/lib/components/Radio/Radio.jsx +39 -31
  45. package/src/lib/components/Radio/Radio.scss +11 -1
  46. package/src/lib/components/ScrollView/README.mdx +2 -2
  47. package/src/lib/components/SelectField/SelectField.jsx +21 -8
  48. package/src/lib/components/SelectField/SelectField.scss +5 -0
  49. package/src/lib/components/Table/_components/TableCell.scss +6 -5
  50. package/src/lib/components/Table/_components/TableHeaderCell/TableHeaderCell.jsx +8 -5
  51. package/src/lib/components/Table/_settings.scss +5 -6
  52. package/src/lib/components/Text/README.mdx +14 -8
  53. package/src/lib/components/TextField/TextField.jsx +21 -8
  54. package/src/lib/components/TextField/TextField.scss +5 -0
  55. package/src/lib/components/TextLink/README.mdx +8 -6
  56. package/src/lib/components/TextLink/TextLink.scss +5 -0
  57. package/src/lib/components/TextLink/_theme.scss +2 -0
  58. package/src/lib/components/Toolbar/README.mdx +19 -11
  59. package/src/lib/components/_helpers/getRootColorClassName.js +4 -0
  60. package/src/lib/index.js +1 -0
  61. package/src/lib/styles/elements/_code.scss +1 -3
  62. package/src/lib/styles/elements/_page.scss +1 -0
  63. package/src/lib/styles/elements/_rulers.scss +1 -3
  64. package/src/lib/styles/elements/_small.scss +1 -1
  65. package/src/lib/styles/settings/_form-fields.scss +1 -1
  66. package/src/lib/styles/settings/_utilities.scss +46 -14
  67. package/src/lib/styles/theme/_accessibility.scss +4 -4
  68. package/src/lib/styles/theme/_borders.scss +3 -2
  69. package/src/lib/styles/theme/_code.scss +2 -2
  70. package/src/lib/styles/theme/_links.scss +6 -4
  71. package/src/lib/styles/theme/_lists.scss +1 -1
  72. package/src/lib/styles/theme/_page.scss +2 -2
  73. package/src/lib/styles/theme/_spacing.scss +11 -11
  74. package/src/lib/styles/theme/_typography.scss +19 -18
  75. package/src/lib/styles/theme-constants/_colors.scss +23 -23
  76. package/src/lib/styles/tools/_spacing.scss +1 -1
  77. package/src/lib/styles/tools/form-fields/_box-field-elements.scss +19 -2
  78. package/src/lib/styles/tools/form-fields/_box-field-sizes.scss +11 -8
  79. package/src/lib/styles/tools/form-fields/_foundation.scss +7 -0
  80. package/src/lib/theme.scss +650 -567
  81. package/src/lib/styles/theme/_colors.scss +0 -65
  82. /package/src/lib/components/{Button/helpers → _helpers}/getRootPriorityClassName.js +0 -0
@@ -0,0 +1,7 @@
1
+ export const getPositionClassName = (modalPosition, styles) => {
2
+ if (modalPosition === 'top') {
3
+ return styles.isRootPositionTop;
4
+ }
5
+
6
+ return styles.isRootPositionCenter;
7
+ };
@@ -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, 1);
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
- color={align === '-start' ? 'dark' : 'primary'}
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
- color={align === '' ? 'dark' : 'primary'}
99
+ aria-pressed={align === ''}
100
+ color={align === '' ? 'selected' : 'secondary'}
99
101
  label="center"
100
102
  onClick={() => setAlign('')}
101
103
  />
102
104
  <Button
103
- color={align === '-end' ? 'dark' : 'primary'}
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
- 📖 [Read more about checkboxes and radios at Nielsen Norman Group.](https://www.nngroup.com/articles/checkboxes-vs-radio-buttons/)
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
- <div
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}__labelText`}
55
+ id={id && `${id}__displayLabel`}
47
56
  >
48
57
  {label}
49
58
  </div>
50
59
  <div className={styles.field}>
51
- <ul className={styles.list}>
60
+ <div className={styles.options}>
52
61
  {
53
62
  options.map((option) => {
54
63
  const key = option.key ?? option.value;
55
64
  return (
56
- <li key={key}>
57
- <label
58
- className={styles.option}
59
- htmlFor={id && `${id}__item__${key}`}
60
- id={id && `${id}__item__${key}__label`}
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
- <input
63
- {...transferProps(restProps)}
64
- className={styles.input}
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
- </ul>
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
- </div>
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>__labelText`
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
- .list {
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="typography-size-3">➡️</span>)}
301
- prevArrowElement={(<span class="typography-size-3">⬅️</span>)}
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 context = useContext(FormLayoutContext);
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
- context && styles.isRootInFormLayout,
39
- resolveContextOrProp(context && context.layout, layout) === 'horizontal'
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
- disabled && styles.isRootDisabled,
45
+ inputGroupContext && styles.isRootGrouped,
43
46
  required && styles.isRootRequired,
44
- getRootSizeClassName(size, styles),
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
  /**
@@ -102,3 +102,8 @@
102
102
  .isRootSizeLarge {
103
103
  @include box-field-sizes.size(large);
104
104
  }
105
+
106
+ // Groups
107
+ .isRootGrouped {
108
+ @include box-field-elements.in-group-layout();
109
+ }
@@ -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
- {sort && column.isSortable && (
20
- <div className={styles.sortButton}>
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
- </div>
34
- )}
35
- {column.label}
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: map.get(colors.$grays, gray-100);
11
- $background-color: colors.$white;
12
- $head-background-color: colors.$white;
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: map.get(colors.$grays, gray-50);
15
- $sorted-background-color: map.get(colors.$grays, gray-50);
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
- color={wordWrapping === 'normal' ? 'dark' : 'primary'}
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
- color={wordWrapping === 'long-words' ? 'dark' : 'primary'}
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
- color={wordWrapping === 'anywhere' ? 'dark' : 'primary'}
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
- color={hyphens === 'none' ? 'dark' : 'primary'}
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
- color={hyphens === 'auto' ? 'dark' : 'primary'}
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
- color={hyphens === 'manual' ? 'dark' : 'primary'}
200
+ aria-pressed={hyphens === 'manual'}
201
+ color={hyphens === 'manual' ? 'selected' : 'secondary'}
196
202
  label="manual"
197
203
  onClick={() => setHyphens('manual')}
198
204
  />