Theme & UI
FLEX UI is a design system that provides brand tokens, theme extensions, utilities, and pre-built widgets to accelerate commerce app design and development. It ensures consistency across your application while maintaining flexibility for customization.
Overview
Section titled “Overview”FLEX UI is located at /lib/shared/flex_ui/
and consists of:
- Theme System: Brand tokens, design tokens, and theme extensions
- Sizing System: Consistent spacing, typography, and component dimensions
- Utilities: Context extensions and helper functions
- Widgets: Pre-built, commerce-focused UI components
Theme System
Section titled “Theme System”Design Tokens
Section titled “Design Tokens”The foundation of FLEX UI is the DesignTokens
class, which defines your app’s color palette and semantic meanings.
Brand Colors
Section titled “Brand Colors”class DesignTokens { // Primary customizable brand colors static const Color brandPrimary = Color(0xFF013D27); // Dark green static const Color brandSecondary = Color(0xFF2437FE); // Blue static const Color brandAccent = Color(0xFFF1FF61); // Yellow-green}
Semantic Colors
Section titled “Semantic Colors”// Status and feedback colorsstatic const Color semanticSuccess = Color(0xFF22AE45);static const Color semanticWarning = Color(0xFFFF9500);static const Color semanticError = Color(0xFFFF3B30);static const Color semanticInfo = Color(0xFF007AFF);
Neutral Colors
Section titled “Neutral Colors”// Background, surface, and text colorsstatic const Color neutralWhite = Color(0xFFFAFAFA);static const Color neutralBlack = Color(0xFF222222);static const Color neutralGray100 = Color(0xFFF2F2F2); // Light surfacestatic const Color neutralGray200 = Color(0xFFE6E6E6); // Dividersstatic const Color neutralGray300 = Color(0xFFE0E0E0); // Medium surfacestatic const Color neutralGray400 = Color(0xFF8E8E93); // Disabledstatic const Color neutralGray800 = Color(0xFF282828); // Dark surface
Brand Theme Extension
Section titled “Brand Theme Extension”The BrandThemeExtension
extends Flutter’s Material Design theme with commerce-specific colors:
// Access brand colors in your widgetsfinal brandColors = context.brandColors;
// Available colors:brandColors.success // Success statesbrandColors.onSuccess // Text on success backgroundsbrandColors.warning // Warning statesbrandColors.onWarning // Text on warning backgroundsbrandColors.info // Info statesbrandColors.onInfo // Text on info backgroundsbrandColors.brandAccent // Brand accent colorbrandColors.onBrandAccent // Text on accent backgroundsbrandColors.disabled // Disabled statesbrandColors.onDisabled // Text on disabled elementsbrandColors.divider // Divider lines
Theme Configuration
Section titled “Theme Configuration”In your main.dart
, configure the theme:
MaterialApp.router( theme: ThemeData( colorScheme: ColorScheme.fromSeed( seedColor: DesignTokens.brandPrimary, secondary: DesignTokens.brandSecondary, ), extensions: [BrandThemeExtension.light], // or .dark ),)
Sizing System
Section titled “Sizing System”FLEX UI provides a comprehensive sizing system through the FlexSizes
class:
Spacing
Section titled “Spacing”FlexSizes.xxs // 4.0 - Minimal spacingFlexSizes.xs // 8.0 - Small spacingFlexSizes.sm // 12.0 - Small-medium spacingFlexSizes.md // 16.0 - Medium spacing (most common)FlexSizes.lg // 24.0 - Large spacingFlexSizes.xl // 32.0 - Extra large spacingFlexSizes.xxl // 40.0 - Maximum spacing
Typography
Section titled “Typography”FlexSizes.fontSizeXs // 12.0 - Small textFlexSizes.fontSizeSm // 14.0 - Body textFlexSizes.fontSizeMd // 16.0 - Default textFlexSizes.fontSizeLg // 18.0 - SubheadingsFlexSizes.fontSizeXl // 20.0 - Headings
Components
Section titled “Components”// ButtonsFlexSizes.buttonHeight // 48.0 - Standard button heightFlexSizes.buttonRadius // 12.0 - Button border radiusFlexSizes.buttonWidth // 120.0 - Minimum button width
// CardsFlexSizes.cardRadiusXs // 6.0 - Minimal card radiusFlexSizes.cardRadiusSm // 10.0 - Small card radiusFlexSizes.cardRadiusMd // 12.0 - Standard card radiusFlexSizes.cardRadiusLg // 16.0 - Large card radius
// IconsFlexSizes.iconXs // 12.0 - Small iconsFlexSizes.iconSm // 16.0 - Standard iconsFlexSizes.iconMd // 24.0 - Medium iconsFlexSizes.iconLg // 32.0 - Large icons
Utilities
Section titled “Utilities”Context Extensions
Section titled “Context Extensions”FLEX UI provides powerful context extensions for easy access to theme data and device information:
Theme Access
Section titled “Theme Access”// Quick access to theme datacontext.theme // Full ThemeDatacontext.textTheme // TextThemecontext.colorScheme // Material ColorSchemecontext.brandColors // FLEX brand colors
Device Information
Section titled “Device Information”// Screen dimensionscontext.deviceSize // Size of the device screencontext.screenWidth // Screen widthcontext.screenHeight // Screen height
// Safe area and paddingcontext.padding // MediaQuery paddingcontext.safeAreaPadding // Safe area insetscontext.statusBarHeight // Status bar heightcontext.bottomSafeArea // Bottom safe area
State and Platform
Section titled “State and Platform”// Theme and input statescontext.isDarkMode // Dark mode detectioncontext.isKeyboardVisible // Keyboard visibility
// Responsive breakpointscontext.isMobile // Width < 768context.isTablet // Width 768-1024context.isDesktop // Width >= 1024
Snackbar Extensions
Section titled “Snackbar Extensions”Show branded snackbars that automatically use your theme colors:
Basic Usage
Section titled “Basic Usage”// Generic snackbarcontext.showAppSnackBar( message: "Operation completed", isSuccess: true, duration: Duration(seconds: 3),);
Semantic Snackbars
Section titled “Semantic Snackbars”// Success feedbackcontext.showSuccessSnackBar("Item added to cart!");
// Error handlingcontext.showErrorSnackBar("Network connection failed");
// Warningscontext.showWarningSnackBar("Low inventory for this item");
State-Safe Snackbars
Section titled “State-Safe Snackbars”For use in StatefulWidget states:
class _MyWidgetState extends State<MyWidget> { void _handleAction() { // Automatically checks if widget is mounted showSuccessSnackBar("Action completed"); }}
Widgets
Section titled “Widgets”FLEX UI includes pre-built widgets optimized for commerce applications:
FlexAppBar: Standardized app bar with consistent styling and behavior.
FlexButton: Enhanced button component with multiple variants.
FlexCard: Consistent card component for product displays and content containers.
FlexConnectivityIndicator: Network connectivity status indicator.
FlexImage / FlexTappableImage: Optimized image components for product catalogs and media.
FlexSearch: Search input component with commerce-specific features.
Customization
Section titled “Customization”Modifying Design Tokens
Section titled “Modifying Design Tokens”To customize your app’s appearance, modify the values in design_tokens.dart
:
class DesignTokens { // Update these colors to match your brand static const Color brandPrimary = Color(0xFF1976D2); // Your primary color static const Color brandSecondary = Color(0xFFF57C00); // Your secondary color static const Color brandAccent = Color(0xFF4CAF50); // Your accent color
// Customize semantic colors if needed static const Color semanticSuccess = Color(0xFF4CAF50); // ... other customizations}
Extending Sizes
Section titled “Extending Sizes”Add custom sizes to sizes.dart
:
class FlexSizes { // Your custom sizes static const double customHeaderHeight = 120.0; static const double customCardWidth = 280.0;
// Override existing sizes if needed static const double buttonHeight = 52.0; // Taller buttons}
Creating Custom Theme Extensions
Section titled “Creating Custom Theme Extensions”Extend the theme system for additional properties:
class CustomThemeExtension extends ThemeExtension<CustomThemeExtension> { final Color specialColor; final double specialSpacing;
const CustomThemeExtension({ required this.specialColor, required this.specialSpacing, });
// Implement required methods...}
Best Practices
Section titled “Best Practices”Using Design Tokens
Section titled “Using Design Tokens”// ✅ Good - Use design tokensContainer( color: DesignTokens.brandPrimary, padding: EdgeInsets.all(FlexSizes.md),)
// ❌ Avoid - Hard-coded valuesContainer( color: Colors.blue, padding: EdgeInsets.all(16.0),)
Accessing Theme Data
Section titled “Accessing Theme Data”// ✅ Good - Use context extensionsContainer( color: context.brandColors.success, width: context.screenWidth * 0.8,)
// ❌ Avoid - Manual theme accessContainer( color: Theme.of(context).extension<BrandThemeExtension>()?.success, width: MediaQuery.of(context).size.width * 0.8,)
Responsive Design
Section titled “Responsive Design”// ✅ Good - Use responsive helpersWidget build(BuildContext context) { return Container( padding: EdgeInsets.all( context.isMobile ? FlexSizes.sm : FlexSizes.lg, ), );}
Component Consistency
Section titled “Component Consistency”// ✅ Good - Use FLEX componentsFlexButton( text: "Add to Cart", onPressed: _handleAddToCart, variant: FlexButtonVariant.primary,)
// ❌ Avoid - Custom implementations for standard patternsElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, padding: EdgeInsets.symmetric(vertical: 12, horizontal: 24), ), onPressed: _handleAddToCart, child: Text("Add to Cart"),)
Integration Examples
Section titled “Integration Examples”Product Card Example
Section titled “Product Card Example”class ProductCard extends StatelessWidget { final Product product;
Widget build(BuildContext context) { return FlexCard( child: Column( children: [ FlexImage( imageUrl: product.imageUrl, height: FlexSizes.imageThumbSize, width: double.infinity, ), SizedBox(height: FlexSizes.sm), Text( product.name, style: context.textTheme.titleMedium, ), SizedBox(height: FlexSizes.xs), Text( product.price, style: context.textTheme.headlineSmall?.copyWith( color: context.brandColors.brandAccent, ), ), SizedBox(height: FlexSizes.md), FlexButton( text: "Add to Cart", onPressed: () => _addToCart(product), variant: FlexButtonVariant.primary, ), ], ), ); }}
Error Handling Example
Section titled “Error Handling Example”class OrderService { Future<void> placeOrder() async { try { await _processOrder(); context.showSuccessSnackBar("Order placed successfully!"); } catch (error) { context.showErrorSnackBar("Failed to place order. Please try again."); } }}