@umituz/react-native-design-system 2.8.43 → 2.8.45
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 +15 -14
- package/src/device/detection/deviceDetection.ts +10 -10
- package/src/onboarding/index.ts +1 -1
- package/src/onboarding/presentation/components/OnboardingFooter.tsx +4 -12
- package/src/onboarding/presentation/components/OnboardingScreenContent.tsx +0 -2
- package/src/onboarding/presentation/providers/OnboardingProvider.tsx +11 -1
- package/src/onboarding/presentation/screens/OnboardingScreen.tsx +8 -2
- package/src/responsive/compute/computeDeviceInfo.ts +7 -5
- package/src/responsive/compute/computeResponsiveSizes.ts +9 -7
- package/src/responsive/gridUtils.ts +6 -2
- package/src/responsive/responsiveModal.ts +4 -4
- package/src/responsive/responsiveSizing.ts +37 -13
- package/src/responsive/useResponsive.ts +14 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-design-system",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.45",
|
|
4
4
|
"description": "Universal design system for React Native apps - Consolidated package with atoms, molecules, organisms, theme, typography, responsive, safe area, exception, infinite scroll, UUID, image, timezone, offline, and onboarding utilities",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -60,16 +60,16 @@
|
|
|
60
60
|
"url": "https://github.com/umituz/react-native-design-system"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
|
-
"@tanstack/query-async-storage-persister": ">=5.0.0",
|
|
64
|
-
"@tanstack/react-query": ">=5.0.0",
|
|
65
|
-
"@tanstack/react-query-persist-client": ">=5.0.0",
|
|
66
63
|
"@expo/vector-icons": ">=15.0.0",
|
|
64
|
+
"@react-native-async-storage/async-storage": ">=1.18.0",
|
|
67
65
|
"@react-native-community/datetimepicker": ">=8.0.0",
|
|
68
66
|
"@react-native-community/slider": ">=4.0.0",
|
|
69
|
-
"@react-native-async-storage/async-storage": ">=1.18.0",
|
|
70
67
|
"@react-navigation/bottom-tabs": ">=7.0.0",
|
|
71
68
|
"@react-navigation/native": ">=7.0.0",
|
|
72
69
|
"@react-navigation/stack": ">=7.0.0",
|
|
70
|
+
"@tanstack/query-async-storage-persister": ">=5.0.0",
|
|
71
|
+
"@tanstack/react-query": ">=5.0.0",
|
|
72
|
+
"@tanstack/react-query-persist-client": ">=5.0.0",
|
|
73
73
|
"@umituz/react-native-haptics": "*",
|
|
74
74
|
"@umituz/react-native-localization": "*",
|
|
75
75
|
"@umituz/react-native-uuid": "*",
|
|
@@ -104,9 +104,6 @@
|
|
|
104
104
|
}
|
|
105
105
|
},
|
|
106
106
|
"devDependencies": {
|
|
107
|
-
"@tanstack/query-async-storage-persister": "^5.66.7",
|
|
108
|
-
"@tanstack/react-query": "^5.66.7",
|
|
109
|
-
"@tanstack/react-query-persist-client": "^5.66.7",
|
|
110
107
|
"@eslint/js": "^9.39.2",
|
|
111
108
|
"@expo/vector-icons": "^15.0.0",
|
|
112
109
|
"@react-native-async-storage/async-storage": "^2.2.0",
|
|
@@ -115,6 +112,9 @@
|
|
|
115
112
|
"@react-navigation/bottom-tabs": "^7.9.0",
|
|
116
113
|
"@react-navigation/native": "^7.1.26",
|
|
117
114
|
"@react-navigation/stack": "^7.6.13",
|
|
115
|
+
"@tanstack/query-async-storage-persister": "^5.66.7",
|
|
116
|
+
"@tanstack/react-query": "^5.66.7",
|
|
117
|
+
"@tanstack/react-query-persist-client": "^5.66.7",
|
|
118
118
|
"@testing-library/react": "^16.3.1",
|
|
119
119
|
"@testing-library/react-native": "^13.3.3",
|
|
120
120
|
"@types/jest": "^30.0.0",
|
|
@@ -135,19 +135,20 @@
|
|
|
135
135
|
"expo-device": "~7.0.2",
|
|
136
136
|
"expo-file-system": "^19.0.21",
|
|
137
137
|
"expo-font": "~14.0.0",
|
|
138
|
-
"expo-network": "~8.0.0",
|
|
139
|
-
"expo-video": "~3.0.0",
|
|
140
138
|
"expo-haptics": "~14.0.0",
|
|
139
|
+
"expo-image": "~3.0.11",
|
|
141
140
|
"expo-image-manipulator": "~13.0.0",
|
|
142
141
|
"expo-image-picker": "~16.0.0",
|
|
143
|
-
"expo-media-library": "~17.0.0",
|
|
144
|
-
"expo-image": "~3.0.11",
|
|
145
142
|
"expo-localization": "~16.0.1",
|
|
143
|
+
"expo-media-library": "~17.0.0",
|
|
144
|
+
"expo-modules-core": "^3.0.29",
|
|
145
|
+
"expo-network": "~8.0.0",
|
|
146
146
|
"expo-secure-store": "~14.0.0",
|
|
147
|
-
"i18next": "^25.0.0",
|
|
148
|
-
"react-i18next": "^16.0.0",
|
|
149
147
|
"expo-sharing": "~14.0.8",
|
|
148
|
+
"expo-video": "~3.0.0",
|
|
149
|
+
"i18next": "^25.0.0",
|
|
150
150
|
"react": "19.1.0",
|
|
151
|
+
"react-i18next": "^16.0.0",
|
|
151
152
|
"react-native": "0.81.5",
|
|
152
153
|
"react-native-gesture-handler": "^2.20.0",
|
|
153
154
|
"react-native-haptic-feedback": "^2.3.3",
|
|
@@ -60,9 +60,9 @@ export const isPhone = (): boolean => {
|
|
|
60
60
|
* Check if current device is a small phone (iPhone SE, 13 mini)
|
|
61
61
|
* Uses width breakpoint within phone category
|
|
62
62
|
*/
|
|
63
|
-
export const isSmallPhone = (): boolean => {
|
|
63
|
+
export const isSmallPhone = (offset?: { width: number }): boolean => {
|
|
64
64
|
if (!isPhone()) return false;
|
|
65
|
-
const { width } = getScreenDimensions();
|
|
65
|
+
const { width } = offset || getScreenDimensions();
|
|
66
66
|
return width <= DEVICE_BREAKPOINTS.SMALL_PHONE;
|
|
67
67
|
};
|
|
68
68
|
|
|
@@ -70,17 +70,17 @@ export const isSmallPhone = (): boolean => {
|
|
|
70
70
|
* Check if current device is a large phone (Pro Max, Plus models)
|
|
71
71
|
* Uses width breakpoint within phone category
|
|
72
72
|
*/
|
|
73
|
-
export const isLargePhone = (): boolean => {
|
|
73
|
+
export const isLargePhone = (offset?: { width: number }): boolean => {
|
|
74
74
|
if (!isPhone()) return false;
|
|
75
|
-
const { width } = getScreenDimensions();
|
|
75
|
+
const { width } = offset || getScreenDimensions();
|
|
76
76
|
return width >= DEVICE_BREAKPOINTS.MEDIUM_PHONE;
|
|
77
77
|
};
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
80
|
* Check if device is in landscape mode
|
|
81
81
|
*/
|
|
82
|
-
export const isLandscape = (): boolean => {
|
|
83
|
-
const { width, height } = getScreenDimensions();
|
|
82
|
+
export const isLandscape = (offset?: { width: number; height: number }): boolean => {
|
|
83
|
+
const { width, height } = offset || getScreenDimensions();
|
|
84
84
|
return width > height;
|
|
85
85
|
};
|
|
86
86
|
|
|
@@ -88,14 +88,14 @@ export const isLandscape = (): boolean => {
|
|
|
88
88
|
* Get current device type with fine-grained phone distinctions
|
|
89
89
|
* Uses expo-device for PHONE vs TABLET, width for phone size variants
|
|
90
90
|
*/
|
|
91
|
-
export const getDeviceType = (): DeviceType => {
|
|
91
|
+
export const getDeviceType = (offset?: { width: number }): DeviceType => {
|
|
92
92
|
// Use expo-device for primary detection
|
|
93
93
|
if (isTablet()) {
|
|
94
94
|
return DeviceType.TABLET;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
// For phones, use width for size variants
|
|
98
|
-
const { width } = getScreenDimensions();
|
|
98
|
+
const { width } = offset || getScreenDimensions();
|
|
99
99
|
|
|
100
100
|
if (width <= DEVICE_BREAKPOINTS.SMALL_PHONE) {
|
|
101
101
|
return DeviceType.SMALL_PHONE;
|
|
@@ -109,12 +109,12 @@ export const getDeviceType = (): DeviceType => {
|
|
|
109
109
|
/**
|
|
110
110
|
* Responsive spacing multiplier based on device type
|
|
111
111
|
*/
|
|
112
|
-
export const getSpacingMultiplier = (): number => {
|
|
112
|
+
export const getSpacingMultiplier = (offset?: { width: number }): number => {
|
|
113
113
|
if (isTablet()) {
|
|
114
114
|
return LAYOUT_CONSTANTS.SPACING_MULTIPLIER_TABLET;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
if (isSmallPhone()) {
|
|
117
|
+
if (isSmallPhone(offset)) {
|
|
118
118
|
return LAYOUT_CONSTANTS.SPACING_MULTIPLIER_SMALL;
|
|
119
119
|
}
|
|
120
120
|
|
package/src/onboarding/index.ts
CHANGED
|
@@ -68,7 +68,7 @@ export {
|
|
|
68
68
|
export { OnboardingScreen, type OnboardingScreenProps } from "./presentation/screens/OnboardingScreen";
|
|
69
69
|
export { OnboardingHeader, type OnboardingHeaderProps } from "./presentation/components/OnboardingHeader";
|
|
70
70
|
export { OnboardingFooter, type OnboardingFooterProps } from "./presentation/components/OnboardingFooter";
|
|
71
|
-
export { OnboardingProvider, type OnboardingProviderProps, useOnboardingProvider } from "./presentation/providers/OnboardingProvider";
|
|
71
|
+
export { OnboardingProvider, type OnboardingProviderProps, type OnboardingTranslations, useOnboardingProvider } from "./presentation/providers/OnboardingProvider";
|
|
72
72
|
export { BackgroundImageCollage, type CollageLayout, type BackgroundImageCollageProps } from "./presentation/components/BackgroundImageCollage";
|
|
73
73
|
export type { OnboardingTheme, OnboardingColors } from "./presentation/types/OnboardingTheme";
|
|
74
74
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { View, StyleSheet, TouchableOpacity } from "react-native";
|
|
3
3
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
4
|
-
import { useLocalization } from "@umituz/react-native-localization";
|
|
5
4
|
import { AtomicText } from "../../../atoms/AtomicText";
|
|
6
5
|
import { useOnboardingProvider } from "../providers/OnboardingProvider";
|
|
7
6
|
|
|
@@ -13,8 +12,6 @@ export interface OnboardingFooterProps {
|
|
|
13
12
|
showProgressBar?: boolean;
|
|
14
13
|
showDots?: boolean;
|
|
15
14
|
showProgressText?: boolean;
|
|
16
|
-
nextButtonText?: string;
|
|
17
|
-
getStartedButtonText?: string;
|
|
18
15
|
disabled?: boolean;
|
|
19
16
|
}
|
|
20
17
|
|
|
@@ -26,19 +23,14 @@ export const OnboardingFooter = ({
|
|
|
26
23
|
showProgressBar = true,
|
|
27
24
|
showDots = true,
|
|
28
25
|
showProgressText = true,
|
|
29
|
-
nextButtonText,
|
|
30
|
-
getStartedButtonText,
|
|
31
26
|
disabled = false,
|
|
32
27
|
}: OnboardingFooterProps) => {
|
|
33
28
|
const insets = useSafeAreaInsets();
|
|
34
|
-
const {
|
|
35
|
-
const {
|
|
36
|
-
theme: { colors },
|
|
37
|
-
} = useOnboardingProvider();
|
|
29
|
+
const { theme: { colors }, translations } = useOnboardingProvider();
|
|
38
30
|
|
|
39
31
|
const buttonText = isLastSlide
|
|
40
|
-
?
|
|
41
|
-
:
|
|
32
|
+
? translations.getStartedButton
|
|
33
|
+
: translations.nextButton;
|
|
42
34
|
|
|
43
35
|
const progressPercent = ((currentIndex + 1) / totalSlides) * 100;
|
|
44
36
|
|
|
@@ -95,7 +87,7 @@ export const OnboardingFooter = ({
|
|
|
95
87
|
type="labelSmall"
|
|
96
88
|
style={[styles.progressText, { color: colors.progressTextColor }]}
|
|
97
89
|
>
|
|
98
|
-
{currentIndex + 1} {
|
|
90
|
+
{currentIndex + 1} {translations.of} {totalSlides}
|
|
99
91
|
</AtomicText>
|
|
100
92
|
)}
|
|
101
93
|
</View>
|
|
@@ -127,8 +127,6 @@ export const OnboardingScreenContent = ({
|
|
|
127
127
|
showProgressBar={showProgressBar}
|
|
128
128
|
showDots={showDots}
|
|
129
129
|
showProgressText={showProgressText}
|
|
130
|
-
nextButtonText={nextButtonText}
|
|
131
|
-
getStartedButtonText={getStartedButtonText}
|
|
132
130
|
disabled={!isAnswerValid}
|
|
133
131
|
/>
|
|
134
132
|
)}
|
|
@@ -8,8 +8,15 @@
|
|
|
8
8
|
import React, { createContext, useContext, useMemo } from "react";
|
|
9
9
|
import type { OnboardingTheme, OnboardingColors } from "../types/OnboardingTheme";
|
|
10
10
|
|
|
11
|
+
export interface OnboardingTranslations {
|
|
12
|
+
nextButton: string;
|
|
13
|
+
getStartedButton: string;
|
|
14
|
+
of: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
11
17
|
interface OnboardingProviderValue {
|
|
12
18
|
theme: OnboardingTheme;
|
|
19
|
+
translations: OnboardingTranslations;
|
|
13
20
|
}
|
|
14
21
|
|
|
15
22
|
const OnboardingScope = createContext<OnboardingProviderValue | undefined>(undefined);
|
|
@@ -18,12 +25,14 @@ export interface OnboardingProviderProps {
|
|
|
18
25
|
children: React.ReactNode;
|
|
19
26
|
useCustomBackground: boolean;
|
|
20
27
|
colors: OnboardingColors;
|
|
28
|
+
translations: OnboardingTranslations;
|
|
21
29
|
}
|
|
22
30
|
|
|
23
31
|
export const OnboardingProvider = ({
|
|
24
32
|
children,
|
|
25
33
|
useCustomBackground,
|
|
26
34
|
colors,
|
|
35
|
+
translations,
|
|
27
36
|
}: OnboardingProviderProps) => {
|
|
28
37
|
const value = useMemo(
|
|
29
38
|
() => ({
|
|
@@ -31,8 +40,9 @@ export const OnboardingProvider = ({
|
|
|
31
40
|
colors,
|
|
32
41
|
useCustomBackground,
|
|
33
42
|
},
|
|
43
|
+
translations,
|
|
34
44
|
}),
|
|
35
|
-
[colors, useCustomBackground]
|
|
45
|
+
[colors, useCustomBackground, translations]
|
|
36
46
|
);
|
|
37
47
|
|
|
38
48
|
return (
|
|
@@ -13,7 +13,7 @@ import { useAppDesignTokens } from "../../../theme/hooks/useAppDesignTokens";
|
|
|
13
13
|
import type { OnboardingOptions } from "../../domain/entities/OnboardingOptions";
|
|
14
14
|
import { useOnboardingScreenState } from "../hooks/useOnboardingScreenState";
|
|
15
15
|
import { OnboardingScreenContent } from "../components/OnboardingScreenContent";
|
|
16
|
-
import { OnboardingProvider } from "../providers/OnboardingProvider";
|
|
16
|
+
import { OnboardingProvider, type OnboardingTranslations } from "../providers/OnboardingProvider";
|
|
17
17
|
import type { OnboardingColors } from "../types/OnboardingTheme";
|
|
18
18
|
|
|
19
19
|
export interface OnboardingScreenProps extends OnboardingOptions {
|
|
@@ -59,6 +59,11 @@ export interface OnboardingScreenProps extends OnboardingOptions {
|
|
|
59
59
|
* Theme colors for the onboarding (Optional - will use design tokens if not provided)
|
|
60
60
|
*/
|
|
61
61
|
themeColors?: OnboardingColors;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* All translations for the onboarding (required)
|
|
65
|
+
*/
|
|
66
|
+
translations: OnboardingTranslations;
|
|
62
67
|
}
|
|
63
68
|
|
|
64
69
|
export const OnboardingScreen = ({
|
|
@@ -82,6 +87,7 @@ export const OnboardingScreen = ({
|
|
|
82
87
|
useCustomBackground: globalUseCustomBackground = false,
|
|
83
88
|
themeVariant = "default",
|
|
84
89
|
themeColors: providedThemeColors,
|
|
90
|
+
translations,
|
|
85
91
|
}: OnboardingScreenProps) => {
|
|
86
92
|
if (__DEV__) {
|
|
87
93
|
console.log("[OnboardingScreen] Rendering with slides:", slides?.length);
|
|
@@ -147,7 +153,7 @@ export const OnboardingScreen = ({
|
|
|
147
153
|
}
|
|
148
154
|
|
|
149
155
|
return (
|
|
150
|
-
<OnboardingProvider useCustomBackground={useCustomBackground} colors={themeColors}>
|
|
156
|
+
<OnboardingProvider useCustomBackground={useCustomBackground} colors={themeColors} translations={translations}>
|
|
151
157
|
<OnboardingScreenContent
|
|
152
158
|
containerStyle={[styles.container, containerStyle]}
|
|
153
159
|
useCustomBackground={useCustomBackground}
|
|
@@ -13,10 +13,12 @@ export interface ComputedDeviceInfo {
|
|
|
13
13
|
readonly spacingMultiplier: number;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export const computeDeviceInfo = (
|
|
17
|
-
|
|
16
|
+
export const computeDeviceInfo = (
|
|
17
|
+
dimensions?: { width: number; height: number }
|
|
18
|
+
): ComputedDeviceInfo => ({
|
|
19
|
+
isSmallDevice: isSmallPhone(dimensions),
|
|
18
20
|
isTabletDevice: isTablet(),
|
|
19
|
-
isLandscapeDevice: isLandscape(),
|
|
20
|
-
deviceType: getDeviceType(),
|
|
21
|
-
spacingMultiplier: getSpacingMultiplier(),
|
|
21
|
+
isLandscapeDevice: isLandscape(dimensions),
|
|
22
|
+
deviceType: getDeviceType(dimensions),
|
|
23
|
+
spacingMultiplier: getSpacingMultiplier(dimensions),
|
|
22
24
|
});
|
|
@@ -25,14 +25,16 @@ export interface ComputedResponsiveSizes {
|
|
|
25
25
|
readonly gridColumns: number;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export const computeResponsiveSizes = (
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
export const computeResponsiveSizes = (
|
|
29
|
+
dimensions?: { width: number; height: number }
|
|
30
|
+
): ComputedResponsiveSizes => ({
|
|
31
|
+
logoSize: getResponsiveLogoSize(undefined, dimensions),
|
|
32
|
+
inputHeight: getResponsiveInputHeight(undefined, dimensions),
|
|
33
|
+
iconContainerSize: getResponsiveIconContainerSize(undefined, dimensions),
|
|
34
|
+
maxContentWidth: getResponsiveMaxWidth(undefined, dimensions),
|
|
33
35
|
minTouchTarget: getMinTouchTarget(),
|
|
34
|
-
modalMaxHeight: getResponsiveModalMaxHeight(),
|
|
35
|
-
modalMinHeight: getResponsiveMinModalHeight(),
|
|
36
|
+
modalMaxHeight: getResponsiveModalMaxHeight(dimensions),
|
|
37
|
+
modalMinHeight: getResponsiveMinModalHeight(dimensions),
|
|
36
38
|
gridColumns: getResponsiveGridColumns(),
|
|
37
39
|
});
|
|
38
40
|
|
|
@@ -46,9 +46,13 @@ export interface GridCellSizeConfig {
|
|
|
46
46
|
* Calculates optimal square cell size for a grid that fills available space
|
|
47
47
|
*
|
|
48
48
|
* @param config - Grid configuration
|
|
49
|
+
* @param dimensions - Optional dimensions override
|
|
49
50
|
* @returns Responsive cell size (width = height for square cells)
|
|
50
51
|
*/
|
|
51
|
-
export const getResponsiveGridCellSize = (
|
|
52
|
+
export const getResponsiveGridCellSize = (
|
|
53
|
+
config: GridCellSizeConfig,
|
|
54
|
+
dimensions?: { width: number; height: number }
|
|
55
|
+
): number => {
|
|
52
56
|
try {
|
|
53
57
|
const {
|
|
54
58
|
columns,
|
|
@@ -61,7 +65,7 @@ export const getResponsiveGridCellSize = (config: GridCellSizeConfig): number =>
|
|
|
61
65
|
statusBarHeight = 50,
|
|
62
66
|
} = config;
|
|
63
67
|
|
|
64
|
-
const { width, height } = getScreenDimensions();
|
|
68
|
+
const { width, height } = dimensions || getScreenDimensions();
|
|
65
69
|
|
|
66
70
|
const totalHorizontalGap = gap * (columns - 1);
|
|
67
71
|
const availableWidth = width - horizontalPadding - totalHorizontalGap;
|
|
@@ -32,9 +32,9 @@ export interface ResponsiveDialogLayout {
|
|
|
32
32
|
borderRadius: number;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export const getResponsiveModalMaxHeight = (): string => {
|
|
35
|
+
export const getResponsiveModalMaxHeight = (dimensions?: { height: number }): string => {
|
|
36
36
|
try {
|
|
37
|
-
const { height } = getScreenDimensions();
|
|
37
|
+
const { height } = dimensions || getScreenDimensions();
|
|
38
38
|
|
|
39
39
|
if (height <= HEIGHT_THRESHOLDS.SMALL_DEVICE) {
|
|
40
40
|
return LAYOUT_CONSTANTS.MODAL_HEIGHT_SMALL;
|
|
@@ -48,9 +48,9 @@ export const getResponsiveModalMaxHeight = (): string => {
|
|
|
48
48
|
}
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
export const getResponsiveMinModalHeight = (): number => {
|
|
51
|
+
export const getResponsiveMinModalHeight = (dimensions?: { height: number }): number => {
|
|
52
52
|
try {
|
|
53
|
-
const { height } = getScreenDimensions();
|
|
53
|
+
const { height } = dimensions || getScreenDimensions();
|
|
54
54
|
|
|
55
55
|
if (height <= HEIGHT_THRESHOLDS.SMALL_DEVICE) {
|
|
56
56
|
const calculatedHeight = height * MODAL_CONFIG.MIN_HEIGHT_PERCENT_SMALL;
|
|
@@ -22,11 +22,19 @@ export {
|
|
|
22
22
|
* Responsive logo/icon size
|
|
23
23
|
* @param baseSize - Base logo size (default: 140)
|
|
24
24
|
*/
|
|
25
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Responsive logo/icon size
|
|
27
|
+
* @param baseSize - Base logo size (default: 140)
|
|
28
|
+
* @param dimensions - Optional dimensions override
|
|
29
|
+
*/
|
|
30
|
+
export const getResponsiveLogoSize = (
|
|
31
|
+
baseSize: number = 140,
|
|
32
|
+
dimensions?: { width: number }
|
|
33
|
+
): number => {
|
|
26
34
|
try {
|
|
27
35
|
const validatedBaseSize = validateNumber(baseSize, 'baseSize', 50, 500);
|
|
28
|
-
const { width } = getScreenDimensions();
|
|
29
|
-
const isSmallPhoneDevice = isSmallPhone();
|
|
36
|
+
const { width } = dimensions || getScreenDimensions();
|
|
37
|
+
const isSmallPhoneDevice = isSmallPhone(dimensions);
|
|
30
38
|
const isTabletDevice = isTablet();
|
|
31
39
|
|
|
32
40
|
if (isSmallPhoneDevice) {
|
|
@@ -46,11 +54,15 @@ export const getResponsiveLogoSize = (baseSize: number = 140): number => {
|
|
|
46
54
|
/**
|
|
47
55
|
* Responsive multiline input height
|
|
48
56
|
* @param baseHeight - Base input height (default: 200)
|
|
57
|
+
* @param dimensions - Optional dimensions override
|
|
49
58
|
*/
|
|
50
|
-
export const getResponsiveInputHeight = (
|
|
59
|
+
export const getResponsiveInputHeight = (
|
|
60
|
+
baseHeight: number = 200,
|
|
61
|
+
dimensions?: { height: number }
|
|
62
|
+
): number => {
|
|
51
63
|
try {
|
|
52
64
|
const validatedBaseHeight = validateNumber(baseHeight, 'baseHeight', 50, 500);
|
|
53
|
-
const { height } = getScreenDimensions();
|
|
65
|
+
const { height } = dimensions || getScreenDimensions();
|
|
54
66
|
|
|
55
67
|
if (height <= HEIGHT_THRESHOLDS.SMALL_DEVICE) {
|
|
56
68
|
const calculatedHeight = safePercentage(height, RESPONSIVE_PERCENTAGES.INPUT_SMALL_DEVICE);
|
|
@@ -69,12 +81,16 @@ export const getResponsiveInputHeight = (baseHeight: number = 200): number => {
|
|
|
69
81
|
/**
|
|
70
82
|
* Responsive icon container size
|
|
71
83
|
* @param baseSize - Base container size (default: 140)
|
|
84
|
+
* @param dimensions - Optional dimensions override
|
|
72
85
|
*/
|
|
73
|
-
export const getResponsiveIconContainerSize = (
|
|
86
|
+
export const getResponsiveIconContainerSize = (
|
|
87
|
+
baseSize: number = 140,
|
|
88
|
+
dimensions?: { width: number }
|
|
89
|
+
): number => {
|
|
74
90
|
try {
|
|
75
91
|
const validatedBaseSize = validateNumber(baseSize, 'baseSize', 50, 300);
|
|
76
|
-
const { width } = getScreenDimensions();
|
|
77
|
-
const isSmallPhoneDevice = isSmallPhone();
|
|
92
|
+
const { width } = dimensions || getScreenDimensions();
|
|
93
|
+
const isSmallPhoneDevice = isSmallPhone(dimensions);
|
|
78
94
|
const isTabletDevice = isTablet();
|
|
79
95
|
|
|
80
96
|
if (isSmallPhoneDevice) {
|
|
@@ -94,12 +110,16 @@ export const getResponsiveIconContainerSize = (baseSize: number = 140): number =
|
|
|
94
110
|
/**
|
|
95
111
|
* Responsive max width for content
|
|
96
112
|
* @param baseWidth - Base content width (default: 400)
|
|
113
|
+
* @param dimensions - Optional dimensions override
|
|
97
114
|
*/
|
|
98
|
-
export const getResponsiveMaxWidth = (
|
|
115
|
+
export const getResponsiveMaxWidth = (
|
|
116
|
+
baseWidth: number = 400,
|
|
117
|
+
dimensions?: { width: number }
|
|
118
|
+
): number => {
|
|
99
119
|
try {
|
|
100
120
|
const validatedBaseWidth = validateNumber(baseWidth, 'baseWidth', 100, 1000);
|
|
101
|
-
const { width } = getScreenDimensions();
|
|
102
|
-
const isSmallPhoneDevice = isSmallPhone();
|
|
121
|
+
const { width } = dimensions || getScreenDimensions();
|
|
122
|
+
const isSmallPhoneDevice = isSmallPhone(dimensions);
|
|
103
123
|
const isTabletDevice = isTablet();
|
|
104
124
|
|
|
105
125
|
if (isSmallPhoneDevice) {
|
|
@@ -119,11 +139,15 @@ export const getResponsiveMaxWidth = (baseWidth: number = 400): number => {
|
|
|
119
139
|
/**
|
|
120
140
|
* Responsive font size
|
|
121
141
|
* @param baseFontSize - Base font size
|
|
142
|
+
* @param dimensions - Optional dimensions override
|
|
122
143
|
*/
|
|
123
|
-
export const getResponsiveFontSize = (
|
|
144
|
+
export const getResponsiveFontSize = (
|
|
145
|
+
baseFontSize: number,
|
|
146
|
+
dimensions?: { width: number }
|
|
147
|
+
): number => {
|
|
124
148
|
try {
|
|
125
149
|
const validatedBaseSize = validateFontSize(baseFontSize);
|
|
126
|
-
const isSmallPhoneDevice = isSmallPhone();
|
|
150
|
+
const isSmallPhoneDevice = isSmallPhone(dimensions);
|
|
127
151
|
const isTabletDevice = isTablet();
|
|
128
152
|
|
|
129
153
|
if (isSmallPhoneDevice) {
|
|
@@ -25,24 +25,24 @@ export const useResponsive = (): UseResponsiveReturn => {
|
|
|
25
25
|
|
|
26
26
|
// Memoize utility functions
|
|
27
27
|
const getLogoSize = useCallback(
|
|
28
|
-
(baseSize?: number) => getResponsiveLogoSize(baseSize),
|
|
29
|
-
[],
|
|
28
|
+
(baseSize?: number) => getResponsiveLogoSize(baseSize, { width }),
|
|
29
|
+
[width],
|
|
30
30
|
);
|
|
31
31
|
const getInputHeight = useCallback(
|
|
32
|
-
(baseHeight?: number) => getResponsiveInputHeight(baseHeight),
|
|
33
|
-
[],
|
|
32
|
+
(baseHeight?: number) => getResponsiveInputHeight(baseHeight, { height }),
|
|
33
|
+
[height],
|
|
34
34
|
);
|
|
35
35
|
const getIconSize = useCallback(
|
|
36
|
-
(baseSize?: number) => getResponsiveIconContainerSize(baseSize),
|
|
37
|
-
[],
|
|
36
|
+
(baseSize?: number) => getResponsiveIconContainerSize(baseSize, { width }),
|
|
37
|
+
[width],
|
|
38
38
|
);
|
|
39
39
|
const getMaxWidth = useCallback(
|
|
40
|
-
(baseWidth?: number) => getResponsiveMaxWidth(baseWidth),
|
|
41
|
-
[],
|
|
40
|
+
(baseWidth?: number) => getResponsiveMaxWidth(baseWidth, { width }),
|
|
41
|
+
[width],
|
|
42
42
|
);
|
|
43
43
|
const getFontSize = useCallback(
|
|
44
|
-
(baseFontSize: number) => getResponsiveFontSize(baseFontSize),
|
|
45
|
-
[],
|
|
44
|
+
(baseFontSize: number) => getResponsiveFontSize(baseFontSize, { width }),
|
|
45
|
+
[width],
|
|
46
46
|
);
|
|
47
47
|
const getGridCols = useCallback(
|
|
48
48
|
(mobile?: number, tablet?: number) =>
|
|
@@ -53,8 +53,9 @@ export const useResponsive = (): UseResponsiveReturn => {
|
|
|
53
53
|
// Compute all responsive values
|
|
54
54
|
const responsiveValues = useMemo(
|
|
55
55
|
() => {
|
|
56
|
-
const
|
|
57
|
-
const
|
|
56
|
+
const dimensions = { width, height };
|
|
57
|
+
const deviceInfo = computeDeviceInfo(dimensions);
|
|
58
|
+
const sizes = computeResponsiveSizes(dimensions);
|
|
58
59
|
const positioning = computeResponsivePositioning(insets);
|
|
59
60
|
const onboarding = computeOnboardingSizes(deviceInfo);
|
|
60
61
|
|
|
@@ -110,7 +111,7 @@ export const useResponsive = (): UseResponsiveReturn => {
|
|
|
110
111
|
getGridCols,
|
|
111
112
|
};
|
|
112
113
|
},
|
|
113
|
-
[width, height, insets],
|
|
114
|
+
[width, height, insets, getLogoSize, getInputHeight, getIconSize, getMaxWidth, getFontSize, getGridCols], // Added callbacks to dep array
|
|
114
115
|
);
|
|
115
116
|
|
|
116
117
|
return responsiveValues;
|