@telus-uds/components-base 0.0.2-prerelease.9 → 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 (282) hide show
  1. package/.eslintrc.js +9 -0
  2. package/.ultra.cache.json +1 -1
  3. package/CHANGELOG.md +32 -0
  4. package/README.md +4 -2
  5. package/__fixtures__/test-utils.js +25 -0
  6. package/__fixtures__/testTheme.js +4 -2
  7. package/__tests__/Button/ButtonGroup.test.jsx +4 -5
  8. package/__tests__/Checkbox/Checkbox.test.jsx +2 -2
  9. package/__tests__/Checkbox/CheckboxGroup.test.jsx +4 -5
  10. package/__tests__/ExpandCollapse/ExpandCollapse.test.jsx +2 -2
  11. package/__tests__/HorizontalScroll/HorizontalScroll.test.jsx +164 -0
  12. package/__tests__/Link/LinkBase.test.jsx +0 -14
  13. package/__tests__/Radio/Radio.test.jsx +2 -2
  14. package/__tests__/Radio/RadioGroup.test.jsx +4 -5
  15. package/__tests__/RadioCard/RadioCard.test.jsx +2 -2
  16. package/__tests__/RadioCard/RadioCardGroup.test.jsx +4 -5
  17. package/__tests__/Search/Search.test.jsx +9 -8
  18. package/__tests__/Select/Select.test.jsx +3 -2
  19. package/__tests__/Tabs/Tabs.test.jsx +1 -161
  20. package/__tests__/Tags/Tags.test.jsx +4 -5
  21. package/__tests__/TextInput/TextArea.test.jsx +3 -2
  22. package/__tests__/TextInput/TextInputBase.test.jsx +10 -5
  23. package/__tests__/ThemeProvider/ThemeProvider.test.jsx +77 -0
  24. package/__tests__/ThemeProvider/useThemeTokens.test.jsx +9 -5
  25. package/__tests__/ThemeProvider/utils/theme-tokens.test.js +41 -0
  26. package/__tests__/ToggleSwitch/ToggleSwitch.test.jsx +3 -2
  27. package/__tests__/utils/children.test.jsx +128 -0
  28. package/__tests__/utils/input.test.js +1 -1
  29. package/__tests__/utils/semantics.test.jsx +43 -0
  30. package/lib/A11yText/index.js +10 -5
  31. package/lib/ActivityIndicator/Spinner.js +16 -13
  32. package/lib/ActivityIndicator/Spinner.native.js +12 -8
  33. package/lib/Box/Box.js +102 -8
  34. package/lib/Button/Button.js +9 -8
  35. package/lib/Button/ButtonBase.js +14 -7
  36. package/lib/Button/ButtonGroup.js +25 -10
  37. package/lib/Button/ButtonLink.js +10 -7
  38. package/lib/Card/Card.js +2 -0
  39. package/lib/Card/CardBase.js +12 -5
  40. package/lib/Card/PressableCardBase.js +12 -8
  41. package/lib/Checkbox/Checkbox.js +25 -14
  42. package/lib/Checkbox/CheckboxGroup.js +22 -12
  43. package/lib/Divider/Divider.js +12 -7
  44. package/lib/ExpandCollapse/Accordion.js +10 -4
  45. package/lib/ExpandCollapse/Control.js +12 -6
  46. package/lib/ExpandCollapse/ExpandCollapse.js +10 -5
  47. package/lib/ExpandCollapse/Panel.js +8 -7
  48. package/lib/Feedback/Feedback.js +10 -5
  49. package/lib/Fieldset/Fieldset.js +10 -5
  50. package/lib/Fieldset/FieldsetContainer.js +10 -5
  51. package/lib/Fieldset/FieldsetContainer.native.js +10 -5
  52. package/lib/Fieldset/Legend.js +10 -5
  53. package/lib/Fieldset/Legend.native.js +10 -5
  54. package/lib/FlexGrid/Col/Col.js +8 -5
  55. package/lib/FlexGrid/FlexGrid.js +31 -6
  56. package/lib/FlexGrid/Row/Row.js +12 -5
  57. package/lib/{Tabs → HorizontalScroll}/HorizontalScroll.js +5 -4
  58. package/lib/{Tabs/TabsScrollButton.js → HorizontalScroll/HorizontalScrollButton.js} +14 -8
  59. package/lib/{Tabs → HorizontalScroll}/ScrollViewEnd.js +0 -0
  60. package/lib/{Tabs → HorizontalScroll}/ScrollViewEnd.native.js +0 -0
  61. package/lib/{Tabs → HorizontalScroll}/dictionary.js +0 -0
  62. package/lib/HorizontalScroll/index.js +35 -0
  63. package/lib/{Tabs → HorizontalScroll}/itemPositions.js +0 -0
  64. package/lib/Icon/Icon.js +16 -9
  65. package/lib/Icon/IconText.js +8 -7
  66. package/lib/IconButton/IconButton.js +10 -5
  67. package/lib/InputLabel/InputLabel.js +33 -5
  68. package/lib/InputLabel/LabelContent.js +22 -12
  69. package/lib/InputLabel/LabelContent.native.js +23 -5
  70. package/lib/InputSupports/InputSupports.js +10 -5
  71. package/lib/Link/ChevronLink.js +12 -5
  72. package/lib/Link/InlinePressable.js +10 -4
  73. package/lib/Link/InlinePressable.native.js +5 -4
  74. package/lib/Link/Link.js +12 -5
  75. package/lib/Link/LinkBase.js +12 -5
  76. package/lib/Link/TextButton.js +10 -5
  77. package/lib/List/List.js +5 -4
  78. package/lib/List/ListItem.js +16 -8
  79. package/lib/Modal/Modal.js +10 -5
  80. package/lib/Notification/Notification.js +21 -5
  81. package/lib/Pagination/PageButton.js +21 -10
  82. package/lib/Pagination/Pagination.js +12 -7
  83. package/lib/Pagination/SideButton.js +12 -7
  84. package/lib/Pagination/usePagination.js +2 -2
  85. package/lib/Progress/Progress.js +10 -5
  86. package/lib/Progress/ProgressBar.js +21 -10
  87. package/lib/Progress/ProgressBarBackground.js +12 -8
  88. package/lib/Radio/Radio.js +14 -13
  89. package/lib/Radio/RadioButton.js +20 -9
  90. package/lib/Radio/RadioGroup.js +24 -13
  91. package/lib/RadioCard/RadioCard.js +14 -10
  92. package/lib/RadioCard/RadioCardGroup.js +13 -12
  93. package/lib/Search/Search.js +29 -18
  94. package/lib/Select/Picker.js +11 -6
  95. package/lib/Select/Picker.native.js +21 -6
  96. package/lib/Select/Select.js +46 -4
  97. package/lib/SideNav/Item.js +10 -5
  98. package/lib/SideNav/ItemsGroup.js +10 -5
  99. package/lib/SideNav/SideNav.js +11 -7
  100. package/lib/Skeleton/Skeleton.js +15 -15
  101. package/lib/Skeleton/skeletonWebAnimation.js +1 -1
  102. package/lib/Spacer/Spacer.js +19 -7
  103. package/lib/StackView/StackView.js +25 -7
  104. package/lib/StackView/StackWrap.js +16 -9
  105. package/lib/StackView/StackWrapBox.js +33 -8
  106. package/lib/StackView/StackWrapGap.js +16 -7
  107. package/lib/StackView/common.js +4 -2
  108. package/lib/StackView/getStackedContent.js +2 -2
  109. package/lib/StepTracker/StepTracker.js +10 -5
  110. package/lib/Tabs/Tabs.js +26 -19
  111. package/lib/Tabs/TabsItem.js +16 -12
  112. package/lib/Tags/Tags.js +27 -11
  113. package/lib/TextInput/TextArea.js +7 -5
  114. package/lib/TextInput/TextInput.js +12 -6
  115. package/lib/TextInput/TextInputBase.js +12 -8
  116. package/lib/ThemeProvider/ThemeProvider.js +14 -10
  117. package/lib/ThemeProvider/useSetTheme.js +6 -1
  118. package/lib/ThemeProvider/utils/styles.js +2 -2
  119. package/lib/ThemeProvider/utils/theme-tokens.js +39 -8
  120. package/lib/ToggleSwitch/ToggleSwitch.js +11 -6
  121. package/lib/Tooltip/Backdrop.js +10 -2
  122. package/lib/Tooltip/Tooltip.js +5 -4
  123. package/lib/Typography/Typography.js +40 -24
  124. package/lib/index.js +21 -0
  125. package/lib/utils/a11y/index.js +13 -0
  126. package/lib/utils/a11y/semantics.js +173 -0
  127. package/lib/utils/animation/useVerticalExpandAnimation.js +1 -1
  128. package/lib/utils/children.js +55 -8
  129. package/lib/utils/input.js +27 -17
  130. package/lib/utils/propTypes.js +82 -29
  131. package/lib/utils/useCopy.js +1 -1
  132. package/lib/utils/useHash.js +8 -4
  133. package/lib/utils/useSpacingScale.js +1 -3
  134. package/lib/utils/useUniqueId.js +1 -1
  135. package/package.json +9 -5
  136. package/release-context.json +4 -4
  137. package/src/A11yText/index.jsx +6 -4
  138. package/src/ActivityIndicator/Spinner.jsx +5 -3
  139. package/src/ActivityIndicator/Spinner.native.jsx +5 -3
  140. package/src/Box/Box.jsx +124 -39
  141. package/src/Button/Button.jsx +7 -4
  142. package/src/Button/ButtonBase.jsx +86 -77
  143. package/src/Button/ButtonGroup.jsx +81 -69
  144. package/src/Button/ButtonLink.jsx +18 -13
  145. package/src/Card/Card.jsx +2 -2
  146. package/src/Card/CardBase.jsx +5 -4
  147. package/src/Card/PressableCardBase.jsx +71 -64
  148. package/src/Checkbox/Checkbox.jsx +118 -108
  149. package/src/Checkbox/CheckboxGroup.jsx +72 -62
  150. package/src/Divider/Divider.jsx +7 -4
  151. package/src/ExpandCollapse/Accordion.jsx +3 -2
  152. package/src/ExpandCollapse/Control.jsx +40 -43
  153. package/src/ExpandCollapse/ExpandCollapse.jsx +26 -23
  154. package/src/ExpandCollapse/Panel.jsx +69 -63
  155. package/src/Feedback/Feedback.jsx +36 -33
  156. package/src/Fieldset/Fieldset.jsx +63 -56
  157. package/src/Fieldset/FieldsetContainer.jsx +14 -5
  158. package/src/Fieldset/FieldsetContainer.native.jsx +7 -4
  159. package/src/Fieldset/Legend.jsx +7 -2
  160. package/src/Fieldset/Legend.native.jsx +7 -2
  161. package/src/FlexGrid/Col/Col.jsx +139 -132
  162. package/src/FlexGrid/FlexGrid.jsx +79 -51
  163. package/src/FlexGrid/Row/Row.jsx +55 -48
  164. package/src/HorizontalScroll/HorizontalScroll.jsx +168 -0
  165. package/src/HorizontalScroll/HorizontalScrollButton.jsx +105 -0
  166. package/src/{Tabs → HorizontalScroll}/ScrollViewEnd.jsx +0 -0
  167. package/src/{Tabs → HorizontalScroll}/ScrollViewEnd.native.jsx +0 -0
  168. package/src/{Tabs → HorizontalScroll}/dictionary.js +0 -0
  169. package/src/HorizontalScroll/index.js +17 -0
  170. package/src/{Tabs → HorizontalScroll}/itemPositions.js +0 -0
  171. package/src/Icon/Icon.jsx +37 -35
  172. package/src/Icon/IconText.jsx +22 -17
  173. package/src/IconButton/IconButton.jsx +49 -42
  174. package/src/InputLabel/InputLabel.jsx +53 -38
  175. package/src/InputLabel/LabelContent.jsx +14 -6
  176. package/src/InputLabel/LabelContent.native.jsx +11 -2
  177. package/src/InputSupports/InputSupports.jsx +29 -34
  178. package/src/Link/ChevronLink.jsx +26 -16
  179. package/src/Link/InlinePressable.jsx +5 -3
  180. package/src/Link/InlinePressable.native.jsx +5 -3
  181. package/src/Link/Link.jsx +22 -16
  182. package/src/Link/LinkBase.jsx +67 -58
  183. package/src/Link/TextButton.jsx +30 -23
  184. package/src/List/List.jsx +5 -4
  185. package/src/List/ListItem.jsx +77 -82
  186. package/src/Modal/Modal.jsx +9 -4
  187. package/src/Notification/Notification.jsx +58 -43
  188. package/src/Pagination/PageButton.jsx +42 -35
  189. package/src/Pagination/Pagination.jsx +88 -92
  190. package/src/Pagination/SideButton.jsx +44 -41
  191. package/src/Progress/Progress.jsx +5 -4
  192. package/src/Progress/ProgressBar.jsx +42 -29
  193. package/src/Progress/ProgressBarBackground.jsx +5 -3
  194. package/src/Radio/Radio.jsx +85 -78
  195. package/src/Radio/RadioButton.jsx +54 -43
  196. package/src/Radio/RadioGroup.jsx +74 -63
  197. package/src/RadioCard/RadioCard.jsx +75 -68
  198. package/src/RadioCard/RadioCardGroup.jsx +82 -75
  199. package/src/Search/Search.jsx +127 -106
  200. package/src/Select/Picker.jsx +49 -42
  201. package/src/Select/Picker.native.jsx +56 -49
  202. package/src/Select/Select.jsx +115 -72
  203. package/src/SideNav/Item.jsx +53 -46
  204. package/src/SideNav/ItemsGroup.jsx +50 -43
  205. package/src/SideNav/SideNav.jsx +68 -60
  206. package/src/Skeleton/Skeleton.jsx +9 -13
  207. package/src/Spacer/Spacer.jsx +11 -4
  208. package/src/StackView/StackView.jsx +46 -23
  209. package/src/StackView/StackWrap.jsx +7 -6
  210. package/src/StackView/StackWrapBox.jsx +61 -28
  211. package/src/StackView/StackWrapGap.jsx +46 -24
  212. package/src/StackView/common.jsx +3 -2
  213. package/src/StepTracker/StepTracker.jsx +73 -62
  214. package/src/Tabs/Tabs.jsx +70 -62
  215. package/src/Tabs/TabsItem.jsx +111 -103
  216. package/src/Tags/Tags.jsx +114 -102
  217. package/src/TextInput/TextArea.jsx +5 -4
  218. package/src/TextInput/TextInput.jsx +5 -4
  219. package/src/TextInput/TextInputBase.jsx +84 -77
  220. package/src/ThemeProvider/ThemeProvider.jsx +11 -7
  221. package/src/ThemeProvider/useSetTheme.js +4 -0
  222. package/src/ThemeProvider/utils/theme-tokens.js +28 -0
  223. package/src/ToggleSwitch/ToggleSwitch.jsx +49 -50
  224. package/src/Tooltip/Tooltip.jsx +134 -130
  225. package/src/Typography/Typography.jsx +67 -44
  226. package/src/index.js +2 -0
  227. package/src/utils/a11y/index.js +1 -0
  228. package/src/utils/a11y/semantics.js +162 -0
  229. package/src/utils/children.jsx +60 -7
  230. package/src/utils/input.js +20 -17
  231. package/src/utils/propTypes.js +101 -39
  232. package/src/utils/useCopy.js +1 -1
  233. package/src/utils/useHash.js +8 -3
  234. package/stories/A11yText/A11yText.stories.jsx +2 -2
  235. package/stories/ActivityIndicator/ActivityIndicator.stories.jsx +1 -1
  236. package/stories/Box/Box.stories.jsx +1 -1
  237. package/stories/Button/Button.stories.jsx +2 -2
  238. package/stories/Button/ButtonGroup.stories.jsx +1 -1
  239. package/stories/Button/ButtonLink.stories.jsx +1 -1
  240. package/stories/Card/Card.stories.jsx +1 -1
  241. package/stories/Checkbox/Checkbox.stories.jsx +1 -1
  242. package/stories/Divider/Divider.stories.jsx +1 -1
  243. package/stories/ExpandCollapse/ExpandCollapse.stories.jsx +2 -2
  244. package/stories/Feedback/Feedback.stories.jsx +1 -1
  245. package/stories/FlexGrid/01 FlexGrid.stories.jsx +1 -1
  246. package/stories/FlexGrid/02 Row.stories.jsx +1 -1
  247. package/stories/FlexGrid/03 Col.stories.jsx +1 -1
  248. package/stories/Icon/Icon.stories.jsx +1 -1
  249. package/stories/IconButton/IconButton.stories.jsx +1 -1
  250. package/stories/InputLabel/InputLabel.stories.jsx +1 -1
  251. package/stories/Link/ChevronLink.stories.jsx +1 -1
  252. package/stories/Link/Link.stories.jsx +1 -1
  253. package/stories/Link/TextButton.stories.jsx +1 -1
  254. package/stories/List/List.stories.jsx +1 -1
  255. package/stories/Modal/Modal.stories.jsx +1 -1
  256. package/stories/Notification/Notification.stories.jsx +1 -1
  257. package/stories/Pagination/Pagination.stories.jsx +1 -1
  258. package/stories/Progress/Progress.stories.jsx +1 -1
  259. package/stories/Radio/Radio.stories.jsx +1 -1
  260. package/stories/RadioCard/RadioCard.stories.jsx +1 -1
  261. package/stories/Search/Search.stories.jsx +1 -1
  262. package/stories/Select/Select.stories.jsx +1 -1
  263. package/stories/SideNav/SideNav.stories.jsx +1 -1
  264. package/stories/SideNav/SideNavItem.stories.jsx +1 -1
  265. package/stories/SideNav/SideNavItemsGroup.stories.jsx +1 -1
  266. package/stories/Skeleton/Skeleton.stories.jsx +2 -2
  267. package/stories/Spacer/Spacer.stories.jsx +1 -1
  268. package/stories/StackView/StackView.stories.jsx +1 -1
  269. package/stories/StackView/StackWrap.stories.jsx +1 -1
  270. package/stories/StepTracker/StepTracker.stories.jsx +1 -1
  271. package/stories/Tabs/Tabs.stories.jsx +1 -1
  272. package/stories/Tags/Tags.stories.jsx +1 -1
  273. package/stories/TextInput/TextArea.stories.jsx +1 -1
  274. package/stories/TextInput/TextInput.stories.jsx +1 -1
  275. package/stories/ToggleSwitch/ToggleSwitch.stories.jsx +1 -1
  276. package/stories/Tooltip/Tooltip.stories.jsx +1 -1
  277. package/stories/TooltipButton/TooltipButton.stories.jsx +1 -1
  278. package/stories/Typography/Typography.stories.jsx +1 -1
  279. package/stories/platform-supports.jsx +1 -1
  280. package/stories/supports.jsx +2 -2
  281. package/src/Tabs/HorizontalScroll.jsx +0 -165
  282. package/src/Tabs/TabsScrollButton.jsx +0 -100
