@telus-uds/components-base 0.0.2-prerelease.1 → 0.0.2-prerelease.5
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/CHANGELOG.md +36 -0
- package/__fixtures__/testTheme.js +264 -84
- package/__tests__/Box/Box.test.jsx +81 -58
- package/__tests__/Card/Card.test.jsx +63 -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__/Pagination/Pagination.test.jsx +160 -0
- package/__tests__/Spacer/Spacer.test.jsx +63 -0
- package/__tests__/StackView/StackView.test.jsx +242 -0
- package/__tests__/StackView/StackWrap.test.jsx +47 -0
- package/__tests__/StackView/getStackedContent.test.jsx +295 -0
- package/__tests__/TextInput/TextInput.test.jsx +146 -0
- package/__tests__/ThemeProvider/useThemeTokens.test.jsx +5 -3
- package/__tests__/utils/spacing.test.jsx +273 -0
- package/__tests__/utils/useUniqueId.test.js +31 -0
- package/babel.config.json +8 -0
- package/jest.config.js +7 -6
- package/lib/A11yInfoProvider/index.js +2 -2
- package/lib/A11yText/index.js +1 -3
- package/lib/ActivityIndicator/Spinner.web.js +3 -5
- package/lib/Box/Box.js +117 -82
- package/lib/Button/Button.js +1 -3
- package/lib/Button/ButtonBase.js +9 -21
- package/lib/Button/ButtonGroup.js +14 -25
- package/lib/Button/ButtonLink.js +1 -3
- package/lib/Card/Card.js +103 -0
- package/lib/Card/index.js +2 -0
- package/lib/Divider/Divider.js +40 -4
- package/lib/ExpandCollapse/Accordion.js +1 -3
- package/lib/ExpandCollapse/Control.js +3 -5
- package/lib/ExpandCollapse/Panel.js +2 -4
- package/lib/Feedback/Feedback.js +110 -0
- package/lib/Feedback/index.js +2 -0
- package/lib/FlexGrid/Col/Col.js +3 -5
- package/lib/FlexGrid/FlexGrid.js +1 -3
- package/lib/FlexGrid/Row/Row.js +1 -3
- package/lib/FlexGrid/providers/GutterContext.js +1 -1
- package/lib/Icon/Icon.js +1 -1
- package/lib/InputLabel/InputLabel.js +86 -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/Link/ChevronLink.js +1 -3
- package/lib/Link/Link.js +1 -3
- package/lib/Link/LinkBase.js +11 -7
- package/lib/Link/TextButton.js +1 -3
- package/lib/Pagination/PageButton.js +85 -0
- package/lib/Pagination/Pagination.js +118 -0
- package/lib/Pagination/SideButton.js +108 -0
- package/lib/Pagination/dictionary.js +18 -0
- package/lib/Pagination/index.js +2 -0
- package/lib/Pagination/useCopy.js +10 -0
- package/lib/Pagination/usePagination.js +70 -0
- package/lib/SideNav/Item.js +4 -6
- package/lib/SideNav/ItemsGroup.js +11 -11
- package/lib/SideNav/SideNav.js +2 -4
- package/lib/Spacer/Spacer.js +98 -0
- package/lib/Spacer/index.js +2 -0
- package/lib/StackView/StackView.js +105 -0
- package/lib/StackView/StackWrap.js +32 -0
- package/lib/StackView/StackWrap.native.js +3 -0
- package/lib/StackView/StackWrapBox.js +85 -0
- package/lib/StackView/StackWrapGap.js +45 -0
- package/lib/StackView/common.js +30 -0
- package/lib/StackView/getStackedContent.js +111 -0
- package/lib/StackView/index.js +5 -0
- package/lib/TextInput/TextInput.js +337 -0
- package/lib/TextInput/index.js +2 -0
- package/lib/ThemeProvider/ThemeProvider.js +2 -2
- package/lib/ThemeProvider/useThemeTokens.js +34 -6
- package/lib/ThemeProvider/utils/theme-tokens.js +37 -9
- package/lib/ToggleSwitch/ToggleSwitch.js +17 -47
- package/lib/Typography/Typography.js +1 -7
- package/lib/ViewportProvider/index.js +1 -1
- package/lib/index.js +8 -1
- package/lib/utils/index.js +2 -1
- package/lib/utils/input.js +3 -1
- package/lib/utils/propTypes.js +103 -8
- package/lib/utils/spacing/index.js +2 -0
- package/lib/utils/spacing/useSpacingScale.js +102 -0
- package/lib/utils/spacing/utils.js +32 -0
- package/lib/utils/useUniqueId.js +12 -0
- package/package.json +6 -9
- package/release-context.json +4 -4
- package/src/Box/Box.jsx +117 -80
- package/src/Button/ButtonBase.jsx +8 -21
- package/src/Button/ButtonGroup.jsx +13 -17
- package/src/Card/Card.jsx +101 -0
- package/src/Card/index.js +3 -0
- package/src/Divider/Divider.jsx +38 -3
- package/src/ExpandCollapse/Control.jsx +2 -3
- package/src/Feedback/Feedback.jsx +99 -0
- package/src/Feedback/index.js +3 -0
- package/src/FlexGrid/Col/Col.jsx +4 -2
- package/src/Icon/Icon.jsx +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/Link/LinkBase.jsx +9 -3
- package/src/Pagination/PageButton.jsx +80 -0
- package/src/Pagination/Pagination.jsx +135 -0
- package/src/Pagination/SideButton.jsx +93 -0
- package/src/Pagination/dictionary.js +18 -0
- package/src/Pagination/index.js +3 -0
- package/src/Pagination/useCopy.js +7 -0
- package/src/Pagination/usePagination.js +69 -0
- package/src/SideNav/Item.jsx +3 -3
- package/src/SideNav/ItemsGroup.jsx +11 -13
- package/src/Spacer/Spacer.jsx +91 -0
- package/src/Spacer/index.js +3 -0
- package/src/StackView/StackView.jsx +103 -0
- package/src/StackView/StackWrap.jsx +33 -0
- package/src/StackView/StackWrap.native.jsx +4 -0
- package/src/StackView/StackWrapBox.jsx +82 -0
- package/src/StackView/StackWrapGap.jsx +39 -0
- package/src/StackView/common.jsx +28 -0
- package/src/StackView/getStackedContent.jsx +106 -0
- package/src/StackView/index.js +6 -0
- package/src/TextInput/TextInput.jsx +325 -0
- package/src/TextInput/index.js +3 -0
- package/src/ThemeProvider/useThemeTokens.js +34 -7
- package/src/ThemeProvider/utils/theme-tokens.js +37 -8
- package/src/ToggleSwitch/ToggleSwitch.jsx +23 -43
- package/src/Typography/Typography.jsx +0 -4
- package/src/index.js +8 -1
- package/src/utils/index.js +1 -0
- package/src/utils/input.js +2 -1
- package/src/utils/propTypes.js +105 -16
- package/src/utils/spacing/index.js +3 -0
- package/src/utils/spacing/useSpacingScale.js +93 -0
- package/src/utils/spacing/utils.js +28 -0
- 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 +46 -17
- package/stories/Button/Button.stories.jsx +17 -21
- package/stories/Button/ButtonGroup.stories.jsx +2 -1
- package/stories/Button/ButtonLink.stories.jsx +6 -4
- package/stories/Card/Card.stories.jsx +62 -0
- package/stories/Divider/Divider.stories.jsx +26 -2
- package/stories/ExpandCollapse/ExpandCollapse.stories.jsx +74 -79
- package/stories/Feedback/Feedback.stories.jsx +97 -0
- package/stories/FlexGrid/01 FlexGrid.stories.jsx +20 -7
- package/stories/Icon/Icon.stories.jsx +11 -3
- package/stories/InputLabel/InputLabel.stories.jsx +37 -0
- package/stories/Link/ChevronLink.stories.jsx +20 -4
- package/stories/Link/Link.stories.jsx +24 -3
- package/stories/Link/TextButton.stories.jsx +24 -3
- package/stories/Pagination/Pagination.stories.jsx +64 -0
- package/stories/SideNav/SideNav.stories.jsx +17 -2
- package/stories/Spacer/Spacer.stories.jsx +33 -0
- package/stories/StackView/StackView.stories.jsx +65 -0
- package/stories/StackView/StackWrap.stories.jsx +52 -0
- package/stories/TextInput/TextInput.stories.jsx +103 -0
- package/stories/ToggleSwitch/ToggleSwitch.stories.jsx +16 -3
- package/stories/Typography/Typography.stories.jsx +12 -3
- package/stories/platform-supports.web.jsx +1 -1
- package/stories/supports.jsx +113 -13
- package/babel.config.js +0 -3
|
@@ -18,6 +18,7 @@ const getOuterBorderOffset = ({ outerBorderGap = 0, outerBorderWidth = 0 }) =>
|
|
|
18
18
|
outerBorderGap + outerBorderWidth
|
|
19
19
|
|
|
20
20
|
const selectOuterContainerStyles = ({
|
|
21
|
+
alignSelf,
|
|
21
22
|
opacity,
|
|
22
23
|
outerBorderColor,
|
|
23
24
|
outerBorderWidth,
|
|
@@ -25,6 +26,7 @@ const selectOuterContainerStyles = ({
|
|
|
25
26
|
outerBorderRadius = 0,
|
|
26
27
|
outerBackgroundColor
|
|
27
28
|
}) => ({
|
|
29
|
+
alignSelf,
|
|
28
30
|
padding: outerBorderGap,
|
|
29
31
|
borderWidth: outerBorderWidth,
|
|
30
32
|
borderColor: outerBorderColor,
|
|
@@ -33,25 +35,12 @@ const selectOuterContainerStyles = ({
|
|
|
33
35
|
opacity
|
|
34
36
|
})
|
|
35
37
|
|
|
36
|
-
const selectOuterWidthStyles = ({
|
|
37
|
-
outerBorderGap,
|
|
38
|
-
outerBorderWidth,
|
|
39
|
-
width,
|
|
40
|
-
// TODO: make margin the responsibility of a parent
|
|
41
|
-
// https://github.com/telus/universal-design-system/issues/525
|
|
42
|
-
marginTop = 0,
|
|
43
|
-
marginBottom = 0,
|
|
44
|
-
marginLeft = 0,
|
|
45
|
-
marginRight = 0
|
|
46
|
-
}) => {
|
|
38
|
+
const selectOuterWidthStyles = ({ outerBorderGap, outerBorderWidth, width }) => {
|
|
47
39
|
// The inner container's bounding box is the bounding box of the button overall
|
|
48
40
|
// so this many device pixels will sit outside of the overall bounding box
|
|
49
41
|
const outerBorderOffset = getOuterBorderOffset({ outerBorderGap, outerBorderWidth })
|
|
50
42
|
const widthStyles = {
|
|
51
|
-
|
|
52
|
-
marginBottom: marginBottom - outerBorderOffset,
|
|
53
|
-
marginLeft: marginLeft - outerBorderOffset,
|
|
54
|
-
marginRight: marginRight - outerBorderOffset
|
|
43
|
+
margin: 0 - outerBorderOffset
|
|
55
44
|
}
|
|
56
45
|
|
|
57
46
|
if (!width) {
|
|
@@ -59,9 +48,8 @@ const selectOuterWidthStyles = ({
|
|
|
59
48
|
...widthStyles,
|
|
60
49
|
// Wrap content, stopping a flex parent's default align-items: stretch stretching focus ring beyond content
|
|
61
50
|
...Platform.select({
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
native: { alignSelf: 'flex-start' }
|
|
51
|
+
// width: fit-content isn't supported on Firefox; can't cascade props like CSS `width: fit-content; width: --moz-fit-content;`
|
|
52
|
+
web: { display: 'inline-flex' }
|
|
65
53
|
})
|
|
66
54
|
}
|
|
67
55
|
}
|
|
@@ -152,7 +140,7 @@ const ButtonBase = ({
|
|
|
152
140
|
selected = false,
|
|
153
141
|
...rest
|
|
154
142
|
}) => {
|
|
155
|
-
const getTokens = useThemeTokensCallback('Button')
|
|
143
|
+
const getTokens = useThemeTokensCallback('Button', tokens, variant)
|
|
156
144
|
const getButtonState = ({ pressed, focused, hovered }) => ({
|
|
157
145
|
pressed,
|
|
158
146
|
focus: focused,
|
|
@@ -160,8 +148,7 @@ const ButtonBase = ({
|
|
|
160
148
|
inactive,
|
|
161
149
|
selected
|
|
162
150
|
})
|
|
163
|
-
const getTokensByPressableState = (pressableState) =>
|
|
164
|
-
getTokens(tokens, variant, getButtonState(pressableState))
|
|
151
|
+
const getTokensByPressableState = (pressableState) => getTokens(getButtonState(pressableState))
|
|
165
152
|
|
|
166
153
|
const a11y = a11yProps.select(rest)
|
|
167
154
|
|
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
|
-
import {
|
|
3
|
+
import { Platform } from 'react-native'
|
|
4
4
|
|
|
5
5
|
import ButtonBase from './ButtonBase'
|
|
6
|
+
import { StackWrap } from '../StackView'
|
|
6
7
|
import { useViewport } from '../ViewportProvider'
|
|
7
8
|
import { useThemeTokens } from '../ThemeProvider'
|
|
8
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
a11yProps,
|
|
11
|
+
pressProps,
|
|
12
|
+
variantProp,
|
|
13
|
+
getTokensPropType,
|
|
14
|
+
selectTokens
|
|
15
|
+
} from '../utils/propTypes'
|
|
9
16
|
import { useMultipleInputValues } from '../utils/input'
|
|
10
17
|
|
|
11
|
-
const selectContainerStyles = ({ direction }) => ({
|
|
12
|
-
flexDirection: direction
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
const selectItemTokens = ({ gap }, index) => ({
|
|
16
|
-
marginLeft: index && gap
|
|
17
|
-
})
|
|
18
|
-
|
|
19
18
|
const ButtonGroup = ({
|
|
20
19
|
variant,
|
|
21
20
|
buttonVariant = {},
|
|
@@ -34,7 +33,8 @@ const ButtonGroup = ({
|
|
|
34
33
|
}) => {
|
|
35
34
|
const viewport = useViewport()
|
|
36
35
|
const themeTokens = useThemeTokens('ButtonGroup', tokens, variant, { viewport })
|
|
37
|
-
const
|
|
36
|
+
const stackTokens = selectTokens('StackView', themeTokens)
|
|
37
|
+
const { direction, space } = themeTokens
|
|
38
38
|
|
|
39
39
|
const { currentValues, toggleOneValue } = useMultipleInputValues({
|
|
40
40
|
initialValues,
|
|
@@ -51,9 +51,8 @@ const ButtonGroup = ({
|
|
|
51
51
|
const itemA11yRole = a11y.accessibilityRole === 'radioGroup' ? 'radio' : 'checkbox'
|
|
52
52
|
|
|
53
53
|
return (
|
|
54
|
-
<
|
|
54
|
+
<StackWrap {...a11y} space={space} direction={direction} tokens={stackTokens}>
|
|
55
55
|
{items.map(({ label, id = label, accessibilityLabel }, index) => {
|
|
56
|
-
const itemTokens = selectItemTokens(themeTokens, index)
|
|
57
56
|
const isSelected = currentValues.includes(id)
|
|
58
57
|
|
|
59
58
|
// Allow handlers to be passed down for blur, hover, focus, pressIn, etc
|
|
@@ -87,15 +86,12 @@ const ButtonGroup = ({
|
|
|
87
86
|
|
|
88
87
|
// Ensure button is direct child of group as MacOS voiceover only applies "X of Y" to
|
|
89
88
|
// "radio" if it's a direct child of "radiogroup", even if aria-posinset etc exists
|
|
90
|
-
// See also: TODO: make margin the responsibility of a parent
|
|
91
|
-
// https://github.com/telus/universal-design-system/issues/525
|
|
92
89
|
return (
|
|
93
90
|
<ButtonBase
|
|
94
91
|
key={id}
|
|
95
92
|
{...pressHandlers}
|
|
96
93
|
onPress={handlePress}
|
|
97
94
|
variant={{ component: 'ButtonGroup', ...buttonVariant }}
|
|
98
|
-
tokens={itemTokens}
|
|
99
95
|
selected={isSelected}
|
|
100
96
|
inactive={inactive}
|
|
101
97
|
{...itemA11y}
|
|
@@ -104,7 +100,7 @@ const ButtonGroup = ({
|
|
|
104
100
|
</ButtonBase>
|
|
105
101
|
)
|
|
106
102
|
})}
|
|
107
|
-
</
|
|
103
|
+
</StackWrap>
|
|
108
104
|
)
|
|
109
105
|
}
|
|
110
106
|
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import { View } from 'react-native'
|
|
4
|
+
|
|
5
|
+
import { applyShadowToken, useThemeTokens } from '../ThemeProvider'
|
|
6
|
+
import { getTokensPropType, variantProp } from '../utils'
|
|
7
|
+
import { useViewport } from '../ViewportProvider'
|
|
8
|
+
import { a11yProps } from '../utils/propTypes'
|
|
9
|
+
|
|
10
|
+
// Ensure explicit selection of tokens
|
|
11
|
+
const selectStyles = ({
|
|
12
|
+
backgroundColor,
|
|
13
|
+
borderColor,
|
|
14
|
+
borderRadius,
|
|
15
|
+
borderWidth,
|
|
16
|
+
paddingBottom,
|
|
17
|
+
paddingLeft,
|
|
18
|
+
paddingRight,
|
|
19
|
+
paddingTop,
|
|
20
|
+
shadow
|
|
21
|
+
}) => ({
|
|
22
|
+
backgroundColor,
|
|
23
|
+
borderColor,
|
|
24
|
+
borderRadius,
|
|
25
|
+
borderWidth,
|
|
26
|
+
paddingBottom,
|
|
27
|
+
paddingLeft,
|
|
28
|
+
paddingRight,
|
|
29
|
+
paddingTop,
|
|
30
|
+
...applyShadowToken(shadow)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A basic card component, unstyled by default.
|
|
35
|
+
*
|
|
36
|
+
* ## Component API
|
|
37
|
+
*
|
|
38
|
+
* ### Background
|
|
39
|
+
*
|
|
40
|
+
* In order to control the background of a card, the following tokens are currently
|
|
41
|
+
* supported:
|
|
42
|
+
*
|
|
43
|
+
* - `backgroundColor`
|
|
44
|
+
*
|
|
45
|
+
* ### Border
|
|
46
|
+
*
|
|
47
|
+
* The following border tokens can be used:
|
|
48
|
+
*
|
|
49
|
+
* - `borderColor`
|
|
50
|
+
* - `borderRadius`
|
|
51
|
+
* - `borderWidth`
|
|
52
|
+
*
|
|
53
|
+
* ### Padding
|
|
54
|
+
*
|
|
55
|
+
* Please use the following tokens to control the padding:
|
|
56
|
+
*
|
|
57
|
+
* - `paddingBottom`
|
|
58
|
+
* - `paddingLeft`
|
|
59
|
+
* - `paddingRight`
|
|
60
|
+
* - `paddingTop`
|
|
61
|
+
*
|
|
62
|
+
* Note that various viewport sizes are supported as well.
|
|
63
|
+
*
|
|
64
|
+
* ### Shadow
|
|
65
|
+
*
|
|
66
|
+
* Feel free to use the following properties within the `shadow` token:
|
|
67
|
+
*
|
|
68
|
+
* - `inset`: boolean
|
|
69
|
+
* - `color`: string
|
|
70
|
+
* - `offsetX`: number
|
|
71
|
+
* - `offsetY`: number
|
|
72
|
+
* - `blur`: number
|
|
73
|
+
* - `spread`: number
|
|
74
|
+
*
|
|
75
|
+
* ## Accessibility
|
|
76
|
+
*
|
|
77
|
+
* Card supports all the common a11y props. Please remember that by marking a card as `accessible`
|
|
78
|
+
* you automatically make inaccessible its children, which may or may not be appropriate
|
|
79
|
+
* depending on what you are trying to achieve.
|
|
80
|
+
*/
|
|
81
|
+
const Card = ({ children, tokens, variant, ...rest }) => {
|
|
82
|
+
const viewport = useViewport()
|
|
83
|
+
const themeTokens = useThemeTokens('Card', tokens, variant, { viewport })
|
|
84
|
+
const cardStyle = selectStyles(themeTokens)
|
|
85
|
+
const a11y = a11yProps.select(rest)
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<View style={cardStyle} {...a11y}>
|
|
89
|
+
{children}
|
|
90
|
+
</View>
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
Card.propTypes = {
|
|
95
|
+
children: PropTypes.node,
|
|
96
|
+
tokens: getTokensPropType('Card'),
|
|
97
|
+
variant: variantProp.propType,
|
|
98
|
+
...a11yProps.types
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export default Card
|
package/src/Divider/Divider.jsx
CHANGED
|
@@ -2,7 +2,12 @@ import React from 'react'
|
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
3
|
import { View, StyleSheet, Platform } from 'react-native'
|
|
4
4
|
import { useThemeTokens } from '../ThemeProvider'
|
|
5
|
-
import
|
|
5
|
+
import Spacer from '../Spacer'
|
|
6
|
+
import { getTokensPropType, variantProp, spacingProps } from '../utils'
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {import('../utils/propTypes.js').SpacingIndex} SpacingIndex
|
|
9
|
+
* @typedef {import('../utils/propTypes.js').SpacingObject} SpacingObject
|
|
10
|
+
*/
|
|
6
11
|
|
|
7
12
|
/**
|
|
8
13
|
* A basic divider component, horizontal by default. Color and thickness can be controlled by theme.
|
|
@@ -16,11 +21,31 @@ import { getTokensPropType, variantProp } from '../utils/propTypes'
|
|
|
16
21
|
*
|
|
17
22
|
* In a flexbox row, vertical dividers will automatically size to their parent height.
|
|
18
23
|
*
|
|
24
|
+
* ## Space
|
|
25
|
+
*
|
|
26
|
+
* Use this to create **space either side of the divider**. For simple cases, pass a number referring to
|
|
27
|
+
* a position on the theme's spacing scale; for example, this will put a Spacer of the smallest supported
|
|
28
|
+
* size either side of the divider:
|
|
29
|
+
*
|
|
30
|
+
* ```jsx
|
|
31
|
+
* <Divider space={1} />
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* `space` prop uses `useSpacingScale` and may accept a {@link SpacingObject} or a {@link SpacingIndex} number.
|
|
35
|
+
*
|
|
36
|
+
* To **reduce the length of a divider** as well as creating space between it and its neighbours, wrap it in
|
|
37
|
+
* a `Box` component. For example, this will have the second-smallest theme-supported spacing value between
|
|
38
|
+
* the dividing line and its neighbours, and will shorten the line at either end by the same amount:
|
|
39
|
+
*
|
|
40
|
+
* ```jsx
|
|
41
|
+
* <Box space={2}><Divider /></Box>
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
19
44
|
* ## Accessibility
|
|
20
45
|
*
|
|
21
46
|
* For accessibility purposes a divider component will be described with ARIA attributes, i.e. `role="separator"` and `aria-orientation="vertical/horizontal"`.
|
|
22
47
|
*/
|
|
23
|
-
const Divider = ({ variant, vertical = false, tokens, testID }) => {
|
|
48
|
+
const Divider = ({ variant, vertical = false, space, tokens, testID }) => {
|
|
24
49
|
const { color, width } = useThemeTokens('Divider', tokens, variant)
|
|
25
50
|
|
|
26
51
|
const borderStyles = vertical
|
|
@@ -43,11 +68,21 @@ const Divider = ({ variant, vertical = false, tokens, testID }) => {
|
|
|
43
68
|
: // There are no such equivalent attributes for native
|
|
44
69
|
{}
|
|
45
70
|
|
|
46
|
-
|
|
71
|
+
const divider = <View style={[styles.divider, borderStyles]} testID={testID} {...a11y} />
|
|
72
|
+
if (!space) return divider
|
|
73
|
+
const spacerProps = { space, direction: vertical ? 'row' : 'column' }
|
|
74
|
+
return (
|
|
75
|
+
<>
|
|
76
|
+
<Spacer {...spacerProps} testID={testID ? `${testID}-Spacer-before` : undefined} />
|
|
77
|
+
{divider}
|
|
78
|
+
<Spacer {...spacerProps} testID={testID ? `${testID}-Spacer-after` : undefined} />
|
|
79
|
+
</>
|
|
80
|
+
)
|
|
47
81
|
}
|
|
48
82
|
|
|
49
83
|
Divider.propTypes = {
|
|
50
84
|
tokens: getTokensPropType('Divider'),
|
|
85
|
+
space: spacingProps.types.spacingValue,
|
|
51
86
|
variant: variantProp.propType,
|
|
52
87
|
/**
|
|
53
88
|
* By default, the divider is a horizontal line the full width of its parent.
|
|
@@ -56,7 +56,7 @@ const ExpandCollapseControl = ({
|
|
|
56
56
|
variant,
|
|
57
57
|
rest
|
|
58
58
|
}) => {
|
|
59
|
-
const getTokens = useThemeTokensCallback('ExpandCollapseControl')
|
|
59
|
+
const getTokens = useThemeTokensCallback('ExpandCollapseControl', tokens, variant)
|
|
60
60
|
|
|
61
61
|
const a11y = a11yProps.select({ ...rest, accessibilityRole })
|
|
62
62
|
a11y.accessibilityState = {
|
|
@@ -70,8 +70,7 @@ const ExpandCollapseControl = ({
|
|
|
70
70
|
focus: focused,
|
|
71
71
|
expanded: isExpanded
|
|
72
72
|
})
|
|
73
|
-
const getControlTokens = (pressableState) =>
|
|
74
|
-
getTokens(tokens, variant, getControlState(pressableState))
|
|
73
|
+
const getControlTokens = (pressableState) => getTokens(getControlState(pressableState))
|
|
75
74
|
const getPressableStyle = (pressableState) =>
|
|
76
75
|
selectContainerStyles(getControlTokens(pressableState))
|
|
77
76
|
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Text, View, StyleSheet } from 'react-native'
|
|
3
|
+
import PropTypes from 'prop-types'
|
|
4
|
+
|
|
5
|
+
import { applyTextStyles, useThemeTokens } from '../ThemeProvider'
|
|
6
|
+
import { a11yProps, getTokensPropType, selectTokens, variantProp } from '../utils'
|
|
7
|
+
|
|
8
|
+
const selectStyles = (tokens) => selectTokens('Feedback', tokens)
|
|
9
|
+
|
|
10
|
+
const selectTitleTextStyles = ({ titleFontSize, ...tokens }) =>
|
|
11
|
+
applyTextStyles(selectTokens('Typography', { ...tokens, fontSize: titleFontSize }))
|
|
12
|
+
const selectContentTextStyles = ({ contentFontSize, ...tokens }) =>
|
|
13
|
+
applyTextStyles(selectTokens('Typography', { ...tokens, fontSize: contentFontSize }))
|
|
14
|
+
|
|
15
|
+
const selectIconTokens = ({ iconSize, iconColor }) => ({
|
|
16
|
+
size: iconSize,
|
|
17
|
+
color: iconColor
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const selectIconContainerStyles = ({ iconGap }) => ({
|
|
21
|
+
paddingRight: iconGap
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A feedback box commonly used with form fields.
|
|
26
|
+
*
|
|
27
|
+
* ### Standalone usage
|
|
28
|
+
* While its primary use is to facilitate feedback states for other form components such as `TextInput`,
|
|
29
|
+
* you may use it standalone.
|
|
30
|
+
*
|
|
31
|
+
* ### Complex content
|
|
32
|
+
* You may pass any React tree as the children of this component, bear in mind that a render function
|
|
33
|
+
* is better suited for styling children based on Feedback's variant.
|
|
34
|
+
*
|
|
35
|
+
* ### Using a render function
|
|
36
|
+
* When a function is passed for rendering content, it will receive the feedback text styles and
|
|
37
|
+
* variant as arguments.
|
|
38
|
+
*
|
|
39
|
+
* ### Accessibility
|
|
40
|
+
* All accessibility props set on this component will be applied to the outer container.
|
|
41
|
+
*/
|
|
42
|
+
const Feedback = ({ title, children, tokens, variant, ...rest }) => {
|
|
43
|
+
const themeTokens = useThemeTokens('Feedback', tokens, variant)
|
|
44
|
+
|
|
45
|
+
const { icon: IconComponent } = themeTokens
|
|
46
|
+
|
|
47
|
+
const titleTextStyles = selectTitleTextStyles(themeTokens)
|
|
48
|
+
const contentTextStyles = selectContentTextStyles(themeTokens)
|
|
49
|
+
|
|
50
|
+
const content =
|
|
51
|
+
typeof children === 'string' ? <Text style={contentTextStyles}>{children}</Text> : children
|
|
52
|
+
|
|
53
|
+
const accessibilityProps = a11yProps.select(rest)
|
|
54
|
+
|
|
55
|
+
// TODO: use Stack to separate the title from content (space 2)
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<View style={selectStyles(themeTokens)} {...accessibilityProps}>
|
|
59
|
+
{title !== undefined && (
|
|
60
|
+
<View style={staticStyles.title}>
|
|
61
|
+
{IconComponent && (
|
|
62
|
+
<View style={selectIconContainerStyles(themeTokens)}>
|
|
63
|
+
<IconComponent tokens={selectIconTokens(themeTokens)} />
|
|
64
|
+
</View>
|
|
65
|
+
)}
|
|
66
|
+
<Text style={titleTextStyles}>{title}</Text>
|
|
67
|
+
</View>
|
|
68
|
+
)}
|
|
69
|
+
{content && typeof content === 'function' ? (
|
|
70
|
+
content({ textStyles: contentTextStyles, variant })
|
|
71
|
+
) : (
|
|
72
|
+
<View>{content}</View>
|
|
73
|
+
)}
|
|
74
|
+
</View>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
Feedback.propTypes = {
|
|
79
|
+
/**
|
|
80
|
+
* Emphasized summary of the feedback. If an icon is set, it is rendered next to the title.
|
|
81
|
+
*/
|
|
82
|
+
title: PropTypes.string,
|
|
83
|
+
/**
|
|
84
|
+
* Feedback content rendered below the title. A render function `({textStyles, variant}) => {}` is supported.
|
|
85
|
+
*/
|
|
86
|
+
children: PropTypes.oneOfType([PropTypes.string, PropTypes.node, PropTypes.func]),
|
|
87
|
+
tokens: getTokensPropType('Feedback'),
|
|
88
|
+
variant: variantProp.propType
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export default Feedback
|
|
92
|
+
|
|
93
|
+
const staticStyles = StyleSheet.create({
|
|
94
|
+
title: {
|
|
95
|
+
display: 'flex',
|
|
96
|
+
flexDirection: 'row',
|
|
97
|
+
alignItems: 'center'
|
|
98
|
+
}
|
|
99
|
+
})
|
package/src/FlexGrid/Col/Col.jsx
CHANGED
|
@@ -6,7 +6,7 @@ import { viewports } from '@telus-uds/system-constants'
|
|
|
6
6
|
import GutterContext from '../providers/GutterContext'
|
|
7
7
|
import { useViewport } from '../../ViewportProvider'
|
|
8
8
|
import applyInheritance from '../helpers'
|
|
9
|
-
import {
|
|
9
|
+
import { responsiveProps } from '../../utils'
|
|
10
10
|
|
|
11
11
|
const Col = ({
|
|
12
12
|
horizontalAlign,
|
|
@@ -258,7 +258,9 @@ Col.propTypes = {
|
|
|
258
258
|
*
|
|
259
259
|
* Accepts a `PropType.string` following the [responsive prop](#/Layout?id=responsive) structure.
|
|
260
260
|
*/
|
|
261
|
-
horizontalAlign:
|
|
261
|
+
horizontalAlign: responsiveProps.getTypeOptionallyByViewport(
|
|
262
|
+
PropTypes.oneOf(['left', 'center', 'right'])
|
|
263
|
+
)
|
|
262
264
|
}
|
|
263
265
|
|
|
264
266
|
export default Col
|
package/src/Icon/Icon.jsx
CHANGED
|
@@ -19,7 +19,8 @@ const Icon = ({ IconSvg, variant, label, titleId, tokens = {} }) => {
|
|
|
19
19
|
transition: 'transform 200ms',
|
|
20
20
|
transform: [
|
|
21
21
|
themeTokens.scale ? `scale(${themeTokens.scale})` : '',
|
|
22
|
-
themeTokens.translateX ? `translateX(${themeTokens.translateX}px)` : ''
|
|
22
|
+
themeTokens.translateX ? `translateX(${themeTokens.translateX}px)` : '',
|
|
23
|
+
themeTokens.translateY ? `translateY(${themeTokens.translateY}px)` : ''
|
|
23
24
|
]
|
|
24
25
|
.filter((exists) => exists)
|
|
25
26
|
.join(' ')
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { View, Text, StyleSheet } from 'react-native'
|
|
3
|
+
import PropTypes from 'prop-types'
|
|
4
|
+
|
|
5
|
+
import { applyTextStyles, useThemeTokens } from '../ThemeProvider'
|
|
6
|
+
import { getTokensPropType, selectTokens, variantProp } from '../utils'
|
|
7
|
+
|
|
8
|
+
import LabelContent from './LabelContent'
|
|
9
|
+
|
|
10
|
+
const selectLabelStyles = (tokens) => applyTextStyles(selectTokens('Typography', tokens))
|
|
11
|
+
|
|
12
|
+
const selectHintStyles = ({
|
|
13
|
+
hintColor,
|
|
14
|
+
hintFontName,
|
|
15
|
+
hintFontSize,
|
|
16
|
+
hintFontWeight,
|
|
17
|
+
hintLineHeight
|
|
18
|
+
}) =>
|
|
19
|
+
applyTextStyles({
|
|
20
|
+
color: hintColor,
|
|
21
|
+
fontName: hintFontName,
|
|
22
|
+
fontSize: hintFontSize,
|
|
23
|
+
fontWeight: hintFontWeight,
|
|
24
|
+
lineHeight: hintLineHeight
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const selectGapStyles = ({ gap }) => ({ marginRight: gap })
|
|
28
|
+
|
|
29
|
+
function InputLabel({
|
|
30
|
+
label,
|
|
31
|
+
forId,
|
|
32
|
+
hint,
|
|
33
|
+
hintPosition = 'inline',
|
|
34
|
+
hintId,
|
|
35
|
+
tooltip,
|
|
36
|
+
tokens,
|
|
37
|
+
variant
|
|
38
|
+
}) {
|
|
39
|
+
const themeTokens = useThemeTokens('InputLabel', tokens, variant)
|
|
40
|
+
|
|
41
|
+
// TODO: use the actual Tooltip component here
|
|
42
|
+
const hasTooltip = tooltip !== undefined
|
|
43
|
+
const isHintInline = hintPosition === 'inline'
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<View style={[staticStyles.container, !isHintInline && staticStyles.containerWithHintBelow]}>
|
|
47
|
+
<Text
|
|
48
|
+
style={[selectLabelStyles(themeTokens), selectGapStyles(themeTokens), staticStyles.label]}
|
|
49
|
+
>
|
|
50
|
+
<LabelContent forId={forId}>{label}</LabelContent>
|
|
51
|
+
</Text>
|
|
52
|
+
{hint && isHintInline && (
|
|
53
|
+
<Text
|
|
54
|
+
style={[selectHintStyles(themeTokens), hasTooltip && selectGapStyles(themeTokens)]}
|
|
55
|
+
nativeID={hintId}
|
|
56
|
+
>
|
|
57
|
+
{hint}
|
|
58
|
+
</Text>
|
|
59
|
+
)}
|
|
60
|
+
{tooltip && <Text>?</Text>}
|
|
61
|
+
{hint && !isHintInline && (
|
|
62
|
+
<Text style={[selectHintStyles(themeTokens), staticStyles.hintBelow]} nativeID={hintId}>
|
|
63
|
+
{hint}
|
|
64
|
+
</Text>
|
|
65
|
+
)}
|
|
66
|
+
</View>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
InputLabel.propTypes = {
|
|
71
|
+
label: PropTypes.string.isRequired,
|
|
72
|
+
forId: PropTypes.string,
|
|
73
|
+
hint: PropTypes.string,
|
|
74
|
+
hintPosition: PropTypes.oneOf(['inline', 'below']),
|
|
75
|
+
hintId: PropTypes.string,
|
|
76
|
+
tooltip: PropTypes.string,
|
|
77
|
+
tokens: getTokensPropType('InputLabel'),
|
|
78
|
+
variant: variantProp.propType
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export default InputLabel
|
|
82
|
+
|
|
83
|
+
const staticStyles = StyleSheet.create({
|
|
84
|
+
container: {
|
|
85
|
+
display: 'flex',
|
|
86
|
+
flexDirection: 'row',
|
|
87
|
+
alignItems: 'center'
|
|
88
|
+
},
|
|
89
|
+
containerWithHintBelow: {
|
|
90
|
+
flexWrap: 'wrap'
|
|
91
|
+
},
|
|
92
|
+
label: {
|
|
93
|
+
flexShrink: 0
|
|
94
|
+
},
|
|
95
|
+
hintBelow: {
|
|
96
|
+
flexBasis: '100%',
|
|
97
|
+
flexShrink: 0
|
|
98
|
+
}
|
|
99
|
+
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
|
|
4
|
+
function LabelContent({ children, forId }) {
|
|
5
|
+
return <label htmlFor={forId}>{children}</label>
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default LabelContent
|
|
9
|
+
|
|
10
|
+
LabelContent.propTypes = {
|
|
11
|
+
children: PropTypes.string,
|
|
12
|
+
forId: PropTypes.string
|
|
13
|
+
}
|
package/src/Link/LinkBase.jsx
CHANGED
|
@@ -40,7 +40,10 @@ const selectOuterBorderStyles = ({
|
|
|
40
40
|
outline: outerBorderOutline,
|
|
41
41
|
borderWidth: outerBorderWidth,
|
|
42
42
|
borderColor: outerBorderColor,
|
|
43
|
-
borderRadius: outerBorderRadius
|
|
43
|
+
borderRadius: outerBorderRadius,
|
|
44
|
+
// Stops focus ring stretching horizontally if parent has display: block
|
|
45
|
+
// width: fit-content isn't supported on Firefox; can't cascade props like CSS `width: fit-content; width: --moz-fit-content;`
|
|
46
|
+
display: 'inline-flex'
|
|
44
47
|
}
|
|
45
48
|
: {}
|
|
46
49
|
|
|
@@ -62,10 +65,12 @@ const selectIconStyles = ({
|
|
|
62
65
|
iconGapBefore,
|
|
63
66
|
iconGapAfter,
|
|
64
67
|
iconScale,
|
|
65
|
-
iconTranslateX
|
|
68
|
+
iconTranslateX,
|
|
69
|
+
iconTranslateY
|
|
66
70
|
}) => ({
|
|
67
71
|
scale: iconScale,
|
|
68
72
|
translateX: iconTranslateX,
|
|
73
|
+
translateY: iconTranslateY,
|
|
69
74
|
size: iconSize,
|
|
70
75
|
gapBefore: iconGapBefore,
|
|
71
76
|
gapAfter: iconGapAfter
|
|
@@ -181,7 +186,8 @@ const LinkBase = ({
|
|
|
181
186
|
size: iconStyles.size ? iconStyles.size * iconScale : undefined,
|
|
182
187
|
color: contentStyles.color ?? undefined,
|
|
183
188
|
scale: iconStyles.scale ?? undefined,
|
|
184
|
-
translateX: iconStyles.translateX ?? undefined
|
|
189
|
+
translateX: iconStyles.translateX ?? undefined,
|
|
190
|
+
translateY: iconStyles.translateY ?? undefined
|
|
185
191
|
}
|
|
186
192
|
|
|
187
193
|
const iconContent = <IconComponent tokens={iconTokens} variant={iconVariant} />
|