@telus-uds/components-base 1.12.0 → 1.12.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 (78) hide show
  1. package/CHANGELOG.md +10 -2
  2. package/component-docs.json +67 -11
  3. package/lib/BaseProvider/index.js +7 -2
  4. package/lib/Button/ButtonBase.js +18 -14
  5. package/lib/Carousel/Carousel.js +19 -51
  6. package/lib/Carousel/CarouselContext.js +12 -4
  7. package/lib/Carousel/CarouselStepTracker/CarouselStepTracker.js +56 -0
  8. package/lib/Carousel/CarouselStepTracker/index.js +13 -0
  9. package/lib/Checkbox/Checkbox.js +7 -3
  10. package/lib/Checkbox/CheckboxGroup.js +1 -1
  11. package/lib/Feedback/Feedback.js +18 -10
  12. package/lib/Icon/IconText.js +5 -0
  13. package/lib/InputLabel/InputLabel.js +11 -5
  14. package/lib/Link/LinkBase.js +7 -3
  15. package/lib/List/ListItem.js +7 -3
  16. package/lib/Notification/Notification.js +7 -2
  17. package/lib/Pagination/Pagination.js +7 -3
  18. package/lib/RadioCard/RadioCard.js +6 -1
  19. package/lib/Select/Select.js +7 -3
  20. package/lib/StepTracker/Step.js +8 -4
  21. package/lib/StepTracker/StepTracker.js +7 -3
  22. package/lib/Tabs/TabsItem.js +4 -0
  23. package/lib/TextInput/TextInputBase.js +7 -3
  24. package/lib/ThemeProvider/ThemeProvider.js +20 -3
  25. package/lib/ThemeProvider/utils/styles.js +8 -1
  26. package/lib/ThemeProvider/utils/theme-tokens.js +1 -1
  27. package/lib/Typography/Typography.js +6 -2
  28. package/lib-module/BaseProvider/index.js +7 -2
  29. package/lib-module/Button/ButtonBase.js +7 -3
  30. package/lib-module/Carousel/Carousel.js +18 -50
  31. package/lib-module/Carousel/CarouselContext.js +11 -4
  32. package/lib-module/Carousel/CarouselStepTracker/CarouselStepTracker.js +42 -0
  33. package/lib-module/Carousel/CarouselStepTracker/index.js +2 -0
  34. package/lib-module/Checkbox/Checkbox.js +8 -4
  35. package/lib-module/Checkbox/CheckboxGroup.js +1 -1
  36. package/lib-module/Feedback/Feedback.js +19 -11
  37. package/lib-module/Icon/IconText.js +5 -0
  38. package/lib-module/InputLabel/InputLabel.js +12 -6
  39. package/lib-module/Link/LinkBase.js +8 -4
  40. package/lib-module/List/ListItem.js +8 -4
  41. package/lib-module/Notification/Notification.js +8 -3
  42. package/lib-module/Pagination/Pagination.js +8 -4
  43. package/lib-module/RadioCard/RadioCard.js +7 -2
  44. package/lib-module/Select/Select.js +8 -4
  45. package/lib-module/StepTracker/Step.js +9 -5
  46. package/lib-module/StepTracker/StepTracker.js +8 -4
  47. package/lib-module/Tabs/TabsItem.js +5 -1
  48. package/lib-module/TextInput/TextInputBase.js +8 -4
  49. package/lib-module/ThemeProvider/ThemeProvider.js +20 -3
  50. package/lib-module/ThemeProvider/utils/styles.js +8 -1
  51. package/lib-module/ThemeProvider/utils/theme-tokens.js +1 -1
  52. package/lib-module/Typography/Typography.js +7 -3
  53. package/package.json +1 -1
  54. package/src/BaseProvider/index.jsx +6 -3
  55. package/src/Button/ButtonBase.jsx +8 -3
  56. package/src/Carousel/Carousel.jsx +27 -58
  57. package/src/Carousel/CarouselContext.jsx +15 -4
  58. package/src/Carousel/CarouselStepTracker/CarouselStepTracker.jsx +36 -0
  59. package/src/Carousel/CarouselStepTracker/index.js +3 -0
  60. package/src/Checkbox/Checkbox.jsx +14 -11
  61. package/src/Checkbox/CheckboxGroup.jsx +1 -1
  62. package/src/Feedback/Feedback.jsx +14 -7
  63. package/src/Icon/IconText.jsx +2 -0
  64. package/src/InputLabel/InputLabel.jsx +13 -12
  65. package/src/Link/LinkBase.jsx +10 -4
  66. package/src/List/ListItem.jsx +9 -4
  67. package/src/Notification/Notification.jsx +5 -3
  68. package/src/Pagination/Pagination.jsx +6 -4
  69. package/src/RadioCard/RadioCard.jsx +3 -2
  70. package/src/Select/Select.jsx +12 -3
  71. package/src/StepTracker/Step.jsx +12 -4
  72. package/src/StepTracker/StepTracker.jsx +11 -10
  73. package/src/Tabs/TabsItem.jsx +3 -2
  74. package/src/TextInput/TextInputBase.jsx +11 -3
  75. package/src/ThemeProvider/ThemeProvider.jsx +16 -3
  76. package/src/ThemeProvider/utils/styles.js +9 -1
  77. package/src/ThemeProvider/utils/theme-tokens.js +1 -1
  78. package/src/Typography/Typography.jsx +11 -12
