@umituz/react-native-design-system 2.3.1 → 2.3.3

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.
Files changed (54) hide show
  1. package/package.json +15 -3
  2. package/src/atoms/AtomicInput.tsx +0 -1
  3. package/src/atoms/AtomicPicker.tsx +0 -1
  4. package/src/atoms/picker/components/PickerChips.tsx +0 -1
  5. package/src/atoms/picker/components/PickerModal.tsx +1 -3
  6. package/src/atoms/picker/styles/pickerStyles.ts +1 -1
  7. package/src/{responsive → device/detection}/deviceDetection.ts +7 -7
  8. package/src/device/detection/iPadBreakpoints.ts +55 -0
  9. package/src/device/detection/iPadDetection.ts +48 -0
  10. package/src/device/detection/iPadLayoutUtils.ts +95 -0
  11. package/src/device/detection/iPadModalUtils.ts +98 -0
  12. package/src/device/detection/index.ts +54 -0
  13. package/src/device/domain/entities/Device.ts +207 -0
  14. package/src/device/domain/entities/DeviceMemoryUtils.ts +62 -0
  15. package/src/device/domain/entities/DeviceTypeUtils.ts +66 -0
  16. package/src/device/domain/entities/__tests__/DeviceMemoryUtils.test.ts +118 -0
  17. package/src/device/domain/entities/__tests__/DeviceTypeUtils.test.ts +104 -0
  18. package/src/device/domain/entities/__tests__/DeviceUtils.test.ts +167 -0
  19. package/src/device/index.ts +104 -0
  20. package/src/device/infrastructure/services/ApplicationInfoService.ts +86 -0
  21. package/src/device/infrastructure/services/DeviceCapabilityService.ts +60 -0
  22. package/src/device/infrastructure/services/DeviceIdService.ts +70 -0
  23. package/src/device/infrastructure/services/DeviceInfoService.ts +95 -0
  24. package/src/device/infrastructure/services/DeviceService.ts +104 -0
  25. package/src/device/infrastructure/services/PersistentDeviceIdService.ts +132 -0
  26. package/src/device/infrastructure/services/UserFriendlyIdService.ts +68 -0
  27. package/src/device/infrastructure/utils/__tests__/nativeModuleUtils.test.ts +158 -0
  28. package/src/device/infrastructure/utils/__tests__/stringUtils.test.ts +120 -0
  29. package/src/device/infrastructure/utils/nativeModuleUtils.ts +69 -0
  30. package/src/device/infrastructure/utils/stringUtils.ts +59 -0
  31. package/src/device/presentation/hooks/useAnonymousUser.ts +117 -0
  32. package/src/device/presentation/hooks/useDeviceInfo.ts +222 -0
  33. package/src/molecules/ConfirmationModalContent.tsx +4 -4
  34. package/src/molecules/ConfirmationModalMain.tsx +1 -1
  35. package/src/molecules/ScreenHeader.tsx +2 -2
  36. package/src/molecules/confirmation-modal/components.tsx +1 -1
  37. package/src/molecules/confirmation-modal/styles/confirmationModalStyles.ts +6 -7
  38. package/src/presentation/utils/variants/__tests__/core.test.ts +0 -1
  39. package/src/responsive/gridUtils.ts +1 -1
  40. package/src/responsive/index.ts +36 -20
  41. package/src/responsive/responsive.ts +2 -2
  42. package/src/responsive/responsiveLayout.ts +1 -1
  43. package/src/responsive/responsiveModal.ts +1 -1
  44. package/src/responsive/responsiveSizing.ts +1 -1
  45. package/src/responsive/useResponsive.ts +1 -1
  46. package/src/safe-area/__tests__/components/SafeAreaProvider.test.tsx +2 -2
  47. package/src/safe-area/__tests__/hooks/useContentSafeAreaPadding.test.tsx +2 -2
  48. package/src/safe-area/__tests__/hooks/useHeaderSafeAreaPadding.test.tsx +2 -2
  49. package/src/safe-area/__tests__/hooks/useSafeAreaInsets.test.tsx +2 -2
  50. package/src/safe-area/__tests__/hooks/useStatusBarSafeAreaPadding.test.tsx +2 -2
  51. package/src/safe-area/__tests__/integration/completeFlow.test.tsx +5 -4
  52. package/src/safe-area/__tests__/utils/testUtils.tsx +5 -4
  53. package/src/theme/infrastructure/stores/themeStore.ts +0 -2
  54. package/src/typography/presentation/utils/textColorUtils.ts +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-design-system",
