@telus-uds/components-base 0.0.2-prerelease.3 → 0.0.2-prerelease.7
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/.ultra.cache.json +1 -0
- package/CHANGELOG.md +55 -0
- package/__fixtures__/testTheme.js +528 -42
- package/__tests__/Button/ButtonBase.test.jsx +3 -32
- package/__tests__/Checkbox/Checkbox.test.jsx +94 -0
- package/__tests__/Divider/Divider.test.jsx +26 -5
- package/__tests__/Feedback/Feedback.test.jsx +42 -0
- package/__tests__/FlexGrid/Col.test.jsx +5 -0
- package/__tests__/InputSupports/InputSupports.test.jsx +50 -0
- package/__tests__/List/List.test.jsx +60 -0
- package/__tests__/Radio/Radio.test.jsx +87 -0
- package/__tests__/Select/Select.test.jsx +93 -0
- package/__tests__/Skeleton/Skeleton.test.jsx +61 -0
- package/__tests__/Spacer/Spacer.test.jsx +63 -0
- package/__tests__/StackView/StackView.test.jsx +216 -0
- package/__tests__/StackView/StackWrap.test.jsx +47 -0
- package/__tests__/StackView/getStackedContent.test.jsx +295 -0
- package/__tests__/Tags/Tags.test.jsx +328 -0
- package/__tests__/TextInput/TextArea.test.jsx +34 -0
- package/__tests__/TextInput/TextInputBase.test.jsx +120 -0
- package/__tests__/Tooltip/Tooltip.test.jsx +65 -0
- package/__tests__/Tooltip/getTooltipPosition.test.js +79 -0
- package/__tests__/utils/useCopy.test.js +31 -0
- package/__tests__/utils/useResponsiveProp.test.jsx +202 -0
- package/__tests__/utils/{spacing.test.jsx → useSpacingScale.test.jsx} +1 -1
- package/__tests__/utils/useUniqueId.test.js +31 -0
- package/jest.config.js +8 -2
- package/lib/Box/Box.js +7 -2
- package/lib/Button/Button.js +10 -3
- package/lib/Button/ButtonBase.js +79 -75
- package/lib/Button/ButtonGroup.js +24 -49
- package/lib/Button/ButtonLink.js +5 -0
- package/lib/Checkbox/Checkbox.js +308 -0
- package/lib/Checkbox/CheckboxInput.native.js +6 -0
- package/lib/Checkbox/CheckboxInput.web.js +57 -0
- package/lib/Checkbox/index.js +2 -0
- package/lib/Divider/Divider.js +40 -2
- package/lib/Feedback/Feedback.js +132 -0
- package/lib/Feedback/index.js +2 -0
- package/lib/Icon/Icon.js +9 -6
- package/lib/Icon/IconText.js +72 -0
- package/lib/Icon/index.js +2 -1
- package/lib/InputLabel/InputLabel.js +88 -0
- package/lib/InputLabel/LabelContent.native.js +8 -0
- package/lib/InputLabel/LabelContent.web.js +17 -0
- package/lib/InputLabel/index.js +2 -0
- package/lib/InputSupports/InputSupports.js +90 -0
- package/lib/InputSupports/index.js +2 -0
- package/lib/InputSupports/propTypes.js +55 -0
- package/lib/Link/ChevronLink.js +35 -10
- package/lib/Link/InlinePressable.native.js +78 -0
- package/lib/Link/InlinePressable.web.js +32 -0
- package/lib/Link/Link.js +11 -10
- package/lib/Link/LinkBase.js +69 -124
- package/lib/Link/TextButton.js +20 -9
- package/lib/Link/index.js +2 -1
- package/lib/List/List.js +52 -0
- package/lib/List/ListItem.js +207 -0
- package/lib/List/index.js +2 -0
- package/lib/Pagination/PageButton.js +3 -26
- package/lib/Pagination/SideButton.js +32 -42
- package/lib/Radio/Radio.js +291 -0
- package/lib/Radio/RadioInput.native.js +6 -0
- package/lib/Radio/RadioInput.web.js +59 -0
- package/lib/Radio/index.js +2 -0
- package/lib/Select/Group.native.js +14 -0
- package/lib/Select/Group.web.js +18 -0
- package/lib/Select/Item.native.js +9 -0
- package/lib/Select/Item.web.js +15 -0
- package/lib/Select/Picker.native.js +87 -0
- package/lib/Select/Picker.web.js +63 -0
- package/lib/Select/Select.js +272 -0
- package/lib/Select/index.js +6 -0
- package/lib/Skeleton/Skeleton.js +119 -0
- package/lib/Skeleton/index.js +2 -0
- package/lib/Spacer/Spacer.js +98 -0
- package/lib/Spacer/index.js +2 -0
- package/lib/StackView/StackView.js +107 -0
- package/lib/StackView/StackWrap.js +32 -0
- package/lib/StackView/StackWrap.native.js +3 -0
- package/lib/StackView/StackWrapBox.js +90 -0
- package/lib/StackView/StackWrapGap.js +50 -0
- package/lib/StackView/common.js +30 -0
- package/lib/StackView/getStackedContent.js +111 -0
- package/lib/StackView/index.js +5 -0
- package/lib/Tags/Tags.js +217 -0
- package/lib/Tags/index.js +2 -0
- package/lib/TextInput/TextArea.js +82 -0
- package/lib/TextInput/TextInput.js +54 -0
- package/lib/TextInput/TextInputBase.js +229 -0
- package/lib/TextInput/index.js +3 -0
- package/lib/TextInput/propTypes.js +31 -0
- package/lib/ThemeProvider/useThemeTokens.js +54 -3
- package/lib/ToggleSwitch/ToggleSwitch.js +1 -1
- package/lib/Tooltip/Backdrop.native.js +35 -0
- package/lib/Tooltip/Backdrop.web.js +52 -0
- package/lib/Tooltip/Tooltip.js +315 -0
- package/lib/Tooltip/dictionary.js +8 -0
- package/lib/Tooltip/getTooltipPosition.js +164 -0
- package/lib/Tooltip/index.js +2 -0
- package/lib/TooltipButton/TooltipButton.js +64 -0
- package/lib/TooltipButton/index.js +2 -0
- package/lib/Typography/Typography.js +4 -23
- package/lib/ViewportProvider/ViewportProvider.js +25 -0
- package/lib/ViewportProvider/index.js +2 -43
- package/lib/ViewportProvider/useViewport.js +3 -0
- package/lib/ViewportProvider/useViewportListener.js +43 -0
- package/lib/index.js +15 -1
- package/lib/utils/a11y/index.js +1 -0
- package/lib/utils/a11y/textSize.js +33 -0
- package/lib/utils/index.js +7 -1
- package/lib/utils/info/index.js +7 -0
- package/lib/utils/info/platform/index.js +11 -0
- package/lib/utils/info/platform/platform.android.js +1 -0
- package/lib/utils/info/platform/platform.ios.js +1 -0
- package/lib/utils/info/platform/platform.native.js +4 -0
- package/lib/utils/info/platform/platform.web.js +1 -0
- package/lib/utils/info/versions.js +5 -0
- package/lib/utils/input.js +3 -1
- package/lib/utils/pressability.js +92 -0
- package/lib/utils/propTypes.js +77 -8
- package/lib/utils/useCopy.js +16 -0
- package/lib/utils/useResponsiveProp.js +47 -0
- package/lib/utils/{spacing/useSpacingScale.js → useSpacingScale.js} +30 -9
- package/lib/utils/useUniqueId.js +12 -0
- package/package.json +7 -5
- package/release-context.json +4 -4
- package/src/Box/Box.jsx +4 -2
- package/src/Button/Button.jsx +6 -3
- package/src/Button/ButtonBase.jsx +72 -75
- package/src/Button/ButtonGroup.jsx +22 -39
- package/src/Button/ButtonLink.jsx +11 -2
- package/src/Checkbox/Checkbox.jsx +275 -0
- package/src/Checkbox/CheckboxInput.native.jsx +6 -0
- package/src/Checkbox/CheckboxInput.web.jsx +55 -0
- package/src/Checkbox/index.js +3 -0
- package/src/Divider/Divider.jsx +38 -3
- package/src/Feedback/Feedback.jsx +108 -0
- package/src/Feedback/index.js +3 -0
- package/src/Icon/Icon.jsx +11 -6
- package/src/Icon/IconText.jsx +63 -0
- package/src/Icon/index.js +2 -1
- package/src/InputLabel/InputLabel.jsx +99 -0
- package/src/InputLabel/LabelContent.native.jsx +6 -0
- package/src/InputLabel/LabelContent.web.jsx +13 -0
- package/src/InputLabel/index.js +3 -0
- package/src/InputSupports/InputSupports.jsx +86 -0
- package/src/InputSupports/index.js +3 -0
- package/src/InputSupports/propTypes.js +44 -0
- package/src/Link/ChevronLink.jsx +28 -7
- package/src/Link/InlinePressable.native.jsx +73 -0
- package/src/Link/InlinePressable.web.jsx +37 -0
- package/src/Link/Link.jsx +17 -13
- package/src/Link/LinkBase.jsx +62 -139
- package/src/Link/TextButton.jsx +25 -11
- package/src/Link/index.js +2 -1
- package/src/List/List.jsx +47 -0
- package/src/List/ListItem.jsx +187 -0
- package/src/List/index.js +3 -0
- package/src/Pagination/PageButton.jsx +3 -17
- package/src/Pagination/SideButton.jsx +27 -38
- package/src/Radio/Radio.jsx +270 -0
- package/src/Radio/RadioInput.native.jsx +6 -0
- package/src/Radio/RadioInput.web.jsx +57 -0
- package/src/Radio/index.js +3 -0
- package/src/Select/Group.native.jsx +14 -0
- package/src/Select/Group.web.jsx +15 -0
- package/src/Select/Item.native.jsx +10 -0
- package/src/Select/Item.web.jsx +11 -0
- package/src/Select/Picker.native.jsx +95 -0
- package/src/Select/Picker.web.jsx +67 -0
- package/src/Select/Select.jsx +265 -0
- package/src/Select/index.js +8 -0
- package/src/Skeleton/Skeleton.jsx +101 -0
- package/src/Skeleton/index.js +3 -0
- package/src/Spacer/Spacer.jsx +91 -0
- package/src/Spacer/index.js +3 -0
- package/src/StackView/StackView.jsx +104 -0
- package/src/StackView/StackWrap.jsx +33 -0
- package/src/StackView/StackWrap.native.jsx +4 -0
- package/src/StackView/StackWrapBox.jsx +93 -0
- package/src/StackView/StackWrapGap.jsx +49 -0
- package/src/StackView/common.jsx +28 -0
- package/src/StackView/getStackedContent.jsx +106 -0
- package/src/StackView/index.js +6 -0
- package/src/Tags/Tags.jsx +206 -0
- package/src/Tags/index.js +3 -0
- package/src/TextInput/TextArea.jsx +78 -0
- package/src/TextInput/TextInput.jsx +52 -0
- package/src/TextInput/TextInputBase.jsx +220 -0
- package/src/TextInput/index.js +4 -0
- package/src/TextInput/propTypes.js +29 -0
- package/src/ThemeProvider/useThemeTokens.js +54 -3
- package/src/ToggleSwitch/ToggleSwitch.jsx +1 -1
- package/src/Tooltip/Backdrop.native.jsx +33 -0
- package/src/Tooltip/Backdrop.web.jsx +60 -0
- package/src/Tooltip/Tooltip.jsx +294 -0
- package/src/Tooltip/dictionary.js +8 -0
- package/src/Tooltip/getTooltipPosition.js +161 -0
- package/src/Tooltip/index.js +3 -0
- package/src/TooltipButton/TooltipButton.jsx +53 -0
- package/src/TooltipButton/index.js +3 -0
- package/src/Typography/Typography.jsx +4 -19
- package/src/ViewportProvider/ViewportProvider.jsx +21 -0
- package/src/ViewportProvider/index.jsx +2 -41
- package/src/ViewportProvider/useViewport.js +5 -0
- package/src/ViewportProvider/useViewportListener.js +43 -0
- package/src/index.js +15 -1
- package/src/utils/a11y/index.js +1 -0
- package/src/utils/a11y/textSize.js +30 -0
- package/src/utils/index.js +8 -1
- package/src/utils/info/index.js +8 -0
- package/src/utils/info/platform/index.js +11 -0
- package/src/utils/info/platform/platform.android.js +1 -0
- package/src/utils/info/platform/platform.ios.js +1 -0
- package/src/utils/info/platform/platform.native.js +4 -0
- package/src/utils/info/platform/platform.web.js +1 -0
- package/src/utils/info/versions.js +6 -0
- package/src/utils/input.js +2 -1
- package/src/utils/pressability.js +92 -0
- package/src/utils/propTypes.js +97 -13
- package/src/utils/useCopy.js +13 -0
- package/src/utils/useResponsiveProp.js +50 -0
- package/src/utils/{spacing/useSpacingScale.js → useSpacingScale.js} +25 -10
- package/src/utils/useUniqueId.js +14 -0
- package/stories/A11yText/A11yText.stories.jsx +11 -5
- package/stories/ActivityIndicator/ActivityIndicator.stories.jsx +11 -2
- package/stories/Box/Box.stories.jsx +29 -2
- package/stories/Button/Button.stories.jsx +21 -20
- package/stories/Button/ButtonGroup.stories.jsx +2 -1
- package/stories/Button/ButtonLink.stories.jsx +6 -4
- package/stories/Card/Card.stories.jsx +13 -1
- package/stories/Checkbox/Checkbox.stories.jsx +71 -0
- package/stories/Divider/Divider.stories.jsx +26 -2
- package/stories/ExpandCollapse/ExpandCollapse.stories.jsx +74 -79
- package/stories/Feedback/Feedback.stories.jsx +96 -0
- package/stories/FlexGrid/01 FlexGrid.stories.jsx +20 -7
- package/stories/Icon/Icon.stories.jsx +11 -3
- package/stories/InputLabel/InputLabel.stories.jsx +42 -0
- package/stories/Link/ChevronLink.stories.jsx +20 -4
- package/stories/Link/Link.stories.jsx +39 -3
- package/stories/Link/TextButton.stories.jsx +24 -2
- package/stories/List/List.stories.jsx +117 -0
- package/stories/Pagination/Pagination.stories.jsx +28 -14
- package/stories/Radio/Radio.stories.jsx +113 -0
- package/stories/Select/Select.stories.jsx +55 -0
- package/stories/SideNav/SideNav.stories.jsx +17 -2
- package/stories/Skeleton/Skeleton.stories.jsx +36 -0
- package/stories/Spacer/Spacer.stories.jsx +38 -0
- package/stories/StackView/StackView.stories.jsx +75 -0
- package/stories/StackView/StackWrap.stories.jsx +64 -0
- package/stories/Tags/Tags.stories.jsx +69 -0
- package/stories/TextInput/TextArea.stories.jsx +100 -0
- package/stories/TextInput/TextInput.stories.jsx +103 -0
- package/stories/ToggleSwitch/ToggleSwitch.stories.jsx +16 -3
- package/stories/Tooltip/Tooltip.stories.jsx +81 -0
- package/stories/TooltipButton/TooltipButton.stories.jsx +11 -0
- package/stories/Typography/Typography.stories.jsx +12 -3
- package/stories/platform-supports.web.jsx +1 -1
- package/stories/supports.jsx +110 -14
- package/lib/Pagination/useCopy.js +0 -10
- package/lib/utils/spacing/index.js +0 -2
- package/lib/utils/spacing/utils.js +0 -32
- package/src/Pagination/useCopy.js +0 -7
- package/src/utils/spacing/index.js +0 -3
- package/src/utils/spacing/utils.js +0 -28
|
@@ -1,36 +1,30 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import { Text } from 'react-native'
|
|
3
3
|
|
|
4
4
|
import PropTypes from 'prop-types'
|
|
5
5
|
|
|
6
6
|
import ButtonBase from '../Button/ButtonBase'
|
|
7
|
-
import {
|
|
7
|
+
import { IconText } from '../Icon'
|
|
8
|
+
import { useThemeTokensCallback } from '../ThemeProvider'
|
|
8
9
|
import { useViewport } from '../ViewportProvider'
|
|
9
10
|
import { copyPropTypes, hrefAttrsProp, linkProps, selectTokens } from '../utils'
|
|
10
11
|
|
|
11
12
|
import dictionary from './dictionary'
|
|
12
|
-
import useCopy from '
|
|
13
|
-
|
|
14
|
-
const selectTextStyles = ({ color, fontName, fontSize, fontWeight, lineHeight }) =>
|
|
15
|
-
applyTextStyles({
|
|
16
|
-
color,
|
|
17
|
-
fontName,
|
|
18
|
-
fontSize,
|
|
19
|
-
fontWeight,
|
|
20
|
-
lineHeight
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
const selectIconTokens = ({ color, iconSize, iconTranslateX }) => {
|
|
24
|
-
// Scale icon with text, but with a cap so text isn't squashed at large scales
|
|
25
|
-
const iconScale = Math.min(PixelRatio.getFontScale(), 2)
|
|
13
|
+
import useCopy from '../utils/useCopy'
|
|
26
14
|
|
|
15
|
+
const selectIconTokens = ({ color, iconSize, iconDisplace }, direction) => {
|
|
27
16
|
return {
|
|
28
17
|
color,
|
|
29
|
-
size: iconSize
|
|
30
|
-
translateX:
|
|
18
|
+
size: iconSize,
|
|
19
|
+
translateX: iconDisplace * (direction === 'previous' ? -1 : 1)
|
|
31
20
|
}
|
|
32
21
|
}
|
|
33
22
|
|
|
23
|
+
const directionToSide = {
|
|
24
|
+
previous: 'left',
|
|
25
|
+
next: 'right'
|
|
26
|
+
}
|
|
27
|
+
|
|
34
28
|
function SideButton({ direction = 'previous', onPress, href, copy, variant, tokens, ...props }) {
|
|
35
29
|
const viewport = useViewport()
|
|
36
30
|
const buttonVariant = { direction, viewport, ...variant }
|
|
@@ -38,11 +32,10 @@ function SideButton({ direction = 'previous', onPress, href, copy, variant, toke
|
|
|
38
32
|
|
|
39
33
|
const getCopy = useCopy({ dictionary, copy })
|
|
40
34
|
|
|
41
|
-
const { icon
|
|
35
|
+
const { icon } = getTokens(tokens, buttonVariant)
|
|
42
36
|
|
|
43
37
|
const getButtonTokens = (buttonState) => selectTokens('Button', getTokens(buttonState))
|
|
44
|
-
const getIconTokens = (buttonState) => selectIconTokens(getTokens(buttonState))
|
|
45
|
-
const getTextStyles = (buttonState) => selectTextStyles(getTokens(buttonState))
|
|
38
|
+
const getIconTokens = (buttonState) => selectIconTokens(getTokens(buttonState), direction)
|
|
46
39
|
|
|
47
40
|
const label = direction === 'previous' ? getCopy('previousText') : getCopy('nextText')
|
|
48
41
|
const showLabel = viewport !== 'sm' && viewport !== 'xs'
|
|
@@ -63,17 +56,19 @@ function SideButton({ direction = 'previous', onPress, href, copy, variant, toke
|
|
|
63
56
|
|
|
64
57
|
return (
|
|
65
58
|
<ButtonBase {...buttonProps} tokens={getButtonTokens}>
|
|
66
|
-
{(buttonState) =>
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
59
|
+
{({ textStyles, ...buttonState }) => {
|
|
60
|
+
const iconProps = { tokens: getIconTokens(buttonState) }
|
|
61
|
+
return (
|
|
62
|
+
<IconText
|
|
63
|
+
icon={icon}
|
|
64
|
+
space={1}
|
|
65
|
+
iconPosition={directionToSide[direction]}
|
|
66
|
+
iconProps={iconProps}
|
|
67
|
+
>
|
|
68
|
+
{showLabel && <Text style={textStyles}>{label}</Text>}
|
|
69
|
+
</IconText>
|
|
70
|
+
)
|
|
71
|
+
}}
|
|
77
72
|
</ButtonBase>
|
|
78
73
|
)
|
|
79
74
|
}
|
|
@@ -85,9 +80,3 @@ SideButton.propTypes = {
|
|
|
85
80
|
}
|
|
86
81
|
|
|
87
82
|
export default SideButton
|
|
88
|
-
|
|
89
|
-
const staticStyles = StyleSheet.create({
|
|
90
|
-
contentContainer: {
|
|
91
|
-
flexDirection: 'row'
|
|
92
|
-
}
|
|
93
|
-
})
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import { Pressable, StyleSheet, Text, View } from 'react-native'
|
|
4
|
+
|
|
5
|
+
import RadioInput from './RadioInput'
|
|
6
|
+
// @todo move `LabelContent` outside of the `InputLabel` and fix
|
|
7
|
+
// the issue with the cursor not being pointer on Web
|
|
8
|
+
import RadioLabel from '../InputLabel/LabelContent'
|
|
9
|
+
import { applyShadowToken, applyTextStyles, useThemeTokensCallback } from '../ThemeProvider'
|
|
10
|
+
import { getTokensPropType, useInputValue, useUniqueId, variantProp } from '../utils'
|
|
11
|
+
import { a11yProps } from '../utils/propTypes'
|
|
12
|
+
import StackView from '../StackView'
|
|
13
|
+
|
|
14
|
+
const selectCheckedStyles = ({ checkedBackgroundColor, checkedSize }) => ({
|
|
15
|
+
backgroundColor: checkedBackgroundColor,
|
|
16
|
+
borderRadius: checkedSize / 2,
|
|
17
|
+
height: checkedSize,
|
|
18
|
+
width: checkedSize
|
|
19
|
+
})
|
|
20
|
+
const selectContainerStyles = ({
|
|
21
|
+
containerBackgroundColor,
|
|
22
|
+
containerBorderRadius,
|
|
23
|
+
containerMarginBottom,
|
|
24
|
+
containerOpacity,
|
|
25
|
+
containerPaddingBottom,
|
|
26
|
+
containerPaddingLeft,
|
|
27
|
+
containerPaddingRight,
|
|
28
|
+
containerPaddingTop,
|
|
29
|
+
containerShadow
|
|
30
|
+
}) => ({
|
|
31
|
+
backgroundColor: containerBackgroundColor,
|
|
32
|
+
borderRadius: containerBorderRadius,
|
|
33
|
+
marginBottom: containerMarginBottom,
|
|
34
|
+
opacity: containerOpacity,
|
|
35
|
+
paddingBottom: containerPaddingBottom,
|
|
36
|
+
paddingLeft: containerPaddingLeft,
|
|
37
|
+
paddingRight: containerPaddingRight,
|
|
38
|
+
paddingTop: containerPaddingTop,
|
|
39
|
+
...applyShadowToken(containerShadow)
|
|
40
|
+
})
|
|
41
|
+
const selectDescriptionStyles = ({
|
|
42
|
+
containerPaddingLeft = 0,
|
|
43
|
+
descriptionFontSize,
|
|
44
|
+
descriptionLineHeight,
|
|
45
|
+
descriptionMarginLeft,
|
|
46
|
+
inputSize,
|
|
47
|
+
labelMarginLeft = 0
|
|
48
|
+
}) => ({
|
|
49
|
+
marginLeft: descriptionMarginLeft ?? containerPaddingLeft + inputSize + labelMarginLeft,
|
|
50
|
+
...applyTextStyles({ fontSize: descriptionFontSize, lineHeight: descriptionLineHeight })
|
|
51
|
+
})
|
|
52
|
+
const selectInputStyles = ({
|
|
53
|
+
inputBackgroundColor,
|
|
54
|
+
inputBorderColor,
|
|
55
|
+
inputBorderWidth,
|
|
56
|
+
inputOutlineColor,
|
|
57
|
+
inputOutlineWidth,
|
|
58
|
+
inputSize
|
|
59
|
+
}) => ({
|
|
60
|
+
borderColor: inputBorderColor,
|
|
61
|
+
borderRadius: inputSize / 2,
|
|
62
|
+
borderWidth: inputBorderWidth,
|
|
63
|
+
backgroundColor: inputBackgroundColor,
|
|
64
|
+
height: inputSize,
|
|
65
|
+
outlineStyle: 'solid',
|
|
66
|
+
outlineColor: inputOutlineColor,
|
|
67
|
+
outlineWidth: inputOutlineWidth,
|
|
68
|
+
width: inputSize
|
|
69
|
+
})
|
|
70
|
+
const selectLabelStyles = ({
|
|
71
|
+
labelColor,
|
|
72
|
+
labelFontName,
|
|
73
|
+
labelFontSize,
|
|
74
|
+
labelFontWeight,
|
|
75
|
+
labelMarginLeft,
|
|
76
|
+
labelLineHeight
|
|
77
|
+
}) =>
|
|
78
|
+
applyTextStyles({
|
|
79
|
+
color: labelColor,
|
|
80
|
+
fontName: labelFontName,
|
|
81
|
+
fontWeight: labelFontWeight,
|
|
82
|
+
fontSize: labelFontSize,
|
|
83
|
+
lineHeight: labelLineHeight,
|
|
84
|
+
marginLeft: labelMarginLeft
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Basic Radio component.
|
|
89
|
+
*
|
|
90
|
+
* ## Component API
|
|
91
|
+
*
|
|
92
|
+
* Use `label` prop to provide a label for the radio button. For a disabled `Radio` set the `inactive` prop to `true`.
|
|
93
|
+
*
|
|
94
|
+
* ### Controlled version
|
|
95
|
+
*
|
|
96
|
+
* If the radio button is controlled from outside, it needs to receive `checked` and `onChange` props.
|
|
97
|
+
*
|
|
98
|
+
* ### Uncontrolled version
|
|
99
|
+
*
|
|
100
|
+
* In case of uncontrolled radio button you can use `defaultChecked` prop to provide the initial value.
|
|
101
|
+
* Whenever the radio button gets toggled, it calls the `onChange` callback with the new value (boolean).
|
|
102
|
+
*
|
|
103
|
+
* ### Using within forms
|
|
104
|
+
*
|
|
105
|
+
* You can pass `name` and `value` props if you need a particular radio button to be a part of a radio group
|
|
106
|
+
* on a form.
|
|
107
|
+
*
|
|
108
|
+
* ### Validation
|
|
109
|
+
*
|
|
110
|
+
* You can mark a radio button as failing validation by setting the `error` prop to `true`.
|
|
111
|
+
*
|
|
112
|
+
* ## A11y guidelines
|
|
113
|
+
*
|
|
114
|
+
* Radio component accepts all the common accessibility props, but also sets some defaults, including
|
|
115
|
+
* accessibility role `'radio'` and accessibility state that depends on the other props (`checked`, `inactive`)
|
|
116
|
+
* or the internal state in case of uncontrolled radio button.
|
|
117
|
+
*
|
|
118
|
+
*/
|
|
119
|
+
const Radio = ({
|
|
120
|
+
checked,
|
|
121
|
+
defaultChecked,
|
|
122
|
+
description,
|
|
123
|
+
error = false,
|
|
124
|
+
id,
|
|
125
|
+
inactive,
|
|
126
|
+
label,
|
|
127
|
+
name,
|
|
128
|
+
onChange,
|
|
129
|
+
tokens,
|
|
130
|
+
value,
|
|
131
|
+
variant,
|
|
132
|
+
...rest
|
|
133
|
+
}) => {
|
|
134
|
+
const { currentValue: isChecked, setValue: setIsChecked, isControlled } = useInputValue(
|
|
135
|
+
{
|
|
136
|
+
value: checked,
|
|
137
|
+
initialValue: defaultChecked,
|
|
138
|
+
onChange
|
|
139
|
+
},
|
|
140
|
+
'useRadioValue'
|
|
141
|
+
)
|
|
142
|
+
const getTokens = useThemeTokensCallback('Radio', tokens, {
|
|
143
|
+
checked: isChecked,
|
|
144
|
+
inactive,
|
|
145
|
+
error,
|
|
146
|
+
...variant
|
|
147
|
+
})
|
|
148
|
+
const handleChange = () => {
|
|
149
|
+
if (!inactive && !isChecked) {
|
|
150
|
+
setIsChecked(true)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const accessibilityProps = a11yProps.select(rest)
|
|
154
|
+
const uniqueId = useUniqueId('radio')
|
|
155
|
+
const inputId = id ?? uniqueId
|
|
156
|
+
|
|
157
|
+
// @todo our current version of React Native Web doesn't include
|
|
158
|
+
// keyboard support on `Pressable` (which starts with 0.15.3), so
|
|
159
|
+
// the complete accessibility of the `Radio` component on Web
|
|
160
|
+
// (namely, change on key pressed) is pending RNW upgrade
|
|
161
|
+
// (see https://github.com/necolas/react-native-web/issues/1950)
|
|
162
|
+
return (
|
|
163
|
+
<Pressable
|
|
164
|
+
disabled={inactive}
|
|
165
|
+
onPress={handleChange}
|
|
166
|
+
accessibilityRole="radio"
|
|
167
|
+
accessibilityState={{ checked: isChecked, disabled: inactive }}
|
|
168
|
+
{...accessibilityProps}
|
|
169
|
+
>
|
|
170
|
+
{({ focused: focus, hovered: hover, pressed }) => {
|
|
171
|
+
const stateTokens = getTokens({ focus, hover, pressed })
|
|
172
|
+
|
|
173
|
+
return (
|
|
174
|
+
<StackView space={0}>
|
|
175
|
+
<View style={[staticStyles.container, selectContainerStyles(stateTokens)]}>
|
|
176
|
+
<View
|
|
177
|
+
style={StyleSheet.flatten([
|
|
178
|
+
staticStyles.defaultInputStyles,
|
|
179
|
+
selectInputStyles(stateTokens, isChecked)
|
|
180
|
+
])}
|
|
181
|
+
testID="Radio-Input"
|
|
182
|
+
>
|
|
183
|
+
{/* Add a real input on Web, skip on native platforms */}
|
|
184
|
+
<RadioInput
|
|
185
|
+
checked={isChecked}
|
|
186
|
+
defaultChecked={defaultChecked}
|
|
187
|
+
disabled={inactive}
|
|
188
|
+
id={inputId}
|
|
189
|
+
isControlled={isControlled}
|
|
190
|
+
name={name}
|
|
191
|
+
value={value}
|
|
192
|
+
/>
|
|
193
|
+
{isChecked && (
|
|
194
|
+
<View style={selectCheckedStyles(stateTokens)} testID="Radio-Checked" />
|
|
195
|
+
)}
|
|
196
|
+
</View>
|
|
197
|
+
{Boolean(label) && (
|
|
198
|
+
<Text style={selectLabelStyles(stateTokens)}>
|
|
199
|
+
<RadioLabel forId={inputId}>{label}</RadioLabel>
|
|
200
|
+
</Text>
|
|
201
|
+
)}
|
|
202
|
+
</View>
|
|
203
|
+
{Boolean(description) && (
|
|
204
|
+
<Text style={selectDescriptionStyles(getTokens())}>{description}</Text>
|
|
205
|
+
)}
|
|
206
|
+
</StackView>
|
|
207
|
+
)
|
|
208
|
+
}}
|
|
209
|
+
</Pressable>
|
|
210
|
+
)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
Radio.propTypes = {
|
|
214
|
+
...a11yProps.propTypes,
|
|
215
|
+
/**
|
|
216
|
+
* Use `checked` for controlled Radio. For uncontrolled Radio, use the `defaultChecked` prop.
|
|
217
|
+
*/
|
|
218
|
+
checked: PropTypes.bool,
|
|
219
|
+
/**
|
|
220
|
+
* Use `defaultChecked` to provide the initial value for an uncontrolled Radio.
|
|
221
|
+
*/
|
|
222
|
+
defaultChecked: PropTypes.bool,
|
|
223
|
+
/**
|
|
224
|
+
* An optional radio button description.
|
|
225
|
+
*/
|
|
226
|
+
description: PropTypes.string,
|
|
227
|
+
/**
|
|
228
|
+
* Radio button ID.
|
|
229
|
+
*/
|
|
230
|
+
id: PropTypes.string,
|
|
231
|
+
/**
|
|
232
|
+
* Whether the corresponding input is disabled or active.
|
|
233
|
+
*/
|
|
234
|
+
inactive: PropTypes.bool,
|
|
235
|
+
/**
|
|
236
|
+
* The label.
|
|
237
|
+
*/
|
|
238
|
+
label: PropTypes.string,
|
|
239
|
+
/**
|
|
240
|
+
* Associate this radio button with a group (set as the name attribute).
|
|
241
|
+
*/
|
|
242
|
+
name: PropTypes.string,
|
|
243
|
+
/**
|
|
244
|
+
* Whether the underlying input triggered a validation error or not.
|
|
245
|
+
*/
|
|
246
|
+
error: PropTypes.bool,
|
|
247
|
+
/**
|
|
248
|
+
* The value. Must be unique within the group.
|
|
249
|
+
*/
|
|
250
|
+
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]),
|
|
251
|
+
/**
|
|
252
|
+
* Callback called when a controlled radio button gets interacted with.
|
|
253
|
+
*/
|
|
254
|
+
onChange: PropTypes.func,
|
|
255
|
+
/**
|
|
256
|
+
* Radio tokens.
|
|
257
|
+
*/
|
|
258
|
+
tokens: getTokensPropType('Radio'),
|
|
259
|
+
/**
|
|
260
|
+
* Radio variant.
|
|
261
|
+
*/
|
|
262
|
+
variant: variantProp.propType
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export default Radio
|
|
266
|
+
|
|
267
|
+
const staticStyles = StyleSheet.create({
|
|
268
|
+
container: { flexDirection: 'row', alignItems: 'center' },
|
|
269
|
+
defaultInputStyles: { alignItems: 'center', justifyContent: 'center' }
|
|
270
|
+
})
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* On Web we need to include an actual input but hide it.
|
|
6
|
+
*/
|
|
7
|
+
const RadioInput = forwardRef(
|
|
8
|
+
({ checked, defaultChecked, disabled, id, isControlled, name, onChange, value }, ref) => {
|
|
9
|
+
const handleClick = (event) => {
|
|
10
|
+
// Cancel the click dispatched via the label tag, since it's already wrapped
|
|
11
|
+
// in <Pressable>
|
|
12
|
+
event.preventDefault()
|
|
13
|
+
event.stopPropagation()
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<input
|
|
18
|
+
checked={isControlled ? checked : undefined}
|
|
19
|
+
defaultChecked={isControlled ? undefined : defaultChecked}
|
|
20
|
+
disabled={disabled}
|
|
21
|
+
hidden
|
|
22
|
+
id={id}
|
|
23
|
+
name={name}
|
|
24
|
+
onChange={onChange}
|
|
25
|
+
onClick={handleClick}
|
|
26
|
+
ref={ref}
|
|
27
|
+
type="radio"
|
|
28
|
+
value={value}
|
|
29
|
+
/>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
)
|
|
33
|
+
RadioInput.displayName = 'Radio'
|
|
34
|
+
|
|
35
|
+
RadioInput.propTypes = {
|
|
36
|
+
checked: PropTypes.bool,
|
|
37
|
+
defaultChecked: PropTypes.bool,
|
|
38
|
+
disabled: PropTypes.bool,
|
|
39
|
+
id: PropTypes.string,
|
|
40
|
+
isControlled: PropTypes.bool,
|
|
41
|
+
name: PropTypes.string,
|
|
42
|
+
onChange: PropTypes.func,
|
|
43
|
+
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool])
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
RadioInput.defaultProps = {
|
|
47
|
+
checked: undefined,
|
|
48
|
+
defaultChecked: undefined,
|
|
49
|
+
disabled: false,
|
|
50
|
+
id: null,
|
|
51
|
+
isControlled: false,
|
|
52
|
+
name: undefined,
|
|
53
|
+
onChange: () => {},
|
|
54
|
+
value: undefined
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default RadioInput
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import PropTypes from 'prop-types'
|
|
2
|
+
|
|
3
|
+
import { componentPropType } from '../utils'
|
|
4
|
+
|
|
5
|
+
const Group = ({ children }) => {
|
|
6
|
+
return children
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default Group
|
|
10
|
+
|
|
11
|
+
Group.propTypes = {
|
|
12
|
+
children: componentPropType('Item'),
|
|
13
|
+
label: PropTypes.string.isRequired
|
|
14
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
|
|
4
|
+
import { componentPropType } from '../utils'
|
|
5
|
+
|
|
6
|
+
const Group = ({ children, label }) => {
|
|
7
|
+
return <optgroup label={label}>{children}</optgroup>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default Group
|
|
11
|
+
|
|
12
|
+
Group.propTypes = {
|
|
13
|
+
children: componentPropType('Item'),
|
|
14
|
+
label: PropTypes.string.isRequired
|
|
15
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
|
|
4
|
+
const Item = ({ children, value }) => <option value={value}>{children}</option>
|
|
5
|
+
|
|
6
|
+
export default Item
|
|
7
|
+
|
|
8
|
+
Item.propTypes = {
|
|
9
|
+
children: PropTypes.string.isRequired,
|
|
10
|
+
value: PropTypes.string.isRequired
|
|
11
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import React, { Children } from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import { View, Platform } from 'react-native'
|
|
4
|
+
import NativePicker from 'react-native-picker-select'
|
|
5
|
+
|
|
6
|
+
import { a11yProps, componentPropType } from '../utils'
|
|
7
|
+
import Group from './Group'
|
|
8
|
+
|
|
9
|
+
// styling of the native input is very limited, most of the styles have to be applied to an additional View
|
|
10
|
+
const selectAndroidInputStyles = ({
|
|
11
|
+
height = 0,
|
|
12
|
+
paddingBottom = 0,
|
|
13
|
+
paddingTop = 0,
|
|
14
|
+
borderWidth = 0,
|
|
15
|
+
color
|
|
16
|
+
}) => ({
|
|
17
|
+
height: height - paddingTop - paddingBottom - 2 * borderWidth,
|
|
18
|
+
color
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
// the native input has a side padding of 8px, which can't be adjusted, so we have to account for that in the container
|
|
22
|
+
const selectAndroidContainerStyles = ({ paddingLeft = 0, paddingRight = 0, ...rest }) => ({
|
|
23
|
+
paddingLeft: paddingLeft > 8 ? paddingLeft - 8 : 0,
|
|
24
|
+
paddingRight: paddingRight > 8 ? paddingRight - 8 : 0,
|
|
25
|
+
...rest
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const Picker = ({
|
|
29
|
+
value,
|
|
30
|
+
onChange,
|
|
31
|
+
onFocus,
|
|
32
|
+
onBlur,
|
|
33
|
+
style,
|
|
34
|
+
inactive,
|
|
35
|
+
children,
|
|
36
|
+
placeholder,
|
|
37
|
+
...rest
|
|
38
|
+
}) => {
|
|
39
|
+
// ungroup items, since there's no way to support groups on native
|
|
40
|
+
const flatChildren = Children.toArray(children).flatMap((child) => {
|
|
41
|
+
if (child.type === Group) {
|
|
42
|
+
return child.props.children
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return child
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const items = flatChildren.map(({ props }) => ({
|
|
49
|
+
label: props.children,
|
|
50
|
+
value: props.value
|
|
51
|
+
}))
|
|
52
|
+
|
|
53
|
+
const picker = (
|
|
54
|
+
<NativePicker
|
|
55
|
+
touchableWrapperProps={a11yProps.select(rest)}
|
|
56
|
+
onOpen={onFocus}
|
|
57
|
+
onClose={onBlur}
|
|
58
|
+
disabled={inactive}
|
|
59
|
+
items={items}
|
|
60
|
+
value={value}
|
|
61
|
+
onValueChange={onChange}
|
|
62
|
+
style={{
|
|
63
|
+
inputIOS: style,
|
|
64
|
+
inputAndroid: selectAndroidInputStyles(style)
|
|
65
|
+
}}
|
|
66
|
+
placeholder={placeholder !== undefined ? placeholder : {}}
|
|
67
|
+
/>
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<>
|
|
72
|
+
{Platform.OS === 'android' ? (
|
|
73
|
+
<View style={selectAndroidContainerStyles(style)}>{picker}</View>
|
|
74
|
+
) : (
|
|
75
|
+
picker
|
|
76
|
+
)}
|
|
77
|
+
</>
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export default Picker
|
|
82
|
+
|
|
83
|
+
Picker.propTypes = {
|
|
84
|
+
value: PropTypes.string,
|
|
85
|
+
onChange: PropTypes.func,
|
|
86
|
+
onFocus: PropTypes.func,
|
|
87
|
+
onBlur: PropTypes.func,
|
|
88
|
+
style: PropTypes.object,
|
|
89
|
+
inactive: PropTypes.bool,
|
|
90
|
+
children: componentPropType(['Item', 'Group']),
|
|
91
|
+
placeholder: PropTypes.shape({
|
|
92
|
+
value: PropTypes.string,
|
|
93
|
+
label: PropTypes.string
|
|
94
|
+
})
|
|
95
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import PropTypes from 'prop-types'
|
|
4
|
+
import { componentPropType } from '../utils'
|
|
5
|
+
|
|
6
|
+
const Picker = ({
|
|
7
|
+
value,
|
|
8
|
+
onChange,
|
|
9
|
+
onFocus,
|
|
10
|
+
onBlur,
|
|
11
|
+
onMouseOver,
|
|
12
|
+
onMouseOut,
|
|
13
|
+
style,
|
|
14
|
+
inactive,
|
|
15
|
+
children,
|
|
16
|
+
placeholder,
|
|
17
|
+
nativeID,
|
|
18
|
+
testID,
|
|
19
|
+
...rest
|
|
20
|
+
}) => {
|
|
21
|
+
const { accessibilityLabel, accessibilityDescribedBy, accessibilityInvalid } = rest
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<select
|
|
25
|
+
style={style}
|
|
26
|
+
onMouseOver={onMouseOver}
|
|
27
|
+
onMouseOut={onMouseOut}
|
|
28
|
+
onFocus={onFocus}
|
|
29
|
+
onBlur={onBlur}
|
|
30
|
+
disabled={inactive}
|
|
31
|
+
value={value || (placeholder !== undefined ? placeholder.value : undefined)}
|
|
32
|
+
onChange={(event) => onChange(event.target.value)}
|
|
33
|
+
id={nativeID}
|
|
34
|
+
aria-label={accessibilityLabel}
|
|
35
|
+
aria-describedby={accessibilityDescribedBy}
|
|
36
|
+
aria-invalid={accessibilityInvalid}
|
|
37
|
+
data-testid={testID}
|
|
38
|
+
>
|
|
39
|
+
{placeholder !== undefined && (
|
|
40
|
+
<option value={placeholder.value} disabled hidden>
|
|
41
|
+
{placeholder.label}
|
|
42
|
+
</option>
|
|
43
|
+
)}
|
|
44
|
+
{children}
|
|
45
|
+
</select>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export default Picker
|
|
50
|
+
|
|
51
|
+
Picker.propTypes = {
|
|
52
|
+
value: PropTypes.string,
|
|
53
|
+
onChange: PropTypes.func,
|
|
54
|
+
onFocus: PropTypes.func,
|
|
55
|
+
onBlur: PropTypes.func,
|
|
56
|
+
onMouseOver: PropTypes.func,
|
|
57
|
+
onMouseOut: PropTypes.func,
|
|
58
|
+
style: PropTypes.object,
|
|
59
|
+
inactive: PropTypes.bool,
|
|
60
|
+
children: componentPropType(['Item', 'Group']),
|
|
61
|
+
placeholder: PropTypes.shape({
|
|
62
|
+
value: PropTypes.string,
|
|
63
|
+
label: PropTypes.string
|
|
64
|
+
}),
|
|
65
|
+
nativeID: PropTypes.string,
|
|
66
|
+
testID: PropTypes.string
|
|
67
|
+
}
|