@@ -1,6 +1,6 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import PropTypes from 'prop-types'
3
- import { Pressable, StyleSheet, Text, View } from 'react-native'
3
+ import { Platform, Pressable, StyleSheet, Text, View } from 'react-native'
4
4
 
5
5
  import CheckboxInput from './CheckboxInput'
6
6
  // @todo move `LabelContent` outside of the `InputLabel` and fix
@@ -32,12 +32,16 @@ const selectInputStyles = (
32
32
  borderWidth: inputBorderWidth,
33
33
  borderRadius: inputBorderRadius,
34
34
  backgroundColor: isChecked ? iconBackgroundColor : inputBackgroundColor,
35
- outlineStyle: 'solid',
36
- outlineColor: inputOutlineColor,
37
- outlineWidth: inputOutlineWidth,
38
35
  height: inputHeight,
39
36
  width: inputWidth,
40
- ...applyShadowToken(inputShadow)
37
+ ...applyShadowToken(inputShadow),
38
+ ...Platform.select({
39
+ web: {
40
+ outlineStyle: 'solid',
41
+ outlineColor: inputOutlineColor,
42
+ outlineWidth: inputOutlineWidth
43
+ }
44
+ })
41
45
  })
42
46
  const selectLabelStyles = ({
43
47
  labelColor,
@@ -103,115 +107,121 @@ const selectFeedbackTokens = ({ feedbackMarginBottom, feedbackMarginTop, feedbac
103
107
  * or the internal state in case of uncontrolled checkbox.
104
108
  *
105
109
  */
106
- const Checkbox = ({
107
- checked,
108
- defaultChecked,
109
- error = false,
110
- feedback,
111
- id,
112
- inactive,
113
- label,
114
- name,
115
- onChange,
116
- tokens,
117
- value,
118
- variant,
119
- ...rest
120
- }) => {
121
- const { currentValue: isChecked, setValue: setIsChecked, isControlled } = useInputValue(
110
+ const Checkbox = forwardRef(
111
+ (
122
112
  {
123
- value: checked,
124
- initialValue: defaultChecked,
125
- onChange
113
+ checked,
114
+ defaultChecked,
115
+ error = false,
116
+ feedback,
117
+ id,
118
+ inactive,
119
+ label,
120
+ name,
121
+ onChange,
122
+ tokens,
123
+ value,
124
+ variant,
125
+ ...rest
126
126
  },
127
- 'useCheckboxValue'
128
- )
129
- const getTokens = useThemeTokensCallback('Checkbox', tokens, {
130
- checked: isChecked,
131
- inactive,
132
- error,
133
- ...variant
134
- })
135
- const defaultTokens = getTokens()
136
- const { feedbackMarginBottom, feedbackMarginTop, feedbackPosition } = selectFeedbackTokens(
137
- defaultTokens
138
- )
139
- const styles = StyleSheet.create({
140
- feedbackContainer: { marginTop: feedbackMarginTop, marginBottom: feedbackMarginBottom }
141
- })
142
- const handleChange = () => {
143
- if (!inactive) {
144
- setIsChecked(!isChecked)
127
+ ref
128
+ ) => {
129
+ const { currentValue: isChecked, setValue: setIsChecked, isControlled } = useInputValue(
130
+ {
131
+ value: checked,
132
+ initialValue: defaultChecked,
133
+ onChange
134
+ },
135
+ 'useCheckboxValue'
136
+ )
137
+ const getTokens = useThemeTokensCallback('Checkbox', tokens, {
138
+ checked: isChecked,
139
+ inactive,
140
+ error,
141
+ ...variant
142
+ })
143
+ const defaultTokens = getTokens()
144
+ const { feedbackMarginBottom, feedbackMarginTop, feedbackPosition } = selectFeedbackTokens(
145
+ defaultTokens
146
+ )
147
+ const styles = StyleSheet.create({
148
+ feedbackContainer: { marginTop: feedbackMarginTop, marginBottom: feedbackMarginBottom }
149
+ })
150
+ const handleChange = (event) => {
151
+ if (!inactive) {
152
+ setIsChecked(!isChecked, event)
153
+ }
145
154
  }
146
- }
147
- const handleKeyDown = (e) => {
148
- // The expected keyboard shortcut for activating a checkbox is the Space key
149
- if (e?.key === ' ') handleChange()
150
- }
151
- const accessibilityProps = a11yProps.select(rest)
152
- const uniqueId = useUniqueId('checkbox')
153
- const inputId = id ?? uniqueId
155
+ const handleKeyDown = (event) => {
156
+ // The expected keyboard shortcut for activating a checkbox is the Space key
157
+ if (event?.key === ' ') handleChange(event)
158
+ }
159
+ const accessibilityProps = a11yProps.select(rest)
160
+ const uniqueId = useUniqueId('checkbox')
161
+ const inputId = id ?? uniqueId
154
162
 
155
- return (
156
- <View style={staticStyles.wrapper}>
157
- <StackView direction={feedbackPosition === 'top' ? 'column-reverse' : 'column'} space={0}>
158
- <Pressable
159
- disabled={inactive}
160
- onKeyDown={handleKeyDown}
161
- onPress={handleChange}
162
- accessibilityRole="checkbox"
163
- accessibilityState={{ checked: isChecked, disabled: inactive }}
164
- {...accessibilityProps}
165
- >
166
- {({ focused: focus, hovered: hover, pressed }) => {
167
- const { icon: IconComponent, ...stateTokens } = getTokens({ focus, hover, pressed })
168
- const iconTokens = selectIconTokens(stateTokens)
163
+ return (
164
+ <View style={staticStyles.wrapper} ref={ref}>
165
+ <StackView direction={feedbackPosition === 'top' ? 'column-reverse' : 'column'} space={0}>
166
+ <Pressable
167
+ disabled={inactive}
168
+ onKeyDown={handleKeyDown}
169
+ onPress={handleChange}
170
+ accessibilityRole="checkbox"
171
+ accessibilityState={{ checked: isChecked, disabled: inactive }}
172
+ {...accessibilityProps}
173
+ >
174
+ {({ focused: focus, hovered: hover, pressed }) => {
175
+ const { icon: IconComponent, ...stateTokens } = getTokens({ focus, hover, pressed })
176
+ const iconTokens = selectIconTokens(stateTokens)
169
177
 
170
- return (
171
- <View style={staticStyles.container}>
172
- <View
173
- style={StyleSheet.flatten([
174
- staticStyles.defaultInputStyles,
175
- selectInputStyles(stateTokens, isChecked)
176
- ])}
177
- testID="Checkbox-Input"
178
- >
179
- {/* Add a real input on Web, skip on native platforms */}
180
- <CheckboxInput
181
- checked={isChecked}
182
- defaultChecked={defaultChecked}
183
- disabled={inactive}
184
- id={inputId}
185
- isControlled={isControlled}
186
- name={name}
187
- value={value}
188
- />
189
- {isChecked && IconComponent && (
190
- <IconComponent {...iconTokens} testID="Checkbox-Icon" />
178
+ return (
179
+ <View style={staticStyles.container}>
180
+ <View
181
+ style={StyleSheet.flatten([
182
+ staticStyles.defaultInputStyles,
183
+ selectInputStyles(stateTokens, isChecked)
184
+ ])}
185
+ testID="Checkbox-Input"
186
+ >
187
+ {/* Add a real input on Web, skip on native platforms */}
188
+ <CheckboxInput
189
+ checked={isChecked}
190
+ defaultChecked={defaultChecked}
191
+ disabled={inactive}
192
+ id={inputId}
193
+ isControlled={isControlled}
194
+ name={name}
195
+ value={value}
196
+ />
197
+ {isChecked && IconComponent && (
198
+ <IconComponent {...iconTokens} testID="Checkbox-Icon" />
199
+ )}
200
+ </View>
201
+ {Boolean(label) && (
202
+ <Text style={selectLabelStyles(stateTokens)}>
203
+ <CheckboxLabel forId={inputId}>{label}</CheckboxLabel>
204
+ </Text>
191
205
  )}
192
206
  </View>
193
- {Boolean(label) && (
194
- <Text style={selectLabelStyles(stateTokens)}>
195
- <CheckboxLabel forId={inputId}>{label}</CheckboxLabel>
196
- </Text>
197
- )}
198
- </View>
199
- )
200
- }}
201
- </Pressable>
202
- {Boolean(feedback) && (
203
- <View style={styles.feedbackContainer}>
204
- <Feedback
205
- title={feedback}
206
- variant={{ icon: error === true }}
207
- validation={error === true ? 'error' : undefined}
208
- />
209
- </View>
210
- )}
211
- </StackView>
212
- </View>
213
- )
214
- }
207
+ )
208
+ }}
209
+ </Pressable>
210
+ {Boolean(feedback) && (
211
+ <View style={styles.feedbackContainer}>
212
+ <Feedback
213
+ title={feedback}
214
+ variant={{ icon: error === true }}
215
+ validation={error === true ? 'error' : undefined}
216
+ />
217
+ </View>
218
+ )}
219
+ </StackView>
220
+ </View>
221
+ )
222
+ }
223
+ )
224
+ Checkbox.displayName = 'Checkbox'
215
225
 
216
226
  Checkbox.propTypes = {
217
227
  ...a11yProps.propTypes,
@@ -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'
@@ -55,71 +56,79 @@ import Fieldset from '../Fieldset'
55
56
  * />
56
57
  * ```
57
58
  */
58
- const CheckboxGroup = ({
59
- tokens,
60
- radioTokens,
61
- variant,
62
- items = [],
63
- legend,
64
- tooltip,
65
- hint,
66
- validation,
67
- feedback,
68
- initialCheckedIds,
69
- checkedIds,
70
- onChange,
71
- readOnly,
72
- name: inputGroupName,
73
- inactive
74
- }) => {
75
- const viewport = useViewport()
59
+ const CheckboxGroup = forwardRef(
60
+ (
61
+ {
62
+ tokens,
63
+ radioTokens,
64
+ variant,
65
+ items = [],
66
+ legend,
67
+ tooltip,
68
+ hint,
69
+ validation,
70
+ feedback,
71
+ initialCheckedIds,
72
+ checkedIds,
73
+ onChange,
74
+ readOnly,
75
+ name: inputGroupName,
76
+ inactive
77
+ },
78
+ ref
79
+ ) => {
80
+ const viewport = useViewport()
76
81
 
77
- const { space, fieldSpace } = useThemeTokens('CheckboxGroup', tokens, variant, {
78
- viewport
79
- })
82
+ const { space, fieldSpace } = useThemeTokens('CheckboxGroup', tokens, variant, {
83
+ viewport
84
+ })
85
+
86
+ const { currentValues, toggleOneValue } = useMultipleInputValues({
87
+ values: checkedIds,
88
+ initialValues: initialCheckedIds,
89
+ onChange,
90
+ readOnly: readOnly || inactive
91
+ })
92
+ const checkboxes = items.map(({ label, id, onChange: itemOnChange, ref: itemRef }, index) => {
93
+ const checkboxId = id || `Checkbox[${index}]`
94
+ const handleChange = (newCheckedState, event) => {
95
+ if (typeof itemOnChange === 'function') itemOnChange(newCheckedState, event)
96
+ toggleOneValue(checkboxId, event)
97
+ }
98
+ return (
99
+ <Checkbox
100
+ ref={itemRef}
101
+ key={checkboxId}
102
+ id={checkboxId}
103
+ checked={currentValues.includes(checkboxId)}
104
+ onChange={handleChange}
105
+ inactive={inactive}
106
+ label={label}
107
+ name={inputGroupName}
108
+ tokens={radioTokens}
109
+ variant={variant}
110
+ />
111
+ )
112
+ })
80
113
 
81
- const { currentValues, toggleOneValue } = useMultipleInputValues({
82
- values: checkedIds,
83
- initialValues: initialCheckedIds,
84
- onChange,
85
- readOnly: readOnly || inactive
86
- })
87
- const checkboxes = items.map(({ label, id, onChange: itemOnChange }, index) => {
88
- const checkboxId = id || `Checkbox[${index}]`
89
- const handleChange = (...args) => {
90
- if (typeof itemOnChange === 'function') itemOnChange(...args)
91
- toggleOneValue(checkboxId)
92
- }
93
114
  return (
94
- <Checkbox
95
- key={checkboxId}
96
- id={checkboxId}
97
- checked={currentValues.includes(checkboxId)}
98
- onChange={handleChange}
99
- inactive={inactive}
100
- label={label}
115
+ <Fieldset
116
+ ref={ref}
101
117
  name={inputGroupName}
102
- tokens={radioTokens}
103
- variant={variant}
104
- />
118
+ legend={legend}
119
+ tooltip={tooltip}
120
+ hint={hint}
121
+ space={fieldSpace}
122
+ feedback={feedback}
123
+ inactive={inactive}
124
+ validation={validation}
125
+ >
126
+ {getStackedContent(checkboxes, { space, direction: 'column' })}
127
+ </Fieldset>
105
128
  )
106
- })
107
-
108
- return (
109
- <Fieldset
110
- name={inputGroupName}
111
- legend={legend}
112
- tooltip={tooltip}
113
- hint={hint}
114
- space={fieldSpace}
115
- feedback={feedback}
116
- inactive={inactive}
117
- status={validation}
118
- >
119
- {getStackedContent(checkboxes, { space, direction: 'column' })}
120
- </Fieldset>
121
- )
122
- }
129
+ }
130
+ )
131
+ CheckboxGroup.displayName = 'CheckboxGroup'
123
132
 
124
133
  CheckboxGroup.propTypes = {
125
134
  /**
@@ -141,7 +150,8 @@ CheckboxGroup.propTypes = {
141
150
  PropTypes.exact({
142
151
  label: PropTypes.string,
143
152
  id: PropTypes.string,
144
- onChange: PropTypes.func
153
+ onChange: PropTypes.func,
154
+ ref: ABBPropTypes.ref()
145
155
  })
146
156
  ),
147
157
  /**
@@ -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, StyleSheet, Platform } from 'react-native'
4
4
  import { useThemeTokens } from '../ThemeProvider'
@@ -45,7 +45,7 @@ import { getTokensPropType, variantProp, spacingProps } from '../utils'
45
45
  *
46
46
  * For accessibility purposes a divider component will be described with ARIA attributes, i.e. `role="separator"` and `aria-orientation="vertical/horizontal"`.
47
47
  */
48
- const Divider = ({ variant, vertical = false, space, tokens, testID }) => {
48
+ const Divider = forwardRef(({ variant, vertical = false, space, tokens, testID }, ref) => {
49
49
  const { color, width } = useThemeTokens('Divider', tokens, variant)
50
50
 
51
51
  const borderStyles = vertical
@@ -68,7 +68,9 @@ const Divider = ({ variant, vertical = false, space, tokens, testID }) => {
68
68
  : // There are no such equivalent attributes for native
69
69
  {}
70
70
 
71
- const divider = <View style={[styles.divider, borderStyles]} testID={testID} {...a11y} />
71
+ const divider = (
72
+ <View ref={ref} style={[styles.divider, borderStyles]} testID={testID} {...a11y} />
73
+ )
72
74
  if (!space) return divider
73
75
  const spacerProps = { space, direction: vertical ? 'row' : 'column' }
74
76
  return (
@@ -78,7 +80,8 @@ const Divider = ({ variant, vertical = false, space, tokens, testID }) => {
78
80
  <Spacer {...spacerProps} testID={testID ? `${testID}-Spacer-after` : undefined} />
79
81
  </>
80
82
  )
81
- }
83
+ })
84
+ Divider.displayName = 'Divider'
82
85
 
83
86
  Divider.propTypes = {
84
87
  tokens: getTokensPropType('Divider'),
@@ -1,10 +1,11 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import ExpandCollapse from './ExpandCollapse'
3
3
 
4
4
  /**
5
5
  * 'Accordion' is a shorthand for an ExpandCollapse where only one item may be open at a time
6
6
  */
7
- const Accordion = (props) => <ExpandCollapse {...props} maxOpen={1} />
7
+ const Accordion = forwardRef((props, ref) => <ExpandCollapse ref={ref} {...props} maxOpen={1} />)
8
+ Accordion.displayName = 'Accordion'
8
9
  Accordion.propTypes = ExpandCollapse.propTypes
9
10
 
10
11
  export default Accordion
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import { Pressable, View } from 'react-native'
3
3
  import PropTypes from 'prop-types'
4
4
 
@@ -47,51 +47,48 @@ function selectIconTokens(tokens) {
47
47
  }
48
48
  }
49
49
 
50
- const ExpandCollapseControl = ({
51
- onPress,
52
- isExpanded,
53
- children,
54
- tokens,
55
- accessibilityRole = 'button',
56
- variant,
57
- rest
58
- }) => {
59
- const getTokens = useThemeTokensCallback('ExpandCollapseControl', tokens, variant)
50
+ const ExpandCollapseControl = forwardRef(
51
+ ({ onPress, isExpanded, children, tokens, accessibilityRole = 'button', variant, rest }, ref) => {
52
+ const getTokens = useThemeTokensCallback('ExpandCollapseControl', tokens, variant)
60
53
 
61
- const a11y = a11yProps.select({ ...rest, accessibilityRole })
62
- a11y.accessibilityState = {
63
- ...(a11y.accessibilityState || {}),
64
- expanded: isExpanded
65
- }
54
+ const a11y = a11yProps.select({ ...rest, accessibilityRole })
55
+ a11y.accessibilityState = {
56
+ ...(a11y.accessibilityState || {}),
57
+ expanded: isExpanded
58
+ }
66
59
 
67
- const getControlState = ({ pressed, hovered, focused }) => ({
68
- pressed,
69
- hover: hovered,
70
- focus: focused,
71
- expanded: isExpanded
72
- })
73
- const getControlTokens = (pressableState) => getTokens(getControlState(pressableState))
74
- const getPressableStyle = (pressableState) =>
75
- selectContainerStyles(getControlTokens(pressableState))
60
+ const getControlState = ({ pressed, hovered, focused }) => ({
61
+ pressed,
62
+ hover: hovered,
63
+ focus: focused,
64
+ expanded: isExpanded
65
+ })
66
+ const getControlTokens = (pressableState) => getTokens(getControlState(pressableState))
67
+ const getPressableStyle = (pressableState) =>
68
+ selectContainerStyles(getControlTokens(pressableState))
76
69
 
77
- return (
78
- <Pressable {...a11y} onPress={onPress} style={getPressableStyle}>
79
- {(pressableState) => {
80
- const { icon: IconComponent, ...themeTokens } = getControlTokens(pressableState)
81
- return (
82
- <>
83
- {IconComponent && (
84
- <View style={selectIconContainerStyles(themeTokens)}>
85
- <IconComponent {...selectIconTokens(themeTokens)} />
86
- </View>
87
- )}
88
- {typeof children === 'function' ? children(getControlState(pressableState)) : children}
89
- </>
90
- )
91
- }}
92
- </Pressable>
93
- )
94
- }
70
+ return (
71
+ <Pressable ref={ref} {...a11y} onPress={onPress} style={getPressableStyle}>
72
+ {(pressableState) => {
73
+ const { icon: IconComponent, ...themeTokens } = getControlTokens(pressableState)
74
+ return (
75
+ <>
76
+ {IconComponent && (
77
+ <View style={selectIconContainerStyles(themeTokens)}>
78
+ <IconComponent {...selectIconTokens(themeTokens)} />
79
+ </View>
80
+ )}
81
+ {typeof children === 'function'
82
+ ? children(getControlState(pressableState))
83
+ : children}
84
+ </>
85
+ )
86
+ }}
87
+ </Pressable>
88
+ )
89
+ }
90
+ )
91
+ ExpandCollapseControl.displayName = 'ExpandCollapseControl'
95
92
 
96
93
  ExpandCollapseControl.propTypes = {
97
94
  ...a11yProps.propTypes,
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import { View } from 'react-native'
3
3
  import PropTypes from 'prop-types'
4
4
 
@@ -20,29 +20,32 @@ function selectBorderStyles(tokens) {
20
20
  * <ExpandCollapse.Panel> children, and assign the panels explicit `panelId` props. The panels may be
21
21
  * nested (they do not need to be direct children), and non-interactive items may be included too.
22
22
  */
23
- const ExpandCollapse = ({ children, tokens, variant, maxOpen, open, initialOpen, onChange }) => {
24
- const {
25
- currentValues: openIds,
26
- toggleOneValue: onToggle,
27
- resetValues,
28
- setValues,
29
- unsetValues
30
- } = useMultipleInputValues({
31
- maxValues: maxOpen,
32
- values: open,
33
- initialValues: initialOpen,
34
- onChange
35
- })
36
- const themeTokens = useThemeTokens('ExpandCollapse', tokens, variant)
23
+ const ExpandCollapse = forwardRef(
24
+ ({ children, tokens, variant, maxOpen, open, initialOpen, onChange }, ref) => {
25
+ const {
26
+ currentValues: openIds,
27
+ toggleOneValue: onToggle,
28
+ resetValues,
29
+ setValues,
30
+ unsetValues
31
+ } = useMultipleInputValues({
32
+ maxValues: maxOpen,
33
+ values: open,
34
+ initialValues: initialOpen,
35
+ onChange
36
+ })
37
+ const themeTokens = useThemeTokens('ExpandCollapse', tokens, variant)
37
38
 
38
- return (
39
- <View style={selectBorderStyles(themeTokens)}>
40
- {typeof children === 'function'
41
- ? children({ openIds, onToggle, resetValues, setValues, unsetValues })
42
- : children}
43
- </View>
44
- )
45
- }
39
+ return (
40
+ <View ref={ref} style={selectBorderStyles(themeTokens)}>
41
+ {typeof children === 'function'
42
+ ? children({ openIds, onToggle, resetValues, setValues, unsetValues })
43
+ : children}
44
+ </View>
45
+ )
46
+ }
47
+ )
48
+ ExpandCollapse.displayName = 'ExpandCollapse'
46
49
 
47
50
  ExpandCollapse.propTypes = {
48
51
  variant: variantProp.propType,