@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.
- package/.storybook/main.js +4 -0
- package/.storybook/preview.js +37 -0
- package/.ultra.cache.json +1 -1
- package/CHANGELOG.md +26 -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__/HorizontalScroll/HorizontalScroll.test.jsx +1 -0
- package/__tests__/ToggleSwitch/ToggleSwitch.test.jsx +10 -0
- package/__tests__/ToggleSwitch/ToggleSwitchGroup.test.jsx +192 -0
- package/babel.config.js +9 -16
- package/component-docs.json +10131 -0
- package/generate-component-docs.js +56 -0
- package/lib/Box/Box.js +1 -0
- package/lib/Button/ButtonBase.js +20 -6
- package/lib/Card/CardBase.js +1 -0
- package/lib/Card/PressableCardBase.js +9 -3
- package/lib/Checkbox/Checkbox.js +0 -2
- package/lib/FlexGrid/FlexGrid.js +1 -1
- package/lib/IconButton/IconButton.js +8 -3
- package/lib/Link/LinkBase.js +10 -3
- package/lib/List/List.js +1 -2
- 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/Radio/Radio.js +0 -2
- package/lib/StackView/StackView.js +1 -0
- package/lib/StackView/StackWrap.js +9 -5
- package/lib/StackView/StackWrapBox.js +1 -0
- package/lib/Tabs/Tabs.js +12 -4
- package/lib/Tabs/TabsItem.js +12 -6
- package/lib/ToggleSwitch/ToggleSwitch.js +99 -37
- package/lib/ToggleSwitch/ToggleSwitchGroup.js +230 -0
- package/lib/ToggleSwitch/index.js +14 -4
- package/lib/index.js +28 -9
- package/lib/utils/a11y/propTypes.js +61 -0
- package/lib/utils/a11y/propTypes.native.js +47 -0
- package/lib/utils/index.js +10 -1
- package/lib/utils/propTypes.js +35 -91
- package/lib/utils/withLinkRouter.js +98 -0
- package/package.json +10 -6
- package/release-context.json +4 -4
- package/src/Box/Box.jsx +1 -0
- package/src/Button/ButtonBase.jsx +11 -4
- package/src/Card/CardBase.jsx +1 -0
- package/src/Card/PressableCardBase.jsx +6 -4
- package/src/Checkbox/Checkbox.jsx +0 -2
- package/src/FlexGrid/FlexGrid.jsx +1 -1
- package/src/IconButton/IconButton.jsx +6 -4
- package/src/Link/LinkBase.jsx +6 -4
- package/src/List/List.jsx +1 -3
- 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/Radio/Radio.jsx +0 -2
- package/src/StackView/StackView.jsx +1 -0
- package/src/StackView/StackWrap.jsx +7 -6
- package/src/StackView/StackWrapBox.jsx +1 -0
- package/src/Tabs/Tabs.jsx +49 -22
- package/src/Tabs/TabsItem.jsx +11 -7
- package/src/ToggleSwitch/ToggleSwitch.jsx +92 -34
- package/src/ToggleSwitch/ToggleSwitchGroup.jsx +203 -0
- package/src/ToggleSwitch/index.js +2 -1
- package/src/index.js +2 -2
- package/src/utils/a11y/propTypes.js +61 -0
- package/src/utils/a11y/propTypes.native.js +39 -0
- package/src/utils/index.js +1 -0
- package/src/utils/propTypes.js +33 -111
- 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
|
@@ -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
|
-
|
|
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 {
|
|
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
|
-
(
|
|
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)
|
package/src/Radio/Radio.jsx
CHANGED
|
@@ -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'
|
|
@@ -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.
|
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)
|
|
@@ -1,8 +1,10 @@
|
|
|
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
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
|
-
{
|
|
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
|
-
<
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
</
|
|
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({
|