@telus-uds/components-base 1.94.0 → 1.95.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 (41) hide show
  1. package/CHANGELOG.md +20 -2
  2. package/lib/Autocomplete/Autocomplete.js +2 -1
  3. package/lib/DownloadApp/DownloadApp.js +168 -0
  4. package/lib/DownloadApp/dictionary.js +17 -0
  5. package/lib/DownloadApp/index.js +10 -0
  6. package/lib/Icon/IconText.js +19 -2
  7. package/lib/Link/LinkBase.js +2 -2
  8. package/lib/Modal/Modal.js +1 -1
  9. package/lib/TabBar/TabBar.js +133 -0
  10. package/lib/TabBar/TabBarItem.js +184 -0
  11. package/lib/TabBar/index.js +10 -0
  12. package/lib/TextInput/TextInputBase.js +2 -1
  13. package/lib/Tooltip/getTooltipPosition.js +8 -9
  14. package/lib/index.js +16 -0
  15. package/lib-module/Autocomplete/Autocomplete.js +2 -1
  16. package/lib-module/DownloadApp/DownloadApp.js +160 -0
  17. package/lib-module/DownloadApp/dictionary.js +10 -0
  18. package/lib-module/DownloadApp/index.js +2 -0
  19. package/lib-module/Icon/IconText.js +19 -2
  20. package/lib-module/Link/LinkBase.js +2 -2
  21. package/lib-module/Modal/Modal.js +1 -1
  22. package/lib-module/TabBar/TabBar.js +125 -0
  23. package/lib-module/TabBar/TabBarItem.js +177 -0
  24. package/lib-module/TabBar/index.js +2 -0
  25. package/lib-module/TextInput/TextInputBase.js +2 -1
  26. package/lib-module/Tooltip/getTooltipPosition.js +8 -9
  27. package/lib-module/index.js +2 -0
  28. package/package.json +2 -2
  29. package/src/Autocomplete/Autocomplete.jsx +2 -1
  30. package/src/DownloadApp/DownloadApp.jsx +165 -0
  31. package/src/DownloadApp/dictionary.js +10 -0
  32. package/src/DownloadApp/index.js +3 -0
  33. package/src/Icon/IconText.jsx +21 -4
  34. package/src/Link/LinkBase.jsx +2 -2
  35. package/src/Modal/Modal.jsx +1 -1
  36. package/src/TabBar/TabBar.jsx +123 -0
  37. package/src/TabBar/TabBarItem.jsx +149 -0
  38. package/src/TabBar/index.js +3 -0
  39. package/src/TextInput/TextInputBase.jsx +1 -1
  40. package/src/Tooltip/getTooltipPosition.js +11 -12
  41. package/src/index.js +2 -0
