diff --git a/example/lib/src/storybook/stories/accordion.dart b/example/lib/src/storybook/stories/accordion.dart index 5dd1c5b2..2c7ad896 100644 --- a/example/lib/src/storybook/stories/accordion.dart +++ b/example/lib/src/storybook/stories/accordion.dart @@ -26,17 +26,6 @@ class AccordionStory extends Story { ], ); - final textColorsKnob = context.knobs.nullable.options( - label: "textColor", - description: "MoonColors variants for MoonAccordion text.", - enabled: false, - initial: 0, - // piccolo - options: colorOptions, - ); - - final textColor = colorTable(context)[textColorsKnob ?? 40]; - final iconColorsKnob = context.knobs.nullable.options( label: "iconColor", description: "MoonColors variants for MoonAccordion trailing icon.", @@ -103,6 +92,28 @@ class AccordionStory extends Story { final dividerColor = colorTable(context)[dividerColorsKnob ?? 40]; + final textColorsKnob = context.knobs.nullable.options( + label: "textColor", + description: "MoonColors variants for MoonAccordion text.", + enabled: false, + initial: 0, + // piccolo + options: colorOptions, + ); + + final textColor = colorTable(context)[textColorsKnob ?? 40]; + + final expandedTextColorsKnob = context.knobs.nullable.options( + label: "expandedTextColor", + description: "MoonColors variants for expanded MoonAccordion text.", + enabled: false, + initial: 0, + // piccolo + options: colorOptions, + ); + + final expandedTextColor = colorTable(context)[expandedTextColorsKnob ?? 40]; + final borderRadiusKnob = context.knobs.nullable.sliderInt( label: "borderRadius", description: "Border radius for MoonAccordion.", @@ -141,6 +152,7 @@ class AccordionStory extends Story { groupIdentityValue: currentlyOpenAccordionItem, accordionSize: accordionSizesKnob, textColor: textColor, + expandedTextColor: expandedTextColor, borderColor: borderColor, trailingIconColor: iconColor, expandedTrailingIconColor: expandedIconColor, @@ -169,6 +181,7 @@ class AccordionStory extends Story { initiallyExpanded: true, accordionSize: accordionSizesKnob, textColor: textColor, + expandedTextColor: expandedTextColor, borderColor: borderColor, trailingIconColor: iconColor, expandedTrailingIconColor: expandedIconColor, @@ -198,6 +211,7 @@ class AccordionStory extends Story { initiallyExpanded: true, hasContentOutside: true, textColor: textColor, + expandedTextColor: expandedTextColor, borderColor: borderColor, trailingIconColor: iconColor, expandedTrailingIconColor: expandedIconColor, @@ -220,6 +234,7 @@ class AccordionStory extends Story { accordionSize: accordionSizesKnob, hasContentOutside: true, textColor: textColor, + expandedTextColor: expandedTextColor, borderColor: borderColor, trailingIconColor: iconColor, expandedTrailingIconColor: expandedIconColor, diff --git a/example/lib/src/storybook/stories/button.dart b/example/lib/src/storybook/stories/button.dart index 07abe4f8..85766ca5 100644 --- a/example/lib/src/storybook/stories/button.dart +++ b/example/lib/src/storybook/stories/button.dart @@ -50,6 +50,17 @@ class ButtonStory extends Story { final borderColor = colorTable(context)[borderColorsKnob ?? 40]; + final textColorsKnob = context.knobs.nullable.options( + label: "textColor", + description: "MoonColors variants for MoonButton text.", + enabled: false, + initial: 0, + // piccolo + options: colorOptions, + ); + + final textColor = colorTable(context)[textColorsKnob ?? 40]; + final borderRadiusKnob = context.knobs.nullable.sliderInt( label: "borderRadius", description: "Border radius for base MoonButton.", @@ -144,6 +155,7 @@ class ButtonStory extends Story { isFullWidth: setFullWidthKnob, backgroundColor: backgroundColor, borderColor: borderColor, + textColor: textColor, showPulseEffect: showPulseEffectKnob, showPulseEffectJiggle: showPulseEffectJiggleKnob, leading: showLeadingKnob ? MoonIcon(resolvedIconVariant) : null, @@ -160,6 +172,7 @@ class ButtonStory extends Story { tooltipMessage: 'This is MoonTooltip', buttonSize: buttonSizesKnob, backgroundColor: backgroundColor, + iconColor: textColor, borderColor: borderColor, showPulseEffect: showPulseEffectKnob, showPulseEffectJiggle: showPulseEffectJiggleKnob, @@ -213,7 +226,8 @@ class ButtonStory extends Story { padding: const EdgeInsets.symmetric(horizontal: 8), showTooltip: showTooltipKnob, tooltipMessage: 'This is MoonTooltip', - decoration: const ShapeDecorationWithPremultipliedAlpha( + showFocusEffect: false, + decoration: const ShapeDecoration( image: DecorationImage( image: AssetImage("assets/images/placeholder-640x359.png"), fit: BoxFit.cover, @@ -242,6 +256,7 @@ class ButtonStory extends Story { padding: const EdgeInsets.symmetric(horizontal: 8), showTooltip: showTooltipKnob, tooltipMessage: 'This is MoonTooltip', + showFocusEffect: false, decoration: ShapeDecorationWithPremultipliedAlpha( shadows: const [ BoxShadow( diff --git a/example/lib/src/storybook/stories/chip.dart b/example/lib/src/storybook/stories/chip.dart index f8991597..130efc49 100644 --- a/example/lib/src/storybook/stories/chip.dart +++ b/example/lib/src/storybook/stories/chip.dart @@ -25,17 +25,6 @@ class ChipStory extends Story { ], ); - final textColorsKnob = context.knobs.nullable.options( - label: "textColor", - description: "MoonColors variants for MoonChip text.", - enabled: false, - initial: 0, - // piccolo - options: colorOptions, - ); - - final textColor = colorTable(context)[textColorsKnob ?? 40]; - final activeColorsKnob = context.knobs.nullable.options( label: "activeColor", description: "MoonColors variants for active MoonChip.", @@ -58,6 +47,17 @@ class ChipStory extends Story { final backgroundColor = colorTable(context)[backgroundColorsKnob ?? 40]; + final activeBackgroundColorsKnob = context.knobs.nullable.options( + label: "activeBackgroundColor", + description: "MoonColors variants for active MoonChip background.", + enabled: false, + initial: 0, + // piccolo + options: colorOptions, + ); + + final activeBackgroundColor = colorTable(context)[activeBackgroundColorsKnob ?? 40]; + final borderColorsKnob = context.knobs.nullable.options( label: "borderColor", description: "MoonColors variants for MoonChip border.", @@ -69,6 +69,17 @@ class ChipStory extends Story { final borderColor = colorTable(context)[borderColorsKnob ?? 40]; + final textColorsKnob = context.knobs.nullable.options( + label: "textColor", + description: "MoonColors variants for MoonChip text.", + enabled: false, + initial: 0, + // piccolo + options: colorOptions, + ); + + final textColor = colorTable(context)[textColorsKnob ?? 40]; + final borderRadiusKnob = context.knobs.nullable.sliderInt( label: "borderRadius", description: "Border radius for MoonChip.", @@ -79,9 +90,8 @@ class ChipStory extends Story { final showBorderKnob = context.knobs.boolean( label: "showBorder", - description: "Show border when isActive.", + description: "Show border when hovered, focused or isActive is true.", ); - final isActiveKnob = context.knobs.boolean( label: "isActive", description: "Whether MoonChip is active/selected.", @@ -116,14 +126,15 @@ class ChipStory extends Story { const SizedBox(height: 32), MoonChip( activeColor: activeColor, - textColor: textColor, borderColor: borderColor, + backgroundColor: backgroundColor, + activeBackgroundColor: activeBackgroundColor, + textColor: textColor, isActive: isActiveKnob, borderRadius: borderRadiusKnob != null ? BorderRadius.circular(borderRadiusKnob.toDouble()) : null, showBorder: showBorderKnob, chipSize: chipSizesKnob, - backgroundColor: backgroundColor, leading: showLeadingKnob ? MoonIcon(resolvedIconVariant) : null, label: showLabelKnob ? Text(customLabelTextKnob) : null, trailing: showTrailingKnob ? MoonIcon(resolvedIconVariant) : null, @@ -131,7 +142,10 @@ class ChipStory extends Story { const SizedBox(height: 40), const TextDivider(text: "Text MoonChip"), const SizedBox(height: 32), - MoonTextChip( + MoonChip.text( + activeBackgroundColor: activeBackgroundColor, + borderColor: borderColor, + textColor: textColor, isActive: isActiveKnob, borderRadius: borderRadiusKnob != null ? BorderRadius.circular(borderRadiusKnob.toDouble()) : null, @@ -148,7 +162,8 @@ class ChipStory extends Story { isActive: isActiveKnob, activeColor: context.moonColors!.dodoria100, backgroundColor: context.moonColors!.krillin100, - hoverEffectColor: context.moonColors!.chiChi10, + activeBackgroundColor: context.moonColors!.chiChi10, + textColor: context.moonTypography!.colors.controlPrimary, borderWidth: 2, showBorder: showBorderKnob, chipSize: chipSizesKnob, diff --git a/example/lib/src/storybook/stories/tooltip.dart b/example/lib/src/storybook/stories/tooltip.dart index 9acd0e65..8ee746e0 100644 --- a/example/lib/src/storybook/stories/tooltip.dart +++ b/example/lib/src/storybook/stories/tooltip.dart @@ -159,6 +159,7 @@ class TooltipStory extends Story { borderRadius: BorderRadius.circular(20), backgroundColor: context.moonColors!.hit, leading: const MoonIcon(MoonIcons.frame_24), + textColor: context.moonTypography!.colors.controlPrimary, label: const Text("MoonChip"), ), const SizedBox(height: 64), diff --git a/lib/moon_design.dart b/lib/moon_design.dart index a36335f7..4407d17a 100644 --- a/lib/moon_design.dart +++ b/lib/moon_design.dart @@ -33,6 +33,7 @@ export 'package:moon_design/src/theme/typography/text_styles.dart'; export 'package:moon_design/src/theme/typography/typography.dart'; export 'package:moon_design/src/utils/color_premul_lerp.dart'; +export 'package:moon_design/src/utils/color_tween_premul.dart'; export 'package:moon_design/src/utils/extensions.dart'; export 'package:moon_design/src/utils/shape_decoration_premul.dart'; export 'package:moon_design/src/utils/squircle/clip_squircle_rect.dart'; @@ -52,7 +53,6 @@ export 'package:moon_design/src/widgets/buttons/outlined_button.dart'; export 'package:moon_design/src/widgets/buttons/text_button.dart'; export 'package:moon_design/src/widgets/checkbox/checkbox.dart'; export 'package:moon_design/src/widgets/chips/chip.dart'; -export 'package:moon_design/src/widgets/chips/text_chip.dart'; export 'package:moon_design/src/widgets/common/animated_icon_theme.dart'; export 'package:moon_design/src/widgets/common/base_control.dart'; export 'package:moon_design/src/widgets/common/base_segmented_tab_bar.dart'; diff --git a/lib/src/theme/accordion/accordion_item_colors.dart b/lib/src/theme/accordion/accordion_item_colors.dart index 54b4e7c6..58067f42 100644 --- a/lib/src/theme/accordion/accordion_item_colors.dart +++ b/lib/src/theme/accordion/accordion_item_colors.dart @@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:moon_design/src/theme/colors.dart'; +import 'package:moon_design/src/theme/typography/typography.dart'; import 'package:moon_design/src/utils/color_premul_lerp.dart'; @immutable @@ -11,8 +12,10 @@ class MoonAccordionItemColors extends ThemeExtension wi expandedBackgroundColor: MoonColors.light.gohan, borderColor: MoonColors.light.beerus, dividerColor: MoonColors.light.beerus, - trailingIconColor: MoonColors.light.trunks, - expandedTrailingIconColor: MoonColors.light.bulma, + textColor: MoonTypography.light.colors.bodyPrimary, + expandedTextColor: MoonTypography.light.colors.bodyPrimary, + trailingIconColor: MoonTypography.light.colors.bodySecondary, + expandedTrailingIconColor: MoonTypography.light.colors.bodyPrimary, ); static final dark = MoonAccordionItemColors( @@ -20,8 +23,10 @@ class MoonAccordionItemColors extends ThemeExtension wi expandedBackgroundColor: MoonColors.dark.gohan, borderColor: MoonColors.dark.beerus, dividerColor: MoonColors.dark.beerus, - trailingIconColor: MoonColors.dark.trunks, - expandedTrailingIconColor: MoonColors.dark.bulma, + textColor: MoonTypography.dark.colors.bodyPrimary, + expandedTextColor: MoonTypography.dark.colors.bodyPrimary, + trailingIconColor: MoonTypography.dark.colors.bodySecondary, + expandedTrailingIconColor: MoonTypography.dark.colors.bodyPrimary, ); /// Accordion item background color. @@ -36,6 +41,12 @@ class MoonAccordionItemColors extends ThemeExtension wi /// Accordion item divider color. final Color dividerColor; + /// Accordion item text color. + final Color textColor; + + /// Accordion item expanded text color. + final Color expandedTextColor; + /// Accordion item trailing icon color. final Color trailingIconColor; @@ -47,6 +58,8 @@ class MoonAccordionItemColors extends ThemeExtension wi required this.expandedBackgroundColor, required this.borderColor, required this.dividerColor, + required this.textColor, + required this.expandedTextColor, required this.trailingIconColor, required this.expandedTrailingIconColor, }); @@ -57,6 +70,8 @@ class MoonAccordionItemColors extends ThemeExtension wi Color? expandedBackgroundColor, Color? borderColor, Color? dividerColor, + Color? textColor, + Color? expandedTextColor, Color? trailingIconColor, Color? expandedTrailingIconColor, }) { @@ -65,6 +80,8 @@ class MoonAccordionItemColors extends ThemeExtension wi expandedBackgroundColor: expandedBackgroundColor ?? this.expandedBackgroundColor, borderColor: borderColor ?? this.borderColor, dividerColor: dividerColor ?? this.dividerColor, + textColor: textColor ?? this.textColor, + expandedTextColor: expandedTextColor ?? this.expandedTextColor, trailingIconColor: trailingIconColor ?? this.trailingIconColor, expandedTrailingIconColor: expandedTrailingIconColor ?? this.expandedTrailingIconColor, ); @@ -79,6 +96,8 @@ class MoonAccordionItemColors extends ThemeExtension wi expandedBackgroundColor: colorPremulLerp(expandedBackgroundColor, other.expandedBackgroundColor, t)!, borderColor: colorPremulLerp(borderColor, other.borderColor, t)!, dividerColor: colorPremulLerp(dividerColor, other.dividerColor, t)!, + textColor: colorPremulLerp(textColor, other.textColor, t)!, + expandedTextColor: colorPremulLerp(expandedTextColor, other.expandedTextColor, t)!, trailingIconColor: colorPremulLerp(trailingIconColor, other.trailingIconColor, t)!, expandedTrailingIconColor: colorPremulLerp(expandedTrailingIconColor, other.expandedTrailingIconColor, t)!, ); @@ -93,6 +112,8 @@ class MoonAccordionItemColors extends ThemeExtension wi ..add(ColorProperty("expandedBackgroundColor", expandedBackgroundColor)) ..add(ColorProperty("borderColor", borderColor)) ..add(ColorProperty("dividerColor", dividerColor)) + ..add(ColorProperty("textColor", textColor)) + ..add(ColorProperty("expandedTextColor", expandedTextColor)) ..add(ColorProperty("trailingIconColor", trailingIconColor)) ..add(ColorProperty("expandedTrailingIconColor", expandedTrailingIconColor)); } diff --git a/lib/src/theme/accordion/accordion_item_properties.dart b/lib/src/theme/accordion/accordion_item_properties.dart index c146f08b..8000c8ac 100644 --- a/lib/src/theme/accordion/accordion_item_properties.dart +++ b/lib/src/theme/accordion/accordion_item_properties.dart @@ -1,18 +1,14 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:moon_design/src/theme/borders.dart'; - @immutable class MoonAccordionItemProperties extends ThemeExtension with DiagnosticableTreeMixin { - static final properties = MoonAccordionItemProperties( - borderRadius: MoonBorders.borders.interactiveSm, - transitionDuration: const Duration(milliseconds: 200), + static const properties = MoonAccordionItemProperties( + transitionDuration: Duration(milliseconds: 200), transitionCurve: Curves.easeInOutCubic, ); /// Accordion item border radius. - final BorderRadiusGeometry borderRadius; /// Accordion item transition duration. final Duration transitionDuration; @@ -21,19 +17,16 @@ class MoonAccordionItemProperties extends ThemeExtension("borderRadius", borderRadius)) ..add(DiagnosticsProperty("transitionDuration", transitionDuration)) ..add(DiagnosticsProperty("transitionCurve", transitionCurve)); } diff --git a/lib/src/theme/accordion/accordion_item_size_properties.dart b/lib/src/theme/accordion/accordion_item_size_properties.dart index 4809d30f..0c97f9fe 100644 --- a/lib/src/theme/accordion/accordion_item_size_properties.dart +++ b/lib/src/theme/accordion/accordion_item_size_properties.dart @@ -3,6 +3,7 @@ import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:moon_design/src/theme/borders.dart'; import 'package:moon_design/src/theme/sizes.dart'; import 'package:moon_design/src/theme/typography/text_styles.dart'; @@ -10,6 +11,7 @@ import 'package:moon_design/src/theme/typography/text_styles.dart'; class MoonAccordionItemSizeProperties extends ThemeExtension with DiagnosticableTreeMixin { static final sm = MoonAccordionItemSizeProperties( + borderRadius: MoonBorders.borders.interactiveSm, headerHeight: MoonSizes.sizes.sm, iconSizeValue: MoonSizes.sizes.x2s, headerPadding: EdgeInsets.symmetric(horizontal: MoonSizes.sizes.x4s), @@ -17,6 +19,7 @@ class MoonAccordionItemSizeProperties extends ThemeExtension("borderRadius", borderRadius)) ..add(DoubleProperty("headerHeight", headerHeight)) ..add(DoubleProperty("iconSizeValue", iconSizeValue)) ..add(DiagnosticsProperty("headerPadding", headerPadding)) diff --git a/lib/src/theme/button/button_colors.dart b/lib/src/theme/button/button_colors.dart index 73e9e5af..d5d7d9e8 100644 --- a/lib/src/theme/button/button_colors.dart +++ b/lib/src/theme/button/button_colors.dart @@ -2,22 +2,27 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:moon_design/src/theme/colors.dart'; +import 'package:moon_design/src/theme/typography/typography.dart'; import 'package:moon_design/src/utils/color_premul_lerp.dart'; @immutable class MoonButtonColors extends ThemeExtension with DiagnosticableTreeMixin { static final light = MoonButtonColors( borderColor: MoonColors.light.trunks, + textColor: MoonTypography.light.colors.bodyPrimary, filledVariantBackgroundColor: MoonColors.light.piccolo, - textVariantTextColor: MoonColors.light.trunks, + filledVariantTextColor: MoonTypography.light.colors.controlPrimary, + textVariantTextColor: MoonTypography.light.colors.bodySecondary, textVariantFocusColor: MoonColors.light.piccolo, textVariantHoverColor: MoonColors.light.jiren, ); static final dark = MoonButtonColors( borderColor: MoonColors.dark.trunks, + textColor: MoonTypography.dark.colors.bodyPrimary, filledVariantBackgroundColor: MoonColors.dark.piccolo, - textVariantTextColor: MoonColors.dark.trunks, + filledVariantTextColor: MoonTypography.dark.colors.controlPrimary, + textVariantTextColor: MoonTypography.dark.colors.bodySecondary, textVariantFocusColor: MoonColors.dark.piccolo, textVariantHoverColor: MoonColors.dark.jiren, ); @@ -25,11 +30,14 @@ class MoonButtonColors extends ThemeExtension with Diagnostica /// Button border color. final Color borderColor; + /// Button text color. + final Color textColor; + /// Filled button background color. final Color filledVariantBackgroundColor; - /// Text button text color. - final Color textVariantTextColor; + /// Filled button text color. + final Color filledVariantTextColor; /// Text button focus effect color. final Color textVariantFocusColor; @@ -37,28 +45,37 @@ class MoonButtonColors extends ThemeExtension with Diagnostica /// Text button hover effect color. final Color textVariantHoverColor; + /// Text button text color. + final Color textVariantTextColor; + const MoonButtonColors({ required this.borderColor, + required this.textColor, required this.filledVariantBackgroundColor, - required this.textVariantTextColor, + required this.filledVariantTextColor, required this.textVariantFocusColor, required this.textVariantHoverColor, + required this.textVariantTextColor, }); @override MoonButtonColors copyWith({ Color? borderColor, + Color? textColor, Color? filledVariantBackgroundColor, - Color? textVariantTextColor, + Color? filledVariantTextColor, Color? textVariantFocusColor, Color? textVariantHoverColor, + Color? textVariantTextColor, }) { return MoonButtonColors( borderColor: borderColor ?? this.borderColor, + textColor: textColor ?? this.textColor, filledVariantBackgroundColor: filledVariantBackgroundColor ?? this.filledVariantBackgroundColor, - textVariantTextColor: textVariantTextColor ?? this.textVariantTextColor, + filledVariantTextColor: filledVariantTextColor ?? this.filledVariantTextColor, textVariantFocusColor: textVariantFocusColor ?? this.textVariantFocusColor, textVariantHoverColor: textVariantHoverColor ?? this.textVariantHoverColor, + textVariantTextColor: textVariantTextColor ?? this.textVariantTextColor, ); } @@ -68,11 +85,13 @@ class MoonButtonColors extends ThemeExtension with Diagnostica return MoonButtonColors( borderColor: colorPremulLerp(borderColor, other.borderColor, t)!, + textColor: colorPremulLerp(textColor, other.textColor, t)!, filledVariantBackgroundColor: colorPremulLerp(filledVariantBackgroundColor, other.filledVariantBackgroundColor, t)!, - textVariantTextColor: colorPremulLerp(textVariantTextColor, other.textVariantTextColor, t)!, + filledVariantTextColor: colorPremulLerp(filledVariantTextColor, other.filledVariantTextColor, t)!, textVariantFocusColor: colorPremulLerp(textVariantFocusColor, other.textVariantFocusColor, t)!, textVariantHoverColor: colorPremulLerp(textVariantHoverColor, other.textVariantHoverColor, t)!, + textVariantTextColor: colorPremulLerp(textVariantTextColor, other.textVariantTextColor, t)!, ); } @@ -82,9 +101,11 @@ class MoonButtonColors extends ThemeExtension with Diagnostica properties ..add(DiagnosticsProperty("type", "MoonButtonColors")) ..add(ColorProperty("borderColor", borderColor)) + ..add(ColorProperty("textColor", textColor)) ..add(ColorProperty("filledVariantBackgroundColor", filledVariantBackgroundColor)) - ..add(ColorProperty("textVariantTextColor", textVariantTextColor)) + ..add(ColorProperty("filledVariantTextColor", filledVariantTextColor)) ..add(ColorProperty("textVariantFocusColor", textVariantFocusColor)) - ..add(ColorProperty("textVariantHoverColor", textVariantHoverColor)); + ..add(ColorProperty("textVariantHoverColor", textVariantHoverColor)) + ..add(ColorProperty("textVariantTextColor", textVariantTextColor)); } } diff --git a/lib/src/theme/chip/chip_colors.dart b/lib/src/theme/chip/chip_colors.dart index 95308586..338576cb 100644 --- a/lib/src/theme/chip/chip_colors.dart +++ b/lib/src/theme/chip/chip_colors.dart @@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:moon_design/src/theme/colors.dart'; +import 'package:moon_design/src/theme/typography/typography.dart'; import 'package:moon_design/src/utils/color_premul_lerp.dart'; @immutable @@ -9,32 +10,48 @@ class MoonChipColors extends ThemeExtension with DiagnosticableT static final light = MoonChipColors( activeColor: MoonColors.light.piccolo, backgroundColor: MoonColors.light.gohan, + activeBackgroundColor: MoonColors.light.jiren, + textColor: MoonTypography.light.colors.bodyPrimary, ); static final dark = MoonChipColors( activeColor: MoonColors.dark.piccolo, backgroundColor: MoonColors.dark.gohan, + activeBackgroundColor: MoonColors.dark.jiren, + textColor: MoonTypography.dark.colors.bodyPrimary, ); - /// Chip active color. + /// Chip text and border color when active. final Color activeColor; /// Chip background color. final Color backgroundColor; + /// Chip background color when active. + final Color activeBackgroundColor; + + /// Chip text color. + final Color textColor; + const MoonChipColors({ required this.activeColor, required this.backgroundColor, + required this.activeBackgroundColor, + required this.textColor, }); @override MoonChipColors copyWith({ Color? activeColor, Color? backgroundColor, + Color? activeBackgroundColor, + Color? textColor, }) { return MoonChipColors( activeColor: activeColor ?? this.activeColor, backgroundColor: backgroundColor ?? this.backgroundColor, + activeBackgroundColor: activeBackgroundColor ?? this.activeBackgroundColor, + textColor: textColor ?? this.textColor, ); } @@ -45,6 +62,8 @@ class MoonChipColors extends ThemeExtension with DiagnosticableT return MoonChipColors( activeColor: colorPremulLerp(activeColor, other.activeColor, t)!, backgroundColor: colorPremulLerp(backgroundColor, other.backgroundColor, t)!, + activeBackgroundColor: colorPremulLerp(activeBackgroundColor, other.activeBackgroundColor, t)!, + textColor: colorPremulLerp(textColor, other.textColor, t)!, ); } @@ -54,6 +73,8 @@ class MoonChipColors extends ThemeExtension with DiagnosticableT properties ..add(DiagnosticsProperty("type", "MoonChipColors")) ..add(ColorProperty("activeColor", activeColor)) - ..add(ColorProperty("backgroundColor", backgroundColor)); + ..add(ColorProperty("backgroundColor", backgroundColor)) + ..add(ColorProperty("activeBackgroundColor", activeBackgroundColor)) + ..add(ColorProperty("textColor", textColor)); } } diff --git a/lib/src/theme/chip/chip_size_properties.dart b/lib/src/theme/chip/chip_size_properties.dart index 4b516226..ca0bf222 100644 --- a/lib/src/theme/chip/chip_size_properties.dart +++ b/lib/src/theme/chip/chip_size_properties.dart @@ -11,7 +11,7 @@ import 'package:moon_design/src/theme/typography/text_styles.dart'; class MoonChipSizeProperties extends ThemeExtension with DiagnosticableTreeMixin { static final sm = MoonChipSizeProperties( borderRadius: MoonBorders.borders.interactiveXs, - gap: MoonSizes.sizes.x5s, + gap: MoonSizes.sizes.x4s, height: MoonSizes.sizes.sm, iconSizeValue: MoonSizes.sizes.x2s, padding: EdgeInsets.symmetric(horizontal: MoonSizes.sizes.x3s), diff --git a/lib/src/utils/color_tween_premul.dart b/lib/src/utils/color_tween_premul.dart new file mode 100644 index 00000000..3249b87e --- /dev/null +++ b/lib/src/utils/color_tween_premul.dart @@ -0,0 +1,21 @@ +import 'package:flutter/animation.dart'; + +import 'package:moon_design/src/utils/color_premul_lerp.dart'; + +// TODO: This will be unnecessary once Flutter finally moves from straight alpha to premultiplied alpha for color lerping. +class ColorTweenWithPremultipliedAlpha extends Tween { + /// Creates a [Color] tween with premultiplied alpha. + /// + /// The [begin] and [end] properties may be null; the null value + /// is treated as transparent. + /// + /// We recommend that you do not pass [Colors.transparent] as [begin] + /// or [end] if you want the effect of fading in or out of transparent. + /// Instead prefer null. [Colors.transparent] refers to black transparent and + /// thus will fade out of or into black which is likely unwanted. + ColorTweenWithPremultipliedAlpha({super.begin, super.end}); + + /// Returns the value this variable has at the given animation clock value. + @override + Color? lerp(double t) => colorPremulLerp(begin, end, t); +} diff --git a/lib/src/widgets/accordion/accordion_item.dart b/lib/src/widgets/accordion/accordion_item.dart index 5d810db3..ef0cf957 100644 --- a/lib/src/widgets/accordion/accordion_item.dart +++ b/lib/src/widgets/accordion/accordion_item.dart @@ -1,16 +1,15 @@ import 'package:flutter/material.dart'; import 'package:moon_design/src/theme/accordion/accordion_item_size_properties.dart'; -import 'package:moon_design/src/theme/borders.dart'; import 'package:moon_design/src/theme/colors.dart'; import 'package:moon_design/src/theme/effects/focus_effects.dart'; import 'package:moon_design/src/theme/effects/hover_effects.dart'; import 'package:moon_design/src/theme/shadows.dart'; import 'package:moon_design/src/theme/theme.dart'; +import 'package:moon_design/src/theme/typography/typography.dart'; +import 'package:moon_design/src/utils/color_tween_premul.dart'; import 'package:moon_design/src/utils/extensions.dart'; -import 'package:moon_design/src/utils/shape_decoration_premul.dart'; import 'package:moon_design/src/utils/squircle/squircle_border.dart'; -import 'package:moon_design/src/widgets/common/animated_icon_theme.dart'; import 'package:moon_design/src/widgets/common/effects/focus_effect.dart'; import 'package:moon_design/src/widgets/common/icons/icons.dart'; import 'package:moon_design/src/widgets/common/icons/moon_icon.dart'; @@ -100,9 +99,12 @@ class MoonAccordionItem extends StatefulWidget { /// The color of accordion's trailing icon (downward caret by default) when the accordion is expanded. final Color? expandedTrailingIconColor; - /// The color of the accordion's title. + /// The color of the accordion's text. final Color? textColor; + /// The color of the expanded accordion's text. + final Color? expandedTextColor; + /// The height of the accordion header. final double? headerHeight; @@ -188,6 +190,7 @@ class MoonAccordionItem extends StatefulWidget { this.trailingIconColor, this.expandedTrailingIconColor, this.textColor, + this.expandedTextColor, this.headerHeight, this.transitionDuration, this.transitionCurve, @@ -217,21 +220,38 @@ class MoonAccordionItem extends StatefulWidget { State> createState() => _MoonAccordionItemState(); } -class _MoonAccordionItemState extends State> with SingleTickerProviderStateMixin { +class _MoonAccordionItemState extends State> with TickerProviderStateMixin { static final Animatable _halfTween = Tween(begin: 0.0, end: 0.5); late final Map> _actions = { ActivateIntent: CallbackAction(onInvoke: (_) => _handleTap()) }; - late Animation? _iconColorAnimation; - late Animation? _backgroundColorAnimation; + final ColorTweenWithPremultipliedAlpha _backgroundColorTween = ColorTweenWithPremultipliedAlpha(); + final ColorTweenWithPremultipliedAlpha _iconColorTween = ColorTweenWithPremultipliedAlpha(); + final ColorTweenWithPremultipliedAlpha _hoverColorTween = ColorTweenWithPremultipliedAlpha(); + final ColorTweenWithPremultipliedAlpha _textColorTween = ColorTweenWithPremultipliedAlpha(); + + Animation? _backgroundColor; + Animation? _iconColor; + Animation? _hoverColor; + Animation? _textColor; + + AnimationController? _expansionAnimationController; + AnimationController? _hoverAnimationController; - AnimationController? _animationController; - CurvedAnimation? _curvedAnimation; + CurvedAnimation? _expansionCurvedAnimation; FocusNode? _focusNode; + Color? _effectiveHoverEffectColor; + + MoonAccordionItemSizeProperties? _effectiveMoonAccordionSize; + BorderRadiusGeometry? _effectiveBorderRadius; + EdgeInsetsGeometry? _effectiveHeaderPadding; + EdgeInsets? _resolvedDirectionalHeaderPadding; + double? _effectiveHeaderHeight; + bool _isExpanded = false; bool _isFocused = false; bool _isHovered = false; @@ -241,12 +261,24 @@ class _MoonAccordionItemState extends State> with Single void _handleHover(bool hover) { if (hover != _isHovered) { setState(() => _isHovered = hover); + + if (hover) { + _hoverAnimationController!.forward(); + } else { + _hoverAnimationController!.reverse(); + } } } void _handleFocus(bool focus) { if (focus != _isFocused) { setState(() => _isFocused = focus); + + if (focus) { + _hoverAnimationController!.forward(); + } else { + _hoverAnimationController!.reverse(); + } } } @@ -258,9 +290,9 @@ class _MoonAccordionItemState extends State> with Single setState(() { _isExpanded = !_isExpanded; if (_isExpanded) { - _animationController!.forward(); + _expansionAnimationController!.forward(); } else { - _animationController!.reverse().then((void value) { + _expansionAnimationController!.reverse().then((void value) { if (!mounted) return; setState(() { @@ -292,15 +324,6 @@ class _MoonAccordionItemState extends State> with Single } } - Color _getTextColor(BuildContext context, {required Color effectiveBackgroundColor}) { - final backgroundLuminance = effectiveBackgroundColor.computeLuminance(); - if (backgroundLuminance > 0.5) { - return MoonColors.light.bulma; - } else { - return MoonColors.dark.bulma; - } - } - @override void initState() { super.initState(); @@ -312,7 +335,7 @@ class _MoonAccordionItemState extends State> with Single if (!mounted) return; if (_isExpanded) { - _animationController!.value = 1.0; + _expansionAnimationController!.value = 1.0; } }); } @@ -331,9 +354,9 @@ class _MoonAccordionItemState extends State> with Single setState(() { if (_isExpanded) { - _animationController!.forward(); + _expansionAnimationController!.forward(); } else { - _animationController!.reverse().then((void value) { + _expansionAnimationController!.reverse().then((void value) { if (!mounted) return; setState(() { @@ -347,7 +370,8 @@ class _MoonAccordionItemState extends State> with Single @override void dispose() { - _animationController!.dispose(); + _expansionAnimationController!.dispose(); + _hoverAnimationController!.dispose(); super.dispose(); } @@ -355,25 +379,24 @@ class _MoonAccordionItemState extends State> with Single Widget? _buildIcon(BuildContext context) { final double iconSize = _getMoonAccordionItemSize(context, widget.accordionSize).iconSizeValue; - final Color effectiveBackgroundColor = widget.backgroundColor ?? - context.moonTheme?.accordionTheme.itemColors.backgroundColor ?? - MoonColors.light.gohan; - final Color effectiveIconColor = widget.trailingIconColor ?? context.moonTheme?.accordionTheme.itemColors.trailingIconColor ?? - _getTextColor(context, effectiveBackgroundColor: effectiveBackgroundColor); + MoonTypography.light.colors.bodySecondary; final Color effectiveExpandedIconColor = widget.expandedTrailingIconColor ?? context.moonTheme?.accordionTheme.itemColors.expandedTrailingIconColor ?? - effectiveIconColor; + MoonTypography.light.colors.bodyPrimary; - _iconColorAnimation = - ColorTween(begin: effectiveIconColor, end: effectiveExpandedIconColor).animate(_curvedAnimation!); + _iconColor ??= _iconColorTween.animate(_expansionCurvedAnimation!); + + _iconColorTween + ..begin = effectiveIconColor + ..end = effectiveExpandedIconColor; return IconTheme( - data: IconThemeData(color: _iconColorAnimation?.value), + data: IconThemeData(color: _iconColor?.value), child: RotationTransition( - turns: _halfTween.animate(_curvedAnimation!), + turns: _halfTween.animate(_expansionCurvedAnimation!), child: MoonIcon( MoonIcons.chevron_down_small_16, size: iconSize, @@ -382,14 +405,71 @@ class _MoonAccordionItemState extends State> with Single ); } - Widget _buildChildren(BuildContext context, Widget? child) { - final BorderRadiusGeometry effectiveBorderRadius = widget.borderRadius ?? - context.moonTheme?.accordionTheme.itemProperties.borderRadius ?? - MoonBorders.borders.interactiveSm; - + Widget _buildHeader({bool isContentOutsideHeader = false, required Widget child}) { final Color effectiveBorderColor = widget.borderColor ?? context.moonTheme?.accordionTheme.itemColors.borderColor ?? MoonColors.light.beerus; + final List effectiveShadows = + widget.shadows ?? context.moonTheme?.accordionTheme.itemShadows.shadows ?? MoonShadows.light.sm; + + final Color effectiveTextColor = widget.textColor ?? + context.moonTheme?.accordionTheme.itemColors.textColor ?? + MoonTypography.light.colors.bodyPrimary; + + final Color effectiveExpandedTextColor = widget.expandedTextColor ?? + context.moonTheme?.accordionTheme.itemColors.expandedTextColor ?? + MoonTypography.light.colors.bodyPrimary; + + _textColor ??= _textColorTween.animate(_expansionCurvedAnimation!); + + _textColorTween + ..begin = effectiveTextColor + ..end = effectiveExpandedTextColor; + + return RepaintBoundary( + child: AnimatedBuilder( + animation: _hoverAnimationController!, + builder: (context, child) { + return IconTheme( + data: IconThemeData(color: _textColor!.value), + child: DefaultTextStyle( + style: DefaultTextStyle.of(context).style.copyWith(color: _textColor!.value), + child: Container( + height: isContentOutsideHeader ? _effectiveHeaderHeight : null, + padding: isContentOutsideHeader ? _resolvedDirectionalHeaderPadding : null, + clipBehavior: widget.clipBehavior ?? Clip.none, + decoration: widget.decoration ?? + ((widget.hasContentOutside && isContentOutsideHeader) || + (!widget.hasContentOutside && !isContentOutsideHeader) + ? ShapeDecoration( + color: _hoverColor!.value, + shadows: effectiveShadows, + shape: MoonSquircleBorder( + side: widget.showBorder ? BorderSide(color: effectiveBorderColor) : BorderSide.none, + borderRadius: _effectiveBorderRadius!.squircleBorderRadius(context), + ), + ) + : null), + child: child, + ), + ), + ); + }, + child: child, + ), + ); + } + + Widget _buildChildren(BuildContext context, Widget? rootChild) { + _effectiveHoverEffectColor ??= context.moonEffects?.controlHoverEffect.primaryHoverColor ?? + MoonHoverEffects.lightHoverEffect.primaryHoverColor; + + _effectiveMoonAccordionSize ??= _getMoonAccordionItemSize(context, widget.accordionSize); + _effectiveBorderRadius ??= widget.borderRadius ?? _effectiveMoonAccordionSize!.borderRadius; + _effectiveHeaderHeight ??= widget.headerHeight ?? _effectiveMoonAccordionSize!.headerHeight; + _effectiveHeaderPadding ??= widget.headerPadding ?? _effectiveMoonAccordionSize!.headerPadding; + _resolvedDirectionalHeaderPadding ??= _effectiveHeaderPadding!.resolve(Directionality.of(context)); + final Color effectiveBackgroundColor = widget.backgroundColor ?? context.moonTheme?.accordionTheme.itemColors.backgroundColor ?? MoonColors.light.gohan; @@ -398,26 +478,6 @@ class _MoonAccordionItemState extends State> with Single context.moonTheme?.accordionTheme.itemColors.expandedBackgroundColor ?? MoonColors.light.gohan; - final MoonAccordionItemSizeProperties effectiveMoonAccordionSize = - _getMoonAccordionItemSize(context, widget.accordionSize); - - final double effectiveHeaderHeight = widget.headerHeight ?? effectiveMoonAccordionSize.headerHeight; - - final EdgeInsetsGeometry effectiveHeaderPadding = widget.headerPadding ?? effectiveMoonAccordionSize.headerPadding; - - final EdgeInsets resolvedDirectionalHeaderPadding = effectiveHeaderPadding.resolve(Directionality.of(context)); - - final List effectiveShadows = - widget.shadows ?? context.moonTheme?.accordionTheme.itemShadows.shadows ?? MoonShadows.light.sm; - - final Duration effectiveTransitionDuration = widget.transitionDuration ?? - context.moonTheme?.accordionTheme.itemProperties.transitionDuration ?? - const Duration(milliseconds: 200); - - final Curve effectiveTransitionCurve = widget.transitionCurve ?? - context.moonTheme?.accordionTheme.itemProperties.transitionCurve ?? - Curves.easeInOutCubic; - final double effectiveFocusEffectExtent = context.moonEffects?.controlFocusEffect.effectExtent ?? MoonFocusEffects.lightFocusEffect.effectExtent; @@ -439,18 +499,32 @@ class _MoonAccordionItemState extends State> with Single final Curve effectiveHoverEffectCurve = context.moonEffects?.controlHoverEffect.hoverCurve ?? MoonHoverEffects.lightHoverEffect.hoverCurve; - _animationController ??= AnimationController(duration: effectiveTransitionDuration, vsync: this); - _curvedAnimation ??= CurvedAnimation(parent: _animationController!, curve: effectiveTransitionCurve); + final Duration effectiveTransitionDuration = widget.transitionDuration ?? + context.moonTheme?.accordionTheme.itemProperties.transitionDuration ?? + const Duration(milliseconds: 200); - _backgroundColorAnimation = - ColorTween(begin: effectiveBackgroundColor, end: effectiveExpandedBackgroundColor).animate(_curvedAnimation!); + final Curve effectiveTransitionCurve = widget.transitionCurve ?? + context.moonTheme?.accordionTheme.itemProperties.transitionCurve ?? + Curves.easeInOutCubic; - final Color? resolvedBackgroundColor = _isHovered || _isFocused - ? Color.alphaBlend(effectiveHoverEffectColor, _backgroundColorAnimation!.value!) - : _backgroundColorAnimation!.value; + _expansionAnimationController ??= AnimationController(duration: effectiveTransitionDuration, vsync: this); + _expansionCurvedAnimation ??= + CurvedAnimation(parent: _expansionAnimationController!, curve: effectiveTransitionCurve); - final Color effectiveTextColor = widget.textColor ?? - _getTextColor(context, effectiveBackgroundColor: resolvedBackgroundColor ?? effectiveBackgroundColor); + _backgroundColor ??= _backgroundColorTween.animate(_expansionCurvedAnimation!); + + _backgroundColorTween + ..begin = effectiveBackgroundColor + ..end = effectiveExpandedBackgroundColor; + + _hoverAnimationController ??= AnimationController(duration: effectiveHoverEffectDuration, vsync: this); + + _hoverColor ??= + _hoverAnimationController!.drive(_hoverColorTween.chain(CurveTween(curve: effectiveHoverEffectCurve))); + + _hoverColorTween + ..begin = _backgroundColor!.value + ..end = Color.alphaBlend(effectiveHoverEffectColor, _backgroundColor!.value!); return Semantics( label: widget.semanticLabel, @@ -465,7 +539,7 @@ class _MoonAccordionItemState extends State> with Single onShowHoverHighlight: _handleHover, child: MoonFocusEffect( show: _isFocused, - childBorderRadius: effectiveBorderRadius, + childBorderRadius: _effectiveBorderRadius, effectColor: effectiveFocusEffectColor, effectDuration: effectiveFocusEffectDuration, effectCurve: effectiveFocusEffectCurve, @@ -475,80 +549,36 @@ class _MoonAccordionItemState extends State> with Single child: GestureDetector( behavior: HitTestBehavior.opaque, onTap: _handleTap, - child: AnimatedIconTheme( - duration: effectiveTransitionDuration, - color: effectiveTextColor, - child: AnimatedDefaultTextStyle( - style: DefaultTextStyle.of(context).style.copyWith(color: effectiveTextColor), - duration: effectiveTransitionDuration, - child: RepaintBoundary( - child: AnimatedContainer( - duration: effectiveHoverEffectDuration, - curve: effectiveHoverEffectCurve, - clipBehavior: widget.clipBehavior ?? Clip.none, - decoration: widget.decoration ?? - (!widget.hasContentOutside - ? ShapeDecorationWithPremultipliedAlpha( - color: resolvedBackgroundColor, - shadows: effectiveShadows, - shape: MoonSquircleBorder( - side: widget.showBorder ? BorderSide(color: effectiveBorderColor) : BorderSide.none, - borderRadius: effectiveBorderRadius.squircleBorderRadius(context), - ), - ) - : null), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - AnimatedContainer( - height: effectiveHeaderHeight, - padding: resolvedDirectionalHeaderPadding, - duration: effectiveHoverEffectDuration, - curve: effectiveHoverEffectCurve, - decoration: widget.decoration ?? - (widget.hasContentOutside - ? ShapeDecorationWithPremultipliedAlpha( - color: resolvedBackgroundColor, - shadows: effectiveShadows, - shape: MoonSquircleBorder( - side: widget.showBorder - ? BorderSide(color: effectiveBorderColor) - : BorderSide.none, - borderRadius: effectiveBorderRadius.squircleBorderRadius(context), - ), - ) - : null), - child: Row( - children: [ - if (widget.leading != null) - Padding( - padding: EdgeInsetsDirectional.only(end: resolvedDirectionalHeaderPadding.left), - child: widget.leading, - ), - AnimatedDefaultTextStyle( - style: effectiveMoonAccordionSize.textStyle.copyWith(color: effectiveTextColor), - duration: effectiveTransitionDuration, - child: Expanded(child: widget.title), - ), - widget.trailing ?? _buildIcon(context)!, - ], - ), - ), - ClipRect( - child: Column( - children: [ - Align( - alignment: widget.expandedAlignment ?? Alignment.topCenter, - heightFactor: _curvedAnimation!.value, - child: child, - ), - ], + child: _buildHeader( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + _buildHeader( + isContentOutsideHeader: true, + child: Row( + children: [ + if (widget.leading != null) + Padding( + padding: EdgeInsetsDirectional.only(end: _resolvedDirectionalHeaderPadding!.left), + child: widget.leading, ), + Expanded(child: widget.title), + widget.trailing ?? _buildIcon(context)!, + ], + ), + ), + ClipRect( + child: Column( + children: [ + Align( + alignment: widget.expandedAlignment ?? Alignment.topCenter, + heightFactor: _expansionCurvedAnimation!.value, + child: rootChild, ), ], ), ), - ), + ], ), ), ), @@ -560,22 +590,22 @@ class _MoonAccordionItemState extends State> with Single @override Widget build(BuildContext context) { + final Color effectiveDividerColor = + widget.dividerColor ?? context.moonTheme?.accordionTheme.itemColors.dividerColor ?? MoonColors.light.beerus; + final Duration effectiveTransitionDuration = widget.transitionDuration ?? context.moonTheme?.accordionTheme.itemProperties.transitionDuration ?? const Duration(milliseconds: 200); - _animationController ??= AnimationController(duration: effectiveTransitionDuration, vsync: this); - - final bool closed = !_isExpanded && _animationController!.isDismissed; - final bool shouldRemoveChildren = closed && !widget.maintainState; + _expansionAnimationController ??= AnimationController(duration: effectiveTransitionDuration, vsync: this); - final Color effectiveDividerColor = - widget.dividerColor ?? context.moonTheme?.accordionTheme.itemColors.dividerColor ?? MoonColors.light.beerus; + final bool isClosed = !_isExpanded && _expansionAnimationController!.isDismissed; + final bool shouldRemoveChildren = isClosed && !widget.maintainState; final Widget result = Offstage( - offstage: closed, + offstage: isClosed, child: TickerMode( - enabled: !closed, + enabled: !isClosed, child: Column( children: [ if (widget.showDivider && !widget.hasContentOutside) Container(height: 1, color: effectiveDividerColor), @@ -592,7 +622,7 @@ class _MoonAccordionItemState extends State> with Single ); return AnimatedBuilder( - animation: _animationController!.view, + animation: _expansionAnimationController!.view, builder: _buildChildren, child: shouldRemoveChildren ? null : result, ); diff --git a/lib/src/widgets/buttons/button.dart b/lib/src/widgets/buttons/button.dart index 0c9eff89..fef0ae53 100644 --- a/lib/src/widgets/buttons/button.dart +++ b/lib/src/widgets/buttons/button.dart @@ -5,10 +5,10 @@ import 'package:moon_design/src/theme/button/button_size_properties.dart'; import 'package:moon_design/src/theme/colors.dart'; import 'package:moon_design/src/theme/effects/hover_effects.dart'; import 'package:moon_design/src/theme/theme.dart'; +import 'package:moon_design/src/theme/typography/typography.dart'; +import 'package:moon_design/src/utils/color_tween_premul.dart'; import 'package:moon_design/src/utils/extensions.dart'; -import 'package:moon_design/src/utils/shape_decoration_premul.dart'; import 'package:moon_design/src/utils/squircle/squircle_border.dart'; -import 'package:moon_design/src/widgets/common/animated_icon_theme.dart'; import 'package:moon_design/src/widgets/common/base_control.dart'; enum MoonButtonSize { @@ -19,7 +19,7 @@ enum MoonButtonSize { xl, } -class MoonButton extends StatelessWidget { +class MoonButton extends StatefulWidget { /// {@macro flutter.widgets.Focus.autofocus} final bool autofocus; @@ -71,6 +71,9 @@ class MoonButton extends StatelessWidget { /// The text color of the button. final Color? textColor; + /// The text color of the button when hovered. + final Color? hoverTextColor; + /// The border width of the button. final double? borderWidth; @@ -181,6 +184,7 @@ class MoonButton extends StatelessWidget { this.hoverEffectColor, this.pulseEffectColor, this.textColor, + this.hoverTextColor, this.borderWidth, this.disabledOpacityValue, this.gap, @@ -212,95 +216,79 @@ class MoonButton extends StatelessWidget { }); /// Constructor for creating explicit icon button. - factory MoonButton.icon({ - bool autofocus = false, - bool isFocusable = true, - bool ensureMinimalTouchTargetSize = false, - bool showBorder = false, - bool showFocusEffect = true, - bool showPulseEffect = false, - bool showPulseEffectJiggle = true, - bool showScaleAnimation = true, - bool showTooltip = false, - BorderRadiusGeometry? borderRadius, - Color? backgroundColor, - Color? borderColor, - Color? focusEffectColor, - Color? hoverEffectColor, - Color? pulseEffectColor, - double? borderWidth, - double? disabledOpacityValue, - double? gap, - double? height, - double? width, - double minTouchTargetSize = 40, - double? focusEffectExtent, - double? pulseEffectExtent, - double? scaleEffectScalar, - Duration? focusEffectDuration, - Duration? hoverEffectDuration, - Duration? pulseEffectDuration, - Duration? scaleEffectDuration, - Curve? focusEffectCurve, - Curve? hoverEffectCurve, - Curve? pulseEffectCurve, - Curve? scaleEffectCurve, - FocusNode? focusNode, - EdgeInsetsGeometry? padding, - MoonButtonSize? buttonSize, - Decoration? decoration, - String? semanticLabel, - String tooltipMessage = "", - VoidCallback? onLongPress, - VoidCallback? onTap, + const MoonButton.icon({ + super.key, + this.autofocus = false, + this.isFocusable = true, + this.ensureMinimalTouchTargetSize = false, + this.isFullWidth = false, + this.showBorder = false, + this.showFocusEffect = true, + this.showPulseEffect = false, + this.showPulseEffectJiggle = true, + this.showScaleAnimation = true, + this.showTooltip = false, + this.borderRadius, + this.backgroundColor, + this.borderColor, + this.focusEffectColor, + this.hoverEffectColor, + this.pulseEffectColor, + this.hoverTextColor, + this.borderWidth, + this.disabledOpacityValue, + this.gap, + this.height, + this.width, + this.minTouchTargetSize = 40, + this.focusEffectExtent, + this.pulseEffectExtent, + this.scaleEffectScalar, + this.focusEffectDuration, + this.hoverEffectDuration, + this.pulseEffectDuration, + this.scaleEffectDuration, + this.focusEffectCurve, + this.hoverEffectCurve, + this.pulseEffectCurve, + this.scaleEffectCurve, + this.padding, + this.focusNode, + this.buttonSize, + this.decoration, + this.semanticLabel, + this.tooltipMessage = "", + this.onTap, + this.onLongPress, + Color? iconColor, Widget? icon, - }) { - return MoonButton( - autofocus: autofocus, - isFocusable: isFocusable, - ensureMinimalTouchTargetSize: ensureMinimalTouchTargetSize, - showBorder: showBorder, - showFocusEffect: showFocusEffect, - showPulseEffect: showPulseEffect, - showPulseEffectJiggle: showPulseEffectJiggle, - showScaleAnimation: showScaleAnimation, - showTooltip: showTooltip, - borderRadius: borderRadius, - backgroundColor: backgroundColor, - borderColor: borderColor, - focusEffectColor: focusEffectColor, - hoverEffectColor: hoverEffectColor, - pulseEffectColor: pulseEffectColor, - borderWidth: borderWidth, - disabledOpacityValue: disabledOpacityValue, - gap: gap, - height: height, - width: width, - minTouchTargetSize: minTouchTargetSize, - focusEffectExtent: focusEffectExtent, - pulseEffectExtent: pulseEffectExtent, - scaleEffectScalar: scaleEffectScalar, - focusEffectDuration: focusEffectDuration, - hoverEffectDuration: hoverEffectDuration, - pulseEffectDuration: pulseEffectDuration, - scaleEffectDuration: scaleEffectDuration, - focusEffectCurve: focusEffectCurve, - hoverEffectCurve: hoverEffectCurve, - pulseEffectCurve: pulseEffectCurve, - scaleEffectCurve: scaleEffectCurve, - focusNode: focusNode, - padding: padding, - buttonSize: buttonSize, - decoration: decoration, - semanticLabel: semanticLabel, - tooltipMessage: tooltipMessage, - onLongPress: onLongPress, - onTap: onTap, - leading: icon, - ); - } + }) : textColor = iconColor, + leading = icon, + label = null, + trailing = null; + + @override + State createState() => _MoonButtonState(); +} + +class _MoonButtonState extends State with SingleTickerProviderStateMixin { + final ColorTweenWithPremultipliedAlpha _backgroundColorTween = ColorTweenWithPremultipliedAlpha(); + final ColorTweenWithPremultipliedAlpha _textColorTween = ColorTweenWithPremultipliedAlpha(); - bool get _isEnabled => onTap != null || onLongPress != null; + Animation? _backgroundColor; + Animation? _textColor; + + AnimationController? _animationController; + + bool get _isEnabled => widget.onTap != null || widget.onLongPress != null; + + void _handleHoverEffect(bool shouldAnimate) { + if (shouldAnimate) { + _animationController?.forward(); + } else { + _animationController?.reverse(); + } + } MoonButtonSizeProperties _getMoonButtonSize(BuildContext context, MoonButtonSize? moonButtonSize) { switch (moonButtonSize) { @@ -319,174 +307,183 @@ class MoonButton extends StatelessWidget { } } - Color _getTextColor( - BuildContext context, { - required bool isDarkMode, - required bool isHovered, - required bool isFocused, - }) { - if (textColor != null && (!isHovered && !isFocused)) return textColor!; - if (backgroundColor == null && context.moonTypography != null) return context.moonTypography!.colors.bodyPrimary; - - final backgroundLuminance = backgroundColor!.computeLuminance(); - if (backgroundLuminance > 0.5) { - return MoonColors.light.bulma; - } else { - return MoonColors.dark.bulma; - } + @override + void dispose() { + _animationController?.dispose(); + super.dispose(); } @override Widget build(BuildContext context) { - final MoonButtonSizeProperties effectiveMoonButtonSize = _getMoonButtonSize(context, buttonSize); + final MoonButtonSizeProperties effectiveMoonButtonSize = _getMoonButtonSize(context, widget.buttonSize); - final BorderRadiusGeometry effectiveBorderRadius = borderRadius ?? effectiveMoonButtonSize.borderRadius; + final BorderRadiusGeometry effectiveBorderRadius = widget.borderRadius ?? effectiveMoonButtonSize.borderRadius; final Color effectiveBorderColor = - borderColor ?? context.moonTheme?.buttonTheme.colors.borderColor ?? MoonColors.light.trunks; + widget.borderColor ?? context.moonTheme?.buttonTheme.colors.borderColor ?? MoonColors.light.trunks; final double effectiveBorderWidth = - borderWidth ?? context.moonBorders?.defaultBorderWidth ?? MoonBorders.borders.defaultBorderWidth; + widget.borderWidth ?? context.moonBorders?.defaultBorderWidth ?? MoonBorders.borders.defaultBorderWidth; - final Color effectiveHoverEffectColor = hoverEffectColor ?? + final Color effectiveTextColor = + widget.textColor ?? context.moonTheme?.buttonTheme.colors.textColor ?? MoonTypography.light.colors.bodyPrimary; + + final Color effectiveHoverEffectColor = widget.hoverEffectColor ?? context.moonEffects?.controlHoverEffect.primaryHoverColor ?? MoonHoverEffects.lightHoverEffect.primaryHoverColor; - final Color hoverColor = Color.alphaBlend(effectiveHoverEffectColor, backgroundColor ?? Colors.transparent); + final Color hoverColor = Color.alphaBlend(effectiveHoverEffectColor, widget.backgroundColor ?? Colors.transparent); - final double effectiveHeight = height ?? effectiveMoonButtonSize.height; + final double effectiveHeight = widget.height ?? effectiveMoonButtonSize.height; - final double effectiveGap = gap ?? effectiveMoonButtonSize.gap; + final double effectiveGap = widget.gap ?? effectiveMoonButtonSize.gap; - final EdgeInsetsGeometry effectivePadding = padding ?? effectiveMoonButtonSize.padding; + final EdgeInsetsGeometry effectivePadding = widget.padding ?? effectiveMoonButtonSize.padding; final EdgeInsets resolvedDirectionalPadding = effectivePadding.resolve(Directionality.of(context)); - final EdgeInsetsGeometry correctedPadding = padding == null + final EdgeInsetsGeometry correctedPadding = widget.padding == null ? EdgeInsetsDirectional.fromSTEB( - leading == null && label != null ? resolvedDirectionalPadding.left : 0, + widget.leading == null && widget.label != null ? resolvedDirectionalPadding.left : 0, resolvedDirectionalPadding.top, - trailing == null && label != null ? resolvedDirectionalPadding.right : 0, + widget.trailing == null && widget.label != null ? resolvedDirectionalPadding.right : 0, resolvedDirectionalPadding.bottom, ) : resolvedDirectionalPadding; - final Duration effectiveHoverEffectDuration = hoverEffectDuration ?? + final Duration effectiveHoverEffectDuration = widget.hoverEffectDuration ?? context.moonEffects?.controlHoverEffect.hoverDuration ?? MoonHoverEffects.lightHoverEffect.hoverDuration; - final Curve effectiveHoverEffectCurve = hoverEffectCurve ?? + final Curve effectiveHoverEffectCurve = widget.hoverEffectCurve ?? context.moonEffects?.controlHoverEffect.hoverCurve ?? MoonHoverEffects.lightHoverEffect.hoverCurve; + _animationController ??= AnimationController(duration: effectiveHoverEffectDuration, vsync: this); + + _backgroundColor ??= + _animationController!.drive(_backgroundColorTween.chain(CurveTween(curve: effectiveHoverEffectCurve))); + + _textColor ??= _animationController!.drive(_textColorTween.chain(CurveTween(curve: effectiveHoverEffectCurve))); + + _backgroundColorTween + ..begin = widget.backgroundColor + ..end = hoverColor; + + _textColorTween + ..begin = effectiveTextColor + ..end = widget.hoverTextColor ?? effectiveTextColor; + return MoonBaseControl( - autofocus: autofocus, - isFocusable: isFocusable, - ensureMinimalTouchTargetSize: ensureMinimalTouchTargetSize, + autofocus: widget.autofocus, + isFocusable: widget.isFocusable, + ensureMinimalTouchTargetSize: widget.ensureMinimalTouchTargetSize, semanticTypeIsButton: true, - showFocusEffect: showFocusEffect, - showPulseEffect: showPulseEffect, - showPulseEffectJiggle: showPulseEffectJiggle, - showScaleAnimation: showScaleAnimation, - showTooltip: showTooltip, + showFocusEffect: widget.showFocusEffect, + showPulseEffect: widget.showPulseEffect, + showPulseEffectJiggle: widget.showPulseEffectJiggle, + showScaleAnimation: widget.showScaleAnimation, + showTooltip: widget.showTooltip, borderRadius: effectiveBorderRadius, - backgroundColor: backgroundColor, - focusEffectColor: focusEffectColor, - pulseEffectColor: pulseEffectColor, - disabledOpacityValue: disabledOpacityValue, - minTouchTargetSize: minTouchTargetSize, - focusEffectExtent: focusEffectExtent, - pulseEffectExtent: pulseEffectExtent, - scaleEffectScalar: scaleEffectScalar, - focusEffectDuration: focusEffectDuration, - pulseEffectDuration: pulseEffectDuration, - scaleEffectDuration: scaleEffectDuration, - focusEffectCurve: focusEffectCurve, - pulseEffectCurve: pulseEffectCurve, - scaleEffectCurve: scaleEffectCurve, - focusNode: focusNode, - semanticLabel: semanticLabel, - tooltipMessage: tooltipMessage, - onTap: onTap, - onLongPress: onLongPress, + backgroundColor: widget.backgroundColor, + focusEffectColor: widget.focusEffectColor, + pulseEffectColor: widget.pulseEffectColor, + disabledOpacityValue: widget.disabledOpacityValue, + minTouchTargetSize: widget.minTouchTargetSize, + focusEffectExtent: widget.focusEffectExtent, + pulseEffectExtent: widget.pulseEffectExtent, + scaleEffectScalar: widget.scaleEffectScalar, + focusEffectDuration: widget.focusEffectDuration, + pulseEffectDuration: widget.pulseEffectDuration, + scaleEffectDuration: widget.scaleEffectDuration, + focusEffectCurve: widget.focusEffectCurve, + pulseEffectCurve: widget.pulseEffectCurve, + scaleEffectCurve: widget.scaleEffectCurve, + focusNode: widget.focusNode, + semanticLabel: widget.semanticLabel, + tooltipMessage: widget.tooltipMessage, + onTap: widget.onTap, + onLongPress: widget.onLongPress, builder: (context, isEnabled, isHovered, isFocused, isPressed) { - final Color effectiveTextColor = - _getTextColor(context, isDarkMode: context.isDarkMode, isHovered: isHovered, isFocused: isFocused); - - final bool canAnimateHover = _isEnabled && (isHovered || isFocused || isPressed); - - return AnimatedContainer( - duration: effectiveHoverEffectDuration, - curve: effectiveHoverEffectCurve, - width: width, - height: effectiveHeight, - constraints: BoxConstraints(minWidth: effectiveHeight), - decoration: decoration ?? - ShapeDecorationWithPremultipliedAlpha( - color: canAnimateHover ? hoverColor : backgroundColor, - shape: MoonSquircleBorder( - side: BorderSide( - color: effectiveBorderColor, - width: showBorder ? effectiveBorderWidth : 0, - style: showBorder ? BorderStyle.solid : BorderStyle.none, - ), - borderRadius: effectiveBorderRadius.squircleBorderRadius(context), - ), + final bool canAnimate = _isEnabled && (isHovered || isFocused || isPressed); + _handleHoverEffect(canAnimate); + + return AnimatedBuilder( + animation: _animationController!, + builder: (context, child) { + return IconTheme( + data: IconThemeData( + color: _textColor!.value, + size: effectiveMoonButtonSize.iconSizeValue, ), - child: Padding( - padding: isFullWidth ? EdgeInsets.zero : correctedPadding, - child: AnimatedIconTheme( - duration: effectiveHoverEffectDuration, - color: effectiveTextColor, - size: effectiveMoonButtonSize.iconSizeValue, - child: AnimatedDefaultTextStyle( - style: TextStyle(color: effectiveTextColor, fontSize: effectiveMoonButtonSize.textStyle.fontSize), - duration: effectiveHoverEffectDuration, - child: isFullWidth - ? Stack( - fit: StackFit.expand, - children: [ - if (leading != null) - Container( - margin: EdgeInsets.symmetric(horizontal: effectiveGap), - alignment: Directionality.of(context) == TextDirection.ltr - ? Alignment.centerLeft - : Alignment.centerRight, - child: leading, - ), - if (label != null) - Align( - child: label, - ), - if (trailing != null) - Container( - margin: EdgeInsets.symmetric(horizontal: effectiveGap), - alignment: Directionality.of(context) == TextDirection.ltr - ? Alignment.centerRight - : Alignment.centerLeft, - child: trailing, - ), - ], - ) - : Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (leading != null) - Padding( - padding: EdgeInsets.symmetric(horizontal: effectiveGap), - child: leading, - ), - if (label != null) label!, - if (trailing != null) - Padding( - padding: EdgeInsets.symmetric(horizontal: effectiveGap), - child: trailing, - ), - ], + child: DefaultTextStyle( + style: TextStyle(color: _textColor!.value, fontSize: effectiveMoonButtonSize.textStyle.fontSize), + child: Container( + width: widget.width, + height: effectiveHeight, + constraints: BoxConstraints(minWidth: effectiveHeight), + decoration: widget.decoration ?? + ShapeDecoration( + color: _backgroundColor!.value, + shape: MoonSquircleBorder( + borderRadius: effectiveBorderRadius.squircleBorderRadius(context), + side: BorderSide( + color: effectiveBorderColor, + width: widget.showBorder ? effectiveBorderWidth : 0, + style: widget.showBorder ? BorderStyle.solid : BorderStyle.none, + ), + ), ), + child: child, + ), ), - ), + ); + }, + child: Padding( + padding: widget.isFullWidth ? EdgeInsets.zero : correctedPadding, + child: widget.isFullWidth + ? Stack( + fit: StackFit.expand, + children: [ + if (widget.leading != null) + Container( + margin: EdgeInsets.symmetric(horizontal: effectiveGap), + alignment: Directionality.of(context) == TextDirection.ltr + ? Alignment.centerLeft + : Alignment.centerRight, + child: widget.leading, + ), + if (widget.label != null) + Align( + child: widget.label, + ), + if (widget.trailing != null) + Container( + margin: EdgeInsets.symmetric(horizontal: effectiveGap), + alignment: Directionality.of(context) == TextDirection.ltr + ? Alignment.centerRight + : Alignment.centerLeft, + child: widget.trailing, + ), + ], + ) + : Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (widget.leading != null) + Padding( + padding: EdgeInsets.symmetric(horizontal: effectiveGap), + child: widget.leading, + ), + if (widget.label != null) widget.label!, + if (widget.trailing != null) + Padding( + padding: EdgeInsets.symmetric(horizontal: effectiveGap), + child: widget.trailing, + ), + ], + ), ), ); }, diff --git a/lib/src/widgets/buttons/filled_button.dart b/lib/src/widgets/buttons/filled_button.dart index e462d827..1d7abebb 100644 --- a/lib/src/widgets/buttons/filled_button.dart +++ b/lib/src/widgets/buttons/filled_button.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:moon_design/src/theme/colors.dart'; import 'package:moon_design/src/theme/theme.dart'; +import 'package:moon_design/src/theme/typography/typography.dart'; import 'package:moon_design/src/widgets/buttons/button.dart'; class MoonFilledButton extends StatelessWidget { @@ -105,6 +106,9 @@ class MoonFilledButton extends StatelessWidget { context.moonTheme?.buttonTheme.colors.filledVariantBackgroundColor ?? MoonColors.light.piccolo; + final effectiveTextColor = + context.moonTheme?.buttonTheme.colors.filledVariantTextColor ?? MoonTypography.light.colors.controlPrimary; + return MoonButton( autofocus: autofocus, isFocusable: isFocusable, @@ -112,6 +116,7 @@ class MoonFilledButton extends StatelessWidget { isFullWidth: isFullWidth, showPulseEffect: showPulseEffect, showTooltip: showTooltip, + textColor: effectiveTextColor, borderRadius: borderRadius, backgroundColor: effectiveBackgroundColor, height: height, diff --git a/lib/src/widgets/buttons/text_button.dart b/lib/src/widgets/buttons/text_button.dart index 01fc137b..162512a5 100644 --- a/lib/src/widgets/buttons/text_button.dart +++ b/lib/src/widgets/buttons/text_button.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:moon_design/src/theme/colors.dart'; import 'package:moon_design/src/theme/theme.dart'; +import 'package:moon_design/src/theme/typography/typography.dart'; import 'package:moon_design/src/utils/extensions.dart'; import 'package:moon_design/src/widgets/buttons/button.dart'; @@ -94,7 +95,11 @@ class MoonTextButton extends StatelessWidget { @override Widget build(BuildContext context) { - final effectiveTextColor = context.moonTheme?.buttonTheme.colors.textVariantTextColor ?? MoonColors.light.trunks; + final effectiveTextColor = + context.moonTheme?.buttonTheme.colors.textVariantTextColor ?? MoonTypography.light.colors.bodySecondary; + + final effectiveHoverTextColor = + context.moonTheme?.buttonTheme.colors.textColor ?? MoonTypography.light.colors.bodyPrimary; final effectiveHoverColor = context.moonTheme?.buttonTheme.colors.textVariantHoverColor ?? MoonColors.light.jiren; @@ -110,6 +115,7 @@ class MoonTextButton extends StatelessWidget { showPulseEffect: showPulseEffect, showTooltip: showTooltip, textColor: effectiveTextColor, + hoverTextColor: effectiveHoverTextColor, hoverEffectColor: effectiveHoverColor, focusEffectColor: effectiveFocusColor, height: height, diff --git a/lib/src/widgets/chips/chip.dart b/lib/src/widgets/chips/chip.dart index eb5c8213..1564ee95 100644 --- a/lib/src/widgets/chips/chip.dart +++ b/lib/src/widgets/chips/chip.dart @@ -5,10 +5,10 @@ import 'package:moon_design/src/theme/chip/chip_size_properties.dart'; import 'package:moon_design/src/theme/colors.dart'; import 'package:moon_design/src/theme/effects/hover_effects.dart'; import 'package:moon_design/src/theme/theme.dart'; +import 'package:moon_design/src/theme/typography/typography.dart'; +import 'package:moon_design/src/utils/color_tween_premul.dart'; import 'package:moon_design/src/utils/extensions.dart'; -import 'package:moon_design/src/utils/shape_decoration_premul.dart'; import 'package:moon_design/src/utils/squircle/squircle_border.dart'; -import 'package:moon_design/src/widgets/common/animated_icon_theme.dart'; import 'package:moon_design/src/widgets/common/base_control.dart'; enum MoonChipSize { @@ -16,7 +16,7 @@ enum MoonChipSize { md, } -class MoonChip extends StatelessWidget { +class MoonChip extends StatefulWidget { /// {@macro flutter.widgets.Focus.autofocus} final bool autofocus; @@ -41,21 +41,21 @@ class MoonChip extends StatelessWidget { /// The border radius of the chip. final BorderRadiusGeometry? borderRadius; - /// The border and text color of the active/selected chip. + /// The border and text color of the chip when active. final Color? activeColor; /// The background color of the chip. final Color? backgroundColor; + /// The background color of the chip when active. + final Color? activeBackgroundColor; + /// The border color of the chip. final Color? borderColor; /// The color of the focus effect. final Color? focusEffectColor; - /// The color of the hover effect. - final Color? hoverEffectColor; - /// The text color of the chip. final Color? textColor; @@ -80,18 +80,18 @@ class MoonChip extends StatelessWidget { /// The minimum size of the touch target. final double minTouchTargetSize; + /// The duration of the active effect. + final Duration? activeEffectDuration; + /// The duration of the focus effect. final Duration? focusEffectDuration; - /// The duration of the hover effect. - final Duration? hoverEffectDuration; + /// The curve of the hover effect. + final Curve? activeEffectCurve; /// The curve of the focus effect. final Curve? focusEffectCurve; - /// The curve of the hover effect. - final Curve? hoverEffectCurve; - /// The padding of the chip. final EdgeInsetsGeometry? padding; @@ -138,9 +138,9 @@ class MoonChip extends StatelessWidget { this.borderRadius, this.activeColor, this.backgroundColor, + this.activeBackgroundColor, this.borderColor, this.focusEffectColor, - this.hoverEffectColor, this.textColor, this.borderWidth, this.disabledOpacityValue, @@ -149,10 +149,10 @@ class MoonChip extends StatelessWidget { this.height, this.width, this.minTouchTargetSize = 40, + this.activeEffectDuration, this.focusEffectDuration, - this.hoverEffectDuration, + this.activeEffectCurve, this.focusEffectCurve, - this.hoverEffectCurve, this.padding, this.focusNode, this.chipSize, @@ -166,6 +166,69 @@ class MoonChip extends StatelessWidget { this.trailing, }); + /// MDS chip widget text variant + const MoonChip.text({ + super.key, + this.autofocus = false, + this.isFocusable = true, + this.ensureMinimalTouchTargetSize = false, + this.isActive = false, + this.showBorder = false, + this.showFocusEffect = true, + this.showTooltip = false, + this.borderRadius, + this.activeColor, + this.activeBackgroundColor, + this.borderColor, + this.focusEffectColor, + this.textColor, + this.borderWidth, + this.disabledOpacityValue, + this.focusEffectExtent, + this.gap, + this.height, + this.width, + this.minTouchTargetSize = 40, + this.focusEffectDuration, + this.activeEffectDuration, + this.focusEffectCurve, + this.activeEffectCurve, + this.padding, + this.focusNode, + this.chipSize, + this.decoration, + this.semanticLabel, + this.tooltipMessage = "", + this.onTap, + this.onLongPress, + this.label, + this.leading, + this.trailing, + }) : backgroundColor = Colors.transparent; + + @override + State createState() => _MoonChipState(); +} + +class _MoonChipState extends State with SingleTickerProviderStateMixin { + final ColorTweenWithPremultipliedAlpha _backgroundColorTween = ColorTweenWithPremultipliedAlpha(); + final ColorTweenWithPremultipliedAlpha _borderColorTween = ColorTweenWithPremultipliedAlpha(); + final ColorTweenWithPremultipliedAlpha _textColorTween = ColorTweenWithPremultipliedAlpha(); + + Animation? _backgroundColor; + Animation? _borderColor; + Animation? _textColor; + + AnimationController? _animationController; + + void _handleActiveEffect(bool shouldAnimate) { + if (shouldAnimate) { + _animationController?.forward(); + } else { + _animationController?.reverse(); + } + } + MoonChipSizeProperties _getMoonChipSize(BuildContext context, MoonChipSize? moonChipSize) { switch (moonChipSize) { case MoonChipSize.sm: @@ -178,146 +241,156 @@ class MoonChip extends StatelessWidget { } } - Color _getTextColor({ - required bool isActive, - required Color activeColor, - required Color backgroundColor, - required Color? textColor, - }) { - if (isActive) return activeColor; - if (textColor != null) return textColor; - - final backgroundLuminance = backgroundColor.computeLuminance(); - if (backgroundLuminance > 0.5) { - return MoonColors.light.bulma; - } else { - return MoonColors.dark.bulma; - } + @override + void dispose() { + _animationController?.dispose(); + super.dispose(); } - Color _getBorderColor({required bool isActive, required Color activeColor}) => - isActive ? activeColor : borderColor ?? Colors.transparent; - @override Widget build(BuildContext context) { - final MoonChipSizeProperties effectiveMoonChipSize = _getMoonChipSize(context, chipSize); + final MoonChipSizeProperties effectiveMoonChipSize = _getMoonChipSize(context, widget.chipSize); - final BorderRadiusGeometry effectiveBorderRadius = borderRadius ?? effectiveMoonChipSize.borderRadius; + final BorderRadiusGeometry effectiveBorderRadius = widget.borderRadius ?? effectiveMoonChipSize.borderRadius; final double effectiveBorderWidth = - borderWidth ?? context.moonBorders?.defaultBorderWidth ?? MoonBorders.borders.defaultBorderWidth; + widget.borderWidth ?? context.moonBorders?.defaultBorderWidth ?? MoonBorders.borders.defaultBorderWidth; - final double effectiveHeight = height ?? effectiveMoonChipSize.height; + final double effectiveHeight = widget.height ?? effectiveMoonChipSize.height; - final double effectiveGap = gap ?? effectiveMoonChipSize.gap; + final double effectiveGap = widget.gap ?? effectiveMoonChipSize.gap; final Color effectiveActiveColor = - activeColor ?? context.moonTheme?.chipTheme.colors.activeColor ?? MoonColors.light.piccolo; + widget.activeColor ?? context.moonTheme?.chipTheme.colors.activeColor ?? MoonColors.light.piccolo; final Color effectiveBackgroundColor = - backgroundColor ?? context.moonTheme?.chipTheme.colors.backgroundColor ?? MoonColors.light.gohan; + widget.backgroundColor ?? context.moonTheme?.chipTheme.colors.backgroundColor ?? MoonColors.light.gohan; - final Color effectiveHoverEffectColor = hoverEffectColor ?? - context.moonEffects?.controlHoverEffect.secondaryHoverColor ?? - MoonHoverEffects.lightHoverEffect.secondaryHoverColor; + final Color effectiveActiveBackgroundColor = widget.activeBackgroundColor ?? + context.moonTheme?.chipTheme.colors.activeBackgroundColor ?? + MoonColors.light.jiren; - final Curve effectiveHoverEffectCurve = hoverEffectCurve ?? + final Color effectiveTextColor = + widget.textColor ?? context.moonTheme?.chipTheme.colors.textColor ?? MoonTypography.light.colors.bodyPrimary; + + final Curve effectiveActiveEffectCurve = widget.activeEffectCurve ?? context.moonEffects?.controlHoverEffect.hoverCurve ?? MoonHoverEffects.lightHoverEffect.hoverCurve; - final Duration effectiveHoverEffectDuration = hoverEffectDuration ?? + final Duration effectiveActiveEffectDuration = widget.activeEffectDuration ?? context.moonEffects?.controlHoverEffect.hoverDuration ?? MoonHoverEffects.lightHoverEffect.hoverDuration; - final EdgeInsetsGeometry effectivePadding = padding ?? effectiveMoonChipSize.padding; + final EdgeInsetsGeometry effectivePadding = widget.padding ?? effectiveMoonChipSize.padding; final EdgeInsets resolvedDirectionalPadding = effectivePadding.resolve(Directionality.of(context)); - final EdgeInsetsGeometry correctedPadding = padding == null + final EdgeInsetsGeometry correctedPadding = widget.padding == null ? EdgeInsetsDirectional.fromSTEB( - leading == null && label != null ? resolvedDirectionalPadding.left : 0, + widget.leading == null && widget.label != null ? resolvedDirectionalPadding.left : 0, resolvedDirectionalPadding.top, - trailing == null && label != null ? resolvedDirectionalPadding.right : 0, + widget.trailing == null && widget.label != null ? resolvedDirectionalPadding.right : 0, resolvedDirectionalPadding.bottom, ) : resolvedDirectionalPadding; + + _animationController ??= AnimationController(duration: effectiveActiveEffectDuration, vsync: this); + + _backgroundColor ??= + _animationController!.drive(_backgroundColorTween.chain(CurveTween(curve: effectiveActiveEffectCurve))); + + _borderColor ??= + _animationController!.drive(_borderColorTween.chain(CurveTween(curve: effectiveActiveEffectCurve))); + + _textColor ??= _animationController!.drive(_textColorTween.chain(CurveTween(curve: effectiveActiveEffectCurve))); + + _backgroundColorTween + ..begin = effectiveBackgroundColor + ..end = effectiveActiveBackgroundColor; + + _borderColorTween + ..begin = Colors.transparent + ..end = widget.borderColor ?? effectiveActiveColor; + + _textColorTween + ..begin = effectiveTextColor + ..end = effectiveActiveColor; + return MoonBaseControl( - autofocus: autofocus, - isFocusable: isFocusable, - ensureMinimalTouchTargetSize: ensureMinimalTouchTargetSize, - showFocusEffect: showFocusEffect, + autofocus: widget.autofocus, + isFocusable: widget.isFocusable, + ensureMinimalTouchTargetSize: widget.ensureMinimalTouchTargetSize, + showFocusEffect: widget.showFocusEffect, showScaleAnimation: false, - showTooltip: showTooltip, + showTooltip: widget.showTooltip, borderRadius: effectiveBorderRadius, - backgroundColor: backgroundColor, - focusEffectColor: focusEffectColor, - disabledOpacityValue: disabledOpacityValue, - minTouchTargetSize: minTouchTargetSize, - focusEffectExtent: focusEffectExtent, - focusEffectDuration: focusEffectDuration, - focusEffectCurve: focusEffectCurve, - focusNode: focusNode, - tooltipMessage: tooltipMessage, - semanticLabel: semanticLabel, - onTap: onTap ?? () {}, - onLongPress: onLongPress, + backgroundColor: widget.backgroundColor, + focusEffectColor: widget.focusEffectColor, + disabledOpacityValue: widget.disabledOpacityValue, + minTouchTargetSize: widget.minTouchTargetSize, + focusEffectExtent: widget.focusEffectExtent, + focusEffectDuration: widget.focusEffectDuration, + focusEffectCurve: widget.focusEffectCurve, + focusNode: widget.focusNode, + tooltipMessage: widget.tooltipMessage, + semanticLabel: widget.semanticLabel, + onTap: widget.onTap ?? () {}, + onLongPress: widget.onLongPress, builder: (context, isEnabled, isHovered, isFocused, isPressed) { - final bool canAnimate = isActive || isHovered || isFocused; - - final Color effectiveBorderColor = - borderColor ?? _getBorderColor(isActive: canAnimate, activeColor: effectiveActiveColor); - - final Color effectiveTextColor = _getTextColor( - isActive: canAnimate, - activeColor: effectiveActiveColor, - backgroundColor: effectiveBackgroundColor, - textColor: textColor, - ); - - return AnimatedContainer( - width: width, - height: effectiveHeight, - padding: correctedPadding, - duration: effectiveHoverEffectDuration, - curve: effectiveHoverEffectCurve, - constraints: BoxConstraints(minWidth: effectiveHeight), - decoration: decoration ?? - ShapeDecorationWithPremultipliedAlpha( - color: canAnimate ? effectiveHoverEffectColor : effectiveBackgroundColor, - shape: MoonSquircleBorder( - side: BorderSide( - color: effectiveBorderColor, - width: showBorder ? effectiveBorderWidth : 0, - style: showBorder ? BorderStyle.solid : BorderStyle.none, - ), - borderRadius: effectiveBorderRadius.squircleBorderRadius(context), - ), + final bool canAnimate = widget.isActive || isHovered || isFocused; + _handleActiveEffect(canAnimate); + + return AnimatedBuilder( + animation: _animationController!, + builder: (context, child) { + return IconTheme( + data: IconThemeData( + color: _textColor!.value, + size: effectiveMoonChipSize.iconSizeValue, ), - child: AnimatedIconTheme( - duration: effectiveHoverEffectDuration, - color: effectiveTextColor, - size: effectiveMoonChipSize.iconSizeValue, - child: AnimatedDefaultTextStyle( - duration: effectiveHoverEffectDuration, - style: TextStyle(fontSize: effectiveMoonChipSize.textStyle.fontSize, color: effectiveTextColor), - child: Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (leading != null) - Padding( - padding: EdgeInsets.symmetric(horizontal: effectiveGap), - child: leading, - ), - if (label != null) label!, - if (trailing != null) - Padding( - padding: EdgeInsets.symmetric(horizontal: effectiveGap), - child: trailing, - ), - ], + child: DefaultTextStyle( + style: TextStyle( + color: _textColor!.value, + fontSize: effectiveMoonChipSize.textStyle.fontSize, + ), + child: Container( + width: widget.width, + height: effectiveHeight, + padding: correctedPadding, + constraints: BoxConstraints(minWidth: effectiveHeight), + decoration: widget.decoration ?? + ShapeDecoration( + color: _backgroundColor!.value, + shape: MoonSquircleBorder( + borderRadius: effectiveBorderRadius.squircleBorderRadius(context), + side: BorderSide( + color: widget.showBorder ? _borderColor!.value! : Colors.transparent, + width: widget.showBorder ? effectiveBorderWidth : 0, + style: widget.showBorder ? BorderStyle.solid : BorderStyle.none, + ), + ), + ), + child: child, + ), ), - ), + ); + }, + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (widget.leading != null) + Padding( + padding: EdgeInsets.symmetric(horizontal: effectiveGap), + child: widget.leading, + ), + if (widget.label != null) widget.label!, + if (widget.trailing != null) + Padding( + padding: EdgeInsets.symmetric(horizontal: effectiveGap), + child: widget.trailing, + ), + ], ), ); }, diff --git a/lib/src/widgets/chips/text_chip.dart b/lib/src/widgets/chips/text_chip.dart deleted file mode 100644 index 7c75b005..00000000 --- a/lib/src/widgets/chips/text_chip.dart +++ /dev/null @@ -1,196 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:moon_design/src/theme/colors.dart'; -import 'package:moon_design/src/theme/theme.dart'; -import 'package:moon_design/src/widgets/chips/chip.dart'; - -class MoonTextChip extends StatelessWidget { - /// {@macro flutter.widgets.Focus.autofocus} - final bool autofocus; - - /// Whether the chip should be focusable. - final bool isFocusable; - - /// Whether this chip should ensure that it has a minimal touch target size. - final bool ensureMinimalTouchTargetSize; - - /// Whether the chip is active/selected. - final bool isActive; - - /// Whether the chip should show a border. - final bool showBorder; - - /// Whether the chip should show a focus effect. - final bool showFocusEffect; - - /// Whether the chip should show a tooltip. - final bool showTooltip; - - /// The border radius of the chip. - final BorderRadiusGeometry? borderRadius; - - /// The border and text color of the active/selected chip. - final Color? activeColor; - - /// The border color of the chip. - final Color? borderColor; - - /// The color of the focus effect. - final Color? focusEffectColor; - - /// The color of the hover effect. - final Color? hoverEffectColor; - - /// The text color of the chip. - final Color? textColor; - - /// The border width of the chip. - final double? borderWidth; - - /// The opacity value of the chip when it is disabled. - final double? disabledOpacityValue; - - /// The extent of the focus effect. - final double? focusEffectExtent; - - /// The gap between the leading or trailing and the label widgets. - final double? gap; - - /// The height of the chip. - final double? height; - - /// The width of the chip. - final double? width; - - /// The minimum size of the touch target. - final double minTouchTargetSize; - - /// The duration of the focus effect. - final Duration? focusEffectDuration; - - /// The duration of the hover effect. - final Duration? hoverEffectDuration; - - /// The curve of the focus effect. - final Curve? focusEffectCurve; - - /// The curve of the hover effect. - final Curve? hoverEffectCurve; - - /// The padding of the chip. - final EdgeInsetsGeometry? padding; - - /// {@macro flutter.widgets.Focus.focusNode}. - final FocusNode? focusNode; - - /// The size of the chip. - final MoonChipSize? chipSize; - - /// Custom decoration for the chip. - final Decoration? decoration; - - /// The semantic label for the chip. - final String? semanticLabel; - - /// The tooltip message for the button. - final String tooltipMessage; - - /// The callback that is called when the chip is tapped or pressed. - final VoidCallback? onTap; - - /// The callback that is called when the chip is long-pressed. - final VoidCallback? onLongPress; - - /// The widget in the leading slot of the chip. - final Widget? leading; - - /// The widget in the label slot of the chip. - final Widget? label; - - /// The widget in the trailing slot of the chip. - final Widget? trailing; - - /// MDS text chip widget. - const MoonTextChip({ - super.key, - this.autofocus = false, - this.isFocusable = true, - this.ensureMinimalTouchTargetSize = false, - this.isActive = false, - this.showBorder = false, - this.showFocusEffect = true, - this.showTooltip = false, - this.borderRadius, - this.activeColor, - this.borderColor, - this.focusEffectColor, - this.hoverEffectColor, - this.textColor, - this.borderWidth, - this.disabledOpacityValue, - this.focusEffectExtent, - this.gap, - this.height, - this.width, - this.minTouchTargetSize = 40, - this.focusEffectDuration, - this.hoverEffectDuration, - this.focusEffectCurve, - this.hoverEffectCurve, - this.padding, - this.focusNode, - this.chipSize, - this.decoration, - this.semanticLabel, - this.tooltipMessage = "", - this.onTap, - this.onLongPress, - this.label, - this.leading, - this.trailing, - }); - - @override - Widget build(BuildContext context) { - final effectiveTextColor = textColor ?? context.moonTypography?.colors.bodyPrimary ?? MoonColors.light.bulma; - - return MoonChip( - key: key, - autofocus: autofocus, - isFocusable: isFocusable, - isActive: isActive, - ensureMinimalTouchTargetSize: ensureMinimalTouchTargetSize, - showBorder: showBorder, - showFocusEffect: showFocusEffect, - showTooltip: showTooltip, - borderRadius: borderRadius, - activeColor: activeColor, - backgroundColor: Colors.transparent, - borderColor: borderColor, - focusEffectColor: focusEffectColor, - hoverEffectColor: hoverEffectColor, - textColor: effectiveTextColor, - disabledOpacityValue: disabledOpacityValue, - focusEffectExtent: focusEffectExtent, - gap: gap, - height: height, - width: width, - minTouchTargetSize: minTouchTargetSize, - focusEffectDuration: focusEffectDuration, - hoverEffectDuration: hoverEffectDuration, - focusEffectCurve: focusEffectCurve, - hoverEffectCurve: hoverEffectCurve, - padding: padding, - focusNode: focusNode, - chipSize: chipSize, - decoration: decoration, - semanticLabel: semanticLabel, - tooltipMessage: tooltipMessage, - onTap: onTap, - onLongPress: onLongPress, - leading: leading, - label: label, - trailing: trailing, - ); - } -} diff --git a/lib/src/widgets/common/animated_icon_theme.dart b/lib/src/widgets/common/animated_icon_theme.dart index a02971bd..96e049dc 100644 --- a/lib/src/widgets/common/animated_icon_theme.dart +++ b/lib/src/widgets/common/animated_icon_theme.dart @@ -1,6 +1,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:moon_design/src/utils/color_tween_premul.dart'; + class AnimatedIconTheme extends ImplicitlyAnimatedWidget { /// The target color for icon. /// @@ -46,13 +48,14 @@ class AnimatedIconTheme extends ImplicitlyAnimatedWidget { } class _AnimatedIconThemeState extends AnimatedWidgetBaseState { - ColorTween? _color; + ColorTweenWithPremultipliedAlpha? _color; SizeTween? _size; @override void forEachTween(TweenVisitor visitor) { if (widget.color != null) { - _color = visitor(_color, widget.color, (dynamic value) => ColorTween(begin: value as Color)) as ColorTween?; + _color = visitor(_color, widget.color, (dynamic value) => ColorTweenWithPremultipliedAlpha(begin: value as Color)) + as ColorTweenWithPremultipliedAlpha?; } if (widget.size != null) { diff --git a/lib/src/widgets/modal/modal.dart b/lib/src/widgets/modal/modal.dart index 00fdb5d3..7a33f466 100644 --- a/lib/src/widgets/modal/modal.dart +++ b/lib/src/widgets/modal/modal.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:moon_design/src/theme/borders.dart'; import 'package:moon_design/src/theme/colors.dart'; import 'package:moon_design/src/theme/theme.dart'; +import 'package:moon_design/src/theme/typography/typography.dart'; import 'package:moon_design/src/utils/extensions.dart'; import 'package:moon_design/src/utils/shape_decoration_premul.dart'; import 'package:moon_design/src/utils/squircle/squircle_border.dart'; @@ -32,19 +33,6 @@ class MoonModal extends StatelessWidget { required this.child, }); - Color _getTextColor(BuildContext context, {required bool isDarkMode, required Color effectiveBackgroundColor}) { - if (backgroundColor == null && context.moonTypography != null) { - return context.moonTypography!.colors.bodyPrimary; - } - - final backgroundLuminance = effectiveBackgroundColor.computeLuminance(); - if (backgroundLuminance > 0.5) { - return MoonColors.light.bulma; - } else { - return MoonColors.dark.bulma; - } - } - @override Widget build(BuildContext context) { final BorderRadiusGeometry effectiveBorderRadius = @@ -54,7 +42,7 @@ class MoonModal extends StatelessWidget { backgroundColor ?? context.moonTheme?.modalTheme.colors.backgroundColor ?? MoonColors.light.gohan; final Color effectiveTextColor = - _getTextColor(context, isDarkMode: context.isDarkMode, effectiveBackgroundColor: effectiveBackgroundColor); + context.moonTypography?.colors.bodyPrimary ?? MoonTypography.light.colors.bodyPrimary; return Semantics( label: semanticLabel, diff --git a/lib/src/widgets/popover/popover.dart b/lib/src/widgets/popover/popover.dart index 98b583c1..b67d8063 100644 --- a/lib/src/widgets/popover/popover.dart +++ b/lib/src/widgets/popover/popover.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:moon_design/src/theme/colors.dart'; import 'package:moon_design/src/theme/shadows.dart'; import 'package:moon_design/src/theme/theme.dart'; +import 'package:moon_design/src/theme/typography/typography.dart'; import 'package:moon_design/src/utils/extensions.dart'; import 'package:moon_design/src/utils/shape_decoration_premul.dart'; import 'package:moon_design/src/utils/squircle/squircle_border.dart'; @@ -176,19 +177,6 @@ class MoonPopoverState extends State with RouteAware, SingleTickerP } } - Color _getTextColor(BuildContext context, {required Color effectiveBackgroundColor}) { - if (widget.backgroundColor == null && context.moonTypography != null) { - return context.moonTypography!.colors.bodyPrimary; - } - - final backgroundLuminance = effectiveBackgroundColor.computeLuminance(); - if (backgroundLuminance > 0.5) { - return MoonColors.light.bulma; - } else { - return MoonColors.dark.bulma; - } - } - _PopoverPositionProperties _resolvePopoverPositionParameters({ required MoonPopoverPosition popoverPosition, required double distanceToTarget, @@ -363,7 +351,8 @@ class MoonPopoverState extends State with RouteAware, SingleTickerP final Color effectiveBackgroundColor = widget.backgroundColor ?? context.moonTheme?.popoverTheme.colors.backgroundColor ?? MoonColors.light.gohan; - final Color effectiveTextColor = _getTextColor(context, effectiveBackgroundColor: effectiveBackgroundColor); + final Color effectiveTextColor = + context.moonTypography?.colors.bodyPrimary ?? MoonTypography.light.colors.bodyPrimary; final double effectiveDistanceToTarget = widget.distanceToTarget ?? context.moonTheme?.popoverTheme.properties.distanceToTarget ?? 8; @@ -450,22 +439,25 @@ class MoonPopoverState extends State with RouteAware, SingleTickerP child: RepaintBoundary( child: FadeTransition( opacity: _curvedAnimation!, - child: DefaultTextStyle( - style: DefaultTextStyle.of(context).style.copyWith(color: effectiveTextColor), - child: Container( - key: _popoverKey, - constraints: BoxConstraints(maxWidth: popoverPositionParameters.popoverMaxWidth), - padding: resolvedContentPadding, - decoration: widget.decoration ?? - ShapeDecorationWithPremultipliedAlpha( - color: effectiveBackgroundColor, - shadows: effectivePopoverShadows, - shape: MoonSquircleBorder( - borderRadius: effectiveBorderRadius.squircleBorderRadius(context), - side: BorderSide(color: widget.borderColor), + child: IconTheme( + data: IconThemeData(color: effectiveTextColor), + child: DefaultTextStyle( + style: DefaultTextStyle.of(context).style.copyWith(color: effectiveTextColor), + child: Container( + key: _popoverKey, + constraints: BoxConstraints(maxWidth: popoverPositionParameters.popoverMaxWidth), + padding: resolvedContentPadding, + decoration: widget.decoration ?? + ShapeDecorationWithPremultipliedAlpha( + color: effectiveBackgroundColor, + shadows: effectivePopoverShadows, + shape: MoonSquircleBorder( + borderRadius: effectiveBorderRadius.squircleBorderRadius(context), + side: BorderSide(color: widget.borderColor), + ), ), - ), - child: widget.content, + child: widget.content, + ), ), ), ), diff --git a/lib/src/widgets/radio/radio.dart b/lib/src/widgets/radio/radio.dart index b6bc4a54..09e8b064 100644 --- a/lib/src/widgets/radio/radio.dart +++ b/lib/src/widgets/radio/radio.dart @@ -4,6 +4,7 @@ import 'package:moon_design/src/theme/colors.dart'; import 'package:moon_design/src/theme/effects/focus_effects.dart'; import 'package:moon_design/src/theme/opacity.dart'; import 'package:moon_design/src/theme/theme.dart'; +import 'package:moon_design/src/theme/typography/typography.dart'; import 'package:moon_design/src/utils/touch_target_padding.dart'; import 'package:moon_design/src/widgets/common/effects/focus_effect.dart'; import 'package:moon_design/src/widgets/radio/radio_painter.dart'; @@ -103,7 +104,8 @@ class MoonRadio extends StatefulWidget { }) { final bool isInteractive = onChanged != null; - final Color effectiveTextColor = context.moonColors?.bulma ?? MoonColors.light.bulma; + final Color effectiveTextColor = + context.moonTypography?.colors.bodyPrimary ?? MoonTypography.light.colors.bodyPrimary; final double effectiveDisabledOpacityValue = context.moonTheme?.opacity.disabled ?? MoonOpacity.opacities.disabled; diff --git a/lib/src/widgets/text_input/input_decorator.dart b/lib/src/widgets/text_input/input_decorator.dart index e7cf3bb3..ca297b44 100644 --- a/lib/src/widgets/text_input/input_decorator.dart +++ b/lib/src/widgets/text_input/input_decorator.dart @@ -17,6 +17,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; +import 'package:moon_design/src/utils/color_tween_premul.dart'; + // Examples can assume: // late Widget _myIcon; @@ -93,7 +95,7 @@ class _InputBorderPainter extends CustomPainter { final _InputBorderGap gap; final TextDirection textDirection; final Color fillColor; - final ColorTween hoverColorTween; + final ColorTweenWithPremultipliedAlpha hoverColorTween; final Animation hoverAnimation; Color get blendedColor => Color.alphaBlend(hoverColorTween.evaluate(hoverAnimation)!, fillColor); @@ -169,7 +171,7 @@ class _BorderContainerState extends State<_BorderContainer> with TickerProviderS late Animation _borderAnimation; late _InputBorderTween _border; late Animation _hoverAnimation; - late ColorTween _hoverColorTween; + late ColorTweenWithPremultipliedAlpha _hoverColorTween; @override void initState() { @@ -195,7 +197,7 @@ class _BorderContainerState extends State<_BorderContainer> with TickerProviderS parent: _hoverColorController, curve: Curves.linear, ); - _hoverColorTween = ColorTween(begin: Colors.transparent, end: widget.hoverColor); + _hoverColorTween = ColorTweenWithPremultipliedAlpha(end: widget.hoverColor); } @override @@ -218,7 +220,7 @@ class _BorderContainerState extends State<_BorderContainer> with TickerProviderS ..forward(); } if (widget.hoverColor != oldWidget.hoverColor) { - _hoverColorTween = ColorTween(begin: Colors.transparent, end: widget.hoverColor); + _hoverColorTween = ColorTweenWithPremultipliedAlpha(end: widget.hoverColor); } if (widget.isHovering != oldWidget.isHovering) { if (widget.isHovering) {