Skip to content

Instantly share code, notes, and snippets.

@fredgrott
Created January 23, 2026 15:29
Show Gist options
  • Select an option

  • Save fredgrott/683eb2f40f538259438e809125697139 to your computer and use it in GitHub Desktop.

Select an option

Save fredgrott/683eb2f40f538259438e809125697139 to your computer and use it in GitHub Desktop.
full theme extension with design tokens
// Copyright 2026 Fredrick Allan Grott. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// Modified from m3e_design package
// Copyright (c) 2025 Emily Moonstone
// MIT Licnese
// ignore_for_file: prefer_constructors_over_static_methods
import 'package:flutter/material.dart';
import 'package:material_expressive_collection/src/tokens/m_3_e_custom__shapes.dart';
import 'package:material_expressive_collection/src/tokens/m_3_e_custom_color_tokens.dart';
import 'package:material_expressive_collection/src/tokens/m_3_e_custom_motion.dart';
import 'package:material_expressive_collection/src/tokens/m_3_e_custom_spacing.dart';
import 'package:material_expressive_collection/src/tokens/m_3_e_custom_typography_tokens.dart';
/// Typically it is used in this manner:
///
/// ```dart
/// @override
/// Widget build(BuildContext context) {
/// 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: light.toM3EThemeData(override: m3eOverride, base: themeDataWithCustomComponentThemes ),
/// darkTheme: dark.toM3EThemeData(),
/// themeMode: _mode,
/// home: GalleryHome(
/// isDark: _mode == ThemeMode.dark,
/// onToggleBrightness: _toggleMode,
/// ),
/// debugShowCheckedModeBanner: false,
/// );
/// }
/// ```
///
/// Typically an m3eOverride is used so as to provide the custom GoogleFont stuff via the
/// text theme and the expressive text themes and ThemeData base to supply the custom
/// component themes especially if you use FlexColorScheme package to generate
/// component themes.
@immutable
class M3ETheme extends ThemeExtension<M3ETheme> {
final M3ECustomColors colors;
final M3ECustomTypography typography;
final M3ECustomShapes shapes;
final M3ECustomSpacing spacing;
final M3EMotion motion;
const M3ETheme({
required this.colors,
required this.typography,
required this.shapes,
required this.spacing,
required this.motion,
});
// Convenience proxy for commonly used text styles in packages (m3e.type.*)
@override
_M3ETypeProxy get type => _M3ETypeProxy(typography);
static M3ETheme defaults(ColorScheme scheme) => M3ETheme(
colors: M3ECustomColors.from(scheme),
typography: M3ECustomTypography.defaultFor(scheme.brightness),
shapes: M3ECustomShapes.expressive(),
spacing: const M3ECustomSpacing.regular(),
motion: const M3EMotion.expressive(),
);
@override
M3ETheme copyWith({
M3ECustomColors? colors,
M3ECustomTypography? typography,
M3ECustomShapes? shapes,
M3ECustomSpacing? spacing,
M3EMotion? motion,
}) => M3ETheme(
colors: colors ?? this.colors,
typography: typography ?? this.typography,
shapes: shapes ?? this.shapes,
spacing: spacing ?? this.spacing,
motion: motion ?? this.motion,
);
@override
M3ETheme lerp(covariant M3ETheme? other, double t) {
if (other == null) return this;
return M3ETheme(
colors: M3ECustomColors.lerp(colors, other.colors, t),
typography: M3ECustomTypography.lerp(typography, other.typography, t),
shapes: M3ECustomShapes.lerp(shapes, other.shapes, t),
spacing: M3ECustomSpacing.lerp(spacing, other.spacing, t),
motion: M3EMotion.lerp(motion, other.motion, t),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment