@telus-uds/components-base 3.28.2 → 3.29.1

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 (93) hide show
  1. package/CHANGELOG.md +27 -1
  2. package/jest.config.cjs +1 -0
  3. package/lib/cjs/ActionCard/ActionCard.js +4 -4
  4. package/lib/cjs/ActivityIndicator/Dots.native.js +1 -2
  5. package/lib/cjs/ActivityIndicator/Spinner.native.js +1 -2
  6. package/lib/cjs/Box/Box.js +1 -2
  7. package/lib/cjs/Button/Button.js +1 -2
  8. package/lib/cjs/Button/ButtonBase.js +8 -8
  9. package/lib/cjs/Button/ButtonDropdown.js +1 -2
  10. package/lib/cjs/Button/ButtonGroup.js +1 -2
  11. package/lib/cjs/Button/ButtonLink.js +1 -2
  12. package/lib/cjs/Card/Card.js +1 -2
  13. package/lib/cjs/Card/CardBase.js +12 -0
  14. package/lib/cjs/Card/PressableCardBase.js +1 -2
  15. package/lib/cjs/Card/index.js +1 -2
  16. package/lib/cjs/CardGroup/CardGroup.js +1 -2
  17. package/lib/cjs/Carousel/Carousel.js +6 -6
  18. package/lib/cjs/CheckboxCard/CheckboxCard.js +1 -2
  19. package/lib/cjs/CheckboxCardGroup/CheckboxCardGroup.js +1 -2
  20. package/lib/cjs/ColourToggle/ColourBubble.js +17 -3
  21. package/lib/cjs/ColourToggle/ColourToggle.js +8 -2
  22. package/lib/cjs/ExpandCollapse/Control.js +17 -3
  23. package/lib/cjs/ExpandCollapse/Panel.js +6 -0
  24. package/lib/cjs/ExpandCollapseMini/ExpandCollapseMini.js +14 -2
  25. package/lib/cjs/ExpandCollapseMini/ExpandCollapseMiniControl.js +15 -2
  26. package/lib/cjs/HorizontalScroll/index.js +1 -2
  27. package/lib/cjs/Icon/IconText.js +1 -2
  28. package/lib/cjs/Icon/index.js +1 -2
  29. package/lib/cjs/InputSupports/InputSupports.js +1 -2
  30. package/lib/cjs/InputSupports/useInputSupports.js +1 -3
  31. package/lib/cjs/Link/ChevronLink.js +1 -0
  32. package/lib/cjs/Link/LinkBase.js +29 -13
  33. package/lib/cjs/Link/MobileIconTextContent.js +155 -0
  34. package/lib/cjs/Listbox/Listbox.js +1 -2
  35. package/lib/cjs/Modal/Modal.js +1 -1
  36. package/lib/cjs/Pagination/PageButton.js +1 -2
  37. package/lib/cjs/Pagination/Pagination.js +1 -2
  38. package/lib/cjs/QuickLinks/QuickLinks.js +7 -0
  39. package/lib/cjs/Radio/Radio.js +1 -2
  40. package/lib/cjs/RadioCard/RadioCard.js +1 -2
  41. package/lib/cjs/RadioCard/RadioCardGroup.js +1 -2
  42. package/lib/cjs/Shortcuts/Shortcuts.js +1 -2
  43. package/lib/cjs/SideNav/SideNav.js +1 -2
  44. package/lib/cjs/StackView/StackWrapBox.js +9 -1
  45. package/lib/cjs/StackView/StackWrapGap.js +3 -1
  46. package/lib/cjs/StackView/getStackedContent.js +21 -12
  47. package/lib/cjs/TabBar/TabBar.js +7 -2
  48. package/lib/cjs/Tabs/Tabs.js +1 -2
  49. package/lib/cjs/Tooltip/Tooltip.native.js +2 -2
  50. package/lib/cjs/index.js +1 -2
  51. package/lib/cjs/utils/index.js +1 -2
  52. package/lib/esm/ActionCard/ActionCard.js +4 -4
  53. package/lib/esm/Button/ButtonBase.js +8 -8
  54. package/lib/esm/Card/CardBase.js +12 -0
  55. package/lib/esm/Carousel/Carousel.js +6 -6
  56. package/lib/esm/ColourToggle/ColourBubble.js +17 -3
  57. package/lib/esm/ColourToggle/ColourToggle.js +8 -2
  58. package/lib/esm/ExpandCollapse/Control.js +17 -3
  59. package/lib/esm/ExpandCollapse/Panel.js +6 -0
  60. package/lib/esm/ExpandCollapseMini/ExpandCollapseMini.js +14 -2
  61. package/lib/esm/ExpandCollapseMini/ExpandCollapseMiniControl.js +15 -2
  62. package/lib/esm/InputSupports/InputSupports.js +1 -2
  63. package/lib/esm/InputSupports/useInputSupports.js +1 -3
  64. package/lib/esm/Link/ChevronLink.js +1 -0
  65. package/lib/esm/Link/LinkBase.js +29 -13
  66. package/lib/esm/Link/MobileIconTextContent.js +147 -0
  67. package/lib/esm/Modal/Modal.js +1 -1
  68. package/lib/esm/QuickLinks/QuickLinks.js +7 -0
  69. package/lib/esm/StackView/StackWrapBox.js +9 -1
  70. package/lib/esm/StackView/StackWrapGap.js +3 -1
  71. package/lib/esm/StackView/getStackedContent.js +20 -10
  72. package/lib/esm/TabBar/TabBar.js +7 -2
  73. package/lib/esm/Tooltip/Tooltip.native.js +2 -2
  74. package/lib/package.json +1 -1
  75. package/package.json +1 -1
  76. package/src/Card/CardBase.jsx +12 -0
  77. package/src/ColourToggle/ColourBubble.jsx +18 -3
  78. package/src/ColourToggle/ColourToggle.jsx +7 -2
  79. package/src/ExpandCollapse/Control.jsx +24 -4
  80. package/src/ExpandCollapse/Panel.jsx +6 -0
  81. package/src/ExpandCollapseMini/ExpandCollapseMini.jsx +23 -3
  82. package/src/ExpandCollapseMini/ExpandCollapseMiniControl.jsx +14 -2
  83. package/src/InputSupports/InputSupports.jsx +1 -6
  84. package/src/InputSupports/useInputSupports.js +1 -1
  85. package/src/Link/ChevronLink.jsx +1 -0
  86. package/src/Link/LinkBase.jsx +47 -20
  87. package/src/Link/MobileIconTextContent.jsx +129 -0
  88. package/src/Modal/Modal.jsx +1 -1
  89. package/src/QuickLinks/QuickLinks.jsx +8 -0
  90. package/src/StackView/StackWrapBox.jsx +13 -1
  91. package/src/StackView/StackWrapGap.jsx +2 -1
  92. package/src/StackView/getStackedContent.jsx +22 -8
  93. package/src/TabBar/TabBar.jsx +21 -4
