@telus-uds/components-web 4.0.0 → 4.2.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.
package/CHANGELOG.md CHANGED
@@ -1,12 +1,44 @@
1
1
  # Change Log - @telus-uds/components-web
2
2
 
3
- This log was last generated on Fri, 31 Jan 2025 20:49:19 GMT and should not be manually modified.
3
+ This log was last generated on Fri, 14 Feb 2025 18:59:39 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## 4.2.0
8
+
9
+ Fri, 14 Feb 2025 18:59:39 GMT
10
+
11
+ ### Minor changes
12
+
13
+ - `PriceLockup`: ability to receive jsx elements in rateText prop added (35577399+JoshHC@users.noreply.github.com)
14
+ - Bump @telus-uds/components-base to v3.2.0
15
+ - Bump @telus-uds/system-theme-tokens to v4.2.0
16
+
17
+ ### Patches
18
+
19
+ - `DatePicker`: remove warnings when opening the component (Mauricio.BatresMontejo@telus.com)
20
+ - `Test`: Update snapshots (sergio.ramirez@telus.com)
21
+ - `Spinner`: fix positioning when overlying a button (guillermo.peitzner@telus.com)
22
+
23
+ ## 4.1.0
24
+
25
+ Mon, 10 Feb 2025 17:36:47 GMT
26
+
27
+ ### Minor changes
28
+
29
+ - `PriceLockup`: aria-label added for all the group of elements (35577399+JoshHC@users.noreply.github.com)
30
+ - Bump @telus-uds/components-base to v3.1.0
31
+ - Bump @telus-uds/system-theme-tokens to v4.1.0
32
+
33
+ ### Patches
34
+
35
+ - QuantitySelector: update snapshot tests (guillermo.peitzner@telus.com)
36
+ - `Table`: new tokens added at row and cell level to achieve new designs (35577399+JoshHC@users.noreply.github.com)
37
+ - `Listbox`: Include export type members for components-web (jaime.tuyuc@telus.com)
38
+
7
39
  ## 4.0.0
8
40
 
9
- Fri, 31 Jan 2025 20:49:19 GMT
41
+ Fri, 31 Jan 2025 20:53:28 GMT
10
42
 
11
43
  ### Major changes
12
44
 
@@ -73,6 +73,10 @@ const getInitialVisibleMonth = (initialVisibleMonth, inputDate) => {
73
73
  }
74
74
  return () => (0, _moment.default)(initialVisibleMonth);
75
75
  };
76
+ const HiddenInputFieldContainer = /*#__PURE__*/_styledComponents.default.div.withConfig({
77
+ displayName: "DatePicker__HiddenInputFieldContainer",
78
+ componentId: "components-web__sc-mz8fi3-3"
79
+ })(["height:", ";width:", ";overflow:hidden;"], props => props.height, props => props.width);
76
80
 
