@telus-uds/components-base 0.0.2-prerelease.6 → 1.0.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 (458) hide show
  1. package/.eslintrc.js +9 -0
  2. package/.ultra.cache.json +1 -1
  3. package/CHANGELOG.md +85 -0
  4. package/README.md +4 -2
  5. package/__fixtures__/Accessible.js +33 -0
  6. package/__fixtures__/Accessible.native.js +32 -0
  7. package/__fixtures__/test-utils.js +25 -0
  8. package/__fixtures__/testTheme.js +851 -57
  9. package/__tests__/ActivityIndicator/ActivityIndicator.test.jsx +1 -1
  10. package/__tests__/Button/ButtonBase.test.jsx +2 -31
  11. package/__tests__/Button/ButtonGroup.test.jsx +6 -7
  12. package/__tests__/Checkbox/Checkbox.test.jsx +94 -0
  13. package/__tests__/Checkbox/CheckboxGroup.test.jsx +246 -0
  14. package/__tests__/ExpandCollapse/ExpandCollapse.test.jsx +2 -2
  15. package/__tests__/HorizontalScroll/HorizontalScroll.test.jsx +164 -0
  16. package/__tests__/Icon/Icon.test.jsx +3 -3
  17. package/__tests__/IconButton/IconButton.test.jsx +52 -0
  18. package/__tests__/InputSupports/InputSupports.test.jsx +50 -0
  19. package/__tests__/Link/LinkBase.test.jsx +0 -14
  20. package/__tests__/List/List.test.jsx +60 -0
  21. package/__tests__/Modal/Modal.test.jsx +47 -0
  22. package/__tests__/Notification/Notification.test.jsx +20 -0
  23. package/__tests__/Pagination/Pagination.test.jsx +2 -2
  24. package/__tests__/Progress/Progress.test.jsx +79 -0
  25. package/__tests__/Radio/Radio.test.jsx +87 -0
  26. package/__tests__/Radio/RadioGroup.test.jsx +220 -0
  27. package/__tests__/RadioCard/RadioCard.test.jsx +87 -0
  28. package/__tests__/RadioCard/RadioCardGroup.test.jsx +246 -0
  29. package/__tests__/Search/Search.test.jsx +73 -0
  30. package/__tests__/Select/Select.test.jsx +94 -0
  31. package/__tests__/Skeleton/Skeleton.test.jsx +61 -0
  32. package/__tests__/StepTracker/StepTracker.test.jsx +94 -0
  33. package/__tests__/Tabs/Tabs.test.jsx +40 -0
  34. package/__tests__/Tags/Tags.test.jsx +327 -0
  35. package/__tests__/TextInput/TextArea.test.jsx +35 -0
  36. package/__tests__/TextInput/{TextInput.test.jsx → TextInputBase.test.jsx} +29 -50
  37. package/__tests__/ThemeProvider/ThemeProvider.test.jsx +77 -0
  38. package/__tests__/ThemeProvider/useThemeTokens.test.jsx +9 -5
  39. package/__tests__/ThemeProvider/utils/theme-tokens.test.js +41 -0
  40. package/__tests__/ToggleSwitch/ToggleSwitch.test.jsx +3 -2
  41. package/__tests__/utils/children.test.jsx +128 -0
  42. package/__tests__/utils/input.test.js +59 -1
  43. package/__tests__/utils/semantics.test.jsx +43 -0
  44. package/__tests__/utils/useCopy.test.js +14 -3
  45. package/babel.config.js +20 -0
  46. package/jest.config.js +8 -3
  47. package/lib/A11yInfoProvider/index.js +54 -26
  48. package/lib/A11yText/index.js +45 -17
  49. package/lib/ActivityIndicator/Spinner.js +81 -0
  50. package/lib/ActivityIndicator/Spinner.native.js +129 -91
  51. package/lib/ActivityIndicator/index.js +28 -12
  52. package/lib/ActivityIndicator/shared.js +27 -12
  53. package/lib/BaseProvider/index.js +34 -11
  54. package/lib/Box/Box.js +152 -35
  55. package/lib/Box/index.js +13 -2
  56. package/lib/Button/Button.js +41 -12
  57. package/lib/Button/ButtonBase.js +125 -97
  58. package/lib/Button/ButtonGroup.js +112 -89
  59. package/lib/Button/ButtonLink.js +48 -17
  60. package/lib/Button/index.js +31 -4
  61. package/lib/Button/propTypes.js +32 -9
  62. package/lib/Card/Card.js +38 -41
  63. package/lib/Card/CardBase.js +85 -0
  64. package/lib/Card/PressableCardBase.js +141 -0
  65. package/lib/Card/index.js +40 -2
  66. package/lib/Checkbox/Checkbox.js +355 -0
  67. package/lib/Checkbox/CheckboxGroup.js +241 -0
  68. package/lib/Checkbox/CheckboxInput.js +74 -0
  69. package/lib/Checkbox/CheckboxInput.native.js +14 -0
  70. package/lib/Checkbox/index.js +21 -0
  71. package/lib/Divider/Divider.js +59 -28
  72. package/lib/Divider/index.js +13 -2
  73. package/lib/ExpandCollapse/Accordion.js +26 -7
  74. package/lib/ExpandCollapse/Control.js +60 -31
  75. package/lib/ExpandCollapse/ExpandCollapse.js +50 -28
  76. package/lib/ExpandCollapse/Panel.js +83 -44
  77. package/lib/ExpandCollapse/index.js +25 -7
  78. package/lib/Feedback/Feedback.js +90 -39
  79. package/lib/Feedback/index.js +13 -2
  80. package/lib/Fieldset/Fieldset.js +165 -0
  81. package/lib/Fieldset/FieldsetContainer.js +46 -0
  82. package/lib/Fieldset/FieldsetContainer.native.js +38 -0
  83. package/lib/Fieldset/Legend.js +38 -0
  84. package/lib/Fieldset/Legend.native.js +48 -0
  85. package/lib/Fieldset/cssReset.js +21 -0
  86. package/lib/Fieldset/index.js +13 -0
  87. package/lib/FlexGrid/Col/Col.js +73 -41
  88. package/lib/FlexGrid/Col/index.js +13 -2
  89. package/lib/FlexGrid/FlexGrid.js +99 -49
  90. package/lib/FlexGrid/Row/Row.js +58 -30
  91. package/lib/FlexGrid/Row/index.js +13 -2
  92. package/lib/FlexGrid/helpers/index.js +9 -1
  93. package/lib/FlexGrid/index.js +13 -2
  94. package/lib/FlexGrid/providers/GutterContext.js +15 -3
  95. package/lib/HorizontalScroll/HorizontalScroll.js +200 -0
  96. package/lib/HorizontalScroll/HorizontalScrollButton.js +127 -0
  97. package/lib/HorizontalScroll/ScrollViewEnd.js +66 -0
  98. package/lib/HorizontalScroll/ScrollViewEnd.native.js +41 -0
  99. package/lib/HorizontalScroll/dictionary.js +18 -0
  100. package/lib/HorizontalScroll/index.js +35 -0
  101. package/lib/HorizontalScroll/itemPositions.js +128 -0
  102. package/lib/Icon/Icon.js +62 -50
  103. package/lib/Icon/IconText.js +101 -0
  104. package/lib/Icon/index.js +31 -3
  105. package/lib/IconButton/IconButton.js +140 -0
  106. package/lib/IconButton/index.js +13 -0
  107. package/lib/InputLabel/InputLabel.js +102 -40
  108. package/lib/InputLabel/LabelContent.js +41 -0
  109. package/lib/InputLabel/LabelContent.native.js +32 -6
  110. package/lib/InputLabel/index.js +13 -2
  111. package/lib/InputSupports/InputSupports.js +109 -0
  112. package/lib/InputSupports/index.js +13 -0
  113. package/lib/InputSupports/propTypes.js +66 -0
  114. package/lib/InputSupports/useInputSupports.js +41 -0
  115. package/lib/Link/ChevronLink.js +58 -31
  116. package/lib/Link/InlinePressable.js +56 -0
  117. package/lib/Link/InlinePressable.native.js +102 -0
  118. package/lib/Link/Link.js +39 -15
  119. package/lib/Link/LinkBase.js +126 -150
  120. package/lib/Link/TextButton.js +53 -18
  121. package/lib/Link/index.js +39 -4
  122. package/lib/List/List.js +81 -0
  123. package/lib/List/ListItem.js +245 -0
  124. package/lib/List/index.js +13 -0
  125. package/lib/Modal/Modal.js +231 -0
  126. package/lib/Modal/dictionary.js +16 -0
  127. package/lib/Modal/index.js +13 -0
  128. package/lib/Notification/Notification.js +216 -0
  129. package/lib/Notification/dictionary.js +15 -0
  130. package/lib/Notification/index.js +13 -0
  131. package/lib/Pagination/PageButton.js +58 -48
  132. package/lib/Pagination/Pagination.js +78 -43
  133. package/lib/Pagination/SideButton.js +79 -58
  134. package/lib/Pagination/dictionary.js +9 -2
  135. package/lib/Pagination/index.js +13 -2
  136. package/lib/Pagination/usePagination.js +12 -2
  137. package/lib/Progress/Progress.js +104 -0
  138. package/lib/Progress/ProgressBar.js +157 -0
  139. package/lib/Progress/ProgressBarBackground.js +61 -0
  140. package/lib/Progress/index.js +16 -0
  141. package/lib/Radio/Radio.js +293 -0
  142. package/lib/Radio/RadioButton.js +152 -0
  143. package/lib/Radio/RadioGroup.js +244 -0
  144. package/lib/Radio/RadioInput.js +76 -0
  145. package/lib/Radio/RadioInput.native.js +14 -0
  146. package/lib/Radio/index.js +21 -0
  147. package/lib/RadioCard/RadioCard.js +244 -0
  148. package/lib/RadioCard/RadioCardGroup.js +252 -0
  149. package/lib/RadioCard/index.js +21 -0
  150. package/lib/Search/Search.js +254 -0
  151. package/lib/Search/dictionary.js +19 -0
  152. package/lib/Search/index.js +13 -0
  153. package/lib/Select/Group.js +33 -0
  154. package/lib/Select/Group.native.js +25 -0
  155. package/lib/Select/Item.js +29 -0
  156. package/lib/Select/Item.native.js +19 -0
  157. package/lib/Select/Picker.js +84 -0
  158. package/lib/Select/Picker.native.js +130 -0
  159. package/lib/Select/Select.js +342 -0
  160. package/lib/Select/index.js +19 -0
  161. package/lib/SideNav/Item.js +63 -37
  162. package/lib/SideNav/ItemContent.js +41 -15
  163. package/lib/SideNav/ItemsGroup.js +55 -31
  164. package/lib/SideNav/SideNav.js +100 -73
  165. package/lib/SideNav/index.js +15 -1
  166. package/lib/Skeleton/Skeleton.js +137 -0
  167. package/lib/Skeleton/index.js +13 -0
  168. package/lib/Skeleton/skeleton.constant.js +12 -0
  169. package/lib/Skeleton/skeletonWebAnimation.js +27 -0
  170. package/lib/Skeleton/useSkeletonNativeAnimation.js +37 -0
  171. package/lib/Spacer/Spacer.js +49 -18
  172. package/lib/Spacer/index.js +13 -2
  173. package/lib/StackView/StackView.js +71 -31
  174. package/lib/StackView/StackWrap.js +43 -13
  175. package/lib/StackView/StackWrap.native.js +13 -2
  176. package/lib/StackView/StackWrapBox.js +76 -29
  177. package/lib/StackView/StackWrapGap.js +56 -26
  178. package/lib/StackView/common.js +23 -6
  179. package/lib/StackView/getStackedContent.js +47 -17
  180. package/lib/StackView/index.js +29 -5
  181. package/lib/StepTracker/Step.js +245 -0
  182. package/lib/StepTracker/StepTracker.js +202 -0
  183. package/lib/StepTracker/dictionary.js +17 -0
  184. package/lib/StepTracker/index.js +13 -0
  185. package/lib/Tabs/Tabs.js +124 -0
  186. package/lib/Tabs/TabsItem.js +238 -0
  187. package/lib/Tabs/index.js +13 -0
  188. package/lib/Tags/Tags.js +266 -0
  189. package/lib/Tags/index.js +13 -0
  190. package/lib/TextInput/TextArea.js +111 -0
  191. package/lib/TextInput/TextInput.js +50 -304
  192. package/lib/TextInput/TextInputBase.js +256 -0
  193. package/lib/TextInput/index.js +23 -2
  194. package/lib/TextInput/propTypes.js +42 -0
  195. package/lib/ThemeProvider/ThemeProvider.js +46 -18
  196. package/lib/ThemeProvider/index.js +61 -6
  197. package/lib/ThemeProvider/useSetTheme.js +19 -5
  198. package/lib/ThemeProvider/useTheme.js +13 -4
  199. package/lib/ThemeProvider/useThemeTokens.js +86 -19
  200. package/lib/ThemeProvider/utils/index.js +31 -2
  201. package/lib/ThemeProvider/utils/styles.js +50 -14
  202. package/lib/ThemeProvider/utils/theme-tokens.js +121 -12
  203. package/lib/ToggleSwitch/ToggleSwitch.js +86 -57
  204. package/lib/ToggleSwitch/index.js +13 -2
  205. package/lib/Tooltip/{Backdrop.web.js → Backdrop.js} +20 -8
  206. package/lib/Tooltip/Backdrop.native.js +39 -15
  207. package/lib/Tooltip/Tooltip.js +117 -74
  208. package/lib/Tooltip/dictionary.js +9 -2
  209. package/lib/Tooltip/getTooltipPosition.js +9 -1
  210. package/lib/Tooltip/index.js +13 -2
  211. package/lib/TooltipButton/TooltipButton.js +57 -38
  212. package/lib/TooltipButton/index.js +13 -2
  213. package/lib/Typography/Typography.js +86 -55
  214. package/lib/Typography/index.js +13 -2
  215. package/lib/ViewportProvider/ViewportProvider.js +34 -13
  216. package/lib/ViewportProvider/index.js +28 -3
  217. package/lib/ViewportProvider/useViewport.js +15 -3
  218. package/lib/ViewportProvider/useViewportListener.js +24 -10
  219. package/lib/index.js +539 -26
  220. package/lib/utils/a11y/index.js +31 -0
  221. package/lib/utils/a11y/semantics.js +173 -0
  222. package/lib/utils/a11y/textSize.js +49 -0
  223. package/lib/utils/animation/index.js +15 -2
  224. package/lib/utils/animation/useVerticalExpandAnimation.js +27 -10
  225. package/lib/utils/children.js +134 -0
  226. package/lib/utils/index.js +163 -7
  227. package/lib/utils/info/index.js +19 -0
  228. package/lib/utils/info/platform/index.js +23 -0
  229. package/lib/utils/info/platform/platform.android.js +8 -0
  230. package/lib/utils/info/platform/platform.ios.js +8 -0
  231. package/lib/utils/info/platform/platform.js +8 -0
  232. package/lib/utils/info/platform/platform.native.js +11 -0
  233. package/lib/utils/info/versions.js +16 -0
  234. package/lib/utils/input.js +53 -25
  235. package/lib/utils/pressability.js +120 -0
  236. package/lib/utils/propTypes.js +338 -132
  237. package/lib/utils/useCopy.js +40 -5
  238. package/lib/utils/useHash.js +52 -0
  239. package/lib/utils/useHash.native.js +15 -0
  240. package/lib/utils/useResponsiveProp.js +21 -9
  241. package/lib/utils/useSpacingScale.js +19 -9
  242. package/lib/utils/useUniqueId.js +12 -3
  243. package/package.json +16 -10
  244. package/release-context.json +4 -4
  245. package/src/A11yText/index.jsx +6 -4
  246. package/src/ActivityIndicator/{Spinner.web.jsx → Spinner.jsx} +5 -3
  247. package/src/ActivityIndicator/Spinner.native.jsx +5 -3
  248. package/src/Box/Box.jsx +131 -39
  249. package/src/Button/Button.jsx +13 -6
  250. package/src/Button/ButtonBase.jsx +134 -125
  251. package/src/Button/ButtonGroup.jsx +85 -86
  252. package/src/Button/ButtonLink.jsx +22 -7
  253. package/src/Button/propTypes.js +12 -2
  254. package/src/Card/Card.jsx +5 -31
  255. package/src/Card/CardBase.jsx +58 -0
  256. package/src/Card/PressableCardBase.jsx +119 -0
  257. package/src/Card/index.js +3 -0
  258. package/src/Checkbox/Checkbox.jsx +284 -0
  259. package/src/Checkbox/CheckboxGroup.jsx +206 -0
  260. package/src/Checkbox/CheckboxInput.jsx +55 -0
  261. package/src/Checkbox/CheckboxInput.native.jsx +6 -0
  262. package/src/Checkbox/index.js +5 -0
  263. package/src/Divider/Divider.jsx +7 -4
  264. package/src/ExpandCollapse/Accordion.jsx +3 -2
  265. package/src/ExpandCollapse/Control.jsx +40 -43
  266. package/src/ExpandCollapse/ExpandCollapse.jsx +26 -23
  267. package/src/ExpandCollapse/Panel.jsx +69 -63
  268. package/src/Feedback/Feedback.jsx +42 -30
  269. package/src/Fieldset/Fieldset.jsx +136 -0
  270. package/src/Fieldset/FieldsetContainer.jsx +31 -0
  271. package/src/Fieldset/FieldsetContainer.native.jsx +19 -0
  272. package/src/Fieldset/Legend.jsx +21 -0
  273. package/src/Fieldset/Legend.native.jsx +27 -0
  274. package/src/Fieldset/cssReset.js +14 -0
  275. package/src/Fieldset/index.js +3 -0
  276. package/src/FlexGrid/Col/Col.jsx +139 -132
  277. package/src/FlexGrid/FlexGrid.jsx +79 -51
  278. package/src/FlexGrid/Row/Row.jsx +55 -48
  279. package/src/HorizontalScroll/HorizontalScroll.jsx +168 -0
  280. package/src/HorizontalScroll/HorizontalScrollButton.jsx +105 -0
  281. package/src/HorizontalScroll/ScrollViewEnd.jsx +53 -0
  282. package/src/HorizontalScroll/ScrollViewEnd.native.jsx +24 -0
  283. package/src/HorizontalScroll/dictionary.js +11 -0
  284. package/src/HorizontalScroll/index.js +17 -0
  285. package/src/HorizontalScroll/itemPositions.js +101 -0
  286. package/src/Icon/Icon.jsx +46 -49
  287. package/src/Icon/IconText.jsx +68 -0
  288. package/src/Icon/index.js +3 -2
  289. package/src/IconButton/IconButton.jsx +114 -0
  290. package/src/IconButton/index.js +3 -0
  291. package/src/InputLabel/InputLabel.jsx +57 -35
  292. package/src/InputLabel/LabelContent.jsx +21 -0
  293. package/src/InputLabel/LabelContent.native.jsx +11 -2
  294. package/src/InputSupports/InputSupports.jsx +70 -0
  295. package/src/InputSupports/index.js +3 -0
  296. package/src/InputSupports/propTypes.js +44 -0
  297. package/src/InputSupports/useInputSupports.js +30 -0
  298. package/src/Link/ChevronLink.jsx +34 -21
  299. package/src/Link/InlinePressable.jsx +39 -0
  300. package/src/Link/InlinePressable.native.jsx +75 -0
  301. package/src/Link/Link.jsx +23 -13
  302. package/src/Link/LinkBase.jsx +98 -170
  303. package/src/Link/TextButton.jsx +37 -16
  304. package/src/Link/index.js +2 -1
  305. package/src/List/List.jsx +48 -0
  306. package/src/List/ListItem.jsx +182 -0
  307. package/src/List/index.js +3 -0
  308. package/src/Modal/Modal.jsx +190 -0
  309. package/src/Modal/dictionary.js +9 -0
  310. package/src/Modal/index.js +3 -0
  311. package/src/Notification/Notification.jsx +164 -0
  312. package/src/Notification/dictionary.js +8 -0
  313. package/src/Notification/index.js +3 -0
  314. package/src/Pagination/PageButton.jsx +42 -49
  315. package/src/Pagination/Pagination.jsx +88 -92
  316. package/src/Pagination/SideButton.jsx +58 -66
  317. package/src/Progress/Progress.jsx +78 -0
  318. package/src/Progress/ProgressBar.jsx +123 -0
  319. package/src/Progress/ProgressBarBackground.jsx +36 -0
  320. package/src/Progress/index.js +6 -0
  321. package/src/Radio/Radio.jsx +240 -0
  322. package/src/Radio/RadioButton.jsx +142 -0
  323. package/src/Radio/RadioGroup.jsx +209 -0
  324. package/src/Radio/RadioInput.jsx +57 -0
  325. package/src/Radio/RadioInput.native.jsx +6 -0
  326. package/src/Radio/index.js +5 -0
  327. package/src/RadioCard/RadioCard.jsx +198 -0
  328. package/src/RadioCard/RadioCardGroup.jsx +218 -0
  329. package/src/RadioCard/index.js +5 -0
  330. package/src/Search/Search.jsx +225 -0
  331. package/src/Search/dictionary.js +12 -0
  332. package/src/Search/index.js +3 -0
  333. package/src/Select/Group.jsx +15 -0
  334. package/src/Select/Group.native.jsx +14 -0
  335. package/src/Select/Item.jsx +11 -0
  336. package/src/Select/Item.native.jsx +10 -0
  337. package/src/Select/Picker.jsx +74 -0
  338. package/src/Select/Picker.native.jsx +102 -0
  339. package/src/Select/Select.jsx +298 -0
  340. package/src/Select/index.js +8 -0
  341. package/src/SideNav/Item.jsx +54 -47
  342. package/src/SideNav/ItemsGroup.jsx +50 -43
  343. package/src/SideNav/SideNav.jsx +68 -60
  344. package/src/Skeleton/Skeleton.jsx +94 -0
  345. package/src/Skeleton/index.js +3 -0
  346. package/src/Skeleton/skeleton.constant.js +3 -0
  347. package/src/Skeleton/skeletonWebAnimation.js +13 -0
  348. package/src/Skeleton/useSkeletonNativeAnimation.js +27 -0
  349. package/src/Spacer/Spacer.jsx +11 -4
  350. package/src/StackView/StackView.jsx +53 -23
  351. package/src/StackView/StackWrap.jsx +16 -7
  352. package/src/StackView/StackWrapBox.jsx +62 -28
  353. package/src/StackView/StackWrapGap.jsx +46 -24
  354. package/src/StackView/common.jsx +3 -2
  355. package/src/StackView/getStackedContent.jsx +8 -2
  356. package/src/StepTracker/Step.jsx +202 -0
  357. package/src/StepTracker/StepTracker.jsx +174 -0
  358. package/src/StepTracker/dictionary.js +10 -0
  359. package/src/StepTracker/index.js +3 -0
  360. package/src/Tabs/Tabs.jsx +97 -0
  361. package/src/Tabs/TabsItem.jsx +212 -0
  362. package/src/Tabs/index.js +3 -0
  363. package/src/Tags/Tags.jsx +219 -0
  364. package/src/Tags/index.js +3 -0
  365. package/src/TextInput/TextArea.jsx +79 -0
  366. package/src/TextInput/TextInput.jsx +18 -284
  367. package/src/TextInput/TextInputBase.jsx +217 -0
  368. package/src/TextInput/index.js +2 -1
  369. package/src/TextInput/propTypes.js +29 -0
  370. package/src/ThemeProvider/ThemeProvider.jsx +11 -7
  371. package/src/ThemeProvider/useSetTheme.js +4 -0
  372. package/src/ThemeProvider/useThemeTokens.js +56 -5
  373. package/src/ThemeProvider/utils/styles.js +18 -5
  374. package/src/ThemeProvider/utils/theme-tokens.js +74 -5
  375. package/src/ToggleSwitch/ToggleSwitch.jsx +51 -53
  376. package/src/Tooltip/{Backdrop.web.jsx → Backdrop.jsx} +0 -0
  377. package/src/Tooltip/Tooltip.jsx +135 -131
  378. package/src/TooltipButton/TooltipButton.jsx +23 -27
  379. package/src/Typography/Typography.jsx +72 -59
  380. package/src/index.js +31 -3
  381. package/src/utils/a11y/index.js +2 -0
  382. package/src/utils/a11y/semantics.js +162 -0
  383. package/src/utils/a11y/textSize.js +30 -0
  384. package/src/utils/children.jsx +119 -0
  385. package/src/utils/index.js +6 -0
  386. package/src/utils/info/index.js +8 -0
  387. package/src/utils/info/platform/index.js +11 -0
  388. package/src/utils/info/platform/platform.android.js +1 -0
  389. package/src/utils/info/platform/platform.ios.js +1 -0
  390. package/src/utils/info/platform/platform.js +1 -0
  391. package/src/utils/info/platform/platform.native.js +4 -0
  392. package/src/utils/info/versions.js +6 -0
  393. package/src/utils/input.js +36 -25
  394. package/src/utils/pressability.js +96 -0
  395. package/src/utils/propTypes.js +291 -90
  396. package/src/utils/useCopy.js +30 -4
  397. package/src/utils/useHash.js +39 -0
  398. package/src/utils/useHash.native.js +6 -0
  399. package/stories/A11yText/A11yText.stories.jsx +6 -10
  400. package/stories/ActivityIndicator/ActivityIndicator.stories.jsx +1 -1
  401. package/stories/Box/Box.stories.jsx +1 -1
  402. package/stories/Button/Button.stories.jsx +7 -2
  403. package/stories/Button/ButtonGroup.stories.jsx +1 -1
  404. package/stories/Button/ButtonLink.stories.jsx +1 -1
  405. package/stories/Card/Card.stories.jsx +1 -1
  406. package/stories/Checkbox/Checkbox.stories.jsx +94 -0
  407. package/stories/Divider/Divider.stories.jsx +1 -1
  408. package/stories/ExpandCollapse/ExpandCollapse.stories.jsx +2 -2
  409. package/stories/Feedback/Feedback.stories.jsx +5 -6
  410. package/stories/FlexGrid/01 FlexGrid.stories.jsx +1 -1
  411. package/stories/FlexGrid/02 Row.stories.jsx +1 -1
  412. package/stories/FlexGrid/03 Col.stories.jsx +1 -1
  413. package/stories/Icon/Icon.stories.jsx +27 -7
  414. package/stories/IconButton/IconButton.stories.jsx +50 -0
  415. package/stories/InputLabel/InputLabel.stories.jsx +1 -1
  416. package/stories/Link/ChevronLink.stories.jsx +1 -1
  417. package/stories/Link/Link.stories.jsx +28 -18
  418. package/stories/Link/TextButton.stories.jsx +1 -1
  419. package/stories/List/List.stories.jsx +117 -0
  420. package/stories/Modal/Modal.stories.jsx +29 -0
  421. package/stories/Notification/Notification.stories.jsx +82 -0
  422. package/stories/Pagination/Pagination.stories.jsx +1 -1
  423. package/stories/Progress/Progress.stories.jsx +93 -0
  424. package/stories/Radio/Radio.stories.jsx +100 -0
  425. package/stories/RadioCard/RadioCard.stories.jsx +98 -0
  426. package/stories/Search/Search.stories.jsx +16 -0
  427. package/stories/Select/Select.stories.jsx +55 -0
  428. package/stories/SideNav/SideNav.stories.jsx +1 -1
  429. package/stories/SideNav/SideNavItem.stories.jsx +1 -1
  430. package/stories/SideNav/SideNavItemsGroup.stories.jsx +1 -1
  431. package/stories/Skeleton/Skeleton.stories.jsx +36 -0
  432. package/stories/Spacer/Spacer.stories.jsx +1 -1
  433. package/stories/StackView/StackView.stories.jsx +1 -1
  434. package/stories/StackView/StackWrap.stories.jsx +1 -1
  435. package/stories/StepTracker/StepTracker.stories.jsx +71 -0
  436. package/stories/Tabs/Tabs.stories.jsx +97 -0
  437. package/stories/Tags/Tags.stories.jsx +69 -0
  438. package/stories/TextInput/TextArea.stories.jsx +100 -0
  439. package/stories/TextInput/TextInput.stories.jsx +1 -1
  440. package/stories/ToggleSwitch/ToggleSwitch.stories.jsx +1 -1
  441. package/stories/Tooltip/Tooltip.stories.jsx +1 -1
  442. package/stories/TooltipButton/TooltipButton.stories.jsx +1 -1
  443. package/stories/Typography/Typography.stories.jsx +1 -1
  444. package/stories/{platform-supports.web.jsx → platform-supports.jsx} +1 -1
  445. package/stories/supports.jsx +38 -4
  446. package/__fixtures__/accessible.icon.svg +0 -6
  447. package/babel.config.json +0 -8
  448. package/docs/Contributing.stories.mdx +0 -9
  449. package/docs/Fonts.stories.mdx +0 -104
  450. package/docs/Icons.stories.mdx +0 -144
  451. package/docs/Introduction.stories.mdx +0 -9
  452. package/lib/ActivityIndicator/Spinner.web.js +0 -55
  453. package/lib/InputLabel/LabelContent.web.js +0 -17
  454. package/lib/config/svgr-icons-web.js +0 -9
  455. package/lib/config/svgr-icons.js +0 -52
  456. package/src/InputLabel/LabelContent.web.jsx +0 -13
  457. package/src/config/svgr-icons-web.js +0 -11
  458. package/src/config/svgr-icons.js +0 -46