@@ -34,6 +34,7 @@ const ChevronLink = React.forwardRef(
34
34
  return (
35
35
  <LinkBase
36
36
  {...otherlinkProps}
37
+ useMeasuredMobileIconLayout
37
38
  iconPosition={direction}
38
39
  tokens={getTokens}
39
40
  dataSet={dataSet}
@@ -16,6 +16,7 @@ import { resolvePressableTokens } from '../utils/pressability'
16
16
  import { withLinkRouter } from '../utils'
17
17
 
18
18
  import InlinePressable from './InlinePressable'
19
+ import MobileIconTextContent from './MobileIconTextContent'
19
20
  import { applyTextStyles, applyOuterBorder, useTheme } from '../ThemeProvider'
20
21
  import { IconText, iconComponentPropTypes } from '../Icon'
21
22
 
@@ -133,6 +134,7 @@ const LinkBase = React.forwardRef(
133
134
  tokens = {},
134
135
  children,
135
136
  dataSet,
137
+ useMeasuredMobileIconLayout = false,
136
138
  accessibilityRole = 'link',
137
139
  ...rawRest
138
140
  },
@@ -171,12 +173,14 @@ const LinkBase = React.forwardRef(
171
173
  const themeTokens = resolveLinkTokens(linkState)
172
174
  const outerBorderStyles = selectOuterBorderStyles(themeTokens)
173
175
  const decorationStyles = selectDecorationStyles(themeTokens)
174
-
175
- const mobileCompensation = null
176
+ const shouldUseMeasuredMobileContent =
177
+ Platform.OS !== 'web' && useMeasuredMobileIconLayout
176
178
 
177
179
  return [
178
180
  outerBorderStyles,
179
- mobileCompensation,
181
+ shouldUseMeasuredMobileContent
182
+ ? staticStyles.measuredMobileOuterBorderCompensation
183
+ : null,
180
184
  blockLeftStyle,
181
185
  decorationStyles,
182
186
  hasIcon && staticStyles.rowContainer
@@ -196,28 +200,50 @@ const LinkBase = React.forwardRef(
196
200
 
197
201
  const isTextOnlyLink = !IconComponent && !icon && accessibilityRole === 'link'
198
202
  const adjustedIconSpace = Platform.OS !== 'web' && isTextOnlyLink ? 0 : iconSpace
203
+ const shouldUseMeasuredMobileContent =
204
+ Platform.OS !== 'web' && useMeasuredMobileIconLayout
205
+ const textBaselineStyle = shouldUseMeasuredMobileContent ? null : staticStyles.baseline
206
+
207
+ const linkTextContent = (
208
+ <Text
209
+ style={[
210
+ textStyles,
211
+ blockTextStyles,
212
+ textBaselineStyle,
213
+ staticStyles.bubblePointerEvents
214
+ ]}
215
+ >
216
+ {typeof children === 'function' ? children(linkState) : children}
217
+ </Text>
218
+ )
219
+
220
+ const sharedIconProps = {
221
+ ...iconProps,
222
+ tokens: iconTokens,
223
+ style: staticStyles.bubblePointerEvents
224
+ }
225
+
226
+ if (shouldUseMeasuredMobileContent) {
227
+ return (
228
+ <MobileIconTextContent
229
+ icon={IconComponent}
230
+ iconPosition={iconPosition}
231
+ space={adjustedIconSpace}
232
+ iconProps={sharedIconProps}
233
+ >
234
+ {linkTextContent}
235
+ </MobileIconTextContent>
236
+ )
237
+ }
199
238
 
200
239
  return (
201
240
  <IconText
202
241
  icon={IconComponent}
203
242
  iconPosition={iconPosition}
204
243
  space={adjustedIconSpace}
205
- iconProps={{
206
- ...iconProps,
207
- tokens: iconTokens,
208
- style: staticStyles.bubblePointerEvents
209
- }}
244
+ iconProps={sharedIconProps}
210
245
  >
211
- <Text
212
- style={[
213
- textStyles,
214
- blockTextStyles,
215
- staticStyles.baseline,
216
- staticStyles.bubblePointerEvents
217
- ]}
218
- >
219
- {typeof children === 'function' ? children(linkState) : children}
220
- </Text>
246
+ {linkTextContent}
221
247
  </IconText>
222
248
  )
223
249
  }}
@@ -280,11 +306,12 @@ const staticStyles = StyleSheet.create({
280
306
  }
281
307
  })
282
308
  },
283
- outerBorderCompensation: {
309
+ measuredMobileOuterBorderCompensation: {
284
310
  ...(Platform.OS !== 'web' && {
285
311
  marginHorizontal: 2,
312
+ marginVertical: 2,
286
313
  paddingHorizontal: Platform.OS === 'android' ? 2 : 0,
287
- paddingTop: Platform.OS === 'android' ? 2 : 0
314
+ paddingVertical: Platform.OS === 'android' ? 2 : 0
288
315
  })
289
316
  }
290
317
  })
