@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.
Files changed (180) 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 +4 -6
  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 +6 -0
  56. package/dist/interfaces.d.ts +2 -11
  57. package/dist/react-lib-components.cjs.development.js +2395 -1696
  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 +2391 -1698
  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 +51 -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 +61 -55
  86. package/src/Form/Input/Input.module.scss +34 -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 +17 -1
  107. package/src/Form/Wrapper/InputWrapper/InputWrapper.test.tsx +89 -1
  108. package/src/Form/Wrapper/InputWrapper/InputWrapper.tsx +134 -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 +5 -7
  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.module.scss +1 -1
  117. package/src/Form/Wrapper/Wrapper/Wrapper.test.tsx +27 -1
  118. package/src/Form/Wrapper/Wrapper/Wrapper.tsx +76 -71
  119. package/src/Form/form.interfaces.ts +4 -3
  120. package/src/Icon/Icon.module.scss +4 -0
  121. package/src/Icon/Icon.test.tsx +30 -2
  122. package/src/Icon/Icon.tsx +5 -5
  123. package/src/Link/Link.test.tsx +27 -1
  124. package/src/Link/Link.tsx +10 -7
  125. package/src/Notifications/BaseModal/BaseModal.test.tsx +27 -1
  126. package/src/Notifications/BaseModal/BaseModal.tsx +59 -54
  127. package/src/Notifications/BaseModal/BaseModalActions/BaseModalActions.test.tsx +26 -1
  128. package/src/Notifications/BaseModal/BaseModalActions/BaseModalActions.tsx +11 -9
  129. package/src/Notifications/BaseModal/BaseModalContent/BaseModalContent.test.tsx +27 -1
  130. package/src/Notifications/BaseModal/BaseModalContent/BaseModalContent.tsx +27 -26
  131. package/src/Notifications/BaseModal/BaseModalHeader/BaseModalHeader.test.tsx +29 -1
  132. package/src/Notifications/BaseModal/BaseModalHeader/BaseModalHeader.tsx +18 -16
  133. package/src/Notifications/Dialog/Dialog.test.tsx +39 -1
  134. package/src/Notifications/Dialog/Dialog.tsx +84 -78
  135. package/src/Notifications/Dialog/DialogActions/DialogActions.test.tsx +27 -1
  136. package/src/Notifications/Dialog/DialogActions/DialogActions.tsx +15 -12
  137. package/src/Notifications/Dialog/DialogTitle/DialogTitle.test.tsx +28 -2
  138. package/src/Notifications/Dialog/DialogTitle/DialogTitle.tsx +13 -11
  139. package/src/Notifications/DiscardChangesModal/DiscardChangesDialog/DiscardChangesDialog.test.tsx +41 -1
  140. package/src/Notifications/DiscardChangesModal/DiscardChangesDialog/DiscardChangesDialog.tsx +43 -36
  141. package/src/Notifications/DiscardChangesModal/DiscardChangesModal.test.tsx +52 -1
  142. package/src/Notifications/DiscardChangesModal/DiscardChangesModal.tsx +8 -3
  143. package/src/Notifications/Snackbar/SnackbarItem/SnackbarItem.tsx +1 -1
  144. package/src/Pagination/Pagination.module.scss +120 -0
  145. package/src/Pagination/Pagination.test.tsx +176 -0
  146. package/src/Pagination/Pagination.tsx +205 -0
  147. package/src/Popover/Popover.tsx +3 -3
  148. package/src/Tabs/Tab.test.tsx +71 -0
  149. package/src/Tabs/Tab.tsx +17 -0
  150. package/src/Tabs/TabButton.module.scss +36 -0
  151. package/src/Tabs/TabButton.test.tsx +77 -0
  152. package/src/Tabs/TabButton.tsx +58 -0
  153. package/src/Tabs/TabPanel.module.scss +7 -0
  154. package/src/Tabs/TabPanel.test.tsx +76 -0
  155. package/src/Tabs/TabPanel.tsx +27 -0
  156. package/src/Tabs/Tabs.module.scss +41 -0
  157. package/src/Tabs/Tabs.test.tsx +268 -0
  158. package/src/Tabs/Tabs.tsx +149 -0
  159. package/src/TextEllipsis/TextEllipsis.module.scss +18 -0
  160. package/src/TextEllipsis/TextEllipsis.test.tsx +80 -0
  161. package/src/TextEllipsis/TextEllipsis.tsx +55 -0
  162. package/src/Tiles/Tile.test.tsx +27 -1
  163. package/src/Tiles/Tile.tsx +59 -62
  164. package/src/Tiles/Tiles.test.tsx +27 -1
  165. package/src/Tiles/Tiles.tsx +42 -39
  166. package/src/Tooltip/Tooltip.test.tsx +27 -1
  167. package/src/Tooltip/Tooltip.tsx +104 -92
  168. package/src/Typography/Typography.test.tsx +27 -1
  169. package/src/Typography/Typography.tsx +66 -68
  170. package/src/Wizard/BaseWizardSteps/BaseWizardSteps.tsx +67 -62
  171. package/src/Wizard/WizardSteps/WizardSteps.tsx +24 -21
  172. package/src/_BaseStyling_/BaseStyling.tsx +19 -1
  173. package/src/hooks/useRepeater.test.tsx +139 -0
  174. package/src/hooks/useRepeater.ts +34 -0
  175. package/src/hooks/useSpacing.ts +1 -1
  176. package/src/hooks/useWrapper.ts +7 -2
  177. package/src/index.ts +15 -1
  178. package/src/interfaces.ts +2 -12
  179. package/src/util/helper.test.tsx +38 -1
  180. package/src/util/helper.tsx +21 -0
