mix_annotations

Pub Version MIT Licence

Annotations used by mix_generator to generate boilerplate code for the Mix styling framework.

Installation

flutter pub add mix_annotations

This package is typically used alongside mix and mix_generator:

dependencies:
  mix: ^2.0.0
  mix_annotations: ^2.0.0

dev_dependencies:
  build_runner: ^2.4.0
  mix_generator: ^2.0.0

Annotations

@MixableSpec

Generates a self-contained _$<Name> mixin for Spec classes (immutable style data). The mixin declares implements Spec<T>, Diagnosticable and inlines type, copyWith, lerp, generated props by default, ==, hashCode, toString, toDiagnosticsNode, and debugFillProperties — so the user class needs a single with to be a fully-formed Spec.

import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:mix/mix.dart';
import 'package:mix_annotations/mix_annotations.dart';

part 'box_spec.g.dart';

@MixableSpec()
@immutable
final class BoxSpec with _$BoxSpec {
  @override
  final Color? color;
  @override
  final double? width;

  const BoxSpec({this.color, this.width});
}

The generated mixin _$BoxSpec is the only thing the user class mixes in — Equatable-style equality (via propsEquals / propsHash helpers) and Diagnosticable's concrete surface are inlined by the generator, not pushed onto the user.

Control which methods are generated via GeneratedSpecMethods flags:

@MixableSpec(methods: GeneratedSpecMethods.skipLerp)

GeneratedSpecMethods.skipEquals suppresses generated props so the class can author custom equality inputs while still using the generated equality surface.

@MixableStyler legacy marker

Retained for compatibility with older code and shared generated styler method flags. New Mix stylers are generated from @MixableSpec(target: Widget.new).

@MixableStyler()
class BoxStyler extends Style<BoxSpec>
    with Diagnosticable, ..., _$BoxStylerMixin {
  final Prop<AlignmentGeometry>? $alignment;
  final Prop<Color>? $color;

  // ...
}

GeneratedStylerMethods flags remain available for generator internals and compatibility.

@Mixable

Generates a mixin for Mix classes (compound property types) with merge(), resolve(), props, and debugFillProperties().

@Mixable()
final class BoxConstraintsMix extends ConstraintsMix<BoxConstraints>
    with DefaultValue<BoxConstraints>, Diagnosticable, _$BoxConstraintsMixMixin {
  final Prop<double>? $minWidth;
  final Prop<double>? $maxWidth;

  // ...
}

@MixableField

Configures code generation for individual fields in Styler classes.

// Skip setter generation for this field
@MixableField(ignoreSetter: true)
final Prop<Matrix4>? $transform;

// Override the setter parameter type
@MixableField(setterType: List<Shadow>)
final Prop<List<Shadow>>? $shadows;

// Forward canonical factories from a nested generated Styler.
@MixableField(forwardStyler: true)
final StyleSpec<BoxSpec>? container;

// Restrict a FlexBox-backed field to the Box-generated Styler surface.
@MixableField(forwardStyler: true, stylerSurface: BoxSpec)
final StyleSpec<FlexBoxSpec>? restrictedContainer;

stylerSurface references the source @MixableSpec type, not its generated Styler, so same-package clean builds do not depend on resolving generated code. Forwarding preserves the canonical named-factory allowlist and does not promote fluent-only helpers such as paddingAll.

When setterType and forwardStyler are combined, the custom setter type must be a concrete class with an accessible unnamed constructor callable without arguments. It must implement every forwarded fluent method with the canonical generated signature and return a type assignable to itself.

@MixWidget

Generates a StatelessWidget wrapper around a top-level styler variable or styler-returning function. By default, the wrapper exposes every non-key value parameter from the styler's call() method:

@MixWidget() // Equivalent to widgetParameters: .all()
final cardStyle = BoxStyler();

Use widgetParameters: .only(...) to keep the generated widget's value- parameter API limited to a deliberate subset. This prevents newly added styler value parameters from becoming public widget parameters automatically:

@MixWidget(
  widgetParameters: .only({'controller', 'focusNode'}),
)
final editorStyle = EditorStyler();

An empty .only({}) exposes no selectable styler value parameters. A valid Key? key and method-level call<T>() type parameters remain automatic; required styler value parameters must be selected. Excluded optional parameters are not forwarded, so the styler method's defaults apply.

Use target to wrap a plain widget constructor directly and factoryParameters to curate recipe controls independently:

@MixWidget(
  name: 'FortalButton',
  target: RemixButton.new,
  factoryParameters: .only({'variant', 'size'}),
)
ButtonStyler fortalButtonStyler({
  ButtonVariant variant = .solid,
  ButtonSize size = .medium,
  bool highContrast = false,
});

The target must be a Widget constructor with a compatible named style parameter. Its style and styleSpec parameters never surface on the generated wrapper. Required factory parameters must be selected; omitted optional parameters use the recipe's defaults.

Generators that also support older mix_annotations releases interpret an annotation without widgetParameters as .all(). Using .only(...) requires an annotations release that defines MixWidgetParameterSelection.

Generator Flags

Each annotation accepts bitwise flags to control which methods or components are generated:

Class Available Flags
GeneratedSpecMethods copyWith, equals, lerp
GeneratedStylerMethods setters, merge, resolve, debugFillProperties, props
GeneratedMixMethods merge, resolve, props, debugFillProperties

Use all (default) to generate everything, or skip* helpers to exclude specific methods:

GeneratedSpecMethods.skipLerp      // all except lerp
GeneratedSpecMethods.skipEquals    // user authors props; equality surface still emits
GeneratedMixMethods.skipResolve    // all except resolve

GeneratedStylerMethods.call / skipCall are retained for source compatibility, but call generation is no longer supported.

Code Generation

After annotating your classes, run build_runner to generate code:

dart run build_runner build --delete-conflicting-outputs

Or within the Mix monorepo:

melos run gen:build

Learn More

Libraries

mix_annotations
Annotations and generation flags for Mix code generation.