{
+ 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;
+}