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: