@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,199 @@
1
+ import React, { useState } from 'react';
2
+ import { DatePicker } from './DatePicker';
3
+ import type { Meta } from '@storybook/react';
4
+ import { Box } from '../Box/Box';
5
+ import { Heading } from '../Heading/Heading';
6
+
7
+ const meta: Meta<typeof DatePicker> = {
8
+ title: 'Components/DatePicker',
9
+ component: DatePicker,
10
+ };
11
+
12
+ export default meta;
13
+
14
+ export const BasicExample = () => {
15
+ const [selectedDate, setSelectedDate] = useState<Date>(new Date(2019, 11, 3));
16
+ return (
17
+ <Box gap="md">
18
+ <DatePicker
19
+ onChange={(date) => setSelectedDate(date as Date)}
20
+ selected={selectedDate}
21
+ />
22
+ <p>Selected Date: {selectedDate.toISOString()}</p>
23
+ </Box>
24
+ );
25
+ };
26
+
27
+ export const DateRange = () => {
28
+ const [startDate, setStartDate] = useState<Date>(new Date(2019, 11, 3));
29
+ const [endDate, setEndDate] = useState<Date>(new Date(2019, 11, 28));
30
+ const setDate = ([startDate, endDate]: [Date, Date]) => {
31
+ setStartDate(startDate);
32
+ setEndDate(endDate);
33
+ };
34
+ return (
35
+ <Box gap="md">
36
+ <DatePicker
37
+ onChange={(date) => setDate(date as [Date, Date])}
38
+ selected={startDate}
39
+ startDate={startDate}
40
+ endDate={endDate}
41
+ selectsRange
42
+ />
43
+ <p>
44
+ {`Selected Date Range: ${startDate && startDate.toISOString()} - ${
45
+ endDate && endDate.toISOString()
46
+ }`}
47
+ </p>
48
+ </Box>
49
+ );
50
+ };
51
+
52
+ export const MinAndMaxDates = () => {
53
+ const [startDate, setStartDate] = useState<Date>(new Date(2019, 11, 18));
54
+ const min = new Date(2019, 11, 18);
55
+ min.setDate(min.getDate() - 5);
56
+ const max = new Date(2019, 11, 18);
57
+ max.setDate(max.getDate() + 5);
58
+ return (
59
+ <Box gap="md">
60
+ <DatePicker
61
+ selected={startDate}
62
+ onChange={(date) => setStartDate(date as Date)}
63
+ minDate={min}
64
+ maxDate={max}
65
+ />
66
+ <p>Selected Date: {startDate.toISOString()}</p>
67
+ </Box>
68
+ );
69
+ };
70
+
71
+ export const MonthPicker = () => {
72
+ const [startDateOne, setStartDateOne] = useState<Date>(new Date(2019, 10));
73
+ const [startDateTwo, setStartDateTwo] = useState<Date>(new Date(2019, 10));
74
+ const [startDateThree, setStartDateThree] = useState<Date>(
75
+ new Date(2019, 10)
76
+ );
77
+ return (
78
+ <Box display="flex" direction="row" gap="md">
79
+ <Box
80
+ gap="md"
81
+ display="flex"
82
+ direction="column"
83
+ alignItems="center"
84
+ width="33"
85
+ >
86
+ <Heading size="md">Default</Heading>
87
+ <DatePicker
88
+ selected={startDateOne}
89
+ onChange={(date) => setStartDateOne(date as Date)}
90
+ showMonthYearPicker
91
+ />
92
+ <p>{startDateOne.toISOString()}</p>
93
+ </Box>
94
+ <Box
95
+ gap="md"
96
+ display="flex"
97
+ direction="column"
98
+ alignItems="center"
99
+ width="33"
100
+ >
101
+ <Heading size="md">With full month name</Heading>
102
+ <DatePicker
103
+ selected={startDateTwo}
104
+ onChange={(date) => setStartDateTwo(date as Date)}
105
+ showMonthYearPicker
106
+ showFullMonthYearPicker
107
+ />
108
+ <p>{startDateTwo.toISOString()}</p>
109
+ </Box>
110
+ <Box
111
+ gap="md"
112
+ display="flex"
113
+ direction="column"
114
+ alignItems="center"
115
+ width="33"
116
+ >
117
+ <Heading size="md">With Two-column layout</Heading>
118
+ <DatePicker
119
+ selected={startDateThree}
120
+ onChange={(date) => setStartDateThree(date as Date)}
121
+ showMonthYearPicker
122
+ showFullMonthYearPicker
123
+ showTwoColumnMonthYearPicker
124
+ />
125
+ <p>{startDateThree.toISOString()}</p>
126
+ </Box>
127
+ </Box>
128
+ );
129
+ };
130
+
131
+ export const ShowMultipleMonths = () => {
132
+ const [startDate, setStartDate] = useState<Date>(new Date(2019, 11, 3));
133
+ const [endDate, setEndDate] = useState<Date>(new Date(2019, 12, 20));
134
+ const setDate = ([startDate, endDate]: [Date, Date]) => {
135
+ setStartDate(startDate);
136
+ setEndDate(endDate);
137
+ };
138
+ return (
139
+ <Box gap="md">
140
+ <DatePicker
141
+ onChange={(date) => setDate(date as [Date, Date])}
142
+ selected={startDate}
143
+ startDate={startDate}
144
+ endDate={endDate}
145
+ selectsRange
146
+ monthsShown={2}
147
+ />
148
+ <p>Start Date: {startDate && startDate.toISOString()}</p>
149
+ <p>End Date: {endDate && endDate.toISOString()}</p>
150
+ </Box>
151
+ );
152
+ };
153
+
154
+ export const WithTimePicker = () => {
155
+ const [startDate, setStartDate] = useState<Date>(new Date('1993/09/28'));
156
+ return (
157
+ <Box gap="md">
158
+ <DatePicker
159
+ selected={startDate}
160
+ onChange={(date) => setStartDate(date as Date)}
161
+ showTimeSelect
162
+ timeIntervals={15}
163
+ timeCaption="Time"
164
+ />
165
+ <p>Selected Date: {startDate && startDate.toISOString()}</p>
166
+ </Box>
167
+ );
168
+ };
169
+
170
+ export const OpenByDefaultOnASpecificDate = () => {
171
+ const [startDate, setStartDate] = useState<Date>(new Date('1993/09/28'));
172
+ return (
173
+ <Box gap="md">
174
+ <DatePicker
175
+ onChange={(date) => setStartDate(date as Date)}
176
+ selected={startDate}
177
+ openToDate={new Date('1993/09/28')}
178
+ />
179
+ <p>Selected Date: {startDate && startDate.toISOString()}</p>
180
+ </Box>
181
+ );
182
+ };
183
+
184
+ export const WithChildren = () => {
185
+ const [selectedDate, setSelectedDate] = useState<Date>(new Date(2019, 11, 3));
186
+ return (
187
+ <Box gap="md">
188
+ <DatePicker
189
+ onChange={(date) => setSelectedDate(date as Date)}
190
+ selected={selectedDate}
191
+ >
192
+ <Box display="block" style={{ textAlign: 'center' }} color="base">
193
+ It will be sunny out today!
194
+ </Box>
195
+ </DatePicker>
196
+ <p>Selected Date: {selectedDate.toISOString()}</p>
197
+ </Box>
198
+ );
199
+ };
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import { fireEvent, render, screen } from '@testing-library/react';
3
+ import { DatePicker } from './DatePicker';
4
+
5
+ describe('DatePicker', () => {
6
+ describe('Default', () => {
7
+ it('renders a datepicker with default props', () => {
8
+ const mockedOnChange = jest.fn();
9
+ const { container } = render(<DatePicker onChange={mockedOnChange} />);
10
+ const datePicker = container.querySelector('.react-datepicker');
11
+ expect(datePicker).toBeInTheDocument();
12
+ });
13
+ });
14
+
15
+ describe('Callbacks', () => {
16
+ it('Fires the expected callback when date is selected', () => {
17
+ const openToDate = new Date('1995, 11, 14');
18
+ const mockedOnChange = jest.fn();
19
+ render(<DatePicker onChange={mockedOnChange} openToDate={openToDate} />);
20
+ const fourteenth = screen.getByText('14');
21
+ expect(fourteenth).toBeInTheDocument();
22
+ fireEvent.click(fourteenth);
23
+ expect(mockedOnChange).toHaveBeenCalledTimes(1);
24
+ });
25
+ });
26
+ });
@@ -0,0 +1,138 @@
1
+ import React, { FC, SyntheticEvent, ReactNode } from 'react';
2
+ import classNames from 'classnames';
3
+ import ReactDatePicker, { ReactDatePickerProps } from 'react-datepicker';
4
+ import styles from './DatePicker.module.scss';
5
+
6
+ export interface DatePickerProps extends ReactDatePickerProps<any, any> {
7
+ /**
8
+ * React children (to be rendered below the calendar dates).
9
+ */
10
+ children?: ReactNode;
11
+ /**
12
+ * Custom classname to be applied to the DatePicker container.
13
+ */
14
+ className?: string;
15
+ /**
16
+ * Callback that fires when a date is changed/selected.
17
+ */
18
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
+ onChange: (
20
+ date: Date | [Date, Date] | null,
21
+ event?: React.SyntheticEvent<any> | undefined
22
+ ) => void;
23
+ /**
24
+ * Callback that fires when a date is clicked.
25
+ */
26
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
+ onSelect?:
28
+ | ((date: Date, event: SyntheticEvent<any, Event> | undefined) => void)
29
+ | undefined;
30
+ /**
31
+ * Custom Class to be applied to a single day element based on a date.
32
+ */
33
+ dayClassName?: ((date: Date) => string | null) | undefined;
34
+ /**
35
+ * Custom Class to be applied to a single week element based on a date.
36
+ */
37
+ weekClassName?: ((date: Date) => string | null) | undefined;
38
+ /**
39
+ * Custom Class to be applied to a single month element based on a date.
40
+ */
41
+ monthClassName?: ((date: Date) => string | null) | undefined;
42
+ /**
43
+ * Custom Class to be applied to a specific time.
44
+ */
45
+ timeClassName?: ((date: Date) => string | null) | undefined;
46
+ /**
47
+ * Custom format for weekday.
48
+ */
49
+ formatWeekDay?: (formattedDate: string) => string;
50
+ /**
51
+ * Last allowable/shown date
52
+ */
53
+ maxDate?: Date | null;
54
+ /**
55
+ * First allowable/shown date
56
+ */
57
+ minDate?: Date | null;
58
+ /**
59
+ * Months to be shown at one time
60
+ */
61
+ monthsShown?: number;
62
+ /**
63
+ * Date that the calendar will open to by default.
64
+ */
65
+ openToDate?: Date;
66
+ /**
67
+ * Currently selected date.
68
+ */
69
+ selected?: Date | null;
70
+ /**
71
+ * Whether or not the picker will return a range of dates.
72
+ */
73
+ selectsRange?: boolean;
74
+ /**
75
+ * Start date in a range
76
+ */
77
+ startDate?: Date | null;
78
+ /**
79
+ * Show month picker in two columns
80
+ */
81
+ showTwoColumnMonthYearPicker?: boolean;
82
+ /**
83
+ * See full month name in the month picker
84
+ */
85
+ showFullMonthYearPicker?: boolean;
86
+ /**
87
+ * Use the month picker
88
+ */
89
+ showMonthYearPicker?: boolean;
90
+ /**
91
+ * Additional props to be spread to rendered element
92
+ */
93
+ [x: string]: any; // eslint-disable-line
94
+ }
95
+
96
+ export const DatePicker: FC<DatePickerProps> = ({
97
+ children = null,
98
+ dayClassName = undefined,
99
+ maxDate = undefined,
100
+ minDate = undefined,
101
+ monthsShown = undefined,
102
+ openToDate = undefined,
103
+ startDate = undefined,
104
+ selected = undefined,
105
+ selectsRange = undefined,
106
+ showTwoColumnMonthYearPicker = false,
107
+ showFullMonthYearPicker = false,
108
+ showMonthYearPicker = false,
109
+ className = undefined,
110
+ formatWeekDay = (formattedDate) => formattedDate[0], // Make days show as 1 character.
111
+ ...restProps
112
+ }) => {
113
+ const datePickerClasses = classNames(styles['react-datepicker'], className);
114
+
115
+ return (
116
+ <ReactDatePicker
117
+ inline
118
+ calendarClassName={datePickerClasses}
119
+ formatWeekDay={formatWeekDay}
120
+ maxDate={maxDate}
121
+ minDate={minDate}
122
+ monthsShown={monthsShown}
123
+ openToDate={openToDate}
124
+ selected={selected}
125
+ startDate={startDate}
126
+ selectsRange={selectsRange}
127
+ showTwoColumnMonthYearPicker={showTwoColumnMonthYearPicker}
128
+ showFullMonthYearPicker={showFullMonthYearPicker}
129
+ showMonthYearPicker={showMonthYearPicker}
130
+ dayClassName={dayClassName}
131
+ {...restProps}
132
+ >
133
+ {children}
134
+ </ReactDatePicker>
135
+ );
136
+ };
137
+
138
+ export default DatePicker;
@@ -0,0 +1,30 @@
1
+ import { Canvas, Meta, ArgTypes } from '@storybook/blocks';
2
+ import { Details } from './Details';
3
+ import { DetailsSummary } from './DetailsSummary';
4
+ import * as Stories from './Details.stories';
5
+
6
+ <Meta of={Stories} />
7
+
8
+ # Details
9
+
10
+ The `<details>` tag specifies additional details that the user can open and close on demand. This custom component
11
+ provides a React implementation of this semantic HTML with controlled state.
12
+
13
+ It includes a child component for the details summary `<Details.Summary />`. The details themselves can be included as children
14
+ inside `<Details>` typically following the `<Details.Summary>`.
15
+
16
+ NOTE: for a custom implementation of this component see the [accordion](/?path=/story/components-accordion-overview--default-story)
17
+
18
+ <Canvas of={Stories.BasicUsage} />
19
+
20
+ ## Props
21
+
22
+ <ArgTypes of={Details} />
23
+
24
+ ## Sub-Components
25
+
26
+ ### `<Details.Summary>`
27
+
28
+ ## Props
29
+
30
+ <ArgTypes of={DetailsSummary} />
@@ -0,0 +1,32 @@
1
+ .details-reset {
2
+ > summary {
3
+ cursor: pointer;
4
+ list-style: none;
5
+
6
+ &::-webkit-details-marker {
7
+ display: none;
8
+ }
9
+
10
+ &::before {
11
+ display: none;
12
+ }
13
+
14
+ &:focus {
15
+ outline: 0;
16
+ box-shadow: 0 0 0 2px var(--color-base-primary-light);
17
+ }
18
+
19
+ //Show focus styles on keyboard focus.
20
+ &:focus-visible {
21
+ outline: 0;
22
+ box-shadow: 0 0 0 2px var(--color-base-primary-light);
23
+ }
24
+
25
+ // Hide focus styles if they are not needed, for example,
26
+ // when an element receives focus via the mouse.
27
+ &:focus:not(:focus-visible) {
28
+ outline: 0;
29
+ box-shadow: none;
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,38 @@
1
+ import { Details } from './Details';
2
+ import type { Meta } from '@storybook/react';
3
+ import React from 'react';
4
+ import { Box } from '../Box/Box';
5
+ import { useOpenClose } from '../../hooks/useOpenClose/useOpenClose';
6
+
7
+ const meta: Meta<typeof Details> = {
8
+ title: 'Components/Details',
9
+ component: Details,
10
+ };
11
+
12
+ export default meta;
13
+
14
+ export const BasicUsage = () => {
15
+ const { isOpen, handleToggle } = useOpenClose();
16
+ return (
17
+ <Details isOpen={isOpen}>
18
+ <Details.Summary
19
+ isDetailsOpen={isOpen}
20
+ onToggle={handleToggle}
21
+ display="inline"
22
+ >
23
+ What is Hyphen's Mission?
24
+ </Details.Summary>
25
+ <Box padding="md 0" gap="sm">
26
+ <Box fontSize="lg" as="h4">
27
+ Empowering Teams with Streamlined DevOps
28
+ </Box>
29
+ <Box as="p">
30
+ Our mission is to streamline DevOps for software teams. By automating
31
+ access management and integrating essential tools, we empower teams to
32
+ focus on innovation and deliver seamless software solutions
33
+ efficiently.
34
+ </Box>
35
+ </Box>
36
+ </Details>
37
+ );
38
+ };
@@ -0,0 +1,189 @@
1
+ import React from 'react';
2
+ import { render, screen, fireEvent } from '@testing-library/react';
3
+ import { Details } from './Details';
4
+
5
+ describe('Details', () => {
6
+ describe('Default', () => {
7
+ test('It renders a default details HTML element and summary', () => {
8
+ render(
9
+ <Details isOpen={false}>
10
+ <Details.Summary isDetailsOpen={false}>summary</Details.Summary>
11
+ </Details>
12
+ );
13
+
14
+ const details = screen.getByRole('group');
15
+ expect(details).toBeInTheDocument();
16
+ const summary = screen.getByText('summary');
17
+ expect(summary).toBeInTheDocument();
18
+ });
19
+ });
20
+
21
+ describe('With open details initially', () => {
22
+ test('It renders a default details HTML element and summary', () => {
23
+ render(
24
+ <Details isOpen>
25
+ <Details.Summary isDetailsOpen>summary</Details.Summary>
26
+ <div>details</div>
27
+ </Details>
28
+ );
29
+
30
+ const details = screen.getByRole('group');
31
+ expect(details).toBeInTheDocument();
32
+ const summary = screen.getByText('summary');
33
+ expect(summary).toBeInTheDocument();
34
+ const innerDetails = screen.getByText('details');
35
+ expect(innerDetails).toBeVisible();
36
+ });
37
+ });
38
+
39
+ describe('Aria', () => {
40
+ test('It renders the summary with the correct "button" role', () => {
41
+ render(
42
+ <Details isOpen={false}>
43
+ <Details.Summary isDetailsOpen={false}>summary</Details.Summary>
44
+ </Details>
45
+ );
46
+
47
+ const summary = screen.getByRole('button');
48
+ expect(summary).toBeInTheDocument();
49
+ expect(summary).toHaveTextContent('summary');
50
+ });
51
+
52
+ test('It notes whether the underlying element is expanded', () => {
53
+ const { rerender } = render(
54
+ <Details isOpen={false}>
55
+ <Details.Summary isDetailsOpen={false}>summary</Details.Summary>
56
+ </Details>
57
+ );
58
+
59
+ const summary = screen.getByText('summary');
60
+ expect(summary).toBeInTheDocument();
61
+ expect(summary).toHaveAttribute('aria-expanded', 'false');
62
+
63
+ rerender(
64
+ <Details isOpen>
65
+ <Details.Summary isDetailsOpen>summary2</Details.Summary>
66
+ </Details>
67
+ );
68
+
69
+ const summaryTwo = screen.getByText('summary2');
70
+ expect(summaryTwo).toBeInTheDocument();
71
+ expect(summaryTwo).toHaveAttribute('aria-expanded', 'true');
72
+ });
73
+
74
+ test('The summary is tabbable', () => {
75
+ render(
76
+ <Details isOpen={false}>
77
+ <Details.Summary isDetailsOpen={false}>summary</Details.Summary>
78
+ </Details>
79
+ );
80
+
81
+ const summary = screen.getByRole('button');
82
+ expect(summary).toBeInTheDocument();
83
+ expect(summary).toHaveAttribute('tabIndex', '0');
84
+ });
85
+ });
86
+
87
+ describe('Events', () => {
88
+ test('it fires an onToggle when summary is clicked', () => {
89
+ const mockedOnToggle = jest.fn(() => null);
90
+
91
+ render(
92
+ <Details isOpen={false}>
93
+ <Details.Summary isDetailsOpen={false} onToggle={mockedOnToggle}>
94
+ summary
95
+ </Details.Summary>
96
+ </Details>
97
+ );
98
+
99
+ const summary = screen.getByRole('button');
100
+ fireEvent.click(summary);
101
+ expect(mockedOnToggle).toHaveBeenCalledTimes(1);
102
+ });
103
+
104
+ test('onToggle event fires with ENTER key', () => {
105
+ const mockedOnToggle = jest.fn(() => null);
106
+
107
+ render(
108
+ <Details isOpen={false}>
109
+ <Details.Summary isDetailsOpen={false} onToggle={mockedOnToggle}>
110
+ summary
111
+ </Details.Summary>
112
+ </Details>
113
+ );
114
+
115
+ const summary = screen.getByRole('button');
116
+ fireEvent.keyDown(summary, { keyCode: 13 });
117
+ fireEvent.keyDown(summary, { keyCode: 32 });
118
+ fireEvent.keyDown(summary, { keyCode: 25 });
119
+ expect(mockedOnToggle).toHaveBeenCalledTimes(2);
120
+ });
121
+
122
+ test('Does not attempt to fire onToggle if function not passed', () => {
123
+ const mockedOnToggle = jest.fn(() => null);
124
+
125
+ render(
126
+ <Details isOpen={false}>
127
+ <Details.Summary isDetailsOpen={false}>summary</Details.Summary>
128
+ </Details>
129
+ );
130
+
131
+ const summary = screen.getByRole('button');
132
+ fireEvent.keyDown(summary, { keyCode: 13 });
133
+ fireEvent.keyDown(summary, { keyCode: 32 });
134
+ fireEvent.click(summary);
135
+ expect(mockedOnToggle).toHaveBeenCalledTimes(0);
136
+ });
137
+
138
+ test('Fires onClick if passed', () => {
139
+ const mockedOnToggle = jest.fn(() => null);
140
+
141
+ render(
142
+ <Details isOpen={false}>
143
+ <Details.Summary isDetailsOpen={false} onClick={mockedOnToggle}>
144
+ summary
145
+ </Details.Summary>
146
+ </Details>
147
+ );
148
+
149
+ const summary = screen.getByRole('button');
150
+ fireEvent.click(summary);
151
+ expect(mockedOnToggle).toHaveBeenCalledTimes(1);
152
+ });
153
+
154
+ test('Fires onKeyDown if passed', () => {
155
+ const mockedOnToggle = jest.fn(() => null);
156
+
157
+ render(
158
+ <Details isOpen={false}>
159
+ <Details.Summary isDetailsOpen={false} onKeyDown={mockedOnToggle}>
160
+ summary
161
+ </Details.Summary>
162
+ </Details>
163
+ );
164
+
165
+ const summary = screen.getByRole('button');
166
+ fireEvent.keyDown(summary, { keyCode: 13 });
167
+
168
+ expect(mockedOnToggle).toHaveBeenCalledTimes(1);
169
+ });
170
+ });
171
+
172
+ describe('Spread props', () => {
173
+ it('takes a className and applies it to root node', () => {
174
+ render(
175
+ <Details isOpen={false} className="m-bottom-md">
176
+ <Details.Summary isDetailsOpen={false} className="m-top-lg">
177
+ summary
178
+ </Details.Summary>
179
+ </Details>
180
+ );
181
+
182
+ const details = screen.getByRole('group');
183
+ expect(details).toHaveClass('m-bottom-md');
184
+
185
+ const summary = screen.getByRole('button');
186
+ expect(summary).toHaveClass('m-top-lg');
187
+ });
188
+ });
189
+ });