From dd4154bf4d1d576f465dc03eaffb13fab73fcead Mon Sep 17 00:00:00 2001 From: hangyu Date: Thu, 28 Jul 2022 20:31:05 +0800 Subject: [PATCH] Migrate TextField to Material 3 (#108366) * Update input style * generate M3 text style * Add test --- dev/tools/gen_defaults/bin/gen_defaults.dart | 2 + .../gen_defaults/lib/text_field_template.dart | 16 ++++++ .../flutter/lib/src/material/text_field.dart | 17 ++++++- .../test/material/text_field_test.dart | 51 +++++++++++++++++++ 4 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 dev/tools/gen_defaults/lib/text_field_template.dart diff --git a/dev/tools/gen_defaults/bin/gen_defaults.dart b/dev/tools/gen_defaults/bin/gen_defaults.dart index 80663a44810..7651bfdc944 100644 --- a/dev/tools/gen_defaults/bin/gen_defaults.dart +++ b/dev/tools/gen_defaults/bin/gen_defaults.dart @@ -30,6 +30,7 @@ import 'package:gen_defaults/input_decorator_template.dart'; import 'package:gen_defaults/navigation_bar_template.dart'; import 'package:gen_defaults/navigation_rail_template.dart'; import 'package:gen_defaults/surface_tint.dart'; +import 'package:gen_defaults/text_field_template.dart'; import 'package:gen_defaults/typography_template.dart'; Map _readTokenFile(String fileName) { @@ -116,5 +117,6 @@ Future main(List args) async { NavigationBarTemplate('NavigationBar', '$materialLib/navigation_bar.dart', tokens).updateFile(); NavigationRailTemplate('NavigationRail', '$materialLib/navigation_rail.dart', tokens).updateFile(); SurfaceTintTemplate('SurfaceTint', '$materialLib/elevation_overlay.dart', tokens).updateFile(); + TextFieldTemplate('TextField', '$materialLib/text_field.dart', tokens).updateFile(); TypographyTemplate('Typography', '$materialLib/typography.dart', tokens).updateFile(); } diff --git a/dev/tools/gen_defaults/lib/text_field_template.dart b/dev/tools/gen_defaults/lib/text_field_template.dart new file mode 100644 index 00000000000..8bb06fc206c --- /dev/null +++ b/dev/tools/gen_defaults/lib/text_field_template.dart @@ -0,0 +1,16 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'template.dart'; + +class TextFieldTemplate extends TokenTemplate { + const TextFieldTemplate(super.blockName, super.fileName, super.tokens); + + @override + String generate() => ''' +// Generated version ${tokens["version"]} + +TextStyle _m3InputStyle(BuildContext context) => ${textStyle("md.comp.filled-text-field.label-text")}!; +'''; +} diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index e4b90e0540a..96bd3b07741 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -1140,7 +1140,7 @@ class _TextFieldState extends State with RestorationMixin implements final ThemeData theme = Theme.of(context); final DefaultSelectionStyle selectionStyle = DefaultSelectionStyle.of(context); - final TextStyle style = theme.textTheme.subtitle1!.merge(widget.style); + final TextStyle style = (theme.useMaterial3 ? _m3InputStyle(context) : theme.textTheme.subtitle1!).merge(widget.style); final Brightness keyboardAppearance = widget.keyboardAppearance ?? theme.brightness; final TextEditingController controller = _effectiveController; final FocusNode focusNode = _effectiveFocusNode; @@ -1368,3 +1368,18 @@ class _TextFieldState extends State with RestorationMixin implements ); } } + +// BEGIN GENERATED TOKEN PROPERTIES - TextField + +// Do not edit by hand. The code between the "BEGIN GENERATED" and +// "END GENERATED" comments are generated from data in the Material +// Design token database by the script: +// dev/tools/gen_defaults/bin/gen_defaults.dart. + +// Token database version: v0_101 + +// Generated version v0_101 + +TextStyle _m3InputStyle(BuildContext context) => Theme.of(context).textTheme.bodyLarge!; + +// END GENERATED TOKEN PROPERTIES - TextField diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index 6c069f3f482..a4c0684c3ea 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -7107,6 +7107,57 @@ void main() { expect(editableText.style.color, isNull); }); + testWidgets('TextField style is merged with theme in Material 3', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/23994 + + final ThemeData themeData = ThemeData( + useMaterial3: true, + textTheme: TextTheme( + bodyLarge: TextStyle( + color: Colors.blue[500], + ), + ), + ); + + Widget buildFrame(TextStyle style) { + return MaterialApp( + theme: themeData, + home: Material( + child: Center( + child: TextField( + style: style, + ), + ), + ), + ); + } + + // Empty TextStyle is overridden by theme + await tester.pumpWidget(buildFrame(const TextStyle())); + EditableText editableText = tester.widget(find.byType(EditableText)); + expect(editableText.style.color, themeData.textTheme.bodyLarge!.color); + expect(editableText.style.background, themeData.textTheme.bodyLarge!.background); + expect(editableText.style.shadows, themeData.textTheme.bodyLarge!.shadows); + expect(editableText.style.decoration, themeData.textTheme.bodyLarge!.decoration); + expect(editableText.style.locale, themeData.textTheme.bodyLarge!.locale); + expect(editableText.style.wordSpacing, themeData.textTheme.bodyLarge!.wordSpacing); + + // Properties set on TextStyle override theme + const Color setColor = Colors.red; + await tester.pumpWidget(buildFrame(const TextStyle(color: setColor))); + editableText = tester.widget(find.byType(EditableText)); + expect(editableText.style.color, setColor); + + // inherit: false causes nothing to be merged in from theme + await tester.pumpWidget(buildFrame(const TextStyle( + fontSize: 24.0, + textBaseline: TextBaseline.alphabetic, + inherit: false, + ))); + editableText = tester.widget(find.byType(EditableText)); + expect(editableText.style.color, isNull); + }); + testWidgets('style enforces required fields', (WidgetTester tester) async { Widget buildFrame(TextStyle style) { return MaterialApp(