@telus-uds/components-base 3.5.1 → 3.6.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 (36) hide show
  1. package/CHANGELOG.md +27 -2
  2. package/lib/cjs/Box/Box.js +53 -7
  3. package/lib/cjs/Carousel/Carousel.js +34 -47
  4. package/lib/cjs/Carousel/CarouselItem/CarouselItem.js +4 -6
  5. package/lib/cjs/Carousel/Constants.js +5 -2
  6. package/lib/cjs/ExpandCollapseMini/ExpandCollapseMini.js +5 -0
  7. package/lib/cjs/ExpandCollapseMini/ExpandCollapseMiniControl.js +17 -26
  8. package/lib/cjs/MultiSelectFilter/MultiSelectFilter.js +8 -2
  9. package/lib/cjs/Notification/Notification.js +26 -16
  10. package/lib/cjs/utils/getSpacingScale.js +66 -0
  11. package/lib/cjs/utils/index.js +9 -1
  12. package/lib/cjs/utils/useResponsiveProp.js +1 -1
  13. package/lib/esm/Box/Box.js +55 -9
  14. package/lib/esm/Carousel/Carousel.js +35 -48
  15. package/lib/esm/Carousel/CarouselItem/CarouselItem.js +4 -6
  16. package/lib/esm/Carousel/Constants.js +4 -1
  17. package/lib/esm/ExpandCollapseMini/ExpandCollapseMini.js +5 -0
  18. package/lib/esm/ExpandCollapseMini/ExpandCollapseMiniControl.js +17 -26
  19. package/lib/esm/MultiSelectFilter/MultiSelectFilter.js +8 -2
  20. package/lib/esm/Notification/Notification.js +27 -17
  21. package/lib/esm/utils/getSpacingScale.js +61 -0
  22. package/lib/esm/utils/index.js +2 -1
  23. package/lib/esm/utils/useResponsiveProp.js +1 -1
  24. package/lib/package.json +4 -4
  25. package/package.json +4 -4
  26. package/src/Box/Box.jsx +61 -8
  27. package/src/Carousel/Carousel.jsx +47 -58
  28. package/src/Carousel/CarouselItem/CarouselItem.jsx +4 -6
  29. package/src/Carousel/Constants.js +3 -0
  30. package/src/ExpandCollapseMini/ExpandCollapseMini.jsx +5 -0
  31. package/src/ExpandCollapseMini/ExpandCollapseMiniControl.jsx +17 -21
  32. package/src/MultiSelectFilter/MultiSelectFilter.jsx +8 -2
  33. package/src/Notification/Notification.jsx +29 -12
  34. package/src/utils/getSpacingScale.js +50 -0
  35. package/src/utils/index.js +1 -0
  36. package/src/utils/useResponsiveProp.js +1 -1
@@ -6,9 +6,10 @@ import Platform from "react-native-web/dist/exports/Platform";
6
6
  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
- import { useThemeTokens } from '../ThemeProvider';
10
- import { a11yProps, getA11yPropsFromHtmlTag, getTokensPropType, layoutTags, responsiveProps, selectSystemProps, spacingProps, useResponsiveProp, useSpacingScale, variantProp, viewProps } from '../utils';
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
11
  import backgroundImageStylesMap from './backgroundImageStylesMap';
12
+ import { useViewport } from '../ViewportProvider';
12
13
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
14
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
14
15
 
@@ -196,8 +197,19 @@ const Box = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
196
197
  ...getA11yPropsFromHtmlTag(tag, accessibilityRole),
197
198
  ...selectProps(rest)
198
199
  };