@@ -1,35 +1,36 @@
1
- import React, { HTMLAttributes, useEffect, useRef } from 'react';
1
+ import React, { ComponentPropsWithRef, createRef, useEffect } from 'react';
2
2
  import classes from './BaseModalContent.module.scss';
3
3
 
4
- export interface Props extends HTMLAttributes<HTMLDivElement> {
4
+ export interface Props extends ComponentPropsWithRef<'div'> {
5
5
  id?: string;
6
6
  children: React.ReactNode;
7
7
  className?: string;
8
8
  disableAutoFocus?: boolean;
9
9
  }
10
10
 
11
- export const BaseModalContent = ({
12
- id,
13
- children,
14
- className = '',
15
- disableAutoFocus = false,
16
- ...restProps
17
- }: Props) => {
18
- const contentRef = useRef<HTMLDivElement>(null);
19
- useEffect(() => {
20
- !disableAutoFocus && contentRef.current?.focus();
21
- }, []);
11
+ export const BaseModalContent = React.forwardRef<HTMLDivElement, Props>(
12
+ ({ id, children, className = '', disableAutoFocus = false, ...rest }: Props, ref) => {
13
+ const contentRef = createRef<HTMLDivElement>();
22
14
 
23
- /**tabIndex is set to be able to do focus on that element which we need for catching keyDown events */
24
- return (
25
- <div
26
- {...restProps}
27
- ref={contentRef}
28
- id={id}
29
- className={`${classes['content']} ${className}`}
30
- tabIndex={-1}
31
- >
32
- {children}
33
- </div>
34
- );
35
- };
15
+ useEffect(() => {
16
+ if (!disableAutoFocus && ref) {
17
+ (ref as React.RefObject<HTMLDivElement>).current?.focus();
18
+ } else if (!disableAutoFocus) {
19
+ contentRef.current?.focus();
20
+ }
21
+ }, []);
22
+
23
+ /**tabIndex is set to be able to do focus on that element which we need for catching keyDown events */
24
+ return (
25
+ <div
26
+ {...rest}
27
+ ref={ref || contentRef}
28
+ id={id}
29
+ className={`${classes['content']} ${className}`}
30
+ tabIndex={-1}
31
+ >
32
+ {children}
33
+ </div>
34
+ );
35
+ }
36
+ );
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useEffect, useRef } from 'react';
2
2
  import { BaseModalHeader, Props } from './BaseModalHeader';
3
3
  import { render, getByRole, getByTestId, getByText } from '@testing-library/react';
4
4
  import { labelId } from '../BaseModalContext';
@@ -28,3 +28,31 @@ describe('BaseModalHeader', () => {
28
28
  expect(initParams.onClose).toBeCalledTimes(1);
29
29
  });
30
30
  });
