@onewelcome/react-lib-components 0.1.1-alpha → 0.1.2-alpha

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 (179) hide show
  1. package/README.md +16 -1
  2. package/dist/Breadcrumbs/Breadcrumbs.d.ts +3 -3
  3. package/dist/Button/BaseButton.d.ts +3 -4
  4. package/dist/Button/Button.d.ts +3 -4
  5. package/dist/Button/IconButton.d.ts +3 -4
  6. package/dist/ContextMenu/ContextMenu.d.ts +3 -3
  7. package/dist/Form/Checkbox/Checkbox.d.ts +5 -5
  8. package/dist/Form/Fieldset/Fieldset.d.ts +4 -4
  9. package/dist/Form/FormControl/FormControl.d.ts +5 -5
  10. package/dist/Form/FormGroup/FormGroup.d.ts +4 -4
  11. package/dist/Form/FormHelperText/FormHelperText.d.ts +4 -5
  12. package/dist/Form/FormSelectorWrapper/FormSelectorWrapper.d.ts +8 -12
  13. package/dist/Form/Input/Input.d.ts +7 -6
  14. package/dist/Form/Label/Label.d.ts +4 -5
  15. package/dist/Form/Radio/Radio.d.ts +5 -5
  16. package/dist/Form/Select/Option.d.ts +3 -4
  17. package/dist/Form/Select/Select.d.ts +4 -4
  18. package/dist/Form/Textarea/Textarea.d.ts +9 -5
  19. package/dist/Form/Toggle/Toggle.d.ts +3 -3
  20. package/dist/Form/Wrapper/CheckboxWrapper/CheckboxWrapper.d.ts +4 -3
  21. package/dist/Form/Wrapper/InputWrapper/InputWrapper.d.ts +5 -5
  22. package/dist/Form/Wrapper/RadioWrapper/RadioWrapper.d.ts +4 -4
  23. package/dist/Form/Wrapper/SelectWrapper/SelectWrapper.d.ts +7 -4
  24. package/dist/Form/Wrapper/TextareaWrapper/TextareaWrapper.d.ts +3 -3
  25. package/dist/Form/Wrapper/Wrapper/Wrapper.d.ts +6 -6
  26. package/dist/Form/form.interfaces.d.ts +4 -3
  27. package/dist/Icon/Icon.d.ts +4 -4
  28. package/dist/Link/Link.d.ts +3 -5
  29. package/dist/Notifications/BaseModal/BaseModal.d.ts +3 -4
  30. package/dist/Notifications/BaseModal/BaseModalActions/BaseModalActions.d.ts +3 -3
  31. package/dist/Notifications/BaseModal/BaseModalContent/BaseModalContent.d.ts +3 -3
  32. package/dist/Notifications/BaseModal/BaseModalHeader/BaseModalHeader.d.ts +3 -3
  33. package/dist/Notifications/Dialog/Dialog.d.ts +3 -3
  34. package/dist/Notifications/Dialog/DialogActions/DialogActions.d.ts +3 -3
  35. package/dist/Notifications/Dialog/DialogTitle/DialogTitle.d.ts +3 -3
  36. package/dist/Notifications/DiscardChangesModal/DiscardChangesDialog/DiscardChangesDialog.d.ts +5 -4
  37. package/dist/Notifications/DiscardChangesModal/DiscardChangesModal.d.ts +3 -1
  38. package/dist/Pagination/Pagination.d.ts +19 -0
  39. package/dist/Popover/Popover.d.ts +3 -3
  40. package/dist/Tabs/Tab.d.ts +11 -0
  41. package/dist/Tabs/TabButton.d.ts +10 -0
  42. package/dist/Tabs/TabPanel.d.ts +8 -0
  43. package/dist/Tabs/Tabs.d.ts +9 -0
  44. package/dist/TextEllipsis/TextEllipsis.d.ts +6 -0
  45. package/dist/Tiles/Tile.d.ts +3 -3
  46. package/dist/Tiles/Tiles.d.ts +3 -3
  47. package/dist/Tooltip/Tooltip.d.ts +3 -3
  48. package/dist/Typography/Typography.d.ts +6 -4
  49. package/dist/Wizard/BaseWizardSteps/BaseWizardSteps.d.ts +3 -3
  50. package/dist/Wizard/WizardSteps/WizardSteps.d.ts +3 -3
  51. package/dist/_BaseStyling_/BaseStyling.d.ts +9 -0
  52. package/dist/hooks/useRepeater.d.ts +10 -0
  53. package/dist/hooks/useSpacing.d.ts +2 -2
  54. package/dist/hooks/useWrapper.d.ts +1 -1
  55. package/dist/index.d.ts +4 -0
  56. package/dist/interfaces.d.ts +2 -11
  57. package/dist/react-lib-components.cjs.development.js +2023 -1551
  58. package/dist/react-lib-components.cjs.development.js.map +1 -1
  59. package/dist/react-lib-components.cjs.production.min.js +1 -1
  60. package/dist/react-lib-components.cjs.production.min.js.map +1 -1
  61. package/dist/react-lib-components.esm.js +2021 -1553
  62. package/dist/react-lib-components.esm.js.map +1 -1
  63. package/dist/util/helper.d.ts +6 -1
  64. package/package.json +30 -24
  65. package/src/Breadcrumbs/Breadcrumbs.tsx +39 -37
  66. package/src/Button/BaseButton.test.tsx +65 -19
  67. package/src/Button/BaseButton.tsx +2 -3
  68. package/src/Button/Button.test.tsx +63 -17
  69. package/src/Button/Button.tsx +15 -4
  70. package/src/Button/IconButton.test.tsx +57 -22
  71. package/src/Button/IconButton.tsx +14 -9
  72. package/src/ContextMenu/ContextMenu.test.tsx +27 -1
  73. package/src/ContextMenu/ContextMenu.tsx +70 -65
  74. package/src/Form/Checkbox/Checkbox.test.tsx +28 -2
  75. package/src/Form/Checkbox/Checkbox.tsx +132 -122
  76. package/src/Form/Fieldset/Fieldset.test.tsx +28 -2
  77. package/src/Form/Fieldset/Fieldset.tsx +96 -50
  78. package/src/Form/FormControl/FormControl.test.tsx +27 -1
  79. package/src/Form/FormControl/FormControl.tsx +36 -39
  80. package/src/Form/FormGroup/FormGroup.test.tsx +27 -1
  81. package/src/Form/FormGroup/FormGroup.tsx +64 -58
  82. package/src/Form/FormHelperText/FormHelperText.test.tsx +27 -1
  83. package/src/Form/FormHelperText/FormHelperText.tsx +20 -16
  84. package/src/Form/FormSelectorWrapper/FormSelectorWrapper.test.tsx +78 -0
  85. package/src/Form/FormSelectorWrapper/FormSelectorWrapper.tsx +60 -55
  86. package/src/Form/Input/Input.module.scss +33 -15
  87. package/src/Form/Input/Input.test.tsx +27 -1
  88. package/src/Form/Input/Input.tsx +88 -47
  89. package/src/Form/Label/Label.test.tsx +27 -1
  90. package/src/Form/Label/Label.tsx +18 -14
  91. package/src/Form/Radio/Radio.test.tsx +28 -2
  92. package/src/Form/Radio/Radio.tsx +98 -90
  93. package/src/Form/Select/Option.test.tsx +27 -1
  94. package/src/Form/Select/Option.tsx +49 -42
  95. package/src/Form/Select/Select.module.scss +5 -1
  96. package/src/Form/Select/Select.test.tsx +224 -30
  97. package/src/Form/Select/Select.tsx +248 -182
  98. package/src/Form/Textarea/Textarea.module.scss +2 -1
  99. package/src/Form/Textarea/Textarea.test.tsx +28 -2
  100. package/src/Form/Textarea/Textarea.tsx +44 -29
  101. package/src/Form/Toggle/Toggle.module.scss +9 -0
  102. package/src/Form/Toggle/Toggle.test.tsx +27 -1
  103. package/src/Form/Toggle/Toggle.tsx +25 -12
  104. package/src/Form/Wrapper/CheckboxWrapper/CheckboxWrapper.test.tsx +27 -1
  105. package/src/Form/Wrapper/CheckboxWrapper/CheckboxWrapper.tsx +45 -48
  106. package/src/Form/Wrapper/InputWrapper/InputWrapper.module.scss +11 -0
  107. package/src/Form/Wrapper/InputWrapper/InputWrapper.test.tsx +89 -1
  108. package/src/Form/Wrapper/InputWrapper/InputWrapper.tsx +127 -74
  109. package/src/Form/Wrapper/RadioWrapper/RadioWrapper.tsx +64 -59
  110. package/src/Form/Wrapper/SelectWrapper/SelectWrapper.module.scss +1 -1
  111. package/src/Form/Wrapper/SelectWrapper/SelectWrapper.test.tsx +43 -1
  112. package/src/Form/Wrapper/SelectWrapper/SelectWrapper.tsx +54 -44
  113. package/src/Form/Wrapper/TextareaWrapper/TextareaWrapper.module.scss +3 -5
  114. package/src/Form/Wrapper/TextareaWrapper/TextareaWrapper.test.tsx +43 -1
  115. package/src/Form/Wrapper/TextareaWrapper/TextareaWrapper.tsx +100 -85
  116. package/src/Form/Wrapper/Wrapper/Wrapper.test.tsx +27 -1
  117. package/src/Form/Wrapper/Wrapper/Wrapper.tsx +76 -71
  118. package/src/Form/form.interfaces.ts +4 -3
  119. package/src/Icon/Icon.module.scss +4 -0
  120. package/src/Icon/Icon.test.tsx +30 -2
  121. package/src/Icon/Icon.tsx +5 -5
  122. package/src/Link/Link.test.tsx +27 -1
  123. package/src/Link/Link.tsx +4 -6
  124. package/src/Notifications/BaseModal/BaseModal.test.tsx +27 -1
  125. package/src/Notifications/BaseModal/BaseModal.tsx +59 -54
  126. package/src/Notifications/BaseModal/BaseModalActions/BaseModalActions.test.tsx +26 -1
  127. package/src/Notifications/BaseModal/BaseModalActions/BaseModalActions.tsx +11 -9
  128. package/src/Notifications/BaseModal/BaseModalContent/BaseModalContent.test.tsx +27 -1
  129. package/src/Notifications/BaseModal/BaseModalContent/BaseModalContent.tsx +27 -26
  130. package/src/Notifications/BaseModal/BaseModalHeader/BaseModalHeader.test.tsx +29 -1
  131. package/src/Notifications/BaseModal/BaseModalHeader/BaseModalHeader.tsx +18 -16
  132. package/src/Notifications/Dialog/Dialog.test.tsx +39 -1
  133. package/src/Notifications/Dialog/Dialog.tsx +84 -78
  134. package/src/Notifications/Dialog/DialogActions/DialogActions.test.tsx +27 -1
  135. package/src/Notifications/Dialog/DialogActions/DialogActions.tsx +15 -12
  136. package/src/Notifications/Dialog/DialogTitle/DialogTitle.test.tsx +28 -2
  137. package/src/Notifications/Dialog/DialogTitle/DialogTitle.tsx +13 -11
  138. package/src/Notifications/DiscardChangesModal/DiscardChangesDialog/DiscardChangesDialog.test.tsx +41 -1
  139. package/src/Notifications/DiscardChangesModal/DiscardChangesDialog/DiscardChangesDialog.tsx +43 -36
  140. package/src/Notifications/DiscardChangesModal/DiscardChangesModal.test.tsx +52 -1
  141. package/src/Notifications/DiscardChangesModal/DiscardChangesModal.tsx +8 -3
  142. package/src/Notifications/Snackbar/SnackbarItem/SnackbarItem.tsx +1 -1
  143. package/src/Pagination/Pagination.module.scss +120 -0
  144. package/src/Pagination/Pagination.test.tsx +176 -0
  145. package/src/Pagination/Pagination.tsx +205 -0
  146. package/src/Popover/Popover.tsx +3 -3
  147. package/src/Tabs/Tab.test.tsx +71 -0
  148. package/src/Tabs/Tab.tsx +17 -0
  149. package/src/Tabs/TabButton.module.scss +36 -0
  150. package/src/Tabs/TabButton.test.tsx +77 -0
  151. package/src/Tabs/TabButton.tsx +58 -0
  152. package/src/Tabs/TabPanel.module.scss +7 -0
  153. package/src/Tabs/TabPanel.test.tsx +76 -0
  154. package/src/Tabs/TabPanel.tsx +27 -0
  155. package/src/Tabs/Tabs.module.scss +41 -0
  156. package/src/Tabs/Tabs.test.tsx +268 -0
  157. package/src/Tabs/Tabs.tsx +149 -0
  158. package/src/TextEllipsis/TextEllipsis.module.scss +18 -0
  159. package/src/TextEllipsis/TextEllipsis.test.tsx +80 -0
  160. package/src/TextEllipsis/TextEllipsis.tsx +55 -0
  161. package/src/Tiles/Tile.test.tsx +27 -1
  162. package/src/Tiles/Tile.tsx +59 -62
  163. package/src/Tiles/Tiles.test.tsx +27 -1
  164. package/src/Tiles/Tiles.tsx +42 -39
  165. package/src/Tooltip/Tooltip.test.tsx +27 -1
  166. package/src/Tooltip/Tooltip.tsx +104 -92
  167. package/src/Typography/Typography.test.tsx +27 -1
  168. package/src/Typography/Typography.tsx +66 -68
  169. package/src/Wizard/BaseWizardSteps/BaseWizardSteps.tsx +67 -62
  170. package/src/Wizard/WizardSteps/WizardSteps.tsx +24 -21
  171. package/src/_BaseStyling_/BaseStyling.tsx +19 -1
  172. package/src/hooks/useRepeater.test.tsx +139 -0
  173. package/src/hooks/useRepeater.ts +34 -0
  174. package/src/hooks/useSpacing.ts +1 -1
  175. package/src/hooks/useWrapper.ts +7 -2
  176. package/src/index.ts +12 -1
  177. package/src/interfaces.ts +2 -12
  178. package/src/util/helper.test.tsx +38 -1
  179. package/src/util/helper.tsx +21 -0
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useEffect, useRef } from 'react';
2
2
  import { ContextMenu, Props } from './ContextMenu';
