@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,144 +1,124 @@
1
1
  import React from 'react';
2
+ import View from "react-native-web/dist/exports/View";
2
3
  import Animated from "react-native-web/dist/exports/Animated";
3
4
  import Easing from "react-native-web/dist/exports/Easing";
4
- import StyleSheet from "react-native-web/dist/exports/StyleSheet";
5
- import View from "react-native-web/dist/exports/View";
6
- import { DURATION, MIN_EMPTY_ANGLE, MIN_STROKE_ANGLE, BEZIER, propTypes } from './shared';
5
+ import Svg, { Circle } from 'react-native-svg';
6
+ import { DURATION, SVG_CIRCUMFERENCE, SVG_SIZE, SVG_CENTER, SPINNER_RADIUS, SPINNER_DASHARRAY_HALF, SPINNER_DASHARRAY_MIN, SPINNER_DASHOFFSET_FACTOR, propTypes } from './shared';
7
7
  import { useA11yInfo } from '../A11yInfoProvider';
8
- import { jsx as _jsx } from "react/jsx-runtime";
9
- const ea = MIN_EMPTY_ANGLE / 2;
10
- const sa = MIN_STROKE_ANGLE / 2;
8
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
9
  const Spinner = /*#__PURE__*/React.forwardRef((_ref, ref) => {
12
10
  let {
13
11
  size,
14
12
  color,
13
+ indicatorBackgroundColor,
15
14
  thickness,
16
15
  label,
17
16
  isStatic = false
18
17
  } = _ref;
19
- const {
20
- current: timer
21
- } = React.useRef(new Animated.Value(0));
22
18
  const {
23
19
  reduceMotionEnabled
24
20
  } = useA11yInfo();
25
21
  const reduceMotion = reduceMotionEnabled || isStatic;
26
- React.useLayoutEffect(() => {
27
- const loop = Animated.timing(timer, {
22
+
23
+ // Animated value between 0..1 that will loop
24
+ const progress = React.useRef(new Animated.Value(0)).current;
25
+
26
+ // Local state to force re-render on each frame
27
+ const [progressVal, setProgressVal] = React.useState(0);
28
+ React.useEffect(() => {
29
+ if (reduceMotion) {
30
+ progress.stopAnimation(() => {
31
+ progress.setValue(0);
32
+ setProgressVal(0);
33
+ });
34
+ return undefined;
35
+ }
36
+ const id = progress.addListener(_ref2 => {
37
+ let {
38
+ value
39
+ } = _ref2;
40
+ setProgressVal(value);
41
+ });
42
+ Animated.loop(Animated.timing(progress, {
43
+ toValue: 1,
28
44
  duration: DURATION,
29
45
  easing: Easing.linear,
30
- // Animated.loop does not work if useNativeDriver is true on web
31
- useNativeDriver: true,
32
- toValue: 1,
46
+ useNativeDriver: false,
33
47
  isInteraction: false
34
- });
35
- if (!reduceMotion) Animated.loop(loop).start();else loop.stop();
36
- }, [timer, reduceMotion]);
37
- const frames = 60 * DURATION / 1000;
38
- const easing = Easing.bezier(...BEZIER);
39
- const containerStyle = {
40
- width: size,
41
- height: size / (reduceMotion ? 1.5 : 2),
42
- overflow: 'hidden'
43
- };
44
- const animationFrequency = reduceMotion ? [0] : [0, 1];
48
+ })).start();
49
+ return () => {
50
+ progress.removeListener(id);
51
+ progress.stopAnimation();
52
+ };
53
+ }, [progress, reduceMotion]);
45
54
 
46
- // Credit to https://github.com/n4kz/react-native-indicators and https://github.com/callstack/react-native-paper for this
55
+ /* The same logic used in Wweb keyframes:
56
+ - rotation from -90° base plus 0..183° => -90..93
57
+ - dasharray from 1% -> 50% -> 1%
58
+ - dashoffset from 0 -> 0 -> -49%
59
+ */
60
+
61
+ // 1) rotation (0->183) plus base offset -90
62
+ const rotationDeg = -90 + 183 * progressVal; // -90..+93
63
+
64
+ // strokeDasharray
65
+ let dashArrayVisible;
66
+ if (progressVal < SPINNER_DASHARRAY_HALF) {
67
+ const segmentProgress = progressVal / SPINNER_DASHARRAY_HALF;
68
+ dashArrayVisible = SPINNER_DASHARRAY_MIN + (SPINNER_DASHARRAY_HALF - SPINNER_DASHARRAY_MIN) * segmentProgress;
69
+ } else {
70
+ const segmentProgress = (progressVal - SPINNER_DASHARRAY_HALF) / SPINNER_DASHARRAY_HALF;
71
+ dashArrayVisible = SPINNER_DASHARRAY_HALF + (SPINNER_DASHARRAY_MIN - SPINNER_DASHARRAY_HALF) * segmentProgress;
72
+ }
73
+ const visibleLength = dashArrayVisible * SVG_CIRCUMFERENCE;
74
+ const invisibleLength = SVG_CIRCUMFERENCE - visibleLength;
75
+ const strokeDasharray = `${visibleLength},${invisibleLength}`;
76
+
77
+ // strokeDashoffset
78
+ let strokeDashoffset = 0;
79
+ if (progressVal > SPINNER_DASHARRAY_HALF) {
80
+ const segmentProgress = (progressVal - SPINNER_DASHARRAY_HALF) / SPINNER_DASHARRAY_HALF;
81
+ strokeDashoffset = -SPINNER_DASHOFFSET_FACTOR * SVG_CIRCUMFERENCE * segmentProgress;
82
+ }
83
+ const strokeWidth = thickness * SVG_SIZE / size;
47
84
  return /*#__PURE__*/_jsx(View, {
48
85
  ref: ref,
49
- style: [styles.container],
86
+ style: {
87
+ width: size,
88
+ height: size
89
+ },
50
90
  accessible: true,
51
91
  accessibilityLabel: label,
52
92
  accessibilityRole: "progressbar",
53
93
  accessibilityState: {
54
94
  busy: true
55
95
  },
56
- children: /*#__PURE__*/_jsx(Animated.View, {
57
- style: [{
58
- width: size,
59
- height: size
60
- }],
61
- collapsable: false,
62
- children: animationFrequency.map(index => {
63
- const inputRange = Array.from(new Array(frames), (_, frameIndex) => frameIndex / (frames - 1));
64
- const outputRange = Array.from(new Array(frames), (_, frameIndex) => {
65
- let progress = 2 * frameIndex / (frames - 1);
66
- const rotation = index ? +(360 - sa) : -(180 - sa);
67
- if (progress > 1.0) {
68
- progress = 2.0 - progress;
69
- }
70
- const direction = index ? -1 : +1;
71
- return `${direction * (180 - (sa + ea)) * easing(progress) + rotation}deg`;
72
- });
73
- const layerStyle = {
74
- width: size,
75
- height: size
76
- };
77
- const viewportStyle = {
78
- width: size,
79
- height: size
80
- };
81
- if (!reduceMotion) {
82
- layerStyle.transform = [{
83
- rotate: timer.interpolate({
84
- inputRange: [0, 1],
85
- outputRange: [`${0 + ea + sa}deg`, `${2 * 360 + ea + sa}deg`]
86
- })
87
- }];
88
- viewportStyle.transform = [{
89
- translateY: index ? -size / 2 : 0
90
- }, {
91
- rotate: timer.interpolate({
92
- inputRange,
93
- outputRange
94
- })
95
- }];
96
- }
97
- const offsetStyle = index ? {
98
- top: size / 2
99
- } : null;
100
- const lineStyle = {
101
- width: size,
102
- height: size,
103
- borderColor: color,
104
- borderWidth: thickness,
105
- borderRadius: size / 2
106
- };
107
- return /*#__PURE__*/_jsx(Animated.View, {
108
- style: [styles.layer],
109
- children: /*#__PURE__*/_jsx(Animated.View, {
110
- style: layerStyle,
111
- children: /*#__PURE__*/_jsx(Animated.View, {
112
- style: [containerStyle, offsetStyle],
113
- collapsable: false,
114
- children: /*#__PURE__*/_jsx(Animated.View, {
115
- style: viewportStyle,
116
- children: /*#__PURE__*/_jsx(Animated.View, {
117
- style: containerStyle,
118
- collapsable: false,
119
- children: /*#__PURE__*/_jsx(Animated.View, {
120
- style: lineStyle
121
- })
122
- })
123
- })
124
- })
125
- })
126
- }, index);
127
- })
96
+ children: /*#__PURE__*/_jsxs(Svg, {
97
+ width: size,
98
+ height: size,
99
+ viewBox: `0 0 ${SVG_SIZE} ${SVG_SIZE}`,
100
+ children: [/*#__PURE__*/_jsx(Circle, {
101
+ cx: SVG_CENTER,
102
+ cy: SVG_CENTER,
103
+ r: SPINNER_RADIUS,
104
+ fill: "none",
105
+ stroke: indicatorBackgroundColor,
106
+ strokeWidth: strokeWidth
107
+ }), /*#__PURE__*/_jsx(Circle, {
108
+ cx: SVG_CENTER,
109
+ cy: SVG_CENTER,
110
+ r: SPINNER_RADIUS,
111
+ fill: "none",
112
+ stroke: color,
113
+ strokeWidth: strokeWidth,
114
+ strokeLinecap: "round",
115
+ transform: `rotate(${rotationDeg}, 24, 24)`,
116
+ strokeDasharray: strokeDasharray,
117
+ strokeDashoffset: strokeDashoffset
118
+ })]
128
119
  })
129
120
  });
130
121
  });
131
122
  Spinner.displayName = 'Spinner';
132
123
  Spinner.propTypes = propTypes;
133
- const styles = StyleSheet.create({
134
- container: {
135
- flexGrow: 0,
136
- flexShrink: 0
137
- },
138
- layer: {
139
- ...StyleSheet.absoluteFillObject,
140
- justifyContent: 'center',
141
- alignItems: 'center'
142
- }
143
- });
144
124
  export default Spinner;
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
3
3
  import { useThemeTokens } from '../ThemeProvider';
4
4
  import { getTokensPropType, variantProp } from '../utils/props';
5
5
  import Spinner from './Spinner';
6
+ import Dots from './Dots';
6
7
 
7
8
  /**
8
9
  * `ActivityIndicator` renders a visual loading state.
@@ -18,13 +19,23 @@ const ActivityIndicator = /*#__PURE__*/React.forwardRef((_ref, ref) => {
18
19
  } = _ref;
19
20
  const {
20
21
  size,
22
+ dotSize,
21
23
  color,
24
+ indicatorBackgroundColor,
22
25
  thickness
23
26
  } = useThemeTokens('ActivityIndicator', tokens, variant);
24
- return /*#__PURE__*/_jsx(Spinner, {
27
+ return variant?.dots ? /*#__PURE__*/_jsx(Dots, {
28
+ ref: ref,
29
+ size: dotSize,
30
+ color: color,
31
+ indicatorBackgroundColor: indicatorBackgroundColor,
32
+ label: label,
33
+ isStatic: isStatic
34
+ }) : /*#__PURE__*/_jsx(Spinner, {
25
35
  ref: ref,
26
36
  size: size,
27
37
  color: color,
38
+ indicatorBackgroundColor: indicatorBackgroundColor,
28
39
  thickness: thickness,
29
40
  label: label,
30
41
  isStatic: isStatic
@@ -1,14 +1,61 @@
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
  export const propTypes = {
9
54
  color: PropTypes.string.isRequired,
55
+ baseColor: PropTypes.string,
10
56
  label: PropTypes.string.isRequired,
11
57
  size: PropTypes.number.isRequired,
58
+ dotsize: PropTypes.number,
12
59
  thickness: PropTypes.number.isRequired,
13
60
  isStatic: PropTypes.bool
14
61
  };
@@ -6,10 +6,10 @@ import StyleSheet from "react-native-web/dist/exports/StyleSheet";
6
6
  import Platform from "react-native-web/dist/exports/Platform";
7
7
  import { applyTextStyles, applyShadowToken, applyOuterBorder, useTheme } from '../ThemeProvider';
8
8
  import buttonPropTypes from './propTypes';
9
- import { a11yProps, clickProps, focusHandlerProps, getCursorStyle, linkProps, resolvePressableState, resolvePressableTokens, selectSystemProps, viewProps, wrapStringsInText, withLinkRouter } from '../utils';
9
+ import { a11yProps, clickProps, focusHandlerProps, getCursorStyle, linkProps, resolvePressableState, resolvePressableTokens, selectSystemProps, viewProps, wrapStringsInText, withLinkRouter, contentfulProps } from '../utils';
10
10
  import { IconText } from '../Icon';
11
11
  import { jsx as _jsx } from "react/jsx-runtime";
12
- const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, focusHandlerProps, linkProps, viewProps]);
12
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, focusHandlerProps, linkProps, viewProps, contentfulProps]);
13
13
  const getOuterBorderOffset = _ref => {
14
14
  let {
15
15
  outerBorderGap = 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
 
@@ -43,6 +43,7 @@ ButtonLink.propTypes = {
43
43
  ...a11yProps.types,
44
44
  ...buttonPropTypes,
45
45
  ...linkProps.types,
46
+ ...contentfulProps.types,
46
47
  children: textAndA11yText,
47
48
  dataSet: PropTypes.object,
48
49
  accessibilityRole: PropTypes.string
@@ -84,7 +84,9 @@ const selectControlButtonPositionStyles = _ref => {
84
84
  positionProperty = getDynamicPositionProperty(),
85
85
  spaceBetweenSlideAndButton,
86
86
  enablePeeking,
87
- enableDisplayMultipleItemsPerSlide
87
+ enableDisplayMultipleItemsPerSlide,
88
+ isAutoPlayEnabled,
89
+ viewport
88
90
  } = _ref;
89
91
  const styles = {};
90
92
  if (positionVariant === 'edge') {
@@ -92,7 +94,7 @@ const selectControlButtonPositionStyles = _ref => {
92
94
  } else if (positionVariant === 'inside') {
93
95
  styles[positionProperty] = DEFAULT_POSITION_OFFSET;
94
96
  } else if (positionVariant === 'outside') {
95
- if (enablePeeking || enableDisplayMultipleItemsPerSlide) {
97
+ if (enablePeeking || enableDisplayMultipleItemsPerSlide || isAutoPlayEnabled && viewport === 'xs') {
96
98
  styles[positionProperty] = 0;
97
99
  } else {
98
100
  styles[positionProperty] = -1 * (spaceBetweenSlideAndButton + buttonWidth);
@@ -100,7 +102,7 @@ const selectControlButtonPositionStyles = _ref => {
100
102
  }
101
103
  return styles;
102
104
  };
103
- const selectPreviousNextNavigationButtonStyles = (previousNextNavigationButtonWidth, previousNextNavigationPosition, spaceBetweenSlideAndPreviousNextNavigation, isFirstSlide, isLastSlide, areStylesAppliedOnPreviousButton, enablePeeking, enableDisplayMultipleItemsPerSlide) => {
105
+ const selectPreviousNextNavigationButtonStyles = (previousNextNavigationButtonWidth, previousNextNavigationPosition, spaceBetweenSlideAndPreviousNextNavigation, isFirstSlide, isLastSlide, areStylesAppliedOnPreviousButton, enablePeeking, enableDisplayMultipleItemsPerSlide, isAutoPlayEnabled, viewport) => {
104
106
  const styles = {
105
107
  zIndex: 1,
106
108
  position: 'absolute'
@@ -120,7 +122,9 @@ const selectPreviousNextNavigationButtonStyles = (previousNextNavigationButtonWi
120
122
  positionProperty: getDynamicPositionProperty(areStylesAppliedOnPreviousButton),
121
123
  spaceBetweenSlideAndButton: spaceBetweenSlideAndPreviousNextNavigation,
122
124
  enablePeeking,
123
- enableDisplayMultipleItemsPerSlide
125
+ enableDisplayMultipleItemsPerSlide,
126
+ isAutoPlayEnabled,
127
+ viewport
124
128
  })
125
129
  };
126
130
  };
@@ -167,6 +171,11 @@ const selectRootContainerStyles = (enableHero, viewport) => {
167
171
  alignItems: 'center'
168
172
  };
169
173
  }
174
+ if (enableHero) {
175
+ return {
176
+ paddingHorizontal: 16
177
+ };
178
+ }
170
179
  return {};
171
180
  };
172
181
  const selectMainContainerStyles = (enableHero, viewport) => {
@@ -881,7 +890,9 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
881
890
  positionProperty: getDynamicPositionProperty(),
882
891
  spaceBetweenSlideAndButton: spaceBetweenSlideAndPreviousNextNavigation,
883
892
  enablePeeking,
884
- enableDisplayMultipleItemsPerSlide
893
+ enableDisplayMultipleItemsPerSlide,
894
+ isAutoPlayEnabled,
895
+ viewport
885
896
  })],
886
897
  children: /*#__PURE__*/_jsx(IconButton, {
887
898
  icon: isCarouselPlaying ? pauseIcon : playIcon,
@@ -890,7 +901,7 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
890
901
  onPress: onAnimationControlButtonPress
891
902
  })
892
903
  }) : null, showPreviousNextNavigation && totalItems > 1 ? /*#__PURE__*/_jsx(View, {
893
- style: selectPreviousNextNavigationButtonStyles(previousNextNavigationButtonWidth, previousNextNavigationPosition, spaceBetweenSlideAndPreviousNextNavigation, isFirstSlide, isLastSlide, true, enablePeeking, enableDisplayMultipleItemsPerSlide),
904
+ style: selectPreviousNextNavigationButtonStyles(previousNextNavigationButtonWidth, previousNextNavigationPosition, spaceBetweenSlideAndPreviousNextNavigation, isFirstSlide, isLastSlide, true, enablePeeking, enableDisplayMultipleItemsPerSlide, isAutoPlayEnabled, viewport),
894
905
  testID: "previous-button-container",
895
906
  children: /*#__PURE__*/_jsx(IconButton, {
896
907
  onLayout: onPreviousNextNavigationButtonLayout,
@@ -942,7 +953,7 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
942
953
  })
943
954
  })
944
955
  }), showPreviousNextNavigation && totalItems > 1 ? /*#__PURE__*/_jsx(View, {
945
- style: selectPreviousNextNavigationButtonStyles(previousNextNavigationButtonWidth, previousNextNavigationPosition, spaceBetweenSlideAndPreviousNextNavigation, isFirstSlide, isLastSlide, false, enablePeeking, enableDisplayMultipleItemsPerSlide),
956
+ style: selectPreviousNextNavigationButtonStyles(previousNextNavigationButtonWidth, previousNextNavigationPosition, spaceBetweenSlideAndPreviousNextNavigation, isFirstSlide, isLastSlide, false, enablePeeking, enableDisplayMultipleItemsPerSlide, isAutoPlayEnabled, viewport),
946
957
  testID: "next-button-container",
947
958
  children: /*#__PURE__*/_jsx(IconButton, {
948
959
  onLayout: onPreviousNextNavigationButtonLayout,
@@ -3,9 +3,9 @@ import View from "react-native-web/dist/exports/View";
3
3
  import StyleSheet from "react-native-web/dist/exports/StyleSheet";
4
4
  import PropTypes from 'prop-types';
5
5
  import { useThemeTokens } from '../ThemeProvider';
6
- import { a11yProps, getTokensPropType, selectSystemProps, useMultipleInputValues, variantProp, viewProps } from '../utils';
6
+ import { a11yProps, getTokensPropType, selectSystemProps, useMultipleInputValues, variantProp, viewProps, contentfulProps } from '../utils';
7
7
  import { jsx as _jsx } from "react/jsx-runtime";
8
- const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
8
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps, contentfulProps]);
9
9
  function selectBorderStyles(tokens) {
10
10
  return {
11
11
  borderBottomWidth: tokens.borderWidth,
@@ -30,6 +30,7 @@ const ExpandCollapse = /*#__PURE__*/React.forwardRef((_ref, ref) => {
30
30
  open,
31
31
  initialOpen,
32
32
  onChange,
33
+ dataSet,
33
34
  ...rest
34
35
  } = _ref;
35
36
  const {
@@ -49,6 +50,7 @@ const ExpandCollapse = /*#__PURE__*/React.forwardRef((_ref, ref) => {
49
50
  style: staticStyles.container,
50
51
  ref: ref,
51
52
  ...selectProps(rest),
53
+ dataSet: dataSet,
52
54
  children: /*#__PURE__*/_jsx(View, {
53
55
  style: selectBorderStyles(themeTokens),
54
56
  children: typeof children === 'function' ? children({
@@ -1,9 +1,10 @@
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
  import { jsx as _jsx } from "react/jsx-runtime";
7
+ const [selectContainerProps, selectedContainerPropTypes] = selectSystemProps([contentfulProps]);
7
8
  const ExpandCollapseMini = /*#__PURE__*/React.forwardRef((_ref, ref) => {
8
9
  let {
9
10
  children,
@@ -11,6 +12,7 @@ const ExpandCollapseMini = /*#__PURE__*/React.forwardRef((_ref, ref) => {
11
12
  tokens = {},
12
13
  nativeID,
13
14
  initialOpen = false,
15
+ dataSet,
14
16
  ...rest
15
17
  } = _ref;
16
18
  const expandCollapeMiniPanelId = 'ExpandCollapseMiniPanel';
@@ -24,6 +26,8 @@ const ExpandCollapseMini = /*#__PURE__*/React.forwardRef((_ref, ref) => {
24
26
  onChange: handleChange,
25
27
  tokens: tokens,
26
28
  initialOpen: initialOpen ? [expandCollapeMiniPanelId] : [],
29
+ ...selectContainerProps(rest),
30
+ dataSet: dataSet,
27
31
  children: expandProps => /*#__PURE__*/_jsx(ExpandCollapse.Panel, {
28
32
  ...expandProps,
29
33
  panelId: expandCollapeMiniPanelId,
@@ -53,6 +57,7 @@ const ExpandCollapseMini = /*#__PURE__*/React.forwardRef((_ref, ref) => {
53
57
  ExpandCollapseMini.displayName = 'ExpandCollapseMini';
54
58
  ExpandCollapseMini.propTypes = {
55
59
  ...ExpandCollapseMiniControl.propTypes,
60
+ ...selectedContainerPropTypes,
56
61
  /**
57
62
  * Function to call on pressing the panel's control, which should open or close the panel.
58
63
  */
@@ -72,6 +77,10 @@ ExpandCollapseMini.propTypes = {
72
77
  /**
73
78
  * Optional variant object to override the default theme tokens
74
79
  */
75
- tokens: getTokensPropType('ExpandCollapseMini')
80
+ tokens: getTokensPropType('ExpandCollapseMini'),
81
+ /**
82
+ * The dataSet prop allows to pass data-* attributes element to the component.
83
+ */
84
+ dataSet: PropTypes.object
76
85
  };
77
86
  export default ExpandCollapseMini;
@@ -10,7 +10,7 @@ import Notification from '../Notification';
10
10
  import Spacer from '../Spacer';
11
11
  import StackView from '../StackView';
12
12
  import NotificationContent from './NotificationContent';
13
- import dictionary from './dictionary';
13
+ import defaultDictionary from './dictionary';
14
14
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
15
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
16
16
  const getHintFromFileTypes = fileTypes => {
@@ -95,6 +95,7 @@ const FileUpload = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
95
95
  onUpload,
96
96
  onDelete,
97
97
  documentPicker,
98
+ dictionary = defaultDictionary,
98
99
  ...rest
99
100
  } = _ref2;
100
101
  if (minFilesCount <= 0) {
@@ -315,6 +316,27 @@ const FileUpload = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
315
316
  });
316
317
  });
317
318
  FileUpload.displayName = 'FileUpload';
319
+ const dictionaryEntryShape = PropTypes.shape({
320
+ label: PropTypes.string.isRequired,
321
+ buttonLabel: PropTypes.string.isRequired,
322
+ dismissButtonLabel: PropTypes.string.isRequired,
323
+ wrongFileType: PropTypes.string.isRequired,
324
+ allowedFileTypes: PropTypes.string.isRequired,
325
+ fileTooBig: PropTypes.string.isRequired,
326
+ fileIsEmpty: PropTypes.string.isRequired,
327
+ problemUploading: PropTypes.string.isRequired,
328
+ problemDeleting: PropTypes.string.isRequired,
329
+ problemUploadingMultipleFiles: PropTypes.string.isRequired,
330
+ only: PropTypes.string.isRequired,
331
+ and: PropTypes.string.isRequired,
332
+ or: PropTypes.string.isRequired,
333
+ uploadSuccess: PropTypes.string.isRequired,
334
+ uploadError: PropTypes.string.isRequired,
335
+ deleteProblem: PropTypes.string.isRequired,
336
+ tooManyFiles: PropTypes.string.isRequired,
337
+ fileTooSmall: PropTypes.string.isRequired,
338
+ fewFiles: PropTypes.string.isRequired
339
+ });
318
340
  FileUpload.propTypes = {
319
341
  ...selectedSystemPropTypes,
320
342
  tokens: getTokensPropType('FileUpload'),
@@ -358,6 +380,13 @@ FileUpload.propTypes = {
358
380
  /**
359
381
  * The minimum file size allowed for upload in MB.
360
382
  */
361
- minFileSize: PropTypes.number
383
+ minFileSize: PropTypes.number,
384
+ /**
385
+ * Custom dictionary containing the labels to use for the steps
386
+ */
387
+ dictionary: PropTypes.shape({
388
+ en: dictionaryEntryShape,
389
+ fr: dictionaryEntryShape
390
+ })
362
391
  };
363
392
  export default FileUpload;
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import PropTypes from 'prop-types';
2
3
  import { useThemeTokensCallback } from '../ThemeProvider';
3
4
  import LinkBase from './LinkBase';
4
5
  import { jsx as _jsx } from "react/jsx-runtime";
@@ -24,5 +25,11 @@ const Link = /*#__PURE__*/React.forwardRef((_ref, ref) => {
24
25
  });
25
26
  });
26
27
  Link.displayName = 'Link';
27
- Link.propTypes = LinkBase.propTypes;
28
+ Link.propTypes = {
29
+ ...LinkBase.propTypes,
30
+ /**
31
+ * The dataSet prop allows to pass data-* attributes element to the component.
32
+ */
33
+ dataSet: PropTypes.object
34
+ };
28
35
  export default Link;
@@ -136,6 +136,7 @@ const LinkBase = /*#__PURE__*/React.forwardRef((_ref6, ref) => {
136
136
  variant,
137
137
  tokens = {},
138
138
  children,
139
+ dataSet,
139
140
  accessibilityRole = 'link',
140
141
  ...rawRest
141
142
  } = _ref6;
@@ -170,6 +171,7 @@ const LinkBase = /*#__PURE__*/React.forwardRef((_ref6, ref) => {
170
171
  } = useTheme();
171
172
  return /*#__PURE__*/_jsx(InlinePressable, {
172
173
  ...selectedProps,
174
+ dataSet: dataSet,
173
175
  inlineFlex: hasIcon
174
176
  // assuming links without icons should be inline (even if they are long)
175
177
  ,
@@ -101,6 +101,7 @@ const MultiSelectFilter = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
101
101
  const [isOpen, setIsOpen] = React.useState(false);
102
102
  const [checkedIds, setCheckedIds] = React.useState(currentValues ?? []);
103
103
  const [maxWidth, setMaxWidth] = React.useState(false);
104
+ const isSelected = currentValues.length > 0;
104
105
  const {
105
106
  headerFontColor,
106
107
  headerFontSize,
@@ -133,7 +134,8 @@ const MultiSelectFilter = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
133
134
  } = useThemeTokens('MultiSelectFilter', tokens, {
134
135
  ...variant,
135
136
  maxHeight,
136
- maxWidth
137
+ maxWidth,
138
+ selected: isSelected
137
139
  }, {
138
140
  viewport
139
141
  });
@@ -161,7 +163,6 @@ const MultiSelectFilter = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
161
163
  const colSizeNotMobile = items.length > rowLimit ? 2 : 1;
162
164
  const colSize = viewport !== 'xs' ? colSizeNotMobile : 1;
163
165
  const itemsLengthNotMobile = items.length > 24 ? items.length / 2 : rowLimit;
164
- const isSelected = currentValues.length > 0;
165
166
  const rowLength = viewport !== 'xs' ? itemsLengthNotMobile : items.length;
166
167
  React.useEffect(() => {
167
168
  if (colSize === 1) return setMaxWidth(false);
@@ -4,10 +4,10 @@
4
4
  // Note that if a value of a field in an item is not set, it will be
5
5
  // excluded from comparison.
6
6
  const containUniqueFields = (items, fields) => {
7
- const map = [];
7
+ const map = new Map();
8
8
  const itemsHaveDuplicateFields = items.some(item => fields.some(field => {
9
- if (!map[field]) {
10
- map[field] = [];
9
+ if (!map.has(field)) {
10
+ map.set(field, new Map());
11
11
  }
12
12
  if (!item[field]) {
13
13
  // We exclude empty values from comparison
@@ -15,8 +15,8 @@ const containUniqueFields = (items, fields) => {
15
15
  }
16
16
 
17
17
  // Duplicate found!
18
- if (map[field][item[field]]) return true;
19
- map[field][item[field]] = true;
18
+ if (map.get(field).has(item[field])) return true;
19
+ map.get(field).set(item[field], true);
20
20
  return false;
21
21
  }));
22
22
  return !itemsHaveDuplicateFields;