@telus-uds/components-base 3.30.0 → 3.32.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 (45) hide show
  1. package/CHANGELOG.md +31 -1
  2. package/lib/cjs/Autocomplete/Autocomplete.js +13 -1
  3. package/lib/cjs/Autocomplete/constants.js +1 -1
  4. package/lib/cjs/Button/ButtonGroup.js +91 -23
  5. package/lib/cjs/Card/CardBase.js +75 -47
  6. package/lib/cjs/ColourToggle/ColourBubble.js +65 -12
  7. package/lib/cjs/ColourToggle/ColourToggle.js +40 -11
  8. package/lib/cjs/ColourToggle/constants.js +15 -0
  9. package/lib/cjs/ColourToggle/dictionary.js +15 -0
  10. package/lib/cjs/Listbox/ListboxOverlay.js +7 -1
  11. package/lib/cjs/MultiSelectFilter/ModalOverlay.js +7 -1
  12. package/lib/cjs/MultiSelectFilter/MultiSelectFilter.js +2 -28
  13. package/lib/cjs/TextInput/TextInputBase.js +2 -1
  14. package/lib/cjs/Validator/Validator.js +5 -1
  15. package/lib/cjs/utils/useOverlaidPosition.js +83 -42
  16. package/lib/esm/Autocomplete/Autocomplete.js +13 -1
  17. package/lib/esm/Autocomplete/constants.js +1 -1
  18. package/lib/esm/Button/ButtonGroup.js +91 -23
  19. package/lib/esm/Card/CardBase.js +75 -47
  20. package/lib/esm/ColourToggle/ColourBubble.js +66 -13
  21. package/lib/esm/ColourToggle/ColourToggle.js +41 -12
  22. package/lib/esm/ColourToggle/constants.js +8 -0
  23. package/lib/esm/ColourToggle/dictionary.js +9 -0
  24. package/lib/esm/Listbox/ListboxOverlay.js +7 -1
  25. package/lib/esm/MultiSelectFilter/ModalOverlay.js +8 -2
  26. package/lib/esm/MultiSelectFilter/MultiSelectFilter.js +2 -28
  27. package/lib/esm/TextInput/TextInputBase.js +2 -1
  28. package/lib/esm/Validator/Validator.js +5 -1
  29. package/lib/esm/utils/useOverlaidPosition.js +83 -42
  30. package/lib/package.json +2 -2
  31. package/package.json +2 -2
  32. package/src/Autocomplete/Autocomplete.jsx +11 -2
  33. package/src/Autocomplete/constants.js +1 -1
  34. package/src/Button/ButtonGroup.jsx +93 -24
  35. package/src/Card/CardBase.jsx +94 -75
  36. package/src/ColourToggle/ColourBubble.jsx +62 -7
  37. package/src/ColourToggle/ColourToggle.jsx +50 -10
  38. package/src/ColourToggle/constants.js +10 -0
  39. package/src/ColourToggle/dictionary.js +6 -0
  40. package/src/Listbox/ListboxOverlay.jsx +6 -2
  41. package/src/MultiSelectFilter/ModalOverlay.jsx +9 -3
  42. package/src/MultiSelectFilter/MultiSelectFilter.jsx +1 -31
  43. package/src/TextInput/TextInputBase.jsx +2 -1
  44. package/src/Validator/Validator.jsx +5 -1
  45. package/src/utils/useOverlaidPosition.js +84 -34
package/CHANGELOG.md CHANGED
@@ -1,9 +1,39 @@
1
1
  # Change Log - @telus-uds/components-base
2
2
 