3
3
  import { render, getByRole } from '@testing-library/react';
4
4
  import { Button } from '../Button/Button';
@@ -91,3 +91,29 @@ describe('ContextMenu should render', () => {
91
91
  console.error = err;
92
92
  });
93
93
  });
94
+
95
+ describe('ref should work', () => {
96
+ it('should give back the proper data prop, this also checks if the component propagates ...rest properly', () => {
97
+ const ExampleComponent = ({
98
+ propagateRef,
99
+ }: {
100
+ propagateRef?: (ref: React.RefObject<HTMLElement>) => void;
101
+ }) => {
102
+ const ref = useRef(null);
103
+
104
+ useEffect(() => {
105
+ if (ref.current) {
106
+ propagateRef && propagateRef(ref);
107
+ }
108
+ }, [ref]);
109
+
110
+ return <ContextMenu {...defaultParams} data-ref="testing" ref={ref} />;
111
+ };
112
+
113
+ const refCheck = (ref: React.RefObject<HTMLElement>) => {
114
+ expect(ref.current).toHaveAttribute('data-ref', 'testing');
115
+ };
116
+
117
+ render(<ExampleComponent propagateRef={refCheck} />);
118
+ });
119
+ });
@@ -1,4 +1,4 @@
1
- import React, { HTMLProps, ReactElement, useEffect, useRef, useState } from 'react';
1
+ import React, { ComponentPropsWithRef, ReactElement, useEffect, useRef, useState } from 'react';
2
2
  import { Props as ButtonProps } from '../Button/Button';
