@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,205 @@
1
+ import React, { ComponentPropsWithRef, Fragment, useState } from 'react';
2
+ import classes from './Pagination.module.scss';
3
+ import readyclasses from '../readyclasses.module.scss';
4
+ import { IconButton } from '../Button/IconButton';
5
+ import { Icons, Icon } from '../Icon/Icon';
6
+ import { Input } from '../Form/Input/Input';
7
+ import { Select } from '../Form/Select/Select';
8
+ import { Option } from '../Form/Select/Option';
9
+ import { Label } from '../Form/Label/Label';
10
+
11
+ export type PaginationTranslations = {
12
+ totalItems: string;
13
+ itemsPerPage: string;
14
+ itemsPerPageLabel: string;
15
+ currentPage: string;
16
+ currentPageLabel: string;
17
+ };
18
+
19
+ export type PageChangeLabels = 'next' | 'previous' | 'first' | 'last';
20
+
21
+ enum DefaultTranslations {
22
+ totalItems = 'Total items',
23
+ itemsPerPage = 'Items per page',
24
+ currentPage = 'Page %1 of %2',
25
+ itemsPerPageLabel = 'Select how many items per page you want to see.',
26
+ currentPageLabel = 'What page you are currently on.',
27
+ }
28
+
29
+ export type PageSize = 10 | 25 | 50;
30
+
31
+ export interface Props extends Omit<ComponentPropsWithRef<'div'>, 'translate'> {
32
+ currentPage?: number;
33
+ totalElements?: number;
34
+ pageSize?: PageSize;
35
+ translate?: PaginationTranslations;
36
+ onPageChange: (pageToGoTo: number) => void;
37
+ onPageSizeChange: (pageSize: PageSize) => void;
38
+ }
39
+
40
+ export const Pagination = React.forwardRef<HTMLDivElement, Props>(
41
+ (
42
+ {
43
+ totalElements,
44
+ pageSize = 10,
45
+ translate = DefaultTranslations,
46
+ currentPage,
47
+ className,
48
+ onPageChange,
49
+ onPageSizeChange,
50
+ ...rest
51
+ }: Props,
52
+ ref
53
+ ) => {
54
+ /** We use an internal state variable, because we don't want to fire onCurrentPageChange whenever onChange fires on the input. Rather, only when the Enter key is pressed. */
55
+ const [internalCurrentPage, setInternalCurrentPage] = useState(currentPage?.toString() || '1');
56
+ const calculateAmountOfPages = () => (totalElements ? Math.ceil(totalElements / pageSize) : 0);
57
+
58
+ const onEnterListener = (event: React.KeyboardEvent<HTMLInputElement>) => {
59
+ if (event.code === 'Enter') {
60
+ onPageChange(Number(internalCurrentPage));
61
+ }
62
+ };
63
+
64
+ const renderCurrentPageTranslation = () => {
65
+ const amountOfPages = calculateAmountOfPages();
66
+
67
+ if (amountOfPages) {
68
+ const splitCurrentPageTranslation = translate.currentPage.split(' ');
69
+
70
+ return splitCurrentPageTranslation.map((string) => {
71
+ if (string.includes('%1')) {
72
+ return (
73
+ <Fragment key={string}>
74
+ <Label
75
+ id="current-value-input-label"
76
+ htmlFor="current-value-input"
77
+ className={readyclasses['sr-only']}
78
+ >
79
+ {translate.currentPageLabel}
80
+ </Label>
81
+ <Input
82
+ aria-labelledby="current-value-input-label"
83
+ key="input"
84
+ id="current-value-input"
85
+ type="text"
86
+ size={currentPage?.toString().length}
87
+ max={calculateAmountOfPages()}
88
+ wrapperProps={{ className: classes['current-value-input'] }}
89
+ onKeyUp={onEnterListener}
90
+ onBlur={(event: React.ChangeEvent<HTMLInputElement>) =>
91
+ onPageChange(Number(event.target.value))
92
+ }
93
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
94
+ setInternalCurrentPage(e.target.value)
95
+ }
96
+ name="current-value-input"
97
+ value={internalCurrentPage}
98
+ className={`${classes['form-element']} ${classes['current-page-input']}`}
99
+ />
100
+ </Fragment>
101
+ );
102
+ }
103
+
104
+ if (string.includes('%2')) {
105
+ return <div key={string}>{string.replace('%2', amountOfPages.toString())}&nbsp;</div>;
106
+ }
107
+
108
+ return <div key={string}>{string}&nbsp;</div>;
109
+ });
110
+ }
111
+
112
+ return null;
113
+ };
114
+
115
+ const onPageSizeChangeHandler = (event: React.ChangeEvent<HTMLSelectElement>) => {
116
+ const pageSizeNumber = Number(event.target.value) as PageSize;
117
+ onPageSizeChange(pageSizeNumber);
118
+ };
119
+
120
+ const onPageChangeHandler = (pageToGoTo: number) => {
121
+ onPageChange(pageToGoTo);
122
+ };
123
+
124
+ return (
125
+ <div
126
+ {...rest}
127
+ ref={ref}
128
+ className={`${classes['pagination-wrapper']} ${className ? className : ''}`}
129
+ >
130
+ {totalElements && (
131
+ <div className={classes['total']}>
132
+ <span tabIndex={0}>
133
+ {translate.totalItems}: <span>{totalElements}</span>
134
+ </span>
135
+ </div>
136
+ )}
137
+ <div className={classes['pagination']}>
138
+ {totalElements && pageSize && (
139
+ <div className={classes['per-page']}>
140
+ <Label id="page-size-select-label">{translate.itemsPerPage}</Label>
141
+ <Select
142
+ labeledBy="page-size-select-label"
143
+ className={`${classes['form-element']} ${classes['page-size-select']}`}
144
+ value={pageSize.toString()}
145
+ onChange={onPageSizeChangeHandler}
146
+ >
147
+ <Option value="10">10</Option>
148
+ <Option value="25">25</Option>
149
+ <Option value="50">50</Option>
150
+ </Select>
151
+ </div>
152
+ )}
153
+ <Fragment>
154
+ {((currentPage && currentPage > 2) || (currentPage && currentPage > 1)) && (
155
+ <div className={classes['previous']}>
156
+ {currentPage > 2 && (
157
+ <IconButton
158
+ title="first"
159
+ onClick={() => onPageChangeHandler(0)}
160
+ data-paginate="first"
161
+ >
162
+ <Icon icon={Icons.NavigationFirst} />
163
+ </IconButton>
164
+ )}
165
+ {currentPage > 1 && (
166
+ <IconButton
167
+ title="previous"
168
+ onClick={() => onPageChangeHandler(currentPage - 1)}
169
+ data-paginate="previous"
170
+ >
171
+ <Icon icon={Icons.ChevronLeft} />
172
+ </IconButton>
173
+ )}
174
+ </div>
175
+ )}
176
+ {totalElements && (
177
+ <div className={classes['page']}>{renderCurrentPageTranslation()}</div>
178
+ )}
179
+ <div className={classes['next']}>
180
+ {((currentPage && currentPage < calculateAmountOfPages()) ||
181
+ (currentPage && !totalElements)) && (
182
+ <IconButton
183
+ title="next"
184
+ onClick={() => onPageChangeHandler(currentPage + 1)}
185
+ data-paginate="next"
186
+ >
187
+ <Icon icon={Icons.ChevronRight} />
188
+ </IconButton>
189
+ )}
190
+ {currentPage && totalElements && currentPage < calculateAmountOfPages()! - 1 && (
191
+ <IconButton
192
+ title="last"
193
+ onClick={() => onPageChangeHandler(totalElements / pageSize)}
194
+ data-paginate="last"
195
+ >
196
+ <Icon icon={Icons.NavigationLast} />
197
+ </IconButton>
198
+ )}
199
+ </div>
200
+ </Fragment>
201
+ </div>
202
+ </div>
203
+ );
204
+ }
205
+ );
@@ -1,4 +1,4 @@
1
- import React, { useRef } from 'react';
1
+ import React, { Fragment, useRef } from 'react';
2
2
  import { Popover, Props } from './Popover';
