# Sistema de Diseño xFarma - Componentes Base

## 🧩 Componentes Base

Los **componentes base** son bloques de construcción reutilizables que implementan el sistema de diseño de xFarma. Estos componentes están optimizados para uso común y garantizan consistencia visual en toda la aplicación.

---

## 📦 Componentes Disponibles

### 1. BaseCard - Contenedor Universal

Componente para crear tarjetas (cards) consistentes con variantes y sombras configurables.

#### Props

| Prop | Tipo | Default | Descripción |
|------|------|---------|-------------|
| `children` | node | - | Contenido de la tarjeta |
| `variant` | string | `"default"` | Variante visual (`"default"`, `"highlighted"`) |
| `shadow` | string | `"sm"` | Tamaño de sombra (`"none"`, `"sm"`, `"md"`, `"lg"`, `"xl"`) |
| `padding` | string | `SPACING["m"]` | Padding personalizado |
| `className` | string | `""` | Clases CSS adicionales |

#### Variantes

- **`default`**: Tarjeta estándar con fondo blanco y borde sutil
- **`highlighted`**: Tarjeta destacada con borde izquierdo coloreado y fondo terciario

#### Ejemplos de Uso

```python
from dash import html
from components.base import BaseCard

# Card básica
basic_card = BaseCard(
    children=[
        html.H4("Título de la Card"),
        html.P("Este es el contenido de la card.")
    ]
)

# Card destacada con sombra grande
highlighted_card = BaseCard(
    children=[
        html.H4("¡Importante!"),
        html.P("Esta card está destacada.")
    ],
    variant="highlighted",
    shadow="lg"
)

# Card sin sombra con padding personalizado
custom_card = BaseCard(
    children=[html.P("Card personalizada")],
    shadow="none",
    padding="32px"
)
```

#### Cuándo Usar

- ✅ **Contenedores de información** (KPIs, resúmenes, métricas)
- ✅ **Agrupación de controles** (formularios, filtros)
- ✅ **Listas de items** con separación visual
- ✅ **Widgets del dashboard**

#### Buenas Prácticas

```python
# ✅ CORRECTO: Usar BaseCard para contenedores
from components.base import BaseCard

card = BaseCard(
    children=[...],
    variant="default",
    shadow="sm"
)

# ❌ INCORRECTO: Crear cards manualmente con estilos hardcoded
import dash_bootstrap_components as dbc

card = dbc.Card(
    children=[...],
    style={"padding": "16px", "boxShadow": "0 2px 4px rgba(0,0,0,0.1)"}
)
```

---

### 2. BaseButton - Botones Consistentes

Componente para crear botones con variantes de color y tamaños estandarizados.

#### Props

| Prop | Tipo | Default | Descripción |
|------|------|---------|-------------|
| `children` | node | - | Texto o contenido del botón |
| `variant` | string | `"primary"` | Variante de color (`"primary"`, `"secondary"`, `"success"`, `"danger"`, `"warning"`, `"info"`) |
| `size` | string | `"md"` | Tamaño del botón (`"sm"`, `"md"`, `"lg"`) |
| `outline` | bool | `False` | Si `True`, usa estilo outline |
| `disabled` | bool | `False` | Si `True`, deshabilita el botón |
| `className` | string | `""` | Clases CSS adicionales |

#### Variantes

- **`primary`**: Botón principal (azul oscuro) - Acción primaria
- **`secondary`**: Botón secundario (gris) - Acción secundaria
- **`success`**: Botón de éxito (verde) - Confirmaciones, guardados
- **`danger`**: Botón de peligro (rojo) - Eliminaciones, acciones destructivas
- **`warning`**: Botón de advertencia (naranja) - Acciones que requieren precaución
- **`info`**: Botón informativo (azul claro) - Información adicional

#### Tamaños

- **`sm`**: Pequeño (padding: 4px 8px, fontSize: 0.875rem)
- **`md`**: Medio (padding: 8px 16px, fontSize: 1rem) - **Default**
- **`lg`**: Grande (padding: 16px 24px, fontSize: 1.125rem)

