import { Dimensions, PixelRatio, Platform } from 'react-native'; // Base dimensions (design reference - typically iPhone 14/15 or similar) const BASE_WIDTH = 390; const BASE_HEIGHT = 844; const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window'); /** * Scale a value based on screen width (horizontal scaling) * Use for: horizontal padding, margins, widths, font sizes */ export function scale(size: number): number { const scaleFactor = SCREEN_WIDTH / BASE_WIDTH; const newSize = size * scaleFactor; if (Platform.OS === 'web') { // On web, respect user zoom settings by using rem-like scaling return size; } return Math.round(PixelRatio.roundToNearestPixel(newSize)); } /** * Scale a value based on screen height (vertical scaling) * Use for: vertical padding, margins, heights */ export function verticalScale(size: number): number { const scaleFactor = SCREEN_HEIGHT / BASE_HEIGHT; const newSize = size * scaleFactor; if (Platform.OS === 'web') { return size; } return Math.round(PixelRatio.roundToNearestPixel(newSize)); } /** * Moderate scaling - scales less aggressively (recommended for most use cases) * Use for: font sizes, icon sizes, border radius * @param factor - how much to scale (0 = no scaling, 1 = full scaling, default 0.5) */ export function moderateScale(size: number, factor: number = 0.5): number { const scaleFactor = SCREEN_WIDTH / BASE_WIDTH; const newSize = size + (scaleFactor - 1) * size * factor; if (Platform.OS === 'web') { return size; } return Math.round(PixelRatio.roundToNearestPixel(newSize)); } /** * Get responsive value based on screen size breakpoints * Use for: completely different layouts at different sizes */ export function responsive(options: { small?: T; // < 375px (iPhone SE, small phones) medium?: T; // 375-428px (most phones) large?: T; // > 428px (tablets, large phones, web) default: T; }): T { if (SCREEN_WIDTH < 375) { return options.small ?? options.default; } if (SCREEN_WIDTH <= 428) { return options.medium ?? options.default; } return options.large ?? options.default; } /** * Check if device is a tablet or large screen */ export function isTablet(): boolean { const aspectRatio = SCREEN_HEIGHT / SCREEN_WIDTH; return ( (Platform.OS !== 'web' && SCREEN_WIDTH >= 768) || (Platform.OS === 'web' && SCREEN_WIDTH >= 1024) || aspectRatio < 1.6 ); } /** * Get screen dimensions (updates on rotation/resize) */ export function getScreenDimensions() { const { width, height } = Dimensions.get('window'); return { width, height }; } // Font scaling with accessibility support export function scaledFontSize(size: number): number { const scaled = moderateScale(size, 0.3); // Respect system font scaling but cap it to prevent extreme sizes const maxScale = 1.3; const fontScale = Math.min(PixelRatio.getFontScale(), maxScale); return Math.round(scaled * fontScale); }