@telus-uds/components-base 1.12.0 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/CHANGELOG.md +41 -2
  2. package/component-docs.json +933 -55
  3. package/lib/BaseProvider/index.js +7 -2
  4. package/lib/Button/ButtonBase.js +52 -19
  5. package/lib/Button/ButtonGroup.js +7 -0
  6. package/lib/Button/propTypes.js +18 -0
  7. package/lib/Carousel/Carousel.js +83 -58
  8. package/lib/Carousel/CarouselContext.js +22 -8
  9. package/lib/Carousel/CarouselFirstFocus/CarouselFirstFocus.js +73 -0
  10. package/lib/Carousel/CarouselStepTracker/CarouselStepTracker.js +56 -0
  11. package/lib/Carousel/CarouselStepTracker/index.js +13 -0
  12. package/lib/Carousel/CarouselTabs/CarouselTabs.js +70 -0
  13. package/lib/Carousel/CarouselTabs/CarouselTabsPanel.js +95 -0
  14. package/lib/Carousel/CarouselTabs/CarouselTabsPanelItem.js +148 -0
  15. package/lib/Carousel/CarouselTabs/index.js +13 -0
  16. package/lib/Carousel/CarouselThumbnail.js +99 -0
  17. package/lib/Carousel/CarouselThumbnailNavigation.js +87 -0
  18. package/lib/Carousel/dictionary.js +4 -2
  19. package/lib/Carousel/index.js +10 -1
  20. package/lib/Checkbox/Checkbox.js +7 -3
  21. package/lib/Checkbox/CheckboxGroup.js +8 -1
  22. package/lib/Feedback/Feedback.js +18 -10
  23. package/lib/Icon/IconText.js +6 -1
  24. package/lib/InputLabel/InputLabel.js +11 -5
  25. package/lib/Link/InlinePressable.js +1 -8
  26. package/lib/Link/LinkBase.js +13 -10
  27. package/lib/List/ListItem.js +8 -4
  28. package/lib/Notification/Notification.js +44 -24
  29. package/lib/Pagination/Pagination.js +7 -3
  30. package/lib/Radio/RadioGroup.js +8 -0
  31. package/lib/RadioCard/RadioCard.js +6 -1
  32. package/lib/RadioCard/RadioCardGroup.js +7 -0
  33. package/lib/Select/Select.js +7 -3
  34. package/lib/SkipLink/SkipLink.js +216 -0
  35. package/lib/SkipLink/index.js +13 -0
  36. package/lib/StepTracker/Step.js +8 -4
  37. package/lib/StepTracker/StepTracker.js +7 -3
  38. package/lib/Tabs/TabsItem.js +4 -0
  39. package/lib/TextInput/TextInputBase.js +7 -3
  40. package/lib/ThemeProvider/ThemeProvider.js +25 -3
  41. package/lib/ThemeProvider/utils/styles.js +8 -1
  42. package/lib/ThemeProvider/utils/theme-tokens.js +1 -1
  43. package/lib/ToggleSwitch/ToggleSwitchGroup.js +7 -0
  44. package/lib/Typography/Typography.js +6 -2
  45. package/lib/index.js +9 -0
  46. package/lib-module/BaseProvider/index.js +7 -2
  47. package/lib-module/Button/ButtonBase.js +41 -9
  48. package/lib-module/Button/ButtonGroup.js +7 -0
  49. package/lib-module/Button/propTypes.js +17 -0
  50. package/lib-module/Carousel/Carousel.js +80 -57
  51. package/lib-module/Carousel/CarouselContext.js +21 -8
  52. package/lib-module/Carousel/CarouselFirstFocus/CarouselFirstFocus.js +51 -0
  53. package/lib-module/Carousel/CarouselStepTracker/CarouselStepTracker.js +42 -0
  54. package/lib-module/Carousel/CarouselStepTracker/index.js +2 -0
  55. package/lib-module/Carousel/CarouselTabs/CarouselTabs.js +50 -0
  56. package/lib-module/Carousel/CarouselTabs/CarouselTabsPanel.js +76 -0
  57. package/lib-module/Carousel/CarouselTabs/CarouselTabsPanelItem.js +126 -0
  58. package/lib-module/Carousel/CarouselTabs/index.js +2 -0
  59. package/lib-module/Carousel/CarouselThumbnail.js +85 -0
  60. package/lib-module/Carousel/CarouselThumbnailNavigation.js +66 -0
  61. package/lib-module/Carousel/dictionary.js +4 -2
  62. package/lib-module/Carousel/index.js +2 -1
  63. package/lib-module/Checkbox/Checkbox.js +8 -4
  64. package/lib-module/Checkbox/CheckboxGroup.js +8 -1
  65. package/lib-module/Feedback/Feedback.js +19 -11
  66. package/lib-module/Icon/IconText.js +6 -1
  67. package/lib-module/InputLabel/InputLabel.js +12 -6
  68. package/lib-module/Link/InlinePressable.js +1 -8
  69. package/lib-module/Link/LinkBase.js +14 -11
  70. package/lib-module/List/ListItem.js +9 -5
  71. package/lib-module/Notification/Notification.js +46 -26
  72. package/lib-module/Pagination/Pagination.js +8 -4
  73. package/lib-module/Radio/RadioGroup.js +8 -0
  74. package/lib-module/RadioCard/RadioCard.js +7 -2
  75. package/lib-module/RadioCard/RadioCardGroup.js +7 -0
  76. package/lib-module/Select/Select.js +8 -4
  77. package/lib-module/SkipLink/SkipLink.js +188 -0
  78. package/lib-module/SkipLink/index.js +2 -0
  79. package/lib-module/StepTracker/Step.js +9 -5
  80. package/lib-module/StepTracker/StepTracker.js +8 -4
  81. package/lib-module/Tabs/TabsItem.js +5 -1
  82. package/lib-module/TextInput/TextInputBase.js +8 -4
  83. package/lib-module/ThemeProvider/ThemeProvider.js +24 -3
  84. package/lib-module/ThemeProvider/utils/styles.js +8 -1
  85. package/lib-module/ThemeProvider/utils/theme-tokens.js +1 -1
  86. package/lib-module/ToggleSwitch/ToggleSwitchGroup.js +7 -0
  87. package/lib-module/Typography/Typography.js +7 -3
  88. package/lib-module/index.js +1 -0
  89. package/package.json +46 -47
  90. package/src/BaseProvider/index.jsx +6 -3
  91. package/src/Button/ButtonBase.jsx +36 -12
  92. package/src/Button/ButtonGroup.jsx +6 -0
  93. package/src/Button/propTypes.js +14 -0
  94. package/src/Carousel/Carousel.jsx +91 -64
  95. package/src/Carousel/CarouselContext.jsx +29 -5
  96. package/src/Carousel/CarouselFirstFocus/CarouselFirstFocus.jsx +49 -0
  97. package/src/Carousel/CarouselStepTracker/CarouselStepTracker.jsx +36 -0
  98. package/src/Carousel/CarouselStepTracker/index.js +3 -0
  99. package/src/Carousel/CarouselTabs/CarouselTabs.jsx +37 -0
  100. package/src/Carousel/CarouselTabs/CarouselTabsPanel.jsx +69 -0
  101. package/src/Carousel/CarouselTabs/CarouselTabsPanelItem.jsx +119 -0
  102. package/src/Carousel/CarouselTabs/index.js +3 -0
  103. package/src/Carousel/CarouselThumbnail.jsx +77 -0
  104. package/src/Carousel/CarouselThumbnailNavigation.jsx +53 -0
  105. package/src/Carousel/dictionary.js +4 -2
  106. package/src/Carousel/index.js +1 -0
  107. package/src/Checkbox/Checkbox.jsx +14 -11
  108. package/src/Checkbox/CheckboxGroup.jsx +8 -1
  109. package/src/Feedback/Feedback.jsx +14 -7
  110. package/src/Icon/IconText.jsx +3 -1
  111. package/src/InputLabel/InputLabel.jsx +13 -12
  112. package/src/Link/InlinePressable.jsx +2 -8
  113. package/src/Link/LinkBase.jsx +18 -21
  114. package/src/List/ListItem.jsx +10 -5
  115. package/src/Notification/Notification.jsx +40 -23
  116. package/src/Pagination/Pagination.jsx +6 -4
  117. package/src/Radio/RadioGroup.jsx +7 -0
  118. package/src/RadioCard/RadioCard.jsx +3 -2
  119. package/src/RadioCard/RadioCardGroup.jsx +6 -0
  120. package/src/Select/Select.jsx +12 -3
  121. package/src/SkipLink/SkipLink.jsx +179 -0
  122. package/src/SkipLink/index.js +3 -0
  123. package/src/StepTracker/Step.jsx +12 -4
  124. package/src/StepTracker/StepTracker.jsx +11 -10
  125. package/src/Tabs/TabsItem.jsx +3 -2
  126. package/src/TextInput/TextInputBase.jsx +11 -3
  127. package/src/ThemeProvider/ThemeProvider.jsx +22 -3
  128. package/src/ThemeProvider/utils/styles.js +9 -1
  129. package/src/ThemeProvider/utils/theme-tokens.js +1 -1
  130. package/src/ToggleSwitch/ToggleSwitchGroup.jsx +6 -0
  131. package/src/Typography/Typography.jsx +11 -12
  132. package/src/index.js +1 -0
@@ -11,7 +11,7 @@ import {
11
11
  viewProps,
12
12
  withLinkRouter
13
13
  } from '../utils'
14
- import { applyTextStyles, useThemeTokens } from '../ThemeProvider'
14
+ import { applyTextStyles, useTheme, useThemeTokens } from '../ThemeProvider'
15
15
  import { useViewport } from '../ViewportProvider'
16
16
  import Box from '../Box'
17
17
 
@@ -21,13 +21,14 @@ import SideButton from './SideButton'
21
21
 
22
22
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
23
23
 
24
- const selectTextStyles = ({ color, fontName, fontSize, fontWeight, lineHeight }) =>
24
+ const selectTextStyles = ({ color, fontName, fontSize, fontWeight, lineHeight }, themeOptions) =>
25
25
  applyTextStyles({
26
26
  color,
27
27
  fontName,
28
28
  fontSize,
29
29
  fontWeight,
30
- lineHeight
30
+ lineHeight,
31
+ themeOptions
31
32
  })
32
33
 
33
34
  const Pagination = forwardRef(
@@ -49,6 +50,7 @@ const Pagination = forwardRef(
49
50
  const { truncateAbove, gap, ...themeTokens } = useThemeTokens('Pagination', tokens, variant, {
50
51
  viewport
51
52
  })
53
+ const { themeOptions } = useTheme()
52
54
 
53
55
  const items = React.Children.toArray(children)
54
56
 
@@ -66,7 +68,7 @@ const Pagination = forwardRef(
66
68
  truncateAbove
67
69
  })
68
70
 
69
- const ellipsisTextStyles = selectTextStyles(themeTokens)
71
+ const ellipsisTextStyles = selectTextStyles(themeTokens, themeOptions)
70
72
 
71
73
  if (items.length === 0) {
72
74
  return null
@@ -84,6 +84,7 @@ const RadioGroup = forwardRef(
84
84
  legend,
85
85
  tooltip,
86
86
  hint,
87
+ hintPosition = 'inline',
87
88
  validation,
88
89
  feedback,
89
90
  initialCheckedId,
@@ -125,6 +126,7 @@ const RadioGroup = forwardRef(
125
126
 
126
127
  return (
127
128
  <Radio
129
+ error={validation === 'error'}
128
130
  ref={itemRef}
129
131
  key={radioId}
130
132
  id={radioId}
@@ -149,6 +151,7 @@ const RadioGroup = forwardRef(
149
151
  legend={legend}
150
152
  tooltip={tooltip}
151
153
  hint={hint}
154
+ hintPosition={hintPosition}
152
155
  space={fieldSpace}
153
156
  feedback={feedback}
154
157
  inactive={inactive}
@@ -201,6 +204,10 @@ RadioGroup.propTypes = {
201
204
  * Optional additional text giving more detail to help a user make a choice.
202
205
  */
203
206
  hint: PropTypes.string,
207
+ /**
208
+ * Position of the hint relative to label. Use `below` to display a larger hint below the label.
209
+ */
210
+ hintPosition: PropTypes.oneOf(['inline', 'below']),
204
211
  /**
205
212
  * Optional tooltip text content to include alongside the legend and hint.
206
213
  */
@@ -2,7 +2,7 @@ import React, { forwardRef } from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import { StyleSheet, Text, View } from 'react-native'
4
4
 
5
- import { useThemeTokensCallback, applyTextStyles } from '../ThemeProvider'
5
+ import { applyTextStyles, useTheme, useThemeTokensCallback } from '../ThemeProvider'
6
6
  import {
7
7
  a11yProps,
8
8
  focusHandlerProps,
@@ -96,6 +96,7 @@ const RadioCard = forwardRef(
96
96
 
97
97
  const getTokens = useThemeTokensCallback('RadioCard', tokens, variant)
98
98
  const getCardTokens = (cardState) => selectPressableCardTokens(getTokens(cardState))
99
+ const { themeOptions } = useTheme()
99
100
 
100
101
  return (
101
102
  <PressableCardBase
@@ -112,7 +113,7 @@ const RadioCard = forwardRef(
112
113
  const { radioSpace, contentSpace, ...themeTokens } = getTokens(cardState)
113
114
  const radioTokens = selectRadioButtonTokens(themeTokens, 'radio')
114
115
  const titleTokens = selectTokens('Typography', themeTokens)
115
- const textStyle = applyTextStyles(titleTokens)
116
+ const textStyle = applyTextStyles({ ...titleTokens, themeOptions })
116
117
  return (
117
118
  <StackView direction="row" space={radioSpace}>
118
119
  <View style={[staticStyles.alignWithText, { height: textStyle.lineHeight }]}>
@@ -85,6 +85,7 @@ const RadioCardGroup = forwardRef(
85
85
  legend,
86
86
  tooltip,
87
87
  hint,
88
+ hintPosition = 'inline',
88
89
  validation,
89
90
  feedback,
90
91
  initialCheckedId,
@@ -127,6 +128,7 @@ const RadioCardGroup = forwardRef(
127
128
  legend={legend}
128
129
  tooltip={tooltip}
129
130
  hint={hint}
131
+ hintPosition={hintPosition}
130
132
  space={fieldSpace}
131
133
  feedback={feedback}
132
134
  inactive={inactive || readOnly}
@@ -208,6 +210,10 @@ RadioCardGroup.propTypes = {
208
210
  * Optional additional text giving more detail to help a user make a choice.
209
211
  */
210
212
  hint: PropTypes.string,
213
+ /**
214
+ * Position of the hint relative to label. Use `below` to display a larger hint below the label.
215
+ */
216
+ hintPosition: PropTypes.oneOf(['inline', 'below']),
211
217
  /**
212
218
  * Optional tooltip text content to include alongside the legend and hint.
213
219
  */
@@ -2,7 +2,7 @@ import React, { forwardRef, useState } from 'react'
2
2
 
3
3
  import { View, Platform, StyleSheet } from 'react-native'
4
4
  import PropTypes from 'prop-types'
5
- import { applyTextStyles, useThemeTokens, applyOuterBorder } from '../ThemeProvider'
5
+ import { applyTextStyles, useThemeTokens, applyOuterBorder, useTheme } from '../ThemeProvider'
6
6
  import {
7
7
  a11yProps,
8
8
  componentPropType,
@@ -43,6 +43,7 @@ const selectInputStyles = (
43
43
  validationIconSize = 0,
44
44
  height
45
45
  },
46
+ themeOptions,
46
47
  inactive
47
48
  ) => {
48
49
  // Subtract border width from padding so overall input width/height doesn't
@@ -50,7 +51,13 @@ const selectInputStyles = (
50
51
  const offsetBorder = (value) =>
51
52
  typeof value === 'number' ? Math.max(0, value - borderWidth) : value
52
53
 
53
- const textStyles = applyTextStyles({ fontName, fontSize, lineHeight, fontWeight })
54
+ const textStyles = applyTextStyles({
55
+ fontName,
56
+ fontSize,
57
+ lineHeight,
58
+ fontWeight,
59
+ themeOptions
60
+ })
54
61
 
55
62
  const webStyles = Platform.select({
56
63
  web: {
@@ -205,13 +212,15 @@ const Select = forwardRef(
205
212
 
206
213
  const { icon: IconComponent, validationIcon: ValidationIconComponent } = themeTokens
207
214
 
215
+ const { themeOptions } = useTheme()
216
+
208
217
  return (
209
218
  <InputSupports {...supportsProps} {...selectedProps}>
210
219
  {({ inputId, ...props }) => (
211
220
  <View style={selectOuterBorderStyles(themeTokens)}>
212
221
  <Picker
213
222
  ref={ref}
214
- style={selectInputStyles(themeTokens, inactive)}
223
+ style={selectInputStyles(themeTokens, themeOptions, inactive)}
215
224
  onFocus={handleFocus}
216
225
  onBlur={handleBlur}
217
226
  onMouseOver={handleMouseOver}
@@ -0,0 +1,179 @@
1
+ import React, { forwardRef } from 'react'
2
+ import { Platform, Pressable, StyleSheet, Text } from 'react-native'
3
+ import PropTypes from 'prop-types'
4
+
5
+ import { useThemeTokensCallback } from '../ThemeProvider'
6
+ import {
7
+ a11yProps,
8
+ clickProps,
9
+ getTokensPropType,
10
+ linkProps,
11
+ resolvePressableTokens,
12
+ selectSystemProps,
13
+ variantProp,
14
+ withLinkRouter
15
+ } from '../utils'
16
+
17
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, linkProps])
18
+
19
+ // ensure explicit selection of tokens
20
+ const selectStyles = ({
21
+ backgroundColor,
22
+ outlineColor,
23
+ outlineOffset,
24
+ outlineStyle,
25
+ outlineWidth,
26
+ paddingHorizontal,
27
+ paddingVertical,
28
+ borderRadius
29
+ }) => ({
30
+ backgroundColor,
31
+ outlineColor,
32
+ outlineOffset,
33
+ outlineStyle,
34
+ outlineWidth,
35
+ paddingHorizontal,
36
+ paddingVertical,
37
+ borderRadius
38
+ })
39
+
40
+ const selectTextStyles = ({ color }) => ({
41
+ color
42
+ })
43
+
44
+ /**
45
+ * A generic Skip link component, unstyled by default.
46
+ * A Skip link component help keyboard-only users, screen reader users to skip
47
+ * sections and navigate to the content they want.
48
+ *
49
+ * ## Component API
50
+ *
51
+ * For common uses, pass a `href` that is a # link to a DOM id that can be skipped to (web only).
52
+ *
53
+ * The element with this ID should be focusable, e.g. `<Box nativeID="skip-target" focusable>`.
54
+ *
55
+ * Other custom behaviour may be set by passing an `onPress` function, and routers may be integrated
56
+ * in the same way as other navigation-related components by passing a `LinkRouter`; but a # anchor
57
+ * href on web and/or a `targetRef` for cross-platform applications is the recommended approach.
58
+ *
59
+ * ## Visible styling
60
+ *
61
+ * When focused, the skip link shows as a visible element similar to a simplified ButtonLink using
62
+ * UDS theming. The `tokens` prop may be used to override these styles.
63
+ *
64
+ * To control the background of a skip link, the following tokens can be used:
65
+ *
66
+ * - `backgroundColor`
67
+ * *
68
+ * In order to control the color of the skip link text, the following tokens can be used:
69
+ *
70
+ * - `color`
71
+ *
72
+ * ### Padding
73
+ *
74
+ * The following padding tokens can be used:
75
+ *
76
+ * - `paddingHorizontal`
77
+ * - `paddingVertical`
78
+ *
79
+ * ### Outline
80
+ *
81
+ * The following tokens to control the outline:
82
+ *
83
+ * - `outlineColor`
84
+ * - `outlineOffset`
85
+ * - `outlineStyle`
86
+ * - `outlineWidth`
87
+ *
88
+ * ## Usability and A11y guidelines
89
+ *
90
+ * - The skip link component is visually hidden until a keyboard press activates it.
91
+ * - Usually, you should place the skip link immediately after the opening <body> tag.
92
+ * - This lets users bypass top-level navigation links and jump to the main content on a page.
93
+ * - Also consider using SkipLink before a complex feature containing many focusable elements.
94
+ *
95
+ * ## Accessibility
96
+ *
97
+ * Skip link supports all the common a11y and link props.
98
+ */
99
+ const SkipLink = forwardRef(({ tokens, variant, href, children, ...rawRest }, ref) => {
100
+ const { onPress, ...rest } = clickProps.toPressProps(rawRest)
101
+
102
+ const getTokens = useThemeTokensCallback('SkipLink', tokens, variant)
103
+ const defaultTokens = getTokens()
104
+
105
+ const resolveLinkTokens = (pressState) => resolvePressableTokens(defaultTokens, pressState)
106
+
107
+ const handlePress = (event) => {
108
+ if (typeof onPress === 'function') onPress(event)
109
+ // TODO - support native apps with something based on refs and/or setAccessibilityFocus
110
+ }
111
+
112
+ return (
113
+ <Pressable
114
+ ref={ref}
115
+ accessibilityRole="link"
116
+ onPress={handlePress}
117
+ href={href}
118
+ style={({ focused: focus }) => {
119
+ const themeTokens = getTokens({ focus })
120
+ const skipLinkStyle = selectStyles(themeTokens)
121
+
122
+ return [staticStyles.absolute, skipLinkStyle, !focus && staticStyles.hidden]
123
+ }}
124
+ {...selectProps(rest)}
125
+ >
126
+ {(pressState) => {
127
+ const themeTokens = resolveLinkTokens(pressState)
128
+ const textStyles = selectTextStyles(themeTokens)
129
+
130
+ return <Text style={[textStyles, staticStyles.baseline]}>{children}</Text>
131
+ }}
132
+ </Pressable>
133
+ )
134
+ })
135
+
136
+ SkipLink.displayName = 'SkipLink'
137
+
138
+ SkipLink.propTypes = {
139
+ ...selectedSystemPropTypes,
140
+ /**
141
+ * The text content shown or read out when the SkipLink is focused, usually a string.
142
+ */
143
+ children: PropTypes.node,
144
+ /**
145
+ * The target to skip to. Usually an anchor link to a section id (e.g. href="#main-section").
146
+ */
147
+ href: PropTypes.string,
148
+ tokens: getTokensPropType('SkipLink'),
149
+ variant: variantProp.propType
150
+ }
151
+
152
+ const staticStyles = StyleSheet.create({
153
+ baseline: {
154
+ alignSelf: 'baseline'
155
+ },
156
+ absolute: {
157
+ margin: 0,
158
+ position: 'absolute',
159
+ top: 0,
160
+ left: 0
161
+ },
162
+ hidden: {
163
+ overflow: 'hidden',
164
+ ...Platform.select({
165
+ web: {
166
+ clip: 'rect(0 0 0 0)',
167
+ clipPath: 'inset(50%)'
168
+ },
169
+ default: {
170
+ // width / height of 0 would make it non-focusable
171
+ height: 1,
172
+ width: 1,
173
+ opacity: 0
174
+ }
175
+ })
176
+ }
177
+ })
178
+
179
+ export default withLinkRouter(SkipLink)
@@ -0,0 +1,3 @@
1
+ import SkipLink from './SkipLink'
2
+
3
+ export default SkipLink
@@ -4,7 +4,7 @@ import { StyleSheet, Text, View } from 'react-native'
4
4
  import StackView from '../StackView'
5
5
  import Icon from '../Icon'
6
6
  import { a11yProps, getTokensPropType, selectSystemProps, variantProp, viewProps } from '../utils'
7
- import { applyTextStyles } from '../ThemeProvider'
7
+ import { applyTextStyles, useTheme } from '../ThemeProvider'
8
8
 
9
9
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
10
10
 
@@ -95,6 +95,7 @@ const selectLabelStyles = (
95
95
  labelFontName,
96
96
  labelLineHeight
97
97
  },
98
+ themeOptions,
98
99
  isCurrent
99
100
  ) =>
100
101
  applyTextStyles({
@@ -102,7 +103,8 @@ const selectLabelStyles = (
102
103
  fontSize: labelFontSize,
103
104
  lineHeight: labelLineHeight,
104
105
  fontWeight: isCurrent ? labelCurrentFontWeight : labelFontWeight,
105
- fontName: labelFontName
106
+ fontName: labelFontName,
107
+ themeOptions
106
108
  })
107
109
  const getStepTestID = (isCompleted, isCurrent) => {
108
110
  let testID = 'StepTracker-Step'
@@ -125,6 +127,7 @@ const Step = ({ label, name, status = 0, stepCount = 0, stepIndex = 0, tokens, .
125
127
  const isCompleted = status > stepIndex
126
128
  const isCurrent = status === stepIndex
127
129
  const isActive = isCompleted || isCurrent
130
+ const { themeOptions } = useTheme()
128
131
 
129
132
  return (
130
133
  <StackView
@@ -158,7 +161,12 @@ const Step = ({ label, name, status = 0, stepCount = 0, stepIndex = 0, tokens, .
158
161
  {showStepLabel && (
159
162
  <View style={[staticStyles.stepLabelContainer, selectLabelContainerStyles(tokens)]}>
160
163
  {showStepName && (
161
- <Text style={[staticStyles.centeredText, selectLabelStyles(tokens, isCurrent)]}>
164
+ <Text
165
+ style={[
166
+ staticStyles.centeredText,
167
+ selectLabelStyles(tokens, themeOptions, isCurrent)
168
+ ]}
169
+ >
162
170
  {name}
163
171
  </Text>
164
172
  )}
@@ -167,7 +175,7 @@ const Step = ({ label, name, status = 0, stepCount = 0, stepIndex = 0, tokens, .
167
175
  style={[
168
176
  staticStyles.centeredText,
169
177
  tokens.labelDirection === 'column' && staticStyles.wrappingLabel,
170
- selectLabelStyles(tokens, isCurrent)
178
+ selectLabelStyles(tokens, themeOptions, isCurrent)
171
179
  ]}
172
180
  >
173
181
  {label}
@@ -2,7 +2,7 @@ import React, { forwardRef } from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import { StyleSheet, Text, View } from 'react-native'
4
4
  import StackView from '../StackView'
5
- import { applyTextStyles, useThemeTokens } from '../ThemeProvider'
5
+ import { applyTextStyles, useTheme, useThemeTokens } from '../ThemeProvider'
6
6
  import { a11yProps, getTokensPropType, selectSystemProps, variantProp, viewProps } from '../utils'
7
7
  import { useViewport } from '../ViewportProvider'
8
8
  import useCopy from '../utils/useCopy'
@@ -25,19 +25,17 @@ const selectContainerStyles = ({
25
25
  const selectStepTrackerLabelContainerStyles = ({ labelMarginTop }) => ({
26
26
  marginTop: labelMarginTop
27
27
  })
28
- const selectStepTrackerLabelStyles = ({
29
- labelColor,
30
- labelFontSize,
31
- labelFontWeight,
32
- labelFontName,
33
- labelLineHeight
34
- }) =>
28
+ const selectStepTrackerLabelStyles = (
29
+ { labelColor, labelFontSize, labelFontWeight, labelFontName, labelLineHeight },
30
+ themeOptions
31
+ ) =>
35
32
  applyTextStyles({
36
33
  color: labelColor,
37
34
  fontSize: labelFontSize,
38
35
  lineHeight: labelLineHeight,
39
36
  fontWeight: labelFontWeight,
40
- fontName: labelFontName
37
+ fontName: labelFontName,
38
+ themeOptions
41
39
  })
42
40
 
43
41
  /**
@@ -106,6 +104,7 @@ const StepTracker = forwardRef(
106
104
  : ''
107
105
  const getStepLabel = (index) =>
108
106
  themeTokens.showStepLabel ? getCopy('stepLabel').replace('%{stepNumber}', index + 1) : ''
107
+ const { themeOptions } = useTheme()
109
108
  if (!steps.length) return null
110
109
  const selectedProps = selectProps({
111
110
  accessibilityLabel: stepTrackerLabel,
@@ -145,7 +144,9 @@ const StepTracker = forwardRef(
145
144
  selectStepTrackerLabelContainerStyles(themeTokens)
146
145
  ]}
147
146
  >
148
- <Text style={selectStepTrackerLabelStyles(themeTokens)}>{stepTrackerLabel}</Text>
147
+ <Text style={selectStepTrackerLabelStyles(themeTokens, themeOptions)}>
148
+ {stepTrackerLabel}
149
+ </Text>
149
150
  </View>
150
151
  )}
151
152
  </StackView>
@@ -2,7 +2,7 @@ import React, { forwardRef, useEffect } from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import { Platform, Pressable, StyleSheet, Text, View } from 'react-native'
4
4
 
5
- import { applyTextStyles, useThemeTokensCallback } from '../ThemeProvider'
5
+ import { applyTextStyles, useTheme, useThemeTokensCallback } from '../ThemeProvider'
6
6
  import {
7
7
  a11yProps,
8
8
  clickProps,
@@ -97,7 +97,7 @@ const TabsItem = forwardRef(
97
97
  ) => {
98
98
  // Convert onClick etc to onPress etc if used in an integration
99
99
  const { onPress, ...rest } = clickProps.toPressProps(rawRest)
100
-
100
+ const { themeOptions } = useTheme()
101
101
  const getTokens = useThemeTokensCallback('TabsItem', tokens, variant)
102
102
  const resolveTokens = (pressableState) =>
103
103
  resolvePressableTokens(getTokens, pressableState, { selected })
@@ -165,6 +165,7 @@ const TabsItem = forwardRef(
165
165
  const containerStyles = selectContainerStyles(themeTokens)
166
166
  const textStyles = applyTextStyles({
167
167
  ...selectTokens('Typography', themeTokens),
168
+ themeOptions,
168
169
  textAlign
169
170
  })
170
171
 
@@ -2,7 +2,7 @@ import React, { forwardRef, useEffect, useState } from 'react'
2
2
  import { Platform, StyleSheet, TextInput as NativeTextInput, View } from 'react-native'
3
3
 
4
4
  import PropTypes from 'prop-types'
5
- import { applyTextStyles, useThemeTokens, applyOuterBorder } from '../ThemeProvider'
5
+ import { applyTextStyles, useTheme, useThemeTokens, applyOuterBorder } from '../ThemeProvider'
6
6
  import {
7
7
  a11yProps,
8
8
  getTokensPropType,
@@ -43,6 +43,7 @@ const selectInputStyles = (
43
43
  width,
44
44
  height
45
45
  },
46
+ themeOptions,
46
47
  inactive
47
48
  ) => {
48
49
  // Subtract border width from padding so overall input width/height doesn't
@@ -50,7 +51,13 @@ const selectInputStyles = (
50
51
  const offsetBorder = (value) =>
51
52
  typeof value === 'number' ? Math.max(0, value - borderWidth) : value
52
53
 
53
- const textStyles = applyTextStyles({ fontName, fontSize, lineHeight, fontWeight })
54
+ const textStyles = applyTextStyles({
55
+ fontName,
56
+ fontSize,
57
+ lineHeight,
58
+ fontWeight,
59
+ themeOptions
60
+ })
54
61
 
55
62
  function linesToHeight(lines) {
56
63
  const { lineHeight: absoluteLineHeight } = textStyles
@@ -197,7 +204,8 @@ const TextInputBase = forwardRef(
197
204
  value: isControlled ? currentValue : undefined
198
205
  }
199
206
 
200
- const nativeInputStyle = selectInputStyles({ ...themeTokens, height }, inactive)
207
+ const { themeOptions } = useTheme()
208
+ const nativeInputStyle = selectInputStyles({ ...themeTokens, height }, themeOptions, inactive)
201
209
 
202
210
  return (
203
211
  <View style={selectOuterBorderStyles(themeTokens)}>
@@ -1,13 +1,19 @@
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
 
5
6
  export const uninitialisedError = new Error('Theme context used outside of ThemeProvider')
6
7
 
7
8
  export const ThemeContext = createContext(uninitialisedError)
8
9
  export const ThemeSetterContext = createContext(uninitialisedError)
9
10
 
10
- const ThemeProvider = ({ children, defaultTheme }) => {
11
+ const ThemeProvider = ({
12
+ children,
13
+ defaultTheme,
14
+ // TODO: switch `forceAbsoluteFontSizing` to be false by default in the next major version
15
+ themeOptions = { forceAbsoluteFontSizing: true }
16
+ }) => {
11
17
  const [theme, setTheme] = useState(defaultTheme)
12
18
 
13
19
  // Validate the theme tokens version on every render.
@@ -17,7 +23,7 @@ const ThemeProvider = ({ children, defaultTheme }) => {
17
23
 
18
24
  return (
19
25
  <ThemeSetterContext.Provider value={setTheme}>
20
- <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>
26
+ <ThemeContext.Provider value={{ ...theme, themeOptions }}>{children}</ThemeContext.Provider>
21
27
  </ThemeSetterContext.Provider>
22
28
  )
23
29
  }
@@ -28,7 +34,20 @@ ThemeProvider.propTypes = {
28
34
  metadata: PropTypes.shape({
29
35
  themeTokensVersion: PropTypes.string.isRequired
30
36
  }).isRequired
31
- }).isRequired
37
+ }).isRequired,
38
+ /**
39
+ * An object containing options allowing to customize the theming experience:
40
+ *
41
+ * - `forceAbsoluteFontSizing`: available on web only; when set to true, allows
42
+ * using absolute font sizing (in pixels, doesn't scale) instead of the
43
+ * relative sizing (in `rem`, scales depending on the browser settings)
44
+ * - `contentMaxWidth`: allows configuration of the content max width to be used in components
45
+ * such as Footnote and Notification to avoid content to stretch width more then the page's width
46
+ */
47
+ themeOptions: PropTypes.shape({
48
+ forceAbsoluteFontSizing: PropTypes.bool,
49
+ contentMaxWidth: responsiveProps.getTypeOptionallyByViewport(PropTypes.number)
50
+ })
32
51
  }
33
52
 
34
53
  export default ThemeProvider
@@ -15,13 +15,21 @@ export function applyTextStyles({
15
15
  fontWeight = '400',
16
16
  fontName,
17
17
  fontStyle = 'normal',
18
+ themeOptions = {
19
+ // TODO: switch `forceAbsoluteFontSizing` to be false by default in the next major version
20
+ forceAbsoluteFontSizing: true
21
+ },
18
22
  ...rest
19
23
  }) {
20
24
  const styles = { ...rest }
25
+ const { forceAbsoluteFontSizing } = themeOptions
21
26
 
22
27
  if (fontSize) {
23
28
  // If relative font sizes are needed, catch and calculate them here
24
- styles.fontSize = fontSize
29
+ styles.fontSize =
30
+ Platform.OS === 'web' && !forceAbsoluteFontSizing
31
+ ? `${fontSize / fontBasePixels}rem`
32
+ : fontSize
25
33
  }
26
34
  if (typeof lineHeight === 'number') {
27
35
  // React Native expects absolute line heights but multipliers are better as design tokens
@@ -157,7 +157,7 @@ export const validateThemeTokensVersion = (theme) => {
157
157
 
158
158
  The UDS base components ${pkg.name} v${pkg.version} are only compatible with UDS themes that are built with @telus-uds/system-theme-tokens version that is semver compatible with ${expectedThemeTokensVersion}. The current theme was built with @telus-uds/system-theme-tokens v${actualThemeTokensVersion}.
159
159
 
160
- If you see this error than most likely you have attempted to install ${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`
160
+ If you see this error than most likely you have attempted to install ${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`
161
161
  )
162
162
  }
163
163
  }
@@ -40,6 +40,7 @@ const ToggleSwitchGroup = forwardRef(
40
40
  inactive = false,
41
41
  feedback,
42
42
  hint,
43
+ hintPosition = 'inline',
43
44
  tooltip,
44
45
  legend,
45
46
  name: inputGroupName,
@@ -130,6 +131,7 @@ const ToggleSwitchGroup = forwardRef(
130
131
  legend={legend}
131
132
  tooltip={tooltip}
132
133
  hint={hint}
134
+ hintPosition={hintPosition}
133
135
  space={fieldSpace}
134
136
  feedback={feedback}
135
137
  inactive={inactive}
@@ -205,6 +207,10 @@ ToggleSwitchGroup.propTypes = {
205
207
  * Optional additional text giving more detail to help a user make a choice.
206
208
  */
207
209
  hint: PropTypes.string,
210
+ /**
211
+ * Position of the hint relative to label. Use `below` to display a larger hint below the label.
212
+ */
213
+ hintPosition: PropTypes.oneOf(['inline', 'below']),
208
214
  /**
209
215
  * Optional tooltip text content to include alongside the legend and hint.
210
216
  */