@telus-uds/components-base 3.28.1 → 3.29.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 (54) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/lib/cjs/Autocomplete/Autocomplete.js +86 -32
  3. package/lib/cjs/Autocomplete/constants.js +2 -1
  4. package/lib/cjs/Card/CardBase.js +12 -0
  5. package/lib/cjs/Carousel/Carousel.js +1 -2
  6. package/lib/cjs/ColourToggle/ColourBubble.js +17 -3
  7. package/lib/cjs/ColourToggle/ColourToggle.js +8 -2
  8. package/lib/cjs/ExpandCollapse/Control.js +17 -3
  9. package/lib/cjs/ExpandCollapse/Panel.js +6 -0
  10. package/lib/cjs/ExpandCollapseMini/ExpandCollapseMini.js +14 -2
  11. package/lib/cjs/ExpandCollapseMini/ExpandCollapseMiniControl.js +15 -2
  12. package/lib/cjs/Link/ChevronLink.js +1 -0
  13. package/lib/cjs/Link/LinkBase.js +29 -13
  14. package/lib/cjs/Link/MobileIconTextContent.js +156 -0
  15. package/lib/cjs/Listbox/ListboxOverlay.js +7 -1
  16. package/lib/cjs/Listbox/PressableItem.js +2 -2
  17. package/lib/cjs/TabBar/TabBar.js +7 -2
  18. package/lib/cjs/TextInput/TextInputBase.js +2 -2
  19. package/lib/esm/Autocomplete/Autocomplete.js +87 -33
  20. package/lib/esm/Autocomplete/constants.js +1 -0
  21. package/lib/esm/Card/CardBase.js +12 -0
  22. package/lib/esm/Carousel/Carousel.js +1 -2
  23. package/lib/esm/ColourToggle/ColourBubble.js +17 -3
  24. package/lib/esm/ColourToggle/ColourToggle.js +8 -2
  25. package/lib/esm/ExpandCollapse/Control.js +17 -3
  26. package/lib/esm/ExpandCollapse/Panel.js +6 -0
  27. package/lib/esm/ExpandCollapseMini/ExpandCollapseMini.js +14 -2
  28. package/lib/esm/ExpandCollapseMini/ExpandCollapseMiniControl.js +15 -2
  29. package/lib/esm/Link/ChevronLink.js +1 -0
  30. package/lib/esm/Link/LinkBase.js +29 -13
  31. package/lib/esm/Link/MobileIconTextContent.js +147 -0
  32. package/lib/esm/Listbox/ListboxOverlay.js +7 -1
  33. package/lib/esm/Listbox/PressableItem.js +3 -3
  34. package/lib/esm/TabBar/TabBar.js +7 -2
  35. package/lib/esm/TextInput/TextInputBase.js +2 -2
  36. package/lib/package.json +1 -1
  37. package/package.json +1 -1
  38. package/src/Autocomplete/Autocomplete.jsx +142 -77
  39. package/src/Autocomplete/constants.js +1 -0
  40. package/src/Card/CardBase.jsx +12 -0
  41. package/src/Carousel/Carousel.jsx +1 -2
  42. package/src/ColourToggle/ColourBubble.jsx +18 -3
  43. package/src/ColourToggle/ColourToggle.jsx +7 -2
  44. package/src/ExpandCollapse/Control.jsx +24 -4
  45. package/src/ExpandCollapse/Panel.jsx +6 -0
  46. package/src/ExpandCollapseMini/ExpandCollapseMini.jsx +23 -3
  47. package/src/ExpandCollapseMini/ExpandCollapseMiniControl.jsx +14 -2
  48. package/src/Link/ChevronLink.jsx +1 -0
  49. package/src/Link/LinkBase.jsx +47 -20
  50. package/src/Link/MobileIconTextContent.jsx +129 -0
  51. package/src/Listbox/ListboxOverlay.jsx +9 -1
  52. package/src/Listbox/PressableItem.jsx +1 -1
  53. package/src/TabBar/TabBar.jsx +21 -4
  54. package/src/TextInput/TextInputBase.jsx +2 -2
package/CHANGELOG.md CHANGED
@@ -1,9 +1,33 @@
1
1
  # Change Log - @telus-uds/components-base
2
2
 
