@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,222 @@
1
+ import React from 'react';
2
+ import { render, fireEvent, screen } from '@testing-library/react';
3
+ import { TextInputInset } from './TextInputInset';
4
+
5
+ const baseProps = {
6
+ name: 'firstName',
7
+ id: 'firstName',
8
+ label: 'first name',
9
+ value: 'hello',
10
+ onChange: () => null,
11
+ onClear: undefined,
12
+ };
13
+
14
+ describe('TextInput', () => {
15
+ describe('Callback Handling', () => {
16
+ describe('onChange', () => {
17
+ test('onChange event fires callback function', () => {
18
+ const mockedHandleChange = jest.fn(() => null);
19
+
20
+ render(<TextInputInset {...baseProps} onChange={mockedHandleChange} />);
21
+ const inputElement = screen.getByDisplayValue(baseProps.value);
22
+
23
+ fireEvent.change(inputElement, { target: { value: 'good bye' } });
24
+ expect(mockedHandleChange).toHaveBeenCalledTimes(1);
25
+ });
26
+
27
+ test('Input value is updated properly when upper state changes', () => {
28
+ let value = 'hello';
29
+ const mockedHandleChange = jest.fn((event) => {
30
+ value = event.target.value;
31
+ });
32
+ const { rerender } = render(
33
+ <TextInputInset
34
+ {...baseProps}
35
+ value={value}
36
+ onChange={mockedHandleChange}
37
+ />
38
+ );
39
+
40
+ const inputElement = screen.getByDisplayValue(
41
+ 'hello'
42
+ ) as HTMLInputElement;
43
+ expect(inputElement.value).toBe('hello');
44
+
45
+ fireEvent.change(inputElement, { target: { value: 'good bye' } });
46
+ expect(mockedHandleChange).toHaveBeenCalledTimes(1);
47
+
48
+ rerender(
49
+ <TextInputInset
50
+ {...baseProps}
51
+ value={value}
52
+ onChange={mockedHandleChange}
53
+ />
54
+ );
55
+ expect(inputElement.value).toBe('good bye');
56
+ });
57
+ });
58
+
59
+ describe('onClear', () => {
60
+ test('onClear prop renders clear icon when input has value', () => {
61
+ render(<TextInputInset {...baseProps} onClear={() => null} />);
62
+ const clearButton = screen.getByTestId('text-input-clear-button');
63
+ expect(clearButton).toBeInTheDocument();
64
+ });
65
+
66
+ test('onClear event fires callback function', () => {
67
+ const mockedHandleClear = jest.fn(() => null);
68
+
69
+ render(<TextInputInset {...baseProps} onClear={mockedHandleClear} />);
70
+ const clearButton = screen.getByTestId('text-input-clear-button');
71
+ expect(clearButton).toBeInTheDocument();
72
+
73
+ fireEvent.click(clearButton);
74
+ expect(mockedHandleClear).toHaveBeenCalledTimes(1);
75
+ fireEvent.keyUp(clearButton, { keyCode: 13 });
76
+ expect(mockedHandleClear).toHaveBeenCalledTimes(2);
77
+ fireEvent.keyUp(clearButton, { keyCode: 99 });
78
+ expect(mockedHandleClear).toHaveBeenCalledTimes(2);
79
+ });
80
+ });
81
+
82
+ describe('onFocus', () => {
83
+ test('Input fires onFocus callback', () => {
84
+ const mockedHandleFocus = jest.fn();
85
+ render(<TextInputInset {...baseProps} onFocus={mockedHandleFocus} />);
86
+ const inputElement = screen.getByDisplayValue(baseProps.value);
87
+ fireEvent.focus(inputElement);
88
+ expect(mockedHandleFocus).toBeCalledTimes(1);
89
+ });
90
+ });
91
+
92
+ describe('onBlur', () => {
93
+ test('Input fires onBlur callback', () => {
94
+ const mockedHandleBlur = jest.fn();
95
+ render(<TextInputInset {...baseProps} onBlur={mockedHandleBlur} />);
96
+ const inputElement = screen.getByDisplayValue(baseProps.value);
97
+ fireEvent.focus(inputElement);
98
+ fireEvent.blur(inputElement);
99
+ expect(mockedHandleBlur).toBeCalledTimes(1);
100
+ });
101
+ });
102
+ });
103
+
104
+ describe('States', () => {
105
+ describe('Label', () => {
106
+ test('it renders a label', () => {
107
+ render(<TextInputInset {...baseProps} />);
108
+
109
+ const labelElement = screen.getByText(baseProps.label);
110
+
111
+ expect(labelElement).toBeInTheDocument();
112
+ });
113
+ });
114
+
115
+ describe('Autofocused', () => {
116
+ test('Input autofocuses if "autoFocus" prop is set to true', () => {
117
+ render(<TextInputInset {...baseProps} autoFocus />);
118
+ const inputElement = screen.getByDisplayValue(baseProps.value);
119
+ expect(document.activeElement).toEqual(inputElement);
120
+ });
121
+ });
122
+
123
+ describe('Autocomplete', () => {
124
+ test('Input correctly assigns autocomplete value of "on" when bool true is provided', () => {
125
+ render(<TextInputInset {...baseProps} autoComplete />);
126
+ const inputElement = screen.getByDisplayValue(baseProps.value);
127
+ expect(inputElement).toHaveAttribute('autocomplete', 'on');
128
+ });
129
+
130
+ test('Input correctly assigns autocomplete value of "off" when bool false is provided', () => {
131
+ render(<TextInputInset {...baseProps} autoComplete={false} />);
132
+ const inputElement = screen.getByDisplayValue('hello');
133
+ expect(inputElement).toHaveAttribute('autocomplete', 'off');
134
+ });
135
+
136
+ test('Input correctly assigns autocomplete specific value when provided', () => {
137
+ render(<TextInputInset {...baseProps} autoComplete="email" />);
138
+ const inputElement = screen.getByDisplayValue('hello');
139
+ expect(inputElement).toHaveAttribute('autocomplete', 'email');
140
+ });
141
+ });
142
+
143
+ describe('Required', () => {
144
+ test('it correctly assigns the "aria-required" attribute when "isRequired" prop is true', () => {
145
+ render(<TextInputInset {...baseProps} isRequired />);
146
+
147
+ const inputElement = screen.getByDisplayValue('hello');
148
+
149
+ expect(inputElement).toHaveAttribute('aria-required', 'true');
150
+ });
151
+ });
152
+
153
+ describe('Error', () => {
154
+ test('Input correctly displays error message if provided', () => {
155
+ render(<TextInputInset {...baseProps} error="You silly goose" />);
156
+
157
+ const validationMessageElement = screen.getByText('You silly goose');
158
+
159
+ expect(validationMessageElement).toBeInTheDocument();
160
+ expect(validationMessageElement).toHaveTextContent('You silly goose');
161
+ });
162
+ });
163
+
164
+ describe('Help Text', () => {
165
+ test('Input renders help text', async () => {
166
+ const { getByText } = render(
167
+ <TextInputInset {...baseProps} value="" helpText="i am help text" />
168
+ );
169
+
170
+ expect(getByText('i am help text')).toBeDefined();
171
+ });
172
+ });
173
+
174
+ describe('Max Length', () => {
175
+ test('Input correctly passes maxlength property if prop is passed', async () => {
176
+ render(<TextInputInset {...baseProps} value="" maxLength={3} />);
177
+
178
+ const inputElement = screen.getByLabelText(baseProps.label);
179
+ expect(inputElement).toBeInTheDocument();
180
+ expect(inputElement).toHaveAttribute('maxlength');
181
+ expect(inputElement.getAttribute('maxlength')).toBe('3');
182
+ });
183
+ });
184
+
185
+ describe('Name', () => {
186
+ test('Input correctly passes name property if prop is passed', async () => {
187
+ render(
188
+ <TextInputInset {...baseProps} value="" name="test floating label" />
189
+ );
190
+
191
+ const inputElement = screen.getByLabelText(baseProps.label);
192
+ expect(inputElement).toBeInTheDocument();
193
+ expect(inputElement).toHaveAttribute('name');
194
+ expect(inputElement.getAttribute('name')).toBe('test floating label');
195
+ });
196
+ });
197
+
198
+ describe('Aria-labelledby', () => {
199
+ test('assigns the "aria-labelledby" attribute and renders label with correct id, when label is provided', () => {
200
+ render(<TextInputInset {...baseProps} />);
201
+ const inputElement = screen.getByDisplayValue(baseProps.value);
202
+ expect(inputElement).toHaveAttribute(
203
+ 'aria-labelledby',
204
+ `${baseProps.id}Label`
205
+ );
206
+ expect(document.getElementById(baseProps.id)).toBeInTheDocument();
207
+ });
208
+ });
209
+
210
+ describe('Prefix and Suffix', () => {
211
+ test('renders the prefix if specified', () => {
212
+ render(<TextInputInset {...baseProps} prefix="prefixValue" />);
213
+ expect(screen.getByText('prefixValue')).toBeInTheDocument();
214
+ });
215
+
216
+ test('renders the suffix if specified', () => {
217
+ render(<TextInputInset {...baseProps} suffix="suffixValue" />);
218
+ expect(screen.getByText('suffixValue')).toBeInTheDocument();
219
+ });
220
+ });
221
+ });
222
+ });
@@ -0,0 +1,261 @@
1
+ import React, {
2
+ ChangeEvent,
3
+ forwardRef,
4
+ MouseEvent,
5
+ KeyboardEvent,
6
+ FocusEvent,
7
+ ForwardRefExoticComponent,
8
+ ReactNode,
9
+ HTMLProps,
10
+ InputHTMLAttributes,
11
+ } from 'react';
12
+ import classNames from 'classnames';
13
+ import { ResponsiveProp } from '../../types';
14
+ import { generateResponsiveClasses } from '../../lib/generateResponsiveClasses';
15
+
16
+ import { Box, BoxProps } from '../Box/Box';
17
+ import { HelpText } from '../HelpText/HelpText';
18
+ import { Icon } from '../Icon/Icon';
19
+ import { getAutoCompleteValue } from '../../lib/getAutoCompleteValue';
20
+ import styles from './TextInputInset.module.scss';
21
+ import { InputValidationMessage } from '../InputValidationMessage/InputValidationMessage';
22
+
23
+ export type TextInputInsetSize = 'md' | 'lg';
24
+ export interface TextInputInsetProps {
25
+ /**
26
+ * The input's id attribute. Used to programmatically tie the input with its label.
27
+ */
28
+ id: string;
29
+ /**
30
+ * Custom content to be displayed above the input. If the label is hidden, will be used to set aria-label attribute.
31
+ */
32
+ label: string;
33
+ /**
34
+ * Callback function to call on change event.
35
+ */
36
+ onChange: (event: ChangeEvent<HTMLInputElement>) => void;
37
+ /**
38
+ * The text value of the input. Required since our Input is a controlled component.
39
+ */
40
+ value: InputHTMLAttributes<HTMLInputElement>['value'];
41
+ /**
42
+ * Automatically focus the input when the page is loaded.
43
+ */
44
+ autoFocus?: boolean;
45
+ /**
46
+ * Custom class to be added to standard input classes.
47
+ */
48
+ className?: string;
49
+ /**
50
+ * Mark the input field as invalid and display a validation message.
51
+ * Pass a string or node to render a validation message below the input.
52
+ */
53
+ error?: ReactNode;
54
+ /**
55
+ * Additional clarifying text to help describe the input
56
+ */
57
+ helpText?: ReactNode;
58
+ /**
59
+ * Props passed directly to the input element of the component
60
+ */
61
+ inputProps?: BoxProps & HTMLProps<HTMLInputElement>;
62
+ /**
63
+ * The input's disabled attribute
64
+ */
65
+ isDisabled?: boolean;
66
+ /**
67
+ * The required and aria-required attributes on the input
68
+ */
69
+ isRequired?: boolean;
70
+ /**
71
+ * The input's 'maxlength' attribute.
72
+ * NOTE: initializing the input with a value longer than the desired maxlength will not trim this value.
73
+ */
74
+ maxLength?: number;
75
+ /**
76
+ * The input's 'name' attribute.
77
+ */
78
+ name?: string;
79
+ /**
80
+ * Callback function to call on blur event.
81
+ */
82
+ onBlur?: (event: FocusEvent<HTMLInputElement>) => void;
83
+ /**
84
+ * Callback function to call when input us cleared. When this is passed,
85
+ * the input will display an icon on the right side, for triggering this callback.
86
+ */
87
+ onClear?: (
88
+ event: MouseEvent<HTMLButtonElement> | KeyboardEvent<HTMLButtonElement>
89
+ ) => void;
90
+ /**
91
+ * Callback function to call on focus event.
92
+ */
93
+ onFocus?: (event: FocusEvent<HTMLInputElement>) => void;
94
+ /**
95
+ * The input placeholder attribute.
96
+ */
97
+ placeholder?: string;
98
+ /**
99
+ * An input helper rendered before the input field value
100
+ */
101
+ prefix?: ReactNode;
102
+ /**
103
+ * Visual indicator that the field is required, that gets appended to the label
104
+ */
105
+ requiredIndicator?: ReactNode;
106
+ /**
107
+ * The size of the text input.
108
+ */
109
+ size?: TextInputInsetSize | ResponsiveProp<TextInputInsetSize>;
110
+ /**
111
+ * An input helper rendered after the input field value
112
+ */
113
+ suffix?: ReactNode;
114
+ /**
115
+ * The input 'type' value. Defaults to type 'text'.
116
+ */
117
+ type?: InputHTMLAttributes<HTMLInputElement>['type'];
118
+ /**
119
+ * Additional props to be spread to rendered element
120
+ */
121
+ [x: string]: any; // eslint-disable-line
122
+ }
123
+
124
+ export const TextInputInset: ForwardRefExoticComponent<TextInputInsetProps> =
125
+ forwardRef<HTMLDivElement, TextInputInsetProps>(
126
+ (
127
+ {
128
+ id,
129
+ label,
130
+ onChange,
131
+ value,
132
+ autoComplete = false,
133
+ autoFocus = false,
134
+ error = false,
135
+ helpText,
136
+ inputProps = {},
137
+ isDisabled = false,
138
+ isRequired = false,
139
+ maxLength = undefined,
140
+ name = '',
141
+ onBlur = undefined,
142
+ onClear = undefined,
143
+ onFocus = undefined,
144
+ prefix = undefined,
145
+ placeholder = ' ',
146
+ requiredIndicator = ' *',
147
+ suffix = undefined,
148
+ size = 'md',
149
+ type = 'text',
150
+ },
151
+ ref
152
+ ) => {
153
+ const responsiveClasses = generateResponsiveClasses('size', size);
154
+
155
+ const inputWrapperClasses = classNames(
156
+ 'hyphen-components__variables__form-control',
157
+ styles['text-input-wrapper'],
158
+ ...responsiveClasses.map((c) => styles[c]),
159
+ {
160
+ [styles.error]: error,
161
+ [styles.disabled]: isDisabled,
162
+ [styles['is-clearable']]: onClear,
163
+ }
164
+ );
165
+
166
+ const clearBtnClasses = classNames(styles['clear-button'], styles.md);
167
+
168
+ const renderClearIcon = (): ReactNode => {
169
+ const handleKeyPress = (
170
+ event: KeyboardEvent<HTMLButtonElement>
171
+ ): void => {
172
+ if (event.keyCode === 13 && onClear) onClear(event);
173
+ };
174
+
175
+ return (
176
+ <button
177
+ type="button"
178
+ onClick={onClear}
179
+ onKeyUp={handleKeyPress}
180
+ className={clearBtnClasses}
181
+ data-testid="text-input-clear-button"
182
+ aria-label="clear input"
183
+ >
184
+ <Icon name="remove" className="display-block" />
185
+ </button>
186
+ );
187
+ };
188
+
189
+ const computedInputProps: TextInputInsetProps['inputProps'] = {
190
+ ...inputProps, // These are spread first so that we don't have top level props overwritten by the user.
191
+ 'aria-required': isRequired,
192
+ 'aria-invalid': !!error,
193
+ 'aria-label': label,
194
+ 'aria-labelledby': label ? `${id}Label` : undefined,
195
+ autoComplete: getAutoCompleteValue(autoComplete),
196
+ autoFocus,
197
+ disabled: isDisabled,
198
+ id,
199
+ maxLength,
200
+ name,
201
+ onBlur,
202
+ onChange,
203
+ onFocus,
204
+ placeholder,
205
+ required: isRequired,
206
+ type,
207
+ value,
208
+ className: classNames(inputProps.className),
209
+ };
210
+
211
+ return (
212
+ <Box width="100" ref={ref}>
213
+ <Box direction="row" className={inputWrapperClasses}>
214
+ {prefix && (
215
+ <Box
216
+ color="base"
217
+ alignItems="center"
218
+ justifyContent="center"
219
+ background="secondary"
220
+ className={classNames(styles.prefix, 'ws-nowrap')}
221
+ >
222
+ {prefix}
223
+ </Box>
224
+ )}
225
+ <Box
226
+ direction="row"
227
+ position="relative"
228
+ className="label-input-wrapper"
229
+ flex="auto"
230
+ >
231
+ <Box as="input" {...computedInputProps} />
232
+ {!!onClear && !!value && renderClearIcon()}
233
+ <label
234
+ htmlFor={id}
235
+ className={styles['text-input-label']}
236
+ id={`${id}Label`}
237
+ >
238
+ {label}
239
+ {isRequired && requiredIndicator && (
240
+ <span>{requiredIndicator}</span>
241
+ )}
242
+ </label>
243
+ </Box>
244
+ {suffix && (
245
+ <Box
246
+ color="base"
247
+ background="secondary"
248
+ className={classNames(styles.suffix, 'ws-nowrap')}
249
+ >
250
+ {suffix}
251
+ </Box>
252
+ )}
253
+ </Box>
254
+ {helpText && <HelpText>{helpText}</HelpText>}
255
+ {error && error !== true && (
256
+ <InputValidationMessage>{error}</InputValidationMessage>
257
+ )}
258
+ </Box>
259
+ );
260
+ }
261
+ );
@@ -0,0 +1,117 @@
1
+ import { Canvas, Meta, ArgTypes } from '@storybook/blocks';
2
+ import { TextareaInput } from './TextareaInput';
3
+ import * as Stories from './TextareaInput.stories';
4
+
5
+ <Meta of={Stories} />
6
+
7
+ # TextareaInput
8
+
9
+ Use TextareaInput to render a multi-line text input.
10
+
11
+ <Canvas isExpanded of={Stories.Basic} />
12
+
13
+ ## Props
14
+
15
+ <ArgTypes of={TextareaInput} />
16
+
17
+ ## Examples
18
+
19
+ All that is required to render a basic version of the TextareaInput is a unique `id`, `label`, `value`, and an onchange event handler passed to the `onChange` prop.
20
+ The input is vertically resizable by default.
21
+
22
+ <Canvas of={Stories.Default} />
23
+
24
+ ## Required
25
+
26
+ Use the `isRequired` prop to set the `required` and `aria-required` on the underlying input element.
27
+
28
+ <Canvas of={Stories.Required} />
29
+
30
+ You can remove or customize the required indicator using the `requiredIndicator` prop.
31
+
32
+ <Canvas of={Stories.CustomRequiredIndicator} />
33
+
34
+ ## Help Text
35
+
36
+ Use the `helpText` prop to add clarifying text beneath the input label.
37
+
38
+ <Canvas of={Stories.HelpText} />
39
+ ## Resize
40
+
41
+ The `resize` prop accepts `horizontal`, `vertical`, `both` or `none` to control the users ability to resize the input.
42
+
43
+ <Canvas of={Stories.Resize} />
44
+
45
+ ## Sizes
46
+
47
+ Set the `size` of the input to `sm`, `md` or `lg`. The `size` prop is also a `ResponsiveProp`, so it can be sized differently at each [breakpoint](?path=/docs/design-tokens-design-tokens--page#breakpoints) by passing an object.
48
+
49
+ <Canvas of={Stories.Sizes} />
50
+
51
+ ## Placeholder
52
+
53
+ Use the `placeholder` prop to add a custom placeholder.
54
+
55
+ <Canvas of={Stories.Placeholder} />
56
+
57
+ ## Autofocus
58
+
59
+ Use the `autoFocus` prop to autofocus the input.
60
+
61
+ <Canvas of={Stories.Autofocus} />
62
+
63
+ ## Hidden Label
64
+
65
+ Use the `hideLabel` prop to not render the label.
66
+
67
+ <Canvas of={Stories.HiddenLabel} />
68
+
69
+ ## Disabled
70
+
71
+ Use the `isDisabled` prop to mark the input as disabled.
72
+
73
+ <Canvas of={Stories.Disabled} />
74
+
75
+ ## Disabled with Value
76
+
77
+ Use the `isDisabled` prop to mark the input as disabled. Disabled inputs can have values that are either preset, or entered by users.
78
+
79
+ <Canvas of={Stories.DisabledWithValue} />
80
+
81
+ ## Disabled with Placeholder
82
+
83
+ Use the `isDisabled` prop to mark the input as disabled. Disabled inputs can have placeholders.
84
+
85
+ <Canvas of={Stories.DisabledWithPlaceholder} />
86
+
87
+ ## Max Length
88
+
89
+ Use the `maxLength` prop to limit the number of characters that can be entered into an input.
90
+
91
+ <Canvas of={Stories.MaxLength} />
92
+
93
+ ## Required with Error
94
+
95
+ Use the `error` prop to mark the input as invalid. `error` accepts a `boolean`, `string`, or `node`. A `boolean` is passed in this example.
96
+
97
+ <Canvas of={Stories.RequiredWithError} />
98
+
99
+ ## Required with Error and Validation Message
100
+
101
+ Pass a `string` or `node` to the `error` prop to render a validation message.
102
+
103
+ <Canvas of={Stories.RequiredWithErrorAndValidationMessage} />
104
+
105
+ ## Not Required with Error and Validation Message
106
+
107
+ An input does not need to be marked as required to render a validation message.
108
+
109
+ <Canvas of={Stories.NotRequiredWithErrorAndValidationMessage} />
110
+
111
+ ## Error with Hidden Label
112
+
113
+ <Canvas of={Stories.ErrorWithHiddenLabel} />
114
+
115
+ ## Component Design Tokens
116
+
117
+ This component shares component design tokens with all form controls. For a complete list of tokens, see the [Theming Form Controls documentation](/docs/theming-form-controls--custom-theme-form).