diff --git a/packages/mix/lib/src/modifiers/align_modifier.dart b/packages/mix/lib/src/modifiers/align_modifier.dart index ffc001ba3..73417b708 100644 --- a/packages/mix/lib/src/modifiers/align_modifier.dart +++ b/packages/mix/lib/src/modifiers/align_modifier.dart @@ -1,18 +1,25 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; +import 'package:mix_annotations/mix_annotations.dart'; import '../core/helpers.dart'; import '../core/widget_modifier.dart'; import '../core/prop.dart'; import '../core/style.dart'; +part 'align_modifier.g.dart'; + /// Modifier that aligns its child within the available space. /// /// Wraps the child in an [Align] widget with the specified alignment and size factors. +@MixableModifier() final class AlignModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$AlignModifierMethods { + @override final AlignmentGeometry alignment; + @override final double? widthFactor; + @override final double? heightFactor; const AlignModifier({ @@ -21,42 +28,6 @@ final class AlignModifier extends WidgetModifier this.heightFactor, }) : alignment = alignment ?? Alignment.center; - @override - AlignModifier copyWith({ - AlignmentGeometry? alignment, - double? widthFactor, - double? heightFactor, - }) { - return AlignModifier( - alignment: alignment ?? this.alignment, - widthFactor: widthFactor ?? this.widthFactor, - heightFactor: heightFactor ?? this.heightFactor, - ); - } - - @override - AlignModifier lerp(AlignModifier? other, double t) { - if (other == null) return this; - - return AlignModifier( - alignment: MixOps.lerp(alignment, other.alignment, t)!, - widthFactor: MixOps.lerp(widthFactor, other.widthFactor, t), - heightFactor: MixOps.lerp(heightFactor, other.heightFactor, t), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('alignment', alignment)) - ..add(DoubleProperty('widthFactor', widthFactor)) - ..add(DoubleProperty('heightFactor', heightFactor)); - } - - @override - List get props => [alignment, widthFactor, heightFactor]; - @override Widget build(Widget child) { return Align( @@ -67,60 +38,3 @@ final class AlignModifier extends WidgetModifier ); } } - -/// Mix class for applying alignment modifications. -/// -/// This class allows for mixing and resolving alignment properties. -class AlignModifierMix extends ModifierMix with Diagnosticable { - final Prop? alignment; - final Prop? widthFactor; - final Prop? heightFactor; - - const AlignModifierMix.create({ - this.alignment, - this.widthFactor, - this.heightFactor, - }); - - AlignModifierMix({ - AlignmentGeometry? alignment, - double? widthFactor, - double? heightFactor, - }) : this.create( - alignment: Prop.maybe(alignment), - widthFactor: Prop.maybe(widthFactor), - heightFactor: Prop.maybe(heightFactor), - ); - - @override - AlignModifier resolve(BuildContext context) { - return AlignModifier( - alignment: MixOps.resolve(context, alignment), - widthFactor: MixOps.resolve(context, widthFactor), - heightFactor: MixOps.resolve(context, heightFactor), - ); - } - - @override - AlignModifierMix merge(AlignModifierMix? other) { - if (other == null) return this; - - return AlignModifierMix.create( - alignment: MixOps.merge(alignment, other.alignment), - widthFactor: MixOps.merge(widthFactor, other.widthFactor), - heightFactor: MixOps.merge(heightFactor, other.heightFactor), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('alignment', alignment)) - ..add(DiagnosticsProperty('widthFactor', widthFactor)) - ..add(DiagnosticsProperty('heightFactor', heightFactor)); - } - - @override - List get props => [alignment, widthFactor, heightFactor]; -} diff --git a/packages/mix/lib/src/modifiers/align_modifier.g.dart b/packages/mix/lib/src/modifiers/align_modifier.g.dart new file mode 100644 index 000000000..33bda8048 --- /dev/null +++ b/packages/mix/lib/src/modifiers/align_modifier.g.dart @@ -0,0 +1,103 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'align_modifier.dart'; + +// ************************************************************************** +// ModifierGenerator +// ************************************************************************** + +mixin _$AlignModifierMethods on WidgetModifier, Diagnosticable { + AlignmentGeometry get alignment; + double? get heightFactor; + double? get widthFactor; + + @override + AlignModifier copyWith({ + AlignmentGeometry? alignment, + double? heightFactor, + double? widthFactor, + }) { + return AlignModifier( + alignment: alignment ?? this.alignment, + heightFactor: heightFactor ?? this.heightFactor, + widthFactor: widthFactor ?? this.widthFactor, + ); + } + + @override + AlignModifier lerp(AlignModifier? other, double t) { + if (other == null) return this as AlignModifier; + + return AlignModifier( + alignment: MixOps.lerp(alignment, other.alignment, t)!, + heightFactor: MixOps.lerp(heightFactor, other.heightFactor, t), + widthFactor: MixOps.lerp(widthFactor, other.widthFactor, t), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('alignment', alignment)) + ..add(DoubleProperty('heightFactor', heightFactor)) + ..add(DoubleProperty('widthFactor', widthFactor)); + } + + @override + List get props => [alignment, heightFactor, widthFactor]; +} + +class AlignModifierMix extends ModifierMix with Diagnosticable { + final Prop? alignment; + final Prop? heightFactor; + final Prop? widthFactor; + + const AlignModifierMix.create({ + this.alignment, + this.heightFactor, + this.widthFactor, + }); + + AlignModifierMix({ + AlignmentGeometry? alignment, + double? heightFactor, + double? widthFactor, + }) : this.create( + alignment: Prop.maybe(alignment), + heightFactor: Prop.maybe(heightFactor), + widthFactor: Prop.maybe(widthFactor), + ); + + @override + AlignModifier resolve(BuildContext context) { + return AlignModifier( + alignment: MixOps.resolve(context, alignment), + heightFactor: MixOps.resolve(context, heightFactor), + widthFactor: MixOps.resolve(context, widthFactor), + ); + } + + @override + AlignModifierMix merge(AlignModifierMix? other) { + if (other == null) return this; + + return AlignModifierMix.create( + alignment: MixOps.merge(alignment, other.alignment), + heightFactor: MixOps.merge(heightFactor, other.heightFactor), + widthFactor: MixOps.merge(widthFactor, other.widthFactor), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('alignment', alignment)) + ..add(DiagnosticsProperty('heightFactor', heightFactor)) + ..add(DiagnosticsProperty('widthFactor', widthFactor)); + } + + @override + List get props => [alignment, heightFactor, widthFactor]; +} diff --git a/packages/mix/lib/src/modifiers/aspect_ratio_modifier.dart b/packages/mix/lib/src/modifiers/aspect_ratio_modifier.dart index 2c30e4a65..4eeef36f2 100644 --- a/packages/mix/lib/src/modifiers/aspect_ratio_modifier.dart +++ b/packages/mix/lib/src/modifiers/aspect_ratio_modifier.dart @@ -1,80 +1,28 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; +import 'package:mix_annotations/mix_annotations.dart'; import '../core/helpers.dart'; import '../core/widget_modifier.dart'; import '../core/prop.dart'; import '../core/style.dart'; +part 'aspect_ratio_modifier.g.dart'; + /// Modifier that constrains its child to a specific aspect ratio. /// /// Wraps the child in an [AspectRatio] widget with the specified ratio. +@MixableModifier() final class AspectRatioModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$AspectRatioModifierMethods { + @override final double aspectRatio; const AspectRatioModifier([double? aspectRatio]) : aspectRatio = aspectRatio ?? 1.0; - @override - AspectRatioModifier copyWith({double? aspectRatio}) { - return AspectRatioModifier(aspectRatio ?? this.aspectRatio); - } - - @override - AspectRatioModifier lerp(AspectRatioModifier? other, double t) { - if (other == null) return this; - - return AspectRatioModifier(MixOps.lerp(aspectRatio, other.aspectRatio, t)!); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DoubleProperty('aspectRatio', aspectRatio)); - } - - @override - List get props => [aspectRatio]; - @override Widget build(Widget child) { return AspectRatio(aspectRatio: aspectRatio, child: child); } } - -/// Mix class for applying aspect ratio modifications. -/// -/// This class allows for mixing and resolving aspect ratio properties. -class AspectRatioModifierMix extends ModifierMix - with Diagnosticable { - final Prop? aspectRatio; - - const AspectRatioModifierMix.create({this.aspectRatio}); - - AspectRatioModifierMix({double? aspectRatio}) - : this.create(aspectRatio: Prop.maybe(aspectRatio)); - - @override - AspectRatioModifier resolve(BuildContext context) { - return AspectRatioModifier(MixOps.resolve(context, aspectRatio)); - } - - @override - AspectRatioModifierMix merge(AspectRatioModifierMix? other) { - if (other == null) return this; - - return AspectRatioModifierMix.create( - aspectRatio: MixOps.merge(aspectRatio, other.aspectRatio), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('aspectRatio', aspectRatio)); - } - - @override - List get props => [aspectRatio]; -} diff --git a/packages/mix/lib/src/modifiers/aspect_ratio_modifier.g.dart b/packages/mix/lib/src/modifiers/aspect_ratio_modifier.g.dart new file mode 100644 index 000000000..458115e40 --- /dev/null +++ b/packages/mix/lib/src/modifiers/aspect_ratio_modifier.g.dart @@ -0,0 +1,66 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'aspect_ratio_modifier.dart'; + +// ************************************************************************** +// ModifierGenerator +// ************************************************************************** + +mixin _$AspectRatioModifierMethods + on WidgetModifier, Diagnosticable { + double get aspectRatio; + + @override + AspectRatioModifier copyWith({double? aspectRatio}) { + return AspectRatioModifier(aspectRatio ?? this.aspectRatio); + } + + @override + AspectRatioModifier lerp(AspectRatioModifier? other, double t) { + if (other == null) return this as AspectRatioModifier; + + return AspectRatioModifier(MixOps.lerp(aspectRatio, other.aspectRatio, t)!); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DoubleProperty('aspectRatio', aspectRatio)); + } + + @override + List get props => [aspectRatio]; +} + +class AspectRatioModifierMix extends ModifierMix + with Diagnosticable { + final Prop? aspectRatio; + + const AspectRatioModifierMix.create({this.aspectRatio}); + + AspectRatioModifierMix({double? aspectRatio}) + : this.create(aspectRatio: Prop.maybe(aspectRatio)); + + @override + AspectRatioModifier resolve(BuildContext context) { + return AspectRatioModifier(MixOps.resolve(context, aspectRatio)); + } + + @override + AspectRatioModifierMix merge(AspectRatioModifierMix? other) { + if (other == null) return this; + + return AspectRatioModifierMix.create( + aspectRatio: MixOps.merge(aspectRatio, other.aspectRatio), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('aspectRatio', aspectRatio)); + } + + @override + List get props => [aspectRatio]; +} diff --git a/packages/mix/lib/src/modifiers/blur_modifier.dart b/packages/mix/lib/src/modifiers/blur_modifier.dart index 88c977555..2419dba6e 100644 --- a/packages/mix/lib/src/modifiers/blur_modifier.dart +++ b/packages/mix/lib/src/modifiers/blur_modifier.dart @@ -2,41 +2,25 @@ import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; +import 'package:mix_annotations/mix_annotations.dart'; import '../core/helpers.dart'; import '../core/prop.dart'; import '../core/style.dart'; import '../core/widget_modifier.dart'; +part 'blur_modifier.g.dart'; + /// Modifier that applies a Gaussian blur filter to its child. +@MixableModifier() final class BlurModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$BlurModifierMethods { /// Blur sigma for X and Y axis. + @override final double sigma; const BlurModifier([double? sigma]) : sigma = sigma ?? 0.0; - @override - BlurModifier copyWith({double? sigma}) { - return BlurModifier(sigma ?? this.sigma); - } - - @override - BlurModifier lerp(BlurModifier? other, double t) { - if (other == null) return this; - - return BlurModifier(MixOps.lerp(sigma, other.sigma, t)!); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DoubleProperty('sigma', sigma)); - } - - @override - List get props => [sigma]; - @override Widget build(Widget child) { if (sigma == 0.0) return child; @@ -51,33 +35,3 @@ final class BlurModifier extends WidgetModifier ); } } - -/// Mix class for applying blur modifications. -class BlurModifierMix extends ModifierMix with Diagnosticable { - final Prop? sigma; - - const BlurModifierMix.create({this.sigma}); - - BlurModifierMix({double? sigma}) : this.create(sigma: Prop.maybe(sigma)); - - @override - BlurModifier resolve(BuildContext context) { - return BlurModifier(MixOps.resolve(context, sigma)); - } - - @override - BlurModifierMix merge(BlurModifierMix? other) { - if (other == null) return this; - - return BlurModifierMix.create(sigma: MixOps.merge(sigma, other.sigma)); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('sigma', sigma)); - } - - @override - List get props => [sigma]; -} diff --git a/packages/mix/lib/src/modifiers/blur_modifier.g.dart b/packages/mix/lib/src/modifiers/blur_modifier.g.dart new file mode 100644 index 000000000..894fa26bc --- /dev/null +++ b/packages/mix/lib/src/modifiers/blur_modifier.g.dart @@ -0,0 +1,61 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'blur_modifier.dart'; + +// ************************************************************************** +// ModifierGenerator +// ************************************************************************** + +mixin _$BlurModifierMethods on WidgetModifier, Diagnosticable { + double get sigma; + + @override + BlurModifier copyWith({double? sigma}) { + return BlurModifier(sigma ?? this.sigma); + } + + @override + BlurModifier lerp(BlurModifier? other, double t) { + if (other == null) return this as BlurModifier; + + return BlurModifier(MixOps.lerp(sigma, other.sigma, t)!); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DoubleProperty('sigma', sigma)); + } + + @override + List get props => [sigma]; +} + +class BlurModifierMix extends ModifierMix with Diagnosticable { + final Prop? sigma; + + const BlurModifierMix.create({this.sigma}); + + BlurModifierMix({double? sigma}) : this.create(sigma: Prop.maybe(sigma)); + + @override + BlurModifier resolve(BuildContext context) { + return BlurModifier(MixOps.resolve(context, sigma)); + } + + @override + BlurModifierMix merge(BlurModifierMix? other) { + if (other == null) return this; + + return BlurModifierMix.create(sigma: MixOps.merge(sigma, other.sigma)); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('sigma', sigma)); + } + + @override + List get props => [sigma]; +} diff --git a/packages/mix/lib/src/modifiers/clip_modifier.dart b/packages/mix/lib/src/modifiers/clip_modifier.dart index ae8cb25ad..69ce5cae0 100644 --- a/packages/mix/lib/src/modifiers/clip_modifier.dart +++ b/packages/mix/lib/src/modifiers/clip_modifier.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; +import 'package:mix_annotations/mix_annotations.dart'; import '../core/helpers.dart'; import '../core/widget_modifier.dart'; @@ -7,185 +8,59 @@ import '../core/prop.dart'; import '../core/style.dart'; import '../properties/painting/border_radius_mix.dart'; +part 'clip_modifier.g.dart'; + /// Modifier that clips its child to an oval shape. /// /// Wraps the child in a [ClipOval] widget with the specified clipper and clip behavior. +@MixableModifier() final class ClipOvalModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$ClipOvalModifierMethods { + @override final CustomClipper? clipper; + @override final Clip clipBehavior; const ClipOvalModifier({this.clipper, Clip? clipBehavior}) : clipBehavior = clipBehavior ?? .antiAlias; - @override - ClipOvalModifier copyWith({ - CustomClipper? clipper, - Clip? clipBehavior, - }) { - return ClipOvalModifier( - clipper: clipper ?? this.clipper, - clipBehavior: clipBehavior ?? this.clipBehavior, - ); - } - - @override - ClipOvalModifier lerp(ClipOvalModifier? other, double t) { - if (other == null) return this; - - return ClipOvalModifier( - clipper: MixOps.lerpSnap(clipper, other.clipper, t), - clipBehavior: MixOps.lerpSnap(clipBehavior, other.clipBehavior, t)!, - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('clipper', clipper)) - ..add(EnumProperty('clipBehavior', clipBehavior)); - } - - @override - List get props => [clipper, clipBehavior]; - @override Widget build(Widget child) { return ClipOval(clipper: clipper, clipBehavior: clipBehavior, child: child); } } -/// Mix class for applying clip oval modifications. -/// -/// This class allows for mixing and resolving clip oval properties. -class ClipOvalModifierMix extends ModifierMix { - final Prop>? clipper; - final Prop? clipBehavior; - - const ClipOvalModifierMix.create({this.clipper, this.clipBehavior}); - - ClipOvalModifierMix({CustomClipper? clipper, Clip? clipBehavior}) - : this.create( - clipper: Prop.maybe(clipper), - clipBehavior: Prop.maybe(clipBehavior), - ); - - @override - ClipOvalModifier resolve(BuildContext context) { - return ClipOvalModifier( - clipper: MixOps.resolve(context, clipper), - clipBehavior: MixOps.resolve(context, clipBehavior), - ); - } - - @override - ClipOvalModifierMix merge(ClipOvalModifierMix? other) { - if (other == null) return this; - - return ClipOvalModifierMix.create( - clipper: MixOps.merge(clipper, other.clipper), - clipBehavior: MixOps.merge(clipBehavior, other.clipBehavior), - ); - } - - @override - List get props => [clipper, clipBehavior]; -} - /// Modifier that clips its child to a rectangular shape. /// /// Wraps the child in a [ClipRect] widget with the specified clipper and clip behavior. +@MixableModifier() final class ClipRectModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$ClipRectModifierMethods { + @override final CustomClipper? clipper; + @override final Clip clipBehavior; const ClipRectModifier({this.clipper, Clip? clipBehavior}) : clipBehavior = clipBehavior ?? .hardEdge; - @override - ClipRectModifier copyWith({ - CustomClipper? clipper, - Clip? clipBehavior, - }) { - return ClipRectModifier( - clipper: clipper ?? this.clipper, - clipBehavior: clipBehavior ?? this.clipBehavior, - ); - } - - @override - ClipRectModifier lerp(ClipRectModifier? other, double t) { - if (other == null) return this; - - return ClipRectModifier( - clipper: MixOps.lerpSnap(clipper, other.clipper, t), - clipBehavior: MixOps.lerpSnap(clipBehavior, other.clipBehavior, t)!, - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('clipper', clipper)) - ..add(EnumProperty('clipBehavior', clipBehavior)); - } - - @override - List get props => [clipper, clipBehavior]; - @override Widget build(Widget child) { return ClipRect(clipper: clipper, clipBehavior: clipBehavior, child: child); } } -/// Mix class for applying clip rect modifications. -/// -/// This class allows for mixing and resolving clip rect properties. -class ClipRectModifierMix extends ModifierMix { - final Prop>? clipper; - final Prop? clipBehavior; - - const ClipRectModifierMix.create({this.clipper, this.clipBehavior}); - - ClipRectModifierMix({CustomClipper? clipper, Clip? clipBehavior}) - : this.create( - clipper: Prop.maybe(clipper), - clipBehavior: Prop.maybe(clipBehavior), - ); - - @override - ClipRectModifier resolve(BuildContext context) { - return ClipRectModifier( - clipper: MixOps.resolve(context, clipper), - clipBehavior: MixOps.resolve(context, clipBehavior), - ); - } - - @override - ClipRectModifierMix merge(ClipRectModifierMix? other) { - if (other == null) return this; - - return ClipRectModifierMix.create( - clipper: MixOps.merge(clipper, other.clipper), - clipBehavior: MixOps.merge(clipBehavior, other.clipBehavior), - ); - } - - @override - List get props => [clipper, clipBehavior]; -} - /// Modifier that clips its child to a rounded rectangular shape. /// /// Wraps the child in a [ClipRRect] widget with the specified border radius. +@MixableModifier() final class ClipRRectModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$ClipRRectModifierMethods { + @override final BorderRadiusGeometry borderRadius; + @override final CustomClipper? clipper; + @override final Clip clipBehavior; const ClipRRectModifier({ @@ -195,42 +70,6 @@ final class ClipRRectModifier extends WidgetModifier }) : borderRadius = borderRadius ?? BorderRadius.zero, clipBehavior = clipBehavior ?? .antiAlias; - @override - ClipRRectModifier copyWith({ - BorderRadiusGeometry? borderRadius, - CustomClipper? clipper, - Clip? clipBehavior, - }) { - return ClipRRectModifier( - borderRadius: borderRadius ?? this.borderRadius, - clipper: clipper ?? this.clipper, - clipBehavior: clipBehavior ?? this.clipBehavior, - ); - } - - @override - ClipRRectModifier lerp(ClipRRectModifier? other, double t) { - if (other == null) return this; - - return ClipRRectModifier( - borderRadius: MixOps.lerp(borderRadius, other.borderRadius, t)!, - clipper: MixOps.lerpSnap(clipper, other.clipper, t), - clipBehavior: MixOps.lerpSnap(clipBehavior, other.clipBehavior, t)!, - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('borderRadius', borderRadius)) - ..add(DiagnosticsProperty('clipper', clipper)) - ..add(EnumProperty('clipBehavior', clipBehavior)); - } - - @override - List get props => [borderRadius, clipper, clipBehavior]; - @override Widget build(Widget child) { return ClipRRect( @@ -242,175 +81,38 @@ final class ClipRRectModifier extends WidgetModifier } } -/// Mix class for applying clip rounded rect modifications. -/// -/// This class allows for mixing and resolving clip rounded rect properties. -class ClipRRectModifierMix extends ModifierMix { - final Prop? borderRadius; - final Prop>? clipper; - final Prop? clipBehavior; - - const ClipRRectModifierMix.create({ - this.borderRadius, - this.clipper, - this.clipBehavior, - }); - - ClipRRectModifierMix({ - BorderRadiusGeometryMix? borderRadius, - CustomClipper? clipper, - Clip? clipBehavior, - }) : this.create( - borderRadius: Prop.maybeMix(borderRadius), - clipper: Prop.maybe(clipper), - clipBehavior: Prop.maybe(clipBehavior), - ); - - @override - ClipRRectModifier resolve(BuildContext context) { - return ClipRRectModifier( - borderRadius: MixOps.resolve(context, borderRadius), - clipper: MixOps.resolve(context, clipper), - clipBehavior: MixOps.resolve(context, clipBehavior), - ); - } - - @override - ClipRRectModifierMix merge(ClipRRectModifierMix? other) { - if (other == null) return this; - - return ClipRRectModifierMix.create( - borderRadius: MixOps.merge(borderRadius, other.borderRadius), - clipper: MixOps.merge(clipper, other.clipper), - clipBehavior: MixOps.merge(clipBehavior, other.clipBehavior), - ); - } - - @override - List get props => [borderRadius, clipper, clipBehavior]; -} - /// Modifier that clips its child using a custom path. /// /// Wraps the child in a [ClipPath] widget with the specified clipper. +@MixableModifier() final class ClipPathModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$ClipPathModifierMethods { + @override final CustomClipper? clipper; + @override final Clip clipBehavior; const ClipPathModifier({this.clipper, Clip? clipBehavior}) : clipBehavior = clipBehavior ?? .antiAlias; - @override - ClipPathModifier copyWith({ - CustomClipper? clipper, - Clip? clipBehavior, - }) { - return ClipPathModifier( - clipper: clipper ?? this.clipper, - clipBehavior: clipBehavior ?? this.clipBehavior, - ); - } - - @override - ClipPathModifier lerp(ClipPathModifier? other, double t) { - if (other == null) return this; - - return ClipPathModifier( - clipper: MixOps.lerpSnap(clipper, other.clipper, t), - clipBehavior: MixOps.lerpSnap(clipBehavior, other.clipBehavior, t)!, - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('clipper', clipper)) - ..add(EnumProperty('clipBehavior', clipBehavior)); - } - - @override - List get props => [clipper, clipBehavior]; - @override Widget build(Widget child) { return ClipPath(clipper: clipper, clipBehavior: clipBehavior, child: child); } } -/// Mix class for applying clip path modifications. -/// -/// This class allows for mixing and resolving clip path properties. -class ClipPathModifierMix extends ModifierMix { - final Prop>? clipper; - final Prop? clipBehavior; - - const ClipPathModifierMix.create({this.clipper, this.clipBehavior}); - - ClipPathModifierMix({CustomClipper? clipper, Clip? clipBehavior}) - : this.create( - clipper: Prop.maybe(clipper), - clipBehavior: Prop.maybe(clipBehavior), - ); - - @override - ClipPathModifier resolve(BuildContext context) { - return ClipPathModifier( - clipper: MixOps.resolve(context, clipper), - clipBehavior: MixOps.resolve(context, clipBehavior), - ); - } - - @override - ClipPathModifierMix merge(ClipPathModifierMix? other) { - if (other == null) return this; - - return ClipPathModifierMix.create( - clipper: MixOps.merge(clipper, other.clipper), - clipBehavior: MixOps.merge(clipBehavior, other.clipBehavior), - ); - } - - @override - List get props => [clipper, clipBehavior]; -} - /// Modifier that clips its child to a triangle shape. /// /// Wraps the child in a [ClipPath] widget using a triangle clipper. +@MixableModifier() final class ClipTriangleModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$ClipTriangleModifierMethods { + @override final Clip clipBehavior; const ClipTriangleModifier({Clip? clipBehavior}) : clipBehavior = clipBehavior ?? .antiAlias; - @override - ClipTriangleModifier copyWith({Clip? clipBehavior}) { - return ClipTriangleModifier( - clipBehavior: clipBehavior ?? this.clipBehavior, - ); - } - - @override - ClipTriangleModifier lerp(ClipTriangleModifier? other, double t) { - if (other == null) return this; - - return ClipTriangleModifier( - clipBehavior: MixOps.lerpSnap(clipBehavior, other.clipBehavior, t)!, - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('clipBehavior', clipBehavior)); - } - - @override - List get props => [clipBehavior]; - @override Widget build(Widget child) { return ClipPath( @@ -421,37 +123,6 @@ final class ClipTriangleModifier extends WidgetModifier } } -/// Mix class for applying clip triangle modifications. -/// -/// This class allows for mixing and resolving clip triangle properties. -class ClipTriangleModifierMix extends ModifierMix { - final Prop? clipBehavior; - - const ClipTriangleModifierMix.create({this.clipBehavior}); - - ClipTriangleModifierMix({Clip? clipBehavior}) - : this.create(clipBehavior: Prop.maybe(clipBehavior)); - - @override - ClipTriangleModifier resolve(BuildContext context) { - return ClipTriangleModifier( - clipBehavior: MixOps.resolve(context, clipBehavior), - ); - } - - @override - ClipTriangleModifierMix merge(ClipTriangleModifierMix? other) { - if (other == null) return this; - - return ClipTriangleModifierMix.create( - clipBehavior: MixOps.merge(clipBehavior, other.clipBehavior), - ); - } - - @override - List get props => [clipBehavior]; -} - class TriangleClipper extends CustomClipper { const TriangleClipper(); @override diff --git a/packages/mix/lib/src/modifiers/clip_modifier.g.dart b/packages/mix/lib/src/modifiers/clip_modifier.g.dart new file mode 100644 index 000000000..75749e103 --- /dev/null +++ b/packages/mix/lib/src/modifiers/clip_modifier.g.dart @@ -0,0 +1,413 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'clip_modifier.dart'; + +// ************************************************************************** +// ModifierGenerator +// ************************************************************************** + +mixin _$ClipOvalModifierMethods + on WidgetModifier, Diagnosticable { + Clip get clipBehavior; + CustomClipper? get clipper; + + @override + ClipOvalModifier copyWith({ + Clip? clipBehavior, + CustomClipper? clipper, + }) { + return ClipOvalModifier( + clipBehavior: clipBehavior ?? this.clipBehavior, + clipper: clipper ?? this.clipper, + ); + } + + @override + ClipOvalModifier lerp(ClipOvalModifier? other, double t) { + if (other == null) return this as ClipOvalModifier; + + return ClipOvalModifier( + clipBehavior: MixOps.lerpSnap(clipBehavior, other.clipBehavior, t)!, + clipper: MixOps.lerpSnap(clipper, other.clipper, t), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(EnumProperty('clipBehavior', clipBehavior)) + ..add(DiagnosticsProperty('clipper', clipper)); + } + + @override + List get props => [clipBehavior, clipper]; +} + +class ClipOvalModifierMix extends ModifierMix + with Diagnosticable { + final Prop? clipBehavior; + final Prop>? clipper; + + const ClipOvalModifierMix.create({this.clipBehavior, this.clipper}); + + ClipOvalModifierMix({Clip? clipBehavior, CustomClipper? clipper}) + : this.create( + clipBehavior: Prop.maybe(clipBehavior), + clipper: Prop.maybe(clipper), + ); + + @override + ClipOvalModifier resolve(BuildContext context) { + return ClipOvalModifier( + clipBehavior: MixOps.resolve(context, clipBehavior), + clipper: MixOps.resolve(context, clipper), + ); + } + + @override + ClipOvalModifierMix merge(ClipOvalModifierMix? other) { + if (other == null) return this; + + return ClipOvalModifierMix.create( + clipBehavior: MixOps.merge(clipBehavior, other.clipBehavior), + clipper: MixOps.merge(clipper, other.clipper), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('clipBehavior', clipBehavior)) + ..add(DiagnosticsProperty('clipper', clipper)); + } + + @override + List get props => [clipBehavior, clipper]; +} + +mixin _$ClipRectModifierMethods + on WidgetModifier, Diagnosticable { + Clip get clipBehavior; + CustomClipper? get clipper; + + @override + ClipRectModifier copyWith({ + Clip? clipBehavior, + CustomClipper? clipper, + }) { + return ClipRectModifier( + clipBehavior: clipBehavior ?? this.clipBehavior, + clipper: clipper ?? this.clipper, + ); + } + + @override + ClipRectModifier lerp(ClipRectModifier? other, double t) { + if (other == null) return this as ClipRectModifier; + + return ClipRectModifier( + clipBehavior: MixOps.lerpSnap(clipBehavior, other.clipBehavior, t)!, + clipper: MixOps.lerpSnap(clipper, other.clipper, t), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(EnumProperty('clipBehavior', clipBehavior)) + ..add(DiagnosticsProperty('clipper', clipper)); + } + + @override + List get props => [clipBehavior, clipper]; +} + +class ClipRectModifierMix extends ModifierMix + with Diagnosticable { + final Prop? clipBehavior; + final Prop>? clipper; + + const ClipRectModifierMix.create({this.clipBehavior, this.clipper}); + + ClipRectModifierMix({Clip? clipBehavior, CustomClipper? clipper}) + : this.create( + clipBehavior: Prop.maybe(clipBehavior), + clipper: Prop.maybe(clipper), + ); + + @override + ClipRectModifier resolve(BuildContext context) { + return ClipRectModifier( + clipBehavior: MixOps.resolve(context, clipBehavior), + clipper: MixOps.resolve(context, clipper), + ); + } + + @override + ClipRectModifierMix merge(ClipRectModifierMix? other) { + if (other == null) return this; + + return ClipRectModifierMix.create( + clipBehavior: MixOps.merge(clipBehavior, other.clipBehavior), + clipper: MixOps.merge(clipper, other.clipper), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('clipBehavior', clipBehavior)) + ..add(DiagnosticsProperty('clipper', clipper)); + } + + @override + List get props => [clipBehavior, clipper]; +} + +mixin _$ClipRRectModifierMethods + on WidgetModifier, Diagnosticable { + BorderRadiusGeometry get borderRadius; + Clip get clipBehavior; + CustomClipper? get clipper; + + @override + ClipRRectModifier copyWith({ + BorderRadiusGeometry? borderRadius, + Clip? clipBehavior, + CustomClipper? clipper, + }) { + return ClipRRectModifier( + borderRadius: borderRadius ?? this.borderRadius, + clipBehavior: clipBehavior ?? this.clipBehavior, + clipper: clipper ?? this.clipper, + ); + } + + @override + ClipRRectModifier lerp(ClipRRectModifier? other, double t) { + if (other == null) return this as ClipRRectModifier; + + return ClipRRectModifier( + borderRadius: MixOps.lerp(borderRadius, other.borderRadius, t)!, + clipBehavior: MixOps.lerpSnap(clipBehavior, other.clipBehavior, t)!, + clipper: MixOps.lerpSnap(clipper, other.clipper, t), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('borderRadius', borderRadius)) + ..add(EnumProperty('clipBehavior', clipBehavior)) + ..add(DiagnosticsProperty('clipper', clipper)); + } + + @override + List get props => [borderRadius, clipBehavior, clipper]; +} + +class ClipRRectModifierMix extends ModifierMix + with Diagnosticable { + final Prop? borderRadius; + final Prop? clipBehavior; + final Prop>? clipper; + + const ClipRRectModifierMix.create({ + this.borderRadius, + this.clipBehavior, + this.clipper, + }); + + ClipRRectModifierMix({ + BorderRadiusGeometryMix? borderRadius, + Clip? clipBehavior, + CustomClipper? clipper, + }) : this.create( + borderRadius: Prop.maybeMix(borderRadius), + clipBehavior: Prop.maybe(clipBehavior), + clipper: Prop.maybe(clipper), + ); + + @override + ClipRRectModifier resolve(BuildContext context) { + return ClipRRectModifier( + borderRadius: MixOps.resolve(context, borderRadius), + clipBehavior: MixOps.resolve(context, clipBehavior), + clipper: MixOps.resolve(context, clipper), + ); + } + + @override + ClipRRectModifierMix merge(ClipRRectModifierMix? other) { + if (other == null) return this; + + return ClipRRectModifierMix.create( + borderRadius: MixOps.merge(borderRadius, other.borderRadius), + clipBehavior: MixOps.merge(clipBehavior, other.clipBehavior), + clipper: MixOps.merge(clipper, other.clipper), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('borderRadius', borderRadius)) + ..add(DiagnosticsProperty('clipBehavior', clipBehavior)) + ..add(DiagnosticsProperty('clipper', clipper)); + } + + @override + List get props => [borderRadius, clipBehavior, clipper]; +} + +mixin _$ClipPathModifierMethods + on WidgetModifier, Diagnosticable { + Clip get clipBehavior; + CustomClipper? get clipper; + + @override + ClipPathModifier copyWith({ + Clip? clipBehavior, + CustomClipper? clipper, + }) { + return ClipPathModifier( + clipBehavior: clipBehavior ?? this.clipBehavior, + clipper: clipper ?? this.clipper, + ); + } + + @override + ClipPathModifier lerp(ClipPathModifier? other, double t) { + if (other == null) return this as ClipPathModifier; + + return ClipPathModifier( + clipBehavior: MixOps.lerpSnap(clipBehavior, other.clipBehavior, t)!, + clipper: MixOps.lerpSnap(clipper, other.clipper, t), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(EnumProperty('clipBehavior', clipBehavior)) + ..add(DiagnosticsProperty('clipper', clipper)); + } + + @override + List get props => [clipBehavior, clipper]; +} + +class ClipPathModifierMix extends ModifierMix + with Diagnosticable { + final Prop? clipBehavior; + final Prop>? clipper; + + const ClipPathModifierMix.create({this.clipBehavior, this.clipper}); + + ClipPathModifierMix({Clip? clipBehavior, CustomClipper? clipper}) + : this.create( + clipBehavior: Prop.maybe(clipBehavior), + clipper: Prop.maybe(clipper), + ); + + @override + ClipPathModifier resolve(BuildContext context) { + return ClipPathModifier( + clipBehavior: MixOps.resolve(context, clipBehavior), + clipper: MixOps.resolve(context, clipper), + ); + } + + @override + ClipPathModifierMix merge(ClipPathModifierMix? other) { + if (other == null) return this; + + return ClipPathModifierMix.create( + clipBehavior: MixOps.merge(clipBehavior, other.clipBehavior), + clipper: MixOps.merge(clipper, other.clipper), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('clipBehavior', clipBehavior)) + ..add(DiagnosticsProperty('clipper', clipper)); + } + + @override + List get props => [clipBehavior, clipper]; +} + +mixin _$ClipTriangleModifierMethods + on WidgetModifier, Diagnosticable { + Clip get clipBehavior; + + @override + ClipTriangleModifier copyWith({Clip? clipBehavior}) { + return ClipTriangleModifier( + clipBehavior: clipBehavior ?? this.clipBehavior, + ); + } + + @override + ClipTriangleModifier lerp(ClipTriangleModifier? other, double t) { + if (other == null) return this as ClipTriangleModifier; + + return ClipTriangleModifier( + clipBehavior: MixOps.lerpSnap(clipBehavior, other.clipBehavior, t)!, + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(EnumProperty('clipBehavior', clipBehavior)); + } + + @override + List get props => [clipBehavior]; +} + +class ClipTriangleModifierMix extends ModifierMix + with Diagnosticable { + final Prop? clipBehavior; + + const ClipTriangleModifierMix.create({this.clipBehavior}); + + ClipTriangleModifierMix({Clip? clipBehavior}) + : this.create(clipBehavior: Prop.maybe(clipBehavior)); + + @override + ClipTriangleModifier resolve(BuildContext context) { + return ClipTriangleModifier( + clipBehavior: MixOps.resolve(context, clipBehavior), + ); + } + + @override + ClipTriangleModifierMix merge(ClipTriangleModifierMix? other) { + if (other == null) return this; + + return ClipTriangleModifierMix.create( + clipBehavior: MixOps.merge(clipBehavior, other.clipBehavior), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('clipBehavior', clipBehavior)); + } + + @override + List get props => [clipBehavior]; +} diff --git a/packages/mix/lib/src/modifiers/default_text_style_modifier.dart b/packages/mix/lib/src/modifiers/default_text_style_modifier.dart index 6f042ebed..b252155ad 100644 --- a/packages/mix/lib/src/modifiers/default_text_style_modifier.dart +++ b/packages/mix/lib/src/modifiers/default_text_style_modifier.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; +import 'package:mix_annotations/mix_annotations.dart'; import '../core/helpers.dart'; import '../core/widget_modifier.dart'; @@ -8,18 +9,28 @@ import '../core/style.dart'; import '../properties/typography/text_height_behavior_mix.dart'; import '../properties/typography/text_style_mix.dart'; +part 'default_text_style_modifier.g.dart'; + /// Modifier that applies default text styling to its descendants. /// /// Wraps the child in a [DefaultTextStyle] widget with the specified text properties. +@MixableModifier() final class DefaultTextStyleModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$DefaultTextStyleModifierMethods { + @override final TextStyle style; + @override final TextAlign? textAlign; + @override final bool softWrap; + @override final TextOverflow overflow; + @override final int? maxLines; + @override final TextWidthBasis textWidthBasis; + @override final TextHeightBehavior? textHeightBehavior; const DefaultTextStyleModifier({ @@ -35,70 +46,6 @@ final class DefaultTextStyleModifier overflow = overflow ?? .clip, textWidthBasis = textWidthBasis ?? .parent; - @override - DefaultTextStyleModifier copyWith({ - TextStyle? style, - TextAlign? textAlign, - bool? softWrap, - TextOverflow? overflow, - int? maxLines, - TextWidthBasis? textWidthBasis, - TextHeightBehavior? textHeightBehavior, - }) { - return DefaultTextStyleModifier( - style: style ?? this.style, - textAlign: textAlign ?? this.textAlign, - softWrap: softWrap ?? this.softWrap, - overflow: overflow ?? this.overflow, - maxLines: maxLines ?? this.maxLines, - textWidthBasis: textWidthBasis ?? this.textWidthBasis, - textHeightBehavior: textHeightBehavior ?? this.textHeightBehavior, - ); - } - - @override - DefaultTextStyleModifier lerp(DefaultTextStyleModifier? other, double t) { - if (other == null) return this; - - return DefaultTextStyleModifier( - style: MixOps.lerp(style, other.style, t)!, - textAlign: MixOps.lerpSnap(textAlign, other.textAlign, t), - softWrap: MixOps.lerpSnap(softWrap, other.softWrap, t)!, - overflow: MixOps.lerpSnap(overflow, other.overflow, t)!, - maxLines: MixOps.lerpSnap(maxLines, other.maxLines, t), - textWidthBasis: MixOps.lerpSnap(textWidthBasis, other.textWidthBasis, t)!, - textHeightBehavior: MixOps.lerpSnap( - textHeightBehavior, - other.textHeightBehavior, - t, - ), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('style', style)) - ..add(EnumProperty('textAlign', textAlign)) - ..add(FlagProperty('softWrap', value: softWrap, ifTrue: 'soft wrap')) - ..add(EnumProperty('overflow', overflow)) - ..add(IntProperty('maxLines', maxLines)) - ..add(EnumProperty('textWidthBasis', textWidthBasis)) - ..add(DiagnosticsProperty('textHeightBehavior', textHeightBehavior)); - } - - @override - List get props => [ - style, - textAlign, - softWrap, - overflow, - maxLines, - textWidthBasis, - textHeightBehavior, - ]; - @override Widget build(Widget child) { return DefaultTextStyle( @@ -113,87 +60,3 @@ final class DefaultTextStyleModifier ); } } - -/// Mix class for applying default text style modifications. -/// -/// This class allows for mixing and resolving default text style properties. -class DefaultTextStyleModifierMix - extends ModifierMix { - final Prop? style; - final Prop? textAlign; - final Prop? softWrap; - final Prop? overflow; - final Prop? maxLines; - final Prop? textWidthBasis; - final Prop? textHeightBehavior; - - const DefaultTextStyleModifierMix.create({ - this.style, - this.textAlign, - this.softWrap, - this.overflow, - this.maxLines, - this.textWidthBasis, - this.textHeightBehavior, - }); - - DefaultTextStyleModifierMix({ - TextStyleMix? style, - TextAlign? textAlign, - bool? softWrap, - TextOverflow? overflow, - int? maxLines, - TextWidthBasis? textWidthBasis, - TextHeightBehaviorMix? textHeightBehavior, - }) : this.create( - style: Prop.maybeMix(style), - textAlign: Prop.maybe(textAlign), - softWrap: Prop.maybe(softWrap), - overflow: Prop.maybe(overflow), - maxLines: Prop.maybe(maxLines), - textWidthBasis: Prop.maybe(textWidthBasis), - textHeightBehavior: Prop.maybeMix(textHeightBehavior), - ); - - @override - DefaultTextStyleModifier resolve(BuildContext context) { - return DefaultTextStyleModifier( - style: MixOps.resolve(context, style), - textAlign: MixOps.resolve(context, textAlign), - softWrap: MixOps.resolve(context, softWrap), - overflow: MixOps.resolve(context, overflow), - maxLines: MixOps.resolve(context, maxLines), - textWidthBasis: MixOps.resolve(context, textWidthBasis), - textHeightBehavior: MixOps.resolve(context, textHeightBehavior), - ); - } - - @override - DefaultTextStyleModifierMix merge(DefaultTextStyleModifierMix? other) { - if (other == null) return this; - - return DefaultTextStyleModifierMix.create( - style: MixOps.merge(style, other.style), - textAlign: MixOps.merge(textAlign, other.textAlign), - softWrap: MixOps.merge(softWrap, other.softWrap), - overflow: MixOps.merge(overflow, other.overflow), - maxLines: MixOps.merge(maxLines, other.maxLines), - textWidthBasis: MixOps.merge(textWidthBasis, other.textWidthBasis), - textHeightBehavior: MixOps.merge( - textHeightBehavior, - other.textHeightBehavior, - ), - ); - } - - @override - List get props => [ - style, - textAlign, - softWrap, - overflow, - maxLines, - textWidthBasis, - textHeightBehavior, - ]; -} diff --git a/packages/mix/lib/src/modifiers/default_text_style_modifier.g.dart b/packages/mix/lib/src/modifiers/default_text_style_modifier.g.dart new file mode 100644 index 000000000..6224bf5b9 --- /dev/null +++ b/packages/mix/lib/src/modifiers/default_text_style_modifier.g.dart @@ -0,0 +1,182 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'default_text_style_modifier.dart'; + +// ************************************************************************** +// ModifierGenerator +// ************************************************************************** + +mixin _$DefaultTextStyleModifierMethods + on WidgetModifier, Diagnosticable { + int? get maxLines; + TextOverflow get overflow; + bool get softWrap; + TextStyle get style; + TextAlign? get textAlign; + TextHeightBehavior? get textHeightBehavior; + TextWidthBasis get textWidthBasis; + + @override + DefaultTextStyleModifier copyWith({ + int? maxLines, + TextOverflow? overflow, + bool? softWrap, + TextStyle? style, + TextAlign? textAlign, + TextHeightBehavior? textHeightBehavior, + TextWidthBasis? textWidthBasis, + }) { + return DefaultTextStyleModifier( + maxLines: maxLines ?? this.maxLines, + overflow: overflow ?? this.overflow, + softWrap: softWrap ?? this.softWrap, + style: style ?? this.style, + textAlign: textAlign ?? this.textAlign, + textHeightBehavior: textHeightBehavior ?? this.textHeightBehavior, + textWidthBasis: textWidthBasis ?? this.textWidthBasis, + ); + } + + @override + DefaultTextStyleModifier lerp(DefaultTextStyleModifier? other, double t) { + if (other == null) return this as DefaultTextStyleModifier; + + return DefaultTextStyleModifier( + maxLines: MixOps.lerp(maxLines, other.maxLines, t), + overflow: MixOps.lerpSnap(overflow, other.overflow, t)!, + softWrap: MixOps.lerpSnap(softWrap, other.softWrap, t)!, + style: MixOps.lerp(style, other.style, t)!, + textAlign: MixOps.lerpSnap(textAlign, other.textAlign, t), + textHeightBehavior: MixOps.lerpSnap( + textHeightBehavior, + other.textHeightBehavior, + t, + ), + textWidthBasis: MixOps.lerpSnap(textWidthBasis, other.textWidthBasis, t)!, + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(IntProperty('maxLines', maxLines)) + ..add(EnumProperty('overflow', overflow)) + ..add( + FlagProperty( + 'softWrap', + value: softWrap, + ifTrue: 'wrapping at word boundaries', + ), + ) + ..add(DiagnosticsProperty('style', style)) + ..add(EnumProperty('textAlign', textAlign)) + ..add(DiagnosticsProperty('textHeightBehavior', textHeightBehavior)) + ..add(EnumProperty('textWidthBasis', textWidthBasis)); + } + + @override + List get props => [ + maxLines, + overflow, + softWrap, + style, + textAlign, + textHeightBehavior, + textWidthBasis, + ]; +} + +class DefaultTextStyleModifierMix extends ModifierMix + with Diagnosticable { + final Prop? maxLines; + final Prop? overflow; + final Prop? softWrap; + final Prop? style; + final Prop? textAlign; + final Prop? textHeightBehavior; + final Prop? textWidthBasis; + + const DefaultTextStyleModifierMix.create({ + this.maxLines, + this.overflow, + this.softWrap, + this.style, + this.textAlign, + this.textHeightBehavior, + this.textWidthBasis, + }); + + DefaultTextStyleModifierMix({ + int? maxLines, + TextOverflow? overflow, + bool? softWrap, + TextStyleMix? style, + TextAlign? textAlign, + TextHeightBehaviorMix? textHeightBehavior, + TextWidthBasis? textWidthBasis, + }) : this.create( + maxLines: Prop.maybe(maxLines), + overflow: Prop.maybe(overflow), + softWrap: Prop.maybe(softWrap), + style: Prop.maybeMix(style), + textAlign: Prop.maybe(textAlign), + textHeightBehavior: Prop.maybeMix(textHeightBehavior), + textWidthBasis: Prop.maybe(textWidthBasis), + ); + + @override + DefaultTextStyleModifier resolve(BuildContext context) { + return DefaultTextStyleModifier( + maxLines: MixOps.resolve(context, maxLines), + overflow: MixOps.resolve(context, overflow), + softWrap: MixOps.resolve(context, softWrap), + style: MixOps.resolve(context, style), + textAlign: MixOps.resolve(context, textAlign), + textHeightBehavior: MixOps.resolve(context, textHeightBehavior), + textWidthBasis: MixOps.resolve(context, textWidthBasis), + ); + } + + @override + DefaultTextStyleModifierMix merge(DefaultTextStyleModifierMix? other) { + if (other == null) return this; + + return DefaultTextStyleModifierMix.create( + maxLines: MixOps.merge(maxLines, other.maxLines), + overflow: MixOps.merge(overflow, other.overflow), + softWrap: MixOps.merge(softWrap, other.softWrap), + style: MixOps.merge(style, other.style), + textAlign: MixOps.merge(textAlign, other.textAlign), + textHeightBehavior: MixOps.merge( + textHeightBehavior, + other.textHeightBehavior, + ), + textWidthBasis: MixOps.merge(textWidthBasis, other.textWidthBasis), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('maxLines', maxLines)) + ..add(DiagnosticsProperty('overflow', overflow)) + ..add(DiagnosticsProperty('softWrap', softWrap)) + ..add(DiagnosticsProperty('style', style)) + ..add(DiagnosticsProperty('textAlign', textAlign)) + ..add(DiagnosticsProperty('textHeightBehavior', textHeightBehavior)) + ..add(DiagnosticsProperty('textWidthBasis', textWidthBasis)); + } + + @override + List get props => [ + maxLines, + overflow, + softWrap, + style, + textAlign, + textHeightBehavior, + textWidthBasis, + ]; +} diff --git a/packages/mix/lib/src/modifiers/flexible_modifier.dart b/packages/mix/lib/src/modifiers/flexible_modifier.dart index 782ca4e7f..959d41577 100644 --- a/packages/mix/lib/src/modifiers/flexible_modifier.dart +++ b/packages/mix/lib/src/modifiers/flexible_modifier.dart @@ -1,91 +1,28 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; +import 'package:mix_annotations/mix_annotations.dart'; import '../core/helpers.dart'; import '../core/widget_modifier.dart'; import '../core/prop.dart'; import '../core/style.dart'; +part 'flexible_modifier.g.dart'; + /// Modifier that makes its child flexible within a flex layout. /// /// Wraps the child in a [Flexible] widget with the specified flex and fit properties. +@MixableModifier() final class FlexibleModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$FlexibleModifierMethods { + @override final int? flex; + @override final FlexFit? fit; const FlexibleModifier({this.flex, this.fit}); - @override - FlexibleModifier copyWith({int? flex, FlexFit? fit}) { - return FlexibleModifier(flex: flex ?? this.flex, fit: fit ?? this.fit); - } - - @override - FlexibleModifier lerp(FlexibleModifier? other, double t) { - if (other == null) return this; - - return FlexibleModifier( - flex: MixOps.lerpSnap(flex, other.flex, t), - fit: MixOps.lerpSnap(fit, other.fit, t), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(IntProperty('flex', flex)) - ..add(EnumProperty('fit', fit)); - } - - @override - List get props => [flex, fit]; - @override Widget build(Widget child) { return Flexible(flex: flex ?? 1, fit: fit ?? .loose, child: child); } } - -/// Mix class for applying flexible modifications. -/// -/// This class allows for mixing and resolving flexible properties. -class FlexibleModifierMix extends ModifierMix - with Diagnosticable { - final Prop? flex; - final Prop? fit; - - const FlexibleModifierMix.create({this.flex, this.fit}); - - FlexibleModifierMix({int? flex, FlexFit? fit}) - : this.create(flex: Prop.maybe(flex), fit: Prop.maybe(fit)); - - @override - FlexibleModifier resolve(BuildContext context) { - return FlexibleModifier( - flex: MixOps.resolve(context, flex), - fit: MixOps.resolve(context, fit), - ); - } - - @override - FlexibleModifierMix merge(FlexibleModifierMix? other) { - if (other == null) return this; - - return FlexibleModifierMix.create( - flex: flex?.mergeProp(other.flex) ?? other.flex, - fit: fit?.mergeProp(other.fit) ?? other.fit, - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('flex', flex)) - ..add(DiagnosticsProperty('fit', fit)); - } - - @override - List get props => [flex, fit]; -} diff --git a/packages/mix/lib/src/modifiers/flexible_modifier.g.dart b/packages/mix/lib/src/modifiers/flexible_modifier.g.dart new file mode 100644 index 000000000..9b9f8036d --- /dev/null +++ b/packages/mix/lib/src/modifiers/flexible_modifier.g.dart @@ -0,0 +1,79 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'flexible_modifier.dart'; + +// ************************************************************************** +// ModifierGenerator +// ************************************************************************** + +mixin _$FlexibleModifierMethods + on WidgetModifier, Diagnosticable { + FlexFit? get fit; + int? get flex; + + @override + FlexibleModifier copyWith({FlexFit? fit, int? flex}) { + return FlexibleModifier(fit: fit ?? this.fit, flex: flex ?? this.flex); + } + + @override + FlexibleModifier lerp(FlexibleModifier? other, double t) { + if (other == null) return this as FlexibleModifier; + + return FlexibleModifier( + fit: MixOps.lerpSnap(fit, other.fit, t), + flex: MixOps.lerp(flex, other.flex, t), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(EnumProperty('fit', fit)) + ..add(IntProperty('flex', flex)); + } + + @override + List get props => [fit, flex]; +} + +class FlexibleModifierMix extends ModifierMix + with Diagnosticable { + final Prop? fit; + final Prop? flex; + + const FlexibleModifierMix.create({this.fit, this.flex}); + + FlexibleModifierMix({FlexFit? fit, int? flex}) + : this.create(fit: Prop.maybe(fit), flex: Prop.maybe(flex)); + + @override + FlexibleModifier resolve(BuildContext context) { + return FlexibleModifier( + fit: MixOps.resolve(context, fit), + flex: MixOps.resolve(context, flex), + ); + } + + @override + FlexibleModifierMix merge(FlexibleModifierMix? other) { + if (other == null) return this; + + return FlexibleModifierMix.create( + fit: MixOps.merge(fit, other.fit), + flex: MixOps.merge(flex, other.flex), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('fit', fit)) + ..add(DiagnosticsProperty('flex', flex)); + } + + @override + List get props => [fit, flex]; +} diff --git a/packages/mix/lib/src/modifiers/fractionally_sized_box_modifier.dart b/packages/mix/lib/src/modifiers/fractionally_sized_box_modifier.dart index e9cf37f54..05c465711 100644 --- a/packages/mix/lib/src/modifiers/fractionally_sized_box_modifier.dart +++ b/packages/mix/lib/src/modifiers/fractionally_sized_box_modifier.dart @@ -1,19 +1,26 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; +import 'package:mix_annotations/mix_annotations.dart'; import '../core/helpers.dart'; import '../core/widget_modifier.dart'; import '../core/prop.dart'; import '../core/style.dart'; +part 'fractionally_sized_box_modifier.g.dart'; + /// Modifier that sizes its child to a fraction of the available space. /// /// Wraps the child in a [FractionallySizedBox] widget with the specified factors. +@MixableModifier() final class FractionallySizedBoxModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$FractionallySizedBoxModifierMethods { + @override final double? widthFactor; + @override final double? heightFactor; + @override final AlignmentGeometry alignment; const FractionallySizedBoxModifier({ @@ -22,45 +29,6 @@ final class FractionallySizedBoxModifier AlignmentGeometry? alignment, }) : alignment = alignment ?? Alignment.center; - @override - FractionallySizedBoxModifier copyWith({ - double? widthFactor, - double? heightFactor, - AlignmentGeometry? alignment, - }) { - return FractionallySizedBoxModifier( - widthFactor: widthFactor ?? this.widthFactor, - heightFactor: heightFactor ?? this.heightFactor, - alignment: alignment ?? this.alignment, - ); - } - - @override - FractionallySizedBoxModifier lerp( - FractionallySizedBoxModifier? other, - double t, - ) { - if (other == null) return this; - - return FractionallySizedBoxModifier( - widthFactor: MixOps.lerp(widthFactor, other.widthFactor, t), - heightFactor: MixOps.lerp(heightFactor, other.heightFactor, t), - alignment: MixOps.lerp(alignment, other.alignment, t)!, - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DoubleProperty('widthFactor', widthFactor)) - ..add(DoubleProperty('heightFactor', heightFactor)) - ..add(DiagnosticsProperty('alignment', alignment)); - } - - @override - List get props => [widthFactor, heightFactor, alignment]; - @override Widget build(Widget child) { return FractionallySizedBox( @@ -71,54 +39,3 @@ final class FractionallySizedBoxModifier ); } } - -/// Mix class for applying fractionally sized box modifications. -/// -/// This class allows for mixing and resolving fractionally sized box properties. -class FractionallySizedBoxModifierMix - extends ModifierMix { - final Prop? widthFactor; - final Prop? heightFactor; - final Prop? alignment; - - const FractionallySizedBoxModifierMix.create({ - this.widthFactor, - this.heightFactor, - this.alignment, - }); - - FractionallySizedBoxModifierMix({ - double? widthFactor, - double? heightFactor, - AlignmentGeometry? alignment, - }) : this.create( - widthFactor: Prop.maybe(widthFactor), - heightFactor: Prop.maybe(heightFactor), - alignment: Prop.maybe(alignment), - ); - - @override - FractionallySizedBoxModifier resolve(BuildContext context) { - return FractionallySizedBoxModifier( - widthFactor: MixOps.resolve(context, widthFactor), - heightFactor: MixOps.resolve(context, heightFactor), - alignment: MixOps.resolve(context, alignment), - ); - } - - @override - FractionallySizedBoxModifierMix merge( - FractionallySizedBoxModifierMix? other, - ) { - if (other == null) return this; - - return FractionallySizedBoxModifierMix.create( - widthFactor: MixOps.merge(widthFactor, other.widthFactor), - heightFactor: MixOps.merge(heightFactor, other.heightFactor), - alignment: MixOps.merge(alignment, other.alignment), - ); - } - - @override - List get props => [widthFactor, heightFactor, alignment]; -} diff --git a/packages/mix/lib/src/modifiers/fractionally_sized_box_modifier.g.dart b/packages/mix/lib/src/modifiers/fractionally_sized_box_modifier.g.dart new file mode 100644 index 000000000..a5343eb37 --- /dev/null +++ b/packages/mix/lib/src/modifiers/fractionally_sized_box_modifier.g.dart @@ -0,0 +1,111 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'fractionally_sized_box_modifier.dart'; + +// ************************************************************************** +// ModifierGenerator +// ************************************************************************** + +mixin _$FractionallySizedBoxModifierMethods + on WidgetModifier, Diagnosticable { + AlignmentGeometry get alignment; + double? get heightFactor; + double? get widthFactor; + + @override + FractionallySizedBoxModifier copyWith({ + AlignmentGeometry? alignment, + double? heightFactor, + double? widthFactor, + }) { + return FractionallySizedBoxModifier( + alignment: alignment ?? this.alignment, + heightFactor: heightFactor ?? this.heightFactor, + widthFactor: widthFactor ?? this.widthFactor, + ); + } + + @override + FractionallySizedBoxModifier lerp( + FractionallySizedBoxModifier? other, + double t, + ) { + if (other == null) return this as FractionallySizedBoxModifier; + + return FractionallySizedBoxModifier( + alignment: MixOps.lerp(alignment, other.alignment, t)!, + heightFactor: MixOps.lerp(heightFactor, other.heightFactor, t), + widthFactor: MixOps.lerp(widthFactor, other.widthFactor, t), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('alignment', alignment)) + ..add(DoubleProperty('heightFactor', heightFactor)) + ..add(DoubleProperty('widthFactor', widthFactor)); + } + + @override + List get props => [alignment, heightFactor, widthFactor]; +} + +class FractionallySizedBoxModifierMix + extends ModifierMix + with Diagnosticable { + final Prop? alignment; + final Prop? heightFactor; + final Prop? widthFactor; + + const FractionallySizedBoxModifierMix.create({ + this.alignment, + this.heightFactor, + this.widthFactor, + }); + + FractionallySizedBoxModifierMix({ + AlignmentGeometry? alignment, + double? heightFactor, + double? widthFactor, + }) : this.create( + alignment: Prop.maybe(alignment), + heightFactor: Prop.maybe(heightFactor), + widthFactor: Prop.maybe(widthFactor), + ); + + @override + FractionallySizedBoxModifier resolve(BuildContext context) { + return FractionallySizedBoxModifier( + alignment: MixOps.resolve(context, alignment), + heightFactor: MixOps.resolve(context, heightFactor), + widthFactor: MixOps.resolve(context, widthFactor), + ); + } + + @override + FractionallySizedBoxModifierMix merge( + FractionallySizedBoxModifierMix? other, + ) { + if (other == null) return this; + + return FractionallySizedBoxModifierMix.create( + alignment: MixOps.merge(alignment, other.alignment), + heightFactor: MixOps.merge(heightFactor, other.heightFactor), + widthFactor: MixOps.merge(widthFactor, other.widthFactor), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('alignment', alignment)) + ..add(DiagnosticsProperty('heightFactor', heightFactor)) + ..add(DiagnosticsProperty('widthFactor', widthFactor)); + } + + @override + List get props => [alignment, heightFactor, widthFactor]; +} diff --git a/packages/mix/lib/src/modifiers/intrinsic_modifier.dart b/packages/mix/lib/src/modifiers/intrinsic_modifier.dart index 0cddae18b..d5c22c674 100644 --- a/packages/mix/lib/src/modifiers/intrinsic_modifier.dart +++ b/packages/mix/lib/src/modifiers/intrinsic_modifier.dart @@ -1,37 +1,21 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; +import 'package:mix_annotations/mix_annotations.dart'; import '../core/widget_modifier.dart'; import '../core/style.dart'; +part 'intrinsic_modifier.g.dart'; + /// Modifier that forces its child to be exactly as tall as its intrinsic height. /// /// Wraps the child in an [IntrinsicHeight] widget. +@MixableModifier() final class IntrinsicHeightModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$IntrinsicHeightModifierMethods { const IntrinsicHeightModifier(); - @override - IntrinsicHeightModifier copyWith() { - return const IntrinsicHeightModifier(); - } - - @override - IntrinsicHeightModifier lerp(IntrinsicHeightModifier? other, double t) { - if (other == null) return this; - - return const IntrinsicHeightModifier(); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - } - - @override - List get props => []; - @override Widget build(Widget child) { return IntrinsicHeight(child: child); @@ -41,137 +25,14 @@ final class IntrinsicHeightModifier /// Modifier that forces its child to be exactly as wide as its intrinsic width. /// /// Wraps the child in an [IntrinsicWidth] widget. +@MixableModifier() final class IntrinsicWidthModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$IntrinsicWidthModifierMethods { const IntrinsicWidthModifier(); - @override - IntrinsicWidthModifier copyWith() { - return const IntrinsicWidthModifier(); - } - - @override - IntrinsicWidthModifier lerp(IntrinsicWidthModifier? other, double t) { - if (other == null) return this; - - return const IntrinsicWidthModifier(); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - } - - @override - List get props => []; - @override Widget build(Widget child) { return IntrinsicWidth(child: child); } } - -/// Represents the attributes of a [IntrinsicHeightModifier]. -/// -/// This class encapsulates properties defining the layout and -/// appearance of a [IntrinsicHeightModifier]. -/// -/// Use this class to configure the attributes of a [IntrinsicHeightModifier] and pass it to -/// the [IntrinsicHeightModifier] constructor. -class IntrinsicHeightModifierMix extends ModifierMix - with Diagnosticable { - const IntrinsicHeightModifierMix(); - - /// Resolves to [IntrinsicHeightModifier] using the provided [BuildContext]. - /// - /// If a property is null in the [BuildContext], it falls back to the - /// default value defined in the `defaultValue` for that property. - /// - /// ```dart - /// final intrinsicHeightModifier = IntrinsicHeightModifierMix(...).resolve(mix); - /// ``` - @override - IntrinsicHeightModifier resolve(BuildContext context) { - return const IntrinsicHeightModifier(); - } - - /// Merges the properties of this [IntrinsicHeightModifierMix] with the properties of [other]. - /// - /// If [other] is null, returns this instance unchanged. Otherwise, returns a new - /// [IntrinsicHeightModifierMix] with the properties of [other] taking precedence over - /// the corresponding properties of this instance. - /// - /// Properties from [other] that are null will fall back - /// to the values from this instance. - @override - IntrinsicHeightModifierMix merge(IntrinsicHeightModifierMix? other) { - if (other == null) return this; - - return other; - } - - /// The list of properties that constitute the state of this [IntrinsicHeightModifierMix]. - /// - /// This property is used by the [==] operator and the [hashCode] getter to - /// compare two [IntrinsicHeightModifierMix] instances for equality. - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - } - - @override - List get props => []; -} - -/// Represents the attributes of a [IntrinsicWidthModifier]. -/// -/// This class encapsulates properties defining the layout and -/// appearance of a [IntrinsicWidthModifier]. -/// -/// Use this class to configure the attributes of a [IntrinsicWidthModifier] and pass it to -/// the [IntrinsicWidthModifier] constructor. -class IntrinsicWidthModifierMix extends ModifierMix - with Diagnosticable { - const IntrinsicWidthModifierMix(); - - /// Resolves to [IntrinsicWidthModifier] using the provided [BuildContext]. - /// - /// If a property is null in the [BuildContext], it falls back to the - /// default value defined in the `defaultValue` for that property. - /// - /// ```dart - /// final intrinsicWidthModifier = IntrinsicWidthModifierMix(...).resolve(mix); - /// ``` - @override - IntrinsicWidthModifier resolve(BuildContext context) { - return const IntrinsicWidthModifier(); - } - - /// Merges the properties of this [IntrinsicWidthModifierMix] with the properties of [other]. - /// - /// If [other] is null, returns this instance unchanged. Otherwise, returns a new - /// [IntrinsicWidthModifierMix] with the properties of [other] taking precedence over - /// the corresponding properties of this instance. - /// - /// Properties from [other] that are null will fall back - /// to the values from this instance. - @override - IntrinsicWidthModifierMix merge(IntrinsicWidthModifierMix? other) { - if (other == null) return this; - - return other; - } - - /// The list of properties that constitute the state of this [IntrinsicWidthModifierMix]. - /// - /// This property is used by the [==] operator and the [hashCode] getter to - /// compare two [IntrinsicWidthModifierMix] instances for equality. - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - } - - @override - List get props => []; -} diff --git a/packages/mix/lib/src/modifiers/intrinsic_modifier.g.dart b/packages/mix/lib/src/modifiers/intrinsic_modifier.g.dart new file mode 100644 index 000000000..ea5a05872 --- /dev/null +++ b/packages/mix/lib/src/modifiers/intrinsic_modifier.g.dart @@ -0,0 +1,107 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'intrinsic_modifier.dart'; + +// ************************************************************************** +// ModifierGenerator +// ************************************************************************** + +mixin _$IntrinsicHeightModifierMethods + on WidgetModifier, Diagnosticable { + @override + IntrinsicHeightModifier copyWith() { + return const IntrinsicHeightModifier(); + } + + @override + IntrinsicHeightModifier lerp(IntrinsicHeightModifier? other, double t) { + if (other == null) return this as IntrinsicHeightModifier; + + return const IntrinsicHeightModifier(); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + } + + @override + List get props => []; +} + +class IntrinsicHeightModifierMix extends ModifierMix + with Diagnosticable { + const IntrinsicHeightModifierMix.create(); + + const IntrinsicHeightModifierMix() : this.create(); + + @override + IntrinsicHeightModifier resolve(BuildContext context) { + return IntrinsicHeightModifier(); + } + + @override + IntrinsicHeightModifierMix merge(IntrinsicHeightModifierMix? other) { + if (other == null) return this; + + return IntrinsicHeightModifierMix.create(); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + } + + @override + List get props => []; +} + +mixin _$IntrinsicWidthModifierMethods + on WidgetModifier, Diagnosticable { + @override + IntrinsicWidthModifier copyWith() { + return const IntrinsicWidthModifier(); + } + + @override + IntrinsicWidthModifier lerp(IntrinsicWidthModifier? other, double t) { + if (other == null) return this as IntrinsicWidthModifier; + + return const IntrinsicWidthModifier(); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + } + + @override + List get props => []; +} + +class IntrinsicWidthModifierMix extends ModifierMix + with Diagnosticable { + const IntrinsicWidthModifierMix.create(); + + const IntrinsicWidthModifierMix() : this.create(); + + @override + IntrinsicWidthModifier resolve(BuildContext context) { + return IntrinsicWidthModifier(); + } + + @override + IntrinsicWidthModifierMix merge(IntrinsicWidthModifierMix? other) { + if (other == null) return this; + + return IntrinsicWidthModifierMix.create(); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + } + + @override + List get props => []; +} diff --git a/packages/mix/lib/src/modifiers/mouse_cursor_modifier.dart b/packages/mix/lib/src/modifiers/mouse_cursor_modifier.dart index 5cc2cc25e..d2db20b11 100644 --- a/packages/mix/lib/src/modifiers/mouse_cursor_modifier.dart +++ b/packages/mix/lib/src/modifiers/mouse_cursor_modifier.dart @@ -1,107 +1,27 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:mix_annotations/mix_annotations.dart'; import '../core/helpers.dart'; import '../core/widget_modifier.dart'; import '../core/prop.dart'; import '../core/style.dart'; +part 'mouse_cursor_modifier.g.dart'; + /// Modifier that applies a mouse cursor to its child. /// /// Wraps the child in a [MouseRegion] widget with the specified cursor. +@MixableModifier() class MouseCursorModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$MouseCursorModifierMethods { + @override final MouseCursor? mouseCursor; const MouseCursorModifier({this.mouseCursor}); - @override - MouseCursorModifier copyWith({MouseCursor? mouseCursor}) { - return MouseCursorModifier(mouseCursor: mouseCursor ?? this.mouseCursor); - } - - @override - MouseCursorModifier lerp(MouseCursorModifier? other, double t) { - if (other == null) return this; - - return MouseCursorModifier( - mouseCursor: MixOps.lerpSnap(mouseCursor, other.mouseCursor, t), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('mouseCursor', mouseCursor)); - } - - @override - List get props => [mouseCursor]; - @override Widget build(Widget child) { return MouseRegion(cursor: mouseCursor ?? .defer, child: child); } } - -/// Represents the attributes of a [MouseCursorModifier]. -/// -/// This class encapsulates properties defining the layout and -/// appearance of a [MouseCursorModifier]. -/// -/// Use this class to configure the attributes of a [MouseCursorModifier] and pass it to -/// the [MouseCursorModifier] constructor. -class MouseCursorModifierMix extends ModifierMix - with Diagnosticable { - final Prop? mouseCursor; - - const MouseCursorModifierMix.create({this.mouseCursor}); - - MouseCursorModifierMix({MouseCursor? mouseCursor}) - : this.create(mouseCursor: Prop.maybe(mouseCursor)); - - /// Resolves to [MouseCursorModifier] using the provided [BuildContext]. - /// - /// If a property is null in the context, it uses the default value - /// defined in the property specification. - /// - /// ```dart - /// final mouseCursorModifier = MouseCursorModifierMix(...).resolve(context); - /// ``` - @override - MouseCursorModifier resolve(BuildContext context) { - return MouseCursorModifier( - mouseCursor: MixOps.resolve(context, mouseCursor), - ); - } - - /// Merges the properties of this [MouseCursorModifierMix] with the properties of [other]. - /// - /// If [other] is null, returns this instance unchanged. Otherwise, returns a new - /// [MouseCursorModifierMix] with the properties of [other] taking precedence over - /// the corresponding properties of this instance. - /// - /// Properties from [other] that are null will fall back - /// to the values from this instance. - @override - MouseCursorModifierMix merge(MouseCursorModifierMix? other) { - if (other == null) return this; - - return MouseCursorModifierMix.create( - mouseCursor: MixOps.merge(mouseCursor, other.mouseCursor), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('mouseCursor', mouseCursor)); - } - - /// The list of properties that constitute the state of this [MouseCursorModifierMix]. - /// - /// This property is used by the [==] operator and the [hashCode] getter to - /// compare two [MouseCursorModifierMix] instances for equality. - @override - List get props => [mouseCursor]; -} diff --git a/packages/mix/lib/src/modifiers/mouse_cursor_modifier.g.dart b/packages/mix/lib/src/modifiers/mouse_cursor_modifier.g.dart new file mode 100644 index 000000000..f59cf10b6 --- /dev/null +++ b/packages/mix/lib/src/modifiers/mouse_cursor_modifier.g.dart @@ -0,0 +1,70 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'mouse_cursor_modifier.dart'; + +// ************************************************************************** +// ModifierGenerator +// ************************************************************************** + +mixin _$MouseCursorModifierMethods + on WidgetModifier, Diagnosticable { + MouseCursor? get mouseCursor; + + @override + MouseCursorModifier copyWith({MouseCursor? mouseCursor}) { + return MouseCursorModifier(mouseCursor: mouseCursor ?? this.mouseCursor); + } + + @override + MouseCursorModifier lerp(MouseCursorModifier? other, double t) { + if (other == null) return this as MouseCursorModifier; + + return MouseCursorModifier( + mouseCursor: MixOps.lerpSnap(mouseCursor, other.mouseCursor, t), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('mouseCursor', mouseCursor)); + } + + @override + List get props => [mouseCursor]; +} + +class MouseCursorModifierMix extends ModifierMix + with Diagnosticable { + final Prop? mouseCursor; + + const MouseCursorModifierMix.create({this.mouseCursor}); + + MouseCursorModifierMix({MouseCursor? mouseCursor}) + : this.create(mouseCursor: Prop.maybe(mouseCursor)); + + @override + MouseCursorModifier resolve(BuildContext context) { + return MouseCursorModifier( + mouseCursor: MixOps.resolve(context, mouseCursor), + ); + } + + @override + MouseCursorModifierMix merge(MouseCursorModifierMix? other) { + if (other == null) return this; + + return MouseCursorModifierMix.create( + mouseCursor: MixOps.merge(mouseCursor, other.mouseCursor), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('mouseCursor', mouseCursor)); + } + + @override + List get props => [mouseCursor]; +} diff --git a/packages/mix/lib/src/modifiers/opacity_modifier.dart b/packages/mix/lib/src/modifiers/opacity_modifier.dart index 47f2a8f62..2a517798a 100644 --- a/packages/mix/lib/src/modifiers/opacity_modifier.dart +++ b/packages/mix/lib/src/modifiers/opacity_modifier.dart @@ -1,79 +1,27 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; +import 'package:mix_annotations/mix_annotations.dart'; import '../core/helpers.dart'; import '../core/widget_modifier.dart'; import '../core/prop.dart'; import '../core/style.dart'; +part 'opacity_modifier.g.dart'; + /// Modifier that applies opacity to its child. /// /// Wraps the child in an [Opacity] widget with the specified opacity value. +@MixableModifier() final class OpacityModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$OpacityModifierMethods { /// Opacity value between 0.0 and 1.0 (inclusive). + @override final double opacity; const OpacityModifier([double? opacity]) : opacity = opacity ?? 1.0; - @override - OpacityModifier copyWith({double? opacity}) { - return OpacityModifier(opacity ?? this.opacity); - } - - @override - OpacityModifier lerp(OpacityModifier? other, double t) { - if (other == null) return this; - - return OpacityModifier(MixOps.lerp(opacity, other.opacity, t)!); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(PercentProperty('opacity', opacity)); - } - - @override - List get props => [opacity]; - @override Widget build(Widget child) { return Opacity(opacity: opacity, child: child); } } - -/// Mix class for applying opacity modifications. -/// -/// This class allows for mixing and resolving opacity properties. -class OpacityModifierMix extends ModifierMix - with Diagnosticable { - final Prop? opacity; - - const OpacityModifierMix.create({this.opacity}); - - OpacityModifierMix({double? opacity}) - : this.create(opacity: Prop.maybe(opacity)); - - @override - OpacityModifier resolve(BuildContext context) { - return OpacityModifier(MixOps.resolve(context, opacity)); - } - - @override - OpacityModifierMix merge(OpacityModifierMix? other) { - if (other == null) return this; - - return OpacityModifierMix.create( - opacity: MixOps.merge(opacity, other.opacity), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('opacity', opacity)); - } - - @override - List get props => [opacity]; -} diff --git a/packages/mix/lib/src/modifiers/opacity_modifier.g.dart b/packages/mix/lib/src/modifiers/opacity_modifier.g.dart new file mode 100644 index 000000000..df5f3b5be --- /dev/null +++ b/packages/mix/lib/src/modifiers/opacity_modifier.g.dart @@ -0,0 +1,66 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'opacity_modifier.dart'; + +// ************************************************************************** +// ModifierGenerator +// ************************************************************************** + +mixin _$OpacityModifierMethods + on WidgetModifier, Diagnosticable { + double get opacity; + + @override + OpacityModifier copyWith({double? opacity}) { + return OpacityModifier(opacity ?? this.opacity); + } + + @override + OpacityModifier lerp(OpacityModifier? other, double t) { + if (other == null) return this as OpacityModifier; + + return OpacityModifier(MixOps.lerp(opacity, other.opacity, t)!); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DoubleProperty('opacity', opacity)); + } + + @override + List get props => [opacity]; +} + +class OpacityModifierMix extends ModifierMix + with Diagnosticable { + final Prop? opacity; + + const OpacityModifierMix.create({this.opacity}); + + OpacityModifierMix({double? opacity}) + : this.create(opacity: Prop.maybe(opacity)); + + @override + OpacityModifier resolve(BuildContext context) { + return OpacityModifier(MixOps.resolve(context, opacity)); + } + + @override + OpacityModifierMix merge(OpacityModifierMix? other) { + if (other == null) return this; + + return OpacityModifierMix.create( + opacity: MixOps.merge(opacity, other.opacity), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('opacity', opacity)); + } + + @override + List get props => [opacity]; +} diff --git a/packages/mix/lib/src/modifiers/padding_modifier.dart b/packages/mix/lib/src/modifiers/padding_modifier.dart index 59568ba96..c77d17d59 100644 --- a/packages/mix/lib/src/modifiers/padding_modifier.dart +++ b/packages/mix/lib/src/modifiers/padding_modifier.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; +import 'package:mix_annotations/mix_annotations.dart'; import '../core/helpers.dart'; import '../core/widget_modifier.dart'; @@ -7,75 +8,22 @@ import '../core/prop.dart'; import '../core/style.dart'; import '../properties/layout/edge_insets_geometry_mix.dart'; +part 'padding_modifier.g.dart'; + /// Modifier that adds padding around its child. /// /// Wraps the child in a [Padding] widget with the specified padding. +@MixableModifier() final class PaddingModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$PaddingModifierMethods { + @override final EdgeInsetsGeometry padding; const PaddingModifier([EdgeInsetsGeometry? padding]) : padding = padding ?? EdgeInsets.zero; - @override - PaddingModifier copyWith({EdgeInsetsGeometry? padding}) { - return PaddingModifier(padding ?? this.padding); - } - - @override - PaddingModifier lerp(PaddingModifier? other, double t) { - if (other == null) return this; - - return PaddingModifier(MixOps.lerp(padding, other.padding, t)!); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('padding', padding)); - } - - @override - List get props => [padding]; - @override Widget build(Widget child) { return Padding(padding: padding, child: child); } } - -/// Mix class for applying padding modifications. -/// -/// This class allows for mixing and resolving padding properties. -class PaddingModifierMix extends ModifierMix - with Diagnosticable { - final Prop? padding; - - const PaddingModifierMix.create({this.padding}); - - PaddingModifierMix({EdgeInsetsGeometryMix? padding}) - : this.create(padding: Prop.maybeMix(padding)); - - @override - PaddingModifier resolve(BuildContext context) { - return PaddingModifier(MixOps.resolve(context, padding)); - } - - @override - PaddingModifierMix merge(PaddingModifierMix? other) { - if (other == null) return this; - - return PaddingModifierMix.create( - padding: MixOps.merge(padding, other.padding), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('padding', padding)); - } - - @override - List get props => [padding]; -} diff --git a/packages/mix/lib/src/modifiers/padding_modifier.g.dart b/packages/mix/lib/src/modifiers/padding_modifier.g.dart new file mode 100644 index 000000000..db8f7a354 --- /dev/null +++ b/packages/mix/lib/src/modifiers/padding_modifier.g.dart @@ -0,0 +1,66 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'padding_modifier.dart'; + +// ************************************************************************** +// ModifierGenerator +// ************************************************************************** + +mixin _$PaddingModifierMethods + on WidgetModifier, Diagnosticable { + EdgeInsetsGeometry get padding; + + @override + PaddingModifier copyWith({EdgeInsetsGeometry? padding}) { + return PaddingModifier(padding ?? this.padding); + } + + @override + PaddingModifier lerp(PaddingModifier? other, double t) { + if (other == null) return this as PaddingModifier; + + return PaddingModifier(MixOps.lerp(padding, other.padding, t)!); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('padding', padding)); + } + + @override + List get props => [padding]; +} + +class PaddingModifierMix extends ModifierMix + with Diagnosticable { + final Prop? padding; + + const PaddingModifierMix.create({this.padding}); + + PaddingModifierMix({EdgeInsetsGeometryMix? padding}) + : this.create(padding: Prop.maybeMix(padding)); + + @override + PaddingModifier resolve(BuildContext context) { + return PaddingModifier(MixOps.resolve(context, padding)); + } + + @override + PaddingModifierMix merge(PaddingModifierMix? other) { + if (other == null) return this; + + return PaddingModifierMix.create( + padding: MixOps.merge(padding, other.padding), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('padding', padding)); + } + + @override + List get props => [padding]; +} diff --git a/packages/mix/lib/src/modifiers/rotated_box_modifier.dart b/packages/mix/lib/src/modifiers/rotated_box_modifier.dart index 5ec4fe596..f687e6886 100644 --- a/packages/mix/lib/src/modifiers/rotated_box_modifier.dart +++ b/packages/mix/lib/src/modifiers/rotated_box_modifier.dart @@ -1,95 +1,27 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; +import 'package:mix_annotations/mix_annotations.dart'; import '../core/helpers.dart'; import '../core/widget_modifier.dart'; import '../core/prop.dart'; import '../core/style.dart'; +part 'rotated_box_modifier.g.dart'; + /// Modifier that rotates its child by quarter turns. /// /// Wraps the child in a [RotatedBox] widget with the specified quarter turns. +@MixableModifier() final class RotatedBoxModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$RotatedBoxModifierMethods { + @override final int quarterTurns; const RotatedBoxModifier([int? quarterTurns]) : quarterTurns = quarterTurns ?? 0; - @override - RotatedBoxModifier copyWith({int? quarterTurns}) { - return RotatedBoxModifier(quarterTurns ?? this.quarterTurns); - } - - @override - RotatedBoxModifier lerp(RotatedBoxModifier? other, double t) { - if (other == null) return this; - - return RotatedBoxModifier(MixOps.lerp(quarterTurns, other.quarterTurns, t)); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(IntProperty('quarterTurns', quarterTurns)); - } - - @override - List get props => [quarterTurns]; - @override Widget build(Widget child) { return RotatedBox(quarterTurns: quarterTurns, child: child); } } - -/// Mix class for applying rotated box modifications. -/// -/// This class allows for mixing and resolving rotated box properties. -class RotatedBoxModifierMix extends ModifierMix - with Diagnosticable { - final Prop? quarterTurns; - - const RotatedBoxModifierMix.create({this.quarterTurns}); - - RotatedBoxModifierMix({int? quarterTurns}) - : this.create(quarterTurns: Prop.maybe(quarterTurns)); - - /// Resolves to [RotatedBoxModifier] using the provided [BuildContext]. - /// - /// If a property is null in the [BuildContext], it falls back to the - /// default value defined in the `defaultValue` for that property. - /// - /// ```dart - /// final rotatedBoxModifier = RotatedBoxModifierMix(...).resolve(mix); - /// ``` - @override - RotatedBoxModifier resolve(BuildContext context) { - return RotatedBoxModifier(MixOps.resolve(context, quarterTurns)); - } - - /// Merges the properties of this [RotatedBoxModifierMix] with the properties of [other]. - /// - /// If [other] is null, returns this instance unchanged. Otherwise, returns a new - /// [RotatedBoxModifierMix] with the properties of [other] taking precedence over - /// the corresponding properties of this instance. - /// - /// Properties from [other] that are null will fall back - /// to the values from this instance. - @override - RotatedBoxModifierMix merge(RotatedBoxModifierMix? other) { - if (other == null) return this; - - return RotatedBoxModifierMix.create( - quarterTurns: MixOps.merge(quarterTurns, other.quarterTurns), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('quarterTurns', quarterTurns)); - } - - @override - List get props => [quarterTurns]; -} diff --git a/packages/mix/lib/src/modifiers/rotated_box_modifier.g.dart b/packages/mix/lib/src/modifiers/rotated_box_modifier.g.dart new file mode 100644 index 000000000..628648da1 --- /dev/null +++ b/packages/mix/lib/src/modifiers/rotated_box_modifier.g.dart @@ -0,0 +1,68 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'rotated_box_modifier.dart'; + +// ************************************************************************** +// ModifierGenerator +// ************************************************************************** + +mixin _$RotatedBoxModifierMethods + on WidgetModifier, Diagnosticable { + int get quarterTurns; + + @override + RotatedBoxModifier copyWith({int? quarterTurns}) { + return RotatedBoxModifier(quarterTurns ?? this.quarterTurns); + } + + @override + RotatedBoxModifier lerp(RotatedBoxModifier? other, double t) { + if (other == null) return this as RotatedBoxModifier; + + return RotatedBoxModifier( + MixOps.lerp(quarterTurns, other.quarterTurns, t)!, + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(IntProperty('quarterTurns', quarterTurns)); + } + + @override + List get props => [quarterTurns]; +} + +class RotatedBoxModifierMix extends ModifierMix + with Diagnosticable { + final Prop? quarterTurns; + + const RotatedBoxModifierMix.create({this.quarterTurns}); + + RotatedBoxModifierMix({int? quarterTurns}) + : this.create(quarterTurns: Prop.maybe(quarterTurns)); + + @override + RotatedBoxModifier resolve(BuildContext context) { + return RotatedBoxModifier(MixOps.resolve(context, quarterTurns)); + } + + @override + RotatedBoxModifierMix merge(RotatedBoxModifierMix? other) { + if (other == null) return this; + + return RotatedBoxModifierMix.create( + quarterTurns: MixOps.merge(quarterTurns, other.quarterTurns), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('quarterTurns', quarterTurns)); + } + + @override + List get props => [quarterTurns]; +} diff --git a/packages/mix/lib/src/modifiers/scroll_view_modifier.dart b/packages/mix/lib/src/modifiers/scroll_view_modifier.dart index 804a476b1..d94364a31 100644 --- a/packages/mix/lib/src/modifiers/scroll_view_modifier.dart +++ b/packages/mix/lib/src/modifiers/scroll_view_modifier.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; +import 'package:mix_annotations/mix_annotations.dart'; import '../core/helpers.dart'; import '../core/widget_modifier.dart'; @@ -7,15 +8,23 @@ import '../core/prop.dart'; import '../core/style.dart'; import '../properties/layout/edge_insets_geometry_mix.dart'; +part 'scroll_view_modifier.g.dart'; + /// Modifier that applies scroll view properties to its child. /// /// Wraps the child in a scrollable widget with the specified properties. +@MixableModifier() final class ScrollViewModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$ScrollViewModifierMethods { + @override final Axis? scrollDirection; + @override final bool? reverse; + @override final EdgeInsetsGeometry? padding; + @override final ScrollPhysics? physics; + @override final Clip? clipBehavior; const ScrollViewModifier({ @@ -26,60 +35,6 @@ final class ScrollViewModifier extends WidgetModifier this.clipBehavior, }); - @override - ScrollViewModifier copyWith({ - Axis? scrollDirection, - bool? reverse, - EdgeInsetsGeometry? padding, - ScrollPhysics? physics, - Clip? clipBehavior, - }) { - return ScrollViewModifier( - scrollDirection: scrollDirection ?? this.scrollDirection, - reverse: reverse ?? this.reverse, - padding: padding ?? this.padding, - physics: physics ?? this.physics, - clipBehavior: clipBehavior ?? this.clipBehavior, - ); - } - - @override - ScrollViewModifier lerp(ScrollViewModifier? other, double t) { - if (other == null) return this; - - return ScrollViewModifier( - scrollDirection: MixOps.lerpSnap( - scrollDirection, - other.scrollDirection, - t, - ), - reverse: MixOps.lerpSnap(reverse, other.reverse, t), - padding: MixOps.lerp(padding, other.padding, t), - physics: MixOps.lerpSnap(physics, other.physics, t), - clipBehavior: MixOps.lerpSnap(clipBehavior, other.clipBehavior, t), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(EnumProperty('scrollDirection', scrollDirection)) - ..add(FlagProperty('reverse', value: reverse, ifTrue: 'reversed')) - ..add(DiagnosticsProperty('padding', padding)) - ..add(DiagnosticsProperty('physics', physics)) - ..add(EnumProperty('clipBehavior', clipBehavior)); - } - - @override - List get props => [ - scrollDirection, - reverse, - padding, - physics, - clipBehavior, - ]; - @override Widget build(Widget child) { return SingleChildScrollView( @@ -92,78 +47,3 @@ final class ScrollViewModifier extends WidgetModifier ); } } - -class ScrollViewModifierMix extends ModifierMix - with Diagnosticable { - final Prop? scrollDirection; - final Prop? reverse; - final Prop? padding; - final Prop? physics; - final Prop? clipBehavior; - - const ScrollViewModifierMix.create({ - this.scrollDirection, - this.reverse, - this.padding, - this.physics, - this.clipBehavior, - }); - - ScrollViewModifierMix({ - Axis? scrollDirection, - bool? reverse, - EdgeInsetsGeometryMix? padding, - ScrollPhysics? physics, - Clip? clipBehavior, - }) : this.create( - scrollDirection: Prop.maybe(scrollDirection), - reverse: Prop.maybe(reverse), - padding: Prop.maybeMix(padding), - physics: Prop.maybe(physics), - clipBehavior: Prop.maybe(clipBehavior), - ); - - @override - ScrollViewModifier resolve(BuildContext context) { - return ScrollViewModifier( - scrollDirection: MixOps.resolve(context, scrollDirection), - reverse: MixOps.resolve(context, reverse), - padding: MixOps.resolve(context, padding), - physics: MixOps.resolve(context, physics), - clipBehavior: MixOps.resolve(context, clipBehavior), - ); - } - - @override - ScrollViewModifierMix merge(ScrollViewModifierMix? other) { - if (other == null) return this; - - return ScrollViewModifierMix.create( - scrollDirection: MixOps.merge(scrollDirection, other.scrollDirection), - reverse: MixOps.merge(reverse, other.reverse), - padding: MixOps.merge(padding, other.padding), - physics: MixOps.merge(physics, other.physics), - clipBehavior: MixOps.merge(clipBehavior, other.clipBehavior), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('scrollDirection', scrollDirection)) - ..add(DiagnosticsProperty('reverse', reverse)) - ..add(DiagnosticsProperty('padding', padding)) - ..add(DiagnosticsProperty('physics', physics)) - ..add(DiagnosticsProperty('clipBehavior', clipBehavior)); - } - - @override - List get props => [ - scrollDirection, - reverse, - padding, - physics, - clipBehavior, - ]; -} diff --git a/packages/mix/lib/src/modifiers/scroll_view_modifier.g.dart b/packages/mix/lib/src/modifiers/scroll_view_modifier.g.dart new file mode 100644 index 000000000..46b3002cb --- /dev/null +++ b/packages/mix/lib/src/modifiers/scroll_view_modifier.g.dart @@ -0,0 +1,145 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'scroll_view_modifier.dart'; + +// ************************************************************************** +// ModifierGenerator +// ************************************************************************** + +mixin _$ScrollViewModifierMethods + on WidgetModifier, Diagnosticable { + Clip? get clipBehavior; + EdgeInsetsGeometry? get padding; + ScrollPhysics? get physics; + bool? get reverse; + Axis? get scrollDirection; + + @override + ScrollViewModifier copyWith({ + Clip? clipBehavior, + EdgeInsetsGeometry? padding, + ScrollPhysics? physics, + bool? reverse, + Axis? scrollDirection, + }) { + return ScrollViewModifier( + clipBehavior: clipBehavior ?? this.clipBehavior, + padding: padding ?? this.padding, + physics: physics ?? this.physics, + reverse: reverse ?? this.reverse, + scrollDirection: scrollDirection ?? this.scrollDirection, + ); + } + + @override + ScrollViewModifier lerp(ScrollViewModifier? other, double t) { + if (other == null) return this as ScrollViewModifier; + + return ScrollViewModifier( + clipBehavior: MixOps.lerpSnap(clipBehavior, other.clipBehavior, t), + padding: MixOps.lerp(padding, other.padding, t), + physics: MixOps.lerpSnap(physics, other.physics, t), + reverse: MixOps.lerpSnap(reverse, other.reverse, t), + scrollDirection: MixOps.lerpSnap( + scrollDirection, + other.scrollDirection, + t, + ), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(EnumProperty('clipBehavior', clipBehavior)) + ..add(DiagnosticsProperty('padding', padding)) + ..add(DiagnosticsProperty('physics', physics)) + ..add(FlagProperty('reverse', value: reverse, ifTrue: 'reversed')) + ..add(EnumProperty('scrollDirection', scrollDirection)); + } + + @override + List get props => [ + clipBehavior, + padding, + physics, + reverse, + scrollDirection, + ]; +} + +class ScrollViewModifierMix extends ModifierMix + with Diagnosticable { + final Prop? clipBehavior; + final Prop? padding; + final Prop? physics; + final Prop? reverse; + final Prop? scrollDirection; + + const ScrollViewModifierMix.create({ + this.clipBehavior, + this.padding, + this.physics, + this.reverse, + this.scrollDirection, + }); + + ScrollViewModifierMix({ + Clip? clipBehavior, + EdgeInsetsGeometryMix? padding, + ScrollPhysics? physics, + bool? reverse, + Axis? scrollDirection, + }) : this.create( + clipBehavior: Prop.maybe(clipBehavior), + padding: Prop.maybeMix(padding), + physics: Prop.maybe(physics), + reverse: Prop.maybe(reverse), + scrollDirection: Prop.maybe(scrollDirection), + ); + + @override + ScrollViewModifier resolve(BuildContext context) { + return ScrollViewModifier( + clipBehavior: MixOps.resolve(context, clipBehavior), + padding: MixOps.resolve(context, padding), + physics: MixOps.resolve(context, physics), + reverse: MixOps.resolve(context, reverse), + scrollDirection: MixOps.resolve(context, scrollDirection), + ); + } + + @override + ScrollViewModifierMix merge(ScrollViewModifierMix? other) { + if (other == null) return this; + + return ScrollViewModifierMix.create( + clipBehavior: MixOps.merge(clipBehavior, other.clipBehavior), + padding: MixOps.merge(padding, other.padding), + physics: MixOps.merge(physics, other.physics), + reverse: MixOps.merge(reverse, other.reverse), + scrollDirection: MixOps.merge(scrollDirection, other.scrollDirection), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('clipBehavior', clipBehavior)) + ..add(DiagnosticsProperty('padding', padding)) + ..add(DiagnosticsProperty('physics', physics)) + ..add(DiagnosticsProperty('reverse', reverse)) + ..add(DiagnosticsProperty('scrollDirection', scrollDirection)); + } + + @override + List get props => [ + clipBehavior, + padding, + physics, + reverse, + scrollDirection, + ]; +} diff --git a/packages/mix/lib/src/modifiers/sized_box_modifier.dart b/packages/mix/lib/src/modifiers/sized_box_modifier.dart index f7731dddd..e625a46ca 100644 --- a/packages/mix/lib/src/modifiers/sized_box_modifier.dart +++ b/packages/mix/lib/src/modifiers/sized_box_modifier.dart @@ -1,95 +1,29 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; +import 'package:mix_annotations/mix_annotations.dart'; import '../core/helpers.dart'; import '../core/widget_modifier.dart'; import '../core/prop.dart'; import '../core/style.dart'; +part 'sized_box_modifier.g.dart'; + /// Modifier that constrains its child to a specific size. /// /// Wraps the child in a [SizedBox] widget with the specified width and height. +@MixableModifier() final class SizedBoxModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$SizedBoxModifierMethods { + @override final double? width; + @override final double? height; const SizedBoxModifier({this.width, this.height}); - @override - SizedBoxModifier copyWith({double? width, double? height}) { - return SizedBoxModifier( - width: width ?? this.width, - height: height ?? this.height, - ); - } - - @override - SizedBoxModifier lerp(SizedBoxModifier? other, double t) { - if (other == null) return this; - - return SizedBoxModifier( - width: MixOps.lerp(width, other.width, t), - height: MixOps.lerp(height, other.height, t), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DoubleProperty('width', width)) - ..add(DoubleProperty('height', height)); - } - - @override - List get props => [width, height]; - @override Widget build(Widget child) { return SizedBox(width: width, height: height, child: child); } } - -/// Mix class for applying sized box modifications. -/// -/// This class allows for mixing and resolving sized box properties. -class SizedBoxModifierMix extends ModifierMix - with Diagnosticable { - final Prop? width; - final Prop? height; - - const SizedBoxModifierMix.create({this.width, this.height}); - - SizedBoxModifierMix({double? width, double? height}) - : this.create(width: Prop.maybe(width), height: Prop.maybe(height)); - - @override - SizedBoxModifier resolve(BuildContext context) { - return SizedBoxModifier( - width: MixOps.resolve(context, width), - height: MixOps.resolve(context, height), - ); - } - - @override - SizedBoxModifierMix merge(SizedBoxModifierMix? other) { - if (other == null) return this; - - return SizedBoxModifierMix.create( - width: MixOps.merge(width, other.width), - height: MixOps.merge(height, other.height), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('width', width)) - ..add(DiagnosticsProperty('height', height)); - } - - @override - List get props => [width, height]; -} diff --git a/packages/mix/lib/src/modifiers/sized_box_modifier.g.dart b/packages/mix/lib/src/modifiers/sized_box_modifier.g.dart new file mode 100644 index 000000000..ff0eb9dce --- /dev/null +++ b/packages/mix/lib/src/modifiers/sized_box_modifier.g.dart @@ -0,0 +1,82 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'sized_box_modifier.dart'; + +// ************************************************************************** +// ModifierGenerator +// ************************************************************************** + +mixin _$SizedBoxModifierMethods + on WidgetModifier, Diagnosticable { + double? get height; + double? get width; + + @override + SizedBoxModifier copyWith({double? height, double? width}) { + return SizedBoxModifier( + height: height ?? this.height, + width: width ?? this.width, + ); + } + + @override + SizedBoxModifier lerp(SizedBoxModifier? other, double t) { + if (other == null) return this as SizedBoxModifier; + + return SizedBoxModifier( + height: MixOps.lerp(height, other.height, t), + width: MixOps.lerp(width, other.width, t), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DoubleProperty('height', height)) + ..add(DoubleProperty('width', width)); + } + + @override + List get props => [height, width]; +} + +class SizedBoxModifierMix extends ModifierMix + with Diagnosticable { + final Prop? height; + final Prop? width; + + const SizedBoxModifierMix.create({this.height, this.width}); + + SizedBoxModifierMix({double? height, double? width}) + : this.create(height: Prop.maybe(height), width: Prop.maybe(width)); + + @override + SizedBoxModifier resolve(BuildContext context) { + return SizedBoxModifier( + height: MixOps.resolve(context, height), + width: MixOps.resolve(context, width), + ); + } + + @override + SizedBoxModifierMix merge(SizedBoxModifierMix? other) { + if (other == null) return this; + + return SizedBoxModifierMix.create( + height: MixOps.merge(height, other.height), + width: MixOps.merge(width, other.width), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('height', height)) + ..add(DiagnosticsProperty('width', width)); + } + + @override + List get props => [height, width]; +} diff --git a/packages/mix/lib/src/modifiers/visibility_modifier.dart b/packages/mix/lib/src/modifiers/visibility_modifier.dart index 5084f1259..7a5f8278c 100644 --- a/packages/mix/lib/src/modifiers/visibility_modifier.dart +++ b/packages/mix/lib/src/modifiers/visibility_modifier.dart @@ -1,90 +1,27 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; +import 'package:mix_annotations/mix_annotations.dart'; import '../core/helpers.dart'; import '../core/widget_modifier.dart'; import '../core/prop.dart'; import '../core/style.dart'; +part 'visibility_modifier.g.dart'; + /// Modifier that controls the visibility of its child. /// /// Wraps the child in a [Visibility] widget to show or hide it while maintaining layout space. +@MixableModifier() final class VisibilityModifier extends WidgetModifier - with Diagnosticable { + with Diagnosticable, _$VisibilityModifierMethods { /// Whether the child widget should be visible. + @override final bool visible; const VisibilityModifier([bool? visible]) : visible = visible ?? true; - @override - VisibilityModifier copyWith({bool? visible}) { - return VisibilityModifier(visible ?? this.visible); - } - - @override - VisibilityModifier lerp(VisibilityModifier? other, double t) { - if (other == null) return this; - if (visible == other.visible) return this; - if (t == 0) return this; - if (t == 1) return other; - - return VisibilityModifier(true); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add( - FlagProperty( - 'visible', - value: visible, - ifTrue: 'visible', - ifFalse: 'hidden', - ), - ); - } - - @override - List get props => [visible]; - @override Widget build(Widget child) { return Visibility(visible: visible, child: child); } } - -/// Mix class for applying visibility modifications. -/// -/// This class allows for mixing and resolving visibility properties. -class VisibilityModifierMix extends ModifierMix - with Diagnosticable { - /// Whether the child widget should be visible. - final Prop? visible; - - const VisibilityModifierMix.create({this.visible}); - - VisibilityModifierMix({bool? visible}) - : this.create(visible: Prop.maybe(visible)); - - @override - VisibilityModifier resolve(BuildContext context) { - return VisibilityModifier(MixOps.resolve(context, visible)); - } - - @override - VisibilityModifierMix merge(VisibilityModifierMix? other) { - if (other == null) return this; - - return VisibilityModifierMix.create( - visible: visible?.mergeProp(other.visible) ?? other.visible, - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('visible', visible)); - } - - @override - List get props => [visible]; -} diff --git a/packages/mix/lib/src/modifiers/visibility_modifier.g.dart b/packages/mix/lib/src/modifiers/visibility_modifier.g.dart new file mode 100644 index 000000000..8d103a805 --- /dev/null +++ b/packages/mix/lib/src/modifiers/visibility_modifier.g.dart @@ -0,0 +1,66 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'visibility_modifier.dart'; + +// ************************************************************************** +// ModifierGenerator +// ************************************************************************** + +mixin _$VisibilityModifierMethods + on WidgetModifier, Diagnosticable { + bool get visible; + + @override + VisibilityModifier copyWith({bool? visible}) { + return VisibilityModifier(visible ?? this.visible); + } + + @override + VisibilityModifier lerp(VisibilityModifier? other, double t) { + if (other == null) return this as VisibilityModifier; + + return VisibilityModifier(MixOps.lerpSnap(visible, other.visible, t)!); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(FlagProperty('visible', value: visible, ifTrue: 'visible')); + } + + @override + List get props => [visible]; +} + +class VisibilityModifierMix extends ModifierMix + with Diagnosticable { + final Prop? visible; + + const VisibilityModifierMix.create({this.visible}); + + VisibilityModifierMix({bool? visible}) + : this.create(visible: Prop.maybe(visible)); + + @override + VisibilityModifier resolve(BuildContext context) { + return VisibilityModifier(MixOps.resolve(context, visible)); + } + + @override + VisibilityModifierMix merge(VisibilityModifierMix? other) { + if (other == null) return this; + + return VisibilityModifierMix.create( + visible: MixOps.merge(visible, other.visible), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('visible', visible)); + } + + @override + List get props => [visible]; +} diff --git a/packages/mix/test/src/modifiers/align_modifier_test.dart b/packages/mix/test/src/modifiers/align_modifier_test.dart index bd942fbfc..a233bbaf5 100644 --- a/packages/mix/test/src/modifiers/align_modifier_test.dart +++ b/packages/mix/test/src/modifiers/align_modifier_test.dart @@ -222,7 +222,7 @@ void main() { heightFactor: 0.8, ); - expect(modifier.props, [Alignment.center, 0.5, 0.8]); + expect(modifier.props, [Alignment.center, 0.8, 0.5]); }); test('contains default alignment and null factors', () { @@ -439,8 +439,8 @@ void main() { final props = attribute.props; expect(props.length, 3); expect(props[0], attribute.alignment); - expect(props[1], attribute.widthFactor); - expect(props[2], attribute.heightFactor); + expect(props[1], attribute.heightFactor); + expect(props[2], attribute.widthFactor); }); }); }); diff --git a/packages/mix/test/src/modifiers/clip_modifier_test.dart b/packages/mix/test/src/modifiers/clip_modifier_test.dart index 9e30961a8..06677a076 100644 --- a/packages/mix/test/src/modifiers/clip_modifier_test.dart +++ b/packages/mix/test/src/modifiers/clip_modifier_test.dart @@ -152,13 +152,13 @@ void main() { clipBehavior: clipBehavior, ); - expect(modifier.props, [clipper, clipBehavior]); + expect(modifier.props, [clipBehavior, clipper]); }); test('contains null clipper and default clip behavior value', () { const modifier = ClipPathModifier(); - expect(modifier.props, [null, Clip.antiAlias]); + expect(modifier.props, [Clip.antiAlias, null]); }); }); @@ -330,8 +330,8 @@ void main() { final props = attribute.props; expect(props.length, 2); - expect(props[0], attribute.clipper); - expect(props[1], attribute.clipBehavior); + expect(props[0], attribute.clipBehavior); + expect(props[1], attribute.clipper); }); }); }); diff --git a/packages/mix/test/src/modifiers/flexible_modifier_test.dart b/packages/mix/test/src/modifiers/flexible_modifier_test.dart index e0853ff1a..2abb8fdc7 100644 --- a/packages/mix/test/src/modifiers/flexible_modifier_test.dart +++ b/packages/mix/test/src/modifiers/flexible_modifier_test.dart @@ -59,13 +59,14 @@ void main() { }); group('lerp', () { - test('uses step function for flex', () { + test('interpolates flex using lerpDouble + round', () { const start = FlexibleModifier(flex: 1); const end = FlexibleModifier(flex: 3); + // MixOps.lerp for int: lerpDouble(a, b, t).round() expect(start.lerp(end, 0.0).flex, 1); - expect(start.lerp(end, 0.49).flex, 1); - expect(start.lerp(end, 0.5).flex, 3); + expect(start.lerp(end, 0.25).flex, 2); // 1 + 0.25 * 2 = 1.5 → 2 + expect(start.lerp(end, 0.5).flex, 2); // 1 + 0.5 * 2 = 2.0 → 2 expect(start.lerp(end, 1.0).flex, 3); }); @@ -84,11 +85,11 @@ void main() { const end = FlexibleModifier(flex: 5, fit: FlexFit.tight); final result = start.lerp(end, 0.3); - expect(result.flex, 1); + expect(result.flex, 2); // lerpDouble(1, 5, 0.3).round() = 2.2 → 2 expect(result.fit, FlexFit.loose); final result2 = start.lerp(end, 0.7); - expect(result2.flex, 5); + expect(result2.flex, 4); // lerpDouble(1, 5, 0.7).round() = 3.8 → 4 expect(result2.fit, FlexFit.tight); }); @@ -104,7 +105,9 @@ void main() { const end = FlexibleModifier(fit: FlexFit.tight); final result = start.lerp(end, 0.5); - expect(result.flex, isNull); + // MixOps.lerp(1, null, 0.5): lerpDouble treats null as 0 + // lerpDouble(1, 0, 0.5) = 0.5, round() = 1 + expect(result.flex, 1); expect(result.fit, FlexFit.tight); }); }); @@ -145,7 +148,7 @@ void main() { test('contains all properties', () { const modifier = FlexibleModifier(flex: 3, fit: FlexFit.tight); - expect(modifier.props, [3, FlexFit.tight]); + expect(modifier.props, [FlexFit.tight, 3]); }); test('contains null values', () { @@ -308,8 +311,8 @@ void main() { final props = attribute.props; expect(props.length, 2); - expect(props[0], attribute.flex); - expect(props[1], attribute.fit); + expect(props[0], attribute.fit); + expect(props[1], attribute.flex); }); }); }); @@ -354,7 +357,7 @@ void main() { expect(result.fit, resolvesTo(FlexFit.tight)); }); - test('Lerp with step function behavior', () { + test('Lerp interpolates flex and snaps fit', () { const start = FlexibleModifier(flex: 1, fit: FlexFit.loose); const end = FlexibleModifier(flex: 5, fit: FlexFit.tight); @@ -362,14 +365,14 @@ void main() { final half = start.lerp(end, 0.5); final threeQuarter = start.lerp(end, 0.75); - // Step function behavior - expect(quarter.flex, 1); + // flex: lerpDouble(1, 5, t).round() + expect(quarter.flex, 2); // 1 + 1.0 = 2.0 → 2 expect(quarter.fit, FlexFit.loose); - expect(half.flex, 5); + expect(half.flex, 3); // 1 + 2.0 = 3.0 → 3 expect(half.fit, FlexFit.tight); - expect(threeQuarter.flex, 5); + expect(threeQuarter.flex, 4); // 1 + 3.0 = 4.0 → 4 expect(threeQuarter.fit, FlexFit.tight); }); }); diff --git a/packages/mix/test/src/modifiers/fractionally_sized_box_modifier_test.dart b/packages/mix/test/src/modifiers/fractionally_sized_box_modifier_test.dart index df56808c8..91fb323a1 100644 --- a/packages/mix/test/src/modifiers/fractionally_sized_box_modifier_test.dart +++ b/packages/mix/test/src/modifiers/fractionally_sized_box_modifier_test.dart @@ -245,13 +245,13 @@ void main() { alignment: Alignment.center, ); - expect(modifier.props, [0.5, 0.8, Alignment.center]); + expect(modifier.props, [Alignment.center, 0.8, 0.5]); }); test('contains default alignment and null factors', () { const modifier = FractionallySizedBoxModifier(); - expect(modifier.props, [null, null, Alignment.center]); + expect(modifier.props, [Alignment.center, null, null]); }); }); @@ -460,9 +460,9 @@ void main() { final props = attribute.props; expect(props.length, 3); - expect(props[0], attribute.widthFactor); + expect(props[0], attribute.alignment); expect(props[1], attribute.heightFactor); - expect(props[2], attribute.alignment); + expect(props[2], attribute.widthFactor); }); }); }); diff --git a/packages/mix/test/src/modifiers/scroll_view_modifier_test.dart b/packages/mix/test/src/modifiers/scroll_view_modifier_test.dart index bb45abed7..ef315946f 100644 --- a/packages/mix/test/src/modifiers/scroll_view_modifier_test.dart +++ b/packages/mix/test/src/modifiers/scroll_view_modifier_test.dart @@ -276,11 +276,11 @@ void main() { ); expect(modifier.props.length, 5); - expect(modifier.props[0], Axis.horizontal); - expect(modifier.props[1], true); - expect(modifier.props[2], const EdgeInsets.all(16.0)); - expect(modifier.props[3], isA()); - expect(modifier.props[4], Clip.antiAlias); + expect(modifier.props[0], Clip.antiAlias); + expect(modifier.props[1], const EdgeInsets.all(16.0)); + expect(modifier.props[2], isA()); + expect(modifier.props[3], true); + expect(modifier.props[4], Axis.horizontal); }); test('contains null values', () { @@ -563,11 +563,11 @@ void main() { final props = attribute.props; expect(props.length, 5); - expect(props[0], attribute.scrollDirection); - expect(props[1], attribute.reverse); - expect(props[2], attribute.padding); - expect(props[3], attribute.physics); - expect(props[4], attribute.clipBehavior); + expect(props[0], attribute.clipBehavior); + expect(props[1], attribute.padding); + expect(props[2], attribute.physics); + expect(props[3], attribute.reverse); + expect(props[4], attribute.scrollDirection); }); }); }); diff --git a/packages/mix/test/src/modifiers/sized_box_modifier_test.dart b/packages/mix/test/src/modifiers/sized_box_modifier_test.dart index e9e335a2d..a92ee610e 100644 --- a/packages/mix/test/src/modifiers/sized_box_modifier_test.dart +++ b/packages/mix/test/src/modifiers/sized_box_modifier_test.dart @@ -150,7 +150,7 @@ void main() { test('contains all properties', () { const modifier = SizedBoxModifier(width: 100.0, height: 200.0); - expect(modifier.props, [100.0, 200.0]); + expect(modifier.props, [200.0, 100.0]); }); test('contains null values', () { @@ -307,8 +307,8 @@ void main() { final props = attribute.props; expect(props.length, 2); - expect(props[0], attribute.width); - expect(props[1], attribute.height); + expect(props[0], attribute.height); + expect(props[1], attribute.width); }); }); }); diff --git a/packages/mix/test/src/modifiers/visibility_modifier_test.dart b/packages/mix/test/src/modifiers/visibility_modifier_test.dart index 7462696f3..35b6293a9 100644 --- a/packages/mix/test/src/modifiers/visibility_modifier_test.dart +++ b/packages/mix/test/src/modifiers/visibility_modifier_test.dart @@ -3,33 +3,32 @@ import 'package:mix/src/modifiers/visibility_modifier.dart'; void main() { group('VisibilityModifier', () { - test('lerp keeps visible during transition', () { + test('lerp snaps at midpoint', () { const start = VisibilityModifier(false); const end = VisibilityModifier(true); - final mid = start.lerp(end, 0.5); - - expect(mid.visible, isTrue); + // lerpSnap: t < 0.5 returns start, t >= 0.5 returns end + expect(start.lerp(end, 0.0).visible, isFalse); + expect(start.lerp(end, 0.49).visible, isFalse); + expect(start.lerp(end, 0.5).visible, isTrue); + expect(start.lerp(end, 1.0).visible, isTrue); }); - test('lerp respects endpoints', () { - const start = VisibilityModifier(false); - const end = VisibilityModifier(true); + test('lerp returns self when other is null', () { + const start = VisibilityModifier(true); - final atStart = start.lerp(end, 0.0); - final atEnd = start.lerp(end, 1.0); + final result = start.lerp(null, 0.5); - expect(identical(atStart, start), isTrue); - expect(identical(atEnd, end), isTrue); + expect(identical(result, start), isTrue); }); - test('lerp returns self when visibility does not change', () { + test('lerp preserves value when both are same', () { const start = VisibilityModifier(true); const end = VisibilityModifier(true); final mid = start.lerp(end, 0.5); - expect(identical(mid, start), isTrue); + expect(mid.visible, isTrue); }); }); } diff --git a/packages/mix_annotations/lib/mix_annotations.dart b/packages/mix_annotations/lib/mix_annotations.dart index fad9bf1aa..ebb81090a 100644 --- a/packages/mix_annotations/lib/mix_annotations.dart +++ b/packages/mix_annotations/lib/mix_annotations.dart @@ -4,3 +4,4 @@ library; export 'src/annotations.dart'; export 'src/generator_flags.dart'; +export 'src/mixable_modifier.dart'; diff --git a/packages/mix_annotations/lib/src/mixable_modifier.dart b/packages/mix_annotations/lib/src/mixable_modifier.dart new file mode 100644 index 000000000..dc1876351 --- /dev/null +++ b/packages/mix_annotations/lib/src/mixable_modifier.dart @@ -0,0 +1,25 @@ +/// Annotation for generating ModifierMix classes from WidgetModifier subclasses. +/// +/// Annotate a class extending `WidgetModifier` to generate the corresponding +/// `ModifierMix` class with resolve, merge, debugFillProperties, and props. +/// +/// Example usage: +/// ```dart +/// @MixableModifier() +/// final class OpacityModifier extends WidgetModifier +/// with Diagnosticable, _$OpacityModifierMethods { +/// @override +/// final double opacity; +/// const OpacityModifier([double? opacity]) : opacity = opacity ?? 1.0; +/// // build... +/// } +/// ``` +/// +/// This generates a `_$OpacityModifierMethods` mixin (with `copyWith`, `lerp`, +/// `debugFillProperties`, and `props`) and the `OpacityModifierMix` class in the +/// `.g.dart` part file. +class MixableModifier { + const MixableModifier(); +} + +const mixableModifier = MixableModifier(); diff --git a/packages/mix_generator/build.yaml b/packages/mix_generator/build.yaml index d2715d817..5dfe3fdfc 100644 --- a/packages/mix_generator/build.yaml +++ b/packages/mix_generator/build.yaml @@ -17,6 +17,10 @@ targets: enabled: true generate_for: - lib/**/*.dart # Broader because users annotate anywhere. + mix_generator:modifier_generator: + enabled: true + generate_for: + - lib/src/modifiers/**/*.dart # WidgetModifier classes. builders: mix_generator: @@ -50,3 +54,11 @@ builders: auto_apply: dependents build_to: cache applies_builders: ['source_gen:combining_builder'] + + modifier_generator: + import: 'package:mix_generator/mix_generator.dart' + builder_factories: ['modifierGenerator'] + build_extensions: {'.dart': ['.modifier_generator.g.part']} + auto_apply: dependents + build_to: cache + applies_builders: ['source_gen:combining_builder'] diff --git a/packages/mix_generator/lib/mix_generator.dart b/packages/mix_generator/lib/mix_generator.dart index 7294f5821..aefbddffe 100644 --- a/packages/mix_generator/lib/mix_generator.dart +++ b/packages/mix_generator/lib/mix_generator.dart @@ -19,6 +19,7 @@ import 'package:source_gen/source_gen.dart'; import 'src/mix_generator.dart'; import 'src/mix_widget_generator.dart'; import 'src/mixable_generator.dart'; +import 'src/modifier_generator.dart'; import 'src/styler_generator.dart'; // Expose internals for generator unit tests. @@ -32,6 +33,7 @@ export 'src/core/resolvers/index.dart'; export 'src/mix_generator.dart'; export 'src/mix_widget_generator.dart'; export 'src/mixable_generator.dart'; +export 'src/modifier_generator.dart'; export 'src/styler_generator.dart'; /// Builder factory for `mix_generator`. @@ -86,3 +88,17 @@ Builder mixWidgetGenerator(BuilderOptions _) { }, ); } + +/// Builder factory for `modifier_generator`. +/// +/// Generates `_$XModifierMethods` mixins and `XModifierMix` classes for +/// `@MixableModifier` `WidgetModifier` subclasses. +Builder modifierGenerator(BuilderOptions _) { + return SharedPartBuilder( + [ModifierGenerator()], + 'modifier_generator', + formatOutput: (code, version) { + return DartFormatter(languageVersion: version).format(code); + }, + ); +} diff --git a/packages/mix_generator/lib/src/core/builders/index.dart b/packages/mix_generator/lib/src/core/builders/index.dart index 13506d50a..904ed2395 100644 --- a/packages/mix_generator/lib/src/core/builders/index.dart +++ b/packages/mix_generator/lib/src/core/builders/index.dart @@ -3,5 +3,7 @@ library; export 'mix_mixin_builder.dart'; export 'mix_widget_builder.dart'; +export 'modifier_mix_builder.dart'; +export 'modifier_mixin_builder.dart'; export 'spec_mixin_builder.dart'; export 'styler_mixin_builder.dart'; diff --git a/packages/mix_generator/lib/src/core/builders/modifier_mix_builder.dart b/packages/mix_generator/lib/src/core/builders/modifier_mix_builder.dart new file mode 100644 index 000000000..93e2791bc --- /dev/null +++ b/packages/mix_generator/lib/src/core/builders/modifier_mix_builder.dart @@ -0,0 +1,255 @@ +/// Modifier Mix builder for generating ModifierMix classes. +/// +/// Generates a full standalone class from `@MixableModifier` annotations. +library; + +/// Kind of `Prop` wrapper to use for a modifier field. +enum PropWrapperKind { + /// `Prop.maybe(value)` — for direct/enum types. + maybe, + + /// `Prop.maybeMix(value)` — for types with a Mix counterpart. + maybeMix, +} + +/// Represents a field from a WidgetModifier for code generation. +class ModifierFieldModel { + /// The field name. + final String name; + + /// The Dart type name of the field. + final String typeName; + + /// The kind of Prop wrapper to use. + final PropWrapperKind propWrapperKind; + + /// The Mix type name (only set when propWrapperKind is maybeMix). + final String? mixTypeName; + + /// Whether this field is a named parameter in the modifier constructor. + final bool isNamedParam; + + /// Whether this field's type is nullable. + final bool isNullable; + + /// Whether this field supports lerp interpolation. + final bool isLerpable; + + /// Whether this field's type is an enum. + final bool isEnum; + + /// The flag description for bool fields (for FlagProperty diagnostic). + final String? flagDescription; + + const ModifierFieldModel({ + required this.name, + required this.typeName, + required this.propWrapperKind, + this.mixTypeName, + this.isNamedParam = true, + this.isNullable = false, + this.isLerpable = false, + this.isEnum = false, + this.flagDescription, + }); + + /// The full type name including nullability suffix. + String get fullTypeName => isNullable ? '$typeName?' : typeName; + + /// The type used in the public constructor parameter. + String get publicParamType { + if (propWrapperKind == PropWrapperKind.maybeMix && mixTypeName != null) { + return mixTypeName!; + } + + return typeName; + } + + /// The Prop factory call expression. + String get propFactoryCall { + switch (propWrapperKind) { + case PropWrapperKind.maybeMix: + return 'Prop.maybeMix($name)'; + case PropWrapperKind.maybe: + return 'Prop.maybe($name)'; + } + } +} + +/// Builds a full ModifierMix class from modifier field models. +class ModifierMixBuilder { + final String modifierName; + final List fields; + + const ModifierMixBuilder({required this.modifierName, required this.fields}); + + /// The generated class name (e.g., OpacityModifier -> OpacityModifierMix). + String get className => '${modifierName}Mix'; + + String _buildFields() { + if (fields.isEmpty) return ''; + + final buffer = StringBuffer(); + for (final field in fields) { + buffer.writeln(' final Prop<${field.typeName}>? ${field.name};'); + } + buffer.writeln(); + + return buffer.toString(); + } + + String _buildCreateConstructor() { + if (fields.isEmpty) { + return ' const $className.create();\n'; + } + + final buffer = StringBuffer(); + buffer.write(' const $className.create({'); + buffer.write(fields.map((f) => 'this.${f.name}').join(', ')); + buffer.writeln('});'); + + return buffer.toString(); + } + + String _buildPublicConstructor() { + if (fields.isEmpty) { + return ' const $className() : this.create();\n'; + } + + final buffer = StringBuffer(); + + // Constructor signature + buffer.writeln(' $className({'); + for (final field in fields) { + buffer.writeln(' ${field.publicParamType}? ${field.name},'); + } + buffer.writeln(' }) : this.create('); + + // Prop wrapping + for (final field in fields) { + buffer.writeln(' ${field.name}: ${field.propFactoryCall},'); + } + buffer.writeln(' );'); + + return buffer.toString(); + } + + String _buildResolve() { + final buffer = StringBuffer(); + + buffer.writeln(' @override'); + buffer.writeln(' $modifierName resolve(BuildContext context) {'); + buffer.writeln(' return $modifierName('); + + for (final field in fields) { + if (field.isNamedParam) { + buffer.writeln( + ' ${field.name}: MixOps.resolve(context, ${field.name}),', + ); + } else { + buffer.writeln(' MixOps.resolve(context, ${field.name}),'); + } + } + + buffer.writeln(' );'); + buffer.writeln(' }'); + + return buffer.toString(); + } + + String _buildMerge() { + final buffer = StringBuffer(); + + buffer.writeln(' @override'); + buffer.writeln(' $className merge($className? other) {'); + buffer.writeln(' if (other == null) return this;'); + buffer.writeln(); + buffer.writeln(' return $className.create('); + + for (final field in fields) { + buffer.writeln( + ' ${field.name}: MixOps.merge(${field.name}, other.${field.name}),', + ); + } + + buffer.writeln(' );'); + buffer.writeln(' }'); + + return buffer.toString(); + } + + String _buildDebugFillProperties() { + final buffer = StringBuffer(); + + buffer.writeln(' @override'); + buffer.writeln( + ' void debugFillProperties(DiagnosticPropertiesBuilder properties) {', + ); + buffer.writeln(' super.debugFillProperties(properties);'); + + if (fields.length == 1) { + final field = fields[0]; + buffer.writeln( + " properties.add(DiagnosticsProperty('${field.name}', ${field.name}));", + ); + } else if (fields.length > 1) { + buffer.writeln(' properties'); + for (int i = 0; i < fields.length; i++) { + final field = fields[i]; + final separator = i == fields.length - 1 ? ';' : ''; + buffer.writeln( + " ..add(DiagnosticsProperty('${field.name}', ${field.name}))$separator", + ); + } + } + + buffer.writeln(' }'); + + return buffer.toString(); + } + + String _buildProps() { + final buffer = StringBuffer(); + + buffer.writeln(' @override'); + buffer.write(' List get props => ['); + + if (fields.isEmpty) { + buffer.writeln('];'); + } else { + buffer.writeln(); + for (final field in fields) { + buffer.writeln(' ${field.name},'); + } + buffer.writeln(' ];'); + } + + return buffer.toString(); + } + + /// Builds the complete class code. + String build() { + final buffer = StringBuffer(); + + buffer.writeln( + 'class $className extends ModifierMix<$modifierName> with Diagnosticable {', + ); + + // Fields + buffer.write(_buildFields()); + + // Constructors + buffer.writeln(_buildCreateConstructor()); + buffer.writeln(_buildPublicConstructor()); + + // Methods + buffer.writeln(_buildResolve()); + buffer.writeln(_buildMerge()); + buffer.writeln(_buildDebugFillProperties()); + buffer.writeln(_buildProps()); + + buffer.writeln('}'); + + return buffer.toString(); + } +} diff --git a/packages/mix_generator/lib/src/core/builders/modifier_mixin_builder.dart b/packages/mix_generator/lib/src/core/builders/modifier_mixin_builder.dart new file mode 100644 index 000000000..1174557c4 --- /dev/null +++ b/packages/mix_generator/lib/src/core/builders/modifier_mixin_builder.dart @@ -0,0 +1,206 @@ +/// Modifier mixin builder for generating the `_$XModifierMethods` mixin. +/// +/// Generates copyWith(), lerp(), debugFillProperties(), and props +/// for `@MixableModifier` annotated classes. +library; + +import 'modifier_mix_builder.dart'; + +/// Builds the `_$XModifierMethods` mixin for a WidgetModifier class. +class ModifierMixinBuilder { + final String modifierName; + final List fields; + + const ModifierMixinBuilder({ + required this.modifierName, + required this.fields, + }); + + /// The mixin name (e.g., AlignModifier -> _$AlignModifierMethods). + String get mixinName => '_\$${modifierName}Methods'; + + String _buildAbstractGetters() { + if (fields.isEmpty) return ''; + + final buffer = StringBuffer(); + for (final field in fields) { + buffer.writeln(' ${field.fullTypeName} get ${field.name};'); + } + buffer.writeln(); + + return buffer.toString(); + } + + String _buildCopyWith() { + final buffer = StringBuffer(); + + buffer.writeln(' @override'); + + if (fields.isEmpty) { + buffer.writeln(' $modifierName copyWith() {'); + buffer.writeln(' return const $modifierName();'); + buffer.writeln(' }'); + + return buffer.toString(); + } + + buffer.writeln(' $modifierName copyWith({'); + for (final field in fields) { + final optionalType = field.isNullable + ? field.fullTypeName + : '${field.typeName}?'; + buffer.writeln(' $optionalType ${field.name},'); + } + buffer.writeln(' }) {'); + buffer.writeln(' return $modifierName('); + for (final field in fields) { + if (field.isNamedParam) { + buffer.writeln( + ' ${field.name}: ${field.name} ?? this.${field.name},', + ); + } else { + buffer.writeln(' ${field.name} ?? this.${field.name},'); + } + } + buffer.writeln(' );'); + buffer.writeln(' }'); + + return buffer.toString(); + } + + String _buildLerp() { + final buffer = StringBuffer(); + + buffer.writeln(' @override'); + buffer.writeln(' $modifierName lerp($modifierName? other, double t) {'); + buffer.writeln(' if (other == null) return this as $modifierName;'); + buffer.writeln(); + + if (fields.isEmpty) { + buffer.writeln(' return const $modifierName();'); + buffer.writeln(' }'); + + return buffer.toString(); + } + + buffer.writeln(' return $modifierName('); + for (final field in fields) { + final lerpFn = field.isLerpable ? 'MixOps.lerp' : 'MixOps.lerpSnap'; + final nullAssert = field.isNullable ? '' : '!'; + if (field.isNamedParam) { + buffer.writeln( + ' ${field.name}: $lerpFn(${field.name}, other.${field.name}, t)$nullAssert,', + ); + } else { + buffer.writeln( + ' $lerpFn(${field.name}, other.${field.name}, t)$nullAssert,', + ); + } + } + buffer.writeln(' );'); + buffer.writeln(' }'); + + return buffer.toString(); + } + + String _buildDebugFillProperties() { + final buffer = StringBuffer(); + + buffer.writeln(' @override'); + buffer.writeln( + ' void debugFillProperties(DiagnosticPropertiesBuilder properties) {', + ); + buffer.writeln(' super.debugFillProperties(properties);'); + + if (fields.length == 1) { + final field = fields[0]; + final diagnosticCode = _getDiagnosticCode(field); + buffer.writeln(' properties.add($diagnosticCode);'); + } else if (fields.length > 1) { + buffer.writeln(' properties'); + for (int i = 0; i < fields.length; i++) { + final field = fields[i]; + final diagnosticCode = _getDiagnosticCode(field); + final separator = i == fields.length - 1 ? ';' : ''; + buffer.writeln(' ..add($diagnosticCode)$separator'); + } + } + + buffer.writeln(' }'); + + return buffer.toString(); + } + + String _getDiagnosticCode(ModifierFieldModel field) { + final name = field.name; + + if (field.typeName == 'double') { + return "DoubleProperty('$name', $name)"; + } + if (field.typeName == 'int') { + return "IntProperty('$name', $name)"; + } + if (field.typeName == 'String') { + return "StringProperty('$name', $name)"; + } + if (field.typeName == 'Color') { + return "ColorProperty('$name', $name)"; + } + if (field.typeName == 'bool') { + if (field.flagDescription != null) { + return "FlagProperty('$name', value: $name, ifTrue: '${field.flagDescription}')"; + } + + return "DiagnosticsProperty('$name', $name)"; + } + if (field.isEnum) { + return "EnumProperty<${field.typeName}>('$name', $name)"; + } + + return "DiagnosticsProperty('$name', $name)"; + } + + String _buildProps() { + final buffer = StringBuffer(); + + buffer.writeln(' @override'); + buffer.write(' List get props => ['); + + if (fields.isEmpty) { + buffer.writeln('];'); + } else { + final fieldNames = fields.map((f) => f.name).join(', '); + buffer.writeln('$fieldNames];'); + } + + return buffer.toString(); + } + + /// Builds the complete mixin code. + String build() { + final buffer = StringBuffer(); + + buffer.writeln( + 'mixin $mixinName on WidgetModifier<$modifierName>, Diagnosticable {', + ); + + // Abstract getters + buffer.write(_buildAbstractGetters()); + + // copyWith + buffer.writeln(_buildCopyWith()); + + // lerp + buffer.writeln(_buildLerp()); + + // debugFillProperties + buffer.writeln(_buildDebugFillProperties()); + + // props + buffer.writeln(_buildProps()); + + buffer.writeln('}'); + + return buffer.toString(); + } +} diff --git a/packages/mix_generator/lib/src/core/curated/type_metadata.dart b/packages/mix_generator/lib/src/core/curated/type_metadata.dart index 7b7a1f7f5..bfe175475 100644 --- a/packages/mix_generator/lib/src/core/curated/type_metadata.dart +++ b/packages/mix_generator/lib/src/core/curated/type_metadata.dart @@ -199,6 +199,8 @@ const flagPropertyDescriptions = { 'isAntiAlias': 'anti-aliased', 'matchTextDirection': 'matches text direction', 'applyTextScaling': 'scales with text', + 'reverse': 'reversed', + 'visible': 'visible', }; TypeMetadata? _metadataFor(String typeName) => typeMetadata[typeName]; diff --git a/packages/mix_generator/lib/src/modifier_generator.dart b/packages/mix_generator/lib/src/modifier_generator.dart new file mode 100644 index 000000000..53e0bc7d4 --- /dev/null +++ b/packages/mix_generator/lib/src/modifier_generator.dart @@ -0,0 +1,136 @@ +/// Modifier generator for ModifierMix class code generation. +/// +/// Generates a modifier mixin and `ModifierMix` class from `@MixableModifier` +/// annotations. +library; + +import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/dart/element/nullability_suffix.dart'; +import 'package:analyzer/dart/element/type.dart'; +import 'package:build/build.dart'; +import 'package:mix_annotations/mix_annotations.dart'; +import 'package:source_gen/source_gen.dart'; + +import 'core/builders/modifier_mix_builder.dart'; +import 'core/builders/modifier_mixin_builder.dart'; +import 'core/curated/type_metadata.dart'; +import 'core/errors.dart'; + +/// Main generator for `ModifierMix` class code. +/// +/// Triggers on `@MixableModifier` annotations and generates: +/// - A `_$XModifierMethods` mixin (copyWith, lerp, debugFillProperties, props) +/// - A full `ModifierMix` class (resolve, merge, debugFillProperties, props) +class ModifierGenerator extends GeneratorForAnnotation { + const ModifierGenerator(); + + bool _isWidgetModifierClass(ClassElement element) { + for (final interface in element.allSupertypes) { + if (interface.element.name == 'WidgetModifier') return true; + } + + return false; + } + + List _extractFields(ClassElement classElement) { + // Only fields declared directly on this class (not inherited). + final fields = classElement.fields + .where((f) => !f.isStatic && !f.isSynthetic && f.isFinal) + .toList(); + + // Map constructor param names to their named/positional status. + final constructor = classElement.unnamedConstructor; + final paramMap = {}; + if (constructor != null) { + for (final param in constructor.formalParameters) { + final name = param.name; + if (name != null) paramMap[name] = param.isNamed; + } + } + + // Stable ordering for deterministic generator output. + fields.sort((a, b) => a.name!.compareTo(b.name!)); + + return fields.map((field) { + final name = field.name!; + final type = field.type; + final typeName = _baseTypeName(type); + final isNullable = type.nullabilitySuffix == NullabilitySuffix.question; + + final mixTypeName = mixTypeFor(typeName); + final propWrapperKind = mixTypeName != null + ? PropWrapperKind.maybeMix + : PropWrapperKind.maybe; + + final isEnum = _isEnum(type); + final flagDescription = typeName == 'bool' + ? flagDescriptionFor(name) + : null; + + return ModifierFieldModel( + name: name, + typeName: typeName, + propWrapperKind: propWrapperKind, + mixTypeName: mixTypeName, + isNamedParam: paramMap[name] ?? true, + isNullable: isNullable, + isLerpable: isLerpableType(typeName), + isEnum: isEnum, + flagDescription: flagDescription, + ); + }).toList(); + } + + String _baseTypeName(DartType type) { + final displayString = type.getDisplayString(); + if (displayString.endsWith('?')) { + return displayString.substring(0, displayString.length - 1); + } + + return displayString; + } + + bool _isEnum(DartType type) { + if (type is InterfaceType) { + return type.element is EnumElement; + } + + return false; + } + + @override + String generateForAnnotatedElement( + Element element, + ConstantReader annotation, + BuildStep buildStep, + ) { + final classElement = requireClassElement(element, '@MixableModifier'); + final modifierName = requireName( + classElement, + orFailWith: '@MixableModifier class must have a name.', + ); + + if (!_isWidgetModifierClass(classElement)) { + fail( + element, + '@MixableModifier can only be applied to classes extending ' + 'WidgetModifier.', + todo: 'Make the class extend `WidgetModifier`.', + ); + } + + final fields = _extractFields(classElement); + + final mixinBuilder = ModifierMixinBuilder( + modifierName: modifierName, + fields: fields, + ); + + final mixBuilder = ModifierMixBuilder( + modifierName: modifierName, + fields: fields, + ); + + return '${mixinBuilder.build()}\n${mixBuilder.build()}'; + } +} diff --git a/packages/mix_generator/test/core/builders/modifier_mix_builder_test.dart b/packages/mix_generator/test/core/builders/modifier_mix_builder_test.dart new file mode 100644 index 000000000..526c2be51 --- /dev/null +++ b/packages/mix_generator/test/core/builders/modifier_mix_builder_test.dart @@ -0,0 +1,241 @@ +import 'package:mix_generator/src/core/builders/modifier_mix_builder.dart'; +import 'package:test/test.dart'; + +void main() { + group('ModifierMixBuilder', () { + group('className', () { + test('generates correct class name from modifier name', () { + final builder = ModifierMixBuilder( + modifierName: 'OpacityModifier', + fields: [], + ); + expect(builder.className, equals('OpacityModifierMix')); + }); + }); + + group('build', () { + test('generates class extending ModifierMix with Diagnosticable', () { + final builder = ModifierMixBuilder( + modifierName: 'OpacityModifier', + fields: [], + ); + final code = builder.build(); + + expect( + code, + contains( + 'class OpacityModifierMix extends ModifierMix with Diagnosticable', + ), + ); + }); + + test('generates create constructor with Prop fields', () { + final builder = ModifierMixBuilder( + modifierName: 'OpacityModifier', + fields: [ + ModifierFieldModel( + name: 'opacity', + typeName: 'double', + propWrapperKind: PropWrapperKind.maybe, + ), + ], + ); + final code = builder.build(); + + expect(code, contains('final Prop? opacity;')); + expect( + code, + contains('const OpacityModifierMix.create({this.opacity});'), + ); + }); + + test('generates public constructor with Prop.maybe for direct types', () { + final builder = ModifierMixBuilder( + modifierName: 'OpacityModifier', + fields: [ + ModifierFieldModel( + name: 'opacity', + typeName: 'double', + propWrapperKind: PropWrapperKind.maybe, + ), + ], + ); + final code = builder.build(); + + expect(code, contains('double? opacity,')); + expect(code, contains('opacity: Prop.maybe(opacity)')); + }); + + test('generates public constructor with Prop.maybeMix for mix types', () { + final builder = ModifierMixBuilder( + modifierName: 'ClipRRectModifier', + fields: [ + ModifierFieldModel( + name: 'borderRadius', + typeName: 'BorderRadiusGeometry', + propWrapperKind: PropWrapperKind.maybeMix, + mixTypeName: 'BorderRadiusGeometryMix', + ), + ModifierFieldModel( + name: 'clipBehavior', + typeName: 'Clip', + propWrapperKind: PropWrapperKind.maybe, + ), + ], + ); + final code = builder.build(); + + expect(code, contains('BorderRadiusGeometryMix? borderRadius')); + expect(code, contains('borderRadius: Prop.maybeMix(borderRadius)')); + expect(code, contains('Clip? clipBehavior')); + expect(code, contains('clipBehavior: Prop.maybe(clipBehavior)')); + }); + + test('generates resolve method with named params', () { + final builder = ModifierMixBuilder( + modifierName: 'AlignModifier', + fields: [ + ModifierFieldModel( + name: 'alignment', + typeName: 'AlignmentGeometry', + propWrapperKind: PropWrapperKind.maybe, + isNamedParam: true, + ), + ], + ); + final code = builder.build(); + + expect(code, contains('@override')); + expect(code, contains('AlignModifier resolve(BuildContext context)')); + expect(code, contains('return AlignModifier(')); + expect(code, contains('alignment: MixOps.resolve(context, alignment)')); + }); + + test('generates resolve method with positional params', () { + final builder = ModifierMixBuilder( + modifierName: 'OpacityModifier', + fields: [ + ModifierFieldModel( + name: 'opacity', + typeName: 'double', + propWrapperKind: PropWrapperKind.maybe, + isNamedParam: false, + ), + ], + ); + final code = builder.build(); + + expect(code, contains('@override')); + expect(code, contains('OpacityModifier resolve(BuildContext context)')); + expect(code, contains('return OpacityModifier(')); + expect(code, contains('MixOps.resolve(context, opacity)')); + expect(code, isNot(contains('opacity: MixOps.resolve'))); + }); + + test('generates merge method', () { + final builder = ModifierMixBuilder( + modifierName: 'OpacityModifier', + fields: [ + ModifierFieldModel( + name: 'opacity', + typeName: 'double', + propWrapperKind: PropWrapperKind.maybe, + ), + ], + ); + final code = builder.build(); + + expect(code, contains('@override')); + expect( + code, + contains('OpacityModifierMix merge(OpacityModifierMix? other)'), + ); + expect(code, contains('if (other == null) return this;')); + expect(code, contains('return OpacityModifierMix.create(')); + expect(code, contains('opacity: MixOps.merge(opacity, other.opacity)')); + }); + + test('generates debugFillProperties', () { + final builder = ModifierMixBuilder( + modifierName: 'OpacityModifier', + fields: [ + ModifierFieldModel( + name: 'opacity', + typeName: 'double', + propWrapperKind: PropWrapperKind.maybe, + ), + ], + ); + final code = builder.build(); + + expect(code, contains('@override')); + expect( + code, + contains( + 'void debugFillProperties(DiagnosticPropertiesBuilder properties)', + ), + ); + expect(code, contains('super.debugFillProperties(properties)')); + expect(code, contains("DiagnosticsProperty('opacity', opacity)")); + }); + + test('generates props getter', () { + final builder = ModifierMixBuilder( + modifierName: 'OpacityModifier', + fields: [ + ModifierFieldModel( + name: 'opacity', + typeName: 'double', + propWrapperKind: PropWrapperKind.maybe, + ), + ], + ); + final code = builder.build(); + + expect(code, contains('@override')); + expect(code, contains('List get props => [')); + expect(code, contains('opacity,')); + }); + + test('handles multiple fields', () { + final builder = ModifierMixBuilder( + modifierName: 'ClipOvalModifier', + fields: [ + ModifierFieldModel( + name: 'clipper', + typeName: 'CustomClipper', + propWrapperKind: PropWrapperKind.maybe, + ), + ModifierFieldModel( + name: 'clipBehavior', + typeName: 'Clip', + propWrapperKind: PropWrapperKind.maybe, + ), + ], + ); + final code = builder.build(); + + expect(code, contains('final Prop>? clipper;')); + expect(code, contains('final Prop? clipBehavior;')); + expect(code, contains('MixOps.resolve(context, clipper)')); + expect(code, contains('MixOps.resolve(context, clipBehavior)')); + }); + + test('generates empty class when no fields', () { + final builder = ModifierMixBuilder( + modifierName: 'NoopModifier', + fields: [], + ); + final code = builder.build(); + + expect( + code, + contains('class NoopModifierMix extends ModifierMix'), + ); + expect(code, contains('const NoopModifierMix.create();')); + expect(code, contains('const NoopModifierMix() : this.create();')); + expect(code, contains('List get props => [];')); + }); + }); + }); +} diff --git a/packages/mix_generator/test/core/builders/modifier_mixin_builder_test.dart b/packages/mix_generator/test/core/builders/modifier_mixin_builder_test.dart new file mode 100644 index 000000000..94270f7a1 --- /dev/null +++ b/packages/mix_generator/test/core/builders/modifier_mixin_builder_test.dart @@ -0,0 +1,317 @@ +import 'package:mix_generator/src/core/builders/modifier_mix_builder.dart'; +import 'package:mix_generator/src/core/builders/modifier_mixin_builder.dart'; +import 'package:test/test.dart'; + +void main() { + group('ModifierMixinBuilder', () { + group('mixinName', () { + test('generates correct mixin name from modifier name', () { + final builder = ModifierMixinBuilder( + modifierName: 'AlignModifier', + fields: [], + ); + expect(builder.mixinName, equals('_\$AlignModifierMethods')); + }); + }); + + group('build', () { + test('generates mixin with WidgetModifier constraint', () { + final builder = ModifierMixinBuilder( + modifierName: 'AlignModifier', + fields: [], + ); + final code = builder.build(); + + expect( + code, + contains( + 'mixin _\$AlignModifierMethods on WidgetModifier, Diagnosticable', + ), + ); + }); + + test('generates abstract getters for fields', () { + final builder = ModifierMixinBuilder( + modifierName: 'AlignModifier', + fields: [ + ModifierFieldModel( + name: 'alignment', + typeName: 'AlignmentGeometry', + propWrapperKind: PropWrapperKind.maybe, + isLerpable: true, + ), + ModifierFieldModel( + name: 'widthFactor', + typeName: 'double', + propWrapperKind: PropWrapperKind.maybe, + isNullable: true, + isLerpable: true, + ), + ], + ); + final code = builder.build(); + + expect(code, contains('AlignmentGeometry get alignment;')); + expect(code, contains('double? get widthFactor;')); + }); + + test('generates copyWith with named params', () { + final builder = ModifierMixinBuilder( + modifierName: 'AlignModifier', + fields: [ + ModifierFieldModel( + name: 'alignment', + typeName: 'AlignmentGeometry', + propWrapperKind: PropWrapperKind.maybe, + isNamedParam: true, + ), + ], + ); + final code = builder.build(); + + expect(code, contains('AlignModifier copyWith({')); + expect(code, contains('AlignmentGeometry? alignment,')); + expect(code, contains('alignment: alignment ?? this.alignment,')); + }); + + test('generates copyWith with positional params', () { + final builder = ModifierMixinBuilder( + modifierName: 'OpacityModifier', + fields: [ + ModifierFieldModel( + name: 'opacity', + typeName: 'double', + propWrapperKind: PropWrapperKind.maybe, + isNamedParam: false, + isLerpable: true, + ), + ], + ); + final code = builder.build(); + + expect(code, contains('OpacityModifier copyWith({')); + expect(code, contains('opacity ?? this.opacity,')); + expect(code, isNot(contains('opacity: opacity ?? this.opacity,'))); + }); + + test('generates lerp with MixOps.lerp for lerpable types', () { + final builder = ModifierMixinBuilder( + modifierName: 'AlignModifier', + fields: [ + ModifierFieldModel( + name: 'alignment', + typeName: 'AlignmentGeometry', + propWrapperKind: PropWrapperKind.maybe, + isNamedParam: true, + isLerpable: true, + ), + ], + ); + final code = builder.build(); + + expect( + code, + contains('alignment: MixOps.lerp(alignment, other.alignment, t)!'), + ); + }); + + test('generates lerp with MixOps.lerpSnap for non-lerpable types', () { + final builder = ModifierMixinBuilder( + modifierName: 'FlexibleModifier', + fields: [ + ModifierFieldModel( + name: 'fit', + typeName: 'FlexFit', + propWrapperKind: PropWrapperKind.maybe, + isNamedParam: true, + isNullable: true, + isEnum: true, + ), + ], + ); + final code = builder.build(); + + expect(code, contains('fit: MixOps.lerpSnap(fit, other.fit, t),')); + }); + + test('generates lerp with null assertion for non-nullable fields', () { + final builder = ModifierMixinBuilder( + modifierName: 'ClipOvalModifier', + fields: [ + ModifierFieldModel( + name: 'clipBehavior', + typeName: 'Clip', + propWrapperKind: PropWrapperKind.maybe, + isNamedParam: true, + isNullable: false, + isEnum: true, + ), + ], + ); + final code = builder.build(); + + expect( + code, + contains( + 'clipBehavior: MixOps.lerpSnap(clipBehavior, other.clipBehavior, t)!', + ), + ); + }); + + test('generates lerp without null assertion for nullable fields', () { + final builder = ModifierMixinBuilder( + modifierName: 'SizedBoxModifier', + fields: [ + ModifierFieldModel( + name: 'width', + typeName: 'double', + propWrapperKind: PropWrapperKind.maybe, + isNamedParam: true, + isNullable: true, + isLerpable: true, + ), + ], + ); + final code = builder.build(); + + expect(code, contains('width: MixOps.lerp(width, other.width, t),')); + expect( + code, + isNot(contains('width: MixOps.lerp(width, other.width, t)!')), + ); + }); + + test('generates DoubleProperty diagnostic for double fields', () { + final builder = ModifierMixinBuilder( + modifierName: 'OpacityModifier', + fields: [ + ModifierFieldModel( + name: 'opacity', + typeName: 'double', + propWrapperKind: PropWrapperKind.maybe, + ), + ], + ); + final code = builder.build(); + + expect(code, contains("DoubleProperty('opacity', opacity)")); + }); + + test('generates IntProperty diagnostic for int fields', () { + final builder = ModifierMixinBuilder( + modifierName: 'RotatedBoxModifier', + fields: [ + ModifierFieldModel( + name: 'quarterTurns', + typeName: 'int', + propWrapperKind: PropWrapperKind.maybe, + ), + ], + ); + final code = builder.build(); + + expect(code, contains("IntProperty('quarterTurns', quarterTurns)")); + }); + + test('generates EnumProperty diagnostic for enum fields', () { + final builder = ModifierMixinBuilder( + modifierName: 'ClipOvalModifier', + fields: [ + ModifierFieldModel( + name: 'clipBehavior', + typeName: 'Clip', + propWrapperKind: PropWrapperKind.maybe, + isEnum: true, + ), + ], + ); + final code = builder.build(); + + expect( + code, + contains("EnumProperty('clipBehavior', clipBehavior)"), + ); + }); + + test('generates FlagProperty for bool with flag description', () { + final builder = ModifierMixinBuilder( + modifierName: 'ScrollViewModifier', + fields: [ + ModifierFieldModel( + name: 'reverse', + typeName: 'bool', + propWrapperKind: PropWrapperKind.maybe, + isNullable: true, + flagDescription: 'reversed', + ), + ], + ); + final code = builder.build(); + + expect( + code, + contains( + "FlagProperty('reverse', value: reverse, ifTrue: 'reversed')", + ), + ); + }); + + test('generates props getter', () { + final builder = ModifierMixinBuilder( + modifierName: 'SizedBoxModifier', + fields: [ + ModifierFieldModel( + name: 'height', + typeName: 'double', + propWrapperKind: PropWrapperKind.maybe, + isNullable: true, + ), + ModifierFieldModel( + name: 'width', + typeName: 'double', + propWrapperKind: PropWrapperKind.maybe, + isNullable: true, + ), + ], + ); + final code = builder.build(); + + expect(code, contains('List get props => [height, width];')); + }); + + test('generates empty methods for zero-field modifier', () { + final builder = ModifierMixinBuilder( + modifierName: 'IntrinsicHeightModifier', + fields: [], + ); + final code = builder.build(); + + expect(code, contains('IntrinsicHeightModifier copyWith()')); + expect(code, contains('return const IntrinsicHeightModifier();')); + expect(code, contains('List get props => [];')); + }); + + test('generates lerp with positional params', () { + final builder = ModifierMixinBuilder( + modifierName: 'OpacityModifier', + fields: [ + ModifierFieldModel( + name: 'opacity', + typeName: 'double', + propWrapperKind: PropWrapperKind.maybe, + isNamedParam: false, + isLerpable: true, + ), + ], + ); + final code = builder.build(); + + expect(code, contains('MixOps.lerp(opacity, other.opacity, t)!,')); + expect( + code, + isNot(contains('opacity: MixOps.lerp(opacity, other.opacity, t)!')), + ); + }); + }); + }); +}