3
- This log was last generated on Fri, 20 Feb 2026 23:53:11 GMT and should not be manually modified.
3
+ This log was last generated on Fri, 13 Mar 2026 20:33:41 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## 3.29.0
8
+
9
+ Fri, 13 Mar 2026 20:33:41 GMT
10
+
11
+ ### Minor changes
12
+
13
+ - `ExpandCollapseMini`: add align prop (guillermo.peitzner@telus.com)
14
+ - `ColourToggle`: add showTooltips prop (guillermo.peitzner@telus.com)
15
+
16
+ ### Patches
17
+
18
+ - `Card`: combinations of align and position fixed (josue.higueroscalderon@telus.com)
19
+ - `TabBar`: missing accesible text for the component added (josue.higueroscalderon@telus.com)
20
+ - `ChevronLink`: fix mobile icon vertical alignment (guillermo.peitzner@telus.com)
21
+
22
+ ## 3.28.2
23
+
24
+ Tue, 03 Mar 2026 23:02:55 GMT
25
+
26
+ ### Patches
27
+
28
+ - `Carousel`: inverse variant navigation arrows fixed by always using raised style even in the inverse state (josue.higueros@telus.com)
29
+ - `Autocomplete`: add the ability to show all values and filter them (josue.higueroscalderon@telus.com)
30
+
7
31
  ## 3.28.1
8
32
 
9
33
  Fri, 20 Feb 2026 23:53:11 GMT
@@ -51,22 +51,36 @@ const highlightAllMatches = function (str) {
51
51
  tokens: {
52
52
  color: resultsTextColor
53
53
  },
54
- children: matchIndexes.reduce((acc, matchIndex, index) => [...acc,
55
- // Add a piece of the string up to the first occurrence of the substring
56
- index === 0 && (str.slice(0, matchIndex) ?? ''),
57
- /*#__PURE__*/
58
- // Unbold the occurrence of the substring (while keeping the original casing)
59
- (0, _jsxRuntime.jsx)(_Typography.default, {
60
- variant: {
61
- bold: true
62
- },
63
- tokens: {
64
- color: resultsTextColor
65
- },
66
- children: str.slice(matchIndex, matchIndex + substring.length)
67
- }, matchIndex),
68
- // Add the rest of the string until the next occurrence or the end of it
69
- str.slice(matchIndex + substring.length, matchIndexes[index + 1] ?? str.length)], [])
54
+ children: matchIndexes.reduce((acc, matchIndex, index) => {
55
+ const prefix = index === 0 ? str.slice(0, matchIndex) : null;
56
+ const match = str.slice(matchIndex, matchIndex + substring.length);
57
+ const suffix = str.slice(matchIndex + substring.length, matchIndexes[index + 1] ?? str.length);
58
+ return [...acc, prefix ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Typography.default, {
59
+ variant: {
60
+ bold: false
61
+ },
62
+ tokens: {
63
+ color: resultsTextColor
64
+ },
65
+ children: prefix
66
+ }, `pre-${matchIndex}`) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_Typography.default, {
67
+ variant: {
68
+ bold: true
69
+ },
70
+ tokens: {
71
+ color: resultsTextColor
72
+ },
73
+ children: match
74
+ }, matchIndex), suffix ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Typography.default, {
75
+ variant: {
76
+ bold: false
77
+ },
78
+ tokens: {
79
+ color: resultsTextColor
80
+ },
81
+ children: suffix
82
+ }, `post-${matchIndex}`) : null];
83
+ }, []).filter(Boolean)
70
84
  })
71
85
  );
72
86
  };
@@ -100,12 +114,14 @@ const Autocomplete = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
100
114
  isLoading = false,
101
115
  items,
102
116
  maxSuggestions = _constants.DEFAULT_MAX_SUGGESTIONS,
117
+ maxDropdownHeight = _constants.DEFAULT_MAX_DROPDOWN_HEIGHT,
103
118
  minToSuggestion = _constants.DEFAULT_MIN_TO_SUGGESTION,
104
119
  noResults,
105
120
  onChange,
106
121
  onClear,
107
122
  onSelect,
108
123
  readOnly,
124
+ showOptionsOnFocus = false,
109
125
  validation,
110
126
  value,
111
127
  helpText = '',
@@ -154,7 +170,7 @@ const Autocomplete = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
154
170
  hint,
155
171
  label: inputLabel
156
172
  } = supportsProps;
