@telus-uds/components-base 3.28.2 → 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 (36) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/lib/cjs/Card/CardBase.js +12 -0
  3. package/lib/cjs/ColourToggle/ColourBubble.js +17 -3
  4. package/lib/cjs/ColourToggle/ColourToggle.js +8 -2
  5. package/lib/cjs/ExpandCollapse/Control.js +17 -3
  6. package/lib/cjs/ExpandCollapse/Panel.js +6 -0
  7. package/lib/cjs/ExpandCollapseMini/ExpandCollapseMini.js +14 -2
  8. package/lib/cjs/ExpandCollapseMini/ExpandCollapseMiniControl.js +15 -2
  9. package/lib/cjs/Link/ChevronLink.js +1 -0
  10. package/lib/cjs/Link/LinkBase.js +29 -13
  11. package/lib/cjs/Link/MobileIconTextContent.js +156 -0
  12. package/lib/cjs/TabBar/TabBar.js +7 -2
  13. package/lib/esm/Card/CardBase.js +12 -0
  14. package/lib/esm/ColourToggle/ColourBubble.js +17 -3
  15. package/lib/esm/ColourToggle/ColourToggle.js +8 -2
  16. package/lib/esm/ExpandCollapse/Control.js +17 -3
  17. package/lib/esm/ExpandCollapse/Panel.js +6 -0
  18. package/lib/esm/ExpandCollapseMini/ExpandCollapseMini.js +14 -2
  19. package/lib/esm/ExpandCollapseMini/ExpandCollapseMiniControl.js +15 -2
  20. package/lib/esm/Link/ChevronLink.js +1 -0
  21. package/lib/esm/Link/LinkBase.js +29 -13
  22. package/lib/esm/Link/MobileIconTextContent.js +147 -0
  23. package/lib/esm/TabBar/TabBar.js +7 -2
  24. package/lib/package.json +1 -1
  25. package/package.json +1 -1
  26. package/src/Card/CardBase.jsx +12 -0
  27. package/src/ColourToggle/ColourBubble.jsx +18 -3
  28. package/src/ColourToggle/ColourToggle.jsx +7 -2
  29. package/src/ExpandCollapse/Control.jsx +24 -4
  30. package/src/ExpandCollapse/Panel.jsx +6 -0
  31. package/src/ExpandCollapseMini/ExpandCollapseMini.jsx +23 -3
  32. package/src/ExpandCollapseMini/ExpandCollapseMiniControl.jsx +14 -2
  33. package/src/Link/ChevronLink.jsx +1 -0
  34. package/src/Link/LinkBase.jsx +47 -20
  35. package/src/Link/MobileIconTextContent.jsx +129 -0
  36. package/src/TabBar/TabBar.jsx +21 -4
package/CHANGELOG.md CHANGED
@@ -1,9 +1,24 @@
1
1
  # Change Log - @telus-uds/components-base
2
2
 
3
- This log was last generated on Tue, 03 Mar 2026 23:02:55 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
+
7
22
  ## 3.28.2
8
23
 
9
24
  Tue, 03 Mar 2026 23:02:55 GMT
@@ -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
  }
