Skip to content

Instantly share code, notes, and snippets.

@zacharytyhacz
Created February 9, 2025 01:24
Show Gist options
  • Save zacharytyhacz/3fe831a062f0713aaea41e9c649dbba6 to your computer and use it in GitHub Desktop.
Save zacharytyhacz/3fe831a062f0713aaea41e9c649dbba6 to your computer and use it in GitHub Desktop.
react native useResponsiveStyles.ts hook
import { useMemo, useCallback } from 'react'
import {
useWindowDimensions,
StyleSheet,
ViewStyle,
TextStyle,
ImageStyle
} from "react-native";
const BREAKPOINTS = {
mobile: 0,
tablet: 768,
desktop: 1024,
};
// Define allowed style types
type StyleObject = ViewStyle | TextStyle | ImageStyle;
// Ensure `mobile`, `tablet`, `desktop` must have the same keys as `shared`
type ResponsiveStyles<T extends Record<string, StyleObject>> = {
base: T;
mobile?: Partial<{ [K in keyof T]: StyleObject }>;
tablet?: Partial<{ [K in keyof T]: StyleObject }>;
desktop?: Partial<{ [K in keyof T]: StyleObject }>;
};
export function useResponsiveStyles<T extends Record<string, StyleObject>>(styles: ResponsiveStyles<T>) {
const { width } = useWindowDimensions();
// Merge shared styles as base for each key
const mergeStyles = useCallback((base: T, override?: Partial<{ [K in keyof T]: StyleObject }>): T => {
const result: Partial<T> = { ...base };
if (override) {
for (const key in base) {
result[key] = { ...base[key], ...(override[key] || {}) };
}
}
return result as T;
}, [])
const generatedStyles = useMemo(() => {
let responsiveStyles: T = styles.base;
if (width >= BREAKPOINTS.tablet && styles.tablet) {
responsiveStyles = mergeStyles(responsiveStyles, styles.tablet);
}
if (width >= BREAKPOINTS.desktop && styles.desktop) {
responsiveStyles = mergeStyles(responsiveStyles, styles.desktop);
}
if (width < BREAKPOINTS.tablet) {
responsiveStyles = mergeStyles(responsiveStyles, styles.mobile);
}
return StyleSheet.create(responsiveStyles) as T;
}, [width, styles]);
return generatedStyles;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment