@telus-uds/components-base 1.12.1 → 1.14.1

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 (84) hide show
  1. package/CHANGELOG.md +41 -2
  2. package/component-docs.json +888 -66
  3. package/lib/Button/ButtonBase.js +36 -7
  4. package/lib/Button/ButtonGroup.js +7 -0
  5. package/lib/Button/propTypes.js +18 -0
  6. package/lib/Carousel/Carousel.js +69 -12
  7. package/lib/Carousel/CarouselContext.js +17 -11
  8. package/lib/Carousel/CarouselFirstFocus/CarouselFirstFocus.js +73 -0
  9. package/lib/Carousel/CarouselTabs/CarouselTabs.js +70 -0
  10. package/lib/Carousel/CarouselTabs/CarouselTabsPanel.js +95 -0
  11. package/lib/Carousel/CarouselTabs/CarouselTabsPanelItem.js +148 -0
  12. package/lib/Carousel/CarouselTabs/index.js +13 -0
  13. package/lib/Carousel/CarouselThumbnail.js +99 -0
  14. package/lib/Carousel/CarouselThumbnailNavigation.js +87 -0
  15. package/lib/Carousel/dictionary.js +4 -2
  16. package/lib/Carousel/index.js +10 -1
  17. package/lib/Checkbox/CheckboxGroup.js +7 -0
  18. package/lib/Icon/IconText.js +1 -1
  19. package/lib/Link/InlinePressable.js +1 -8
  20. package/lib/Link/LinkBase.js +6 -7
  21. package/lib/List/ListItem.js +1 -1
  22. package/lib/Notification/Notification.js +37 -22
  23. package/lib/Radio/RadioGroup.js +8 -0
  24. package/lib/RadioCard/RadioCardGroup.js +7 -0
  25. package/lib/SkipLink/SkipLink.js +216 -0
  26. package/lib/SkipLink/index.js +13 -0
  27. package/lib/ThemeProvider/ThemeProvider.js +6 -1
  28. package/lib/ToggleSwitch/ToggleSwitchGroup.js +7 -0
  29. package/lib/index.js +9 -0
  30. package/lib-module/Button/ButtonBase.js +35 -7
  31. package/lib-module/Button/ButtonGroup.js +7 -0
  32. package/lib-module/Button/propTypes.js +17 -0
  33. package/lib-module/Carousel/Carousel.js +66 -11
  34. package/lib-module/Carousel/CarouselContext.js +17 -11
  35. package/lib-module/Carousel/CarouselFirstFocus/CarouselFirstFocus.js +51 -0
  36. package/lib-module/Carousel/CarouselTabs/CarouselTabs.js +50 -0
  37. package/lib-module/Carousel/CarouselTabs/CarouselTabsPanel.js +76 -0
  38. package/lib-module/Carousel/CarouselTabs/CarouselTabsPanelItem.js +126 -0
  39. package/lib-module/Carousel/CarouselTabs/index.js +2 -0
  40. package/lib-module/Carousel/CarouselThumbnail.js +85 -0
  41. package/lib-module/Carousel/CarouselThumbnailNavigation.js +66 -0
  42. package/lib-module/Carousel/dictionary.js +4 -2
  43. package/lib-module/Carousel/index.js +2 -1
  44. package/lib-module/Checkbox/CheckboxGroup.js +7 -0
  45. package/lib-module/Icon/IconText.js +1 -1
  46. package/lib-module/Link/InlinePressable.js +1 -8
  47. package/lib-module/Link/LinkBase.js +6 -7
  48. package/lib-module/List/ListItem.js +1 -1
  49. package/lib-module/Notification/Notification.js +38 -23
  50. package/lib-module/Radio/RadioGroup.js +8 -0
  51. package/lib-module/RadioCard/RadioCardGroup.js +7 -0
  52. package/lib-module/SkipLink/SkipLink.js +188 -0
  53. package/lib-module/SkipLink/index.js +2 -0
  54. package/lib-module/ThemeProvider/ThemeProvider.js +5 -1
  55. package/lib-module/ToggleSwitch/ToggleSwitchGroup.js +7 -0
  56. package/lib-module/index.js +1 -0
  57. package/package.json +46 -47
  58. package/src/Button/ButtonBase.jsx +28 -9
  59. package/src/Button/ButtonGroup.jsx +6 -0
  60. package/src/Button/propTypes.js +14 -0
  61. package/src/Carousel/Carousel.jsx +68 -10
  62. package/src/Carousel/CarouselContext.jsx +22 -9
  63. package/src/Carousel/CarouselFirstFocus/CarouselFirstFocus.jsx +49 -0
  64. package/src/Carousel/CarouselTabs/CarouselTabs.jsx +37 -0
  65. package/src/Carousel/CarouselTabs/CarouselTabsPanel.jsx +69 -0
  66. package/src/Carousel/CarouselTabs/CarouselTabsPanelItem.jsx +119 -0
  67. package/src/Carousel/CarouselTabs/index.js +3 -0
  68. package/src/Carousel/CarouselThumbnail.jsx +77 -0
  69. package/src/Carousel/CarouselThumbnailNavigation.jsx +53 -0
  70. package/src/Carousel/dictionary.js +4 -2
  71. package/src/Carousel/index.js +1 -0
  72. package/src/Checkbox/CheckboxGroup.jsx +7 -0
  73. package/src/Icon/IconText.jsx +1 -1
  74. package/src/Link/InlinePressable.jsx +2 -8
  75. package/src/Link/LinkBase.jsx +8 -17
  76. package/src/List/ListItem.jsx +1 -1
  77. package/src/Notification/Notification.jsx +35 -20
  78. package/src/Radio/RadioGroup.jsx +7 -0
  79. package/src/RadioCard/RadioCardGroup.jsx +6 -0
  80. package/src/SkipLink/SkipLink.jsx +179 -0
  81. package/src/SkipLink/index.js +3 -0
  82. package/src/ThemeProvider/ThemeProvider.jsx +7 -1
  83. package/src/ToggleSwitch/ToggleSwitchGroup.jsx +6 -0
  84. package/src/index.js +1 -0