31
+
32
+ describe('ref should work', () => {
33
+ it('should give back the proper data prop, this also checks if the component propagates ...rest properly', () => {
34
+ const ExampleComponent = ({
35
+ propagateRef,
36
+ }: {
37
+ propagateRef?: (ref: React.RefObject<HTMLElement>) => void;
38
+ }) => {
39
+ const ref = useRef(null);
40
+
41
+ useEffect(() => {
42
+ if (ref.current) {
43
+ propagateRef && propagateRef(ref);
44
+ }
45
+ }, [ref]);
46
+
47
+ return (
48
+ <BaseModalHeader id="test" title="test" onClose={jest.fn()} data-ref="testing" ref={ref} />
49
+ );
50
+ };
51
+
52
+ const refCheck = (ref: React.RefObject<HTMLElement>) => {
53
+ expect(ref.current).toHaveAttribute('data-ref', 'testing');
54
+ };
55
+
56
+ render(<ExampleComponent propagateRef={refCheck} />);
57
+ });
58
+ });
@@ -1,28 +1,30 @@
1
- import React, { HTMLAttributes } from 'react';
1
+ import React, { ComponentPropsWithRef } from 'react';
2
2
  import classes from './BaseModalHeader.module.scss';
3
3
  import { IconButton } from '../../../Button/IconButton';
4
4
  import { Icon, Icons } from '../../../Icon/Icon';
5
5
  import { Typography } from '../../../Typography/Typography';
6
6
 
7
- export interface Props extends HTMLAttributes<HTMLDivElement> {
7
+ export interface Props extends ComponentPropsWithRef<'div'> {
8
8
  id: string;
9
9
  title: string;
10
10
  children?: React.ReactNode;
11
11
  onClose: (event: React.MouseEvent<HTMLButtonElement>) => void;
12
12
  }
13
13
 
14
- export const BaseModalHeader = ({ id, title, children, onClose, ...restProps }: Props) => {
15
- return (
16
- <div {...restProps} className={classes['header']}>
17
- <div className={classes['headline']}>
18
- <Typography id={id} className={classes['title']} tag="h1" variant="h4">
19
- {title}
20
- </Typography>
21
- <IconButton onClick={onClose} className={classes['closeBtn']} title="close modal">
22
- <Icon icon={Icons.Times} />
23
- </IconButton>
14
+ export const BaseModalHeader = React.forwardRef<HTMLDivElement, Props>(
15
+ ({ id, title, children, onClose, ...rest }: Props, ref) => {
16
+ return (
17
+ <div {...rest} ref={ref} className={classes['header']}>
18
+ <div className={classes['headline']}>
19
+ <Typography id={id} className={classes['title']} tag="h1" variant="h4">
20
+ {title}
21
+ </Typography>
22
+ <IconButton onClick={onClose} className={classes['closeBtn']} title="close modal">
23
+ <Icon icon={Icons.Times} />
24
+ </IconButton>
25
+ </div>
26
+ {children}
24
27
  </div>
25
- {children}
26
- </div>
27
- );
28
- };
28
+ );
29
+ }
30
+ );
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useEffect, useRef } from 'react';
2
2
  import { Dialog, Props } from './Dialog';
3
3
  import { render, getAllByRole } from '@testing-library/react';
4
4
  import userEvent from '@testing-library/user-event';
@@ -74,3 +74,41 @@ describe('Dialog', () => {
74
74
  expect(initParams.secondaryAction?.onClick).toHaveBeenCalledTimes(1);
75
75
  });
76
76
  });
77
+
78
+ describe('ref should work', () => {
79
+ it('should give back the proper data prop, this also checks if the component propagates ...rest properly', () => {
80
+ const ExampleComponent = ({
81
+ propagateRef,
82
+ }: {
83
+ propagateRef?: (ref: React.RefObject<HTMLElement>) => void;
84
+ }) => {
85
+ const ref = useRef(null);
86
+
87
+ useEffect(() => {
88
+ if (ref.current) {
89
+ propagateRef && propagateRef(ref);
90
+ }
91
+ }, [ref]);
92
+
93
+ return (
94
+ <Dialog
95
+ children="test"
96
+ open={false}
97
+ alignActions={'left'}
98
+ onClose={jest.fn()}
99
+ primaryAction={{ label: 'test', onClick: jest.fn() }}
100
+ title="test"
101
+ id="test"
102
+ data-ref="testing"
103
+ ref={ref}
104
+ />
105
+ );
106
+ };
107
+
108
+ const refCheck = (ref: React.RefObject<HTMLElement>) => {
109
+ expect(ref.current).toHaveAttribute('data-ref', 'testing');
110
+ };
111
+
112
+ render(<ExampleComponent propagateRef={refCheck} />);
113
+ });
114
+ });
@@ -1,4 +1,4 @@
1
- import React, { HTMLAttributes, useState } from 'react';
1
+ import React, { ComponentPropsWithRef, useState } from 'react';
2
2
  import { BaseModal } from '../BaseModal/BaseModal';
