@telus-uds/components-base 1.85.1 → 1.87.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 (59) hide show
  1. package/CHANGELOG.md +34 -2
  2. package/lib/ActionCard/ActionCard.js +350 -0
  3. package/lib/ActionCard/index.js +10 -0
  4. package/lib/Card/Card.js +3 -3
  5. package/lib/Card/PressableCardBase.js +1 -1
  6. package/lib/Checkbox/Checkbox.js +4 -0
  7. package/lib/Link/TextButton.js +17 -7
  8. package/lib/List/List.js +9 -2
  9. package/lib/List/ListItemContent.js +3 -2
  10. package/lib/Modal/ModalContent.js +6 -8
  11. package/lib/Modal/WebModal.js +2 -1
  12. package/lib/Notification/Notification.js +20 -15
  13. package/lib/Radio/Radio.js +4 -0
  14. package/lib/Select/Picker.js +4 -0
  15. package/lib/Select/Select.js +1 -1
  16. package/lib/Tabs/Tabs.js +4 -1
  17. package/lib/Tabs/TabsItem.js +7 -1
  18. package/lib/index.js +8 -0
  19. package/lib/utils/animation/useVerticalExpandAnimation.js +3 -3
  20. package/lib/utils/props/tokens.js +2 -2
  21. package/lib-module/ActionCard/ActionCard.js +343 -0
  22. package/lib-module/ActionCard/index.js +2 -0
  23. package/lib-module/Card/Card.js +4 -4
  24. package/lib-module/Card/PressableCardBase.js +1 -1
  25. package/lib-module/Checkbox/Checkbox.js +4 -0
  26. package/lib-module/Link/TextButton.js +17 -7
  27. package/lib-module/List/List.js +9 -2
  28. package/lib-module/List/ListItemContent.js +3 -2
  29. package/lib-module/Modal/ModalContent.js +6 -8
  30. package/lib-module/Modal/WebModal.js +2 -1
  31. package/lib-module/Notification/Notification.js +20 -15
  32. package/lib-module/Radio/Radio.js +4 -0
  33. package/lib-module/Select/Picker.js +5 -1
  34. package/lib-module/Select/Select.js +2 -2
  35. package/lib-module/Tabs/Tabs.js +4 -1
  36. package/lib-module/Tabs/TabsItem.js +7 -1
  37. package/lib-module/index.js +1 -0
  38. package/lib-module/utils/animation/useVerticalExpandAnimation.js +3 -3
  39. package/lib-module/utils/props/tokens.js +2 -2
  40. package/package.json +2 -2
  41. package/src/ActionCard/ActionCard.jsx +306 -0
  42. package/src/ActionCard/index.js +3 -0
  43. package/src/Card/Card.jsx +6 -4
  44. package/src/Card/PressableCardBase.jsx +1 -1
  45. package/src/Checkbox/Checkbox.jsx +3 -1
  46. package/src/Link/TextButton.jsx +17 -9
  47. package/src/List/List.jsx +7 -2
  48. package/src/List/ListItemContent.jsx +2 -2
  49. package/src/Modal/ModalContent.jsx +3 -5
  50. package/src/Modal/WebModal.jsx +2 -1
  51. package/src/Notification/Notification.jsx +36 -16
  52. package/src/Radio/Radio.jsx +3 -1
  53. package/src/Select/Picker.jsx +6 -1
  54. package/src/Select/Select.jsx +4 -2
  55. package/src/Tabs/Tabs.jsx +4 -1
  56. package/src/Tabs/TabsItem.jsx +5 -1
  57. package/src/index.js +1 -0
  58. package/src/utils/animation/useVerticalExpandAnimation.js +3 -3
  59. package/src/utils/props/tokens.js +4 -2
@@ -1,5 +1,6 @@
1
1
  import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
+ import { View, StyleSheet } from 'react-native'
3
4
  import { useThemeTokensCallback } from '../ThemeProvider'
4
5
  import LinkBase from './LinkBase'
5
6
  import { variantProp } from '../utils'
