@telus-uds/components-base 3.18.0 → 3.20.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/CHANGELOG.md +32 -1
- package/jest.config.cjs +10 -2
- package/lib/cjs/Box/Box.js +114 -62
- package/lib/cjs/Box/backgroundImageStylesMap.js +136 -28
- package/lib/cjs/Button/ButtonDropdown.js +1 -0
- package/lib/cjs/Carousel/Carousel.js +1 -1
- package/lib/cjs/ExpandCollapseMini/ExpandCollapseMiniControl.js +8 -21
- package/lib/cjs/Link/LinkBase.js +8 -9
- package/lib/cjs/MultiSelectFilter/MultiSelectFilter.js +10 -10
- package/lib/cjs/Spacer/Spacer.js +65 -5
- package/lib/cjs/StepTracker/Step.js +12 -1
- package/lib/cjs/StepTracker/StepTracker.js +15 -4
- package/lib/cjs/TabBar/TabBar.js +4 -2
- package/lib/cjs/TabBar/index.js +2 -0
- package/lib/cjs/Tooltip/Backdrop.js +1 -1
- package/lib/cjs/utils/index.js +17 -1
- package/lib/cjs/utils/isTouchDevice.js +34 -0
- package/lib/cjs/utils/useMediaQuerySpacing.js +121 -0
- package/lib/esm/Box/Box.js +113 -63
- package/lib/esm/Box/backgroundImageStylesMap.js +134 -27
- package/lib/esm/Button/ButtonDropdown.js +1 -0
- package/lib/esm/Carousel/Carousel.js +2 -2
- package/lib/esm/ExpandCollapseMini/ExpandCollapseMiniControl.js +8 -21
- package/lib/esm/Link/LinkBase.js +8 -9
- package/lib/esm/MultiSelectFilter/MultiSelectFilter.js +10 -10
- package/lib/esm/Spacer/Spacer.js +66 -6
- package/lib/esm/StepTracker/Step.js +12 -1
- package/lib/esm/StepTracker/StepTracker.js +15 -4
- package/lib/esm/TabBar/TabBar.js +4 -2
- package/lib/esm/TabBar/index.js +2 -0
- package/lib/esm/Tooltip/Backdrop.js +1 -1
- package/lib/esm/utils/index.js +3 -1
- package/lib/esm/utils/isTouchDevice.js +27 -0
- package/lib/esm/utils/useMediaQuerySpacing.js +116 -0
- package/lib/package.json +2 -2
- package/package.json +2 -2
- package/src/Box/Box.jsx +97 -55
- package/src/Box/backgroundImageStylesMap.js +48 -15
- package/src/Button/ButtonDropdown.jsx +1 -0
- package/src/Carousel/Carousel.jsx +3 -2
- package/src/ExpandCollapseMini/ExpandCollapseMiniControl.jsx +9 -16
- package/src/Link/LinkBase.jsx +11 -9
- package/src/MultiSelectFilter/MultiSelectFilter.jsx +11 -10
- package/src/Spacer/Spacer.jsx +54 -7
- package/src/StepTracker/Step.jsx +47 -27
- package/src/StepTracker/StepTracker.jsx +9 -1
- package/src/TabBar/TabBar.jsx +3 -1
- package/src/TabBar/index.js +3 -0
- package/src/Tooltip/Backdrop.jsx +1 -1
- package/src/utils/index.js +2 -0
- package/src/utils/isTouchDevice.js +34 -0
- package/src/utils/useMediaQuerySpacing.js +124 -0
|
@@ -1,21 +1,54 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { Platform } from 'react-native'
|
|
2
|
+
|
|
3
|
+
const webStyles = {
|
|
4
|
+
'top-start': { top: 0, left: 0 },
|
|
5
|
+
'top-center': { top: 0, left: '50%', transform: [{ translateX: '-50%' }] },
|
|
4
6
|
'top-end': { top: 0, right: 0 },
|
|
5
7
|
'right-start': { top: 0, right: 0 },
|
|
6
|
-
'left-start': { top: 0 },
|
|
7
|
-
'left-center': { top:
|
|
8
|
-
'
|
|
9
|
-
'none-center': { top: 0, bottom: 0, left: 0, right: 0, margin: 'auto' },
|
|
10
|
-
'right-center': { top: 0, bottom: 0, right: 0, marginVertical: 'auto' },
|
|
11
|
-
'none-end': { top: 0, bottom: 0, right: 0, marginVertical: 'auto' },
|
|
8
|
+
'left-start': { top: 0, left: 0 },
|
|
9
|
+
'left-center': { top: '50%', left: 0, transform: [{ translateY: '-50%' }] },
|
|
10
|
+
'right-center': { top: '50%', right: 0, transform: [{ translateY: '-50%' }] },
|
|
12
11
|
'bottom-start': { bottom: 0, left: 0 },
|
|
13
12
|
'left-end': { bottom: 0, left: 0 },
|
|
14
|
-
'bottom-center': {
|
|
15
|
-
'bottom-end': {
|
|
16
|
-
'right-end': {
|
|
17
|
-
'top-stretch': { left: 0, right: 0, width: '100%' },
|
|
18
|
-
'left-stretch': { top: 0, bottom: 0, height: '100%' },
|
|
13
|
+
'bottom-center': { bottom: 0, left: '50%', transform: [{ translateX: '-50%' }] },
|
|
14
|
+
'bottom-end': { bottom: 0, right: 0 },
|
|
15
|
+
'right-end': { bottom: 0, right: 0 },
|
|
16
|
+
'top-stretch': { top: 0, left: 0, right: 0, width: '100%' },
|
|
17
|
+
'left-stretch': { top: 0, bottom: 0, left: 0, height: '100%' },
|
|
19
18
|
'right-stretch': { top: 0, bottom: 0, right: 0, height: '100%' },
|
|
20
|
-
'bottom-stretch': {
|
|
19
|
+
'bottom-stretch': { bottom: 0, left: 0, right: 0, width: '100%' }
|
|
21
20
|
}
|
|
21
|
+
|
|
22
|
+
const webBackgroundPositions = {
|
|
23
|
+
'top-start': 'left top',
|
|
24
|
+
'top-center': 'center top',
|
|
25
|
+
'top-end': 'right top',
|
|
26
|
+
'bottom-start': 'left bottom',
|
|
27
|
+
'bottom-center': 'center bottom',
|
|
28
|
+
'bottom-end': 'right bottom',
|
|
29
|
+
'left-center': 'left center',
|
|
30
|
+
'right-center': 'right center'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const nativeStyles = {
|
|
34
|
+
'top-start': { top: 0, left: 0, width: 150, height: 200 },
|
|
35
|
+
'top-center': { top: 0, left: '50%', marginLeft: -75, width: 150, height: 200 },
|
|
36
|
+
'top-end': { top: 0, right: 0, width: 150, height: 200 },
|
|
37
|
+
'right-start': { top: 0, right: 0, width: 150, height: 200 },
|
|
38
|
+
'left-start': { top: 0, left: 0, width: 150, height: 200 },
|
|
39
|
+
'left-center': { left: 0, top: '50%', marginTop: -100, width: 150, height: 200 },
|
|
40
|
+
'right-center': { right: 0, top: '50%', marginTop: -100, width: 150, height: 200 },
|
|
41
|
+
'bottom-start': { bottom: 0, left: 0, width: 150, height: 200 },
|
|
42
|
+
'left-end': { bottom: 0, left: 0, width: 150, height: 200 },
|
|
43
|
+
'bottom-center': { bottom: 0, left: '50%', marginLeft: -75, width: 150, height: 200 },
|
|
44
|
+
'bottom-end': { bottom: 0, right: 0, width: 150, height: 200 },
|
|
45
|
+
'right-end': { bottom: 0, right: 0, width: 150, height: 200 },
|
|
46
|
+
'top-stretch': { top: 0, left: 0, right: 0, width: '100%' },
|
|
47
|
+
'left-stretch': { top: 0, bottom: 0, left: 0, height: '100%' },
|
|
48
|
+
'right-stretch': { top: 0, bottom: 0, right: 0, height: '100%' },
|
|
49
|
+
'bottom-stretch': { bottom: 0, left: 0, right: 0, width: '100%' }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const backgroundPositions = Platform.OS === 'web' ? webBackgroundPositions : {}
|
|
53
|
+
|
|
54
|
+
export default Platform.OS === 'web' ? webStyles : nativeStyles
|
|
@@ -56,6 +56,7 @@ const selectDescriptionTextStyles = (tokens) => ({
|
|
|
56
56
|
fontName: tokens?.descriptionFontName,
|
|
57
57
|
fontSize: tokens?.descriptionFontSize,
|
|
58
58
|
fontWeight: tokens?.descriptionFontWeight,
|
|
59
|
+
lineHeight: tokens?.descriptionLineHeight,
|
|
59
60
|
fontColor: tokens?.color
|
|
60
61
|
}),
|
|
61
62
|
paddingBottom: tokens?.descriptionTextPaddingBottom
|
|
@@ -12,7 +12,8 @@ import {
|
|
|
12
12
|
a11yProps,
|
|
13
13
|
viewProps,
|
|
14
14
|
useCopy,
|
|
15
|
-
unpackFragment
|
|
15
|
+
unpackFragment,
|
|
16
|
+
isTouchDevice
|
|
16
17
|
} from '../utils'
|
|
17
18
|
import { useA11yInfo } from '../A11yInfoProvider'
|
|
18
19
|
import { CarouselProvider } from './CarouselContext'
|
|
@@ -799,7 +800,7 @@ const Carousel = React.forwardRef(
|
|
|
799
800
|
return false
|
|
800
801
|
}
|
|
801
802
|
if (Platform.OS === 'web') {
|
|
802
|
-
return !!(viewport === 'xs' || viewport === 'sm')
|
|
803
|
+
return !!(viewport === 'xs' || viewport === 'sm' || (viewport === 'md' && isTouchDevice()))
|
|
803
804
|
}
|
|
804
805
|
return true
|
|
805
806
|
}, [viewport, totalItems])
|
|
@@ -62,36 +62,28 @@ const ExpandCollapseMiniControl = React.forwardRef(
|
|
|
62
62
|
const iconBaselineOffset = 0
|
|
63
63
|
const hoverTranslateY = 4
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
const staticOffset = hoverTranslateY // Fixed downward adjustment to fine-tune vertical alignment
|
|
70
|
-
const sizeCompensation = -Math.abs(iconSize - fontSize) // Compensates when icon and text sizes differ significantly
|
|
65
|
+
const fontBaseline = fontSize / hoverTranslateY
|
|
66
|
+
const iconBaseline = iconSize / hoverTranslateY
|
|
67
|
+
const staticOffset = hoverTranslateY
|
|
68
|
+
const sizeCompensation = -Math.abs(iconSize - fontSize)
|
|
71
69
|
|
|
72
70
|
const baselineAlignment = fontBaseline + iconBaseline - staticOffset + sizeCompensation
|
|
73
71
|
|
|
74
|
-
|
|
75
|
-
// For native platforms, use baseline alignment with optional offset
|
|
76
|
-
return { iconTranslateY: baselineAlignment + iconBaselineOffset }
|
|
77
|
-
}
|
|
72
|
+
const mobileAdjustment = Platform.OS !== 'web' ? -2 : 0
|
|
78
73
|
|
|
79
74
|
if (isHovered) {
|
|
80
|
-
// Apply animation offset to the baseline-aligned position
|
|
81
|
-
// When expanded: move icon UP (1.3 the hover distance for clear movement)
|
|
82
|
-
// When collapsed: move icon DOWN (single hover distance)
|
|
83
75
|
const hoverMovementDistance = 1.3
|
|
84
76
|
const animationOffset = expanded
|
|
85
77
|
? -(hoverTranslateY * hoverMovementDistance)
|
|
86
78
|
: hoverTranslateY
|
|
87
79
|
|
|
88
80
|
return {
|
|
89
|
-
iconTranslateY:
|
|
81
|
+
iconTranslateY:
|
|
82
|
+
baselineAlignment + iconBaselineOffset + animationOffset + mobileAdjustment
|
|
90
83
|
}
|
|
91
84
|
}
|
|
92
85
|
|
|
93
|
-
|
|
94
|
-
return { iconTranslateY: baselineAlignment + iconBaselineOffset }
|
|
86
|
+
return { iconTranslateY: baselineAlignment + iconBaselineOffset + mobileAdjustment }
|
|
95
87
|
}
|
|
96
88
|
|
|
97
89
|
return (
|
|
@@ -103,6 +95,7 @@ const ExpandCollapseMiniControl = React.forwardRef(
|
|
|
103
95
|
...linkTokens,
|
|
104
96
|
...getTokens(linkState),
|
|
105
97
|
iconSize,
|
|
98
|
+
blockFontSize: fontSize,
|
|
106
99
|
blockLineHeight: lineHeight
|
|
107
100
|
})}
|
|
108
101
|
ref={ref}
|
package/src/Link/LinkBase.jsx
CHANGED
|
@@ -171,9 +171,12 @@ const LinkBase = React.forwardRef(
|
|
|
171
171
|
const themeTokens = resolveLinkTokens(linkState)
|
|
172
172
|
const outerBorderStyles = selectOuterBorderStyles(themeTokens)
|
|
173
173
|
const decorationStyles = selectDecorationStyles(themeTokens)
|
|
174
|
+
|
|
175
|
+
const mobileCompensation = null
|
|
176
|
+
|
|
174
177
|
return [
|
|
175
178
|
outerBorderStyles,
|
|
176
|
-
|
|
179
|
+
mobileCompensation,
|
|
177
180
|
blockLeftStyle,
|
|
178
181
|
decorationStyles,
|
|
179
182
|
hasIcon && staticStyles.rowContainer
|
|
@@ -191,11 +194,14 @@ const LinkBase = React.forwardRef(
|
|
|
191
194
|
const IconComponent = icon || themeTokens.icon
|
|
192
195
|
const { iconSpace } = themeTokens
|
|
193
196
|
|
|
197
|
+
const isTextOnlyLink = !IconComponent && !icon && accessibilityRole === 'link'
|
|
198
|
+
const adjustedIconSpace = Platform.OS !== 'web' && isTextOnlyLink ? 0 : iconSpace
|
|
199
|
+
|
|
194
200
|
return (
|
|
195
201
|
<IconText
|
|
196
202
|
icon={IconComponent}
|
|
197
203
|
iconPosition={iconPosition}
|
|
198
|
-
space={
|
|
204
|
+
space={adjustedIconSpace}
|
|
199
205
|
iconProps={{
|
|
200
206
|
...iconProps,
|
|
201
207
|
tokens: iconTokens,
|
|
@@ -274,15 +280,11 @@ const staticStyles = StyleSheet.create({
|
|
|
274
280
|
}
|
|
275
281
|
})
|
|
276
282
|
},
|
|
277
|
-
|
|
283
|
+
outerBorderCompensation: {
|
|
278
284
|
...(Platform.OS !== 'web' && {
|
|
279
|
-
margin: 0,
|
|
280
285
|
marginHorizontal: 2,
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
...(Platform.OS === 'android' && {
|
|
284
|
-
paddingHorizontal: 2,
|
|
285
|
-
paddingTop: 2
|
|
286
|
+
paddingHorizontal: Platform.OS === 'android' ? 2 : 0,
|
|
287
|
+
paddingTop: Platform.OS === 'android' ? 2 : 0
|
|
286
288
|
})
|
|
287
289
|
}
|
|
288
290
|
})
|
|
@@ -65,7 +65,6 @@ const selectContainerStyle = (windowHeight, windowWidth) => ({
|
|
|
65
65
|
})
|
|
66
66
|
|
|
67
67
|
const TOTAL_COLUMNS = 12
|
|
68
|
-
const MAX_ITEMS_THRESHOLD = 12
|
|
69
68
|
|
|
70
69
|
const MultiSelectFilter = React.forwardRef(
|
|
71
70
|
(
|
|
@@ -174,13 +173,15 @@ const MultiSelectFilter = React.forwardRef(
|
|
|
174
173
|
const getCopy = useCopy({ dictionary, copy })
|
|
175
174
|
const colSizeNotMobile = items.length > rowLimit ? 2 : 1
|
|
176
175
|
const colSize = viewport !== 'xs' ? colSizeNotMobile : 1
|
|
177
|
-
|
|
178
|
-
|
|
176
|
+
|
|
177
|
+
let rowLength = items.length
|
|
178
|
+
if (viewport !== 'xs' && colSize === 2) {
|
|
179
|
+
rowLength = Math.ceil(items.length / 2)
|
|
180
|
+
}
|
|
179
181
|
|
|
180
182
|
React.useEffect(() => {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}, [colSize])
|
|
183
|
+
setMaxWidth(items.length >= rowLimit)
|
|
184
|
+
}, [items.length, rowLimit])
|
|
184
185
|
|
|
185
186
|
React.useEffect(() => setCheckedIds(currentValues ?? []), [currentValues])
|
|
186
187
|
|
|
@@ -414,14 +415,14 @@ const MultiSelectFilter = React.forwardRef(
|
|
|
414
415
|
dismissWhenPressedOutside={dismissWhenPressedOutside}
|
|
415
416
|
onClose={onClose}
|
|
416
417
|
overlaidPosition={overlaidPosition}
|
|
417
|
-
maxHeight={items.length
|
|
418
|
+
maxHeight={items.length >= rowLimit ? true : maxHeight}
|
|
418
419
|
maxHeightSize={maxHeightSize}
|
|
419
420
|
maxWidthSize={maxWidthSize}
|
|
420
421
|
minHeight={minHeight}
|
|
421
422
|
minWidth={minWidth}
|
|
422
423
|
tokens={{
|
|
423
424
|
...tokens,
|
|
424
|
-
maxWidth: items.length
|
|
425
|
+
maxWidth: items.length >= rowLimit ? true : maxWidth,
|
|
425
426
|
borderColor: containerBorderColor
|
|
426
427
|
}}
|
|
427
428
|
copy={copy}
|
|
@@ -479,9 +480,9 @@ MultiSelectFilter.propTypes = {
|
|
|
479
480
|
*/
|
|
480
481
|
label: PropTypes.string.isRequired,
|
|
481
482
|
/**
|
|
482
|
-
* The text for the subtitle
|
|
483
|
+
* The text for the subtitle. Can also be JSX.
|
|
483
484
|
*/
|
|
484
|
-
subtitle: PropTypes.string,
|
|
485
|
+
subtitle: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
|
485
486
|
/**
|
|
486
487
|
* An optional unique string may be provided to identify the ButtonDropdown.
|
|
487
488
|
* If not provided, the label is used.
|
package/src/Spacer/Spacer.jsx
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { View, StyleSheet } from 'react-native'
|
|
4
|
+
import {
|
|
5
|
+
a11yProps,
|
|
6
|
+
selectSystemProps,
|
|
7
|
+
spacingProps,
|
|
8
|
+
useSpacingScale,
|
|
9
|
+
viewProps,
|
|
10
|
+
StyleSheet as StyleSheetUtils,
|
|
11
|
+
createMediaQueryStyles
|
|
12
|
+
} from '../utils'
|
|
13
|
+
import useMediaQuerySpacing from '../utils/useMediaQuerySpacing'
|
|
14
|
+
import useTheme from '../ThemeProvider/useTheme'
|
|
5
15
|
|
|
6
16
|
/**
|
|
7
17
|
* @typedef {import('../utils/props/spacingProps.js').SpacingValue} SpacingValue
|
|
@@ -56,11 +66,43 @@ const selectSizeStyle = (size, direction) => ({
|
|
|
56
66
|
* Spacer has no content and is ignored by tools such as screen readers. Use `Divider` for
|
|
57
67
|
* separations between elements that may be treated as semantically meaningful on web.
|
|
58
68
|
*/
|
|
59
|
-
const Spacer = React.forwardRef(({ space = 1, direction = 'column', ...rest }, ref) => {
|
|
60
|
-
const
|
|
61
|
-
|
|
69
|
+
const Spacer = React.forwardRef(({ space = 1, direction = 'column', dataSet, ...rest }, ref) => {
|
|
70
|
+
const {
|
|
71
|
+
themeOptions: { enableMediaQueryStyleSheet }
|
|
72
|
+
} = useTheme()
|
|
62
73
|
|
|
63
|
-
|
|
74
|
+
const { sizeByViewport } = useMediaQuerySpacing(space)
|
|
75
|
+
|
|
76
|
+
const fallbackSize = useSpacingScale(space)
|
|
77
|
+
const sizeStyle = selectSizeStyle(fallbackSize, direction)
|
|
78
|
+
|
|
79
|
+
let spacerStyles
|
|
80
|
+
let dataSetValue = dataSet
|
|
81
|
+
|
|
82
|
+
if (enableMediaQueryStyleSheet) {
|
|
83
|
+
const sizeKey = direction === 'row' ? 'width' : 'height'
|
|
84
|
+
const stylesByViewport = {
|
|
85
|
+
xs: { [sizeKey]: sizeByViewport.xs, ...staticStyles.stretch },
|
|
86
|
+
sm: { [sizeKey]: sizeByViewport.sm, ...staticStyles.stretch },
|
|
87
|
+
md: { [sizeKey]: sizeByViewport.md, ...staticStyles.stretch },
|
|
88
|
+
lg: { [sizeKey]: sizeByViewport.lg, ...staticStyles.stretch },
|
|
89
|
+
xl: { [sizeKey]: sizeByViewport.xl, ...staticStyles.stretch }
|
|
90
|
+
}
|
|
91
|
+
const mediaQueryStyles = createMediaQueryStyles(stylesByViewport)
|
|
92
|
+
|
|
93
|
+
const { ids, styles } = StyleSheetUtils.create({
|
|
94
|
+
spacer: {
|
|
95
|
+
...mediaQueryStyles
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
spacerStyles = styles.spacer
|
|
100
|
+
dataSetValue = { media: ids.spacer, ...dataSet }
|
|
101
|
+
} else {
|
|
102
|
+
spacerStyles = [staticStyles.stretch, sizeStyle]
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return <View ref={ref} style={spacerStyles} dataSet={dataSetValue} {...selectProps(rest)} />
|
|
64
106
|
})
|
|
65
107
|
Spacer.displayName = 'Spacer'
|
|
66
108
|
|
|
@@ -78,7 +120,12 @@ Spacer.propTypes = {
|
|
|
78
120
|
* - `'column'` (default) applies space vertically; has a fixed height and not width.
|
|
79
121
|
* - `'row'` applies space horizontally; has a fixed width and not height.
|
|
80
122
|
*/
|
|
81
|
-
direction: PropTypes.oneOf(['column', 'row'])
|
|
123
|
+
direction: PropTypes.oneOf(['column', 'row']),
|
|
124
|
+
/**
|
|
125
|
+
* Data attributes to be applied to the element. When media query stylesheet is enabled,
|
|
126
|
+
* this will include media query IDs for responsive styling.
|
|
127
|
+
*/
|
|
128
|
+
dataSet: PropTypes.object
|
|
82
129
|
}
|
|
83
130
|
|
|
84
131
|
const staticStyles = StyleSheet.create({
|
package/src/StepTracker/Step.jsx
CHANGED
|
@@ -137,12 +137,24 @@ const getStepTestID = (isCompleted, isCurrent) => {
|
|
|
137
137
|
|
|
138
138
|
return testID
|
|
139
139
|
}
|
|
140
|
+
const selectBarContainerStyles = (themeTokens, isCompleted, isCurrent) => ({
|
|
141
|
+
backgroundColor: isCompleted
|
|
142
|
+
? themeTokens.barCompletedBackgroundColor
|
|
143
|
+
: themeTokens.barBackgroundColor,
|
|
144
|
+
height: themeTokens.barHeight,
|
|
145
|
+
...(isCurrent && {
|
|
146
|
+
backgroundColor: themeTokens.barCurrentBackgroundColor
|
|
147
|
+
})
|
|
148
|
+
})
|
|
140
149
|
|
|
141
150
|
/**
|
|
142
151
|
* A single step of a StepTracker.
|
|
143
152
|
*/
|
|
144
153
|
const Step = React.forwardRef(
|
|
145
|
-
(
|
|
154
|
+
(
|
|
155
|
+
{ label, name, status = 0, stepCount = 0, stepIndex = 0, tokens, isBarVariant, ...rest },
|
|
156
|
+
ref
|
|
157
|
+
) => {
|
|
146
158
|
const { completedIcon, showStepLabel, showStepName, textStepTrackerLabel, ...themeTokens } =
|
|
147
159
|
tokens
|
|
148
160
|
const isFirst = stepIndex === 0
|
|
@@ -162,35 +174,43 @@ const Step = React.forwardRef(
|
|
|
162
174
|
ref={ref}
|
|
163
175
|
{...selectProps(rest)}
|
|
164
176
|
>
|
|
165
|
-
|
|
166
|
-
direction="row"
|
|
167
|
-
space={0}
|
|
168
|
-
tokens={{ alignItems: 'center', flexGrow: 0, justifyContent: 'center' }}
|
|
169
|
-
>
|
|
177
|
+
{isBarVariant && (
|
|
170
178
|
<View
|
|
171
|
-
style={
|
|
172
|
-
staticStyles.connector,
|
|
173
|
-
!isFirst && selectConnectorStyles(themeTokens, isActive)
|
|
174
|
-
]}
|
|
175
|
-
/>
|
|
176
|
-
<View
|
|
177
|
-
style={[staticStyles.knob, selectKnobStyles(themeTokens, isCompleted, isCurrent)]}
|
|
179
|
+
style={selectBarContainerStyles(themeTokens, isCompleted, isCurrent)}
|
|
178
180
|
testID={getStepTestID(isCompleted, isCurrent)}
|
|
179
|
-
>
|
|
180
|
-
{isCompleted && completedIcon && (
|
|
181
|
-
<Icon icon={completedIcon} tokens={selectCompletedIconTokens(themeTokens)} />
|
|
182
|
-
)}
|
|
183
|
-
{((isCurrent && completedIcon) || (isCurrent && !completedIcon)) && (
|
|
184
|
-
<View style={selectCurrentInnerStyles(themeTokens)} />
|
|
185
|
-
)}
|
|
186
|
-
</View>
|
|
187
|
-
<View
|
|
188
|
-
style={[
|
|
189
|
-
staticStyles.connector,
|
|
190
|
-
!isLast && selectConnectorStyles(themeTokens, isCompleted)
|
|
191
|
-
]}
|
|
192
181
|
/>
|
|
193
|
-
|
|
182
|
+
)}
|
|
183
|
+
{!isBarVariant && (
|
|
184
|
+
<StackView
|
|
185
|
+
direction="row"
|
|
186
|
+
space={0}
|
|
187
|
+
tokens={{ alignItems: 'center', flexGrow: 0, justifyContent: 'center' }}
|
|
188
|
+
>
|
|
189
|
+
<View
|
|
190
|
+
style={[
|
|
191
|
+
staticStyles.connector,
|
|
192
|
+
!isFirst && selectConnectorStyles(themeTokens, isActive)
|
|
193
|
+
]}
|
|
194
|
+
/>
|
|
195
|
+
<View
|
|
196
|
+
style={[staticStyles.knob, selectKnobStyles(themeTokens, isCompleted, isCurrent)]}
|
|
197
|
+
testID={getStepTestID(isCompleted, isCurrent)}
|
|
198
|
+
>
|
|
199
|
+
{isCompleted && completedIcon && (
|
|
200
|
+
<Icon icon={completedIcon} tokens={selectCompletedIconTokens(themeTokens)} />
|
|
201
|
+
)}
|
|
202
|
+
{((isCurrent && completedIcon) || (isCurrent && !completedIcon)) && (
|
|
203
|
+
<View style={selectCurrentInnerStyles(themeTokens)} />
|
|
204
|
+
)}
|
|
205
|
+
</View>
|
|
206
|
+
<View
|
|
207
|
+
style={[
|
|
208
|
+
staticStyles.connector,
|
|
209
|
+
!isLast && selectConnectorStyles(themeTokens, isCompleted)
|
|
210
|
+
]}
|
|
211
|
+
/>
|
|
212
|
+
</StackView>
|
|
213
|
+
)}
|
|
194
214
|
{showStepLabel && (
|
|
195
215
|
<View style={[staticStyles.stepLabelContainer, selectLabelContainerStyles(tokens)]}>
|
|
196
216
|
{showStepName && (
|
|
@@ -9,6 +9,8 @@ import useCopy from '../utils/useCopy'
|
|
|
9
9
|
import Step from './Step'
|
|
10
10
|
import defaultDictionary from './dictionary'
|
|
11
11
|
|
|
12
|
+
const STYLE_BAR_VARIANT = 'bar'
|
|
13
|
+
|
|
12
14
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
|
|
13
15
|
|
|
14
16
|
const selectContainerStyles = ({
|
|
@@ -38,6 +40,10 @@ const selectStepTrackerLabelStyles = (
|
|
|
38
40
|
themeOptions
|
|
39
41
|
})
|
|
40
42
|
|
|
43
|
+
const selectStepsContainerStyles = ({ barGap }) => ({
|
|
44
|
+
gap: barGap
|
|
45
|
+
})
|
|
46
|
+
|
|
41
47
|
/**
|
|
42
48
|
* StepTracker component shows the current position in a sequence of steps.
|
|
43
49
|
*
|
|
@@ -83,6 +89,7 @@ const StepTracker = React.forwardRef(
|
|
|
83
89
|
},
|
|
84
90
|
ref
|
|
85
91
|
) => {
|
|
92
|
+
const isBarVariant = variant?.style === STYLE_BAR_VARIANT
|
|
86
93
|
const viewport = useViewport()
|
|
87
94
|
const { showStepTrackerLabel, ...themeTokens } = useThemeTokens(
|
|
88
95
|
'StepTracker',
|
|
@@ -135,7 +142,7 @@ const StepTracker = React.forwardRef(
|
|
|
135
142
|
<View ref={ref} style={selectContainerStyles(themeTokens)} {...selectedProps}>
|
|
136
143
|
<StackView space={0}>
|
|
137
144
|
<View
|
|
138
|
-
style={staticStyles.stepsContainer}
|
|
145
|
+
style={[staticStyles.stepsContainer, selectStepsContainerStyles(themeTokens)]}
|
|
139
146
|
accessibilityRole={stepsContainerAccessibilityRole}
|
|
140
147
|
>
|
|
141
148
|
{steps.map((label, index) => {
|
|
@@ -150,6 +157,7 @@ const StepTracker = React.forwardRef(
|
|
|
150
157
|
tokens={themeTokens}
|
|
151
158
|
accessibilityRole={stepAccessibilityRole}
|
|
152
159
|
accessibilityCurrent={current === index && Platform.OS === 'web' && 'step'}
|
|
160
|
+
isBarVariant={isBarVariant}
|
|
153
161
|
/>
|
|
154
162
|
)
|
|
155
163
|
})}
|
package/src/TabBar/TabBar.jsx
CHANGED
|
@@ -74,6 +74,7 @@ const TabBar = React.forwardRef(
|
|
|
74
74
|
onPress={() => handlePress(item.id)}
|
|
75
75
|
id={`tab-item-${index}`}
|
|
76
76
|
accessibilityRole="tablist"
|
|
77
|
+
tokens={item.tokens}
|
|
77
78
|
/>
|
|
78
79
|
))}
|
|
79
80
|
</View>
|
|
@@ -93,7 +94,8 @@ TabBar.propTypes = {
|
|
|
93
94
|
icon: PropTypes.node,
|
|
94
95
|
iconActive: PropTypes.node,
|
|
95
96
|
label: PropTypes.string.isRequired,
|
|
96
|
-
href: PropTypes.string
|
|
97
|
+
href: PropTypes.string,
|
|
98
|
+
tokens: getTokensPropType('TabBarItem')
|
|
97
99
|
})
|
|
98
100
|
).isRequired,
|
|
99
101
|
/** Id of the initially selected item. */
|
package/src/TabBar/index.js
CHANGED
package/src/Tooltip/Backdrop.jsx
CHANGED
package/src/utils/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export { default as info } from './info'
|
|
|
9
9
|
export { default as useCopy } from './useCopy'
|
|
10
10
|
export { default as useHash } from './useHash'
|
|
11
11
|
export { default as useSpacingScale } from './useSpacingScale'
|
|
12
|
+
export { default as useMediaQuerySpacing } from './useMediaQuerySpacing'
|
|
12
13
|
export { default as useResponsiveProp } from './useResponsiveProp'
|
|
13
14
|
export { default as useOverlaidPosition } from './useOverlaidPosition'
|
|
14
15
|
export { default as useSafeLayoutEffect } from './useSafeLayoutEffect'
|
|
@@ -25,3 +26,4 @@ export { default as convertFromMegaByteToByte } from './convertFromMegaByteToByt
|
|
|
25
26
|
export { default as formatImageSource } from './formatImageSource'
|
|
26
27
|
export { default as getSpacingScale } from './getSpacingScale'
|
|
27
28
|
export { default as useVariants } from './useVariants'
|
|
29
|
+
export { default as isTouchDevice } from './isTouchDevice'
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Platform } from 'react-native'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Determines if the current device supports touch interactions
|
|
5
|
+
*
|
|
6
|
+
* @returns {boolean} True if the device supports touch, false otherwise
|
|
7
|
+
*/
|
|
8
|
+
const isTouchDevice = () => {
|
|
9
|
+
if (Platform.OS !== 'web') {
|
|
10
|
+
return true
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (typeof window !== 'undefined') {
|
|
14
|
+
if ('ontouchstart' in window) {
|
|
15
|
+
return true
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (window.navigator && window.navigator.maxTouchPoints > 0) {
|
|
19
|
+
return true
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (window.navigator && window.navigator.msMaxTouchPoints > 0) {
|
|
23
|
+
return true
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (window.matchMedia && window.matchMedia('(pointer: coarse)').matches) {
|
|
27
|
+
return true
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return false
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default isTouchDevice
|