Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit e74b9b5

Browse files
authored
Migrate InputDecorator to Material 3 (#107943)
* Support material 3 in inputDecorator * Format polish * format polish * update input_decorator_test * revert pub * style update * style polish * default before base * resolve comments * Update text_field.2.dart * move text styles into M2 theme * add error style * fix typo * resolve comments * fix g3 test
1 parent 2f4299a commit e74b9b5

File tree

6 files changed

+1122
-351
lines changed

6 files changed

+1122
-351
lines changed

dev/tools/gen_defaults/bin/gen_defaults.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import 'package:gen_defaults/chip_input_template.dart';
2626
import 'package:gen_defaults/dialog_template.dart';
2727
import 'package:gen_defaults/fab_template.dart';
2828
import 'package:gen_defaults/icon_button_template.dart';
29+
import 'package:gen_defaults/input_decorator_template.dart';
2930
import 'package:gen_defaults/navigation_bar_template.dart';
3031
import 'package:gen_defaults/navigation_rail_template.dart';
3132
import 'package:gen_defaults/surface_tint.dart';
@@ -111,6 +112,7 @@ Future<void> main(List<String> args) async {
111112
DialogTemplate('Dialog', '$materialLib/dialog.dart', tokens).updateFile();
112113
FABTemplate('FAB', '$materialLib/floating_action_button.dart', tokens).updateFile();
113114
IconButtonTemplate('IconButton', '$materialLib/icon_button.dart', tokens).updateFile();
115+
InputDecoratorTemplate('InputDecorator', '$materialLib/input_decorator.dart', tokens).updateFile();
114116
NavigationBarTemplate('NavigationBar', '$materialLib/navigation_bar.dart', tokens).updateFile();
115117
NavigationRailTemplate('NavigationRail', '$materialLib/navigation_rail.dart', tokens).updateFile();
116118
SurfaceTintTemplate('SurfaceTint', '$materialLib/elevation_overlay.dart', tokens).updateFile();
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'template.dart';
6+
7+
class InputDecoratorTemplate extends TokenTemplate {
8+
const InputDecoratorTemplate(super.blockName, super.fileName, super.tokens, {
9+
super.colorSchemePrefix = '_colors.',
10+
super.textThemePrefix = '_textTheme.'
11+
});
12+
13+
@override
14+
String generate() => '''
15+
// Generated version ${tokens["version"]}
16+
class _${blockName}DefaultsM3 extends InputDecorationTheme {
17+
_${blockName}DefaultsM3(this.context)
18+
: super();
19+
20+
final BuildContext context;
21+
22+
late final ColorScheme _colors = Theme.of(context).colorScheme;
23+
late final TextTheme _textTheme = Theme.of(context).textTheme;
24+
25+
@override
26+
TextStyle? get hintStyle => MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
27+
if (states.contains(MaterialState.disabled)) {
28+
return TextStyle(color: Theme.of(context).disabledColor);
29+
}
30+
return TextStyle(color: Theme.of(context).hintColor);
31+
});
32+
33+
@override
34+
Color? get fillColor => MaterialStateColor.resolveWith((Set<MaterialState> states) {
35+
if (states.contains(MaterialState.disabled)) {
36+
return ${componentColor("md.comp.filled-text-field.disabled.container")};
37+
}
38+
return ${componentColor("md.comp.filled-text-field.container")};
39+
});
40+
41+
@override
42+
BorderSide? get activeIndicatorBorder => MaterialStateBorderSide.resolveWith((Set<MaterialState> states) {
43+
if (states.contains(MaterialState.error)) {
44+
if (states.contains(MaterialState.hovered)) {
45+
return ${border('md.comp.filled-text-field.error.hover.active-indicator')};
46+
}
47+
if (states.contains(MaterialState.focused)) {
48+
return ${border('md.comp.filled-text-field.error.focus.active-indicator')};
49+
}
50+
return ${border('md.comp.filled-text-field.error.active-indicator')};
51+
}
52+
if (states.contains(MaterialState.hovered)) {
53+
return ${border('md.comp.filled-text-field.hover.active-indicator')};
54+
}
55+
if (states.contains(MaterialState.focused)) {
56+
return ${border('md.comp.filled-text-field.focus.active-indicator')};
57+
}
58+
if (states.contains(MaterialState.disabled)) {
59+
return ${border('md.comp.filled-text-field.disabled.active-indicator')};
60+
}
61+
return ${border('md.comp.filled-text-field.active-indicator')};
62+
});
63+
64+
@override
65+
BorderSide? get outlineBorder => MaterialStateBorderSide.resolveWith((Set<MaterialState> states) {
66+
if (states.contains(MaterialState.error)) {
67+
if (states.contains(MaterialState.hovered)) {
68+
return ${border('md.comp.outlined-text-field.error.hover.outline')};
69+
}
70+
if (states.contains(MaterialState.focused)) {
71+
return ${border('md.comp.outlined-text-field.error.focus.outline')};
72+
}
73+
return ${border('md.comp.outlined-text-field.error.outline')};
74+
}
75+
if (states.contains(MaterialState.hovered)) {
76+
return ${border('md.comp.outlined-text-field.hover.outline')};
77+
}
78+
if (states.contains(MaterialState.focused)) {
79+
return ${border('md.comp.outlined-text-field.focus.outline')};
80+
}
81+
if (states.contains(MaterialState.disabled)) {
82+
return ${border('md.comp.outlined-text-field.disabled.outline')};
83+
}
84+
return ${border('md.comp.outlined-text-field.outline')};
85+
});
86+
87+
@override
88+
Color? get iconColor => ${componentColor("md.comp.filled-text-field.leading-icon")};
89+
90+
@override
91+
Color? get prefixIconColor => MaterialStateColor.resolveWith((Set<MaterialState> states) {
92+
if(states.contains(MaterialState.error)) {
93+
if (states.contains(MaterialState.hovered)) {
94+
return ${componentColor('md.comp.filled-text-field.error.hover.leading-icon')};
95+
}
96+
if (states.contains(MaterialState.focused)) {
97+
return ${componentColor('md.comp.filled-text-field.error.focus.leading-icon')};
98+
}
99+
return ${componentColor('md.comp.filled-text-field.error.leading-icon')};
100+
}
101+
if (states.contains(MaterialState.hovered)) {
102+
return ${componentColor('md.comp.filled-text-field.hover.leading-icon')};
103+
}
104+
if (states.contains(MaterialState.focused)) {
105+
return ${componentColor('md.comp.filled-text-field.focus.leading-icon')};
106+
}
107+
if (states.contains(MaterialState.disabled)) {
108+
return ${componentColor('md.comp.filled-text-field.disabled.leading-icon')};
109+
}
110+
return ${componentColor('md.comp.filled-text-field.leading-icon')};
111+
});
112+
113+
@override
114+
Color? get suffixIconColor => MaterialStateColor.resolveWith((Set<MaterialState> states) {
115+
if(states.contains(MaterialState.error)) {
116+
if (states.contains(MaterialState.hovered)) {
117+
return ${componentColor('md.comp.filled-text-field.error.hover.trailing-icon')};
118+
}
119+
if (states.contains(MaterialState.focused)) {
120+
return ${componentColor('md.comp.filled-text-field.error.focus.trailing-icon')};
121+
}
122+
return ${componentColor('md.comp.filled-text-field.error.trailing-icon')};
123+
}
124+
if (states.contains(MaterialState.hovered)) {
125+
return ${componentColor('md.comp.filled-text-field.hover.trailing-icon')};
126+
}
127+
if (states.contains(MaterialState.focused)) {
128+
return ${componentColor('md.comp.filled-text-field.focus.trailing-icon')};
129+
}
130+
if (states.contains(MaterialState.disabled)) {
131+
return ${componentColor('md.comp.filled-text-field.disabled.trailing-icon')};
132+
}
133+
return ${componentColor('md.comp.filled-text-field.trailing-icon')};
134+
});
135+
136+
@override
137+
TextStyle? get labelStyle => MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
138+
final TextStyle textStyle= ${textStyle("md.comp.filled-text-field.label-text")} ?? const TextStyle();
139+
if(states.contains(MaterialState.error)) {
140+
if (states.contains(MaterialState.hovered)) {
141+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.error.hover.label-text')});
142+
}
143+
if (states.contains(MaterialState.focused)) {
144+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.error.focus.label-text')});
145+
}
146+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.error.label-text')});
147+
}
148+
if (states.contains(MaterialState.hovered)) {
149+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.hover.label-text')});
150+
}
151+
if (states.contains(MaterialState.focused)) {
152+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.focus.label-text')});
153+
}
154+
if (states.contains(MaterialState.disabled)) {
155+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.disabled.label-text')});
156+
}
157+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.label-text')});
158+
});
159+
160+
@override
161+
TextStyle? get floatingLabelStyle => MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
162+
final TextStyle textStyle= ${textStyle("md.comp.filled-text-field.label-text")} ?? const TextStyle();
163+
if(states.contains(MaterialState.error)) {
164+
if (states.contains(MaterialState.hovered)) {
165+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.error.hover.label-text')});
166+
}
167+
if (states.contains(MaterialState.focused)) {
168+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.error.focus.label-text')});
169+
}
170+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.error.label-text')});
171+
}
172+
if (states.contains(MaterialState.hovered)) {
173+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.hover.label-text')});
174+
}
175+
if (states.contains(MaterialState.focused)) {
176+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.focus.label-text')});
177+
}
178+
if (states.contains(MaterialState.disabled)) {
179+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.disabled.label-text')});
180+
}
181+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.label-text')});
182+
});
183+
184+
@override
185+
TextStyle? get helperStyle => MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
186+
final TextStyle textStyle= ${textStyle("md.comp.filled-text-field.supporting-text")} ?? const TextStyle();
187+
if (states.contains(MaterialState.hovered)) {
188+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.hover.supporting-text')});
189+
}
190+
if (states.contains(MaterialState.focused)) {
191+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.focus.supporting-text')});
192+
}
193+
if (states.contains(MaterialState.disabled)) {
194+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.disabled.supporting-text')});
195+
}
196+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.supporting-text')});
197+
});
198+
199+
@override
200+
TextStyle? get errorStyle => MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
201+
final TextStyle textStyle= ${textStyle("md.comp.filled-text-field.supporting-text")} ?? const TextStyle();
202+
if (states.contains(MaterialState.hovered)) {
203+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.error.hover.supporting-text')});
204+
}
205+
if (states.contains(MaterialState.focused)) {
206+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.error.focus.supporting-text')});
207+
}
208+
return textStyle.copyWith(color:${componentColor('md.comp.filled-text-field.error.supporting-text')});
209+
});
210+
}
211+
''';
212+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flutter code sample for Material Design 3 TextFields.
6+
7+
import 'package:flutter/material.dart';
8+
9+
void main() { runApp(const TextFieldExamplesApp()); }
10+
11+
class TextFieldExamplesApp extends StatelessWidget {
12+
const TextFieldExamplesApp({super.key});
13+
14+
@override
15+
Widget build(BuildContext context) {
16+
return MaterialApp(
17+
theme: ThemeData(colorSchemeSeed: const Color(0xff6750a4), useMaterial3: true),
18+
home: Scaffold(
19+
appBar: AppBar(title: const Text('TextField Examples')),
20+
body: Column(
21+
children: const <Widget>[
22+
Spacer(),
23+
FilledTextFieldExample(),
24+
OutlinedTextFieldExample(),
25+
Spacer(),
26+
],
27+
),
28+
),
29+
);
30+
}
31+
}
32+
33+
/// An example of the filled text field type.
34+
///
35+
/// A filled [TextField] with default settings matching the spec:
36+
/// https://m3.material.io/components/text-fields/specs#6d654d1d-262e-4697-858c-9a75e8e7c81d
37+
class FilledTextFieldExample extends StatelessWidget {
38+
const FilledTextFieldExample({ super.key });
39+
40+
@override
41+
Widget build(BuildContext context) {
42+
return const TextField(
43+
decoration: InputDecoration(
44+
prefixIcon: Icon(Icons.search),
45+
suffixIcon: Icon(Icons.clear),
46+
labelText: 'Filled',
47+
hintText: 'hint text',
48+
helperText: 'supporting text',
49+
filled: true,
50+
)
51+
);
52+
}
53+
}
54+
55+
/// An example of the outlined text field type.
56+
///
57+
/// A Outlined [TextField] with default settings matching the spec:
58+
/// https://m3.material.io/components/text-fields/specs#68b00bd6-ab40-4b4f-93d9-ed1fbbc5d06e
59+
class OutlinedTextFieldExample extends StatelessWidget {
60+
const OutlinedTextFieldExample({ super.key });
61+
62+
@override
63+
Widget build(BuildContext context) {
64+
return const TextField(
65+
decoration: InputDecoration(
66+
prefixIcon: Icon(Icons.search),
67+
suffixIcon: Icon(Icons.clear),
68+
labelText: 'Outlined',
69+
hintText: 'hint text',
70+
helperText: 'supporting text',
71+
border: OutlineInputBorder(),
72+
),
73+
);
74+
}
75+
}

0 commit comments

Comments
 (0)