@telus-uds/components-base 1.0.0 → 1.2.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 (121) hide show
  1. package/.storybook/main.js +4 -0
  2. package/.storybook/preview.js +37 -0
  3. package/.ultra.cache.json +1 -1
  4. package/CHANGELOG.md +26 -0
  5. package/README.md +1 -1
  6. package/__fixtures__/Accessible.js +4 -2
  7. package/__fixtures__/Accessible.native.js +5 -2
  8. package/__fixtures__/testTheme.js +9 -0
  9. package/__tests__/HorizontalScroll/HorizontalScroll.test.jsx +1 -0
  10. package/__tests__/ToggleSwitch/ToggleSwitch.test.jsx +10 -0
  11. package/__tests__/ToggleSwitch/ToggleSwitchGroup.test.jsx +192 -0
  12. package/babel.config.js +9 -16
  13. package/component-docs.json +10131 -0
  14. package/generate-component-docs.js +56 -0
  15. package/lib/Box/Box.js +1 -0
  16. package/lib/Button/ButtonBase.js +20 -6
  17. package/lib/Card/CardBase.js +1 -0
  18. package/lib/Card/PressableCardBase.js +9 -3
  19. package/lib/Checkbox/Checkbox.js +0 -2
  20. package/lib/FlexGrid/FlexGrid.js +1 -1
  21. package/lib/IconButton/IconButton.js +8 -3
  22. package/lib/Link/LinkBase.js +10 -3
  23. package/lib/List/List.js +1 -2
  24. package/lib/List/ListItem.js +14 -27
  25. package/lib/List/index.js +15 -0
  26. package/lib/Pagination/PageButton.js +4 -8
  27. package/lib/Pagination/Pagination.js +16 -4
  28. package/lib/Pagination/SideButton.js +3 -1
  29. package/lib/Radio/Radio.js +0 -2
  30. package/lib/StackView/StackView.js +1 -0
  31. package/lib/StackView/StackWrap.js +9 -5
  32. package/lib/StackView/StackWrapBox.js +1 -0
  33. package/lib/Tabs/Tabs.js +12 -4
  34. package/lib/Tabs/TabsItem.js +12 -6
  35. package/lib/ToggleSwitch/ToggleSwitch.js +99 -37
  36. package/lib/ToggleSwitch/ToggleSwitchGroup.js +230 -0
  37. package/lib/ToggleSwitch/index.js +14 -4
  38. package/lib/index.js +28 -9
  39. package/lib/utils/a11y/propTypes.js +61 -0
  40. package/lib/utils/a11y/propTypes.native.js +47 -0
  41. package/lib/utils/index.js +10 -1
  42. package/lib/utils/propTypes.js +35 -91
  43. package/lib/utils/withLinkRouter.js +98 -0
  44. package/package.json +10 -6
  45. package/release-context.json +4 -4
  46. package/src/Box/Box.jsx +1 -0
  47. package/src/Button/ButtonBase.jsx +11 -4
  48. package/src/Card/CardBase.jsx +1 -0
  49. package/src/Card/PressableCardBase.jsx +6 -4
  50. package/src/Checkbox/Checkbox.jsx +0 -2
  51. package/src/FlexGrid/FlexGrid.jsx +1 -1
  52. package/src/IconButton/IconButton.jsx +6 -4
  53. package/src/Link/LinkBase.jsx +6 -4
  54. package/src/List/List.jsx +1 -3
  55. package/src/List/ListItem.jsx +11 -26
  56. package/src/List/index.js +5 -0
  57. package/src/Pagination/PageButton.jsx +5 -8
  58. package/src/Pagination/Pagination.jsx +29 -2
  59. package/src/Pagination/SideButton.jsx +2 -2
  60. package/src/Radio/Radio.jsx +0 -2
  61. package/src/StackView/StackView.jsx +1 -0
  62. package/src/StackView/StackWrap.jsx +7 -6
  63. package/src/StackView/StackWrapBox.jsx +1 -0
  64. package/src/Tabs/Tabs.jsx +49 -22
  65. package/src/Tabs/TabsItem.jsx +11 -7
  66. package/src/ToggleSwitch/ToggleSwitch.jsx +92 -34
  67. package/src/ToggleSwitch/ToggleSwitchGroup.jsx +203 -0
  68. package/src/ToggleSwitch/index.js +2 -1
  69. package/src/index.js +2 -2
  70. package/src/utils/a11y/propTypes.js +61 -0
  71. package/src/utils/a11y/propTypes.native.js +39 -0
  72. package/src/utils/index.js +1 -0
  73. package/src/utils/propTypes.js +33 -111
  74. package/src/utils/withLinkRouter.jsx +68 -0
  75. package/stories/A11yText/A11yText.stories.jsx +1 -1
  76. package/stories/ActivityIndicator/ActivityIndicator.stories.jsx +1 -1
  77. package/stories/Box/Box.stories.jsx +1 -1
  78. package/stories/Button/Button.stories.jsx +1 -1
  79. package/stories/Button/ButtonGroup.stories.jsx +1 -1
  80. package/stories/Button/ButtonLink.stories.jsx +1 -1
  81. package/stories/Card/Card.stories.jsx +1 -1
  82. package/stories/Checkbox/Checkbox.stories.jsx +1 -1
  83. package/stories/Divider/Divider.stories.jsx +1 -1
  84. package/stories/ExpandCollapse/ExpandCollapse.stories.jsx +1 -1
  85. package/stories/Feedback/Feedback.stories.jsx +1 -1
  86. package/stories/FlexGrid/01 FlexGrid.stories.jsx +1 -1
  87. package/stories/FlexGrid/02 Row.stories.jsx +1 -1
  88. package/stories/FlexGrid/03 Col.stories.jsx +1 -1
  89. package/stories/Icon/Icon.stories.jsx +1 -1
  90. package/stories/IconButton/IconButton.stories.jsx +1 -1
  91. package/stories/InputLabel/InputLabel.stories.jsx +1 -1
  92. package/stories/Link/ChevronLink.stories.jsx +1 -1
  93. package/stories/Link/Link.stories.jsx +1 -1
  94. package/stories/Link/TextButton.stories.jsx +1 -1
  95. package/stories/List/List.stories.jsx +1 -1
  96. package/stories/Modal/Modal.stories.jsx +1 -1
  97. package/stories/Notification/Notification.stories.jsx +1 -1
  98. package/stories/Pagination/Pagination.stories.jsx +1 -1
  99. package/stories/Progress/Progress.stories.jsx +1 -1
  100. package/stories/Radio/Radio.stories.jsx +1 -1
  101. package/stories/RadioCard/RadioCard.stories.jsx +1 -1
  102. package/stories/Search/Search.stories.jsx +1 -1
  103. package/stories/Select/Select.stories.jsx +1 -1
  104. package/stories/SideNav/SideNav.stories.jsx +1 -1
  105. package/stories/SideNav/SideNavItem.stories.jsx +1 -1
  106. package/stories/SideNav/SideNavItemsGroup.stories.jsx +1 -1
  107. package/stories/Skeleton/Skeleton.stories.jsx +1 -1
  108. package/stories/Spacer/Spacer.stories.jsx +1 -1
  109. package/stories/StackView/StackView.stories.jsx +1 -1
  110. package/stories/StackView/StackWrap.stories.jsx +1 -1
  111. package/stories/StepTracker/StepTracker.stories.jsx +1 -1
  112. package/stories/Tabs/Tabs.stories.jsx +1 -1
  113. package/stories/Tags/Tags.stories.jsx +1 -1
  114. package/stories/TextInput/TextArea.stories.jsx +2 -1
  115. package/stories/TextInput/TextInput.stories.jsx +1 -1
  116. package/stories/ToggleSwitch/ToggleSwitch.stories.jsx +6 -2
  117. package/stories/ToggleSwitch/ToggleSwitchGroup.stories.jsx +81 -0
  118. package/stories/Tooltip/Tooltip.stories.jsx +1 -1
  119. package/stories/TooltipButton/TooltipButton.stories.jsx +1 -1
  120. package/stories/Typography/Typography.stories.jsx +1 -1
  121. package/stories/supports.jsx +2 -3
@@ -8,8 +8,10 @@ import {
8
8
  copyPropTypes,
9
9
  getTokensPropType,
10
10
  hrefAttrsProp,
11
+ linkProps,
11
12
  selectTokens,
12
- variantProp
13
+ variantProp,
14
+ withLinkRouter
13
15
  } from '../utils'
14
16
 
15
17
  import useCopy from '../utils/useCopy'
@@ -57,12 +59,7 @@ const PageButton = forwardRef(
57
59
  PageButton.displayName = 'PageButton'
58
60
 
59
61
  PageButton.propTypes = {
60
- // Spreading any props into a secondary component accessed like Pagination.PageButton
61
- // crashes a Docusaurus props table, but only in production, not in development
62
- onPress: PropTypes.func,
63
- href: PropTypes.string,
64
- // If the above is fixed, the above can be replaced with this which includes full a11y etc:
65
- // ...linkProps.types,
62
+ ...linkProps.types,
66
63
  label: PropTypes.string,
67
64
  isActive: PropTypes.bool,
68
65
  copy: copyPropTypes,
@@ -70,4 +67,4 @@ PageButton.propTypes = {
70
67
  tokens: getTokensPropType('PaginationPageButton')
71
68
  }
72
69
 
73
- export default PageButton
70
+ export default withLinkRouter(PageButton)
@@ -1,7 +1,13 @@
1
1
  import React, { forwardRef } from 'react'
2
2
  import { View, Text, StyleSheet } from 'react-native'
3
3
 
4
- import { componentPropType, copyPropTypes, getTokensPropType, variantProp } from '../utils'
4
+ import {
5
+ componentPropType,
6
+ copyPropTypes,
7
+ getTokensPropType,
8
+ variantProp,
9
+ withLinkRouter
10
+ } from '../utils'
5
11
  import { applyTextStyles, useThemeTokens } from '../ThemeProvider'
6
12
  import { useViewport } from '../ViewportProvider'
7
13
  import Box from '../Box'
@@ -20,7 +26,19 @@ const selectTextStyles = ({ color, fontName, fontSize, fontWeight, lineHeight })
20
26
  })
