@umituz/react-native-design-system 2.6.16 → 2.6.18
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 +1 -1
- package/src/device/index.ts +2 -0
- package/src/device/infrastructure/services/DeviceExtrasCollector.ts +86 -0
- package/src/index.ts +2 -0
- package/src/layouts/ScreenLayout/ScreenLayout.tsx +58 -28
- package/src/molecules/navigation/hooks/useTabBarStyles.ts +13 -5
- package/src/responsive/config.ts +9 -1
- package/src/responsive/index.ts +3 -0
- package/src/responsive/responsive.ts +3 -0
- package/src/responsive/responsiveLayout.ts +76 -4
- package/src/responsive/responsiveModal.ts +4 -4
- package/src/responsive/useResponsive.ts +11 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-design-system",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.18",
|
|
4
4
|
"description": "Universal design system for React Native apps - Consolidated package with atoms, molecules, organisms, theme, typography, responsive and safe area utilities",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
package/src/device/index.ts
CHANGED
|
@@ -74,6 +74,8 @@ export { DeviceService } from './infrastructure/services/DeviceService';
|
|
|
74
74
|
export { UserFriendlyIdService } from './infrastructure/services/UserFriendlyIdService';
|
|
75
75
|
import { PersistentDeviceIdService } from './infrastructure/services/PersistentDeviceIdService';
|
|
76
76
|
export { PersistentDeviceIdService };
|
|
77
|
+
export { collectDeviceExtras } from './infrastructure/services/DeviceExtrasCollector';
|
|
78
|
+
export type { DeviceExtras } from './infrastructure/services/DeviceExtrasCollector';
|
|
77
79
|
|
|
78
80
|
// ============================================================================
|
|
79
81
|
// PRESENTATION - Device hooks
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Device Extras Collector
|
|
3
|
+
*
|
|
4
|
+
* Collects device and application information for user documents.
|
|
5
|
+
* Used with @umituz/react-native-auth's UserDocumentService.
|
|
6
|
+
*
|
|
7
|
+
* @domain device
|
|
8
|
+
* @layer infrastructure/services
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import * as Localization from 'expo-localization';
|
|
12
|
+
import { DeviceInfoService } from './DeviceInfoService';
|
|
13
|
+
import { ApplicationInfoService } from './ApplicationInfoService';
|
|
14
|
+
import { PersistentDeviceIdService } from './PersistentDeviceIdService';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Device extras for user documents
|
|
18
|
+
* Compatible with UserDocumentExtras from @umituz/react-native-auth
|
|
19
|
+
*/
|
|
20
|
+
export interface DeviceExtras {
|
|
21
|
+
deviceId?: string;
|
|
22
|
+
platform?: string;
|
|
23
|
+
deviceModel?: string;
|
|
24
|
+
deviceBrand?: string;
|
|
25
|
+
osVersion?: string;
|
|
26
|
+
appVersion?: string;
|
|
27
|
+
buildNumber?: string;
|
|
28
|
+
locale?: string;
|
|
29
|
+
timezone?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get device locale code
|
|
34
|
+
*/
|
|
35
|
+
function getDeviceLocale(): string | undefined {
|
|
36
|
+
try {
|
|
37
|
+
const locales = Localization.getLocales();
|
|
38
|
+
if (locales && locales.length > 0) {
|
|
39
|
+
const locale = locales[0];
|
|
40
|
+
return locale.languageTag || undefined;
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
} catch {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Collect device extras for user documents
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* import { collectDeviceExtras } from '@umituz/react-native-design-system';
|
|
54
|
+
* import { initializeAuth } from '@umituz/react-native-auth';
|
|
55
|
+
*
|
|
56
|
+
* await initializeAuth({
|
|
57
|
+
* userCollection: 'users',
|
|
58
|
+
* collectExtras: collectDeviceExtras,
|
|
59
|
+
* });
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export async function collectDeviceExtras(): Promise<DeviceExtras> {
|
|
63
|
+
try {
|
|
64
|
+
const [deviceInfo, appInfo, deviceId] = await Promise.all([
|
|
65
|
+
DeviceInfoService.getDeviceInfo(),
|
|
66
|
+
ApplicationInfoService.getApplicationInfo(),
|
|
67
|
+
PersistentDeviceIdService.getDeviceId(),
|
|
68
|
+
]);
|
|
69
|
+
|
|
70
|
+
const locale = getDeviceLocale();
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
deviceId,
|
|
74
|
+
platform: deviceInfo.platform,
|
|
75
|
+
deviceModel: deviceInfo.modelName || undefined,
|
|
76
|
+
deviceBrand: deviceInfo.brand || undefined,
|
|
77
|
+
osVersion: deviceInfo.osVersion || undefined,
|
|
78
|
+
appVersion: appInfo.nativeApplicationVersion || undefined,
|
|
79
|
+
buildNumber: appInfo.nativeBuildVersion || undefined,
|
|
80
|
+
locale,
|
|
81
|
+
timezone: deviceInfo.timezone || undefined,
|
|
82
|
+
};
|
|
83
|
+
} catch {
|
|
84
|
+
return {};
|
|
85
|
+
}
|
|
86
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -166,11 +166,13 @@ export {
|
|
|
166
166
|
useDeviceId,
|
|
167
167
|
useAnonymousUser,
|
|
168
168
|
getAnonymousUserId,
|
|
169
|
+
collectDeviceExtras,
|
|
169
170
|
type DeviceInfo,
|
|
170
171
|
type ApplicationInfo,
|
|
171
172
|
type SystemInfo,
|
|
172
173
|
type AnonymousUser,
|
|
173
174
|
type UseAnonymousUserOptions,
|
|
175
|
+
type DeviceExtras,
|
|
174
176
|
} from './device';
|
|
175
177
|
|
|
176
178
|
// =============================================================================
|
|
@@ -24,12 +24,11 @@
|
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
import React, { useMemo } from 'react';
|
|
27
|
-
import { View, ScrollView, StyleSheet, type ViewStyle, RefreshControlProps } from 'react-native';
|
|
27
|
+
import { View, ScrollView, StyleSheet, KeyboardAvoidingView, type ViewStyle, type RefreshControlProps } from 'react-native';
|
|
28
28
|
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
29
29
|
import type { Edge } from 'react-native-safe-area-context';
|
|
30
30
|
import { useAppDesignTokens } from '../../theme';
|
|
31
|
-
import {
|
|
32
|
-
import { isTablet as checkIsTablet } from '../../device/detection';
|
|
31
|
+
import { getScreenLayoutConfig } from '../../responsive/responsiveLayout';
|
|
33
32
|
|
|
34
33
|
/**
|
|
35
34
|
* NOTE: This component now works in conjunction with the SafeAreaProvider
|
|
@@ -161,16 +160,25 @@ export const ScreenLayout: React.FC<ScreenLayoutProps> = ({
|
|
|
161
160
|
// Automatically uses current theme from global store
|
|
162
161
|
const tokens = useAppDesignTokens();
|
|
163
162
|
const insets = useSafeAreaInsets();
|
|
164
|
-
const isTabletDevice = checkIsTablet();
|
|
165
163
|
|
|
166
|
-
//
|
|
167
|
-
const
|
|
168
|
-
|
|
164
|
+
// Get all responsive layout values from centralized config
|
|
165
|
+
const layoutConfig = useMemo(
|
|
166
|
+
() => getScreenLayoutConfig(insets),
|
|
167
|
+
[insets]
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
// Use provided maxWidth or responsive default
|
|
171
|
+
const finalMaxWidth = maxWidth || (responsiveEnabled ? layoutConfig.maxContentWidth : undefined);
|
|
172
|
+
const horizontalPadding = responsiveEnabled ? layoutConfig.horizontalPadding : tokens.spacing.md;
|
|
173
|
+
const verticalPadding = responsiveEnabled ? layoutConfig.verticalPadding : tokens.spacing.lg;
|
|
169
174
|
|
|
170
175
|
const styles = useMemo(() => StyleSheet.create({
|
|
171
176
|
container: {
|
|
172
177
|
flex: 1,
|
|
173
178
|
},
|
|
179
|
+
keyboardAvoidingView: {
|
|
180
|
+
flex: 1,
|
|
181
|
+
},
|
|
174
182
|
responsiveWrapper: {
|
|
175
183
|
flex: 1,
|
|
176
184
|
width: '100%',
|
|
@@ -178,6 +186,7 @@ export const ScreenLayout: React.FC<ScreenLayoutProps> = ({
|
|
|
178
186
|
},
|
|
179
187
|
content: {
|
|
180
188
|
flex: 1,
|
|
189
|
+
paddingTop: verticalPadding,
|
|
181
190
|
paddingHorizontal: horizontalPadding,
|
|
182
191
|
},
|
|
183
192
|
scrollView: {
|
|
@@ -185,13 +194,30 @@ export const ScreenLayout: React.FC<ScreenLayoutProps> = ({
|
|
|
185
194
|
},
|
|
186
195
|
scrollContent: {
|
|
187
196
|
flexGrow: 1,
|
|
197
|
+
paddingTop: verticalPadding,
|
|
188
198
|
paddingHorizontal: horizontalPadding,
|
|
189
|
-
paddingBottom:
|
|
199
|
+
paddingBottom: verticalPadding,
|
|
190
200
|
},
|
|
191
|
-
}), [tokens, finalMaxWidth, horizontalPadding]);
|
|
201
|
+
}), [tokens, finalMaxWidth, horizontalPadding, verticalPadding]);
|
|
192
202
|
|
|
193
203
|
const bgColor = backgroundColor || tokens.colors.backgroundPrimary;
|
|
194
204
|
|
|
205
|
+
// Content wrapper - optionally with KeyboardAvoidingView
|
|
206
|
+
// Uses 'padding' behavior which works consistently cross-platform
|
|
207
|
+
const ContentWrapper: React.FC<{ children: React.ReactNode }> = ({ children: wrapperChildren }) => {
|
|
208
|
+
if (keyboardAvoiding) {
|
|
209
|
+
return (
|
|
210
|
+
<KeyboardAvoidingView
|
|
211
|
+
style={styles.keyboardAvoidingView}
|
|
212
|
+
behavior="padding"
|
|
213
|
+
>
|
|
214
|
+
{wrapperChildren}
|
|
215
|
+
</KeyboardAvoidingView>
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
return <>{wrapperChildren}</>;
|
|
219
|
+
};
|
|
220
|
+
|
|
195
221
|
// Non-scrollable layout
|
|
196
222
|
if (!scrollable) {
|
|
197
223
|
return (
|
|
@@ -200,13 +226,15 @@ export const ScreenLayout: React.FC<ScreenLayoutProps> = ({
|
|
|
200
226
|
edges={edges}
|
|
201
227
|
testID={testID}
|
|
202
228
|
>
|
|
203
|
-
<
|
|
204
|
-
{
|
|
205
|
-
|
|
206
|
-
{
|
|
229
|
+
<ContentWrapper>
|
|
230
|
+
<View style={styles.responsiveWrapper}>
|
|
231
|
+
{header}
|
|
232
|
+
<View style={[styles.content, contentContainerStyle]}>
|
|
233
|
+
{children}
|
|
234
|
+
</View>
|
|
235
|
+
{footer}
|
|
207
236
|
</View>
|
|
208
|
-
|
|
209
|
-
</View>
|
|
237
|
+
</ContentWrapper>
|
|
210
238
|
</SafeAreaView>
|
|
211
239
|
);
|
|
212
240
|
}
|
|
@@ -218,19 +246,21 @@ export const ScreenLayout: React.FC<ScreenLayoutProps> = ({
|
|
|
218
246
|
edges={edges}
|
|
219
247
|
testID={testID}
|
|
220
248
|
>
|
|
221
|
-
<
|
|
222
|
-
{
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
249
|
+
<ContentWrapper>
|
|
250
|
+
<View style={styles.responsiveWrapper}>
|
|
251
|
+
{header}
|
|
252
|
+
<ScrollView
|
|
253
|
+
style={styles.scrollView}
|
|
254
|
+
contentContainerStyle={[styles.scrollContent, contentContainerStyle]}
|
|
255
|
+
showsVerticalScrollIndicator={!hideScrollIndicator}
|
|
256
|
+
keyboardShouldPersistTaps={keyboardAvoiding ? 'handled' : 'never'}
|
|
257
|
+
refreshControl={refreshControl}
|
|
258
|
+
>
|
|
259
|
+
{children}
|
|
260
|
+
</ScrollView>
|
|
261
|
+
{footer}
|
|
262
|
+
</View>
|
|
263
|
+
</ContentWrapper>
|
|
234
264
|
</SafeAreaView>
|
|
235
265
|
);
|
|
236
266
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Platform } from 'react-native';
|
|
2
1
|
import { useMemo } from 'react';
|
|
2
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
3
3
|
import { useAppDesignTokens } from '../../../theme';
|
|
4
|
+
import { getResponsiveTabBarConfig } from '../../../responsive/responsiveLayout';
|
|
4
5
|
|
|
5
6
|
export interface TabBarConfig {
|
|
6
7
|
backgroundColor?: string;
|
|
@@ -19,17 +20,24 @@ export interface TabBarConfig {
|
|
|
19
20
|
|
|
20
21
|
export function useTabBarStyles(config: TabBarConfig = {}) {
|
|
21
22
|
const tokens = useAppDesignTokens();
|
|
23
|
+
const insets = useSafeAreaInsets();
|
|
24
|
+
|
|
25
|
+
// Get responsive tab bar config based on device type and safe area
|
|
26
|
+
const responsiveConfig = useMemo(
|
|
27
|
+
() => getResponsiveTabBarConfig(insets),
|
|
28
|
+
[insets]
|
|
29
|
+
);
|
|
22
30
|
|
|
23
31
|
const tabBarStyle = useMemo(() => ({
|
|
24
32
|
backgroundColor: config.backgroundColor || tokens.colors.surface,
|
|
25
33
|
borderTopColor: config.borderTopColor || tokens.colors.borderLight,
|
|
26
34
|
borderTopWidth: config.borderTopWidth ?? 1,
|
|
27
|
-
paddingTop: config.paddingTop ??
|
|
28
|
-
paddingBottom: config.paddingBottom ??
|
|
29
|
-
minHeight: config.minHeight ??
|
|
35
|
+
paddingTop: config.paddingTop ?? responsiveConfig.paddingTop,
|
|
36
|
+
paddingBottom: config.paddingBottom ?? responsiveConfig.paddingBottom,
|
|
37
|
+
minHeight: config.minHeight ?? responsiveConfig.height,
|
|
30
38
|
}), [config.backgroundColor, config.borderTopColor, config.borderTopWidth,
|
|
31
39
|
config.paddingTop, config.paddingBottom, config.minHeight, tokens.colors.surface,
|
|
32
|
-
tokens.colors.borderLight]);
|
|
40
|
+
tokens.colors.borderLight, responsiveConfig]);
|
|
33
41
|
|
|
34
42
|
const screenOptions = useMemo(() => ({
|
|
35
43
|
headerShown: false,
|
package/src/responsive/config.ts
CHANGED
|
@@ -91,6 +91,11 @@ export const MODAL_CONFIG = {
|
|
|
91
91
|
HEIGHT_PERCENT_STANDARD: 0.78, // 78% of screen height for standard devices
|
|
92
92
|
HEIGHT_PERCENT_TABLET: 0.70, // 70% of screen height for tablets
|
|
93
93
|
|
|
94
|
+
// Min modal height percentages (for calculated min heights)
|
|
95
|
+
MIN_HEIGHT_PERCENT_SMALL: 0.40, // 40% of screen height for small devices
|
|
96
|
+
MIN_HEIGHT_PERCENT_STANDARD: 0.45, // 45% of screen height for standard devices
|
|
97
|
+
MIN_HEIGHT_PERCENT_TABLET: 0.35, // 35% of screen height for tablets
|
|
98
|
+
|
|
94
99
|
// Max width constraints
|
|
95
100
|
MAX_WIDTH_PHONE: 480, // Maximum modal width for phones
|
|
96
101
|
MAX_WIDTH_TABLET: 600, // Maximum modal width for tablets
|
|
@@ -121,9 +126,12 @@ export const LAYOUT_CONSTANTS = {
|
|
|
121
126
|
SPACING_MULTIPLIER_SMALL: 0.90, // 90% spacing for small devices
|
|
122
127
|
SPACING_MULTIPLIER_TABLET: 1.20, // 120% spacing for tablets
|
|
123
128
|
SPACING_MULTIPLIER_STANDARD: 1.0, // 100% spacing for standard devices
|
|
124
|
-
|
|
129
|
+
|
|
125
130
|
// Padding and margins
|
|
126
131
|
HORIZONTAL_PADDING_BASE: 16, // Base horizontal padding
|
|
132
|
+
VERTICAL_PADDING_SMALL: 12, // Vertical padding for small devices
|
|
133
|
+
VERTICAL_PADDING_STANDARD: 16, // Vertical padding for standard devices
|
|
134
|
+
VERTICAL_PADDING_TABLET: 24, // Vertical padding for tablets
|
|
127
135
|
BOTTOM_POSITION_BASE: 32, // Base bottom position
|
|
128
136
|
|
|
129
137
|
// Safe area offsets
|
package/src/responsive/index.ts
CHANGED
|
@@ -14,11 +14,14 @@ export {
|
|
|
14
14
|
getResponsiveLogoSize,
|
|
15
15
|
getResponsiveInputHeight,
|
|
16
16
|
getResponsiveHorizontalPadding,
|
|
17
|
+
getResponsiveVerticalPadding,
|
|
18
|
+
getScreenLayoutConfig,
|
|
17
19
|
getResponsiveBottomPosition,
|
|
18
20
|
getResponsiveFABPosition,
|
|
19
21
|
getResponsiveTabBarHeight,
|
|
20
22
|
getResponsiveTabBarConfig,
|
|
21
23
|
type ResponsiveTabBarConfig,
|
|
24
|
+
type ScreenLayoutConfig,
|
|
22
25
|
getResponsiveModalMaxHeight,
|
|
23
26
|
getResponsiveMinModalHeight,
|
|
24
27
|
getResponsiveModalWidth,
|
|
@@ -19,11 +19,14 @@ export {
|
|
|
19
19
|
// Responsive layout
|
|
20
20
|
export {
|
|
21
21
|
getResponsiveHorizontalPadding,
|
|
22
|
+
getResponsiveVerticalPadding,
|
|
23
|
+
getScreenLayoutConfig,
|
|
22
24
|
getResponsiveBottomPosition,
|
|
23
25
|
getResponsiveFABPosition,
|
|
24
26
|
getResponsiveTabBarHeight,
|
|
25
27
|
getResponsiveTabBarConfig,
|
|
26
28
|
type ResponsiveTabBarConfig,
|
|
29
|
+
type ScreenLayoutConfig,
|
|
27
30
|
} from './responsiveLayout';
|
|
28
31
|
|
|
29
32
|
// Responsive modal utilities
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Layout utilities for positioning and spacing.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import { LAYOUT_CONSTANTS } from './config';
|
|
6
|
+
import { isTablet, isSmallPhone, getSpacingMultiplier } from '../device/detection';
|
|
7
|
+
import { LAYOUT_CONSTANTS, SIZE_CONSTRAINTS } from './config';
|
|
8
8
|
import { validateNumber, validateSafeAreaInsets } from './validation';
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -13,6 +13,75 @@ import { validateNumber, validateSafeAreaInsets } from './validation';
|
|
|
13
13
|
*/
|
|
14
14
|
const checkIsTabletSize = (): boolean => isTablet();
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Screen layout configuration for ScreenLayout component
|
|
18
|
+
*/
|
|
19
|
+
export interface ScreenLayoutConfig {
|
|
20
|
+
maxContentWidth: number | undefined;
|
|
21
|
+
horizontalPadding: number;
|
|
22
|
+
verticalPadding: number;
|
|
23
|
+
spacingMultiplier: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get complete screen layout configuration
|
|
28
|
+
* Returns all responsive values needed for ScreenLayout
|
|
29
|
+
*/
|
|
30
|
+
export const getScreenLayoutConfig = (
|
|
31
|
+
insets: { left?: number; right?: number; top?: number; bottom?: number } = {}
|
|
32
|
+
): ScreenLayoutConfig => {
|
|
33
|
+
try {
|
|
34
|
+
const isTabletDevice = checkIsTabletSize();
|
|
35
|
+
const spacingMultiplier = getSpacingMultiplier();
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
maxContentWidth: isTabletDevice ? SIZE_CONSTRAINTS.CONTENT_MAX_TABLET : undefined,
|
|
39
|
+
horizontalPadding: getResponsiveHorizontalPadding(LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE, insets),
|
|
40
|
+
verticalPadding: getResponsiveVerticalPadding(insets),
|
|
41
|
+
spacingMultiplier,
|
|
42
|
+
};
|
|
43
|
+
} catch {
|
|
44
|
+
return {
|
|
45
|
+
maxContentWidth: undefined,
|
|
46
|
+
horizontalPadding: LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE,
|
|
47
|
+
verticalPadding: LAYOUT_CONSTANTS.VERTICAL_PADDING_STANDARD,
|
|
48
|
+
spacingMultiplier: LAYOUT_CONSTANTS.SPACING_MULTIPLIER_STANDARD,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Responsive vertical padding
|
|
55
|
+
* Adjusts based on device type and safe area insets
|
|
56
|
+
*/
|
|
57
|
+
export const getResponsiveVerticalPadding = (
|
|
58
|
+
insets: { top?: number; bottom?: number } = { top: 0, bottom: 0 }
|
|
59
|
+
): number => {
|
|
60
|
+
try {
|
|
61
|
+
validateSafeAreaInsets(insets);
|
|
62
|
+
const { top = 0 } = insets;
|
|
63
|
+
const isTabletDevice = checkIsTabletSize();
|
|
64
|
+
const isSmall = isSmallPhone();
|
|
65
|
+
const spacingMultiplier = getSpacingMultiplier();
|
|
66
|
+
|
|
67
|
+
// Base padding adjusted by device type
|
|
68
|
+
let basePadding: number = LAYOUT_CONSTANTS.VERTICAL_PADDING_STANDARD;
|
|
69
|
+
if (isTabletDevice) {
|
|
70
|
+
basePadding = LAYOUT_CONSTANTS.VERTICAL_PADDING_TABLET;
|
|
71
|
+
} else if (isSmall) {
|
|
72
|
+
basePadding = LAYOUT_CONSTANTS.VERTICAL_PADDING_SMALL;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Apply spacing multiplier for consistency
|
|
76
|
+
const adjustedPadding = basePadding * spacingMultiplier;
|
|
77
|
+
|
|
78
|
+
// Ensure minimum padding respects safe area
|
|
79
|
+
return Math.max(adjustedPadding, top > 0 ? 8 : adjustedPadding);
|
|
80
|
+
} catch {
|
|
81
|
+
return LAYOUT_CONSTANTS.VERTICAL_PADDING_STANDARD;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
16
85
|
/**
|
|
17
86
|
* Responsive horizontal padding
|
|
18
87
|
*/
|
|
@@ -28,7 +97,7 @@ export const getResponsiveHorizontalPadding = (
|
|
|
28
97
|
const isTabletDevice = checkIsTabletSize();
|
|
29
98
|
|
|
30
99
|
if (isTabletDevice) {
|
|
31
|
-
const tabletPadding = validatedBasePadding *
|
|
100
|
+
const tabletPadding = validatedBasePadding * LAYOUT_CONSTANTS.SPACING_MULTIPLIER_TABLET;
|
|
32
101
|
return Math.max(
|
|
33
102
|
tabletPadding,
|
|
34
103
|
left + LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE,
|
|
@@ -99,7 +168,10 @@ export const getResponsiveFABPosition = (
|
|
|
99
168
|
),
|
|
100
169
|
};
|
|
101
170
|
} catch {
|
|
102
|
-
return {
|
|
171
|
+
return {
|
|
172
|
+
bottom: LAYOUT_CONSTANTS.TAB_BAR_OFFSET,
|
|
173
|
+
right: LAYOUT_CONSTANTS.FAB_RIGHT_PHONE,
|
|
174
|
+
};
|
|
103
175
|
}
|
|
104
176
|
};
|
|
105
177
|
|
|
@@ -53,17 +53,17 @@ export const getResponsiveMinModalHeight = (): number => {
|
|
|
53
53
|
const { height } = getScreenDimensions();
|
|
54
54
|
|
|
55
55
|
if (height <= HEIGHT_THRESHOLDS.SMALL_DEVICE) {
|
|
56
|
-
const calculatedHeight = height *
|
|
56
|
+
const calculatedHeight = height * MODAL_CONFIG.MIN_HEIGHT_PERCENT_SMALL;
|
|
57
57
|
return Math.max(calculatedHeight, SIZE_CONSTRAINTS.MODAL_MIN_SMALL);
|
|
58
58
|
} else if (height >= HEIGHT_THRESHOLDS.LARGE_DEVICE) {
|
|
59
|
-
const calculatedHeight = height *
|
|
59
|
+
const calculatedHeight = height * MODAL_CONFIG.MIN_HEIGHT_PERCENT_TABLET;
|
|
60
60
|
return Math.min(
|
|
61
61
|
Math.max(calculatedHeight, SIZE_CONSTRAINTS.MODAL_MIN_TABLET),
|
|
62
62
|
SIZE_CONSTRAINTS.MODAL_MAX_TABLET
|
|
63
63
|
);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
const calculatedHeight = height *
|
|
66
|
+
const calculatedHeight = height * MODAL_CONFIG.MIN_HEIGHT_PERCENT_STANDARD;
|
|
67
67
|
return Math.max(calculatedHeight, SIZE_CONSTRAINTS.MODAL_MIN_STANDARD);
|
|
68
68
|
} catch {
|
|
69
69
|
return 300;
|
|
@@ -146,7 +146,7 @@ export const getResponsiveModalLayout = (): ResponsiveModalLayout => {
|
|
|
146
146
|
borderRadius: getResponsiveModalBorderRadius(),
|
|
147
147
|
backdropOpacity: getResponsiveBackdropOpacity(),
|
|
148
148
|
horizontalPadding: isTabletDevice
|
|
149
|
-
? LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE *
|
|
149
|
+
? LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE * LAYOUT_CONSTANTS.SPACING_MULTIPLIER_TABLET
|
|
150
150
|
: LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE,
|
|
151
151
|
};
|
|
152
152
|
};
|
|
@@ -17,6 +17,8 @@ import {
|
|
|
17
17
|
getResponsiveLogoSize,
|
|
18
18
|
getResponsiveInputHeight,
|
|
19
19
|
getResponsiveHorizontalPadding,
|
|
20
|
+
getResponsiveVerticalPadding,
|
|
21
|
+
getScreenLayoutConfig,
|
|
20
22
|
getResponsiveBottomPosition,
|
|
21
23
|
getResponsiveFABPosition,
|
|
22
24
|
getResponsiveTabBarConfig,
|
|
@@ -33,6 +35,7 @@ import {
|
|
|
33
35
|
type ResponsiveBottomSheetLayout,
|
|
34
36
|
type ResponsiveDialogLayout,
|
|
35
37
|
type ResponsiveTabBarConfig,
|
|
38
|
+
type ScreenLayoutConfig,
|
|
36
39
|
} from "./responsive";
|
|
37
40
|
import {
|
|
38
41
|
isSmallPhone,
|
|
@@ -70,9 +73,13 @@ export interface UseResponsiveReturn {
|
|
|
70
73
|
|
|
71
74
|
// Responsive positioning
|
|
72
75
|
horizontalPadding: number;
|
|
76
|
+
verticalPadding: number;
|
|
73
77
|
bottomPosition: number;
|
|
74
78
|
fabPosition: { bottom: number; right: number };
|
|
75
79
|
|
|
80
|
+
// Screen layout config (complete configuration for ScreenLayout)
|
|
81
|
+
screenLayoutConfig: ScreenLayoutConfig;
|
|
82
|
+
|
|
76
83
|
// Responsive layout
|
|
77
84
|
modalMaxHeight: string;
|
|
78
85
|
modalMinHeight: number;
|
|
@@ -160,9 +167,13 @@ export const useResponsive = (): UseResponsiveReturn => {
|
|
|
160
167
|
|
|
161
168
|
// Responsive positioning
|
|
162
169
|
horizontalPadding: getResponsiveHorizontalPadding(undefined, insets),
|
|
170
|
+
verticalPadding: getResponsiveVerticalPadding(insets),
|
|
163
171
|
bottomPosition: getResponsiveBottomPosition(undefined, insets),
|
|
164
172
|
fabPosition: getResponsiveFABPosition(insets),
|
|
165
173
|
|
|
174
|
+
// Screen layout config (complete configuration for ScreenLayout)
|
|
175
|
+
screenLayoutConfig: getScreenLayoutConfig(insets),
|
|
176
|
+
|
|
166
177
|
// Responsive layout
|
|
167
178
|
modalMaxHeight: getResponsiveModalMaxHeight(),
|
|
168
179
|
modalMinHeight: getResponsiveMinModalHeight(),
|