@umituz/react-native-design-system 1.14.0 → 2.0.0

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 (87) hide show
  1. package/package.json +26 -19
  2. package/src/atoms/AtomicAvatar.tsx +161 -0
  3. package/src/atoms/AtomicButton.tsx +241 -0
  4. package/src/atoms/AtomicChip.tsx +226 -0
  5. package/src/atoms/AtomicDatePicker.tsx +255 -0
  6. package/src/atoms/AtomicFab.tsx +99 -0
  7. package/src/atoms/AtomicIcon.tsx +149 -0
  8. package/src/atoms/AtomicInput.tsx +308 -0
  9. package/src/atoms/AtomicPicker.tsx +310 -0
  10. package/src/atoms/AtomicProgress.tsx +149 -0
  11. package/src/atoms/AtomicText.tsx +55 -0
  12. package/src/atoms/__tests__/AtomicButton.test.tsx +107 -0
  13. package/src/atoms/__tests__/AtomicIcon.test.tsx +110 -0
  14. package/src/atoms/__tests__/AtomicInput.test.tsx +195 -0
  15. package/src/atoms/datepicker/components/DatePickerButton.tsx +112 -0
  16. package/src/atoms/datepicker/components/DatePickerModal.tsx +143 -0
  17. package/src/atoms/fab/styles/fabStyles.ts +98 -0
  18. package/src/atoms/fab/types/index.ts +88 -0
  19. package/src/atoms/index.ts +70 -0
  20. package/src/atoms/input/hooks/useInputState.ts +63 -0
  21. package/src/atoms/input/styles/inputStylesHelper.ts +120 -0
  22. package/src/atoms/picker/components/PickerChips.tsx +57 -0
  23. package/src/atoms/picker/components/PickerModal.tsx +214 -0
  24. package/src/atoms/picker/styles/pickerStyles.ts +223 -0
  25. package/src/atoms/picker/types/index.ts +42 -0
  26. package/src/index.ts +148 -79
  27. package/src/molecules/ConfirmationModal.tsx +42 -0
  28. package/src/molecules/ConfirmationModalContent.tsx +87 -0
  29. package/src/molecules/ConfirmationModalMain.tsx +91 -0
  30. package/src/molecules/FormField.tsx +155 -0
  31. package/src/molecules/IconContainer.tsx +79 -0
  32. package/src/molecules/ListItem.tsx +35 -0
  33. package/src/molecules/ScreenHeader.tsx +171 -0
  34. package/src/molecules/SearchBar.tsx +198 -0
  35. package/src/molecules/confirmation-modal/components.tsx +94 -0
  36. package/src/molecules/confirmation-modal/index.ts +7 -0
  37. package/src/molecules/confirmation-modal/styles/confirmationModalStyles.ts +133 -0
  38. package/src/molecules/confirmation-modal/types/index.ts +41 -0
  39. package/src/molecules/confirmation-modal/useConfirmationModal.ts +50 -0
  40. package/src/molecules/index.ts +19 -0
  41. package/src/molecules/listitem/index.ts +6 -0
  42. package/src/molecules/listitem/styles/listItemStyles.ts +37 -0
  43. package/src/molecules/listitem/types/index.ts +21 -0
  44. package/src/organisms/AppHeader.tsx +136 -0
  45. package/src/organisms/FormContainer.tsx +169 -0
  46. package/src/organisms/ScreenLayout.tsx +183 -0
  47. package/src/organisms/index.ts +31 -0
  48. package/src/responsive/config.ts +139 -0
  49. package/src/responsive/deviceDetection.ts +155 -0
  50. package/src/responsive/gridUtils.ts +79 -0
  51. package/src/responsive/index.ts +52 -0
  52. package/src/responsive/platformConstants.ts +98 -0
  53. package/src/responsive/responsive.ts +61 -0
  54. package/src/responsive/responsiveLayout.ts +137 -0
  55. package/src/responsive/responsiveSizing.ts +134 -0
  56. package/src/responsive/useResponsive.ts +140 -0
  57. package/src/responsive/validation.ts +158 -0
  58. package/src/theme/core/BaseTokens.ts +42 -0
  59. package/src/theme/core/ColorPalette.ts +29 -0
  60. package/src/theme/core/CustomColors.ts +122 -0
  61. package/src/theme/core/NavigationTheme.ts +72 -0
  62. package/src/theme/core/TokenFactory.ts +103 -0
  63. package/src/theme/core/colors/ColorUtils.ts +53 -0
  64. package/src/theme/core/colors/DarkColors.ts +146 -0
  65. package/src/theme/core/colors/LightColors.ts +146 -0
  66. package/src/theme/core/constants/DesignConstants.ts +31 -0
  67. package/src/theme/core/themes.ts +118 -0
  68. package/src/theme/core/tokens/BaseTokens.ts +144 -0
  69. package/src/theme/core/tokens/Borders.ts +43 -0
  70. package/src/theme/core/tokens/Sizes.ts +51 -0
  71. package/src/theme/core/tokens/Spacing.ts +38 -0
  72. package/src/theme/core/tokens/Typography.ts +143 -0
  73. package/src/theme/hooks/useAppDesignTokens.ts +45 -0
  74. package/src/theme/hooks/useCommonStyles.ts +248 -0
  75. package/src/theme/hooks/useThemedStyles.ts +68 -0
  76. package/src/theme/index.ts +94 -0
  77. package/src/theme/infrastructure/globalThemeStore.ts +69 -0
  78. package/src/theme/infrastructure/storage/ThemeStorage.ts +93 -0
  79. package/src/theme/infrastructure/stores/themeStore.ts +109 -0
  80. package/src/typography/__tests__/colorValidationUtils.test.ts +180 -0
  81. package/src/typography/__tests__/textColorUtils.test.ts +185 -0
  82. package/src/typography/__tests__/textStyleUtils.test.ts +168 -0
  83. package/src/typography/domain/entities/TypographyTypes.ts +88 -0
  84. package/src/typography/index.ts +53 -0
  85. package/src/typography/presentation/utils/colorValidationUtils.ts +133 -0
  86. package/src/typography/presentation/utils/textColorUtils.ts +205 -0
  87. package/src/typography/presentation/utils/textStyleUtils.ts +159 -0
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Device Detection Utilities
3
+ *
4
+ * Utilities for detecting device types and screen dimensions.
5
+ * Follows universal design principles for cross-platform compatibility.
6
+ */
7
+
8
+ import { Dimensions } from 'react-native';
9
+ import { DEVICE_BREAKPOINTS, LAYOUT_CONSTANTS } from './config';
10
+ import { validateScreenDimensions } from './validation';
11
+
12
+ /**
13
+ * Helper function for device detection with fallback
14
+ * @param operation - Operation to perform
15
+ * @param fallback - Fallback value if operation fails
16
+ * @param warningMessage - Warning message for __DEV__
17
+ * @returns Operation result or fallback
18
+ */
19
+ const withDeviceDetectionFallback = <T>(
20
+ operation: () => T,
21
+ fallback: T,
22
+ warningMessage: string
23
+ ): T => {
24
+ try {
25
+ return operation();
26
+ } catch (error) {
27
+ if (__DEV__) {
28
+ console.warn(`[DeviceDetection] ${warningMessage}`);
29
+ }
30
+ return fallback;
31
+ }
32
+ };
33
+
34
+ /**
35
+ * Device type enum for conditional rendering
36
+ */
37
+ export enum DeviceType {
38
+ SMALL_PHONE = 'SMALL_PHONE',
39
+ MEDIUM_PHONE = 'MEDIUM_PHONE',
40
+ LARGE_PHONE = 'LARGE_PHONE',
41
+ TABLET = 'TABLET',
42
+ }
43
+
44
+ /**
45
+ * Get current screen dimensions
46
+ * @returns Screen width and height
47
+ * @throws ResponsiveValidationError if dimensions are invalid
48
+ */
49
+ export const getScreenDimensions = () => {
50
+ const { width, height } = Dimensions.get('window');
51
+
52
+ try {
53
+ validateScreenDimensions(width, height);
54
+ return { width, height };
55
+ } catch (error) {
56
+ if (__DEV__) {
57
+ console.warn('[getScreenDimensions] Invalid screen dimensions detected, using fallback values');
58
+ }
59
+ // Fallback to safe default dimensions
60
+ return { width: 414, height: 896 };
61
+ }
62
+ };
63
+
64
+ /**
65
+ * Check if current device is a small phone (iPhone 13 mini, SE)
66
+ * @returns true if device is a small phone
67
+ */
68
+ export const isSmallPhone = (): boolean => {
69
+ return withDeviceDetectionFallback(
70
+ () => {
71
+ const { width } = getScreenDimensions();
72
+ return width <= DEVICE_BREAKPOINTS.SMALL_PHONE;
73
+ },
74
+ false,
75
+ 'Error detecting device type, assuming standard phone'
76
+ );
77
+ };
78
+
79
+ /**
80
+ * Check if current device is a tablet (iPad)
81
+ * @returns true if device is a tablet
82
+ */
83
+ export const isTablet = (): boolean => {
84
+ return withDeviceDetectionFallback(
85
+ () => {
86
+ const { width } = getScreenDimensions();
87
+ return width >= DEVICE_BREAKPOINTS.SMALL_TABLET;
88
+ },
89
+ false,
90
+ 'Error detecting device type, assuming phone'
91
+ );
92
+ };
93
+
94
+ /**
95
+ * Check if device is in landscape mode
96
+ * @returns true if device is in landscape orientation
97
+ */
98
+ export const isLandscape = (): boolean => {
99
+ return withDeviceDetectionFallback(
100
+ () => {
101
+ const { width, height } = getScreenDimensions();
102
+ return width > height;
103
+ },
104
+ false,
105
+ 'Error detecting orientation, assuming portrait'
106
+ );
107
+ };
108
+
109
+ /**
110
+ * Get current device type
111
+ * @returns Device type enum value
112
+ */
113
+ export const getDeviceType = (): DeviceType => {
114
+ return withDeviceDetectionFallback(
115
+ () => {
116
+ const { width } = getScreenDimensions();
117
+
118
+ if (width <= DEVICE_BREAKPOINTS.SMALL_PHONE) {
119
+ return DeviceType.SMALL_PHONE;
120
+ } else if (width <= DEVICE_BREAKPOINTS.MEDIUM_PHONE) {
121
+ return DeviceType.MEDIUM_PHONE;
122
+ } else if (width <= DEVICE_BREAKPOINTS.LARGE_PHONE) {
123
+ return DeviceType.LARGE_PHONE;
124
+ }
125
+
126
+ return DeviceType.TABLET;
127
+ },
128
+ DeviceType.MEDIUM_PHONE,
129
+ 'Error detecting device type, assuming medium phone'
130
+ );
131
+ };
132
+
133
+ /**
134
+ * Responsive spacing multiplier
135
+ * Returns a multiplier for spacing based on device size
136
+ *
137
+ * @returns Spacing multiplier (0.9-1.2)
138
+ */
139
+ export const getSpacingMultiplier = (): number => {
140
+ return withDeviceDetectionFallback(
141
+ () => {
142
+ const { width } = getScreenDimensions();
143
+
144
+ if (width <= DEVICE_BREAKPOINTS.SMALL_PHONE) {
145
+ return LAYOUT_CONSTANTS.SPACING_MULTIPLIER_SMALL;
146
+ } else if (width >= DEVICE_BREAKPOINTS.TABLET) {
147
+ return LAYOUT_CONSTANTS.SPACING_MULTIPLIER_TABLET;
148
+ }
149
+
150
+ return LAYOUT_CONSTANTS.SPACING_MULTIPLIER_STANDARD;
151
+ },
152
+ LAYOUT_CONSTANTS.SPACING_MULTIPLIER_STANDARD,
153
+ 'Error calculating spacing multiplier, using fallback'
154
+ );
155
+ };
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Grid Utilities
3
+ * Responsive grid sizing and column calculations
4
+ */
5
+
6
+ import { getScreenDimensions } from './deviceDetection';
7
+ import { DEVICE_BREAKPOINTS, GRID_CONFIG } from './config';
8
+ import { validateNumber } from './validation';
9
+
10
+ /**
11
+ * Responsive grid columns
12
+ * Returns number of columns for grid layouts
13
+ *
14
+ * @param mobileColumns - Number of columns for mobile devices (default: 2)
15
+ * @param tabletColumns - Number of columns for tablet devices (default: 4)
16
+ * @returns Responsive number of grid columns
17
+ */
18
+ export const getResponsiveGridColumns = (
19
+ mobileColumns: number = GRID_CONFIG.DEFAULT_MOBILE_COLUMNS,
20
+ tabletColumns: number = GRID_CONFIG.DEFAULT_TABLET_COLUMNS
21
+ ): number => {
22
+ try {
23
+ const validatedMobile = validateNumber(mobileColumns, 'mobileColumns', 1, 20);
24
+ const validatedTablet = validateNumber(tabletColumns, 'tabletColumns', 1, 20);
25
+
26
+ const { width } = getScreenDimensions();
27
+ return width >= DEVICE_BREAKPOINTS.TABLET ? validatedTablet : validatedMobile;
28
+ } catch {
29
+ return 2;
30
+ }
31
+ };
32
+
33
+ export interface GridCellSizeConfig {
34
+ columns: number;
35
+ rows: number;
36
+ horizontalPadding?: number;
37
+ verticalPadding?: number;
38
+ gap?: number;
39
+ headerHeight?: number;
40
+ tabBarHeight?: number;
41
+ statusBarHeight?: number;
42
+ }
43
+
44
+ /**
45
+ * Responsive grid cell size
46
+ * Calculates optimal square cell size for a grid that fills available space
47
+ *
48
+ * @param config - Grid configuration
49
+ * @returns Responsive cell size (width = height for square cells)
50
+ */
51
+ export const getResponsiveGridCellSize = (config: GridCellSizeConfig): number => {
52
+ try {
53
+ const {
54
+ columns,
55
+ rows,
56
+ horizontalPadding = 32,
57
+ verticalPadding = 32,
58
+ gap = 8,
59
+ headerHeight = 120,
60
+ tabBarHeight = 80,
61
+ statusBarHeight = 50,
62
+ } = config;
63
+
64
+ const { width, height } = getScreenDimensions();
65
+
66
+ const totalHorizontalGap = gap * (columns - 1);
67
+ const availableWidth = width - horizontalPadding - totalHorizontalGap;
68
+ const maxCellWidth = availableWidth / columns;
69
+
70
+ const totalVerticalGap = gap * (rows - 1);
71
+ const usedHeight = headerHeight + tabBarHeight + statusBarHeight + verticalPadding;
72
+ const availableHeight = height - usedHeight - totalVerticalGap;
73
+ const maxCellHeight = availableHeight / rows;
74
+
75
+ return Math.floor(Math.min(maxCellWidth, maxCellHeight));
76
+ } catch {
77
+ return 60;
78
+ }
79
+ };
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @umituz/react-native-design-system-responsive - Public API
3
+ *
4
+ * Responsive design utilities for React Native - Screen dimensions, device detection,
5
+ * and responsive sizing utilities following Material Design 3 and iOS HIG principles.
6
+ *
7
+ * Usage:
8
+ * ```typescript
9
+ * import { useResponsive, isTablet, getResponsiveLogoSize } from '@umituz/react-native-design-system-responsive';
10
+ * ```
11
+ */
12
+
13
+ // Hook exports
14
+ export { useResponsive } from './useResponsive';
15
+ export type { UseResponsiveReturn } from './useResponsive';
16
+
17
+ // Utility function exports
18
+ export {
19
+ getScreenDimensions,
20
+ isSmallPhone,
21
+ isTablet,
22
+ getResponsiveLogoSize,
23
+ getResponsiveInputHeight,
24
+ getResponsiveHorizontalPadding,
25
+ getResponsiveBottomPosition,
26
+ getResponsiveFABPosition,
27
+ getResponsiveModalMaxHeight,
28
+ getResponsiveMinModalHeight,
29
+ getResponsiveIconContainerSize,
30
+ getResponsiveGridColumns,
31
+ getResponsiveGridCellSize,
32
+ type GridCellSizeConfig,
33
+ getResponsiveMaxWidth,
34
+ getResponsiveFontSize,
35
+ isLandscape,
36
+ getDeviceType,
37
+ DeviceType,
38
+ } from './responsive';
39
+
40
+ // Device detection exports
41
+ export { getSpacingMultiplier } from './deviceDetection';
42
+
43
+
44
+
45
+ // Platform constants exports
46
+ export {
47
+ IOS_HIG,
48
+ PLATFORM_CONSTANTS,
49
+ isValidTouchTarget,
50
+ getMinTouchTarget,
51
+ } from './platformConstants';
52
+
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Platform-Specific Constants
3
+ *
4
+ * Design system constants that ensure compliance with platform guidelines.
5
+ * These values are based on official Human Interface Guidelines (HIG) from Apple and Material Design from Google.
6
+ */
7
+
8
+ /**
9
+ * iOS Human Interface Guidelines (HIG) Constants
10
+ *
11
+ * @see https://developer.apple.com/design/human-interface-guidelines/layout
12
+ */
13
+ export const IOS_HIG = {
14
+ /**
15
+ * Minimum Touch Target Size
16
+ *
17
+ * Apple requires a minimum tappable area of 44pt x 44pt for ALL interactive controls.
18
+ * This is enforced during App Store review.
19
+ *
20
+ * @critical Violating this can result in App Store rejection
21
+ */
22
+ MIN_TOUCH_TARGET: 44,
23
+
24
+ /**
25
+ * Recommended Minimum Touch Target Size
26
+ *
27
+ * For better accessibility and usability, Apple recommends 48pt x 48pt.
28
+ */
29
+ RECOMMENDED_TOUCH_TARGET: 48,
30
+
31
+ /**
32
+ * Minimum Text Size
33
+ *
34
+ * Minimum font size for body text to ensure readability.
35
+ */
36
+ MIN_TEXT_SIZE: 17,
37
+
38
+
39
+ } as const;
40
+
41
+
42
+
43
+ /**
44
+ * Universal Platform Constants
45
+ *
46
+ * These values work across both iOS and Android, taking the more restrictive requirement.
47
+ */
48
+ export const PLATFORM_CONSTANTS = {
49
+ /**
50
+ * Minimum Touch Target Size
51
+ *
52
+ * Uses iOS requirement (44pt) as it's more restrictive than Android (48dp).
53
+ * This ensures compliance on both platforms.
54
+ */
55
+ MIN_TOUCH_TARGET: Math.max(IOS_HIG.MIN_TOUCH_TARGET, 48),
56
+
57
+ /**
58
+ * Recommended Touch Target Size
59
+ *
60
+ * Uses the higher value between iOS and Android recommendations.
61
+ */
62
+ RECOMMENDED_TOUCH_TARGET: 48,
63
+
64
+ /**
65
+ * Minimum Text Size
66
+ *
67
+ * Uses iOS requirement as it's larger.
68
+ */
69
+ MIN_TEXT_SIZE: Math.max(IOS_HIG.MIN_TEXT_SIZE, 14),
70
+ } as const;
71
+
72
+ /**
73
+ * Helper function to validate touch target size
74
+ *
75
+ * @param size - The size to validate (in pt/dp)
76
+ * @returns true if size meets platform requirements
77
+ */
78
+ export const isValidTouchTarget = (size: number): boolean => {
79
+ return size >= IOS_HIG.MIN_TOUCH_TARGET;
80
+ };
81
+
82
+ /**
83
+ * Helper function to get minimum touch target for component
84
+ *
85
+ * @param componentType - The type of component ('button' | 'input' | 'icon' | 'generic')
86
+ * @returns The minimum touch target size for that component type
87
+ */
88
+ export const getMinTouchTarget = (componentType: 'button' | 'input' | 'icon' | 'generic' = 'generic'): number => {
89
+ switch (componentType) {
90
+ case 'button':
91
+ case 'input':
92
+ return PLATFORM_CONSTANTS.RECOMMENDED_TOUCH_TARGET; // 48pt recommended for buttons and inputs
93
+ case 'icon':
94
+ case 'generic':
95
+ default:
96
+ return IOS_HIG.MIN_TOUCH_TARGET; // 44pt minimum for icons and generic elements
97
+ }
98
+ };
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Responsive Design Utilities
3
+ *
4
+ * Centralized responsive sizing and spacing utilities to prevent
5
+ * Apple App Store rejection due to layout issues on different devices.
6
+ *
7
+ * This is the main export file that imports from specialized modules.
8
+ */
9
+
10
+ // Device detection
11
+ export {
12
+ getScreenDimensions,
13
+ isSmallPhone,
14
+ isTablet,
15
+ isLandscape,
16
+ getDeviceType,
17
+ DeviceType,
18
+ } from './deviceDetection';
19
+
20
+ // Responsive sizing
21
+ export {
22
+ getResponsiveLogoSize,
23
+ getResponsiveInputHeight,
24
+ getResponsiveIconContainerSize,
25
+ getResponsiveMaxWidth,
26
+ getResponsiveFontSize,
27
+ getResponsiveGridColumns,
28
+ getResponsiveGridCellSize,
29
+ type GridCellSizeConfig,
30
+ } from './responsiveSizing';
31
+
32
+ // Responsive layout
33
+ export {
34
+ getResponsiveHorizontalPadding,
35
+ getResponsiveBottomPosition,
36
+ getResponsiveFABPosition,
37
+ getResponsiveModalMaxHeight,
38
+ getResponsiveMinModalHeight,
39
+ } from './responsiveLayout';
40
+
41
+ // Platform constants
42
+ export {
43
+ IOS_HIG,
44
+ PLATFORM_CONSTANTS,
45
+ isValidTouchTarget,
46
+ getMinTouchTarget,
47
+ } from './platformConstants';
48
+
49
+ // Configuration
50
+ export {
51
+ DEVICE_BREAKPOINTS,
52
+ RESPONSIVE_PERCENTAGES,
53
+ SIZE_CONSTRAINTS,
54
+ LAYOUT_CONSTANTS,
55
+ HEIGHT_THRESHOLDS,
56
+ GRID_CONFIG,
57
+ VALIDATION_CONSTRAINTS,
58
+ } from './config';
59
+
60
+
61
+
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Responsive Layout Utilities
3
+ * Layout utilities for positioning and spacing.
4
+ */
5
+
6
+ import { getScreenDimensions } from './deviceDetection';
7
+ import {
8
+ DEVICE_BREAKPOINTS,
9
+ LAYOUT_CONSTANTS,
10
+ HEIGHT_THRESHOLDS,
11
+ SIZE_CONSTRAINTS,
12
+ } from './config';
13
+ import { validateNumber, validateSafeAreaInsets } from './validation';
14
+
15
+ /**
16
+ * Responsive horizontal padding
17
+ * @param basePadding - Base padding value (default: 16)
18
+ * @param insets - Safe area insets object
19
+ */
20
+ export const getResponsiveHorizontalPadding = (
21
+ basePadding: number = LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE,
22
+ insets: { left?: number; right?: number } = { left: 0, right: 0 }
23
+ ): number => {
24
+ try {
25
+ const validatedBasePadding = validateNumber(basePadding, 'basePadding', 0, 100);
26
+ validateSafeAreaInsets(insets);
27
+
28
+ const { width } = getScreenDimensions();
29
+ const { left = 0, right = 0 } = insets;
30
+
31
+ if (width >= DEVICE_BREAKPOINTS.TABLET) {
32
+ const tabletPadding = validatedBasePadding * 1.5;
33
+ return Math.max(
34
+ tabletPadding,
35
+ left + LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE,
36
+ right + LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE
37
+ );
38
+ }
39
+
40
+ return Math.max(
41
+ validatedBasePadding,
42
+ left + LAYOUT_CONSTANTS.SAFE_AREA_OFFSET,
43
+ right + LAYOUT_CONSTANTS.SAFE_AREA_OFFSET
44
+ );
45
+ } catch {
46
+ return 16;
47
+ }
48
+ };
49
+
50
+ /**
51
+ * Responsive bottom positioning
52
+ * @param basePosition - Base bottom position (default: 32)
53
+ * @param insets - Safe area insets object
54
+ */
55
+ export const getResponsiveBottomPosition = (
56
+ basePosition: number = LAYOUT_CONSTANTS.BOTTOM_POSITION_BASE,
57
+ insets: { bottom?: number } = { bottom: 0 }
58
+ ): number => {
59
+ try {
60
+ const validatedBasePosition = validateNumber(basePosition, 'basePosition', 0, 500);
61
+ validateSafeAreaInsets(insets);
62
+
63
+ const { bottom = 0 } = insets;
64
+ return Math.max(validatedBasePosition, bottom + LAYOUT_CONSTANTS.SAFE_AREA_OFFSET);
65
+ } catch {
66
+ return 32;
67
+ }
68
+ };
69
+
70
+ /**
71
+ * Responsive FAB position
72
+ * @param insets - Safe area insets object
73
+ */
74
+ export const getResponsiveFABPosition = (
75
+ insets: { bottom?: number; right?: number } = { bottom: 0, right: 0 }
76
+ ): { bottom: number; right: number } => {
77
+ try {
78
+ validateSafeAreaInsets(insets);
79
+ const { width } = getScreenDimensions();
80
+ const { bottom = 0, right = 0 } = insets;
81
+
82
+ if (width >= DEVICE_BREAKPOINTS.TABLET) {
83
+ return {
84
+ bottom: Math.max(LAYOUT_CONSTANTS.FAB_BOTTOM_TABLET, bottom + LAYOUT_CONSTANTS.TAB_BAR_OFFSET),
85
+ right: Math.max(LAYOUT_CONSTANTS.FAB_RIGHT_TABLET, right + LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE),
86
+ };
87
+ }
88
+
89
+ return {
90
+ bottom: Math.max(LAYOUT_CONSTANTS.TAB_BAR_OFFSET, bottom + LAYOUT_CONSTANTS.SAFE_AREA_OFFSET),
91
+ right: Math.max(LAYOUT_CONSTANTS.FAB_RIGHT_PHONE, right + LAYOUT_CONSTANTS.SAFE_AREA_OFFSET),
92
+ };
93
+ } catch {
94
+ return { bottom: 90, right: 20 };
95
+ }
96
+ };
97
+
98
+ /**
99
+ * Responsive modal max height
100
+ */
101
+ export const getResponsiveModalMaxHeight = (): string => {
102
+ try {
103
+ const { height } = getScreenDimensions();
104
+
105
+ if (height <= HEIGHT_THRESHOLDS.SMALL_DEVICE) {
106
+ return LAYOUT_CONSTANTS.MODAL_HEIGHT_SMALL;
107
+ } else if (height >= HEIGHT_THRESHOLDS.LARGE_DEVICE) {
108
+ return LAYOUT_CONSTANTS.MODAL_HEIGHT_TABLET;
109
+ }
110
+
111
+ return LAYOUT_CONSTANTS.MODAL_HEIGHT_STANDARD;
112
+ } catch {
113
+ return '70%';
114
+ }
115
+ };
116
+
117
+ /**
118
+ * Responsive modal min height
119
+ */
120
+ export const getResponsiveMinModalHeight = (): number => {
121
+ try {
122
+ const { height } = getScreenDimensions();
123
+
124
+ if (height <= HEIGHT_THRESHOLDS.SMALL_DEVICE) {
125
+ const calculatedHeight = height * 0.4;
126
+ return Math.max(calculatedHeight, SIZE_CONSTRAINTS.MODAL_MIN_SMALL);
127
+ } else if (height >= HEIGHT_THRESHOLDS.LARGE_DEVICE) {
128
+ const calculatedHeight = height * 0.35;
129
+ return Math.min(Math.max(calculatedHeight, SIZE_CONSTRAINTS.MODAL_MIN_TABLET), SIZE_CONSTRAINTS.MODAL_MAX_TABLET);
130
+ }
131
+
132
+ const calculatedHeight = height * 0.45;
133
+ return Math.max(calculatedHeight, SIZE_CONSTRAINTS.MODAL_MIN_STANDARD);
134
+ } catch {
135
+ return 300;
136
+ }
137
+ };