@telus-uds/components-base 0.0.2-prerelease.9 → 1.0.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 (282) hide show
  1. package/.eslintrc.js +9 -0
  2. package/.ultra.cache.json +1 -1
  3. package/CHANGELOG.md +32 -0
  4. package/README.md +4 -2
  5. package/__fixtures__/test-utils.js +25 -0
  6. package/__fixtures__/testTheme.js +4 -2
  7. package/__tests__/Button/ButtonGroup.test.jsx +4 -5
  8. package/__tests__/Checkbox/Checkbox.test.jsx +2 -2
  9. package/__tests__/Checkbox/CheckboxGroup.test.jsx +4 -5
  10. package/__tests__/ExpandCollapse/ExpandCollapse.test.jsx +2 -2
  11. package/__tests__/HorizontalScroll/HorizontalScroll.test.jsx +164 -0
  12. package/__tests__/Link/LinkBase.test.jsx +0 -14
  13. package/__tests__/Radio/Radio.test.jsx +2 -2
  14. package/__tests__/Radio/RadioGroup.test.jsx +4 -5
  15. package/__tests__/RadioCard/RadioCard.test.jsx +2 -2
  16. package/__tests__/RadioCard/RadioCardGroup.test.jsx +4 -5
  17. package/__tests__/Search/Search.test.jsx +9 -8
  18. package/__tests__/Select/Select.test.jsx +3 -2
  19. package/__tests__/Tabs/Tabs.test.jsx +1 -161
  20. package/__tests__/Tags/Tags.test.jsx +4 -5
  21. package/__tests__/TextInput/TextArea.test.jsx +3 -2
  22. package/__tests__/TextInput/TextInputBase.test.jsx +10 -5
  23. package/__tests__/ThemeProvider/ThemeProvider.test.jsx +77 -0
  24. package/__tests__/ThemeProvider/useThemeTokens.test.jsx +9 -5
  25. package/__tests__/ThemeProvider/utils/theme-tokens.test.js +41 -0
  26. package/__tests__/ToggleSwitch/ToggleSwitch.test.jsx +3 -2
  27. package/__tests__/utils/children.test.jsx +128 -0
  28. package/__tests__/utils/input.test.js +1 -1
  29. package/__tests__/utils/semantics.test.jsx +43 -0
  30. package/lib/A11yText/index.js +10 -5
  31. package/lib/ActivityIndicator/Spinner.js +16 -13
  32. package/lib/ActivityIndicator/Spinner.native.js +12 -8
  33. package/lib/Box/Box.js +102 -8
  34. package/lib/Button/Button.js +9 -8
  35. package/lib/Button/ButtonBase.js +14 -7
  36. package/lib/Button/ButtonGroup.js +25 -10
  37. package/lib/Button/ButtonLink.js +10 -7
  38. package/lib/Card/Card.js +2 -0
  39. package/lib/Card/CardBase.js +12 -5
  40. package/lib/Card/PressableCardBase.js +12 -8
  41. package/lib/Checkbox/Checkbox.js +25 -14
  42. package/lib/Checkbox/CheckboxGroup.js +22 -12
  43. package/lib/Divider/Divider.js +12 -7
  44. package/lib/ExpandCollapse/Accordion.js +10 -4
  45. package/lib/ExpandCollapse/Control.js +12 -6
  46. package/lib/ExpandCollapse/ExpandCollapse.js +10 -5
  47. package/lib/ExpandCollapse/Panel.js +8 -7
  48. package/lib/Feedback/Feedback.js +10 -5
  49. package/lib/Fieldset/Fieldset.js +10 -5
  50. package/lib/Fieldset/FieldsetContainer.js +10 -5
  51. package/lib/Fieldset/FieldsetContainer.native.js +10 -5
  52. package/lib/Fieldset/Legend.js +10 -5
  53. package/lib/Fieldset/Legend.native.js +10 -5
  54. package/lib/FlexGrid/Col/Col.js +8 -5
  55. package/lib/FlexGrid/FlexGrid.js +31 -6
  56. package/lib/FlexGrid/Row/Row.js +12 -5
  57. package/lib/{Tabs → HorizontalScroll}/HorizontalScroll.js +5 -4
  58. package/lib/{Tabs/TabsScrollButton.js → HorizontalScroll/HorizontalScrollButton.js} +14 -8
  59. package/lib/{Tabs → HorizontalScroll}/ScrollViewEnd.js +0 -0
  60. package/lib/{Tabs → HorizontalScroll}/ScrollViewEnd.native.js +0 -0
  61. package/lib/{Tabs → HorizontalScroll}/dictionary.js +0 -0
  62. package/lib/HorizontalScroll/index.js +35 -0
  63. package/lib/{Tabs → HorizontalScroll}/itemPositions.js +0 -0
  64. package/lib/Icon/Icon.js +16 -9
  65. package/lib/Icon/IconText.js +8 -7
  66. package/lib/IconButton/IconButton.js +10 -5
  67. package/lib/InputLabel/InputLabel.js +33 -5
  68. package/lib/InputLabel/LabelContent.js +22 -12
  69. package/lib/InputLabel/LabelContent.native.js +23 -5
  70. package/lib/InputSupports/InputSupports.js +10 -5
  71. package/lib/Link/ChevronLink.js +12 -5
  72. package/lib/Link/InlinePressable.js +10 -4
  73. package/lib/Link/InlinePressable.native.js +5 -4
  74. package/lib/Link/Link.js +12 -5
  75. package/lib/Link/LinkBase.js +12 -5
  76. package/lib/Link/TextButton.js +10 -5
  77. package/lib/List/List.js +5 -4
  78. package/lib/List/ListItem.js +16 -8
  79. package/lib/Modal/Modal.js +10 -5
  80. package/lib/Notification/Notification.js +21 -5
  81. package/lib/Pagination/PageButton.js +21 -10
  82. package/lib/Pagination/Pagination.js +12 -7
  83. package/lib/Pagination/SideButton.js +12 -7
  84. package/lib/Pagination/usePagination.js +2 -2
  85. package/lib/Progress/Progress.js +10 -5
  86. package/lib/Progress/ProgressBar.js +21 -10
  87. package/lib/Progress/ProgressBarBackground.js +12 -8
  88. package/lib/Radio/Radio.js +14 -13
  89. package/lib/Radio/RadioButton.js +20 -9
  90. package/lib/Radio/RadioGroup.js +24 -13
  91. package/lib/RadioCard/RadioCard.js +14 -10
  92. package/lib/RadioCard/RadioCardGroup.js +13 -12
  93. package/lib/Search/Search.js +29 -18
  94. package/lib/Select/Picker.js +11 -6
  95. package/lib/Select/Picker.native.js +21 -6
  96. package/lib/Select/Select.js +46 -4
  97. package/lib/SideNav/Item.js +10 -5
  98. package/lib/SideNav/ItemsGroup.js +10 -5
  99. package/lib/SideNav/SideNav.js +11 -7
  100. package/lib/Skeleton/Skeleton.js +15 -15
  101. package/lib/Skeleton/skeletonWebAnimation.js +1 -1
  102. package/lib/Spacer/Spacer.js +19 -7
  103. package/lib/StackView/StackView.js +25 -7
  104. package/lib/StackView/StackWrap.js +16 -9
  105. package/lib/StackView/StackWrapBox.js +33 -8
  106. package/lib/StackView/StackWrapGap.js +16 -7
  107. package/lib/StackView/common.js +4 -2
  108. package/lib/StackView/getStackedContent.js +2 -2
  109. package/lib/StepTracker/StepTracker.js +10 -5
  110. package/lib/Tabs/Tabs.js +26 -19
  111. package/lib/Tabs/TabsItem.js +16 -12
  112. package/lib/Tags/Tags.js +27 -11
  113. package/lib/TextInput/TextArea.js +7 -5
  114. package/lib/TextInput/TextInput.js +12 -6
  115. package/lib/TextInput/TextInputBase.js +12 -8
  116. package/lib/ThemeProvider/ThemeProvider.js +14 -10
  117. package/lib/ThemeProvider/useSetTheme.js +6 -1
  118. package/lib/ThemeProvider/utils/styles.js +2 -2
  119. package/lib/ThemeProvider/utils/theme-tokens.js +39 -8
  120. package/lib/ToggleSwitch/ToggleSwitch.js +11 -6
  121. package/lib/Tooltip/Backdrop.js +10 -2
  122. package/lib/Tooltip/Tooltip.js +5 -4
  123. package/lib/Typography/Typography.js +40 -24
  124. package/lib/index.js +21 -0
  125. package/lib/utils/a11y/index.js +13 -0
  126. package/lib/utils/a11y/semantics.js +173 -0
  127. package/lib/utils/animation/useVerticalExpandAnimation.js +1 -1
  128. package/lib/utils/children.js +55 -8
  129. package/lib/utils/input.js +27 -17
  130. package/lib/utils/propTypes.js +82 -29
  131. package/lib/utils/useCopy.js +1 -1
  132. package/lib/utils/useHash.js +8 -4
  133. package/lib/utils/useSpacingScale.js +1 -3
  134. package/lib/utils/useUniqueId.js +1 -1
  135. package/package.json +9 -5
  136. package/release-context.json +4 -4
  137. package/src/A11yText/index.jsx +6 -4
  138. package/src/ActivityIndicator/Spinner.jsx +5 -3
  139. package/src/ActivityIndicator/Spinner.native.jsx +5 -3
  140. package/src/Box/Box.jsx +124 -39
  141. package/src/Button/Button.jsx +7 -4
  142. package/src/Button/ButtonBase.jsx +86 -77
  143. package/src/Button/ButtonGroup.jsx +81 -69
  144. package/src/Button/ButtonLink.jsx +18 -13
  145. package/src/Card/Card.jsx +2 -2
  146. package/src/Card/CardBase.jsx +5 -4
  147. package/src/Card/PressableCardBase.jsx +71 -64
  148. package/src/Checkbox/Checkbox.jsx +118 -108
  149. package/src/Checkbox/CheckboxGroup.jsx +72 -62
  150. package/src/Divider/Divider.jsx +7 -4
  151. package/src/ExpandCollapse/Accordion.jsx +3 -2
  152. package/src/ExpandCollapse/Control.jsx +40 -43
  153. package/src/ExpandCollapse/ExpandCollapse.jsx +26 -23
  154. package/src/ExpandCollapse/Panel.jsx +69 -63
  155. package/src/Feedback/Feedback.jsx +36 -33
  156. package/src/Fieldset/Fieldset.jsx +63 -56
  157. package/src/Fieldset/FieldsetContainer.jsx +14 -5
  158. package/src/Fieldset/FieldsetContainer.native.jsx +7 -4
  159. package/src/Fieldset/Legend.jsx +7 -2
  160. package/src/Fieldset/Legend.native.jsx +7 -2
  161. package/src/FlexGrid/Col/Col.jsx +139 -132
  162. package/src/FlexGrid/FlexGrid.jsx +79 -51
  163. package/src/FlexGrid/Row/Row.jsx +55 -48
  164. package/src/HorizontalScroll/HorizontalScroll.jsx +168 -0
  165. package/src/HorizontalScroll/HorizontalScrollButton.jsx +105 -0
  166. package/src/{Tabs → HorizontalScroll}/ScrollViewEnd.jsx +0 -0
  167. package/src/{Tabs → HorizontalScroll}/ScrollViewEnd.native.jsx +0 -0
  168. package/src/{Tabs → HorizontalScroll}/dictionary.js +0 -0
  169. package/src/HorizontalScroll/index.js +17 -0
  170. package/src/{Tabs → HorizontalScroll}/itemPositions.js +0 -0
  171. package/src/Icon/Icon.jsx +37 -35
  172. package/src/Icon/IconText.jsx +22 -17
  173. package/src/IconButton/IconButton.jsx +49 -42
  174. package/src/InputLabel/InputLabel.jsx +53 -38
  175. package/src/InputLabel/LabelContent.jsx +14 -6
  176. package/src/InputLabel/LabelContent.native.jsx +11 -2
  177. package/src/InputSupports/InputSupports.jsx +29 -34
  178. package/src/Link/ChevronLink.jsx +26 -16
  179. package/src/Link/InlinePressable.jsx +5 -3
  180. package/src/Link/InlinePressable.native.jsx +5 -3
  181. package/src/Link/Link.jsx +22 -16
  182. package/src/Link/LinkBase.jsx +67 -58
  183. package/src/Link/TextButton.jsx +30 -23
  184. package/src/List/List.jsx +5 -4
  185. package/src/List/ListItem.jsx +77 -82
  186. package/src/Modal/Modal.jsx +9 -4
  187. package/src/Notification/Notification.jsx +58 -43
  188. package/src/Pagination/PageButton.jsx +42 -35
  189. package/src/Pagination/Pagination.jsx +88 -92
  190. package/src/Pagination/SideButton.jsx +44 -41
  191. package/src/Progress/Progress.jsx +5 -4
  192. package/src/Progress/ProgressBar.jsx +42 -29
  193. package/src/Progress/ProgressBarBackground.jsx +5 -3
  194. package/src/Radio/Radio.jsx +85 -78
  195. package/src/Radio/RadioButton.jsx +54 -43
  196. package/src/Radio/RadioGroup.jsx +74 -63
  197. package/src/RadioCard/RadioCard.jsx +75 -68
  198. package/src/RadioCard/RadioCardGroup.jsx +82 -75
  199. package/src/Search/Search.jsx +127 -106
  200. package/src/Select/Picker.jsx +49 -42
  201. package/src/Select/Picker.native.jsx +56 -49
  202. package/src/Select/Select.jsx +115 -72
  203. package/src/SideNav/Item.jsx +53 -46
  204. package/src/SideNav/ItemsGroup.jsx +50 -43
  205. package/src/SideNav/SideNav.jsx +68 -60
  206. package/src/Skeleton/Skeleton.jsx +9 -13
  207. package/src/Spacer/Spacer.jsx +11 -4
  208. package/src/StackView/StackView.jsx +46 -23
  209. package/src/StackView/StackWrap.jsx +7 -6
  210. package/src/StackView/StackWrapBox.jsx +61 -28
  211. package/src/StackView/StackWrapGap.jsx +46 -24
  212. package/src/StackView/common.jsx +3 -2
  213. package/src/StepTracker/StepTracker.jsx +73 -62
  214. package/src/Tabs/Tabs.jsx +70 -62
  215. package/src/Tabs/TabsItem.jsx +111 -103
  216. package/src/Tags/Tags.jsx +114 -102
  217. package/src/TextInput/TextArea.jsx +5 -4
  218. package/src/TextInput/TextInput.jsx +5 -4
  219. package/src/TextInput/TextInputBase.jsx +84 -77
  220. package/src/ThemeProvider/ThemeProvider.jsx +11 -7
  221. package/src/ThemeProvider/useSetTheme.js +4 -0
  222. package/src/ThemeProvider/utils/theme-tokens.js +28 -0
  223. package/src/ToggleSwitch/ToggleSwitch.jsx +49 -50
  224. package/src/Tooltip/Tooltip.jsx +134 -130
  225. package/src/Typography/Typography.jsx +67 -44
  226. package/src/index.js +2 -0
  227. package/src/utils/a11y/index.js +1 -0
  228. package/src/utils/a11y/semantics.js +162 -0
  229. package/src/utils/children.jsx +60 -7
  230. package/src/utils/input.js +20 -17
  231. package/src/utils/propTypes.js +101 -39
  232. package/src/utils/useCopy.js +1 -1
  233. package/src/utils/useHash.js +8 -3
  234. package/stories/A11yText/A11yText.stories.jsx +2 -2
  235. package/stories/ActivityIndicator/ActivityIndicator.stories.jsx +1 -1
  236. package/stories/Box/Box.stories.jsx +1 -1
  237. package/stories/Button/Button.stories.jsx +2 -2
  238. package/stories/Button/ButtonGroup.stories.jsx +1 -1
  239. package/stories/Button/ButtonLink.stories.jsx +1 -1
  240. package/stories/Card/Card.stories.jsx +1 -1
  241. package/stories/Checkbox/Checkbox.stories.jsx +1 -1
  242. package/stories/Divider/Divider.stories.jsx +1 -1
  243. package/stories/ExpandCollapse/ExpandCollapse.stories.jsx +2 -2
  244. package/stories/Feedback/Feedback.stories.jsx +1 -1
  245. package/stories/FlexGrid/01 FlexGrid.stories.jsx +1 -1
  246. package/stories/FlexGrid/02 Row.stories.jsx +1 -1
  247. package/stories/FlexGrid/03 Col.stories.jsx +1 -1
  248. package/stories/Icon/Icon.stories.jsx +1 -1
  249. package/stories/IconButton/IconButton.stories.jsx +1 -1
  250. package/stories/InputLabel/InputLabel.stories.jsx +1 -1
  251. package/stories/Link/ChevronLink.stories.jsx +1 -1
  252. package/stories/Link/Link.stories.jsx +1 -1
  253. package/stories/Link/TextButton.stories.jsx +1 -1
  254. package/stories/List/List.stories.jsx +1 -1
  255. package/stories/Modal/Modal.stories.jsx +1 -1
  256. package/stories/Notification/Notification.stories.jsx +1 -1
  257. package/stories/Pagination/Pagination.stories.jsx +1 -1
  258. package/stories/Progress/Progress.stories.jsx +1 -1
  259. package/stories/Radio/Radio.stories.jsx +1 -1
  260. package/stories/RadioCard/RadioCard.stories.jsx +1 -1
  261. package/stories/Search/Search.stories.jsx +1 -1
  262. package/stories/Select/Select.stories.jsx +1 -1
  263. package/stories/SideNav/SideNav.stories.jsx +1 -1
  264. package/stories/SideNav/SideNavItem.stories.jsx +1 -1
  265. package/stories/SideNav/SideNavItemsGroup.stories.jsx +1 -1
  266. package/stories/Skeleton/Skeleton.stories.jsx +2 -2
  267. package/stories/Spacer/Spacer.stories.jsx +1 -1
  268. package/stories/StackView/StackView.stories.jsx +1 -1
  269. package/stories/StackView/StackWrap.stories.jsx +1 -1
  270. package/stories/StepTracker/StepTracker.stories.jsx +1 -1
  271. package/stories/Tabs/Tabs.stories.jsx +1 -1
  272. package/stories/Tags/Tags.stories.jsx +1 -1
  273. package/stories/TextInput/TextArea.stories.jsx +1 -1
  274. package/stories/TextInput/TextInput.stories.jsx +1 -1
  275. package/stories/ToggleSwitch/ToggleSwitch.stories.jsx +1 -1
  276. package/stories/Tooltip/Tooltip.stories.jsx +1 -1
  277. package/stories/TooltipButton/TooltipButton.stories.jsx +1 -1
  278. package/stories/Typography/Typography.stories.jsx +1 -1
  279. package/stories/platform-supports.jsx +1 -1
  280. package/stories/supports.jsx +2 -2
  281. package/src/Tabs/HorizontalScroll.jsx +0 -165
  282. package/src/Tabs/TabsScrollButton.jsx +0 -100
