@telus-uds/components-base 0.0.2-prerelease.9 → 1.1.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 (293) hide show
  1. package/.eslintrc.js +9 -0
  2. package/.storybook/main.js +4 -0
  3. package/.storybook/preview.js +37 -0
  4. package/.ultra.cache.json +1 -1
  5. package/CHANGELOG.md +50 -0
  6. package/README.md +4 -2
  7. package/__fixtures__/test-utils.js +25 -0
  8. package/__fixtures__/testTheme.js +4 -2
  9. package/__tests__/Button/ButtonGroup.test.jsx +4 -5
  10. package/__tests__/Checkbox/Checkbox.test.jsx +2 -2
  11. package/__tests__/Checkbox/CheckboxGroup.test.jsx +4 -5
  12. package/__tests__/ExpandCollapse/ExpandCollapse.test.jsx +2 -2
  13. package/__tests__/HorizontalScroll/HorizontalScroll.test.jsx +164 -0
  14. package/__tests__/Link/LinkBase.test.jsx +0 -14
  15. package/__tests__/Radio/Radio.test.jsx +2 -2
  16. package/__tests__/Radio/RadioGroup.test.jsx +4 -5
  17. package/__tests__/RadioCard/RadioCard.test.jsx +2 -2
  18. package/__tests__/RadioCard/RadioCardGroup.test.jsx +4 -5
  19. package/__tests__/Search/Search.test.jsx +9 -8
  20. package/__tests__/Select/Select.test.jsx +3 -2
  21. package/__tests__/Tabs/Tabs.test.jsx +1 -161
  22. package/__tests__/Tags/Tags.test.jsx +4 -5
  23. package/__tests__/TextInput/TextArea.test.jsx +3 -2
  24. package/__tests__/TextInput/TextInputBase.test.jsx +10 -5
  25. package/__tests__/ThemeProvider/ThemeProvider.test.jsx +77 -0
  26. package/__tests__/ThemeProvider/useThemeTokens.test.jsx +9 -5
  27. package/__tests__/ThemeProvider/utils/theme-tokens.test.js +41 -0
  28. package/__tests__/ToggleSwitch/ToggleSwitch.test.jsx +3 -2
  29. package/__tests__/utils/children.test.jsx +128 -0
  30. package/__tests__/utils/input.test.js +1 -1
  31. package/__tests__/utils/semantics.test.jsx +43 -0
  32. package/babel.config.js +9 -16
  33. package/component-docs.json +10313 -0
  34. package/generate-component-docs.js +56 -0
  35. package/lib/A11yText/index.js +10 -5
  36. package/lib/ActivityIndicator/Spinner.js +16 -13
  37. package/lib/ActivityIndicator/Spinner.native.js +12 -8
  38. package/lib/Box/Box.js +103 -8
  39. package/lib/Button/Button.js +9 -8
  40. package/lib/Button/ButtonBase.js +14 -7
  41. package/lib/Button/ButtonGroup.js +25 -10
  42. package/lib/Button/ButtonLink.js +10 -7
  43. package/lib/Card/Card.js +2 -0
  44. package/lib/Card/CardBase.js +13 -5
  45. package/lib/Card/PressableCardBase.js +12 -8
  46. package/lib/Checkbox/Checkbox.js +25 -14
  47. package/lib/Checkbox/CheckboxGroup.js +22 -12
  48. package/lib/Divider/Divider.js +12 -7
  49. package/lib/ExpandCollapse/Accordion.js +10 -4
  50. package/lib/ExpandCollapse/Control.js +12 -6
  51. package/lib/ExpandCollapse/ExpandCollapse.js +10 -5
  52. package/lib/ExpandCollapse/Panel.js +8 -7
  53. package/lib/Feedback/Feedback.js +10 -5
  54. package/lib/Fieldset/Fieldset.js +10 -5
  55. package/lib/Fieldset/FieldsetContainer.js +10 -5
  56. package/lib/Fieldset/FieldsetContainer.native.js +10 -5
  57. package/lib/Fieldset/Legend.js +10 -5
  58. package/lib/Fieldset/Legend.native.js +10 -5
  59. package/lib/FlexGrid/Col/Col.js +8 -5
  60. package/lib/FlexGrid/FlexGrid.js +31 -6
  61. package/lib/FlexGrid/Row/Row.js +12 -5
  62. package/lib/{Tabs → HorizontalScroll}/HorizontalScroll.js +5 -4
  63. package/lib/{Tabs/TabsScrollButton.js → HorizontalScroll/HorizontalScrollButton.js} +14 -8
  64. package/lib/{Tabs → HorizontalScroll}/ScrollViewEnd.js +0 -0
  65. package/lib/{Tabs → HorizontalScroll}/ScrollViewEnd.native.js +0 -0
  66. package/lib/{Tabs → HorizontalScroll}/dictionary.js +0 -0
  67. package/lib/HorizontalScroll/index.js +35 -0
  68. package/lib/{Tabs → HorizontalScroll}/itemPositions.js +0 -0
  69. package/lib/Icon/Icon.js +16 -9
  70. package/lib/Icon/IconText.js +8 -7
  71. package/lib/IconButton/IconButton.js +10 -5
  72. package/lib/InputLabel/InputLabel.js +33 -5
  73. package/lib/InputLabel/LabelContent.js +22 -12
  74. package/lib/InputLabel/LabelContent.native.js +23 -5
  75. package/lib/InputSupports/InputSupports.js +10 -5
  76. package/lib/Link/ChevronLink.js +12 -5
  77. package/lib/Link/InlinePressable.js +10 -4
  78. package/lib/Link/InlinePressable.native.js +5 -4
  79. package/lib/Link/Link.js +12 -5
  80. package/lib/Link/LinkBase.js +12 -5
  81. package/lib/Link/TextButton.js +10 -5
  82. package/lib/List/List.js +6 -6
  83. package/lib/List/ListItem.js +28 -33
  84. package/lib/List/index.js +15 -0
  85. package/lib/Modal/Modal.js +10 -5
  86. package/lib/Notification/Notification.js +21 -5
  87. package/lib/Pagination/PageButton.js +16 -11
  88. package/lib/Pagination/Pagination.js +12 -7
  89. package/lib/Pagination/SideButton.js +12 -7
  90. package/lib/Pagination/usePagination.js +2 -2
  91. package/lib/Progress/Progress.js +10 -5
  92. package/lib/Progress/ProgressBar.js +21 -10
  93. package/lib/Progress/ProgressBarBackground.js +12 -8
  94. package/lib/Radio/Radio.js +14 -13
  95. package/lib/Radio/RadioButton.js +20 -9
  96. package/lib/Radio/RadioGroup.js +24 -13
  97. package/lib/RadioCard/RadioCard.js +14 -10
  98. package/lib/RadioCard/RadioCardGroup.js +13 -12
  99. package/lib/Search/Search.js +29 -18
  100. package/lib/Select/Picker.js +11 -6
  101. package/lib/Select/Picker.native.js +21 -6
  102. package/lib/Select/Select.js +46 -4
  103. package/lib/SideNav/Item.js +10 -5
  104. package/lib/SideNav/ItemsGroup.js +10 -5
  105. package/lib/SideNav/SideNav.js +11 -7
  106. package/lib/Skeleton/Skeleton.js +15 -15
  107. package/lib/Skeleton/skeletonWebAnimation.js +1 -1
  108. package/lib/Spacer/Spacer.js +19 -7
  109. package/lib/StackView/StackView.js +26 -7
  110. package/lib/StackView/StackWrap.js +24 -13
  111. package/lib/StackView/StackWrapBox.js +34 -8
  112. package/lib/StackView/StackWrapGap.js +16 -7
  113. package/lib/StackView/common.js +4 -2
  114. package/lib/StackView/getStackedContent.js +2 -2
  115. package/lib/StepTracker/StepTracker.js +10 -5
  116. package/lib/Tabs/Tabs.js +26 -19
  117. package/lib/Tabs/TabsItem.js +16 -12
  118. package/lib/Tags/Tags.js +27 -11
  119. package/lib/TextInput/TextArea.js +7 -5
  120. package/lib/TextInput/TextInput.js +12 -6
  121. package/lib/TextInput/TextInputBase.js +12 -8
  122. package/lib/ThemeProvider/ThemeProvider.js +14 -10
  123. package/lib/ThemeProvider/useSetTheme.js +6 -1
  124. package/lib/ThemeProvider/utils/styles.js +2 -2
  125. package/lib/ThemeProvider/utils/theme-tokens.js +39 -8
  126. package/lib/ToggleSwitch/ToggleSwitch.js +11 -6
  127. package/lib/Tooltip/Backdrop.js +10 -2
  128. package/lib/Tooltip/Tooltip.js +5 -4
  129. package/lib/Typography/Typography.js +40 -24
  130. package/lib/index.js +36 -1
  131. package/lib/utils/a11y/index.js +13 -0
  132. package/lib/utils/a11y/propTypes.js +61 -0
  133. package/lib/utils/a11y/propTypes.native.js +47 -0
  134. package/lib/utils/a11y/semantics.js +173 -0
  135. package/lib/utils/animation/useVerticalExpandAnimation.js +1 -1
  136. package/lib/utils/children.js +55 -8
  137. package/lib/utils/input.js +27 -17
  138. package/lib/utils/propTypes.js +40 -68
  139. package/lib/utils/useCopy.js +1 -1
  140. package/lib/utils/useHash.js +8 -4
  141. package/lib/utils/useSpacingScale.js +1 -3
  142. package/lib/utils/useUniqueId.js +1 -1
  143. package/package.json +14 -6
  144. package/release-context.json +4 -4
  145. package/src/A11yText/index.jsx +6 -4
  146. package/src/ActivityIndicator/Spinner.jsx +5 -3
  147. package/src/ActivityIndicator/Spinner.native.jsx +5 -3
  148. package/src/Box/Box.jsx +125 -39
  149. package/src/Button/Button.jsx +7 -4
  150. package/src/Button/ButtonBase.jsx +86 -77
  151. package/src/Button/ButtonGroup.jsx +81 -69
  152. package/src/Button/ButtonLink.jsx +18 -13
  153. package/src/Card/Card.jsx +2 -2
  154. package/src/Card/CardBase.jsx +6 -4
  155. package/src/Card/PressableCardBase.jsx +71 -64
  156. package/src/Checkbox/Checkbox.jsx +118 -108
  157. package/src/Checkbox/CheckboxGroup.jsx +72 -62
  158. package/src/Divider/Divider.jsx +7 -4
  159. package/src/ExpandCollapse/Accordion.jsx +3 -2
  160. package/src/ExpandCollapse/Control.jsx +40 -43
  161. package/src/ExpandCollapse/ExpandCollapse.jsx +26 -23
  162. package/src/ExpandCollapse/Panel.jsx +69 -63
  163. package/src/Feedback/Feedback.jsx +36 -33
  164. package/src/Fieldset/Fieldset.jsx +63 -56
  165. package/src/Fieldset/FieldsetContainer.jsx +14 -5
  166. package/src/Fieldset/FieldsetContainer.native.jsx +7 -4
  167. package/src/Fieldset/Legend.jsx +7 -2
  168. package/src/Fieldset/Legend.native.jsx +7 -2
  169. package/src/FlexGrid/Col/Col.jsx +139 -132
  170. package/src/FlexGrid/FlexGrid.jsx +79 -51
  171. package/src/FlexGrid/Row/Row.jsx +55 -48
  172. package/src/HorizontalScroll/HorizontalScroll.jsx +168 -0
  173. package/src/HorizontalScroll/HorizontalScrollButton.jsx +105 -0
  174. package/src/{Tabs → HorizontalScroll}/ScrollViewEnd.jsx +0 -0
  175. package/src/{Tabs → HorizontalScroll}/ScrollViewEnd.native.jsx +0 -0
  176. package/src/{Tabs → HorizontalScroll}/dictionary.js +0 -0
  177. package/src/HorizontalScroll/index.js +17 -0
  178. package/src/{Tabs → HorizontalScroll}/itemPositions.js +0 -0
  179. package/src/Icon/Icon.jsx +37 -35
  180. package/src/Icon/IconText.jsx +22 -17
  181. package/src/IconButton/IconButton.jsx +49 -42
  182. package/src/InputLabel/InputLabel.jsx +53 -38
  183. package/src/InputLabel/LabelContent.jsx +14 -6
  184. package/src/InputLabel/LabelContent.native.jsx +11 -2
  185. package/src/InputSupports/InputSupports.jsx +29 -34
  186. package/src/Link/ChevronLink.jsx +26 -16
  187. package/src/Link/InlinePressable.jsx +5 -3
  188. package/src/Link/InlinePressable.native.jsx +5 -3
  189. package/src/Link/Link.jsx +22 -16
  190. package/src/Link/LinkBase.jsx +67 -58
  191. package/src/Link/TextButton.jsx +30 -23
  192. package/src/List/List.jsx +6 -7
  193. package/src/List/ListItem.jsx +70 -90
  194. package/src/List/index.js +5 -0
  195. package/src/Modal/Modal.jsx +9 -4
  196. package/src/Notification/Notification.jsx +58 -43
  197. package/src/Pagination/PageButton.jsx +37 -34
  198. package/src/Pagination/Pagination.jsx +88 -92
  199. package/src/Pagination/SideButton.jsx +44 -41
  200. package/src/Progress/Progress.jsx +5 -4
  201. package/src/Progress/ProgressBar.jsx +42 -29
  202. package/src/Progress/ProgressBarBackground.jsx +5 -3
  203. package/src/Radio/Radio.jsx +85 -78
  204. package/src/Radio/RadioButton.jsx +54 -43
  205. package/src/Radio/RadioGroup.jsx +74 -63
  206. package/src/RadioCard/RadioCard.jsx +75 -68
  207. package/src/RadioCard/RadioCardGroup.jsx +82 -75
  208. package/src/Search/Search.jsx +127 -106
  209. package/src/Select/Picker.jsx +49 -42
  210. package/src/Select/Picker.native.jsx +56 -49
  211. package/src/Select/Select.jsx +115 -72
  212. package/src/SideNav/Item.jsx +53 -46
  213. package/src/SideNav/ItemsGroup.jsx +50 -43
  214. package/src/SideNav/SideNav.jsx +68 -60
  215. package/src/Skeleton/Skeleton.jsx +9 -13
  216. package/src/Spacer/Spacer.jsx +11 -4
  217. package/src/StackView/StackView.jsx +47 -23
  218. package/src/StackView/StackWrap.jsx +14 -12
  219. package/src/StackView/StackWrapBox.jsx +62 -28
  220. package/src/StackView/StackWrapGap.jsx +46 -24
  221. package/src/StackView/common.jsx +3 -2
  222. package/src/StepTracker/StepTracker.jsx +73 -62
  223. package/src/Tabs/Tabs.jsx +70 -62
  224. package/src/Tabs/TabsItem.jsx +111 -103
  225. package/src/Tags/Tags.jsx +114 -102
  226. package/src/TextInput/TextArea.jsx +5 -4
  227. package/src/TextInput/TextInput.jsx +5 -4
  228. package/src/TextInput/TextInputBase.jsx +84 -77
  229. package/src/ThemeProvider/ThemeProvider.jsx +11 -7
  230. package/src/ThemeProvider/useSetTheme.js +4 -0
  231. package/src/ThemeProvider/utils/theme-tokens.js +28 -0
  232. package/src/ToggleSwitch/ToggleSwitch.jsx +49 -50
  233. package/src/Tooltip/Tooltip.jsx +134 -130
  234. package/src/Typography/Typography.jsx +67 -44
  235. package/src/index.js +3 -1
  236. package/src/utils/a11y/index.js +1 -0
  237. package/src/utils/a11y/propTypes.js +61 -0
  238. package/src/utils/a11y/propTypes.native.js +39 -0
  239. package/src/utils/a11y/semantics.js +162 -0
  240. package/src/utils/children.jsx +60 -7
  241. package/src/utils/input.js +20 -17
  242. package/src/utils/propTypes.js +30 -76
  243. package/src/utils/useCopy.js +1 -1
  244. package/src/utils/useHash.js +8 -3
  245. package/stories/A11yText/A11yText.stories.jsx +3 -3
  246. package/stories/ActivityIndicator/ActivityIndicator.stories.jsx +2 -2
  247. package/stories/Box/Box.stories.jsx +2 -2
  248. package/stories/Button/Button.stories.jsx +3 -3
  249. package/stories/Button/ButtonGroup.stories.jsx +2 -2
  250. package/stories/Button/ButtonLink.stories.jsx +2 -2
  251. package/stories/Card/Card.stories.jsx +2 -2
  252. package/stories/Checkbox/Checkbox.stories.jsx +2 -2
  253. package/stories/Divider/Divider.stories.jsx +2 -2
  254. package/stories/ExpandCollapse/ExpandCollapse.stories.jsx +3 -3
  255. package/stories/Feedback/Feedback.stories.jsx +2 -2
  256. package/stories/FlexGrid/01 FlexGrid.stories.jsx +2 -2
  257. package/stories/FlexGrid/02 Row.stories.jsx +2 -2
  258. package/stories/FlexGrid/03 Col.stories.jsx +2 -2
  259. package/stories/Icon/Icon.stories.jsx +2 -2
  260. package/stories/IconButton/IconButton.stories.jsx +2 -2
  261. package/stories/InputLabel/InputLabel.stories.jsx +2 -2
  262. package/stories/Link/ChevronLink.stories.jsx +2 -2
  263. package/stories/Link/Link.stories.jsx +2 -2
  264. package/stories/Link/TextButton.stories.jsx +2 -2
  265. package/stories/List/List.stories.jsx +2 -2
  266. package/stories/Modal/Modal.stories.jsx +2 -2
  267. package/stories/Notification/Notification.stories.jsx +2 -2
  268. package/stories/Pagination/Pagination.stories.jsx +2 -2
  269. package/stories/Progress/Progress.stories.jsx +2 -2
  270. package/stories/Radio/Radio.stories.jsx +2 -2
  271. package/stories/RadioCard/RadioCard.stories.jsx +2 -2
  272. package/stories/Search/Search.stories.jsx +2 -2
  273. package/stories/Select/Select.stories.jsx +2 -2
  274. package/stories/SideNav/SideNav.stories.jsx +2 -2
  275. package/stories/SideNav/SideNavItem.stories.jsx +2 -2
  276. package/stories/SideNav/SideNavItemsGroup.stories.jsx +2 -2
  277. package/stories/Skeleton/Skeleton.stories.jsx +3 -3
  278. package/stories/Spacer/Spacer.stories.jsx +2 -2
  279. package/stories/StackView/StackView.stories.jsx +2 -2
  280. package/stories/StackView/StackWrap.stories.jsx +2 -2
  281. package/stories/StepTracker/StepTracker.stories.jsx +2 -2
  282. package/stories/Tabs/Tabs.stories.jsx +2 -2
  283. package/stories/Tags/Tags.stories.jsx +2 -2
  284. package/stories/TextInput/TextArea.stories.jsx +2 -2
  285. package/stories/TextInput/TextInput.stories.jsx +2 -2
  286. package/stories/ToggleSwitch/ToggleSwitch.stories.jsx +2 -2
  287. package/stories/Tooltip/Tooltip.stories.jsx +2 -2
  288. package/stories/TooltipButton/TooltipButton.stories.jsx +2 -2
  289. package/stories/Typography/Typography.stories.jsx +2 -2
  290. package/stories/platform-supports.jsx +1 -1
  291. package/stories/supports.jsx +4 -5
  292. package/src/Tabs/HorizontalScroll.jsx +0 -165
  293. package/src/Tabs/TabsScrollButton.jsx +0 -100
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import { Text } from 'react-native'
3
3
 
