@telus-uds/components-base 3.12.2 → 3.14.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 (63) hide show
  1. package/CHANGELOG.md +37 -2
  2. package/lib/cjs/BaseProvider/index.js +4 -1
  3. package/lib/cjs/Button/ButtonDropdown.js +105 -12
  4. package/lib/cjs/Card/Card.js +23 -4
  5. package/lib/cjs/Card/CardBase.js +170 -19
  6. package/lib/cjs/Card/PressableCardBase.js +19 -5
  7. package/lib/cjs/Card/backgroundImageStylesMap.js +197 -0
  8. package/lib/cjs/ExpandCollapse/ExpandCollapse.js +3 -1
  9. package/lib/cjs/ExpandCollapseMini/ExpandCollapseMini.js +1 -1
  10. package/lib/cjs/ExpandCollapseMini/ExpandCollapseMiniControl.js +30 -6
  11. package/lib/cjs/FlexGrid/FlexGrid.js +71 -6
  12. package/lib/cjs/Icon/Icon.js +3 -1
  13. package/lib/cjs/InputLabel/InputLabel.js +1 -1
  14. package/lib/cjs/InputSupports/InputSupports.js +1 -1
  15. package/lib/cjs/Notification/Notification.js +27 -8
  16. package/lib/cjs/Tabs/Tabs.js +34 -2
  17. package/lib/cjs/Tabs/TabsDropdown.js +252 -0
  18. package/lib/cjs/Tabs/TabsItem.js +4 -2
  19. package/lib/cjs/Tabs/dictionary.js +14 -0
  20. package/lib/cjs/ViewportProvider/ViewportProvider.js +9 -3
  21. package/lib/cjs/utils/props/inputSupportsProps.js +1 -1
  22. package/lib/esm/BaseProvider/index.js +4 -1
  23. package/lib/esm/Button/ButtonDropdown.js +107 -14
  24. package/lib/esm/Card/Card.js +21 -4
  25. package/lib/esm/Card/CardBase.js +169 -19
  26. package/lib/esm/Card/PressableCardBase.js +19 -5
  27. package/lib/esm/Card/backgroundImageStylesMap.js +190 -0
  28. package/lib/esm/ExpandCollapse/ExpandCollapse.js +4 -2
  29. package/lib/esm/ExpandCollapseMini/ExpandCollapseMini.js +2 -2
  30. package/lib/esm/ExpandCollapseMini/ExpandCollapseMiniControl.js +30 -6
  31. package/lib/esm/FlexGrid/FlexGrid.js +72 -7
  32. package/lib/esm/Icon/Icon.js +3 -1
  33. package/lib/esm/InputLabel/InputLabel.js +1 -1
  34. package/lib/esm/InputSupports/InputSupports.js +1 -1
  35. package/lib/esm/Notification/Notification.js +27 -8
  36. package/lib/esm/Tabs/Tabs.js +35 -3
  37. package/lib/esm/Tabs/TabsDropdown.js +245 -0
  38. package/lib/esm/Tabs/TabsItem.js +4 -2
  39. package/lib/esm/Tabs/dictionary.js +8 -0
  40. package/lib/esm/ViewportProvider/ViewportProvider.js +9 -3
  41. package/lib/esm/utils/props/inputSupportsProps.js +1 -1
  42. package/lib/package.json +2 -2
  43. package/package.json +2 -2
  44. package/src/BaseProvider/index.jsx +4 -2
  45. package/src/Button/ButtonDropdown.jsx +109 -16
  46. package/src/Card/Card.jsx +27 -3
  47. package/src/Card/CardBase.jsx +165 -19
  48. package/src/Card/PressableCardBase.jsx +31 -4
  49. package/src/Card/backgroundImageStylesMap.js +41 -0
  50. package/src/ExpandCollapse/ExpandCollapse.jsx +5 -2
  51. package/src/ExpandCollapseMini/ExpandCollapseMini.jsx +2 -2
  52. package/src/ExpandCollapseMini/ExpandCollapseMiniControl.jsx +39 -9
  53. package/src/FlexGrid/FlexGrid.jsx +80 -7
  54. package/src/Icon/Icon.jsx +3 -1
  55. package/src/InputLabel/InputLabel.jsx +1 -1
  56. package/src/InputSupports/InputSupports.jsx +1 -1
  57. package/src/Notification/Notification.jsx +58 -9
  58. package/src/Tabs/Tabs.jsx +36 -2
  59. package/src/Tabs/TabsDropdown.jsx +265 -0
  60. package/src/Tabs/TabsItem.jsx +4 -2
  61. package/src/Tabs/dictionary.js +8 -0
  62. package/src/ViewportProvider/ViewportProvider.jsx +8 -3
  63. package/src/utils/props/inputSupportsProps.js +1 -1
