diff --git a/examples/todo_list/lib/style/components/button.dart b/examples/todo_list/lib/style/components/button.dart index eb585d17a..57b4ac45c 100644 --- a/examples/todo_list/lib/style/components/button.dart +++ b/examples/todo_list/lib/style/components/button.dart @@ -33,10 +33,10 @@ class TodoButton extends StatelessWidget { $text.style.ref($token.textStyle.heading3), $text.style.bold(), $with.scale(1), + $with.align(alignment: Alignment.center), $on.press( $with.scale(1.1), ), - $with.align(alignment: Alignment.center), ), ), ); diff --git a/packages/mix/lib/src/modifiers/padding_widget_modifier.dart b/packages/mix/lib/src/modifiers/padding_widget_modifier.dart index b3e533f01..d5a057dc4 100644 --- a/packages/mix/lib/src/modifiers/padding_widget_modifier.dart +++ b/packages/mix/lib/src/modifiers/padding_widget_modifier.dart @@ -3,8 +3,10 @@ import 'package:flutter/widgets.dart'; import '../attributes/spacing/edge_insets_dto.dart'; +import '../core/attribute.dart'; import '../core/factory/mix_data.dart'; import '../core/modifier.dart'; +import '../core/utility.dart'; final class PaddingSpec extends WidgetModifierSpec { final EdgeInsetsGeometry padding; @@ -38,7 +40,7 @@ final class PaddingModifierAttribute @override PaddingModifierAttribute merge(PaddingModifierAttribute? other) { - return PaddingModifierAttribute(other?.padding ?? padding); + return PaddingModifierAttribute(padding.merge(other?.padding)); } @override @@ -47,3 +49,9 @@ final class PaddingModifierAttribute @override get props => [padding]; } + +final class PaddingModifierUtility + extends MixUtility { + const PaddingModifierUtility(super.builder); + T call(SpacingDto value) => builder(PaddingModifierAttribute(value)); +} diff --git a/packages/mix/lib/src/modifiers/widget_modifiers_util.dart b/packages/mix/lib/src/modifiers/widget_modifiers_util.dart index 8cb691c0e..ca28f269e 100644 --- a/packages/mix/lib/src/modifiers/widget_modifiers_util.dart +++ b/packages/mix/lib/src/modifiers/widget_modifiers_util.dart @@ -1,4 +1,6 @@ import '../attributes/spacing/spacing_util.dart'; +import '../core/attribute.dart'; +import '../core/modifier.dart'; import '../core/utility.dart'; import 'align_widget_modifier.dart'; import 'aspect_ratio_widget_modifier.dart'; @@ -13,35 +15,33 @@ import 'sized_box_widget_modifier.dart'; import 'transform_widget_modifier.dart'; import 'visibility_widget_modifier.dart'; -class WithModifierUtility { - late final intrinsicWidth = - const IntrinsicWidthWidgetUtility(MixUtility.selfBuilder); - late final intrinsicHeight = - const IntrinsicHeightWidgetUtility(MixUtility.selfBuilder); - late final rotate = const RotatedBoxWidgetUtility(MixUtility.selfBuilder); - late final opacity = const OpacityUtility(MixUtility.selfBuilder); - late final clipPath = const ClipPathUtility(MixUtility.selfBuilder); - late final clipRRect = const ClipRRectUtility(MixUtility.selfBuilder); - late final clipOval = const ClipOvalUtility(MixUtility.selfBuilder); - late final clipRect = const ClipRectUtility(MixUtility.selfBuilder); - late final clipTriangle = const ClipTriangleUtility(MixUtility.selfBuilder); - late final visibility = const VisibilityUtility(MixUtility.selfBuilder); +class WithModifierUtility + extends MixUtility { + late final intrinsicWidth = IntrinsicWidthWidgetUtility(builder); + late final intrinsicHeight = IntrinsicHeightWidgetUtility(builder); + late final rotate = RotatedBoxWidgetUtility(builder); + late final opacity = OpacityUtility(builder); + late final clipPath = ClipPathUtility(builder); + late final clipRRect = ClipRRectUtility(builder); + late final clipOval = ClipOvalUtility(builder); + late final clipRect = ClipRectUtility(builder); + late final clipTriangle = ClipTriangleUtility(builder); + late final visibility = VisibilityUtility(builder); late final show = visibility.on; late final hide = visibility.off; - late final aspectRatio = const AspectRatioUtility(MixUtility.selfBuilder); - late final flexible = _flexible; + late final aspectRatio = AspectRatioUtility(builder); + late final flexible = FlexibleModifierUtility(builder); late final expanded = flexible.expanded; - late final transform = const TransformUtility(MixUtility.selfBuilder); + late final transform = TransformUtility(builder); late final scale = transform.scale; - late final align = const AlignWidgetUtility(MixUtility.selfBuilder); + late final align = AlignWidgetUtility(builder); late final fractionallySizedBox = - const FractionallySizedBoxModifierUtility(MixUtility.selfBuilder); - late final sizedBox = SizedBoxModifierUtility(MixUtility.selfBuilder); - late final padding = SpacingUtility(PaddingModifierAttribute.new); + FractionallySizedBoxModifierUtility(builder); + late final sizedBox = SizedBoxModifierUtility(builder); + late final padding = SpacingUtility(PaddingModifierUtility(builder).call); - static final self = WithModifierUtility._(); - late final _flexible = const FlexibleModifierUtility(MixUtility.selfBuilder); + static final self = WithModifierUtility(MixUtility.selfBuilder); - WithModifierUtility._(); + WithModifierUtility(super.builder); } diff --git a/packages/mix/lib/src/specs/icon/icon_spec.dart b/packages/mix/lib/src/specs/icon/icon_spec.dart index 622a12e08..745d1f2d1 100644 --- a/packages/mix/lib/src/specs/icon/icon_spec.dart +++ b/packages/mix/lib/src/specs/icon/icon_spec.dart @@ -36,16 +36,22 @@ final class IconSpec extends Spec with _$IconSpec { super.animated, }); - Widget call([IconData? icon]) { + Widget call(IconData? icon, {String? semanticLabel}) { return isAnimated ? AnimatedIconSpecWidget( icon, spec: this, + semanticLabel: semanticLabel, textDirection: textDirection, curve: animated!.curve, duration: animated!.duration, ) - : IconSpecWidget(icon, spec: this, textDirection: textDirection); + : IconSpecWidget( + icon, + spec: this, + semanticLabel: semanticLabel, + textDirection: textDirection, + ); } } diff --git a/packages/mix/lib/src/specs/icon/icon_widget.dart b/packages/mix/lib/src/specs/icon/icon_widget.dart index c439b7ce1..56b774956 100644 --- a/packages/mix/lib/src/specs/icon/icon_widget.dart +++ b/packages/mix/lib/src/specs/icon/icon_widget.dart @@ -16,6 +16,7 @@ class StyledIcon extends StyledWidget { final IconData? icon; final String? semanticLabel; + // TODO: Should textDirection be a contructor argument or a style attribute? final TextDirection? textDirection; @override diff --git a/packages/mix/lib/src/specs/image/image_spec.dart b/packages/mix/lib/src/specs/image/image_spec.dart index e2ac5b56e..a590f6647 100644 --- a/packages/mix/lib/src/specs/image/image_spec.dart +++ b/packages/mix/lib/src/specs/image/image_spec.dart @@ -34,14 +34,46 @@ final class ImageSpec extends Spec with _$ImageSpec { super.animated, }); - Widget call({required ImageProvider image}) { + Widget call({ + required ImageProvider image, + ImageFrameBuilder? frameBuilder, + ImageLoadingBuilder? loadingBuilder, + ImageErrorWidgetBuilder? errorBuilder, + String? semanticLabel, + bool excludeFromSemantics = false, + bool gaplessPlayback = false, + bool isAntiAlias = false, + bool matchTextDirection = false, + Animation? opacity, + }) { return isAnimated ? AnimatedImageSpecWidget( spec: this, image: image, + frameBuilder: frameBuilder, + loadingBuilder: loadingBuilder, + errorBuilder: errorBuilder, + semanticLabel: semanticLabel, + excludeFromSemantics: excludeFromSemantics, duration: animated!.duration, curve: animated!.curve, + gaplessPlayback: gaplessPlayback, + isAntiAlias: isAntiAlias, + matchTextDirection: matchTextDirection, + opacity: opacity, ) - : ImageSpecWidget(spec: this, image: image); + : ImageSpecWidget( + spec: this, + image: image, + frameBuilder: frameBuilder, + loadingBuilder: loadingBuilder, + errorBuilder: errorBuilder, + semanticLabel: semanticLabel, + excludeFromSemantics: excludeFromSemantics, + gaplessPlayback: gaplessPlayback, + isAntiAlias: isAntiAlias, + opacity: opacity, + matchTextDirection: matchTextDirection, + ); } } diff --git a/packages/mix/lib/src/specs/text/text_spec.dart b/packages/mix/lib/src/specs/text/text_spec.dart index 98438c504..a1e0f9a67 100644 --- a/packages/mix/lib/src/specs/text/text_spec.dart +++ b/packages/mix/lib/src/specs/text/text_spec.dart @@ -52,14 +52,21 @@ final class TextSpec extends Spec with _$TextSpec { super.animated, }); - Widget call(String text) { + Widget call(String text, {String? semanticLabel, Locale? locale}) { return isAnimated ? AnimatedTextSpecWidget( text, spec: this, + semanticsLabel: semanticLabel, + locale: locale, duration: animated!.duration, curve: animated!.curve, ) - : TextSpecWidget(text, spec: this); + : TextSpecWidget( + text, + spec: this, + semanticsLabel: semanticLabel, + locale: locale, + ); } } diff --git a/packages/mix/test/src/modifiers/padding_widget_modifier_test.dart b/packages/mix/test/src/modifiers/padding_widget_modifier_test.dart index 708de6973..2c9e5fb68 100644 --- a/packages/mix/test/src/modifiers/padding_widget_modifier_test.dart +++ b/packages/mix/test/src/modifiers/padding_widget_modifier_test.dart @@ -82,6 +82,22 @@ void main() { expect(result.padding, equals(padding2)); }); + test('deep merge returns correct PaddingModifierAttribute', () { + const padding1 = EdgeInsetsDto(top: 1, bottom: 2, left: 3, right: 4); + const padding2 = EdgeInsetsDto(top: 4, bottom: 3); + const attribute1 = PaddingModifierAttribute(padding1); + const attribute2 = PaddingModifierAttribute(padding2); + + final result = attribute1.merge(attribute2); + + expect( + result.padding, + equals( + const EdgeInsetsDto(top: 4, bottom: 3, left: 3, right: 4), + ), + ); + }); + test('merge returns original PaddingModifierAttribute when other is null', () { const padding = EdgeInsetsDto.all(10.0); diff --git a/packages/mix/test/src/modifiers/scale_widget_decorator_test.dart b/packages/mix/test/src/modifiers/scale_widget_decorator_test.dart index a869396e8..648d47c2c 100644 --- a/packages/mix/test/src/modifiers/scale_widget_decorator_test.dart +++ b/packages/mix/test/src/modifiers/scale_widget_decorator_test.dart @@ -14,7 +14,7 @@ void main() { MockMixData( Style(modifier), ), - ); + ) as TransformModifierSpec; expect(spec.transform, Matrix4.diagonal3Values(scale, scale, 1)); });