Unverified Commit df110ef0 authored by Darren Austin's avatar Darren Austin Committed by GitHub

Provide Material 3 defaults for vanilla `Chip` widget. (#111597)

parent d0a1e9e3
......@@ -104,6 +104,7 @@ Future<void> main(List<String> args) async {
tokens['colorsLight'] = _readTokenFile('color_light.json');
tokens['colorsDark'] = _readTokenFile('color_dark.json');
ActionChipTemplate('Chip', '$materialLib/chip.dart', tokens).updateFile();
ActionChipTemplate('ActionChip', '$materialLib/action_chip.dart', tokens).updateFile();
AppBarTemplate('AppBar', '$materialLib/app_bar.dart', tokens).updateFile();
BannerTemplate('Banner', '$materialLib/banner.dart', tokens).updateFile();
......
......@@ -170,6 +170,13 @@ abstract class TokenTemplate {
final Map<String, dynamic> shape = tokens[tokens['$componentToken.shape']!]! as Map<String, dynamic>;
switch (shape['family']) {
case 'SHAPE_FAMILY_ROUNDED_CORNERS':
final double topLeft = shape['topLeft'] as double;
final double topRight = shape['topRight'] as double;
final double bottomLeft = shape['bottomLeft'] as double;
final double bottomRight = shape['bottomRight'] as double;
if (topLeft == topRight && topLeft == bottomLeft && topLeft == bottomRight) {
return '${prefix}RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular($topLeft)))';
}
return '${prefix}RoundedRectangleBorder(borderRadius: '
'BorderRadius.only('
'topLeft: Radius.circular(${shape['topLeft']}), '
......
......@@ -184,7 +184,7 @@ class _ActionChipDefaultsM3 extends ChipThemeData {
const _ActionChipDefaultsM3(this.context, this.isEnabled)
: super(
elevation: 0.0,
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.only(topLeft: Radius.circular(8.0), topRight: Radius.circular(8.0), bottomLeft: Radius.circular(8.0), bottomRight: Radius.circular(8.0))),
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))),
showCheckmark: true,
);
......
......@@ -223,7 +223,7 @@ class _CardDefaultsM3 extends CardTheme {
clipBehavior: Clip.none,
elevation: 1.0,
margin: const EdgeInsets.all(4.0),
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.only(topLeft: Radius.circular(12.0), topRight: Radius.circular(12.0), bottomLeft: Radius.circular(12.0), bottomRight: Radius.circular(12.0))),
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(12.0))),
);
final BuildContext context;
......
......@@ -1164,11 +1164,15 @@ class _RawChipState extends State<RawChip> with MaterialStateMixin, TickerProvid
final ThemeData theme = Theme.of(context);
final ChipThemeData chipTheme = ChipTheme.of(context);
final Brightness brightness = chipTheme.brightness ?? theme.brightness;
final ChipThemeData chipDefaults = widget.defaultProperties ?? ChipThemeData.fromDefaults(
brightness: brightness,
secondaryColor: brightness == Brightness.dark ? Colors.tealAccent[200]! : theme.primaryColor,
labelStyle: theme.textTheme.bodyLarge!,
);
final ChipThemeData chipDefaults = widget.defaultProperties ??
(theme.useMaterial3
? _ChipDefaultsM3(context, widget.isEnabled)
: ChipThemeData.fromDefaults(
brightness: brightness,
secondaryColor: brightness == Brightness.dark ? Colors.tealAccent[200]! : theme.primaryColor,
labelStyle: theme.textTheme.bodyLarge!,
)
);
final TextDirection? textDirection = Directionality.maybeOf(context);
final OutlinedBorder resolvedShape = _getShape(theme, chipTheme, chipDefaults);
......@@ -2184,3 +2188,77 @@ bool _hitIsOnDeleteIcon({
return adjustedPosition.dx <= accessibleDeleteButtonWidth;
}
}
// BEGIN GENERATED TOKEN PROPERTIES - Chip
// 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_127
class _ChipDefaultsM3 extends ChipThemeData {
const _ChipDefaultsM3(this.context, this.isEnabled)
: super(
elevation: 0.0,
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))),
showCheckmark: true,
);
final BuildContext context;
final bool isEnabled;
@override
TextStyle? get labelStyle => Theme.of(context).textTheme.labelLarge;
@override
Color? get backgroundColor => null;
@override
Color? get shadowColor => Colors.transparent;
@override
Color? get surfaceTintColor => Theme.of(context).colorScheme.surfaceTint;
@override
Color? get selectedColor => null;
@override
Color? get checkmarkColor => null;
@override
Color? get disabledColor => null;
@override
Color? get deleteIconColor => null;
@override
BorderSide? get side => isEnabled
? BorderSide(color: Theme.of(context).colorScheme.outline)
: BorderSide(color: Theme.of(context).colorScheme.onSurface.withOpacity(0.12));
@override
IconThemeData? get iconTheme => IconThemeData(
color: isEnabled
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.onSurface,
size: 18.0,
);
@override
EdgeInsetsGeometry? get padding => const EdgeInsets.all(8.0);
/// The chip at text scale 1 starts with 8px on each side and as text scaling
/// gets closer to 2 the label padding is linearly interpolated from 8px to 4px.
/// Once the widget has a text scaling of 2 or higher than the label padding
/// remains 4px.
@override
EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp(
const EdgeInsets.symmetric(horizontal: 8.0),
const EdgeInsets.symmetric(horizontal: 4.0),
clampDouble(MediaQuery.of(context).textScaleFactor - 1.0, 0.0, 1.0),
)!;
}
// END GENERATED TOKEN PROPERTIES - Chip
......@@ -195,7 +195,7 @@ class _FilterChipDefaultsM3 extends ChipThemeData {
const _FilterChipDefaultsM3(this.context, this.isEnabled, this.isSelected)
: super(
elevation: 0.0,
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.only(topLeft: Radius.circular(8.0), topRight: Radius.circular(8.0), bottomLeft: Radius.circular(8.0), bottomRight: Radius.circular(8.0))),
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))),
showCheckmark: true,
);
......
......@@ -1396,7 +1396,7 @@ class _DialogDefaultsM3 extends DialogTheme {
: super(
alignment: Alignment.center,
elevation: 6.0,
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.only(topLeft: Radius.circular(28.0), topRight: Radius.circular(28.0), bottomLeft: Radius.circular(28.0), bottomRight: Radius.circular(28.0))),
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(28.0))),
);
final BuildContext context;
......
......@@ -204,7 +204,7 @@ class _FilterChipDefaultsM3 extends ChipThemeData {
const _FilterChipDefaultsM3(this.context, this.isEnabled, this.isSelected)
: super(
elevation: 0.0,
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.only(topLeft: Radius.circular(8.0), topRight: Radius.circular(8.0), bottomLeft: Radius.circular(8.0), bottomRight: Radius.circular(8.0))),
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))),
showCheckmark: true,
);
......
......@@ -850,13 +850,13 @@ class _FABDefaultsM3 extends FloatingActionButtonThemeData {
ShapeBorder? get shape {
switch (type) {
case _FloatingActionButtonType.regular:
return const RoundedRectangleBorder(borderRadius: BorderRadius.only(topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0), bottomLeft: Radius.circular(16.0), bottomRight: Radius.circular(16.0)));
return const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0)));
case _FloatingActionButtonType.small:
return const RoundedRectangleBorder(borderRadius: BorderRadius.only(topLeft: Radius.circular(12.0), topRight: Radius.circular(12.0), bottomLeft: Radius.circular(12.0), bottomRight: Radius.circular(12.0)));
return const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(12.0)));
case _FloatingActionButtonType.large:
return const RoundedRectangleBorder(borderRadius: BorderRadius.only(topLeft: Radius.circular(28.0), topRight: Radius.circular(28.0), bottomLeft: Radius.circular(28.0), bottomRight: Radius.circular(28.0)));
return const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(28.0)));
case _FloatingActionButtonType.extended:
return const RoundedRectangleBorder(borderRadius: BorderRadius.only(topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0), bottomLeft: Radius.circular(16.0), bottomRight: Radius.circular(16.0)));
return const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0)));
}
}
......
......@@ -255,7 +255,7 @@ class _InputChipDefaultsM3 extends ChipThemeData {
const _InputChipDefaultsM3(this.context, this.isEnabled)
: super(
elevation: 0.0,
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.only(topLeft: Radius.circular(8.0), topRight: Radius.circular(8.0), bottomLeft: Radius.circular(8.0), bottomRight: Radius.circular(8.0))),
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))),
showCheckmark: true,
);
......
......@@ -215,7 +215,7 @@ Finder findTooltipContainer(String tooltipText) {
}
void main() {
testWidgets('Chip defaults', (WidgetTester tester) async {
testWidgets('M2 Chip defaults', (WidgetTester tester) async {
late TextTheme textTheme;
Widget buildFrame(Brightness brightness) {
......@@ -292,6 +292,87 @@ void main() {
expect(labelStyle.wordSpacing, textTheme.bodyLarge?.wordSpacing);
});
testWidgets('M3 Chip defaults', (WidgetTester tester) async {
late TextTheme textTheme;
final ThemeData lightTheme = ThemeData.light(useMaterial3: true);
final ThemeData darkTheme = ThemeData.dark(useMaterial3: true);
Widget buildFrame(ThemeData theme) {
return MaterialApp(
theme: theme,
home: Scaffold(
body: Center(
child: Builder(
builder: (BuildContext context) {
textTheme = Theme.of(context).textTheme;
return Chip(
avatar: const CircleAvatar(child: Text('A')),
label: const Text('Chip A'),
onDeleted: () { },
);
},
),
),
),
);
}
await tester.pumpWidget(buildFrame(lightTheme));
expect(getMaterial(tester).color, null);
expect(getMaterial(tester).elevation, 0);
expect(getMaterial(tester).shape, RoundedRectangleBorder(
side: BorderSide(color: lightTheme.colorScheme.outline),
borderRadius: BorderRadius.circular(8.0),
));
expect(getIconData(tester).color, lightTheme.colorScheme.primary);
expect(getIconData(tester).opacity, null);
expect(getIconData(tester).size, 18);
TextStyle labelStyle = getLabelStyle(tester, 'Chip A').style;
expect(labelStyle.color, textTheme.labelLarge?.color);
expect(labelStyle.fontFamily, textTheme.labelLarge?.fontFamily);
expect(labelStyle.fontFamilyFallback, textTheme.labelLarge?.fontFamilyFallback);
expect(labelStyle.fontFeatures, textTheme.labelLarge?.fontFeatures);
expect(labelStyle.fontSize, textTheme.labelLarge?.fontSize);
expect(labelStyle.fontStyle, textTheme.labelLarge?.fontStyle);
expect(labelStyle.fontWeight, textTheme.labelLarge?.fontWeight);
expect(labelStyle.height, textTheme.labelLarge?.height);
expect(labelStyle.inherit, textTheme.labelLarge?.inherit);
expect(labelStyle.leadingDistribution, textTheme.labelLarge?.leadingDistribution);
expect(labelStyle.letterSpacing, textTheme.labelLarge?.letterSpacing);
expect(labelStyle.overflow, textTheme.labelLarge?.overflow);
expect(labelStyle.textBaseline, textTheme.labelLarge?.textBaseline);
expect(labelStyle.wordSpacing, textTheme.labelLarge?.wordSpacing);
await tester.pumpWidget(buildFrame(darkTheme));
await tester.pumpAndSettle(); // Theme transition animation
expect(getMaterial(tester).color, null);
expect(getMaterial(tester).elevation, 0);
expect(getMaterial(tester).shape, RoundedRectangleBorder(
side: BorderSide(color: darkTheme.colorScheme.outline),
borderRadius: BorderRadius.circular(8.0),
));
expect(getIconData(tester).color, darkTheme.colorScheme.primary);
expect(getIconData(tester).opacity, null);
expect(getIconData(tester).size, 18);
labelStyle = getLabelStyle(tester, 'Chip A').style;
expect(labelStyle.color, textTheme.labelLarge?.color);
expect(labelStyle.fontFamily, textTheme.labelLarge?.fontFamily);
expect(labelStyle.fontFamilyFallback, textTheme.labelLarge?.fontFamilyFallback);
expect(labelStyle.fontFeatures, textTheme.labelLarge?.fontFeatures);
expect(labelStyle.fontSize, textTheme.labelLarge?.fontSize);
expect(labelStyle.fontStyle, textTheme.labelLarge?.fontStyle);
expect(labelStyle.fontWeight, textTheme.labelLarge?.fontWeight);
expect(labelStyle.height, textTheme.labelLarge?.height);
expect(labelStyle.inherit, textTheme.labelLarge?.inherit);
expect(labelStyle.leadingDistribution, textTheme.labelLarge?.leadingDistribution);
expect(labelStyle.letterSpacing, textTheme.labelLarge?.letterSpacing);
expect(labelStyle.overflow, textTheme.labelLarge?.overflow);
expect(labelStyle.textBaseline, textTheme.labelLarge?.textBaseline);
expect(labelStyle.wordSpacing, textTheme.labelLarge?.wordSpacing);
});
testWidgets('Chip control test', (WidgetTester tester) async {
final FeedbackTester feedback = FeedbackTester();
final List<String> deletedChipLabels = <String>[];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment