@hyphen/hyphen-components 2.9.0

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 (319) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +70 -0
  3. package/package.json +138 -0
  4. package/src/components/Alert/Alert.constants.ts +19 -0
  5. package/src/components/Alert/Alert.mdx +29 -0
  6. package/src/components/Alert/Alert.module.scss +74 -0
  7. package/src/components/Alert/Alert.stories.tsx +102 -0
  8. package/src/components/Alert/Alert.test.tsx +187 -0
  9. package/src/components/Alert/Alert.tsx +157 -0
  10. package/src/components/Alert/Alert.types.ts +14 -0
  11. package/src/components/Badge/Badge.mdx +28 -0
  12. package/src/components/Badge/Badge.module.scss +155 -0
  13. package/src/components/Badge/Badge.stories.tsx +52 -0
  14. package/src/components/Badge/Badge.test.tsx +74 -0
  15. package/src/components/Badge/Badge.tsx +70 -0
  16. package/src/components/Box/Box.mdx +259 -0
  17. package/src/components/Box/Box.module.scss +16 -0
  18. package/src/components/Box/Box.stories.tsx +1679 -0
  19. package/src/components/Box/Box.test.tsx +478 -0
  20. package/src/components/Box/Box.tsx +636 -0
  21. package/src/components/Button/Button.constants.ts +10 -0
  22. package/src/components/Button/Button.mdx +71 -0
  23. package/src/components/Button/Button.module.scss +312 -0
  24. package/src/components/Button/Button.stories.tsx +117 -0
  25. package/src/components/Button/Button.test.tsx +460 -0
  26. package/src/components/Button/Button.tsx +241 -0
  27. package/src/components/Card/Card.mdx +46 -0
  28. package/src/components/Card/Card.module.scss +6 -0
  29. package/src/components/Card/Card.stories.tsx +101 -0
  30. package/src/components/Card/Card.test.tsx +11 -0
  31. package/src/components/Card/Card.tsx +61 -0
  32. package/src/components/Card/components/CardFooter/CardFooter.test.tsx +11 -0
  33. package/src/components/Card/components/CardFooter/CardFooter.tsx +35 -0
  34. package/src/components/Card/components/CardHeader/CardHeader.test.tsx +23 -0
  35. package/src/components/Card/components/CardHeader/CardHeader.tsx +54 -0
  36. package/src/components/Card/components/CardSection/CardSection.test.tsx +28 -0
  37. package/src/components/Card/components/CardSection/CardSection.tsx +102 -0
  38. package/src/components/Card/components/index.ts +3 -0
  39. package/src/components/CheckboxInput/CheckboxInput.mdx +98 -0
  40. package/src/components/CheckboxInput/CheckboxInput.stories.tsx +254 -0
  41. package/src/components/CheckboxInput/CheckboxInput.test.tsx +436 -0
  42. package/src/components/CheckboxInput/CheckboxInput.tsx +171 -0
  43. package/src/components/CheckboxInput/components/Checkbox.module.scss +174 -0
  44. package/src/components/CheckboxInput/components/Checkbox.test.tsx +201 -0
  45. package/src/components/CheckboxInput/components/Checkbox.tsx +176 -0
  46. package/src/components/CheckboxInput/components/CheckboxIcon.tsx +71 -0
  47. package/src/components/DateInput/DateInput.mdx +61 -0
  48. package/src/components/DateInput/DateInput.stories.tsx +168 -0
  49. package/src/components/DateInput/DateInput.test.tsx +258 -0
  50. package/src/components/DateInput/DateInput.tsx +189 -0
  51. package/src/components/DatePicker/DatePicker.mdx +52 -0
  52. package/src/components/DatePicker/DatePicker.module.scss +603 -0
  53. package/src/components/DatePicker/DatePicker.stories.tsx +199 -0
  54. package/src/components/DatePicker/DatePicker.test.tsx +26 -0
  55. package/src/components/DatePicker/DatePicker.tsx +138 -0
  56. package/src/components/Details/Details.mdx +30 -0
  57. package/src/components/Details/Details.module.scss +32 -0
  58. package/src/components/Details/Details.stories.tsx +38 -0
  59. package/src/components/Details/Details.test.tsx +189 -0
  60. package/src/components/Details/Details.tsx +51 -0
  61. package/src/components/Details/DetailsSummary.tsx +65 -0
  62. package/src/components/Drawer/Drawer.mdx +117 -0
  63. package/src/components/Drawer/Drawer.module.scss +96 -0
  64. package/src/components/Drawer/Drawer.stories.tsx +380 -0
  65. package/src/components/Drawer/Drawer.test.tsx +90 -0
  66. package/src/components/Drawer/Drawer.tsx +249 -0
  67. package/src/components/FormControl/FormControl.tsx +78 -0
  68. package/src/components/FormLabel/FormLabel.mdx +24 -0
  69. package/src/components/FormLabel/FormLabel.module.scss +19 -0
  70. package/src/components/FormLabel/FormLabel.stories.tsx +20 -0
  71. package/src/components/FormLabel/FormLabel.test.tsx +35 -0
  72. package/src/components/FormLabel/FormLabel.tsx +96 -0
  73. package/src/components/Formik/Formik.mdx +10 -0
  74. package/src/components/Formik/Formik.stories.tsx +307 -0
  75. package/src/components/Formik/FormikCheckboxInput/FormikCheckboxInput.test.tsx +172 -0
  76. package/src/components/Formik/FormikCheckboxInput/FormikCheckboxInput.tsx +41 -0
  77. package/src/components/Formik/FormikRadioGroup/FormikRadioGroup.test.tsx +205 -0
  78. package/src/components/Formik/FormikRadioGroup/FormikRadioGroup.tsx +37 -0
  79. package/src/components/Formik/FormikSelectInput/FormikSelectInput.test.tsx +210 -0
  80. package/src/components/Formik/FormikSelectInput/FormikSelectInput.tsx +41 -0
  81. package/src/components/Formik/FormikSelectInputInset/FormikSelectInputInset.test.tsx +153 -0
  82. package/src/components/Formik/FormikSelectInputInset/FormikSelectInputInset.tsx +44 -0
  83. package/src/components/Formik/FormikSelectInputNative/FormikSelectInputNative.test.tsx +161 -0
  84. package/src/components/Formik/FormikSelectInputNative/FormikSelectInputNative.tsx +46 -0
  85. package/src/components/Formik/FormikTextInput/FormikTextInput.test.tsx +176 -0
  86. package/src/components/Formik/FormikTextInput/FormikTextInput.tsx +38 -0
  87. package/src/components/Formik/FormikTextInputInset/FormikTextInputInset.test.tsx +170 -0
  88. package/src/components/Formik/FormikTextInputInset/FormikTextInputInset.tsx +42 -0
  89. package/src/components/Formik/FormikTextareaInput/FormikTextareaInput.test.tsx +186 -0
  90. package/src/components/Formik/FormikTextareaInput/FormikTextareaInput.tsx +42 -0
  91. package/src/components/Formik/FormikTextareaInputInset/FormikTextareaInputInset.test.tsx +179 -0
  92. package/src/components/Formik/FormikTextareaInputInset/FormikTextareaInputInset.tsx +42 -0
  93. package/src/components/Formik/FormikTimePicker/FormikTimePicker.test.tsx +224 -0
  94. package/src/components/Formik/FormikTimePicker/FormikTimePicker.tsx +37 -0
  95. package/src/components/Formik/FormikTimePickerNative/FormikTimePickerNative.test.tsx +175 -0
  96. package/src/components/Formik/FormikTimePickerNative/FormikTimePickerNative.tsx +38 -0
  97. package/src/components/Formik/FormikToggle/FormikToggle.test.tsx +172 -0
  98. package/src/components/Formik/FormikToggle/FormikToggle.tsx +38 -0
  99. package/src/components/Heading/Heading.constants.ts +19 -0
  100. package/src/components/Heading/Heading.mdx +35 -0
  101. package/src/components/Heading/Heading.module.scss +5 -0
  102. package/src/components/Heading/Heading.stories.tsx +90 -0
  103. package/src/components/Heading/Heading.test.tsx +67 -0
  104. package/src/components/Heading/Heading.tsx +67 -0
  105. package/src/components/HelpText/HelpText.module.scss +14 -0
  106. package/src/components/HelpText/HelpText.tsx +33 -0
  107. package/src/components/Icon/Icon.mdx +40 -0
  108. package/src/components/Icon/Icon.stories.tsx +72 -0
  109. package/src/components/Icon/Icon.test.tsx +30 -0
  110. package/src/components/Icon/Icon.tsx +61 -0
  111. package/src/components/InputValidationMessage/InputValidationMessage.module.scss +3 -0
  112. package/src/components/InputValidationMessage/InputValidationMessage.tsx +27 -0
  113. package/src/components/Modal/Modal.mdx +60 -0
  114. package/src/components/Modal/Modal.module.scss +135 -0
  115. package/src/components/Modal/Modal.stories.tsx +194 -0
  116. package/src/components/Modal/Modal.test.tsx +81 -0
  117. package/src/components/Modal/Modal.tsx +174 -0
  118. package/src/components/Modal/components/ModalBody/ModalBody.test.tsx +20 -0
  119. package/src/components/Modal/components/ModalBody/ModalBody.tsx +24 -0
  120. package/src/components/Modal/components/ModalFooter/ModalFooter.test.tsx +32 -0
  121. package/src/components/Modal/components/ModalFooter/ModalFooter.tsx +37 -0
  122. package/src/components/Modal/components/ModalHeader/ModalHeader.test.tsx +29 -0
  123. package/src/components/Modal/components/ModalHeader/ModalHeader.tsx +58 -0
  124. package/src/components/Modal/components/index.ts +5 -0
  125. package/src/components/Pagination/Pagination.mdx +26 -0
  126. package/src/components/Pagination/Pagination.stories.tsx +55 -0
  127. package/src/components/Pagination/Pagination.test.tsx +225 -0
  128. package/src/components/Pagination/Pagination.tsx +162 -0
  129. package/src/components/Pagination/Pagination.utilities.test.ts +133 -0
  130. package/src/components/Pagination/Pagination.utilities.ts +101 -0
  131. package/src/components/Popover/Popover.mdx +104 -0
  132. package/src/components/Popover/Popover.module.scss +74 -0
  133. package/src/components/Popover/Popover.stories.tsx +471 -0
  134. package/src/components/Popover/Popover.test.tsx +128 -0
  135. package/src/components/Popover/Popover.tsx +277 -0
  136. package/src/components/RadioGroup/RadioGroup.mdx +81 -0
  137. package/src/components/RadioGroup/RadioGroup.module.scss +23 -0
  138. package/src/components/RadioGroup/RadioGroup.stories.tsx +375 -0
  139. package/src/components/RadioGroup/RadioGroup.test.tsx +282 -0
  140. package/src/components/RadioGroup/RadioGroup.tsx +145 -0
  141. package/src/components/RadioGroup/RadioInput/RadioInput.module.scss +114 -0
  142. package/src/components/RadioGroup/RadioInput/RadioInput.test.tsx +156 -0
  143. package/src/components/RadioGroup/RadioInput/RadioInput.tsx +148 -0
  144. package/src/components/RadioGroup/RadioInput/RadioInputIcon.tsx +59 -0
  145. package/src/components/ResponsiveProvider/ResponsiveProvider.mdx +36 -0
  146. package/src/components/ResponsiveProvider/ResponsiveProvider.stories.tsx +54 -0
  147. package/src/components/ResponsiveProvider/ResponsiveProvider.test.tsx +70 -0
  148. package/src/components/ResponsiveProvider/ResponsiveProvider.tsx +73 -0
  149. package/src/components/SelectInput/SelectInput.mdx +115 -0
  150. package/src/components/SelectInput/SelectInput.module.scss +357 -0
  151. package/src/components/SelectInput/SelectInput.stories.tsx +373 -0
  152. package/src/components/SelectInput/SelectInput.test.tsx +403 -0
  153. package/src/components/SelectInput/SelectInput.tsx +245 -0
  154. package/src/components/SelectInputInset/SelectInputInset.mdx +56 -0
  155. package/src/components/SelectInputInset/SelectInputInset.module.scss +397 -0
  156. package/src/components/SelectInputInset/SelectInputInset.stories.tsx +189 -0
  157. package/src/components/SelectInputInset/SelectInputInset.test.tsx +305 -0
  158. package/src/components/SelectInputInset/SelectInputInset.tsx +235 -0
  159. package/src/components/SelectInputNative/SelectInputNative.mdx +87 -0
  160. package/src/components/SelectInputNative/SelectInputNative.module.scss +356 -0
  161. package/src/components/SelectInputNative/SelectInputNative.stories.tsx +282 -0
  162. package/src/components/SelectInputNative/SelectInputNative.test.tsx +341 -0
  163. package/src/components/SelectInputNative/SelectInputNative.tsx +121 -0
  164. package/src/components/Spinner/Spinner.mdx +29 -0
  165. package/src/components/Spinner/Spinner.module.scss +16 -0
  166. package/src/components/Spinner/Spinner.stories.tsx +48 -0
  167. package/src/components/Spinner/Spinner.test.tsx +47 -0
  168. package/src/components/Spinner/Spinner.tsx +116 -0
  169. package/src/components/Table/Table.mdx +216 -0
  170. package/src/components/Table/Table.module.scss +61 -0
  171. package/src/components/Table/Table.stories.tsx +884 -0
  172. package/src/components/Table/Table.test.tsx +437 -0
  173. package/src/components/Table/Table.tsx +171 -0
  174. package/src/components/Table/TableBody/TableBody.module.scss +19 -0
  175. package/src/components/Table/TableBody/TableBody.test.tsx +38 -0
  176. package/src/components/Table/TableBody/TableBody.tsx +96 -0
  177. package/src/components/Table/TableBody/TableBodyCell/TableBodyCell.module.scss +47 -0
  178. package/src/components/Table/TableBody/TableBodyCell/TableBodyCell.test.tsx +81 -0
  179. package/src/components/Table/TableBody/TableBodyCell/TableBodyCell.tsx +94 -0
  180. package/src/components/Table/TableHead/TableHead.test.tsx +20 -0
  181. package/src/components/Table/TableHead/TableHead.tsx +78 -0
  182. package/src/components/Table/TableHead/TableHeaderCell/TableHeaderCell.module.scss +72 -0
  183. package/src/components/Table/TableHead/TableHeaderCell/TableHeaderCell.test.tsx +187 -0
  184. package/src/components/Table/TableHead/TableHeaderCell/TableHeaderCell.tsx +192 -0
  185. package/src/components/Table/common/TableRow/TableRow.module.scss +5 -0
  186. package/src/components/Table/common/TableRow/TableRow.test.tsx +52 -0
  187. package/src/components/Table/common/TableRow/TableRow.tsx +155 -0
  188. package/src/components/TextInput/TextInput.mdx +96 -0
  189. package/src/components/TextInput/TextInput.module.scss +405 -0
  190. package/src/components/TextInput/TextInput.stories.tsx +268 -0
  191. package/src/components/TextInput/TextInput.test.tsx +231 -0
  192. package/src/components/TextInput/TextInput.tsx +263 -0
  193. package/src/components/TextInputInset/TextInputInset.mdx +62 -0
  194. package/src/components/TextInputInset/TextInputInset.module.scss +418 -0
  195. package/src/components/TextInputInset/TextInputInset.stories.tsx +213 -0
  196. package/src/components/TextInputInset/TextInputInset.test.tsx +222 -0
  197. package/src/components/TextInputInset/TextInputInset.tsx +261 -0
  198. package/src/components/TextareaInput/TextareaInput.mdx +117 -0
  199. package/src/components/TextareaInput/TextareaInput.module.scss +275 -0
  200. package/src/components/TextareaInput/TextareaInput.stories.tsx +293 -0
  201. package/src/components/TextareaInput/TextareaInput.test.tsx +195 -0
  202. package/src/components/TextareaInput/TextareaInput.tsx +182 -0
  203. package/src/components/TextareaInputInset/TextareaInputInset.mdx +55 -0
  204. package/src/components/TextareaInputInset/TextareaInputInset.module.scss +337 -0
  205. package/src/components/TextareaInputInset/TextareaInputInset.stories.tsx +160 -0
  206. package/src/components/TextareaInputInset/TextareaInputInset.test.tsx +199 -0
  207. package/src/components/TextareaInputInset/TextareaInputInset.tsx +213 -0
  208. package/src/components/ThemeProvider/ThemeProvider.mdx +11 -0
  209. package/src/components/ThemeProvider/ThemeProvider.stories.tsx +56 -0
  210. package/src/components/ThemeProvider/ThemeProvider.tsx +75 -0
  211. package/src/components/TimePicker/TimePicker.mdx +75 -0
  212. package/src/components/TimePicker/TimePicker.stories.tsx +149 -0
  213. package/src/components/TimePicker/TimePicker.test.tsx +97 -0
  214. package/src/components/TimePicker/TimePicker.tsx +83 -0
  215. package/src/components/TimePickerNative/TimePickerNative.mdx +67 -0
  216. package/src/components/TimePickerNative/TimePickerNative.stories.tsx +151 -0
  217. package/src/components/TimePickerNative/TimePickerNative.test.tsx +117 -0
  218. package/src/components/TimePickerNative/TimePickerNative.tsx +93 -0
  219. package/src/components/Toast/Toast.mdx +134 -0
  220. package/src/components/Toast/Toast.store.ts +280 -0
  221. package/src/components/Toast/Toast.stories.tsx +283 -0
  222. package/src/components/Toast/Toast.test.tsx +784 -0
  223. package/src/components/Toast/Toast.types.ts +98 -0
  224. package/src/components/Toast/ToastContainer.tsx +170 -0
  225. package/src/components/Toast/ToastNotification.module.scss +63 -0
  226. package/src/components/Toast/ToastNotification.tsx +176 -0
  227. package/src/components/Toast/index.ts +4 -0
  228. package/src/components/Toast/toast.ts +102 -0
  229. package/src/components/Toast/useToasts.ts +102 -0
  230. package/src/components/Toggle/Toggle.mdx +51 -0
  231. package/src/components/Toggle/Toggle.module.scss +294 -0
  232. package/src/components/Toggle/Toggle.stories.tsx +128 -0
  233. package/src/components/Toggle/Toggle.test.tsx +308 -0
  234. package/src/components/Toggle/Toggle.tsx +184 -0
  235. package/src/constants/keyCodes.ts +2 -0
  236. package/src/docs/Brands.mdx +153 -0
  237. package/src/docs/Colors.mdx +158 -0
  238. package/src/docs/DesignTokens.mdx +415 -0
  239. package/src/docs/GetStarted.mdx +47 -0
  240. package/src/docs/intro.mdx +12 -0
  241. package/src/fonts/AvenirBold.otf +0 -0
  242. package/src/fonts/AvenirBold.woff +0 -0
  243. package/src/fonts/AvenirBold.woff2 +0 -0
  244. package/src/fonts/AvenirLight.otf +0 -0
  245. package/src/fonts/AvenirLight.woff +0 -0
  246. package/src/fonts/AvenirLight.woff2 +0 -0
  247. package/src/fonts/AvenirRegular.otf +0 -0
  248. package/src/fonts/AvenirRegular.woff +0 -0
  249. package/src/fonts/AvenirRegular.woff2 +0 -0
  250. package/src/fonts/Geist-Bold.otf +0 -0
  251. package/src/fonts/Geist-Bold.woff +0 -0
  252. package/src/fonts/Geist-Bold.woff2 +0 -0
  253. package/src/fonts/Geist-Medium.otf +0 -0
  254. package/src/fonts/Geist-Medium.woff +0 -0
  255. package/src/fonts/Geist-Medium.woff2 +0 -0
  256. package/src/fonts/Geist-Regular.otf +0 -0
  257. package/src/fonts/Geist-Regular.woff +0 -0
  258. package/src/fonts/Geist-Regular.woff2 +0 -0
  259. package/src/fonts/Geist-SemiBold.otf +0 -0
  260. package/src/fonts/Geist-SemiBold.woff +0 -0
  261. package/src/fonts/Geist-SemiBold.woff2 +0 -0
  262. package/src/fonts/GeistMono-Regular.otf +0 -0
  263. package/src/fonts/GeistMono-Regular.woff +0 -0
  264. package/src/fonts/GeistMono-Regular.woff2 +0 -0
  265. package/src/hooks/index.ts +4 -0
  266. package/src/hooks/useBreakpoint/useBreakpoint.mdx +26 -0
  267. package/src/hooks/useBreakpoint/useBreakpoint.stories.tsx +30 -0
  268. package/src/hooks/useBreakpoint/useBreakpoint.test.tsx +19 -0
  269. package/src/hooks/useBreakpoint/useBreakpoint.ts +50 -0
  270. package/src/hooks/useIsomorphicLayoutEffect/useIsomorphicLayouEffect.ts +5 -0
  271. package/src/hooks/useOpenClose/useOpenClose.mdx +15 -0
  272. package/src/hooks/useOpenClose/useOpenClose.stories.tsx +41 -0
  273. package/src/hooks/useOpenClose/useOpenClose.test.tsx +119 -0
  274. package/src/hooks/useOpenClose/useOpenClose.tsx +95 -0
  275. package/src/hooks/useWindowSize/useWindowSize.mdx +25 -0
  276. package/src/hooks/useWindowSize/useWindowSize.stories.tsx +35 -0
  277. package/src/hooks/useWindowSize/useWindowSize.ts +24 -0
  278. package/src/index.ts +48 -0
  279. package/src/lib/cssShorthandToClasses.test.ts +149 -0
  280. package/src/lib/cssShorthandToClasses.ts +133 -0
  281. package/src/lib/doesStringIncludeCssUnit.ts +6 -0
  282. package/src/lib/generateResponsiveClasses.test.ts +24 -0
  283. package/src/lib/generateResponsiveClasses.ts +30 -0
  284. package/src/lib/getAutoCompleteValue.test.ts +27 -0
  285. package/src/lib/getAutoCompleteValue.ts +12 -0
  286. package/src/lib/getColumnKeys.ts +27 -0
  287. package/src/lib/getDimensionCss.test.ts +148 -0
  288. package/src/lib/getDimensionCss.ts +73 -0
  289. package/src/lib/getElementType.test.tsx +42 -0
  290. package/src/lib/getElementType.ts +42 -0
  291. package/src/lib/getFlexCss.test.ts +122 -0
  292. package/src/lib/getFlexCss.ts +67 -0
  293. package/src/lib/index.ts +15 -0
  294. package/src/lib/isFunction.ts +6 -0
  295. package/src/lib/mergeRefs.ts +15 -0
  296. package/src/lib/prefersReducedMotion.ts +12 -0
  297. package/src/lib/react-children-utilities/filter.ts +12 -0
  298. package/src/lib/react-children-utilities/index.ts +1 -0
  299. package/src/lib/reactRouterClickHandler.ts +37 -0
  300. package/src/lib/resolveValue.ts +7 -0
  301. package/src/lib/tokens.ts +139 -0
  302. package/src/modes.ts +8 -0
  303. package/src/styles/animation.scss +152 -0
  304. package/src/styles/cursor.scss +43 -0
  305. package/src/styles/display.scss +119 -0
  306. package/src/styles/flex.scss +453 -0
  307. package/src/styles/fonts.scss +44 -0
  308. package/src/styles/globals/utilities.scss +4 -0
  309. package/src/styles/mixins.scss +14 -0
  310. package/src/styles/overflow.scss +41 -0
  311. package/src/styles/position.scss +45 -0
  312. package/src/styles/reset.scss +108 -0
  313. package/src/styles/text-align.scss +21 -0
  314. package/src/styles/utilities.scss +9 -0
  315. package/src/styles/variables/forms.scss +71 -0
  316. package/src/styles/variables/index.scss +3 -0
  317. package/src/styles/white-space.scss +21 -0
  318. package/src/types/index.ts +201 -0
  319. package/src/types/lib.types.ts +3 -0
