@telus-uds/components-base 3.23.0 → 3.24.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 (51) hide show
  1. package/CHANGELOG.md +12 -1
  2. package/lib/cjs/Card/CardBase.js +97 -17
  3. package/lib/cjs/Card/PressableCardBase.js +12 -8
  4. package/lib/cjs/HorizontalScroll/HorizontalScroll.js +5 -2
  5. package/lib/cjs/Icon/Icon.js +3 -0
  6. package/lib/cjs/Listbox/GroupControl.js +12 -6
  7. package/lib/cjs/Listbox/Listbox.js +41 -7
  8. package/lib/cjs/Listbox/ListboxGroup.js +139 -8
  9. package/lib/cjs/Listbox/ListboxOverlay.js +10 -5
  10. package/lib/cjs/Listbox/SecondLevelHeader.js +201 -0
  11. package/lib/cjs/Listbox/dictionary.js +14 -0
  12. package/lib/cjs/Shortcuts/Shortcuts.js +169 -0
  13. package/lib/cjs/Shortcuts/ShortcutsItem.js +280 -0
  14. package/lib/cjs/Shortcuts/index.js +16 -0
  15. package/lib/cjs/Tooltip/Tooltip.native.js +2 -0
  16. package/lib/cjs/index.js +15 -0
  17. package/lib/esm/Card/CardBase.js +97 -17
  18. package/lib/esm/Card/PressableCardBase.js +10 -8
  19. package/lib/esm/HorizontalScroll/HorizontalScroll.js +6 -3
  20. package/lib/esm/Icon/Icon.js +3 -0
  21. package/lib/esm/Listbox/GroupControl.js +12 -6
  22. package/lib/esm/Listbox/Listbox.js +41 -7
  23. package/lib/esm/Listbox/ListboxGroup.js +141 -10
  24. package/lib/esm/Listbox/ListboxOverlay.js +10 -5
  25. package/lib/esm/Listbox/SecondLevelHeader.js +194 -0
  26. package/lib/esm/Listbox/dictionary.js +8 -0
  27. package/lib/esm/Shortcuts/Shortcuts.js +160 -0
  28. package/lib/esm/Shortcuts/ShortcutsItem.js +273 -0
  29. package/lib/esm/Shortcuts/index.js +3 -0
  30. package/lib/esm/Tooltip/Tooltip.native.js +2 -0
  31. package/lib/esm/index.js +1 -0
  32. package/lib/package.json +2 -2
  33. package/package.json +2 -2
  34. package/src/Card/CardBase.jsx +113 -14
  35. package/src/Card/PressableCardBase.jsx +17 -5
  36. package/src/HorizontalScroll/HorizontalScroll.jsx +6 -3
  37. package/src/Icon/Icon.jsx +3 -0
  38. package/src/Listbox/GroupControl.jsx +41 -33
  39. package/src/Listbox/Listbox.jsx +41 -2
  40. package/src/Listbox/ListboxGroup.jsx +158 -26
  41. package/src/Listbox/ListboxOverlay.jsx +18 -5
  42. package/src/Listbox/SecondLevelHeader.jsx +182 -0
  43. package/src/Listbox/dictionary.js +8 -0
  44. package/src/Shortcuts/Shortcuts.jsx +174 -0
  45. package/src/Shortcuts/ShortcutsItem.jsx +297 -0
  46. package/src/Shortcuts/index.js +4 -0
  47. package/src/Tooltip/Tooltip.native.jsx +2 -1
  48. package/src/index.js +1 -0
  49. package/types/Listbox.d.ts +24 -0
  50. package/types/Shortcuts.d.ts +136 -0
  51. package/types/index.d.ts +12 -0
package/CHANGELOG.md CHANGED
@@ -1,9 +1,20 @@
1
1
  # Change Log - @telus-uds/components-base
2
2
 
