@telus-uds/components-base 1.6.1 → 1.8.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 (97) hide show
  1. package/.storybook/main.js +7 -0
  2. package/.turbo/turbo-build.log +3 -3
  3. package/.turbo/turbo-lint.log +3 -13
  4. package/CHANGELOG.json +112 -1
  5. package/CHANGELOG.md +41 -2
  6. package/__fixtures__/Accessible.js +1 -2
  7. package/__fixtures__/Accessible.native.js +1 -2
  8. package/__tests__/FlexGrid/Col.test.jsx +5 -0
  9. package/__tests__/InputLabel/InputLabel.test.jsx +28 -0
  10. package/__tests__/InputLabel/__snapshots__/InputLabel.test.jsx.snap +3 -0
  11. package/__tests__/InputSupports/InputSupports.test.jsx +10 -0
  12. package/component-docs.json +278 -40
  13. package/lib/Button/ButtonGroup.js +118 -45
  14. package/lib/Checkbox/CheckboxGroup.js +3 -3
  15. package/lib/ExpandCollapse/Panel.js +2 -1
  16. package/lib/Fieldset/Fieldset.js +7 -0
  17. package/lib/InputLabel/InputLabel.js +8 -1
  18. package/lib/InputSupports/InputSupports.js +7 -0
  19. package/lib/List/ListItem.js +22 -12
  20. package/lib/Notification/Notification.js +1 -1
  21. package/lib/Radio/RadioGroup.js +12 -5
  22. package/lib/RadioCard/RadioCardGroup.js +7 -0
  23. package/lib/Search/Search.js +28 -20
  24. package/lib/Skeleton/Skeleton.js +48 -2
  25. package/lib/TextInput/TextArea.js +1 -1
  26. package/lib/TextInput/TextInput.js +1 -1
  27. package/lib/TextInput/TextInputBase.js +1 -1
  28. package/lib/ToggleSwitch/ToggleSwitch.js +7 -0
  29. package/lib/ToggleSwitch/ToggleSwitchGroup.js +7 -0
  30. package/lib/Tooltip/Tooltip.js +1 -1
  31. package/lib/Typography/Typography.js +12 -10
  32. package/lib/index.js +22 -1
  33. package/lib/utils/animation/useVerticalExpandAnimation.js +26 -13
  34. package/lib/utils/input.js +5 -6
  35. package/lib/utils/props/index.js +18 -0
  36. package/lib/utils/props/inputSupportsProps.js +7 -0
  37. package/lib/utils/props/textInputProps.js +207 -0
  38. package/lib/utils/props/textProps.js +72 -0
  39. package/lib-module/Button/ButtonGroup.js +117 -45
  40. package/lib-module/Checkbox/CheckboxGroup.js +3 -3
  41. package/lib-module/ExpandCollapse/Panel.js +2 -1
  42. package/lib-module/Fieldset/Fieldset.js +7 -0
  43. package/lib-module/InputLabel/InputLabel.js +8 -1
  44. package/lib-module/InputSupports/InputSupports.js +7 -0
  45. package/lib-module/List/ListItem.js +22 -12
  46. package/lib-module/Notification/Notification.js +1 -1
  47. package/lib-module/Radio/RadioGroup.js +12 -5
  48. package/lib-module/RadioCard/RadioCardGroup.js +7 -0
  49. package/lib-module/Search/Search.js +30 -22
  50. package/lib-module/Skeleton/Skeleton.js +49 -3
  51. package/lib-module/TextInput/TextArea.js +2 -2
  52. package/lib-module/TextInput/TextInput.js +2 -2
  53. package/lib-module/TextInput/TextInputBase.js +2 -2
  54. package/lib-module/ToggleSwitch/ToggleSwitch.js +7 -0
  55. package/lib-module/ToggleSwitch/ToggleSwitchGroup.js +7 -0
  56. package/lib-module/Tooltip/Tooltip.js +1 -1
  57. package/lib-module/Typography/Typography.js +13 -11
  58. package/lib-module/index.js +1 -1
  59. package/lib-module/utils/animation/useVerticalExpandAnimation.js +26 -14
  60. package/lib-module/utils/input.js +6 -6
  61. package/lib-module/utils/props/index.js +2 -0
  62. package/lib-module/utils/props/inputSupportsProps.js +7 -0
  63. package/lib-module/utils/props/textInputProps.js +194 -0
  64. package/lib-module/utils/props/textProps.js +59 -0
  65. package/package.json +9 -4
  66. package/src/Button/ButtonGroup.jsx +106 -41
  67. package/src/Checkbox/Checkbox.jsx +7 -4
  68. package/src/Checkbox/CheckboxGroup.jsx +3 -3
  69. package/src/ExpandCollapse/Panel.jsx +3 -1
  70. package/src/Fieldset/Fieldset.jsx +6 -0
  71. package/src/InputLabel/InputLabel.jsx +17 -2
  72. package/src/InputSupports/InputSupports.jsx +9 -1
  73. package/src/List/ListItem.jsx +17 -9
  74. package/src/Notification/Notification.jsx +1 -1
  75. package/src/Radio/Radio.jsx +5 -1
  76. package/src/Radio/RadioGroup.jsx +11 -5
  77. package/src/RadioCard/RadioCard.jsx +5 -1
  78. package/src/RadioCard/RadioCardGroup.jsx +6 -0
  79. package/src/Search/Search.jsx +34 -22
  80. package/src/Skeleton/Skeleton.jsx +56 -3
  81. package/src/TextInput/TextArea.jsx +2 -0
  82. package/src/TextInput/TextInput.jsx +2 -0
  83. package/src/TextInput/TextInputBase.jsx +2 -0
  84. package/src/ToggleSwitch/ToggleSwitch.jsx +6 -0
  85. package/src/ToggleSwitch/ToggleSwitchGroup.jsx +6 -0
  86. package/src/Tooltip/Tooltip.jsx +1 -1
  87. package/src/Typography/Typography.jsx +13 -9
  88. package/src/index.js +4 -1
  89. package/src/utils/animation/useVerticalExpandAnimation.js +25 -12
  90. package/src/utils/input.js +5 -7
  91. package/src/utils/props/index.js +2 -0
  92. package/src/utils/props/inputSupportsProps.js +6 -1
  93. package/src/utils/props/textInputProps.js +178 -0
  94. package/src/utils/props/textProps.js +58 -0
  95. package/src/utils/props/tokens.js +21 -19
  96. package/stories/Search/Search.stories.jsx +49 -2
  97. package/stories/Tabs/Tabs.stories.jsx +4 -3