@@ -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
  });
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _propTypes = _interopRequireDefault(require("prop-types"));
9
+ var _Text = _interopRequireDefault(require("react-native-web/dist/cjs/exports/Text"));
10
+ var _View = _interopRequireDefault(require("react-native-web/dist/cjs/exports/View"));
11
+ var _StyleSheet = _interopRequireDefault(require("react-native-web/dist/cjs/exports/StyleSheet"));
12
+ var _Icon = _interopRequireWildcard(require("../Icon/Icon"));
13
+ var _utils = require("../utils");
14
+ var _jsxRuntime = require("react/jsx-runtime");
15
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
16
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
17
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
18
+ const MobileIconTextContent = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
19
+ let {
20
+ space = 0,
21
+ iconPosition = 'left',
22
+ icon: IconComponent,
23
+ iconProps = {},
24
+ children
25
+ } = _ref;
26
+ const [translateY, setTranslateY] = _react.default.useState(0);
27
+ const latestTranslateYRef = _react.default.useRef(0);
28
+ const layoutsRef = _react.default.useRef({
29
+ container: null,
30
+ text: null,
31
+ icon: null
32
+ });
33
+ const applyAlignment = _react.default.useCallback(() => {
34
+ const {
35
+ container,
36
+ text,
37
+ icon
38
+ } = layoutsRef.current;
39
+ if (!container || !icon || !icon.height) return;
40
+ const targetY = text ? text.y + text.height / 2 : container.height / 2;
41
+ const iconY = icon.y + icon.height / 2;
42
+ const nextTranslateY = Math.round((targetY - iconY) * 100) / 100;
43
+ if (!Number.isFinite(nextTranslateY)) return;
44
+ if (Math.abs(nextTranslateY - latestTranslateYRef.current) < 0.5) return;
45
+ latestTranslateYRef.current = nextTranslateY;
46
+ setTranslateY(nextTranslateY);
47
+ }, []);
48
+ const handleContainerLayout = _react.default.useCallback(_ref2 => {
49
+ let {
50
+ nativeEvent: {
51
+ layout
52
+ }
53
+ } = _ref2;
54
+ layoutsRef.current.container = layout;
55
+ applyAlignment();
56
+ }, [applyAlignment]);
57
+ const handleTextLayout = _react.default.useCallback(_ref3 => {
58
+ let {
59
+ nativeEvent: {
60
+ layout
61
+ }
62
+ } = _ref3;
63
+ layoutsRef.current.text = layout;
64
+ applyAlignment();
65
+ }, [applyAlignment]);
66
+ const handleIconLayout = _react.default.useCallback(_ref4 => {
67
+ let {
68
+ nativeEvent: {
69
+ layout
70
+ }
71
+ } = _ref4;
72
+ layoutsRef.current.icon = layout;
73
+ applyAlignment();
74
+ }, [applyAlignment]);
75
+ const iconContent = IconComponent ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.default, {
76
+ ref: ref,
77
+ icon: IconComponent,
78
+ scalesWithText: true,
79
+ ...iconProps
80
+ }) : null;
81
+ const iconWrapper = IconComponent ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
82
+ onLayout: handleIconLayout,
83
+ style: [staticStyles.iconContainer, {
84
+ transform: [{
85
+ translateY
86
+ }]
87
+ }],
88
+ children: iconContent
89
+ }) : null;
90
+ if (iconPosition === 'inline') {
91
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Text.default, {
92
+ onLayout: handleContainerLayout,
93
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Text.default, {
94
+ onLayout: handleTextLayout,
95
+ children: children
96
+ }), ' ', /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
97
+ style: staticStyles.inlineIconContainer,
98
+ children: iconWrapper
99
+ })]
100
+ });
101
+ }
102
+ const iconSpaceStyle = iconPosition === 'left' ? {
103
+ marginRight: space
104
+ } : {
105
+ marginLeft: space
106
+ };
107
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_View.default, {
108
+ onLayout: handleContainerLayout,
109
+ style: staticStyles.rowContainer,
110
+ children: [iconPosition === 'left' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
111
+ style: iconSpaceStyle,
112
+ children: iconWrapper
113
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
114
+ onLayout: handleTextLayout,
115
+ children: children
116
+ }), iconPosition === 'right' && /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
117
+ style: iconSpaceStyle,
118
+ children: iconWrapper
119
+ })]
120
+ });
121
+ });
122
+ MobileIconTextContent.displayName = 'MobileIconTextContent';
123
+ MobileIconTextContent.propTypes = {
124
+ /**
125
+ * Amount of space between text and icon. Uses the theme spacing scale.
126
+ */
127
+ space: _utils.spacingProps.types.spacingValue,
128
+ /**
129
+ * Position of the icon relative to text.
130
+ */
131
+ iconPosition: _propTypes.default.oneOf(['left', 'right', 'inline']),
132
+ /**
133
+ * A valid UDS icon component imported from a UDS palette.
134
+ */
135
+ icon: _propTypes.default.elementType,
136
+ /**
137
+ * Props passed to the icon component.
138
+ */
139
+ iconProps: _propTypes.default.exact(_Icon.iconComponentPropTypes),
140
+ /**
141
+ * Content rendered alongside the icon.
142
+ */
143
+ children: _propTypes.default.node
144
+ };
145
+ const staticStyles = _StyleSheet.default.create({
146
+ rowContainer: {
147
+ flexDirection: 'row'
148
+ },
149
+ iconContainer: {
150
+ alignSelf: 'flex-start'
151
+ },
152
+ inlineIconContainer: {
153
+ position: 'absolute'
154
+ }
155
+ });
156
+ var _default = exports.default = MobileIconTextContent;
@@ -58,6 +58,7 @@ const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_u
58
58
  * items={items}
59
59
  * initiallySelectedItem="1"
60
60
  * onChange={(itemId) => console.log(itemId)}
61
+ * accessibilityLabel="Main navigation"
61
62
  * />
62
63
  * )
63
64
  */
