@idealyst/navigation 1.0.61 → 1.0.63
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.
- package/package.json +3 -3
- package/src/context/NavigatorContext.native.tsx +5 -3
- package/src/context/NavigatorContext.web.tsx +14 -6
- package/src/context/types.ts +2 -2
- package/src/examples/CustomStackLayout.tsx +63 -0
- package/src/examples/CustomTabLayout.tsx +44 -0
- package/src/examples/ExampleHybridRouter.tsx +34 -32
- package/src/examples/ExampleStackRouter.tsx +22 -24
- package/src/examples/ExampleTabRouter.tsx +42 -37
- package/src/layouts/DefaultStackLayout.tsx +57 -0
- package/src/layouts/DefaultTabLayout.tsx +101 -0
- package/src/layouts/index.ts +4 -1
- package/src/routing/router.native.tsx +40 -179
- package/src/routing/router.web.tsx +192 -335
- package/src/routing/types.ts +64 -17
- package/src/layouts/GeneralLayout/GeneralLayout.styles.tsx +0 -55
- package/src/layouts/GeneralLayout/GeneralLayout.tsx +0 -143
- package/src/layouts/GeneralLayout/README.md +0 -498
- package/src/layouts/GeneralLayout/index.ts +0 -2
- package/src/layouts/GeneralLayout/types.ts +0 -99
- package/src/layouts/TabBarLayout/TabBarLayout.native.tsx +0 -283
- package/src/layouts/TabBarLayout/TabBarLayout.styles.tsx +0 -142
- package/src/layouts/TabBarLayout/TabBarLayout.web.tsx +0 -286
- package/src/layouts/TabBarLayout/index.native.ts +0 -2
- package/src/layouts/TabBarLayout/index.ts +0 -2
- package/src/layouts/TabBarLayout/index.web.ts +0 -2
- package/src/layouts/TabBarLayout/types.ts +0 -176
- package/src/routing/README.md +0 -421
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
export interface SidebarConfig {
|
|
4
|
-
/**
|
|
5
|
-
* Whether the sidebar is enabled
|
|
6
|
-
*/
|
|
7
|
-
enabled?: boolean;
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Whether the sidebar is initially expanded
|
|
11
|
-
*/
|
|
12
|
-
initiallyExpanded?: boolean;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Width of the sidebar when expanded
|
|
16
|
-
*/
|
|
17
|
-
expandedWidth?: number;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Width of the sidebar when collapsed
|
|
21
|
-
*/
|
|
22
|
-
collapsedWidth?: number;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Whether the sidebar can be collapsed
|
|
26
|
-
*/
|
|
27
|
-
collapsible?: boolean;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Position of the sidebar
|
|
31
|
-
*/
|
|
32
|
-
position?: 'left' | 'right';
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Content to display in the sidebar
|
|
36
|
-
*/
|
|
37
|
-
content?: ReactNode;
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Custom styles for the sidebar
|
|
41
|
-
*/
|
|
42
|
-
style?: any;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface HeaderConfig {
|
|
46
|
-
/**
|
|
47
|
-
* Whether the header is enabled
|
|
48
|
-
*/
|
|
49
|
-
enabled?: boolean;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Height of the header
|
|
53
|
-
*/
|
|
54
|
-
height?: number;
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Content to display in the header
|
|
58
|
-
*/
|
|
59
|
-
content?: ReactNode;
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Custom styles for the header
|
|
63
|
-
*/
|
|
64
|
-
style?: any;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export interface GeneralLayoutProps {
|
|
68
|
-
/**
|
|
69
|
-
* The main content to display
|
|
70
|
-
*/
|
|
71
|
-
children?: ReactNode;
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Sidebar configuration
|
|
75
|
-
*/
|
|
76
|
-
sidebar?: SidebarConfig;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Header configuration
|
|
80
|
-
*/
|
|
81
|
-
header?: HeaderConfig;
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Additional styles for the layout container
|
|
85
|
-
*/
|
|
86
|
-
style?: any;
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Test ID for testing
|
|
90
|
-
*/
|
|
91
|
-
testID?: string;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export interface GeneralLayoutState {
|
|
95
|
-
/**
|
|
96
|
-
* Whether the sidebar is currently expanded
|
|
97
|
-
*/
|
|
98
|
-
isSidebarExpanded: boolean;
|
|
99
|
-
}
|
|
@@ -1,283 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
|
2
|
-
import { View, Text, Button, Icon, Pressable } from '@idealyst/components';
|
|
3
|
-
import { TabBarLayoutProps, TabBarConfig, TabButtonProps } from './types';
|
|
4
|
-
import { tabBarLayoutStyles } from './TabBarLayout.styles';
|
|
5
|
-
import { Dimensions } from 'react-native';
|
|
6
|
-
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
7
|
-
|
|
8
|
-
const DEFAULT_AUTO_BREAKPOINT = 768;
|
|
9
|
-
|
|
10
|
-
const NativeHeader: React.FC<{
|
|
11
|
-
config: any;
|
|
12
|
-
styles: any;
|
|
13
|
-
showTabsInHeader: boolean;
|
|
14
|
-
tabBarConfig: TabBarConfig;
|
|
15
|
-
insets: any;
|
|
16
|
-
}> = ({ config, styles, showTabsInHeader, tabBarConfig, insets }) => {
|
|
17
|
-
const handleBackPress = () => {
|
|
18
|
-
if (config.onBackPress) {
|
|
19
|
-
config.onBackPress();
|
|
20
|
-
}
|
|
21
|
-
// Could integrate with React Navigation here
|
|
22
|
-
// navigation.goBack();
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const headerDynamicStyles = {
|
|
26
|
-
height: config.height,
|
|
27
|
-
minHeight: config.height,
|
|
28
|
-
paddingTop: config.enabled ? insets.top : 0,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
return (
|
|
32
|
-
<View
|
|
33
|
-
style={[
|
|
34
|
-
styles.headerContainer,
|
|
35
|
-
headerDynamicStyles,
|
|
36
|
-
config.style,
|
|
37
|
-
]}
|
|
38
|
-
>
|
|
39
|
-
<View style={styles.headerContent}>
|
|
40
|
-
{/* Custom content overrides native elements */}
|
|
41
|
-
{config.content ? (
|
|
42
|
-
config.content
|
|
43
|
-
) : (
|
|
44
|
-
<View style={{ flexDirection: 'row', alignItems: 'center', flex: 1 }}>
|
|
45
|
-
{/* Back Button */}
|
|
46
|
-
{config.showBackButton && (
|
|
47
|
-
<Button
|
|
48
|
-
variant="text"
|
|
49
|
-
onPress={handleBackPress}
|
|
50
|
-
style={{ marginRight: 8, minWidth: 'auto' }}
|
|
51
|
-
>
|
|
52
|
-
<Icon name="arrow-left" size="lg" color="primary" />
|
|
53
|
-
</Button>
|
|
54
|
-
)}
|
|
55
|
-
|
|
56
|
-
{/* Title */}
|
|
57
|
-
{config.title && (
|
|
58
|
-
<Text
|
|
59
|
-
size="large"
|
|
60
|
-
weight="semibold"
|
|
61
|
-
style={{ flex: 1 }}
|
|
62
|
-
>
|
|
63
|
-
{config.title}
|
|
64
|
-
</Text>
|
|
65
|
-
)}
|
|
66
|
-
</View>
|
|
67
|
-
)}
|
|
68
|
-
</View>
|
|
69
|
-
|
|
70
|
-
<View style={styles.headerRightContent}>
|
|
71
|
-
{/* Tabs in header for wide screens */}
|
|
72
|
-
{showTabsInHeader && tabBarConfig.items.length > 0 && (
|
|
73
|
-
<TabBar config={tabBarConfig} position="header" />
|
|
74
|
-
)}
|
|
75
|
-
|
|
76
|
-
{/* Additional right content */}
|
|
77
|
-
{config.rightContent}
|
|
78
|
-
</View>
|
|
79
|
-
</View>
|
|
80
|
-
);
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
const TabButton: React.FC<TabButtonProps> = ({ item, isActive, onPress, position }) => {
|
|
84
|
-
const styles = tabBarLayoutStyles;
|
|
85
|
-
const isHeader = position === 'header';
|
|
86
|
-
|
|
87
|
-
return (
|
|
88
|
-
<Pressable
|
|
89
|
-
onPress={onPress}
|
|
90
|
-
disabled={item.disabled}
|
|
91
|
-
style={[
|
|
92
|
-
isHeader ? styles.tabButtonHeader : styles.tabButton,
|
|
93
|
-
isActive && styles.tabButtonActive,
|
|
94
|
-
item.disabled && styles.tabButtonDisabled,
|
|
95
|
-
]}
|
|
96
|
-
>
|
|
97
|
-
<View style={styles.tabIconContainer}>
|
|
98
|
-
{item.icon && (
|
|
99
|
-
typeof item.icon === 'string' ? (
|
|
100
|
-
<Icon name={item.icon as any} size={isHeader ? "lg" : "md"} color={isActive ? 'primary' : 'secondary'} />
|
|
101
|
-
) : (
|
|
102
|
-
item.icon
|
|
103
|
-
)
|
|
104
|
-
)}
|
|
105
|
-
{item.badge !== undefined && (
|
|
106
|
-
<View style={styles.tabBadge}>
|
|
107
|
-
<Text style={styles.tabBadgeText}>
|
|
108
|
-
{typeof item.badge === 'number' && item.badge > 99 ? '99+' : item.badge}
|
|
109
|
-
</Text>
|
|
110
|
-
</View>
|
|
111
|
-
)}
|
|
112
|
-
</View>
|
|
113
|
-
{(!isHeader || (isHeader && item.label)) && (
|
|
114
|
-
<Text
|
|
115
|
-
size={isHeader ? "medium" : "small"}
|
|
116
|
-
color={isActive ? 'primary' : 'secondary'}
|
|
117
|
-
style={isHeader ? { marginLeft: 8 } : { marginTop: 2, textAlign: 'center', fontSize: 10 }}
|
|
118
|
-
>
|
|
119
|
-
{item.label}
|
|
120
|
-
</Text>
|
|
121
|
-
)}
|
|
122
|
-
</Pressable>
|
|
123
|
-
);
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const TabBar: React.FC<{
|
|
127
|
-
config: TabBarConfig;
|
|
128
|
-
position: 'bottom' | 'header';
|
|
129
|
-
}> = ({ config, position }) => {
|
|
130
|
-
const styles = tabBarLayoutStyles;
|
|
131
|
-
|
|
132
|
-
if (config.renderTabBar) {
|
|
133
|
-
return (
|
|
134
|
-
<>
|
|
135
|
-
{config.renderTabBar({
|
|
136
|
-
items: config.items,
|
|
137
|
-
activeTab: config.activeTab,
|
|
138
|
-
onTabSelect: config.onTabSelect,
|
|
139
|
-
position,
|
|
140
|
-
})}
|
|
141
|
-
</>
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const containerStyle = position === 'header'
|
|
146
|
-
? styles.headerTabs
|
|
147
|
-
: [styles.tabBarBottom, config.style];
|
|
148
|
-
|
|
149
|
-
return (
|
|
150
|
-
<View style={containerStyle}>
|
|
151
|
-
{config.items.map((item) => {
|
|
152
|
-
if (item.renderTab) {
|
|
153
|
-
return (
|
|
154
|
-
<React.Fragment key={item.id}>
|
|
155
|
-
{item.renderTab({
|
|
156
|
-
item,
|
|
157
|
-
isActive: item.id === config.activeTab,
|
|
158
|
-
onPress: () => config.onTabSelect?.(item.id),
|
|
159
|
-
position,
|
|
160
|
-
})}
|
|
161
|
-
</React.Fragment>
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return (
|
|
166
|
-
<TabButton
|
|
167
|
-
key={item.id}
|
|
168
|
-
item={item}
|
|
169
|
-
isActive={item.id === config.activeTab}
|
|
170
|
-
onPress={() => config.onTabSelect?.(item.id)}
|
|
171
|
-
position={position}
|
|
172
|
-
/>
|
|
173
|
-
);
|
|
174
|
-
})}
|
|
175
|
-
</View>
|
|
176
|
-
);
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
const TabBarLayout: React.FC<TabBarLayoutProps> = ({
|
|
180
|
-
children,
|
|
181
|
-
tabBar = {},
|
|
182
|
-
header = {},
|
|
183
|
-
style,
|
|
184
|
-
testID,
|
|
185
|
-
}) => {
|
|
186
|
-
const styles = tabBarLayoutStyles;
|
|
187
|
-
const insets = useSafeAreaInsets();
|
|
188
|
-
const [screenWidth, setScreenWidth] = useState(() => Dimensions.get('window').width);
|
|
189
|
-
|
|
190
|
-
// Default tab bar configuration
|
|
191
|
-
const tabBarConfig = {
|
|
192
|
-
items: [],
|
|
193
|
-
activeTab: undefined,
|
|
194
|
-
onTabSelect: undefined,
|
|
195
|
-
position: 'auto' as const,
|
|
196
|
-
autoBreakpoint: DEFAULT_AUTO_BREAKPOINT,
|
|
197
|
-
style: undefined,
|
|
198
|
-
tabStyle: undefined,
|
|
199
|
-
showLabels: true,
|
|
200
|
-
renderTabBar: undefined,
|
|
201
|
-
...tabBar,
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
// Default header configuration
|
|
205
|
-
const headerConfig = {
|
|
206
|
-
enabled: true,
|
|
207
|
-
height: 64,
|
|
208
|
-
title: undefined,
|
|
209
|
-
showBackButton: false,
|
|
210
|
-
onBackPress: undefined,
|
|
211
|
-
content: null,
|
|
212
|
-
rightContent: null,
|
|
213
|
-
style: undefined,
|
|
214
|
-
showTabs: true,
|
|
215
|
-
native: true,
|
|
216
|
-
...header,
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
// Update screen width on orientation change
|
|
220
|
-
useEffect(() => {
|
|
221
|
-
const updateDimensions = () => {
|
|
222
|
-
setScreenWidth(Dimensions.get('window').width);
|
|
223
|
-
};
|
|
224
|
-
|
|
225
|
-
const subscription = Dimensions.addEventListener('change', updateDimensions);
|
|
226
|
-
return () => subscription?.remove();
|
|
227
|
-
}, []);
|
|
228
|
-
|
|
229
|
-
// Determine actual tab position - native always uses bottom for mobile
|
|
230
|
-
const actualTabPosition = (() => {
|
|
231
|
-
if (tabBarConfig.position === 'auto') {
|
|
232
|
-
return 'bottom'; // Native mobile apps typically use bottom tabs
|
|
233
|
-
}
|
|
234
|
-
return tabBarConfig.position;
|
|
235
|
-
})();
|
|
236
|
-
|
|
237
|
-
const showTabsInHeader = actualTabPosition === 'header' && headerConfig.showTabs;
|
|
238
|
-
const showTabsAtBottom = actualTabPosition === 'bottom';
|
|
239
|
-
|
|
240
|
-
// Create dynamic styles for bottom tab bar
|
|
241
|
-
const tabBarBottomStyles = {
|
|
242
|
-
paddingBottom: showTabsAtBottom ? insets.bottom : 0,
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
return (
|
|
246
|
-
<View
|
|
247
|
-
style={[
|
|
248
|
-
styles.container,
|
|
249
|
-
style,
|
|
250
|
-
]}
|
|
251
|
-
testID={testID}
|
|
252
|
-
>
|
|
253
|
-
{/* Header */}
|
|
254
|
-
{headerConfig.enabled && (
|
|
255
|
-
<NativeHeader
|
|
256
|
-
config={headerConfig}
|
|
257
|
-
styles={styles}
|
|
258
|
-
showTabsInHeader={showTabsInHeader}
|
|
259
|
-
tabBarConfig={tabBarConfig}
|
|
260
|
-
insets={insets}
|
|
261
|
-
/>
|
|
262
|
-
)}
|
|
263
|
-
|
|
264
|
-
{/* Main Content Area */}
|
|
265
|
-
<View style={styles.bodyContainer}>
|
|
266
|
-
<View style={styles.mainContent}>
|
|
267
|
-
<View style={styles.contentArea}>
|
|
268
|
-
{children}
|
|
269
|
-
</View>
|
|
270
|
-
</View>
|
|
271
|
-
</View>
|
|
272
|
-
|
|
273
|
-
{/* Bottom Tab Bar */}
|
|
274
|
-
{showTabsAtBottom && tabBarConfig.items.length > 0 && (
|
|
275
|
-
<View style={tabBarBottomStyles}>
|
|
276
|
-
<TabBar config={tabBarConfig} position="bottom" />
|
|
277
|
-
</View>
|
|
278
|
-
)}
|
|
279
|
-
</View>
|
|
280
|
-
);
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
export default TabBarLayout;
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { StyleSheet } from 'react-native-unistyles';
|
|
2
|
-
|
|
3
|
-
export const tabBarLayoutStyles = StyleSheet.create(theme => ({
|
|
4
|
-
container: {
|
|
5
|
-
flex: 1,
|
|
6
|
-
backgroundColor: theme.colors.background,
|
|
7
|
-
},
|
|
8
|
-
|
|
9
|
-
headerContainer: {
|
|
10
|
-
flexDirection: 'row',
|
|
11
|
-
alignItems: 'center',
|
|
12
|
-
justifyContent: 'space-between',
|
|
13
|
-
backgroundColor: theme.colors.surface,
|
|
14
|
-
borderBottomWidth: 1,
|
|
15
|
-
borderBottomColor: theme.colors.border,
|
|
16
|
-
paddingHorizontal: theme.spacing?.md,
|
|
17
|
-
zIndex: 10,
|
|
18
|
-
web: {
|
|
19
|
-
backgroundColor: '#ffffff', // Light background for web
|
|
20
|
-
borderBottomColor: '#e0e0e0', // Light border for web
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
|
|
24
|
-
headerContent: {
|
|
25
|
-
flex: 1,
|
|
26
|
-
flexDirection: 'row',
|
|
27
|
-
alignItems: 'center',
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
headerRightContent: {
|
|
31
|
-
flexDirection: 'row',
|
|
32
|
-
alignItems: 'center',
|
|
33
|
-
gap: theme.spacing?.sm,
|
|
34
|
-
},
|
|
35
|
-
|
|
36
|
-
headerTabs: {
|
|
37
|
-
flexDirection: 'row',
|
|
38
|
-
alignItems: 'center',
|
|
39
|
-
gap: theme.spacing?.xs,
|
|
40
|
-
},
|
|
41
|
-
|
|
42
|
-
bodyContainer: {
|
|
43
|
-
flex: 1,
|
|
44
|
-
position: 'relative',
|
|
45
|
-
},
|
|
46
|
-
|
|
47
|
-
mainContent: {
|
|
48
|
-
flex: 1,
|
|
49
|
-
},
|
|
50
|
-
|
|
51
|
-
contentArea: {
|
|
52
|
-
flex: 1,
|
|
53
|
-
},
|
|
54
|
-
|
|
55
|
-
tabBarBottom: {
|
|
56
|
-
flexDirection: 'row',
|
|
57
|
-
backgroundColor: theme.colors.surface,
|
|
58
|
-
borderTopWidth: 1,
|
|
59
|
-
borderTopColor: theme.colors.border,
|
|
60
|
-
paddingTop: 6,
|
|
61
|
-
paddingHorizontal: 0,
|
|
62
|
-
web: {
|
|
63
|
-
backgroundColor: '#ffffff', // Light background for web
|
|
64
|
-
borderTopColor: '#e0e0e0', // Light border for web
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
|
|
68
|
-
tabButton: {
|
|
69
|
-
flex: 1,
|
|
70
|
-
alignItems: 'center',
|
|
71
|
-
justifyContent: 'center',
|
|
72
|
-
paddingVertical: 6,
|
|
73
|
-
paddingHorizontal: 4,
|
|
74
|
-
minHeight: 49,
|
|
75
|
-
},
|
|
76
|
-
|
|
77
|
-
tabButtonHeader: {
|
|
78
|
-
flex: 0,
|
|
79
|
-
flexDirection: 'row',
|
|
80
|
-
alignItems: 'center',
|
|
81
|
-
justifyContent: 'center',
|
|
82
|
-
paddingVertical: theme.spacing?.xs,
|
|
83
|
-
paddingHorizontal: theme.spacing?.md,
|
|
84
|
-
borderRadius: theme.radius?.md,
|
|
85
|
-
minHeight: 36,
|
|
86
|
-
},
|
|
87
|
-
|
|
88
|
-
tabButtonActive: {
|
|
89
|
-
// Let native platform handle active state styling
|
|
90
|
-
},
|
|
91
|
-
|
|
92
|
-
tabButtonDisabled: {
|
|
93
|
-
opacity: 0.5,
|
|
94
|
-
},
|
|
95
|
-
|
|
96
|
-
tabIconContainer: {
|
|
97
|
-
alignItems: 'center',
|
|
98
|
-
justifyContent: 'center',
|
|
99
|
-
},
|
|
100
|
-
|
|
101
|
-
tabIcon: {
|
|
102
|
-
width: 24,
|
|
103
|
-
height: 24,
|
|
104
|
-
},
|
|
105
|
-
|
|
106
|
-
tabLabel: {
|
|
107
|
-
fontSize: 10,
|
|
108
|
-
marginTop: 2,
|
|
109
|
-
color: theme.colors.onSurface,
|
|
110
|
-
textAlign: 'center',
|
|
111
|
-
},
|
|
112
|
-
|
|
113
|
-
tabLabelHeader: {
|
|
114
|
-
fontSize: 14,
|
|
115
|
-
marginLeft: theme.spacing?.xs,
|
|
116
|
-
color: theme.colors.onSurface,
|
|
117
|
-
},
|
|
118
|
-
|
|
119
|
-
tabLabelActive: {
|
|
120
|
-
color: theme.colors.primary,
|
|
121
|
-
fontWeight: '600',
|
|
122
|
-
},
|
|
123
|
-
|
|
124
|
-
tabBadge: {
|
|
125
|
-
position: 'absolute',
|
|
126
|
-
top: -4,
|
|
127
|
-
right: -8,
|
|
128
|
-
backgroundColor: theme.colors.error,
|
|
129
|
-
borderRadius: 10,
|
|
130
|
-
minWidth: 16,
|
|
131
|
-
height: 16,
|
|
132
|
-
alignItems: 'center',
|
|
133
|
-
justifyContent: 'center',
|
|
134
|
-
paddingHorizontal: 4,
|
|
135
|
-
},
|
|
136
|
-
|
|
137
|
-
tabBadgeText: {
|
|
138
|
-
color: theme.colors.onError,
|
|
139
|
-
fontSize: 10,
|
|
140
|
-
fontWeight: 'bold',
|
|
141
|
-
},
|
|
142
|
-
}));
|