3
3
  import { render } from '@testing-library/react';
4
4
  import { usePosition } from '../hooks/usePosition';
@@ -32,7 +32,7 @@ const createPopover = (params?: (defaultParams: Props) => Props) => {
32
32
  });
33
33
 
34
34
  return (
35
- <>
35
+ <Fragment>
36
36
  <button data-testid="button" onClick={calculatePosition} ref={relativeElement}>
37
37
  Test
38
38
  </button>
@@ -44,7 +44,7 @@ const createPopover = (params?: (defaultParams: Props) => Props) => {
44
44
  >
45
45
  Test
46
46
  </Popover>
47
- </>
47
+ </Fragment>
48
48
  );
49
49
  };
50
50
 
@@ -1,8 +1,8 @@
1
- import React, { forwardRef, HTMLProps, ReactNode, RefObject, useEffect, useRef } from 'react';
1
+ import React, { ComponentPropsWithRef, ReactNode, RefObject, useEffect, useRef } from 'react';
2
2
  import { usePosition, Offset, Placement } from '../hooks/usePosition';
3
3
  import classes from './Popover.module.scss';
4
4
 
5
- export interface Props extends HTMLProps<HTMLDivElement> {
5
+ export interface Props extends ComponentPropsWithRef<'div'> {
6
6
  children?: ReactNode;
7
7
  show?: boolean;
8
8
  anchorEl?: RefObject<HTMLOrSVGElement>;
@@ -11,7 +11,7 @@ export interface Props extends HTMLProps<HTMLDivElement> {
11
11
  transformOrigin?: Placement;
12
12
  }
13
13
 
14
- export const Popover = forwardRef<HTMLDivElement, Props>(
14
+ export const Popover = React.forwardRef<HTMLDivElement, Props>(
15
15
  ({ children, className, show, placement, offset, transformOrigin, anchorEl, ...rest }, ref) => {
16
16
  const elToBePositioned = useRef<HTMLDivElement>(null);
17
17
 
@@ -0,0 +1,71 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+ import { Tabs } from './Tabs';
3
+ import { Tab, Props } from './Tab';
4
+ import { render } from '@testing-library/react';
5
+
6
+ const defaultParams: Props = {
7
+ title: 'Title of tab',
8
+ };
9
+
10
+ const createTab = (params?: (defaultParams: Props) => Props) => {
11
+ let parameters: Props = defaultParams;
12
+ if (params) {
13
+ parameters = params(defaultParams);
14
+ }
15
+ const queries = render(
16
+ <Tab {...parameters} data-testid="tab">
17
+ tab content
18
+ </Tab>
19
+ );
20
+ const tab = queries.getByTestId('tab');
21
+
22
+ return {
23
+ ...queries,
24
+ tab,
25
+ };
26
+ };
27
+
28
+ describe('Tab should render', () => {
29
+ it('renders without crashing', () => {
30
+ const { tab } = createTab();
31
+
32
+ expect(tab).toBeTruthy();
33
+ });
34
+ });
35
+
36
+ describe('Tab useRef should work for panel and button', () => {
37
+ it('gives us back the proper refs', () => {
38
+ type logRefsFunction = (
39
+ buttonRef: React.RefObject<HTMLButtonElement>,
40
+ panelRef: React.RefObject<HTMLDivElement>
41
+ ) => void;
42
+ const ExampleComponent = ({ logRefs }: { logRefs: logRefsFunction }) => {
43
+ const ref1 = useRef<HTMLButtonElement>(null);
44
+ const ref2 = useRef<HTMLDivElement>(null);
45
+
46
+ useEffect(() => {
47
+ if (ref1.current && ref2.current) {
48
+ logRefs(ref1, ref2);
49
+ }
50
+ }, [ref1, ref2]);
51
+
52
+ return (
53
+ <Tabs>
54
+ <Tab buttonRef={ref1} panelRef={ref2} title="ShouldBeButtonRef">
55
+ <span>Should be panel ref</span>
56
+ </Tab>
57
+ </Tabs>
58
+ );
59
+ };
60
+
61
+ const setCorrectText = (
62
+ buttonRef: React.RefObject<HTMLButtonElement>,
63
+ panelRef: React.RefObject<HTMLDivElement>
64
+ ) => {
65
+ expect(buttonRef.current?.innerHTML).toContain('ShouldBeButtonRef');
66
+ expect(panelRef.current?.innerHTML).toEqual('<span>Should be panel ref</span>');
67
+ };
68
+
69
+ render(<ExampleComponent logRefs={setCorrectText} />);
70
+ });
71
+ });
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+
3
+ export interface Props {
4
+ title: string;
5
+ children?: React.ReactNode;
6
+ selected?: boolean;
7
+ focussed?: boolean;
8
+ buttonRef?: React.RefObject<HTMLButtonElement>;
9
+ panelRef?: React.RefObject<HTMLDivElement>;
10
+ onTabButtonClick?: () => void;
11
+ }
12
+
13
+ export const Tab = (args: Props) => {
14
+ return (
15
+ <div {...args}>{`A <Tab /> component should only be used inside the <Tabs /> component.`}</div>
16
+ );
17
+ };
@@ -0,0 +1,36 @@
1
+ .tabbutton {
2
+ border: 0;
3
+ border-radius: 0;
4
+ font-size: var(--font-size);
5
+ line-height: 1.5;
6
+ margin: 0;
7
+ padding: 0.25rem 0 1rem 0;
8
+ min-height: 2.5rem;
9
+ cursor: pointer;
10
+ font-family: var(--font-family);
11
+ background-color: transparent;
12
+ white-space: nowrap;
13
+ position: relative;
14
+ font-weight: bold;
15
+ color: transparent;
16
+
17
+ &.focussed:not(:focus-visible) {
18
+ outline: none;
19
+ }
20
+
21
+ span {
22
+ color: var(--tab-text-color);
23
+ font-weight: normal;
24
+ position: absolute;
25
+ left: 0;
26
+ }
27
+
28
+ &.selected {
29
+ color: var(--tab-text-color);
30
+
31
+ span {
32
+ color: transparent;
33
+ visibility: hidden;
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,77 @@
1
+ import React from 'react';
2
+ import { Props, TabButton } from './TabButton';
3
+ import { render } from '@testing-library/react';
4
+
5
+ const defaultParams: Props = {};
6
+
7
+ const createTabButton = (params?: (defaultParams: Props) => Props) => {
8
+ let parameters: Props = defaultParams;
9
+ if (params) {
10
+ parameters = params(defaultParams);
11
+ }
12
+ const queries = render(
13
+ <TabButton {...parameters} data-testid="tabbutton">
14
+ tab content
15
+ </TabButton>
16
+ );
17
+ const tabButton = queries.getByTestId('tabbutton');
18
+
19
+ return {
20
+ ...queries,
21
+ tabButton,
22
+ };
23
+ };
24
+
25
+ describe('Tab should render', () => {
26
+ it('renders without crashing', () => {
27
+ const { tabButton } = createTabButton();
28
+
29
+ expect(tabButton).toBeTruthy();
30
+ });
31
+
32
+ it('should be selected when prop selected is passed', () => {
33
+ const { tabButton } = createTabButton((defaultParams) => ({
34
+ ...defaultParams,
35
+ selected: true,
36
+ }));
37
+
38
+ expect(tabButton).toHaveAttribute('aria-selected', 'true');
39
+ expect(tabButton).toHaveAttribute('tabIndex', '0');
40
+ });
41
+
42
+ it('should be focussed when prop focussed is passed', () => {
43
+ const { tabButton } = createTabButton((defaultParams) => ({
44
+ ...defaultParams,
45
+ focussed: true,
46
+ }));
47
+
48
+ expect(tabButton).toHaveClass('focussed');
49
+ });
50
+
51
+ it('should set accessibility attributes when prop tabPanelId is passed', () => {
52
+ const { tabButton } = createTabButton((defaultParams) => ({
53
+ ...defaultParams,
54
+ tabPanelId: 'fakeId',
55
+ }));
56
+
57
+ expect(tabButton).toHaveAttribute('aria-controls', 'fakeId');
58
+ });
59
+
60
+ it('should set id attribute when prop tabId is passed', () => {
61
+ const { tabButton } = createTabButton((defaultParams) => ({
62
+ ...defaultParams,
63
+ tabId: 'fakeId',
64
+ }));
65
+
66
+ expect(tabButton).toHaveAttribute('id', 'fakeId');
67
+ });
68
+
69
+ it('should set class when prop className is passed', () => {
70
+ const { tabButton } = createTabButton((defaultParams) => ({
71
+ ...defaultParams,
72
+ className: 'customclass',
73
+ }));
74
+
75
+ expect(tabButton).toHaveClass('customclass');
76
+ });
77
+ });
@@ -0,0 +1,58 @@
1
+ import React, { ComponentPropsWithRef, useEffect } from 'react';
2
+ import classes from './TabButton.module.scss';
3
+
4
+ export interface Props extends ComponentPropsWithRef<'button'> {
5
+ children?: string;
6
+ selected?: boolean;
7
+ focussed?: boolean;
8
+ tabId?: string;
9
+ tabPanelId?: string;
10
+ onTabButtonClick?: () => void;
11
+ }
12
+
13
+ export const TabButton = React.forwardRef<HTMLButtonElement, Props>(
14
+ (
15
+ {
16
+ children,
17
+ selected = false,
18
+ focussed = false,
19
+ tabId,
20
+ tabPanelId,
21
+ className,
22
+ onTabButtonClick,
23
+ ...rest
24
+ }: Props,
25
+ ref
26
+ ) => {
27
+ useEffect(() => {
28
+ if (focussed && ref) {
29
+ (ref as React.MutableRefObject<HTMLButtonElement>).current.focus();
30
+ }
31
+ }, [focussed]);
32
+
33
+ const classNames = [classes['tabbutton']];
34
+
35
+ selected && classNames.push(classes['selected']);
36
+ focussed && !selected && classNames.push(classes['focussed']);
37
+ className && classNames.push(className);
38
+
39
+ return (
40
+ <button
41
+ {...rest}
42
+ aria-selected={selected}
43
+ key={tabId}
44
+ className={classNames.join(' ')}
45
+ ref={ref}
46
+ role="tab"
47
+ tabIndex={selected ? 0 : -1}
48
+ type="button"
49
+ aria-controls={tabPanelId}
50
+ id={tabId}
51
+ onClick={onTabButtonClick}
52
+ >
53
+ <span aria-hidden="true">{children}</span>
54
+ {children}
55
+ </button>
56
+ );
57
+ }
58
+ );
@@ -0,0 +1,7 @@
1
+ .tabpanel {
2
+ display: none;
3
+
4
+ &.selected {
5
+ display: block;
6
+ }
7
+ }
@@ -0,0 +1,76 @@
1
+ import React from 'react';
2
+ import { TabPanel, Props } from './TabPanel';
3
+ import { render } from '@testing-library/react';
4
+
5
+ const defaultParams: Props = {
6
+ tabId: 'fakeTabId',
7
+ tabPanelId: 'fakeTabPanelId',
8
+ children: [],
9
+ };
10
+
11
+ const createTabPanel = (params?: (defaultParams: Props) => Props) => {
12
+ let parameters: Props = defaultParams;
13
+ if (params) {
14
+ parameters = params(defaultParams);
15
+ }
16
+ const queries = render(
17
+ <TabPanel {...parameters} data-testid="tabpanel">
18
+ tabpanel content
19
+ </TabPanel>
20
+ );
21
+ const tabpanel = queries.getByTestId('tabpanel');
22
+
23
+ return {
24
+ ...queries,
25
+ tabpanel,
26
+ };
27
+ };
28
+
29
+ describe('TabPanel should render', () => {
30
+ it('renders without crashing', () => {
31
+ const { tabpanel } = createTabPanel();
32
+
33
+ expect(tabpanel).toBeTruthy();
34
+
35
+ expect(tabpanel).toHaveAttribute('aria-hidden', 'true');
36
+ expect(tabpanel).toHaveAttribute('hidden');
37
+ });
38
+
39
+ it('should be visible when prop selected is passed', () => {
40
+ const { tabpanel } = createTabPanel((defaultParams) => ({
41
+ ...defaultParams,
42
+ selected: true,
43
+ }));
44
+
45
+ expect(tabpanel).toHaveClass('selected');
46
+ expect(tabpanel).toHaveAttribute('aria-hidden', 'false');
47
+ expect(tabpanel).not.toHaveAttribute('hidden');
48
+ });
49
+
50
+ it('should set id when prop tabPanelId is passed', () => {
51
+ const { tabpanel } = createTabPanel((defaultParams) => ({
52
+ ...defaultParams,
53
+ tabPanelId: 'fakeId',
54
+ }));
55
+
56
+ expect(tabpanel).toHaveAttribute('id', 'fakeId');
57
+ });
58
+
59
+ it('should set accessibility attributes when prop tabId is passed', () => {
60
+ const { tabpanel } = createTabPanel((defaultParams) => ({
61
+ ...defaultParams,
62
+ tabId: 'fakeId',
63
+ }));
64
+
65
+ expect(tabpanel).toHaveAttribute('aria-labelledby', 'fakeId');
66
+ });
67
+
68
+ it('should set class when prop className is passed', () => {
69
+ const { tabpanel } = createTabPanel((defaultParams) => ({
70
+ ...defaultParams,
71
+ className: 'customclass',
72
+ }));
73
+
74
+ expect(tabpanel).toHaveClass('customclass');
75
+ });
76
+ });
@@ -0,0 +1,27 @@
1
+ import React, { ComponentPropsWithRef } from 'react';
2
+ import classes from './TabPanel.module.scss';
3
+
4
+ export interface Props extends ComponentPropsWithRef<'div'> {
5
+ children: React.ReactNode;
6
+ tabId: string;
7
+ tabPanelId: string;
8
+ selected?: boolean;
9
+ }
10
+
11
+ export const TabPanel = React.forwardRef<HTMLDivElement, Props>(
12
+ ({ children, tabId, tabPanelId, selected = false, className, ...rest }: Props, ref) => (
13
+ <div
14
+ {...rest}
15
+ ref={ref}
16
+ aria-labelledby={tabId}
17
+ className={`${classes['tabpanel']} ${selected ? classes['selected'] : ''} ${className ?? ''}`}
18
+ id={tabPanelId}
19
+ role="tabpanel"
20
+ tabIndex={0}
21
+ hidden={!selected || undefined}
22
+ aria-hidden={!selected}
23
+ >
24
+ {children}
25
+ </div>
26
+ )
27
+ );
@@ -0,0 +1,41 @@
1
+ $focus-width: 5px;
2
+
3
+ .tabs {
4
+ background-color: var(--tabs-background-color);
5
+ padding: 1rem 1.25rem;
6
+ border-radius: 0.5rem;
7
+ display: flex;
8
+ flex-direction: column;
9
+ gap: 1rem;
10
+ }
11
+
12
+ .tablist {
13
+ display: flex;
14
+ flex-wrap: nowrap;
15
+ overflow-x: auto;
16
+ gap: 2rem;
17
+ position: relative;
18
+ margin: -$focus-width;
19
+ padding: $focus-width;
20
+ z-index: 0;
21
+ }
22
+
23
+ .indicator {
24
+ position: absolute;
25
+ height: 2px;
26
+ background-color: var(--color-primary);
27
+ transition-property: left, width;
28
+ transition-duration: 0.2s;
29
+ transition-timing-function: ease-in-out;
30
+ }
31
+
32
+ .tabdivider {
33
+ border-bottom-style: var(--tablist-border-style);
34
+ border-bottom-width: var(--tablist-border-width);
35
+ border-bottom-color: var(--tablist-border-color);
36
+ width: calc(100% - ($focus-width * 2));
37
+ position: absolute;
38
+ bottom: $focus-width;
39
+ left: $focus-width;
40
+ z-index: -1;
41
+ }