@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.
@@ -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
- }));