Fix label text color is wrong for a focused and hovered TextField (#146572)
Before, hovering a focused TextField would incorrect change the label color. Now it does not, which is correct per the spec.
This commit is contained in:
parent
7db26b09bb
commit
58ac0dc16b
@ -21,6 +21,16 @@ class _${blockName}DefaultsM3 extends InputDecorationTheme {
|
|||||||
late final ColorScheme _colors = Theme.of(context).colorScheme;
|
late final ColorScheme _colors = Theme.of(context).colorScheme;
|
||||||
late final TextTheme _textTheme = Theme.of(context).textTheme;
|
late final TextTheme _textTheme = Theme.of(context).textTheme;
|
||||||
|
|
||||||
|
// For InputDecorator, focused state should take precedence over hovered state.
|
||||||
|
// For instance, the focused state increases border width (2dp) and applies bright
|
||||||
|
// colors (primary color or error color) while the hovered state has the same border
|
||||||
|
// than the non-focused state (1dp) and uses a color a little darker than non-focused
|
||||||
|
// state. On desktop, it is also very common that a text field is focused and hovered
|
||||||
|
// because users often rely on mouse selection.
|
||||||
|
// For other widgets, hovered state takes precedence over focused state, because it
|
||||||
|
// is mainly used to determine the overlay color,
|
||||||
|
// see https://github.com/flutter/flutter/pull/125905.
|
||||||
|
|
||||||
@override
|
@override
|
||||||
TextStyle? get hintStyle => MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
|
TextStyle? get hintStyle => MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(MaterialState.disabled)) {
|
||||||
@ -139,20 +149,20 @@ class _${blockName}DefaultsM3 extends InputDecorationTheme {
|
|||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.disabled.label-text')});
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.disabled.label-text')});
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.error)) {
|
if (states.contains(MaterialState.error)) {
|
||||||
if (states.contains(MaterialState.hovered)) {
|
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.error.hover.label-text')});
|
|
||||||
}
|
|
||||||
if (states.contains(MaterialState.focused)) {
|
if (states.contains(MaterialState.focused)) {
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.error.focus.label-text')});
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.error.focus.label-text')});
|
||||||
}
|
}
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.error.label-text')});
|
|
||||||
}
|
|
||||||
if (states.contains(MaterialState.hovered)) {
|
if (states.contains(MaterialState.hovered)) {
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.hover.label-text')});
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.error.hover.label-text')});
|
||||||
|
}
|
||||||
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.error.label-text')});
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.focused)) {
|
if (states.contains(MaterialState.focused)) {
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.focus.label-text')});
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.focus.label-text')});
|
||||||
}
|
}
|
||||||
|
if (states.contains(MaterialState.hovered)) {
|
||||||
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.hover.label-text')});
|
||||||
|
}
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.label-text')});
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.label-text')});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -163,20 +173,20 @@ class _${blockName}DefaultsM3 extends InputDecorationTheme {
|
|||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.disabled.label-text')});
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.disabled.label-text')});
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.error)) {
|
if (states.contains(MaterialState.error)) {
|
||||||
if (states.contains(MaterialState.hovered)) {
|
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.error.hover.label-text')});
|
|
||||||
}
|
|
||||||
if (states.contains(MaterialState.focused)) {
|
if (states.contains(MaterialState.focused)) {
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.error.focus.label-text')});
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.error.focus.label-text')});
|
||||||
}
|
}
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.error.label-text')});
|
|
||||||
}
|
|
||||||
if (states.contains(MaterialState.hovered)) {
|
if (states.contains(MaterialState.hovered)) {
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.hover.label-text')});
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.error.hover.label-text')});
|
||||||
|
}
|
||||||
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.error.label-text')});
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.focused)) {
|
if (states.contains(MaterialState.focused)) {
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.focus.label-text')});
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.focus.label-text')});
|
||||||
}
|
}
|
||||||
|
if (states.contains(MaterialState.hovered)) {
|
||||||
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.hover.label-text')});
|
||||||
|
}
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.label-text')});
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.label-text')});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -185,12 +195,12 @@ class _${blockName}DefaultsM3 extends InputDecorationTheme {
|
|||||||
final TextStyle textStyle = ${textStyle("md.comp.filled-text-field.supporting-text")} ?? const TextStyle();
|
final TextStyle textStyle = ${textStyle("md.comp.filled-text-field.supporting-text")} ?? const TextStyle();
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(MaterialState.disabled)) {
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.disabled.supporting-text')});
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.disabled.supporting-text')});
|
||||||
}${componentColor('md.comp.filled-text-field.hover.supporting-text') == componentColor('md.comp.filled-text-field.supporting-text') ? '' : '''
|
}${componentColor('md.comp.filled-text-field.focus.supporting-text') == componentColor('md.comp.filled-text-field.supporting-text') ? '' : '''
|
||||||
if (states.contains(MaterialState.hovered)) {
|
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.hover.supporting-text')});
|
|
||||||
}'''}${componentColor('md.comp.filled-text-field.focus.supporting-text') == componentColor('md.comp.filled-text-field.supporting-text') ? '' : '''
|
|
||||||
if (states.contains(MaterialState.focused)) {
|
if (states.contains(MaterialState.focused)) {
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.focus.supporting-text')});
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.focus.supporting-text')});
|
||||||
|
}'''}${componentColor('md.comp.filled-text-field.hover.supporting-text') == componentColor('md.comp.filled-text-field.supporting-text') ? '' : '''
|
||||||
|
if (states.contains(MaterialState.hovered)) {
|
||||||
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.hover.supporting-text')});
|
||||||
}'''}
|
}'''}
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.supporting-text')});
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.supporting-text')});
|
||||||
});
|
});
|
||||||
@ -198,11 +208,11 @@ class _${blockName}DefaultsM3 extends InputDecorationTheme {
|
|||||||
@override
|
@override
|
||||||
TextStyle? get errorStyle => MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
|
TextStyle? get errorStyle => MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
|
||||||
final TextStyle textStyle = ${textStyle("md.comp.filled-text-field.supporting-text")} ?? const TextStyle();${componentColor('md.comp.filled-text-field.error.hover.supporting-text') == componentColor('md.comp.filled-text-field.error.supporting-text') ? '' : '''
|
final TextStyle textStyle = ${textStyle("md.comp.filled-text-field.supporting-text")} ?? const TextStyle();${componentColor('md.comp.filled-text-field.error.hover.supporting-text') == componentColor('md.comp.filled-text-field.error.supporting-text') ? '' : '''
|
||||||
if (states.contains(MaterialState.hovered)) {
|
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.error.hover.supporting-text')});
|
|
||||||
}'''}${componentColor('md.comp.filled-text-field.error.focus.supporting-text') == componentColor('md.comp.filled-text-field.error.supporting-text') ? '' : '''
|
|
||||||
if (states.contains(MaterialState.focused)) {
|
if (states.contains(MaterialState.focused)) {
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.error.focus.supporting-text')});
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.error.focus.supporting-text')});
|
||||||
|
}'''}${componentColor('md.comp.filled-text-field.error.focus.supporting-text') == componentColor('md.comp.filled-text-field.error.supporting-text') ? '' : '''
|
||||||
|
if (states.contains(MaterialState.hovered)) {
|
||||||
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.error.hover.supporting-text')});
|
||||||
}'''}
|
}'''}
|
||||||
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.error.supporting-text')});
|
return textStyle.copyWith(color: ${componentColor('md.comp.filled-text-field.error.supporting-text')});
|
||||||
});
|
});
|
||||||
|
@ -4617,6 +4617,16 @@ class _InputDecoratorDefaultsM3 extends InputDecorationTheme {
|
|||||||
late final ColorScheme _colors = Theme.of(context).colorScheme;
|
late final ColorScheme _colors = Theme.of(context).colorScheme;
|
||||||
late final TextTheme _textTheme = Theme.of(context).textTheme;
|
late final TextTheme _textTheme = Theme.of(context).textTheme;
|
||||||
|
|
||||||
|
// For InputDecorator, focused state should take precedence over hovered state.
|
||||||
|
// For instance, the focused state increases border width (2dp) and applies bright
|
||||||
|
// colors (primary color or error color) while the hovered state has the same border
|
||||||
|
// than the non-focused state (1dp) and uses a color a little darker than non-focused
|
||||||
|
// state. On desktop, it is also very common that a text field is focused and hovered
|
||||||
|
// because users often rely on mouse selection.
|
||||||
|
// For other widgets, hovered state takes precedence over focused state, because it
|
||||||
|
// is mainly used to determine the overlay color,
|
||||||
|
// see https://github.com/flutter/flutter/pull/125905.
|
||||||
|
|
||||||
@override
|
@override
|
||||||
TextStyle? get hintStyle => MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
|
TextStyle? get hintStyle => MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
|
||||||
if (states.contains(MaterialState.disabled)) {
|
if (states.contains(MaterialState.disabled)) {
|
||||||
@ -4705,20 +4715,20 @@ class _InputDecoratorDefaultsM3 extends InputDecorationTheme {
|
|||||||
return textStyle.copyWith(color: _colors.onSurface.withOpacity(0.38));
|
return textStyle.copyWith(color: _colors.onSurface.withOpacity(0.38));
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.error)) {
|
if (states.contains(MaterialState.error)) {
|
||||||
|
if (states.contains(MaterialState.focused)) {
|
||||||
|
return textStyle.copyWith(color: _colors.error);
|
||||||
|
}
|
||||||
if (states.contains(MaterialState.hovered)) {
|
if (states.contains(MaterialState.hovered)) {
|
||||||
return textStyle.copyWith(color: _colors.onErrorContainer);
|
return textStyle.copyWith(color: _colors.onErrorContainer);
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.focused)) {
|
|
||||||
return textStyle.copyWith(color: _colors.error);
|
return textStyle.copyWith(color: _colors.error);
|
||||||
}
|
}
|
||||||
return textStyle.copyWith(color: _colors.error);
|
|
||||||
}
|
|
||||||
if (states.contains(MaterialState.hovered)) {
|
|
||||||
return textStyle.copyWith(color: _colors.onSurfaceVariant);
|
|
||||||
}
|
|
||||||
if (states.contains(MaterialState.focused)) {
|
if (states.contains(MaterialState.focused)) {
|
||||||
return textStyle.copyWith(color: _colors.primary);
|
return textStyle.copyWith(color: _colors.primary);
|
||||||
}
|
}
|
||||||
|
if (states.contains(MaterialState.hovered)) {
|
||||||
|
return textStyle.copyWith(color: _colors.onSurfaceVariant);
|
||||||
|
}
|
||||||
return textStyle.copyWith(color: _colors.onSurfaceVariant);
|
return textStyle.copyWith(color: _colors.onSurfaceVariant);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -4729,20 +4739,20 @@ class _InputDecoratorDefaultsM3 extends InputDecorationTheme {
|
|||||||
return textStyle.copyWith(color: _colors.onSurface.withOpacity(0.38));
|
return textStyle.copyWith(color: _colors.onSurface.withOpacity(0.38));
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.error)) {
|
if (states.contains(MaterialState.error)) {
|
||||||
|
if (states.contains(MaterialState.focused)) {
|
||||||
|
return textStyle.copyWith(color: _colors.error);
|
||||||
|
}
|
||||||
if (states.contains(MaterialState.hovered)) {
|
if (states.contains(MaterialState.hovered)) {
|
||||||
return textStyle.copyWith(color: _colors.onErrorContainer);
|
return textStyle.copyWith(color: _colors.onErrorContainer);
|
||||||
}
|
}
|
||||||
if (states.contains(MaterialState.focused)) {
|
|
||||||
return textStyle.copyWith(color: _colors.error);
|
return textStyle.copyWith(color: _colors.error);
|
||||||
}
|
}
|
||||||
return textStyle.copyWith(color: _colors.error);
|
|
||||||
}
|
|
||||||
if (states.contains(MaterialState.hovered)) {
|
|
||||||
return textStyle.copyWith(color: _colors.onSurfaceVariant);
|
|
||||||
}
|
|
||||||
if (states.contains(MaterialState.focused)) {
|
if (states.contains(MaterialState.focused)) {
|
||||||
return textStyle.copyWith(color: _colors.primary);
|
return textStyle.copyWith(color: _colors.primary);
|
||||||
}
|
}
|
||||||
|
if (states.contains(MaterialState.hovered)) {
|
||||||
|
return textStyle.copyWith(color: _colors.onSurfaceVariant);
|
||||||
|
}
|
||||||
return textStyle.copyWith(color: _colors.onSurfaceVariant);
|
return textStyle.copyWith(color: _colors.onSurfaceVariant);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1634,6 +1634,328 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group('Material3 - InputDecoration label', () {
|
||||||
|
group('for filled text field', () {
|
||||||
|
group('when field is enabled', () {
|
||||||
|
testWidgets('label text has correct style', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
filled: true,
|
||||||
|
labelText: labelText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(tester.element(findDecorator()));
|
||||||
|
final Color expectedColor = theme.colorScheme.onSurfaceVariant;
|
||||||
|
// Current input decorator implementation forces line height to 1.0,
|
||||||
|
// this is not compliant with M3 spec.
|
||||||
|
final TextStyle expectedStyle = theme.textTheme.bodyLarge!.copyWith(color: expectedColor, height: 1.0);
|
||||||
|
expect(getLabelStyle(tester), expectedStyle);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('when field is disabled', () {
|
||||||
|
testWidgets('label text has correct color', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
filled: true,
|
||||||
|
enabled: false,
|
||||||
|
labelText: labelText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(tester.element(findDecorator()));
|
||||||
|
expect(getLabelStyle(tester).color, theme.colorScheme.onSurface.withOpacity(0.38));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('when field is hovered', () {
|
||||||
|
testWidgets('label text has correct color', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
isHovering: true,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
filled: true,
|
||||||
|
labelText: labelText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(tester.element(findDecorator()));
|
||||||
|
expect(getLabelStyle(tester).color, theme.colorScheme.onSurfaceVariant);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('when field is focused', () {
|
||||||
|
testWidgets('label text has correct color', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
isFocused: true,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
filled: true,
|
||||||
|
labelText: labelText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(tester.element(findDecorator()));
|
||||||
|
expect(getLabelStyle(tester).color, theme.colorScheme.primary);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('label text has correct color when focused and hovered', (WidgetTester tester) async {
|
||||||
|
// Regression test for https://github.com/flutter/flutter/issues/146565.
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
isFocused: true,
|
||||||
|
isHovering: true,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
filled: true,
|
||||||
|
labelText: labelText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(tester.element(findDecorator()));
|
||||||
|
expect(getLabelStyle(tester).color, theme.colorScheme.primary);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('when field is in error', () {
|
||||||
|
testWidgets('label text has correct color', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
filled: true,
|
||||||
|
labelText: labelText,
|
||||||
|
errorText: errorText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(tester.element(findDecorator()));
|
||||||
|
expect(getLabelStyle(tester).color, theme.colorScheme.error);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('label text has correct color when focused', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
isFocused: true,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
filled: true,
|
||||||
|
labelText: labelText,
|
||||||
|
errorText: errorText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(tester.element(findDecorator()));
|
||||||
|
expect(getLabelStyle(tester).color, theme.colorScheme.error);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('label text has correct style when hovered', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
isHovering: true,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
filled: true,
|
||||||
|
labelText: labelText,
|
||||||
|
errorText: errorText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(tester.element(findDecorator()));
|
||||||
|
expect(getLabelStyle(tester).color, theme.colorScheme.onErrorContainer);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('label text has correct style when focused and hovered', (WidgetTester tester) async {
|
||||||
|
// Regression test for https://github.com/flutter/flutter/issues/146565.
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
isFocused: true,
|
||||||
|
isHovering: true,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
filled: true,
|
||||||
|
labelText: labelText,
|
||||||
|
errorText: errorText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(tester.element(findDecorator()));
|
||||||
|
expect(getLabelStyle(tester).color, theme.colorScheme.error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('for outlined text field', () {
|
||||||
|
group('when field is enabled', () {
|
||||||
|
testWidgets('label text has correct style', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: labelText,
|
||||||
|
helperText: helperText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(tester.element(findDecorator()));
|
||||||
|
final Color expectedColor = theme.colorScheme.onSurfaceVariant;
|
||||||
|
// Current input decorator implementation forces line height to 1.0,
|
||||||
|
// this is not compliant with M3 spec.
|
||||||
|
final TextStyle expectedStyle = theme.textTheme.bodyLarge!.copyWith(color: expectedColor, height: 1.0);
|
||||||
|
expect(getLabelStyle(tester), expectedStyle);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('when field is disabled', () {
|
||||||
|
testWidgets('label text has correct color', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
enabled: false,
|
||||||
|
labelText: labelText,
|
||||||
|
helperText: helperText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(tester.element(findDecorator()));
|
||||||
|
expect(getLabelStyle(tester).color, theme.colorScheme.onSurface.withOpacity(0.38));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('when field is hovered', () {
|
||||||
|
testWidgets('label text has correct color', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
isHovering: true,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: labelText,
|
||||||
|
helperText: helperText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(tester.element(findDecorator()));
|
||||||
|
expect(getLabelStyle(tester).color, theme.colorScheme.onSurfaceVariant);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('when field is focused', () {
|
||||||
|
testWidgets('label text has correct color', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
isFocused: true,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: labelText,
|
||||||
|
helperText: helperText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(tester.element(findDecorator()));
|
||||||
|
expect(getLabelStyle(tester).color, theme.colorScheme.primary);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
testWidgets('label text has correct color when focused and hovered', (WidgetTester tester) async {
|
||||||
|
// Regression test for https://github.com/flutter/flutter/issues/146565.
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
isFocused: true,
|
||||||
|
isHovering: true,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: labelText,
|
||||||
|
helperText: helperText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(tester.element(findDecorator()));
|
||||||
|
expect(getLabelStyle(tester).color, theme.colorScheme.primary);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('when field is in error', () {
|
||||||
|
testWidgets('label text has correct color', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: labelText,
|
||||||
|
errorText: errorText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(tester.element(findDecorator()));
|
||||||
|
expect(getLabelStyle(tester).color, theme.colorScheme.error);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('label text has correct color when focused', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
isFocused: true,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: labelText,
|
||||||
|
errorText: errorText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(tester.element(findDecorator()));
|
||||||
|
expect(getLabelStyle(tester).color, theme.colorScheme.error);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('label text has correct color when hovered', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
isHovering: true,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: labelText,
|
||||||
|
errorText: errorText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(tester.element(findDecorator()));
|
||||||
|
expect(getLabelStyle(tester).color, theme.colorScheme.onErrorContainer);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('label text has correct color when focused and hovered', (WidgetTester tester) async {
|
||||||
|
// Regression test for https://github.com/flutter/flutter/issues/146565.
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildInputDecorator(
|
||||||
|
isFocused: true,
|
||||||
|
isHovering: true,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: labelText,
|
||||||
|
errorText: errorText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final ThemeData theme = Theme.of(tester.element(findDecorator()));
|
||||||
|
expect(getLabelStyle(tester).color, theme.colorScheme.error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
group('Material3 - InputDecoration labelText layout', () {
|
group('Material3 - InputDecoration labelText layout', () {
|
||||||
testWidgets('The label appears above input', (WidgetTester tester) async {
|
testWidgets('The label appears above input', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
@ -3957,40 +4279,6 @@ void main() {
|
|||||||
expect(getIconStyle(tester, Icons.close)?.color, theme.colorScheme.error);
|
expect(getIconStyle(tester, Icons.close)?.color, theme.colorScheme.error);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('InputDecoration default floatingLabelStyle resolves hovered/focused states', (WidgetTester tester) async {
|
|
||||||
final FocusNode focusNode = FocusNode();
|
|
||||||
addTearDown(focusNode.dispose);
|
|
||||||
|
|
||||||
await tester.pumpWidget(
|
|
||||||
MaterialApp(
|
|
||||||
home: Material(
|
|
||||||
child: TextField(
|
|
||||||
focusNode: focusNode,
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
labelText: 'label',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Focused.
|
|
||||||
focusNode.requestFocus();
|
|
||||||
await tester.pump(kTransitionDuration);
|
|
||||||
final ThemeData theme = Theme.of(tester.element(find.byType(TextField)));
|
|
||||||
expect(getLabelStyle(tester).color, theme.colorScheme.primary);
|
|
||||||
|
|
||||||
// Hovered.
|
|
||||||
final Offset center = tester.getCenter(find.byType(TextField));
|
|
||||||
final TestGesture gesture = await tester.createGesture(
|
|
||||||
kind: PointerDeviceKind.mouse,
|
|
||||||
);
|
|
||||||
await gesture.addPointer();
|
|
||||||
await gesture.moveTo(center);
|
|
||||||
await tester.pump(kTransitionDuration);
|
|
||||||
expect(getLabelStyle(tester).color, theme.colorScheme.onSurfaceVariant);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('FloatingLabelAlignment.toString()', (WidgetTester tester) async {
|
testWidgets('FloatingLabelAlignment.toString()', (WidgetTester tester) async {
|
||||||
expect(FloatingLabelAlignment.start.toString(), 'FloatingLabelAlignment.start');
|
expect(FloatingLabelAlignment.start.toString(), 'FloatingLabelAlignment.start');
|
||||||
expect(FloatingLabelAlignment.center.toString(), 'FloatingLabelAlignment.center');
|
expect(FloatingLabelAlignment.center.toString(), 'FloatingLabelAlignment.center');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user