@telus-uds/components-base 3.17.1 → 3.19.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 (44) hide show
  1. package/CHANGELOG.md +20 -4
  2. package/LICENSE +21 -0
  3. package/jest.config.cjs +10 -2
  4. package/lib/cjs/Box/Box.js +114 -62
  5. package/lib/cjs/Box/backgroundImageStylesMap.js +136 -28
  6. package/lib/cjs/Carousel/Carousel.js +1 -1
  7. package/lib/cjs/Modal/Modal.js +7 -1
  8. package/lib/cjs/Modal/ModalContent.js +6 -4
  9. package/lib/cjs/MultiSelectFilter/MultiSelectFilter.js +2 -2
  10. package/lib/cjs/StepTracker/Step.js +12 -1
  11. package/lib/cjs/StepTracker/StepTracker.js +15 -4
  12. package/lib/cjs/TabBar/TabBar.js +4 -2
  13. package/lib/cjs/TabBar/index.js +2 -0
  14. package/lib/cjs/Tooltip/Backdrop.js +1 -1
  15. package/lib/cjs/utils/index.js +9 -1
  16. package/lib/cjs/utils/isTouchDevice.js +34 -0
  17. package/lib/esm/Box/Box.js +113 -63
  18. package/lib/esm/Box/backgroundImageStylesMap.js +134 -27
  19. package/lib/esm/Carousel/Carousel.js +2 -2
  20. package/lib/esm/Modal/Modal.js +7 -1
  21. package/lib/esm/Modal/ModalContent.js +6 -4
  22. package/lib/esm/MultiSelectFilter/MultiSelectFilter.js +2 -2
  23. package/lib/esm/StepTracker/Step.js +12 -1
  24. package/lib/esm/StepTracker/StepTracker.js +15 -4
  25. package/lib/esm/TabBar/TabBar.js +4 -2
  26. package/lib/esm/TabBar/index.js +2 -0
  27. package/lib/esm/Tooltip/Backdrop.js +1 -1
  28. package/lib/esm/utils/index.js +2 -1
  29. package/lib/esm/utils/isTouchDevice.js +27 -0
  30. package/lib/package.json +2 -2
  31. package/package.json +2 -2
  32. package/src/Box/Box.jsx +97 -55
  33. package/src/Box/backgroundImageStylesMap.js +48 -15
  34. package/src/Carousel/Carousel.jsx +3 -2
  35. package/src/Modal/Modal.jsx +7 -1
  36. package/src/Modal/ModalContent.jsx +6 -3
  37. package/src/MultiSelectFilter/MultiSelectFilter.jsx +2 -2
  38. package/src/StepTracker/Step.jsx +47 -27
  39. package/src/StepTracker/StepTracker.jsx +9 -1
  40. package/src/TabBar/TabBar.jsx +3 -1
  41. package/src/TabBar/index.js +3 -0
  42. package/src/Tooltip/Backdrop.jsx +1 -1
  43. package/src/utils/index.js +1 -0
  44. package/src/utils/isTouchDevice.js +34 -0
package/CHANGELOG.md CHANGED
@@ -1,16 +1,32 @@
1
1
  # Change Log - @telus-uds/components-base
2
2
 
3
- This log was last generated on Fri, 12 Sep 2025 17:00:54 GMT and should not be manually modified.
3
+ This log was last generated on Fri, 03 Oct 2025 20:34:06 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
- ## 3.17.1
7
+ ## 3.19.0
8
8
 
9
- Fri, 12 Sep 2025 17:00:54 GMT
9
+ Fri, 03 Oct 2025 20:34:06 GMT
10
+
11
+ ### Minor changes
12
+
13
+ - `Carousel`: add swipe functionality to MD viewport (guillermo.peitzner@telus.com)
14
+ - `MultiSelectFilter`: add documentation for JSX usage in `subtitle` prop (oscar.palencia@telus.com)
15
+ - `StepTracker`: add style bar variant (guillermo.peitzner@telus.com)
16
+ - Bump @telus-uds/system-theme-tokens to v4.15.0
10
17
 
