Unverified Commit b1146549 authored by Qun Cheng's avatar Qun Cheng Committed by GitHub

Add `IconButton.filled`, `IconButton.filledTonal`, `IconButton.outlined` (#121884)

parent 7979d8eb
...@@ -158,7 +158,10 @@ Future<void> main(List<String> args) async { ...@@ -158,7 +158,10 @@ Future<void> main(List<String> args) async {
FABTemplate('FAB', '$materialLib/floating_action_button.dart', tokens).updateFile(); FABTemplate('FAB', '$materialLib/floating_action_button.dart', tokens).updateFile();
FilterChipTemplate('ChoiceChip', '$materialLib/choice_chip.dart', tokens).updateFile(); FilterChipTemplate('ChoiceChip', '$materialLib/choice_chip.dart', tokens).updateFile();
FilterChipTemplate('FilterChip', '$materialLib/filter_chip.dart', tokens).updateFile(); FilterChipTemplate('FilterChip', '$materialLib/filter_chip.dart', tokens).updateFile();
IconButtonTemplate('IconButton', '$materialLib/icon_button.dart', tokens).updateFile(); IconButtonTemplate('md.comp.icon-button', 'IconButton', '$materialLib/icon_button.dart', tokens).updateFile();
IconButtonTemplate('md.comp.filled-icon-button', 'FilledIconButton', '$materialLib/icon_button.dart', tokens).updateFile();
IconButtonTemplate('md.comp.filled-tonal-icon-button', 'FilledTonalIconButton', '$materialLib/icon_button.dart', tokens).updateFile();
IconButtonTemplate('md.comp.outlined-icon-button', 'OutlinedIconButton', '$materialLib/icon_button.dart', tokens).updateFile();
InputChipTemplate('InputChip', '$materialLib/input_chip.dart', tokens).updateFile(); InputChipTemplate('InputChip', '$materialLib/input_chip.dart', tokens).updateFile();
ListTileTemplate('LisTile', '$materialLib/list_tile.dart', tokens).updateFile(); ListTileTemplate('LisTile', '$materialLib/list_tile.dart', tokens).updateFile();
InputDecoratorTemplate('InputDecorator', '$materialLib/input_decorator.dart', tokens).updateFile(); InputDecoratorTemplate('InputDecorator', '$materialLib/input_decorator.dart', tokens).updateFile();
......
...@@ -5,75 +5,259 @@ ...@@ -5,75 +5,259 @@
import 'template.dart'; import 'template.dart';
class IconButtonTemplate extends TokenTemplate { class IconButtonTemplate extends TokenTemplate {
const IconButtonTemplate(super.blockName, super.fileName, super.tokens, { const IconButtonTemplate(this.tokenGroup, super.blockName, super.fileName, super.tokens, {
super.colorSchemePrefix = '_colors.', super.colorSchemePrefix = '_colors.',
}); });
final String tokenGroup;
String _elevationColor(String token) { String _backgroundColor() {
if (tokens.containsKey(token)) { switch (tokenGroup) {
return 'MaterialStatePropertyAll<Color>(${color(token)})'; case 'md.comp.filled-icon-button':
} else { case 'md.comp.filled-tonal-icon-button':
return 'const MaterialStatePropertyAll<Color>(Colors.transparent)'; return '''
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return ${componentColor('$tokenGroup.disabled.container')};
}
if (states.contains(MaterialState.selected)) {
return ${componentColor('$tokenGroup.selected.container')};
} }
if (toggleable) { // toggleable but unselected case
return ${componentColor('$tokenGroup.unselected.container')};
} }
return ${componentColor('$tokenGroup.container')};
})''';
case 'md.comp.outlined-icon-button':
return '''
@override MaterialStateProperty.resolveWith((Set<MaterialState> states) {
String generate() => ''' if (states.contains(MaterialState.disabled)) {
class _${blockName}DefaultsM3 extends ButtonStyle { if (states.contains(MaterialState.selected)) {
_${blockName}DefaultsM3(this.context) return ${componentColor('$tokenGroup.disabled.selected.container')};
: super( }
animationDuration: kThemeChangeDuration, return Colors.transparent;
enableFeedback: true, }
alignment: Alignment.center, if (states.contains(MaterialState.selected)) {
); return ${componentColor('$tokenGroup.selected.container')};
}
return Colors.transparent;
})''';
}
return '''
final BuildContext context; const MaterialStatePropertyAll<Color?>(Colors.transparent)''';
late final ColorScheme _colors = Theme.of(context).colorScheme; }
// No default text style String _foregroundColor() {
switch (tokenGroup) {
case 'md.comp.filled-icon-button':
case 'md.comp.filled-tonal-icon-button':
return '''
@override MaterialStateProperty.resolveWith((Set<MaterialState> states) {
MaterialStateProperty<Color?>? get backgroundColor => if (states.contains(MaterialState.disabled)) {
const MaterialStatePropertyAll<Color?>(Colors.transparent); return ${componentColor('$tokenGroup.disabled.icon')};
}
if (states.contains(MaterialState.selected)) {
return ${componentColor('$tokenGroup.toggle.selected.icon')};
}
if (toggleable) { // toggleable but unselected case
return ${componentColor('$tokenGroup.toggle.unselected.icon')};
}
return ${componentColor('$tokenGroup.icon')};
})''';
case 'md.comp.outlined-icon-button':
case 'md.comp.icon-button':
return '''
@override
MaterialStateProperty<Color?>? get foregroundColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) { MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) { if (states.contains(MaterialState.disabled)) {
return ${componentColor('md.comp.icon-button.disabled.icon')}; return ${componentColor('$tokenGroup.disabled.icon')};
} }
if (states.contains(MaterialState.selected)) { if (states.contains(MaterialState.selected)) {
return ${componentColor('md.comp.icon-button.selected.icon')}; return ${componentColor('$tokenGroup.selected.icon')};
} }
return ${componentColor('md.comp.icon-button.unselected.icon')}; return ${componentColor('$tokenGroup.unselected.icon')};
}); })''';
}
return '''
@override const MaterialStatePropertyAll<Color?>(Colors.transparent)''';
MaterialStateProperty<Color?>? get overlayColor => }
String _overlayColor() {
switch (tokenGroup) {
case 'md.comp.filled-icon-button':
case 'md.comp.filled-tonal-icon-button':
return '''
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.hovered)) {
return ${componentColor('$tokenGroup.toggle.selected.hover.state-layer')}.withOpacity(${opacity('$tokenGroup.hover.state-layer.opacity')});
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('$tokenGroup.toggle.selected.focus.state-layer')}.withOpacity(${opacity('$tokenGroup.focus.state-layer.opacity')});
}
if (states.contains(MaterialState.pressed)) {
return ${componentColor('$tokenGroup.toggle.selected.pressed.state-layer')}.withOpacity(${opacity('$tokenGroup.pressed.state-layer.opacity')});
}
}
if (toggleable) { // toggleable but unselected case
if (states.contains(MaterialState.hovered)) {
return ${componentColor('$tokenGroup.toggle.unselected.hover.state-layer')}.withOpacity(${opacity('$tokenGroup.hover.state-layer.opacity')});
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('$tokenGroup.toggle.unselected.focus.state-layer')}.withOpacity(${opacity('$tokenGroup.focus.state-layer.opacity')});
}
if (states.contains(MaterialState.pressed)) {
return ${componentColor('$tokenGroup.toggle.unselected.pressed.state-layer')}.withOpacity(${opacity('$tokenGroup.pressed.state-layer.opacity')});
}
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('$tokenGroup.hover.state-layer')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('$tokenGroup.focus.state-layer')};
}
if (states.contains(MaterialState.pressed)) {
return ${componentColor('$tokenGroup.pressed.state-layer')};
}
return Colors.transparent;
})''';
case 'md.comp.outlined-icon-button':
return '''
MaterialStateProperty.resolveWith((Set<MaterialState> states) { MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) { if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.hovered)) { if (states.contains(MaterialState.hovered)) {
return ${componentColor('md.comp.icon-button.selected.hover.state-layer')}; return ${componentColor('$tokenGroup.selected.hover.state-layer')}.withOpacity(${opacity('$tokenGroup.hover.state-layer.opacity')});
} }
if (states.contains(MaterialState.focused)) { if (states.contains(MaterialState.focused)) {
return ${componentColor('md.comp.icon-button.selected.focus.state-layer')}; return ${componentColor('$tokenGroup.selected.focus.state-layer')}.withOpacity(${opacity('$tokenGroup.focus.state-layer.opacity')});
} }
if (states.contains(MaterialState.pressed)) { if (states.contains(MaterialState.pressed)) {
return ${componentColor('md.comp.icon-button.selected.pressed.state-layer')}; return ${componentColor('$tokenGroup.selected.pressed.state-layer')}.withOpacity(${opacity('$tokenGroup.pressed.state-layer.opacity')});
} }
} }
if (states.contains(MaterialState.hovered)) { if (states.contains(MaterialState.hovered)) {
return ${componentColor('md.comp.icon-button.unselected.hover.state-layer')}; return ${componentColor('$tokenGroup.unselected.hover.state-layer')}.withOpacity(${opacity('$tokenGroup.hover.state-layer.opacity')});
} }
if (states.contains(MaterialState.focused)) { if (states.contains(MaterialState.focused)) {
return ${componentColor('md.comp.icon-button.unselected.focus.state-layer')}; return ${componentColor('$tokenGroup.unselected.focus.state-layer')}.withOpacity(${opacity('$tokenGroup.focus.state-layer.opacity')});
} }
if (states.contains(MaterialState.pressed)) { if (states.contains(MaterialState.pressed)) {
return ${componentColor('md.comp.icon-button.unselected.pressed.state-layer')}; return ${componentColor('$tokenGroup.unselected.pressed.state-layer')}.withOpacity(${opacity('$tokenGroup.pressed.state-layer.opacity')});
} }
return Colors.transparent;
})''';
case 'md.comp.icon-button':
return '''
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.hovered)) {
return ${componentColor('$tokenGroup.selected.hover.state-layer')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('$tokenGroup.selected.focus.state-layer')};
}
if (states.contains(MaterialState.pressed)) {
return ${componentColor('$tokenGroup.selected.pressed.state-layer')};
}
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('$tokenGroup.unselected.hover.state-layer')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('$tokenGroup.unselected.focus.state-layer')};
}
if (states.contains(MaterialState.pressed)) {
return ${componentColor('$tokenGroup.unselected.pressed.state-layer')};
}
return Colors.transparent;
})''';
}
return '''
const MaterialStatePropertyAll<Color?>(Colors.transparent)''';
}
String _minimumSize() {
if (tokens.containsKey('$tokenGroup.container.size')) {
return '''
const MaterialStatePropertyAll<Size>(Size(${tokens['$tokenGroup.container.size']}, ${tokens['$tokenGroup.container.size']}))''';
} else {
return '''
const MaterialStatePropertyAll<Size>(Size(${tokens['$tokenGroup.state-layer.size']}, ${tokens['$tokenGroup.state-layer.size']}))''';
}
}
String _shape() {
if (tokens.containsKey('$tokenGroup.container.shape')) {
return '''
const MaterialStatePropertyAll<OutlinedBorder>(${shape("$tokenGroup.container", "")})''';
} else {
return '''
const MaterialStatePropertyAll<OutlinedBorder>(${shape("$tokenGroup.state-layer", "")})''';
}
}
String _side() {
if (tokens.containsKey('$tokenGroup.unselected.outline.color')) {
return '''
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
return null; return null;
}); } else {
if (states.contains(MaterialState.disabled)) {
return BorderSide(color: ${componentColor('$tokenGroup.disabled.unselected.outline')});
}
return BorderSide(color: ${componentColor('$tokenGroup.unselected.outline')});
}
})''';
}
return ''' null''';
}
String _elevationColor(String token) {
if (tokens.containsKey(token)) {
return 'MaterialStatePropertyAll<Color>(${color(token)})';
} else {
return 'const MaterialStatePropertyAll<Color>(Colors.transparent)';
}
}
@override
String generate() => '''
class _${blockName}DefaultsM3 extends ButtonStyle {
_${blockName}DefaultsM3(this.context, this.toggleable)
: super(
animationDuration: kThemeChangeDuration,
enableFeedback: true,
alignment: Alignment.center,
);
final BuildContext context;
final bool toggleable;
late final ColorScheme _colors = Theme.of(context).colorScheme;
// No default text style
@override
MaterialStateProperty<Color?>? get backgroundColor =>${_backgroundColor()};
@override
MaterialStateProperty<Color?>? get foregroundColor =>${_foregroundColor()};
@override
MaterialStateProperty<Color?>? get overlayColor =>${_overlayColor()};
@override @override
MaterialStateProperty<double>? get elevation => MaterialStateProperty<double>? get elevation =>
...@@ -81,19 +265,18 @@ class _${blockName}DefaultsM3 extends ButtonStyle { ...@@ -81,19 +265,18 @@ class _${blockName}DefaultsM3 extends ButtonStyle {
@override @override
MaterialStateProperty<Color>? get shadowColor => MaterialStateProperty<Color>? get shadowColor =>
${_elevationColor("md.comp.icon-button.container.shadow-color")}; ${_elevationColor("$tokenGroup.container.shadow-color")};
@override @override
MaterialStateProperty<Color>? get surfaceTintColor => MaterialStateProperty<Color>? get surfaceTintColor =>
${_elevationColor("md.comp.icon-button.container.surface-tint-layer.color")}; ${_elevationColor("$tokenGroup.container.surface-tint-layer.color")};
@override @override
MaterialStateProperty<EdgeInsetsGeometry>? get padding => MaterialStateProperty<EdgeInsetsGeometry>? get padding =>
const MaterialStatePropertyAll<EdgeInsetsGeometry>(EdgeInsets.all(8.0)); const MaterialStatePropertyAll<EdgeInsetsGeometry>(EdgeInsets.all(8.0));
@override @override
MaterialStateProperty<Size>? get minimumSize => MaterialStateProperty<Size>? get minimumSize =>${_minimumSize()};
const MaterialStatePropertyAll<Size>(Size(${tokens["md.comp.icon-button.state-layer.size"]}, ${tokens["md.comp.icon-button.state-layer.size"]}));
// No default fixedSize // No default fixedSize
...@@ -103,13 +286,13 @@ class _${blockName}DefaultsM3 extends ButtonStyle { ...@@ -103,13 +286,13 @@ class _${blockName}DefaultsM3 extends ButtonStyle {
@override @override
MaterialStateProperty<double>? get iconSize => MaterialStateProperty<double>? get iconSize =>
const MaterialStatePropertyAll<double>(${tokens["md.comp.icon-button.icon.size"]}); const MaterialStatePropertyAll<double>(${tokens["$tokenGroup.icon.size"]});
// No default side @override
MaterialStateProperty<BorderSide?>? get side =>${_side()};
@override @override
MaterialStateProperty<OutlinedBorder>? get shape => MaterialStateProperty<OutlinedBorder>? get shape =>${_shape()};
const MaterialStatePropertyAll<OutlinedBorder>(${shape("md.comp.icon-button.state-layer", "")});
@override @override
MaterialStateProperty<MouseCursor?>? get mouseCursor => MaterialStateProperty<MouseCursor?>? get mouseCursor =>
......
...@@ -52,7 +52,6 @@ class ButtonTypesGroup extends StatelessWidget { ...@@ -52,7 +52,6 @@ class ButtonTypesGroup extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final VoidCallback? onPressed = enabled ? () {} : null; final VoidCallback? onPressed = enabled ? () {} : null;
final ColorScheme colors = Theme.of(context).colorScheme;
return Padding( return Padding(
padding: const EdgeInsets.all(4.0), padding: const EdgeInsets.all(4.0),
...@@ -61,56 +60,14 @@ class ButtonTypesGroup extends StatelessWidget { ...@@ -61,56 +60,14 @@ class ButtonTypesGroup extends StatelessWidget {
children: <Widget>[ children: <Widget>[
IconButton(icon: const Icon(Icons.filter_drama), onPressed: onPressed), IconButton(icon: const Icon(Icons.filter_drama), onPressed: onPressed),
// Use a standard IconButton with specific style to implement the // Filled icon button
// 'Filled' type. IconButton.filled(onPressed: onPressed, icon: const Icon(Icons.filter_drama)),
IconButton(
icon: const Icon(Icons.filter_drama),
onPressed: onPressed,
style: IconButton.styleFrom(
foregroundColor: colors.onPrimary,
backgroundColor: colors.primary,
disabledBackgroundColor: colors.onSurface.withOpacity(0.12),
hoverColor: colors.onPrimary.withOpacity(0.08),
focusColor: colors.onPrimary.withOpacity(0.12),
highlightColor: colors.onPrimary.withOpacity(0.12),
)
),
// Use a standard IconButton with specific style to implement the // Filled tonal icon button
// 'Filled Tonal' type. IconButton.filledTonal(onPressed: onPressed, icon: const Icon(Icons.filter_drama)),
IconButton(
icon: const Icon(Icons.filter_drama),
onPressed: onPressed,
style: IconButton.styleFrom(
foregroundColor: colors.onSecondaryContainer,
backgroundColor: colors.secondaryContainer,
disabledBackgroundColor: colors.onSurface.withOpacity(0.12),
hoverColor: colors.onSecondaryContainer.withOpacity(0.08),
focusColor: colors.onSecondaryContainer.withOpacity(0.12),
highlightColor: colors.onSecondaryContainer.withOpacity(0.12),
),
),
// Use a standard IconButton with specific style to implement the // Outlined icon button
// 'Outlined' type. IconButton.outlined(onPressed: onPressed, icon: const Icon(Icons.filter_drama)),
IconButton(
icon: const Icon(Icons.filter_drama),
onPressed: onPressed,
style: IconButton.styleFrom(
focusColor: colors.onSurfaceVariant.withOpacity(0.12),
highlightColor: colors.onSurface.withOpacity(0.12),
side: onPressed == null
? BorderSide(color: Theme.of(context).colorScheme.onSurface.withOpacity(0.12))
: BorderSide(color: colors.outline),
).copyWith(
foregroundColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.pressed)) {
return colors.onSurface;
}
return null;
}),
),
),
], ],
), ),
); );
......
...@@ -36,153 +36,105 @@ class DemoIconToggleButtons extends StatefulWidget { ...@@ -36,153 +36,105 @@ class DemoIconToggleButtons extends StatefulWidget {
} }
class _DemoIconToggleButtonsState extends State<DemoIconToggleButtons> { class _DemoIconToggleButtonsState extends State<DemoIconToggleButtons> {
bool standardSelected = false;
bool filledSelected = false;
bool tonalSelected = false;
bool outlinedSelected = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return const Padding( return Column(
padding: EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[ children: <Widget>[
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
// Standard IconButton
children: <Widget>[ children: <Widget>[
DemoIconToggleButton(isEnabled: true), IconButton(
SizedBox(width: 10), isSelected: standardSelected,
DemoIconToggleButton(isEnabled: false), icon: const Icon(Icons.settings_outlined),
] selectedIcon: const Icon(Icons.settings),
onPressed: () {
setState(() {
standardSelected = !standardSelected;
});
},
),
const SizedBox(width: 10),
IconButton(
isSelected: standardSelected,
icon: const Icon(Icons.settings_outlined),
selectedIcon: const Icon(Icons.settings),
onPressed: null,
),
],
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
// Filled IconButton IconButton.filled(
DemoIconToggleButton(isEnabled: true, getDefaultStyle: enabledFilledButtonStyle,), isSelected: filledSelected,
SizedBox(width: 10), icon: const Icon(Icons.settings_outlined),
DemoIconToggleButton(isEnabled: false, getDefaultStyle: disabledFilledButtonStyle,) selectedIcon: const Icon(Icons.settings),
] onPressed: () {
setState(() {
filledSelected = !filledSelected;
});
},
),
const SizedBox(width: 10),
IconButton.filled(
isSelected: filledSelected,
icon: const Icon(Icons.settings_outlined),
selectedIcon: const Icon(Icons.settings),
onPressed: null,
),
],
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
// Filled Tonal IconButton IconButton.filledTonal(
DemoIconToggleButton(isEnabled: true, getDefaultStyle: enabledFilledTonalButtonStyle,), isSelected: tonalSelected,
SizedBox(width: 10), icon: const Icon(Icons.settings_outlined),
DemoIconToggleButton(isEnabled: false, getDefaultStyle: disabledFilledTonalButtonStyle,), selectedIcon: const Icon(Icons.settings),
] onPressed: () {
setState(() {
tonalSelected = !tonalSelected;
});
},
),
const SizedBox(width: 10),
IconButton.filledTonal(
isSelected: tonalSelected,
icon: const Icon(Icons.settings_outlined),
selectedIcon: const Icon(Icons.settings),
onPressed: null,
),
],
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
// Outlined IconButton IconButton.outlined(
DemoIconToggleButton(isEnabled: true, getDefaultStyle: enabledOutlinedButtonStyle,), isSelected: outlinedSelected,
SizedBox(width: 10), icon: const Icon(Icons.settings_outlined),
DemoIconToggleButton(isEnabled: false, getDefaultStyle: disabledOutlinedButtonStyle,), selectedIcon: const Icon(Icons.settings),
] onPressed: () {
),
]
),
);
}
}
class DemoIconToggleButton extends StatefulWidget {
const DemoIconToggleButton({required this.isEnabled, this.getDefaultStyle, super.key});
final bool isEnabled;
final ButtonStyle? Function(bool, ColorScheme)? getDefaultStyle;
@override
State<DemoIconToggleButton> createState() => _DemoIconToggleButtonState();
}
class _DemoIconToggleButtonState extends State<DemoIconToggleButton> {
bool selected = false;
@override
Widget build(BuildContext context) {
final ColorScheme colors = Theme.of(context).colorScheme;
final VoidCallback? onPressed = widget.isEnabled
? () {
setState(() { setState(() {
selected = !selected; outlinedSelected = !outlinedSelected;
}); });
} },
: null; ),
ButtonStyle? style; const SizedBox(width: 10),
if (widget.getDefaultStyle != null) { IconButton.outlined(
style = widget.getDefaultStyle!(selected, colors); isSelected: outlinedSelected,
}
return IconButton(
isSelected: selected,
icon: const Icon(Icons.settings_outlined), icon: const Icon(Icons.settings_outlined),
selectedIcon: const Icon(Icons.settings), selectedIcon: const Icon(Icons.settings),
onPressed: onPressed, onPressed: null,
style: style, ),
); ],
} ),
} ]
ButtonStyle enabledFilledButtonStyle(bool selected, ColorScheme colors) {
return IconButton.styleFrom(
foregroundColor: selected ? colors.onPrimary : colors.primary,
backgroundColor: selected ? colors.primary : colors.surfaceVariant,
disabledForegroundColor: colors.onSurface.withOpacity(0.38),
disabledBackgroundColor: colors.onSurface.withOpacity(0.12),
hoverColor: selected ? colors.onPrimary.withOpacity(0.08) : colors.primary.withOpacity(0.08),
focusColor: selected ? colors.onPrimary.withOpacity(0.12) : colors.primary.withOpacity(0.12),
highlightColor: selected ? colors.onPrimary.withOpacity(0.12) : colors.primary.withOpacity(0.12),
);
}
ButtonStyle disabledFilledButtonStyle(bool selected, ColorScheme colors) {
return IconButton.styleFrom(
disabledForegroundColor: colors.onSurface.withOpacity(0.38),
disabledBackgroundColor: colors.onSurface.withOpacity(0.12),
);
}
ButtonStyle enabledFilledTonalButtonStyle(bool selected, ColorScheme colors) {
return IconButton.styleFrom(
foregroundColor: selected ? colors.onSecondaryContainer : colors.onSurfaceVariant,
backgroundColor: selected ? colors.secondaryContainer : colors.surfaceVariant,
hoverColor: selected ? colors.onSecondaryContainer.withOpacity(0.08) : colors.onSurfaceVariant.withOpacity(0.08),
focusColor: selected ? colors.onSecondaryContainer.withOpacity(0.12) : colors.onSurfaceVariant.withOpacity(0.12),
highlightColor: selected ? colors.onSecondaryContainer.withOpacity(0.12) : colors.onSurfaceVariant.withOpacity(0.12),
);
}
ButtonStyle disabledFilledTonalButtonStyle(bool selected, ColorScheme colors) {
return IconButton.styleFrom(
disabledForegroundColor: colors.onSurface.withOpacity(0.38),
disabledBackgroundColor: colors.onSurface.withOpacity(0.12),
); );
}
ButtonStyle enabledOutlinedButtonStyle(bool selected, ColorScheme colors) {
return IconButton.styleFrom(
backgroundColor: selected ? colors.inverseSurface : null,
hoverColor: selected ? colors.onInverseSurface.withOpacity(0.08) : colors.onSurfaceVariant.withOpacity(0.08),
focusColor: selected ? colors.onInverseSurface.withOpacity(0.12) : colors.onSurfaceVariant.withOpacity(0.12),
highlightColor: selected ? colors.onInverseSurface.withOpacity(0.12) : colors.onSurface.withOpacity(0.12),
side: BorderSide(color: colors.outline),
).copyWith(
foregroundColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
return colors.onInverseSurface;
}
if (states.contains(MaterialState.pressed)) {
return colors.onSurface;
} }
return null;
}),
);
}
ButtonStyle disabledOutlinedButtonStyle(bool selected, ColorScheme colors) {
return IconButton.styleFrom(
disabledForegroundColor: colors.onSurface.withOpacity(0.38),
disabledBackgroundColor: selected ? colors.onSurface.withOpacity(0.12) : null,
side: selected ? null : BorderSide(color: colors.outline.withOpacity(0.12)),
);
} }
...@@ -30,6 +30,8 @@ import 'tooltip.dart'; ...@@ -30,6 +30,8 @@ import 'tooltip.dart';
// See: <https://material.io/design/usability/accessibility.html#layout-typography>. // See: <https://material.io/design/usability/accessibility.html#layout-typography>.
const double _kMinButtonSize = kMinInteractiveDimension; const double _kMinButtonSize = kMinInteractiveDimension;
enum _IconButtonVariant { standard, filled, filledTonal, outlined }
/// A Material Design icon button. /// A Material Design icon button.
/// ///
/// An icon button is a picture printed on a [Material] widget that reacts to /// An icon button is a picture printed on a [Material] widget that reacts to
...@@ -115,8 +117,9 @@ const double _kMinButtonSize = kMinInteractiveDimension; ...@@ -115,8 +117,9 @@ const double _kMinButtonSize = kMinInteractiveDimension;
/// {@end-tool} /// {@end-tool}
/// ///
/// Material Design 3 introduced new types (standard and contained) of [IconButton]s. /// Material Design 3 introduced new types (standard and contained) of [IconButton]s.
/// The default [IconButton] is the standard type, and contained icon buttons can be produced /// The default [IconButton] is the standard type. To create a filled icon button,
/// by configuring the [IconButton] widget's properties. /// use [IconButton.filled]; to create a filled tonal icon button, use [IconButton.filledTonal];
/// to create a outlined icon button, use [IconButton.outlined].
/// ///
/// Material Design 3 also treats [IconButton]s as toggle buttons. In order /// Material Design 3 also treats [IconButton]s as toggle buttons. In order
/// to not break existing apps, the toggle feature can be optionally controlled /// to not break existing apps, the toggle feature can be optionally controlled
...@@ -198,7 +201,104 @@ class IconButton extends StatelessWidget { ...@@ -198,7 +201,104 @@ class IconButton extends StatelessWidget {
this.isSelected, this.isSelected,
this.selectedIcon, this.selectedIcon,
required this.icon, required this.icon,
}) : assert(splashRadius == null || splashRadius > 0); }) : assert(splashRadius == null || splashRadius > 0),
_variant = _IconButtonVariant.standard;
/// Create a filled variant of IconButton.
///
/// Filled icon buttons have higher visual impact and should be used for
/// high emphasis actions, such as turning off a microphone or camera.
const IconButton.filled({
super.key,
this.iconSize,
this.visualDensity,
this.padding,
this.alignment,
this.splashRadius,
this.color,
this.focusColor,
this.hoverColor,
this.highlightColor,
this.splashColor,
this.disabledColor,
required this.onPressed,
this.mouseCursor,
this.focusNode,
this.autofocus = false,
this.tooltip,
this.enableFeedback,
this.constraints,
this.style,
this.isSelected,
this.selectedIcon,
required this.icon,
}) : assert(splashRadius == null || splashRadius > 0),
_variant = _IconButtonVariant.filled;
/// Create a filled tonal variant of IconButton.
///
/// Filled tonal icon buttons are a middle ground between filled and outlined
/// icon buttons. They’re useful in contexts where the button requires slightly
/// more emphasis than an outline would give, such as a secondary action paired
/// with a high emphasis action.
const IconButton.filledTonal({
super.key,
this.iconSize,
this.visualDensity,
this.padding,
this.alignment,
this.splashRadius,
this.color,
this.focusColor,
this.hoverColor,
this.highlightColor,
this.splashColor,
this.disabledColor,
required this.onPressed,
this.mouseCursor,
this.focusNode,
this.autofocus = false,
this.tooltip,
this.enableFeedback,
this.constraints,
this.style,
this.isSelected,
this.selectedIcon,
required this.icon,
}) : assert(splashRadius == null || splashRadius > 0),
_variant = _IconButtonVariant.filledTonal;
/// Create a filled tonal variant of IconButton.
///
/// Outlined icon buttons are medium-emphasis buttons. They’re useful when an
/// icon button needs more emphasis than a standard icon button but less than
/// a filled or filled tonal icon button.
const IconButton.outlined({
super.key,
this.iconSize,
this.visualDensity,
this.padding,
this.alignment,
this.splashRadius,
this.color,
this.focusColor,
this.hoverColor,
this.highlightColor,
this.splashColor,
this.disabledColor,
required this.onPressed,
this.mouseCursor,
this.focusNode,
this.autofocus = false,
this.tooltip,
this.enableFeedback,
this.constraints,
this.style,
this.isSelected,
this.selectedIcon,
required this.icon,
}) : assert(splashRadius == null || splashRadius > 0),
_variant = _IconButtonVariant.outlined;
/// The size of the icon inside the button. /// The size of the icon inside the button.
/// ///
...@@ -465,6 +565,8 @@ class IconButton extends StatelessWidget { ...@@ -465,6 +565,8 @@ class IconButton extends StatelessWidget {
/// * [ImageIcon], for showing icons from [AssetImage]s or other [ImageProvider]s. /// * [ImageIcon], for showing icons from [AssetImage]s or other [ImageProvider]s.
final Widget? selectedIcon; final Widget? selectedIcon;
final _IconButtonVariant _variant;
/// A static convenience method that constructs an icon button /// A static convenience method that constructs an icon button
/// [ButtonStyle] given simple values. This method is only used for Material 3. /// [ButtonStyle] given simple values. This method is only used for Material 3.
/// ///
...@@ -615,6 +717,7 @@ class IconButton extends StatelessWidget { ...@@ -615,6 +717,7 @@ class IconButton extends StatelessWidget {
autofocus: autofocus, autofocus: autofocus,
focusNode: focusNode, focusNode: focusNode,
isSelected: isSelected, isSelected: isSelected,
variant: _variant,
child: iconButton, child: iconButton,
); );
} }
...@@ -714,6 +817,7 @@ class _SelectableIconButton extends StatefulWidget { ...@@ -714,6 +817,7 @@ class _SelectableIconButton extends StatefulWidget {
this.isSelected, this.isSelected,
this.style, this.style,
this.focusNode, this.focusNode,
required this.variant,
required this.autofocus, required this.autofocus,
required this.onPressed, required this.onPressed,
required this.child, required this.child,
...@@ -722,6 +826,7 @@ class _SelectableIconButton extends StatefulWidget { ...@@ -722,6 +826,7 @@ class _SelectableIconButton extends StatefulWidget {
final bool? isSelected; final bool? isSelected;
final ButtonStyle? style; final ButtonStyle? style;
final FocusNode? focusNode; final FocusNode? focusNode;
final _IconButtonVariant variant;
final bool autofocus; final bool autofocus;
final VoidCallback? onPressed; final VoidCallback? onPressed;
final Widget child; final Widget child;
...@@ -761,12 +866,16 @@ class _SelectableIconButtonState extends State<_SelectableIconButton> { ...@@ -761,12 +866,16 @@ class _SelectableIconButtonState extends State<_SelectableIconButton> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final bool toggleable = widget.isSelected != null;
return _IconButtonM3( return _IconButtonM3(
statesController: statesController, statesController: statesController,
style: widget.style, style: widget.style,
autofocus: widget.autofocus, autofocus: widget.autofocus,
focusNode: widget.focusNode, focusNode: widget.focusNode,
onPressed: widget.onPressed, onPressed: widget.onPressed,
variant: widget.variant,
toggleable: toggleable,
child: widget.child, child: widget.child,
); );
} }
...@@ -779,6 +888,8 @@ class _IconButtonM3 extends ButtonStyleButton { ...@@ -779,6 +888,8 @@ class _IconButtonM3 extends ButtonStyleButton {
super.focusNode, super.focusNode,
super.autofocus = false, super.autofocus = false,
super.statesController, super.statesController,
required this.variant,
required this.toggleable,
required Widget super.child, required Widget super.child,
}) : super( }) : super(
onLongPress: null, onLongPress: null,
...@@ -786,6 +897,9 @@ class _IconButtonM3 extends ButtonStyleButton { ...@@ -786,6 +897,9 @@ class _IconButtonM3 extends ButtonStyleButton {
onFocusChange: null, onFocusChange: null,
clipBehavior: Clip.none); clipBehavior: Clip.none);
final _IconButtonVariant variant;
final bool toggleable;
/// ## Material 3 defaults /// ## Material 3 defaults
/// ///
/// If [ThemeData.useMaterial3] is set to true the following defaults will /// If [ThemeData.useMaterial3] is set to true the following defaults will
...@@ -825,7 +939,16 @@ class _IconButtonM3 extends ButtonStyleButton { ...@@ -825,7 +939,16 @@ class _IconButtonM3 extends ButtonStyleButton {
/// * `splashFactory` - Theme.splashFactory /// * `splashFactory` - Theme.splashFactory
@override @override
ButtonStyle defaultStyleOf(BuildContext context) { ButtonStyle defaultStyleOf(BuildContext context) {
return _IconButtonDefaultsM3(context); switch (variant) {
case _IconButtonVariant.filled:
return _FilledIconButtonDefaultsM3(context, toggleable);
case _IconButtonVariant.filledTonal:
return _FilledTonalIconButtonDefaultsM3(context, toggleable);
case _IconButtonVariant.outlined:
return _OutlinedIconButtonDefaultsM3(context, toggleable);
case _IconButtonVariant.standard:
return _IconButtonDefaultsM3(context, toggleable);
}
} }
/// Returns the [IconButtonThemeData.style] of the closest [IconButtonTheme] ancestor. /// Returns the [IconButtonThemeData.style] of the closest [IconButtonTheme] ancestor.
...@@ -963,7 +1086,7 @@ class _IconButtonDefaultMouseCursor extends MaterialStateProperty<MouseCursor> w ...@@ -963,7 +1086,7 @@ class _IconButtonDefaultMouseCursor extends MaterialStateProperty<MouseCursor> w
// Token database version: v0_158 // Token database version: v0_158
class _IconButtonDefaultsM3 extends ButtonStyle { class _IconButtonDefaultsM3 extends ButtonStyle {
_IconButtonDefaultsM3(this.context) _IconButtonDefaultsM3(this.context, this.toggleable)
: super( : super(
animationDuration: kThemeChangeDuration, animationDuration: kThemeChangeDuration,
enableFeedback: true, enableFeedback: true,
...@@ -971,6 +1094,7 @@ class _IconButtonDefaultsM3 extends ButtonStyle { ...@@ -971,6 +1094,7 @@ class _IconButtonDefaultsM3 extends ButtonStyle {
); );
final BuildContext context; final BuildContext context;
final bool toggleable;
late final ColorScheme _colors = Theme.of(context).colorScheme; late final ColorScheme _colors = Theme.of(context).colorScheme;
// No default text style // No default text style
...@@ -1014,7 +1138,7 @@ class _IconButtonDefaultsM3 extends ButtonStyle { ...@@ -1014,7 +1138,7 @@ class _IconButtonDefaultsM3 extends ButtonStyle {
if (states.contains(MaterialState.pressed)) { if (states.contains(MaterialState.pressed)) {
return _colors.onSurfaceVariant.withOpacity(0.12); return _colors.onSurfaceVariant.withOpacity(0.12);
} }
return null; return Colors.transparent;
}); });
@override @override
...@@ -1047,7 +1171,8 @@ class _IconButtonDefaultsM3 extends ButtonStyle { ...@@ -1047,7 +1171,8 @@ class _IconButtonDefaultsM3 extends ButtonStyle {
MaterialStateProperty<double>? get iconSize => MaterialStateProperty<double>? get iconSize =>
const MaterialStatePropertyAll<double>(24.0); const MaterialStatePropertyAll<double>(24.0);
// No default side @override
MaterialStateProperty<BorderSide?>? get side => null;
@override @override
MaterialStateProperty<OutlinedBorder>? get shape => MaterialStateProperty<OutlinedBorder>? get shape =>
...@@ -1073,3 +1198,442 @@ class _IconButtonDefaultsM3 extends ButtonStyle { ...@@ -1073,3 +1198,442 @@ class _IconButtonDefaultsM3 extends ButtonStyle {
} }
// END GENERATED TOKEN PROPERTIES - IconButton // END GENERATED TOKEN PROPERTIES - IconButton
// BEGIN GENERATED TOKEN PROPERTIES - FilledIconButton
// 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_158
class _FilledIconButtonDefaultsM3 extends ButtonStyle {
_FilledIconButtonDefaultsM3(this.context, this.toggleable)
: super(
animationDuration: kThemeChangeDuration,
enableFeedback: true,
alignment: Alignment.center,
);
final BuildContext context;
final bool toggleable;
late final ColorScheme _colors = Theme.of(context).colorScheme;
// No default text style
@override
MaterialStateProperty<Color?>? get backgroundColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return _colors.onSurface.withOpacity(0.12);
}
if (states.contains(MaterialState.selected)) {
return _colors.primary;
}
if (toggleable) { // toggleable but unselected case
return _colors.surfaceVariant;
}
return _colors.primary;
});
@override
MaterialStateProperty<Color?>? get foregroundColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return _colors.onSurface.withOpacity(0.38);
}
if (states.contains(MaterialState.selected)) {
return _colors.onPrimary;
}
if (toggleable) { // toggleable but unselected case
return _colors.primary;
}
return _colors.onPrimary;
});
@override
MaterialStateProperty<Color?>? get overlayColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.hovered)) {
return _colors.onPrimary.withOpacity(0.08);
}
if (states.contains(MaterialState.focused)) {
return _colors.onPrimary.withOpacity(0.12);
}
if (states.contains(MaterialState.pressed)) {
return _colors.onPrimary.withOpacity(0.12);
}
}
if (toggleable) { // toggleable but unselected case
if (states.contains(MaterialState.hovered)) {
return _colors.primary.withOpacity(0.08);
}
if (states.contains(MaterialState.focused)) {
return _colors.primary.withOpacity(0.12);
}
if (states.contains(MaterialState.pressed)) {
return _colors.primary.withOpacity(0.12);
}
}
if (states.contains(MaterialState.hovered)) {
return _colors.onPrimary.withOpacity(0.08);
}
if (states.contains(MaterialState.focused)) {
return _colors.onPrimary.withOpacity(0.12);
}
if (states.contains(MaterialState.pressed)) {
return _colors.onPrimary.withOpacity(0.12);
}
return Colors.transparent;
});
@override
MaterialStateProperty<double>? get elevation =>
const MaterialStatePropertyAll<double>(0.0);
@override
MaterialStateProperty<Color>? get shadowColor =>
const MaterialStatePropertyAll<Color>(Colors.transparent);
@override
MaterialStateProperty<Color>? get surfaceTintColor =>
const MaterialStatePropertyAll<Color>(Colors.transparent);
@override
MaterialStateProperty<EdgeInsetsGeometry>? get padding =>
const MaterialStatePropertyAll<EdgeInsetsGeometry>(EdgeInsets.all(8.0));
@override
MaterialStateProperty<Size>? get minimumSize =>
const MaterialStatePropertyAll<Size>(Size(40.0, 40.0));
// No default fixedSize
@override
MaterialStateProperty<Size>? get maximumSize =>
const MaterialStatePropertyAll<Size>(Size.infinite);
@override
MaterialStateProperty<double>? get iconSize =>
const MaterialStatePropertyAll<double>(24.0);
@override
MaterialStateProperty<BorderSide?>? get side => null;
@override
MaterialStateProperty<OutlinedBorder>? get shape =>
const MaterialStatePropertyAll<OutlinedBorder>(StadiumBorder());
@override
MaterialStateProperty<MouseCursor?>? get mouseCursor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return SystemMouseCursors.basic;
}
return SystemMouseCursors.click;
});
@override
VisualDensity? get visualDensity => VisualDensity.standard;
@override
MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize;
@override
InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory;
}
// END GENERATED TOKEN PROPERTIES - FilledIconButton
// BEGIN GENERATED TOKEN PROPERTIES - FilledTonalIconButton
// 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_158
class _FilledTonalIconButtonDefaultsM3 extends ButtonStyle {
_FilledTonalIconButtonDefaultsM3(this.context, this.toggleable)
: super(
animationDuration: kThemeChangeDuration,
enableFeedback: true,
alignment: Alignment.center,
);
final BuildContext context;
final bool toggleable;
late final ColorScheme _colors = Theme.of(context).colorScheme;
// No default text style
@override
MaterialStateProperty<Color?>? get backgroundColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return _colors.onSurface.withOpacity(0.12);
}
if (states.contains(MaterialState.selected)) {
return _colors.secondaryContainer;
}
if (toggleable) { // toggleable but unselected case
return _colors.surfaceVariant;
}
return _colors.secondaryContainer;
});
@override
MaterialStateProperty<Color?>? get foregroundColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return _colors.onSurface.withOpacity(0.38);
}
if (states.contains(MaterialState.selected)) {
return _colors.onSecondaryContainer;
}
if (toggleable) { // toggleable but unselected case
return _colors.onSurfaceVariant;
}
return _colors.onSecondaryContainer;
});
@override
MaterialStateProperty<Color?>? get overlayColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.hovered)) {
return _colors.onSecondaryContainer.withOpacity(0.08);
}
if (states.contains(MaterialState.focused)) {
return _colors.onSecondaryContainer.withOpacity(0.12);
}
if (states.contains(MaterialState.pressed)) {
return _colors.onSecondaryContainer.withOpacity(0.12);
}
}
if (toggleable) { // toggleable but unselected case
if (states.contains(MaterialState.hovered)) {
return _colors.onSurfaceVariant.withOpacity(0.08);
}
if (states.contains(MaterialState.focused)) {
return _colors.onSurfaceVariant.withOpacity(0.12);
}
if (states.contains(MaterialState.pressed)) {
return _colors.onSurfaceVariant.withOpacity(0.12);
}
}
if (states.contains(MaterialState.hovered)) {
return _colors.onSecondaryContainer.withOpacity(0.08);
}
if (states.contains(MaterialState.focused)) {
return _colors.onSecondaryContainer.withOpacity(0.12);
}
if (states.contains(MaterialState.pressed)) {
return _colors.onSecondaryContainer.withOpacity(0.12);
}
return Colors.transparent;
});
@override
MaterialStateProperty<double>? get elevation =>
const MaterialStatePropertyAll<double>(0.0);
@override
MaterialStateProperty<Color>? get shadowColor =>
const MaterialStatePropertyAll<Color>(Colors.transparent);
@override
MaterialStateProperty<Color>? get surfaceTintColor =>
const MaterialStatePropertyAll<Color>(Colors.transparent);
@override
MaterialStateProperty<EdgeInsetsGeometry>? get padding =>
const MaterialStatePropertyAll<EdgeInsetsGeometry>(EdgeInsets.all(8.0));
@override
MaterialStateProperty<Size>? get minimumSize =>
const MaterialStatePropertyAll<Size>(Size(40.0, 40.0));
// No default fixedSize
@override
MaterialStateProperty<Size>? get maximumSize =>
const MaterialStatePropertyAll<Size>(Size.infinite);
@override
MaterialStateProperty<double>? get iconSize =>
const MaterialStatePropertyAll<double>(24.0);
@override
MaterialStateProperty<BorderSide?>? get side => null;
@override
MaterialStateProperty<OutlinedBorder>? get shape =>
const MaterialStatePropertyAll<OutlinedBorder>(StadiumBorder());
@override
MaterialStateProperty<MouseCursor?>? get mouseCursor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return SystemMouseCursors.basic;
}
return SystemMouseCursors.click;
});
@override
VisualDensity? get visualDensity => VisualDensity.standard;
@override
MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize;
@override
InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory;
}
// END GENERATED TOKEN PROPERTIES - FilledTonalIconButton
// BEGIN GENERATED TOKEN PROPERTIES - OutlinedIconButton
// 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_158
class _OutlinedIconButtonDefaultsM3 extends ButtonStyle {
_OutlinedIconButtonDefaultsM3(this.context, this.toggleable)
: super(
animationDuration: kThemeChangeDuration,
enableFeedback: true,
alignment: Alignment.center,
);
final BuildContext context;
final bool toggleable;
late final ColorScheme _colors = Theme.of(context).colorScheme;
// No default text style
@override
MaterialStateProperty<Color?>? get backgroundColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
if (states.contains(MaterialState.selected)) {
return _colors.onSurface.withOpacity(0.12);
}
return Colors.transparent;
}
if (states.contains(MaterialState.selected)) {
return _colors.inverseSurface;
}
return Colors.transparent;
});
@override
MaterialStateProperty<Color?>? get foregroundColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return _colors.onSurface.withOpacity(0.38);
}
if (states.contains(MaterialState.selected)) {
return _colors.onInverseSurface;
}
return _colors.onSurfaceVariant;
});
@override
MaterialStateProperty<Color?>? get overlayColor => MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.hovered)) {
return _colors.onInverseSurface.withOpacity(0.08);
}
if (states.contains(MaterialState.focused)) {
return _colors.onInverseSurface.withOpacity(0.08);
}
if (states.contains(MaterialState.pressed)) {
return _colors.onInverseSurface.withOpacity(0.12);
}
}
if (states.contains(MaterialState.hovered)) {
return _colors.onSurfaceVariant.withOpacity(0.08);
}
if (states.contains(MaterialState.focused)) {
return _colors.onSurfaceVariant.withOpacity(0.08);
}
if (states.contains(MaterialState.pressed)) {
return _colors.onSurface.withOpacity(0.12);
}
return Colors.transparent;
});
@override
MaterialStateProperty<double>? get elevation =>
const MaterialStatePropertyAll<double>(0.0);
@override
MaterialStateProperty<Color>? get shadowColor =>
const MaterialStatePropertyAll<Color>(Colors.transparent);
@override
MaterialStateProperty<Color>? get surfaceTintColor =>
const MaterialStatePropertyAll<Color>(Colors.transparent);
@override
MaterialStateProperty<EdgeInsetsGeometry>? get padding =>
const MaterialStatePropertyAll<EdgeInsetsGeometry>(EdgeInsets.all(8.0));
@override
MaterialStateProperty<Size>? get minimumSize =>
const MaterialStatePropertyAll<Size>(Size(40.0, 40.0));
// No default fixedSize
@override
MaterialStateProperty<Size>? get maximumSize =>
const MaterialStatePropertyAll<Size>(Size.infinite);
@override
MaterialStateProperty<double>? get iconSize =>
const MaterialStatePropertyAll<double>(24.0);
@override
MaterialStateProperty<BorderSide?>? get side =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
return null;
} else {
if (states.contains(MaterialState.disabled)) {
return BorderSide(color: _colors.onSurface.withOpacity(0.12));
}
return BorderSide(color: _colors.outline);
}
});
@override
MaterialStateProperty<OutlinedBorder>? get shape =>
const MaterialStatePropertyAll<OutlinedBorder>(StadiumBorder());
@override
MaterialStateProperty<MouseCursor?>? get mouseCursor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return SystemMouseCursors.basic;
}
return SystemMouseCursors.click;
});
@override
VisualDensity? get visualDensity => VisualDensity.standard;
@override
MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize;
@override
InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory;
}
// END GENERATED TOKEN PROPERTIES - OutlinedIconButton
...@@ -1133,6 +1133,609 @@ void main() { ...@@ -1133,6 +1133,609 @@ void main() {
expect(material.type, MaterialType.button); expect(material.type, MaterialType.button);
}); });
testWidgets('IconButton.fill defaults - M3', (WidgetTester tester) async {
final ThemeData themeM3 = ThemeData.from(colorScheme: colorScheme, useMaterial3: true);
// Enabled IconButton
await tester.pumpWidget(
MaterialApp(
theme: themeM3,
home: Center(
child: IconButton.filled(
onPressed: () { },
icon: const Icon(Icons.ac_unit),
),
),
),
);
final Finder buttonMaterial = find.descendant(
of: find.byType(IconButton),
matching: find.byType(Material),
);
Color? iconColor() => _iconStyle(tester, Icons.ac_unit)?.color;
expect(iconColor(), colorScheme.onPrimary);
Material material = tester.widget<Material>(buttonMaterial);
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, colorScheme.primary);
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, const StadiumBorder());
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
final Align align = tester.firstWidget<Align>(find.ancestor(of: find.byIcon(Icons.ac_unit), matching: find.byType(Align)));
expect(align.alignment, Alignment.center);
expect(tester.getSize(find.byIcon(Icons.ac_unit)), const Size(24.0, 24.0));
final Offset center = tester.getCenter(find.byType(IconButton));
final TestGesture gesture = await tester.startGesture(center);
await tester.pump(); // start the splash animation
await tester.pump(const Duration(milliseconds: 100)); // splash is underway
await gesture.up();
await tester.pumpAndSettle();
material = tester.widget<Material>(buttonMaterial);
// No change vs enabled and not pressed.
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, colorScheme.primary);
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, const StadiumBorder());
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
// Disabled IconButton
await tester.pumpWidget(
MaterialApp(
theme: themeM3,
home: const Center(
child: IconButton.filled(
onPressed: null,
icon: Icon(Icons.ac_unit),
),
),
),
);
material = tester.widget<Material>(buttonMaterial);
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, colorScheme.onSurface.withOpacity(0.12));
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, const StadiumBorder());
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
expect(iconColor(), colorScheme.onSurface.withOpacity(0.38));
});
testWidgets('Toggleable IconButton.fill defaults - M3', (WidgetTester tester) async {
final ThemeData themeM3 = ThemeData.from(colorScheme: colorScheme, useMaterial3: true);
// Enabled selected IconButton
await tester.pumpWidget(
MaterialApp(
theme: themeM3,
home: Center(
child: IconButton.filled(
isSelected: true,
onPressed: () { },
icon: const Icon(Icons.ac_unit),
),
),
),
);
final Finder buttonMaterial = find.descendant(
of: find.byType(IconButton),
matching: find.byType(Material),
);
Color? iconColor() => _iconStyle(tester, Icons.ac_unit)?.color;
expect(iconColor(), colorScheme.onPrimary);
Material material = tester.widget<Material>(buttonMaterial);
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, colorScheme.primary);
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, const StadiumBorder());
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
final Align align = tester.firstWidget<Align>(find.ancestor(of: find.byIcon(Icons.ac_unit), matching: find.byType(Align)));
expect(align.alignment, Alignment.center);
expect(tester.getSize(find.byIcon(Icons.ac_unit)), const Size(24.0, 24.0));
final Offset center = tester.getCenter(find.byType(IconButton));
final TestGesture gesture = await tester.startGesture(center);
await tester.pump(); // start the splash animation
await tester.pump(const Duration(milliseconds: 100)); // splash is underway
await gesture.up();
await tester.pumpAndSettle();
material = tester.widget<Material>(buttonMaterial);
// No change vs enabled and not pressed.
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, colorScheme.primary);
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, const StadiumBorder());
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
// Enabled unselected IconButton
await tester.pumpWidget(
MaterialApp(
theme: themeM3,
home: Center(
child: IconButton.filled(
isSelected: false,
onPressed: () { },
icon: const Icon(Icons.ac_unit),
),
),
),
);
material = tester.widget<Material>(buttonMaterial);
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, colorScheme.surfaceVariant);
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, const StadiumBorder());
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
expect(iconColor(), colorScheme.primary);
// Disabled IconButton
await tester.pumpWidget(
MaterialApp(
theme: themeM3,
home: const Center(
child: IconButton.filled(
isSelected: true,
onPressed: null,
icon: Icon(Icons.ac_unit),
),
),
),
);
material = tester.widget<Material>(buttonMaterial);
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, colorScheme.onSurface.withOpacity(0.12));
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, const StadiumBorder());
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
expect(iconColor(), colorScheme.onSurface.withOpacity(0.38));
});
testWidgets('IconButton.filledTonal defaults - M3', (WidgetTester tester) async {
final ThemeData themeM3 = ThemeData.from(colorScheme: colorScheme, useMaterial3: true);
// Enabled IconButton.tonal
await tester.pumpWidget(
MaterialApp(
theme: themeM3,
home: Center(
child: IconButton.filledTonal(
onPressed: () { },
icon: const Icon(Icons.ac_unit),
),
),
),
);
final Finder buttonMaterial = find.descendant(
of: find.byType(IconButton),
matching: find.byType(Material),
);
Color? iconColor() => _iconStyle(tester, Icons.ac_unit)?.color;
expect(iconColor(), colorScheme.onSecondaryContainer);
Material material = tester.widget<Material>(buttonMaterial);
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, colorScheme.secondaryContainer);
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, const StadiumBorder());
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
final Align align = tester.firstWidget<Align>(find.ancestor(of: find.byIcon(Icons.ac_unit), matching: find.byType(Align)));
expect(align.alignment, Alignment.center);
expect(tester.getSize(find.byIcon(Icons.ac_unit)), const Size(24.0, 24.0));
final Offset center = tester.getCenter(find.byType(IconButton));
final TestGesture gesture = await tester.startGesture(center);
await tester.pump(); // start the splash animation
await tester.pump(const Duration(milliseconds: 100)); // splash is underway
await gesture.up();
await tester.pumpAndSettle();
material = tester.widget<Material>(buttonMaterial);
// No change vs enabled and not pressed.
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, colorScheme.secondaryContainer);
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, const StadiumBorder());
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
// Disabled IconButton
await tester.pumpWidget(
MaterialApp(
theme: themeM3,
home: const Center(
child: IconButton.filledTonal(
onPressed: null,
icon: Icon(Icons.ac_unit),
),
),
),
);
material = tester.widget<Material>(buttonMaterial);
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, colorScheme.onSurface.withOpacity(0.12));
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, const StadiumBorder());
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
expect(iconColor(), colorScheme.onSurface.withOpacity(0.38));
});
testWidgets('Toggleable IconButton.filledTonal defaults - M3', (WidgetTester tester) async {
final ThemeData themeM3 = ThemeData.from(colorScheme: colorScheme, useMaterial3: true);
// Enabled selected IconButton
await tester.pumpWidget(
MaterialApp(
theme: themeM3,
home: Center(
child: IconButton.filledTonal(
isSelected: true,
onPressed: () { },
icon: const Icon(Icons.ac_unit),
),
),
),
);
final Finder buttonMaterial = find.descendant(
of: find.byType(IconButton),
matching: find.byType(Material),
);
Color? iconColor() => _iconStyle(tester, Icons.ac_unit)?.color;
expect(iconColor(), colorScheme.onSecondaryContainer);
Material material = tester.widget<Material>(buttonMaterial);
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, colorScheme.secondaryContainer);
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, const StadiumBorder());
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
final Align align = tester.firstWidget<Align>(find.ancestor(of: find.byIcon(Icons.ac_unit), matching: find.byType(Align)));
expect(align.alignment, Alignment.center);
expect(tester.getSize(find.byIcon(Icons.ac_unit)), const Size(24.0, 24.0));
final Offset center = tester.getCenter(find.byType(IconButton));
final TestGesture gesture = await tester.startGesture(center);
await tester.pump(); // start the splash animation
await tester.pump(const Duration(milliseconds: 100)); // splash is underway
await gesture.up();
await tester.pumpAndSettle();
material = tester.widget<Material>(buttonMaterial);
// No change vs enabled and not pressed.
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, colorScheme.secondaryContainer);
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, const StadiumBorder());
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
// Enabled unselected IconButton
await tester.pumpWidget(
MaterialApp(
theme: themeM3,
home: Center(
child: IconButton.filledTonal(
isSelected: false,
onPressed: () { },
icon: const Icon(Icons.ac_unit),
),
),
),
);
material = tester.widget<Material>(buttonMaterial);
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, colorScheme.surfaceVariant);
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, const StadiumBorder());
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
expect(iconColor(), colorScheme.onSurfaceVariant);
// Disabled IconButton
await tester.pumpWidget(
MaterialApp(
theme: themeM3,
home: const Center(
child: IconButton.filledTonal(
isSelected: true,
onPressed: null,
icon: Icon(Icons.ac_unit),
),
),
),
);
material = tester.widget<Material>(buttonMaterial);
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, colorScheme.onSurface.withOpacity(0.12));
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, const StadiumBorder());
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
expect(iconColor(), colorScheme.onSurface.withOpacity(0.38));
});
testWidgets('IconButton.outlined defaults - M3', (WidgetTester tester) async {
final ThemeData themeM3 = ThemeData.from(colorScheme: colorScheme, useMaterial3: true);
// Enabled IconButton.tonal
await tester.pumpWidget(
MaterialApp(
theme: themeM3,
home: Center(
child: IconButton.outlined(
onPressed: () { },
icon: const Icon(Icons.ac_unit),
),
),
),
);
final Finder buttonMaterial = find.descendant(
of: find.byType(IconButton),
matching: find.byType(Material),
);
Color? iconColor() => _iconStyle(tester, Icons.ac_unit)?.color;
expect(iconColor(), colorScheme.onSurfaceVariant);
Material material = tester.widget<Material>(buttonMaterial);
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, Colors.transparent);
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, StadiumBorder(side: BorderSide(color: colorScheme.outline)));
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
final Align align = tester.firstWidget<Align>(find.ancestor(of: find.byIcon(Icons.ac_unit), matching: find.byType(Align)));
expect(align.alignment, Alignment.center);
expect(tester.getSize(find.byIcon(Icons.ac_unit)), const Size(24.0, 24.0));
final Offset center = tester.getCenter(find.byType(IconButton));
final TestGesture gesture = await tester.startGesture(center);
await tester.pump(); // start the splash animation
await tester.pump(const Duration(milliseconds: 100)); // splash is underway
await gesture.up();
await tester.pumpAndSettle();
material = tester.widget<Material>(buttonMaterial);
// No change vs enabled and not pressed.
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, Colors.transparent);
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, StadiumBorder(side: BorderSide(color: colorScheme.outline)));
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
// Disabled IconButton
await tester.pumpWidget(
MaterialApp(
theme: themeM3,
home: const Center(
child: IconButton.outlined(
onPressed: null,
icon: Icon(Icons.ac_unit),
),
),
),
);
material = tester.widget<Material>(buttonMaterial);
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, Colors.transparent);
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, StadiumBorder(side: BorderSide(color: colorScheme.onSurface.withOpacity(0.12))));
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
expect(iconColor(), colorScheme.onSurface.withOpacity(0.38));
});
testWidgets('Toggleable IconButton.outlined defaults - M3', (WidgetTester tester) async {
final ThemeData themeM3 = ThemeData.from(colorScheme: colorScheme, useMaterial3: true);
// Enabled selected IconButton
await tester.pumpWidget(
MaterialApp(
theme: themeM3,
home: Center(
child: IconButton.outlined(
isSelected: true,
onPressed: () { },
icon: const Icon(Icons.ac_unit),
),
),
),
);
final Finder buttonMaterial = find.descendant(
of: find.byType(IconButton),
matching: find.byType(Material),
);
Color? iconColor() => _iconStyle(tester, Icons.ac_unit)?.color;
expect(iconColor(), colorScheme.onInverseSurface);
Material material = tester.widget<Material>(buttonMaterial);
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, colorScheme.inverseSurface);
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, const StadiumBorder());
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
final Align align = tester.firstWidget<Align>(find.ancestor(of: find.byIcon(Icons.ac_unit), matching: find.byType(Align)));
expect(align.alignment, Alignment.center);
expect(tester.getSize(find.byIcon(Icons.ac_unit)), const Size(24.0, 24.0));
final Offset center = tester.getCenter(find.byType(IconButton));
final TestGesture gesture = await tester.startGesture(center);
await tester.pump(); // start the splash animation
await tester.pump(const Duration(milliseconds: 100)); // splash is underway
await gesture.up();
await tester.pumpAndSettle();
material = tester.widget<Material>(buttonMaterial);
// No change vs enabled and not pressed.
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, colorScheme.inverseSurface);
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, const StadiumBorder());
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
// Enabled unselected IconButton
await tester.pumpWidget(
MaterialApp(
theme: themeM3,
home: Center(
child: IconButton.outlined(
isSelected: false,
onPressed: () { },
icon: const Icon(Icons.ac_unit),
),
),
),
);
material = tester.widget<Material>(buttonMaterial);
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, Colors.transparent);
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, StadiumBorder(side: BorderSide(color: colorScheme.outline)));
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
expect(iconColor(), colorScheme.onSurfaceVariant);
// Disabled IconButton
await tester.pumpWidget(
MaterialApp(
theme: themeM3,
home: const Center(
child: IconButton.outlined(
isSelected: true,
onPressed: null,
icon: Icon(Icons.ac_unit),
),
),
),
);
material = tester.widget<Material>(buttonMaterial);
expect(material.animationDuration, const Duration(milliseconds: 200));
expect(material.borderOnForeground, true);
expect(material.borderRadius, null);
expect(material.clipBehavior, Clip.none);
expect(material.color, colorScheme.onSurface.withOpacity(0.12));
expect(material.elevation, 0.0);
expect(material.shadowColor, Colors.transparent);
expect(material.shape, const StadiumBorder());
expect(material.textStyle, null);
expect(material.type, MaterialType.button);
expect(iconColor(), colorScheme.onSurface.withOpacity(0.38));
});
testWidgets('Default IconButton meets a11y contrast guidelines - M3', (WidgetTester tester) async { testWidgets('Default IconButton meets a11y contrast guidelines - M3', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode(); final FocusNode focusNode = FocusNode();
......
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