@telus-uds/components-base 3.25.0 → 3.27.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 (48) hide show
  1. package/CHANGELOG.md +28 -1
  2. package/lib/cjs/Card/Card.js +34 -13
  3. package/lib/cjs/Card/CardBase.js +78 -11
  4. package/lib/cjs/Card/PressableCardBase.js +147 -8
  5. package/lib/cjs/Carousel/Carousel.js +161 -77
  6. package/lib/cjs/Carousel/CarouselContext.js +10 -4
  7. package/lib/cjs/Carousel/CarouselItem/CarouselItem.js +11 -7
  8. package/lib/cjs/Carousel/Constants.js +22 -2
  9. package/lib/cjs/Checkbox/Checkbox.js +43 -13
  10. package/lib/cjs/InputSupports/InputSupports.js +2 -1
  11. package/lib/cjs/List/List.js +24 -9
  12. package/lib/cjs/List/ListItem.js +18 -1
  13. package/lib/cjs/List/ListItemBase.js +27 -8
  14. package/lib/cjs/List/ListItemMark.js +33 -62
  15. package/lib/cjs/List/PressableListItemBase.js +1 -0
  16. package/lib/cjs/PriceLockup/PriceLockup.js +1 -1
  17. package/lib/esm/Card/Card.js +34 -13
  18. package/lib/esm/Card/CardBase.js +78 -11
  19. package/lib/esm/Card/PressableCardBase.js +148 -9
  20. package/lib/esm/Carousel/Carousel.js +153 -69
  21. package/lib/esm/Carousel/CarouselContext.js +10 -4
  22. package/lib/esm/Carousel/CarouselItem/CarouselItem.js +11 -7
  23. package/lib/esm/Carousel/Constants.js +21 -1
  24. package/lib/esm/Checkbox/Checkbox.js +43 -13
  25. package/lib/esm/InputSupports/InputSupports.js +2 -1
  26. package/lib/esm/List/List.js +24 -9
  27. package/lib/esm/List/ListItem.js +19 -2
  28. package/lib/esm/List/ListItemBase.js +27 -8
  29. package/lib/esm/List/ListItemMark.js +33 -62
  30. package/lib/esm/List/PressableListItemBase.js +1 -0
  31. package/lib/esm/PriceLockup/PriceLockup.js +1 -1
  32. package/lib/package.json +2 -2
  33. package/package.json +2 -2
  34. package/src/Card/Card.jsx +29 -7
  35. package/src/Card/CardBase.jsx +88 -8
  36. package/src/Card/PressableCardBase.jsx +135 -9
  37. package/src/Carousel/Carousel.jsx +185 -88
  38. package/src/Carousel/CarouselContext.jsx +12 -4
  39. package/src/Carousel/CarouselItem/CarouselItem.jsx +10 -6
  40. package/src/Carousel/Constants.js +24 -0
  41. package/src/Checkbox/Checkbox.jsx +29 -7
  42. package/src/InputSupports/InputSupports.jsx +6 -1
  43. package/src/List/List.jsx +33 -9
  44. package/src/List/ListItem.jsx +33 -11
  45. package/src/List/ListItemBase.jsx +33 -9
  46. package/src/List/ListItemMark.jsx +32 -53
  47. package/src/List/PressableListItemBase.jsx +1 -0
  48. package/src/PriceLockup/PriceLockup.jsx +1 -1
@@ -107,9 +107,51 @@ const setBackgroundImage = _ref => {
107
107
  children: content
108
108
  });
109
109
  };
110
+ const selectPaddedContentStyles = _ref2 => {
111
+ let {
112
+ paddingTop,
113
+ paddingBottom,
114
+ paddingLeft,
115
+ paddingRight,
116
+ borderWidth,
117
+ borderColor,
118
+ borderRadius,
119
+ hasInteractiveBorder
120
+ } = _ref2;
121
+ return {
122
+ paddingTop,
123
+ paddingBottom,
124
+ paddingLeft,
125
+ paddingRight,
126
+ ...(hasInteractiveBorder ? {
127
+ borderWidth,
128
+ borderColor,
129
+ borderRadius
130
+ } : {})
131
+ };
132
+ };
133
+ const selectInteractiveOverlayStyles = _ref3 => {
134
+ let {
135
+ backgroundColor,
136
+ borderRadius,
137
+ borderWidth
138
+ } = _ref3;
139
+ const adjustedBorderRadius = Math.max(0, borderRadius - borderWidth);
140
+ return {
141
+ position: 'absolute',
142
+ top: 0,
143
+ left: 0,
144
+ right: 0,
145
+ bottom: 0,
146
+ backgroundColor,
147
+ borderRadius: adjustedBorderRadius,
148
+ pointerEvents: 'none',
149
+ zIndex: 1
150
+ };
151
+ };
110
152
 
111
153
  // Ensure explicit selection of tokens
112
- export const selectStyles = _ref2 => {
154
+ export const selectStyles = _ref4 => {
113
155
  let {
114
156
  flex,
115
157
  backgroundColor,
@@ -130,7 +172,7 @@ export const selectStyles = _ref2 => {
130
172
  gradient,
131
173
  maxHeight,
132
174
  overflowY
133
- } = _ref2;
175
+ } = _ref4;
134
176
  const hasGradient = (gradient || backgroundGradient) && Platform.OS === 'web';
135
177
  let backgroundImageValue = null;
136
178
  if (hasGradient) {
@@ -176,7 +218,7 @@ export const selectStyles = _ref2 => {
176
218
  * A themeless base component for Card which components can apply theme tokens to. Not
177
219
  * intended to be used in apps or sites directly: build themed components on top of this.
178
220
  */
179
- const CardBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
221
+ const CardBase = /*#__PURE__*/React.forwardRef((_ref5, ref) => {
180
222
  let {
181
223
  children,
182
224
  tokens,
@@ -185,7 +227,7 @@ const CardBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
185
227
  fullBleedContent,
186
228
  cardState,
187
229
  ...rest
188
- } = _ref3;
230
+ } = _ref5;
189
231
  const cardStyle = selectStyles(typeof tokens === 'function' ? tokens(cardState) : tokens);
190
232
  const props = selectProps(rest);
191
233
  let content = children;
@@ -212,26 +254,51 @@ const CardBase = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
212
254
  paddingBottom,
213
255
  paddingLeft,
214
256
  paddingRight,
257
+ borderWidth,
258
+ borderColor,
259
+ borderRadius,
260
+ backgroundColor,
215
261
  ...containerStyle
216
262
  } = cardStyle;
217
263
  const hasPadding = paddingTop || paddingBottom || paddingLeft || paddingRight;
218
- const paddedContent = hasPadding ? /*#__PURE__*/_jsx(View, {
219
- style: {
264
+ const hasInteractiveBorder = borderWidth && borderWidth > 0;
265
+ const hasInteractiveOverlay = isOverlayColor(backgroundColor);
266
+ const paddedContent = hasPadding || hasInteractiveBorder ? /*#__PURE__*/_jsx(View, {
267
+ style: selectPaddedContentStyles({
220
268
  paddingTop,
221
269
  paddingBottom,
222
270
  paddingLeft,
223
- paddingRight
224
- },
271
+ paddingRight,
272
+ borderWidth,
273
+ borderColor,
274
+ borderRadius,
275
+ hasInteractiveBorder
276
+ }),
225
277
  children: children
226
278
  }) : children;
279
+ const contentWithOverlay = /*#__PURE__*/_jsxs(_Fragment, {
280
+ children: [hasInteractiveOverlay && Platform.OS === 'web' && /*#__PURE__*/_jsx(View, {
281
+ style: selectInteractiveOverlayStyles({
282
+ backgroundColor,
283
+ borderRadius,
284
+ borderWidth
285
+ })
286
+ }), /*#__PURE__*/_jsx(View, {
287
+ style: staticStyles.contentOverlay,
288
+ children: paddedContent
289
+ })]
290
+ });
227
291
  content = setBackgroundImage({
228
292
  src: imageSourceViewport,
229
293
  alt,
230
294
  backgroundImageResizeMode,
231
295
  backgroundImagePosition,
232
296
  backgroundImageAlign,
233
- content: paddedContent,
234
- cardStyle: containerStyle
297
+ content: contentWithOverlay,
298
+ cardStyle: {
299
+ ...containerStyle,
300
+ borderRadius
301
+ }
235
302
  });
236
303
  return /*#__PURE__*/_jsx(View, {
237
304
  style: containerStyle,
@@ -313,7 +380,7 @@ const staticStyles = StyleSheet.create({
313
380
  position: 'relative',
314
381
  width: '100%',
315
382
  height: '100%',
316
- zIndex: 1
383
+ zIndex: 2
317
384
  },
318
385
  containContainer: {
319
386
  width: '100%',
@@ -8,8 +8,74 @@ 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
10
  import CardBase, { fullBleedContentPropTypes } from './CardBase';
11
- import { jsx as _jsx } from "react/jsx-runtime";
11
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
12
12
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, focusHandlerProps, viewProps]);
13
+ const selectFocusOverlayContainerStyles = tokens => {
14
+ const {
15
+ flex,
16
+ minWidth,
17
+ marginTop,
18
+ marginBottom,
19
+ marginLeft,
20
+ marginRight
21
+ } = tokens;
22
+ return {
23
+ flex: flex || 1,
24
+ minWidth: minWidth || 0,
25
+ marginTop,
26
+ marginBottom,
27
+ marginLeft,
28
+ marginRight
29
+ };
30
+ };
31
+ const selectFocusBorderStyles = tokens => {
32
+ const {
33
+ borderWidth,
34
+ borderColor,
35
+ borderRadius
36
+ } = tokens;
37
+ return {
38
+ borderWidth,
39
+ borderColor,
40
+ borderRadius: borderRadius || 0
41
+ };
42
+ };
43
+ const FocusBorderOverlay = _ref => {
44
+ let {
45
+ tokens,
46
+ pressableState,
47
+ children
48
+ } = _ref;
49
+ const {
50
+ borderWidth = 0
51
+ } = tokens;
52
+ const showFocusBorder = pressableState.focused && borderWidth > 0;
53
+ return /*#__PURE__*/_jsxs(View, {
54
+ style: [staticStyles.focusOverlayContainer, selectFocusOverlayContainerStyles(tokens), Platform.OS === 'web' && staticStyles.webOutlineNone],
55
+ children: [children, showFocusBorder && /*#__PURE__*/_jsx(View, {
56
+ style: [staticStyles.focusBorder, selectFocusBorderStyles(tokens)],
57
+ accessible: false,
58
+ importantForAccessibility: "no"
59
+ })]
60
+ });
61
+ };
62
+ FocusBorderOverlay.propTypes = {
63
+ tokens: PropTypes.shape({
64
+ flex: PropTypes.number,
65
+ minWidth: PropTypes.number,
66
+ marginTop: PropTypes.number,
67
+ marginBottom: PropTypes.number,
68
+ marginLeft: PropTypes.number,
69
+ marginRight: PropTypes.number,
70
+ borderColor: PropTypes.string,
71
+ borderWidth: PropTypes.number,
72
+ borderRadius: PropTypes.number
73
+ }).isRequired,
74
+ pressableState: PropTypes.shape({
75
+ focused: PropTypes.bool
76
+ }).isRequired,
77
+ children: PropTypes.node
78
+ };
13
79
  const tokenKeys = ['flex', 'backgroundColor', 'borderColor', 'gradient', 'borderRadius', 'borderWidth', 'paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop', 'marginTop', 'marginBottom', 'marginLeft', 'marginRight', 'minWidth', 'shadow', 'contentAlignItems', 'contentJustifyContent', 'contentFlexGrow', 'contentFlexShrink',
14
80
  // Outer border tokens. TODO: centralise common token sets like these as part of
15
81
  // https://github.com/telus/universal-design-system/issues/782
@@ -21,7 +87,7 @@ export const selectPressableCardTokens = tokens => Object.fromEntries(tokenKeys.
21
87
  * based on these to an outer border and a base Card component. Not intended to be used in
22
88
  * apps or sites directly: build themed components on top of this.
23
89
  */
24
- const PressableCardBase = /*#__PURE__*/React.forwardRef((_ref, ref) => {
90
+ const PressableCardBase = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
25
91
  let {
26
92
  children,
27
93
  tokens,
@@ -35,7 +101,7 @@ const PressableCardBase = /*#__PURE__*/React.forwardRef((_ref, ref) => {
35
101
  fullBleedContent,
36
102
  accessibilityRole = href ? 'link' : undefined,
37
103
  ...rawRest
38
- } = _ref;
104
+ } = _ref2;
39
105
  const {
40
106
  onPress,
41
107
  ...rest
@@ -52,11 +118,62 @@ const PressableCardBase = /*#__PURE__*/React.forwardRef((_ref, ref) => {
52
118
  partial: true,
53
119
  allowFunction: true
54
120
  }), 'PressableCard');
55
- const getCardTokens = pressableState => selectTokens('Card', getTokens(pressableState));
121
+ const getCardTokens = pressableState => {
122
+ const allTokens = getTokens(pressableState);
123
+ const cardTokens = selectTokens('Card', allTokens);
124
+
125
+ // Handle focus border transparency to avoid double borders
126
+ if (pressableState.focused && allTokens.borderWidth > 0) {
127
+ const result = {
128
+ ...cardTokens,
129
+ borderColor: 'transparent'
130
+ };
131
+
132
+ // Also handle backgroundImage for interactive states
133
+ if (backgroundImage) {
134
+ const {
135
+ hovered,
136
+ pressed,
137
+ focused
138
+ } = pressableState || {};
139
+ const isInteractiveState = hovered || pressed || focused;
140
+ if (!isInteractiveState) {
141
+ const {
142
+ backgroundColor,
143
+ ...restTokens
144
+ } = result;
145
+ return restTokens;
146
+ }
147
+ }
148
+ return result;
149
+ }
150
+
151
+ // Handle backgroundImage when not in focus state
152
+ if (backgroundImage) {
153
+ const {
154
+ hovered,
155
+ pressed,
156
+ focused
157
+ } = pressableState || {};
158
+ const isInteractiveState = hovered || pressed || focused;
159
+ if (!isInteractiveState) {
160
+ const {
161
+ backgroundColor,
162
+ ...restTokens
163
+ } = cardTokens;
164
+ return restTokens;
165
+ }
166
+ }
167
+ return cardTokens;
168
+ };
56
169
  const getOuterBorderStyle = pressableState => {
57
170
  const {
58
171
  flex,
59
172
  minWidth,
173
+ marginTop,
174
+ marginBottom,
175
+ marginLeft,
176
+ marginRight,
60
177
  outerBorderColor,
61
178
  outerBorderGap = 0,
62
179
  outerBorderWidth = 0,
@@ -65,6 +182,10 @@ const PressableCardBase = /*#__PURE__*/React.forwardRef((_ref, ref) => {
65
182
  return {
66
183
  flex,
67
184
  minWidth: minWidth + outerBorderGap + outerBorderWidth,
185
+ marginTop,
186
+ marginBottom,
187
+ marginLeft,
188
+ marginRight,
68
189
  ...applyOuterBorder({
69
190
  outerBorderColor,
70
191
  outerBorderGap,
@@ -158,11 +279,15 @@ const PressableCardBase = /*#__PURE__*/React.forwardRef((_ref, ref) => {
158
279
  ...rest,
159
280
  accessibilityRole
160
281
  }),
161
- children: pressableState => /*#__PURE__*/_jsx(CardBase, {
162
- tokens: getCardTokens(pressableState),
163
- backgroundImage: backgroundImage,
164
- fullBleedContent: fullBleedContent,
165
- children: typeof children === 'function' ? children(getCardState(pressableState)) : children
282
+ children: pressableState => /*#__PURE__*/_jsx(FocusBorderOverlay, {
283
+ tokens: getTokens(pressableState),
284
+ pressableState: pressableState,
285
+ children: /*#__PURE__*/_jsx(CardBase, {
286
+ tokens: getCardTokens(pressableState),
287
+ backgroundImage: backgroundImage,
288
+ fullBleedContent: fullBleedContent,
289
+ children: typeof children === 'function' ? children(getCardState(pressableState)) : children
290
+ })
166
291
  })
167
292
  });
168
293
  });
@@ -177,6 +302,20 @@ const staticStyles = StyleSheet.create({
177
302
  alignItems: 'stretch',
178
303
  justifyContent: 'flex-start',
179
304
  textDecorationLine: 'none'
305
+ },
306
+ focusOverlayContainer: {
307
+ position: 'relative'
308
+ },
309
+ webOutlineNone: {
310
+ outline: 'none'
311
+ },
312
+ focusBorder: {
313
+ position: 'absolute',
314
+ top: 0,
315
+ left: 0,
316
+ right: 0,
317
+ bottom: 0,
318
+ pointerEvents: 'none'
180
319
  }
181
320
  });
182
321
  PressableCardBase.displayName = 'PressableCardBase';