Amba-Agent-App/lib/utils/responsive.ts
2026-01-16 00:22:35 +03:00

104 lines
3.0 KiB
TypeScript

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<T>(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);
}