@onewelcome/react-lib-components 0.1.0-alpha → 0.1.3-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 (240) 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 +4 -5
  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 +9 -7
  9. package/dist/Form/FormControl/FormControl.d.ts +6 -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 +8 -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 +17 -0
  30. package/dist/Notifications/BaseModal/BaseModalActions/BaseModalActions.d.ts +5 -0
  31. package/dist/Notifications/BaseModal/BaseModalContent/BaseModalContent.d.ts +8 -0
  32. package/dist/{BaseModal → Notifications/BaseModal}/BaseModalContext.d.ts +0 -0
  33. package/dist/Notifications/BaseModal/BaseModalHeader/BaseModalHeader.d.ts +8 -0
  34. package/dist/Notifications/Dialog/Dialog.d.ts +19 -0
  35. package/dist/Notifications/Dialog/DialogActions/DialogActions.d.ts +6 -0
  36. package/dist/Notifications/Dialog/DialogTitle/DialogTitle.d.ts +6 -0
  37. package/dist/Notifications/DiscardChangesModal/DiscardChangesDialog/DiscardChangesDialog.d.ts +13 -0
  38. package/dist/Notifications/DiscardChangesModal/DiscardChangesModal.d.ts +13 -0
  39. package/dist/{Modal → Notifications/Modal}/Modal.d.ts +0 -0
  40. package/dist/{Modal → Notifications/Modal}/ModalActions/ModalActions.d.ts +0 -0
  41. package/dist/{Modal → Notifications/Modal}/ModalContent/ModalContent.d.ts +0 -0
  42. package/dist/{Modal → Notifications/Modal}/ModalHeader/ModalHeader.d.ts +0 -0
  43. package/dist/{Snackbar → Notifications/Snackbar}/SnackbarContainer/SnackbarContainer.d.ts +0 -0
  44. package/dist/{Snackbar → Notifications/Snackbar}/SnackbarItem/SnackbarItem.d.ts +0 -0
  45. package/dist/{Snackbar → Notifications/Snackbar}/SnackbarProvider/SnackbarProvider.d.ts +1 -1
  46. package/dist/{Snackbar → Notifications/Snackbar}/SnackbarProvider/SnackbarStateProvider.d.ts +0 -0
  47. package/dist/{Snackbar → Notifications/Snackbar}/interfaces.d.ts +0 -0
  48. package/dist/{Snackbar → Notifications/Snackbar}/useSnackbar.d.ts +0 -0
  49. package/dist/Pagination/Pagination.d.ts +19 -0
  50. package/dist/Popover/Popover.d.ts +3 -3
  51. package/dist/Tabs/Tab.d.ts +11 -0
  52. package/dist/Tabs/TabButton.d.ts +10 -0
  53. package/dist/Tabs/TabPanel.d.ts +8 -0
  54. package/dist/Tabs/Tabs.d.ts +9 -0
  55. package/dist/TextEllipsis/TextEllipsis.d.ts +6 -0
  56. package/dist/Tiles/Tile.d.ts +6 -7
  57. package/dist/Tiles/Tiles.d.ts +3 -3
  58. package/dist/Tooltip/Tooltip.d.ts +3 -3
  59. package/dist/Typography/Typography.d.ts +6 -4
  60. package/dist/Wizard/BaseWizardSteps/BaseWizardSteps.d.ts +3 -3
  61. package/dist/Wizard/WizardSteps/WizardSteps.d.ts +3 -3
  62. package/dist/_BaseStyling_/BaseStyling.d.ts +9 -0
  63. package/dist/hooks/useRepeater.d.ts +10 -0
  64. package/dist/hooks/useSpacing.d.ts +2 -2
  65. package/dist/hooks/useWrapper.d.ts +1 -1
  66. package/dist/index.d.ts +12 -7
  67. package/dist/interfaces.d.ts +2 -11
  68. package/dist/react-lib-components.cjs.development.js +1861 -1287
  69. package/dist/react-lib-components.cjs.development.js.map +1 -1
  70. package/dist/react-lib-components.cjs.production.min.js +1 -1
  71. package/dist/react-lib-components.cjs.production.min.js.map +1 -1
  72. package/dist/react-lib-components.esm.js +1858 -1289
  73. package/dist/react-lib-components.esm.js.map +1 -1
  74. package/dist/util/helper.d.ts +6 -1
  75. package/package.json +30 -24
  76. package/src/Breadcrumbs/Breadcrumbs.tsx +39 -37
  77. package/src/Button/BaseButton.test.tsx +65 -19
  78. package/src/Button/BaseButton.tsx +2 -3
  79. package/src/Button/Button.test.tsx +63 -17
  80. package/src/Button/Button.tsx +15 -4
  81. package/src/Button/IconButton.test.tsx +57 -22
  82. package/src/Button/IconButton.tsx +21 -12
  83. package/src/ContextMenu/ContextMenu.test.tsx +27 -1
  84. package/src/ContextMenu/ContextMenu.tsx +70 -65
  85. package/src/Form/Checkbox/Checkbox.module.scss +4 -0
  86. package/src/Form/Checkbox/Checkbox.test.tsx +28 -2
  87. package/src/Form/Checkbox/Checkbox.tsx +132 -117
  88. package/src/Form/Fieldset/Fieldset.module.scss +11 -1
  89. package/src/Form/Fieldset/Fieldset.test.tsx +30 -4
  90. package/src/Form/Fieldset/Fieldset.tsx +101 -43
  91. package/src/Form/FormControl/FormControl.test.tsx +27 -1
  92. package/src/Form/FormControl/FormControl.tsx +37 -37
  93. package/src/Form/FormGroup/FormGroup.test.tsx +27 -1
  94. package/src/Form/FormGroup/FormGroup.tsx +64 -58
  95. package/src/Form/FormHelperText/FormHelperText.test.tsx +27 -1
  96. package/src/Form/FormHelperText/FormHelperText.tsx +20 -16
  97. package/src/Form/FormSelectorWrapper/FormSelectorWrapper.test.tsx +78 -0
  98. package/src/Form/FormSelectorWrapper/FormSelectorWrapper.tsx +61 -55
  99. package/src/Form/Input/Input.module.scss +34 -15
  100. package/src/Form/Input/Input.test.tsx +27 -1
  101. package/src/Form/Input/Input.tsx +88 -47
  102. package/src/Form/Label/Label.test.tsx +27 -1
  103. package/src/Form/Label/Label.tsx +18 -14
  104. package/src/Form/Radio/Radio.module.scss +4 -0
  105. package/src/Form/Radio/Radio.test.tsx +28 -2
  106. package/src/Form/Radio/Radio.tsx +98 -80
  107. package/src/Form/Select/Option.test.tsx +27 -1
  108. package/src/Form/Select/Option.tsx +49 -42
  109. package/src/Form/Select/Select.module.scss +5 -1
  110. package/src/Form/Select/Select.test.tsx +224 -30
  111. package/src/Form/Select/Select.tsx +248 -182
  112. package/src/Form/Textarea/Textarea.module.scss +2 -1
  113. package/src/Form/Textarea/Textarea.test.tsx +28 -2
  114. package/src/Form/Textarea/Textarea.tsx +44 -29
  115. package/src/Form/Toggle/Toggle.module.scss +9 -0
  116. package/src/Form/Toggle/Toggle.test.tsx +27 -1
  117. package/src/Form/Toggle/Toggle.tsx +25 -12
  118. package/src/Form/Wrapper/CheckboxWrapper/CheckboxWrapper.test.tsx +28 -2
  119. package/src/Form/Wrapper/CheckboxWrapper/CheckboxWrapper.tsx +45 -48
  120. package/src/Form/Wrapper/InputWrapper/InputWrapper.module.scss +17 -1
  121. package/src/Form/Wrapper/InputWrapper/InputWrapper.test.tsx +89 -1
  122. package/src/Form/Wrapper/InputWrapper/InputWrapper.tsx +134 -74
  123. package/src/Form/Wrapper/RadioWrapper/RadioWrapper.test.tsx +1 -1
  124. package/src/Form/Wrapper/RadioWrapper/RadioWrapper.tsx +64 -59
  125. package/src/Form/Wrapper/SelectWrapper/SelectWrapper.module.scss +1 -1
  126. package/src/Form/Wrapper/SelectWrapper/SelectWrapper.test.tsx +43 -1
  127. package/src/Form/Wrapper/SelectWrapper/SelectWrapper.tsx +55 -44
  128. package/src/Form/Wrapper/TextareaWrapper/TextareaWrapper.module.scss +5 -7
  129. package/src/Form/Wrapper/TextareaWrapper/TextareaWrapper.test.tsx +43 -1
  130. package/src/Form/Wrapper/TextareaWrapper/TextareaWrapper.tsx +100 -85
  131. package/src/Form/Wrapper/Wrapper/Wrapper.module.scss +1 -1
  132. package/src/Form/Wrapper/Wrapper/Wrapper.test.tsx +27 -1
  133. package/src/Form/Wrapper/Wrapper/Wrapper.tsx +76 -71
  134. package/src/Form/form.interfaces.ts +4 -3
  135. package/src/Icon/Icon.module.scss +4 -0
  136. package/src/Icon/Icon.test.tsx +30 -2
  137. package/src/Icon/Icon.tsx +5 -5
  138. package/src/Link/Link.test.tsx +27 -1
  139. package/src/Link/Link.tsx +4 -6
  140. package/src/{BaseModal → Notifications/BaseModal}/BaseModal.module.scss +0 -0
  141. package/src/{BaseModal → Notifications/BaseModal}/BaseModal.test.tsx +35 -16
  142. package/src/Notifications/BaseModal/BaseModal.tsx +105 -0
  143. package/src/{BaseModal → Notifications/BaseModal}/BaseModalActions/BaseModalActions.module.scss +0 -0
  144. package/src/Notifications/BaseModal/BaseModalActions/BaseModalActions.test.tsx +42 -0
  145. package/src/Notifications/BaseModal/BaseModalActions/BaseModalActions.tsx +16 -0
  146. package/src/{BaseModal → Notifications/BaseModal}/BaseModalContent/BaseModalContent.module.scss +0 -0
  147. package/src/{BaseModal → Notifications/BaseModal}/BaseModalContent/BaseModalContent.test.tsx +27 -1
  148. package/src/Notifications/BaseModal/BaseModalContent/BaseModalContent.tsx +36 -0
  149. package/src/{BaseModal → Notifications/BaseModal}/BaseModalContext.ts +0 -0
  150. package/src/{BaseModal → Notifications/BaseModal}/BaseModalHeader/BaseModalHeader.module.scss +0 -0
  151. package/src/{BaseModal → Notifications/BaseModal}/BaseModalHeader/BaseModalHeader.test.tsx +29 -1
  152. package/src/Notifications/BaseModal/BaseModalHeader/BaseModalHeader.tsx +30 -0
  153. package/src/{Dialog → Notifications/Dialog}/Dialog.module.scss +0 -0
  154. package/src/{Dialog → Notifications/Dialog}/Dialog.test.tsx +52 -17
  155. package/src/Notifications/Dialog/Dialog.tsx +113 -0
  156. package/src/{Dialog → Notifications/Dialog}/DialogActions/DialogActions.module.scss +0 -0
  157. package/src/Notifications/Dialog/DialogActions/DialogActions.test.tsx +51 -0
  158. package/src/Notifications/Dialog/DialogActions/DialogActions.tsx +24 -0
  159. package/src/{Dialog → Notifications/Dialog}/DialogTitle/DialogTitle.module.scss +0 -0
  160. package/src/Notifications/Dialog/DialogTitle/DialogTitle.test.tsx +44 -0
  161. package/src/Notifications/Dialog/DialogTitle/DialogTitle.tsx +20 -0
  162. package/src/Notifications/DiscardChangesModal/DiscardChangesDialog/DiscardChangesDialog.test.tsx +95 -0
  163. package/src/Notifications/DiscardChangesModal/DiscardChangesDialog/DiscardChangesDialog.tsx +55 -0
  164. package/src/Notifications/DiscardChangesModal/DiscardChangesModal.test.tsx +162 -0
  165. package/src/Notifications/DiscardChangesModal/DiscardChangesModal.tsx +61 -0
  166. package/src/{Modal → Notifications/Modal}/Modal.test.tsx +0 -0
  167. package/src/{Modal → Notifications/Modal}/Modal.tsx +0 -0
  168. package/src/{Modal → Notifications/Modal}/ModalActions/ModalActions.tsx +0 -0
  169. package/src/{Modal → Notifications/Modal}/ModalContent/ModalContent.tsx +0 -0
  170. package/src/{Modal → Notifications/Modal}/ModalHeader/ModalHeader.tsx +0 -0
  171. package/src/{Snackbar → Notifications/Snackbar}/SnackbarContainer/SnackbarContainer.module.scss +0 -0
  172. package/src/{Snackbar → Notifications/Snackbar}/SnackbarContainer/SnackbarContainer.test.tsx +0 -0
  173. package/src/{Snackbar → Notifications/Snackbar}/SnackbarContainer/SnackbarContainer.tsx +0 -0
  174. package/src/{Snackbar → Notifications/Snackbar}/SnackbarItem/SnackbarItem.module.scss +1 -1
  175. package/src/{Snackbar → Notifications/Snackbar}/SnackbarItem/SnackbarItem.test.tsx +0 -0
  176. package/src/{Snackbar → Notifications/Snackbar}/SnackbarItem/SnackbarItem.tsx +6 -7
  177. package/src/{Snackbar → Notifications/Snackbar}/SnackbarProvider/SnackbarProvider.test.tsx +0 -0
  178. package/src/{Snackbar → Notifications/Snackbar}/SnackbarProvider/SnackbarProvider.tsx +2 -2
  179. package/src/{Snackbar → Notifications/Snackbar}/SnackbarProvider/SnackbarStateProvider.tsx +0 -0
  180. package/src/{Snackbar → Notifications/Snackbar}/interfaces.ts +0 -0
  181. package/src/{Snackbar → Notifications/Snackbar}/useSnackbar.ts +0 -0
  182. package/src/Pagination/Pagination.module.scss +120 -0
  183. package/src/Pagination/Pagination.test.tsx +176 -0
  184. package/src/Pagination/Pagination.tsx +205 -0
  185. package/src/Popover/Popover.test.tsx +3 -3
  186. package/src/Popover/Popover.tsx +3 -3
  187. package/src/Tabs/Tab.test.tsx +71 -0
  188. package/src/Tabs/Tab.tsx +17 -0
  189. package/src/Tabs/TabButton.module.scss +36 -0
  190. package/src/Tabs/TabButton.test.tsx +77 -0
  191. package/src/Tabs/TabButton.tsx +58 -0
  192. package/src/Tabs/TabPanel.module.scss +7 -0
  193. package/src/Tabs/TabPanel.test.tsx +76 -0
  194. package/src/Tabs/TabPanel.tsx +27 -0
  195. package/src/Tabs/Tabs.module.scss +41 -0
  196. package/src/Tabs/Tabs.test.tsx +268 -0
  197. package/src/Tabs/Tabs.tsx +149 -0
  198. package/src/TextEllipsis/TextEllipsis.module.scss +18 -0
  199. package/src/TextEllipsis/TextEllipsis.test.tsx +80 -0
  200. package/src/TextEllipsis/TextEllipsis.tsx +55 -0
  201. package/src/Tiles/Tile.module.scss +1 -1
  202. package/src/Tiles/Tile.test.tsx +48 -12
  203. package/src/Tiles/Tile.tsx +68 -34
  204. package/src/Tiles/Tiles.test.tsx +38 -10
  205. package/src/Tiles/Tiles.tsx +42 -39
  206. package/src/Tooltip/Tooltip.test.tsx +27 -1
  207. package/src/Tooltip/Tooltip.tsx +104 -92
  208. package/src/Typography/Typography.test.tsx +27 -1
  209. package/src/Typography/Typography.tsx +66 -68
  210. package/src/Wizard/BaseWizardSteps/BaseWizardSteps.tsx +67 -62
  211. package/src/Wizard/Wizard.tsx +2 -2
  212. package/src/Wizard/WizardActions/WizardActions.tsx +3 -3
  213. package/src/Wizard/WizardSteps/WizardSteps.tsx +24 -21
  214. package/src/_BaseStyling_/BaseStyling.tsx +19 -1
  215. package/src/hooks/usePosition.test.tsx +3 -3
  216. package/src/hooks/useRepeater.test.tsx +139 -0
  217. package/src/hooks/useRepeater.ts +34 -0
  218. package/src/hooks/useSpacing.ts +1 -1
  219. package/src/hooks/useWrapper.ts +7 -2
  220. package/src/index.ts +20 -8
  221. package/src/interfaces.ts +2 -12
  222. package/src/util/helper.test.tsx +38 -1
  223. package/src/util/helper.tsx +21 -0
  224. package/dist/BaseModal/BaseModal.d.ts +0 -16
  225. package/dist/BaseModal/BaseModalActions/BaseModalActions.d.ts +0 -5
  226. package/dist/BaseModal/BaseModalContent/BaseModalContent.d.ts +0 -8
  227. package/dist/BaseModal/BaseModalHeader/BaseModalHeader.d.ts +0 -8
  228. package/dist/Dialog/Dialog.d.ts +0 -18
  229. package/dist/Dialog/DialogActions/DialogActions.d.ts +0 -6
  230. package/dist/Dialog/DialogTitle/DialogTitle.d.ts +0 -6
  231. package/src/BaseModal/BaseModal.tsx +0 -113
  232. package/src/BaseModal/BaseModalActions/BaseModalActions.test.tsx +0 -17
  233. package/src/BaseModal/BaseModalActions/BaseModalActions.tsx +0 -14
  234. package/src/BaseModal/BaseModalContent/BaseModalContent.tsx +0 -35
  235. package/src/BaseModal/BaseModalHeader/BaseModalHeader.tsx +0 -28
  236. package/src/Dialog/Dialog.tsx +0 -96
  237. package/src/Dialog/DialogActions/DialogActions.test.tsx +0 -25
  238. package/src/Dialog/DialogActions/DialogActions.tsx +0 -21
  239. package/src/Dialog/DialogTitle/DialogTitle.test.tsx +0 -18
  240. package/src/Dialog/DialogTitle/DialogTitle.tsx +0 -18
@@ -0,0 +1,36 @@
1
+ import React, { ComponentPropsWithRef, createRef, useEffect } from 'react';
2
+ import classes from './BaseModalContent.module.scss';
3
+
4
+ export interface Props extends ComponentPropsWithRef<'div'> {
5
+ id?: string;
6
+ children: React.ReactNode;
7
+ className?: string;
8
+ disableAutoFocus?: boolean;
9
+ }
10
+
11
+ export const BaseModalContent = React.forwardRef<HTMLDivElement, Props>(
12
+ ({ id, children, className = '', disableAutoFocus = false, ...rest }: Props, ref) => {
13
+ const contentRef = createRef<HTMLDivElement>();
14
+
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
+ });
@@ -0,0 +1,30 @@
1
+ import React, { ComponentPropsWithRef } from 'react';
2
+ import classes from './BaseModalHeader.module.scss';
3
+ import { IconButton } from '../../../Button/IconButton';
4
+ import { Icon, Icons } from '../../../Icon/Icon';
5
+ import { Typography } from '../../../Typography/Typography';
6
+
7
+ export interface Props extends ComponentPropsWithRef<'div'> {
8
+ id: string;
9
+ title: string;
10
+ children?: React.ReactNode;
11
+ onClose: (event: React.MouseEvent<HTMLButtonElement>) => void;
12
+ }
13
+
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}
27
+ </div>
28
+ );
29
+ }
30
+ );
@@ -1,6 +1,6 @@
1
- import React from 'react';
1
+ import React, { useEffect, useRef } from 'react';
2
2
  import { Dialog, Props } from './Dialog';