4
4
  import PropTypes from 'prop-types'
@@ -25,53 +25,56 @@ const directionToSide = {
25
25
  next: 'right'
26
26
  }
27
27
 
28
- function SideButton({ direction = 'previous', onPress, href, copy, variant, tokens, ...props }) {
29
- const viewport = useViewport()
30
- const buttonVariant = { direction, viewport, ...variant }
31
- const getTokens = useThemeTokensCallback('PaginationSideButton', tokens, buttonVariant)
28
+ const SideButton = forwardRef(
29
+ ({ direction = 'previous', onPress, href, copy, variant, tokens, ...props }, ref) => {
30
+ const viewport = useViewport()
31
+ const buttonVariant = { direction, viewport, ...variant }
32
+ const getTokens = useThemeTokensCallback('PaginationSideButton', tokens, buttonVariant)
32
33
 
33
- const getCopy = useCopy({ dictionary, copy })
34
+ const getCopy = useCopy({ dictionary, copy })
34
35
 
35
- const { icon } = getTokens(tokens, buttonVariant)
36
+ const { icon } = getTokens(tokens, buttonVariant)
36
37
 
37
- const getButtonTokens = (buttonState) => selectTokens('Button', getTokens(buttonState))
38
- const getIconTokens = (buttonState) => selectIconTokens(getTokens(buttonState), direction)
38
+ const getButtonTokens = (buttonState) => selectTokens('Button', getTokens(buttonState))
39
+ const getIconTokens = (buttonState) => selectIconTokens(getTokens(buttonState), direction)
39
40
 
40
- const label = direction === 'previous' ? getCopy('previousText') : getCopy('nextText')
41
- const showLabel = viewport !== 'sm' && viewport !== 'xs'
41
+ const label = direction === 'previous' ? getCopy('previousText') : getCopy('nextText')
42
+ const showLabel = viewport !== 'sm' && viewport !== 'xs'
42
43
 
43
- const accessibilityLabel =
44
- direction === 'previous' ? getCopy('previousLabel') : getCopy('nextLabel')
45
- const accessibilityRole = href !== undefined ? 'link' : 'button'
44
+ const accessibilityLabel =
45
+ direction === 'previous' ? getCopy('previousLabel') : getCopy('nextLabel')
46
+ const accessibilityRole = href !== undefined ? 'link' : 'button'
46
47
 
47
- const { hrefAttrs, rest } = hrefAttrsProp.bundle(props)
48
- const buttonProps = {
49
- accessibilityRole,
50
- accessibilityLabel,
51
- onPress,
52
- href,
53
- hrefAttrs,
54
- ...rest
55
- }
48
+ const { hrefAttrs, rest } = hrefAttrsProp.bundle(props)
49
+ const buttonProps = {
50
+ accessibilityRole,
51
+ accessibilityLabel,
52
+ onPress,
53
+ href,
54
+ hrefAttrs,
55
+ ...rest
56
+ }
56
57
 
57
- return (
58
- <ButtonBase {...buttonProps} tokens={getButtonTokens}>
59
- {({ textStyles, ...buttonState }) => {
60
- const iconProps = { tokens: getIconTokens(buttonState) }
61
- return (
62
- <IconText
63
- icon={icon}
64
- space={1}
65
- iconPosition={directionToSide[direction]}
66
- iconProps={iconProps}
67
- >
68
- {showLabel && <Text style={textStyles}>{label}</Text>}
69
- </IconText>
70
- )
71
- }}
72
- </ButtonBase>
73
- )
74
- }
58
+ return (
59
+ <ButtonBase ref={ref} {...buttonProps} tokens={getButtonTokens}>
60
+ {({ textStyles, ...buttonState }) => {
61
+ const iconProps = { tokens: getIconTokens(buttonState) }
62
+ return (
63
+ <IconText
64
+ icon={icon}
65
+ space={1}
66
+ iconPosition={directionToSide[direction]}
67
+ iconProps={iconProps}
68
+ >
69
+ {showLabel && <Text style={textStyles}>{label}</Text>}
70
+ </IconText>
71
+ )
72
+ }}
73
+ </ButtonBase>
74
+ )
75
+ }
76
+ )
77
+ SideButton.displayName = 'SideButton'
75
78
 
