@umituz/react-native-design-system 2.6.12 → 2.6.13
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-design-system",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.13",
|
|
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",
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Device Detection Utilities
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Uses expo-device for primary device type detection (PHONE vs TABLET)
|
|
5
|
+
* and screen dimensions for secondary distinctions (small vs large phone).
|
|
6
|
+
*
|
|
7
|
+
* Benefits:
|
|
8
|
+
* - expo-device uses system-level detection on iOS (100% reliable)
|
|
9
|
+
* - Uses screen diagonal on Android (more accurate than pixels)
|
|
10
|
+
* - Future-proof: new devices automatically detected correctly
|
|
6
11
|
*/
|
|
7
12
|
|
|
8
13
|
import { Dimensions } from 'react-native';
|
|
14
|
+
import * as Device from 'expo-device';
|
|
15
|
+
import { DeviceType as ExpoDeviceType } from 'expo-device';
|
|
9
16
|
import { DEVICE_BREAKPOINTS, LAYOUT_CONSTANTS } from '../../responsive/config';
|
|
10
17
|
import { validateScreenDimensions } from '../../responsive/validation';
|
|
11
18
|
|
|
12
19
|
/**
|
|
13
20
|
* Helper function for device detection with fallback
|
|
14
|
-
* @param operation - Operation to perform
|
|
15
|
-
* @param fallback - Fallback value if operation fails
|
|
16
|
-
* @returns Operation result or fallback
|
|
17
21
|
*/
|
|
18
22
|
const withDeviceDetectionFallback = <T>(
|
|
19
23
|
operation: () => T,
|
|
@@ -28,6 +32,7 @@ const withDeviceDetectionFallback = <T>(
|
|
|
28
32
|
|
|
29
33
|
/**
|
|
30
34
|
* Device type enum for conditional rendering
|
|
35
|
+
* Used for fine-grained phone size distinctions
|
|
31
36
|
*/
|
|
32
37
|
export enum DeviceType {
|
|
33
38
|
SMALL_PHONE = 'SMALL_PHONE',
|
|
@@ -38,8 +43,6 @@ export enum DeviceType {
|
|
|
38
43
|
|
|
39
44
|
/**
|
|
40
45
|
* Get current screen dimensions
|
|
41
|
-
* @returns Screen width and height
|
|
42
|
-
* @throws ResponsiveValidationError if dimensions are invalid
|
|
43
46
|
*/
|
|
44
47
|
export const getScreenDimensions = () => {
|
|
45
48
|
const { width, height } = Dimensions.get('window');
|
|
@@ -48,18 +51,40 @@ export const getScreenDimensions = () => {
|
|
|
48
51
|
validateScreenDimensions(width, height);
|
|
49
52
|
return { width, height };
|
|
50
53
|
} catch {
|
|
51
|
-
// Fallback to safe default dimensions
|
|
52
54
|
return { width: 414, height: 896 };
|
|
53
55
|
}
|
|
54
56
|
};
|
|
55
57
|
|
|
56
58
|
/**
|
|
57
|
-
* Check if current device is a
|
|
58
|
-
*
|
|
59
|
+
* Check if current device is a tablet
|
|
60
|
+
* Uses expo-device for accurate system-level detection
|
|
61
|
+
*/
|
|
62
|
+
export const isTablet = (): boolean => {
|
|
63
|
+
return withDeviceDetectionFallback(
|
|
64
|
+
() => Device.deviceType === ExpoDeviceType.TABLET,
|
|
65
|
+
false
|
|
66
|
+
);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Check if current device is a phone
|
|
71
|
+
* Uses expo-device for accurate system-level detection
|
|
72
|
+
*/
|
|
73
|
+
export const isPhone = (): boolean => {
|
|
74
|
+
return withDeviceDetectionFallback(
|
|
75
|
+
() => Device.deviceType === ExpoDeviceType.PHONE,
|
|
76
|
+
true
|
|
77
|
+
);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Check if current device is a small phone (iPhone SE, 13 mini)
|
|
82
|
+
* Uses width breakpoint within phone category
|
|
59
83
|
*/
|
|
60
84
|
export const isSmallPhone = (): boolean => {
|
|
61
85
|
return withDeviceDetectionFallback(
|
|
62
86
|
() => {
|
|
87
|
+
if (!isPhone()) return false;
|
|
63
88
|
const { width } = getScreenDimensions();
|
|
64
89
|
return width <= DEVICE_BREAKPOINTS.SMALL_PHONE;
|
|
65
90
|
},
|
|
@@ -68,14 +93,15 @@ export const isSmallPhone = (): boolean => {
|
|
|
68
93
|
};
|
|
69
94
|
|
|
70
95
|
/**
|
|
71
|
-
* Check if current device is a
|
|
72
|
-
*
|
|
96
|
+
* Check if current device is a large phone (Pro Max, Plus models)
|
|
97
|
+
* Uses width breakpoint within phone category
|
|
73
98
|
*/
|
|
74
|
-
export const
|
|
99
|
+
export const isLargePhone = (): boolean => {
|
|
75
100
|
return withDeviceDetectionFallback(
|
|
76
101
|
() => {
|
|
102
|
+
if (!isPhone()) return false;
|
|
77
103
|
const { width } = getScreenDimensions();
|
|
78
|
-
return width >= DEVICE_BREAKPOINTS.
|
|
104
|
+
return width >= DEVICE_BREAKPOINTS.MEDIUM_PHONE;
|
|
79
105
|
},
|
|
80
106
|
false
|
|
81
107
|
);
|
|
@@ -83,7 +109,6 @@ export const isTablet = (): boolean => {
|
|
|
83
109
|
|
|
84
110
|
/**
|
|
85
111
|
* Check if device is in landscape mode
|
|
86
|
-
* @returns true if device is in landscape orientation
|
|
87
112
|
*/
|
|
88
113
|
export const isLandscape = (): boolean => {
|
|
89
114
|
return withDeviceDetectionFallback(
|
|
@@ -96,47 +121,48 @@ export const isLandscape = (): boolean => {
|
|
|
96
121
|
};
|
|
97
122
|
|
|
98
123
|
/**
|
|
99
|
-
* Get current device type
|
|
100
|
-
*
|
|
124
|
+
* Get current device type with fine-grained phone distinctions
|
|
125
|
+
* Uses expo-device for PHONE vs TABLET, width for phone size variants
|
|
101
126
|
*/
|
|
102
127
|
export const getDeviceType = (): DeviceType => {
|
|
103
128
|
return withDeviceDetectionFallback(
|
|
104
129
|
() => {
|
|
130
|
+
// Use expo-device for primary detection
|
|
131
|
+
if (isTablet()) {
|
|
132
|
+
return DeviceType.TABLET;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// For phones, use width for size variants
|
|
105
136
|
const { width } = getScreenDimensions();
|
|
106
137
|
|
|
107
138
|
if (width <= DEVICE_BREAKPOINTS.SMALL_PHONE) {
|
|
108
139
|
return DeviceType.SMALL_PHONE;
|
|
109
140
|
} else if (width <= DEVICE_BREAKPOINTS.MEDIUM_PHONE) {
|
|
110
141
|
return DeviceType.MEDIUM_PHONE;
|
|
111
|
-
} else if (width <= DEVICE_BREAKPOINTS.LARGE_PHONE) {
|
|
112
|
-
return DeviceType.LARGE_PHONE;
|
|
113
142
|
}
|
|
114
143
|
|
|
115
|
-
return DeviceType.
|
|
144
|
+
return DeviceType.LARGE_PHONE;
|
|
116
145
|
},
|
|
117
146
|
DeviceType.MEDIUM_PHONE
|
|
118
147
|
);
|
|
119
148
|
};
|
|
120
149
|
|
|
121
150
|
/**
|
|
122
|
-
* Responsive spacing multiplier
|
|
123
|
-
* Returns a multiplier for spacing based on device size
|
|
124
|
-
*
|
|
125
|
-
* @returns Spacing multiplier (0.9-1.2)
|
|
151
|
+
* Responsive spacing multiplier based on device type
|
|
126
152
|
*/
|
|
127
153
|
export const getSpacingMultiplier = (): number => {
|
|
128
154
|
return withDeviceDetectionFallback(
|
|
129
155
|
() => {
|
|
130
|
-
|
|
156
|
+
if (isTablet()) {
|
|
157
|
+
return LAYOUT_CONSTANTS.SPACING_MULTIPLIER_TABLET;
|
|
158
|
+
}
|
|
131
159
|
|
|
132
|
-
if (
|
|
160
|
+
if (isSmallPhone()) {
|
|
133
161
|
return LAYOUT_CONSTANTS.SPACING_MULTIPLIER_SMALL;
|
|
134
|
-
} else if (width >= DEVICE_BREAKPOINTS.TABLET) {
|
|
135
|
-
return LAYOUT_CONSTANTS.SPACING_MULTIPLIER_TABLET;
|
|
136
162
|
}
|
|
137
163
|
|
|
138
164
|
return LAYOUT_CONSTANTS.SPACING_MULTIPLIER_STANDARD;
|
|
139
165
|
},
|
|
140
166
|
LAYOUT_CONSTANTS.SPACING_MULTIPLIER_STANDARD
|
|
141
167
|
);
|
|
142
|
-
};
|
|
168
|
+
};
|
|
@@ -29,8 +29,7 @@ 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
31
|
import { getResponsiveHorizontalPadding } from '../../responsive/responsiveLayout';
|
|
32
|
-
import {
|
|
33
|
-
import { DEVICE_BREAKPOINTS } from '../../responsive/config';
|
|
32
|
+
import { isTablet as checkIsTablet } from '../../device/detection';
|
|
34
33
|
|
|
35
34
|
/**
|
|
36
35
|
* NOTE: This component now works in conjunction with the SafeAreaProvider
|
|
@@ -162,11 +161,10 @@ export const ScreenLayout: React.FC<ScreenLayoutProps> = ({
|
|
|
162
161
|
// Automatically uses current theme from global store
|
|
163
162
|
const tokens = useAppDesignTokens();
|
|
164
163
|
const insets = useSafeAreaInsets();
|
|
165
|
-
const
|
|
166
|
-
const isTablet = screenWidth >= DEVICE_BREAKPOINTS.SMALL_TABLET;
|
|
164
|
+
const isTabletDevice = checkIsTablet();
|
|
167
165
|
|
|
168
166
|
// Only apply maxWidth for tablets - phones should fill full width
|
|
169
|
-
const finalMaxWidth = maxWidth || (responsiveEnabled &&
|
|
167
|
+
const finalMaxWidth = maxWidth || (responsiveEnabled && isTabletDevice ? 600 : undefined);
|
|
170
168
|
const horizontalPadding = responsiveEnabled ? getResponsiveHorizontalPadding(tokens.spacing.md, insets) : tokens.spacing.md;
|
|
171
169
|
|
|
172
170
|
const styles = useMemo(() => StyleSheet.create({
|
package/src/responsive/config.ts
CHANGED
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
* These values determine when responsive behaviors change
|
|
11
11
|
*/
|
|
12
12
|
export const DEVICE_BREAKPOINTS = {
|
|
13
|
-
SMALL_PHONE: 375, // iPhone 13 mini
|
|
14
|
-
MEDIUM_PHONE: 414, // iPhone 13/14/15
|
|
15
|
-
LARGE_PHONE:
|
|
13
|
+
SMALL_PHONE: 375, // iPhone SE, iPhone 13 mini
|
|
14
|
+
MEDIUM_PHONE: 414, // iPhone 13/14/15 (390-393px actual)
|
|
15
|
+
LARGE_PHONE: 500, // iPhone 14/15 Pro Max (430px) - buffer for future devices
|
|
16
16
|
SMALL_TABLET: 768, // iPad mini
|
|
17
17
|
TABLET: 1024, // iPad Air and larger tablets
|
|
18
18
|
} as const;
|