UI Package
Meilleures pratiques pour créer un package UI Flutter — une bibliothèque de widgets réutilisables qui s'appuie sur package:flutter/material.dart, l'étend avec des composants spécifiques à l'application, des design tokens personnalisés via ThemeExtension, et une surface API cohérente.
Fondation de thématisation : Cette skill se concentre sur la structure du package UI, les APIs de widgets et les tests. Pour la thématisation Material 3 fondamentale (
ColorScheme,TextTheme, thèmes de composants, constantes d'espacement, mode clair/sombre), voir la skill Material Theming (/vgv-material-theming). Les deux skills sont complémentaires — Material Theming couvre comment configurer et utiliserThemeData; cette skill couvre comment l'étendre avec des tokensThemeExtensionet packager des widgets réutilisables autour.
Standards Fondamentaux
Appliquez ces standards à TOUS les travaux de package UI :
- Construire sur Material — dépendre de
flutter/material.dartet composer des widgets Material ; ne pas reconstruire les primitives que Material fournit déjà - Un widget par fichier — chaque widget public vit dans son propre fichier nommé d'après le widget en snake_case (ex.
app_button.dart) - Fichier barrel pour l'API publique — exposer tous les widgets publics et les classes de thème via un unique fichier barrel (ex.
lib/my_ui.dart) qui ré-exporte aussimaterial.dart - Étendre la thématisation avec
ThemeExtension— utiliserThemeData,ColorScheme, etTextThemede Material comme base (voir skill Material Theming) ; ajouter des tokens spécifiques à l'application (espacement, couleurs personnalisées) viaThemeExtension<T> - Chaque widget a un test de widget correspondant — les tests comportementaux vérifient les interactions, callbacks et changements d'état
- Préfixer toutes les classes publiques — utiliser un préfixe cohérent (ex.
App,Vg) pour éviter les collisions de noms avec les widgets Material - Utiliser des constructeurs
constpartout où possible — tous les constructeurs de widget doivent êtreconstquand c'est possible - Documenter chaque membre public — chaque classe publique, paramètre de constructeur et méthode a un commentaire dartdoc
Structure du Package
my_ui/
├── lib/
│ ├── my_ui.dart # Fichier barrel — ré-exporte material.dart + toute l'API publique
│ └── src/
│ ├── theme/
│ │ ├── app_theme.dart # Classe AppTheme avec les builders ThemeData clair/sombre
│ │ ├── app_colors.dart # ThemeExtension AppColors pour les tokens de couleur personnalisés
│ │ ├── app_spacing.dart # ThemeExtension AppSpacing pour les tokens d'espacement
│ │ └── app_text_styles.dart # Optionnel : styles de texte supplémentaires au-delà de TextTheme de Material
│ ├── widgets/
│ │ ├── app_button.dart
│ │ ├── app_text_field.dart
│ │ ├── app_card.dart
│ │ └── ...
│ └── extensions/
│ └── build_context_extensions.dart # Raccourcis context.appColors, context.appSpacing
├── test/
│ ├── src/
│ │ ├── theme/
│ │ │ └── app_theme_test.dart
│ │ └── widgets/
│ │ ├── app_button_test.dart
│ │ └── ...
│ └── helpers/
│ └── pump_app.dart # Helper de test wrappant les widgets dans MaterialApp + thème
├── widgetbook/ # Sous-module catalogue Widgetbook (sandbox + showcase)
│ └── ...
└── pubspec.yaml
Construire des Widgets
Directives d'API de Widget
- Composer des widgets Material — utiliser
FilledButton,OutlinedButton,TextField,Card, etc. comme briques de construction - Accepter uniquement les paramètres strictement nécessaires — éviter les constructeurs « fourre-tout »
- Utiliser des paramètres nommés pour tout sauf
keyetchild/children - Fournir des valeurs par défaut sensées dérivées du thème quand un paramètre n'est pas fourni
- Exposer les callbacks avec
ValueChanged<T>ouVoidCallback— ne pas utiliserFunctionbrut - Utiliser
Widget?pour la composition optionnelle basée sur des slots (icônes leading, trailing, etc.)
Anti-Patterns
| Anti-Pattern | Approche Correcte |
|---|---|
Reconstruire des widgets que Material fournit déjà (ex. bouton personnalisé à partir de GestureDetector + DecoratedBox) |
Composer des widgets Material (FilledButton, OutlinedButton) et les styliser |
Créer un système de thème parallèle avec InheritedWidget personnalisé |
Utiliser ThemeData de Material comme base et ThemeExtension pour les tokens personnalisés |
Hardcoder Color(0xFF...) dans le code du widget |
Utiliser Theme.of(context).colorScheme pour les couleurs standard et context.appColors pour les tokens personnalisés |
Dupliquer les rôles ColorScheme de Material dans une classe personnalisée |
Créer des tokens ThemeExtension uniquement pour les valeurs que Material ne couvre pas (ex. success, warning, info) |
Utiliser dynamic ou Object pour les types de callback |
Utiliser VoidCallback, ValueChanged<T>, ou des typedefs de fonction spécifiques |
| Exposer directement les fichiers d'implémentation interne | Utiliser un fichier barrel ; garder tous les fichiers sous src/ privés |
Créer le Package
Utiliser l'outil MCP Very Good CLI pour scaffolder l'app_ui_package.