@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
@@ -19,6 +19,7 @@ var _Step = _interopRequireDefault(require("./Step"));
19
19
  var _dictionary = _interopRequireDefault(require("./dictionary"));
20
20
  var _jsxRuntime = require("react/jsx-runtime");
21
21
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
22
+ const STYLE_BAR_VARIANT = 'bar';
22
23
  const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.viewProps]);
23
24
  const selectContainerStyles = _ref => {
24
25
  let {
@@ -59,6 +60,14 @@ const selectStepTrackerLabelStyles = (_ref3, themeOptions) => {
59
60
  themeOptions
60
61
  });
61
62
  };
63
+ const selectStepsContainerStyles = _ref4 => {
64
+ let {
65
+ barGap
66
+ } = _ref4;
67
+ return {
68
+ gap: barGap
69
+ };
70
+ };
62
71
 
63
72
  /**
64
73
  * StepTracker component shows the current position in a sequence of steps.
@@ -92,7 +101,7 @@ const selectStepTrackerLabelStyles = (_ref3, themeOptions) => {
92
101
  * - `accessibilityValue.text` (`aria-valuetext`): `<Current Step Label>`,
93
102
  *
94
103
  */
95
- const StepTracker = /*#__PURE__*/_react.default.forwardRef((_ref4, ref) => {
104
+ const StepTracker = /*#__PURE__*/_react.default.forwardRef((_ref5, ref) => {
96
105
  let {
97
106
  current = 0,
98
107
  copy = 'en',
@@ -101,7 +110,8 @@ const StepTracker = /*#__PURE__*/_react.default.forwardRef((_ref4, ref) => {
101
110
  tokens,
102
111
  variant,
103
112
  ...rest
104
- } = _ref4;
113
+ } = _ref5;
114
+ const isBarVariant = variant?.style === STYLE_BAR_VARIANT;
105
115
  const viewport = (0, _ViewportProvider.useViewport)();
106
116
  const {
107
117
  showStepTrackerLabel,
@@ -147,7 +157,7 @@ const StepTracker = /*#__PURE__*/_react.default.forwardRef((_ref4, ref) => {
147
157
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_StackView.default, {
148
158
  space: 0,
149
159
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
150
- style: staticStyles.stepsContainer,
160
+ style: [staticStyles.stepsContainer, selectStepsContainerStyles(themeTokens)],
151
161
  accessibilityRole: stepsContainerAccessibilityRole,
152
162
  children: steps.map((label, index) => {
153
163
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Step.default, {
@@ -158,7 +168,8 @@ const StepTracker = /*#__PURE__*/_react.default.forwardRef((_ref4, ref) => {
158
168
  stepCount: steps.length,
159
169
  tokens: themeTokens,
160
170
  accessibilityRole: stepAccessibilityRole,
161
- accessibilityCurrent: current === index && _Platform.default.OS === 'web' && 'step'
171
+ accessibilityCurrent: current === index && _Platform.default.OS === 'web' && 'step',
172
+ isBarVariant: isBarVariant
162
173
  }, label);
163
174
  })
164
175
  }), showStepTrackerLabel && /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
@@ -91,7 +91,8 @@ const TabBar = /*#__PURE__*/_react.default.forwardRef((_ref3, ref) => {
91
91
  iconActive: item.iconActive,
92
92
  onPress: () => handlePress(item.id),
93
93
  id: `tab-item-${index}`,
94
- accessibilityRole: "tablist"
94
+ accessibilityRole: "tablist",
95
+ tokens: item.tokens
95
96
  }, item.id))
96
97
  })
97
98
  });
@@ -105,7 +106,8 @@ TabBar.propTypes = {
105
106
  icon: _propTypes.default.node,
106
107
  iconActive: _propTypes.default.node,
107
108
  label: _propTypes.default.string.isRequired,
108
- href: _propTypes.default.string
109
+ href: _propTypes.default.string,
110
+ tokens: (0, _utils.getTokensPropType)('TabBarItem')
109
111
  })).isRequired,
110
112
  /** Id of the initially selected item. */
111
113
  initiallySelectedItem: _propTypes.default.number,
@@ -5,5 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _TabBar = _interopRequireDefault(require("./TabBar"));
8
+ var _TabBarItem = _interopRequireDefault(require("./TabBarItem"));
8
9
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
+ _TabBar.default.Item = _TabBarItem.default;
9
11
  var _default = exports.default = _TabBar.default;
@@ -21,7 +21,7 @@ function createPortalNode(nodeId) {
21
21
  left: ${window.scrollX}px;
22
22
  right: 0;
23
23
  bottom: 0;
24
- z-index: 9999;
24
+ z-index: 100000;
25
25
  pointer-events: none;
26
26
  `;
27
27
  document.body.appendChild(node);
@@ -21,7 +21,8 @@ var _exportNames = {
21
21
  convertFromMegaByteToByte: true,
22
22
  formatImageSource: true,
23
23
  getSpacingScale: true,
24
- useVariants: true
24
+ useVariants: true,
25
+ isTouchDevice: true
25
26
  };
26
27
  Object.defineProperty(exports, "BaseView", {
27
28
  enumerable: true,
@@ -65,6 +66,12 @@ Object.defineProperty(exports, "info", {
65
66
  return _info.default;
66
67
  }
67
68
  });
69
+ Object.defineProperty(exports, "isTouchDevice", {
70
+ enumerable: true,
71
+ get: function () {
72
+ return _isTouchDevice.default;
73
+ }
74
+ });
68
75
  Object.defineProperty(exports, "transformGradient", {
69
76
  enumerable: true,
70
77
  get: function () {
@@ -256,6 +263,7 @@ var _convertFromMegaByteToByte = _interopRequireDefault(require("./convertFromMe
256
263
  var _formatImageSource = _interopRequireDefault(require("./formatImageSource"));
257
264
  var _getSpacingScale = _interopRequireDefault(require("./getSpacingScale"));
258
265
  var _useVariants = _interopRequireDefault(require("./useVariants"));
266
+ var _isTouchDevice = _interopRequireDefault(require("./isTouchDevice"));
259
267
  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); }
260
268
  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; }
261
269
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = 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
+ /**
10
+ * Determines if the current device supports touch interactions
11
+ *
12
+ * @returns {boolean} True if the device supports touch, false otherwise
13
+ */
14
+ const isTouchDevice = () => {
15
+ if (_Platform.default.OS !== 'web') {
16
+ return true;
17
+ }
18
+ if (typeof window !== 'undefined') {
19
+ if ('ontouchstart' in window) {
20
+ return true;
21
+ }
22
+ if (window.navigator && window.navigator.maxTouchPoints > 0) {
23
+ return true;
24
+ }
25
+ if (window.navigator && window.navigator.msMaxTouchPoints > 0) {
26
+ return true;
27
+ }
28
+ if (window.matchMedia && window.matchMedia('(pointer: coarse)').matches) {
29
+ return true;
30
+ }
31
+ }
32
+ return false;
33
+ };
34
+ var _default = exports.default = isTouchDevice;
@@ -7,8 +7,8 @@ import StyleSheet from "react-native-web/dist/exports/StyleSheet";
7
7
  import ImageBackground from "react-native-web/dist/exports/ImageBackground";
8
8
  import Image from "react-native-web/dist/exports/Image";
9
9
  import { useTheme, useThemeTokens, useResponsiveThemeTokens, useThemeTokensCallback } from '../ThemeProvider';
10
- import { a11yProps, createMediaQueryStyles, getA11yPropsFromHtmlTag, getTokensPropType, layoutTags, responsiveProps, selectSystemProps, spacingProps, useResponsiveProp, useSpacingScale, variantProp, viewProps, StyleSheet as RNMQStyleSheet, getSpacingScale } from '../utils';
11
- import backgroundImageStylesMap from './backgroundImageStylesMap';
10
+ import { a11yProps, createMediaQueryStyles, getA11yPropsFromHtmlTag, getTokensPropType, layoutTags, responsiveProps, selectSystemProps, spacingProps, useResponsiveProp, useSpacingScale, variantProp, viewProps, StyleSheet as RNMQStyleSheet, getSpacingScale, formatImageSource } from '../utils';
11
+ import backgroundImageStylesMap, { backgroundPositions } from './backgroundImageStylesMap';
12
12
  import { useViewport } from '../ViewportProvider';
13
13
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
14
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
@@ -68,39 +68,51 @@ const setBackgroundImage = _ref2 => {
68
68
  backgroundImageResizeMode,
69
69
  backgroundImagePosition,
70
70
  backgroundImageAlign,
71
- backgroundImageWidth,
72
- backgroundImageHeight,
73
- content
71
+ content,
72
+ testID
74
73
  } = _ref2;
75
- if (backgroundImageResizeMode === 'contain') {
76
- const containedViewStyle = {
77
- ...staticStyles.containedView,
78
- width: backgroundImageWidth,
79
- height: backgroundImageHeight,
80
- ...backgroundImageStylesMap[`${backgroundImagePosition}-${backgroundImageAlign}`]
81
- };
74
+ const backgroundImageTestID = testID ? `${testID}-background-image` : undefined;
75
+ if (backgroundImageResizeMode === 'contain' && backgroundImagePosition && backgroundImageAlign) {
76
+ const positionKey = `${backgroundImagePosition}-${backgroundImageAlign}`;
77
+ if (Platform.OS === 'web') {
78
+ const backgroundPosition = backgroundPositions[positionKey] || 'center center';
79
+ const backgroundImageStyle = {
80
+ backgroundImage: `url(${src})`,
81
+ backgroundSize: 'contain',
82
+ backgroundRepeat: 'no-repeat',
83
+ backgroundPosition
84
+ };
85
+ return /*#__PURE__*/_jsx(View, {
86
+ style: [staticStyles.imageBackground, backgroundImageStyle],
87
+ "aria-label": alt,
88
+ testID: backgroundImageTestID,
89
+ children: content
90
+ });
91
+ }
92
+ const positionStyles = backgroundImageStylesMap[positionKey] || {};
82
93
  return /*#__PURE__*/_jsxs(View, {
83
- style: staticStyles.containedContainer,
84
- children: [/*#__PURE__*/_jsx(View, {
85
- style: containedViewStyle,
86
- children: /*#__PURE__*/_jsx(Image, {
87
- source: {
88
- uri: src
89
- },
90
- alt: alt,
91
- style: staticStyles.containedImage,
92
- accessibilityIgnoresInvertColors: true
93
- })
94
- }), content]
94
+ style: staticStyles.containContainer,
95
+ children: [/*#__PURE__*/_jsx(Image, {
96
+ source: src,
97
+ resizeMode: backgroundImageResizeMode,
98
+ style: [staticStyles.containImage, positionStyles],
99
+ accessible: true,
100
+ accessibilityLabel: alt,
101
+ accessibilityIgnoresInvertColors: true,
102
+ testID: backgroundImageTestID
103
+ }), /*#__PURE__*/_jsx(View, {
104
+ style: staticStyles.contentOverlay,
105
+ children: content
106
+ })]
95
107
  });
96
108
  }
97
109
  return /*#__PURE__*/_jsx(ImageBackground, {
98
- source: {
99
- uri: src
100
- },
101
- alt: alt,
102
- style: staticStyles.backgroundImageContainer,
110
+ source: src,
103
111
  resizeMode: backgroundImageResizeMode,
112
+ style: staticStyles.imageBackground,
113
+ accessible: true,
114
+ accessibilityLabel: alt,
115
+ testID: backgroundImageTestID,
104
116
  children: content
105
117
  });
106
118
  };
@@ -257,31 +269,61 @@ const Box = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
257
269
  align = ''
258
270
  } = backgroundImage || {};
259
271
  const backgroundImageResizeMode = useResponsiveProp(resizeMode, 'cover');
260
- const backgroundImagePosition = useResponsiveProp(position, 'none');
261
- const backgroundImageAlign = useResponsiveProp(align, 'stretch');
262
- const [backgroundImageWidth, setBackgroundImageWidth] = React.useState(0);
263
- const [backgroundImageHeight, setBackgroundImageHeight] = React.useState(0);
264
- if (backgroundImage) content = setBackgroundImage({
265
- src,
266
- alt,
267
- backgroundImageResizeMode,
268
- backgroundImagePosition,
269
- backgroundImageAlign,
270
- backgroundImageWidth,
271
- backgroundImageHeight,
272
- content
273
- });
274
- React.useEffect(() => {
275
- if (backgroundImage && backgroundImageWidth === 0 && backgroundImageHeight === 0) {
276
- Image.getSize(src, (width, height) => {
277
- // Only update the state if the size has changed
278
- if (width !== backgroundImageWidth || height !== backgroundImageHeight) {
279
- setBackgroundImageWidth(width);
280
- setBackgroundImageHeight(height);
281
- }
272
+ const backgroundImagePosition = useResponsiveProp(position);
273
+ const backgroundImageAlign = useResponsiveProp(align);
274
+ const imageSourceViewport = formatImageSource(useResponsiveProp(src));
275
+ if (backgroundImage && src) {
276
+ const {
277
+ paddingTop,
278
+ paddingBottom,
279
+ paddingLeft,
280
+ paddingRight,
281
+ ...containerStyle
282
+ } = boxStyles;
283
+ const hasPadding = paddingTop || paddingBottom || paddingLeft || paddingRight;
284
+ const paddedContent = hasPadding ? /*#__PURE__*/_jsx(View, {
285
+ style: {
286
+ paddingTop,
287
+ paddingBottom,
288
+ paddingLeft,
289
+ paddingRight
290
+ },
291
+ children: children
292
+ }) : children;
293
+ content = setBackgroundImage({
294
+ src: imageSourceViewport,
295
+ alt,
296
+ backgroundImageResizeMode,
297
+ backgroundImagePosition,
298
+ backgroundImageAlign,
299
+ content: paddedContent,
300
+ testID
301
+ });
302
+ const dataSetValue = boxMediaIds ? {
303
+ media: boxMediaIds,
304
+ ...dataSet
305
+ } : dataSet;
306
+ if (scroll) {
307
+ const scrollProps = typeof scroll === 'object' ? scroll : {};
308
+ scrollProps.contentContainerStyle = [containerStyle, scrollProps.contentContainerStyle];
309
+ return /*#__PURE__*/_jsx(ScrollView, {
310
+ ...scrollProps,
311
+ ...props,
312
+ testID: testID,
313
+ dataSet: dataSetValue,
314
+ ref: ref,
315
+ children: content
282
316
  });
283
317
  }
284
- }, [backgroundImage, backgroundImageWidth, backgroundImageHeight, src]);
318
+ return /*#__PURE__*/_jsx(View, {
319
+ ...props,
320
+ style: containerStyle,
321
+ testID: testID,
322
+ dataSet: dataSetValue,
323
+ ref: ref,
324
+ children: content
325
+ });
326
+ }
285
327
  const dataSetValue = boxMediaIds ? {
286
328
  media: boxMediaIds,
287
329
  ...dataSet
@@ -394,10 +436,12 @@ Box.propTypes = {
394
436
  */
395
437
  customGradient: PropTypes.func,
396
438
  /**
397
- * Use this prop to add a background image to the box.
439
+ * Apply background image to the box.
398
440
  */
399
441
  backgroundImage: PropTypes.shape({
400
- src: PropTypes.string.isRequired,
442
+ // The image src is either a URI string or a number (when a local image src is bundled in IOS or Android app)
443
+ // src is an object when used responsively to provide different image sources for different screen sizes
444
+ src: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.object]).isRequired,
401
445
  alt: PropTypes.string,
402
446
  resizeMode: responsiveProps.getTypeOptionallyByViewport(PropTypes.oneOf(['cover', 'contain', 'stretch', 'repeat', 'center'])),
403
447
  position: responsiveProps.getTypeOptionallyByViewport(PropTypes.oneOf(['none', 'bottom', 'left', 'right', 'top'])),
@@ -406,18 +450,24 @@ Box.propTypes = {
406
450
  };
407
451
  export default Box;
408
452
  const staticStyles = StyleSheet.create({
409
- backgroundImageContainer: {
410
- flex: 1
453
+ imageBackground: {
454
+ width: '100%',
455
+ height: '100%'
411
456
  },
412
- containedContainer: {
413
- flex: 1,
414
- overflow: 'hidden'
457
+ contentOverlay: {
458
+ position: 'relative',
459
+ width: '100%',
460
+ height: '100%',
461
+ zIndex: 1
415
462
  },
416
- containedView: {
417
- zIndex: -1,
418
- position: 'absolute'
463
+ containContainer: {
464
+ width: '100%',
465
+ height: '100%',
466
+ overflow: 'hidden',
467
+ position: 'relative'
419
468
  },
420
- containedImage: {
469
+ containImage: {
470
+ position: 'absolute',
421
471
  width: '100%',
422
472
  height: '100%'
423
473
  }
@@ -1,11 +1,15 @@
1
- export default {
1
+ import Platform from "react-native-web/dist/exports/Platform";
2
+ const webStyles = {
2
3
  'top-start': {
3
- top: 0
4
+ top: 0,
5
+ left: 0
4
6
  },
5
7
  'top-center': {
6
- left: 0,
7
- right: 0,
8
- marginHorizontal: 'auto'
8
+ top: 0,
9
+ left: '50%',
10
+ transform: [{
11
+ translateX: '-50%'
12
+ }]
9
13
  },
10
14
  'top-end': {
11
15
  top: 0,
@@ -16,60 +20,160 @@ export default {
16
20
  right: 0
17
21
  },
18
22
  'left-start': {
19
- top: 0
23
+ top: 0,
24
+ left: 0
20
25
  },
21
26
  'left-center': {
22
- top: 0,
27
+ top: '50%',
28
+ left: 0,
29
+ transform: [{
30
+ translateY: '-50%'
31
+ }]
32
+ },
33
+ 'right-center': {
34
+ top: '50%',
35
+ right: 0,
36
+ transform: [{
37
+ translateY: '-50%'
38
+ }]
39
+ },
40
+ 'bottom-start': {
41
+ bottom: 0,
42
+ left: 0
43
+ },
44
+ 'left-end': {
45
+ bottom: 0,
46
+ left: 0
47
+ },
48
+ 'bottom-center': {
49
+ bottom: 0,
50
+ left: '50%',
51
+ transform: [{
52
+ translateX: '-50%'
53
+ }]
54
+ },
55
+ 'bottom-end': {
23
56
  bottom: 0,
24
- marginVertical: 'auto'
57
+ right: 0
58
+ },
59
+ 'right-end': {
60
+ bottom: 0,
61
+ right: 0
25
62
  },
26
- 'none-start': {
63
+ 'top-stretch': {
64
+ top: 0,
65
+ left: 0,
66
+ right: 0,
67
+ width: '100%'
68
+ },
69
+ 'left-stretch': {
27
70
  top: 0,
28
71
  bottom: 0,
29
- marginVertical: 'auto'
72
+ left: 0,
73
+ height: '100%'
30
74
  },
31
- 'none-center': {
75
+ 'right-stretch': {
32
76
  top: 0,
77
+ bottom: 0,
78
+ right: 0,
79
+ height: '100%'
80
+ },
81
+ 'bottom-stretch': {
33
82
  bottom: 0,
34
83
  left: 0,
35
84
  right: 0,
36
- margin: 'auto'
85
+ width: '100%'
86
+ }
87
+ };
88
+ const webBackgroundPositions = {
89
+ 'top-start': 'left top',
90
+ 'top-center': 'center top',
91
+ 'top-end': 'right top',
92
+ 'bottom-start': 'left bottom',
93
+ 'bottom-center': 'center bottom',
94
+ 'bottom-end': 'right bottom',
95
+ 'left-center': 'left center',
96
+ 'right-center': 'right center'
97
+ };
98
+ const nativeStyles = {
99
+ 'top-start': {
100
+ top: 0,
101
+ left: 0,
102
+ width: 150,
103
+ height: 200
37
104
  },
38
- 'right-center': {
105
+ 'top-center': {
106
+ top: 0,
107
+ left: '50%',
108
+ marginLeft: -75,
109
+ width: 150,
110
+ height: 200
111
+ },
112
+ 'top-end': {
39
113
  top: 0,
40
- bottom: 0,
41
114
  right: 0,
42
- marginVertical: 'auto'
115
+ width: 150,
116
+ height: 200
43
117
  },
44
- 'none-end': {
118
+ 'right-start': {
45
119
  top: 0,
46
- bottom: 0,
47
120
  right: 0,
48
- marginVertical: 'auto'
121
+ width: 150,
122
+ height: 200
123
+ },
124
+ 'left-start': {
125
+ top: 0,
126
+ left: 0,
127
+ width: 150,
128
+ height: 200
129
+ },
130
+ 'left-center': {
131
+ left: 0,
132
+ top: '50%',
133
+ marginTop: -100,
134
+ width: 150,
135
+ height: 200
136
+ },
137
+ 'right-center': {
138
+ right: 0,
139
+ top: '50%',
140
+ marginTop: -100,
141
+ width: 150,
142
+ height: 200
49
143
  },
50
144
  'bottom-start': {
51
145
  bottom: 0,
52
- left: 0
146
+ left: 0,
147
+ width: 150,
148
+ height: 200
53
149
  },
54
150
  'left-end': {
55
151
  bottom: 0,
56
- left: 0
152
+ left: 0,
153
+ width: 150,
154
+ height: 200
57
155
  },
58
156
  'bottom-center': {
59
- left: 0,
60
- right: 0,
61
157
  bottom: 0,
62
- marginHorizontal: 'auto'
158
+ left: '50%',
159
+ marginLeft: -75,
160
+ width: 150,
161
+ height: 200
63
162
  },
64
163
  'bottom-end': {
164
+ bottom: 0,
65
165
  right: 0,
66
- bottom: 0
166
+ width: 150,
167
+ height: 200
67
168
  },
68
169
  'right-end': {
170
+ bottom: 0,
69
171
  right: 0,
70
- bottom: 0
172
+ width: 150,
173
+ height: 200
71
174
  },
72
175
  'top-stretch': {
176
+ top: 0,
73
177
  left: 0,
74
178
  right: 0,
75
179
  width: '100%'
@@ -77,6 +181,7 @@ export default {
77
181
  'left-stretch': {
78
182
  top: 0,
79
183
  bottom: 0,
184
+ left: 0,
80
185
  height: '100%'
81
186
  },
82
187
  'right-stretch': {
@@ -86,9 +191,11 @@ export default {
86
191
  height: '100%'
87
192
  },
88
193
  'bottom-stretch': {
194
+ bottom: 0,
89
195
  left: 0,
90
196
  right: 0,
91
- bottom: 0,
92
197
  width: '100%'
93
198
  }
94
- };
199
+ };
200
+ export const backgroundPositions = Platform.OS === 'web' ? webBackgroundPositions : {};
201
+ export default Platform.OS === 'web' ? webStyles : nativeStyles;
@@ -8,7 +8,7 @@ import Dimensions from "react-native-web/dist/exports/Dimensions";
8
8
  import PropTypes from 'prop-types';
9
9
  import { useThemeTokens } from '../ThemeProvider';
10
10
  import { useViewport } from '../ViewportProvider';
11
- import { getTokensPropType, getA11yPropsFromHtmlTag, layoutTags, variantProp, selectSystemProps, a11yProps, viewProps, useCopy, unpackFragment } from '../utils';
11
+ import { getTokensPropType, getA11yPropsFromHtmlTag, layoutTags, variantProp, selectSystemProps, a11yProps, viewProps, useCopy, unpackFragment, isTouchDevice } from '../utils';
12
12
  import { useA11yInfo } from '../A11yInfoProvider';
13
13
  import { CarouselProvider } from './CarouselContext';
14
14
  import CarouselItem from './CarouselItem';
@@ -717,7 +717,7 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
717
717
  return false;
718
718
  }
719
719
  if (Platform.OS === 'web') {
720
- return !!(viewport === 'xs' || viewport === 'sm');
720
+ return !!(viewport === 'xs' || viewport === 'sm' || viewport === 'md' && isTouchDevice());
721
721
  }
722
722
  return true;
723
723
  }, [viewport, totalItems]);
@@ -120,6 +120,7 @@ const Modal = /*#__PURE__*/React.forwardRef((_ref5, ref) => {
120
120
  confirmButtonVariant,
121
121
  cancelButtonText,
122
122
  cancelButtonType,
123
+ footer,
123
124
  ...rest
124
125
  } = _ref5;
125
126
  const viewport = useViewport();
@@ -223,6 +224,7 @@ const Modal = /*#__PURE__*/React.forwardRef((_ref5, ref) => {
223
224
  confirmButtonVariant: confirmButtonVariant,
224
225
  cancelButtonText: cancelButtonText,
225
226
  cancelButtonType: cancelButtonType,
227
+ footer: footer,
226
228
  children: Platform.OS !== 'web' ? /*#__PURE__*/_jsx(ScrollView, {
227
229
  style: selectScrollViewStyles,
228
230
  children: children
@@ -323,7 +325,11 @@ Modal.propTypes = {
323
325
  /**
324
326
  * Receive a function for the onCancel event in the cancel button.
325
327
  */
326
- onCancel: PropTypes.func
328
+ onCancel: PropTypes.func,
329
+ /**
330
+ * Receive a react node or an array of nodes to render at the bottom of the modal, above the action buttons.
331
+ */
332
+ footer: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)])
327
333
  };
328
334
  export default Modal;
329
335
  const staticStyles = StyleSheet.create({