@@ -1,4 +1,4 @@
1
- function normalizePosition(position) {
1
+ function getAbsolutePosition(position) {
2
2
  const {
3
3
  left,
4
4
  right,
@@ -9,7 +9,7 @@ function normalizePosition(position) {
9
9
  } = position;
10
10
 
11
11
  // adjust the coordinates so that it fits within the window
12
- const normalized = {
12
+ const finalPosition = {
13
13
  left: Math.max(0, left),
14
14
  right: Math.max(0, right),
15
15
  top: Math.max(0, top),
@@ -19,15 +19,14 @@ function normalizePosition(position) {
19
19
  const getAbsoluteDiff = (value1, value2) => Math.abs(Math.abs(value1) - Math.abs(value2));
20
20
 
21
21
  // adjust the width by whatever has been subtracted from left or right
22
- normalized.width = width - Math.abs(getAbsoluteDiff(left, normalized.left) - getAbsoluteDiff(right, normalized.right));
23
- if (normalized.top !== top) {
24
- normalized.bottom += normalized.top - top;
22
+ finalPosition.width = width - Math.abs(getAbsoluteDiff(left, finalPosition.left) - getAbsoluteDiff(right, finalPosition.right));
23
+ if (finalPosition.top !== top) {
24
+ finalPosition.bottom += finalPosition.top - top;
25
25
  }
26
- const isNormalized = normalized.right !== right || normalized.left !== left || normalized.top !== top;
27
26
  return {
28
- ...normalized,
27
+ ...finalPosition,
29
28
  ...rest,
30
- isNormalized
29
+ isNormalized: false
31
30
  };
32
31
  }
33
32
  function invertPosition(position) {
@@ -166,6 +165,6 @@ function getTooltipPosition(position, _ref2) {
166
165
 
167
166
  // prefer 'below' over 'above', since we can always expand the document downwards,
168
167
  // and 'above' might cause issues on small viewports with large tooltips
169
- return normalizePosition(leastOverflowing.position === 'above' ? findRectByPosition('below', boundingRects) : leastOverflowing);
168
+ return getAbsolutePosition(leastOverflowing.position === 'above' ? findRectByPosition('below', boundingRects) : leastOverflowing);
170
169
  }
171
170
  export default getTooltipPosition;
@@ -15,6 +15,7 @@ export * from './Checkbox';
15
15
  export { default as CheckboxCard } from './CheckboxCard';
16
16
  export { default as CheckboxCardGroup } from './CheckboxCardGroup';
17
17
  export { default as ColourToggle } from './ColourToggle';
18
+ export { default as DownloadApp } from './DownloadApp';
18
19
  export { default as Divider } from './Divider';
19
20
  export { default as ExpandCollapse, Accordion } from './ExpandCollapse';
20
21
  export { default as Feedback } from './Feedback';
@@ -57,6 +58,7 @@ export * from './StackView';
57
58
  export { default as Status } from './Status';
58
59
  export { default as StepTracker } from './StepTracker';
59
60
  export { default as Tabs } from './Tabs';
61
+ export { default as TabBar } from './TabBar';
60
62
  export { default as Tags } from './Tags';
61
63
  export * from './TextInput';
62
64
  export { default as Timeline } from './Timeline';
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "@floating-ui/react-native": "^0.8.1",
12
12
  "@gorhom/portal": "^1.0.14",
13
13
  "@telus-uds/system-constants": "^1.3.0",
14
- "@telus-uds/system-theme-tokens": "^2.63.0",
14
+ "@telus-uds/system-theme-tokens": "^2.64.0",
15
15
  "airbnb-prop-types": "^2.16.0",
16
16
  "css-mediaquery": "^0.1.2",
17
17
  "expo-linear-gradient": "^12.5.0",
@@ -86,6 +86,6 @@
86
86
  "standard-engine": {
87
87
  "skip": true
88
88
  },
89
- "version": "1.94.0",
89
+ "version": "1.95.0",
90
90
  "types": "types/index.d.ts"
91
91
  }
@@ -102,6 +102,7 @@ const Autocomplete = React.forwardRef(
102
102
  validation,
103
103
  value,
104
104
  helpText = '',
105
+ loadingLabel,
105
106
  ...rest
106
107
  },
107
108
  ref
@@ -334,7 +335,7 @@ const Autocomplete = React.forwardRef(
334
335
  ref={openOverlayRef}
335
336
  >
336
337
  {isLoading ? (
337
- <Loading label={getCopy('loading')} />
338
+ <Loading label={loadingLabel ?? getCopy('loading')} />
338
339
  ) : (
339
340
  <Suggestions
340
341
  hasResults={getCopy('hasResults')}
@@ -0,0 +1,165 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import { Pressable, Platform, StyleSheet } from 'react-native'
4
+ import {
5
+ a11yProps,
6
+ linkProps,
7
+ hrefAttrsProp,
8
+ viewProps,
9
+ getTokensPropType,
10
+ resolvePressableTokens,
11
+ variantProp,
12
+ copyPropTypes,
13
+ selectSystemProps,
14
+ useCopy
15
+ } from '../utils'
16
+ import { useThemeTokensCallback } from '../ThemeProvider'
17
+ import defaultDictionary from './dictionary'
18
+
19
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, linkProps, viewProps])
20
+
21
+ const selectOuterStyles = ({ borderColor, borderWidth, borderGap, borderRadius, padding }) => ({
22
+ outline: 'none',
23
+ borderColor,
24
+ borderWidth,
25
+ borderGap,
26
+ borderRadius,
27
+ padding
28
+ })
29
+
30
+ const DownloadApp = React.forwardRef(
31
+ (
32
+ {
33
+ copy = 'en',
34
+ dictionary = defaultDictionary,
35
+ type = 'ios',
36
+ href,
37
+ onPress,
38
+ tokens = {},
39
+ variant = {},
40
+ ...props
41
+ },
42
+ ref
43
+ ) => {
44
+ const getCopy = useCopy({ dictionary, copy })
45
+ const { hrefAttrs, rest } = hrefAttrsProp.bundle(props)
46
+
47
+ const selectedProps = selectProps({
48
+ accessibilityRole: href ? 'link' : 'button',
49
+ href,
50
+ onPress: linkProps.handleHref({ href, onPress }),
51
+ hrefAttrs,
52
+ ...rest
53
+ })
54
+
55
+ const getDownloadAppTokens = useThemeTokensCallback('DownloadApp', tokens, variant)
56
+ const resolveDownloadAppTokens = (pressableState) => {
57
+ const themeTokens = resolvePressableTokens(getDownloadAppTokens, pressableState, {})
58
+ return selectOuterStyles(themeTokens)
59
+ }
60
+
61
+ const { androidENIcon, androidFRIcon, iosENIcon, iosFRIcon } = getDownloadAppTokens()
62
+
63
+ const imageResources = {
64
+ en: {
65
+ android: androidENIcon,
66
+ ios: iosENIcon
67
+ },
68
+ fr: {
69
+ android: androidFRIcon,
70
+ ios: iosFRIcon
71
+ }
72
+ }
73
+ const IconComponent = imageResources[copy][type]
74
+
75
+ return (
76
+ <Pressable
77
+ ref={ref}
78
+ style={(pressState) => [resolveDownloadAppTokens(pressState), staticStyles.row]}
79
+ {...selectedProps}
80
+ >
81
+ <IconComponent
82
+ style={staticImageSizes[type][copy]}
83
+ alt={type === 'ios' ? getCopy('altTextIos') : getCopy('altTextAndroid')}
84
+ />
85
+ </Pressable>
86
+ )
87
+ }
88
+ )
89
+ DownloadApp.displayName = 'DownloadApp'
90
+
91
+ const dictionaryContentShape = PropTypes.shape({
92
+ altTextAndroid: PropTypes.string.isRequired,
93
+ altTextIos: PropTypes.string.isRequired
94
+ })
95
+
96
+ DownloadApp.propTypes = {
97
+ ...selectedSystemPropTypes,
98
+ copy: copyPropTypes,
99
+ /**
100
+ * Override the default dictionary, by passing the complete dictionary object for `en` and `fr`
101
+ */
102
+ dictionary: PropTypes.shape({
103
+ en: dictionaryContentShape,
104
+ fr: dictionaryContentShape
105
+ }),
106
+ /**
107
+ * Select the type of image to show.
108
+ */
109
+ type: PropTypes.oneOf(['android', 'ios']),
110
+ /**
111
+ * It's a simple link that opens the Download Button instead of the onPress function.
112
+ */
113
+ href: PropTypes.string,
114
+ /**
115
+ * Function called when the button is pressed. Required unless the button has a href.
116
+ */
117
+ onPress: PropTypes.func,
118
+ /**
119
+ * DownloadApp tokens.
120
+ */
121
+ tokens: getTokensPropType('DownloadApp'),
122
+ /**
123
+ * DownloadApp variant.
124
+ */
125
+ variant: variantProp.propType
126
+ }
127
+
128
+ const staticStyles = StyleSheet.create({
129
+ row: {
130
+ ...Platform.select({
131
+ web: {
132
+ display: 'inline-flex',
133
+ width: 'fit-content'
134
+ },
135
+ default: {
136
+ alignSelf: 'flex-start'
137
+ }
138
+ })
139
+ }
140
+ })
141
+
142
+ const staticImageSizes = {
143
+ android: {
144
+ en: {
145
+ width: 162,
146
+ height: 48
147
+ },
148
+ fr: {
149
+ width: 162,
150
+ height: 48
151
+ }
152
+ },
153
+ ios: {
154
+ en: {
155
+ width: 144,
156
+ height: 48
157
+ },
158
+ fr: {
159
+ width: 152,
160
+ height: 48
161
+ }
162
+ }
163
+ }
164
+
165
+ export default DownloadApp
@@ -0,0 +1,10 @@
1
+ export default {
2
+ en: {
3
+ altTextAndroid: 'Get it on Google Play',
4
+ altTextIos: 'Download on the App Store'
5
+ },
6
+ fr: {
7
+ altTextAndroid: 'Disponible sur Google Play',
8
+ altTextIos: 'Télécharger dans l’App Store'
9
+ }
10
+ }
@@ -0,0 +1,3 @@
1
+ import DownloadApp from './DownloadApp'
2
+
3
+ export default DownloadApp
@@ -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.
@@ -147,7 +147,7 @@ const Modal = React.forwardRef(
147
147
  if (Platform.OS === 'web') {
148
148
  const handleFocus = () => {
149
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) {
150
+ if (document.activeElement === focusTrapRef.current && closeButtonRef.current) {
151
151
  closeButtonRef.current.focus()
152
152
  }
153
153
  return undefined
@@ -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