@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,5 +1,6 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import PropTypes from 'prop-types'
3
+ import ABBPropTypes from 'airbnb-prop-types'
3
4
 
4
5
  import { useViewport } from '../ViewportProvider'
5
6
  import { useThemeTokens } from '../ThemeProvider'
@@ -56,72 +57,81 @@ import Fieldset from '../Fieldset'
56
57
  * />
57
58
  * ```
58
59
  */
59
- const RadioGroup = ({
60
- tokens,
61
- radioTokens,
62
- variant,
63
- items = [],
64
- legend,
65
- tooltip,
66
- hint,
67
- validation,
68
- feedback,
69
- initialCheckedId,
70
- checkedId,
71
- onChange,
72
- readOnly,
73
- name: inputGroupName,
74
- inactive
75
- }) => {
76
- const viewport = useViewport()
60
+ const RadioGroup = forwardRef(
61
+ (
62
+ {
63
+ tokens,
64
+ radioTokens,
65
+ variant,
66
+ items = [],
67
+ legend,
68
+ tooltip,
69
+ hint,
70
+ validation,
71
+ feedback,
72
+ initialCheckedId,
73
+ checkedId,
74
+ onChange,
75
+ readOnly,
76
+ name: inputGroupName,
77
+ inactive
78
+ },
79
+ ref
80
+ ) => {
81
+ const viewport = useViewport()
77
82
 
78
- const { space, fieldSpace } = useThemeTokens('RadioGroup', tokens, variant, {
79
- viewport
80
- })
83
+ const { space, fieldSpace } = useThemeTokens('RadioGroup', tokens, variant, {
84
+ viewport
85
+ })
86
+
87
+ const { currentValue, setValue } = useInputValue({
88
+ value: checkedId,
89
+ initialValue: initialCheckedId,
90
+ onChange,
91
+ readOnly: readOnly || inactive
92
+ })
93
+ const radios = items.map(({ label, id, onChange: itemOnChange, ref: itemRef }, index) => {
94
+ const radioId = id || `Radio[${index}]`
95
+ const isChecked = currentValue === radioId
96
+ const handleChange = (newCheckedState, event) => {
97
+ if (typeof itemOnChange === 'function') itemOnChange(newCheckedState, event)
98
+ if (newCheckedState) setValue(radioId, event)
99
+ }
100
+ return (
101
+ <Radio
102
+ ref={itemRef}
103
+ key={radioId}
104
+ id={radioId}
105
+ checked={isChecked}
106
+ onChange={handleChange}
107
+ inactive={inactive}
108
+ label={label}
109
+ name={inputGroupName}
110
+ tokens={radioTokens}
111
+ variant={variant}
112
+ />
113
+ )
114
+ })
81
115
 
82
- const { currentValue, setValue } = useInputValue({
83
- value: checkedId,
84
- initialValue: initialCheckedId,
85
- onChange,
86
- readOnly: readOnly || inactive
87
- })
88
- const radios = items.map(({ label, id, onChange: itemOnChange }, index) => {
89
- const radioId = id || `Radio[${index}]`
90
- const handleChange = (...args) => {
91
- if (typeof itemOnChange === 'function') itemOnChange(...args)
92
- setValue(radioId)
93
- }
94
116
  return (
95
- <Radio
96
- key={radioId}
97
- id={radioId}
98
- checked={currentValue === radioId}
99
- onChange={handleChange}
100
- inactive={inactive}
101
- label={label}
117
+ <Fieldset
118
+ ref={ref}
102
119
  name={inputGroupName}
103
- tokens={radioTokens}
104
- variant={variant}
105
- />
120
+ legend={legend}
121
+ tooltip={tooltip}
122
+ hint={hint}
123
+ space={fieldSpace}
124
+ feedback={feedback}
125
+ inactive={inactive}
126
+ validation={validation}
127
+ accessibilityRole="radiogroup"
128
+ >
129
+ {getStackedContent(radios, { space, direction: 'column' })}
130
+ </Fieldset>
106
131
  )
107
- })
108
-
109
- return (
110
- <Fieldset
111
- name={inputGroupName}
112
- legend={legend}
113
- tooltip={tooltip}
114
- hint={hint}
115
- space={fieldSpace}
116
- feedback={feedback}
117
- inactive={inactive}
118
- status={validation}
119
- accessibilityRole="radiogroup"
120
- >
121
- {getStackedContent(radios, { space, direction: 'column' })}
122
- </Fieldset>
123
- )
124
- }
132
+ }
133
+ )
134
+ RadioGroup.displayName = 'RadioGroup'
125
135
 
126
136
  RadioGroup.propTypes = {
127
137
  /**
@@ -143,7 +153,8 @@ RadioGroup.propTypes = {
143
153
  PropTypes.exact({
144
154
  label: PropTypes.string,
145
155
  id: PropTypes.string,
146
- onChange: PropTypes.func
156
+ onChange: PropTypes.func,
157
+ ref: ABBPropTypes.ref()
147
158
  })
148
159
  ),
149
160
  /**
@@ -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 { StyleSheet, Text, View } from 'react-native'
4
4
 
@@ -50,77 +50,84 @@ import RadioButton, { selectRadioButtonTokens } from '../Radio/RadioButton'
50
50
  * accessibility role `'radio'` and accessibility state that depends on the other props (`checked`, `inactive`)
51
51
  * or the internal state in case of uncontrolled radio button.
52
52
  */
53
- const RadioCard = ({
54
- tokens,
55
- variant,
56
- title,
57
- children,
58
- inactive,
59
- defaultChecked,
60
- checked,
61
- name: inputName,
62
- value,
63
- id,
64
- onChange,
65
- ...rest
66
- }) => {
67
- const { currentValue: isChecked, setValue: setIsChecked, isControlled } = useInputValue({
68
- value: checked,
69
- initialValue: defaultChecked,
70
- onChange
71
- })
72
- const handleChange = () => {
73
- if (!inactive && !isChecked) {
74
- setIsChecked(true)
53
+ const RadioCard = forwardRef(
54
+ (
55
+ {
56
+ tokens,
57
+ variant,
58
+ title,
59
+ children,
60
+ inactive,
61
+ defaultChecked,
62
+ checked,
63
+ name: inputName,
64
+ value,
65
+ id,
66
+ onChange,
67
+ ...rest
68
+ },
69
+ ref
70
+ ) => {
71
+ const { currentValue: isChecked, setValue: setIsChecked, isControlled } = useInputValue({
72
+ value: checked,
73
+ initialValue: defaultChecked,
74
+ onChange
75
+ })
76
+ const handleChange = (event) => {
77
+ if (!inactive && !isChecked) {
78
+ setIsChecked(true, event)
79
+ }
75
80
  }
76
- }
77
- const a11y = a11yProps.select(rest)
78
- const uniqueId = useUniqueId('RadioCard')
79
- const inputId = id ?? uniqueId
81
+ const a11y = a11yProps.select(rest)
82
+ const uniqueId = useUniqueId('RadioCard')
83
+ const inputId = id ?? uniqueId
80
84
 
81
- const getTokens = useThemeTokensCallback('RadioCard', tokens, variant)
82
- const getCardTokens = (cardState) => selectPressableCardTokens(getTokens(cardState))
85
+ const getTokens = useThemeTokensCallback('RadioCard', tokens, variant)
86
+ const getCardTokens = (cardState) => selectPressableCardTokens(getTokens(cardState))
83
87
 
84
- return (
85
- <PressableCardBase
86
- inactive={inactive}
87
- checked={isChecked}
88
- tokens={getCardTokens}
89
- onPress={handleChange}
90
- accessibilityRole="radio"
91
- accessibilityState={{ checked: isChecked, disabled: inactive }}
92
- {...a11y}
93
- >
94
- {(cardState) => {
95
- const { radioSpace, contentSpace, ...themeTokens } = getTokens(cardState)
96
- const radioTokens = selectRadioButtonTokens(themeTokens, 'radio')
97
- const titleTokens = selectTokens('Typography', themeTokens)
98
- const textStyle = applyTextStyles(titleTokens)
99
- return (
100
- <StackView direction="row" space={radioSpace}>
101
- <View style={[staticStyles.alignWithText, { height: textStyle.lineHeight }]}>
102
- <RadioButton
103
- tokens={radioTokens}
104
- isControlled={isControlled}
105
- isChecked={isChecked}
106
- inactive={inactive}
107
- defaultChecked={defaultChecked}
108
- inputId={inputId}
109
- handleChange={handleChange}
110
- name={inputName}
111
- value={value}
112
- />
113
- </View>
114
- <StackView direction="column" space={contentSpace}>
115
- {title && <Text style={textStyle}>{title}</Text>}
116
- {typeof children === 'function' ? children(cardState, textStyle) : children}
88
+ return (
89
+ <PressableCardBase
90
+ ref={ref}
91
+ inactive={inactive}
92
+ checked={isChecked}
93
+ tokens={getCardTokens}
94
+ onPress={handleChange}
95
+ accessibilityRole="radio"
96
+ accessibilityState={{ checked: isChecked, disabled: inactive }}
97
+ {...a11y}
98
+ >
99
+ {(cardState) => {
100
+ const { radioSpace, contentSpace, ...themeTokens } = getTokens(cardState)
101
+ const radioTokens = selectRadioButtonTokens(themeTokens, 'radio')
102
+ const titleTokens = selectTokens('Typography', themeTokens)
103
+ const textStyle = applyTextStyles(titleTokens)
104
+ return (
105
+ <StackView direction="row" space={radioSpace}>
106
+ <View style={[staticStyles.alignWithText, { height: textStyle.lineHeight }]}>
107
+ <RadioButton
108
+ tokens={radioTokens}
109
+ isControlled={isControlled}
110
+ isChecked={isChecked}
111
+ inactive={inactive}
112
+ defaultChecked={defaultChecked}
113
+ inputId={inputId}
114
+ handleChange={handleChange}
115
+ name={inputName}
116
+ value={value}
117
+ />
118
+ </View>
119
+ <StackView direction="column" space={contentSpace} tokens={{ flexShrink: 1 }}>
120
+ {title && <Text style={textStyle}>{title}</Text>}
121
+ {typeof children === 'function' ? children(cardState, textStyle) : children}
122
+ </StackView>
117
123
  </StackView>
118
- </StackView>
119
- )
120
- }}
121
- </PressableCardBase>
122
- )
123
- }
124
+ )
125
+ }}
126
+ </PressableCardBase>
127
+ )
128
+ }
129
+ )
130
+ RadioCard.displayName = 'RadioCard'
124
131
 
125
132
  RadioCard.propTypes = {
126
133
  ...a11yProps.propTypes,
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
 
4
4
  import { useViewport } from '../ViewportProvider'
@@ -58,82 +58,89 @@ import Fieldset from '../Fieldset'
58
58
  * />
59
59
  * ```