@@ -0,0 +1,52 @@
1
+ import React from 'react'
2
+ import { fireEvent, render } from '@testing-library/react-native'
3
+
4
+ import { IconButton } from '../../src'
5
+ import Theme from '../../__fixtures__/Theme'
6
+
7
+ describe('IconButton', () => {
8
+ it('renders a link if href is passed', () => {
9
+ const { queryByRole } = render(<IconButton href="https://telus.com" icon={() => null} />, {
10
+ wrapper: Theme
11
+ })
12
+
13
+ expect(queryByRole('link')).toBeTruthy()
14
+
15
+ expect(queryByRole('button')).toBeFalsy()
16
+ })
17
+
18
+ it('renders a button if onPress is passed', () => {
19
+ const { queryByRole } = render(<IconButton onPress={() => {}} icon={() => null} />, {
20
+ wrapper: Theme
21
+ })
22
+
23
+ expect(queryByRole('button')).toBeTruthy()
24
+
25
+ expect(queryByRole('link')).toBeFalsy()
26
+ })
27
+
28
+ it('renders an accessible label', () => {
29
+ const { getByA11yLabel } = render(
30
+ <IconButton onPress={() => {}} icon={() => null} accessibilityLabel="test label" />,
31
+ {
32
+ wrapper: Theme
33
+ }
34
+ )
35
+
36
+ expect(getByA11yLabel('test label')).toBeTruthy()
37
+ })
38
+
39
+ it('calls onPress function when pressed', async () => {
40
+ const handlePress = jest.fn()
41
+ const { getByA11yLabel } = render(
42
+ <IconButton onPress={handlePress} icon={() => null} accessibilityLabel="test label" />,
43
+ {
44
+ wrapper: Theme
45
+ }
46
+ )
47
+ const iconButton = getByA11yLabel('test label')
48
+ expect(handlePress).toHaveBeenCalledTimes(0)
49
+ await fireEvent.press(iconButton)
50
+ expect(handlePress).toHaveBeenCalledTimes(1)
51
+ })
52
+ })
@@ -0,0 +1,50 @@
1
+ import React from 'react'
2
+ import { fireEvent, render } from '@testing-library/react-native'
3
+
4
+ import InputSupports from '../../src/InputSupports'
5
+ import Theme from '../../__fixtures__/Theme'
6
+ import Viewport from '../../__fixtures__/Viewport'
7
+
8
+ // eslint-disable-next-line react/prop-types
9
+ const Wrapper = ({ children }) => (
10
+ <Viewport viewport="xs">
11
+ <Theme>{children}</Theme>
12
+ </Viewport>
13
+ )
14
+
15
+ describe('InputSupports', () => {
16
+ it('renders the label', () => {
17
+ const { queryByText } = render(<InputSupports label="Test label content" />, {
18
+ wrapper: Wrapper
19
+ })
20
+
21
+ expect(queryByText('Test label content')).toBeTruthy()
22
+ })
23
+
24
+ it('renders the hint', () => {
25
+ const { queryByText } = render(
26
+ <InputSupports label="Test label content" hint="Test hint content" />,
27
+ { wrapper: Wrapper }
28
+ )
29
+
30
+ expect(queryByText('Test hint content')).toBeTruthy()
31
+ })
32
+
33
+ it('renders the feedback', () => {
34
+ const { queryByText } = render(<InputSupports feedback="Test feedback content" />, {
35
+ wrapper: Wrapper
36
+ })
37
+
38
+ expect(queryByText('Test feedback content')).toBeTruthy()
39
+ })
40
+
41
+ it('renders the tooltip which content shows up when pressed', () => {
42
+ const { queryByText, getByRole } = render(
43
+ <InputSupports label="Test label content" tooltip="Test tooltip content" />,
44
+ { wrapper: Wrapper }
45
+ )
46
+
47
+ fireEvent(getByRole('button'), 'press')
48
+ expect(queryByText('Test tooltip content')).toBeTruthy()
49
+ })
50
+ })
@@ -8,20 +8,6 @@ import LinkBase from '../../src/Link/LinkBase'
8
8
  beforeEach(() => jest.clearAllMocks())
