@onewelcome/react-lib-components 0.1.1-alpha → 0.1.4-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.
- package/README.md +16 -1
- package/dist/Breadcrumbs/Breadcrumbs.d.ts +3 -3
- package/dist/Button/BaseButton.d.ts +3 -4
- package/dist/Button/Button.d.ts +3 -4
- package/dist/Button/IconButton.d.ts +3 -4
- package/dist/ContextMenu/ContextMenu.d.ts +3 -3
- package/dist/Form/Checkbox/Checkbox.d.ts +5 -5
- package/dist/Form/Fieldset/Fieldset.d.ts +4 -4
- package/dist/Form/FormControl/FormControl.d.ts +5 -5
- package/dist/Form/FormGroup/FormGroup.d.ts +4 -4
- package/dist/Form/FormHelperText/FormHelperText.d.ts +4 -5
- package/dist/Form/FormSelectorWrapper/FormSelectorWrapper.d.ts +8 -12
- package/dist/Form/Input/Input.d.ts +7 -6
- package/dist/Form/Label/Label.d.ts +4 -5
- package/dist/Form/Radio/Radio.d.ts +5 -5
- package/dist/Form/Select/Option.d.ts +3 -4
- package/dist/Form/Select/Select.d.ts +4 -4
- package/dist/Form/Textarea/Textarea.d.ts +9 -5
- package/dist/Form/Toggle/Toggle.d.ts +3 -3
- package/dist/Form/Wrapper/CheckboxWrapper/CheckboxWrapper.d.ts +4 -3
- package/dist/Form/Wrapper/InputWrapper/InputWrapper.d.ts +5 -5
- package/dist/Form/Wrapper/RadioWrapper/RadioWrapper.d.ts +4 -4
- package/dist/Form/Wrapper/SelectWrapper/SelectWrapper.d.ts +7 -4
- package/dist/Form/Wrapper/TextareaWrapper/TextareaWrapper.d.ts +3 -3
- package/dist/Form/Wrapper/Wrapper/Wrapper.d.ts +6 -6
- package/dist/Form/form.interfaces.d.ts +4 -3
- package/dist/Icon/Icon.d.ts +4 -4
- package/dist/Link/Link.d.ts +4 -6
- package/dist/Notifications/BaseModal/BaseModal.d.ts +3 -4
- package/dist/Notifications/BaseModal/BaseModalActions/BaseModalActions.d.ts +3 -3
- package/dist/Notifications/BaseModal/BaseModalContent/BaseModalContent.d.ts +3 -3
- package/dist/Notifications/BaseModal/BaseModalHeader/BaseModalHeader.d.ts +3 -3
- package/dist/Notifications/Dialog/Dialog.d.ts +3 -3
- package/dist/Notifications/Dialog/DialogActions/DialogActions.d.ts +3 -3
- package/dist/Notifications/Dialog/DialogTitle/DialogTitle.d.ts +3 -3
- package/dist/Notifications/DiscardChangesModal/DiscardChangesDialog/DiscardChangesDialog.d.ts +5 -4
- package/dist/Notifications/DiscardChangesModal/DiscardChangesModal.d.ts +3 -1
- package/dist/Pagination/Pagination.d.ts +19 -0
- package/dist/Popover/Popover.d.ts +3 -3
- package/dist/Tabs/Tab.d.ts +11 -0
- package/dist/Tabs/TabButton.d.ts +10 -0
- package/dist/Tabs/TabPanel.d.ts +8 -0
- package/dist/Tabs/Tabs.d.ts +9 -0
- package/dist/TextEllipsis/TextEllipsis.d.ts +6 -0
- package/dist/Tiles/Tile.d.ts +3 -3
- package/dist/Tiles/Tiles.d.ts +3 -3
- package/dist/Tooltip/Tooltip.d.ts +3 -3
- package/dist/Typography/Typography.d.ts +6 -4
- package/dist/Wizard/BaseWizardSteps/BaseWizardSteps.d.ts +3 -3
- package/dist/Wizard/WizardSteps/WizardSteps.d.ts +3 -3
- package/dist/_BaseStyling_/BaseStyling.d.ts +9 -0
- package/dist/hooks/useRepeater.d.ts +10 -0
- package/dist/hooks/useSpacing.d.ts +2 -2
- package/dist/hooks/useWrapper.d.ts +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/interfaces.d.ts +2 -11
- package/dist/react-lib-components.cjs.development.js +2395 -1696
- package/dist/react-lib-components.cjs.development.js.map +1 -1
- package/dist/react-lib-components.cjs.production.min.js +1 -1
- package/dist/react-lib-components.cjs.production.min.js.map +1 -1
- package/dist/react-lib-components.esm.js +2391 -1698
- package/dist/react-lib-components.esm.js.map +1 -1
- package/dist/util/helper.d.ts +6 -1
- package/package.json +30 -24
- package/src/Breadcrumbs/Breadcrumbs.tsx +39 -37
- package/src/Button/BaseButton.test.tsx +65 -19
- package/src/Button/BaseButton.tsx +2 -3
- package/src/Button/Button.test.tsx +63 -17
- package/src/Button/Button.tsx +15 -4
- package/src/Button/IconButton.test.tsx +57 -22
- package/src/Button/IconButton.tsx +14 -9
- package/src/ContextMenu/ContextMenu.test.tsx +27 -1
- package/src/ContextMenu/ContextMenu.tsx +70 -65
- package/src/Form/Checkbox/Checkbox.test.tsx +28 -2
- package/src/Form/Checkbox/Checkbox.tsx +132 -122
- package/src/Form/Fieldset/Fieldset.test.tsx +28 -2
- package/src/Form/Fieldset/Fieldset.tsx +96 -50
- package/src/Form/FormControl/FormControl.test.tsx +27 -1
- package/src/Form/FormControl/FormControl.tsx +36 -39
- package/src/Form/FormGroup/FormGroup.test.tsx +51 -1
- package/src/Form/FormGroup/FormGroup.tsx +64 -58
- package/src/Form/FormHelperText/FormHelperText.test.tsx +27 -1
- package/src/Form/FormHelperText/FormHelperText.tsx +20 -16
- package/src/Form/FormSelectorWrapper/FormSelectorWrapper.test.tsx +78 -0
- package/src/Form/FormSelectorWrapper/FormSelectorWrapper.tsx +61 -55
- package/src/Form/Input/Input.module.scss +34 -15
- package/src/Form/Input/Input.test.tsx +27 -1
- package/src/Form/Input/Input.tsx +88 -47
- package/src/Form/Label/Label.test.tsx +27 -1
- package/src/Form/Label/Label.tsx +18 -14
- package/src/Form/Radio/Radio.test.tsx +28 -2
- package/src/Form/Radio/Radio.tsx +98 -90
- package/src/Form/Select/Option.test.tsx +27 -1
- package/src/Form/Select/Option.tsx +49 -42
- package/src/Form/Select/Select.module.scss +5 -1
- package/src/Form/Select/Select.test.tsx +224 -30
- package/src/Form/Select/Select.tsx +248 -182
- package/src/Form/Textarea/Textarea.module.scss +2 -1
- package/src/Form/Textarea/Textarea.test.tsx +28 -2
- package/src/Form/Textarea/Textarea.tsx +44 -29
- package/src/Form/Toggle/Toggle.module.scss +9 -0
- package/src/Form/Toggle/Toggle.test.tsx +27 -1
- package/src/Form/Toggle/Toggle.tsx +25 -12
- package/src/Form/Wrapper/CheckboxWrapper/CheckboxWrapper.test.tsx +27 -1
- package/src/Form/Wrapper/CheckboxWrapper/CheckboxWrapper.tsx +45 -48
- package/src/Form/Wrapper/InputWrapper/InputWrapper.module.scss +17 -1
- package/src/Form/Wrapper/InputWrapper/InputWrapper.test.tsx +89 -1
- package/src/Form/Wrapper/InputWrapper/InputWrapper.tsx +134 -74
- package/src/Form/Wrapper/RadioWrapper/RadioWrapper.tsx +64 -59
- package/src/Form/Wrapper/SelectWrapper/SelectWrapper.module.scss +1 -1
- package/src/Form/Wrapper/SelectWrapper/SelectWrapper.test.tsx +43 -1
- package/src/Form/Wrapper/SelectWrapper/SelectWrapper.tsx +54 -44
- package/src/Form/Wrapper/TextareaWrapper/TextareaWrapper.module.scss +5 -7
- package/src/Form/Wrapper/TextareaWrapper/TextareaWrapper.test.tsx +43 -1
- package/src/Form/Wrapper/TextareaWrapper/TextareaWrapper.tsx +100 -85
- package/src/Form/Wrapper/Wrapper/Wrapper.module.scss +1 -1
- package/src/Form/Wrapper/Wrapper/Wrapper.test.tsx +27 -1
- package/src/Form/Wrapper/Wrapper/Wrapper.tsx +76 -71
- package/src/Form/form.interfaces.ts +4 -3
- package/src/Icon/Icon.module.scss +4 -0
- package/src/Icon/Icon.test.tsx +30 -2
- package/src/Icon/Icon.tsx +5 -5
- package/src/Link/Link.test.tsx +27 -1
- package/src/Link/Link.tsx +10 -7
- package/src/Notifications/BaseModal/BaseModal.test.tsx +27 -1
- package/src/Notifications/BaseModal/BaseModal.tsx +59 -54
- package/src/Notifications/BaseModal/BaseModalActions/BaseModalActions.test.tsx +26 -1
- package/src/Notifications/BaseModal/BaseModalActions/BaseModalActions.tsx +11 -9
- package/src/Notifications/BaseModal/BaseModalContent/BaseModalContent.test.tsx +27 -1
- package/src/Notifications/BaseModal/BaseModalContent/BaseModalContent.tsx +27 -26
- package/src/Notifications/BaseModal/BaseModalHeader/BaseModalHeader.test.tsx +29 -1
- package/src/Notifications/BaseModal/BaseModalHeader/BaseModalHeader.tsx +18 -16
- package/src/Notifications/Dialog/Dialog.test.tsx +39 -1
- package/src/Notifications/Dialog/Dialog.tsx +84 -78
- package/src/Notifications/Dialog/DialogActions/DialogActions.test.tsx +27 -1
- package/src/Notifications/Dialog/DialogActions/DialogActions.tsx +15 -12
- package/src/Notifications/Dialog/DialogTitle/DialogTitle.test.tsx +28 -2
- package/src/Notifications/Dialog/DialogTitle/DialogTitle.tsx +13 -11
- package/src/Notifications/DiscardChangesModal/DiscardChangesDialog/DiscardChangesDialog.test.tsx +41 -1
- package/src/Notifications/DiscardChangesModal/DiscardChangesDialog/DiscardChangesDialog.tsx +43 -36
- package/src/Notifications/DiscardChangesModal/DiscardChangesModal.test.tsx +52 -1
- package/src/Notifications/DiscardChangesModal/DiscardChangesModal.tsx +8 -3
- package/src/Notifications/Snackbar/SnackbarItem/SnackbarItem.tsx +1 -1
- package/src/Pagination/Pagination.module.scss +120 -0
- package/src/Pagination/Pagination.test.tsx +176 -0
- package/src/Pagination/Pagination.tsx +205 -0
- package/src/Popover/Popover.tsx +3 -3
- package/src/Tabs/Tab.test.tsx +71 -0
- package/src/Tabs/Tab.tsx +17 -0
- package/src/Tabs/TabButton.module.scss +36 -0
- package/src/Tabs/TabButton.test.tsx +77 -0
- package/src/Tabs/TabButton.tsx +58 -0
- package/src/Tabs/TabPanel.module.scss +7 -0
- package/src/Tabs/TabPanel.test.tsx +76 -0
- package/src/Tabs/TabPanel.tsx +27 -0
- package/src/Tabs/Tabs.module.scss +41 -0
- package/src/Tabs/Tabs.test.tsx +268 -0
- package/src/Tabs/Tabs.tsx +149 -0
- package/src/TextEllipsis/TextEllipsis.module.scss +18 -0
- package/src/TextEllipsis/TextEllipsis.test.tsx +80 -0
- package/src/TextEllipsis/TextEllipsis.tsx +55 -0
- package/src/Tiles/Tile.test.tsx +27 -1
- package/src/Tiles/Tile.tsx +59 -62
- package/src/Tiles/Tiles.test.tsx +27 -1
- package/src/Tiles/Tiles.tsx +42 -39
- package/src/Tooltip/Tooltip.test.tsx +27 -1
- package/src/Tooltip/Tooltip.tsx +104 -92
- package/src/Typography/Typography.test.tsx +27 -1
- package/src/Typography/Typography.tsx +66 -68
- package/src/Wizard/BaseWizardSteps/BaseWizardSteps.tsx +67 -62
- package/src/Wizard/WizardSteps/WizardSteps.tsx +24 -21
- package/src/_BaseStyling_/BaseStyling.tsx +19 -1
- package/src/hooks/useRepeater.test.tsx +139 -0
- package/src/hooks/useRepeater.ts +34 -0
- package/src/hooks/useSpacing.ts +1 -1
- package/src/hooks/useWrapper.ts +7 -2
- package/src/index.ts +15 -1
- package/src/interfaces.ts +2 -12
- package/src/util/helper.test.tsx +38 -1
- 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, {
|
|
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
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
if (!id) {
|
|
45
|
+
throw new Error('You need to provide an ID to the context menu');
|
|
46
|
+
}
|
|
43
47
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
useBodyClick(
|
|
49
|
+
(event) => {
|
|
50
|
+
return showContextMenu && anchorEl.current !== event.target;
|
|
51
|
+
},
|
|
52
|
+
() => {
|
|
53
|
+
setShowContextMenu(false);
|
|
54
|
+
},
|
|
55
|
+
showContextMenu
|
|
56
|
+
);
|
|
53
57
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (showContextMenu === true) {
|
|
60
|
+
onShow && onShow();
|
|
61
|
+
} else {
|
|
62
|
+
onClose && onClose();
|
|
63
|
+
}
|
|
64
|
+
}, [showContextMenu]);
|
|
61
65
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
19
|
+
formSelectorWrapperProps?: FormSelectorWrapperProps;
|
|
18
20
|
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
export const Checkbox = (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
if (!name) {
|
|
56
|
+
console.error("Please pass a 'name' prop to your <Checkbox> component.");
|
|
57
|
+
}
|
|
52
58
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
'
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
const onChangeHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
105
|
+
if (disabled) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
onChange && onChange(event);
|
|
109
|
+
};
|
|
104
110
|
|
|
105
|
-
|
|
111
|
+
const renderToggle = () => React.Children.toArray(children).filter(isToggle);
|
|
106
112
|
|
|
107
|
-
|
|
113
|
+
const iconClasses = [classes['input'], disabled ? classes['disabled'] : ''];
|
|
108
114
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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 }));
|