Skip to content

Latest commit

 

History

History
83 lines (68 loc) · 5.21 KB

File metadata and controls

83 lines (68 loc) · 5.21 KB
name vgv-ui-package
description Best practices for building a Flutter UI package on top of Material — custom components, ThemeExtension-based theming, consistent APIs, and widget tests. Use when user says "create a ui package". Supports app_ui_package template.
allowed-tools Edit,mcp__very-good-cli__create

UI Package

Best practices for creating a Flutter UI package — a reusable widget library that builds on top of package:flutter/material.dart, extending it with app-specific components, custom design tokens via ThemeExtension, and a consistent API surface.

Theming foundation: This skill focuses on UI package structure, widget APIs, and testing. For foundational Material 3 theming (ColorScheme, TextTheme, component themes, spacing constants, light/dark mode), see the Material Theming skill (/vgv-material-theming). The two skills are complementary — Material Theming covers how to set up and use ThemeData; this skill covers how to extend it with ThemeExtension tokens and package reusable widgets around it.

Core Standards

Apply these standards to ALL UI package work:

  • Build on Material — depend on flutter/material.dart and compose Material widgets; do not rebuild primitives that Material already provides
  • One widget per file — each public widget lives in its own file named after the widget in snake_case (e.g., app_button.dart)
  • Barrel file for public API — expose all public widgets and theme classes through a single barrel file (e.g., lib/my_ui.dart) that also re-exports material.dart
  • Extend theming with ThemeExtension — use Material's ThemeData, ColorScheme, and TextTheme as the base (see Material Theming skill); add app-specific tokens (spacing, custom colors) via ThemeExtension<T>
  • Every widget has a corresponding widget test — behavioral tests verify interactions, callbacks, and state changes
  • Prefix all public classes — use a consistent prefix (e.g., App, Vg) to avoid naming collisions with Material widgets
  • Use const constructors everywhere possible — all widget constructors must be const when feasible
  • Document every public member — every public class, constructor parameter, and method has a dartdoc comment

Package Structure

my_ui/
├── lib/
│   ├── my_ui.dart              # Barrel file — re-exports material.dart + all public API
│   └── src/
│       ├── theme/
│       │   ├── app_theme.dart        # AppTheme class with light/dark ThemeData builders
│       │   ├── app_colors.dart       # AppColors ThemeExtension for custom color tokens
│       │   ├── app_spacing.dart      # AppSpacing ThemeExtension for spacing tokens
│       │   └── app_text_styles.dart  # Optional: extra text styles beyond Material's TextTheme
│       ├── widgets/
│       │   ├── app_button.dart
│       │   ├── app_text_field.dart
│       │   ├── app_card.dart
│       │   └── ...
│       └── extensions/
│           └── build_context_extensions.dart  # context.appColors, context.appSpacing shortcuts
├── test/
│   ├── src/
│   │   ├── theme/
│   │   │   └── app_theme_test.dart
│   │   └── widgets/
│   │       ├── app_button_test.dart
│   │       └── ...
│   └── helpers/
│       └── pump_app.dart         # Test helper wrapping widgets in MaterialApp + theme
├── widgetbook/                   # Widgetbook catalog submodule (sandbox + showcase)
│   └── ...
└── pubspec.yaml

Building Widgets

Widget API Guidelines

  • Compose Material widgets — use FilledButton, OutlinedButton, TextField, Card, etc. as building blocks
  • Accept only the minimum required parameters — avoid "kitchen sink" constructors
  • Use named parameters for everything except key and child/children
  • Provide sensible defaults derived from the theme when a parameter is not supplied
  • Expose callbacks with ValueChanged<T> or VoidCallback — do not use raw Function
  • Use Widget? for optional slot-based composition (leading, trailing icons, etc.)

Anti-Patterns

Anti-Pattern Correct Approach
Rebuilding widgets Material already provides (e.g., custom button from GestureDetector + DecoratedBox) Compose Material widgets (FilledButton, OutlinedButton) and style them
Creating a parallel theme system with custom InheritedWidget Use Material's ThemeData as the base and ThemeExtension for custom tokens
Hardcoding Color(0xFF...) in widget code Use Theme.of(context).colorScheme for standard colors and context.appColors for custom tokens
Duplicating Material's ColorScheme roles in a custom class Only create ThemeExtension tokens for values Material does not cover (e.g., success, warning, info)
Using dynamic or Object for callback types Use VoidCallback, ValueChanged<T>, or specific function typedefs
Exposing internal implementation files directly Use a barrel file; keep all files under src/ private

Creating the Package

Use the Very Good CLI MCP tool to scaffold the app_ui_package.