@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.
Files changed (54) hide show
  1. package/CHANGELOG.md +28 -2
  2. package/lib/cjs/ActivityIndicator/Dots.js +165 -0
  3. package/lib/cjs/ActivityIndicator/Dots.native.js +221 -0
  4. package/lib/cjs/ActivityIndicator/Spinner.js +57 -50
  5. package/lib/cjs/ActivityIndicator/Spinner.native.js +90 -108
  6. package/lib/cjs/ActivityIndicator/index.js +12 -1
  7. package/lib/cjs/ActivityIndicator/shared.js +53 -6
  8. package/lib/cjs/Button/ButtonBase.js +1 -1
  9. package/lib/cjs/Button/ButtonLink.js +1 -0
  10. package/lib/cjs/Carousel/Carousel.js +18 -7
  11. package/lib/cjs/ExpandCollapse/ExpandCollapse.js +3 -1
  12. package/lib/cjs/ExpandCollapseMini/ExpandCollapseMini.js +10 -1
  13. package/lib/cjs/FileUpload/FileUpload.js +31 -2
  14. package/lib/cjs/Link/Link.js +8 -1
  15. package/lib/cjs/Link/LinkBase.js +2 -0
  16. package/lib/cjs/MultiSelectFilter/MultiSelectFilter.js +3 -2
  17. package/lib/cjs/utils/containUniqueFields.js +5 -5
  18. package/lib/cjs/utils/useUniqueId.js +2 -6
  19. package/lib/esm/ActivityIndicator/Dots.js +158 -0
  20. package/lib/esm/ActivityIndicator/Dots.native.js +212 -0
  21. package/lib/esm/ActivityIndicator/Spinner.js +58 -51
  22. package/lib/esm/ActivityIndicator/Spinner.native.js +90 -110
  23. package/lib/esm/ActivityIndicator/index.js +12 -1
  24. package/lib/esm/ActivityIndicator/shared.js +52 -5
  25. package/lib/esm/Button/ButtonBase.js +2 -2
  26. package/lib/esm/Button/ButtonLink.js +2 -1
  27. package/lib/esm/Carousel/Carousel.js +18 -7
  28. package/lib/esm/ExpandCollapse/ExpandCollapse.js +4 -2
  29. package/lib/esm/ExpandCollapseMini/ExpandCollapseMini.js +11 -2
  30. package/lib/esm/FileUpload/FileUpload.js +31 -2
  31. package/lib/esm/Link/Link.js +8 -1
  32. package/lib/esm/Link/LinkBase.js +2 -0
  33. package/lib/esm/MultiSelectFilter/MultiSelectFilter.js +3 -2
  34. package/lib/esm/utils/containUniqueFields.js +5 -5
  35. package/lib/esm/utils/useUniqueId.js +3 -7
  36. package/lib/package.json +4 -3
  37. package/package.json +4 -3
  38. package/src/ActivityIndicator/Dots.jsx +200 -0
  39. package/src/ActivityIndicator/Dots.native.jsx +213 -0
  40. package/src/ActivityIndicator/Spinner.jsx +95 -59
  41. package/src/ActivityIndicator/Spinner.native.jsx +125 -132
  42. package/src/ActivityIndicator/index.jsx +17 -2
  43. package/src/ActivityIndicator/shared.js +52 -5
  44. package/src/Button/ButtonBase.jsx +4 -2
  45. package/src/Button/ButtonLink.jsx +3 -1
  46. package/src/Carousel/Carousel.jsx +28 -7
  47. package/src/ExpandCollapse/ExpandCollapse.jsx +9 -4
  48. package/src/ExpandCollapseMini/ExpandCollapseMini.jsx +15 -3
  49. package/src/FileUpload/FileUpload.jsx +32 -2
  50. package/src/Link/Link.jsx +8 -1
  51. package/src/Link/LinkBase.jsx +2 -0
  52. package/src/MultiSelectFilter/MultiSelectFilter.jsx +2 -2
  53. package/src/utils/containUniqueFields.js +5 -5
  54. package/src/utils/useUniqueId.js +3 -8
@@ -1,140 +1,133 @@
1
1
  import React from 'react'
2
- import { Animated, Easing, StyleSheet, View } from 'react-native'
3
- import { DURATION, MIN_EMPTY_ANGLE, MIN_STROKE_ANGLE, BEZIER, propTypes } from './shared'
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 ea = MIN_EMPTY_ANGLE / 2
7
- const sa = MIN_STROKE_ANGLE / 2
8
-
9
- const Spinner = React.forwardRef(({ size, color, thickness, label, isStatic = false }, ref) => {
10
- const { current: timer } = React.useRef(new Animated.Value(0))
11
- const { reduceMotionEnabled } = useA11yInfo()
12
- const reduceMotion = reduceMotionEnabled || isStatic
13
-
14
- React.useLayoutEffect(() => {
15
- const loop = Animated.timing(timer, {
16
- duration: DURATION,
17
- easing: Easing.linear,
18
- // Animated.loop does not work if useNativeDriver is true on web
19
- useNativeDriver: true,
20
- toValue: 1,
21
- isInteraction: false
22
- })
23
-
24
- if (!reduceMotion) Animated.loop(loop).start()
25
- else loop.stop()
26
- }, [timer, reduceMotion])
27
-
28
- const frames = (60 * DURATION) / 1000
29
- const easing = Easing.bezier(...BEZIER)
30
- const containerStyle = {
31
- width: size,
32
- height: size / (reduceMotion ? 1.5 : 2),
33
- overflow: 'hidden'
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
- const animationFrequency = reduceMotion ? [0] : [0, 1]
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('ActivityIndicator', tokens, variant)
14
- return (
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
- // these could be specified by the theme
4
- export const DURATION = 1800
5
- export const MIN_EMPTY_ANGLE = 60
6
- export const MIN_STROKE_ANGLE = 30
7
- export const BEZIER = [0.42, 0.0, 0.58, 1.0]
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 (enablePeeking || enableDisplayMultipleItemsPerSlide) {
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([a11yProps, viewProps])
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
- ({ children, onToggle = () => {}, tokens = {}, nativeID, initialOpen = false, ...rest }, ref) => {
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 dictionary from './dictionary'
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 = LinkBase.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
@@ -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}