@idealyst/navigation 1.0.24 → 1.0.26
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 +50 -50
- package/src/context/NavigatorContext.web.tsx +36 -36
- package/src/context/index.native.ts +1 -1
- package/src/context/index.ts +1 -1
- package/src/context/index.web.ts +1 -1
- package/src/context/types.ts +12 -12
- package/src/examples/ExampleDrawerRouter.tsx +158 -158
- package/src/examples/ExampleStackRouter.tsx +244 -244
- package/src/examples/ExampleTabRouter.tsx +156 -156
- package/src/examples/highContrastThemes.ts +582 -582
- package/src/examples/index.ts +2 -2
- package/src/examples/unistyles.ts +83 -83
- package/src/index.ts +4 -4
- package/src/layouts/GeneralLayout/GeneralLayout.styles.ts +55 -55
- package/src/layouts/GeneralLayout/GeneralLayout.tsx +144 -144
- package/src/layouts/GeneralLayout/index.ts +2 -2
- package/src/layouts/GeneralLayout/types.ts +98 -98
- package/src/routing/index.native.tsx +1 -1
- package/src/routing/index.ts +1 -1
- package/src/routing/index.web.tsx +1 -1
- package/src/routing/router.native.tsx +89 -89
- package/src/routing/router.web.tsx +73 -73
- package/src/routing/types.ts +14 -14
package/src/examples/index.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { default as ExampleStackRouter } from './ExampleStackRouter';
|
|
2
|
-
export { default as ExampleTabRouter } from './ExampleTabRouter';
|
|
1
|
+
export { default as ExampleStackRouter } from './ExampleStackRouter';
|
|
2
|
+
export { default as ExampleTabRouter } from './ExampleTabRouter';
|
|
3
3
|
export { default as ExampleDrawerRouter } from './ExampleDrawerRouter';
|
|
@@ -1,84 +1,84 @@
|
|
|
1
|
-
import { breakpoints, defaultLightTheme, defaultDarkTheme } from '@idealyst/theme';
|
|
2
|
-
import { highContrastThemes } from './highContrastThemes';
|
|
3
|
-
import { StyleSheet } from 'react-native-unistyles';
|
|
4
|
-
|
|
5
|
-
// Extend UnistylesThemes to include high contrast themes
|
|
6
|
-
// This overrides the more limited declaration from the components package
|
|
7
|
-
declare module 'react-native-unistyles' {
|
|
8
|
-
export interface UnistylesThemes {
|
|
9
|
-
light: typeof defaultLightTheme;
|
|
10
|
-
dark: typeof defaultDarkTheme;
|
|
11
|
-
lightHighContrast: typeof highContrastThemes.lightHighContrast;
|
|
12
|
-
darkHighContrast: typeof highContrastThemes.darkHighContrast;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// Configure with all themes, including high contrast variants
|
|
17
|
-
// This will override any previous configuration
|
|
18
|
-
StyleSheet.configure({
|
|
19
|
-
themes: {
|
|
20
|
-
light: defaultLightTheme,
|
|
21
|
-
dark: defaultDarkTheme,
|
|
22
|
-
lightHighContrast: highContrastThemes.lightHighContrast,
|
|
23
|
-
darkHighContrast: highContrastThemes.darkHighContrast,
|
|
24
|
-
},
|
|
25
|
-
settings: {
|
|
26
|
-
initialTheme: 'light',
|
|
27
|
-
},
|
|
28
|
-
breakpoints,
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
// Export theme names for easy reference
|
|
32
|
-
export const availableThemes = [
|
|
33
|
-
'light',
|
|
34
|
-
'dark',
|
|
35
|
-
'lightHighContrast',
|
|
36
|
-
'darkHighContrast'
|
|
37
|
-
] as const;
|
|
38
|
-
|
|
39
|
-
export type AvailableTheme = typeof availableThemes[number];
|
|
40
|
-
|
|
41
|
-
// Helper function to get next theme in rotation
|
|
42
|
-
export function getNextTheme(currentTheme: string): AvailableTheme {
|
|
43
|
-
const currentIndex = availableThemes.indexOf(currentTheme as AvailableTheme);
|
|
44
|
-
const nextIndex = (currentIndex + 1) % availableThemes.length;
|
|
45
|
-
return availableThemes[nextIndex];
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Helper function to get theme display name
|
|
49
|
-
export function getThemeDisplayName(theme: string): string {
|
|
50
|
-
switch (theme) {
|
|
51
|
-
case 'light':
|
|
52
|
-
return 'Light';
|
|
53
|
-
case 'dark':
|
|
54
|
-
return 'Dark';
|
|
55
|
-
case 'lightHighContrast':
|
|
56
|
-
return 'Light High Contrast';
|
|
57
|
-
case 'darkHighContrast':
|
|
58
|
-
return 'Dark High Contrast';
|
|
59
|
-
default:
|
|
60
|
-
return theme;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Helper function to check if theme is high contrast
|
|
65
|
-
export function isHighContrastTheme(theme: string): boolean {
|
|
66
|
-
return theme.includes('HighContrast');
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Helper function to get matching theme mode
|
|
70
|
-
export function getThemeMode(theme: string): 'light' | 'dark' {
|
|
71
|
-
return theme.includes('dark') ? 'dark' : 'light';
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Helper function to get high contrast variant of current theme
|
|
75
|
-
export function getHighContrastVariant(theme: string): AvailableTheme {
|
|
76
|
-
const mode = getThemeMode(theme);
|
|
77
|
-
return mode === 'dark' ? 'darkHighContrast' : 'lightHighContrast';
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Helper function to get standard variant of current theme
|
|
81
|
-
export function getStandardVariant(theme: string): AvailableTheme {
|
|
82
|
-
const mode = getThemeMode(theme);
|
|
83
|
-
return mode === 'dark' ? 'dark' : 'light';
|
|
1
|
+
import { breakpoints, defaultLightTheme, defaultDarkTheme } from '@idealyst/theme';
|
|
2
|
+
import { highContrastThemes } from './highContrastThemes';
|
|
3
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
4
|
+
|
|
5
|
+
// Extend UnistylesThemes to include high contrast themes
|
|
6
|
+
// This overrides the more limited declaration from the components package
|
|
7
|
+
declare module 'react-native-unistyles' {
|
|
8
|
+
export interface UnistylesThemes {
|
|
9
|
+
light: typeof defaultLightTheme;
|
|
10
|
+
dark: typeof defaultDarkTheme;
|
|
11
|
+
lightHighContrast: typeof highContrastThemes.lightHighContrast;
|
|
12
|
+
darkHighContrast: typeof highContrastThemes.darkHighContrast;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Configure with all themes, including high contrast variants
|
|
17
|
+
// This will override any previous configuration
|
|
18
|
+
StyleSheet.configure({
|
|
19
|
+
themes: {
|
|
20
|
+
light: defaultLightTheme,
|
|
21
|
+
dark: defaultDarkTheme,
|
|
22
|
+
lightHighContrast: highContrastThemes.lightHighContrast,
|
|
23
|
+
darkHighContrast: highContrastThemes.darkHighContrast,
|
|
24
|
+
},
|
|
25
|
+
settings: {
|
|
26
|
+
initialTheme: 'light',
|
|
27
|
+
},
|
|
28
|
+
breakpoints,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Export theme names for easy reference
|
|
32
|
+
export const availableThemes = [
|
|
33
|
+
'light',
|
|
34
|
+
'dark',
|
|
35
|
+
'lightHighContrast',
|
|
36
|
+
'darkHighContrast'
|
|
37
|
+
] as const;
|
|
38
|
+
|
|
39
|
+
export type AvailableTheme = typeof availableThemes[number];
|
|
40
|
+
|
|
41
|
+
// Helper function to get next theme in rotation
|
|
42
|
+
export function getNextTheme(currentTheme: string): AvailableTheme {
|
|
43
|
+
const currentIndex = availableThemes.indexOf(currentTheme as AvailableTheme);
|
|
44
|
+
const nextIndex = (currentIndex + 1) % availableThemes.length;
|
|
45
|
+
return availableThemes[nextIndex];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Helper function to get theme display name
|
|
49
|
+
export function getThemeDisplayName(theme: string): string {
|
|
50
|
+
switch (theme) {
|
|
51
|
+
case 'light':
|
|
52
|
+
return 'Light';
|
|
53
|
+
case 'dark':
|
|
54
|
+
return 'Dark';
|
|
55
|
+
case 'lightHighContrast':
|
|
56
|
+
return 'Light High Contrast';
|
|
57
|
+
case 'darkHighContrast':
|
|
58
|
+
return 'Dark High Contrast';
|
|
59
|
+
default:
|
|
60
|
+
return theme;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Helper function to check if theme is high contrast
|
|
65
|
+
export function isHighContrastTheme(theme: string): boolean {
|
|
66
|
+
return theme.includes('HighContrast');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Helper function to get matching theme mode
|
|
70
|
+
export function getThemeMode(theme: string): 'light' | 'dark' {
|
|
71
|
+
return theme.includes('dark') ? 'dark' : 'light';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Helper function to get high contrast variant of current theme
|
|
75
|
+
export function getHighContrastVariant(theme: string): AvailableTheme {
|
|
76
|
+
const mode = getThemeMode(theme);
|
|
77
|
+
return mode === 'dark' ? 'darkHighContrast' : 'lightHighContrast';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Helper function to get standard variant of current theme
|
|
81
|
+
export function getStandardVariant(theme: string): AvailableTheme {
|
|
82
|
+
const mode = getThemeMode(theme);
|
|
83
|
+
return mode === 'dark' ? 'dark' : 'light';
|
|
84
84
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// Web-specific exports
|
|
2
|
-
export * from './context';
|
|
3
|
-
|
|
4
|
-
// Layout components
|
|
1
|
+
// Web-specific exports
|
|
2
|
+
export * from './context';
|
|
3
|
+
|
|
4
|
+
// Layout components
|
|
5
5
|
export * from './layouts';
|
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
// Simple style objects for the GeneralLayout
|
|
2
|
-
export const generalLayoutStyles = {
|
|
3
|
-
container: {
|
|
4
|
-
display: 'flex',
|
|
5
|
-
width: '100%',
|
|
6
|
-
height: '100vh',
|
|
7
|
-
overflow: 'hidden',
|
|
8
|
-
} as const,
|
|
9
|
-
|
|
10
|
-
headerContainer: {
|
|
11
|
-
display: 'flex',
|
|
12
|
-
flexDirection: 'row',
|
|
13
|
-
width: '100%',
|
|
14
|
-
zIndex: 100,
|
|
15
|
-
} as const,
|
|
16
|
-
|
|
17
|
-
bodyContainer: {
|
|
18
|
-
display: 'flex',
|
|
19
|
-
flexDirection: 'row',
|
|
20
|
-
flex: 1,
|
|
21
|
-
overflow: 'hidden',
|
|
22
|
-
} as const,
|
|
23
|
-
|
|
24
|
-
sidebar: {
|
|
25
|
-
display: 'flex',
|
|
26
|
-
flexDirection: 'column',
|
|
27
|
-
transition: 'width 0.3s ease-in-out',
|
|
28
|
-
overflow: 'hidden',
|
|
29
|
-
zIndex: 50,
|
|
30
|
-
} as const,
|
|
31
|
-
|
|
32
|
-
sidebarContent: {
|
|
33
|
-
flex: 1,
|
|
34
|
-
overflow: 'auto',
|
|
35
|
-
} as const,
|
|
36
|
-
|
|
37
|
-
sidebarToggle: {
|
|
38
|
-
alignSelf: 'flex-end',
|
|
39
|
-
margin: '8px',
|
|
40
|
-
marginBottom: '16px',
|
|
41
|
-
} as const,
|
|
42
|
-
|
|
43
|
-
mainContent: {
|
|
44
|
-
flex: 1,
|
|
45
|
-
display: 'flex',
|
|
46
|
-
flexDirection: 'column',
|
|
47
|
-
overflow: 'auto',
|
|
48
|
-
order: 2,
|
|
49
|
-
} as const,
|
|
50
|
-
|
|
51
|
-
contentArea: {
|
|
52
|
-
flex: 1,
|
|
53
|
-
overflow: 'auto',
|
|
54
|
-
} as const,
|
|
55
|
-
};
|
|
1
|
+
// Simple style objects for the GeneralLayout
|
|
2
|
+
export const generalLayoutStyles = {
|
|
3
|
+
container: {
|
|
4
|
+
display: 'flex',
|
|
5
|
+
width: '100%',
|
|
6
|
+
height: '100vh',
|
|
7
|
+
overflow: 'hidden',
|
|
8
|
+
} as const,
|
|
9
|
+
|
|
10
|
+
headerContainer: {
|
|
11
|
+
display: 'flex',
|
|
12
|
+
flexDirection: 'row',
|
|
13
|
+
width: '100%',
|
|
14
|
+
zIndex: 100,
|
|
15
|
+
} as const,
|
|
16
|
+
|
|
17
|
+
bodyContainer: {
|
|
18
|
+
display: 'flex',
|
|
19
|
+
flexDirection: 'row',
|
|
20
|
+
flex: 1,
|
|
21
|
+
overflow: 'hidden',
|
|
22
|
+
} as const,
|
|
23
|
+
|
|
24
|
+
sidebar: {
|
|
25
|
+
display: 'flex',
|
|
26
|
+
flexDirection: 'column',
|
|
27
|
+
transition: 'width 0.3s ease-in-out',
|
|
28
|
+
overflow: 'hidden',
|
|
29
|
+
zIndex: 50,
|
|
30
|
+
} as const,
|
|
31
|
+
|
|
32
|
+
sidebarContent: {
|
|
33
|
+
flex: 1,
|
|
34
|
+
overflow: 'auto',
|
|
35
|
+
} as const,
|
|
36
|
+
|
|
37
|
+
sidebarToggle: {
|
|
38
|
+
alignSelf: 'flex-end',
|
|
39
|
+
margin: '8px',
|
|
40
|
+
marginBottom: '16px',
|
|
41
|
+
} as const,
|
|
42
|
+
|
|
43
|
+
mainContent: {
|
|
44
|
+
flex: 1,
|
|
45
|
+
display: 'flex',
|
|
46
|
+
flexDirection: 'column',
|
|
47
|
+
overflow: 'auto',
|
|
48
|
+
order: 2,
|
|
49
|
+
} as const,
|
|
50
|
+
|
|
51
|
+
contentArea: {
|
|
52
|
+
flex: 1,
|
|
53
|
+
overflow: 'auto',
|
|
54
|
+
} as const,
|
|
55
|
+
};
|
|
@@ -1,144 +1,144 @@
|
|
|
1
|
-
import React, { useState, useCallback } from 'react';
|
|
2
|
-
import { View, Button, Text } from '@idealyst/components';
|
|
3
|
-
import { GeneralLayoutProps, SidebarConfig, HeaderConfig } from './types';
|
|
4
|
-
import { generalLayoutStyles } from './GeneralLayout.styles';
|
|
5
|
-
|
|
6
|
-
const GeneralLayout: React.FC<GeneralLayoutProps> = ({
|
|
7
|
-
children,
|
|
8
|
-
sidebar = {},
|
|
9
|
-
header = {},
|
|
10
|
-
style,
|
|
11
|
-
testID,
|
|
12
|
-
}) => {
|
|
13
|
-
// Default sidebar configuration
|
|
14
|
-
const sidebarConfig: Required<SidebarConfig> = {
|
|
15
|
-
enabled: true,
|
|
16
|
-
initiallyExpanded: true,
|
|
17
|
-
expandedWidth: 280,
|
|
18
|
-
collapsedWidth: 60,
|
|
19
|
-
collapsible: true,
|
|
20
|
-
position: 'left',
|
|
21
|
-
content: null,
|
|
22
|
-
style: undefined,
|
|
23
|
-
...sidebar,
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
// Default header configuration
|
|
27
|
-
const headerConfig: Required<HeaderConfig> = {
|
|
28
|
-
enabled: true,
|
|
29
|
-
height: 64,
|
|
30
|
-
content: null,
|
|
31
|
-
style: undefined,
|
|
32
|
-
...header,
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
// State for sidebar expansion
|
|
36
|
-
const [isSidebarExpanded, setIsSidebarExpanded] = useState(
|
|
37
|
-
sidebarConfig.initiallyExpanded
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
// Toggle sidebar expansion
|
|
41
|
-
const toggleSidebar = useCallback(() => {
|
|
42
|
-
if (sidebarConfig.collapsible) {
|
|
43
|
-
setIsSidebarExpanded((prev) => !prev);
|
|
44
|
-
}
|
|
45
|
-
}, [sidebarConfig.collapsible]);
|
|
46
|
-
|
|
47
|
-
// Calculate sidebar width based on expanded state
|
|
48
|
-
const sidebarWidth = isSidebarExpanded
|
|
49
|
-
? sidebarConfig.expandedWidth
|
|
50
|
-
: sidebarConfig.collapsedWidth;
|
|
51
|
-
|
|
52
|
-
// Create dynamic styles for sidebar width
|
|
53
|
-
const sidebarDynamicStyles = {
|
|
54
|
-
width: sidebarWidth,
|
|
55
|
-
minWidth: sidebarWidth,
|
|
56
|
-
maxWidth: sidebarWidth,
|
|
57
|
-
order: sidebarConfig.position === 'right' ? 3 : 1,
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
// Create dynamic styles for header height
|
|
61
|
-
const headerDynamicStyles = {
|
|
62
|
-
height: headerConfig.height,
|
|
63
|
-
minHeight: headerConfig.height,
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
return (
|
|
67
|
-
<View
|
|
68
|
-
background="transparent"
|
|
69
|
-
style={[
|
|
70
|
-
generalLayoutStyles.container,
|
|
71
|
-
style,
|
|
72
|
-
]}
|
|
73
|
-
testID={testID}
|
|
74
|
-
>
|
|
75
|
-
{/* Header */}
|
|
76
|
-
{headerConfig.enabled && (
|
|
77
|
-
<View
|
|
78
|
-
background="surface"
|
|
79
|
-
border="thin"
|
|
80
|
-
spacing="md"
|
|
81
|
-
style={[
|
|
82
|
-
generalLayoutStyles.headerContainer,
|
|
83
|
-
headerDynamicStyles,
|
|
84
|
-
headerConfig.style,
|
|
85
|
-
]}
|
|
86
|
-
>
|
|
87
|
-
{headerConfig.content}
|
|
88
|
-
</View>
|
|
89
|
-
)}
|
|
90
|
-
|
|
91
|
-
{/* Body Container */}
|
|
92
|
-
<View style={generalLayoutStyles.bodyContainer}>
|
|
93
|
-
{/* Sidebar */}
|
|
94
|
-
{sidebarConfig.enabled && (
|
|
95
|
-
<View
|
|
96
|
-
background="surface"
|
|
97
|
-
border="thin"
|
|
98
|
-
spacing="md"
|
|
99
|
-
style={[
|
|
100
|
-
generalLayoutStyles.sidebar,
|
|
101
|
-
sidebarDynamicStyles,
|
|
102
|
-
sidebarConfig.style,
|
|
103
|
-
]}
|
|
104
|
-
>
|
|
105
|
-
{/* Sidebar Toggle Button - Positioned within sidebar using flexbox */}
|
|
106
|
-
{sidebarConfig.collapsible && (
|
|
107
|
-
<Button
|
|
108
|
-
onPress={toggleSidebar}
|
|
109
|
-
variant="outlined"
|
|
110
|
-
size="small"
|
|
111
|
-
style={[
|
|
112
|
-
generalLayoutStyles.sidebarToggle,
|
|
113
|
-
// Align toggle button based on sidebar position
|
|
114
|
-
{ alignSelf: sidebarConfig.position === 'right' ? 'flex-start' : 'flex-end' }
|
|
115
|
-
]}
|
|
116
|
-
>
|
|
117
|
-
{sidebarConfig.position === 'right'
|
|
118
|
-
? (isSidebarExpanded ? '→' : '←')
|
|
119
|
-
: (isSidebarExpanded ? '←' : '→')
|
|
120
|
-
}
|
|
121
|
-
</Button>
|
|
122
|
-
)}
|
|
123
|
-
|
|
124
|
-
{/* Sidebar Content */}
|
|
125
|
-
<View style={generalLayoutStyles.sidebarContent}>
|
|
126
|
-
{sidebarConfig.content}
|
|
127
|
-
</View>
|
|
128
|
-
</View>
|
|
129
|
-
)}
|
|
130
|
-
|
|
131
|
-
{/* Main Content Area */}
|
|
132
|
-
<View style={generalLayoutStyles.mainContent}>
|
|
133
|
-
<View
|
|
134
|
-
style={generalLayoutStyles.contentArea}
|
|
135
|
-
>
|
|
136
|
-
{children}
|
|
137
|
-
</View>
|
|
138
|
-
</View>
|
|
139
|
-
</View>
|
|
140
|
-
</View>
|
|
141
|
-
);
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
export default GeneralLayout;
|
|
1
|
+
import React, { useState, useCallback } from 'react';
|
|
2
|
+
import { View, Button, Text } from '@idealyst/components';
|
|
3
|
+
import { GeneralLayoutProps, SidebarConfig, HeaderConfig } from './types';
|
|
4
|
+
import { generalLayoutStyles } from './GeneralLayout.styles';
|
|
5
|
+
|
|
6
|
+
const GeneralLayout: React.FC<GeneralLayoutProps> = ({
|
|
7
|
+
children,
|
|
8
|
+
sidebar = {},
|
|
9
|
+
header = {},
|
|
10
|
+
style,
|
|
11
|
+
testID,
|
|
12
|
+
}) => {
|
|
13
|
+
// Default sidebar configuration
|
|
14
|
+
const sidebarConfig: Required<SidebarConfig> = {
|
|
15
|
+
enabled: true,
|
|
16
|
+
initiallyExpanded: true,
|
|
17
|
+
expandedWidth: 280,
|
|
18
|
+
collapsedWidth: 60,
|
|
19
|
+
collapsible: true,
|
|
20
|
+
position: 'left',
|
|
21
|
+
content: null,
|
|
22
|
+
style: undefined,
|
|
23
|
+
...sidebar,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// Default header configuration
|
|
27
|
+
const headerConfig: Required<HeaderConfig> = {
|
|
28
|
+
enabled: true,
|
|
29
|
+
height: 64,
|
|
30
|
+
content: null,
|
|
31
|
+
style: undefined,
|
|
32
|
+
...header,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// State for sidebar expansion
|
|
36
|
+
const [isSidebarExpanded, setIsSidebarExpanded] = useState(
|
|
37
|
+
sidebarConfig.initiallyExpanded
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
// Toggle sidebar expansion
|
|
41
|
+
const toggleSidebar = useCallback(() => {
|
|
42
|
+
if (sidebarConfig.collapsible) {
|
|
43
|
+
setIsSidebarExpanded((prev) => !prev);
|
|
44
|
+
}
|
|
45
|
+
}, [sidebarConfig.collapsible]);
|
|
46
|
+
|
|
47
|
+
// Calculate sidebar width based on expanded state
|
|
48
|
+
const sidebarWidth = isSidebarExpanded
|
|
49
|
+
? sidebarConfig.expandedWidth
|
|
50
|
+
: sidebarConfig.collapsedWidth;
|
|
51
|
+
|
|
52
|
+
// Create dynamic styles for sidebar width
|
|
53
|
+
const sidebarDynamicStyles = {
|
|
54
|
+
width: sidebarWidth,
|
|
55
|
+
minWidth: sidebarWidth,
|
|
56
|
+
maxWidth: sidebarWidth,
|
|
57
|
+
order: sidebarConfig.position === 'right' ? 3 : 1,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Create dynamic styles for header height
|
|
61
|
+
const headerDynamicStyles = {
|
|
62
|
+
height: headerConfig.height,
|
|
63
|
+
minHeight: headerConfig.height,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<View
|
|
68
|
+
background="transparent"
|
|
69
|
+
style={[
|
|
70
|
+
generalLayoutStyles.container,
|
|
71
|
+
style,
|
|
72
|
+
]}
|
|
73
|
+
testID={testID}
|
|
74
|
+
>
|
|
75
|
+
{/* Header */}
|
|
76
|
+
{headerConfig.enabled && (
|
|
77
|
+
<View
|
|
78
|
+
background="surface"
|
|
79
|
+
border="thin"
|
|
80
|
+
spacing="md"
|
|
81
|
+
style={[
|
|
82
|
+
generalLayoutStyles.headerContainer,
|
|
83
|
+
headerDynamicStyles,
|
|
84
|
+
headerConfig.style,
|
|
85
|
+
]}
|
|
86
|
+
>
|
|
87
|
+
{headerConfig.content}
|
|
88
|
+
</View>
|
|
89
|
+
)}
|
|
90
|
+
|
|
91
|
+
{/* Body Container */}
|
|
92
|
+
<View style={generalLayoutStyles.bodyContainer}>
|
|
93
|
+
{/* Sidebar */}
|
|
94
|
+
{sidebarConfig.enabled && (
|
|
95
|
+
<View
|
|
96
|
+
background="surface"
|
|
97
|
+
border="thin"
|
|
98
|
+
spacing="md"
|
|
99
|
+
style={[
|
|
100
|
+
generalLayoutStyles.sidebar,
|
|
101
|
+
sidebarDynamicStyles,
|
|
102
|
+
sidebarConfig.style,
|
|
103
|
+
]}
|
|
104
|
+
>
|
|
105
|
+
{/* Sidebar Toggle Button - Positioned within sidebar using flexbox */}
|
|
106
|
+
{sidebarConfig.collapsible && (
|
|
107
|
+
<Button
|
|
108
|
+
onPress={toggleSidebar}
|
|
109
|
+
variant="outlined"
|
|
110
|
+
size="small"
|
|
111
|
+
style={[
|
|
112
|
+
generalLayoutStyles.sidebarToggle,
|
|
113
|
+
// Align toggle button based on sidebar position
|
|
114
|
+
{ alignSelf: sidebarConfig.position === 'right' ? 'flex-start' : 'flex-end' }
|
|
115
|
+
]}
|
|
116
|
+
>
|
|
117
|
+
{sidebarConfig.position === 'right'
|
|
118
|
+
? (isSidebarExpanded ? '→' : '←')
|
|
119
|
+
: (isSidebarExpanded ? '←' : '→')
|
|
120
|
+
}
|
|
121
|
+
</Button>
|
|
122
|
+
)}
|
|
123
|
+
|
|
124
|
+
{/* Sidebar Content */}
|
|
125
|
+
<View style={generalLayoutStyles.sidebarContent}>
|
|
126
|
+
{sidebarConfig.content}
|
|
127
|
+
</View>
|
|
128
|
+
</View>
|
|
129
|
+
)}
|
|
130
|
+
|
|
131
|
+
{/* Main Content Area */}
|
|
132
|
+
<View style={generalLayoutStyles.mainContent}>
|
|
133
|
+
<View
|
|
134
|
+
style={generalLayoutStyles.contentArea}
|
|
135
|
+
>
|
|
136
|
+
{children}
|
|
137
|
+
</View>
|
|
138
|
+
</View>
|
|
139
|
+
</View>
|
|
140
|
+
</View>
|
|
141
|
+
);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export default GeneralLayout;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { default as GeneralLayout } from './GeneralLayout';
|
|
2
|
-
export type { GeneralLayoutProps, SidebarConfig, HeaderConfig } from './types';
|
|
1
|
+
export { default as GeneralLayout } from './GeneralLayout';
|
|
2
|
+
export type { GeneralLayoutProps, SidebarConfig, HeaderConfig } from './types';
|