@telus-uds/components-base 1.1.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 (50) hide show
  1. package/.ultra.cache.json +1 -1
  2. package/CHANGELOG.md +8 -0
  3. package/__fixtures__/Accessible.js +4 -2
  4. package/__fixtures__/Accessible.native.js +5 -2
  5. package/__fixtures__/testTheme.js +9 -0
  6. package/__tests__/HorizontalScroll/HorizontalScroll.test.jsx +1 -0
  7. package/__tests__/ToggleSwitch/ToggleSwitch.test.jsx +10 -0
  8. package/__tests__/ToggleSwitch/ToggleSwitchGroup.test.jsx +192 -0
  9. package/component-docs.json +614 -796
  10. package/lib/Button/ButtonBase.js +20 -6
  11. package/lib/Card/PressableCardBase.js +9 -3
  12. package/lib/Checkbox/Checkbox.js +0 -2
  13. package/lib/IconButton/IconButton.js +8 -3
  14. package/lib/Link/LinkBase.js +10 -3
  15. package/lib/Pagination/PageButton.js +3 -1
  16. package/lib/Pagination/Pagination.js +16 -4
  17. package/lib/Pagination/SideButton.js +3 -1
  18. package/lib/Radio/Radio.js +0 -2
  19. package/lib/Tabs/Tabs.js +12 -4
  20. package/lib/Tabs/TabsItem.js +12 -6
  21. package/lib/ToggleSwitch/ToggleSwitch.js +99 -37
  22. package/lib/ToggleSwitch/ToggleSwitchGroup.js +230 -0
  23. package/lib/ToggleSwitch/index.js +14 -4
  24. package/lib/index.js +13 -8
  25. package/lib/utils/index.js +10 -1
  26. package/lib/utils/propTypes.js +26 -1
  27. package/lib/utils/withLinkRouter.js +98 -0
  28. package/package.json +2 -2
  29. package/release-context.json +4 -4
  30. package/src/Button/ButtonBase.jsx +11 -4
  31. package/src/Card/PressableCardBase.jsx +6 -4
  32. package/src/Checkbox/Checkbox.jsx +0 -2
  33. package/src/IconButton/IconButton.jsx +6 -4
  34. package/src/Link/LinkBase.jsx +6 -4
  35. package/src/Pagination/PageButton.jsx +3 -2
  36. package/src/Pagination/Pagination.jsx +29 -2
  37. package/src/Pagination/SideButton.jsx +2 -2
  38. package/src/Radio/Radio.jsx +0 -2
  39. package/src/Tabs/Tabs.jsx +49 -22
  40. package/src/Tabs/TabsItem.jsx +11 -7
  41. package/src/ToggleSwitch/ToggleSwitch.jsx +92 -34
  42. package/src/ToggleSwitch/ToggleSwitchGroup.jsx +203 -0
  43. package/src/ToggleSwitch/index.js +2 -1
  44. package/src/index.js +1 -1
  45. package/src/utils/index.js +1 -0
  46. package/src/utils/propTypes.js +30 -0
  47. package/src/utils/withLinkRouter.jsx +68 -0
  48. package/stories/TextInput/TextArea.stories.jsx +1 -0
  49. package/stories/ToggleSwitch/ToggleSwitch.stories.jsx +5 -1
  50. package/stories/ToggleSwitch/ToggleSwitchGroup.stories.jsx +81 -0
@@ -6,9 +6,11 @@ import {
6
6
  hrefAttrsProp,
7
7
  variantProp,
8
8
  linkProps,
9
- getTokensPropType
9
+ getTokensPropType,
10
+ clickProps
10
11
  } from '../utils/propTypes'
11
12
  import { resolvePressableTokens } from '../utils/pressability'
13
+ import { withLinkRouter } from '../utils'
12
14
 
13
15
  import InlinePressable from './InlinePressable'
14
16
  import { applyTextStyles, applyOuterBorder } from '../ThemeProvider'