157
- const hintExpansionEnabled = isFocused && helpText && !currentValue;
173
+ const hintExpansionEnabled = isFocused && !!helpText && !currentValue;
158
174
  const {
159
175
  overlaidPosition,
160
176
  sourceRef: inputRef,
@@ -208,9 +224,10 @@ const Autocomplete = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
208
224
  }
209
225
  };
210
226
  const handleChange = newValue => {
211
- onChange?.(newValue || '');
227
+ onChange?.(newValue);
212
228
  setCurrentValue(newValue);
213
- setIsExpanded(newValue?.length >= minToSuggestion);
229
+ const shouldExpand = newValue?.length >= minToSuggestion || showOptionsOnFocus && isFocused && newValue?.length === 0;
230
+ setIsExpanded(shouldExpand);
214
231
  if (!isControlled && initialItems !== undefined) {
215
232
  setCurrentItems(initialItems.filter(_ref3 => {
216
233
  let {
@@ -222,25 +239,29 @@ const Autocomplete = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
222
239
  };
223
240
  const handleSelect = selectedId => {
224
241
  onSelect?.(selectedId);
225
- const {
226
- label: newValue,
227
- nested,
228
- title
229
- } = (isControlled ? items : currentItems)?.find(_ref4 => {
242
+ const selectedItem = (isControlled ? items : currentItems)?.find(_ref4 => {
230
243
  let {
231
244
  id
232
245
  } = _ref4;
233
246
  return id === selectedId;
234
247
  });
248
+ const {
249
+ label,
250
+ nested,
251
+ title
252
+ } = selectedItem;
235
253
  if (title) return;
236
254
  if (!nested) {
237
255
  setNestedSelectedValue(null);
238
- onChange?.(newValue);
256
+ onChange?.(label);
239
257
  setIsExpanded(false);
258
+ setCurrentValue(label);
259
+ }
260
+ if (!isControlled && inputRef?.current) inputRef.current.value = label;
261
+ if (nested) {
262
+ setNestedSelectedValue(label);
263
+ setCurrentValue(label);
240
264
  }
241
- setCurrentValue(newValue);
242
- if (!isControlled && inputRef?.current) inputRef.current.value = newValue;
243
- if (nested) setNestedSelectedValue(newValue);
244
265
  inputRef.current.focus();
245
266
  };
246
267
 
@@ -288,15 +309,33 @@ const Autocomplete = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
288
309
  };
289
310
  }, [inputRef]);
290
311
  const handleClose = event => {
291
- if (event.type === 'keydown' && (event.key === 'Escape' || event.key === '27') || event.type === 'click' && !openOverlayRef?.current?.contains(event.target) || event.type === 'touchstart' && openOverlayRef?.current && event.touches[0].target && !openOverlayRef?.current?.contains(event.touches[0].target)) {
312
+ if (event.type === 'keydown' && (event.key === 'Escape' || event.key === '27')) {
292
313
  setIsExpanded(false);
293
314
  setNestedSelectedValue(null);
294
- } else if (event.type === 'keydown' && (event.key === 'ArrowDown' || event.key === 'Tab') && isExpanded && !isLoading && targetRef?.current) {
315
+ return;
316
+ }
317
+ if (event.type === 'keydown' && (event.key === 'ArrowDown' || event.key === 'Tab') && isExpanded && !isLoading && targetRef?.current) {
295
318
  event.preventDefault();
296
319
  targetRef.current.focus();
320
+ return;
321
+ }
322
+ if (event.type === 'click' || event.type === 'touchstart') {
323
+ const clickTarget = event.type === 'click' ? event.target : event.touches[0]?.target;
324
+ const isOutsideOverlay = openOverlayRef?.current && !openOverlayRef.current.contains(clickTarget);
325
+ const isOutsideInput = inputRef?.current && !inputRef.current.contains(clickTarget);
326
+ if (isOutsideOverlay && isOutsideInput) {
327
+ setIsExpanded(false);
328
+ setNestedSelectedValue(null);
329
+ }
297
330
  }
298
331
  };
299
- const itemsToShow = currentValue ? itemsToSuggest(highlight(isControlled ? items : currentItems, currentValue, resultsTextColor)) : [];
332
+ // Calculate items to show based on current state
333
+ let itemsToShow = [];
334
+ if (currentValue?.length > 0) {
335
+ itemsToShow = itemsToSuggest(highlight(isControlled ? items : currentItems, currentValue, resultsTextColor));
336
+ } else if (showOptionsOnFocus && isFocused) {
337
+ itemsToShow = itemsToSuggest(isControlled ? items : currentItems || initialItems);
338
+ }
300
339
  const helpTextToShow = isFocused && !currentValue ? helpText : noResults ?? getCopy('noResults');
301
340
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_View.default, {
302
341
  style: staticStyles.container,
@@ -333,9 +372,15 @@ const Autocomplete = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
333
372
  onChange: handleChange,
334
373
  onFocus: () => {
335
374
  setisFocused(true);
375
+ if (showOptionsOnFocus && (!currentValue || currentValue.length === 0)) {
376
+ setIsExpanded(true);
377
+ }
336
378
  },
337
379
  onBlur: () => {
338
380
  setisFocused(false);
381
+ if (showOptionsOnFocus && (!currentValue || currentValue.length === 0)) {
382
+ setIsExpanded(false);
383
+ }
339
384
  },
340
385
  onClear: onClear,
341
386
  onKeyPress: handleClose,
@@ -367,12 +412,13 @@ const Autocomplete = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
367
412
  })
368
413
  });
369
414
  }
370
- }), (isExpanded || hintExpansionEnabled) && isInputVisible && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
415
+ }), (isExpanded || hintExpansionEnabled) && isInputVisible && (itemsToShow.length > 0 || isExpanded || hintExpansionEnabled) && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
371
416
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Listbox.default.Overlay, {
372
417
  overlaidPosition: overlaidPosition,
373
418
  isReady: isReady,
374
419
  minWidth: fullWidth ? inputWidth : _constants.MIN_LISTBOX_WIDTH,
375
420
  maxWidth: inputWidth,
421
+ maxHeight: maxDropdownHeight,
376
422
  onLayout: handleMeasure,
377
423
  tokens: restOfTokens,
378
424
  ref: openOverlayRef,
@@ -456,6 +502,10 @@ Autocomplete.propTypes = {
456
502
  * Maximum number of suggestions provided at the same time
457
503
  */
458
504
  maxSuggestions: _propTypes.default.number,
505
+ /**
506
+ * Maximum height (in pixels) of the dropdown before scrolling is enabled
507
+ */
508
+ maxDropdownHeight: _propTypes.default.number,
459
509
  /**
460
510
  * Text or JSX to render when no results are available
461
511
  */
@@ -476,6 +526,10 @@ Autocomplete.propTypes = {
476
526
  * Callback function to be called when an item is selected from the list
477
527
  */
478
528
  onSelect: _propTypes.default.func,
529
+ /**
530
+ * When true, displays all available options when the input receives focus (even without typing)
531
+ */
532
+ showOptionsOnFocus: _propTypes.default.bool,
479
533
  /**
480
534
  * Input value for controlled usage
481
535
  */
@@ -3,8 +3,9 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.MIN_LISTBOX_WIDTH = exports.INPUT_LEFT_PADDING = exports.DEFAULT_MIN_TO_SUGGESTION = exports.DEFAULT_MAX_SUGGESTIONS = void 0;
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
10
  const INPUT_LEFT_PADDING = exports.INPUT_LEFT_PADDING = 16;
10
11
  const MIN_LISTBOX_WIDTH = exports.MIN_LISTBOX_WIDTH = 288;
@@ -64,9 +64,21 @@ const setBackgroundImage = _ref => {
64
64
  case 'left-center':
65
65
  backgroundPosition = 'left center';
66
66
  break;
67
+ case 'left-start':
68
+ backgroundPosition = 'left top';
69
+ break;
70
+ case 'left-end':
71
+ backgroundPosition = 'left bottom';
72
+ break;
67
73
  case 'right-center':
68
74
  backgroundPosition = 'right center';
69
75
  break;
76
+ case 'right-start':
77
+ backgroundPosition = 'right top';
78
+ break;
79
+ case 'right-end':
80
+ backgroundPosition = 'right bottom';
81
+ break;
70
82
  default:
71
83
  backgroundPosition = 'center center';
72
84
  }
@@ -924,8 +924,7 @@ const Carousel = /*#__PURE__*/_react.default.forwardRef((_ref3, ref) => {
924
924
  // Related discussion - https://github.com/telus/universal-design-system/issues/1549
925
925
  const previousNextIconButtonVariants = {
926
926
  size: previousNextIconSize,
927
- raised: !variant?.inverse && true,
928
- inverse: variant?.inverse
927
+ raised: true
929
928
  };
930
929
  const getCopyWithPlaceholders = _react.default.useCallback(copyKey => {
931
930
  const copyText = getCopy(copyKey).replace(/%\{title\}/g, title).replace(/%\{itemLabel\}/g, itemLabel).replace(/%\{stepNumber\}/g, activeIndex + 1).replace(/%\{stepCount\}/g, totalItems);
@@ -12,6 +12,7 @@ var _Platform = _interopRequireDefault(require("react-native-web/dist/cjs/export
12
12
  var _pressability = require("../utils/pressability");
13
13
  var _ThemeProvider = require("../ThemeProvider");
14
14
  var _utils = require("../utils");
15
+ var _Tooltip = _interopRequireDefault(require("../Tooltip"));
15
16
  var _jsxRuntime = require("react/jsx-runtime");
16
17
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
18
  const selectGeneralBubbleTokens = _ref => {
@@ -76,14 +77,15 @@ const ColourBubble = /*#__PURE__*/_react.default.forwardRef((_ref4, ref) => {
76
77
  colourHexCode,
77
78
  colourName,
78
79
  isSelected,
79
- onPress
80
+ onPress,
81
+ showTooltip
80
82
  } = _ref4;
81
83
  const defaultTokens = tokens({
82
84
  selected: isSelected
83
85
  });
84
86
  const resolveColourBubbleTokens = pressState => (0, _pressability.resolvePressableTokens)(tokens, pressState, {});
85
87
  const themeTokens = _react.default.useMemo(() => tokens(), [tokens]);
86
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Pressable.default, {
88
+ const pressable = /*#__PURE__*/(0, _jsxRuntime.jsx)(_Pressable.default, {
87
89
  style: state => [selectGeneralBubbleTokens(resolveColourBubbleTokens(state)), isSelected && selectBorderBubbleTokens(defaultTokens)],
88
90
  onPress: onPress,
89
91
  accessible: true,
@@ -100,6 +102,14 @@ const ColourBubble = /*#__PURE__*/_react.default.forwardRef((_ref4, ref) => {
100
102
  }]
101
103
  })
102
104
  });
105
+ if (showTooltip) {
106
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
107
+ content: colourName,
108
+ activateOnHover: true,
109
+ children: pressable
110
+ });
111
+ }
112
+ return pressable;
103
113
  });
104
114
  ColourBubble.displayName = 'ColourBubble';
105
115
  ColourBubble.propTypes = {
@@ -128,6 +138,10 @@ ColourBubble.propTypes = {
128
138
  * of the color is changed of all currently `items`.
129
139
  * Receives two parameters: item object selected and the event
130
140
  */
131
- onPress: _propTypes.default.func
141
+ onPress: _propTypes.default.func,
142
+ /**
143
+ * When true, wraps the bubble in a Tooltip that displays the colourName on hover (web only).
144
+ */
145
+ showTooltip: _propTypes.default.bool
132
146
  };
133
147
  var _default = exports.default = ColourBubble;
@@ -22,6 +22,7 @@ const ColourToggle = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
22
22
  defaultColourId,
23
23
  items,
24
24
  onChange,
25
+ showTooltips,
25
26
  ...rest
26
27
  } = _ref;
27
28
  const [currentColourId, setCurrentColourId] = _react.default.useState(defaultColourId);
@@ -61,7 +62,8 @@ const ColourToggle = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
61
62
  isSelected: id === currentColourId,
62
63
  colourHexCode: colourHexCode,
63
64
  colourName: colourName,
64
- onPress: handleChangeColour
65
+ onPress: handleChangeColour,
66
+ showTooltip: showTooltips
65
67
  }, colourBubbleId);
66
68
  })
67
69
  })]
