@telus-uds/components-base 0.0.2-prerelease.9 → 1.1.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 (293) hide show
  1. package/.eslintrc.js +9 -0
  2. package/.storybook/main.js +4 -0
  3. package/.storybook/preview.js +37 -0
  4. package/.ultra.cache.json +1 -1
  5. package/CHANGELOG.md +50 -0
  6. package/README.md +4 -2
  7. package/__fixtures__/test-utils.js +25 -0
  8. package/__fixtures__/testTheme.js +4 -2
  9. package/__tests__/Button/ButtonGroup.test.jsx +4 -5
  10. package/__tests__/Checkbox/Checkbox.test.jsx +2 -2
  11. package/__tests__/Checkbox/CheckboxGroup.test.jsx +4 -5
  12. package/__tests__/ExpandCollapse/ExpandCollapse.test.jsx +2 -2
  13. package/__tests__/HorizontalScroll/HorizontalScroll.test.jsx +164 -0
  14. package/__tests__/Link/LinkBase.test.jsx +0 -14
  15. package/__tests__/Radio/Radio.test.jsx +2 -2
  16. package/__tests__/Radio/RadioGroup.test.jsx +4 -5
  17. package/__tests__/RadioCard/RadioCard.test.jsx +2 -2
  18. package/__tests__/RadioCard/RadioCardGroup.test.jsx +4 -5
  19. package/__tests__/Search/Search.test.jsx +9 -8
  20. package/__tests__/Select/Select.test.jsx +3 -2
  21. package/__tests__/Tabs/Tabs.test.jsx +1 -161
  22. package/__tests__/Tags/Tags.test.jsx +4 -5
  23. package/__tests__/TextInput/TextArea.test.jsx +3 -2
  24. package/__tests__/TextInput/TextInputBase.test.jsx +10 -5
  25. package/__tests__/ThemeProvider/ThemeProvider.test.jsx +77 -0
  26. package/__tests__/ThemeProvider/useThemeTokens.test.jsx +9 -5
  27. package/__tests__/ThemeProvider/utils/theme-tokens.test.js +41 -0
  28. package/__tests__/ToggleSwitch/ToggleSwitch.test.jsx +3 -2
  29. package/__tests__/utils/children.test.jsx +128 -0
  30. package/__tests__/utils/input.test.js +1 -1
  31. package/__tests__/utils/semantics.test.jsx +43 -0
  32. package/babel.config.js +9 -16
  33. package/component-docs.json +10313 -0
  34. package/generate-component-docs.js +56 -0
  35. package/lib/A11yText/index.js +10 -5
  36. package/lib/ActivityIndicator/Spinner.js +16 -13
  37. package/lib/ActivityIndicator/Spinner.native.js +12 -8
  38. package/lib/Box/Box.js +103 -8
  39. package/lib/Button/Button.js +9 -8
  40. package/lib/Button/ButtonBase.js +14 -7
  41. package/lib/Button/ButtonGroup.js +25 -10
  42. package/lib/Button/ButtonLink.js +10 -7
  43. package/lib/Card/Card.js +2 -0
  44. package/lib/Card/CardBase.js +13 -5
  45. package/lib/Card/PressableCardBase.js +12 -8
  46. package/lib/Checkbox/Checkbox.js +25 -14
  47. package/lib/Checkbox/CheckboxGroup.js +22 -12
  48. package/lib/Divider/Divider.js +12 -7
  49. package/lib/ExpandCollapse/Accordion.js +10 -4
  50. package/lib/ExpandCollapse/Control.js +12 -6
  51. package/lib/ExpandCollapse/ExpandCollapse.js +10 -5
  52. package/lib/ExpandCollapse/Panel.js +8 -7
  53. package/lib/Feedback/Feedback.js +10 -5
  54. package/lib/Fieldset/Fieldset.js +10 -5
  55. package/lib/Fieldset/FieldsetContainer.js +10 -5
  56. package/lib/Fieldset/FieldsetContainer.native.js +10 -5
  57. package/lib/Fieldset/Legend.js +10 -5
  58. package/lib/Fieldset/Legend.native.js +10 -5
  59. package/lib/FlexGrid/Col/Col.js +8 -5
  60. package/lib/FlexGrid/FlexGrid.js +31 -6
  61. package/lib/FlexGrid/Row/Row.js +12 -5
  62. package/lib/{Tabs → HorizontalScroll}/HorizontalScroll.js +5 -4
  63. package/lib/{Tabs/TabsScrollButton.js → HorizontalScroll/HorizontalScrollButton.js} +14 -8
  64. package/lib/{Tabs → HorizontalScroll}/ScrollViewEnd.js +0 -0
  65. package/lib/{Tabs → HorizontalScroll}/ScrollViewEnd.native.js +0 -0
  66. package/lib/{Tabs → HorizontalScroll}/dictionary.js +0 -0
  67. package/lib/HorizontalScroll/index.js +35 -0
  68. package/lib/{Tabs → HorizontalScroll}/itemPositions.js +0 -0
  69. package/lib/Icon/Icon.js +16 -9
  70. package/lib/Icon/IconText.js +8 -7
  71. package/lib/IconButton/IconButton.js +10 -5
  72. package/lib/InputLabel/InputLabel.js +33 -5
  73. package/lib/InputLabel/LabelContent.js +22 -12
  74. package/lib/InputLabel/LabelContent.native.js +23 -5
  75. package/lib/InputSupports/InputSupports.js +10 -5
  76. package/lib/Link/ChevronLink.js +12 -5
  77. package/lib/Link/InlinePressable.js +10 -4
  78. package/lib/Link/InlinePressable.native.js +5 -4
  79. package/lib/Link/Link.js +12 -5
  80. package/lib/Link/LinkBase.js +12 -5
  81. package/lib/Link/TextButton.js +10 -5
  82. package/lib/List/List.js +6 -6
  83. package/lib/List/ListItem.js +28 -33
  84. package/lib/List/index.js +15 -0
  85. package/lib/Modal/Modal.js +10 -5
  86. package/lib/Notification/Notification.js +21 -5
  87. package/lib/Pagination/PageButton.js +16 -11
  88. package/lib/Pagination/Pagination.js +12 -7
  89. package/lib/Pagination/SideButton.js +12 -7
  90. package/lib/Pagination/usePagination.js +2 -2
  91. package/lib/Progress/Progress.js +10 -5
  92. package/lib/Progress/ProgressBar.js +21 -10
  93. package/lib/Progress/ProgressBarBackground.js +12 -8
  94. package/lib/Radio/Radio.js +14 -13
  95. package/lib/Radio/RadioButton.js +20 -9
  96. package/lib/Radio/RadioGroup.js +24 -13
  97. package/lib/RadioCard/RadioCard.js +14 -10
  98. package/lib/RadioCard/RadioCardGroup.js +13 -12
  99. package/lib/Search/Search.js +29 -18
  100. package/lib/Select/Picker.js +11 -6
  101. package/lib/Select/Picker.native.js +21 -6
  102. package/lib/Select/Select.js +46 -4
  103. package/lib/SideNav/Item.js +10 -5
  104. package/lib/SideNav/ItemsGroup.js +10 -5
  105. package/lib/SideNav/SideNav.js +11 -7
  106. package/lib/Skeleton/Skeleton.js +15 -15
  107. package/lib/Skeleton/skeletonWebAnimation.js +1 -1
  108. package/lib/Spacer/Spacer.js +19 -7
  109. package/lib/StackView/StackView.js +26 -7
  110. package/lib/StackView/StackWrap.js +24 -13
  111. package/lib/StackView/StackWrapBox.js +34 -8
  112. package/lib/StackView/StackWrapGap.js +16 -7
  113. package/lib/StackView/common.js +4 -2
  114. package/lib/StackView/getStackedContent.js +2 -2
  115. package/lib/StepTracker/StepTracker.js +10 -5
  116. package/lib/Tabs/Tabs.js +26 -19
  117. package/lib/Tabs/TabsItem.js +16 -12
  118. package/lib/Tags/Tags.js +27 -11
  119. package/lib/TextInput/TextArea.js +7 -5
  120. package/lib/TextInput/TextInput.js +12 -6
  121. package/lib/TextInput/TextInputBase.js +12 -8
  122. package/lib/ThemeProvider/ThemeProvider.js +14 -10
  123. package/lib/ThemeProvider/useSetTheme.js +6 -1
  124. package/lib/ThemeProvider/utils/styles.js +2 -2
  125. package/lib/ThemeProvider/utils/theme-tokens.js +39 -8
  126. package/lib/ToggleSwitch/ToggleSwitch.js +11 -6
  127. package/lib/Tooltip/Backdrop.js +10 -2
  128. package/lib/Tooltip/Tooltip.js +5 -4
  129. package/lib/Typography/Typography.js +40 -24
  130. package/lib/index.js +36 -1
  131. package/lib/utils/a11y/index.js +13 -0
  132. package/lib/utils/a11y/propTypes.js +61 -0
  133. package/lib/utils/a11y/propTypes.native.js +47 -0
  134. package/lib/utils/a11y/semantics.js +173 -0
  135. package/lib/utils/animation/useVerticalExpandAnimation.js +1 -1
  136. package/lib/utils/children.js +55 -8
  137. package/lib/utils/input.js +27 -17
  138. package/lib/utils/propTypes.js +40 -68
  139. package/lib/utils/useCopy.js +1 -1
  140. package/lib/utils/useHash.js +8 -4
  141. package/lib/utils/useSpacingScale.js +1 -3
  142. package/lib/utils/useUniqueId.js +1 -1
  143. package/package.json +14 -6
  144. package/release-context.json +4 -4
  145. package/src/A11yText/index.jsx +6 -4
  146. package/src/ActivityIndicator/Spinner.jsx +5 -3
  147. package/src/ActivityIndicator/Spinner.native.jsx +5 -3
  148. package/src/Box/Box.jsx +125 -39
  149. package/src/Button/Button.jsx +7 -4
  150. package/src/Button/ButtonBase.jsx +86 -77
  151. package/src/Button/ButtonGroup.jsx +81 -69
  152. package/src/Button/ButtonLink.jsx +18 -13
  153. package/src/Card/Card.jsx +2 -2
  154. package/src/Card/CardBase.jsx +6 -4
  155. package/src/Card/PressableCardBase.jsx +71 -64
  156. package/src/Checkbox/Checkbox.jsx +118 -108
  157. package/src/Checkbox/CheckboxGroup.jsx +72 -62
  158. package/src/Divider/Divider.jsx +7 -4
  159. package/src/ExpandCollapse/Accordion.jsx +3 -2
  160. package/src/ExpandCollapse/Control.jsx +40 -43
  161. package/src/ExpandCollapse/ExpandCollapse.jsx +26 -23
  162. package/src/ExpandCollapse/Panel.jsx +69 -63
  163. package/src/Feedback/Feedback.jsx +36 -33
  164. package/src/Fieldset/Fieldset.jsx +63 -56
  165. package/src/Fieldset/FieldsetContainer.jsx +14 -5
  166. package/src/Fieldset/FieldsetContainer.native.jsx +7 -4
  167. package/src/Fieldset/Legend.jsx +7 -2
  168. package/src/Fieldset/Legend.native.jsx +7 -2
  169. package/src/FlexGrid/Col/Col.jsx +139 -132
  170. package/src/FlexGrid/FlexGrid.jsx +79 -51
  171. package/src/FlexGrid/Row/Row.jsx +55 -48
  172. package/src/HorizontalScroll/HorizontalScroll.jsx +168 -0
  173. package/src/HorizontalScroll/HorizontalScrollButton.jsx +105 -0
  174. package/src/{Tabs → HorizontalScroll}/ScrollViewEnd.jsx +0 -0
  175. package/src/{Tabs → HorizontalScroll}/ScrollViewEnd.native.jsx +0 -0
  176. package/src/{Tabs → HorizontalScroll}/dictionary.js +0 -0
  177. package/src/HorizontalScroll/index.js +17 -0
  178. package/src/{Tabs → HorizontalScroll}/itemPositions.js +0 -0
  179. package/src/Icon/Icon.jsx +37 -35
  180. package/src/Icon/IconText.jsx +22 -17
  181. package/src/IconButton/IconButton.jsx +49 -42
  182. package/src/InputLabel/InputLabel.jsx +53 -38
  183. package/src/InputLabel/LabelContent.jsx +14 -6
  184. package/src/InputLabel/LabelContent.native.jsx +11 -2
  185. package/src/InputSupports/InputSupports.jsx +29 -34
  186. package/src/Link/ChevronLink.jsx +26 -16
  187. package/src/Link/InlinePressable.jsx +5 -3
  188. package/src/Link/InlinePressable.native.jsx +5 -3
  189. package/src/Link/Link.jsx +22 -16
  190. package/src/Link/LinkBase.jsx +67 -58
  191. package/src/Link/TextButton.jsx +30 -23
  192. package/src/List/List.jsx +6 -7
  193. package/src/List/ListItem.jsx +70 -90
  194. package/src/List/index.js +5 -0
  195. package/src/Modal/Modal.jsx +9 -4
  196. package/src/Notification/Notification.jsx +58 -43
  197. package/src/Pagination/PageButton.jsx +37 -34
  198. package/src/Pagination/Pagination.jsx +88 -92
  199. package/src/Pagination/SideButton.jsx +44 -41
  200. package/src/Progress/Progress.jsx +5 -4
  201. package/src/Progress/ProgressBar.jsx +42 -29
  202. package/src/Progress/ProgressBarBackground.jsx +5 -3
  203. package/src/Radio/Radio.jsx +85 -78
  204. package/src/Radio/RadioButton.jsx +54 -43
  205. package/src/Radio/RadioGroup.jsx +74 -63
  206. package/src/RadioCard/RadioCard.jsx +75 -68
  207. package/src/RadioCard/RadioCardGroup.jsx +82 -75
  208. package/src/Search/Search.jsx +127 -106
  209. package/src/Select/Picker.jsx +49 -42
  210. package/src/Select/Picker.native.jsx +56 -49
  211. package/src/Select/Select.jsx +115 -72
  212. package/src/SideNav/Item.jsx +53 -46
  213. package/src/SideNav/ItemsGroup.jsx +50 -43
  214. package/src/SideNav/SideNav.jsx +68 -60
  215. package/src/Skeleton/Skeleton.jsx +9 -13
  216. package/src/Spacer/Spacer.jsx +11 -4
  217. package/src/StackView/StackView.jsx +47 -23
  218. package/src/StackView/StackWrap.jsx +14 -12
  219. package/src/StackView/StackWrapBox.jsx +62 -28
  220. package/src/StackView/StackWrapGap.jsx +46 -24
  221. package/src/StackView/common.jsx +3 -2
  222. package/src/StepTracker/StepTracker.jsx +73 -62
  223. package/src/Tabs/Tabs.jsx +70 -62
  224. package/src/Tabs/TabsItem.jsx +111 -103
  225. package/src/Tags/Tags.jsx +114 -102
  226. package/src/TextInput/TextArea.jsx +5 -4
  227. package/src/TextInput/TextInput.jsx +5 -4
  228. package/src/TextInput/TextInputBase.jsx +84 -77
  229. package/src/ThemeProvider/ThemeProvider.jsx +11 -7
  230. package/src/ThemeProvider/useSetTheme.js +4 -0
  231. package/src/ThemeProvider/utils/theme-tokens.js +28 -0
  232. package/src/ToggleSwitch/ToggleSwitch.jsx +49 -50
  233. package/src/Tooltip/Tooltip.jsx +134 -130
  234. package/src/Typography/Typography.jsx +67 -44
  235. package/src/index.js +3 -1
  236. package/src/utils/a11y/index.js +1 -0
  237. package/src/utils/a11y/propTypes.js +61 -0
  238. package/src/utils/a11y/propTypes.native.js +39 -0
  239. package/src/utils/a11y/semantics.js +162 -0
  240. package/src/utils/children.jsx +60 -7
  241. package/src/utils/input.js +20 -17
  242. package/src/utils/propTypes.js +30 -76
  243. package/src/utils/useCopy.js +1 -1
  244. package/src/utils/useHash.js +8 -3
  245. package/stories/A11yText/A11yText.stories.jsx +3 -3
  246. package/stories/ActivityIndicator/ActivityIndicator.stories.jsx +2 -2
  247. package/stories/Box/Box.stories.jsx +2 -2
  248. package/stories/Button/Button.stories.jsx +3 -3
  249. package/stories/Button/ButtonGroup.stories.jsx +2 -2
  250. package/stories/Button/ButtonLink.stories.jsx +2 -2
  251. package/stories/Card/Card.stories.jsx +2 -2
  252. package/stories/Checkbox/Checkbox.stories.jsx +2 -2
  253. package/stories/Divider/Divider.stories.jsx +2 -2
  254. package/stories/ExpandCollapse/ExpandCollapse.stories.jsx +3 -3
  255. package/stories/Feedback/Feedback.stories.jsx +2 -2
  256. package/stories/FlexGrid/01 FlexGrid.stories.jsx +2 -2
  257. package/stories/FlexGrid/02 Row.stories.jsx +2 -2
  258. package/stories/FlexGrid/03 Col.stories.jsx +2 -2
  259. package/stories/Icon/Icon.stories.jsx +2 -2
  260. package/stories/IconButton/IconButton.stories.jsx +2 -2
  261. package/stories/InputLabel/InputLabel.stories.jsx +2 -2
  262. package/stories/Link/ChevronLink.stories.jsx +2 -2
  263. package/stories/Link/Link.stories.jsx +2 -2
  264. package/stories/Link/TextButton.stories.jsx +2 -2
  265. package/stories/List/List.stories.jsx +2 -2
  266. package/stories/Modal/Modal.stories.jsx +2 -2
  267. package/stories/Notification/Notification.stories.jsx +2 -2
  268. package/stories/Pagination/Pagination.stories.jsx +2 -2
  269. package/stories/Progress/Progress.stories.jsx +2 -2
  270. package/stories/Radio/Radio.stories.jsx +2 -2
  271. package/stories/RadioCard/RadioCard.stories.jsx +2 -2
  272. package/stories/Search/Search.stories.jsx +2 -2
  273. package/stories/Select/Select.stories.jsx +2 -2
  274. package/stories/SideNav/SideNav.stories.jsx +2 -2
  275. package/stories/SideNav/SideNavItem.stories.jsx +2 -2
  276. package/stories/SideNav/SideNavItemsGroup.stories.jsx +2 -2
  277. package/stories/Skeleton/Skeleton.stories.jsx +3 -3
  278. package/stories/Spacer/Spacer.stories.jsx +2 -2
  279. package/stories/StackView/StackView.stories.jsx +2 -2
  280. package/stories/StackView/StackWrap.stories.jsx +2 -2
  281. package/stories/StepTracker/StepTracker.stories.jsx +2 -2
  282. package/stories/Tabs/Tabs.stories.jsx +2 -2
  283. package/stories/Tags/Tags.stories.jsx +2 -2
  284. package/stories/TextInput/TextArea.stories.jsx +2 -2
  285. package/stories/TextInput/TextInput.stories.jsx +2 -2
  286. package/stories/ToggleSwitch/ToggleSwitch.stories.jsx +2 -2
  287. package/stories/Tooltip/Tooltip.stories.jsx +2 -2
  288. package/stories/TooltipButton/TooltipButton.stories.jsx +2 -2
  289. package/stories/Typography/Typography.stories.jsx +2 -2
  290. package/stories/platform-supports.jsx +1 -1
  291. package/stories/supports.jsx +4 -5
  292. package/src/Tabs/HorizontalScroll.jsx +0 -165
  293. package/src/Tabs/TabsScrollButton.jsx +0 -100