@@ -92,7 +94,6 @@ const LinkBase = forwardRef(
92
94
  (
93
95
  {
94
96
  href,
95
- onPress,
96
97
  icon,
97
98
  iconPosition = icon ? 'left' : undefined,
98
99
  iconProps,
@@ -101,10 +102,11 @@ const LinkBase = forwardRef(
101
102
  children,
102
103
  accessibilityRole = 'link',
103
104
  dataSet,
104
- ...props
105
+ ...rawRest
105
106
  },
106
107
  ref
107
108
  ) => {
109
+ const { onPress, ...props } = clickProps.toPressProps(rawRest)
108
110
  const { hrefAttrs, rest } = hrefAttrsProp.bundle(props)
109
111
  const linkPropSet = linkProps.select({
110
112
  accessibilityRole,
@@ -200,4 +202,4 @@ const staticStyles = StyleSheet.create({
200
202
  }
201
203
  })
202
204
 
203
- export default LinkBase
205
+ export default withLinkRouter(LinkBase)
@@ -10,7 +10,8 @@ import {
10
10
  hrefAttrsProp,
11
11
  linkProps,
12
12
  selectTokens,
13
- variantProp
13
+ variantProp,
14
+ withLinkRouter
14
15
  } from '../utils'
15
16
 
16
17
  import useCopy from '../utils/useCopy'
@@ -66,4 +67,4 @@ PageButton.propTypes = {
66
67
  tokens: getTokensPropType('PaginationPageButton')
67
68
  }
68
69
 
69
- 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'
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({
@@ -0,0 +1,203 @@
1
+ import React, { forwardRef } from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import ABBPropTypes from 'airbnb-prop-types'
4
+ import { Platform } from 'react-native'
5
+
6
+ import ToggleSwitch from './ToggleSwitch'
7
+ import Fieldset from '../Fieldset'
8
+ import { getStackedContent } from '../StackView'
9
+ import { useViewport } from '../ViewportProvider'
10
+ import { useThemeTokens } from '../ThemeProvider'
11
+ import { a11yProps, pressProps, variantProp, getTokensPropType } from '../utils/propTypes'
12
+ import { useMultipleInputValues } from '../utils/input'
13
+
14
+ const ToggleSwitchGroup = forwardRef(
15
+ (
16
+ {
17
+ variant,
18
+ tokens,
19
+ items = [],
20
+ values,
21
+ initialValues,
22
+ maxValues = 1,
23
+ onChange,
24
+ readOnly = false,
25
+ inactive = false,
26
+ feedback,
27
+ hint,
28
+ tooltip,
29
+ legend,
30
+ name: inputGroupName,
31
+ accessibilityRole = maxValues === 1
32
+ ? 'radiogroup' // radiogroup is cross-platform; only web aria has generic groups
33
+ : Platform.select({ web: 'group', default: 'none' }),
34
+ toggleSwitchTokens,
35
+ validation,
36
+ ...rest
37
+ },
38
+ ref
39
+ ) => {
40
+ const viewport = useViewport()
41
+
42
+ const { space, fieldSpace } = useThemeTokens('ToggleSwitchGroup', tokens, variant, {
43
+ viewport
44
+ })
45
+
46
+ const { currentValues, toggleOneValue } = useMultipleInputValues({
47
+ initialValues,
48
+ values,
49
+ maxValues,
50
+ onChange,
51
+ readOnly
52
+ })
53
+
54
+ const a11y = a11yProps.select({
55
+ accessibilityRole,
56
+ ...rest
57
+ })
58
+ const itemA11yRole = a11y.accessibilityRole === 'radiogroup' ? 'radio' : 'switch'
59
+
60
+ const toggleSwitches = items.map(
61
+ (
62
+ {
63
+ label,
64
+ id = label,
65
+ accessibilityLabel = label,
66
+ onChange: itemOnChange,
67
+ ref: itemRef,
68
+ tooltip: itemTooltip
69
+ },
70
+ index
71
+ ) => {
72
+ const isSelected = currentValues.includes(id)
73
+
74
+ const handleChange = (newCheckedState, event) => {
75
+ if (typeof itemOnChange === 'function') itemOnChange(newCheckedState, event)
76
+ toggleOneValue(id, event)
77
+ }
78
+
79
+ const itemA11y = {
80
+ accessibilityState: { checked: isSelected },
81
+ accessibilityRole: itemA11yRole,
82
+ accessibilityLabel,
83
+ ...a11yProps.getPositionInSet(items.length, index)
84
+ }
85
+
86
+ return (
87
+ <ToggleSwitch
88
+ id={id}
89
+ ref={itemRef}
90
+ key={id}
91
+ onChange={handleChange}
92
+ tokens={toggleSwitchTokens}
93
+ value={isSelected}
94
+ inactive={inactive}
95
+ label={label}
96
+ tooltip={itemTooltip}
97
+ {...itemA11y}
98
+ />
99
+ )
100
+ }
101
+ )
102
+
103
+ return (
104
+ <Fieldset
105
+ ref={ref}
106
+ name={inputGroupName}
107
+ legend={legend}
108
+ tooltip={tooltip}
109
+ hint={hint}
110
+ space={fieldSpace}
111
+ feedback={feedback}
112
+ inactive={inactive}
113
+ validation={validation}
114
+ {...a11y}
115
+ >
116
+ {getStackedContent(toggleSwitches, { space, direction: 'column' })}
117
+ </Fieldset>
118
+ )
119
+ }
120
+ )
121
+ ToggleSwitchGroup.displayName = 'ToggleSwitchGroup'
122
+
123
+ ToggleSwitchGroup.propTypes = {
124
+ ...a11yProps.propTypes,
125
+ ...pressProps.propTypes,
126
+ tokens: getTokensPropType('ToggleSwitchGroup'),
127
+ variant: variantProp.propType,
128
+ /**
129
+ * The maximum number of items a user may select at once. Defaults to 1 and behaves
130
+ * like radio buttons. To have no limit and allow any number of selections, pass `null`.
131
+ */
132
+ maxValues: PropTypes.number,
133
+ /**
134
+ * The options a user may select
135
+ */
136
+ items: PropTypes.arrayOf(
137
+ PropTypes.shape({
138
+ /**
139
+ * The text displayed to the user on the label.
140
+ */
141
+ label: PropTypes.string.isRequired,
142
+ /**
143
+ * An optional accessibility label may be passed to each ToggleSwitch
144
+ * and will be applied as normal for a React Native accessibilityLabel prop.
145
+ */
146
+ accessibilityLabel: PropTypes.string,
147
+ /**
148
+ * An optional unique string may be provided to identify this option,
149
+ * which will be used in code and passed to any onChange function.
150
+ * If not provided, the label is used.
151
+ */
152
+ id: PropTypes.string,
153
+ /**
154
+ * An optional ref for one individual ToggleSwitch in the ToggleSwitchGroup
155
+ */
156
+ ref: ABBPropTypes.ref()
157
+ })
158
+ ),
159
+ /**
160
+ * If provided, this function is called when the current selection is changed
161
+ * and is passed an array of the `id`s of all currently selected `items`.
162
+ */
163
+ onChange: PropTypes.func,
164
+ /**
165
+ * If the selected item(s) in the toggle switch group are to be controlled externally by
166
+ * a parent component, pass an array of strings as well as an `onChange` handler.
167
+ * Passing an array for "values" makes the ToggleSwitchGroup a "controlled" component that
168
+ * expects its state to be handled via `onChange` and so doesn't handle it itself.
169
+ */
170
+ values: PropTypes.arrayOf(PropTypes.string),
171
+ /**
172
+ * If `values` is not passed, making the ToggleSwitchGroup an "uncontrolled" component
173
+ * managing its own selected state, a default set of selections may be provided.
174
+ * Changing the `initialValues` does not change the user's selections.
175
+ */
176
+ initialValues: PropTypes.arrayOf(PropTypes.string),
177
+ /**
178
+ * Optional additional text giving more detail to help a user make a choice.
179
+ */
180
+ hint: PropTypes.string,
181
+ /**
182
+ * Optional tooltip text content to include alongside the legend and hint.
183
+ */
184
+ tooltip: PropTypes.string,
185
+ /**
186
+ * If provided, a Feedback element is rendered containing this text.
187
+ */
188
+ feedback: PropTypes.string,
189
+ /**
190
+ * Main text used to describe this group, used in Fieldset's Legend element.
191
+ */
192
+ legend: PropTypes.string,
193
+ /**
194
+ * Toggle switch token overrides.
195
+ */
196
+ toggleSwitchTokens: getTokensPropType('ToggleSwitch'),
197
+ /**
198
+ * Current validation status of the group, passed to the feedback element if there is one.
199
+ */
200
+ validation: PropTypes.oneOf(['error', 'success'])
201
+ }
202
+
203
+ export default ToggleSwitchGroup