@umituz/react-native-design-system 2.6.11 → 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.11",
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
- * Utilities for detecting device types and screen dimensions.
5
- * Follows universal design principles for cross-platform compatibility.
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 small phone (iPhone 13 mini, SE)
58
- * @returns true if device is a small phone
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 tablet (iPad)
72
- * @returns true if device is a tablet
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 isTablet = (): boolean => {
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.SMALL_TABLET;
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
- * @returns Device type enum value
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.TABLET;
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
- const { width } = getScreenDimensions();
156
+ if (isTablet()) {
157
+ return LAYOUT_CONSTANTS.SPACING_MULTIPLIER_TABLET;
158
+ }
131
159
 
132
- if (width <= DEVICE_BREAKPOINTS.SMALL_PHONE) {
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
+ };
@@ -28,8 +28,8 @@ import { View, ScrollView, StyleSheet, type ViewStyle, RefreshControlProps } fro
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 { getResponsiveMaxWidth } from '../../responsive/responsiveSizing';
32
31
  import { getResponsiveHorizontalPadding } from '../../responsive/responsiveLayout';
32
+ import { isTablet as checkIsTablet } from '../../device/detection';
33
33
 
34
34
  /**
35
35
  * NOTE: This component now works in conjunction with the SafeAreaProvider
@@ -161,8 +161,10 @@ export const ScreenLayout: React.FC<ScreenLayoutProps> = ({
161
161
  // Automatically uses current theme from global store
162
162
  const tokens = useAppDesignTokens();
163
163
  const insets = useSafeAreaInsets();
164
+ const isTabletDevice = checkIsTablet();
164
165
 
165
- const finalMaxWidth = maxWidth || (responsiveEnabled ? getResponsiveMaxWidth() : undefined);
166
+ // Only apply maxWidth for tablets - phones should fill full width
167
+ const finalMaxWidth = maxWidth || (responsiveEnabled && isTabletDevice ? 600 : undefined);
166
168
  const horizontalPadding = responsiveEnabled ? getResponsiveHorizontalPadding(tokens.spacing.md, insets) : tokens.spacing.md;
167
169
 
168
170
  const styles = useMemo(() => StyleSheet.create({
@@ -172,8 +174,7 @@ export const ScreenLayout: React.FC<ScreenLayoutProps> = ({
172
174
  responsiveWrapper: {
173
175
  flex: 1,
174
176
  width: '100%',
175
- maxWidth: finalMaxWidth,
176
- alignSelf: 'flex-start',
177
+ ...(finalMaxWidth ? { maxWidth: finalMaxWidth, alignSelf: 'center' as const } : {}),
177
178
  },
178
179
  content: {
179
180
  flex: 1,
@@ -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 and smaller
14
- MEDIUM_PHONE: 414, // iPhone 13/14/15
15
- LARGE_PHONE: 428, // iPhone 14 Pro Max
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;