3
3
  import { Props as IconButtonProps } from '../Button/IconButton';
4
4
  import { Popover } from '../Popover/Popover';
@@ -8,7 +8,7 @@ import classes from './ContextMenu.module.scss';
8
8
  import { useBodyClick } from '../hooks/useBodyClick';
9
9
  import { createPortal } from 'react-dom';
10
10
 
11
- export interface Props extends HTMLProps<HTMLDivElement> {
11
+ export interface Props extends ComponentPropsWithRef<'div'> {
12
12
  trigger: ReactElement<ButtonProps> | ReactElement<IconButtonProps>;
13
13
  children: ReactElement<ContextMenuItemProps> | ReactElement<ContextMenuItemProps>[];
14
14
  placement?: Placement;
@@ -21,71 +21,76 @@ export interface Props extends HTMLProps<HTMLDivElement> {
21
21
  onClose?: () => void;
22
22
  }
23
23
 
24
- export const ContextMenu = ({
25
- trigger,
26
- children,
27
- id,
28
- show = false,
29
- onShow,
30
- onClose,
31
- placement = { horizontal: 'right', vertical: 'top' },
32
- offset = { top: 0, bottom: 0, left: 0, right: 0 },
33
- transformOrigin = { horizontal: 'left', vertical: 'top' },
34
- domRoot = document.body,
35
- ...rest
36
- }: Props) => {
37
- const anchorEl = useRef<HTMLButtonElement>(null);
38
- const [showContextMenu, setShowContextMenu] = useState(show);
24
+ export const ContextMenu = React.forwardRef<HTMLDivElement, Props>(
25
+ (
26
+ {
27
+ trigger,
28
+ children,
29
+ id,
30
+ show = false,
31
+ onShow,
32
+ onClose,
33
+ placement = { horizontal: 'right', vertical: 'top' },
34
+ offset = { top: 0, bottom: 0, left: 0, right: 0 },
35
+ transformOrigin = { horizontal: 'left', vertical: 'top' },
36
+ domRoot = document.body,
37
+ ...rest
38
+ }: Props,
39
+ ref
40
+ ) => {
41
+ const anchorEl = useRef<HTMLButtonElement>(null);
42
+ const [showContextMenu, setShowContextMenu] = useState(show);
39
43
 
40
- if (!id) {
41
- throw new Error('You need to provide an ID to the context menu');
42
- }
44
+ if (!id) {
45
+ throw new Error('You need to provide an ID to the context menu');
46
+ }
43
47
 
44
- useBodyClick(
45
- (event) => {
46
- return showContextMenu && anchorEl.current !== event.target;
47
- },
48
- () => {
49
- setShowContextMenu(false);
50
- },
51
- showContextMenu
52
- );
48
+ useBodyClick(
49
+ (event) => {
50
+ return showContextMenu && anchorEl.current !== event.target;
51
+ },
52
+ () => {
53
+ setShowContextMenu(false);
54
+ },
55
+ showContextMenu
56
+ );
53
57
 
54
- useEffect(() => {
55
- if (showContextMenu === true) {
56
- onShow && onShow();
57
- } else {
58
- onClose && onClose();
59
- }
60
- }, [showContextMenu]);
58
+ useEffect(() => {
59
+ if (showContextMenu === true) {
60
+ onShow && onShow();
61
+ } else {
62
+ onClose && onClose();
63
+ }
64
+ }, [showContextMenu]);
61
65
 
62
- const renderTrigger = () =>
63
- React.cloneElement(trigger, {
64
- id: id,
65
- ['aria-haspopup']: 'true',
66
- ['aria-controls']: `${id}-menu`,
67
- ['aria-expanded']: show,
68
- onClick: () => setShowContextMenu(!showContextMenu),
69
- ref: anchorEl,
70
- });
66
+ const renderTrigger = () =>
67
+ React.cloneElement(trigger, {
68
+ id: id,
69
+ 'aria-haspopup': 'true',
70
+ 'aria-controls': `${id}-menu`,
71
+ 'aria-expanded': show,
72
+ onClick: () => setShowContextMenu(!showContextMenu),
73
+ ref: anchorEl,
74
+ });
71
75
 
72
- return (
73
- <div {...rest} className={classes['context-menu']}>
74
- {renderTrigger()}
75
- {createPortal(
76
- <Popover
77
- placement={placement}
78
- transformOrigin={transformOrigin}
79
- offset={offset}
80
- anchorEl={anchorEl}
81
- show={showContextMenu}
82
- >
83
- <ul className={classes.menu} id={`${id}-menu`} aria-describedby={id} role="menu">
84
- {children}
85
- </ul>
86
- </Popover>,
87
- domRoot
88
- )}
89
- </div>
90
- );
91
- };
76
+ return (
77
+ <div {...rest} ref={ref} className={classes['context-menu']}>
78
+ {renderTrigger()}
79
+ {createPortal(
80
+ <Popover
81
+ placement={placement}
82
+ transformOrigin={transformOrigin}
83
+ offset={offset}
84
+ anchorEl={anchorEl}
85
+ show={showContextMenu}
86
+ >
87
+ <ul className={classes.menu} id={`${id}-menu`} aria-describedby={id} role="menu">
88
+ {children}
89
+ </ul>
90
+ </Popover>,
91
+ domRoot
92
+ )}
93
+ </div>
94
+ );
95
+ }
96
+ );
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useEffect, useRef } from 'react';
2
2
  import { Checkbox, CheckboxProps as Props } from './Checkbox';
3
3
  import { render } from '@testing-library/react';
4
4
  import userEvent from '@testing-library/user-event';
@@ -33,6 +33,32 @@ describe('Checkbox should render', () => {
33
33
  });
34
34
  });