@@ -1,8 +1,8 @@
1
- import React from 'react'
2
- import { View, Platform, Text, StyleSheet } from 'react-native'
1
+ import React, { forwardRef } from 'react'
2
+ import { View, Platform, StyleSheet } from 'react-native'
3
3
  import PropTypes from 'prop-types'
4
4
  import { useThemeTokens, applyTextStyles } from '../ThemeProvider'
5
- import { getTokensPropType, variantProp } from '../utils'
5
+ import { getTokensPropType, variantProp, wrapStringsInText } from '../utils'
6
6
 
7
7
  const selectBulletStyles = ({ itemBulletWidth, itemBulletHeight, itemBulletColor }) => ({
8
8
  width: itemBulletWidth,
@@ -22,6 +22,10 @@ const selectItemIconTokens = ({ itemIconSize, itemIconColor }) => ({
22
22
  color: itemIconColor
23
23
  })
24
24
 
25
+ const selectCommonIconStyles = ({ iconMarginTop }) => ({
26
+ marginTop: iconMarginTop
27
+ })
28
+
25
29
  const selectSideItemContainerStyles = ({ listGutter }) => ({
26
30
  marginRight: listGutter
27
31
  })
@@ -48,111 +52,87 @@ const selectDividerStyles = ({ dividerColor, dividerSize, interItemMarginWithDiv
48
52
  /**
49
53
  * ListItem is responsible for rendering icon or a bullet as side item
50
54
  */
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')
75
- }
76
-
77
- return typeof children === 'string'
78
- }
79
-
80
- const renderItem = () => {
81
- if (areChildrenStrings()) {
82
- return <Text style={itemStyles}>{children}</Text>
83
- }
84
-
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
96
- }
55
+ const ListItem = forwardRef(
56
+ ({ tokens, variant, icon, iconColor, iconSize, showDivider, children, isLastItem }, ref) => {
57
+ const themeTokens = useThemeTokens('List', tokens, variant)
58
+
59
+ const itemStyles = selectItemStyles(themeTokens)
60
+ const itemBlockStyles = selectItemBlockStyles(themeTokens)
61
+ const dividerStyles = selectDividerStyles(themeTokens)
62
+ const itemBulletContainerStyles = selectBulletContainerStyles(themeTokens)
63
+ const itemBulletStyles = selectBulletStyles(themeTokens)
64
+ const iconTokens = selectItemIconTokens(themeTokens)
65
+ const commonIconStyles = selectCommonIconStyles(themeTokens)
66
+ const sideItemContainerStyles = selectSideItemContainerStyles(themeTokens)
67
+ const accessibilityRole = Platform.select({ web: 'listitem', default: 'item' })
68
+
69
+ const renderItem = () => (
70
+ <View style={staticStyles.wrap}>{wrapStringsInText(children, { style: itemStyles })}</View>
71
+ )
97
72
 
98
- if (showDivider) {
99
- return dividerStyles
73
+ /**
74
+ * Function responsible returning styling, in case the item is the last shouldn't
75
+ * add extra margin on the bottom, if "showDivider" is true it should add a divider
76
+ * and custom margin and padding, otherwise just adds a margin to the bottom
77
+ */
78
+ const getContainerStyle = () => {
79
+ if (isLastItem) {
80
+ return undefined
81
+ }
82
+
83
+ if (showDivider) {
84
+ return dividerStyles
85
+ }
86
+
87
+ return itemBlockStyles
100
88
  }
101
89
 
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 || <></>
90
+ /**
91
+ * Renders item bullet or Icon in case it's defined
92
+ * in case children are string the icon is centered otherwise
93
+ * it will align itself at start of the container
94
+ */
95
+ const renderMarker = () => {
96
+ const IconComponent = icon || <></>
97
+
98
+ if (icon) {
99
+ return (
100
+ <View style={[sideItemContainerStyles, commonIconStyles]}>
101
+ <IconComponent
102
+ size={iconSize || iconTokens.size}
103
+ color={iconColor || iconTokens.color}
104
+ />
105
+ </View>
106
+ )
107
+ }
112
108
 
113
- if (icon) {
114
109
  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
- />
110
+ <View style={[sideItemContainerStyles, itemBulletContainerStyles]}>
111
+ <View style={itemBulletStyles} testID="unordered-item-bullet" />
128
112
  </View>
129
113
  )
130
114
  }
131
115
 
132
116
  return (
133
- <View style={[sideItemContainerStyles, itemBulletContainerStyles]}>
134
- <View style={itemBulletStyles} testID="unordered-item-bullet" />
117
+ <View
118
+ ref={ref}
119
+ style={[staticStyles.itemContainer, getContainerStyle()]}
120
+ accessibilityRole={accessibilityRole}
121
+ >
122
+ {renderMarker()}
123
+ {renderItem()}
135
124
  </View>
136
125
  )
137
126
  }
138
-
139
- return (
140
- <View
141
- style={[staticStyles.itemContainer, getContainerStyle()]}
142
- accessibilityRole={accessibilityRole}
143
- >
144
- {renderMarker()}
145
- {renderItem()}
146
- </View>
147
- )
148
- }
127
+ )
128
+ ListItem.displayName = 'ListItem'
149
129
 
150
130
  const staticStyles = StyleSheet.create({
151
131
  itemContainer: {
152
132
  flexDirection: 'row'
153
133
  },
154
- centeredIcons: {
155
- justifyContent: 'center'
134
+ wrap: {
135
+ flex: 1
156
136
  }
157
137
  })
158
138
 
package/src/List/index.js CHANGED
@@ -1,3 +1,8 @@
1
1
  import List from './List'
2
+ import ListItem from './ListItem'
3
+
4
+ List.Item = ListItem
5
+
6
+ export { List as ListBase, ListItem }
2
7
 
3
8
  export default List
@@ -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'
@@ -16,51 +16,54 @@ import {
16
16
  import useCopy from '../utils/useCopy'
17
17
  import dictionary from './dictionary'
18
18
 
19
- function PageButton({ label, onPress, href, isActive, copy, variant, tokens, ...props }) {
20
- const getTokens = useThemeTokensCallback('PaginationPageButton', tokens, variant)
19
+ const PageButton = forwardRef(
20
+ ({ label, onPress, href, isActive, copy, variant, tokens, ...props }, ref) => {
21
+ const getTokens = useThemeTokensCallback('PaginationPageButton', tokens, variant)
21
22
 
22
- const getCopy = useCopy({ dictionary, copy })
23
+ const getCopy = useCopy({ dictionary, copy })
23
24
 
24
- const getButtonTokens = (buttonState) => selectTokens('Button', getTokens(buttonState))
25
+ const getButtonTokens = (buttonState) => selectTokens('Button', getTokens(buttonState))
25
26
 
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
- : {}
27
+ const activeProps = isActive
28
+ ? {
29
+ selected: true,
30
+ ...a11yProps.nonFocusableProps,
31
+ // a brute fix for the focus state being stuck on an active item since it becomes non-focusable
32
+ // (see https://github.com/telus/universal-design-system/pull/577#issuecomment-931344107)
33
+ key: 'active-item'
34
+ }
35
+ : {}
35
36
 
36
- const accessibilityRole = href !== undefined ? 'link' : 'button'
37
- const activeLabel = isActive ? ` ${getCopy('currentLabel')}` : ''
38
- const accessibilityLabel = `${getCopy('goToLabel')} ${label}${activeLabel}`
37
+ const accessibilityRole = href !== undefined ? 'link' : 'button'
38
+ const activeLabel = isActive ? ` ${getCopy('currentLabel')}` : ''
39
+ const accessibilityLabel = `${getCopy('goToLabel')} ${label}${activeLabel}`
39
40
 
40
- const { hrefAttrs, rest } = hrefAttrsProp.bundle(props)
41
- const buttonProps = {
42
- accessibilityRole,
43
- accessibilityLabel,
44
- onPress,
45
- href,
46
- hrefAttrs,
47
- ...rest
48
- }
41
+ const { hrefAttrs, rest } = hrefAttrsProp.bundle(props)
42
+ const buttonProps = {
43
+ accessibilityRole,
44
+ accessibilityLabel,
45
+ onPress,
46
+ href,
47
+ hrefAttrs,
48
+ ...rest
49
+ }
49
50
 
50
- return (
51
- <ButtonBase {...buttonProps} tokens={getButtonTokens} {...activeProps}>
52
- {label}
53
- </ButtonBase>
54
- )
55
- }
51
+ return (
52
+ <ButtonBase ref={ref} {...buttonProps} tokens={getButtonTokens} {...activeProps}>
53
+ {label}
54
+ </ButtonBase>
55
+ )
56
+ }
57
+ )
58
+ PageButton.displayName = 'PageButton'
56
59
 
57
60
  PageButton.propTypes = {
61
+ ...linkProps.types,
58
62
  label: PropTypes.string,
59
63
  isActive: PropTypes.bool,
60
64
  copy: copyPropTypes,
61
65
  variant: variantProp.propType,
62
- tokens: getTokensPropType('PaginationPageButton'),
63
- ...linkProps.types
66
+ tokens: getTokensPropType('PaginationPageButton')
64
67
  }
65
68
 
66
69
  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