Customizing Themes
Generate and customize themes and widget styles using the CLI.
This guide uses FAccordionStyle
as an example, but the same principles apply to all Forui widgets. It relies on the CLI.
Generate main.dart
Navigate to your project directory.
Generate a main.dart:
dart run forui initThis generates a main.dart file where you will add your generated theme:
12import 'package:flutter/material.dart';34import 'package:forui/forui.dart';56import 'theme.dart';78void main() {9 runApp(const Application());10}1112class Application extends StatelessWidget {13 const Application({super.key});1415 @override16 Widget build(BuildContext context) {17 // Assign the generated theme to `theme`.18 final theme = neutralLight;1920 return MaterialApp(21 localizationsDelegates: FLocalizations.localizationsDelegates,22 supportedLocales: FLocalizations.supportedLocales,23 builder: (_, child) => FTheme(24 data: theme,25 child: FToaster(child: FTooltipGroup(child: child!)),26 ),27 theme: theme.toApproximateMaterialTheme(),28 home: const FScaffold(29 // TODO: replace with your widget.30 child: Placeholder(),31 ),32 );33 }34}35Generate a Style
Tip: Run dart run forui style ls to see all available styles.
Generate a FAccordionStyle:
dart run forui style create accordionThis generates an accordion style file which you can add to your theme:
1FAccordionStyle accordionStyle({2 required FColors colors,3 required FTypography typography,4 required FStyle style,5 required bool touch,6}) => FAccordionStyle(7 titleTextStyle: FVariants.from(8 // This text style is applied when the accordion is NOT hovered OR pressed.9 typography.display.sm.copyWith(fontWeight: .w500, color: colors.foreground),10 variants: {11 // This text style is applied when the accordion is hovered OR pressed.12 [.hovered, .pressed]: .delta(decoration: () => .underline),13 },14 ),15 childTextStyle: typography.body.sm.copyWith(color: colors.foreground),16 iconStyle: .all(17 IconThemeData(18 color: colors.mutedForeground,19 size: touch20 ? typography.display.lg.fontSize21 : typography.display.md.fontSize,22 ),23 ),24 focusedOutlineStyle: style.focusedOutlineStyle,25 dividerStyle: FDividerStyle(color: colors.border, padding: .zero),26 tappableStyle: style.tappableStyle.copyWith(motion: FTappableMotion.none),27 titlePadding: const .symmetric(vertical: 16),28 childPadding: const .only(bottom: 16),29 motion: const FAccordionMotion(),30);31To learn how to customize widget styles, see the customizing widget styles guide.
Generate a Theme
Tip: Run dart run forui theme ls to see all available themes.
Generate a theme based on neutral's light variant:
dart run forui theme create neutral-lightThis generates a theme directory with a theme.dart and three part files (colors.dart, typography.dart, style.dart)
Each part file already includes a starter App<Section> extension you can fill in with your custom tokens.
Theme
12import 'package:flutter/material.dart';3import 'package:flutter/services.dart';45import 'package:forui/forui.dart';67part 'colors.dart';8part 'typography.dart';9part 'style.dart';1011/// Generated by Forui CLI.12///13/// Modify the generated function bodies to create your own custom style.14/// Then, call the modified function and pass it to [FTheme].15///16/// You can also generate styles to be used in the generated [FThemeData] using:17/// ```shell18/// dart forui style create [styles]19/// ```20///21/// See:22/// * https://forui.dev/docs/guides/customizing-themes for customizing themes.23/// * https://forui.dev/docs/guides/customizing-widget-styles for customizing individual widget styles.24FThemeData get neutralLight {25 // Change this to false to use the desktop variant of this theme.26 const touch = true;2728 final colors = lightColors;2930 final typography = _typography(colors: colors, touch: touch);3132 final icons = FIcons(33 arrowLeft: FIcons.iconData(FLucideIcons.arrowLeft),34 calendar: FIcons.iconData(FLucideIcons.calendar),35 check: FIcons.iconData(FLucideIcons.check),36 chevronDown: FIcons.iconData(FLucideIcons.chevronDown),37 chevronLeft: FIcons.iconData(FLucideIcons.chevronLeft),38 chevronRight: FIcons.iconData(FLucideIcons.chevronRight),39 chevronUp: FIcons.iconData(FLucideIcons.chevronUp),40 chevronsUpDown: FIcons.iconData(FLucideIcons.chevronsUpDown),41 circleAlert: FIcons.iconData(FLucideIcons.circleAlert),42 clock4: FIcons.iconData(FLucideIcons.clock4),43 ellipsis: FIcons.iconData(FLucideIcons.ellipsis),44 eye: FIcons.iconData(FLucideIcons.eye),45 eyeClosed: FIcons.iconData(FLucideIcons.eyeClosed),46 gripHorizontal: FIcons.iconData(FLucideIcons.gripHorizontal),47 gripVertical: FIcons.iconData(FLucideIcons.gripVertical),48 loader: FIcons.iconData(FLucideIcons.loader),49 loaderCircle: FIcons.iconData(FLucideIcons.loaderCircle),50 loaderPinwheel: FIcons.iconData(FLucideIcons.loaderPinwheel),51 search: FIcons.iconData(FLucideIcons.search),52 userRound: FIcons.iconData(FLucideIcons.userRound),53 x: FIcons.iconData(FLucideIcons.x),54 );5556 final style = _style(colors: colors, typography: typography, touch: touch);5758 return FThemeData(59 colors: colors,60 typography: typography,61 icons: icons,62 style: style,63 touch: touch,64 );65}6667FThemeData get neutralDark {68 // Change this to false to use the desktop variant of this theme.69 const touch = true;7071 final colors = darkColors;7273 final typography = _typography(colors: colors, touch: touch);7475 final icons = FIcons(76 arrowLeft: FIcons.iconData(FLucideIcons.arrowLeft),77 calendar: FIcons.iconData(FLucideIcons.calendar),78 check: FIcons.iconData(FLucideIcons.check),79 chevronDown: FIcons.iconData(FLucideIcons.chevronDown),80 chevronLeft: FIcons.iconData(FLucideIcons.chevronLeft),81 chevronRight: FIcons.iconData(FLucideIcons.chevronRight),82 chevronUp: FIcons.iconData(FLucideIcons.chevronUp),83 chevronsUpDown: FIcons.iconData(FLucideIcons.chevronsUpDown),84 circleAlert: FIcons.iconData(FLucideIcons.circleAlert),85 clock4: FIcons.iconData(FLucideIcons.clock4),86 ellipsis: FIcons.iconData(FLucideIcons.ellipsis),87 eye: FIcons.iconData(FLucideIcons.eye),88 eyeClosed: FIcons.iconData(FLucideIcons.eyeClosed),89 gripHorizontal: FIcons.iconData(FLucideIcons.gripHorizontal),90 gripVertical: FIcons.iconData(FLucideIcons.gripVertical),91 loader: FIcons.iconData(FLucideIcons.loader),92 loaderCircle: FIcons.iconData(FLucideIcons.loaderCircle),93 loaderPinwheel: FIcons.iconData(FLucideIcons.loaderPinwheel),94 search: FIcons.iconData(FLucideIcons.search),95 userRound: FIcons.iconData(FLucideIcons.userRound),96 x: FIcons.iconData(FLucideIcons.x),97 );9899 final style = _style(colors: colors, typography: typography, touch: touch);100101 return FThemeData(102 colors: colors,103 typography: typography,104 icons: icons,105 style: style,106 touch: touch,107 );108}109Colors
1part of 'theme.dart';23/// Generated by Forui CLI.4///5/// Color tokens and theme extensions for the generated theme.6final FColors lightColors = FColors(7 brightness: .light,8 systemOverlayStyle: .dark,9 barrier: Color(0x33000000),10 background: Color(0xFFFFFFFF),11 foreground: Color(0xFF0A0A0A),12 primary: Color(0xFF171717),13 primaryForeground: Color(0xFFFAFAFA),14 secondary: Color(0xFFF5F5F5),15 secondaryForeground: Color(0xFF171717),16 muted: Color(0xFFF5F5F5),17 mutedForeground: Color(0xFF737373),18 destructive: Color(0xFFE7000B),19 destructiveForeground: Color(0xFFFAFAFA),20 error: Color(0xFFE7000B),21 errorForeground: Color(0xFFFAFAFA),22 card: Color(0xFFFFFFFF),23 border: Color(0xFFE5E5E5),24 extensions: const [AppColors()],25);2627final FColors darkColors = FColors(28 brightness: .dark,29 systemOverlayStyle: .light,30 barrier: Color(0x7A000000),31 background: Color(0xFF0A0A0A),32 foreground: Color(0xFFFAFAFA),33 primary: Color(0xFFE5E5E5),34 primaryForeground: Color(0xFF171717),35 secondary: Color(0xFF262626),36 secondaryForeground: Color(0xFFFAFAFA),37 muted: Color(0xFF262626),38 mutedForeground: Color(0xFFA1A1A1),39 destructive: Color(0xFFFF6467),40 destructiveForeground: Color(0xFFFAFAFA),41 error: Color(0xFFFF6467),42 errorForeground: Color(0xFFFAFAFA),43 card: Color(0xFF171717),44 border: Color(0x1AFFFFFF),45 extensions: const [AppColors()],46);4748/// Provides convenient access to theme extensions on [FColors].49///50/// ```dart51/// final accent = context.theme.colors.app.accent; ✅52///53/// // Alternatively, you can create a getter to access extension fields directly.54/// final accent = context.theme.colors.accent; ✅55///56/// final accent = context.theme.colors.extension<AppColors>().accent; ❌57/// ```58extension FColorsExtensions on FColors {59 AppColors get app => extension<AppColors>();60}6162/// Custom color tokens unique to your app.63///64/// Add your fields below, then implement [copyWith], [lerp], [==], and [hashCode].65/// See https://api.flutter.dev/flutter/material/ThemeExtension-class.html.66class AppColors extends ThemeExtension<AppColors> {67 // TODO: add your color fields here:68 // final Color accent;6970 const AppColors();7172 @override73 AppColors copyWith() => const AppColors();7475 @override76 AppColors lerp(covariant AppColors? other, double t) {77 if (other == null) {78 return this;79 }80 return const AppColors();81 }8283 @override84 bool operator ==(Object other) =>85 identical(this, other) ||86 other is AppColors && runtimeType == other.runtimeType;8788 @override89 int get hashCode => runtimeType.hashCode;90}91Typography
1part of 'theme.dart';23/// Generated by Forui CLI.4///5/// Typography tokens for the generated theme.6FTypography _typography({required FColors colors, required bool touch}) =>7 FTypography(8 display: _display(colors: colors, touch: touch),9 body: _body(colors: colors, touch: touch),10 );1112/// The typographical tokens used for prominent text such as headings.13FTypeface _display({14 required FColors colors,15 required bool touch,16 String fontFamily = FTypeface.defaultFontFamily,17 List<String>? fontFamilyFallback,18}) {19 assert(20 fontFamily.isNotEmpty,21 'fontFamily ($fontFamily) should not be empty.',22 );23 final color = colors.foreground;24 if (touch) {25 return FTypeface(26 fontFamily: fontFamily,27 fontFamilyFallback: fontFamilyFallback,28 xs3: TextStyle(29 color: color,30 fontFamily: fontFamily,31 fontFamilyFallback: fontFamilyFallback,32 fontSize: 10,33 height: 1,34 leadingDistribution: .even,35 ),36 xs2: TextStyle(37 color: color,38 fontFamily: fontFamily,39 fontFamilyFallback: fontFamilyFallback,40 fontSize: 12,41 height: 1,42 leadingDistribution: .even,43 ),44 xs: TextStyle(45 color: color,46 fontFamily: fontFamily,47 fontFamilyFallback: fontFamilyFallback,48 fontSize: 14,49 height: 1.25,50 leadingDistribution: .even,51 ),52 sm: TextStyle(53 color: color,54 fontFamily: fontFamily,55 fontFamilyFallback: fontFamilyFallback,56 fontSize: 16,57 height: 1.5,58 leadingDistribution: .even,59 ),60 md: TextStyle(61 color: color,62 fontFamily: fontFamily,63 fontFamilyFallback: fontFamilyFallback,64 fontSize: 18,65 height: 1.75,66 leadingDistribution: .even,67 ),68 lg: TextStyle(69 color: color,70 fontFamily: fontFamily,71 fontFamilyFallback: fontFamilyFallback,72 fontSize: 20,73 height: 1.75,74 leadingDistribution: .even,75 ),76 xl: TextStyle(77 color: color,78 fontFamily: fontFamily,79 fontFamilyFallback: fontFamilyFallback,80 fontSize: 22,81 height: 2,82 leadingDistribution: .even,83 ),84 xl2: TextStyle(85 color: color,86 fontFamily: fontFamily,87 fontFamilyFallback: fontFamilyFallback,88 fontSize: 30,89 height: 2.25,90 leadingDistribution: .even,91 ),92 xl3: TextStyle(93 color: color,94 fontFamily: fontFamily,95 fontFamilyFallback: fontFamilyFallback,96 fontSize: 36,97 height: 2.5,98 leadingDistribution: .even,99 ),100 xl4: TextStyle(101 color: color,102 fontFamily: fontFamily,103 fontFamilyFallback: fontFamilyFallback,104 fontSize: 48,105 height: 1,106 leadingDistribution: .even,107 ),108 xl5: TextStyle(109 color: color,110 fontFamily: fontFamily,111 fontFamilyFallback: fontFamilyFallback,112 fontSize: 60,113 height: 1,114 leadingDistribution: .even,115 ),116 xl6: TextStyle(117 color: color,118 fontFamily: fontFamily,119 fontFamilyFallback: fontFamilyFallback,120 fontSize: 72,121 height: 1,122 leadingDistribution: .even,123 ),124 xl7: TextStyle(125 color: color,126 fontFamily: fontFamily,127 fontFamilyFallback: fontFamilyFallback,128 fontSize: 96,129 height: 1,130 leadingDistribution: .even,131 ),132 xl8: TextStyle(133 color: color,134 fontFamily: fontFamily,135 fontFamilyFallback: fontFamilyFallback,136 fontSize: 108,137 height: 1,138 leadingDistribution: .even,139 ),140 );141 } else {142 return FTypeface(143 fontFamily: fontFamily,144 fontFamilyFallback: fontFamilyFallback,145 xs3: TextStyle(146 color: color,147 fontFamily: fontFamily,148 fontFamilyFallback: fontFamilyFallback,149 fontSize: 8,150 height: 1,151 leadingDistribution: .even,152 ),153 xs2: TextStyle(154 color: color,155 fontFamily: fontFamily,156 fontFamilyFallback: fontFamilyFallback,157 fontSize: 10,158 height: 1,159 leadingDistribution: .even,160 ),161 xs: TextStyle(162 color: color,163 fontFamily: fontFamily,164 fontFamilyFallback: fontFamilyFallback,165 fontSize: 12,166 height: 1,167 leadingDistribution: .even,168 ),169 sm: TextStyle(170 color: color,171 fontFamily: fontFamily,172 fontFamilyFallback: fontFamilyFallback,173 fontSize: 14,174 height: 1.25,175 leadingDistribution: .even,176 ),177 md: TextStyle(178 color: color,179 fontFamily: fontFamily,180 fontFamilyFallback: fontFamilyFallback,181 fontSize: 16,182 height: 1.5,183 leadingDistribution: .even,184 ),185 lg: TextStyle(186 color: color,187 fontFamily: fontFamily,188 fontFamilyFallback: fontFamilyFallback,189 fontSize: 18,190 height: 1.75,191 leadingDistribution: .even,192 ),193 xl: TextStyle(194 color: color,195 fontFamily: fontFamily,196 fontFamilyFallback: fontFamilyFallback,197 fontSize: 20,198 height: 1.75,199 leadingDistribution: .even,200 ),201 xl2: TextStyle(202 color: color,203 fontFamily: fontFamily,204 fontFamilyFallback: fontFamilyFallback,205 fontSize: 22,206 height: 2,207 leadingDistribution: .even,208 ),209 xl3: TextStyle(210 color: color,211 fontFamily: fontFamily,212 fontFamilyFallback: fontFamilyFallback,213 fontSize: 30,214 height: 2.25,215 leadingDistribution: .even,216 ),217 xl4: TextStyle(218 color: color,219 fontFamily: fontFamily,220 fontFamilyFallback: fontFamilyFallback,221 fontSize: 36,222 height: 2.5,223 leadingDistribution: .even,224 ),225 xl5: TextStyle(226 color: color,227 fontFamily: fontFamily,228 fontFamilyFallback: fontFamilyFallback,229 fontSize: 48,230 height: 1,231 leadingDistribution: .even,232 ),233 xl6: TextStyle(234 color: color,235 fontFamily: fontFamily,236 fontFamilyFallback: fontFamilyFallback,237 fontSize: 60,238 height: 1,239 leadingDistribution: .even,240 ),241 xl7: TextStyle(242 color: color,243 fontFamily: fontFamily,244 fontFamilyFallback: fontFamilyFallback,245 fontSize: 72,246 height: 1,247 leadingDistribution: .even,248 ),249 xl8: TextStyle(250 color: color,251 fontFamily: fontFamily,252 fontFamilyFallback: fontFamilyFallback,253 fontSize: 96,254 height: 1,255 leadingDistribution: .even,256 ),257 );258 }259}260261/// The typographical tokens for content and UI text.262FTypeface _body({263 required FColors colors,264 required bool touch,265 String fontFamily = FTypeface.defaultFontFamily,266 List<String>? fontFamilyFallback,267}) {268 assert(269 fontFamily.isNotEmpty,270 'fontFamily ($fontFamily) should not be empty.',271 );272 final color = colors.foreground;273 if (touch) {274 return FTypeface(275 fontFamily: fontFamily,276 fontFamilyFallback: fontFamilyFallback,277 xs3: TextStyle(278 color: color,279 fontFamily: fontFamily,280 fontFamilyFallback: fontFamilyFallback,281 fontSize: 10,282 height: 1,283 leadingDistribution: .even,284 ),285 xs2: TextStyle(286 color: color,287 fontFamily: fontFamily,288 fontFamilyFallback: fontFamilyFallback,289 fontSize: 12,290 height: 1,291 leadingDistribution: .even,292 ),293 xs: TextStyle(294 color: color,295 fontFamily: fontFamily,296 fontFamilyFallback: fontFamilyFallback,297 fontSize: 14,298 height: 1.25,299 leadingDistribution: .even,300 ),301 sm: TextStyle(302 color: color,303 fontFamily: fontFamily,304 fontFamilyFallback: fontFamilyFallback,305 fontSize: 16,306 height: 1.5,307 leadingDistribution: .even,308 ),309 md: TextStyle(310 color: color,311 fontFamily: fontFamily,312 fontFamilyFallback: fontFamilyFallback,313 fontSize: 18,314 height: 1.75,315 leadingDistribution: .even,316 ),317 lg: TextStyle(318 color: color,319 fontFamily: fontFamily,320 fontFamilyFallback: fontFamilyFallback,321 fontSize: 20,322 height: 1.75,323 leadingDistribution: .even,324 ),325 xl: TextStyle(326 color: color,327 fontFamily: fontFamily,328 fontFamilyFallback: fontFamilyFallback,329 fontSize: 22,330 height: 2,331 leadingDistribution: .even,332 ),333 xl2: TextStyle(334 color: color,335 fontFamily: fontFamily,336 fontFamilyFallback: fontFamilyFallback,337 fontSize: 30,338 height: 2.25,339 leadingDistribution: .even,340 ),341 xl3: TextStyle(342 color: color,343 fontFamily: fontFamily,344 fontFamilyFallback: fontFamilyFallback,345 fontSize: 36,346 height: 2.5,347 leadingDistribution: .even,348 ),349 xl4: TextStyle(350 color: color,351 fontFamily: fontFamily,352 fontFamilyFallback: fontFamilyFallback,353 fontSize: 48,354 height: 1,355 leadingDistribution: .even,356 ),357 xl5: TextStyle(358 color: color,359 fontFamily: fontFamily,360 fontFamilyFallback: fontFamilyFallback,361 fontSize: 60,362 height: 1,363 leadingDistribution: .even,364 ),365 xl6: TextStyle(366 color: color,367 fontFamily: fontFamily,368 fontFamilyFallback: fontFamilyFallback,369 fontSize: 72,370 height: 1,371 leadingDistribution: .even,372 ),373 xl7: TextStyle(374 color: color,375 fontFamily: fontFamily,376 fontFamilyFallback: fontFamilyFallback,377 fontSize: 96,378 height: 1,379 leadingDistribution: .even,380 ),381 xl8: TextStyle(382 color: color,383 fontFamily: fontFamily,384 fontFamilyFallback: fontFamilyFallback,385 fontSize: 108,386 height: 1,387 leadingDistribution: .even,388 ),389 );390 } else {391 return FTypeface(392 fontFamily: fontFamily,393 fontFamilyFallback: fontFamilyFallback,394 xs3: TextStyle(395 color: color,396 fontFamily: fontFamily,397 fontFamilyFallback: fontFamilyFallback,398 fontSize: 8,399 height: 1,400 leadingDistribution: .even,401 ),402 xs2: TextStyle(403 color: color,404 fontFamily: fontFamily,405 fontFamilyFallback: fontFamilyFallback,406 fontSize: 10,407 height: 1,408 leadingDistribution: .even,409 ),410 xs: TextStyle(411 color: color,412 fontFamily: fontFamily,413 fontFamilyFallback: fontFamilyFallback,414 fontSize: 12,415 height: 1,416 leadingDistribution: .even,417 ),418 sm: TextStyle(419 color: color,420 fontFamily: fontFamily,421 fontFamilyFallback: fontFamilyFallback,422 fontSize: 14,423 height: 1.25,424 leadingDistribution: .even,425 ),426 md: TextStyle(427 color: color,428 fontFamily: fontFamily,429 fontFamilyFallback: fontFamilyFallback,430 fontSize: 16,431 height: 1.5,432 leadingDistribution: .even,433 ),434 lg: TextStyle(435 color: color,436 fontFamily: fontFamily,437 fontFamilyFallback: fontFamilyFallback,438 fontSize: 18,439 height: 1.75,440 leadingDistribution: .even,441 ),442 xl: TextStyle(443 color: color,444 fontFamily: fontFamily,445 fontFamilyFallback: fontFamilyFallback,446 fontSize: 20,447 height: 1.75,448 leadingDistribution: .even,449 ),450 xl2: TextStyle(451 color: color,452 fontFamily: fontFamily,453 fontFamilyFallback: fontFamilyFallback,454 fontSize: 22,455 height: 2,456 leadingDistribution: .even,457 ),458 xl3: TextStyle(459 color: color,460 fontFamily: fontFamily,461 fontFamilyFallback: fontFamilyFallback,462 fontSize: 30,463 height: 2.25,464 leadingDistribution: .even,465 ),466 xl4: TextStyle(467 color: color,468 fontFamily: fontFamily,469 fontFamilyFallback: fontFamilyFallback,470 fontSize: 36,471 height: 2.5,472 leadingDistribution: .even,473 ),474 xl5: TextStyle(475 color: color,476 fontFamily: fontFamily,477 fontFamilyFallback: fontFamilyFallback,478 fontSize: 48,479 height: 1,480 leadingDistribution: .even,481 ),482 xl6: TextStyle(483 color: color,484 fontFamily: fontFamily,485 fontFamilyFallback: fontFamilyFallback,486 fontSize: 60,487 height: 1,488 leadingDistribution: .even,489 ),490 xl7: TextStyle(491 color: color,492 fontFamily: fontFamily,493 fontFamilyFallback: fontFamilyFallback,494 fontSize: 72,495 height: 1,496 leadingDistribution: .even,497 ),498 xl8: TextStyle(499 color: color,500 fontFamily: fontFamily,501 fontFamilyFallback: fontFamilyFallback,502 fontSize: 96,503 height: 1,504 leadingDistribution: .even,505 ),506 );507 }508}509Style
1part of 'theme.dart';23/// Generated by Forui CLI.4///5/// Style tokens and theme extensions for the generated theme.6FStyle _style({7 required FColors colors,8 required FTypography typography,9 required bool touch,10}) {11 const borderRadius = FBorderRadius();12 return FStyle(13 formFieldStyle: .inherit(14 colors: colors,15 typography: typography,16 touch: touch,17 ),18 focusedOutlineStyle: FFocusedOutlineStyle(19 color: colors.primary,20 borderRadius: borderRadius.md,21 ),22 sizes: FSizes.inherit(touch: touch),23 iconStyle: IconThemeData(24 color: colors.foreground,25 size: typography.body.lg.fontSize,26 ),27 tappableStyle: FTappableStyle(),28 borderRadius: const FBorderRadius(),29 borderWidth: 1,30 pagePadding: const .symmetric(vertical: 8, horizontal: 12),31 shadow: const [32 BoxShadow(color: Color(0x0d000000), offset: Offset(0, 1), blurRadius: 2),33 ],34 extensions: const [AppStyle()],35 );36}3738/// Provides convenient access to theme extensions on [FStyle].39///40/// ```dart41/// final cardRadius = context.theme.style.app.cardRadius; ✅42///43/// // Alternatively, you can create a getter to access extension fields directly.44/// final cardRadius = context.theme.style.cardRadius; ✅45///46/// final cardRadius = context.theme.style.extension<AppStyle>().cardRadius; ❌47/// ```48extension FStyleExtensions on FStyle {49 AppStyle get app => extension<AppStyle>();50}5152/// Custom style tokens unique to your app.53///54/// Add your fields below, then implement [copyWith], [lerp], [==], and [hashCode].55/// See https://api.flutter.dev/flutter/material/ThemeExtension-class.html.56class AppStyle extends ThemeExtension<AppStyle> {57 // TODO: add your style fields here:58 // final double cardRadius;5960 const AppStyle();6162 @override63 AppStyle copyWith() => const AppStyle();6465 @override66 AppStyle lerp(covariant AppStyle? other, double t) {67 if (other == null) {68 return this;69 }70 return const AppStyle();71 }7273 @override74 bool operator ==(Object other) =>75 identical(this, other) ||76 other is AppStyle && runtimeType == other.runtimeType;7778 @override79 int get hashCode => runtimeType.hashCode;80}81