3
3
  import { BaseModalContent } from '../BaseModal/BaseModalContent/BaseModalContent';
4
4
  import { DialogActions } from './DialogActions/DialogActions';
@@ -8,7 +8,7 @@ import { Button, Props as ButtonProps } from '../../Button/Button';
8
8
  import { labelId, descriptionId } from '../BaseModal/BaseModalContext';
9
9
  import { generateID } from '../../util/helper';
10
10
 
11
- export interface Props extends HTMLAttributes<HTMLDivElement> {
11
+ export interface Props extends ComponentPropsWithRef<'div'> {
12
12
  id?: string;
13
13
  open: boolean;
14
14
  children: React.ReactNode;
@@ -26,82 +26,88 @@ export interface Action extends Omit<ButtonProps, 'variant' | 'ref'> {
26
26
  onClick: (event?: React.MouseEvent<HTMLButtonElement>) => unknown;
27
27
  }
28
28
 
29
- export const Dialog = ({
30
- id,
31
- open,
32
- children,
33
- alignActions,
34
- onClose,
35
- title,
36
- primaryAction,
37
- secondaryAction,
38
- zIndex,
39
- disableEscapeKeyDown = true,
40
- ...restProps
41
- }: Props) => {
42
- const [dialogId] = useState(id ?? generateID(20));
43
- const { label: primaryLabel, ...restOfPrimaryAction } = primaryAction;
44
- const PrimaryButton = (
45
- <Button key="primary" {...restOfPrimaryAction}>
46
- {primaryLabel}
47
- </Button>
48
- );
49
- const TertiaryButton =
50
- secondaryAction &&
51
- (function () {
52
- const { label: secondaryLabel, ...restOfSecondaryAction } = secondaryAction;
53
- return (
54
- <Button key="tertiary" variant="text" {...restOfSecondaryAction}>
55
- {secondaryLabel}
56
- </Button>
57
- );
58
- })();
29
+ export const Dialog = React.forwardRef<HTMLDivElement, Props>(
30
+ (
31
+ {
32
+ id,
33
+ open,
34
+ children,
35
+ alignActions,
36
+ onClose,
37
+ title,
38
+ primaryAction,
39
+ secondaryAction,
40
+ zIndex,
41
+ disableEscapeKeyDown = true,
42
+ ...rest
43
+ }: Props,
44
+ ref
45
+ ) => {
46
+ const [dialogId] = useState(id ?? generateID(20));
47
+ const { label: primaryLabel, ...restOfPrimaryAction } = primaryAction;
48
+ const PrimaryButton = (
49
+ <Button key="primary" {...restOfPrimaryAction}>
50
+ {primaryLabel}
51
+ </Button>
52
+ );
53
+ const TertiaryButton =
54
+ secondaryAction &&
55
+ (function () {
56
+ const { label: secondaryLabel, ...restOfSecondaryAction } = secondaryAction;
57
+ return (
58
+ <Button key="tertiary" variant="text" {...restOfSecondaryAction}>
59
+ {secondaryLabel}
60
+ </Button>
61
+ );
62
+ })();
59
63
 
60
- const onHiddenInputKeyPress = (event: React.KeyboardEvent<HTMLInputElement>) => {
61
- /** It has to be here because then we will need to check if user doesn't click tab to select action button and want to do another action then primary one? */
62
- if (event.key === 'Enter') {
63
- primaryAction.onClick();
64
- }
65
- };
64
+ const onHiddenInputKeyPress = (event: React.KeyboardEvent<HTMLInputElement>) => {
65
+ /** It has to be here because then we will need to check if user doesn't click tab to select action button and want to do another action then primary one? */
66
+ if (event.key === 'Enter') {
67
+ primaryAction.onClick();
68
+ }
69
+ };
66
70
 
67
- return (
68
- <BaseModal
69
- {...restProps}
70
- id={dialogId}
71
- className={classes['dialog']}
72
- containerClassName={classes['container']}
73
- open={open}
74
- disableBackdrop
75
- onClose={onClose}
76
- zIndex={zIndex}
77
- disableEscapeKeyDown={disableEscapeKeyDown}
78
- >
79
- <DialogTitle id={labelId(dialogId)} title={title} />
80
- <BaseModalContent
81
- id={descriptionId(dialogId)}
82
- className={classes['content']}
83
- disableAutoFocus
71
+ return (
72
+ <BaseModal
73
+ {...rest}
74
+ ref={ref}
75
+ id={dialogId}
76
+ className={classes['dialog']}
77
+ containerClassName={classes['container']}
78
+ open={open}
79
+ disableBackdrop
80
+ onClose={onClose}
81
+ zIndex={zIndex}
82
+ disableEscapeKeyDown={disableEscapeKeyDown}
84
83
  >
85
- {children}
86
- </BaseModalContent>
87
- <DialogActions align={alignActions}>
88
- {alignActions === 'left'
89
- ? [PrimaryButton, TertiaryButton]
90
- : [TertiaryButton, PrimaryButton]}
91
- </DialogActions>
92
- <input
93
- autoFocus
94
- aria-hidden={true}
95
- style={{
96
- position: 'absolute',
97
- width: 0,
98
- height: 0,
99
- opacity: 0,
100
- }}
101
- maxLength={0}
102
- tabIndex={-1}
103
- onKeyPress={onHiddenInputKeyPress}
104
- />
105
- </BaseModal>
106
- );
107
- };
84
+ <DialogTitle id={labelId(dialogId)} title={title} />
85
+ <BaseModalContent
86
+ id={descriptionId(dialogId)}
87
+ className={classes['content']}
88
+ disableAutoFocus
89
+ >
90
+ {children}
91
+ </BaseModalContent>
92
+ <DialogActions align={alignActions}>
93
+ {alignActions === 'left'
94
+ ? [PrimaryButton, TertiaryButton]
95
+ : [TertiaryButton, PrimaryButton]}
96
+ </DialogActions>
97
+ <input
98
+ autoFocus
99
+ aria-hidden={true}
100
+ style={{
101
+ position: 'absolute',
102
+ width: 0,
103
+ height: 0,
104
+ opacity: 0,
105
+ }}
106
+ maxLength={0}
107
+ tabIndex={-1}
108
+ onKeyPress={onHiddenInputKeyPress}
109
+ />
110
+ </BaseModal>
111
+ );
112
+ }
113
+ );
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useEffect, useRef } from 'react';
2
2
  import { DialogActions, Props } from './DialogActions';
3
3
  import { render } from '@testing-library/react';
4
4
 
@@ -23,3 +23,29 @@ describe('DialogActions', () => {
23
23
  expect(dialogActionsContainer).toHaveClass('actions', 'left');
24
24
  });
25
25
  });
