@react-ui-org/react-ui 0.59.3 → 0.61.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 (59) hide show
  1. package/.env.playwright +9 -0
  2. package/.env.playwright.dist +9 -0
  3. package/.eslintrc-ts +40 -0
  4. package/README.md +18 -1
  5. package/dist/react-ui.css +4 -4
  6. package/dist/react-ui.development.css +8 -0
  7. package/dist/react-ui.development.js +57 -47
  8. package/dist/react-ui.js +1 -1
  9. package/jest.config-ts.js +34 -0
  10. package/package.json +25 -6
  11. package/playwright-ct.config.ts +68 -0
  12. package/src/components/Alert/Alert.jsx +2 -2
  13. package/src/components/Button/Button.jsx +5 -5
  14. package/src/components/Button/README.md +1 -1
  15. package/src/components/ButtonGroup/ButtonGroup.jsx +2 -2
  16. package/src/components/Card/Card.module.scss +1 -0
  17. package/src/components/Card/CardFooter.jsx +2 -2
  18. package/src/components/Card/README.md +2 -0
  19. package/src/components/Card/_theme.scss +2 -0
  20. package/src/components/CheckboxField/CheckboxField.jsx +3 -3
  21. package/src/components/FileInputField/FileInputField.jsx +21 -8
  22. package/src/components/FileInputField/FileInputField.module.scss +4 -0
  23. package/src/components/FormLayout/FormLayout.jsx +2 -2
  24. package/src/components/FormLayout/FormLayoutCustomField.jsx +5 -5
  25. package/src/components/Grid/Grid.jsx +2 -2
  26. package/src/components/Grid/GridSpan.jsx +2 -2
  27. package/src/components/InputGroup/InputGroup.jsx +25 -5
  28. package/src/components/InputGroup/InputGroup.module.scss +2 -1
  29. package/src/components/InputGroup/README.md +69 -14
  30. package/src/components/Modal/Modal.jsx +26 -8
  31. package/src/components/Modal/ModalBody.jsx +2 -2
  32. package/src/components/Modal/ModalContent.jsx +2 -2
  33. package/src/components/Modal/_helpers/dialogOnClickHandler.js +6 -0
  34. package/src/components/Popover/Popover.jsx +5 -5
  35. package/src/components/Radio/Radio.jsx +3 -3
  36. package/src/components/ScrollView/ScrollView.jsx +42 -12
  37. package/src/components/ScrollView/_hooks/useScrollPositionHook.js +4 -4
  38. package/src/components/SelectField/SelectField.jsx +9 -6
  39. package/src/components/Table/Table.jsx +1 -1
  40. package/src/components/Table/_components/TableBodyCell/TableBodyCell.jsx +1 -1
  41. package/src/components/Table/_components/TableHeaderCell/TableHeaderCell.jsx +1 -1
  42. package/src/components/Tabs/TabsItem.jsx +3 -3
  43. package/src/components/Text/Text.jsx +2 -2
  44. package/src/components/TextArea/TextArea.jsx +3 -3
  45. package/src/components/TextField/TextField.jsx +11 -8
  46. package/src/components/Toggle/Toggle.jsx +3 -3
  47. package/src/components/Toolbar/Toolbar.jsx +2 -2
  48. package/src/components/Toolbar/ToolbarGroup.jsx +2 -2
  49. package/src/components/Toolbar/ToolbarItem.jsx +2 -2
  50. package/src/helpers/isChildrenEmpty/README.md +57 -0
  51. package/src/helpers/isChildrenEmpty/index.js +1 -0
  52. package/src/index.js +1 -0
  53. package/src/providers/globalProps/GlobalPropsProvider.jsx +1 -1
  54. package/src/providers/translations/TranslationsProvider.jsx +1 -1
  55. package/src/styles/settings/_breakpoints.scss +2 -0
  56. package/src/theme.scss +2 -0
  57. package/src/translations/en.js +1 -0
  58. package/tsconfig.json +27 -0
  59. /package/src/{components/_helpers → helpers/isChildrenEmpty}/isChildrenEmpty.js +0 -0
