@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,51 @@
1
+ import React from 'react';
2
+ import classNames from 'classnames';
3
+ import { DetailsSummary } from './DetailsSummary';
4
+ import styles from './Details.module.scss';
5
+ import { Box, BoxProps } from '../Box/Box';
6
+
7
+ export interface DetailsProps extends BoxProps {
8
+ /**
9
+ * Whether the details below the summary are opened. Directly corresponds to `open` property in <details> element.
10
+ */
11
+ isOpen: boolean;
12
+ }
13
+
14
+ export const DetailsBaseComponent: React.FC<DetailsProps> = React.forwardRef<
15
+ HTMLDetailsElement,
16
+ DetailsProps
17
+ >(({ children, className, display = 'block', isOpen, ...restProps }, ref) => {
18
+ const detailsClasses = classNames(
19
+ className,
20
+ styles['details-reset'],
21
+ styles.details
22
+ );
23
+
24
+ return (
25
+ <Box
26
+ as="details"
27
+ className={detailsClasses}
28
+ display={display}
29
+ open={isOpen}
30
+ ref={ref}
31
+ {...restProps}
32
+ >
33
+ {children}
34
+ </Box>
35
+ );
36
+ });
37
+
38
+ export interface DetailsStatic {
39
+ Summary: typeof DetailsSummary;
40
+ }
41
+
42
+ export type DetailsWithStaticComponents = typeof DetailsBaseComponent &
43
+ DetailsStatic;
44
+
45
+ // Actual component is wrapped in an IIFE for the export
46
+ // To allow tree-shaking even with static properties (subcomponents in this case).
47
+ export const Details = (() => {
48
+ const Details = DetailsBaseComponent as DetailsWithStaticComponents; // eslint-disable-line no-shadow
49
+ Details.Summary = DetailsSummary;
50
+ return Details;
51
+ })();
@@ -0,0 +1,65 @@
1
+ import React, { MouseEvent, KeyboardEvent } from 'react';
2
+ import { ENTER, SPACE } from '../../constants/keyCodes';
3
+ import { Box, BoxProps } from '../Box/Box';
4
+
5
+ export interface DetailsSummaryProps extends BoxProps {
6
+ isDetailsOpen: boolean;
7
+ onToggle?: (
8
+ event: MouseEvent<HTMLElement> | KeyboardEvent<HTMLElement>
9
+ ) => void;
10
+ }
11
+
12
+ export const DetailsSummary: React.FC<DetailsSummaryProps> = ({
13
+ children,
14
+ display = 'block',
15
+ isDetailsOpen,
16
+ onToggle,
17
+ ...restProps
18
+ }) => {
19
+ const handleClick = (event: MouseEvent<HTMLElement>) => {
20
+ // Needed to avoid default `details` behavior on a click event and keep this as controlled component.
21
+ event.preventDefault();
22
+
23
+ if (!onToggle && !restProps?.onClick) return;
24
+
25
+ if (onToggle) {
26
+ onToggle(event);
27
+ }
28
+
29
+ if (restProps?.onClick) {
30
+ restProps.onClick(event);
31
+ }
32
+ };
33
+
34
+ const handleKeyDown = (event: KeyboardEvent<HTMLElement>) => {
35
+ if ([ENTER, SPACE].indexOf(event.keyCode) !== -1) {
36
+ // Needed to avoid default `details` behavior on a click event and keep this as controlled component.
37
+ event.preventDefault();
38
+ }
39
+
40
+ if (!onToggle && !restProps?.onKeyDown) return;
41
+
42
+ if (onToggle && [ENTER, SPACE].indexOf(event.keyCode) !== -1) {
43
+ onToggle(event);
44
+ }
45
+
46
+ if (restProps?.onKeyDown) {
47
+ restProps.onKeyDown(event);
48
+ }
49
+ };
50
+
51
+ return (
52
+ <Box
53
+ {...restProps}
54
+ as="summary"
55
+ display={display}
56
+ role="button"
57
+ aria-expanded={isDetailsOpen}
58
+ tabIndex={0}
59
+ onClick={handleClick}
60
+ onKeyDown={handleKeyDown}
61
+ >
62
+ {children}
63
+ </Box>
64
+ );
65
+ };
@@ -0,0 +1,117 @@
1
+ import { Canvas, Meta, ArgTypes } from '@storybook/blocks';
2
+ import { Drawer } from './Drawer';
3
+ import { Alert } from '../Alert/Alert';
4
+ import * as Stories from './Drawer.stories';
5
+
6
+ <Meta of={Stories} />
7
+
8
+ # Drawer
9
+
10
+ A Drawer is a panel that slides in from one edge of the viewport and overlays content on top of the page. It contains information or actions without leaving the context of the original page.
11
+
12
+ <Canvas withSource="open" of={Stories.BasicUsage} />
13
+
14
+ ## Usage Guidelines
15
+
16
+ - Use the drawer as way to achieve progressive disclosure, to reveal relevant information at the appropriate time.
17
+ - The Drawer visibility is controlled via the `isOpen` prop, and is hidden by default. To handle closing the Drawer, provide an `onDismiss` callback that will be called when the user clicks the Overlay or Esc keyboard key.
18
+ - When a Drawer is open, the main body is scroll-locked by default.
19
+ - Avoid nesting Drawers to prevent usability issues.
20
+ - The button that triggers the drawer opening should be in close proximity to the Drawer itself.
21
+ - Drawers are appropriate for supplemental information, filters, or subtasks where it's important to keep the subtasks in the context of the main task
22
+
23
+ ### When not to use
24
+
25
+ - To force users to complete an action before continuing. Use a [Modal](/docs/components-modal--docs) instead.
26
+ - For small content or a few options near the original content, use a [Popover](/docs/components-popover--docs).
27
+
28
+ ## Content Guidelines
29
+
30
+ Drawers are good for short pieces of content that are related to the main screen but not a part of it. Examples include:
31
+
32
+ - Contextual help
33
+ - Notifications or activity log
34
+ - Simple forms or settings
35
+ - Navigation or page table of contents
36
+
37
+ ## Accessibility
38
+
39
+ - Use the `ariaLabel` or `ariaLabelledBy` props to properly label a drawer to provide context for users with assistive technology such as screen readers. If a drawer is announced to the user without a label, it can be confusing and difficult to navigate.
40
+ - When the Drawer is opened, focus is trapped inside the Drawer.
41
+ - The 'Esc' key will close the Drawer.
42
+ - After the drawer closes, focus is returned to the element that triggered it.
43
+
44
+ ## Props
45
+
46
+ <ArgTypes of={Drawer} />
47
+
48
+ ## Placement
49
+
50
+ The Drawer can appear from the right (default), left, top, or bottom of the screen. When appearing from the left or right of the screen, the close Icon Button is positioned on the same side where the Drawer originates from. When appearing from the top or bottom of the screen, the close Icon Button is positioned on the right as default.
51
+
52
+ <Canvas withSource="open" of={Stories.Placement} />
53
+
54
+ ## Drawer Header
55
+
56
+ A header will be added to the drawer content if `title` is defined, or `closeButton` is `true`. If the content of the drawer is taller than the drawer height, then the content will scroll while the header remains fixed to the top.
57
+
58
+ <Canvas withSource="open" of={Stories.DrawerHeader} />
59
+
60
+ ## Title and Close Button
61
+
62
+ <Canvas withSource="open" of={Stories.TitleAndCloseButton} />
63
+
64
+ ## Close Button Only
65
+
66
+ <Canvas withSource="open" of={Stories.CloseButtonOnly} />
67
+
68
+ ## Width
69
+
70
+ Set the width of a Drawer to specific value for a `left` or `right` placement via `width`. The Drawer height will be 100% of the viewport, or if `containerRef` is used, 100% of the container.
71
+
72
+ When `placement` is set to `top` or `bottom`, the `width` prop is ignored and the drawer will be 100% of the viewport or container.
73
+
74
+ <Canvas withSource="open" of={Stories.Width} />
75
+
76
+ ## Height
77
+
78
+ The height of Drawers with a `top` or `bottom` placement is determined by Drawer's contents. The width will be set to 100%.
79
+
80
+ <Canvas withSource="open" of={Stories.Height} />
81
+
82
+ ## Hidden Overlay
83
+
84
+ In cases where content in the drawer is supplemental to content on the main area of the page, use `hideOverlay` to allow for interaction between the areas (e.g. copy-and-paste text from main area into a form in the drawer).
85
+
86
+ <Alert
87
+ variant="warning"
88
+ title="Focus Management"
89
+ hasIcon
90
+ message="If you decide to use `hideOverlay`, then you must also manage focus. Focus and page scrolling will not be locked if `hideOverlay` is true. Also, the 'Esc' key button will no longer automatically close the Drawer."
91
+ />
92
+
93
+ <Canvas withSource="open" of={Stories.HiddenOverlay} />
94
+
95
+ ## Initial Focus Ref
96
+
97
+ By default the first focusable element will receive focus when the drawer opens, but you can provide a ref to focus instead.
98
+
99
+ <Alert
100
+ hasIcon
101
+ message="Without the initialFocusRef prop, the drawer will automatically focus on the first focusable element in it's children."
102
+ variant="info"
103
+ />
104
+
105
+ <Canvas withSource="open" of={Stories.InitialFocusRef} />
106
+
107
+ ## Contained Drawer
108
+
109
+ Render the Drawer within a containing div using `containerRef`.
110
+
111
+ <Alert
112
+ hasIcon
113
+ message="When choosing to use a Drawer within a containing div, use dangerouslyBypassScrollLock to allow the content outside of the containing div to remain interactive."
114
+ variant="info"
115
+ />
116
+
117
+ <Canvas withSource="open" of={Stories.ContainedDrawer} />
@@ -0,0 +1,96 @@
1
+ @import '@hyphen/hyphen-design-tokens/build/scss/variables';
2
+
3
+ .drawer {
4
+ top: 0;
5
+ right: 0;
6
+ bottom: 0;
7
+ left: 0;
8
+ z-index: var(--size-z-index-overlay);
9
+ background: hsl(0deg 0% 0% / 33%);
10
+ max-height: 100vh;
11
+ overflow: visible;
12
+
13
+ //for the hide-overlay-* classes, push the overlay to opposite edge so that underlying content is not covered
14
+ &.hide-overlay-right {
15
+ left: 100%;
16
+ background-color: transparent;
17
+ }
18
+
19
+ &.hide-overlay-left {
20
+ right: 100%;
21
+ background-color: transparent;
22
+ }
23
+
24
+ &.hide-overlay-bottom {
25
+ top: 100%;
26
+ background-color: transparent;
27
+ }
28
+
29
+ &.hide-overlay-top {
30
+ bottom: 100%;
31
+ background-color: transparent;
32
+ }
33
+
34
+ :global {
35
+ animation: fadeIn 0.2s;
36
+ }
37
+ }
38
+
39
+ .drawer {
40
+ .drawer-content {
41
+ background-color: var(--color-background-primary);
42
+ display: flex;
43
+ flex-direction: column;
44
+ padding: 0;
45
+ position: absolute;
46
+ box-shadow: var(--drawer-box-shadow, var(--size-box-shadow-xl));
47
+ z-index: var(--size-z-index-drawer);
48
+
49
+ &.left {
50
+ left: 0;
51
+ width: var(--w, 80vw);
52
+ height: 100%;
53
+
54
+ :global {
55
+ animation: fadeInRight 0.2s ease-out;
56
+ }
57
+ }
58
+
59
+ &.right {
60
+ right: 0;
61
+ width: var(--w, 80vw);
62
+ height: 100%;
63
+
64
+ :global {
65
+ animation: fadeInLeft 0.2s ease-out;
66
+ }
67
+ }
68
+
69
+ &.bottom {
70
+ bottom: 0;
71
+ width: 100%;
72
+ max-height: 100vh;
73
+
74
+ :global {
75
+ animation: fadeInUp 0.2s ease-out;
76
+ }
77
+ }
78
+
79
+ &.top {
80
+ top: 0;
81
+ width: 100%;
82
+ max-height: 100vh;
83
+
84
+ :global {
85
+ animation: fadeInDown 0.2s ease-out;
86
+ }
87
+ }
88
+
89
+ @media (min-width: $size-breakpoint-tablet) {
90
+ &.right,
91
+ &.left {
92
+ width: var(--w, var(--size-dimension-8xl));
93
+ }
94
+ }
95
+ }
96
+ }
@@ -0,0 +1,380 @@
1
+ import { Drawer, DrawerPlacementType } from './Drawer';
2
+ import type { Meta } from '@storybook/react';
3
+ import React, { MutableRefObject, useEffect, useRef, useState } from 'react';
4
+ import { useOpenClose } from '../../hooks';
5
+ import { Button } from '../Button/Button';
6
+ import { Box } from '../Box/Box';
7
+ import { RadioGroup } from '../RadioGroup/RadioGroup';
8
+ import { WidthSize } from '../../types';
9
+
10
+ const meta: Meta<typeof Drawer> = {
11
+ title: 'Components/Drawer',
12
+ component: Drawer,
13
+ };
14
+
15
+ export default meta;
16
+
17
+ export const BasicUsage = () => {
18
+ const {
19
+ isOpen: isDrawerOpen,
20
+ handleOpen: openDrawer,
21
+ handleClose: closeDrawer,
22
+ } = useOpenClose();
23
+ return (
24
+ <>
25
+ <Button variant="primary" onClick={openDrawer}>
26
+ Open Drawer
27
+ </Button>
28
+ <Drawer
29
+ isOpen={isDrawerOpen}
30
+ title="Drawer Title"
31
+ onDismiss={closeDrawer}
32
+ ariaLabel="drawer component example"
33
+ >
34
+ <Box padding="2xl" display="block" childGap="md">
35
+ <Box>Drawer content&hellip;</Box>
36
+ <Box>Drawer content&hellip;</Box>
37
+ <Box>Drawer content&hellip;</Box>
38
+ </Box>
39
+ </Drawer>
40
+ </>
41
+ );
42
+ };
43
+
44
+ export const Placement = () => {
45
+ const {
46
+ isOpen: isDrawerOpen,
47
+ handleOpen: openDrawer,
48
+ handleClose: closeDrawer,
49
+ } = useOpenClose();
50
+ const [placement, setPlacement] = useState('right');
51
+ const placementOptions = [
52
+ {
53
+ id: 'top',
54
+ value: 'top',
55
+ label: 'top',
56
+ },
57
+ {
58
+ id: 'right',
59
+ value: 'right',
60
+ label: 'right',
61
+ },
62
+ {
63
+ id: 'bottom',
64
+ value: 'bottom',
65
+ label: 'bottom',
66
+ },
67
+ {
68
+ id: 'left',
69
+ value: 'left',
70
+ label: 'left',
71
+ },
72
+ ];
73
+ return (
74
+ <Box display="block" childGap="md">
75
+ <RadioGroup
76
+ title="Placement"
77
+ direction="row"
78
+ name="placement"
79
+ onChange={(event) => setPlacement(event.target.value)}
80
+ value={placement}
81
+ options={placementOptions}
82
+ />
83
+ <Button variant="primary" onClick={openDrawer}>
84
+ Open Drawer
85
+ </Button>
86
+ <Drawer
87
+ title="test"
88
+ isOpen={isDrawerOpen}
89
+ onDismiss={closeDrawer}
90
+ placement={placement as DrawerPlacementType}
91
+ ariaLabel="drawer component example"
92
+ >
93
+ <Box padding="2xl" display="block" childGap="md">
94
+ <Box as="p">drawer content</Box>
95
+ <Box as="p">drawer content</Box>
96
+ <Box as="p">drawer content</Box>
97
+ <Box as="p">drawer content</Box>
98
+ <Box as="p">drawer content</Box>
99
+ <Box as="p">drawer content</Box>
100
+ <Box as="p">drawer content</Box>
101
+ <Box as="p">drawer content</Box>
102
+ <Box as="p">drawer content</Box>
103
+ </Box>
104
+ </Drawer>
105
+ </Box>
106
+ );
107
+ };
108
+
109
+ export const DrawerHeader = () => {
110
+ const {
111
+ isOpen: isDrawerOpen,
112
+ handleOpen: openDrawer,
113
+ handleClose: closeDrawer,
114
+ } = useOpenClose();
115
+ const drawerContent = [];
116
+ for (let i = 0; i < 50; i++) {
117
+ drawerContent.push(<Box key={i}>Drawer content&hellip;</Box>);
118
+ }
119
+ return (
120
+ <>
121
+ <Button variant="primary" onClick={openDrawer}>
122
+ Title and Close Button
123
+ </Button>
124
+ <Drawer
125
+ ariaLabel="drawer component example"
126
+ isOpen={isDrawerOpen}
127
+ onDismiss={closeDrawer}
128
+ title="Drawer Title"
129
+ >
130
+ <Box padding="2xl" display="block" childGap="md">
131
+ {drawerContent}
132
+ </Box>
133
+ </Drawer>
134
+ </>
135
+ );
136
+ };
137
+
138
+ export const TitleAndCloseButton = () => {
139
+ const {
140
+ isOpen: isDrawerOpen,
141
+ handleOpen: openDrawer,
142
+ handleClose: closeDrawer,
143
+ } = useOpenClose();
144
+ const drawerContent = [];
145
+ for (let i = 0; i < 50; i++) {
146
+ drawerContent.push(<Box key={i}>Drawer content&hellip;</Box>);
147
+ }
148
+ return (
149
+ <>
150
+ <Button variant="primary" onClick={openDrawer}>
151
+ Title and Close Button
152
+ </Button>
153
+ <Drawer
154
+ ariaLabel="drawer component example"
155
+ isOpen={isDrawerOpen}
156
+ onDismiss={closeDrawer}
157
+ title="Drawer Title"
158
+ >
159
+ <Box padding="2xl" display="block" childGap="md">
160
+ {drawerContent}
161
+ </Box>
162
+ </Drawer>
163
+ </>
164
+ );
165
+ };
166
+
167
+ export const CloseButtonOnly = () => {
168
+ const {
169
+ isOpen: isDrawerOpen,
170
+ handleOpen: openDrawer,
171
+ handleClose: closeDrawer,
172
+ } = useOpenClose();
173
+ const drawerContent = [];
174
+ for (let i = 0; i < 50; i++) {
175
+ drawerContent.push(<Box key={i}>Drawer content&hellip;</Box>);
176
+ }
177
+ return (
178
+ <>
179
+ <Button variant="primary" onClick={openDrawer}>
180
+ Close Button Only
181
+ </Button>
182
+ <Drawer
183
+ ariaLabel="drawer component example"
184
+ isOpen={isDrawerOpen}
185
+ onDismiss={closeDrawer}
186
+ closeButton
187
+ >
188
+ <Box padding="2xl" display="block" childGap="md">
189
+ {drawerContent}
190
+ </Box>
191
+ </Drawer>
192
+ </>
193
+ );
194
+ };
195
+
196
+ export const Width = () => {
197
+ const {
198
+ isOpen: isDrawerOpen,
199
+ handleOpen: openDrawer,
200
+ handleClose: closeDrawer,
201
+ } = useOpenClose();
202
+ const [width, setWidth] = React.useState('default');
203
+ const handleClick = (newWidth: WidthSize) => {
204
+ setWidth(newWidth);
205
+ openDrawer();
206
+ };
207
+ const widths = ['16rem', '400px', '100%'];
208
+ return (
209
+ <>
210
+ <Box gap="sm" direction="row">
211
+ {widths.map((width: string) => (
212
+ <Button
213
+ variant="primary"
214
+ onClick={() => handleClick(width as WidthSize)}
215
+ key={width}
216
+ >
217
+ {`Open ${width} Drawer `}
218
+ </Button>
219
+ ))}
220
+ </Box>
221
+ <Drawer
222
+ width={width as WidthSize}
223
+ title={`${width} wide drawer`}
224
+ isOpen={isDrawerOpen}
225
+ onDismiss={closeDrawer}
226
+ closeButton
227
+ ariaLabel="drawer component example"
228
+ >
229
+ <Box padding="2xl" display="block" childGap="md">
230
+ <Box>drawer content</Box>
231
+ </Box>
232
+ </Drawer>
233
+ </>
234
+ );
235
+ };
236
+
237
+ export const Height = () => {
238
+ const {
239
+ isOpen: isDrawerOpen,
240
+ handleOpen: openDrawer,
241
+ handleClose: closeDrawer,
242
+ } = useOpenClose();
243
+ return (
244
+ <>
245
+ <Button variant="primary" onClick={openDrawer}>
246
+ Open Drawer
247
+ </Button>
248
+ <Drawer
249
+ placement="top"
250
+ isOpen={isDrawerOpen}
251
+ onDismiss={closeDrawer}
252
+ closeButton
253
+ ariaLabel="drawer component example"
254
+ >
255
+ <Box padding="lg" height="3xl" display="block" childGap="md">
256
+ <Box>3xl Height</Box>
257
+ </Box>
258
+ </Drawer>
259
+ </>
260
+ );
261
+ };
262
+
263
+ export const HiddenOverlay = () => {
264
+ const closeBtnRef = useRef<HTMLButtonElement>();
265
+ const returnFocusRef = useRef<HTMLButtonElement>();
266
+ const returnFocus = () => {
267
+ if (returnFocusRef && returnFocusRef.current) {
268
+ returnFocusRef.current.focus();
269
+ }
270
+ };
271
+ const {
272
+ isOpen: isDrawerOpen,
273
+ handleToggle: handleDrawerToggle,
274
+ handleClose: closeDrawer,
275
+ } = useOpenClose({ onClose: returnFocus });
276
+ useEffect(() => {
277
+ setTimeout(() => {
278
+ if (closeBtnRef && closeBtnRef.current) {
279
+ closeBtnRef.current.focus();
280
+ }
281
+ }, 100);
282
+ }, [isDrawerOpen]);
283
+ return (
284
+ <>
285
+ <Button
286
+ variant="primary"
287
+ onClick={handleDrawerToggle}
288
+ ref={returnFocusRef as MutableRefObject<HTMLButtonElement>}
289
+ >
290
+ Toggle Drawer
291
+ </Button>
292
+ <Drawer
293
+ isOpen={isDrawerOpen}
294
+ onDismiss={closeDrawer}
295
+ ariaLabel="drawer component example"
296
+ hideOverlay
297
+ >
298
+ <Box padding="2xl" display="block" childGap="md">
299
+ <Button
300
+ ref={closeBtnRef as MutableRefObject<HTMLButtonElement>}
301
+ onClick={closeDrawer}
302
+ variant="primary"
303
+ >
304
+ close
305
+ </Button>
306
+ <Box>drawer content</Box>
307
+ </Box>
308
+ </Drawer>
309
+ </>
310
+ );
311
+ };
312
+
313
+ export const InitialFocusRef = () => {
314
+ const {
315
+ isOpen: isDrawerOpen,
316
+ handleOpen: openDrawer,
317
+ handleClose: closeDrawer,
318
+ } = useOpenClose();
319
+ const ref = useRef(null);
320
+ return (
321
+ <>
322
+ <Button variant="primary" onClick={openDrawer}>
323
+ Open Drawer
324
+ </Button>
325
+ <Drawer
326
+ isOpen={isDrawerOpen}
327
+ onDismiss={closeDrawer}
328
+ initialFocusRef={ref}
329
+ title="initialFocusRef"
330
+ ariaLabel="drawer component example"
331
+ >
332
+ <Box padding="2xl" display="block" childGap="md">
333
+ <Box>drawer content</Box>
334
+ <Button variant="primary" ref={ref} onClick={closeDrawer}>
335
+ I receive focus
336
+ </Button>
337
+ </Box>
338
+ </Drawer>
339
+ </>
340
+ );
341
+ };
342
+
343
+ export const ContainedDrawer = () => {
344
+ const containerRef = useRef<HTMLDivElement>();
345
+ const {
346
+ isOpen: isDrawerOpen,
347
+ handleOpen: openDrawer,
348
+ handleClose: closeDrawer,
349
+ } = useOpenClose();
350
+ return (
351
+ <Box
352
+ position="relative"
353
+ display="block"
354
+ height="500px"
355
+ id="myContainer"
356
+ ref={containerRef}
357
+ background="info"
358
+ padding="lg"
359
+ overflow="hidden"
360
+ >
361
+ <Button variant="primary" onClick={openDrawer}>
362
+ Show Drawer
363
+ </Button>
364
+ <Drawer
365
+ isOpen={isDrawerOpen}
366
+ onDismiss={closeDrawer}
367
+ containerRef={containerRef as MutableRefObject<HTMLDivElement>}
368
+ dangerouslyBypassScrollLock
369
+ hideOverlay
370
+ title="containerRef"
371
+ ariaLabel="drawer component example"
372
+ >
373
+ <Box padding="lg" as="p">
374
+ This drawer is rendered inside it&apos;s containing div, rather than
375
+ the document.body
376
+ </Box>
377
+ </Drawer>
378
+ </Box>
379
+ );
380
+ };