@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,341 @@
1
+ import React from 'react';
2
+ import { render, fireEvent, screen } from '@testing-library/react';
3
+ import { BreakpointSize } from '../../types';
4
+ import { SelectInputNative } from './SelectInputNative';
5
+
6
+ const selectOptions = [
7
+ { value: 'chocolate', label: 'Chocolate' },
8
+ { value: 'strawberry', label: 'Strawberry' },
9
+ { value: 'vanilla', label: 'Vanilla' },
10
+ ];
11
+
12
+ function getByTextWithMarkup(text: string) {
13
+ // eslint-disable-next-line
14
+ // @ts-ignore
15
+ return (content, element) => {
16
+ const hasText = (node: Element) => node.textContent === text;
17
+ const elementHasText = hasText(element);
18
+ // eslint-disable-next-line
19
+ // @ts-ignore
20
+ const childrenDontHaveText = Array.from(element.children).every(
21
+ (child) => !hasText(child as Element)
22
+ );
23
+
24
+ return elementHasText && childrenDontHaveText;
25
+ };
26
+ }
27
+
28
+ describe('SelectInputNative', () => {
29
+ describe('Callback Handling', () => {
30
+ test('it fires onChange callback on change', async () => {
31
+ const mockedHandleChange = jest.fn();
32
+
33
+ const { getByLabelText } = render(
34
+ <SelectInputNative
35
+ id="testId"
36
+ onChange={mockedHandleChange}
37
+ placeholder="Test Placeholder"
38
+ label="onchange test"
39
+ options={selectOptions}
40
+ value={null}
41
+ />
42
+ );
43
+
44
+ await fireEvent.change(getByLabelText('onchange test'));
45
+
46
+ expect(mockedHandleChange).toBeCalledTimes(1);
47
+ });
48
+
49
+ test('it fires onFocus callback on focus', () => {
50
+ const mockedHandleChange = jest.fn();
51
+ const mockedHandleFocus = jest.fn();
52
+
53
+ render(
54
+ <SelectInputNative
55
+ id="testId"
56
+ onChange={mockedHandleChange}
57
+ onFocus={mockedHandleFocus}
58
+ placeholder="Test Placeholder"
59
+ options={selectOptions}
60
+ value={null}
61
+ label="onfocus test"
62
+ />
63
+ );
64
+ const select = screen.getByLabelText('onfocus test');
65
+ fireEvent.focus(select);
66
+
67
+ expect(mockedHandleFocus).toBeCalledTimes(1);
68
+ });
69
+
70
+ test('it fires onBlur callback on blur', () => {
71
+ const mockedHandleChange = jest.fn();
72
+ const mockedHandleBlur = jest.fn();
73
+
74
+ render(
75
+ <SelectInputNative
76
+ id="testId"
77
+ onChange={mockedHandleChange}
78
+ onBlur={mockedHandleBlur}
79
+ placeholder="Test Placeholder"
80
+ options={selectOptions}
81
+ value={null}
82
+ label="onblur test"
83
+ />
84
+ );
85
+
86
+ const select = screen.getByLabelText('onblur test');
87
+ fireEvent.blur(select);
88
+
89
+ expect(mockedHandleBlur).toBeCalledTimes(1);
90
+ });
91
+ });
92
+
93
+ describe('States', () => {
94
+ describe('Hidden label, with a placeholder', () => {
95
+ test('it renders input without a visual label, and with a placeholder', () => {
96
+ const mockedHandleChange = jest.fn();
97
+
98
+ render(
99
+ <SelectInputNative
100
+ id="testId"
101
+ label="hidden label"
102
+ hideLabel
103
+ onChange={mockedHandleChange}
104
+ placeholder="Test Placeholder"
105
+ options={selectOptions}
106
+ value={null}
107
+ />
108
+ );
109
+ expect(screen.queryByText('hidden label')).toBeNull();
110
+ expect(screen.getByText('Test Placeholder')).toBeInTheDocument();
111
+ });
112
+ });
113
+
114
+ test('does not assign "aria-labelledby" attribute when a label is hidden', () => {
115
+ const mockedHandleChange = jest.fn();
116
+
117
+ render(
118
+ <SelectInputNative
119
+ id="testInput"
120
+ label="hidden label"
121
+ hideLabel
122
+ onChange={mockedHandleChange}
123
+ options={selectOptions}
124
+ value={null}
125
+ />
126
+ );
127
+ const inputElement = screen.getByLabelText('hidden label');
128
+ expect(inputElement).not.toHaveAttribute('aria-labelledby');
129
+ });
130
+
131
+ describe('With a label, and no custom placeholder', () => {
132
+ test('it renders input with a label, and with a default placeholder', () => {
133
+ const mockedHandleChange = jest.fn();
134
+
135
+ render(
136
+ <SelectInputNative
137
+ id="testId"
138
+ onChange={mockedHandleChange}
139
+ label="Select Label"
140
+ options={selectOptions}
141
+ value={selectOptions[1].value}
142
+ />
143
+ );
144
+
145
+ expect(screen.getByLabelText('Select Label')).toBeInTheDocument();
146
+ expect(screen.getByText('Select...')).toBeInTheDocument();
147
+ });
148
+
149
+ test('assigns the "aria-labelledby" attribute and renders label correct id, when a label is provided', () => {
150
+ render(
151
+ <SelectInputNative
152
+ id="testInput"
153
+ label="test label"
154
+ options={selectOptions}
155
+ value={null}
156
+ onChange={() => null}
157
+ />
158
+ );
159
+ const inputElement = screen.getByLabelText('test label');
160
+ expect(inputElement).toHaveAttribute(
161
+ 'aria-labelledby',
162
+ 'testInputLabel'
163
+ );
164
+ expect(document.getElementById('testInputLabel')).toBeInTheDocument();
165
+ });
166
+ });
167
+
168
+ // @TODO -- This test doesn't do what we need at this time. Need to find a way to check for the selected value
169
+ // but react doesnt use the select attr in options.
170
+ /* eslint-disable */
171
+ // describe('Single select, pre-selected', () => {
172
+ // test('it renders with value pre-selected', () => {
173
+ // const mockedHandleChange = jest.fn();
174
+
175
+ // const { debug } = render(
176
+ // <SelectInputNative
177
+ // id="testId"
178
+ // onChange={mockedHandleChange}
179
+ // label="Select Label"
180
+ // options={selectOptions}
181
+ // value={selectOptions[2].value}
182
+ // />,
183
+ // );
184
+ // const selectElement = screen.getByLabelText('Select Label');
185
+ // const option = screen.getByText('Vanilla');
186
+
187
+ // expect(option).toHaveAttribute('selected', true);
188
+ // });
189
+ // });
190
+ /* eslint-enable */
191
+
192
+ describe('Is Required', () => {
193
+ test('it sets the required and aria-required properties on the input', () => {
194
+ const mockedHandleChange = jest.fn();
195
+
196
+ render(
197
+ <SelectInputNative
198
+ id="testId"
199
+ onChange={mockedHandleChange}
200
+ label="Required Select"
201
+ options={selectOptions}
202
+ isRequired
203
+ value={selectOptions[0].value}
204
+ />
205
+ );
206
+
207
+ const inputElement = screen.getByLabelText('Required Select');
208
+ expect(inputElement).toHaveAttribute('aria-required', 'true');
209
+ expect(inputElement).toHaveAttribute('required');
210
+ });
211
+
212
+ test('it renders an asterisk in the label by default', () => {
213
+ const mockedHandleChange = jest.fn();
214
+
215
+ render(
216
+ <SelectInputNative
217
+ id="testId"
218
+ onChange={mockedHandleChange}
219
+ label="Select Label"
220
+ options={selectOptions}
221
+ isRequired
222
+ value={selectOptions[0].value}
223
+ />
224
+ );
225
+
226
+ expect(
227
+ screen.getByText(getByTextWithMarkup('Select Label *'))
228
+ ).toBeInTheDocument();
229
+ });
230
+ });
231
+
232
+ describe('Is Disabled', () => {
233
+ test('it disables the input', () => {
234
+ const mockedHandleChange = jest.fn();
235
+
236
+ render(
237
+ <SelectInputNative
238
+ id="testId"
239
+ onChange={mockedHandleChange}
240
+ label="disabled test"
241
+ options={selectOptions}
242
+ isDisabled
243
+ value={null}
244
+ />
245
+ );
246
+ const select = screen.getByLabelText('disabled test');
247
+ expect(select).toBeDisabled();
248
+ });
249
+ });
250
+
251
+ describe('Is Invalid, with a helpful message', () => {
252
+ test('it renders the helpful message', () => {
253
+ const mockedHandleChange = jest.fn();
254
+
255
+ render(
256
+ <SelectInputNative
257
+ id="testId"
258
+ onChange={mockedHandleChange}
259
+ label="Select Label"
260
+ options={selectOptions}
261
+ error="Helpful message"
262
+ value={null}
263
+ />
264
+ );
265
+
266
+ expect(screen.getByText('Helpful message')).toBeInTheDocument();
267
+ });
268
+ });
269
+ });
270
+
271
+ describe('Sizes', () => {
272
+ const mockedHandleChange = jest.fn();
273
+ const sizes = ['sm', 'md', 'lg'] as ('sm' | 'md' | 'lg')[];
274
+
275
+ const breakpoints: BreakpointSize[] = ['tablet', 'desktop', 'hd'];
276
+
277
+ sizes.forEach((size) => {
278
+ test(`it has a ${size} class applied to it`, () => {
279
+ render(
280
+ <SelectInputNative
281
+ id="testId"
282
+ onChange={mockedHandleChange}
283
+ options={selectOptions}
284
+ value={selectOptions[0].value}
285
+ size={size}
286
+ label="size test"
287
+ />
288
+ );
289
+ const select = screen.getByLabelText('size test');
290
+ const selectParent = select.closest('div');
291
+ expect(selectParent?.getAttribute('class')).toContain(size);
292
+ });
293
+
294
+ breakpoints.forEach((breakpoint) => {
295
+ test(`it applies responsive classes for breakpoint: ${breakpoint} and size: ${size}`, () => {
296
+ render(
297
+ <SelectInputNative
298
+ id="testId"
299
+ onChange={mockedHandleChange}
300
+ options={selectOptions}
301
+ value={selectOptions[0].value}
302
+ size={{ [breakpoint]: size }}
303
+ label="size test"
304
+ />
305
+ );
306
+ const select = screen.getByLabelText('size test');
307
+ const selectParent = select.closest('div');
308
+
309
+ expect(selectParent?.getAttribute('class')).toContain(
310
+ `size-${size}-${breakpoint}`
311
+ );
312
+ });
313
+ });
314
+ });
315
+
316
+ test('It applies responsive classes when multiple are applied', () => {
317
+ render(
318
+ <SelectInputNative
319
+ id="testId"
320
+ onChange={mockedHandleChange}
321
+ options={selectOptions}
322
+ value={selectOptions[0].value}
323
+ size={{
324
+ base: 'sm',
325
+ tablet: 'md',
326
+ desktop: 'lg',
327
+ hd: 'sm',
328
+ }}
329
+ label="size test"
330
+ />
331
+ );
332
+ const select = screen.getByLabelText('size test');
333
+ const selectParent = select.closest('div');
334
+
335
+ expect(selectParent?.getAttribute('class')).toContain('size-sm');
336
+ expect(selectParent?.getAttribute('class')).toContain('size-md-tablet');
337
+ expect(selectParent?.getAttribute('class')).toContain('size-lg-desktop');
338
+ expect(selectParent?.getAttribute('class')).toContain('size-sm-hd');
339
+ });
340
+ });
341
+ });
@@ -0,0 +1,121 @@
1
+ import React from 'react';
2
+ import classNames from 'classnames';
3
+ import { generateResponsiveClasses } from '../../lib/generateResponsiveClasses';
4
+ import { ResponsiveProp } from '../../types';
5
+ import { Box, BoxProps } from '../Box/Box';
6
+ import { FormControl, FormControlProps } from '../FormControl/FormControl';
7
+ import styles from './SelectInputNative.module.scss';
8
+
9
+ export type SelectInputNativeSize = 'sm' | 'md' | 'lg';
10
+ export interface SelectInputNativeProps extends BoxProps, FormControlProps {
11
+ /**
12
+ * List of options for the select input.
13
+ */
14
+ options: { value: string | number; label: string | number }[];
15
+ /**
16
+ * onChange callback from select element.
17
+ */
18
+ onChange: (event: React.ChangeEvent<HTMLSelectElement>) => void;
19
+ /**
20
+ * Value of selected option. Should match the value key in the option object.
21
+ */
22
+ value: string | number | null;
23
+ /**
24
+ * The input's 'name' attribute.
25
+ */
26
+ name?: string;
27
+ /**
28
+ * Visual indicator that the field is required, that gets appended to the label
29
+ */
30
+ requiredIndicator?: React.ReactNode;
31
+ /**
32
+ * Size of the input. ('sm' | 'md' | 'lg')
33
+ */
34
+ size?: SelectInputNativeSize | ResponsiveProp<SelectInputNativeSize>;
35
+ /**
36
+ * Whether the input is autofocused on initial render.
37
+ */
38
+ autoFocus?: HTMLSelectElement['autofocus'];
39
+ /**
40
+ * Additional props to be spread.
41
+ */
42
+ [x: string]: any; // eslint-disable-line
43
+ }
44
+
45
+ export const SelectInputNative: React.FC<SelectInputNativeProps> = ({
46
+ autoFocus = false,
47
+ label,
48
+ hideLabel,
49
+ helpText,
50
+ error,
51
+ id,
52
+ isDisabled,
53
+ isRequired,
54
+ name,
55
+ value,
56
+ options,
57
+ onChange,
58
+ placeholder = 'Select...',
59
+ requiredIndicator = ' *',
60
+ size = 'md',
61
+ ...restProps
62
+ }) => {
63
+ const placeholderOption = { value: '', label: placeholder };
64
+ const optionsWithPlaceholder = [{ ...placeholderOption }, ...options];
65
+
66
+ const responsiveClasses = generateResponsiveClasses('size', size);
67
+
68
+ const selectWrapperClasses = classNames(
69
+ 'hyphen-components__variables__form-control',
70
+ styles['select-input-native-wrapper'],
71
+ ...responsiveClasses.map((className) => styles[className]),
72
+ {
73
+ [styles.disabled]: isDisabled,
74
+ [styles.error]: error,
75
+ }
76
+ );
77
+
78
+ return (
79
+ <FormControl
80
+ label={label}
81
+ hideLabel={hideLabel}
82
+ id={id}
83
+ error={error}
84
+ helpText={helpText}
85
+ isDisabled={isDisabled}
86
+ isRequired={isRequired}
87
+ requiredIndicator={requiredIndicator}
88
+ {...restProps}
89
+ >
90
+ <Box className={selectWrapperClasses}>
91
+ <Box
92
+ as="select"
93
+ aria-label={label}
94
+ aria-labelledby={label && !hideLabel ? `${id}Label` : undefined}
95
+ aria-required={isRequired}
96
+ value={value ?? ''}
97
+ onChange={onChange}
98
+ color={!value ? 'disabled' : 'base'}
99
+ autoFocus={autoFocus}
100
+ disabled={isDisabled}
101
+ name={name}
102
+ id={id}
103
+ required={isRequired}
104
+ >
105
+ {optionsWithPlaceholder.map((option) => (
106
+ <Box
107
+ as="option"
108
+ key={option.value}
109
+ value={option.value}
110
+ disabled={option.value === ''}
111
+ hidden={option.value === ''}
112
+ color={option.value === '' ? 'disabled' : 'base'}
113
+ >
114
+ {option.label}
115
+ </Box>
116
+ ))}
117
+ </Box>
118
+ </Box>
119
+ </FormControl>
120
+ );
121
+ };
@@ -0,0 +1,29 @@
1
+ import { Spinner } from './Spinner';
2
+ import { Meta, Story, Canvas, ArgTypes } from '@storybook/addon-docs';
3
+ import * as Stories from './Spinner.stories';
4
+
5
+ <Meta of={Stories} />
6
+
7
+ # Spinner
8
+
9
+ Spinners are used to communicate a loading state to the user.
10
+ They may be used in buttons, forms, containers, pages,
11
+ and anywhere else a loading state is necessary.
12
+
13
+ <Canvas isExpanded of={Stories.Default} />
14
+
15
+ ## Props
16
+
17
+ <ArgTypes of={Spinner} />
18
+
19
+ ## Variants
20
+
21
+ Spinner will inherit the font color of its parent.
22
+
23
+ <Canvas of={Stories.Color} />
24
+
25
+ ## Sizes
26
+
27
+ Use the `size` prop on your Spinner based on what's a best fit for your layout
28
+
29
+ <Canvas of={Stories.Sizes} />
@@ -0,0 +1,16 @@
1
+ .spinner {
2
+ svg {
3
+ display: inherit;
4
+ animation: spin 1.5s infinite linear;
5
+
6
+ @keyframes spin {
7
+ 0% {
8
+ transform: rotate(0deg);
9
+ }
10
+
11
+ 100% {
12
+ transform: rotate(360deg);
13
+ }
14
+ }
15
+ }
16
+ }
@@ -0,0 +1,48 @@
1
+ import { Box } from '../Box/Box';
2
+ import type { Meta } from '@storybook/react';
3
+ import React from 'react';
4
+ import { Spinner } from './Spinner';
5
+
6
+ const meta: Meta<typeof Spinner> = {
7
+ title: 'Components/Spinner',
8
+ component: Spinner,
9
+ };
10
+
11
+ export default meta;
12
+
13
+ export const Default = () => <Spinner />;
14
+
15
+ export const Color = () => (
16
+ <Box display="block" childGap="md">
17
+ <Box>
18
+ <Spinner />
19
+ </Box>
20
+ <Box color="success">
21
+ <Spinner />
22
+ </Box>
23
+ <Box color="inverse">
24
+ <Spinner />
25
+ </Box>
26
+ </Box>
27
+ );
28
+
29
+ export const Sizes = () => (
30
+ <Box direction="row" childGap="md">
31
+ <Box direction="row" childGap="sm">
32
+ <Spinner size="sm" />
33
+ <div>sm</div>
34
+ </Box>
35
+ <Box direction="row" childGap="sm">
36
+ <Spinner size="md" />
37
+ <div>md</div>
38
+ </Box>
39
+ <Box direction="row" childGap="sm">
40
+ <Spinner size="lg" />
41
+ <div>lg</div>
42
+ </Box>
43
+ <Box direction="row" childGap="sm">
44
+ <Spinner size="xl" />
45
+ <div>xl</div>
46
+ </Box>
47
+ </Box>
48
+ );
@@ -0,0 +1,47 @@
1
+ import React from 'react';
2
+ import { Spinner } from './Spinner';
3
+ import { render } from '@testing-library/react';
4
+
5
+ describe('Spinner', () => {
6
+ describe('States', () => {
7
+ describe('Default', () => {
8
+ test('Renders with default props', () => {
9
+ const defaultSize = '16';
10
+ const { getByTestId } = render(<Spinner />);
11
+ const svg = getByTestId('spinner-testid');
12
+ expect(svg).toBeInTheDocument();
13
+ expect(svg).toHaveAttribute('width', defaultSize);
14
+ expect(svg).toHaveAttribute('height', defaultSize);
15
+ });
16
+ });
17
+
18
+ describe('Sizes', () => {
19
+ test('Renders with proper size when passed `sm` prop', () => {
20
+ const smallSize = '12';
21
+ const { getByTestId } = render(<Spinner size="sm" />);
22
+ const svg = getByTestId('spinner-testid');
23
+ expect(svg).toBeInTheDocument();
24
+ expect(svg).toHaveAttribute('width', smallSize);
25
+ expect(svg).toHaveAttribute('height', smallSize);
26
+ });
27
+
28
+ test('Renders with proper size when passed `lg` prop', () => {
29
+ const largeSize = '24';
30
+ const { getByTestId } = render(<Spinner size="lg" />);
31
+ const svg = getByTestId('spinner-testid');
32
+ expect(svg).toBeInTheDocument();
33
+ expect(svg).toHaveAttribute('width', largeSize);
34
+ expect(svg).toHaveAttribute('height', largeSize);
35
+ });
36
+
37
+ test('Renders with proper size when passed `xl` prop', () => {
38
+ const extraLargeSize = '30';
39
+ const { getByTestId } = render(<Spinner size="xl" />);
40
+ const svg = getByTestId('spinner-testid');
41
+ expect(svg).toBeInTheDocument();
42
+ expect(svg).toHaveAttribute('width', extraLargeSize);
43
+ expect(svg).toHaveAttribute('height', extraLargeSize);
44
+ });
45
+ });
46
+ });
47
+ });