3
- This log was last generated on Wed, 19 Nov 2025 05:51:39 GMT and should not be manually modified.
3
+ This log was last generated on Fri, 12 Dec 2025 05:37:22 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## 3.24.0
8
+
9
+ Fri, 12 Dec 2025 05:37:22 GMT
10
+
11
+ ### Minor changes
12
+
13
+ - `Card`: interactive mode added for FullBleedContent (35577399+JoshHC@users.noreply.github.com)
14
+ - `Shortcuts`: add component (guillermo.peitzner@telus.com)
15
+ - `Listbox & NavigationBar`: add `secondLevel` variant (sergio.ramirez@telus.com)
16
+ - Bump @telus-uds/system-theme-tokens to v4.17.0
17
+
7
18
  ## 3.23.0
8
19
 
9
20
  Wed, 19 Nov 2025 05:51:39 GMT
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.selectStyles = exports.default = void 0;
6
+ exports.selectStyles = exports.fullBleedContentPropTypes = exports.default = void 0;
7
7
  var _react = _interopRequireDefault(require("react"));
8
8
  var _propTypes = _interopRequireDefault(require("prop-types"));
9
9
  var _View = _interopRequireDefault(require("react-native-web/dist/cjs/exports/View"));
@@ -15,9 +15,16 @@ var _ThemeProvider = require("../ThemeProvider");
15
15
  var _utils = require("../utils");
16
16
  var _props = require("../utils/props");
17
17
  var _backgroundImageStylesMap = _interopRequireDefault(require("./backgroundImageStylesMap"));
18
+ var _FlexGrid = _interopRequireDefault(require("../FlexGrid/FlexGrid"));
19
+ var _Row = _interopRequireDefault(require("../FlexGrid/Row"));
20
+ var _Col = _interopRequireDefault(require("../FlexGrid/Col"));
18
21
  var _jsxRuntime = require("react/jsx-runtime");
19
22
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
20
23
  const [selectProps, selectedSystemPropTypes] = (0, _props.selectSystemProps)([_props.a11yProps, _props.viewProps]);
24
+ const GRID_COLUMNS = 12;
25
+ const isOverlayColor = color => {
26
+ return color && typeof color === 'string' && color.startsWith('rgba(');
27
+ };
21
28
  const setBackgroundImage = _ref => {
22
29
  let {
23
30
  src,
@@ -31,12 +38,9 @@ const setBackgroundImage = _ref => {
31
38
  const borderRadius = cardStyle?.borderRadius || 0;
32
39
  const borderWidth = cardStyle?.borderWidth || 0;
33
40
  const adjustedBorderRadius = Math.max(0, borderRadius - borderWidth);
34
-
35
- // For contain mode with position and align, use CSS background properties for web
36
41
  if (backgroundImageResizeMode === 'contain' && backgroundImagePosition && backgroundImageAlign) {
37
42
  const positionKey = `${backgroundImagePosition}-${backgroundImageAlign}`;
38
43
  if (_Platform.default.OS === 'web') {
39
- // Create background position based on position and align
40
44
  let backgroundPosition;
41
45
  switch (positionKey) {
42
46
  case 'top-start':
@@ -80,7 +84,6 @@ const setBackgroundImage = _ref => {
80
84
  children: content
81
85
  });
82
86
  }
83
- // For React Native, apply positioning styles with full dimensions
84
87
  const positionStyles = _backgroundImageStylesMap.default[positionKey] || {};
85
88
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_View.default, {
86
89
  style: [staticStyles.containContainer, {
@@ -99,8 +102,6 @@ const setBackgroundImage = _ref => {
99
102
  })]
100
103
  });
101
104
  }
102
-
103
- // Use ImageBackground for all other resize modes and React Native
104
105
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ImageBackground.default, {
105
106
  source: src,
106
107
  imageStyle: {
@@ -126,6 +127,10 @@ const selectStyles = _ref2 => {
126
127
  paddingLeft,
127
128
  paddingRight,
128
129
  paddingTop,
130
+ marginTop,
131
+ marginBottom,
132
+ marginLeft,
133
+ marginRight,
129
134
  minWidth,
130
135
  shadow,
131
136
  backgroundGradient,
@@ -133,9 +138,18 @@ const selectStyles = _ref2 => {
133
138
  maxHeight,
134
139
  overflowY
135
140
  } = _ref2;
141
+ const hasGradient = (gradient || backgroundGradient) && _Platform.default.OS === 'web';
142
+ let backgroundImageValue = null;
143
+ if (hasGradient) {
144
+ const gradientObj = gradient || backgroundGradient;
145
+ const gradientString = `linear-gradient(${gradientObj.angle}deg, ${gradientObj.stops[0].color}, ${gradientObj.stops[1].color})`;
146
+ const shouldApplyOverlay = (gradient || backgroundGradient && backgroundColor && backgroundColor !== 'transparent') && isOverlayColor(backgroundColor);
147
+ backgroundImageValue = shouldApplyOverlay ? `linear-gradient(${backgroundColor}, ${backgroundColor}), ${gradientString}` : gradientString;
148
+ }
149
+ const boxShadowColor = isOverlayColor(backgroundColor) ? backgroundColor : 'white';
136
150
  return {
137
151
  flex,
138
- backgroundColor,
152
+ backgroundColor: hasGradient ? 'transparent' : backgroundColor,
139
153
  borderColor,
140
154
  borderRadius,
141
155
  borderWidth,
@@ -143,16 +157,20 @@ const selectStyles = _ref2 => {
143
157
  paddingLeft,
144
158
  paddingRight,
145
159
  paddingTop,
160
+ marginTop,
161
+ marginBottom,
162
+ marginLeft,
163
+ marginRight,
146
164
  minWidth,
147
165
  ...(0, _ThemeProvider.applyShadowToken)(shadow),
148
166
  ...(gradient && _Platform.default.OS === 'web' ? {
149
- backgroundImage: `linear-gradient(${gradient.angle}deg, ${gradient.stops[0].color}, ${gradient.stops[1].color})`,
167
+ backgroundImage: backgroundImageValue,
150
168
  backgroundOrigin: `border-box`,
151
- boxShadow: `inset 0 1000px white`,
169
+ boxShadow: `inset 0 1000px ${boxShadowColor}`,
152
170
  border: `${borderWidth}px solid transparent`
153
171
  } : {}),
154
172
  ...(backgroundGradient && _Platform.default.OS === 'web' ? {
155
- backgroundImage: `linear-gradient(${backgroundGradient.angle}deg, ${backgroundGradient.stops[0].color}, ${backgroundGradient.stops[1].color})`
173
+ backgroundImage: backgroundImageValue
156
174
  } : {}),
157
175
  ...(_Platform.default.OS === 'web' ? {
158
176
  maxHeight,
@@ -172,9 +190,11 @@ const CardBase = /*#__PURE__*/_react.default.forwardRef((_ref3, ref) => {
172
190
  tokens,
173
191
  dataSet,
174
192
  backgroundImage,
193
+ fullBleedContent,
194
+ cardState,
175
195
  ...rest
176
196
  } = _ref3;
177
- const cardStyle = selectStyles(typeof tokens === 'function' ? tokens() : tokens);
197
+ const cardStyle = selectStyles(typeof tokens === 'function' ? tokens(cardState) : tokens);
178
198
  const props = selectProps(rest);
179
199
  let content = children;
180
200
  const {
@@ -188,9 +208,13 @@ const CardBase = /*#__PURE__*/_react.default.forwardRef((_ref3, ref) => {
188
208
  const backgroundImagePosition = (0, _utils.useResponsiveProp)(position);
189
209
  const backgroundImageAlign = (0, _utils.useResponsiveProp)(align);
190
210
  const imageSourceViewport = (0, _utils.formatImageSource)((0, _utils.useResponsiveProp)(src));
211
+ const {
212
+ content: fullBleedImageContent,
213
+ position: fullBleedContentPosition,
214
+ imgCol
215
+ } = fullBleedContent || {};
216
+ const fullBleedPosition = (0, _utils.useResponsiveProp)(fullBleedContentPosition, 'bottom');
191
217
  if (backgroundImage && src) {
192
- // When there's a background image, separate the padding from the container style
193
- // so the image can fill the entire container without padding interference
194
218
  const {
195
219
  paddingTop,
196
220
  paddingBottom,
@@ -198,8 +222,6 @@ const CardBase = /*#__PURE__*/_react.default.forwardRef((_ref3, ref) => {
198
222
  paddingRight,
199
223
  ...containerStyle
200
224
  } = cardStyle;
201
-
202
- // Only create padding wrapper if there's actually padding defined
203
225
  const hasPadding = paddingTop || paddingBottom || paddingLeft || paddingRight;
204
226
  const paddedContent = hasPadding ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
205
227
  style: {
@@ -227,6 +249,53 @@ const CardBase = /*#__PURE__*/_react.default.forwardRef((_ref3, ref) => {
227
249
  children: content
228
250
  });
229
251
  }
252
+ if (fullBleedContent && fullBleedImageContent) {
253
+ const {
254
+ paddingTop,
255
+ paddingBottom,
256
+ paddingLeft,
257
+ paddingRight,
258
+ ...containerStyle
259
+ } = cardStyle;
260
+ const imageColumns = imgCol || {
261
+ xs: GRID_COLUMNS
262
+ };
263
+ const textColumns = {};
264
+ Object.keys(imageColumns).forEach(breakpoint => {
265
+ textColumns[breakpoint] = GRID_COLUMNS - (imageColumns[breakpoint] || GRID_COLUMNS);
266
+ });
267
+ const imageFirst = fullBleedPosition === 'top' || fullBleedPosition === 'left';
268
+ const imageColContent = /*#__PURE__*/(0, _jsxRuntime.jsx)(_Col.default, {
269
+ ...imageColumns,
270
+ style: staticStyles.fullBleedImageCol,
271
+ children: fullBleedImageContent
272
+ });
273
+ const textColContent = /*#__PURE__*/(0, _jsxRuntime.jsx)(_Col.default, {
274
+ ...textColumns,
275
+ style: {
276
+ paddingTop,
277
+ paddingBottom,
278
+ paddingLeft,
279
+ paddingRight
280
+ },
281
+ children: children
282
+ });
283
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
284
+ style: containerStyle,
285
+ dataSet: dataSet,
286
+ ref: ref,
287
+ ...props,
288
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_FlexGrid.default, {
289
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Row.default, {
290
+ children: imageFirst ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
291
+ children: [imageColContent, textColContent]
292
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
293
+ children: [textColContent, imageColContent]
294
+ })
295
+ })
296
+ })
297
+ });
298
+ }
230
299
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
231
300
  style: cardStyle,
232
301
  dataSet: dataSet,
@@ -236,6 +305,13 @@ const CardBase = /*#__PURE__*/_react.default.forwardRef((_ref3, ref) => {
236
305
  });
237
306
  });
238
307
  CardBase.displayName = 'CardBase';
308
+ const fullBleedContentPropTypes = exports.fullBleedContentPropTypes = _propTypes.default.shape({
309
+ content: _propTypes.default.node.isRequired,
310
+ alt: _propTypes.default.string,
311
+ position: _utils.responsiveProps.getTypeOptionallyByViewport(_propTypes.default.oneOf(['bottom', 'left', 'right', 'top'])),
312
+ align: _utils.responsiveProps.getTypeOptionallyByViewport(_propTypes.default.oneOf(['start', 'end', 'center', 'stretch'])),
313
+ imgCol: _propTypes.default.object
314
+ });
239
315
  const staticStyles = _StyleSheet.default.create({
240
316
  imageBackground: {
241
317
  width: '100%',
@@ -257,6 +333,9 @@ const staticStyles = _StyleSheet.default.create({
257
333
  position: 'absolute',
258
334
  width: '100%',
259
335
  height: '100%'
336
+ },
337
+ fullBleedImageCol: {
338
+ padding: 0
260
339
  }
261
340
  });
262
341
  CardBase.propTypes = {
@@ -274,6 +353,7 @@ CardBase.propTypes = {
274
353
  resizeMode: _utils.responsiveProps.getTypeOptionallyByViewport(_propTypes.default.oneOf(['cover', 'contain', 'stretch', 'repeat', 'center'])),
275
354
  position: _utils.responsiveProps.getTypeOptionallyByViewport(_propTypes.default.oneOf(['bottom', 'left', 'right', 'top'])),
276
355
  align: _utils.responsiveProps.getTypeOptionallyByViewport(_propTypes.default.oneOf(['start', 'end', 'center', 'stretch']))
277
- })
356
+ }),
357
+ fullBleedContent: fullBleedContentPropTypes
278
358
  };
279
359
  var _default = exports.default = CardBase;
@@ -13,11 +13,13 @@ var _StyleSheet = _interopRequireDefault(require("react-native-web/dist/cjs/expo
13
13
  var _ViewportProvider = require("../ViewportProvider");
14
14
  var _ThemeProvider = require("../ThemeProvider");
15
15
  var _utils = require("../utils");
16
- var _CardBase = _interopRequireDefault(require("./CardBase"));
16
+ var _CardBase = _interopRequireWildcard(require("./CardBase"));
17
17
  var _jsxRuntime = require("react/jsx-runtime");
18
+ 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); }
19
+ 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; }
18
20
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
19
21
  const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.focusHandlerProps, _utils.viewProps]);
20
- const tokenKeys = ['flex', 'backgroundColor', 'borderColor', 'gradient', 'borderRadius', 'borderWidth', 'paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop', 'minWidth', 'shadow', 'contentAlignItems', 'contentJustifyContent', 'contentFlexGrow', 'contentFlexShrink',
22
+ const tokenKeys = ['flex', 'backgroundColor', 'borderColor', 'gradient', 'borderRadius', 'borderWidth', 'paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop', 'marginTop', 'marginBottom', 'marginLeft', 'marginRight', 'minWidth', 'shadow', 'contentAlignItems', 'contentJustifyContent', 'contentFlexGrow', 'contentFlexShrink',
21
23
  // Outer border tokens. TODO: centralise common token sets like these as part of
22
24
  // https://github.com/telus/universal-design-system/issues/782
23
25
  'outerBorderColor', 'outerBorderWidth', 'outerBorderGap', 'icon', 'iconBackgroundColor', 'iconColor', 'iconSize', 'inputBackgroundColor', 'inputBorderColor', 'inputBorderRadius', 'inputBorderWidth', 'inputHeight', 'inputShadow', 'inputWidth'];
@@ -40,6 +42,7 @@ const PressableCardBase = /*#__PURE__*/_react.default.forwardRef((_ref, ref) =>
40
42
  hrefAttrs,
41
43
  dataSet,
42
44
  backgroundImage,
45
+ fullBleedContent,
43
46
  accessibilityRole = href ? 'link' : undefined,
44
47
  ...rawRest
45
48
  } = _ref;
@@ -133,10 +136,7 @@ const PressableCardBase = /*#__PURE__*/_react.default.forwardRef((_ref, ref) =>
133
136
  setFocused(false);
134
137
  setPressed(false);
135
138
  },
136
- style: {
137
- ...staticStyles.linkContainer,
138
- textDecoration: 'none'
139
- },
139
+ style: staticStyles.linkContainer,
140
140
  ...(hrefAttrs || {}),
141
141
  role: accessibilityRole,
142
142
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_CardBase.default, {
@@ -146,6 +146,7 @@ const PressableCardBase = /*#__PURE__*/_react.default.forwardRef((_ref, ref) =>
146
146
  hovered
147
147
  }),
148
148
  backgroundImage: backgroundImage,
149
+ fullBleedContent: fullBleedContent,
149
150
  children: typeof children === 'function' ? children(getCardState({
150
151
  pressed,
151
152
  focused,
@@ -170,6 +171,7 @@ const PressableCardBase = /*#__PURE__*/_react.default.forwardRef((_ref, ref) =>
170
171
  children: pressableState => /*#__PURE__*/(0, _jsxRuntime.jsx)(_CardBase.default, {
171
172
  tokens: getCardTokens(pressableState),
172
173
  backgroundImage: backgroundImage,
174
+ fullBleedContent: fullBleedContent,
173
175
  children: typeof children === 'function' ? children(getCardState(pressableState)) : children
174
176
  })
175
177
  });
@@ -183,7 +185,8 @@ const staticStyles = _StyleSheet.default.create({
183
185
  flex: 1,
184
186
  display: 'flex',
185
187
  alignItems: 'stretch',
186
- justifyContent: 'flex-start'
188
+ justifyContent: 'flex-start',
189
+ textDecorationLine: 'none'
187
190
  }
188
191
  });
189
192
  PressableCardBase.displayName = 'PressableCardBase';
@@ -203,6 +206,7 @@ PressableCardBase.propTypes = {
203
206
  resizeMode: _propTypes.default.oneOfType([_propTypes.default.oneOf(['cover', 'contain', 'stretch', 'repeat', 'center']), _propTypes.default.object]),
204
207
  position: _propTypes.default.oneOfType([_propTypes.default.oneOf(['bottom', 'left', 'right', 'top']), _propTypes.default.object]),
205
208
  align: _propTypes.default.oneOfType([_propTypes.default.oneOf(['start', 'end', 'center', 'stretch']), _propTypes.default.object])
206
- })
209
+ }),
210
+ fullBleedContent: _CardBase.fullBleedContentPropTypes
207
211
  };
208
212
  var _default = exports.default = (0, _utils.withLinkRouter)(PressableCardBase);
@@ -35,6 +35,7 @@ const HorizontalScroll = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
35
35
  ScrollButton,
36
36
  tokens,
37
37
  itemPositions,
38
+ variant,
38
39
  children,
39
40
  ...rest
40
41
  } = _ref;
@@ -78,8 +79,9 @@ const HorizontalScroll = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
78
79
  setScrollOffset(x);
79
80
  };
