diff --git a/.run/widgetbook build.run.xml b/.run/widgetbook build.run.xml new file mode 100644 index 0000000..7496ab9 --- /dev/null +++ b/.run/widgetbook build.run.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/README.md b/README.md index f9cd5cd..89eaf1f 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,85 @@ flutter run See `melos.yaml`, `analysis_options.yaml`, and the package-level READMEs. +## Using the M3E Theme + +The design tokens and helpers live in the `m3e_design` package. Import it once in files where you access the theme: + +```dart +import 'package:m3e_design/m3e_design.dart'; +``` + +- Install the theme once at the app level (one-liner): + +```dart +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + theme: ColorScheme.fromSeed(seedColor: Colors.teal).toM3EThemeData(), + home: const MyHomePage(), + ); + } +} +``` + +- With dynamic color (Android 12+), setting both light and dark themes: + +```dart +Widget buildDynamicApp() { + return DynamicColorBuilder( + builder: (lightDynamic, darkDynamic) { + final light = lightDynamic ?? ColorScheme.fromSeed(seedColor: Colors.teal); + final dark = darkDynamic ?? + ColorScheme.fromSeed(seedColor: Colors.teal, brightness: Brightness.dark); + return MaterialApp( + theme: light.toM3EThemeData(), + darkTheme: dark.toM3EThemeData(), + home: const MyHomePage(), + ); + }, + ); +} +``` + +- Access M3E tokens anywhere using the new ThemeData accessor: + +```dart +final m3e = Theme.of(context).m3e; // ThemeData extension + +// Examples +final br = m3e.shapes.round.sm; // BorderRadius +final pad = EdgeInsets.all(m3e.spacing.md); // Spacing scale +final bg = m3e.colors.surfaceContainerHigh; // Colors mapped to ColorScheme +final curve = m3e.motion.emphasized; // Motion/curves +final title = m3e.typography.base.titleLarge; // Typography +``` + +- Apply a rounded shape to a widget: + +```dart +Widget roundedExample(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: Theme.of(context).m3e.shapes.round.sm, + ), + ); +} +``` + +- Optional context sugar if you prefer: + +```dart +// Provided by BuildContext extension in m3e_design +final m3e = context.m3e; +``` + +Notes: +- In debug, accessing `Theme.of(context).m3e` asserts if the extension isn't installed, helping catch setup issues. +- In release, it safely falls back to sensible defaults derived from the active `ColorScheme`. --- @@ -49,4 +128,4 @@ cd apps/gallery flutter run -d chrome ``` -_Last updated: 2025-10-23_ +_Last updated: 2025-10-25_ diff --git a/apps/gallery/lib/main.dart b/apps/gallery/lib/main.dart index d74c25a..7a51c32 100644 --- a/apps/gallery/lib/main.dart +++ b/apps/gallery/lib/main.dart @@ -31,20 +31,14 @@ class _GalleryAppState extends State { @override Widget build(BuildContext context) { - final baseLight = ThemeData( - useMaterial3: true, - colorSchemeSeed: Colors.purple, - brightness: Brightness.light, - ); - final baseDark = ThemeData( - useMaterial3: true, - colorSchemeSeed: Colors.purple, - brightness: Brightness.dark, - ); + final light = ColorScheme.fromSeed( + seedColor: Colors.purple, brightness: Brightness.light); + final dark = ColorScheme.fromSeed( + seedColor: Colors.purple, brightness: Brightness.dark); return MaterialApp( title: 'M3E Gallery', - theme: withM3ETheme(baseLight), - darkTheme: withM3ETheme(baseDark), + theme: light.toM3EThemeData(), + darkTheme: dark.toM3EThemeData(), themeMode: _mode, home: GalleryHome( isDark: _mode == ThemeMode.dark, @@ -56,7 +50,8 @@ class _GalleryAppState extends State { } class GalleryHome extends StatefulWidget { - const GalleryHome({super.key, required this.isDark, required this.onToggleBrightness}); + const GalleryHome( + {super.key, required this.isDark, required this.onToggleBrightness}); final bool isDark; final VoidCallback onToggleBrightness; @@ -77,7 +72,8 @@ class _GalleryHomeState extends State { titleText: 'M3E Gallery', actions: [ IconButton( - tooltip: widget.isDark ? 'Switch to light mode' : 'Switch to dark mode', + tooltip: + widget.isDark ? 'Switch to light mode' : 'Switch to dark mode', onPressed: widget.onToggleBrightness, icon: Icon(widget.isDark ? Icons.dark_mode : Icons.light_mode), ), diff --git a/apps/gallery/pubspec.yaml b/apps/gallery/pubspec.yaml index 3716d56..c07dd22 100644 --- a/apps/gallery/pubspec.yaml +++ b/apps/gallery/pubspec.yaml @@ -11,6 +11,7 @@ dependencies: m3e_collection: path: ../../packages/m3e_collection material_color_utilities: ^0.11.0 + widgetbook: ^3.18.0 flutter: uses-material-design: true diff --git a/apps/gallery/pubspec_overrides.yaml b/apps/gallery/pubspec_overrides.yaml new file mode 100644 index 0000000..2b624e1 --- /dev/null +++ b/apps/gallery/pubspec_overrides.yaml @@ -0,0 +1,30 @@ +# melos_managed_dependency_overrides: app_bar_m3e,button_group_m3e,button_m3e,fab_m3e,icon_button_m3e,loading_indicator_m3e,m3e_collection,m3e_design,navigation_bar_m3e,navigation_rail_m3e,progress_indicator_m3e,slider_m3e,split_button_m3e,toolbar_m3e +dependency_overrides: + app_bar_m3e: + path: ..\\..\\packages\\app_bar_m3e + button_group_m3e: + path: ..\\..\\packages\\button_group_m3e + button_m3e: + path: ..\\..\\packages\\button_m3e + fab_m3e: + path: ..\\..\\packages\\fab_m3e + icon_button_m3e: + path: ..\\..\\packages\\icon_button_m3e + loading_indicator_m3e: + path: ..\\..\\packages\\loading_indicator_m3e + m3e_collection: + path: ..\\..\\packages\\m3e_collection + m3e_design: + path: ..\\..\\packages\\m3e_design + navigation_bar_m3e: + path: ..\\..\\packages\\navigation_bar_m3e + navigation_rail_m3e: + path: ..\\..\\packages\\navigation_rail_m3e + progress_indicator_m3e: + path: ..\\..\\packages\\progress_indicator_m3e + slider_m3e: + path: ..\\..\\packages\\slider_m3e + split_button_m3e: + path: ..\\..\\packages\\split_button_m3e + toolbar_m3e: + path: ..\\..\\packages\\toolbar_m3e diff --git a/melos.yaml b/melos.yaml index d7ac43f..59d215a 100644 --- a/melos.yaml +++ b/melos.yaml @@ -2,6 +2,7 @@ name: m3e packages: - "packages/*" - "apps/*" + - "widgetbook/" command: bootstrap: