@telus-uds/components-base 0.0.2-prerelease.3 → 0.0.2-prerelease.7

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 (266) hide show
  1. package/.ultra.cache.json +1 -0
  2. package/CHANGELOG.md +55 -0
  3. package/__fixtures__/testTheme.js +528 -42
  4. package/__tests__/Button/ButtonBase.test.jsx +3 -32
  5. package/__tests__/Checkbox/Checkbox.test.jsx +94 -0
  6. package/__tests__/Divider/Divider.test.jsx +26 -5
  7. package/__tests__/Feedback/Feedback.test.jsx +42 -0
  8. package/__tests__/FlexGrid/Col.test.jsx +5 -0
  9. package/__tests__/InputSupports/InputSupports.test.jsx +50 -0
  10. package/__tests__/List/List.test.jsx +60 -0
  11. package/__tests__/Radio/Radio.test.jsx +87 -0
  12. package/__tests__/Select/Select.test.jsx +93 -0
  13. package/__tests__/Skeleton/Skeleton.test.jsx +61 -0
  14. package/__tests__/Spacer/Spacer.test.jsx +63 -0
  15. package/__tests__/StackView/StackView.test.jsx +216 -0
  16. package/__tests__/StackView/StackWrap.test.jsx +47 -0
  17. package/__tests__/StackView/getStackedContent.test.jsx +295 -0
  18. package/__tests__/Tags/Tags.test.jsx +328 -0
  19. package/__tests__/TextInput/TextArea.test.jsx +34 -0
  20. package/__tests__/TextInput/TextInputBase.test.jsx +120 -0
  21. package/__tests__/Tooltip/Tooltip.test.jsx +65 -0
  22. package/__tests__/Tooltip/getTooltipPosition.test.js +79 -0
  23. package/__tests__/utils/useCopy.test.js +31 -0
  24. package/__tests__/utils/useResponsiveProp.test.jsx +202 -0
  25. package/__tests__/utils/{spacing.test.jsx → useSpacingScale.test.jsx} +1 -1
  26. package/__tests__/utils/useUniqueId.test.js +31 -0
  27. package/jest.config.js +8 -2
  28. package/lib/Box/Box.js +7 -2
  29. package/lib/Button/Button.js +10 -3
  30. package/lib/Button/ButtonBase.js +79 -75
  31. package/lib/Button/ButtonGroup.js +24 -49
  32. package/lib/Button/ButtonLink.js +5 -0
  33. package/lib/Checkbox/Checkbox.js +308 -0
  34. package/lib/Checkbox/CheckboxInput.native.js +6 -0
  35. package/lib/Checkbox/CheckboxInput.web.js +57 -0
  36. package/lib/Checkbox/index.js +2 -0
  37. package/lib/Divider/Divider.js +40 -2
  38. package/lib/Feedback/Feedback.js +132 -0
  39. package/lib/Feedback/index.js +2 -0
  40. package/lib/Icon/Icon.js +9 -6
  41. package/lib/Icon/IconText.js +72 -0
  42. package/lib/Icon/index.js +2 -1
  43. package/lib/InputLabel/InputLabel.js +88 -0
  44. package/lib/InputLabel/LabelContent.native.js +8 -0
  45. package/lib/InputLabel/LabelContent.web.js +17 -0
  46. package/lib/InputLabel/index.js +2 -0
  47. package/lib/InputSupports/InputSupports.js +90 -0
  48. package/lib/InputSupports/index.js +2 -0
  49. package/lib/InputSupports/propTypes.js +55 -0
  50. package/lib/Link/ChevronLink.js +35 -10
  51. package/lib/Link/InlinePressable.native.js +78 -0
  52. package/lib/Link/InlinePressable.web.js +32 -0
  53. package/lib/Link/Link.js +11 -10
  54. package/lib/Link/LinkBase.js +69 -124
  55. package/lib/Link/TextButton.js +20 -9
  56. package/lib/Link/index.js +2 -1
  57. package/lib/List/List.js +52 -0
  58. package/lib/List/ListItem.js +207 -0
  59. package/lib/List/index.js +2 -0
  60. package/lib/Pagination/PageButton.js +3 -26
  61. package/lib/Pagination/SideButton.js +32 -42
  62. package/lib/Radio/Radio.js +291 -0
  63. package/lib/Radio/RadioInput.native.js +6 -0
  64. package/lib/Radio/RadioInput.web.js +59 -0
  65. package/lib/Radio/index.js +2 -0
  66. package/lib/Select/Group.native.js +14 -0
  67. package/lib/Select/Group.web.js +18 -0
  68. package/lib/Select/Item.native.js +9 -0
  69. package/lib/Select/Item.web.js +15 -0
  70. package/lib/Select/Picker.native.js +87 -0
  71. package/lib/Select/Picker.web.js +63 -0
  72. package/lib/Select/Select.js +272 -0
  73. package/lib/Select/index.js +6 -0
  74. package/lib/Skeleton/Skeleton.js +119 -0
  75. package/lib/Skeleton/index.js +2 -0
  76. package/lib/Spacer/Spacer.js +98 -0
  77. package/lib/Spacer/index.js +2 -0
  78. package/lib/StackView/StackView.js +107 -0
  79. package/lib/StackView/StackWrap.js +32 -0
  80. package/lib/StackView/StackWrap.native.js +3 -0
  81. package/lib/StackView/StackWrapBox.js +90 -0
  82. package/lib/StackView/StackWrapGap.js +50 -0
  83. package/lib/StackView/common.js +30 -0
  84. package/lib/StackView/getStackedContent.js +111 -0
  85. package/lib/StackView/index.js +5 -0
  86. package/lib/Tags/Tags.js +217 -0
  87. package/lib/Tags/index.js +2 -0
  88. package/lib/TextInput/TextArea.js +82 -0
  89. package/lib/TextInput/TextInput.js +54 -0
  90. package/lib/TextInput/TextInputBase.js +229 -0
  91. package/lib/TextInput/index.js +3 -0
  92. package/lib/TextInput/propTypes.js +31 -0
  93. package/lib/ThemeProvider/useThemeTokens.js +54 -3
  94. package/lib/ToggleSwitch/ToggleSwitch.js +1 -1
  95. package/lib/Tooltip/Backdrop.native.js +35 -0
  96. package/lib/Tooltip/Backdrop.web.js +52 -0
  97. package/lib/Tooltip/Tooltip.js +315 -0
  98. package/lib/Tooltip/dictionary.js +8 -0
  99. package/lib/Tooltip/getTooltipPosition.js +164 -0
  100. package/lib/Tooltip/index.js +2 -0
  101. package/lib/TooltipButton/TooltipButton.js +64 -0
  102. package/lib/TooltipButton/index.js +2 -0
  103. package/lib/Typography/Typography.js +4 -23
  104. package/lib/ViewportProvider/ViewportProvider.js +25 -0
  105. package/lib/ViewportProvider/index.js +2 -43
  106. package/lib/ViewportProvider/useViewport.js +3 -0
  107. package/lib/ViewportProvider/useViewportListener.js +43 -0
  108. package/lib/index.js +15 -1
  109. package/lib/utils/a11y/index.js +1 -0
  110. package/lib/utils/a11y/textSize.js +33 -0
  111. package/lib/utils/index.js +7 -1
  112. package/lib/utils/info/index.js +7 -0
  113. package/lib/utils/info/platform/index.js +11 -0
  114. package/lib/utils/info/platform/platform.android.js +1 -0
  115. package/lib/utils/info/platform/platform.ios.js +1 -0
  116. package/lib/utils/info/platform/platform.native.js +4 -0
  117. package/lib/utils/info/platform/platform.web.js +1 -0
  118. package/lib/utils/info/versions.js +5 -0
  119. package/lib/utils/input.js +3 -1
  120. package/lib/utils/pressability.js +92 -0
  121. package/lib/utils/propTypes.js +77 -8
  122. package/lib/utils/useCopy.js +16 -0
  123. package/lib/utils/useResponsiveProp.js +47 -0
  124. package/lib/utils/{spacing/useSpacingScale.js → useSpacingScale.js} +30 -9
  125. package/lib/utils/useUniqueId.js +12 -0
  126. package/package.json +7 -5
  127. package/release-context.json +4 -4
  128. package/src/Box/Box.jsx +4 -2
  129. package/src/Button/Button.jsx +6 -3
  130. package/src/Button/ButtonBase.jsx +72 -75
  131. package/src/Button/ButtonGroup.jsx +22 -39
  132. package/src/Button/ButtonLink.jsx +11 -2
  133. package/src/Checkbox/Checkbox.jsx +275 -0
  134. package/src/Checkbox/CheckboxInput.native.jsx +6 -0
  135. package/src/Checkbox/CheckboxInput.web.jsx +55 -0
  136. package/src/Checkbox/index.js +3 -0
  137. package/src/Divider/Divider.jsx +38 -3
  138. package/src/Feedback/Feedback.jsx +108 -0
  139. package/src/Feedback/index.js +3 -0
  140. package/src/Icon/Icon.jsx +11 -6
  141. package/src/Icon/IconText.jsx +63 -0
  142. package/src/Icon/index.js +2 -1
  143. package/src/InputLabel/InputLabel.jsx +99 -0
  144. package/src/InputLabel/LabelContent.native.jsx +6 -0
  145. package/src/InputLabel/LabelContent.web.jsx +13 -0
  146. package/src/InputLabel/index.js +3 -0
  147. package/src/InputSupports/InputSupports.jsx +86 -0
  148. package/src/InputSupports/index.js +3 -0
  149. package/src/InputSupports/propTypes.js +44 -0
  150. package/src/Link/ChevronLink.jsx +28 -7
  151. package/src/Link/InlinePressable.native.jsx +73 -0
  152. package/src/Link/InlinePressable.web.jsx +37 -0
  153. package/src/Link/Link.jsx +17 -13
  154. package/src/Link/LinkBase.jsx +62 -139
  155. package/src/Link/TextButton.jsx +25 -11
  156. package/src/Link/index.js +2 -1
  157. package/src/List/List.jsx +47 -0
  158. package/src/List/ListItem.jsx +187 -0
  159. package/src/List/index.js +3 -0
  160. package/src/Pagination/PageButton.jsx +3 -17
  161. package/src/Pagination/SideButton.jsx +27 -38
  162. package/src/Radio/Radio.jsx +270 -0
  163. package/src/Radio/RadioInput.native.jsx +6 -0
  164. package/src/Radio/RadioInput.web.jsx +57 -0
  165. package/src/Radio/index.js +3 -0
  166. package/src/Select/Group.native.jsx +14 -0
  167. package/src/Select/Group.web.jsx +15 -0
  168. package/src/Select/Item.native.jsx +10 -0
  169. package/src/Select/Item.web.jsx +11 -0
  170. package/src/Select/Picker.native.jsx +95 -0
  171. package/src/Select/Picker.web.jsx +67 -0
  172. package/src/Select/Select.jsx +265 -0
  173. package/src/Select/index.js +8 -0
  174. package/src/Skeleton/Skeleton.jsx +101 -0
  175. package/src/Skeleton/index.js +3 -0
  176. package/src/Spacer/Spacer.jsx +91 -0
  177. package/src/Spacer/index.js +3 -0
  178. package/src/StackView/StackView.jsx +104 -0
  179. package/src/StackView/StackWrap.jsx +33 -0
  180. package/src/StackView/StackWrap.native.jsx +4 -0
  181. package/src/StackView/StackWrapBox.jsx +93 -0
  182. package/src/StackView/StackWrapGap.jsx +49 -0
  183. package/src/StackView/common.jsx +28 -0
  184. package/src/StackView/getStackedContent.jsx +106 -0
  185. package/src/StackView/index.js +6 -0
  186. package/src/Tags/Tags.jsx +206 -0
  187. package/src/Tags/index.js +3 -0
  188. package/src/TextInput/TextArea.jsx +78 -0
  189. package/src/TextInput/TextInput.jsx +52 -0
  190. package/src/TextInput/TextInputBase.jsx +220 -0
  191. package/src/TextInput/index.js +4 -0
  192. package/src/TextInput/propTypes.js +29 -0
  193. package/src/ThemeProvider/useThemeTokens.js +54 -3
  194. package/src/ToggleSwitch/ToggleSwitch.jsx +1 -1
  195. package/src/Tooltip/Backdrop.native.jsx +33 -0
  196. package/src/Tooltip/Backdrop.web.jsx +60 -0
  197. package/src/Tooltip/Tooltip.jsx +294 -0
  198. package/src/Tooltip/dictionary.js +8 -0
  199. package/src/Tooltip/getTooltipPosition.js +161 -0
  200. package/src/Tooltip/index.js +3 -0
  201. package/src/TooltipButton/TooltipButton.jsx +53 -0
  202. package/src/TooltipButton/index.js +3 -0
  203. package/src/Typography/Typography.jsx +4 -19
  204. package/src/ViewportProvider/ViewportProvider.jsx +21 -0
  205. package/src/ViewportProvider/index.jsx +2 -41
  206. package/src/ViewportProvider/useViewport.js +5 -0
  207. package/src/ViewportProvider/useViewportListener.js +43 -0
  208. package/src/index.js +15 -1
  209. package/src/utils/a11y/index.js +1 -0
  210. package/src/utils/a11y/textSize.js +30 -0
  211. package/src/utils/index.js +8 -1
  212. package/src/utils/info/index.js +8 -0
  213. package/src/utils/info/platform/index.js +11 -0
  214. package/src/utils/info/platform/platform.android.js +1 -0
  215. package/src/utils/info/platform/platform.ios.js +1 -0
  216. package/src/utils/info/platform/platform.native.js +4 -0
  217. package/src/utils/info/platform/platform.web.js +1 -0
  218. package/src/utils/info/versions.js +6 -0
  219. package/src/utils/input.js +2 -1
  220. package/src/utils/pressability.js +92 -0
  221. package/src/utils/propTypes.js +97 -13
  222. package/src/utils/useCopy.js +13 -0
  223. package/src/utils/useResponsiveProp.js +50 -0
  224. package/src/utils/{spacing/useSpacingScale.js → useSpacingScale.js} +25 -10
  225. package/src/utils/useUniqueId.js +14 -0
  226. package/stories/A11yText/A11yText.stories.jsx +11 -5
  227. package/stories/ActivityIndicator/ActivityIndicator.stories.jsx +11 -2
  228. package/stories/Box/Box.stories.jsx +29 -2
  229. package/stories/Button/Button.stories.jsx +21 -20
  230. package/stories/Button/ButtonGroup.stories.jsx +2 -1
  231. package/stories/Button/ButtonLink.stories.jsx +6 -4
  232. package/stories/Card/Card.stories.jsx +13 -1
  233. package/stories/Checkbox/Checkbox.stories.jsx +71 -0
  234. package/stories/Divider/Divider.stories.jsx +26 -2
  235. package/stories/ExpandCollapse/ExpandCollapse.stories.jsx +74 -79
  236. package/stories/Feedback/Feedback.stories.jsx +96 -0
  237. package/stories/FlexGrid/01 FlexGrid.stories.jsx +20 -7
  238. package/stories/Icon/Icon.stories.jsx +11 -3
  239. package/stories/InputLabel/InputLabel.stories.jsx +42 -0
  240. package/stories/Link/ChevronLink.stories.jsx +20 -4
  241. package/stories/Link/Link.stories.jsx +39 -3
  242. package/stories/Link/TextButton.stories.jsx +24 -2
  243. package/stories/List/List.stories.jsx +117 -0
  244. package/stories/Pagination/Pagination.stories.jsx +28 -14
  245. package/stories/Radio/Radio.stories.jsx +113 -0
  246. package/stories/Select/Select.stories.jsx +55 -0
  247. package/stories/SideNav/SideNav.stories.jsx +17 -2
  248. package/stories/Skeleton/Skeleton.stories.jsx +36 -0
  249. package/stories/Spacer/Spacer.stories.jsx +38 -0
  250. package/stories/StackView/StackView.stories.jsx +75 -0
  251. package/stories/StackView/StackWrap.stories.jsx +64 -0
  252. package/stories/Tags/Tags.stories.jsx +69 -0
  253. package/stories/TextInput/TextArea.stories.jsx +100 -0
  254. package/stories/TextInput/TextInput.stories.jsx +103 -0
  255. package/stories/ToggleSwitch/ToggleSwitch.stories.jsx +16 -3
  256. package/stories/Tooltip/Tooltip.stories.jsx +81 -0
  257. package/stories/TooltipButton/TooltipButton.stories.jsx +11 -0
  258. package/stories/Typography/Typography.stories.jsx +12 -3
  259. package/stories/platform-supports.web.jsx +1 -1
  260. package/stories/supports.jsx +110 -14
  261. package/lib/Pagination/useCopy.js +0 -10
  262. package/lib/utils/spacing/index.js +0 -2
  263. package/lib/utils/spacing/utils.js +0 -32
  264. package/src/Pagination/useCopy.js +0 -7
  265. package/src/utils/spacing/index.js +0 -3
  266. package/src/utils/spacing/utils.js +0 -28