@@ -0,0 +1,129 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import { Text, View, StyleSheet } from 'react-native'
4
+
5
+ import Icon, { iconComponentPropTypes } from '../Icon/Icon'
6
+ import { spacingProps } from '../utils'
7
+
8
+ const MobileIconTextContent = React.forwardRef(
9
+ ({ space = 0, iconPosition = 'left', icon: IconComponent, iconProps = {}, children }, ref) => {
10
+ const [translateY, setTranslateY] = React.useState(0)
11
+ const latestTranslateYRef = React.useRef(0)
12
+ const layoutsRef = React.useRef({
13
+ container: null,
14
+ text: null,
15
+ icon: null
16
+ })
17
+
18
+ const applyAlignment = React.useCallback(() => {
19
+ const { container, text, icon } = layoutsRef.current
20
+
21
+ if (!container || !icon || !icon.height) return
22
+
23
+ const targetY = text ? text.y + text.height / 2 : container.height / 2
24
+ const iconY = icon.y + icon.height / 2
25
+ const nextTranslateY = Math.round((targetY - iconY) * 100) / 100
26
+
27
+ if (!Number.isFinite(nextTranslateY)) return
28
+ if (Math.abs(nextTranslateY - latestTranslateYRef.current) < 0.5) return
29
+
30
+ latestTranslateYRef.current = nextTranslateY
31
+ setTranslateY(nextTranslateY)
32
+ }, [])
33
+
34
+ const handleContainerLayout = React.useCallback(
35
+ ({ nativeEvent: { layout } }) => {
36
+ layoutsRef.current.container = layout
37
+ applyAlignment()
38
+ },
39
+ [applyAlignment]
40
+ )
41
+
42
+ const handleTextLayout = React.useCallback(
43
+ ({ nativeEvent: { layout } }) => {
44
+ layoutsRef.current.text = layout
45
+ applyAlignment()
46
+ },
47
+ [applyAlignment]
48
+ )
49
+
50
+ const handleIconLayout = React.useCallback(
51
+ ({ nativeEvent: { layout } }) => {
52
+ layoutsRef.current.icon = layout
53
+ applyAlignment()
54
+ },
55
+ [applyAlignment]
56
+ )
57
+
58
+ const iconContent = IconComponent ? (
59
+ <Icon ref={ref} icon={IconComponent} scalesWithText {...iconProps} />
60
+ ) : null
61
+
62
+ const iconWrapper = IconComponent ? (
63
+ <View
64
+ onLayout={handleIconLayout}
65
+ style={[staticStyles.iconContainer, { transform: [{ translateY }] }]}
66
+ >
67
+ {iconContent}
68
+ </View>
69
+ ) : null
70
+
71
+ if (iconPosition === 'inline') {
72
+ return (
73
+ <Text onLayout={handleContainerLayout}>
74
+ <Text onLayout={handleTextLayout}>{children}</Text>{' '}
75
+ <View style={staticStyles.inlineIconContainer}>{iconWrapper}</View>
76
+ </Text>
77
+ )
78
+ }
79
+
80
+ const iconSpaceStyle = iconPosition === 'left' ? { marginRight: space } : { marginLeft: space }
81
+
82
+ return (
83
+ <View onLayout={handleContainerLayout} style={staticStyles.rowContainer}>
84
+ {iconPosition === 'left' && <View style={iconSpaceStyle}>{iconWrapper}</View>}
85
+ <View onLayout={handleTextLayout}>{children}</View>
86
+ {iconPosition === 'right' && <View style={iconSpaceStyle}>{iconWrapper}</View>}
87
+ </View>
88
+ )
89
+ }
90
+ )
91
+
92
+ MobileIconTextContent.displayName = 'MobileIconTextContent'
93
+
94
+ MobileIconTextContent.propTypes = {
95
+ /**
96
+ * Amount of space between text and icon. Uses the theme spacing scale.
97
+ */
98
+ space: spacingProps.types.spacingValue,
99
+ /**
100
+ * Position of the icon relative to text.
101
+ */
102
+ iconPosition: PropTypes.oneOf(['left', 'right', 'inline']),
103
+ /**
104
+ * A valid UDS icon component imported from a UDS palette.
105
+ */
106
+ icon: PropTypes.elementType,
107
+ /**
108
+ * Props passed to the icon component.
109
+ */
110
+ iconProps: PropTypes.exact(iconComponentPropTypes),
111
+ /**
112
+ * Content rendered alongside the icon.
113
+ */
114
+ children: PropTypes.node
115
+ }
116
+
117
+ const staticStyles = StyleSheet.create({
118
+ rowContainer: {
119
+ flexDirection: 'row'
120
+ },
121
+ iconContainer: {
122
+ alignSelf: 'flex-start'
123
+ },
124
+ inlineIconContainer: {
125
+ position: 'absolute'
126
+ }
127
+ })
128
+
129
+ export default MobileIconTextContent
@@ -262,7 +262,7 @@ const Modal = React.forwardRef(
262
262
  </View>
263
263
  {/* when a modal becomes open its first focusable element is being automatically focused */}
264
264
  {/* and we prefer the close button over backdrop */}
265
- <TouchableWithoutFeedback onPress={isBackdropClickable && handleClose}>
265
+ <TouchableWithoutFeedback onPress={isBackdropClickable ? handleClose : undefined}>
266
266
  <View style={[staticStyles.backdrop, selectBackdropStyles(themeTokens)]} />
267
267
  </TouchableWithoutFeedback>
268
268
  </ScrollView>
@@ -1,9 +1,11 @@
1
1
  import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
 
4
+ import { Platform } from 'react-native'
4
5
  import { useThemeTokens } from '../ThemeProvider'
5
6
  import { useViewport } from '../ViewportProvider'
6
7
  import { getTokensPropType, variantProp } from '../utils'
8
+ import { tagsToRoles } from '../utils/a11y/semantics'
7
9
 
8
10
  import List from '../List'
9
11
  import StackWrap from '../StackView/StackWrap'
@@ -27,6 +29,11 @@ const QuickLinks = React.forwardRef(
27
29
  }
28
30
  )
