Saltar al contenido principal

Widgets compartidos

lib/core/widgets/ contiene los building blocks de UI reutilizables organizados por categoría. Son widgets feature-agnostic: no contienen lógica de negocio ni dependen de BLoCs de features específicos.

CarpetaContenido
wrappers/Listeners globales del árbol raíz
buttons/Botones de uso común
inputs/Campos de texto y entradas especializadas
bottom_sheets/Sheets de sistema para permisos, servicios, pagos
cards/Tarjetas para distintos tipos de datos
layout/Contenedores y layouts base
app_bars/AppBars personalizados
bottom_navigation_bar/Barra de navegación inferior
list_tile/Tiles de lista
tags/Badges y etiquetas de estado
skeletons/Placeholders de carga
loaders/Spinners e indicadores de progreso
snack_bars/Snackbars personalizados
general/Widgets de propósito general

Cuándo un widget pertenece al core​

Un widget debe vivir en lib/core/widgets/ si cumple todos estos criterios:

1. Es completamente feature-agnostic​

El widget no importa nada de lib/src/[feature]/. Funciona con datos que le pasan por props, sin conocer el dominio de ningún feature.

// ✅ Pertenece al core — solo datos primitivos o entidades genéricas
class EmptyInfoWidget extends StatelessWidget {
const EmptyInfoWidget({required this.message, this.icon, super.key});

final String message;
final IconData? icon;
...
}

// ❌ No pertenece al core — depende de un dominio específico
class ProductCardWidget extends StatelessWidget {
const ProductCardWidget({required this.product, super.key});

final Product product; // Product es del dominio de products
...
}

2. Es usado por al menos dos features distintos​

Si solo un feature usa el widget, pertenece en lib/src/[feature]/presentation/widgets/.

3. No tiene estado de negocio propio​

Los widgets del core son StatelessWidget o tienen estado únicamente de UI (animaciones, scroll, interacciones). No hacen llamadas a repositorios ni contienen BLoCs de features.

Reglas para agregar un nuevo widget al core​

1. Definir la carpeta correcta​

Agregar el widget a la subcarpeta temática que mejor corresponda. Si no existe una categoría adecuada, crear una nueva.

2. Solo props, sin dependencias ocultas​

El widget recibe todo lo que necesita por constructor. No accede a BLoCs de features con context.read<FeatureBloc>() internamente.

// ✅ Correcto — todo por props
class InfoCard extends StatelessWidget {
const InfoCard({
required this.title,
required this.subtitle,
this.onTap,
super.key,
});

final String title;
final String subtitle;
final VoidCallback? onTap;
...
}

// ❌ Incorrecto — dependencia oculta de un BLoC de feature
class InfoCard extends StatelessWidget {

Widget build(BuildContext context) {
final productBloc = context.read<ProductBloc>(); // acoplamiento oculto
...
}
}

3. Usar el design system​

Los widgets del core siempre usan las constantes de variables/ y los estilos de theme/. Nunca hardcodean colores, tamaños o fuentes.

// ✅ Correcto
Container(
padding: EdgeInsets.all(AppSpacing.md),
color: context.colorScheme.surface,
)

// ❌ Incorrecto
Container(
padding: EdgeInsets.all(16),
color: Colors.white,
)

4. Barrel file de la categoría​

Agregar el nuevo widget al barrel file de su carpeta:

lib/core/widgets/buttons/buttons.dart
export 'custom_text_button.dart';
export 'custom_back_button.dart';
export 'base_layout_action_button.dart';
export 'copy_button.dart';
export 'new_button.dart'; // ← nuevo

Estructura de archivos​

lib/
└── core/
└── widgets/
├── wrappers/
│ └── wrappers.dart
├── buttons/
│ └── buttons.dart
├── inputs/
│ └── inputs.dart
├── bottom_sheets/
│ └── bottom_sheets.dart
├── cards/
│ └── cards.dart
├── layout/
│ └── layout.dart
├── app_bars/
│ └── app_bars.dart
├── bottom_navigation_bar/
│ └── bottom_navigation_bar.dart
├── list_tile/
│ └── list_tile.dart
├── tags/
│ └── tags.dart
├── skeletons/
│ └── skeletons.dart
├── loaders/
│ └── loaders.dart
├── snack_bars/
│ └── snack_bars.dart
├── general/
│ └── general.dart
└── svg/
└── svg.dart