@telus-uds/components-base 1.7.0 → 1.8.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 (183) hide show
  1. package/CHANGELOG.md +38 -2
  2. package/component-docs.json +264 -18
  3. package/lib/Button/ButtonGroup.js +118 -45
  4. package/lib/Checkbox/CheckboxGroup.js +3 -3
  5. package/lib/ExpandCollapse/Panel.js +2 -1
  6. package/lib/Fieldset/Fieldset.js +7 -0
  7. package/lib/InputLabel/InputLabel.js +8 -1
  8. package/lib/InputSupports/InputSupports.js +7 -0
  9. package/lib/Notification/Notification.js +1 -1
  10. package/lib/Radio/RadioGroup.js +12 -5
  11. package/lib/RadioCard/RadioCardGroup.js +7 -0
  12. package/lib/Search/Search.js +1 -1
  13. package/lib/Skeleton/Skeleton.js +48 -2
  14. package/lib/ToggleSwitch/ToggleSwitch.js +7 -0
  15. package/lib/ToggleSwitch/ToggleSwitchGroup.js +7 -0
  16. package/lib/Tooltip/Tooltip.js +1 -1
  17. package/lib/utils/animation/useVerticalExpandAnimation.js +26 -13
  18. package/lib/utils/props/inputSupportsProps.js +7 -0
  19. package/lib/utils/props/textInputProps.js +2 -1
  20. package/lib-module/Button/ButtonGroup.js +117 -45
  21. package/lib-module/Checkbox/CheckboxGroup.js +3 -3
  22. package/lib-module/ExpandCollapse/Panel.js +2 -1
  23. package/lib-module/Fieldset/Fieldset.js +7 -0
  24. package/lib-module/InputLabel/InputLabel.js +8 -1
  25. package/lib-module/InputSupports/InputSupports.js +7 -0
  26. package/lib-module/Notification/Notification.js +1 -1
  27. package/lib-module/Radio/RadioGroup.js +12 -5
  28. package/lib-module/RadioCard/RadioCardGroup.js +7 -0
  29. package/lib-module/Search/Search.js +1 -1
  30. package/lib-module/Skeleton/Skeleton.js +49 -3
  31. package/lib-module/ToggleSwitch/ToggleSwitch.js +7 -0
  32. package/lib-module/ToggleSwitch/ToggleSwitchGroup.js +7 -0
  33. package/lib-module/Tooltip/Tooltip.js +1 -1
  34. package/lib-module/utils/animation/useVerticalExpandAnimation.js +26 -14
  35. package/lib-module/utils/props/inputSupportsProps.js +7 -0
  36. package/lib-module/utils/props/textInputProps.js +2 -1
  37. package/package.json +11 -6
  38. package/src/Button/ButtonGroup.jsx +106 -41
  39. package/src/Checkbox/Checkbox.jsx +7 -4
  40. package/src/Checkbox/CheckboxGroup.jsx +3 -3
  41. package/src/ExpandCollapse/Panel.jsx +3 -1
  42. package/src/Fieldset/Fieldset.jsx +6 -0
  43. package/src/InputLabel/InputLabel.jsx +17 -2
  44. package/src/InputSupports/InputSupports.jsx +9 -1
  45. package/src/Notification/Notification.jsx +1 -1
  46. package/src/Radio/Radio.jsx +5 -1
  47. package/src/Radio/RadioGroup.jsx +11 -5
  48. package/src/RadioCard/RadioCard.jsx +5 -1
  49. package/src/RadioCard/RadioCardGroup.jsx +6 -0
  50. package/src/Search/Search.jsx +1 -1
  51. package/src/Skeleton/Skeleton.jsx +56 -3
  52. package/src/ToggleSwitch/ToggleSwitch.jsx +6 -0
  53. package/src/ToggleSwitch/ToggleSwitchGroup.jsx +6 -0
  54. package/src/Tooltip/Tooltip.jsx +1 -1
  55. package/src/utils/animation/useVerticalExpandAnimation.js +25 -12
  56. package/src/utils/props/inputSupportsProps.js +6 -1
  57. package/src/utils/props/textInputProps.js +2 -1
  58. package/src/utils/props/tokens.js +21 -19
  59. package/.storybook/main.js +0 -4
  60. package/.storybook/preview.js +0 -37
  61. package/.turbo/turbo-build.log +0 -8
  62. package/.turbo/turbo-lint.log +0 -13
  63. package/CHANGELOG.json +0 -235
  64. package/__fixtures__/Accessible.js +0 -35
  65. package/__fixtures__/Accessible.native.js +0 -35
  66. package/__fixtures__/Theme.jsx +0 -13
  67. package/__fixtures__/Viewport.jsx +0 -17
  68. package/__fixtures__/test-utils.js +0 -25
  69. package/__fixtures__/testTheme.js +0 -1830
  70. package/__tests__/A11yText/A11yText.test.jsx +0 -34
  71. package/__tests__/ActivityIndicator/ActivityIndicator.test.jsx +0 -68
  72. package/__tests__/ActivityIndicator/__snapshots__/ActivityIndicator.test.jsx.snap +0 -287
  73. package/__tests__/Box/Box.test.jsx +0 -111
  74. package/__tests__/Button/Button.test.jsx +0 -86
  75. package/__tests__/Button/ButtonBase.test.jsx +0 -82
  76. package/__tests__/Button/ButtonGroup.test.jsx +0 -347
  77. package/__tests__/Button/ButtonLink.test.jsx +0 -61
  78. package/__tests__/Card/Card.test.jsx +0 -63
  79. package/__tests__/Checkbox/Checkbox.test.jsx +0 -94
  80. package/__tests__/Checkbox/CheckboxGroup.test.jsx +0 -246
  81. package/__tests__/Divider/Divider.test.jsx +0 -91
  82. package/__tests__/ExpandCollapse/ExpandCollapse.test.jsx +0 -109
  83. package/__tests__/Feedback/Feedback.test.jsx +0 -42
  84. package/__tests__/FlexGrid/Col.test.jsx +0 -256
  85. package/__tests__/FlexGrid/FlexGrid.test.jsx +0 -136
  86. package/__tests__/FlexGrid/Row.test.jsx +0 -273
  87. package/__tests__/HorizontalScroll/HorizontalScroll.test.jsx +0 -165
  88. package/__tests__/Icon/Icon.test.jsx +0 -61
  89. package/__tests__/IconButton/IconButton.test.jsx +0 -52
  90. package/__tests__/InputSupports/InputSupports.test.jsx +0 -50
  91. package/__tests__/Link/Link.test.jsx +0 -63
  92. package/__tests__/Link/TextButton.test.jsx +0 -35
  93. package/__tests__/List/List.test.jsx +0 -60
  94. package/__tests__/Modal/Modal.test.jsx +0 -47
  95. package/__tests__/Notification/Notification.test.jsx +0 -20
  96. package/__tests__/Pagination/Pagination.test.jsx +0 -160
  97. package/__tests__/Progress/Progress.test.jsx +0 -79
  98. package/__tests__/Radio/Radio.test.jsx +0 -87
  99. package/__tests__/Radio/RadioGroup.test.jsx +0 -220
  100. package/__tests__/RadioCard/RadioCard.test.jsx +0 -87
  101. package/__tests__/RadioCard/RadioCardGroup.test.jsx +0 -246
  102. package/__tests__/Search/Search.test.jsx +0 -73
  103. package/__tests__/Select/Select.test.jsx +0 -94
  104. package/__tests__/SideNav/SideNav.test.jsx +0 -110
  105. package/__tests__/Skeleton/Skeleton.test.jsx +0 -61
  106. package/__tests__/Spacer/Spacer.test.jsx +0 -63
  107. package/__tests__/StackView/StackView.test.jsx +0 -216
  108. package/__tests__/StackView/StackWrap.test.jsx +0 -47
  109. package/__tests__/StackView/getStackedContent.test.jsx +0 -295
  110. package/__tests__/StepTracker/StepTracker.test.jsx +0 -94
  111. package/__tests__/Tabs/Tabs.test.jsx +0 -40
  112. package/__tests__/Tags/Tags.test.jsx +0 -327
  113. package/__tests__/TextInput/TextArea.test.jsx +0 -35
  114. package/__tests__/TextInput/TextInputBase.test.jsx +0 -125
  115. package/__tests__/ThemeProvider/ThemeProvider.test.jsx +0 -77
  116. package/__tests__/ThemeProvider/useThemeTokens.test.jsx +0 -514
  117. package/__tests__/ThemeProvider/utils/theme-tokens.test.js +0 -41
  118. package/__tests__/ToggleSwitch/ToggleSwitch.test.jsx +0 -82
  119. package/__tests__/ToggleSwitch/ToggleSwitchGroup.test.jsx +0 -192
  120. package/__tests__/Tooltip/Tooltip.test.jsx +0 -65
  121. package/__tests__/Tooltip/getTooltipPosition.test.js +0 -79
  122. package/__tests__/Typography/typography.test.jsx +0 -90
  123. package/__tests__/utils/children.test.jsx +0 -128
  124. package/__tests__/utils/containUniqueFields.test.js +0 -25
  125. package/__tests__/utils/input.test.js +0 -375
  126. package/__tests__/utils/props.test.js +0 -36
  127. package/__tests__/utils/semantics.test.jsx +0 -34
  128. package/__tests__/utils/useCopy.test.js +0 -42
  129. package/__tests__/utils/useResponsiveProp.test.jsx +0 -202
  130. package/__tests__/utils/useSpacingScale.test.jsx +0 -273
  131. package/__tests__/utils/useUniqueId.test.js +0 -31
  132. package/babel.config.js +0 -35
  133. package/generate-component-docs.js +0 -72
  134. package/jest.config.js +0 -32
  135. package/stories/A11yText/A11yText.stories.jsx +0 -71
  136. package/stories/ActivityIndicator/ActivityIndicator.stories.jsx +0 -22
  137. package/stories/Box/Box.stories.jsx +0 -143
  138. package/stories/Button/Button.stories.jsx +0 -72
  139. package/stories/Button/ButtonGroup.stories.jsx +0 -81
  140. package/stories/Button/ButtonLink.stories.jsx +0 -30
  141. package/stories/Card/Card.stories.jsx +0 -62
  142. package/stories/Checkbox/Checkbox.stories.jsx +0 -94
  143. package/stories/Divider/Divider.stories.jsx +0 -68
  144. package/stories/ExpandCollapse/ExpandCollapse.stories.jsx +0 -112
  145. package/stories/Feedback/Feedback.stories.jsx +0 -96
  146. package/stories/FlexGrid/01 FlexGrid.stories.jsx +0 -54
  147. package/stories/FlexGrid/02 Row.stories.jsx +0 -41
  148. package/stories/FlexGrid/03 Col.stories.jsx +0 -141
  149. package/stories/Icon/Icon.stories.jsx +0 -79
  150. package/stories/IconButton/IconButton.stories.jsx +0 -50
  151. package/stories/InputLabel/InputLabel.stories.jsx +0 -39
  152. package/stories/Link/ChevronLink.stories.jsx +0 -48
  153. package/stories/Link/Link.stories.jsx +0 -90
  154. package/stories/Link/TextButton.stories.jsx +0 -79
  155. package/stories/List/List.stories.jsx +0 -117
  156. package/stories/Modal/Modal.stories.jsx +0 -54
  157. package/stories/Notification/Notification.stories.jsx +0 -82
  158. package/stories/Pagination/Pagination.stories.jsx +0 -64
  159. package/stories/Progress/Progress.stories.jsx +0 -93
  160. package/stories/Radio/Radio.stories.jsx +0 -100
  161. package/stories/RadioCard/RadioCard.stories.jsx +0 -98
  162. package/stories/Search/Search.stories.jsx +0 -66
  163. package/stories/Select/Select.stories.jsx +0 -55
  164. package/stories/SideNav/SideNav.stories.jsx +0 -42
  165. package/stories/SideNav/SideNavItem.stories.jsx +0 -9
  166. package/stories/SideNav/SideNavItemsGroup.stories.jsx +0 -17
  167. package/stories/Skeleton/Skeleton.stories.jsx +0 -36
  168. package/stories/Spacer/Spacer.stories.jsx +0 -38
  169. package/stories/StackView/StackView.stories.jsx +0 -75
  170. package/stories/StackView/StackWrap.stories.jsx +0 -64
  171. package/stories/StepTracker/StepTracker.stories.jsx +0 -71
  172. package/stories/Tabs/Tabs.stories.jsx +0 -97
  173. package/stories/Tags/Tags.stories.jsx +0 -69
  174. package/stories/TextInput/TextArea.stories.jsx +0 -101
  175. package/stories/TextInput/TextInput.stories.jsx +0 -141
  176. package/stories/ToggleSwitch/ToggleSwitch.stories.jsx +0 -64
  177. package/stories/ToggleSwitch/ToggleSwitchGroup.stories.jsx +0 -81
  178. package/stories/Tooltip/Tooltip.stories.jsx +0 -81
  179. package/stories/TooltipButton/TooltipButton.stories.jsx +0 -11
  180. package/stories/Typography/Typography.stories.jsx +0 -49
  181. package/stories/platform-supports.jsx +0 -32
  182. package/stories/platform-supports.native.jsx +0 -3
  183. package/stories/supports.jsx +0 -236
@@ -32,7 +32,8 @@ const textProps = {
32
32
  const inputValueProps = {
33
33
  value: _propTypes.default.string,
34
34
  initialValue: _propTypes.default.string,
35
- readOnly: _propTypes.default.bool
35
+ readOnly: _propTypes.default.bool,
36
+ inactive: _propTypes.default.bool
36
37
  };
37
38
  /**
38
39
  * This collection adds props that can be passed through to both React Native's
@@ -4,6 +4,7 @@ import ABBPropTypes from 'airbnb-prop-types';
4
4
  import Platform from "react-native-web/dist/exports/Platform";
5
5
  import ButtonBase from './ButtonBase';
6
6
  import { StackWrap } from '../StackView';
7
+ import Fieldset from '../Fieldset';
7
8
  import { useViewport } from '../ViewportProvider';
8
9
  import { useThemeTokens, useThemeTokensCallback } from '../ThemeProvider';
9
10
  import { a11yProps, containUniqueFields, focusHandlerProps, pressProps, getTokensPropType, selectSystemProps, selectTokens, useMultipleInputValues, variantProp, viewProps } from '../utils';
@@ -21,6 +22,13 @@ const ButtonGroup = /*#__PURE__*/forwardRef(({
21
22
  onChange,
22
23
  readOnly = false,
23
24
  inactive = false,
25
+ legend,
26
+ tooltip,
27
+ hint,
28
+ validation,
29
+ feedback,
30
+ name: inputGroupName,
31
+ copy,
24
32
  accessibilityRole = maxValues === 1 ? 'radiogroup' // radiogroup is cross-platform; only web aria has generic groups
25
33
  : Platform.select({
26
34
  web: 'group',
@@ -35,7 +43,8 @@ const ButtonGroup = /*#__PURE__*/forwardRef(({
35
43
  const stackTokens = selectTokens('StackView', themeTokens);
36
44
  const {
37
45
  direction,
38
- space
46
+ space,
47
+ fieldSpace
39
48
  } = themeTokens;
40
49
  const getButtonTokens = useThemeTokensCallback('ButtonGroupItem', tokens, variant);
41
50
  const {
@@ -57,54 +66,71 @@ const ButtonGroup = /*#__PURE__*/forwardRef(({
57
66
 
58
67
  if (!containUniqueFields(items, uniqueFields)) {
59
68
  throw new Error(`ButtonGroup items must have unique ${uniqueFields.join(', ')}`);
60
- }
69
+ } // Some web screenreaders e.g. MacOS Voiceover don't handle radiogroups properly unless radio is direct child of radiogroup
61
70
 
62
- return /*#__PURE__*/_jsx(StackWrap, { ...systemProps,
63
- space: space,
64
- direction: direction,
65
- tokens: stackTokens,
71
+
72
+ const innerRole = Platform.OS === 'web' && accessibilityRole === 'radiogroup' ? accessibilityRole : undefined;
73
+ return /*#__PURE__*/_jsx(Fieldset, { ...systemProps,
66
74
  ref: ref,
67
- children: items.map(({
68
- label,
69
- id = label,
70
- accessibilityLabel,
71
- ref: itemRef,
72
- ...itemRest
73
- }, index) => {
74
- const isSelected = currentValues.includes(id); // Pass an object of relevant component state as first argument for any passed-in press handlers
75
-
76
- const pressHandlers = getPressHandlersWithArgs(rest, [{
77
- id,
75
+ name: inputGroupName,
76
+ legend: legend,
77
+ tooltip: tooltip,
78
+ hint: hint,
79
+ space: fieldSpace,
80
+ feedback: feedback,
81
+ readOnly: readOnly,
82
+ inactive: inactive,
83
+ validation: validation,
84
+ accessibilityRole: accessibilityRole,
85
+ ...selectProps(rest),
86
+ children: /*#__PURE__*/_jsx(StackWrap, {
87
+ accessibilityRole: innerRole,
88
+ space: space,
89
+ direction: direction,
90
+ tokens: stackTokens,
91
+ ref: ref,
92
+ children: items.map(({
78
93
  label,
79
- currentValues
80
- }]);
81
-
82
- const handlePress = event => {
83
- if (pressHandlers.onPress) pressHandlers.onPress(event);
84
- toggleOneValue(id, event);
85
- };
86
-
87
- const itemA11y = {
88
- accessibilityState: {
89
- checked: isSelected
90
- },
91
- accessibilityRole: itemA11yRole,
94
+ id = label,
92
95
  accessibilityLabel,
93
- ...a11yProps.getPositionInSet(items.length, index)
94
- }; // Ensure button is direct child of group as MacOS voiceover only applies "X of Y" to
95
- // "radio" if it's a direct child of "radiogroup", even if aria-posinset etc exists
96
-
97
- return /*#__PURE__*/_jsx(ButtonBase, {
98
96
  ref: itemRef,
99
- ...pressHandlers,
100
- onPress: handlePress,
101
- tokens: getButtonTokens,
102
- selected: isSelected,
103
- inactive: inactive,
104
- ...itemA11y,
105
- ...selectItemProps(itemRest),
106
- children: label
107
- }, id);
97
+ ...itemRest
98
+ }, index) => {
99
+ const isSelected = currentValues.includes(id); // Pass an object of relevant component state as first argument for any passed-in press handlers
100
+
101
+ const pressHandlers = getPressHandlersWithArgs(rest, [{
102
+ id,
103
+ label,
104
+ currentValues
105
+ }]);
106
+
107
+ const handlePress = event => {
108
+ if (pressHandlers.onPress) pressHandlers.onPress(event);
109
+ toggleOneValue(id, event);
110
+ };
111
+
112
+ const itemA11y = {
113
+ accessibilityState: {
114
+ checked: isSelected
115
+ },
116
+ accessibilityRole: itemA11yRole,
117
+ accessibilityLabel,
118
+ ...a11yProps.getPositionInSet(items.length, index)
119
+ }; // Ensure button is direct child of group as MacOS voiceover only applies "X of Y" to
120
+ // "radio" if it's a direct child of "radiogroup", even if aria-posinset etc exists
121
+
122
+ return /*#__PURE__*/_jsx(ButtonBase, {
123
+ ref: itemRef,
124
+ ...pressHandlers,
125
+ onPress: handlePress,
126
+ tokens: getButtonTokens,
127
+ selected: isSelected,
128
+ inactive: inactive,
129
+ ...itemA11y,
130
+ ...selectItemProps(itemRest),
131
+ children: label
132
+ }, id);
133
+ })
108
134
  })
109
135
  });
110
136
  });
@@ -168,6 +194,52 @@ ButtonGroup.propTypes = { ...selectedSystemPropTypes,
168
194
  * managing its own selected state, a default set of selections may be provided.
169
195
  * Changing the `initialValues` does not change the user's selections.
170
196
  */
171
- initialValues: PropTypes.arrayOf(PropTypes.string)
197
+ initialValues: PropTypes.arrayOf(PropTypes.string),
198
+
199
+ /**
200
+ * Main text used to describe this group, used in Fieldset's Legend element.
201
+ */
202
+ legend: PropTypes.string,
203
+
204
+ /**
205
+ * Optional additional text giving more detail to help a user make a choice.
206
+ */
207
+ hint: PropTypes.string,
208
+
209
+ /**
210
+ * Optional tooltip text content to include alongside the legend and hint.
211
+ */
212
+ tooltip: PropTypes.string,
213
+
214
+ /**
215
+ * Current validation status of the group, passed to the feedback element if there is one.
216
+ */
217
+ validation: PropTypes.oneOf(['error', 'success']),
218
+
219
+ /**
220
+ * If provided, a Feedback element is rendered containing this text.
221
+ */
222
+ feedback: PropTypes.string,
223
+
224
+ /**
225
+ * If true, the buttons cannot be selected by the user and simply show their current state.
226
+ */
227
+ readOnly: PropTypes.bool,
228
+
229
+ /**
230
+ * If true, the buttons cannot be interacted with, elements are set as `disabled` and if the
231
+ * theme supports `inactive` appearances rules, these are applied.
232
+ */
233
+ inactive: PropTypes.bool,
234
+
235
+ /**
236
+ * On Web, this is passed to the `name` attribute of the fieldset.
237
+ */
238
+ name: PropTypes.string,
239
+
240
+ /**
241
+ * Sets the language of microcopy in subcomponents (e.g. Tooltip's default accessibility label).
242
+ */
243
+ copy: PropTypes.oneOf(['en', 'fr'])
172
244
  };
173
245
  export default ButtonGroup;
@@ -213,18 +213,18 @@ CheckboxGroup.propTypes = { ...selectedSystemPropTypes,
213
213
  onChange: PropTypes.func,
214
214
 
215
215
  /**
216
- * If true, the radio cards cannot be selected by the user and simply show their current state.
216
+ * If true, the checkboxes cannot be selected by the user and simply show their current state.
217
217
  */
218
218
  readOnly: PropTypes.bool,
219
219
 
220
220
  /**
221
- * If true, the checkbox cannot be interacted with, elements are set as `disabled` and if the
221
+ * If true, the checkboxes cannot be interacted with, elements are set as `disabled` and if the
222
222
  * theme supports `inactive` appearances rules, these are applied.
223
223
  */
224
224
  inactive: PropTypes.bool,
225
225
 
226
226
  /**
227
- * On Web, this is passed to the `name` attribute of the fieldset and each radio input.
227
+ * On Web, this is passed to the `name` attribute of the fieldset and each checkbox input.
228
228
  */
229
229
  name: PropTypes.string
230
230
  };
@@ -75,7 +75,7 @@ const ExpandCollapsePanel = /*#__PURE__*/forwardRef(({
75
75
  }
76
76
  };
77
77
 
78
- const animatedStyles = useVerticalExpandAnimation({
78
+ const [animatedStyles, animatedRef] = useVerticalExpandAnimation({
79
79
  containerHeight,
80
80
  isExpanded,
81
81
  tokens: themeTokens
@@ -96,6 +96,7 @@ const ExpandCollapsePanel = /*#__PURE__*/forwardRef(({
96
96
  onPress: handleControlPress,
97
97
  children: control
98
98
  }), /*#__PURE__*/_jsx(Animated.View, {
99
+ ref: animatedRef,
99
100
  style: [overflowContainerStyles, animatedStyles, staticStyles.itemsContainer],
100
101
  ...focusabilityProps,
101
102
  children: /*#__PURE__*/_jsx(View, {
@@ -17,6 +17,7 @@ import Legend from './Legend';
17
17
  import { jsx as _jsx } from "react/jsx-runtime";
18
18
  import { Fragment as _Fragment } from "react/jsx-runtime";
19
19
  const Fieldset = /*#__PURE__*/forwardRef(({
20
+ copy = 'en',
20
21
  space,
21
22
  feedback,
22
23
  feedbackPosition = 'top',
@@ -44,6 +45,7 @@ const Fieldset = /*#__PURE__*/forwardRef(({
44
45
 
45
46
  const legendContent = legend && /*#__PURE__*/_jsx(Legend, {
46
47
  children: /*#__PURE__*/_jsx(InputLabel, {
48
+ copy: copy,
47
49
  label: legend,
48
50
  hint: hint,
49
51
  hintPosition: hintPosition,
@@ -83,6 +85,11 @@ Fieldset.displayName = 'Fieldset';
83
85
  Fieldset.propTypes = {
84
86
  children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
85
87
 
88
+ /**
89
+ * Whether the English or French copy will be used (e.g. for accessibility labels).
90
+ */
91
+ copy: PropTypes.oneOf(['en', 'fr']),
92
+
86
93
  /**
87
94
  * The accessibility role of the `<fieldset>` element itself. Other React Native accessibility
88
95
  * props are not supported because there is not an appropriate counterpart for Fieldsets.
@@ -35,6 +35,7 @@ const selectGapStyles = ({
35
35
  });
36
36
 
37
37
  const InputLabel = /*#__PURE__*/forwardRef(({
38
+ copy = 'en',
38
39
  label,
39
40
  forId,
40
41
  hint,
@@ -68,7 +69,8 @@ const InputLabel = /*#__PURE__*/forwardRef(({
68
69
  height: themeTokens.fontSize * themeTokens.lineHeight
69
70
  }],
70
71
  children: /*#__PURE__*/_jsx(Tooltip, {
71
- content: tooltip
72
+ content: tooltip,
73
+ copy: copy
72
74
  })
73
75
  })]
74
76
  }), hint && !isHintInline && /*#__PURE__*/_jsx(Text, {
@@ -81,6 +83,11 @@ const InputLabel = /*#__PURE__*/forwardRef(({
81
83
  InputLabel.displayName = 'InputLabel';
82
84
  InputLabel.propTypes = { ...selectedSystemPropTypes,
83
85
 
86
+ /**
87
+ * Whether the English or French copy will be used (e.g. for accessibility labels).
88
+ */
89
+ copy: PropTypes.oneOf(['en', 'fr']),
90
+
84
91
  /**
85
92
  * The input label.
86
93
  */
@@ -9,6 +9,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
9
9
  import { jsxs as _jsxs } from "react/jsx-runtime";
10
10
  const InputSupports = /*#__PURE__*/forwardRef(({
11
11
  children,
12
+ copy = 'en',
12
13
  label,
13
14
  hint,
14
15
  hintPosition = 'inline',
@@ -34,6 +35,7 @@ const InputSupports = /*#__PURE__*/forwardRef(({
34
35
  space: space,
35
36
  ref: ref,
36
37
  children: [label && /*#__PURE__*/_jsx(InputLabel, {
38
+ copy: copy,
37
39
  label: label,
38
40
  hint: hint,
39
41
  hintPosition: hintPosition,
@@ -54,6 +56,11 @@ InputSupports.displayName = 'InputSupports';
54
56
  InputSupports.propTypes = {
55
57
  children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
56
58
 
59
+ /**
60
+ * Whether the English or French copy will be used (e.g. for accessibility labels).
61
+ */
62
+ copy: PropTypes.oneOf(['en', 'fr']),
63
+
57
64
  /**
58
65
  * The input label.
59
66
  */
@@ -177,7 +177,7 @@ Notification.propTypes = { ...selectedSystemPropTypes,
177
177
  dismissible: PropTypes.bool,
178
178
 
179
179
  /**
180
- * Select english or french copy for the accessible label of the dismiss button.
180
+ * Select English or French copy for the accessible label of the dismiss button.
181
181
  */
182
182
  copy: PropTypes.oneOfType([PropTypes.oneOf(['en', 'fr']), PropTypes.shape({
183
183
  dismiss: PropTypes.string
@@ -29,7 +29,7 @@ const [selectItemProps, selectedItemPropTypes] = selectSystemProps([a11yProps, f
29
29
  * ### Uncontrolled version
30
30
  *
31
31
  * If the RadioGroup manages its own state, you can use `initialCheckedId` prop to provide the initial value.
32
- * Whenever the radio card gets toggled, it calls the `onChange` callback with the new value (string).
32
+ * Whenever the radio gets toggled, it calls the `onChange` callback with the new value (string).
33
33
  *
34
34
  * ### Use in forms
35
35
  *
@@ -60,6 +60,7 @@ const [selectItemProps, selectedItemPropTypes] = selectSystemProps([a11yProps, f
60
60
  */
61
61
 
62
62
  const RadioGroup = /*#__PURE__*/forwardRef(({
63
+ copy = 'en',
63
64
  tokens,
64
65
  radioTokens,
65
66
  variant,
@@ -128,6 +129,7 @@ const RadioGroup = /*#__PURE__*/forwardRef(({
128
129
  }, radioId);
129
130
  });
130
131
  return /*#__PURE__*/_jsx(Fieldset, {
132
+ copy: copy,
131
133
  ref: ref,
132
134
  name: inputGroupName,
133
135
  legend: legend,
@@ -148,6 +150,11 @@ const RadioGroup = /*#__PURE__*/forwardRef(({
148
150
  RadioGroup.displayName = 'RadioGroup';
149
151
  RadioGroup.propTypes = { ...selectedSystemPropTypes,
150
152
 
153
+ /**
154
+ * Whether the English or French copy will be used (e.g. for accessibility labels).
155
+ */
156
+ copy: PropTypes.oneOf(['en', 'fr']),
157
+
151
158
  /**
152
159
  * Optional theme token overrides for the outer RadioGroup component
153
160
  */
@@ -199,12 +206,12 @@ RadioGroup.propTypes = { ...selectedSystemPropTypes,
199
206
  feedback: PropTypes.string,
200
207
 
201
208
  /**
202
- * If provided, the radio card with this id is selected on first render.
209
+ * If provided, the radio with this id is selected on first render.
203
210
  */
204
211
  initialCheckedId: PropTypes.string,
205
212
 
206
213
  /**
207
- * If not undefined, the radio card with this id is selected (or none is selected if `null`), and the
214
+ * If not undefined, the radio with this id is selected (or none is selected if `null`), and the
208
215
  * element's selection state will be controlled by its parent using the `onChange` function.
209
216
  */
210
217
  checkedId: PropTypes.string,
@@ -216,12 +223,12 @@ RadioGroup.propTypes = { ...selectedSystemPropTypes,
216
223
  onChange: PropTypes.func,
217
224
 
218
225
  /**
219
- * If true, the radio cards cannot be selected by the user and simply show their current state.
226
+ * If true, the radios cannot be selected by the user and simply show their current state.
220
227
  */
221
228
  readOnly: PropTypes.bool,
222
229
 
223
230
  /**
224
- * If true, the radio card cannot be interacted with, elements are set as `disabled` and if the
231
+ * If true, the radios cannot be interacted with, elements are set as `disabled` and if the
225
232
  * theme supports `inactive` appearances rules, these are applied.
226
233
  */
227
234
  inactive: PropTypes.bool,
@@ -61,6 +61,7 @@ const [selectItemProps, selectedItemPropTypes] = selectSystemProps([a11yProps, f
61
61
  */
62
62
 
63
63
  const RadioCardGroup = /*#__PURE__*/forwardRef(({
64
+ copy = 'en',
64
65
  tokens,
65
66
  radioCardTokens,
66
67
  variant,
@@ -106,6 +107,7 @@ const RadioCardGroup = /*#__PURE__*/forwardRef(({
106
107
  }
107
108
 
108
109
  return /*#__PURE__*/_jsx(Fieldset, {
110
+ copy: copy,
109
111
  ref: ref,
110
112
  name: inputGroupName,
111
113
  legend: legend,
@@ -155,6 +157,11 @@ const RadioCardGroup = /*#__PURE__*/forwardRef(({
155
157
  RadioCardGroup.displayName = 'RadioCardGroup';
156
158
  RadioCardGroup.propTypes = { ...selectedSystemPropTypes,
157
159
 
160
+ /**
161
+ * Whether the English or French copy will be used (e.g. for accessibility labels).
162
+ */
163
+ copy: PropTypes.oneOf(['en', 'fr']),
164
+
158
165
  /**
159
166
  * Optional theme token overrides for the outer RadioCardGroup component
160
167
  */
@@ -216,7 +216,7 @@ Search.propTypes = { ...selectedContainerPropTypes,
216
216
  accessibilityLabel: PropTypes.string,
217
217
 
218
218
  /**
219
- * Select english or french copy for the accessible labels.
219
+ * Select English or French copy for the accessible labels.
220
220
  * You may also pass in a custom dictionary object.
221
221
  */
222
222
  copy: PropTypes.oneOfType([PropTypes.oneOf(['en', 'fr']), PropTypes.shape({
@@ -4,7 +4,7 @@ import Platform from "react-native-web/dist/exports/Platform";
4
4
  import propTypes from 'prop-types';
5
5
  import StackView from '../StackView';
6
6
  import { useThemeTokens } from '../ThemeProvider';
7
- import { a11yProps, getTokensPropType, selectSystemProps, useSpacingScale, variantProp, viewProps } from '../utils';
7
+ import { a11yProps, getTokensPropType, selectSystemProps, responsiveProps, useResponsiveProp, useSpacingScale, spacingProps, variantProp, viewProps } from '../utils';
8
8
  import useSkeletonNativeAnimation from './useSkeletonNativeAnimation';
9
9
  import skeletonWebAnimation from './skeletonWebAnimation';
10
10
  import { jsx as _jsx } from "react/jsx-runtime";
@@ -45,13 +45,23 @@ const Skeleton = /*#__PURE__*/forwardRef(({
45
45
  tokens,
46
46
  variant,
47
47
  size,
48
+ sizeIndex = size,
49
+ sizePixels,
48
50
  characters,
49
51
  lines,
50
52
  shape = 'line',
51
53
  ...rest
52
54
  }, ref) => {
53
55
  const themeTokens = useThemeTokens('Skeleton', tokens, variant);
54
- const skeletonHeight = useSpacingScale(size || themeTokens.size);
56
+ const pixels = useResponsiveProp(sizePixels);
57
+ const spacingScaleValue = typeof pixels === 'number' ? // Size by an exact number of pixels
58
+ {
59
+ options: {
60
+ size: pixels
61
+ }
62
+ } : // Size by an index on the spacing scale (getting default index from theme if none provided)
63
+ sizeIndex || themeTokens.size;
64
+ const skeletonHeight = useSpacingScale(spacingScaleValue);
55
65
  const nativeAnimation = useSkeletonNativeAnimation();
56
66
 
57
67
  const getAnimationBaseOnPlatform = () => {
@@ -109,9 +119,45 @@ Skeleton.displayName = 'Skeleton';
109
119
  Skeleton.propTypes = { ...selectedSystemPropTypes,
110
120
  tokens: getTokensPropType('Skeleton'),
111
121
  variant: variantProp.propType,
112
- size: propTypes.number,
122
+
123
+ /**
124
+ * Sets the size of Skeleton lines or shape according to the theme's spacing scale. For example, size={1} gives the smallest non-zero theme-defined spacing size.
125
+ *
126
+ * May also accept an object with responsive viewport keys or spacing scale options - see `useSpacingScale` for details.
127
+ */
128
+ sizeIndex: spacingProps.types.spacingValue,
129
+
130
+ /**
131
+ * @deprecated alias for `sizeIndex`
132
+ */
133
+ size: spacingProps.types.spacingValue,
134
+
135
+ /**
136
+ * Sets the size of Skeleton lines or shape to an exact number of pixels. Use when it's necessary to exactly match sizes of images or other boxes.
137
+ *
138
+ * Accepts a number or an object with responsive viewport keys, e.g. { xs: 32, lg: 64 } would be 32px at xs, sm and md and 64 at lg and xl viewports.
139
+ */
140
+ sizePixels: responsiveProps.getTypeOptionallyByViewport(propTypes.number),
141
+
142
+ /**
143
+ * Determines the width of simulated lines of text if the Skeleton's shape is 'line' (the default shape).
144
+ *
145
+ * Only has any affect if shape is line (the default). If unset, takes a default value from the theme.
146
+ */
113
147
  characters: propTypes.number,
148
+
149
+ /**
150
+ * Determines how many Skeleton items are rendered (default 1).
151
+ *
152
+ * Recommended usage is to simulate paragraphs of text when Skeleton's shape is 'line' (the default shape).
153
+ *
154
+ * The amount of spacing between multiple lines is controlled by theme tokens.
155
+ */
114
156
  lines: propTypes.number,
157
+
158
+ /**
159
+ * Determines if the skeleton should resemble lines of text (default), a circle, or a square box with themed rounded corners.
160
+ */
115
161
  shape: propTypes.oneOf(['line', 'circle', 'box'])
116
162
  };
117
163
  export default Skeleton;
@@ -83,6 +83,7 @@ const selectLabelTokens = ({
83
83
  });
84
84
 
85
85
  const ToggleSwitch = /*#__PURE__*/forwardRef(({
86
+ copy = 'en',
86
87
  value,
87
88
  initialValue,
88
89
  onChange,
@@ -119,6 +120,7 @@ const ToggleSwitch = /*#__PURE__*/forwardRef(({
119
120
  children: [Boolean(label) && /*#__PURE__*/_jsx(View, {
120
121
  style: [selectLabelStyles(themeTokens), staticStyles.containText],
121
122
  children: /*#__PURE__*/_jsx(InputLabel, {
123
+ copy: copy,
122
124
  forId: inputId,
123
125
  label: label,
124
126
  tokens: selectLabelTokens(themeTokens),
@@ -167,6 +169,11 @@ const ToggleSwitch = /*#__PURE__*/forwardRef(({
167
169
  });
168
170
  ToggleSwitch.displayName = 'ToggleSwitch';
169
171
  ToggleSwitch.propTypes = { ...selectedSystemPropTypes,
172
+
173
+ /**
174
+ * Whether the English or French copy will be used (e.g. for accessibility labels).
175
+ */
176
+ copy: PropTypes.oneOf(['en', 'fr']),
170
177
  tokens: getTokensPropType('ToggleSwitch'),
171
178
  variant: variantProp.propType,
172
179
 
@@ -12,6 +12,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
12
12
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
13
13
  const [selectItemProps, selectedItemPropTypes] = selectSystemProps([a11yProps, focusHandlerProps, viewProps]);
14
14
  const ToggleSwitchGroup = /*#__PURE__*/forwardRef(({
15
+ copy = 'en',
15
16
  variant,
16
17
  tokens,
17
18
  items = [],
@@ -88,6 +89,7 @@ const ToggleSwitchGroup = /*#__PURE__*/forwardRef(({
88
89
  ...a11yProps.getPositionInSet(items.length, index)
89
90
  };
90
91
  return /*#__PURE__*/_jsx(ToggleSwitch, {
92
+ copy: copy,
91
93
  id: id,
92
94
  ref: itemRef,
93
95
  onChange: handleChange,
@@ -119,6 +121,11 @@ const ToggleSwitchGroup = /*#__PURE__*/forwardRef(({
119
121
  });
120
122
  ToggleSwitchGroup.displayName = 'ToggleSwitchGroup';
121
123
  ToggleSwitchGroup.propTypes = { ...selectedSystemPropTypes,
124
+
125
+ /**
126
+ * Whether the English or French copy will be used (e.g. for accessibility labels).
127
+ */
128
+ copy: PropTypes.oneOf(['en', 'fr']),
122
129
  tokens: getTokensPropType('ToggleSwitchGroup'),
123
130
  variant: variantProp.propType,
124
131
 
@@ -301,7 +301,7 @@ Tooltip.propTypes = { ...selectedSystemPropTypes,
301
301
  content: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
302
302
 
303
303
  /**
304
- * Select english or french copy for the accessible label.
304
+ * Select English or French copy for the accessible label.
305
305
  */
306
306
  copy: PropTypes.oneOf(['en', 'fr']),
307
307
 
@@ -1,4 +1,4 @@
1
- import { useEffect, useRef } from 'react';
1
+ import { useEffect, useRef, useState } from 'react';
2
2
  import Animated from "react-native-web/dist/exports/Animated";
3
3
  import Easing from "react-native-web/dist/exports/Easing";
4
4
  import Platform from "react-native-web/dist/exports/Platform"; // TODO: systematise animations
@@ -9,14 +9,25 @@ function useVerticalExpandAnimation({
9
9
  isExpanded,
10
10
  tokens
11
11
  }) {
12
+ const [isAnimating, setIsAnimating] = useState(false);
12
13
  const expandAnimatedValue = useRef(new Animated.Value(0)).current;
14
+ const elementRef = useRef(null);
13
15
  const {
14
16
  expandDuration,
15
17
  collapseDuration
16
- } = tokens;
18
+ } = tokens; // Treat as animating from when expanded state changes, until animation completes
19
+
20
+ useEffect(() => setIsAnimating(true), [isExpanded]);
17
21
  useEffect(() => {
22
+ const onComplete = () => !isExpanded && setIsAnimating(false);
23
+
18
24
  if (Platform.OS === 'web') {
19
- return;
25
+ if (!elementRef.current) return () => {}; // React Native Web does not pass `onTransitionEnd` through, must attach manually.
26
+ // https://github.com/necolas/react-native-web/pull/1713
27
+
28
+ const element = elementRef.current;
29
+ element.addEventListener('transitionend', onComplete);
30
+ return () => element.removeEventListener('transitionend', onComplete);
20
31
  }
21
32
 
22
33
  const animationConfig = {
@@ -25,25 +36,26 @@ function useVerticalExpandAnimation({
25
36
  toValue: isExpanded ? containerHeight : 0,
26
37
  useNativeDriver: false
27
38
  };
28
- Animated.timing(expandAnimatedValue, animationConfig).start();
29
- }, [isExpanded, expandAnimatedValue, containerHeight, expandDuration, collapseDuration]);
30
- let containerStyles; // don't visually collapse the container until we have it measured
39
+ const animation = Animated.timing(expandAnimatedValue, animationConfig);
40
+ animation.start(onComplete);
41
+ return () => animation.stop();
42
+ }, [isExpanded, expandAnimatedValue, containerHeight, expandDuration, collapseDuration]); // Without `visibility: 'hidden', descendents are focusable on web even when collapsed
43
+
44
+ const containerStyles = !isExpanded && !isAnimating ? {
45
+ visibility: 'hidden'
46
+ } : {}; // don't visually collapse the container until we have it measured
31
47
 
32
48
  if (containerHeight !== null) {
33
49
  if (Platform.OS === 'web') {
34
50
  const transitionDuration = isExpanded ? expandDuration : collapseDuration;
35
- containerStyles = {
36
- transition: `height ${transitionDuration}ms ease-in-out`,
37
- height: isExpanded ? containerHeight : 0
38
- };
51
+ containerStyles.transition = `height ${transitionDuration}ms ease-in-out`;
52
+ containerStyles.height = isExpanded ? containerHeight : 0;
39
53
  } else {
40
- containerStyles = {
41
- height: expandAnimatedValue
42
- };
54
+ containerStyles.height = expandAnimatedValue;
43
55
  }
44
56
  }
45
57
 
46
- return containerStyles;
58
+ return [containerStyles, elementRef];
47
59
  }
48
60
 
49
61
  export default useVerticalExpandAnimation;