@@ -0,0 +1,197 @@
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
+ const webStyles = {
10
+ 'top-start': {
11
+ top: 0,
12
+ left: 0
13
+ },
14
+ 'top-center': {
15
+ top: 0,
16
+ left: '50%',
17
+ transform: [{
18
+ translateX: '-50%'
19
+ }]
20
+ },
21
+ 'top-end': {
22
+ top: 0,
23
+ right: 0
24
+ },
25
+ 'right-start': {
26
+ top: 0,
27
+ right: 0
28
+ },
29
+ 'left-start': {
30
+ top: 0,
31
+ left: 0
32
+ },
33
+ 'left-center': {
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': {
63
+ bottom: 0,
64
+ right: 0
65
+ },
66
+ 'right-end': {
67
+ bottom: 0,
68
+ right: 0
69
+ },
70
+ 'top-stretch': {
71
+ top: 0,
72
+ left: 0,
73
+ right: 0,
74
+ width: '100%'
75
+ },
76
+ 'left-stretch': {
77
+ top: 0,
78
+ bottom: 0,
79
+ left: 0,
80
+ height: '100%'
81
+ },
82
+ 'right-stretch': {
83
+ top: 0,
84
+ bottom: 0,
85
+ right: 0,
86
+ height: '100%'
87
+ },
88
+ 'bottom-stretch': {
89
+ bottom: 0,
90
+ left: 0,
91
+ right: 0,
92
+ width: '100%'
93
+ }
94
+ };
95
+ const nativeStyles = {
96
+ 'top-start': {
97
+ top: 0,
98
+ left: 0,
99
+ width: 150,
100
+ height: 200
101
+ },
102
+ 'top-center': {
103
+ top: 0,
104
+ left: '50%',
105
+ marginLeft: -75,
106
+ width: 150,
107
+ height: 200
108
+ },
109
+ 'top-end': {
110
+ top: 0,
111
+ right: 0,
112
+ width: 150,
113
+ height: 200
114
+ },
115
+ 'right-start': {
116
+ top: 0,
117
+ right: 0,
118
+ width: 150,
119
+ height: 200
120
+ },
121
+ 'left-start': {
122
+ top: 0,
123
+ left: 0,
124
+ width: 150,
125
+ height: 200
126
+ },
127
+ 'left-center': {
128
+ left: 0,
129
+ top: '50%',
130
+ marginTop: -100,
131
+ width: 150,
132
+ height: 200
133
+ },
134
+ 'right-center': {
135
+ right: 0,
136
+ top: '50%',
137
+ marginTop: -100,
138
+ width: 150,
139
+ height: 200
140
+ },
141
+ 'bottom-start': {
142
+ bottom: 0,
143
+ left: 0,
144
+ width: 150,
145
+ height: 200
146
+ },
147
+ 'left-end': {
148
+ bottom: 0,
149
+ left: 0,
150
+ width: 150,
151
+ height: 200
152
+ },
153
+ 'bottom-center': {
154
+ bottom: 0,
155
+ left: '50%',
156
+ marginLeft: -75,
157
+ width: 150,
158
+ height: 200
159
+ },
160
+ 'bottom-end': {
161
+ bottom: 0,
162
+ right: 0,
163
+ width: 150,
164
+ height: 200
165
+ },
166
+ 'right-end': {
167
+ bottom: 0,
168
+ right: 0,
169
+ width: 150,
170
+ height: 200
171
+ },
172
+ 'top-stretch': {
173
+ top: 0,
174
+ left: 0,
175
+ right: 0,
176
+ width: '100%'
177
+ },
178
+ 'left-stretch': {
179
+ top: 0,
180
+ bottom: 0,
181
+ left: 0,
182
+ height: '100%'
183
+ },
184
+ 'right-stretch': {
185
+ top: 0,
186
+ bottom: 0,
187
+ right: 0,
188
+ height: '100%'
189
+ },
190
+ 'bottom-stretch': {
191
+ bottom: 0,
192
+ left: 0,
193
+ right: 0,
194
+ width: '100%'
195
+ }
196
+ };
197
+ var _default = exports.default = _Platform.default.OS === 'web' ? webStyles : nativeStyles;
@@ -40,6 +40,7 @@ const ExpandCollapse = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
40
40
  dataSet,
41
41
  ...rest
42
42
  } = _ref;
43
+ const instanceId = (0, _utils.useUniqueId)('ExpandCollapse');
43
44
  const {
44
45
  currentValues: openIds,
45
46
  toggleOneValue: onToggle,
@@ -65,7 +66,8 @@ const ExpandCollapse = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
65
66
  onToggle,
66
67
  resetValues,
67
68
  setValues,
68
- unsetValues
69
+ unsetValues,
70
+ instanceId
69
71
  }) : children
70
72
  })
71
73
  });
@@ -23,7 +23,7 @@ const ExpandCollapseMini = /*#__PURE__*/_react.default.forwardRef((_ref, ref) =>
23
23
  dataSet,
24
24
  ...rest
25
25
  } = _ref;
26
- const expandCollapeMiniPanelId = 'ExpandCollapseMiniPanel';
26
+ const expandCollapeMiniPanelId = (0, _utils.useUniqueId)('ExpandCollapseMiniPanel');
27
27
  const handleChange = (openPanels, event) => {
28
28
  if (typeof onToggle === 'function') {
29
29
  const isOpen = openPanels.length > 0;
@@ -52,7 +52,9 @@ const ExpandCollapseMiniControl = /*#__PURE__*/_react.default.forwardRef((_ref,
52
52
  pressed
53
53
  });
54
54
  const {
55
- size,
55
+ fontSize,
56
+ lineHeight,
57
+ iconSize,
56
58
  icon
57
59
  } = (0, _ThemeProvider.useThemeTokens)('ExpandCollapseMiniControl', tokens, variant, {
58
60
  expanded,
@@ -69,18 +71,38 @@ const ExpandCollapseMiniControl = /*#__PURE__*/_react.default.forwardRef((_ref,
69
71
  hover: linkHover
70
72
  } = linkState || {};
71
73
  const isHovered = hover || linkHover;
74
+ const iconBaselineOffset = 0;
75
+ const hoverTranslateY = 4;
76
+
77
+ // Calculate baseline alignment to vertically center icon with text
78
+ // This combines font and icon metrics with adjustments for visual balance
79
+ const fontBaseline = fontSize / hoverTranslateY; // Quarter of font size - adjusts for text's visual center point
80
+ const iconBaseline = iconSize / hoverTranslateY; // Quarter of icon size - adjusts for icon's visual center point
81
+ const staticOffset = hoverTranslateY; // Fixed downward adjustment to fine-tune vertical alignment
82
+ const sizeCompensation = -Math.abs(iconSize - fontSize); // Compensates when icon and text sizes differ significantly
83
+
84
+ const baselineAlignment = fontBaseline + iconBaseline - staticOffset + sizeCompensation;
72
85
  if (_Platform.default.OS !== 'web') {
86
+ // For native platforms, use baseline alignment with optional offset
73
87
  return {
74
- iconTranslateY: -1
88
+ iconTranslateY: baselineAlignment + iconBaselineOffset
75
89
  };
76
90
  }
77
91
  if (isHovered) {
78
- // Include vertical icon animation on hover alongside built-in Link theme, the size is size4
92
+ // Apply animation offset to the baseline-aligned position
93
+ // When expanded: move icon UP (1.3 the hover distance for clear movement)
94
+ // When collapsed: move icon DOWN (single hover distance)
95
+ const hoverMovementDistance = 1.3;
96
+ const animationOffset = expanded ? -(hoverTranslateY * hoverMovementDistance) : hoverTranslateY;
79
97
  return {
80
- iconTranslateY: (expanded ? -1 : 1) * size
98
+ iconTranslateY: baselineAlignment + iconBaselineOffset + animationOffset
81
99
  };
82
100
  }
83
- return {};
101
+
102
+ // Default state uses baseline alignment with optional offset
103
+ return {
104
+ iconTranslateY: baselineAlignment + iconBaselineOffset
105
+ };
84
106
  };
85
107
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Link.Link, {
86
108
  variant: appearance,
@@ -88,7 +110,9 @@ const ExpandCollapseMiniControl = /*#__PURE__*/_react.default.forwardRef((_ref,
88
110
  iconPosition: iconPosition,
89
111
  tokens: linkState => ({
90
112
  ...linkTokens,
91
- ...getTokens(linkState)
113
+ ...getTokens(linkState),
114
+ iconSize,
115
+ blockLineHeight: lineHeight
92
116
  }),
93
117
  ref: ref,
94
118
  ...presentationOnly,
@@ -17,6 +17,48 @@ var _ViewportProvider = require("../ViewportProvider");
17
17
  var _jsxRuntime = require("react/jsx-runtime");
18
18
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
19
19
  const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.viewProps]);
20
+ const CONTENT_MAX_WIDTH = 'max';
21
+ const CONTENT_FULL_WIDTH = 'full';
22
+
23
+ /**
24
+ * Resolves the maximum width for content based on the provided value and responsive width.
25
+ *
26
+ * @param {number|string|null|undefined} contentMinWidthValue - The minimum width value for the content.
27
+ * Can be a number, a special string constant (e.g., CONTENT_FULL_WIDTH, CONTENT_MAX_WIDTH), or null/undefined.
28
+ * @param {number} responsiveWidth - The responsive width to use when contentMinWidthValue is CONTENT_MAX_WIDTH.
29
+ * @returns {number|string|null} The resolved maximum width value, or null if full width is desired.
30
+ */
31
+ const resolveContentMaxWidth = (contentMinWidthValue, responsiveWidth) => {
32
+ if (!contentMinWidthValue || contentMinWidthValue === CONTENT_FULL_WIDTH) {
33
+ return null;
34
+ }
35
+ if (Number.isFinite(contentMinWidthValue)) {
36
+ return contentMinWidthValue;
37
+ }
38
+ if (contentMinWidthValue === CONTENT_MAX_WIDTH) {
39
+ return responsiveWidth;
40
+ }
41
+ return contentMinWidthValue;
42
+ };
43
+
44
+ /**
45
+ * Calculates the maximum width for a given viewport based on limitWidth and contentMinWidth settings.
46
+ *
47
+ * @param {string} viewportKey - The viewport key ('xs', 'sm', 'md', 'lg', 'xl')
48
+ * @param {boolean} limitWidth - Whether to limit the width to viewport breakpoints
49
+ * @param {any} contentMinWidth - The contentMinWidth prop value
50
+ * @param {number|string|null} maxWidth - The resolved max width value
51
+ * @returns {number|string|null} The calculated maximum width for the viewport
52
+ */
53
+ const getMaxWidthForViewport = (viewportKey, limitWidth, contentMinWidth, maxWidth) => {
54
+ if (limitWidth) {
55
+ return _systemConstants.viewports.map.get(viewportKey === 'xs' ? 'sm' : viewportKey);
56
+ }
57
+ if (contentMinWidth) {
58
+ return maxWidth;
59
+ }
60
+ return viewportKey === 'xl' ? _systemConstants.viewports.map.get('xl') : null;
61
+ };
20
62
 
21
63
  /**
22
64
  * A mobile-first flexbox grid.
@@ -24,7 +66,7 @@ const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_u
24
66
 
25
67
  const FlexGrid = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
26
68
  let {
27
- limitWidth = true,
69
+ limitWidth = false,
28
70
  gutter = true,
29
71
  outsideGutter = true,
30
72
  xsReverse,
@@ -36,35 +78,41 @@ const FlexGrid = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
36
78
  accessibilityRole,
37
79
  children,
38
80
  dataSet,
81
+ contentMinWidth,
39
82
  ...rest
40
83
  } = _ref;
41
84
  const reverseLevel = (0, _helpers.default)([xsReverse, smReverse, mdReverse, lgReverse, xlReverse]);
42
85
  const viewport = (0, _ViewportProvider.useViewport)();
43
86
  const {
87
+ themeOptions,
44
88
  themeOptions: {
45
89
  enableMediaQueryStyleSheet
46
90
  }
47
91
  } = (0, _ThemeProvider.useTheme)();
48
92
  let flexgridStyles;
49
93
  let mediaIds;
94
+ const contentMinWidthValue = (0, _utils.useResponsiveProp)(contentMinWidth);
95
+ const responsiveWidth = (0, _utils.useResponsiveProp)(themeOptions?.contentMaxWidth);
96
+ const maxWidth = resolveContentMaxWidth(contentMinWidthValue, responsiveWidth);
50
97
  const stylesByViewport = {
51
98
  xs: {
99
+ maxWidth: getMaxWidthForViewport('xs', limitWidth, contentMinWidth, maxWidth),
52
100
  flexDirection: reverseLevel[0] ? 'column-reverse' : 'column'
53
101
  },
54
102
  sm: {
55
- maxWidth: limitWidth && _systemConstants.viewports.map.get('sm'),
103
+ maxWidth: getMaxWidthForViewport('sm', limitWidth, contentMinWidth, maxWidth),
56
104
  flexDirection: reverseLevel[1] ? 'column-reverse' : 'column'
57
105
  },
58
106
  md: {
59
- maxWidth: limitWidth && _systemConstants.viewports.map.get('md'),
107
+ maxWidth: getMaxWidthForViewport('md', limitWidth, contentMinWidth, maxWidth),
60
108
  flexDirection: reverseLevel[2] ? 'column-reverse' : 'column'
61
109
  },
62
110
  lg: {
63
- maxWidth: limitWidth && _systemConstants.viewports.map.get('lg'),
111
+ maxWidth: getMaxWidthForViewport('lg', limitWidth, contentMinWidth, maxWidth),
64
112
  flexDirection: reverseLevel[3] ? 'column-reverse' : 'column'
65
113
  },
66
114
  xl: {
67
- maxWidth: limitWidth && _systemConstants.viewports.map.get('xl'),
115
+ maxWidth: getMaxWidthForViewport('xl', limitWidth, contentMinWidth, maxWidth),
68
116
  flexDirection: reverseLevel[4] ? 'column-reverse' : 'column'
69
117
  }
70
118
  };
@@ -158,7 +206,24 @@ FlexGrid.propTypes = {
158
206
  /**
159
207
  * The rows and columns of the Grid. Will typically be `FlexGrid.Row` and `FlexGrid.Col` components.
160
208
  */
161
- children: _propTypes.default.node.isRequired
209
+ children: _propTypes.default.node.isRequired,
210
+ /**
211
+ * The minimum width of the content in the FlexGrid.
212
+ * This prop accepts responsive values for different viewports. If a number is provided,
213
+ * it will be the max content width for the desired viewport.
214
+ * - `xs`: 'max' | 'full' | <number>
215
+ * - `sm`: 'max' | 'full' | <number>
216
+ * - `md`: 'max' | 'full' | <number>
217
+ * - `lg`: 'max' | 'full' | <number>
218
+ * - `xl`: 'max' | 'full' | <number>
219
+ */
220
+ contentMinWidth: _propTypes.default.shape({
221
+ xl: _propTypes.default.oneOfType([_propTypes.default.oneOf(['max', 'full']), _propTypes.default.number]),
222
+ lg: _propTypes.default.oneOfType([_propTypes.default.oneOf(['max', 'full']), _propTypes.default.number]),
223
+ md: _propTypes.default.oneOfType([_propTypes.default.oneOf(['max', 'full']), _propTypes.default.number]),
224
+ sm: _propTypes.default.oneOfType([_propTypes.default.oneOf(['max', 'full']), _propTypes.default.number]),
225
+ xs: _propTypes.default.oneOfType([_propTypes.default.oneOf(['max', 'full']), _propTypes.default.number])
226
+ })
162
227
  };
163
228
  FlexGrid.Row = _Row.default;
164
229
  FlexGrid.Col = _Col.default;
@@ -39,7 +39,9 @@ const Icon = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
39
39
  width: themeTokens.size + themeTokens.width * 2,
40
40
  // sets the diameter of the circle which is the size of the icon plus twice the general padding established to obtain a perfect circle
41
41
  height: themeTokens.size + themeTokens.width * 2
42
- } : {};
42
+ } : {
43
+ padding: themeTokens.padding
44
+ };
43
45
  const getIconContentForMobile = () => {
44
46
  if (Object.keys(paddingStyles).length) {
45
47
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
@@ -149,7 +149,7 @@ InputLabel.propTypes = {
149
149
  /**
150
150
  * Content of an optional `Tooltip`. If set, a tooltip button will be shown next to the label.
151
151
  */
152
- tooltip: _propTypes.default.oneOfType([_shared.default, _propTypes.default.string]),
152
+ tooltip: _propTypes.default.oneOfType([_propTypes.default.shape(_shared.default), _propTypes.default.string]),
153
153
  /**
154
154
  * Current number of characterts of an input text.
155
155
  */
@@ -123,7 +123,7 @@ InputSupports.propTypes = {
123
123
  * 1. `tooltip` as a string - The content of the tooltip.
124
124
  * 2. `tooltip` as an object - Tooltip component props to be passed.
125
125
  */
126
- tooltip: _propTypes.default.oneOfType([_shared.default, _propTypes.default.string]),
126
+ tooltip: _propTypes.default.oneOfType([_propTypes.default.shape(_shared.default), _propTypes.default.string]),
127
127
  /**
128
128
  * Use to visually mark an input as valid or invalid.
129
129
  */
@@ -16,6 +16,7 @@ var _dictionary = _interopRequireDefault(require("./dictionary"));
16
16
  var _ViewportProvider = require("../ViewportProvider");
17
17
  var _jsxRuntime = require("react/jsx-runtime");
18
18
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
19
+ const CONTENT_MAX_WIDTH = 'max';
19
20
  const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.viewProps]);
20
21
  const selectContainerStyles = tokens => ({
21
22
  ...tokens
@@ -70,13 +71,13 @@ const selectDismissButtonContainerStyles = _ref4 => {
70
71
  placeContent: 'start'
71
72
  };
72
73
  };
73
- const selectContentContainerStyle = (themeTokens, maxWidth, system, viewport) => ({
74
- maxWidth: system && viewport === 'xl' ? maxWidth : '100%',
74
+ const selectContentContainerStyle = (themeTokens, maxWidth, system, viewport, useContentMaxWidth) => ({
75
+ maxWidth: system && (useContentMaxWidth || viewport === 'xl') ? maxWidth : '100%',
75
76
  width: '100%',
76
77
  paddingRight: themeTokens?.containerPaddingRight,
77
78
  paddingLeft: themeTokens?.containerPaddingLeft
78
79
  });
79
- const getMediaQueryStyles = (themeTokens, themeOptions, maxWidth, mediaIdsRef, dismissible, viewport, system) => {
80
+ const getMediaQueryStyles = (themeTokens, themeOptions, maxWidth, mediaIdsRef, dismissible, viewport, system, useContentMaxWidth) => {
80
81
  const transformedSelectContainerStyles = Object.entries(themeTokens).reduce((acc, _ref5) => {
81
82
  let [vp, viewportTokens] = _ref5;
82
83
  acc[vp] = {
@@ -99,7 +100,7 @@ const getMediaQueryStyles = (themeTokens, themeOptions, maxWidth, mediaIdsRef, d
99
100
  const transformedSelectContentContainerStyles = Object.entries(themeTokens).reduce((acc, _ref6) => {
100
101
  let [vp, viewportTokens] = _ref6;
101
102
  acc[vp] = {
102
- ...selectContentContainerStyle(viewportTokens, maxWidth, system, vp),
103
+ ...selectContentContainerStyle(viewportTokens, maxWidth, system, vp, useContentMaxWidth),
103
104
  flexDirection: 'row',
104
105
  flexShrink: 1,
105
106
  justifyContent: 'space-between',
@@ -176,7 +177,7 @@ const getMediaQueryStyles = (themeTokens, themeOptions, maxWidth, mediaIdsRef, d
176
177
  selectDismissIconPropsStyles
177
178
  };
178
179
  };
179
- const getDefaultStyles = (themeTokens, themeOptions, maxWidth, dismissible, viewport, system) => ({
180
+ const getDefaultStyles = (themeTokens, themeOptions, maxWidth, dismissible, viewport, system, useContentMaxWidth) => ({
180
181
  containerStyles: {
181
182
  container: {
182
183
  flexDirection: 'column',
@@ -188,7 +189,7 @@ const getDefaultStyles = (themeTokens, themeOptions, maxWidth, dismissible, view
188
189
  flexDirection: 'row',
189
190
  flexShrink: 1,
190
191
  justifyContent: 'space-between',
191
- ...selectContentContainerStyle(themeTokens, maxWidth, system, viewport),
192
+ ...selectContentContainerStyle(themeTokens, maxWidth, system, viewport, useContentMaxWidth),
192
193
  ...(system && {
193
194
  alignSelf: 'center'
194
195
  })
@@ -287,6 +288,7 @@ const Notification = /*#__PURE__*/_react.default.forwardRef((_ref7, ref) => {
287
288
  tokens,
288
289
  variant,
289
290
  onDismiss,
291
+ contentMinWidth,
290
292
  ...rest
291
293
  } = _ref7;
292
294
  const [isDismissed, setIsDismissed] = _react.default.useState(false);
@@ -309,6 +311,7 @@ const Notification = /*#__PURE__*/_react.default.forwardRef((_ref7, ref) => {
309
311
  system: isSystemEnabled,
310
312
  viewport
311
313
  });
314
+ const useContentMaxWidth = (0, _utils.useResponsiveProp)(contentMinWidth) === CONTENT_MAX_WIDTH;
312
315
  const maxWidth = (0, _utils.useResponsiveProp)(themeOptions?.contentMaxWidth, _systemConstants.viewports.map.get(_systemConstants.viewports.xl));
313
316
  const notificationComponentRef = _react.default.useRef({
314
317
  containerStyles: {},
@@ -331,9 +334,9 @@ const Notification = /*#__PURE__*/_react.default.forwardRef((_ref7, ref) => {
331
334
  selectDismissIconPropsIds: {}
332
335
  });
333
336
  if (enableMediaQueryStyleSheet) {
334
- notificationComponentRef.current = getMediaQueryStyles(themeTokens, themeOptions, maxWidth, mediaIdsRef, dismissible, viewport, isSystemEnabled);
337
+ notificationComponentRef.current = getMediaQueryStyles(themeTokens, themeOptions, maxWidth, mediaIdsRef, dismissible, viewport, isSystemEnabled, useContentMaxWidth);
335
338
  } else {
336
- notificationComponentRef.current = getDefaultStyles(themeTokens, themeOptions, maxWidth, dismissible, viewport, isSystemEnabled);
339
+ notificationComponentRef.current = getDefaultStyles(themeTokens, themeOptions, maxWidth, dismissible, viewport, isSystemEnabled, useContentMaxWidth);
337
340
  }
338
341
  if (isDismissed) {
339
342
  return null;
@@ -430,6 +433,22 @@ Notification.propTypes = {
430
433
  * Callback function called when the dismiss button is clicked
431
434
  */
432
435
  onDismiss: _propTypes.default.func,
436
+ /**
437
+ * The minimum width of the content in the Notification when using the system variant.
438
+ * This prop accepts responsive values for different viewports.
439
+ * - `xs`: 'max' | 'full'
440
+ * - `sm`: 'max' | 'full'
441
+ * - `md`: 'max' | 'full'
442
+ * - `lg`: 'max' | 'full'
443
+ * - `xl`: 'max' | 'full'
444
+ */
445
+ contentMinWidth: _propTypes.default.shape({
446
+ xl: _propTypes.default.oneOf(['max', 'full']),
447
+ lg: _propTypes.default.oneOf(['max', 'full']),
448
+ md: _propTypes.default.oneOf(['max', 'full']),
449
+ sm: _propTypes.default.oneOf(['max', 'full']),
450
+ xs: _propTypes.default.oneOf(['max', 'full'])
451
+ }),
433
452
  tokens: (0, _utils.getTokensPropType)('Notification'),
434
453
  variant: _utils.variantProp.propType
435
454
  };
@@ -13,6 +13,7 @@ var _StackView = _interopRequireDefault(require("../StackView"));
13
13
  var _utils = require("../utils");
14
14
  var _HorizontalScroll = _interopRequireWildcard(require("../HorizontalScroll"));
15
15
  var _TabsItem = _interopRequireDefault(require("./TabsItem"));
16
+ var _TabsDropdown = _interopRequireDefault(require("./TabsDropdown"));
16
17
  var _jsxRuntime = require("react/jsx-runtime");
17
18
  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); }
18
19
  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; }
@@ -48,6 +49,12 @@ const getStackViewTokens = variant => {
48
49
  * Tabs renders a horizontally-scrolling menu of selectable buttons which may link
49
50
  * to a page or control what content is displayed on this page.
50
51
  *
52
+ * By default, Tabs always renders as horizontal scrolling tabs regardless of viewport.
53
+ * To enable dropdown mode, you must explicitly pass `variant={{ dropdown: true }}`.
54
+ * When dropdown is enabled, it will only render as a dropdown on mobile and tablet
55
+ * viewports (XS and SM). On larger viewports (MD, LG, XL), it will still render as
56
+ * horizontal tabs even with dropdown enabled.
57
+ *
51
58
  * If you are using Tabs to navigate to a new page (web-only) you should pass
52
59
  * `navigation`as the `accessibilityRole` to te Tabs component, this will cause
53
60
  * TabItems to default to a role of link and obtain aria-current behaviour.
@@ -93,6 +100,31 @@ const Tabs = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
93
100
  const parentAccessibilityRole = restProps.accessibilityRole ?? 'tablist';
94
101
  const defaultTabItemAccessibiltyRole = getDefaultTabItemAccessibilityRole(parentAccessibilityRole);
95
102
  const stackViewTokens = getStackViewTokens(variant);
103
+
104
+ // Render dropdown only if explicitly requested via variant AND viewport is xs or sm
105
+ const isSmallViewport = (0, _utils.useResponsiveProp)({
106
+ xs: true,
107
+ sm: true,
108
+ md: false,
109
+ lg: false,
110
+ xl: false
111
+ }, false);
112
+ const shouldRenderDropdown = variant?.dropdown === true && isSmallViewport;
113
+ if (shouldRenderDropdown) {
114
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_TabsDropdown.default, {
115
+ ref: ref,
116
+ tokens: tokens,
117
+ itemTokens: itemTokens,
118
+ variant: variant,
119
+ value: currentValue,
120
+ onChange: setValue,
121
+ items: items,
122
+ LinkRouter: LinkRouter,
123
+ linkRouterProps: linkRouterProps,
124
+ accessibilityRole: parentAccessibilityRole === 'tablist' ? 'button' : parentAccessibilityRole,
125
+ ...restProps
126
+ });
127
+ }
96
128
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_HorizontalScroll.default, {
97
129
  ref: ref,
98
130
  ScrollButton: _HorizontalScroll.HorizontalScrollButton,
@@ -152,13 +184,13 @@ const Tabs = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
152
184
  Tabs.displayName = 'Tabs';
153
185
  Tabs.propTypes = {
154
186
  ...selectedSystemPropTypes,
155
- ..._utils.withLinkRouter.PropTypes,
187
+ ..._utils.withLinkRouter.propTypes,
156
188
  /**
157
189
  * Array of `TabsItem`s
158
190
  */
159
191
  items: _propTypes.default.arrayOf(_propTypes.default.shape({
160
192
  ...selectedItemPropTypes,
161
- ..._utils.withLinkRouter.PropTypes,
193
+ ..._utils.withLinkRouter.propTypes,
162
194
  href: _propTypes.default.string,
163
195
  label: _propTypes.default.string,
164
196
  id: _propTypes.default.string,