3
- import { render, getAllByRole, getByRole, fireEvent, getByText } from '@testing-library/react';
3
+ import { render, getAllByRole } from '@testing-library/react';
4
4
  import userEvent from '@testing-library/user-event';
5
5
 
6
6
  const initParams: Props = {
@@ -24,11 +24,11 @@ const getButtons = (container: HTMLElement) => getAllByRole(container, 'button')
24
24
 
25
25
  describe('Dialog', () => {
26
26
  it('renders without crashing', () => {
27
- const { container } = render(<Dialog {...initParams} />);
28
- const [primaryButton, secondaryButton] = getButtons(container);
27
+ const { getByText } = render(<Dialog {...initParams} />);
28
+ const [primaryButton, secondaryButton] = getButtons(document.body);
29
29
 
30
- expect(getByText(container, initParams.title)).toBeDefined();
31
- expect(getByText(container, initParams.children as string)).toBeDefined();
30
+ expect(getByText(initParams.title)).toBeDefined();
31
+ expect(getByText(initParams.children as string)).toBeDefined();
32
32
  const actionsDiv = primaryButton.closest('footer');
33
33
  expect(actionsDiv).toHaveClass('left');
34
34
  expect(actionsDiv?.children[0]).toEqual(primaryButton);
@@ -38,8 +38,8 @@ describe('Dialog', () => {
38
38
  });
39
39
 
40
40
  it('renders action aligned to right', () => {
41
- const { container } = render(<Dialog {...initParams} alignActions="right" />);
42
- const [secondaryButton, primaryButton] = getButtons(container);
41
+ render(<Dialog {...initParams} alignActions="right" />);
42
+ const [secondaryButton, primaryButton] = getButtons(document.body);
43
43
 
44
44
  const actionsDiv = primaryButton.closest('footer');
45
45
  expect(actionsDiv).not.toHaveClass('left');
@@ -50,30 +50,65 @@ describe('Dialog', () => {
50
50
  });
51
51
 
52
52
  it('renders only one button', () => {
53
- const { container } = render(<Dialog {...initParams} secondaryAction={undefined} />);
54
- const buttons = getButtons(container);
53
+ render(<Dialog {...initParams} secondaryAction={undefined} />);
54
+ const buttons = getButtons(document.body);
55
55
 
56
56
  expect(buttons).toHaveLength(1);
57
57
  expect(buttons[0]).toHaveClass('fill');
58
58
  });
59
59
 
60
- it('should handle clicking on buttons, ESC and ENTER keys', () => {
61
- const { container } = render(<Dialog {...initParams} />);
62
- const [primaryButton, secondaryButton] = getButtons(container);
60
+ it('should handle clicking on buttons and ENTER press', () => {
61
+ render(<Dialog {...initParams} />);
62
+ const [primaryButton, secondaryButton] = getButtons(document.body);
63
63
  expect(initParams.primaryAction.onClick).toHaveBeenCalledTimes(0);
64
64
  expect(initParams.secondaryAction?.onClick).toHaveBeenCalledTimes(0);
65
65
  expect(initParams.onClose).toHaveBeenCalledTimes(0);
66
66
 
67
- const autoSummissionInput = container.querySelector('input') as HTMLElement;
67
+ const autoSummissionInput = document.body.querySelector('input') as HTMLElement;
68
68
  userEvent.type(autoSummissionInput, '{enter}');
69
69
  expect(initParams.primaryAction.onClick).toHaveBeenCalledTimes(1);
70
70
 
71
- fireEvent.keyDown(getByRole(container, 'dialog'), { key: 'Escape' });
72
- expect(initParams.onClose).toHaveBeenCalledTimes(1);
73
-
74
71
  userEvent.click(primaryButton);
75
72
  expect(initParams.primaryAction.onClick).toHaveBeenCalledTimes(2);
76
73
  userEvent.click(secondaryButton);
77
74
  expect(initParams.secondaryAction?.onClick).toHaveBeenCalledTimes(1);
78
75
  });
79
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
+ });
@@ -0,0 +1,113 @@
1
+ import React, { ComponentPropsWithRef, useState } from 'react';
2
+ import { BaseModal } from '../BaseModal/BaseModal';
3
+ import { BaseModalContent } from '../BaseModal/BaseModalContent/BaseModalContent';
4
+ import { DialogActions } from './DialogActions/DialogActions';
5
+ import classes from './Dialog.module.scss';
6
+ import { DialogTitle } from './DialogTitle/DialogTitle';
7
+ import { Button, Props as ButtonProps } from '../../Button/Button';
8
+ import { labelId, descriptionId } from '../BaseModal/BaseModalContext';
9
+ import { generateID } from '../../util/helper';
10
+
11
+ export interface Props extends ComponentPropsWithRef<'div'> {
12
+ id?: string;
13
+ open: boolean;
14
+ children: React.ReactNode;
15
+ alignActions: 'left' | 'right';
16
+ onClose: () => void;
17
+ title: string;
18
+ primaryAction: Action;
19
+ secondaryAction?: Action;
20
+ zIndex?: number;
21
+ disableEscapeKeyDown?: boolean;
22
+ }
23
+
24
+ export interface Action extends Omit<ButtonProps, 'variant' | 'ref'> {
25
+ label: string;
26
+ onClick: (event?: React.MouseEvent<HTMLButtonElement>) => unknown;
27
+ }
28
+
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
+ })();
63
+
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
+ };
70
+
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}
83
+ >
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
+ );
@@ -0,0 +1,51 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+ import { DialogActions, Props } from './DialogActions';
3
+ import { render } from '@testing-library/react';
4
+
5
+ const initParams: Props = {
6
+ align: 'right',
7
+ children: 'Content',
8
+ };
9
+
10
+ describe('DialogActions', () => {
11
+ it('renders without crashing', () => {
12
+ const { container } = render(<DialogActions {...initParams} />);
13
+
14
+ const dialogActionsContainer = container.children[0];
15
+ expect(dialogActionsContainer).toHaveClass('actions');
16
+ expect(dialogActionsContainer).toHaveTextContent(initParams.children as string);
17
+ });
18
+
19
+ it('should align items to left', () => {
20
+ const { container } = render(<DialogActions {...initParams} align="left" />);
21
+
22
+ const dialogActionsContainer = container.children[0];
23
+ expect(dialogActionsContainer).toHaveClass('actions', 'left');
24
+ });
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
+ });
@@ -0,0 +1,24 @@
1
+ import React, { ComponentPropsWithRef } from 'react';
2
+ import {
3
+ BaseModalActions,
4
+ Props as BaseModalActionsProps,
5
+ } from '../../BaseModal/BaseModalActions/BaseModalActions';
6
+ import classes from './DialogActions.module.scss';
7
+
8
+ export interface Props extends ComponentPropsWithRef<any>, BaseModalActionsProps {
9
+ align: 'left' | 'right';
10
+ }
11
+
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
+ );
@@ -0,0 +1,44 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+ import { DialogTitle, Props } from './DialogTitle';
3
+ import { render, getByText } from '@testing-library/react';
4
+
5
+ const initParams: Props = {
6
+ id: 'dialog-label',
7
+ title: 'Example title',
8
+ };
9
+
10
+ describe('DialogTitle', () => {
11
+ it('renders without crashing', () => {
12
+ const { container } = render(<DialogTitle {...initParams} />);
13
+
14
+ const dialogTitleContainer = container.children[0];
15
+ expect(dialogTitleContainer).toHaveClass('header');
16
+ expect(getByText(container, initParams.title));
17
+ });
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
+ });
@@ -0,0 +1,20 @@
1
+ import React, { ComponentPropsWithRef } from 'react';
2
+ import { Typography } from '../../../Typography/Typography';
3
+ import classes from './DialogTitle.module.scss';
4
+
5
+ export interface Props extends ComponentPropsWithRef<'div'> {
6
+ id: string;
7
+ title: string;
8
+ }
9
+
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
+ );
@@ -0,0 +1,95 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+ import { DiscardChangesDialog, Props } from './DiscardChangesDialog';
3
+ import { render } from '@testing-library/react';
4
+ import userEvent from '@testing-library/user-event';
5
+
6
+ const defaultParams: Props = {
7
+ open: true,
8
+ onKeepEditing: jest.fn(),
9
+ onDiscardChanges: jest.fn(),
10
+ discardChangesButtonLabel: 'Discard Changes',
11
+ keepEditingButtonLabel: 'Keep Editing',
12
+ contentLabel: 'Content',
13
+ titleLabel: 'Unsaved changes',
14
+ };
15
+
16
+ const createDiscardChangesDialog = (params?: (defaultParams: Props) => Props) => {
17
+ let parameters: Props = defaultParams;
18
+ if (params) {
19
+ parameters = params(defaultParams);
20
+ }
21
+ const queries = render(
22
+ <DiscardChangesDialog {...parameters} data-testid="DiscardChangesDialog"></DiscardChangesDialog>
23
+ );
24
+ const discardChangesDialog = queries.getByTestId('DiscardChangesDialog');
25
+ const discardChangesBtn = queries.getByRole('button', {
26
+ name: defaultParams.discardChangesButtonLabel,
27
+ });
28
+ const keepEditingBtn = queries.getByRole('button', {
29
+ name: defaultParams.keepEditingButtonLabel,
30
+ });
31
+
32
+ return {
33
+ ...queries,
34
+ discardChangesDialog,
35
+ discardChangesBtn,
36
+ keepEditingBtn,
37
+ };
38
+ };
39
+
40
+ describe('DiscardChangesDialog should render', () => {
41
+ it('renders without crashing', () => {
42
+ const { discardChangesDialog, discardChangesBtn, keepEditingBtn } =
43
+ createDiscardChangesDialog();
44
+
45
+ expect(discardChangesDialog).toBeDefined();
46
+ expect(discardChangesDialog).toHaveTextContent(defaultParams.contentLabel);
47
+ expect(discardChangesDialog).toHaveTextContent(defaultParams.titleLabel);
48
+
49
+ userEvent.click(discardChangesBtn);
50
+ expect(defaultParams.onDiscardChanges).toBeCalledTimes(1);
51
+
52
+ userEvent.click(keepEditingBtn);
53
+ expect(defaultParams.onKeepEditing).toBeCalledTimes(1);
54
+ });
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
+ });
@@ -0,0 +1,55 @@
1
+ import React, { ComponentPropsWithRef } from 'react';
2
+ import { Dialog } from '../../Dialog/Dialog';
3
+ import { Typography } from '../../../Typography/Typography';
4
+ import { DataAttributeKey } from '../../../interfaces';
5
+
6
+ export interface Props extends ComponentPropsWithRef<'div'> {
7
+ open: boolean;
8
+ discardChangesButtonLabel: string;
9
+ keepEditingButtonLabel: string;
10
+ contentLabel: string;
11
+ titleLabel: string;
12
+ [dataAttribute: DataAttributeKey]: any;
13
+ onKeepEditing: () => void;
14
+ onDiscardChanges: () => void;
15
+ }
16
+
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
+ );