@@ -3,7 +3,7 @@ import StyleSheet from "react-native-web/dist/exports/StyleSheet";
3
3
  import View from "react-native-web/dist/exports/View";
4
4
  import PropTypes from 'prop-types';
5
5
  import { applyTextStyles, useTheme, useThemeTokens } from '../ThemeProvider';
6
- import { a11yProps, getTokensPropType, selectSystemProps, selectTokens, variantProp, viewProps, wrapStringsInText } from '../utils';
6
+ import { a11yProps, getTokensPropType, selectSystemProps, selectTokens, variantProp, viewProps, wrapStringsInText, useResponsiveProp } from '../utils';
7
7
  import ButtonBase from '../Button/ButtonBase';
8
8
  import useCopy from '../utils/useCopy';
9
9
  import dictionary from './dictionary';
@@ -57,6 +57,10 @@ const selectDismissButtonContainerStyles = _ref4 => {
57
57
  paddingLeft: dismissButtonGap
58
58
  };
59
59
  };
60
+
61
+ const selectContentContainerStyle = maxWidth => ({
62
+ width: maxWidth || '100%'
63
+ });
60
64
  /**
61
65
  * A banner that highlights important messages:
62
66
  * - Status message to show there is an error or outage of services
@@ -131,6 +135,7 @@ const Notification = /*#__PURE__*/forwardRef((_ref5, ref) => {
131
135
  const {
132
136
  themeOptions
133
137
  } = useTheme();
138
+ const contentMaxWidth = useResponsiveProp(themeOptions === null || themeOptions === void 0 ? void 0 : themeOptions.contentMaxWidth);
134
139
 
135
140
  if (isDismissed) {
136
141
  return null;
@@ -150,30 +155,33 @@ const Notification = /*#__PURE__*/forwardRef((_ref5, ref) => {
150
155
  const onDismissPress = () => setIsDismissed(true); // TODO: replace the dismiss button with IconButton when implemented (https://github.com/telus/universal-design-system/issues/281)
151
156
 
152
157
 
153
- return /*#__PURE__*/_jsxs(View, {
158
+ return /*#__PURE__*/_jsx(View, {
154
159
  ref: ref,
155
160
  style: [staticStyles.container, selectContainerStyles(themeTokens)],
156
161
  ...selectProps(rest),
157
- children: [IconComponent && /*#__PURE__*/_jsx(View, {
158
- style: selectIconContainerStyles(themeTokens),
159
- children: /*#__PURE__*/_jsx(IconComponent, { ...selectIconProps(themeTokens)
160
- })
161
- }), /*#__PURE__*/_jsx(View, {
162
- style: staticStyles.contentContainer,
163
- children: content && typeof content === 'function' ? content({
164
- textStyles,
165
- variant
166
- }) : content
167
- }), dismissible && DismissIconComponent && /*#__PURE__*/_jsx(View, {
168
- style: selectDismissButtonContainerStyles(themeTokens),
169
- children: /*#__PURE__*/_jsx(ButtonBase, {
170
- onPress: onDismissPress,
171
- accessibilityRole: "button",
172
- accessibilityLabel: getCopy('dismiss'),
173
- children: () => /*#__PURE__*/_jsx(DismissIconComponent, { ...selectDismissIconProps(themeTokens)
162
+ children: /*#__PURE__*/_jsxs(View, {
163
+ style: [staticStyles.content, selectContentContainerStyle(contentMaxWidth)],
164
+ children: [/*#__PURE__*/_jsxs(View, {
165
+ style: staticStyles.contentContainer,
166
+ children: [IconComponent && /*#__PURE__*/_jsx(View, {
167
+ style: selectIconContainerStyles(themeTokens),
168
+ children: /*#__PURE__*/_jsx(IconComponent, { ...selectIconProps(themeTokens)
169
+ })
170
+ }), content && typeof content === 'function' ? content({
171
+ textStyles,
172
+ variant
173
+ }) : content]
174
+ }), dismissible && DismissIconComponent && /*#__PURE__*/_jsx(View, {
175
+ style: selectDismissButtonContainerStyles(themeTokens),
176
+ children: /*#__PURE__*/_jsx(ButtonBase, {
177
+ onPress: onDismissPress,
178
+ accessibilityRole: "button",
179
+ accessibilityLabel: getCopy('dismiss'),
180
+ children: () => /*#__PURE__*/_jsx(DismissIconComponent, { ...selectDismissIconProps(themeTokens)
181
+ })
174
182
  })
175
- })
176
- })]
183
+ })]
184
+ })
177
185
  });
178
186
  });
179
187
  Notification.displayName = 'Notification';
@@ -206,9 +214,16 @@ Notification.propTypes = { ...selectedSystemPropTypes,
206
214
  export default Notification;
207
215
  const staticStyles = StyleSheet.create({
208
216
  container: {
209
- flexDirection: 'row'
217
+ flexDirection: 'row',
218
+ justifyContent: 'center'
210
219
  },
211
220
  contentContainer: {
212
- flex: 1
221
+ flexDirection: 'row',
222
+ flexShrink: 1
223
+ },
224
+ content: {
225
+ flexDirection: 'row',
226
+ flexShrink: 1,
227
+ justifyContent: 'space-between'
213
228
  }
214
229
  });
@@ -69,6 +69,7 @@ const RadioGroup = /*#__PURE__*/forwardRef((_ref, ref) => {
69
69
  legend,
70
70
  tooltip,
71
71
  hint,
72
+ hintPosition = 'inline',
72
73
  validation,
73
74
  feedback,
74
75
  initialCheckedId,
@@ -118,6 +119,7 @@ const RadioGroup = /*#__PURE__*/forwardRef((_ref, ref) => {
118
119
  };
119
120
 
120
121
  return /*#__PURE__*/_jsx(Radio, {
122
+ error: validation === 'error',
121
123
  ref: itemRef,
122
124
  id: radioId,
123
125
  checked: isChecked,
@@ -137,6 +139,7 @@ const RadioGroup = /*#__PURE__*/forwardRef((_ref, ref) => {
137
139
  legend: legend,
138
140
  tooltip: tooltip,
139
141
  hint: hint,
142
+ hintPosition: hintPosition,
140
143
  space: fieldSpace,
141
144
  feedback: feedback,
142
145
  inactive: inactive,
@@ -192,6 +195,11 @@ RadioGroup.propTypes = { ...selectedSystemPropTypes,
192
195
  */
193
196
  hint: PropTypes.string,
194
197
 
198
+ /**
199
+ * Position of the hint relative to label. Use `below` to display a larger hint below the label.
200
+ */
201
+ hintPosition: PropTypes.oneOf(['inline', 'below']),
202
+
195
203
  /**
196
204
  * Optional tooltip text content to include alongside the legend and hint.
197
205
  */
@@ -70,6 +70,7 @@ const RadioCardGroup = /*#__PURE__*/forwardRef((_ref, ref) => {
70
70
  legend,
71
71
  tooltip,
72
72
  hint,
73
+ hintPosition = 'inline',
73
74
  validation,
74
75
  feedback,
75
76
  initialCheckedId,
@@ -114,6 +115,7 @@ const RadioCardGroup = /*#__PURE__*/forwardRef((_ref, ref) => {
114
115
  legend: legend,
115
116
  tooltip: tooltip,
116
117
  hint: hint,
118
+ hintPosition: hintPosition,
117
119
  space: fieldSpace,
118
120
  feedback: feedback,
119
121
  inactive: inactive || readOnly,
@@ -199,6 +201,11 @@ RadioCardGroup.propTypes = { ...selectedSystemPropTypes,
199
201
  */
200
202
  hint: PropTypes.string,
201
203
 
204
+ /**
205
+ * Position of the hint relative to label. Use `below` to display a larger hint below the label.
206
+ */
207
+ hintPosition: PropTypes.oneOf(['inline', 'below']),
208
+
202
209
  /**
203
210
  * Optional tooltip text content to include alongside the legend and hint.
204
211
  */
@@ -0,0 +1,188 @@
1
+ import React, { forwardRef } from 'react';
2
+ import Platform from "react-native-web/dist/exports/Platform";
3
+ import Pressable from "react-native-web/dist/exports/Pressable";
4
+ import StyleSheet from "react-native-web/dist/exports/StyleSheet";
5
+ import Text from "react-native-web/dist/exports/Text";
6
+ import PropTypes from 'prop-types';
7
+ import { useThemeTokensCallback } from '../ThemeProvider';
8
+ import { a11yProps, clickProps, getTokensPropType, linkProps, resolvePressableTokens, selectSystemProps, variantProp, withLinkRouter } from '../utils';
9
+ import { jsx as _jsx } from "react/jsx-runtime";
10
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, linkProps]); // ensure explicit selection of tokens
11
+
12
+ const selectStyles = _ref => {
13
+ let {
14
+ backgroundColor,
15
+ outlineColor,
16
+ outlineOffset,
17
+ outlineStyle,
18
+ outlineWidth,
19
+ paddingHorizontal,
20
+ paddingVertical,
21
+ borderRadius
22
+ } = _ref;
23
+ return {
24
+ backgroundColor,
25
+ outlineColor,
26
+ outlineOffset,
27
+ outlineStyle,
28
+ outlineWidth,
29
+ paddingHorizontal,
30
+ paddingVertical,
31
+ borderRadius
32
+ };
33
+ };
34
+
35
+ const selectTextStyles = _ref2 => {
36
+ let {
37
+ color
38
+ } = _ref2;
39
+ return {
40
+ color
41
+ };
42
+ };
43
+ /**
44
+ * A generic Skip link component, unstyled by default.
45
+ * A Skip link component help keyboard-only users, screen reader users to skip
46
+ * sections and navigate to the content they want.
47
+ *
48
+ * ## Component API
49
+ *
50
+ * For common uses, pass a `href` that is a # link to a DOM id that can be skipped to (web only).
51
+ *
52
+ * The element with this ID should be focusable, e.g. `<Box nativeID="skip-target" focusable>`.
53
+ *
54
+ * Other custom behaviour may be set by passing an `onPress` function, and routers may be integrated
55
+ * in the same way as other navigation-related components by passing a `LinkRouter`; but a # anchor
56
+ * href on web and/or a `targetRef` for cross-platform applications is the recommended approach.
57
+ *
58
+ * ## Visible styling
59
+ *
60
+ * When focused, the skip link shows as a visible element similar to a simplified ButtonLink using
61
+ * UDS theming. The `tokens` prop may be used to override these styles.
62
+ *
63
+ * To control the background of a skip link, the following tokens can be used:
64
+ *
65
+ * - `backgroundColor`
66
+ * *
67
+ * In order to control the color of the skip link text, the following tokens can be used:
68
+ *
69
+ * - `color`
70
+ *
71
+ * ### Padding
72
+ *
73
+ * The following padding tokens can be used:
74
+ *
75
+ * - `paddingHorizontal`
76
+ * - `paddingVertical`
77
+ *
78
+ * ### Outline
79
+ *
80
+ * The following tokens to control the outline:
81
+ *
82
+ * - `outlineColor`
83
+ * - `outlineOffset`
84
+ * - `outlineStyle`
85
+ * - `outlineWidth`
86
+ *
87
+ * ## Usability and A11y guidelines
88
+ *
89
+ * - The skip link component is visually hidden until a keyboard press activates it.
90
+ * - Usually, you should place the skip link immediately after the opening <body> tag.
91
+ * - This lets users bypass top-level navigation links and jump to the main content on a page.
92
+ * - Also consider using SkipLink before a complex feature containing many focusable elements.
93
+ *
94
+ * ## Accessibility
95
+ *
96
+ * Skip link supports all the common a11y and link props.
97
+ */
98
+
99
+
100
+ const SkipLink = /*#__PURE__*/forwardRef((_ref3, ref) => {
101
+ let {
102
+ tokens,
103
+ variant,
104
+ href,
105
+ children,
106
+ ...rawRest
107
+ } = _ref3;
108
+ const {
109
+ onPress,
110
+ ...rest
111
+ } = clickProps.toPressProps(rawRest);
112
+ const getTokens = useThemeTokensCallback('SkipLink', tokens, variant);
113
+ const defaultTokens = getTokens();
114
+
115
+ const resolveLinkTokens = pressState => resolvePressableTokens(defaultTokens, pressState);
116
+
117
+ const handlePress = event => {
118
+ if (typeof onPress === 'function') onPress(event); // TODO - support native apps with something based on refs and/or setAccessibilityFocus
119
+ };
120
+
121
+ return /*#__PURE__*/_jsx(Pressable, {
122
+ ref: ref,
123
+ accessibilityRole: "link",
124
+ onPress: handlePress,
125
+ href: href,
126
+ style: _ref4 => {
127
+ let {
128
+ focused: focus
129
+ } = _ref4;
130
+ const themeTokens = getTokens({
131
+ focus
132
+ });
133
+ const skipLinkStyle = selectStyles(themeTokens);
134
+ return [staticStyles.absolute, skipLinkStyle, !focus && staticStyles.hidden];
135
+ },
136
+ ...selectProps(rest),
137
+ children: pressState => {
138
+ const themeTokens = resolveLinkTokens(pressState);
139
+ const textStyles = selectTextStyles(themeTokens);
140
+ return /*#__PURE__*/_jsx(Text, {
141
+ style: [textStyles, staticStyles.baseline],
142
+ children: children
143
+ });
144
+ }
145
+ });
146
+ });
147
+ SkipLink.displayName = 'SkipLink';
148
+ SkipLink.propTypes = { ...selectedSystemPropTypes,
149
+
150
+ /**
151
+ * The text content shown or read out when the SkipLink is focused, usually a string.
152
+ */
153
+ children: PropTypes.node,
154
+
155
+ /**
156
+ * The target to skip to. Usually an anchor link to a section id (e.g. href="#main-section").
157
+ */
158
+ href: PropTypes.string,
159
+ tokens: getTokensPropType('SkipLink'),
160
+ variant: variantProp.propType
161
+ };
162
+ const staticStyles = StyleSheet.create({
163
+ baseline: {
164
+ alignSelf: 'baseline'
165
+ },
166
+ absolute: {
167
+ margin: 0,
168
+ position: 'absolute',
169
+ top: 0,
170
+ left: 0
171
+ },
172
+ hidden: {
173
+ overflow: 'hidden',
174
+ ...Platform.select({
175
+ web: {
176
+ clip: 'rect(0 0 0 0)',
177
+ clipPath: 'inset(50%)'
178
+ },
179
+ default: {
180
+ // width / height of 0 would make it non-focusable
181
+ height: 1,
182
+ width: 1,
183
+ opacity: 0
184
+ }
185
+ })
186
+ }
187
+ });
188
+ export default withLinkRouter(SkipLink);
@@ -0,0 +1,2 @@
1
+ import SkipLink from './SkipLink';
2
+ export default SkipLink;
@@ -1,6 +1,7 @@
1
1
  import React, { createContext, useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { validateThemeTokensVersion } from './utils';
4
+ import responsiveProps from '../utils/props/responsiveProps';
4
5
  import { jsx as _jsx } from "react/jsx-runtime";
5
6
  export const uninitialisedError = new Error('Theme context used outside of ThemeProvider');
6
7
  export const ThemeContext = /*#__PURE__*/createContext(uninitialisedError);
@@ -45,9 +46,12 @@ ThemeProvider.propTypes = {
45
46
  * - `forceAbsoluteFontSizing`: available on web only; when set to true, allows
46
47
  * using absolute font sizing (in pixels, doesn't scale) instead of the
47
48
  * relative sizing (in `rem`, scales depending on the browser settings)
49
+ * - `contentMaxWidth`: allows configuration of the content max width to be used in components
50
+ * such as Footnote and Notification to avoid content to stretch width more then the page's width
48
51
  */
49
52
  themeOptions: PropTypes.shape({
50
- forceAbsoluteFontSizing: PropTypes.bool
53
+ forceAbsoluteFontSizing: PropTypes.bool,
54
+ contentMaxWidth: responsiveProps.getTypeOptionallyByViewport(PropTypes.number)
51
55
  })
52
56
  };
53
57
  export default ThemeProvider;
@@ -25,6 +25,7 @@ const ToggleSwitchGroup = /*#__PURE__*/forwardRef((_ref, ref) => {
25
25
  inactive = false,
26
26
  feedback,
27
27
  hint,
28
+ hintPosition = 'inline',
28
29
  tooltip,
29
30
  legend,
30
31
  name: inputGroupName,
@@ -110,6 +111,7 @@ const ToggleSwitchGroup = /*#__PURE__*/forwardRef((_ref, ref) => {
110
111
  legend: legend,
111
112
  tooltip: tooltip,
112
113
  hint: hint,
114
+ hintPosition: hintPosition,
113
115
  space: fieldSpace,
114
116
  feedback: feedback,
115
117
  inactive: inactive,
@@ -192,6 +194,11 @@ ToggleSwitchGroup.propTypes = { ...selectedSystemPropTypes,
192
194
  */
193
195
  hint: PropTypes.string,
194
196
 
197
+ /**
198
+ * Position of the hint relative to label. Use `below` to display a larger hint below the label.
199
+ */
200
+ hintPosition: PropTypes.oneOf(['inline', 'below']),
201
+
195
202
  /**
196
203
  * Optional tooltip text content to include alongside the legend and hint.
197
204
  */
@@ -32,6 +32,7 @@ export { default as Search } from './Search';
32
32
  export { default as Select } from './Select';
33
33
  export { default as SideNav } from './SideNav';
34
34
  export { default as Skeleton } from './Skeleton';
35
+ export { default as SkipLink } from './SkipLink';
35
36
  export { default as Spacer } from './Spacer';
36
37
  export { default as StackView } from './StackView';
37
38
  export * from './StackView';
package/package.json CHANGED
@@ -1,21 +1,55 @@
1
1
  {
2
- "name": "@telus-uds/components-base",
3
- "version": "1.12.1",
2
+ "author": "TELUS Digital",
3
+ "browserslist": [
4
+ "extends @telus-uds/browserslist-config"
5
+ ],
6
+ "bugs": {
7
+ "url": "https://github.com/telus/universal-design-system/issues"
8
+ },
9
+ "dependencies": {
10
+ "airbnb-prop-types": "^2.16.0",
11
+ "@telus-uds/system-constants": "^1.0.4",
12
+ "@telus-uds/system-theme-tokens": "^2.3.0",
13
+ "lodash.debounce": "^4.0.8",
14
+ "lodash.merge": "^4.6.2",
15
+ "prop-types": "^15.7.2",
16
+ "react-native-picker-select": "^8.0.4",
17
+ "semver": "^7.3.5"
18
+ },
4
19
  "description": "Base components",
20
+ "devDependencies": {
21
+ "@storybook/addon-a11y": "^6.5.6",
22
+ "@storybook/addon-essentials": "^6.5.6",
23
+ "@storybook/cli": "^6.5.6",
24
+ "@storybook/react": "^6.5.6",
25
+ "@storybook/builder-webpack5": "^6.5.6",
26
+ "@storybook/manager-webpack5": "^6.5.6",
27
+ "@telus-uds/browserslist-config": "^1.0.4",
28
+ "@testing-library/jest-native": "^4.0.1",
29
+ "@testing-library/react-hooks": "^7.0.1",
30
+ "@testing-library/react-native": "^7.2.0",
31
+ "react-test-renderer": "^16.3.2",
32
+ "webpack": "5.x"
33
+ },
34
+ "directories": {
35
+ "lib": "lib",
36
+ "test": "__tests__"
37
+ },
38
+ "homepage": "https://github.com/telus/universal-design-system#readme",
5
39
  "keywords": [
6
40
  "base"
7
41
  ],
8
- "author": "TELUS Digital",
9
- "homepage": "https://github.com/telus/universal-design-system#readme",
10
42
  "license": "UNLICENSED",
11
43
  "main": "lib/index.js",
12
44
  "module": "lib-module/index.js",
13
- "react-native": "src/index.js",
14
- "sideEffects": false,
15
- "directories": {
16
- "lib": "lib",
17
- "test": "__tests__"
45
+ "name": "@telus-uds/components-base",
46
+ "peerDependencies": {
47
+ "react": "^17.0.2",
48
+ "react-dom": "^17.0.2",
49
+ "react-native": "*",
50
+ "react-native-web": "~0.17.5"
18
51
  },
52
+ "react-native": "src/index.js",
19
53
  "repository": {
20
54
  "type": "git",
21
55
  "url": "git+https://github.com/telus/universal-design-system.git"
@@ -31,46 +65,11 @@
31
65
  "build:code": "npm run build:main && npm run build:module",
32
66
  "build:docs": "babel-node --plugins=@nearform/babel-plugin-react-docgen generate-component-docs.js",
33
67
  "storybook": "start-storybook",
34
- "build-storybook": "build-storybook",
35
- "dev": "npm run build:code --watch"
36
- },
37
- "bugs": {
38
- "url": "https://github.com/telus/universal-design-system/issues"
68
+ "build-storybook": "build-storybook"
39
69
  },
70
+ "sideEffects": false,
40
71
  "standard-engine": {
41
72
  "skip": true
42
73
  },
43
- "browserslist": [
44
- "extends @telus-uds/browserslist-config"
45
- ],
46
- "peerDependencies": {
47
- "react": "^17.0.2",
48
- "react-dom": "^17.0.2",
49
- "react-native": "*",
50
- "react-native-web": "~0.17.5"
51
- },
52
- "devDependencies": {
53
- "@storybook/addon-a11y": "^6.5.6",
54
- "@storybook/addon-essentials": "^6.5.6",
55
- "@storybook/cli": "^6.5.6",
56
- "@storybook/react": "^6.5.6",
57
- "@storybook/builder-webpack5": "^6.5.6",
58
- "@storybook/manager-webpack5": "^6.5.6",
59
- "@telus-uds/browserslist-config": "^1.0.4",
60
- "@testing-library/jest-native": "^4.0.1",
61
- "@testing-library/react-hooks": "^7.0.1",
62
- "@testing-library/react-native": "^7.2.0",
63
- "react-test-renderer": "^16.3.2",
64
- "webpack": "5.x"
65
- },
66
- "dependencies": {
67
- "airbnb-prop-types": "^2.16.0",
68
- "@telus-uds/system-constants": "^1.0.4",
69
- "@telus-uds/system-theme-tokens": "^2.1.0",
70
- "lodash.debounce": "^4.0.8",
71
- "lodash.merge": "^4.6.2",
72
- "prop-types": "^15.7.2",
73
- "react-native-picker-select": "^8.0.4",
74
- "semver": "^7.3.5"
75
- }
74
+ "version": "1.14.1"
76
75
  }
@@ -17,6 +17,7 @@ import {
17
17
  wrapStringsInText,
18
18
  withLinkRouter
19
19
  } from '../utils'
20
+ import { IconText } from '../Icon'
20
21
 
21
22
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([
22
23
  a11yProps,
@@ -147,6 +148,11 @@ const selectWebOnlyStyles = (inactive, themeTokens, { accessibilityRole }) => {
147
148
  })
148
149
  }
149
150
 
151
+ const selectItemIconTokens = ({ color, iconSize }) => ({
152
+ size: iconSize,
153
+ color
154
+ })
155
+
150
156
  const ButtonBase = forwardRef(
151
157
  (
152
158
  {
@@ -158,6 +164,9 @@ const ButtonBase = forwardRef(
158
164
  disabled = false, // alias for inactive
159
165
  inactive = disabled,
160
166
  selected = false,
167
+ icon,
168
+ iconPosition = icon ? 'left' : undefined,
169
+ iconProps,
161
170
  ...rawRest
162
171
  },
163
172
  ref
@@ -195,10 +204,13 @@ const ButtonBase = forwardRef(
195
204
  const containerStyles = selectInnerContainerStyles(themeTokens)
196
205
  const borderStyles = selectBorderStyles(themeTokens)
197
206
  const textStyles = [selectTextStyles(themeTokens, themeOptions), staticStyles.text]
207
+ const iconTokens = selectItemIconTokens(themeTokens)
208
+ const { iconSpace } = themeTokens
198
209
 
199
210
  // If the container has a width set, fill it instead of sizing from content.
200
211
  // If in future we support text alignments other than center, add here.
201
212
  const stretchStyles = themeTokens.width ? staticStyles.stretch : staticStyles.align
213
+ const IconComponent = icon || themeTokens.icon
202
214
 
203
215
  return (
204
216
  <View
@@ -217,15 +229,22 @@ const ButtonBase = forwardRef(
217
229
  })
218
230
  ]}
219
231
  >
220
- {wrapStringsInText(
221
- typeof children === 'function'
222
- ? children({
223
- ...resolvePressableState(pressableState, extraButtonState),
224
- textStyles
225
- })
226
- : children,
227
- { style: textStyles }
228
- )}
232
+ <IconText
233
+ icon={IconComponent}
234
+ iconPosition={iconPosition}
235
+ space={iconSpace}
236
+ iconProps={{ ...iconProps, tokens: iconTokens }}
237
+ >
238
+ {wrapStringsInText(
239
+ typeof children === 'function'
240
+ ? children({
241
+ ...resolvePressableState(pressableState, extraButtonState),
242
+ textStyles
243
+ })
244
+ : children,
245
+ { style: textStyles }
246
+ )}
247
+ </IconText>
229
248
  </View>
230
249
  )
231
250
  }}
@@ -45,6 +45,7 @@ const ButtonGroup = forwardRef(
45
45
  legend,
46
46
  tooltip,
47
47
  hint,
48
+ hintPosition = 'inline',
48
49
  validation,
49
50
  feedback,
50
51
  name: inputGroupName,
@@ -94,6 +95,7 @@ const ButtonGroup = forwardRef(
94
95
  legend={legend}
95
96
  tooltip={tooltip}
96
97
  hint={hint}
98
+ hintPosition={hintPosition}
97
99
  space={fieldSpace}
98
100
  feedback={feedback}
99
101
  readOnly={readOnly}
@@ -217,6 +219,10 @@ ButtonGroup.propTypes = {
217
219
  * Optional additional text giving more detail to help a user make a choice.
218
220
  */
219
221
  hint: PropTypes.string,
222
+ /**
223
+ * Position of the hint relative to label. Use `below` to display a larger hint below the label.
224
+ */
225
+ hintPosition: PropTypes.oneOf(['inline', 'below']),
220
226
  /**
221
227
  * Optional tooltip text content to include alongside the legend and hint.
222
228
  */
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types'
2
2
  import ABBPropTypes from 'airbnb-prop-types'
3
3
  import { variantProp, getTokensPropType } from '../utils/props'
4
4
  import A11yText from '../A11yText'
5
+ import { iconComponentPropTypes } from '../Icon'
5
6
 
6
7
  export const textAndA11yText = ABBPropTypes.childrenOf(
7
8
  PropTypes.oneOfType([ABBPropTypes.elementType(A11yText), PropTypes.string])
@@ -31,6 +32,19 @@ const buttonPropTypes = {
31
32
  * Function called when the button is pressed. Required unless the button has a href.
32
33
  */
33
34
  onPress: PropTypes.func,
35
+ /**
36
+ * Optional variant that may be passed down to the link's icon if there is one
37
+ */
38
+ iconProps: PropTypes.exact(iconComponentPropTypes),
39
+ /**
40
+ * When `icon` is provided, use `iconPosition` to place the Icon to the left or right side of the button.
41
+ */
42
+ iconPosition: PropTypes.oneOf(['left', 'right']),
43
+ /**
44
+ * A function component for an SVG icon to render inside the link. Inherits size and color from
45
+ * the link and any Typography the link is nested inside.
46
+ */
47
+ icon: PropTypes.func,
34
48
  variant: variantProp.propType
35
49
  }
36
50
  export default buttonPropTypes