@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,4 +1,4 @@
1
- import React, { useState } from 'react'
1
+ import React, { forwardRef, useState } from 'react'
2
2
 
3
3
  import { View, Platform, StyleSheet } from 'react-native'
4
4
  import PropTypes from 'prop-types'
@@ -147,100 +147,143 @@ const selectValidationIconContainerStyles = ({
147
147
  * NOTE: this does not work on native platforms - the grouped items will be shown at the same level as the non-grouped items.
148
148
  *
149
149
  */
150
- const Select = ({
151
- value,
152
- initialValue,
153
- onChange,
154
- children,
155
- inactive,
156
- readOnly,
157
- placeholder,
158
- validation,
159
- tokens,
160
- variant,
161
- testID,
162
- ...rest
163
- }) => {
164
- const { currentValue, setValue } = useInputValue({
165
- value,
166
- initialValue,
167
- onChange,
168
- readOnly
169
- })
150
+ const Select = forwardRef(
151
+ (
152
+ {
153
+ value,
154
+ initialValue,
155
+ onChange,
156
+ children,
157
+ inactive,
158
+ readOnly,
159
+ placeholder,
160
+ validation,
161
+ tokens,
162
+ variant,
163
+ testID,
164
+ ...rest
165
+ },
166
+ ref
167
+ ) => {
168
+ const { currentValue, setValue } = useInputValue({
169
+ value,
170
+ initialValue,
171
+ onChange,
172
+ readOnly
173
+ })
170
174
 
171
- const [isFocused, setIsFocused] = useState(false)
172
- const handleFocus = () => setIsFocused(true)
173
- const handleBlur = () => setIsFocused(false)
175
+ const [isFocused, setIsFocused] = useState(false)
176
+ const handleFocus = () => setIsFocused(true)
177
+ const handleBlur = () => setIsFocused(false)
174
178
 
175
- const [isHovered, setIsHovered] = useState(false)
176
- const handleMouseOver = () => setIsHovered(true)
177
- const handleMouseOut = () => setIsHovered(false)
179
+ const [isHovered, setIsHovered] = useState(false)
180
+ const handleMouseOver = () => setIsHovered(true)
181
+ const handleMouseOut = () => setIsHovered(false)
178
182
 
179
- const { props: supportsProps } = inputSupportsProps.select(rest)
183
+ const { props: supportsProps } = inputSupportsProps.select(rest)
180
184
 
181
- const themeTokens = useThemeTokens('Select', tokens, variant, {
182
- focus: isFocused,
183
- hover: isHovered,
184
- inactive,
185
- validation
186
- })
185
+ const themeTokens = useThemeTokens('Select', tokens, variant, {
186
+ focus: isFocused,
187
+ hover: isHovered,
188
+ inactive,
189
+ validation
190
+ })
191
+
192
+ const { icon: IconComponent, validationIcon: ValidationIconComponent } = themeTokens
187
193
 
188
- const { icon: IconComponent, validationIcon: ValidationIconComponent } = themeTokens
189
-
190
- return (
191
- <InputSupports {...supportsProps}>
192
- {({ a11yProps, inputId }) => (
193
- <View style={selectOuterBorderStyles(themeTokens)}>
194
- <Picker
195
- style={selectInputStyles(themeTokens, inactive)}
196
- onFocus={handleFocus}
197
- onBlur={handleBlur}
198
- onMouseOver={handleMouseOver}
199
- onMouseOut={handleMouseOut}
200
- onChange={setValue}
201
- value={currentValue}
202
- inactive={inactive}
203
- placeholder={placeholder !== undefined ? { label: placeholder, value: '' } : undefined}
204
- {...a11yProps}
205
- nativeID={inputId}
206
- testID={testID}
207
- >
208
- {children}
209
- </Picker>
210
- {ValidationIconComponent && (
211
- <View
212
- pointerEvents="none"
213
- style={[staticStyles.iconContainer, selectValidationIconContainerStyles(themeTokens)]}
194
+ return (
195
+ <InputSupports {...supportsProps}>
196
+ {({ a11yProps, inputId }) => (
197
+ <View style={selectOuterBorderStyles(themeTokens)}>
198
+ <Picker
199
+ ref={ref}
200
+ style={selectInputStyles(themeTokens, inactive)}
201
+ onFocus={handleFocus}
202
+ onBlur={handleBlur}
203
+ onMouseOver={handleMouseOver}
204
+ onMouseOut={handleMouseOut}
205
+ onChange={setValue}
206
+ value={currentValue}
207
+ inactive={inactive}
208
+ placeholder={
209
+ placeholder !== undefined ? { label: placeholder, value: '' } : undefined
210
+ }
211
+ {...a11yProps}
212
+ nativeID={inputId}
213
+ testID={testID}
214
214
  >
215
- <ValidationIconComponent tokens={selectValidationIconTokens(themeTokens)} />
216
- </View>
217
- )}
218
- {IconComponent &&
219
- Platform.OS !== 'android' && ( // we can't hide the default caret of a native picker on android
215
+ {children}
216
+ </Picker>
217
+ {ValidationIconComponent && (
220
218
  <View
221
219
  pointerEvents="none"
222
- style={[staticStyles.iconContainer, selectIconContainerStyles(themeTokens)]}
220
+ style={[
221
+ staticStyles.iconContainer,
222
+ selectValidationIconContainerStyles(themeTokens)
223
+ ]}
223
224
  >
224
- <IconComponent {...selectIconTokens(themeTokens)} />
225
+ <ValidationIconComponent tokens={selectValidationIconTokens(themeTokens)} />
225
226
  </View>
226
227
  )}
227
- </View>
228
- )}
229
- </InputSupports>
230
- )
231
- }
228
+ {IconComponent &&
229
+ Platform.OS !== 'android' && ( // we can't hide the default caret of a native picker on android
230
+ <View
231
+ pointerEvents="none"
232
+ style={[staticStyles.iconContainer, selectIconContainerStyles(themeTokens)]}
233
+ >
234
+ <IconComponent {...selectIconTokens(themeTokens)} />
235
+ </View>
236
+ )}
237
+ </View>
238
+ )}
239
+ </InputSupports>
240
+ )
241
+ }
242
+ )
243
+ Select.displayName = 'Select'
232
244
 
233
245
  Select.propTypes = {
234
246
  ...inputSupportsProps.types,
247
+ /**
248
+ * Initial value for the uncontrolled version.
249
+ */
235
250
  initialValue: PropTypes.string,
251
+ /**
252
+ * Current value to be set as selected.
253
+ */
236
254
  value: PropTypes.string,
255
+ /**
256
+ * Callback to be called when the value changes.
257
+ */
237
258
  onChange: PropTypes.func,
259
+ /**
260
+ * An array of items or item groups to be used as options.
261
+ */
238
262
  children: componentPropType(['Item', 'Group']),
263
+ /**
264
+ * Whether the select is disabled.
265
+ */
239
266
  inactive: PropTypes.bool,
267
+ /**
268
+ * Whether the select is read-only.
269
+ */
240
270
  readOnly: PropTypes.bool,
271
+ /**
272
+ * A placeholder to provide instructions (such as "Please select...")
273
+ * as an unselectable option
274
+ */
241
275
  placeholder: PropTypes.string,
276
+ /**
277
+ * Select tokens.
278
+ */
242
279
  tokens: getTokensPropType('Select'),
280
+ /**
281
+ * Select variant.
282
+ */
243
283
  variant: variantProp.propType,
284
+ /**
285
+ * Dedicated ID for testing.
286
+ */
244
287
  testID: PropTypes.string
245
288
  }
246
289
 
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import { Pressable } from 'react-native'
3
3
  import PropTypes from 'prop-types'
4
4
 
@@ -37,54 +37,61 @@ function selectItemStyles({
37
37
 
38
38
  This component can only be accessed as a name-spaced component: `SideNav.Item`.
39
39
  */
40
- const Item = ({
41
- children,
42
- itemId,
43
- groupId,
44
- onPress,
45
- isActive = false,
46
- isExpanded = false,
47
- tokens,
48
- variant,
49
- href,
50
- accessibilityRole = 'link',
51
- testID,
52
- ...props
53
- }) => {
54
- const handlePress = () => onPress(itemId, groupId)
40
+ const Item = forwardRef(
41
+ (
42
+ {
43
+ children,
44
+ itemId,
45
+ groupId,
46
+ onPress,
47
+ isActive = false,
48
+ isExpanded = false,
49
+ tokens,
50
+ variant,
51
+ href,
52
+ accessibilityRole = 'link',
53
+ testID,
54
+ ...props
55
+ },
56
+ ref
57
+ ) => {
58
+ const handlePress = () => onPress(itemId, groupId)
55
59
 
56
- const { hrefAttrs, rest } = hrefAttrsProp.bundle(props)
57
- const linkPropSet = linkProps.select({
58
- accessibilityRole,
59
- href,
60
- onPress: handlePress,
61
- hrefAttrs,
62
- ...rest
63
- })
60
+ const { hrefAttrs, rest } = hrefAttrsProp.bundle(props)
61
+ const linkPropSet = linkProps.select({
62
+ accessibilityRole,
63
+ href,
64
+ onPress: handlePress,
65
+ hrefAttrs,
66
+ ...rest
67
+ })
64
68
 
65
- const getTokens = useThemeTokensCallback('SideNavItem', tokens, variant)
66
- const getAppearanceState = ({ hovered }) => ({
67
- hover: hovered,
68
- active: isActive,
69
- expanded: isExpanded
70
- })
71
- const getPressableStyle = (pressableState) =>
72
- selectItemStyles(getTokens(getAppearanceState(pressableState)))
69
+ const getTokens = useThemeTokensCallback('SideNavItem', tokens, variant)
70
+ const getAppearanceState = ({ hovered }) => ({
71
+ hover: hovered,
72
+ active: isActive,
73
+ expanded: isExpanded
74
+ })
75
+ const getPressableStyle = (pressableState) =>
76
+ selectItemStyles(getTokens(getAppearanceState(pressableState)))
73
77
 
74
- return (
75
- <Pressable
76
- style={getPressableStyle}
77
- {...linkPropSet}
78
- accessibilityState={{ selected: isActive }}
79
- testID={testID}
80
- >
81
- {(pressableState) => {
82
- const themeTokens = getTokens(getAppearanceState(pressableState))
83
- return <ItemContent tokens={themeTokens}>{children}</ItemContent>
84
- }}
85
- </Pressable>
86
- )
87
- }
78
+ return (
79
+ <Pressable
80
+ ref={ref}
81
+ style={getPressableStyle}
82
+ {...linkPropSet}
83
+ accessibilityState={{ selected: isActive }}
84
+ testID={testID}
85
+ >
86
+ {(pressableState) => {
87
+ const themeTokens = getTokens(getAppearanceState(pressableState))
88
+ return <ItemContent tokens={themeTokens}>{children}</ItemContent>
89
+ }}
90
+ </Pressable>
91
+ )
92
+ }
93
+ )
94
+ Item.displayName = 'Item'
88
95
 
89
96
  Item.propTypes = {
90
97
  /**
@@ -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 ItemContent from './ItemContent'
@@ -16,52 +16,59 @@ import { useThemeTokensCallback } from '../ThemeProvider'
16
16
  ## Usage Criteria
17
17
  - Use `SideNav.ItemsGroup` with large pages that have multiple sections
18
18
  */
19
- const ItemsGroup = ({
20
- children,
21
- label,
22
- openGroups,
23
- groupId,
24
- isActive = false,
25
- variant,
26
- tokens,
27
- itemTokens,
28
- onToggle
29
- }) => {
30
- // A SideNav control uses the same style and theme as SideNavItem, with a 'parent' variant,
31
- // plus control-specific tokens from the SideNavItemsGroup theme (e.g. open/close icon, etc).
32
- const getAppearance = (appearance) => ({ ...variant, ...appearance, active: isActive })
33
- const getItemAppearance = (appearance) => ({ ...getAppearance(appearance), type: 'parent' })
19
+ const ItemsGroup = forwardRef(
20
+ (
21
+ {
22
+ children,
23
+ label,
24
+ openGroups,
25
+ groupId,
26
+ isActive = false,
27
+ variant,
28
+ tokens,
29
+ itemTokens,
30
+ onToggle
31
+ },
32
+ ref
33
+ ) => {
34
+ // A SideNav control uses the same style and theme as SideNavItem, with a 'parent' variant,
35
+ // plus control-specific tokens from the SideNavItemsGroup theme (e.g. open/close icon, etc).
36
+ const getAppearance = (appearance) => ({ ...variant, ...appearance, active: isActive })
37
+ const getItemAppearance = (appearance) => ({ ...getAppearance(appearance), type: 'parent' })
34
38
 
35
- const getGroupTokens = useThemeTokensCallback('SideNavItemsGroup', tokens, variant)
36
- const getPanelTokens = (appearance) =>
37
- selectTokens('ExpandCollapsePanel', getGroupTokens(getAppearance(appearance)))
39
+ const getGroupTokens = useThemeTokensCallback('SideNavItemsGroup', tokens, variant)
40
+ const getPanelTokens = (appearance) =>
41
+ selectTokens('ExpandCollapsePanel', getGroupTokens(getAppearance(appearance)))
38
42
 
39
- const getItemTokens = useThemeTokensCallback('SideNavItem', itemTokens, variant)
40
- const getControlTokens = (appearance) =>
41
- selectTokens('ExpandCollapseControl', {
42
- ...getItemTokens(getItemAppearance(appearance)), // main style from SideNavItem
43
- ...getGroupTokens(getAppearance(appearance)) // control-specific tokens like icon etc
44
- })
43
+ const getItemTokens = useThemeTokensCallback('SideNavItem', itemTokens, variant)
44
+ const getControlTokens = (appearance) =>
45
+ selectTokens('ExpandCollapseControl', {
46
+ ...getItemTokens(getItemAppearance(appearance)), // main style from SideNavItem
47
+ ...getGroupTokens(getAppearance(appearance)) // control-specific tokens like icon etc
48
+ })
45
49
 
46
- const controlContent = (controlState) => {
47
- const currentItemTokens = getItemTokens(getItemAppearance(controlState))
48
- return <ItemContent tokens={currentItemTokens}>{label}</ItemContent>
49
- }
50
+ const controlContent = (controlState) => {
51
+ const currentItemTokens = getItemTokens(getItemAppearance(controlState))
52
+ return <ItemContent tokens={currentItemTokens}>{label}</ItemContent>
53
+ }
50
54
 
51
- return (
52
- <ExpandCollapse.Panel
53
- openIds={openGroups}
54
- panelId={groupId}
55
- onToggle={onToggle}
56
- tokens={getPanelTokens}
57
- controlTokens={getControlTokens}
58
- control={controlContent}
59
- accessibilityState={{ active: isActive }} // ExpandCollapse.Panel handles expanded state
60
- >
61
- {children}
62
- </ExpandCollapse.Panel>
63
- )
64
- }
55
+ return (
56
+ <ExpandCollapse.Panel
57
+ ref={ref}
58
+ openIds={openGroups}
59
+ panelId={groupId}
60
+ onToggle={onToggle}
61
+ tokens={getPanelTokens}
62
+ controlTokens={getControlTokens}
63
+ control={controlContent}
64
+ accessibilityState={{ active: isActive }} // ExpandCollapse.Panel handles expanded state
65
+ >
66
+ {children}
67
+ </ExpandCollapse.Panel>
68
+ )
69
+ }
70
+ )
71
+ ItemsGroup.displayName = 'ItemsGroup'
65
72
 
66
73
  ItemsGroup.propTypes = {
67
74
  /**
@@ -1,4 +1,4 @@
1
- import React, { useState } from 'react'
1
+ import React, { forwardRef, useState } from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
 
4
4
  import ExpandCollapse from '../ExpandCollapse'
@@ -20,73 +20,81 @@ function selectBorderStyles(tokens) {
20
20
  - Use in conjunction with a large amount of educational / informational content
21
21
  - Allow the user to navigate between options frequently and efficiently
22
22
  */
23
- const SideNav = ({ children, variant = {}, tokens, accordion = true, itemTokens, groupTokens }) => {
24
- const themeTokens = useThemeTokens('SideNav', tokens, variant)
25
- const [active, setActive] = useState({ groupId: undefined, itemId: undefined })
23
+ const SideNav = forwardRef(
24
+ ({ children, variant = {}, tokens, accordion = true, itemTokens, groupTokens }, ref) => {
25
+ const themeTokens = useThemeTokens('SideNav', tokens, variant)
26
+ const [active, setActive] = useState({ groupId: undefined, itemId: undefined })
26
27
 
27
- const onItemPress = (itemId, groupId) => {
28
- setActive({ itemId, groupId })
29
- }
30
-
31
- const isItemActive = (itemId, groupId) => {
32
- return active.groupId === groupId && active.itemId === itemId
33
- }
34
-
35
- return (
36
- <ExpandCollapse maxOpen={accordion ? 1 : null} style={selectBorderStyles(themeTokens)}>
37
- {({ openIds, onToggle }) => {
38
- const renderItem = (item, index, groupId) => {
39
- const { itemId = `item-${index}`, onPress } = item.props
40
- const handlePress = (...args) => {
41
- onItemPress(...args)
42
- if (onPress) onPress(...args)
43
- }
44
- return (
45
- <Item
46
- {...item.props}
47
- key={itemId}
48
- itemId={itemId}
49
- groupId={groupId}
50
- variant={groupId ? { ...variant, type: 'child' } : variant}
51
- tokens={itemTokens}
52
- isActive={isItemActive(itemId, groupId)}
53
- onPress={handlePress}
54
- />
55
- )
56
- }
28
+ const onItemPress = (itemId, groupId) => {
29
+ setActive({ itemId, groupId })
30
+ }
57
31
 
58
- return React.Children.map(children, (child, index) => {
59
- // iterate over children and identify them internally to later reference expanded groups and active items
60
- if (child.type === Item) return renderItem(child, index)
32
+ const isItemActive = (itemId, groupId) => {
33
+ return active.groupId === groupId && active.itemId === itemId
34
+ }
61
35
 
62
- if (child.type === ItemsGroup) {
63
- const { groupId = `group-${index}` } = child.props
64
- const isGroupActive = active.itemId !== undefined && active.groupId === groupId
36
+ return (
37
+ <ExpandCollapse
38
+ ref={ref}
39
+ maxOpen={accordion ? 1 : null}
40
+ style={selectBorderStyles(themeTokens)}
41
+ >
42
+ {({ openIds, onToggle }) => {
43
+ const renderItem = (item, index, groupId) => {
44
+ const { itemId = `item-${index}`, onPress } = item.props
45
+ const handlePress = (...args) => {
46
+ onItemPress(...args)
47
+ if (onPress) onPress(...args)
48
+ }
65
49
  return (
66
- <ItemsGroup
67
- {...child.props}
68
- key={groupId}
50
+ <Item
51
+ {...item.props}
52
+ key={itemId}
53
+ itemId={itemId}
69
54
  groupId={groupId}
70
- variant={variant}
71
- tokens={groupTokens}
72
- itemTokens={itemTokens}
73
- openGroups={openIds}
74
- isActive={isGroupActive}
75
- onToggle={() => onToggle(groupId)}
76
- >
77
- {React.Children.map(child.props.children, (item, itemIndex) =>
78
- renderItem(item, itemIndex, groupId)
79
- )}
80
- </ItemsGroup>
55
+ variant={groupId ? { ...variant, type: 'child' } : variant}
56
+ tokens={itemTokens}
57
+ isActive={isItemActive(itemId, groupId)}
58
+ onPress={handlePress}
59
+ />
81
60
  )
82
61
  }
83
62
 
84
- return null
85
- })
86
- }}
87
- </ExpandCollapse>
88
- )
89
- }
63
+ return React.Children.map(children, (child, index) => {
64
+ // iterate over children and identify them internally to later reference expanded groups and active items
65
+ if (child.type === Item) return renderItem(child, index)
66
+
67
+ if (child.type === ItemsGroup) {
68
+ const { groupId = `group-${index}` } = child.props
69
+ const isGroupActive = active.itemId !== undefined && active.groupId === groupId
70
+ const handleToggle = (event) => onToggle(groupId, event)
71
+ return (
72
+ <ItemsGroup
73
+ {...child.props}
74
+ key={groupId}
75
+ groupId={groupId}
76
+ variant={variant}
77
+ tokens={groupTokens}
78
+ itemTokens={itemTokens}
79
+ openGroups={openIds}
80
+ isActive={isGroupActive}
81
+ onToggle={handleToggle}
82
+ >
83
+ {React.Children.map(child.props.children, (item, itemIndex) =>
84
+ renderItem(item, itemIndex, groupId)
85
+ )}
86
+ </ItemsGroup>
87
+ )
88
+ }
89
+
90
+ return null
91
+ })
92
+ }}
93
+ </ExpandCollapse>
94
+ )
95
+ }
96
+ )
97
+ SideNav.displayName = 'SideNav'
90
98
 
91
99
  SideNav.propTypes = {
92
100
  /**
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import { Animated, Platform } from 'react-native'
3
3
  import propTypes from 'prop-types'
4
4
  import StackView from '../StackView'
@@ -27,7 +27,7 @@ const selectSquareStyles = ({ radius }) => ({
27
27
  borderRadius: radius
28
28
  })
29
29
 
30
- const Skeleton = ({ tokens, variant, size, characters, lines, shape = 'line' }) => {
30
+ const Skeleton = forwardRef(({ tokens, variant, size, characters, lines, shape = 'line' }, ref) => {
31
31
  const themeTokens = useThemeTokens('Skeleton', tokens, variant)
32
32
  const skeletonHeight = useSpacingScale(size || themeTokens.size)
33
33
  const nativeAnimation = useSkeletonNativeAnimation()
@@ -74,17 +74,13 @@ const Skeleton = ({ tokens, variant, size, characters, lines, shape = 'line' })
74
74
  />
75
75
  )
76
76
 
77
- if (lines) {
78
- const arrayOfSkeletons = [...Array(lines)]
79
- return (
80
- <StackView space={themeTokens.spaceBetweenLines}>
81
- {arrayOfSkeletons.map((_, index) => renderSkeleton(index))}
82
- </StackView>
83
- )
84
- }
85
-
86
- return renderSkeleton()
87
- }
77
+ return (
78
+ <StackView space={themeTokens.spaceBetweenLines} ref={ref}>
79
+ {lines > 1 ? [...Array(lines)].map((_, index) => renderSkeleton(index)) : renderSkeleton()}
80
+ </StackView>
81
+ )
82
+ })
83
+ Skeleton.displayName = 'Skeleton'
88
84
 
89
85
  Skeleton.propTypes = {
90
86
  tokens: getTokensPropType('Skeleton'),
@@ -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, View } from 'react-native'
4
4
 
@@ -54,11 +54,14 @@ const selectSizeStyle = (size, direction) => ({
54
54
  * Spacer has no content and is ignored by tools such as screen readers. Use `Divider` for
55
55
  * separations between elements that may be treated as semantically meaningful on web.
56
56
  */
57
- const Spacer = ({ space = 1, direction = 'column', testID }) => {
57
+ const Spacer = forwardRef(({ space = 1, direction = 'column', testID, dataSet }, ref) => {
58
58
  const size = useSpacingScale(space)
59
59
  const sizeStyle = selectSizeStyle(size, direction)
60
- return <View testID={testID} style={[staticStyles.stretch, sizeStyle]} />
61
- }
60
+ return (
61
+ <View ref={ref} testID={testID} style={[staticStyles.stretch, sizeStyle]} dataSet={dataSet} />
62
+ )
63
+ })
64
+ Spacer.displayName = 'Spacer'
62
65
 
63
66
  Spacer.propTypes = {
64
67
  /**
@@ -74,6 +77,10 @@ Spacer.propTypes = {
74
77
  * - `'row'` applies space horizontally; has a fixed width and not height.
75
78
  */
76
79
  direction: PropTypes.oneOf(['column', 'row']),
80
+ /**
81
+ * @ignore
82
+ */
83
+ dataSet: PropTypes.object,
77
84
  /**
78
85
  * @ignore
79
86
  * In tests, the only way to select Spacers is with testID prop and getByTestId, since they have no content,