199
- const themeTokens = useThemeTokens('Box', tokens, variant);
200
- const styles = {
200
+ const viewport = useViewport();
201
+ const {
202
+ themeOptions
203
+ } = useTheme();
204
+ const {
205
+ enableMediaQueryStyleSheet
206
+ } = themeOptions;
207
+ const useTokens = enableMediaQueryStyleSheet ? useResponsiveThemeTokens : useThemeTokens;
208
+ const themeTokens = useTokens('Box', tokens, variant, !enableMediaQueryStyleSheet && {
209
+ viewport
210
+ });
211
+ const getSpacingTokens = useThemeTokensCallback('spacingScale');
212
+ let boxStyles = {
201
213
  flex,
202
214
  paddingLeft: useSpacingScale(left),
203
215
  paddingRight: useSpacingScale(right),
@@ -205,8 +217,38 @@ const Box = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
205
217
  paddingBottom: useSpacingScale(bottom),
206
218
  ...selectBoxStyles(themeTokens, customGradient)
207
219
  };
220
+ let boxMediaIds;
221
+ if (enableMediaQueryStyleSheet) {
222
+ const {
223
+ transformedThemeTokens
224
+ } = Object.entries(themeTokens).reduce((acc, _ref4) => {
225
+ let [vp] = _ref4;
226
+ acc.transformedThemeTokens[vp] = {
227
+ paddingLeft: getSpacingScale(left, vp, getSpacingTokens),
228
+ paddingRight: getSpacingScale(right, vp, getSpacingTokens),
229
+ paddingTop: getSpacingScale(top, vp, getSpacingTokens),
230
+ paddingBottom: getSpacingScale(bottom, vp, getSpacingTokens)
231
+ };
232
+ return acc;
233
+ }, {
234
+ transformedThemeTokens: {}
235
+ });
236
+ const mediaQueryStyles = createMediaQueryStyles(transformedThemeTokens);
237
+ const {
238
+ ids
239
+ } = RNMQStyleSheet.create({
240
+ box: {
241
+ ...mediaQueryStyles
242
+ }
243
+ });
244
+ boxStyles = {
245
+ flex,
246
+ ...selectBoxStyles(themeTokens[viewport], customGradient)
247
+ };
248
+ boxMediaIds = ids.box;
249
+ }
208
250
  let content = children;
209
- if (typeof customGradient === 'function') content = customGradient(styles.colors, styles)(children);
251
+ if (typeof customGradient === 'function') content = customGradient(boxStyles.colors, boxStyles)(children);
210
252
  const {
211
253
  src = '',
212
254
  alt = '',
@@ -240,23 +282,27 @@ const Box = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
240
282
  });
241
283
  }
242
284
  }, [backgroundImage, backgroundImageWidth, backgroundImageHeight, src]);
285
+ const dataSetValue = boxMediaIds ? {
286
+ media: boxMediaIds,
287
+ ...dataSet
288
+ } : dataSet;
243
289
  if (scroll) {
244
290
  const scrollProps = typeof scroll === 'object' ? scroll : {};
245
- scrollProps.contentContainerStyle = [styles, scrollProps.contentContainerStyle];
291
+ scrollProps.contentContainerStyle = [boxStyles, scrollProps.contentContainerStyle];
246
292
  return /*#__PURE__*/_jsx(ScrollView, {
247
293
  ...scrollProps,
248
294
  ...props,
249
295
  testID: testID,
250
- dataSet: dataSet,
296
+ dataSet: dataSetValue,
251
297
  ref: ref,
252
298
  children: content
253
299
  });
254
300
  }
255
301
  return /*#__PURE__*/_jsx(View, {
256
302
  ...props,
257
- style: styles,
303
+ style: boxStyles,
258
304
  testID: testID,
259
- dataSet: dataSet,
305
+ dataSet: dataSetValue,
260
306
  ref: ref,
261
307
  children: content
262
308
  });
@@ -21,7 +21,7 @@ import CarouselTabsPanel from './CarouselTabs/CarouselTabsPanel';
21
21
  import CarouselTabsPanelItem from './CarouselTabs/CarouselTabsPanelItem';
22
22
  import dictionary from './dictionary';
23
23
  import Box from '../Box';