9
9
 
10
10
  describe('LinkBase', () => {
11
- it('throws if both href and onPress are provided', async () => {
12
- jest.spyOn(console, 'error').mockImplementation()
13
- expect(() =>
14
- render(
15
- <Theme>
16
- <LinkBase href="example.com" onPress={jest.fn()}>
17
- click me
18
- </LinkBase>
19
- </Theme>
20
- )
21
- ).toThrow()
22
- expect(console.error).toHaveBeenCalledTimes(1)
23
- })
24
-
25
11
  it('throws if neither href nor onPress are provided', async () => {
26
12
  jest.spyOn(console, 'error').mockImplementation()
27
13
  expect(() =>
@@ -0,0 +1,60 @@
1
+ import React from 'react'
2
+ import { Text } from 'react-native'
3
+ import { render } from '@testing-library/react-native'
4
+ import { List } from '../../src'
5
+ import Theme from '../../__fixtures__/Theme'
6
+ import testTheme from '../../__fixtures__/testTheme'
7
+
8
+ const setup = ({ showDivider = false, icon, children } = {}) =>
9
+ render(
10
+ <Theme>
11
+ <List showDivider={showDivider}>
12
+ <List.Item icon={icon}>{children || 'Item'}</List.Item>
13
+ <List.Item icon={icon}>{children || 'Item'}</List.Item>
14
+ <List.Item icon={icon}>{children || 'Item'}</List.Item>
15
+ <List.Item icon={icon}>{children || 'Item'}</List.Item>
16
+ </List>
17
+ </Theme>
18
+ )
19
+
20
+ describe('List', () => {
21
+ it('should render bullets by default', () => {
22
+ const { queryAllByTestId } = setup()
23
+ const bullet = queryAllByTestId('unordered-item-bullet')
24
+ expect(bullet.length).toBe(4)
25
+ })
26
+
27
+ it('should render dividers for all items except for the last one', () => {
28
+ const { getAllByRole } = setup({ showDivider: true })
29
+ const {
30
+ interItemMarginWithDivider: marginBottom,
31
+ dividerColor: borderColor,
32
+ dividerSize: borderBottomWidth
33
+ } = testTheme.components.List.tokens
34
+
35
+ const listItems = getAllByRole('item')
36
+
37
+ listItems.forEach((item, index) => {
38
+ if (index + 1 !== listItems.length) {
39
+ expect(item).toHaveStyle({ marginBottom, borderColor, borderBottomWidth })
40
+ } else {
41
+ expect(item).toHaveStyle({})
42
+ }
43
+ })
44
+ })
45
+
46
+ it('should render the icon when defined', () => {
47
+ const { queryAllByTestId } = setup({ icon: () => <Text testID="icon" /> })
48
+
49
+ const icons = queryAllByTestId('icon')
50
+
51
+ expect(icons.length).toBe(4)
52
+ })
53
+ it('should allow children nested components', () => {
54
+ const { queryAllByTestId } = setup({ children: <Text testID="child" /> })
55
+
56
+ const children = queryAllByTestId('child')
57
+
58
+ expect(children.length).toBe(4)
59
+ })
60
+ })
@@ -0,0 +1,47 @@
1
+ import React from 'react'
2
+ import { Text } from 'react-native'
3
+ import { fireEvent, render } from '@testing-library/react-native'
4
+
5
+ import { Modal } from '../../src'
6
+ import Theme from '../../__fixtures__/Theme'
7
+
8
+ describe('Modal', () => {
9
+ it('is not rendered when closed', () => {
10
+ const { queryByText } = render(
11
+ <Modal>
12
+ <Text>Test content</Text>
13
+ </Modal>,
14
+ { wrapper: Theme }
15
+ )
16
+
17
+ expect(queryByText('Test content')).toBeFalsy()
18
+ })
19
+
20
+ it('is rendered when open', () => {
21
+ const { queryByText } = render(
22
+ <Modal isOpen>
23
+ <Text>Test content</Text>
24
+ </Modal>,
25
+ { wrapper: Theme }
26
+ )
27
+
28
+ expect(queryByText('Test content')).not.toBeFalsy()
29
+ })
30
+
31
+ it('onClose callback is triggered when closing', () => {
32
+ const onClose = jest.fn()
33
+
34
+ const { getByA11yRole } = render(
35
+ <Modal isOpen onClose={onClose}>
36
+ <Text>Test content</Text>
37
+ </Modal>,
38
+ { wrapper: Theme }
39
+ )
40
+
41
+ expect(onClose).not.toHaveBeenCalled()
42
+
43
+ fireEvent.press(getByA11yRole('button'))
44
+
45
+ expect(onClose).toHaveBeenCalledTimes(1)
46
+ })
47
+ })
@@ -0,0 +1,20 @@
1
+ import React from 'react'
2
+ import { fireEvent, render } from '@testing-library/react-native'
3
+
4
+ import { Notification } from '../../src'
5
+ import Theme from '../../__fixtures__/Theme'
6
+
7
+ describe('Notification', () => {
8
+ it('is removed when dismiss button is pressed', () => {
9
+ const content = 'Notification content lands here'
10
+ const { getByRole, getByText } = render(<Notification dismissible>{content}</Notification>, {
11
+ wrapper: Theme
12
+ })
13
+
14
+ expect(() => getByText(content)).not.toThrow()
15
+
16
+ fireEvent.press(getByRole('button'))
17
+
18
+ expect(() => getByText(content)).toThrow()
19
+ })
20
+ })
@@ -114,7 +114,7 @@ describe('Pagination', () => {
114
114
 
115
115
  expect(button).toHaveProp('accessibilityRole', 'link')
116
116
  expect(button).toHaveProp('href', 'test-url')
117
- expect(button).toHaveProp('target', '_blank')
117
+ expect(button).toHaveProp('hrefAttrs', { target: '_blank' })
118
118
  })
119
119
  })
120
120
 
@@ -154,7 +154,7 @@ describe('Pagination', () => {
154
154
 
155
155
  expect(button).toHaveProp('accessibilityRole', 'link')
156
156
  expect(button).toHaveProp('href', 'test-url')
157
- expect(button).toHaveProp('target', '_blank')
157
+ expect(button).toHaveProp('hrefAttrs', { target: '_blank' })
158
158
  })
159
159
  })
160
160
  })