35
35
 
36
+ describe('ref should work', () => {
37
+ it('should give back the proper data prop, this also checks if the component propagates ...rest properly', () => {
38
+ const ExampleComponent = ({
39
+ propagateRef,
40
+ }: {
41
+ propagateRef?: (ref: React.RefObject<HTMLElement>) => void;
42
+ }) => {
43
+ const ref = useRef(null);
44
+
45
+ useEffect(() => {
46
+ if (ref.current) {
47
+ propagateRef && propagateRef(ref);
48
+ }
49
+ }, [ref]);
50
+
51
+ return <Checkbox {...defaultParams} data-ref="testing" ref={ref} />;
52
+ };
53
+
54
+ const refCheck = (ref: React.RefObject<HTMLElement>) => {
55
+ expect(ref.current).toHaveAttribute('data-ref', 'testing');
56
+ };
57
+
58
+ render(<ExampleComponent propagateRef={refCheck} />);
59
+ });
60
+ });
61
+
36
62
  describe('Checkbox should have proper attributes', () => {
37
63
  it('should be unchecked', () => {
38
64
  const { checkbox } = createCheckbox();
@@ -75,7 +101,7 @@ describe('Checkbox should have proper attributes', () => {
75
101
  ...defaultParams,
76
102
  error: true,
77
103
  errorMessage: 'This is an error',
78
- wrapperProps: { 'data-testid': 'checkbox-wrapper' },
104
+ formSelectorWrapperProps: { 'data-testid': 'checkbox-wrapper' },
79
105
  }));
80
106
 
81
107
  expect(checkbox).toHaveAttribute(
@@ -1,150 +1,160 @@
1
- import React, { ReactElement, ReactNode, useEffect } from 'react';
1
+ import React, { ComponentPropsWithRef, ReactElement, ReactNode, useEffect } from 'react';
2
2
  import { Icon, Icons } from '../../Icon/Icon';
3
3
  import { Props as FormHelperTextProps } from '../FormHelperText/FormHelperText';
4
4
  import classes from './Checkbox.module.scss';
5
5
  import { useFormSelector } from '../../hooks/useFormSelector';
6
+ import {
7
+ FormSelectorWrapper,
8
+ Props as FormSelectorWrapperProps,
9
+ } from '../FormSelectorWrapper/FormSelectorWrapper';
6
10
  import { FormSelector } from '../form.interfaces';
7
- import { HTMLProps } from '../../interfaces';
8
- import { FormSelectorWrapper } from '../FormSelectorWrapper/FormSelectorWrapper';
9
11
 
10
12
  const isToggle = (children: ReactNode) => (children as ReactElement)?.props?.['data-toggle'];
11
13
 
12
- export interface CheckboxProps extends FormSelector<HTMLInputElement> {
14
+ export interface CheckboxProps extends ComponentPropsWithRef<'input'>, FormSelector {
13
15
  children: ReactNode;
14
16
  label?: string;
15
17
  indeterminate?: boolean;
16
18
  helperProps?: FormHelperTextProps;
17
- wrapperProps?: HTMLProps<HTMLDivElement>;
19
+ formSelectorWrapperProps?: FormSelectorWrapperProps;
18
20
  onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
19
21
  }
20
22
 
21
- export const Checkbox = ({
22
- children,
23
- name,
24
- helperText,
25
- helperProps,
26
- indeterminate,
27
- parentErrorId,
28
- errorMessage,
29
- disabled,
30
- label,
31
- parentHelperId,
32
- className,
33
- error,
34
- checked = false,
35
- wrapperProps,
36
- onChange,
37
- ...rest
38
- }: CheckboxProps) => {
39
- const { errorId, identifier, describedBy } = useFormSelector({
40
- name,
41
- helperText,
42
- parentErrorId,
43
- errorMessage,
44
- error,
45
- parentHelperId,
46
- });
23
+ export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
24
+ (
25
+ {
26
+ children,
27
+ name,
28
+ helperText,
29
+ helperProps,
30
+ indeterminate,
31
+ parentErrorId,
32
+ errorMessage,
33
+ disabled,
34
+ label,
35
+ parentHelperId,
36
+ className,
37
+ error,
38
+ checked = false,
39
+ formSelectorWrapperProps,
40
+ onChange,
41
+ ...rest
42
+ }: CheckboxProps,
43
+ ref
44
+ ) => {
45
+ const { errorId, identifier, describedBy } = useFormSelector({
46
+ name,
47
+ helperText,
48
+ parentErrorId,
49
+ errorMessage,
50
+ error,
51
+ parentHelperId,
52
+ });
47
53
 
48
- useEffect(() => {
49
- if (!name) {
50
- console.error("Please pass a 'name' prop to your <Checkbox> component.");
51
- }
54
+ useEffect(() => {
55
+ if (!name) {
56
+ console.error("Please pass a 'name' prop to your <Checkbox> component.");
57
+ }
52
58
 
53
- if (typeof children === 'object' && !isToggle(children) && indeterminate === undefined) {
54
- throw new Error(
55
- 'If you have nested checkboxes you have to manage the indeterminate state by passing a boolean to the `indeterminate` prop.'
56
- );
57
- }
58
- }, []);
59
+ if (typeof children === 'object' && !isToggle(children) && indeterminate === undefined) {
60
+ throw new Error(
61
+ 'If you have nested checkboxes you have to manage the indeterminate state by passing a boolean to the `indeterminate` prop.'
62
+ );
63
+ }
64
+ }, []);
65
+
66
+ const determineLabel = () => {
67
+ if (label) {
68
+ return label;
69
+ } else if (children === undefined) {
70
+ throw new Error(
71
+ 'Please make sure to pass either a string or more Checkbox components as a child of your Checkbox component.'
72
+ );
73
+ }
74
+
75
+ if (typeof children === 'string') {
76
+ return children;
77
+ }
59
78
 
60
- const determineLabel = () => {
61
- if (label) {
62
- return label;
63
- } else if (children === undefined) {
64
79
  throw new Error(
65
- 'Please make sure to pass either a string or more Checkbox components as a child of your Checkbox component.'
80
+ 'If you pass Checkboxes as a child component (to create nested checkbox tree) you need to pass a label to the parent checkbox.'
66
81
  );
67
- }
82
+ };
68
83
 
69
- if (typeof children === 'string') {
70
- return children;
71
- }
72
-
73
- throw new Error(
74
- 'If you pass Checkboxes as a child component (to create nested checkbox tree) you need to pass a label to the parent checkbox.'
84
+ const renderNestedCheckboxes = () => (
85
+ <ul className={classes['checkbox-list']}>
86
+ {React.Children.map(children as ReactNode[], (child) => {
87
+ return (
88
+ <li>
89
+ <Checkbox
90
+ {...(child as ReactElement).props}
91
+ parentHelperId={parentHelperId}
92
+ parentErrorId={parentErrorId}
93
+ error={error}
94
+ disabled={disabled ? disabled : (child as CheckboxProps).disabled}
95
+ >
96
+ {(child as ReactElement).props.children}
97
+ </Checkbox>
98
+ </li>
99
+ );
100
+ })}
101
+ </ul>
75
102
  );
76
- };
77
-
78
- const renderNestedCheckboxes = () => (
79
- <ul className={classes['checkbox-list']}>
80
- {React.Children.map(children as ReactNode[], (child) => {
81
- return (
82
- <li>
83
- <Checkbox
84
- {...(child as ReactElement).props}
85
- parentHelperId={parentHelperId}
86
- parentErrorId={parentErrorId}
87
- error={error}
88
- disabled={disabled ? disabled : (child as CheckboxProps).disabled}
89
- >
90
- {(child as ReactElement).props.children}
91
- </Checkbox>
92
- </li>
93
- );
94
- })}
95
- </ul>
96
- );
97
103
 
98
- const onChangeHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
99
- if (disabled) {
100
- return;
101
- }
102
- onChange && onChange(event);
103
- };
104
+ const onChangeHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
105
+ if (disabled) {
106
+ return;
107
+ }
108
+ onChange && onChange(event);
109
+ };
104
110
 
105
- const renderToggle = () => React.Children.toArray(children).filter(isToggle);
111
+ const renderToggle = () => React.Children.toArray(children).filter(isToggle);
106
112
 
107
- const iconClasses = [classes['input'], disabled ? classes['disabled'] : ''];
113
+ const iconClasses = [classes['input'], disabled ? classes['disabled'] : ''];
108
114
 
109
- /** Default return value is the default checkbox */
110
- return (
111
- <FormSelectorWrapper
112
- {...wrapperProps}
113
- className={`${classes['checkbox-wrapper']} ${className ? className : ''}`}
114
- containerProps={{ className: classes['checkbox-container'] }}
115
- helperText={helperText}
116
- helperProps={helperProps}
117
- parentErrorId={parentErrorId}
118
- errorId={errorId}
119
- errorMessage={errorMessage}
120
- error={error}
121
- disabled={disabled}
122
- identifier={identifier}
123
- nestedChildren={
124
- typeof children === 'object' && !isToggle(children) && renderNestedCheckboxes()
125
- }
126
- >
127
- <input
128
- {...rest}
115
+ /** Default return value is the default checkbox */
116
+ return (
117
+ <FormSelectorWrapper
118
+ {...formSelectorWrapperProps}
119
+ className={`${classes['checkbox-wrapper']} ${className ? className : ''}`}
120
+ containerProps={{ className: classes['checkbox-container'] }}
121
+ helperText={helperText}
122
+ helperProps={helperProps}
123
+ parentErrorId={parentErrorId}
124
+ errorId={errorId}
125
+ errorMessage={errorMessage}
126
+ error={error}
129
127
  disabled={disabled}
130
- className={`${classes['native-input']} ${error ? classes['error'] : ''}`}
131
- checked={checked}
132
- onChange={onChangeHandler}
133
- aria-invalid={error as boolean}
134
- aria-checked={indeterminate ? 'mixed' : checked}
135
- aria-describedby={describedBy}
136
- id={`${identifier}-checkbox`}
137
- name={name}
138
- type="checkbox"
139
- />
140
- {renderToggle()}
128
+ identifier={identifier}
129
+ nestedChildren={
130
+ typeof children === 'object' && !isToggle(children) && renderNestedCheckboxes()
131
+ }
132
+ >
133
+ <input
134
+ {...rest}
135
+ ref={ref}
136
+ disabled={disabled}
137
+ className={`${classes['native-input']} ${error ? classes['error'] : ''}`}
138
+ checked={checked}
139
+ onChange={onChangeHandler}
140
+ aria-invalid={error as boolean}
141
+ aria-checked={indeterminate ? 'mixed' : checked}
142
+ aria-describedby={describedBy}
143
+ id={`${identifier}-checkbox`}
144
+ name={name}
145
+ type="checkbox"
146
+ />
147
+ {renderToggle()}
141
148
 
142
- {indeterminate && <Icon className={iconClasses.join(' ')} icon={Icons.MinusSquare} />}
143
- {checked && !indeterminate && (
144
- <Icon className={iconClasses.join(' ')} icon={Icons.CheckmarkSquare} />
145
- )}
146
- {!checked && !indeterminate && <Icon className={iconClasses.join(' ')} icon={Icons.Square} />}
147
- <label htmlFor={`${identifier}-checkbox`}>{determineLabel()}</label>
148
- </FormSelectorWrapper>
149
- );
150
- };
149
+ {indeterminate && <Icon className={iconClasses.join(' ')} icon={Icons.MinusSquare} />}
150
+ {checked && !indeterminate && (
151
+ <Icon className={iconClasses.join(' ')} icon={Icons.CheckmarkSquare} />
152
+ )}
153
+ {!checked && !indeterminate && (
154
+ <Icon className={iconClasses.join(' ')} icon={Icons.Square} />
155
+ )}
156
+ <label htmlFor={`${identifier}-checkbox`}>{determineLabel()}</label>
157
+ </FormSelectorWrapper>
158
+ );
159
+ }
160
+ );
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useEffect, useRef } from 'react';
2
2
  import { Fieldset, Props } from './Fieldset';
3
3
  import { render } from '@testing-library/react';
4
4
  import { FormControl } from '../FormControl/FormControl';
@@ -14,7 +14,7 @@ const defaultParams: Props = {
14
14
  <Input placeholder="This is a placeholder" name="example" type="text" />
15
15
  </FormControl>,
16
16
  <FormControl data-testid="form-control">
17
- <Select value="placeholder" onChange={jest.fn}>
17
+ <Select name="Example select" value="placeholder" onChange={jest.fn}>
18
18
  <Option value="option1">Option1</Option>
19
19
  <Option value="option2">Option2</Option>
20
20
  <Option value="option3">Option3</Option>
@@ -45,6 +45,32 @@ describe('Fieldset should render', () => {
45
45
  });
46
46
  });
47
47
 
48
+ describe('ref should work', () => {
49
+ it('should give back the proper data prop, this also checks if the component propagates ...rest properly', () => {
50
+ const ExampleComponent = ({
51
+ propagateRef,
52
+ }: {
53
+ propagateRef?: (ref: React.RefObject<HTMLElement>) => void;
54
+ }) => {
55
+ const ref = useRef(null);
56
+
57
+ useEffect(() => {
58
+ if (ref.current) {
59
+ propagateRef && propagateRef(ref);
60
+ }
61
+ }, [ref]);
62
+
63
+ return <Fieldset {...defaultParams} data-ref="testing" ref={ref} />;
64
+ };
65
+
66
+ const refCheck = (ref: React.RefObject<HTMLElement>) => {
67
+ expect(ref.current).toHaveAttribute('data-ref', 'testing');
68
+ };
69
+
70
+ render(<ExampleComponent propagateRef={refCheck} />);
71
+ });
72
+ });
73
+
48
74
  describe('Fieldset should get proper attributes and classes', () => {
49
75
  it('has no padding class', () => {
50
76
  const { fieldset } = createFieldset((defaultParams) => ({ ...defaultParams, noPadding: true }));