24
- import { ITEMS_PER_VIEWPORT_MD, ITEMS_PER_VIEWPORT_LG_XL, DEFAULT_POSITION_OFFSET, LARGE_VIEWPORT_MARGIN, DEFAULT_VIEWPORT_MARGIN } from './Constants';
24
+ import { ITEMS_PER_VIEWPORT_MD, ITEMS_PER_VIEWPORT_LG_XL, DEFAULT_POSITION_OFFSET, LARGE_VIEWPORT_MARGIN, DEFAULT_VIEWPORT_MARGIN, PEEKING_MULTIPLIER, ACTIVE_INDEX_OFFSET_MULTIPLIER, NEGATIVE_MULTIPLIER } from './Constants';
25
25
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
26
26
  const TRANSITION_MODES = {
27
27
  MANUAL: 'manual',
@@ -198,56 +198,27 @@ const selectNavigationStyles = (tabs, enableHero, viewport) => {
198
198
  };
199
199
 
200
200
  /**
201
- * Calculates the final width of the carousel container for displacement purposes based on various conditions.
201
+ * Calculates the final width of a carousel container based on the provided parameters.
202
202
  *
203
- * @param {number} containerWidth - The initial width of the container.
204
- * @param {boolean} enablePeeking - Flag indicating if peeking is enabled.
205
- * @param {object} viewport - The viewport properties.
206
- * @param {object} activeIndexRef - A ref object holding the current active index.
207
- * @param {number} totalItems - The total number of items in the carousel.
208
- * @param {number} calcDelta - The delta value used for calculations.
209
- * @returns {number} - The final calculated width of the container.
210
- *
211
- * The function adjusts the container width for displacement purposes based on the peeking properties and the position
212
- * of the active item (first, middle, or last). It considers different peeking spaces and gaps
213
- * to ensure the correct width is calculated for the carousel to display properly.
203
+ * @param {number} containerWidth - The width of the carousel container.
204
+ * @param {boolean} enablePeeking - Flag indicating whether peeking is enabled.
205
+ * @param {Object} viewport - The viewport configuration object used to determine peeking properties.
206
+ * @param {React.MutableRefObject<number>} activeIndexRef - A ref object holding the current active index of the carousel.
207
+ * @returns {number} The calculated final width of the carousel container.
214
208
  */
215
- const calculateFinalWidth = (containerWidth, enablePeeking, viewport, activeIndexRef, totalItems, calcDelta) => {
209
+ const calculateFinalWidth = (containerWidth, enablePeeking, viewport, activeIndexRef) => {
216
210
  let finalWidth = containerWidth;
217
211
  if (enablePeeking) {
218
212
  const {
219
- peekingFirstSpace,
220
213
  peekingGap,
221
- peekingLastSpace,
222
- peekingMiddleSpace
214
+ peekingMiddleSpace,
215
+ peekingMarginLeft
223
216
  } = getPeekingProps(viewport);
224
- const isFirst = activeIndexRef.current === 0;
225
- const isLast = activeIndexRef.current + 1 >= totalItems;
226
- const isMiddle = !isFirst && !isLast;
227
- const basePeekingSpace = peekingFirstSpace + peekingGap + peekingMiddleSpace;
228
- const middlePeekingSpace = peekingMiddleSpace * 2 + peekingGap;
229
- if (isFirst) {
230
- finalWidth -= basePeekingSpace;
231
- if (activeIndexRef.current + 1 === totalItems - 1) {
232
- finalWidth -= peekingLastSpace - peekingMiddleSpace;
233
- }
234
- } else if (isMiddle) {
235
- if (calcDelta > 0) {
236
- finalWidth -= basePeekingSpace + middlePeekingSpace * activeIndexRef.current;
237
- if (activeIndexRef.current + 1 === totalItems - 1) {
238
- finalWidth -= peekingLastSpace - peekingMiddleSpace;
239
- }
240
- } else {
241
- finalWidth += basePeekingSpace + middlePeekingSpace * (activeIndexRef.current - 2);
242
- if (activeIndexRef.current - 1 === 0) {
243
- finalWidth -= peekingFirstSpace - peekingMiddleSpace;
244
- }
245
- }
246
- } else if (isLast) {
247
- finalWidth += basePeekingSpace + middlePeekingSpace * (activeIndexRef.current - 2);
248
- if (activeIndexRef.current - 1 === 0) {
249
- finalWidth -= peekingLastSpace - peekingMiddleSpace;
250
- }
217
+ const slideWide = containerWidth - (peekingMiddleSpace * PEEKING_MULTIPLIER + peekingGap * PEEKING_MULTIPLIER);
218
+ if (activeIndexRef.current === 0) {
219
+ finalWidth = slideWide + peekingMarginLeft - peekingMiddleSpace;
220
+ } else {
221
+ finalWidth = slideWide + peekingGap;
251
222
  }
252
223
  }
253
224
  return finalWidth;
@@ -434,7 +405,23 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
434
405
  setIsAnimating(false);
435
406
  }, [onAnimationEnd]);
436
407
  const updateOffset = React.useCallback(() => {
437
- animatedX.current = containerLayoutRef.current.width * activeIndexRef.current * -1;
408
+ if (enablePeeking) {
409
+ const {
410
+ peekingGap,
411
+ peekingMiddleSpace,
412
+ peekingMarginLeft
413
+ } = getPeekingProps(viewport);
414
+ let finalWidth;
415
+ const slideWide = containerLayoutRef.current.width - (peekingMiddleSpace * PEEKING_MULTIPLIER + peekingGap * PEEKING_MULTIPLIER);
416
+ if (activeIndexRef.current === 0) {
417
+ finalWidth = 0;
418
+ } else {
419
+ finalWidth = slideWide + peekingMarginLeft - peekingMiddleSpace + (slideWide + peekingGap) * (activeIndexRef.current - ACTIVE_INDEX_OFFSET_MULTIPLIER);
420
+ }
421
+ animatedX.current = finalWidth * NEGATIVE_MULTIPLIER;
422
+ } else {
423
+ animatedX.current = containerLayoutRef.current.width * activeIndexRef.current * NEGATIVE_MULTIPLIER;
424
+ }
438
425
  animatedY.current = 0;
439
426
  pan.setOffset({
440
427
  x: animatedX.current,
@@ -445,7 +432,7 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
445
432
  y: 0
446
433
  });
447
434
  if (enableHero) {
448
- heroAnimatedX.current = heroContainerLayoutRef.current.width * activeIndexRef.current * -1;
435
+ heroAnimatedX.current = heroContainerLayoutRef.current.width * activeIndexRef.current * NEGATIVE_MULTIPLIER;
449
436
  heroAnimatedY.current = 0;
450
437
  heroPan.setOffset({
451
438
  x: heroAnimatedX.current,
@@ -456,7 +443,7 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
456
443
  y: 0
457
444
  });
458
445
  }
459
- }, [pan, animatedX, heroPan, heroAnimatedX, enableHero]);
446
+ }, [pan, animatedX, heroPan, heroAnimatedX, enableHero, viewport, enablePeeking]);
460
447
  const animate = React.useCallback((panToAnimate, toValue, toIndex) => {
461
448
  const handleAnimationEndToIndex = function () {
462
449
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
@@ -531,7 +518,7 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
531
518
  }
532
519
  stopAutoplay();
533
520
  setActiveIndex(index);
534
- const finalWidth = calculateFinalWidth(containerLayoutRef.current.width, enablePeeking, viewport, activeIndexRef, totalItems, calcDelta);
521
+ const finalWidth = calculateFinalWidth(containerLayoutRef.current.width, enablePeeking, viewport, activeIndexRef);
535
522
  toValue.x = finalWidth * -1 * calcDelta;
536
523
  const heroToValue = {
537
524
  x: 0,
@@ -13,18 +13,17 @@ const selectContainerStyle = _ref => {
13
13
  elementIndex,
14
14
  enablePeeking,
15
15
  peekingMarginLeft,
16
- peekingFirstSpace,
17
16
  peekingGap,
18
17
  hidden,
19
18
  enableDisplayMultipleItemsPerSlide,
20
- viewport
19
+ viewport,
20
+ peekingMiddleSpace
21
21
  } = _ref;
22
22
  let adjustedWidth = width;
23
23
  let marginLeft = 0;
24
- const marginRight = 0;
25
24
  if (enablePeeking) {
26
25
  const isFirst = elementIndex === 0;
27
- adjustedWidth = width - (peekingMarginLeft + peekingGap + peekingFirstSpace);
26
+ adjustedWidth = width - (peekingMiddleSpace * 2 + peekingGap * 2);
28
27
  if (isFirst) {
29
28
  marginLeft = peekingMarginLeft;
30
29
  } else {
@@ -61,8 +60,7 @@ const selectContainerStyle = _ref => {
61
60
  }
62
61
  const style = {
63
62
  width: adjustedWidth,
64
- marginLeft,
65
- marginRight
63
+ marginLeft
66
64
  };
67
65
  if (hidden && Platform.OS === 'web') {
68
66
  style.visibility = 'hidden';
@@ -4,4 +4,7 @@ export const GAP_BETWEEN_ITEMS = 16;
4
4
  export const HERO_POSITION_OFFSET = 20;
5
5
  export const DEFAULT_POSITION_OFFSET = 0;
6
6
  export const LARGE_VIEWPORT_MARGIN = 40;
7
- export const DEFAULT_VIEWPORT_MARGIN = 10;
7
+ export const DEFAULT_VIEWPORT_MARGIN = 10;
8
+ export const PEEKING_MULTIPLIER = 2;
9
+ export const ACTIVE_INDEX_OFFSET_MULTIPLIER = 1;
10
+ export const NEGATIVE_MULTIPLIER = -1;
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import ExpandCollapse from '../ExpandCollapse';
4
4
  import { getTokensPropType, selectSystemProps, contentfulProps } from '../utils';
5
+ import { variantProp } from '../utils/props';
5
6
  import ExpandCollapseMiniControl from './ExpandCollapseMiniControl';
6
7
  import { jsx as _jsx } from "react/jsx-runtime";
7
8
  const [selectContainerProps, selectedContainerPropTypes] = selectSystemProps([contentfulProps]);
@@ -78,6 +79,10 @@ ExpandCollapseMini.propTypes = {
78
79
  * Optional variant object to override the default theme tokens
79
80
  */
80
81
  tokens: getTokensPropType('ExpandCollapseMini'),
82
+ /**
83
+ * ExpandCollapseMini variant.
84
+ */
85
+ variant: variantProp.propType,
81
86
  /**
82
87
  * The dataSet prop allows to pass data-* attributes element to the component.
83
88
  */
@@ -16,21 +16,7 @@ const presentationOnly = {
16
16
  // Stop RNW from stopping clicks from bubbling to Control
17
17
  focusable: false // Stop RNW from setting tabIndex={0}: focus goes to Control only
18
18
  };
19
- const selectLinkTokens = _ref => {
20
- let {
21
- color,
22
- textLine,
23
- lineHeight,
24
- fontSize
25
- } = _ref;
26
- return {
27
- color,
28
- textLine,
29
- blockLineHeight: lineHeight,
30
- blockFontSize: fontSize
31
- };
32
- };
33
- const ExpandCollapseMiniControl = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
19
+ const ExpandCollapseMiniControl = /*#__PURE__*/React.forwardRef((_ref, ref) => {
34
20
  let {
35
21
  pressableState,
36
22
  collapseTitle,
@@ -39,22 +25,28 @@ const ExpandCollapseMiniControl = /*#__PURE__*/React.forwardRef((_ref2, ref) =>
39
25
  tokens,
40
26
  variant = {},
41
27
  ...rest
42
- } = _ref2;
28
+ } = _ref;
43
29
  const {
44
30
  expanded,
45
31
  hover,
46
- focus
32
+ focus,
33
+ pressed
47
34
  } = pressableState || {};
48
- // we only want focus outline when focusing, if user is pressing we don't want the border.
49
35
  const {
50
- outerBorderColor
51
- } = useThemeTokens('Link', {}, {}, {
52
- focus: Platform.OS !== 'web' ? expanded : focus
36
+ quiet
37
+ } = variant;
38
+ const isFocusVisible = Platform.OS === 'web' ? focus && !pressed && !hover : expanded;
39
+ const linkTokens = useThemeTokens('Link', {}, {
40
+ ...variant,
41
+ quiet: expanded ?? quiet
42
+ }, {
43
+ focus: isFocusVisible,
44
+ hover,
45
+ pressed
53
46
  });
54
47
  const {
55
48
  size,
56
- icon,
57
- ...themeTokens
49
+ icon
58
50
  } = useThemeTokens('ExpandCollapseMiniControl', tokens, variant, {
59
51
  expanded,
60
52
  focus
@@ -88,9 +80,8 @@ const ExpandCollapseMiniControl = /*#__PURE__*/React.forwardRef((_ref2, ref) =>
88
80
  icon: icon,
89
81
  iconPosition: iconPosition,
90
82
  tokens: linkState => ({
91
- ...getTokens(linkState),
92
- ...selectLinkTokens(themeTokens),
93
- outerBorderColor
83
+ ...linkTokens,
84
+ ...getTokens(linkState)
94
85
  }),
95
86
  ref: ref,
96
87
  ...presentationOnly,
@@ -130,6 +130,10 @@ const MultiSelectFilter = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
130
130
  buttonIconPadding,
131
131
  subtitleColor,
132
132
  dividerColor,
133
+ iconColor,
134
+ buttonBackgroundColor,
135
+ iconColorSelected,
136
+ buttonBackgroundColorSelected,
133
137
  ...restTokens
134
138
  } = useThemeTokens('MultiSelectFilter', tokens, {
135
139
  ...variant,
@@ -152,7 +156,9 @@ const MultiSelectFilter = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
152
156
  paddingBottom: labelPaddingBottom,
153
157
  paddingLeft: labelPaddingLeft,
154
158
  paddingRight: labelPaddingRight,
155
- iconBackground: buttonIconBackgroundColor
159
+ iconBackground: buttonIconBackgroundColor,
160
+ iconColor: isSelected ? iconColorSelected : iconColor,
161
+ backgroundColor: isSelected ? buttonBackgroundColorSelected : buttonBackgroundColor
156
162
  };
157
163
  const getButtonDropdownTokens = useThemeTokensCallback('ButtonDropdown', dropdownTokens, variant);
158
164
  const getButtonTokens = buttonState => selectTokens('ButtonDropdown', getButtonDropdownTokens(buttonState));
@@ -242,7 +248,7 @@ const MultiSelectFilter = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
242
248
  const [isScrolling, setIsScrolling] = React.useState(false);
243
249
  const [scrollViewHeight, setScrollViewHeight] = React.useState(0);
244
250
  const [rowHeight, setRowHeight] = React.useState(0);
245
- const modalRef = useScrollBlocking(isOpen);
251
+ const modalRef = useScrollBlocking(isOpen && viewport === 'xs');
246
252
  const windowWidth = Dimensions.get('window').width;
247
253
  const windowHeight = Dimensions.get('window').height;
248
254
  React.useEffect(() => {
@@ -3,7 +3,7 @@ import View from "react-native-web/dist/exports/View";
3
3
  import PropTypes from 'prop-types';
4
4
  import { viewports } from '@telus-uds/system-constants';
5
5
  import { applyTextStyles, useTheme, useThemeTokens, useResponsiveThemeTokens } from '../ThemeProvider';
6
- import { a11yProps, getTokensPropType, selectSystemProps, selectTokens, variantProp, viewProps, wrapStringsInText, createMediaQueryStyles, StyleSheet } from '../utils';
6
+ import { a11yProps, getTokensPropType, selectSystemProps, selectTokens, variantProp, viewProps, wrapStringsInText, createMediaQueryStyles, StyleSheet, useResponsiveProp } from '../utils';
7
7
  import IconButton from '../IconButton';
8
8
  import useCopy from '../utils/useCopy';
9
9
  import dictionary from './dictionary';
@@ -63,8 +63,8 @@ const selectDismissButtonContainerStyles = _ref4 => {
63
63
  placeContent: 'start'
64
64
  };
65
65
  };
66
- const selectContentContainerStyle = (themeTokens, maxWidth, viewport, system) => ({
67
- maxWidth: viewport === 'xl' && system === true ? maxWidth : '100%',
66
+ const selectContentContainerStyle = (themeTokens, maxWidth, system, viewport) => ({
67
+ maxWidth: system && viewport === 'xl' ? maxWidth : '100%',
68
68
  width: '100%',
69
69
  paddingRight: themeTokens?.containerPaddingRight,
70
70
  paddingLeft: themeTokens?.containerPaddingLeft
@@ -72,9 +72,12 @@ const selectContentContainerStyle = (themeTokens, maxWidth, viewport, system) =>
72
72
  const getMediaQueryStyles = (themeTokens, themeOptions, maxWidth, mediaIdsRef, dismissible, viewport, system) => {
73
73
  const transformedSelectContainerStyles = Object.entries(themeTokens).reduce((acc, _ref5) => {
74
74
  let [vp, viewportTokens] = _ref5;
75
- acc[vp] = selectContainerStyles({
76
- ...viewportTokens
77
- });
75
+ acc[vp] = {
76
+ ...selectContainerStyles({
77
+ ...viewportTokens
78
+ }),
79
+ flexDirection: 'column'
80
+ };
78
81
  return acc;
79
82
  }, {});
80
83
  const selectContainerMediaQueryStyles = createMediaQueryStyles(transformedSelectContainerStyles);
@@ -83,22 +86,29 @@ const getMediaQueryStyles = (themeTokens, themeOptions, maxWidth, mediaIdsRef, d
83
86
  styles: containerStyles
84
87
  } = StyleSheet.create({
85
88
  container: {
86
- flexDirection: 'column',
87
89
  ...selectContainerMediaQueryStyles
88
90
  }
89
91
  });
90
- const {
91
- ids: contentContainerIds,
92
- styles: contentContainerStyles
93
- } = StyleSheet.create({
94
- contentContainer: {
92
+ const transformedSelectContentContainerStyles = Object.entries(themeTokens).reduce((acc, _ref6) => {
93
+ let [vp, viewportTokens] = _ref6;
94
+ acc[vp] = {
95
+ ...selectContentContainerStyle(viewportTokens, maxWidth, system, vp),
95
96
  flexDirection: 'row',
96
97
  flexShrink: 1,
97
98
  justifyContent: 'space-between',
98
- ...selectContentContainerStyle(themeTokens, maxWidth, viewport, system),
99
99
  ...(system && {
100
100
  alignSelf: 'center'
101
101
  })
102
+ };
103
+ return acc;
104
+ }, {});
105
+ const selectContentContainerMediaQueryStyles = createMediaQueryStyles(transformedSelectContentContainerStyles);
106
+ const {
107
+ ids: contentContainerIds,
108
+ styles: contentContainerStyles
109
+ } = StyleSheet.create({
110
+ contentContainer: {
111
+ ...selectContentContainerMediaQueryStyles
102
112
  }
103
113
  });
104
114
  const {
@@ -171,7 +181,7 @@ const getDefaultStyles = (themeTokens, themeOptions, maxWidth, dismissible, view
171
181
  flexDirection: 'row',
172
182
  flexShrink: 1,
173
183
  justifyContent: 'space-between',
174
- ...selectContentContainerStyle(themeTokens, maxWidth, viewport, system),
184
+ ...selectContentContainerStyle(themeTokens, maxWidth, system, viewport),
175
185
  ...(system && {
176
186
  alignSelf: 'center'
177
187
  })
@@ -261,7 +271,7 @@ const getDefaultStyles = (themeTokens, themeOptions, maxWidth, dismissible, view
261
271
  * Use full-width `Notifications` to show system-based messages coming from the application, not in response to user action.
262
272
  * Show system notifications at the top of the page, below the navigation, and expands the full-width of the viewport
263
273
  */
264
- const Notification = /*#__PURE__*/React.forwardRef((_ref6, ref) => {
274
+ const Notification = /*#__PURE__*/React.forwardRef((_ref7, ref) => {
265
275
  let {
266
276
  children,
267
277
  system,
@@ -271,7 +281,7 @@ const Notification = /*#__PURE__*/React.forwardRef((_ref6, ref) => {
271
281
  variant,
272
282
  onDismiss,
273
283
  ...rest
274
- } = _ref6;
284
+ } = _ref7;
275
285
  const [isDismissed, setIsDismissed] = React.useState(false);
276
286
  const viewport = useViewport();
277
287
  const getCopy = useCopy({
@@ -292,7 +302,7 @@ const Notification = /*#__PURE__*/React.forwardRef((_ref6, ref) => {
292
302
  system: isSystemEnabled,
293
303
  viewport
294
304
  });
295
- const maxWidth = viewports.map.get(viewports.xl);
305
+ const maxWidth = useResponsiveProp(themeOptions?.contentMaxWidth, viewports.map.get(viewports.xl));
296
306
  const notificationComponentRef = React.useRef({
297
307
  containerStyles: {},
298
308
  contentContainerStyles: {},
@@ -0,0 +1,61 @@
1
+ import { resolveResponsiveProp } from './useResponsiveProp';
2
+
3
+ /**
4
+ * Resolves spacing options from the provided space object.
5
+ *
6
+ * @param {Object} space - The space configuration object.
7
+ * @param {Object} [space.options] - The options for spacing.
8
+ * @param {number|string} [space.options.size] - The size of the spacing. Can be a number or a string.
9
+ * @param {string} [space.options.variant] - The variant of the spacing.
10
+ * @param {number} [space.options.subtract=0] - A value to subtract from the spacing size.
11
+ * @returns {Object} An object containing resolved spacing tokens, variant, overridden flag, and subtract value.
12
+ * @property {Object} tokens - The resolved spacing tokens.
13
+ * @property {number|string} tokens.size - The size of the spacing.
14
+ * @property {string} [variant] - The variant of the spacing.
15
+ * @property {boolean} overridden - Indicates if the size is explicitly overridden as a number.
16
+ * @property {number} subtract - The value to subtract from the spacing size.
17
+ */
18
+ const resolveSpacingOptions = space => {
19
+ if (!space?.options) return {};
20
+ const {
21
+ size,
22
+ variant,
23
+ subtract = 0
24
+ } = space.options;
25
+ const overridden = typeof size === 'number';
26
+ return {
27
+ tokens: {
28
+ size
29
+ },
30
+ variant,
31
+ overridden,
32
+ subtract
33
+ };
34
+ };
35
+
36
+ /**
37
+ * Calculates the spacing scale based on the provided space value, viewport, and spacing tokens.
38
+ *
39
+ * @param {Object} spaceValue - The space value configuration, which may include responsive properties.
40
+ * @param {Object} viewport - The current viewport dimensions or configuration.
41
+ * @param {Function} getSpacingTokens - A function that retrieves spacing tokens based on the provided options.
42
+ * @returns {number} The calculated spacing scale, ensuring it is non-negative.
43
+ */
44
+ const getSpacingScale = (spaceValue, viewport, getSpacingTokens) => {
45
+ const {
46
+ tokens,
47
+ variant,
48
+ overridden,
49
+ subtract = 0
50
+ } = resolveSpacingOptions(spaceValue);
51
+ const space = !overridden && (spaceValue?.space ?? resolveResponsiveProp(spaceValue, viewport, 0));
52
+ const {
53
+ size
54
+ } = getSpacingTokens({
55
+ ...variant,
56
+ space: typeof space === 'number' ? space : 0,
57
+ viewport
58
+ }, tokens);
59
+ return Math.max(size - subtract, 0);
60
+ };
61
+ export default getSpacingScale;
@@ -22,4 +22,5 @@ export { default as BaseView } from './BaseView';
22
22
  export { default as htmlAttrs } from './htmlAttrs';
23
23
  export { transformGradient } from './transformGradient';
24
24
  export { default as convertFromMegaByteToByte } from './convertFromMegaByteToByte';
25
- export { default as formatImageSource } from './formatImageSource';
25
+ export { default as formatImageSource } from './formatImageSource';
26
+ export { default as getSpacingScale } from './getSpacingScale';
@@ -21,7 +21,7 @@ export const resolveResponsiveProp = (prop, viewport, defaultValue) => {
21
21
  viewports.inherit(prop)[viewport] :
22
22
  // If no current viewport is available, default to smallest viewport
23
23
  prop[viewports.keys.find(key => hasOwnProperty(prop, key))];
24
- return value === undefined ? defaultValue : value;
24
+ return value === undefined || value === null ? defaultValue : value;
25
25
  };
26
26
 
27
27
  /**
package/lib/package.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "@gorhom/portal": "^1.0.14",
13
13
  "@react-native-picker/picker": "^2.9.0",
14
14
  "@telus-uds/system-constants": "^3.0.0",
15
- "@telus-uds/system-theme-tokens": "^4.3.0",
15
+ "@telus-uds/system-theme-tokens": "^4.4.0",
16
16
  "airbnb-prop-types": "^2.16.0",
17
17
  "css-mediaquery": "^0.1.2",
18
18
  "expo-document-picker": "^13.0.1",
@@ -56,8 +56,8 @@
56
56
  "module": "lib/esm/index.js",
57
57
  "name": "@telus-uds/components-base",
58
58
  "peerDependencies": {
59
- "react": "^18.2.0",
60
- "react-dom": "^18.2.0",
59
+ "react": ">=18.2.0 <19.0.0",
60
+ "react-dom": ">=18.2.0 <19.0.0",
61
61
  "react-native": "^0.74.5",
62
62
  "react-native-web": "^0.19.10",
63
63
  "react-native-svg": "15.7.1"
@@ -84,6 +84,6 @@
84
84
  "standard-engine": {
85
85
  "skip": true
86
86
  },
87
- "version": "3.5.1",
87
+ "version": "3.6.0",
88
88
  "types": "types/index.d.ts"
89
89
  }
package/package.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "@gorhom/portal": "^1.0.14",
13
13
  "@react-native-picker/picker": "^2.9.0",
14
14
  "@telus-uds/system-constants": "^3.0.0",
15
- "@telus-uds/system-theme-tokens": "^4.3.0",
15
+ "@telus-uds/system-theme-tokens": "^4.4.0",
16
16
  "airbnb-prop-types": "^2.16.0",
17
17
  "css-mediaquery": "^0.1.2",
18
18
  "expo-document-picker": "^13.0.1",
@@ -56,8 +56,8 @@
56
56
  "module": "lib/esm/index.js",
57
57
  "name": "@telus-uds/components-base",
58
58
  "peerDependencies": {
59
- "react": "^18.2.0",
60
- "react-dom": "^18.2.0",
59
+ "react": ">=18.2.0 <19.0.0",
60
+ "react-dom": ">=18.2.0 <19.0.0",
61
61
  "react-native": "^0.74.5",
62
62
  "react-native-web": "^0.19.10",
63
63
  "react-native-svg": "15.7.1"
@@ -84,6 +84,6 @@
84
84
  "standard-engine": {
85
85
  "skip": true
86
86
  },
87
- "version": "3.5.1",
87
+ "version": "3.6.0",
88
88
  "types": "types/index.d.ts"
89
89
  }