26
+
27
+ describe('ref should work', () => {
28
+ it('should give back the proper data prop, this also checks if the component propagates ...rest properly', () => {
29
+ const ExampleComponent = ({
30
+ propagateRef,
31
+ }: {
32
+ propagateRef?: (ref: React.RefObject<HTMLElement>) => void;
33
+ }) => {
34
+ const ref = useRef(null);
35
+
36
+ useEffect(() => {
37
+ if (ref.current) {
38
+ propagateRef && propagateRef(ref);
39
+ }
40
+ }, [ref]);
41
+
42
+ return <DialogActions id="test" children="test" open={true} data-ref="testing" ref={ref} />;
43
+ };
44
+
45
+ const refCheck = (ref: React.RefObject<HTMLElement>) => {
46
+ expect(ref.current).toHaveAttribute('data-ref', 'testing');
47
+ };
48
+
49
+ render(<ExampleComponent propagateRef={refCheck} />);
50
+ });
51
+ });
@@ -1,21 +1,24 @@
1
- import React from 'react';
1
+ import React, { ComponentPropsWithRef } from 'react';
2
2
  import {
3
3
  BaseModalActions,
4
4
  Props as BaseModalActionsProps,
5
5
  } from '../../BaseModal/BaseModalActions/BaseModalActions';
6
6
  import classes from './DialogActions.module.scss';
7
7
 