3
- "version": "2.3.1",
3
+ "version": "2.3.3",
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",
@@ -18,6 +18,7 @@
18
18
  "./typography": "./src/typography/index.ts",
19
19
  "./responsive": "./src/responsive/index.ts",
20
20
  "./safe-area": "./src/safe-area/index.ts",
21
+ "./device": "./src/device/index.ts",
21
22
  "./package.json": "./package.json"
22
23
  },
23
24
  "scripts": {
@@ -60,7 +61,9 @@
60
61
  "react-native-reanimated": ">=3.16.0",
61
62
  "react-native-safe-area-context": ">=5.0.0",
62
63
  "react-native-svg": ">=15.0.0",
63
- "zustand": ">=5.0.0"
64
+ "zustand": ">=5.0.0",
65
+ "expo-device": ">=5.0.0",
66
+ "expo-application": ">=5.0.0"
64
67
  },
65
68
  "peerDependenciesMeta": {
66
69
  "expo-linear-gradient": {
@@ -71,6 +74,12 @@
71
74
  },
72
75
  "@gorhom/bottom-sheet": {
73
76
  "optional": true
77
+ },
78
+ "expo-device": {
79
+ "optional": true
80
+ },
81
+ "expo-application": {
82
+ "optional": true
74
83
  }
75
84
  },
76
85
  "devDependencies": {
@@ -95,7 +104,10 @@
95
104
  "react-native-safe-area-context": "^5.6.0",
96
105
  "react-native-svg": "15.12.1",
97
106
  "typescript": "~5.9.2",
98
- "zustand": "^5.0.2"
107
+ "zustand": "^5.0.2",
108
+ "expo-device": "~7.0.2",
109
+ "expo-application": "~5.9.1",
110
+ "expo-localization": "~16.0.1"
99
111
  },