@@ -13,18 +14,25 @@ const TextButton = React.forwardRef(
13
14
  ({ onPress, children, variant, tokens, accessibilityRole = 'button', ...linkProps }, ref) => {
14
15
  const getTokens = useThemeTokensCallback('Link', tokens, variant)
15
16
  return (
16
- <LinkBase
17
- onPress={onPress}
18
- accessibilityRole={accessibilityRole}
19
- tokens={getTokens}
20
- ref={ref}
21
- {...linkProps}
22
- >
23
- {children}
24
- </LinkBase>
17
+ <View style={styles.textButton}>
18
+ <LinkBase
19
+ onPress={onPress}
20
+ accessibilityRole={accessibilityRole}
21
+ tokens={getTokens}
22
+ ref={ref}
23
+ {...linkProps}
24
+ >
25
+ {children}
26
+ </LinkBase>
27
+ </View>
25
28
  )
26
29
  }
27
30
  )
31
+ const styles = StyleSheet.create({
32
+ textButton: {
33
+ flex: 1
34
+ }
35
+ })
28
36
  TextButton.displayName = 'TextButton'
29
37
 
30
38
  TextButton.propTypes = {
package/src/List/List.jsx CHANGED
@@ -41,20 +41,25 @@ const List = React.forwardRef(
41
41
  return child
42
42
  })
43
43
 
44
- return (
44
+ const content = (
45
45
  <View
46
- ref={ref}
47
46
  style={styles.list}
48
47
  accessibilityRole={accessibilityRole}
48
+ ref={ref}
49
49
  {...selectProps(rest)}
50
50
  >
51
51
  {items}
52
52
  </View>
53
53
  )
54
+
55
+ return Platform.OS === 'web' ? <div style={styles.container}>{content}</div> : content
54
56
  }
55
57
  )
56
58
 