11
18
  ### Patches
12
19
 
13
- - `Card`: fix pressable-card text-decoration when href is present (guillermo.peitzner@telus.com)
20
+ - `TabBar`: fix item token management (guillermo.peitzner@telus.com)
21
+ - `Box`: fix background image contain position (guillermo.peitzner@telus.com)
22
+
23
+ ## 3.18.0
24
+
25
+ Tue, 16 Sep 2025 21:19:36 GMT
26
+
27
+ ### Minor changes
28
+
29
+ - `Modal`: add footer prop (guillermo.peitzner@telus.com)
14
30
 
15
31
  ## 3.13.0
16
32
 
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 TELUS
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/jest.config.cjs CHANGED
@@ -29,12 +29,20 @@ module.exports = {
29
29
  ],
30
30
  cacheDirectory: '.cache/jest-cache-react-17',
31
31
  moduleNameMapper: {
32
- '.+\\.(otf|svg|png|jpg)$': 'identity-obj-proxy'
32
+ '.+\\.(otf|svg|png|jpg)$': 'identity-obj-proxy',
33
+ '^@telus-uds/system-constants$': '<rootDir>/../system-constants/src',
34
+ '^@telus-uds/system-theme-tokens$': '<rootDir>/../system-theme-tokens/src'
33
35
  },
34
36
  testMatch: [`<rootDir>/__tests__/**/*.test.js?(x)`],
35
37
  transformIgnorePatterns: [
36
38
  'node_modules/(?!(jest-)?react-native|@react-native|@react-native-community|react-native-web|@react-native-picker)'
37
39
  ],
38
- // Count everything in src when calculating coverage
40
+ // Count everything in src when calculating coverage,
41
+ coveragePathIgnorePatterns: [
42
+ '/node_modules/',
43
+ '/packages/palette-allium/build/'
44
+ // '/@telus-uds/palette-allium',
45
+ // '/@telus-uds/palette-allium/build/rn/icons/, /@telus-uds/palette-allium/build/web/icons/'
46
+ ],
39
47
  collectCoverageFrom: ['src/**/*.{js,jsx}']
40
48
  }
@@ -14,9 +14,11 @@ var _ImageBackground = _interopRequireDefault(require("react-native-web/dist/cjs
14
14
  var _Image = _interopRequireDefault(require("react-native-web/dist/cjs/exports/Image"));
15
15
  var _ThemeProvider = require("../ThemeProvider");
16
16
  var _utils = require("../utils");
17
- var _backgroundImageStylesMap = _interopRequireDefault(require("./backgroundImageStylesMap"));
17
+ var _backgroundImageStylesMap = _interopRequireWildcard(require("./backgroundImageStylesMap"));
18
18
  var _ViewportProvider = require("../ViewportProvider");
19
19
  var _jsxRuntime = require("react/jsx-runtime");
20
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
21
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
20
22
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
21
23
  const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.viewProps]);
22
24
 
@@ -75,39 +77,51 @@ const setBackgroundImage = _ref2 => {
75
77
  backgroundImageResizeMode,
76
78
  backgroundImagePosition,
77
79
  backgroundImageAlign,
78
- backgroundImageWidth,
79
- backgroundImageHeight,
80
- content
80
+ content,
81
+ testID
81
82
  } = _ref2;