100
112
  "publishConfig": {
101
113
  "access": "public"
@@ -107,7 +107,6 @@ export const AtomicInput: React.FC<AtomicInputProps> = ({
107
107
  isFocused,
108
108
  isPasswordVisible,
109
109
  characterCount,
110
- isAtMaxLength: _isAtMaxLength,
111
110
  setIsFocused,
112
111
  handleTextChange,
113
112
  togglePasswordVisibility,
@@ -80,7 +80,6 @@ export const AtomicPicker: React.FC<AtomicPickerProps> = ({
80
80
  searchable = false,
81
81
  clearable = false,
82
82
  autoClose = true,
83
- color: _color = 'primary',
84
83
  size = 'md',
85
84
  modalTitle,
86
85
  emptyMessage = 'No options available',
@@ -26,7 +26,6 @@ interface PickerChipsProps {
26
26
  export const PickerChips: React.FC<PickerChipsProps> = React.memo(({
27
27
  selectedOptions,
28
28
  onRemoveChip,
29
- testID: _testID,
30
29
  }) => {
31
30
  const tokens = useAppDesignTokens();
32
31
 
@@ -59,7 +59,6 @@ interface PickerModalProps {
59
59
  export const PickerModal: React.FC<PickerModalProps> = React.memo(({
60
60
  visible,
61
61
  onClose,
62
- options: _options,
63
62
  selectedValues,
64
63
  onSelect,
65
64
  title,
@@ -67,7 +66,6 @@ export const PickerModal: React.FC<PickerModalProps> = React.memo(({
67
66
  searchQuery,
68
67
  onSearchChange,
69
68
  filteredOptions,
70
- multiple: _multiple = false,
71
69
  emptyMessage = 'No options available',
72
70
  searchPlaceholder = 'Search...',
73
71
  closeAccessibilityLabel = 'Close picker',
@@ -76,7 +74,7 @@ export const PickerModal: React.FC<PickerModalProps> = React.memo(({
76
74
  const tokens = useAppDesignTokens();
77
75
  const insets = useSafeAreaInsets();
78
76
 
79
- const modalOverlayStyles = getModalOverlayStyles(tokens);
77
+ const modalOverlayStyles = getModalOverlayStyles();
80
78
  const modalContainerStyles = getModalContainerStyles(tokens, 0);
81
79
  const modalHeaderStyles = getModalHeaderStyles(tokens);
82
80
  const modalTitleStyles = getModalTitleStyles(tokens);
@@ -110,7 +110,7 @@ export const getPickerErrorStyles = (tokens: DesignTokens): TextStyle => ({
110
110
  });
111
111
 
112
112
  // Modal styles
113
- export const getModalOverlayStyles = (_tokens: DesignTokens): ViewStyle => ({
113
+ export const getModalOverlayStyles = (): ViewStyle => ({
114
114
  flex: 1,
115
115
  backgroundColor: 'rgba(0, 0, 0, 0.5)',
116
116
  justifyContent: 'flex-end',
@@ -6,8 +6,8 @@
6
6
  */
7
7
 
8
8
  import { Dimensions } from 'react-native';
9
- import { DEVICE_BREAKPOINTS, LAYOUT_CONSTANTS } from './config';
10
- import { validateScreenDimensions } from './validation';
9
+ import { DEVICE_BREAKPOINTS, LAYOUT_CONSTANTS } from '../../responsive/config';
10
+ import { validateScreenDimensions } from '../../responsive/validation';
11
11
 
12
12
  /**
13
13
  * Helper function for device detection with fallback
@@ -17,13 +17,13 @@ import { validateScreenDimensions } from './validation';
17
17
  * @returns Operation result or fallback
18
18
  */
19
19
  const withDeviceDetectionFallback = <T>(
20
- operation: () => T,
21
- fallback: T,
20
+ operation: () => T,
21
+ fallback: T,
22
22
  warningMessage: string
23
23
  ): T => {
24
24
  try {
25
25
  return operation();
26
- } catch (error) {
26
+ } catch {
27
27
  if (__DEV__) {
28
28
  console.warn(`[DeviceDetection] ${warningMessage}`);
29
29
  }
@@ -48,11 +48,11 @@ export enum DeviceType {
48
48
  */
49
49
  export const getScreenDimensions = () => {
50
50
  const { width, height } = Dimensions.get('window');
51
-
51
+
52
52
  try {
53
53
  validateScreenDimensions(width, height);
54
54
  return { width, height };
55
- } catch (error) {
55
+ } catch {
56
56
  if (__DEV__) {
57
57
  console.warn('[getScreenDimensions] Invalid screen dimensions detected, using fallback values');
58
58
  }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * iPad Breakpoints and Constants
3
+ * Apple HIG compliant values for iPad responsive design
4
+ */
5
+
6
+ /**
7
+ * iPad specific breakpoints following Apple HIG
8
+ */
9
+ export const IPAD_BREAKPOINTS = {
10
+ IPAD_MINI: 744,
11
+ IPAD_10_2: 810,
12
+ IPAD_AIR: 820,
13
+ IPAD_11_PRO: 834,
14
+ IPAD_12_9_PRO: 1024,
15
+ IPAD_LANDSCAPE_MINI: 1133,
16
+ IPAD_LANDSCAPE_AIR: 1180,
17
+ IPAD_LANDSCAPE_PRO: 1366,
18
+ } as const;
19
+
20
+ /**
21
+ * Apple HIG Touch Target Guidelines
22
+ */
23
+ export const TOUCH_TARGETS = {
24
+ MINIMUM: 44,
25
+ RECOMMENDED: 48,
26
+ IPAD_RECOMMENDED: 50,
27
+ } as const;
28
+
29
+ /**
30
+ * Content width constraints for iPad
31
+ */
32
+ export const CONTENT_WIDTH_CONSTRAINTS = {
33
+ READABLE_MAX: 672,
34
+ FORM_MAX: 580,
35
+ CARD_MAX: 400,
36
+ MODAL_MAX: 600,
37
+ PAYWALL_MAX: 540,
38
+ } as const;
39
+
40
+ /**
41
+ * iPad Layout Configuration
42
+ */
43
+ export const IPAD_LAYOUT_CONFIG = {
44
+ SCREEN_PADDING: 24,
45
+ SECTION_SPACING: 32,
46
+ CARD_SPACING: 20,
47
+ GRID_COLUMNS_PORTRAIT: 2,
48
+ GRID_COLUMNS_LANDSCAPE: 3,
49
+ GRID_GAP: 20,
50
+ MODAL_CORNER_RADIUS: 16,
51
+ SHEET_CORNER_RADIUS: 20,
52
+ MODAL_HORIZONTAL_MARGIN: 48,
53
+ FONT_SCALE: 1.1,
54
+ HEADING_SCALE: 1.15,
55
+ } as const;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * iPad Device Detection Utilities
3
+ */
4
+
5
+ import { Dimensions, Platform } from 'react-native';
6
+ import { DEVICE_BREAKPOINTS } from '../../responsive/config';
7
+ import { IPAD_BREAKPOINTS } from './iPadBreakpoints';
8
+
9
+ /**
10
+ * Detect if the current device is an iPad
11
+ */
12
+ export function isIPad(): boolean {
13
+ if (Platform.OS !== 'ios') return false;
14
+
15
+ const { width, height } = Dimensions.get('window');
16
+ const minDimension = Math.min(width, height);
17
+ return minDimension >= DEVICE_BREAKPOINTS.SMALL_TABLET;
18
+ }
19
+
20
+ /**
21
+ * Detect if the current device is an iPad mini
22
+ */
23
+ export function isIPadMini(): boolean {
24
+ if (!isIPad()) return false;
25
+
26
+ const { width, height } = Dimensions.get('window');
27
+ const minWidth = Math.min(width, height);
28
+ return minWidth < IPAD_BREAKPOINTS.IPAD_AIR;
29
+ }
30
+
31
+ /**
32
+ * Detect if the current device is an iPad Pro (12.9")
33
+ */
34
+ export function isIPadPro(): boolean {
35
+ if (!isIPad()) return false;
36
+
37
+ const { width, height } = Dimensions.get('window');
38
+ const minWidth = Math.min(width, height);
39
+ return minWidth >= IPAD_BREAKPOINTS.IPAD_11_PRO;
40
+ }
41
+
42
+ /**
43
+ * Check if device is in landscape orientation
44
+ */
45
+ export function isIPadLandscape(): boolean {
46
+ const { width, height } = Dimensions.get('window');
47
+ return width > height;
48
+ }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * iPad Layout Utilities
3
+ */
4
+
5
+ import { Dimensions } from 'react-native';
6
+ import { DEVICE_BREAKPOINTS } from '../../responsive/config';
7
+ import {
8
+ IPAD_BREAKPOINTS,
9
+ TOUCH_TARGETS,
10
+ CONTENT_WIDTH_CONSTRAINTS,
11
+ IPAD_LAYOUT_CONFIG,
12
+ } from './iPadBreakpoints';
13
+ import { isIPad, isIPadPro } from './iPadDetection';
14
+
15
+ /**
16
+ * Get optimal content max width based on screen size
17
+ */
18
+ export function getContentMaxWidth(screenWidth: number): number {
19
+ if (screenWidth >= IPAD_BREAKPOINTS.IPAD_12_9_PRO) {
20
+ return CONTENT_WIDTH_CONSTRAINTS.READABLE_MAX;
21
+ }
22
+ if (screenWidth >= IPAD_BREAKPOINTS.IPAD_AIR) {
23
+ return Math.min(screenWidth * 0.85, CONTENT_WIDTH_CONSTRAINTS.READABLE_MAX);
24
+ }
25
+ if (screenWidth >= DEVICE_BREAKPOINTS.SMALL_TABLET) {
26
+ return Math.min(screenWidth * 0.90, CONTENT_WIDTH_CONSTRAINTS.FORM_MAX);
27
+ }
28
+ return screenWidth;
29
+ }
30
+
31
+ /**
32
+ * Get grid columns based on screen width
33
+ */
34
+ export function getIPadGridColumns(screenWidth: number): number {
35
+ if (screenWidth >= IPAD_BREAKPOINTS.IPAD_LANDSCAPE_AIR) return 4;
36
+ if (screenWidth >= IPAD_BREAKPOINTS.IPAD_12_9_PRO) return 3;
37
+ if (screenWidth >= DEVICE_BREAKPOINTS.SMALL_TABLET) return 2;
38
+ return 1;
39
+ }
40
+
41
+ /**
42
+ * Get touch target size based on device
43
+ */
44
+ export function getTouchTargetSize(): number {
45
+ return isIPad() ? TOUCH_TARGETS.IPAD_RECOMMENDED : TOUCH_TARGETS.RECOMMENDED;
46
+ }
47
+
48
+ /**
49
+ * Get screen padding based on device type
50
+ */
51
+ export function getIPadScreenPadding(): number {
52
+ if (isIPadPro()) return 32;
53
+ if (isIPad()) return IPAD_LAYOUT_CONFIG.SCREEN_PADDING;
54
+ return 16;
55
+ }
56
+
57
+ /**
58
+ * Get font scale for iPad
59
+ */
60
+ export function getIPadFontScale(): number {
61
+ if (isIPadPro()) return 1.15;
62
+ if (isIPad()) return IPAD_LAYOUT_CONFIG.FONT_SCALE;
63
+ return 1.0;
64
+ }
65
+
66
+ export interface IPadLayoutInfo {
67
+ isIPad: boolean;
68
+ isLandscape: boolean;
69
+ screenWidth: number;
70
+ screenHeight: number;
71
+ contentMaxWidth: number;
72
+ gridColumns: number;
73
+ touchTargetSize: number;
74
+ screenPadding: number;
75
+ fontScale: number;
76
+ }
77
+
78
+ /**
79
+ * Get complete iPad layout information
80
+ */
81
+ export function getIPadLayoutInfo(): IPadLayoutInfo {
82
+ const { width, height } = Dimensions.get('window');
83
+
84
+ return {
85
+ isIPad: isIPad(),
86
+ isLandscape: width > height,
87
+ screenWidth: width,
88
+ screenHeight: height,
89
+ contentMaxWidth: getContentMaxWidth(width),
90
+ gridColumns: getIPadGridColumns(width),
91
+ touchTargetSize: getTouchTargetSize(),
92
+ screenPadding: getIPadScreenPadding(),
93
+ fontScale: getIPadFontScale(),
94
+ };
95
+ }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * iPad Modal Utilities
3
+ * Modal dimensions optimized for iPad following Apple HIG
4
+ */
5
+
6
+ import { Dimensions } from 'react-native';
7
+ import { CONTENT_WIDTH_CONSTRAINTS, IPAD_LAYOUT_CONFIG } from './iPadBreakpoints';
8
+ import { isIPad, isIPadPro } from './iPadDetection';
9
+
10
+ export interface ModalDimensions {
11
+ width: number | string;
12
+ maxWidth: number;
13
+ maxHeight: string | number;
14
+ horizontalMargin: number;
15
+ borderRadius: number;
16
+ }
17
+
18
+ /**
19
+ * Get modal dimensions optimized for iPad
20
+ */
21
+ export function getIPadModalDimensions(): ModalDimensions {
22
+ const { width } = Dimensions.get('window');
23
+
24
+ if (isIPadPro()) {
25
+ return {
26
+ width: CONTENT_WIDTH_CONSTRAINTS.MODAL_MAX,
27
+ maxWidth: CONTENT_WIDTH_CONSTRAINTS.MODAL_MAX,
28
+ maxHeight: '75%',
29
+ horizontalMargin: 64,
30
+ borderRadius: 20,
31
+ };
32
+ }
33
+
34
+ if (isIPad()) {
35
+ return {
36
+ width: Math.min(width * 0.8, CONTENT_WIDTH_CONSTRAINTS.MODAL_MAX),
37
+ maxWidth: CONTENT_WIDTH_CONSTRAINTS.MODAL_MAX,
38
+ maxHeight: '80%',
39
+ horizontalMargin: IPAD_LAYOUT_CONFIG.MODAL_HORIZONTAL_MARGIN,
40
+ borderRadius: IPAD_LAYOUT_CONFIG.MODAL_CORNER_RADIUS,
41
+ };
42
+ }
43
+
44
+ return {
45
+ width: '92%',
46
+ maxWidth: 480,
47
+ maxHeight: '90%',
48
+ horizontalMargin: 16,
49
+ borderRadius: 24,
50
+ };
51
+ }
52
+
53
+ export interface PaywallDimensions {
54
+ width: number | string;
55
+ maxWidth: number;
56
+ maxHeight: string | number;
57
+ padding: number;
58
+ buttonHeight: number;
59
+ priceTextScale: number;
60
+ }
61
+
62
+ /**
63
+ * Get paywall modal dimensions - Apple HIG compliant
64
+ */
65
+ export function getPaywallDimensions(): PaywallDimensions {
66
+ const { width } = Dimensions.get('window');
67
+
68
+ if (isIPadPro()) {
69
+ return {
70
+ width: CONTENT_WIDTH_CONSTRAINTS.PAYWALL_MAX,
71
+ maxWidth: CONTENT_WIDTH_CONSTRAINTS.PAYWALL_MAX,
72
+ maxHeight: '80%',
73
+ padding: 32,
74
+ buttonHeight: 56,
75
+ priceTextScale: 1.2,
76
+ };
77
+ }
78
+
79
+ if (isIPad()) {
80
+ return {
81
+ width: Math.min(width * 0.75, CONTENT_WIDTH_CONSTRAINTS.PAYWALL_MAX),
82
+ maxWidth: CONTENT_WIDTH_CONSTRAINTS.PAYWALL_MAX,
83
+ maxHeight: '85%',
84
+ padding: 28,
85
+ buttonHeight: 52,
86
+ priceTextScale: 1.1,
87
+ };
88
+ }
89
+
90
+ return {
91
+ width: '100%',
92
+ maxWidth: 480,
93
+ maxHeight: '95%',
94
+ padding: 20,
95
+ buttonHeight: 50,
96
+ priceTextScale: 1.0,
97
+ };
98
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Device Detection Module - Public API
3
+ *
4
+ * Centralized device detection utilities including:
5
+ * - Device type detection (phone, tablet, iPad variants)
6
+ * - Screen dimension utilities
7
+ * - Layout utilities for different device types
8
+ */
9
+
10
+ // Breakpoints and constants
11
+ export {
12
+ IPAD_BREAKPOINTS,
13
+ TOUCH_TARGETS,
14
+ CONTENT_WIDTH_CONSTRAINTS,
15
+ IPAD_LAYOUT_CONFIG,
16
+ } from './iPadBreakpoints';
17
+
18
+ // Device type detection
19
+ export {
20
+ DeviceType,
21
+ getScreenDimensions,
22
+ isSmallPhone,
23
+ isTablet,
24
+ isLandscape,
25
+ getDeviceType,
26
+ getSpacingMultiplier,
27
+ } from './deviceDetection';
28
+
29
+ // iPad-specific detection
30
+ export {
31
+ isIPad,
32
+ isIPadMini,
33
+ isIPadPro,
34
+ isIPadLandscape,
35
+ } from './iPadDetection';
36
+
37
+ // iPad layout utilities
38
+ export {
39
+ getContentMaxWidth,
40
+ getIPadGridColumns,
41
+ getTouchTargetSize,
42
+ getIPadScreenPadding,
43
+ getIPadFontScale,
44
+ getIPadLayoutInfo,
45
+ type IPadLayoutInfo,
46
+ } from './iPadLayoutUtils';
47
+
48
+ // iPad modal utilities
49
+ export {
50
+ getIPadModalDimensions,
51
+ getPaywallDimensions,
52
+ type ModalDimensions,
53
+ type PaywallDimensions,
54
+ } from './iPadModalUtils';