diff --git a/packages/wyatt_ui_components/lib/src/core/core.dart b/packages/wyatt_ui_components/lib/src/core/core.dart index a18f1e81..50874264 100644 --- a/packages/wyatt_ui_components/lib/src/core/core.dart +++ b/packages/wyatt_ui_components/lib/src/core/core.dart @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -export 'enums/control_state.dart'; +export 'enums/enums.dart'; export 'extensions/build_context_extensions.dart'; export 'extensions/string_extension.dart'; export 'mixins/copy_with_mixin.dart'; diff --git a/packages/wyatt_ui_components/lib/src/core/enums/enums.dart b/packages/wyatt_ui_components/lib/src/core/enums/enums.dart new file mode 100644 index 00000000..9b4b1438 --- /dev/null +++ b/packages/wyatt_ui_components/lib/src/core/enums/enums.dart @@ -0,0 +1,18 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +export './control_state.dart'; +export './status_state.dart'; diff --git a/packages/wyatt_ui_components/lib/src/core/enums/status_state.dart b/packages/wyatt_ui_components/lib/src/core/enums/status_state.dart new file mode 100644 index 00000000..878899f6 --- /dev/null +++ b/packages/wyatt_ui_components/lib/src/core/enums/status_state.dart @@ -0,0 +1,22 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +enum StatusState { + initial, + success, + loading, + error; +} diff --git a/packages/wyatt_ui_components/lib/src/core/utils/multi_color.dart b/packages/wyatt_ui_components/lib/src/core/utils/multi_color.dart index 8f36e970..d64ac9a3 100644 --- a/packages/wyatt_ui_components/lib/src/core/utils/multi_color.dart +++ b/packages/wyatt_ui_components/lib/src/core/utils/multi_color.dart @@ -23,32 +23,57 @@ class MultiColor { final List? _colors; final Color? _color; - Color get color { - if (_color != null) { - return _color!; - } - if (_colors?.isNotEmpty ?? false) { - return _colors!.first; - } - throw IndexError.withLength( - 0, - _colors?.length ?? 0, - message: '_color is not defined or _colors is empty.', - ); - } + Color get color => _color != null + ? _color! + : _colors?.isNotEmpty ?? false + ? _colors!.first + : throw IndexError.withLength( + 0, + _colors?.length ?? 0, + message: '_color is not defined or _colors is empty.', + ); List get colors => _colors ?? []; - bool get isGradient => - (_colors?.isNotEmpty ?? false) && (_colors?.length ?? 0) > 1; + bool get isGradient => (_colors?.length ?? 0) > 1; + bool get isColor => _color != null || isGradient; static MultiColor? lerp(MultiColor? a, MultiColor? b, double t) { if (a == null && b == null) { return null; - } - if (b == null) { + } else if (a == null) { + return b; + } else if (b == null) { return a; } + if (a.isColor && b.isColor) { + return MultiColor.single(Color.lerp(a.color, b.color, t)); + } else if (a.isColor && b.isGradient) { + return MultiColor( + b.colors + .map((e) => Color.lerp(a.color, e, t)) + .whereType() + .toList(), + ); + } else if (a.isGradient && b.isColor) { + return MultiColor( + a.colors + .map((e) => Color.lerp(b.color, e, t)) + .whereType() + .toList(), + ); + } else if (a.isGradient && b.isGradient) { + final colors = List.empty(growable: true); + final shortestList = + (a.colors.length > b.colors.length) ? b.colors : a.colors; + for (int i = 0; i < shortestList.length; i++) { + final lerpColor = Color.lerp(a.colors[i], b.colors[i], t); + if (lerpColor != null) { + colors.add(lerpColor); + } + } + return MultiColor(colors); + } return b; } diff --git a/packages/wyatt_ui_components/lib/src/core/utils/theme_resolver.dart b/packages/wyatt_ui_components/lib/src/core/utils/theme_resolver.dart index 45834ca5..4626fb50 100644 --- a/packages/wyatt_ui_components/lib/src/core/utils/theme_resolver.dart +++ b/packages/wyatt_ui_components/lib/src/core/utils/theme_resolver.dart @@ -35,60 +35,55 @@ abstract class ThemeResolver, T, E> { /// {@macro theme_resolver} const ThemeResolver(); - S? Function( - BuildContext context, - S defaultValue, - T themeExtension, { - E? extra, - }) get computeExtensionValueFn; S? Function(BuildContext context, {E? extra}) get customStyleFn; /// Compute default value from Flutter Theme or with hardcoded values. S computeDefaultValue(BuildContext context, {E? extra}); - /// Compute values from the extension if found - S? computeExtensionValue( + S? computeExtensionValueFn( BuildContext context, - S defaultValue, { + T themeExtension, { + E? extra, + }); + + /// Compute values from the extension if found + S? _computeExtensionValue( + BuildContext context, { E? extra, }) { - final themeExtension = findExtension(context); + final themeExtension = Theme.of(context).extension(); if (themeExtension != null) { return computeExtensionValueFn( context, - defaultValue, themeExtension, extra: extra, ); } - return defaultValue; + return null; } /// Compute custom value - S? computeCustomValue( - BuildContext context, - S previousPhaseValue, { + S? _computeCustomValue( + BuildContext context, { E? extra, }) { - final customStyle = customStyleFn(context, extra: extra); + final customStyle = customStyleFn( + context, + extra: extra, + ); if (customStyle != null) { return customStyle; } - return previousPhaseValue; + return null; } - T? findExtension(BuildContext context) => Theme.of(context).extension(); - /// Choose most suitable style for a given context. S negotiate(BuildContext context, {E? extra}) { S style = computeDefaultValue(context, extra: extra); - final S? extensionStyle = - computeExtensionValue(context, style, extra: extra); - - style = style.mergeWith(extensionStyle); - - final S? customStyle = computeCustomValue(context, style, extra: extra); - - return style.mergeWith(customStyle); + style = + style.mergeWith(_computeExtensionValue(context, extra: extra)) ?? style; + style = + style.mergeWith(_computeCustomValue(context, extra: extra)) ?? style; + return style; } } diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/file_selection_button_style.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/file_selection_button_style.dart index 75fc9a42..85f20b88 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/file_selection_button_style.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/file_selection_button_style.dart @@ -104,18 +104,11 @@ class FileSelectionButtonStyle extends ButtonStyle { final TextStyle? subTitle; @override - FileSelectionButtonStyle mergeWith(FileSelectionButtonStyle? other) => - FileSelectionButtonStyle.merge(this, other)!; + FileSelectionButtonStyle? mergeWith(FileSelectionButtonStyle? other) => + FileSelectionButtonStyle.merge(this, other); @override - FileSelectionButtonStyle? lerpWith( - FileSelectionButtonStyle? other, - double t, - ) => - FileSelectionButtonStyle.lerp(this, other, t); - - @override - FileSelectionButtonStyle copyWith({ + FileSelectionButtonStyle? copyWith({ TextStyle? title, TextStyle? subTitle, BorderRadiusGeometry? radius, diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/flat_button_style.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/flat_button_style.dart index f5476e31..4a15cc42 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/flat_button_style.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/flat_button_style.dart @@ -96,15 +96,11 @@ class FlatButtonStyle extends ButtonStyle { final TextStyle? label; @override - FlatButtonStyle mergeWith(FlatButtonStyle? other) => - FlatButtonStyle.merge(this, other)!; + FlatButtonStyle? mergeWith(FlatButtonStyle? other) => + FlatButtonStyle.merge(this, other); @override - FlatButtonStyle? lerpWith(FlatButtonStyle? other, double t) => - FlatButtonStyle.lerp(this, other, t); - - @override - FlatButtonStyle copyWith({ + FlatButtonStyle? copyWith({ TextStyle? label, BorderRadiusGeometry? radius, EdgeInsetsGeometry? padding, diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/simple_icon_button_style.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/simple_icon_button_style.dart index e31acee7..f2ea057b 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/simple_icon_button_style.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/simple_icon_button_style.dart @@ -96,12 +96,8 @@ class SimpleIconButtonStyle extends ButtonStyle { final double? dimension; @override - SimpleIconButtonStyle mergeWith(SimpleIconButtonStyle? other) => - SimpleIconButtonStyle.merge(this, other)!; - - @override - SimpleIconButtonStyle? lerpWith(SimpleIconButtonStyle? other, double t) => - SimpleIconButtonStyle.lerp(this, other, t); + SimpleIconButtonStyle? mergeWith(SimpleIconButtonStyle? other) => + SimpleIconButtonStyle.merge(this, other); @override SimpleIconButtonStyle copyWith({ diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/symbol_button_style.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/symbol_button_style.dart index a0815b3c..1357724e 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/symbol_button_style.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/symbol_button_style.dart @@ -104,15 +104,11 @@ class SymbolButtonStyle extends ButtonStyle { final double? dimension; @override - SymbolButtonStyle mergeWith(SymbolButtonStyle? other) => - SymbolButtonStyle.merge(this, other)!; + SymbolButtonStyle? mergeWith(SymbolButtonStyle? other) => + SymbolButtonStyle.merge(this, other); @override - SymbolButtonStyle? lerpWith(SymbolButtonStyle? other, double t) => - SymbolButtonStyle.lerp(this, other, t); - - @override - SymbolButtonStyle copyWith({ + SymbolButtonStyle? copyWith({ TextStyle? label, double? dimension, BorderRadiusGeometry? radius, diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/cards/card_component.dart b/packages/wyatt_ui_components/lib/src/domain/entities/cards/card_component.dart index bafc5c9a..2085f99c 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/cards/card_component.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/cards/card_component.dart @@ -15,6 +15,7 @@ // along with this program. If not, see . import 'package:flutter/widgets.dart'; +import 'package:wyatt_ui_components/src/core/utils/multi_color.dart'; import 'package:wyatt_ui_components/src/domain/entities/component.dart'; abstract class CardComponent extends Component { @@ -41,10 +42,10 @@ abstract class CardComponent extends Component { final double? padding; /// Border gradient color (from left to right) - final List? borderColors; + final MultiColor? borderColors; /// Card background color - final List? backgroundColors; + final MultiColor? backgroundColors; /// Minimum size for this card final Size? minSize; diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/cards/information_card_component.g.dart b/packages/wyatt_ui_components/lib/src/domain/entities/cards/information_card_component.g.dart index 4802eb9e..59c9369e 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/cards/information_card_component.g.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/cards/information_card_component.g.dart @@ -14,8 +14,8 @@ abstract class $InformationCardComponentCWProxy { InformationCardComponent axis(Axis? axis); InformationCardComponent radius(double? radius); InformationCardComponent padding(double? padding); - InformationCardComponent borderColors(List? borderColors); - InformationCardComponent backgroundColors(List? backgroundColors); + InformationCardComponent borderColors(MultiColor? borderColors); + InformationCardComponent backgroundColors(MultiColor? backgroundColors); InformationCardComponent minSize(Size? minSize); InformationCardComponent maxSize(Size? maxSize); InformationCardComponent shadow(BoxShadow? shadow); @@ -29,8 +29,8 @@ abstract class $InformationCardComponentCWProxy { Axis? axis, double? radius, double? padding, - List? borderColors, - List? backgroundColors, + MultiColor? borderColors, + MultiColor? backgroundColors, Size? minSize, Size? maxSize, BoxShadow? shadow, diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/cards/portfolio_card_component.g.dart b/packages/wyatt_ui_components/lib/src/domain/entities/cards/portfolio_card_component.g.dart index a21bd6bc..87ddefb6 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/cards/portfolio_card_component.g.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/cards/portfolio_card_component.g.dart @@ -19,8 +19,8 @@ abstract class $PortfolioCardComponentCWProxy { PortfolioCardComponent assets(List? assets); PortfolioCardComponent radius(double? radius); PortfolioCardComponent padding(double? padding); - PortfolioCardComponent borderColors(List? borderColors); - PortfolioCardComponent backgroundColors(List? backgroundColors); + PortfolioCardComponent borderColors(MultiColor? borderColors); + PortfolioCardComponent backgroundColors(MultiColor? backgroundColors); PortfolioCardComponent minSize(Size? minSize); PortfolioCardComponent maxSize(Size? maxSize); PortfolioCardComponent shadow(BoxShadow? shadow); @@ -38,8 +38,8 @@ abstract class $PortfolioCardComponentCWProxy { List? assets, double? radius, double? padding, - List? borderColors, - List? backgroundColors, + MultiColor? borderColors, + MultiColor? backgroundColors, Size? minSize, Size? maxSize, BoxShadow? shadow, diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/cards/quote_card_component.g.dart b/packages/wyatt_ui_components/lib/src/domain/entities/cards/quote_card_component.g.dart index 0ce84883..cef1cb7d 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/cards/quote_card_component.g.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/cards/quote_card_component.g.dart @@ -16,8 +16,8 @@ abstract class $QuoteCardComponentCWProxy { QuoteCardComponent rightQuote(Widget? rightQuote); QuoteCardComponent radius(double? radius); QuoteCardComponent padding(double? padding); - QuoteCardComponent borderColors(List? borderColors); - QuoteCardComponent backgroundColors(List? backgroundColors); + QuoteCardComponent borderColors(MultiColor? borderColors); + QuoteCardComponent backgroundColors(MultiColor? backgroundColors); QuoteCardComponent minSize(Size? minSize); QuoteCardComponent maxSize(Size? maxSize); QuoteCardComponent shadow(BoxShadow? shadow); @@ -33,8 +33,8 @@ abstract class $QuoteCardComponentCWProxy { Widget? rightQuote, double? radius, double? padding, - List? borderColors, - List? backgroundColors, + MultiColor? borderColors, + MultiColor? backgroundColors, Size? minSize, Size? maxSize, BoxShadow? shadow, diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/cards/skill_card_component.g.dart b/packages/wyatt_ui_components/lib/src/domain/entities/cards/skill_card_component.g.dart index a69c819d..86094931 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/cards/skill_card_component.g.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/cards/skill_card_component.g.dart @@ -17,8 +17,8 @@ abstract class $SkillCardComponentCWProxy { Color? secondaryBackgroundColors); SkillCardComponent radius(double? radius); SkillCardComponent padding(double? padding); - SkillCardComponent borderColors(List? borderColors); - SkillCardComponent backgroundColors(List? backgroundColors); + SkillCardComponent borderColors(MultiColor? borderColors); + SkillCardComponent backgroundColors(MultiColor? backgroundColors); SkillCardComponent minSize(Size? minSize); SkillCardComponent maxSize(Size? maxSize); SkillCardComponent shadow(BoxShadow? shadow); @@ -34,8 +34,8 @@ abstract class $SkillCardComponentCWProxy { Color? secondaryBackgroundColors, double? radius, double? padding, - List? borderColors, - List? backgroundColors, + MultiColor? borderColors, + MultiColor? backgroundColors, Size? minSize, Size? maxSize, BoxShadow? shadow, diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/entities.dart b/packages/wyatt_ui_components/lib/src/domain/entities/entities.dart index 85ce40c3..93e81e4a 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/entities.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/entities.dart @@ -24,4 +24,5 @@ export './loader_component.dart'; export './loader_style.dart'; export './loading_widget_component.dart'; export './rich_text_builder/rich_text_builder.dart'; +export './text_inputs/text_inputs.dart'; export './theme_style.dart'; diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/loader_style.dart b/packages/wyatt_ui_components/lib/src/domain/entities/loader_style.dart index 43c3253c..b32c3a35 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/loader_style.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/loader_style.dart @@ -65,11 +65,7 @@ class LoaderStyle extends ThemeStyle { final double? stroke; @override - LoaderStyle mergeWith(LoaderStyle? other) => LoaderStyle.merge(this, other)!; - - @override - LoaderStyle? lerpWith(LoaderStyle? other, double t) => - LoaderStyle.lerp(this, other, t); + LoaderStyle? mergeWith(LoaderStyle? other) => LoaderStyle.merge(this, other); @override LoaderStyle copyWith({ diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/rich_text_builder/parser.dart b/packages/wyatt_ui_components/lib/src/domain/entities/rich_text_builder/parser.dart index bd92d252..b60684e4 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/rich_text_builder/parser.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/rich_text_builder/parser.dart @@ -23,7 +23,7 @@ class RichTextStyleParameter { this.styleName, ); - final TextStyle defaultStyle; + final TextStyle? defaultStyle; final Map definedStyle; final String? styleName; @@ -31,7 +31,7 @@ class RichTextStyleParameter { if (definedStyle.containsKey(styleName)) { return definedStyle[styleName]!; } - return defaultStyle; + return defaultStyle ?? const TextStyle(); } RichTextStyleParameter copyWith({ diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/rich_text_builder/rich_text_builder_style.dart b/packages/wyatt_ui_components/lib/src/domain/entities/rich_text_builder/rich_text_builder_style.dart index 43a03ff5..814bc237 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/rich_text_builder/rich_text_builder_style.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/rich_text_builder/rich_text_builder_style.dart @@ -64,15 +64,11 @@ class RichTextBuilderStyle extends ThemeStyle { final Map? styles; @override - RichTextBuilderStyle mergeWith(RichTextBuilderStyle? other) => - RichTextBuilderStyle.merge(this, other)!; + RichTextBuilderStyle? mergeWith(RichTextBuilderStyle? other) => + RichTextBuilderStyle.merge(this, other); @override - RichTextBuilderStyle? lerpWith(RichTextBuilderStyle? other, double t) => - RichTextBuilderStyle.lerp(this, other, t); - - @override - RichTextBuilderStyle copyWith({ + RichTextBuilderStyle? copyWith({ TextStyle? defaultStyle, Map? styles, }) => diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/text_inputs/text_input_component.dart b/packages/wyatt_ui_components/lib/src/domain/entities/text_inputs/text_input_component.dart new file mode 100644 index 00000000..2963da6a --- /dev/null +++ b/packages/wyatt_ui_components/lib/src/domain/entities/text_inputs/text_input_component.dart @@ -0,0 +1,173 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'dart:ui'; + +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart'; +import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; + +part 'text_input_component.g.dart'; + +@ComponentProxyExtension() +abstract class TextInputComponent extends Component + with CopyWithMixin<$TextInputComponentCWProxy> { + const TextInputComponent({ + this.expand, + this.onError, + this.validator, + this.suffixText, + this.prefixText, + this.prefixIcon, + this.suffixIcon, + this.label, + this.hint, + this.normalStyle, + this.focusedStyle, + this.errorStyle, + this.disableStyle, + this.controller, + this.focusNode, + this.keyboardType, + this.smartDashesType, + this.smartQuotesType, + this.enableInteractiveSelection, + this.textInputAction, + this.textCapitalization, + this.style, + this.strutStyle, + this.textAlign, + this.textAlignVertical, + this.textDirection, + this.readOnly, + this.showCursor, + this.autofocus, + this.obscuringCharacter, + this.obscureText, + this.autocorrect, + this.enableSuggestions, + this.maxLines, + this.minLines, + this.expands, + this.maxLength, + this.maxLengthEnforcement, + this.onChanged, + this.onEditingComplete, + this.onSubmitted, + this.onAppPrivateCommand, + this.inputFormatters, + this.enabled, + this.cursorWidth, + this.cursorHeight, + this.cursorRadius, + this.cursorColor, + this.selectionHeightStyle, + this.selectionWidthStyle, + this.keyboardAppearance, + this.scrollPadding, + this.dragStartBehavior, + this.selectionControls, + this.onTap, + this.onTapOutside, + this.mouseCursor, + this.scrollController, + this.scrollPhysics, + this.autofillHints, + this.clipBehavior, + this.restorationId, + this.scribbleEnabled, + this.enableIMEPersonalizedLearning, + this.contextMenuBuilder, + this.spellCheckConfiguration, + this.magnifierConfiguration, + super.key, + }); + + final TextMagnifierConfiguration? magnifierConfiguration; + final TextEditingController? controller; + final FocusNode? focusNode; + final TextInputType? keyboardType; + final TextInputAction? textInputAction; + final TextCapitalization? textCapitalization; + final TextStyle? style; + final StrutStyle? strutStyle; + final TextAlign? textAlign; + final TextAlignVertical? textAlignVertical; + final TextDirection? textDirection; + final bool? autofocus; + final String? obscuringCharacter; + final bool? obscureText; + final bool? autocorrect; + final SmartDashesType? smartDashesType; + final SmartQuotesType? smartQuotesType; + final bool? enableSuggestions; + final int? maxLines; + final int? minLines; + final bool? expands; + final bool? readOnly; + final bool? showCursor; + final int? maxLength; + final MaxLengthEnforcement? maxLengthEnforcement; + final ValueChanged? onChanged; + final VoidCallback? onEditingComplete; + final ValueChanged? onSubmitted; + final AppPrivateCommandCallback? onAppPrivateCommand; + final List? inputFormatters; + final ValueNotifier? enabled; + final double? cursorWidth; + final double? cursorHeight; + final Radius? cursorRadius; + final Color? cursorColor; + final BoxHeightStyle? selectionHeightStyle; + final BoxWidthStyle? selectionWidthStyle; + final Brightness? keyboardAppearance; + final EdgeInsets? scrollPadding; + final bool? enableInteractiveSelection; + final TextSelectionControls? selectionControls; + final DragStartBehavior? dragStartBehavior; + final GestureTapCallback? onTap; + final TapRegionCallback? onTapOutside; + final MouseCursor? mouseCursor; + final ScrollPhysics? scrollPhysics; + final ScrollController? scrollController; + final Iterable? autofillHints; + final Clip? clipBehavior; + final String? restorationId; + final bool? scribbleEnabled; + final bool? enableIMEPersonalizedLearning; + final EditableTextContextMenuBuilder? contextMenuBuilder; + final SpellCheckConfiguration? spellCheckConfiguration; + + final bool Function(String)? validator; + final String? Function(String)? onError; + + final TextInputStyle? normalStyle; + final TextInputStyle? focusedStyle; + final TextInputStyle? errorStyle; + final TextInputStyle? disableStyle; + + final bool? expand; + + final TextWrapper? label; + final TextWrapper? hint; + + final TextWrapper? prefixText; + final TextWrapper? suffixText; + final Icon? prefixIcon; + final Icon? suffixIcon; +} diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/text_inputs/text_input_component.g.dart b/packages/wyatt_ui_components/lib/src/domain/entities/text_inputs/text_input_component.g.dart new file mode 100644 index 00000000..59083bd6 --- /dev/null +++ b/packages/wyatt_ui_components/lib/src/domain/entities/text_inputs/text_input_component.g.dart @@ -0,0 +1,157 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'text_input_component.dart'; + +// ************************************************************************** +// ComponentProxyGenerator +// ************************************************************************** + +abstract class $TextInputComponentCWProxy { + TextInputComponent expand(bool? expand); + TextInputComponent onError(String Function(String)? onError); + TextInputComponent validator(bool Function(String)? validator); + TextInputComponent suffixText(TextWrapper? suffixText); + TextInputComponent prefixText(TextWrapper? prefixText); + TextInputComponent prefixIcon(Icon? prefixIcon); + TextInputComponent suffixIcon(Icon? suffixIcon); + TextInputComponent label(TextWrapper? label); + TextInputComponent hint(TextWrapper? hint); + TextInputComponent normalStyle(TextInputStyle? normalStyle); + TextInputComponent focusedStyle(TextInputStyle? focusedStyle); + TextInputComponent errorStyle(TextInputStyle? errorStyle); + TextInputComponent disableStyle(TextInputStyle? disableStyle); + TextInputComponent controller(TextEditingController? controller); + TextInputComponent focusNode(FocusNode? focusNode); + TextInputComponent keyboardType(TextInputType? keyboardType); + TextInputComponent smartDashesType(SmartDashesType? smartDashesType); + TextInputComponent smartQuotesType(SmartQuotesType? smartQuotesType); + TextInputComponent enableInteractiveSelection( + bool? enableInteractiveSelection); + TextInputComponent textInputAction(TextInputAction? textInputAction); + TextInputComponent textCapitalization(TextCapitalization? textCapitalization); + TextInputComponent style(TextStyle? style); + TextInputComponent strutStyle(StrutStyle? strutStyle); + TextInputComponent textAlign(TextAlign? textAlign); + TextInputComponent textAlignVertical(TextAlignVertical? textAlignVertical); + TextInputComponent textDirection(TextDirection? textDirection); + TextInputComponent readOnly(bool? readOnly); + TextInputComponent showCursor(bool? showCursor); + TextInputComponent autofocus(bool? autofocus); + TextInputComponent obscuringCharacter(String? obscuringCharacter); + TextInputComponent obscureText(bool? obscureText); + TextInputComponent autocorrect(bool? autocorrect); + TextInputComponent enableSuggestions(bool? enableSuggestions); + TextInputComponent maxLines(int? maxLines); + TextInputComponent minLines(int? minLines); + TextInputComponent expands(bool? expands); + TextInputComponent maxLength(int? maxLength); + TextInputComponent maxLengthEnforcement( + MaxLengthEnforcement? maxLengthEnforcement); + TextInputComponent onChanged(void Function(String)? onChanged); + TextInputComponent onEditingComplete(void Function()? onEditingComplete); + TextInputComponent onSubmitted(void Function(String)? onSubmitted); + TextInputComponent onAppPrivateCommand( + void Function(String, Map)? onAppPrivateCommand); + TextInputComponent inputFormatters(List? inputFormatters); + TextInputComponent enabled(ValueNotifier? enabled); + TextInputComponent cursorWidth(double? cursorWidth); + TextInputComponent cursorHeight(double? cursorHeight); + TextInputComponent cursorRadius(Radius? cursorRadius); + TextInputComponent cursorColor(Color? cursorColor); + TextInputComponent selectionHeightStyle(BoxHeightStyle? selectionHeightStyle); + TextInputComponent selectionWidthStyle(BoxWidthStyle? selectionWidthStyle); + TextInputComponent keyboardAppearance(Brightness? keyboardAppearance); + TextInputComponent scrollPadding(EdgeInsets? scrollPadding); + TextInputComponent dragStartBehavior(DragStartBehavior? dragStartBehavior); + TextInputComponent selectionControls( + TextSelectionControls? selectionControls); + TextInputComponent onTap(void Function()? onTap); + TextInputComponent onTapOutside( + void Function(PointerDownEvent)? onTapOutside); + TextInputComponent mouseCursor(MouseCursor? mouseCursor); + TextInputComponent scrollController(ScrollController? scrollController); + TextInputComponent scrollPhysics(ScrollPhysics? scrollPhysics); + TextInputComponent autofillHints(Iterable? autofillHints); + TextInputComponent clipBehavior(Clip? clipBehavior); + TextInputComponent restorationId(String? restorationId); + TextInputComponent scribbleEnabled(bool? scribbleEnabled); + TextInputComponent enableIMEPersonalizedLearning( + bool? enableIMEPersonalizedLearning); + TextInputComponent contextMenuBuilder( + Widget Function(BuildContext, EditableTextState)? contextMenuBuilder); + TextInputComponent spellCheckConfiguration( + SpellCheckConfiguration? spellCheckConfiguration); + TextInputComponent magnifierConfiguration( + TextMagnifierConfiguration? magnifierConfiguration); + TextInputComponent key(Key? key); + TextInputComponent call({ + bool? expand, + String Function(String)? onError, + bool Function(String)? validator, + TextWrapper? suffixText, + TextWrapper? prefixText, + Icon? prefixIcon, + Icon? suffixIcon, + TextWrapper? label, + TextWrapper? hint, + TextInputStyle? normalStyle, + TextInputStyle? focusedStyle, + TextInputStyle? errorStyle, + TextInputStyle? disableStyle, + TextEditingController? controller, + FocusNode? focusNode, + TextInputType? keyboardType, + SmartDashesType? smartDashesType, + SmartQuotesType? smartQuotesType, + bool? enableInteractiveSelection, + TextInputAction? textInputAction, + TextCapitalization? textCapitalization, + TextStyle? style, + StrutStyle? strutStyle, + TextAlign? textAlign, + TextAlignVertical? textAlignVertical, + TextDirection? textDirection, + bool? readOnly, + bool? showCursor, + bool? autofocus, + String? obscuringCharacter, + bool? obscureText, + bool? autocorrect, + bool? enableSuggestions, + int? maxLines, + int? minLines, + bool? expands, + int? maxLength, + MaxLengthEnforcement? maxLengthEnforcement, + void Function(String)? onChanged, + void Function()? onEditingComplete, + void Function(String)? onSubmitted, + void Function(String, Map)? onAppPrivateCommand, + List? inputFormatters, + ValueNotifier? enabled, + double? cursorWidth, + double? cursorHeight, + Radius? cursorRadius, + Color? cursorColor, + BoxHeightStyle? selectionHeightStyle, + BoxWidthStyle? selectionWidthStyle, + Brightness? keyboardAppearance, + EdgeInsets? scrollPadding, + DragStartBehavior? dragStartBehavior, + TextSelectionControls? selectionControls, + void Function()? onTap, + void Function(PointerDownEvent)? onTapOutside, + MouseCursor? mouseCursor, + ScrollController? scrollController, + ScrollPhysics? scrollPhysics, + Iterable? autofillHints, + Clip? clipBehavior, + String? restorationId, + bool? scribbleEnabled, + bool? enableIMEPersonalizedLearning, + Widget Function(BuildContext, EditableTextState)? contextMenuBuilder, + SpellCheckConfiguration? spellCheckConfiguration, + TextMagnifierConfiguration? magnifierConfiguration, + Key? key, + }); +} diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/text_inputs/text_input_style.dart b/packages/wyatt_ui_components/lib/src/domain/entities/text_inputs/text_input_style.dart new file mode 100644 index 00000000..7849eb19 --- /dev/null +++ b/packages/wyatt_ui_components/lib/src/domain/entities/text_inputs/text_input_style.dart @@ -0,0 +1,133 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'package:flutter/material.dart'; +import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; + +class TextInputStyle extends ThemeStyle { + TextInputStyle({ + this.labelStyle, + this.hintStyle, + this.backgroundColors, + this.borderColors, + this.boxShadow, + this.radius, + this.inputStyle, + this.iconColor, + this.prefixStyle, + this.prefixIconColor, + this.suffixStyle, + this.suffixIconColor, + }); + + final TextStyle? labelStyle; + final TextStyle? hintStyle; + + final Color? iconColor; + final TextStyle? prefixStyle; + final Color? prefixIconColor; + final TextStyle? suffixStyle; + final Color? suffixIconColor; + + final MultiColor? backgroundColors; + final Color? borderColors; + final BoxShadow? boxShadow; + final BorderRadiusGeometry? radius; + final TextStyle? inputStyle; + + static TextInputStyle? merge(TextInputStyle? a, TextInputStyle? b) { + if (b == null) { + return a?.copyWith(); + } + if (a == null) { + return b.copyWith(); + } + return a.copyWith( + labelStyle: b.labelStyle, + hintStyle: b.hintStyle, + backgroundColors: b.backgroundColors, + borderColors: b.borderColors, + boxShadow: b.boxShadow, + radius: b.radius, + inputStyle: b.inputStyle, + iconColor: b.iconColor, + prefixStyle: b.prefixStyle, + prefixIconColor: b.prefixIconColor, + suffixIconColor: b.suffixIconColor, + suffixStyle: b.suffixStyle, + ); + } + + static TextInputStyle? lerp( + TextInputStyle? a, + TextInputStyle? b, + double t, + ) { + if (a == null || b == null) { + return null; + } + + return b.copyWith( + labelStyle: TextStyle.lerp(a.labelStyle, b.labelStyle, t), + hintStyle: TextStyle.lerp(a.hintStyle, b.hintStyle, t), + backgroundColors: + MultiColor.lerp(a.backgroundColors, b.backgroundColors, t), + radius: BorderRadiusGeometry.lerp(a.radius, b.radius, t), + borderColors: Color.lerp(a.borderColors, b.borderColors, t), + boxShadow: BoxShadow.lerp(a.boxShadow, b.boxShadow, t), + inputStyle: TextStyle.lerp(a.inputStyle, b.inputStyle, t), + prefixStyle: TextStyle.lerp(a.prefixStyle, b.prefixStyle, t), + suffixStyle: TextStyle.lerp(a.suffixStyle, b.suffixStyle, t), + prefixIconColor: Color.lerp(a.prefixIconColor, b.prefixIconColor, t), + suffixIconColor: Color.lerp(a.suffixIconColor, b.suffixIconColor, t), + iconColor: Color.lerp(a.iconColor, b.iconColor, t), + ); + } + + @override + TextInputStyle? mergeWith(TextInputStyle? other) => + TextInputStyle.merge(this, other); + + @override + TextInputStyle copyWith({ + TextStyle? labelStyle, + TextStyle? hintStyle, + MultiColor? backgroundColors, + Color? borderColors, + BoxShadow? boxShadow, + BorderRadiusGeometry? radius, + TextStyle? inputStyle, + Color? iconColor, + TextStyle? prefixStyle, + Color? prefixIconColor, + TextStyle? suffixStyle, + Color? suffixIconColor, + }) => + TextInputStyle( + labelStyle: labelStyle ?? this.labelStyle, + hintStyle: hintStyle ?? this.hintStyle, + backgroundColors: backgroundColors ?? this.backgroundColors, + radius: radius ?? this.radius, + borderColors: borderColors ?? this.borderColors, + boxShadow: boxShadow ?? this.boxShadow, + inputStyle: inputStyle ?? this.inputStyle, + prefixStyle: prefixStyle ?? this.prefixStyle, + suffixStyle: suffixStyle ?? this.suffixStyle, + prefixIconColor: prefixIconColor ?? this.prefixIconColor, + suffixIconColor: suffixIconColor ?? this.suffixIconColor, + iconColor: iconColor ?? this.iconColor, + ); +} diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/text_inputs/text_inputs.dart b/packages/wyatt_ui_components/lib/src/domain/entities/text_inputs/text_inputs.dart new file mode 100644 index 00000000..26b4e465 --- /dev/null +++ b/packages/wyatt_ui_components/lib/src/domain/entities/text_inputs/text_inputs.dart @@ -0,0 +1,18 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +export './text_input_component.dart'; +export './text_input_style.dart'; diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/theme_style.dart b/packages/wyatt_ui_components/lib/src/domain/entities/theme_style.dart index 0f637eed..a0a69ffb 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/theme_style.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/theme_style.dart @@ -18,11 +18,8 @@ abstract class ThemeStyle { const ThemeStyle(); /// Merges non-null `other` attributes in `this` and returns a copy. - T mergeWith(T? other); - - /// Used for interpolation. - T? lerpWith(T? other, double t); + T? mergeWith(T? other); /// Copy with (mandatory for mergeWith, needs to be simple and ignore `null`) - T copyWith(); + T? copyWith(); } diff --git a/packages/wyatt_ui_kit/example/lib/home.dart b/packages/wyatt_ui_kit/example/lib/home.dart index cac6c236..9d772a61 100644 --- a/packages/wyatt_ui_kit/example/lib/home.dart +++ b/packages/wyatt_ui_kit/example/lib/home.dart @@ -6,6 +6,7 @@ import 'package:wyatt_ui_kit_example/cards/cards.dart'; import 'package:wyatt_ui_kit_example/demo_page.dart'; import 'package:wyatt_ui_kit_example/loaders/loaders.dart'; import 'package:wyatt_ui_kit_example/rich_text_builders/rich_text_builders.dart'; +import 'package:wyatt_ui_kit_example/text_input/text_inputs.dart'; import 'package:wyatt_ui_kit_example/theme/themes.dart'; const String title = 'Wyatt UIKit Example'; @@ -26,6 +27,7 @@ class _HomeState extends State { Buttons(), Loaders(), RichTextBuilders(), + TextInputs(), ]; int currentIndex = 0; diff --git a/packages/wyatt_ui_kit/example/lib/loaders/loaders.dart b/packages/wyatt_ui_kit/example/lib/loaders/loaders.dart index bc5d8945..cc456ae7 100644 --- a/packages/wyatt_ui_kit/example/lib/loaders/loaders.dart +++ b/packages/wyatt_ui_kit/example/lib/loaders/loaders.dart @@ -23,7 +23,7 @@ import 'package:wyatt_ui_kit_example/theme/constants.dart'; class Loaders extends DemoPage { const Loaders({super.key}); - + @override String get title => 'Loaders'; @@ -64,5 +64,4 @@ class Loaders extends DemoPage { const Gap(20), ], ); - } diff --git a/packages/wyatt_ui_kit/example/lib/text_input/text_inputs.dart b/packages/wyatt_ui_kit/example/lib/text_input/text_inputs.dart new file mode 100644 index 00000000..7d568abd --- /dev/null +++ b/packages/wyatt_ui_kit/example/lib/text_input/text_inputs.dart @@ -0,0 +1,140 @@ +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; +import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; +import 'package:wyatt_ui_kit_example/demo_page.dart'; + +class TextInputs extends DemoPage { + const TextInputs({super.key}); + + @override + Widget build(BuildContext context) => const TextInputsCore(); + + @override + String get title => 'Text Inputs'; +} + +class TextInputsCore extends StatefulWidget { + const TextInputsCore({super.key}); + + @override + State createState() => _TextInputsCoreState(); +} + +class _TextInputsCoreState extends State { + final _formKey = GlobalKey(); + final _controller = TextEditingController(); + final _focusNode = FocusNode(); + + final _formKey2 = GlobalKey(); + final _controller2 = TextEditingController(); + final _focusNode2 = FocusNode(); + + final _formKey3 = GlobalKey(); + final _controller3 = TextEditingController(); + final _focusNode3 = FocusNode(); + + final _formKey4 = GlobalKey(); + final _controller4 = TextEditingController(); + final _focusNode4 = FocusNode(); + + final _formKey5 = GlobalKey(); + final _controller5 = TextEditingController(); + final _focusNode5 = FocusNode(); + + final _formKey6 = GlobalKey(); + final _controller6 = TextEditingController(); + final _focusNode6 = FocusNode(); + + final ValueNotifier _enable = ValueNotifier(true); + + @override + void initState() { + super.initState(); + Future.delayed(const Duration(milliseconds: 500), () { + setState(() { + _enable.value = false; + }); + }); + } + + @override + Widget build(BuildContext context) => Form( + child: ListView( + cacheExtent: 1000, + children: [ + const Gap(20), + Align( + child: Text( + 'Text inputs', + style: Theme.of(context).textTheme.titleLarge, + ), + ), + const Gap(20), + TextInput( + key: _formKey6, + controller: _controller6, + focusNode: _focusNode6, + label: 'Nom / Prénom'.wrap(), + onError: (value) => 'Erreur : ${value.length} > 5.', + validator: (value) => value.length > 5, + ), + const Gap(20), + TextInput( + key: _formKey, + enabled: _enable, + controller: _controller, + focusNode: _focusNode, + label: 'Nom / Prénom'.wrap(), + onError: (value) => 'Erreur : ${value.length} > 5.', + validator: (value) => value.length > 5, + ), + const Gap(20), + TextInput( + key: _formKey2, + controller: _controller2, + focusNode: _focusNode2, + maxLines: 3, + onError: (value) => 'Erreur : ${value.length} > 5.', + validator: (value) => value.length > 5, + onChanged: (value) {}, + ), + const Gap(20), + TextInput( + key: _formKey3, + controller: _controller3, + focusNode: _focusNode3, + expand: false, + label: 'Nom / Prénom'.wrap(), + onError: (value) => 'Erreur : ${value.length} > 5.', + validator: (value) => value.length > 5, + onChanged: (value) {}, + ), + const Gap(20), + TextInput( + key: _formKey4, + expand: false, + controller: _controller4, + focusNode: _focusNode4, + label: 'Nom / Prénom'.wrap(), + maxLines: 3, + onError: (value) => 'Erreur : ${value.length} > 5.', + validator: (value) => value.length > 5, + onChanged: (value) {}, + ), + const Gap(20), + TextInput( + key: _formKey5, + prefixIcon: const Icon(Icons.architecture), + suffixIcon: const Icon(Icons.architecture), + controller: _controller5, + focusNode: _focusNode5, + label: 'Nom / Prénom'.wrap(), + onError: (value) => 'Erreur : ${value.length} > 5.', + validator: (value) => value.length > 5, + ), + const Gap(20), + ], + ), + ); +} diff --git a/packages/wyatt_ui_kit/example/lib/theme/text_input_theme.dart b/packages/wyatt_ui_kit/example/lib/theme/text_input_theme.dart new file mode 100644 index 00000000..63b6dc41 --- /dev/null +++ b/packages/wyatt_ui_kit/example/lib/theme/text_input_theme.dart @@ -0,0 +1,161 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; +import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; + +class TextInputTheme extends TextInputThemeExtension { + const TextInputTheme({ + super.normalStyle, + super.focusedStyle, + super.disableStyle, + super.errorStyle, + }); + + factory TextInputTheme.light() => TextInputTheme( + normalStyle: TextInputStyle( + radius: BorderRadius.circular(12), + borderColors: const Color.fromRGBO(221, 224, 227, 1), + labelStyle: GoogleFonts.montserrat( + fontWeight: FontWeight.w300, + color: const Color.fromRGBO(55, 65, 81, 1), + ), + inputStyle: GoogleFonts.montserrat( + fontWeight: FontWeight.w300, + color: const Color.fromRGBO(55, 65, 81, 1), + ), + ), + focusedStyle: TextInputStyle( + radius: BorderRadius.circular(12), + borderColors: const Color.fromRGBO(60, 125, 251, 1), + labelStyle: GoogleFonts.montserrat( + fontWeight: FontWeight.w300, + color: const Color.fromRGBO(55, 65, 81, 1), + ), + inputStyle: GoogleFonts.montserrat( + fontWeight: FontWeight.w300, + color: const Color.fromRGBO(55, 65, 81, 1), + ), + ), + errorStyle: TextInputStyle( + radius: BorderRadius.circular(12), + borderColors: const Color.fromRGBO(244, 68, 100, 1), + labelStyle: GoogleFonts.montserrat( + fontWeight: FontWeight.w300, + color: const Color.fromRGBO(244, 68, 100, 1), + ), + inputStyle: GoogleFonts.montserrat( + fontWeight: FontWeight.w300, + color: const Color.fromRGBO(55, 65, 81, 1), + ), + ), + disableStyle: TextInputStyle( + radius: BorderRadius.circular(12), + borderColors: const Color.fromRGBO(229, 231, 235, 1), + labelStyle: GoogleFonts.montserrat( + fontWeight: FontWeight.w300, + color: const Color.fromRGBO(156, 163, 175, 1), + ), + inputStyle: GoogleFonts.montserrat( + fontWeight: FontWeight.w300, + color: const Color.fromRGBO(156, 163, 175, 1), + ), + ), + ); + + factory TextInputTheme.dark() => TextInputTheme( + normalStyle: TextInputStyle( + radius: BorderRadius.circular(12), + borderColors: const Color.fromRGBO(96, 101, 106, 1), + labelStyle: GoogleFonts.montserrat( + fontWeight: FontWeight.w300, + color: const Color.fromRGBO(204, 204, 204, 1), + ), + inputStyle: GoogleFonts.montserrat( + fontWeight: FontWeight.w300, + color: const Color.fromRGBO(255, 255, 255, 1), + ), + ), + focusedStyle: TextInputStyle( + radius: BorderRadius.circular(12), + borderColors: const Color.fromRGBO(60, 125, 251, 1), + labelStyle: GoogleFonts.montserrat( + fontWeight: FontWeight.w300, + color: const Color.fromRGBO(204, 204, 204, 1), + ), + inputStyle: GoogleFonts.montserrat( + fontWeight: FontWeight.w300, + color: const Color.fromRGBO(255, 255, 255, 1), + ), + ), + errorStyle: TextInputStyle( + radius: BorderRadius.circular(12), + borderColors: const Color.fromRGBO(244, 68, 100, 1), + labelStyle: GoogleFonts.montserrat( + fontWeight: FontWeight.w300, + color: const Color.fromRGBO(244, 68, 100, 1), + ), + inputStyle: GoogleFonts.montserrat( + fontWeight: FontWeight.w300, + color: const Color.fromRGBO(255, 255, 255, 1), + ), + ), + disableStyle: TextInputStyle( + radius: BorderRadius.circular(12), + borderColors: const Color.fromRGBO(96, 101, 106, 1), + labelStyle: GoogleFonts.montserrat( + fontWeight: FontWeight.w300, + color: const Color.fromRGBO(96, 101, 106, 1), + ), + inputStyle: GoogleFonts.montserrat( + fontWeight: FontWeight.w300, + color: const Color.fromRGBO(255, 255, 255, 1), + ), + ), + ); + + @override + ThemeExtension lerp( + covariant ThemeExtension? other, + double t, + ) { + if (other is! TextInputTheme) { + return this; + } + return TextInputTheme( + normalStyle: TextInputStyle.lerp(normalStyle, other.normalStyle, t), + focusedStyle: TextInputStyle.lerp(focusedStyle, other.focusedStyle, t), + disableStyle: TextInputStyle.lerp(disableStyle, other.disableStyle, t), + errorStyle: TextInputStyle.lerp(errorStyle, other.errorStyle, t), + ); + } + + @override + ThemeExtension copyWith({ + TextInputStyle? normalStyle, + TextInputStyle? focusedStyle, + TextInputStyle? disableStyle, + TextInputStyle? errorStyle, + }) => + TextInputTheme( + normalStyle: normalStyle ?? this.normalStyle, + focusedStyle: focusedStyle ?? this.focusedStyle, + disableStyle: disableStyle ?? this.disableStyle, + errorStyle: errorStyle ?? this.errorStyle, + ); +} diff --git a/packages/wyatt_ui_kit/example/lib/theme/themes.dart b/packages/wyatt_ui_kit/example/lib/theme/themes.dart index 63ecea53..6bb52867 100644 --- a/packages/wyatt_ui_kit/example/lib/theme/themes.dart +++ b/packages/wyatt_ui_kit/example/lib/theme/themes.dart @@ -24,6 +24,7 @@ import 'package:wyatt_ui_kit_example/theme/loader_theme.dart'; import 'package:wyatt_ui_kit_example/theme/rich_text_builder_theme.dart'; import 'package:wyatt_ui_kit_example/theme/simple_icon_button_theme.dart'; import 'package:wyatt_ui_kit_example/theme/symbol_button_theme.dart'; +import 'package:wyatt_ui_kit_example/theme/text_input_theme.dart'; /// Easely switch between Material and Studio themes. abstract class Themes { @@ -90,6 +91,7 @@ abstract class Themes { LoaderTheme.light(), // Rich Text RichTextBuilderTheme.light(), + TextInputTheme.light(), ], ); @@ -121,6 +123,7 @@ abstract class Themes { LoaderTheme.dark(), // Rich Text RichTextBuilderTheme.dark(), + TextInputTheme.dark(), ], ); } diff --git a/packages/wyatt_ui_kit/lib/src/components/buttons/file_selection_button/file_selection_button_screen.dart b/packages/wyatt_ui_kit/lib/src/components/buttons/file_selection_button/file_selection_button_screen.dart index bc45bec9..d707014c 100644 --- a/packages/wyatt_ui_kit/lib/src/components/buttons/file_selection_button/file_selection_button_screen.dart +++ b/packages/wyatt_ui_kit/lib/src/components/buttons/file_selection_button/file_selection_button_screen.dart @@ -67,40 +67,6 @@ class FileSelectionButtonScreen FileSelectionButtonStyle _resolve(BuildContext context, ButtonState state) { final FileSelectionButtonThemeResolver resolver = themeResolver ?? FileSelectionButtonThemeResolver( - computeExtensionValueFn: ( - context, - defaultValue, - themeExtension, { - extra, - }) { - FileSelectionButtonStyle? style = defaultValue; - switch (extra?.state) { - case ControlState.disabled: - style = themeExtension.disabledStyle; - break; - case ControlState.focused: - style = themeExtension.focusedStyle; - break; - case ControlState.hovered: - style = themeExtension.hoveredStyle; - break; - case ControlState.tapped: - style = themeExtension.tappedStyle; - break; - case ControlState.normal: - case null: - style = themeExtension.normalStyle; - break; - } - if (extra?.isSelected ?? false) { - style = themeExtension.selectedStyle; - } - if (extra?.isInvalid ?? false) { - style = themeExtension.invalidStyle; - } - - return style; - }, customStyleFn: (context, {extra}) { FileSelectionButtonStyle? style; switch (extra?.state) { diff --git a/packages/wyatt_ui_kit/lib/src/components/buttons/file_selection_button/file_selection_button_theme_resolver.dart b/packages/wyatt_ui_kit/lib/src/components/buttons/file_selection_button/file_selection_button_theme_resolver.dart index 7c1f9634..505e9e37 100644 --- a/packages/wyatt_ui_kit/lib/src/components/buttons/file_selection_button/file_selection_button_theme_resolver.dart +++ b/packages/wyatt_ui_kit/lib/src/components/buttons/file_selection_button/file_selection_button_theme_resolver.dart @@ -22,7 +22,6 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; class FileSelectionButtonThemeResolver extends ThemeResolver< FileSelectionButtonStyle, FileSelectionButtonThemeExtension, ButtonState> { const FileSelectionButtonThemeResolver({ - required this.computeExtensionValueFn, required this.customStyleFn, }); @@ -57,8 +56,7 @@ class FileSelectionButtonThemeResolver extends ThemeResolver< } if (extra?.isInvalid ?? false) { - backgroundColor = - MultiColor.single(context.colorScheme.error); + backgroundColor = MultiColor.single(context.colorScheme.error); } return FileSelectionButtonStyle( @@ -73,17 +71,43 @@ class FileSelectionButtonThemeResolver extends ThemeResolver< ); } - @override - final FileSelectionButtonStyle? Function( - BuildContext context, - FileSelectionButtonStyle defaultValue, - FileSelectionButtonThemeExtension themeExtension, { - ButtonState? extra, - }) computeExtensionValueFn; - @override final FileSelectionButtonStyle? Function( BuildContext context, { ButtonState? extra, }) customStyleFn; + + @override + FileSelectionButtonStyle? computeExtensionValueFn( + BuildContext context, + FileSelectionButtonThemeExtension themeExtension, { + ButtonState? extra, + }) { + FileSelectionButtonStyle? style; + switch (extra?.state) { + case ControlState.disabled: + style = themeExtension.disabledStyle; + break; + case ControlState.focused: + style = themeExtension.focusedStyle; + break; + case ControlState.hovered: + style = themeExtension.hoveredStyle; + break; + case ControlState.tapped: + style = themeExtension.tappedStyle; + break; + case ControlState.normal: + case null: + style = themeExtension.normalStyle; + break; + } + if (extra?.isSelected ?? false) { + style = themeExtension.selectedStyle; + } + if (extra?.isInvalid ?? false) { + style = themeExtension.invalidStyle; + } + return style; + } } diff --git a/packages/wyatt_ui_kit/lib/src/components/buttons/flat_button/flat_button_screen.dart b/packages/wyatt_ui_kit/lib/src/components/buttons/flat_button/flat_button_screen.dart index 803c68cc..6be53168 100644 --- a/packages/wyatt_ui_kit/lib/src/components/buttons/flat_button/flat_button_screen.dart +++ b/packages/wyatt_ui_kit/lib/src/components/buttons/flat_button/flat_button_screen.dart @@ -61,26 +61,6 @@ class FlatButtonScreen extends CubitScreen { FlatButtonStyle _resolve(BuildContext context, ControlState state) { final FlatButtonThemeResolver resolver = themeResolver ?? FlatButtonThemeResolver( - computeExtensionValueFn: ( - context, - defaultValue, - themeExtension, { - extra, - }) { - switch (extra) { - case ControlState.disabled: - return themeExtension.disabledStyle; - case ControlState.focused: - return themeExtension.focusedStyle; - case ControlState.hovered: - return themeExtension.hoveredStyle; - case ControlState.tapped: - return themeExtension.tappedStyle; - case ControlState.normal: - case null: - return themeExtension.normalStyle; - } - }, customStyleFn: (context, {extra}) { switch (extra) { case ControlState.disabled: diff --git a/packages/wyatt_ui_kit/lib/src/components/buttons/flat_button/flat_button_theme_resolver.dart b/packages/wyatt_ui_kit/lib/src/components/buttons/flat_button/flat_button_theme_resolver.dart index c48c6b8e..dfbe1349 100644 --- a/packages/wyatt_ui_kit/lib/src/components/buttons/flat_button/flat_button_theme_resolver.dart +++ b/packages/wyatt_ui_kit/lib/src/components/buttons/flat_button/flat_button_theme_resolver.dart @@ -21,7 +21,6 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; class FlatButtonThemeResolver extends ThemeResolver { const FlatButtonThemeResolver({ - required this.computeExtensionValueFn, required this.customStyleFn, }); @@ -70,13 +69,28 @@ class FlatButtonThemeResolver extends ThemeResolver { const SimpleIconButtonThemeResolver({ - required this.computeExtensionValueFn, required this.customStyleFn, }); @@ -66,17 +65,30 @@ class SimpleIconButtonThemeResolver extends ThemeResolver { SimpleIconButtonStyle _resolve(BuildContext context, ControlState state) { final SimpleIconButtonThemeResolver resolver = themeResolver ?? SimpleIconButtonThemeResolver( - computeExtensionValueFn: ( - context, - defaultValue, - themeExtension, { - extra, - }) { - switch (extra) { - case ControlState.disabled: - return themeExtension.disabledStyle; - case ControlState.focused: - return themeExtension.focusedStyle; - case ControlState.hovered: - return themeExtension.hoveredStyle; - case ControlState.tapped: - return themeExtension.tappedStyle; - case ControlState.normal: - case null: - return themeExtension.normalStyle; - } - }, customStyleFn: (context, {extra}) { switch (extra) { case ControlState.disabled: diff --git a/packages/wyatt_ui_kit/lib/src/components/buttons/symbol_button/symbol_button_screen.dart b/packages/wyatt_ui_kit/lib/src/components/buttons/symbol_button/symbol_button_screen.dart index b8c84633..be5009db 100644 --- a/packages/wyatt_ui_kit/lib/src/components/buttons/symbol_button/symbol_button_screen.dart +++ b/packages/wyatt_ui_kit/lib/src/components/buttons/symbol_button/symbol_button_screen.dart @@ -63,37 +63,6 @@ class SymbolButtonScreen SymbolButtonStyle _resolve(BuildContext context, ButtonState state) { final SymbolButtonThemeResolver resolver = themeResolver ?? SymbolButtonThemeResolver( - computeExtensionValueFn: ( - context, - defaultValue, - themeExtension, { - extra, - }) { - SymbolButtonStyle? style = defaultValue; - switch (extra?.state) { - case ControlState.disabled: - style = themeExtension.disabledStyle; - break; - case ControlState.focused: - style = themeExtension.focusedStyle; - break; - case ControlState.hovered: - style = themeExtension.hoveredStyle; - break; - case ControlState.tapped: - style = themeExtension.tappedStyle; - break; - case ControlState.normal: - case null: - style = themeExtension.normalStyle; - break; - } - if (extra?.isSelected ?? false) { - style = themeExtension.selectedStyle; - } - - return style; - }, customStyleFn: (context, {extra}) { SymbolButtonStyle? style; switch (extra?.state) { diff --git a/packages/wyatt_ui_kit/lib/src/components/buttons/symbol_button/symbol_button_theme_resolver.dart b/packages/wyatt_ui_kit/lib/src/components/buttons/symbol_button/symbol_button_theme_resolver.dart index 8d679e22..4628bd87 100644 --- a/packages/wyatt_ui_kit/lib/src/components/buttons/symbol_button/symbol_button_theme_resolver.dart +++ b/packages/wyatt_ui_kit/lib/src/components/buttons/symbol_button/symbol_button_theme_resolver.dart @@ -22,7 +22,6 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; class SymbolButtonThemeResolver extends ThemeResolver { const SymbolButtonThemeResolver({ - required this.computeExtensionValueFn, required this.customStyleFn, }); @@ -58,7 +57,7 @@ class SymbolButtonThemeResolver extends ThemeResolver this(padding: padding); @override - InformationCard borderColors(List? borderColors) => + InformationCard borderColors(MultiColor? borderColors) => this(borderColors: borderColors); @override - InformationCard backgroundColors(List? backgroundColors) => + InformationCard backgroundColors(MultiColor? backgroundColors) => this(backgroundColors: backgroundColors); @override InformationCard minSize(Size? minSize) => this(minSize: minSize); @@ -49,8 +49,8 @@ class $InformationCardCWProxyImpl implements $InformationCardComponentCWProxy { Axis? axis, double? radius, double? padding, - List? borderColors, - List? backgroundColors, + MultiColor? borderColors, + MultiColor? backgroundColors, Size? minSize, Size? maxSize, BoxShadow? shadow, diff --git a/packages/wyatt_ui_kit/lib/src/components/cards/portfolio_card/portfolio_card.g.dart b/packages/wyatt_ui_kit/lib/src/components/cards/portfolio_card/portfolio_card.g.dart index 0142a408..735f8f58 100644 --- a/packages/wyatt_ui_kit/lib/src/components/cards/portfolio_card/portfolio_card.g.dart +++ b/packages/wyatt_ui_kit/lib/src/components/cards/portfolio_card/portfolio_card.g.dart @@ -36,10 +36,10 @@ class $PortfolioCardCWProxyImpl implements $PortfolioCardComponentCWProxy { @override PortfolioCard padding(double? padding) => this(padding: padding); @override - PortfolioCard borderColors(List? borderColors) => + PortfolioCard borderColors(MultiColor? borderColors) => this(borderColors: borderColors); @override - PortfolioCard backgroundColors(List? backgroundColors) => + PortfolioCard backgroundColors(MultiColor? backgroundColors) => this(backgroundColors: backgroundColors); @override PortfolioCard minSize(Size? minSize) => this(minSize: minSize); @@ -64,8 +64,8 @@ class $PortfolioCardCWProxyImpl implements $PortfolioCardComponentCWProxy { List? assets, double? radius, double? padding, - List? borderColors, - List? backgroundColors, + MultiColor? borderColors, + MultiColor? backgroundColors, Size? minSize, Size? maxSize, BoxShadow? shadow, diff --git a/packages/wyatt_ui_kit/lib/src/components/cards/quote_card/quote_card.g.dart b/packages/wyatt_ui_kit/lib/src/components/cards/quote_card/quote_card.g.dart index 548c0088..90c7d5f2 100644 --- a/packages/wyatt_ui_kit/lib/src/components/cards/quote_card/quote_card.g.dart +++ b/packages/wyatt_ui_kit/lib/src/components/cards/quote_card/quote_card.g.dart @@ -28,10 +28,10 @@ class $QuoteCardCWProxyImpl implements $QuoteCardComponentCWProxy { @override QuoteCard padding(double? padding) => this(padding: padding); @override - QuoteCard borderColors(List? borderColors) => + QuoteCard borderColors(MultiColor? borderColors) => this(borderColors: borderColors); @override - QuoteCard backgroundColors(List? backgroundColors) => + QuoteCard backgroundColors(MultiColor? backgroundColors) => this(backgroundColors: backgroundColors); @override QuoteCard minSize(Size? minSize) => this(minSize: minSize); @@ -54,8 +54,8 @@ class $QuoteCardCWProxyImpl implements $QuoteCardComponentCWProxy { Widget? rightQuote, double? radius, double? padding, - List? borderColors, - List? backgroundColors, + MultiColor? borderColors, + MultiColor? backgroundColors, Size? minSize, Size? maxSize, BoxShadow? shadow, diff --git a/packages/wyatt_ui_kit/lib/src/components/cards/skill_card/skill_card.g.dart b/packages/wyatt_ui_kit/lib/src/components/cards/skill_card/skill_card.g.dart index 96f74491..e66fe9e2 100644 --- a/packages/wyatt_ui_kit/lib/src/components/cards/skill_card/skill_card.g.dart +++ b/packages/wyatt_ui_kit/lib/src/components/cards/skill_card/skill_card.g.dart @@ -31,10 +31,10 @@ class $SkillCardCWProxyImpl implements $SkillCardComponentCWProxy { @override SkillCard padding(double? padding) => this(padding: padding); @override - SkillCard borderColors(List? borderColors) => + SkillCard borderColors(MultiColor? borderColors) => this(borderColors: borderColors); @override - SkillCard backgroundColors(List? backgroundColors) => + SkillCard backgroundColors(MultiColor? backgroundColors) => this(backgroundColors: backgroundColors); @override SkillCard minSize(Size? minSize) => this(minSize: minSize); @@ -57,8 +57,8 @@ class $SkillCardCWProxyImpl implements $SkillCardComponentCWProxy { Color? secondaryBackgroundColors, double? radius, double? padding, - List? borderColors, - List? backgroundColors, + MultiColor? borderColors, + MultiColor? backgroundColors, Size? minSize, Size? maxSize, BoxShadow? shadow, diff --git a/packages/wyatt_ui_kit/lib/src/components/cards/widgets/card_background.dart b/packages/wyatt_ui_kit/lib/src/components/cards/widgets/card_background.dart new file mode 100644 index 00000000..76862ab2 --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/cards/widgets/card_background.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class CardBackground extends StatefulWidget { + const CardBackground({super.key, this.background, this.cardKey}); + + final Widget? background; + final GlobalKey? cardKey; + + @override + State createState() => _CardBackgroundState(); +} + +class _CardBackgroundState extends State { + Size _cardSize = Size.zero; + + @override + void initState() { + super.initState(); + if (widget.background != null) { + WidgetsBinding.instance.addPostFrameCallback((_) { + _resizeCard(); + }); + } + } + + @override + void didUpdateWidget(covariant CardBackground oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.background != null) { + _resizeCard(); + } + } + + void _resizeCard() { + final RenderObject? renderBox = + widget.cardKey?.currentContext?.findRenderObject(); + if (renderBox != null) { + setState(() { + _cardSize = + Size(renderBox.paintBounds.width, renderBox.paintBounds.height); + }); + } + } + + @override + Widget build(BuildContext context) => SizedBox( + width: _cardSize.width, + height: _cardSize.height, + child: Center(child: widget.background), + ); +} diff --git a/packages/wyatt_ui_kit/lib/src/components/cards/widgets/card_wrapper.dart b/packages/wyatt_ui_kit/lib/src/components/cards/widgets/card_wrapper.dart index 4c608380..aed05cae 100644 --- a/packages/wyatt_ui_kit/lib/src/components/cards/widgets/card_wrapper.dart +++ b/packages/wyatt_ui_kit/lib/src/components/cards/widgets/card_wrapper.dart @@ -15,11 +15,12 @@ // along with this program. If not, see . import 'package:flutter/material.dart'; -import 'package:wyatt_ui_kit/src/components/gradients/gradient_box_border.dart'; -import 'package:wyatt_ui_kit/src/domain/card_theme_extension.dart'; +import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; +import 'package:wyatt_ui_kit/src/components/cards/widgets/card_background.dart'; +import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; -class CardWrapper extends StatefulWidget { - const CardWrapper({ +class CardWrapper extends StatelessWidget { + CardWrapper({ required this.child, required this.backgroundColors, required this.borderColors, @@ -33,61 +34,26 @@ class CardWrapper extends StatefulWidget { final Widget? background; final Widget child; - final List? backgroundColors; - final List? borderColors; + final MultiColor? backgroundColors; + final MultiColor? borderColors; final BoxShadow? shadow; final Size? minSize; final Size? maxSize; final double? padding; - @override - State createState() => _CardWrapperState(); -} - -class _CardWrapperState extends State { - Size _cardSize = Size.zero; final GlobalKey _key = GlobalKey(); - @override - void initState() { - super.initState(); - if (widget.background != null) { - WidgetsBinding.instance.addPostFrameCallback((_) { - _resizeCard(); - }); - } - } - - @override - void didUpdateWidget(covariant CardWrapper oldWidget) { - super.didUpdateWidget(oldWidget); - if (widget.background != null) { - _resizeCard(); - } - } - - void _resizeCard() { - final RenderObject? renderBox = _key.currentContext?.findRenderObject(); - if (renderBox != null) { - setState(() { - _cardSize = - Size(renderBox.paintBounds.width, renderBox.paintBounds.height); - }); - } - } - - Widget _buildChild(Widget child) => (widget.background != null) + Widget _buildChild(Widget child) => (background != null) ? Stack( alignment: Alignment.center, children: [ - SizedBox( - width: _cardSize.width, - height: _cardSize.height, - child: Center(child: widget.background), + CardBackground( + cardKey: _key, + background: background, ), Padding( padding: EdgeInsets.all( - widget.padding ?? 25, + padding ?? 25, ), child: child, ), @@ -95,92 +61,22 @@ class _CardWrapperState extends State { ) : Padding( padding: EdgeInsets.all( - widget.padding ?? 25, + padding ?? 25, ), child: child, ); - Gradient? _cardGradient(BuildContext context) { - if (widget.backgroundColors != null && - widget.backgroundColors!.length >= 2) { - return LinearGradient(colors: widget.backgroundColors!); - } else { - final extensionCardColor = - Theme.of(context).extension(); - - if (extensionCardColor != null && - extensionCardColor.backgroundColors != null && - extensionCardColor.backgroundColors!.isGradient) { - return LinearGradient( - colors: extensionCardColor.backgroundColors!.colors,); - } - } - return null; - } - - Color? _cardColor(BuildContext context) { - if (widget.backgroundColors != null && - widget.backgroundColors!.length == 1) { - return widget.backgroundColors!.first; - } else { - final extensionCardColor = - Theme.of(context).extension(); - - if (extensionCardColor != null && - extensionCardColor.backgroundColors != null) { - return extensionCardColor.backgroundColors!.color; - } - } - return Theme.of(context).cardColor; - } - - BoxBorder? _boxBorder(BuildContext context) { - if (widget.borderColors != null) { - if (widget.borderColors!.length >= 2) { - return GradientBoxBorder( - gradient: LinearGradient( - colors: widget.borderColors!, - ), - ); - } else if (widget.borderColors!.isNotEmpty) { - return Border.all( - color: widget.borderColors!.first, - ); - } - } else { - final extensionCardColor = - Theme.of(context).extension(); - if (extensionCardColor != null && - extensionCardColor.borderColors != null) { - if (extensionCardColor.borderColors!.isGradient) { - return GradientBoxBorder( - gradient: LinearGradient( - colors: extensionCardColor.borderColors!.colors, - ), - ); - } else if (extensionCardColor.backgroundColors!.colors.isNotEmpty) { - return Border.all( - color: extensionCardColor.backgroundColors!.color, - ); - } - } - } - return null; - } - List _shadow(BuildContext context) { - final shadows = List.empty(growable: true); - if (widget.shadow != null) { - shadows.add(widget.shadow!); - } else { - final extensionCardColor = - Theme.of(context).extension(); - if (extensionCardColor != null && - extensionCardColor.shadowColor != null) { - shadows.add(extensionCardColor.shadowColor!); - } - } - return shadows; + final themeShadow = ThemeHelper.getThemeElement( + [ + shadow, + Theme.of(context).extension()?.shadowColor, + ], + valueValidator: (shadow) => shadow != null, + transform: (shadow) => shadow, + defaultValue: null, + ); + return (themeShadow != null) ? [themeShadow] : []; } @override @@ -189,22 +85,66 @@ class _CardWrapperState extends State { key: _key, decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(12)), - gradient: _cardGradient(context), - color: _cardColor(context), - border: _boxBorder(context), + gradient: ThemeHelper.getThemeElement( + [ + backgroundColors, + Theme.of(context) + .extension() + ?.backgroundColors, + ], + valueValidator: (multiColor) => + multiColor != null && multiColor.isGradient, + transform: (multiColor) => + LinearGradientHelper.fromMultiColor(multiColor!), + defaultValue: null, + ), + color: ThemeHelper.getThemeElement( + [ + backgroundColors, + Theme.of(context) + .extension() + ?.backgroundColors, + ], + valueValidator: (multiColor) => + multiColor != null && multiColor.isColor, + transform: (multiColor) => multiColor?.color, + defaultValue: Theme.of(context).cardColor, + ), + border: ThemeHelper.getThemeElement( + [ + borderColors, + Theme.of(context).extension()?.borderColors, + Theme.of(context) + .extension() + ?.backgroundColors, + ], + valueValidator: (multiColor) => + multiColor != null && multiColor.isColor, + transform: (multiColor) { + if (multiColor!.isGradient) { + return GradientBoxBorder( + gradient: LinearGradientHelper.fromMultiColor(multiColor), + ); + } + return Border.all( + color: multiColor.color, + ); + }, + defaultValue: null, + ), boxShadow: _shadow(context), ), - child: (widget.minSize != null && widget.maxSize != null) + child: (minSize != null && maxSize != null) ? ConstrainedBox( constraints: BoxConstraints( - minWidth: widget.minSize!.width, - minHeight: widget.minSize!.height, - maxWidth: widget.maxSize!.width, - maxHeight: widget.maxSize!.height, + minWidth: minSize!.width, + minHeight: minSize!.height, + maxWidth: maxSize!.width, + maxHeight: maxSize!.height, ), - child: _buildChild(widget.child), + child: _buildChild(child), ) - : _buildChild(widget.child), + : _buildChild(child), ), ); } diff --git a/packages/wyatt_ui_kit/lib/src/components/components.dart b/packages/wyatt_ui_kit/lib/src/components/components.dart index e78cb40d..34d4753d 100644 --- a/packages/wyatt_ui_kit/lib/src/components/components.dart +++ b/packages/wyatt_ui_kit/lib/src/components/components.dart @@ -19,3 +19,4 @@ export './cards/cards.dart'; export './gradients/gradients.dart'; export './loader/loader.dart'; export './rich_text_builder/rich_text_builder.dart'; +export './text_inputs/text_input.dart'; diff --git a/packages/wyatt_ui_kit/lib/src/components/gradients/gradient_box_border.dart b/packages/wyatt_ui_kit/lib/src/components/gradients/gradient_box_border.dart index 912a9c53..2a77264e 100644 --- a/packages/wyatt_ui_kit/lib/src/components/gradients/gradient_box_border.dart +++ b/packages/wyatt_ui_kit/lib/src/components/gradients/gradient_box_border.dart @@ -14,9 +14,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +import 'package:flutter/material.dart'; import 'package:flutter/painting.dart'; -class GradientBoxBorder extends BoxBorder { +class GradientBoxBorder extends Border { const GradientBoxBorder({this.gradient, this.width = 1}); final Gradient? gradient; @@ -34,9 +35,6 @@ class GradientBoxBorder extends BoxBorder { @override bool get isUniform => true; - @override - ShapeBorder scale(double t) => this; - @override void paint( Canvas canvas, diff --git a/packages/wyatt_ui_kit/lib/src/components/loader/loader.dart b/packages/wyatt_ui_kit/lib/src/components/loader/loader.dart index 620b5d70..dd28e602 100644 --- a/packages/wyatt_ui_kit/lib/src/components/loader/loader.dart +++ b/packages/wyatt_ui_kit/lib/src/components/loader/loader.dart @@ -45,16 +45,6 @@ class Loader extends LoaderComponent with $LoaderCWMixin { LoaderStyle _resolve(BuildContext context) { final LoaderThemeResolver resolver = themeResolver ?? LoaderThemeResolver( - computeExtensionValueFn: ( - context, - defaultValue, - themeExtension, { - extra, - }) => - LoaderStyle( - colors: themeExtension.colors, - stroke: themeExtension.stroke, - ), customStyleFn: (context, {extra}) => LoaderStyle( colors: colors, stroke: stroke, @@ -69,15 +59,14 @@ class Loader extends LoaderComponent with $LoaderCWMixin { final style = _resolve(context); final dimension = (radius != null) ? radius! * 2 : context.buttonTheme.height; - return SizedBox.square( dimension: dimension, child: RepaintBoundary( child: CustomPaint( painter: _LoaderPainter( - style.colors!, + style.colors ?? const MultiColor([]), dimension / 2, - style.stroke!, + style.stroke ?? 4, flip: flip ?? false, ), ) diff --git a/packages/wyatt_ui_kit/lib/src/components/loader/loader_theme_resolver.dart b/packages/wyatt_ui_kit/lib/src/components/loader/loader_theme_resolver.dart index 60047759..a5384e54 100644 --- a/packages/wyatt_ui_kit/lib/src/components/loader/loader_theme_resolver.dart +++ b/packages/wyatt_ui_kit/lib/src/components/loader/loader_theme_resolver.dart @@ -21,10 +21,15 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; class LoaderThemeResolver extends ThemeResolver { const LoaderThemeResolver({ - required this.computeExtensionValueFn, required this.customStyleFn, }); + @override + final LoaderStyle? Function( + BuildContext context, { + void extra, + }) customStyleFn; + /// Values taken from @override LoaderStyle computeDefaultValue( @@ -41,13 +46,13 @@ class LoaderThemeResolver ); @override - final LoaderStyle? Function( + LoaderStyle? computeExtensionValueFn( BuildContext context, - LoaderStyle defaultValue, LoaderThemeExtension themeExtension, { void extra, - }) computeExtensionValueFn; - - @override - final LoaderStyle? Function(BuildContext context, {void extra}) customStyleFn; + }) => + LoaderStyle( + colors: themeExtension.colors, + stroke: themeExtension.stroke, + ); } diff --git a/packages/wyatt_ui_kit/lib/src/components/rich_text_builder/rich_text_builder.dart b/packages/wyatt_ui_kit/lib/src/components/rich_text_builder/rich_text_builder.dart index 745d3462..c16df96c 100644 --- a/packages/wyatt_ui_kit/lib/src/components/rich_text_builder/rich_text_builder.dart +++ b/packages/wyatt_ui_kit/lib/src/components/rich_text_builder/rich_text_builder.dart @@ -42,16 +42,6 @@ class RichTextBuilder extends RichTextBuilderComponent RichTextBuilderStyle _resolve(BuildContext context) { final RichTextBuilderThemeResolver resolver = themeResolver ?? RichTextBuilderThemeResolver( - computeExtensionValueFn: ( - context, - defaultValue, - themeExtension, { - extra, - }) => - RichTextBuilderStyle( - defaultStyle: themeExtension.defaultStyle, - styles: themeExtension.styles, - ), customStyleFn: (context, {extra}) => RichTextBuilderStyle( defaultStyle: defaultStyle, styles: styles, @@ -69,7 +59,7 @@ class RichTextBuilder extends RichTextBuilderComponent text ?? '', regex, RichTextStyleParameter( - style.defaultStyle!, + style.defaultStyle, style.styles ?? {}, null, ), diff --git a/packages/wyatt_ui_kit/lib/src/components/rich_text_builder/rich_text_builder_theme_resolver.dart b/packages/wyatt_ui_kit/lib/src/components/rich_text_builder/rich_text_builder_theme_resolver.dart index f619d0a0..4661a264 100644 --- a/packages/wyatt_ui_kit/lib/src/components/rich_text_builder/rich_text_builder_theme_resolver.dart +++ b/packages/wyatt_ui_kit/lib/src/components/rich_text_builder/rich_text_builder_theme_resolver.dart @@ -21,7 +21,6 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; class RichTextBuilderThemeResolver extends ThemeResolver { const RichTextBuilderThemeResolver({ - required this.computeExtensionValueFn, required this.customStyleFn, }); @@ -37,13 +36,18 @@ class RichTextBuilderThemeResolver extends ThemeResolver + RichTextBuilderStyle( + defaultStyle: themeExtension.defaultStyle, + styles: themeExtension.styles, + ); } diff --git a/packages/wyatt_ui_kit/lib/src/components/text_inputs/cubit/text_input_cubit.dart b/packages/wyatt_ui_kit/lib/src/components/text_inputs/cubit/text_input_cubit.dart new file mode 100644 index 00000000..4c50a1b9 --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/text_inputs/cubit/text_input_cubit.dart @@ -0,0 +1,57 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'dart:async'; + +import 'package:equatable/equatable.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; + +part 'text_input_state.dart'; + +class TextInputCubit extends Cubit { + TextInputCubit() : super(const TextInputState.initial()); + + // ControlState logic + FutureOr onFocus() async { + if (state.controlState != ControlState.disabled) { + emit(state.copyWith(controlState: ControlState.focused)); + } + } + + FutureOr onUnfocus() async { + if (state.controlState != ControlState.disabled) { + emit(state.copyWith(controlState: ControlState.normal)); + } + } + + Future disable() async { + emit(state.copyWith(controlState: ControlState.disabled)); + } + + Future enable() async { + emit(state.copyWith(controlState: ControlState.normal)); + } + + // StatusState logic + FutureOr onInvalid(String? error) async { + emit(state.copyWith(statusState: StatusState.error, statusMessage: error)); + } + + FutureOr onSuccess() async { + emit(state.copyWith(statusState: StatusState.initial, statusMessage: '')); + } +} diff --git a/packages/wyatt_ui_kit/lib/src/components/text_inputs/cubit/text_input_state.dart b/packages/wyatt_ui_kit/lib/src/components/text_inputs/cubit/text_input_state.dart new file mode 100644 index 00000000..2b91bd2d --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/text_inputs/cubit/text_input_state.dart @@ -0,0 +1,49 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +part of 'text_input_cubit.dart'; + +class TextInputState extends Equatable { + const TextInputState({ + required this.controlState, + required this.statusState, + this.statusMessage, + }); + + const TextInputState.initial() + : controlState = ControlState.normal, + statusState = StatusState.initial, + statusMessage = null; + + final ControlState controlState; + final StatusState statusState; + + final String? statusMessage; + + @override + List get props => [controlState, statusState, statusMessage]; + + TextInputState copyWith({ + ControlState? controlState, + StatusState? statusState, + String? statusMessage, + }) => + TextInputState( + controlState: controlState ?? this.controlState, + statusState: statusState ?? this.statusState, + statusMessage: statusMessage ?? this.statusMessage, + ); +} diff --git a/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input.dart b/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input.dart new file mode 100644 index 00000000..8e5139c7 --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input.dart @@ -0,0 +1,168 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// super program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// super program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with super program. If not, see . + +import 'dart:ui'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart'; +import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; +import 'package:wyatt_ui_kit/src/components/text_inputs/text_input_screen.dart'; +part 'text_input.g.dart'; + +@ComponentCopyWithExtension() +class TextInput extends TextInputComponent with $TextInputCWMixin { + TextInput({ + super.expand, + super.validator, + super.key, + super.prefixIcon, + super.prefixText, + super.suffixIcon, + super.suffixText, + super.label, + super.onError, + super.hint, + super.normalStyle, + super.focusedStyle, + super.errorStyle, + super.disableStyle, + super.controller, + super.focusNode, + super.keyboardType, + super.smartDashesType, + super.smartQuotesType, + super.enableInteractiveSelection, + super.textInputAction, + super.textCapitalization, + super.style, + super.strutStyle, + super.textAlign, + super.textAlignVertical, + super.textDirection, + super.readOnly, + super.showCursor, + super.autofocus, + super.obscuringCharacter, + super.obscureText, + super.autocorrect, + super.enableSuggestions, + super.maxLines, + super.minLines, + super.expands, + super.maxLength, + super.maxLengthEnforcement, + super.onChanged, + super.onEditingComplete, + super.onSubmitted, + super.onAppPrivateCommand, + super.inputFormatters, + super.enabled, + super.cursorWidth, + super.cursorHeight, + super.cursorRadius, + super.cursorColor, + super.selectionHeightStyle, + super.selectionWidthStyle, + super.keyboardAppearance, + super.scrollPadding, + super.dragStartBehavior, + super.selectionControls, + super.onTap, + super.onTapOutside, + super.mouseCursor, + super.scrollController, + super.scrollPhysics, + super.autofillHints, + super.clipBehavior, + super.restorationId, + super.scribbleEnabled, + super.enableIMEPersonalizedLearning, + super.contextMenuBuilder, + super.spellCheckConfiguration, + super.magnifierConfiguration, + }); + + @override + Widget build(BuildContext context) => TextInputScreen( + expand: expand, + validator: validator, + label: label, + onError: onError, + hint: hint, + focusedStyle: focusedStyle, + normalStyle: normalStyle, + errorStyle: errorStyle, + disableStyle: disableStyle, + prefixIcon: prefixIcon, + prefixText: prefixText, + suffixIcon: suffixIcon, + magnifierConfiguration: magnifierConfiguration, + controller: controller, + focusNode: focusNode, + keyboardType: keyboardType, + textInputAction: textInputAction, + textCapitalization: textCapitalization, + style: style, + strutStyle: strutStyle, + textAlign: textAlign, + textAlignVertical: textAlignVertical, + textDirection: textDirection, + autofocus: autofocus, + obscuringCharacter: obscuringCharacter, + obscureText: obscureText, + autocorrect: autocorrect, + smartDashesType: smartDashesType, + smartQuotesType: smartQuotesType, + enableSuggestions: enableSuggestions, + maxLines: maxLines, + minLines: minLines, + expands: expands, + readOnly: readOnly, + showCursor: showCursor, + maxLength: maxLength, + maxLengthEnforcement: maxLengthEnforcement, + onChanged: onChanged, + onEditingComplete: onEditingComplete, + onSubmitted: onSubmitted, + onAppPrivateCommand: onAppPrivateCommand, + inputFormatters: inputFormatters, + enabled: enabled, + cursorWidth: cursorWidth, + cursorHeight: cursorHeight, + cursorRadius: cursorRadius, + cursorColor: cursorColor, + selectionHeightStyle: selectionHeightStyle, + selectionWidthStyle: selectionWidthStyle, + keyboardAppearance: keyboardAppearance, + scrollPadding: scrollPadding, + enableInteractiveSelection: enableInteractiveSelection, + selectionControls: selectionControls, + dragStartBehavior: dragStartBehavior, + onTap: onTap, + onTapOutside: onTapOutside, + mouseCursor: mouseCursor, + scrollPhysics: scrollPhysics, + scrollController: scrollController, + autofillHints: autofillHints, + clipBehavior: clipBehavior, + restorationId: restorationId, + scribbleEnabled: scribbleEnabled, + enableIMEPersonalizedLearning: enableIMEPersonalizedLearning, + contextMenuBuilder: contextMenuBuilder, + spellCheckConfiguration: spellCheckConfiguration, + ); +} diff --git a/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input.g.dart b/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input.g.dart new file mode 100644 index 00000000..2547f95c --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input.g.dart @@ -0,0 +1,348 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'text_input.dart'; + +// ************************************************************************** +// ComponentCopyWithGenerator +// ************************************************************************** + +class $TextInputCWProxyImpl implements $TextInputComponentCWProxy { + const $TextInputCWProxyImpl(this._value); + final TextInput _value; + @override + TextInput expand(bool? expand) => this(expand: expand); + @override + TextInput onError(String Function(String)? onError) => this(onError: onError); + @override + TextInput validator(bool Function(String)? validator) => + this(validator: validator); + @override + TextInput suffixText(TextWrapper? suffixText) => this(suffixText: suffixText); + @override + TextInput prefixText(TextWrapper? prefixText) => this(prefixText: prefixText); + @override + TextInput prefixIcon(Icon? prefixIcon) => this(prefixIcon: prefixIcon); + @override + TextInput suffixIcon(Icon? suffixIcon) => this(suffixIcon: suffixIcon); + @override + TextInput label(TextWrapper? label) => this(label: label); + @override + TextInput hint(TextWrapper? hint) => this(hint: hint); + @override + TextInput normalStyle(TextInputStyle? normalStyle) => + this(normalStyle: normalStyle); + @override + TextInput focusedStyle(TextInputStyle? focusedStyle) => + this(focusedStyle: focusedStyle); + @override + TextInput errorStyle(TextInputStyle? errorStyle) => + this(errorStyle: errorStyle); + @override + TextInput disableStyle(TextInputStyle? disableStyle) => + this(disableStyle: disableStyle); + @override + TextInput controller(TextEditingController? controller) => + this(controller: controller); + @override + TextInput focusNode(FocusNode? focusNode) => this(focusNode: focusNode); + @override + TextInput keyboardType(TextInputType? keyboardType) => + this(keyboardType: keyboardType); + @override + TextInput smartDashesType(SmartDashesType? smartDashesType) => + this(smartDashesType: smartDashesType); + @override + TextInput smartQuotesType(SmartQuotesType? smartQuotesType) => + this(smartQuotesType: smartQuotesType); + @override + TextInput enableInteractiveSelection(bool? enableInteractiveSelection) => + this(enableInteractiveSelection: enableInteractiveSelection); + @override + TextInput textInputAction(TextInputAction? textInputAction) => + this(textInputAction: textInputAction); + @override + TextInput textCapitalization(TextCapitalization? textCapitalization) => + this(textCapitalization: textCapitalization); + @override + TextInput style(TextStyle? style) => this(style: style); + @override + TextInput strutStyle(StrutStyle? strutStyle) => this(strutStyle: strutStyle); + @override + TextInput textAlign(TextAlign? textAlign) => this(textAlign: textAlign); + @override + TextInput textAlignVertical(TextAlignVertical? textAlignVertical) => + this(textAlignVertical: textAlignVertical); + @override + TextInput textDirection(TextDirection? textDirection) => + this(textDirection: textDirection); + @override + TextInput readOnly(bool? readOnly) => this(readOnly: readOnly); + @override + TextInput showCursor(bool? showCursor) => this(showCursor: showCursor); + @override + TextInput autofocus(bool? autofocus) => this(autofocus: autofocus); + @override + TextInput obscuringCharacter(String? obscuringCharacter) => + this(obscuringCharacter: obscuringCharacter); + @override + TextInput obscureText(bool? obscureText) => this(obscureText: obscureText); + @override + TextInput autocorrect(bool? autocorrect) => this(autocorrect: autocorrect); + @override + TextInput enableSuggestions(bool? enableSuggestions) => + this(enableSuggestions: enableSuggestions); + @override + TextInput maxLines(int? maxLines) => this(maxLines: maxLines); + @override + TextInput minLines(int? minLines) => this(minLines: minLines); + @override + TextInput expands(bool? expands) => this(expands: expands); + @override + TextInput maxLength(int? maxLength) => this(maxLength: maxLength); + @override + TextInput maxLengthEnforcement(MaxLengthEnforcement? maxLengthEnforcement) => + this(maxLengthEnforcement: maxLengthEnforcement); + @override + TextInput onChanged(void Function(String)? onChanged) => + this(onChanged: onChanged); + @override + TextInput onEditingComplete(void Function()? onEditingComplete) => + this(onEditingComplete: onEditingComplete); + @override + TextInput onSubmitted(void Function(String)? onSubmitted) => + this(onSubmitted: onSubmitted); + @override + TextInput onAppPrivateCommand( + void Function(String, Map)? onAppPrivateCommand) => + this(onAppPrivateCommand: onAppPrivateCommand); + @override + TextInput inputFormatters(List? inputFormatters) => + this(inputFormatters: inputFormatters); + @override + TextInput enabled(ValueNotifier? enabled) => this(enabled: enabled); + @override + TextInput cursorWidth(double? cursorWidth) => this(cursorWidth: cursorWidth); + @override + TextInput cursorHeight(double? cursorHeight) => + this(cursorHeight: cursorHeight); + @override + TextInput cursorRadius(Radius? cursorRadius) => + this(cursorRadius: cursorRadius); + @override + TextInput cursorColor(Color? cursorColor) => this(cursorColor: cursorColor); + @override + TextInput selectionHeightStyle(BoxHeightStyle? selectionHeightStyle) => + this(selectionHeightStyle: selectionHeightStyle); + @override + TextInput selectionWidthStyle(BoxWidthStyle? selectionWidthStyle) => + this(selectionWidthStyle: selectionWidthStyle); + @override + TextInput keyboardAppearance(Brightness? keyboardAppearance) => + this(keyboardAppearance: keyboardAppearance); + @override + TextInput scrollPadding(EdgeInsets? scrollPadding) => + this(scrollPadding: scrollPadding); + @override + TextInput dragStartBehavior(DragStartBehavior? dragStartBehavior) => + this(dragStartBehavior: dragStartBehavior); + @override + TextInput selectionControls(TextSelectionControls? selectionControls) => + this(selectionControls: selectionControls); + @override + TextInput onTap(void Function()? onTap) => this(onTap: onTap); + @override + TextInput onTapOutside(void Function(PointerDownEvent)? onTapOutside) => + this(onTapOutside: onTapOutside); + @override + TextInput mouseCursor(MouseCursor? mouseCursor) => + this(mouseCursor: mouseCursor); + @override + TextInput scrollController(ScrollController? scrollController) => + this(scrollController: scrollController); + @override + TextInput scrollPhysics(ScrollPhysics? scrollPhysics) => + this(scrollPhysics: scrollPhysics); + @override + TextInput autofillHints(Iterable? autofillHints) => + this(autofillHints: autofillHints); + @override + TextInput clipBehavior(Clip? clipBehavior) => + this(clipBehavior: clipBehavior); + @override + TextInput restorationId(String? restorationId) => + this(restorationId: restorationId); + @override + TextInput scribbleEnabled(bool? scribbleEnabled) => + this(scribbleEnabled: scribbleEnabled); + @override + TextInput enableIMEPersonalizedLearning( + bool? enableIMEPersonalizedLearning) => + this(enableIMEPersonalizedLearning: enableIMEPersonalizedLearning); + @override + TextInput contextMenuBuilder( + Widget Function(BuildContext, EditableTextState)? + contextMenuBuilder) => + this(contextMenuBuilder: contextMenuBuilder); + @override + TextInput spellCheckConfiguration( + SpellCheckConfiguration? spellCheckConfiguration) => + this(spellCheckConfiguration: spellCheckConfiguration); + @override + TextInput magnifierConfiguration( + TextMagnifierConfiguration? magnifierConfiguration) => + this(magnifierConfiguration: magnifierConfiguration); + @override + TextInput key(Key? key) => this(key: key); + @override + TextInput call({ + bool? expand, + String Function(String)? onError, + bool Function(String)? validator, + TextWrapper? suffixText, + TextWrapper? prefixText, + Icon? prefixIcon, + Icon? suffixIcon, + TextWrapper? label, + TextWrapper? hint, + TextInputStyle? normalStyle, + TextInputStyle? focusedStyle, + TextInputStyle? errorStyle, + TextInputStyle? disableStyle, + TextEditingController? controller, + FocusNode? focusNode, + TextInputType? keyboardType, + SmartDashesType? smartDashesType, + SmartQuotesType? smartQuotesType, + bool? enableInteractiveSelection, + TextInputAction? textInputAction, + TextCapitalization? textCapitalization, + TextStyle? style, + StrutStyle? strutStyle, + TextAlign? textAlign, + TextAlignVertical? textAlignVertical, + TextDirection? textDirection, + bool? readOnly, + bool? showCursor, + bool? autofocus, + String? obscuringCharacter, + bool? obscureText, + bool? autocorrect, + bool? enableSuggestions, + int? maxLines, + int? minLines, + bool? expands, + int? maxLength, + MaxLengthEnforcement? maxLengthEnforcement, + void Function(String)? onChanged, + void Function()? onEditingComplete, + void Function(String)? onSubmitted, + void Function(String, Map)? onAppPrivateCommand, + List? inputFormatters, + ValueNotifier? enabled, + double? cursorWidth, + double? cursorHeight, + Radius? cursorRadius, + Color? cursorColor, + BoxHeightStyle? selectionHeightStyle, + BoxWidthStyle? selectionWidthStyle, + Brightness? keyboardAppearance, + EdgeInsets? scrollPadding, + DragStartBehavior? dragStartBehavior, + TextSelectionControls? selectionControls, + void Function()? onTap, + void Function(PointerDownEvent)? onTapOutside, + MouseCursor? mouseCursor, + ScrollController? scrollController, + ScrollPhysics? scrollPhysics, + Iterable? autofillHints, + Clip? clipBehavior, + String? restorationId, + bool? scribbleEnabled, + bool? enableIMEPersonalizedLearning, + Widget Function(BuildContext, EditableTextState)? contextMenuBuilder, + SpellCheckConfiguration? spellCheckConfiguration, + TextMagnifierConfiguration? magnifierConfiguration, + Key? key, + }) => + TextInput( + expand: expand ?? _value.expand, + validator: validator ?? _value.validator, + key: key ?? _value.key, + prefixIcon: prefixIcon ?? _value.prefixIcon, + prefixText: prefixText ?? _value.prefixText, + suffixIcon: suffixIcon ?? _value.suffixIcon, + suffixText: suffixText ?? _value.suffixText, + label: label ?? _value.label, + onError: onError ?? _value.onError, + hint: hint ?? _value.hint, + normalStyle: normalStyle ?? _value.normalStyle, + focusedStyle: focusedStyle ?? _value.focusedStyle, + errorStyle: errorStyle ?? _value.errorStyle, + disableStyle: disableStyle ?? _value.disableStyle, + controller: controller ?? _value.controller, + focusNode: focusNode ?? _value.focusNode, + keyboardType: keyboardType ?? _value.keyboardType, + smartDashesType: smartDashesType ?? _value.smartDashesType, + smartQuotesType: smartQuotesType ?? _value.smartQuotesType, + enableInteractiveSelection: + enableInteractiveSelection ?? _value.enableInteractiveSelection, + textInputAction: textInputAction ?? _value.textInputAction, + textCapitalization: textCapitalization ?? _value.textCapitalization, + style: style ?? _value.style, + strutStyle: strutStyle ?? _value.strutStyle, + textAlign: textAlign ?? _value.textAlign, + textAlignVertical: textAlignVertical ?? _value.textAlignVertical, + textDirection: textDirection ?? _value.textDirection, + readOnly: readOnly ?? _value.readOnly, + showCursor: showCursor ?? _value.showCursor, + autofocus: autofocus ?? _value.autofocus, + obscuringCharacter: obscuringCharacter ?? _value.obscuringCharacter, + obscureText: obscureText ?? _value.obscureText, + autocorrect: autocorrect ?? _value.autocorrect, + enableSuggestions: enableSuggestions ?? _value.enableSuggestions, + maxLines: maxLines ?? _value.maxLines, + minLines: minLines ?? _value.minLines, + expands: expands ?? _value.expands, + maxLength: maxLength ?? _value.maxLength, + maxLengthEnforcement: + maxLengthEnforcement ?? _value.maxLengthEnforcement, + onChanged: onChanged ?? _value.onChanged, + onEditingComplete: onEditingComplete ?? _value.onEditingComplete, + onSubmitted: onSubmitted ?? _value.onSubmitted, + onAppPrivateCommand: onAppPrivateCommand ?? _value.onAppPrivateCommand, + inputFormatters: inputFormatters ?? _value.inputFormatters, + enabled: enabled ?? _value.enabled, + cursorWidth: cursorWidth ?? _value.cursorWidth, + cursorHeight: cursorHeight ?? _value.cursorHeight, + cursorRadius: cursorRadius ?? _value.cursorRadius, + cursorColor: cursorColor ?? _value.cursorColor, + selectionHeightStyle: + selectionHeightStyle ?? _value.selectionHeightStyle, + selectionWidthStyle: selectionWidthStyle ?? _value.selectionWidthStyle, + keyboardAppearance: keyboardAppearance ?? _value.keyboardAppearance, + scrollPadding: scrollPadding ?? _value.scrollPadding, + dragStartBehavior: dragStartBehavior ?? _value.dragStartBehavior, + selectionControls: selectionControls ?? _value.selectionControls, + onTap: onTap ?? _value.onTap, + onTapOutside: onTapOutside ?? _value.onTapOutside, + mouseCursor: mouseCursor ?? _value.mouseCursor, + scrollController: scrollController ?? _value.scrollController, + scrollPhysics: scrollPhysics ?? _value.scrollPhysics, + autofillHints: autofillHints ?? _value.autofillHints, + clipBehavior: clipBehavior ?? _value.clipBehavior, + restorationId: restorationId ?? _value.restorationId, + scribbleEnabled: scribbleEnabled ?? _value.scribbleEnabled, + enableIMEPersonalizedLearning: enableIMEPersonalizedLearning ?? + _value.enableIMEPersonalizedLearning, + contextMenuBuilder: contextMenuBuilder ?? _value.contextMenuBuilder, + spellCheckConfiguration: + spellCheckConfiguration ?? _value.spellCheckConfiguration, + magnifierConfiguration: + magnifierConfiguration ?? _value.magnifierConfiguration, + ); +} + +mixin $TextInputCWMixin on Component { + $TextInputComponentCWProxy get copyWith => + $TextInputCWProxyImpl(this as TextInput); +} diff --git a/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input_screen.dart b/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input_screen.dart new file mode 100644 index 00000000..bc109d98 --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input_screen.dart @@ -0,0 +1,383 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'dart:ui'; + +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart'; +import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; +import 'package:wyatt_ui_kit/src/components/text_inputs/cubit/text_input_cubit.dart'; +import 'package:wyatt_ui_kit/src/components/text_inputs/text_input_theme_resolver.dart'; +import 'package:wyatt_ui_kit/src/components/text_inputs/widgets/label_widget.dart'; +import 'package:wyatt_ui_kit/src/components/text_inputs/widgets/text_input_wrapper.dart'; + +class TextInputScreen extends CubitScreen { + TextInputScreen({ + this.expand, + this.onError, + this.validator, + super.key, + this.suffixText, + this.prefixText, + this.prefixIcon, + this.suffixIcon, + this.label, + this.hint, + this.normalStyle, + this.focusedStyle, + this.errorStyle, + this.disableStyle, + this.magnifierConfiguration, + this.controller, + this.focusNode, + this.keyboardType, + this.textInputAction, + this.textCapitalization, + this.style, + this.strutStyle, + this.textAlign, + this.textAlignVertical, + this.textDirection, + this.autofocus, + this.obscuringCharacter, + this.obscureText, + this.autocorrect, + this.smartDashesType, + this.smartQuotesType, + this.enableSuggestions, + this.maxLines, + this.minLines, + this.expands, + this.readOnly, + this.showCursor, + this.maxLength, + this.maxLengthEnforcement, + this.onChanged, + this.onEditingComplete, + this.onSubmitted, + this.onAppPrivateCommand, + this.inputFormatters, + this.enabled, + this.cursorWidth, + this.cursorHeight, + this.cursorRadius, + this.cursorColor, + this.selectionHeightStyle, + this.selectionWidthStyle, + this.keyboardAppearance, + this.scrollPadding, + this.enableInteractiveSelection, + this.selectionControls, + this.dragStartBehavior, + this.onTap, + this.onTapOutside, + this.mouseCursor, + this.scrollPhysics, + this.scrollController, + this.autofillHints, + this.clipBehavior, + this.restorationId, + this.scribbleEnabled, + this.enableIMEPersonalizedLearning, + this.contextMenuBuilder, + this.spellCheckConfiguration, + }); + + final TextMagnifierConfiguration? magnifierConfiguration; + final TextEditingController? controller; + final FocusNode? focusNode; + final TextInputType? keyboardType; + final TextInputAction? textInputAction; + final TextCapitalization? textCapitalization; + final TextStyle? style; + final StrutStyle? strutStyle; + final TextAlign? textAlign; + final TextAlignVertical? textAlignVertical; + final TextDirection? textDirection; + final bool? autofocus; + final String? obscuringCharacter; + final bool? obscureText; + final bool? autocorrect; + final SmartDashesType? smartDashesType; + final SmartQuotesType? smartQuotesType; + final bool? enableSuggestions; + final int? maxLines; + final int? minLines; + final bool? expands; + final bool? readOnly; + final bool? showCursor; + final int? maxLength; + final MaxLengthEnforcement? maxLengthEnforcement; + final ValueChanged? onChanged; + final VoidCallback? onEditingComplete; + final ValueChanged? onSubmitted; + final AppPrivateCommandCallback? onAppPrivateCommand; + final List? inputFormatters; + final double? cursorWidth; + final double? cursorHeight; + final Radius? cursorRadius; + final Color? cursorColor; + final BoxHeightStyle? selectionHeightStyle; + final BoxWidthStyle? selectionWidthStyle; + final Brightness? keyboardAppearance; + final EdgeInsets? scrollPadding; + final bool? enableInteractiveSelection; + final TextSelectionControls? selectionControls; + final DragStartBehavior? dragStartBehavior; + final GestureTapCallback? onTap; + final TapRegionCallback? onTapOutside; + final MouseCursor? mouseCursor; + final ScrollPhysics? scrollPhysics; + final ScrollController? scrollController; + final Iterable? autofillHints; + final Clip? clipBehavior; + final String? restorationId; + final bool? scribbleEnabled; + final bool? enableIMEPersonalizedLearning; + final EditableTextContextMenuBuilder? contextMenuBuilder; + final SpellCheckConfiguration? spellCheckConfiguration; + + final bool Function(String)? validator; + final String? Function(String)? onError; + + final TextInputStyle? normalStyle; + final TextInputStyle? focusedStyle; + final TextInputStyle? errorStyle; + final TextInputStyle? disableStyle; + + final TextWrapper? label; + final TextWrapper? hint; + final ValueNotifier? enabled; + + final bool? expand; + + final TextWrapper? prefixText; + final Icon? prefixIcon; + final Icon? suffixIcon; + final TextWrapper? suffixText; + + @override + TextInputCubit create(BuildContext context) => TextInputCubit(); + + @override + TextInputCubit init(BuildContext context, TextInputCubit bloc) { + enabled?.addListener(() { + if (enabled?.value ?? false) { + bloc.enable(); + } else { + bloc.disable(); + } + }); + return bloc; + } + + final _focusNode = FocusNode(); + final _controller = TextEditingController(); + + final _notOutilinedBorder = const OutlineInputBorder( + borderSide: BorderSide(color: Colors.transparent), + ); + + TextInputStyle _resolve(BuildContext context, TextInputState state) { + final resolver = TextInputThemeResolver( + customStyleFn: (context, {extra}) { + TextInputStyle? textInputStyle; + switch (extra?.controlState) { + case ControlState.focused: + textInputStyle = focusedStyle; + break; + case ControlState.disabled: + textInputStyle = disableStyle; + break; + case ControlState.normal: + textInputStyle = normalStyle; + break; + case ControlState.hovered: + case ControlState.tapped: + case null: + break; + } + + TextInputStyle? style; + switch (extra?.statusState) { + case StatusState.error: + style = errorStyle; + break; + case StatusState.initial: + case StatusState.success: + case StatusState.loading: + case null: + break; + } + + return TextInputStyle.merge(textInputStyle, style); + }, + ); + + return resolver.negotiate(context, extra: state); + } + + bool _wrapperExpanded(TextInputState state) { + final fn = focusNode ?? _focusNode; + final tec = controller ?? _controller; + if (fn.hasFocus && label != null) { + return true; + } else if (tec.value.text.isNotEmpty && label != null) { + return true; + } else if (state.statusState == StatusState.error && + (state.statusMessage?.isNotEmpty ?? false)) { + return true; + } + return false; + } + + @override + Widget onBuild(BuildContext context, TextInputState state) { + final style = _resolve(context, state); + return Focus( + onFocusChange: (hasFocus) { + if (hasFocus) { + bloc(context).onFocus(); + } else { + bloc(context).onUnfocus(); + } + }, + child: AnimatedContainer( + duration: const Duration(milliseconds: 600), + decoration: BoxDecoration( + boxShadow: style.boxShadow != null ? [style.boxShadow!] : null, + gradient: style.backgroundColors?.isGradient ?? false + ? LinearGradient(colors: style.backgroundColors!.colors) + : null, + color: style.backgroundColors?.isColor ?? false + ? style.backgroundColors?.color + : null, + borderRadius: style.radius ?? BorderRadius.circular(4), + border: (style.borderColors != null) + ? Border.all( + width: 1.5, + color: style.borderColors!, + ) + : null, + ), + child: TextInputWrapper( + expand: expand ?? true, + expanded: _wrapperExpanded(state), + child: TextField( + onTap: onTap, + onChanged: (value) { + onChanged?.call(value); + if (validator?.call(value) ?? false) { + bloc(context).onInvalid(onError?.call(value)); + } else { + bloc(context).onSuccess(); + } + }, + onTapOutside: onTapOutside, + controller: controller ?? _controller, + focusNode: focusNode ?? _focusNode, + textAlignVertical: textAlignVertical ?? TextAlignVertical.top, + style: style.inputStyle ?? this.style, + decoration: InputDecoration( + focusedErrorBorder: _notOutilinedBorder, + focusedBorder: _notOutilinedBorder, + errorBorder: _notOutilinedBorder, + disabledBorder: _notOutilinedBorder, + enabledBorder: _notOutilinedBorder, + border: _notOutilinedBorder, + isDense: true, + iconColor: style.iconColor, + alignLabelWithHint: true, + label: (state.statusState == StatusState.error && + (state.statusMessage?.isNotEmpty ?? false)) || + label != null + ? LabelWidget( + focusNode: focusNode ?? _focusNode, + label: (state.statusState == StatusState.error && + (state.statusMessage?.isNotEmpty ?? false)) + ? state.statusMessage?.wrap() + : label, + labelStyle: style.labelStyle, + ) + : null, + hintText: hint?.text, + hintStyle: hint?.style, + prefixIcon: prefixIcon, + prefixText: prefixText?.text, + prefixStyle: prefixText?.style, + prefixIconColor: style.prefixIconColor, + suffixIcon: suffixIcon, + suffixText: suffixText?.text, + suffixStyle: suffixText?.style, + suffixIconColor: style.suffixIconColor, + enabled: state.controlState != ControlState.disabled, + ), + keyboardType: keyboardType, + smartDashesType: smartDashesType, + smartQuotesType: smartQuotesType, + enableInteractiveSelection: enableInteractiveSelection, + textInputAction: textInputAction, + textCapitalization: textCapitalization ?? TextCapitalization.none, + strutStyle: strutStyle, + textAlign: textAlign ?? TextAlign.start, + textDirection: textDirection, + readOnly: readOnly ?? false, + showCursor: showCursor, + autofocus: autofocus ?? false, + obscuringCharacter: obscuringCharacter ?? '*', + obscureText: obscureText ?? false, + autocorrect: autocorrect ?? true, + enableSuggestions: enableSuggestions ?? true, + maxLines: maxLines ?? 1, + minLines: minLines, + expands: expands ?? false, + maxLength: maxLength, + maxLengthEnforcement: maxLengthEnforcement, + onEditingComplete: onEditingComplete, + onSubmitted: onSubmitted, + onAppPrivateCommand: onAppPrivateCommand, + inputFormatters: inputFormatters, + enabled: state.controlState != ControlState.disabled, + cursorWidth: cursorWidth ?? 2.0, + cursorHeight: cursorHeight, + cursorRadius: cursorRadius, + cursorColor: cursorColor, + selectionHeightStyle: selectionHeightStyle ?? BoxHeightStyle.tight, + selectionWidthStyle: selectionWidthStyle ?? BoxWidthStyle.tight, + keyboardAppearance: keyboardAppearance, + scrollPadding: scrollPadding ?? const EdgeInsets.all(20), + dragStartBehavior: dragStartBehavior ?? DragStartBehavior.start, + selectionControls: selectionControls, + mouseCursor: mouseCursor, + scrollController: scrollController, + scrollPhysics: scrollPhysics, + autofillHints: autofillHints, + clipBehavior: clipBehavior ?? Clip.hardEdge, + restorationId: restorationId, + scribbleEnabled: scribbleEnabled ?? true, + enableIMEPersonalizedLearning: + enableIMEPersonalizedLearning ?? true, + contextMenuBuilder: contextMenuBuilder, + spellCheckConfiguration: spellCheckConfiguration, + magnifierConfiguration: magnifierConfiguration, + ), + ), + ), + ); + } +} diff --git a/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input_theme_resolver.dart b/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input_theme_resolver.dart new file mode 100644 index 00000000..5a3fbd0c --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input_theme_resolver.dart @@ -0,0 +1,155 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'package:flutter/material.dart'; +import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; +import 'package:wyatt_ui_kit/src/components/text_inputs/cubit/text_input_cubit.dart'; +import 'package:wyatt_ui_kit/src/core/core.dart'; +import 'package:wyatt_ui_kit/src/domain/text_input_theme_extension.dart'; + +class TextInputThemeResolver extends ThemeResolver { + const TextInputThemeResolver({ + required this.customStyleFn, + }); + + @override + final TextInputStyle? Function( + BuildContext context, { + TextInputState? extra, + }) customStyleFn; + + @override + TextInputStyle computeDefaultValue( + BuildContext context, { + TextInputState? extra, + }) { + TextStyle? labelStyle = context.textTheme.labelLarge + ?.copyWith(color: Theme.of(context).unselectedWidgetColor); + + TextStyle? hintStyle = context.textTheme.labelLarge; + TextStyle? prefixStyle = context.textTheme.bodyMedium; + TextStyle? suffixStyle = context.textTheme.bodyMedium; + TextStyle? inputStyle = context.textTheme.bodyMedium; + + Color? iconColor = context.colorScheme.inversePrimary; + Color? prefixIconColor = Theme.of(context).unselectedWidgetColor; + Color? suffixIconColor = Theme.of(context).unselectedWidgetColor; + + Color? borderColors = Theme.of(context).unselectedWidgetColor; + + MultiColor? backgroundColors; + BoxShadow? boxShadow; + + final BorderRadiusGeometry radius = BorderRadius.circular(4); + + switch (extra?.controlState) { + case ControlState.disabled: + labelStyle = + labelStyle?.copyWith(color: Theme.of(context).disabledColor); + hintStyle = hintStyle?.copyWith(color: Theme.of(context).disabledColor); + prefixStyle = + prefixStyle?.copyWith(color: Theme.of(context).disabledColor); + suffixStyle = + suffixStyle?.copyWith(color: Theme.of(context).disabledColor); + inputStyle = + inputStyle?.copyWith(color: Theme.of(context).disabledColor); + borderColors = Theme.of(context).disabledColor; + prefixIconColor = Theme.of(context).disabledColor; + suffixIconColor = Theme.of(context).disabledColor; + + break; + + case ControlState.focused: + prefixIconColor = context.colorScheme.primary; + suffixIconColor = context.colorScheme.primary; + iconColor = context.colorScheme.primary; + borderColors = context.colorScheme.primary; + labelStyle = labelStyle?.copyWith(color: context.colorScheme.primary); + break; + case ControlState.hovered: + case ControlState.tapped: + case ControlState.normal: + case null: + break; + } + + switch (extra?.statusState) { + case StatusState.error: + labelStyle = context.textTheme.labelLarge + ?.copyWith(color: context.colorScheme.error); + borderColors = context.colorScheme.error; + break; + case StatusState.initial: + case StatusState.success: + case StatusState.loading: + case null: + break; + } + return TextInputStyle( + labelStyle: labelStyle, + hintStyle: hintStyle, + iconColor: iconColor, + prefixIconColor: prefixIconColor, + prefixStyle: prefixStyle, + suffixStyle: suffixStyle, + suffixIconColor: suffixIconColor, + backgroundColors: backgroundColors, + borderColors: borderColors, + boxShadow: boxShadow, + radius: radius, + inputStyle: inputStyle, + ); + } + + @override + TextInputStyle? computeExtensionValueFn( + BuildContext context, + TextInputThemeExtension themeExtension, { + TextInputState? extra, + }) { + TextInputStyle? textInputStyle; + switch (extra?.controlState) { + case ControlState.focused: + textInputStyle = themeExtension.focusedStyle; + break; + case ControlState.disabled: + textInputStyle = themeExtension.disableStyle; + break; + case ControlState.normal: + textInputStyle = themeExtension.normalStyle; + break; + case ControlState.hovered: + case ControlState.tapped: + case null: + break; + } + + TextInputStyle? style; + switch (extra?.statusState) { + case StatusState.error: + style = themeExtension.errorStyle; + break; + case StatusState.initial: + case StatusState.success: + case StatusState.loading: + case null: + break; + } + + return TextInputStyle.merge(textInputStyle, style); + } +} diff --git a/packages/wyatt_ui_kit/lib/src/components/text_inputs/widgets/label_widget.dart b/packages/wyatt_ui_kit/lib/src/components/text_inputs/widgets/label_widget.dart new file mode 100644 index 00000000..0312c62e --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/text_inputs/widgets/label_widget.dart @@ -0,0 +1,37 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// super program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// super program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with super program. If not, see . + +import 'package:flutter/material.dart'; +import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; + +class LabelWidget extends StatelessWidget { + const LabelWidget({ + required this.label, + required this.focusNode, + required this.labelStyle, + super.key, + }); + + final TextWrapper? label; + final FocusNode focusNode; + final TextStyle? labelStyle; + + @override + Widget build(BuildContext context) => Text( + label?.text ?? '', + style: labelStyle, + ); +} diff --git a/packages/wyatt_ui_kit/lib/src/components/text_inputs/widgets/text_input_wrapper.dart b/packages/wyatt_ui_kit/lib/src/components/text_inputs/widgets/text_input_wrapper.dart new file mode 100644 index 00000000..ba868365 --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/text_inputs/widgets/text_input_wrapper.dart @@ -0,0 +1,60 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// super program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// super program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with super program. If not, see . + +import 'package:flutter/material.dart'; + +const _defaultPadding = 7.5; +const _paddingAnimationDuration = Duration(milliseconds: 200); + +class TextInputWrapper extends StatelessWidget { + const TextInputWrapper({ + required this.expand, + required this.expanded, + required this.child, + super.key, + }); + final bool expand; + final bool expanded; + final Widget child; + + double _top() { + if (expanded) { + return 2 * _defaultPadding; + } else if (!expand) { + return _defaultPadding; + } + return 0; + } + + double _bottom() { + if (expanded) { + return 0; + } else if (!expand) { + return _defaultPadding; + } + return 0; + } + + @override + Widget build(BuildContext context) => AnimatedPadding( + duration: _paddingAnimationDuration, + padding: EdgeInsets.only( + top: _top(), + bottom: _bottom(), + ), + child: child, + ); +} diff --git a/packages/wyatt_ui_kit/lib/src/core/extensions/theme_extensions.dart b/packages/wyatt_ui_kit/lib/src/core/extensions/theme_extensions.dart index 5e39a69c..c874454a 100644 --- a/packages/wyatt_ui_kit/lib/src/core/extensions/theme_extensions.dart +++ b/packages/wyatt_ui_kit/lib/src/core/extensions/theme_extensions.dart @@ -21,4 +21,6 @@ extension BuildContextThemeExtension on BuildContext { TextTheme get textTheme => Theme.of(this).textTheme; ColorScheme get colorScheme => Theme.of(this).colorScheme; ButtonThemeData get buttonTheme => Theme.of(this).buttonTheme; + InputDecorationTheme get inputDecorationTheme => + Theme.of(this).inputDecorationTheme; } diff --git a/packages/wyatt_ui_kit/lib/src/core/helpers/helpers.dart b/packages/wyatt_ui_kit/lib/src/core/helpers/helpers.dart index 35d48e7f..0e95fe99 100644 --- a/packages/wyatt_ui_kit/lib/src/core/helpers/helpers.dart +++ b/packages/wyatt_ui_kit/lib/src/core/helpers/helpers.dart @@ -15,3 +15,4 @@ // along with this program. If not, see . export './linear_gradient_helper.dart'; +export './theme_helper.dart'; diff --git a/packages/wyatt_ui_kit/lib/src/core/helpers/theme_helper.dart b/packages/wyatt_ui_kit/lib/src/core/helpers/theme_helper.dart new file mode 100644 index 00000000..79cb54c8 --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/core/helpers/theme_helper.dart @@ -0,0 +1,41 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// super program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// super program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with super program. If not, see . + +/// A helper class for getting theme elements. +abstract class ThemeHelper { + + /// Gets a theme element from a list of styles. + /// Styles are checked in order, and the first one that passes the + /// [valueValidator] is returned. + /// If no style passes the [valueValidator], the [defaultValue] is returned. + /// If [styles] is null or empty, the [defaultValue] is returned. + /// Style elements are transformed using the [transform] function. + static T? getThemeElement( + List? styles, { + required T? Function(P?)? transform, + required T? defaultValue, + bool? Function(P?)? valueValidator, + }) { + if (styles?.isNotEmpty ?? false) { + for (final element in styles!) { + if (valueValidator?.call(element) ?? false) { + return transform?.call(element); + } + } + } + return defaultValue; + } +} diff --git a/packages/wyatt_ui_kit/lib/src/domain/domain.dart b/packages/wyatt_ui_kit/lib/src/domain/domain.dart index 51fa4377..6cf19139 100644 --- a/packages/wyatt_ui_kit/lib/src/domain/domain.dart +++ b/packages/wyatt_ui_kit/lib/src/domain/domain.dart @@ -18,3 +18,4 @@ export './button_theme_extension/button_theme_extension.dart'; export './card_theme_extension.dart'; export './loader_theme_extension.dart'; export './rich_text_builder_theme_extension.dart'; +export './text_input_theme_extension.dart'; diff --git a/packages/wyatt_ui_kit/lib/src/domain/text_input_theme_extension.dart b/packages/wyatt_ui_kit/lib/src/domain/text_input_theme_extension.dart new file mode 100644 index 00000000..8fe456bb --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/domain/text_input_theme_extension.dart @@ -0,0 +1,33 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +import 'package:flutter/material.dart'; +import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; + +abstract class TextInputThemeExtension + extends ThemeExtension { + const TextInputThemeExtension({ + this.normalStyle, + this.focusedStyle, + this.errorStyle, + this.disableStyle, + }); + + final TextInputStyle? normalStyle; + final TextInputStyle? focusedStyle; + final TextInputStyle? errorStyle; + final TextInputStyle? disableStyle; +}