#### Ejemplos de Uso

```python
from components.base import BaseButton

# Botón primario estándar
primary_btn = BaseButton("Guardar", variant="primary")

# Botón outline secundario
secondary_btn = BaseButton("Cancelar", variant="secondary", outline=True)

# Botón pequeño de peligro
delete_btn = BaseButton("Eliminar", variant="danger", size="sm")

# Botón grande de éxito
submit_btn = BaseButton("Enviar Formulario", variant="success", size="lg")

# Botón deshabilitado
disabled_btn = BaseButton("No Disponible", variant="primary", disabled=True)
```

#### Cuándo Usar Cada Variante

| Variante | Uso Recomendado |
|----------|-----------------|
| `primary` | Acción principal de la página/sección (guardar, continuar) |
| `secondary` | Acciones secundarias (cancelar, volver) |
| `success` | Confirmaciones exitosas (guardar, aprobar) |
| `danger` | Acciones destructivas (eliminar, descartar) |
| `warning` | Acciones que requieren precaución (resetear, sobrescribir) |
| `info` | Información adicional (ver detalles, ayuda) |

#### Uso con Dash Callbacks

BaseButton está diseñado para integrarse perfectamente con el sistema de callbacks de Dash. Usa el parámetro `id` para identificar botones y `n_clicks` como Input en los callbacks.

```python
from dash import callback, Input, Output
from components.base import BaseButton

# Crear botón con ID para callback
button = BaseButton(
    "Guardar Cambios",
    variant="success",
    id="save-button"  # ID único para el callback
)

# Callback que reacciona al click del botón
@callback(
    Output("status-message", "children"),
    Input("save-button", "n_clicks"),
    prevent_initial_call=True
)
def handle_save(n_clicks):
    """Callback ejecutado cuando se hace click en el botón"""
    if n_clicks:
        # Lógica de guardado
        return "Cambios guardados exitosamente"
    return ""
```

**Mejores Prácticas para Callbacks:**

```python
# ✅ CORRECTO: ID único y descriptivo
BaseButton("Eliminar", variant="danger", id="delete-product-btn")

# ✅ CORRECTO: prevent_initial_call=True para botones
@callback(
    Output("result", "children"),
    Input("my-button", "n_clicks"),
    prevent_initial_call=True  # Evita ejecución al cargar
)

# ❌ INCORRECTO: ID genérico no descriptivo
BaseButton("Guardar", id="btn1")  # Poco claro

# ❌ INCORRECTO: Olvidar prevent_initial_call
@callback(
    Output("result", "children"),
    Input("my-button", "n_clicks")
    # SIN prevent_initial_call - se ejecutará al cargar la página
)
```

**Ejemplo Completo: Botón con Loading State**

```python
from dash import callback, Input, Output
from components.base import BaseButton
import time

layout = html.Div([
    BaseButton(
        "Procesar Datos",
        variant="primary",
        id="process-button"
    ),
    html.Div(id="process-status"),
    dcc.Loading(
        id="loading-process",
        type="default",
        children=html.Div(id="loading-output")
    )
])

@callback(
    [Output("process-status", "children"),
     Output("loading-output", "children")],
    Input("process-button", "n_clicks"),
    prevent_initial_call=True
)
def process_data(n_clicks):
    """Callback con loading state durante procesamiento"""
    if n_clicks:
        # Simular procesamiento largo
        time.sleep(2)
        return "Procesamiento completado", ""
    return "", ""
```

#### Buenas Prácticas

```python
# ✅ CORRECTO: Usar BaseButton para consistencia
from components.base import BaseButton

button = BaseButton(
    "Guardar Cambios",
    variant="success",
    size="md"
)

# ❌ INCORRECTO: Crear botones con estilos manuales
import dash_bootstrap_components as dbc

button = dbc.Button(
    "Guardar",
    color="success",
    style={"padding": "8px 16px", "fontSize": "1rem"}
)
```

