project-widget

gsmlg-app's avatarfrom gsmlg-app

Guide for creating reusable widgets in app_widget packages with platform adaptive support (project)

⭐1stars🔀0forks📁View on GitHub🕐Updated Jan 7, 2026

When & Why to Use This Skill

This Claude skill provides a standardized framework for Flutter developers to create reusable, platform-adaptive UI components. It streamlines the development process by leveraging Mason templates for boilerplate generation, enforcing modular package architecture, and ensuring seamless UI transitions between Material and Cupertino designs, which significantly improves code maintainability and cross-platform consistency.

Use Cases

  • Rapidly scaffolding new UI components using Mason templates to ensure consistent folder structures and naming conventions across a Flutter project.
  • Developing platform-aware widgets that automatically switch between Android (Material) and iOS (Cupertino) styles based on the host operating system.
  • Organizing complex UI libraries into modular packages within the app_widget directory to facilitate code reuse and easier testing.
  • Implementing the barrel export pattern to manage public APIs of widget packages, simplifying imports for the main application.
  • Standardizing widget testing and dependency management within a workspace-based Flutter architecture.
nameproject-widget
descriptionGuide for creating reusable widgets in app_widget packages with platform adaptive support (project)

Flutter Widget Development Skill

This skill guides the creation of reusable widgets following this project's modular package conventions.

When to Use

Trigger this skill when:

  • Creating a reusable UI component
  • Building platform-adaptive widgets (Material/Cupertino)
  • User asks to "create a widget", "add a component", or "build reusable UI"

Mason Template

Always use Mason template first:

# Create widget package
mason make widget --name WidgetName --type stateless --folder subfolder

# Options:
# --type: stateless or stateful
# --folder: subfolder in app_widget/ (e.g., "buttons", "cards")
# --has_platform_adaptive: Include Material/Cupertino variants (default: true)

Project Structure

Widgets are organized in app_widget/ as separate packages:

app_widget/
├── adaptive/              # Responsive/adaptive components
│   ├── lib/
│   │   ├── app_adaptive_widgets.dart  # Barrel export
│   │   └── src/
│   │       ├── scaffold.dart           # AppAdaptiveScaffold
│   │       └── action.dart             # Adaptive action widgets
│   └── pubspec.yaml
├── artwork/               # Assets (icons, lottie, images)
├── feedback/              # Snackbars, dialogs, toasts
└── web_view/              # WebView wrapper

Widget Package Structure

app_widget/widget_name/
├── lib/
│   ├── widget_name.dart           # Barrel export (package entry point)
│   └── src/
│       ├── widget_name.dart       # Main widget implementation
│       └── widget_name_theme.dart # Optional theming
├── test/
│   └── widget_name_test.dart
└── pubspec.yaml

Barrel Export Pattern

Every widget package needs a barrel export file:

// lib/app_widget_name.dart
library app_widget_name;

export 'src/main_widget.dart';
export 'src/secondary_widget.dart';
// Export all public widgets

Widget Implementation Patterns

Stateless Widget

import 'package:flutter/material.dart';

class CustomButton extends StatelessWidget {
  final String label;
  final VoidCallback? onPressed;

  const CustomButton({
    super.key,
    required this.label,
    this.onPressed,
  });

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onPressed,
      child: Text(label),
    );
  }
}

Platform Adaptive Widget

import 'dart:io' show Platform;
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class AdaptiveButton extends StatelessWidget {
  final String label;
  final VoidCallback? onPressed;

  const AdaptiveButton({
    super.key,
    required this.label,
    this.onPressed,
  });

  @override
  Widget build(BuildContext context) {
    if (Platform.isIOS || Platform.isMacOS) {
      return CupertinoButton(
        onPressed: onPressed,
        child: Text(label),
      );
    }
    return ElevatedButton(
      onPressed: onPressed,
      child: Text(label),
    );
  }
}

Dependencies

In widget package pubspec.yaml:

name: app_widget_name
description: Widget description

environment:
  sdk: ">=3.8.0 <4.0.0"

dependencies:
  flutter:
    sdk: flutter

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^6.0.0

Workspace Registration

Add new widget packages to root pubspec.yaml:

workspace:
  # existing packages...
  - app_widget/widget_name

Using Widgets in Main App

Import the package:

import 'package:app_widget_name/app_widget_name.dart';

// Use in widget tree
CustomButton(
  label: 'Click me',
  onPressed: () => print('Clicked'),
)

Testing

Create widget tests in package test/ directory:

import 'package:flutter_test/flutter_test.dart';
import 'package:app_widget_name/app_widget_name.dart';

void main() {
  testWidgets('CustomButton renders label', (tester) async {
    await tester.pumpWidget(
      MaterialApp(
        home: Scaffold(
          body: CustomButton(label: 'Test'),
        ),
      ),
    );
    expect(find.text('Test'), findsOneWidget);
  });
}

Run tests: cd app_widget/widget_name && flutter test

Existing Widget Packages Reference

  • app_adaptive_widgets: AppAdaptiveScaffold, responsive layouts
  • app_artwork: LaddingPageLottie, SVG icons, images
  • app_feedback: Snackbar helpers, dialog utilities
  • app_web_view: WebView wrapper with platform support