@telus-uds/components-base 1.52.0 → 1.54.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.
@@ -1,5 +1,5 @@
1
1
  import React, { forwardRef, useState } from 'react'
2
- import { Animated, Platform, View } from 'react-native'
2
+ import { Animated, Platform, View, Text } from 'react-native'
3
3
  import PropTypes from 'prop-types'
4
4
  import ABBPropTypes from 'airbnb-prop-types'
5
5
 
@@ -26,7 +26,42 @@ const selectContainerStyles = ({
26
26
  paddingLeft: contentPaddingLeft,
27
27
  paddingRight: contentPaddingRight,
28
28
  paddingTop: contentPaddingTop,
29
- paddingBottom: contentPaddingBottom
29
+ paddingBottom: contentPaddingBottom,
30
+ flex: 1
31
+ })
32
+ const selectTextStyles = ({
33
+ contentPanelFontSize,
34
+ contentPanelFontName,
35
+ contentPanelFontColor,
36
+ contentPanelFontWeight,
37
+ contentPanelLineHeight
38
+ }) => ({
39
+ fontSize: contentPanelFontSize,
40
+ fontFamily: `${contentPanelFontName}${contentPanelFontWeight}normal`,
41
+ lineHeight: contentPanelFontSize * contentPanelLineHeight,
42
+ color: contentPanelFontColor
43
+ })
44
+ const selectContentPanelStyles = ({
45
+ contentPanelBackgroundColor,
46
+ contentPanelPaddingTop,
47
+ contentPanelPaddingBottom,
48
+ contentPanelPaddingLeft,
49
+ contentPanelPaddingRight,
50
+ contentPanelBorderWidth,
51
+ contentPanelBorderColor,
52
+ borderRadius,
53
+ marginBottom
54
+ }) => ({
55
+ backgroundColor: contentPanelBackgroundColor,
56
+ paddingTop: contentPanelPaddingTop,
57
+ paddingBottom: contentPanelPaddingBottom,
58
+ paddingLeft: contentPanelPaddingLeft,
59
+ paddingRight: contentPanelPaddingRight,
60
+ borderWidth: contentPanelBorderWidth,
61
+ borderColor: contentPanelBorderColor,
62
+ borderStyle: 'solid',
63
+ borderRadius,
64
+ marginBottom
30
65
  })
31
66
 
32
67
  /**
@@ -52,6 +87,7 @@ const ExpandCollapsePanel = forwardRef(
52
87
  tokens,
53
88
  variant,
54
89
  controlRef,
90
+ content,
55
91
  ...rest
56
92
  },
57
93
  ref
@@ -90,8 +126,15 @@ const ExpandCollapsePanel = forwardRef(
90
126
  })
91
127
 
92
128
  const focusabilityProps = isExpanded ? {} : a11yProps.nonFocusableProps
93
-
94
- return (
129
+ return content ? (
130
+ <View style={selectContentPanelStyles(themeTokens)}>
131
+ {typeof children === 'string' ? (
132
+ <Text style={selectTextStyles(themeTokens)}>{children}</Text>
133
+ ) : (
134
+ children
135
+ )}
136
+ </View>
137
+ ) : (
95
138
  <View ref={ref} style={themeTokens}>
96
139
  <ExpandCollapseControl
97
140
  {...selectedProps}
@@ -140,7 +183,7 @@ ExpandCollapsePanel.propTypes = {
140
183
  * Function to call on pressing the panel's control, which should open or close the panel.
141
184
  * If Panel is a direct child of `ExpandCollapse`, this prop will be provided by the ExpandCollapse parent.
142
185
  */
143
- onToggle: PropTypes.func.isRequired,
186
+ onToggle: PropTypes.func,
144
187
  /**
145
188
  * Optional function to call on pressing the panel's control, in addition to opening or closing the panel.
146
189
  */
@@ -151,9 +194,9 @@ ExpandCollapsePanel.propTypes = {
151
194
  */
152
195
  children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
153
196
  /**
154
- * The content inside the always-visible control element that opens and closes the ExpandCollapse when pressed.
197
+ * The content inside the control element that opens and closes the ExpandCollapse when pressed.
155
198
  */
156
- control: ExpandCollapseControl.propTypes.children.isRequired,
199
+ control: ExpandCollapseControl.propTypes.children,
157
200
  /**
158
201
  * Optional theme token overrides that may be passed to the ExpandCollapseControl element.
159
202
  */
@@ -161,7 +204,11 @@ ExpandCollapsePanel.propTypes = {
161
204
  /**
162
205
  * An optional ref to be attached to the control
163
206
  */
164
- controlRef: ABBPropTypes.ref()
207
+ controlRef: ABBPropTypes.ref(),
208
+ /**
209
+ * A boolean prop to determine if the panel is a content panel or not. If true, the panel will not have a control
210
+ */
211
+ content: PropTypes.bool
165
212
  }
166
213
 
167
214
  export default ExpandCollapsePanel
@@ -3,6 +3,7 @@ import {
3
3
  StyleSheet,
4
4
  TouchableWithoutFeedback,
5
5
  View,
6
+ ScrollView,
6
7
  Modal as NativeModal,
7
8
  Platform
8
9
  } from 'react-native'
@@ -114,7 +115,7 @@ const Modal = forwardRef(
114
115
 
115
116
  return (
116
117
  <NativeModal transparent {...selectProps(rest)}>
117
- <View style={[staticStyles.positioningContainer]} ref={modalRef}>
118
+ <ScrollView contentContainerStyle={[staticStyles.positioningContainer]} ref={modalRef}>
118
119
  <View
119
120
  style={[staticStyles.sizingContainer, selectContainerStyles(themeTokens)]}
120
121
  pointerEvents="box-none" // don't capture backdrop press events
@@ -149,7 +150,7 @@ const Modal = forwardRef(
149
150
  <TouchableWithoutFeedback onPress={handleClose}>
150
151
  <View style={[staticStyles.backdrop, selectBackdropStyles(themeTokens)]} />
151
152
  </TouchableWithoutFeedback>
152
- </View>
153
+ </ScrollView>
153
154
  </NativeModal>
154
155
  )
155
156
  }
@@ -210,7 +211,11 @@ const staticStyles = StyleSheet.create({
210
211
  },
211
212
  modal: {
212
213
  maxHeight: '100%', // so that the modal can expand vertically up to the sizing container's height (exclusive of its vertical padding)
213
- overflow: 'auto'
214
+ ...Platform.select({
215
+ web: {
216
+ overflow: 'auto'
217
+ }
218
+ })
214
219
  },
215
220
  closeButtonContainer: {
216
221
  position: 'absolute',
@@ -37,8 +37,12 @@ const selectStyles = ({
37
37
  borderRadius
38
38
  })
39
39
 
40
- const selectTextStyles = ({ color }) => ({
41
- color
40
+ const selectTextStyles = ({ color, textLine, fontName, fontSize, fontWeight, lineHeight }) => ({
41
+ color,
42
+ textDecorationLine: textLine,
43
+ fontFamily: `${fontName}${fontWeight}normal`,
44
+ lineHeight: fontSize * lineHeight,
45
+ fontSize
42
46
  })
43
47
 
44
48
  /**
@@ -100,9 +104,6 @@ const SkipLink = forwardRef(({ tokens, variant, href, children, ...rawRest }, re
100
104
  const { onPress, ...rest } = clickProps.toPressProps(rawRest)
101
105
 
102
106
  const getTokens = useThemeTokensCallback('SkipLink', tokens, variant)
103
- const defaultTokens = getTokens()
104
-
105
- const resolveLinkTokens = (pressState) => resolvePressableTokens(defaultTokens, pressState)
106
107
 
107
108
  const handlePress = (event) => {
108
109
  if (typeof onPress === 'function') onPress(event)
@@ -115,18 +116,17 @@ const SkipLink = forwardRef(({ tokens, variant, href, children, ...rawRest }, re
115
116
  accessibilityRole="link"
116
117
  onPress={handlePress}
117
118
  href={href}
118
- style={({ focused: focus }) => {
119
- const themeTokens = getTokens({ focus })
119
+ style={(pressableState) => {
120
+ const themeTokens = resolvePressableTokens(getTokens, pressableState)
120
121
  const skipLinkStyle = selectStyles(themeTokens)
121
-
122
- return [staticStyles.absolute, skipLinkStyle, !focus && staticStyles.hidden]
122
+ const { focused } = pressableState
123
+ return [staticStyles.absolute, skipLinkStyle, !focused && staticStyles.hidden]
123
124
  }}
124
125
  {...selectProps(rest)}
125
126
  >
126
- {(pressState) => {
127
- const themeTokens = resolveLinkTokens(pressState)
127
+ {(pressableState) => {
128
+ const themeTokens = resolvePressableTokens(getTokens, pressableState)
128
129
  const textStyles = selectTextStyles(themeTokens)
129
-
130
130
  return <Text style={[textStyles, staticStyles.baseline]}>{children}</Text>
131
131
  }}
132
132
  </Pressable>
@@ -28,10 +28,12 @@ const [selectProps, selectedSystemPropTypes] = selectSystemProps([
28
28
 
29
29
  // We need to drop the icon before passing it to the `ButtonBase`, because it's
30
30
  // being handled separately in this case
31
- const selectButtonTokens = ({ icon: _, ...tokens }) =>
31
+ const selectButtonTokens = ({ icon: _, ...tokens }, { trackHeight, outerBorderGapButton }) =>
32
32
  selectTokens('Button', {
33
33
  ...tokens,
34
34
  // Width tokens are applied to our inner track. Disable Button width token so it wraps our track width.
35
+ outerBorderGap: outerBorderGapButton,
36
+ height: trackHeight,
35
37
  width: null
36
38
  })
37
39
 
@@ -41,6 +43,11 @@ const selectIconTokens = ({ iconSize, iconColor }) => ({
41
43
  color: iconColor
42
44
  })
43
45
 
46
+ const selectTrackSwitchStyles = ({ switchSize, width, trackHeight }) => ({
47
+ width,
48
+ height: Math.max(switchSize, trackHeight)
49
+ })
50
+
44
51
  const selectTrackStyles = ({ trackBorderWidth, trackBorderColor, trackBorderRadius, width }) => ({
45
52
  borderWidth: trackBorderWidth,
46
53
  borderColor: trackBorderColor,
@@ -56,6 +63,7 @@ const selectSwitchStyles = ({
56
63
  switchBorderRadius,
57
64
  switchShadow
58
65
  }) => ({
66
+ position: 'absolute',
59
67
  width: switchSize,
60
68
  height: switchSize,
61
69
  backgroundColor: switchColor,
@@ -113,12 +121,12 @@ const ToggleSwitch = forwardRef(
113
121
  })
114
122
 
115
123
  const handlePress = (event) => setValue(!currentValue, event)
116
- const getButtonTokens = (buttonState) => selectButtonTokens(getTokens(buttonState))
124
+ const getButtonTokens = (buttonState) =>
125
+ selectButtonTokens(getTokens(buttonState), getTokens(themeTokens))
117
126
  const uniqueId = useUniqueId('toggleSwitch')
118
127
  const inputId = id ?? uniqueId
119
-
120
128
  return (
121
- <StackView space={2} direction="row">
129
+ <StackView space={themeTokens.space} direction="row" tokens={{ alignItems: 'center' }}>
122
130
  {Boolean(label) && (
123
131
  <View style={[selectLabelStyles(themeTokens), staticStyles.containText]}>
124
132
  <InputLabel
@@ -148,17 +156,22 @@ const ToggleSwitch = forwardRef(
148
156
  const switchStyles = selectSwitchStyles(stateTokens)
149
157
  const trackStyles = selectTrackStyles(stateTokens)
150
158
  const iconTokens = selectIconTokens(stateTokens)
151
-
159
+ const trackSwitchStyles = selectTrackSwitchStyles(stateTokens)
160
+ const { switchSize, trackHeight, width, trackBorderWidth } = stateTokens
152
161
  // If drag-slide support is needed, use a PanResponder and apply these to an Animated value.
153
162
  // Use translate transforms for smoothest non-thread-blocking animations and to allow drag.
154
- const slideStart = 0
155
- const slideEnd =
156
- stateTokens.width - stateTokens.switchSize - stateTokens.trackBorderWidth * 2
163
+ // Two different translates depending on the switchSize and trackSize relationship.
164
+ const isSwitchTallerThanTrack = switchSize >= trackHeight
165
+ const slideStart = isSwitchTallerThanTrack ? 0 : trackBorderWidth
166
+ const slideEnd = isSwitchTallerThanTrack
167
+ ? width - switchSize
168
+ : width - switchSize - trackBorderWidth
157
169
  const switchOffset = buttonState.selected ? slideEnd : slideStart
158
170
  const switchPositionStyle = { transform: [{ translateX: switchOffset }] }
159
171
 
160
172
  return (
161
- <View style={[staticStyles.track, trackStyles]}>
173
+ <View nativeID="trackSwitch" style={[trackSwitchStyles, staticStyles.trackSwitch]}>
174
+ <View style={[staticStyles.track, trackStyles]} />
162
175
  <View style={[staticStyles.switch, switchStyles, switchPositionStyle]}>
163
176
  {IconComponent && <IconComponent {...iconTokens} />}
164
177
  </View>
@@ -225,6 +238,10 @@ const staticStyles = StyleSheet.create({
225
238
  },
226
239
  containText: {
227
240
  flexShrink: 1
241
+ },
242
+ trackSwitch: {
243
+ flexDirection: 'row',
244
+ alignItems: 'center'
228
245
  }
229
246
  })
230
247
 
@@ -26,7 +26,15 @@ const TooltipButton = ({ pressableState, tokens, variant, ...rest }) => {
26
26
  const { icon: IconComponent } = themeTokens
27
27
 
28
28
  return (
29
- <View style={applyOuterBorder(themeTokens)} {...selectProps(rest)}>
29
+ <View
30
+ style={[
31
+ applyOuterBorder(themeTokens),
32
+ themeTokens.outerBorderWidth && {
33
+ margin: -themeTokens.outerBorderWidth
34
+ }
35
+ ]}
36
+ {...selectProps(rest)}
37
+ >
30
38
  <View style={selectInnerContainerStyles(themeTokens)}>
31
39
  {IconComponent && <Icon icon={IconComponent} tokens={selectIconTokens(themeTokens)} />}
32
40
  </View>
@@ -59,7 +59,9 @@ const Typography = forwardRef(
59
59
  ref
60
60
  ) => {
61
61
  const viewport = useViewport()
62
- const themeTokens = useThemeTokens('Typography', tokens, variant, { viewport })
62
+ const { superScriptFontSize, ...themeTokens } = useThemeTokens('Typography', tokens, variant, {
63
+ viewport
64
+ })
63
65
  const { themeOptions } = useTheme()
64
66
 
65
67
  const resolvedTextProps = {
@@ -80,9 +82,12 @@ const Typography = forwardRef(
80
82
 
81
83
  const resetTagStyling = (child) => {
82
84
  if (typeof child === 'object' && (child?.type === 'sub' || child?.type === 'sup')) {
85
+ const childStyles = child?.props?.style || {}
86
+ const supFontSize = childStyles.fontSize ?? superScriptFontSize
83
87
  const sanitizedChild = React.cloneElement(child, {
84
88
  style: {
85
- ...child?.props?.style,
89
+ ...childStyles,
90
+ ...(supFontSize ? { fontSize: supFontSize } : {}),
86
91
  lineHeight: 0
87
92
  }
88
93
  })