From e739ad0782a49d550bcc0a1e3b113ee9969c8b4a Mon Sep 17 00:00:00 2001 From: hangyu Date: Wed, 26 Oct 2022 16:32:58 +0800 Subject: [PATCH] M3 Text field UI update (#113776) * text field update * update tests * lint * polish template --- .../lib/input_decorator_template.dart | 110 ++++++++++-------- dev/tools/gen_defaults/lib/template.dart | 7 +- .../lib/src/material/input_decorator.dart | 42 ++++--- .../test/material/input_decorator_test.dart | 2 +- 4 files changed, 91 insertions(+), 70 deletions(-) diff --git a/dev/tools/gen_defaults/lib/input_decorator_template.dart b/dev/tools/gen_defaults/lib/input_decorator_template.dart index efe3129e9aa..5c0260997ad 100644 --- a/dev/tools/gen_defaults/lib/input_decorator_template.dart +++ b/dev/tools/gen_defaults/lib/input_decorator_template.dart @@ -41,20 +41,20 @@ class _${blockName}DefaultsM3 extends InputDecorationTheme { @override BorderSide? get activeIndicatorBorder => MaterialStateBorderSide.resolveWith((Set states) { if (states.contains(MaterialState.error)) { + if (states.contains(MaterialState.focused)) { + return ${mergedBorder('md.comp.filled-text-field.error.focus.active-indicator','md.comp.filled-text-field.focus.active-indicator')}; + } if (states.contains(MaterialState.hovered)) { return ${border('md.comp.filled-text-field.error.hover.active-indicator')}; - }${border('md.comp.filled-text-field.error.focus.active-indicator') == border('md.comp.filled-text-field.error.active-indicator') ? '' : ''' - if (states.contains(MaterialState.focused)) { - return ${border('md.comp.filled-text-field.error.focus.active-indicator')}; - }'''} + } return ${border('md.comp.filled-text-field.error.active-indicator')}; } - if (states.contains(MaterialState.hovered)) { - return ${border('md.comp.filled-text-field.hover.active-indicator')}; - } if (states.contains(MaterialState.focused)) { return ${border('md.comp.filled-text-field.focus.active-indicator')}; } + if (states.contains(MaterialState.hovered)) { + return ${border('md.comp.filled-text-field.hover.active-indicator')}; + } if (states.contains(MaterialState.disabled)) { return ${border('md.comp.filled-text-field.disabled.active-indicator')}; } @@ -64,20 +64,20 @@ class _${blockName}DefaultsM3 extends InputDecorationTheme { @override BorderSide? get outlineBorder => MaterialStateBorderSide.resolveWith((Set states) { if (states.contains(MaterialState.error)) { + if (states.contains(MaterialState.focused)) { + return ${mergedBorder('md.comp.outlined-text-field.error.focus.outline','md.comp.outlined-text-field.focus.outline')}; + } if (states.contains(MaterialState.hovered)) { return ${border('md.comp.outlined-text-field.error.hover.outline')}; - }${border('md.comp.outlined-text-field.error.focus.outline') == border('md.comp.outlined-text-field.error.outline') ? '' : ''' - if (states.contains(MaterialState.focused)) { - return ${border('md.comp.outlined-text-field.error.focus.outline')}; - }'''} + } return ${border('md.comp.outlined-text-field.error.outline')}; } - if (states.contains(MaterialState.hovered)) { - return ${border('md.comp.outlined-text-field.hover.outline')}; - } if (states.contains(MaterialState.focused)) { return ${border('md.comp.outlined-text-field.focus.outline')}; } + if (states.contains(MaterialState.hovered)) { + return ${border('md.comp.outlined-text-field.hover.outline')}; + } if (states.contains(MaterialState.disabled)) { return ${border('md.comp.outlined-text-field.disabled.outline')}; } @@ -90,19 +90,19 @@ class _${blockName}DefaultsM3 extends InputDecorationTheme { @override Color? get prefixIconColor => MaterialStateColor.resolveWith((Set states) {${componentColor('md.comp.filled-text-field.error.leading-icon') == componentColor('md.comp.filled-text-field.leading-icon') ? '' : ''' if(states.contains(MaterialState.error)) { - if (states.contains(MaterialState.hovered)) { - return ${componentColor('md.comp.filled-text-field.error.hover.leading-icon')}; - } if (states.contains(MaterialState.focused)) { return ${componentColor('md.comp.filled-text-field.error.focus.leading-icon')}; } + if (states.contains(MaterialState.hovered)) { + return ${componentColor('md.comp.filled-text-field.error.hover.leading-icon')}; + } return ${componentColor('md.comp.filled-text-field.error.leading-icon')}; - }'''}${componentColor('md.comp.filled-text-field.hover.leading-icon') == componentColor('md.comp.filled-text-field.leading-icon') ? '' : ''' - if (states.contains(MaterialState.hovered)) { - return ${componentColor('md.comp.filled-text-field.hover.leading-icon')}; }'''}${componentColor('md.comp.filled-text-field.focus.leading-icon') == componentColor('md.comp.filled-text-field.leading-icon') ? '' : ''' if (states.contains(MaterialState.focused)) { return ${componentColor('md.comp.filled-text-field.focus.leading-icon')}; + }'''}${componentColor('md.comp.filled-text-field.hover.leading-icon') == componentColor('md.comp.filled-text-field.leading-icon') ? '' : ''' + if (states.contains(MaterialState.hovered)) { + return ${componentColor('md.comp.filled-text-field.hover.leading-icon')}; }'''} if (states.contains(MaterialState.disabled)) { return ${componentColor('md.comp.filled-text-field.disabled.leading-icon')}; @@ -112,20 +112,20 @@ class _${blockName}DefaultsM3 extends InputDecorationTheme { @override Color? get suffixIconColor => MaterialStateColor.resolveWith((Set states) { - if(states.contains(MaterialState.error)) { - if (states.contains(MaterialState.hovered)) { - return ${componentColor('md.comp.filled-text-field.error.hover.trailing-icon')}; - }${componentColor('md.comp.filled-text-field.error.trailing-icon') == componentColor('md.comp.filled-text-field.error.focus.trailing-icon') ? '' : ''' + if(states.contains(MaterialState.error)) {${componentColor('md.comp.filled-text-field.error.trailing-icon') == componentColor('md.comp.filled-text-field.error.focus.trailing-icon') ? '' : ''' if (states.contains(MaterialState.focused)) { return ${componentColor('md.comp.filled-text-field.error.focus.trailing-icon')}; }'''} + if (states.contains(MaterialState.hovered)) { + return ${componentColor('md.comp.filled-text-field.error.hover.trailing-icon')}; + } return ${componentColor('md.comp.filled-text-field.error.trailing-icon')}; - }${componentColor('md.comp.filled-text-field.hover.trailing-icon') == componentColor('md.comp.filled-text-field.trailing-icon') ? '' : ''' - if (states.contains(MaterialState.hovered)) { - return ${componentColor('md.comp.filled-text-field.hover.trailing-icon')}; - }'''}${componentColor('md.comp.filled-text-field.focus.trailing-icon') == componentColor('md.comp.filled-text-field.trailing-icon') ? '' : ''' + }${componentColor('md.comp.filled-text-field.focus.trailing-icon') == componentColor('md.comp.filled-text-field.trailing-icon') ? '' : ''' if (states.contains(MaterialState.focused)) { return ${componentColor('md.comp.filled-text-field.focus.trailing-icon')}; + }'''}${componentColor('md.comp.filled-text-field.hover.trailing-icon') == componentColor('md.comp.filled-text-field.trailing-icon') ? '' : ''' + if (states.contains(MaterialState.hovered)) { + return ${componentColor('md.comp.filled-text-field.hover.trailing-icon')}; }'''} if (states.contains(MaterialState.disabled)) { return ${componentColor('md.comp.filled-text-field.disabled.trailing-icon')}; @@ -137,20 +137,20 @@ class _${blockName}DefaultsM3 extends InputDecorationTheme { TextStyle? get labelStyle => MaterialStateTextStyle.resolveWith((Set states) { final TextStyle textStyle= ${textStyle("md.comp.filled-text-field.label-text")} ?? const TextStyle(); 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)) { return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.error.focus.label-text')}); } + if (states.contains(MaterialState.hovered)) { + 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.hovered)) { - return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.hover.label-text')}); - } if (states.contains(MaterialState.focused)) { 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')}); + } if (states.contains(MaterialState.disabled)) { return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.disabled.label-text')}); } @@ -161,20 +161,20 @@ class _${blockName}DefaultsM3 extends InputDecorationTheme { TextStyle? get floatingLabelStyle => MaterialStateTextStyle.resolveWith((Set states) { final TextStyle textStyle= ${textStyle("md.comp.filled-text-field.label-text")} ?? const TextStyle(); 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)) { return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.error.focus.label-text')}); } + if (states.contains(MaterialState.hovered)) { + 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.hovered)) { - return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.hover.label-text')}); - } if (states.contains(MaterialState.focused)) { 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')}); + } if (states.contains(MaterialState.disabled)) { return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.disabled.label-text')}); } @@ -183,12 +183,12 @@ class _${blockName}DefaultsM3 extends InputDecorationTheme { @override TextStyle? get helperStyle => MaterialStateTextStyle.resolveWith((Set states) { - final TextStyle textStyle= ${textStyle("md.comp.filled-text-field.supporting-text")} ?? const TextStyle();${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')}); - }'''}${componentColor('md.comp.filled-text-field.focus.supporting-text') == componentColor('md.comp.filled-text-field.supporting-text') ? '' : ''' + final TextStyle textStyle= ${textStyle("md.comp.filled-text-field.supporting-text")} ?? const TextStyle();${componentColor('md.comp.filled-text-field.focus.supporting-text') == componentColor('md.comp.filled-text-field.supporting-text') ? '' : ''' if (states.contains(MaterialState.focused)) { 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')}); }'''} if (states.contains(MaterialState.disabled)) { return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.disabled.supporting-text')}); @@ -198,15 +198,29 @@ class _${blockName}DefaultsM3 extends InputDecorationTheme { @override TextStyle? get errorStyle => MaterialStateTextStyle.resolveWith((Set 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') ? '' : ''' - 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') ? '' : ''' + final TextStyle textStyle= ${textStyle("md.comp.filled-text-field.supporting-text")} ?? const TextStyle();${componentColor('md.comp.filled-text-field.error.focus.supporting-text') == componentColor('md.comp.filled-text-field.error.supporting-text') ? '' : ''' if (states.contains(MaterialState.focused)) { return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.error.focus.supporting-text')}); + }'''}${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')}); }'''} return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.error.supporting-text')}); }); } '''; + + /// Generate a [BorderSide] for the given components. + String mergedBorder(String componentToken1, String componentToken2) { + final String borderColor = componentColor(componentToken1)!= 'null' + ? componentColor(componentToken1) + : componentColor(componentToken2); + final double width = ( + tokens['$componentToken1.width'] ?? + tokens['$componentToken1.height'] ?? + tokens['$componentToken2.width'] ?? + tokens['$componentToken2.height'] ?? + 1.0) as double; + return 'BorderSide(color: $borderColor${width != 1.0 ? ", width: $width" : ""})'; + } } diff --git a/dev/tools/gen_defaults/lib/template.dart b/dev/tools/gen_defaults/lib/template.dart index 093688747a1..807c6c5bba1 100644 --- a/dev/tools/gen_defaults/lib/template.dart +++ b/dev/tools/gen_defaults/lib/template.dart @@ -179,8 +179,9 @@ abstract class TokenTemplate { } if (topLeft == topRight && bottomLeft == bottomRight) { return '${prefix}RoundedRectangleBorder(borderRadius: BorderRadius.vertical(' - '${topLeft > 0 ? 'top: Radius.circular($topLeft),':''}' - '${bottomLeft > 0 ? 'bottom: Radius.circular($bottomLeft),':''}' + '${topLeft > 0 ? 'top: Radius.circular($topLeft)':''}' + '${topLeft > 0 && bottomLeft > 0 ? ',':''}' + '${bottomLeft > 0 ? 'bottom: Radius.circular($bottomLeft)':''}' '))'; } return '${prefix}RoundedRectangleBorder(borderRadius: ' @@ -202,7 +203,7 @@ abstract class TokenTemplate { return 'null'; } final String borderColor = componentColor(componentToken); - final double width = (tokens['$componentToken.width'] ?? 1.0) as double; + final double width = (tokens['$componentToken.width'] ?? tokens['$componentToken.height'] ?? 1.0) as double; return 'BorderSide(color: $borderColor${width != 1.0 ? ", width: $width" : ""})'; } diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index 98b5efa7276..9bdedc87872 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -4494,17 +4494,20 @@ class _InputDecoratorDefaultsM3 extends InputDecorationTheme { @override BorderSide? get activeIndicatorBorder => MaterialStateBorderSide.resolveWith((Set states) { if (states.contains(MaterialState.error)) { + if (states.contains(MaterialState.focused)) { + return BorderSide(color: _colors.error, width: 2.0); + } if (states.contains(MaterialState.hovered)) { return BorderSide(color: _colors.onErrorContainer); } return BorderSide(color: _colors.error); } + if (states.contains(MaterialState.focused)) { + return BorderSide(color: _colors.primary, width: 2.0); + } if (states.contains(MaterialState.hovered)) { return BorderSide(color: _colors.onSurface); } - if (states.contains(MaterialState.focused)) { - return BorderSide(color: _colors.primary); - } if (states.contains(MaterialState.disabled)) { return BorderSide(color: _colors.onSurface.withOpacity(0.38)); } @@ -4514,17 +4517,20 @@ class _InputDecoratorDefaultsM3 extends InputDecorationTheme { @override BorderSide? get outlineBorder => MaterialStateBorderSide.resolveWith((Set states) { if (states.contains(MaterialState.error)) { + if (states.contains(MaterialState.focused)) { + return BorderSide(color: _colors.error, width: 2.0); + } if (states.contains(MaterialState.hovered)) { return BorderSide(color: _colors.onErrorContainer); } return BorderSide(color: _colors.error); } - if (states.contains(MaterialState.hovered)) { - return BorderSide(color: _colors.onSurface); - } if (states.contains(MaterialState.focused)) { return BorderSide(color: _colors.primary, width: 2.0); } + if (states.contains(MaterialState.hovered)) { + return BorderSide(color: _colors.onSurface); + } if (states.contains(MaterialState.disabled)) { return BorderSide(color: _colors.onSurface.withOpacity(0.12)); } @@ -4560,20 +4566,20 @@ class _InputDecoratorDefaultsM3 extends InputDecorationTheme { TextStyle? get labelStyle => MaterialStateTextStyle.resolveWith((Set states) { final TextStyle textStyle= _textTheme.bodyLarge ?? const TextStyle(); if(states.contains(MaterialState.error)) { - if (states.contains(MaterialState.hovered)) { - return textStyle.copyWith(color:_colors.onErrorContainer); - } if (states.contains(MaterialState.focused)) { return textStyle.copyWith(color:_colors.error); } + if (states.contains(MaterialState.hovered)) { + return textStyle.copyWith(color:_colors.onErrorContainer); + } return textStyle.copyWith(color:_colors.error); } - if (states.contains(MaterialState.hovered)) { - return textStyle.copyWith(color:_colors.onSurfaceVariant); - } if (states.contains(MaterialState.focused)) { return textStyle.copyWith(color:_colors.primary); } + if (states.contains(MaterialState.hovered)) { + return textStyle.copyWith(color:_colors.onSurfaceVariant); + } if (states.contains(MaterialState.disabled)) { return textStyle.copyWith(color:_colors.onSurface.withOpacity(0.38)); } @@ -4584,20 +4590,20 @@ class _InputDecoratorDefaultsM3 extends InputDecorationTheme { TextStyle? get floatingLabelStyle => MaterialStateTextStyle.resolveWith((Set states) { final TextStyle textStyle= _textTheme.bodyLarge ?? const TextStyle(); if(states.contains(MaterialState.error)) { - if (states.contains(MaterialState.hovered)) { - return textStyle.copyWith(color:_colors.onErrorContainer); - } if (states.contains(MaterialState.focused)) { return textStyle.copyWith(color:_colors.error); } + if (states.contains(MaterialState.hovered)) { + return textStyle.copyWith(color:_colors.onErrorContainer); + } return textStyle.copyWith(color:_colors.error); } - if (states.contains(MaterialState.hovered)) { - return textStyle.copyWith(color:_colors.onSurfaceVariant); - } if (states.contains(MaterialState.focused)) { return textStyle.copyWith(color:_colors.primary); } + if (states.contains(MaterialState.hovered)) { + return textStyle.copyWith(color:_colors.onSurfaceVariant); + } if (states.contains(MaterialState.disabled)) { return textStyle.copyWith(color:_colors.onSurface.withOpacity(0.38)); } diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart index 32a174bd084..a9e9201dec2 100644 --- a/packages/flutter/test/material/input_decorator_test.dart +++ b/packages/flutter/test/material/input_decorator_test.dart @@ -3453,7 +3453,7 @@ void main() { expect(tester.getTopRight(find.text('text')).dx, lessThanOrEqualTo(tester.getTopLeft(find.text('s')).dx)); expect(getBorderBottom(tester), 32.0); - expect(getBorderWeight(tester), useMaterial3 ? 1.0 : 2.0); + expect(getBorderWeight(tester), 2.0); }); testWidgets('InputDecorator with empty InputDecoration', (WidgetTester tester) async {