@telus-uds/components-base 1.54.0 → 1.56.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 (33) hide show
  1. package/CHANGELOG.md +31 -2
  2. package/component-docs.json +136 -54
  3. package/lib/Carousel/CarouselStepTracker/CarouselStepTracker.js +6 -2
  4. package/lib/Carousel/CarouselTabs/CarouselTabsPanel.js +9 -8
  5. package/lib/Carousel/CarouselThumbnail.js +53 -26
  6. package/lib/Carousel/CarouselThumbnailNavigation.js +15 -6
  7. package/lib/IconButton/IconButton.js +41 -7
  8. package/lib/InputLabel/InputLabel.js +2 -1
  9. package/lib/Link/LinkBase.js +3 -3
  10. package/lib/Select/Select.js +3 -2
  11. package/lib/ThemeProvider/utils/styles.js +18 -2
  12. package/lib/TooltipButton/TooltipButton.js +4 -2
  13. package/lib-module/Carousel/CarouselStepTracker/CarouselStepTracker.js +6 -2
  14. package/lib-module/Carousel/CarouselTabs/CarouselTabsPanel.js +9 -8
  15. package/lib-module/Carousel/CarouselThumbnail.js +51 -27
  16. package/lib-module/Carousel/CarouselThumbnailNavigation.js +13 -6
  17. package/lib-module/IconButton/IconButton.js +41 -7
  18. package/lib-module/InputLabel/InputLabel.js +2 -1
  19. package/lib-module/Link/LinkBase.js +3 -3
  20. package/lib-module/Select/Select.js +3 -2
  21. package/lib-module/ThemeProvider/utils/styles.js +19 -2
  22. package/lib-module/TooltipButton/TooltipButton.js +4 -2
  23. package/package.json +3 -3
  24. package/src/Carousel/CarouselStepTracker/CarouselStepTracker.jsx +10 -2
  25. package/src/Carousel/CarouselTabs/CarouselTabsPanel.jsx +5 -5
  26. package/src/Carousel/CarouselThumbnail.jsx +31 -25
  27. package/src/Carousel/CarouselThumbnailNavigation.jsx +8 -3
  28. package/src/IconButton/IconButton.jsx +50 -6
  29. package/src/InputLabel/InputLabel.jsx +4 -1
  30. package/src/Link/LinkBase.jsx +3 -4
  31. package/src/Select/Select.jsx +3 -2
  32. package/src/ThemeProvider/utils/styles.js +29 -2
  33. package/src/TooltipButton/TooltipButton.jsx +5 -1
@@ -17,11 +17,6 @@ const CarouselTabsPanel = forwardRef(({ items }, ref) => {
17
17
  const firstTabRef = useRef()
18
18
  const [isInverse, setIsInverse] = useState(false)
19
19
 
20
- // TODO: figure out a better cross-brand way to specify subcomponent variants.
21
- // For now, this picks an Allium variant, and does nothing in brands that lack it.
22
- // See similar comment in Carousel and https://github.com/telus/universal-design-system/issues/1549
23
- const dividerVariant = { decorative: true }
24
-
25
20
  const lastTabSelected = activeIndex === items.length - 1
26
21
 
27
22
  // Get current select tab style
@@ -30,6 +25,11 @@ const CarouselTabsPanel = forwardRef(({ items }, ref) => {
30
25
  setIsInverse(selectedVariantIsInverse?.inverse)
31
26
  }, [items, activeIndex])
32
27
 
28
+ // TODO: figure out a better cross-brand way to specify subcomponent variants.
29
+ // For now, this picks an Allium variant, and does nothing in brands that lack it.
30
+ // See similar comment in Carousel and https://github.com/telus/universal-design-system/issues/1549
31
+ const dividerVariant = { decorative: true, inverse: isInverse }
32
+
33
33
  return (
34
34
  <View style={selectTabPanelStyle()}>
35
35
  <StackView direction="row" space={3} divider={{ variant: dividerVariant }} ref={ref}>
@@ -2,14 +2,25 @@ import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import { Pressable, Image } from 'react-native'
4
4
  import { useCarousel } from './CarouselContext'
5
+ import { useThemeTokensCallback } from '../ThemeProvider'
6
+ import { useViewport } from '../ViewportProvider'
7
+
8
+ const selectPressableTokens = ({ borderColor, borderRadius, borderWidth, margin, padding }) => ({
9
+ borderColor,
10
+ borderRadius,
11
+ borderWidth,
12
+ margin,
13
+ padding
14
+ })
5
15
 
6
16
  /**
7
17
  * `Carousel.Thumbnail` is used to wrap the content of an individual slide and is suppsoed to be the
8
18
  * only top-level component passed to the `Carousel`
9
19
  */
10
20
  const CarouselThumbnail = ({ accessibilityLabel, alt, index, src }) => {
11
- const { activeIndex, itemLabel, totalItems, getCopyWithPlaceholders, goTo, themeTokens } =
12
- useCarousel()
21
+ const { activeIndex, itemLabel, totalItems, getCopyWithPlaceholders, goTo } = useCarousel()
22
+ const getThumbnailTokens = useThemeTokensCallback('CarouselThumbnail')
23
+ const viewport = useViewport()
13
24
  const thumbnailTitle =
14
25
  alt ??
15
26
  getCopyWithPlaceholders('stepTrackerLabel')
@@ -21,32 +32,17 @@ const CarouselThumbnail = ({ accessibilityLabel, alt, index, src }) => {
21
32
  // Allow using the spacebar for navigation
22
33
  if (event?.key === ' ') goTo(index)
23
34
  }
24
- const {
25
- thumbnailBorderColor,
26
- thumbnailBorderRadius,
27
- thumbnailBorderWidth,
28
- thumbnailMargin,
29
- thumbnailPadding,
30
- thumbnailSelectedBorderColor,
31
- thumbnailSelectedBorderWidth,
32
- thumbnailSize
33
- } = themeTokens
35
+ const { borderWidth, padding, selectedBorderColor, selectedBorderWidth, size } =
36
+ getThumbnailTokens({ viewport })
34
37
  const styles = {
35
- pressable: {
36
- borderColor: thumbnailBorderColor,
37
- borderRadius: thumbnailBorderRadius,
38
- borderWidth: thumbnailBorderWidth,
39
- margin: thumbnailMargin,
40
- padding: thumbnailPadding
41
- },
42
38
  image: {
43
- height: thumbnailSize,
44
- width: thumbnailSize
39
+ height: size,
40
+ width: size
45
41
  },
46
42
  selected: {
47
- borderColor: thumbnailSelectedBorderColor,
48
- borderWidth: thumbnailSelectedBorderWidth,
49
- padding: thumbnailPadding - thumbnailSelectedBorderWidth + thumbnailBorderWidth
43
+ borderColor: selectedBorderColor,
44
+ borderWidth: selectedBorderWidth,
45
+ padding: padding - selectedBorderWidth + borderWidth
50
46
  }
51
47
  }
52
48
 
@@ -55,7 +51,17 @@ const CarouselThumbnail = ({ accessibilityLabel, alt, index, src }) => {
55
51
  key={src}
56
52
  onKeyDown={handleKeyDown}
57
53
  onPress={handlePress}
58
- style={[styles.pressable, index === activeIndex && styles.selected]}
54
+ style={({ hovered, pressed, focused }) => {
55
+ const pressableStyles = selectPressableTokens(
56
+ getThumbnailTokens({
57
+ hover: hovered,
58
+ pressed,
59
+ focus: focused
60
+ })
61
+ )
62
+
63
+ return [pressableStyles, index === activeIndex && styles.selected]
64
+ }}
59
65
  >
60
66
  <Image
61
67
  accessibilityIgnoresInvertColors
@@ -4,19 +4,24 @@ import { View } from 'react-native'
4
4
  import { useCarousel } from './CarouselContext'
5
5
  import CarouselThumbnail from './CarouselThumbnail'
6
6
  import { StackWrap } from '../StackView'
7
+ import { useThemeTokens } from '../ThemeProvider'
8
+ import { useViewport } from '../ViewportProvider'
7
9
 
8
10
  const CarouselThumbnailNavigation = forwardRef(({ thumbnails = [] }, ref) => {
9
- const { totalItems, themeTokens } = useCarousel()
11
+ const viewport = useViewport()
12
+ const { alignItems } = useThemeTokens('CarouselThumbnail', {}, { viewport })
13
+ const { totalItems } = useCarousel()
10
14
  if (thumbnails.length !== totalItems) {
11
15
  throw new Error('Thumbnail set provided does not match the number of slides in the carousel')
12
16
  }
13
- const { thumbnailContainerPaddingTop, thumbnailMargin } = themeTokens
17
+ const { containerPaddingTop: thumbnailContainerPaddingTop, margin: thumbnailMargin } =
18
+ useThemeTokens('CarouselThumbnail')
14
19
  const stackWrapTokens = {
15
20
  justifyContent: 'flex-start'
16
21
  }
17
22
  const containerStyles = {
18
23
  justifyContent: 'center',
19
- alignItems: 'center',
24
+ alignItems,
20
25
  paddingTop: thumbnailContainerPaddingTop - thumbnailMargin
21
26
  }
22
27
 
@@ -22,27 +22,71 @@ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, vie
22
22
 
23
23
  const selectOuterStyle = ({
24
24
  backgroundColor,
25
- borderRadius,
26
25
  outerBorderWidth,
27
26
  outerBorderColor,
28
27
  outerBorderGap,
28
+ borderRadius,
29
+ borderTopLeftRadius,
30
+ borderTopRightRadius,
31
+ borderBottomLeftRadius,
32
+ borderBottomRightRadius,
29
33
  shadow
30
34
  }) => [
31
35
  {
32
36
  backgroundColor,
33
37
  ...applyShadowToken(shadow),
34
- ...applyOuterBorder({ borderRadius, outerBorderWidth, outerBorderColor, outerBorderGap }),
38
+ ...applyOuterBorder({
39
+ borderRadius,
40
+ borderTopLeftRadius,
41
+ borderTopRightRadius,
42
+ borderBottomLeftRadius,
43
+ borderBottomRightRadius,
44
+ outerBorderWidth,
45
+ outerBorderColor,
46
+ outerBorderGap
47
+ }),
35
48
  ...Platform.select({ web: { outline: 'none', display: 'inline-flex' } })
36
49
  },
37
50
  staticStyles.outer
38
51
  ]
39
52
 
40
- const selectInnerStyle = ({ borderColor, borderWidth = 0, borderRadius, padding = 0 }) => ({
53
+ const calculatePadding = (padding, borderWidth) => padding && Math.max(0, padding - borderWidth) // Stable size as border changes
54
+
55
+ const selectInnerStyle = ({
56
+ borderColor,
57
+ borderWidth,
58
+ borderTopLeftRadius,
59
+ borderTopRightRadius,
60
+ borderBottomLeftRadius,
61
+ borderBottomRightRadius,
62
+ borderRadius,
63
+ padding = 0,
64
+ borderTopWidth,
65
+ borderRightWidth,
66
+ borderBottomWidth,
67
+ borderLeftWidth,
68
+ paddingLeft,
69
+ paddingRight,
70
+ paddingTop,
71
+ paddingBottom
72
+ }) => ({
41
73
  // Inner borders animate with the icon and should be treated like a themable feature of the icon
42
74
  borderColor,
43
75
  borderRadius,
44
76
  borderWidth,
45
- padding: Math.max(0, padding - borderWidth) // Stable size as border changes
77
+ borderTopLeftRadius,
78
+ borderTopRightRadius,
79
+ borderBottomLeftRadius,
80
+ borderBottomRightRadius,
81
+ borderTopWidth,
82
+ borderRightWidth,
83
+ borderBottomWidth,
84
+ borderLeftWidth,
85
+ padding: calculatePadding(padding, borderWidth),
86
+ paddingLeft: calculatePadding(paddingLeft, borderLeftWidth),
87
+ paddingRight: calculatePadding(paddingRight, borderRightWidth),
88
+ paddingTop: calculatePadding(paddingTop, borderTopWidth),
89
+ paddingBottom: calculatePadding(paddingBottom, borderBottomWidth)
46
90
  })
47
91
 
48
92
  /**
@@ -90,7 +134,7 @@ const IconButton = forwardRef(
90
134
  return (
91
135
  <View style={selectInnerStyle(themeTokens)}>
92
136
  <Icon
93
- icon={IconComponent}
137
+ icon={IconComponent || themeTokens.icon}
94
138
  title={selectedProps.accessibilityLabel}
95
139
  tokens={selectTokens('Icon', themeTokens, 'icon')}
96
140
  variant={variant}
@@ -111,7 +155,7 @@ IconButton.propTypes = {
111
155
  /**
112
156
  * Defines the icon to be rendered
113
157
  */
114
- icon: PropTypes.elementType.isRequired,
158
+ icon: PropTypes.elementType,
115
159
  /**
116
160
  * URL to navigate to when the `Iconbutton` is pressed
117
161
  */
@@ -86,7 +86,10 @@ const InputLabel = forwardRef(
86
86
  <View
87
87
  style={[
88
88
  staticStyles.tooltipAlign,
89
- { height: themeTokens.fontSize * themeTokens.lineHeight }
89
+ {
90
+ height: themeTokens.fontSize * themeTokens.lineHeight,
91
+ color: themeTokens.color
92
+ }
90
93
  ]}
91
94
  >
92
95
  <Tooltip content={tooltip} copy={copy} />
@@ -36,9 +36,9 @@ const selectOuterBorderStyles = ({
36
36
  ...applyOuterBorder({
37
37
  outerBorderColor,
38
38
  outerBorderWidth,
39
- outerBorderGap,
40
- borderRadius
41
- })
39
+ outerBorderGap
40
+ }),
41
+ borderRadius
42
42
  }
43
43
  : {}
44
44
 
@@ -156,7 +156,6 @@ const LinkBase = forwardRef(
156
156
  const themeTokens = resolveLinkTokens(linkState)
157
157
  const outerBorderStyles = selectOuterBorderStyles(themeTokens)
158
158
  const decorationStyles = selectDecorationStyles(themeTokens)
159
-
160
159
  return [
161
160
  outerBorderStyles,
162
161
  blockLeftStyle,
@@ -119,7 +119,8 @@ const selectIconTokens = ({ iconSize, iconColor }) => ({
119
119
  })
120
120
 
121
121
  const selectIconContainerStyles = ({ paddingRight, paddingBottom }) => ({
122
- paddingRight,
122
+ paddingRight: paddingRight + 4,
123
+ marginRight: -4,
123
124
  paddingBottom
124
125
  })
125
126
 
@@ -134,7 +135,7 @@ const selectValidationIconContainerStyles = ({
134
135
  paddingRight = 0,
135
136
  paddingBottom
136
137
  }) => ({
137
- paddingRight: icon ? paddingRight + iconSize : paddingRight,
138
+ paddingRight: icon ? paddingRight + iconSize + 4 : paddingRight,
138
139
  ...(Platform.OS === 'android'
139
140
  ? {
140
141
  paddingBottom: paddingBottom + ANDROID_VALIDATION_ICON_CONTAINER_OFFSET
@@ -147,6 +147,13 @@ export function verticalAlignRow(verticalAlign, reverse = false) {
147
147
  }
148
148
  }
149
149
 
150
+ const calculateBorderRadius = (borderRadius, outerBorderGap, outerBorderWidth) => {
151
+ if (borderRadius) {
152
+ return borderRadius + outerBorderGap + outerBorderWidth
153
+ }
154
+
155
+ return null
156
+ }
150
157
  /**
151
158
  * Use on an outer container to create an outer border with an optional gap around it
152
159
  * that matches the border radius of any inner border.
@@ -155,11 +162,31 @@ export const applyOuterBorder = ({
155
162
  outerBorderColor,
156
163
  outerBorderWidth = 0,
157
164
  outerBorderGap = 0,
158
- borderRadius = 0
165
+ borderRadius,
166
+ borderTopLeftRadius,
167
+ borderTopRightRadius,
168
+ borderBottomLeftRadius,
169
+ borderBottomRightRadius
159
170
  }) => ({
160
171
  margin: 0 - outerBorderWidth - outerBorderGap,
161
172
  padding: outerBorderGap,
162
- borderRadius: borderRadius + outerBorderGap + outerBorderWidth,
173
+ borderRadius: calculateBorderRadius(borderRadius, outerBorderGap, outerBorderWidth),
174
+ borderTopLeftRadius: calculateBorderRadius(borderTopLeftRadius, outerBorderGap, outerBorderWidth),
175
+ borderTopRightRadius: calculateBorderRadius(
176
+ borderTopRightRadius,
177
+ outerBorderGap,
178
+ outerBorderWidth
179
+ ),
180
+ borderBottomLeftRadius: calculateBorderRadius(
181
+ borderBottomLeftRadius,
182
+ outerBorderGap,
183
+ outerBorderWidth
184
+ ),
185
+ borderBottomRightRadius: calculateBorderRadius(
186
+ borderBottomRightRadius,
187
+ outerBorderGap,
188
+ outerBorderWidth
189
+ ),
163
190
  borderWidth: outerBorderWidth,
164
191
  borderColor: outerBorderColor
165
192
  })
@@ -7,7 +7,11 @@ import Icon from '../Icon'
7
7
 
8
8
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
9
9
 
10
- const selectInnerContainerStyles = ({ borderRadius, width }) => ({ borderRadius, width })
10
+ const selectInnerContainerStyles = ({ borderRadius, width, backgroundColor }) => ({
11
+ borderRadius,
12
+ width,
13
+ backgroundColor
14
+ })
11
15
 
12
16
  const selectIconTokens = ({ iconSize, iconColor, iconScale = 1 }) => ({
13
17
  size: iconSize,