80
81
  const scrollMax = Math.max(0, contentWidth - containerWidth);
81
- const showNextButton = scrollOffset < scrollMax;
82
- const showPreviousButton = scrollOffset > 0;
82
+ const hideNavigationButtons = variant?.hideNavigationButtons || false;
83
+ const showNextButton = scrollOffset < scrollMax && !hideNavigationButtons;
84
+ const showPreviousButton = scrollOffset > 0 && !hideNavigationButtons;
83
85
  const scrollRef = _react.default.useRef(null);
84
86
  const scrollTo = targetX => {
85
87
  if (typeof scrollRef.current?.scrollTo === 'function') {
@@ -170,6 +172,7 @@ HorizontalScroll.propTypes = {
170
172
  tokens: (0, _utils.getTokensSetPropType)(tokenKeys, {
171
173
  allowFunction: true
172
174
  }),
175
+ variant: _utils.variantProp.propType,
173
176
  children: _propTypes.default.node
174
177
  };
175
178
  var _default = exports.default = HorizontalScroll;
@@ -21,6 +21,7 @@ const Icon = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
21
21
  tokens,
22
22
  scalesWithText = false,
23
23
  style = {},
24
+ testID,
24
25
  dataSet
25
26
  } = _ref;
26
27
  const themeTokens = (0, _ThemeProvider.useThemeTokens)('Icon', tokens, variant);
@@ -44,6 +45,7 @@ const Icon = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
44
45
  };
