@telus-uds/components-base 3.26.0 → 3.28.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 (75) hide show
  1. package/CHANGELOG.md +35 -2
  2. package/lib/cjs/Card/Card.js +34 -13
  3. package/lib/cjs/Card/CardBase.js +90 -14
  4. package/lib/cjs/Card/PressableCardBase.js +147 -8
  5. package/lib/cjs/Carousel/Carousel.js +105 -50
  6. package/lib/cjs/Carousel/CarouselContext.js +10 -4
  7. package/lib/cjs/Carousel/CarouselItem/CarouselItem.js +11 -7
  8. package/lib/cjs/Carousel/Constants.js +11 -2
  9. package/lib/cjs/Checkbox/Checkbox.js +43 -13
  10. package/lib/cjs/ExpandCollapse/Control.js +5 -1
  11. package/lib/cjs/ExpandCollapse/ExpandCollapse.js +17 -8
  12. package/lib/cjs/ExpandCollapse/Panel.js +7 -2
  13. package/lib/cjs/IconButton/IconButton.js +10 -5
  14. package/lib/cjs/List/List.js +24 -9
  15. package/lib/cjs/List/ListItem.js +18 -1
  16. package/lib/cjs/List/ListItemBase.js +27 -8
  17. package/lib/cjs/List/ListItemMark.js +33 -62
  18. package/lib/cjs/List/PressableListItemBase.js +1 -0
  19. package/lib/cjs/Modal/Modal.js +21 -11
  20. package/lib/cjs/Progress/Progress.js +19 -5
  21. package/lib/cjs/Progress/ProgressBar.js +22 -4
  22. package/lib/cjs/Progress/ProgressContext.js +11 -0
  23. package/lib/cjs/SideNav/Item.js +3 -3
  24. package/lib/cjs/SideNav/ItemsGroup.js +46 -19
  25. package/lib/cjs/SideNav/SideNav.js +29 -13
  26. package/lib/esm/Card/Card.js +34 -13
  27. package/lib/esm/Card/CardBase.js +90 -14
  28. package/lib/esm/Card/PressableCardBase.js +148 -9
  29. package/lib/esm/Carousel/Carousel.js +106 -51
  30. package/lib/esm/Carousel/CarouselContext.js +10 -4
  31. package/lib/esm/Carousel/CarouselItem/CarouselItem.js +11 -7
  32. package/lib/esm/Carousel/Constants.js +10 -1
  33. package/lib/esm/Checkbox/Checkbox.js +43 -13
  34. package/lib/esm/ExpandCollapse/Control.js +5 -1
  35. package/lib/esm/ExpandCollapse/ExpandCollapse.js +17 -8
  36. package/lib/esm/ExpandCollapse/Panel.js +7 -2
  37. package/lib/esm/IconButton/IconButton.js +10 -5
  38. package/lib/esm/List/List.js +24 -9
  39. package/lib/esm/List/ListItem.js +19 -2
  40. package/lib/esm/List/ListItemBase.js +27 -8
  41. package/lib/esm/List/ListItemMark.js +33 -62
  42. package/lib/esm/List/PressableListItemBase.js +1 -0
  43. package/lib/esm/Modal/Modal.js +21 -11
  44. package/lib/esm/Progress/Progress.js +19 -5
  45. package/lib/esm/Progress/ProgressBar.js +22 -4
  46. package/lib/esm/Progress/ProgressContext.js +5 -0
  47. package/lib/esm/SideNav/Item.js +3 -3
  48. package/lib/esm/SideNav/ItemsGroup.js +45 -20
  49. package/lib/esm/SideNav/SideNav.js +29 -13
  50. package/lib/package.json +2 -2
  51. package/package.json +2 -2
  52. package/src/Card/Card.jsx +29 -7
  53. package/src/Card/CardBase.jsx +97 -11
  54. package/src/Card/PressableCardBase.jsx +135 -9
  55. package/src/Carousel/Carousel.jsx +119 -64
  56. package/src/Carousel/CarouselContext.jsx +12 -4
  57. package/src/Carousel/CarouselItem/CarouselItem.jsx +10 -6
  58. package/src/Carousel/Constants.js +10 -0
  59. package/src/Checkbox/Checkbox.jsx +29 -7
  60. package/src/ExpandCollapse/Control.jsx +1 -1
  61. package/src/ExpandCollapse/ExpandCollapse.jsx +9 -8
  62. package/src/ExpandCollapse/Panel.jsx +10 -2
  63. package/src/IconButton/IconButton.jsx +40 -28
  64. package/src/List/List.jsx +33 -9
  65. package/src/List/ListItem.jsx +33 -11
  66. package/src/List/ListItemBase.jsx +33 -9
  67. package/src/List/ListItemMark.jsx +32 -53
  68. package/src/List/PressableListItemBase.jsx +1 -0
  69. package/src/Modal/Modal.jsx +23 -11
  70. package/src/Progress/Progress.jsx +18 -7
  71. package/src/Progress/ProgressBar.jsx +19 -14
  72. package/src/Progress/ProgressContext.js +5 -0
  73. package/src/SideNav/Item.jsx +3 -3
  74. package/src/SideNav/ItemsGroup.jsx +36 -16
  75. package/src/SideNav/SideNav.jsx +22 -8