57
59
  const styles = StyleSheet.create({
60
+ container: {
61
+ display: 'block'
62
+ },
58
63
  list: {
59
64
  flex: 1,
60
65
  flexShrink: 1
@@ -14,11 +14,11 @@ export const tokenTypes = {
14
14
  }
15
15
 
16
16
  const selectItemTextStyles = (
17
- { itemFontWeight, itemFontSize, itemLineHeight, itemFontName, itemFontColor },
17
+ { itemFontWeight, itemFontSize, itemLineHeight, itemFontName, itemFontColor, itemTextColor },
18
18
  themeOptions
19
19
  ) =>
20
20
  applyTextStyles({
21
- fontColor: itemFontColor,
21
+ fontColor: itemFontColor || itemTextColor,
22
22
  fontWeight: itemFontWeight,
23
23
  fontSize: itemFontSize,
24
24
  lineHeight: itemLineHeight,
@@ -133,11 +133,9 @@ const ModalContent = React.forwardRef(
133
133
  </Button>
134
134
  )}
135
135
  {hasCancelButton ? (
136
- <View>
137
- <CancelButton tokens={{ color: cancelButtonColor }} onPress={onCancel}>
138
- {cancelButtonText}
139
- </CancelButton>
140
- </View>
136
+ <CancelButton tokens={{ color: cancelButtonColor }} onPress={onCancel}>
137
+ {cancelButtonText}
138
+ </CancelButton>
141
139
  ) : null}
142
140
  </View>
143
141
  )}
@@ -62,7 +62,8 @@ const staticStyles = StyleSheet.create({
62
62
  flexShrink: 1,
63
63
  flexBasis: 0,
64
64
  zIndex: 1000,
65
- display: 'flex'
65
+ display: 'flex',
66
+ overflowY: 'auto'
66
67
  }
67
68
  })
68
69
 
@@ -61,14 +61,24 @@ const selectDismissIconProps = ({ dismissIconSize, dismissIconColor }) => ({
61
61
 
62
62
  const selectDismissButtonContainerStyles = ({ dismissButtonGap }) => ({
63
63
  paddingLeft: dismissButtonGap,
64
- placeContent: 'center'
64
+ placeContent: 'start'
65
65
  })
66
66
 
67
- const selectContentContainerStyle = (maxWidth) => ({
68
- maxWidth: maxWidth || '100%'
67
+ const selectContentContainerStyle = (themeTokens, maxWidth, viewport, system) => ({
68
+ maxWidth: viewport === 'xl' && system === true ? maxWidth : 'auto',
69
+ minWidth: viewport === 'xl' && system === true ? maxWidth : 'auto',
70
+ paddingRight: themeTokens?.containerPaddingRight,
71
+ paddingLeft: themeTokens?.containerPaddingLeft
69
72
  })
70
73
 
71
- const getMediaQueryStyles = (themeTokens, themeOptions, viewport, mediaIdsRef, dismissible) => {
74
+ const getMediaQueryStyles = (
75
+ themeTokens,
76
+ themeOptions,
77
+ mediaIdsRef,
78
+ dismissible,
79
+ viewport,
80
+ system
81
+ ) => {
72
82
  const transformedSelectContainerStyles = Object.entries(themeTokens).reduce(
73
83
  (acc, [vp, viewportTokens]) => {
74
84
  acc[vp] = selectContainerStyles({ ...viewportTokens })
@@ -80,7 +90,10 @@ const getMediaQueryStyles = (themeTokens, themeOptions, viewport, mediaIdsRef, d
80
90
  const selectContainerMediaQueryStyles = createMediaQueryStyles(transformedSelectContainerStyles)
81
91
 
82
92
  const { ids: containerIds, styles: containerStyles } = StyleSheet.create({
83
- container: { flexDirection: 'row', ...selectContainerMediaQueryStyles }
93
+ container: {
94
+ flexDirection: system === true && viewport === 'xl' ? 'row' : 'inherit',
95
+ ...selectContainerMediaQueryStyles
96
+ }
84
97
  })
85
98
 
86
99
  const { ids: contentContainerIds, styles: contentContainerStyles } = StyleSheet.create({
@@ -89,11 +102,11 @@ const getMediaQueryStyles = (themeTokens, themeOptions, viewport, mediaIdsRef, d
89
102
  flexShrink: 1,
90
103
  justifyContent: 'space-between',
91
104
  ...createMediaQueryStyles({
92
- xs: { width: themeOptions?.contentMaxWidth.xs || '100%' },
93
- md: { width: themeOptions?.contentMaxWidth.md || '100%' },
94
- lg: { width: themeOptions?.contentMaxWidth.lg || '100%' },
95
- sm: { width: themeOptions?.contentMaxWidth.sm || '100%' },
96
- xl: { width: themeOptions?.contentMaxWidth.xl || '100%' }
105
+ xs: { width: themeOptions?.contentMaxWidth?.xs || '100%' },
106
+ md: { width: themeOptions?.contentMaxWidth?.md || '100%' },
107
+ lg: { width: themeOptions?.contentMaxWidth?.lg || '100%' },
108
+ sm: { width: themeOptions?.contentMaxWidth?.sm || '100%' },
109
+ xl: { width: themeOptions?.contentMaxWidth?.xl || '100%' }
97
110
  })
98
111
  }
99
112
  })
@@ -146,16 +159,20 @@ const getMediaQueryStyles = (themeTokens, themeOptions, viewport, mediaIdsRef, d
146
159
  }
147
160
  }
148
161
 
149
- const getDefaultStyles = (themeTokens, themeOptions, maxWidth, dismissible) => ({
162
+ const getDefaultStyles = (themeTokens, themeOptions, maxWidth, dismissible, viewport, system) => ({
150
163
  containerStyles: {
151
- container: { flexDirection: 'row', ...selectContainerStyles(themeTokens) }
164
+ container: {
165
+ flexDirection: system === true && viewport === 'xl' ? 'row' : 'inherit',
166
+ ...selectContainerStyles(themeTokens)
167
+ }
152
168
  },
153
169
  contentContainerStyles: {
154
170
  contentContainer: {
171
+ flex: 1,
155
172
  flexDirection: 'row',
156
173
  flexShrink: 1,
157
174
  justifyContent: 'space-between',
158
- ...selectContentContainerStyle(maxWidth)
175
+ ...selectContentContainerStyle(themeTokens, maxWidth, viewport, system)
159
176
  }
160
177
  },
161
178
  staticContentContainerStyles: {
@@ -260,16 +277,19 @@ const Notification = React.forwardRef(
260
277
  notificationComponentRef.current = getMediaQueryStyles(
261
278
  themeTokens,
262
279
  themeOptions,
263
- viewport,
264
280
  mediaIdsRef,
265
- dismissible
281
+ dismissible,
282
+ viewport,
283
+ system
266
284
  )
267
285
  } else {
268
286
  notificationComponentRef.current = getDefaultStyles(
269
287
  themeTokens,
270
288
  themeOptions,
271
289
  maxWidth,
272
- dismissible
290
+ dismissible,
291
+ viewport,
292
+ system
273
293
  )
274
294
  }
275
295
 
@@ -173,6 +173,7 @@ const Radio = React.forwardRef(
173
173
  onKeyDown={handleKeyDown}
174
174
  onPress={handleChange}
175
175
  {...selectedProps}
176
+ style={staticStyles.removeOutline}
176
177
  >
177
178
  {({ focused: focus, hovered: hover, pressed }) => {
178
179
  const stateTokens = getTokens({ focus, hover, pressed })
@@ -278,5 +279,6 @@ export default Radio
278
279
 
279
280
  const staticStyles = StyleSheet.create({
280
281
  container: { flexDirection: 'row', alignItems: 'center' },
281
- alignWithLabel: { alignSelf: 'flex-start', justifyContent: 'center' }
282
+ alignWithLabel: { alignSelf: 'flex-start', justifyContent: 'center' },
283
+ removeOutline: { outlineStyle: 'none' }
282
284
  })
@@ -1,7 +1,9 @@
1
1
  import React from 'react'
2
2
 
3
3
  import PropTypes from 'prop-types'
4
- import { componentPropType } from '../utils'
4
+ import { componentPropType, selectSystemProps, htmlAttrs } from '../utils'
5
+
6
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs])
5
7
 
6
8
  const Picker = React.forwardRef(
7
9
  (
@@ -22,6 +24,7 @@ const Picker = React.forwardRef(
22
24
  },
23
25
  ref
24
26
  ) => {
27
+ const selectedProps = selectProps(rest)
25
28
  const { accessibilityLabel, accessibilityDescribedBy, accessibilityInvalid } = rest
26
29
 
27
30
  return (
@@ -40,6 +43,7 @@ const Picker = React.forwardRef(
40
43
  aria-describedby={accessibilityDescribedBy}
41
44
  aria-invalid={accessibilityInvalid}
42
45
  data-testid={testID}
46
+ {...selectedProps}
43
47
  >
44
48
  {placeholder !== undefined && (
45
49
  <option value={placeholder.value} disabled hidden>
@@ -56,6 +60,7 @@ Picker.displayName = 'Picker'
56
60
  export default Picker
57
61
 
58
62
  Picker.propTypes = {
63
+ ...selectedSystemPropTypes,
59
64
  value: PropTypes.string,
60
65
  onChange: PropTypes.func,
61
66
  onFocus: PropTypes.func,
@@ -11,7 +11,8 @@ import {
11
11
  selectSystemProps,
12
12
  useInputValue,
13
13
  variantProp,
14
- viewProps
14
+ viewProps,
15
+ htmlAttrs
15
16
  } from '../utils'
16
17
  import Picker from './Picker'
17
18
  import InputSupports from '../InputSupports'
@@ -21,7 +22,8 @@ import { ANDROID_VALIDATION_ICON_CONTAINER_OFFSET } from './constants'
21
22
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([
22
23
  a11yProps,
23
24
  inputSupportsProps,
24
- viewProps
25
+ viewProps,
26
+ htmlAttrs
25
27
  ])
26
28
 
27
29
  const selectInputStyles = (
package/src/Tabs/Tabs.jsx CHANGED
@@ -124,6 +124,7 @@ const Tabs = React.forwardRef(
124
124
  ref: itemRef,
125
125
  LinkRouter: ItemLinkRouter = LinkRouter,
126
126
  linkRouterProps: itemLinkRouterProps,
127
+ render,
127
128
  ...itemRest
128
129
  },
129
130
  index
@@ -151,6 +152,7 @@ const Tabs = React.forwardRef(
151
152
  accessibilityRole={accessibilityRole}
152
153
  LinkRouter={ItemLinkRouter}
153
154
  linkRouterProps={{ ...linkRouterProps, ...itemLinkRouterProps }}
155
+ render={render}
154
156
  {...itemProps}
155
157
  >
156
158
  {label}
@@ -178,7 +180,8 @@ Tabs.propTypes = {
178
180
  href: PropTypes.string,
179
181
  label: PropTypes.string,
180
182
  id: PropTypes.string,
181
- ref: ABBPropTypes.ref()
183
+ ref: ABBPropTypes.ref(),
184
+ render: PropTypes.func
182
185
  })
183
186
  ),
184
187
  /**
@@ -92,6 +92,7 @@ const TabsItem = React.forwardRef(
92
92
  : undefined,
93
93
  accessibilityState = accessibilityRole === 'tab' ? { selected } : undefined,
94
94
  id,
95
+ render,
95
96
  ...rawRest
96
97
  },
97
98
  ref
@@ -144,6 +145,8 @@ const TabsItem = React.forwardRef(
144
145
  // itemPositions is a ref object so this should only re-run when `selected` (or `index`) change
145
146
  }, [selected, index, itemPositions])
146
147
 
148
+ if (render) return render({ selected, handlePress })
149
+
147
150
  return (
148
151
  <Pressable
149
152
  ref={ref}
@@ -202,7 +205,8 @@ TabsItem.propTypes = {
202
205
  selected: PropTypes.bool,
203
206
  itemPositions: itemPositionsPropType,
204
207
  children: PropTypes.string,
205
- id: PropTypes.string
208
+ id: PropTypes.string,
209
+ render: PropTypes.func
206
210
  }
207
211
 
208
212
  const staticStyles = StyleSheet.create({
package/src/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { default as A11yText } from './A11yText'
2
+ export { default as ActionCard } from './ActionCard'
2
3
  export { default as ActivityIndicator } from './ActivityIndicator'
3
4
  export { default as Autocomplete } from './Autocomplete'
4
5
  export { default as Box } from './Box'
@@ -53,8 +53,8 @@ function useVerticalExpandAnimation({ containerHeight, isExpanded, tokens }) {
53
53
 
54
54
  if (!isExpanded && !isAnimating && !expandStateChanged) {
55
55
  if (Platform.OS === 'web') {
56
- // Without `visibility: 'hidden', descendents are focusable on web even when collapsed.
57
- containerStyles.visibility = 'hidden'
56
+ // Without `display: 'none', descendents are focusable on web even when collapsed.
57
+ containerStyles.display = 'none'
58
58
  } else {
59
59
  // There's no `visibility: hidden` in React Native, and display: none causes a flicker on expand.
60
60
  // Without some form of hiding, some children leak through even when closed e.g. `List.Item` bullets.
@@ -68,7 +68,7 @@ function useVerticalExpandAnimation({ containerHeight, isExpanded, tokens }) {
68
68
  // on web we can hide the contents until we have the container measured and avoid occasional jitter
69
69
  // this won't work on native platforms
70
70
  containerStyles.height = 0
71
- containerStyles.visibility = 'hidden'
71
+ containerStyles.display = 'none'
72
72
  }
73
73
  } else if (Platform.OS === 'web') {
74
74
  const transitionDuration = isExpanded ? expandDuration : collapseDuration
@@ -122,7 +122,7 @@ export const getTokensPropType =
122
122
  * For example, for a set of tokens used in a common style, or for a set of tokens required by
123
123
  * a themeless component whose tokens are set by a parent but requires tokens of a certain shape.
124
124
  *
125
- * By default, requires an object with a complete set of tokens (allowing `null`, but not `undefined`).
125
+ * By default, requires an object with a complete set of tokens (allowing `null` and `undefined`).
126
126
  *
127
127
  * @param {string[]} componentTokenKeys - array of strings of token names
128
128
  * @param {object} [options]
@@ -142,7 +142,9 @@ export const getTokensSetPropType = (
142
142
  ? tokenValueType
143
143
  : // Some theme tokens can validly resolve to `null`, but .isRequired treats null as undefined
144
144
  (props, propName, ...args) =>
145
- props[propName] !== null && tokenValueType.isRequired(props, propName, ...args)
145
+ props[propName] !== null &&
146
+ props[propName] !== undefined &&
147
+ tokenValueType.isRequired(props, propName, ...args)
146
148
  ])
147
149
  )
148
150
  )