@telus-uds/components-base 4.0.0-alpha.0 → 4.0.0-alpha.2
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 +62 -6
- package/jest.config.cjs +1 -0
- package/lib/cjs/ActionCard/ActionCard.js +10 -3
- package/lib/cjs/Card/Card.js +3 -3
- package/lib/cjs/Carousel/Carousel.js +6 -1
- package/lib/cjs/Carousel/CarouselThumbnail.js +125 -33
- package/lib/cjs/Carousel/CarouselThumbnailNavigation.js +8 -1
- package/lib/cjs/Footnote/FootnoteLink.js +18 -17
- package/lib/cjs/InputSupports/InputSupports.js +1 -2
- package/lib/cjs/InputSupports/useInputSupports.js +1 -3
- package/lib/cjs/Link/ChevronLink.js +1 -2
- package/lib/cjs/Notification/Notification.js +4 -12
- package/lib/cjs/Progress/Progress.js +30 -5
- package/lib/cjs/Progress/ProgressBar.js +3 -3
- package/lib/cjs/Progress/ProgressBarBackground.js +2 -3
- package/lib/cjs/QuickLinks/QuickLinks.js +7 -0
- package/lib/cjs/Scroll/Scroll.js +472 -0
- package/lib/cjs/Scroll/ScrollContext.js +55 -0
- package/lib/cjs/Scroll/ScrollItem.js +106 -0
- package/lib/cjs/Scroll/ScrollProgress.js +100 -0
- package/lib/cjs/Scroll/dictionary.js +18 -0
- package/lib/cjs/StackView/StackWrapBox.js +9 -1
- package/lib/cjs/StackView/StackWrapGap.js +3 -1
- package/lib/cjs/StackView/getStackedContent.js +20 -10
- package/lib/cjs/index.js +14 -0
- package/lib/cjs/utils/animation/useAnimatedValue.js +46 -0
- package/lib/cjs/utils/children.js +2 -1
- package/lib/esm/ActionCard/ActionCard.js +10 -3
- package/lib/esm/Card/Card.js +3 -3
- package/lib/esm/Carousel/Carousel.js +6 -1
- package/lib/esm/Carousel/CarouselThumbnail.js +126 -34
- package/lib/esm/Carousel/CarouselThumbnailNavigation.js +8 -1
- package/lib/esm/Footnote/FootnoteLink.js +18 -17
- package/lib/esm/InputSupports/InputSupports.js +1 -2
- package/lib/esm/InputSupports/useInputSupports.js +1 -3
- package/lib/esm/Link/ChevronLink.js +1 -2
- package/lib/esm/Notification/Notification.js +4 -12
- package/lib/esm/Progress/Progress.js +30 -5
- package/lib/esm/Progress/ProgressBar.js +3 -3
- package/lib/esm/Progress/ProgressBarBackground.js +2 -3
- package/lib/esm/QuickLinks/QuickLinks.js +7 -0
- package/lib/esm/Scroll/Scroll.js +465 -0
- package/lib/esm/Scroll/ScrollContext.js +46 -0
- package/lib/esm/Scroll/ScrollItem.js +100 -0
- package/lib/esm/Scroll/ScrollProgress.js +93 -0
- package/lib/esm/Scroll/dictionary.js +12 -0
- package/lib/esm/StackView/StackWrapBox.js +9 -1
- package/lib/esm/StackView/StackWrapGap.js +3 -1
- package/lib/esm/StackView/getStackedContent.js +20 -10
- package/lib/esm/index.js +2 -0
- package/lib/esm/utils/animation/useAnimatedValue.js +38 -0
- package/lib/esm/utils/children.js +2 -1
- package/lib/package.json +2 -2
- package/package.json +2 -2
- package/src/ActionCard/ActionCard.jsx +13 -4
- package/src/Card/Card.jsx +3 -3
- package/src/Carousel/Carousel.jsx +6 -1
- package/src/Carousel/CarouselThumbnail.jsx +117 -30
- package/src/Carousel/CarouselThumbnailNavigation.jsx +8 -2
- package/src/Footnote/FootnoteLink.jsx +17 -12
- package/src/InputSupports/InputSupports.jsx +1 -6
- package/src/InputSupports/useInputSupports.js +1 -1
- package/src/Link/ChevronLink.jsx +1 -2
- package/src/Notification/Notification.jsx +5 -21
- package/src/Progress/Progress.jsx +22 -3
- package/src/Progress/ProgressBar.jsx +3 -3
- package/src/Progress/ProgressBarBackground.jsx +2 -3
- package/src/QuickLinks/QuickLinks.jsx +8 -0
- package/src/Scroll/Scroll.jsx +483 -0
- package/src/Scroll/ScrollContext.jsx +39 -0
- package/src/Scroll/ScrollItem.jsx +87 -0
- package/src/Scroll/ScrollProgress.jsx +74 -0
- package/src/Scroll/dictionary.js +12 -0
- package/src/StackView/StackWrapBox.jsx +13 -1
- package/src/StackView/StackWrapGap.jsx +2 -1
- package/src/StackView/getStackedContent.jsx +22 -8
- package/src/index.js +2 -0
- package/src/utils/animation/useAnimatedValue.js +35 -0
- package/src/utils/children.jsx +4 -1
- package/types/Link.d.ts +1 -2
- package/types/Scroll.d.ts +66 -0
- package/types/index.d.ts +9 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
|
-
import { Pressable, Image } from 'react-native'
|
|
3
|
+
import { StyleSheet, Pressable, Image, View } from 'react-native'
|
|
4
4
|
import { useCarousel } from './CarouselContext'
|
|
5
5
|
import { useThemeTokensCallback } from '../ThemeProvider/useThemeTokens'
|
|
6
6
|
import { useViewport } from '../ViewportProvider/useViewport'
|
|
7
|
+
import { Icon } from '../Icon/Icon'
|
|
7
8
|
|
|
8
9
|
const selectPressableTokens = ({ borderColor, borderRadius, borderWidth, margin, padding }) => ({
|
|
9
10
|
borderColor,
|
|
@@ -13,12 +14,47 @@ const selectPressableTokens = ({ borderColor, borderRadius, borderWidth, margin,
|
|
|
13
14
|
padding
|
|
14
15
|
})
|
|
15
16
|
|
|
17
|
+
// Play icon overlay appearance is consistent across all brands and is not theme-configurable.
|
|
18
|
+
// The circle occupies 55% of the thumbnail size, and the icon occupies 55% of the circle diameter.
|
|
19
|
+
const PLAY_ICON_RATIO = 0.55
|
|
20
|
+
const PLAY_ICON_BORDER_RADIUS_DIVISOR = 2
|
|
21
|
+
|
|
22
|
+
const selectImageStyles = (size) => ({
|
|
23
|
+
width: size,
|
|
24
|
+
height: size
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const selectSelectedStyles = ({ selectedBorderColor, selectedBorderWidth, padding, margin }) => ({
|
|
28
|
+
borderColor: selectedBorderColor,
|
|
29
|
+
borderWidth: selectedBorderWidth,
|
|
30
|
+
padding: padding - selectedBorderWidth,
|
|
31
|
+
marginBottom: margin + selectedBorderWidth
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const selectNonSelectedStyles = ({ borderWidth, padding, margin, selectedBorderWidth }) => ({
|
|
35
|
+
padding: padding - borderWidth,
|
|
36
|
+
marginBottom: margin + selectedBorderWidth
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const selectPlayIconCircleStyles = (thumbnailSize) => {
|
|
40
|
+
const diameter = thumbnailSize * PLAY_ICON_RATIO
|
|
41
|
+
return {
|
|
42
|
+
width: diameter,
|
|
43
|
+
height: diameter,
|
|
44
|
+
borderRadius: diameter / PLAY_ICON_BORDER_RADIUS_DIVISOR
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const selectPlayIconTokens = (thumbnailSize) => ({
|
|
49
|
+
size: thumbnailSize * PLAY_ICON_RATIO * PLAY_ICON_RATIO
|
|
50
|
+
})
|
|
51
|
+
|
|
16
52
|
/**
|
|
17
|
-
* `
|
|
53
|
+
* `CarouselThumbnail` is used to wrap the content of an individual slide and is suppsoed to be the
|
|
18
54
|
* only top-level component passed to the `Carousel`
|
|
19
55
|
*/
|
|
20
56
|
export const CarouselThumbnail = React.forwardRef(
|
|
21
|
-
({ accessibilityLabel, alt, index, src }, ref) => {
|
|
57
|
+
({ accessibilityLabel, alt, index, isVideo, src }, ref) => {
|
|
22
58
|
const { activeIndex, itemLabel, totalItems, getCopyWithPlaceholders, goTo } = useCarousel()
|
|
23
59
|
const getThumbnailTokens = useThemeTokensCallback('CarouselThumbnail')
|
|
24
60
|
const viewport = useViewport()
|
|
@@ -33,24 +69,15 @@ export const CarouselThumbnail = React.forwardRef(
|
|
|
33
69
|
// Allow using the spacebar for navigation
|
|
34
70
|
if (event?.key === ' ') goTo(index)
|
|
35
71
|
}
|
|
36
|
-
const {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
borderWidth: selectedBorderWidth,
|
|
46
|
-
padding: padding - selectedBorderWidth,
|
|
47
|
-
marginBottom: margin + selectedBorderWidth
|
|
48
|
-
},
|
|
49
|
-
nonSelected: {
|
|
50
|
-
padding: padding - borderWidth,
|
|
51
|
-
marginBottom: margin + selectedBorderWidth
|
|
52
|
-
}
|
|
53
|
-
}
|
|
72
|
+
const {
|
|
73
|
+
borderWidth,
|
|
74
|
+
padding,
|
|
75
|
+
selectedBorderColor,
|
|
76
|
+
selectedBorderWidth,
|
|
77
|
+
size,
|
|
78
|
+
margin,
|
|
79
|
+
playIcon
|
|
80
|
+
} = getThumbnailTokens({ viewport })
|
|
54
81
|
|
|
55
82
|
return (
|
|
56
83
|
<Pressable
|
|
@@ -68,18 +95,48 @@ export const CarouselThumbnail = React.forwardRef(
|
|
|
68
95
|
|
|
69
96
|
return [
|
|
70
97
|
pressableStyles,
|
|
71
|
-
index === activeIndex
|
|
98
|
+
index === activeIndex
|
|
99
|
+
? [
|
|
100
|
+
selectSelectedStyles({
|
|
101
|
+
selectedBorderColor,
|
|
102
|
+
selectedBorderWidth,
|
|
103
|
+
padding,
|
|
104
|
+
margin
|
|
105
|
+
}),
|
|
106
|
+
staticStyles.selectedPressableOutline
|
|
107
|
+
]
|
|
108
|
+
: selectNonSelectedStyles({ borderWidth, padding, margin, selectedBorderWidth })
|
|
72
109
|
]
|
|
73
110
|
}}
|
|
74
111
|
ref={ref}
|
|
75
112
|
>
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
113
|
+
<View style={[staticStyles.imageContainer, selectImageStyles(size)]}>
|
|
114
|
+
<Image
|
|
115
|
+
accessibilityIgnoresInvertColors
|
|
116
|
+
accessibilityLabel={accessibilityLabel ?? alt}
|
|
117
|
+
source={src}
|
|
118
|
+
style={selectImageStyles(size)}
|
|
119
|
+
title={thumbnailTitle}
|
|
120
|
+
/>
|
|
121
|
+
{isVideo && playIcon && (
|
|
122
|
+
<View
|
|
123
|
+
style={staticStyles.playIconOverlayContainer}
|
|
124
|
+
testID={`play-icon-overlay-${index}`}
|
|
125
|
+
>
|
|
126
|
+
<View
|
|
127
|
+
style={[selectPlayIconCircleStyles(size), staticStyles.playIconCircleBackground]}
|
|
128
|
+
>
|
|
129
|
+
<Icon
|
|
130
|
+
icon={playIcon}
|
|
131
|
+
tokens={{
|
|
132
|
+
...selectPlayIconTokens(size),
|
|
133
|
+
color: staticStyles.playIconSymbol.color
|
|
134
|
+
}}
|
|
135
|
+
/>
|
|
136
|
+
</View>
|
|
137
|
+
</View>
|
|
138
|
+
)}
|
|
139
|
+
</View>
|
|
83
140
|
</Pressable>
|
|
84
141
|
)
|
|
85
142
|
}
|
|
@@ -88,8 +145,38 @@ export const CarouselThumbnail = React.forwardRef(
|
|
|
88
145
|
CarouselThumbnail.displayName = 'CarouselThumbnail'
|
|
89
146
|
|
|
90
147
|
CarouselThumbnail.propTypes = {
|
|
148
|
+
/** Accessibility label for screen readers, overrides the alt text */
|
|
91
149
|
accessibilityLabel: PropTypes.string,
|
|
150
|
+
/** Alt text for the thumbnail image */
|
|
92
151
|
alt: PropTypes.string,
|
|
152
|
+
/** Zero-based index of this thumbnail within the carousel */
|
|
93
153
|
index: PropTypes.number,
|
|
94
|
-
|
|
154
|
+
/**
|
|
155
|
+
* When true, renders a play icon overlay on the thumbnail to indicate that the slide contains a video.
|
|
156
|
+
*/
|
|
157
|
+
isVideo: PropTypes.bool,
|
|
158
|
+
/** Image source URI (web) or local asset require() (native) */
|
|
159
|
+
src: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
|
|
95
160
|
}
|
|
161
|
+
|
|
162
|
+
const staticStyles = StyleSheet.create({
|
|
163
|
+
imageContainer: {
|
|
164
|
+
position: 'relative'
|
|
165
|
+
},
|
|
166
|
+
playIconOverlayContainer: {
|
|
167
|
+
position: 'absolute',
|
|
168
|
+
top: 0,
|
|
169
|
+
left: 0,
|
|
170
|
+
right: 0,
|
|
171
|
+
bottom: 0,
|
|
172
|
+
justifyContent: 'center',
|
|
173
|
+
alignItems: 'center'
|
|
174
|
+
},
|
|
175
|
+
selectedPressableOutline: { outlineStyle: 'none' },
|
|
176
|
+
playIconCircleBackground: {
|
|
177
|
+
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
|
178
|
+
justifyContent: 'center',
|
|
179
|
+
alignItems: 'center'
|
|
180
|
+
},
|
|
181
|
+
playIconSymbol: { color: 'rgb(255, 255, 255)' }
|
|
182
|
+
})
|
|
@@ -27,11 +27,12 @@ export const CarouselThumbnailNavigation = React.forwardRef(({ thumbnails = [] }
|
|
|
27
27
|
return (
|
|
28
28
|
<View style={containerStyles}>
|
|
29
29
|
<StackWrap direction="row" tokens={stackWrapTokens} space={2} ref={ref}>
|
|
30
|
-
{thumbnails.map(({ accessibilityLabel, alt, src }, index) => (
|
|
30
|
+
{thumbnails.map(({ accessibilityLabel, alt, isVideo, src }, index) => (
|
|
31
31
|
<CarouselThumbnail
|
|
32
32
|
accessibilityLabel={accessibilityLabel}
|
|
33
33
|
alt={alt}
|
|
34
34
|
index={index}
|
|
35
|
+
isVideo={isVideo}
|
|
35
36
|
key={src}
|
|
36
37
|
src={src}
|
|
37
38
|
/>
|
|
@@ -47,9 +48,14 @@ CarouselThumbnailNavigation.propTypes = {
|
|
|
47
48
|
*/
|
|
48
49
|
thumbnails: PropTypes.arrayOf(
|
|
49
50
|
PropTypes.shape({
|
|
51
|
+
/** Accessibility label for the thumbnail image, used by assistive technologies. */
|
|
50
52
|
accessibilityLabel: PropTypes.string,
|
|
53
|
+
/** Alternative text for the thumbnail image, displayed when the image cannot be rendered. */
|
|
51
54
|
alt: PropTypes.string,
|
|
52
|
-
|
|
55
|
+
/** When true, renders a play icon overlay on the thumbnail to indicate that the slide contains a video. */
|
|
56
|
+
isVideo: PropTypes.bool,
|
|
57
|
+
/** URL or path of the thumbnail image. When used with `isVideo`, this should be the video's poster/preview image. */
|
|
58
|
+
src: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
|
|
53
59
|
})
|
|
54
60
|
).isRequired
|
|
55
61
|
}
|
|
@@ -13,22 +13,26 @@ import { useThemeTokens } from '../ThemeProvider/useThemeTokens'
|
|
|
13
13
|
|
|
14
14
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs, viewProps])
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
const HALF_FONT_SIZE = 2
|
|
17
|
+
const QUARTER_FONT_SIZE = 4
|
|
18
|
+
const DEFAULT_LINE_HEIGHT = 1
|
|
19
|
+
const LINE_HEIGHT_MULTIPLIER = 2
|
|
20
|
+
|
|
21
|
+
const selectTextStyle = ({ fontSize, lineHeight }) =>
|
|
22
|
+
Platform.select({
|
|
23
|
+
native: {
|
|
24
|
+
fontSize: fontSize / HALF_FONT_SIZE,
|
|
25
|
+
lineHeight: fontSize,
|
|
26
|
+
position: 'relative',
|
|
27
|
+
top: -(fontSize * lineHeight) / HALF_FONT_SIZE
|
|
26
28
|
},
|
|
27
29
|
web: {
|
|
28
|
-
|
|
30
|
+
fontSize,
|
|
31
|
+
lineHeight:
|
|
32
|
+
lineHeight !== DEFAULT_LINE_HEIGHT ? lineHeight : fontSize * LINE_HEIGHT_MULTIPLIER,
|
|
33
|
+
top: -fontSize / QUARTER_FONT_SIZE
|
|
29
34
|
}
|
|
30
35
|
})
|
|
31
|
-
})
|
|
32
36
|
|
|
33
37
|
export const FootnoteLink = React.forwardRef(
|
|
34
38
|
({ copy = 'en', content = [], onClick, tokens, variant = {}, ...rest }, ref) => {
|
|
@@ -69,6 +73,7 @@ export const FootnoteLink = React.forwardRef(
|
|
|
69
73
|
)
|
|
70
74
|
|
|
71
75
|
FootnoteLink.displayName = 'FootnoteLink'
|
|
76
|
+
FootnoteLink.__UDS_COMPONENT_NAME__ = 'FootnoteLink'
|
|
72
77
|
|
|
73
78
|
const copyShape = PropTypes.shape({ a11yLabel: PropTypes.string.isRequired })
|
|
74
79
|
|
|
@@ -67,12 +67,7 @@ export const InputSupports = React.forwardRef(
|
|
|
67
67
|
/>
|
|
68
68
|
)}
|
|
69
69
|
{typeof children === 'function'
|
|
70
|
-
? children({
|
|
71
|
-
inputId,
|
|
72
|
-
...a11yProps,
|
|
73
|
-
validation: feedbackValidation,
|
|
74
|
-
accessibilityDescribedBy: feedbackId
|
|
75
|
-
})
|
|
70
|
+
? children({ inputId, ...a11yProps, validation: feedbackValidation })
|
|
76
71
|
: children}
|
|
77
72
|
{feedback || maxCharsReachedErrorMessage ? (
|
|
78
73
|
<Feedback
|
|
@@ -31,8 +31,8 @@ export const useInputSupports = ({
|
|
|
31
31
|
: undefined
|
|
32
32
|
]), // native only -> replaced with describedBy on web
|
|
33
33
|
accessibilityDescribedBy: joinDefined([
|
|
34
|
-
!hasValidationError && feedback && feedbackId, // feedback receives a11yRole=alert on error, so there's no need to include it here
|
|
35
34
|
hint && hintId,
|
|
35
|
+
(feedback && feedbackId) || undefined,
|
|
36
36
|
charactersCount
|
|
37
37
|
? getCopy('charactersRemaining').replace(/%\{charCount\}/g, charactersCount)
|
|
38
38
|
: undefined
|
package/src/Link/ChevronLink.jsx
CHANGED
|
@@ -53,8 +53,7 @@ ChevronLink.propTypes = {
|
|
|
53
53
|
children: PropTypes.node,
|
|
54
54
|
variant: PropTypes.exact({
|
|
55
55
|
size: PropTypes.oneOf(['large', 'small', 'micro']),
|
|
56
|
-
|
|
57
|
-
inverse: PropTypes.bool
|
|
56
|
+
style: PropTypes.oneOf(['inline', 'subtle', 'feature', 'danger', 'inverse'])
|
|
58
57
|
}),
|
|
59
58
|
...linkProps.types,
|
|
60
59
|
tokens: getTokensPropType('ChevronLink', 'Link'),
|
|
@@ -227,11 +227,10 @@ const getDefaultStyles = (
|
|
|
227
227
|
* ### Variants
|
|
228
228
|
* - Use `variant.style` to set the visual style of the notification
|
|
229
229
|
* - Use `dismissible` prop to enable dismissible functionality
|
|
230
|
-
* - Use `system` prop to set the visual style of the notification and denote an announcement from the system or application
|
|
231
230
|
*
|
|
232
|
-
* ### When to use the system
|
|
233
|
-
* - Use `system
|
|
234
|
-
* - Don’t use `system` when the message is in response to user action
|
|
231
|
+
* ### When to use the system style variant?
|
|
232
|
+
* - Use `variant.style ‘system’` to show system-based messages coming from the application
|
|
233
|
+
* - Don’t use the `system` style variant when the message is in response to user action
|
|
235
234
|
*
|
|
236
235
|
* ## Variants
|
|
237
236
|
*
|
|
@@ -263,25 +262,14 @@ const getDefaultStyles = (
|
|
|
263
262
|
*/
|
|
264
263
|
export const Notification = React.forwardRef(
|
|
265
264
|
(
|
|
266
|
-
{
|
|
267
|
-
children,
|
|
268
|
-
system,
|
|
269
|
-
dismissible,
|
|
270
|
-
copy = 'en',
|
|
271
|
-
tokens,
|
|
272
|
-
variant,
|
|
273
|
-
onDismiss,
|
|
274
|
-
contentMinWidth,
|
|
275
|
-
...rest
|
|
276
|
-
},
|
|
265
|
+
{ children, dismissible, copy = 'en', tokens, variant, onDismiss, contentMinWidth, ...rest },
|
|
277
266
|
ref
|
|
278
267
|
) => {
|
|
279
268
|
const [isDismissed, setIsDismissed] = React.useState(false)
|
|
280
269
|
const viewport = useViewport()
|
|
281
270
|
const getCopy = useCopy({ dictionary, copy })
|
|
282
271
|
|
|
283
|
-
|
|
284
|
-
const isSystemEnabled = system || variant?.style?.includes('system')
|
|
272
|
+
const isSystemEnabled = variant?.style?.includes('system')
|
|
285
273
|
|
|
286
274
|
const { themeOptions } = useTheme()
|
|
287
275
|
const { enableMediaQueryStyleSheet } = themeOptions
|
|
@@ -442,10 +430,6 @@ Notification.propTypes = {
|
|
|
442
430
|
* Content of the `Notification`.
|
|
443
431
|
*/
|
|
444
432
|
children: PropTypes.oneOfType([PropTypes.string, PropTypes.node, PropTypes.func]),
|
|
445
|
-
/**
|
|
446
|
-
* Use `system` prop to set the visual style of the notification and denote an announcement from the system or application
|
|
447
|
-
*/
|
|
448
|
-
system: PropTypes.bool,
|
|
449
433
|
/**
|
|
450
434
|
* Use the `dismissible` prop to allow users to dismiss the Notification at any time.
|
|
451
435
|
*/
|
|
@@ -13,6 +13,9 @@ import { ProgressContext } from './ProgressContext'
|
|
|
13
13
|
|
|
14
14
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
|
|
15
15
|
|
|
16
|
+
const BORDER_SIDES = 2
|
|
17
|
+
const CENTER_DIVISOR = 2
|
|
18
|
+
|
|
16
19
|
const selectProgressStyles = ({
|
|
17
20
|
backgroundColor,
|
|
18
21
|
borderWidth,
|
|
@@ -29,6 +32,14 @@ const selectProgressStyles = ({
|
|
|
29
32
|
...applyShadowToken(shadow)
|
|
30
33
|
})
|
|
31
34
|
|
|
35
|
+
const selectBarWrapperStyles = ({ barHeight, borderRadius, borderWidth, height }) => ({
|
|
36
|
+
height: barHeight,
|
|
37
|
+
width: '100%',
|
|
38
|
+
position: 'absolute',
|
|
39
|
+
top: (height - borderWidth * BORDER_SIDES - barHeight) / CENTER_DIVISOR,
|
|
40
|
+
borderRadius
|
|
41
|
+
})
|
|
42
|
+
|
|
32
43
|
/**
|
|
33
44
|
* The `Progress` is a container for displaying one or several `ProgressBar`s.
|
|
34
45
|
*
|
|
@@ -41,10 +52,11 @@ const selectProgressStyles = ({
|
|
|
41
52
|
*
|
|
42
53
|
* - Use the following tokens to customize the appearance:
|
|
43
54
|
* - `backgroundColor` for the background color of the progress container,
|
|
55
|
+
* - `barHeight` to control the height of the progress bars displayed within the container,
|
|
44
56
|
* - `borderColor` to control the color of the border,
|
|
45
57
|
* - `borderRadius` for the rounded corners,
|
|
46
58
|
* - `borderWidth` to change the border width.
|
|
47
|
-
* - `height` to control the height of the progress
|
|
59
|
+
* - `height` to control the height of the progress bar container.
|
|
48
60
|
* - `shadow` to apply a box shadow to the progress bar container.
|
|
49
61
|
*
|
|
50
62
|
* ## Variants
|
|
@@ -67,8 +79,15 @@ const selectProgressStyles = ({
|
|
|
67
79
|
*/
|
|
68
80
|
export const Progress = React.forwardRef(({ children, tokens, variant, ...rest }, ref) => {
|
|
69
81
|
const themeTokens = useThemeTokens('Progress', tokens, variant)
|
|
70
|
-
// Default to false (vertical layout) to preserve existing behavior and avoid breaking changes
|
|
71
82
|
const layers = variant?.layers ?? false
|
|
83
|
+
const { barHeight, height } = themeTokens
|
|
84
|
+
|
|
85
|
+
const content =
|
|
86
|
+
barHeight && barHeight !== height ? (
|
|
87
|
+
<View style={selectBarWrapperStyles(themeTokens)}>{children}</View>
|
|
88
|
+
) : (
|
|
89
|
+
children
|
|
90
|
+
)
|
|
72
91
|
|
|
73
92
|
return (
|
|
74
93
|
<ProgressContext.Provider value={{ layers }}>
|
|
@@ -77,7 +96,7 @@ export const Progress = React.forwardRef(({ children, tokens, variant, ...rest }
|
|
|
77
96
|
style={[staticStyles.progressContainer, selectProgressStyles(themeTokens)]}
|
|
78
97
|
{...selectProps(rest)}
|
|
79
98
|
>
|
|
80
|
-
{
|
|
99
|
+
{content}
|
|
81
100
|
</View>
|
|
82
101
|
</ProgressContext.Provider>
|
|
83
102
|
)
|
|
@@ -48,9 +48,9 @@ const selectBarStyles = ({ themeTokens, calculatedPercentage, barPosition, layer
|
|
|
48
48
|
*
|
|
49
49
|
* ## Variants
|
|
50
50
|
*
|
|
51
|
-
* - Use
|
|
52
|
-
* - `negative
|
|
53
|
-
* - `inactive
|
|
51
|
+
* - Use `variant={{ style: 'value' }}` to render specific types of progress bars:
|
|
52
|
+
* - `style: 'negative'` for negative theming for progress bar filling,
|
|
53
|
+
* - `style: 'inactive'` to style the progress bar as inactive.
|
|
54
54
|
*
|
|
55
55
|
* ## Usability and A11y guidelines
|
|
56
56
|
*
|
|
@@ -9,10 +9,9 @@ const negativeBackground = `%3Csvg xmlns='http://www.w3.org/2000/svg' width='100
|
|
|
9
9
|
|
|
10
10
|
export const ProgressBarBackground = React.forwardRef(({ variant }, ref) => {
|
|
11
11
|
let source = null
|
|
12
|
-
|
|
13
|
-
if (variant?.inactive || variant?.style === INACTIVE_VARIANT) {
|
|
12
|
+
if (variant?.style === INACTIVE_VARIANT) {
|
|
14
13
|
source = inactiveBackground
|
|
15
|
-
} else if (variant?.
|
|
14
|
+
} else if (variant?.style === NEGATIVE_VARIANT) {
|
|
16
15
|
source = negativeBackground
|
|
17
16
|
} else {
|
|
18
17
|
return null
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
3
|
|
|
4
|
+
import { Platform } from 'react-native'
|
|
4
5
|
import { useThemeTokens } from '../ThemeProvider/useThemeTokens'
|
|
5
6
|
import { useViewport } from '../ViewportProvider/useViewport'
|
|
6
7
|
import { getTokensPropType } from '../utils/props/tokens'
|
|
7
8
|
import { variantProp } from '../utils/props/variantProp'
|
|
9
|
+
import { tagsToRoles } from '../utils/a11y/semantics'
|
|
8
10
|
|
|
9
11
|
import { List } from '../List/List'
|
|
10
12
|
import { StackWrap } from '../StackView/StackWrap'
|
|
@@ -28,6 +30,11 @@ export const QuickLinks = React.forwardRef(
|
|
|
28
30
|
}
|
|
29
31
|
)
|
|
30
32
|
|
|
33
|
+
const itemAccessibilityRole = Platform.select({
|
|
34
|
+
web: ['ul', 'ol'].includes(tag) ? tagsToRoles.li : undefined,
|
|
35
|
+
default: undefined
|
|
36
|
+
})
|
|
37
|
+
|
|
31
38
|
const content = (list && (
|
|
32
39
|
<List ref={ref} tokens={listTokens} showDivider={dividers} tag={tag} {...rest}>
|
|
33
40
|
{children}
|
|
@@ -38,6 +45,7 @@ export const QuickLinks = React.forwardRef(
|
|
|
38
45
|
gap={stackGap}
|
|
39
46
|
tokens={{ justifyContent: stackJustify }}
|
|
40
47
|
tag={tag}
|
|
48
|
+
itemAccessibilityRole={itemAccessibilityRole}
|
|
41
49
|
{...rest}
|
|
42
50
|
>
|
|
43
51
|
{children}
|