@@ -0,0 +1,194 @@
1
+ import PropTypes from 'prop-types';
2
+ import Platform from "react-native-web/dist/exports/Platform";
3
+ import getPropSelector from './getPropSelector'; // This file contains common props for components that render a React Native TextInput
4
+ // It excludes interaction handler functions which are in `./handlerProps.js`
5
+
6
+ /**
7
+ * TextInput (web and native) supports some common React Native props
8
+ * shared with React Native's Text component.
9
+ */
10
+
11
+ const textProps = {
12
+ maxFontSizeMultiplier: PropTypes.number,
13
+ nativeId: PropTypes.string,
14
+ onLayout: PropTypes.func
15
+ };
16
+ /**
17
+ * UDS text inputs accept props related to UDS's useInputValue hook
18
+ */
19
+
20
+ const inputValueProps = {
21
+ value: PropTypes.string,
22
+ initialValue: PropTypes.string,
23
+ readOnly: PropTypes.bool,
24
+ inactive: PropTypes.bool
25
+ };
26
+ /**
27
+ * This collection adds props that can be passed through to both React Native's
28
+ * and React Native Web's implementations of the React Native TextInput component.
29
+ */
30
+
31
+ const crossPlatform = { ...textProps,
32
+ ...inputValueProps,
33
+
34
+ /**
35
+ * Web and Android; 'off' disables device autocomplete, other strings are platform-specific.
36
+ * Valid values on Native: https://reactnative.dev/docs/textinput#autocomplete-android
37
+ * Valid values on Web: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete
38
+ */
39
+ autoComplete: PropTypes.string,
40
+
41
+ /**
42
+ * On Native, default is `true`, passing `false` disables autoCorrect.
43
+ * On web, only supported by Safari and expects "on" or "off" strings.
44
+ */
45
+ autoCorrect: PropTypes.oneOf([true, false, 'on', 'off']),
46
+
47
+ /**
48
+ * Focuses the element on mount. On Web, only the first form element with autoFocus is focussed.
49
+ */
50
+ autoFocus: PropTypes.bool,
51
+
52
+ /**
53
+ * Default is `true` for single line, `false` for multi-line
54
+ */
55
+ blurOnSubmit: PropTypes.bool,
56
+
57
+ /**
58
+ * iOS and Web only, no effect on Android
59
+ */
60
+ clearTextOnFocus: PropTypes.bool,
61
+
62
+ /**
63
+ * Default is `true`. On web, this works by mapping to input's `readonly` attribute
64
+ */
65
+ editable: PropTypes.bool,
66
+
67
+ /**
68
+ * See documentation for allowed values (varies between Web, Android and iOS) and important notes:
69
+ * - Native: https://reactnative.dev/docs/textinput#keyboardtype
70
+ * - Web: equivalent to `inputmode` but see https://necolas.github.io/react-native-web/docs/text-input/
71
+ */
72
+ keyboardType: PropTypes.string,
73
+
74
+ /**
75
+ * Uses native tools (no flicker) to cap the maximum number of characters.
76
+ * On Web, works via `maxlength` attr.
77
+ */
78
+ maxLength: PropTypes.number,
79
+
80
+ /**
81
+ * If passed as true, the text input can be multiple lines.
82
+ *
83
+ * > It is important to note that this aligns the text to the top on iOS, and centers it on Android.
84
+ * > Use with textAlignVertical set to top for the same behavior in both platforms.
85
+ */
86
+ multiline: PropTypes.bool,
87
+
88
+ /**
89
+ * Web and Android only, requires `multiline` to be `true`.
90
+ */
91
+ numberOfLines: PropTypes.number,
92
+
93
+ /**
94
+ * Text to display when no value set.
95
+ * Accesibility guidelines recommend using labels to describe the input and using
96
+ * placeholders rarely and sparingly to prompt a particular format.
97
+ */
98
+ placeholder: PropTypes.string,
99
+
100
+ /**
101
+ * Sets placeholder colour. On Web, uses `::placeholder { color: ... }` selector.
102
+ */
103
+ placeholderTextColor: PropTypes.string,
104
+
105
+ /**
106
+ * One of a subset of platform-specific options that controls labelling and presentation
107
+ * in on-screen keyboards and accessibility tools. Uses `enterkeyhint` attr on Web.
108
+ *
109
+ * 'done', 'go', 'next', 'search', and 'send' are available for Web, Android and iOS.
110
+ */
111
+ returnKeyType: PropTypes.string,
112
+
113
+ /**
114
+ * Obscures passwords and similar. Equivalent to type="password" on Web.
115
+ * Does not work if multiline is true.
116
+ */
117
+ secureTextEntry: PropTypes.bool,
118
+
119
+ /**
120
+ * If true, all text will automatically be selected on focus.
121
+ */
122
+ selectTextOnFocus: PropTypes.bool,
123
+
124
+ /**
125
+ * Web and iOS. On iOS, default inherits from `autoCorrect`.
126
+ * On Web, equivalent to `spellcheck` attr.
127
+ */
128
+ spellCheck: PropTypes.bool
129
+ };
130
+ /**
131
+ * These web-only props all control HTML `input` attributes of the same name.
132
+ * Refer to general HTML documentation for more details.
133
+ */
134
+
135
+ const webOnly = {
136
+ disabled: PropTypes.bool,
137
+ dir: PropTypes.oneOf(['auto', 'ltr', 'rtl']),
138
+ lang: PropTypes.string
139
+ };
140
+ /**
141
+ * These props are supported in React Native but not React Native Web.
142
+ *
143
+ * React Native text inputs can be quirky, so a full set of props should be allowed to handle edge cases.
144
+ * Refer to React Native documentation for details, allowed values, and Android/iOS support and versions:
145
+ * https://reactnative.dev/docs/textinput
146
+ *
147
+ * Beware that many React Native text input props apply via complicated logic that chooses a built-in
148
+ * native component based on the values of multiple boolean flags, and may sometimes appear to pick an
149
+ * option that is inappropriate for one flag based on the values of one or more other other flags.
150
+ */
151
+
152
+ const nativeOnly = {
153
+ caretHidden: PropTypes.bool,
154
+ clearButtonMode: PropTypes.string,
155
+ contextMenuHidden: PropTypes.bool,
156
+ dataDetectorTypes: PropTypes.string,
157
+ disableFullscreenUI: PropTypes.bool,
158
+ enablesReturnKeyAutomatically: PropTypes.bool,
159
+ importantForAutofill: PropTypes.string,
160
+ inlineImageLeft: PropTypes.string,
161
+ keyboardAppearance: PropTypes.string,
162
+ returnKeyLabel: PropTypes.string,
163
+ rejectResponderTermination: PropTypes.bool,
164
+ scrollEnabled: PropTypes.bool,
165
+ selection: PropTypes.object,
166
+ selectionColor: PropTypes.string,
167
+ showSoftInputOnFocus: PropTypes.bool,
168
+ textAlign: PropTypes.string,
169
+ textContentType: PropTypes.string,
170
+ passwordRules: PropTypes.string,
171
+ textBreakStrategy: PropTypes.string,
172
+ underlineColorAndroid: PropTypes.string
173
+ };
174
+ export default {
175
+ /**
176
+ * Subset of proptypes that can be passed down to a React Native or React Native Web
177
+ * `TextInput` component. Allow regardless of platform, so cross-platform apps don't warn.
178
+ */
179
+ types: { ...crossPlatform,
180
+ ...webOnly,
181
+ ...nativeOnly
182
+ },
183
+
184
+ /**
185
+ * Filters a props object. Return only platform-appropriate TextInput props, native inputs
186
+ * may throw errors on receiving unknown props.
187
+ */
188
+ select: getPropSelector({ ...crossPlatform,
189
+ ...Platform.select({
190
+ web: webOnly,
191
+ default: nativeOnly
192
+ })
193
+ })
194
+ };
@@ -0,0 +1,59 @@
1
+ import PropTypes from 'prop-types';
2
+ import Platform from "react-native-web/dist/exports/Platform";
3
+ import getPropSelector from './getPropSelector'; // These are the props accepted specifically on React Native (Web) `Text` elements.
4
+ // They are generally concerned with the behaviour of multiline text.
5
+
6
+ const crossPlatform = {
7
+ /**
8
+ * Truncates text after this many lines with an ellipsis at the end.
9
+ * On native, ellipsis behaviour may be changed with `ellipsizeMode` prop.
10
+ */
11
+ numberOfLines: PropTypes.number,
12
+
13
+ /**
14
+ * Default is true on web and false on native
15
+ */
16
+ selectable: PropTypes.bool
17
+ };
18
+ /**
19
+ * See React Native docs for latest details on these.
20
+ * https://reactnative.dev/docs/text
21
+ */
22
+
23
+ const nativeOnly = {
24
+ ellipsizeMode: PropTypes.string,
25
+ maxFontSizeMultiplier: PropTypes.number,
26
+ minimumFontScale: PropTypes.number,
27
+ onTextLayout: PropTypes.func,
28
+ suppressHighlighting: PropTypes.bool,
29
+ textBreakStrategy: PropTypes.string
30
+ };
31
+ /**
32
+ * These set HTML attributes of the same name.
33
+ */
34
+
35
+ const webOnly = {
36
+ dir: PropTypes.oneOf(['auto', 'ltr', 'rtl']),
37
+ lang: PropTypes.string
38
+ };
39
+ export default {
40
+ /**
41
+ * Set of prop types specific to React Native and React Native Web `Text`,
42
+ * which largely revolve around the behaviour of multiline non-pressable text.
43
+ */
44
+ types: { ...crossPlatform,
45
+ ...webOnly,
46
+ ...nativeOnly
47
+ },
48
+
49
+ /**
50
+ * Filters a props object, returning only props specific to `Text` elements
51
+ * on the current platform. Does not include props applicable to `Text` and `View`.
52
+ */
53
+ select: getPropSelector({ ...crossPlatform,
54
+ ...Platform.select({
55
+ web: webOnly,
56
+ default: nativeOnly
57
+ })
58
+ })
59
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telus-uds/components-base",
3
- "version": "1.6.1",
3
+ "version": "1.8.0",
4
4
  "description": "Base components",
5
5
  "keywords": [
6
6
  "base"
@@ -31,8 +31,7 @@
31
31
  "build:code": "yarn build:main && yarn build:module",
32
32
  "build:docs": "babel-node --plugins=@nearform/babel-plugin-react-docgen generate-component-docs.js",
33
33
  "storybook": "start-storybook",
34
- "dev": "yarn build:code --watch",
35
- "release": "standard-version"
34
+ "dev": "yarn build:code --watch"
36
35
  },
37
36
  "bugs": {
38
37
  "url": "https://github.com/telus/universal-design-system/issues"
@@ -50,6 +49,12 @@
50
49
  "react-native-web": "^0.17.0"
51
50
  },
52
51
  "devDependencies": {
52
+ "@storybook/addon-a11y": "^6.5.6",
53
+ "@storybook/addon-essentials": "^6.5.6",
54
+ "@storybook/cli": "^6.5.6",
55
+ "@storybook/react": "^6.5.6",
56
+ "@storybook/builder-webpack5": "^6.5.6",
57
+ "@storybook/manager-webpack5": "^6.5.6",
53
58
  "@telus-uds/browserslist-config": "^1.0.1",
54
59
  "@testing-library/jest-native": "^4.0.1",
55
60
  "@testing-library/react-hooks": "^7.0.1",
@@ -59,7 +64,7 @@
59
64
  "dependencies": {
60
65
  "airbnb-prop-types": "^2.16.0",
61
66
  "@telus-uds/system-constants": "^1.0.2",
62
- "@telus-uds/system-theme-tokens": "^1.5.0",
67
+ "@telus-uds/system-theme-tokens": "^2.0.0",
63
68
  "lodash.debounce": "^4.0.8",
64
69
  "lodash.merge": "^4.6.2",
65
70
  "prop-types": "^15.7.2",
@@ -5,6 +5,7 @@ import { Platform } from 'react-native'
5
5
 
6
6
  import ButtonBase from './ButtonBase'
7
7
  import { StackWrap } from '../StackView'
8
+ import Fieldset from '../Fieldset'
8
9
  import { useViewport } from '../ViewportProvider'
9
10
  import { useThemeTokens, useThemeTokensCallback } from '../ThemeProvider'
10
11
  import {
@@ -41,6 +42,13 @@ const ButtonGroup = forwardRef(
41
42
  onChange,
42
43
  readOnly = false,
43
44
  inactive = false,
45
+ legend,
46
+ tooltip,
47
+ hint,
48
+ validation,
49
+ feedback,
50
+ name: inputGroupName,
51
+ copy,
44
52
  accessibilityRole = maxValues === 1
45
53
  ? 'radiogroup' // radiogroup is cross-platform; only web aria has generic groups
46
54
  : Platform.select({ web: 'group', default: 'none' }),
@@ -51,7 +59,7 @@ const ButtonGroup = forwardRef(
51
59
  const viewport = useViewport()
52
60
  const themeTokens = useThemeTokens('ButtonGroup', tokens, variant, { viewport })
53
61
  const stackTokens = selectTokens('StackView', themeTokens)
54
- const { direction, space } = themeTokens
62
+ const { direction, space, fieldSpace } = themeTokens
55
63
 
56
64
  const getButtonTokens = useThemeTokensCallback('ButtonGroupItem', tokens, variant)
57
65
 
@@ -74,53 +82,73 @@ const ButtonGroup = forwardRef(
74
82
  throw new Error(`ButtonGroup items must have unique ${uniqueFields.join(', ')}`)
75
83
  }
76
84
 
85
+ // Some web screenreaders e.g. MacOS Voiceover don't handle radiogroups properly unless radio is direct child of radiogroup
86
+ const innerRole =
87
+ Platform.OS === 'web' && accessibilityRole === 'radiogroup' ? accessibilityRole : undefined
88
+
77
89
  return (
78
- <StackWrap
90
+ <Fieldset
79
91
  {...systemProps}
80
- space={space}
81
- direction={direction}
82
- tokens={stackTokens}
83
92
  ref={ref}
93
+ name={inputGroupName}
94
+ legend={legend}
95
+ tooltip={tooltip}
96
+ hint={hint}
97
+ space={fieldSpace}
98
+ feedback={feedback}
99
+ readOnly={readOnly}
100
+ inactive={inactive}
101
+ validation={validation}
102
+ accessibilityRole={accessibilityRole}
103
+ {...selectProps(rest)}
84
104
  >
85
- {items.map(
86
- ({ label, id = label, accessibilityLabel, ref: itemRef, ...itemRest }, index) => {
87
- const isSelected = currentValues.includes(id)
105
+ <StackWrap
106
+ accessibilityRole={innerRole}
107
+ space={space}
108
+ direction={direction}
109
+ tokens={stackTokens}
110
+ ref={ref}
111
+ >
112
+ {items.map(
113
+ ({ label, id = label, accessibilityLabel, ref: itemRef, ...itemRest }, index) => {
114
+ const isSelected = currentValues.includes(id)
88
115
 
89
- // Pass an object of relevant component state as first argument for any passed-in press handlers
90
- const pressHandlers = getPressHandlersWithArgs(rest, [{ id, label, currentValues }])
116
+ // Pass an object of relevant component state as first argument for any passed-in press handlers
117
+ const pressHandlers = getPressHandlersWithArgs(rest, [{ id, label, currentValues }])
91
118
 
92
- const handlePress = (event) => {
93
- if (pressHandlers.onPress) pressHandlers.onPress(event)
94
- toggleOneValue(id, event)
95
- }
119
+ const handlePress = (event) => {
120
+ if (pressHandlers.onPress) pressHandlers.onPress(event)
121
+ toggleOneValue(id, event)
122
+ }
96
123
 
97
- const itemA11y = {
98
- accessibilityState: { checked: isSelected },
99
- accessibilityRole: itemA11yRole,
100
- accessibilityLabel,
101
- ...a11yProps.getPositionInSet(items.length, index)
102
- }
124
+ const itemA11y = {
125
+ accessibilityState: { checked: isSelected },
126
+ accessibilityRole: itemA11yRole,
127
+ accessibilityLabel,
128
+ ...a11yProps.getPositionInSet(items.length, index)
129
+ }
103
130
 
104
- // Ensure button is direct child of group as MacOS voiceover only applies "X of Y" to
105
- // "radio" if it's a direct child of "radiogroup", even if aria-posinset etc exists
106
- return (
107
- <ButtonBase
108
- ref={itemRef}
109
- key={id}
110
- {...pressHandlers}
111
- onPress={handlePress}
112
- tokens={getButtonTokens}
113
- selected={isSelected}
114
- inactive={inactive}
115
- {...itemA11y}
116
- {...selectItemProps(itemRest)}
117
- >
118
- {label}
119
- </ButtonBase>
120
- )
121
- }
122
- )}
123
- </StackWrap>
131
+ // Ensure button is direct child of group as MacOS voiceover only applies "X of Y" to
132
+ // "radio" if it's a direct child of "radiogroup", even if aria-posinset etc exists
133
+ return (
134
+ <ButtonBase
135
+ ref={itemRef}
136
+ key={id}
137
+ {...pressHandlers}
138
+ onPress={handlePress}
139
+ tokens={getButtonTokens}
140
+ selected={isSelected}
141
+ inactive={inactive}
142
+ {...itemA11y}
143
+ {...selectItemProps(itemRest)}
144
+ >
145
+ {label}
146
+ </ButtonBase>
147
+ )
148
+ }
149
+ )}
150
+ </StackWrap>
151
+ </Fieldset>
124
152
  )
125
153
  }
126
154
  )
@@ -180,7 +208,44 @@ ButtonGroup.propTypes = {
180
208
  * managing its own selected state, a default set of selections may be provided.
181
209
  * Changing the `initialValues` does not change the user's selections.
182
210
  */
183
- initialValues: PropTypes.arrayOf(PropTypes.string)
211
+ initialValues: PropTypes.arrayOf(PropTypes.string),
212
+ /**
213
+ * Main text used to describe this group, used in Fieldset's Legend element.
214
+ */
215
+ legend: PropTypes.string,
216
+ /**
217
+ * Optional additional text giving more detail to help a user make a choice.
218
+ */
219
+ hint: PropTypes.string,
220
+ /**
221
+ * Optional tooltip text content to include alongside the legend and hint.
222
+ */
223
+ tooltip: PropTypes.string,
224
+ /**
225
+ * Current validation status of the group, passed to the feedback element if there is one.
226
+ */
227
+ validation: PropTypes.oneOf(['error', 'success']),
228
+ /**
229
+ * If provided, a Feedback element is rendered containing this text.
230
+ */
231
+ feedback: PropTypes.string,
232
+ /**
233
+ * If true, the buttons cannot be selected by the user and simply show their current state.
234
+ */
235
+ readOnly: PropTypes.bool,
236
+ /**
237
+ * If true, the buttons cannot be interacted with, elements are set as `disabled` and if the
238
+ * theme supports `inactive` appearances rules, these are applied.
239
+ */
240
+ inactive: PropTypes.bool,
241
+ /**
242
+ * On Web, this is passed to the `name` attribute of the fieldset.
243
+ */
244
+ name: PropTypes.string,
245
+ /**
246
+ * Sets the language of microcopy in subcomponents (e.g. Tooltip's default accessibility label).
247
+ */
248
+ copy: PropTypes.oneOf(['en', 'fr'])
184
249
  }
185
250
 
186
251
  export default ButtonGroup
@@ -137,7 +137,11 @@ const Checkbox = forwardRef(
137
137
  },
138
138
  ref
139
139
  ) => {
140
- const { currentValue: isChecked, setValue: setIsChecked, isControlled } = useInputValue(
140
+ const {
141
+ currentValue: isChecked,
142
+ setValue: setIsChecked,
143
+ isControlled
144
+ } = useInputValue(
141
145
  {
142
146
  value: checked,
143
147
  initialValue: defaultChecked,
@@ -152,9 +156,8 @@ const Checkbox = forwardRef(
152
156
  ...variant
153
157
  })
154
158
  const defaultTokens = getTokens()
155
- const { feedbackMarginBottom, feedbackMarginTop, feedbackPosition } = selectFeedbackTokens(
156
- defaultTokens
157
- )
159
+ const { feedbackMarginBottom, feedbackMarginTop, feedbackPosition } =
160
+ selectFeedbackTokens(defaultTokens)
158
161
  const styles = StyleSheet.create({
159
162
  feedbackContainer: { marginTop: feedbackMarginTop, marginBottom: feedbackMarginBottom }
160
163
  })
@@ -219,16 +219,16 @@ CheckboxGroup.propTypes = {
219
219
  */
220
220
  onChange: PropTypes.func,
221
221
  /**
222
- * If true, the radio cards cannot be selected by the user and simply show their current state.
222
+ * If true, the checkboxes cannot be selected by the user and simply show their current state.
223
223
  */
224
224
  readOnly: PropTypes.bool,
225
225
  /**
226
- * If true, the checkbox cannot be interacted with, elements are set as `disabled` and if the
226
+ * If true, the checkboxes cannot be interacted with, elements are set as `disabled` and if the
227
227
  * theme supports `inactive` appearances rules, these are applied.
228
228
  */
229
229
  inactive: PropTypes.bool,
230
230
  /**
231
- * On Web, this is passed to the `name` attribute of the fieldset and each radio input.
231
+ * On Web, this is passed to the `name` attribute of the fieldset and each checkbox input.
232
232
  */
233
233
  name: PropTypes.string
234
234
  }
@@ -79,7 +79,8 @@ const ExpandCollapsePanel = forwardRef(
79
79
  setContainerHeight(height)
80
80
  }
81
81
  }
82
- const animatedStyles = useVerticalExpandAnimation({
82
+
83
+ const [animatedStyles, animatedRef] = useVerticalExpandAnimation({
83
84
  containerHeight,
84
85
  isExpanded,
85
86
  tokens: themeTokens
@@ -105,6 +106,7 @@ const ExpandCollapsePanel = forwardRef(
105
106
  {control}
106
107
  </ExpandCollapseControl>
107
108
  <Animated.View
109
+ ref={animatedRef}
108
110
  style={[overflowContainerStyles, animatedStyles, staticStyles.itemsContainer]}
109
111
  {...focusabilityProps}
110
112
  >
@@ -18,6 +18,7 @@ import Legend from './Legend'
18
18
  const Fieldset = forwardRef(
19
19
  (
20
20
  {
21
+ copy = 'en',
21
22
  space,
22
23
  feedback,
23
24
  feedbackPosition = 'top',
@@ -44,6 +45,7 @@ const Fieldset = forwardRef(
44
45
  const legendContent = legend && (
45
46
  <Legend>
46
47
  <InputLabel
48
+ copy={copy}
47
49
  label={legend}
48
50
  hint={hint}
49
51
  hintPosition={hintPosition}
@@ -83,6 +85,10 @@ Fieldset.displayName = 'Fieldset'
83
85
 
84
86
  Fieldset.propTypes = {
85
87
  children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
88
+ /**
89
+ * Whether the English or French copy will be used (e.g. for accessibility labels).
90
+ */
91
+ copy: PropTypes.oneOf(['en', 'fr']),
86
92
  /**
87
93
  * The accessibility role of the `<fieldset>` element itself. Other React Native accessibility
88
94
  * props are not supported because there is not an appropriate counterpart for Fieldsets.
@@ -38,7 +38,18 @@ const selectGapStyles = ({ gap }) => ({ marginRight: gap })
38
38
 
39
39
  const InputLabel = forwardRef(
40
40
  (
41
- { label, forId, hint, hintPosition = 'inline', hintId, tooltip, tokens, variant, ...rest },
41
+ {
42
+ copy = 'en',
43
+ label,
44
+ forId,
45
+ hint,
46
+ hintPosition = 'inline',
47
+ hintId,
48
+ tooltip,
49
+ tokens,
50
+ variant,
51
+ ...rest
52
+ },
42
53
  ref
43
54
  ) => {
44
55
  const themeTokens = useThemeTokens('InputLabel', tokens, variant)
@@ -77,7 +88,7 @@ const InputLabel = forwardRef(
77
88
  { height: themeTokens.fontSize * themeTokens.lineHeight }
78
89
  ]}
79
90
  >
80
- <Tooltip content={tooltip} />
91
+ <Tooltip content={tooltip} copy={copy} />
81
92
  </View>
82
93
  )}
83
94
  </View>
@@ -94,6 +105,10 @@ InputLabel.displayName = 'InputLabel'
94
105
 
95
106
  InputLabel.propTypes = {
96
107
  ...selectedSystemPropTypes,
108
+ /**
109
+ * Whether the English or French copy will be used (e.g. for accessibility labels).
110
+ */
111
+ copy: PropTypes.oneOf(['en', 'fr']),
97
112
  /**
98
113
  * The input label.
99
114
  */
@@ -8,7 +8,10 @@ import { useThemeTokens } from '../ThemeProvider'
8
8
  import useInputSupports from './useInputSupports'
9
9
 
10
10
  const InputSupports = forwardRef(
11
- ({ children, label, hint, hintPosition = 'inline', feedback, tooltip, validation }, ref) => {
11
+ (
12
+ { children, copy = 'en', label, hint, hintPosition = 'inline', feedback, tooltip, validation },
13
+ ref
14
+ ) => {
12
15
  const { space } = useThemeTokens('InputSupports')
13
16
 
14
17
  const { inputId, hintId, feedbackId, a11yProps } = useInputSupports({
@@ -22,6 +25,7 @@ const InputSupports = forwardRef(
22
25
  <StackView space={space} ref={ref}>
23
26
  {label && (
24
27
  <InputLabel
28
+ copy={copy}
25
29
  label={label}
26
30
  hint={hint}
27
31
  hintPosition={hintPosition}
@@ -40,6 +44,10 @@ InputSupports.displayName = 'InputSupports'
40
44
 
41
45
  InputSupports.propTypes = {
42
46
  children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
47
+ /**
48
+ * Whether the English or French copy will be used (e.g. for accessibility labels).
49
+ */
50
+ copy: PropTypes.oneOf(['en', 'fr']),
43
51
  /**
44
52
  * The input label.
45
53
  */