@@ -1,11 +1,14 @@
1
1
  import React from 'react'
2
+
2
3
  import ButtonBase from './ButtonBase'
3
4
  import buttonPropTypes from './propTypes'
5
+ import { useThemeTokensCallback } from '../ThemeProvider'
4
6
  import { a11yProps } from '../utils/propTypes'
5
7
 
6
- const Button = ({ accessibilityRole = 'button', ...props }) => (
7
- <ButtonBase {...props} accessibilityRole={accessibilityRole} />
8
- )
8
+ const Button = ({ accessibilityRole = 'button', tokens, variant, ...props }) => {
9
+ const getTokens = useThemeTokensCallback('Button', tokens, variant)
10
+ return <ButtonBase {...props} tokens={getTokens} accessibilityRole={accessibilityRole} />
11
+ }
9
12
 
10
13
  Button.propTypes = {
11
14
  ...a11yProps.types,
@@ -1,23 +1,22 @@
1
1
  import React from 'react'
2
2
  import { Pressable, Text, View, StyleSheet, Platform } from 'react-native'
3
3
 
4
- import { useThemeTokensCallback } from '../ThemeProvider'
5
4
  import { applyTextStyles, applyShadowToken } from '../ThemeProvider/utils'
6
5
  import buttonPropTypes from './propTypes'
7
- import { a11yProps, hrefAttrsProp, linkProps } from '../utils/propTypes'
8
-
9
- const getCursorStyle = (inactive, accessibilityRole) => {
10
- if (inactive) return 'not-allowed'
11
- // These roles should result in cursor: pointer but don't in current RNW releases
12
- if (['checkbox', 'radio', 'switch'].includes(accessibilityRole)) return 'pointer'
13
- // For everything else, let React Native Web figure it out internally
14
- return undefined
15
- }
6
+ import {
7
+ a11yProps,
8
+ getCursorStyle,
9
+ hrefAttrsProp,
10
+ linkProps,
11
+ resolvePressableState,
12
+ resolvePressableTokens
13
+ } from '../utils'
16
14
 
17
15
  const getOuterBorderOffset = ({ outerBorderGap = 0, outerBorderWidth = 0 }) =>
18
16
  outerBorderGap + outerBorderWidth
19
17
 
20
18
  const selectOuterContainerStyles = ({
19
+ alignSelf,
21
20
  opacity,
22
21
  outerBorderColor,
23
22
  outerBorderWidth,
@@ -25,6 +24,7 @@ const selectOuterContainerStyles = ({
25
24
  outerBorderRadius = 0,
26
25
  outerBackgroundColor
27
26
  }) => ({
27
+ alignSelf,
28
28
  padding: outerBorderGap,
29
29
  borderWidth: outerBorderWidth,
30
30
  borderColor: outerBorderColor,
@@ -33,25 +33,13 @@ const selectOuterContainerStyles = ({
33
33
  opacity
34
34
  })
35
35
 
36
- const selectOuterWidthStyles = ({
37
- outerBorderGap,
38
- outerBorderWidth,
39
- width,
40
- // TODO: make margin the responsibility of a parent
41
- // https://github.com/telus/universal-design-system/issues/525
42
- marginTop = 0,
43
- marginBottom = 0,
44
- marginLeft = 0,
45
- marginRight = 0
46
- }) => {
36
+ const selectOuterWidthStyles = ({ outerBorderGap, outerBorderWidth, width }) => {
47
37
  // The inner container's bounding box is the bounding box of the button overall
48
38
  // so this many device pixels will sit outside of the overall bounding box
49
39
  const outerBorderOffset = getOuterBorderOffset({ outerBorderGap, outerBorderWidth })
40
+
50
41
  const widthStyles = {
51
- marginTop: marginTop - outerBorderOffset,
52
- marginBottom: marginBottom - outerBorderOffset,
53
- marginLeft: marginLeft - outerBorderOffset,
54
- marginRight: marginRight - outerBorderOffset
42
+ margin: 0 - outerBorderOffset
55
43
  }
56
44
 
57
45
  if (!width) {
@@ -59,9 +47,8 @@ const selectOuterWidthStyles = ({
59
47
  ...widthStyles,
60
48
  // Wrap content, stopping a flex parent's default align-items: stretch stretching focus ring beyond content
61
49
  ...Platform.select({
62
- web: { width: 'fit-content' },
63
- // No fit-content or inline-block in RN. TODO: we might need to provide a prop to allow flex-end or center
64
- native: { alignSelf: 'flex-start' }
50
+ // width: fit-content isn't supported on Firefox; can't cascade props like CSS `width: fit-content; width: --moz-fit-content;`
51
+ web: { display: 'inline-flex' }
65
52
  })
66
53
  }
67
54
  }
@@ -95,7 +82,8 @@ const selectInnerContainerStyles = ({
95
82
  paddingTop,
96
83
  paddingBottom,
97
84
  shadow,
98
- borderWidth
85
+ borderWidth,
86
+ minWidth
99
87
  }) => {
100
88
  // Subtract border width from padding so overall button width/height doesn't
101
89
  // jump around if the border width changes (avoiding NaN and negative padding)
@@ -110,6 +98,7 @@ const selectInnerContainerStyles = ({
110
98
  paddingTop: offsetBorder(paddingTop),
111
99
  paddingBottom: offsetBorder(paddingBottom),
112
100
  backgroundColor,
101
+ minWidth,
113
102
  ...applyShadowToken(shadow)
114
103
  }
115
104
  }
@@ -130,76 +119,76 @@ const selectTextStyles = ({ fontSize, color, lineHeight, fontName, fontWeight, t
130
119
  textAlign
131
120
  })
132
121
 
133
- const selectWebOnlyStyles = (inactive, themeTokens, { accessibilityRole }) =>
134
- Platform.OS === 'web'
135
- ? {
136
- // if it would overflow the container, wraps instead
137
- maxWidth: `calc(100% + ${getOuterBorderOffset(themeTokens) * 2}px)`,
138
- cursor: getCursorStyle(inactive, accessibilityRole),
139
- outline: 'none' // removes the default browser :focus outline
140
- }
141
- : {}
122
+ const selectWebOnlyStyles = (inactive, themeTokens, { accessibilityRole }) => {
123
+ return Platform.select({
124
+ web: {
125
+ // if it would overflow the container, wraps instead
126
+ maxWidth: `calc(100% + ${getOuterBorderOffset(themeTokens) * 2}px)`,
127
+ outline: 'none', // removes the default browser :focus outline
128
+ ...getCursorStyle(inactive, accessibilityRole)
129
+ },
130
+ default: {}
131
+ })
132
+ }
133
+
134
+ // TODO: see if this can be made into a generalised utility, ideally when
135
+ // there is a stable, generic, generalised approach to within-component text
136
+ const resolveChildren = (children, { textStyles, state }) => {
137
+ switch (typeof children) {
138
+ case 'function':
139
+ return children(state)
140
+ case 'string':
141
+ return <Text style={textStyles}>{children}</Text>
142
+ default:
143
+ return children
144
+ }
145
+ }
142
146
 
143
147
  const ButtonBase = ({
144
148
  href,
145
149
  hrefAttrs,
146
150
  children,
147
- variant,
148
151
  onPress,
149
- tokens,
152
+ tokens = {},
150
153
  disabled = false, // alias for inactive
151
154
  inactive = disabled,
152
155
  selected = false,
153
156
  ...rest
154
157
  }) => {
155
- const getTokens = useThemeTokensCallback('Button', tokens, variant)
156
- const getButtonState = ({ pressed, focused, hovered }) => ({
157
- pressed,
158
- focus: focused,
159
- hover: hovered,
160
- inactive,
161
- selected
162
- })
163
- const getTokensByPressableState = (pressableState) => getTokens(getButtonState(pressableState))
158
+ const extraButtonState = { inactive, selected }
159
+ const resolveTokens = (pressableState) =>
160
+ resolvePressableTokens(tokens, pressableState, extraButtonState)
164
161
 
165
162
  const a11y = a11yProps.select(rest)
166
163
 
167
164
  const getPressableStyle = (pressableState) => {
168
- const themeTokens = getTokensByPressableState(pressableState)
165
+ const themeTokens = resolveTokens(pressableState)
169
166
  return [
170
- staticStyles.wrapper,
167
+ staticStyles.row,
171
168
  selectWebOnlyStyles(inactive, themeTokens, a11y),
172
169
  selectOuterContainerStyles(themeTokens),
173
170
  selectOuterWidthStyles(themeTokens)
174
171
  ]
175
172
  }
176
173
 
177
- const handlePress = linkProps.handleHref({ href, onPress })
178
-
179
174
  return (
180
175
  <Pressable
181
- onPress={handlePress}
176
+ href={href}
177
+ onPress={linkProps.handleHref({ href, onPress })}
182
178
  style={getPressableStyle}
183
179
  disabled={inactive}
184
- href={href}
185
180
  {...hrefAttrsProp.spread(hrefAttrs)}
186
181
  {...a11y}
187
182
  >
188
183
  {(pressableState) => {
189
- const themeTokens = getTokensByPressableState(pressableState)
184
+ const themeTokens = resolveTokens(pressableState)
190
185
  const containerStyles = selectInnerContainerStyles(themeTokens)
191
186
  const borderStyles = selectBorderStyles(themeTokens)
192
- const textStyles = {
193
- ...selectTextStyles(themeTokens),
194
- ...Platform.select({
195
- // TODO: https://github.com/telus/universal-design-system/issues/487
196
- web: { transition: 'color 200ms' }
197
- })
198
- }
187
+ const textStyles = [selectTextStyles(themeTokens), staticStyles.text]
199
188
 
200
189
  // If the container has a width set, fill it instead of sizing from content.
201
190
  // If in future we support text alignments other than center, add here.
202
- const stretchStyles = !!themeTokens.width && staticStyles.center
191
+ const stretchStyles = themeTokens.width ? staticStyles.stretch : staticStyles.align
203
192
 
204
193
  return (
205
194
  <View
@@ -207,6 +196,7 @@ const ButtonBase = ({
207
196
  containerStyles,
208
197
  borderStyles,
209
198
  stretchStyles,
199
+ staticStyles.row,
210
200
  Platform.select({
211
201
  web: {
212
202
  maxWidth: '100%', // ensure overflowing content wraps
@@ -216,14 +206,10 @@ const ButtonBase = ({
216
206
  })
217
207
  ]}
218
208
  >
219
- {typeof children === 'function' ? (
220
- children({
221
- ...getButtonState(pressableState),
222
- textStyles
223
- })
224
- ) : (
225
- <Text style={textStyles}>{children}</Text>
226
- )}
209
+ {resolveChildren(children, {
210
+ state: { ...resolvePressableState(pressableState, extraButtonState), textStyles },
211
+ textStyles
212
+ })}
227
213
  </View>
228
214
  )
229
215
  }}
@@ -238,10 +224,21 @@ ButtonBase.propTypes = {
238
224
  }
239
225
 
240
226
  const staticStyles = StyleSheet.create({
241
- wrapper: {
242
- flexDirection: 'row' // ensures alignSelf is horizontal
227
+ row: {
228
+ // Apply all button alignment horizontally; no vertical stacking within a button
229
+ flexDirection: 'row'
230
+ },
231
+ text: {
232
+ flexGrow: 1, // On native but not web, flexShrink here wraps text prematurely
233
+ ...Platform.select({
234
+ // TODO: https://github.com/telus/universal-design-system/issues/487
235
+ web: { transition: 'color 200ms' }
236
+ })
237
+ },
238
+ align: {
239
+ alignItems: 'center'
243
240
  },
244
- center: {
241
+ stretch: {
245
242
  flex: 1,
246
243
  alignItems: 'center',
247
244
  justifyContent: 'center'
@@ -1,24 +1,23 @@
1
1
  import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
- import { View, Platform } from 'react-native'
3
+ import { Platform } from 'react-native'
4
4
 
5
5
  import ButtonBase from './ButtonBase'
6
+ import { StackWrap } from '../StackView'
6
7
  import { useViewport } from '../ViewportProvider'
7
- import { useThemeTokens } from '../ThemeProvider'
8
- import { a11yProps, pressProps, variantProp, getTokensPropType } from '../utils/propTypes'
8
+ import { useThemeTokens, useThemeTokensCallback } from '../ThemeProvider'
9
+ import {
10
+ a11yProps,
11
+ pressProps,
12
+ variantProp,
13
+ getTokensPropType,
14
+ selectTokens
15
+ } from '../utils/propTypes'
9
16
  import { useMultipleInputValues } from '../utils/input'
10
-
11
- const selectContainerStyles = ({ direction }) => ({
12
- flexDirection: direction
13
- })
14
-
15
- const selectItemTokens = ({ gap }, index) => ({
16
- marginLeft: index && gap
17
- })
17
+ import { getPressHandlersWithArgs } from '../utils/pressability'
18
18
 
19
19
  const ButtonGroup = ({
20
20
  variant,
21
- buttonVariant = {},
22
21
  tokens,
23
22
  items = [],
24
23
  values,
@@ -34,7 +33,10 @@ const ButtonGroup = ({
34
33
  }) => {
35
34
  const viewport = useViewport()
36
35
  const themeTokens = useThemeTokens('ButtonGroup', tokens, variant, { viewport })
37
- const containerStyles = selectContainerStyles(themeTokens)
36
+ const stackTokens = selectTokens('StackView', themeTokens)
37
+ const { direction, space } = themeTokens
38
+
39
+ const getButtonTokens = useThemeTokensCallback('ButtonGroupItem', tokens, variant)
38
40
 
39
41
  const { currentValues, toggleOneValue } = useMultipleInputValues({
40
42
  initialValues,
@@ -51,20 +53,13 @@ const ButtonGroup = ({
51
53
  const itemA11yRole = a11y.accessibilityRole === 'radioGroup' ? 'radio' : 'checkbox'
52
54
 
53
55
  return (
54
- <View style={containerStyles} {...a11y}>
56
+ <StackWrap {...a11y} space={space} direction={direction} tokens={stackTokens}>
55
57
  {items.map(({ label, id = label, accessibilityLabel }, index) => {
56
- const itemTokens = selectItemTokens(themeTokens, index)
57
58
  const isSelected = currentValues.includes(id)
58
59
 
59
- // Allow handlers to be passed down for blur, hover, focus, pressIn, etc
60
- const pressHandlers = Object.fromEntries(
61
- Object.entries(pressProps.select(rest)).map(([key, handler]) => ({
62
- [key]: (args) => {
63
- // Pass each handler data on this button and current selection
64
- handler({ id, label, currentValues }, ...args)
65
- }
66
- }))
67
- )
60
+ // Pass an object of relevant component state as first argument for any passed-in press handlers
61
+ const pressHandlers = getPressHandlersWithArgs(rest, [{ id, label, currentValues }])
62
+
68
63
  const handlePress = () => {
69
64
  if (pressHandlers.onPress) pressHandlers.onPress()
70
65
  toggleOneValue(id)
@@ -74,28 +69,17 @@ const ButtonGroup = ({
74
69
  accessibilityState: { checked: isSelected },
75
70
  accessibilityRole: itemA11yRole,
76
71
  accessibilityLabel,
77
- ...Platform.select({
78
- web: {
79
- // accessibilityPosInSet etc exists in React Native Web main branch
80
- // but not in a release compatible with Expo etc; just use `aria-*`
81
- 'aria-setsize': items.length,
82
- 'aria-posinset': index + 1
83
- },
84
- default: {}
85
- })
72
+ ...a11yProps.getPositionInSet(items.length, index)
86
73
  }
87
74
 
88
75
  // Ensure button is direct child of group as MacOS voiceover only applies "X of Y" to
89
76
  // "radio" if it's a direct child of "radiogroup", even if aria-posinset etc exists
90
- // See also: TODO: make margin the responsibility of a parent
91
- // https://github.com/telus/universal-design-system/issues/525
92
77
  return (
93
78
  <ButtonBase
94
79
  key={id}
95
80
  {...pressHandlers}
96
81
  onPress={handlePress}
97
- variant={{ component: 'ButtonGroup', ...buttonVariant }}
98
- tokens={itemTokens}
82
+ tokens={getButtonTokens}
99
83
  selected={isSelected}
100
84
  inactive={inactive}
101
85
  {...itemA11y}
@@ -104,7 +88,7 @@ const ButtonGroup = ({
104
88
  </ButtonBase>
105
89
  )
106
90
  })}
107
- </View>
91
+ </StackWrap>
108
92
  )
109
93
  }
110
94
 
@@ -113,7 +97,6 @@ ButtonGroup.propTypes = {
113
97
  ...pressProps.propTypes,
114
98
  tokens: getTokensPropType('ButtonGroup'),
115
99
  variant: variantProp.propType,
116
- buttonVariant: variantProp.propType,
117
100
  /**
118
101
  * The maximum number of items a user may select at once. Defaults to 1 and behaves
119
102
  * like radio buttons. To have no limit and allow any number of selections, pass `null`.
@@ -2,14 +2,23 @@ import React from 'react'
2
2
  import ButtonBase from './ButtonBase'
3
3
  import buttonPropTypes from './propTypes'
4
4
  import { a11yProps, hrefAttrsProp, linkProps } from '../utils/propTypes'
5
+ import { useThemeTokensCallback } from '../ThemeProvider'
5
6
 
6
7
  /**
7
8
  * `ButtonLink` is a component with the semantics and behaviour of a link, but with the visual appearance of a button.
8
9
  * ButtonLink is a block-level component and should not be used inline.
9
10
  */
10
- const ButtonLink = ({ accessibilityRole = 'link', ...props }) => {
11
+ const ButtonLink = ({ accessibilityRole = 'link', tokens, variant, ...props }) => {
11
12
  const { hrefAttrs, rest } = hrefAttrsProp.bundle(props)
12
- return <ButtonBase accessibilityRole={accessibilityRole} hrefAttrs={hrefAttrs} {...rest} />
13
+ const getTokens = useThemeTokensCallback('Button', tokens, variant)
14
+ return (
15
+ <ButtonBase
16
+ accessibilityRole={accessibilityRole}
17
+ tokens={getTokens}
18
+ hrefAttrs={hrefAttrs}
19
+ {...rest}
20
+ />
21
+ )
13
22
  }
14
23
 
15
24
  ButtonLink.propTypes = {