@@ -0,0 +1,784 @@
1
+ import {
2
+ act,
3
+ cleanup,
4
+ fireEvent,
5
+ render,
6
+ screen,
7
+ waitFor,
8
+ } from '@testing-library/react';
9
+ import React, { ReactNode } from 'react';
10
+ import { ToastPosition } from '.';
11
+ import { toast } from './toast';
12
+ import { ToastContainer } from './ToastContainer';
13
+
14
+ Object.defineProperty(window, 'matchMedia', {
15
+ writable: true,
16
+ value: jest.fn().mockImplementation((query) => ({
17
+ matches: false,
18
+ media: query,
19
+ onchange: null,
20
+ addListener: jest.fn(), // Deprecated
21
+ removeListener: jest.fn(), // Deprecated
22
+ addEventListener: jest.fn(),
23
+ removeEventListener: jest.fn(),
24
+ dispatchEvent: jest.fn(),
25
+ })),
26
+ });
27
+
28
+ function wait(t: number) {
29
+ return new Promise((resolve) => {
30
+ window.setTimeout(resolve, t);
31
+ });
32
+ }
33
+
34
+ describe('Toast', () => {
35
+ const originalGetBoundingClientRect = Element.prototype.getBoundingClientRect;
36
+
37
+ beforeEach(() => {
38
+ jest.useFakeTimers();
39
+ Element.prototype.getBoundingClientRect = jest.fn(() => ({
40
+ width: 300,
41
+ height: 50,
42
+ top: 0,
43
+ left: 0,
44
+ bottom: 0,
45
+ right: 0,
46
+ x: 0,
47
+ y: 0,
48
+ toJSON: () => {}, // eslint-disable-line
49
+ }));
50
+ });
51
+
52
+ afterEach(() => {
53
+ jest.useRealTimers();
54
+ cleanup();
55
+ Element.prototype.getBoundingClientRect = originalGetBoundingClientRect;
56
+ });
57
+
58
+ test('Default', () => {
59
+ render(<ToastContainer data-testid="toast-container-default" />);
60
+
61
+ expect(screen.getByTestId('toast-container-default')).toBeInTheDocument();
62
+ });
63
+
64
+ test('With Children', () => {
65
+ render(
66
+ <ToastContainer
67
+ data-testid="toast-container-children"
68
+ // eslint-disable-next-line
69
+ children={(t) => (
70
+ <button type="button">{t.message as ReactNode}</button>
71
+ )}
72
+ />
73
+ );
74
+
75
+ act(() => {
76
+ toast('test with children function');
77
+ });
78
+
79
+ expect(
80
+ screen.getByText('test with children function').closest('button')
81
+ ).toBeInTheDocument();
82
+
83
+ act(() => {
84
+ toast.dismiss();
85
+ jest.advanceTimersByTime(1000);
86
+ });
87
+
88
+ expect(screen.queryByText('test with children function')).toBe(null);
89
+ });
90
+
91
+ test('With Toasts', () => {
92
+ render(<ToastContainer data-testid="toast-container" />);
93
+ act(() => {
94
+ toast('test blank toast');
95
+ });
96
+
97
+ expect(screen.getByText('test blank toast')).toBeInTheDocument();
98
+
99
+ act(() => {
100
+ toast.dismiss();
101
+ jest.advanceTimersByTime(1000);
102
+ });
103
+
104
+ expect(screen.queryByText('test blank toast')).toBe(null);
105
+ });
106
+
107
+ describe('Positions', () => {
108
+ const positions: ToastPosition[] = [
109
+ 'top-left',
110
+ 'top-right',
111
+ 'top-center',
112
+ 'bottom-left',
113
+ 'bottom-center',
114
+ 'bottom-right',
115
+ ];
116
+
117
+ positions.forEach((position) => {
118
+ test(`${position}`, () => {
119
+ render(
120
+ <ToastContainer
121
+ data-testid={`toast-container-${position}`}
122
+ position={position}
123
+ />
124
+ );
125
+
126
+ act(() => {
127
+ toast(`test position toast ${position}`);
128
+ });
129
+
130
+ expect(
131
+ screen.getByTestId(`toast-container-${position}`)
132
+ ).toBeInTheDocument();
133
+
134
+ expect(
135
+ screen.getByText(`test position toast ${position}`)
136
+ ).toBeInTheDocument();
137
+
138
+ const verticalStyle: React.CSSProperties = position.includes('top')
139
+ ? { top: 0 }
140
+ : { bottom: 0 };
141
+ const horizontalStyle = {
142
+ ...(position.includes('center') && { justifyContent: 'center' }),
143
+ ...(!position.includes('center') &&
144
+ position.includes('right') && { justifyContent: 'flex-end' }),
145
+ };
146
+
147
+ expect(
148
+ screen.getByTestId(`toast-container-${position}`).children[0]
149
+ ).toHaveStyle({
150
+ ...verticalStyle,
151
+ ...horizontalStyle,
152
+ });
153
+
154
+ act(() => {
155
+ toast.dismiss();
156
+ jest.advanceTimersByTime(1000);
157
+ });
158
+
159
+ expect(screen.queryByText(`test position toast ${position}`)).toBe(
160
+ null
161
+ );
162
+ });
163
+ });
164
+
165
+ positions.forEach((position) => {
166
+ test(`Custom toast positions ${position}`, () => {
167
+ render(<ToastContainer />);
168
+
169
+ act(() => {
170
+ toast(`test custom position toast ${position}`, { position });
171
+ });
172
+
173
+ expect(
174
+ screen.getByText(`test custom position toast ${position}`)
175
+ ).toBeInTheDocument();
176
+
177
+ act(() => {
178
+ toast.dismiss();
179
+ jest.advanceTimersByTime(1000);
180
+ });
181
+
182
+ expect(
183
+ screen.queryByText(`test custom position toast ${position}`)
184
+ ).toBe(null);
185
+ });
186
+ });
187
+ });
188
+
189
+ describe('Toast Types', () => {
190
+ test('Success', () => {
191
+ render(<ToastContainer />);
192
+
193
+ act(() => {
194
+ toast.success('test success toast');
195
+ });
196
+
197
+ expect(screen.getByText('test success toast')).toBeInTheDocument();
198
+
199
+ act(() => {
200
+ toast.dismiss();
201
+ jest.advanceTimersByTime(1000);
202
+ });
203
+
204
+ expect(screen.queryByText('test success toast')).toBe(null);
205
+ });
206
+
207
+ test('error', () => {
208
+ render(<ToastContainer />);
209
+
210
+ act(() => {
211
+ toast.error('test error toast');
212
+ });
213
+
214
+ expect(screen.getByText('test error toast')).toBeInTheDocument();
215
+
216
+ act(() => {
217
+ toast.dismiss();
218
+ jest.advanceTimersByTime(1000);
219
+ });
220
+
221
+ expect(screen.queryByText('test error toast')).toBe(null);
222
+ });
223
+
224
+ test('Loading', () => {
225
+ render(<ToastContainer />);
226
+
227
+ act(() => {
228
+ toast.loading('test loading toast');
229
+ });
230
+
231
+ expect(screen.getByText('test loading toast')).toBeInTheDocument();
232
+
233
+ act(() => {
234
+ toast.dismiss();
235
+ jest.advanceTimersByTime(1000);
236
+ });
237
+
238
+ expect(screen.queryByText('test loading toast')).toBe(null);
239
+ });
240
+
241
+ test('Custom', () => {
242
+ render(<ToastContainer />);
243
+
244
+ act(() => {
245
+ toast.custom(<p>test custom toast</p>);
246
+ });
247
+
248
+ expect(screen.getByText('test custom toast')).toBeInTheDocument();
249
+
250
+ act(() => {
251
+ toast.dismiss();
252
+ jest.advanceTimersByTime(1000);
253
+ });
254
+
255
+ expect(screen.queryByText('test custom toast')).toBe(null);
256
+ });
257
+
258
+ test('Async Success', async () => {
259
+ render(<ToastContainer />);
260
+
261
+ const myPromise = new Promise(async (resolve) => {
262
+ // eslint-disable-line no-async-promise-executor
263
+ await wait(1000);
264
+ resolve('yay');
265
+ });
266
+
267
+ act(() => {
268
+ toast.async(myPromise, {
269
+ loading: 'loading...',
270
+ success: (data) => `success ${data}`,
271
+ error: (err) => `error ${err}`,
272
+ });
273
+ });
274
+
275
+ expect(screen.getByText('loading...')).toBeInTheDocument();
276
+
277
+ act(() => {
278
+ jest.advanceTimersByTime(1000);
279
+ jest.useRealTimers();
280
+ });
281
+
282
+ await waitFor(() => {
283
+ expect(screen.getByText('success yay')).toBeInTheDocument();
284
+ });
285
+ });
286
+
287
+ test('Async Error', async () => {
288
+ render(<ToastContainer />);
289
+
290
+ const myPromise = new Promise(async (_resolve, reject) => {
291
+ // eslint-disable-line no-async-promise-executor
292
+ await wait(1000);
293
+ reject('boo'); // eslint-disable-line prefer-promise-reject-errors
294
+ });
295
+
296
+ act(() => {
297
+ toast.async(myPromise, {
298
+ loading: 'loading...',
299
+ success: (data) => `success ${data}`,
300
+ error: (err) => `error ${err}`,
301
+ });
302
+ });
303
+
304
+ expect(screen.getByText('loading...')).toBeInTheDocument();
305
+
306
+ act(() => {
307
+ jest.advanceTimersByTime(1000);
308
+ jest.useRealTimers();
309
+ });
310
+
311
+ await waitFor(() => {
312
+ expect(screen.getByText('error boo')).toBeInTheDocument();
313
+ });
314
+ });
315
+
316
+ test('With children function', async () => {
317
+ render(<ToastContainer />);
318
+
319
+ act(() => {
320
+ toast((t) => (
321
+ <span>
322
+ Custom and
323
+ <b>bold</b>
324
+ <button type="button" onClick={() => toast.dismiss(t.id)}>
325
+ Dismiss
326
+ </button>
327
+ </span>
328
+ ));
329
+ });
330
+
331
+ expect(screen.getByText('Custom and')).toBeInTheDocument();
332
+
333
+ act(() => {
334
+ toast.dismiss();
335
+ jest.advanceTimersByTime(1000);
336
+ });
337
+
338
+ expect(screen.queryByText('Custom and')).toBe(null);
339
+ });
340
+ });
341
+
342
+ test('Compact', async () => {
343
+ render(<ToastContainer data-testid="toast-container" />);
344
+
345
+ act(() => {
346
+ toast('test compact toast', { isCompact: true });
347
+ });
348
+
349
+ expect(screen.getByText('test compact toast')).toBeInTheDocument();
350
+ expect(screen.getByText('test compact toast').parentElement).toHaveClass(
351
+ 'p-sm'
352
+ );
353
+
354
+ act(() => {
355
+ toast.dismiss();
356
+ jest.advanceTimersByTime(1000);
357
+ });
358
+
359
+ expect(screen.queryByText('test compact toast')).toBe(null);
360
+ });
361
+
362
+ test('Dismissing Toast', async () => {
363
+ render(<ToastContainer data-testid="toast-container" />);
364
+
365
+ act(() => {
366
+ toast('dismissing toast');
367
+ });
368
+
369
+ const closeIcon = await screen.getByTestId('icon-testid--remove');
370
+ const closeButton = closeIcon.closest('button');
371
+ expect(closeButton).toBeInTheDocument();
372
+
373
+ if (closeButton) {
374
+ await act(async () => {
375
+ await fireEvent.click(closeButton);
376
+ jest.advanceTimersByTime(1000);
377
+ });
378
+ }
379
+
380
+ expect(screen.queryByText('dismissing toast')).toBe(null);
381
+ });
382
+
383
+ test('Non-dismissable toast', async () => {
384
+ render(<ToastContainer data-testid="toast-container" />);
385
+
386
+ act(() => {
387
+ toast('cannot dismiss', { canDismiss: false });
388
+ });
389
+
390
+ await waitFor(() => {
391
+ expect(screen.getByText('cannot dismiss')).toBeInTheDocument();
392
+ expect(screen.queryByTestId('icon-testid--remove-light')).toBe(null);
393
+ });
394
+
395
+ act(() => {
396
+ toast.dismiss();
397
+ jest.advanceTimersByTime(1000);
398
+ });
399
+
400
+ expect(screen.queryByText('cannot dismiss')).toBe(null);
401
+ });
402
+
403
+ test('Dismiss a single toast', () => {
404
+ render(<ToastContainer data-testid="toast-container" />);
405
+
406
+ let toastId: string;
407
+
408
+ act(() => {
409
+ toast('multiple toasts 1');
410
+ jest.advanceTimersByTime(1500);
411
+ toastId = toast('multiple toasts 2');
412
+ jest.advanceTimersByTime(1000);
413
+ });
414
+
415
+ expect(screen.getByText('multiple toasts 1')).toBeInTheDocument();
416
+ expect(screen.getByText('multiple toasts 2')).toBeInTheDocument();
417
+
418
+ act(() => {
419
+ toast.dismiss(toastId);
420
+ jest.advanceTimersByTime(1000);
421
+ });
422
+
423
+ expect(screen.getByText('multiple toasts 1')).toBeInTheDocument();
424
+ expect(screen.queryByText('multiple toasts 2')).toBe(null);
425
+
426
+ // cleanup -- dismiss remaining toast.
427
+ act(() => {
428
+ toast.dismiss();
429
+ jest.advanceTimersByTime(1000);
430
+ });
431
+ });
432
+
433
+ describe('Duration', () => {
434
+ /**
435
+ * Based on a default duration time for each toast,
436
+ * we track the state of the toast at various points in time.
437
+ */
438
+ test('Default duration -- blank toast', async () => {
439
+ render(<ToastContainer />);
440
+
441
+ act(() => {
442
+ toast('default timeout blank toast');
443
+ });
444
+ expect(
445
+ screen.getByText('default timeout blank toast')
446
+ ).toBeInTheDocument();
447
+
448
+ // After 3000ms nothing should have changed.
449
+ act(() => {
450
+ jest.advanceTimersByTime(3000);
451
+ });
452
+ expect(
453
+ screen.getByText('default timeout blank toast')
454
+ ).toBeInTheDocument();
455
+
456
+ // After 4000ms (3000 + 1000) the toast should still be in the DOM,
457
+ // but not visible. We confirm this with the `not-visible` class.
458
+ act(() => {
459
+ jest.advanceTimersByTime(1000);
460
+ });
461
+ expect(
462
+ screen.getByText('default timeout blank toast')?.parentElement
463
+ ).toHaveClass('toast-notification--not-visible');
464
+
465
+ // After another 1000ms the toast is cleared from the DOM completely (after animation is done).
466
+ act(() => {
467
+ jest.advanceTimersByTime(1000);
468
+ });
469
+ expect(screen.queryByText('default timeout blank toast')).toBe(null);
470
+ });
471
+
472
+ test('Default duration -- error toast', async () => {
473
+ render(<ToastContainer />);
474
+
475
+ act(() => {
476
+ toast.error('default timeout error toast');
477
+ });
478
+ expect(
479
+ screen.getByText('default timeout error toast')
480
+ ).toBeInTheDocument();
481
+
482
+ // After 3000ms nothing should have changed.
483
+ act(() => {
484
+ jest.advanceTimersByTime(3000);
485
+ });
486
+ expect(
487
+ screen.getByText('default timeout error toast')
488
+ ).toBeInTheDocument();
489
+
490
+ // After 4000ms (3000 + 1000) the toast should still be in the DOM,
491
+ // but not visible. We confirm this with the `not-visible` class.
492
+ act(() => {
493
+ jest.advanceTimersByTime(1000);
494
+ });
495
+ expect(
496
+ screen.getByText('default timeout error toast')?.parentElement
497
+ ).toHaveClass('toast-notification--not-visible');
498
+
499
+ // After another 1000ms the toast is cleared from the DOM completely (after animation is done).
500
+ act(() => {
501
+ jest.advanceTimersByTime(1000);
502
+ });
503
+
504
+ expect(screen.queryByText('default timeout error toast')).toBe(null);
505
+ });
506
+ test('Default duration -- success toast', async () => {
507
+ render(<ToastContainer />);
508
+
509
+ act(() => {
510
+ toast.success('default timeout success toast');
511
+ });
512
+ expect(
513
+ screen.getByText('default timeout success toast')
514
+ ).toBeInTheDocument();
515
+
516
+ // After 1000ms nothing should have changed.
517
+ act(() => {
518
+ jest.advanceTimersByTime(1000);
519
+ });
520
+ expect(
521
+ screen.getByText('default timeout success toast')
522
+ ).toBeInTheDocument();
523
+
524
+ // After 2000ms (1000 + 1000) the toast should still be in the DOM,
525
+ // but not visible. We confirm this with the `not-visible` class.
526
+ act(() => {
527
+ jest.advanceTimersByTime(1000);
528
+ });
529
+ expect(
530
+ screen.getByText('default timeout success toast')?.parentElement
531
+ ).toHaveClass('toast-notification--not-visible');
532
+
533
+ // After another 1000ms the toast is cleared from the DOM completely (after animation is done).
534
+ act(() => {
535
+ jest.advanceTimersByTime(1000);
536
+ });
537
+ expect(screen.queryByText('default timeout success toast')).toBe(null);
538
+ });
539
+ test('Default duration -- loading toast', async () => {
540
+ render(<ToastContainer />);
541
+
542
+ act(() => {
543
+ toast.loading('default timeout loading toast');
544
+ });
545
+ expect(
546
+ screen.getByText('default timeout loading toast')
547
+ ).toBeInTheDocument();
548
+
549
+ // After any amount of time nothing should have changed.
550
+ act(() => {
551
+ jest.advanceTimersByTime(999999);
552
+ });
553
+ expect(
554
+ screen.getByText('default timeout loading toast')
555
+ ).toBeInTheDocument();
556
+
557
+ // Toast can be dismissed programmatically, however.
558
+ act(() => {
559
+ toast.dismiss();
560
+ jest.advanceTimersByTime(1000);
561
+ });
562
+ expect(screen.queryByText('default timeout loading toast')).toBe(null);
563
+ });
564
+ test('With a custom duration on the container', async () => {
565
+ render(<ToastContainer toastOptions={{ duration: 10000 }} />);
566
+
567
+ act(() => {
568
+ toast('custom timeout on container toast');
569
+ });
570
+ expect(
571
+ screen.getByText('custom timeout on container toast')
572
+ ).toBeInTheDocument();
573
+
574
+ // After 8000ms nothing should have changed.
575
+ act(() => {
576
+ jest.advanceTimersByTime(8000);
577
+ });
578
+ expect(
579
+ screen.getByText('custom timeout on container toast')
580
+ ).toBeInTheDocument();
581
+
582
+ // after 10000ms toast should be in DOM but not visible.
583
+ act(() => {
584
+ jest.advanceTimersByTime(2000);
585
+ });
586
+ expect(
587
+ screen.getByText('custom timeout on container toast')?.parentElement
588
+ ).toHaveClass('toast-notification--not-visible');
589
+
590
+ // after another 1000ms the toast should be removed from the DOM.
591
+ act(() => {
592
+ jest.advanceTimersByTime(1000);
593
+ });
594
+ expect(screen.queryByText('custom timeout on container toast')).toBe(
595
+ null
596
+ );
597
+ });
598
+ test('Overriding container duration in single toast', async () => {
599
+ render(<ToastContainer />);
600
+
601
+ act(() => {
602
+ toast('custom timeout on individual toast', { duration: 10000 });
603
+ });
604
+ expect(
605
+ screen.getByText('custom timeout on individual toast')
606
+ ).toBeInTheDocument();
607
+
608
+ // After 8000ms nothing should have changed.
609
+ act(() => {
610
+ jest.advanceTimersByTime(8000);
611
+ });
612
+ expect(
613
+ screen.getByText('custom timeout on individual toast')
614
+ ).toBeInTheDocument();
615
+
616
+ // after 10000ms toast should be in DOM but not visible.
617
+ act(() => {
618
+ jest.advanceTimersByTime(2000);
619
+ });
620
+ expect(
621
+ screen.getByText('custom timeout on individual toast')?.parentElement
622
+ ).toHaveClass('toast-notification--not-visible');
623
+
624
+ // after another 1000ms the toast should be removed from the DOM.
625
+ act(() => {
626
+ jest.advanceTimersByTime(1000);
627
+ });
628
+ expect(screen.queryByText('custom timeout on individual toast')).toBe(
629
+ null
630
+ );
631
+ });
632
+ });
633
+
634
+ test('Removing Toast', () => {
635
+ render(<ToastContainer data-testid="toast-container" />);
636
+ let toastId: string;
637
+
638
+ act(() => {
639
+ toastId = toast('test remove toast');
640
+ });
641
+
642
+ expect(screen.getByText('test remove toast')).toBeInTheDocument();
643
+
644
+ act(() => {
645
+ toast.remove(toastId);
646
+ });
647
+
648
+ expect(screen.queryByText('test remove toast')).toBe(null);
649
+ });
650
+
651
+ test('Pause duration on mouseover', async () => {
652
+ render(<ToastContainer />);
653
+
654
+ act(() => {
655
+ toast('default timeout blank toast');
656
+ });
657
+ expect(screen.getByText('default timeout blank toast')).toBeInTheDocument();
658
+
659
+ // Mousing over the element should delay the duration until toast is dismissed
660
+ await fireEvent.mouseOver(screen.getByText('default timeout blank toast'));
661
+
662
+ // Toast should still be present since user has moused over it.
663
+ act(() => {
664
+ jest.advanceTimersByTime(99999);
665
+ });
666
+ expect(screen.getByText('default timeout blank toast')).toBeInTheDocument();
667
+
668
+ // Mouse out should re-start timer.
669
+ await fireEvent.mouseOut(screen.getByText('default timeout blank toast'));
670
+
671
+ // After 3000ms nothing should have changed.
672
+ act(() => {
673
+ jest.advanceTimersByTime(3000);
674
+ });
675
+ expect(screen.getByText('default timeout blank toast')).toBeInTheDocument();
676
+
677
+ // After 4000ms (3000 + 1000) the toast should still be in the DOM,
678
+ // but not visible. We confirm this with the `not-visible` class.
679
+ act(() => {
680
+ jest.advanceTimersByTime(1000);
681
+ });
682
+ expect(
683
+ screen.getByText('default timeout blank toast')?.parentElement
684
+ ).toHaveClass('toast-notification--not-visible');
685
+
686
+ // After another 1000ms the toast is cleared from the DOM completely (after animation is done).
687
+ act(() => {
688
+ jest.advanceTimersByTime(1000);
689
+ });
690
+ expect(screen.queryByText('default timeout blank toast')).toBe(null);
691
+ });
692
+
693
+ test('Toasts in reverse order', () => {
694
+ render(<ToastContainer data-testid="toast-container" reverseOrder />);
695
+ act(() => {
696
+ toast('test reverse order');
697
+ });
698
+
699
+ expect(screen.getByText('test reverse order')).toBeInTheDocument();
700
+
701
+ act(() => {
702
+ toast.dismiss();
703
+ jest.advanceTimersByTime(1000);
704
+ });
705
+
706
+ expect(screen.queryByText('test reverse order')).toBe(null);
707
+ });
708
+
709
+ test('Update Existing Toast', () => {
710
+ render(<ToastContainer />);
711
+ let toastId: string;
712
+
713
+ act(() => {
714
+ toastId = toast('test update toast');
715
+ });
716
+
717
+ expect(screen.getByText('test update toast')).toBeInTheDocument();
718
+
719
+ act(() => {
720
+ toast.success('updated to success', { id: toastId });
721
+ });
722
+
723
+ expect(screen.queryByText('test update toast')).toBe(null);
724
+ expect(screen.getByText('updated to success')).toBeInTheDocument();
725
+
726
+ act(() => {
727
+ toast.remove();
728
+ });
729
+
730
+ expect(screen.queryByText('updated to success')).toBe(null);
731
+ });
732
+
733
+ test('Update after dismiss', () => {
734
+ render(<ToastContainer />);
735
+ let toastId: string;
736
+
737
+ act(() => {
738
+ toastId = toast('update after dismiss');
739
+ });
740
+
741
+ expect(screen.getByText('update after dismiss')).toBeInTheDocument();
742
+
743
+ act(() => {
744
+ toast.dismiss(toastId);
745
+ jest.advanceTimersByTime(100);
746
+ });
747
+
748
+ act(() => {
749
+ toast.success('updated after dismiss to success', { id: toastId });
750
+ });
751
+
752
+ expect(screen.queryByText('update after dismiss')).toBe(null);
753
+ expect(
754
+ screen.getByText('updated after dismiss to success')
755
+ ).toBeInTheDocument();
756
+
757
+ act(() => {
758
+ toast.remove();
759
+ });
760
+
761
+ expect(screen.queryByText('updated after dismiss to success')).toBe(null);
762
+ });
763
+
764
+ test('Dismiss toast that is already in dismiss queue', () => {
765
+ render(<ToastContainer data-testid="toast-container" />);
766
+ act(() => {
767
+ toast('dismiss twice');
768
+ });
769
+
770
+ expect(screen.getByText('dismiss twice')).toBeInTheDocument();
771
+
772
+ act(() => {
773
+ toast.dismiss();
774
+ jest.advanceTimersByTime(100);
775
+ });
776
+
777
+ act(() => {
778
+ toast.dismiss();
779
+ jest.advanceTimersByTime(900);
780
+ });
781
+
782
+ expect(screen.queryByText('dismiss twice')).toBe(null);
783
+ });
784
+ });