@@ -93,6 +95,10 @@ ColourToggle.propTypes = {
93
95
  /**
94
96
  * If provided, this function is called when the current selection of the color is changed of all currently `items`. Receives two parameters: item object selected and the event
95
97
  */
96
- onChange: _propTypes.default.func
98
+ onChange: _propTypes.default.func,
99
+ /**
100
+ * When true, displays each colour's name as a tooltip on hover (web only).
101
+ */
102
+ showTooltips: _propTypes.default.bool
97
103
  };
98
104
  var _default = exports.default = ColourToggle;
@@ -73,11 +73,15 @@ function selectIconContainerStyles(_ref2) {
73
73
  }
74
74
  function selectTextContainerStyles(_ref3) {
75
75
  let {
76
- textLine
76
+ textLine,
77
+ controlAlign
77
78
  } = _ref3;
78
79
  return {
79
80
  textDecorationLine: textLine,
80
- flex: 1
81
+ flex: 1,
82
+ ...(controlAlign && {
83
+ alignItems: controlAlign
84
+ })
81
85
  };
82
86
  }
83
87
  function selectIconTokens(tokens) {
@@ -92,6 +96,7 @@ const ExpandCollapseControl = /*#__PURE__*/_react.default.forwardRef((_ref4, ref
92
96
  isExpanded,
93
97
  children,
94
98
  tokens,
99
+ controlAlign,
95
100
  accessibilityRole = 'button',
96
101
  variant,
97
102
  ...rest
@@ -142,7 +147,12 @@ const ExpandCollapseControl = /*#__PURE__*/_react.default.forwardRef((_ref4, ref
142
147
  ...selectIconTokens(themeTokens)
143
148
  })
144
149
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
145
- style: [selectTextContainerStyles(themeTokens), staticStyles.bubblePointerEvents],
150
+ style: [selectTextContainerStyles({
151
+ ...themeTokens,
152
+ ...(controlAlign && {
153
+ controlAlign
154
+ })
155
+ }), staticStyles.bubblePointerEvents],
146
156
  children: typeof children === 'function' ? children(getControlState(pressableState)) : children
147
157
  })]
