garnish_ui 0.3.0 copy "garnish_ui: ^0.3.0" to clipboard
garnish_ui: ^0.3.0 copied to clipboard

A premium, brand-agnostic Flutter UI component library with built-in animations, 5 visual style categories, fully customizable theming, and 40+ accessible components.

example/lib/main.dart

// Copyright 2026 Garnish UI. All rights reserved.
// Use of this source code is governed by an MIT license that can be
// found in the LICENSE file.

import 'package:flutter/widgets.dart';
import 'package:garnish_ui/garnish_ui.dart';

void main() {
  runApp(const GarnishUIExample());
}

/// The root widget for the Garnish UI example app.
class GarnishUIExample extends StatelessWidget {
  /// Creates the Garnish UI example app.
  const GarnishUIExample({super.key});

  @override
  Widget build(BuildContext context) {
    // Wrap your app with GarnishApp to provide theming
    return GarnishApp(
      theme: GarnishTheme.light(),
      darkTheme: GarnishTheme.dark(),
      themeMode: ThemeMode.system,
      child: WidgetsApp(
        title: 'Garnish UI Example',
        color: const Color(0xFF6366F1),
        home: const ExampleHomePage(),
      ),
    );
  }
}

/// The main example page showcasing Garnish UI components.
class ExampleHomePage extends StatefulWidget {
  /// Creates the example home page.
  const ExampleHomePage({super.key});

  @override
  State<ExampleHomePage> createState() => _ExampleHomePageState();
}

class _ExampleHomePageState extends State<ExampleHomePage> {
  // Animation controller for programmatic animations
  final _shakeController = GarnishAnimationController();

  // Form state
  bool _checkboxValue = false;
  bool _switchValue = false;
  String? _selectedOption;

  // Style category for the styled container demo
  GarnishStyleCategory _styleCategory = GarnishStyleCategory.minimal;

  @override
  Widget build(BuildContext context) {
    final theme = GarnishTheme.of(context);

    return SingleChildScrollView(
      padding: EdgeInsets.all(theme.spacing.lg),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // Header
          Text(
            'Garnish UI Demo',
            style: theme.typography.headlineLarge.copyWith(
              color: theme.colors.onBackground,
            ),
          ),
          SizedBox(height: theme.spacing.md),
          Text(
            'A premium, brand-agnostic Flutter UI component library with built-in animations.',
            style: theme.typography.bodyLarge.copyWith(
              color: theme.colors.onBackground,
            ),
          ),
          SizedBox(height: theme.spacing.xxl),

          // ============================================================
          // ANIMATION SYSTEM DEMO
          // ============================================================
          _SectionTitle(title: 'Animation System'),
          SizedBox(height: theme.spacing.md),

          // Animated buttons with different presets
          Wrap(
            spacing: theme.spacing.sm,
            runSpacing: theme.spacing.sm,
            children: [
              // Fade slide up animation
              GarnishButton(
                animation: GarnishAnimation.fadeSlideUp(),
                onPressed: () {},
                child: const Text('Fade Slide Up'),
              ),
              // Scale animation
              GarnishButton(
                animation: GarnishAnimation.scale(),
                onPressed: () {},
                variant: GarnishButtonVariant.secondary,
                child: const Text('Scale'),
              ),
              // Bounce animation
              GarnishButton(
                animation: GarnishAnimation.bounce(),
                onPressed: () {},
                variant: GarnishButtonVariant.outlined,
                child: const Text('Bounce'),
              ),
            ],
          ),
          SizedBox(height: theme.spacing.md),

          // Programmatic shake animation
          Row(
            children: [
              Expanded(
                child: GarnishTextField(
                  animation: GarnishAnimation.shake(animateOnMount: false),
                  animationController: _shakeController,
                  placeholder: 'Enter something...',
                  onChanged: (_) {},
                ),
              ),
              SizedBox(width: theme.spacing.sm),
              GarnishButton(
                onPressed: () => _shakeController.play(),
                variant: GarnishButtonVariant.destructive,
                child: const Text('Trigger Shake'),
              ),
            ],
          ),
          SizedBox(height: theme.spacing.xxl),

          // ============================================================
          // STYLE CATEGORIES DEMO
          // ============================================================
          _SectionTitle(title: 'Style Categories'),
          SizedBox(height: theme.spacing.md),
          Text(
            'Apply different visual styles to components:',
            style: theme.typography.bodyMedium.copyWith(
              color: theme.colors.onBackground,
            ),
          ),
          SizedBox(height: theme.spacing.md),

          // Style selector
          Wrap(
            spacing: theme.spacing.xs,
            runSpacing: theme.spacing.xs,
            children: GarnishStyleCategory.values.map((category) {
              final isSelected = category == _styleCategory;
              return GarnishButton(
                onPressed: () => setState(() => _styleCategory = category),
                variant: isSelected
                    ? GarnishButtonVariant.primary
                    : GarnishButtonVariant.text,
                size: GarnishButtonSize.small,
                child: Text(_styleCategoryName(category)),
              );
            }).toList(),
          ),
          SizedBox(height: theme.spacing.md),

          // Styled container demo
          GarnishStyledContainer(
            styleCategory: _styleCategory,
            padding: EdgeInsets.all(theme.spacing.lg),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  _styleCategoryName(_styleCategory),
                  style: theme.typography.titleLarge.copyWith(
                    color: theme.colors.onSurface,
                  ),
                ),
                SizedBox(height: theme.spacing.sm),
                Text(
                  _styleCategoryDescription(_styleCategory),
                  style: theme.typography.bodyMedium.copyWith(
                    color: theme.colors.onSurface,
                  ),
                ),
              ],
            ),
          ),
          SizedBox(height: theme.spacing.xxl),

          // ============================================================
          // BUTTON VARIANTS
          // ============================================================
          _SectionTitle(title: 'Button Variants'),
          SizedBox(height: theme.spacing.md),

          Wrap(
            spacing: theme.spacing.sm,
            runSpacing: theme.spacing.sm,
            children: [
              GarnishButton(
                onPressed: () {},
                variant: GarnishButtonVariant.primary,
                child: const Text('Primary'),
              ),
              GarnishButton(
                onPressed: () {},
                variant: GarnishButtonVariant.secondary,
                child: const Text('Secondary'),
              ),
              GarnishButton(
                onPressed: () {},
                variant: GarnishButtonVariant.outlined,
                child: const Text('Outlined'),
              ),
              GarnishButton(
                onPressed: () {},
                variant: GarnishButtonVariant.text,
                child: const Text('Text'),
              ),
              GarnishButton(
                onPressed: () {},
                variant: GarnishButtonVariant.destructive,
                child: const Text('Destructive'),
              ),
              GarnishButton(
                onPressed: null, // Disabled
                child: const Text('Disabled'),
              ),
              GarnishButton(
                onPressed: () {},
                isLoading: true,
                child: const Text('Loading'),
              ),
            ],
          ),
          SizedBox(height: theme.spacing.xxl),

          // ============================================================
          // INPUT COMPONENTS
          // ============================================================
          _SectionTitle(title: 'Input Components'),
          SizedBox(height: theme.spacing.md),

          // Text field with various states
          GarnishTextField(
            label: 'Username',
            placeholder: 'Enter your username',
            onChanged: (_) {},
            helperText: 'This is a helper text',
          ),
          SizedBox(height: theme.spacing.md),

          GarnishTextField(
            label: 'Email',
            placeholder: 'Enter your email',
            onChanged: (_) {},
            errorText: 'Invalid email address',
          ),
          SizedBox(height: theme.spacing.md),

          // Checkbox
          GarnishCheckbox(
            value: _checkboxValue,
            onChanged: (value) => setState(() => _checkboxValue = value ?? false),
            label: 'Accept terms and conditions',
          ),
          SizedBox(height: theme.spacing.sm),

          // Switch
          GarnishSwitch(
            value: _switchValue,
            onChanged: (value) => setState(() => _switchValue = value),
            label: 'Enable notifications',
          ),
          SizedBox(height: theme.spacing.md),

          // Select dropdown
          GarnishSelect<String>(
            value: _selectedOption,
            options: const [
              GarnishSelectOption(value: 'option1', label: 'Option 1'),
              GarnishSelectOption(value: 'option2', label: 'Option 2'),
              GarnishSelectOption(value: 'option3', label: 'Option 3'),
            ],
            onChanged: (value) => setState(() => _selectedOption = value),
            placeholder: 'Select an option',
            label: 'Dropdown',
          ),
          SizedBox(height: theme.spacing.xxl),

          // ============================================================
          // CARD COMPONENT
          // ============================================================
          _SectionTitle(title: 'Card Component'),
          SizedBox(height: theme.spacing.md),

          GarnishCard(
            animation: GarnishAnimation.fadeSlideUp(delay: const Duration(milliseconds: 100)),
            child: Padding(
              padding: EdgeInsets.all(theme.spacing.lg),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    'Card Title',
                    style: theme.typography.titleLarge.copyWith(
                      color: theme.colors.onSurface,
                    ),
                  ),
                  SizedBox(height: theme.spacing.sm),
                  Text(
                    'This is a card component with a title and description. Cards are versatile containers for content.',
                    style: theme.typography.bodyMedium.copyWith(
                      color: theme.colors.onSurface,
                    ),
                  ),
                  SizedBox(height: theme.spacing.md),
                  GarnishButton(
                    onPressed: () {},
                    size: GarnishButtonSize.small,
                    child: const Text('Learn More'),
                  ),
                ],
              ),
            ),
          ),
          SizedBox(height: theme.spacing.xxl),

          // ============================================================
          // STAGGERED ANIMATION DEMO
          // ============================================================
          _SectionTitle(title: 'Staggered Animations'),
          SizedBox(height: theme.spacing.md),
          Text(
            'Items animate with increasing delays:',
            style: theme.typography.bodyMedium.copyWith(
              color: theme.colors.onBackground,
            ),
          ),
          SizedBox(height: theme.spacing.md),

          ...List.generate(4, (index) {
            return Padding(
              padding: EdgeInsets.only(bottom: theme.spacing.sm),
              child: GarnishCard(
                animation: GarnishAnimation.fadeSlideUp().staggered(index),
                child: Padding(
                  padding: EdgeInsets.all(theme.spacing.md),
                  child: Row(
                    children: [
                      GarnishAvatar(
                        initials: 'U${index + 1}',
                        size: GarnishAvatarSize.md,
                      ),
                      SizedBox(width: theme.spacing.md),
                      Expanded(
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text(
                              'List Item ${index + 1}',
                              style: theme.typography.titleSmall.copyWith(
                                color: theme.colors.onSurface,
                              ),
                            ),
                            Text(
                              'Stagger delay: ${50 * index}ms',
                              style: theme.typography.bodySmall.copyWith(
                                color: theme.colors.onSurface,
                              ),
                            ),
                          ],
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            );
          }),
          SizedBox(height: theme.spacing.xxl),

          // ============================================================
          // FEEDBACK COMPONENTS
          // ============================================================
          _SectionTitle(title: 'Feedback Components'),
          SizedBox(height: theme.spacing.md),

          GarnishAlert(
            severity: GarnishAlertSeverity.info,
            title: 'Information',
            message: 'This is an informational alert message.',
          ),
          SizedBox(height: theme.spacing.sm),
          GarnishAlert(
            severity: GarnishAlertSeverity.success,
            title: 'Success',
            message: 'Your changes have been saved successfully.',
          ),
          SizedBox(height: theme.spacing.sm),
          GarnishAlert(
            severity: GarnishAlertSeverity.warning,
            title: 'Warning',
            message: 'Please review your input before continuing.',
          ),
          SizedBox(height: theme.spacing.sm),
          GarnishAlert(
            severity: GarnishAlertSeverity.error,
            title: 'Error',
            message: 'Something went wrong. Please try again.',
          ),
          SizedBox(height: theme.spacing.xxl),

          // ============================================================
          // DISPLAY COMPONENTS
          // ============================================================
          _SectionTitle(title: 'Display Components'),
          SizedBox(height: theme.spacing.md),

          Wrap(
            spacing: theme.spacing.md,
            runSpacing: theme.spacing.md,
            crossAxisAlignment: WrapCrossAlignment.center,
            children: [
              // Avatars
              GarnishAvatar(
                initials: 'JD',
                size: GarnishAvatarSize.sm,
              ),
              GarnishAvatar(
                initials: 'AB',
                size: GarnishAvatarSize.md,
              ),
              GarnishAvatar(
                initials: 'XY',
                size: GarnishAvatarSize.lg,
              ),

              // Badges
              GarnishBadge(
                label: 'New',
                variant: GarnishBadgeVariant.filled,
              ),
              GarnishBadge(
                label: 'Beta',
                variant: GarnishBadgeVariant.outlined,
              ),
              GarnishBadge(
                label: 'Deprecated',
                variant: GarnishBadgeVariant.subtle,
              ),
            ],
          ),
          SizedBox(height: theme.spacing.md),

          // Progress indicators
          GarnishProgress(
            value: 0.7,
            variant: GarnishProgressVariant.linear,
          ),
          SizedBox(height: theme.spacing.xxl),

          // Footer
          Center(
            child: Text(
              'Garnish UI v0.3.0',
              style: theme.typography.bodySmall.copyWith(
                color: theme.colors.onBackground,
              ),
            ),
          ),
          SizedBox(height: theme.spacing.lg),
        ],
      ),
    );
  }

  String _styleCategoryName(GarnishStyleCategory category) {
    switch (category) {
      case GarnishStyleCategory.minimal:
        return 'Minimal';
      case GarnishStyleCategory.material:
        return 'Material';
      case GarnishStyleCategory.neumorphism:
        return 'Neumorphism';
      case GarnishStyleCategory.glassmorphism:
        return 'Glassmorphism';
      case GarnishStyleCategory.brutalism:
        return 'Brutalism';
    }
  }

  String _styleCategoryDescription(GarnishStyleCategory category) {
    switch (category) {
      case GarnishStyleCategory.minimal:
        return 'Clean, flat design with subtle shadows and rounded corners.';
      case GarnishStyleCategory.material:
        return 'Elevated surfaces with depth, shadows, and Material Design principles.';
      case GarnishStyleCategory.neumorphism:
        return 'Soft, extruded appearance with inner and outer shadows.';
      case GarnishStyleCategory.glassmorphism:
        return 'Frosted glass effect with transparency and blur.';
      case GarnishStyleCategory.brutalism:
        return 'Bold, raw aesthetic with hard shadows and strong borders.';
    }
  }
}

/// A section title widget for organizing content.
class _SectionTitle extends StatelessWidget {
  const _SectionTitle({required this.title});

  final String title;

  @override
  Widget build(BuildContext context) {
    final theme = GarnishTheme.of(context);
    return Text(
      title,
      style: theme.typography.titleLarge.copyWith(
        color: theme.colors.onBackground,
        fontWeight: FontWeight.w600,
      ),
    );
  }
}
1
likes
0
points
38
downloads

Documentation

Documentation

Publisher

unverified uploader

Weekly Downloads

A premium, brand-agnostic Flutter UI component library with built-in animations, 5 visual style categories, fully customizable theming, and 40+ accessible components.

Repository
View/report issues

Topics

#ui #components #design-system #widget #animation

License

unknown (license)

Dependencies

flutter

More

Packages that depend on garnish_ui