Unverified Commit 7cd6fd43 authored by lirantzairi's avatar lirantzairi Committed by GitHub

TextField - allow to customize cursor color in error state (#136121)

The color of the TextField's cursor in error state is the same as the error text color by default. However we should be allowed to customize it

Fixes #135580
parent c15ff682
......@@ -288,6 +288,7 @@ class TextField extends StatefulWidget {
this.cursorRadius,
this.cursorOpacityAnimates,
this.cursorColor,
this.cursorErrorColor,
this.selectionHeightStyle = ui.BoxHeightStyle.tight,
this.selectionWidthStyle = ui.BoxWidthStyle.tight,
this.keyboardAppearance,
......@@ -595,6 +596,13 @@ class TextField extends StatefulWidget {
/// the value of [ColorScheme.primary] of [ThemeData.colorScheme].
final Color? cursorColor;
/// The color of the cursor when the [InputDecorator] is showing an error.
///
/// If this is null it will default to [TextStyle.color] of
/// [InputDecoration.errorStyle]. If that is null, it will use
/// [ColorScheme.error] of [ThemeData.colorScheme].
final Color? cursorErrorColor;
/// Controls how tall the selection highlight boxes are computed to be.
///
/// See [ui.BoxHeightStyle] for details on available styles.
......@@ -893,6 +901,7 @@ class TextField extends StatefulWidget {
properties.add(DiagnosticsProperty<Radius>('cursorRadius', cursorRadius, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('cursorOpacityAnimates', cursorOpacityAnimates, defaultValue: null));
properties.add(ColorProperty('cursorColor', cursorColor, defaultValue: null));
properties.add(ColorProperty('cursorErrorColor', cursorErrorColor, defaultValue: null));
properties.add(DiagnosticsProperty<Brightness>('keyboardAppearance', keyboardAppearance, defaultValue: null));
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('scrollPadding', scrollPadding, defaultValue: const EdgeInsets.all(20.0)));
properties.add(FlagProperty('selectionEnabled', value: selectionEnabled, defaultValue: true, ifFalse: 'selection disabled'));
......@@ -946,7 +955,7 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
bool get _hasError => widget.decoration?.errorText != null || widget.decoration?.error != null || _hasIntrinsicError;
Color get _errorColor => widget.decoration?.errorStyle?.color ?? Theme.of(context).colorScheme.error;
Color get _errorColor => widget.cursorErrorColor ?? widget.decoration?.errorStyle?.color ?? Theme.of(context).colorScheme.error;
InputDecoration _getEffectiveDecoration() {
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
......
......@@ -144,6 +144,7 @@ class TextFormField extends FormField<String> {
double? cursorHeight,
Radius? cursorRadius,
Color? cursorColor,
Color? cursorErrorColor,
Brightness? keyboardAppearance,
EdgeInsets scrollPadding = const EdgeInsets.all(20.0),
bool? enableInteractiveSelection,
......@@ -236,6 +237,7 @@ class TextFormField extends FormField<String> {
cursorHeight: cursorHeight,
cursorRadius: cursorRadius,
cursorColor: cursorColor,
cursorErrorColor: cursorErrorColor,
scrollPadding: scrollPadding,
scrollPhysics: scrollPhysics,
keyboardAppearance: keyboardAppearance,
......
......@@ -1481,27 +1481,64 @@ void main() {
});
testWidgetsWithLeakTracking('Error color for cursor while validating', (WidgetTester tester) async {
const Color errorColor = Color(0xff123456);
await tester.pumpWidget(MaterialApp(
theme: ThemeData(
colorScheme: const ColorScheme.light(error: errorColor),
),
home: Material(
child: Center(
child: TextFormField(
enabled: true,
autovalidateMode: AutovalidateMode.always,
validator: (String? value) {
return 'Please enter value';
},
const Color themeErrorColor = Color(0xff111111);
const Color errorStyleColor = Color(0xff777777);
const Color cursorErrorColor = Color(0xffbbbbbb);
Widget buildWidget({Color? errorStyleColor, Color? cursorErrorColor}) {
return MaterialApp(
theme: ThemeData(
colorScheme: const ColorScheme.light(error: themeErrorColor),
),
home: Material(
child: Center(
child: TextFormField(
enabled: true,
autovalidateMode: AutovalidateMode.always,
decoration: InputDecoration(
errorStyle: TextStyle(
color: errorStyleColor,
),
),
cursorErrorColor: cursorErrorColor,
validator: (String? value) {
return 'Please enter value';
},
),
),
),
);
}
Future<void> runTest(Widget widget, {required Color expectedColor}) async {
await tester.pumpWidget(widget);
await tester.enterText(find.byType(TextField), 'a');
final EditableText textField = tester.widget(
find.byType(EditableText).first,
);
await tester.pump();
expect(textField.cursorColor, expectedColor);
}
await runTest(
buildWidget(),
expectedColor: themeErrorColor,
);
await runTest(
buildWidget(errorStyleColor: errorStyleColor),
expectedColor: errorStyleColor,
);
await runTest(
buildWidget(cursorErrorColor: cursorErrorColor),
expectedColor: cursorErrorColor,
);
await runTest(
buildWidget(
errorStyleColor: errorStyleColor,
cursorErrorColor: cursorErrorColor,
),
));
await tester.enterText(find.byType(TextField), 'a');
final EditableText textField = tester.widget(find.byType(EditableText).first);
await tester.pump();
expect(textField.cursorColor, errorColor);
expectedColor: cursorErrorColor,
);
});
testWidgetsWithLeakTracking('TextFormField onChanged is called when the form is reset', (WidgetTester tester) async {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment