@telus-uds/components-base 3.23.0 → 3.25.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 (73) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/lib/cjs/Button/ButtonGroup.js +9 -2
  3. package/lib/cjs/Card/CardBase.js +97 -17
  4. package/lib/cjs/Card/PressableCardBase.js +12 -8
  5. package/lib/cjs/Carousel/Carousel.js +35 -4
  6. package/lib/cjs/FlexGrid/FlexGrid.js +31 -35
  7. package/lib/cjs/HorizontalScroll/HorizontalScroll.js +5 -2
  8. package/lib/cjs/Icon/Icon.js +3 -0
  9. package/lib/cjs/IconButton/IconButton.js +15 -5
  10. package/lib/cjs/Listbox/GroupControl.js +12 -6
  11. package/lib/cjs/Listbox/Listbox.js +41 -7
  12. package/lib/cjs/Listbox/ListboxGroup.js +139 -8
  13. package/lib/cjs/Listbox/ListboxOverlay.js +10 -5
  14. package/lib/cjs/Listbox/SecondLevelHeader.js +201 -0
  15. package/lib/cjs/Listbox/dictionary.js +14 -0
  16. package/lib/cjs/Shortcuts/Shortcuts.js +169 -0
  17. package/lib/cjs/Shortcuts/ShortcutsItem.js +280 -0
  18. package/lib/cjs/Shortcuts/index.js +16 -0
  19. package/lib/cjs/TextInput/TextInputBase.js +2 -3
  20. package/lib/cjs/Tooltip/Tooltip.native.js +2 -0
  21. package/lib/cjs/index.js +15 -0
  22. package/lib/cjs/utils/index.js +9 -1
  23. package/lib/cjs/utils/resolveContentMaxWidth.js +30 -0
  24. package/lib/esm/Button/ButtonGroup.js +9 -2
  25. package/lib/esm/Card/CardBase.js +97 -17
  26. package/lib/esm/Card/PressableCardBase.js +10 -8
  27. package/lib/esm/Carousel/Carousel.js +37 -6
  28. package/lib/esm/FlexGrid/FlexGrid.js +31 -35
  29. package/lib/esm/HorizontalScroll/HorizontalScroll.js +6 -3
  30. package/lib/esm/Icon/Icon.js +3 -0
  31. package/lib/esm/IconButton/IconButton.js +15 -5
  32. package/lib/esm/Listbox/GroupControl.js +12 -6
  33. package/lib/esm/Listbox/Listbox.js +41 -7
  34. package/lib/esm/Listbox/ListboxGroup.js +141 -10
  35. package/lib/esm/Listbox/ListboxOverlay.js +10 -5
  36. package/lib/esm/Listbox/SecondLevelHeader.js +194 -0
  37. package/lib/esm/Listbox/dictionary.js +8 -0
  38. package/lib/esm/Shortcuts/Shortcuts.js +160 -0
  39. package/lib/esm/Shortcuts/ShortcutsItem.js +273 -0
  40. package/lib/esm/Shortcuts/index.js +3 -0
  41. package/lib/esm/TextInput/TextInputBase.js +2 -3
  42. package/lib/esm/Tooltip/Tooltip.native.js +2 -0
  43. package/lib/esm/index.js +1 -0
  44. package/lib/esm/utils/index.js +2 -1
  45. package/lib/esm/utils/resolveContentMaxWidth.js +24 -0
  46. package/lib/package.json +2 -2
  47. package/package.json +2 -2
  48. package/src/Button/ButtonGroup.jsx +20 -3
  49. package/src/Card/CardBase.jsx +113 -14
  50. package/src/Card/PressableCardBase.jsx +17 -5
  51. package/src/Carousel/Carousel.jsx +38 -6
  52. package/src/FlexGrid/FlexGrid.jsx +30 -39
  53. package/src/HorizontalScroll/HorizontalScroll.jsx +6 -3
  54. package/src/Icon/Icon.jsx +3 -0
  55. package/src/IconButton/IconButton.jsx +12 -5
  56. package/src/Listbox/GroupControl.jsx +41 -33
  57. package/src/Listbox/Listbox.jsx +41 -2
  58. package/src/Listbox/ListboxGroup.jsx +158 -26
  59. package/src/Listbox/ListboxOverlay.jsx +18 -5
  60. package/src/Listbox/SecondLevelHeader.jsx +182 -0
  61. package/src/Listbox/dictionary.js +8 -0
  62. package/src/Shortcuts/Shortcuts.jsx +174 -0
  63. package/src/Shortcuts/ShortcutsItem.jsx +297 -0
  64. package/src/Shortcuts/index.js +4 -0
  65. package/src/TextInput/TextInputBase.jsx +2 -2
  66. package/src/Tooltip/Tooltip.native.jsx +2 -1
  67. package/src/index.js +1 -0
  68. package/src/utils/index.js +1 -0
  69. package/src/utils/resolveContentMaxWidth.js +28 -0
  70. package/types/Listbox.d.ts +24 -0
  71. package/types/Shortcuts.d.ts +136 -0
  72. package/types/Status.d.ts +42 -0
  73. package/types/index.d.ts +15 -0
@@ -9,8 +9,15 @@ import { applyShadowToken } from '../ThemeProvider';
9
9
  import { getTokensPropType, responsiveProps, useResponsiveProp, formatImageSource } from '../utils';
10
10
  import { a11yProps, viewProps, selectSystemProps } from '../utils/props';
11
11
  import backgroundImageStylesMap from './backgroundImageStylesMap';
12
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
12
+ import FlexGrid from '../FlexGrid/FlexGrid';
13
+ import FlexGridRow from '../FlexGrid/Row';
14
+ import FlexGridCol from '../FlexGrid/Col';
15
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
13
16
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
17
+ const GRID_COLUMNS = 12;
18
+ const isOverlayColor = color => {
19
+ return color && typeof color === 'string' && color.startsWith('rgba(');
20
+ };
14
21
  const setBackgroundImage = _ref => {
15
22
  let {
16
23
  src,
@@ -24,12 +31,9 @@ const setBackgroundImage = _ref => {
24
31
  const borderRadius = cardStyle?.borderRadius || 0;
25
32
  const borderWidth = cardStyle?.borderWidth || 0;
26
33
  const adjustedBorderRadius = Math.max(0, borderRadius - borderWidth);
27
-
28
- // For contain mode with position and align, use CSS background properties for web
29
34
  if (backgroundImageResizeMode === 'contain' && backgroundImagePosition && backgroundImageAlign) {
30
35
  const positionKey = `${backgroundImagePosition}-${backgroundImageAlign}`;
31
36
  if (Platform.OS === 'web') {
32
- // Create background position based on position and align
33
37
  let backgroundPosition;
34
38
  switch (positionKey) {
35
39
  case 'top-start':
@@ -73,7 +77,6 @@ const setBackgroundImage = _ref => {
73
77
  children: content
74
78
  });
75
79
  }
76
- // For React Native, apply positioning styles with full dimensions
77
80
  const positionStyles = backgroundImageStylesMap[positionKey] || {};
78
81
  return /*#__PURE__*/_jsxs(View, {
79
82
  style: [staticStyles.containContainer, {
@@ -92,8 +95,6 @@ const setBackgroundImage = _ref => {
92
95
  })]
93
96
  });
94
97
  }
95
-
96
- // Use ImageBackground for all other resize modes and React Native
97
98
  return /*#__PURE__*/_jsx(ImageBackground, {
98
99
  source: src,
99
100
  imageStyle: {
@@ -119,6 +120,10 @@ export const selectStyles = _ref2 => {
119
120
  paddingLeft,
120
121
  paddingRight,
121
122
  paddingTop,
123
+ marginTop,
124
+ marginBottom,
125
+ marginLeft,
126
+ marginRight,
122
127
  minWidth,
123
128
  shadow,
124
129
  backgroundGradient,
@@ -126,9 +131,18 @@ export const selectStyles = _ref2 => {
126
131
  maxHeight,
127
132
  overflowY
128
133
  } = _ref2;
134
+ const hasGradient = (gradient || backgroundGradient) && Platform.OS === 'web';
135
+ let backgroundImageValue = null;
136
+ if (hasGradient) {
137
+ const gradientObj = gradient || backgroundGradient;
138
+ const gradientString = `linear-gradient(${gradientObj.angle}deg, ${gradientObj.stops[0].color}, ${gradientObj.stops[1].color})`;
139
+ const shouldApplyOverlay = (gradient || backgroundGradient && backgroundColor && backgroundColor !== 'transparent') && isOverlayColor(backgroundColor);
140
+ backgroundImageValue = shouldApplyOverlay ? `linear-gradient(${backgroundColor}, ${backgroundColor}), ${gradientString}` : gradientString;
141
+ }
142
+ const boxShadowColor = isOverlayColor(backgroundColor) ? backgroundColor : 'white';
129
143
  return {
130
144
  flex,
131
- backgroundColor,
145
+ backgroundColor: hasGradient ? 'transparent' : backgroundColor,
132
146
  borderColor,
133
147
  borderRadius,
134
148
  borderWidth,
@@ -136,16 +150,20 @@ export const selectStyles = _ref2 => {
136
150
  paddingLeft,
137
151
  paddingRight,
138
152
  paddingTop,
153
+ marginTop,
154
+ marginBottom,
155
+ marginLeft,
156
+ marginRight,
139
157
  minWidth,
140
158
  ...applyShadowToken(shadow),
141
159
  ...(gradient && Platform.OS === 'web' ? {
142
- backgroundImage: `linear-gradient(${gradient.angle}deg, ${gradient.stops[0].color}, ${gradient.stops[1].color})`,
160
+ backgroundImage: backgroundImageValue,
143
161
  backgroundOrigin: `border-box`,
144
- boxShadow: `inset 0 1000px white`,
162
+ boxShadow: `inset 0 1000px ${boxShadowColor}`,
145
163
  border: `${borderWidth}px solid transparent`
146
164
  } : {}),
147
165
  ...(backgroundGradient && Platform.OS === 'web' ? {
148
- backgroundImage: `linear-gradient(${backgroundGradient.angle}deg, ${backgroundGradient.stops[0].color}, ${backgroundGradient.stops[1].color})`
166
+ backgroundImage: backgroundImageValue
149
167
  } : {}),
150
168
  ...(Platform.OS === 'web' ? {
151
169
  maxHeight,
@@ -164,9 +182,11 @@ const CardBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
164
182
  tokens,
165
183
  dataSet,
166
184
  backgroundImage,
185
+ fullBleedContent,
186
+ cardState,
167
187
  ...rest
168
188
  } = _ref3;
169
- const cardStyle = selectStyles(typeof tokens === 'function' ? tokens() : tokens);
189
+ const cardStyle = selectStyles(typeof tokens === 'function' ? tokens(cardState) : tokens);
170
190
  const props = selectProps(rest);
171
191
  let content = children;
172
192
  const {
@@ -180,9 +200,13 @@ const CardBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
180
200
  const backgroundImagePosition = useResponsiveProp(position);
181
201
  const backgroundImageAlign = useResponsiveProp(align);
182
202
  const imageSourceViewport = formatImageSource(useResponsiveProp(src));
203
+ const {
204
+ content: fullBleedImageContent,
205
+ position: fullBleedContentPosition,
206
+ imgCol
207
+ } = fullBleedContent || {};
208
+ const fullBleedPosition = useResponsiveProp(fullBleedContentPosition, 'bottom');
183
209
  if (backgroundImage && src) {
184
- // When there's a background image, separate the padding from the container style
185
- // so the image can fill the entire container without padding interference
186
210
  const {
187
211
  paddingTop,
188
212
  paddingBottom,
@@ -190,8 +214,6 @@ const CardBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
190
214
  paddingRight,
191
215
  ...containerStyle
192
216
  } = cardStyle;
193
-
194
- // Only create padding wrapper if there's actually padding defined
195
217
  const hasPadding = paddingTop || paddingBottom || paddingLeft || paddingRight;
196
218
  const paddedContent = hasPadding ? /*#__PURE__*/_jsx(View, {
197
219
  style: {
@@ -219,6 +241,53 @@ const CardBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
219
241
  children: content
220
242
  });
221
243
  }
244
+ if (fullBleedContent && fullBleedImageContent) {
245
+ const {
246
+ paddingTop,
247
+ paddingBottom,
248
+ paddingLeft,
249
+ paddingRight,
250
+ ...containerStyle
251
+ } = cardStyle;
252
+ const imageColumns = imgCol || {
253
+ xs: GRID_COLUMNS
254
+ };
255
+ const textColumns = {};
256
+ Object.keys(imageColumns).forEach(breakpoint => {
257
+ textColumns[breakpoint] = GRID_COLUMNS - (imageColumns[breakpoint] || GRID_COLUMNS);
258
+ });
259
+ const imageFirst = fullBleedPosition === 'top' || fullBleedPosition === 'left';
260
+ const imageColContent = /*#__PURE__*/_jsx(FlexGridCol, {
261
+ ...imageColumns,
262
+ style: staticStyles.fullBleedImageCol,
263
+ children: fullBleedImageContent
264
+ });
265
+ const textColContent = /*#__PURE__*/_jsx(FlexGridCol, {
266
+ ...textColumns,
267
+ style: {
268
+ paddingTop,
269
+ paddingBottom,
270
+ paddingLeft,
271
+ paddingRight
272
+ },
273
+ children: children
274
+ });
275
+ return /*#__PURE__*/_jsx(View, {
276
+ style: containerStyle,
277
+ dataSet: dataSet,
278
+ ref: ref,
279
+ ...props,
280
+ children: /*#__PURE__*/_jsx(FlexGrid, {
281
+ children: /*#__PURE__*/_jsx(FlexGridRow, {
282
+ children: imageFirst ? /*#__PURE__*/_jsxs(_Fragment, {
283
+ children: [imageColContent, textColContent]
284
+ }) : /*#__PURE__*/_jsxs(_Fragment, {
285
+ children: [textColContent, imageColContent]
286
+ })
287
+ })
288
+ })
289
+ });
290
+ }
222
291
  return /*#__PURE__*/_jsx(View, {
223
292
  style: cardStyle,
224
293
  dataSet: dataSet,
@@ -228,6 +297,13 @@ const CardBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
228
297
  });
229
298
  });
230
299
  CardBase.displayName = 'CardBase';
300
+ export const fullBleedContentPropTypes = PropTypes.shape({
301
+ content: PropTypes.node.isRequired,
302
+ alt: PropTypes.string,
303
+ position: responsiveProps.getTypeOptionallyByViewport(PropTypes.oneOf(['bottom', 'left', 'right', 'top'])),
304
+ align: responsiveProps.getTypeOptionallyByViewport(PropTypes.oneOf(['start', 'end', 'center', 'stretch'])),
305
+ imgCol: PropTypes.object
306
+ });
231
307
  const staticStyles = StyleSheet.create({
232
308
  imageBackground: {
233
309
  width: '100%',
@@ -249,6 +325,9 @@ const staticStyles = StyleSheet.create({
249
325
  position: 'absolute',
250
326
  width: '100%',
251
327
  height: '100%'
328
+ },
329
+ fullBleedImageCol: {
330
+ padding: 0
252
331
  }
253
332
  });
254
333
  CardBase.propTypes = {
@@ -266,6 +345,7 @@ CardBase.propTypes = {
266
345
  resizeMode: responsiveProps.getTypeOptionallyByViewport(PropTypes.oneOf(['cover', 'contain', 'stretch', 'repeat', 'center'])),
267
346
  position: responsiveProps.getTypeOptionallyByViewport(PropTypes.oneOf(['bottom', 'left', 'right', 'top'])),
268
347
  align: responsiveProps.getTypeOptionallyByViewport(PropTypes.oneOf(['start', 'end', 'center', 'stretch']))
269
- })
348
+ }),
349
+ fullBleedContent: fullBleedContentPropTypes
270
350
  };
271
351
  export default CardBase;
@@ -7,10 +7,10 @@ import StyleSheet from "react-native-web/dist/exports/StyleSheet";
7
7
  import { useViewport } from '../ViewportProvider';
8
8
  import { applyOuterBorder, validateThemeTokens } from '../ThemeProvider';
9
9
  import { a11yProps, clickProps, focusHandlerProps, getTokensSetPropType, linkProps, resolvePressableState, resolvePressableTokens, selectSystemProps, selectTokens, variantProp, viewProps, withLinkRouter } from '../utils';
10
- import CardBase from './CardBase';
10
+ import CardBase, { fullBleedContentPropTypes } from './CardBase';
11
11
  import { jsx as _jsx } from "react/jsx-runtime";
12
12
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, focusHandlerProps, viewProps]);
13
- const tokenKeys = ['flex', 'backgroundColor', 'borderColor', 'gradient', 'borderRadius', 'borderWidth', 'paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop', 'minWidth', 'shadow', 'contentAlignItems', 'contentJustifyContent', 'contentFlexGrow', 'contentFlexShrink',
13
+ const tokenKeys = ['flex', 'backgroundColor', 'borderColor', 'gradient', 'borderRadius', 'borderWidth', 'paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop', 'marginTop', 'marginBottom', 'marginLeft', 'marginRight', 'minWidth', 'shadow', 'contentAlignItems', 'contentJustifyContent', 'contentFlexGrow', 'contentFlexShrink',
14
14
  // Outer border tokens. TODO: centralise common token sets like these as part of
15
15
  // https://github.com/telus/universal-design-system/issues/782
16
16
  'outerBorderColor', 'outerBorderWidth', 'outerBorderGap', 'icon', 'iconBackgroundColor', 'iconColor', 'iconSize', 'inputBackgroundColor', 'inputBorderColor', 'inputBorderRadius', 'inputBorderWidth', 'inputHeight', 'inputShadow', 'inputWidth'];
@@ -32,6 +32,7 @@ const PressableCardBase = /*#__PURE__*/React.forwardRef((_ref, ref) => {
32
32
  hrefAttrs,
33
33
  dataSet,
34
34
  backgroundImage,
35
+ fullBleedContent,
35
36
  accessibilityRole = href ? 'link' : undefined,
36
37
  ...rawRest
37
38
  } = _ref;
@@ -125,10 +126,7 @@ const PressableCardBase = /*#__PURE__*/React.forwardRef((_ref, ref) => {
125
126
  setFocused(false);
126
127
  setPressed(false);
127
128
  },
128
- style: {
129
- ...staticStyles.linkContainer,
130
- textDecoration: 'none'
131
- },
129
+ style: staticStyles.linkContainer,
132
130
  ...(hrefAttrs || {}),
133
131
  role: accessibilityRole,
134
132
  children: /*#__PURE__*/_jsx(CardBase, {
@@ -138,6 +136,7 @@ const PressableCardBase = /*#__PURE__*/React.forwardRef((_ref, ref) => {
138
136
  hovered
139
137
  }),
140
138
  backgroundImage: backgroundImage,
139
+ fullBleedContent: fullBleedContent,
141
140
  children: typeof children === 'function' ? children(getCardState({
142
141
  pressed,
143
142
  focused,
@@ -162,6 +161,7 @@ const PressableCardBase = /*#__PURE__*/React.forwardRef((_ref, ref) => {
162
161
  children: pressableState => /*#__PURE__*/_jsx(CardBase, {
163
162
  tokens: getCardTokens(pressableState),
164
163
  backgroundImage: backgroundImage,
164
+ fullBleedContent: fullBleedContent,
165
165
  children: typeof children === 'function' ? children(getCardState(pressableState)) : children
166
166
  })
167
167
  });
@@ -175,7 +175,8 @@ const staticStyles = StyleSheet.create({
175
175
  flex: 1,
176
176
  display: 'flex',
177
177
  alignItems: 'stretch',
178
- justifyContent: 'flex-start'
178
+ justifyContent: 'flex-start',
179
+ textDecorationLine: 'none'
179
180
  }
180
181
  });
181
182
  PressableCardBase.displayName = 'PressableCardBase';
@@ -195,6 +196,7 @@ PressableCardBase.propTypes = {
195
196
  resizeMode: PropTypes.oneOfType([PropTypes.oneOf(['cover', 'contain', 'stretch', 'repeat', 'center']), PropTypes.object]),
196
197
  position: PropTypes.oneOfType([PropTypes.oneOf(['bottom', 'left', 'right', 'top']), PropTypes.object]),
197
198
  align: PropTypes.oneOfType([PropTypes.oneOf(['start', 'end', 'center', 'stretch']), PropTypes.object])
198
- })
199
+ }),
200
+ fullBleedContent: fullBleedContentPropTypes
199
201
  };
200
202
  export default withLinkRouter(PressableCardBase);
@@ -6,9 +6,9 @@ import StyleSheet from "react-native-web/dist/exports/StyleSheet";
6
6
  import Platform from "react-native-web/dist/exports/Platform";
7
7
  import Dimensions from "react-native-web/dist/exports/Dimensions";
8
8
  import PropTypes from 'prop-types';
9
- import { useThemeTokens } from '../ThemeProvider';
9
+ import { useThemeTokens, useTheme } from '../ThemeProvider';
10
10
  import { useViewport } from '../ViewportProvider';
11
- import { getTokensPropType, getA11yPropsFromHtmlTag, layoutTags, variantProp, selectSystemProps, a11yProps, viewProps, useCopy, unpackFragment, isTouchDevice } from '../utils';
11
+ import { getTokensPropType, getA11yPropsFromHtmlTag, layoutTags, variantProp, selectSystemProps, a11yProps, viewProps, useCopy, unpackFragment, isTouchDevice, useResponsiveProp, resolveContentMaxWidth } from '../utils';
12
12
  import { useA11yInfo } from '../A11yInfoProvider';
13
13
  import { CarouselProvider } from './CarouselContext';
14
14
  import CarouselItem from './CarouselItem';
@@ -203,11 +203,18 @@ const selectRootContainerStyles = (enableHero, viewport) => {
203
203
  }
204
204
  return {};
205
205
  };
206
- const selectMainContainerStyles = (enableHero, viewport) => {
206
+ const selectMainContainerStyles = (enableHero, viewport, maxWidth) => {
207
207
  if (enableHero && viewport === 'xl' && Platform.OS === 'web') {
208
208
  return {
209
209
  width: '100%',
210
- maxWidth: 1200
210
+ maxWidth: maxWidth || 1200
211
+ };
212
+ }
213
+ if (maxWidth !== null && maxWidth !== undefined) {
214
+ return {
215
+ maxWidth,
216
+ alignSelf: 'center',
217
+ width: '100%'
211
218
  };
212
219
  }
213
220
  return {};
@@ -354,11 +361,18 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
354
361
  loopDuration = transitionDuration,
355
362
  autoPlay = false,
356
363
  enablePeeking = false,
364
+ contentMaxWidth,
357
365
  ...rest
358
366
  } = _ref3;
359
367
  let childrenArray = unpackFragment(children);
360
368
  const isTransitioningRef = React.useRef(false);
361
369
  const viewport = useViewport();
370
+ const {
371
+ themeOptions
372
+ } = useTheme();
373
+ const contentMaxWidthValue = useResponsiveProp(contentMaxWidth);
374
+ const responsiveWidth = useResponsiveProp(themeOptions?.contentMaxWidth);
375
+ const maxWidth = resolveContentMaxWidth(contentMaxWidthValue, responsiveWidth);
362
376
  const totalItems = getTotalItems(enableDisplayMultipleItemsPerSlide, childrenArray, viewport);
363
377
  const autoPlayFeatureEnabled = autoPlay && slideDuration > 0 && transitionDuration > 0 && totalItems > 1;
364
378
  // if `Carousel` only has one `Carousel.Item`, convert this to a single-item array
@@ -889,7 +903,7 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
889
903
  return /*#__PURE__*/_jsxs(View, {
890
904
  style: selectRootContainerStyles(enableHero, viewport),
891
905
  children: [/*#__PURE__*/_jsx(View, {
892
- style: selectMainContainerStyles(enableHero, viewport),
906
+ style: selectMainContainerStyles(enableHero, viewport, maxWidth),
893
907
  children: /*#__PURE__*/_jsxs(CarouselProvider, {
894
908
  activeIndex: activeIndex,
895
909
  goTo: goTo,
@@ -1247,7 +1261,24 @@ Carousel.propTypes = {
1247
1261
  * If set to `true`, the Carousel will show multiple slides at once
1248
1262
  * - Default value is `false`
1249
1263
  */
1250
- enableDisplayMultipleItemsPerSlide: PropTypes.bool
1264
+ enableDisplayMultipleItemsPerSlide: PropTypes.bool,
1265
+ /**
1266
+ * The maximum width of the content in the Carousel.
1267
+ * This prop accepts responsive values for different viewports. If a number is provided,
1268
+ * it will be the max content width for the desired viewport.
1269
+ * - `xs`: 'max' | 'full' | <number>
1270
+ * - `sm`: 'max' | 'full' | <number>
1271
+ * - `md`: 'max' | 'full' | <number>
1272
+ * - `lg`: 'max' | 'full' | <number>
1273
+ * - `xl`: 'max' | 'full' | <number>
1274
+ */
1275
+ contentMaxWidth: PropTypes.shape({
1276
+ xl: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
1277
+ lg: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
1278
+ md: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
1279
+ sm: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
1280
+ xs: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number])
1281
+ })
1251
1282
  };
1252
1283
  Carousel.Item = CarouselItem;
1253
1284
  Carousel.displayName = 'Carousel';
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { viewports } from '@telus-uds/system-constants';
4
4
  import { a11yProps, viewProps, getA11yPropsFromHtmlTag, layoutTags, selectSystemProps, BaseView, StyleSheet, createMediaQueryStyles, useResponsiveProp } from '../utils';
5
+ import resolveContentMaxWidth from '../utils/resolveContentMaxWidth';
5
6
  import Row from './Row';
6
7
  import Col from './Col';
7
8
  import GutterContext from './providers/GutterContext';
@@ -10,47 +11,24 @@ import { useTheme } from '../ThemeProvider';
10
11
  import { useViewport } from '../ViewportProvider';
11
12
  import { jsx as _jsx } from "react/jsx-runtime";
12
13
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
13
- const CONTENT_MAX_WIDTH = 'max';
14
- const CONTENT_FULL_WIDTH = 'full';
15
14
 
16
15
  /**
17
- * Resolves the maximum width for content based on the provided value and responsive width.
18
- *
19
- * @param {number|string|null|undefined} contentMinWidthValue - The minimum width value for the content.
20
- * Can be a number, a special string constant (e.g., CONTENT_FULL_WIDTH, CONTENT_MAX_WIDTH), or null/undefined.
21
- * @param {number} responsiveWidth - The responsive width to use when contentMinWidthValue is CONTENT_MAX_WIDTH.
22
- * @returns {number|string|null} The resolved maximum width value, or null if full width is desired.
23
- */
24
- const resolveContentMaxWidth = (contentMinWidthValue, responsiveWidth) => {
25
- if (!contentMinWidthValue || contentMinWidthValue === CONTENT_FULL_WIDTH) {
26
- return null;
27
- }
28
- if (Number.isFinite(contentMinWidthValue)) {
29
- return contentMinWidthValue;
30
- }
31
- if (contentMinWidthValue === CONTENT_MAX_WIDTH) {
32
- return responsiveWidth;
33
- }
34
- return contentMinWidthValue;
35
- };
36
-
37
- /**
38
- * Calculates the maximum width for a given viewport based on limitWidth and contentMinWidth settings.
16
+ * Calculates the maximum width for a given viewport based on limitWidth and contentMaxWidth settings.
39
17
  *
40
18
  * @param {string} viewportKey - The viewport key ('xs', 'sm', 'md', 'lg', 'xl')
41
19
  * @param {boolean} limitWidth - Whether to limit the width to viewport breakpoints
42
- * @param {any} contentMinWidth - The contentMinWidth prop value
20
+ * @param {any} contentWidthProp - The contentMaxWidth (or contentMinWidth) prop value
43
21
  * @param {number|string|null} maxWidth - The resolved max width value
44
22
  * @returns {number|string|null} The calculated maximum width for the viewport
45
23
  */
46
- const getMaxWidthForViewport = (viewportKey, limitWidth, contentMinWidth, maxWidth) => {
24
+ const getMaxWidthForViewport = (viewportKey, limitWidth, contentWidthProp, maxWidth) => {
47
25
  if (limitWidth) {
48
26
  if (viewportKey === 'xs') {
49
27
  return null;
50
28
  }
51
29
  return viewports.map.get(viewportKey);
52
30
  }
53
- if (contentMinWidth) {
31
+ if (contentWidthProp) {
54
32
  return maxWidth;
55
33
  }
56
34
  return null;
@@ -74,6 +52,7 @@ const FlexGrid = /*#__PURE__*/React.forwardRef((_ref, ref) => {
74
52
  accessibilityRole,
75
53
  children,
76
54
  dataSet,
55
+ contentMaxWidth,
77
56
  contentMinWidth,
78
57
  ...rest
79
58
  } = _ref;
@@ -87,28 +66,31 @@ const FlexGrid = /*#__PURE__*/React.forwardRef((_ref, ref) => {
87
66
  } = useTheme();
88
67
  let flexgridStyles;
89
68
  let mediaIds;
90
- const contentMinWidthValue = useResponsiveProp(contentMinWidth);
69
+
70
+ // Support both contentMaxWidth and deprecated contentMinWidth for backwards compatibility
71
+ const contentWidthProp = contentMaxWidth || contentMinWidth;
72
+ const contentWidthValue = useResponsiveProp(contentWidthProp);
91
73
  const responsiveWidth = useResponsiveProp(themeOptions?.contentMaxWidth);
92
- const maxWidth = resolveContentMaxWidth(contentMinWidthValue, responsiveWidth);
74
+ const maxWidth = resolveContentMaxWidth(contentWidthValue, responsiveWidth);
93
75
  const stylesByViewport = {
94
76
  xs: {
95
- maxWidth: getMaxWidthForViewport('xs', limitWidth, contentMinWidth, maxWidth),
77
+ maxWidth: getMaxWidthForViewport('xs', limitWidth, contentWidthProp, maxWidth),
96
78
  flexDirection: reverseLevel[0] ? 'column-reverse' : 'column'
97
79
  },
98
80
  sm: {
99
- maxWidth: getMaxWidthForViewport('sm', limitWidth, contentMinWidth, maxWidth),
81
+ maxWidth: getMaxWidthForViewport('sm', limitWidth, contentWidthProp, maxWidth),
100
82
  flexDirection: reverseLevel[1] ? 'column-reverse' : 'column'
101
83
  },
102
84
  md: {
103
- maxWidth: getMaxWidthForViewport('md', limitWidth, contentMinWidth, maxWidth),
85
+ maxWidth: getMaxWidthForViewport('md', limitWidth, contentWidthProp, maxWidth),
104
86
  flexDirection: reverseLevel[2] ? 'column-reverse' : 'column'
105
87
  },
106
88
  lg: {
107
- maxWidth: getMaxWidthForViewport('lg', limitWidth, contentMinWidth, maxWidth),
89
+ maxWidth: getMaxWidthForViewport('lg', limitWidth, contentWidthProp, maxWidth),
108
90
  flexDirection: reverseLevel[3] ? 'column-reverse' : 'column'
109
91
  },
110
92
  xl: {
111
- maxWidth: getMaxWidthForViewport('xl', limitWidth, contentMinWidth, maxWidth),
93
+ maxWidth: getMaxWidthForViewport('xl', limitWidth, contentWidthProp, maxWidth),
112
94
  flexDirection: reverseLevel[4] ? 'column-reverse' : 'column'
113
95
  }
114
96
  };
@@ -204,7 +186,7 @@ FlexGrid.propTypes = {
204
186
  */
205
187
  children: PropTypes.node.isRequired,
206
188
  /**
207
- * The minimum width of the content in the FlexGrid.
189
+ * The maximum width of the content in the FlexGrid.
208
190
  * This prop accepts responsive values for different viewports. If a number is provided,
209
191
  * it will be the max content width for the desired viewport.
210
192
  * - `xs`: 'max' | 'full' | <number>
@@ -213,6 +195,20 @@ FlexGrid.propTypes = {
213
195
  * - `lg`: 'max' | 'full' | <number>
214
196
  * - `xl`: 'max' | 'full' | <number>
215
197
  */
198
+ contentMaxWidth: PropTypes.shape({
199
+ xl: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
200
+ lg: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
201
+ md: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
202
+ sm: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
203
+ xs: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number])
204
+ }),
205
+ /**
206
+ * @deprecated Use `contentMaxWidth` instead. This prop will be removed in a future version.
207
+ *
208
+ * The minimum width of the content in the FlexGrid.
209
+ * This prop accepts responsive values for different viewports. If a number is provided,
210
+ * it will be the max content width for the desired viewport.
211
+ */
216
212
  contentMinWidth: PropTypes.shape({
217
213
  xl: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
218
214
  lg: PropTypes.oneOfType([PropTypes.oneOf(['max', 'full']), PropTypes.number]),
@@ -4,7 +4,7 @@ import Platform from "react-native-web/dist/exports/Platform";
4
4
  import StyleSheet from "react-native-web/dist/exports/StyleSheet";
5
5
  import View from "react-native-web/dist/exports/View";
6
6
  import { validateThemeTokens, resolveThemeTokens } from '../ThemeProvider';
7
- import { a11yProps, getTokensSetPropType, selectSystemProps, selectTokens, viewProps } from '../utils';
7
+ import { a11yProps, getTokensSetPropType, selectSystemProps, selectTokens, variantProp, viewProps } from '../utils';
8
8
  import ScrollViewEnd from './ScrollViewEnd';
9
9
  import { getItemPositionScrollTarget, itemPositionsPropType } from './itemPositions';
10
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -27,6 +27,7 @@ const HorizontalScroll = /*#__PURE__*/React.forwardRef((_ref, ref) => {
27
27
  ScrollButton,
28
28
  tokens,
29
29
  itemPositions,
30
+ variant,
30
31
  children,
31
32
  ...rest
32
33
  } = _ref;
@@ -70,8 +71,9 @@ const HorizontalScroll = /*#__PURE__*/React.forwardRef((_ref, ref) => {
70
71
  setScrollOffset(x);
71
72
  };
72
73
  const scrollMax = Math.max(0, contentWidth - containerWidth);
73
- const showNextButton = scrollOffset < scrollMax;
74
- const showPreviousButton = scrollOffset > 0;
74
+ const hideNavigationButtons = variant?.hideNavigationButtons || false;
75
+ const showNextButton = scrollOffset < scrollMax && !hideNavigationButtons;
76
+ const showPreviousButton = scrollOffset > 0 && !hideNavigationButtons;
75
77
  const scrollRef = React.useRef(null);
76
78
  const scrollTo = targetX => {
77
79
  if (typeof scrollRef.current?.scrollTo === 'function') {
@@ -162,6 +164,7 @@ HorizontalScroll.propTypes = {
162
164
  tokens: getTokensSetPropType(tokenKeys, {
163
165
  allowFunction: true
164
166
  }),
167
+ variant: variantProp.propType,
165
168
  children: PropTypes.node
166
169
  };
167
170
  export default HorizontalScroll;
@@ -14,6 +14,7 @@ const Icon = /*#__PURE__*/React.forwardRef((_ref, ref) => {
14
14
  tokens,
15
15
  scalesWithText = false,
16
16
  style = {},
17
+ testID,
17
18
  dataSet
18
19
  } = _ref;
19
20
  const themeTokens = useThemeTokens('Icon', tokens, variant);
@@ -37,6 +38,7 @@ const Icon = /*#__PURE__*/React.forwardRef((_ref, ref) => {
37
38
  };
38
39
  const getIconContentForMobile = () => {
39
40
  return /*#__PURE__*/_jsx(View, {
41
+ testID: testID,
40
42
  style: {
41
43
  backgroundColor: themeTokens.backgroundColor,
42
44
  borderRadius: themeTokens.borderRadius,
@@ -46,6 +48,7 @@ const Icon = /*#__PURE__*/React.forwardRef((_ref, ref) => {
46
48
  });
47
49
  };
48
50
  return Platform.OS === 'web' ? /*#__PURE__*/_jsx(View, {
51
+ testID: testID,
49
52
  ref: ref
50
53
  // eslint-disable-next-line react-native/no-inline-styles
51
54
  ,
@@ -123,6 +123,7 @@ const IconButton = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
123
123
  hrefAttrs,
124
124
  testID,
125
125
  accessibilityRole = href ? 'link' : 'button',
126
+ inactive = false,
126
127
  ...rawRest
127
128
  } = _ref3;
128
129
  const {
@@ -143,8 +144,12 @@ const IconButton = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
143
144
  }
144
145
  });
145
146
  };
146
- const getTokens = useThemeTokensCallback('IconButton', tokens, variant);
147
- const getOuterStyle = pressableState => selectOuterStyle(getTokens(resolvePressableState(pressableState), variant.password));
147
+ const mergedVariant = inactive ? {
148
+ ...variant,
149
+ inactive: true
150
+ } : variant;
151
+ const getTokens = useThemeTokensCallback('IconButton', tokens, mergedVariant);
152
+ const getOuterStyle = pressableState => selectOuterStyle(getTokens(resolvePressableState(pressableState), mergedVariant.password));
148
153
  return /*#__PURE__*/_jsx(Pressable, {
149
154
  ref: ref,
150
155
  href: href,
@@ -153,15 +158,16 @@ const IconButton = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
153
158
  style: getOuterStyle,
154
159
  ...selectedProps,
155
160
  testID: testID,
161
+ disabled: inactive,
156
162
  children: pressableState => {
157
163
  const themeTokens = getTokens(resolvePressableState(pressableState));
158
164
  return /*#__PURE__*/_jsx(View, {
159
- style: selectInnerStyle(themeTokens, variant.password),
165
+ style: selectInnerStyle(themeTokens, mergedVariant.password),
160
166
  children: /*#__PURE__*/_jsx(Icon, {
161
167
  icon: IconComponent || themeTokens.icon,
162
168
  title: selectedProps.accessibilityLabel,
163
169
  tokens: selectTokens('Icon', themeTokens, 'icon'),
164
- variant: variant
170
+ variant: mergedVariant
165
171
  })
166
172
  });
167
173
  }
@@ -192,7 +198,11 @@ IconButton.propTypes = {
192
198
  /**
193
199
  * Function to execute when the `Iconbutton` is pressed
194
200
  */
195
- onPress: PropTypes.func
201
+ onPress: PropTypes.func,
202
+ /**
203
+ * When true, applies the inactive variant styling
204
+ */
205
+ inactive: PropTypes.bool
196
206
  };
197
207
  const staticStyles = StyleSheet.create({
198
208
  outer: {