---

### 3. Title - Jerarquía Tipográfica

Componente para crear títulos con jerarquía automática basada en design tokens.

#### Props

| Prop | Tipo | Default | Descripción |
|------|------|---------|-------------|
| `children` | node | - | Texto del título |
| `level` | int | `2` | Nivel jerárquico (1-5) |
| `color` | string | `None` | Color del texto (nombre de token o valor CSS) |
| `className` | string | `""` | Clases CSS adicionales |
| `margin_bottom` | string | `SPACING["m"]` | Margen inferior personalizado |

#### Niveles Jerárquicos

| Level | Elemento | Tamaño | Uso Recomendado |
|-------|----------|--------|-----------------|
| 1 | h1 | 2.5rem (40px) | Títulos principales de página |
| 2 | h2 | 2rem (32px) | Títulos de sección importante |
| 3 | h3 | 1.75rem (28px) | Subtítulos destacados |
| 4 | h4 | 1.5rem (24px) | Subtítulos secundarios |
| 5 | h5 | 1.25rem (20px) | Títulos terciarios |

#### Ejemplos de Uso

```python
from components.base import Title

# Título principal de página (h1)
page_title = Title("Dashboard de Ventas", level=1)

# Título de sección (h2)
section_title = Title("Resumen Mensual", level=2)

# Subtítulo con color personalizado (h3)
subsection_title = Title(
    "Análisis de Productos",
    level=3,
    color="primary"
)

# Título sin margen inferior (h4)
compact_title = Title(
    "Filtros",
    level=4,
    margin_bottom="0"
)

# Título terciario con color de éxito (h5)
success_title = Title(
    "Proceso Completado",
    level=5,
    color="success"
)
```

#### Jerarquía Semántica

```python
from components.base import Title

# Estructura jerárquica correcta
layout = html.Div([
    Title("Dashboard Principal", level=1),        # Título de página

    html.Section([
        Title("Ventas del Mes", level=2),         # Sección principal
        html.P("Análisis de ventas..."),

        Title("Productos Destacados", level=3),    # Subsección
        html.Ul([...]),

        Title("Detalles", level=4),                # Subsección menor
        html.P("Información adicional...")
    ])
])
```

#### Cuándo Usar Cada Nivel

- **Level 1 (h1)**: Una sola vez por página - título principal
- **Level 2 (h2)**: Secciones principales del contenido
- **Level 3 (h3)**: Subsecciones dentro de secciones h2
- **Level 4 (h4)**: Subsecciones menores o títulos de cards
- **Level 5 (h5)**: Títulos de menor importancia, labels destacados

#### Buenas Prácticas

```python
# ✅ CORRECTO: Usar Title con jerarquía correcta
from components.base import Title

title = Title("Ventas del Mes", level=2, color="primary")

# ❌ INCORRECTO: Crear títulos manualmente sin tokens
from dash import html

title = html.H2(
    "Ventas del Mes",
    style={"fontSize": "2rem", "fontWeight": "300", "color": "#2C3E50"}
)
```

---

## 🎯 Patrones de Uso Común

### Patrón 1: Card con Título y Contenido

```python
from dash import html
from components.base import BaseCard, Title

card_with_title = BaseCard(
    children=[
        Title("Ventas Totales", level=4, margin_bottom="8px"),
        html.H2("€25,450", style={"color": COLORS["success"]}),
        html.P("↑ 12.5% vs mes anterior", style={"fontSize": "0.875rem"})
    ]
)
```

### Patrón 2: Card Destacada con Botón

```python
from dash import html
from components.base import BaseCard, BaseButton, Title

highlighted_card = BaseCard(
    children=[
        Title("Acción Requerida", level=4, color="warning"),
        html.P("Hay productos con bajo stock"),
        BaseButton("Ver Detalles", variant="warning", size="sm")
    ],
    variant="highlighted",
    shadow="md"
)
```