3
- This log was last generated on Thu, 16 Apr 2026 21:04:33 GMT and should not be manually modified.
3
+ This log was last generated on Fri, 29 May 2026 18:55:39 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## 3.32.0
8
+
9
+ Fri, 29 May 2026 18:55:39 GMT
10
+
11
+ ### Minor changes
12
+
13
+ - `ColourToggle`: Add crossedOut variant (david.melara1@telus.com)
14
+ - `Card`: Add testID to CardBase and its subcomponents (david.melara1@telus.com)
15
+ - Bump @telus-uds/system-theme-tokens to v4.22.0
16
+
17
+ ### Patches
18
+
19
+ - `Validator`: Fix guard skipping code reset on empty string value prop (david.melara1@telus.com)
20
+ - `ButtonGroup`: Fixed a bug where it wasn't displaying correctly for the `responsive` width variant on web-mobile, Android, and iOS (kevin.ruiz@telus.com)
21
+ - `Card`: preserve `style` gradient border and custom `backgroundColor` tokens when `backgroundImage` is set (josue.higueroscalderon@telus.com)
22
+
23
+ ## 3.31.0
24
+
25
+ Fri, 22 May 2026 05:09:10 GMT
26
+
27
+ ### Minor changes
28
+
29
+ - `Autocomplete`: Add scroll to overlay in mobile (david.melara1@telus.com)
30
+
31
+ ### Patches
32
+
33
+ - `MultiSelectFilter`: position issues fixed in MFE (josue.higueroscalderon@telus.com)
34
+ - `TextInput`: Fix `onChangeText` returning `undefined` instead of an empty string when `isNumeric` is set and no text is provided (david.melara1@telus.com)
35
+ - `Autocomplete`: inside modal story fixed to show the close button properly (josue.higueroscalderon@telus.com)
36
+
7
37
  ## 3.30.0
8
38
 
9
39
  Thu, 16 Apr 2026 21:04:33 GMT
@@ -126,6 +126,7 @@ const Autocomplete = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
126
126
  value,
127
127
  helpText = '',
128
128
  loadingLabel,
129
+ dropdownPosition = 'bottom',
129
130
  tokens,
130
131
  ...rest
131
132
  } = _ref2;
@@ -181,6 +182,13 @@ const Autocomplete = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
181
182
  isShown: isExpanded || hintExpansionEnabled,
182
183
  offsets: {
183
184
  vertical: _Platform.default.OS !== 'web' && (hint || inputLabel) ? 28 : 4
185
+ },
186
+ align: dropdownPosition === 'top' ? {
187
+ center: 'center',
188
+ bottom: 'top'
189
+ } : {
190
+ center: 'center',
191
+ top: 'bottom'
184
192
  }
185
193
  });
186
194
  const targetRef = _react.default.useRef(null);
@@ -533,6 +541,10 @@ Autocomplete.propTypes = {
533
541
  /**
534
542
  * Input value for controlled usage
535
543
  */
536
- value: _propTypes.default.string
544
+ value: _propTypes.default.string,
545
+ /**
546
+ * Controls whether the dropdown renders above or below the input. Defaults to 'bottom'.
547
+ */
548
+ dropdownPosition: _propTypes.default.oneOf(['top', 'bottom'])
537
549
  };
538
550
  var _default = exports.default = Autocomplete;
@@ -6,6 +6,6 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.MIN_LISTBOX_WIDTH = exports.INPUT_LEFT_PADDING = exports.DEFAULT_MIN_TO_SUGGESTION = exports.DEFAULT_MAX_SUGGESTIONS = exports.DEFAULT_MAX_DROPDOWN_HEIGHT = void 0;
7
7
  const DEFAULT_MIN_TO_SUGGESTION = exports.DEFAULT_MIN_TO_SUGGESTION = 1;
8
8
  const DEFAULT_MAX_SUGGESTIONS = exports.DEFAULT_MAX_SUGGESTIONS = 5;
9
- const DEFAULT_MAX_DROPDOWN_HEIGHT = exports.DEFAULT_MAX_DROPDOWN_HEIGHT = 336; // Approximately 7 items (48px each)
9
+ const DEFAULT_MAX_DROPDOWN_HEIGHT = exports.DEFAULT_MAX_DROPDOWN_HEIGHT = 500;
10
10
  const INPUT_LEFT_PADDING = exports.INPUT_LEFT_PADDING = 16;
11
11
  const MIN_LISTBOX_WIDTH = exports.MIN_LISTBOX_WIDTH = 288;
@@ -21,6 +21,8 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
21
21
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
22
22
  const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.viewProps]);
23
23
  const [selectItemProps, selectedItemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.focusHandlerProps, _utils.pressProps, _utils.viewProps]);
24
+ const EQUAL_WIDTH = 'equal';
25
+ const RESPONSIVE_WIDTH = 'responsive';
24
26
  const ButtonGroup = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
25
27
  let {
26
28
  variant,
@@ -65,31 +67,90 @@ const ButtonGroup = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
65
67
  const isMobileNonContained = _Platform.default.OS !== 'web' && (!variant || variant?.style !== 'contained');
66
68
  const themeButtonTokensCallback = (0, _ThemeProvider.useThemeTokensCallback)('ButtonGroupItem', tokens, variant);
67
69
  const gapValue = (0, _utils.useSpacingScale)(gap || space);
70
+ const isWeb = _Platform.default.OS === 'web';
71
+ const buttonWidthVariant = variant?.width;
68
72
  const getButtonTokens = (0, _react.useCallback)(state => {
69
73
  const themeButtonTokens = themeButtonTokensCallback(state);
70
74
  const shouldUseTransparentBackground = isMobileNonContained && !state.selected && !state.pressed && !state.hover && !state.focus;
75
+ let widthStyle;
76
+ switch (buttonWidthVariant) {
77
+ case EQUAL_WIDTH:
78
+ widthStyle = staticStyles.equalWidth;
79
+ break;
80
+ case RESPONSIVE_WIDTH:
81
+ widthStyle = staticStyles.responsiveWidth;
82
+ break;
83
+ // no default
84
+ }
71
85
  return {
72
86
  ...themeButtonTokens,
73
- ...(variant?.width === 'equal' && staticStyles.equalWidth),
87
+ ...widthStyle,
74
88
  ...(shouldUseTransparentBackground && {
75
89
  backgroundColor: 'transparent'
76
90
  }),
77
91
  alignSelf: themeButtonTokens.width ? 'flex-start' : 'center'
78
92
  };
79
- }, [themeButtonTokensCallback, isMobileNonContained, variant?.width]);
80
- const fieldsetStyles = (0, _react.useMemo)(() => ({
81
- ...staticStyles.fieldsetBase,
82
- borderRadius,
83
- backgroundColor: isMobileNonContained ? 'transparent' : backgroundColor || 'transparent',
84
- padding,
85
- width: variant?.width === 'equal' ? '100%' : 'auto'
86
- }), [borderRadius, backgroundColor, padding, variant?.width, isMobileNonContained]);
87
- const viewStyles = (0, _react.useMemo)(() => ({
88
- ...staticStyles.viewBase,
89
- flexDirection: direction === 'column' ? 'column' : 'row',
90
- gap: gapValue || 0,
91
- justifyContent: variant?.width === 'equal' ? 'space-evenly' : 'flex-start'
92
- }), [direction, gapValue, variant?.width]);
93
+ }, [themeButtonTokensCallback, isMobileNonContained, buttonWidthVariant]);
94
+ const fieldsetStyles = (0, _react.useMemo)(() => {
95
+ let fieldSetBase;
96
+ switch (buttonWidthVariant) {
97
+ case EQUAL_WIDTH:
98
+ case RESPONSIVE_WIDTH:
99
+ fieldSetBase = staticStyles.fieldSetResponsive;
100
+ break;
101
+ default:
102
+ fieldSetBase = staticStyles.fieldsetBase;
103
+ break;
104
+ }
105
+ return {
106
+ ...fieldSetBase,
107
+ borderRadius,
108
+ backgroundColor: isMobileNonContained ? 'transparent' : backgroundColor || 'transparent',
109
+ padding
110
+ };
111
+ }, [borderRadius, backgroundColor, padding, isMobileNonContained, buttonWidthVariant]);
112
+ const buttonsContainerStyles = (0, _react.useMemo)(() => {
113
+ let flexWrap;
114
+ if (isWeb) {
115
+ flexWrap = 'wrap';
116
+ } else {
117
+ switch (buttonWidthVariant) {
118
+ case EQUAL_WIDTH:
119
+ case RESPONSIVE_WIDTH:
120
+ flexWrap = 'nowrap';
121
+ break;
122
+ default:
123
+ flexWrap = 'wrap';
124
+ break;
125
+ }
126
+ }
127
+ let justifyContent;
128
+ switch (buttonWidthVariant) {
129
+ case EQUAL_WIDTH:
130
+ justifyContent = 'space-evenly';
131
+ break;
132
+ default:
133
+ justifyContent = 'flex-start';
134
+ break;
135
+ }
136
+ let viewBaseStyle;
137
+ switch (buttonWidthVariant) {
138
+ case EQUAL_WIDTH:
139
+ case RESPONSIVE_WIDTH:
140
+ viewBaseStyle = {};
141
+ break;
142
+ default:
143
+ viewBaseStyle = staticStyles.viewBase;
144
+ break;
145
+ }
146
+ return {
147
+ ...viewBaseStyle,
148
+ flexWrap,
149
+ flexDirection: direction === 'column' ? 'column' : 'row',
150
+ gap: gapValue || 0,
151
+ justifyContent
152
+ };
153
+ }, [direction, gapValue, buttonWidthVariant, isWeb]);
93
154
  const {
94
155
  currentValues,
95
156
  toggleOneValue
@@ -111,7 +172,7 @@ const ButtonGroup = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
111
172
  }
112
173
 
113
174
  // Some web screenreaders e.g. MacOS Voiceover don't handle radiogroups properly unless radio is direct child of radiogroup
114
- const innerRole = _Platform.default.OS === 'web' && accessibilityRole === 'radiogroup' ? accessibilityRole : undefined;
175
+ const buttonsWrapperRole = _Platform.default.OS === 'web' && accessibilityRole === 'radiogroup' ? accessibilityRole : undefined;
115
176
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Fieldset.default, {
116
177
  ...systemProps,
117
178
  ref: ref,
@@ -129,8 +190,8 @@ const ButtonGroup = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
129
190
  style: fieldsetStyles,
130
191
  ...selectProps(rest),
131
192
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
132
- accessibilityRole: innerRole,
133
- style: viewStyles,
193
+ accessibilityRole: buttonsWrapperRole,
194
+ style: buttonsContainerStyles,
134
195
  children: items.map((_ref2, index) => {
135
196
  let {
136
197
  label,
@@ -298,17 +359,24 @@ ButtonGroup.propTypes = {
298
359
  copy: _propTypes.default.oneOf(['en', 'fr'])
299
360
  };
300
361
  const staticStyles = _StyleSheet.default.create({
362
+ equalWidth: {
363
+ width: '100%',
364
+ flex: 1
365
+ },
366
+ responsiveWidth: {
367
+ width: 'auto'
368
+ },
301
369
  fieldsetBase: {
302
370
  alignSelf: 'flex-start',
303
- display: 'inline'
371
+ display: 'inline',
372
+ width: 'auto'
373
+ },
374
+ fieldSetResponsive: {
375
+ width: '100%'
304
376
  },
305
377
  viewBase: {
306
378
  flexWrap: 'wrap',
307
379
  alignItems: 'center'
308
- },
309
- equalWidth: {
310
- width: '100%',
311
- flex: 1
312
380
  }
313
381
  });
314
382
  var _default = exports.default = ButtonGroup;
@@ -22,9 +22,7 @@ var _jsxRuntime = require("react/jsx-runtime");
22
22
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
23
23
  const [selectProps, selectedSystemPropTypes] = (0, _props.selectSystemProps)([_props.a11yProps, _props.viewProps]);
24
24
  const GRID_COLUMNS = 12;
25
- const isOverlayColor = color => {
26
- return color && typeof color === 'string' && color.startsWith('rgba(');
27
- };
25
+ const isOverlayColor = color => color && typeof color === 'string' && color.startsWith('rgba(');
28
26
  const setBackgroundImage = _ref => {
29
27
  let {
30
28
  src,
@@ -33,7 +31,8 @@ const setBackgroundImage = _ref => {
33
31
  backgroundImagePosition,
34
32
  backgroundImageAlign,
35
33
  content,
36
- cardStyle
34
+ cardStyle,
35
+ testID
37
36
  } = _ref;
38
37
  const borderRadius = cardStyle?.borderRadius || 0;
39
38
  const borderWidth = cardStyle?.borderWidth || 0;
@@ -93,6 +92,7 @@ const setBackgroundImage = _ref => {
93
92
  style: [staticStyles.imageBackground, backgroundImageStyle],
94
93
  role: "img",
95
94
  "aria-label": alt,
95
+ testID: testID,
96
96
  children: content
97
97
  });
98
98
  }
@@ -107,7 +107,8 @@ const setBackgroundImage = _ref => {
107
107
  style: [staticStyles.containImage, positionStyles],
108
108
  accessible: true,
109
109
  accessibilityLabel: alt,
110
- accessibilityIgnoresInvertColors: true
110
+ accessibilityIgnoresInvertColors: true,
111
+ testID: testID
111
112
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
112
113
  style: staticStyles.contentOverlay,
113
114
  children: content
@@ -123,6 +124,7 @@ const setBackgroundImage = _ref => {
123
124
  style: staticStyles.imageBackground,
124
125
  accessible: true,
125
126
  accessibilityLabel: alt,
127
+ testID: testID,
126
128
  children: content
127
129
  });
128
130
  };
@@ -131,22 +133,13 @@ const selectPaddedContentStyles = _ref2 => {
131
133
  paddingTop,
132
134
  paddingBottom,
133
135
  paddingLeft,
134
- paddingRight,
135
- borderWidth,
136
- borderColor,
137
- borderRadius,
138
- hasInteractiveBorder
136
+ paddingRight
139
137
  } = _ref2;
140
138
  return {
141
139
  paddingTop,
142
140
  paddingBottom,
143
141
  paddingLeft,
144
- paddingRight,
145
- ...(hasInteractiveBorder ? {
146
- borderWidth,
147
- borderColor,
148
- borderRadius
149
- } : {})
142
+ paddingRight
150
143
  };
151
144
  };
152
145
  const selectInteractiveOverlayStyles = _ref3 => {
@@ -165,12 +158,31 @@ const selectInteractiveOverlayStyles = _ref3 => {
165
158
  backgroundColor,
166
159
  borderRadius: adjustedBorderRadius,
167
160
  pointerEvents: 'none',
168
- zIndex: 1
161
+ zIndex: 3
162
+ };
163
+ };
164
+ const selectOuterContainerStyles = _ref4 => {
165
+ let {
166
+ containerStyle,
167
+ backgroundColor,
168
+ borderRadius,
169
+ borderColor,
170
+ borderWidth,
171
+ hasGradientToken
172
+ } = _ref4;
173
+ return {
174
+ ...containerStyle,
175
+ backgroundColor,
176
+ borderRadius,
177
+ ...(hasGradientToken ? {} : {
178
+ borderColor,
179
+ borderWidth
180
+ })
169
181
  };
170
182
  };
171
183
 
172
184
  // Ensure explicit selection of tokens
173
- const selectStyles = _ref4 => {
185
+ const selectStyles = function (_ref5) {
174
186
  let {
175
187
  flex,
176
188
  backgroundColor,
@@ -191,7 +203,10 @@ const selectStyles = _ref4 => {
191
203
  gradient,
192
204
  maxHeight,
193
205
  overflowY
194
- } = _ref4;
206
+ } = _ref5;
207
+ let {
208
+ hasBgImage = false
209
+ } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
195
210
  const hasGradient = (gradient || backgroundGradient) && _Platform.default.OS === 'web';
196
211
  let backgroundImageValue = null;
197
212
  if (hasGradient) {
@@ -220,7 +235,11 @@ const selectStyles = _ref4 => {
220
235
  ...(gradient && _Platform.default.OS === 'web' ? {
221
236
  backgroundImage: backgroundImageValue,
222
237
  backgroundOrigin: `border-box`,
223
- boxShadow: `inset 0 1000px ${boxShadowColor}`,
238
+ // bgImage child fills the content-box and replaces what the inset shadow
239
+ // used to cover, so we omit it to avoid hiding the image.
240
+ ...(hasBgImage ? {} : {
241
+ boxShadow: `inset 0 1000px ${boxShadowColor}`
242
+ }),
224
243
  border: `${borderWidth}px solid transparent`
225
244
  } : {}),
226
245
  ...(backgroundGradient && _Platform.default.OS === 'web' ? {
@@ -238,7 +257,7 @@ const selectStyles = _ref4 => {
238
257
  * intended to be used in apps or sites directly: build themed components on top of this.
239
258
  */
240
259
  exports.selectStyles = selectStyles;
241
- const CardBase = /*#__PURE__*/_react.default.forwardRef((_ref5, ref) => {
260
+ const CardBase = /*#__PURE__*/_react.default.forwardRef((_ref6, ref) => {
242
261
  let {
243
262
  children,
244
263
  tokens,
@@ -246,15 +265,14 @@ const CardBase = /*#__PURE__*/_react.default.forwardRef((_ref5, ref) => {
246
265
  backgroundImage,
247
266
  fullBleedContent,
248
267
  cardState,
268
+ testID,
249
269
  ...rest
250
- } = _ref5;
270
+ } = _ref6;
251
271
  const resolvedTokens = typeof tokens === 'function' ? tokens(cardState) : tokens;
252
- const tokensToUse = backgroundImage && backgroundImage.src ? {
253
- ...resolvedTokens,
254
- gradient: undefined,
255
- backgroundGradient: undefined
256
- } : resolvedTokens;
257
- const cardStyle = selectStyles(tokensToUse);
272
+ const hasBgImage = Boolean(backgroundImage && backgroundImage.src);
273
+ const cardStyle = selectStyles(resolvedTokens, {
274
+ hasBgImage
275
+ });
258
276
  const props = selectProps(rest);
259
277
  let content = children;
260
278
  const {
@@ -287,31 +305,29 @@ const CardBase = /*#__PURE__*/_react.default.forwardRef((_ref5, ref) => {
287
305
  ...containerStyle
288
306
  } = cardStyle;
289
307
  const hasPadding = paddingTop || paddingBottom || paddingLeft || paddingRight;
290
- const hasInteractiveBorder = borderWidth && borderWidth > 0;
291
308
  const hasInteractiveOverlay = isOverlayColor(backgroundColor);
292
- const paddedContent = hasPadding || hasInteractiveBorder ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
309
+ const outerBackgroundColor = hasInteractiveOverlay ? undefined : backgroundColor;
310
+ const hasGradientToken = Boolean(resolvedTokens.gradient) && _Platform.default.OS === 'web';
311
+ const paddedContent = hasPadding ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
293
312
  style: selectPaddedContentStyles({
294
313
  paddingTop,
295
314
  paddingBottom,
296
315
  paddingLeft,
297
- paddingRight,
298
- borderWidth,
299
- borderColor,
300
- borderRadius,
301
- hasInteractiveBorder
316
+ paddingRight
302
317
  }),
303
318
  children: children
304
319
  }) : children;
305
320
  const contentWithOverlay = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
306
- children: [hasInteractiveOverlay && _Platform.default.OS === 'web' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
321
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
322
+ style: staticStyles.contentOverlay,
323
+ children: paddedContent
324
+ }), hasInteractiveOverlay && _Platform.default.OS === 'web' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
307
325
  style: selectInteractiveOverlayStyles({
308
326
  backgroundColor,
309
327
  borderRadius,
310
328
  borderWidth
311
- })
312
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
313
- style: staticStyles.contentOverlay,
314
- children: paddedContent
329
+ }),
330
+ testID: testID && `${testID}-card-base-bg-overlay`
315
331
  })]
316
332
  });
317
333
  content = setBackgroundImage({
@@ -322,17 +338,23 @@ const CardBase = /*#__PURE__*/_react.default.forwardRef((_ref5, ref) => {
322
338
  backgroundImageAlign,
323
339
  content: contentWithOverlay,
324
340
  cardStyle: {
325
- ...containerStyle,
326
- borderRadius
327
- }
341
+ borderRadius,
342
+ borderWidth
343
+ },
344
+ testID: testID && `${testID}-card-base-bg-image`
328
345
  });
329
346
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
330
- style: {
331
- ...containerStyle,
332
- borderRadius
333
- },
347
+ style: selectOuterContainerStyles({
348
+ containerStyle,
349
+ backgroundColor: outerBackgroundColor,
350
+ borderRadius,
351
+ borderColor,
352
+ borderWidth,
353
+ hasGradientToken
354
+ }),
334
355
  dataSet: dataSet,
335
356
  ref: ref,
357
+ testID: testID,
336
358
  ...props,
337
359
  children: content
338
360
  });
@@ -372,6 +394,7 @@ const CardBase = /*#__PURE__*/_react.default.forwardRef((_ref5, ref) => {
372
394
  style: containerStyle,
373
395
  dataSet: dataSet,
374
396
  ref: ref,
397
+ testID: testID,
375
398
  ...props,
376
399
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_FlexGrid.default, {
377
400
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Row.default, {
@@ -388,6 +411,7 @@ const CardBase = /*#__PURE__*/_react.default.forwardRef((_ref5, ref) => {
388
411
  style: cardStyle,
389
412
  dataSet: dataSet,
390
413
  ref: ref,
414
+ testID: testID,
391
415
  ...props,
392
416
  children: content
393
417
  });
@@ -430,6 +454,10 @@ CardBase.propTypes = {
430
454
  ...selectedSystemPropTypes,
431
455
  children: _propTypes.default.node,
432
456
  tokens: (0, _utils.getTokensPropType)('Card'),
457
+ /**
458
+ * Identifier for testing purposes.
459
+ */
460
+ testID: _propTypes.default.string,
433
461
  /**
434
462
  * Apply background image to the card.
435
463
  */
@@ -9,10 +9,12 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
9
9
  var _View = _interopRequireDefault(require("react-native-web/dist/cjs/exports/View"));
10
10
  var _Pressable = _interopRequireDefault(require("react-native-web/dist/cjs/exports/Pressable"));
11
11
  var _Platform = _interopRequireDefault(require("react-native-web/dist/cjs/exports/Platform"));
12
+ var _StyleSheet = _interopRequireDefault(require("react-native-web/dist/cjs/exports/StyleSheet"));
12
13
  var _pressability = require("../utils/pressability");
13
14
  var _ThemeProvider = require("../ThemeProvider");
14
15
  var _utils = require("../utils");
15
16
  var _Tooltip = _interopRequireDefault(require("../Tooltip"));
17
+ var _constants = require("./constants");
16
18
  var _jsxRuntime = require("react/jsx-runtime");
17
19
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
18
20
  const selectGeneralBubbleTokens = _ref => {
@@ -70,37 +72,70 @@ const selectBorderBubbleTokens = _ref3 => {
70
72
  borderRadius: bubbleBorderRadius
71
73
  };
72
74
  };
73
- const ColourBubble = /*#__PURE__*/_react.default.forwardRef((_ref4, ref) => {
75
+ const selectOverlayStyles = _ref4 => {
74
76
  let {
75
- tokens = {},
77
+ overlayColor,
78
+ innerBubbleBorderRadius
79
+ } = _ref4;
80
+ return {
81
+ borderRadius: innerBubbleBorderRadius,
82
+ backgroundColor: overlayColor
83
+ };
84
+ };
85
+ const selectSlashStyles = (_ref5, unavailable) => {
86
+ let {
87
+ slashLightColor,
88
+ slashDarkColor,
89
+ slashWidth,
90
+ slashOffset
91
+ } = _ref5;
92
+ return {
93
+ width: slashWidth,
94
+ backgroundColor: unavailable === _constants.UNAVAILABLE_VARIANT.DARK ? slashDarkColor : slashLightColor,
95
+ marginLeft: slashOffset
96
+ };
97
+ };
98
+ const ColourBubble = /*#__PURE__*/_react.default.forwardRef((_ref6, ref) => {
99
+ let {
100
+ tokens = () => ({}),
76
101
  id,
77
102
  colourHexCode,
78
103
  colourName,
79
104
  isSelected,
80
105
  onPress,
81
- showTooltip
82
- } = _ref4;
106
+ showTooltip,
107
+ unavailable,
108
+ isDisabled
109
+ } = _ref6;
83
110
  const defaultTokens = tokens({
84
111
  selected: isSelected
85
112
  });
86
- const resolveColourBubbleTokens = pressState => (0, _pressability.resolvePressableTokens)(tokens, pressState, {});
87
- const themeTokens = _react.default.useMemo(() => tokens(), [tokens]);
88
- const pressable = /*#__PURE__*/(0, _jsxRuntime.jsx)(_Pressable.default, {
113
+ const resolveColourBubbleTokens = pressState => (0, _pressability.resolvePressableTokens)(tokens, isDisabled ? {} : pressState, {});
114
+ const themeTokens = tokens();
115
+ const pressable = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Pressable.default, {
89
116
  style: state => [selectGeneralBubbleTokens(resolveColourBubbleTokens(state)), isSelected && selectBorderBubbleTokens(defaultTokens)],
90
117
  onPress: onPress,
118
+ disabled: isDisabled,
119
+ focusable: !isDisabled,
91
120
  accessible: true,
92
121
  accessibilityRole: "radio",
93
122
  accessibilityLabel: colourName,
94
123
  accessibilityState: {
95
- checked: isSelected
124
+ checked: isSelected,
125
+ disabled: isDisabled
96
126
  },
97
127
  ref: ref,
98
128
  testID: id,
99
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
129
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
100
130
  style: [selectInnerBubbleTokens(themeTokens), {
101
131
  backgroundColor: colourHexCode
102
- }]
103
- })
132
+ }],
133
+ children: unavailable && /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
134
+ style: [_StyleSheet.default.absoluteFillObject, selectOverlayStyles(themeTokens)]
135
+ })
136
+ }), unavailable && /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
137
+ style: [staticStyles.indicator, selectSlashStyles(themeTokens, unavailable)]
138
+ })]
104
139
  });
105
140
  if (showTooltip) {
106
141
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
@@ -142,6 +177,24 @@ ColourBubble.propTypes = {
142
177
  /**
143
178
  * When true, wraps the bubble in a Tooltip that displays the colourName on hover (web only).
144
179
  */
145
- showTooltip: _propTypes.default.bool
180
+ showTooltip: _propTypes.default.bool,
181
+ /**
182
+ * When set, renders a diagonal indicator over the bubble. Accepts either 'dark' or 'light' to determine the colour of the indicator.
183
+ */
184
+ unavailable: _propTypes.default.oneOf(Object.values(_constants.UNAVAILABLE_VARIANT)),
185
+ /**
186
+ * When true, disables interaction on the bubble.
187
+ */
188
+ isDisabled: _propTypes.default.bool
146
189
  };
190
+ const staticStyles = _StyleSheet.default.create({
191
+ indicator: {
192
+ position: 'absolute',
193
+ top: '50%',
194
+ height: 2,
195
+ transform: [{
196
+ rotate: '-45deg'
197
+ }]
198
+ }
199
+ });
147
200
  var _default = exports.default = ColourBubble;