@@ -79,6 +79,11 @@ const selectInnerStyle = (_ref2, password) => {
79
79
  width,
80
80
  height
81
81
  } = _ref2;
82
+ const basePadding = calculatePadding(padding, borderWidth);
83
+ const calculateSpecificPadding = (specificPadding, specificBorderWidth) => {
84
+ const calculated = calculatePadding(specificPadding ?? padding, specificBorderWidth ?? borderWidth);
85
+ return calculated !== basePadding && calculated !== undefined ? calculated : undefined;
86
+ };
82
87
  return {
83
88
  // Inner borders animate with the icon and should be treated like a themable feature of the icon
84
89
  borderColor,
@@ -92,11 +97,11 @@ const selectInnerStyle = (_ref2, password) => {
92
97
  borderRightWidth,
93
98
  borderBottomWidth,
94
99
  borderLeftWidth,
95
- padding: calculatePadding(padding, borderWidth),
96
- paddingLeft: calculatePadding(paddingLeft, borderLeftWidth),
97
- paddingRight: calculatePadding(paddingRight, borderRightWidth),
98
- paddingTop: calculatePadding(paddingTop, borderTopWidth),
99
- paddingBottom: calculatePadding(paddingBottom, borderBottomWidth),
100
+ padding: basePadding,
101
+ paddingLeft: calculateSpecificPadding(paddingLeft, borderLeftWidth),
102
+ paddingRight: calculateSpecificPadding(paddingRight, borderRightWidth),
103
+ paddingTop: calculateSpecificPadding(paddingTop, borderTopWidth),
104
+ paddingBottom: calculateSpecificPadding(paddingBottom, borderBottomWidth),
100
105
  ...Platform.select({
101
106
  web: {
102
107
  pointerEvents: 'none',
@@ -6,10 +6,15 @@ import PropTypes from 'prop-types';
6
6
  import { a11yProps, getTokensPropType, selectSystemProps, variantProp, viewProps } from '../utils';
7
7
  import { jsx as _jsx } from "react/jsx-runtime";
8
8
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
9
+ const LIST_ITEM_TYPE = 'ListItem';
10
+ const LINKS_ITEM_TYPE = 'LinksItem';
9
11
  const isListItem = element => {
10
- const elementName = element?.type?.displayName || element?.type?.name;
11
- // Match our own ListItem, and also, custom list items
12
- return Boolean(elementName.match(/Item/));
12
+ if (!element?.type) return false;
13
+ if (element.type.__UDS_COMPONENT_TYPE__ === LIST_ITEM_TYPE) {
14
+ return true;
15
+ }
16
+ const elementName = element.type.displayName || element.type.name || '';
17
+ return elementName === LIST_ITEM_TYPE || elementName.includes(LIST_ITEM_TYPE) || elementName.includes(LINKS_ITEM_TYPE);
13
18
  };
14
19
 
15
20
  /**
@@ -22,6 +27,7 @@ const List = /*#__PURE__*/React.forwardRef((_ref, ref) => {
22
27
  showDivider,
23
28
  tokens,
24
29
  variant,
30
+ iconVerticalAlign,
25
31
  accessibilityRole = Platform.select({
26
32
  web: 'list',
27
33
  default: undefined
@@ -31,13 +37,17 @@ const List = /*#__PURE__*/React.forwardRef((_ref, ref) => {
31
37
  const items = React.Children.map(children, (child, index) => {
32
38
  // Pass ListItem-specific props to children (by name so teams can add their own ListItems)
33
39
  if (isListItem(child)) {
34
- return /*#__PURE__*/React.cloneElement(child, {
35
- showDivider,
36
- isLastItem: index + 1 === React.Children.count(children),
40
+ const childProps = {
37
41
  tokens,
38
42
  variant,
39
- ...child.props
40
- });
43
+ ...child.props,
44
+ showDivider,
45
+ isLastItem: index + 1 === React.Children.count(children)
46
+ };
47
+ if (!child.props.iconVerticalAlign && iconVerticalAlign) {
48
+ childProps.iconVerticalAlign = iconVerticalAlign;
49
+ }
50
+ return /*#__PURE__*/React.cloneElement(child, childProps);
41
51
  }
42
52
  return child;
43
53
  });
@@ -71,6 +81,11 @@ List.propTypes = {
71
81
  /**
72
82
  * In case it is not the last item allow display divider
73
83
  */
74
- showDivider: PropTypes.bool
84
+ showDivider: PropTypes.bool,
85
+ /**
86
+ * The vertical alignment of the icon in ListItems.
87
+ * This prop is passed down to ListItem components and can be overridden in individual List.Item components.
88
+ */
89
+ iconVerticalAlign: PropTypes.oneOf(['top', 'center', 'bottom'])
75
90
  };
76
91
  export default List;
@@ -1,7 +1,8 @@
1
1
  import React from 'react';
2
+ import PropTypes from 'prop-types';
2
3
  import ListItemBase from './ListItemBase';
3
4
  import { useThemeTokens } from '../ThemeProvider';
4
- import { variantProp } from '../utils';
5
+ import { getTokensPropType, variantProp } from '../utils';
5
6
 
6
7
  /**
7
8
  * ListItem is responsible for rendering icon or a bullet as side item
@@ -13,6 +14,7 @@ const ListItem = /*#__PURE__*/React.forwardRef((_ref, ref) => {
13
14
  variant,
14
15
  children,
15
16
  title,
17
+ iconVerticalAlign = 'top',
16
18
  ...listItemProps
17
19
  } = _ref;
18
20
  const themeTokens = useThemeTokens('List', tokens, variant);
@@ -21,12 +23,27 @@ const ListItem = /*#__PURE__*/React.forwardRef((_ref, ref) => {
21
23
  ref: ref,
22
24
  ...listItemProps,
23
25
  title: title,
26
+ iconVerticalAlign: iconVerticalAlign,
24
27
  children: children
25
28
  });
26
29
  });
27
30
  ListItem.displayName = 'ListItem';
28
31
  ListItem.propTypes = {
32
+ /** Theme tokens for styling */
33
+ tokens: getTokensPropType('List'),
34
+ /** Variant configuration for the component */
29
35
  variant: variantProp.propType,
30
- ...ListItemBase.propTypes
36
+ /** Content to be rendered within the list item */
37
+ children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired,
38
+ /** Title of the list item */
39
+ title: PropTypes.node,
40
+ /** Controls the vertical alignment of the icon */
41
+ iconVerticalAlign: PropTypes.oneOf(['top', 'center', 'bottom']),
42
+ /** Icon to be displayed */
43
+ icon: PropTypes.elementType,
44
+ /** Color of the icon */
45
+ iconColor: PropTypes.string,
46
+ /** Size of the icon */
47
+ iconSize: PropTypes.number
31
48
  };
32
49
  export default ListItem;
@@ -10,6 +10,12 @@ import Typography from '../Typography';
10
10
  import { useThemeTokens } from '../ThemeProvider';
11
11
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
12
12
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
13
+ const VERTICAL_CENTERING_DIVISOR = 2;
14
+ const alignmentMap = {
15
+ top: 'flex-start',
16
+ center: 'center',
17
+ bottom: 'flex-end'
18
+ };
13
19
  const selectItemBlockStyles = _ref => {
14
20
  let {
15
21
  interItemMargin
@@ -31,10 +37,16 @@ const selectDividerStyles = _ref2 => {
31
37
  paddingBottom: interItemMarginWithDivider
32
38
  };
33
39
  };
40
+ const selectAlignmentStyles = iconVerticalAlign => ({
41
+ alignItems: alignmentMap[iconVerticalAlign]
42
+ });
34
43
 
35
44
  /**
36
45
  * ListItem is responsible for rendering icon or a bullet as side item
37
46
  */
47
+ const calculateIconMarginTop = (itemIconSize, fontSize, lineHeightRatio) => {
48
+ return (fontSize * lineHeightRatio - itemIconSize) / VERTICAL_CENTERING_DIVISOR;
49
+ };
38
50
  const ListItemBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
39
51
  let {
40
52
  tokens,
@@ -45,6 +57,7 @@ const ListItemBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
45
57
  children,
46
58
  title,
47
59
  isLastItem,
60
+ iconVerticalAlign = 'top',
48
61
  accessibilityRole = Platform.select({
49
62
  web: 'listitem',
50
63
  default: undefined
@@ -58,7 +71,6 @@ const ListItemBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
58
71
  iconMarginTop,
59
72
  itemIconSize
60
73
  } = themeTokens;
61
- let adjustedIconMarginTop = iconMarginTop;
62
74
  const {
63
75
  fontSize,
64
76
  lineHeight: lineHeightRatio
@@ -66,9 +78,8 @@ const ListItemBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
66
78
  size: 'h4',
67
79
  bold: true
68
80
  });
69
- if (title) {
70
- adjustedIconMarginTop = (fontSize * lineHeightRatio - itemIconSize) / 2;
71
- }
81
+ const adjustedIconMarginTop = title ? calculateIconMarginTop(itemIconSize, fontSize, lineHeightRatio) : iconMarginTop;
82
+
72
83
  /**
73
84
  * Function responsible returning styling, in case the item is the last shouldn't
74
85
  * add extra margin on the bottom, if "showDivider" is true it should add a divider
@@ -95,7 +106,7 @@ const ListItemBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
95
106
  iconSize,
96
107
  isLastItem
97
108
  }) : /*#__PURE__*/_jsxs(View, {
98
- style: staticStyles.container,
109
+ style: [staticStyles.innerContainer, selectAlignmentStyles(iconVerticalAlign)],
99
110
  children: [/*#__PURE__*/_jsx(ListItemMark, {
100
111
  tokens: {
101
112
  ...tokens,
@@ -105,7 +116,7 @@ const ListItemBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
105
116
  iconColor: iconColor,
106
117
  iconSize: iconSize
107
118
  }), /*#__PURE__*/_jsxs(View, {
108
- style: staticStyles.titleAndContentContainer,
119
+ style: [staticStyles.titleAndContentContainer],
109
120
  children: [Boolean(title) && /*#__PURE__*/_jsx(Typography, {
110
121
  variant: {
111
122
  size: 'h4',
@@ -121,15 +132,21 @@ const ListItemBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
121
132
  });
122
133
  });
123
134
  ListItemBase.displayName = 'ListItem';
135
+ ListItemBase.__UDS_COMPONENT_TYPE__ = 'ListItem';
124
136
  const staticStyles = StyleSheet.create({
125
137
  container: {
138
+ flexDirection: 'row',
139
+ width: '100%'
140
+ },
141
+ innerContainer: {
126
142
  flex: 1,
127
143
  flexDirection: 'row'
128
144
  },
129
145
  titleAndContentContainer: {
130
146
  flexDirection: 'column',
131
- flexShrink: 1,
132
- flexGrow: 1
147
+ flex: 1,
148
+ flexGrow: 1,
149
+ flexShrink: 1
133
150
  }
134
151
  });
135
152
  ListItemBase.propTypes = {
@@ -137,6 +154,8 @@ ListItemBase.propTypes = {
137
154
  tokens: getTokensPropType('List'),
138
155
  variant: variantProp.propType,
139
156
  children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired,
157
+ /** Controls the vertical alignment of the icon */
158
+ iconVerticalAlign: PropTypes.oneOf(['top', 'center', 'bottom']),
140
159
  /**
141
160
  * Renders side item icon
142
161
  */
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import View from "react-native-web/dist/exports/View";
4
- import StyleSheet from "react-native-web/dist/exports/StyleSheet";
5
4
  import Icon from '../Icon';
6
5
  import { useVariants } from '../utils';
7
6
  import { jsx as _jsx } from "react/jsx-runtime";
@@ -9,49 +8,29 @@ export const tokenTypes = {
9
8
  itemIconSize: PropTypes.number.isRequired,
10
9
  itemIconColor: PropTypes.string.isRequired,
11
10
  listGutter: PropTypes.number.isRequired,
12
- iconMarginTop: PropTypes.number.isRequired
11
+ iconMarginTop: PropTypes.number.isRequired,
12
+ bulletIcon: PropTypes.elementType.isRequired
13
13
  };
14
- const selectItemIconTokens = _ref => {
14
+ const selectContainerStyles = _ref => {
15
15
  let {
16
- itemIconSize,
17
- itemIconColor
16
+ listGutter
18
17
  } = _ref;
19
18
  return {
20
- size: itemIconSize,
21
- color: itemIconColor
22
- };
23
- };
24
- const selectSideItemContainerStyles = _ref2 => {
25
- let {
26
- listGutter,
27
- iconMarginTop
28
- } = _ref2;
29
- return {
30
- marginTop: iconMarginTop,
31
- marginRight: listGutter
19
+ marginInlineEnd: listGutter,
20
+ display: 'flex',
21
+ alignItems: 'flex-start'
32
22
  };
33
23
  };
34
-
35
- // Align bullets with the top line of text the same way icons are aligned
36
- const selectBulletPositioningStyles = _ref3 => {
24
+ const selectBulletStyles = _ref2 => {
37
25
  let {
38
26
  itemIconSize
39
- } = _ref3;
27
+ } = _ref2;
40
28
  return {
41
29
  width: itemIconSize,
42
- height: itemIconSize
43
- };
44
- };
45
- const selectBulletContainerStyles = _ref4 => {
46
- let {
47
- itemBulletContainerWidth,
48
- itemBulletContainerHeight,
49
- itemBulletContainerAlign
50
- } = _ref4;
51
- return {
52
- width: itemBulletContainerWidth,
53
- height: itemBulletContainerHeight,
54
- alignItems: itemBulletContainerAlign
30
+ height: itemIconSize,
31
+ alignItems: 'center',
32
+ justifyContent: 'center',
33
+ flexShrink: 0
55
34
  };
56
35
  };
57
36
  const getIconColorVariants = iconVariants => iconVariants?.filter(variant => variant[0] === 'color').map(variant => variant[1]);
@@ -63,31 +42,31 @@ const getIconColorVariants = iconVariants => iconVariants?.filter(variant => var
63
42
  * It's the responsibility of themes to make sure that the supplied tokens align the
64
43
  * icon or bullet nicely against the first line of text in a ListIconContent.
65
44
  */
66
- const ListItemMark = /*#__PURE__*/React.forwardRef((_ref5, ref) => {
45
+ const ListItemMark = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
67
46
  let {
68
47
  icon,
69
48
  iconColor,
70
49
  iconSize,
71
50
  tokens = {}
72
- } = _ref5;
51
+ } = _ref3;
73
52
  const themeTokens = typeof tokens === 'function' ? tokens() : tokens;
74
- const sideItemContainerStyles = selectSideItemContainerStyles(themeTokens);
75
- const bulletContainerStyles = selectBulletContainerStyles(themeTokens);
76
-
77
- // TODO: Remove it when iconColor custom colors are deprecated.
53
+ const containerStyles = selectContainerStyles(themeTokens);
78
54
  const iconVariants = useVariants('Icon');
79
55
  const iconColorVariants = getIconColorVariants(iconVariants);
80
56
  if (icon) {
81
- const iconTokens = selectItemIconTokens(themeTokens);
57
+ const {
58
+ itemIconSize,
59
+ itemIconColor
60
+ } = themeTokens;
61
+ const finalIconSize = iconSize ?? itemIconSize;
62
+ const finalIconColor = iconColor && !iconColorVariants?.includes(iconColor) ? iconColor : itemIconColor;
82
63
  return /*#__PURE__*/_jsx(View, {
83
- style: [sideItemContainerStyles, bulletContainerStyles],
64
+ style: containerStyles,
84
65
  children: /*#__PURE__*/_jsx(Icon, {
85
66
  icon: icon,
86
67
  tokens: {
87
- size: iconSize ?? iconTokens.size,
88
- ...((iconColor && !iconColorVariants?.includes(iconColor) || !iconColor) && {
89
- color: iconColor && !iconColorVariants?.includes(iconColor) ? iconColor : iconTokens.color
90
- })
68
+ size: finalIconSize,
69
+ color: finalIconColor
91
70
  },
92
71
  variant: {
93
72
  ...(iconColorVariants?.includes(iconColor) && {
@@ -97,23 +76,21 @@ const ListItemMark = /*#__PURE__*/React.forwardRef((_ref5, ref) => {
97
76
  })
98
77
  });
99
78
  }
100
- const bulletColor = themeTokens.itemBulletColor;
101
79
  const {
102
- bulletIcon
80
+ itemIconSize,
81
+ itemIconColor
103
82
  } = themeTokens;
104
- const itemBulletContainerStyles = selectBulletContainerStyles(themeTokens);
105
- const itemBulletPositioningStyles = selectBulletPositioningStyles(themeTokens);
83
+ const bulletStyles = selectBulletStyles(themeTokens);
106
84
  return /*#__PURE__*/_jsx(View, {
107
- style: [sideItemContainerStyles, itemBulletContainerStyles],
85
+ style: containerStyles,
108
86
  ref: ref,
109
87
  children: /*#__PURE__*/_jsx(View, {
110
- style: [staticStyles.bulletPositioning, itemBulletPositioningStyles],
111
- testID: "unordered-item-bullet",
88
+ style: bulletStyles,
112
89
  children: /*#__PURE__*/_jsx(Icon, {
113
- icon: bulletIcon,
90
+ icon: themeTokens.bulletIcon,
114
91
  tokens: {
115
- color: bulletColor,
116
- size: themeTokens.itemIconSize
92
+ color: itemIconColor,
93
+ size: itemIconSize
117
94
  }
118
95
  })
119
96
  })
@@ -135,10 +112,4 @@ ListItemMark.propTypes = {
135
112
  */
136
113
  iconSize: PropTypes.number
137
114
  };
138
- const staticStyles = StyleSheet.create({
139
- bulletPositioning: {
140
- alignItems: 'center',
141
- justifyContent: 'center'
142
- }
143
- });
144
115
  export default ListItemMark;
@@ -91,6 +91,7 @@ const PressableListItemBase = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
91
91
  });
92
92
  });
93
93
  PressableListItemBase.displayName = 'PressableListItemBase';
94
+ PressableListItemBase.__UDS_COMPONENT_TYPE__ = 'ListItem';
94
95
  const staticStyles = StyleSheet.create({
95
96
  itemContainer: {
96
97
  flexDirection: 'row',
@@ -64,11 +64,15 @@ const selectModalStyles = _ref2 => {
64
64
  const selectBackdropStyles = _ref3 => {
65
65
  let {
66
66
  backdropColor,
67
- backdropOpacity
67
+ backdropOpacity,
68
+ backdropCursor
68
69
  } = _ref3;
69
70
  return {
70
71
  backgroundColor: backdropColor,
71
- opacity: backdropOpacity
72
+ opacity: backdropOpacity,
73
+ ...(Platform.OS === 'web' && backdropCursor ? {
74
+ cursor: backdropCursor
75
+ } : {})
72
76
  };
73
77
  };
74
78
  const selectCloseButtonContainerStyles = _ref4 => {
@@ -121,12 +125,15 @@ const Modal = /*#__PURE__*/React.forwardRef((_ref5, ref) => {
121
125
  cancelButtonText,
122
126
  cancelButtonType,
123
127
  footer,
128
+ backgroundDismissible = true,
124
129
  ...rest
125
130
  } = _ref5;
126
131
  const viewport = useViewport();
132
+ const isBackdropClickable = onClose && backgroundDismissible;
127
133
  const themeTokens = useThemeTokens('Modal', tokens, variant, {
128
134
  viewport,
129
- maxWidth
135
+ maxWidth,
136
+ backdropCursor: isBackdropClickable ? 'pointer' : 'default'
130
137
  });
131
138
  const modalRef = useScrollBlocking(isOpen);
132
139
  const modalBodyRef = React.useRef(ref);
@@ -232,7 +239,7 @@ const Modal = /*#__PURE__*/React.forwardRef((_ref5, ref) => {
232
239
  })]
233
240
  })
234
241
  }), /*#__PURE__*/_jsx(TouchableWithoutFeedback, {
235
- onPress: handleClose,
242
+ onPress: isBackdropClickable && handleClose,
236
243
  children: /*#__PURE__*/_jsx(View, {
237
244
  style: [staticStyles.backdrop, selectBackdropStyles(themeTokens)]
238
245
  })
@@ -329,7 +336,15 @@ Modal.propTypes = {
329
336
  /**
330
337
  * Receive a react node or an array of nodes to render at the bottom of the modal, above the action buttons.
331
338
  */
332
- footer: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)])
339
+ footer: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]),
340
+ /**
341
+ * Controls whether the modal can be dismissed by clicking on the backdrop.
342
+ * When set to `false`, clicking the backdrop will not close the modal.
343
+ * The backdrop cursor automatically changes to 'default' to indicate it's not clickable.
344
+ * Note: Backdrop dismissal requires `onClose` to be defined.
345
+ * @default true
346
+ */
347
+ backgroundDismissible: PropTypes.bool
333
348
  };
334
349
  export default Modal;
335
350
  const staticStyles = StyleSheet.create({
@@ -339,12 +354,7 @@ const staticStyles = StyleSheet.create({
339
354
  left: 0,
340
355
  right: 0,
341
356
  bottom: 0,
342
- zIndex: -1,
343
- ...Platform.select({
344
- web: {
345
- cursor: 'pointer'
346
- }
347
- })
357
+ zIndex: -1
348
358
  },
349
359
  positioningContainer: {
350
360
  flexBasis: '100%',
@@ -4,6 +4,7 @@ import View from "react-native-web/dist/exports/View";
4
4
  import StyleSheet from "react-native-web/dist/exports/StyleSheet";
5
5
  import { applyShadowToken, useThemeTokens } from '../ThemeProvider';
6
6
  import { a11yProps, getTokensPropType, selectSystemProps, variantProp, viewProps } from '../utils';
7
+ import ProgressContext from './ProgressContext';
7
8
  import { jsx as _jsx } from "react/jsx-runtime";
8
9
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
9
10
  const selectProgressStyles = _ref => {
@@ -47,6 +48,12 @@ const selectProgressStyles = _ref => {
47
48
  *
48
49
  * - Use the `size` variant to control the height of your progress bars: passing `'mini'` will make your
49
50
  * progress bar container narrower.
51
+ * - Use the `layers` variant to control how multiple progress bars are positioned:
52
+ * - `false` (default): bars are positioned vertically one below the other.
53
+ * - `true`: bars overlay on top of each other (layered/stacked on z-axis).
54
+ * Note: The `layers` prop is deprecated. After August 2026, `layers: true` will become the permanent
55
+ * default behavior and the `layers` prop will be removed. To maintain vertical layout after removal,
56
+ * use separate individual Progress components.
50
57
  *
51
58
  * ## Usability and A11y guidelines
52
59
  *
@@ -63,11 +70,18 @@ const Progress = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
63
70
  ...rest
64
71
  } = _ref2;
65
72
  const themeTokens = useThemeTokens('Progress', tokens, variant);
66
- return /*#__PURE__*/_jsx(View, {
67
- ref: ref,
68
- style: [staticStyles.progressContainer, selectProgressStyles(themeTokens)],
69
- ...selectProps(rest),
70
- children: children
73
+ // Default to false (vertical layout) to preserve existing behavior and avoid breaking changes
74
+ const layers = variant?.layers ?? false;
75
+ return /*#__PURE__*/_jsx(ProgressContext.Provider, {
76
+ value: {
77
+ layers
78
+ },
79
+ children: /*#__PURE__*/_jsx(View, {
80
+ ref: ref,
81
+ style: [staticStyles.progressContainer, selectProgressStyles(themeTokens)],
82
+ ...selectProps(rest),
83
+ children: children
84
+ })
71
85
  });
72
86
  });
73
87
  Progress.displayName = 'Progress';
@@ -7,16 +7,23 @@ import ProgressBarBackground from './ProgressBarBackground';
7
7
  import { applyShadowToken, useThemeTokens } from '../ThemeProvider';
8
8
  import { a11yProps, getTokensPropType, selectSystemProps, variantProp, viewProps } from '../utils';
9
9
  import { MAX_PERCENT_VALUE, MIN_PERCENT_VALUE } from './constants';
10
+ import ProgressContext from './ProgressContext';
10
11
  import { jsx as _jsx } from "react/jsx-runtime";
11
12
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
12
- const selectBarStyles = (_ref, calculatedPercentage, barPosition) => {
13
+ const selectBarStyles = _ref => {
13
14
  let {
15
+ themeTokens,
16
+ calculatedPercentage,
17
+ barPosition,
18
+ layers
19
+ } = _ref;
20
+ const {
14
21
  backgroundColor,
15
22
  borderRadius,
16
23
  outlineWidth,
17
24
  outlineColor,
18
25
  shadow
19
- } = _ref;
26
+ } = themeTokens;
20
27
  return {
21
28
  backgroundColor,
22
29
  borderRadius,
@@ -24,7 +31,10 @@ const selectBarStyles = (_ref, calculatedPercentage, barPosition) => {
24
31
  outlineColor,
25
32
  ...applyShadowToken(shadow),
26
33
  width: `${calculatedPercentage}%`,
27
- left: `${barPosition}%`
34
+ left: `${barPosition}%`,
35
+ ...(layers ? {
36
+ position: 'absolute'
37
+ } : {})
28
38
  };
29
39
  };
30
40
 
@@ -75,6 +85,9 @@ const ProgressBar = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
75
85
  },
76
86
  ...rest
77
87
  } = _ref2;
88
+ const {
89
+ layers
90
+ } = React.useContext(ProgressContext);
78
91
  const {
79
92
  items,
80
93
  current
@@ -107,7 +120,12 @@ const ProgressBar = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
107
120
  });
108
121
  return percentage > MIN_PERCENT_VALUE || items ? /*#__PURE__*/_jsx(View, {
109
122
  ref: ref,
110
- style: [staticStyles.bar, selectBarStyles(themeTokens, calculatedPercentage, barPosition)],
123
+ style: [staticStyles.bar, selectBarStyles({
124
+ themeTokens,
125
+ calculatedPercentage,
126
+ barPosition,
127
+ layers
128
+ })],
111
129
  ...selectedProps,
112
130
  children: children ?? /*#__PURE__*/_jsx(ProgressBarBackground, {
113
131
  variant: variant
@@ -0,0 +1,5 @@
1
+ import { createContext } from 'react';
2
+ const ProgressContext = /*#__PURE__*/createContext({
3
+ layers: false
4
+ });
5
+ export default ProgressContext;
@@ -22,9 +22,9 @@ function selectItemStyles(_ref) {
22
22
  } = _ref;
23
23
  return {
24
24
  backgroundColor,
25
- borderTopColor: borderColor,
26
- borderTopWidth: borderWidth,
27
- borderTopStyle: borderStyle,
25
+ borderBottomColor: borderColor,
26
+ borderBottomWidth: borderWidth,
27
+ borderBottomStyle: borderStyle,
28
28
  paddingLeft,
29
29
  paddingRight,
30
30
  paddingTop,