@telus-uds/components-base 3.3.0 → 3.5.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 +28 -2
- package/lib/cjs/ActivityIndicator/Dots.js +165 -0
- package/lib/cjs/ActivityIndicator/Dots.native.js +221 -0
- package/lib/cjs/ActivityIndicator/Spinner.js +57 -50
- package/lib/cjs/ActivityIndicator/Spinner.native.js +90 -108
- package/lib/cjs/ActivityIndicator/index.js +12 -1
- package/lib/cjs/ActivityIndicator/shared.js +53 -6
- package/lib/cjs/Button/ButtonBase.js +1 -1
- package/lib/cjs/Button/ButtonLink.js +1 -0
- package/lib/cjs/Carousel/Carousel.js +18 -7
- package/lib/cjs/ExpandCollapse/ExpandCollapse.js +3 -1
- package/lib/cjs/ExpandCollapseMini/ExpandCollapseMini.js +10 -1
- package/lib/cjs/FileUpload/FileUpload.js +31 -2
- package/lib/cjs/Link/Link.js +8 -1
- package/lib/cjs/Link/LinkBase.js +2 -0
- package/lib/cjs/MultiSelectFilter/MultiSelectFilter.js +3 -2
- package/lib/cjs/utils/containUniqueFields.js +5 -5
- package/lib/cjs/utils/useUniqueId.js +2 -6
- package/lib/esm/ActivityIndicator/Dots.js +158 -0
- package/lib/esm/ActivityIndicator/Dots.native.js +212 -0
- package/lib/esm/ActivityIndicator/Spinner.js +58 -51
- package/lib/esm/ActivityIndicator/Spinner.native.js +90 -110
- package/lib/esm/ActivityIndicator/index.js +12 -1
- package/lib/esm/ActivityIndicator/shared.js +52 -5
- package/lib/esm/Button/ButtonBase.js +2 -2
- package/lib/esm/Button/ButtonLink.js +2 -1
- package/lib/esm/Carousel/Carousel.js +18 -7
- package/lib/esm/ExpandCollapse/ExpandCollapse.js +4 -2
- package/lib/esm/ExpandCollapseMini/ExpandCollapseMini.js +11 -2
- package/lib/esm/FileUpload/FileUpload.js +31 -2
- package/lib/esm/Link/Link.js +8 -1
- package/lib/esm/Link/LinkBase.js +2 -0
- package/lib/esm/MultiSelectFilter/MultiSelectFilter.js +3 -2
- package/lib/esm/utils/containUniqueFields.js +5 -5
- package/lib/esm/utils/useUniqueId.js +3 -7
- package/lib/package.json +4 -3
- package/package.json +4 -3
- package/src/ActivityIndicator/Dots.jsx +200 -0
- package/src/ActivityIndicator/Dots.native.jsx +213 -0
- package/src/ActivityIndicator/Spinner.jsx +95 -59
- package/src/ActivityIndicator/Spinner.native.jsx +125 -132
- package/src/ActivityIndicator/index.jsx +17 -2
- package/src/ActivityIndicator/shared.js +52 -5
- package/src/Button/ButtonBase.jsx +4 -2
- package/src/Button/ButtonLink.jsx +3 -1
- package/src/Carousel/Carousel.jsx +28 -7
- package/src/ExpandCollapse/ExpandCollapse.jsx +9 -4
- package/src/ExpandCollapseMini/ExpandCollapseMini.jsx +15 -3
- package/src/FileUpload/FileUpload.jsx +32 -2
- package/src/Link/Link.jsx +8 -1
- package/src/Link/LinkBase.jsx +2 -0
- package/src/MultiSelectFilter/MultiSelectFilter.jsx +2 -2
- package/src/utils/containUniqueFields.js +5 -5
- package/src/utils/useUniqueId.js +3 -8
|
@@ -1,140 +1,133 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import { Animated, Easing
|
|
3
|
-
import
|
|
2
|
+
import { View, Animated, Easing } from 'react-native'
|
|
3
|
+
import Svg, { Circle } from 'react-native-svg'
|
|
4
|
+
import {
|
|
5
|
+
DURATION,
|
|
6
|
+
SVG_CIRCUMFERENCE,
|
|
7
|
+
SVG_SIZE,
|
|
8
|
+
SVG_CENTER,
|
|
9
|
+
SPINNER_RADIUS,
|
|
10
|
+
SPINNER_DASHARRAY_HALF,
|
|
11
|
+
SPINNER_DASHARRAY_MIN,
|
|
12
|
+
SPINNER_DASHOFFSET_FACTOR,
|
|
13
|
+
propTypes
|
|
14
|
+
} from './shared'
|
|
4
15
|
import { useA11yInfo } from '../A11yInfoProvider'
|
|
5
16
|
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
17
|
+
const Spinner = React.forwardRef(
|
|
18
|
+
({ size, color, indicatorBackgroundColor, thickness, label, isStatic = false }, ref) => {
|
|
19
|
+
const { reduceMotionEnabled } = useA11yInfo()
|
|
20
|
+
const reduceMotion = reduceMotionEnabled || isStatic
|
|
21
|
+
|
|
22
|
+
// Animated value between 0..1 that will loop
|
|
23
|
+
const progress = React.useRef(new Animated.Value(0)).current
|
|
24
|
+
|
|
25
|
+
// Local state to force re-render on each frame
|
|
26
|
+
const [progressVal, setProgressVal] = React.useState(0)
|
|
27
|
+
|
|
28
|
+
React.useEffect(() => {
|
|
29
|
+
if (reduceMotion) {
|
|
30
|
+
progress.stopAnimation(() => {
|
|
31
|
+
progress.setValue(0)
|
|
32
|
+
setProgressVal(0)
|
|
33
|
+
})
|
|
34
|
+
return undefined
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const id = progress.addListener(({ value }) => {
|
|
38
|
+
setProgressVal(value)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
Animated.loop(
|
|
42
|
+
Animated.timing(progress, {
|
|
43
|
+
toValue: 1,
|
|
44
|
+
duration: DURATION,
|
|
45
|
+
easing: Easing.linear,
|
|
46
|
+
useNativeDriver: false,
|
|
47
|
+
isInteraction: false
|
|
48
|
+
})
|
|
49
|
+
).start()
|
|
50
|
+
|
|
51
|
+
return () => {
|
|
52
|
+
progress.removeListener(id)
|
|
53
|
+
progress.stopAnimation()
|
|
54
|
+
}
|
|
55
|
+
}, [progress, reduceMotion])
|
|
56
|
+
|
|
57
|
+
/* The same logic used in Wweb keyframes:
|
|
58
|
+
- rotation from -90° base plus 0..183° => -90..93
|
|
59
|
+
- dasharray from 1% -> 50% -> 1%
|
|
60
|
+
- dashoffset from 0 -> 0 -> -49%
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
// 1) rotation (0->183) plus base offset -90
|
|
64
|
+
const rotationDeg = -90 + 183 * progressVal // -90..+93
|
|
65
|
+
|
|
66
|
+
// strokeDasharray
|
|
67
|
+
let dashArrayVisible
|
|
68
|
+
if (progressVal < SPINNER_DASHARRAY_HALF) {
|
|
69
|
+
const segmentProgress = progressVal / SPINNER_DASHARRAY_HALF
|
|
70
|
+
dashArrayVisible =
|
|
71
|
+
SPINNER_DASHARRAY_MIN + (SPINNER_DASHARRAY_HALF - SPINNER_DASHARRAY_MIN) * segmentProgress
|
|
72
|
+
} else {
|
|
73
|
+
const segmentProgress = (progressVal - SPINNER_DASHARRAY_HALF) / SPINNER_DASHARRAY_HALF
|
|
74
|
+
dashArrayVisible =
|
|
75
|
+
SPINNER_DASHARRAY_HALF + (SPINNER_DASHARRAY_MIN - SPINNER_DASHARRAY_HALF) * segmentProgress
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const visibleLength = dashArrayVisible * SVG_CIRCUMFERENCE
|
|
79
|
+
const invisibleLength = SVG_CIRCUMFERENCE - visibleLength
|
|
80
|
+
const strokeDasharray = `${visibleLength},${invisibleLength}`
|
|
81
|
+
|
|
82
|
+
// strokeDashoffset
|
|
83
|
+
let strokeDashoffset = 0
|
|
84
|
+
if (progressVal > SPINNER_DASHARRAY_HALF) {
|
|
85
|
+
const segmentProgress = (progressVal - SPINNER_DASHARRAY_HALF) / SPINNER_DASHARRAY_HALF
|
|
86
|
+
strokeDashoffset = -SPINNER_DASHOFFSET_FACTOR * SVG_CIRCUMFERENCE * segmentProgress
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const strokeWidth = (thickness * SVG_SIZE) / size
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<View
|
|
93
|
+
ref={ref}
|
|
94
|
+
style={{ width: size, height: size }}
|
|
95
|
+
accessible
|
|
96
|
+
accessibilityLabel={label}
|
|
97
|
+
accessibilityRole="progressbar"
|
|
98
|
+
accessibilityState={{ busy: true }}
|
|
99
|
+
>
|
|
100
|
+
<Svg width={size} height={size} viewBox={`0 0 ${SVG_SIZE} ${SVG_SIZE}`}>
|
|
101
|
+
{/* Base static circle */}
|
|
102
|
+
<Circle
|
|
103
|
+
cx={SVG_CENTER}
|
|
104
|
+
cy={SVG_CENTER}
|
|
105
|
+
r={SPINNER_RADIUS}
|
|
106
|
+
fill="none"
|
|
107
|
+
stroke={indicatorBackgroundColor}
|
|
108
|
+
strokeWidth={strokeWidth}
|
|
109
|
+
/>
|
|
110
|
+
|
|
111
|
+
{/* Animated circle */}
|
|
112
|
+
<Circle
|
|
113
|
+
cx={SVG_CENTER}
|
|
114
|
+
cy={SVG_CENTER}
|
|
115
|
+
r={SPINNER_RADIUS}
|
|
116
|
+
fill="none"
|
|
117
|
+
stroke={color}
|
|
118
|
+
strokeWidth={strokeWidth}
|
|
119
|
+
strokeLinecap="round"
|
|
120
|
+
transform={`rotate(${rotationDeg}, 24, 24)`}
|
|
121
|
+
strokeDasharray={strokeDasharray}
|
|
122
|
+
strokeDashoffset={strokeDashoffset}
|
|
123
|
+
/>
|
|
124
|
+
</Svg>
|
|
125
|
+
</View>
|
|
126
|
+
)
|
|
34
127
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
// Credit to https://github.com/n4kz/react-native-indicators and https://github.com/callstack/react-native-paper for this
|
|
38
|
-
return (
|
|
39
|
-
<View
|
|
40
|
-
ref={ref}
|
|
41
|
-
style={[styles.container]}
|
|
42
|
-
accessible
|
|
43
|
-
accessibilityLabel={label}
|
|
44
|
-
accessibilityRole="progressbar"
|
|
45
|
-
accessibilityState={{ busy: true }}
|
|
46
|
-
>
|
|
47
|
-
<Animated.View style={[{ width: size, height: size }]} collapsable={false}>
|
|
48
|
-
{animationFrequency.map((index) => {
|
|
49
|
-
const inputRange = Array.from(
|
|
50
|
-
new Array(frames),
|
|
51
|
-
(_, frameIndex) => frameIndex / (frames - 1)
|
|
52
|
-
)
|
|
53
|
-
const outputRange = Array.from(new Array(frames), (_, frameIndex) => {
|
|
54
|
-
let progress = (2 * frameIndex) / (frames - 1)
|
|
55
|
-
const rotation = index ? +(360 - sa) : -(180 - sa)
|
|
56
|
-
|
|
57
|
-
if (progress > 1.0) {
|
|
58
|
-
progress = 2.0 - progress
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const direction = index ? -1 : +1
|
|
62
|
-
|
|
63
|
-
return `${direction * (180 - (sa + ea)) * easing(progress) + rotation}deg`
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
const layerStyle = {
|
|
67
|
-
width: size,
|
|
68
|
-
height: size
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const viewportStyle = {
|
|
72
|
-
width: size,
|
|
73
|
-
height: size
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (!reduceMotion) {
|
|
77
|
-
layerStyle.transform = [
|
|
78
|
-
{
|
|
79
|
-
rotate: timer.interpolate({
|
|
80
|
-
inputRange: [0, 1],
|
|
81
|
-
outputRange: [`${0 + ea + sa}deg`, `${2 * 360 + ea + sa}deg`]
|
|
82
|
-
})
|
|
83
|
-
}
|
|
84
|
-
]
|
|
85
|
-
viewportStyle.transform = [
|
|
86
|
-
{
|
|
87
|
-
translateY: index ? -size / 2 : 0
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
rotate: timer.interpolate({ inputRange, outputRange })
|
|
91
|
-
}
|
|
92
|
-
]
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const offsetStyle = index ? { top: size / 2 } : null
|
|
96
|
-
|
|
97
|
-
const lineStyle = {
|
|
98
|
-
width: size,
|
|
99
|
-
height: size,
|
|
100
|
-
borderColor: color,
|
|
101
|
-
borderWidth: thickness,
|
|
102
|
-
borderRadius: size / 2
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return (
|
|
106
|
-
<Animated.View key={index} style={[styles.layer]}>
|
|
107
|
-
<Animated.View style={layerStyle}>
|
|
108
|
-
<Animated.View style={[containerStyle, offsetStyle]} collapsable={false}>
|
|
109
|
-
<Animated.View style={viewportStyle}>
|
|
110
|
-
<Animated.View style={containerStyle} collapsable={false}>
|
|
111
|
-
<Animated.View style={lineStyle} />
|
|
112
|
-
</Animated.View>
|
|
113
|
-
</Animated.View>
|
|
114
|
-
</Animated.View>
|
|
115
|
-
</Animated.View>
|
|
116
|
-
</Animated.View>
|
|
117
|
-
)
|
|
118
|
-
})}
|
|
119
|
-
</Animated.View>
|
|
120
|
-
</View>
|
|
121
|
-
)
|
|
122
|
-
})
|
|
123
|
-
Spinner.displayName = 'Spinner'
|
|
128
|
+
)
|
|
124
129
|
|
|
130
|
+
Spinner.displayName = 'Spinner'
|
|
125
131
|
Spinner.propTypes = propTypes
|
|
126
132
|
|
|
127
|
-
const styles = StyleSheet.create({
|
|
128
|
-
container: {
|
|
129
|
-
flexGrow: 0,
|
|
130
|
-
flexShrink: 0
|
|
131
|
-
},
|
|
132
|
-
|
|
133
|
-
layer: {
|
|
134
|
-
...StyleSheet.absoluteFillObject,
|
|
135
|
-
justifyContent: 'center',
|
|
136
|
-
alignItems: 'center'
|
|
137
|
-
}
|
|
138
|
-
})
|
|
139
|
-
|
|
140
133
|
export default Spinner
|
|
@@ -4,18 +4,33 @@ import { useThemeTokens } from '../ThemeProvider'
|
|
|
4
4
|
import { getTokensPropType, variantProp } from '../utils/props'
|
|
5
5
|
|
|
6
6
|
import Spinner from './Spinner'
|
|
7
|
+
import Dots from './Dots'
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* `ActivityIndicator` renders a visual loading state.
|
|
10
11
|
* It does not handle positioning or layout of that visual loader.
|
|
11
12
|
*/
|
|
12
13
|
const ActivityIndicator = React.forwardRef(({ variant, tokens, label, isStatic = false }, ref) => {
|
|
13
|
-
const { size, color, thickness } = useThemeTokens(
|
|
14
|
-
|
|
14
|
+
const { size, dotSize, color, indicatorBackgroundColor, thickness } = useThemeTokens(
|
|
15
|
+
'ActivityIndicator',
|
|
16
|
+
tokens,
|
|
17
|
+
variant
|
|
18
|
+
)
|
|
19
|
+
return variant?.dots ? (
|
|
20
|
+
<Dots
|
|
21
|
+
ref={ref}
|
|
22
|
+
size={dotSize}
|
|
23
|
+
color={color}
|
|
24
|
+
indicatorBackgroundColor={indicatorBackgroundColor}
|
|
25
|
+
label={label}
|
|
26
|
+
isStatic={isStatic}
|
|
27
|
+
/>
|
|
28
|
+
) : (
|
|
15
29
|
<Spinner
|
|
16
30
|
ref={ref}
|
|
17
31
|
size={size}
|
|
18
32
|
color={color}
|
|
33
|
+
indicatorBackgroundColor={indicatorBackgroundColor}
|
|
19
34
|
thickness={thickness}
|
|
20
35
|
label={label}
|
|
21
36
|
isStatic={isStatic}
|
|
@@ -1,15 +1,62 @@
|
|
|
1
1
|
import PropTypes from 'prop-types'
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
export const DURATION =
|
|
5
|
-
export const
|
|
6
|
-
export const
|
|
7
|
-
export const
|
|
3
|
+
// Spinner
|
|
4
|
+
export const DURATION = 1200
|
|
5
|
+
export const SVG_RADIUS = 20
|
|
6
|
+
export const SVG_CIRCUMFERENCE = SVG_RADIUS * 2 * Math.PI
|
|
7
|
+
export const SVG_SIZE = 48
|
|
8
|
+
export const ROTATION_TRANSFORM = 'rotate(-90 24 24)'
|
|
9
|
+
export const SVG_CENTER = 24
|
|
10
|
+
export const SPINNER_RADIUS = 20
|
|
11
|
+
export const SPINNER_ROTATION_DEGREES = 183
|
|
12
|
+
export const SPINNER_DASHARRAY_MIN = 0.01
|
|
13
|
+
export const SPINNER_DASHARRAY_MAX = 0.99
|
|
14
|
+
|
|
15
|
+
// Spinner animation
|
|
16
|
+
export const SPINNER_KEYTIMES = '0; 0.5; 1'
|
|
17
|
+
export const SPINNER_DASHARRAY_HALF = 0.5
|
|
18
|
+
export const SPINNER_DASHOFFSET_FACTOR = 0.49
|
|
19
|
+
|
|
20
|
+
// Dots
|
|
21
|
+
export const DOTS_ANIMATION_DURATION = 300
|
|
22
|
+
export const DOTS_TOTAL_ANIMATION_DURATION = DOTS_ANIMATION_DURATION * 10
|
|
23
|
+
export const OVERSHOOT_FACTOR = 1.3
|
|
24
|
+
export const UNDERSHOOT_FACTOR = 0.2
|
|
25
|
+
export const BOUNCY_CURVE = '0.2 1 0.8 1'
|
|
26
|
+
export const DOTS_SPACING_X = 3
|
|
27
|
+
export const DOTS_BASE_Y_FACTOR = 3
|
|
28
|
+
export const DOTS_JUMP_HEIGHT_FACTOR = 1
|
|
29
|
+
export const DOTS_PADDING_FACTOR = 0.5
|
|
30
|
+
|
|
31
|
+
// Dots fadeout
|
|
32
|
+
export const DOTS_FADEOUT_KEYTIMES = '0; 0.7; 0.8; 1'
|
|
33
|
+
export const DOTS_FADEOUT_VALUES = '1; 1; 0; 0'
|
|
34
|
+
|
|
35
|
+
// Dots animation
|
|
36
|
+
export const DOT1_ANIMATION_KEYTIMES = '0; 0.1; 0.2; 1'
|
|
37
|
+
export const DOT2_ANIMATION_KEYTIMES = '0; 0.3; 0.4; 0.5; 1'
|
|
38
|
+
export const DOT3_ANIMATION_KEYTIMES = '0; 0.6; 0.7; 0.8; 1'
|
|
39
|
+
|
|
40
|
+
// Dots color keytimes
|
|
41
|
+
export const DOT1_COLOR_KEYTIMES = '0; 0.3; 0.4; 1'
|
|
42
|
+
export const DOT2_COLOR_KEYTIMES = '0; 0.3; 0.4; 0.6; 0.7; 1'
|
|
43
|
+
export const DOT3_COLOR_KEYTIMES = '0; 0.5; 0.6; 0.8; 1'
|
|
44
|
+
|
|
45
|
+
// Dots native fadeout
|
|
46
|
+
export const DOT_FADEOUT_INPUT_RANGE = [0, 0.7, 0.8, 1]
|
|
47
|
+
export const DOT_FADEOUT_OUTPUT_RANGE = [1, 1, 0, 0]
|
|
48
|
+
|
|
49
|
+
// Dots native animation
|
|
50
|
+
export const DOT1_ANIMATION_INPUT_RANGE = [0, 0.1, 0.2, 1]
|
|
51
|
+
export const DOT2_ANIMATION_INPUT_RANGE = [0, 0.3, 0.4, 0.5, 1]
|
|
52
|
+
export const DOT3_ANIMATION_INPUT_RANGE = [0, 0.6, 0.7, 0.8, 1]
|
|
8
53
|
|
|
9
54
|
export const propTypes = {
|
|
10
55
|
color: PropTypes.string.isRequired,
|
|
56
|
+
baseColor: PropTypes.string,
|
|
11
57
|
label: PropTypes.string.isRequired,
|
|
12
58
|
size: PropTypes.number.isRequired,
|
|
59
|
+
dotsize: PropTypes.number,
|
|
13
60
|
thickness: PropTypes.number.isRequired,
|
|
14
61
|
isStatic: PropTypes.bool
|
|
15
62
|
}
|
|
@@ -15,7 +15,8 @@ import {
|
|
|
15
15
|
selectSystemProps,
|
|
16
16
|
viewProps,
|
|
17
17
|
wrapStringsInText,
|
|
18
|
-
withLinkRouter
|
|
18
|
+
withLinkRouter,
|
|
19
|
+
contentfulProps
|
|
19
20
|
} from '../utils'
|
|
20
21
|
import { IconText } from '../Icon'
|
|
21
22
|
|
|
@@ -23,7 +24,8 @@ const [selectProps, selectedSystemPropTypes] = selectSystemProps([
|
|
|
23
24
|
a11yProps,
|
|
24
25
|
focusHandlerProps,
|
|
25
26
|
linkProps,
|
|
26
|
-
viewProps
|
|
27
|
+
viewProps,
|
|
28
|
+
contentfulProps
|
|
27
29
|
])
|
|
28
30
|
|
|
29
31
|
const getOuterBorderOffset = ({ outerBorderGap = 0, outerBorderWidth = 0 }) =>
|
|
@@ -2,7 +2,7 @@ import React from 'react'
|
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
3
|
import ButtonBase from './ButtonBase'
|
|
4
4
|
import buttonPropTypes, { textAndA11yText } from './propTypes'
|
|
5
|
-
import { a11yProps, hrefAttrsProp, linkProps } from '../utils/props'
|
|
5
|
+
import { a11yProps, hrefAttrsProp, linkProps, contentfulProps } from '../utils/props'
|
|
6
6
|
import { useThemeTokensCallback } from '../ThemeProvider'
|
|
7
7
|
import { useViewport } from '../ViewportProvider'
|
|
8
8
|
|
|
@@ -16,6 +16,7 @@ const ButtonLink = React.forwardRef(
|
|
|
16
16
|
const viewport = useViewport()
|
|
17
17
|
const buttonVariant = { viewport, ...variant }
|
|
18
18
|
const getTokens = useThemeTokensCallback('Button', tokens, buttonVariant)
|
|
19
|
+
|
|
19
20
|
return (
|
|
20
21
|
<ButtonBase
|
|
21
22
|
ref={ref}
|
|
@@ -34,6 +35,7 @@ ButtonLink.propTypes = {
|
|
|
34
35
|
...a11yProps.types,
|
|
35
36
|
...buttonPropTypes,
|
|
36
37
|
...linkProps.types,
|
|
38
|
+
...contentfulProps.types,
|
|
37
39
|
children: textAndA11yText,
|
|
38
40
|
dataSet: PropTypes.object,
|
|
39
41
|
accessibilityRole: PropTypes.string
|
|
@@ -107,7 +107,9 @@ const selectControlButtonPositionStyles = ({
|
|
|
107
107
|
positionProperty = getDynamicPositionProperty(),
|
|
108
108
|
spaceBetweenSlideAndButton,
|
|
109
109
|
enablePeeking,
|
|
110
|
-
enableDisplayMultipleItemsPerSlide
|
|
110
|
+
enableDisplayMultipleItemsPerSlide,
|
|
111
|
+
isAutoPlayEnabled,
|
|
112
|
+
viewport
|
|
111
113
|
}) => {
|
|
112
114
|
const styles = {}
|
|
113
115
|
if (positionVariant === 'edge') {
|
|
@@ -115,7 +117,11 @@ const selectControlButtonPositionStyles = ({
|
|
|
115
117
|
} else if (positionVariant === 'inside') {
|
|
116
118
|
styles[positionProperty] = DEFAULT_POSITION_OFFSET
|
|
117
119
|
} else if (positionVariant === 'outside') {
|
|
118
|
-
if (
|
|
120
|
+
if (
|
|
121
|
+
enablePeeking ||
|
|
122
|
+
enableDisplayMultipleItemsPerSlide ||
|
|
123
|
+
(isAutoPlayEnabled && viewport === 'xs')
|
|
124
|
+
) {
|
|
119
125
|
styles[positionProperty] = 0
|
|
120
126
|
} else {
|
|
121
127
|
styles[positionProperty] = -1 * (spaceBetweenSlideAndButton + buttonWidth)
|
|
@@ -132,7 +138,9 @@ const selectPreviousNextNavigationButtonStyles = (
|
|
|
132
138
|
isLastSlide,
|
|
133
139
|
areStylesAppliedOnPreviousButton,
|
|
134
140
|
enablePeeking,
|
|
135
|
-
enableDisplayMultipleItemsPerSlide
|
|
141
|
+
enableDisplayMultipleItemsPerSlide,
|
|
142
|
+
isAutoPlayEnabled,
|
|
143
|
+
viewport
|
|
136
144
|
) => {
|
|
137
145
|
const styles = {
|
|
138
146
|
zIndex: 1,
|
|
@@ -154,7 +162,9 @@ const selectPreviousNextNavigationButtonStyles = (
|
|
|
154
162
|
positionProperty: getDynamicPositionProperty(areStylesAppliedOnPreviousButton),
|
|
155
163
|
spaceBetweenSlideAndButton: spaceBetweenSlideAndPreviousNextNavigation,
|
|
156
164
|
enablePeeking,
|
|
157
|
-
enableDisplayMultipleItemsPerSlide
|
|
165
|
+
enableDisplayMultipleItemsPerSlide,
|
|
166
|
+
isAutoPlayEnabled,
|
|
167
|
+
viewport
|
|
158
168
|
})
|
|
159
169
|
}
|
|
160
170
|
}
|
|
@@ -204,6 +214,11 @@ const selectRootContainerStyles = (enableHero, viewport) => {
|
|
|
204
214
|
alignItems: 'center'
|
|
205
215
|
}
|
|
206
216
|
}
|
|
217
|
+
if (enableHero) {
|
|
218
|
+
return {
|
|
219
|
+
paddingHorizontal: 16
|
|
220
|
+
}
|
|
221
|
+
}
|
|
207
222
|
return {}
|
|
208
223
|
}
|
|
209
224
|
|
|
@@ -1012,7 +1027,9 @@ const Carousel = React.forwardRef(
|
|
|
1012
1027
|
positionProperty: getDynamicPositionProperty(),
|
|
1013
1028
|
spaceBetweenSlideAndButton: spaceBetweenSlideAndPreviousNextNavigation,
|
|
1014
1029
|
enablePeeking,
|
|
1015
|
-
enableDisplayMultipleItemsPerSlide
|
|
1030
|
+
enableDisplayMultipleItemsPerSlide,
|
|
1031
|
+
isAutoPlayEnabled,
|
|
1032
|
+
viewport
|
|
1016
1033
|
})
|
|
1017
1034
|
]}
|
|
1018
1035
|
>
|
|
@@ -1036,7 +1053,9 @@ const Carousel = React.forwardRef(
|
|
|
1036
1053
|
isLastSlide,
|
|
1037
1054
|
true,
|
|
1038
1055
|
enablePeeking,
|
|
1039
|
-
enableDisplayMultipleItemsPerSlide
|
|
1056
|
+
enableDisplayMultipleItemsPerSlide,
|
|
1057
|
+
isAutoPlayEnabled,
|
|
1058
|
+
viewport
|
|
1040
1059
|
)}
|
|
1041
1060
|
testID="previous-button-container"
|
|
1042
1061
|
>
|
|
@@ -1110,7 +1129,9 @@ const Carousel = React.forwardRef(
|
|
|
1110
1129
|
isLastSlide,
|
|
1111
1130
|
false,
|
|
1112
1131
|
enablePeeking,
|
|
1113
|
-
enableDisplayMultipleItemsPerSlide
|
|
1132
|
+
enableDisplayMultipleItemsPerSlide,
|
|
1133
|
+
isAutoPlayEnabled,
|
|
1134
|
+
viewport
|
|
1114
1135
|
)}
|
|
1115
1136
|
testID="next-button-container"
|
|
1116
1137
|
>
|
|
@@ -9,10 +9,15 @@ import {
|
|
|
9
9
|
selectSystemProps,
|
|
10
10
|
useMultipleInputValues,
|
|
11
11
|
variantProp,
|
|
12
|
-
viewProps
|
|
12
|
+
viewProps,
|
|
13
|
+
contentfulProps
|
|
13
14
|
} from '../utils'
|
|
14
15
|
|
|
15
|
-
const [selectProps, selectedSystemPropTypes] = selectSystemProps([
|
|
16
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([
|
|
17
|
+
a11yProps,
|
|
18
|
+
viewProps,
|
|
19
|
+
contentfulProps
|
|
20
|
+
])
|
|
16
21
|
|
|
17
22
|
function selectBorderStyles(tokens) {
|
|
18
23
|
return {
|
|
@@ -30,7 +35,7 @@ function selectBorderStyles(tokens) {
|
|
|
30
35
|
* nested (they do not need to be direct children), and non-interactive items may be included too.
|
|
31
36
|
*/
|
|
32
37
|
const ExpandCollapse = React.forwardRef(
|
|
33
|
-
({ children, tokens, variant, maxOpen, open, initialOpen, onChange, ...rest }, ref) => {
|
|
38
|
+
({ children, tokens, variant, maxOpen, open, initialOpen, onChange, dataSet, ...rest }, ref) => {
|
|
34
39
|
const {
|
|
35
40
|
currentValues: openIds,
|
|
36
41
|
toggleOneValue: onToggle,
|
|
@@ -46,7 +51,7 @@ const ExpandCollapse = React.forwardRef(
|
|
|
46
51
|
const themeTokens = useThemeTokens('ExpandCollapse', tokens, variant)
|
|
47
52
|
|
|
48
53
|
return (
|
|
49
|
-
<View style={staticStyles.container} ref={ref} {...selectProps(rest)}>
|
|
54
|
+
<View style={staticStyles.container} ref={ref} {...selectProps(rest)} dataSet={dataSet}>
|
|
50
55
|
<View style={selectBorderStyles(themeTokens)}>
|
|
51
56
|
{typeof children === 'function'
|
|
52
57
|
? children({ openIds, onToggle, resetValues, setValues, unsetValues })
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
3
|
import ExpandCollapse from '../ExpandCollapse'
|
|
4
|
-
import { getTokensPropType } from '../utils'
|
|
4
|
+
import { getTokensPropType, selectSystemProps, contentfulProps } from '../utils'
|
|
5
5
|
import ExpandCollapseMiniControl from './ExpandCollapseMiniControl'
|
|
6
6
|
|
|
7
|
+
const [selectContainerProps, selectedContainerPropTypes] = selectSystemProps([contentfulProps])
|
|
8
|
+
|
|
7
9
|
const ExpandCollapseMini = React.forwardRef(
|
|
8
|
-
(
|
|
10
|
+
(
|
|
11
|
+
{ children, onToggle = () => {}, tokens = {}, nativeID, initialOpen = false, dataSet, ...rest },
|
|
12
|
+
ref
|
|
13
|
+
) => {
|
|
9
14
|
const expandCollapeMiniPanelId = 'ExpandCollapseMiniPanel'
|
|
10
15
|
const handleChange = (openPanels, event) => {
|
|
11
16
|
if (typeof onToggle === 'function') {
|
|
@@ -19,6 +24,8 @@ const ExpandCollapseMini = React.forwardRef(
|
|
|
19
24
|
onChange={handleChange}
|
|
20
25
|
tokens={tokens}
|
|
21
26
|
initialOpen={initialOpen ? [expandCollapeMiniPanelId] : []}
|
|
27
|
+
{...selectContainerProps(rest)}
|
|
28
|
+
dataSet={dataSet}
|
|
22
29
|
>
|
|
23
30
|
{(expandProps) => (
|
|
24
31
|
<ExpandCollapse.Panel
|
|
@@ -51,6 +58,7 @@ ExpandCollapseMini.displayName = 'ExpandCollapseMini'
|
|
|
51
58
|
|
|
52
59
|
ExpandCollapseMini.propTypes = {
|
|
53
60
|
...ExpandCollapseMiniControl.propTypes,
|
|
61
|
+
...selectedContainerPropTypes,
|
|
54
62
|
/**
|
|
55
63
|
* Function to call on pressing the panel's control, which should open or close the panel.
|
|
56
64
|
*/
|
|
@@ -70,7 +78,11 @@ ExpandCollapseMini.propTypes = {
|
|
|
70
78
|
/**
|
|
71
79
|
* Optional variant object to override the default theme tokens
|
|
72
80
|
*/
|
|
73
|
-
tokens: getTokensPropType('ExpandCollapseMini')
|
|
81
|
+
tokens: getTokensPropType('ExpandCollapseMini'),
|
|
82
|
+
/**
|
|
83
|
+
* The dataSet prop allows to pass data-* attributes element to the component.
|
|
84
|
+
*/
|
|
85
|
+
dataSet: PropTypes.object
|
|
74
86
|
}
|
|
75
87
|
|
|
76
88
|
export default ExpandCollapseMini
|
|
@@ -21,7 +21,7 @@ import Spacer from '../Spacer'
|
|
|
21
21
|
import StackView from '../StackView'
|
|
22
22
|
|
|
23
23
|
import NotificationContent from './NotificationContent'
|
|
24
|
-
import
|
|
24
|
+
import defaultDictionary from './dictionary'
|
|
25
25
|
|
|
26
26
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
|
|
27
27
|
|
|
@@ -113,6 +113,7 @@ const FileUpload = React.forwardRef(
|
|
|
113
113
|
onUpload,
|
|
114
114
|
onDelete,
|
|
115
115
|
documentPicker,
|
|
116
|
+
dictionary = defaultDictionary,
|
|
116
117
|
...rest
|
|
117
118
|
},
|
|
118
119
|
ref
|
|
@@ -390,6 +391,28 @@ const FileUpload = React.forwardRef(
|
|
|
390
391
|
|
|
391
392
|
FileUpload.displayName = 'FileUpload'
|
|
392
393
|
|
|
394
|
+
const dictionaryEntryShape = PropTypes.shape({
|
|
395
|
+
label: PropTypes.string.isRequired,
|
|
396
|
+
buttonLabel: PropTypes.string.isRequired,
|
|
397
|
+
dismissButtonLabel: PropTypes.string.isRequired,
|
|
398
|
+
wrongFileType: PropTypes.string.isRequired,
|
|
399
|
+
allowedFileTypes: PropTypes.string.isRequired,
|
|
400
|
+
fileTooBig: PropTypes.string.isRequired,
|
|
401
|
+
fileIsEmpty: PropTypes.string.isRequired,
|
|
402
|
+
problemUploading: PropTypes.string.isRequired,
|
|
403
|
+
problemDeleting: PropTypes.string.isRequired,
|
|
404
|
+
problemUploadingMultipleFiles: PropTypes.string.isRequired,
|
|
405
|
+
only: PropTypes.string.isRequired,
|
|
406
|
+
and: PropTypes.string.isRequired,
|
|
407
|
+
or: PropTypes.string.isRequired,
|
|
408
|
+
uploadSuccess: PropTypes.string.isRequired,
|
|
409
|
+
uploadError: PropTypes.string.isRequired,
|
|
410
|
+
deleteProblem: PropTypes.string.isRequired,
|
|
411
|
+
tooManyFiles: PropTypes.string.isRequired,
|
|
412
|
+
fileTooSmall: PropTypes.string.isRequired,
|
|
413
|
+
fewFiles: PropTypes.string.isRequired
|
|
414
|
+
})
|
|
415
|
+
|
|
393
416
|
FileUpload.propTypes = {
|
|
394
417
|
...selectedSystemPropTypes,
|
|
395
418
|
tokens: getTokensPropType('FileUpload'),
|
|
@@ -433,7 +456,14 @@ FileUpload.propTypes = {
|
|
|
433
456
|
/**
|
|
434
457
|
* The minimum file size allowed for upload in MB.
|
|
435
458
|
*/
|
|
436
|
-
minFileSize: PropTypes.number
|
|
459
|
+
minFileSize: PropTypes.number,
|
|
460
|
+
/**
|
|
461
|
+
* Custom dictionary containing the labels to use for the steps
|
|
462
|
+
*/
|
|
463
|
+
dictionary: PropTypes.shape({
|
|
464
|
+
en: dictionaryEntryShape,
|
|
465
|
+
fr: dictionaryEntryShape
|
|
466
|
+
})
|
|
437
467
|
}
|
|
438
468
|
|
|
439
469
|
export default FileUpload
|
package/src/Link/Link.jsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
2
3
|
|
|
3
4
|
import { useThemeTokensCallback } from '../ThemeProvider'
|
|
4
5
|
import LinkBase from './LinkBase'
|
|
@@ -25,6 +26,12 @@ const Link = React.forwardRef(
|
|
|
25
26
|
)
|
|
26
27
|
Link.displayName = 'Link'
|
|
27
28
|
|
|
28
|
-
Link.propTypes =
|
|
29
|
+
Link.propTypes = {
|
|
30
|
+
...LinkBase.propTypes,
|
|
31
|
+
/**
|
|
32
|
+
* The dataSet prop allows to pass data-* attributes element to the component.
|
|
33
|
+
*/
|
|
34
|
+
dataSet: PropTypes.object
|
|
35
|
+
}
|
|
29
36
|
|
|
30
37
|
export default Link
|
package/src/Link/LinkBase.jsx
CHANGED
|
@@ -132,6 +132,7 @@ const LinkBase = React.forwardRef(
|
|
|
132
132
|
variant,
|
|
133
133
|
tokens = {},
|
|
134
134
|
children,
|
|
135
|
+
dataSet,
|
|
135
136
|
accessibilityRole = 'link',
|
|
136
137
|
...rawRest
|
|
137
138
|
},
|
|
@@ -162,6 +163,7 @@ const LinkBase = React.forwardRef(
|
|
|
162
163
|
return (
|
|
163
164
|
<InlinePressable
|
|
164
165
|
{...selectedProps}
|
|
166
|
+
dataSet={dataSet}
|
|
165
167
|
inlineFlex={hasIcon}
|
|
166
168
|
// assuming links without icons should be inline (even if they are long)
|
|
167
169
|
ref={ref}
|