82
- if (backgroundImageResizeMode === 'contain') {
83
- const containedViewStyle = {
84
- ...staticStyles.containedView,
85
- width: backgroundImageWidth,
86
- height: backgroundImageHeight,
87
- ..._backgroundImageStylesMap.default[`${backgroundImagePosition}-${backgroundImageAlign}`]
88
- };
83
+ const backgroundImageTestID = testID ? `${testID}-background-image` : undefined;
84
+ if (backgroundImageResizeMode === 'contain' && backgroundImagePosition && backgroundImageAlign) {
85
+ const positionKey = `${backgroundImagePosition}-${backgroundImageAlign}`;
86
+ if (_Platform.default.OS === 'web') {
87
+ const backgroundPosition = _backgroundImageStylesMap.backgroundPositions[positionKey] || 'center center';
88
+ const backgroundImageStyle = {
89
+ backgroundImage: `url(${src})`,
90
+ backgroundSize: 'contain',
91
+ backgroundRepeat: 'no-repeat',
92
+ backgroundPosition
93
+ };
94
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
95
+ style: [staticStyles.imageBackground, backgroundImageStyle],
96
+ "aria-label": alt,
97
+ testID: backgroundImageTestID,
98
+ children: content
99
+ });
100
+ }
101
+ const positionStyles = _backgroundImageStylesMap.default[positionKey] || {};
89
102
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_View.default, {
90
- style: staticStyles.containedContainer,
91
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
92
- style: containedViewStyle,
93
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Image.default, {
94
- source: {
95
- uri: src
96
- },
97
- alt: alt,
98
- style: staticStyles.containedImage,
99
- accessibilityIgnoresInvertColors: true
100
- })
101
- }), content]
103
+ style: staticStyles.containContainer,
104
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Image.default, {
105
+ source: src,
106
+ resizeMode: backgroundImageResizeMode,
107
+ style: [staticStyles.containImage, positionStyles],
108
+ accessible: true,
109
+ accessibilityLabel: alt,
110
+ accessibilityIgnoresInvertColors: true,
111
+ testID: backgroundImageTestID
112
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
113
+ style: staticStyles.contentOverlay,
114
+ children: content
115
+ })]
102
116
  });
103
117
  }
104
118
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ImageBackground.default, {
105
- source: {
106
- uri: src
107
- },
108
- alt: alt,
109
- style: staticStyles.backgroundImageContainer,
119
+ source: src,
110
120
  resizeMode: backgroundImageResizeMode,
121
+ style: staticStyles.imageBackground,
122
+ accessible: true,
123
+ accessibilityLabel: alt,
124
+ testID: backgroundImageTestID,
111
125
  children: content
112
126
  });
113
127
  };
