🎨 Styling and Design Guide
Sistema de Diseño
Colores
export const Colors = {
primary: '#0A84FF',
primaryLight: '#3D9FFF',
primaryDark: '#0066CC',
secondary: '#5E5CE6',
accent: '#FF6B35',
success: '#30D158',
warning: '#FF9F0A',
error: '#FF453A',
background: '#F8F9FA',
surface: '#FFFFFF',
surfaceSecondary: '#F2F3F5',
text: '#1A1A2E',
textSecondary: '#6B7280',
textTertiary: '#9CA3AF',
textInverse: '#FFFFFF',
border: '#E5E7EB',
borderLight: '#F3F4F6',
};
Espaciado
export const Spacing = {
xs: 4,
sm: 8,
md: 12,
lg: 16,
xl: 20,
xxl: 24,
xxxl: 32,
};
padding: Spacing.md,
marginVertical: Spacing.lg,
gap: Spacing.sm,
Border Radius
export const BorderRadius = {
sm: 6,
md: 10,
lg: 14,
xl: 20,
full: 9999,
};
borderRadius: BorderRadius.md,
borderRadius: BorderRadius.full,
Tipografía
export const FontSizes = {
xs: 11,
sm: 13,
md: 15,
lg: 17,
xl: 20,
xxl: 24,
xxxl: 32,
display: 40,
};
export const FontWeights = {
regular: '400' as const,
medium: '500' as const,
semibold: '600' as const,
bold: '700' as const,
};
fontSize: FontSizes.lg,
fontWeight: FontWeights.semibold,
Patrones de Estilos
Contenedor Base
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: Colors.background,
},
content: {
padding: Spacing.lg,
},
});
Card
const styles = StyleSheet.create({
card: {
backgroundColor: Colors.surface,
borderRadius: BorderRadius.lg,
padding: Spacing.md,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.06,
shadowRadius: 8,
elevation: 3,
},
});
Lista con Separadores
const styles = StyleSheet.create({
listItem: {
paddingVertical: Spacing.md,
paddingHorizontal: Spacing.lg,
borderBottomWidth: 1,
borderBottomColor: Colors.borderLight,
},
});
const styles = StyleSheet.create({
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: Spacing.lg,
paddingVertical: Spacing.md,
backgroundColor: Colors.surface,
borderBottomWidth: 1,
borderBottomColor: Colors.borderLight,
},
});
Gradientes
import { LinearGradient } from 'expo-linear-gradient';
<LinearGradient
colors={Colors.gradients.primary}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
style={styles.gradientButton}
>
<Text style={styles.buttonText}>Gradient Button</Text>
</LinearGradient>
Colors.gradients.primary
Colors.gradients.sunset
Colors.gradients.ocean
Colors.gradients.purple
Sombras
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.06,
shadowRadius: 8,
elevation: 3,
shadowColor: '#000',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.1,
shadowRadius: 12,
elevation: 5,
shadowColor: '#000',
shadowOffset: { width: 0, height: 8 },
shadowOpacity: 0.15,
shadowRadius: 16,
elevation: 8,
Animaciones con Animated API
Fade In
import { Animated } from 'react-native';
function FadeInView({ children }) {
const fadeAnim = useRef(new Animated.Value(0)).current;
useEffect(() => {
Animated.timing(fadeAnim, {
toValue: 1,
duration: 300,
useNativeDriver: true,
}).start();
}, []);
return (
<Animated.View style={{ opacity: fadeAnim }}>
{children}
</Animated.View>
);
}
Scale on Press
function ScaleButton({ onPress, children }) {
const scale = useRef(new Animated.Value(1)).current;
const handlePressIn = () => {
Animated.spring(scale, {
toValue: 0.95,
useNativeDriver: true,
}).start();
};
const handlePressOut = () => {
Animated.spring(scale, {
toValue: 1,
useNativeDriver: true,
}).start();
};
return (
<TouchableOpacity
onPressIn={handlePressIn}
onPressOut={handlePressOut}
onPress={onPress}
activeOpacity={1}
>
<Animated.View style={{ transform: [{ scale }] }}>
{children}
</Animated.View>
</TouchableOpacity>
);
}
Dark Mode
const { isDark, colors } = useTheme();
const styles = StyleSheet.create({
container: {
backgroundColor: isDark ? colors.background : colors.backgroundLight,
},
text: {
color: isDark ? colors.textDark : colors.text,
},
});
Responsive Design
import { Dimensions, useWindowDimensions } from 'react-native';
function ResponsiveGrid() {
const { width } = useWindowDimensions();
const numColumns = width > 600 ? 3 : 2;
const itemWidth = (width - Spacing.lg * (numColumns + 1)) / numColumns;
return (
<FlatList
data={items}
numColumns={numColumns}
key={numColumns}
renderItem={({ item }) => (
<Card style={{ width: itemWidth }} item={item} />
)}
/>
);
}
Best Practices
- Usar constantes - Nunca hardcodear colores o espaciados
- Consistencia - Mantener el mismo espaciado en toda la app
- Accesibilidad - Contraste mínimo de 4.5:1 para texto
- Performance - Usar
useNativeDriver: true en animaciones
- Modularidad - Crear componentes para estilos repetidos