@react-ui-org/react-ui 0.48.0 → 0.50.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 (105) hide show
  1. package/dist/lib.development.js +162 -66
  2. package/dist/lib.js +1 -1
  3. package/package.json +1 -1
  4. package/src/lib/components/Alert/Alert.jsx +3 -0
  5. package/src/lib/components/Alert/Alert.scss +10 -10
  6. package/src/lib/components/Alert/README.mdx +14 -0
  7. package/src/lib/components/Badge/Badge.jsx +4 -8
  8. package/src/lib/components/Badge/Badge.scss +21 -21
  9. package/src/lib/components/Badge/README.mdx +14 -0
  10. package/src/lib/components/Button/Button.jsx +2 -13
  11. package/src/lib/components/Button/README.mdx +17 -5
  12. package/src/lib/components/Button/_base.scss +20 -20
  13. package/src/lib/components/Button/_priorities.scss +35 -35
  14. package/src/lib/components/Button/helpers/getRootLabelVisibilityClassName.js +7 -7
  15. package/src/lib/components/Button/helpers/getRootPriorityClassName.js +3 -3
  16. package/src/lib/components/ButtonGroup/ButtonGroup.jsx +0 -7
  17. package/src/lib/components/ButtonGroup/README.mdx +14 -0
  18. package/src/lib/components/Card/Card.jsx +6 -10
  19. package/src/lib/components/Card/Card.scss +13 -13
  20. package/src/lib/components/Card/CardBody.jsx +6 -10
  21. package/src/lib/components/Card/CardFooter.jsx +6 -7
  22. package/src/lib/components/Card/README.mdx +14 -0
  23. package/src/lib/components/CheckboxField/CheckboxField.jsx +1 -27
  24. package/src/lib/components/CheckboxField/README.mdx +17 -5
  25. package/src/lib/components/FileInputField/FileInputField.jsx +2 -12
  26. package/src/lib/components/FileInputField/FileInputField.scss +3 -7
  27. package/src/lib/components/FileInputField/README.mdx +29 -27
  28. package/src/lib/components/FormLayout/FormLayout.jsx +5 -9
  29. package/src/lib/components/FormLayout/FormLayout.scss +3 -3
  30. package/src/lib/components/FormLayout/FormLayoutCustomField.jsx +4 -1
  31. package/src/lib/components/FormLayout/FormLayoutCustomField.scss +8 -8
  32. package/src/lib/components/FormLayout/README.mdx +13 -0
  33. package/src/lib/components/Grid/Grid.jsx +0 -7
  34. package/src/lib/components/Grid/GridSpan.jsx +0 -7
  35. package/src/lib/components/Grid/README.mdx +14 -0
  36. package/src/lib/components/Modal/Modal.jsx +7 -11
  37. package/src/lib/components/Modal/ModalBody.jsx +3 -7
  38. package/src/lib/components/Modal/ModalCloseButton.jsx +0 -16
  39. package/src/lib/components/Modal/ModalContent.jsx +3 -7
  40. package/src/lib/components/Modal/ModalFooter.jsx +3 -7
  41. package/src/lib/components/Modal/ModalFooter.scss +5 -5
  42. package/src/lib/components/Modal/ModalHeader.jsx +3 -7
  43. package/src/lib/components/Modal/ModalHeader.scss +5 -5
  44. package/src/lib/components/Modal/ModalTitle.jsx +6 -7
  45. package/src/lib/components/Modal/README.mdx +32 -6
  46. package/src/lib/components/Modal/_helpers/getJustifyClassName.js +5 -5
  47. package/src/lib/components/Paper/Paper.jsx +5 -9
  48. package/src/lib/components/Paper/Paper.scss +2 -2
  49. package/src/lib/components/Paper/README.mdx +14 -0
  50. package/src/lib/components/Popover/Popover.jsx +0 -16
  51. package/src/lib/components/Popover/PopoverWrapper.jsx +0 -7
  52. package/src/lib/components/Popover/README.mdx +19 -0
  53. package/src/lib/components/Radio/README.mdx +12 -5
  54. package/src/lib/components/Radio/Radio.jsx +2 -2
  55. package/src/lib/components/Radio/Radio.scss +3 -3
  56. package/src/lib/components/ScrollView/README.mdx +19 -0
  57. package/src/lib/components/ScrollView/ScrollView.jsx +11 -4
  58. package/src/lib/components/SelectField/README.mdx +17 -5
  59. package/src/lib/components/SelectField/SelectField.jsx +3 -22
  60. package/src/lib/components/SelectField/SelectField.scss +8 -8
  61. package/src/lib/components/Table/README.mdx +21 -7
  62. package/src/lib/components/Table/Table.jsx +43 -101
  63. package/src/lib/components/Table/Table.scss +0 -24
  64. package/src/lib/components/Table/_components/TableBodyCell/TableBodyCell.jsx +46 -0
  65. package/src/lib/components/Table/_components/TableBodyCell/index.js +1 -0
  66. package/src/lib/components/Table/_components/TableCell.scss +25 -0
  67. package/src/lib/components/Table/_components/TableHeaderCell/TableHeaderCell.jsx +71 -0
  68. package/src/lib/components/Table/_components/TableHeaderCell/index.js +1 -0
  69. package/src/lib/components/Tabs/README.mdx +16 -0
  70. package/src/lib/components/Tabs/Tabs.jsx +6 -1
  71. package/src/lib/components/Tabs/TabsItem.jsx +3 -0
  72. package/src/lib/components/Text/README.mdx +16 -0
  73. package/src/lib/components/Text/Text.jsx +3 -7
  74. package/src/lib/components/Text/Text.scss +6 -6
  75. package/src/lib/components/Text/_helpers/getRootClampClassName.js +2 -2
  76. package/src/lib/components/Text/_helpers/getRootHyphensClassName.js +2 -2
  77. package/src/lib/components/Text/_helpers/getRootWordWrappingClassName.js +2 -2
  78. package/src/lib/components/TextArea/README.mdx +33 -30
  79. package/src/lib/components/TextArea/TextArea.jsx +3 -43
  80. package/src/lib/components/TextArea/TextArea.scss +8 -8
  81. package/src/lib/components/TextField/README.mdx +53 -51
  82. package/src/lib/components/TextField/TextField.jsx +3 -29
  83. package/src/lib/components/TextField/TextField.scss +9 -9
  84. package/src/lib/components/TextLink/README.mdx +12 -5
  85. package/src/lib/components/TextLink/TextLink.jsx +0 -10
  86. package/src/lib/components/Toggle/README.mdx +17 -5
  87. package/src/lib/components/Toggle/Toggle.jsx +1 -27
  88. package/src/lib/components/Toolbar/README.mdx +13 -0
  89. package/src/lib/components/Toolbar/Toolbar.jsx +9 -43
  90. package/src/lib/components/Toolbar/Toolbar.scss +24 -12
  91. package/src/lib/components/Toolbar/ToolbarGroup.jsx +7 -26
  92. package/src/lib/components/Toolbar/ToolbarItem.jsx +3 -7
  93. package/src/lib/components/Toolbar/_helpers/getAlignClassName.js +19 -0
  94. package/src/lib/components/Toolbar/_helpers/getJustifyClassName.js +16 -0
  95. package/src/lib/components/_helpers/getRootColorClassName.js +10 -10
  96. package/src/lib/components/_helpers/getRootSizeClassName.js +3 -3
  97. package/src/lib/styles/generic/_forms.scss +10 -6
  98. package/src/lib/styles/theme/_accessibility.scss +2 -0
  99. package/src/lib/styles/theme/_form-fields.scss +1 -0
  100. package/src/lib/styles/tools/_accessibility.scss +2 -0
  101. package/src/lib/styles/tools/form-fields/_box-field-layout.scss +15 -15
  102. package/src/lib/styles/tools/form-fields/_foundation.scss +2 -0
  103. package/src/lib/styles/tools/form-fields/_inline-field-elements.scss +1 -1
  104. package/src/lib/styles/tools/form-fields/_inline-field-layout.scss +9 -9
  105. package/src/lib/theme.scss +4 -1