@@ -60,13 +60,14 @@ See [API](#api) for all available options.
60
60
  Make sure your inputs fit their container, especially on small screens.
61
61
 
62
62
  - In the background, InputGroup uses the [`fieldset`][fieldset] element. Not
63
- only it improves the [accessibility] of the group, it also allows you to make
64
- use of its built-in features like disabling all nested inputs or pairing the
65
- group with a form outside. Consult [the MDN docs][fieldset] to learn more.
63
+ only does it improve the [accessibility] of the group, it also allows you to
64
+ make use of its built-in features like disabling all nested inputs or pairing
65
+ the group with a form outside. Consult [the MDN docs][fieldset] to learn more.
66
66
 
67
67
  - InputGroup currently **supports grouping of**
68
68
  [TextField](/components/TextField), [SelectField](/components/SelectField),
69
- and [Button](/components/Button) components.
69
+ [FileInputField](/components/FileInputField), and [Button](/components/Button)
70
+ components.
70
71
 
71
72
  - To group [Buttons](/components/Button) only, use the
72
73
  [ButtonGroup](/components/ButtonGroup) component which is designed
@@ -104,7 +105,7 @@ You can set the `size` property directly on InputGroup to be shared for all
104
105
  fields and buttons inside the group. This property is then passed over to
105
106
  individual elements. At the same time, it **cannot be overridden** on the
106
107
  fields' or buttons' level. While technically possible, from the design point of
107
- view it's undesirable to group elements of totally different types or sizes.
108
+ view, it's undesirable to group elements of totally different types or sizes.
108
109
 
109
110
  ## Invisible Label
110
111
 
@@ -136,9 +137,9 @@ the input.
136
137
 
137
138
  ## Horizontal layout
138
139
 
139
- The default vertical layout is very easy to use and work with. However, there
140
- are situations where horizontal layout suits better — and that's why React UI
141
- supports this kind of layout as well.
140
+ The default vertical layout is straightforward to use and work with. However,
141
+ there are situations where horizontal layout suits better — and that's why
142
+ React UI supports this kind of layout as well.
142
143
 
143
144
  ```docoff-react-preview
144
145
  <InputGroup
@@ -150,6 +151,57 @@ supports this kind of layout as well.
150
151
  </InputGroup>
151
152
  ```
152
153
 
154
+ ## Help Text
155
+
156
+ You may provide one or more additional help texts to clarify how the input group
157
+ should be filled.
158
+
159
+ These messages are not semantically tied to the `children` elements, the
160
+ connection should be expressed in textual form in the actual message.
161
+
162
+ ⚠️ Help texts passed to input elements' `helpText` prop are ignored within
163
+ InputGroup.
164
+
165
+ ```docoff-react-preview
166
+ React.createElement(() => {
167
+ const [fruit, setFruit] = React.useState('apple');
168
+ const options = [
169
+ {
170
+ label: 'Apple',
171
+ value: 'apple',
172
+ },
173
+ {
174
+ label: 'Pear',
175
+ value: 'pear',
176
+ },
177
+ {
178
+ label: 'Cherry',
179
+ value: 'cherry',
180
+ },
181
+ ];
182
+ return (
183
+ <InputGroup
184
+ label="Your favourite fruit"
185
+ helpTexts={[
186
+ "Choose one or more kinds of fruit to feel happy.",
187
+ ]}
188
+ >
189
+ <SelectField
190
+ label="Your favourite fruit"
191
+ onChange={(e) => setFruit(e.target.value)}
192
+ options={options}
193
+ value={fruit}
194
+ />
195
+ <TextField
196
+ label="Variety"
197
+ placeholder="Eg. Golden delicious"
198
+ />
199
+ <Button label="Submit" />
200
+ </InputGroup>
201
+ );
202
+ })
203
+ ```
204
+
153
205
  ## States
154
206
 
155
207
  ### Disabled State
@@ -169,12 +221,15 @@ Validation states visually present the result of validation of the grouped
169
221
  inputs. Input group's validation state is taken from its child inputs. You
170
222
  should always **provide validation messages for states other than valid**
171
223
  directly through `validationTexts` prop so users know what happened and what
172
- action they should take or what options they have. These messages are not
173
- semantically tied to the `children` elements, the connection should be expressed
174
- in textual form in the actual message. The individual `children` elements must
175
- not show any `validationText`, they only show their respective `validationState`.
176
- Validation messages passed to input elements' `validationText` prop will be
177
- ignored.
224
+ action they should take or what options they have.
225
+
226
+ These messages are not semantically tied to the `children` elements, the
227
+ connection should be expressed in textual form in the actual message. The
228
+ individual `children` elements must not show any `validationText`, they only
229
+ show their respective `validationState`.
230
+
231
+ ⚠️ Validation messages passed to input elements' `validationText` prop are
232
+ ignored within InputGroup.
178
233
 
179
234
  👉 While there is a `required` property to visually denote the whole input group
180
235
  is required, there is no functional effect as there is no such HTML attribute
@@ -61,6 +61,7 @@ export const Modal = ({
61
61
  ...restProps
62
62
  }) => {
63
63
  const internalDialogRef = useRef();
64
+ const mouseDownTarget = useRef(null);
64
65
 
65
66
  useEffect(() => {
66
67
  internalDialogRef.current.showModal();
@@ -75,11 +76,22 @@ export const Modal = ({
75
76
  useModalScrollPrevention(preventScrollUnderneath);
76
77
 
77
78
  const onCancel = useCallback(
78
- (e) => dialogOnCancelHandler(e, closeButtonRef, restProps.onCancel),
79
+ (e) => {
80
+ if (e.target !== internalDialogRef.current) {
81
+ return;
82
+ }
83
+ dialogOnCancelHandler(e, closeButtonRef, restProps.onCancel);
84
+ },
79
85
  [closeButtonRef, restProps.onCancel],
80
86
  );
81
87
  const onClick = useCallback(
82
- (e) => dialogOnClickHandler(e, closeButtonRef, internalDialogRef, allowCloseOnBackdropClick),
88
+ (e) => dialogOnClickHandler(
89
+ e,
90
+ closeButtonRef,
91
+ internalDialogRef,
92
+ allowCloseOnBackdropClick,
93
+ mouseDownTarget.current,
94
+ ),
83
95
  [allowCloseOnBackdropClick, closeButtonRef, internalDialogRef],
84
96
  );
85
97
  const onClose = useCallback(
@@ -101,14 +113,20 @@ export const Modal = ({
101
113
  primaryButtonRef,
102
114
  ],
103
115
  );
116
+
117
+ const onMouseDown = useCallback((e) => {
118
+ mouseDownTarget.current = e.target;
119
+ }, []);
120
+
104
121
  const events = {
105
122
  onCancel,
106
123
  onClick,
107
124
  onClose,
108
125
  onKeyDown,
126
+ onMouseDown,
109
127
  };
110
128
 
111
- if (portalId === null) {
129
+ if (portalId === undefined) {
112
130
  return preRender(
113
131
  children,
114
132
  color,
@@ -139,14 +157,14 @@ Modal.defaultProps = {
139
157
  allowCloseOnEscapeKey: true,
140
158
  allowPrimaryActionOnEnterKey: true,
141
159
  autoFocus: true,
142
- children: null,
143
- closeButtonRef: null,
160
+ children: undefined,
161
+ closeButtonRef: undefined,
144
162
  color: undefined,
145
- dialogRef: null,
146
- portalId: null,
163
+ dialogRef: undefined,
164
+ portalId: undefined,
147
165
  position: 'center',
148
166
  preventScrollUnderneath: window.document.body,
149
- primaryButtonRef: null,
167
+ primaryButtonRef: undefined,
150
168
  size: 'medium',
151
169
  };
152
170
 
@@ -3,7 +3,7 @@ import React from 'react';
3
3
  import { withGlobalProps } from '../../providers/globalProps';
4
4
  import { classNames } from '../../helpers/classNames/classNames';
5
5
  import { transferProps } from '../../helpers/transferProps';
6
- import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
6
+ import { isChildrenEmpty } from '../../helpers/isChildrenEmpty/isChildrenEmpty';
7
7
  import { getScrollingClassName } from './_helpers/getScrollingClassName';
8
8
  import styles from './ModalBody.module.scss';
9
9
 
@@ -30,7 +30,7 @@ export const ModalBody = ({
30
30
  };
31
31
 
32
32
  ModalBody.defaultProps = {
33
- children: null,
33
+ children: undefined,
34
34
  scrolling: 'auto',
35
35
  };
36
36
 
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
3
  import { withGlobalProps } from '../../providers/globalProps';
4
4
  import { transferProps } from '../../helpers/transferProps';
5
- import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
5
+ import { isChildrenEmpty } from '../../helpers/isChildrenEmpty/isChildrenEmpty';
6
6
  import styles from './ModalContent.module.scss';
7
7
 
8
8
  export const ModalContent = ({
@@ -24,7 +24,7 @@ export const ModalContent = ({
24
24
  };
25
25
 
26
26
  ModalContent.defaultProps = {
27
- children: null,
27
+ children: undefined,
28
28
  };
29
29
 
30
30
  ModalContent.propTypes = {
@@ -17,12 +17,18 @@ export const dialogOnClickHandler = (
17
17
  closeButtonRef,
18
18
  dialogRef,
19
19
  allowCloseOnBackdropClick,
20
+ mouseDownTarget,
20
21
  ) => {
21
22
  // If it is not allowed to close modal on backdrop click, do nothing.
22
23
  if (!allowCloseOnBackdropClick) {
23
24
  return;
24
25
  }
25
26
 
27
+ // If the click started on the inside of the dialog, do nothing.
28
+ if (e.target !== mouseDownTarget) {
29
+ return;
30
+ }
31
+
26
32
  // Detection of the click on the backdrop is based on the following conditions:
27
33
  // 1. The click target is the dialog itself. This prevents detection of clicks on the dialog's children.
28
34
  // 2. The click is outside the dialog's boundaries.
@@ -43,7 +43,7 @@ export const Popover = React.forwardRef((props, ref) => {
43
43
  getRootAlignmentClassName(placement, styles),
44
44
  )}
45
45
  ref={ref}
46
- style={placementStyle ? cleanPlacementStyle(placementStyle) : null}
46
+ style={placementStyle ? cleanPlacementStyle(placementStyle) : undefined}
47
47
  >
48
48
  {children}
49
49
  <span className={styles.arrow} />
@@ -51,7 +51,7 @@ export const Popover = React.forwardRef((props, ref) => {
51
51
  </>
52
52
  );
53
53
 
54
- if (portalId === null) {
54
+ if (portalId === undefined) {
55
55
  return PopoverEl;
56
56
  }
57
57
 
@@ -60,9 +60,9 @@ export const Popover = React.forwardRef((props, ref) => {
60
60
 
61
61
  Popover.defaultProps = {
62
62
  placement: 'bottom',
63
- placementStyle: null,
64
- popoverTargetId: null,
65
- portalId: null,
63
+ placementStyle: undefined,
64
+ popoverTargetId: undefined,
65
+ portalId: undefined,
66
66
  };
67
67
 
68
68
  Popover.propTypes = {
@@ -113,14 +113,14 @@ export const Radio = ({
113
113
 
114
114
  Radio.defaultProps = {
115
115
  disabled: false,
116
- helpText: null,
116
+ helpText: undefined,
117
117
  id: undefined,
118
118
  isLabelVisible: true,
119
119
  layout: 'vertical',
120
120
  renderAsRequired: false,
121
121
  required: false,
122
- validationState: null,
123
- validationText: null,
122
+ validationState: undefined,
123
+ validationText: undefined,
124
124
  value: undefined,
125
125
  };
126
126
 
@@ -5,6 +5,7 @@ import React, {
5
5
  useLayoutEffect,
6
6
  useRef,
7
7
  useState,
8
+ useCallback,
8
9
  } from 'react';
9
10
  import { TranslationsContext } from '../../providers/translations';
10
11
  import { withGlobalProps } from '../../providers/globalProps';
@@ -58,20 +59,26 @@ export const ScrollView = React.forwardRef((props, ref) => {
58
59
  const blankRef = useRef(null);
59
60
  const scrollViewViewportEl = ref ?? blankRef;
60
61
 
61
- const handleScrollViewState = (currentPosition) => {
62
+ const handleScrollViewState = useCallback((currentPosition) => {
62
63
  const isScrolledAtStartActive = currentPosition[scrollPositionStart]
63
64
  <= -1 * EDGE_DETECTION_INACCURACY_PX;
64
65
  const isScrolledAtEndActive = currentPosition[scrollPositionEnd]
65
66
  >= EDGE_DETECTION_INACCURACY_PX;
66
67
 
67
- if (isScrolledAtStartActive !== isScrolledAtStart) {
68
- setIsScrolledAtStart(isScrolledAtStartActive);
69
- }
68
+ setIsScrolledAtStart((prevIsScrolledAtStart) => {
69
+ if (isScrolledAtStartActive !== prevIsScrolledAtStart) {
70
+ return isScrolledAtStartActive;
71
+ }
72
+ return prevIsScrolledAtStart;
73
+ });
70
74
 
71
- if (isScrolledAtEndActive !== isScrolledAtEnd) {
72
- setIsScrolledAtEnd(isScrolledAtEndActive);
73
- }
74
- };
75
+ setIsScrolledAtEnd((prevIsScrolledAtEnd) => {
76
+ if (isScrolledAtEndActive !== prevIsScrolledAtEnd) {
77
+ return isScrolledAtEndActive;
78
+ }
79
+ return prevIsScrolledAtEnd;
80
+ });
81
+ }, [scrollPositionStart, scrollPositionEnd]);
75
82
 
76
83
  /**
77
84
  * It handles scroll event fired on `scrollViewViewportEl` element. If autoScroll is in progress,
@@ -146,7 +153,6 @@ export const ScrollView = React.forwardRef((props, ref) => {
146
153
 
147
154
  useScrollPosition(
148
155
  (currentPosition) => (handleScrollViewState(currentPosition)),
149
- [isScrolledAtStart, isScrolledAtEnd],
150
156
  scrollViewContentEl,
151
157
  scrollViewViewportEl,
152
158
  debounce,
@@ -163,6 +169,30 @@ export const ScrollView = React.forwardRef((props, ref) => {
163
169
  [autoScroll, autoScrollChildrenKeys, autoScrollChildrenLength],
164
170
  );
165
171
 
172
+ // ResizeObserver to detect when content or viewport dimensions change due to style changes
173
+ useLayoutEffect(() => {
174
+ const contentElement = scrollViewContentEl.current;
175
+ const viewportElement = scrollViewViewportEl.current;
176
+
177
+ if (!contentElement || !viewportElement) {
178
+ return () => {};
179
+ }
180
+
181
+ const resizeObserver = new ResizeObserver(() => {
182
+ handleScrollViewState(
183
+ getElementsPositionDifference(scrollViewContentEl, scrollViewViewportEl),
184
+ );
185
+ });
186
+
187
+ // Observe both content and viewport for dimension changes
188
+ resizeObserver.observe(contentElement);
189
+ resizeObserver.observe(viewportElement);
190
+
191
+ return () => {
192
+ resizeObserver.disconnect();
193
+ };
194
+ }, [scrollViewContentEl, scrollViewViewportEl, handleScrollViewState]);
195
+
166
196
  const arrowHandler = (contentEl, viewportEl, scrollViewDirection, shiftDirection, step) => {
167
197
  const offset = shiftDirection === 'next' ? step : -1 * step;
168
198
  const differenceX = scrollViewDirection === 'horizontal' ? offset : 0;
@@ -267,7 +297,7 @@ ScrollView.defaultProps = {
267
297
  arrows: false,
268
298
  arrowsScrollStep: 200,
269
299
  autoScroll: 'off',
270
- children: null,
300
+ children: undefined,
271
301
  debounce: 50,
272
302
  direction: 'vertical',
273
303
  endShadowBackground: 'linear-gradient(var(--rui-local-end-shadow-direction), rgba(255 255 255 / 1), rgba(255 255 255 / 0))',
@@ -275,10 +305,10 @@ ScrollView.defaultProps = {
275
305
  endShadowSize: '2em',
276
306
  id: undefined,
277
307
  nextArrowColor: undefined,
278
- nextArrowElement: null,
308
+ nextArrowElement: undefined,
279
309
  nextArrowInitialOffset: '-0.5rem',
280
310
  prevArrowColor: undefined,
281
- prevArrowElement: null,
311
+ prevArrowElement: undefined,
282
312
  prevArrowInitialOffset: '-0.5rem',
283
313
  scrollbar: true,
284
314
  shadows: true,
@@ -1,10 +1,10 @@
1
1
  import {
2
- useLayoutEffect,
3
2
  useRef,
3
+ useEffect,
4
4
  } from 'react';
5
5
  import { getElementsPositionDifference } from '../_helpers/getElementsPositionDifference';
6
6
 
7
- export const useScrollPosition = (effect, dependencies, contentEl, viewportEl, wait) => {
7
+ export const useScrollPosition = (effect, contentEl, viewportEl, wait) => {
8
8
  const throttleTimeout = useRef(null);
9
9
 
10
10
  const callBack = (wasDelayed = false) => {
@@ -15,7 +15,7 @@ export const useScrollPosition = (effect, dependencies, contentEl, viewportEl, w
15
15
  }
16
16
  };
17
17
 
18
- useLayoutEffect(() => {
18
+ useEffect(() => {
19
19
  const viewport = viewportEl.current;
20
20
 
21
21
  const handleScroll = () => {
@@ -34,7 +34,7 @@ export const useScrollPosition = (effect, dependencies, contentEl, viewportEl, w
34
34
  clearTimeout(throttleTimeout.current);
35
35
  viewport.removeEventListener('scroll', handleScroll);
36
36
  };
37
- }, dependencies); // eslint-disable-line react-hooks/exhaustive-deps
37
+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
38
38
  };
39
39
 
40
40
  export default useScrollPosition;
@@ -109,7 +109,7 @@ export const SelectField = React.forwardRef((props, ref) => {
109
109
  <div className={styles.bottomLine} />
110
110
  )}
111
111
  </div>
112
- {helpText && (
112
+ {(helpText && !inputGroupContext) && (
113
113
  <div
114
114
  className={styles.helpText}
115
115
  id={id && `${id}__helpText`}
@@ -133,15 +133,15 @@ export const SelectField = React.forwardRef((props, ref) => {
133
133
  SelectField.defaultProps = {
134
134
  disabled: false,
135
135
  fullWidth: false,
136
- helpText: null,
136
+ helpText: undefined,
137
137
  id: undefined,
138
138
  isLabelVisible: true,
139
139
  layout: 'vertical',
140
140
  renderAsRequired: false,
141
141
  required: false,
142
142
  size: 'medium',
143
- validationState: null,
144
- validationText: null,
143
+ validationState: undefined,
144
+ validationText: undefined,
145
145
  variant: 'outline',
146
146
  };
147
147
 
@@ -156,6 +156,9 @@ SelectField.propTypes = {
156
156
  fullWidth: PropTypes.bool,
157
157
  /**
158
158
  * Optional help text.
159
+ *
160
+ * Help text is never rendered when the component is placed into `InputGroup`.
161
+ * If a help text is needed, it must be defined on the `InputGroup` component instead.
159
162
  */
160
163
  helpText: PropTypes.node,
161
164
  /**
@@ -249,8 +252,8 @@ SelectField.propTypes = {
249
252
  /**
250
253
  * Validation message to be displayed.
251
254
  *
252
- * Validation text is never rendered when the component is placed into `InputGroup`. Instead, the `InputGroup`
253
- * component itself renders all validation texts of its nested components.
255
+ * Validation text is never rendered when the component is placed into `InputGroup`.
256
+ * If a validation text is needed, it must be defined on the `InputGroup` component instead.
254
257
  */
255
258
  validationText: PropTypes.node,
256
259
  /**
@@ -53,7 +53,7 @@ export const Table = ({
53
53
 
54
54
  Table.defaultProps = {
55
55
  id: undefined,
56
- sort: null,
56
+ sort: undefined,
57
57
  };
58
58
 
59
59
  Table.propTypes = {
@@ -20,7 +20,7 @@ TableBodyCell.defaultProps = {
20
20
  format: undefined,
21
21
  id: undefined,
22
22
  isSortingActive: false,
23
- value: null,
23
+ value: undefined,
24
24
  };
25
25
 
26
26
  TableBodyCell.propTypes = {
@@ -42,7 +42,7 @@ export const TableHeaderCell = ({
42
42
 
43
43
  TableHeaderCell.defaultProps = {
44
44
  id: undefined,
45
- sort: null,
45
+ sort: undefined,
46
46
  };
47
47
 
48
48
  TableHeaderCell.propTypes = {
@@ -45,11 +45,11 @@ export const TabsItem = ({
45
45
  );
46
46
 
47
47
  TabsItem.defaultProps = {
48
- afterLabel: null,
49
- beforeLabel: null,
48
+ afterLabel: undefined,
49
+ beforeLabel: undefined,
50
50
  id: undefined,
51
51
  isActive: false,
52
- onClick: null,
52
+ onClick: undefined,
53
53
  };
54
54
 
55
55
  TabsItem.propTypes = {
@@ -3,7 +3,7 @@ import React from 'react';
3
3
  import { withGlobalProps } from '../../providers/globalProps';
4
4
  import { classNames } from '../../helpers/classNames/classNames';
5
5
  import { transferProps } from '../../helpers/transferProps';
6
- import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
6
+ import { isChildrenEmpty } from '../../helpers/isChildrenEmpty/isChildrenEmpty';
7
7
  import { getRootClampClassName } from './_helpers/getRootClampClassName';
8
8
  import { getRootHyphensClassName } from './_helpers/getRootHyphensClassName';
9
9
  import { getRootWordWrappingClassName } from './_helpers/getRootWordWrappingClassName';
@@ -42,7 +42,7 @@ export const Text = ({
42
42
 
43
43
  Text.defaultProps = {
44
44
  blockLevel: false,
45
- children: null,
45
+ children: undefined,
46
46
  hyphens: 'none',
47
47
  lines: undefined,
48
48
  wordWrapping: 'normal',
@@ -93,14 +93,14 @@ export const TextArea = React.forwardRef((props, ref) => {
93
93
  TextArea.defaultProps = {
94
94
  disabled: false,
95
95
  fullWidth: false,
96
- helpText: null,
96
+ helpText: undefined,
97
97
  id: undefined,
98
98
  isLabelVisible: true,
99
99
  layout: 'vertical',
100
100
  required: false,
101
101
  size: 'medium',
102
- validationState: null,
103
- validationText: null,
102
+ validationState: undefined,
103
+ validationText: undefined,
104
104
  variant: 'outline',
105
105
  };
106
106
 
@@ -32,7 +32,7 @@ export const TextField = React.forwardRef((props, ref) => {
32
32
  } = props;
33
33
  const formLayoutContext = useContext(FormLayoutContext);
34
34
  const inputGroupContext = useContext(InputGroupContext);
35
- const hasSmallInput = (inputSize !== null) && (inputSize <= SMALL_INPUT_SIZE);
35
+ const hasSmallInput = (inputSize !== undefined) && (inputSize <= SMALL_INPUT_SIZE);
36
36
 
37
37
  return (
38
38
  <label
@@ -84,7 +84,7 @@ export const TextField = React.forwardRef((props, ref) => {
84
84
  <div className={styles.bottomLine} />
85
85
  )}
86
86
  </div>
87
- {helpText && (
87
+ {(helpText && !inputGroupContext) && (
88
88
  <div
89
89
  className={styles.helpText}
90
90
  id={id && `${id}__helpText`}
@@ -108,16 +108,16 @@ export const TextField = React.forwardRef((props, ref) => {
108
108
  TextField.defaultProps = {
109
109
  disabled: false,
110
110
  fullWidth: false,
111
- helpText: null,
111
+ helpText: undefined,
112
112
  id: undefined,
113
- inputSize: null,
113
+ inputSize: undefined,
114
114
  isLabelVisible: true,
115
115
  layout: 'vertical',
116
116
  required: false,
117
117
  size: 'medium',
118
118
  type: 'text',
119
- validationState: null,
120
- validationText: null,
119
+ validationState: undefined,
120
+ validationText: undefined,
121
121
  variant: 'outline',
122
122
  };
123
123
 
@@ -132,6 +132,9 @@ TextField.propTypes = {
132
132
  fullWidth: PropTypes.bool,
133
133
  /**
134
134
  * Optional help text.
135
+ *
136
+ * Help text is never rendered when the component is placed into `InputGroup`.
137
+ * If a help text is needed, it must be defined on the `InputGroup` component instead.
135
138
  */
136
139
  helpText: PropTypes.node,
137
140
  /**
@@ -185,8 +188,8 @@ TextField.propTypes = {
185
188
  /**
186
189
  * Validation message to be displayed.
187
190
  *
188
- * Validation text is never rendered when the component is placed into `InputGroup`. Instead, the `InputGroup`
189
- * component itself renders all validation texts of its nested components.
191
+ * Validation text is never rendered when the component is placed into `InputGroup`.
192
+ * If a validation text is needed, it must be defined on the `InputGroup` component instead.
190
193
  */
191
194
  validationText: PropTypes.node,
192
195
  /**
@@ -81,14 +81,14 @@ export const Toggle = React.forwardRef((props, ref) => {
81
81
 
82
82
  Toggle.defaultProps = {
83
83
  disabled: false,
84
- helpText: null,
84
+ helpText: undefined,
85
85
  id: undefined,
86
86
  isLabelVisible: true,
87
87
  labelPosition: 'after',
88
88
  renderAsRequired: false,
89
89
  required: false,
90
- validationState: null,
91
- validationText: null,
90
+ validationState: undefined,
91
+ validationText: undefined,
92
92
  };
93
93
 
94
94
  Toggle.propTypes = {
@@ -3,7 +3,7 @@ import React from 'react';
3
3
  import { withGlobalProps } from '../../providers/globalProps';
4
4
  import { classNames } from '../../helpers/classNames/classNames';
5
5
  import { transferProps } from '../../helpers/transferProps';
6
- import { isChildrenEmpty } from '../_helpers/isChildrenEmpty';
6
+ import { isChildrenEmpty } from '../../helpers/isChildrenEmpty/isChildrenEmpty';
7
7
  import { getAlignClassName } from './_helpers/getAlignClassName';
8
8
  import { getJustifyClassName } from './_helpers/getJustifyClassName';
9
9
  import styles from './Toolbar.module.scss';
@@ -38,7 +38,7 @@ export const Toolbar = ({
38
38
 
39
39
  Toolbar.defaultProps = {
40
40
  align: 'top',
41
- children: null,
41
+ children: undefined,
42
42
  dense: false,
43
43
  justify: 'start',
44
44
  nowrap: false,