expressive_m3 0.2.0 copy "expressive_m3: ^0.2.0" to clipboard
expressive_m3: ^0.2.0 copied to clipboard

Material 3 Expressive design tokens, motion and widgets for Flutter — a shape-morphing loading indicator, pull-to-refresh, wavy progress gauge, spring transitions, expressive shapes and the full M3 ty [...]

expressive_m3 #

Material 3 Expressive design tokens, motion and widgets for Flutter.

A drop-in expressive layer on top of Material 3: emphasized easing + duration tokens, the M3 spring matrix as native SpringDescriptions, the full corner / spacing / elevation / type scales, the expressive polygon shapes, and a small set of polished widgets — a shape-morphing loading indicator, a pull-to-refresh that uses it, a wavy progress gauge, a spring press response and shared-axis page transitions.

Every animated widget honours the platform reduce-motion setting.

Features #

  • Motion tokensExpressiveMotion (M3 emphasized/standard easing + durations, with a reduced-motion gate).
  • Spring physicsExpressiveSpringScheme, the M3 spring matrix (spatial/effects × fast/default/slow) as Flutter-native springs, in expressive and standard presets; drive any controller with controller.springTo(target, spring). Swap the scheme per subtree with MotionSchemeScope.
  • Page motionExpressivePageTransitionsBuilder (shared-axis X, no black flash), SpringPagePhysics (spring-settled paging), TabSwitchTransition (fade-through).
  • Design tokensExpressiveRadius, ExpressiveSpacing, ExpressiveElevation (tonal), ExpressiveShapeTokens, ExpressiveTextTheme (M3 2021 type scale) and EmphasizedTextTheme (the M3 emphasized scale as a ThemeExtension).
  • ShapesExpressiveShape + ShapeClip / ExpressiveShapeBorder to clip or outline anything with the M3E polygons (cookie, sunny, clover, pill …).
  • WidgetsExpressiveLoadingIndicator, ExpressiveRefreshIndicator, CircularWavyProgress, PressableScale, ExpressiveLoader.
  • M3 Expressive components (not yet in Flutter) — ExpressiveButtonGroup, ExpressiveSplitButton, ExpressiveFabMenu, ExpressiveToolbar (floating + docked), ExpressiveWavyLinearProgress and ExpressiveWavyCircularProgress.
  • HapticsExpressiveHaptics, a consistent selection/light/success/warning vocabulary.

Getting started #

dependencies:
  expressive_m3: ^0.1.0
import 'package:expressive_m3/expressive_m3.dart';

Usage #

Theme — wire the tokens into ThemeData #

final textTheme = ExpressiveTextTheme.base;

MaterialApp(
  theme: ThemeData(
    useMaterial3: true,
    colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
    textTheme: textTheme,
    pageTransitionsTheme: expressivePageTransitionsTheme,
    extensions: [EmphasizedTextTheme.of(textTheme)],
  ),
  home: const HomePage(),
);

Shape-morphing loading indicator #

const ExpressiveLoadingIndicator();               // morphing glyph
const ExpressiveLoadingIndicator(contained: true); // on a tonal disc

Pull-to-refresh with the expressive indicator #

ExpressiveRefreshIndicator(
  onRefresh: () => controller.refresh(),
  // edgeOffset: 56, // clear a pinned header inside a NestedScrollView
  child: ListView(children: [...]),
);

Wavy progress gauge #

CircularWavyProgress(
  value: done / total,
  label: '$done/$total',
  // In a scroll list, give it a stable id so the sweep plays on first
  // appearance / value increase — but not on every scroll re-mount.
  animationId: 'job:$id',
);

Spring press response #

PressableScale(
  child: Card(child: ...),
);

Springs directly #

class _S extends State<Foo> with SingleTickerProviderStateMixin {
  late final _c = AnimationController.unbounded(vsync: this, value: 0);

  void _open() =>
      _c.springTo(1, MotionSchemeScope.of(context).spatialDefault);
}

Emphasized type + numeric identifiers #

Text('DR87 NMJ', style: context.emphasizedText.titleLarge.numericId);

Expressive shapes #

ShapeClip(
  shape: ExpressiveShape.cookie,
  child: ColoredBox(color: scheme.secondaryContainer),
);

Material(
  shape: const ExpressiveShapeBorder(ExpressiveShape.sunny),
  child: ...,
);

M3 Expressive components #

// Connected button group.
ExpressiveButtonGroup(
  children: [
    FilledButton(onPressed: () {}, child: const Text('Day')),
    FilledButton(onPressed: () {}, child: const Text('Week')),
    FilledButton(onPressed: () {}, child: const Text('Month')),
  ],
);

// Split button — primary action + attached menu.
ExpressiveSplitButton(
  label: const Text('Save'),
  onPressed: () {},
  menuChildren: [
    MenuItemButton(onPressed: () {}, child: const Text('Save as draft')),
  ],
);

// FAB menu (drop into Scaffold.floatingActionButton).
ExpressiveFabMenu(
  items: [
    ExpressiveFabMenuItem(icon: const Icon(Icons.edit), label: 'Edit', onPressed: () {}),
    ExpressiveFabMenuItem(icon: const Icon(Icons.share), label: 'Share', onPressed: () {}),
  ],
);

// Floating toolbar.
ExpressiveToolbar(
  children: [
    IconButton(onPressed: () {}, icon: const Icon(Icons.undo)),
    IconButton(onPressed: () {}, icon: const Icon(Icons.redo)),
  ],
);

// Wavy progress — determinate + indeterminate.
const ExpressiveWavyLinearProgress(value: 0.6);
const ExpressiveWavyLinearProgress();               // indeterminate
const ExpressiveWavyCircularProgress(value: 0.65);

See the example/ app for a gallery of every token and widget.

Additional information #

Contributions and issues are welcome on the repository. All animated widgets degrade to a static / instant state under the platform reduce-motion setting.

2
likes
150
points
44
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Material 3 Expressive design tokens, motion and widgets for Flutter — a shape-morphing loading indicator, pull-to-refresh, wavy progress gauge, spring transitions, expressive shapes and the full M3 type/shape/spacing scales.

Repository (GitHub)
View/report issues

Topics

#material-design #material-3 #animations #ui #widget

License

MIT (license)

Dependencies

animations, flutter, material_new_shapes

More

Packages that depend on expressive_m3