prf_design 0.6.0
prf_design: ^0.6.0 copied to clipboard
PRF Design System - Shared widgets, theme system, and essential utilities.
PRF Design #
A reusable Flutter package containing shared widgets, theme system, and essential utilities for PRF applications.
Installation #
Add this package to your pubspec.yaml:
dependencies:
prf_design: ^0.3.0
Or run:
flutter pub add prf_design
For local development in a monorepo, use a path dependency instead:
dependencies:
prf_design:
path: packages/prf_design
Quick Start #
import 'package:prf_design/prf_design.dart';
MaterialApp(
theme: PRFTheme.light(scaleFactor: DeviceHelper.getScaleFactor(context: context)),
darkTheme: PRFTheme.dark(scaleFactor: DeviceHelper.getScaleFactor(context: context)),
home: const MyHomePage(),
)
Imports #
Full Import #
import 'package:prf_design/prf_design.dart';
Granular Imports #
// Theme only
import 'package:prf_design/exports/theme.dart';
// Widgets only
import 'package:prf_design/exports/widgets.dart';
// Utilities only
import 'package:prf_design/exports/utils.dart';
// Enums & error models only
import 'package:prf_design/exports/enums.dart';
Theme System #
PRFTheme #
Provides complete Material 3 theme configurations for light and dark modes.
// Static factory methods (breaking API)
static ThemeData light({required double scaleFactor})
static ThemeData dark({required double scaleFactor})
Both methods configure: color scheme, text theme, app bar, buttons, inputs, cards, dividers, tab bar, data table, snackbar, icon, dialog, list tile, chip, and dropdown menu themes.
PRFColors #
Core brand colors and semantic color constants.
Brand Colors:
| Color | Hex | Usage |
|---|---|---|
| Navy Blue | #17154C |
Primary brand color |
| Lime Green | #93D500 |
Secondary brand color |
Neutral Colors: gray50 through gray900 (10 shades from light to dark)
Status Colors: success, successLight, successDark, warning, warningLight, warningDark, error, errorLight, errorDark, info, infoLight, infoDark
Accent Colors: purple (#6B21A8), blue (#2563EB), orange (#EA580C), emerald (#10B981)
Common Colors: white, black, transparent
PRFColorPalette #
Tints and shades for brand colors.
- Navy palette:
navy50throughnavy900(10 shades) - Lime palette:
lime50throughlime900(10 shades) - Convenience getters:
primary,primaryLight,primaryContainer,primaryDark,secondary,secondaryLight,secondaryContainer,secondaryDark
PRFColorsExtension #
Theme extension for accessing brand colors through the theme system. Includes all palette colors, grays, and accent colors with light/dark variants.
// Access via context
final colors = context.prfColors;
Container(color: colors.navyBlue)
PRFStatusExtension #
Theme extension providing semantic status colors via StatusColorSet.
StatusColorSet:
StatusColorSet({
required Color main, // Primary status color
required Color background, // Light background for containers
required Color onColor, // Text/icon color on main
})
Standard statuses: success, warning, error, info
Mission statuses: pending (orange), initiated (blue), scheduled (orange), inProgress (emerald), completed (success), failed (error), ignored (gray)
Active indicator: active, activeGlow
final status = context.statusColors;
Container(
color: status.success.background,
child: Text('Done', style: TextStyle(color: status.success.main)),
)
Context Extensions #
Convenience getters on BuildContext:
context.prfColors // PRFColorsExtension
context.statusColors // PRFStatusExtension
context.colorScheme // ColorScheme
context.textTheme // TextTheme
context.theme // ThemeData
PRFTextTheme #
Typography system using Google Fonts (Lato) with responsive scaling and light/dark variants.
static TextTheme getLightTheme({required double scaleFactor})
static TextTheme getDarkTheme({required double scaleFactor})
Utility text styles:
PRFTextTheme.getErrorTextStyle(scaleFactor: 1)
PRFTextTheme.getSuccessTextStyle(scaleFactor: 1)
PRFTextTheme.getWarningTextStyle(scaleFactor: 1)
PRFTextTheme.getInfoTextStyle(scaleFactor: 1)
PRFTextTheme.getButtonTextStyle(scaleFactor: 1)
PRFTextTheme.getCaptionTextStyle(scaleFactor: 1)
Widgets #
Buttons #
PRFPrimaryButton
Adaptive primary button with handset/tablet variants.
PRFPrimaryButton({
required VoidCallback onPressed,
required String title,
required bool disabled,
bool? isLoading,
})
PRFSecondaryButton
Outlined style variant. Same signature as PRFPrimaryButton.
PRFDestroyButton
Destructive/error style variant. Same signature as PRFPrimaryButton.
PRFGoogleAuthButton
PRFGoogleAuthButton({
required VoidCallback onPressed,
required String title,
required bool disabled,
bool? isLoading,
Widget? googleLogoAsset,
})
Inputs #
All input widgets are responsive with handset/tablet adaptive variants.
PRFTextInput
PRFTextInput({
required String hintText,
required TextEditingController controller,
bool enabled = true,
ValueChanged<String>? onChanged,
})
PRFEmailInput
PRFEmailInput({
required String hintText,
required TextEditingController emailController,
bool enabled = true,
})
PRFPasswordInput
PRFPasswordInput({
required String hintText,
required ValueNotifier<bool> hidePasswordNotifier,
required TextEditingController passwordController,
bool enabled = true,
})
PRFNameInput
PRFNameInput({
required String hintText,
required TextEditingController controller,
bool enabled = true,
})
PRFNumberInput
PRFNumberInput({
required String hintText,
required TextEditingController controller,
bool isLoading = false,
String? prefixText,
TextInputAction textInputAction = TextInputAction.next,
})
PRFTextAreaInput
PRFTextAreaInput({
required String hintText,
required TextEditingController controller,
bool enabled = true,
int minLines = 3,
int maxLines = 5,
TextInputAction textInputAction = TextInputAction.newline,
})
FormFieldLabel
FormFieldLabel({
required String label,
bool? isRequired,
Color? color,
bool? isBold,
})
Progress Indicators #
PRFCircularProgressIndicator
PRFCircularProgressIndicator({
Color? color,
double? value,
double size = 24,
double strokeWidth = 2,
})
PRFLinearProgressIndicator
PRFLinearProgressIndicator({
Color? color,
double? value,
double height = 4,
double? borderRadius,
Color? backgroundColor,
})
State Displays #
PRFEmptyView
PRFEmptyView({
required String label,
required String description,
IconData? icon,
Widget? action,
String? actionLabel,
VoidCallback? onActionPressed,
})
PRFErrorView
PRFErrorView({
required PRFFailure failure,
VoidCallback? onRetry,
bool compact = false,
})
// Factory constructors
PRFErrorView.fromMessage({required String message, VoidCallback? onRetry, bool compact})
PRFErrorView.fromFailure({required PRFFailure failure, VoidCallback? onRetry, bool compact})
PRFSnackbar
Static methods for typed snackbar notifications. Replaces the old PRFErrorSnackbar.
PRFSnackbar.error(context, 'Something went wrong', onRetry: () => _retry());
PRFSnackbar.success(context, 'Saved successfully');
PRFSnackbar.info(context, 'New update available');
PRFSnackbar.warning(context, 'Low storage space');
Each method accepts an optional Duration duration parameter.
PRFCategoryChips<T>
PRFCategoryChips<T>({
required List<T> categories,
required void Function(T?) onCategorySelected,
required String Function(T) labelBuilder,
T? selectedCategory,
bool isLoading = false,
bool showAllOption = true,
String allLabel = 'ALL',
double height = 48,
double spacing = 10,
EdgeInsets padding = const EdgeInsets.symmetric(horizontal: 16),
})
ImagePreviewPage
Full-screen image preview with pan/zoom and pagination.
ImagePreviewPage({
required List<String> imageUrls,
required int initialIndex,
String Function(int index, int total)? titleBuilder,
String? appBarTitle,
})
ReplyStatusView
ReplyStatusView({
required void Function({required bool status}) onStatusSelected,
required String unreadLabel,
required String repliedLabel,
bool reversed = false,
bool defaultStatus = false,
})
Cards #
AnimatedStatCard
AnimatedStatCard({
required String value,
required String label,
IconData? icon,
Color? color,
Duration delay = Duration.zero,
})
StatHighlightCard
StatHighlightCard({
required String title,
required String subtitle,
IconData? icon,
List<Color>? gradient,
Duration delay = Duration.zero,
})
Viewers #
PDFViewerPage
PDFViewerPage({
required String pdfUrl,
required String title,
})
Indicators #
WrappedPageIndicator
WrappedPageIndicator({
required int currentPage,
required int pageCount,
})
Utilities #
DeviceHelper #
Device type detection and responsive scaling.
// Get scale factor for responsive sizing
double scale = DeviceHelper.getScaleFactor(
context: context,
customBaseWidth: 375,
minScale: 0.8,
maxScale: 1.4,
);
// Detect device type
DeviceType type = DeviceHelper.getDeviceType(context: context);
// DeviceType.phone | DeviceType.tablet | DeviceType.desktop
// Check orientation
bool landscape = DeviceHelper.isLandscape(context: context);
Debouncer #
final debouncer = Debouncer(milliseconds: 300);
debouncer.run(() => search(query));
debouncer.cancel();
debouncer.flush(); // Execute pending action immediately
debouncer.isPending; // Check if action is pending
debouncer.dispose();
DateFormatter #
Timezone-aware date/time formatting.
DateFormatter.formatDateTime(dateTime, 'Africa/Nairobi') // "Jan 15, 2025, 2:30 PM"
DateFormatter.formatMissionDate(dateTime, 'Africa/Nairobi') // Mission-specific format
DateFormatter.formatDate(dateTime, 'Africa/Nairobi') // "Jan 15, 2025"
DateFormatter.timestamp(dateTime, 'Africa/Nairobi') // Timestamp format
DateFormatter.formatTime('14:30', 'Africa/Nairobi') // "2:30 PM"
DateFormatter.formatTimeFromDateTime(dateTime, 'Africa/Nairobi')
DateFormatter.getRelativeTime(dateTime) // "2 hours ago"
DateFormatter.getMonthAbbreviation(1) // "Jan"
All methods accept an optional locale parameter.
NumberFormatter #
NumberFormatter.formatCash(1500.50, locale: 'en_KE', symbol: '', decimalDigits: 0, customSymbol: 'KES')
NumberFormatter.truncateToDecimalPlaces(3.14159, 2) // 3.14
NumberFormatter.roundToDecimalPlaces(3.14159, 2) // 3.14
NumberFormatter.formatFileSize(1572864) // "1.5 MB"
StringFormatter #
StringFormatter.getUserNameInitials('John Doe', maxInitials: 2) // "JD"
StringFormatter.getFileName('/path/to/file.pdf') // "file.pdf"
StringFormatter.generateRandomString(16, includeNumbers: true, includeSymbols: false)
Error Handling #
PRFFailure #
Comprehensive error model for structured error handling.
PRFFailure({
required String message, // User-friendly message
int? statusCode, // HTTP status code
PRFErrorType type, // Error category (default: unknown)
PRFErrorSeverity severity, // Severity level (default: medium)
String? technicalMessage, // Debug details (not shown to users)
bool isRecoverable, // Whether user can retry (default: true)
StackTrace? stackTrace,
Map<String, dynamic> context, // Additional context data
})
Factory constructors:
PRFFailure.fromStatusCode(404, 'Not found')
PRFFailure.fromException(error, stackTrace)
PRFFailure.noConnection()
PRFFailure.timeout()
PRFFailure.authentication(message: 'Session expired')
PRFFailure.authorization(message: 'Insufficient permissions')
Methods:
failure.copyWith(message: 'Updated message', severity: PRFErrorSeverity.high)
PRFErrorType #
network | authentication | authorization | validation | notFound | server | timeout | cancelled | unknown
PRFErrorSeverity #
low | medium | high | critical
PRFSnackbarType #
error | success | info | warning
Example: Error Creation & Display #
// Create a failure
final failure = PRFFailure.noConnection();
// Display as error view
PRFErrorView(
failure: failure,
onRetry: () => _reload(),
)
// Display as snackbar
PRFSnackbar.error(context, failure.message, onRetry: () => _retry());
Package Structure #
prf_design/
├── lib/
│ ├── prf_design.dart # Main barrel export
│ ├── exports/
│ │ ├── theme.dart # Theme system exports
│ │ ├── widgets.dart # Widget exports
│ │ ├── utils.dart # Utility exports
│ │ └── enums.dart # Enum & model exports
│ └── src/
│ ├── enums/ # Error types, failure model
│ │ ├── prf_error_type.dart
│ │ ├── prf_error_severity.dart
│ │ ├── prf_snackbar_type.dart
│ │ └── prf_failure.dart
│ ├── theme/ # Colors, text, extensions
│ │ ├── prf_theme.dart
│ │ ├── text_theme.dart
│ │ ├── colors/
│ │ │ ├── prf_colors.dart
│ │ │ └── prf_color_palette.dart
│ │ └── extensions/
│ │ ├── prf_colors_extension.dart
│ │ ├── prf_status_extension.dart
│ │ └── theme_context_extensions.dart
│ ├── utils/ # DeviceHelper, formatters, debouncer
│ │ ├── debouncer.dart
│ │ ├── device_helper.dart
│ │ └── formatters/
│ │ ├── date_formatter.dart
│ │ ├── number_formatter.dart
│ │ └── string_formatter.dart
│ └── widgets/ # All UI components
│ ├── buttons/
│ ├── cards/
│ ├── indicators/
│ ├── inputs/
│ ├── progress/
│ ├── states/
│ └── viewers/
Requirements #
| Requirement | Version |
|---|---|
| Dart SDK | >=3.10.3 <4.0.0 |
| Flutter | >=3.38.5 |
Dependencies #
| Package | Description |
|---|---|
flutter_adaptive_ui |
Responsive handset/tablet layouts |
flutter_animate |
Declarative animations |
google_fonts |
Lato font and other Google Fonts |
http |
HTTP client for network requests |
intl |
Internationalization and formatting |
pdfx |
PDF rendering |
timezone |
Timezone-aware date/time handling |
Contributing #
Development #
# Format code
make fmt
# Run analysis
flutter analyze
# Run tests
flutter test
CI #
All pull requests are checked for:
- Code formatting
- Static analysis
- Tests
Publishing to pub.dev is automated via GitHub Actions.
License #
MIT