🧩 Components Guide

Componentes Disponibles

1. Button

Botón versátil con múltiples variantes y estados.

import { Button } from '@/components/Button';

// Variantes disponibles
<Button title="Primary" variant="primary" onPress={handlePress} />
<Button title="Secondary" variant="secondary" onPress={handlePress} />
<Button title="Outline" variant="outline" onPress={handlePress} />
<Button title="Ghost" variant="ghost" onPress={handlePress} />
<Button title="Gradient" variant="gradient" onPress={handlePress} />

// Tamaños
<Button title="Small" size="small" />
<Button title="Medium" size="medium" />
<Button title="Large" size="large" />

// Con icono
<Button 
  title="Add" 
  icon={<Plus size={18} color={Colors.textInverse} />}
  onPress={handlePress}
/>

// Estado de carga
<Button title="Loading" loading={true} />

// Deshabilitado
<Button title="Disabled" disabled={true} />

Props:

PropTipoDefaultDescripción
titlestringrequiredTexto del botón
onPress() => void-Handler de click
variant'primary' | 'secondary' | 'outline' | 'ghost' | 'gradient''primary'Estilo visual
size'small' | 'medium' | 'large''medium'Tamaño
loadingbooleanfalseEstado de carga
disabledbooleanfalseDeshabilitar
iconReactNode-Icono a mostrar

2. Card

Tarjeta para mostrar items con imagen, título y detalles.

import { Card } from '@/components/Card';

// Card default
<Card 
  item={item}
  onPress={() => handleItemPress(item.id)}
  onFavorite={() => toggleFavorite(item.id)}
  isFavorite={isFavorite(item.id)}
/>

// Card horizontal (para listas)
<Card 
  item={item}
  variant="horizontal"
  onPress={handlePress}
/>

// Card compacta (para carruseles)
<Card 
  item={item}
  variant="compact"
  onPress={handlePress}
/>

Props:

PropTipoDefaultDescripción
itemItemrequiredDatos del item
onPress() => void-Handler de click
onFavorite() => void-Handler de favorito
isFavoritebooleanfalseEstado de favorito
variant'default' | 'compact' | 'horizontal''default'Variante visual

3. Input

Campo de entrada con validación y estados.

import { Input } from '@/components/Input';

// Input básico
<Input
  label="Email"
  value={email}
  onChangeText={setEmail}
  placeholder="correo@ejemplo.com"
  keyboardType="email-address"
/>

// Con validación
<Input
  label="Contraseña"
  value={password}
  onChangeText={setPassword}
  secureTextEntry
  error={errors.password}
/>

// Con icono
<Input
  label="Buscar"
  value={search}
  onChangeText={setSearch}
  leftIcon={<Search size={20} color={Colors.textTertiary} />}
/>

// Textarea
<Input
  label="Descripción"
  value={description}
  onChangeText={setDescription}
  multiline
  numberOfLines={4}
/>

Props:

PropTipoDefaultDescripción
labelstring-Etiqueta del campo
valuestringrequiredValor actual
onChangeText(text: string) => voidrequiredHandler de cambio
placeholderstring-Placeholder
errorstring-Mensaje de error
leftIconReactNode-Icono izquierdo
rightIconReactNode-Icono derecho
secureTextEntrybooleanfalseCampo de contraseña
multilinebooleanfalseTextarea

4. Avatar

Componente de avatar con imagen o iniciales.

import { Avatar } from '@/components/Avatar';

// Con imagen
<Avatar 
  source="https://example.com/avatar.jpg"
  name="John Doe"
  size="large"
/>

// Sin imagen (muestra iniciales)
<Avatar 
  name="John Doe"
  size="medium"
/>

// Tamaños disponibles
<Avatar name="JD" size="small" />   // 32px
<Avatar name="JD" size="medium" />  // 48px
<Avatar name="JD" size="large" />   // 64px
<Avatar name="JD" size="xlarge" />  // 96px

// Con borde de estado
<Avatar 
  name="JD" 
  showBorder 
  borderColor={Colors.success}
/>

5. SkeletonLoader

Placeholder animado para estados de carga.

import { SkeletonLoader } from '@/components/SkeletonLoader';

// Rectángulo
<SkeletonLoader width={200} height={20} />

// Círculo
<SkeletonLoader width={48} height={48} borderRadius={24} />

// Card skeleton
<SkeletonLoader width="100%" height={200} borderRadius={12} />

6. EmptyState

Empty state con mensaje y acción.

import { EmptyState } from '@/components/EmptyState';

<EmptyState
  icon="Heart"
  title="No hay favoritos"
  description="Los items que marques como favoritos aparecerán aquí"
  actionTitle="Explorar"
  onAction={() => router.push('/explore')}
/>

7. Toast

Notificaciones temporales.

import { useToast } from '@/contexts/ToastContext';

const { showToast } = useToast();

// Tipos de toast
showToast('Operación exitosa', 'success');
showToast('Hubo un error', 'error');
showToast('Advertencia', 'warning');
showToast('Información', 'info');

Creando Nuevos Componentes

Plantilla Base

import React from 'react';
import { View, Text, StyleSheet, ViewStyle } from 'react-native';
import { Colors, Spacing, FontSizes, FontWeights, BorderRadius } from '@/constants/colors';

interface MyComponentProps {
  title: string;
  subtitle?: string;
  style?: ViewStyle;
  testID?: string;
}

export function MyComponent({ 
  title, 
  subtitle, 
  style, 
  testID 
}: MyComponentProps) {
  return (
    <View style={[styles.container, style]} testID={testID}>
      <Text style={styles.title}>{title}</Text>
      {subtitle && <Text style={styles.subtitle}>{subtitle}</Text>}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    backgroundColor: Colors.surface,
    padding: Spacing.md,
    borderRadius: BorderRadius.md,
  },
  title: {
    fontSize: FontSizes.lg,
    fontWeight: FontWeights.semibold,
    color: Colors.text,
  },
  subtitle: {
    fontSize: FontSizes.sm,
    color: Colors.textSecondary,
    marginTop: Spacing.xs,
  },
});

Checklist para Nuevos Componentes

  • Definir interface de Props con tipos correctos
  • Incluir style prop para personalización
  • Incluir testID prop para testing
  • Usar constantes de colors.ts para estilos
  • Manejar estados: loading, error, disabled
  • Agregar feedback táctil (haptics) si es interactivo
  • Documentar props y ejemplos de uso