77
81
  /**
78
82
  * Use DatePicker to select a date on a calendar.
@@ -258,10 +262,6 @@ const DatePicker = /*#__PURE__*/_react.default.forwardRef((_ref3, ref) => {
258
262
  const viewport = (0, _componentsBase.useViewport)();
259
263
  const daySize = getResponsiveDaySize(inline, viewport);
260
264
  const circleSize = getResponsiveCircleSize(inline, viewport);
261
- const HiddenInputFieldContainer = /*#__PURE__*/_styledComponents.default.div.withConfig({
262
- displayName: "DatePicker__HiddenInputFieldContainer",
263
- componentId: "components-web__sc-mz8fi3-3"
264
- })(["height:", ";width:", ";overflow:hidden;"], props => props.height, props => props.width);
265
265
  const {
266
266
  hiddenInputFieldContainerHeight,
267
267
  hiddenInputFieldContainerWidth,
@@ -11,9 +11,10 @@ var _styledComponents = _interopRequireDefault(require("styled-components"));
11
11
  var _FootnoteLink = _interopRequireDefault(require("../Footnote/FootnoteLink"));
12
12
  var _tokens = _interopRequireDefault(require("./tokens"));
13
13
  var _utils = require("../utils");
14
+ var _dictionary = _interopRequireDefault(require("./dictionary"));
14
15
  var _jsxRuntime = require("react/jsx-runtime");
15
16
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
16
- const [selectProps, selectedSystemPropTypes] = (0, _componentsBase.selectSystemProps)([_utils.htmlAttrs]);
17
+ const [selectProps, selectedSystemPropTypes] = (0, _componentsBase.selectSystemProps)([_utils.htmlAttrs, _componentsBase.a11yProps]);
17
18
  const PriceLockupContainer = /*#__PURE__*/_styledComponents.default.div.withConfig({
18
19
  displayName: "PriceLockup__PriceLockupContainer",
19
20
  componentId: "components-web__sc-1x6duay-0"
@@ -23,7 +24,9 @@ const PriceLockupContainer = /*#__PURE__*/_styledComponents.default.div.withConf
23
24
  } = _ref;
24
25
  return alignItemsText;
25
26
  });
26
- const PriceContainer = /*#__PURE__*/_styledComponents.default.div.withConfig({
27
+ const PriceContainer = /*#__PURE__*/_styledComponents.default.div.attrs({
28
+ 'aria-hidden': 'true'
29
+ }).withConfig({
27
30
  displayName: "PriceLockup__PriceContainer",
28
31
  componentId: "components-web__sc-1x6duay-1"
29
32
  })(["display:flex;margin-bottom:", ";"], _ref2 => {
@@ -64,7 +67,9 @@ const BottomLinksContainer = /*#__PURE__*/_styledComponents.default.div.withConf
64
67
  } = _ref6;
65
68
  return bottomLinksMarginLeft;
66
69
  });
67
- const TopTextContainer = /*#__PURE__*/_styledComponents.default.div.withConfig({
70
+ const TopTextContainer = /*#__PURE__*/_styledComponents.default.div.attrs({
71
+ 'aria-hidden': 'true'
72
+ }).withConfig({
68
73
  displayName: "PriceLockup__TopTextContainer",
69
74
  componentId: "components-web__sc-1x6duay-5"
70
75
  })(["margin-bottom:", ";"], _ref7 => {
@@ -165,6 +170,8 @@ const PriceLockup = /*#__PURE__*/_react.default.forwardRef((_ref16, ref) => {
165
170
  a11yText,
166
171
  tokens: priceLockupTokens,
167
172
  variant = {},
173
+ copy = 'en',
174
+ dictionary = _dictionary.default,
168
175
  ...rest
169
176
  } = _ref16;
170
177
  const viewport = (0, _componentsBase.useViewport)();
@@ -277,10 +284,48 @@ const PriceLockup = /*#__PURE__*/_react.default.forwardRef((_ref16, ref) => {
277
284
  if (strikeThrough && !a11yText) {
278
285
  (0, _utils.warn)('PriceLockup', 'a11yText must be provided with strikethrough pricing');
279
286
  }
287
+
288
+ /**
289
+ * Converts rateText to string if rateText is an JSX.
290
+ */
291
+ function getRateText(rateTextValue) {
292
+ if (!rateTextValue) return '';
293
+ switch (typeof rateTextValue) {
294
+ case 'string':
295
+ return rateTextValue.replace('/', '');
296
+ case 'object':
297
+ if (/*#__PURE__*/_react.default.isValidElement(rateTextValue)) {
298
+ return _react.default.Children.toArray(rateTextValue.props.children).map(getRateText).join('');
299
+ }
300
+ // If it's an object but not a React element, return empty string
301
+ break;
302
+ default:
303
+ break;
304
+ }
305
+ return '';
306
+ }
307
+ const getAriaContent = () => {
308
+ const {
309
+ price: dictionaryPrice,
310
+ priceWithCents,
311
+ rate
312
+ } = dictionary[copy];
313
+ let ariaLabel = hasCents ? priceWithCents.replace('%{amount}', amount).replace('%{cents}', cents).replace('%{currency}', currencySymbol) : dictionaryPrice.replace('%{amount}', amount).replace('%{currency}', currencySymbol);
314
+ if (!ariaLabel.includes(currencySymbol)) {
315
+ ariaLabel = `${ariaLabel} ${currencySymbol}`;
316
+ }
317
+ if (rateText) {
318
+ ariaLabel += ` ${rate.replace('%{rateText}', getRateText(rateText))}`;
319
+ }
320
+ return ariaLabel;
321
+ };
322
+ const ariaLabel = selectProps(rest)['aria-label'] ?? getAriaContent();
280
323
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(PriceLockupContainer, {
281
324
  ...selectProps(rest),
282
325
  alignItemsText: alignItemsText,
283
326
  ref: ref,
327
+ role: "group",
328
+ "aria-label": ariaLabel,
284
329
  children: [topText && /*#__PURE__*/(0, _jsxRuntime.jsx)(TopTextContainer, {
285
330
  topTextMarginBottom: `${topTextMarginBottom}px`,
286
331
  children: renderTypography(topText, typographyTokens.topText)
@@ -294,6 +339,13 @@ const PriceLockup = /*#__PURE__*/_react.default.forwardRef((_ref16, ref) => {
294
339
  });
295
340
  });
296
341
  PriceLockup.displayName = 'PriceLockup';
342
+
343
+ // If a language dictionary entry is provided, it must contain every key
344
+ const dictionaryContentShape = _propTypes.default.shape({
345
+ price: _propTypes.default.string.isRequired,
346
+ priceWithCents: _propTypes.default.string.isRequired,
347
+ rate: _propTypes.default.string.isRequired
348
+ });
297
349
  PriceLockup.propTypes = {
298
350
  ...selectedSystemPropTypes,
299
351
  /**
@@ -317,7 +369,7 @@ PriceLockup.propTypes = {
317
369
  /**
318
370
  * Shows month/year unit
319
371
  */
320
- rateText: _propTypes.default.string,
372
+ rateText: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.element]),
321
373
  /**
322
374
  * Shows additional info below the price with a `Divider`
323
375
  */
@@ -348,6 +400,16 @@ PriceLockup.propTypes = {
348
400
  * **Note:** a11yText will override strikethrough price, so it must include price (ie. "was 50 dollars per month")
349
401
  */
350
402
  a11yText: _propTypes.default.string,
403
+ /**
404
+ * Select English or French copy for the accessible label.
405
+ */
406
+ copy: _propTypes.default.oneOf(['en', 'fr']),
407
+ /* Custom dictionary containing the labels
408
+ */
409
+ dictionary: _propTypes.default.shape({
410
+ en: dictionaryContentShape,
411
+ fr: dictionaryContentShape
412
+ }),
351
413
  /**
352
414
  * `PriceLockup` tokens
353
415
  */
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _default = exports.default = {
8
+ en: {
9
+ price: '%{amount} %{currency}',
10
+ priceWithCents: '%{amount} %{currency} and %{cents} cents',
11
+ rate: 'per %{rateText}'
12
+ },
13
+ fr: {
14
+ price: '%{amount} %{currency}',
15
+ priceWithCents: '%{amount} %{currency} et %{cents} centimes',
16
+ rate: 'par %{rateText}'
17
+ }
18
+ };
@@ -21,12 +21,13 @@ const SpinnerContainer = /*#__PURE__*/_styledComponents.default.div.withConfig({
21
21
  })(_ref => {
22
22
  let {
23
23
  inline,
24
- fullScreen
24
+ fullScreen,
25
+ overlay
25
26
  } = _ref;
26
27
  return {
27
28
  position: 'relative',
28
29
  ...(inline && {
29
- display: 'block',
30
+ display: overlay ? 'inline-block' : 'block',
30
31
  ...(0, _utils.media)().from('md').css({
31
32
  display: 'inline-block'
32
33
  })
@@ -139,6 +140,7 @@ const Spinner = /*#__PURE__*/_react.default.forwardRef((_ref3, ref) => {
139
140
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(SpinnerContainer, {
140
141
  inline: inline,
141
142
  "aria-live": "assertive",
143
+ overlay: true,
142
144
  ...selectProps(rest),
143
145
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_SpinnerContent.default, {
144
146
  label: label,
@@ -34,17 +34,20 @@ const sharedStyles = /*#__PURE__*/(0, _styledComponents.css)(["", ""], _ref2 =>
34
34
  cellPaddingRight,
35
35
  cellPaddingBottom,
36
36
  cellPaddingLeft,
37
+ cellBorderWidth,
38
+ cellBorderColor,
39
+ cellBorderTopWidth,
37
40
  cellMinWidth,
38
41
  cellBackground,
39
42
  cellStickyShadow,
40
43
  stickyBackgroundColor,
41
44
  type
42
45
  } = _ref2;
43
- return (0, _styledComponents.css)(["text-align:", ";min-width:", "px;padding:", "px ", "px ", "px ", "px;background-color:", ";", ";"], align, cellMinWidth, cellPaddingTop, cellPaddingRight, cellPaddingBottom, cellPaddingLeft, cellBackground, isSticky && stickyStyles({
46
+ return (0, _styledComponents.css)(["text-align:", ";min-width:", "px;padding:", "px ", "px ", "px ", "px;background-color:", ";", ";border-style:", ";border-color:", ";border-width:", ";border-top-width:", ";"], align, cellMinWidth, cellPaddingTop, cellPaddingRight, cellPaddingBottom, cellPaddingLeft, cellBackground, isSticky && stickyStyles({
44
47
  type,
45
48
  cellStickyShadow,
46
49
  stickyBackgroundColor
47
- }));
50
+ }), cellBorderWidth || cellBorderTopWidth ? 'solid' : 'none', cellBorderColor, cellBorderWidth, cellBorderTopWidth || cellBorderWidth);
48
51
  });
49
52
  const createStyledCell = htmlElement => _styledComponents.default[htmlElement].withConfig({
50
53
  displayName: "Cell__createStyledCell",
@@ -93,6 +96,9 @@ const Cell = /*#__PURE__*/_react.default.forwardRef((_ref5, ref) => {
93
96
  cellPaddingRight,
94
97
  cellPaddingLeft,
95
98
  cellPaddingBottom,
99
+ cellBorderWidth,
100
+ cellBorderColor,
101
+ cellBorderTopWidth,
96
102
  fontName,
97
103
  fontWeight,
98
104
  fontSize,
@@ -116,6 +122,9 @@ const Cell = /*#__PURE__*/_react.default.forwardRef((_ref5, ref) => {
116
122
  cellPaddingRight,
117
123
  cellPaddingLeft,
118
124
  cellPaddingBottom,
125
+ cellBorderWidth,
126
+ cellBorderColor,
127
+ cellBorderTopWidth,
119
128
  stickyBackgroundColor,
120
129
  cellBoxShadowColor,
121
130
  display,
@@ -13,22 +13,47 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
13
13
  const StyledTR = /*#__PURE__*/_styledComponents.default.tr.withConfig({
14
14
  displayName: "Row__StyledTR",
15
15
  componentId: "components-web__sc-6pbb9a-0"
16
- })(["&:hover{background-color:", " !important;}"], _ref => {
16
+ })(["&:hover{background-color:", " !important;}border-style:", ";border-color:", ";border-width:", ";border-top-width:", ";"], _ref => {
17
17
  let {
18
- rowHoverBackgroundColor
18
+ tokens
19
19
  } = _ref;
20
- return rowHoverBackgroundColor;
21
- });
22
- const Row = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
20
+ return tokens?.rowHoverBackgroundColor;
21
+ }, _ref2 => {
23
22
  let {
24
- children
23
+ tokens
25
24
  } = _ref2;
25
+ return tokens?.rowBorderWidth || tokens?.rowBorderTopWidth ? 'solid' : 'none';
26
+ }, _ref3 => {
27
+ let {
28
+ tokens
29
+ } = _ref3;
30
+ return tokens?.rowBorderColor;
31
+ }, _ref4 => {
32
+ let {
33
+ tokens
34
+ } = _ref4;
35
+ return tokens?.rowBorderWidth || '0px';
36
+ }, _ref5 => {
37
+ let {
38
+ tokens
39
+ } = _ref5;
40
+ return tokens?.rowBorderTopWidth || tokens?.rowBorderWidth;
41
+ });
42
+ const Row = /*#__PURE__*/_react.default.forwardRef((_ref6, ref) => {
43
+ let {
44
+ children,
45
+ tokens: rowTokens
46
+ } = _ref6;
26
47
  const {
27
48
  themeTokens
28
49
  } = (0, _Table.useTableContext)();
50
+ const mergedTokens = {
51
+ ...themeTokens,
52
+ ...rowTokens
53
+ };
29
54
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(StyledTR, {
30
55
  ref: ref,
31
- rowHoverBackgroundColor: themeTokens?.rowHoverBackgroundColor,
56
+ tokens: mergedTokens,
32
57
  children: _react.default.Children.map(children, (child, index) => /*#__PURE__*/_react.default.cloneElement(child, {
33
58
  isFirstInRow: index === 0
34
59
  }))
@@ -36,6 +61,14 @@ const Row = /*#__PURE__*/_react.default.forwardRef((_ref2, ref) => {
36
61
  });
37
62
  Row.displayName = 'Row';
38
63
  Row.propTypes = {
64
+ tokens: _propTypes.default.shape({
65
+ borderColor: _propTypes.default.string,
66
+ topBorderWidth: _propTypes.default.string,
67
+ bottomBorderWidth: _propTypes.default.string,
68
+ leftBorderWidth: _propTypes.default.string,
69
+ rightBorderWidth: _propTypes.default.string,
70
+ rowHoverBackgroundColor: _propTypes.default.string
71
+ }),
39
72
  children: _propTypes.default.node
40
73
  };
41
74
  var _default = exports.default = Row;
@@ -66,6 +66,10 @@ const getInitialVisibleMonth = (initialVisibleMonth, inputDate) => {
66
66
  }
67
67
  return () => moment(initialVisibleMonth);
68
68
  };
69
+ const HiddenInputFieldContainer = /*#__PURE__*/styled.div.withConfig({
70
+ displayName: "DatePicker__HiddenInputFieldContainer",
71
+ componentId: "components-web__sc-mz8fi3-3"
72
+ })(["height:", ";width:", ";overflow:hidden;"], props => props.height, props => props.width);
69
73
 
70
74
  /**
71
75
  * Use DatePicker to select a date on a calendar.
@@ -251,10 +255,6 @@ const DatePicker = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
251
255
  const viewport = useViewport();
252
256
  const daySize = getResponsiveDaySize(inline, viewport);
253
257
  const circleSize = getResponsiveCircleSize(inline, viewport);
254
- const HiddenInputFieldContainer = /*#__PURE__*/styled.div.withConfig({
255
- displayName: "DatePicker__HiddenInputFieldContainer",
256
- componentId: "components-web__sc-mz8fi3-3"
257
- })(["height:", ";width:", ";overflow:hidden;"], props => props.height, props => props.width);
258
258
  const {
259
259
  hiddenInputFieldContainerHeight,
260
260
  hiddenInputFieldContainerWidth,
@@ -1,12 +1,13 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { A11yText, Divider, selectSystemProps, Typography, useThemeTokens, useViewport, getTokensPropType } from '@telus-uds/components-base';
3
+ import { A11yText, Divider, selectSystemProps, Typography, useThemeTokens, useViewport, getTokensPropType, a11yProps } from '@telus-uds/components-base';
4
4
  import styled from 'styled-components';
5
5
  import FootnoteLink from '../Footnote/FootnoteLink';
6
6
  import getTypographyTokens from './tokens';
7
7
  import { htmlAttrs, warn } from '../utils';
8
+ import defaultDictionary from './dictionary';
8
9
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
9
- const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs]);
10
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs, a11yProps]);
10
11
  const PriceLockupContainer = /*#__PURE__*/styled.div.withConfig({
11
12
  displayName: "PriceLockup__PriceLockupContainer",
12
13
  componentId: "components-web__sc-1x6duay-0"
@@ -16,7 +17,9 @@ const PriceLockupContainer = /*#__PURE__*/styled.div.withConfig({
16
17
  } = _ref;
17
18
  return alignItemsText;
18
19
  });
19
- const PriceContainer = /*#__PURE__*/styled.div.withConfig({
20
+ const PriceContainer = /*#__PURE__*/styled.div.attrs({
21
+ 'aria-hidden': 'true'
22
+ }).withConfig({
20
23
  displayName: "PriceLockup__PriceContainer",
21
24
  componentId: "components-web__sc-1x6duay-1"
22
25
  })(["display:flex;margin-bottom:", ";"], _ref2 => {
@@ -57,7 +60,9 @@ const BottomLinksContainer = /*#__PURE__*/styled.div.withConfig({
57
60
  } = _ref6;
58
61
  return bottomLinksMarginLeft;
59
62
  });
60
- const TopTextContainer = /*#__PURE__*/styled.div.withConfig({
63
+ const TopTextContainer = /*#__PURE__*/styled.div.attrs({
64
+ 'aria-hidden': 'true'
65
+ }).withConfig({
61
66
  displayName: "PriceLockup__TopTextContainer",
62
67
  componentId: "components-web__sc-1x6duay-5"
63
68
  })(["margin-bottom:", ";"], _ref7 => {
@@ -158,6 +163,8 @@ const PriceLockup = /*#__PURE__*/React.forwardRef((_ref16, ref) => {
158
163
  a11yText,
159
164
  tokens: priceLockupTokens,
160
165
  variant = {},
166
+ copy = 'en',
167
+ dictionary = defaultDictionary,
161
168
  ...rest
162
169
  } = _ref16;
163
170
  const viewport = useViewport();
@@ -270,10 +277,48 @@ const PriceLockup = /*#__PURE__*/React.forwardRef((_ref16, ref) => {
270
277
  if (strikeThrough && !a11yText) {
271
278
  warn('PriceLockup', 'a11yText must be provided with strikethrough pricing');
272
279
  }
280
+
281
+ /**
282
+ * Converts rateText to string if rateText is an JSX.
283
+ */
284
+ function getRateText(rateTextValue) {
285
+ if (!rateTextValue) return '';
286
+ switch (typeof rateTextValue) {
287
+ case 'string':
288
+ return rateTextValue.replace('/', '');
289
+ case 'object':
290
+ if (/*#__PURE__*/React.isValidElement(rateTextValue)) {
291
+ return React.Children.toArray(rateTextValue.props.children).map(getRateText).join('');
292
+ }
293
+ // If it's an object but not a React element, return empty string
294
+ break;
295
+ default:
296
+ break;
297
+ }
298
+ return '';
299
+ }
300
+ const getAriaContent = () => {
301
+ const {
302
+ price: dictionaryPrice,
303
+ priceWithCents,
304
+ rate
305
+ } = dictionary[copy];
306
+ let ariaLabel = hasCents ? priceWithCents.replace('%{amount}', amount).replace('%{cents}', cents).replace('%{currency}', currencySymbol) : dictionaryPrice.replace('%{amount}', amount).replace('%{currency}', currencySymbol);
307
+ if (!ariaLabel.includes(currencySymbol)) {
308
+ ariaLabel = `${ariaLabel} ${currencySymbol}`;
309
+ }
310
+ if (rateText) {
311
+ ariaLabel += ` ${rate.replace('%{rateText}', getRateText(rateText))}`;
312
+ }
313
+ return ariaLabel;
314
+ };
315
+ const ariaLabel = selectProps(rest)['aria-label'] ?? getAriaContent();
273
316
  return /*#__PURE__*/_jsxs(PriceLockupContainer, {
274
317
  ...selectProps(rest),
275
318
  alignItemsText: alignItemsText,
276
319
  ref: ref,
320
+ role: "group",
321
+ "aria-label": ariaLabel,
277
322
  children: [topText && /*#__PURE__*/_jsx(TopTextContainer, {
278
323
  topTextMarginBottom: `${topTextMarginBottom}px`,
279
324
  children: renderTypography(topText, typographyTokens.topText)
@@ -287,6 +332,13 @@ const PriceLockup = /*#__PURE__*/React.forwardRef((_ref16, ref) => {
287
332
  });
288
333
  });
289
334
  PriceLockup.displayName = 'PriceLockup';
335
+
336
+ // If a language dictionary entry is provided, it must contain every key
337
+ const dictionaryContentShape = PropTypes.shape({
338
+ price: PropTypes.string.isRequired,
339
+ priceWithCents: PropTypes.string.isRequired,
340
+ rate: PropTypes.string.isRequired
341
+ });
290
342
  PriceLockup.propTypes = {
291
343
  ...selectedSystemPropTypes,
292
344
  /**
@@ -310,7 +362,7 @@ PriceLockup.propTypes = {
310
362
  /**
311
363
  * Shows month/year unit
312
364
  */
313
- rateText: PropTypes.string,
365
+ rateText: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
314
366
  /**
315
367
  * Shows additional info below the price with a `Divider`
316
368
  */
@@ -341,6 +393,16 @@ PriceLockup.propTypes = {
341
393
  * **Note:** a11yText will override strikethrough price, so it must include price (ie. "was 50 dollars per month")
342
394
  */
343
395
  a11yText: PropTypes.string,
396
+ /**
397
+ * Select English or French copy for the accessible label.
398
+ */
399
+ copy: PropTypes.oneOf(['en', 'fr']),
400
+ /* Custom dictionary containing the labels
401
+ */
402
+ dictionary: PropTypes.shape({
403
+ en: dictionaryContentShape,
404
+ fr: dictionaryContentShape
405
+ }),
344
406
  /**
345
407
  * `PriceLockup` tokens
346
408
  */
@@ -0,0 +1,12 @@
1
+ export default {
2
+ en: {
3
+ price: '%{amount} %{currency}',
4
+ priceWithCents: '%{amount} %{currency} and %{cents} cents',
5
+ rate: 'per %{rateText}'
6
+ },
7
+ fr: {
8
+ price: '%{amount} %{currency}',
9
+ priceWithCents: '%{amount} %{currency} et %{cents} centimes',
10
+ rate: 'par %{rateText}'
11
+ }
12
+ };
@@ -14,12 +14,13 @@ const SpinnerContainer = /*#__PURE__*/styled.div.withConfig({
14
14
  })(_ref => {
15
15
  let {
16
16
  inline,
17
- fullScreen
17
+ fullScreen,
18
+ overlay
18
19
  } = _ref;
19
20
  return {
20
21
  position: 'relative',
21
22
  ...(inline && {
22
- display: 'block',
23
+ display: overlay ? 'inline-block' : 'block',
23
24
  ...media().from('md').css({
24
25
  display: 'inline-block'
25
26
  })
@@ -132,6 +133,7 @@ const Spinner = /*#__PURE__*/React.forwardRef((_ref3, ref) => {
132
133
  return /*#__PURE__*/_jsxs(SpinnerContainer, {
133
134
  inline: inline,
134
135
  "aria-live": "assertive",
136
+ overlay: true,
135
137
  ...selectProps(rest),
136
138
  children: [/*#__PURE__*/_jsx(SpinnerContent, {
137
139
  label: label,
@@ -25,17 +25,20 @@ const sharedStyles = /*#__PURE__*/css(["", ""], _ref2 => {
25
25
  cellPaddingRight,
26
26
  cellPaddingBottom,
27
27
  cellPaddingLeft,
28
+ cellBorderWidth,
29
+ cellBorderColor,
30
+ cellBorderTopWidth,
28
31
  cellMinWidth,
29
32
  cellBackground,
30
33
  cellStickyShadow,
31
34
  stickyBackgroundColor,
32
35
  type
33
36
  } = _ref2;
34
- return css(["text-align:", ";min-width:", "px;padding:", "px ", "px ", "px ", "px;background-color:", ";", ";"], align, cellMinWidth, cellPaddingTop, cellPaddingRight, cellPaddingBottom, cellPaddingLeft, cellBackground, isSticky && stickyStyles({
37
+ return css(["text-align:", ";min-width:", "px;padding:", "px ", "px ", "px ", "px;background-color:", ";", ";border-style:", ";border-color:", ";border-width:", ";border-top-width:", ";"], align, cellMinWidth, cellPaddingTop, cellPaddingRight, cellPaddingBottom, cellPaddingLeft, cellBackground, isSticky && stickyStyles({
35
38
  type,
36
39
  cellStickyShadow,
37
40
  stickyBackgroundColor
38
- }));
41
+ }), cellBorderWidth || cellBorderTopWidth ? 'solid' : 'none', cellBorderColor, cellBorderWidth, cellBorderTopWidth || cellBorderWidth);
39
42
  });
40
43
  const createStyledCell = htmlElement => styled[htmlElement].withConfig({
41
44
  displayName: "Cell__createStyledCell",
@@ -84,6 +87,9 @@ const Cell = /*#__PURE__*/React.forwardRef((_ref5, ref) => {
84
87
  cellPaddingRight,
85
88
  cellPaddingLeft,
86
89
  cellPaddingBottom,
90
+ cellBorderWidth,
91
+ cellBorderColor,
92
+ cellBorderTopWidth,
87
93
  fontName,
88
94
  fontWeight,
89
95
  fontSize,
@@ -107,6 +113,9 @@ const Cell = /*#__PURE__*/React.forwardRef((_ref5, ref) => {
107
113
  cellPaddingRight,
108
114
  cellPaddingLeft,
109
115
  cellPaddingBottom,
116
+ cellBorderWidth,
117
+ cellBorderColor,
118
+ cellBorderTopWidth,
110
119
  stickyBackgroundColor,
111
120
  cellBoxShadowColor,
112
121
  display,
@@ -6,22 +6,47 @@ import { jsx as _jsx } from "react/jsx-runtime";
6
6
  const StyledTR = /*#__PURE__*/styled.tr.withConfig({
7
7
  displayName: "Row__StyledTR",
8
8
  componentId: "components-web__sc-6pbb9a-0"
9
- })(["&:hover{background-color:", " !important;}"], _ref => {
9
+ })(["&:hover{background-color:", " !important;}border-style:", ";border-color:", ";border-width:", ";border-top-width:", ";"], _ref => {
10
10
  let {
11
- rowHoverBackgroundColor
11
+ tokens
12
12
  } = _ref;
13
- return rowHoverBackgroundColor;
14
- });
15
- const Row = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
13
+ return tokens?.rowHoverBackgroundColor;
14
+ }, _ref2 => {
16
15
  let {
17
- children
16
+ tokens
18
17
  } = _ref2;
18
+ return tokens?.rowBorderWidth || tokens?.rowBorderTopWidth ? 'solid' : 'none';
19
+ }, _ref3 => {
20
+ let {
21
+ tokens
22
+ } = _ref3;
23
+ return tokens?.rowBorderColor;
24
+ }, _ref4 => {
25
+ let {
26
+ tokens
27
+ } = _ref4;
28
+ return tokens?.rowBorderWidth || '0px';
29
+ }, _ref5 => {
30
+ let {
31
+ tokens
32
+ } = _ref5;
33
+ return tokens?.rowBorderTopWidth || tokens?.rowBorderWidth;
34
+ });
35
+ const Row = /*#__PURE__*/React.forwardRef((_ref6, ref) => {
36
+ let {
37
+ children,
38
+ tokens: rowTokens
39
+ } = _ref6;
19
40
  const {
20
41
  themeTokens
21
42
  } = useTableContext();
43
+ const mergedTokens = {
44
+ ...themeTokens,
45
+ ...rowTokens
46
+ };
22
47
  return /*#__PURE__*/_jsx(StyledTR, {
23
48
  ref: ref,
24
- rowHoverBackgroundColor: themeTokens?.rowHoverBackgroundColor,
49
+ tokens: mergedTokens,
25
50
  children: React.Children.map(children, (child, index) => /*#__PURE__*/React.cloneElement(child, {
26
51
  isFirstInRow: index === 0
27
52
  }))
@@ -29,6 +54,14 @@ const Row = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
29
54
  });
30
55
  Row.displayName = 'Row';
31
56
  Row.propTypes = {
57
+ tokens: PropTypes.shape({
58
+ borderColor: PropTypes.string,
59
+ topBorderWidth: PropTypes.string,
60
+ bottomBorderWidth: PropTypes.string,
61
+ leftBorderWidth: PropTypes.string,
62
+ rightBorderWidth: PropTypes.string,
63
+ rowHoverBackgroundColor: PropTypes.string
64
+ }),
32
65
  children: PropTypes.node
33
66
  };
34
67
  export default Row;
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  ],
6
6
  "dependencies": {
7
7
  "@gorhom/portal": "^1.0.14",
8
- "@telus-uds/components-base": "^3.0.0",
8
+ "@telus-uds/components-base": "^3.2.0",
9
9
  "@telus-uds/system-constants": "^3.0.0",
10
10
  "fscreen": "^1.2.0",
11
11
  "lodash.omit": "^4.5.0",
@@ -13,7 +13,7 @@
13
13
  "react-dates": "^21.8.0",
14
14
  "react-helmet-async": "^1.3.0",
15
15
  "react-moment-proptypes": "^1.8.1",
16
- "@telus-uds/system-theme-tokens": "^4.0.0",
16
+ "@telus-uds/system-theme-tokens": "^4.2.0",
17
17
  "prop-types": "^15.7.2",
18
18
  "lodash.throttle": "^4.1.1",
19
19
  "react-youtube": "^10.1.0",
@@ -82,5 +82,5 @@
82
82
  "skip": true
83
83
  },
84
84
  "types": "types/index.d.ts",
85
- "version": "4.0.0"
85
+ "version": "4.2.0"
86
86
  }
@@ -61,6 +61,12 @@ const getInitialVisibleMonth = (initialVisibleMonth, inputDate) => {
61
61
  return () => moment(initialVisibleMonth)
62
62
  }
63
63
 
64
+ const HiddenInputFieldContainer = styled.div`
65
+ height: ${(props) => props.height};
66
+ width: ${(props) => props.width};
67
+ overflow: hidden;
68
+ `
69
+
64
70
  /**
65
71
  * Use DatePicker to select a date on a calendar.
66
72
  *
@@ -260,12 +266,6 @@ const DatePicker = React.forwardRef(
260
266
  const daySize = getResponsiveDaySize(inline, viewport)
261
267
  const circleSize = getResponsiveCircleSize(inline, viewport)
262
268
 
263
- const HiddenInputFieldContainer = styled.div`
264
- height: ${(props) => props.height};
265
- width: ${(props) => props.width};
266
- overflow: hidden;
267
- `
268
-
269
269
  const {
270
270
  hiddenInputFieldContainerHeight,
271
271
  hiddenInputFieldContainerWidth,
@@ -7,14 +7,16 @@ import {
7
7
  Typography,
8
8
  useThemeTokens,
9
9
  useViewport,
10
- getTokensPropType
10
+ getTokensPropType,
11
+ a11yProps
11
12
  } from '@telus-uds/components-base'
12
13
  import styled from 'styled-components'
13
14
  import FootnoteLink from '../Footnote/FootnoteLink'
14
15
  import getTypographyTokens from './tokens'
15
16
  import { htmlAttrs, warn } from '../utils'
17
+ import defaultDictionary from './dictionary'
16
18
 
17
- const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs])
19
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs, a11yProps])
18
20
 
19
21
  const PriceLockupContainer = styled.div`
20
22
  align-items: ${({ alignItemsText }) => alignItemsText};
@@ -22,12 +24,12 @@ const PriceLockupContainer = styled.div`
22
24
  flex-direction: column;
23
25
  width: fit-content;
24
26
  `
25
-
26
- const PriceContainer = styled.div`
27
+ const PriceContainer = styled.div.attrs({
28
+ 'aria-hidden': 'true'
29
+ })`
27
30
  display: flex;
28
31
  margin-bottom: ${({ priceMarginBottom }) => priceMarginBottom};
29
32
  `
30
-
31
33
  const FootnoteContainer = styled.div`
32
34
  display: flex;
33
35
  margin-top: ${({ footnoteMarginTop }) => footnoteMarginTop};
@@ -43,7 +45,9 @@ const BottomLinksContainer = styled.div`
43
45
  margin-left: ${({ bottomLinksMarginLeft }) => bottomLinksMarginLeft};
44
46
  `
45
47
 
46
- const TopTextContainer = styled.div`
48
+ const TopTextContainer = styled.div.attrs({
49
+ 'aria-hidden': 'true'
50
+ })`
47
51
  margin-bottom: ${({ topTextMarginBottom }) => topTextMarginBottom};
48
52
  `
49
53
 
@@ -119,6 +123,8 @@ const PriceLockup = React.forwardRef(
119
123
  a11yText,
120
124
  tokens: priceLockupTokens,
121
125
  variant = {},
126
+ copy = 'en',
127
+ dictionary = defaultDictionary,
122
128
  ...rest
123
129
  },
124
130
  ref
@@ -245,8 +251,59 @@ const PriceLockup = React.forwardRef(
245
251
  warn('PriceLockup', 'a11yText must be provided with strikethrough pricing')
246
252
  }
247
253
 
254
+ /**
255
+ * Converts rateText to string if rateText is an JSX.
256
+ */
257
+ function getRateText(rateTextValue) {
258
+ if (!rateTextValue) return ''
259
+
260
+ switch (typeof rateTextValue) {
261
+ case 'string':
262
+ return rateTextValue.replace('/', '')
263
+
264
+ case 'object':
265
+ if (React.isValidElement(rateTextValue)) {
266
+ return React.Children.toArray(rateTextValue.props.children).map(getRateText).join('')
267
+ }
268
+ // If it's an object but not a React element, return empty string
269
+ break
270
+
271
+ default:
272
+ break
273
+ }
274
+
275
+ return ''
276
+ }
277
+
278
+ const getAriaContent = () => {
279
+ const { price: dictionaryPrice, priceWithCents, rate } = dictionary[copy]
280
+ let ariaLabel = hasCents
281
+ ? priceWithCents
282
+ .replace('%{amount}', amount)
283
+ .replace('%{cents}', cents)
284
+ .replace('%{currency}', currencySymbol)
285
+ : dictionaryPrice.replace('%{amount}', amount).replace('%{currency}', currencySymbol)
286
+
287
+ if (!ariaLabel.includes(currencySymbol)) {
288
+ ariaLabel = `${ariaLabel} ${currencySymbol}`
289
+ }
290
+
291
+ if (rateText) {
292
+ ariaLabel += ` ${rate.replace('%{rateText}', getRateText(rateText))}`
293
+ }
294
+ return ariaLabel
295
+ }
296
+
297
+ const ariaLabel = selectProps(rest)['aria-label'] ?? getAriaContent()
298
+
248
299
  return (
249
- <PriceLockupContainer {...selectProps(rest)} alignItemsText={alignItemsText} ref={ref}>
300
+ <PriceLockupContainer
301
+ {...selectProps(rest)}
302
+ alignItemsText={alignItemsText}
303
+ ref={ref}
304
+ role="group"
305
+ aria-label={ariaLabel}
306
+ >
250
307
  {topText && (
251
308
  <TopTextContainer topTextMarginBottom={`${topTextMarginBottom}px`}>
252
309
  {renderTypography(topText, typographyTokens.topText)}
@@ -268,6 +325,13 @@ const PriceLockup = React.forwardRef(
268
325
 
269
326
  PriceLockup.displayName = 'PriceLockup'
270
327
 
328
+ // If a language dictionary entry is provided, it must contain every key
329
+ const dictionaryContentShape = PropTypes.shape({
330
+ price: PropTypes.string.isRequired,
331
+ priceWithCents: PropTypes.string.isRequired,
332
+ rate: PropTypes.string.isRequired
333
+ })
334
+
271
335
  PriceLockup.propTypes = {
272
336
  ...selectedSystemPropTypes,
273
337
  /**
@@ -291,7 +355,7 @@ PriceLockup.propTypes = {
291
355
  /**
292
356
  * Shows month/year unit
293
357
  */
294
- rateText: PropTypes.string,
358
+ rateText: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
295
359
  /**
296
360
  * Shows additional info below the price with a `Divider`
297
361
  */
@@ -322,6 +386,16 @@ PriceLockup.propTypes = {
322
386
  * **Note:** a11yText will override strikethrough price, so it must include price (ie. "was 50 dollars per month")
323
387
  */
324
388
  a11yText: PropTypes.string,
389
+ /**
390
+ * Select English or French copy for the accessible label.
391
+ */
392
+ copy: PropTypes.oneOf(['en', 'fr']),
393
+ /* Custom dictionary containing the labels
394
+ */
395
+ dictionary: PropTypes.shape({
396
+ en: dictionaryContentShape,
397
+ fr: dictionaryContentShape
398
+ }),
325
399
  /**
326
400
  * `PriceLockup` tokens
327
401
  */
@@ -0,0 +1,12 @@
1
+ export default {
2
+ en: {
3
+ price: '%{amount} %{currency}',
4
+ priceWithCents: '%{amount} %{currency} and %{cents} cents',
5
+ rate: 'per %{rateText}'
6
+ },
7
+ fr: {
8
+ price: '%{amount} %{currency}',
9
+ priceWithCents: '%{amount} %{currency} et %{cents} centimes',
10
+ rate: 'par %{rateText}'
11
+ }
12
+ }
@@ -14,10 +14,10 @@ import { BACKDROP_OPACITY, BACKDROP_Z_INDEX } from './constants'
14
14
 
15
15
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs])
16
16
 
17
- const SpinnerContainer = styled.div(({ inline, fullScreen }) => ({
17
+ const SpinnerContainer = styled.div(({ inline, fullScreen, overlay }) => ({
18
18
  position: 'relative',
19
19
  ...(inline && {
20
- display: 'block',
20
+ display: overlay ? 'inline-block' : 'block',
21
21
  ...media().from('md').css({
22
22
  display: 'inline-block'
23
23
  })
@@ -123,7 +123,7 @@ const Spinner = React.forwardRef(
123
123
  // Overlay spinner
124
124
  if (children) {
125
125
  return (
126
- <SpinnerContainer inline={inline} aria-live="assertive" {...selectProps(rest)}>
126
+ <SpinnerContainer inline={inline} aria-live="assertive" overlay {...selectProps(rest)}>
127
127
  <SpinnerContent
128
128
  label={label}
129
129
  labelPosition={labelPosition}
@@ -39,6 +39,9 @@ const sharedStyles = css`
39
39
  cellPaddingRight,
40
40
  cellPaddingBottom,
41
41
  cellPaddingLeft,
42
+ cellBorderWidth,
43
+ cellBorderColor,
44
+ cellBorderTopWidth,
42
45
  cellMinWidth,
43
46
  cellBackground,
44
47
  cellStickyShadow,
@@ -50,6 +53,10 @@ const sharedStyles = css`
50
53
  padding: ${cellPaddingTop}px ${cellPaddingRight}px ${cellPaddingBottom}px ${cellPaddingLeft}px;
51
54
  background-color: ${cellBackground};
52
55
  ${isSticky && stickyStyles({ type, cellStickyShadow, stickyBackgroundColor })};
56
+ border-style: ${cellBorderWidth || cellBorderTopWidth ? 'solid' : 'none'};
57
+ border-color: ${cellBorderColor};
58
+ border-width: ${cellBorderWidth};
59
+ border-top-width: ${cellBorderTopWidth || cellBorderWidth};
53
60
  `}
54
61
  `
55
62
  const createStyledCell = (htmlElement) => styled[htmlElement]`
@@ -88,6 +95,9 @@ const Cell = React.forwardRef(
88
95
  cellPaddingRight,
89
96
  cellPaddingLeft,
90
97
  cellPaddingBottom,
98
+ cellBorderWidth,
99
+ cellBorderColor,
100
+ cellBorderTopWidth,
91
101
  fontName,
92
102
  fontWeight,
93
103
  fontSize,
@@ -107,6 +117,9 @@ const Cell = React.forwardRef(
107
117
  cellPaddingRight,
108
118
  cellPaddingLeft,
109
119
  cellPaddingBottom,
120
+ cellBorderWidth,
121
+ cellBorderColor,
122
+ cellBorderTopWidth,
110
123
  stickyBackgroundColor,
111
124
  cellBoxShadowColor,
112
125
  display,
package/src/Table/Row.jsx CHANGED
@@ -1,20 +1,25 @@
1
1
  import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
-
4
3
  import styled from 'styled-components'
5
4
  import { useTableContext } from './Table'
6
5
 
7
6
  const StyledTR = styled.tr`
8
7
  &:hover {
9
- background-color: ${({ rowHoverBackgroundColor }) => rowHoverBackgroundColor} !important;
8
+ background-color: ${({ tokens }) => tokens?.rowHoverBackgroundColor} !important;
10
9
  }
10
+ border-style: ${({ tokens }) =>
11
+ tokens?.rowBorderWidth || tokens?.rowBorderTopWidth ? 'solid' : 'none'};
12
+ border-color: ${({ tokens }) => tokens?.rowBorderColor};
13
+ border-width: ${({ tokens }) => tokens?.rowBorderWidth || '0px'};
14
+ border-top-width: ${({ tokens }) => tokens?.rowBorderTopWidth || tokens?.rowBorderWidth};
11
15
  `
12
16
 
13
- const Row = React.forwardRef(({ children }, ref) => {
17
+ const Row = React.forwardRef(({ children, tokens: rowTokens }, ref) => {
14
18
  const { themeTokens } = useTableContext()
19
+ const mergedTokens = { ...themeTokens, ...rowTokens }
15
20
 
16
21
  return (
17
- <StyledTR ref={ref} rowHoverBackgroundColor={themeTokens?.rowHoverBackgroundColor}>
22
+ <StyledTR ref={ref} tokens={mergedTokens}>
18
23
  {React.Children.map(children, (child, index) =>
19
24
  React.cloneElement(child, { isFirstInRow: index === 0 })
20
25
  )}
@@ -25,6 +30,14 @@ const Row = React.forwardRef(({ children }, ref) => {
25
30
  Row.displayName = 'Row'
26
31
 
27
32
  Row.propTypes = {
33
+ tokens: PropTypes.shape({
34
+ borderColor: PropTypes.string,
35
+ topBorderWidth: PropTypes.string,
36
+ bottomBorderWidth: PropTypes.string,
37
+ leftBorderWidth: PropTypes.string,
38
+ rightBorderWidth: PropTypes.string,
39
+ rowHoverBackgroundColor: PropTypes.string
40
+ }),
28
41
  children: PropTypes.node
29
42
  }
30
43
 
@@ -0,0 +1,67 @@
1
+ // TODO: Duplicate of the one in components-base. TS module resolution doesn't seem to be working from web -> base.
2
+ import type { ComponentType, ElementType } from 'react'
3
+
4
+ type ListboxTokens = {
5
+ groupBorderRadius?: number | string
6
+ groupBorderWidth?: number | string
7
+ groupFontSize?: number
8
+ groupFontName?: string
9
+ groupFontWeight?: string
10
+ groupColor?: string
11
+ groupBorderColor?: string
12
+ groupBackgroundColor?: string
13
+ groupPaddingTop?: number
14
+ groupPaddingBottom?: number
15
+ groupPaddingLeft?: number
16
+ groupPaddingRight?: number
17
+ groupIcon?: string
18
+ itemDisplay?: boolean
19
+ itemFontName?: string
20
+ itemFontWeight?: string
21
+ itemFontSize?: number
22
+ itemPaddingTop?: number
23
+ itemPaddingBottom?: number
24
+ itemPaddingLeft?: number
25
+ itemPaddingRight?: number
26
+ itemColor?: string
27
+ itemBackgroundColor?: string
28
+ itemBorderLeftColor?: string
29
+ itemBorderLeftWidth?: number | string
30
+ itemBorderWidth?: number | string
31
+ itemTextDecoration?: string
32
+ itemOutline?: number | string
33
+ shadow?: string
34
+ itemBorderRightColor?: string
35
+ itemBorderBottomColor?: string
36
+ itemBorderTopColor?: string
37
+ itemBorderRightWidth?: number | string
38
+ itemBorderBottomWidth?: number | string
39
+ itemBorderTopWidth?: number | string
40
+ itemBorderRadius?: number | string
41
+ minWidth?: number
42
+ minHeight?: number
43
+ itemHeight?: number
44
+ groupHeight?: number
45
+ lineHeight?: number
46
+ }
47
+
48
+ type ListboxItems = {
49
+ label: string
50
+ href: string
51
+ tokens?: ListboxTokens
52
+ }
53
+
54
+ export interface ListboxProps {
55
+ items: ListboxItems[]
56
+ firstItemRef?: object
57
+ parentRef?: object
58
+ LinkRouter?: ElementType
59
+ linkRouterProps?: object
60
+ tokens?: ListboxTokens
61
+ selectedId?: string
62
+ onClose?: () => void
63
+ }
64
+
65
+ declare const Listbox: ComponentType<ListboxProps>
66
+
67
+ export default Listbox
package/types/index.d.ts CHANGED
@@ -42,6 +42,9 @@ declare const ExpandCollapseMini: ComponentType<Props>
42
42
  export { default as FileUpload } from './FileUpload'
43
43
  export type { FileUploadProps, FileUploadTokens } from './FileUpload'
44
44
 
45
+ // Listbox Exports
46
+ export { default as Listbox } from './Listbox'
47
+
45
48
  declare const Footnote: ComponentType<Props> & {
46
49
  Link: ComponentType<Props>
47
50
  }