76
79
  SideButton.propTypes = {
77
80
  direction: PropTypes.oneOf(['previous', 'next']),
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import { View } from 'react-native'
4
4
 
@@ -49,15 +49,16 @@ const selectProgressStyles = ({
49
49
  * role.
50
50
  *
51
51
  */
52
- const Progress = ({ children, tokens, variant, ...rest }) => {
52
+ const Progress = forwardRef(({ children, tokens, variant, ...rest }, ref) => {
53
53
  const themeTokens = useThemeTokens('Progress', tokens, variant)
54
54
 
55
55
  return (
56
- <View style={selectProgressStyles(themeTokens)} {...a11yProps.select(rest)}>
56
+ <View ref={ref} style={selectProgressStyles(themeTokens)} {...a11yProps.select(rest)}>
57
57
  {children}
58
58
  </View>
59
59
  )
60
- }
60
+ })
61
+ Progress.displayName = 'Progress'
61
62
 
62
63
  Progress.propTypes = {
63
64
  /**
@@ -1,6 +1,6 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import PropTypes from 'prop-types'
3
- import { StyleSheet, View } from 'react-native'
3
+ import { Platform, StyleSheet, View } from 'react-native'
4
4
 
5
5
  import ProgressBarBackground from './ProgressBarBackground'
6
6
  import { a11yProps } from '../utils/propTypes'
@@ -52,33 +52,37 @@ const selectBarStyles = (
52
52
  * - `accessibilityValue.text` (`aria-valuetext`): `%{percentage}%`,
53
53
  *
54
54
  */
55
- const ProgressBar = ({ children = null, percentage = 0, tokens, variant, ...rest }) => {
56
- const themeTokens = useThemeTokens('ProgressBar', tokens, variant)
57
- if (percentage < 0) {
58
- throw new Error('ProgressBar: `percentage` must be a positive number')
59
- } else if (percentage > 100) {
60
- throw new Error('ProgressBar: `percentage` cannot exceed 100')
61
- }
62
- const accessibilityProps = {
63
- accessibilityRole: 'progressbar',
64
- accessibilityValue: {
65
- min: 0,
66
- max: 100,
67
- now: percentage,
68
- text: `${percentage}%`
69
- },
70
- ...a11yProps.select(rest)
71
- }
55
+ const ProgressBar = forwardRef(
56
+ ({ children = null, percentage = 0, tokens, variant, ...rest }, ref) => {
57
+ const themeTokens = useThemeTokens('ProgressBar', tokens, variant)
58
+ if (percentage < 0) {
59
+ throw new Error('ProgressBar: `percentage` must be a positive number')
60
+ } else if (percentage > 100) {
61
+ throw new Error('ProgressBar: `percentage` cannot exceed 100')
62
+ }
63
+ const accessibilityProps = {
64
+ accessibilityRole: 'progressbar',
65
+ accessibilityValue: {
66
+ min: 0,
67
+ max: 100,
68
+ now: percentage,
69
+ text: `${percentage}%`
70
+ },
71
+ ...a11yProps.select(rest)
72
+ }
72
73
 
73
- return percentage > 0 ? (
74
- <View
75
- style={[staticStyles.bar, selectBarStyles(themeTokens, percentage)]}
76
- {...accessibilityProps}
77
- >
78
- {children ?? <ProgressBarBackground variant={variant} />}
79
- </View>
80
- ) : null
81
- }
74
+ return percentage > 0 ? (
75
+ <View
76
+ ref={ref}
77
+ style={[staticStyles.bar, selectBarStyles(themeTokens, percentage)]}
78
+ {...accessibilityProps}
79
+ >
80
+ {children ?? <ProgressBarBackground variant={variant} />}
81
+ </View>
82
+ ) : null
83
+ }
84
+ )
85
+ ProgressBar.displayName = 'ProgressBar'
82
86
 
83
87
  ProgressBar.propTypes = {
84
88
  /**
@@ -106,5 +110,14 @@ ProgressBar.propTypes = {
106
110
  export default ProgressBar
107
111
 
108
112
  const staticStyles = StyleSheet.create({
109
- bar: { height: '100%', outlineStyle: 'solid', overflow: 'hidden', position: 'absolute' }
113
+ bar: {
114
+ height: '100%',
115
+ overflow: 'hidden',
116
+ position: 'absolute',
117
+ ...Platform.select({
118
+ web: {
119
+ outlineStyle: 'solid'
120
+ }
121
+ })
122
+ }
110
123
  })
@@ -1,11 +1,11 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import { ImageBackground, StyleSheet } from 'react-native'
3
3
 
4
4
  import { variantProp } from '../utils'
5
5
 
6
6
  const inactiveBackground = `%3Csvg xmlns='http://www.w3.org/2000/svg' width='100%25' height='24'%3E%3Cdefs%3E%3Cpattern id='DisabledProgress7' patternUnits='userSpaceOnUse' width='8' height='8'%3E%3Crect width='8' height='8' fill='%23B2B9BF'%3E%3C/rect%3E%3Ccircle cx='4' cy='4' r='2' fill='%23676E73' stroke='%23676E73' stroke-width='0'%3E%3C/circle%3E%3Ccircle cx='0' cy='0' r='2' fill='%23676E73' stroke='%23676E73' stroke-width='0'%3E%3C/circle%3E%3Ccircle cx='0' cy='8' r='2' fill='%23676E73' stroke='%23676E73' stroke-width='0'%3E%3C/circle%3E%3Ccircle cx='8' cy='0' r='2' fill='%23676E73' stroke='%23676E73' stroke-width='0'%3E%3C/circle%3E%3Ccircle cx='8' cy='8' r='2' fill='%23676E73' stroke='%23676E73' stroke-width='0'%3E%3C/circle%3E%3C/pattern%3E%3C/defs%3E%3Cpath d='M 0 0 L 0 140 L 2000 2000 L 2000 0 Z' style='fill: url(&quot;%23DisabledProgress7&quot;);'%3E%3C/path%3E%3C/svg%3E`
7
7
  const negativeBackground = `%3Csvg xmlns='http://www.w3.org/2000/svg' width='100%25' height='24'%3E%3Cdefs%3E%3Cpattern id='NegativeProgress6' patternUnits='userSpaceOnUse' width='8' height='8'%3E%3Crect width='8' height='8' fill='%23C12335'%3E%3C/rect%3E%3Cpath d='M 0,8 l 8,-8 M -2,2 l 4,-4 M 6,10 l 4,-4' stroke-width='2' shape-rendering='auto' stroke='%23e7adb4' stroke-linecap='square'%3E%3C/path%3E%3C/pattern%3E%3C/defs%3E%3Cpath d='M 0 0 L 0 140 L 2000 2000 L 2000 0 Z' style='fill: url(&quot;%23NegativeProgress6&quot;);'%3E%3C/path%3E%3C/svg%3E`
8
- const ProgressBarBackground = ({ variant }) => {
8
+ const ProgressBarBackground = forwardRef(({ variant }, ref) => {
9
9
  let source = null
10
10
  if (variant?.inactive) {
11
11
  source = inactiveBackground
@@ -16,11 +16,13 @@ const ProgressBarBackground = ({ variant }) => {
16
16
  }
17
17
  return (
18
18
  <ImageBackground
19
+ ref={ref}
19
20
  source={{ uri: `data:image/svg+xml,${source}` }}
20
21
  style={staticStyles.imageBackground}
21
22
  />
22
23
  )
23
- }
24
+ })
25
+ ProgressBarBackground.displayName = 'ProgressBarBackground'
24
26
 
25
27
  ProgressBarBackground.propTypes = {
26
28
  /**
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import { Pressable, StyleSheet, Text, View } from 'react-native'
4
4
 
@@ -90,89 +90,96 @@ const selectLabelStyles = ({
90
90
  * or the internal state in case of uncontrolled radio button.
91
91
  *
92
92
  */
93
- const Radio = ({
94
- checked,
95
- defaultChecked,
96
- description,
97
- error = false,
98
- id,
99
- inactive,
100
- label,
101
- name: inputName,
102
- onChange,
103
- tokens,
104
- value,
105
- variant,
106
- ...rest
107
- }) => {
108
- const { currentValue: isChecked, setValue: setIsChecked, isControlled } = useInputValue(
93
+ const Radio = forwardRef(
94
+ (
109
95
  {
110
- value: checked,
111
- initialValue: defaultChecked,
112
- onChange
96
+ checked,
97
+ defaultChecked,
98
+ description,
99
+ error = false,
100
+ id,
101
+ inactive,
102
+ label,
103
+ name: inputName,
104
+ onChange,
105
+ tokens,
106
+ value,
107
+ variant,
108
+ ...rest
113
109
  },
114
- 'useRadioValue'
115
- )
116
- const getTokens = useThemeTokensCallback('Radio', tokens, {
117
- checked: isChecked,
118
- inactive,
119
- error,
120
- ...variant
121
- })
122
- const handleChange = () => {
123
- if (!inactive && !isChecked) {
124
- setIsChecked(true)
110
+ ref
111
+ ) => {
112
+ const { currentValue: isChecked, setValue: setIsChecked, isControlled } = useInputValue(
113
+ {
114
+ value: checked,
115
+ initialValue: defaultChecked,
116
+ onChange
117
+ },
118
+ 'useRadioValue'
119
+ )
120
+ const getTokens = useThemeTokensCallback('Radio', tokens, {
121
+ checked: isChecked,
122
+ inactive,
123
+ error,
124
+ ...variant
125
+ })
126
+ const handleChange = (event) => {
127
+ if (!inactive && !isChecked) {
128
+ setIsChecked(true, event)
129
+ }
125
130
  }
126
- }
127
- const handleKeyDown = (e) => {
128
- // The expected keyboard shortcut for activating a radio is the Space key
129
- if (e?.key === ' ') handleChange()
130
- }
131
- const accessibilityProps = a11yProps.select(rest)
132
- const uniqueId = useUniqueId('radio')
133
- const inputId = id ?? uniqueId
131
+ const handleKeyDown = (event) => {
132
+ // The expected keyboard shortcut for activating a radio is the Space key
133
+ if (event?.key === ' ') handleChange(event)
134
+ }
135
+ const accessibilityProps = a11yProps.select(rest)
136
+ const uniqueId = useUniqueId('radio')
137
+ const inputId = id ?? uniqueId
134
138
 
135
- return (
136
- <Pressable
137
- disabled={inactive}
138
- onKeyDown={handleKeyDown}
139
- onPress={handleChange}
140
- accessibilityRole="radio"
141
- accessibilityState={{ checked: isChecked, disabled: inactive }}
142
- {...accessibilityProps}
143
- >
144
- {({ focused: focus, hovered: hover, pressed }) => {
145
- const stateTokens = getTokens({ focus, hover, pressed })
139
+ return (
140
+ <Pressable
141
+ ref={ref}
142
+ disabled={inactive}
143
+ onKeyDown={handleKeyDown}
144
+ onPress={handleChange}
145
+ accessibilityRole="radio"
146
+ accessibilityState={{ checked: isChecked, disabled: inactive }}
147
+ {...accessibilityProps}
148
+ >
149
+ {({ focused: focus, hovered: hover, pressed }) => {
150
+ const stateTokens = getTokens({ focus, hover, pressed })
146
151
 
147
- return (
148
- <StackView space={0}>
149
- <View style={[staticStyles.container, selectContainerStyles(stateTokens)]}>
150
- <RadioButton
151
- tokens={selectRadioButtonTokens(stateTokens)}
152
- isControlled={isControlled}
153
- isChecked={isChecked}
154
- inactive={inactive}
155
- defaultChecked={defaultChecked}
156
- inputId={inputId}
157
- handleChange={handleChange}
158
- name={inputName}
159
- value={value}
160
- />
161
- {Boolean(label) && (
162
- <Text style={selectLabelStyles(stateTokens)}>
163
- <RadioLabel forId={inputId}>{label}</RadioLabel>
164
- </Text>
152
+ return (
153
+ <StackView space={0}>
154
+ <View style={[staticStyles.container, selectContainerStyles(stateTokens)]}>
155
+ <RadioButton
156
+ tokens={selectRadioButtonTokens(stateTokens)}
157
+ isControlled={isControlled}
158
+ isChecked={isChecked}
159
+ inactive={inactive}
160
+ defaultChecked={defaultChecked}
161
+ inputId={inputId}
162
+ handleChange={handleChange}
163
+ name={inputName}
164
+ value={value}
165
+ />
166
+ {Boolean(label) && (
167
+ <Text style={selectLabelStyles(stateTokens)}>
168
+ <RadioLabel forId={inputId}>{label}</RadioLabel>
169
+ </Text>
170
+ )}
171
+ </View>
172
+ {Boolean(description) && (
173
+ <Text style={selectDescriptionStyles(getTokens())}>{description}</Text>
165
174
  )}
166
- </View>
167
- {Boolean(description) && (
168
- <Text style={selectDescriptionStyles(getTokens())}>{description}</Text>
169
- )}
170
- </StackView>
171
- )
172
- }}
173
- </Pressable>
174
- )
175
- }
175
+ </StackView>
176
+ )
177
+ }}
178
+ </Pressable>
179
+ )
180
+ }
181
+ )
182
+ Radio.displayName = 'Radio'
176
183
 
177
184
  Radio.propTypes = {
178
185
  ...a11yProps.propTypes,
@@ -1,6 +1,6 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import PropTypes from 'prop-types'
3
- import { StyleSheet, View } from 'react-native'
3
+ import { Platform, StyleSheet, View } from 'react-native'
4
4
 
5
5
  import RadioInput from './RadioInput'
6
6
  import { applyOuterBorder, resolveThemeTokens, validateThemeTokens } from '../ThemeProvider'
@@ -47,11 +47,15 @@ const selectInputStyles = ({
47
47
  borderRadius: getBorderRadius(inputSize),
48
48
  borderWidth: inputBorderWidth,
49
49
  backgroundColor: inputBackgroundColor,
50
- outlineStyle: 'solid',
51
- outlineColor: inputOutlineColor,
52
- outlineWidth: inputOutlineWidth,
53
50
  height: inputSize,
54
- width: inputSize
51
+ width: inputSize,
52
+ ...Platform.select({
53
+ web: {
54
+ outlineStyle: 'solid',
55
+ outlineColor: inputOutlineColor,
56
+ outlineWidth: inputOutlineWidth
57
+ }
58
+ })
55
59
  })
56
60
 
57
61
  const selectOuterBorderStyles = ({
@@ -72,45 +76,52 @@ const selectOuterBorderStyles = ({
72
76
  * The visual toggle of a radio input. Is not interactive on its own, should be used inside
73
77
  * an interactive parent that passes down props when interacted with.
74
78
  */
75
- const RadioButton = ({
76
- isChecked,
77
- tokens,
78
- inactive,
79
- defaultChecked,
80
- inputId,
81
- isControlled,
82
- handleChange,
83
- name: inputName,
84
- value
85
- }) => {
86
- const themeTokens = validateThemeTokens(
87
- resolveThemeTokens(tokens, { checked: isChecked }),
88
- getTokensSetPropType(tokenKeys),
89
- 'RadioButton'
90
- )
79
+ const RadioButton = forwardRef(
80
+ (
81
+ {
82
+ isChecked,
83
+ tokens,
84
+ inactive,
85
+ defaultChecked,
86
+ inputId,
87
+ isControlled,
88
+ handleChange,
89
+ name: inputName,
90
+ value
91
+ },
92
+ ref
93
+ ) => {
94
+ const themeTokens = validateThemeTokens(
95
+ resolveThemeTokens(tokens, { checked: isChecked }),
96
+ getTokensSetPropType(tokenKeys),
97
+ 'RadioButton'
98
+ )
91
99
 
92
- return (
93
- <View style={selectOuterBorderStyles(themeTokens)}>
94
- <View
95
- style={[staticStyles.defaultInputStyles, selectInputStyles(themeTokens, isChecked)]}
96
- testID="Radio-Input"
97
- >
98
- {/* Add a real input on Web, skip on native platforms */}
99
- <RadioInput
100
- checked={isChecked}
101
- defaultChecked={defaultChecked}
102
- disabled={inactive}
103
- id={inputId}
104
- isControlled={isControlled}
105
- onChange={handleChange}
106
- name={inputName}
107
- value={value}
108
- />
109
- {isChecked && <View style={selectCheckedStyles(themeTokens)} testID="Radio-Checked" />}
100
+ return (
101
+ <View style={selectOuterBorderStyles(themeTokens)}>
102
+ <View
103
+ style={[staticStyles.defaultInputStyles, selectInputStyles(themeTokens, isChecked)]}
104
+ testID="Radio-Input"
105
+ >
106
+ {/* Add a real input on Web, skip on native platforms */}
107
+ <RadioInput
108
+ ref={ref}
109
+ checked={isChecked}
110
+ defaultChecked={defaultChecked}
111
+ disabled={inactive}
112
+ id={inputId}
113
+ isControlled={isControlled}
114
+ onChange={handleChange}
115
+ name={inputName}
116
+ value={value}
117
+ />
118
+ {isChecked && <View style={selectCheckedStyles(themeTokens)} testID="Radio-Checked" />}
119
+ </View>
110
120
  </View>
111
- </View>
112
- )
113
- }
121
+ )
122
+ }
123
+ )
124
+ RadioButton.displayName = 'RadioButton'
114
125
 
115
126
  RadioButton.propTypes = {
116
127
  isChecked: PropTypes.bool,