@telus-uds/components-base 1.94.0 → 1.96.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 (68) hide show
  1. package/CHANGELOG.md +41 -2
  2. package/lib/Autocomplete/Autocomplete.js +38 -3
  3. package/lib/Card/CardBase.js +4 -0
  4. package/lib/DownloadApp/DownloadApp.js +168 -0
  5. package/lib/DownloadApp/dictionary.js +17 -0
  6. package/lib/DownloadApp/index.js +10 -0
  7. package/lib/Icon/IconText.js +19 -2
  8. package/lib/Link/LinkBase.js +2 -2
  9. package/lib/List/ListItemBase.js +2 -1
  10. package/lib/Modal/Modal.js +34 -13
  11. package/lib/Modal/ModalContent.js +1 -1
  12. package/lib/Modal/WebModal.js +1 -0
  13. package/lib/Notification/Notification.js +5 -5
  14. package/lib/PriceLockup/PriceLockup.js +11 -3
  15. package/lib/Progress/Progress.js +5 -2
  16. package/lib/Progress/ProgressBar.js +4 -1
  17. package/lib/TabBar/TabBar.js +133 -0
  18. package/lib/TabBar/TabBarItem.js +184 -0
  19. package/lib/TabBar/index.js +10 -0
  20. package/lib/TextInput/TextInputBase.js +2 -1
  21. package/lib/Tooltip/getTooltipPosition.js +8 -9
  22. package/lib/Typography/Typography.js +42 -19
  23. package/lib/index.js +23 -0
  24. package/lib-module/Autocomplete/Autocomplete.js +38 -3
  25. package/lib-module/Card/CardBase.js +4 -0
  26. package/lib-module/DownloadApp/DownloadApp.js +160 -0
  27. package/lib-module/DownloadApp/dictionary.js +10 -0
  28. package/lib-module/DownloadApp/index.js +2 -0
  29. package/lib-module/Icon/IconText.js +19 -2
  30. package/lib-module/Link/LinkBase.js +2 -2
  31. package/lib-module/List/ListItemBase.js +2 -1
  32. package/lib-module/Modal/Modal.js +34 -13
  33. package/lib-module/Modal/ModalContent.js +1 -1
  34. package/lib-module/Modal/WebModal.js +1 -0
  35. package/lib-module/Notification/Notification.js +5 -5
  36. package/lib-module/PriceLockup/PriceLockup.js +11 -3
  37. package/lib-module/Progress/Progress.js +6 -3
  38. package/lib-module/Progress/ProgressBar.js +5 -2
  39. package/lib-module/TabBar/TabBar.js +125 -0
  40. package/lib-module/TabBar/TabBarItem.js +177 -0
  41. package/lib-module/TabBar/index.js +2 -0
  42. package/lib-module/TextInput/TextInputBase.js +2 -1
  43. package/lib-module/Tooltip/getTooltipPosition.js +8 -9
  44. package/lib-module/Typography/Typography.js +42 -19
  45. package/lib-module/index.js +3 -1
  46. package/package.json +2 -2
  47. package/src/Autocomplete/Autocomplete.jsx +43 -3
  48. package/src/Card/CardBase.jsx +6 -0
  49. package/src/DownloadApp/DownloadApp.jsx +165 -0
  50. package/src/DownloadApp/dictionary.js +10 -0
  51. package/src/DownloadApp/index.js +3 -0
  52. package/src/Icon/IconText.jsx +21 -4
  53. package/src/Link/LinkBase.jsx +2 -2
  54. package/src/List/ListItemBase.jsx +1 -1
  55. package/src/Modal/Modal.jsx +40 -14
  56. package/src/Modal/ModalContent.jsx +1 -1
  57. package/src/Modal/WebModal.jsx +1 -1
  58. package/src/Notification/Notification.jsx +5 -5
  59. package/src/PriceLockup/PriceLockup.jsx +9 -1
  60. package/src/Progress/Progress.jsx +6 -3
  61. package/src/Progress/ProgressBar.jsx +4 -2
  62. package/src/TabBar/TabBar.jsx +123 -0
  63. package/src/TabBar/TabBarItem.jsx +149 -0
  64. package/src/TabBar/index.js +3 -0
  65. package/src/TextInput/TextInputBase.jsx +1 -1
  66. package/src/Tooltip/getTooltipPosition.js +11 -12
  67. package/src/Typography/Typography.jsx +37 -13
  68. package/src/index.js +4 -1
@@ -1,7 +1,6 @@
1
1
  import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
- import { Platform, View } from 'react-native'
4
-
3
+ import { Platform, View, Text, StyleSheet } from 'react-native'
5
4
  import Icon, { iconComponentPropTypes } from './Icon'
6
5
  import { getStackedContent } from '../StackView'
7
6
  import { spacingProps } from '../utils'
@@ -46,6 +45,18 @@ const IconText = React.forwardRef(
46
45
  const mobile = Platform.OS === 'android' ? iconAdjustedAndroid : iconAdjustedIOS
47
46
  const adjustedContainer = Platform.OS === 'web' ? iconContent : mobile
48
47
 
48
+ const adjustedContainerWithPosition = (
49
+ <View style={staticStyles.adjustedContainer}>{adjustedContainer}</View>
50
+ )
51
+
52
+ if (iconPosition === 'inline') {
53
+ return (
54
+ <Text>
55
+ {children} {adjustedContainerWithPosition}
56
+ </Text>
57
+ )
58
+ }
59
+
49
60
  return getStackedContent(
50
61
  iconPosition === 'left' ? [adjustedContainer, children] : [children, adjustedContainer],
51
62
  { space, direction: 'row' }
@@ -62,9 +73,9 @@ IconText.propTypes = {
62
73
  */
63
74
  space: spacingProps.types.spacingValue,
64
75
  /**
65
- * Whether the icon should be to the left of the content or the right of the content.
76
+ * Whether the icon should be to the left of the content, the right of the content or inline with the content.
66
77
  */
67
- iconPosition: PropTypes.oneOf(['left', 'right']),
78
+ iconPosition: PropTypes.oneOf(['left', 'right', 'inline']),
68
79
  /**
69
80
  * A valid UDS icon component imported from a UDS palette.
70
81
  */
@@ -83,4 +94,10 @@ IconText.propTypes = {
83
94
  /* eslint-enable react/no-unused-prop-types */
84
95
  }
85
96
 
97
+ const staticStyles = StyleSheet.create({
98
+ adjustedContainer: {
99
+ position: 'absolute'
100
+ }
101
+ })
102
+
86
103
  export default IconText
@@ -240,9 +240,9 @@ LinkBase.propTypes = {
240
240
  */
241
241
  icon: PropTypes.elementType,
242
242
  /**
243
- * When `icon` is provided, use `iconPosition` to place the Icon to the left or right side of Link.
243
+ * When `icon` is provided, use `iconPosition` to place the Icon to the left, right or inline with Link.
244
244
  */
245
- iconPosition: PropTypes.oneOf(['left', 'right']),
245
+ iconPosition: PropTypes.oneOf(['left', 'right', 'inline']),
246
246
  /**
247
247
  * On Web if href is passed, React Native Web maps this object's props to
248
248
  * `rel`, `target` and `download` attrs.
@@ -107,7 +107,7 @@ const staticStyles = StyleSheet.create({
107
107
  flex: 1,
108
108
  flexDirection: 'row'
109
109
  },
110
- titleAndContentContainer: { flexDirection: 'column', flexShrink: 1 }
110
+ titleAndContentContainer: { flexDirection: 'column', flexShrink: 1, flexGrow: 1 }
111
111
  })
112
112
 
113
113
  ListItemBase.propTypes = {
@@ -121,6 +121,8 @@ const Modal = React.forwardRef(
121
121
  const viewport = useViewport()
122
122
  const themeTokens = useThemeTokens('Modal', tokens, variant, { viewport, maxWidth })
123
123
  const modalRef = useScrollBlocking(isOpen)
124
+ const modalBodyRef = React.useRef(ref)
125
+ const modalContentRef = React.useRef(null)
124
126
 
125
127
  const { closeIcon: CloseIconComponent } = themeTokens
126
128
 
@@ -135,6 +137,32 @@ const Modal = React.forwardRef(
135
137
  if (event.key === 'Escape') onClose()
136
138
  }
137
139
 
140
+ const manageFocus = React.useCallback(
141
+ (event) => {
142
+ if (event.key === 'Tab') {
143
+ const focusableElements = Array.from(
144
+ modalBodyRef?.current?.querySelectorAll(`
145
+ a[href], button, textarea, input, select,
146
+ [tabindex]:not([tabindex="-1"]),
147
+ [contenteditable="true"]
148
+ `)
149
+ )
150
+
151
+ const firstElement = focusableElements[0]
152
+ const lastElement = focusableElements[focusableElements.length - 1]
153
+
154
+ if (event.shiftKey && document.activeElement === firstElement) {
155
+ event.preventDefault()
156
+ lastElement.focus()
157
+ } else if (!event.shiftKey && document.activeElement === lastElement) {
158
+ event.preventDefault()
159
+ firstElement.focus()
160
+ }
161
+ }
162
+ },
163
+ [modalBodyRef]
164
+ )
165
+
138
166
  // Show the custom react node passed to `closedButton` or the default close button if `closeButton` is `undefined`.
139
167
  // Hide the close button if `closeButton` is `null`.
140
168
  const showCloseButton = closeButton !== null
@@ -145,22 +173,20 @@ const Modal = React.forwardRef(
145
173
 
146
174
  React.useEffect(() => {
147
175
  if (Platform.OS === 'web') {
148
- const handleFocus = () => {
149
- // If the focus is on the last item of the web modal container, move it to the close button
150
- if (document.activeElement === focusTrapRef.current) {
151
- closeButtonRef.current.focus()
152
- }
153
- return undefined
154
- }
155
-
156
- // Add an event listener to manage focus in the web modal container
157
- document.addEventListener('focusin', handleFocus)
176
+ // Add an event listener to manage keydown and focus in the web modal container
177
+ document.addEventListener('keydown', manageFocus)
158
178
 
159
179
  // Clean up the event listener
160
- return () => document.removeEventListener('focusin', handleFocus)
180
+ return () => document.removeEventListener('keydown', manageFocus)
161
181
  }
162
182
  return undefined
163
- }, [])
183
+ }, [manageFocus])
184
+
185
+ React.useEffect(() => {
186
+ if (isOpen) {
187
+ modalContentRef?.current?.focus()
188
+ }
189
+ }, [isOpen, modalContentRef?.current?.focus])
164
190
 
165
191
  if (!isOpen) {
166
192
  return null
@@ -174,7 +200,7 @@ const Modal = React.forwardRef(
174
200
  pointerEvents="box-none" // don't capture backdrop press events
175
201
  >
176
202
  <View
177
- ref={ref}
203
+ ref={modalBodyRef}
178
204
  style={[staticStyles.modal, selectModalStyles(themeTokens)]}
179
205
  onKeyUp={handleKeyUp}
180
206
  >
@@ -230,7 +256,7 @@ const Modal = React.forwardRef(
230
256
 
231
257
  if (Platform.OS === 'web') {
232
258
  return (
233
- <WebModal {...selectProps(rest)}>
259
+ <WebModal {...selectProps(rest)} ref={modalContentRef}>
234
260
  {content}
235
261
  <View accessibilityRole="button" ref={focusTrapRef} />
236
262
  </WebModal>
@@ -155,7 +155,7 @@ const styles = StyleSheet.create({
155
155
  minHeight: Platform.OS === 'web' ? '100%' : 'auto'
156
156
  },
157
157
  cancelButton: {
158
- flex: 1
158
+ display: 'flex'
159
159
  }
160
160
  })
161
161
 
@@ -17,7 +17,7 @@ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, vie
17
17
  const WebModal = React.forwardRef(({ children, ...rest }, ref) => {
18
18
  return (
19
19
  <Portal>
20
- <View style={staticStyles.container} {...selectProps(rest)} ref={ref}>
20
+ <View style={staticStyles.container} {...selectProps(rest)} focusable={true} ref={ref}>
21
21
  <div style={staticStyles.content} role="dialog" aria-modal={true}>
22
22
  {children}
23
23
  </div>
@@ -102,11 +102,11 @@ const getMediaQueryStyles = (
102
102
  flexShrink: 1,
103
103
  justifyContent: 'space-between',
104
104
  ...createMediaQueryStyles({
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%' }
105
+ xs: { maxWidth: themeOptions?.contentMaxWidth?.xs || '100%' },
106
+ md: { maxWidth: themeOptions?.contentMaxWidth?.md || '100%' },
107
+ lg: { maxWidth: themeOptions?.contentMaxWidth?.lg || '100%' },
108
+ sm: { maxWidth: themeOptions?.contentMaxWidth?.sm || '100%' },
109
+ xl: { maxWidth: themeOptions?.contentMaxWidth?.xl || '100%' }
110
110
  })
111
111
  }
112
112
  })
@@ -61,6 +61,10 @@ const selectBottomTextTypographyTokens = ({ bottomTextFontSize, bottomTextLineHe
61
61
  lineHeight: bottomTextLineHeight
62
62
  })
63
63
 
64
+ const selectContainertokens = ({ alignItemsText }) => ({
65
+ alignItems: alignItemsText
66
+ })
67
+
64
68
  const PriceLockup = React.forwardRef(
65
69
  (
66
70
  {
@@ -106,7 +110,11 @@ const PriceLockup = React.forwardRef(
106
110
  const bottomTextTypographyTokens = selectBottomTextTypographyTokens(themeTokens)
107
111
 
108
112
  return (
109
- <View style={[staticStyles.priceLockupContainer]} ref={ref} {...selectProps(rest)}>
113
+ <View
114
+ style={[staticStyles.priceLockupContainer, selectContainertokens(themeTokens)]}
115
+ ref={ref}
116
+ {...selectProps(rest)}
117
+ >
110
118
  {topText ? (
111
119
  <View style={staticStyles.topText}>
112
120
  {renderTypography(topText, topTextTypographyTokens)}
@@ -2,7 +2,7 @@ import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import { View } from 'react-native'
4
4
 
5
- import { useThemeTokens } from '../ThemeProvider'
5
+ import { applyShadowToken, useThemeTokens } from '../ThemeProvider'
6
6
  import { a11yProps, getTokensPropType, selectSystemProps, variantProp, viewProps } from '../utils'
7
7
 
8
8
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
@@ -12,13 +12,15 @@ const selectProgressStyles = ({
12
12
  borderWidth,
13
13
  borderColor,
14
14
  borderRadius,
15
- height
15
+ height,
16
+ shadow
16
17
  }) => ({
17
18
  backgroundColor,
18
19
  borderWidth,
19
20
  borderColor,
20
21
  borderRadius,
21
- height
22
+ height,
23
+ ...applyShadowToken(shadow)
22
24
  })
23
25
 
24
26
  /**
@@ -37,6 +39,7 @@ const selectProgressStyles = ({
37
39
  * - `borderRadius` for the rounded corners,
38
40
  * - `borderWidth` to change the border width.
39
41
  * - `height` to control the height of the progress bars displayed within the progress bar container.
42
+ * - `shadow` to apply a box shadow to the progress bar container.
40
43
  *
41
44
  * ## Variants
42
45
  *
@@ -3,19 +3,20 @@ import PropTypes from 'prop-types'
3
3
  import { Platform, StyleSheet, View } from 'react-native'
4
4
 
5
5
  import ProgressBarBackground from './ProgressBarBackground'
6
- import { useThemeTokens } from '../ThemeProvider'
6
+ import { applyShadowToken, useThemeTokens } from '../ThemeProvider'
7
7
  import { a11yProps, getTokensPropType, selectSystemProps, variantProp, viewProps } from '../utils'
8
8
 
9
9
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
10
10
 
11
11
  const selectBarStyles = (
12
- { backgroundColor, borderRadius, outlineWidth, outlineColor },
12
+ { backgroundColor, borderRadius, outlineWidth, outlineColor, shadow },
13
13
  percentage
14
14
  ) => ({
15
15
  backgroundColor,
16
16
  borderRadius,
17
17
  outlineWidth,
18
18
  outlineColor,
19
+ ...applyShadowToken(shadow),
19
20
  width: `${percentage}%`
20
21
  })
21
22
 
@@ -34,6 +35,7 @@ const selectBarStyles = (
34
35
  * - `borderRadius` for the rounded corners,
35
36
  * - `outlineColor` to control the color of the border (outline),
36
37
  * - `outlineWidth` to change the outline width.
38
+ * - `shadow` to apply a box shadow to the progress bar.
37
39
  *
38
40
  * ## Variants
39
41
  *
@@ -0,0 +1,123 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import { View, StyleSheet } from 'react-native'
4
+ import TabBarItem from './TabBarItem'
5
+ import { useThemeTokens } from '../ThemeProvider'
6
+ import { variantProp, getTokensPropType, selectSystemProps, a11yProps, viewProps } from '../utils'
7
+
8
+ const selectTabBarContainerStyles = ({
9
+ paddingTop,
10
+ paddingBottom,
11
+ borderTopWidth,
12
+ borderTopColor,
13
+ backgroundColor
14
+ }) => ({
15
+ paddingTop,
16
+ paddingBottom,
17
+ borderTopWidth,
18
+ borderTopColor,
19
+ backgroundColor
20
+ })
21
+
22
+ const selectTabBarItemContainerStyles = ({ paddingLeft, paddingRight, gap }) => ({
23
+ paddingLeft,
24
+ paddingRight,
25
+ gap
26
+ })
27
+
28
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
29
+
30
+ /**
31
+ * TabBar component renders a navigation bar with multiple TabBarItems.
32
+ * It allows users to switch between different views or sections.
33
+ *
34
+ * @component
35
+ * @example
36
+ * const items = [
37
+ * { id: '1', label: 'Home', icon: <HomeIcon />, iconActive: <HomeActiveIcon /> },
38
+ * { id: '2', label: 'Profile', icon: <ProfileIcon />, iconActive: <ProfileActiveIcon /> },
39
+ * ]
40
+ * return (
41
+ * <TabBar
42
+ * items={items}
43
+ * initiallySelectedItem="1"
44
+ * onChange={(itemId) => console.log(itemId)}
45
+ * />
46
+ * )
47
+ */
48
+
49
+ const TabBar = React.forwardRef(
50
+ ({ items = [], initiallySelectedItem = '0', onChange, variant, tokens, ...rest }, ref) => {
51
+ const [isSelected, setIsSelected] = React.useState(initiallySelectedItem)
52
+ const themeTokens = useThemeTokens('TabBar', tokens, variant)
53
+
54
+ const handlePress = (itemId) => {
55
+ setIsSelected(itemId)
56
+ onChange?.(itemId)
57
+ }
58
+
59
+ return (
60
+ <View
61
+ ref={ref}
62
+ style={[styles.tabBar, selectTabBarContainerStyles(themeTokens)]}
63
+ {...selectProps(rest)}
64
+ >
65
+ <View style={[styles.tabBarItem, selectTabBarItemContainerStyles(themeTokens)]}>
66
+ {items.map((item, index) => (
67
+ <TabBarItem
68
+ key={item.id}
69
+ label={item.label}
70
+ href={item.href}
71
+ isSelected={isSelected === item.id}
72
+ icon={item.icon}
73
+ iconActive={item.iconActive}
74
+ onPress={() => handlePress(item.id)}
75
+ id={`tab-item-${index}`}
76
+ accessibilityRole="tablist"
77
+ />
78
+ ))}
79
+ </View>
80
+ </View>
81
+ )
82
+ }
83
+ )
84
+
85
+ TabBar.displayName = 'TabBar'
86
+
87
+ TabBar.propTypes = {
88
+ ...selectedSystemPropTypes,
89
+ /** Array of TabBarItems to be displayed in TabBar */
90
+ items: PropTypes.arrayOf(
91
+ PropTypes.shape({
92
+ id: PropTypes.string.isRequired,
93
+ icon: PropTypes.node,
94
+ iconActive: PropTypes.node,
95
+ label: PropTypes.string.isRequired,
96
+ href: PropTypes.string
97
+ })
98
+ ).isRequired,
99
+ /** Id of the initially selected item. */
100
+ initiallySelectedItem: PropTypes.number,
101
+ /** Callback function to handle item selection change. */
102
+ onChange: PropTypes.func,
103
+ /** Variant of TabBar for styling purposes. */
104
+ variant: variantProp.propType,
105
+ /** Tokens for theming and styling. */
106
+ tokens: getTokensPropType('TabBar')
107
+ }
108
+
109
+ const styles = StyleSheet.create({
110
+ tabBar: {
111
+ flex: 1,
112
+ justifyContent: 'center',
113
+ alignItems: 'center'
114
+ },
115
+ tabBarItem: {
116
+ flex: 1,
117
+ flexDirection: 'row',
118
+ justifyContent: 'space-between',
119
+ width: '100%'
120
+ }
121
+ })
122
+
123
+ export default TabBar
@@ -0,0 +1,149 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import { Pressable, View, StyleSheet } from 'react-native'
4
+ import { getTokensPropType, resolvePressableTokens, variantProp } from '../utils'
5
+ import { useThemeTokensCallback } from '../ThemeProvider'
6
+ import Typography from '../Typography'
7
+ import Spacer from '../Spacer'
8
+
9
+ const selectTypographyStyles = (
10
+ { fontWeight, color, lineHeight, fontName, activeColor },
11
+ isSelected
12
+ ) => ({
13
+ fontWeight,
14
+ color: isSelected ? activeColor : color,
15
+ lineHeight,
16
+ fontName
17
+ })
18
+
19
+ const selectIconContainerStyles = ({ paddingTop, paddingBottom }) => ({
20
+ paddingTop,
21
+ paddingBottom,
22
+ alignItems: 'center'
23
+ })
24
+
25
+ const selectIconStyles = ({ iconSize, iconColor, activeColor }, isSelected) => ({
26
+ size: iconSize,
27
+ color: isSelected ? activeColor : iconColor
28
+ })
29
+
30
+ const selectContainerStyles = ({ borderRadius, backgroundColor }) => ({
31
+ borderRadius,
32
+ backgroundColor,
33
+ alignSelf: 'center',
34
+ alignItems: 'center'
35
+ })
36
+
37
+ const TabBarItem = React.forwardRef(
38
+ (
39
+ {
40
+ href,
41
+ variant,
42
+ tokens,
43
+ label,
44
+ isSelected,
45
+ id,
46
+ onPress,
47
+ icon: IconComponent,
48
+ iconActive: IconActiveComponent,
49
+ accessibilityRole = 'tab'
50
+ },
51
+ ref
52
+ ) => {
53
+ const getTokens = useThemeTokensCallback('TabBarItem', tokens, variant)
54
+
55
+ const getPressableStyle = ({ pressed, focused, hovered }) => {
56
+ const resolvedTokens = resolvePressableTokens(
57
+ getTokens,
58
+ { pressed, focused, hovered },
59
+ { isSelected }
60
+ )
61
+ return {
62
+ ...resolvedTokens,
63
+ outline: 'none' // removes the default browser :focus outline
64
+ }
65
+ }
66
+
67
+ return (
68
+ <Pressable
69
+ ref={ref}
70
+ href={href}
71
+ nativeID={id}
72
+ onPress={onPress}
73
+ style={({ pressed, focused, hovered }) => [
74
+ styles.flexContainer,
75
+ getPressableStyle({ pressed, focused, hovered })
76
+ ]}
77
+ accessibilityRole={accessibilityRole}
78
+ testID={id}
79
+ >
80
+ {(pressableState) => {
81
+ const resolvedTokens = getPressableStyle(pressableState)
82
+
83
+ return (
84
+ <View style={selectContainerStyles(resolvedTokens)}>
85
+ <View style={[selectIconContainerStyles(resolvedTokens), styles.iconContainer]}>
86
+ {isSelected
87
+ ? IconActiveComponent && (
88
+ <IconActiveComponent {...selectIconStyles(resolvedTokens, isSelected)} />
89
+ )
90
+ : IconComponent && <IconComponent {...selectIconStyles(resolvedTokens)} />}
91
+ </View>
92
+ <Spacer space={1} />
93
+ <Typography
94
+ variant={{ size: 'micro' }}
95
+ tokens={selectTypographyStyles(resolvedTokens, isSelected)}
96
+ align="center"
97
+ >
98
+ {label}
99
+ </Typography>
100
+ <Spacer space={1} />
101
+ </View>
102
+ )
103
+ }}
104
+ </Pressable>
105
+ )
106
+ }
107
+ )
108
+
109
+ TabBarItem.displayName = 'TabBarItem'
110
+
111
+ TabBarItem.propTypes = {
112
+ /** The icon to be displayed when the item is not selected. */
113
+ icon: PropTypes.elementType,
114
+ /** The icon to be displayed when the item is selected. */
115
+ iconActive: PropTypes.elementType,
116
+ /** Tokens for theming and styling the TabBarItem. */
117
+ tokens: getTokensPropType('TabBarItem'),
118
+ /** Variant of the TabBarItem for styling purposes. */
119
+ variant: variantProp.propType,
120
+ /** Callback function to handle press events. */
121
+ onPress: PropTypes.func,
122
+ /** URL to navigate to when the item is pressed. */
123
+ href: PropTypes.string,
124
+ /** Indicates whether the item is selected. */
125
+ isSelected: PropTypes.bool,
126
+ /** Unique identifier for the item. */
127
+ id: PropTypes.string,
128
+ /** Label text for the item. */
129
+ label: PropTypes.string.isRequired,
130
+ /** Accessibility role for the item. */
131
+ accessibilityRole: PropTypes.string
132
+ }
133
+
134
+ const styles = StyleSheet.create({
135
+ flexContainer: {
136
+ flex: 1,
137
+ alignItems: 'center'
138
+ },
139
+ iconContainer: {
140
+ flex: 1,
141
+ justifyContent: 'center',
142
+ alignItems: 'center',
143
+ minWidth: 44,
144
+ minHeight: 40,
145
+ aspectRatio: 1.1
146
+ }
147
+ })
148
+
149
+ export default TabBarItem
@@ -0,0 +1,3 @@
1
+ import TabBar from './TabBar'
2
+
3
+ export default TabBar
@@ -61,7 +61,7 @@ const selectInputStyles = (
61
61
  typeof value === 'number' ? Math.max(0, value - borderWidth) : value
62
62
 
63
63
  const textStyles = applyTextStyles({
64
- fontName,
64
+ fontName: isPassword ? undefined : fontName, // In this case, we don't want to apply the fontName to the input if it's a password because Monotype don't have support for the masked characters in mobile.
65
65
  fontSize,
66
66
  lineHeight,
67
67
  fontWeight,
@@ -1,8 +1,8 @@
1
- function normalizePosition(position) {
1
+ function getAbsolutePosition(position) {
2
2
  const { left, right, bottom, top, width, ...rest } = position
3
3
 
4
4
  // adjust the coordinates so that it fits within the window
5
- const normalized = {
5
+ const finalPosition = {
6
6
  left: Math.max(0, left),
7
7
  right: Math.max(0, right),
8
8
  top: Math.max(0, top),
@@ -12,21 +12,20 @@ function normalizePosition(position) {
12
12
  const getAbsoluteDiff = (value1, value2) => Math.abs(Math.abs(value1) - Math.abs(value2))
13
13
 
14
14
  // adjust the width by whatever has been subtracted from left or right
15
- normalized.width =
15
+ finalPosition.width =
16
16
  width -
17
- Math.abs(getAbsoluteDiff(left, normalized.left) - getAbsoluteDiff(right, normalized.right))
17
+ Math.abs(
18
+ getAbsoluteDiff(left, finalPosition.left) - getAbsoluteDiff(right, finalPosition.right)
19
+ )
18
20
 
19
- if (normalized.top !== top) {
20
- normalized.bottom += normalized.top - top
21
+ if (finalPosition.top !== top) {
22
+ finalPosition.bottom += finalPosition.top - top
21
23
  }
22
24
 
23
- const isNormalized =
24
- normalized.right !== right || normalized.left !== left || normalized.top !== top
25
-
26
25
  return {
27
- ...normalized,
26
+ ...finalPosition,
28
27
  ...rest,
29
- isNormalized
28
+ isNormalized: false
30
29
  }
31
30
  }
32
31
 
@@ -151,7 +150,7 @@ function getTooltipPosition(
151
150
 
152
151
  // prefer 'below' over 'above', since we can always expand the document downwards,
153
152
  // and 'above' might cause issues on small viewports with large tooltips
154
- return normalizePosition(
153
+ return getAbsolutePosition(
155
154
  leastOverflowing.position === 'above'
156
155
  ? findRectByPosition('below', boundingRects)
157
156
  : leastOverflowing