148
158
  });
@@ -168,6 +178,10 @@ ExpandCollapseControl.propTypes = {
168
178
  * Whether the linked ExpandCollapsePanel is opened or closed. Allows themes to set `expanded` styles.
169
179
  */
170
180
  isExpanded: _propTypes.default.bool,
181
+ /**
182
+ * Optional alignment for control content. Overrides token-driven alignment.
183
+ */
184
+ controlAlign: _propTypes.default.oneOf(['flex-start', 'center', 'flex-end']),
171
185
  /**
172
186
  * Function called when the ExpandCollapse is pressed.
173
187
  */
@@ -104,6 +104,7 @@ const ExpandCollapsePanel = /*#__PURE__*/_react.default.forwardRef((_ref5, ref)
104
104
  onPress,
105
105
  control,
106
106
  controlTokens,
107
+ controlAlign,
107
108
  children,
108
109
  tokens,
109
110
  variant,
@@ -173,6 +174,7 @@ const ExpandCollapsePanel = /*#__PURE__*/_react.default.forwardRef((_ref5, ref)
173
174
  ...selectedProps,
174
175
  isExpanded: isExpanded,
175
176
  tokens: controlTokens,
177
+ controlAlign: controlAlign,
176
178
  variant: variant,
177
179
  onPress: handleControlPress,
178
180
  ref: controlRef,
@@ -272,6 +274,10 @@ ExpandCollapsePanel.propTypes = {
272
274
  * Optional theme token overrides that may be passed to the ExpandCollapseControl element.
273
275
  */
274
276
  controlTokens: (0, _utils.getTokensPropType)('ExpandCollapseControl'),
277
+ /**
278
+ * Optional alignment for control content.
279
+ */
280
+ controlAlign: _propTypes.default.oneOf(['flex-start', 'center', 'flex-end']),
275
281
  /**
276
282
  * An optional ref to be attached to the control
277
283
  */
@@ -13,6 +13,11 @@ var _ExpandCollapseMiniControl = _interopRequireDefault(require("./ExpandCollaps
13
13
  var _jsxRuntime = require("react/jsx-runtime");
14
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
15
  const [selectContainerProps, selectedContainerPropTypes] = (0, _utils.selectSystemProps)([_utils.contentfulProps]);
16
+ const alignMap = {
17
+ start: 'flex-start',
18
+ middle: 'center',
19
+ end: 'flex-end'
20
+ };
16
21
  const ExpandCollapseMini = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
17
22
  let {
18
23
  children,
@@ -21,6 +26,7 @@ const ExpandCollapseMini = /*#__PURE__*/_react.default.forwardRef((_ref, ref) =>
21
26
  nativeID,
22
27
  initialOpen = false,
23
28
  dataSet,
29
+ align,
24
30
  ...rest
25
31
  } = _ref;
26
32
  const expandCollapeMiniPanelId = (0, _utils.useUniqueId)('ExpandCollapseMiniPanel');
@@ -48,12 +54,14 @@ const ExpandCollapseMini = /*#__PURE__*/_react.default.forwardRef((_ref, ref) =>
48
54
  borderColor: 'transparent',
49
55
  textLine: tokens.textLine ?? 'none',
50
56
  backgroundColor: 'transparent'
51
- }
57
+ },
58
+ controlAlign: align && alignMap[align]
52
59
  // TODO refactor
53
60
  // eslint-disable-next-line react/no-unstable-nested-components
54
61
  ,
55
62
  control: pressableState => /*#__PURE__*/(0, _jsxRuntime.jsx)(_ExpandCollapseMiniControl.default, {
56
63
  pressableState: pressableState,
64
+ align: align,
57
65
  ...rest
58
66
  }),
59
67
  controlRef: ref,
@@ -93,6 +101,10 @@ ExpandCollapseMini.propTypes = {
93
101
  /**
94
102
  * The dataSet prop allows to pass data-* attributes element to the component.
95
103
  */
96
- dataSet: _propTypes.default.object
104
+ dataSet: _propTypes.default.object,
105
+ /**
106
+ * Controls the horizontal alignment of the trigger label and icon within the panel width.
107
+ */
108
+ align: _propTypes.default.oneOf(['start', 'middle', 'end'])
97
109
  };
98
110
  var _default = exports.default = ExpandCollapseMini;
@@ -13,6 +13,11 @@ var _utils = require("../utils");
13
13
  var _jsxRuntime = require("react/jsx-runtime");
14
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
15
  const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_utils.htmlAttrs, _utils.viewProps]);
16
+ const alignSelfMap = {
17
+ start: 'flex-start',
18
+ middle: 'center',
19
+ end: 'flex-end'
20
+ };
16
21
 
17
22
  // The ExpandCollapseControl has all the appropriate role, a11y, press handling etc
18
23
  // and a more appropriate press area, defer interaction handling to it.
@@ -31,6 +36,7 @@ const ExpandCollapseMiniControl = /*#__PURE__*/_react.default.forwardRef((_ref,
31
36
  iconPosition = 'right',
32
37
  tokens,
33
38
  variant = {},
39
+ align,
34
40
  ...rest
35
41
  } = _ref;
36
42
  const {
@@ -99,7 +105,10 @@ const ExpandCollapseMiniControl = /*#__PURE__*/_react.default.forwardRef((_ref,
99
105
  ...getTokens(linkState),
100
106
  iconSize,
101
107
  blockFontSize: fontSize,
102
- blockLineHeight: lineHeight
108
+ blockLineHeight: lineHeight,
109
+ ...(align && {
110
+ alignSelf: alignSelfMap[align]
111
+ })
103
112
  }),
104
113
  ref: ref,
105
114
  ...presentationOnly,
@@ -130,6 +139,10 @@ ExpandCollapseMiniControl.propTypes = {
130
139
  /**
131
140
  * Optional variant object to override the default theme tokens
132
141
  */
133
- variant: _propTypes.default.object
142
+ variant: _propTypes.default.object,
143
+ /**
144
+ * Controls the horizontal alignment of the trigger label and icon
145
+ */
146
+ align: _propTypes.default.oneOf(['start', 'middle', 'end'])
134
147
  };
135
148
  var _default = exports.default = ExpandCollapseMiniControl;
@@ -47,6 +47,7 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
47
47
  const getTokens = (0, _ThemeProvider.useThemeTokensCallback)('Link', applyChevronTokens, variant);
48
48
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_LinkBase.default, {
49
49
  ...otherlinkProps,
50
+ useMeasuredMobileIconLayout: true,
50
51
  iconPosition: direction,
51
52
  tokens: getTokens,
52
53
  dataSet: dataSet,
@@ -13,6 +13,7 @@ var _props = require("../utils/props");
13
13
  var _pressability = require("../utils/pressability");
14
14
  var _utils = require("../utils");
15
15
  var _InlinePressable = _interopRequireDefault(require("./InlinePressable"));
16
+ var _MobileIconTextContent = _interopRequireDefault(require("./MobileIconTextContent"));
16
17
  var _ThemeProvider = require("../ThemeProvider");
17
18
  var _Icon = require("../Icon");
18
19
  var _jsxRuntime = require("react/jsx-runtime");
@@ -144,6 +145,7 @@ const LinkBase = /*#__PURE__*/_react.default.forwardRef((_ref6, ref) => {
144
145
  tokens = {},
145
146
  children,
146
147
  dataSet,
148
+ useMeasuredMobileIconLayout = false,
147
149
  accessibilityRole = 'link',
148
150
  ...rawRest
149
151
  } = _ref6;
@@ -187,8 +189,8 @@ const LinkBase = /*#__PURE__*/_react.default.forwardRef((_ref6, ref) => {
187
189
  const themeTokens = resolveLinkTokens(linkState);
188
190
  const outerBorderStyles = selectOuterBorderStyles(themeTokens);
189
191
  const decorationStyles = selectDecorationStyles(themeTokens);
190
- const mobileCompensation = null;
191
- return [outerBorderStyles, mobileCompensation, blockLeftStyle, decorationStyles, hasIcon && staticStyles.rowContainer];
192
+ const shouldUseMeasuredMobileContent = _Platform.default.OS !== 'web' && useMeasuredMobileIconLayout;
193
+ return [outerBorderStyles, shouldUseMeasuredMobileContent ? staticStyles.measuredMobileOuterBorderCompensation : null, blockLeftStyle, decorationStyles, hasIcon && staticStyles.rowContainer];
192
194
  },
193
195
  children: linkState => {
194
196
  const themeTokens = resolveLinkTokens(linkState);
@@ -203,19 +205,32 @@ const LinkBase = /*#__PURE__*/_react.default.forwardRef((_ref6, ref) => {
203
205
  } = themeTokens;
204
206
  const isTextOnlyLink = !IconComponent && !icon && accessibilityRole === 'link';
205
207
  const adjustedIconSpace = _Platform.default.OS !== 'web' && isTextOnlyLink ? 0 : iconSpace;
208
+ const shouldUseMeasuredMobileContent = _Platform.default.OS !== 'web' && useMeasuredMobileIconLayout;
209
+ const textBaselineStyle = shouldUseMeasuredMobileContent ? null : staticStyles.baseline;
210
+ const linkTextContent = /*#__PURE__*/(0, _jsxRuntime.jsx)(_Text.default, {
211
+ style: [textStyles, blockTextStyles, textBaselineStyle, staticStyles.bubblePointerEvents],
212
+ children: typeof children === 'function' ? children(linkState) : children
213
+ });
214
+ const sharedIconProps = {
215
+ ...iconProps,
216
+ tokens: iconTokens,
217
+ style: staticStyles.bubblePointerEvents
218
+ };
219
+ if (shouldUseMeasuredMobileContent) {
220
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_MobileIconTextContent.default, {
221
+ icon: IconComponent,
222
+ iconPosition: iconPosition,
223
+ space: adjustedIconSpace,
224
+ iconProps: sharedIconProps,
225
+ children: linkTextContent
226
+ });
227
+ }
206
228
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.IconText, {
207
229
  icon: IconComponent,
208
230
  iconPosition: iconPosition,
209
231
  space: adjustedIconSpace,
210
- iconProps: {
211
- ...iconProps,
212
- tokens: iconTokens,
213
- style: staticStyles.bubblePointerEvents
214
- },
215
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Text.default, {
216
- style: [textStyles, blockTextStyles, staticStyles.baseline, staticStyles.bubblePointerEvents],
217
- children: typeof children === 'function' ? children(linkState) : children
218
- })
232
+ iconProps: sharedIconProps,
233
+ children: linkTextContent
219
234
  });
220
235
  }
221
236
  });
@@ -273,11 +288,12 @@ const staticStyles = _StyleSheet.default.create({
273
288
  }
274
289
  })
275
290
  },
276
- outerBorderCompensation: {
291
+ measuredMobileOuterBorderCompensation: {
277
292
  ...(_Platform.default.OS !== 'web' && {
278
293
  marginHorizontal: 2,
294
+ marginVertical: 2,
279
295
  paddingHorizontal: _Platform.default.OS === 'android' ? 2 : 0,
280
- paddingTop: _Platform.default.OS === 'android' ? 2 : 0
296
+ paddingVertical: _Platform.default.OS === 'android' ? 2 : 0
281
297
  })
282
298
  }
283
299
  });