@@ -69,6 +70,7 @@ const TabBar = /*#__PURE__*/_react.default.forwardRef((_ref3, ref) => {
69
70
  onChange,
70
71
  variant,
71
72
  tokens,
73
+ accessibilityLabel,
72
74
  ...rest
73
75
  } = _ref3;
74
76
  const [isSelected, setIsSelected] = _react.default.useState(initiallySelectedItem);
@@ -83,6 +85,8 @@ const TabBar = /*#__PURE__*/_react.default.forwardRef((_ref3, ref) => {
83
85
  ...selectProps(rest),
84
86
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
85
87
  style: [styles.tabBarItem, selectTabBarItemContainerStyles(themeTokens)],
88
+ accessibilityRole: "tablist",
89
+ accessibilityLabel: accessibilityLabel,
86
90
  children: items.map((item, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_TabBarItem.default, {
87
91
  label: item.label,
88
92
  href: item.href,
@@ -91,7 +95,6 @@ const TabBar = /*#__PURE__*/_react.default.forwardRef((_ref3, ref) => {
91
95
  iconActive: item.iconActive,
92
96
  onPress: () => handlePress(item.id),
93
97
  id: `tab-item-${index}`,
94
- accessibilityRole: "tablist",
95
98
  tokens: item.tokens
96
99
  }, item.id))
97
100
  })
@@ -116,7 +119,9 @@ TabBar.propTypes = {
116
119
  /** Variant of TabBar for styling purposes. */
117
120
  variant: _utils.variantProp.propType,
118
121
  /** Tokens for theming and styling. */
119
- tokens: (0, _utils.getTokensPropType)('TabBar')
122
+ tokens: (0, _utils.getTokensPropType)('TabBar'),
123
+ /** Accessible label for the tab bar navigation region, used by screen readers to identify the tablist. */
124
+ accessibilityLabel: _propTypes.default.string
120
125
  };
121
126
  const styles = _StyleSheet.default.create({
122
127
  tabBar: {
@@ -57,9 +57,21 @@ const setBackgroundImage = _ref => {
57
57
  case 'left-center':
58
58
  backgroundPosition = 'left center';
59
59
  break;
60
+ case 'left-start':
61
+ backgroundPosition = 'left top';
62
+ break;
63
+ case 'left-end':
64
+ backgroundPosition = 'left bottom';
65
+ break;
60
66
  case 'right-center':
61
67
  backgroundPosition = 'right center';
62
68
  break;
69
+ case 'right-start':
70
+ backgroundPosition = 'right top';
71
+ break;
72
+ case 'right-end':
73
+ backgroundPosition = 'right bottom';
74
+ break;
63
75
  default:
64
76
  backgroundPosition = 'center center';
65
77
  }
@@ -6,6 +6,7 @@ import Platform from "react-native-web/dist/exports/Platform";
6
6
  import { resolvePressableTokens } from '../utils/pressability';
7
7
  import { applyShadowToken } from '../ThemeProvider';
8
8
  import { getTokensPropType } from '../utils';
9
+ import Tooltip from '../Tooltip';
9
10
  import { jsx as _jsx } from "react/jsx-runtime";
10
11
  const selectGeneralBubbleTokens = _ref => {
11
12
  let {
@@ -69,14 +70,15 @@ const ColourBubble = /*#__PURE__*/React.forwardRef((_ref4, ref) => {
69
70
  colourHexCode,
70
71
  colourName,
71
72
  isSelected,
72
- onPress
73
+ onPress,
74
+ showTooltip
73
75
  } = _ref4;
74
76
  const defaultTokens = tokens({
75
77
  selected: isSelected
76
78
  });
77
79
  const resolveColourBubbleTokens = pressState => resolvePressableTokens(tokens, pressState, {});
78
80
  const themeTokens = React.useMemo(() => tokens(), [tokens]);
79
- return /*#__PURE__*/_jsx(Pressable, {
81
+ const pressable = /*#__PURE__*/_jsx(Pressable, {
80
82
  style: state => [selectGeneralBubbleTokens(resolveColourBubbleTokens(state)), isSelected && selectBorderBubbleTokens(defaultTokens)],
81
83
  onPress: onPress,
82
84
  accessible: true,
@@ -93,6 +95,14 @@ const ColourBubble = /*#__PURE__*/React.forwardRef((_ref4, ref) => {
93
95
  }]
94
96
  })
95
97
  });
98
+ if (showTooltip) {
99
+ return /*#__PURE__*/_jsx(Tooltip, {
100
+ content: colourName,
101
+ activateOnHover: true,
102
+ children: pressable
103
+ });
104
+ }
105
+ return pressable;
96
106
  });
97
107
  ColourBubble.displayName = 'ColourBubble';
98
108
  ColourBubble.propTypes = {
@@ -121,6 +131,10 @@ ColourBubble.propTypes = {
121
131
  * of the color is changed of all currently `items`.
122
132
  * Receives two parameters: item object selected and the event
123
133
  */
124
- onPress: PropTypes.func
134
+ onPress: PropTypes.func,
135
+ /**
136
+ * When true, wraps the bubble in a Tooltip that displays the colourName on hover (web only).
137
+ */
138
+ showTooltip: PropTypes.bool
125
139
  };
126
140
  export default ColourBubble;