@@ -264,31 +278,61 @@ const Box = /*#__PURE__*/_react.default.forwardRef((_ref3, ref) => {
264
278
  align = ''
265
279
  } = backgroundImage || {};
266
280
  const backgroundImageResizeMode = (0, _utils.useResponsiveProp)(resizeMode, 'cover');
267
- const backgroundImagePosition = (0, _utils.useResponsiveProp)(position, 'none');
268
- const backgroundImageAlign = (0, _utils.useResponsiveProp)(align, 'stretch');
269
- const [backgroundImageWidth, setBackgroundImageWidth] = _react.default.useState(0);
270
- const [backgroundImageHeight, setBackgroundImageHeight] = _react.default.useState(0);
271
- if (backgroundImage) content = setBackgroundImage({
272
- src,
273
- alt,
274
- backgroundImageResizeMode,
275
- backgroundImagePosition,
276
- backgroundImageAlign,
277
- backgroundImageWidth,
278
- backgroundImageHeight,
279
- content
280
- });
281
- _react.default.useEffect(() => {
282
- if (backgroundImage && backgroundImageWidth === 0 && backgroundImageHeight === 0) {
283
- _Image.default.getSize(src, (width, height) => {
284
- // Only update the state if the size has changed
285
- if (width !== backgroundImageWidth || height !== backgroundImageHeight) {
286
- setBackgroundImageWidth(width);
287
- setBackgroundImageHeight(height);
288
- }
281
+ const backgroundImagePosition = (0, _utils.useResponsiveProp)(position);
282
+ const backgroundImageAlign = (0, _utils.useResponsiveProp)(align);
283
+ const imageSourceViewport = (0, _utils.formatImageSource)((0, _utils.useResponsiveProp)(src));
284
+ if (backgroundImage && src) {
285
+ const {
286
+ paddingTop,
287
+ paddingBottom,
288
+ paddingLeft,
289
+ paddingRight,
290
+ ...containerStyle
291
+ } = boxStyles;
292
+ const hasPadding = paddingTop || paddingBottom || paddingLeft || paddingRight;
293
+ const paddedContent = hasPadding ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
294
+ style: {
295
+ paddingTop,
296
+ paddingBottom,
297
+ paddingLeft,
298
+ paddingRight
299
+ },
300
+ children: children
301
+ }) : children;
302
+ content = setBackgroundImage({
303
+ src: imageSourceViewport,
304
+ alt,
305
+ backgroundImageResizeMode,
306
+ backgroundImagePosition,
307
+ backgroundImageAlign,
308
+ content: paddedContent,
309
+ testID
310
+ });
311
+ const dataSetValue = boxMediaIds ? {
312
+ media: boxMediaIds,
313
+ ...dataSet
314
+ } : dataSet;
315
+ if (scroll) {
316
+ const scrollProps = typeof scroll === 'object' ? scroll : {};
317
+ scrollProps.contentContainerStyle = [containerStyle, scrollProps.contentContainerStyle];
318
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ScrollView.default, {
319
+ ...scrollProps,
320
+ ...props,
321
+ testID: testID,
322
+ dataSet: dataSetValue,
323
+ ref: ref,
324
+ children: content
289
325
  });
290
326
  }
291
- }, [backgroundImage, backgroundImageWidth, backgroundImageHeight, src]);
327
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
328
+ ...props,
329
+ style: containerStyle,
330
+ testID: testID,
331
+ dataSet: dataSetValue,
332
+ ref: ref,
333
+ children: content
334
+ });
335
+ }
292
336
  const dataSetValue = boxMediaIds ? {
293
337
  media: boxMediaIds,
294
338
  ...dataSet
@@ -401,10 +445,12 @@ Box.propTypes = {
401
445
  */
402
446
  customGradient: _propTypes.default.func,
403
447
  /**
404
- * Use this prop to add a background image to the box.
448
+ * Apply background image to the box.
405
449
  */
406
450
  backgroundImage: _propTypes.default.shape({
407
- src: _propTypes.default.string.isRequired,
451
+ // The image src is either a URI string or a number (when a local image src is bundled in IOS or Android app)
452
+ // src is an object when used responsively to provide different image sources for different screen sizes
453
+ src: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number, _propTypes.default.object]).isRequired,
408
454
  alt: _propTypes.default.string,
409
455
  resizeMode: _utils.responsiveProps.getTypeOptionallyByViewport(_propTypes.default.oneOf(['cover', 'contain', 'stretch', 'repeat', 'center'])),
410
456
  position: _utils.responsiveProps.getTypeOptionallyByViewport(_propTypes.default.oneOf(['none', 'bottom', 'left', 'right', 'top'])),
@@ -413,18 +459,24 @@ Box.propTypes = {
413
459
  };
414
460
  var _default = exports.default = Box;
415
461
  const staticStyles = _StyleSheet.default.create({
416
- backgroundImageContainer: {
417
- flex: 1
462
+ imageBackground: {
463
+ width: '100%',
464
+ height: '100%'
418
465
  },
419
- containedContainer: {
420
- flex: 1,
421
- overflow: 'hidden'
466
+ contentOverlay: {
467
+ position: 'relative',
468
+ width: '100%',
469
+ height: '100%',
470
+ zIndex: 1
422
471
  },
423
- containedView: {
424
- zIndex: -1,
425
- position: 'absolute'
472
+ containContainer: {
473
+ width: '100%',
474
+ height: '100%',
475
+ overflow: 'hidden',
476
+ position: 'relative'
426
477
  },
427
- containedImage: {
478
+ containImage: {
479
+ position: 'absolute',
428
480
  width: '100%',
429
481
  height: '100%'
430
482
  }
@@ -3,15 +3,20 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = void 0;
7
- var _default = exports.default = {
6
+ exports.default = exports.backgroundPositions = void 0;
7
+ var _Platform = _interopRequireDefault(require("react-native-web/dist/cjs/exports/Platform"));
8
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
+ const webStyles = {
8
10
  'top-start': {
9
- top: 0
11
+ top: 0,
12
+ left: 0
10
13
  },
11
14
  'top-center': {
12
- left: 0,
13
- right: 0,
14
- marginHorizontal: 'auto'
15
+ top: 0,
16
+ left: '50%',
17
+ transform: [{
18
+ translateX: '-50%'
19
+ }]
15
20
  },
16
21
  'top-end': {
17
22
  top: 0,
@@ -22,60 +27,160 @@ var _default = exports.default = {
22
27
  right: 0
23
28
  },
24
29
  'left-start': {
25
- top: 0
30
+ top: 0,
31
+ left: 0
26
32
  },
27
33
  'left-center': {
28
- top: 0,
34
+ top: '50%',
35
+ left: 0,
36
+ transform: [{
37
+ translateY: '-50%'
38
+ }]
39
+ },
40
+ 'right-center': {
41
+ top: '50%',
42
+ right: 0,
43
+ transform: [{
44
+ translateY: '-50%'
45
+ }]
46
+ },
47
+ 'bottom-start': {
48
+ bottom: 0,
49
+ left: 0
50
+ },
51
+ 'left-end': {
52
+ bottom: 0,
53
+ left: 0
54
+ },
55
+ 'bottom-center': {
56
+ bottom: 0,
57
+ left: '50%',
58
+ transform: [{
59
+ translateX: '-50%'
60
+ }]
61
+ },
62
+ 'bottom-end': {
29
63
  bottom: 0,
30
- marginVertical: 'auto'
64
+ right: 0
65
+ },
66
+ 'right-end': {
67
+ bottom: 0,
68
+ right: 0
31
69
  },
32
- 'none-start': {
70
+ 'top-stretch': {
71
+ top: 0,
72
+ left: 0,
73
+ right: 0,
74
+ width: '100%'
75
+ },
76
+ 'left-stretch': {
33
77
  top: 0,
34
78
  bottom: 0,
35
- marginVertical: 'auto'
79
+ left: 0,
80
+ height: '100%'
36
81
  },
37
- 'none-center': {
82
+ 'right-stretch': {
38
83
  top: 0,
84
+ bottom: 0,
85
+ right: 0,
86
+ height: '100%'
87
+ },
88
+ 'bottom-stretch': {
39
89
  bottom: 0,
40
90
  left: 0,
41
91
  right: 0,
42
- margin: 'auto'
92
+ width: '100%'
93
+ }
94
+ };
95
+ const webBackgroundPositions = {
96
+ 'top-start': 'left top',
97
+ 'top-center': 'center top',
98
+ 'top-end': 'right top',
99
+ 'bottom-start': 'left bottom',
100
+ 'bottom-center': 'center bottom',
101
+ 'bottom-end': 'right bottom',
102
+ 'left-center': 'left center',
103
+ 'right-center': 'right center'
104
+ };
105
+ const nativeStyles = {
106
+ 'top-start': {
107
+ top: 0,
108
+ left: 0,
109
+ width: 150,
110
+ height: 200
43
111
  },
44
- 'right-center': {
112
+ 'top-center': {
113
+ top: 0,
114
+ left: '50%',
115
+ marginLeft: -75,
116
+ width: 150,
117
+ height: 200
118
+ },
119
+ 'top-end': {
45
120
  top: 0,
46
- bottom: 0,
47
121
  right: 0,
48
- marginVertical: 'auto'
122
+ width: 150,
123
+ height: 200
49
124
  },
50
- 'none-end': {
125
+ 'right-start': {
51
126
  top: 0,
52
- bottom: 0,
53
127
  right: 0,
54
- marginVertical: 'auto'
128
+ width: 150,
129
+ height: 200
130
+ },
131
+ 'left-start': {
132
+ top: 0,
133
+ left: 0,
134
+ width: 150,
135
+ height: 200
136
+ },
137
+ 'left-center': {
138
+ left: 0,
139
+ top: '50%',
140
+ marginTop: -100,
141
+ width: 150,
142
+ height: 200
143
+ },
144
+ 'right-center': {
145
+ right: 0,
146
+ top: '50%',
147
+ marginTop: -100,
148
+ width: 150,
149
+ height: 200
55
150
  },
56
151
  'bottom-start': {
57
152
  bottom: 0,
58
- left: 0
153
+ left: 0,
154
+ width: 150,
155
+ height: 200
59
156
  },
60
157
  'left-end': {
61
158
  bottom: 0,
62
- left: 0
159
+ left: 0,
160
+ width: 150,
161
+ height: 200
63
162
  },
64
163
  'bottom-center': {
65
- left: 0,
66
- right: 0,
67
164
  bottom: 0,
68
- marginHorizontal: 'auto'
165
+ left: '50%',
166
+ marginLeft: -75,
167
+ width: 150,
168
+ height: 200
69
169
  },
70
170
  'bottom-end': {
171
+ bottom: 0,
71
172
  right: 0,
72
- bottom: 0
173
+ width: 150,
174
+ height: 200
73
175
  },
74
176
  'right-end': {
177
+ bottom: 0,
75
178
  right: 0,
76
- bottom: 0
179
+ width: 150,
180
+ height: 200
77
181
  },
78
182
  'top-stretch': {
183
+ top: 0,
79
184
  left: 0,
80
185
  right: 0,
81
186
  width: '100%'
@@ -83,6 +188,7 @@ var _default = exports.default = {
83
188
  'left-stretch': {
84
189
  top: 0,
85
190
  bottom: 0,
191
+ left: 0,
86
192
  height: '100%'
87
193
  },
88
194
  'right-stretch': {
@@ -92,9 +198,11 @@ var _default = exports.default = {
92
198
  height: '100%'
93
199
  },
94
200
  'bottom-stretch': {
201
+ bottom: 0,
95
202
  left: 0,
96
203
  right: 0,
97
- bottom: 0,
98
204
  width: '100%'
99
205
  }
100
- };
206
+ };
207
+ const backgroundPositions = exports.backgroundPositions = _Platform.default.OS === 'web' ? webBackgroundPositions : {};
208
+ var _default = exports.default = _Platform.default.OS === 'web' ? webStyles : nativeStyles;
@@ -724,7 +724,7 @@ const Carousel = /*#__PURE__*/_react.default.forwardRef((_ref3, ref) => {
724
724
  return false;
725
725
  }
726
726
  if (_Platform.default.OS === 'web') {
727
- return !!(viewport === 'xs' || viewport === 'sm');
727
+ return !!(viewport === 'xs' || viewport === 'sm' || viewport === 'md' && (0, _utils.isTouchDevice)());
728
728
  }
729
729
  return true;
730
730
  }, [viewport, totalItems]);
@@ -127,6 +127,7 @@ const Modal = /*#__PURE__*/_react.default.forwardRef((_ref5, ref) => {
127
127
  confirmButtonVariant,
128
128
  cancelButtonText,
129
129
  cancelButtonType,
130
+ footer,
130
131
  ...rest
131
132
  } = _ref5;
132
133
  const viewport = (0, _ViewportProvider.useViewport)();
@@ -230,6 +231,7 @@ const Modal = /*#__PURE__*/_react.default.forwardRef((_ref5, ref) => {
230
231
  confirmButtonVariant: confirmButtonVariant,
231
232
  cancelButtonText: cancelButtonText,
232
233
  cancelButtonType: cancelButtonType,
234
+ footer: footer,
233
235
  children: _Platform.default.OS !== 'web' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_ScrollView.default, {
234
236
  style: selectScrollViewStyles,
235
237
  children: children
@@ -330,7 +332,11 @@ Modal.propTypes = {
330
332
  /**
331
333
  * Receive a function for the onCancel event in the cancel button.
332
334
  */
333
- onCancel: _propTypes.default.func
335
+ onCancel: _propTypes.default.func,
336
+ /**
337
+ * Receive a react node or an array of nodes to render at the bottom of the modal, above the action buttons.
338
+ */
339
+ footer: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.arrayOf(_propTypes.default.node)])
334
340
  };
335
341
  var _default = exports.default = Modal;
336
342
  const staticStyles = _StyleSheet.default.create({
@@ -35,7 +35,8 @@ const ModalContent = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
35
35
  cancelButtonText,
36
36
  cancelButtonType: CancelButton = _Link.TextButton,
37
37
  children,
38
- onCancel
38
+ onCancel,
39
+ footer
39
40
  } = _ref;
40
41
  const viewport = (0, _ViewportProvider.useViewport)();
41
42
  const {
@@ -149,7 +150,7 @@ const ModalContent = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
149
150
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Typography.default, {
150
151
  children: bodyText
151
152
  })
152
- }), children, (hasConfirmButton || hasCancelButton) && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_View.default, {
153
+ }), children, (hasConfirmButton || hasCancelButton) && !footer && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_View.default, {
153
154
  style: [selectFooterContainerStyles({
154
155
  ...themeTokens,
155
156
  hasBorder: isContentOverflowing
@@ -171,7 +172,7 @@ const ModalContent = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
171
172
  children: cancelButtonText
172
173
  })
173
174
  }) : null]
174
- })]
175
+ }), footer]
175
176
  });
176
177
  });
177
178
  ModalContent.displayName = 'ModalContent';
@@ -200,6 +201,7 @@ ModalContent.propTypes = {
200
201
  cancelButtonType: _propTypes.default.elementType,
201
202
  // TODO: figure out a way of passing an icon to the TextButton
202
203
  children: _propTypes.default.node,
203
- onCancel: _propTypes.default.func
204
+ onCancel: _propTypes.default.func,
205
+ footer: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.arrayOf(_propTypes.default.node)])
204
206
  };
205
207
  var _default = exports.default = ModalContent;
@@ -489,9 +489,9 @@ MultiSelectFilter.propTypes = {
489
489
  */
490
490
  label: _propTypes.default.string.isRequired,
491
491
  /**
492
- * The text for the subtitle
492
+ * The text for the subtitle. Can also be JSX.
493
493
  */
494
- subtitle: _propTypes.default.string,
494
+ subtitle: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.node]),
495
495
  /**
496
496
  * An optional unique string may be provided to identify the ButtonDropdown.
497
497
  * If not provided, the label is used.
@@ -157,6 +157,13 @@ const getStepTestID = (isCompleted, isCurrent) => {
157
157
  }
158
158
  return testID;
159
159
  };
160
+ const selectBarContainerStyles = (themeTokens, isCompleted, isCurrent) => ({
161
+ backgroundColor: isCompleted ? themeTokens.barCompletedBackgroundColor : themeTokens.barBackgroundColor,
162
+ height: themeTokens.barHeight,
163
+ ...(isCurrent && {
164
+ backgroundColor: themeTokens.barCurrentBackgroundColor
165
+ })
166
+ });
160
167
 
161
168
  /**
162
169
  * A single step of a StepTracker.
@@ -169,6 +176,7 @@ const Step = /*#__PURE__*/_react.default.forwardRef((_ref8, ref) => {
169
176
  stepCount = 0,
170
177
  stepIndex = 0,
171
178
  tokens,
179
+ isBarVariant,
172
180
  ...rest
173
181
  } = _ref8;
174
182
  const {
@@ -197,7 +205,10 @@ const Step = /*#__PURE__*/_react.default.forwardRef((_ref8, ref) => {
197
205
  accessibilityCurrent: status === stepIndex,
198
206
  ref: ref,
199
207
  ...selectProps(rest),
200
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_StackView.default, {
208
+ children: [isBarVariant && /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
209
+ style: selectBarContainerStyles(themeTokens, isCompleted, isCurrent),
210
+ testID: getStepTestID(isCompleted, isCurrent)
211
+ }), !isBarVariant && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_StackView.default, {
201
212
  direction: "row",
202
213
  space: 0,
203
214
  tokens: {