From 692d010d0c7957e1130c2b10a17cc8e28ee983ca Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Wed, 18 Dec 2024 15:34:07 -0300 Subject: [PATCH] create select trigger --- .../remix/demo/lib/components/select.dart | 12 +- .../lib/src/components/select/select.dart | 13 +- .../lib/src/components/select/select.g.dart | 403 +++++++++--------- .../src/components/select/select_widget.dart | 87 ++-- .../select_trigger.dart} | 17 +- .../select_trigger_widget.dart} | 11 +- 6 files changed, 256 insertions(+), 287 deletions(-) rename packages/remix/lib/src/components/select/{button/select_button.dart => trigger/select_trigger.dart} (58%) rename packages/remix/lib/src/components/select/{button/select_button_widget.dart => trigger/select_trigger_widget.dart} (84%) diff --git a/packages/remix/demo/lib/components/select.dart b/packages/remix/demo/lib/components/select.dart index 7b22e886e..41d90fa34 100644 --- a/packages/remix/demo/lib/components/select.dart +++ b/packages/remix/demo/lib/components/select.dart @@ -1,5 +1,4 @@ import 'package:demo/helpers/knob_builder.dart'; -import 'package:flutter/material.dart' as m; import 'package:flutter/widgets.dart'; import 'package:remix/remix.dart'; import 'package:remix/themes/fortaleza.dart'; @@ -43,13 +42,12 @@ class _SelectDemoState extends State { child: Select( value: selectedValue, onChanged: (value) => setState(() => selectedValue = value), - trigger: (spec) => spec( + trigger: SelectTrigger( text: selectedValue, - trailingIcon: m.Icons.keyboard_arrow_down_rounded, - ), - disabled: context.knobs.boolean( - label: 'disabled', - initialValue: false, + disabled: context.knobs.boolean( + label: 'disabled', + initialValue: false, + ), ), variants: [context.knobs.variant(FortalezaSelectStyle.variants)], items: List.generate( diff --git a/packages/remix/lib/src/components/select/select.dart b/packages/remix/lib/src/components/select/select.dart index b90d3adab..ce8c18c11 100644 --- a/packages/remix/lib/src/components/select/select.dart +++ b/packages/remix/lib/src/components/select/select.dart @@ -4,23 +4,22 @@ import 'package:mix/mix.dart'; import 'package:mix_annotations/mix_annotations.dart'; import '../../core/theme/remix_theme.dart'; -import '../../helpers/component_builder.dart'; import '../../helpers/object_ext.dart'; import '../../helpers/overlay.dart'; import '../../helpers/spec/composited_transform_follower_spec.dart'; -part 'button/select_button.dart'; -part 'button/select_button_widget.dart'; part 'item/select_menu.dart'; part 'item/select_menu_widget.dart'; part 'select.g.dart'; part 'select_style.dart'; part 'select_widget.dart'; +part 'trigger/select_trigger.dart'; +part 'trigger/select_trigger_widget.dart'; @MixableSpec() class SelectSpec extends Spec with _$SelectSpec, Diagnosticable { - @MixableProperty(dto: MixableFieldDto(type: 'SelectButtonSpecAttribute')) - final SelectButtonSpec button; + @MixableProperty(dto: MixableFieldDto(type: 'SelectTriggerSpecAttribute')) + final SelectTriggerSpec button; @MixableProperty(dto: MixableFieldDto(type: 'SelectMenuSpecAttribute')) final SelectMenuSpec menu; @@ -39,13 +38,13 @@ class SelectSpec extends Spec with _$SelectSpec, Diagnosticable { static const from = _$SelectSpec.from; const SelectSpec({ - SelectButtonSpec? button, + SelectTriggerSpec? button, SelectMenuSpec? menu, SelectMenuItemSpec? item, CompositedTransformFollowerSpec? position, super.modifiers, super.animated, - }) : button = button ?? const SelectButtonSpec(), + }) : button = button ?? const SelectTriggerSpec(), item = item ?? const SelectMenuItemSpec(), menu = menu ?? const SelectMenuSpec(), position = position ?? const CompositedTransformFollowerSpec(); diff --git a/packages/remix/lib/src/components/select/select.g.dart b/packages/remix/lib/src/components/select/select.g.dart index ebfb688ce..886584c74 100644 --- a/packages/remix/lib/src/components/select/select.g.dart +++ b/packages/remix/lib/src/components/select/select.g.dart @@ -33,7 +33,7 @@ mixin _$SelectSpec on Spec { /// replaced with the new values. @override SelectSpec copyWith({ - SelectButtonSpec? button, + SelectTriggerSpec? button, SelectMenuSpec? menu, SelectMenuItemSpec? item, CompositedTransformFollowerSpec? position, @@ -123,7 +123,7 @@ mixin _$SelectSpec on Spec { /// the [SelectSpec] constructor. class SelectSpecAttribute extends SpecAttribute with Diagnosticable { - final SelectButtonSpecAttribute? button; + final SelectTriggerSpecAttribute? button; final SelectMenuSpecAttribute? menu; final SelectMenuItemSpecAttribute? item; final CompositedTransformFollowerSpecAttribute? position; @@ -215,7 +215,7 @@ class SelectSpecAttribute extends SpecAttribute class SelectSpecUtility extends SpecUtility { /// Utility for defining [SelectSpecAttribute.button] - late final button = SelectButtonSpecUtility((v) => only(button: v)); + late final button = SelectTriggerSpecUtility((v) => only(button: v)); /// Utility for defining [SelectSpecAttribute.menu] late final menu = SelectMenuSpecUtility((v) => only(menu: v)); @@ -244,7 +244,7 @@ class SelectSpecUtility /// Returns a new [SelectSpecAttribute] with the specified properties. @override T only({ - SelectButtonSpecAttribute? button, + SelectTriggerSpecAttribute? button, SelectMenuSpecAttribute? menu, SelectMenuItemSpecAttribute? item, CompositedTransformFollowerSpecAttribute? position, @@ -533,104 +533,104 @@ class SelectMenuSpecTween extends Tween { } } -mixin _$SelectButtonSpec on Spec { - static SelectButtonSpec from(MixData mix) { - return mix.attributeOf()?.resolve(mix) ?? - const SelectButtonSpec(); +mixin _$SelectMenuItemSpec on Spec { + static SelectMenuItemSpec from(MixData mix) { + return mix.attributeOf()?.resolve(mix) ?? + const SelectMenuItemSpec(); } - /// {@template select_button_spec_of} - /// Retrieves the [SelectButtonSpec] from the nearest [Mix] ancestor in the widget tree. + /// {@template select_menu_item_spec_of} + /// Retrieves the [SelectMenuItemSpec] 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 [SelectButtonSpec] from that [Mix]. - /// If no ancestor [Mix] is found, this method returns an empty [SelectButtonSpec]. + /// given [BuildContext], and then retrieves the [SelectMenuItemSpec] from that [Mix]. + /// If no ancestor [Mix] is found, this method returns an empty [SelectMenuItemSpec]. /// /// Example: /// /// ```dart - /// final selectButtonSpec = SelectButtonSpec.of(context); + /// final selectMenuItemSpec = SelectMenuItemSpec.of(context); /// ``` /// {@endtemplate} - static SelectButtonSpec of(BuildContext context) { - return _$SelectButtonSpec.from(Mix.of(context)); + static SelectMenuItemSpec of(BuildContext context) { + return _$SelectMenuItemSpec.from(Mix.of(context)); } - /// Creates a copy of this [SelectButtonSpec] but with the given fields + /// Creates a copy of this [SelectMenuItemSpec] but with the given fields /// replaced with the new values. @override - SelectButtonSpec copyWith({ - FlexBoxSpec? container, + SelectMenuItemSpec copyWith({ IconSpec? icon, - TextSpec? label, + TextSpec? text, + FlexBoxSpec? container, WidgetModifiersData? modifiers, AnimatedData? animated, }) { - return SelectButtonSpec( - container: container ?? _$this.container, + return SelectMenuItemSpec( icon: icon ?? _$this.icon, - label: label ?? _$this.label, + text: text ?? _$this.text, + container: container ?? _$this.container, modifiers: modifiers ?? _$this.modifiers, animated: animated ?? _$this.animated, ); } - /// Linearly interpolates between this [SelectButtonSpec] and another [SelectButtonSpec] based on the given parameter [t]. + /// Linearly interpolates between this [SelectMenuItemSpec] and another [SelectMenuItemSpec] 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 [SelectButtonSpec] is returned. When [t] is 1.0, the [other] [SelectButtonSpec] is returned. - /// For values of [t] between 0.0 and 1.0, an interpolated [SelectButtonSpec] is returned. + /// When [t] is 0.0, the current [SelectMenuItemSpec] is returned. When [t] is 1.0, the [other] [SelectMenuItemSpec] is returned. + /// For values of [t] between 0.0 and 1.0, an interpolated [SelectMenuItemSpec] is returned. /// - /// If [other] is null, this method returns the current [SelectButtonSpec] instance. + /// If [other] is null, this method returns the current [SelectMenuItemSpec] instance. /// - /// The interpolation is performed on each property of the [SelectButtonSpec] using the appropriate + /// The interpolation is performed on each property of the [SelectMenuItemSpec] using the appropriate /// interpolation method: /// - /// - [FlexBoxSpec.lerp] for [container]. /// - [IconSpec.lerp] for [icon]. - /// - [TextSpec.lerp] for [label]. + /// - [TextSpec.lerp] for [text]. + /// - [FlexBoxSpec.lerp] for [container]. /// For [modifiers] and [animated], the interpolation is performed using a step function. - /// If [t] is less than 0.5, the value from the current [SelectButtonSpec] is used. Otherwise, the value - /// from the [other] [SelectButtonSpec] is used. + /// If [t] is less than 0.5, the value from the current [SelectMenuItemSpec] is used. Otherwise, the value + /// from the [other] [SelectMenuItemSpec] is used. /// /// This method is typically used in animations to smoothly transition between - /// different [SelectButtonSpec] configurations. + /// different [SelectMenuItemSpec] configurations. @override - SelectButtonSpec lerp(SelectButtonSpec? other, double t) { + SelectMenuItemSpec lerp(SelectMenuItemSpec? other, double t) { if (other == null) return _$this; - return SelectButtonSpec( - container: _$this.container.lerp(other.container, t), + return SelectMenuItemSpec( icon: _$this.icon.lerp(other.icon, t), - label: _$this.label.lerp(other.label, t), + text: _$this.text.lerp(other.text, t), + container: _$this.container.lerp(other.container, t), modifiers: other.modifiers, animated: t < 0.5 ? _$this.animated : other.animated, ); } - /// The list of properties that constitute the state of this [SelectButtonSpec]. + /// The list of properties that constitute the state of this [SelectMenuItemSpec]. /// /// This property is used by the [==] operator and the [hashCode] getter to - /// compare two [SelectButtonSpec] instances for equality. + /// compare two [SelectMenuItemSpec] instances for equality. @override List get props => [ - _$this.container, _$this.icon, - _$this.label, + _$this.text, + _$this.container, _$this.modifiers, _$this.animated, ]; - SelectButtonSpec get _$this => this as SelectButtonSpec; + SelectMenuItemSpec get _$this => this as SelectMenuItemSpec; void _debugFillProperties(DiagnosticPropertiesBuilder properties) { - properties.add( - DiagnosticsProperty('container', _$this.container, defaultValue: null)); properties .add(DiagnosticsProperty('icon', _$this.icon, defaultValue: null)); properties - .add(DiagnosticsProperty('label', _$this.label, defaultValue: null)); + .add(DiagnosticsProperty('text', _$this.text, defaultValue: null)); + properties.add( + DiagnosticsProperty('container', _$this.container, defaultValue: null)); properties.add( DiagnosticsProperty('modifiers', _$this.modifiers, defaultValue: null)); properties.add( @@ -638,76 +638,77 @@ mixin _$SelectButtonSpec on Spec { } } -/// Represents the attributes of a [SelectButtonSpec]. +/// Represents the attributes of a [SelectMenuItemSpec]. /// /// This class encapsulates properties defining the layout and -/// appearance of a [SelectButtonSpec]. +/// appearance of a [SelectMenuItemSpec]. /// -/// Use this class to configure the attributes of a [SelectButtonSpec] and pass it to -/// the [SelectButtonSpec] constructor. -class SelectButtonSpecAttribute extends SpecAttribute +/// Use this class to configure the attributes of a [SelectMenuItemSpec] and pass it to +/// the [SelectMenuItemSpec] constructor. +base class SelectMenuItemSpecAttribute extends SpecAttribute with Diagnosticable { - final FlexBoxSpecAttribute? container; final IconSpecAttribute? icon; - final TextSpecAttribute? label; + final TextSpecAttribute? text; + final FlexBoxSpecAttribute? container; - const SelectButtonSpecAttribute({ - this.container, + const SelectMenuItemSpecAttribute({ this.icon, - this.label, + this.text, + this.container, super.modifiers, super.animated, }); - /// Resolves to [SelectButtonSpec] using the provided [MixData]. + /// Resolves to [SelectMenuItemSpec] 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 selectButtonSpec = SelectButtonSpecAttribute(...).resolve(mix); + /// final selectMenuItemSpec = SelectMenuItemSpecAttribute(...).resolve(mix); /// ``` @override - SelectButtonSpec resolve(MixData mix) { - return SelectButtonSpec( - container: container?.resolve(mix), + SelectMenuItemSpec resolve(MixData mix) { + return SelectMenuItemSpec( icon: icon?.resolve(mix), - label: label?.resolve(mix), + text: text?.resolve(mix), + container: container?.resolve(mix), modifiers: modifiers?.resolve(mix), animated: animated?.resolve(mix) ?? mix.animation, ); } - /// Merges the properties of this [SelectButtonSpecAttribute] with the properties of [other]. + /// Merges the properties of this [SelectMenuItemSpecAttribute] with the properties of [other]. /// /// If [other] is null, returns this instance unchanged. Otherwise, returns a new - /// [SelectButtonSpecAttribute] with the properties of [other] taking precedence over + /// [SelectMenuItemSpecAttribute] 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 - SelectButtonSpecAttribute merge(covariant SelectButtonSpecAttribute? other) { + SelectMenuItemSpecAttribute merge( + covariant SelectMenuItemSpecAttribute? other) { if (other == null) return this; - return SelectButtonSpecAttribute( - container: container?.merge(other.container) ?? other.container, + return SelectMenuItemSpecAttribute( icon: icon?.merge(other.icon) ?? other.icon, - label: label?.merge(other.label) ?? other.label, + text: text?.merge(other.text) ?? other.text, + container: container?.merge(other.container) ?? other.container, modifiers: modifiers?.merge(other.modifiers) ?? other.modifiers, animated: animated?.merge(other.animated) ?? other.animated, ); } - /// The list of properties that constitute the state of this [SelectButtonSpecAttribute]. + /// The list of properties that constitute the state of this [SelectMenuItemSpecAttribute]. /// /// This property is used by the [==] operator and the [hashCode] getter to - /// compare two [SelectButtonSpecAttribute] instances for equality. + /// compare two [SelectMenuItemSpecAttribute] instances for equality. @override List get props => [ - container, icon, - label, + text, + container, modifiers, animated, ]; @@ -715,10 +716,10 @@ class SelectButtonSpecAttribute extends SpecAttribute @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('icon', icon, defaultValue: null)); + properties.add(DiagnosticsProperty('text', text, defaultValue: null)); properties .add(DiagnosticsProperty('container', container, defaultValue: null)); - properties.add(DiagnosticsProperty('icon', icon, defaultValue: null)); - properties.add(DiagnosticsProperty('label', label, defaultValue: null)); properties .add(DiagnosticsProperty('modifiers', modifiers, defaultValue: null)); properties @@ -726,68 +727,68 @@ class SelectButtonSpecAttribute extends SpecAttribute } } -/// Utility class for configuring [SelectButtonSpec] properties. +/// Utility class for configuring [SelectMenuItemSpec] properties. /// -/// This class provides methods to set individual properties of a [SelectButtonSpec]. -/// Use the methods of this class to configure specific properties of a [SelectButtonSpec]. -class SelectButtonSpecUtility - extends SpecUtility { - /// Utility for defining [SelectButtonSpecAttribute.container] - late final container = FlexBoxSpecUtility((v) => only(container: v)); - - /// Utility for defining [SelectButtonSpecAttribute.icon] +/// This class provides methods to set individual properties of a [SelectMenuItemSpec]. +/// Use the methods of this class to configure specific properties of a [SelectMenuItemSpec]. +class SelectMenuItemSpecUtility + extends SpecUtility { + /// Utility for defining [SelectMenuItemSpecAttribute.icon] late final icon = IconSpecUtility((v) => only(icon: v)); - /// Utility for defining [SelectButtonSpecAttribute.label] - late final label = TextSpecUtility((v) => only(label: v)); + /// Utility for defining [SelectMenuItemSpecAttribute.text] + late final text = TextSpecUtility((v) => only(text: v)); + + /// Utility for defining [SelectMenuItemSpecAttribute.container] + late final container = FlexBoxSpecUtility((v) => only(container: v)); - /// Utility for defining [SelectButtonSpecAttribute.modifiers] + /// Utility for defining [SelectMenuItemSpecAttribute.modifiers] late final wrap = SpecModifierUtility((v) => only(modifiers: v)); - /// Utility for defining [SelectButtonSpecAttribute.animated] + /// Utility for defining [SelectMenuItemSpecAttribute.animated] late final animated = AnimatedUtility((v) => only(animated: v)); - SelectButtonSpecUtility(super.builder, {super.mutable}); + SelectMenuItemSpecUtility(super.builder, {super.mutable}); - SelectButtonSpecUtility get chain => - SelectButtonSpecUtility(attributeBuilder, mutable: true); + SelectMenuItemSpecUtility get chain => + SelectMenuItemSpecUtility(attributeBuilder, mutable: true); - static SelectButtonSpecUtility get self => - SelectButtonSpecUtility((v) => v); + static SelectMenuItemSpecUtility get self => + SelectMenuItemSpecUtility((v) => v); - /// Returns a new [SelectButtonSpecAttribute] with the specified properties. + /// Returns a new [SelectMenuItemSpecAttribute] with the specified properties. @override T only({ - FlexBoxSpecAttribute? container, IconSpecAttribute? icon, - TextSpecAttribute? label, + TextSpecAttribute? text, + FlexBoxSpecAttribute? container, WidgetModifiersDataDto? modifiers, AnimatedDataDto? animated, }) { - return builder(SelectButtonSpecAttribute( - container: container, + return builder(SelectMenuItemSpecAttribute( icon: icon, - label: label, + text: text, + container: container, modifiers: modifiers, animated: animated, )); } } -/// A tween that interpolates between two [SelectButtonSpec] instances. +/// A tween that interpolates between two [SelectMenuItemSpec] instances. /// /// This class can be used in animations to smoothly transition between -/// different [SelectButtonSpec] specifications. -class SelectButtonSpecTween extends Tween { - SelectButtonSpecTween({ +/// different [SelectMenuItemSpec] specifications. +class SelectMenuItemSpecTween extends Tween { + SelectMenuItemSpecTween({ super.begin, super.end, }); @override - SelectButtonSpec lerp(double t) { + SelectMenuItemSpec lerp(double t) { if (begin == null && end == null) { - return const SelectButtonSpec(); + return const SelectMenuItemSpec(); } if (begin == null) { @@ -798,104 +799,104 @@ class SelectButtonSpecTween extends Tween { } } -mixin _$SelectMenuItemSpec on Spec { - static SelectMenuItemSpec from(MixData mix) { - return mix.attributeOf()?.resolve(mix) ?? - const SelectMenuItemSpec(); +mixin _$SelectTriggerSpec on Spec { + static SelectTriggerSpec from(MixData mix) { + return mix.attributeOf()?.resolve(mix) ?? + const SelectTriggerSpec(); } - /// {@template select_menu_item_spec_of} - /// Retrieves the [SelectMenuItemSpec] from the nearest [Mix] ancestor in the widget tree. + /// {@template select_trigger_spec_of} + /// Retrieves the [SelectTriggerSpec] 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 [SelectMenuItemSpec] from that [Mix]. - /// If no ancestor [Mix] is found, this method returns an empty [SelectMenuItemSpec]. + /// given [BuildContext], and then retrieves the [SelectTriggerSpec] from that [Mix]. + /// If no ancestor [Mix] is found, this method returns an empty [SelectTriggerSpec]. /// /// Example: /// /// ```dart - /// final selectMenuItemSpec = SelectMenuItemSpec.of(context); + /// final selectTriggerSpec = SelectTriggerSpec.of(context); /// ``` /// {@endtemplate} - static SelectMenuItemSpec of(BuildContext context) { - return _$SelectMenuItemSpec.from(Mix.of(context)); + static SelectTriggerSpec of(BuildContext context) { + return _$SelectTriggerSpec.from(Mix.of(context)); } - /// Creates a copy of this [SelectMenuItemSpec] but with the given fields + /// Creates a copy of this [SelectTriggerSpec] but with the given fields /// replaced with the new values. @override - SelectMenuItemSpec copyWith({ - IconSpec? icon, - TextSpec? text, + SelectTriggerSpec copyWith({ FlexBoxSpec? container, + IconSpec? icon, + TextSpec? label, WidgetModifiersData? modifiers, AnimatedData? animated, }) { - return SelectMenuItemSpec( - icon: icon ?? _$this.icon, - text: text ?? _$this.text, + return SelectTriggerSpec( container: container ?? _$this.container, + icon: icon ?? _$this.icon, + label: label ?? _$this.label, modifiers: modifiers ?? _$this.modifiers, animated: animated ?? _$this.animated, ); } - /// Linearly interpolates between this [SelectMenuItemSpec] and another [SelectMenuItemSpec] based on the given parameter [t]. + /// Linearly interpolates between this [SelectTriggerSpec] and another [SelectTriggerSpec] 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 [SelectMenuItemSpec] is returned. When [t] is 1.0, the [other] [SelectMenuItemSpec] is returned. - /// For values of [t] between 0.0 and 1.0, an interpolated [SelectMenuItemSpec] is returned. + /// When [t] is 0.0, the current [SelectTriggerSpec] is returned. When [t] is 1.0, the [other] [SelectTriggerSpec] is returned. + /// For values of [t] between 0.0 and 1.0, an interpolated [SelectTriggerSpec] is returned. /// - /// If [other] is null, this method returns the current [SelectMenuItemSpec] instance. + /// If [other] is null, this method returns the current [SelectTriggerSpec] instance. /// - /// The interpolation is performed on each property of the [SelectMenuItemSpec] using the appropriate + /// The interpolation is performed on each property of the [SelectTriggerSpec] using the appropriate /// interpolation method: /// - /// - [IconSpec.lerp] for [icon]. - /// - [TextSpec.lerp] for [text]. /// - [FlexBoxSpec.lerp] for [container]. + /// - [IconSpec.lerp] for [icon]. + /// - [TextSpec.lerp] for [label]. /// For [modifiers] and [animated], the interpolation is performed using a step function. - /// If [t] is less than 0.5, the value from the current [SelectMenuItemSpec] is used. Otherwise, the value - /// from the [other] [SelectMenuItemSpec] is used. + /// If [t] is less than 0.5, the value from the current [SelectTriggerSpec] is used. Otherwise, the value + /// from the [other] [SelectTriggerSpec] is used. /// /// This method is typically used in animations to smoothly transition between - /// different [SelectMenuItemSpec] configurations. + /// different [SelectTriggerSpec] configurations. @override - SelectMenuItemSpec lerp(SelectMenuItemSpec? other, double t) { + SelectTriggerSpec lerp(SelectTriggerSpec? other, double t) { if (other == null) return _$this; - return SelectMenuItemSpec( - icon: _$this.icon.lerp(other.icon, t), - text: _$this.text.lerp(other.text, t), + return SelectTriggerSpec( container: _$this.container.lerp(other.container, t), + icon: _$this.icon.lerp(other.icon, t), + label: _$this.label.lerp(other.label, t), modifiers: other.modifiers, animated: t < 0.5 ? _$this.animated : other.animated, ); } - /// The list of properties that constitute the state of this [SelectMenuItemSpec]. + /// The list of properties that constitute the state of this [SelectTriggerSpec]. /// /// This property is used by the [==] operator and the [hashCode] getter to - /// compare two [SelectMenuItemSpec] instances for equality. + /// compare two [SelectTriggerSpec] instances for equality. @override List get props => [ - _$this.icon, - _$this.text, _$this.container, + _$this.icon, + _$this.label, _$this.modifiers, _$this.animated, ]; - SelectMenuItemSpec get _$this => this as SelectMenuItemSpec; + SelectTriggerSpec get _$this => this as SelectTriggerSpec; void _debugFillProperties(DiagnosticPropertiesBuilder properties) { + properties.add( + DiagnosticsProperty('container', _$this.container, defaultValue: null)); properties .add(DiagnosticsProperty('icon', _$this.icon, defaultValue: null)); properties - .add(DiagnosticsProperty('text', _$this.text, defaultValue: null)); - properties.add( - DiagnosticsProperty('container', _$this.container, defaultValue: null)); + .add(DiagnosticsProperty('label', _$this.label, defaultValue: null)); properties.add( DiagnosticsProperty('modifiers', _$this.modifiers, defaultValue: null)); properties.add( @@ -903,77 +904,77 @@ mixin _$SelectMenuItemSpec on Spec { } } -/// Represents the attributes of a [SelectMenuItemSpec]. +/// Represents the attributes of a [SelectTriggerSpec]. /// /// This class encapsulates properties defining the layout and -/// appearance of a [SelectMenuItemSpec]. +/// appearance of a [SelectTriggerSpec]. /// -/// Use this class to configure the attributes of a [SelectMenuItemSpec] and pass it to -/// the [SelectMenuItemSpec] constructor. -base class SelectMenuItemSpecAttribute extends SpecAttribute +/// Use this class to configure the attributes of a [SelectTriggerSpec] and pass it to +/// the [SelectTriggerSpec] constructor. +class SelectTriggerSpecAttribute extends SpecAttribute with Diagnosticable { - final IconSpecAttribute? icon; - final TextSpecAttribute? text; final FlexBoxSpecAttribute? container; + final IconSpecAttribute? icon; + final TextSpecAttribute? label; - const SelectMenuItemSpecAttribute({ - this.icon, - this.text, + const SelectTriggerSpecAttribute({ this.container, + this.icon, + this.label, super.modifiers, super.animated, }); - /// Resolves to [SelectMenuItemSpec] using the provided [MixData]. + /// Resolves to [SelectTriggerSpec] 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 selectMenuItemSpec = SelectMenuItemSpecAttribute(...).resolve(mix); + /// final selectTriggerSpec = SelectTriggerSpecAttribute(...).resolve(mix); /// ``` @override - SelectMenuItemSpec resolve(MixData mix) { - return SelectMenuItemSpec( - icon: icon?.resolve(mix), - text: text?.resolve(mix), + SelectTriggerSpec resolve(MixData mix) { + return SelectTriggerSpec( container: container?.resolve(mix), + icon: icon?.resolve(mix), + label: label?.resolve(mix), modifiers: modifiers?.resolve(mix), animated: animated?.resolve(mix) ?? mix.animation, ); } - /// Merges the properties of this [SelectMenuItemSpecAttribute] with the properties of [other]. + /// Merges the properties of this [SelectTriggerSpecAttribute] with the properties of [other]. /// /// If [other] is null, returns this instance unchanged. Otherwise, returns a new - /// [SelectMenuItemSpecAttribute] with the properties of [other] taking precedence over + /// [SelectTriggerSpecAttribute] 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 - SelectMenuItemSpecAttribute merge( - covariant SelectMenuItemSpecAttribute? other) { + SelectTriggerSpecAttribute merge( + covariant SelectTriggerSpecAttribute? other) { if (other == null) return this; - return SelectMenuItemSpecAttribute( - icon: icon?.merge(other.icon) ?? other.icon, - text: text?.merge(other.text) ?? other.text, + return SelectTriggerSpecAttribute( container: container?.merge(other.container) ?? other.container, + icon: icon?.merge(other.icon) ?? other.icon, + label: label?.merge(other.label) ?? other.label, modifiers: modifiers?.merge(other.modifiers) ?? other.modifiers, animated: animated?.merge(other.animated) ?? other.animated, ); } - /// The list of properties that constitute the state of this [SelectMenuItemSpecAttribute]. + /// The list of properties that constitute the state of this [SelectTriggerSpecAttribute]. /// /// This property is used by the [==] operator and the [hashCode] getter to - /// compare two [SelectMenuItemSpecAttribute] instances for equality. + /// compare two [SelectTriggerSpecAttribute] instances for equality. @override List get props => [ - icon, - text, container, + icon, + label, modifiers, animated, ]; @@ -981,10 +982,10 @@ base class SelectMenuItemSpecAttribute extends SpecAttribute @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('icon', icon, defaultValue: null)); - properties.add(DiagnosticsProperty('text', text, defaultValue: null)); properties .add(DiagnosticsProperty('container', container, defaultValue: null)); + properties.add(DiagnosticsProperty('icon', icon, defaultValue: null)); + properties.add(DiagnosticsProperty('label', label, defaultValue: null)); properties .add(DiagnosticsProperty('modifiers', modifiers, defaultValue: null)); properties @@ -992,68 +993,68 @@ base class SelectMenuItemSpecAttribute extends SpecAttribute } } -/// Utility class for configuring [SelectMenuItemSpec] properties. +/// Utility class for configuring [SelectTriggerSpec] properties. /// -/// This class provides methods to set individual properties of a [SelectMenuItemSpec]. -/// Use the methods of this class to configure specific properties of a [SelectMenuItemSpec]. -class SelectMenuItemSpecUtility - extends SpecUtility { - /// Utility for defining [SelectMenuItemSpecAttribute.icon] - late final icon = IconSpecUtility((v) => only(icon: v)); +/// This class provides methods to set individual properties of a [SelectTriggerSpec]. +/// Use the methods of this class to configure specific properties of a [SelectTriggerSpec]. +class SelectTriggerSpecUtility + extends SpecUtility { + /// Utility for defining [SelectTriggerSpecAttribute.container] + late final container = FlexBoxSpecUtility((v) => only(container: v)); - /// Utility for defining [SelectMenuItemSpecAttribute.text] - late final text = TextSpecUtility((v) => only(text: v)); + /// Utility for defining [SelectTriggerSpecAttribute.icon] + late final icon = IconSpecUtility((v) => only(icon: v)); - /// Utility for defining [SelectMenuItemSpecAttribute.container] - late final container = FlexBoxSpecUtility((v) => only(container: v)); + /// Utility for defining [SelectTriggerSpecAttribute.label] + late final label = TextSpecUtility((v) => only(label: v)); - /// Utility for defining [SelectMenuItemSpecAttribute.modifiers] + /// Utility for defining [SelectTriggerSpecAttribute.modifiers] late final wrap = SpecModifierUtility((v) => only(modifiers: v)); - /// Utility for defining [SelectMenuItemSpecAttribute.animated] + /// Utility for defining [SelectTriggerSpecAttribute.animated] late final animated = AnimatedUtility((v) => only(animated: v)); - SelectMenuItemSpecUtility(super.builder, {super.mutable}); + SelectTriggerSpecUtility(super.builder, {super.mutable}); - SelectMenuItemSpecUtility get chain => - SelectMenuItemSpecUtility(attributeBuilder, mutable: true); + SelectTriggerSpecUtility get chain => + SelectTriggerSpecUtility(attributeBuilder, mutable: true); - static SelectMenuItemSpecUtility get self => - SelectMenuItemSpecUtility((v) => v); + static SelectTriggerSpecUtility get self => + SelectTriggerSpecUtility((v) => v); - /// Returns a new [SelectMenuItemSpecAttribute] with the specified properties. + /// Returns a new [SelectTriggerSpecAttribute] with the specified properties. @override T only({ - IconSpecAttribute? icon, - TextSpecAttribute? text, FlexBoxSpecAttribute? container, + IconSpecAttribute? icon, + TextSpecAttribute? label, WidgetModifiersDataDto? modifiers, AnimatedDataDto? animated, }) { - return builder(SelectMenuItemSpecAttribute( - icon: icon, - text: text, + return builder(SelectTriggerSpecAttribute( container: container, + icon: icon, + label: label, modifiers: modifiers, animated: animated, )); } } -/// A tween that interpolates between two [SelectMenuItemSpec] instances. +/// A tween that interpolates between two [SelectTriggerSpec] instances. /// /// This class can be used in animations to smoothly transition between -/// different [SelectMenuItemSpec] specifications. -class SelectMenuItemSpecTween extends Tween { - SelectMenuItemSpecTween({ +/// different [SelectTriggerSpec] specifications. +class SelectTriggerSpecTween extends Tween { + SelectTriggerSpecTween({ super.begin, super.end, }); @override - SelectMenuItemSpec lerp(double t) { + SelectTriggerSpec lerp(double t) { if (begin == null && end == null) { - return const SelectMenuItemSpec(); + return const SelectTriggerSpec(); } if (begin == null) { diff --git a/packages/remix/lib/src/components/select/select_widget.dart b/packages/remix/lib/src/components/select/select_widget.dart index 16ce7fd74..f8c20d739 100644 --- a/packages/remix/lib/src/components/select/select_widget.dart +++ b/packages/remix/lib/src/components/select/select_widget.dart @@ -16,7 +16,6 @@ class Select extends StatefulWidget { required this.items, this.variants = const [], this.style, - this.disabled = false, }); /// The currently selected value in the select component. @@ -34,10 +33,7 @@ class Select extends StatefulWidget { /// Builder function that creates the button portion of the select component. /// When tapped, this button will display the dropdown menu. /// This allows customizing how the button is displayed. - final WidgetSpecBuilder trigger; - - /// {@macro remix.component.disabled} - final bool disabled; + final SelectTrigger trigger; /// The list of items to display in the dropdown menu. /// Each item contains a value and widget to display. @@ -49,7 +45,6 @@ class Select extends StatefulWidget { class SelectState extends State> { late final MixWidgetStateController _menuStateController; - late final MixWidgetStateController _buttonStateController; final _link = LayerLink(); @@ -58,15 +53,6 @@ class SelectState extends State> { super.initState(); _menuStateController = MixWidgetStateController()..selected = false; - _buttonStateController = MixWidgetStateController() - ..disabled = widget.disabled; - } - - @override - void didUpdateWidget(covariant Select oldWidget) { - super.didUpdateWidget(oldWidget); - - _buttonStateController.disabled = widget.disabled; } void openMenu() { @@ -83,7 +69,6 @@ class SelectState extends State> { @override void dispose() { - _buttonStateController.dispose(); _menuStateController.dispose(); super.dispose(); } @@ -98,50 +83,42 @@ class SelectState extends State> { final animatedStyle = appliedStyle.cast(); return OverlayWrapper( - target: RepaintBoundary( + target: widget.trigger, + overlayChild: RepaintBoundary( child: SpecBuilder( - controller: _buttonStateController, + controller: _menuStateController, style: appliedStyle, builder: (context) { - final buttonSpec = SelectSpec.of(context).button; - - return widget.trigger(buttonSpec); - }, - ), - ), - overlayChild: SpecBuilder( - controller: _menuStateController, - style: appliedStyle, - builder: (context) { - final select = SelectSpec.of(context); - final menu = select.menu; - - final FlexContainer = menu.container.copyWith( - box: menu.container.box.copyWith( - width: menu.autoWidth ? _link.leaderSize!.width : null, - ), - ); - - return FlexContainer( - direction: Axis.vertical, - children: widget.items - .map( - (item) => Pressable( - onPress: () { - widget.onChanged(item.value); - closeMenu(); - }, - child: SpecBuilder( - style: appliedStyle, - builder: (context) { - return item.child; + final select = SelectSpec.of(context); + final menu = select.menu; + + final FlexContainer = menu.container.copyWith( + box: menu.container.box.copyWith( + width: menu.autoWidth ? _link.leaderSize!.width : null, + ), + ); + + return FlexContainer( + direction: Axis.vertical, + children: widget.items + .map( + (item) => Pressable( + onPress: () { + widget.onChanged(item.value); + closeMenu(); }, + child: SpecBuilder( + style: appliedStyle, + builder: (context) { + return item.child; + }, + ), ), - ), - ) - .toList(), - ); - }, + ) + .toList(), + ); + }, + ), ), onTapOutside: closeMenu, showOverlay: _menuStateController.selected, diff --git a/packages/remix/lib/src/components/select/button/select_button.dart b/packages/remix/lib/src/components/select/trigger/select_trigger.dart similarity index 58% rename from packages/remix/lib/src/components/select/button/select_button.dart rename to packages/remix/lib/src/components/select/trigger/select_trigger.dart index 0cb5e861a..7a2808082 100644 --- a/packages/remix/lib/src/components/select/button/select_button.dart +++ b/packages/remix/lib/src/components/select/trigger/select_trigger.dart @@ -1,18 +1,18 @@ part of '../select.dart'; @MixableSpec() -class SelectButtonSpec extends Spec - with _$SelectButtonSpec, Diagnosticable { +class SelectTriggerSpec extends Spec + with _$SelectTriggerSpec, Diagnosticable { final FlexBoxSpec container; final TextSpec label; final IconSpec icon; /// {@macro select_button_spec_of} - static const of = _$SelectButtonSpec.of; + static const of = _$SelectTriggerSpec.of; - static const from = _$SelectButtonSpec.from; + static const from = _$SelectTriggerSpec.from; - const SelectButtonSpec({ + const SelectTriggerSpec({ FlexBoxSpec? container, IconSpec? icon, TextSpec? label, @@ -22,13 +22,6 @@ class SelectButtonSpec extends Spec icon = icon ?? const IconSpec(), label = label ?? const TextSpec(); - Widget call({required String text, required IconData trailingIcon}) => - SelectButtonSpecWidget( - spec: this, - text: text, - trailingIcon: trailingIcon, - ); - @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); diff --git a/packages/remix/lib/src/components/select/button/select_button_widget.dart b/packages/remix/lib/src/components/select/trigger/select_trigger_widget.dart similarity index 84% rename from packages/remix/lib/src/components/select/button/select_button_widget.dart rename to packages/remix/lib/src/components/select/trigger/select_trigger_widget.dart index 83840b564..5df5f23d3 100644 --- a/packages/remix/lib/src/components/select/button/select_button_widget.dart +++ b/packages/remix/lib/src/components/select/trigger/select_trigger_widget.dart @@ -1,16 +1,16 @@ part of '../select.dart'; -class SelectButtonSpecWidget extends StatelessWidget { - const SelectButtonSpecWidget({ +class SelectTrigger extends StatelessWidget { + const SelectTrigger({ super.key, - required this.spec, required this.text, - required this.trailingIcon, + this.trailingIcon = Icons.keyboard_arrow_down_rounded, + this.disabled = false, }); - final SelectButtonSpec spec; final String text; final IconData trailingIcon; + final bool disabled; @override Widget build(BuildContext context) { @@ -26,6 +26,7 @@ class SelectButtonSpecWidget extends StatelessWidget { style.makeStyle(configuration).applyVariants(select.widget.variants); return Pressable( + enabled: !disabled, onPress: () { select.openMenu(); },