### Patrón 3: Grupo de Botones

```python
from dash import html
from components.base import BaseButton
from styles.design_tokens import SPACING

button_group = html.Div(
    [
        BaseButton("Guardar", variant="success"),
        BaseButton("Cancelar", variant="secondary", outline=True)
    ],
    style={
        "display": "flex",
        "gap": SPACING["s"],
        "justifyContent": "flex-end",
        "marginTop": SPACING["l"]
    }
)
```

### Patrón 4: Lista de Cards

```python
from dash import html
from components.base import BaseCard, Title
from styles.design_tokens import SPACING

cards_list = html.Div(
    [
        BaseCard(
            children=[
                Title(f"Producto {i}", level=5),
                html.P(f"Descripción del producto {i}")
            ]
        )
        for i in range(1, 6)
    ],
    style={
        "display": "grid",
        "gridTemplateColumns": "repeat(auto-fill, minmax(300px, 1fr))",
        "gap": SPACING["m"]
    }
)
```

---

## 🚀 Migración a Componentes Base

### Paso 1: Identificar Componentes Candidatos

Busca en tu código:
- Cards con estilos repetidos
- Botones con configuraciones similares
- Títulos con tamaños inconsistentes

### Paso 2: Reemplazar con Componentes Base

```python
# ANTES
import dash_bootstrap_components as dbc
from dash import html

card = dbc.Card(
    dbc.CardBody([
        html.H4("Título"),
        html.P("Contenido")
    ]),
    style={
        "padding": "16px",
        "boxShadow": "0 0.125rem 0.25rem rgba(0, 0, 0, 0.075)",
        "borderRadius": "0.375rem"
    }
)

# DESPUÉS
from components.base import BaseCard, Title

card = BaseCard(
    children=[
        Title("Título", level=4),
        html.P("Contenido")
    ]
)
```

### Paso 3: Ajustar Props según Necesidad

```python
# Personalizar según casos de uso
card = BaseCard(
    children=[...],
    variant="highlighted",  # Destacar si es importante
    shadow="lg",            # Más sombra para mayor énfasis
    padding="24px"          # Padding custom si es necesario
)
```

---

## 📋 Checklist de Migración

- [ ] Reemplazar `dbc.Card` con `BaseCard`
- [ ] Reemplazar `dbc.Button` con `BaseButton`
- [ ] Reemplazar `html.H1-H5` con `Title`
- [ ] Eliminar estilos hardcoded duplicados
- [ ] Verificar que variantes y tamaños son correctos
- [ ] Probar responsive en diferentes viewports
- [ ] Validar accesibilidad (keyboard navigation, ARIA)

---

## 🎨 Personalización Avanzada

Si necesitas personalizar más allá de las props disponibles:

```python
from components.base import BaseCard
from styles.design_tokens import COLORS, SPACING

# Sobrescribir estilos usando el parámetro style
custom_card = BaseCard(
    children=[...],
    style={
        "borderTop": f"8px solid {COLORS['success']}",
        "paddingTop": SPACING["xl"]
    }
)
```

**Nota**: Siempre intenta usar las props disponibles antes de sobrescribir estilos. Si un patrón se repite mucho, considera crear un nuevo componente base.

---

## 🤝 Contribuir

Al crear nuevos componentes base:

1. **Sigue la estructura** de los componentes existentes
2. **Usa design tokens** exclusivamente (no valores hardcoded)
3. **Proporciona variantes** para casos de uso comunes
4. **Documenta props** y ejemplos de uso
5. **Mantén simplicidad** - componentes base deben ser versátiles

---

## 📚 Recursos Adicionales

- **Design Tokens**: Ver `styles/README.md`
- **Style Helpers**: Ver `utils/style_helpers.py`
- **Código Fuente**: Ver archivos individuales en `components/base/`

---

**xFarma Base Components** - Construyendo UIs consistentes con bloques reutilizables
