Skip to content

Commit c5da507

Browse files
authored
Feat : TextField cursor color matching M2 and M3 Spec in error state (#119225)
According to Material specs, cursor should be red in error state.
1 parent 9b13fda commit c5da507

File tree

2 files changed

+31
-5
lines changed

2 files changed

+31
-5
lines changed

packages/flutter/lib/src/material/text_field.dart

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,8 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
917917

918918
bool get _hasError => widget.decoration?.errorText != null || _hasIntrinsicError;
919919

920+
Color get _errorColor => widget.decoration?.errorStyle?.color ?? Theme.of(context).colorScheme.error;
921+
920922
InputDecoration _getEffectiveDecoration() {
921923
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
922924
final ThemeData themeData = Theme.of(context);
@@ -1247,7 +1249,7 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
12471249
textSelectionControls ??= cupertinoTextSelectionHandleControls;
12481250
paintCursorAboveText = true;
12491251
cursorOpacityAnimates = true;
1250-
cursorColor = widget.cursorColor ?? selectionStyle.cursorColor ?? cupertinoTheme.primaryColor;
1252+
cursorColor = _hasError ? _errorColor : widget.cursorColor ?? selectionStyle.cursorColor ?? cupertinoTheme.primaryColor;
12511253
selectionColor = selectionStyle.selectionColor ?? cupertinoTheme.primaryColor.withOpacity(0.40);
12521254
cursorRadius ??= const Radius.circular(2.0);
12531255
cursorOffset = Offset(iOSHorizontalOffset / MediaQuery.devicePixelRatioOf(context), 0);
@@ -1260,7 +1262,7 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
12601262
textSelectionControls ??= cupertinoDesktopTextSelectionHandleControls;
12611263
paintCursorAboveText = true;
12621264
cursorOpacityAnimates = false;
1263-
cursorColor = widget.cursorColor ?? selectionStyle.cursorColor ?? cupertinoTheme.primaryColor;
1265+
cursorColor = _hasError ? _errorColor : widget.cursorColor ?? selectionStyle.cursorColor ?? cupertinoTheme.primaryColor;
12641266
selectionColor = selectionStyle.selectionColor ?? cupertinoTheme.primaryColor.withOpacity(0.40);
12651267
cursorRadius ??= const Radius.circular(2.0);
12661268
cursorOffset = Offset(iOSHorizontalOffset / MediaQuery.devicePixelRatioOf(context), 0);
@@ -1278,7 +1280,7 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
12781280
textSelectionControls ??= materialTextSelectionHandleControls;
12791281
paintCursorAboveText = false;
12801282
cursorOpacityAnimates = false;
1281-
cursorColor = widget.cursorColor ?? selectionStyle.cursorColor ?? theme.colorScheme.primary;
1283+
cursorColor = _hasError ? _errorColor : widget.cursorColor ?? selectionStyle.cursorColor ?? theme.colorScheme.primary;
12821284
selectionColor = selectionStyle.selectionColor ?? theme.colorScheme.primary.withOpacity(0.40);
12831285
break;
12841286

@@ -1287,7 +1289,7 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
12871289
textSelectionControls ??= desktopTextSelectionHandleControls;
12881290
paintCursorAboveText = false;
12891291
cursorOpacityAnimates = false;
1290-
cursorColor = widget.cursorColor ?? selectionStyle.cursorColor ?? theme.colorScheme.primary;
1292+
cursorColor = _hasError ? _errorColor : widget.cursorColor ?? selectionStyle.cursorColor ?? theme.colorScheme.primary;
12911293
selectionColor = selectionStyle.selectionColor ?? theme.colorScheme.primary.withOpacity(0.40);
12921294
break;
12931295

@@ -1296,7 +1298,7 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
12961298
textSelectionControls ??= desktopTextSelectionHandleControls;
12971299
paintCursorAboveText = false;
12981300
cursorOpacityAnimates = false;
1299-
cursorColor = widget.cursorColor ?? selectionStyle.cursorColor ?? theme.colorScheme.primary;
1301+
cursorColor = _hasError ? _errorColor : widget.cursorColor ?? selectionStyle.cursorColor ?? theme.colorScheme.primary;
13001302
selectionColor = selectionStyle.selectionColor ?? theme.colorScheme.primary.withOpacity(0.40);
13011303
handleDidGainAccessibilityFocus = () {
13021304
// Automatically activate the TextField when it receives accessibility focus.

packages/flutter/test/material/text_form_field_test.dart

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,4 +1169,28 @@ void main() {
11691169
final EditableText editableText = tester.widget(find.byType(EditableText));
11701170
expect(editableText.magnifierConfiguration, equals(myTextMagnifierConfiguration));
11711171
});
1172+
1173+
testWidgets('Error color for cursor while validating', (WidgetTester tester) async {
1174+
const Color errorColor = Color(0xff123456);
1175+
await tester.pumpWidget(MaterialApp(
1176+
theme: ThemeData(
1177+
colorScheme: const ColorScheme.light(error: errorColor),
1178+
),
1179+
home: Material(
1180+
child: Center(
1181+
child: TextFormField(
1182+
enabled: true,
1183+
autovalidateMode: AutovalidateMode.always,
1184+
validator: (String? value) {
1185+
return 'Please enter value';
1186+
},
1187+
),
1188+
),
1189+
),
1190+
));
1191+
await tester.enterText(find.byType(TextField), 'a');
1192+
final EditableText textField = tester.widget(find.byType(EditableText).first);
1193+
await tester.pump();
1194+
expect(textField.cursorColor, errorColor);
1195+
});
11721196
}

0 commit comments

Comments
 (0)