@@ -24,14 +24,14 @@
24
24
  @include spacing.bottom(layouts);
25
25
  }
26
26
 
27
- .rootFieldLayoutVertical,
28
- .rootFieldLayoutHorizontal {
27
+ .isRootFieldLayoutVertical,
28
+ .isRootFieldLayoutHorizontal {
29
29
  display: grid;
30
30
  grid-template-columns: var(--rui-local-field-width);
31
31
  grid-row-gap: theme.$row-gap;
32
32
  }
33
33
 
34
- .rootFieldLayoutHorizontal {
34
+ .isRootFieldLayoutHorizontal {
35
35
  @include breakpoint.up(forms.$horizontal-breakpoint) {
36
36
  grid-template-columns: var(--rui-local-label-width) var(--rui-local-field-width); // 1.
37
37
  }
@@ -1,6 +1,7 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React, { useContext } from 'react';
3
3
  import { withGlobalProps } from '../../provider';
4
+ import { transferProps } from '../_helpers/transferProps';
4
5
  import { classNames } from '../../utils/classNames';
5
6
  import { getRootSizeClassName } from '../_helpers/getRootSizeClassName';
6
7
  import { getRootValidationStateClassName } from '../_helpers/getRootValidationStateClassName';
@@ -45,6 +46,7 @@ export const FormLayoutCustomField = ({
45
46
  labelForId,
46
47
  required,
47
48
  validationState,
49
+ ...restProps
48
50
  }) => {
49
51
  const context = useContext(FormLayoutContext);
50
52
 
@@ -54,11 +56,12 @@ export const FormLayoutCustomField = ({
54
56
 
55
57
  return (
56
58
  <div
59
+ {...transferProps(restProps)}
57
60
  id={id}
58
61
  className={classNames(
59
62
  styles.root,
60
63
  fullWidth && styles.isRootFullWidth,
61
- context && context.layout === 'horizontal' ? styles.rootLayoutHorizontal : styles.rootLayoutVertical,
64
+ context && context.layout === 'horizontal' ? styles.isRootLayoutHorizontal : styles.isRootLayoutVertical,
62
65
  disabled && styles.isRootDisabled,
63
66
  required && styles.isRootRequired,
64
67
  getRootSizeClassName(innerFieldSize, styles),
@@ -31,17 +31,17 @@
31
31
  }
32
32
 
33
33
  // Layouts
34
- .rootLayoutVertical,
35
- .rootLayoutHorizontal {
34
+ .isRootLayoutVertical,
35
+ .isRootLayoutHorizontal {
36
36
  @include box-field-layout.vertical();
37
37
  }
38
38
 
39
- .rootLayoutHorizontal {
39
+ .isRootLayoutHorizontal {
40
40
  @include box-field-layout.horizontal();
41
41
  }
42
42
 
43
- .rootLayoutVertical .field,
44
- .rootLayoutHorizontal .field {
43
+ .isRootLayoutVertical .field,
44
+ .isRootLayoutHorizontal .field {
45
45
  width: auto;
46
46
  }
47
47
 
@@ -50,14 +50,14 @@
50
50
  }
51
51
 
52
52
  // Sizes
53
- .rootSizeSmall {
53
+ .isRootSizeSmall {
54
54
  @include box-field-sizes.size(small);
55
55
  }
56
56
 
57
- .rootSizeMedium {
57
+ .isRootSizeMedium {
58
58
  @include box-field-sizes.size(medium);
59
59
  }
60
60
 
61
- .rootSizeLarge {
61
+ .isRootSizeLarge {
62
62
  @include box-field-sizes.size(large);
63
63
  }
@@ -438,6 +438,17 @@ This is a demo of all components supported by FormLayout.
438
438
  }}
439
439
  </Playground>
440
440
 
441
+ ## Forwarding HTML Attributes
442
+
443
+ In addition to the options below in the [component's API](#api) section, you
444
+ can specify [React synthetic events] or **any HTML attribute you like.** All
445
+ attributes that don't interfere with the API are forwarded to the root `<div>`
446
+ HTML element. This enables making the component interactive and helps to improve
447
+ its accessibility.
448
+
449
+ 👉 Refer to the MDN reference for the full list of supported attributes of the
450
+ [div] element.
451
+
441
452
  ## API
442
453
 
443
454
  <Props table of={FormLayout} />
@@ -472,3 +483,5 @@ FormLayoutCustomField can be styled using a small subset of
472
483
  [fragments]: https://reactjs.org/docs/fragments.html
473
484
  [rui-232]: https://github.com/react-ui-org/react-ui/issues/232
474
485
  [rui-265]: https://github.com/react-ui-org/react-ui/issues/265
486
+ [React synthetic events]: https://reactjs.org/docs/events.html
487
+ [div]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div#attributes
@@ -15,7 +15,6 @@ export const Grid = ({
15
15
  children,
16
16
  columnGap,
17
17
  columns,
18
- id,
19
18
  justifyContent,
20
19
  justifyItems,
21
20
  rowGap,
@@ -30,7 +29,6 @@ export const Grid = ({
30
29
  return (
31
30
  <Tag
32
31
  {...transferProps(restProps)}
33
- id={id}
34
32
  className={styles.root}
35
33
  style={{
36
34
  ...generateResponsiveCustomProperties(columns, 'columns'),
@@ -59,7 +57,6 @@ Grid.defaultProps = {
59
57
  children: null,
60
58
  columnGap: 4,
61
59
  columns: '1fr',
62
- id: undefined,
63
60
  justifyContent: undefined,
64
61
  justifyItems: undefined,
65
62
  rowGap: 4,
@@ -152,10 +149,6 @@ Grid.propTypes = {
152
149
  x3l: PropTypes.string,
153
150
  }),
154
151
  ]),
155
- /**
156
- * ID of the root HTML element.
157
- */
158
- id: PropTypes.string,
159
152
  /**
160
153
  * Content justification. Accepts any valid value of `justify-content` CSS property.
161
154
  * See [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content) for more.
@@ -9,7 +9,6 @@ import styles from './Grid.scss';
9
9
  export const GridSpan = ({
10
10
  children,
11
11
  columns,
12
- id,
13
12
  rows,
14
13
  tag: Tag,
15
14
  ...restProps
@@ -21,7 +20,6 @@ export const GridSpan = ({
21
20
  return (
22
21
  <Tag
23
22
  {...transferProps(restProps)}
24
- id={id}
25
23
  className={styles.span}
26
24
  style={{
27
25
  ...generateResponsiveCustomProperties(columns, 'column-span'),
@@ -39,7 +37,6 @@ export const GridSpan = ({
39
37
  GridSpan.defaultProps = {
40
38
  children: null,
41
39
  columns: 1,
42
- id: undefined,
43
40
  rows: 1,
44
41
  tag: 'div',
45
42
  };
@@ -64,10 +61,6 @@ GridSpan.propTypes = {
64
61
  x3l: PropTypes.number,
65
62
  }),
66
63
  ]),
67
- /**
68
- * ID of the root HTML element.
69
- */
70
- id: PropTypes.string,
71
64
  /**
72
65
  * Number of rows to span.
73
66
  */
@@ -263,6 +263,17 @@ with responsive columns and rows.
263
263
  👉 `autoFlow` (used in the example above) implements the `grid-auto-flow` CSS
264
264
  property. Check [MDN][grid-auto-flow] to fully understand available options.
265
265
 
266
+ ## Forwarding HTML Attributes
267
+
268
+ In addition to the options below in the [component's API](#api) section, you
269
+ can specify [React synthetic events] or **any HTML attribute you like.** All
270
+ attributes that don't interfere with the API are forwarded to the HTML element
271
+ of your choice provided by `tag`, which is `<div>` by default. It enables making
272
+ the component interactive and helps to improve its accessibility.
273
+
274
+ 👉 Refer to the MDN reference for the full list of supported attributes of the
275
+ [div] element or [any other][all-html-elements] element of your choice.
276
+
266
277
  ## API
267
278
 
268
279
  <Props table of={Grid} />
@@ -283,3 +294,6 @@ Wrapper for content that should span multiple rows or columns.
283
294
  [justify-items]: https://developer.mozilla.org/en-US/docs/Web/CSS/justify-items
284
295
  [repeat]: https://developer.mozilla.org/en-US/docs/Web/CSS/repeat
285
296
  [minmax]: https://developer.mozilla.org/en-US/docs/Web/CSS/minmax
297
+ [React synthetic events]: https://reactjs.org/docs/events.html
298
+ [div]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div#attributes
299
+ [all-html-elements]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element
@@ -5,15 +5,16 @@ import React, {
5
5
  } from 'react';
6
6
  import { createPortal } from 'react-dom';
7
7
  import { withGlobalProps } from '../../provider';
8
+ import { transferProps } from '../_helpers/transferProps';
8
9
  import { classNames } from '../../utils/classNames';
9
10
  import styles from './Modal.scss';
10
11
 
11
12
  const preRender = (
12
13
  children,
13
14
  childrenWrapperRef,
14
- id,
15
15
  closeButtonRef,
16
16
  position,
17
+ restProps,
17
18
  size,
18
19
  ) => {
19
20
  const sizeClass = (modalSize) => {
@@ -47,7 +48,6 @@ const preRender = (
47
48
  return (
48
49
  <div
49
50
  className={styles.backdrop}
50
- id={id}
51
51
  onClick={() => {
52
52
  if (closeButtonRef?.current != null) {
53
53
  closeButtonRef.current.click();
@@ -56,6 +56,7 @@ const preRender = (
56
56
  role="presentation"
57
57
  >
58
58
  <div
59
+ {...transferProps(restProps)}
59
60
  className={classNames(
60
61
  styles.root,
61
62
  sizeClass(size),
@@ -77,11 +78,11 @@ export const Modal = ({
77
78
  autoFocus,
78
79
  children,
79
80
  closeButtonRef,
80
- id,
81
81
  portalId,
82
82
  position,
83
83
  primaryButtonRef,
84
84
  size,
85
+ ...restProps
85
86
  }) => {
86
87
  const childrenWrapperRef = useRef();
87
88
 
@@ -109,7 +110,7 @@ export const Modal = ({
109
110
  const childrenWrapperElement = childrenWrapperRef.current;
110
111
  const childrenElements = childrenWrapperElement.querySelectorAll('*');
111
112
  const formFieldEl = Array.from(childrenElements).find(
112
- (element) => ['INPUT', 'TEXTAREA', 'SELECT'].includes(element.nodeName),
113
+ (element) => ['INPUT', 'TEXTAREA', 'SELECT'].includes(element.nodeName) && !element.disabled,
113
114
  );
114
115
 
115
116
  if (formFieldEl) {
@@ -130,9 +131,9 @@ export const Modal = ({
130
131
  return preRender(
131
132
  children,
132
133
  childrenWrapperRef,
133
- id,
134
134
  closeButtonRef,
135
135
  position,
136
+ restProps,
136
137
  size,
137
138
  );
138
139
  }
@@ -141,9 +142,9 @@ export const Modal = ({
141
142
  preRender(
142
143
  children,
143
144
  childrenWrapperRef,
144
- id,
145
145
  closeButtonRef,
146
146
  position,
147
+ restProps,
147
148
  size,
148
149
  ),
149
150
  document.getElementById(portalId),
@@ -154,7 +155,6 @@ Modal.defaultProps = {
154
155
  autoFocus: true,
155
156
  children: null,
156
157
  closeButtonRef: null,
157
- id: undefined,
158
158
  portalId: null,
159
159
  position: 'center',
160
160
  primaryButtonRef: null,
@@ -184,10 +184,6 @@ Modal.propTypes = {
184
184
  // eslint-disable-next-line react/forbid-prop-types
185
185
  current: PropTypes.any,
186
186
  }),
187
- /**
188
- * ID of the root HTML element.
189
- */
190
- id: PropTypes.string,
191
187
  /**
192
188
  * If set, modal is rendered in the React Portal with that ID.
193
189
  */
@@ -1,6 +1,7 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
3
  import { withGlobalProps } from '../../provider';
4
+ import { transferProps } from '../_helpers/transferProps';
4
5
  import { classNames } from '../../utils/classNames';
5
6
  import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
6
7
  import { getScrollingClassName } from './_helpers/getScrollingClassName';
@@ -8,8 +9,8 @@ import styles from './ModalBody.scss';
8
9
 
9
10
  export const ModalBody = ({
10
11
  children,
11
- id,
12
12
  scrolling,
13
+ ...restProps
13
14
  }) => {
14
15
  if (isChildrenEmpty(children)) {
15
16
  return null;
@@ -17,11 +18,11 @@ export const ModalBody = ({
17
18
 
18
19
  return (
19
20
  <div
21
+ {...transferProps(restProps)}
20
22
  className={classNames(
21
23
  styles.root,
22
24
  getScrollingClassName(scrolling, styles),
23
25
  )}
24
- id={id}
25
26
  >
26
27
  {children}
27
28
  </div>
@@ -30,7 +31,6 @@ export const ModalBody = ({
30
31
 
31
32
  ModalBody.defaultProps = {
32
33
  children: null,
33
- id: undefined,
34
34
  scrolling: 'auto',
35
35
  };
36
36
 
@@ -45,10 +45,6 @@ ModalBody.propTypes = {
45
45
  * At most one nested element is allowed. If none are provided nothing is rendered.
46
46
  */
47
47
  children: PropTypes.node,
48
- /**
49
- * ID of the root HTML element.
50
- */
51
- id: PropTypes.string,
52
48
  /**
53
49
  * Scrolling mode:
54
50
  *
@@ -10,7 +10,6 @@ import styles from './ModalCloseButton.scss';
10
10
  export const ModalCloseButton = React.forwardRef((props, ref) => {
11
11
  const {
12
12
  disabled,
13
- id,
14
13
  ...restProps
15
14
  } = props;
16
15
 
@@ -22,7 +21,6 @@ export const ModalCloseButton = React.forwardRef((props, ref) => {
22
21
  type="button"
23
22
  className={styles.root}
24
23
  disabled={disabled}
25
- id={id}
26
24
  ref={ref}
27
25
  title={translations.ModalCloseButton.close}
28
26
  >
@@ -33,8 +31,6 @@ export const ModalCloseButton = React.forwardRef((props, ref) => {
33
31
 
34
32
  ModalCloseButton.defaultProps = {
35
33
  disabled: false,
36
- id: undefined,
37
- ref: undefined,
38
34
  };
39
35
 
40
36
  ModalCloseButton.propTypes = {
@@ -42,18 +38,6 @@ ModalCloseButton.propTypes = {
42
38
  * If `true`, close button will be disabled.
43
39
  */
44
40
  disabled: PropTypes.bool,
45
- /**
46
- * ID of the root HTML element.
47
- */
48
- id: PropTypes.string,
49
- /**
50
- * Reference forwarded to the `button` element.
51
- */
52
- ref: PropTypes.oneOfType([
53
- PropTypes.func,
54
- // eslint-disable-next-line react/forbid-prop-types
55
- PropTypes.shape({ current: PropTypes.any }),
56
- ]),
57
41
  };
58
42
 
59
43
  export const ModalCloseButtonWithGlobalProps = withGlobalProps(ModalCloseButton, 'ModalCloseButton');
@@ -2,11 +2,12 @@ import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
3
  import { withGlobalProps } from '../../provider';
4
4
  import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
5
+ import { transferProps } from '../_helpers/transferProps';
5
6
  import styles from './ModalContent.scss';
6
7
 
7
8
  export const ModalContent = ({
8
9
  children,
9
- id,
10
+ ...restProps
10
11
  }) => {
11
12
  if (isChildrenEmpty(children)) {
12
13
  return null;
@@ -14,8 +15,8 @@ export const ModalContent = ({
14
15
 
15
16
  return (
16
17
  <div
18
+ {...transferProps(restProps)}
17
19
  className={styles.root}
18
- id={id}
19
20
  >
20
21
  {children}
21
22
  </div>
@@ -24,7 +25,6 @@ export const ModalContent = ({
24
25
 
25
26
  ModalContent.defaultProps = {
26
27
  children: null,
27
- id: undefined,
28
28
  };
29
29
 
30
30
  ModalContent.propTypes = {
@@ -32,10 +32,6 @@ ModalContent.propTypes = {
32
32
  * Content of the modal.
33
33
  */
34
34
  children: PropTypes.node,
35
- /**
36
- * ID of the root HTML element.
37
- */
38
- id: PropTypes.string,
39
35
  };
40
36
 
41
37
  export const ModalContentWithGlobalProps = withGlobalProps(ModalContent, 'ModalContent');
@@ -1,28 +1,28 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
3
  import { withGlobalProps } from '../../provider';
4
+ import { transferProps } from '../_helpers/transferProps';
4
5
  import { classNames } from '../../utils/classNames';
5
6
  import { getJustifyClassName } from './_helpers/getJustifyClassName';
6
7
  import styles from './ModalFooter.scss';
7
8
 
8
9
  export const ModalFooter = ({
9
10
  children,
10
- id,
11
11
  justify,
12
+ ...restProps
12
13
  }) => (
13
14
  <div
15
+ {...transferProps(restProps)}
14
16
  className={classNames(
15
17
  styles.root,
16
18
  getJustifyClassName(justify, styles),
17
19
  )}
18
- id={id}
19
20
  >
20
21
  {children}
21
22
  </div>
22
23
  );
23
24
 
24
25
  ModalFooter.defaultProps = {
25
- id: undefined,
26
26
  justify: 'center',
27
27
  };
28
28
 
@@ -31,10 +31,6 @@ ModalFooter.propTypes = {
31
31
  * Content of the footer (preferably nested `Button` elements).
32
32
  */
33
33
  children: PropTypes.node.isRequired,
34
- /**
35
- * ID of the root HTML element.
36
- */
37
- id: PropTypes.string,
38
34
  /**
39
35
  * Horizontal alignment (distribution) of individual buttons.
40
36
  */
@@ -14,22 +14,22 @@
14
14
  background: theme.$footer-background;
15
15
  }
16
16
 
17
- .isJustifiedToStart {
17
+ .isRootJustifiedToStart {
18
18
  justify-content: flex-start;
19
19
  }
20
20
 
21
- .isJustifiedToCenter {
21
+ .isRootJustifiedToCenter {
22
22
  justify-content: center;
23
23
  }
24
24
 
25
- .isJustifiedToEnd {
25
+ .isRootJustifiedToEnd {
26
26
  justify-content: flex-end;
27
27
  }
28
28
 
29
- .isJustifiedToSpaceBetween {
29
+ .isRootJustifiedToSpaceBetween {
30
30
  justify-content: space-between;
31
31
  }
32
32
 
33
- .isJustifiedToStretch {
33
+ .isRootJustifiedToStretch {
34
34
  display: block;
35
35
  }
@@ -3,28 +3,28 @@ import React from 'react';
3
3
  import {
4
4
  withGlobalProps,
5
5
  } from '../../provider';
6
+ import { transferProps } from '../_helpers/transferProps';
6
7
  import { classNames } from '../../utils/classNames';
7
8
  import { getJustifyClassName } from './_helpers/getJustifyClassName';
8
9
  import styles from './ModalHeader.scss';
9
10
 
10
11
  export const ModalHeader = ({
11
12
  children,
12
- id,
13
13
  justify,
14
+ ...restProps
14
15
  }) => (
15
16
  <div
17
+ {...transferProps(restProps)}
16
18
  className={classNames(
17
19
  styles.root,
18
20
  getJustifyClassName(justify, styles),
19
21
  )}
20
- id={id}
21
22
  >
22
23
  {children}
23
24
  </div>
24
25
  );
25
26
 
26
27
  ModalHeader.defaultProps = {
27
- id: undefined,
28
28
  justify: 'space-between',
29
29
  };
30
30
 
@@ -33,10 +33,6 @@ ModalHeader.propTypes = {
33
33
  * Content of the header (preferably ModalTitle and ModalCloseButton).
34
34
  */
35
35
  children: PropTypes.node.isRequired,
36
- /**
37
- * ID of the root HTML element.
38
- */
39
- id: PropTypes.string,
40
36
  /**
41
37
  * Horizontal alignment (distribution) of individual buttons.
42
38
  */
@@ -9,22 +9,22 @@
9
9
  border-bottom: theme.$separator-width solid theme.$separator-color;
10
10
  }
11
11
 
12
- .isJustifiedToStart {
12
+ .isRootJustifiedToStart {
13
13
  justify-content: flex-start;
14
14
  }
15
15
 
16
- .isJustifiedToCenter {
16
+ .isRootJustifiedToCenter {
17
17
  justify-content: center;
18
18
  }
19
19
 
20
- .isJustifiedToEnd {
20
+ .isRootJustifiedToEnd {
21
21
  justify-content: flex-end;
22
22
  }
23
23
 
24
- .isJustifiedToSpaceBetween {
24
+ .isRootJustifiedToSpaceBetween {
25
25
  justify-content: space-between;
26
26
  }
27
27
 
28
- .isJustifiedToStretch {
28
+ .isRootJustifiedToStretch {
29
29
  display: block;
30
30
  }
@@ -3,24 +3,27 @@ import React from 'react';
3
3
  import {
4
4
  withGlobalProps,
5
5
  } from '../../provider';
6
+ import { transferProps } from '../_helpers/transferProps';
6
7
  import styles from './ModalTitle.scss';
7
8
 
8
9
  export const ModalTitle = ({
9
10
  children,
10
- id,
11
11
  level,
12
+ ...restProps
12
13
  }) => {
13
14
  const HeadingTag = `h${level}`;
14
15
 
15
16
  return (
16
- <HeadingTag className={styles.root} id={id}>
17
+ <HeadingTag
18
+ {...transferProps(restProps)}
19
+ className={styles.root}
20
+ >
17
21
  {children}
18
22
  </HeadingTag>
19
23
  );
20
24
  };
21
25
 
22
26
  ModalTitle.defaultProps = {
23
- id: undefined,
24
27
  level: 2,
25
28
  };
26
29
 
@@ -29,10 +32,6 @@ ModalTitle.propTypes = {
29
32
  * Content of the header (preferably ModalTitle and ModalCloseButton).
30
33
  */
31
34
  children: PropTypes.node.isRequired,
32
- /**
33
- * ID of the root HTML element.
34
- */
35
- id: PropTypes.string,
36
35
  /**
37
36
  * Optional heading level. Preferably `1` or `2` should be used, see
38
37
  * [W3C recommendation](https://github.com/w3c/aria-practices/issues/551#issuecomment-365134527).
@@ -115,10 +115,10 @@ See [API](#api) for all available options.
115
115
  - **Modal actions** should correspond to the modal purpose, too. E.g. “Delete”
116
116
  tells better what happens rather than “OK”.
117
117
 
118
- - Modal **automatically focuses the first form field** by default which allows
119
- users to confirm the modal by hitting the enter key. When no field is found
120
- then the primary button (in the footer) is focused. To turn this feature off,
121
- set the `autofocus` prop to `false`.
118
+ - Modal **automatically focuses the first non-disabled form field** by default
119
+ which allows users to confirm the modal by hitting the enter key. When no
120
+ field is found then the primary button (in the footer) is focused. To turn
121
+ this feature off, set the `autofocus` prop to `false`.
122
122
 
123
123
  - **Avoid stacking** of modals. While it may technically work, the modal is just
124
124
  not designed for that.
@@ -841,8 +841,9 @@ Autofocus is implemented to enhance the user experience by automatically
841
841
  focussing an element within the modal.
842
842
 
843
843
  How does it work? It tries to find `input`, `textarea`, and `select` elements
844
- inside of Modal and moves focus into the first found. If none is found and the
845
- `primaryButtonRef` prop on Modal is set, then the primary button is focused.
844
+ inside of Modal and moves focus onto the first non-disabled one. If none is
845
+ found and the `primaryButtonRef` prop on Modal is set, then the primary button
846
+ is focused.
846
847
 
847
848
  Autofocus is enabled by default, so if you want to control the focus of
848
849
  elements manually, set the `autoFocus` prop on Modal to `false`.
@@ -1017,6 +1018,26 @@ opened.
1017
1018
 
1018
1019
  <!-- markdownlint-disable MD024 -->
1019
1020
 
1021
+ ## Forwarding HTML Attributes
1022
+
1023
+ In addition to the options below in the [component's API](#api) section, you
1024
+ can specify [React synthetic events] or **any HTML attribute you like.** All
1025
+ attributes that don't interfere with the API are forwarded to the:
1026
+
1027
+ - `<div>` HTML element in case of the `Modal` component. This `<div>` is not the
1028
+ root, but its first child which represents the modal window.
1029
+ - root `<div>` HTML element in case of `ModalHeader`, `ModalBody`, `ModalContent`
1030
+ and `ModalFooter` components.
1031
+ - heading HTML element, which level can be specified through `level` option, in
1032
+ case of the `ModalTitle` component.
1033
+ - native HTML `<button>` in case of the `ModalCloseButton` component.
1034
+
1035
+ This enables making the component interactive and helps to improve its
1036
+ accessibility.
1037
+
1038
+ 👉 Refer to the MDN reference for the full list of supported attributes of the
1039
+ [div], [heading] and [button] element.
1040
+
1020
1041
  ## API
1021
1042
 
1022
1043
  <Props table of={Modal} />
@@ -1068,3 +1089,8 @@ opened.
1068
1089
  | `--rui-Modal--large__width` | Width of large modal |
1069
1090
  | `--rui-Modal--fullscreen__width` | Width of fullscreen modal |
1070
1091
  | `--rui-Modal--fullscreen__height` | Height of fullscreen modal |
1092
+
1093
+ [React synthetic events]: https://reactjs.org/docs/events.html
1094
+ [div]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div#attributes
1095
+ [heading]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#attributes
1096
+ [button]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attributes