60
60
  */
61
- const RadioCardGroup = ({
62
- tokens,
63
- radioCardTokens,
64
- variant,
65
- items = [],
66
- legend,
67
- tooltip,
68
- hint,
69
- validation,
70
- feedback,
71
- initialCheckedId,
72
- checkedId,
73
- onChange,
74
- readOnly,
75
- name: inputGroupName,
76
- inactive
77
- }) => {
78
- const viewport = useViewport()
79
- const { space, fieldSpace, direction } = useThemeTokens('RadioCardGroup', tokens, variant, {
80
- viewport
81
- })
61
+ const RadioCardGroup = forwardRef(
62
+ (
63
+ {
64
+ tokens,
65
+ radioCardTokens,
66
+ variant,
67
+ items = [],
68
+ legend,
69
+ tooltip,
70
+ hint,
71
+ validation,
72
+ feedback,
73
+ initialCheckedId,
74
+ checkedId,
75
+ onChange,
76
+ readOnly,
77
+ name: inputGroupName,
78
+ inactive
79
+ },
80
+ ref
81
+ ) => {
82
+ const viewport = useViewport()
83
+ const { space, fieldSpace, direction } = useThemeTokens('RadioCardGroup', tokens, variant, {
84
+ viewport
85
+ })
82
86
 
83
- const { currentValue, setValue } = useInputValue({
84
- value: checkedId,
85
- initialValue: initialCheckedId,
86
- onChange,
87
- readOnly: readOnly || inactive
88
- })
87
+ const { currentValue, setValue } = useInputValue({
88
+ value: checkedId,
89
+ initialValue: initialCheckedId,
90
+ onChange,
91
+ readOnly: readOnly || inactive
92
+ })
89
93
 
90
- const StackContainer = direction === 'row' ? StackWrap : StackView
91
- // Needs 'radiogroup' role on direct parent of radios for MacOS Voiceover's numbering to work,
92
- // and also needs 'radiogroup' role on fieldset for correct description on focusing the set.
93
- // TODO: test this on more web screen readers.
94
- return (
95
- <Fieldset
96
- name={inputGroupName}
97
- legend={legend}
98
- tooltip={tooltip}
99
- hint={hint}
100
- space={fieldSpace}
101
- feedback={feedback}
102
- inactive={inactive || readOnly}
103
- status={validation}
104
- accessibilityRole="radiogroup"
105
- >
106
- {({ a11yProps }) => (
107
- <StackContainer space={space} accessibilityRole="radiogroup">
108
- {items.map(({ title, content, id, onChange: itemOnChange }, index) => {
109
- const cardId = id || `RadioCard[${index}]`
110
- const handleChange = (...args) => {
111
- if (typeof itemOnChange === 'function') itemOnChange(...args)
112
- setValue(cardId)
113
- }
114
- return (
115
- <RadioCard
116
- key={cardId}
117
- id={cardId}
118
- checked={currentValue === cardId}
119
- onChange={handleChange}
120
- inactive={inactive}
121
- title={title}
122
- name={inputGroupName}
123
- tokens={radioCardTokens}
124
- variant={variant}
125
- readOnly={readOnly}
126
- {...a11yProps}
127
- >
128
- {content}
129
- </RadioCard>
130
- )
131
- })}
132
- </StackContainer>
133
- )}
134
- </Fieldset>
135
- )
136
- }
94
+ const StackContainer = direction === 'row' ? StackWrap : StackView
95
+ // Needs 'radiogroup' role on direct parent of radios for MacOS Voiceover's numbering to work,
96
+ // and also needs 'radiogroup' role on fieldset for correct description on focusing the set.
97
+ // TODO: test this on more web screen readers.
98
+ return (
99
+ <Fieldset
100
+ ref={ref}
101
+ name={inputGroupName}
102
+ legend={legend}
103
+ tooltip={tooltip}
104
+ hint={hint}
105
+ space={fieldSpace}
106
+ feedback={feedback}
107
+ inactive={inactive || readOnly}
108
+ validation={validation}
109
+ accessibilityRole="radiogroup"
110
+ >
111
+ {({ a11yProps }) => (
112
+ <StackContainer space={space} accessibilityRole="radiogroup">
113
+ {items.map(({ title, content, id, onChange: itemOnChange }, index) => {
114
+ const cardId = id || `RadioCard[${index}]`
115
+ const handleChange = (newCheckedState, event) => {
116
+ if (typeof itemOnChange === 'function') itemOnChange(newCheckedState, event)
117
+ if (newCheckedState) setValue(cardId, event)
118
+ }
119
+ return (
120
+ <RadioCard
121
+ key={cardId}
122
+ id={cardId}
123
+ checked={currentValue === cardId}
124
+ onChange={handleChange}
125
+ inactive={inactive}
126
+ title={title}
127
+ name={inputGroupName}
128
+ tokens={radioCardTokens}
129
+ variant={variant}
130
+ readOnly={readOnly}
131
+ {...a11yProps}
132
+ >
133
+ {content}
134
+ </RadioCard>
135
+ )
136
+ })}
137
+ </StackContainer>
138
+ )}
139
+ </Fieldset>
140
+ )
141
+ }
142
+ )
143
+ RadioCardGroup.displayName = 'RadioCardGroup'
137
144
 
138
145
  RadioCardGroup.propTypes = {
139
146
  /**