@@ -6,7 +6,7 @@ import View from "react-native-web/dist/exports/View";
6
6
  import StackView from '../StackView';
7
7
  import Icon from '../Icon';
8
8
  import { a11yProps, getTokensPropType, selectSystemProps, variantProp, viewProps } from '../utils';
9
- import { applyTextStyles } from '../ThemeProvider';
9
+ import { applyTextStyles, useTheme } from '../ThemeProvider';
10
10
  import { jsx as _jsx } from "react/jsx-runtime";
11
11
  import { jsxs as _jsxs } from "react/jsx-runtime";
12
12
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
@@ -110,7 +110,7 @@ const selectLabelContainerStyles = _ref5 => {
110
110
  };
111
111
  };
112
112
 
113
- const selectLabelStyles = (_ref6, isCurrent) => {
113
+ const selectLabelStyles = (_ref6, themeOptions, isCurrent) => {
114
114
  let {
115
115
  labelColor,
116
116
  labelCurrentColor,
@@ -125,7 +125,8 @@ const selectLabelStyles = (_ref6, isCurrent) => {
125
125
  fontSize: labelFontSize,
126
126
  lineHeight: labelLineHeight,
127
127
  fontWeight: isCurrent ? labelCurrentFontWeight : labelFontWeight,
128
- fontName: labelFontName
128
+ fontName: labelFontName,
129
+ themeOptions
129
130
  });
130
131
  };
131
132
 
@@ -166,6 +167,9 @@ const Step = _ref7 => {
166
167
  const isCompleted = status > stepIndex;
167
168
  const isCurrent = status === stepIndex;
168
169
  const isActive = isCompleted || isCurrent;
170
+ const {
171
+ themeOptions
172
+ } = useTheme();
169
173
  return /*#__PURE__*/_jsxs(StackView, {
170
174
  space: 0,
171
175
  tokens: {
@@ -200,12 +204,12 @@ const Step = _ref7 => {
200
204
  }), showStepLabel && /*#__PURE__*/_jsxs(View, {
201
205
  style: [staticStyles.stepLabelContainer, selectLabelContainerStyles(tokens)],
202
206
  children: [showStepName && /*#__PURE__*/_jsx(Text, {
203
- style: [staticStyles.centeredText, selectLabelStyles(tokens, isCurrent)],
207
+ style: [staticStyles.centeredText, selectLabelStyles(tokens, themeOptions, isCurrent)],
204
208
  children: name
205
209
  }), /*#__PURE__*/_jsx(StackView, {
206
210
  direction: "row",
207
211
  children: /*#__PURE__*/_jsx(Text, {
208
- style: [staticStyles.centeredText, tokens.labelDirection === 'column' && staticStyles.wrappingLabel, selectLabelStyles(tokens, isCurrent)],
212
+ style: [staticStyles.centeredText, tokens.labelDirection === 'column' && staticStyles.wrappingLabel, selectLabelStyles(tokens, themeOptions, isCurrent)],
209
213
  children: label
210
214
  })
211
215
  })]
@@ -4,7 +4,7 @@ import StyleSheet from "react-native-web/dist/exports/StyleSheet";
4
4
  import Text from "react-native-web/dist/exports/Text";
5
5
  import View from "react-native-web/dist/exports/View";
6
6
  import StackView from '../StackView';
7
- import { applyTextStyles, useThemeTokens } from '../ThemeProvider';
7
+ import { applyTextStyles, useTheme, useThemeTokens } from '../ThemeProvider';
8
8
  import { a11yProps, getTokensPropType, selectSystemProps, variantProp, viewProps } from '../utils';
9
9
  import { useViewport } from '../ViewportProvider';
10
10
  import useCopy from '../utils/useCopy';
@@ -38,7 +38,7 @@ const selectStepTrackerLabelContainerStyles = _ref2 => {
38
38
  };
39
39
  };
40
40
 
41
- const selectStepTrackerLabelStyles = _ref3 => {
41
+ const selectStepTrackerLabelStyles = (_ref3, themeOptions) => {
42
42
  let {
43
43
  labelColor,
44
44
  labelFontSize,
@@ -51,7 +51,8 @@ const selectStepTrackerLabelStyles = _ref3 => {
51
51
  fontSize: labelFontSize,
52
52
  lineHeight: labelLineHeight,
53
53
  fontWeight: labelFontWeight,
54
- fontName: labelFontName
54
+ fontName: labelFontName,
55
+ themeOptions
55
56
  });
56
57
  };
57
58
  /**
@@ -113,6 +114,9 @@ const StepTracker = /*#__PURE__*/forwardRef((_ref4, ref) => {
113
114
 
114
115
  const getStepLabel = index => themeTokens.showStepLabel ? getCopy('stepLabel').replace('%{stepNumber}', index + 1) : '';
115
116
 
117
+ const {
118
+ themeOptions
119
+ } = useTheme();
116
120
  if (!steps.length) return null;
117
121
  const selectedProps = selectProps({
118
122
  accessibilityLabel: stepTrackerLabel,
@@ -147,7 +151,7 @@ const StepTracker = /*#__PURE__*/forwardRef((_ref4, ref) => {
147
151
  }), showStepTrackerLabel && /*#__PURE__*/_jsx(View, {
148
152
  style: [staticStyles.stepTrackerLabelContainer, selectStepTrackerLabelContainerStyles(themeTokens)],
149
153
  children: /*#__PURE__*/_jsx(Text, {
150
- style: selectStepTrackerLabelStyles(themeTokens),
154
+ style: selectStepTrackerLabelStyles(themeTokens, themeOptions),
151
155
  children: stepTrackerLabel
152
156
  })
153
157
  })]
@@ -5,7 +5,7 @@ import Pressable from "react-native-web/dist/exports/Pressable";
5
5
  import StyleSheet from "react-native-web/dist/exports/StyleSheet";
6
6
  import Text from "react-native-web/dist/exports/Text";
7
7
  import View from "react-native-web/dist/exports/View";
8
- import { applyTextStyles, useThemeTokensCallback } from '../ThemeProvider';
8
+ import { applyTextStyles, useTheme, useThemeTokensCallback } from '../ThemeProvider';
9
9
  import { a11yProps, clickProps, getTokensPropType, linkProps, resolvePressableTokens, selectSystemProps, selectTokens, variantProp, viewProps, withLinkRouter } from '../utils';
10
10
  import Spacer from '../Spacer';
11
11
  import { horizontalScrollUtils } from '../HorizontalScroll';
@@ -105,6 +105,9 @@ const TabsItem = /*#__PURE__*/forwardRef((_ref4, ref) => {
105
105
  onPress,
106
106
  ...rest
107
107
  } = clickProps.toPressProps(rawRest);
108
+ const {
109
+ themeOptions
110
+ } = useTheme();
108
111
  const getTokens = useThemeTokensCallback('TabsItem', tokens, variant);
109
112
 
110
113
  const resolveTokens = pressableState => resolvePressableTokens(getTokens, pressableState, {
@@ -170,6 +173,7 @@ const TabsItem = /*#__PURE__*/forwardRef((_ref4, ref) => {
170
173
  const highlightTriangleStyle = hasHighlightTriangle && selectHighlightTriangleStyles(themeTokens);
171
174
  const containerStyles = selectContainerStyles(themeTokens);
172
175
  const textStyles = applyTextStyles({ ...selectTokens('Typography', themeTokens),
176
+ themeOptions,
173
177
  textAlign
174
178
  });
175
179
  return /*#__PURE__*/_jsxs(View, {
@@ -4,13 +4,13 @@ import StyleSheet from "react-native-web/dist/exports/StyleSheet";
4
4
  import NativeTextInput from "react-native-web/dist/exports/TextInput";
5
5
  import View from "react-native-web/dist/exports/View";
6
6
  import PropTypes from 'prop-types';
7
- import { applyTextStyles, useThemeTokens, applyOuterBorder } from '../ThemeProvider';
7
+ import { applyTextStyles, useTheme, useThemeTokens, applyOuterBorder } from '../ThemeProvider';
8
8
  import { a11yProps, getTokensPropType, selectSystemProps, textInputHandlerProps, textInputProps, useInputValue, variantProp, viewProps } from '../utils';
9
9
  import { jsx as _jsx } from "react/jsx-runtime";
10
10
  import { jsxs as _jsxs } from "react/jsx-runtime";
11
11
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, textInputHandlerProps, textInputProps, viewProps]);
12
12
 
13
- const selectInputStyles = (_ref, inactive) => {
13
+ const selectInputStyles = (_ref, themeOptions, inactive) => {
14
14
  let {
15
15
  backgroundColor,
16
16
  color,
@@ -41,7 +41,8 @@ const selectInputStyles = (_ref, inactive) => {
41
41
  fontName,
42
42
  fontSize,
43
43
  lineHeight,
44
- fontWeight
44
+ fontWeight,
45
+ themeOptions
45
46
  });
46
47
 
47
48
  function linesToHeight(lines) {
@@ -210,9 +211,12 @@ const TextInputBase = /*#__PURE__*/forwardRef((_ref5, ref) => {
210
211
  // Input could lead to changing its state from uncontrolled to controlled
211
212
  value: isControlled ? currentValue : undefined
212
213
  };
214
+ const {
215
+ themeOptions
216
+ } = useTheme();
213
217
  const nativeInputStyle = selectInputStyles({ ...themeTokens,
214
218
  height
215
- }, inactive);
219
+ }, themeOptions, inactive);
216
220
  return /*#__PURE__*/_jsxs(View, {
217
221
  style: selectOuterBorderStyles(themeTokens),
218
222
  children: [/*#__PURE__*/_jsx(NativeTextInput, {
@@ -9,7 +9,11 @@ export const ThemeSetterContext = /*#__PURE__*/createContext(uninitialisedError)
9
9
  const ThemeProvider = _ref => {
10
10
  let {
11
11
  children,
12
- defaultTheme
12
+ defaultTheme,
13
+ // TODO: switch `forceAbsoluteFontSizing` to be false by default in the next major version
14
+ themeOptions = {
15
+ forceAbsoluteFontSizing: true
16
+ }
13
17
  } = _ref;
14
18
  const [theme, setTheme] = useState(defaultTheme); // Validate the theme tokens version on every render.
15
19
  // This will intentionally break the application when attempting to use an invalid theme.
@@ -19,7 +23,9 @@ const ThemeProvider = _ref => {
19
23
  return /*#__PURE__*/_jsx(ThemeSetterContext.Provider, {
20
24
  value: setTheme,
21
25
  children: /*#__PURE__*/_jsx(ThemeContext.Provider, {
22
- value: theme,
26
+ value: { ...theme,
27
+ themeOptions
28
+ },
23
29
  children: children
24
30
  })
25
31
  });
@@ -31,6 +37,17 @@ ThemeProvider.propTypes = {
31
37
  metadata: PropTypes.shape({
32
38
  themeTokensVersion: PropTypes.string.isRequired
33
39
  }).isRequired
34
- }).isRequired
40
+ }).isRequired,
41
+
42
+ /**
43
+ * An object containing options allowing to customize the theming experience:
44
+ *
45
+ * - `forceAbsoluteFontSizing`: available on web only; when set to true, allows
46
+ * using absolute font sizing (in pixels, doesn't scale) instead of the
47
+ * relative sizing (in `rem`, scales depending on the browser settings)
48
+ */
49
+ themeOptions: PropTypes.shape({
50
+ forceAbsoluteFontSizing: PropTypes.bool
51
+ })
35
52
  };
36
53
  export default ThemeProvider;
@@ -14,14 +14,21 @@ export function applyTextStyles(_ref) {
14
14
  fontWeight = '400',
15
15
  fontName,
16
16
  fontStyle = 'normal',
17
+ themeOptions = {
18
+ // TODO: switch `forceAbsoluteFontSizing` to be false by default in the next major version
19
+ forceAbsoluteFontSizing: true
20
+ },
17
21
  ...rest
18
22
  } = _ref;
19
23
  const styles = { ...rest
20
24
  };
25
+ const {
26
+ forceAbsoluteFontSizing
27
+ } = themeOptions;
21
28
 
22
29
  if (fontSize) {
23
30
  // If relative font sizes are needed, catch and calculate them here
24
- styles.fontSize = fontSize;
31
+ styles.fontSize = Platform.OS === 'web' && !forceAbsoluteFontSizing ? "".concat(fontSize / fontBasePixels, "rem") : fontSize;
25
32
  }
26
33
 
27
34
  if (typeof lineHeight === 'number') {
@@ -158,6 +158,6 @@ export const validateThemeTokensVersion = theme => {
158
158
  const actualThemeTokensVersion = theme === null || theme === void 0 ? void 0 : (_theme$metadata2 = theme.metadata) === null || _theme$metadata2 === void 0 ? void 0 : _theme$metadata2.themeTokensVersion;
159
159
 
160
160
  if (!semVerSatisfies(actualThemeTokensVersion, expectedThemeTokensVersion)) {
161
- throw new Error("Invalid UDS token schema version detected.\n\nThe UDS base components ".concat(pkg.name, " v").concat(pkg.version, " are only compatible with UDS themes that are built with @telus-uds/system-theme-tokens version that is semver compatible with ").concat(expectedThemeTokensVersion, ". The current theme was built with @telus-uds/system-theme-tokens v").concat(actualThemeTokensVersion, ".\n\nIf you see this error than most likely you have attempted to install ").concat(pkg.name, " and a UDS theme manually because you are building a multi-brand application. If you are building a single brand application, consider installing the brand specific design system package such as @telus-uds/ds-allium. For more information, see https://github.com/telus/universal-design-system/blob/main/packages/docs-uds/docs/multi-brand-usage.md"));
161
+ throw new Error("Invalid UDS token schema version detected.\n\nThe UDS base components ".concat(pkg.name, " v").concat(pkg.version, " are only compatible with UDS themes that are built with @telus-uds/system-theme-tokens version that is semver compatible with ").concat(expectedThemeTokensVersion, ". The current theme was built with @telus-uds/system-theme-tokens v").concat(actualThemeTokensVersion, ".\n\nIf you see this error than most likely you have attempted to install ").concat(pkg.name, " and a UDS theme manually because you are building a multi-brand application. If you are building a single brand application, consider installing the brand specific design system package such as @telus-uds/ds-allium. For more information, see https://github.com/telus/universal-design-system/blob/main/docs/docs/multi-brand-usage.md"));
162
162
  }
163
163
  };
@@ -2,7 +2,7 @@ import React, { forwardRef } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import Text from "react-native-web/dist/exports/Text";
4
4
  import View from "react-native-web/dist/exports/View";
5
- import { useThemeTokens } from '../ThemeProvider';
5
+ import { useTheme, useThemeTokens } from '../ThemeProvider';
6
6
  import { useViewport } from '../ViewportProvider';
7
7
  import { applyTextStyles } from '../ThemeProvider/utils';
8
8
  import { a11yProps, variantProp, getTokensPropType, getMaxFontMultiplier, headingTags, selectSystemProps, textTags, textProps, viewProps, getA11yPropsFromHtmlTag } from '../utils';
@@ -14,7 +14,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
14
14
  const [selectContainerProps, selectedContainerPropTypes] = selectSystemProps([a11yProps, viewProps]);
15
15
  const [selectTextProps, selectedTextPropTypes] = selectSystemProps([textProps]);
16
16
 
17
- const selectTextStyles = _ref => {
17
+ const selectTextStyles = (_ref, themeOptions) => {
18
18
  let {
19
19
  fontWeight,
20
20
  fontSize,
@@ -31,6 +31,7 @@ const selectTextStyles = _ref => {
31
31
  color,
32
32
  lineHeight,
33
33
  fontName,
34
+ themeOptions,
34
35
  textAlign,
35
36
  textTransform,
36
37
  letterSpacing
@@ -55,10 +56,13 @@ const Typography = /*#__PURE__*/forwardRef((_ref2, ref) => {
55
56
  const themeTokens = useThemeTokens('Typography', tokens, variant, {
56
57
  viewport
57
58
  });
59
+ const {
60
+ themeOptions
61
+ } = useTheme();
58
62
  const resolvedTextProps = { ...selectTextProps(rest),
59
63
  style: selectTextStyles(align ? { ...themeTokens,
60
64
  textAlign: align
61
- } : themeTokens),
65
+ } : themeTokens, themeOptions),
62
66
  dataSet,
63
67
  maxFontSizeMultiplier: getMaxFontMultiplier(themeTokens)
64
68
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telus-uds/components-base",
3
- "version": "1.12.0",
3
+ "version": "1.12.1",
4
4
  "description": "Base components",
5
5
  "keywords": [
6
6
  "base"
@@ -4,17 +4,20 @@ import A11yInfoProvider from '../A11yInfoProvider'
4
4
  import ViewportProvider from '../ViewportProvider'
5
5
  import ThemeProvider from '../ThemeProvider'
6
6
 
7
- const BaseProvider = ({ defaultTheme, children }) => (
7
+ const BaseProvider = ({ defaultTheme, children, themeOptions }) => (
8
8
  <A11yInfoProvider>
9
9
  <ViewportProvider>
10
- <ThemeProvider defaultTheme={defaultTheme}>{children}</ThemeProvider>
10
+ <ThemeProvider defaultTheme={defaultTheme} themeOptions={themeOptions}>
11
+ {children}
12
+ </ThemeProvider>
11
13
  </ViewportProvider>
12
14
  </A11yInfoProvider>
13
15
  )
14
16
 
15
17
  BaseProvider.propTypes = {
18
+ children: PropTypes.node.isRequired,
16
19
  defaultTheme: ThemeProvider.propTypes?.defaultTheme,
17
- children: PropTypes.node.isRequired
20
+ themeOptions: PropTypes.shape({ forceAbsoluteFontSizing: PropTypes.bool })
18
21
  }
19
22
 
20
23
  export default BaseProvider
@@ -2,7 +2,7 @@ import React, { forwardRef } from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import { Pressable, View, StyleSheet, Platform } from 'react-native'
4
4
 
5
- import { applyTextStyles, applyShadowToken, applyOuterBorder } from '../ThemeProvider/utils'
5
+ import { applyTextStyles, applyShadowToken, applyOuterBorder, useTheme } from '../ThemeProvider'
6
6
  import buttonPropTypes from './propTypes'
7
7
  import {
8
8
  a11yProps,
@@ -121,13 +121,17 @@ const selectBorderStyles = ({ borderColor, borderWidth, borderRadius }) => ({
121
121
  borderRadius
122
122
  })
123
123
 
124
- const selectTextStyles = ({ fontSize, color, lineHeight, fontName, fontWeight, textAlign }) =>
124
+ const selectTextStyles = (
125
+ { fontSize, color, lineHeight, fontName, fontWeight, textAlign },
126
+ themeOptions
127
+ ) =>
125
128
  applyTextStyles({
126
129
  fontSize,
127
130
  color,
128
131
  lineHeight,
129
132
  fontName,
130
133
  fontWeight,
134
+ themeOptions,
131
135
  textAlign
132
136
  })
133
137
 
@@ -174,6 +178,7 @@ const ButtonBase = forwardRef(
174
178
  selectOuterWidthStyles(themeTokens)
175
179
  ]
176
180
  }
181
+ const { themeOptions } = useTheme()
177
182
 
178
183
  return (
179
184
  <Pressable
@@ -189,7 +194,7 @@ const ButtonBase = forwardRef(
189
194
  const themeTokens = resolveButtonTokens(pressableState)
190
195
  const containerStyles = selectInnerContainerStyles(themeTokens)
191
196
  const borderStyles = selectBorderStyles(themeTokens)
192
- const textStyles = [selectTextStyles(themeTokens), staticStyles.text]
197
+ const textStyles = [selectTextStyles(themeTokens, themeOptions), staticStyles.text]
193
198
 
194
199
  // If the container has a width set, fill it instead of sizing from content.
195
200
  // If in future we support text alignments other than center, add here.
@@ -16,10 +16,8 @@ import {
16
16
  import { useA11yInfo } from '../A11yInfoProvider'
17
17
  import { CarouselProvider } from './CarouselContext'
18
18
  import CarouselItem from './CarouselItem'
19
- import StepTracker from '../StepTracker'
20
- import StackView from '../StackView'
21
19
  import IconButton from '../IconButton'
22
-
20
+ import CarouselStepTracker from './CarouselStepTracker/CarouselStepTracker'
23
21
  import dictionary from './dictionary'
24
22
 
25
23
  const staticStyles = StyleSheet.create({
@@ -33,19 +31,6 @@ const staticStyles = StyleSheet.create({
33
31
  }
34
32
  })
35
33
 
36
- const staticTokens = {
37
- stackView: {
38
- justifyContent: 'center'
39
- },
40
- stepTracker: {
41
- showStepLabel: false,
42
- showStepTrackerLabel: true,
43
- knobCompletedBackgroundColor: 'none',
44
- connectorCompletedColor: 'none',
45
- connectorColor: 'none'
46
- }
47
- }
48
-
49
34
  const selectContainerStyles = (width) => ({
50
35
  backgroundColor: 'transparent',
51
36
  overflow: 'hidden',
@@ -161,7 +146,7 @@ const Carousel = React.forwardRef(
161
146
  onAnimationEnd,
162
147
  onIndexChanged,
163
148
  springConfig = undefined,
164
- onRenderPanelNavigation,
149
+ panelNavigation = <CarouselStepTracker />,
165
150
  tag = 'ul',
166
151
  accessibilityRole = 'adjustable',
167
152
  accessibilityLabel = 'carousel',
@@ -171,16 +156,16 @@ const Carousel = React.forwardRef(
171
156
  ref
172
157
  ) => {
173
158
  const viewport = useViewport()
159
+ const themeTokens = useThemeTokens('Carousel', tokens, variant, {
160
+ viewport
161
+ })
174
162
  const {
175
163
  previousIcon,
176
164
  nextIcon,
177
165
  showPreviousNextNavigation,
178
166
  showPanelNavigation,
179
- spaceBetweenSlideAndPreviousNextNavigation,
180
- spaceBetweenSlideAndPanelNavigation
181
- } = useThemeTokens('Carousel', tokens, variant, {
182
- viewport
183
- })
167
+ spaceBetweenSlideAndPreviousNextNavigation
168
+ } = themeTokens
184
169
  const [activeIndex, setActiveIndex] = React.useState(0)
185
170
 
186
171
  const [isAnimating, setIsAnimating] = React.useState(false)
@@ -225,10 +210,6 @@ const Carousel = React.forwardRef(
225
210
  const animatedY = React.useRef(0)
226
211
  const isFirstSlide = !activeIndex
227
212
  const isLastSlide = activeIndex + 1 >= children.length
228
- const panelNavigationTokens = {
229
- ...staticTokens.stepTracker,
230
- containerPaddingTop: spaceBetweenSlideAndPanelNavigation
231
- }
232
213
 
233
214
  const onContainerLayout = ({
234
215
  nativeEvent: {
@@ -405,15 +386,18 @@ const Carousel = React.forwardRef(
405
386
  // Related discussion - https://github.com/telus/universal-design-system/issues/1549
406
387
  const previousNextIconButtonVariants = { size: previousNextIconSize, raised: true }
407
388
 
408
- const getCopyWithPlaceholders = (copyKey) => {
409
- const copyText = getCopy(copyKey)
410
- .replace(/%\{itemLabel\}/g, itemLabel)
411
- .replace(/%\{stepNumber\}/g, activeIndex + 1)
412
- .replace(/%\{stepCount\}/g, childrenArray.length)
389
+ const getCopyWithPlaceholders = React.useCallback(
390
+ (copyKey) => {
391
+ const copyText = getCopy(copyKey)
392
+ .replace(/%\{itemLabel\}/g, itemLabel)
393
+ .replace(/%\{stepNumber\}/g, activeIndex + 1)
394
+ .replace(/%\{stepCount\}/g, childrenArray.length)
413
395
 
414
- // First word might be a lowercase placeholder: capitalize the first letter
415
- return `${copyText[0].toUpperCase()}${copyText.slice(1)}`
416
- }
396
+ // First word might be a lowercase placeholder: capitalize the first letter
397
+ return `${copyText[0].toUpperCase()}${copyText.slice(1)}`
398
+ },
399
+ [activeIndex, childrenArray.length, itemLabel, getCopy]
400
+ )
417
401
 
418
402
  return (
419
403
  <CarouselProvider
@@ -421,6 +405,8 @@ const Carousel = React.forwardRef(
421
405
  totalItems={childrenArray.length}
422
406
  width={containerLayout.width}
423
407
  goTo={goTo}
408
+ getCopyWithPlaceholders={getCopyWithPlaceholders}
409
+ themeTokens={themeTokens}
424
410
  >
425
411
  <View style={staticStyles.root} onLayout={onContainerLayout} ref={ref} {...systemProps}>
426
412
  {showPreviousNextNavigation && (
@@ -490,24 +476,7 @@ const Carousel = React.forwardRef(
490
476
  </View>
491
477
  )}
492
478
  </View>
493
- {showPanelNavigation ? (
494
- <StackView direction="row" tokens={staticTokens.stackView}>
495
- {onRenderPanelNavigation ? (
496
- onRenderPanelNavigation({ activeIndex, totalItems: childrenArray.length })
497
- ) : (
498
- <StepTracker
499
- current={activeIndex}
500
- steps={childrenArray.map((_, index) => String(index))}
501
- copy={{
502
- // Give StepTracker copy from Carousel's language and dictionary
503
- stepLabel: getCopyWithPlaceholders('stepLabel'),
504
- stepTrackerLabel: getCopyWithPlaceholders('stepTrackerLabel')
505
- }}
506
- tokens={panelNavigationTokens}
507
- />
508
- )}
509
- </StackView>
510
- ) : null}
479
+ {showPanelNavigation ? panelNavigation : null}
511
480
  </CarouselProvider>
512
481
  )
513
482
  }
@@ -569,20 +538,20 @@ Carousel.propTypes = {
569
538
  */
570
539
  onIndexChanged: PropTypes.func,
571
540
  /**
572
- * Use this to render a custom panel navigation element instead of dots navigation
573
- * This function is also provided with an object with the following properties
574
- * activeIndex: index of current slide
575
- * totalItems: total number of slides
541
+ * Use this to render a custom panel navigation element instead of the default StepTracker's based navigation
542
+ * You can make use of `useCarousel` within your custom panel navigation component to hook into various Carousel states such as:
543
+ * - activeIndex: index of current slide
544
+ * - totalItems: total number of slides
576
545
  * Use it as follows:
577
546
  * ```js
578
547
  * <Carousel
579
- * onRenderPanelNavigation={({ totalItems, activeIndex }) => <Text>Showing {activeIndex + 1}</Text>}
548
+ * panelNavigation={<CustomPanelNavigation />}
580
549
  * >
581
550
  * <Carousel.Item>First Slide</Carousel.Item>
582
551
  * </Carousel>
583
552
  * ```
584
553
  */
585
- onRenderPanelNavigation: PropTypes.func,
554
+ panelNavigation: PropTypes.element,
586
555
  /**
587
556
  * When slide animation start
588
557
  * This function is also provided with a parameter indicating the current slide index before animation starts
@@ -1,12 +1,21 @@
1
1
  import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
+ import { getTokensPropType } from '../utils'
3
4
 
4
5
  const CarouselContext = React.createContext()
5
6
 
6
- const CarouselProvider = ({ children, activeIndex, totalItems, width, goTo }) => {
7
+ const CarouselProvider = ({
8
+ children,
9
+ activeIndex,
10
+ totalItems,
11
+ width,
12
+ goTo,
13
+ getCopyWithPlaceholders,
14
+ themeTokens
15
+ }) => {
7
16
  const value = React.useMemo(
8
- () => ({ activeIndex, totalItems, width, goTo }),
9
- [activeIndex, totalItems, width, goTo]
17
+ () => ({ activeIndex, totalItems, width, goTo, getCopyWithPlaceholders, themeTokens }),
18
+ [activeIndex, totalItems, width, goTo, getCopyWithPlaceholders, themeTokens]
10
19
  )
11
20
  return <CarouselContext.Provider value={value}>{children}</CarouselContext.Provider>
12
21
  }
@@ -24,7 +33,9 @@ CarouselProvider.propTypes = {
24
33
  activeIndex: PropTypes.number.isRequired,
25
34
  totalItems: PropTypes.number.isRequired,
26
35
  width: PropTypes.number.isRequired,
27
- goTo: PropTypes.func.isRequired
36
+ goTo: PropTypes.func.isRequired,
37
+ getCopyWithPlaceholders: PropTypes.func.isRequired,
38
+ themeTokens: getTokensPropType('Carousel')
28
39
  }
29
40
 
30
41
  export { CarouselProvider, useCarousel }
@@ -0,0 +1,36 @@
1
+ import React from 'react'
2
+ import { useCarousel } from '../CarouselContext'
3
+ import StepTracker from '../../StepTracker'
4
+ import StackView from '../../StackView'
5
+
6
+ const CarouselStepTracker = () => {
7
+ const { activeIndex, totalItems, getCopyWithPlaceholders, themeTokens } = useCarousel()
8
+ const stackViewTokens = {
9
+ justifyContent: 'center'
10
+ }
11
+ const stepTrackerTokens = {
12
+ showStepLabel: false,
13
+ showStepTrackerLabel: true,
14
+ knobCompletedBackgroundColor: 'none',
15
+ connectorCompletedColor: 'none',
16
+ connectorColor: 'none',
17
+ containerPaddingTop: themeTokens.spaceBetweenSlideAndPanelNavigation
18
+ }
19
+ const steps = Array.from(Array(totalItems)).map((_, index) => String(index))
20
+ return (
21
+ <StackView direction="row" tokens={stackViewTokens}>
22
+ <StepTracker
23
+ current={activeIndex}
24
+ steps={steps}
25
+ copy={{
26
+ // Give StepTracker copy from Carousel's language and dictionary
27
+ stepLabel: getCopyWithPlaceholders('stepLabel'),
28
+ stepTrackerLabel: getCopyWithPlaceholders('stepTrackerLabel')
29
+ }}
30
+ tokens={stepTrackerTokens}
31
+ />
32
+ </StackView>
33
+ )
34
+ }
35
+
36
+ export default CarouselStepTracker
@@ -0,0 +1,3 @@
1
+ import CarouselStepTracker from './CarouselStepTracker'
2
+
3
+ export default CarouselStepTracker
@@ -6,7 +6,12 @@ import CheckboxInput from './CheckboxInput'
6
6
  import CheckboxLabel from '../InputLabel/LabelContent'
7
7
  import Feedback from '../Feedback'
8
8
  import StackView from '../StackView'
9
- import { applyShadowToken, applyTextStyles, useThemeTokensCallback } from '../ThemeProvider'
9
+ import {
10
+ applyShadowToken,
11
+ applyTextStyles,
12
+ useTheme,
13
+ useThemeTokensCallback
14
+ } from '../ThemeProvider'
10
15
  import {
11
16
  a11yProps,
12
17
  focusHandlerProps,
@@ -54,21 +59,18 @@ const selectInputStyles = (
54
59
  }
55
60
  })
56
61
  })
57
- const selectLabelStyles = ({
58
- labelColor,
59
- labelFontName,
60
- labelFontSize,
61
- labelFontWeight,
62
- labelMarginLeft,
63
- labelLineHeight
64
- }) => ({
62
+ const selectLabelStyles = (
63
+ { labelColor, labelFontName, labelFontSize, labelFontWeight, labelMarginLeft, labelLineHeight },
64
+ themeOptions
65
+ ) => ({
65
66
  marginLeft: labelMarginLeft,
66
67
  ...applyTextStyles({
67
68
  color: labelColor,
68
69
  fontName: labelFontName,
69
70
  fontWeight: labelFontWeight,
70
71
  fontSize: labelFontSize,
71
- lineHeight: labelLineHeight
72
+ lineHeight: labelLineHeight,
73
+ themeOptions
72
74
  })
73
75
  })
74
76
  const selectIconTokens = ({ icon, iconColor, iconSize }) => ({
@@ -172,6 +174,7 @@ const Checkbox = forwardRef(
172
174
  }
173
175
  const uniqueId = useUniqueId('checkbox')
174
176
  const inputId = id ?? uniqueId
177
+ const { themeOptions } = useTheme()
175
178
 
176
179
  return (
177
180
  <View style={staticStyles.wrapper} ref={ref}>
@@ -187,7 +190,7 @@ const Checkbox = forwardRef(
187
190
  {({ focused: focus, hovered: hover, pressed }) => {
188
191
  const { icon: IconComponent, ...stateTokens } = getTokens({ focus, hover, pressed })
189
192
  const iconTokens = selectIconTokens(stateTokens)
190
- const labelStyles = selectLabelStyles(stateTokens)
193
+ const labelStyles = selectLabelStyles(stateTokens, themeOptions)
191
194
  const alignWithLabel = label
192
195
  ? [staticStyles.alignWithLabel, { height: labelStyles.lineHeight }]
193
196
  : null