@telus-uds/components-base 1.0.1 → 1.3.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.
- package/.storybook/main.js +4 -0
- package/.storybook/preview.js +37 -0
- package/.turbo/turbo-build.log +5 -0
- package/CHANGELOG.md +32 -0
- package/README.md +1 -1
- package/__fixtures__/Accessible.js +4 -2
- package/__fixtures__/Accessible.native.js +5 -2
- package/__fixtures__/testTheme.js +9 -0
- package/__tests__/FlexGrid/Col.test.jsx +6 -10
- package/__tests__/HorizontalScroll/HorizontalScroll.test.jsx +1 -0
- package/__tests__/ToggleSwitch/ToggleSwitch.test.jsx +10 -0
- package/__tests__/ToggleSwitch/ToggleSwitchGroup.test.jsx +192 -0
- package/__tests__/utils/props.test.js +36 -0
- package/__tests__/utils/semantics.test.jsx +1 -10
- package/babel.config.js +9 -16
- package/component-docs.json +10142 -0
- package/generate-component-docs.js +59 -0
- package/lib/A11yText/index.js +2 -2
- package/lib/ActivityIndicator/index.js +3 -3
- package/lib/Box/Box.js +4 -4
- package/lib/Button/Button.js +2 -2
- package/lib/Button/ButtonBase.js +20 -6
- package/lib/Button/ButtonGroup.js +10 -12
- package/lib/Button/ButtonLink.js +4 -4
- package/lib/Button/propTypes.js +4 -2
- package/lib/Card/Card.js +2 -2
- package/lib/Card/CardBase.js +6 -9
- package/lib/Card/PressableCardBase.js +12 -6
- package/lib/Checkbox/Checkbox.js +3 -5
- package/lib/Divider/Divider.js +2 -2
- package/lib/FlexGrid/FlexGrid.js +4 -4
- package/lib/FlexGrid/helpers/index.js +1 -4
- package/lib/IconButton/IconButton.js +11 -6
- package/lib/Link/LinkBase.js +19 -12
- package/lib/List/List.js +4 -5
- package/lib/List/ListItem.js +14 -27
- package/lib/List/index.js +15 -0
- package/lib/Pagination/PageButton.js +4 -8
- package/lib/Pagination/Pagination.js +16 -4
- package/lib/Pagination/SideButton.js +3 -1
- package/lib/Progress/Progress.js +2 -2
- package/lib/Progress/ProgressBar.js +2 -2
- package/lib/Radio/Radio.js +3 -5
- package/lib/Spacer/Spacer.js +2 -2
- package/lib/StackView/StackWrap.js +9 -5
- package/lib/StackView/getStackedContent.js +1 -1
- package/lib/StepTracker/StepTracker.js +2 -2
- package/lib/Tabs/Tabs.js +12 -4
- package/lib/Tabs/TabsItem.js +12 -6
- package/lib/Tags/Tags.js +9 -9
- package/lib/ThemeProvider/useThemeTokens.js +3 -3
- package/lib/ThemeProvider/utils/theme-tokens.js +3 -3
- package/lib/ToggleSwitch/ToggleSwitch.js +105 -43
- package/lib/ToggleSwitch/ToggleSwitchGroup.js +230 -0
- package/lib/ToggleSwitch/index.js +14 -4
- package/lib/index.js +28 -9
- package/lib/utils/a11y/semantics.js +4 -3
- package/lib/utils/index.js +14 -5
- package/lib/utils/pressability.js +2 -2
- package/lib/utils/props/a11yProps.js +153 -0
- package/lib/utils/props/clickProps.js +36 -0
- package/lib/utils/props/componentPropType.js +70 -0
- package/lib/utils/props/copyPropTypes.js +14 -0
- package/lib/utils/props/getPropSelector.js +13 -0
- package/lib/utils/props/hrefAttrsProp.js +41 -0
- package/lib/utils/props/index.js +149 -0
- package/lib/utils/props/linkProps.js +64 -0
- package/lib/utils/props/paddingProp.js +20 -0
- package/lib/utils/props/pressProps.js +57 -0
- package/lib/utils/props/rectProp.js +20 -0
- package/lib/utils/props/responsiveProps.js +40 -0
- package/lib/utils/props/selectSystemProps.js +31 -0
- package/lib/utils/props/spacingProps.js +71 -0
- package/lib/utils/props/tokens.js +145 -0
- package/lib/utils/props/variantProp.js +28 -0
- package/lib/utils/props/viewProps.js +34 -0
- package/lib/utils/useResponsiveProp.js +1 -1
- package/lib/utils/useSpacingScale.js +4 -4
- package/lib/utils/withLinkRouter.js +98 -0
- package/package.json +9 -5
- package/release-context.json +4 -4
- package/src/A11yText/index.jsx +1 -1
- package/src/ActivityIndicator/index.jsx +1 -1
- package/src/Box/Box.jsx +5 -4
- package/src/Button/Button.jsx +1 -1
- package/src/Button/ButtonBase.jsx +11 -4
- package/src/Button/ButtonGroup.jsx +17 -8
- package/src/Button/ButtonLink.jsx +1 -1
- package/src/Button/propTypes.js +2 -1
- package/src/Card/Card.jsx +1 -1
- package/src/Card/CardBase.jsx +6 -5
- package/src/Card/PressableCardBase.jsx +7 -5
- package/src/Checkbox/Checkbox.jsx +1 -3
- package/src/Divider/Divider.jsx +2 -2
- package/src/FlexGrid/FlexGrid.jsx +11 -5
- package/src/FlexGrid/helpers/index.js +1 -3
- package/src/IconButton/IconButton.jsx +7 -5
- package/src/Link/LinkBase.jsx +7 -5
- package/src/List/List.jsx +2 -4
- package/src/List/ListItem.jsx +11 -26
- package/src/List/index.js +5 -0
- package/src/Pagination/PageButton.jsx +5 -8
- package/src/Pagination/Pagination.jsx +29 -2
- package/src/Pagination/SideButton.jsx +2 -2
- package/src/Progress/Progress.jsx +1 -1
- package/src/Progress/ProgressBar.jsx +1 -1
- package/src/Radio/Radio.jsx +1 -3
- package/src/Spacer/Spacer.jsx +2 -2
- package/src/StackView/StackWrap.jsx +7 -6
- package/src/StackView/getStackedContent.jsx +1 -1
- package/src/StepTracker/StepTracker.jsx +1 -1
- package/src/Tabs/Tabs.jsx +49 -22
- package/src/Tabs/TabsItem.jsx +11 -7
- package/src/Tags/Tags.jsx +1 -7
- package/src/ThemeProvider/useThemeTokens.js +3 -3
- package/src/ThemeProvider/utils/theme-tokens.js +3 -3
- package/src/ToggleSwitch/ToggleSwitch.jsx +93 -41
- package/src/ToggleSwitch/ToggleSwitchGroup.jsx +203 -0
- package/src/ToggleSwitch/index.js +2 -1
- package/src/index.js +2 -2
- package/src/utils/a11y/semantics.js +3 -2
- package/src/utils/index.js +2 -1
- package/src/utils/pressability.js +1 -1
- package/src/utils/props/a11yProps.js +151 -0
- package/src/utils/props/clickProps.js +31 -0
- package/src/utils/props/componentPropType.js +67 -0
- package/src/utils/props/copyPropTypes.js +3 -0
- package/src/utils/props/getPropSelector.js +14 -0
- package/src/utils/props/hrefAttrsProp.js +25 -0
- package/src/utils/props/index.js +15 -0
- package/src/utils/props/linkProps.js +43 -0
- package/src/utils/props/paddingProp.js +10 -0
- package/src/utils/props/pressProps.js +45 -0
- package/src/utils/props/rectProp.js +10 -0
- package/src/utils/props/responsiveProps.js +30 -0
- package/src/utils/props/selectSystemProps.js +25 -0
- package/src/utils/props/spacingProps.js +58 -0
- package/src/utils/props/tokens.js +150 -0
- package/src/utils/props/variantProp.js +20 -0
- package/src/utils/props/viewProps.js +23 -0
- package/src/utils/useResponsiveProp.js +1 -1
- package/src/utils/useSpacingScale.js +4 -4
- package/src/utils/withLinkRouter.jsx +68 -0
- package/stories/A11yText/A11yText.stories.jsx +1 -1
- package/stories/ActivityIndicator/ActivityIndicator.stories.jsx +1 -1
- package/stories/Box/Box.stories.jsx +1 -1
- package/stories/Button/Button.stories.jsx +1 -1
- package/stories/Button/ButtonGroup.stories.jsx +1 -1
- package/stories/Button/ButtonLink.stories.jsx +1 -1
- package/stories/Card/Card.stories.jsx +1 -1
- package/stories/Checkbox/Checkbox.stories.jsx +1 -1
- package/stories/Divider/Divider.stories.jsx +1 -1
- package/stories/ExpandCollapse/ExpandCollapse.stories.jsx +1 -1
- package/stories/Feedback/Feedback.stories.jsx +1 -1
- package/stories/FlexGrid/01 FlexGrid.stories.jsx +1 -1
- package/stories/FlexGrid/02 Row.stories.jsx +1 -1
- package/stories/FlexGrid/03 Col.stories.jsx +1 -1
- package/stories/Icon/Icon.stories.jsx +1 -1
- package/stories/IconButton/IconButton.stories.jsx +1 -1
- package/stories/InputLabel/InputLabel.stories.jsx +1 -1
- package/stories/Link/ChevronLink.stories.jsx +1 -1
- package/stories/Link/Link.stories.jsx +1 -1
- package/stories/Link/TextButton.stories.jsx +1 -1
- package/stories/List/List.stories.jsx +1 -1
- package/stories/Modal/Modal.stories.jsx +1 -1
- package/stories/Notification/Notification.stories.jsx +1 -1
- package/stories/Pagination/Pagination.stories.jsx +1 -1
- package/stories/Progress/Progress.stories.jsx +1 -1
- package/stories/Radio/Radio.stories.jsx +1 -1
- package/stories/RadioCard/RadioCard.stories.jsx +1 -1
- package/stories/Search/Search.stories.jsx +1 -1
- package/stories/Select/Select.stories.jsx +1 -1
- package/stories/SideNav/SideNav.stories.jsx +1 -1
- package/stories/SideNav/SideNavItem.stories.jsx +1 -1
- package/stories/SideNav/SideNavItemsGroup.stories.jsx +1 -1
- package/stories/Skeleton/Skeleton.stories.jsx +1 -1
- package/stories/Spacer/Spacer.stories.jsx +1 -1
- package/stories/StackView/StackView.stories.jsx +1 -1
- package/stories/StackView/StackWrap.stories.jsx +1 -1
- package/stories/StepTracker/StepTracker.stories.jsx +1 -1
- package/stories/Tabs/Tabs.stories.jsx +1 -1
- package/stories/Tags/Tags.stories.jsx +1 -1
- package/stories/TextInput/TextArea.stories.jsx +2 -1
- package/stories/TextInput/TextInput.stories.jsx +1 -1
- package/stories/ToggleSwitch/ToggleSwitch.stories.jsx +6 -2
- package/stories/ToggleSwitch/ToggleSwitchGroup.stories.jsx +81 -0
- package/stories/Tooltip/Tooltip.stories.jsx +1 -1
- package/stories/TooltipButton/TooltipButton.stories.jsx +1 -1
- package/stories/Typography/Typography.stories.jsx +1 -1
- package/stories/supports.jsx +2 -3
- package/.ultra.cache.json +0 -1
- package/lib/utils/propTypes.js +0 -623
- package/src/utils/propTypes.js +0 -640
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
|
-
{
|
|
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(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
ref
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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,
|
package/src/Tabs/TabsItem.jsx
CHANGED
|
@@ -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
|
-
...
|
|
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)
|
package/src/Tags/Tags.jsx
CHANGED
|
@@ -8,13 +8,7 @@ import Icon from '../Icon'
|
|
|
8
8
|
import { StackWrap, getStackedContent } from '../StackView'
|
|
9
9
|
import { useViewport } from '../ViewportProvider'
|
|
10
10
|
import { useThemeTokens, useThemeTokensCallback } from '../ThemeProvider'
|
|
11
|
-
import {
|
|
12
|
-
a11yProps,
|
|
13
|
-
pressProps,
|
|
14
|
-
variantProp,
|
|
15
|
-
getTokensPropType,
|
|
16
|
-
selectTokens
|
|
17
|
-
} from '../utils/propTypes'
|
|
11
|
+
import { a11yProps, pressProps, variantProp, getTokensPropType, selectTokens } from '../utils/props'
|
|
18
12
|
import { useMultipleInputValues } from '../utils/input'
|
|
19
13
|
import { getPressHandlersWithArgs } from '../utils/pressability'
|
|
20
14
|
|
|
@@ -2,9 +2,9 @@ import { useCallback } from 'react'
|
|
|
2
2
|
import useTheme from './useTheme'
|
|
3
3
|
import { getComponentTheme, getThemeTokens, resolveThemeTokens, mergeAppearances } from './utils'
|
|
4
4
|
/**
|
|
5
|
-
* @typedef {import('../utils/
|
|
6
|
-
* @typedef {import('../utils/
|
|
7
|
-
* @typedef {import('../utils/
|
|
5
|
+
* @typedef {import('../utils/props/variantProp.js').AppearanceSet} AppearanceSet
|
|
6
|
+
* @typedef {import('../utils/props/tokens.js').TokensProp} TokensProp
|
|
7
|
+
* @typedef {import('../utils/props/tokens.js').TokensSet} TokensSet
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -3,9 +3,9 @@ import semVerSatisfies from 'semver/functions/satisfies'
|
|
|
3
3
|
import pkg from '../../../package.json'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* @typedef {import('../../utils/
|
|
7
|
-
* @typedef {import('../../utils/
|
|
8
|
-
* @typedef {import('../../utils/
|
|
6
|
+
* @typedef {import('../../utils/props/variantProp.js').AppearanceSet} AppearanceSet
|
|
7
|
+
* @typedef {import('../../utils/props/tokens.js').TokensProp} TokensProp
|
|
8
|
+
* @typedef {import('../../utils/props/tokens.js').TokensSet} TokensSet
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import React, { forwardRef } from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
|
-
import { Platform,
|
|
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
|
-
import {
|
|
8
|
-
a11yProps,
|
|
9
|
-
pressProps,
|
|
10
|
-
variantProp,
|
|
11
|
-
getTokensPropType,
|
|
12
|
-
selectTokens
|
|
13
|
-
} from '../utils/propTypes'
|
|
9
|
+
import { a11yProps, pressProps, variantProp, getTokensPropType, selectTokens } from '../utils/props'
|
|
14
10
|
import { useInputValue } from '../utils/input'
|
|
11
|
+
import { useUniqueId } from '../utils'
|
|
15
12
|
|
|
16
13
|
const selectButtonTokens = (tokens) =>
|
|
17
14
|
selectTokens('Button', {
|
|
@@ -54,12 +51,40 @@ const selectSwitchStyles = ({
|
|
|
54
51
|
})
|
|
55
52
|
})
|
|
56
53
|
|
|
54
|
+
const selectLabelStyles = ({ labelMarginLeft }) => ({ marginLeft: labelMarginLeft })
|
|
55
|
+
const selectLabelTokens = ({
|
|
56
|
+
labelColor,
|
|
57
|
+
labelFontName,
|
|
58
|
+
labelFontSize,
|
|
59
|
+
labelFontWeight,
|
|
60
|
+
labelLineHeight
|
|
61
|
+
}) => ({
|
|
62
|
+
color: labelColor,
|
|
63
|
+
fontName: labelFontName,
|
|
64
|
+
fontWeight: labelFontWeight,
|
|
65
|
+
fontSize: labelFontSize,
|
|
66
|
+
lineHeight: labelLineHeight
|
|
67
|
+
})
|
|
68
|
+
|
|
57
69
|
const ToggleSwitch = forwardRef(
|
|
58
70
|
(
|
|
59
|
-
{
|
|
71
|
+
{
|
|
72
|
+
value,
|
|
73
|
+
initialValue,
|
|
74
|
+
onChange,
|
|
75
|
+
id,
|
|
76
|
+
label,
|
|
77
|
+
inactive,
|
|
78
|
+
tokens,
|
|
79
|
+
tooltip,
|
|
80
|
+
variant,
|
|
81
|
+
accessibilityRole = 'switch',
|
|
82
|
+
accessibilityLabel = label
|
|
83
|
+
},
|
|
60
84
|
ref
|
|
61
85
|
) => {
|
|
62
86
|
const getTokens = useThemeTokensCallback('ToggleSwitch', tokens, variant)
|
|
87
|
+
const themeTokens = getTokens()
|
|
63
88
|
|
|
64
89
|
const { currentValue, setValue } = useInputValue({
|
|
65
90
|
value,
|
|
@@ -68,43 +93,58 @@ const ToggleSwitch = forwardRef(
|
|
|
68
93
|
})
|
|
69
94
|
|
|
70
95
|
const handlePress = (event) => setValue(!currentValue, event)
|
|
71
|
-
|
|
72
96
|
const getButtonTokens = (buttonState) => selectButtonTokens(getTokens(buttonState))
|
|
97
|
+
const uniqueId = useUniqueId('toggleSwitch')
|
|
98
|
+
const inputId = id ?? uniqueId
|
|
73
99
|
|
|
74
100
|
return (
|
|
75
|
-
<
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
101
|
+
<StackView space={2} direction="row">
|
|
102
|
+
{Boolean(label) && (
|
|
103
|
+
<View style={selectLabelStyles(themeTokens)}>
|
|
104
|
+
<InputLabel
|
|
105
|
+
forId={inputId}
|
|
106
|
+
label={label}
|
|
107
|
+
tokens={selectLabelTokens(themeTokens)}
|
|
108
|
+
tooltip={tooltip}
|
|
109
|
+
/>
|
|
110
|
+
</View>
|
|
111
|
+
)}
|
|
112
|
+
<ButtonBase
|
|
113
|
+
id={id}
|
|
114
|
+
ref={ref}
|
|
115
|
+
selected={currentValue}
|
|
116
|
+
inactive={inactive}
|
|
117
|
+
tokens={getButtonTokens}
|
|
118
|
+
accessibilityLabel={accessibilityLabel}
|
|
119
|
+
accessibilityRole={accessibilityRole}
|
|
120
|
+
accessibilityState={{ checked: currentValue }}
|
|
121
|
+
onPress={handlePress}
|
|
122
|
+
>
|
|
123
|
+
{(buttonState) => {
|
|
124
|
+
const stateTokens = getTokens(buttonState)
|
|
125
|
+
const IconComponent = stateTokens.icon
|
|
126
|
+
const switchStyles = selectSwitchStyles(stateTokens)
|
|
127
|
+
const trackStyles = selectTrackStyles(stateTokens)
|
|
128
|
+
const iconTokens = selectIconTokens(stateTokens)
|
|
90
129
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
130
|
+
// If drag-slide support is needed, use a PanResponder and apply these to an Animated value.
|
|
131
|
+
// Use translate transforms for smoothest non-thread-blocking animations and to allow drag.
|
|
132
|
+
const slideStart = 0
|
|
133
|
+
const slideEnd =
|
|
134
|
+
stateTokens.width - stateTokens.switchSize - stateTokens.trackBorderWidth * 2
|
|
135
|
+
const switchOffset = buttonState.selected ? slideEnd : slideStart
|
|
136
|
+
const switchPositionStyle = { transform: [{ translateX: switchOffset }] }
|
|
98
137
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
138
|
+
return (
|
|
139
|
+
<View style={[staticStyles.track, trackStyles]}>
|
|
140
|
+
<View style={[staticStyles.switch, switchStyles, switchPositionStyle]}>
|
|
141
|
+
{IconComponent && <IconComponent {...iconTokens} />}
|
|
142
|
+
</View>
|
|
103
143
|
</View>
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
</
|
|
144
|
+
)
|
|
145
|
+
}}
|
|
146
|
+
</ButtonBase>
|
|
147
|
+
</StackView>
|
|
108
148
|
)
|
|
109
149
|
}
|
|
110
150
|
)
|
|
@@ -131,11 +171,23 @@ ToggleSwitch.propTypes = {
|
|
|
131
171
|
* this should always be passed and used to control the state of the switch.
|
|
132
172
|
*/
|
|
133
173
|
onChange: PropTypes.func,
|
|
174
|
+
/**
|
|
175
|
+
* Input ID.
|
|
176
|
+
*/
|
|
177
|
+
id: PropTypes.string,
|
|
178
|
+
/**
|
|
179
|
+
* An optional label.
|
|
180
|
+
*/
|
|
181
|
+
label: PropTypes.string,
|
|
134
182
|
/**
|
|
135
183
|
* If passed, the switch does not respond to user input and may recieve different
|
|
136
184
|
* theme tokens if the theme supports inactive appearance.
|
|
137
185
|
*/
|
|
138
|
-
inactive: PropTypes.bool
|
|
186
|
+
inactive: PropTypes.bool,
|
|
187
|
+
/**
|
|
188
|
+
* Content of an optional Tooltip. If set, a tooltip button will be shown next to the label.
|
|
189
|
+
*/
|
|
190
|
+
tooltip: PropTypes.string
|
|
139
191
|
}
|
|
140
192
|
|
|
141
193
|
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/props'
|
|
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
|
package/src/index.js
CHANGED
|
@@ -17,7 +17,7 @@ export * from './Icon'
|
|
|
17
17
|
export { default as IconButton } from './IconButton'
|
|
18
18
|
export { default as InputLabel } from './InputLabel'
|
|
19
19
|
export * from './Link'
|
|
20
|
-
export { default as List } from './List'
|
|
20
|
+
export { default as List, ListItem, ListBase } from './List'
|
|
21
21
|
export { default as Modal } from './Modal'
|
|
22
22
|
export { default as Notification } from './Notification'
|
|
23
23
|
export { default as Pagination } from './Pagination'
|
|
@@ -37,7 +37,7 @@ export { default as StepTracker } from './StepTracker'
|
|
|
37
37
|
export { default as Tabs } from './Tabs'
|
|
38
38
|
export { default as Tags } from './Tags'
|
|
39
39
|
export * from './TextInput'
|
|
40
|
-
export
|
|
40
|
+
export * from './ToggleSwitch'
|
|
41
41
|
export { default as Tooltip } from './Tooltip'
|
|
42
42
|
export { default as TooltipButton } from './TooltipButton'
|
|
43
43
|
export { default as Typography } from './Typography'
|
|
@@ -150,8 +150,9 @@ export const getA11yPropsFromHtmlTag = (tag, nativeRole) => {
|
|
|
150
150
|
if (nativeRole !== undefined && Platform.OS !== 'web') return { accessibilityRole: nativeRole }
|
|
151
151
|
|
|
152
152
|
if (tag) {
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
// aria roles don't have native counterparts and RN may throw an error if an unrecognised role is passed
|
|
154
|
+
const ariaRole = Platform.OS === 'web' && tagsToRoles[tag]
|
|
155
|
+
if (ariaRole) return { accessibilityRole: ariaRole }
|
|
155
156
|
|
|
156
157
|
const accessibilityLevel = getHeadingLevel(tag)
|
|
157
158
|
if (accessibilityLevel) return { accessibilityRole: 'header', accessibilityLevel }
|
package/src/utils/index.js
CHANGED
|
@@ -3,7 +3,7 @@ export * from './animation'
|
|
|
3
3
|
export * from './children'
|
|
4
4
|
export * from './input'
|
|
5
5
|
export * from './pressability'
|
|
6
|
-
export * from './
|
|
6
|
+
export * from './props'
|
|
7
7
|
|
|
8
8
|
export { default as info } from './info'
|
|
9
9
|
export { default as useCopy } from './useCopy'
|
|
@@ -12,3 +12,4 @@ export { default as useSpacingScale } from './useSpacingScale'
|
|
|
12
12
|
export { default as useResponsiveProp } from './useResponsiveProp'
|
|
13
13
|
export * from './useResponsiveProp'
|
|
14
14
|
export { default as useUniqueId } from './useUniqueId'
|
|
15
|
+
export { default as withLinkRouter } from './withLinkRouter'
|