From 1c2166533eb860a597d36aeed3eed7ad46eedb49 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Mon, 11 Nov 2024 21:24:11 -0300 Subject: [PATCH 01/11] feat: implement a new Mix's primitive component --- packages/mix/lib/mix.dart | 30 +- .../src/core/factory/style_widgets_ext.dart | 1 + .../mix/lib/src/specs/flex/flex_widget.dart | 98 +--- .../lib/src/specs/flexbox/flexbox_spec.dart | 111 +++++ .../lib/src/specs/flexbox/flexbox_spec.g.dart | 355 +++++++++++++++ .../lib/src/specs/flexbox/flexbox_widget.dart | 196 ++++++++ packages/mix/lib/src/specs/spec_util.dart | 4 + .../test/src/specs/flex/flex_widget_test.dart | 47 ++ .../specs/flexbox/flexbox_attribute_test.dart | 407 +++++++++++++++++ .../src/specs/flexbox/flexbox_spec_test.dart | 424 ++++++++++++++++++ .../src/specs/flexbox/flexbox_util_test.dart | 147 ++++++ .../specs/flexbox/flexbox_widget_test.dart | 262 +++++++++++ 12 files changed, 1970 insertions(+), 112 deletions(-) create mode 100644 packages/mix/lib/src/specs/flexbox/flexbox_spec.dart create mode 100644 packages/mix/lib/src/specs/flexbox/flexbox_spec.g.dart create mode 100644 packages/mix/lib/src/specs/flexbox/flexbox_widget.dart create mode 100644 packages/mix/test/src/specs/flexbox/flexbox_attribute_test.dart create mode 100644 packages/mix/test/src/specs/flexbox/flexbox_spec_test.dart create mode 100644 packages/mix/test/src/specs/flexbox/flexbox_util_test.dart create mode 100644 packages/mix/test/src/specs/flexbox/flexbox_widget_test.dart diff --git a/packages/mix/lib/mix.dart b/packages/mix/lib/mix.dart index 1fda7fcbb..ef70982e7 100644 --- a/packages/mix/lib/mix.dart +++ b/packages/mix/lib/mix.dart @@ -1,15 +1,15 @@ -/// /\\\\ /\\\\ /\\\\\\\\\\\ /\\\ /\\\ -/// \/\\\\\\ /\\\\\\ \/////\\\/// \///\\\ /\\\/ -/// \/\\\//\\\ /\\\//\\\ \/\\\ \///\\\\\\/ -/// \/\\\\///\\\/\\\/ \/\\\ \/\\\ \//\\\\ -/// \/\\\ \///\\\/ \/\\\ \/\\\ \/\\\\ -/// \/\\\ \/// \/\\\ \/\\\ /\\\\\\ -/// \/\\\ \/\\\ \/\\\ /\\\////\\\ -/// \/\\\ \/\\\ /\\\\\\\\\\\ /\\\/ \///\\\ -/// \/// \/// \/////////// \/// \/// -/// -/// https://fluttermix.com +/// /\\\\ /\\\\ /\\\\\\\\\\\ /\\\ /\\\ +/// \/\\\\\\ /\\\\\\ \/////\\\/// \///\\\ /\\\/ +/// \/\\\//\\\ /\\\//\\\ \/\\\ \///\\\\\\/ +/// \/\\\\///\\\/\\\/ \/\\\ \/\\\ \//\\\\ +/// \/\\\ \///\\\/ \/\\\ \/\\\ \/\\\\ +/// \/\\\ \/// \/\\\ \/\\\ /\\\\\\ +/// \/\\\ \/\\\ \/\\\ /\\\////\\\ +/// \/\\\ \/\\\ /\\\\\\\\\\\ /\\\/ \///\\\ +/// \/// \/// \/////////// \/// \/// /// +/// https://fluttermix.com +/// /// /\///////////////////////////////////////////////////\ /// \/\ ***** GENERATED CODE ***** \ \ /// \/\ ** DO NOT EDIT THIS FILE ** \ \ @@ -54,7 +54,6 @@ export 'src/attributes/strut_style/strut_style_dto.dart'; export 'src/attributes/text_height_behavior/text_height_behavior_dto.dart'; export 'src/attributes/text_style/text_style_dto.dart'; export 'src/attributes/text_style/text_style_util.dart'; - /// CORE export 'src/core/attribute.dart'; export 'src/core/attributes_map.dart'; @@ -72,7 +71,6 @@ export 'src/core/styled_widget.dart'; export 'src/core/utility.dart'; export 'src/core/variant.dart'; export 'src/core/widget_state/widget_state_controller.dart'; - /// MODIFIERS export 'src/modifiers/align_widget_modifier.dart'; export 'src/modifiers/aspect_ratio_widget_modifier.dart'; @@ -89,12 +87,13 @@ export 'src/modifiers/sized_box_widget_modifier.dart'; export 'src/modifiers/transform_widget_modifier.dart'; export 'src/modifiers/visibility_widget_modifier.dart'; export 'src/modifiers/widget_modifiers_util.dart'; - /// SPECS export 'src/specs/box/box_spec.dart'; export 'src/specs/box/box_widget.dart'; export 'src/specs/flex/flex_spec.dart'; export 'src/specs/flex/flex_widget.dart'; +export 'src/specs/flexbox/flexbox_spec.dart'; +export 'src/specs/flexbox/flexbox_widget.dart'; export 'src/specs/icon/icon_spec.dart'; export 'src/specs/icon/icon_widget.dart'; export 'src/specs/image/image_spec.dart'; @@ -105,7 +104,6 @@ export 'src/specs/stack/stack_widget.dart'; export 'src/specs/text/text_directives_util.dart'; export 'src/specs/text/text_spec.dart'; export 'src/specs/text/text_widget.dart'; - /// THEME export 'src/theme/material/material_theme.dart'; export 'src/theme/material/material_tokens.dart'; @@ -118,7 +116,6 @@ export 'src/theme/tokens/space_token.dart'; export 'src/theme/tokens/text_style_token.dart'; export 'src/theme/tokens/token_resolver.dart'; export 'src/theme/tokens/token_util.dart'; - /// VARIANTS export 'src/variants/context_variant.dart'; export 'src/variants/context_variant_util/on_breakpoint_util.dart'; @@ -130,6 +127,5 @@ export 'src/variants/context_variant_util/on_platform_util.dart'; export 'src/variants/context_variant_util/on_util.dart'; export 'src/variants/variant_attribute.dart'; export 'src/variants/widget_state_variant.dart'; - /// WIDGETS export 'src/widgets/pressable_widget.dart'; diff --git a/packages/mix/lib/src/core/factory/style_widgets_ext.dart b/packages/mix/lib/src/core/factory/style_widgets_ext.dart index 843c2a700..d4478b7f3 100644 --- a/packages/mix/lib/src/core/factory/style_widgets_ext.dart +++ b/packages/mix/lib/src/core/factory/style_widgets_ext.dart @@ -3,6 +3,7 @@ import 'package:flutter/widgets.dart'; import '../../specs/box/box_widget.dart'; import '../../specs/flex/flex_widget.dart'; +import '../../specs/flexbox/flexbox_widget.dart'; import '../../specs/icon/icon_widget.dart'; import '../../specs/text/text_widget.dart'; import 'style_mix.dart'; diff --git a/packages/mix/lib/src/specs/flex/flex_widget.dart b/packages/mix/lib/src/specs/flex/flex_widget.dart index a5ff1c2ff..b30a925de 100644 --- a/packages/mix/lib/src/specs/flex/flex_widget.dart +++ b/packages/mix/lib/src/specs/flex/flex_widget.dart @@ -4,7 +4,6 @@ import 'package:flutter/widgets.dart'; import '../../core/styled_widget.dart'; import '../../modifiers/internal/render_widget_modifier.dart'; -import '../box/box_spec.dart'; import 'flex_spec.dart'; /// A flexible layout widget enhanced with `Style` for simplified styling. @@ -88,8 +87,11 @@ class FlexSpecWidget extends StatelessWidget { mainAxisSize: spec?.mainAxisSize ?? _defaultFlex.mainAxisSize, crossAxisAlignment: spec?.crossAxisAlignment ?? _defaultFlex.crossAxisAlignment, + textDirection: spec?.textDirection ?? _defaultFlex.textDirection, verticalDirection: spec?.verticalDirection ?? _defaultFlex.verticalDirection, + textBaseline: spec?.textBaseline ?? _defaultFlex.textBaseline, + clipBehavior: spec?.clipBehavior ?? _defaultFlex.clipBehavior, children: _buildChildren(gap), ); @@ -200,98 +202,4 @@ class StyledColumn extends StyledFlex { }) : super(direction: Axis.vertical); } -/// A flex container widget with integrated `Style` for enhanced styling. -/// -/// `FlexBox` combines the features of `StyledContainer` and `StyledFlex`, offering -/// a powerful tool for creating flexible layouts with advanced styling capabilities -/// through `Style`. It's perfect for designing complex layouts that require both -/// container and flex properties with uniform styling. -/// -/// The `direction` parameter sets the layout's orientation, while the `Style` -/// integration simplifies the process of applying consistent styles to all elements. -/// -/// Example Usage: -/// ```dart -/// FlexBox( -/// direction: Axis.horizontal, -/// style: yourStyle, -/// children: [Widget1(), Widget2()], -/// ); -/// ``` -class FlexBox extends StyledWidget { - const FlexBox({ - super.style, - super.key, - super.inherit, - required this.direction, - required this.children, - super.orderOfModifiers = const [], - }); - - final List children; - final Axis direction; - - @override - Widget build(BuildContext context) { - return withMix(context, (mix) { - final boxSpec = BoxSpec.of(mix); - final flexSpec = FlexSpec.of(mix); - - return boxSpec( - orderOfModifiers: orderOfModifiers, - child: flexSpec(direction: direction, children: children), - ); - }); - } -} - -/// A horizontal flex container with `Style` for easy and consistent styling. -/// -/// `HBox` is a specialized `FlexBox` designed for horizontal layouts, simplifying -/// the process of applying horizontal alignment with advanced styling via `Style`. -/// It's an efficient way to achieve consistent styling in horizontal arrangements. -/// -/// Inherits all functionalities of `FlexBox`, optimized for horizontal layouts. -/// -/// Example Usage: -/// ```dart -/// HBox( -/// style: yourStyle, -/// children: [Widget1(), Widget2()], -/// ); -/// ``` -class HBox extends FlexBox { - const HBox({ - super.style, - super.key, - super.inherit, - super.children = const [], - }) : super(direction: Axis.horizontal); -} - -/// A vertical flex container that uses `Style` for streamlined styling. -/// -/// `VBox` is a vertical counterpart to `HBox`, utilizing `Style` for efficient -/// and consistent styling in vertical layouts. It offers an easy way to manage -/// vertical alignment and styling in a cohesive manner. -/// -/// Inherits the comprehensive styling and layout capabilities of `FlexBox`, tailored -/// for vertical orientations. -/// -/// Example Usage: -/// ```dart -/// VBox( -/// style: yourStyle, -/// children: [Widget1(), Widget2()], -/// ); -/// ``` -class VBox extends FlexBox { - const VBox({ - super.style, - super.key, - super.inherit, - super.children = const [], - }) : super(direction: Axis.vertical); -} - final _defaultFlex = Flex(direction: Axis.horizontal, children: const []); diff --git a/packages/mix/lib/src/specs/flexbox/flexbox_spec.dart b/packages/mix/lib/src/specs/flexbox/flexbox_spec.dart new file mode 100644 index 000000000..36c874ca8 --- /dev/null +++ b/packages/mix/lib/src/specs/flexbox/flexbox_spec.dart @@ -0,0 +1,111 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:mix_annotations/mix_annotations.dart'; + +import '../../attributes/animated/animated_data.dart'; +import '../../attributes/animated/animated_data_dto.dart'; +import '../../attributes/animated/animated_util.dart'; +import '../../attributes/modifiers/widget_modifiers_data.dart'; +import '../../attributes/modifiers/widget_modifiers_data_dto.dart'; +import '../../attributes/modifiers/widget_modifiers_util.dart'; +import '../../core/attribute.dart'; +import '../../core/factory/mix_data.dart'; +import '../../core/factory/mix_provider.dart'; +import '../../core/spec.dart'; +import '../box/box_spec.dart'; +import '../flex/flex_spec.dart'; +import 'flexbox_widget.dart'; + +part 'flexbox_spec.g.dart'; + +const _boxUtility = MixableUtility( + properties: [ + (path: 'alignment', alias: 'alignment'), + (path: 'padding', alias: 'padding'), + (path: 'margin', alias: 'margin'), + (path: 'constraints', alias: 'constraints'), + (path: 'constraints.minWidth', alias: 'minWidth'), + (path: 'constraints.maxWidth', alias: 'maxWidth'), + (path: 'constraints.minHeight', alias: 'minHeight'), + (path: 'constraints.maxHeight', alias: 'maxHeight'), + (path: 'decoration.color', alias: 'color'), + (path: 'decoration.border', alias: 'border'), + (path: 'decoration.border.directional', alias: 'borderDirectional'), + (path: 'decoration.borderRadius', alias: 'borderRadius'), + ( + path: 'decoration.borderRadius.directional', + alias: 'borderRadiusDirectional', + ), + (path: 'decoration.gradient', alias: 'gradient'), + (path: 'decoration.gradient.sweep', alias: 'sweepGradient'), + (path: 'decoration.gradient.radial', alias: 'radialGradient'), + (path: 'decoration.gradient.linear', alias: 'linearGradient'), + (path: 'decoration.boxShadows', alias: 'shadows'), + (path: 'decoration.boxShadow', alias: 'shadow'), + (path: 'decoration.elevation', alias: 'elevation'), + (path: 'shape', alias: 'shape'), + (path: 'foregroundDecoration', alias: 'foregroundDecoration'), + (path: 'transform', alias: 'transform'), + (path: 'transformAlignment', alias: 'transformAlignment'), + (path: 'clipBehavior', alias: 'clipBehavior'), + (path: 'width', alias: 'width'), + (path: 'height', alias: 'height'), + ], +); + +const _flexUtility = MixableUtility( + properties: [ + (path: 'direction', alias: 'direction'), + (path: 'mainAxisAlignment', alias: 'mainAxisAlignment'), + (path: 'crossAxisAlignment', alias: 'crossAxisAlignment'), + (path: 'mainAxisSize', alias: 'mainAxisSize'), + (path: 'verticalDirection', alias: 'verticalDirection'), + (path: 'textDirection', alias: 'textDirection'), + (path: 'textBaseline', alias: 'textBaseline'), + (path: 'gap', alias: 'gap'), + ], +); + +@MixableSpec() +final class FlexBoxSpec extends Spec + with _$FlexBoxSpec, Diagnosticable { + @MixableProperty(utilities: [_boxUtility]) + final BoxSpec box; + + @MixableProperty(utilities: [_flexUtility]) + final FlexSpec flex; + + static const of = _$FlexBoxSpec.of; + static const from = _$FlexBoxSpec.from; + + const FlexBoxSpec({ + super.animated, + super.modifiers, + BoxSpec? box, + FlexSpec? flex, + }) : box = box ?? const BoxSpec(), + flex = flex ?? const FlexSpec(); + + Widget call({List children = const [], required Axis direction}) { + return (isAnimated) + ? AnimatedFlexBoxSpecWidget( + spec: this, + direction: direction, + curve: animated!.curve, + duration: animated!.duration, + onEnd: animated!.onEnd, + children: children, + ) + : FlexBoxSpecWidget( + spec: this, + direction: direction, + children: children, + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + _debugFillProperties(properties); + } +} diff --git a/packages/mix/lib/src/specs/flexbox/flexbox_spec.g.dart b/packages/mix/lib/src/specs/flexbox/flexbox_spec.g.dart new file mode 100644 index 000000000..060a48bcf --- /dev/null +++ b/packages/mix/lib/src/specs/flexbox/flexbox_spec.g.dart @@ -0,0 +1,355 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'flexbox_spec.dart'; + +// ************************************************************************** +// MixableSpecGenerator +// ************************************************************************** + +mixin _$FlexBoxSpec on Spec { + static FlexBoxSpec from(MixData mix) { + return mix.attributeOf()?.resolve(mix) ?? + const FlexBoxSpec(); + } + + /// {@template flex_box_spec_of} + /// Retrieves the [FlexBoxSpec] from the nearest [Mix] ancestor in the widget tree. + /// + /// This method uses [Mix.of] to obtain the [Mix] instance associated with the + /// given [BuildContext], and then retrieves the [FlexBoxSpec] from that [Mix]. + /// If no ancestor [Mix] is found, this method returns an empty [FlexBoxSpec]. + /// + /// Example: + /// + /// ```dart + /// final flexBoxSpec = FlexBoxSpec.of(context); + /// ``` + /// {@endtemplate} + static FlexBoxSpec of(BuildContext context) { + return _$FlexBoxSpec.from(Mix.of(context)); + } + + /// Creates a copy of this [FlexBoxSpec] but with the given fields + /// replaced with the new values. + @override + FlexBoxSpec copyWith({ + AnimatedData? animated, + WidgetModifiersData? modifiers, + BoxSpec? box, + FlexSpec? flex, + }) { + return FlexBoxSpec( + animated: animated ?? _$this.animated, + modifiers: modifiers ?? _$this.modifiers, + box: box ?? _$this.box, + flex: flex ?? _$this.flex, + ); + } + + /// Linearly interpolates between this [FlexBoxSpec] and another [FlexBoxSpec] based on the given parameter [t]. + /// + /// The parameter [t] represents the interpolation factor, typically ranging from 0.0 to 1.0. + /// When [t] is 0.0, the current [FlexBoxSpec] is returned. When [t] is 1.0, the [other] [FlexBoxSpec] is returned. + /// For values of [t] between 0.0 and 1.0, an interpolated [FlexBoxSpec] is returned. + /// + /// If [other] is null, this method returns the current [FlexBoxSpec] instance. + /// + /// The interpolation is performed on each property of the [FlexBoxSpec] using the appropriate + /// interpolation method: + /// + + /// For [animated] and [modifiers] and [box] and [flex], the interpolation is performed using a step function. + /// If [t] is less than 0.5, the value from the current [FlexBoxSpec] is used. Otherwise, the value + /// from the [other] [FlexBoxSpec] is used. + /// + /// This method is typically used in animations to smoothly transition between + /// different [FlexBoxSpec] configurations. + @override + FlexBoxSpec lerp(FlexBoxSpec? other, double t) { + if (other == null) return _$this; + + return FlexBoxSpec( + animated: t < 0.5 ? _$this.animated : other.animated, + modifiers: other.modifiers, + box: _$this.box.lerp(other.box, t), + flex: _$this.flex.lerp(other.flex, t), + ); + } + + /// The list of properties that constitute the state of this [FlexBoxSpec]. + /// + /// This property is used by the [==] operator and the [hashCode] getter to + /// compare two [FlexBoxSpec] instances for equality. + @override + List get props => [ + _$this.animated, + _$this.modifiers, + _$this.box, + _$this.flex, + ]; + + FlexBoxSpec get _$this => this as FlexBoxSpec; + + void _debugFillProperties(DiagnosticPropertiesBuilder properties) { + properties.add( + DiagnosticsProperty('animated', _$this.animated, defaultValue: null)); + properties.add( + DiagnosticsProperty('modifiers', _$this.modifiers, defaultValue: null)); + properties.add(DiagnosticsProperty('box', _$this.box, defaultValue: null)); + properties + .add(DiagnosticsProperty('flex', _$this.flex, defaultValue: null)); + } +} + +/// Represents the attributes of a [FlexBoxSpec]. +/// +/// This class encapsulates properties defining the layout and +/// appearance of a [FlexBoxSpec]. +/// +/// Use this class to configure the attributes of a [FlexBoxSpec] and pass it to +/// the [FlexBoxSpec] constructor. +final class FlexBoxSpecAttribute extends SpecAttribute + with Diagnosticable { + final BoxSpecAttribute? box; + final FlexSpecAttribute? flex; + + const FlexBoxSpecAttribute({ + super.animated, + super.modifiers, + this.box, + this.flex, + }); + + /// Resolves to [FlexBoxSpec] using the provided [MixData]. + /// + /// If a property is null in the [MixData], it falls back to the + /// default value defined in the `defaultValue` for that property. + /// + /// ```dart + /// final flexBoxSpec = FlexBoxSpecAttribute(...).resolve(mix); + /// ``` + @override + FlexBoxSpec resolve(MixData mix) { + return FlexBoxSpec( + animated: animated?.resolve(mix) ?? mix.animation, + modifiers: modifiers?.resolve(mix), + box: box?.resolve(mix), + flex: flex?.resolve(mix), + ); + } + + /// Merges the properties of this [FlexBoxSpecAttribute] with the properties of [other]. + /// + /// If [other] is null, returns this instance unchanged. Otherwise, returns a new + /// [FlexBoxSpecAttribute] 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 + FlexBoxSpecAttribute merge(FlexBoxSpecAttribute? other) { + if (other == null) return this; + + return FlexBoxSpecAttribute( + animated: animated?.merge(other.animated) ?? other.animated, + modifiers: modifiers?.merge(other.modifiers) ?? other.modifiers, + box: box?.merge(other.box) ?? other.box, + flex: flex?.merge(other.flex) ?? other.flex, + ); + } + + /// The list of properties that constitute the state of this [FlexBoxSpecAttribute]. + /// + /// This property is used by the [==] operator and the [hashCode] getter to + /// compare two [FlexBoxSpecAttribute] instances for equality. + @override + List get props => [ + animated, + modifiers, + box, + flex, + ]; + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + .add(DiagnosticsProperty('animated', animated, defaultValue: null)); + properties + .add(DiagnosticsProperty('modifiers', modifiers, defaultValue: null)); + properties.add(DiagnosticsProperty('box', box, defaultValue: null)); + properties.add(DiagnosticsProperty('flex', flex, defaultValue: null)); + } +} + +/// Utility class for configuring [FlexBoxSpec] properties. +/// +/// This class provides methods to set individual properties of a [FlexBoxSpec]. +/// Use the methods of this class to configure specific properties of a [FlexBoxSpec]. +class FlexBoxSpecUtility + extends SpecUtility { + /// Utility for defining [FlexBoxSpecAttribute.animated] + late final animated = AnimatedUtility((v) => only(animated: v)); + + /// Utility for defining [FlexBoxSpecAttribute.modifiers] + late final wrap = SpecModifierUtility((v) => only(modifiers: v)); + + /// Utility for defining [FlexBoxSpecAttribute.box] + late final box = BoxSpecUtility((v) => only(box: v)); + + /// Utility for defining [FlexBoxSpecAttribute.box.alignment] + late final alignment = box.alignment; + + /// Utility for defining [FlexBoxSpecAttribute.box.padding] + late final padding = box.padding; + + /// Utility for defining [FlexBoxSpecAttribute.box.margin] + late final margin = box.margin; + + /// Utility for defining [FlexBoxSpecAttribute.box.constraints] + late final constraints = box.constraints; + + /// Utility for defining [FlexBoxSpecAttribute.box.constraints.minWidth] + late final minWidth = box.constraints.minWidth; + + /// Utility for defining [FlexBoxSpecAttribute.box.constraints.maxWidth] + late final maxWidth = box.constraints.maxWidth; + + /// Utility for defining [FlexBoxSpecAttribute.box.constraints.minHeight] + late final minHeight = box.constraints.minHeight; + + /// Utility for defining [FlexBoxSpecAttribute.box.constraints.maxHeight] + late final maxHeight = box.constraints.maxHeight; + + /// Utility for defining [FlexBoxSpecAttribute.box.decoration.color] + late final color = box.decoration.color; + + /// Utility for defining [FlexBoxSpecAttribute.box.decoration.border] + late final border = box.decoration.border; + + /// Utility for defining [FlexBoxSpecAttribute.box.decoration.border.directional] + late final borderDirectional = box.decoration.border.directional; + + /// Utility for defining [FlexBoxSpecAttribute.box.decoration.borderRadius] + late final borderRadius = box.decoration.borderRadius; + + /// Utility for defining [FlexBoxSpecAttribute.box.decoration.borderRadius.directional] + late final borderRadiusDirectional = box.decoration.borderRadius.directional; + + /// Utility for defining [FlexBoxSpecAttribute.box.decoration.gradient] + late final gradient = box.decoration.gradient; + + /// Utility for defining [FlexBoxSpecAttribute.box.decoration.gradient.sweep] + late final sweepGradient = box.decoration.gradient.sweep; + + /// Utility for defining [FlexBoxSpecAttribute.box.decoration.gradient.radial] + late final radialGradient = box.decoration.gradient.radial; + + /// Utility for defining [FlexBoxSpecAttribute.box.decoration.gradient.linear] + late final linearGradient = box.decoration.gradient.linear; + + /// Utility for defining [FlexBoxSpecAttribute.box.decoration.boxShadows] + late final shadows = box.decoration.boxShadows; + + /// Utility for defining [FlexBoxSpecAttribute.box.decoration.boxShadow] + late final shadow = box.decoration.boxShadow; + + /// Utility for defining [FlexBoxSpecAttribute.box.decoration.elevation] + late final elevation = box.decoration.elevation; + + /// Utility for defining [FlexBoxSpecAttribute.box.shape] + late final shape = box.shape; + + /// Utility for defining [FlexBoxSpecAttribute.box.foregroundDecoration] + late final foregroundDecoration = box.foregroundDecoration; + + /// Utility for defining [FlexBoxSpecAttribute.box.transform] + late final transform = box.transform; + + /// Utility for defining [FlexBoxSpecAttribute.box.transformAlignment] + late final transformAlignment = box.transformAlignment; + + /// Utility for defining [FlexBoxSpecAttribute.box.clipBehavior] + late final clipBehavior = box.clipBehavior; + + /// Utility for defining [FlexBoxSpecAttribute.box.width] + late final width = box.width; + + /// Utility for defining [FlexBoxSpecAttribute.box.height] + late final height = box.height; + + /// Utility for defining [FlexBoxSpecAttribute.flex] + late final flex = FlexSpecUtility((v) => only(flex: v)); + + /// Utility for defining [FlexBoxSpecAttribute.flex.direction] + late final direction = flex.direction; + + /// Utility for defining [FlexBoxSpecAttribute.flex.mainAxisAlignment] + late final mainAxisAlignment = flex.mainAxisAlignment; + + /// Utility for defining [FlexBoxSpecAttribute.flex.crossAxisAlignment] + late final crossAxisAlignment = flex.crossAxisAlignment; + + /// Utility for defining [FlexBoxSpecAttribute.flex.mainAxisSize] + late final mainAxisSize = flex.mainAxisSize; + + /// Utility for defining [FlexBoxSpecAttribute.flex.verticalDirection] + late final verticalDirection = flex.verticalDirection; + + /// Utility for defining [FlexBoxSpecAttribute.flex.textDirection] + late final textDirection = flex.textDirection; + + /// Utility for defining [FlexBoxSpecAttribute.flex.textBaseline] + late final textBaseline = flex.textBaseline; + + /// Utility for defining [FlexBoxSpecAttribute.flex.gap] + late final gap = flex.gap; + + FlexBoxSpecUtility(super.builder, {super.mutable}); + + FlexBoxSpecUtility get chain => + FlexBoxSpecUtility(attributeBuilder, mutable: true); + + static FlexBoxSpecUtility get self => + FlexBoxSpecUtility((v) => v); + + /// Returns a new [FlexBoxSpecAttribute] with the specified properties. + @override + T only({ + AnimatedDataDto? animated, + WidgetModifiersDataDto? modifiers, + BoxSpecAttribute? box, + FlexSpecAttribute? flex, + }) { + return builder(FlexBoxSpecAttribute( + animated: animated, + modifiers: modifiers, + box: box, + flex: flex, + )); + } +} + +/// A tween that interpolates between two [FlexBoxSpec] instances. +/// +/// This class can be used in animations to smoothly transition between +/// different [FlexBoxSpec] specifications. +class FlexBoxSpecTween extends Tween { + FlexBoxSpecTween({ + super.begin, + super.end, + }); + + @override + FlexBoxSpec lerp(double t) { + if (begin == null && end == null) { + return const FlexBoxSpec(); + } + + if (begin == null) { + return end!; + } + + return begin!.lerp(end!, t); + } +} diff --git a/packages/mix/lib/src/specs/flexbox/flexbox_widget.dart b/packages/mix/lib/src/specs/flexbox/flexbox_widget.dart new file mode 100644 index 000000000..22b6fb3e9 --- /dev/null +++ b/packages/mix/lib/src/specs/flexbox/flexbox_widget.dart @@ -0,0 +1,196 @@ +// ignore_for_file: prefer_const_constructors + +import 'package:flutter/widgets.dart'; + +import '../../core/factory/mix_provider.dart'; +import '../../core/styled_widget.dart'; +import '../../modifiers/internal/render_widget_modifier.dart'; +import '../box/box_spec.dart'; +import '../flex/flex_spec.dart'; +import 'flexbox_spec.dart'; + +/// A flex container widget with integrated `Style` for enhanced styling. +/// +/// `FlexBox` combines the features of `StyledContainer` and `StyledFlex`, offering +/// a powerful tool for creating flexible layouts with advanced styling capabilities +/// through `Style`. It's perfect for designing complex layouts that require both +/// container and flex properties with uniform styling. +/// +/// The `direction` parameter sets the layout's orientation, while the `Style` +/// integration simplifies the process of applying consistent styles to all elements. +/// +/// Example Usage: +/// ```dart +/// FlexBox( +/// direction: Axis.horizontal, +/// style: yourStyle, +/// children: [Widget1(), Widget2()], +/// ); +/// ``` +class FlexBox extends StyledWidget { + const FlexBox({ + super.style, + super.key, + super.inherit, + required this.direction, + required this.children, + super.orderOfModifiers = const [], + }); + + final List children; + final Axis direction; + + @override + Widget build(BuildContext context) { + // TODO: the support for FlexBoxSpec using BoxSpec and FlexSpec is a temporary + // solution to not break the existing API. it should be implemented using only + // FlexBoxSpec in the next major version. + return withMix(context, (context) { + final mixData = Mix.of(context); + + final spec = + mixData.attributeOf()?.resolve(mixData); + + final boxSpec = spec?.box ?? BoxSpec.of(context); + final flexSpec = spec?.flex ?? FlexSpec.of(context); + + final newSpec = FlexBoxSpec( + animated: spec?.animated, + modifiers: spec?.modifiers, + box: boxSpec, + flex: flexSpec, + ); + + return newSpec(direction: direction, children: children); + }); + } +} + +class FlexBoxSpecWidget extends StatelessWidget { + const FlexBoxSpecWidget({ + super.key, + this.spec, + required this.children, + required this.direction, + this.orderOfModifiers = const [], + }); + + final List children; + final Axis direction; + final FlexBoxSpec? spec; + final List orderOfModifiers; + + @override + Widget build(BuildContext context) { + final spec = this.spec ?? const FlexBoxSpec(); + + // TODO: Convert to a BoxSpecWidget and a FlexSpecWidget in the next major version. + // it should be implemented following the same pattern as the others SpecWidgets. + // This code must be like this to keep the existing animation API working. + return RenderSpecModifiers( + orderOfModifiers: orderOfModifiers, + spec: spec, + child: spec.box( + orderOfModifiers: orderOfModifiers, + child: spec.flex(direction: direction, children: children), + ), + ); + } +} + +class AnimatedFlexBoxSpecWidget extends ImplicitlyAnimatedWidget { + const AnimatedFlexBoxSpecWidget({ + super.key, + required this.spec, + required this.children, + required this.direction, + this.orderOfModifiers = const [], + super.curve, + required super.duration, + super.onEnd, + }); + + final FlexBoxSpec spec; + final List children; + final Axis direction; + final List orderOfModifiers; + + @override + AnimatedFlexBoxSpecWidgetState createState() => + AnimatedFlexBoxSpecWidgetState(); +} + +class AnimatedFlexBoxSpecWidgetState + extends AnimatedWidgetBaseState { + FlexBoxSpecTween? _specTween; + + @override + // ignore: avoid-dynamic + void forEachTween(TweenVisitor visitor) { + _specTween = visitor( + _specTween, + widget.spec, + // ignore: avoid-dynamic + (dynamic value) => FlexBoxSpecTween(begin: value as FlexBoxSpec), + ) as FlexBoxSpecTween?; + } + + @override + Widget build(BuildContext context) { + return FlexBoxSpecWidget( + spec: _specTween?.evaluate(animation), + direction: widget.direction, + orderOfModifiers: widget.orderOfModifiers, + children: widget.children, + ); + } +} + +/// A horizontal flex container with `Style` for easy and consistent styling. +/// +/// `HBox` is a specialized `FlexBox` designed for horizontal layouts, simplifying +/// the process of applying horizontal alignment with advanced styling via `Style`. +/// It's an efficient way to achieve consistent styling in horizontal arrangements. +/// +/// Inherits all functionalities of `FlexBox`, optimized for horizontal layouts. +/// +/// Example Usage: +/// ```dart +/// HBox( +/// style: yourStyle, +/// children: [Widget1(), Widget2()], +/// ); +/// ``` +class HBox extends FlexBox { + const HBox({ + super.style, + super.key, + super.inherit, + super.children = const [], + }) : super(direction: Axis.horizontal); +} + +/// A vertical flex container that uses `Style` for streamlined styling. +/// +/// `VBox` is a vertical counterpart to `HBox`, utilizing `Style` for efficient +/// and consistent styling in vertical layouts. It offers an easy way to manage +/// vertical alignment and styling in a cohesive manner. +/// +/// Inherits the comprehensive styling and layout capabilities of `FlexBox`, tailored +/// for vertical orientations. +/// +/// Example Usage: +/// ```dart +/// VBox( +/// style: yourStyle, +/// children: [Widget1(), Widget2()], +/// ); +/// ``` +class VBox extends FlexBox { + const VBox({ + super.style, + super.key, + super.inherit, + super.children = const [], + }) : super(direction: Axis.vertical); +} diff --git a/packages/mix/lib/src/specs/spec_util.dart b/packages/mix/lib/src/specs/spec_util.dart index 600ba0d82..2f5938790 100644 --- a/packages/mix/lib/src/specs/spec_util.dart +++ b/packages/mix/lib/src/specs/spec_util.dart @@ -3,6 +3,7 @@ import '../modifiers/widget_modifiers_util.dart'; import '../variants/context_variant_util/on_util.dart'; import 'box/box_spec.dart'; import 'flex/flex_spec.dart'; +import 'flexbox/flexbox_spec.dart'; import 'icon/icon_spec.dart'; import 'image/image_spec.dart'; import 'stack/stack_spec.dart'; @@ -11,6 +12,7 @@ import 'text/text_spec.dart'; const _mixUtility = MixUtilities(); BoxSpecUtility get $box => _mixUtility.box; +FlexBoxSpecUtility get $flexbox => _mixUtility.flexbox; FlexSpecUtility get $flex => _mixUtility.flex; ImageSpecUtility get $image => _mixUtility.image; IconSpecUtility get $icon => _mixUtility.icon; @@ -23,6 +25,8 @@ class MixUtilities { const MixUtilities(); BoxSpecUtility get box => BoxSpecUtility.self; FlexSpecUtility get flex => FlexSpecUtility.self; + FlexBoxSpecUtility get flexbox => + FlexBoxSpecUtility.self; ImageSpecUtility get image => ImageSpecUtility.self; IconSpecUtility get icon => IconSpecUtility.self; TextSpecUtility get text => TextSpecUtility.self; diff --git a/packages/mix/test/src/specs/flex/flex_widget_test.dart b/packages/mix/test/src/specs/flex/flex_widget_test.dart index 7d136f94b..a6e962e1b 100644 --- a/packages/mix/test/src/specs/flex/flex_widget_test.dart +++ b/packages/mix/test/src/specs/flex/flex_widget_test.dart @@ -6,6 +6,53 @@ import '../../../helpers/override_modifiers_order.dart'; import '../../../helpers/testing_utils.dart'; void main() { + testWidgets('FlexSpec properties should match Flex properties', + (WidgetTester tester) async { + const flexSpec = FlexSpec( + direction: Axis.horizontal, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + verticalDirection: VerticalDirection.down, + textDirection: TextDirection.ltr, + textBaseline: TextBaseline.alphabetic, + clipBehavior: Clip.antiAlias, + gap: 16, + ); + + const flexKey = Key('flex'); + const flexWidget = FlexSpecWidget( + key: flexKey, + spec: flexSpec, + direction: Axis.horizontal, + children: [Text('test')], + ); + + await tester.pumpWidget( + const MaterialApp( + home: Scaffold( + body: flexWidget, + ), + ), + ); + + final flexFinder = find.byKey(flexKey); + expect(flexFinder, findsOneWidget); + + final flex = tester.widget(find.descendant( + of: flexFinder, + matching: find.byType(Flex), + )); + + expect(flex.direction, flexSpec.direction); + expect(flex.mainAxisAlignment, flexSpec.mainAxisAlignment); + expect(flex.crossAxisAlignment, flexSpec.crossAxisAlignment); + expect(flex.mainAxisSize, flexSpec.mainAxisSize); + expect(flex.verticalDirection, flexSpec.verticalDirection); + expect(flex.textDirection, flexSpec.textDirection); + expect(flex.textBaseline, flexSpec.textBaseline); + }); + group('FlexSpecWidget', () { testWidgets('prioritizes the direction in spec', (tester) async { await tester.pumpMaterialApp( diff --git a/packages/mix/test/src/specs/flexbox/flexbox_attribute_test.dart b/packages/mix/test/src/specs/flexbox/flexbox_attribute_test.dart new file mode 100644 index 000000000..49ec6e5db --- /dev/null +++ b/packages/mix/test/src/specs/flexbox/flexbox_attribute_test.dart @@ -0,0 +1,407 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../../helpers/testing_utils.dart'; + +void main() { + group('FlexBoxSpecAttribute', () { + test('Constructor assigns correct properties', () { + final flexBoxSpecAttribute = FlexBoxSpecAttribute( + box: BoxSpecAttribute( + alignment: Alignment.center, + padding: SpacingDto.only(top: 20, bottom: 20, left: 20, right: 20), + margin: SpacingDto.only( + top: 10, + bottom: 10, + left: 10, + right: 10, + ), + constraints: const BoxConstraintsDto(maxHeight: 100), + decoration: const BoxDecorationDto(color: ColorDto(Colors.blue)), + transform: Matrix4.identity(), + clipBehavior: Clip.antiAlias, + width: 100, + height: 100, + modifiers: const WidgetModifiersDataDto([ + OpacityModifierSpecAttribute(opacity: 0.5), + SizedBoxModifierSpecAttribute(height: 10, width: 10), + ]), + ), + flex: const FlexSpecAttribute( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + verticalDirection: VerticalDirection.down, + textDirection: TextDirection.ltr, + textBaseline: TextBaseline.alphabetic, + ), + ); + + expect(flexBoxSpecAttribute.box!.alignment, Alignment.center); + expect(flexBoxSpecAttribute.box!.clipBehavior, Clip.antiAlias); + + expect( + flexBoxSpecAttribute.box!.constraints, + const BoxConstraintsDto(maxHeight: 100), + ); + expect( + flexBoxSpecAttribute.box!.decoration, + const BoxDecorationDto(color: ColorDto(Colors.blue)), + ); + + expect(flexBoxSpecAttribute.box!.height, 100); + expect( + flexBoxSpecAttribute.box!.margin, + SpacingDto.only(top: 10, bottom: 10, left: 10, right: 10), + ); + expect( + flexBoxSpecAttribute.box!.padding, + SpacingDto.only(top: 20, bottom: 20, left: 20, right: 20), + ); + expect(flexBoxSpecAttribute.box!.transform, Matrix4.identity()); + expect(flexBoxSpecAttribute.box!.width, 100); + expect( + flexBoxSpecAttribute.box!.modifiers, + const WidgetModifiersDataDto([ + OpacityModifierSpecAttribute(opacity: 0.5), + SizedBoxModifierSpecAttribute(height: 10, width: 10), + ])); + + expect(flexBoxSpecAttribute.flex!.mainAxisAlignment, + MainAxisAlignment.center); + expect(flexBoxSpecAttribute.flex!.crossAxisAlignment, + CrossAxisAlignment.center); + expect(flexBoxSpecAttribute.flex!.mainAxisSize, MainAxisSize.max); + expect( + flexBoxSpecAttribute.flex!.verticalDirection, VerticalDirection.down); + expect(flexBoxSpecAttribute.flex!.textDirection, TextDirection.ltr); + expect(flexBoxSpecAttribute.flex!.textBaseline, TextBaseline.alphabetic); + }); + + // resolve() + test('resolve() returns correct instance', () { + final flexBoxSpecAttribute = FlexBoxSpecAttribute( + box: BoxSpecAttribute( + alignment: Alignment.center, + padding: SpacingDto.only(top: 20, bottom: 20, left: 20, right: 20), + margin: SpacingDto.only( + top: 10, + bottom: 10, + left: 10, + right: 10, + ), + constraints: const BoxConstraintsDto(maxHeight: 100), + decoration: const BoxDecorationDto(color: ColorDto(Colors.blue)), + transform: Matrix4.identity(), + clipBehavior: Clip.antiAlias, + width: 100, + height: 100, + modifiers: const WidgetModifiersDataDto([ + OpacityModifierSpecAttribute(opacity: 0.5), + SizedBoxModifierSpecAttribute(height: 10, width: 10), + ]), + ), + flex: const FlexSpecAttribute( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + verticalDirection: VerticalDirection.down, + textDirection: TextDirection.ltr, + textBaseline: TextBaseline.alphabetic, + ), + ); + + final flexBoxSpec = flexBoxSpecAttribute.resolve(EmptyMixData); + + expect(flexBoxSpec.box.alignment, Alignment.center); + expect(flexBoxSpec.box.clipBehavior, Clip.antiAlias); + + expect( + flexBoxSpec.box.constraints, + const BoxConstraints(maxWidth: double.infinity, maxHeight: 100), + ); + expect( + flexBoxSpec.box.decoration, const BoxDecoration(color: Colors.blue)); + + expect(flexBoxSpec.box.height, 100); + expect( + flexBoxSpec.box.margin, + const EdgeInsets.only(left: 10, top: 10, right: 10, bottom: 10), + ); + expect( + flexBoxSpec.box.padding, + const EdgeInsets.only(left: 20, top: 20, right: 20, bottom: 20), + ); + expect(flexBoxSpec.box.transform, Matrix4.identity()); + expect(flexBoxSpec.box.width, 100); + expect(flexBoxSpec.box.modifiers!.value, [ + const OpacityModifierSpec(0.5), + const SizedBoxModifierSpec(height: 10, width: 10), + ]); + + expect(flexBoxSpec.flex.mainAxisAlignment, MainAxisAlignment.center); + expect(flexBoxSpec.flex.crossAxisAlignment, CrossAxisAlignment.center); + expect(flexBoxSpec.flex.mainAxisSize, MainAxisSize.max); + expect(flexBoxSpec.flex.verticalDirection, VerticalDirection.down); + expect(flexBoxSpec.flex.textDirection, TextDirection.ltr); + expect(flexBoxSpec.flex.textBaseline, TextBaseline.alphabetic); + }); + + // merge() + test('merge() returns correct instance', () { + final flexBoxSpecAttribute = FlexBoxSpecAttribute( + box: BoxSpecAttribute( + alignment: Alignment.center, + padding: SpacingDto.only(top: 20, bottom: 20, left: 20, right: 20), + margin: SpacingDto.only( + top: 10, + bottom: 10, + left: 10, + right: 10, + ), + constraints: const BoxConstraintsDto(maxHeight: 100), + decoration: const BoxDecorationDto(color: ColorDto(Colors.blue)), + transform: Matrix4.identity(), + clipBehavior: Clip.antiAlias, + width: 100, + height: 100, + modifiers: const WidgetModifiersDataDto([ + OpacityModifierSpecAttribute(opacity: 0.5), + SizedBoxModifierSpecAttribute(height: 10, width: 10), + ]), + ), + flex: const FlexSpecAttribute( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + verticalDirection: VerticalDirection.down, + textDirection: TextDirection.ltr, + textBaseline: TextBaseline.alphabetic, + ), + ); + + final mergedFlexBoxSpecAttribute = flexBoxSpecAttribute.merge( + FlexBoxSpecAttribute( + box: BoxSpecAttribute( + alignment: Alignment.centerLeft, + padding: SpacingDto.only(top: 30, bottom: 30, left: 30, right: 30), + margin: SpacingDto.only( + top: 20, + bottom: 20, + left: 20, + right: 20, + ), + constraints: const BoxConstraintsDto(maxHeight: 200), + decoration: const BoxDecorationDto(color: ColorDto(Colors.red)), + transform: Matrix4.identity(), + clipBehavior: Clip.antiAliasWithSaveLayer, + width: 200, + height: 200, + modifiers: const WidgetModifiersDataDto([ + SizedBoxModifierSpecAttribute(width: 20), + ]), + ), + flex: const FlexSpecAttribute( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + verticalDirection: VerticalDirection.up, + textDirection: TextDirection.rtl, + textBaseline: TextBaseline.ideographic, + ), + ), + ); + + expect(mergedFlexBoxSpecAttribute.box!.alignment, Alignment.centerLeft); + expect(mergedFlexBoxSpecAttribute.box!.clipBehavior, + Clip.antiAliasWithSaveLayer); + + expect( + mergedFlexBoxSpecAttribute.box!.constraints, + const BoxConstraintsDto(maxHeight: 200), + ); + expect( + mergedFlexBoxSpecAttribute.box!.decoration, + const BoxDecorationDto(color: ColorDto(Colors.red)), + ); + + expect(mergedFlexBoxSpecAttribute.box!.height, 200); + expect( + mergedFlexBoxSpecAttribute.box!.margin, + SpacingDto.only(top: 20, bottom: 20, left: 20, right: 20), + ); + expect( + mergedFlexBoxSpecAttribute.box!.padding, + SpacingDto.only(top: 30, bottom: 30, left: 30, right: 30), + ); + expect(mergedFlexBoxSpecAttribute.box!.transform, Matrix4.identity()); + expect(mergedFlexBoxSpecAttribute.box!.width, 200); + expect( + mergedFlexBoxSpecAttribute.box!.modifiers, + const WidgetModifiersDataDto([ + OpacityModifierSpecAttribute(opacity: 0.5), + SizedBoxModifierSpecAttribute(height: 10, width: 20), + ])); + + expect(mergedFlexBoxSpecAttribute.flex!.mainAxisAlignment, + MainAxisAlignment.start); + expect(mergedFlexBoxSpecAttribute.flex!.crossAxisAlignment, + CrossAxisAlignment.start); + expect(mergedFlexBoxSpecAttribute.flex!.mainAxisSize, MainAxisSize.min); + expect(mergedFlexBoxSpecAttribute.flex!.verticalDirection, + VerticalDirection.up); + expect(mergedFlexBoxSpecAttribute.flex!.textDirection, TextDirection.rtl); + expect(mergedFlexBoxSpecAttribute.flex!.textBaseline, + TextBaseline.ideographic); + }); + + // equality + test('equality', () { + final flexBoxSpecAttribute = FlexBoxSpecAttribute( + box: BoxSpecAttribute( + alignment: Alignment.center, + padding: SpacingDto.only(top: 20, bottom: 20, left: 20, right: 20), + margin: SpacingDto.only( + top: 10, + bottom: 10, + left: 10, + right: 10, + ), + constraints: const BoxConstraintsDto(maxHeight: 100), + decoration: const BoxDecorationDto(color: ColorDto(Colors.blue)), + transform: Matrix4.identity(), + clipBehavior: Clip.antiAlias, + width: 100, + height: 100, + modifiers: const WidgetModifiersDataDto([ + OpacityModifierSpecAttribute(opacity: 0.5), + SizedBoxModifierSpecAttribute(height: 10, width: 10), + ]), + ), + flex: const FlexSpecAttribute( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + verticalDirection: VerticalDirection.down, + textDirection: TextDirection.ltr, + textBaseline: TextBaseline.alphabetic, + ), + ); + + expect( + flexBoxSpecAttribute, + equals( + FlexBoxSpecAttribute( + box: BoxSpecAttribute( + alignment: Alignment.center, + padding: + SpacingDto.only(top: 20, bottom: 20, left: 20, right: 20), + margin: SpacingDto.only( + top: 10, + bottom: 10, + left: 10, + right: 10, + ), + constraints: const BoxConstraintsDto(maxHeight: 100), + decoration: const BoxDecorationDto(color: ColorDto(Colors.blue)), + transform: Matrix4.identity(), + clipBehavior: Clip.antiAlias, + width: 100, + height: 100, + modifiers: const WidgetModifiersDataDto( + [ + OpacityModifierSpecAttribute(opacity: 0.5), + SizedBoxModifierSpecAttribute(height: 10, width: 10), + ], + ), + ), + flex: const FlexSpecAttribute( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + verticalDirection: VerticalDirection.down, + textDirection: TextDirection.ltr, + textBaseline: TextBaseline.alphabetic, + ), + ), + ), + ); + }); + + // not equals + test('not equals', () { + final flexBoxSpecAttribute = FlexBoxSpecAttribute( + box: BoxSpecAttribute( + alignment: Alignment.center, + padding: SpacingDto.only(top: 20, bottom: 20, left: 20, right: 20), + margin: SpacingDto.only( + top: 10, + bottom: 10, + left: 10, + right: 10, + ), + constraints: const BoxConstraintsDto(maxHeight: 100), + decoration: const BoxDecorationDto(color: ColorDto(Colors.blue)), + transform: Matrix4.identity(), + clipBehavior: Clip.antiAlias, + width: 100, + height: 100, + ), + flex: const FlexSpecAttribute( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + verticalDirection: VerticalDirection.down, + textDirection: TextDirection.ltr, + textBaseline: TextBaseline.alphabetic, + ), + ); + + expect( + flexBoxSpecAttribute, + isNot( + equals( + FlexBoxSpecAttribute( + box: BoxSpecAttribute( + alignment: Alignment.centerLeft, + padding: SpacingDto.only( + top: 30, + bottom: 30, + left: 30, + right: 30, + ), + margin: SpacingDto.only( + top: 20, + bottom: 20, + left: 20, + right: 20, + ), + constraints: const BoxConstraintsDto(maxHeight: 200), + decoration: const BoxDecorationDto(color: ColorDto(Colors.red)), + transform: Matrix4.identity(), + clipBehavior: Clip.antiAliasWithSaveLayer, + width: 200, + height: 200, + modifiers: const WidgetModifiersDataDto( + [ + OpacityModifierSpecAttribute(opacity: 0.4), + SizedBoxModifierSpecAttribute(height: 20, width: 10), + ], + ), + ), + flex: const FlexSpecAttribute( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + verticalDirection: VerticalDirection.up, + textDirection: TextDirection.rtl, + textBaseline: TextBaseline.ideographic, + ), + ), + ), + ), + ); + }); + }); +} diff --git a/packages/mix/test/src/specs/flexbox/flexbox_spec_test.dart b/packages/mix/test/src/specs/flexbox/flexbox_spec_test.dart new file mode 100644 index 000000000..6ce9d9449 --- /dev/null +++ b/packages/mix/test/src/specs/flexbox/flexbox_spec_test.dart @@ -0,0 +1,424 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../../helpers/testing_utils.dart'; + +void main() { + group('FlexBoxSpec', () { + test('resolve', () { + final mix = MixData.create( + MockBuildContext(), + Style( + FlexBoxSpecAttribute( + box: BoxSpecAttribute( + alignment: Alignment.center, + padding: SpacingDto.only(top: 8, bottom: 16), + margin: SpacingDto.only(top: 10.0, bottom: 12.0), + constraints: + const BoxConstraintsDto(maxWidth: 300.0, minHeight: 200.0), + decoration: const BoxDecorationDto(color: ColorDto(Colors.blue)), + transform: Matrix4.translationValues(10.0, 10.0, 0.0), + clipBehavior: Clip.antiAlias, + width: 300, + height: 200, + ), + flex: const FlexSpecAttribute( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + verticalDirection: VerticalDirection.down, + textDirection: TextDirection.ltr, + textBaseline: TextBaseline.alphabetic, + ), + ), + ), + ); + + final spec = mix.attributeOf()!.resolve(mix); + + expect(spec.box.alignment, Alignment.center); + expect(spec.box.padding, const EdgeInsets.only(top: 8.0, bottom: 16.0)); + expect(spec.box.margin, const EdgeInsets.only(top: 10.0, bottom: 12.0)); + expect( + spec.box.constraints, + const BoxConstraints(maxWidth: 300.0, minHeight: 200.0), + ); + expect(spec.box.decoration, const BoxDecoration(color: Colors.blue)); + expect(spec.box.transform, Matrix4.translationValues(10.0, 10.0, 0.0)); + expect(spec.box.clipBehavior, Clip.antiAlias); + expect(spec.box.width, 300); + expect(spec.box.height, 200); + + expect(spec.flex.mainAxisAlignment, MainAxisAlignment.center); + expect(spec.flex.crossAxisAlignment, CrossAxisAlignment.center); + expect(spec.flex.mainAxisSize, MainAxisSize.max); + expect(spec.flex.verticalDirection, VerticalDirection.down); + expect(spec.flex.textDirection, TextDirection.ltr); + expect(spec.flex.textBaseline, TextBaseline.alphabetic); + }); + + test('copyWith', () { + final spec = FlexBoxSpec( + box: BoxSpec( + alignment: Alignment.center, + padding: const EdgeInsets.all(16.0), + margin: const EdgeInsets.only(top: 8.0, bottom: 8.0), + constraints: const BoxConstraints(maxWidth: 300.0, minHeight: 200.0), + decoration: const BoxDecoration(color: Colors.blue), + transform: Matrix4.translationValues(10.0, 10.0, 0.0), + clipBehavior: Clip.antiAlias, + width: 300, + height: 200, + ), + flex: const FlexSpec( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + verticalDirection: VerticalDirection.down, + textDirection: TextDirection.ltr, + textBaseline: TextBaseline.alphabetic, + ), + ); + + final copiedSpec = spec.copyWith( + box: spec.box.copyWith( + width: 250.0, + height: 150.0, + ), + flex: spec.flex.copyWith( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + ), + ); + + expect(copiedSpec.box.alignment, Alignment.center); + expect(copiedSpec.box.padding, const EdgeInsets.all(16.0)); + expect( + copiedSpec.box.margin, const EdgeInsets.only(top: 8.0, bottom: 8.0)); + expect(copiedSpec.box.width, 250.0); + expect(copiedSpec.box.height, 150.0); + + expect(copiedSpec.flex.mainAxisAlignment, MainAxisAlignment.start); + expect(copiedSpec.flex.crossAxisAlignment, CrossAxisAlignment.start); + expect(copiedSpec.flex.mainAxisSize, MainAxisSize.max); + expect(copiedSpec.flex.verticalDirection, VerticalDirection.down); + expect(copiedSpec.flex.textDirection, TextDirection.ltr); + expect(copiedSpec.flex.textBaseline, TextBaseline.alphabetic); + }); + + test('lerp', () { + final spec1 = FlexBoxSpec( + box: BoxSpec( + alignment: Alignment.topLeft, + padding: const EdgeInsets.all(8.0), + margin: const EdgeInsets.only(top: 4.0), + constraints: const BoxConstraints(maxWidth: 200.0), + decoration: const BoxDecoration(color: Colors.red), + transform: Matrix4.identity(), + clipBehavior: Clip.none, + width: 300, + height: 200, + ), + flex: const FlexSpec( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + ), + ); + + final spec2 = FlexBoxSpec( + box: BoxSpec( + alignment: Alignment.bottomRight, + padding: const EdgeInsets.all(16.0), + margin: const EdgeInsets.only(top: 8.0), + constraints: const BoxConstraints(maxWidth: 400.0), + decoration: const BoxDecoration(color: Colors.blue), + transform: Matrix4.rotationZ(0.5), + clipBehavior: Clip.antiAlias, + width: 400, + height: 300, + ), + flex: const FlexSpec( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.max, + ), + ); + + const t = 0.5; + final lerpedSpec = spec1.lerp(spec2, t); + + expect( + lerpedSpec.box.alignment, + Alignment.lerp(Alignment.topLeft, Alignment.bottomRight, t), + ); + expect( + lerpedSpec.box.padding, + EdgeInsets.lerp( + const EdgeInsets.all(8.0), + const EdgeInsets.all(16.0), + t, + ), + ); + expect(lerpedSpec.box.width, lerpDouble(300, 400, t)); + expect(lerpedSpec.box.height, lerpDouble(200, 300, t)); + + expect(lerpedSpec.flex.mainAxisAlignment, MainAxisAlignment.end); + expect(lerpedSpec.flex.crossAxisAlignment, CrossAxisAlignment.end); + expect(lerpedSpec.flex.mainAxisSize, MainAxisSize.max); + }); + + test('equality', () { + final spec1 = FlexBoxSpec( + box: BoxSpec( + alignment: Alignment.topLeft, + padding: const EdgeInsets.all(8.0), + margin: const EdgeInsets.only(top: 4.0), + constraints: const BoxConstraints(maxWidth: 200.0), + decoration: const BoxDecoration(color: Colors.red), + transform: Matrix4.identity(), + clipBehavior: Clip.none, + width: 300, + height: 200, + ), + flex: const FlexSpec( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + ), + ); + + final spec2 = FlexBoxSpec( + box: BoxSpec( + alignment: Alignment.topLeft, + padding: const EdgeInsets.all(8.0), + margin: const EdgeInsets.only(top: 4.0), + constraints: const BoxConstraints(maxWidth: 200.0), + decoration: const BoxDecoration(color: Colors.red), + transform: Matrix4.identity(), + clipBehavior: Clip.none, + width: 300, + height: 200, + ), + flex: const FlexSpec( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + ), + ); + + expect(spec1, spec2); + }); + + test('merge() returns correct instance', () { + final flexBoxSpecAttribute = FlexBoxSpecAttribute( + box: BoxSpecAttribute( + alignment: Alignment.center, + padding: SpacingDto.only(top: 20, bottom: 20, left: 20, right: 20), + margin: SpacingDto.only( + top: 10, + bottom: 10, + left: 10, + right: 10, + ), + constraints: const BoxConstraintsDto(maxHeight: 100), + decoration: const BoxDecorationDto(color: ColorDto(Colors.blue)), + transform: Matrix4.identity(), + clipBehavior: Clip.antiAlias, + width: 100, + height: 100, + ), + flex: const FlexSpecAttribute( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + verticalDirection: VerticalDirection.down, + textDirection: TextDirection.ltr, + textBaseline: TextBaseline.alphabetic, + ), + ); + + final mergedFlexBoxSpecAttribute = flexBoxSpecAttribute.merge( + FlexBoxSpecAttribute( + box: BoxSpecAttribute( + alignment: Alignment.centerLeft, + padding: SpacingDto.only(top: 30, bottom: 30, left: 30, right: 30), + margin: SpacingDto.only( + top: 20, + bottom: 20, + left: 20, + right: 20, + ), + constraints: const BoxConstraintsDto(maxHeight: 200), + decoration: const BoxDecorationDto(color: ColorDto(Colors.red)), + transform: Matrix4.identity(), + clipBehavior: Clip.antiAliasWithSaveLayer, + width: 200, + height: 200, + ), + flex: const FlexSpecAttribute( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + verticalDirection: VerticalDirection.up, + textDirection: TextDirection.rtl, + textBaseline: TextBaseline.ideographic, + ), + ), + ); + + expect(mergedFlexBoxSpecAttribute.box!.alignment, Alignment.centerLeft); + expect(mergedFlexBoxSpecAttribute.box!.clipBehavior, + Clip.antiAliasWithSaveLayer); + expect(mergedFlexBoxSpecAttribute.box!.constraints, + const BoxConstraintsDto(maxHeight: 200)); + expect(mergedFlexBoxSpecAttribute.box!.decoration, + const BoxDecorationDto(color: ColorDto(Colors.red))); + expect(mergedFlexBoxSpecAttribute.box!.height, 200); + expect( + mergedFlexBoxSpecAttribute.box!.margin, + SpacingDto.only(top: 20, bottom: 20, left: 20, right: 20), + ); + expect( + mergedFlexBoxSpecAttribute.box!.padding, + SpacingDto.only(top: 30, bottom: 30, left: 30, right: 30), + ); + expect(mergedFlexBoxSpecAttribute.box!.transform, Matrix4.identity()); + expect(mergedFlexBoxSpecAttribute.box!.width, 200); + + expect(mergedFlexBoxSpecAttribute.flex!.mainAxisAlignment, + MainAxisAlignment.start); + expect(mergedFlexBoxSpecAttribute.flex!.crossAxisAlignment, + CrossAxisAlignment.start); + expect(mergedFlexBoxSpecAttribute.flex!.mainAxisSize, MainAxisSize.min); + expect(mergedFlexBoxSpecAttribute.flex!.verticalDirection, + VerticalDirection.up); + expect(mergedFlexBoxSpecAttribute.flex!.textDirection, TextDirection.rtl); + expect(mergedFlexBoxSpecAttribute.flex!.textBaseline, + TextBaseline.ideographic); + }); + }); + + group('FlexBoxSpecUtility fluent', () { + test('fluent behavior', () { + final flexBox = FlexBoxSpecUtility.self; + + final util = flexBox.chain + ..box.alignment.center() + ..box.padding(8) + ..flex.mainAxisAlignment.center() + ..flex.crossAxisAlignment.center(); + + final attr = util.attributeValue!; + + expect(util, isA()); + expect(attr.box!.alignment, Alignment.center); + expect(attr.box!.padding, const EdgeInsets.all(8.0).toDto()); + expect(attr.box!.margin, null); + expect(attr.flex!.mainAxisAlignment, MainAxisAlignment.center); + expect(attr.flex!.crossAxisAlignment, CrossAxisAlignment.center); + + final style = Style(util); + + final flexBoxAttribute = + style.styles.attributeOfType(); + + expect(flexBoxAttribute?.box!.alignment, Alignment.center); + expect(flexBoxAttribute?.box!.padding, const EdgeInsets.all(8.0).toDto()); + expect(flexBoxAttribute?.box!.margin, null); + expect( + flexBoxAttribute?.flex!.mainAxisAlignment, MainAxisAlignment.center); + expect(flexBoxAttribute?.flex!.crossAxisAlignment, + CrossAxisAlignment.center); + + final mixData = style.of(MockBuildContext()); + final flexBoxSpec = FlexBoxSpec.from(mixData); + + expect(flexBoxSpec.box.alignment, Alignment.center); + expect(flexBoxSpec.box.padding, const EdgeInsets.all(8.0)); + expect(flexBoxSpec.box.margin, null); + expect(flexBoxSpec.flex.mainAxisAlignment, MainAxisAlignment.center); + expect(flexBoxSpec.flex.crossAxisAlignment, CrossAxisAlignment.center); + }); + + test('Immutable behavior when having multiple flexboxes', () { + final flexBoxUtil = FlexBoxSpecUtility.self; + final flexBox1 = flexBoxUtil.chain + ..box.padding(10) + ..flex.mainAxisAlignment.start(); + final flexBox2 = flexBoxUtil.chain + ..box.padding(20) + ..flex.mainAxisAlignment.end(); + + final attr1 = flexBox1.attributeValue!; + final attr2 = flexBox2.attributeValue!; + + expect(attr1.box!.padding, const EdgeInsets.all(10.0).toDto()); + expect(attr2.box!.padding, const EdgeInsets.all(20.0).toDto()); + expect(attr1.flex!.mainAxisAlignment, MainAxisAlignment.start); + expect(attr2.flex!.mainAxisAlignment, MainAxisAlignment.end); + + final style1 = Style(flexBox1); + final style2 = Style(flexBox2); + + final flexBoxAttribute1 = + style1.styles.attributeOfType(); + final flexBoxAttribute2 = + style2.styles.attributeOfType(); + + expect( + flexBoxAttribute1?.box!.padding, const EdgeInsets.all(10.0).toDto()); + expect( + flexBoxAttribute2?.box!.padding, const EdgeInsets.all(20.0).toDto()); + expect( + flexBoxAttribute1?.flex!.mainAxisAlignment, MainAxisAlignment.start); + expect(flexBoxAttribute2?.flex!.mainAxisAlignment, MainAxisAlignment.end); + + final mixData1 = style1.of(MockBuildContext()); + final mixData2 = style2.of(MockBuildContext()); + + final flexBoxSpec1 = FlexBoxSpec.from(mixData1); + final flexBoxSpec2 = FlexBoxSpec.from(mixData2); + + expect(flexBoxSpec1.box.padding, const EdgeInsets.all(10.0)); + expect(flexBoxSpec2.box.padding, const EdgeInsets.all(20.0)); + expect(flexBoxSpec1.flex.mainAxisAlignment, MainAxisAlignment.start); + expect(flexBoxSpec2.flex.mainAxisAlignment, MainAxisAlignment.end); + }); + + test('Mutate behavior and not on same utility', () { + final flexBox = FlexBoxSpecUtility.self; + + final flexBoxValue = flexBox.chain; + flexBoxValue + ..box.padding(10) + ..box.color.red() + ..box.alignment.center() + ..flex.mainAxisAlignment.center() + ..flex.crossAxisAlignment.center(); + + final flexBoxAttribute = flexBoxValue.attributeValue!; + final flexBoxAttribute2 = flexBox.box.padding(20); + + expect(flexBoxAttribute.box!.padding, const EdgeInsets.all(10.0).toDto()); + expect( + (flexBoxAttribute.box!.decoration as BoxDecorationDto).color, + const ColorDto(Colors.red), + ); + expect(flexBoxAttribute.box!.alignment, Alignment.center); + expect( + flexBoxAttribute.flex!.mainAxisAlignment, MainAxisAlignment.center); + expect( + flexBoxAttribute.flex!.crossAxisAlignment, CrossAxisAlignment.center); + + expect( + flexBoxAttribute2.box!.padding, const EdgeInsets.all(20.0).toDto()); + expect((flexBoxAttribute2.box!.decoration as BoxDecorationDto?)?.color, + isNull); + expect(flexBoxAttribute2.box!.alignment, isNull); + }); + }); +} diff --git a/packages/mix/test/src/specs/flexbox/flexbox_util_test.dart b/packages/mix/test/src/specs/flexbox/flexbox_util_test.dart new file mode 100644 index 000000000..6f04bb1a5 --- /dev/null +++ b/packages/mix/test/src/specs/flexbox/flexbox_util_test.dart @@ -0,0 +1,147 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +const $testvariant = Variant('test'); +void main() { + group('FlexBoxUtility', () { + final flexBoxUtility = FlexBoxSpecUtility.self; + + test('call() returns correct instance', () { + final flexBox = flexBoxUtility.chain + ..box.alignment.center() + ..box.padding(10) + ..box.margin(10) + ..box.constraints.maxWidth(200) + ..box.width(10) + ..box.height(10) + ..box.transform(Matrix4.identity()) + ..box.clipBehavior.antiAlias() + ..flex.mainAxisAlignment.center() + ..flex.crossAxisAlignment.center(); + + final attr = flexBox.attributeValue!; + + expect(attr.box!.alignment, Alignment.center); + expect(attr.box!.clipBehavior, Clip.antiAlias); + expect(attr.box!.constraints!.maxWidth, 200); + expect(attr.box!.height, 10); + expect(attr.box!.margin, const EdgeInsets.all(10).toDto()); + expect(attr.box!.padding, const EdgeInsets.all(10).toDto()); + expect(attr.box!.transform, Matrix4.identity()); + expect(attr.box!.width, 10); + expect(attr.flex!.mainAxisAlignment, MainAxisAlignment.center); + expect(attr.flex!.crossAxisAlignment, CrossAxisAlignment.center); + }); + + test('box alignment returns correct instance', () { + final flexBox = flexBoxUtility.chain..box.alignment.center(); + expect(flexBox.attributeValue!.box!.alignment, Alignment.center); + }); + + test('box clipBehavior returns correct instance', () { + final flexBox = flexBoxUtility.chain..box.clipBehavior.antiAlias(); + expect(flexBox.attributeValue!.box!.clipBehavior, Clip.antiAlias); + }); + + test('box color returns correct instance', () { + final flexBox = flexBoxUtility.chain..box.color.blue(); + expect( + (flexBox.attributeValue!.box!.decoration as BoxDecorationDto).color, + const ColorDto(Colors.blue), + ); + }); + + test('box constraints returns correct instance', () { + expect(flexBoxUtility.box.constraints, isA()); + }); + + test('box shape returns correct instance', () { + expect(flexBoxUtility.box.shapeDecoration, isA()); + }); + + test('box height returns correct instance', () { + final flexBox = flexBoxUtility.chain..box.height(10); + expect(flexBox.attributeValue!.box!.height, 10); + }); + + test('box margin returns correct instance', () { + expect(flexBoxUtility.box.margin, isA()); + }); + + test('box padding returns correct instance', () { + expect(flexBoxUtility.box.padding, isA()); + }); + + test('box transform returns correct instance', () { + final flexBox = flexBoxUtility.chain..box.transform(Matrix4.identity()); + expect(flexBox.attributeValue!.box!.transform, Matrix4.identity()); + }); + + test('box width returns correct instance', () { + final flexBox = flexBoxUtility.chain..box.width(10); + expect(flexBox.attributeValue!.box!.width, 10); + }); + + test('box decoration returns correct instance', () { + final flexBox = flexBoxUtility.chain + ..box.decoration( + borderRadius: BorderRadius.circular(10), + color: Colors.amber, + ); + + final decoration = + flexBox.attributeValue!.box!.decoration as BoxDecorationDto; + expect(decoration.color, const ColorDto(Colors.amber)); + expect( + decoration.borderRadius, + BorderRadius.circular(10).toDto(), + ); + }); + + test('box foregroundDecoration returns correct instance', () { + final flexBox = flexBoxUtility.chain + ..box.foregroundDecoration( + borderRadius: BorderRadius.circular(10), + color: Colors.amber, + ); + + final foregroundDecoration = + flexBox.attributeValue!.box!.foregroundDecoration as BoxDecorationDto; + expect( + foregroundDecoration.color, + const ColorDto(Colors.amber), + reason: 'The color is not correct', + ); + expect( + foregroundDecoration.borderRadius, + BorderRadius.circular(10).toDto(), + reason: 'The BorderRadius is not correct', + ); + }); + + test('flex properties return correct instances', () { + final flexBox = flexBoxUtility.chain + ..flex.mainAxisAlignment.center() + ..flex.crossAxisAlignment.center() + ..flex.mainAxisSize.min() + ..flex.direction.horizontal() + ..flex.verticalDirection.down() + ..flex.textDirection.ltr() + ..flex.textBaseline.alphabetic() + ..flex.clipBehavior.antiAlias() + ..flex.gap(10); + + final attr = flexBox.attributeValue!.flex!; + expect(attr.mainAxisAlignment, MainAxisAlignment.center); + expect(attr.crossAxisAlignment, CrossAxisAlignment.center); + expect(attr.mainAxisSize, MainAxisSize.min); + expect(attr.direction, Axis.horizontal); + expect(attr.verticalDirection, VerticalDirection.down); + expect(attr.textDirection, TextDirection.ltr); + expect(attr.textBaseline, TextBaseline.alphabetic); + expect(attr.clipBehavior, Clip.antiAlias); + expect(attr.gap!.value, 10); + }); + }); +} diff --git a/packages/mix/test/src/specs/flexbox/flexbox_widget_test.dart b/packages/mix/test/src/specs/flexbox/flexbox_widget_test.dart new file mode 100644 index 000000000..dd629ab5f --- /dev/null +++ b/packages/mix/test/src/specs/flexbox/flexbox_widget_test.dart @@ -0,0 +1,262 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../../helpers/override_modifiers_order.dart'; +import '../../../helpers/testing_utils.dart'; + +void main() { + testWidgets('FlexBox', (WidgetTester tester) async { + final paddingAttr = $box.padding(10); + final marginAttr = $box.margin(15); + final alignmentAttr = $box.alignment.center(); + final clipAttr = $box.clipBehavior.hardEdge(); + final mainAxisAttr = $flex.mainAxisAlignment.center(); + final crossAxisAttr = $flex.crossAxisAlignment.center(); + + final boxDecorationAttr = $box.decoration( + border: Border.all(color: Colors.red, width: 1, style: BorderStyle.solid), + borderRadius: BorderRadius.circular(10), + color: Colors.red, + ); + + await tester.pumpStyledWidget( + FlexBox( + style: Style( + paddingAttr, + marginAttr, + alignmentAttr, + clipAttr, + boxDecorationAttr, + mainAxisAttr, + crossAxisAttr, + ), + direction: Axis.horizontal, + children: const [], + ), + ); + + final flexFinder = find.byType(Flex); + final containerFinder = find.byType(Container); + final flexWidget = tester.widget(flexFinder); + final containerWidget = tester.widget(containerFinder); + + expect(containerWidget.padding, const EdgeInsets.all(10)); + expect(containerWidget.margin, const EdgeInsets.all(15)); + expect(containerWidget.alignment, Alignment.center); + expect(containerWidget.clipBehavior, Clip.hardEdge); + expect( + containerWidget.decoration, + BoxDecoration( + color: Colors.red, + border: + Border.all(color: Colors.red, width: 1, style: BorderStyle.solid), + borderRadius: BorderRadius.circular(10), + ), + ); + expect(flexWidget.mainAxisAlignment, MainAxisAlignment.center); + expect(flexWidget.crossAxisAlignment, CrossAxisAlignment.center); + }); + + testWidgets( + 'FlexBox should apply modifiers only once', + (tester) async { + await tester.pumpMaterialApp( + FlexBox( + style: Style( + $box.height(100), + $box.width(100), + $with.align(), + ), + direction: Axis.horizontal, + children: const [ + FlexBox( + direction: Axis.horizontal, + children: [], + ), + ], + ), + ); + + expect(find.byType(Align), findsOneWidget); + }, + ); + + testWidgets('FlexBox handles onEnd', (WidgetTester tester) async { + var countPressTime = 0; + var countOnEnd = 0; + + await tester.pumpWidget( + MaterialApp( + home: PressableBox( + onPress: () { + countPressTime++; + }, + child: FlexBox( + style: Style( + $flexbox.height(50), + $flexbox.width(50), + $flexbox.wrap.transform.scale(1), + $on.press( + $flexbox.wrap.transform.scale(1.5), + ), + ).animate( + onEnd: () { + print('onEnd'); + countOnEnd++; + }, + ), + direction: Axis.horizontal, + children: const [Box()], + ), + ), + ), + ); + + final pressableFinder = find.byType(Pressable); + await tester.tap(pressableFinder); + + await tester.pumpAndSettle(); + + expect(countPressTime, 1); + expect(countOnEnd, 1); + }); + + testWidgets('FlexBox handles onEnd #2', (WidgetTester tester) async { + var countPressTime = 0; + var countOnEnd = 0; + + await tester.pumpWidget( + MaterialApp( + home: PressableBox( + onPress: () { + countPressTime++; + }, + child: FlexBox( + style: Style( + $box.height(50), + $box.width(50), + $box.wrap.transform.scale(1), + $on.press( + $box.wrap.transform.scale(1.5), + ), + ).animate( + onEnd: () { + print('onEnd'); + countOnEnd++; + }, + ), + direction: Axis.horizontal, + children: const [Box()], + ), + ), + ), + ); + + final pressableFinder = find.byType(Pressable); + await tester.tap(pressableFinder); + + await tester.pumpAndSettle(); + + expect(countPressTime, 1); + expect(countOnEnd, 1); + }); + + testWidgets( + 'FlexBoxSpec properties should match Flex and Container properties', + (WidgetTester tester) async { + final flexBoxSpec = FlexBoxSpec( + box: BoxSpec( + alignment: Alignment.center, + padding: const EdgeInsets.all(16), + margin: const EdgeInsets.symmetric(horizontal: 8), + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.circular(10), + ), + foregroundDecoration: BoxDecoration( + border: Border.all(color: Colors.red, width: 2), + ), + transform: Matrix4.rotationZ(0.1), + transformAlignment: Alignment.topLeft, + clipBehavior: Clip.antiAlias, + width: 150, + height: 100, + ), + flex: const FlexSpec( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + direction: Axis.horizontal, + verticalDirection: VerticalDirection.down, + textDirection: TextDirection.ltr, + textBaseline: TextBaseline.alphabetic, + ), + ); + + const flexBoxKey = Key('flexbox'); + final flexBox = FlexBoxSpecWidget( + key: flexBoxKey, + spec: flexBoxSpec, + direction: Axis.horizontal, + children: const [], + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: flexBox, + ), + ), + ); + + final flexBoxFinder = find.byKey(flexBoxKey); + expect(flexBoxFinder, findsOneWidget); + + final containerWidget = tester.widget(find.descendant( + of: flexBoxFinder, + matching: find.byType(Container), + )); + + final flexWidget = tester.widget(find.descendant( + of: flexBoxFinder, + matching: find.byType(Flex), + )); + + expect(containerWidget.alignment, flexBoxSpec.box.alignment); + expect(containerWidget.padding, flexBoxSpec.box.padding); + expect(containerWidget.margin, flexBoxSpec.box.margin); + expect(containerWidget.decoration, flexBoxSpec.box.decoration); + expect(containerWidget.foregroundDecoration, + flexBoxSpec.box.foregroundDecoration); + expect(containerWidget.transform, flexBoxSpec.box.transform); + expect( + containerWidget.transformAlignment, flexBoxSpec.box.transformAlignment); + expect(containerWidget.clipBehavior, flexBoxSpec.box.clipBehavior); + + expect(flexWidget.mainAxisAlignment, flexBoxSpec.flex.mainAxisAlignment); + expect(flexWidget.crossAxisAlignment, flexBoxSpec.flex.crossAxisAlignment); + expect(flexWidget.mainAxisSize, flexBoxSpec.flex.mainAxisSize); + expect(flexWidget.direction, flexBoxSpec.flex.direction); + expect(flexWidget.verticalDirection, flexBoxSpec.flex.verticalDirection); + expect(flexWidget.textDirection, flexBoxSpec.flex.textDirection); + expect(flexWidget.textBaseline, flexBoxSpec.flex.textBaseline); + }); + + testWidgets( + 'Renders modifiers in the correct order with many overrides', + (tester) async { + testOverrideModifiersOrder( + tester, + widgetBuilder: (style, orderOfModifiers) { + return FlexBox( + style: style, + orderOfModifiers: orderOfModifiers, + direction: Axis.horizontal, + children: const [], + ); + }, + ); + }, + ); +} From ac9dfd8c1eefb79c9cc089b4a5f6d2c21d0724db Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Mon, 11 Nov 2024 21:37:24 -0300 Subject: [PATCH 02/11] Update main.dart --- packages/mix/example/lib/main.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mix/example/lib/main.dart b/packages/mix/example/lib/main.dart index d9e2c59d7..406dce46c 100644 --- a/packages/mix/example/lib/main.dart +++ b/packages/mix/example/lib/main.dart @@ -19,8 +19,8 @@ final style = Style( $box.margin(10), $box.border( color: Colors.black, - width: 1, style: BorderStyle.solid, + width: 1, ), ); From a4f04f60e655b611478e8eb0dbff992f4c5669c7 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Mon, 11 Nov 2024 21:57:34 -0300 Subject: [PATCH 03/11] lint --- packages/mix/lib/src/theme/tokens/breakpoints_token.dart | 2 +- packages/mix/lib/src/theme/tokens/color_token.dart | 2 +- packages/remix/lib/src/app/remix_app.dart | 2 +- .../lib/src/components/checkbox/checkbox_widget.dart | 2 +- packages/remix/lib/src/theme/remix_theme.dart | 8 ++++---- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/mix/lib/src/theme/tokens/breakpoints_token.dart b/packages/mix/lib/src/theme/tokens/breakpoints_token.dart index dcad98970..22ea3d456 100644 --- a/packages/mix/lib/src/theme/tokens/breakpoints_token.dart +++ b/packages/mix/lib/src/theme/tokens/breakpoints_token.dart @@ -73,7 +73,7 @@ class BreakpointToken extends MixToken { return themeValue is BreakpointResolver ? themeValue.resolve(context) - : themeValue ?? const Breakpoint(); + : (themeValue ?? const Breakpoint()); } } diff --git a/packages/mix/lib/src/theme/tokens/color_token.dart b/packages/mix/lib/src/theme/tokens/color_token.dart index f2724083e..18a424d5b 100644 --- a/packages/mix/lib/src/theme/tokens/color_token.dart +++ b/packages/mix/lib/src/theme/tokens/color_token.dart @@ -32,7 +32,7 @@ class ColorToken extends MixToken { return themeValue is ColorResolver ? themeValue.resolve(context) - : themeValue ?? Colors.transparent; + : (themeValue ?? Colors.transparent); } } diff --git a/packages/remix/lib/src/app/remix_app.dart b/packages/remix/lib/src/app/remix_app.dart index b25f7c2ef..0f52184da 100644 --- a/packages/remix/lib/src/app/remix_app.dart +++ b/packages/remix/lib/src/app/remix_app.dart @@ -129,7 +129,7 @@ class _RemixAppState extends State { return widget.builder!(context, child); }, ) - : child ?? const SizedBox.shrink(), + : (child ?? const SizedBox.shrink()), ); } diff --git a/packages/remix/lib/src/components/checkbox/checkbox_widget.dart b/packages/remix/lib/src/components/checkbox/checkbox_widget.dart index a1500ef68..ebe41b1c0 100644 --- a/packages/remix/lib/src/components/checkbox/checkbox_widget.dart +++ b/packages/remix/lib/src/components/checkbox/checkbox_widget.dart @@ -89,7 +89,7 @@ class _CheckboxState extends State { child: IconWidget( widget.value ? widget.iconChecked - : widget.iconUnchecked ?? widget.iconChecked, + : (widget.iconUnchecked ?? widget.iconChecked), ), ), if (widget.label != null) spec.label(widget.label!), diff --git a/packages/remix/lib/src/theme/remix_theme.dart b/packages/remix/lib/src/theme/remix_theme.dart index e9622a6ba..3384b8941 100644 --- a/packages/remix/lib/src/theme/remix_theme.dart +++ b/packages/remix/lib/src/theme/remix_theme.dart @@ -293,16 +293,16 @@ class RemixTheme extends StatelessWidget { RemixThemeData _defineRemixThemeData(BuildContext context) { if (themeMode != null) { return themeMode == ThemeMode.dark - ? darkTheme ?? _defaultThemeDark - : theme ?? _defaultThemeLight; + ? (darkTheme ?? _defaultThemeDark) + : (theme ?? _defaultThemeLight); } final brightness = MediaQuery.platformBrightnessOf(context); final isDark = brightness == Brightness.dark; return isDark - ? darkTheme ?? _defaultThemeDark - : theme ?? _defaultThemeLight; + ? (darkTheme ?? _defaultThemeDark) + : (theme ?? _defaultThemeLight); } @override From 3d37800c55cd6bf25ff82e89a54a6af780958037 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Mon, 11 Nov 2024 22:00:09 -0300 Subject: [PATCH 04/11] Update rule_config.dart --- packages/mix_lint/lib/src/utils/rule_config.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mix_lint/lib/src/utils/rule_config.dart b/packages/mix_lint/lib/src/utils/rule_config.dart index 982e876c4..c04e5f14d 100644 --- a/packages/mix_lint/lib/src/utils/rule_config.dart +++ b/packages/mix_lint/lib/src/utils/rule_config.dart @@ -6,7 +6,7 @@ typedef RuleParameterParser = T Function(Map json); typedef RuleProblemFactory = String Function(T value); -class RuleConfig { +class RuleConfig { final String name; final ErrorSeverity errorSeverity; final String? correctionMessage; From a4334040d083c7b52289ae90ed9be4b891cba8c2 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Thu, 14 Nov 2024 11:55:27 -0300 Subject: [PATCH 05/11] lint fixes --- melos.yaml | 4 +- packages/mix/example/lib/main.dart | 25 ++++------ .../src/core/factory/style_widgets_ext.dart | 2 +- packages/mix/lib/src/core/styled_widget.dart | 6 +-- .../internal/gesture_mix_state.dart | 2 +- .../internal/render_widget_modifier.dart | 8 ++-- .../scroll_view_widget_modifier.dart | 2 +- .../modifiers/visibility_widget_modifier.dart | 2 +- packages/mix/lib/src/specs/box/box_spec.dart | 4 +- .../mix/lib/src/specs/box/box_widget.dart | 4 +- .../mix/lib/src/specs/flex/flex_spec.dart | 4 +- .../mix/lib/src/specs/flex/flex_widget.dart | 6 +-- .../lib/src/specs/flexbox/flexbox_spec.dart | 4 +- .../lib/src/specs/flexbox/flexbox_widget.dart | 8 ++-- .../mix/lib/src/specs/icon/icon_widget.dart | 2 +- .../mix/lib/src/specs/image/image_widget.dart | 2 +- .../mix/lib/src/specs/stack/stack_spec.dart | 2 +- .../mix/lib/src/specs/stack/stack_widget.dart | 4 +- .../mix/lib/src/specs/text/text_widget.dart | 2 +- .../mix/lib/src/widgets/pressable_widget.dart | 42 ++++++++-------- ...ining_tokens_or_variants_within_style.dart | 4 +- packages/remix/lib/src/app/remix_app.dart | 2 +- .../accordion/accordion_widget.dart | 6 +-- .../header/accordion_header_spec_widget.dart | 2 +- .../src/components/button/button_widget.dart | 6 +-- .../components/callout/callout_widget.dart | 2 +- .../components/checkbox/checkbox_widget.dart | 8 ++-- .../lib/src/components/chip/chip_widget.dart | 10 ++-- .../src/components/dialog/dialog_widget.dart | 4 +- .../icon_button/icon_button_widget.dart | 4 +- .../menu_item/menu_item_widget.dart | 8 ++-- .../src/components/radio/radio_widget.dart | 8 ++-- .../segmented_control_button_widget.dart | 2 +- .../segmented_control_widget.dart | 4 +- .../select/button/select_button_widget.dart | 2 +- .../select/item/select_menu_widget.dart | 2 +- .../src/components/select/select_widget.dart | 14 +++--- .../src/components/slider/slider_widget.dart | 48 +++++++++---------- .../src/components/switch/switch_widget.dart | 6 +-- .../textfield/textfield_widget.dart | 10 ++-- .../lib/src/components/toast/toast_layer.dart | 4 +- .../src/components/toast/toast_widget.dart | 4 +- packages/remix/lib/src/theme/remix_theme.dart | 2 +- 43 files changed, 145 insertions(+), 152 deletions(-) diff --git a/melos.yaml b/melos.yaml index 23d5690b3..6926ab284 100644 --- a/melos.yaml +++ b/melos.yaml @@ -30,11 +30,11 @@ scripts: failFast: true analyze:dart: - run: melos exec -c 10 -- dart analyze . + run: melos exec -c 4 -- dart analyze . description: Run Dart static analysis checks. analyze:dcm: - run: melos exec -c 10 -- dcm analyze . --fatal-style --fatal-performance --fatal-warnings + run: melos exec -c 4 -- dcm analyze . --fatal-style --fatal-performance --fatal-warnings description: Run DCM static analysis checks. packageFilters: dependsOn: "dart_code_metrics_presets" diff --git a/packages/mix/example/lib/main.dart b/packages/mix/example/lib/main.dart index 406dce46c..d3f9f813b 100644 --- a/packages/mix/example/lib/main.dart +++ b/packages/mix/example/lib/main.dart @@ -1,12 +1,8 @@ import 'package:flutter/material.dart'; import 'package:mix/mix.dart'; -void main() async { - runApp( - const MaterialApp( - home: MyApp(), - ), - ); +void main() { + runApp(const MaterialApp(home: MyApp())); } final style = Style( @@ -17,11 +13,7 @@ final style = Style( $box.borderRadius(10), $box.padding(20, 10), $box.margin(10), - $box.border( - color: Colors.black, - style: BorderStyle.solid, - width: 1, - ), + $box.border(color: Colors.black, style: BorderStyle.solid, width: 1), ); class MyApp extends StatelessWidget { @@ -30,11 +22,12 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - body: Center( - child: Box( - style: style, - child: const Center(child: Text('Hello Mix')), + body: Center( + child: Box( + style: style, + child: const Center(child: Text('Hello Mix')), + ), ), - )); + ); } } diff --git a/packages/mix/lib/src/core/factory/style_widgets_ext.dart b/packages/mix/lib/src/core/factory/style_widgets_ext.dart index d4478b7f3..939be5adb 100644 --- a/packages/mix/lib/src/core/factory/style_widgets_ext.dart +++ b/packages/mix/lib/src/core/factory/style_widgets_ext.dart @@ -29,7 +29,7 @@ extension StyleExt on Style { Key? key, Style? style, }) { - return container(inherit: inherit, key: key, style: style, child: child); + return container(child: child, inherit: inherit, key: key, style: style); } HBox hbox({ diff --git a/packages/mix/lib/src/core/styled_widget.dart b/packages/mix/lib/src/core/styled_widget.dart index a3626566e..2a41f2e25 100644 --- a/packages/mix/lib/src/core/styled_widget.dart +++ b/packages/mix/lib/src/core/styled_widget.dart @@ -105,17 +105,17 @@ class SpecBuilder extends StatelessWidget { return mix.isAnimated ? RenderAnimatedModifiers( modifiers: modifiers, + child: child, duration: mix.animation!.duration, mix: mix, orderOfModifiers: orderOfModifiers, curve: mix.animation!.curve, - child: child, ) : RenderModifiers( + child: child, modifiers: modifiers, mix: mix, orderOfModifiers: orderOfModifiers, - child: child, ); } @@ -143,7 +143,7 @@ class SpecBuilder extends StatelessWidget { _hasWidgetStateVariant && MixWidgetState.of(context) == null; if (needsWidgetState || controller != null) { - current = Interactable(controller: controller, child: current); + current = Interactable(child: current, controller: controller); } // Otherwise, directly build the mixed child widget diff --git a/packages/mix/lib/src/core/widget_state/internal/gesture_mix_state.dart b/packages/mix/lib/src/core/widget_state/internal/gesture_mix_state.dart index 21f1673e9..018eccc50 100644 --- a/packages/mix/lib/src/core/widget_state/internal/gesture_mix_state.dart +++ b/packages/mix/lib/src/core/widget_state/internal/gesture_mix_state.dart @@ -189,6 +189,7 @@ class _GestureMixStateWidgetState extends State { @override Widget build(BuildContext context) { return GestureDetector( + child: widget.child, onTapUp: widget.onTap != null ? _onTapUp : null, onTap: widget.onTap != null ? _onTap : null, onTapCancel: widget.onTap != null ? _onTapCancel : null, @@ -203,7 +204,6 @@ class _GestureMixStateWidgetState extends State { onPanCancel: widget.onPanCancel != null ? _onPanCancel : null, behavior: widget.hitTestBehavior, excludeFromSemantics: widget.excludeFromSemantics, - child: widget.child, ); } } diff --git a/packages/mix/lib/src/modifiers/internal/render_widget_modifier.dart b/packages/mix/lib/src/modifiers/internal/render_widget_modifier.dart index a18024c13..8808e656a 100644 --- a/packages/mix/lib/src/modifiers/internal/render_widget_modifier.dart +++ b/packages/mix/lib/src/modifiers/internal/render_widget_modifier.dart @@ -105,8 +105,8 @@ class RenderModifiers extends StatelessWidget { @override Widget build(BuildContext context) { return _RenderModifiers( - modifiers: combineModifiers(mix, modifiers, orderOfModifiers).reversed, child: child, + modifiers: combineModifiers(mix, modifiers, orderOfModifiers).reversed, ); } } @@ -160,10 +160,10 @@ class RenderAnimatedModifiers extends StatelessWidget { orderOfModifiers, defaultOrder: MixTheme.maybeOf(context)?.defaultOrderOfModifiers, ).reversed.toList(), + child: child, duration: duration, curve: curve, onEnd: onEnd, - child: child, ); } } @@ -275,15 +275,15 @@ class RenderSpecModifiers extends StatelessWidget { return spec.isAnimated ? RenderAnimatedModifiers( modifiers: modifiers, + child: child, duration: spec.animated!.duration, orderOfModifiers: orderOfModifiers, curve: spec.animated!.curve, - child: child, ) : RenderModifiers( + child: child, modifiers: modifiers, orderOfModifiers: orderOfModifiers, - child: child, ); } } diff --git a/packages/mix/lib/src/modifiers/scroll_view_widget_modifier.dart b/packages/mix/lib/src/modifiers/scroll_view_widget_modifier.dart index 624f642b9..31192fe53 100644 --- a/packages/mix/lib/src/modifiers/scroll_view_widget_modifier.dart +++ b/packages/mix/lib/src/modifiers/scroll_view_widget_modifier.dart @@ -43,8 +43,8 @@ final class ScrollViewModifierSpec reverse: reverse ?? false, padding: padding, physics: physics, - clipBehavior: clipBehavior ?? Clip.hardEdge, child: child, + clipBehavior: clipBehavior ?? Clip.hardEdge, ); } } diff --git a/packages/mix/lib/src/modifiers/visibility_widget_modifier.dart b/packages/mix/lib/src/modifiers/visibility_widget_modifier.dart index b195d113f..6baa69419 100644 --- a/packages/mix/lib/src/modifiers/visibility_widget_modifier.dart +++ b/packages/mix/lib/src/modifiers/visibility_widget_modifier.dart @@ -26,7 +26,7 @@ final class VisibilityModifierSpec @override Widget build(Widget child) { - return Visibility(visible: visible, child: child); + return Visibility(child: child, visible: visible); } } diff --git a/packages/mix/lib/src/specs/box/box_spec.dart b/packages/mix/lib/src/specs/box/box_spec.dart index 63529c0ad..d842cd1ad 100644 --- a/packages/mix/lib/src/specs/box/box_spec.dart +++ b/packages/mix/lib/src/specs/box/box_spec.dart @@ -123,16 +123,16 @@ final class BoxSpec extends Spec with _$BoxSpec, Diagnosticable { return isAnimated ? AnimatedBoxSpecWidget( spec: this, + child: child, duration: animated!.duration, curve: animated!.curve, onEnd: animated?.onEnd, orderOfModifiers: orderOfModifiers, - child: child, ) : BoxSpecWidget( spec: this, - orderOfModifiers: orderOfModifiers, child: child, + orderOfModifiers: orderOfModifiers, ); } diff --git a/packages/mix/lib/src/specs/box/box_widget.dart b/packages/mix/lib/src/specs/box/box_widget.dart index d5e8ab6f9..7d99f43d1 100644 --- a/packages/mix/lib/src/specs/box/box_widget.dart +++ b/packages/mix/lib/src/specs/box/box_widget.dart @@ -75,7 +75,6 @@ class BoxSpecWidget extends StatelessWidget { Widget build(BuildContext context) { return RenderSpecModifiers( orderOfModifiers: orderOfModifiers, - spec: spec ?? const BoxSpec(), child: Container( alignment: spec?.alignment, padding: spec?.padding, @@ -87,9 +86,10 @@ class BoxSpecWidget extends StatelessWidget { margin: spec?.margin, transform: spec?.transform, transformAlignment: spec?.transformAlignment, - clipBehavior: spec?.clipBehavior ?? Clip.none, child: child, + clipBehavior: spec?.clipBehavior ?? Clip.none, ), + spec: spec ?? const BoxSpec(), ); } } diff --git a/packages/mix/lib/src/specs/flex/flex_spec.dart b/packages/mix/lib/src/specs/flex/flex_spec.dart index 27831ed84..cea690187 100644 --- a/packages/mix/lib/src/specs/flex/flex_spec.dart +++ b/packages/mix/lib/src/specs/flex/flex_spec.dart @@ -67,15 +67,15 @@ final class FlexSpec extends Spec with _$FlexSpec, Diagnosticable { return isAnimated ? AnimatedFlexSpecWidget( spec: this, + children: children, direction: direction, curve: animated!.curve, duration: animated!.duration, - children: children, ) : FlexSpecWidget( spec: this, - direction: direction, children: children, + direction: direction, ); } diff --git a/packages/mix/lib/src/specs/flex/flex_widget.dart b/packages/mix/lib/src/specs/flex/flex_widget.dart index b30a925de..e9d3cbbf6 100644 --- a/packages/mix/lib/src/specs/flex/flex_widget.dart +++ b/packages/mix/lib/src/specs/flex/flex_widget.dart @@ -42,7 +42,7 @@ class StyledFlex extends StyledWidget { return withMix(context, (context) { final spec = FlexSpec.of(context); - return spec(direction: direction, children: children); + return spec(children: children, direction: direction); }); } } @@ -99,8 +99,8 @@ class FlexSpecWidget extends StatelessWidget { ? flexWidget : RenderSpecModifiers( orderOfModifiers: orderOfModifiers, - spec: spec!, child: flexWidget, + spec: spec!, ); } } @@ -145,9 +145,9 @@ class AnimatedFlexSpecWidgetState Widget build(BuildContext context) { return FlexSpecWidget( spec: _specTween?.evaluate(animation), + children: widget.children, direction: widget.direction, orderOfModifiers: widget.orderOfModifiers, - children: widget.children, ); } } diff --git a/packages/mix/lib/src/specs/flexbox/flexbox_spec.dart b/packages/mix/lib/src/specs/flexbox/flexbox_spec.dart index 36c874ca8..2cf2dc94b 100644 --- a/packages/mix/lib/src/specs/flexbox/flexbox_spec.dart +++ b/packages/mix/lib/src/specs/flexbox/flexbox_spec.dart @@ -90,16 +90,16 @@ final class FlexBoxSpec extends Spec return (isAnimated) ? AnimatedFlexBoxSpecWidget( spec: this, + children: children, direction: direction, curve: animated!.curve, duration: animated!.duration, onEnd: animated!.onEnd, - children: children, ) : FlexBoxSpecWidget( spec: this, - direction: direction, children: children, + direction: direction, ); } diff --git a/packages/mix/lib/src/specs/flexbox/flexbox_widget.dart b/packages/mix/lib/src/specs/flexbox/flexbox_widget.dart index 22b6fb3e9..e8e0341f7 100644 --- a/packages/mix/lib/src/specs/flexbox/flexbox_widget.dart +++ b/packages/mix/lib/src/specs/flexbox/flexbox_widget.dart @@ -61,7 +61,7 @@ class FlexBox extends StyledWidget { flex: flexSpec, ); - return newSpec(direction: direction, children: children); + return newSpec(children: children, direction: direction); }); } } @@ -89,11 +89,11 @@ class FlexBoxSpecWidget extends StatelessWidget { // This code must be like this to keep the existing animation API working. return RenderSpecModifiers( orderOfModifiers: orderOfModifiers, - spec: spec, child: spec.box( + child: spec.flex(children: children, direction: direction), orderOfModifiers: orderOfModifiers, - child: spec.flex(direction: direction, children: children), ), + spec: spec, ); } } @@ -139,9 +139,9 @@ class AnimatedFlexBoxSpecWidgetState Widget build(BuildContext context) { return FlexBoxSpecWidget( spec: _specTween?.evaluate(animation), + children: widget.children, direction: widget.direction, orderOfModifiers: widget.orderOfModifiers, - children: widget.children, ); } } diff --git a/packages/mix/lib/src/specs/icon/icon_widget.dart b/packages/mix/lib/src/specs/icon/icon_widget.dart index dbd8f3193..cb62796c6 100644 --- a/packages/mix/lib/src/specs/icon/icon_widget.dart +++ b/packages/mix/lib/src/specs/icon/icon_widget.dart @@ -76,7 +76,6 @@ class IconSpecWidget extends StatelessWidget { Widget build(BuildContext context) { return RenderSpecModifiers( orderOfModifiers: orderOfModifiers, - spec: spec ?? const IconSpec(), child: Icon( icon, size: spec?.size, @@ -89,6 +88,7 @@ class IconSpecWidget extends StatelessWidget { semanticLabel: semanticLabel, textDirection: textDirection, ), + spec: spec ?? const IconSpec(), ); } } diff --git a/packages/mix/lib/src/specs/image/image_widget.dart b/packages/mix/lib/src/specs/image/image_widget.dart index 6f25d0543..4cab8893d 100644 --- a/packages/mix/lib/src/specs/image/image_widget.dart +++ b/packages/mix/lib/src/specs/image/image_widget.dart @@ -106,7 +106,6 @@ class ImageSpecWidget extends StatelessWidget { Widget build(BuildContext context) { return RenderSpecModifiers( orderOfModifiers: orderOfModifiers, - spec: spec ?? const ImageSpec(), child: Image( image: image, frameBuilder: frameBuilder, @@ -128,6 +127,7 @@ class ImageSpecWidget extends StatelessWidget { isAntiAlias: isAntiAlias, filterQuality: spec?.filterQuality ?? FilterQuality.low, ), + spec: spec ?? const ImageSpec(), ); } } diff --git a/packages/mix/lib/src/specs/stack/stack_spec.dart b/packages/mix/lib/src/specs/stack/stack_spec.dart index d849ea831..f633d45f5 100644 --- a/packages/mix/lib/src/specs/stack/stack_spec.dart +++ b/packages/mix/lib/src/specs/stack/stack_spec.dart @@ -42,9 +42,9 @@ final class StackSpec extends Spec with _$StackSpec, Diagnosticable { return isAnimated ? AnimatedStackSpecWidget( spec: this, + children: children, curve: animated!.curve, duration: animated!.duration, - children: children, ) : StackSpecWidget(spec: this, children: children); } diff --git a/packages/mix/lib/src/specs/stack/stack_widget.dart b/packages/mix/lib/src/specs/stack/stack_widget.dart index 187c82173..75b2cc5eb 100644 --- a/packages/mix/lib/src/specs/stack/stack_widget.dart +++ b/packages/mix/lib/src/specs/stack/stack_widget.dart @@ -57,7 +57,6 @@ class StackSpecWidget extends StatelessWidget { // The Stack widget is used here, applying the resolved styles from StackSpec. return RenderSpecModifiers( orderOfModifiers: orderOfModifiers, - spec: spec ?? const StackSpec(), child: Stack( alignment: spec?.alignment ?? _defaultStack.alignment, textDirection: spec?.textDirection, @@ -65,6 +64,7 @@ class StackSpecWidget extends StatelessWidget { clipBehavior: spec?.clipBehavior ?? _defaultStack.clipBehavior, children: children ?? const [], ), + spec: spec ?? const StackSpec(), ); } } @@ -109,8 +109,8 @@ class AnimatedStackSpecWidgetState return StackSpecWidget( spec: spec, - orderOfModifiers: widget.orderOfModifiers, children: widget.children, + orderOfModifiers: widget.orderOfModifiers, ); } } diff --git a/packages/mix/lib/src/specs/text/text_widget.dart b/packages/mix/lib/src/specs/text/text_widget.dart index 75de9aeb2..55ec69f3d 100644 --- a/packages/mix/lib/src/specs/text/text_widget.dart +++ b/packages/mix/lib/src/specs/text/text_widget.dart @@ -93,7 +93,6 @@ class TextSpecWidget extends StatelessWidget { // The Text widget is used here, applying the resolved styles and properties from TextSpec. return RenderSpecModifiers( orderOfModifiers: const [], - spec: spec ?? const TextSpec(), child: Text( spec?.directive?.apply(text) ?? text, style: spec?.style, @@ -111,6 +110,7 @@ class TextSpecWidget extends StatelessWidget { textWidthBasis: spec?.textWidthBasis, textHeightBehavior: spec?.textHeightBehavior, ), + spec: spec ?? const TextSpec(), ); } } diff --git a/packages/mix/lib/src/widgets/pressable_widget.dart b/packages/mix/lib/src/widgets/pressable_widget.dart index 228a00236..89d47be7b 100644 --- a/packages/mix/lib/src/widgets/pressable_widget.dart +++ b/packages/mix/lib/src/widgets/pressable_widget.dart @@ -55,6 +55,7 @@ class PressableBox extends StatelessWidget { @override Widget build(BuildContext context) { return Pressable( + child: Box(style: style, child: child), enabled: enabled, onPress: onPress, hitTestBehavior: hitTestBehavior, @@ -63,7 +64,6 @@ class PressableBox extends StatelessWidget { autofocus: autofocus, focusNode: focusNode, unpressDelay: unpressDelay, - child: Box(style: style, child: child), ); } } @@ -197,14 +197,13 @@ class PressableWidgetState extends State { @override Widget build(BuildContext context) { Widget current = GestureMixStateWidget( - enableFeedback: widget.enableFeedback, - controller: _controller, - onTap: widget.enabled ? widget.onPress?.call : null, - onLongPress: widget.enabled ? widget.onLongPress?.call : null, - excludeFromSemantics: widget.excludeFromSemantics, - hitTestBehavior: widget.hitTestBehavior, - unpressDelay: widget.unpressDelay, child: InteractiveMixStateWidget( + child: MouseRegionMixStateWidget( + child: MixWidgetStateBuilder( + controller: _controller, + builder: (_) => widget.child, + ), + ), enabled: widget.enabled, onFocusChange: widget.onFocusChange, autofocus: widget.autofocus, @@ -215,21 +214,22 @@ class PressableWidgetState extends State { mouseCursor: mouseCursor, controller: _controller, actions: actions, - child: MouseRegionMixStateWidget( - child: MixWidgetStateBuilder( - controller: _controller, - builder: (_) => widget.child, - ), - ), ), + enableFeedback: widget.enableFeedback, + controller: _controller, + onTap: widget.enabled ? widget.onPress?.call : null, + onLongPress: widget.enabled ? widget.onLongPress?.call : null, + excludeFromSemantics: widget.excludeFromSemantics, + hitTestBehavior: widget.hitTestBehavior, + unpressDelay: widget.unpressDelay, ); if (!widget.excludeFromSemantics) { current = Semantics( + child: current, button: true, label: widget.semanticButtonLabel, onTap: widget.onPress, - child: current, ); } @@ -308,6 +308,12 @@ class _InteractableState extends State { @override Widget build(BuildContext context) { return InteractiveMixStateWidget( + child: MouseRegionMixStateWidget( + child: MixWidgetStateBuilder( + controller: _controller, + builder: (context) => widget.child, + ), + ), enabled: widget.enabled, onFocusChange: widget.onFocusChange, autofocus: widget.autofocus, @@ -321,12 +327,6 @@ class _InteractableState extends State { shortcuts: widget.shortcuts, controller: _controller, actions: widget.actions, - child: MouseRegionMixStateWidget( - child: MixWidgetStateBuilder( - controller: _controller, - builder: (context) => widget.child, - ), - ), ); } } diff --git a/packages/mix_lint/lib/src/lints/avoid_defining_tokens_or_variants_within_style.dart b/packages/mix_lint/lib/src/lints/avoid_defining_tokens_or_variants_within_style.dart index af6939e9f..a7e0bc730 100644 --- a/packages/mix_lint/lib/src/lints/avoid_defining_tokens_or_variants_within_style.dart +++ b/packages/mix_lint/lib/src/lints/avoid_defining_tokens_or_variants_within_style.dart @@ -23,16 +23,16 @@ class AvoidDefiningTokensOrVariantsWithinStyle extends DartLintRule { ) { context.checkTypeHierarchyCompliance( parent: styleChecker, + child: variantChecker, reporter: reporter, code: _code, - child: variantChecker, ); context.checkTypeHierarchyCompliance( parent: styleChecker, + child: mixTokenChecker, reporter: reporter, code: _code, - child: mixTokenChecker, ); } } diff --git a/packages/remix/lib/src/app/remix_app.dart b/packages/remix/lib/src/app/remix_app.dart index 0f52184da..81fa1af80 100644 --- a/packages/remix/lib/src/app/remix_app.dart +++ b/packages/remix/lib/src/app/remix_app.dart @@ -122,7 +122,6 @@ class _RemixAppState extends State { Widget _remixBuilder(BuildContext context, Widget? child) { return RemixTheme( theme: widget.theme, - darkTheme: widget.darkTheme, child: widget.builder != null ? Builder( builder: (BuildContext context) { @@ -130,6 +129,7 @@ class _RemixAppState extends State { }, ) : (child ?? const SizedBox.shrink()), + darkTheme: widget.darkTheme, ); } diff --git a/packages/remix/lib/src/components/accordion/accordion_widget.dart b/packages/remix/lib/src/components/accordion/accordion_widget.dart index fb3acaf39..e20391bcb 100644 --- a/packages/remix/lib/src/components/accordion/accordion_widget.dart +++ b/packages/remix/lib/src/components/accordion/accordion_widget.dart @@ -66,11 +66,8 @@ class _AccordionState extends State with TickerProviderStateMixin { return spec.container( child: spec.flex( - direction: Axis.vertical, children: [ Pressable( - onPress: _handleTap, - controller: _controller, child: SpecBuilder( style: variantStyle, builder: (context) { @@ -79,9 +76,12 @@ class _AccordionState extends State with TickerProviderStateMixin { return widget.header(spec.header); }, ), + onPress: _handleTap, + controller: _controller, ), content, ], + direction: Axis.vertical, ), ); }, diff --git a/packages/remix/lib/src/components/accordion/header/accordion_header_spec_widget.dart b/packages/remix/lib/src/components/accordion/header/accordion_header_spec_widget.dart index db02b5ae9..bb70adb49 100644 --- a/packages/remix/lib/src/components/accordion/header/accordion_header_spec_widget.dart +++ b/packages/remix/lib/src/components/accordion/header/accordion_header_spec_widget.dart @@ -24,13 +24,13 @@ class AccordionHeaderSpecWidget extends StatelessWidget { return ContainerWidget( child: FlexWidget( - direction: Axis.horizontal, children: [ if (leadingIcon != null) LeadingIconWidget(leadingIcon), TitleWidget(title), const Spacer(), TrailingIconWidget(trailingIcon), ], + direction: Axis.horizontal, ), ); } diff --git a/packages/remix/lib/src/components/button/button_widget.dart b/packages/remix/lib/src/components/button/button_widget.dart index 1c397ede1..5bf622a20 100644 --- a/packages/remix/lib/src/components/button/button_widget.dart +++ b/packages/remix/lib/src/components/button/button_widget.dart @@ -53,8 +53,6 @@ class Button extends StatelessWidget { final configuration = SpecConfiguration(context, ButtonSpecUtility.self); return Pressable( - enabled: !isDisabled, - onPress: disabled || loading ? null : onPressed, child: SpecBuilder( style: style.makeStyle(configuration).applyVariants([ ...variants, @@ -73,6 +71,8 @@ class Button extends StatelessWidget { ); }, ), + enabled: !isDisabled, + onPress: disabled || loading ? null : onPressed, ); } } @@ -114,13 +114,13 @@ class ButtonSpecWidget extends StatelessWidget { Widget _buildChildren(ButtonSpec spec) { final flexWidget = spec.flex( - direction: Axis.horizontal, children: [ if (iconLeft != null) spec.icon(iconLeft), // If there is no icon always render the label if (label.isNotEmpty || !_hasIcon) spec.label(label), if (iconRight != null) spec.icon(iconRight), ], + direction: Axis.horizontal, ); return loading ? _buildLoadingOverlay(spec, flexWidget) : flexWidget; diff --git a/packages/remix/lib/src/components/callout/callout_widget.dart b/packages/remix/lib/src/components/callout/callout_widget.dart index 1ab33b6cb..d4e864556 100644 --- a/packages/remix/lib/src/components/callout/callout_widget.dart +++ b/packages/remix/lib/src/components/callout/callout_widget.dart @@ -31,8 +31,8 @@ class Callout extends StatelessWidget { return spec.container( child: spec.flex( - direction: Axis.horizontal, children: [if (icon != null) spec.icon(icon!), spec.text(text)], + direction: Axis.horizontal, ), ); }, diff --git a/packages/remix/lib/src/components/checkbox/checkbox_widget.dart b/packages/remix/lib/src/components/checkbox/checkbox_widget.dart index ebe41b1c0..e80a5f7e2 100644 --- a/packages/remix/lib/src/components/checkbox/checkbox_widget.dart +++ b/packages/remix/lib/src/components/checkbox/checkbox_widget.dart @@ -67,9 +67,6 @@ class _CheckboxState extends State { final configuration = SpecConfiguration(context, CheckboxSpecUtility.self); return Pressable( - enabled: !widget.disabled, - onPress: widget.disabled ? null : _handleOnPress, - controller: _controller, child: SpecBuilder( style: style .makeStyle(configuration) @@ -83,7 +80,6 @@ class _CheckboxState extends State { final IconWidget = spec.indicator; return ContainerLayout( - direction: Axis.horizontal, children: [ ContainerWidget( child: IconWidget( @@ -94,9 +90,13 @@ class _CheckboxState extends State { ), if (widget.label != null) spec.label(widget.label!), ], + direction: Axis.horizontal, ); }, ), + enabled: !widget.disabled, + onPress: widget.disabled ? null : _handleOnPress, + controller: _controller, ); } } diff --git a/packages/remix/lib/src/components/chip/chip_widget.dart b/packages/remix/lib/src/components/chip/chip_widget.dart index 0c2af005a..9c4966056 100644 --- a/packages/remix/lib/src/components/chip/chip_widget.dart +++ b/packages/remix/lib/src/components/chip/chip_widget.dart @@ -64,10 +64,6 @@ class _ChipState extends State { final configuration = SpecConfiguration(context, ChipSpecUtility.self); return Pressable( - enabled: !widget.disabled, - onPress: - widget.disabled ? null : () => widget.onChanged?.call(!widget.value), - controller: _controller, child: SpecBuilder( style: style.makeStyle(configuration).applyVariants(widget.variants), builder: (context) { @@ -75,16 +71,20 @@ class _ChipState extends State { return spec.container( child: spec.flex( - direction: Axis.horizontal, children: [ if (widget.iconLeft != null) spec.icon(widget.iconLeft), if (widget.label?.isNotEmpty == true) spec.label(widget.label!), if (widget.iconRight != null) spec.icon(widget.iconRight), ], + direction: Axis.horizontal, ), ); }, ), + enabled: !widget.disabled, + onPress: + widget.disabled ? null : () => widget.onChanged?.call(!widget.value), + controller: _controller, ); } } diff --git a/packages/remix/lib/src/components/dialog/dialog_widget.dart b/packages/remix/lib/src/components/dialog/dialog_widget.dart index ebdb649c0..fd8824bd2 100644 --- a/packages/remix/lib/src/components/dialog/dialog_widget.dart +++ b/packages/remix/lib/src/components/dialog/dialog_widget.dart @@ -42,7 +42,6 @@ class Dialog extends StatelessWidget { return spec.container( child: spec.mainFlex( - direction: Axis.vertical, children: [ if (titleBuilder != null) titleBuilder!(spec.title), if (descriptionBuilder != null) @@ -50,10 +49,11 @@ class Dialog extends StatelessWidget { content ?? const SizedBox.shrink(), if (actions != null) spec.actionsFlex( - direction: Axis.horizontal, children: actions!, + direction: Axis.horizontal, ), ], + direction: Axis.vertical, ), ); }, diff --git a/packages/remix/lib/src/components/icon_button/icon_button_widget.dart b/packages/remix/lib/src/components/icon_button/icon_button_widget.dart index 05fc28b39..14a4c1ee2 100644 --- a/packages/remix/lib/src/components/icon_button/icon_button_widget.dart +++ b/packages/remix/lib/src/components/icon_button/icon_button_widget.dart @@ -47,8 +47,6 @@ class IconButton extends StatelessWidget { SpecConfiguration(context, IconButtonSpecUtility.self); return Pressable( - enabled: !isDisabled, - onPress: disabled || loading ? null : onPressed, child: SpecBuilder( style: style.makeStyle(configuration).applyVariants(variants), builder: (context) { @@ -65,6 +63,8 @@ class IconButton extends StatelessWidget { ); }, ), + enabled: !isDisabled, + onPress: disabled || loading ? null : onPressed, ); } } diff --git a/packages/remix/lib/src/components/menu_item/menu_item_widget.dart b/packages/remix/lib/src/components/menu_item/menu_item_widget.dart index 7f83ed2e1..2a18b47a5 100644 --- a/packages/remix/lib/src/components/menu_item/menu_item_widget.dart +++ b/packages/remix/lib/src/components/menu_item/menu_item_widget.dart @@ -28,8 +28,6 @@ class MenuItem extends StatelessWidget { final configuration = SpecConfiguration(context, MenuItemSpecUtility.self); return Pressable( - enabled: !disabled, - onPress: disabled ? null : onPress, child: SpecBuilder( style: style.makeStyle(configuration).applyVariants([...variants]), builder: (context) { @@ -37,24 +35,26 @@ class MenuItem extends StatelessWidget { return spec.outerContainer( child: spec.contentLayout( - direction: Axis.horizontal, children: [ if (leadingWidgetBuilder != null) leadingWidgetBuilder!(spec.icon), spec.titleSubtitleLayout( - direction: Axis.vertical, children: [ spec.title(title), if (subtitle != null) spec.subtitle(subtitle!), ], + direction: Axis.vertical, ), if (trailingWidgetBuilder != null) trailingWidgetBuilder!(spec.icon), ], + direction: Axis.horizontal, ), ); }, ), + enabled: !disabled, + onPress: disabled ? null : onPress, ); } } diff --git a/packages/remix/lib/src/components/radio/radio_widget.dart b/packages/remix/lib/src/components/radio/radio_widget.dart index 3ee0083d0..07ea3e392 100644 --- a/packages/remix/lib/src/components/radio/radio_widget.dart +++ b/packages/remix/lib/src/components/radio/radio_widget.dart @@ -66,9 +66,6 @@ class _RadioState extends State> { final configuration = SpecConfiguration(context, RadioSpecUtility.self); return Pressable( - enabled: !widget.disabled, - onPress: widget.disabled ? null : _handleOnPress, - controller: _controller, child: SpecBuilder( style: style.makeStyle(configuration).applyVariants(widget.variants), builder: (context) { @@ -80,14 +77,17 @@ class _RadioState extends State> { final TextWidget = spec.text; return FlexWidget( - direction: Axis.horizontal, children: [ ContainerWidget(child: IndicatorWidget()), TextWidget(widget.label), ], + direction: Axis.horizontal, ); }, ), + enabled: !widget.disabled, + onPress: widget.disabled ? null : _handleOnPress, + controller: _controller, ); } } diff --git a/packages/remix/lib/src/components/segmented_control/button/segmented_control_button_widget.dart b/packages/remix/lib/src/components/segmented_control/button/segmented_control_button_widget.dart index 464a9f9e5..d9494d348 100644 --- a/packages/remix/lib/src/components/segmented_control/button/segmented_control_button_widget.dart +++ b/packages/remix/lib/src/components/segmented_control/button/segmented_control_button_widget.dart @@ -20,11 +20,11 @@ class SegmentButton extends StatelessWidget { return container( child: flex( - direction: Axis.horizontal, children: [ if (iconData != null) icon(iconData), if (text != null) label(text!), ], + direction: Axis.horizontal, ), ); }, diff --git a/packages/remix/lib/src/components/segmented_control/segmented_control_widget.dart b/packages/remix/lib/src/components/segmented_control/segmented_control_widget.dart index 7f271dc9a..1ea5edb1d 100644 --- a/packages/remix/lib/src/components/segmented_control/segmented_control_widget.dart +++ b/packages/remix/lib/src/components/segmented_control/segmented_control_widget.dart @@ -56,14 +56,12 @@ class _SegmentedControlState extends State { alignment: Alignment.centerLeft, children: [ spec.flex( - direction: Axis.vertical, children: [ for (int i = 0; i < widget.buttons.length; i++) Stack( alignment: Alignment.centerRight, children: [ Pressable( - onPress: () => widget.onIndexChanged(i), child: SpecBuilder( controller: i == widget.index ? controller : null, style: style.makeStyle(configuration), @@ -71,6 +69,7 @@ class _SegmentedControlState extends State { return widget.buttons[i]; }, ), + onPress: () => widget.onIndexChanged(i), ), if (i < lastIndex && spec.showDivider && @@ -80,6 +79,7 @@ class _SegmentedControlState extends State { ], ), ], + direction: Axis.vertical, ), ], ), diff --git a/packages/remix/lib/src/components/select/button/select_button_widget.dart b/packages/remix/lib/src/components/select/button/select_button_widget.dart index 98d63cd23..e2bc955e9 100644 --- a/packages/remix/lib/src/components/select/button/select_button_widget.dart +++ b/packages/remix/lib/src/components/select/button/select_button_widget.dart @@ -26,8 +26,8 @@ class XSelectButtonSpecWidget extends StatelessWidget { return container( child: flex( - direction: Axis.horizontal, children: [label(text), icon(trailingIcon)], + direction: Axis.horizontal, ), ); }, diff --git a/packages/remix/lib/src/components/select/item/select_menu_widget.dart b/packages/remix/lib/src/components/select/item/select_menu_widget.dart index db21d8872..24880dcd5 100644 --- a/packages/remix/lib/src/components/select/item/select_menu_widget.dart +++ b/packages/remix/lib/src/components/select/item/select_menu_widget.dart @@ -24,11 +24,11 @@ class SelectMenuItemWidget extends StatelessWidget { return container( child: flex( - direction: Axis.horizontal, children: [ if (iconData != null) icon(iconData), text(this.text), ], + direction: Axis.horizontal, ), ); }, diff --git a/packages/remix/lib/src/components/select/select_widget.dart b/packages/remix/lib/src/components/select/select_widget.dart index cf4305d8c..e8a3adfac 100644 --- a/packages/remix/lib/src/components/select/select_widget.dart +++ b/packages/remix/lib/src/components/select/select_widget.dart @@ -89,8 +89,8 @@ class SelectState extends State> overlayChildBuilder: (BuildContext context) { return Stack(children: [ GestureDetector( - onTap: () => hide(), child: Container(color: Colors.transparent), + onTap: () => hide(), ), CompositedTransformFollower( link: _link, @@ -119,13 +119,8 @@ class SelectState extends State> return Container( child: Flex( - direction: Axis.vertical, children: widget.items.map((item) { return Pressable( - onPress: () { - widget.onChanged(item.value); - hide(); - }, child: SpecBuilder( style: appliedStyle.animate( duration: _baseAnimation.duration, @@ -135,8 +130,13 @@ class SelectState extends State> return item.child; }, ), + onPress: () { + widget.onChanged(item.value); + hide(); + }, ); }).toList(), + direction: Axis.vertical, ), ); }, @@ -146,9 +146,9 @@ class SelectState extends State> }, child: RepaintBoundary( child: Pressable( + child: widget.button(button), enabled: !widget.disabled, onPress: onTap, - child: widget.button(button), ), ), ), diff --git a/packages/remix/lib/src/components/slider/slider_widget.dart b/packages/remix/lib/src/components/slider/slider_widget.dart index 89cfb2db5..e70070193 100644 --- a/packages/remix/lib/src/components/slider/slider_widget.dart +++ b/packages/remix/lib/src/components/slider/slider_widget.dart @@ -75,31 +75,7 @@ class _SliderState extends State with TickerProviderStateMixin { final configuration = SpecConfiguration(context, SliderSpecUtility.self); return Interactable( - enabled: !widget.disabled, - mouseCursor: widget.disabled - ? SystemMouseCursors.forbidden - : SystemMouseCursors.click, - controller: _controller, child: GestureDetector( - onPanStart: (details) { - _handleInteraction((c) { - c.pressed = true; - final value = _calculateValue(details.localPosition); - widget.onChangeStart?.call(value); - }); - }, - onPanUpdate: (details) { - _handleInteraction((c) { - c.pressed = true; - final value = _calculateValue(details.localPosition); - widget.onChanged?.call(value); - }); - }, - onPanEnd: (details) { - _handleInteraction((c) { - c.pressed = false; - }); - }, child: SpecBuilder( style: style.makeStyle(configuration).applyVariants(widget.variants), builder: (context) { @@ -155,7 +131,31 @@ class _SliderState extends State with TickerProviderStateMixin { ); }, ), + onPanStart: (details) { + _handleInteraction((c) { + c.pressed = true; + final value = _calculateValue(details.localPosition); + widget.onChangeStart?.call(value); + }); + }, + onPanUpdate: (details) { + _handleInteraction((c) { + c.pressed = true; + final value = _calculateValue(details.localPosition); + widget.onChanged?.call(value); + }); + }, + onPanEnd: (details) { + _handleInteraction((c) { + c.pressed = false; + }); + }, ), + enabled: !widget.disabled, + mouseCursor: widget.disabled + ? SystemMouseCursors.forbidden + : SystemMouseCursors.click, + controller: _controller, ); } } diff --git a/packages/remix/lib/src/components/switch/switch_widget.dart b/packages/remix/lib/src/components/switch/switch_widget.dart index 86de7ff22..b2e0f7a6e 100644 --- a/packages/remix/lib/src/components/switch/switch_widget.dart +++ b/packages/remix/lib/src/components/switch/switch_widget.dart @@ -59,9 +59,6 @@ class _SwitchState extends State { final configuration = SpecConfiguration(context, SwitchSpecUtility.self); return Pressable( - enabled: !widget.disabled, - onPress: widget.disabled ? null : _handleOnPress, - controller: _controller, child: SpecBuilder( style: style.makeStyle(configuration).applyVariants(widget.variants), builder: (context) { @@ -73,6 +70,9 @@ class _SwitchState extends State { return containerWidget(child: indicatorWidget()); }, ), + enabled: !widget.disabled, + onPress: widget.disabled ? null : _handleOnPress, + controller: _controller, ); } } diff --git a/packages/remix/lib/src/components/textfield/textfield_widget.dart b/packages/remix/lib/src/components/textfield/textfield_widget.dart index 86fced8ad..8d46dc575 100644 --- a/packages/remix/lib/src/components/textfield/textfield_widget.dart +++ b/packages/remix/lib/src/components/textfield/textfield_widget.dart @@ -520,11 +520,9 @@ class _TextFieldState extends State _effectiveController.value.text.isNotEmpty); return spec.containerLayout( - direction: Axis.vertical, children: [ spec.container( child: spec.contentLayout( - direction: Axis.horizontal, children: [ if (widget.prefixBuilder != null) widget.prefixBuilder!(spec.icon), @@ -621,25 +619,25 @@ class _TextFieldState extends State ), if (widget.suffix != null) widget.suffix!, ], + direction: Axis.horizontal, ), ), spec.helperText(widget.helperText ?? ''), ], + direction: Axis.vertical, ); }, ); return Interactable( - mouseCursor: SystemMouseCursors.text, - controller: _statesController, child: TextFieldTapRegion( child: IgnorePointer( ignoring: widget.ignorePointers ?? !widget.enabled, child: AnimatedBuilder( animation: _effectiveController, builder: (context, child) => _TextFieldContext( - isEmpty: _effectiveController.value.text.isEmpty, child: child!, + isEmpty: _effectiveController.value.text.isEmpty, ), child: _selectionGestureDetectorBuilder.buildGestureDetector( behavior: HitTestBehavior.translucent, @@ -648,6 +646,8 @@ class _TextFieldState extends State ), ), ), + mouseCursor: SystemMouseCursors.text, + controller: _statesController, ); } diff --git a/packages/remix/lib/src/components/toast/toast_layer.dart b/packages/remix/lib/src/components/toast/toast_layer.dart index ebe58804a..61dc8fa22 100644 --- a/packages/remix/lib/src/components/toast/toast_layer.dart +++ b/packages/remix/lib/src/components/toast/toast_layer.dart @@ -54,7 +54,7 @@ class ToastLayerState extends State implements ToastActions { Widget build(BuildContext context) { final toast = currentToast; final alignment = currentToast?.alignment ?? Alignment.bottomCenter; - + final toastWidget = KeyedSubtree( key: UniqueKey(), child: Align( @@ -66,6 +66,7 @@ class ToastLayerState extends State implements ToastActions { return Stack( children: [ AnimatedSwitcher( + child: toastWidget, duration: toast?.animationDuration ?? const Duration(milliseconds: 500), reverseDuration: toast?.reverseAnimationDuration ?? @@ -96,7 +97,6 @@ class ToastLayerState extends State implements ToastActions { child: FadeTransition(opacity: animation, child: child), ); }, - child: toastWidget, ), widget.child, ], diff --git a/packages/remix/lib/src/components/toast/toast_widget.dart b/packages/remix/lib/src/components/toast/toast_widget.dart index 243b0a6d5..a26c32266 100644 --- a/packages/remix/lib/src/components/toast/toast_widget.dart +++ b/packages/remix/lib/src/components/toast/toast_widget.dart @@ -31,18 +31,18 @@ class Toast extends StatelessWidget { return spec.container( child: spec.containerFlex( - direction: Axis.horizontal, children: [ if (leading != null) leading!, spec.textContentFlex( - direction: Axis.vertical, children: [ spec.title(title), if (description != null) spec.description(description!), ], + direction: Axis.vertical, ), if (trailing != null) trailing!, ], + direction: Axis.horizontal, ), ); }, diff --git a/packages/remix/lib/src/theme/remix_theme.dart b/packages/remix/lib/src/theme/remix_theme.dart index 3384b8941..107b45af6 100644 --- a/packages/remix/lib/src/theme/remix_theme.dart +++ b/packages/remix/lib/src/theme/remix_theme.dart @@ -311,13 +311,13 @@ class RemixTheme extends StatelessWidget { final tokens = theme.tokens; return MixTheme( + child: _RemixThemeInherited(child: child, data: theme), data: MixThemeData( colors: tokens.colors, spaces: tokens.spaces, textStyles: tokens.textStyles, radii: tokens.radii, ), - child: _RemixThemeInherited(data: theme, child: child), ); } } From 62b14c0fe644972068b420c762b099b90ff89321 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Thu, 14 Nov 2024 13:26:55 -0300 Subject: [PATCH 06/11] remove flex alias --- .../lib/src/specs/flexbox/flexbox_spec.dart | 20 +++---------- .../lib/src/specs/flexbox/flexbox_spec.g.dart | 30 ++++--------------- 2 files changed, 10 insertions(+), 40 deletions(-) diff --git a/packages/mix/lib/src/specs/flexbox/flexbox_spec.dart b/packages/mix/lib/src/specs/flexbox/flexbox_spec.dart index 2cf2dc94b..0d20adb6c 100644 --- a/packages/mix/lib/src/specs/flexbox/flexbox_spec.dart +++ b/packages/mix/lib/src/specs/flexbox/flexbox_spec.dart @@ -28,6 +28,7 @@ const _boxUtility = MixableUtility( (path: 'constraints.maxWidth', alias: 'maxWidth'), (path: 'constraints.minHeight', alias: 'minHeight'), (path: 'constraints.maxHeight', alias: 'maxHeight'), + (path: 'decoration', alias: 'decoration'), (path: 'decoration.color', alias: 'color'), (path: 'decoration.border', alias: 'border'), (path: 'decoration.border.directional', alias: 'borderDirectional'), @@ -43,6 +44,7 @@ const _boxUtility = MixableUtility( (path: 'decoration.boxShadows', alias: 'shadows'), (path: 'decoration.boxShadow', alias: 'shadow'), (path: 'decoration.elevation', alias: 'elevation'), + (path: 'shapeDecoration', alias: 'shapeDecoration'), (path: 'shape', alias: 'shape'), (path: 'foregroundDecoration', alias: 'foregroundDecoration'), (path: 'transform', alias: 'transform'), @@ -53,26 +55,12 @@ const _boxUtility = MixableUtility( ], ); -const _flexUtility = MixableUtility( - properties: [ - (path: 'direction', alias: 'direction'), - (path: 'mainAxisAlignment', alias: 'mainAxisAlignment'), - (path: 'crossAxisAlignment', alias: 'crossAxisAlignment'), - (path: 'mainAxisSize', alias: 'mainAxisSize'), - (path: 'verticalDirection', alias: 'verticalDirection'), - (path: 'textDirection', alias: 'textDirection'), - (path: 'textBaseline', alias: 'textBaseline'), - (path: 'gap', alias: 'gap'), - ], -); - @MixableSpec() final class FlexBoxSpec extends Spec with _$FlexBoxSpec, Diagnosticable { @MixableProperty(utilities: [_boxUtility]) final BoxSpec box; - @MixableProperty(utilities: [_flexUtility]) final FlexSpec flex; static const of = _$FlexBoxSpec.of; @@ -90,16 +78,16 @@ final class FlexBoxSpec extends Spec return (isAnimated) ? AnimatedFlexBoxSpecWidget( spec: this, - children: children, direction: direction, curve: animated!.curve, duration: animated!.duration, onEnd: animated!.onEnd, + children: children, ) : FlexBoxSpecWidget( spec: this, - children: children, direction: direction, + children: children, ); } diff --git a/packages/mix/lib/src/specs/flexbox/flexbox_spec.g.dart b/packages/mix/lib/src/specs/flexbox/flexbox_spec.g.dart index 060a48bcf..fcb879d8e 100644 --- a/packages/mix/lib/src/specs/flexbox/flexbox_spec.g.dart +++ b/packages/mix/lib/src/specs/flexbox/flexbox_spec.g.dart @@ -221,6 +221,9 @@ class FlexBoxSpecUtility /// Utility for defining [FlexBoxSpecAttribute.box.constraints.maxHeight] late final maxHeight = box.constraints.maxHeight; + /// Utility for defining [FlexBoxSpecAttribute.box.decoration] + late final decoration = box.decoration; + /// Utility for defining [FlexBoxSpecAttribute.box.decoration.color] late final color = box.decoration.color; @@ -257,6 +260,9 @@ class FlexBoxSpecUtility /// Utility for defining [FlexBoxSpecAttribute.box.decoration.elevation] late final elevation = box.decoration.elevation; + /// Utility for defining [FlexBoxSpecAttribute.box.shapeDecoration] + late final shapeDecoration = box.shapeDecoration; + /// Utility for defining [FlexBoxSpecAttribute.box.shape] late final shape = box.shape; @@ -281,30 +287,6 @@ class FlexBoxSpecUtility /// Utility for defining [FlexBoxSpecAttribute.flex] late final flex = FlexSpecUtility((v) => only(flex: v)); - /// Utility for defining [FlexBoxSpecAttribute.flex.direction] - late final direction = flex.direction; - - /// Utility for defining [FlexBoxSpecAttribute.flex.mainAxisAlignment] - late final mainAxisAlignment = flex.mainAxisAlignment; - - /// Utility for defining [FlexBoxSpecAttribute.flex.crossAxisAlignment] - late final crossAxisAlignment = flex.crossAxisAlignment; - - /// Utility for defining [FlexBoxSpecAttribute.flex.mainAxisSize] - late final mainAxisSize = flex.mainAxisSize; - - /// Utility for defining [FlexBoxSpecAttribute.flex.verticalDirection] - late final verticalDirection = flex.verticalDirection; - - /// Utility for defining [FlexBoxSpecAttribute.flex.textDirection] - late final textDirection = flex.textDirection; - - /// Utility for defining [FlexBoxSpecAttribute.flex.textBaseline] - late final textBaseline = flex.textBaseline; - - /// Utility for defining [FlexBoxSpecAttribute.flex.gap] - late final gap = flex.gap; - FlexBoxSpecUtility(super.builder, {super.mutable}); FlexBoxSpecUtility get chain => From 26a1dfe1a4955a979fc577041d341b5ad438c055 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Thu, 14 Nov 2024 13:56:23 -0300 Subject: [PATCH 07/11] implement flexbox in the remix --- .../lib/src/specs/flexbox/flexbox_spec.dart | 1 + .../lib/src/helpers/type_ref_repository.dart | 2 + .../lib/src/components/button/button.dart | 9 ++-- .../lib/src/components/button/button.g.dart | 51 ++++++------------- .../src/components/button/button_style.dart | 25 ++++----- .../src/components/button/button_theme.dart | 42 +++++++-------- .../src/components/button/button_widget.dart | 10 ++-- .../components/button/button_widget_test.dart | 2 +- 8 files changed, 59 insertions(+), 83 deletions(-) diff --git a/packages/mix/lib/src/specs/flexbox/flexbox_spec.dart b/packages/mix/lib/src/specs/flexbox/flexbox_spec.dart index 0d20adb6c..07cb78f3e 100644 --- a/packages/mix/lib/src/specs/flexbox/flexbox_spec.dart +++ b/packages/mix/lib/src/specs/flexbox/flexbox_spec.dart @@ -55,6 +55,7 @@ const _boxUtility = MixableUtility( ], ); +//TODO: Find a way to reuse as much code as possible from the FlexSpec and BoxSpec @MixableSpec() final class FlexBoxSpec extends Spec with _$FlexBoxSpec, Diagnosticable { diff --git a/packages/mix_generator/lib/src/helpers/type_ref_repository.dart b/packages/mix_generator/lib/src/helpers/type_ref_repository.dart index 54f033372..07dc4f8f3 100644 --- a/packages/mix_generator/lib/src/helpers/type_ref_repository.dart +++ b/packages/mix_generator/lib/src/helpers/type_ref_repository.dart @@ -1,4 +1,5 @@ import 'package:analyzer/dart/element/type.dart'; + import 'builder_utils.dart'; import 'helpers.dart'; @@ -44,6 +45,7 @@ class TypeRefRepository { 'TextSpec': 'TextSpecAttribute', 'ImageSpec': 'ImageSpecAttribute', 'IconSpec': 'IconSpecAttribute', + 'FlexBoxSpec': 'FlexBoxSpecAttribute', 'StackSpec': 'StackSpecAttribute', }; diff --git a/packages/remix/lib/src/components/button/button.dart b/packages/remix/lib/src/components/button/button.dart index 486d3e131..5f96bae3f 100644 --- a/packages/remix/lib/src/components/button/button.dart +++ b/packages/remix/lib/src/components/button/button.dart @@ -16,8 +16,7 @@ part 'button_widget.dart'; @MixableSpec() class ButtonSpec extends Spec with _$ButtonSpec, Diagnosticable { - final FlexSpec flex; - final BoxSpec container; + final FlexBoxSpec flexbox; final IconSpec icon; final TextSpec label; @@ -30,15 +29,13 @@ class ButtonSpec extends Spec with _$ButtonSpec, Diagnosticable { static const from = _$ButtonSpec.from; const ButtonSpec({ - BoxSpec? container, - FlexSpec? flex, + FlexBoxSpec? flexbox, IconSpec? icon, TextSpec? label, super.modifiers, SpinnerSpec? spinner, super.animated, - }) : flex = flex ?? const FlexSpec(), - container = container ?? const BoxSpec(), + }) : flexbox = flexbox ?? const FlexBoxSpec(), icon = icon ?? const IconSpec(), label = label ?? const TextSpec(), spinner = spinner ?? const SpinnerSpec(); diff --git a/packages/remix/lib/src/components/button/button.g.dart b/packages/remix/lib/src/components/button/button.g.dart index 27b9cd3e2..c6b475596 100644 --- a/packages/remix/lib/src/components/button/button.g.dart +++ b/packages/remix/lib/src/components/button/button.g.dart @@ -33,8 +33,7 @@ mixin _$ButtonSpec on Spec { /// replaced with the new values. @override ButtonSpec copyWith({ - BoxSpec? container, - FlexSpec? flex, + FlexBoxSpec? flexbox, IconSpec? icon, TextSpec? label, WidgetModifiersData? modifiers, @@ -42,8 +41,7 @@ mixin _$ButtonSpec on Spec { AnimatedData? animated, }) { return ButtonSpec( - container: container ?? _$this.container, - flex: flex ?? _$this.flex, + flexbox: flexbox ?? _$this.flexbox, icon: icon ?? _$this.icon, label: label ?? _$this.label, modifiers: modifiers ?? _$this.modifiers, @@ -63,8 +61,7 @@ mixin _$ButtonSpec on Spec { /// The interpolation is performed on each property of the [ButtonSpec] using the appropriate /// interpolation method: /// - /// - [BoxSpec.lerp] for [container]. - /// - [FlexSpec.lerp] for [flex]. + /// - [FlexBoxSpec.lerp] for [flexbox]. /// - [IconSpec.lerp] for [icon]. /// - [TextSpec.lerp] for [label]. @@ -79,8 +76,7 @@ mixin _$ButtonSpec on Spec { if (other == null) return _$this; return ButtonSpec( - container: _$this.container.lerp(other.container, t), - flex: _$this.flex.lerp(other.flex, t), + flexbox: _$this.flexbox.lerp(other.flexbox, t), icon: _$this.icon.lerp(other.icon, t), label: _$this.label.lerp(other.label, t), modifiers: other.modifiers, @@ -95,8 +91,7 @@ mixin _$ButtonSpec on Spec { /// compare two [ButtonSpec] instances for equality. @override List get props => [ - _$this.container, - _$this.flex, + _$this.flexbox, _$this.icon, _$this.label, _$this.modifiers, @@ -108,9 +103,7 @@ mixin _$ButtonSpec on Spec { void _debugFillProperties(DiagnosticPropertiesBuilder properties) { properties.add( - DiagnosticsProperty('container', _$this.container, defaultValue: null)); - properties - .add(DiagnosticsProperty('flex', _$this.flex, defaultValue: null)); + DiagnosticsProperty('flexbox', _$this.flexbox, defaultValue: null)); properties .add(DiagnosticsProperty('icon', _$this.icon, defaultValue: null)); properties @@ -133,15 +126,13 @@ mixin _$ButtonSpec on Spec { /// the [ButtonSpec] constructor. class ButtonSpecAttribute extends SpecAttribute with Diagnosticable { - final BoxSpecAttribute? container; - final FlexSpecAttribute? flex; + final FlexBoxSpecAttribute? flexbox; final IconSpecAttribute? icon; final TextSpecAttribute? label; final SpinnerSpecAttribute? spinner; const ButtonSpecAttribute({ - this.container, - this.flex, + this.flexbox, this.icon, this.label, super.modifiers, @@ -160,8 +151,7 @@ class ButtonSpecAttribute extends SpecAttribute @override ButtonSpec resolve(MixData mix) { return ButtonSpec( - container: container?.resolve(mix), - flex: flex?.resolve(mix), + flexbox: flexbox?.resolve(mix), icon: icon?.resolve(mix), label: label?.resolve(mix), modifiers: modifiers?.resolve(mix), @@ -183,8 +173,7 @@ class ButtonSpecAttribute extends SpecAttribute if (other == null) return this; return ButtonSpecAttribute( - container: container?.merge(other.container) ?? other.container, - flex: flex?.merge(other.flex) ?? other.flex, + flexbox: flexbox?.merge(other.flexbox) ?? other.flexbox, icon: icon?.merge(other.icon) ?? other.icon, label: label?.merge(other.label) ?? other.label, modifiers: modifiers?.merge(other.modifiers) ?? other.modifiers, @@ -199,8 +188,7 @@ class ButtonSpecAttribute extends SpecAttribute /// compare two [ButtonSpecAttribute] instances for equality. @override List get props => [ - container, - flex, + flexbox, icon, label, modifiers, @@ -211,9 +199,7 @@ class ButtonSpecAttribute extends SpecAttribute @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties - .add(DiagnosticsProperty('container', container, defaultValue: null)); - properties.add(DiagnosticsProperty('flex', flex, defaultValue: null)); + properties.add(DiagnosticsProperty('flexbox', flexbox, defaultValue: null)); properties.add(DiagnosticsProperty('icon', icon, defaultValue: null)); properties.add(DiagnosticsProperty('label', label, defaultValue: null)); properties @@ -230,11 +216,8 @@ class ButtonSpecAttribute extends SpecAttribute /// Use the methods of this class to configure specific properties of a [ButtonSpec]. class ButtonSpecUtility extends SpecUtility { - /// Utility for defining [ButtonSpecAttribute.container] - late final container = BoxSpecUtility((v) => only(container: v)); - - /// Utility for defining [ButtonSpecAttribute.flex] - late final flex = FlexSpecUtility((v) => only(flex: v)); + /// Utility for defining [ButtonSpecAttribute.flexbox] + late final flexbox = FlexBoxSpecUtility((v) => only(flexbox: v)); /// Utility for defining [ButtonSpecAttribute.icon] late final icon = IconSpecUtility((v) => only(icon: v)); @@ -262,8 +245,7 @@ class ButtonSpecUtility /// Returns a new [ButtonSpecAttribute] with the specified properties. @override T only({ - BoxSpecAttribute? container, - FlexSpecAttribute? flex, + FlexBoxSpecAttribute? flexbox, IconSpecAttribute? icon, TextSpecAttribute? label, WidgetModifiersDataDto? modifiers, @@ -271,8 +253,7 @@ class ButtonSpecUtility AnimatedDataDto? animated, }) { return builder(ButtonSpecAttribute( - container: container, - flex: flex, + flexbox: flexbox, icon: icon, label: label, modifiers: modifiers, diff --git a/packages/remix/lib/src/components/button/button_style.dart b/packages/remix/lib/src/components/button/button_style.dart index 9d8c69f97..68b2cfb6f 100644 --- a/packages/remix/lib/src/components/button/button_style.dart +++ b/packages/remix/lib/src/components/button/button_style.dart @@ -7,14 +7,6 @@ class ButtonStyle extends SpecStyle { Style makeStyle(SpecConfiguration spec) { final $ = spec.utilities; - final flexStyle = [ - $.flex.chain - ..mainAxisAlignment.center() - ..crossAxisAlignment.center() - ..mainAxisSize.min() - ..gap(8), - ]; - final iconStyle = [ $.icon.chain ..size(24) @@ -38,20 +30,23 @@ class ButtonStyle extends SpecStyle { ..color.white(), ]; - final containerStyle = [ - $.container.chain + final flexboxStyle = [ + $.flexbox.chain ..borderRadius(6) ..color.black() ..padding.vertical(8) - ..padding.horizontal(12), - spec.on.disabled($.container.color.grey.shade400()), + ..padding.horizontal(12) + ..flex.mainAxisAlignment.center() + ..flex.crossAxisAlignment.center() + ..flex.mainAxisSize.min() + ..flex.gap(8), + spec.on.disabled($.flexbox.color.grey.shade400()), ]; return Style.create([ - ...flexStyle, + ...flexboxStyle, ...iconStyle, ...labelStyle, - ...containerStyle, ...spinnerStyle, ]); } @@ -66,7 +61,7 @@ class ButtonDarkStyle extends ButtonStyle { return Style.create([ super.makeStyle(spec).call(), - $.container.color.white(), + $.flexbox.color.white(), $.label.style.color.black(), ]); } diff --git a/packages/remix/lib/src/components/button/button_theme.dart b/packages/remix/lib/src/components/button/button_theme.dart index a4f63570c..25ba09924 100644 --- a/packages/remix/lib/src/components/button/button_theme.dart +++ b/packages/remix/lib/src/components/button/button_theme.dart @@ -17,17 +17,17 @@ class FortalezaButtonStyle extends ButtonStyle { final baseStyle = super.makeStyle(spec); final baseOverrides = Style( baseStyle(), - $.container.chain + $.flexbox.chain ..padding.vertical.$space(2) - ..padding.horizontal.$space(3), - $.flex.gap.$space(2), + ..padding.horizontal.$space(3) + ..flex.gap.$space(2), $.label.style.$text(2), $.icon.size(14), $.spinner.size(14), ); final onDisabledForeground = $on.disabled( - $.container.color.$neutral(7), + $.flexbox.color.$neutral(7), $.label.style.color.$neutral(8), $.icon.color.$neutral(8), $.spinner.color.$neutral(7), @@ -36,25 +36,25 @@ class FortalezaButtonStyle extends ButtonStyle { final spinnerDisabled = $.spinner.color.$neutralAlpha(7); final solidVariant = Style( - $.container.color.$accent(), + $.flexbox.color.$accent(), $.label.style.color.white(), $.spinner.color.white(), $.icon.color.white(), - spec.on.hover($.container.color.$accent(10)), - spec.on.disabled($.container.color.$neutralAlpha(3), spinnerDisabled), + spec.on.hover($.flexbox.color.$accent(10)), + spec.on.disabled($.flexbox.color.$neutralAlpha(3), spinnerDisabled), ); final softVariant = Style( - $.container.color.$accentAlpha(3), + $.flexbox.color.$accentAlpha(3), $.label.style.color.$accentAlpha(11), $.spinner.color.$accentAlpha(11), $.icon.color.$accentAlpha(11), - spec.on.hover($.container.color.$accentAlpha(4)), - spec.on.disabled($.container.color.$neutralAlpha(3)), + spec.on.hover($.flexbox.color.$accentAlpha(4)), + spec.on.disabled($.flexbox.color.$neutralAlpha(3)), ); final outlineVariant = Style( - $.container.chain + $.flexbox.chain ..color.transparent() ..border.width(1) ..border.strokeAlign(0) @@ -62,9 +62,9 @@ class FortalezaButtonStyle extends ButtonStyle { $.spinner.color.$accentAlpha(11), $.icon.color.$accentAlpha(11), $.label.style.color.$accentAlpha(11), - spec.on.hover($.container.color.$accentAlpha(2)), + spec.on.hover($.flexbox.color.$accentAlpha(2)), spec.on.disabled( - $.container.chain + $.flexbox.chain ..border.color.$neutralAlpha(8) ..color.transparent(), ), @@ -72,22 +72,22 @@ class FortalezaButtonStyle extends ButtonStyle { final surfaceVariant = Style( outlineVariant(), - $.container.color.$accentAlpha(3), + $.flexbox.color.$accentAlpha(3), spec.on.hover( - $.container.color.$accentAlpha(4), - $.container.border.color.$accentAlpha(8), + $.flexbox.color.$accentAlpha(4), + $.flexbox.border.color.$accentAlpha(8), ), - spec.on.disabled($.container.color.$neutral(1)), + spec.on.disabled($.flexbox.color.$neutral(1)), ); final ghostVariant = Style( - $.container.border.style.none(), - $.container.color.transparent(), + $.flexbox.border.style.none(), + $.flexbox.color.transparent(), $.spinner.color.$accentAlpha(11), $.icon.color.$accentAlpha(11), $.label.style.color.$accentAlpha(11), - spec.on.hover($.container.color.$accentAlpha(3)), - spec.on.disabled($.container.color.transparent()), + spec.on.hover($.flexbox.color.$accentAlpha(3)), + spec.on.disabled($.flexbox.color.transparent()), ); return Style.create( diff --git a/packages/remix/lib/src/components/button/button_widget.dart b/packages/remix/lib/src/components/button/button_widget.dart index 5bf622a20..4d7ac5bb3 100644 --- a/packages/remix/lib/src/components/button/button_widget.dart +++ b/packages/remix/lib/src/components/button/button_widget.dart @@ -53,6 +53,8 @@ class Button extends StatelessWidget { final configuration = SpecConfiguration(context, ButtonSpecUtility.self); return Pressable( + enabled: !isDisabled, + onPress: disabled || loading ? null : onPressed, child: SpecBuilder( style: style.makeStyle(configuration).applyVariants([ ...variants, @@ -71,8 +73,6 @@ class Button extends StatelessWidget { ); }, ), - enabled: !isDisabled, - onPress: disabled || loading ? null : onPressed, ); } } @@ -113,7 +113,7 @@ class ButtonSpecWidget extends StatelessWidget { } Widget _buildChildren(ButtonSpec spec) { - final flexWidget = spec.flex( + final flexboxWidget = spec.flexbox( children: [ if (iconLeft != null) spec.icon(iconLeft), // If there is no icon always render the label @@ -123,13 +123,13 @@ class ButtonSpecWidget extends StatelessWidget { direction: Axis.horizontal, ); - return loading ? _buildLoadingOverlay(spec, flexWidget) : flexWidget; + return loading ? _buildLoadingOverlay(spec, flexboxWidget) : flexboxWidget; } @override Widget build(BuildContext context) { final spec = this.spec ?? const ButtonSpec(); - return spec.container(child: _buildChildren(spec)); + return _buildChildren(spec); } } diff --git a/packages/remix/test/components/button/button_widget_test.dart b/packages/remix/test/components/button/button_widget_test.dart index 155ae50fe..af7e082f6 100644 --- a/packages/remix/test/components/button/button_widget_test.dart +++ b/packages/remix/test/components/button/button_widget_test.dart @@ -170,7 +170,7 @@ class FakeButtonStyle extends ButtonStyle { final baseStyle = super.makeStyle(spec); return Style.create([ baseStyle(), - $.container.color(color), + $.flexbox.color(color), ]); } } From 11eb9e00af8cbd18295d6786937bc886795f9973 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Thu, 14 Nov 2024 13:58:13 -0300 Subject: [PATCH 08/11] lint --- .../mix/lib/src/widgets/pressable_widget.dart | 44 +++++++++---------- .../accordion/accordion_widget.dart | 4 +- .../components/checkbox/checkbox_widget.dart | 6 +-- .../lib/src/components/chip/chip_widget.dart | 8 ++-- .../icon_button/icon_button_widget.dart | 4 +- .../menu_item/menu_item_widget.dart | 4 +- .../src/components/radio/radio_widget.dart | 6 +-- .../segmented_control_widget.dart | 2 +- .../src/components/select/select_widget.dart | 10 ++--- .../src/components/switch/switch_widget.dart | 6 +-- 10 files changed, 47 insertions(+), 47 deletions(-) diff --git a/packages/mix/lib/src/widgets/pressable_widget.dart b/packages/mix/lib/src/widgets/pressable_widget.dart index 89d47be7b..ff13307b8 100644 --- a/packages/mix/lib/src/widgets/pressable_widget.dart +++ b/packages/mix/lib/src/widgets/pressable_widget.dart @@ -55,7 +55,6 @@ class PressableBox extends StatelessWidget { @override Widget build(BuildContext context) { return Pressable( - child: Box(style: style, child: child), enabled: enabled, onPress: onPress, hitTestBehavior: hitTestBehavior, @@ -64,6 +63,7 @@ class PressableBox extends StatelessWidget { autofocus: autofocus, focusNode: focusNode, unpressDelay: unpressDelay, + child: Box(style: style, child: child), ); } } @@ -71,7 +71,6 @@ class PressableBox extends StatelessWidget { class Pressable extends StatefulWidget { const Pressable({ super.key, - required this.child, this.enabled = true, this.enableFeedback = false, this.onPress, @@ -89,6 +88,7 @@ class Pressable extends StatefulWidget { this.unpressDelay = kDefaultAnimationDuration, this.controller, this.actions, + required this.child, }); final Widget child; @@ -197,13 +197,14 @@ class PressableWidgetState extends State { @override Widget build(BuildContext context) { Widget current = GestureMixStateWidget( + enableFeedback: widget.enableFeedback, + controller: _controller, + onTap: widget.enabled ? widget.onPress?.call : null, + onLongPress: widget.enabled ? widget.onLongPress?.call : null, + excludeFromSemantics: widget.excludeFromSemantics, + hitTestBehavior: widget.hitTestBehavior, + unpressDelay: widget.unpressDelay, child: InteractiveMixStateWidget( - child: MouseRegionMixStateWidget( - child: MixWidgetStateBuilder( - controller: _controller, - builder: (_) => widget.child, - ), - ), enabled: widget.enabled, onFocusChange: widget.onFocusChange, autofocus: widget.autofocus, @@ -214,22 +215,21 @@ class PressableWidgetState extends State { mouseCursor: mouseCursor, controller: _controller, actions: actions, + child: MouseRegionMixStateWidget( + child: MixWidgetStateBuilder( + controller: _controller, + builder: (_) => widget.child, + ), + ), ), - enableFeedback: widget.enableFeedback, - controller: _controller, - onTap: widget.enabled ? widget.onPress?.call : null, - onLongPress: widget.enabled ? widget.onLongPress?.call : null, - excludeFromSemantics: widget.excludeFromSemantics, - hitTestBehavior: widget.hitTestBehavior, - unpressDelay: widget.unpressDelay, ); if (!widget.excludeFromSemantics) { current = Semantics( - child: current, button: true, label: widget.semanticButtonLabel, onTap: widget.onPress, + child: current, ); } @@ -308,12 +308,6 @@ class _InteractableState extends State { @override Widget build(BuildContext context) { return InteractiveMixStateWidget( - child: MouseRegionMixStateWidget( - child: MixWidgetStateBuilder( - controller: _controller, - builder: (context) => widget.child, - ), - ), enabled: widget.enabled, onFocusChange: widget.onFocusChange, autofocus: widget.autofocus, @@ -327,6 +321,12 @@ class _InteractableState extends State { shortcuts: widget.shortcuts, controller: _controller, actions: widget.actions, + child: MouseRegionMixStateWidget( + child: MixWidgetStateBuilder( + controller: _controller, + builder: (context) => widget.child, + ), + ), ); } } diff --git a/packages/remix/lib/src/components/accordion/accordion_widget.dart b/packages/remix/lib/src/components/accordion/accordion_widget.dart index e20391bcb..75b55890e 100644 --- a/packages/remix/lib/src/components/accordion/accordion_widget.dart +++ b/packages/remix/lib/src/components/accordion/accordion_widget.dart @@ -68,6 +68,8 @@ class _AccordionState extends State with TickerProviderStateMixin { child: spec.flex( children: [ Pressable( + onPress: _handleTap, + controller: _controller, child: SpecBuilder( style: variantStyle, builder: (context) { @@ -76,8 +78,6 @@ class _AccordionState extends State with TickerProviderStateMixin { return widget.header(spec.header); }, ), - onPress: _handleTap, - controller: _controller, ), content, ], diff --git a/packages/remix/lib/src/components/checkbox/checkbox_widget.dart b/packages/remix/lib/src/components/checkbox/checkbox_widget.dart index e80a5f7e2..afecc38bf 100644 --- a/packages/remix/lib/src/components/checkbox/checkbox_widget.dart +++ b/packages/remix/lib/src/components/checkbox/checkbox_widget.dart @@ -67,6 +67,9 @@ class _CheckboxState extends State { final configuration = SpecConfiguration(context, CheckboxSpecUtility.self); return Pressable( + enabled: !widget.disabled, + onPress: widget.disabled ? null : _handleOnPress, + controller: _controller, child: SpecBuilder( style: style .makeStyle(configuration) @@ -94,9 +97,6 @@ class _CheckboxState extends State { ); }, ), - enabled: !widget.disabled, - onPress: widget.disabled ? null : _handleOnPress, - controller: _controller, ); } } diff --git a/packages/remix/lib/src/components/chip/chip_widget.dart b/packages/remix/lib/src/components/chip/chip_widget.dart index 9c4966056..e32b25d02 100644 --- a/packages/remix/lib/src/components/chip/chip_widget.dart +++ b/packages/remix/lib/src/components/chip/chip_widget.dart @@ -64,6 +64,10 @@ class _ChipState extends State { final configuration = SpecConfiguration(context, ChipSpecUtility.self); return Pressable( + enabled: !widget.disabled, + onPress: + widget.disabled ? null : () => widget.onChanged?.call(!widget.value), + controller: _controller, child: SpecBuilder( style: style.makeStyle(configuration).applyVariants(widget.variants), builder: (context) { @@ -81,10 +85,6 @@ class _ChipState extends State { ); }, ), - enabled: !widget.disabled, - onPress: - widget.disabled ? null : () => widget.onChanged?.call(!widget.value), - controller: _controller, ); } } diff --git a/packages/remix/lib/src/components/icon_button/icon_button_widget.dart b/packages/remix/lib/src/components/icon_button/icon_button_widget.dart index 14a4c1ee2..05fc28b39 100644 --- a/packages/remix/lib/src/components/icon_button/icon_button_widget.dart +++ b/packages/remix/lib/src/components/icon_button/icon_button_widget.dart @@ -47,6 +47,8 @@ class IconButton extends StatelessWidget { SpecConfiguration(context, IconButtonSpecUtility.self); return Pressable( + enabled: !isDisabled, + onPress: disabled || loading ? null : onPressed, child: SpecBuilder( style: style.makeStyle(configuration).applyVariants(variants), builder: (context) { @@ -63,8 +65,6 @@ class IconButton extends StatelessWidget { ); }, ), - enabled: !isDisabled, - onPress: disabled || loading ? null : onPressed, ); } } diff --git a/packages/remix/lib/src/components/menu_item/menu_item_widget.dart b/packages/remix/lib/src/components/menu_item/menu_item_widget.dart index 2a18b47a5..515d86beb 100644 --- a/packages/remix/lib/src/components/menu_item/menu_item_widget.dart +++ b/packages/remix/lib/src/components/menu_item/menu_item_widget.dart @@ -28,6 +28,8 @@ class MenuItem extends StatelessWidget { final configuration = SpecConfiguration(context, MenuItemSpecUtility.self); return Pressable( + enabled: !disabled, + onPress: disabled ? null : onPress, child: SpecBuilder( style: style.makeStyle(configuration).applyVariants([...variants]), builder: (context) { @@ -53,8 +55,6 @@ class MenuItem extends StatelessWidget { ); }, ), - enabled: !disabled, - onPress: disabled ? null : onPress, ); } } diff --git a/packages/remix/lib/src/components/radio/radio_widget.dart b/packages/remix/lib/src/components/radio/radio_widget.dart index 07ea3e392..a07fbe4ae 100644 --- a/packages/remix/lib/src/components/radio/radio_widget.dart +++ b/packages/remix/lib/src/components/radio/radio_widget.dart @@ -66,6 +66,9 @@ class _RadioState extends State> { final configuration = SpecConfiguration(context, RadioSpecUtility.self); return Pressable( + enabled: !widget.disabled, + onPress: widget.disabled ? null : _handleOnPress, + controller: _controller, child: SpecBuilder( style: style.makeStyle(configuration).applyVariants(widget.variants), builder: (context) { @@ -85,9 +88,6 @@ class _RadioState extends State> { ); }, ), - enabled: !widget.disabled, - onPress: widget.disabled ? null : _handleOnPress, - controller: _controller, ); } } diff --git a/packages/remix/lib/src/components/segmented_control/segmented_control_widget.dart b/packages/remix/lib/src/components/segmented_control/segmented_control_widget.dart index 1ea5edb1d..657ff1083 100644 --- a/packages/remix/lib/src/components/segmented_control/segmented_control_widget.dart +++ b/packages/remix/lib/src/components/segmented_control/segmented_control_widget.dart @@ -62,6 +62,7 @@ class _SegmentedControlState extends State { alignment: Alignment.centerRight, children: [ Pressable( + onPress: () => widget.onIndexChanged(i), child: SpecBuilder( controller: i == widget.index ? controller : null, style: style.makeStyle(configuration), @@ -69,7 +70,6 @@ class _SegmentedControlState extends State { return widget.buttons[i]; }, ), - onPress: () => widget.onIndexChanged(i), ), if (i < lastIndex && spec.showDivider && diff --git a/packages/remix/lib/src/components/select/select_widget.dart b/packages/remix/lib/src/components/select/select_widget.dart index e8a3adfac..3be4528fb 100644 --- a/packages/remix/lib/src/components/select/select_widget.dart +++ b/packages/remix/lib/src/components/select/select_widget.dart @@ -121,6 +121,10 @@ class SelectState extends State> child: Flex( children: widget.items.map((item) { return Pressable( + onPress: () { + widget.onChanged(item.value); + hide(); + }, child: SpecBuilder( style: appliedStyle.animate( duration: _baseAnimation.duration, @@ -130,10 +134,6 @@ class SelectState extends State> return item.child; }, ), - onPress: () { - widget.onChanged(item.value); - hide(); - }, ); }).toList(), direction: Axis.vertical, @@ -146,9 +146,9 @@ class SelectState extends State> }, child: RepaintBoundary( child: Pressable( - child: widget.button(button), enabled: !widget.disabled, onPress: onTap, + child: widget.button(button), ), ), ), diff --git a/packages/remix/lib/src/components/switch/switch_widget.dart b/packages/remix/lib/src/components/switch/switch_widget.dart index b2e0f7a6e..86de7ff22 100644 --- a/packages/remix/lib/src/components/switch/switch_widget.dart +++ b/packages/remix/lib/src/components/switch/switch_widget.dart @@ -59,6 +59,9 @@ class _SwitchState extends State { final configuration = SpecConfiguration(context, SwitchSpecUtility.self); return Pressable( + enabled: !widget.disabled, + onPress: widget.disabled ? null : _handleOnPress, + controller: _controller, child: SpecBuilder( style: style.makeStyle(configuration).applyVariants(widget.variants), builder: (context) { @@ -70,9 +73,6 @@ class _SwitchState extends State { return containerWidget(child: indicatorWidget()); }, ), - enabled: !widget.disabled, - onPress: widget.disabled ? null : _handleOnPress, - controller: _controller, ); } } From fc40ee66d83ac4991e72a5de027ea7b2a82de602 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Thu, 14 Nov 2024 14:02:52 -0300 Subject: [PATCH 09/11] lint: child and children as last --- lints_with_dcm.yaml | 4 +- .../src/core/factory/style_widgets_ext.dart | 2 +- packages/mix/lib/src/core/styled_widget.dart | 6 +-- .../internal/gesture_mix_state.dart | 2 +- .../internal/render_widget_modifier.dart | 8 ++-- .../scroll_view_widget_modifier.dart | 2 +- .../modifiers/visibility_widget_modifier.dart | 2 +- packages/mix/lib/src/specs/box/box_spec.dart | 4 +- .../mix/lib/src/specs/box/box_widget.dart | 4 +- .../mix/lib/src/specs/flex/flex_spec.dart | 4 +- .../mix/lib/src/specs/flex/flex_widget.dart | 6 +-- .../lib/src/specs/flexbox/flexbox_widget.dart | 8 ++-- .../mix/lib/src/specs/icon/icon_widget.dart | 2 +- .../mix/lib/src/specs/image/image_widget.dart | 2 +- .../mix/lib/src/specs/stack/stack_spec.dart | 2 +- .../mix/lib/src/specs/stack/stack_widget.dart | 4 +- .../mix/lib/src/specs/text/text_widget.dart | 2 +- ...ining_tokens_or_variants_within_style.dart | 4 +- packages/remix/lib/src/app/remix_app.dart | 2 +- .../accordion/accordion_widget.dart | 2 +- .../header/accordion_header_spec_widget.dart | 2 +- .../src/components/button/button_widget.dart | 2 +- .../components/callout/callout_widget.dart | 2 +- .../components/checkbox/checkbox_widget.dart | 2 +- .../lib/src/components/chip/chip_widget.dart | 2 +- .../src/components/dialog/dialog_widget.dart | 4 +- .../menu_item/menu_item_widget.dart | 4 +- .../src/components/radio/radio_widget.dart | 2 +- .../segmented_control_button_widget.dart | 2 +- .../segmented_control_widget.dart | 2 +- .../select/button/select_button_widget.dart | 2 +- .../select/item/select_menu_widget.dart | 2 +- .../src/components/select/select_widget.dart | 4 +- .../src/components/slider/slider_widget.dart | 48 +++++++++---------- .../textfield/textfield_widget.dart | 10 ++-- .../lib/src/components/toast/toast_layer.dart | 2 +- .../src/components/toast/toast_widget.dart | 4 +- packages/remix/lib/src/theme/remix_theme.dart | 2 +- 38 files changed, 86 insertions(+), 84 deletions(-) diff --git a/lints_with_dcm.yaml b/lints_with_dcm.yaml index adcd7083b..cf27c31cc 100644 --- a/lints_with_dcm.yaml +++ b/lints_with_dcm.yaml @@ -25,7 +25,9 @@ dart_code_metrics: prefer-prefixed-global-constants: false avoid-returning-widgets: false arguments-ordering: - child-last: true + last: + - child + - children avoid-nested-conditional-expressions: acceptable-level: 3 member-ordering: diff --git a/packages/mix/lib/src/core/factory/style_widgets_ext.dart b/packages/mix/lib/src/core/factory/style_widgets_ext.dart index 939be5adb..d4478b7f3 100644 --- a/packages/mix/lib/src/core/factory/style_widgets_ext.dart +++ b/packages/mix/lib/src/core/factory/style_widgets_ext.dart @@ -29,7 +29,7 @@ extension StyleExt on Style { Key? key, Style? style, }) { - return container(child: child, inherit: inherit, key: key, style: style); + return container(inherit: inherit, key: key, style: style, child: child); } HBox hbox({ diff --git a/packages/mix/lib/src/core/styled_widget.dart b/packages/mix/lib/src/core/styled_widget.dart index 2a41f2e25..a3626566e 100644 --- a/packages/mix/lib/src/core/styled_widget.dart +++ b/packages/mix/lib/src/core/styled_widget.dart @@ -105,17 +105,17 @@ class SpecBuilder extends StatelessWidget { return mix.isAnimated ? RenderAnimatedModifiers( modifiers: modifiers, - child: child, duration: mix.animation!.duration, mix: mix, orderOfModifiers: orderOfModifiers, curve: mix.animation!.curve, + child: child, ) : RenderModifiers( - child: child, modifiers: modifiers, mix: mix, orderOfModifiers: orderOfModifiers, + child: child, ); } @@ -143,7 +143,7 @@ class SpecBuilder extends StatelessWidget { _hasWidgetStateVariant && MixWidgetState.of(context) == null; if (needsWidgetState || controller != null) { - current = Interactable(child: current, controller: controller); + current = Interactable(controller: controller, child: current); } // Otherwise, directly build the mixed child widget diff --git a/packages/mix/lib/src/core/widget_state/internal/gesture_mix_state.dart b/packages/mix/lib/src/core/widget_state/internal/gesture_mix_state.dart index 018eccc50..21f1673e9 100644 --- a/packages/mix/lib/src/core/widget_state/internal/gesture_mix_state.dart +++ b/packages/mix/lib/src/core/widget_state/internal/gesture_mix_state.dart @@ -189,7 +189,6 @@ class _GestureMixStateWidgetState extends State { @override Widget build(BuildContext context) { return GestureDetector( - child: widget.child, onTapUp: widget.onTap != null ? _onTapUp : null, onTap: widget.onTap != null ? _onTap : null, onTapCancel: widget.onTap != null ? _onTapCancel : null, @@ -204,6 +203,7 @@ class _GestureMixStateWidgetState extends State { onPanCancel: widget.onPanCancel != null ? _onPanCancel : null, behavior: widget.hitTestBehavior, excludeFromSemantics: widget.excludeFromSemantics, + child: widget.child, ); } } diff --git a/packages/mix/lib/src/modifiers/internal/render_widget_modifier.dart b/packages/mix/lib/src/modifiers/internal/render_widget_modifier.dart index 8808e656a..a18024c13 100644 --- a/packages/mix/lib/src/modifiers/internal/render_widget_modifier.dart +++ b/packages/mix/lib/src/modifiers/internal/render_widget_modifier.dart @@ -105,8 +105,8 @@ class RenderModifiers extends StatelessWidget { @override Widget build(BuildContext context) { return _RenderModifiers( - child: child, modifiers: combineModifiers(mix, modifiers, orderOfModifiers).reversed, + child: child, ); } } @@ -160,10 +160,10 @@ class RenderAnimatedModifiers extends StatelessWidget { orderOfModifiers, defaultOrder: MixTheme.maybeOf(context)?.defaultOrderOfModifiers, ).reversed.toList(), - child: child, duration: duration, curve: curve, onEnd: onEnd, + child: child, ); } } @@ -275,15 +275,15 @@ class RenderSpecModifiers extends StatelessWidget { return spec.isAnimated ? RenderAnimatedModifiers( modifiers: modifiers, - child: child, duration: spec.animated!.duration, orderOfModifiers: orderOfModifiers, curve: spec.animated!.curve, + child: child, ) : RenderModifiers( - child: child, modifiers: modifiers, orderOfModifiers: orderOfModifiers, + child: child, ); } } diff --git a/packages/mix/lib/src/modifiers/scroll_view_widget_modifier.dart b/packages/mix/lib/src/modifiers/scroll_view_widget_modifier.dart index 31192fe53..624f642b9 100644 --- a/packages/mix/lib/src/modifiers/scroll_view_widget_modifier.dart +++ b/packages/mix/lib/src/modifiers/scroll_view_widget_modifier.dart @@ -43,8 +43,8 @@ final class ScrollViewModifierSpec reverse: reverse ?? false, padding: padding, physics: physics, - child: child, clipBehavior: clipBehavior ?? Clip.hardEdge, + child: child, ); } } diff --git a/packages/mix/lib/src/modifiers/visibility_widget_modifier.dart b/packages/mix/lib/src/modifiers/visibility_widget_modifier.dart index 6baa69419..b195d113f 100644 --- a/packages/mix/lib/src/modifiers/visibility_widget_modifier.dart +++ b/packages/mix/lib/src/modifiers/visibility_widget_modifier.dart @@ -26,7 +26,7 @@ final class VisibilityModifierSpec @override Widget build(Widget child) { - return Visibility(child: child, visible: visible); + return Visibility(visible: visible, child: child); } } diff --git a/packages/mix/lib/src/specs/box/box_spec.dart b/packages/mix/lib/src/specs/box/box_spec.dart index d842cd1ad..63529c0ad 100644 --- a/packages/mix/lib/src/specs/box/box_spec.dart +++ b/packages/mix/lib/src/specs/box/box_spec.dart @@ -123,16 +123,16 @@ final class BoxSpec extends Spec with _$BoxSpec, Diagnosticable { return isAnimated ? AnimatedBoxSpecWidget( spec: this, - child: child, duration: animated!.duration, curve: animated!.curve, onEnd: animated?.onEnd, orderOfModifiers: orderOfModifiers, + child: child, ) : BoxSpecWidget( spec: this, - child: child, orderOfModifiers: orderOfModifiers, + child: child, ); } diff --git a/packages/mix/lib/src/specs/box/box_widget.dart b/packages/mix/lib/src/specs/box/box_widget.dart index 7d99f43d1..d5e8ab6f9 100644 --- a/packages/mix/lib/src/specs/box/box_widget.dart +++ b/packages/mix/lib/src/specs/box/box_widget.dart @@ -75,6 +75,7 @@ class BoxSpecWidget extends StatelessWidget { Widget build(BuildContext context) { return RenderSpecModifiers( orderOfModifiers: orderOfModifiers, + spec: spec ?? const BoxSpec(), child: Container( alignment: spec?.alignment, padding: spec?.padding, @@ -86,10 +87,9 @@ class BoxSpecWidget extends StatelessWidget { margin: spec?.margin, transform: spec?.transform, transformAlignment: spec?.transformAlignment, - child: child, clipBehavior: spec?.clipBehavior ?? Clip.none, + child: child, ), - spec: spec ?? const BoxSpec(), ); } } diff --git a/packages/mix/lib/src/specs/flex/flex_spec.dart b/packages/mix/lib/src/specs/flex/flex_spec.dart index cea690187..27831ed84 100644 --- a/packages/mix/lib/src/specs/flex/flex_spec.dart +++ b/packages/mix/lib/src/specs/flex/flex_spec.dart @@ -67,15 +67,15 @@ final class FlexSpec extends Spec with _$FlexSpec, Diagnosticable { return isAnimated ? AnimatedFlexSpecWidget( spec: this, - children: children, direction: direction, curve: animated!.curve, duration: animated!.duration, + children: children, ) : FlexSpecWidget( spec: this, - children: children, direction: direction, + children: children, ); } diff --git a/packages/mix/lib/src/specs/flex/flex_widget.dart b/packages/mix/lib/src/specs/flex/flex_widget.dart index e9d3cbbf6..b30a925de 100644 --- a/packages/mix/lib/src/specs/flex/flex_widget.dart +++ b/packages/mix/lib/src/specs/flex/flex_widget.dart @@ -42,7 +42,7 @@ class StyledFlex extends StyledWidget { return withMix(context, (context) { final spec = FlexSpec.of(context); - return spec(children: children, direction: direction); + return spec(direction: direction, children: children); }); } } @@ -99,8 +99,8 @@ class FlexSpecWidget extends StatelessWidget { ? flexWidget : RenderSpecModifiers( orderOfModifiers: orderOfModifiers, - child: flexWidget, spec: spec!, + child: flexWidget, ); } } @@ -145,9 +145,9 @@ class AnimatedFlexSpecWidgetState Widget build(BuildContext context) { return FlexSpecWidget( spec: _specTween?.evaluate(animation), - children: widget.children, direction: widget.direction, orderOfModifiers: widget.orderOfModifiers, + children: widget.children, ); } } diff --git a/packages/mix/lib/src/specs/flexbox/flexbox_widget.dart b/packages/mix/lib/src/specs/flexbox/flexbox_widget.dart index e8e0341f7..22b6fb3e9 100644 --- a/packages/mix/lib/src/specs/flexbox/flexbox_widget.dart +++ b/packages/mix/lib/src/specs/flexbox/flexbox_widget.dart @@ -61,7 +61,7 @@ class FlexBox extends StyledWidget { flex: flexSpec, ); - return newSpec(children: children, direction: direction); + return newSpec(direction: direction, children: children); }); } } @@ -89,11 +89,11 @@ class FlexBoxSpecWidget extends StatelessWidget { // This code must be like this to keep the existing animation API working. return RenderSpecModifiers( orderOfModifiers: orderOfModifiers, + spec: spec, child: spec.box( - child: spec.flex(children: children, direction: direction), orderOfModifiers: orderOfModifiers, + child: spec.flex(direction: direction, children: children), ), - spec: spec, ); } } @@ -139,9 +139,9 @@ class AnimatedFlexBoxSpecWidgetState Widget build(BuildContext context) { return FlexBoxSpecWidget( spec: _specTween?.evaluate(animation), - children: widget.children, direction: widget.direction, orderOfModifiers: widget.orderOfModifiers, + children: widget.children, ); } } diff --git a/packages/mix/lib/src/specs/icon/icon_widget.dart b/packages/mix/lib/src/specs/icon/icon_widget.dart index cb62796c6..dbd8f3193 100644 --- a/packages/mix/lib/src/specs/icon/icon_widget.dart +++ b/packages/mix/lib/src/specs/icon/icon_widget.dart @@ -76,6 +76,7 @@ class IconSpecWidget extends StatelessWidget { Widget build(BuildContext context) { return RenderSpecModifiers( orderOfModifiers: orderOfModifiers, + spec: spec ?? const IconSpec(), child: Icon( icon, size: spec?.size, @@ -88,7 +89,6 @@ class IconSpecWidget extends StatelessWidget { semanticLabel: semanticLabel, textDirection: textDirection, ), - spec: spec ?? const IconSpec(), ); } } diff --git a/packages/mix/lib/src/specs/image/image_widget.dart b/packages/mix/lib/src/specs/image/image_widget.dart index 4cab8893d..6f25d0543 100644 --- a/packages/mix/lib/src/specs/image/image_widget.dart +++ b/packages/mix/lib/src/specs/image/image_widget.dart @@ -106,6 +106,7 @@ class ImageSpecWidget extends StatelessWidget { Widget build(BuildContext context) { return RenderSpecModifiers( orderOfModifiers: orderOfModifiers, + spec: spec ?? const ImageSpec(), child: Image( image: image, frameBuilder: frameBuilder, @@ -127,7 +128,6 @@ class ImageSpecWidget extends StatelessWidget { isAntiAlias: isAntiAlias, filterQuality: spec?.filterQuality ?? FilterQuality.low, ), - spec: spec ?? const ImageSpec(), ); } } diff --git a/packages/mix/lib/src/specs/stack/stack_spec.dart b/packages/mix/lib/src/specs/stack/stack_spec.dart index f633d45f5..d849ea831 100644 --- a/packages/mix/lib/src/specs/stack/stack_spec.dart +++ b/packages/mix/lib/src/specs/stack/stack_spec.dart @@ -42,9 +42,9 @@ final class StackSpec extends Spec with _$StackSpec, Diagnosticable { return isAnimated ? AnimatedStackSpecWidget( spec: this, - children: children, curve: animated!.curve, duration: animated!.duration, + children: children, ) : StackSpecWidget(spec: this, children: children); } diff --git a/packages/mix/lib/src/specs/stack/stack_widget.dart b/packages/mix/lib/src/specs/stack/stack_widget.dart index 75b2cc5eb..187c82173 100644 --- a/packages/mix/lib/src/specs/stack/stack_widget.dart +++ b/packages/mix/lib/src/specs/stack/stack_widget.dart @@ -57,6 +57,7 @@ class StackSpecWidget extends StatelessWidget { // The Stack widget is used here, applying the resolved styles from StackSpec. return RenderSpecModifiers( orderOfModifiers: orderOfModifiers, + spec: spec ?? const StackSpec(), child: Stack( alignment: spec?.alignment ?? _defaultStack.alignment, textDirection: spec?.textDirection, @@ -64,7 +65,6 @@ class StackSpecWidget extends StatelessWidget { clipBehavior: spec?.clipBehavior ?? _defaultStack.clipBehavior, children: children ?? const [], ), - spec: spec ?? const StackSpec(), ); } } @@ -109,8 +109,8 @@ class AnimatedStackSpecWidgetState return StackSpecWidget( spec: spec, - children: widget.children, orderOfModifiers: widget.orderOfModifiers, + children: widget.children, ); } } diff --git a/packages/mix/lib/src/specs/text/text_widget.dart b/packages/mix/lib/src/specs/text/text_widget.dart index 55ec69f3d..75de9aeb2 100644 --- a/packages/mix/lib/src/specs/text/text_widget.dart +++ b/packages/mix/lib/src/specs/text/text_widget.dart @@ -93,6 +93,7 @@ class TextSpecWidget extends StatelessWidget { // The Text widget is used here, applying the resolved styles and properties from TextSpec. return RenderSpecModifiers( orderOfModifiers: const [], + spec: spec ?? const TextSpec(), child: Text( spec?.directive?.apply(text) ?? text, style: spec?.style, @@ -110,7 +111,6 @@ class TextSpecWidget extends StatelessWidget { textWidthBasis: spec?.textWidthBasis, textHeightBehavior: spec?.textHeightBehavior, ), - spec: spec ?? const TextSpec(), ); } } diff --git a/packages/mix_lint/lib/src/lints/avoid_defining_tokens_or_variants_within_style.dart b/packages/mix_lint/lib/src/lints/avoid_defining_tokens_or_variants_within_style.dart index a7e0bc730..af6939e9f 100644 --- a/packages/mix_lint/lib/src/lints/avoid_defining_tokens_or_variants_within_style.dart +++ b/packages/mix_lint/lib/src/lints/avoid_defining_tokens_or_variants_within_style.dart @@ -23,16 +23,16 @@ class AvoidDefiningTokensOrVariantsWithinStyle extends DartLintRule { ) { context.checkTypeHierarchyCompliance( parent: styleChecker, - child: variantChecker, reporter: reporter, code: _code, + child: variantChecker, ); context.checkTypeHierarchyCompliance( parent: styleChecker, - child: mixTokenChecker, reporter: reporter, code: _code, + child: mixTokenChecker, ); } } diff --git a/packages/remix/lib/src/app/remix_app.dart b/packages/remix/lib/src/app/remix_app.dart index 81fa1af80..0f52184da 100644 --- a/packages/remix/lib/src/app/remix_app.dart +++ b/packages/remix/lib/src/app/remix_app.dart @@ -122,6 +122,7 @@ class _RemixAppState extends State { Widget _remixBuilder(BuildContext context, Widget? child) { return RemixTheme( theme: widget.theme, + darkTheme: widget.darkTheme, child: widget.builder != null ? Builder( builder: (BuildContext context) { @@ -129,7 +130,6 @@ class _RemixAppState extends State { }, ) : (child ?? const SizedBox.shrink()), - darkTheme: widget.darkTheme, ); } diff --git a/packages/remix/lib/src/components/accordion/accordion_widget.dart b/packages/remix/lib/src/components/accordion/accordion_widget.dart index 75b55890e..fb3acaf39 100644 --- a/packages/remix/lib/src/components/accordion/accordion_widget.dart +++ b/packages/remix/lib/src/components/accordion/accordion_widget.dart @@ -66,6 +66,7 @@ class _AccordionState extends State with TickerProviderStateMixin { return spec.container( child: spec.flex( + direction: Axis.vertical, children: [ Pressable( onPress: _handleTap, @@ -81,7 +82,6 @@ class _AccordionState extends State with TickerProviderStateMixin { ), content, ], - direction: Axis.vertical, ), ); }, diff --git a/packages/remix/lib/src/components/accordion/header/accordion_header_spec_widget.dart b/packages/remix/lib/src/components/accordion/header/accordion_header_spec_widget.dart index bb70adb49..db02b5ae9 100644 --- a/packages/remix/lib/src/components/accordion/header/accordion_header_spec_widget.dart +++ b/packages/remix/lib/src/components/accordion/header/accordion_header_spec_widget.dart @@ -24,13 +24,13 @@ class AccordionHeaderSpecWidget extends StatelessWidget { return ContainerWidget( child: FlexWidget( + direction: Axis.horizontal, children: [ if (leadingIcon != null) LeadingIconWidget(leadingIcon), TitleWidget(title), const Spacer(), TrailingIconWidget(trailingIcon), ], - direction: Axis.horizontal, ), ); } diff --git a/packages/remix/lib/src/components/button/button_widget.dart b/packages/remix/lib/src/components/button/button_widget.dart index 4d7ac5bb3..fad00358b 100644 --- a/packages/remix/lib/src/components/button/button_widget.dart +++ b/packages/remix/lib/src/components/button/button_widget.dart @@ -114,13 +114,13 @@ class ButtonSpecWidget extends StatelessWidget { Widget _buildChildren(ButtonSpec spec) { final flexboxWidget = spec.flexbox( + direction: Axis.horizontal, children: [ if (iconLeft != null) spec.icon(iconLeft), // If there is no icon always render the label if (label.isNotEmpty || !_hasIcon) spec.label(label), if (iconRight != null) spec.icon(iconRight), ], - direction: Axis.horizontal, ); return loading ? _buildLoadingOverlay(spec, flexboxWidget) : flexboxWidget; diff --git a/packages/remix/lib/src/components/callout/callout_widget.dart b/packages/remix/lib/src/components/callout/callout_widget.dart index d4e864556..1ab33b6cb 100644 --- a/packages/remix/lib/src/components/callout/callout_widget.dart +++ b/packages/remix/lib/src/components/callout/callout_widget.dart @@ -31,8 +31,8 @@ class Callout extends StatelessWidget { return spec.container( child: spec.flex( - children: [if (icon != null) spec.icon(icon!), spec.text(text)], direction: Axis.horizontal, + children: [if (icon != null) spec.icon(icon!), spec.text(text)], ), ); }, diff --git a/packages/remix/lib/src/components/checkbox/checkbox_widget.dart b/packages/remix/lib/src/components/checkbox/checkbox_widget.dart index afecc38bf..ebe41b1c0 100644 --- a/packages/remix/lib/src/components/checkbox/checkbox_widget.dart +++ b/packages/remix/lib/src/components/checkbox/checkbox_widget.dart @@ -83,6 +83,7 @@ class _CheckboxState extends State { final IconWidget = spec.indicator; return ContainerLayout( + direction: Axis.horizontal, children: [ ContainerWidget( child: IconWidget( @@ -93,7 +94,6 @@ class _CheckboxState extends State { ), if (widget.label != null) spec.label(widget.label!), ], - direction: Axis.horizontal, ); }, ), diff --git a/packages/remix/lib/src/components/chip/chip_widget.dart b/packages/remix/lib/src/components/chip/chip_widget.dart index e32b25d02..0c2af005a 100644 --- a/packages/remix/lib/src/components/chip/chip_widget.dart +++ b/packages/remix/lib/src/components/chip/chip_widget.dart @@ -75,12 +75,12 @@ class _ChipState extends State { return spec.container( child: spec.flex( + direction: Axis.horizontal, children: [ if (widget.iconLeft != null) spec.icon(widget.iconLeft), if (widget.label?.isNotEmpty == true) spec.label(widget.label!), if (widget.iconRight != null) spec.icon(widget.iconRight), ], - direction: Axis.horizontal, ), ); }, diff --git a/packages/remix/lib/src/components/dialog/dialog_widget.dart b/packages/remix/lib/src/components/dialog/dialog_widget.dart index fd8824bd2..ebdb649c0 100644 --- a/packages/remix/lib/src/components/dialog/dialog_widget.dart +++ b/packages/remix/lib/src/components/dialog/dialog_widget.dart @@ -42,6 +42,7 @@ class Dialog extends StatelessWidget { return spec.container( child: spec.mainFlex( + direction: Axis.vertical, children: [ if (titleBuilder != null) titleBuilder!(spec.title), if (descriptionBuilder != null) @@ -49,11 +50,10 @@ class Dialog extends StatelessWidget { content ?? const SizedBox.shrink(), if (actions != null) spec.actionsFlex( - children: actions!, direction: Axis.horizontal, + children: actions!, ), ], - direction: Axis.vertical, ), ); }, diff --git a/packages/remix/lib/src/components/menu_item/menu_item_widget.dart b/packages/remix/lib/src/components/menu_item/menu_item_widget.dart index 515d86beb..7f83ed2e1 100644 --- a/packages/remix/lib/src/components/menu_item/menu_item_widget.dart +++ b/packages/remix/lib/src/components/menu_item/menu_item_widget.dart @@ -37,20 +37,20 @@ class MenuItem extends StatelessWidget { return spec.outerContainer( child: spec.contentLayout( + direction: Axis.horizontal, children: [ if (leadingWidgetBuilder != null) leadingWidgetBuilder!(spec.icon), spec.titleSubtitleLayout( + direction: Axis.vertical, children: [ spec.title(title), if (subtitle != null) spec.subtitle(subtitle!), ], - direction: Axis.vertical, ), if (trailingWidgetBuilder != null) trailingWidgetBuilder!(spec.icon), ], - direction: Axis.horizontal, ), ); }, diff --git a/packages/remix/lib/src/components/radio/radio_widget.dart b/packages/remix/lib/src/components/radio/radio_widget.dart index a07fbe4ae..3ee0083d0 100644 --- a/packages/remix/lib/src/components/radio/radio_widget.dart +++ b/packages/remix/lib/src/components/radio/radio_widget.dart @@ -80,11 +80,11 @@ class _RadioState extends State> { final TextWidget = spec.text; return FlexWidget( + direction: Axis.horizontal, children: [ ContainerWidget(child: IndicatorWidget()), TextWidget(widget.label), ], - direction: Axis.horizontal, ); }, ), diff --git a/packages/remix/lib/src/components/segmented_control/button/segmented_control_button_widget.dart b/packages/remix/lib/src/components/segmented_control/button/segmented_control_button_widget.dart index d9494d348..464a9f9e5 100644 --- a/packages/remix/lib/src/components/segmented_control/button/segmented_control_button_widget.dart +++ b/packages/remix/lib/src/components/segmented_control/button/segmented_control_button_widget.dart @@ -20,11 +20,11 @@ class SegmentButton extends StatelessWidget { return container( child: flex( + direction: Axis.horizontal, children: [ if (iconData != null) icon(iconData), if (text != null) label(text!), ], - direction: Axis.horizontal, ), ); }, diff --git a/packages/remix/lib/src/components/segmented_control/segmented_control_widget.dart b/packages/remix/lib/src/components/segmented_control/segmented_control_widget.dart index 657ff1083..7f271dc9a 100644 --- a/packages/remix/lib/src/components/segmented_control/segmented_control_widget.dart +++ b/packages/remix/lib/src/components/segmented_control/segmented_control_widget.dart @@ -56,6 +56,7 @@ class _SegmentedControlState extends State { alignment: Alignment.centerLeft, children: [ spec.flex( + direction: Axis.vertical, children: [ for (int i = 0; i < widget.buttons.length; i++) Stack( @@ -79,7 +80,6 @@ class _SegmentedControlState extends State { ], ), ], - direction: Axis.vertical, ), ], ), diff --git a/packages/remix/lib/src/components/select/button/select_button_widget.dart b/packages/remix/lib/src/components/select/button/select_button_widget.dart index e2bc955e9..98d63cd23 100644 --- a/packages/remix/lib/src/components/select/button/select_button_widget.dart +++ b/packages/remix/lib/src/components/select/button/select_button_widget.dart @@ -26,8 +26,8 @@ class XSelectButtonSpecWidget extends StatelessWidget { return container( child: flex( - children: [label(text), icon(trailingIcon)], direction: Axis.horizontal, + children: [label(text), icon(trailingIcon)], ), ); }, diff --git a/packages/remix/lib/src/components/select/item/select_menu_widget.dart b/packages/remix/lib/src/components/select/item/select_menu_widget.dart index 24880dcd5..db21d8872 100644 --- a/packages/remix/lib/src/components/select/item/select_menu_widget.dart +++ b/packages/remix/lib/src/components/select/item/select_menu_widget.dart @@ -24,11 +24,11 @@ class SelectMenuItemWidget extends StatelessWidget { return container( child: flex( + direction: Axis.horizontal, children: [ if (iconData != null) icon(iconData), text(this.text), ], - direction: Axis.horizontal, ), ); }, diff --git a/packages/remix/lib/src/components/select/select_widget.dart b/packages/remix/lib/src/components/select/select_widget.dart index 3be4528fb..cf4305d8c 100644 --- a/packages/remix/lib/src/components/select/select_widget.dart +++ b/packages/remix/lib/src/components/select/select_widget.dart @@ -89,8 +89,8 @@ class SelectState extends State> overlayChildBuilder: (BuildContext context) { return Stack(children: [ GestureDetector( - child: Container(color: Colors.transparent), onTap: () => hide(), + child: Container(color: Colors.transparent), ), CompositedTransformFollower( link: _link, @@ -119,6 +119,7 @@ class SelectState extends State> return Container( child: Flex( + direction: Axis.vertical, children: widget.items.map((item) { return Pressable( onPress: () { @@ -136,7 +137,6 @@ class SelectState extends State> ), ); }).toList(), - direction: Axis.vertical, ), ); }, diff --git a/packages/remix/lib/src/components/slider/slider_widget.dart b/packages/remix/lib/src/components/slider/slider_widget.dart index e70070193..89cfb2db5 100644 --- a/packages/remix/lib/src/components/slider/slider_widget.dart +++ b/packages/remix/lib/src/components/slider/slider_widget.dart @@ -75,7 +75,31 @@ class _SliderState extends State with TickerProviderStateMixin { final configuration = SpecConfiguration(context, SliderSpecUtility.self); return Interactable( + enabled: !widget.disabled, + mouseCursor: widget.disabled + ? SystemMouseCursors.forbidden + : SystemMouseCursors.click, + controller: _controller, child: GestureDetector( + onPanStart: (details) { + _handleInteraction((c) { + c.pressed = true; + final value = _calculateValue(details.localPosition); + widget.onChangeStart?.call(value); + }); + }, + onPanUpdate: (details) { + _handleInteraction((c) { + c.pressed = true; + final value = _calculateValue(details.localPosition); + widget.onChanged?.call(value); + }); + }, + onPanEnd: (details) { + _handleInteraction((c) { + c.pressed = false; + }); + }, child: SpecBuilder( style: style.makeStyle(configuration).applyVariants(widget.variants), builder: (context) { @@ -131,31 +155,7 @@ class _SliderState extends State with TickerProviderStateMixin { ); }, ), - onPanStart: (details) { - _handleInteraction((c) { - c.pressed = true; - final value = _calculateValue(details.localPosition); - widget.onChangeStart?.call(value); - }); - }, - onPanUpdate: (details) { - _handleInteraction((c) { - c.pressed = true; - final value = _calculateValue(details.localPosition); - widget.onChanged?.call(value); - }); - }, - onPanEnd: (details) { - _handleInteraction((c) { - c.pressed = false; - }); - }, ), - enabled: !widget.disabled, - mouseCursor: widget.disabled - ? SystemMouseCursors.forbidden - : SystemMouseCursors.click, - controller: _controller, ); } } diff --git a/packages/remix/lib/src/components/textfield/textfield_widget.dart b/packages/remix/lib/src/components/textfield/textfield_widget.dart index 8d46dc575..86fced8ad 100644 --- a/packages/remix/lib/src/components/textfield/textfield_widget.dart +++ b/packages/remix/lib/src/components/textfield/textfield_widget.dart @@ -520,9 +520,11 @@ class _TextFieldState extends State _effectiveController.value.text.isNotEmpty); return spec.containerLayout( + direction: Axis.vertical, children: [ spec.container( child: spec.contentLayout( + direction: Axis.horizontal, children: [ if (widget.prefixBuilder != null) widget.prefixBuilder!(spec.icon), @@ -619,25 +621,25 @@ class _TextFieldState extends State ), if (widget.suffix != null) widget.suffix!, ], - direction: Axis.horizontal, ), ), spec.helperText(widget.helperText ?? ''), ], - direction: Axis.vertical, ); }, ); return Interactable( + mouseCursor: SystemMouseCursors.text, + controller: _statesController, child: TextFieldTapRegion( child: IgnorePointer( ignoring: widget.ignorePointers ?? !widget.enabled, child: AnimatedBuilder( animation: _effectiveController, builder: (context, child) => _TextFieldContext( - child: child!, isEmpty: _effectiveController.value.text.isEmpty, + child: child!, ), child: _selectionGestureDetectorBuilder.buildGestureDetector( behavior: HitTestBehavior.translucent, @@ -646,8 +648,6 @@ class _TextFieldState extends State ), ), ), - mouseCursor: SystemMouseCursors.text, - controller: _statesController, ); } diff --git a/packages/remix/lib/src/components/toast/toast_layer.dart b/packages/remix/lib/src/components/toast/toast_layer.dart index 61dc8fa22..f2066592d 100644 --- a/packages/remix/lib/src/components/toast/toast_layer.dart +++ b/packages/remix/lib/src/components/toast/toast_layer.dart @@ -66,7 +66,6 @@ class ToastLayerState extends State implements ToastActions { return Stack( children: [ AnimatedSwitcher( - child: toastWidget, duration: toast?.animationDuration ?? const Duration(milliseconds: 500), reverseDuration: toast?.reverseAnimationDuration ?? @@ -97,6 +96,7 @@ class ToastLayerState extends State implements ToastActions { child: FadeTransition(opacity: animation, child: child), ); }, + child: toastWidget, ), widget.child, ], diff --git a/packages/remix/lib/src/components/toast/toast_widget.dart b/packages/remix/lib/src/components/toast/toast_widget.dart index a26c32266..243b0a6d5 100644 --- a/packages/remix/lib/src/components/toast/toast_widget.dart +++ b/packages/remix/lib/src/components/toast/toast_widget.dart @@ -31,18 +31,18 @@ class Toast extends StatelessWidget { return spec.container( child: spec.containerFlex( + direction: Axis.horizontal, children: [ if (leading != null) leading!, spec.textContentFlex( + direction: Axis.vertical, children: [ spec.title(title), if (description != null) spec.description(description!), ], - direction: Axis.vertical, ), if (trailing != null) trailing!, ], - direction: Axis.horizontal, ), ); }, diff --git a/packages/remix/lib/src/theme/remix_theme.dart b/packages/remix/lib/src/theme/remix_theme.dart index 107b45af6..3384b8941 100644 --- a/packages/remix/lib/src/theme/remix_theme.dart +++ b/packages/remix/lib/src/theme/remix_theme.dart @@ -311,13 +311,13 @@ class RemixTheme extends StatelessWidget { final tokens = theme.tokens; return MixTheme( - child: _RemixThemeInherited(child: child, data: theme), data: MixThemeData( colors: tokens.colors, spaces: tokens.spaces, textStyles: tokens.textStyles, radii: tokens.radii, ), + child: _RemixThemeInherited(data: theme, child: child), ); } } From 90d2a11f634a6cbb4e229734973e660064d97aa3 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Thu, 14 Nov 2024 14:04:36 -0300 Subject: [PATCH 10/11] lint: add key and spec as first --- lints_with_dcm.yaml | 3 +++ packages/mix/lib/src/specs/box/box_widget.dart | 2 +- packages/mix/lib/src/specs/flex/flex_widget.dart | 2 +- packages/mix/lib/src/specs/flexbox/flexbox_widget.dart | 2 +- packages/mix/lib/src/specs/icon/icon_widget.dart | 2 +- packages/mix/lib/src/specs/image/image_widget.dart | 2 +- packages/mix/lib/src/specs/stack/stack_widget.dart | 2 +- packages/mix/lib/src/specs/text/text_widget.dart | 2 +- packages/remix/lib/src/components/button/button.dart | 2 +- packages/remix/lib/src/components/button/button_widget.dart | 2 +- 10 files changed, 12 insertions(+), 9 deletions(-) diff --git a/lints_with_dcm.yaml b/lints_with_dcm.yaml index cf27c31cc..05262ac5b 100644 --- a/lints_with_dcm.yaml +++ b/lints_with_dcm.yaml @@ -25,6 +25,9 @@ dart_code_metrics: prefer-prefixed-global-constants: false avoid-returning-widgets: false arguments-ordering: + first: + - key + - spec last: - child - children diff --git a/packages/mix/lib/src/specs/box/box_widget.dart b/packages/mix/lib/src/specs/box/box_widget.dart index d5e8ab6f9..37b7b893b 100644 --- a/packages/mix/lib/src/specs/box/box_widget.dart +++ b/packages/mix/lib/src/specs/box/box_widget.dart @@ -74,8 +74,8 @@ class BoxSpecWidget extends StatelessWidget { @override Widget build(BuildContext context) { return RenderSpecModifiers( - orderOfModifiers: orderOfModifiers, spec: spec ?? const BoxSpec(), + orderOfModifiers: orderOfModifiers, child: Container( alignment: spec?.alignment, padding: spec?.padding, diff --git a/packages/mix/lib/src/specs/flex/flex_widget.dart b/packages/mix/lib/src/specs/flex/flex_widget.dart index b30a925de..ca9d5817e 100644 --- a/packages/mix/lib/src/specs/flex/flex_widget.dart +++ b/packages/mix/lib/src/specs/flex/flex_widget.dart @@ -98,8 +98,8 @@ class FlexSpecWidget extends StatelessWidget { return spec == null ? flexWidget : RenderSpecModifiers( - orderOfModifiers: orderOfModifiers, spec: spec!, + orderOfModifiers: orderOfModifiers, child: flexWidget, ); } diff --git a/packages/mix/lib/src/specs/flexbox/flexbox_widget.dart b/packages/mix/lib/src/specs/flexbox/flexbox_widget.dart index 22b6fb3e9..db109b4bb 100644 --- a/packages/mix/lib/src/specs/flexbox/flexbox_widget.dart +++ b/packages/mix/lib/src/specs/flexbox/flexbox_widget.dart @@ -88,8 +88,8 @@ class FlexBoxSpecWidget extends StatelessWidget { // it should be implemented following the same pattern as the others SpecWidgets. // This code must be like this to keep the existing animation API working. return RenderSpecModifiers( - orderOfModifiers: orderOfModifiers, spec: spec, + orderOfModifiers: orderOfModifiers, child: spec.box( orderOfModifiers: orderOfModifiers, child: spec.flex(direction: direction, children: children), diff --git a/packages/mix/lib/src/specs/icon/icon_widget.dart b/packages/mix/lib/src/specs/icon/icon_widget.dart index dbd8f3193..195a29f11 100644 --- a/packages/mix/lib/src/specs/icon/icon_widget.dart +++ b/packages/mix/lib/src/specs/icon/icon_widget.dart @@ -75,8 +75,8 @@ class IconSpecWidget extends StatelessWidget { @override Widget build(BuildContext context) { return RenderSpecModifiers( - orderOfModifiers: orderOfModifiers, spec: spec ?? const IconSpec(), + orderOfModifiers: orderOfModifiers, child: Icon( icon, size: spec?.size, diff --git a/packages/mix/lib/src/specs/image/image_widget.dart b/packages/mix/lib/src/specs/image/image_widget.dart index 6f25d0543..cca7620d6 100644 --- a/packages/mix/lib/src/specs/image/image_widget.dart +++ b/packages/mix/lib/src/specs/image/image_widget.dart @@ -105,8 +105,8 @@ class ImageSpecWidget extends StatelessWidget { @override Widget build(BuildContext context) { return RenderSpecModifiers( - orderOfModifiers: orderOfModifiers, spec: spec ?? const ImageSpec(), + orderOfModifiers: orderOfModifiers, child: Image( image: image, frameBuilder: frameBuilder, diff --git a/packages/mix/lib/src/specs/stack/stack_widget.dart b/packages/mix/lib/src/specs/stack/stack_widget.dart index 187c82173..31853eb16 100644 --- a/packages/mix/lib/src/specs/stack/stack_widget.dart +++ b/packages/mix/lib/src/specs/stack/stack_widget.dart @@ -56,8 +56,8 @@ class StackSpecWidget extends StatelessWidget { Widget build(BuildContext context) { // The Stack widget is used here, applying the resolved styles from StackSpec. return RenderSpecModifiers( - orderOfModifiers: orderOfModifiers, spec: spec ?? const StackSpec(), + orderOfModifiers: orderOfModifiers, child: Stack( alignment: spec?.alignment ?? _defaultStack.alignment, textDirection: spec?.textDirection, diff --git a/packages/mix/lib/src/specs/text/text_widget.dart b/packages/mix/lib/src/specs/text/text_widget.dart index 75de9aeb2..97db1a0be 100644 --- a/packages/mix/lib/src/specs/text/text_widget.dart +++ b/packages/mix/lib/src/specs/text/text_widget.dart @@ -92,8 +92,8 @@ class TextSpecWidget extends StatelessWidget { Widget build(BuildContext context) { // The Text widget is used here, applying the resolved styles and properties from TextSpec. return RenderSpecModifiers( - orderOfModifiers: const [], spec: spec ?? const TextSpec(), + orderOfModifiers: const [], child: Text( spec?.directive?.apply(text) ?? text, style: spec?.style, diff --git a/packages/remix/lib/src/components/button/button.dart b/packages/remix/lib/src/components/button/button.dart index 5f96bae3f..1b4e633c2 100644 --- a/packages/remix/lib/src/components/button/button.dart +++ b/packages/remix/lib/src/components/button/button.dart @@ -52,6 +52,7 @@ class ButtonSpec extends Spec with _$ButtonSpec, Diagnosticable { }) { return ButtonSpecWidget( key: key, + spec: this, label: label, disabled: disabled, loading: loading, @@ -59,7 +60,6 @@ class ButtonSpec extends Spec with _$ButtonSpec, Diagnosticable { iconRight: iconRight, spinnerBuilder: spinnerBuilder, onPressed: onPressed, - spec: this, ); } diff --git a/packages/remix/lib/src/components/button/button_widget.dart b/packages/remix/lib/src/components/button/button_widget.dart index fad00358b..c322587e5 100644 --- a/packages/remix/lib/src/components/button/button_widget.dart +++ b/packages/remix/lib/src/components/button/button_widget.dart @@ -62,6 +62,7 @@ class Button extends StatelessWidget { ]), builder: (context) { return ButtonSpecWidget( + spec: ButtonSpec.of(context), label: label, disabled: disabled, loading: loading, @@ -69,7 +70,6 @@ class Button extends StatelessWidget { iconRight: iconRight, spinnerBuilder: spinnerBuilder, onPressed: onPressed, - spec: ButtonSpec.of(context), ); }, ), From 753f8a8fc89611fa6f46a660d16d30cd3efe69a4 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Thu, 14 Nov 2024 14:04:59 -0300 Subject: [PATCH 11/11] add key as first --- .../lib/src/core/factory/style_widgets_ext.dart | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/mix/lib/src/core/factory/style_widgets_ext.dart b/packages/mix/lib/src/core/factory/style_widgets_ext.dart index d4478b7f3..d060e00d1 100644 --- a/packages/mix/lib/src/core/factory/style_widgets_ext.dart +++ b/packages/mix/lib/src/core/factory/style_widgets_ext.dart @@ -16,8 +16,8 @@ extension StyleExt on Style { Style? style, }) { return Box( - style: merge(style), key: key, + style: merge(style), inherit: inherit, child: child, ); @@ -29,7 +29,7 @@ extension StyleExt on Style { Key? key, Style? style, }) { - return container(inherit: inherit, key: key, style: style, child: child); + return container(key: key, inherit: inherit, style: style, child: child); } HBox hbox({ @@ -39,8 +39,8 @@ extension StyleExt on Style { Style? style, }) { return HBox( - style: merge(style), key: key, + style: merge(style), inherit: inherit, children: children, ); @@ -53,8 +53,8 @@ extension StyleExt on Style { Style? style, }) { return StyledRow( - style: merge(style), key: key, + style: merge(style), inherit: inherit, children: children, ); @@ -69,9 +69,9 @@ extension StyleExt on Style { }) { return StyledText( text, + key: key, semanticsLabel: semanticsLabel, style: merge(style), - key: key, inherit: inherit, ); } @@ -83,8 +83,8 @@ extension StyleExt on Style { Style? style, }) { return VBox( - style: merge(style), key: key, + style: merge(style), inherit: inherit, children: children, ); @@ -97,8 +97,8 @@ extension StyleExt on Style { Style? style, }) { return StyledColumn( - style: merge(style), key: key, + style: merge(style), inherit: inherit, children: children, ); @@ -110,6 +110,6 @@ extension StyleExt on Style { Key? key, Style? style, }) { - return StyledIcon(icon, style: merge(style), key: key, inherit: inherit); + return StyledIcon(icon, key: key, style: merge(style), inherit: inherit); } }