@umituz/react-native-design-system 2.0.9 → 2.0.11
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/molecules/BaseModal.tsx +98 -0
- package/src/molecules/index.ts +1 -0
- package/src/responsive/config.ts +40 -5
- package/src/responsive/index.ts +12 -0
- package/src/responsive/responsive.ts +17 -1
- package/src/responsive/responsiveLayout.ts +17 -56
- package/src/responsive/responsiveModal.ts +179 -0
- package/src/responsive/useResponsive.ts +16 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-design-system",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.11",
|
|
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",
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BaseModal Component
|
|
3
|
+
* Generic fullscreen modal with responsive design
|
|
4
|
+
* Used across all modals in the app for consistency
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import { View, Modal, StyleSheet, TouchableOpacity, ViewStyle } from 'react-native';
|
|
9
|
+
import { useAppDesignTokens } from '../theme';
|
|
10
|
+
import { useResponsive } from '../responsive';
|
|
11
|
+
|
|
12
|
+
export interface BaseModalProps {
|
|
13
|
+
visible: boolean;
|
|
14
|
+
onClose: () => void;
|
|
15
|
+
children: React.ReactNode;
|
|
16
|
+
dismissOnBackdrop?: boolean;
|
|
17
|
+
contentStyle?: ViewStyle;
|
|
18
|
+
testID?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const BaseModal: React.FC<BaseModalProps> = ({
|
|
22
|
+
visible,
|
|
23
|
+
onClose,
|
|
24
|
+
children,
|
|
25
|
+
dismissOnBackdrop = true,
|
|
26
|
+
contentStyle,
|
|
27
|
+
testID = 'base-modal',
|
|
28
|
+
}) => {
|
|
29
|
+
const tokens = useAppDesignTokens();
|
|
30
|
+
const { modalLayout } = useResponsive();
|
|
31
|
+
|
|
32
|
+
const handleBackdropPress = React.useCallback(() => {
|
|
33
|
+
if (dismissOnBackdrop) {
|
|
34
|
+
onClose();
|
|
35
|
+
}
|
|
36
|
+
}, [dismissOnBackdrop, onClose]);
|
|
37
|
+
|
|
38
|
+
if (!visible) return null;
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<Modal
|
|
42
|
+
visible={visible}
|
|
43
|
+
transparent
|
|
44
|
+
animationType="fade"
|
|
45
|
+
onRequestClose={onClose}
|
|
46
|
+
statusBarTranslucent
|
|
47
|
+
testID={testID}
|
|
48
|
+
>
|
|
49
|
+
<View style={styles.overlay}>
|
|
50
|
+
<TouchableOpacity
|
|
51
|
+
style={[
|
|
52
|
+
styles.backdrop,
|
|
53
|
+
{ backgroundColor: `rgba(0, 0, 0, ${modalLayout.backdropOpacity})` }
|
|
54
|
+
]}
|
|
55
|
+
activeOpacity={1}
|
|
56
|
+
onPress={handleBackdropPress}
|
|
57
|
+
testID={`${testID}-backdrop`}
|
|
58
|
+
/>
|
|
59
|
+
|
|
60
|
+
<View
|
|
61
|
+
style={[
|
|
62
|
+
styles.content,
|
|
63
|
+
{
|
|
64
|
+
width: modalLayout.width,
|
|
65
|
+
height: modalLayout.height,
|
|
66
|
+
borderRadius: modalLayout.borderRadius,
|
|
67
|
+
backgroundColor: tokens.colors.backgroundPrimary,
|
|
68
|
+
borderColor: tokens.colors.border,
|
|
69
|
+
},
|
|
70
|
+
contentStyle,
|
|
71
|
+
]}
|
|
72
|
+
testID={`${testID}-content`}
|
|
73
|
+
>
|
|
74
|
+
{children}
|
|
75
|
+
</View>
|
|
76
|
+
</View>
|
|
77
|
+
</Modal>
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const styles = StyleSheet.create({
|
|
82
|
+
overlay: {
|
|
83
|
+
flex: 1,
|
|
84
|
+
justifyContent: 'center',
|
|
85
|
+
alignItems: 'center',
|
|
86
|
+
},
|
|
87
|
+
backdrop: {
|
|
88
|
+
position: 'absolute',
|
|
89
|
+
top: 0,
|
|
90
|
+
left: 0,
|
|
91
|
+
right: 0,
|
|
92
|
+
bottom: 0,
|
|
93
|
+
},
|
|
94
|
+
content: {
|
|
95
|
+
overflow: 'hidden',
|
|
96
|
+
borderWidth: 1,
|
|
97
|
+
},
|
|
98
|
+
});
|
package/src/molecules/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ export { ListItem, type ListItemProps } from './ListItem';
|
|
|
9
9
|
export { SearchBar, type SearchBarProps } from './SearchBar';
|
|
10
10
|
export { IconContainer } from './IconContainer';
|
|
11
11
|
export { ScreenHeader, type ScreenHeaderProps } from './ScreenHeader';
|
|
12
|
+
export { BaseModal, type BaseModalProps } from './BaseModal';
|
|
12
13
|
export { ConfirmationModal } from './ConfirmationModalMain';
|
|
13
14
|
export { useConfirmationModal } from './confirmation-modal/useConfirmationModal';
|
|
14
15
|
|
package/src/responsive/config.ts
CHANGED
|
@@ -54,29 +54,64 @@ export const SIZE_CONSTRAINTS = {
|
|
|
54
54
|
LOGO_MAX_SMALL: 120, // Maximum logo size for small phones
|
|
55
55
|
LOGO_MIN_TABLET: 140, // Minimum logo size for tablets
|
|
56
56
|
LOGO_MAX_TABLET: 200, // Maximum logo size for tablets
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
// Input height constraints
|
|
59
59
|
INPUT_MAX_SMALL: 120, // Maximum input height for small devices
|
|
60
60
|
INPUT_MAX_MEDIUM: 150, // Maximum input height for medium devices
|
|
61
61
|
INPUT_MAX_LARGE: 200, // Maximum input height for large devices
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
// Icon container constraints
|
|
64
64
|
ICON_MAX_SMALL: 120, // Maximum icon container for small phones
|
|
65
65
|
ICON_MAX_TABLET: 180, // Maximum icon container for tablets
|
|
66
|
-
|
|
66
|
+
|
|
67
67
|
// Content width constraints
|
|
68
68
|
CONTENT_MAX_TABLET: 600, // Maximum content width for tablets
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
// Modal height constraints
|
|
71
71
|
MODAL_MIN_SMALL: 250, // Minimum modal height for small devices
|
|
72
72
|
MODAL_MIN_STANDARD: 300, // Minimum modal height for standard devices
|
|
73
73
|
MODAL_MIN_TABLET: 350, // Minimum modal height for tablets
|
|
74
74
|
MODAL_MAX_TABLET: 500, // Maximum modal height for tablets
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
// Font size constraints
|
|
77
77
|
FONT_MIN_SIZE: 11, // Minimum font size
|
|
78
78
|
} as const;
|
|
79
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Modal layout configuration
|
|
82
|
+
* Responsive values for modal/overlay components
|
|
83
|
+
*/
|
|
84
|
+
export const MODAL_CONFIG = {
|
|
85
|
+
// Width percentages by device type
|
|
86
|
+
WIDTH_PERCENT_PHONE: 0.92, // 92% of screen width for phones
|
|
87
|
+
WIDTH_PERCENT_TABLET: 0.75, // 75% of screen width for tablets
|
|
88
|
+
|
|
89
|
+
// Height percentages by device type
|
|
90
|
+
HEIGHT_PERCENT_SMALL: 0.85, // 85% of screen height for small devices
|
|
91
|
+
HEIGHT_PERCENT_STANDARD: 0.88, // 88% of screen height for standard devices
|
|
92
|
+
HEIGHT_PERCENT_TABLET: 0.80, // 80% of screen height for tablets
|
|
93
|
+
|
|
94
|
+
// Max width constraints
|
|
95
|
+
MAX_WIDTH_PHONE: 480, // Maximum modal width for phones
|
|
96
|
+
MAX_WIDTH_TABLET: 600, // Maximum modal width for tablets
|
|
97
|
+
|
|
98
|
+
// Border radius by device type
|
|
99
|
+
BORDER_RADIUS_PHONE: 32, // Border radius for phones
|
|
100
|
+
BORDER_RADIUS_TABLET: 24, // Border radius for tablets
|
|
101
|
+
|
|
102
|
+
// Backdrop opacity
|
|
103
|
+
BACKDROP_OPACITY_DEFAULT: 0.85, // Default backdrop opacity
|
|
104
|
+
|
|
105
|
+
// Bottom sheet specific
|
|
106
|
+
BOTTOM_SHEET_MIN_HEIGHT: 400, // Minimum height for bottom sheets
|
|
107
|
+
BOTTOM_SHEET_MAX_HEIGHT_PERCENT: 0.9, // Max height percentage for bottom sheets
|
|
108
|
+
|
|
109
|
+
// Dialog specific
|
|
110
|
+
DIALOG_WIDTH_PERCENT: 0.94, // Dialog width percentage
|
|
111
|
+
DIALOG_MAX_WIDTH: 500, // Maximum dialog width
|
|
112
|
+
DIALOG_MAX_HEIGHT_PERCENT: 0.85, // Dialog max height percentage
|
|
113
|
+
} as const;
|
|
114
|
+
|
|
80
115
|
/**
|
|
81
116
|
* Layout spacing and positioning
|
|
82
117
|
* These values control spacing, padding, and positioning
|
package/src/responsive/index.ts
CHANGED
|
@@ -26,6 +26,17 @@ export {
|
|
|
26
26
|
getResponsiveFABPosition,
|
|
27
27
|
getResponsiveModalMaxHeight,
|
|
28
28
|
getResponsiveMinModalHeight,
|
|
29
|
+
getResponsiveModalWidth,
|
|
30
|
+
getResponsiveModalHeight,
|
|
31
|
+
getResponsiveModalBorderRadius,
|
|
32
|
+
getResponsiveModalMaxWidth,
|
|
33
|
+
getResponsiveBackdropOpacity,
|
|
34
|
+
getResponsiveModalLayout,
|
|
35
|
+
getResponsiveBottomSheetLayout,
|
|
36
|
+
getResponsiveDialogLayout,
|
|
37
|
+
type ResponsiveModalLayout,
|
|
38
|
+
type ResponsiveBottomSheetLayout,
|
|
39
|
+
type ResponsiveDialogLayout,
|
|
29
40
|
getResponsiveIconContainerSize,
|
|
30
41
|
getResponsiveGridColumns,
|
|
31
42
|
getResponsiveGridCellSize,
|
|
@@ -35,6 +46,7 @@ export {
|
|
|
35
46
|
isLandscape,
|
|
36
47
|
getDeviceType,
|
|
37
48
|
DeviceType,
|
|
49
|
+
MODAL_CONFIG,
|
|
38
50
|
} from './responsive';
|
|
39
51
|
|
|
40
52
|
// Device detection exports
|
|
@@ -34,9 +34,24 @@ export {
|
|
|
34
34
|
getResponsiveHorizontalPadding,
|
|
35
35
|
getResponsiveBottomPosition,
|
|
36
36
|
getResponsiveFABPosition,
|
|
37
|
+
} from './responsiveLayout';
|
|
38
|
+
|
|
39
|
+
// Responsive modal utilities
|
|
40
|
+
export {
|
|
37
41
|
getResponsiveModalMaxHeight,
|
|
38
42
|
getResponsiveMinModalHeight,
|
|
39
|
-
|
|
43
|
+
getResponsiveModalWidth,
|
|
44
|
+
getResponsiveModalHeight,
|
|
45
|
+
getResponsiveModalBorderRadius,
|
|
46
|
+
getResponsiveModalMaxWidth,
|
|
47
|
+
getResponsiveBackdropOpacity,
|
|
48
|
+
getResponsiveModalLayout,
|
|
49
|
+
getResponsiveBottomSheetLayout,
|
|
50
|
+
getResponsiveDialogLayout,
|
|
51
|
+
type ResponsiveModalLayout,
|
|
52
|
+
type ResponsiveBottomSheetLayout,
|
|
53
|
+
type ResponsiveDialogLayout,
|
|
54
|
+
} from './responsiveModal';
|
|
40
55
|
|
|
41
56
|
// Platform constants
|
|
42
57
|
export {
|
|
@@ -55,6 +70,7 @@ export {
|
|
|
55
70
|
HEIGHT_THRESHOLDS,
|
|
56
71
|
GRID_CONFIG,
|
|
57
72
|
VALIDATION_CONSTRAINTS,
|
|
73
|
+
MODAL_CONFIG,
|
|
58
74
|
} from './config';
|
|
59
75
|
|
|
60
76
|
|
|
@@ -4,18 +4,11 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { getScreenDimensions } from './deviceDetection';
|
|
7
|
-
import {
|
|
8
|
-
DEVICE_BREAKPOINTS,
|
|
9
|
-
LAYOUT_CONSTANTS,
|
|
10
|
-
HEIGHT_THRESHOLDS,
|
|
11
|
-
SIZE_CONSTRAINTS,
|
|
12
|
-
} from './config';
|
|
7
|
+
import { DEVICE_BREAKPOINTS, LAYOUT_CONSTANTS } from './config';
|
|
13
8
|
import { validateNumber, validateSafeAreaInsets } from './validation';
|
|
14
9
|
|
|
15
10
|
/**
|
|
16
11
|
* Responsive horizontal padding
|
|
17
|
-
* @param basePadding - Base padding value (default: 16)
|
|
18
|
-
* @param insets - Safe area insets object
|
|
19
12
|
*/
|
|
20
13
|
export const getResponsiveHorizontalPadding = (
|
|
21
14
|
basePadding: number = LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE,
|
|
@@ -49,8 +42,6 @@ export const getResponsiveHorizontalPadding = (
|
|
|
49
42
|
|
|
50
43
|
/**
|
|
51
44
|
* Responsive bottom positioning
|
|
52
|
-
* @param basePosition - Base bottom position (default: 32)
|
|
53
|
-
* @param insets - Safe area insets object
|
|
54
45
|
*/
|
|
55
46
|
export const getResponsiveBottomPosition = (
|
|
56
47
|
basePosition: number = LAYOUT_CONSTANTS.BOTTOM_POSITION_BASE,
|
|
@@ -69,7 +60,6 @@ export const getResponsiveBottomPosition = (
|
|
|
69
60
|
|
|
70
61
|
/**
|
|
71
62
|
* Responsive FAB position
|
|
72
|
-
* @param insets - Safe area insets object
|
|
73
63
|
*/
|
|
74
64
|
export const getResponsiveFABPosition = (
|
|
75
65
|
insets: { bottom?: number; right?: number } = { bottom: 0, right: 0 }
|
|
@@ -81,57 +71,28 @@ export const getResponsiveFABPosition = (
|
|
|
81
71
|
|
|
82
72
|
if (width >= DEVICE_BREAKPOINTS.TABLET) {
|
|
83
73
|
return {
|
|
84
|
-
bottom: Math.max(
|
|
85
|
-
|
|
74
|
+
bottom: Math.max(
|
|
75
|
+
LAYOUT_CONSTANTS.FAB_BOTTOM_TABLET,
|
|
76
|
+
bottom + LAYOUT_CONSTANTS.TAB_BAR_OFFSET
|
|
77
|
+
),
|
|
78
|
+
right: Math.max(
|
|
79
|
+
LAYOUT_CONSTANTS.FAB_RIGHT_TABLET,
|
|
80
|
+
right + LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE
|
|
81
|
+
),
|
|
86
82
|
};
|
|
87
83
|
}
|
|
88
84
|
|
|
89
85
|
return {
|
|
90
|
-
bottom: Math.max(
|
|
91
|
-
|
|
86
|
+
bottom: Math.max(
|
|
87
|
+
LAYOUT_CONSTANTS.TAB_BAR_OFFSET,
|
|
88
|
+
bottom + LAYOUT_CONSTANTS.SAFE_AREA_OFFSET
|
|
89
|
+
),
|
|
90
|
+
right: Math.max(
|
|
91
|
+
LAYOUT_CONSTANTS.FAB_RIGHT_PHONE,
|
|
92
|
+
right + LAYOUT_CONSTANTS.SAFE_AREA_OFFSET
|
|
93
|
+
),
|
|
92
94
|
};
|
|
93
95
|
} catch {
|
|
94
96
|
return { bottom: 90, right: 20 };
|
|
95
97
|
}
|
|
96
98
|
};
|
|
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
|
-
};
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Responsive Modal Utilities
|
|
3
|
+
* Modal, bottom sheet, and dialog layout utilities.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { getScreenDimensions } from './deviceDetection';
|
|
7
|
+
import {
|
|
8
|
+
DEVICE_BREAKPOINTS,
|
|
9
|
+
LAYOUT_CONSTANTS,
|
|
10
|
+
HEIGHT_THRESHOLDS,
|
|
11
|
+
SIZE_CONSTRAINTS,
|
|
12
|
+
MODAL_CONFIG,
|
|
13
|
+
} from './config';
|
|
14
|
+
|
|
15
|
+
export interface ResponsiveModalLayout {
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
maxWidth: number;
|
|
19
|
+
borderRadius: number;
|
|
20
|
+
backdropOpacity: number;
|
|
21
|
+
horizontalPadding: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ResponsiveBottomSheetLayout {
|
|
25
|
+
minHeight: number;
|
|
26
|
+
maxHeight: number;
|
|
27
|
+
borderRadius: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface ResponsiveDialogLayout {
|
|
31
|
+
width: number;
|
|
32
|
+
maxHeight: number;
|
|
33
|
+
borderRadius: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const getResponsiveModalMaxHeight = (): string => {
|
|
37
|
+
try {
|
|
38
|
+
const { height } = getScreenDimensions();
|
|
39
|
+
|
|
40
|
+
if (height <= HEIGHT_THRESHOLDS.SMALL_DEVICE) {
|
|
41
|
+
return LAYOUT_CONSTANTS.MODAL_HEIGHT_SMALL;
|
|
42
|
+
} else if (height >= HEIGHT_THRESHOLDS.LARGE_DEVICE) {
|
|
43
|
+
return LAYOUT_CONSTANTS.MODAL_HEIGHT_TABLET;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return LAYOUT_CONSTANTS.MODAL_HEIGHT_STANDARD;
|
|
47
|
+
} catch {
|
|
48
|
+
return '70%';
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const getResponsiveMinModalHeight = (): number => {
|
|
53
|
+
try {
|
|
54
|
+
const { height } = getScreenDimensions();
|
|
55
|
+
|
|
56
|
+
if (height <= HEIGHT_THRESHOLDS.SMALL_DEVICE) {
|
|
57
|
+
const calculatedHeight = height * 0.4;
|
|
58
|
+
return Math.max(calculatedHeight, SIZE_CONSTRAINTS.MODAL_MIN_SMALL);
|
|
59
|
+
} else if (height >= HEIGHT_THRESHOLDS.LARGE_DEVICE) {
|
|
60
|
+
const calculatedHeight = height * 0.35;
|
|
61
|
+
return Math.min(
|
|
62
|
+
Math.max(calculatedHeight, SIZE_CONSTRAINTS.MODAL_MIN_TABLET),
|
|
63
|
+
SIZE_CONSTRAINTS.MODAL_MAX_TABLET
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const calculatedHeight = height * 0.45;
|
|
68
|
+
return Math.max(calculatedHeight, SIZE_CONSTRAINTS.MODAL_MIN_STANDARD);
|
|
69
|
+
} catch {
|
|
70
|
+
return 300;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const getResponsiveModalWidth = (): number => {
|
|
75
|
+
try {
|
|
76
|
+
const { width } = getScreenDimensions();
|
|
77
|
+
const isTabletDevice = width >= DEVICE_BREAKPOINTS.TABLET;
|
|
78
|
+
|
|
79
|
+
const widthPercent = isTabletDevice
|
|
80
|
+
? MODAL_CONFIG.WIDTH_PERCENT_TABLET
|
|
81
|
+
: MODAL_CONFIG.WIDTH_PERCENT_PHONE;
|
|
82
|
+
|
|
83
|
+
const maxWidth = isTabletDevice
|
|
84
|
+
? MODAL_CONFIG.MAX_WIDTH_TABLET
|
|
85
|
+
: MODAL_CONFIG.MAX_WIDTH_PHONE;
|
|
86
|
+
|
|
87
|
+
return Math.min(width * widthPercent, maxWidth);
|
|
88
|
+
} catch {
|
|
89
|
+
return 400;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const getResponsiveModalHeight = (): number => {
|
|
94
|
+
try {
|
|
95
|
+
const { width, height } = getScreenDimensions();
|
|
96
|
+
const isTabletDevice = width >= DEVICE_BREAKPOINTS.TABLET;
|
|
97
|
+
|
|
98
|
+
if (isTabletDevice) {
|
|
99
|
+
return height * MODAL_CONFIG.HEIGHT_PERCENT_TABLET;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (height <= HEIGHT_THRESHOLDS.SMALL_DEVICE) {
|
|
103
|
+
return height * MODAL_CONFIG.HEIGHT_PERCENT_SMALL;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return height * MODAL_CONFIG.HEIGHT_PERCENT_STANDARD;
|
|
107
|
+
} catch {
|
|
108
|
+
return 600;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const getResponsiveModalBorderRadius = (): number => {
|
|
113
|
+
try {
|
|
114
|
+
const { width } = getScreenDimensions();
|
|
115
|
+
const isTabletDevice = width >= DEVICE_BREAKPOINTS.TABLET;
|
|
116
|
+
|
|
117
|
+
return isTabletDevice
|
|
118
|
+
? MODAL_CONFIG.BORDER_RADIUS_TABLET
|
|
119
|
+
: MODAL_CONFIG.BORDER_RADIUS_PHONE;
|
|
120
|
+
} catch {
|
|
121
|
+
return 32;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export const getResponsiveModalMaxWidth = (): number => {
|
|
126
|
+
try {
|
|
127
|
+
const { width } = getScreenDimensions();
|
|
128
|
+
const isTabletDevice = width >= DEVICE_BREAKPOINTS.TABLET;
|
|
129
|
+
|
|
130
|
+
return isTabletDevice
|
|
131
|
+
? MODAL_CONFIG.MAX_WIDTH_TABLET
|
|
132
|
+
: MODAL_CONFIG.MAX_WIDTH_PHONE;
|
|
133
|
+
} catch {
|
|
134
|
+
return 480;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export const getResponsiveBackdropOpacity = (): number => {
|
|
139
|
+
return MODAL_CONFIG.BACKDROP_OPACITY_DEFAULT;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export const getResponsiveModalLayout = (): ResponsiveModalLayout => {
|
|
143
|
+
const { width } = getScreenDimensions();
|
|
144
|
+
const isTabletDevice = width >= DEVICE_BREAKPOINTS.TABLET;
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
width: getResponsiveModalWidth(),
|
|
148
|
+
height: getResponsiveModalHeight(),
|
|
149
|
+
maxWidth: getResponsiveModalMaxWidth(),
|
|
150
|
+
borderRadius: getResponsiveModalBorderRadius(),
|
|
151
|
+
backdropOpacity: getResponsiveBackdropOpacity(),
|
|
152
|
+
horizontalPadding: isTabletDevice
|
|
153
|
+
? LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE * 1.5
|
|
154
|
+
: LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE,
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
export const getResponsiveBottomSheetLayout = (): ResponsiveBottomSheetLayout => {
|
|
159
|
+
const { height } = getScreenDimensions();
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
minHeight: MODAL_CONFIG.BOTTOM_SHEET_MIN_HEIGHT,
|
|
163
|
+
maxHeight: height * MODAL_CONFIG.BOTTOM_SHEET_MAX_HEIGHT_PERCENT,
|
|
164
|
+
borderRadius: getResponsiveModalBorderRadius(),
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export const getResponsiveDialogLayout = (): ResponsiveDialogLayout => {
|
|
169
|
+
const { width, height } = getScreenDimensions();
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
width: Math.min(
|
|
173
|
+
width * MODAL_CONFIG.DIALOG_WIDTH_PERCENT,
|
|
174
|
+
MODAL_CONFIG.DIALOG_MAX_WIDTH
|
|
175
|
+
),
|
|
176
|
+
maxHeight: height * MODAL_CONFIG.DIALOG_MAX_HEIGHT_PERCENT,
|
|
177
|
+
borderRadius: getResponsiveModalBorderRadius(),
|
|
178
|
+
};
|
|
179
|
+
};
|
|
@@ -21,6 +21,9 @@ import {
|
|
|
21
21
|
getResponsiveFABPosition,
|
|
22
22
|
getResponsiveModalMaxHeight,
|
|
23
23
|
getResponsiveMinModalHeight,
|
|
24
|
+
getResponsiveModalLayout,
|
|
25
|
+
getResponsiveBottomSheetLayout,
|
|
26
|
+
getResponsiveDialogLayout,
|
|
24
27
|
getResponsiveIconContainerSize,
|
|
25
28
|
getResponsiveGridColumns,
|
|
26
29
|
getResponsiveMaxWidth,
|
|
@@ -31,6 +34,9 @@ import {
|
|
|
31
34
|
getDeviceType,
|
|
32
35
|
getMinTouchTarget,
|
|
33
36
|
DeviceType,
|
|
37
|
+
type ResponsiveModalLayout,
|
|
38
|
+
type ResponsiveBottomSheetLayout,
|
|
39
|
+
type ResponsiveDialogLayout,
|
|
34
40
|
} from './responsive';
|
|
35
41
|
import { getSpacingMultiplier } from './deviceDetection';
|
|
36
42
|
|
|
@@ -69,6 +75,11 @@ export interface UseResponsiveReturn {
|
|
|
69
75
|
gridColumns: number;
|
|
70
76
|
spacingMultiplier: number;
|
|
71
77
|
|
|
78
|
+
// Modal layouts (complete configurations)
|
|
79
|
+
modalLayout: ResponsiveModalLayout;
|
|
80
|
+
bottomSheetLayout: ResponsiveBottomSheetLayout;
|
|
81
|
+
dialogLayout: ResponsiveDialogLayout;
|
|
82
|
+
|
|
72
83
|
// Utility functions
|
|
73
84
|
getLogoSize: (baseSize?: number) => number;
|
|
74
85
|
getInputHeight: (baseHeight?: number) => number;
|
|
@@ -125,6 +136,11 @@ export const useResponsive = (): UseResponsiveReturn => {
|
|
|
125
136
|
gridColumns: getResponsiveGridColumns(),
|
|
126
137
|
spacingMultiplier: getSpacingMultiplier(),
|
|
127
138
|
|
|
139
|
+
// Modal layouts (complete configurations)
|
|
140
|
+
modalLayout: getResponsiveModalLayout(),
|
|
141
|
+
bottomSheetLayout: getResponsiveBottomSheetLayout(),
|
|
142
|
+
dialogLayout: getResponsiveDialogLayout(),
|
|
143
|
+
|
|
128
144
|
// Utility functions (memoized)
|
|
129
145
|
getLogoSize,
|
|
130
146
|
getInputHeight,
|