29
31
 
32
+ const itemAccessibilityRole = Platform.select({
33
+ web: ['ul', 'ol'].includes(tag) ? tagsToRoles.li : undefined,
34
+ default: undefined
35
+ })
36
+
30
37
  const content = (list && (
31
38
  <List ref={ref} tokens={listTokens} showDivider={dividers} tag={tag} {...rest}>
32
39
  {children}
@@ -37,6 +44,7 @@ const QuickLinks = React.forwardRef(
37
44
  gap={stackGap}
38
45
  tokens={{ justifyContent: stackJustify }}
39
46
  tag={tag}
47
+ itemAccessibilityRole={itemAccessibilityRole}
40
48
  {...rest}
41
49
  >
42
50
  {children}
@@ -58,6 +58,7 @@ const StackWrapBox = React.forwardRef(
58
58
  variant,
59
59
  tag,
60
60
  accessibilityRole,
61
+ itemAccessibilityRole,
61
62
  ...rest
62
63
  },
63
64
  ref
@@ -76,7 +77,12 @@ const StackWrapBox = React.forwardRef(
76
77
  const gapSize = useSpacingScale(gap)
77
78
  const offsetStyle = { [offsetSides[direction]]: -1 * gapSize }
78
79
  const boxProps = { [gapSides[direction]]: gap, [spaceSides[direction]]: space }
79
- const content = getStackedContent(children, { direction, space: 0, box: boxProps })
80
+ const content = getStackedContent(children, {
81
+ direction,
82
+ space: 0,
83
+ box: boxProps,
84
+ itemAccessibilityRole
85
+ })
80
86
 
81
87
  return (
82
88
  <View
@@ -119,6 +125,12 @@ StackWrapBox.propTypes = {
119
125
  * is not defined, the accessibilityRole will default to "heading".
120
126
  */
121
127
  tag: PropTypes.oneOf(layoutTags),
128
+ /**
129
+ * Optional accessibility role to apply to each item in the stack.
130
+ * On web, items are wrapped (or cloned) with this role, enabling correct list semantics
131
+ * when the container tag is "ul" or "ol".
132
+ */
133
+ itemAccessibilityRole: PropTypes.string,
122
134
  /**
123
135
  * A StackWrap may take any children, but will have no effect if it is only passed one child or is passed children
124
136
  * wrapped in a component. If necessary, children may be wrapped in one React Fragment.
@@ -37,6 +37,7 @@ const StackWrapGap = React.forwardRef(
37
37
  children,
38
38
  tag,
39
39
  accessibilityRole,
40
+ itemAccessibilityRole,
40
41
  ...rest
41
42
  },
42
43
  ref
@@ -54,7 +55,7 @@ const StackWrapGap = React.forwardRef(
54
55
  const size = useSpacingScale(space)
55
56
  const gapStyle = { gap: size }
56
57
 
57
- const content = getStackedContent(children, { direction, space: 0 })
58
+ const content = getStackedContent(children, { direction, space: 0, itemAccessibilityRole })
58
59
 
59
60
  return (
60
61
  <View
@@ -32,7 +32,7 @@ import Spacer from '../Spacer'
32
32
  */
33
33
  const getStackedContent = (
34
34
  children,
35
- { divider, space, direction = 'column', box, preserveFragments = false }
35
+ { divider, space, direction = 'column', box, preserveFragments = false, itemAccessibilityRole }
36
36
  ) => {
37
37
  const boxProps = box && typeof box === 'object' ? box : { space }
38
38
  const dividerProps = divider && typeof divider === 'object' ? divider : {}
@@ -42,15 +42,29 @@ const getStackedContent = (
42
42
  const validChildren = React.Children.toArray(topLevelChildren).filter(Boolean)
43
43
  const content = validChildren.reduce((newChildren, child, index) => {
44
44
  const boxID = `Stack-Box-${index}`
45
- const item = box ? (
45
+
46
+ let item
47
+ if (box) {
46
48
  // If wrapped in Box, that Box needs a key.
47
49
  // If possible, use an existing content key; use an index-based key only if necessary.
48
- <Box {...boxProps} key={child.key || boxID} testID={boxID}>
49
- {child}
50
- </Box>
51
- ) : (
52
- child
53
- )
50
+ item = (
51
+ <Box
52
+ {...boxProps}
53
+ accessibilityRole={itemAccessibilityRole}
54
+ key={child.key || boxID}
55
+ testID={boxID}
56
+ >
57
+ {child}
58
+ </Box>
59
+ )
60
+ } else if (itemAccessibilityRole) {
61
+ item = React.cloneElement(child, {
62
+ accessibilityRole: itemAccessibilityRole,
63
+ key: child.key || boxID
64
+ })
65
+ } else {
66
+ item = child
67
+ }
54
68
  if (!index || (!space && !divider)) return [...newChildren, item]
55
69
 
56
70
  const testID = `Stack-${divider ? 'Divider' : 'Spacer'}-${index}`
@@ -42,12 +42,24 @@ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, vie
42
42
  * items={items}
43
43
  * initiallySelectedItem="1"
44
44
  * onChange={(itemId) => console.log(itemId)}
45
+ * accessibilityLabel="Main navigation"
45
46
  * />
46
47
  * )
47
48
  */
48
49
 
49
50
  const TabBar = React.forwardRef(
50
- ({ items = [], initiallySelectedItem = '0', onChange, variant, tokens, ...rest }, ref) => {
51
+ (
52
+ {
53
+ items = [],
54
+ initiallySelectedItem = '0',
55
+ onChange,
56
+ variant,
57
+ tokens,
58
+ accessibilityLabel,
59
+ ...rest
60
+ },
61
+ ref
62
+ ) => {
51
63
  const [isSelected, setIsSelected] = React.useState(initiallySelectedItem)
52
64
  const themeTokens = useThemeTokens('TabBar', tokens, variant)
53
65
 
@@ -62,7 +74,11 @@ const TabBar = React.forwardRef(
62
74
  style={[styles.tabBar, selectTabBarContainerStyles(themeTokens)]}
63
75
  {...selectProps(rest)}
64
76
  >
65
- <View style={[styles.tabBarItem, selectTabBarItemContainerStyles(themeTokens)]}>
77
+ <View
78
+ style={[styles.tabBarItem, selectTabBarItemContainerStyles(themeTokens)]}
79
+ accessibilityRole="tablist"
80
+ accessibilityLabel={accessibilityLabel}
81
+ >
66
82
  {items.map((item, index) => (
67
83
  <TabBarItem
68
84
  key={item.id}
@@ -73,7 +89,6 @@ const TabBar = React.forwardRef(
73
89
  iconActive={item.iconActive}
74
90
  onPress={() => handlePress(item.id)}
75
91
  id={`tab-item-${index}`}
76
- accessibilityRole="tablist"
77
92
  tokens={item.tokens}
78
93
  />
79
94
  ))}
@@ -105,7 +120,9 @@ TabBar.propTypes = {
105
120
  /** Variant of TabBar for styling purposes. */
106
121
  variant: variantProp.propType,
107
122
  /** Tokens for theming and styling. */
108
- tokens: getTokensPropType('TabBar')
123
+ tokens: getTokensPropType('TabBar'),
124
+ /** Accessible label for the tab bar navigation region, used by screen readers to identify the tablist. */
125
+ accessibilityLabel: PropTypes.string
109
126
  }
110
127
 
111
128
  const styles = StyleSheet.create({