45
46
  const getIconContentForMobile = () => {
46
47
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
48
+ testID: testID,
47
49
  style: {
48
50
  backgroundColor: themeTokens.backgroundColor,
49
51
  borderRadius: themeTokens.borderRadius,
@@ -53,6 +55,7 @@ const Icon = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
53
55
  });
54
56
  };
55
57
  return _Platform.default.OS === 'web' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
58
+ testID: testID,
56
59
  ref: ref
57
60
  // eslint-disable-next-line react-native/no-inline-styles
58
61
  ,
@@ -13,6 +13,7 @@ var _ThemeProvider = require("../ThemeProvider");
13
13
  var _Icon = _interopRequireDefault(require("../Icon"));
14
14
  var _Spacer = _interopRequireDefault(require("../Spacer"));
15
15
  var _ListboxContext = require("./ListboxContext");
16
+ var _utils = require("../utils");
16
17
  var _jsxRuntime = require("react/jsx-runtime");
17
18
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
18
19
  const styles = _StyleSheet.default.create({
@@ -60,19 +61,23 @@ const GroupControl = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
60
61
  hover,
61
62
  focus,
62
63
  label,
63
- id
64
+ id,
65
+ variant = {}
64
66
  } = _ref;
65
67
  const {
66
68
  selectedId,
67
69
  setSelectedId
68
70
  } = (0, _ListboxContext.useListboxContext)();
69
- const tokens = (0, _ThemeProvider.useThemeTokens)('Listbox', {}, {}, {
71
+ const isSecondLevel = variant?.secondLevel === true;
72
+ const tokens = (0, _ThemeProvider.useThemeTokens)('Listbox', variant, {}, {
70
73
  expanded,
71
74
  pressed,
72
75
  hover,
73
76
  current: selectedId === id && id !== undefined,
74
- focus
77
+ focus,
78
+ secondLevel: isSecondLevel
75
79
  });
80
+ const displayIcon = isSecondLevel ? tokens.secondLevelParentIcon : tokens.groupIcon;
76
81
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_View.default, {
77
82
  onPress: () => setSelectedId(id),
78
83
  style: [styles.container, selectContainerStyles(tokens)],
@@ -83,8 +88,8 @@ const GroupControl = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
83
88
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Spacer.default, {
84
89
  space: 1,
85
90
  direction: "row"
86
- }), tokens.groupIcon && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.default, {
87
- icon: tokens.groupIcon,
91
+ }), displayIcon && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.default, {
92
+ icon: displayIcon,
88
93
  tokens: {
89
94
  color: tokens.groupColor
90
95
  },
@@ -101,6 +106,7 @@ GroupControl.propTypes = {
101
106
  pressed: _propTypes.default.bool,
102
107
  hover: _propTypes.default.bool,
103
108
  focus: _propTypes.default.bool,
104
- label: _propTypes.default.string
109
+ label: _propTypes.default.string,
110
+ variant: _utils.variantProp.propType
105
111
  };
106
112
  var _default = exports.default = GroupControl;
@@ -16,6 +16,7 @@ var _ListboxGroup = _interopRequireDefault(require("./ListboxGroup"));
16
16
  var _ListboxItem = _interopRequireDefault(require("./ListboxItem"));
17
17
  var _ListboxContext = require("./ListboxContext");
18
18
  var _ListboxOverlay = _interopRequireDefault(require("./ListboxOverlay"));
19
+ var _dictionary = _interopRequireDefault(require("./dictionary"));
19
20
  var _jsxRuntime = require("react/jsx-runtime");
20
21
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
21
22
  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); }
@@ -23,7 +24,9 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
23
24
  const styles = _StyleSheet.default.create({
24
25
  container: {
25
26
  padding: 0,
26
- margin: 0
27
+ margin: 0,
28
+ position: 'relative',
29
+ overflow: 'visible'
27
30
  }
28
31
  });
29
32
  const selectContainerStyles = tokens => ({
@@ -43,12 +46,15 @@ const Listbox = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
43
46
  LinkRouter,
44
47
  itemRouterProps,
45
48
  onClose,
49
+ copy = 'en',
50
+ dictionary = _dictionary.default,
46
51
  variant,
47
52
  tokens,
48
53
  testID
49
54
  } = _ref;
50
55
  const initialOpen = getInitialOpen(items, defaultSelectedId);
51
56
  const [selectedId, setSelectedId] = _react.default.useState(defaultSelectedId);
57
+ const [activeSecondLevelGroup, setActiveSecondLevelGroup] = _react.default.useState(null);
52
58
  const listboxTokens = (0, _ThemeProvider.useThemeTokens)('Listbox', tokens, variant);
53
59
 
54
60
  // We need to keep track of each item's ref in order to be able to
@@ -98,11 +104,14 @@ const Listbox = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
98
104
  }
99
105
  return () => {};
100
106
  }, [onClose, handleKeydown]);