21
27
 
22
28
  const Pagination = forwardRef(
23
- ({ children, copy = 'en', variant, tokens, sideButtonVariant, sideButtonTokens }, ref) => {
29
+ (
30
+ {
31
+ children,
32
+ copy = 'en',
33
+ variant,
34
+ tokens,
35
+ sideButtonVariant,
36
+ sideButtonTokens,
37
+ LinkRouter,
38
+ linkRouterProps
39
+ },
40
+ ref
41
+ ) => {
24
42
  const viewport = useViewport()
25
43
  const { truncateAbove, gap, ...themeTokens } = useThemeTokens('Pagination', tokens, variant, {
26
44
  viewport
@@ -58,16 +76,22 @@ const Pagination = forwardRef(
58
76
  copy={copy}
59
77
  variant={sideButtonVariant}
60
78
  tokens={sideButtonTokens}
79
+ LinkRouter={LinkRouter}
80
+ linkRouterProps={linkRouterProps}
61
81
  />
62
82
  ),
63
83
  ...items.map((child, itemIndex) => {
64
84
  const buttonLabel = `${itemIndex + 1}`
65
85
  const itemProps = getItemProps(itemIndex)
86
+ const ItemLinkRouter = itemProps.LinkRouter ?? LinkRouter
87
+ const itemLinkRouterProps = { ...linkRouterProps, ...itemProps.linkRouterProps }
66
88
 
67
89
  if (shouldRenderButton(itemIndex)) {
68
90
  return (
69
91
  <PageButton
70
92
  {...itemProps}
93
+ LinkRouter={ItemLinkRouter}
94
+ linkRouterProps={itemLinkRouterProps}
71
95
  label={buttonLabel}
72
96
  copy={copy}
73
97
  isActive={isItemActive(itemIndex)}
@@ -88,6 +112,8 @@ const Pagination = forwardRef(
88
112
  copy={copy}
89
113
  variant={sideButtonVariant}
90
114
  tokens={sideButtonTokens}
115
+ LinkRouter={LinkRouter}
116
+ linkRouterProps={linkRouterProps}
91
117
  />
92
118
  )
93
119
  ]
@@ -112,6 +138,7 @@ PageButton.displayName = 'PageButton'
112
138
  Pagination.PageButton = PageButton
113
139
 
114
140
  Pagination.propTypes = {
141
+ ...withLinkRouter.propTypes,
115
142
  children: componentPropType('PageButton'),
116
143
  copy: copyPropTypes,
117
144
  variant: variantProp.propType,
@@ -7,7 +7,7 @@ import ButtonBase from '../Button/ButtonBase'
7
7
  import { IconText } from '../Icon'
8
8
  import { useThemeTokensCallback } from '../ThemeProvider'
9
9
  import { useViewport } from '../ViewportProvider'
10
- import { copyPropTypes, hrefAttrsProp, linkProps, selectTokens } from '../utils'
10
+ import { copyPropTypes, hrefAttrsProp, linkProps, selectTokens, withLinkRouter } from '../utils'
11
11
 
12
12
  import dictionary from './dictionary'
13
13
  import useCopy from '../utils/useCopy'
@@ -82,4 +82,4 @@ SideButton.propTypes = {
82
82
  ...linkProps.types
83
83
  }
84
84
 
85
- export default SideButton
85
+ export default withLinkRouter(SideButton)
@@ -2,8 +2,6 @@ import React, { forwardRef } from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import { Pressable, StyleSheet, Text, View } from 'react-native'
4
4
 
5
- // @todo move `LabelContent` outside of the `InputLabel` and fix
6
- // the issue with the cursor not being pointer on Web
7
5
  import RadioLabel from '../InputLabel/LabelContent'
8
6
  import RadioButton, { selectRadioButtonTokens } from './RadioButton'
9
7
  import { applyShadowToken, applyTextStyles, useThemeTokensCallback } from '../ThemeProvider'
@@ -98,6 +98,7 @@ StackView.displayName = 'StackView'
98
98
 
99
99
  StackView.propTypes = {
100
100
  ...a11yProps.propTypes,
101
+ ...viewProps.types,
101
102
  tokens: getTokensPropType('StackView'),
102
103
  variant: variantProp.propType,
103
104
  /**
@@ -4,6 +4,12 @@ import { Platform } from 'react-native'
4
4
  import StackWrapBox from './StackWrapBox'
5
5
  import StackWrapGap from './StackWrapGap'
6
6
 
7
+ // In Jest/CI/SSR, global CSS isn't always available and doesn't always have .supports method
8
+ const cssSupports = (...args) =>
9
+ typeof window !== 'undefined' &&
10
+ typeof window.CSS?.supports === 'function' &&
11
+ window.CSS.supports(...args)
12
+
7
13
  // CSS.supports needs an example of the type of value you intend to use.
8
14
  // Will be an integer appended `px` after hooks and JSX styles are resolved.
9
15
  const exampleGapValue = '1px'
@@ -20,12 +26,7 @@ const StackWrap = forwardRef((props, ref) => {
20
26
  // Don't apply separate gap if `null` or `undefined`, so can be unset in Storybook etc
21
27
  const gap = props.gap ?? space
22
28
 
23
- const canUseCSSGap =
24
- Platform.OS === 'web' &&
25
- gap === space &&
26
- // In Jest/CI, global CSS isn't always available and doesn't always have .supports method
27
- typeof CSS?.supports === 'function' &&
28
- CSS.supports('gap', exampleGapValue)
29
+ const canUseCSSGap = Platform.OS === 'web' && gap === space && cssSupports('gap', exampleGapValue)
29
30
 
30
31
  return canUseCSSGap ? (
31
32
  // If possible, use the cleaner implementation that applies CSS `gap` styles to the container.
@@ -91,6 +91,7 @@ StackWrapBox.displayName = 'StackWrapBox'
91
91
 
92
92
  StackWrapBox.propTypes = {
93
93
  ...a11yProps.propTypes,
94
+ ...viewProps.types,
94
95
  tokens: getTokensPropType('StackView'),
95
96
  /**
96
97
  * Sets the `flexDirection` of the container
package/src/Tabs/Tabs.jsx CHANGED
@@ -4,7 +4,7 @@ import ABBPropTypes from 'airbnb-prop-types'
4
4
 
5
5
  import { useThemeTokens } from '../ThemeProvider'
6
6
  import StackView from '../StackView'
7
- import { getTokensPropType, variantProp, useHash, useInputValue } from '../utils'
7
+ import { getTokensPropType, variantProp, useHash, useInputValue, withLinkRouter } from '../utils'
8
8
  import HorizontalScroll, {
9
9
  horizontalScrollUtils,
10
10
  HorizontalScrollButton
@@ -19,7 +19,18 @@ const { selectHorizontalScrollTokens, useItemPositions } = horizontalScrollUtils
19
19
  */
20
20
  const Tabs = forwardRef(
21
21
  (
22
- { tokens, itemTokens, scrollButtonTokens, variant, value, initialValue, onChange, items = [] },
22
+ {
23
+ tokens,
24
+ itemTokens,
25
+ scrollButtonTokens,
26
+ variant,
27
+ value,
28
+ initialValue,
29
+ onChange,
30
+ items = [],
31
+ LinkRouter,
32
+ linkRouterProps
33
+ },
23
34
  ref
24
35
  ) => {
25
36
  const { space, ...themeTokens } = useThemeTokens('Tabs', tokens, variant)
@@ -49,26 +60,40 @@ const Tabs = forwardRef(
49
60
  accessibilityRole="tablist"
50
61
  >
51
62
  <StackView space={space} direction="row">
52
- {items.map(({ href, label, id, ref: itemRef }, index) => {
53
- const itemId = id ?? label
54
- const isSelected = Boolean(currentValue && currentValue === itemId)
55
- const handlePress = (event) => setValue(itemId, event)
56
- return (
57
- <TabsItem
58
- ref={itemRef}
59
- key={itemId}
60
- href={href}
61
- variant={variant}
62
- tokens={itemTokens}
63
- onPress={handlePress}
64
- selected={isSelected}
65
- itemPositions={itemPositions}
66
- index={index}
67
- >
68
- {label}
69
- </TabsItem>
70
- )
71
- })}
63
+ {items.map(
64
+ (
65
+ {
66
+ href,
67
+ label,
68
+ id,
69
+ ref: itemRef,
70
+ LinkRouter: ItemLinkRouter = LinkRouter,
71
+ linkRouterProps: itemLinkRouterProps
72
+ },
73
+ index
74
+ ) => {
75
+ const itemId = id ?? label
76
+ const isSelected = Boolean(currentValue && currentValue === itemId)
77
+ const handlePress = (event) => setValue(itemId, event)
78
+ return (
79
+ <TabsItem
80
+ ref={itemRef}
81
+ key={itemId}
82
+ href={href}
83
+ variant={variant}
84
+ tokens={itemTokens}
85
+ onPress={handlePress}
86
+ selected={isSelected}
87
+ itemPositions={itemPositions}
88
+ index={index}
89
+ LinkRouter={ItemLinkRouter}
90
+ linkRouterProps={{ ...linkRouterProps, ...itemLinkRouterProps }}
91
+ >
92
+ {label}
93
+ </TabsItem>
94
+ )
95
+ }
96
+ )}
72
97
  </StackView>
73
98
  </HorizontalScroll>
74
99
  )
@@ -77,8 +102,10 @@ const Tabs = forwardRef(
77
102
  Tabs.displayName = 'Tabs'
78
103
 
79
104
  Tabs.propTypes = {
105
+ ...withLinkRouter.PropTypes,
80
106
  items: PropTypes.arrayOf(
81
107
  PropTypes.shape({
108
+ ...withLinkRouter.PropTypes,
82
109
  href: PropTypes.string,
83
110
  label: PropTypes.string,
84
111
  id: PropTypes.string,
@@ -9,7 +9,9 @@ import {
9
9
  variantProp,
10
10
  getTokensPropType,
11
11
  linkProps,
12
- a11yProps
12
+ a11yProps,
13
+ clickProps,
14
+ withLinkRouter
13
15
  } from '../utils'
14
16
  import Spacer from '../Spacer'
15
17
  import { horizontalScrollUtils } from '../HorizontalScroll'
@@ -73,7 +75,6 @@ const selectContainerStyles = ({
73
75
  const TabsItem = forwardRef(
74
76
  (
75
77
  {
76
- onPress,
77
78
  href,
78
79
  variant,
79
80
  tokens,
@@ -86,10 +87,13 @@ const TabsItem = forwardRef(
86
87
  ? // Web links can't be aria-selected but can be aria-current
87
88
  { current: selected ? 'page' : false }
88
89
  : { selected },
89
- ...rest
90
+ ...rawRest
90
91
  },
91
92
  ref
92
93
  ) => {
94
+ // Convert onClick etc to onPress etc if used in an integration
95
+ const { onPress, ...rest } = clickProps.toPressProps(rawRest)
96
+
93
97
  const getTokens = useThemeTokensCallback('TabsItem', tokens, variant)
94
98
  const resolveTokens = (pressableState) =>
95
99
  resolvePressableTokens(getTokens, pressableState, { selected })
@@ -105,9 +109,9 @@ const TabsItem = forwardRef(
105
109
  const openHref = href && linkProps.handleHref({ href })
106
110
  const handlePress =
107
111
  onPress || openHref
108
- ? () => {
109
- if (onPress) onPress()
110
- if (openHref) openHref()
112
+ ? (...args) => {
113
+ if (onPress) onPress(...args)
114
+ if (openHref) openHref(...args)
111
115
  }
112
116
  : undefined
113
117
 
@@ -209,4 +213,4 @@ const staticStyles = StyleSheet.create({
209
213
  }
210
214
  })
211
215
 
212
- export default TabsItem
216
+ export default withLinkRouter(TabsItem)
@@ -1,8 +1,10 @@
1
1
  import React, { forwardRef } from 'react'
2
2
  import PropTypes from 'prop-types'
3
- import { Platform, View, StyleSheet } from 'react-native'
3
+ import { Platform, StyleSheet, View } from 'react-native'
4
4
 
5
+ import InputLabel from '../InputLabel'
5
6
  import ButtonBase from '../Button/ButtonBase'
7
+ import StackView from '../StackView'
6
8
  import { useThemeTokensCallback, applyShadowToken } from '../ThemeProvider'
7
9
  import {
8
10
  a11yProps,
@@ -12,6 +14,7 @@ import {
12
14
  selectTokens
13
15
  } from '../utils/propTypes'
14
16
  import { useInputValue } from '../utils/input'
17
+ import { useUniqueId } from '../utils'
15
18
 
16
19
  const selectButtonTokens = (tokens) =>
17
20
  selectTokens('Button', {
@@ -54,12 +57,40 @@ const selectSwitchStyles = ({
54
57
  })
55
58
  })
56
59
 
60
+ const selectLabelStyles = ({ labelMarginLeft }) => ({ marginLeft: labelMarginLeft })
61
+ const selectLabelTokens = ({
62
+ labelColor,
63
+ labelFontName,
64
+ labelFontSize,
65
+ labelFontWeight,
66
+ labelLineHeight
67
+ }) => ({
68
+ color: labelColor,
69
+ fontName: labelFontName,
70
+ fontWeight: labelFontWeight,
71
+ fontSize: labelFontSize,
72
+ lineHeight: labelLineHeight
73
+ })
74
+
57
75
  const ToggleSwitch = forwardRef(
58
76
  (
59
- { value, initialValue, onChange, inactive, tokens, variant, accessibilityRole = 'switch' },
77
+ {
78
+ value,
79
+ initialValue,
80
+ onChange,
81
+ id,
82
+ label,
83
+ inactive,
84
+ tokens,
85
+ tooltip,
86
+ variant,
87
+ accessibilityRole = 'switch',
88
+ accessibilityLabel = label
89
+ },
60
90
  ref
61
91
  ) => {
62
92
  const getTokens = useThemeTokensCallback('ToggleSwitch', tokens, variant)
93
+ const themeTokens = getTokens()
63
94
 
64
95
  const { currentValue, setValue } = useInputValue({
65
96
  value,
@@ -68,43 +99,58 @@ const ToggleSwitch = forwardRef(
68
99
  })
69
100
 
70
101
  const handlePress = (event) => setValue(!currentValue, event)
71
-
72
102
  const getButtonTokens = (buttonState) => selectButtonTokens(getTokens(buttonState))
103
+ const uniqueId = useUniqueId('toggleSwitch')
104
+ const inputId = id ?? uniqueId
73
105
 
74
106
  return (
75
- <ButtonBase
76
- ref={ref}
77
- selected={currentValue}
78
- inactive={inactive}
79
- tokens={getButtonTokens}
80
- accessibilityRole={accessibilityRole}
81
- accessibilityState={{ checked: currentValue }}
82
- onPress={handlePress}
83
- >
84
- {(buttonState) => {
85
- const themeTokens = getTokens(buttonState)
86
- const IconComponent = themeTokens.icon
87
- const switchStyles = selectSwitchStyles(themeTokens)
88
- const trackStyles = selectTrackStyles(themeTokens)
89
- const iconTokens = selectIconTokens(themeTokens)
107
+ <StackView space={2} direction="row">
108
+ {Boolean(label) && (
109
+ <View style={selectLabelStyles(themeTokens)}>
110
+ <InputLabel
111
+ forId={inputId}
112
+ label={label}
113
+ tokens={selectLabelTokens(themeTokens)}
114
+ tooltip={tooltip}
115
+ />
116
+ </View>
117
+ )}
118
+ <ButtonBase
119
+ id={id}
120
+ ref={ref}
121
+ selected={currentValue}
122
+ inactive={inactive}
123
+ tokens={getButtonTokens}
124
+ accessibilityLabel={accessibilityLabel}
125
+ accessibilityRole={accessibilityRole}
126
+ accessibilityState={{ checked: currentValue }}
127
+ onPress={handlePress}
128
+ >
129
+ {(buttonState) => {
130
+ const stateTokens = getTokens(buttonState)
131
+ const IconComponent = stateTokens.icon
132
+ const switchStyles = selectSwitchStyles(stateTokens)
133
+ const trackStyles = selectTrackStyles(stateTokens)
134
+ const iconTokens = selectIconTokens(stateTokens)
90
135
 
91
- // If drag-slide support is needed, use a PanResponder and apply these to an Animated value.
92
- // Use translate transforms for smoothest non-thread-blocking animations and to allow drag.
93
- const slideStart = 0
94
- const slideEnd =
95
- themeTokens.width - themeTokens.switchSize - themeTokens.trackBorderWidth * 2
96
- const switchOffset = buttonState.selected ? slideEnd : slideStart
97
- const switchPositionStyle = { transform: [{ translateX: switchOffset }] }
136
+ // If drag-slide support is needed, use a PanResponder and apply these to an Animated value.
137
+ // Use translate transforms for smoothest non-thread-blocking animations and to allow drag.
138
+ const slideStart = 0
139
+ const slideEnd =
140
+ stateTokens.width - stateTokens.switchSize - stateTokens.trackBorderWidth * 2
141
+ const switchOffset = buttonState.selected ? slideEnd : slideStart
142
+ const switchPositionStyle = { transform: [{ translateX: switchOffset }] }
98
143
 
99
- return (
100
- <View style={[staticStyles.track, trackStyles]}>
101
- <View style={[staticStyles.switch, switchStyles, switchPositionStyle]}>
102
- {IconComponent && <IconComponent {...iconTokens} />}
144
+ return (
145
+ <View style={[staticStyles.track, trackStyles]}>
146
+ <View style={[staticStyles.switch, switchStyles, switchPositionStyle]}>
147
+ {IconComponent && <IconComponent {...iconTokens} />}
148
+ </View>
103
149
  </View>
104
- </View>
105
- )
106
- }}
107
- </ButtonBase>
150
+ )
151
+ }}
152
+ </ButtonBase>
153
+ </StackView>
108
154
  )
109
155
  }
110
156
  )
@@ -131,11 +177,23 @@ ToggleSwitch.propTypes = {
131
177
  * this should always be passed and used to control the state of the switch.
132
178
  */
133
179
  onChange: PropTypes.func,
180
+ /**
181
+ * Input ID.
182
+ */
183
+ id: PropTypes.string,
184
+ /**
185
+ * An optional label.
186
+ */
187
+ label: PropTypes.string,
134
188
  /**
135
189
  * If passed, the switch does not respond to user input and may recieve different
136
190
  * theme tokens if the theme supports inactive appearance.
137
191
  */
138
- inactive: PropTypes.bool
192
+ inactive: PropTypes.bool,
193
+ /**
194
+ * Content of an optional Tooltip. If set, a tooltip button will be shown next to the label.
195
+ */
196
+ tooltip: PropTypes.string
139
197
  }
140
198
 
141
199
  const staticStyles = StyleSheet.create({