@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
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import { View, Platform, Text, StyleSheet } from 'react-native'
3
3
  import PropTypes from 'prop-types'
4
4
  import { useThemeTokens, applyTextStyles } from '../ThemeProvider'
@@ -48,104 +48,96 @@ const selectDividerStyles = ({ dividerColor, dividerSize, interItemMarginWithDiv
48
48
  /**
49
49
  * ListItem is responsible for rendering icon or a bullet as side item
50
50
  */
51
- const ListItem = ({
52
- tokens,
53
- variant,
54
- icon,
55
- iconColor,
56
- iconSize,
57
- showDivider,
58
- children,
59
- isLastItem
60
- }) => {
61
- const themeTokens = useThemeTokens('List', tokens, variant)
62
-
63
- const itemStyles = selectItemStyles(themeTokens)
64
- const itemBlockStyles = selectItemBlockStyles(themeTokens)
65
- const dividerStyles = selectDividerStyles(themeTokens)
66
- const itemBulletContainerStyles = selectBulletContainerStyles(themeTokens)
67
- const itemBulletStyles = selectBulletStyles(themeTokens)
68
- const iconTokens = selectItemIconTokens(themeTokens)
69
- const sideItemContainerStyles = selectSideItemContainerStyles(themeTokens)
70
- const accessibilityRole = Platform.select({ web: 'listitem', default: 'item' })
71
-
72
- const areChildrenStrings = () => {
73
- if (Array.isArray(children)) {
74
- return children.every((child) => typeof child === 'string')
51
+ const ListItem = forwardRef(
52
+ ({ tokens, variant, icon, iconColor, iconSize, showDivider, children, isLastItem }, ref) => {
53
+ const themeTokens = useThemeTokens('List', tokens, variant)
54
+
55
+ const itemStyles = selectItemStyles(themeTokens)
56
+ const itemBlockStyles = selectItemBlockStyles(themeTokens)
57
+ const dividerStyles = selectDividerStyles(themeTokens)
58
+ const itemBulletContainerStyles = selectBulletContainerStyles(themeTokens)
59
+ const itemBulletStyles = selectBulletStyles(themeTokens)
60
+ const iconTokens = selectItemIconTokens(themeTokens)
61
+ const sideItemContainerStyles = selectSideItemContainerStyles(themeTokens)
62
+ const accessibilityRole = Platform.select({ web: 'listitem', default: 'item' })
63
+
64
+ const areChildrenStrings = () => {
65
+ if (Array.isArray(children)) {
66
+ return children.every((child) => typeof child === 'string')
67
+ }
68
+
69
+ return typeof children === 'string'
75
70
  }
76
71
 
77
- return typeof children === 'string'
78
- }
79
-
80
- const renderItem = () => {
81
- if (areChildrenStrings()) {
82
- return <Text style={itemStyles}>{children}</Text>
83
- }
72
+ const renderItem = () => {
73
+ if (areChildrenStrings()) {
74
+ return <Text style={itemStyles}>{children}</Text>
75
+ }
84
76
 
85
- return <View>{children}</View>
86
- }
87
-
88
- /**
89
- * Function responsible returning styling, in case the item is the last shouldn't
90
- * add extra margin on the bottom, if "showDivider" is true it should add a divider
91
- * and custom margin and padding, otherwise just adds a margin to the bottom
92
- */
93
- const getContainerStyle = () => {
94
- if (isLastItem) {
95
- return undefined
77
+ return <View style={staticStyles.wrap}>{children}</View>
96
78
  }
97
79
 
98
- if (showDivider) {
99
- return dividerStyles
80
+ /**
81
+ * Function responsible returning styling, in case the item is the last shouldn't
82
+ * add extra margin on the bottom, if "showDivider" is true it should add a divider
83
+ * and custom margin and padding, otherwise just adds a margin to the bottom
84
+ */
85
+ const getContainerStyle = () => {
86
+ if (isLastItem) {
87
+ return undefined
88
+ }
89
+
90
+ if (showDivider) {
91
+ return dividerStyles
92
+ }
93
+
94
+ return itemBlockStyles
100
95
  }
101
96
 
102
- return itemBlockStyles
103
- }
104
-
105
- /**
106
- * Renders item bullet or Icon in case it's defined
107
- * in case children are string the icon is centered otherwise
108
- * it will align itself at start of the container
109
- */
110
- const renderMarker = () => {
111
- const IconComponent = icon || <></>
97
+ /**
98
+ * Renders item bullet or Icon in case it's defined
99
+ * in case children are string the icon is centered otherwise
100
+ * it will align itself at start of the container
101
+ */
102
+ const renderMarker = () => {
103
+ const IconComponent = icon || <></>
104
+
105
+ if (icon) {
106
+ return (
107
+ <View
108
+ style={[
109
+ sideItemContainerStyles,
110
+ areChildrenStrings() ? staticStyles.centeredIcons : undefined
111
+ ]}
112
+ >
113
+ <IconComponent
114
+ size={iconSize || iconTokens.size}
115
+ color={iconColor || iconTokens.color}
116
+ />
117
+ </View>
118
+ )
119
+ }
112
120
 
113
- if (icon) {
114
121
  return (
115
- <View
116
- style={[
117
- sideItemContainerStyles,
118
- areChildrenStrings() ? staticStyles.centeredIcons : undefined
119
- ]}
120
- >
121
- <IconComponent
122
- tokens={{
123
- ...iconTokens,
124
- size: iconSize || iconTokens.size,
125
- color: iconColor || iconTokens.color
126
- }}
127
- />
122
+ <View style={[sideItemContainerStyles, itemBulletContainerStyles]}>
123
+ <View style={itemBulletStyles} testID="unordered-item-bullet" />
128
124
  </View>
129
125
  )
130
126
  }
131
127
 
132
128
  return (
133
- <View style={[sideItemContainerStyles, itemBulletContainerStyles]}>
134
- <View style={itemBulletStyles} testID="unordered-item-bullet" />
129
+ <View
130
+ ref={ref}
131
+ style={[staticStyles.itemContainer, getContainerStyle()]}
132
+ accessibilityRole={accessibilityRole}
133
+ >
134
+ {renderMarker()}
135
+ {renderItem()}
135
136
  </View>
136
137
  )
137
138
  }
138
-
139
- return (
140
- <View
141
- style={[staticStyles.itemContainer, getContainerStyle()]}
142
- accessibilityRole={accessibilityRole}
143
- >
144
- {renderMarker()}
145
- {renderItem()}
146
- </View>
147
- )
148
- }
139
+ )
140
+ ListItem.displayName = 'ListItem'
149
141
 
150
142
  const staticStyles = StyleSheet.create({
151
143
  itemContainer: {
@@ -153,6 +145,9 @@ const staticStyles = StyleSheet.create({
153
145
  },
154
146
  centeredIcons: {
155
147
  justifyContent: 'center'
148
+ },
149
+ wrap: {
150
+ flex: 1
156
151
  }
157
152
  })
158
153
 
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import {
3
3
  StyleSheet,
4
4
  TouchableWithoutFeedback,
@@ -79,7 +79,7 @@ const selectCloseIconProps = ({ closeIconSize, closeIconColor }) => ({
79
79
  * - Don’t use modals to reinforce or repeat information already available in the parent page or view
80
80
  * - Don’t use modals consecutively
81
81
  */
82
- const Modal = ({ children, isOpen, onClose, maxWidth, tokens, variant, copy }) => {
82
+ const Modal = forwardRef(({ children, isOpen, onClose, maxWidth, tokens, variant, copy }, ref) => {
83
83
  const viewport = useViewport()
84
84
  const themeTokens = useThemeTokens('Modal', tokens, variant, { viewport, maxWidth })
85
85
 
@@ -108,7 +108,11 @@ const Modal = ({ children, isOpen, onClose, maxWidth, tokens, variant, copy }) =
108
108
  style={[staticStyles.sizingContainer, selectContainerStyles(themeTokens)]}
109
109
  pointerEvents="box-none" // don't capture backdrop press events
110
110
  >
111
- <View style={[staticStyles.modal, selectModalStyles(themeTokens)]} onKeyUp={handleKeyUp}>
111
+ <View
112
+ ref={ref}
113
+ style={[staticStyles.modal, selectModalStyles(themeTokens)]}
114
+ onKeyUp={handleKeyUp}
115
+ >
112
116
  <View
113
117
  style={[
114
118
  staticStyles.closeButtonContainer,
@@ -137,7 +141,8 @@ const Modal = ({ children, isOpen, onClose, maxWidth, tokens, variant, copy }) =
137
141
  </View>
138
142
  </NativeModal>
139
143
  )
140
- }
144
+ })
145
+ Modal.displayName = 'Modal'
141
146
 
142
147
  Modal.propTypes = {
143
148
  children: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]),
@@ -1,4 +1,4 @@
1
- import React, { useState } from 'react'
1
+ import React, { forwardRef, useState } from 'react'
2
2
  import { StyleSheet, Text, View } from 'react-native'
3
3
 
4
4
  import PropTypes from 'prop-types'
@@ -42,7 +42,7 @@ const selectDismissButtonContainerStyles = ({ dismissButtonGap }) => ({
42
42
  * - Show system notifications at the top of the page, below the navigation, and expands the full-width of the viewport
43
43
  * - When showing multiple notifications, show them in order of importance from top to bottom
44
44
  * - Use variants to visually show the type of message contained within the Notification.
45
- * The icon and colour will indicate meaning and importance
45
+ * - The icon and colour will indicate meaning and importance
46
46
  *
47
47
  * ### Variants
48
48
  * - Use `variant.style` to set the visual style of the notification
@@ -81,54 +81,69 @@ const selectDismissButtonContainerStyles = ({ dismissButtonGap }) => ({
81
81
  * Use full-width `Notifications` to show system-based messages coming from the application, not in response to user action.
82
82
  * Show system notifications at the top of the page, below the navigation, and expands the full-width of the viewport
83
83
  */
84
- const Notification = ({ children, system, dismissible, copy = 'en', tokens, variant }) => {
85
- const [isDismissed, setIsDismissed] = useState(false)
86
- const themeTokens = useThemeTokens('Notification', tokens, variant, { system })
87
- const getCopy = useCopy({ dictionary, copy })
88
-
89
- if (isDismissed) {
90
- return null
91
- }
92
-
93
- const textStyles = selectTextStyles(themeTokens)
94
-
95
- const content =
96
- typeof children === 'string' ? <Text style={textStyles}>{children}</Text> : children
97
-
98
- const { icon: IconComponent, dismissIcon: DismissIconComponent } = themeTokens
99
-
100
- const onDismissPress = () => setIsDismissed(true)
101
-
102
- // TODO: replace the dismiss button with IconButton when implemented (https://github.com/telus/universal-design-system/issues/281)
103
- return (
104
- <View style={[staticStyles.container, selectContainerStyles(themeTokens)]}>
105
- {IconComponent && (
106
- <View style={selectIconContainerStyles(themeTokens)}>
107
- <IconComponent {...selectIconProps(themeTokens)} />
84
+ const Notification = forwardRef(
85
+ ({ children, system, dismissible, copy = 'en', tokens, variant }, ref) => {
86
+ const [isDismissed, setIsDismissed] = useState(false)
87
+ const themeTokens = useThemeTokens('Notification', tokens, variant, { system })
88
+ const getCopy = useCopy({ dictionary, copy })
89
+
90
+ if (isDismissed) {
91
+ return null
92
+ }
93
+
94
+ const textStyles = selectTextStyles(themeTokens)
95
+
96
+ const content =
97
+ typeof children === 'string' ? <Text style={textStyles}>{children}</Text> : children
98
+
99
+ const { icon: IconComponent, dismissIcon: DismissIconComponent } = themeTokens
100
+
101
+ const onDismissPress = () => setIsDismissed(true)
102
+
103
+ // TODO: replace the dismiss button with IconButton when implemented (https://github.com/telus/universal-design-system/issues/281)
104
+ return (
105
+ <View ref={ref} style={[staticStyles.container, selectContainerStyles(themeTokens)]}>
106
+ {IconComponent && (
107
+ <View style={selectIconContainerStyles(themeTokens)}>
108
+ <IconComponent {...selectIconProps(themeTokens)} />
109
+ </View>
110
+ )}
111
+ <View style={staticStyles.contentContainer}>
112
+ {content && typeof content === 'function' ? content({ textStyles, variant }) : content}
108
113
  </View>
109
- )}
110
- <View style={staticStyles.contentContainer}>
111
- {content && typeof content === 'function' ? content({ textStyles, variant }) : content}
114
+ {dismissible && DismissIconComponent && (
115
+ <View style={selectDismissButtonContainerStyles(themeTokens)}>
116
+ <ButtonBase
117
+ onPress={onDismissPress}
118
+ accessibilityRole="button"
119
+ accessibilityLabel={getCopy('dismiss')}
120
+ >
121
+ {() => <DismissIconComponent {...selectDismissIconProps(themeTokens)} />}
122
+ </ButtonBase>
123
+ </View>
124
+ )}
112
125
  </View>
113
- {dismissible && DismissIconComponent && (
114
- <View style={selectDismissButtonContainerStyles(themeTokens)}>
115
- <ButtonBase
116
- onPress={onDismissPress}
117
- accessibilityRole="button"
118
- accessibilityLabel={getCopy('dismiss')}
119
- >
120
- {() => <DismissIconComponent {...selectDismissIconProps(themeTokens)} />}
121
- </ButtonBase>
122
- </View>
123
- )}
124
- </View>
125
- )
126
- }
126
+ )
127
+ }
128
+ )
129
+ Notification.displayName = 'Notification'
127
130
 
128
131
  Notification.propTypes = {
132
+ /**
133
+ * Content of the `Notification`.
134
+ */
129
135
  children: PropTypes.oneOfType([PropTypes.string, PropTypes.node, PropTypes.func]),
136
+ /**
137
+ * Use `system` prop to set the visual style of the notification and denote an announcement from the system or application
138
+ */
130
139
  system: PropTypes.bool,
140
+ /**
141
+ * Use the `dismissible` prop to allow users to dismiss the Notification at any time.
142
+ */
131
143
  dismissible: PropTypes.bool,
144
+ /**
145
+ * Select english or french copy for the accessible label of the dismiss button.
146
+ */
132
147
  copy: PropTypes.oneOfType([
133
148
  PropTypes.oneOf(['en', 'fr']),
134
149
  PropTypes.shape({ dismiss: PropTypes.string })
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
 
4
4
  import ButtonBase from '../Button/ButtonBase'
@@ -8,7 +8,6 @@ import {
8
8
  copyPropTypes,
9
9
  getTokensPropType,
10
10
  hrefAttrsProp,
11
- linkProps,
12
11
  selectTokens,
13
12
  variantProp
14
13
  } from '../utils'
@@ -16,51 +15,59 @@ import {
16
15
  import useCopy from '../utils/useCopy'
17
16
  import dictionary from './dictionary'
18
17
 
19
- function PageButton({ label, onPress, href, isActive, copy, variant, tokens, ...props }) {
20
- const getTokens = useThemeTokensCallback('PaginationPageButton', tokens, variant)
18
+ const PageButton = forwardRef(
19
+ ({ label, onPress, href, isActive, copy, variant, tokens, ...props }, ref) => {
20
+ const getTokens = useThemeTokensCallback('PaginationPageButton', tokens, variant)
21
21
 
22
- const getCopy = useCopy({ dictionary, copy })
22
+ const getCopy = useCopy({ dictionary, copy })
23
23
 
24
- const getButtonTokens = (buttonState) => selectTokens('Button', getTokens(buttonState))
24
+ const getButtonTokens = (buttonState) => selectTokens('Button', getTokens(buttonState))
25
25
 
26
- const activeProps = isActive
27
- ? {
28
- selected: true,
29
- ...a11yProps.nonFocusableProps,
30
- // a brute fix for the focus state being stuck on an active item since it becomes non-focusable
31
- // (see https://github.com/telus/universal-design-system/pull/577#issuecomment-931344107)
32
- key: 'active-item'
33
- }
34
- : {}
26
+ const activeProps = isActive
27
+ ? {
28
+ selected: true,
29
+ ...a11yProps.nonFocusableProps,
30
+ // a brute fix for the focus state being stuck on an active item since it becomes non-focusable
31
+ // (see https://github.com/telus/universal-design-system/pull/577#issuecomment-931344107)
32
+ key: 'active-item'
33
+ }
34
+ : {}
35
35
 
36
- const accessibilityRole = href !== undefined ? 'link' : 'button'
37
- const activeLabel = isActive ? ` ${getCopy('currentLabel')}` : ''
38
- const accessibilityLabel = `${getCopy('goToLabel')} ${label}${activeLabel}`
36
+ const accessibilityRole = href !== undefined ? 'link' : 'button'
37
+ const activeLabel = isActive ? ` ${getCopy('currentLabel')}` : ''
38
+ const accessibilityLabel = `${getCopy('goToLabel')} ${label}${activeLabel}`
39
39
 
40
- const { hrefAttrs, rest } = hrefAttrsProp.bundle(props)
41
- const buttonProps = {
42
- accessibilityRole,
43
- accessibilityLabel,
44
- onPress,
45
- href,
46
- hrefAttrs,
47
- ...rest
48
- }
40
+ const { hrefAttrs, rest } = hrefAttrsProp.bundle(props)
41
+ const buttonProps = {
42
+ accessibilityRole,
43
+ accessibilityLabel,
44
+ onPress,
45
+ href,
46
+ hrefAttrs,
47
+ ...rest
48
+ }
49
49
 
50
- return (
51
- <ButtonBase {...buttonProps} tokens={getButtonTokens} {...activeProps}>
52
- {label}
53
- </ButtonBase>
54
- )
55
- }
50
+ return (
51
+ <ButtonBase ref={ref} {...buttonProps} tokens={getButtonTokens} {...activeProps}>
52
+ {label}
53
+ </ButtonBase>
54
+ )
55
+ }
56
+ )
57
+ PageButton.displayName = 'PageButton'
56
58
 
57
59
  PageButton.propTypes = {
60
+ // Spreading any props into a secondary component accessed like Pagination.PageButton
61
+ // crashes a Docusaurus props table, but only in production, not in development
62
+ onPress: PropTypes.func,
63
+ href: PropTypes.string,
64
+ // If the above is fixed, the above can be replaced with this which includes full a11y etc:
65
+ // ...linkProps.types,
58
66
  label: PropTypes.string,
59
67
  isActive: PropTypes.bool,
60
68
  copy: copyPropTypes,
61
69
  variant: variantProp.propType,
62
- tokens: getTokensPropType('PaginationPageButton'),
63
- ...linkProps.types
70
+ tokens: getTokensPropType('PaginationPageButton')
64
71
  }
65
72
 
66
73
  export default PageButton
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import { View, Text, StyleSheet } from 'react-native'
3
3
 
4
4
  import { componentPropType, copyPropTypes, getTokensPropType, variantProp } from '../utils'
@@ -19,99 +19,95 @@ const selectTextStyles = ({ color, fontName, fontSize, fontWeight, lineHeight })
19
19
  lineHeight
20
20
  })
21
21
 
22
- function Pagination({
23
- children,
24
- copy = 'en',
25
- variant,
26
- tokens,
27
- sideButtonVariant,
28
- sideButtonTokens
29
- }) {
30
- const viewport = useViewport()
31
- const { truncateAbove, gap, ...themeTokens } = useThemeTokens('Pagination', tokens, variant, {
32
- viewport
33
- })
34
-
35
- const items = React.Children.toArray(children)
36
-
37
- const {
38
- isItemActive,
39
- getItemProps,
40
- showPrevious,
41
- showNext,
42
- nextItemProps,
43
- previousItemProps,
44
- shouldRenderButton,
45
- shouldRenderEllipsis
46
- } = usePagination({
47
- items,
48
- truncateAbove
49
- })
50
-
51
- const ellipsisTextStyles = selectTextStyles(themeTokens)
52
-
53
- if (items.length === 0) {
54
- return null
55
- }
56
-
57
- // TODO: replace with a spacing component when https://github.com/telus/universal-design-system/pull/531 is implemented
58
- // concatenate all items to easily wrap them in identical spacing components
59
- const buttons = [
60
- showPrevious && (
61
- <SideButton
62
- {...previousItemProps}
63
- direction="previous"
64
- copy={copy}
65
- variant={sideButtonVariant}
66
- tokens={sideButtonTokens}
67
- />
68
- ),
69
- ...items.map((child, itemIndex) => {
70
- const buttonLabel = `${itemIndex + 1}`
71
- const itemProps = getItemProps(itemIndex)
72
-
73
- if (shouldRenderButton(itemIndex)) {
74
- return (
75
- <PageButton
76
- {...itemProps}
77
- label={buttonLabel}
78
- copy={copy}
79
- isActive={isItemActive(itemIndex)}
80
- />
81
- )
82
- }
83
-
84
- if (shouldRenderEllipsis(itemIndex)) {
85
- return <Text style={ellipsisTextStyles}>...</Text>
86
- }
87
-
22
+ const Pagination = forwardRef(
23
+ ({ children, copy = 'en', variant, tokens, sideButtonVariant, sideButtonTokens }, ref) => {
24
+ const viewport = useViewport()
25
+ const { truncateAbove, gap, ...themeTokens } = useThemeTokens('Pagination', tokens, variant, {
26
+ viewport
27
+ })
28
+
29
+ const items = React.Children.toArray(children)
30
+
31
+ const {
32
+ isItemActive,
33
+ getItemProps,
34
+ showPrevious,
35
+ showNext,
36
+ nextItemProps,
37
+ previousItemProps,
38
+ shouldRenderButton,
39
+ shouldRenderEllipsis
40
+ } = usePagination({
41
+ items,
42
+ truncateAbove
43
+ })
44
+
45
+ const ellipsisTextStyles = selectTextStyles(themeTokens)
46
+
47
+ if (items.length === 0) {
88
48
  return null
89
- }),
90
- showNext && (
91
- <SideButton
92
- {...nextItemProps}
93
- direction="next"
94
- copy={copy}
95
- variant={sideButtonVariant}
96
- tokens={sideButtonTokens}
97
- />
49
+ }
50
+
51
+ // TODO: replace with a spacing component when https://github.com/telus/universal-design-system/pull/531 is implemented
52
+ // concatenate all items to easily wrap them in identical spacing components
53
+ const buttons = [
54
+ showPrevious && (
55
+ <SideButton
56
+ {...previousItemProps}
57
+ direction="previous"
58
+ copy={copy}
59
+ variant={sideButtonVariant}
60
+ tokens={sideButtonTokens}
61
+ />
62
+ ),
63
+ ...items.map((child, itemIndex) => {
64
+ const buttonLabel = `${itemIndex + 1}`
65
+ const itemProps = getItemProps(itemIndex)
66
+
67
+ if (shouldRenderButton(itemIndex)) {
68
+ return (
69
+ <PageButton
70
+ {...itemProps}
71
+ label={buttonLabel}
72
+ copy={copy}
73
+ isActive={isItemActive(itemIndex)}
74
+ />
75
+ )
76
+ }
77
+
78
+ if (shouldRenderEllipsis(itemIndex)) {
79
+ return <Text style={ellipsisTextStyles}>...</Text>
80
+ }
81
+
82
+ return null
83
+ }),
84
+ showNext && (
85
+ <SideButton
86
+ {...nextItemProps}
87
+ direction="next"
88
+ copy={copy}
89
+ variant={sideButtonVariant}
90
+ tokens={sideButtonTokens}
91
+ />
92
+ )
93
+ ]
94
+
95
+ return (
96
+ <View style={staticStyles.container} ref={ref}>
97
+ {buttons
98
+ // keep the keys in-line with the page numbers regardless of which buttons are actually rendered
99
+ .map((element, index) => [element, `page-${index + 1}`])
100
+ .filter(([element]) => element !== null)
101
+ .map(([element, key]) => (
102
+ <Box right={gap} key={key}>
103
+ {element}
104
+ </Box>
105
+ ))}
106
+ </View>
98
107
  )
99
- ]
100
-
101
- return (
102
- <View style={staticStyles.container}>
103
- {buttons
104
- // keep the keys in-line with the page numbers regardless of which buttons are actually rendered
105
- .map((element, index) => [element, `page-${index + 1}`])
106
- .filter(([element]) => element !== null)
107
- .map(([element, key]) => (
108
- <Box right={gap} key={key}>
109
- {element}
110
- </Box>
111
- ))}
112
- </View>
113
- )
114
- }
108
+ }
109
+ )
110
+ PageButton.displayName = 'PageButton'
115
111
 
116
112
  Pagination.PageButton = PageButton
117
113