107
+ const contextValue = {
108
+ selectedId,
109
+ setSelectedId,
110
+ activeSecondLevelGroup,
111
+ setActiveSecondLevelGroup
112
+ };
101
113
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ListboxContext.ListboxContext.Provider, {
102
- value: {
103
- selectedId,
104
- setSelectedId
105
- },
114
+ value: contextValue,
106
115
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_ExpandCollapse.default, {
107
116
  initialOpen: initialOpen,
108
117
  maxOpen: 1,
@@ -124,6 +133,9 @@ const Listbox = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
124
133
  itemRefs.current[index] = currentItemRef;
125
134
  return currentItemRef;
126
135
  };
136
+ if (!nestedItems && activeSecondLevelGroup) {
137
+ return null;
138
+ }
127
139
  return nestedItems ? /*#__PURE__*/(0, _react.createElement)(_ListboxGroup.default, {
128
140
  ...item,
129
141
  expandProps: expandProps,
@@ -132,7 +144,12 @@ const Listbox = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
132
144
  prevItemRef: itemRefs.current[index - 1] ?? null,
133
145
  nextItemRef: itemRefs.current[index + 1] ?? null,
134
146
  ref: index === 0 ? firstItemRef : itemRef,
135
- key: itemId
147
+ key: itemId,
148
+ copy: copy,
149
+ dictionary: dictionary,
150
+ variant: variant,
151
+ tokens: tokens,
152
+ onClose: onClose
136
153
  }) : /*#__PURE__*/(0, _react.createElement)(_ListboxItem.default, {
137
154
  ...item,
138
155
  key: itemId,
@@ -141,7 +158,9 @@ const Listbox = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
141
158
  itemRouterProps: itemRouterProps,
142
159
  prevItemRef: itemRefs.current[index - 1] ?? null,
143
160
  nextItemRef: itemRefs.current[index + 1] ?? null,
144
- ref: index === 0 ? firstItemRef : itemRef
161
+ ref: index === 0 ? firstItemRef : itemRef,
162
+ variant: variant,
163
+ tokens: tokens
145
164
  });
146
165
  })
147
166
  })
@@ -177,6 +196,21 @@ Listbox.propTypes = {
177
196
  * Test ID for testing
178
197
  */
179
198
  testID: _propTypes.default.string,
199
+ /**
200
+ * Select English or French copy
201
+ */
202
+ copy: _propTypes.default.oneOf(['en', 'fr']),
203
+ /**
204
+ * Override the default dictionary, by passing the complete dictionary object for `en` and `fr`
205
+ */
206
+ dictionary: _propTypes.default.shape({
207
+ en: _propTypes.default.shape({
208
+ closeMenu: _propTypes.default.string.isRequired
209
+ }),
210
+ fr: _propTypes.default.shape({
211
+ closeMenu: _propTypes.default.string.isRequired
212
+ })
213
+ }),
180
214
  /**
181
215
  * Listbox variant
182
216
  */