UI Package
Bonnes pratiques pour créer un package UI Flutter — une bibliothèque de widgets réutilisables qui s'appuie sur package:flutter/material.dart, l'étendant avec des composants spécifiques à l'application, des tokens de design 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 des widgets et les tests. Pour la thématisation Material 3 fondamentale (
ColorScheme,TextTheme, thèmes de composants, constantes d'espacement, mode clair/sombre), consultez la skill Material Theming (/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 les widgets réutilisables autour.
Standards Essentiels
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 (p. ex.,
app_button.dart) - Fichier barrel pour l'API publique — exposer tous les widgets publics et les classes de thème via un seul fichier barrel (p. ex.,
lib/my_ui.dart) qui ré-exporte aussimaterial.dart - Étendre la thématisation avec
ThemeExtension— utiliserThemeData,ColorScheme, etTextThemede Material comme base (consultez la 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, les callbacks et les changements d'état
- Préfixer toutes les classes publiques — utiliser un préfixe cohérent (p. ex.,
App,Vg) pour éviter les collisions de noms avec les widgets Material - Utiliser des constructeurs
constpartout où c'est possible — tous les constructeurs de widget doivent êtreconstquand c'est réalisable - 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 builders ThemeData clair/sombre
│ │ ├── app_colors.dart # AppColors ThemeExtension pour les tokens de couleur personnalisés
│ │ ├── app_spacing.dart # AppSpacing ThemeExtension pour les tokens d'espacement
│ │ └── app_text_styles.dart # Optionnel : styles de texte supplémentaires au-delà du 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 # Utilitaire de test encapsulant les widgets dans MaterialApp + thème
├── widgetbook/ # Sous-module catalogue Widgetbook (sandbox + showcase)
│ └── ...
└── pubspec.yaml
Construction de Widgets
Directives d'API Widget
- Composer des widgets Material — utiliser
FilledButton,OutlinedButton,TextField,Card, etc. comme éléments de base - 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 utiliserFunctionbrute - Utiliser
Widget?pour la composition optionnelle basée sur des emplacements (icônes principales, finales, etc.)
Anti-Patterns
| Anti-Pattern | Approche Correcte |
|---|---|
Reconstruire des widgets que Material fournit déjà (p. ex., bouton personnalisé à partir de GestureDetector + DecoratedBox) |
Composer des widgets Material (FilledButton, OutlinedButton) et les styler |
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 |
Coder en dur 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 de ColorScheme de Material dans une classe personnalisée |
Créer uniquement des tokens ThemeExtension pour les valeurs que Material ne couvre pas (p. ex., succès, avertissement, 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éation du Package
Utiliser l'outil MCP Very Good CLI pour scaffolder le app_ui_package.