8
- export interface Props extends BaseModalActionsProps {
8
+ export interface Props extends ComponentPropsWithRef<any>, BaseModalActionsProps {
9
9
  align: 'left' | 'right';
10
10
  }
11
11
 
12
- export const DialogActions = ({ children, align, ...restProps }: Props) => {
13
- return (
14
- <BaseModalActions
15
- {...restProps}
16
- className={`${classes['actions']}${align === 'left' ? ' ' + classes['left'] : ''}`}
17
- >
18
- {children}
19
- </BaseModalActions>
20
- );
21
- };
12
+ export const DialogActions = React.forwardRef<HTMLElement, Props>(
13
+ ({ children, align, ...rest }: Props, ref) => {
14
+ return (
15
+ <BaseModalActions
16
+ {...rest}
17
+ ref={ref}
18
+ className={`${classes['actions']}${align === 'left' ? ' ' + classes['left'] : ''}`}
19
+ >
20
+ {children}
21
+ </BaseModalActions>
22
+ );
23
+ }
24
+ );
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useEffect, useRef } from 'react';
2
2
  import { DialogTitle, Props } from './DialogTitle';
3
3
  import { render, getByText } from '@testing-library/react';
4
4
 
@@ -7,7 +7,7 @@ const initParams: Props = {
7
7
  title: 'Example title',
8
8
  };
9
9
 
10
- describe('DialogActions', () => {
10
+ describe('DialogTitle', () => {
11
11
  it('renders without crashing', () => {
12
12
  const { container } = render(<DialogTitle {...initParams} />);
13
13
 
@@ -16,3 +16,29 @@ describe('DialogActions', () => {
16
16
  expect(getByText(container, initParams.title));
17
17
  });
18
18
  });
19
+
20
+ describe('ref should work', () => {
21
+ it('should give back the proper data prop, this also checks if the component propagates ...rest properly', () => {
22
+ const ExampleComponent = ({
23
+ propagateRef,
24
+ }: {
25
+ propagateRef?: (ref: React.RefObject<HTMLElement>) => void;
26
+ }) => {
27
+ const ref = useRef(null);
28
+
29
+ useEffect(() => {
30
+ if (ref.current) {
31
+ propagateRef && propagateRef(ref);
32
+ }
33
+ }, [ref]);
34
+
35
+ return <DialogTitle title="test" id="test" data-ref="testing" ref={ref} />;
36
+ };
37
+
38
+ const refCheck = (ref: React.RefObject<HTMLElement>) => {
39
+ expect(ref.current).toHaveAttribute('data-ref', 'testing');
40
+ };
41
+
42
+ render(<ExampleComponent propagateRef={refCheck} />);
43
+ });
44
+ });
@@ -1,18 +1,20 @@
1
- import React from 'react';
1
+ import React, { ComponentPropsWithRef } from 'react';
2
2
  import { Typography } from '../../../Typography/Typography';
3
3
  import classes from './DialogTitle.module.scss';
4
4
 
5
- export interface Props {
5
+ export interface Props extends ComponentPropsWithRef<'div'> {
6
6
  id: string;
7
7
  title: string;
8
8
  }
9
9
 
10
- export const DialogTitle = ({ id, title }: Props) => {
11
- return (
12
- <div className={classes['header']}>
13
- <Typography id={id} className={classes['title']} tag="h1" variant="h4">
14
- {title}
15
- </Typography>
16
- </div>
17
- );
18
- };
10
+ export const DialogTitle = React.forwardRef<HTMLDivElement, Props>(
11
+ ({ id, title, ...rest }: Props, ref) => {
12
+ return (
13
+ <div {...rest} ref={ref} className={classes['header']}>
14
+ <Typography id={id} className={classes['title']} tag="h1" variant="h4">
15
+ {title}
16
+ </Typography>
17
+ </div>
18
+ );
19
+ }
20
+ );
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useEffect, useRef } from 'react';
2
2
  import { DiscardChangesDialog, Props } from './DiscardChangesDialog';
3
3
  import { render } from '@testing-library/react';
4
4
  import userEvent from '@testing-library/user-event';
@@ -53,3 +53,43 @@ describe('DiscardChangesDialog should render', () => {
53
53
  expect(defaultParams.onKeepEditing).toBeCalledTimes(1);
54
54
  });
55
55
  });
56
+
57
+ describe('ref should work', () => {
58
+ it('should give back the proper data prop, this also checks if the component propagates ...rest properly', () => {
59
+ const ExampleComponent = ({
60
+ propagateRef,
61
+ }: {
62
+ propagateRef?: (ref: React.RefObject<HTMLElement>) => void;
63
+ }) => {
64
+ const ref = useRef(null);
65
+
66
+ useEffect(() => {
67
+ if (ref.current) {
68
+ propagateRef && propagateRef(ref);
69
+ }
70
+ }, [ref]);
71
+
72
+ return (
73
+ <DiscardChangesDialog
74
+ open={false}
75
+ onKeepEditing={jest.fn()}
76
+ onDiscardChanges={jest.fn()}
77
+ discardChangesButtonLabel="test"
78
+ keepEditingButtonLabel="test"
79
+ contentLabel="test"
80
+ titleLabel="test"
81
+ title="test"
82
+ id="test"
83
+ data-ref="testing"
84
+ ref={ref}
85
+ />
86
+ );
87
+ };
88
+
89
+ const refCheck = (ref: React.RefObject<HTMLElement>) => {
90
+ expect(ref.current).toHaveAttribute('data-ref', 'testing');
91
+ };
92
+
93
+ render(<ExampleComponent propagateRef={refCheck} />);
94
+ });
95
+ });
@@ -1,48 +1,55 @@
1
- import React from 'react';
1
+ import React, { ComponentPropsWithRef } from 'react';
2
2
  import { Dialog } from '../../Dialog/Dialog';
3
- import { HTMLProps } from '../../../interfaces';
4
3
  import { Typography } from '../../../Typography/Typography';
4
+ import { DataAttributeKey } from '../../../interfaces';
5
5
 
6
- export interface Props extends Omit<HTMLProps<HTMLDivElement>, 'children'> {
6
+ export interface Props extends ComponentPropsWithRef<'div'> {
7
7
  open: boolean;
8
8
  discardChangesButtonLabel: string;
9
9
  keepEditingButtonLabel: string;
10
10
  contentLabel: string;
11
11
  titleLabel: string;
12
+ [dataAttribute: DataAttributeKey]: any;
12
13
  onKeepEditing: () => void;
13
14
  onDiscardChanges: () => void;
14
15
  }
15
16
 
16
- export const DiscardChangesDialog = ({
17
- open,
18
- onKeepEditing,
19
- onDiscardChanges,
20
- discardChangesButtonLabel,
21
- keepEditingButtonLabel,
22
- contentLabel,
23
- titleLabel,
24
- ...rest
25
- }: Props) => {
26
- return (
27
- <Dialog
28
- {...rest}
29
- open={open}
30
- alignActions="left"
31
- title={titleLabel}
32
- onClose={onKeepEditing}
33
- primaryAction={{
34
- label: discardChangesButtonLabel,
35
- onClick: onDiscardChanges,
36
- }}
37
- secondaryAction={{
38
- label: keepEditingButtonLabel,
39
- onClick: onKeepEditing,
40
- }}
41
- disableEscapeKeyDown={false}
42
- >
43
- <Typography variant="body" spacing={{ margin: 0 }}>
44
- {contentLabel}
45
- </Typography>
46
- </Dialog>
47
- );
48
- };
17
+ export const DiscardChangesDialog = React.forwardRef<HTMLDivElement, Props>(
18
+ (
19
+ {
20
+ open,
21
+ onKeepEditing,
22
+ onDiscardChanges,
23
+ discardChangesButtonLabel,
24
+ keepEditingButtonLabel,
25
+ contentLabel,
26
+ titleLabel,
27
+ ...rest
28
+ }: Props,
29
+ ref
30
+ ) => {
31
+ return (
32
+ <Dialog
33
+ {...rest}
34
+ ref={ref}
35
+ open={open}
36
+ alignActions="left"
37
+ title={titleLabel}
38
+ onClose={onKeepEditing}
39
+ primaryAction={{
40
+ label: discardChangesButtonLabel,
41
+ onClick: onDiscardChanges,
42
+ }}
43
+ secondaryAction={{
44
+ label: keepEditingButtonLabel,
45
+ onClick: onKeepEditing,
46
+ }}
47
+ disableEscapeKeyDown={false}
48
+ >
49
+ <Typography variant="body" spacing={{ margin: 0 }}>
50
+ {contentLabel}
51
+ </Typography>
52
+ </Dialog>
53
+ );
54
+ }
55
+ );