@@ -0,0 +1,173 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getA11yPropsFromHtmlTag = exports.getHeadingLevel = exports.textTags = exports.layoutTags = exports.supportedTags = exports.headingTags = exports.tagsToRoles = void 0;
7
+
8
+ var _Platform = _interopRequireDefault(require("react-native-web/dist/cjs/exports/Platform"));
9
+
10
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
+
12
+ /**
13
+ * @typedef {import('react-native').AccessibilityRole} AccessibilityRole
14
+ */
15
+
16
+ /**
17
+ * This is based on the role-to-tag mapping that React Native Web uses to set HTML tags.
18
+ * It's not exported in any way from RNW, so we need to keep this up-to-date manually.
19
+ * https://github.com/necolas/react-native-web/blob/master/packages/react-native-web/src/modules/AccessibilityUtil/propsToAccessibilityComponent.js
20
+ *
21
+ * Note: every role in this list is a web-only aria-role. There is no overlap between _these_ web tags
22
+ * or roles and native accessibilityRoles. Only h1, h2, h3 etc map to an RN equivalent ("heading").
23
+ *
24
+ * - RN "summary" native role maps to "region" aria-role, but setting `<section>`/"region" does not
25
+ * set React Native's "summary" role, which has a much narrower use case.
26
+ * - `<Header>`/"Banner" also do not map to RN's "heading". Only h1 / h2 etc map to RN "heading".
27
+ *
28
+ * Therefore, all of these tags / roles default to no accessibilityRole in native apps. This is not wrong:
29
+ * in general, RN accessibilityRoles tend to be more about interaction and less about semantics than web roles.
30
+ *
31
+ * RNW's one-way mapping of React Native accessibilityRoles to web aria-roles:
32
+ * https://github.com/necolas/react-native-web/blob/master/packages/react-native-web/src/modules/AccessibilityUtil/propsToAriaRole.js
33
+ */
34
+ // Adding `/** @type {const} */ ({...})` denotes object content as `readonly` in many IDEs
35
+ // eslint-disable-next-line prettier/prettier
36
+ const rolesToTags =
37
+ /** @type {const} */
38
+ {
39
+ article: 'article',
40
+ banner: 'header',
41
+ blockquote: 'blockquote',
42
+ code: 'code',
43
+ complementary: 'aside',
44
+ contentinfo: 'footer',
45
+ deletion: 'del',
46
+ emphasis: 'em',
47
+ figure: 'figure',
48
+ insertion: 'ins',
49
+ form: 'form',
50
+ list: 'ul',
51
+ listitem: 'li',
52
+ main: 'main',
53
+ navigation: 'nav',
54
+ region: 'section',
55
+ strong: 'strong',
56
+ // Add special cases that are in RNW's function logic but not in its mapping object
57
+ label: 'label' // eslint-disable-next-line prettier/prettier
58
+
59
+ }; // Invert React Native Web's mapping, so a tag gets the role that gets that tag
60
+
61
+ const tagsToRoles = Object.fromEntries(Object.entries(rolesToTags).map(([key, value]) => [value, key]));
62
+ /**
63
+ * Heading HTML tags map to the "heading" accessibilityRole in native apps, which is similar
64
+ * to headings on web but without the expectation of a hierarchy of headings within one screen.
65
+ */
66
+ // eslint-disable-next-line prettier/prettier
67
+
68
+ exports.tagsToRoles = tagsToRoles;
69
+ const headingTags =
70
+ /** @type {const} */
71
+ ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
72
+ /**
73
+ * @typedef {typeof headingTags[number]} HeadingTag
74
+ */
75
+
76
+ /**
77
+ * All HTML tags that may be set via RNW accesibility props alone and therefore may be set using
78
+ * the getA11yPropsFromHtmlTag function without changing other behaviour.
79
+ *
80
+ * Of these, only headers (h1, h2, ...h5, h6) set a corresponding accessibilityRole in native apps ("heading").
81
+ */
82
+
83
+ exports.headingTags = headingTags;
84
+ const supportedTags = [...Object.keys(tagsToRoles), ...headingTags];
85
+ /**
86
+ * Uses readonly mapping keys/values to generate static types for IDEs that support TS in JSDoc.
87
+ * @typedef {keyof rolesToTags} RoleWithTag
88
+ * @typedef {typeof rolesToTags[RoleWithTag] | typeof headingTags[number]} SupportedTag
89
+ */
90
+
91
+ /**
92
+ * Subset of supported HTML tags that may be used with layout containers like Box.
93
+ *
94
+ * Of these, only headers (h1, h2, ...h5, h6) set a corresponding accessibilityRole in native apps ("heading").
95
+ */
96
+ // eslint-disable-next-line prettier/prettier
97
+
98
+ exports.supportedTags = supportedTags;
99
+ const layoutTags =
100
+ /** @type {const} */
101
+ [...headingTags, 'article', 'aside', 'blockquote', 'footer', 'figure', 'form', 'header', 'ul', 'li', 'main', 'nav', 'section', 'label' // eslint-disable-next-line prettier/prettier
102
+ ];
103
+ /**
104
+ * @typedef {typeof layoutTags[number]} LayoutTag
105
+ */
106
+
107
+ /**
108
+ * Subset of supported HTML tags that may be used with text elements like Typography.
109
+ *
110
+ * Of these, only headers (h1, h2, ...h5, h6) set a corresponding accessibilityRole in native apps ("heading").
111
+ */
112
+ // eslint-disable-next-line prettier/prettier
113
+
114
+ exports.layoutTags = layoutTags;
115
+ const textTags =
116
+ /** @type {const} */
117
+ [...headingTags, 'blockquote', 'code', 'del', 'em', 'ins', 'li', 'strong', 'label' // eslint-disable-next-line prettier/prettier
118
+ ];
119
+ /**
120
+ * @typedef {typeof layoutTags[number]} TextTag
121
+ */
122
+
123
+ /**
124
+ * If passed a heading tag string like 'h1', 'h2' etc, returns the heading number as a number
125
+ * ready for use in `accessibilityLevel` props and similar.
126
+ *
127
+ * @param {string} [tag] - HTML tag string; returns undefined if not a {@link HeadingTag}
128
+ * @returns {'1' | '2' | '3' | '4' | '5' | '6' | undefined}
129
+ */
130
+
131
+ exports.textTags = textTags;
132
+
133
+ const getHeadingLevel = tag => headingTags.includes(tag) ? Number(tag[1]) : undefined;
134
+ /**
135
+ * Takes a supported HTML tag, and returns the accessibility props that, on web, make React Native Web
136
+ * render that tag.
137
+ *
138
+ * For cross-platform apps, a second argument may be passed with an [accessibilityRole](https://reactnative.dev/docs/accessibility#accessibilityrole)
139
+ * to use in native apps. Heading tags (h1, h2, ...h5, h6) map to "heading" role by default;
140
+ * no other supported semantic HTML tags have an equivalent native accessibilityRole.
141
+ *
142
+ * @param {SupportedTag} tag - HTML tag to use on web
143
+ * @param {AccessibilityRole | null} [nativeRole] - optional accessibilityRole for native apps
144
+ * @returns {{ accessibilityRole: string, accessibilityLevel?: string } | undefined}
145
+ */
146
+
147
+
148
+ exports.getHeadingLevel = getHeadingLevel;
149
+
150
+ const getA11yPropsFromHtmlTag = (tag, nativeRole) => {
151
+ // Allow cross-platform apps to set accessibilityRoles alongside a web tag without conflict
152
+ if (nativeRole !== undefined && _Platform.default.OS !== 'web') return {
153
+ accessibilityRole: nativeRole
154
+ };
155
+
156
+ if (tag) {
157
+ const accessibilityRole = tagsToRoles[tag];
158
+ if (accessibilityRole) return {
159
+ accessibilityRole
160
+ };
161
+ const accessibilityLevel = getHeadingLevel(tag);
162
+ if (accessibilityLevel) return {
163
+ accessibilityRole: 'header',
164
+ accessibilityLevel
165
+ };
166
+ } // If nothing matches or no tag supplied, return undefined and let component decide how to fall back.
167
+ // Note that return value may always be spread in objects (it is safe to spread undefined like { ...undefined })
168
+
169
+
170
+ return undefined;
171
+ };
172
+
173
+ exports.getA11yPropsFromHtmlTag = getA11yPropsFromHtmlTag;
@@ -47,7 +47,7 @@ function useVerticalExpandAnimation({
47
47
  if (_Platform.default.OS === 'web') {
48
48
  const transitionDuration = isExpanded ? expandDuration : collapseDuration;
49
49
  containerStyles = {
50
- transition: "height ".concat(transitionDuration, "ms ease-in-out"),
50
+ transition: `height ${transitionDuration}ms ease-in-out`,
51
51
  height: isExpanded ? containerHeight : 0
52
52
  };
53
53
  } else {
@@ -9,6 +9,8 @@ var _react = _interopRequireWildcard(require("react"));
9
9
 
10
10
  var _Text = _interopRequireDefault(require("react-native-web/dist/cjs/exports/Text"));
11
11
 
12
+ var _A11yText = _interopRequireDefault(require("../A11yText"));
13
+
12
14
  var _jsxRuntime = require("react/jsx-runtime");
13
15
 
14
16
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -59,16 +61,38 @@ const unpackFragment = child => {
59
61
 
60
62
  return child;
61
63
  };
64
+
65
+ exports.unpackFragment = unpackFragment;
66
+
67
+ const isStringOrNumber = child => typeof child === 'string' || typeof child === 'number'; // Wrap an A11yText with neighouring text strings so it doesn't split them into multiple <Text>s
68
+
69
+
70
+ const isWrapable = child => isStringOrNumber(child) || child.type === _A11yText.default;
71
+
72
+ const combineKeys = childrenArray => childrenArray.reduce((newKey, child) => `${newKey}${child.key || ''}`, ''); // Group wrappable children for one `<Text>` parent, merging adjacent text nodes
73
+
74
+
75
+ const wrapChild = (child, wrappedText) => {
76
+ const lastIndex = wrappedText.length - 1; // If possible, simplify content by combining text nodes into one string.
77
+ // jest-native's `.toHaveTextContent` is buggy about array of text nodes in <Text> elements.
78
+
79
+ if (lastIndex >= 0 && isStringOrNumber(child) && isStringOrNumber(wrappedText[lastIndex])) {
80
+ /* eslint-disable-next-line no-param-reassign */
81
+ wrappedText[lastIndex] = `${wrappedText[lastIndex]}${child}`;
82
+ } else {
83
+ wrappedText.push(child);
84
+ }
85
+ };
62
86
  /**
63
87
  * React Native on Native crashes if text content is rendered outside `<Text>`, and on web,
64
- * text style inheritance isn't as expected.
88
+ * text style inheritance behaves differently with text compared to regular HTML.
65
89
  *
66
90
  * Call this function on children that may contain text (strings or numbers) at the top level,
67
91
  * and any that are found will be wrapped in a React Native `<Text>` element with supplied props.
68
92
  *
69
- * Note that this does not wrap strings that are nested children of the top level children:
93
+ * Note that this does not wrap strings that are nested children of rendered top level children:
70
94
  * `wrapStringsInText(<View>Some text</View>)` will not wrap the inner text and will still crash,
71
- * but `wrapStringsInText(<>{someString}{anotherString}</>)` will wrap the strings in the fragment.
95
+ * but `wrapStringsInText(<>{someString}{anotherString}</>)` wraps the strings inside the fragment.
72
96
  *
73
97
  * @param {ReactChildren} children
74
98
  * @param {TextProps} props
@@ -76,12 +100,35 @@ const unpackFragment = child => {
76
100
  */
77
101
 
78
102
 
79
- exports.unpackFragment = unpackFragment;
103
+ const wrapStringsInText = (children, textProps = {}) => {
104
+ const childrenArray = unpackFragment(_react.Children.toArray(children)); // Group adjacent wrapable children together in one Text element to create as few Text elements
105
+ // as possible, e.g. give <X>Text {someString}</X> one Text, same as <X>{`Text ${someString}`}</X>
80
106
 
81
- const wrapStringsInText = (children, props = {}) => {
82
- return _react.Children.map(unpackFragment(children), child => typeof child === 'string' || typeof child === 'number' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Text.default, { ...props,
83
- children: child
84
- }) : child);
107
+ const wrapables = [[]];
108
+ let wrapablesIndex = 0;
109
+ childrenArray.forEach(child => {
110
+ if (isWrapable(child)) {
111
+ // Make this child a child of the current `Text`
112
+ wrapChild(child, wrapables[wrapablesIndex]);
113
+ } else {
114
+ // Close current `Text` and start a new one after this child
115
+ wrapables.push(child, []);
116
+ wrapablesIndex += 2;
117
+ }
118
+ });
119
+ const items = wrapables.reduce((flatChildren, group, index) => {
120
+ // Skip nullish children and empty arrays
121
+ if (!group || Array.isArray(group) && !group.length) return flatChildren;
122
+ return [...flatChildren, Array.isArray(group) && group.some(child => isStringOrNumber(child)) ?
123
+ /*#__PURE__*/
124
+ // Wrap text nodes and their wrappable neighbours in Text with as stable a key as possible.
125
+ // Avoid one-item arrays because jest-native's `.toHaveTextContent` is buggy
126
+ // and sometimes fails to match text content in arrays.
127
+ (0, _jsxRuntime.jsx)(_Text.default, { ...textProps,
128
+ children: group.length === 1 ? group[0] : group
129
+ }, combineKeys(group) || index) : group];
130
+ }, []);
131
+ return items.length === 1 ? items[0] : items;
85
132
  };
86
133
 
87
134
  exports.wrapStringsInText = wrapStringsInText;
@@ -23,23 +23,29 @@ const validateProps = ({
23
23
  const usageError = error => {
24
24
  // Errors inside hooks in React Native get incomplete stack traces pointing at parent component only.
25
25
  // Help devs out by telling them exactly which hook threw the error as well as why.
26
- throw new Error("".concat(hookName, " ").concat(error, ".\n\nConsumers of this hook must be one of:\n1. An \"uncontrolled\" component responding directly to user actions, with an optional `initialValue").concat(s, "` but no `value").concat(s, "` prop,\n2. A \"controlled\" component where an always-defined `value").concat(s, "` prop is managed by an `onChange` handler, with no `initialValue").concat(s, "`,\n3. A \"read-only\" component, with `readOnly` prop set as `true`.\n"));
26
+ throw new Error(`${hookName} ${error}.
27
+
28
+ Consumers of this hook must be one of:
29
+ 1. An "uncontrolled" component responding directly to user actions, with an optional \`initialValue${s}\` but no \`value${s}\` prop,
30
+ 2. A "controlled" component where an always-defined \`value${s}\` prop is managed by an \`onChange\` handler, with no \`initialValue${s}\`,
31
+ 3. A "read-only" component, with \`readOnly\` prop set as \`true\`.
32
+ `);
27
33
  };
28
34
 
29
35
  if (value && !onChange && !readOnly) {
30
- usageError("has `value".concat(s, "` prop without `onChange` or `readOnly`"));
36
+ usageError(`has \`value${s}\` prop without \`onChange\` or \`readOnly\``);
31
37
  }
32
38
 
33
39
  if (initialValue && value) {
34
- usageError("has both `initialValue".concat(s, "` and `value").concat(s, "`"));
40
+ usageError(`has both \`initialValue${s}\` and \`value${s}\``);
35
41
  }
36
42
 
37
43
  if (isControlled && !isCurrentlyControlled) {
38
- usageError("stopped receiving `value".concat(s, "` from parent after delegating state management"));
44
+ usageError(`stopped receiving \`value${s}\` from parent after delegating state management`);
39
45
  }
40
46
 
41
47
  if (!isControlled && isCurrentlyControlled) {
42
- usageError("started receiving `value".concat(s, "` from parent after starting managing own state"));
48
+ usageError(`started receiving \`value${s}\` from parent after starting managing own state`);
43
49
  }
44
50
  };
45
51
  /**
@@ -92,14 +98,14 @@ const useInputValue = (props = {}, hookName = 'useInputValue') => {
92
98
  }); // Make current value accessible inside useCallback without rememoizing every time the value changes
93
99
 
94
100
  valueRef.current.value = currentValue;
95
- const setValue = (0, _react.useCallback)(arg => {
101
+ const setValue = (0, _react.useCallback)((arg, event) => {
96
102
  if (readOnly) return;
97
- const newValue = typeof arg === 'function' ? arg(valueRef.current.value) : arg; // Only call onChange if the value actually changed
103
+ const newValue = typeof arg === 'function' ? arg(valueRef.current.value) : arg;
104
+ if (!isControlled) setOwnValue(newValue); // Call onChange handler if there's something for it to handle (event or a changed value)
98
105
 
99
- if (onChange && valueRef.current.value !== newValue) onChange(newValue);
100
- if (!isControlled) setOwnValue(newValue);
106
+ if (onChange && (event || valueRef.current.value !== newValue)) onChange(newValue, event);
101
107
  }, [isControlled, onChange, readOnly]);
102
- const resetValue = (0, _react.useCallback)(() => setValue(valueRef.current.initial), [setValue]);
108
+ const resetValue = (0, _react.useCallback)(event => setValue(valueRef.current.initial, event), [setValue]);
103
109
  return {
104
110
  currentValue,
105
111
  setValue,
@@ -154,7 +160,7 @@ const useMultipleInputValues = ({
154
160
  onChange,
155
161
  value: values,
156
162
  // if we're controlling our own state, always start with an array
157
- initialValue: initialValues !== null && initialValues !== void 0 ? initialValues : values === undefined ? [] : undefined
163
+ initialValue: initialValues ?? (values === undefined ? [] : undefined)
158
164
  }, 'useMultipleInputValues');
159
165
  const enforceMaxValues = (0, _react.useCallback)(newValues => {
160
166
  if (!maxValues) return newValues;
@@ -162,14 +168,18 @@ const useMultipleInputValues = ({
162
168
  return excess > 0 ? newValues.slice(excess) : newValues;
163
169
  }, [maxValues]);
164
170
  const currentValues = enforceMaxValues(currentValue);
165
- const setValues = (0, _react.useCallback)(newValues => setValue(enforceMaxValues(newValues)), [setValue, enforceMaxValues]);
171
+ const setValues = (0, _react.useCallback)((newValues, event) => {
172
+ const validNewValues = enforceMaxValues(newValues);
173
+ setValue(validNewValues, event);
174
+ }, [setValue, enforceMaxValues]);
166
175
  const resetValues = resetValue;
167
- const unsetValues = (0, _react.useCallback)(() => setValues([]), [setValues]);
168
- const toggleOneValue = (0, _react.useCallback)(newValue => {
169
- if (readOnly) return;
170
- setValues( // This will only work with primitive values (e.g. strings, numbers), swap for .some() and
176
+ const unsetValues = (0, _react.useCallback)(event => setValues([], event), [setValues]);
177
+ const toggleOneValue = (0, _react.useCallback)((newValue, event) => {
178
+ if (readOnly) return; // This will only work with primitive values (e.g. strings, numbers), swap for .some() and
171
179
  // a deepEqual() function if there's any use case for toggling stored objects or arrays.
172
- currentValues.includes(newValue) ? currentValues.filter(oldValue => oldValue !== newValue) : [...currentValues, newValue]);
180
+
181
+ const newValues = currentValues.includes(newValue) ? currentValues.filter(oldValue => oldValue !== newValue) : [...currentValues, newValue];
182
+ setValues(newValues, event);
173
183
  }, [currentValues, readOnly, setValues]);
174
184
  return {
175
185
  currentValues,
@@ -11,7 +11,7 @@ var _Linking = _interopRequireDefault(require("react-native-web/dist/cjs/exports
11
11
 
12
12
  var _Platform = _interopRequireDefault(require("react-native-web/dist/cjs/exports/Platform"));
13
13
 
14
- var _schema = require("@telus-uds/system-themes/schema");
14
+ var _systemThemeTokens = require("@telus-uds/system-theme-tokens");
15
15
 
16
16
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
17
 
@@ -60,13 +60,13 @@ const tokenValue = _propTypes.default.oneOfType([_propTypes.default.string, _pro
60
60
  const tokenValueType = _propTypes.default.oneOfType([tokenValue, _propTypes.default.objectOf(tokenValue)]);
61
61
 
62
62
  const getTokenNames = componentName => {
63
- const componentTokenNames = _schema.components[componentName];
63
+ const componentTokenSchema = _systemThemeTokens.components[componentName];
64
64
 
65
- if (!componentTokenNames) {
66
- throw new Error("No \"".concat(componentName, "\" tokenKeys in @telus-uds/system-themes/schema"));
65
+ if (!componentTokenSchema) {
66
+ throw new Error(`No "${componentName}" tokenKeys in @telus-uds/system-theme-tokens`);
67
67
  }
68
68
 
69
- return componentTokenNames;
69
+ return Object.keys(componentTokenSchema);
70
70
  };
71
71
  /**
72
72
  * Returns the subset of a set of tokens that may be accepted by the `tokens` prop of a named component
@@ -104,7 +104,7 @@ exports.getTokenNames = getTokenNames;
104
104
  const selectTokens = (specifier, tokens, prefix) => {
105
105
  const tokenNames = typeof specifier === 'string' ? getTokenNames(specifier) : specifier;
106
106
  const filteredTokens = tokenNames.reduce((validTokens, key) => {
107
- const prefixedKey = prefix ? "".concat(prefix).concat(key[0].toUpperCase()).concat(key.slice(1)) : key;
107
+ const prefixedKey = prefix ? `${prefix}${key[0].toUpperCase()}${key.slice(1)}` : key;
108
108
  const token = tokens[prefixedKey];
109
109
  return token !== undefined ? { ...validTokens,
110
110
  [key]: token
@@ -225,7 +225,56 @@ const a11yPropTypes = {
225
225
  importantForAccessibility: _propTypes.default.oneOf(['auto', 'yes', 'no', 'no-hide-descendants']),
226
226
  onAccessibilityAction: _propTypes.default.func,
227
227
  onAccessibilityEscape: _propTypes.default.func,
228
- onAccessibilityTap: _propTypes.default.func
228
+ onAccessibilityTap: _propTypes.default.func,
229
+ ..._Platform.default.select({
230
+ web: {
231
+ // React Native Web adds many a11y props that alias aria-* attributes
232
+ // Types based on https://necolas.github.io/react-native-web/docs/accessibility/
233
+ accessibilityActiveDescendant: _propTypes.default.string,
234
+ accessibilityAtomic: _propTypes.default.bool,
235
+ accessibilityAutoComplete: _propTypes.default.string,
236
+ accessibilityBusy: _propTypes.default.bool,
237
+ accessibilityChecked: _propTypes.default.oneOf([true, false, 'mixed']),
238
+ accessibilityColumnCount: _propTypes.default.number,
239
+ accessibilityColumnIndex: _propTypes.default.number,
240
+ accessibilityColumnSpan: _propTypes.default.number,
241
+ accessibilityControls: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.arrayOf(_propTypes.default.string)]),
242
+ accessibilityCurrent: _propTypes.default.oneOf([true, false, 'page', 'step', 'location', 'date', 'time']),
243
+ accessibilityDescribedBy: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.arrayOf(_propTypes.default.string)]),
244
+ accessibilityDetails: _propTypes.default.string,
245
+ accessibilityDisabled: _propTypes.default.bool,
246
+ accessibilityErrorMessage: _propTypes.default.string,
247
+ accessibilityExpanded: _propTypes.default.bool,
248
+ accessibilityFlowTo: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.arrayOf(_propTypes.default.string)]),
249
+ accessibilityHasPopup: _propTypes.default.string,
250
+ accessibilityHidden: _propTypes.default.bool,
251
+ accessibilityInvalid: _propTypes.default.bool,
252
+ accessibilityKeyShortcuts: _propTypes.default.string,
253
+ accessibilityLabelledBy: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.arrayOf(_propTypes.default.string)]),
254
+ accessibilityLevel: _propTypes.default.number,
255
+ accessibilityModal: _propTypes.default.bool,
256
+ accessibilityMultiline: _propTypes.default.bool,
257
+ accessibilityMultiSelectable: _propTypes.default.bool,
258
+ accessibilityOrientation: _propTypes.default.oneOf(['horizontal', 'vertical']),
259
+ accessibilityOwns: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.arrayOf(_propTypes.default.string)]),
260
+ accessibilityPlaceholder: _propTypes.default.string,
261
+ accessibilityPosInSet: _propTypes.default.number,
262
+ accessibilityPressed: _propTypes.default.bool,
263
+ accessibilityReadOnly: _propTypes.default.bool,
264
+ accessibilityRequired: _propTypes.default.bool,
265
+ accessibilityRoleDescription: _propTypes.default.string,
266
+ accessibilityRowCount: _propTypes.default.number,
267
+ accessibilityRowIndex: _propTypes.default.number,
268
+ accessibilityRowSpan: _propTypes.default.number,
269
+ accessibilitySelected: _propTypes.default.bool,
270
+ accessibilitySetSize: _propTypes.default.number,
271
+ accessibilitySort: _propTypes.default.oneOf(['ascending', 'descending', 'none', 'other']),
272
+ accessibilityValueMax: _propTypes.default.number,
273
+ accessibilityValueMin: _propTypes.default.number,
274
+ accessibilityValueNow: _propTypes.default.number,
275
+ accessibilityValueText: _propTypes.default.string
276
+ }
277
+ })
229
278
  };
230
279
  const a11yProps = {
231
280
  /**
@@ -332,8 +381,11 @@ const pressHandlerPropTypes = {
332
381
  const pressPropTypes = { ...pressHandlerPropTypes,
333
382
  disabled: _propTypes.default.bool,
334
383
  ..._Platform.default.select({
335
- hitSlop: _propTypes.default.number,
336
- pressRetentionOffset: _propTypes.default.oneOfType([_propTypes.default.number, rectProp.propType])
384
+ web: {},
385
+ default: {
386
+ hitSlop: _propTypes.default.number,
387
+ pressRetentionOffset: _propTypes.default.oneOfType([_propTypes.default.number, rectProp.propType])
388
+ }
337
389
  })
338
390
  };
339
391
  const pressProps = {
@@ -366,7 +418,7 @@ const linkProps = {
366
418
  select: getPropSelector(linkPropTypes),
367
419
 
368
420
  /**
369
- * Turn hrefs into press handlers on Native and throw if not given `onPress` xor `href`.
421
+ * Turn hrefs into press handlers on Native and throw if not given `onPress` or `href`.
370
422
  *
371
423
  * @param {({ onPress?: () => void, href?: string })}
372
424
  * @returns {(() => void)|undefined} Returns a press handler, or undefined on web if href
@@ -376,24 +428,25 @@ const linkProps = {
376
428
  onPress,
377
429
  href
378
430
  }) => {
379
- // TODO: revisit this when integrating routing packages
380
- // https://github.com/telus/universal-design-system/issues/24
381
- if (href && onPress) {
382
- throw new Error("handleHref currently doesn't support both href and onPress");
383
- }
384
-
385
431
  if (!href && !onPress) {
386
432
  throw new Error('handleHref requires either href or onPress');
387
433
  }
388
434
 
389
- return _Platform.default.OS !== 'web' && href ? () => _Linking.default.openURL(href) : onPress;
435
+ return _Platform.default.select({
436
+ web: onPress,
437
+ default: (...args) => {
438
+ if (onPress) onPress(...args);
439
+ if (href) _Linking.default.openURL(href);
440
+ }
441
+ });
390
442
  }
391
443
  };
392
444
  exports.linkProps = linkProps;
393
445
  const viewPropTypes = {
394
446
  pointerEvents: _propTypes.default.oneOf(['all', 'none', 'box-only', 'box-none']),
395
447
  onLayout: _propTypes.default.func,
396
- nativeID: _propTypes.default.string
448
+ nativeID: _propTypes.default.string,
449
+ testID: _propTypes.default.string
397
450
  };
398
451
  const viewProps = {
399
452
  /**
@@ -496,23 +549,24 @@ const spacingProps = {
496
549
  }
497
550
  };
498
551
  /**
499
- * Returns a prop type validator which checks whether a prop is either a component or an array of components of a given
500
- * type, based on their `name` property.
552
+ * Returns a prop type validator which checks whether a prop is either a component or an array of
553
+ * components of a given type, based on their `name` or `displayName` properties.
501
554
  * Use an array of strings for `passedName` to accept more than one component type.
502
555
  * For an array the validation fails on the first occurrence of an invalid element.
503
556
  *
504
557
  * @param {string|string[]} passedName
505
- * @param {boolean} [checkDisplayName] - if `true` then `displayName` property on the component will be validated instead of `name`
506
558
  * @return {function}
507
559
  */
508
560
 
509
561
  exports.spacingProps = spacingProps;
510
562
 
511
- const componentPropType = (passedName, checkDisplayName = false) => {
563
+ const componentPropType = passedName => {
512
564
  const passedNames = typeof passedName === 'string' ? [passedName] : passedName;
513
565
 
514
566
  const checkProp = (props, propName, componentName) => {
515
- if (typeof props[propName] === 'undefined' || props[propName] === null) {
567
+ var _props$propName$type, _props$propName$type2;
568
+
569
+ if (props[propName] === undefined || props[propName] === null) {
516
570
  return undefined;
517
571
  }
518
572
 
@@ -522,12 +576,11 @@ const componentPropType = (passedName, checkDisplayName = false) => {
522
576
  return props[propName].map((_, index) => checkProp(props[propName], index, componentName)).find(Boolean);
523
577
  }
524
578
 
525
- const testNameInObject = () => typeof props[propName] === 'object' && (!checkDisplayName && !passedNames.includes(props[propName].type.name) || checkDisplayName && !passedNames.includes(props[propName].type.displayName));
526
-
527
- const testNameInFunction = () => typeof props[propName] === 'function' && (!checkDisplayName && !passedNames.includes(props[propName].name) || checkDisplayName && !passedNames.includes(props[propName].displayName));
579
+ const nameInProp = ((_props$propName$type = props[propName].type) === null || _props$propName$type === void 0 ? void 0 : _props$propName$type.displayName) || ((_props$propName$type2 = props[propName].type) === null || _props$propName$type2 === void 0 ? void 0 : _props$propName$type2.name);
528
580
 
529
- if (props[propName] && typeof props[propName] !== 'object' && typeof props[propName] !== 'function' || testNameInObject() || testNameInFunction()) {
530
- return new Error("".concat(componentName, ": Component passed to `").concat(propName, "` prop should be ").concat(passedNames.join(' or ')));
581
+ if (!nameInProp || !passedNames.includes(nameInProp)) {
582
+ const propDescription = nameInProp ? `Component ${nameInProp}` : typeof props[propName];
583
+ return new Error(`${componentName}: ${propDescription} was passed to \`${propName}\` prop; should be ${passedNames.join(' or ')}`);
531
584
  }
532
585
 
533
586
  return undefined;
@@ -535,7 +588,7 @@ const componentPropType = (passedName, checkDisplayName = false) => {
535
588
 
536
589
  const checkRequired = (props, propName, componentName) => {
537
590
  if (props[propName] === undefined) {
538
- return new Error("The prop `".concat(propName, "` is marked as required in `").concat(componentName, "`, but its value is ").concat(props[propName], "."));
591
+ return new Error(`The prop \`${propName}\` is marked as required in \`${componentName}\`, but its value is ${props[propName]}.`);
539
592
  }
540
593
 
541
594
  return undefined;
@@ -40,7 +40,7 @@ function useCopy({
40
40
  copy = DEFAULT_COPY
41
41
  }) {
42
42
  if (typeof copy === 'string') {
43
- return key => dictionary[copy][key];
43
+ return key => key ? dictionary[copy][key] : dictionary[copy];
44
44
  } // support overriding the entire copy dictionary with an object for a single language
45
45
 
46
46
 
@@ -7,11 +7,15 @@ exports.default = void 0;
7
7
 
8
8
  var _react = require("react");
9
9
 
10
- const doAction = action => {
10
+ const doAction = (action, event) => {
11
11
  var _window, _window$location;
12
12
 
13
- return typeof action === 'function' && action((_window = window) === null || _window === void 0 ? void 0 : (_window$location = _window.location) === null || _window$location === void 0 ? void 0 : _window$location.hash);
13
+ return typeof action === 'function' && action((_window = window) === null || _window === void 0 ? void 0 : (_window$location = _window.location) === null || _window$location === void 0 ? void 0 : _window$location.hash, event);
14
14
  };
15
+ /**
16
+ * @typedef {import('react').SyntheticEvent} SyntheticEvent
17
+ */
18
+
15
19
  /**
16
20
  * Calls a function (passing it the current hash) based on the current hash state on mount,
17
21
  * and binds it to call it again any time the hash changes.
@@ -20,7 +24,7 @@ const doAction = action => {
20
24
  *
21
25
  * On Native, this is replaced with a harmless no-op function as there is no direct equivalent.
22
26
  *
23
- * @param {(hash: string) => void} action - a function to act on the current hash on load and when it changes
27
+ * @param {(hash: string, event?: SyntheticEvent) => void} action - a function to act on the current hash on load and when it changes
24
28
  * @returns
25
29
  */
26
30
 
@@ -37,7 +41,7 @@ const useHash = (action, isReady = true) => {
37
41
  }, [isToDo, action]); // Bind the action for each hash change; do re-bind if the function changes.
38
42
 
39
43
  (0, _react.useEffect)(() => {
40
- const handleChange = () => doAction(action);
44
+ const handleChange = event => doAction(action, event);
41
45
 
42
46
  window.addEventListener('hashchange', handleChange);
43
47
  return () => window.removeEventListener('hashchange', handleChange);
@@ -110,8 +110,6 @@ const resolveSpacingOptions = space => {
110
110
 
111
111
 
112
112
  const useSpacingScale = spaceValue => {
113
- var _spaceValue$space;
114
-
115
113
  // In future, may need to consider window height as well as width, particularly for native apps,
116
114
  // e.g. to ensure designs don't look lost on large, tall, not-so-wide portrait screens.
117
115
  const viewport = (0, _ViewportProvider.useViewport)();
@@ -121,7 +119,7 @@ const useSpacingScale = spaceValue => {
121
119
  overridden,
122
120
  subtract = 0
123
121
  } = resolveSpacingOptions(spaceValue);
124
- const space = !overridden && ((_spaceValue$space = spaceValue === null || spaceValue === void 0 ? void 0 : spaceValue.space) !== null && _spaceValue$space !== void 0 ? _spaceValue$space : (0, _useResponsiveProp.resolveResponsiveProp)(spaceValue, viewport, 0));
122
+ const space = !overridden && ((spaceValue === null || spaceValue === void 0 ? void 0 : spaceValue.space) ?? (0, _useResponsiveProp.resolveResponsiveProp)(spaceValue, viewport, 0));
125
123
  const {
126
124
  size
127
125
  } = (0, _ThemeProvider.useThemeTokens)('spacingScale', tokens, variant, {
@@ -12,7 +12,7 @@ let id = 0;
12
12
  function useUniqueId(prefix = '') {
13
13
  const [uniqueId] = (0, _react.useState)(() => {
14
14
  id += 1;
15
- return "".concat(prefix, "-").concat(id);
15
+ return `${prefix}-${id}`;
16
16
  });
17
17
  return uniqueId;
18
18
  }