@@ -0,0 +1,79 @@
1
+ import React from 'react'
2
+ import { Text } from 'react-native'
3
+ import { render, within } from '@testing-library/react-native'
4
+
5
+ import { Progress } from '../../src'
6
+ import Theme from '../../__fixtures__/Theme'
7
+
8
+ const barTokens = {
9
+ backgroundColor: 'green'
10
+ }
11
+ const percentage = 75
12
+ const progressTokens = {
13
+ backgroundColor: 'white',
14
+ borderColor: 'black'
15
+ }
16
+ const a11yLabel = 'Progress bar'
17
+ const progressA11yLabel = 'This is a progress indicator'
18
+ const setup = (
19
+ { children, ...props } = {
20
+ children: (
21
+ <Progress.Bar percentage={percentage} tokens={barTokens} accessibilityLabel={a11yLabel} />
22
+ )
23
+ }
24
+ ) =>
25
+ render(
26
+ <Progress tokens={progressTokens} accessibilityLabel={progressA11yLabel} {...props}>
27
+ {children}
28
+ </Progress>,
29
+ { wrapper: Theme }
30
+ )
31
+
32
+ describe('Progress', () => {
33
+ it('renders with correct percentage and applies tokens accordingly', () => {
34
+ const { getByA11yLabel } = setup()
35
+ expect(getByA11yLabel(progressA11yLabel)).toHaveStyle(progressTokens)
36
+ expect(getByA11yLabel(a11yLabel)).toHaveStyle({
37
+ width: `${percentage}%`,
38
+ ...barTokens
39
+ })
40
+ })
41
+
42
+ it('renders arbitrary content inside the progress bar', () => {
43
+ const contentText = 'This can be an arbitrary content'
44
+ const { getByA11yLabel } = setup({
45
+ children: (
46
+ <Progress.Bar percentage={percentage} tokens={barTokens} accessibilityLabel={a11yLabel}>
47
+ <Text>{contentText}</Text>
48
+ </Progress.Bar>
49
+ )
50
+ })
51
+ expect(within(getByA11yLabel(a11yLabel)).getByText(contentText)).toBeTruthy()
52
+ })
53
+
54
+ it('renders proper accessibility attributes on the progress bar', () => {
55
+ const { getByA11yRole, getByA11yValue } = setup()
56
+ expect(getByA11yRole('progressbar')).toBeTruthy()
57
+ expect(
58
+ getByA11yValue({ min: 0, max: 100, now: percentage, text: `${percentage}%` })
59
+ ).toBeTruthy()
60
+ })
61
+
62
+ it('renders stacked progress bars', () => {
63
+ const inactiveA11yLabel = 'This bar is inactive'
64
+ const { getByA11yLabel } = setup({
65
+ children: (
66
+ <>
67
+ <Progress.Bar
68
+ percentage={percentage + 10}
69
+ variant={{ inactive: true }}
70
+ accessibilityLabel={inactiveA11yLabel}
71
+ />
72
+ <Progress.Bar percentage={percentage} accessibilityLabel={a11yLabel} />
73
+ </>
74
+ )
75
+ })
76
+ expect(within(getByA11yLabel(progressA11yLabel)).getByA11yLabel(inactiveA11yLabel)).toBeTruthy()
77
+ expect(within(getByA11yLabel(progressA11yLabel)).getByA11yLabel(a11yLabel)).toBeTruthy()
78
+ })
79
+ })
@@ -0,0 +1,87 @@
1
+ import React from 'react'
2
+ import { fireEvent, render } from '@testing-library/react-native'
3
+
4
+ import { Radio } from '../../src'
5
+ import Theme from '../../__fixtures__/Theme'
6
+
7
+ const checkedId = 'Radio-Checked'
8
+ const inputId = 'Radio-Input'
9
+ const setup = (props) =>
10
+ render(
11
+ <Theme>
12
+ <Radio {...props} />
13
+ </Theme>
14
+ )
15
+
16
+ describe('Radio', () => {
17
+ it('renders with defaults', () => {
18
+ const { getByRole } = setup()
19
+
20
+ expect(getByRole('radio')).toBeTruthy()
21
+ })
22
+
23
+ it('renders the label', () => {
24
+ const label = 'Test label message'
25
+ const { queryByText } = setup({ label })
26
+
27
+ expect(queryByText(label)).toBeTruthy()
28
+ })
29
+
30
+ it('renders error styling on validation failure', () => {
31
+ const errorBorderColor = '#e12339' // from __fixtures__/testTheme.js
32
+ const { getByTestId } = setup({ error: true })
33
+
34
+ const radioInput = getByTestId(inputId)
35
+ expect(radioInput).toHaveStyle({ borderColor: errorBorderColor })
36
+ })
37
+
38
+ it('triggers the callback', () => {
39
+ const onChange = jest.fn()
40
+
41
+ const { getByRole } = setup({ onChange })
42
+
43
+ const radio = getByRole('radio')
44
+ expect(onChange).not.toHaveBeenCalled()
45
+ fireEvent(radio, 'press')
46
+ expect(onChange).toHaveBeenCalledTimes(1)
47
+ })
48
+
49
+ it('cannot be changed if inactive', () => {
50
+ const { getByRole, queryByTestId } = setup({ inactive: true })
51
+
52
+ const radio = getByRole('radio')
53
+ expect(queryByTestId(checkedId)).toBeFalsy()
54
+ fireEvent(radio, 'press')
55
+ expect(queryByTestId(checkedId)).toBeFalsy()
56
+ })
57
+
58
+ describe('when uncontrolled', () => {
59
+ it('uses `defaultChecked` as the initial value', () => {
60
+ const { queryByTestId } = setup({ defaultChecked: true })
61
+
62
+ expect(queryByTestId(checkedId)).toBeTruthy()
63
+ })
64
+
65
+ it('changes value', () => {
66
+ const { getByRole, queryByTestId } = setup({ defaultChecked: false })
67
+
68
+ const radio = getByRole('radio')
69
+ expect(queryByTestId(checkedId)).toBeFalsy()
70
+ fireEvent(radio, 'press')
71
+ expect(queryByTestId(checkedId)).toBeTruthy()
72
+ })
73
+ })
74
+
75
+ describe('when controlled', () => {
76
+ it('calls `onChange` with the new value', () => {
77
+ const onChange = jest.fn()
78
+ const { getByRole, queryByTestId } = setup({ onChange, checked: false })
79
+
80
+ const radio = getByRole('radio')
81
+ expect(queryByTestId(checkedId)).toBeFalsy()
82
+ fireEvent(radio, 'press', { nativeEvent: 'example' })
83
+ expect(onChange).toHaveBeenCalledTimes(1)
84
+ expect(onChange).toHaveBeenCalledWith(true, { nativeEvent: 'example' })
85
+ })
86
+ })
87
+ })
@@ -0,0 +1,220 @@
1
+ import React from 'react'
2
+ import { render, fireEvent } from '@testing-library/react-native'
3
+ import { toHaveTextContent } from '@testing-library/jest-native'
4
+
5
+ import Theme from '../../__fixtures__/Theme'
6
+ import RadioGroup from '../../src/Radio/RadioGroup'
7
+
8
+ const items = [
9
+ { label: 'One', id: 'one' },
10
+ { label: 'Two', id: 'two' },
11
+ { label: 'Three', id: 'three' },
12
+ { label: 'Four', id: 'four' }
13
+ ]
14
+ const checked = { checked: true }
15
+
16
+ // expect().toHaveTextContent doesn't work on arrays, expect().toContain etc doesn't match elements
17
+ const containsText = (queryResult, text) =>
18
+ queryResult.some((testInstance) => toHaveTextContent(testInstance, text).pass)
19
+
20
+ describe('RadioGroup', () => {
21
+ // eslint-disable-next-line no-console
22
+ const consoleError = console.error
23
+ beforeEach(() => {
24
+ // eslint-disable-next-line no-console
25
+ console.error = () => {}
26
+ })
27
+ afterEach(() => {
28
+ // eslint-disable-next-line no-console
29
+ console.error = consoleError
30
+ })
31
+
32
+ it('Throws if has `checkedId` without `onChange`', () => {
33
+ expect(() =>
34
+ render(
35
+ <Theme>
36
+ <RadioGroup items={items} checkedId="one" />
37
+ </Theme>
38
+ )
39
+ ).toThrow(/value.+without.+onChange/)
40
+ })
41
+ it("Doesn't throw if has `checkedId` without `onChange` and is read only", () => {
42
+ expect(() =>
43
+ render(
44
+ <Theme>
45
+ <RadioGroup items={items} checkedId="one" readOnly />
46
+ </Theme>
47
+ )
48
+ ).not.toThrow()
49
+ })
50
+ it('Throws if has both `checkedId` and `initialCheckedId`', () => {
51
+ expect(() =>
52
+ render(
53
+ <Theme>
54
+ <RadioGroup items={items} initialCheckedId="one" checkedId="one" onChange={() => {}} />
55
+ </Theme>
56
+ )
57
+ ).toThrow(/both(?=.*initialValue)(?=.*value){2}/)
58
+ })
59
+ })
60
+
61
+ describe('RadioGroup (uncontrolled)', () => {
62
+ it('Selects one and only one item', async () => {
63
+ const { getByText, queryAllByA11yState } = render(
64
+ <Theme>
65
+ <RadioGroup items={items} />
66
+ </Theme>
67
+ )
68
+
69
+ expect(queryAllByA11yState(checked)).toHaveLength(0)
70
+
71
+ const one = getByText('One')
72
+ await fireEvent.press(one)
73
+ expect(queryAllByA11yState(checked)).toHaveLength(1)
74
+ expect(containsText(queryAllByA11yState(checked), 'One')).toBeTruthy()
75
+
76
+ const two = getByText('Two')
77
+ await fireEvent.press(two)
78
+ expect(queryAllByA11yState(checked)).toHaveLength(1)
79
+ expect(containsText(queryAllByA11yState(checked), 'Two')).toBeTruthy()
80
+ expect(containsText(queryAllByA11yState(checked), 'One')).not.toBeTruthy()
81
+ })
82
+
83
+ it('Does not deselect if the selected item is pressed', async () => {
84
+ const { getByText, queryAllByA11yState } = render(
85
+ <Theme>
86
+ <RadioGroup items={items} />
87
+ </Theme>
88
+ )
89
+
90
+ expect(queryAllByA11yState(checked)).toHaveLength(0)
91
+
92
+ const three = getByText('Three')
93
+ await fireEvent.press(three)
94
+ expect(queryAllByA11yState(checked)).toHaveLength(1)
95
+ expect(containsText(queryAllByA11yState(checked), 'Three')).toBeTruthy()
96
+
97
+ await fireEvent.press(three)
98
+ expect(queryAllByA11yState(checked)).toHaveLength(1)
99
+ expect(containsText(queryAllByA11yState(checked), 'Three')).toBeTruthy()
100
+ })
101
+
102
+ it('Is accessible as a radio button', async () => {
103
+ const { queryAllByA11yRole, queryAllByA11yState } = render(
104
+ <Theme>
105
+ <RadioGroup items={items} />
106
+ </Theme>
107
+ )
108
+
109
+ expect(queryAllByA11yRole('checkbox')).toHaveLength(0)
110
+ expect(queryAllByA11yRole('radiogroup')).toHaveLength(1)
111
+ const radios = queryAllByA11yRole('radio')
112
+ expect(radios).toHaveLength(4)
113
+
114
+ expect(queryAllByA11yState(checked)).toHaveLength(0)
115
+ await fireEvent.press(radios[0])
116
+ expect(queryAllByA11yState(checked)).toHaveLength(1)
117
+ })
118
+
119
+ it('Auto-selects initialCheckedId', async () => {
120
+ const { getByText, queryAllByA11yState } = render(
121
+ <Theme>
122
+ <RadioGroup items={items} initialCheckedId="two" />
123
+ </Theme>
124
+ )
125
+ expect(queryAllByA11yState(checked)).toHaveLength(1)
126
+ expect(containsText(queryAllByA11yState(checked), 'One')).not.toBeTruthy()
127
+ expect(containsText(queryAllByA11yState(checked), 'Two')).toBeTruthy()
128
+
129
+ const three = getByText('Three')
130
+ await fireEvent.press(three)
131
+
132
+ expect(queryAllByA11yState(checked)).toHaveLength(1)
133
+ expect(containsText(queryAllByA11yState(checked), 'Three')).toBeTruthy()
134
+ expect(containsText(queryAllByA11yState(checked), 'Two')).not.toBeTruthy()
135
+ expect(containsText(queryAllByA11yState(checked), 'One')).not.toBeTruthy()
136
+ })
137
+ })
138
+
139
+ describe('RadioGroup (controlled)', () => {
140
+ it('Calls onChange handler on press in controlled mode, providing pressed id', async () => {
141
+ const handleChange = jest.fn((arg) => arg)
142
+ const { getByText } = render(
143
+ <Theme>
144
+ <RadioGroup items={items} checkedId={null} onChange={handleChange} />
145
+ </Theme>
146
+ )
147
+
148
+ expect(handleChange).toHaveBeenCalledTimes(0)
149
+
150
+ const one = getByText('One')
151
+ await fireEvent(one, 'press', { nativeEvent: 'example' })
152
+ expect(handleChange).toHaveBeenCalledTimes(1)
153
+ expect(handleChange).toHaveBeenLastCalledWith('one', { nativeEvent: 'example' })
154
+
155
+ const two = getByText('Two')
156
+ await fireEvent(two, 'press', { nativeEvent: 'example2' })
157
+ expect(handleChange).toHaveBeenCalledTimes(2)
158
+ expect(handleChange).toHaveBeenLastCalledWith('two', { nativeEvent: 'example2' })
159
+ })
160
+
161
+ it("Doesn't change its own selection if `checkedId` is passed", async () => {
162
+ const { getByText, queryAllByA11yState } = render(
163
+ <Theme>
164
+ <RadioGroup items={items} checkedId="one" onChange={() => {}} />
165
+ </Theme>
166
+ )
167
+
168
+ expect(queryAllByA11yState(checked)).toHaveLength(1)
169
+ expect(containsText(queryAllByA11yState(checked), 'One')).toBeTruthy()
170
+
171
+ const two = getByText('Two')
172
+ await fireEvent.press(two)
173
+ expect(queryAllByA11yState(checked)).toHaveLength(1)
174
+ expect(containsText(queryAllByA11yState(checked), 'Two')).not.toBeTruthy()
175
+ expect(containsText(queryAllByA11yState(checked), 'One')).toBeTruthy()
176
+ })
177
+ })
178
+
179
+ describe('RadioGroup (read-only)', () => {
180
+ it("Doesn't call onChange handler when read-only", async () => {
181
+ const handleChange = jest.fn((arg) => arg)
182
+ const { getByText } = render(
183
+ <Theme>
184
+ <RadioGroup items={items} checkedId="two" onChange={handleChange} readOnly />
185
+ </Theme>
186
+ )
187
+
188
+ expect(handleChange).toHaveBeenCalledTimes(0)
189
+
190
+ const one = getByText('One')
191
+ await fireEvent.press(one)
192
+ expect(handleChange).toHaveBeenCalledTimes(0)
193
+
194
+ const two = getByText('Two')
195
+ await fireEvent.press(two)
196
+ expect(handleChange).toHaveBeenCalledTimes(0)
197
+ })
198
+
199
+ it("Doesn't change its selection on press", async () => {
200
+ const { getByText, queryAllByA11yState } = render(
201
+ <Theme>
202
+ <RadioGroup items={items} checkedId="one" readOnly />
203
+ </Theme>
204
+ )
205
+
206
+ expect(queryAllByA11yState(checked)).toHaveLength(1)
207
+ expect(containsText(queryAllByA11yState(checked), 'One')).toBeTruthy()
208
+
209
+ const one = getByText('One')
210
+ await fireEvent.press(one)
211
+ expect(queryAllByA11yState(checked)).toHaveLength(1)
212
+ expect(containsText(queryAllByA11yState(checked), 'One')).toBeTruthy()
213
+
214
+ const two = getByText('Two')
215
+ await fireEvent.press(two)
216
+ expect(queryAllByA11yState(checked)).toHaveLength(1)
217
+ expect(containsText(queryAllByA11yState(checked), 'Two')).not.toBeTruthy()
218
+ expect(containsText(queryAllByA11yState(checked), 'One')).toBeTruthy()
219
+ })
220
+ })