From 6589f900131d86ac28e23c5c2271964c3f145761 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Thu, 28 May 2026 17:24:05 -0700 Subject: [PATCH 01/31] Add M3E IconButton --- .../material_ui/lib/src/button_style.dart | 80 +- .../generated/icon_button_defaults_m3e.g.dart | 1056 +++++++++++++++++ packages/material_ui/lib/src/icon_button.dart | 86 +- .../lib/src/icon_button_theme.dart | 21 +- .../material_ui/test/icon_button_test.dart | 734 ++++++++++++ .../test/icon_button_theme_test.dart | 30 + .../tool/gen_defaults/bin/gen_defaults.dart | 5 +- .../templates/icon_button_template.dart | 771 ++++++++++++ 8 files changed, 2768 insertions(+), 15 deletions(-) create mode 100644 packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart create mode 100644 packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart diff --git a/packages/material_ui/lib/src/button_style.dart b/packages/material_ui/lib/src/button_style.dart index e251296f42ed..95666b215b46 100644 --- a/packages/material_ui/lib/src/button_style.dart +++ b/packages/material_ui/lib/src/button_style.dart @@ -31,6 +31,47 @@ import 'theme_data.dart'; // late BuildContext context; // typedef MyAppHome = Placeholder; +/// Defines size variants for Material 3 Expressive button components. +/// +/// Components interpret each size variant according to their own token set. +enum ButtonSize { + /// Extra small button size. + xSmall, + + /// Small button size. This is the default for icon buttons. + small, + + /// Medium button size. + medium, + + /// Large button size. + large, + + /// Extra large button size. + xLarge, +} + +/// Defines the width variants for Material 3 Expressive [IconButton]. +enum IconButtonWidth { + /// Uses the narrow leading and trailing space tokens. + narrow, + + /// Uses the default leading and trailing space tokens. + standard, + + /// Uses the wide leading and trailing space tokens. + wide, +} + +/// Defines the shape variants for Material 3 Expressive [IconButton]. +enum IconButtonShape { + /// Uses the round shape tokens. + round, + + /// Uses the square shape tokens. + square, +} + /// The type for [ButtonStyle.backgroundBuilder] and [ButtonStyle.foregroundBuilder]. /// /// The [states] parameter is the button's current pressed/hovered/etc state. The [child] is @@ -187,6 +228,9 @@ class ButtonStyle with Diagnosticable { this.splashFactory, this.backgroundBuilder, this.foregroundBuilder, + this.size, + this.iconButtonWidth, + this.iconButtonShape, }); /// The style for a button's [Text] widget descendants. @@ -423,6 +467,15 @@ class ButtonStyle with Diagnosticable { /// configuring clipping. final ButtonLayerBuilder? foregroundBuilder; + /// The size variant for this button. + final ButtonSize? size; + + /// The width variant for this icon button. + final IconButtonWidth? iconButtonWidth; + + /// The shape variant for this icon button. + final IconButtonShape? iconButtonShape; + /// Returns a copy of this ButtonStyle with the given fields replaced with /// the new values. ButtonStyle copyWith({ @@ -451,6 +504,9 @@ class ButtonStyle with Diagnosticable { InteractiveInkFeatureFactory? splashFactory, ButtonLayerBuilder? backgroundBuilder, ButtonLayerBuilder? foregroundBuilder, + ButtonSize? size, + IconButtonWidth? iconButtonWidth, + IconButtonShape? iconButtonShape, }) { return ButtonStyle( textStyle: textStyle ?? this.textStyle, @@ -478,6 +534,9 @@ class ButtonStyle with Diagnosticable { splashFactory: splashFactory ?? this.splashFactory, backgroundBuilder: backgroundBuilder ?? this.backgroundBuilder, foregroundBuilder: foregroundBuilder ?? this.foregroundBuilder, + size: size ?? this.size, + iconButtonWidth: iconButtonWidth ?? this.iconButtonWidth, + iconButtonShape: iconButtonShape ?? this.iconButtonShape, ); } @@ -516,6 +575,9 @@ class ButtonStyle with Diagnosticable { splashFactory: splashFactory ?? style.splashFactory, backgroundBuilder: backgroundBuilder ?? style.backgroundBuilder, foregroundBuilder: foregroundBuilder ?? style.foregroundBuilder, + size: size ?? style.size, + iconButtonWidth: iconButtonWidth ?? style.iconButtonWidth, + iconButtonShape: iconButtonShape ?? style.iconButtonShape, ); } @@ -547,6 +609,9 @@ class ButtonStyle with Diagnosticable { splashFactory, backgroundBuilder, foregroundBuilder, + size, + iconButtonWidth, + iconButtonShape, ]; return Object.hashAll(values); } @@ -584,7 +649,10 @@ class ButtonStyle with Diagnosticable { other.alignment == alignment && other.splashFactory == splashFactory && other.backgroundBuilder == backgroundBuilder && - other.foregroundBuilder == foregroundBuilder; + other.foregroundBuilder == foregroundBuilder && + other.size == size && + other.iconButtonWidth == iconButtonWidth && + other.iconButtonShape == iconButtonShape; } @override @@ -706,6 +774,13 @@ class ButtonStyle with Diagnosticable { defaultValue: null, ), ); + properties.add(EnumProperty('size', size, defaultValue: null)); + properties.add( + EnumProperty('iconButtonWidth', iconButtonWidth, defaultValue: null), + ); + properties.add( + EnumProperty('iconButtonShape', iconButtonShape, defaultValue: null), + ); } /// Linearly interpolate between two [ButtonStyle]s. @@ -769,6 +844,9 @@ class ButtonStyle with Diagnosticable { splashFactory: t < 0.5 ? a?.splashFactory : b?.splashFactory, backgroundBuilder: t < 0.5 ? a?.backgroundBuilder : b?.backgroundBuilder, foregroundBuilder: t < 0.5 ? a?.foregroundBuilder : b?.foregroundBuilder, + size: t < 0.5 ? a?.size : b?.size, + iconButtonWidth: t < 0.5 ? a?.iconButtonWidth : b?.iconButtonWidth, + iconButtonShape: t < 0.5 ? a?.iconButtonShape : b?.iconButtonShape, ); } } diff --git a/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart b/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart new file mode 100644 index 000000000000..9ee830af00c8 --- /dev/null +++ b/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart @@ -0,0 +1,1056 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Do not edit by hand. The code is generated from data in the Material +// Design token database by the script: +// packages/material_ui/tool/gen_defaults/bin/gen_defaults.dart. +part of '../icon_button.dart'; + +class _IconButtonDefaultsM3E extends ButtonStyle { + _IconButtonDefaultsM3E( + this.context, + this.toggleable, + this.buttonSize, + this.buttonWidth, + this.buttonShape, + ) : super( + animationDuration: kThemeChangeDuration, + enableFeedback: true, + alignment: Alignment.center, + ); + + final BuildContext context; + final bool toggleable; + final ButtonSize? buttonSize; + final IconButtonWidth? buttonWidth; + final IconButtonShape? buttonShape; + late final ColorScheme _colors = Theme.of(context).colorScheme; + + @override + WidgetStateProperty? get backgroundColor => + const MaterialStatePropertyAll(Colors.transparent); + + @override + WidgetStateProperty? get foregroundColor => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.disabled)) { + return _colors.onSurface.withOpacity(0.38); + } + if (toggleable && states.contains(WidgetState.selected)) { + return _colors.primary; + } + return _colors.onSurfaceVariant; + }); + + @override + WidgetStateProperty? get overlayColor => + WidgetStateProperty.resolveWith((Set states) { + if (toggleable && states.contains(WidgetState.selected)) { + if (states.contains(WidgetState.pressed)) { + return _colors.primary.withOpacity(0.1); + } + if (states.contains(WidgetState.hovered)) { + return _colors.primary.withOpacity(0.08); + } + if (states.contains(WidgetState.focused)) { + return _colors.primary.withOpacity(0.1); + } + } + if (states.contains(WidgetState.pressed)) { + return _colors.onSurfaceVariant.withOpacity(0.1); + } + if (states.contains(WidgetState.hovered)) { + return _colors.onSurfaceVariant.withOpacity(0.08); + } + if (states.contains(WidgetState.focused)) { + return _colors.onSurfaceVariant.withOpacity(0.1); + } + return Colors.transparent; + }); + + @override + WidgetStateProperty? get elevation => const MaterialStatePropertyAll(0.0); + + @override + WidgetStateProperty? get shadowColor => + const MaterialStatePropertyAll(Colors.transparent); + + @override + WidgetStateProperty? get surfaceTintColor => + const MaterialStatePropertyAll(Colors.transparent); + + @override + WidgetStateProperty? get padding => + MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), + }, + ButtonSize.small => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), + }, + ButtonSize.medium => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(16.0, 16.0, 16.0, 16.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), + }, + ButtonSize.large => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(32.0, 32.0, 32.0, 32.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), + }, + ButtonSize.xLarge => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(48.0, 48.0, 48.0, 48.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), + }, + }); + + @override + WidgetStateProperty? get minimumSize => + MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(28.0, 32.0), + IconButtonWidth.standard => const Size(32.0, 32.0), + IconButtonWidth.wide => const Size(40.0, 32.0), + }, + ButtonSize.small => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(32.0, 40.0), + IconButtonWidth.standard => const Size(40.0, 40.0), + IconButtonWidth.wide => const Size(52.0, 40.0), + }, + ButtonSize.medium => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(48.0, 56.0), + IconButtonWidth.standard => const Size(56.0, 56.0), + IconButtonWidth.wide => const Size(72.0, 56.0), + }, + ButtonSize.large => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(64.0, 96.0), + IconButtonWidth.standard => const Size(96.0, 96.0), + IconButtonWidth.wide => const Size(128.0, 96.0), + }, + ButtonSize.xLarge => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(104.0, 136.0), + IconButtonWidth.standard => const Size(136.0, 136.0), + IconButtonWidth.wide => const Size(184.0, 136.0), + }, + }); + + @override + WidgetStateProperty? get maximumSize => const MaterialStatePropertyAll(Size.infinite); + + @override + WidgetStateProperty? get iconSize => + MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => 20.0, + ButtonSize.small => 24.0, + ButtonSize.medium => 24.0, + ButtonSize.large => 32.0, + ButtonSize.xLarge => 40.0, + }); + + @override + WidgetStateProperty? get shape => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.pressed)) { + return switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(8.0)), + ), + ButtonSize.small => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(8.0)), + ), + ButtonSize.medium => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.large => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)), + ), + ButtonSize.xLarge => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)), + ), + }; + } + if (toggleable && states.contains(WidgetState.selected)) { + return switch (buttonShape ?? IconButtonShape.round) { + IconButtonShape.round => switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.small => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.medium => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)), + ), + ButtonSize.large => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(28.0)), + ), + ButtonSize.xLarge => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(28.0)), + ), + }, + IconButtonShape.square => switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const StadiumBorder(), + ButtonSize.small => const StadiumBorder(), + ButtonSize.medium => const StadiumBorder(), + ButtonSize.large => const StadiumBorder(), + ButtonSize.xLarge => const StadiumBorder(), + }, + }; + } + return switch (buttonShape ?? IconButtonShape.round) { + IconButtonShape.round => switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const StadiumBorder(), + ButtonSize.small => const StadiumBorder(), + ButtonSize.medium => const StadiumBorder(), + ButtonSize.large => const StadiumBorder(), + ButtonSize.xLarge => const StadiumBorder(), + }, + IconButtonShape.square => switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.small => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.medium => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)), + ), + ButtonSize.large => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(28.0)), + ), + ButtonSize.xLarge => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(28.0)), + ), + }, + }; + }); + + @override + WidgetStateProperty? get side => null; + + @override + WidgetStateProperty? get mouseCursor => WidgetStateMouseCursor.adaptiveClickable; + + @override + VisualDensity? get visualDensity => VisualDensity.standard; + + @override + MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + + @override + InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; +} + +class _M3EFilledIconButtonDefaults extends ButtonStyle { + _M3EFilledIconButtonDefaults( + this.context, + this.toggleable, + this.buttonSize, + this.buttonWidth, + this.buttonShape, + ) : super( + animationDuration: kThemeChangeDuration, + enableFeedback: true, + alignment: Alignment.center, + ); + + final BuildContext context; + final bool toggleable; + final ButtonSize? buttonSize; + final IconButtonWidth? buttonWidth; + final IconButtonShape? buttonShape; + late final ColorScheme _colors = Theme.of(context).colorScheme; + + @override + WidgetStateProperty? get backgroundColor => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.disabled)) { + return _colors.onSurface.withOpacity(0.1); + } + if (toggleable && states.contains(WidgetState.selected)) { + return _colors.primary; + } + if (toggleable) { + return _colors.surfaceContainer; + } + return _colors.primary; + }); + + @override + WidgetStateProperty? get foregroundColor => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.disabled)) { + return _colors.onSurface.withOpacity(0.38); + } + if (toggleable && states.contains(WidgetState.selected)) { + return _colors.onPrimary; + } + if (toggleable) { + return _colors.onSurfaceVariant; + } + return _colors.onPrimary; + }); + + @override + WidgetStateProperty? get overlayColor => + WidgetStateProperty.resolveWith((Set states) { + if (toggleable && states.contains(WidgetState.selected)) { + if (states.contains(WidgetState.pressed)) { + return _colors.onPrimary.withOpacity(0.1); + } + if (states.contains(WidgetState.hovered)) { + return _colors.onPrimary.withOpacity(0.08); + } + if (states.contains(WidgetState.focused)) { + return _colors.onPrimary.withOpacity(0.1); + } + } + if (toggleable) { + if (states.contains(WidgetState.pressed)) { + return _colors.onSurfaceVariant.withOpacity(0.1); + } + if (states.contains(WidgetState.hovered)) { + return _colors.onSurfaceVariant.withOpacity(0.08); + } + if (states.contains(WidgetState.focused)) { + return _colors.onSurfaceVariant.withOpacity(0.1); + } + } + if (states.contains(WidgetState.pressed)) { + return _colors.onPrimary.withOpacity(0.1); + } + if (states.contains(WidgetState.hovered)) { + return _colors.onPrimary.withOpacity(0.08); + } + if (states.contains(WidgetState.focused)) { + return _colors.onPrimary.withOpacity(0.1); + } + return Colors.transparent; + }); + + @override + WidgetStateProperty? get elevation => const MaterialStatePropertyAll(0.0); + + @override + WidgetStateProperty? get shadowColor => + const MaterialStatePropertyAll(Colors.transparent); + + @override + WidgetStateProperty? get surfaceTintColor => + const MaterialStatePropertyAll(Colors.transparent); + + @override + WidgetStateProperty? get padding => + MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), + }, + ButtonSize.small => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), + }, + ButtonSize.medium => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(16.0, 16.0, 16.0, 16.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), + }, + ButtonSize.large => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(32.0, 32.0, 32.0, 32.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), + }, + ButtonSize.xLarge => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(48.0, 48.0, 48.0, 48.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), + }, + }); + + @override + WidgetStateProperty? get minimumSize => + MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(28.0, 32.0), + IconButtonWidth.standard => const Size(32.0, 32.0), + IconButtonWidth.wide => const Size(40.0, 32.0), + }, + ButtonSize.small => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(32.0, 40.0), + IconButtonWidth.standard => const Size(40.0, 40.0), + IconButtonWidth.wide => const Size(52.0, 40.0), + }, + ButtonSize.medium => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(48.0, 56.0), + IconButtonWidth.standard => const Size(56.0, 56.0), + IconButtonWidth.wide => const Size(72.0, 56.0), + }, + ButtonSize.large => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(64.0, 96.0), + IconButtonWidth.standard => const Size(96.0, 96.0), + IconButtonWidth.wide => const Size(128.0, 96.0), + }, + ButtonSize.xLarge => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(104.0, 136.0), + IconButtonWidth.standard => const Size(136.0, 136.0), + IconButtonWidth.wide => const Size(184.0, 136.0), + }, + }); + + @override + WidgetStateProperty? get maximumSize => const MaterialStatePropertyAll(Size.infinite); + + @override + WidgetStateProperty? get iconSize => + MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => 20.0, + ButtonSize.small => 24.0, + ButtonSize.medium => 24.0, + ButtonSize.large => 32.0, + ButtonSize.xLarge => 40.0, + }); + + @override + WidgetStateProperty? get shape => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.pressed)) { + return switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(8.0)), + ), + ButtonSize.small => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(8.0)), + ), + ButtonSize.medium => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.large => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)), + ), + ButtonSize.xLarge => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)), + ), + }; + } + if (toggleable && states.contains(WidgetState.selected)) { + return switch (buttonShape ?? IconButtonShape.round) { + IconButtonShape.round => switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.small => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.medium => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)), + ), + ButtonSize.large => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(28.0)), + ), + ButtonSize.xLarge => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(28.0)), + ), + }, + IconButtonShape.square => switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const StadiumBorder(), + ButtonSize.small => const StadiumBorder(), + ButtonSize.medium => const StadiumBorder(), + ButtonSize.large => const StadiumBorder(), + ButtonSize.xLarge => const StadiumBorder(), + }, + }; + } + return switch (buttonShape ?? IconButtonShape.round) { + IconButtonShape.round => switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const StadiumBorder(), + ButtonSize.small => const StadiumBorder(), + ButtonSize.medium => const StadiumBorder(), + ButtonSize.large => const StadiumBorder(), + ButtonSize.xLarge => const StadiumBorder(), + }, + IconButtonShape.square => switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.small => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.medium => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)), + ), + ButtonSize.large => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(28.0)), + ), + ButtonSize.xLarge => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(28.0)), + ), + }, + }; + }); + + @override + WidgetStateProperty? get side => null; + + @override + WidgetStateProperty? get mouseCursor => WidgetStateMouseCursor.adaptiveClickable; + + @override + VisualDensity? get visualDensity => VisualDensity.standard; + + @override + MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + + @override + InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; +} + +class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { + _M3EFilledTonalIconButtonDefaults( + this.context, + this.toggleable, + this.buttonSize, + this.buttonWidth, + this.buttonShape, + ) : super( + animationDuration: kThemeChangeDuration, + enableFeedback: true, + alignment: Alignment.center, + ); + + final BuildContext context; + final bool toggleable; + final ButtonSize? buttonSize; + final IconButtonWidth? buttonWidth; + final IconButtonShape? buttonShape; + late final ColorScheme _colors = Theme.of(context).colorScheme; + + @override + WidgetStateProperty? get backgroundColor => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.disabled)) { + return _colors.onSurface.withOpacity(0.1); + } + if (toggleable && states.contains(WidgetState.selected)) { + return _colors.secondary; + } + if (toggleable) { + return _colors.secondaryContainer; + } + return _colors.secondaryContainer; + }); + + @override + WidgetStateProperty? get foregroundColor => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.disabled)) { + return _colors.onSurface.withOpacity(0.38); + } + if (toggleable && states.contains(WidgetState.selected)) { + return _colors.onSecondary; + } + if (toggleable) { + return _colors.onSecondaryContainer; + } + return _colors.onSecondaryContainer; + }); + + @override + WidgetStateProperty? get overlayColor => + WidgetStateProperty.resolveWith((Set states) { + if (toggleable && states.contains(WidgetState.selected)) { + if (states.contains(WidgetState.pressed)) { + return _colors.onSecondary.withOpacity(0.1); + } + if (states.contains(WidgetState.hovered)) { + return _colors.onSecondary.withOpacity(0.08); + } + if (states.contains(WidgetState.focused)) { + return _colors.onSecondary.withOpacity(0.1); + } + } + if (toggleable) { + if (states.contains(WidgetState.pressed)) { + return _colors.onSecondaryContainer.withOpacity(0.1); + } + if (states.contains(WidgetState.hovered)) { + return _colors.onSecondaryContainer.withOpacity(0.08); + } + if (states.contains(WidgetState.focused)) { + return _colors.onSecondaryContainer.withOpacity(0.1); + } + } + if (states.contains(WidgetState.pressed)) { + return _colors.onSecondaryContainer.withOpacity(0.1); + } + if (states.contains(WidgetState.hovered)) { + return _colors.onSecondaryContainer.withOpacity(0.08); + } + if (states.contains(WidgetState.focused)) { + return _colors.onSecondaryContainer.withOpacity(0.1); + } + return Colors.transparent; + }); + + @override + WidgetStateProperty? get elevation => const MaterialStatePropertyAll(0.0); + + @override + WidgetStateProperty? get shadowColor => + const MaterialStatePropertyAll(Colors.transparent); + + @override + WidgetStateProperty? get surfaceTintColor => + const MaterialStatePropertyAll(Colors.transparent); + + @override + WidgetStateProperty? get padding => + MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), + }, + ButtonSize.small => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), + }, + ButtonSize.medium => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(16.0, 16.0, 16.0, 16.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), + }, + ButtonSize.large => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(32.0, 32.0, 32.0, 32.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), + }, + ButtonSize.xLarge => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(48.0, 48.0, 48.0, 48.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), + }, + }); + + @override + WidgetStateProperty? get minimumSize => + MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(28.0, 32.0), + IconButtonWidth.standard => const Size(32.0, 32.0), + IconButtonWidth.wide => const Size(40.0, 32.0), + }, + ButtonSize.small => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(32.0, 40.0), + IconButtonWidth.standard => const Size(40.0, 40.0), + IconButtonWidth.wide => const Size(52.0, 40.0), + }, + ButtonSize.medium => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(48.0, 56.0), + IconButtonWidth.standard => const Size(56.0, 56.0), + IconButtonWidth.wide => const Size(72.0, 56.0), + }, + ButtonSize.large => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(64.0, 96.0), + IconButtonWidth.standard => const Size(96.0, 96.0), + IconButtonWidth.wide => const Size(128.0, 96.0), + }, + ButtonSize.xLarge => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(104.0, 136.0), + IconButtonWidth.standard => const Size(136.0, 136.0), + IconButtonWidth.wide => const Size(184.0, 136.0), + }, + }); + + @override + WidgetStateProperty? get maximumSize => const MaterialStatePropertyAll(Size.infinite); + + @override + WidgetStateProperty? get iconSize => + MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => 20.0, + ButtonSize.small => 24.0, + ButtonSize.medium => 24.0, + ButtonSize.large => 32.0, + ButtonSize.xLarge => 40.0, + }); + + @override + WidgetStateProperty? get shape => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.pressed)) { + return switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(8.0)), + ), + ButtonSize.small => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(8.0)), + ), + ButtonSize.medium => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.large => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)), + ), + ButtonSize.xLarge => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)), + ), + }; + } + if (toggleable && states.contains(WidgetState.selected)) { + return switch (buttonShape ?? IconButtonShape.round) { + IconButtonShape.round => switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.small => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.medium => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)), + ), + ButtonSize.large => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(28.0)), + ), + ButtonSize.xLarge => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(28.0)), + ), + }, + IconButtonShape.square => switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const StadiumBorder(), + ButtonSize.small => const StadiumBorder(), + ButtonSize.medium => const StadiumBorder(), + ButtonSize.large => const StadiumBorder(), + ButtonSize.xLarge => const StadiumBorder(), + }, + }; + } + return switch (buttonShape ?? IconButtonShape.round) { + IconButtonShape.round => switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const StadiumBorder(), + ButtonSize.small => const StadiumBorder(), + ButtonSize.medium => const StadiumBorder(), + ButtonSize.large => const StadiumBorder(), + ButtonSize.xLarge => const StadiumBorder(), + }, + IconButtonShape.square => switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.small => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.medium => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)), + ), + ButtonSize.large => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(28.0)), + ), + ButtonSize.xLarge => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(28.0)), + ), + }, + }; + }); + + @override + WidgetStateProperty? get side => null; + + @override + WidgetStateProperty? get mouseCursor => WidgetStateMouseCursor.adaptiveClickable; + + @override + VisualDensity? get visualDensity => VisualDensity.standard; + + @override + MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + + @override + InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; +} + +class _M3EOutlinedIconButtonDefaults extends ButtonStyle { + _M3EOutlinedIconButtonDefaults( + this.context, + this.toggleable, + this.buttonSize, + this.buttonWidth, + this.buttonShape, + ) : super( + animationDuration: kThemeChangeDuration, + enableFeedback: true, + alignment: Alignment.center, + ); + + final BuildContext context; + final bool toggleable; + final ButtonSize? buttonSize; + final IconButtonWidth? buttonWidth; + final IconButtonShape? buttonShape; + late final ColorScheme _colors = Theme.of(context).colorScheme; + + @override + WidgetStateProperty? get backgroundColor => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.disabled)) { + if (toggleable && states.contains(WidgetState.selected)) { + return _colors.onSurface.withOpacity(0.1); + } + return Colors.transparent; + } + if (toggleable && states.contains(WidgetState.selected)) { + return _colors.inverseSurface; + } + return Colors.transparent; + }); + + @override + WidgetStateProperty? get foregroundColor => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.disabled)) { + return _colors.onSurface.withOpacity(0.38); + } + if (toggleable && states.contains(WidgetState.selected)) { + return _colors.onInverseSurface; + } + return _colors.onSurfaceVariant; + }); + + @override + WidgetStateProperty? get overlayColor => + WidgetStateProperty.resolveWith((Set states) { + if (toggleable && states.contains(WidgetState.selected)) { + if (states.contains(WidgetState.pressed)) { + return _colors.onInverseSurface.withOpacity(0.1); + } + if (states.contains(WidgetState.hovered)) { + return _colors.onInverseSurface.withOpacity(0.08); + } + if (states.contains(WidgetState.focused)) { + return _colors.onInverseSurface.withOpacity(0.1); + } + } + if (states.contains(WidgetState.pressed)) { + return _colors.onSurfaceVariant.withOpacity(0.1); + } + if (states.contains(WidgetState.hovered)) { + return _colors.onSurfaceVariant.withOpacity(0.08); + } + if (states.contains(WidgetState.focused)) { + return _colors.onSurfaceVariant.withOpacity(0.1); + } + return Colors.transparent; + }); + + @override + WidgetStateProperty? get elevation => const MaterialStatePropertyAll(0.0); + + @override + WidgetStateProperty? get shadowColor => + const MaterialStatePropertyAll(Colors.transparent); + + @override + WidgetStateProperty? get surfaceTintColor => + const MaterialStatePropertyAll(Colors.transparent); + + @override + WidgetStateProperty? get padding => + MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), + }, + ButtonSize.small => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), + }, + ButtonSize.medium => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(16.0, 16.0, 16.0, 16.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), + }, + ButtonSize.large => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(32.0, 32.0, 32.0, 32.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), + }, + ButtonSize.xLarge => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(48.0, 48.0, 48.0, 48.0), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), + }, + }); + + @override + WidgetStateProperty? get minimumSize => + MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(28.0, 32.0), + IconButtonWidth.standard => const Size(32.0, 32.0), + IconButtonWidth.wide => const Size(40.0, 32.0), + }, + ButtonSize.small => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(32.0, 40.0), + IconButtonWidth.standard => const Size(40.0, 40.0), + IconButtonWidth.wide => const Size(52.0, 40.0), + }, + ButtonSize.medium => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(48.0, 56.0), + IconButtonWidth.standard => const Size(56.0, 56.0), + IconButtonWidth.wide => const Size(72.0, 56.0), + }, + ButtonSize.large => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(64.0, 96.0), + IconButtonWidth.standard => const Size(96.0, 96.0), + IconButtonWidth.wide => const Size(128.0, 96.0), + }, + ButtonSize.xLarge => switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(104.0, 136.0), + IconButtonWidth.standard => const Size(136.0, 136.0), + IconButtonWidth.wide => const Size(184.0, 136.0), + }, + }); + + @override + WidgetStateProperty? get maximumSize => const MaterialStatePropertyAll(Size.infinite); + + @override + WidgetStateProperty? get iconSize => + MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => 20.0, + ButtonSize.small => 24.0, + ButtonSize.medium => 24.0, + ButtonSize.large => 32.0, + ButtonSize.xLarge => 40.0, + }); + + @override + WidgetStateProperty? get shape => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.pressed)) { + return switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(8.0)), + ), + ButtonSize.small => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(8.0)), + ), + ButtonSize.medium => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.large => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)), + ), + ButtonSize.xLarge => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)), + ), + }; + } + if (toggleable && states.contains(WidgetState.selected)) { + return switch (buttonShape ?? IconButtonShape.round) { + IconButtonShape.round => switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.small => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.medium => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)), + ), + ButtonSize.large => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(28.0)), + ), + ButtonSize.xLarge => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(28.0)), + ), + }, + IconButtonShape.square => switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const StadiumBorder(), + ButtonSize.small => const StadiumBorder(), + ButtonSize.medium => const StadiumBorder(), + ButtonSize.large => const StadiumBorder(), + ButtonSize.xLarge => const StadiumBorder(), + }, + }; + } + return switch (buttonShape ?? IconButtonShape.round) { + IconButtonShape.round => switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const StadiumBorder(), + ButtonSize.small => const StadiumBorder(), + ButtonSize.medium => const StadiumBorder(), + ButtonSize.large => const StadiumBorder(), + ButtonSize.xLarge => const StadiumBorder(), + }, + IconButtonShape.square => switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.small => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12.0)), + ), + ButtonSize.medium => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)), + ), + ButtonSize.large => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(28.0)), + ), + ButtonSize.xLarge => const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(28.0)), + ), + }, + }; + }); + + @override + WidgetStateProperty? get side => + WidgetStateProperty.resolveWith((Set states) { + if (toggleable && states.contains(WidgetState.selected)) { + return null; + } + if (states.contains(WidgetState.disabled)) { + return BorderSide( + color: _colors.outlineVariant, + width: switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => 1.0, + ButtonSize.small => 1.0, + ButtonSize.medium => 1.0, + ButtonSize.large => 2.0, + ButtonSize.xLarge => 3.0, + }, + ); + } + return BorderSide( + color: _colors.outlineVariant, + width: switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => 1.0, + ButtonSize.small => 1.0, + ButtonSize.medium => 1.0, + ButtonSize.large => 2.0, + ButtonSize.xLarge => 3.0, + }, + ); + }); + + @override + WidgetStateProperty? get mouseCursor => WidgetStateMouseCursor.adaptiveClickable; + + @override + VisualDensity? get visualDensity => VisualDensity.standard; + + @override + MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + + @override + InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; +} diff --git a/packages/material_ui/lib/src/icon_button.dart b/packages/material_ui/lib/src/icon_button.dart index 9f026b7aa3dc..54351408d99a 100644 --- a/packages/material_ui/lib/src/icon_button.dart +++ b/packages/material_ui/lib/src/icon_button.dart @@ -31,6 +31,8 @@ import 'theme.dart'; import 'theme_data.dart'; import 'tooltip.dart'; +part 'generated/icon_button_defaults_m3e.g.dart'; + // Examples can assume: // late BuildContext context; @@ -626,6 +628,11 @@ class IconButton extends StatelessWidget { /// create a [WidgetStateProperty] with a single value for all /// states. /// + /// The [size], [iconButtonWidth], and [iconButtonShape] parameters configure + /// the Material 3 Expressive token size, width, and shape through + /// [ButtonStyle.size], [ButtonStyle.iconButtonWidth], and + /// [ButtonStyle.iconButtonShape]. + /// /// All parameters default to null, by default this method returns /// a [ButtonStyle] that doesn't override anything. /// @@ -670,6 +677,9 @@ class IconButton extends StatelessWidget { bool? enableFeedback, AlignmentGeometry? alignment, InteractiveInkFeatureFactory? splashFactory, + ButtonSize? size, + IconButtonWidth? iconButtonWidth, + IconButtonShape? iconButtonShape, }) { final Color? overlayFallback = overlayColor ?? foregroundColor; WidgetStateProperty? overlayColorProp; @@ -710,6 +720,9 @@ class IconButton extends StatelessWidget { enableFeedback: enableFeedback, alignment: alignment, splashFactory: splashFactory, + size: size, + iconButtonWidth: iconButtonWidth, + iconButtonShape: iconButtonShape, ); } @@ -718,6 +731,9 @@ class IconButton extends StatelessWidget { final ThemeData theme = Theme.of(context); if (theme.useMaterial3) { + final StyleVariant effectiveVariant = + IconButtonTheme.of(context).variant ?? StyleVariant.material3; + final Size? minSize = constraints == null ? null : Size(constraints!.minWidth, constraints!.minHeight); @@ -761,6 +777,7 @@ class IconButton extends StatelessWidget { focusNode: focusNode, isSelected: isSelected, variant: _variant, + styleVariant: effectiveVariant, tooltip: tooltip, statesController: statesController, child: effectiveIcon, @@ -867,6 +884,7 @@ class _SelectableIconButton extends StatefulWidget { this.onHover, this.statesController, required this.variant, + required this.styleVariant, required this.autofocus, required this.onPressed, this.tooltip, @@ -877,6 +895,7 @@ class _SelectableIconButton extends StatefulWidget { final ButtonStyle? style; final FocusNode? focusNode; final _IconButtonVariant variant; + final StyleVariant styleVariant; final bool autofocus; final VoidCallback? onPressed; final String? tooltip; @@ -945,7 +964,8 @@ class _SelectableIconButtonState extends State<_SelectableIconButton> { onPressed: widget.onPressed, onHover: widget.onHover, onLongPress: widget.onPressed != null ? widget.onLongPress : null, - variant: widget.variant, + iconButtonVariant: widget.variant, + styleVariant: widget.styleVariant, toggleable: toggleable, tooltip: widget.tooltip, child: Semantics(selected: widget.isSelected, child: widget.child), @@ -968,15 +988,29 @@ class _IconButtonM3 extends ButtonStyleButton { super.onLongPress, super.autofocus = false, super.statesController, - required this.variant, + required this.iconButtonVariant, + required this.styleVariant, required this.toggleable, super.tooltip, required Widget super.child, }) : super(onFocusChange: null, clipBehavior: Clip.none); - final _IconButtonVariant variant; + final _IconButtonVariant iconButtonVariant; + final StyleVariant styleVariant; final bool toggleable; + ButtonSize? _effectiveSize(BuildContext context) { + return style?.size ?? IconButtonTheme.of(context).style?.size; + } + + IconButtonWidth? _effectiveWidth(BuildContext context) { + return style?.iconButtonWidth ?? IconButtonTheme.of(context).style?.iconButtonWidth; + } + + IconButtonShape? _effectiveShape(BuildContext context) { + return style?.iconButtonShape ?? IconButtonTheme.of(context).style?.iconButtonShape; + } + /// ## Material 3 defaults /// /// If [ThemeData.useMaterial3] is set to true the following defaults will @@ -1014,11 +1048,47 @@ class _IconButtonM3 extends ButtonStyleButton { /// * `splashFactory` - Theme.splashFactory @override ButtonStyle defaultStyleOf(BuildContext context) { - return switch (variant) { - _IconButtonVariant.filled => _FilledIconButtonDefaultsM3(context, toggleable), - _IconButtonVariant.filledTonal => _FilledTonalIconButtonDefaultsM3(context, toggleable), - _IconButtonVariant.outlined => _OutlinedIconButtonDefaultsM3(context, toggleable), - _IconButtonVariant.standard => _IconButtonDefaultsM3(context, toggleable), + final ButtonSize? effectiveSize = _effectiveSize(context); + final IconButtonWidth? effectiveWidth = _effectiveWidth(context); + final IconButtonShape? effectiveShape = _effectiveShape(context); + + return switch (styleVariant) { + StyleVariant.material3 => switch (iconButtonVariant) { + _IconButtonVariant.filled => _FilledIconButtonDefaultsM3(context, toggleable), + _IconButtonVariant.filledTonal => _FilledTonalIconButtonDefaultsM3(context, toggleable), + _IconButtonVariant.outlined => _OutlinedIconButtonDefaultsM3(context, toggleable), + _IconButtonVariant.standard => _IconButtonDefaultsM3(context, toggleable), + }, + StyleVariant.material3Expressive => switch (iconButtonVariant) { + _IconButtonVariant.filled => _M3EFilledIconButtonDefaults( + context, + toggleable, + effectiveSize, + effectiveWidth, + effectiveShape, + ), + _IconButtonVariant.filledTonal => _M3EFilledTonalIconButtonDefaults( + context, + toggleable, + effectiveSize, + effectiveWidth, + effectiveShape, + ), + _IconButtonVariant.outlined => _M3EOutlinedIconButtonDefaults( + context, + toggleable, + effectiveSize, + effectiveWidth, + effectiveShape, + ), + _IconButtonVariant.standard => _IconButtonDefaultsM3E( + context, + toggleable, + effectiveSize, + effectiveWidth, + effectiveShape, + ), + }, }; } diff --git a/packages/material_ui/lib/src/icon_button_theme.dart b/packages/material_ui/lib/src/icon_button_theme.dart index 0d38686dba0f..cd86c3bf3879 100644 --- a/packages/material_ui/lib/src/icon_button_theme.dart +++ b/packages/material_ui/lib/src/icon_button_theme.dart @@ -10,6 +10,7 @@ import 'package:flutter/widgets.dart'; import 'button_style.dart'; import 'theme.dart'; +import 'theme_data.dart'; // Examples can assume: // late BuildContext context; @@ -39,7 +40,7 @@ class IconButtonThemeData with Diagnosticable { /// Creates a [IconButtonThemeData]. /// /// The [style] may be null. - const IconButtonThemeData({this.style}); + const IconButtonThemeData({this.style, this.variant}); /// Overrides for [IconButton]'s default style if [ThemeData.useMaterial3] /// is set to true. @@ -50,16 +51,27 @@ class IconButtonThemeData with Diagnosticable { /// If [style] is null, then this theme doesn't override anything. final ButtonStyle? style; + /// The style variant of Material Design used by [IconButton]. + /// + /// Set this to [StyleVariant.material3Expressive] to opt icon buttons into + /// the Material 3 Expressive defaults. + /// + /// If null, [IconButton] uses [StyleVariant.material3]. + final StyleVariant? variant; + /// Linearly interpolate between two icon button themes. static IconButtonThemeData? lerp(IconButtonThemeData? a, IconButtonThemeData? b, double t) { if (identical(a, b)) { return a; } - return IconButtonThemeData(style: ButtonStyle.lerp(a?.style, b?.style, t)); + return IconButtonThemeData( + style: ButtonStyle.lerp(a?.style, b?.style, t), + variant: t < 0.5 ? a?.variant : b?.variant, + ); } @override - int get hashCode => style.hashCode; + int get hashCode => Object.hash(style, variant); @override bool operator ==(Object other) { @@ -69,13 +81,14 @@ class IconButtonThemeData with Diagnosticable { if (other.runtimeType != runtimeType) { return false; } - return other is IconButtonThemeData && other.style == style; + return other is IconButtonThemeData && other.style == style && other.variant == variant; } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(DiagnosticsProperty('style', style, defaultValue: null)); + properties.add(EnumProperty('variant', variant, defaultValue: null)); } } diff --git a/packages/material_ui/test/icon_button_test.dart b/packages/material_ui/test/icon_button_test.dart index 1bb186526103..95cafa50c451 100644 --- a/packages/material_ui/test/icon_button_test.dart +++ b/packages/material_ui/test/icon_button_test.dart @@ -3571,6 +3571,740 @@ void main() { ); expect(tester.getSize(find.byType(IconButton)), Size.zero); }); + + Widget buildM3EApp({required Widget child, ThemeData? theme}) { + return MaterialApp( + theme: + theme ?? + ThemeData( + useMaterial3: true, + iconButtonTheme: const IconButtonThemeData(variant: StyleVariant.material3Expressive), + ), + home: Scaffold(body: Center(child: child)), + ); + } + + Finder m3eIconButtonMaterialFinder() { + return find.descendant(of: find.byType(IconButton), matching: find.byType(Material)); + } + + Material m3eIconButtonMaterial(WidgetTester tester) { + return tester.widget(m3eIconButtonMaterialFinder()); + } + + Size m3eIconButtonMaterialSize(WidgetTester tester) { + return tester.getSize(m3eIconButtonMaterialFinder()); + } + + ColorScheme m3eColorScheme(WidgetTester tester) { + return Theme.of(tester.element(find.byType(IconButton))).colorScheme; + } + + Color? m3eIconColor(WidgetTester tester, IconData icon) { + return IconTheme.of(tester.element(find.byIcon(icon))).color; + } + + group('M3E IconButton size variants', () { + testWidgets('default size is small (40x40)', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp( + child: IconButton(onPressed: () {}, icon: const Icon(Icons.add)), + ), + ); + + // ButtonStyleButton renders with minimum size 40x40, but tap target + // padding brings it to 48x48. + expect(m3eIconButtonMaterialSize(tester), const Size(40.0, 40.0)); + expect(tester.getSize(find.byType(IconButton)), const Size(48.0, 48.0)); + }); + + testWidgets('xSmall size renders at 32dp minimum', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + onPressed: () {}, + icon: const Icon(Icons.add), + style: const ButtonStyle(size: ButtonSize.xSmall), + ), + ), + ); + + expect(m3eIconButtonMaterialSize(tester), const Size(32.0, 32.0)); + expect(tester.getSize(find.byType(IconButton)), const Size(48.0, 48.0)); + }); + + testWidgets('styleFrom sets the size variant', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + onPressed: () {}, + icon: const Icon(Icons.add), + style: IconButton.styleFrom(size: ButtonSize.medium), + ), + ), + ); + + expect(m3eIconButtonMaterialSize(tester), const Size(56.0, 56.0)); + expect(tester.getSize(find.byType(IconButton)), const Size(56.0, 56.0)); + }); + + testWidgets('medium size renders at 56dp minimum', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + onPressed: () {}, + icon: const Icon(Icons.add), + style: const ButtonStyle(size: ButtonSize.medium), + ), + ), + ); + + expect(m3eIconButtonMaterialSize(tester), const Size(56.0, 56.0)); + expect(tester.getSize(find.byType(IconButton)), const Size(56.0, 56.0)); + }); + + testWidgets('large size renders at 96dp minimum', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + onPressed: () {}, + icon: const Icon(Icons.add), + style: const ButtonStyle(size: ButtonSize.large), + ), + ), + ); + + expect(m3eIconButtonMaterialSize(tester), const Size(96.0, 96.0)); + expect(tester.getSize(find.byType(IconButton)), const Size(96.0, 96.0)); + }); + + testWidgets('xLarge size renders at 136dp minimum', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + onPressed: () {}, + icon: const Icon(Icons.add), + style: const ButtonStyle(size: ButtonSize.xLarge), + ), + ), + ); + + expect(m3eIconButtonMaterialSize(tester), const Size(136.0, 136.0)); + expect(tester.getSize(find.byType(IconButton)), const Size(136.0, 136.0)); + }); + }); + + group('M3E IconButton width variants', () { + testWidgets('small IconButton supports narrow, standard, and wide widths', ( + WidgetTester tester, + ) async { + Future materialSizeFor(IconButtonWidth width) async { + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + onPressed: () {}, + icon: const Icon(Icons.add), + style: ButtonStyle(iconButtonWidth: width), + ), + ), + ); + return m3eIconButtonMaterialSize(tester); + } + + expect(await materialSizeFor(IconButtonWidth.narrow), const Size(32.0, 40.0)); + expect(await materialSizeFor(IconButtonWidth.standard), const Size(40.0, 40.0)); + expect(await materialSizeFor(IconButtonWidth.wide), const Size(52.0, 40.0)); + + expect(m3eIconButtonMaterial(tester).animationDuration, kThemeChangeDuration); + }); + + testWidgets('IconButtonThemeData style width sets default width', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp( + theme: ThemeData( + useMaterial3: true, + iconButtonTheme: const IconButtonThemeData( + style: ButtonStyle(iconButtonWidth: IconButtonWidth.wide), + variant: StyleVariant.material3Expressive, + ), + ), + child: IconButton(onPressed: () {}, icon: const Icon(Icons.add)), + ), + ); + + expect(m3eIconButtonMaterialSize(tester), const Size(52.0, 40.0)); + }); + }); + + group('M3E IconButton shape', () { + OutlinedBorder materialShape(WidgetTester tester) { + final Material material = tester.widget( + find.descendant(of: find.byType(IconButton), matching: find.byType(Material)), + ); + return material.shape! as OutlinedBorder; + } + + testWidgets('default shape resolves M3E token shapes by state', (WidgetTester tester) async { + final statesController = MaterialStatesController(); + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + statesController: statesController, + isSelected: true, + onPressed: () {}, + icon: const Icon(Icons.add), + ), + ), + ); + expect( + materialShape(tester), + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(12.0))), + ); + + statesController.update(WidgetState.pressed, true); + await tester.pumpAndSettle(); + + expect( + materialShape(tester), + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))), + ); + statesController.dispose(); + }); + + testWidgets('square shape resolves M3E token shapes by state', (WidgetTester tester) async { + final statesController = MaterialStatesController(); + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + statesController: statesController, + isSelected: false, + onPressed: () {}, + icon: const Icon(Icons.add), + style: const ButtonStyle( + size: ButtonSize.medium, + iconButtonShape: IconButtonShape.square, + ), + ), + ), + ); + + expect( + materialShape(tester), + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))), + ); + + statesController.update(WidgetState.pressed, true); + await tester.pumpAndSettle(); + + expect( + materialShape(tester), + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(12.0))), + ); + + statesController.update(WidgetState.pressed, false); + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + statesController: statesController, + isSelected: true, + onPressed: () {}, + icon: const Icon(Icons.add), + style: const ButtonStyle( + size: ButtonSize.medium, + iconButtonShape: IconButtonShape.square, + ), + ), + ), + ); + await tester.pumpAndSettle(); + + expect(materialShape(tester), const StadiumBorder()); + statesController.dispose(); + }); + + testWidgets('ButtonStyle.shape remains the stateful shape override API', ( + WidgetTester tester, + ) async { + final statesController = MaterialStatesController(); + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + statesController: statesController, + onPressed: () {}, + icon: const Icon(Icons.add), + style: ButtonStyle( + shape: WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.pressed)) { + return const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0)), + ); + } + return const StadiumBorder(); + }), + ), + ), + ), + ); + + expect(materialShape(tester), const StadiumBorder()); + + statesController.update(WidgetState.pressed, true); + await tester.pumpAndSettle(); + + expect( + materialShape(tester), + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))), + ); + statesController.dispose(); + }); + }); + + group('M3E IconButton variants', () { + testWidgets('standard variant has transparent background', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp( + child: IconButton(onPressed: () {}, icon: const Icon(Icons.add)), + ), + ); + + expect(m3eIconButtonMaterial(tester).color, Colors.transparent); + expect(m3eIconButtonMaterial(tester).shape, const StadiumBorder()); + }); + + testWidgets('filled variant resolves default container color', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp( + child: IconButton.filled(onPressed: () {}, icon: const Icon(Icons.add)), + ), + ); + + expect(m3eIconButtonMaterial(tester).color, m3eColorScheme(tester).primary); + expect(m3eIconButtonMaterial(tester).shape, const StadiumBorder()); + }); + + testWidgets('filledTonal variant resolves default container color', ( + WidgetTester tester, + ) async { + await tester.pumpWidget( + buildM3EApp( + child: IconButton.filledTonal(onPressed: () {}, icon: const Icon(Icons.add)), + ), + ); + + expect(m3eIconButtonMaterial(tester).color, m3eColorScheme(tester).secondaryContainer); + expect(m3eIconButtonMaterial(tester).shape, const StadiumBorder()); + }); + + testWidgets('outlined variant resolves default side and transparent background', ( + WidgetTester tester, + ) async { + await tester.pumpWidget( + buildM3EApp( + child: IconButton.outlined(onPressed: () {}, icon: const Icon(Icons.add)), + ), + ); + + final shape = m3eIconButtonMaterial(tester).shape! as StadiumBorder; + expect(m3eIconButtonMaterial(tester).color, Colors.transparent); + expect(shape.side, BorderSide(color: m3eColorScheme(tester).outlineVariant)); + }); + + testWidgets('filled variant with style size', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp( + child: IconButton.filled( + onPressed: () {}, + icon: const Icon(Icons.add), + style: const ButtonStyle(size: ButtonSize.large), + ), + ), + ); + + expect(m3eIconButtonMaterialSize(tester), const Size(96.0, 96.0)); + expect(tester.getSize(find.byType(IconButton)), const Size(96.0, 96.0)); + }); + + testWidgets('outlined variant with style size', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp( + child: IconButton.outlined( + onPressed: () {}, + icon: const Icon(Icons.add), + style: const ButtonStyle(size: ButtonSize.medium), + ), + ), + ); + + expect(m3eIconButtonMaterialSize(tester), const Size(56.0, 56.0)); + expect(tester.getSize(find.byType(IconButton)), const Size(56.0, 56.0)); + }); + }); + + group('M3E IconButton theme integration', () { + testWidgets('IconButtonThemeData style size sets default size', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp( + theme: ThemeData( + useMaterial3: true, + iconButtonTheme: const IconButtonThemeData( + style: ButtonStyle(size: ButtonSize.large), + variant: StyleVariant.material3Expressive, + ), + ), + child: IconButton(onPressed: () {}, icon: const Icon(Icons.add)), + ), + ); + + expect(m3eIconButtonMaterialSize(tester), const Size(96.0, 96.0)); + expect(tester.getSize(find.byType(IconButton)), const Size(96.0, 96.0)); + }); + + testWidgets('widget size overrides theme size', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp( + theme: ThemeData( + useMaterial3: true, + iconButtonTheme: const IconButtonThemeData( + style: ButtonStyle(size: ButtonSize.large), + variant: StyleVariant.material3Expressive, + ), + ), + child: IconButton( + onPressed: () {}, + icon: const Icon(Icons.add), + style: const ButtonStyle(size: ButtonSize.xSmall), + ), + ), + ); + + expect(m3eIconButtonMaterialSize(tester), const Size(32.0, 32.0)); + expect(tester.getSize(find.byType(IconButton)), const Size(48.0, 48.0)); + }); + + testWidgets('IconButtonTheme wrapping sets size', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp( + child: IconButtonTheme( + data: const IconButtonThemeData( + style: ButtonStyle(size: ButtonSize.medium), + variant: StyleVariant.material3Expressive, + ), + child: IconButton(onPressed: () {}, icon: const Icon(Icons.add)), + ), + ), + ); + + expect(m3eIconButtonMaterialSize(tester), const Size(56.0, 56.0)); + expect(tester.getSize(find.byType(IconButton)), const Size(56.0, 56.0)); + }); + }); + + group('M3E IconButton selection', () { + testWidgets('isSelected shows selectedIcon', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + onPressed: () {}, + isSelected: true, + icon: const Icon(Icons.favorite_border), + selectedIcon: const Icon(Icons.favorite), + ), + ), + ); + + expect(find.byIcon(Icons.favorite), findsOneWidget); + expect(find.byIcon(Icons.favorite_border), findsNothing); + }); + + testWidgets('isSelected exposes selected semantics', (WidgetTester tester) async { + final SemanticsHandle handle = tester.ensureSemantics(); + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + onPressed: () {}, + isSelected: true, + icon: const Icon(Icons.favorite_border, semanticLabel: 'favorite'), + selectedIcon: const Icon(Icons.favorite, semanticLabel: 'favorite'), + ), + ), + ); + + expect( + tester.getSemantics(find.byType(IconButton)), + matchesSemantics( + hasTapAction: true, + hasFocusAction: true, + hasEnabledState: true, + isButton: true, + isEnabled: true, + isFocusable: true, + hasSelectedState: true, + isSelected: true, + label: 'favorite', + ), + ); + handle.dispose(); + }); + + testWidgets('external selected state does not affect non-toggleable visual state', ( + WidgetTester tester, + ) async { + final statesController = MaterialStatesController(); + statesController.update(WidgetState.selected, true); + + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + onPressed: () {}, + statesController: statesController, + icon: const Icon(Icons.favorite_border), + selectedIcon: const Icon(Icons.favorite), + ), + ), + ); + + final Material material = tester.widget( + find.descendant(of: find.byType(IconButton), matching: find.byType(Material)), + ); + expect(material.shape, const StadiumBorder()); + expect(find.byIcon(Icons.favorite_border), findsOneWidget); + expect(find.byIcon(Icons.favorite), findsNothing); + }); + + testWidgets('isSelected false shows regular icon', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + onPressed: () {}, + isSelected: false, + icon: const Icon(Icons.favorite_border), + selectedIcon: const Icon(Icons.favorite), + ), + ), + ); + + expect(find.byIcon(Icons.favorite_border), findsOneWidget); + expect(find.byIcon(Icons.favorite), findsNothing); + }); + + testWidgets('isSelected updates selected widget state when toggled through null', ( + WidgetTester tester, + ) async { + final statesController = MaterialStatesController(); + + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + onPressed: () {}, + isSelected: true, + statesController: statesController, + icon: const Icon(Icons.favorite_border), + selectedIcon: const Icon(Icons.favorite), + ), + ), + ); + expect(statesController.value, contains(WidgetState.selected)); + + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + onPressed: () {}, + statesController: statesController, + icon: const Icon(Icons.favorite_border), + selectedIcon: const Icon(Icons.favorite), + ), + ), + ); + expect(statesController.value, isNot(contains(WidgetState.selected))); + + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + onPressed: () {}, + isSelected: false, + statesController: statesController, + icon: const Icon(Icons.favorite_border), + selectedIcon: const Icon(Icons.favorite), + ), + ), + ); + expect(statesController.value, isNot(contains(WidgetState.selected))); + + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + onPressed: () {}, + isSelected: true, + statesController: statesController, + icon: const Icon(Icons.favorite_border), + selectedIcon: const Icon(Icons.favorite), + ), + ), + ); + expect(statesController.value, contains(WidgetState.selected)); + }); + }); + + group('M3E IconButton disabled state', () { + testWidgets('disabled button has reduced opacity colors', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp(child: const IconButton(onPressed: null, icon: Icon(Icons.add))), + ); + + expect(m3eIconButtonMaterial(tester).color, Colors.transparent); + expect(m3eIconColor(tester, Icons.add), m3eColorScheme(tester).onSurface.withOpacity(0.38)); + }); + + testWidgets('onLongPress without onPressed keeps button disabled', (WidgetTester tester) async { + var longPressed = false; + final SemanticsHandle handle = tester.ensureSemantics(); + + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + onPressed: null, + onLongPress: () { + longPressed = true; + }, + icon: const Icon(Icons.add, semanticLabel: 'add'), + ), + ), + ); + + expect( + tester.getSemantics(find.byType(IconButton)), + matchesSemantics(hasEnabledState: true, isButton: true, label: 'add'), + ); + + await tester.longPress(find.byType(IconButton)); + expect(longPressed, isFalse); + handle.dispose(); + }); + + testWidgets('disabled filled button has reduced background', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp(child: const IconButton.filled(onPressed: null, icon: Icon(Icons.add))), + ); + + expect( + m3eIconButtonMaterial(tester).color, + m3eColorScheme(tester).onSurface.withOpacity(0.1), + ); + expect(m3eIconColor(tester, Icons.add), m3eColorScheme(tester).onSurface.withOpacity(0.38)); + }); + }); + + group('IconButtonThemeData', () { + test('equality', () { + const a = IconButtonThemeData( + style: ButtonStyle( + size: ButtonSize.small, + iconButtonWidth: IconButtonWidth.standard, + iconButtonShape: IconButtonShape.round, + ), + ); + const b = IconButtonThemeData( + style: ButtonStyle( + size: ButtonSize.small, + iconButtonWidth: IconButtonWidth.standard, + iconButtonShape: IconButtonShape.round, + ), + ); + const c = IconButtonThemeData( + style: ButtonStyle( + size: ButtonSize.large, + iconButtonWidth: IconButtonWidth.wide, + iconButtonShape: IconButtonShape.square, + ), + ); + + expect(a, equals(b)); + expect(a, isNot(equals(c))); + }); + + test('hashCode', () { + const a = IconButtonThemeData( + style: ButtonStyle( + size: ButtonSize.small, + iconButtonWidth: IconButtonWidth.narrow, + iconButtonShape: IconButtonShape.round, + ), + ); + const b = IconButtonThemeData( + style: ButtonStyle( + size: ButtonSize.small, + iconButtonWidth: IconButtonWidth.narrow, + iconButtonShape: IconButtonShape.round, + ), + ); + + expect(a.hashCode, equals(b.hashCode)); + }); + + test('lerp', () { + const a = IconButtonThemeData( + style: ButtonStyle( + size: ButtonSize.small, + iconButtonWidth: IconButtonWidth.narrow, + iconButtonShape: IconButtonShape.round, + ), + ); + const b = IconButtonThemeData( + style: ButtonStyle( + size: ButtonSize.large, + iconButtonWidth: IconButtonWidth.wide, + iconButtonShape: IconButtonShape.square, + ), + ); + + expect(IconButtonThemeData.lerp(a, b, 0.0)?.style?.size, ButtonSize.small); + expect(IconButtonThemeData.lerp(a, b, 0.4)?.style?.size, ButtonSize.small); + expect(IconButtonThemeData.lerp(a, b, 0.5)?.style?.size, ButtonSize.large); + expect(IconButtonThemeData.lerp(a, b, 1.0)?.style?.size, ButtonSize.large); + expect(IconButtonThemeData.lerp(a, b, 0.4)?.style?.iconButtonWidth, IconButtonWidth.narrow); + expect(IconButtonThemeData.lerp(a, b, 0.5)?.style?.iconButtonWidth, IconButtonWidth.wide); + expect(IconButtonThemeData.lerp(a, b, 0.4)?.style?.iconButtonShape, IconButtonShape.round); + expect(IconButtonThemeData.lerp(a, b, 0.5)?.style?.iconButtonShape, IconButtonShape.square); + }); + + test('debugFillProperties includes size, width, and shape', () { + const data = IconButtonThemeData( + style: ButtonStyle( + size: ButtonSize.medium, + iconButtonWidth: IconButtonWidth.wide, + iconButtonShape: IconButtonShape.square, + ), + ); + final builder = DiagnosticPropertiesBuilder(); + data.debugFillProperties(builder); + + final List descriptions = builder.properties + .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) + .map((DiagnosticsNode node) => node.toString()) + .toList(); + + expect(descriptions, contains(contains('size: medium'))); + expect(descriptions, contains(contains('iconButtonWidth: wide'))); + expect(descriptions, contains(contains('iconButtonShape: square'))); + }); + }); + + group('M3E IconButton variant opt in', () { + testWidgets('IconButtonThemeData variant enables M3E defaults', (WidgetTester tester) async { + await tester.pumpWidget( + buildM3EApp( + child: IconButton( + onPressed: () {}, + icon: const Icon(Icons.add), + style: const ButtonStyle(size: ButtonSize.medium), + ), + ), + ); + + expect(m3eIconButtonMaterialSize(tester), const Size(56.0, 56.0)); + expect(tester.getSize(find.byType(IconButton)), const Size(56.0, 56.0)); + }); + }); } Widget buildAllVariants({ diff --git a/packages/material_ui/test/icon_button_theme_test.dart b/packages/material_ui/test/icon_button_theme_test.dart index c271ba758bd4..c4671671f0c6 100644 --- a/packages/material_ui/test/icon_button_theme_test.dart +++ b/packages/material_ui/test/icon_button_theme_test.dart @@ -20,6 +20,36 @@ void main() { expect(identical(IconButtonThemeData.lerp(data, data, 0.5), data), true); }); + test('IconButtonThemeData supports Material 3 Expressive variant', () { + const data = IconButtonThemeData(variant: StyleVariant.material3Expressive); + + expect(data.variant, StyleVariant.material3Expressive); + }); + + test('IconButtonThemeData variant defaults to null', () { + const data = IconButtonThemeData(); + + expect(data.variant, isNull); + }); + + testWidgets('IconButton supports Material 3 Expressive style variants', ( + WidgetTester tester, + ) async { + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const Scaffold( + body: IconButtonTheme( + data: IconButtonThemeData(variant: StyleVariant.material3Expressive), + child: IconButton(onPressed: null, icon: Icon(Icons.ac_unit)), + ), + ), + ), + ); + + expect(tester.takeException(), isNull); + }); + testWidgets('Passing no IconButtonTheme returns defaults', (WidgetTester tester) async { const colorScheme = ColorScheme.light(); await tester.pumpWidget( diff --git a/packages/material_ui/tool/gen_defaults/bin/gen_defaults.dart b/packages/material_ui/tool/gen_defaults/bin/gen_defaults.dart index 07c1adee0f27..cf90a94907ae 100644 --- a/packages/material_ui/tool/gen_defaults/bin/gen_defaults.dart +++ b/packages/material_ui/tool/gen_defaults/bin/gen_defaults.dart @@ -30,7 +30,8 @@ import '../templates/bottom_sheet_template.dart'; // import '../templates/expansion_tile_template.dart'; // import '../templates/fab_template.dart'; // import '../templates/filter_chip_template.dart'; -// import '../templates/icon_button_template.dart'; +import '../templates/icon_button_template.dart'; + // import '../templates/input_chip_template.dart'; // import '../templates/input_decorator_template.dart'; // import '../templates/list_tile_template.dart'; @@ -81,7 +82,7 @@ Future main(List args) async { // const ExpansionTileTemplateM3().generateFile(verbose: verbose); // const FabTemplateM3().generateFile(verbose: verbose); // const FilterChipTemplateM3().generateFile(verbose: verbose); - // const IconButtonTemplateM3().generateFile(verbose: verbose); + const IconButtonTemplate().generateFile(verbose: verbose); // const InputChipTemplateM3().generateFile(verbose: verbose); // const InputDecoratorTemplateM3().generateFile(verbose: verbose); // const ListTileTemplateM3().generateFile(verbose: verbose); diff --git a/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart b/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart new file mode 100644 index 000000000000..962491931571 --- /dev/null +++ b/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart @@ -0,0 +1,771 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import '../data/color_role.dart'; +import '../data/icon_button_filled.dart'; +import '../data/icon_button_large.dart'; +import '../data/icon_button_medium.dart'; +import '../data/icon_button_outlined.dart'; +import '../data/icon_button_small.dart'; +import '../data/icon_button_standard.dart'; +import '../data/icon_button_tonal.dart'; +import '../data/icon_button_xlarge.dart'; +import '../data/icon_button_xsmall.dart'; +import 'template.dart'; + +class IconButtonTemplate extends TokenTemplateM3E { + const IconButtonTemplate(); + + @override + String get name => 'Icon Button'; + + @override + String get parentFilePath => 'icon_button.dart'; + + String tokenColor(TokenColorRole role) { + return switch (role) { + TokenColorRole.inverseOnSurface => '_colors.onInverseSurface', + _ => color(role, '_colors'), + }; + } + + String componentColor(TokenColorRole role, double opacity) { + final String value = tokenColor(role); + if (opacity == 1.0) { + return value; + } + return '$value.withOpacity($opacity)'; + } + + @override + String generateContents(String className) { + return ''' +${_generateStandardDefaults(className)} +${_generateFilledDefaults()} +${_generateFilledTonalDefaults()} +${_generateOutlinedDefaults()} +'''; + } + + String _sizeSwitch({ + required String xSmall, + required String small, + required String medium, + required String large, + required String xLarge, + }) { + return ''' +switch (buttonSize ?? ButtonSize.small) { + ButtonSize.xSmall => $xSmall, + ButtonSize.small => $small, + ButtonSize.medium => $medium, + ButtonSize.large => $large, + ButtonSize.xLarge => $xLarge, + }'''; + } + + String get _paddingSwitch { + return _sizeSwitch( + xSmall: _edgeInsetsSwitch( + defaultLeading: TokenIconButtonXsmall.defaultLeadingSpace, + defaultTrailing: TokenIconButtonXsmall.defaultTrailingSpace, + narrowLeading: TokenIconButtonXsmall.narrowLeadingSpace, + narrowTrailing: TokenIconButtonXsmall.narrowTrailingSpace, + wideLeading: TokenIconButtonXsmall.wideLeadingSpace, + wideTrailing: TokenIconButtonXsmall.wideTrailingSpace, + ), + small: _edgeInsetsSwitch( + defaultLeading: TokenIconButtonSmall.defaultLeadingSpace, + defaultTrailing: TokenIconButtonSmall.defaultTrailingSpace, + narrowLeading: TokenIconButtonSmall.narrowLeadingSpace, + narrowTrailing: TokenIconButtonSmall.narrowTrailingSpace, + wideLeading: TokenIconButtonSmall.wideLeadingSpace, + wideTrailing: TokenIconButtonSmall.wideTrailingSpace, + ), + medium: _edgeInsetsSwitch( + defaultLeading: TokenIconButtonMedium.defaultLeadingSpace, + defaultTrailing: TokenIconButtonMedium.defaultTrailingSpace, + narrowLeading: TokenIconButtonMedium.narrowLeadingSpace, + narrowTrailing: TokenIconButtonMedium.narrowTrailingSpace, + wideLeading: TokenIconButtonMedium.wideLeadingSpace, + wideTrailing: TokenIconButtonMedium.wideTrailingSpace, + ), + large: _edgeInsetsSwitch( + defaultLeading: TokenIconButtonLarge.defaultLeadingSpace, + defaultTrailing: TokenIconButtonLarge.defaultTrailingSpace, + narrowLeading: TokenIconButtonLarge.narrowLeadingSpace, + narrowTrailing: TokenIconButtonLarge.narrowTrailingSpace, + wideLeading: TokenIconButtonLarge.wideLeadingSpace, + wideTrailing: TokenIconButtonLarge.wideTrailingSpace, + ), + xLarge: _edgeInsetsSwitch( + defaultLeading: TokenIconButtonXlarge.defaultLeadingSpace, + defaultTrailing: TokenIconButtonXlarge.defaultTrailingSpace, + narrowLeading: TokenIconButtonXlarge.narrowLeadingSpace, + narrowTrailing: TokenIconButtonXlarge.narrowTrailingSpace, + wideLeading: TokenIconButtonXlarge.wideLeadingSpace, + wideTrailing: TokenIconButtonXlarge.wideTrailingSpace, + ), + ); + } + + String _edgeInsetsSwitch({ + required double defaultLeading, + required double defaultTrailing, + required double narrowLeading, + required double narrowTrailing, + required double wideLeading, + required double wideTrailing, + }) { + return ''' +switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB($narrowLeading, $defaultLeading, $narrowTrailing, $defaultTrailing), + IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB($defaultLeading, $defaultLeading, $defaultTrailing, $defaultTrailing), + IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB($wideLeading, $defaultLeading, $wideTrailing, $defaultTrailing), + }'''; + } + + String get _minimumSizeSwitch { + return _sizeSwitch( + xSmall: _minimumSizeWidthSwitch( + iconSize: TokenIconButtonXsmall.iconSize, + height: TokenIconButtonXsmall.containerHeight, + defaultLeading: TokenIconButtonXsmall.defaultLeadingSpace, + defaultTrailing: TokenIconButtonXsmall.defaultTrailingSpace, + narrowLeading: TokenIconButtonXsmall.narrowLeadingSpace, + narrowTrailing: TokenIconButtonXsmall.narrowTrailingSpace, + wideLeading: TokenIconButtonXsmall.wideLeadingSpace, + wideTrailing: TokenIconButtonXsmall.wideTrailingSpace, + ), + small: _minimumSizeWidthSwitch( + iconSize: TokenIconButtonSmall.iconSize, + height: TokenIconButtonSmall.containerHeight, + defaultLeading: TokenIconButtonSmall.defaultLeadingSpace, + defaultTrailing: TokenIconButtonSmall.defaultTrailingSpace, + narrowLeading: TokenIconButtonSmall.narrowLeadingSpace, + narrowTrailing: TokenIconButtonSmall.narrowTrailingSpace, + wideLeading: TokenIconButtonSmall.wideLeadingSpace, + wideTrailing: TokenIconButtonSmall.wideTrailingSpace, + ), + medium: _minimumSizeWidthSwitch( + iconSize: TokenIconButtonMedium.iconSize, + height: TokenIconButtonMedium.containerHeight, + defaultLeading: TokenIconButtonMedium.defaultLeadingSpace, + defaultTrailing: TokenIconButtonMedium.defaultTrailingSpace, + narrowLeading: TokenIconButtonMedium.narrowLeadingSpace, + narrowTrailing: TokenIconButtonMedium.narrowTrailingSpace, + wideLeading: TokenIconButtonMedium.wideLeadingSpace, + wideTrailing: TokenIconButtonMedium.wideTrailingSpace, + ), + large: _minimumSizeWidthSwitch( + iconSize: TokenIconButtonLarge.iconSize, + height: TokenIconButtonLarge.containerHeight, + defaultLeading: TokenIconButtonLarge.defaultLeadingSpace, + defaultTrailing: TokenIconButtonLarge.defaultTrailingSpace, + narrowLeading: TokenIconButtonLarge.narrowLeadingSpace, + narrowTrailing: TokenIconButtonLarge.narrowTrailingSpace, + wideLeading: TokenIconButtonLarge.wideLeadingSpace, + wideTrailing: TokenIconButtonLarge.wideTrailingSpace, + ), + xLarge: _minimumSizeWidthSwitch( + iconSize: TokenIconButtonXlarge.iconSize, + height: TokenIconButtonXlarge.containerHeight, + defaultLeading: TokenIconButtonXlarge.defaultLeadingSpace, + defaultTrailing: TokenIconButtonXlarge.defaultTrailingSpace, + narrowLeading: TokenIconButtonXlarge.narrowLeadingSpace, + narrowTrailing: TokenIconButtonXlarge.narrowTrailingSpace, + wideLeading: TokenIconButtonXlarge.wideLeadingSpace, + wideTrailing: TokenIconButtonXlarge.wideTrailingSpace, + ), + ); + } + + String _minimumSizeWidthSwitch({ + required double iconSize, + required double height, + required double defaultLeading, + required double defaultTrailing, + required double narrowLeading, + required double narrowTrailing, + required double wideLeading, + required double wideTrailing, + }) { + return ''' +switch (buttonWidth ?? IconButtonWidth.standard) { + IconButtonWidth.narrow => const Size(${iconSize + narrowLeading + narrowTrailing}, $height), + IconButtonWidth.standard => const Size(${iconSize + defaultLeading + defaultTrailing}, $height), + IconButtonWidth.wide => const Size(${iconSize + wideLeading + wideTrailing}, $height), + }'''; + } + + String get _iconSizeSwitch { + return _sizeSwitch( + xSmall: '${TokenIconButtonXsmall.iconSize}', + small: '${TokenIconButtonSmall.iconSize}', + medium: '${TokenIconButtonMedium.iconSize}', + large: '${TokenIconButtonLarge.iconSize}', + xLarge: '${TokenIconButtonXlarge.iconSize}', + ); + } + + String get _outlineWidthSwitch { + return _sizeSwitch( + xSmall: '${TokenIconButtonXsmall.outlinedOutlineWidth}', + small: '${TokenIconButtonSmall.outlinedOutlineWidth}', + medium: '${TokenIconButtonMedium.outlinedOutlineWidth}', + large: '${TokenIconButtonLarge.outlinedOutlineWidth}', + xLarge: '${TokenIconButtonXlarge.outlinedOutlineWidth}', + ); + } + + String get _containerRoundShapeSwitch { + return _sizeSwitch( + xSmall: shape(TokenIconButtonXsmall.containerShapeRound), + small: shape(TokenIconButtonSmall.containerShapeRound), + medium: shape(TokenIconButtonMedium.containerShapeRound), + large: shape(TokenIconButtonLarge.containerShapeRound), + xLarge: shape(TokenIconButtonXlarge.containerShapeRound), + ); + } + + String get _containerSquareShapeSwitch { + return _sizeSwitch( + xSmall: shape(TokenIconButtonXsmall.containerShapeSquare), + small: shape(TokenIconButtonSmall.containerShapeSquare), + medium: shape(TokenIconButtonMedium.containerShapeSquare), + large: shape(TokenIconButtonLarge.containerShapeSquare), + xLarge: shape(TokenIconButtonXlarge.containerShapeSquare), + ); + } + + String get _containerShapeSwitch { + return ''' +switch (buttonShape ?? IconButtonShape.round) { + IconButtonShape.round => $_containerRoundShapeSwitch, + IconButtonShape.square => $_containerSquareShapeSwitch, + }'''; + } + + String get _pressedShapeSwitch { + return _sizeSwitch( + xSmall: shape(TokenIconButtonXsmall.pressedContainerShape), + small: shape(TokenIconButtonSmall.pressedContainerShape), + medium: shape(TokenIconButtonMedium.pressedContainerShape), + large: shape(TokenIconButtonLarge.pressedContainerShape), + xLarge: shape(TokenIconButtonXlarge.pressedContainerShape), + ); + } + + String get _selectedRoundShapeSwitch { + return _sizeSwitch( + xSmall: shape(TokenIconButtonXsmall.selectedContainerShapeRound), + small: shape(TokenIconButtonSmall.selectedContainerShapeRound), + medium: shape(TokenIconButtonMedium.selectedContainerShapeRound), + large: shape(TokenIconButtonLarge.selectedContainerShapeRound), + xLarge: shape(TokenIconButtonXlarge.selectedContainerShapeRound), + ); + } + + String get _selectedSquareShapeSwitch { + return _sizeSwitch( + xSmall: shape(TokenIconButtonXsmall.selectedContainerShapeSquare), + small: shape(TokenIconButtonSmall.selectedContainerShapeSquare), + medium: shape(TokenIconButtonMedium.selectedContainerShapeSquare), + large: shape(TokenIconButtonLarge.selectedContainerShapeSquare), + xLarge: shape(TokenIconButtonXlarge.selectedContainerShapeSquare), + ); + } + + String get _selectedShapeSwitch { + return ''' +switch (buttonShape ?? IconButtonShape.round) { + IconButtonShape.round => $_selectedRoundShapeSwitch, + IconButtonShape.square => $_selectedSquareShapeSwitch, + }'''; + } + + String get _sizeDependentProperties { + return ''' + @override + WidgetStateProperty? get padding => + MaterialStatePropertyAll($_paddingSwitch); + + @override + WidgetStateProperty? get minimumSize => + MaterialStatePropertyAll($_minimumSizeSwitch); + + @override + WidgetStateProperty? get maximumSize => + const MaterialStatePropertyAll(Size.infinite); + + @override + WidgetStateProperty? get iconSize => + MaterialStatePropertyAll($_iconSizeSwitch); + + @override + WidgetStateProperty? get shape => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.pressed)) { + return $_pressedShapeSwitch; + } + if (toggleable && states.contains(WidgetState.selected)) { + return $_selectedShapeSwitch; + } + return $_containerShapeSwitch; + }); +'''; + } + + String _generateStandardDefaults(String className) { + return ''' +class $className extends ButtonStyle { + $className(this.context, this.toggleable, this.buttonSize, this.buttonWidth, this.buttonShape) + : super( + animationDuration: kThemeChangeDuration, + enableFeedback: true, + alignment: Alignment.center, + ); + + final BuildContext context; + final bool toggleable; + final ButtonSize? buttonSize; + final IconButtonWidth? buttonWidth; + final IconButtonShape? buttonShape; + late final ColorScheme _colors = Theme.of(context).colorScheme; + + @override + WidgetStateProperty? get backgroundColor => + const MaterialStatePropertyAll(Colors.transparent); + + @override + WidgetStateProperty? get foregroundColor => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.disabled)) { + return ${componentColor(TokenIconButtonStandard.disabledIconColor, TokenIconButtonStandard.disabledIconOpacity)}; + } + if (toggleable && states.contains(WidgetState.selected)) { + return ${tokenColor(TokenIconButtonStandard.selectedIconColor)}; + } + return ${tokenColor(TokenIconButtonStandard.iconColor)}; + }); + + @override + WidgetStateProperty? get overlayColor => + WidgetStateProperty.resolveWith((Set states) { + if (toggleable && states.contains(WidgetState.selected)) { + if (states.contains(WidgetState.pressed)) { + return ${componentColor(TokenIconButtonStandard.selectedPressedStateLayerColor, TokenIconButtonStandard.pressedStateLayerOpacity)}; + } + if (states.contains(WidgetState.hovered)) { + return ${componentColor(TokenIconButtonStandard.selectedHoveredStateLayerColor, TokenIconButtonStandard.hoveredStateLayerOpacity)}; + } + if (states.contains(WidgetState.focused)) { + return ${componentColor(TokenIconButtonStandard.selectedFocusedStateLayerColor, TokenIconButtonStandard.focusedStateLayerOpacity)}; + } + } + if (states.contains(WidgetState.pressed)) { + return ${componentColor(TokenIconButtonStandard.pressedStateLayerColor, TokenIconButtonStandard.pressedStateLayerOpacity)}; + } + if (states.contains(WidgetState.hovered)) { + return ${componentColor(TokenIconButtonStandard.hoveredStateLayerColor, TokenIconButtonStandard.hoveredStateLayerOpacity)}; + } + if (states.contains(WidgetState.focused)) { + return ${componentColor(TokenIconButtonStandard.focusedStateLayerColor, TokenIconButtonStandard.focusedStateLayerOpacity)}; + } + return Colors.transparent; + }); + + @override + WidgetStateProperty? get elevation => + const MaterialStatePropertyAll(0.0); + + @override + WidgetStateProperty? get shadowColor => + const MaterialStatePropertyAll(Colors.transparent); + + @override + WidgetStateProperty? get surfaceTintColor => + const MaterialStatePropertyAll(Colors.transparent); + +$_sizeDependentProperties + + @override + WidgetStateProperty? get side => null; + + @override + WidgetStateProperty? get mouseCursor => WidgetStateMouseCursor.adaptiveClickable; + + @override + VisualDensity? get visualDensity => VisualDensity.standard; + + @override + MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + + @override + InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; +} +'''; + } + + String _generateFilledDefaults() { + return ''' +class _M3EFilledIconButtonDefaults extends ButtonStyle { + _M3EFilledIconButtonDefaults( + this.context, + this.toggleable, + this.buttonSize, + this.buttonWidth, + this.buttonShape, + ) + : super( + animationDuration: kThemeChangeDuration, + enableFeedback: true, + alignment: Alignment.center, + ); + + final BuildContext context; + final bool toggleable; + final ButtonSize? buttonSize; + final IconButtonWidth? buttonWidth; + final IconButtonShape? buttonShape; + late final ColorScheme _colors = Theme.of(context).colorScheme; + + @override + WidgetStateProperty? get backgroundColor => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.disabled)) { + return ${componentColor(TokenIconButtonFilled.disabledContainerColor, TokenIconButtonFilled.disabledContainerOpacity)}; + } + if (toggleable && states.contains(WidgetState.selected)) { + return ${tokenColor(TokenIconButtonFilled.selectedContainerColor)}; + } + if (toggleable) { + return ${tokenColor(TokenIconButtonFilled.unselectedContainerColor)}; + } + return ${tokenColor(TokenIconButtonFilled.containerColor)}; + }); + + @override + WidgetStateProperty? get foregroundColor => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.disabled)) { + return ${componentColor(TokenIconButtonFilled.disabledIconColor, TokenIconButtonFilled.disabledIconOpacity)}; + } + if (toggleable && states.contains(WidgetState.selected)) { + return ${tokenColor(TokenIconButtonFilled.selectedIconColor)}; + } + if (toggleable) { + return ${tokenColor(TokenIconButtonFilled.unselectedIconColor)}; + } + return ${tokenColor(TokenIconButtonFilled.iconColor)}; + }); + + @override + WidgetStateProperty? get overlayColor => + WidgetStateProperty.resolveWith((Set states) { + if (toggleable && states.contains(WidgetState.selected)) { + if (states.contains(WidgetState.pressed)) { + return ${componentColor(TokenIconButtonFilled.selectedPressedStateLayerColor, TokenIconButtonFilled.pressedStateLayerOpacity)}; + } + if (states.contains(WidgetState.hovered)) { + return ${componentColor(TokenIconButtonFilled.selectedHoveredStateLayerColor, TokenIconButtonFilled.hoveredStateLayerOpacity)}; + } + if (states.contains(WidgetState.focused)) { + return ${componentColor(TokenIconButtonFilled.selectedFocusedStateLayerColor, TokenIconButtonFilled.focusedStateLayerOpacity)}; + } + } + if (toggleable) { + if (states.contains(WidgetState.pressed)) { + return ${componentColor(TokenIconButtonFilled.unselectedPressedStateLayerColor, TokenIconButtonFilled.pressedStateLayerOpacity)}; + } + if (states.contains(WidgetState.hovered)) { + return ${componentColor(TokenIconButtonFilled.unselectedHoveredStateLayerColor, TokenIconButtonFilled.hoveredStateLayerOpacity)}; + } + if (states.contains(WidgetState.focused)) { + return ${componentColor(TokenIconButtonFilled.unselectedFocusedStateLayerColor, TokenIconButtonFilled.focusedStateLayerOpacity)}; + } + } + if (states.contains(WidgetState.pressed)) { + return ${componentColor(TokenIconButtonFilled.pressedStateLayerColor, TokenIconButtonFilled.pressedStateLayerOpacity)}; + } + if (states.contains(WidgetState.hovered)) { + return ${componentColor(TokenIconButtonFilled.hoveredStateLayerColor, TokenIconButtonFilled.hoveredStateLayerOpacity)}; + } + if (states.contains(WidgetState.focused)) { + return ${componentColor(TokenIconButtonFilled.focusedStateLayerColor, TokenIconButtonFilled.focusedStateLayerOpacity)}; + } + return Colors.transparent; + }); + + @override + WidgetStateProperty? get elevation => + const MaterialStatePropertyAll(0.0); + + @override + WidgetStateProperty? get shadowColor => + const MaterialStatePropertyAll(Colors.transparent); + + @override + WidgetStateProperty? get surfaceTintColor => + const MaterialStatePropertyAll(Colors.transparent); + +$_sizeDependentProperties + + @override + WidgetStateProperty? get side => null; + + @override + WidgetStateProperty? get mouseCursor => WidgetStateMouseCursor.adaptiveClickable; + + @override + VisualDensity? get visualDensity => VisualDensity.standard; + + @override + MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + + @override + InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; +} +'''; + } + + String _generateFilledTonalDefaults() { + return ''' +class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { + _M3EFilledTonalIconButtonDefaults( + this.context, + this.toggleable, + this.buttonSize, + this.buttonWidth, + this.buttonShape, + ) + : super( + animationDuration: kThemeChangeDuration, + enableFeedback: true, + alignment: Alignment.center, + ); + + final BuildContext context; + final bool toggleable; + final ButtonSize? buttonSize; + final IconButtonWidth? buttonWidth; + final IconButtonShape? buttonShape; + late final ColorScheme _colors = Theme.of(context).colorScheme; + + @override + WidgetStateProperty? get backgroundColor => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.disabled)) { + return ${componentColor(TokenIconButtonTonal.disabledContainerColor, TokenIconButtonTonal.disabledContainerOpacity)}; + } + if (toggleable && states.contains(WidgetState.selected)) { + return ${tokenColor(TokenIconButtonTonal.selectedContainerColor)}; + } + if (toggleable) { + return ${tokenColor(TokenIconButtonTonal.unselectedContainerColor)}; + } + return ${tokenColor(TokenIconButtonTonal.containerColor)}; + }); + + @override + WidgetStateProperty? get foregroundColor => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.disabled)) { + return ${componentColor(TokenIconButtonTonal.disabledIconColor, TokenIconButtonTonal.disabledIconOpacity)}; + } + if (toggleable && states.contains(WidgetState.selected)) { + return ${tokenColor(TokenIconButtonTonal.selectedIconColor)}; + } + if (toggleable) { + return ${tokenColor(TokenIconButtonTonal.unselectedIconColor)}; + } + return ${tokenColor(TokenIconButtonTonal.iconColor)}; + }); + + @override + WidgetStateProperty? get overlayColor => + WidgetStateProperty.resolveWith((Set states) { + if (toggleable && states.contains(WidgetState.selected)) { + if (states.contains(WidgetState.pressed)) { + return ${componentColor(TokenIconButtonTonal.selectedPressedStateLayerColor, TokenIconButtonTonal.pressedStateLayerOpacity)}; + } + if (states.contains(WidgetState.hovered)) { + return ${componentColor(TokenIconButtonTonal.selectedHoveredStateLayerColor, TokenIconButtonTonal.hoveredStateLayerOpacity)}; + } + if (states.contains(WidgetState.focused)) { + return ${componentColor(TokenIconButtonTonal.selectedFocusedStateLayerColor, TokenIconButtonTonal.focusedStateLayerOpacity)}; + } + } + if (toggleable) { + if (states.contains(WidgetState.pressed)) { + return ${componentColor(TokenIconButtonTonal.unselectedPressedStateLayerColor, TokenIconButtonTonal.pressedStateLayerOpacity)}; + } + if (states.contains(WidgetState.hovered)) { + return ${componentColor(TokenIconButtonTonal.unselectedHoveredStateLayerColor, TokenIconButtonTonal.hoveredStateLayerOpacity)}; + } + if (states.contains(WidgetState.focused)) { + return ${componentColor(TokenIconButtonTonal.unselectedFocusedStateLayerColor, TokenIconButtonTonal.focusedStateLayerOpacity)}; + } + } + if (states.contains(WidgetState.pressed)) { + return ${componentColor(TokenIconButtonTonal.pressedStateLayerColor, TokenIconButtonTonal.pressedStateLayerOpacity)}; + } + if (states.contains(WidgetState.hovered)) { + return ${componentColor(TokenIconButtonTonal.hoveredStateLayerColor, TokenIconButtonTonal.hoveredStateLayerOpacity)}; + } + if (states.contains(WidgetState.focused)) { + return ${componentColor(TokenIconButtonTonal.focusedStateLayerColor, TokenIconButtonTonal.focusedStateLayerOpacity)}; + } + return Colors.transparent; + }); + + @override + WidgetStateProperty? get elevation => + const MaterialStatePropertyAll(0.0); + + @override + WidgetStateProperty? get shadowColor => + const MaterialStatePropertyAll(Colors.transparent); + + @override + WidgetStateProperty? get surfaceTintColor => + const MaterialStatePropertyAll(Colors.transparent); + +$_sizeDependentProperties + + @override + WidgetStateProperty? get side => null; + + @override + WidgetStateProperty? get mouseCursor => WidgetStateMouseCursor.adaptiveClickable; + + @override + VisualDensity? get visualDensity => VisualDensity.standard; + + @override + MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + + @override + InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; +} +'''; + } + + String _generateOutlinedDefaults() { + return ''' +class _M3EOutlinedIconButtonDefaults extends ButtonStyle { + _M3EOutlinedIconButtonDefaults( + this.context, + this.toggleable, + this.buttonSize, + this.buttonWidth, + this.buttonShape, + ) + : super( + animationDuration: kThemeChangeDuration, + enableFeedback: true, + alignment: Alignment.center, + ); + + final BuildContext context; + final bool toggleable; + final ButtonSize? buttonSize; + final IconButtonWidth? buttonWidth; + final IconButtonShape? buttonShape; + late final ColorScheme _colors = Theme.of(context).colorScheme; + + @override + WidgetStateProperty? get backgroundColor => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.disabled)) { + if (toggleable && states.contains(WidgetState.selected)) { + return ${componentColor(TokenIconButtonOutlined.selectedDisabledContainerColor, TokenIconButtonOutlined.selectedDisabledContainerOpacity)}; + } + return Colors.transparent; + } + if (toggleable && states.contains(WidgetState.selected)) { + return ${tokenColor(TokenIconButtonOutlined.selectedContainerColor)}; + } + return Colors.transparent; + }); + + @override + WidgetStateProperty? get foregroundColor => + WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.disabled)) { + return ${componentColor(TokenIconButtonOutlined.disabledIconColor, TokenIconButtonOutlined.disabledIconOpacity)}; + } + if (toggleable && states.contains(WidgetState.selected)) { + return ${tokenColor(TokenIconButtonOutlined.selectedIconColor)}; + } + return ${tokenColor(TokenIconButtonOutlined.iconColor)}; + }); + + @override + WidgetStateProperty? get overlayColor => + WidgetStateProperty.resolveWith((Set states) { + if (toggleable && states.contains(WidgetState.selected)) { + if (states.contains(WidgetState.pressed)) { + return ${componentColor(TokenIconButtonOutlined.selectedPressedStateLayerColor, TokenIconButtonOutlined.pressedStateLayerOpacity)}; + } + if (states.contains(WidgetState.hovered)) { + return ${componentColor(TokenIconButtonOutlined.selectedHoveredStateLayerColor, TokenIconButtonOutlined.hoveredStateLayerOpacity)}; + } + if (states.contains(WidgetState.focused)) { + return ${componentColor(TokenIconButtonOutlined.selectedFocusedStateLayerColor, TokenIconButtonOutlined.focusedStateLayerOpacity)}; + } + } + if (states.contains(WidgetState.pressed)) { + return ${componentColor(TokenIconButtonOutlined.pressedStateLayerColor, TokenIconButtonOutlined.pressedStateLayerOpacity)}; + } + if (states.contains(WidgetState.hovered)) { + return ${componentColor(TokenIconButtonOutlined.hoveredStateLayerColor, TokenIconButtonOutlined.hoveredStateLayerOpacity)}; + } + if (states.contains(WidgetState.focused)) { + return ${componentColor(TokenIconButtonOutlined.focusedStateLayerColor, TokenIconButtonOutlined.focusedStateLayerOpacity)}; + } + return Colors.transparent; + }); + + @override + WidgetStateProperty? get elevation => + const MaterialStatePropertyAll(0.0); + + @override + WidgetStateProperty? get shadowColor => + const MaterialStatePropertyAll(Colors.transparent); + + @override + WidgetStateProperty? get surfaceTintColor => + const MaterialStatePropertyAll(Colors.transparent); + +$_sizeDependentProperties + + @override + WidgetStateProperty? get side => + WidgetStateProperty.resolveWith((Set states) { + if (toggleable && states.contains(WidgetState.selected)) { + return null; + } + if (states.contains(WidgetState.disabled)) { + return BorderSide(color: ${tokenColor(TokenIconButtonOutlined.unselectedDisabledOutlineColor)}, width: $_outlineWidthSwitch); + } + return BorderSide(color: ${tokenColor(TokenIconButtonOutlined.outlineColor)}, width: $_outlineWidthSwitch); + }); + + @override + WidgetStateProperty? get mouseCursor => WidgetStateMouseCursor.adaptiveClickable; + + @override + VisualDensity? get visualDensity => VisualDensity.standard; + + @override + MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + + @override + InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; +} +'''; + } +} From ca7c3e48abea5d8f29d1fcecba8514031b696ed8 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Fri, 7 Aug 2026 17:10:45 -0700 Subject: [PATCH 02/31] Rename IconButton M3E template --- packages/material_ui/tool/gen_defaults/bin/gen_defaults.dart | 5 +++-- .../tool/gen_defaults/templates/icon_button_template.dart | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/material_ui/tool/gen_defaults/bin/gen_defaults.dart b/packages/material_ui/tool/gen_defaults/bin/gen_defaults.dart index cf90a94907ae..1aa834d1f711 100644 --- a/packages/material_ui/tool/gen_defaults/bin/gen_defaults.dart +++ b/packages/material_ui/tool/gen_defaults/bin/gen_defaults.dart @@ -14,8 +14,8 @@ import 'package:args/args.dart'; import '../templates/action_chip_template.dart'; import '../templates/app_bar_template.dart'; -import '../templates/banner_template.dart'; import '../templates/badge_template.dart'; +import '../templates/banner_template.dart'; // import '../templates/bottom_app_bar_template.dart'; import '../templates/bottom_sheet_template.dart'; // import '../templates/button_template.dart'; @@ -82,7 +82,8 @@ Future main(List args) async { // const ExpansionTileTemplateM3().generateFile(verbose: verbose); // const FabTemplateM3().generateFile(verbose: verbose); // const FilterChipTemplateM3().generateFile(verbose: verbose); - const IconButtonTemplate().generateFile(verbose: verbose); + // const IconButtonTemplateM3().generateFile(verbose: verbose); + const IconButtonTemplateM3E().generateFile(verbose: verbose); // const InputChipTemplateM3().generateFile(verbose: verbose); // const InputDecoratorTemplateM3().generateFile(verbose: verbose); // const ListTileTemplateM3().generateFile(verbose: verbose); diff --git a/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart b/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart index 962491931571..e3c6969d2bdf 100644 --- a/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart +++ b/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart @@ -14,8 +14,8 @@ import '../data/icon_button_xlarge.dart'; import '../data/icon_button_xsmall.dart'; import 'template.dart'; -class IconButtonTemplate extends TokenTemplateM3E { - const IconButtonTemplate(); +class IconButtonTemplateM3E extends TokenTemplateM3E { + const IconButtonTemplateM3E(); @override String get name => 'Icon Button'; From 2bb61e1dc44d1550204dd00f8250399ba94afc03 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Sun, 16 Aug 2026 19:50:29 -0700 Subject: [PATCH 03/31] Add IconButton xSmall tap target coverage --- .../material_ui/test/icon_button_test.dart | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/material_ui/test/icon_button_test.dart b/packages/material_ui/test/icon_button_test.dart index 95cafa50c451..8001fda258c8 100644 --- a/packages/material_ui/test/icon_button_test.dart +++ b/packages/material_ui/test/icon_button_test.dart @@ -3618,11 +3618,16 @@ void main() { expect(tester.getSize(find.byType(IconButton)), const Size(48.0, 48.0)); }); - testWidgets('xSmall size renders at 32dp minimum', (WidgetTester tester) async { + testWidgets('xSmall size renders at 32dp minimum with 48dp tap target', ( + WidgetTester tester, + ) async { + int pressCount = 0; await tester.pumpWidget( buildM3EApp( child: IconButton( - onPressed: () {}, + onPressed: () { + pressCount += 1; + }, icon: const Icon(Icons.add), style: const ButtonStyle(size: ButtonSize.xSmall), ), @@ -3631,6 +3636,19 @@ void main() { expect(m3eIconButtonMaterialSize(tester), const Size(32.0, 32.0)); expect(tester.getSize(find.byType(IconButton)), const Size(48.0, 48.0)); + + final Offset center = tester.getCenter(find.byType(IconButton)); + for (final Offset offset in const [ + Offset(23.0, 0.0), + Offset(-23.0, 0.0), + Offset(0.0, 23.0), + Offset(0.0, -23.0), + ]) { + await tester.tapAt(center + offset); + await tester.pump(); + } + + expect(pressCount, 4); }); testWidgets('styleFrom sets the size variant', (WidgetTester tester) async { From 2bc07db23dd703bee0d246ff5feb243eeca224a0 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 14:33:04 -0700 Subject: [PATCH 04/31] Rename IconButton M3E style variants --- .../material_ui/lib/src/button_style.dart | 42 ++++----- .../generated/icon_button_defaults_m3e.g.dart | 56 ++++++------ packages/material_ui/lib/src/icon_button.dart | 22 ++--- .../material_ui/test/icon_button_test.dart | 86 +++++++++---------- .../templates/icon_button_template.dart | 20 ++--- 5 files changed, 113 insertions(+), 113 deletions(-) diff --git a/packages/material_ui/lib/src/button_style.dart b/packages/material_ui/lib/src/button_style.dart index 95666b215b46..7f5d3da12f33 100644 --- a/packages/material_ui/lib/src/button_style.dart +++ b/packages/material_ui/lib/src/button_style.dart @@ -63,8 +63,8 @@ enum IconButtonWidth { wide, } -/// Defines the shape variants for Material 3 Expressive [IconButton]. -enum IconButtonShape { +/// Defines shape variants for Material 3 Expressive button components. +enum ButtonShapeVariant { /// Uses the round shape tokens. round, @@ -228,9 +228,9 @@ class ButtonStyle with Diagnosticable { this.splashFactory, this.backgroundBuilder, this.foregroundBuilder, - this.size, + this.sizeVariant, this.iconButtonWidth, - this.iconButtonShape, + this.shapeVariant, }); /// The style for a button's [Text] widget descendants. @@ -468,13 +468,13 @@ class ButtonStyle with Diagnosticable { final ButtonLayerBuilder? foregroundBuilder; /// The size variant for this button. - final ButtonSize? size; + final ButtonSize? sizeVariant; /// The width variant for this icon button. final IconButtonWidth? iconButtonWidth; - /// The shape variant for this icon button. - final IconButtonShape? iconButtonShape; + /// The shape variant for this button. + final ButtonShapeVariant? shapeVariant; /// Returns a copy of this ButtonStyle with the given fields replaced with /// the new values. @@ -504,9 +504,9 @@ class ButtonStyle with Diagnosticable { InteractiveInkFeatureFactory? splashFactory, ButtonLayerBuilder? backgroundBuilder, ButtonLayerBuilder? foregroundBuilder, - ButtonSize? size, + ButtonSize? sizeVariant, IconButtonWidth? iconButtonWidth, - IconButtonShape? iconButtonShape, + ButtonShapeVariant? shapeVariant, }) { return ButtonStyle( textStyle: textStyle ?? this.textStyle, @@ -534,9 +534,9 @@ class ButtonStyle with Diagnosticable { splashFactory: splashFactory ?? this.splashFactory, backgroundBuilder: backgroundBuilder ?? this.backgroundBuilder, foregroundBuilder: foregroundBuilder ?? this.foregroundBuilder, - size: size ?? this.size, + sizeVariant: sizeVariant ?? this.sizeVariant, iconButtonWidth: iconButtonWidth ?? this.iconButtonWidth, - iconButtonShape: iconButtonShape ?? this.iconButtonShape, + shapeVariant: shapeVariant ?? this.shapeVariant, ); } @@ -575,9 +575,9 @@ class ButtonStyle with Diagnosticable { splashFactory: splashFactory ?? style.splashFactory, backgroundBuilder: backgroundBuilder ?? style.backgroundBuilder, foregroundBuilder: foregroundBuilder ?? style.foregroundBuilder, - size: size ?? style.size, + sizeVariant: sizeVariant ?? style.sizeVariant, iconButtonWidth: iconButtonWidth ?? style.iconButtonWidth, - iconButtonShape: iconButtonShape ?? style.iconButtonShape, + shapeVariant: shapeVariant ?? style.shapeVariant, ); } @@ -609,9 +609,9 @@ class ButtonStyle with Diagnosticable { splashFactory, backgroundBuilder, foregroundBuilder, - size, + sizeVariant, iconButtonWidth, - iconButtonShape, + shapeVariant, ]; return Object.hashAll(values); } @@ -650,9 +650,9 @@ class ButtonStyle with Diagnosticable { other.splashFactory == splashFactory && other.backgroundBuilder == backgroundBuilder && other.foregroundBuilder == foregroundBuilder && - other.size == size && + other.sizeVariant == sizeVariant && other.iconButtonWidth == iconButtonWidth && - other.iconButtonShape == iconButtonShape; + other.shapeVariant == shapeVariant; } @override @@ -774,12 +774,12 @@ class ButtonStyle with Diagnosticable { defaultValue: null, ), ); - properties.add(EnumProperty('size', size, defaultValue: null)); + properties.add(EnumProperty('sizeVariant', sizeVariant, defaultValue: null)); properties.add( EnumProperty('iconButtonWidth', iconButtonWidth, defaultValue: null), ); properties.add( - EnumProperty('iconButtonShape', iconButtonShape, defaultValue: null), + EnumProperty('shapeVariant', shapeVariant, defaultValue: null), ); } @@ -844,9 +844,9 @@ class ButtonStyle with Diagnosticable { splashFactory: t < 0.5 ? a?.splashFactory : b?.splashFactory, backgroundBuilder: t < 0.5 ? a?.backgroundBuilder : b?.backgroundBuilder, foregroundBuilder: t < 0.5 ? a?.foregroundBuilder : b?.foregroundBuilder, - size: t < 0.5 ? a?.size : b?.size, + sizeVariant: t < 0.5 ? a?.sizeVariant : b?.sizeVariant, iconButtonWidth: t < 0.5 ? a?.iconButtonWidth : b?.iconButtonWidth, - iconButtonShape: t < 0.5 ? a?.iconButtonShape : b?.iconButtonShape, + shapeVariant: t < 0.5 ? a?.shapeVariant : b?.shapeVariant, ); } } diff --git a/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart b/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart index 9ee830af00c8..be5cd59164d4 100644 --- a/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart +++ b/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart @@ -24,7 +24,7 @@ class _IconButtonDefaultsM3E extends ButtonStyle { final bool toggleable; final ButtonSize? buttonSize; final IconButtonWidth? buttonWidth; - final IconButtonShape? buttonShape; + final ButtonShapeVariant? buttonShape; late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -176,8 +176,8 @@ class _IconButtonDefaultsM3E extends ButtonStyle { }; } if (toggleable && states.contains(WidgetState.selected)) { - return switch (buttonShape ?? IconButtonShape.round) { - IconButtonShape.round => switch (buttonSize ?? ButtonSize.small) { + return switch (buttonShape ?? ButtonShapeVariant.round) { + ButtonShapeVariant.round => switch (buttonSize ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -194,7 +194,7 @@ class _IconButtonDefaultsM3E extends ButtonStyle { borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, - IconButtonShape.square => switch (buttonSize ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (buttonSize ?? ButtonSize.small) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), @@ -203,15 +203,15 @@ class _IconButtonDefaultsM3E extends ButtonStyle { }, }; } - return switch (buttonShape ?? IconButtonShape.round) { - IconButtonShape.round => switch (buttonSize ?? ButtonSize.small) { + return switch (buttonShape ?? ButtonShapeVariant.round) { + ButtonShapeVariant.round => switch (buttonSize ?? ButtonSize.small) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), ButtonSize.large => const StadiumBorder(), ButtonSize.xLarge => const StadiumBorder(), }, - IconButtonShape.square => switch (buttonSize ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (buttonSize ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -264,7 +264,7 @@ class _M3EFilledIconButtonDefaults extends ButtonStyle { final bool toggleable; final ButtonSize? buttonSize; final IconButtonWidth? buttonWidth; - final IconButtonShape? buttonShape; + final ButtonShapeVariant? buttonShape; late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -441,8 +441,8 @@ class _M3EFilledIconButtonDefaults extends ButtonStyle { }; } if (toggleable && states.contains(WidgetState.selected)) { - return switch (buttonShape ?? IconButtonShape.round) { - IconButtonShape.round => switch (buttonSize ?? ButtonSize.small) { + return switch (buttonShape ?? ButtonShapeVariant.round) { + ButtonShapeVariant.round => switch (buttonSize ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -459,7 +459,7 @@ class _M3EFilledIconButtonDefaults extends ButtonStyle { borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, - IconButtonShape.square => switch (buttonSize ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (buttonSize ?? ButtonSize.small) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), @@ -468,15 +468,15 @@ class _M3EFilledIconButtonDefaults extends ButtonStyle { }, }; } - return switch (buttonShape ?? IconButtonShape.round) { - IconButtonShape.round => switch (buttonSize ?? ButtonSize.small) { + return switch (buttonShape ?? ButtonShapeVariant.round) { + ButtonShapeVariant.round => switch (buttonSize ?? ButtonSize.small) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), ButtonSize.large => const StadiumBorder(), ButtonSize.xLarge => const StadiumBorder(), }, - IconButtonShape.square => switch (buttonSize ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (buttonSize ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -529,7 +529,7 @@ class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { final bool toggleable; final ButtonSize? buttonSize; final IconButtonWidth? buttonWidth; - final IconButtonShape? buttonShape; + final ButtonShapeVariant? buttonShape; late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -706,8 +706,8 @@ class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { }; } if (toggleable && states.contains(WidgetState.selected)) { - return switch (buttonShape ?? IconButtonShape.round) { - IconButtonShape.round => switch (buttonSize ?? ButtonSize.small) { + return switch (buttonShape ?? ButtonShapeVariant.round) { + ButtonShapeVariant.round => switch (buttonSize ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -724,7 +724,7 @@ class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, - IconButtonShape.square => switch (buttonSize ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (buttonSize ?? ButtonSize.small) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), @@ -733,15 +733,15 @@ class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { }, }; } - return switch (buttonShape ?? IconButtonShape.round) { - IconButtonShape.round => switch (buttonSize ?? ButtonSize.small) { + return switch (buttonShape ?? ButtonShapeVariant.round) { + ButtonShapeVariant.round => switch (buttonSize ?? ButtonSize.small) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), ButtonSize.large => const StadiumBorder(), ButtonSize.xLarge => const StadiumBorder(), }, - IconButtonShape.square => switch (buttonSize ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (buttonSize ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -794,7 +794,7 @@ class _M3EOutlinedIconButtonDefaults extends ButtonStyle { final bool toggleable; final ButtonSize? buttonSize; final IconButtonWidth? buttonWidth; - final IconButtonShape? buttonShape; + final ButtonShapeVariant? buttonShape; late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -957,8 +957,8 @@ class _M3EOutlinedIconButtonDefaults extends ButtonStyle { }; } if (toggleable && states.contains(WidgetState.selected)) { - return switch (buttonShape ?? IconButtonShape.round) { - IconButtonShape.round => switch (buttonSize ?? ButtonSize.small) { + return switch (buttonShape ?? ButtonShapeVariant.round) { + ButtonShapeVariant.round => switch (buttonSize ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -975,7 +975,7 @@ class _M3EOutlinedIconButtonDefaults extends ButtonStyle { borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, - IconButtonShape.square => switch (buttonSize ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (buttonSize ?? ButtonSize.small) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), @@ -984,15 +984,15 @@ class _M3EOutlinedIconButtonDefaults extends ButtonStyle { }, }; } - return switch (buttonShape ?? IconButtonShape.round) { - IconButtonShape.round => switch (buttonSize ?? ButtonSize.small) { + return switch (buttonShape ?? ButtonShapeVariant.round) { + ButtonShapeVariant.round => switch (buttonSize ?? ButtonSize.small) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), ButtonSize.large => const StadiumBorder(), ButtonSize.xLarge => const StadiumBorder(), }, - IconButtonShape.square => switch (buttonSize ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (buttonSize ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), diff --git a/packages/material_ui/lib/src/icon_button.dart b/packages/material_ui/lib/src/icon_button.dart index 54351408d99a..e6d132959635 100644 --- a/packages/material_ui/lib/src/icon_button.dart +++ b/packages/material_ui/lib/src/icon_button.dart @@ -628,10 +628,10 @@ class IconButton extends StatelessWidget { /// create a [WidgetStateProperty] with a single value for all /// states. /// - /// The [size], [iconButtonWidth], and [iconButtonShape] parameters configure + /// The [sizeVariant], [iconButtonWidth], and [shapeVariant] parameters configure /// the Material 3 Expressive token size, width, and shape through - /// [ButtonStyle.size], [ButtonStyle.iconButtonWidth], and - /// [ButtonStyle.iconButtonShape]. + /// [ButtonStyle.sizeVariant], [ButtonStyle.iconButtonWidth], and + /// [ButtonStyle.shapeVariant]. /// /// All parameters default to null, by default this method returns /// a [ButtonStyle] that doesn't override anything. @@ -677,9 +677,9 @@ class IconButton extends StatelessWidget { bool? enableFeedback, AlignmentGeometry? alignment, InteractiveInkFeatureFactory? splashFactory, - ButtonSize? size, + ButtonSize? sizeVariant, IconButtonWidth? iconButtonWidth, - IconButtonShape? iconButtonShape, + ButtonShapeVariant? shapeVariant, }) { final Color? overlayFallback = overlayColor ?? foregroundColor; WidgetStateProperty? overlayColorProp; @@ -720,9 +720,9 @@ class IconButton extends StatelessWidget { enableFeedback: enableFeedback, alignment: alignment, splashFactory: splashFactory, - size: size, + sizeVariant: sizeVariant, iconButtonWidth: iconButtonWidth, - iconButtonShape: iconButtonShape, + shapeVariant: shapeVariant, ); } @@ -1000,15 +1000,15 @@ class _IconButtonM3 extends ButtonStyleButton { final bool toggleable; ButtonSize? _effectiveSize(BuildContext context) { - return style?.size ?? IconButtonTheme.of(context).style?.size; + return style?.sizeVariant ?? IconButtonTheme.of(context).style?.sizeVariant; } IconButtonWidth? _effectiveWidth(BuildContext context) { return style?.iconButtonWidth ?? IconButtonTheme.of(context).style?.iconButtonWidth; } - IconButtonShape? _effectiveShape(BuildContext context) { - return style?.iconButtonShape ?? IconButtonTheme.of(context).style?.iconButtonShape; + ButtonShapeVariant? _effectiveShape(BuildContext context) { + return style?.shapeVariant ?? IconButtonTheme.of(context).style?.shapeVariant; } /// ## Material 3 defaults @@ -1050,7 +1050,7 @@ class _IconButtonM3 extends ButtonStyleButton { ButtonStyle defaultStyleOf(BuildContext context) { final ButtonSize? effectiveSize = _effectiveSize(context); final IconButtonWidth? effectiveWidth = _effectiveWidth(context); - final IconButtonShape? effectiveShape = _effectiveShape(context); + final ButtonShapeVariant? effectiveShape = _effectiveShape(context); return switch (styleVariant) { StyleVariant.material3 => switch (iconButtonVariant) { diff --git a/packages/material_ui/test/icon_button_test.dart b/packages/material_ui/test/icon_button_test.dart index 8001fda258c8..541651eb3870 100644 --- a/packages/material_ui/test/icon_button_test.dart +++ b/packages/material_ui/test/icon_button_test.dart @@ -3621,7 +3621,7 @@ void main() { testWidgets('xSmall size renders at 32dp minimum with 48dp tap target', ( WidgetTester tester, ) async { - int pressCount = 0; + var pressCount = 0; await tester.pumpWidget( buildM3EApp( child: IconButton( @@ -3629,7 +3629,7 @@ void main() { pressCount += 1; }, icon: const Icon(Icons.add), - style: const ButtonStyle(size: ButtonSize.xSmall), + style: const ButtonStyle(sizeVariant: ButtonSize.xSmall), ), ), ); @@ -3638,7 +3638,7 @@ void main() { expect(tester.getSize(find.byType(IconButton)), const Size(48.0, 48.0)); final Offset center = tester.getCenter(find.byType(IconButton)); - for (final Offset offset in const [ + for (final offset in const [ Offset(23.0, 0.0), Offset(-23.0, 0.0), Offset(0.0, 23.0), @@ -3657,7 +3657,7 @@ void main() { child: IconButton( onPressed: () {}, icon: const Icon(Icons.add), - style: IconButton.styleFrom(size: ButtonSize.medium), + style: IconButton.styleFrom(sizeVariant: ButtonSize.medium), ), ), ); @@ -3672,7 +3672,7 @@ void main() { child: IconButton( onPressed: () {}, icon: const Icon(Icons.add), - style: const ButtonStyle(size: ButtonSize.medium), + style: const ButtonStyle(sizeVariant: ButtonSize.medium), ), ), ); @@ -3687,7 +3687,7 @@ void main() { child: IconButton( onPressed: () {}, icon: const Icon(Icons.add), - style: const ButtonStyle(size: ButtonSize.large), + style: const ButtonStyle(sizeVariant: ButtonSize.large), ), ), ); @@ -3702,7 +3702,7 @@ void main() { child: IconButton( onPressed: () {}, icon: const Icon(Icons.add), - style: const ButtonStyle(size: ButtonSize.xLarge), + style: const ButtonStyle(sizeVariant: ButtonSize.xLarge), ), ), ); @@ -3799,8 +3799,8 @@ void main() { onPressed: () {}, icon: const Icon(Icons.add), style: const ButtonStyle( - size: ButtonSize.medium, - iconButtonShape: IconButtonShape.square, + sizeVariant: ButtonSize.medium, + shapeVariant: ButtonShapeVariant.square, ), ), ), @@ -3828,8 +3828,8 @@ void main() { onPressed: () {}, icon: const Icon(Icons.add), style: const ButtonStyle( - size: ButtonSize.medium, - iconButtonShape: IconButtonShape.square, + sizeVariant: ButtonSize.medium, + shapeVariant: ButtonShapeVariant.square, ), ), ), @@ -3933,7 +3933,7 @@ void main() { child: IconButton.filled( onPressed: () {}, icon: const Icon(Icons.add), - style: const ButtonStyle(size: ButtonSize.large), + style: const ButtonStyle(sizeVariant: ButtonSize.large), ), ), ); @@ -3948,7 +3948,7 @@ void main() { child: IconButton.outlined( onPressed: () {}, icon: const Icon(Icons.add), - style: const ButtonStyle(size: ButtonSize.medium), + style: const ButtonStyle(sizeVariant: ButtonSize.medium), ), ), ); @@ -3965,7 +3965,7 @@ void main() { theme: ThemeData( useMaterial3: true, iconButtonTheme: const IconButtonThemeData( - style: ButtonStyle(size: ButtonSize.large), + style: ButtonStyle(sizeVariant: ButtonSize.large), variant: StyleVariant.material3Expressive, ), ), @@ -3983,14 +3983,14 @@ void main() { theme: ThemeData( useMaterial3: true, iconButtonTheme: const IconButtonThemeData( - style: ButtonStyle(size: ButtonSize.large), + style: ButtonStyle(sizeVariant: ButtonSize.large), variant: StyleVariant.material3Expressive, ), ), child: IconButton( onPressed: () {}, icon: const Icon(Icons.add), - style: const ButtonStyle(size: ButtonSize.xSmall), + style: const ButtonStyle(sizeVariant: ButtonSize.xSmall), ), ), ); @@ -4004,7 +4004,7 @@ void main() { buildM3EApp( child: IconButtonTheme( data: const IconButtonThemeData( - style: ButtonStyle(size: ButtonSize.medium), + style: ButtonStyle(sizeVariant: ButtonSize.medium), variant: StyleVariant.material3Expressive, ), child: IconButton(onPressed: () {}, icon: const Icon(Icons.add)), @@ -4216,23 +4216,23 @@ void main() { test('equality', () { const a = IconButtonThemeData( style: ButtonStyle( - size: ButtonSize.small, + sizeVariant: ButtonSize.small, iconButtonWidth: IconButtonWidth.standard, - iconButtonShape: IconButtonShape.round, + shapeVariant: ButtonShapeVariant.round, ), ); const b = IconButtonThemeData( style: ButtonStyle( - size: ButtonSize.small, + sizeVariant: ButtonSize.small, iconButtonWidth: IconButtonWidth.standard, - iconButtonShape: IconButtonShape.round, + shapeVariant: ButtonShapeVariant.round, ), ); const c = IconButtonThemeData( style: ButtonStyle( - size: ButtonSize.large, + sizeVariant: ButtonSize.large, iconButtonWidth: IconButtonWidth.wide, - iconButtonShape: IconButtonShape.square, + shapeVariant: ButtonShapeVariant.square, ), ); @@ -4243,16 +4243,16 @@ void main() { test('hashCode', () { const a = IconButtonThemeData( style: ButtonStyle( - size: ButtonSize.small, + sizeVariant: ButtonSize.small, iconButtonWidth: IconButtonWidth.narrow, - iconButtonShape: IconButtonShape.round, + shapeVariant: ButtonShapeVariant.round, ), ); const b = IconButtonThemeData( style: ButtonStyle( - size: ButtonSize.small, + sizeVariant: ButtonSize.small, iconButtonWidth: IconButtonWidth.narrow, - iconButtonShape: IconButtonShape.round, + shapeVariant: ButtonShapeVariant.round, ), ); @@ -4262,35 +4262,35 @@ void main() { test('lerp', () { const a = IconButtonThemeData( style: ButtonStyle( - size: ButtonSize.small, + sizeVariant: ButtonSize.small, iconButtonWidth: IconButtonWidth.narrow, - iconButtonShape: IconButtonShape.round, + shapeVariant: ButtonShapeVariant.round, ), ); const b = IconButtonThemeData( style: ButtonStyle( - size: ButtonSize.large, + sizeVariant: ButtonSize.large, iconButtonWidth: IconButtonWidth.wide, - iconButtonShape: IconButtonShape.square, + shapeVariant: ButtonShapeVariant.square, ), ); - expect(IconButtonThemeData.lerp(a, b, 0.0)?.style?.size, ButtonSize.small); - expect(IconButtonThemeData.lerp(a, b, 0.4)?.style?.size, ButtonSize.small); - expect(IconButtonThemeData.lerp(a, b, 0.5)?.style?.size, ButtonSize.large); - expect(IconButtonThemeData.lerp(a, b, 1.0)?.style?.size, ButtonSize.large); + expect(IconButtonThemeData.lerp(a, b, 0.0)?.style?.sizeVariant, ButtonSize.small); + expect(IconButtonThemeData.lerp(a, b, 0.4)?.style?.sizeVariant, ButtonSize.small); + expect(IconButtonThemeData.lerp(a, b, 0.5)?.style?.sizeVariant, ButtonSize.large); + expect(IconButtonThemeData.lerp(a, b, 1.0)?.style?.sizeVariant, ButtonSize.large); expect(IconButtonThemeData.lerp(a, b, 0.4)?.style?.iconButtonWidth, IconButtonWidth.narrow); expect(IconButtonThemeData.lerp(a, b, 0.5)?.style?.iconButtonWidth, IconButtonWidth.wide); - expect(IconButtonThemeData.lerp(a, b, 0.4)?.style?.iconButtonShape, IconButtonShape.round); - expect(IconButtonThemeData.lerp(a, b, 0.5)?.style?.iconButtonShape, IconButtonShape.square); + expect(IconButtonThemeData.lerp(a, b, 0.4)?.style?.shapeVariant, ButtonShapeVariant.round); + expect(IconButtonThemeData.lerp(a, b, 0.5)?.style?.shapeVariant, ButtonShapeVariant.square); }); - test('debugFillProperties includes size, width, and shape', () { + test('debugFillProperties includes size variant, width, and shape variant', () { const data = IconButtonThemeData( style: ButtonStyle( - size: ButtonSize.medium, + sizeVariant: ButtonSize.medium, iconButtonWidth: IconButtonWidth.wide, - iconButtonShape: IconButtonShape.square, + shapeVariant: ButtonShapeVariant.square, ), ); final builder = DiagnosticPropertiesBuilder(); @@ -4301,9 +4301,9 @@ void main() { .map((DiagnosticsNode node) => node.toString()) .toList(); - expect(descriptions, contains(contains('size: medium'))); + expect(descriptions, contains(contains('sizeVariant: medium'))); expect(descriptions, contains(contains('iconButtonWidth: wide'))); - expect(descriptions, contains(contains('iconButtonShape: square'))); + expect(descriptions, contains(contains('shapeVariant: square'))); }); }); @@ -4314,7 +4314,7 @@ void main() { child: IconButton( onPressed: () {}, icon: const Icon(Icons.add), - style: const ButtonStyle(size: ButtonSize.medium), + style: const ButtonStyle(sizeVariant: ButtonSize.medium), ), ), ); diff --git a/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart b/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart index e3c6969d2bdf..7328909e5cc0 100644 --- a/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart +++ b/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart @@ -241,9 +241,9 @@ switch (buttonWidth ?? IconButtonWidth.standard) { String get _containerShapeSwitch { return ''' -switch (buttonShape ?? IconButtonShape.round) { - IconButtonShape.round => $_containerRoundShapeSwitch, - IconButtonShape.square => $_containerSquareShapeSwitch, +switch (buttonShape ?? ButtonShapeVariant.round) { + ButtonShapeVariant.round => $_containerRoundShapeSwitch, + ButtonShapeVariant.square => $_containerSquareShapeSwitch, }'''; } @@ -279,9 +279,9 @@ switch (buttonShape ?? IconButtonShape.round) { String get _selectedShapeSwitch { return ''' -switch (buttonShape ?? IconButtonShape.round) { - IconButtonShape.round => $_selectedRoundShapeSwitch, - IconButtonShape.square => $_selectedSquareShapeSwitch, +switch (buttonShape ?? ButtonShapeVariant.round) { + ButtonShapeVariant.round => $_selectedRoundShapeSwitch, + ButtonShapeVariant.square => $_selectedSquareShapeSwitch, }'''; } @@ -331,7 +331,7 @@ class $className extends ButtonStyle { final bool toggleable; final ButtonSize? buttonSize; final IconButtonWidth? buttonWidth; - final IconButtonShape? buttonShape; + final ButtonShapeVariant? buttonShape; late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -428,7 +428,7 @@ class _M3EFilledIconButtonDefaults extends ButtonStyle { final bool toggleable; final ButtonSize? buttonSize; final IconButtonWidth? buttonWidth; - final IconButtonShape? buttonShape; + final ButtonShapeVariant? buttonShape; late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -550,7 +550,7 @@ class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { final bool toggleable; final ButtonSize? buttonSize; final IconButtonWidth? buttonWidth; - final IconButtonShape? buttonShape; + final ButtonShapeVariant? buttonShape; late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -672,7 +672,7 @@ class _M3EOutlinedIconButtonDefaults extends ButtonStyle { final bool toggleable; final ButtonSize? buttonSize; final IconButtonWidth? buttonWidth; - final IconButtonShape? buttonShape; + final ButtonShapeVariant? buttonShape; late final ColorScheme _colors = Theme.of(context).colorScheme; @override From 97329e3cdb5235f8653b869225b06ee56538847e Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 14:57:19 -0700 Subject: [PATCH 05/31] Rename M3E IconButton default internals --- .../generated/icon_button_defaults_m3e.g.dart | 224 +++++++++--------- packages/material_ui/lib/src/icon_button.dart | 6 +- .../templates/icon_button_template.dart | 66 +++--- 3 files changed, 148 insertions(+), 148 deletions(-) diff --git a/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart b/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart index be5cd59164d4..3dc79d201d57 100644 --- a/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart +++ b/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart @@ -11,9 +11,9 @@ class _IconButtonDefaultsM3E extends ButtonStyle { _IconButtonDefaultsM3E( this.context, this.toggleable, - this.buttonSize, - this.buttonWidth, - this.buttonShape, + this.sizeVariant, + this.iconButtonWidth, + this.shapeVariant, ) : super( animationDuration: kThemeChangeDuration, enableFeedback: true, @@ -22,9 +22,9 @@ class _IconButtonDefaultsM3E extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? buttonSize; - final IconButtonWidth? buttonWidth; - final ButtonShapeVariant? buttonShape; + final ButtonSize? sizeVariant; + final IconButtonWidth? iconButtonWidth; + final ButtonShapeVariant? shapeVariant; late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -82,28 +82,28 @@ class _IconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get padding => - MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { - ButtonSize.xSmall => switch (buttonWidth ?? IconButtonWidth.standard) { + MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { + ButtonSize.xSmall => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), }, - ButtonSize.small => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.small => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), }, - ButtonSize.medium => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.medium => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(16.0, 16.0, 16.0, 16.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), }, - ButtonSize.large => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.large => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(32.0, 32.0, 32.0, 32.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), }, - ButtonSize.xLarge => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.xLarge => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(48.0, 48.0, 48.0, 48.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), @@ -112,28 +112,28 @@ class _IconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get minimumSize => - MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { - ButtonSize.xSmall => switch (buttonWidth ?? IconButtonWidth.standard) { + MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { + ButtonSize.xSmall => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(28.0, 32.0), IconButtonWidth.standard => const Size(32.0, 32.0), IconButtonWidth.wide => const Size(40.0, 32.0), }, - ButtonSize.small => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.small => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(32.0, 40.0), IconButtonWidth.standard => const Size(40.0, 40.0), IconButtonWidth.wide => const Size(52.0, 40.0), }, - ButtonSize.medium => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.medium => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(48.0, 56.0), IconButtonWidth.standard => const Size(56.0, 56.0), IconButtonWidth.wide => const Size(72.0, 56.0), }, - ButtonSize.large => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.large => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(64.0, 96.0), IconButtonWidth.standard => const Size(96.0, 96.0), IconButtonWidth.wide => const Size(128.0, 96.0), }, - ButtonSize.xLarge => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.xLarge => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(104.0, 136.0), IconButtonWidth.standard => const Size(136.0, 136.0), IconButtonWidth.wide => const Size(184.0, 136.0), @@ -145,7 +145,7 @@ class _IconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get iconSize => - MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { + MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => 20.0, ButtonSize.small => 24.0, ButtonSize.medium => 24.0, @@ -157,7 +157,7 @@ class _IconButtonDefaultsM3E extends ButtonStyle { WidgetStateProperty? get shape => WidgetStateProperty.resolveWith((Set states) { if (states.contains(WidgetState.pressed)) { - return switch (buttonSize ?? ButtonSize.small) { + return switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), @@ -176,8 +176,8 @@ class _IconButtonDefaultsM3E extends ButtonStyle { }; } if (toggleable && states.contains(WidgetState.selected)) { - return switch (buttonShape ?? ButtonShapeVariant.round) { - ButtonShapeVariant.round => switch (buttonSize ?? ButtonSize.small) { + return switch (shapeVariant ?? ButtonShapeVariant.round) { + ButtonShapeVariant.round => switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -194,7 +194,7 @@ class _IconButtonDefaultsM3E extends ButtonStyle { borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, - ButtonShapeVariant.square => switch (buttonSize ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), @@ -203,15 +203,15 @@ class _IconButtonDefaultsM3E extends ButtonStyle { }, }; } - return switch (buttonShape ?? ButtonShapeVariant.round) { - ButtonShapeVariant.round => switch (buttonSize ?? ButtonSize.small) { + return switch (shapeVariant ?? ButtonShapeVariant.round) { + ButtonShapeVariant.round => switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), ButtonSize.large => const StadiumBorder(), ButtonSize.xLarge => const StadiumBorder(), }, - ButtonShapeVariant.square => switch (buttonSize ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -247,13 +247,13 @@ class _IconButtonDefaultsM3E extends ButtonStyle { InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; } -class _M3EFilledIconButtonDefaults extends ButtonStyle { - _M3EFilledIconButtonDefaults( +class _FilledIconButtonDefaultsM3E extends ButtonStyle { + _FilledIconButtonDefaultsM3E( this.context, this.toggleable, - this.buttonSize, - this.buttonWidth, - this.buttonShape, + this.sizeVariant, + this.iconButtonWidth, + this.shapeVariant, ) : super( animationDuration: kThemeChangeDuration, enableFeedback: true, @@ -262,9 +262,9 @@ class _M3EFilledIconButtonDefaults extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? buttonSize; - final IconButtonWidth? buttonWidth; - final ButtonShapeVariant? buttonShape; + final ButtonSize? sizeVariant; + final IconButtonWidth? iconButtonWidth; + final ButtonShapeVariant? shapeVariant; late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -347,28 +347,28 @@ class _M3EFilledIconButtonDefaults extends ButtonStyle { @override WidgetStateProperty? get padding => - MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { - ButtonSize.xSmall => switch (buttonWidth ?? IconButtonWidth.standard) { + MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { + ButtonSize.xSmall => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), }, - ButtonSize.small => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.small => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), }, - ButtonSize.medium => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.medium => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(16.0, 16.0, 16.0, 16.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), }, - ButtonSize.large => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.large => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(32.0, 32.0, 32.0, 32.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), }, - ButtonSize.xLarge => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.xLarge => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(48.0, 48.0, 48.0, 48.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), @@ -377,28 +377,28 @@ class _M3EFilledIconButtonDefaults extends ButtonStyle { @override WidgetStateProperty? get minimumSize => - MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { - ButtonSize.xSmall => switch (buttonWidth ?? IconButtonWidth.standard) { + MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { + ButtonSize.xSmall => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(28.0, 32.0), IconButtonWidth.standard => const Size(32.0, 32.0), IconButtonWidth.wide => const Size(40.0, 32.0), }, - ButtonSize.small => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.small => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(32.0, 40.0), IconButtonWidth.standard => const Size(40.0, 40.0), IconButtonWidth.wide => const Size(52.0, 40.0), }, - ButtonSize.medium => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.medium => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(48.0, 56.0), IconButtonWidth.standard => const Size(56.0, 56.0), IconButtonWidth.wide => const Size(72.0, 56.0), }, - ButtonSize.large => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.large => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(64.0, 96.0), IconButtonWidth.standard => const Size(96.0, 96.0), IconButtonWidth.wide => const Size(128.0, 96.0), }, - ButtonSize.xLarge => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.xLarge => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(104.0, 136.0), IconButtonWidth.standard => const Size(136.0, 136.0), IconButtonWidth.wide => const Size(184.0, 136.0), @@ -410,7 +410,7 @@ class _M3EFilledIconButtonDefaults extends ButtonStyle { @override WidgetStateProperty? get iconSize => - MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { + MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => 20.0, ButtonSize.small => 24.0, ButtonSize.medium => 24.0, @@ -422,7 +422,7 @@ class _M3EFilledIconButtonDefaults extends ButtonStyle { WidgetStateProperty? get shape => WidgetStateProperty.resolveWith((Set states) { if (states.contains(WidgetState.pressed)) { - return switch (buttonSize ?? ButtonSize.small) { + return switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), @@ -441,8 +441,8 @@ class _M3EFilledIconButtonDefaults extends ButtonStyle { }; } if (toggleable && states.contains(WidgetState.selected)) { - return switch (buttonShape ?? ButtonShapeVariant.round) { - ButtonShapeVariant.round => switch (buttonSize ?? ButtonSize.small) { + return switch (shapeVariant ?? ButtonShapeVariant.round) { + ButtonShapeVariant.round => switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -459,7 +459,7 @@ class _M3EFilledIconButtonDefaults extends ButtonStyle { borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, - ButtonShapeVariant.square => switch (buttonSize ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), @@ -468,15 +468,15 @@ class _M3EFilledIconButtonDefaults extends ButtonStyle { }, }; } - return switch (buttonShape ?? ButtonShapeVariant.round) { - ButtonShapeVariant.round => switch (buttonSize ?? ButtonSize.small) { + return switch (shapeVariant ?? ButtonShapeVariant.round) { + ButtonShapeVariant.round => switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), ButtonSize.large => const StadiumBorder(), ButtonSize.xLarge => const StadiumBorder(), }, - ButtonShapeVariant.square => switch (buttonSize ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -512,13 +512,13 @@ class _M3EFilledIconButtonDefaults extends ButtonStyle { InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; } -class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { - _M3EFilledTonalIconButtonDefaults( +class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { + _FilledTonalIconButtonDefaultsM3E( this.context, this.toggleable, - this.buttonSize, - this.buttonWidth, - this.buttonShape, + this.sizeVariant, + this.iconButtonWidth, + this.shapeVariant, ) : super( animationDuration: kThemeChangeDuration, enableFeedback: true, @@ -527,9 +527,9 @@ class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? buttonSize; - final IconButtonWidth? buttonWidth; - final ButtonShapeVariant? buttonShape; + final ButtonSize? sizeVariant; + final IconButtonWidth? iconButtonWidth; + final ButtonShapeVariant? shapeVariant; late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -612,28 +612,28 @@ class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { @override WidgetStateProperty? get padding => - MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { - ButtonSize.xSmall => switch (buttonWidth ?? IconButtonWidth.standard) { + MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { + ButtonSize.xSmall => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), }, - ButtonSize.small => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.small => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), }, - ButtonSize.medium => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.medium => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(16.0, 16.0, 16.0, 16.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), }, - ButtonSize.large => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.large => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(32.0, 32.0, 32.0, 32.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), }, - ButtonSize.xLarge => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.xLarge => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(48.0, 48.0, 48.0, 48.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), @@ -642,28 +642,28 @@ class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { @override WidgetStateProperty? get minimumSize => - MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { - ButtonSize.xSmall => switch (buttonWidth ?? IconButtonWidth.standard) { + MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { + ButtonSize.xSmall => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(28.0, 32.0), IconButtonWidth.standard => const Size(32.0, 32.0), IconButtonWidth.wide => const Size(40.0, 32.0), }, - ButtonSize.small => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.small => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(32.0, 40.0), IconButtonWidth.standard => const Size(40.0, 40.0), IconButtonWidth.wide => const Size(52.0, 40.0), }, - ButtonSize.medium => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.medium => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(48.0, 56.0), IconButtonWidth.standard => const Size(56.0, 56.0), IconButtonWidth.wide => const Size(72.0, 56.0), }, - ButtonSize.large => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.large => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(64.0, 96.0), IconButtonWidth.standard => const Size(96.0, 96.0), IconButtonWidth.wide => const Size(128.0, 96.0), }, - ButtonSize.xLarge => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.xLarge => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(104.0, 136.0), IconButtonWidth.standard => const Size(136.0, 136.0), IconButtonWidth.wide => const Size(184.0, 136.0), @@ -675,7 +675,7 @@ class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { @override WidgetStateProperty? get iconSize => - MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { + MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => 20.0, ButtonSize.small => 24.0, ButtonSize.medium => 24.0, @@ -687,7 +687,7 @@ class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { WidgetStateProperty? get shape => WidgetStateProperty.resolveWith((Set states) { if (states.contains(WidgetState.pressed)) { - return switch (buttonSize ?? ButtonSize.small) { + return switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), @@ -706,8 +706,8 @@ class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { }; } if (toggleable && states.contains(WidgetState.selected)) { - return switch (buttonShape ?? ButtonShapeVariant.round) { - ButtonShapeVariant.round => switch (buttonSize ?? ButtonSize.small) { + return switch (shapeVariant ?? ButtonShapeVariant.round) { + ButtonShapeVariant.round => switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -724,7 +724,7 @@ class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, - ButtonShapeVariant.square => switch (buttonSize ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), @@ -733,15 +733,15 @@ class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { }, }; } - return switch (buttonShape ?? ButtonShapeVariant.round) { - ButtonShapeVariant.round => switch (buttonSize ?? ButtonSize.small) { + return switch (shapeVariant ?? ButtonShapeVariant.round) { + ButtonShapeVariant.round => switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), ButtonSize.large => const StadiumBorder(), ButtonSize.xLarge => const StadiumBorder(), }, - ButtonShapeVariant.square => switch (buttonSize ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -777,13 +777,13 @@ class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; } -class _M3EOutlinedIconButtonDefaults extends ButtonStyle { - _M3EOutlinedIconButtonDefaults( +class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { + _OutlinedIconButtonDefaultsM3E( this.context, this.toggleable, - this.buttonSize, - this.buttonWidth, - this.buttonShape, + this.sizeVariant, + this.iconButtonWidth, + this.shapeVariant, ) : super( animationDuration: kThemeChangeDuration, enableFeedback: true, @@ -792,9 +792,9 @@ class _M3EOutlinedIconButtonDefaults extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? buttonSize; - final IconButtonWidth? buttonWidth; - final ButtonShapeVariant? buttonShape; + final ButtonSize? sizeVariant; + final IconButtonWidth? iconButtonWidth; + final ButtonShapeVariant? shapeVariant; late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -863,28 +863,28 @@ class _M3EOutlinedIconButtonDefaults extends ButtonStyle { @override WidgetStateProperty? get padding => - MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { - ButtonSize.xSmall => switch (buttonWidth ?? IconButtonWidth.standard) { + MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { + ButtonSize.xSmall => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), }, - ButtonSize.small => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.small => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), }, - ButtonSize.medium => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.medium => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(16.0, 16.0, 16.0, 16.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), }, - ButtonSize.large => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.large => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(32.0, 32.0, 32.0, 32.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), }, - ButtonSize.xLarge => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.xLarge => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(48.0, 48.0, 48.0, 48.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), @@ -893,28 +893,28 @@ class _M3EOutlinedIconButtonDefaults extends ButtonStyle { @override WidgetStateProperty? get minimumSize => - MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { - ButtonSize.xSmall => switch (buttonWidth ?? IconButtonWidth.standard) { + MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { + ButtonSize.xSmall => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(28.0, 32.0), IconButtonWidth.standard => const Size(32.0, 32.0), IconButtonWidth.wide => const Size(40.0, 32.0), }, - ButtonSize.small => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.small => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(32.0, 40.0), IconButtonWidth.standard => const Size(40.0, 40.0), IconButtonWidth.wide => const Size(52.0, 40.0), }, - ButtonSize.medium => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.medium => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(48.0, 56.0), IconButtonWidth.standard => const Size(56.0, 56.0), IconButtonWidth.wide => const Size(72.0, 56.0), }, - ButtonSize.large => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.large => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(64.0, 96.0), IconButtonWidth.standard => const Size(96.0, 96.0), IconButtonWidth.wide => const Size(128.0, 96.0), }, - ButtonSize.xLarge => switch (buttonWidth ?? IconButtonWidth.standard) { + ButtonSize.xLarge => switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(104.0, 136.0), IconButtonWidth.standard => const Size(136.0, 136.0), IconButtonWidth.wide => const Size(184.0, 136.0), @@ -926,7 +926,7 @@ class _M3EOutlinedIconButtonDefaults extends ButtonStyle { @override WidgetStateProperty? get iconSize => - MaterialStatePropertyAll(switch (buttonSize ?? ButtonSize.small) { + MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => 20.0, ButtonSize.small => 24.0, ButtonSize.medium => 24.0, @@ -938,7 +938,7 @@ class _M3EOutlinedIconButtonDefaults extends ButtonStyle { WidgetStateProperty? get shape => WidgetStateProperty.resolveWith((Set states) { if (states.contains(WidgetState.pressed)) { - return switch (buttonSize ?? ButtonSize.small) { + return switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), @@ -957,8 +957,8 @@ class _M3EOutlinedIconButtonDefaults extends ButtonStyle { }; } if (toggleable && states.contains(WidgetState.selected)) { - return switch (buttonShape ?? ButtonShapeVariant.round) { - ButtonShapeVariant.round => switch (buttonSize ?? ButtonSize.small) { + return switch (shapeVariant ?? ButtonShapeVariant.round) { + ButtonShapeVariant.round => switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -975,7 +975,7 @@ class _M3EOutlinedIconButtonDefaults extends ButtonStyle { borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, - ButtonShapeVariant.square => switch (buttonSize ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), @@ -984,15 +984,15 @@ class _M3EOutlinedIconButtonDefaults extends ButtonStyle { }, }; } - return switch (buttonShape ?? ButtonShapeVariant.round) { - ButtonShapeVariant.round => switch (buttonSize ?? ButtonSize.small) { + return switch (shapeVariant ?? ButtonShapeVariant.round) { + ButtonShapeVariant.round => switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), ButtonSize.large => const StadiumBorder(), ButtonSize.xLarge => const StadiumBorder(), }, - ButtonShapeVariant.square => switch (buttonSize ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -1021,7 +1021,7 @@ class _M3EOutlinedIconButtonDefaults extends ButtonStyle { if (states.contains(WidgetState.disabled)) { return BorderSide( color: _colors.outlineVariant, - width: switch (buttonSize ?? ButtonSize.small) { + width: switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => 1.0, ButtonSize.small => 1.0, ButtonSize.medium => 1.0, @@ -1032,7 +1032,7 @@ class _M3EOutlinedIconButtonDefaults extends ButtonStyle { } return BorderSide( color: _colors.outlineVariant, - width: switch (buttonSize ?? ButtonSize.small) { + width: switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => 1.0, ButtonSize.small => 1.0, ButtonSize.medium => 1.0, diff --git a/packages/material_ui/lib/src/icon_button.dart b/packages/material_ui/lib/src/icon_button.dart index e6d132959635..3e12b297e2da 100644 --- a/packages/material_ui/lib/src/icon_button.dart +++ b/packages/material_ui/lib/src/icon_button.dart @@ -1060,21 +1060,21 @@ class _IconButtonM3 extends ButtonStyleButton { _IconButtonVariant.standard => _IconButtonDefaultsM3(context, toggleable), }, StyleVariant.material3Expressive => switch (iconButtonVariant) { - _IconButtonVariant.filled => _M3EFilledIconButtonDefaults( + _IconButtonVariant.filled => _FilledIconButtonDefaultsM3E( context, toggleable, effectiveSize, effectiveWidth, effectiveShape, ), - _IconButtonVariant.filledTonal => _M3EFilledTonalIconButtonDefaults( + _IconButtonVariant.filledTonal => _FilledTonalIconButtonDefaultsM3E( context, toggleable, effectiveSize, effectiveWidth, effectiveShape, ), - _IconButtonVariant.outlined => _M3EOutlinedIconButtonDefaults( + _IconButtonVariant.outlined => _OutlinedIconButtonDefaultsM3E( context, toggleable, effectiveSize, diff --git a/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart b/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart index 7328909e5cc0..31d9263b973c 100644 --- a/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart +++ b/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart @@ -56,7 +56,7 @@ ${_generateOutlinedDefaults()} required String xLarge, }) { return ''' -switch (buttonSize ?? ButtonSize.small) { +switch (sizeVariant ?? ButtonSize.small) { ButtonSize.xSmall => $xSmall, ButtonSize.small => $small, ButtonSize.medium => $medium, @@ -119,7 +119,7 @@ switch (buttonSize ?? ButtonSize.small) { required double wideTrailing, }) { return ''' -switch (buttonWidth ?? IconButtonWidth.standard) { +switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB($narrowLeading, $defaultLeading, $narrowTrailing, $defaultTrailing), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB($defaultLeading, $defaultLeading, $defaultTrailing, $defaultTrailing), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB($wideLeading, $defaultLeading, $wideTrailing, $defaultTrailing), @@ -192,7 +192,7 @@ switch (buttonWidth ?? IconButtonWidth.standard) { required double wideTrailing, }) { return ''' -switch (buttonWidth ?? IconButtonWidth.standard) { +switch (iconButtonWidth ?? IconButtonWidth.standard) { IconButtonWidth.narrow => const Size(${iconSize + narrowLeading + narrowTrailing}, $height), IconButtonWidth.standard => const Size(${iconSize + defaultLeading + defaultTrailing}, $height), IconButtonWidth.wide => const Size(${iconSize + wideLeading + wideTrailing}, $height), @@ -241,7 +241,7 @@ switch (buttonWidth ?? IconButtonWidth.standard) { String get _containerShapeSwitch { return ''' -switch (buttonShape ?? ButtonShapeVariant.round) { +switch (shapeVariant ?? ButtonShapeVariant.round) { ButtonShapeVariant.round => $_containerRoundShapeSwitch, ButtonShapeVariant.square => $_containerSquareShapeSwitch, }'''; @@ -279,7 +279,7 @@ switch (buttonShape ?? ButtonShapeVariant.round) { String get _selectedShapeSwitch { return ''' -switch (buttonShape ?? ButtonShapeVariant.round) { +switch (shapeVariant ?? ButtonShapeVariant.round) { ButtonShapeVariant.round => $_selectedRoundShapeSwitch, ButtonShapeVariant.square => $_selectedSquareShapeSwitch, }'''; @@ -320,7 +320,7 @@ switch (buttonShape ?? ButtonShapeVariant.round) { String _generateStandardDefaults(String className) { return ''' class $className extends ButtonStyle { - $className(this.context, this.toggleable, this.buttonSize, this.buttonWidth, this.buttonShape) + $className(this.context, this.toggleable, this.sizeVariant, this.iconButtonWidth, this.shapeVariant) : super( animationDuration: kThemeChangeDuration, enableFeedback: true, @@ -329,9 +329,9 @@ class $className extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? buttonSize; - final IconButtonWidth? buttonWidth; - final ButtonShapeVariant? buttonShape; + final ButtonSize? sizeVariant; + final IconButtonWidth? iconButtonWidth; + final ButtonShapeVariant? shapeVariant; late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -410,13 +410,13 @@ $_sizeDependentProperties String _generateFilledDefaults() { return ''' -class _M3EFilledIconButtonDefaults extends ButtonStyle { - _M3EFilledIconButtonDefaults( +class _FilledIconButtonDefaultsM3E extends ButtonStyle { + _FilledIconButtonDefaultsM3E( this.context, this.toggleable, - this.buttonSize, - this.buttonWidth, - this.buttonShape, + this.sizeVariant, + this.iconButtonWidth, + this.shapeVariant, ) : super( animationDuration: kThemeChangeDuration, @@ -426,9 +426,9 @@ class _M3EFilledIconButtonDefaults extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? buttonSize; - final IconButtonWidth? buttonWidth; - final ButtonShapeVariant? buttonShape; + final ButtonSize? sizeVariant; + final IconButtonWidth? iconButtonWidth; + final ButtonShapeVariant? shapeVariant; late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -532,13 +532,13 @@ $_sizeDependentProperties String _generateFilledTonalDefaults() { return ''' -class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { - _M3EFilledTonalIconButtonDefaults( +class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { + _FilledTonalIconButtonDefaultsM3E( this.context, this.toggleable, - this.buttonSize, - this.buttonWidth, - this.buttonShape, + this.sizeVariant, + this.iconButtonWidth, + this.shapeVariant, ) : super( animationDuration: kThemeChangeDuration, @@ -548,9 +548,9 @@ class _M3EFilledTonalIconButtonDefaults extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? buttonSize; - final IconButtonWidth? buttonWidth; - final ButtonShapeVariant? buttonShape; + final ButtonSize? sizeVariant; + final IconButtonWidth? iconButtonWidth; + final ButtonShapeVariant? shapeVariant; late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -654,13 +654,13 @@ $_sizeDependentProperties String _generateOutlinedDefaults() { return ''' -class _M3EOutlinedIconButtonDefaults extends ButtonStyle { - _M3EOutlinedIconButtonDefaults( +class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { + _OutlinedIconButtonDefaultsM3E( this.context, this.toggleable, - this.buttonSize, - this.buttonWidth, - this.buttonShape, + this.sizeVariant, + this.iconButtonWidth, + this.shapeVariant, ) : super( animationDuration: kThemeChangeDuration, @@ -670,9 +670,9 @@ class _M3EOutlinedIconButtonDefaults extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? buttonSize; - final IconButtonWidth? buttonWidth; - final ButtonShapeVariant? buttonShape; + final ButtonSize? sizeVariant; + final IconButtonWidth? iconButtonWidth; + final ButtonShapeVariant? shapeVariant; late final ColorScheme _colors = Theme.of(context).colorScheme; @override From 1cca05ee0e29e82a74855d72c637f62d6f894b3a Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 16:04:57 -0700 Subject: [PATCH 06/31] Use padded tap target for M3E IconButton defaults --- .../generated/icon_button_defaults_m3e.g.dart | 8 +++---- packages/material_ui/lib/src/icon_button.dart | 3 ++- .../material_ui/test/icon_button_test.dart | 22 +++++++++++++++++++ .../templates/icon_button_template.dart | 8 +++---- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart b/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart index 3dc79d201d57..90e77658d853 100644 --- a/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart +++ b/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart @@ -241,7 +241,7 @@ class _IconButtonDefaultsM3E extends ButtonStyle { VisualDensity? get visualDensity => VisualDensity.standard; @override - MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + MaterialTapTargetSize? get tapTargetSize => MaterialTapTargetSize.padded; @override InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; @@ -506,7 +506,7 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { VisualDensity? get visualDensity => VisualDensity.standard; @override - MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + MaterialTapTargetSize? get tapTargetSize => MaterialTapTargetSize.padded; @override InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; @@ -771,7 +771,7 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { VisualDensity? get visualDensity => VisualDensity.standard; @override - MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + MaterialTapTargetSize? get tapTargetSize => MaterialTapTargetSize.padded; @override InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; @@ -1049,7 +1049,7 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { VisualDensity? get visualDensity => VisualDensity.standard; @override - MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + MaterialTapTargetSize? get tapTargetSize => MaterialTapTargetSize.padded; @override InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; diff --git a/packages/material_ui/lib/src/icon_button.dart b/packages/material_ui/lib/src/icon_button.dart index 3e12b297e2da..34dbeece2168 100644 --- a/packages/material_ui/lib/src/icon_button.dart +++ b/packages/material_ui/lib/src/icon_button.dart @@ -1041,7 +1041,8 @@ class _IconButtonM3 extends ButtonStyleButton { /// * `shape` - StadiumBorder() /// * `mouseCursor` - WidgetStateMouseCursor.adaptiveClickable /// * `visualDensity` - VisualDensity.standard - /// * `tapTargetSize` - theme.materialTapTargetSize + /// * `tapTargetSize` - theme.materialTapTargetSize for Material 3, + /// MaterialTapTargetSize.padded for Material 3 Expressive /// * `animationDuration` - kThemeChangeDuration /// * `enableFeedback` - true /// * `alignment` - Alignment.center diff --git a/packages/material_ui/test/icon_button_test.dart b/packages/material_ui/test/icon_button_test.dart index 541651eb3870..ea349b5545d5 100644 --- a/packages/material_ui/test/icon_button_test.dart +++ b/packages/material_ui/test/icon_button_test.dart @@ -3651,6 +3651,28 @@ void main() { expect(pressCount, 4); }); + testWidgets('xSmall size keeps 48dp tap target when theme tapTargetSize is shrinkWrap', ( + WidgetTester tester, + ) async { + await tester.pumpWidget( + buildM3EApp( + theme: ThemeData( + useMaterial3: true, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + iconButtonTheme: const IconButtonThemeData(variant: StyleVariant.material3Expressive), + ), + child: IconButton( + onPressed: () {}, + icon: const Icon(Icons.add), + style: const ButtonStyle(sizeVariant: ButtonSize.xSmall), + ), + ), + ); + + expect(m3eIconButtonMaterialSize(tester), const Size(32.0, 32.0)); + expect(tester.getSize(find.byType(IconButton)), const Size(48.0, 48.0)); + }); + testWidgets('styleFrom sets the size variant', (WidgetTester tester) async { await tester.pumpWidget( buildM3EApp( diff --git a/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart b/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart index 31d9263b973c..22bf9e9a9d6f 100644 --- a/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart +++ b/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart @@ -400,7 +400,7 @@ $_sizeDependentProperties VisualDensity? get visualDensity => VisualDensity.standard; @override - MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + MaterialTapTargetSize? get tapTargetSize => MaterialTapTargetSize.padded; @override InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; @@ -522,7 +522,7 @@ $_sizeDependentProperties VisualDensity? get visualDensity => VisualDensity.standard; @override - MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + MaterialTapTargetSize? get tapTargetSize => MaterialTapTargetSize.padded; @override InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; @@ -644,7 +644,7 @@ $_sizeDependentProperties VisualDensity? get visualDensity => VisualDensity.standard; @override - MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + MaterialTapTargetSize? get tapTargetSize => MaterialTapTargetSize.padded; @override InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; @@ -761,7 +761,7 @@ $_sizeDependentProperties VisualDensity? get visualDensity => VisualDensity.standard; @override - MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + MaterialTapTargetSize? get tapTargetSize => MaterialTapTargetSize.padded; @override InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; From 1753f51fa8eda56ffe931d04ebc0276097cd4938 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 16:27:25 -0700 Subject: [PATCH 07/31] Document M3E IconButton tap target defaults --- packages/material_ui/lib/src/icon_button.dart | 5 +++++ packages/material_ui/lib/src/icon_button_theme.dart | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/material_ui/lib/src/icon_button.dart b/packages/material_ui/lib/src/icon_button.dart index 34dbeece2168..f47bb920f2a4 100644 --- a/packages/material_ui/lib/src/icon_button.dart +++ b/packages/material_ui/lib/src/icon_button.dart @@ -633,6 +633,11 @@ class IconButton extends StatelessWidget { /// [ButtonStyle.sizeVariant], [ButtonStyle.iconButtonWidth], and /// [ButtonStyle.shapeVariant]. /// + /// When [IconButtonThemeData.variant] is [StyleVariant.material3Expressive], + /// [IconButton]'s default [ButtonStyle.tapTargetSize] is + /// [MaterialTapTargetSize.padded]. The [tapTargetSize] parameter can still be + /// used to override that default for an individual icon button style. + /// /// All parameters default to null, by default this method returns /// a [ButtonStyle] that doesn't override anything. /// diff --git a/packages/material_ui/lib/src/icon_button_theme.dart b/packages/material_ui/lib/src/icon_button_theme.dart index cd86c3bf3879..b231d0c8c705 100644 --- a/packages/material_ui/lib/src/icon_button_theme.dart +++ b/packages/material_ui/lib/src/icon_button_theme.dart @@ -54,7 +54,9 @@ class IconButtonThemeData with Diagnosticable { /// The style variant of Material Design used by [IconButton]. /// /// Set this to [StyleVariant.material3Expressive] to opt icon buttons into - /// the Material 3 Expressive defaults. + /// the Material 3 Expressive defaults. These defaults include the Material 3 + /// Expressive size, width, and shape tokens, and use + /// [MaterialTapTargetSize.padded] for the default tap target size. /// /// If null, [IconButton] uses [StyleVariant.material3]. final StyleVariant? variant; From 73e648fe53c362f1c292ed84113e04400932c159 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 16:34:26 -0700 Subject: [PATCH 08/31] Expand ButtonStyle variant documentation --- .../material_ui/lib/src/button_style.dart | 44 +++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/packages/material_ui/lib/src/button_style.dart b/packages/material_ui/lib/src/button_style.dart index 7f5d3da12f33..b286b3e267f6 100644 --- a/packages/material_ui/lib/src/button_style.dart +++ b/packages/material_ui/lib/src/button_style.dart @@ -467,13 +467,51 @@ class ButtonStyle with Diagnosticable { /// configuring clipping. final ButtonLayerBuilder? foregroundBuilder; - /// The size variant for this button. + /// The Material 3 Expressive size variant for this button. + /// + /// A size variant selects a component-defined token set rather than a single + /// dimension. For example, an [IconButton] uses this value to choose its + /// default container size, padding, and icon size when it is using + /// [StyleVariant.material3Expressive]. + /// + /// If null, the button uses its component default. For Material 3 Expressive + /// [IconButton] defaults, the fallback is [ButtonSize.small]. + /// + /// This property is only interpreted by button components that define + /// Material 3 Expressive size variants. Use [minimumSize], [fixedSize], + /// [maximumSize], [padding], or [iconSize] to directly override those + /// individual style properties. final ButtonSize? sizeVariant; - /// The width variant for this icon button. + /// The Material 3 Expressive width variant for an [IconButton]. + /// + /// A width variant selects the leading and trailing space tokens used to + /// compute an icon button's default horizontal padding and minimum width when + /// it is using [StyleVariant.material3Expressive]. It does not change the + /// button's height or icon size. + /// + /// If null, Material 3 Expressive [IconButton] defaults use + /// [IconButtonWidth.standard]. + /// + /// This property is only interpreted by icon buttons. Use [padding], + /// [minimumSize], [fixedSize], or [maximumSize] to directly override the + /// resulting layout. final IconButtonWidth? iconButtonWidth; - /// The shape variant for this button. + /// The Material 3 Expressive shape variant for this button. + /// + /// A shape variant selects between component-defined token families, such as + /// round and square shapes. For [IconButton], this affects the default + /// container and selected-state shapes when it is using + /// [StyleVariant.material3Expressive]; state-specific tokens, such as the + /// pressed shape, are still resolved by the component defaults. + /// + /// If null, Material 3 Expressive [IconButton] defaults use + /// [ButtonShapeVariant.round]. + /// + /// Use [shape] to provide a specific [OutlinedBorder] or stateful shape + /// override instead of selecting one of the Material 3 Expressive token + /// variants. final ButtonShapeVariant? shapeVariant; /// Returns a copy of this ButtonStyle with the given fields replaced with From dafdf77a7322e4061b914dc81e597da06e8c7d8c Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 19:31:54 -0700 Subject: [PATCH 09/31] Clarify ButtonStyle variant enum docs --- .../material_ui/lib/src/button_style.dart | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/packages/material_ui/lib/src/button_style.dart b/packages/material_ui/lib/src/button_style.dart index b286b3e267f6..3a412d02209c 100644 --- a/packages/material_ui/lib/src/button_style.dart +++ b/packages/material_ui/lib/src/button_style.dart @@ -33,42 +33,54 @@ import 'theme_data.dart'; /// Defines size variants for Material 3 Expressive button components. /// -/// Components interpret each size variant according to their own token set. +/// Components interpret each size variant according to their own design. For +/// example, a Material 3 Expressive [IconButton] changes its container size, +/// icon size, and padding when its size variant changes. enum ButtonSize { - /// Extra small button size. + /// The smallest button size. xSmall, - /// Small button size. This is the default for icon buttons. + /// A small button size. + /// + /// This is the default for Material 3 Expressive [IconButton]. small, - /// Medium button size. + /// A medium button size. medium, - /// Large button size. + /// A large button size. large, - /// Extra large button size. + /// The largest button size. xLarge, } /// Defines the width variants for Material 3 Expressive [IconButton]. enum IconButtonWidth { - /// Uses the narrow leading and trailing space tokens. + /// A narrower icon button. narrow, - /// Uses the default leading and trailing space tokens. + /// The standard icon button width. + /// + /// This is the default for Material 3 Expressive [IconButton]. standard, - /// Uses the wide leading and trailing space tokens. + /// A wider icon button. wide, } /// Defines shape variants for Material 3 Expressive button components. enum ButtonShapeVariant { - /// Uses the round shape tokens. + /// A rounded button shape. + /// + /// For example, a Material 3 Expressive [IconButton] with this variant uses + /// rounder default container shapes. round, - /// Uses the square shape tokens. + /// A squared button shape. + /// + /// For example, a Material 3 Expressive [IconButton] with this variant uses + /// more squared default container shapes. square, } From 0d748d9f720c7254d0523679a46a63e970f5812f Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 19:43:47 -0700 Subject: [PATCH 10/31] Move IconButton variant defaults to IconButton docs --- packages/material_ui/lib/src/button_style.dart | 13 ------------- packages/material_ui/lib/src/icon_button.dart | 7 +++++++ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/packages/material_ui/lib/src/button_style.dart b/packages/material_ui/lib/src/button_style.dart index 3a412d02209c..0be5923ff33b 100644 --- a/packages/material_ui/lib/src/button_style.dart +++ b/packages/material_ui/lib/src/button_style.dart @@ -41,8 +41,6 @@ enum ButtonSize { xSmall, /// A small button size. - /// - /// This is the default for Material 3 Expressive [IconButton]. small, /// A medium button size. @@ -61,8 +59,6 @@ enum IconButtonWidth { narrow, /// The standard icon button width. - /// - /// This is the default for Material 3 Expressive [IconButton]. standard, /// A wider icon button. @@ -486,9 +482,6 @@ class ButtonStyle with Diagnosticable { /// default container size, padding, and icon size when it is using /// [StyleVariant.material3Expressive]. /// - /// If null, the button uses its component default. For Material 3 Expressive - /// [IconButton] defaults, the fallback is [ButtonSize.small]. - /// /// This property is only interpreted by button components that define /// Material 3 Expressive size variants. Use [minimumSize], [fixedSize], /// [maximumSize], [padding], or [iconSize] to directly override those @@ -502,9 +495,6 @@ class ButtonStyle with Diagnosticable { /// it is using [StyleVariant.material3Expressive]. It does not change the /// button's height or icon size. /// - /// If null, Material 3 Expressive [IconButton] defaults use - /// [IconButtonWidth.standard]. - /// /// This property is only interpreted by icon buttons. Use [padding], /// [minimumSize], [fixedSize], or [maximumSize] to directly override the /// resulting layout. @@ -518,9 +508,6 @@ class ButtonStyle with Diagnosticable { /// [StyleVariant.material3Expressive]; state-specific tokens, such as the /// pressed shape, are still resolved by the component defaults. /// - /// If null, Material 3 Expressive [IconButton] defaults use - /// [ButtonShapeVariant.round]. - /// /// Use [shape] to provide a specific [OutlinedBorder] or stateful shape /// override instead of selecting one of the Material 3 Expressive token /// variants. diff --git a/packages/material_ui/lib/src/icon_button.dart b/packages/material_ui/lib/src/icon_button.dart index f47bb920f2a4..f182eee391fa 100644 --- a/packages/material_ui/lib/src/icon_button.dart +++ b/packages/material_ui/lib/src/icon_button.dart @@ -633,6 +633,10 @@ class IconButton extends StatelessWidget { /// [ButtonStyle.sizeVariant], [ButtonStyle.iconButtonWidth], and /// [ButtonStyle.shapeVariant]. /// + /// When these properties are null, Material 3 Expressive [IconButton] + /// defaults use [ButtonSize.small], [IconButtonWidth.standard], and + /// [ButtonShapeVariant.round]. + /// /// When [IconButtonThemeData.variant] is [StyleVariant.material3Expressive], /// [IconButton]'s default [ButtonStyle.tapTargetSize] is /// [MaterialTapTargetSize.padded]. The [tapTargetSize] parameter can still be @@ -1044,6 +1048,9 @@ class _IconButtonM3 extends ButtonStyleButton { /// * `iconSize` - 24 /// * `side` - null /// * `shape` - StadiumBorder() + /// * `sizeVariant` - ButtonSize.small for Material 3 Expressive + /// * `iconButtonWidth` - IconButtonWidth.standard for Material 3 Expressive + /// * `shapeVariant` - ButtonShapeVariant.round for Material 3 Expressive /// * `mouseCursor` - WidgetStateMouseCursor.adaptiveClickable /// * `visualDensity` - VisualDensity.standard /// * `tapTargetSize` - theme.materialTapTargetSize for Material 3, From 2a96f0ccd328ff0066381208ecc871a81cf087c0 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 19:49:51 -0700 Subject: [PATCH 11/31] Refine ButtonSize API documentation --- packages/material_ui/lib/src/button_style.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/material_ui/lib/src/button_style.dart b/packages/material_ui/lib/src/button_style.dart index 0be5923ff33b..72a14b564028 100644 --- a/packages/material_ui/lib/src/button_style.dart +++ b/packages/material_ui/lib/src/button_style.dart @@ -33,9 +33,9 @@ import 'theme_data.dart'; /// Defines size variants for Material 3 Expressive button components. /// -/// Components interpret each size variant according to their own design. For -/// example, a Material 3 Expressive [IconButton] changes its container size, -/// icon size, and padding when its size variant changes. +/// Each size variant represents a named visual scale. For example, a Material +/// 3 Expressive [IconButton] uses this value to choose its container size, icon +/// size, and padding. enum ButtonSize { /// The smallest button size. xSmall, From 84b2cd864d4ed5b547f1f430f847d66ac352ee83 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 19:54:28 -0700 Subject: [PATCH 12/31] Rephrase ButtonStyle size variant docs --- packages/material_ui/lib/src/button_style.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/material_ui/lib/src/button_style.dart b/packages/material_ui/lib/src/button_style.dart index 72a14b564028..7e22048378a7 100644 --- a/packages/material_ui/lib/src/button_style.dart +++ b/packages/material_ui/lib/src/button_style.dart @@ -482,8 +482,8 @@ class ButtonStyle with Diagnosticable { /// default container size, padding, and icon size when it is using /// [StyleVariant.material3Expressive]. /// - /// This property is only interpreted by button components that define - /// Material 3 Expressive size variants. Use [minimumSize], [fixedSize], + /// Buttons without Material 3 Expressive size variants ignore this property. + /// Use [minimumSize], [fixedSize], /// [maximumSize], [padding], or [iconSize] to directly override those /// individual style properties. final ButtonSize? sizeVariant; From 9259994ba509f6405157175ffcee5e9e4da1b01a Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 19:56:14 -0700 Subject: [PATCH 13/31] Simplify ButtonStyle size variant docs --- packages/material_ui/lib/src/button_style.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/material_ui/lib/src/button_style.dart b/packages/material_ui/lib/src/button_style.dart index 7e22048378a7..66c5489caa84 100644 --- a/packages/material_ui/lib/src/button_style.dart +++ b/packages/material_ui/lib/src/button_style.dart @@ -482,10 +482,8 @@ class ButtonStyle with Diagnosticable { /// default container size, padding, and icon size when it is using /// [StyleVariant.material3Expressive]. /// - /// Buttons without Material 3 Expressive size variants ignore this property. - /// Use [minimumSize], [fixedSize], - /// [maximumSize], [padding], or [iconSize] to directly override those - /// individual style properties. + /// Use [minimumSize], [fixedSize], [maximumSize], [padding], or [iconSize] to + /// directly override those individual style properties. final ButtonSize? sizeVariant; /// The Material 3 Expressive width variant for an [IconButton]. From bff0159a05db5526fe6eb8b6864422e6e271e222 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 19:57:36 -0700 Subject: [PATCH 14/31] Clarify IconButton width variant docs --- packages/material_ui/lib/src/button_style.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/material_ui/lib/src/button_style.dart b/packages/material_ui/lib/src/button_style.dart index 66c5489caa84..59cfcf213752 100644 --- a/packages/material_ui/lib/src/button_style.dart +++ b/packages/material_ui/lib/src/button_style.dart @@ -493,7 +493,7 @@ class ButtonStyle with Diagnosticable { /// it is using [StyleVariant.material3Expressive]. It does not change the /// button's height or icon size. /// - /// This property is only interpreted by icon buttons. Use [padding], + /// This property is only used by icon buttons. Use [padding], /// [minimumSize], [fixedSize], or [maximumSize] to directly override the /// resulting layout. final IconButtonWidth? iconButtonWidth; From e4228ec79c3e2858ed4914cb472d242c953f79bb Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 20:00:27 -0700 Subject: [PATCH 15/31] Clarify ButtonStyle shape variant docs --- packages/material_ui/lib/src/button_style.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/material_ui/lib/src/button_style.dart b/packages/material_ui/lib/src/button_style.dart index 59cfcf213752..2072e38b1b04 100644 --- a/packages/material_ui/lib/src/button_style.dart +++ b/packages/material_ui/lib/src/button_style.dart @@ -507,7 +507,7 @@ class ButtonStyle with Diagnosticable { /// pressed shape, are still resolved by the component defaults. /// /// Use [shape] to provide a specific [OutlinedBorder] or stateful shape - /// override instead of selecting one of the Material 3 Expressive token + /// override instead of selecting one of the Material 3 Expressive shape /// variants. final ButtonShapeVariant? shapeVariant; From 97a9f18b48a3ede8a0ed102497769e054ac5f751 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 20:06:02 -0700 Subject: [PATCH 16/31] Polish IconButton variant style docs --- packages/material_ui/lib/src/icon_button.dart | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/material_ui/lib/src/icon_button.dart b/packages/material_ui/lib/src/icon_button.dart index f182eee391fa..ca1ea4a85c48 100644 --- a/packages/material_ui/lib/src/icon_button.dart +++ b/packages/material_ui/lib/src/icon_button.dart @@ -628,10 +628,11 @@ class IconButton extends StatelessWidget { /// create a [WidgetStateProperty] with a single value for all /// states. /// - /// The [sizeVariant], [iconButtonWidth], and [shapeVariant] parameters configure - /// the Material 3 Expressive token size, width, and shape through - /// [ButtonStyle.sizeVariant], [ButtonStyle.iconButtonWidth], and - /// [ButtonStyle.shapeVariant]. + /// The [sizeVariant], [iconButtonWidth], and [shapeVariant] parameters + /// configure the Material 3 Expressive appearance of an [IconButton]. They + /// provide options for extra-small through extra-large sizes, narrow through + /// wide widths, and round or square shapes through [ButtonStyle.sizeVariant], + /// [ButtonStyle.iconButtonWidth], and [ButtonStyle.shapeVariant]. /// /// When these properties are null, Material 3 Expressive [IconButton] /// defaults use [ButtonSize.small], [IconButtonWidth.standard], and From 618b953642304309b0ad309ccddfd927f182773c Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 20:08:35 -0700 Subject: [PATCH 17/31] Clarify IconButton M3E option docs --- packages/material_ui/lib/src/icon_button.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/material_ui/lib/src/icon_button.dart b/packages/material_ui/lib/src/icon_button.dart index ca1ea4a85c48..02b348e77d84 100644 --- a/packages/material_ui/lib/src/icon_button.dart +++ b/packages/material_ui/lib/src/icon_button.dart @@ -628,11 +628,11 @@ class IconButton extends StatelessWidget { /// create a [WidgetStateProperty] with a single value for all /// states. /// - /// The [sizeVariant], [iconButtonWidth], and [shapeVariant] parameters - /// configure the Material 3 Expressive appearance of an [IconButton]. They - /// provide options for extra-small through extra-large sizes, narrow through - /// wide widths, and round or square shapes through [ButtonStyle.sizeVariant], - /// [ButtonStyle.iconButtonWidth], and [ButtonStyle.shapeVariant]. + /// The [sizeVariant], [iconButtonWidth], and [shapeVariant] parameters are + /// Material 3 Expressive options. They provide extra-small through + /// extra-large sizes, narrow through wide widths, and round or square shapes + /// through [ButtonStyle.sizeVariant], [ButtonStyle.iconButtonWidth], and + /// [ButtonStyle.shapeVariant]. /// /// When these properties are null, Material 3 Expressive [IconButton] /// defaults use [ButtonSize.small], [IconButtonWidth.standard], and From 4971afc65027aea8373c9640da7fc10d1ae09e45 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 20:11:29 -0700 Subject: [PATCH 18/31] Simplify IconButton M3E option docs --- packages/material_ui/lib/src/icon_button.dart | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/material_ui/lib/src/icon_button.dart b/packages/material_ui/lib/src/icon_button.dart index 02b348e77d84..5f1e091a4726 100644 --- a/packages/material_ui/lib/src/icon_button.dart +++ b/packages/material_ui/lib/src/icon_button.dart @@ -634,14 +634,10 @@ class IconButton extends StatelessWidget { /// through [ButtonStyle.sizeVariant], [ButtonStyle.iconButtonWidth], and /// [ButtonStyle.shapeVariant]. /// - /// When these properties are null, Material 3 Expressive [IconButton] - /// defaults use [ButtonSize.small], [IconButtonWidth.standard], and - /// [ButtonShapeVariant.round]. - /// /// When [IconButtonThemeData.variant] is [StyleVariant.material3Expressive], - /// [IconButton]'s default [ButtonStyle.tapTargetSize] is - /// [MaterialTapTargetSize.padded]. The [tapTargetSize] parameter can still be - /// used to override that default for an individual icon button style. + /// and these properties are null, Material 3 Expressive [IconButton] defaults + /// use [ButtonSize.small], [IconButtonWidth.standard], and + /// [ButtonShapeVariant.round]. /// /// All parameters default to null, by default this method returns /// a [ButtonStyle] that doesn't override anything. From 7b22aae8ace481f09187daef39abf6857d627f54 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 20:33:01 -0700 Subject: [PATCH 19/31] Separate IconButton M3E default docs --- packages/material_ui/lib/src/icon_button.dart | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/material_ui/lib/src/icon_button.dart b/packages/material_ui/lib/src/icon_button.dart index 5f1e091a4726..0a6c03bd0b23 100644 --- a/packages/material_ui/lib/src/icon_button.dart +++ b/packages/material_ui/lib/src/icon_button.dart @@ -1019,8 +1019,9 @@ class _IconButtonM3 extends ButtonStyleButton { /// ## Material 3 defaults /// - /// If [ThemeData.useMaterial3] is set to true the following defaults will - /// be used: + /// If [ThemeData.useMaterial3] is true and [IconButtonThemeData.variant] is + /// not [StyleVariant.material3Expressive], the following defaults will be + /// used: /// /// * `textStyle` - null /// * `backgroundColor` - transparent @@ -1045,17 +1046,24 @@ class _IconButtonM3 extends ButtonStyleButton { /// * `iconSize` - 24 /// * `side` - null /// * `shape` - StadiumBorder() - /// * `sizeVariant` - ButtonSize.small for Material 3 Expressive - /// * `iconButtonWidth` - IconButtonWidth.standard for Material 3 Expressive - /// * `shapeVariant` - ButtonShapeVariant.round for Material 3 Expressive /// * `mouseCursor` - WidgetStateMouseCursor.adaptiveClickable /// * `visualDensity` - VisualDensity.standard - /// * `tapTargetSize` - theme.materialTapTargetSize for Material 3, - /// MaterialTapTargetSize.padded for Material 3 Expressive + /// * `tapTargetSize` - theme.materialTapTargetSize /// * `animationDuration` - kThemeChangeDuration /// * `enableFeedback` - true /// * `alignment` - Alignment.center /// * `splashFactory` - Theme.splashFactory + /// + /// ## Material 3 Expressive defaults + /// + /// If [ThemeData.useMaterial3] is true and [IconButtonThemeData.variant] is + /// [StyleVariant.material3Expressive], Material 3 Expressive defaults are + /// used. The Material 3 Expressive-specific defaults include: + /// + /// * `sizeVariant` - ButtonSize.small + /// * `iconButtonWidth` - IconButtonWidth.standard + /// * `shapeVariant` - ButtonShapeVariant.round + /// * `tapTargetSize` - MaterialTapTargetSize.padded @override ButtonStyle defaultStyleOf(BuildContext context) { final ButtonSize? effectiveSize = _effectiveSize(context); From 85289b9f5621a1ec5987be075a6d501a9a169060 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 20:36:24 -0700 Subject: [PATCH 20/31] Inline IconButton variant style lookup --- packages/material_ui/lib/src/icon_button.dart | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/packages/material_ui/lib/src/icon_button.dart b/packages/material_ui/lib/src/icon_button.dart index 0a6c03bd0b23..7bbf87e0e051 100644 --- a/packages/material_ui/lib/src/icon_button.dart +++ b/packages/material_ui/lib/src/icon_button.dart @@ -1005,18 +1005,6 @@ class _IconButtonM3 extends ButtonStyleButton { final StyleVariant styleVariant; final bool toggleable; - ButtonSize? _effectiveSize(BuildContext context) { - return style?.sizeVariant ?? IconButtonTheme.of(context).style?.sizeVariant; - } - - IconButtonWidth? _effectiveWidth(BuildContext context) { - return style?.iconButtonWidth ?? IconButtonTheme.of(context).style?.iconButtonWidth; - } - - ButtonShapeVariant? _effectiveShape(BuildContext context) { - return style?.shapeVariant ?? IconButtonTheme.of(context).style?.shapeVariant; - } - /// ## Material 3 defaults /// /// If [ThemeData.useMaterial3] is true and [IconButtonThemeData.variant] is @@ -1066,9 +1054,12 @@ class _IconButtonM3 extends ButtonStyleButton { /// * `tapTargetSize` - MaterialTapTargetSize.padded @override ButtonStyle defaultStyleOf(BuildContext context) { - final ButtonSize? effectiveSize = _effectiveSize(context); - final IconButtonWidth? effectiveWidth = _effectiveWidth(context); - final ButtonShapeVariant? effectiveShape = _effectiveShape(context); + final ButtonStyle? iconButtonThemeStyle = IconButtonTheme.of(context).style; + final ButtonSize? effectiveSize = style?.sizeVariant ?? iconButtonThemeStyle?.sizeVariant; + final IconButtonWidth? effectiveWidth = + style?.iconButtonWidth ?? iconButtonThemeStyle?.iconButtonWidth; + final ButtonShapeVariant? effectiveShape = + style?.shapeVariant ?? iconButtonThemeStyle?.shapeVariant; return switch (styleVariant) { StyleVariant.material3 => switch (iconButtonVariant) { From fd25bf98dafb364545300117e4417e328b6ab376 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 20:56:35 -0700 Subject: [PATCH 21/31] Clean up IconButton M3E default variants --- .../generated/icon_button_defaults_m3e.g.dart | 252 ++++++++++-------- packages/material_ui/lib/src/icon_button.dart | 36 ++- .../templates/icon_button_template.dart | 63 +++-- 3 files changed, 216 insertions(+), 135 deletions(-) diff --git a/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart b/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart index 90e77658d853..aec896434e21 100644 --- a/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart +++ b/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart @@ -11,9 +11,9 @@ class _IconButtonDefaultsM3E extends ButtonStyle { _IconButtonDefaultsM3E( this.context, this.toggleable, - this.sizeVariant, - this.iconButtonWidth, - this.shapeVariant, + this._sizeVariant, + this._iconButtonWidth, + this._shapeVariant, ) : super( animationDuration: kThemeChangeDuration, enableFeedback: true, @@ -22,9 +22,19 @@ class _IconButtonDefaultsM3E extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? sizeVariant; - final IconButtonWidth? iconButtonWidth; - final ButtonShapeVariant? shapeVariant; + final ButtonSize? _sizeVariant; + final IconButtonWidth? _iconButtonWidth; + final ButtonShapeVariant? _shapeVariant; + + @override + ButtonSize get sizeVariant => _sizeVariant ?? ButtonSize.small; + + @override + IconButtonWidth get iconButtonWidth => _iconButtonWidth ?? IconButtonWidth.standard; + + @override + ButtonShapeVariant get shapeVariant => _shapeVariant ?? ButtonShapeVariant.round; + late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -82,28 +92,28 @@ class _IconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get padding => - MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { - ButtonSize.xSmall => switch (iconButtonWidth ?? IconButtonWidth.standard) { + MaterialStatePropertyAll(switch (sizeVariant) { + ButtonSize.xSmall => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), }, - ButtonSize.small => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.small => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), }, - ButtonSize.medium => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.medium => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(16.0, 16.0, 16.0, 16.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), }, - ButtonSize.large => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.large => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(32.0, 32.0, 32.0, 32.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), }, - ButtonSize.xLarge => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.xLarge => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(48.0, 48.0, 48.0, 48.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), @@ -112,28 +122,28 @@ class _IconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get minimumSize => - MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { - ButtonSize.xSmall => switch (iconButtonWidth ?? IconButtonWidth.standard) { + MaterialStatePropertyAll(switch (sizeVariant) { + ButtonSize.xSmall => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(28.0, 32.0), IconButtonWidth.standard => const Size(32.0, 32.0), IconButtonWidth.wide => const Size(40.0, 32.0), }, - ButtonSize.small => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.small => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(32.0, 40.0), IconButtonWidth.standard => const Size(40.0, 40.0), IconButtonWidth.wide => const Size(52.0, 40.0), }, - ButtonSize.medium => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.medium => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(48.0, 56.0), IconButtonWidth.standard => const Size(56.0, 56.0), IconButtonWidth.wide => const Size(72.0, 56.0), }, - ButtonSize.large => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.large => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(64.0, 96.0), IconButtonWidth.standard => const Size(96.0, 96.0), IconButtonWidth.wide => const Size(128.0, 96.0), }, - ButtonSize.xLarge => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.xLarge => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(104.0, 136.0), IconButtonWidth.standard => const Size(136.0, 136.0), IconButtonWidth.wide => const Size(184.0, 136.0), @@ -145,7 +155,7 @@ class _IconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get iconSize => - MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { + MaterialStatePropertyAll(switch (sizeVariant) { ButtonSize.xSmall => 20.0, ButtonSize.small => 24.0, ButtonSize.medium => 24.0, @@ -157,7 +167,7 @@ class _IconButtonDefaultsM3E extends ButtonStyle { WidgetStateProperty? get shape => WidgetStateProperty.resolveWith((Set states) { if (states.contains(WidgetState.pressed)) { - return switch (sizeVariant ?? ButtonSize.small) { + return switch (sizeVariant) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), @@ -176,8 +186,8 @@ class _IconButtonDefaultsM3E extends ButtonStyle { }; } if (toggleable && states.contains(WidgetState.selected)) { - return switch (shapeVariant ?? ButtonShapeVariant.round) { - ButtonShapeVariant.round => switch (sizeVariant ?? ButtonSize.small) { + return switch (shapeVariant) { + ButtonShapeVariant.round => switch (sizeVariant) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -194,7 +204,7 @@ class _IconButtonDefaultsM3E extends ButtonStyle { borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, - ButtonShapeVariant.square => switch (sizeVariant ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (sizeVariant) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), @@ -203,15 +213,15 @@ class _IconButtonDefaultsM3E extends ButtonStyle { }, }; } - return switch (shapeVariant ?? ButtonShapeVariant.round) { - ButtonShapeVariant.round => switch (sizeVariant ?? ButtonSize.small) { + return switch (shapeVariant) { + ButtonShapeVariant.round => switch (sizeVariant) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), ButtonSize.large => const StadiumBorder(), ButtonSize.xLarge => const StadiumBorder(), }, - ButtonShapeVariant.square => switch (sizeVariant ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (sizeVariant) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -251,9 +261,9 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { _FilledIconButtonDefaultsM3E( this.context, this.toggleable, - this.sizeVariant, - this.iconButtonWidth, - this.shapeVariant, + this._sizeVariant, + this._iconButtonWidth, + this._shapeVariant, ) : super( animationDuration: kThemeChangeDuration, enableFeedback: true, @@ -262,9 +272,19 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? sizeVariant; - final IconButtonWidth? iconButtonWidth; - final ButtonShapeVariant? shapeVariant; + final ButtonSize? _sizeVariant; + final IconButtonWidth? _iconButtonWidth; + final ButtonShapeVariant? _shapeVariant; + + @override + ButtonSize get sizeVariant => _sizeVariant ?? ButtonSize.small; + + @override + IconButtonWidth get iconButtonWidth => _iconButtonWidth ?? IconButtonWidth.standard; + + @override + ButtonShapeVariant get shapeVariant => _shapeVariant ?? ButtonShapeVariant.round; + late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -347,28 +367,28 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get padding => - MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { - ButtonSize.xSmall => switch (iconButtonWidth ?? IconButtonWidth.standard) { + MaterialStatePropertyAll(switch (sizeVariant) { + ButtonSize.xSmall => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), }, - ButtonSize.small => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.small => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), }, - ButtonSize.medium => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.medium => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(16.0, 16.0, 16.0, 16.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), }, - ButtonSize.large => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.large => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(32.0, 32.0, 32.0, 32.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), }, - ButtonSize.xLarge => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.xLarge => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(48.0, 48.0, 48.0, 48.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), @@ -377,28 +397,28 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get minimumSize => - MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { - ButtonSize.xSmall => switch (iconButtonWidth ?? IconButtonWidth.standard) { + MaterialStatePropertyAll(switch (sizeVariant) { + ButtonSize.xSmall => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(28.0, 32.0), IconButtonWidth.standard => const Size(32.0, 32.0), IconButtonWidth.wide => const Size(40.0, 32.0), }, - ButtonSize.small => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.small => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(32.0, 40.0), IconButtonWidth.standard => const Size(40.0, 40.0), IconButtonWidth.wide => const Size(52.0, 40.0), }, - ButtonSize.medium => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.medium => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(48.0, 56.0), IconButtonWidth.standard => const Size(56.0, 56.0), IconButtonWidth.wide => const Size(72.0, 56.0), }, - ButtonSize.large => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.large => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(64.0, 96.0), IconButtonWidth.standard => const Size(96.0, 96.0), IconButtonWidth.wide => const Size(128.0, 96.0), }, - ButtonSize.xLarge => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.xLarge => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(104.0, 136.0), IconButtonWidth.standard => const Size(136.0, 136.0), IconButtonWidth.wide => const Size(184.0, 136.0), @@ -410,7 +430,7 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get iconSize => - MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { + MaterialStatePropertyAll(switch (sizeVariant) { ButtonSize.xSmall => 20.0, ButtonSize.small => 24.0, ButtonSize.medium => 24.0, @@ -422,7 +442,7 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { WidgetStateProperty? get shape => WidgetStateProperty.resolveWith((Set states) { if (states.contains(WidgetState.pressed)) { - return switch (sizeVariant ?? ButtonSize.small) { + return switch (sizeVariant) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), @@ -441,8 +461,8 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { }; } if (toggleable && states.contains(WidgetState.selected)) { - return switch (shapeVariant ?? ButtonShapeVariant.round) { - ButtonShapeVariant.round => switch (sizeVariant ?? ButtonSize.small) { + return switch (shapeVariant) { + ButtonShapeVariant.round => switch (sizeVariant) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -459,7 +479,7 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, - ButtonShapeVariant.square => switch (sizeVariant ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (sizeVariant) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), @@ -468,15 +488,15 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { }, }; } - return switch (shapeVariant ?? ButtonShapeVariant.round) { - ButtonShapeVariant.round => switch (sizeVariant ?? ButtonSize.small) { + return switch (shapeVariant) { + ButtonShapeVariant.round => switch (sizeVariant) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), ButtonSize.large => const StadiumBorder(), ButtonSize.xLarge => const StadiumBorder(), }, - ButtonShapeVariant.square => switch (sizeVariant ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (sizeVariant) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -516,9 +536,9 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { _FilledTonalIconButtonDefaultsM3E( this.context, this.toggleable, - this.sizeVariant, - this.iconButtonWidth, - this.shapeVariant, + this._sizeVariant, + this._iconButtonWidth, + this._shapeVariant, ) : super( animationDuration: kThemeChangeDuration, enableFeedback: true, @@ -527,9 +547,19 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? sizeVariant; - final IconButtonWidth? iconButtonWidth; - final ButtonShapeVariant? shapeVariant; + final ButtonSize? _sizeVariant; + final IconButtonWidth? _iconButtonWidth; + final ButtonShapeVariant? _shapeVariant; + + @override + ButtonSize get sizeVariant => _sizeVariant ?? ButtonSize.small; + + @override + IconButtonWidth get iconButtonWidth => _iconButtonWidth ?? IconButtonWidth.standard; + + @override + ButtonShapeVariant get shapeVariant => _shapeVariant ?? ButtonShapeVariant.round; + late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -612,28 +642,28 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get padding => - MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { - ButtonSize.xSmall => switch (iconButtonWidth ?? IconButtonWidth.standard) { + MaterialStatePropertyAll(switch (sizeVariant) { + ButtonSize.xSmall => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), }, - ButtonSize.small => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.small => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), }, - ButtonSize.medium => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.medium => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(16.0, 16.0, 16.0, 16.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), }, - ButtonSize.large => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.large => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(32.0, 32.0, 32.0, 32.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), }, - ButtonSize.xLarge => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.xLarge => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(48.0, 48.0, 48.0, 48.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), @@ -642,28 +672,28 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get minimumSize => - MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { - ButtonSize.xSmall => switch (iconButtonWidth ?? IconButtonWidth.standard) { + MaterialStatePropertyAll(switch (sizeVariant) { + ButtonSize.xSmall => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(28.0, 32.0), IconButtonWidth.standard => const Size(32.0, 32.0), IconButtonWidth.wide => const Size(40.0, 32.0), }, - ButtonSize.small => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.small => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(32.0, 40.0), IconButtonWidth.standard => const Size(40.0, 40.0), IconButtonWidth.wide => const Size(52.0, 40.0), }, - ButtonSize.medium => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.medium => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(48.0, 56.0), IconButtonWidth.standard => const Size(56.0, 56.0), IconButtonWidth.wide => const Size(72.0, 56.0), }, - ButtonSize.large => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.large => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(64.0, 96.0), IconButtonWidth.standard => const Size(96.0, 96.0), IconButtonWidth.wide => const Size(128.0, 96.0), }, - ButtonSize.xLarge => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.xLarge => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(104.0, 136.0), IconButtonWidth.standard => const Size(136.0, 136.0), IconButtonWidth.wide => const Size(184.0, 136.0), @@ -675,7 +705,7 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get iconSize => - MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { + MaterialStatePropertyAll(switch (sizeVariant) { ButtonSize.xSmall => 20.0, ButtonSize.small => 24.0, ButtonSize.medium => 24.0, @@ -687,7 +717,7 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { WidgetStateProperty? get shape => WidgetStateProperty.resolveWith((Set states) { if (states.contains(WidgetState.pressed)) { - return switch (sizeVariant ?? ButtonSize.small) { + return switch (sizeVariant) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), @@ -706,8 +736,8 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { }; } if (toggleable && states.contains(WidgetState.selected)) { - return switch (shapeVariant ?? ButtonShapeVariant.round) { - ButtonShapeVariant.round => switch (sizeVariant ?? ButtonSize.small) { + return switch (shapeVariant) { + ButtonShapeVariant.round => switch (sizeVariant) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -724,7 +754,7 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, - ButtonShapeVariant.square => switch (sizeVariant ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (sizeVariant) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), @@ -733,15 +763,15 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { }, }; } - return switch (shapeVariant ?? ButtonShapeVariant.round) { - ButtonShapeVariant.round => switch (sizeVariant ?? ButtonSize.small) { + return switch (shapeVariant) { + ButtonShapeVariant.round => switch (sizeVariant) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), ButtonSize.large => const StadiumBorder(), ButtonSize.xLarge => const StadiumBorder(), }, - ButtonShapeVariant.square => switch (sizeVariant ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (sizeVariant) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -781,9 +811,9 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { _OutlinedIconButtonDefaultsM3E( this.context, this.toggleable, - this.sizeVariant, - this.iconButtonWidth, - this.shapeVariant, + this._sizeVariant, + this._iconButtonWidth, + this._shapeVariant, ) : super( animationDuration: kThemeChangeDuration, enableFeedback: true, @@ -792,9 +822,19 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? sizeVariant; - final IconButtonWidth? iconButtonWidth; - final ButtonShapeVariant? shapeVariant; + final ButtonSize? _sizeVariant; + final IconButtonWidth? _iconButtonWidth; + final ButtonShapeVariant? _shapeVariant; + + @override + ButtonSize get sizeVariant => _sizeVariant ?? ButtonSize.small; + + @override + IconButtonWidth get iconButtonWidth => _iconButtonWidth ?? IconButtonWidth.standard; + + @override + ButtonShapeVariant get shapeVariant => _shapeVariant ?? ButtonShapeVariant.round; + late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -863,28 +903,28 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get padding => - MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { - ButtonSize.xSmall => switch (iconButtonWidth ?? IconButtonWidth.standard) { + MaterialStatePropertyAll(switch (sizeVariant) { + ButtonSize.xSmall => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), }, - ButtonSize.small => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.small => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), }, - ButtonSize.medium => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.medium => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(16.0, 16.0, 16.0, 16.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), }, - ButtonSize.large => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.large => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(32.0, 32.0, 32.0, 32.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), }, - ButtonSize.xLarge => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.xLarge => switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(48.0, 48.0, 48.0, 48.0), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), @@ -893,28 +933,28 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get minimumSize => - MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { - ButtonSize.xSmall => switch (iconButtonWidth ?? IconButtonWidth.standard) { + MaterialStatePropertyAll(switch (sizeVariant) { + ButtonSize.xSmall => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(28.0, 32.0), IconButtonWidth.standard => const Size(32.0, 32.0), IconButtonWidth.wide => const Size(40.0, 32.0), }, - ButtonSize.small => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.small => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(32.0, 40.0), IconButtonWidth.standard => const Size(40.0, 40.0), IconButtonWidth.wide => const Size(52.0, 40.0), }, - ButtonSize.medium => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.medium => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(48.0, 56.0), IconButtonWidth.standard => const Size(56.0, 56.0), IconButtonWidth.wide => const Size(72.0, 56.0), }, - ButtonSize.large => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.large => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(64.0, 96.0), IconButtonWidth.standard => const Size(96.0, 96.0), IconButtonWidth.wide => const Size(128.0, 96.0), }, - ButtonSize.xLarge => switch (iconButtonWidth ?? IconButtonWidth.standard) { + ButtonSize.xLarge => switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(104.0, 136.0), IconButtonWidth.standard => const Size(136.0, 136.0), IconButtonWidth.wide => const Size(184.0, 136.0), @@ -926,7 +966,7 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get iconSize => - MaterialStatePropertyAll(switch (sizeVariant ?? ButtonSize.small) { + MaterialStatePropertyAll(switch (sizeVariant) { ButtonSize.xSmall => 20.0, ButtonSize.small => 24.0, ButtonSize.medium => 24.0, @@ -938,7 +978,7 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { WidgetStateProperty? get shape => WidgetStateProperty.resolveWith((Set states) { if (states.contains(WidgetState.pressed)) { - return switch (sizeVariant ?? ButtonSize.small) { + return switch (sizeVariant) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), @@ -957,8 +997,8 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { }; } if (toggleable && states.contains(WidgetState.selected)) { - return switch (shapeVariant ?? ButtonShapeVariant.round) { - ButtonShapeVariant.round => switch (sizeVariant ?? ButtonSize.small) { + return switch (shapeVariant) { + ButtonShapeVariant.round => switch (sizeVariant) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -975,7 +1015,7 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, - ButtonShapeVariant.square => switch (sizeVariant ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (sizeVariant) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), @@ -984,15 +1024,15 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { }, }; } - return switch (shapeVariant ?? ButtonShapeVariant.round) { - ButtonShapeVariant.round => switch (sizeVariant ?? ButtonSize.small) { + return switch (shapeVariant) { + ButtonShapeVariant.round => switch (sizeVariant) { ButtonSize.xSmall => const StadiumBorder(), ButtonSize.small => const StadiumBorder(), ButtonSize.medium => const StadiumBorder(), ButtonSize.large => const StadiumBorder(), ButtonSize.xLarge => const StadiumBorder(), }, - ButtonShapeVariant.square => switch (sizeVariant ?? ButtonSize.small) { + ButtonShapeVariant.square => switch (sizeVariant) { ButtonSize.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), @@ -1021,7 +1061,7 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { if (states.contains(WidgetState.disabled)) { return BorderSide( color: _colors.outlineVariant, - width: switch (sizeVariant ?? ButtonSize.small) { + width: switch (sizeVariant) { ButtonSize.xSmall => 1.0, ButtonSize.small => 1.0, ButtonSize.medium => 1.0, @@ -1032,7 +1072,7 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { } return BorderSide( color: _colors.outlineVariant, - width: switch (sizeVariant ?? ButtonSize.small) { + width: switch (sizeVariant) { ButtonSize.xSmall => 1.0, ButtonSize.small => 1.0, ButtonSize.medium => 1.0, diff --git a/packages/material_ui/lib/src/icon_button.dart b/packages/material_ui/lib/src/icon_button.dart index 7bbf87e0e051..b274ef161b49 100644 --- a/packages/material_ui/lib/src/icon_button.dart +++ b/packages/material_ui/lib/src/icon_button.dart @@ -1046,12 +1046,44 @@ class _IconButtonM3 extends ButtonStyleButton { /// /// If [ThemeData.useMaterial3] is true and [IconButtonThemeData.variant] is /// [StyleVariant.material3Expressive], Material 3 Expressive defaults are - /// used. The Material 3 Expressive-specific defaults include: + /// used: /// + /// * `textStyle` - null + /// * `backgroundColor` - transparent + /// * `foregroundColor` + /// * disabled - Theme.colorScheme.onSurface(0.38) + /// * selected - Theme.colorScheme.primary + /// * others - Theme.colorScheme.onSurfaceVariant + /// * `overlayColor` + /// * selected + /// * hovered - Theme.colorScheme.primary(0.08) + /// * focused or pressed - Theme.colorScheme.primary(0.1) + /// * hovered - Theme.colorScheme.onSurfaceVariant(0.08) + /// * pressed or focused - Theme.colorScheme.onSurfaceVariant(0.1) + /// * others - transparent + /// * `shadowColor` - null + /// * `surfaceTintColor` - null + /// * `elevation` - 0 + /// * `padding` - based on [ButtonStyle.sizeVariant] and + /// [ButtonStyle.iconButtonWidth]; defaults to all(8) + /// * `minimumSize` - based on [ButtonStyle.sizeVariant] and + /// [ButtonStyle.iconButtonWidth]; defaults to Size(40, 40) + /// * `fixedSize` - null + /// * `maximumSize` - Size.infinite + /// * `iconSize` - based on [ButtonStyle.sizeVariant]; defaults to 24 + /// * `side` - null + /// * `shape` - based on [ButtonStyle.sizeVariant], + /// [ButtonStyle.shapeVariant], and state; defaults to StadiumBorder() + /// * `mouseCursor` - WidgetStateMouseCursor.adaptiveClickable + /// * `visualDensity` - VisualDensity.standard + /// * `tapTargetSize` - MaterialTapTargetSize.padded + /// * `animationDuration` - kThemeChangeDuration + /// * `enableFeedback` - true + /// * `alignment` - Alignment.center + /// * `splashFactory` - Theme.splashFactory /// * `sizeVariant` - ButtonSize.small /// * `iconButtonWidth` - IconButtonWidth.standard /// * `shapeVariant` - ButtonShapeVariant.round - /// * `tapTargetSize` - MaterialTapTargetSize.padded @override ButtonStyle defaultStyleOf(BuildContext context) { final ButtonStyle? iconButtonThemeStyle = IconButtonTheme.of(context).style; diff --git a/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart b/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart index 22bf9e9a9d6f..c0e0da9df885 100644 --- a/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart +++ b/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart @@ -56,7 +56,7 @@ ${_generateOutlinedDefaults()} required String xLarge, }) { return ''' -switch (sizeVariant ?? ButtonSize.small) { +switch (sizeVariant) { ButtonSize.xSmall => $xSmall, ButtonSize.small => $small, ButtonSize.medium => $medium, @@ -119,7 +119,7 @@ switch (sizeVariant ?? ButtonSize.small) { required double wideTrailing, }) { return ''' -switch (iconButtonWidth ?? IconButtonWidth.standard) { +switch (iconButtonWidth) { IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB($narrowLeading, $defaultLeading, $narrowTrailing, $defaultTrailing), IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB($defaultLeading, $defaultLeading, $defaultTrailing, $defaultTrailing), IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB($wideLeading, $defaultLeading, $wideTrailing, $defaultTrailing), @@ -192,7 +192,7 @@ switch (iconButtonWidth ?? IconButtonWidth.standard) { required double wideTrailing, }) { return ''' -switch (iconButtonWidth ?? IconButtonWidth.standard) { +switch (iconButtonWidth) { IconButtonWidth.narrow => const Size(${iconSize + narrowLeading + narrowTrailing}, $height), IconButtonWidth.standard => const Size(${iconSize + defaultLeading + defaultTrailing}, $height), IconButtonWidth.wide => const Size(${iconSize + wideLeading + wideTrailing}, $height), @@ -241,7 +241,7 @@ switch (iconButtonWidth ?? IconButtonWidth.standard) { String get _containerShapeSwitch { return ''' -switch (shapeVariant ?? ButtonShapeVariant.round) { +switch (shapeVariant) { ButtonShapeVariant.round => $_containerRoundShapeSwitch, ButtonShapeVariant.square => $_containerSquareShapeSwitch, }'''; @@ -279,12 +279,29 @@ switch (shapeVariant ?? ButtonShapeVariant.round) { String get _selectedShapeSwitch { return ''' -switch (shapeVariant ?? ButtonShapeVariant.round) { +switch (shapeVariant) { ButtonShapeVariant.round => $_selectedRoundShapeSwitch, ButtonShapeVariant.square => $_selectedSquareShapeSwitch, }'''; } + String get _variantProperties { + return ''' + final ButtonSize? _sizeVariant; + final IconButtonWidth? _iconButtonWidth; + final ButtonShapeVariant? _shapeVariant; + + @override + ButtonSize get sizeVariant => _sizeVariant ?? ButtonSize.small; + + @override + IconButtonWidth get iconButtonWidth => _iconButtonWidth ?? IconButtonWidth.standard; + + @override + ButtonShapeVariant get shapeVariant => _shapeVariant ?? ButtonShapeVariant.round; +'''; + } + String get _sizeDependentProperties { return ''' @override @@ -320,7 +337,7 @@ switch (shapeVariant ?? ButtonShapeVariant.round) { String _generateStandardDefaults(String className) { return ''' class $className extends ButtonStyle { - $className(this.context, this.toggleable, this.sizeVariant, this.iconButtonWidth, this.shapeVariant) + $className(this.context, this.toggleable, this._sizeVariant, this._iconButtonWidth, this._shapeVariant) : super( animationDuration: kThemeChangeDuration, enableFeedback: true, @@ -329,9 +346,7 @@ class $className extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? sizeVariant; - final IconButtonWidth? iconButtonWidth; - final ButtonShapeVariant? shapeVariant; +$_variantProperties late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -414,9 +429,9 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { _FilledIconButtonDefaultsM3E( this.context, this.toggleable, - this.sizeVariant, - this.iconButtonWidth, - this.shapeVariant, + this._sizeVariant, + this._iconButtonWidth, + this._shapeVariant, ) : super( animationDuration: kThemeChangeDuration, @@ -426,9 +441,7 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? sizeVariant; - final IconButtonWidth? iconButtonWidth; - final ButtonShapeVariant? shapeVariant; +$_variantProperties late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -536,9 +549,9 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { _FilledTonalIconButtonDefaultsM3E( this.context, this.toggleable, - this.sizeVariant, - this.iconButtonWidth, - this.shapeVariant, + this._sizeVariant, + this._iconButtonWidth, + this._shapeVariant, ) : super( animationDuration: kThemeChangeDuration, @@ -548,9 +561,7 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? sizeVariant; - final IconButtonWidth? iconButtonWidth; - final ButtonShapeVariant? shapeVariant; +$_variantProperties late final ColorScheme _colors = Theme.of(context).colorScheme; @override @@ -658,9 +669,9 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { _OutlinedIconButtonDefaultsM3E( this.context, this.toggleable, - this.sizeVariant, - this.iconButtonWidth, - this.shapeVariant, + this._sizeVariant, + this._iconButtonWidth, + this._shapeVariant, ) : super( animationDuration: kThemeChangeDuration, @@ -670,9 +681,7 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? sizeVariant; - final IconButtonWidth? iconButtonWidth; - final ButtonShapeVariant? shapeVariant; +$_variantProperties late final ColorScheme _colors = Theme.of(context).colorScheme; @override From cbdf5ac53dd77616e811fa1441a7cc10de813894 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 21:04:17 -0700 Subject: [PATCH 22/31] Move IconButton M3E variant getters --- .../generated/icon_button_defaults_m3e.g.dart | 16 +++++++------- .../templates/icon_button_template.dart | 22 ++++++++++++++----- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart b/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart index aec896434e21..ac1c92286b63 100644 --- a/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart +++ b/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart @@ -26,6 +26,8 @@ class _IconButtonDefaultsM3E extends ButtonStyle { final IconButtonWidth? _iconButtonWidth; final ButtonShapeVariant? _shapeVariant; + late final ColorScheme _colors = Theme.of(context).colorScheme; + @override ButtonSize get sizeVariant => _sizeVariant ?? ButtonSize.small; @@ -35,8 +37,6 @@ class _IconButtonDefaultsM3E extends ButtonStyle { @override ButtonShapeVariant get shapeVariant => _shapeVariant ?? ButtonShapeVariant.round; - late final ColorScheme _colors = Theme.of(context).colorScheme; - @override WidgetStateProperty? get backgroundColor => const MaterialStatePropertyAll(Colors.transparent); @@ -276,6 +276,8 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { final IconButtonWidth? _iconButtonWidth; final ButtonShapeVariant? _shapeVariant; + late final ColorScheme _colors = Theme.of(context).colorScheme; + @override ButtonSize get sizeVariant => _sizeVariant ?? ButtonSize.small; @@ -285,8 +287,6 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { @override ButtonShapeVariant get shapeVariant => _shapeVariant ?? ButtonShapeVariant.round; - late final ColorScheme _colors = Theme.of(context).colorScheme; - @override WidgetStateProperty? get backgroundColor => WidgetStateProperty.resolveWith((Set states) { @@ -551,6 +551,8 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { final IconButtonWidth? _iconButtonWidth; final ButtonShapeVariant? _shapeVariant; + late final ColorScheme _colors = Theme.of(context).colorScheme; + @override ButtonSize get sizeVariant => _sizeVariant ?? ButtonSize.small; @@ -560,8 +562,6 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { @override ButtonShapeVariant get shapeVariant => _shapeVariant ?? ButtonShapeVariant.round; - late final ColorScheme _colors = Theme.of(context).colorScheme; - @override WidgetStateProperty? get backgroundColor => WidgetStateProperty.resolveWith((Set states) { @@ -826,6 +826,8 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { final IconButtonWidth? _iconButtonWidth; final ButtonShapeVariant? _shapeVariant; + late final ColorScheme _colors = Theme.of(context).colorScheme; + @override ButtonSize get sizeVariant => _sizeVariant ?? ButtonSize.small; @@ -835,8 +837,6 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { @override ButtonShapeVariant get shapeVariant => _shapeVariant ?? ButtonShapeVariant.round; - late final ColorScheme _colors = Theme.of(context).colorScheme; - @override WidgetStateProperty? get backgroundColor => WidgetStateProperty.resolveWith((Set states) { diff --git a/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart b/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart index c0e0da9df885..a78b439be8e2 100644 --- a/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart +++ b/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart @@ -285,12 +285,16 @@ switch (shapeVariant) { }'''; } - String get _variantProperties { + String get _variantFields { return ''' final ButtonSize? _sizeVariant; final IconButtonWidth? _iconButtonWidth; final ButtonShapeVariant? _shapeVariant; +'''; + } + String get _variantGetters { + return ''' @override ButtonSize get sizeVariant => _sizeVariant ?? ButtonSize.small; @@ -346,9 +350,11 @@ class $className extends ButtonStyle { final BuildContext context; final bool toggleable; -$_variantProperties +$_variantFields late final ColorScheme _colors = Theme.of(context).colorScheme; +$_variantGetters + @override WidgetStateProperty? get backgroundColor => const MaterialStatePropertyAll(Colors.transparent); @@ -441,9 +447,11 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { final BuildContext context; final bool toggleable; -$_variantProperties +$_variantFields late final ColorScheme _colors = Theme.of(context).colorScheme; +$_variantGetters + @override WidgetStateProperty? get backgroundColor => WidgetStateProperty.resolveWith((Set states) { @@ -561,9 +569,11 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { final BuildContext context; final bool toggleable; -$_variantProperties +$_variantFields late final ColorScheme _colors = Theme.of(context).colorScheme; +$_variantGetters + @override WidgetStateProperty? get backgroundColor => WidgetStateProperty.resolveWith((Set states) { @@ -681,9 +691,11 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { final BuildContext context; final bool toggleable; -$_variantProperties +$_variantFields late final ColorScheme _colors = Theme.of(context).colorScheme; +$_variantGetters + @override WidgetStateProperty? get backgroundColor => WidgetStateProperty.resolveWith((Set states) { From aa5eaaa9a8bfd7a205b52da765d778ff07145e4b Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 21:10:48 -0700 Subject: [PATCH 23/31] Clarify IconButton M3E default constructors --- .../generated/icon_button_defaults_m3e.g.dart | 44 ++++++++++------- .../templates/icon_button_template.dart | 48 ++++++++++++------- 2 files changed, 59 insertions(+), 33 deletions(-) diff --git a/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart b/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart index ac1c92286b63..0d9cc5e5fb18 100644 --- a/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart +++ b/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart @@ -11,10 +11,13 @@ class _IconButtonDefaultsM3E extends ButtonStyle { _IconButtonDefaultsM3E( this.context, this.toggleable, - this._sizeVariant, - this._iconButtonWidth, - this._shapeVariant, - ) : super( + ButtonSize? sizeVariant, + IconButtonWidth? iconButtonWidth, + ButtonShapeVariant? shapeVariant, + ) : _sizeVariant = sizeVariant, + _iconButtonWidth = iconButtonWidth, + _shapeVariant = shapeVariant, + super( animationDuration: kThemeChangeDuration, enableFeedback: true, alignment: Alignment.center, @@ -261,10 +264,13 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { _FilledIconButtonDefaultsM3E( this.context, this.toggleable, - this._sizeVariant, - this._iconButtonWidth, - this._shapeVariant, - ) : super( + ButtonSize? sizeVariant, + IconButtonWidth? iconButtonWidth, + ButtonShapeVariant? shapeVariant, + ) : _sizeVariant = sizeVariant, + _iconButtonWidth = iconButtonWidth, + _shapeVariant = shapeVariant, + super( animationDuration: kThemeChangeDuration, enableFeedback: true, alignment: Alignment.center, @@ -536,10 +542,13 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { _FilledTonalIconButtonDefaultsM3E( this.context, this.toggleable, - this._sizeVariant, - this._iconButtonWidth, - this._shapeVariant, - ) : super( + ButtonSize? sizeVariant, + IconButtonWidth? iconButtonWidth, + ButtonShapeVariant? shapeVariant, + ) : _sizeVariant = sizeVariant, + _iconButtonWidth = iconButtonWidth, + _shapeVariant = shapeVariant, + super( animationDuration: kThemeChangeDuration, enableFeedback: true, alignment: Alignment.center, @@ -811,10 +820,13 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { _OutlinedIconButtonDefaultsM3E( this.context, this.toggleable, - this._sizeVariant, - this._iconButtonWidth, - this._shapeVariant, - ) : super( + ButtonSize? sizeVariant, + IconButtonWidth? iconButtonWidth, + ButtonShapeVariant? shapeVariant, + ) : _sizeVariant = sizeVariant, + _iconButtonWidth = iconButtonWidth, + _shapeVariant = shapeVariant, + super( animationDuration: kThemeChangeDuration, enableFeedback: true, alignment: Alignment.center, diff --git a/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart b/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart index a78b439be8e2..b8e5ed93347e 100644 --- a/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart +++ b/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart @@ -341,8 +341,16 @@ switch (shapeVariant) { String _generateStandardDefaults(String className) { return ''' class $className extends ButtonStyle { - $className(this.context, this.toggleable, this._sizeVariant, this._iconButtonWidth, this._shapeVariant) - : super( + $className( + this.context, + this.toggleable, + ButtonSize? sizeVariant, + IconButtonWidth? iconButtonWidth, + ButtonShapeVariant? shapeVariant, + ) : _sizeVariant = sizeVariant, + _iconButtonWidth = iconButtonWidth, + _shapeVariant = shapeVariant, + super( animationDuration: kThemeChangeDuration, enableFeedback: true, alignment: Alignment.center, @@ -435,11 +443,13 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { _FilledIconButtonDefaultsM3E( this.context, this.toggleable, - this._sizeVariant, - this._iconButtonWidth, - this._shapeVariant, - ) - : super( + ButtonSize? sizeVariant, + IconButtonWidth? iconButtonWidth, + ButtonShapeVariant? shapeVariant, + ) : _sizeVariant = sizeVariant, + _iconButtonWidth = iconButtonWidth, + _shapeVariant = shapeVariant, + super( animationDuration: kThemeChangeDuration, enableFeedback: true, alignment: Alignment.center, @@ -557,11 +567,13 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { _FilledTonalIconButtonDefaultsM3E( this.context, this.toggleable, - this._sizeVariant, - this._iconButtonWidth, - this._shapeVariant, - ) - : super( + ButtonSize? sizeVariant, + IconButtonWidth? iconButtonWidth, + ButtonShapeVariant? shapeVariant, + ) : _sizeVariant = sizeVariant, + _iconButtonWidth = iconButtonWidth, + _shapeVariant = shapeVariant, + super( animationDuration: kThemeChangeDuration, enableFeedback: true, alignment: Alignment.center, @@ -679,11 +691,13 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { _OutlinedIconButtonDefaultsM3E( this.context, this.toggleable, - this._sizeVariant, - this._iconButtonWidth, - this._shapeVariant, - ) - : super( + ButtonSize? sizeVariant, + IconButtonWidth? iconButtonWidth, + ButtonShapeVariant? shapeVariant, + ) : _sizeVariant = sizeVariant, + _iconButtonWidth = iconButtonWidth, + _shapeVariant = shapeVariant, + super( animationDuration: kThemeChangeDuration, enableFeedback: true, alignment: Alignment.center, From 844066451ac281c493b0907b262d906b4d8d847d Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 21:21:56 -0700 Subject: [PATCH 24/31] Rename IconButton M3E variant enums --- .../material_ui/lib/src/button_style.dart | 16 +- .../generated/icon_button_defaults_m3e.g.dart | 752 ++++++++++-------- packages/material_ui/lib/src/icon_button.dart | 15 +- .../material_ui/test/icon_button_test.dart | 90 ++- .../templates/icon_button_template.dart | 46 +- 5 files changed, 493 insertions(+), 426 deletions(-) diff --git a/packages/material_ui/lib/src/button_style.dart b/packages/material_ui/lib/src/button_style.dart index 2072e38b1b04..e12120be7555 100644 --- a/packages/material_ui/lib/src/button_style.dart +++ b/packages/material_ui/lib/src/button_style.dart @@ -36,7 +36,7 @@ import 'theme_data.dart'; /// Each size variant represents a named visual scale. For example, a Material /// 3 Expressive [IconButton] uses this value to choose its container size, icon /// size, and padding. -enum ButtonSize { +enum ButtonSizeVariant { /// The smallest button size. xSmall, @@ -54,7 +54,7 @@ enum ButtonSize { } /// Defines the width variants for Material 3 Expressive [IconButton]. -enum IconButtonWidth { +enum IconButtonWidthVariant { /// A narrower icon button. narrow, @@ -484,7 +484,7 @@ class ButtonStyle with Diagnosticable { /// /// Use [minimumSize], [fixedSize], [maximumSize], [padding], or [iconSize] to /// directly override those individual style properties. - final ButtonSize? sizeVariant; + final ButtonSizeVariant? sizeVariant; /// The Material 3 Expressive width variant for an [IconButton]. /// @@ -496,7 +496,7 @@ class ButtonStyle with Diagnosticable { /// This property is only used by icon buttons. Use [padding], /// [minimumSize], [fixedSize], or [maximumSize] to directly override the /// resulting layout. - final IconButtonWidth? iconButtonWidth; + final IconButtonWidthVariant? iconButtonWidth; /// The Material 3 Expressive shape variant for this button. /// @@ -539,8 +539,8 @@ class ButtonStyle with Diagnosticable { InteractiveInkFeatureFactory? splashFactory, ButtonLayerBuilder? backgroundBuilder, ButtonLayerBuilder? foregroundBuilder, - ButtonSize? sizeVariant, - IconButtonWidth? iconButtonWidth, + ButtonSizeVariant? sizeVariant, + IconButtonWidthVariant? iconButtonWidth, ButtonShapeVariant? shapeVariant, }) { return ButtonStyle( @@ -809,9 +809,9 @@ class ButtonStyle with Diagnosticable { defaultValue: null, ), ); - properties.add(EnumProperty('sizeVariant', sizeVariant, defaultValue: null)); + properties.add(EnumProperty('sizeVariant', sizeVariant, defaultValue: null)); properties.add( - EnumProperty('iconButtonWidth', iconButtonWidth, defaultValue: null), + EnumProperty('iconButtonWidth', iconButtonWidth, defaultValue: null), ); properties.add( EnumProperty('shapeVariant', shapeVariant, defaultValue: null), diff --git a/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart b/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart index 0d9cc5e5fb18..4c3c68d1b040 100644 --- a/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart +++ b/packages/material_ui/lib/src/generated/icon_button_defaults_m3e.g.dart @@ -11,8 +11,8 @@ class _IconButtonDefaultsM3E extends ButtonStyle { _IconButtonDefaultsM3E( this.context, this.toggleable, - ButtonSize? sizeVariant, - IconButtonWidth? iconButtonWidth, + ButtonSizeVariant? sizeVariant, + IconButtonWidthVariant? iconButtonWidth, ButtonShapeVariant? shapeVariant, ) : _sizeVariant = sizeVariant, _iconButtonWidth = iconButtonWidth, @@ -25,17 +25,17 @@ class _IconButtonDefaultsM3E extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? _sizeVariant; - final IconButtonWidth? _iconButtonWidth; + final ButtonSizeVariant? _sizeVariant; + final IconButtonWidthVariant? _iconButtonWidth; final ButtonShapeVariant? _shapeVariant; late final ColorScheme _colors = Theme.of(context).colorScheme; @override - ButtonSize get sizeVariant => _sizeVariant ?? ButtonSize.small; + ButtonSizeVariant get sizeVariant => _sizeVariant ?? ButtonSizeVariant.small; @override - IconButtonWidth get iconButtonWidth => _iconButtonWidth ?? IconButtonWidth.standard; + IconButtonWidthVariant get iconButtonWidth => _iconButtonWidth ?? IconButtonWidthVariant.standard; @override ButtonShapeVariant get shapeVariant => _shapeVariant ?? ButtonShapeVariant.round; @@ -94,62 +94,77 @@ class _IconButtonDefaultsM3E extends ButtonStyle { const MaterialStatePropertyAll(Colors.transparent); @override - WidgetStateProperty? get padding => - MaterialStatePropertyAll(switch (sizeVariant) { - ButtonSize.xSmall => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), - }, - ButtonSize.small => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), - }, - ButtonSize.medium => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(16.0, 16.0, 16.0, 16.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), - }, - ButtonSize.large => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(32.0, 32.0, 32.0, 32.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), - }, - ButtonSize.xLarge => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(48.0, 48.0, 48.0, 48.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), - }, - }); + WidgetStateProperty? + get padding => MaterialStatePropertyAll(switch (sizeVariant) { + ButtonSizeVariant.xSmall => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), + }, + ButtonSizeVariant.small => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), + }, + ButtonSizeVariant.medium => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB( + 16.0, + 16.0, + 16.0, + 16.0, + ), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), + }, + ButtonSizeVariant.large => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB( + 32.0, + 32.0, + 32.0, + 32.0, + ), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), + }, + ButtonSizeVariant.xLarge => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB( + 48.0, + 48.0, + 48.0, + 48.0, + ), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), + }, + }); @override WidgetStateProperty? get minimumSize => MaterialStatePropertyAll(switch (sizeVariant) { - ButtonSize.xSmall => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(28.0, 32.0), - IconButtonWidth.standard => const Size(32.0, 32.0), - IconButtonWidth.wide => const Size(40.0, 32.0), + ButtonSizeVariant.xSmall => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(28.0, 32.0), + IconButtonWidthVariant.standard => const Size(32.0, 32.0), + IconButtonWidthVariant.wide => const Size(40.0, 32.0), }, - ButtonSize.small => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(32.0, 40.0), - IconButtonWidth.standard => const Size(40.0, 40.0), - IconButtonWidth.wide => const Size(52.0, 40.0), + ButtonSizeVariant.small => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(32.0, 40.0), + IconButtonWidthVariant.standard => const Size(40.0, 40.0), + IconButtonWidthVariant.wide => const Size(52.0, 40.0), }, - ButtonSize.medium => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(48.0, 56.0), - IconButtonWidth.standard => const Size(56.0, 56.0), - IconButtonWidth.wide => const Size(72.0, 56.0), + ButtonSizeVariant.medium => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(48.0, 56.0), + IconButtonWidthVariant.standard => const Size(56.0, 56.0), + IconButtonWidthVariant.wide => const Size(72.0, 56.0), }, - ButtonSize.large => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(64.0, 96.0), - IconButtonWidth.standard => const Size(96.0, 96.0), - IconButtonWidth.wide => const Size(128.0, 96.0), + ButtonSizeVariant.large => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(64.0, 96.0), + IconButtonWidthVariant.standard => const Size(96.0, 96.0), + IconButtonWidthVariant.wide => const Size(128.0, 96.0), }, - ButtonSize.xLarge => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(104.0, 136.0), - IconButtonWidth.standard => const Size(136.0, 136.0), - IconButtonWidth.wide => const Size(184.0, 136.0), + ButtonSizeVariant.xLarge => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(104.0, 136.0), + IconButtonWidthVariant.standard => const Size(136.0, 136.0), + IconButtonWidthVariant.wide => const Size(184.0, 136.0), }, }); @@ -159,11 +174,11 @@ class _IconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get iconSize => MaterialStatePropertyAll(switch (sizeVariant) { - ButtonSize.xSmall => 20.0, - ButtonSize.small => 24.0, - ButtonSize.medium => 24.0, - ButtonSize.large => 32.0, - ButtonSize.xLarge => 40.0, + ButtonSizeVariant.xSmall => 20.0, + ButtonSizeVariant.small => 24.0, + ButtonSizeVariant.medium => 24.0, + ButtonSizeVariant.large => 32.0, + ButtonSizeVariant.xLarge => 40.0, }); @override @@ -171,19 +186,19 @@ class _IconButtonDefaultsM3E extends ButtonStyle { WidgetStateProperty.resolveWith((Set states) { if (states.contains(WidgetState.pressed)) { return switch (sizeVariant) { - ButtonSize.xSmall => const RoundedRectangleBorder( + ButtonSizeVariant.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), - ButtonSize.small => const RoundedRectangleBorder( + ButtonSizeVariant.small => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), - ButtonSize.medium => const RoundedRectangleBorder( + ButtonSizeVariant.medium => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.large => const RoundedRectangleBorder( + ButtonSizeVariant.large => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16.0)), ), - ButtonSize.xLarge => const RoundedRectangleBorder( + ButtonSizeVariant.xLarge => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16.0)), ), }; @@ -191,53 +206,53 @@ class _IconButtonDefaultsM3E extends ButtonStyle { if (toggleable && states.contains(WidgetState.selected)) { return switch (shapeVariant) { ButtonShapeVariant.round => switch (sizeVariant) { - ButtonSize.xSmall => const RoundedRectangleBorder( + ButtonSizeVariant.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.small => const RoundedRectangleBorder( + ButtonSizeVariant.small => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.medium => const RoundedRectangleBorder( + ButtonSizeVariant.medium => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16.0)), ), - ButtonSize.large => const RoundedRectangleBorder( + ButtonSizeVariant.large => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(28.0)), ), - ButtonSize.xLarge => const RoundedRectangleBorder( + ButtonSizeVariant.xLarge => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, ButtonShapeVariant.square => switch (sizeVariant) { - ButtonSize.xSmall => const StadiumBorder(), - ButtonSize.small => const StadiumBorder(), - ButtonSize.medium => const StadiumBorder(), - ButtonSize.large => const StadiumBorder(), - ButtonSize.xLarge => const StadiumBorder(), + ButtonSizeVariant.xSmall => const StadiumBorder(), + ButtonSizeVariant.small => const StadiumBorder(), + ButtonSizeVariant.medium => const StadiumBorder(), + ButtonSizeVariant.large => const StadiumBorder(), + ButtonSizeVariant.xLarge => const StadiumBorder(), }, }; } return switch (shapeVariant) { ButtonShapeVariant.round => switch (sizeVariant) { - ButtonSize.xSmall => const StadiumBorder(), - ButtonSize.small => const StadiumBorder(), - ButtonSize.medium => const StadiumBorder(), - ButtonSize.large => const StadiumBorder(), - ButtonSize.xLarge => const StadiumBorder(), + ButtonSizeVariant.xSmall => const StadiumBorder(), + ButtonSizeVariant.small => const StadiumBorder(), + ButtonSizeVariant.medium => const StadiumBorder(), + ButtonSizeVariant.large => const StadiumBorder(), + ButtonSizeVariant.xLarge => const StadiumBorder(), }, ButtonShapeVariant.square => switch (sizeVariant) { - ButtonSize.xSmall => const RoundedRectangleBorder( + ButtonSizeVariant.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.small => const RoundedRectangleBorder( + ButtonSizeVariant.small => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.medium => const RoundedRectangleBorder( + ButtonSizeVariant.medium => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16.0)), ), - ButtonSize.large => const RoundedRectangleBorder( + ButtonSizeVariant.large => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(28.0)), ), - ButtonSize.xLarge => const RoundedRectangleBorder( + ButtonSizeVariant.xLarge => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, @@ -264,8 +279,8 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { _FilledIconButtonDefaultsM3E( this.context, this.toggleable, - ButtonSize? sizeVariant, - IconButtonWidth? iconButtonWidth, + ButtonSizeVariant? sizeVariant, + IconButtonWidthVariant? iconButtonWidth, ButtonShapeVariant? shapeVariant, ) : _sizeVariant = sizeVariant, _iconButtonWidth = iconButtonWidth, @@ -278,17 +293,17 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? _sizeVariant; - final IconButtonWidth? _iconButtonWidth; + final ButtonSizeVariant? _sizeVariant; + final IconButtonWidthVariant? _iconButtonWidth; final ButtonShapeVariant? _shapeVariant; late final ColorScheme _colors = Theme.of(context).colorScheme; @override - ButtonSize get sizeVariant => _sizeVariant ?? ButtonSize.small; + ButtonSizeVariant get sizeVariant => _sizeVariant ?? ButtonSizeVariant.small; @override - IconButtonWidth get iconButtonWidth => _iconButtonWidth ?? IconButtonWidth.standard; + IconButtonWidthVariant get iconButtonWidth => _iconButtonWidth ?? IconButtonWidthVariant.standard; @override ButtonShapeVariant get shapeVariant => _shapeVariant ?? ButtonShapeVariant.round; @@ -372,62 +387,77 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { const MaterialStatePropertyAll(Colors.transparent); @override - WidgetStateProperty? get padding => - MaterialStatePropertyAll(switch (sizeVariant) { - ButtonSize.xSmall => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), - }, - ButtonSize.small => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), - }, - ButtonSize.medium => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(16.0, 16.0, 16.0, 16.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), - }, - ButtonSize.large => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(32.0, 32.0, 32.0, 32.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), - }, - ButtonSize.xLarge => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(48.0, 48.0, 48.0, 48.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), - }, - }); + WidgetStateProperty? + get padding => MaterialStatePropertyAll(switch (sizeVariant) { + ButtonSizeVariant.xSmall => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), + }, + ButtonSizeVariant.small => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), + }, + ButtonSizeVariant.medium => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB( + 16.0, + 16.0, + 16.0, + 16.0, + ), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), + }, + ButtonSizeVariant.large => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB( + 32.0, + 32.0, + 32.0, + 32.0, + ), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), + }, + ButtonSizeVariant.xLarge => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB( + 48.0, + 48.0, + 48.0, + 48.0, + ), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), + }, + }); @override WidgetStateProperty? get minimumSize => MaterialStatePropertyAll(switch (sizeVariant) { - ButtonSize.xSmall => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(28.0, 32.0), - IconButtonWidth.standard => const Size(32.0, 32.0), - IconButtonWidth.wide => const Size(40.0, 32.0), + ButtonSizeVariant.xSmall => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(28.0, 32.0), + IconButtonWidthVariant.standard => const Size(32.0, 32.0), + IconButtonWidthVariant.wide => const Size(40.0, 32.0), }, - ButtonSize.small => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(32.0, 40.0), - IconButtonWidth.standard => const Size(40.0, 40.0), - IconButtonWidth.wide => const Size(52.0, 40.0), + ButtonSizeVariant.small => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(32.0, 40.0), + IconButtonWidthVariant.standard => const Size(40.0, 40.0), + IconButtonWidthVariant.wide => const Size(52.0, 40.0), }, - ButtonSize.medium => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(48.0, 56.0), - IconButtonWidth.standard => const Size(56.0, 56.0), - IconButtonWidth.wide => const Size(72.0, 56.0), + ButtonSizeVariant.medium => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(48.0, 56.0), + IconButtonWidthVariant.standard => const Size(56.0, 56.0), + IconButtonWidthVariant.wide => const Size(72.0, 56.0), }, - ButtonSize.large => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(64.0, 96.0), - IconButtonWidth.standard => const Size(96.0, 96.0), - IconButtonWidth.wide => const Size(128.0, 96.0), + ButtonSizeVariant.large => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(64.0, 96.0), + IconButtonWidthVariant.standard => const Size(96.0, 96.0), + IconButtonWidthVariant.wide => const Size(128.0, 96.0), }, - ButtonSize.xLarge => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(104.0, 136.0), - IconButtonWidth.standard => const Size(136.0, 136.0), - IconButtonWidth.wide => const Size(184.0, 136.0), + ButtonSizeVariant.xLarge => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(104.0, 136.0), + IconButtonWidthVariant.standard => const Size(136.0, 136.0), + IconButtonWidthVariant.wide => const Size(184.0, 136.0), }, }); @@ -437,11 +467,11 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get iconSize => MaterialStatePropertyAll(switch (sizeVariant) { - ButtonSize.xSmall => 20.0, - ButtonSize.small => 24.0, - ButtonSize.medium => 24.0, - ButtonSize.large => 32.0, - ButtonSize.xLarge => 40.0, + ButtonSizeVariant.xSmall => 20.0, + ButtonSizeVariant.small => 24.0, + ButtonSizeVariant.medium => 24.0, + ButtonSizeVariant.large => 32.0, + ButtonSizeVariant.xLarge => 40.0, }); @override @@ -449,19 +479,19 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { WidgetStateProperty.resolveWith((Set states) { if (states.contains(WidgetState.pressed)) { return switch (sizeVariant) { - ButtonSize.xSmall => const RoundedRectangleBorder( + ButtonSizeVariant.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), - ButtonSize.small => const RoundedRectangleBorder( + ButtonSizeVariant.small => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), - ButtonSize.medium => const RoundedRectangleBorder( + ButtonSizeVariant.medium => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.large => const RoundedRectangleBorder( + ButtonSizeVariant.large => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16.0)), ), - ButtonSize.xLarge => const RoundedRectangleBorder( + ButtonSizeVariant.xLarge => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16.0)), ), }; @@ -469,53 +499,53 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { if (toggleable && states.contains(WidgetState.selected)) { return switch (shapeVariant) { ButtonShapeVariant.round => switch (sizeVariant) { - ButtonSize.xSmall => const RoundedRectangleBorder( + ButtonSizeVariant.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.small => const RoundedRectangleBorder( + ButtonSizeVariant.small => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.medium => const RoundedRectangleBorder( + ButtonSizeVariant.medium => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16.0)), ), - ButtonSize.large => const RoundedRectangleBorder( + ButtonSizeVariant.large => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(28.0)), ), - ButtonSize.xLarge => const RoundedRectangleBorder( + ButtonSizeVariant.xLarge => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, ButtonShapeVariant.square => switch (sizeVariant) { - ButtonSize.xSmall => const StadiumBorder(), - ButtonSize.small => const StadiumBorder(), - ButtonSize.medium => const StadiumBorder(), - ButtonSize.large => const StadiumBorder(), - ButtonSize.xLarge => const StadiumBorder(), + ButtonSizeVariant.xSmall => const StadiumBorder(), + ButtonSizeVariant.small => const StadiumBorder(), + ButtonSizeVariant.medium => const StadiumBorder(), + ButtonSizeVariant.large => const StadiumBorder(), + ButtonSizeVariant.xLarge => const StadiumBorder(), }, }; } return switch (shapeVariant) { ButtonShapeVariant.round => switch (sizeVariant) { - ButtonSize.xSmall => const StadiumBorder(), - ButtonSize.small => const StadiumBorder(), - ButtonSize.medium => const StadiumBorder(), - ButtonSize.large => const StadiumBorder(), - ButtonSize.xLarge => const StadiumBorder(), + ButtonSizeVariant.xSmall => const StadiumBorder(), + ButtonSizeVariant.small => const StadiumBorder(), + ButtonSizeVariant.medium => const StadiumBorder(), + ButtonSizeVariant.large => const StadiumBorder(), + ButtonSizeVariant.xLarge => const StadiumBorder(), }, ButtonShapeVariant.square => switch (sizeVariant) { - ButtonSize.xSmall => const RoundedRectangleBorder( + ButtonSizeVariant.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.small => const RoundedRectangleBorder( + ButtonSizeVariant.small => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.medium => const RoundedRectangleBorder( + ButtonSizeVariant.medium => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16.0)), ), - ButtonSize.large => const RoundedRectangleBorder( + ButtonSizeVariant.large => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(28.0)), ), - ButtonSize.xLarge => const RoundedRectangleBorder( + ButtonSizeVariant.xLarge => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, @@ -542,8 +572,8 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { _FilledTonalIconButtonDefaultsM3E( this.context, this.toggleable, - ButtonSize? sizeVariant, - IconButtonWidth? iconButtonWidth, + ButtonSizeVariant? sizeVariant, + IconButtonWidthVariant? iconButtonWidth, ButtonShapeVariant? shapeVariant, ) : _sizeVariant = sizeVariant, _iconButtonWidth = iconButtonWidth, @@ -556,17 +586,17 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? _sizeVariant; - final IconButtonWidth? _iconButtonWidth; + final ButtonSizeVariant? _sizeVariant; + final IconButtonWidthVariant? _iconButtonWidth; final ButtonShapeVariant? _shapeVariant; late final ColorScheme _colors = Theme.of(context).colorScheme; @override - ButtonSize get sizeVariant => _sizeVariant ?? ButtonSize.small; + ButtonSizeVariant get sizeVariant => _sizeVariant ?? ButtonSizeVariant.small; @override - IconButtonWidth get iconButtonWidth => _iconButtonWidth ?? IconButtonWidth.standard; + IconButtonWidthVariant get iconButtonWidth => _iconButtonWidth ?? IconButtonWidthVariant.standard; @override ButtonShapeVariant get shapeVariant => _shapeVariant ?? ButtonShapeVariant.round; @@ -650,62 +680,77 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { const MaterialStatePropertyAll(Colors.transparent); @override - WidgetStateProperty? get padding => - MaterialStatePropertyAll(switch (sizeVariant) { - ButtonSize.xSmall => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), - }, - ButtonSize.small => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), - }, - ButtonSize.medium => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(16.0, 16.0, 16.0, 16.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), - }, - ButtonSize.large => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(32.0, 32.0, 32.0, 32.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), - }, - ButtonSize.xLarge => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(48.0, 48.0, 48.0, 48.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), - }, - }); + WidgetStateProperty? + get padding => MaterialStatePropertyAll(switch (sizeVariant) { + ButtonSizeVariant.xSmall => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), + }, + ButtonSizeVariant.small => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), + }, + ButtonSizeVariant.medium => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB( + 16.0, + 16.0, + 16.0, + 16.0, + ), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), + }, + ButtonSizeVariant.large => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB( + 32.0, + 32.0, + 32.0, + 32.0, + ), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), + }, + ButtonSizeVariant.xLarge => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB( + 48.0, + 48.0, + 48.0, + 48.0, + ), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), + }, + }); @override WidgetStateProperty? get minimumSize => MaterialStatePropertyAll(switch (sizeVariant) { - ButtonSize.xSmall => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(28.0, 32.0), - IconButtonWidth.standard => const Size(32.0, 32.0), - IconButtonWidth.wide => const Size(40.0, 32.0), + ButtonSizeVariant.xSmall => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(28.0, 32.0), + IconButtonWidthVariant.standard => const Size(32.0, 32.0), + IconButtonWidthVariant.wide => const Size(40.0, 32.0), }, - ButtonSize.small => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(32.0, 40.0), - IconButtonWidth.standard => const Size(40.0, 40.0), - IconButtonWidth.wide => const Size(52.0, 40.0), + ButtonSizeVariant.small => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(32.0, 40.0), + IconButtonWidthVariant.standard => const Size(40.0, 40.0), + IconButtonWidthVariant.wide => const Size(52.0, 40.0), }, - ButtonSize.medium => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(48.0, 56.0), - IconButtonWidth.standard => const Size(56.0, 56.0), - IconButtonWidth.wide => const Size(72.0, 56.0), + ButtonSizeVariant.medium => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(48.0, 56.0), + IconButtonWidthVariant.standard => const Size(56.0, 56.0), + IconButtonWidthVariant.wide => const Size(72.0, 56.0), }, - ButtonSize.large => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(64.0, 96.0), - IconButtonWidth.standard => const Size(96.0, 96.0), - IconButtonWidth.wide => const Size(128.0, 96.0), + ButtonSizeVariant.large => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(64.0, 96.0), + IconButtonWidthVariant.standard => const Size(96.0, 96.0), + IconButtonWidthVariant.wide => const Size(128.0, 96.0), }, - ButtonSize.xLarge => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(104.0, 136.0), - IconButtonWidth.standard => const Size(136.0, 136.0), - IconButtonWidth.wide => const Size(184.0, 136.0), + ButtonSizeVariant.xLarge => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(104.0, 136.0), + IconButtonWidthVariant.standard => const Size(136.0, 136.0), + IconButtonWidthVariant.wide => const Size(184.0, 136.0), }, }); @@ -715,11 +760,11 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get iconSize => MaterialStatePropertyAll(switch (sizeVariant) { - ButtonSize.xSmall => 20.0, - ButtonSize.small => 24.0, - ButtonSize.medium => 24.0, - ButtonSize.large => 32.0, - ButtonSize.xLarge => 40.0, + ButtonSizeVariant.xSmall => 20.0, + ButtonSizeVariant.small => 24.0, + ButtonSizeVariant.medium => 24.0, + ButtonSizeVariant.large => 32.0, + ButtonSizeVariant.xLarge => 40.0, }); @override @@ -727,19 +772,19 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { WidgetStateProperty.resolveWith((Set states) { if (states.contains(WidgetState.pressed)) { return switch (sizeVariant) { - ButtonSize.xSmall => const RoundedRectangleBorder( + ButtonSizeVariant.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), - ButtonSize.small => const RoundedRectangleBorder( + ButtonSizeVariant.small => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), - ButtonSize.medium => const RoundedRectangleBorder( + ButtonSizeVariant.medium => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.large => const RoundedRectangleBorder( + ButtonSizeVariant.large => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16.0)), ), - ButtonSize.xLarge => const RoundedRectangleBorder( + ButtonSizeVariant.xLarge => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16.0)), ), }; @@ -747,53 +792,53 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { if (toggleable && states.contains(WidgetState.selected)) { return switch (shapeVariant) { ButtonShapeVariant.round => switch (sizeVariant) { - ButtonSize.xSmall => const RoundedRectangleBorder( + ButtonSizeVariant.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.small => const RoundedRectangleBorder( + ButtonSizeVariant.small => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.medium => const RoundedRectangleBorder( + ButtonSizeVariant.medium => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16.0)), ), - ButtonSize.large => const RoundedRectangleBorder( + ButtonSizeVariant.large => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(28.0)), ), - ButtonSize.xLarge => const RoundedRectangleBorder( + ButtonSizeVariant.xLarge => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, ButtonShapeVariant.square => switch (sizeVariant) { - ButtonSize.xSmall => const StadiumBorder(), - ButtonSize.small => const StadiumBorder(), - ButtonSize.medium => const StadiumBorder(), - ButtonSize.large => const StadiumBorder(), - ButtonSize.xLarge => const StadiumBorder(), + ButtonSizeVariant.xSmall => const StadiumBorder(), + ButtonSizeVariant.small => const StadiumBorder(), + ButtonSizeVariant.medium => const StadiumBorder(), + ButtonSizeVariant.large => const StadiumBorder(), + ButtonSizeVariant.xLarge => const StadiumBorder(), }, }; } return switch (shapeVariant) { ButtonShapeVariant.round => switch (sizeVariant) { - ButtonSize.xSmall => const StadiumBorder(), - ButtonSize.small => const StadiumBorder(), - ButtonSize.medium => const StadiumBorder(), - ButtonSize.large => const StadiumBorder(), - ButtonSize.xLarge => const StadiumBorder(), + ButtonSizeVariant.xSmall => const StadiumBorder(), + ButtonSizeVariant.small => const StadiumBorder(), + ButtonSizeVariant.medium => const StadiumBorder(), + ButtonSizeVariant.large => const StadiumBorder(), + ButtonSizeVariant.xLarge => const StadiumBorder(), }, ButtonShapeVariant.square => switch (sizeVariant) { - ButtonSize.xSmall => const RoundedRectangleBorder( + ButtonSizeVariant.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.small => const RoundedRectangleBorder( + ButtonSizeVariant.small => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.medium => const RoundedRectangleBorder( + ButtonSizeVariant.medium => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16.0)), ), - ButtonSize.large => const RoundedRectangleBorder( + ButtonSizeVariant.large => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(28.0)), ), - ButtonSize.xLarge => const RoundedRectangleBorder( + ButtonSizeVariant.xLarge => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, @@ -820,8 +865,8 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { _OutlinedIconButtonDefaultsM3E( this.context, this.toggleable, - ButtonSize? sizeVariant, - IconButtonWidth? iconButtonWidth, + ButtonSizeVariant? sizeVariant, + IconButtonWidthVariant? iconButtonWidth, ButtonShapeVariant? shapeVariant, ) : _sizeVariant = sizeVariant, _iconButtonWidth = iconButtonWidth, @@ -834,17 +879,17 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { final BuildContext context; final bool toggleable; - final ButtonSize? _sizeVariant; - final IconButtonWidth? _iconButtonWidth; + final ButtonSizeVariant? _sizeVariant; + final IconButtonWidthVariant? _iconButtonWidth; final ButtonShapeVariant? _shapeVariant; late final ColorScheme _colors = Theme.of(context).colorScheme; @override - ButtonSize get sizeVariant => _sizeVariant ?? ButtonSize.small; + ButtonSizeVariant get sizeVariant => _sizeVariant ?? ButtonSizeVariant.small; @override - IconButtonWidth get iconButtonWidth => _iconButtonWidth ?? IconButtonWidth.standard; + IconButtonWidthVariant get iconButtonWidth => _iconButtonWidth ?? IconButtonWidthVariant.standard; @override ButtonShapeVariant get shapeVariant => _shapeVariant ?? ButtonShapeVariant.round; @@ -914,62 +959,77 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { const MaterialStatePropertyAll(Colors.transparent); @override - WidgetStateProperty? get padding => - MaterialStatePropertyAll(switch (sizeVariant) { - ButtonSize.xSmall => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), - }, - ButtonSize.small => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), - }, - ButtonSize.medium => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(16.0, 16.0, 16.0, 16.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), - }, - ButtonSize.large => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(32.0, 32.0, 32.0, 32.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), - }, - ButtonSize.xLarge => switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB(48.0, 48.0, 48.0, 48.0), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), - }, - }); + WidgetStateProperty? + get padding => MaterialStatePropertyAll(switch (sizeVariant) { + ButtonSizeVariant.xSmall => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 6.0, 4.0, 6.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB(6.0, 6.0, 6.0, 6.0), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(10.0, 6.0, 10.0, 6.0), + }, + ButtonSizeVariant.small => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(4.0, 8.0, 4.0, 8.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB(8.0, 8.0, 8.0, 8.0), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(14.0, 8.0, 14.0, 8.0), + }, + ButtonSizeVariant.medium => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(12.0, 16.0, 12.0, 16.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB( + 16.0, + 16.0, + 16.0, + 16.0, + ), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(24.0, 16.0, 24.0, 16.0), + }, + ButtonSizeVariant.large => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(16.0, 32.0, 16.0, 32.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB( + 32.0, + 32.0, + 32.0, + 32.0, + ), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(48.0, 32.0, 48.0, 32.0), + }, + ButtonSizeVariant.xLarge => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB(32.0, 48.0, 32.0, 48.0), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB( + 48.0, + 48.0, + 48.0, + 48.0, + ), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB(72.0, 48.0, 72.0, 48.0), + }, + }); @override WidgetStateProperty? get minimumSize => MaterialStatePropertyAll(switch (sizeVariant) { - ButtonSize.xSmall => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(28.0, 32.0), - IconButtonWidth.standard => const Size(32.0, 32.0), - IconButtonWidth.wide => const Size(40.0, 32.0), + ButtonSizeVariant.xSmall => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(28.0, 32.0), + IconButtonWidthVariant.standard => const Size(32.0, 32.0), + IconButtonWidthVariant.wide => const Size(40.0, 32.0), }, - ButtonSize.small => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(32.0, 40.0), - IconButtonWidth.standard => const Size(40.0, 40.0), - IconButtonWidth.wide => const Size(52.0, 40.0), + ButtonSizeVariant.small => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(32.0, 40.0), + IconButtonWidthVariant.standard => const Size(40.0, 40.0), + IconButtonWidthVariant.wide => const Size(52.0, 40.0), }, - ButtonSize.medium => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(48.0, 56.0), - IconButtonWidth.standard => const Size(56.0, 56.0), - IconButtonWidth.wide => const Size(72.0, 56.0), + ButtonSizeVariant.medium => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(48.0, 56.0), + IconButtonWidthVariant.standard => const Size(56.0, 56.0), + IconButtonWidthVariant.wide => const Size(72.0, 56.0), }, - ButtonSize.large => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(64.0, 96.0), - IconButtonWidth.standard => const Size(96.0, 96.0), - IconButtonWidth.wide => const Size(128.0, 96.0), + ButtonSizeVariant.large => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(64.0, 96.0), + IconButtonWidthVariant.standard => const Size(96.0, 96.0), + IconButtonWidthVariant.wide => const Size(128.0, 96.0), }, - ButtonSize.xLarge => switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(104.0, 136.0), - IconButtonWidth.standard => const Size(136.0, 136.0), - IconButtonWidth.wide => const Size(184.0, 136.0), + ButtonSizeVariant.xLarge => switch (iconButtonWidth) { + IconButtonWidthVariant.narrow => const Size(104.0, 136.0), + IconButtonWidthVariant.standard => const Size(136.0, 136.0), + IconButtonWidthVariant.wide => const Size(184.0, 136.0), }, }); @@ -979,11 +1039,11 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { @override WidgetStateProperty? get iconSize => MaterialStatePropertyAll(switch (sizeVariant) { - ButtonSize.xSmall => 20.0, - ButtonSize.small => 24.0, - ButtonSize.medium => 24.0, - ButtonSize.large => 32.0, - ButtonSize.xLarge => 40.0, + ButtonSizeVariant.xSmall => 20.0, + ButtonSizeVariant.small => 24.0, + ButtonSizeVariant.medium => 24.0, + ButtonSizeVariant.large => 32.0, + ButtonSizeVariant.xLarge => 40.0, }); @override @@ -991,19 +1051,19 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { WidgetStateProperty.resolveWith((Set states) { if (states.contains(WidgetState.pressed)) { return switch (sizeVariant) { - ButtonSize.xSmall => const RoundedRectangleBorder( + ButtonSizeVariant.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), - ButtonSize.small => const RoundedRectangleBorder( + ButtonSizeVariant.small => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), - ButtonSize.medium => const RoundedRectangleBorder( + ButtonSizeVariant.medium => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.large => const RoundedRectangleBorder( + ButtonSizeVariant.large => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16.0)), ), - ButtonSize.xLarge => const RoundedRectangleBorder( + ButtonSizeVariant.xLarge => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16.0)), ), }; @@ -1011,53 +1071,53 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { if (toggleable && states.contains(WidgetState.selected)) { return switch (shapeVariant) { ButtonShapeVariant.round => switch (sizeVariant) { - ButtonSize.xSmall => const RoundedRectangleBorder( + ButtonSizeVariant.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.small => const RoundedRectangleBorder( + ButtonSizeVariant.small => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.medium => const RoundedRectangleBorder( + ButtonSizeVariant.medium => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16.0)), ), - ButtonSize.large => const RoundedRectangleBorder( + ButtonSizeVariant.large => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(28.0)), ), - ButtonSize.xLarge => const RoundedRectangleBorder( + ButtonSizeVariant.xLarge => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, ButtonShapeVariant.square => switch (sizeVariant) { - ButtonSize.xSmall => const StadiumBorder(), - ButtonSize.small => const StadiumBorder(), - ButtonSize.medium => const StadiumBorder(), - ButtonSize.large => const StadiumBorder(), - ButtonSize.xLarge => const StadiumBorder(), + ButtonSizeVariant.xSmall => const StadiumBorder(), + ButtonSizeVariant.small => const StadiumBorder(), + ButtonSizeVariant.medium => const StadiumBorder(), + ButtonSizeVariant.large => const StadiumBorder(), + ButtonSizeVariant.xLarge => const StadiumBorder(), }, }; } return switch (shapeVariant) { ButtonShapeVariant.round => switch (sizeVariant) { - ButtonSize.xSmall => const StadiumBorder(), - ButtonSize.small => const StadiumBorder(), - ButtonSize.medium => const StadiumBorder(), - ButtonSize.large => const StadiumBorder(), - ButtonSize.xLarge => const StadiumBorder(), + ButtonSizeVariant.xSmall => const StadiumBorder(), + ButtonSizeVariant.small => const StadiumBorder(), + ButtonSizeVariant.medium => const StadiumBorder(), + ButtonSizeVariant.large => const StadiumBorder(), + ButtonSizeVariant.xLarge => const StadiumBorder(), }, ButtonShapeVariant.square => switch (sizeVariant) { - ButtonSize.xSmall => const RoundedRectangleBorder( + ButtonSizeVariant.xSmall => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.small => const RoundedRectangleBorder( + ButtonSizeVariant.small => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(12.0)), ), - ButtonSize.medium => const RoundedRectangleBorder( + ButtonSizeVariant.medium => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16.0)), ), - ButtonSize.large => const RoundedRectangleBorder( + ButtonSizeVariant.large => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(28.0)), ), - ButtonSize.xLarge => const RoundedRectangleBorder( + ButtonSizeVariant.xLarge => const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(28.0)), ), }, @@ -1074,22 +1134,22 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { return BorderSide( color: _colors.outlineVariant, width: switch (sizeVariant) { - ButtonSize.xSmall => 1.0, - ButtonSize.small => 1.0, - ButtonSize.medium => 1.0, - ButtonSize.large => 2.0, - ButtonSize.xLarge => 3.0, + ButtonSizeVariant.xSmall => 1.0, + ButtonSizeVariant.small => 1.0, + ButtonSizeVariant.medium => 1.0, + ButtonSizeVariant.large => 2.0, + ButtonSizeVariant.xLarge => 3.0, }, ); } return BorderSide( color: _colors.outlineVariant, width: switch (sizeVariant) { - ButtonSize.xSmall => 1.0, - ButtonSize.small => 1.0, - ButtonSize.medium => 1.0, - ButtonSize.large => 2.0, - ButtonSize.xLarge => 3.0, + ButtonSizeVariant.xSmall => 1.0, + ButtonSizeVariant.small => 1.0, + ButtonSizeVariant.medium => 1.0, + ButtonSizeVariant.large => 2.0, + ButtonSizeVariant.xLarge => 3.0, }, ); }); diff --git a/packages/material_ui/lib/src/icon_button.dart b/packages/material_ui/lib/src/icon_button.dart index b274ef161b49..339ba89b113f 100644 --- a/packages/material_ui/lib/src/icon_button.dart +++ b/packages/material_ui/lib/src/icon_button.dart @@ -636,7 +636,7 @@ class IconButton extends StatelessWidget { /// /// When [IconButtonThemeData.variant] is [StyleVariant.material3Expressive], /// and these properties are null, Material 3 Expressive [IconButton] defaults - /// use [ButtonSize.small], [IconButtonWidth.standard], and + /// use [ButtonSizeVariant.small], [IconButtonWidthVariant.standard], and /// [ButtonShapeVariant.round]. /// /// All parameters default to null, by default this method returns @@ -683,8 +683,8 @@ class IconButton extends StatelessWidget { bool? enableFeedback, AlignmentGeometry? alignment, InteractiveInkFeatureFactory? splashFactory, - ButtonSize? sizeVariant, - IconButtonWidth? iconButtonWidth, + ButtonSizeVariant? sizeVariant, + IconButtonWidthVariant? iconButtonWidth, ButtonShapeVariant? shapeVariant, }) { final Color? overlayFallback = overlayColor ?? foregroundColor; @@ -1081,14 +1081,15 @@ class _IconButtonM3 extends ButtonStyleButton { /// * `enableFeedback` - true /// * `alignment` - Alignment.center /// * `splashFactory` - Theme.splashFactory - /// * `sizeVariant` - ButtonSize.small - /// * `iconButtonWidth` - IconButtonWidth.standard + /// * `sizeVariant` - ButtonSizeVariant.small + /// * `iconButtonWidth` - IconButtonWidthVariant.standard /// * `shapeVariant` - ButtonShapeVariant.round @override ButtonStyle defaultStyleOf(BuildContext context) { final ButtonStyle? iconButtonThemeStyle = IconButtonTheme.of(context).style; - final ButtonSize? effectiveSize = style?.sizeVariant ?? iconButtonThemeStyle?.sizeVariant; - final IconButtonWidth? effectiveWidth = + final ButtonSizeVariant? effectiveSize = + style?.sizeVariant ?? iconButtonThemeStyle?.sizeVariant; + final IconButtonWidthVariant? effectiveWidth = style?.iconButtonWidth ?? iconButtonThemeStyle?.iconButtonWidth; final ButtonShapeVariant? effectiveShape = style?.shapeVariant ?? iconButtonThemeStyle?.shapeVariant; diff --git a/packages/material_ui/test/icon_button_test.dart b/packages/material_ui/test/icon_button_test.dart index ea349b5545d5..f7dd98739688 100644 --- a/packages/material_ui/test/icon_button_test.dart +++ b/packages/material_ui/test/icon_button_test.dart @@ -3629,7 +3629,7 @@ void main() { pressCount += 1; }, icon: const Icon(Icons.add), - style: const ButtonStyle(sizeVariant: ButtonSize.xSmall), + style: const ButtonStyle(sizeVariant: ButtonSizeVariant.xSmall), ), ), ); @@ -3664,7 +3664,7 @@ void main() { child: IconButton( onPressed: () {}, icon: const Icon(Icons.add), - style: const ButtonStyle(sizeVariant: ButtonSize.xSmall), + style: const ButtonStyle(sizeVariant: ButtonSizeVariant.xSmall), ), ), ); @@ -3679,7 +3679,7 @@ void main() { child: IconButton( onPressed: () {}, icon: const Icon(Icons.add), - style: IconButton.styleFrom(sizeVariant: ButtonSize.medium), + style: IconButton.styleFrom(sizeVariant: ButtonSizeVariant.medium), ), ), ); @@ -3694,7 +3694,7 @@ void main() { child: IconButton( onPressed: () {}, icon: const Icon(Icons.add), - style: const ButtonStyle(sizeVariant: ButtonSize.medium), + style: const ButtonStyle(sizeVariant: ButtonSizeVariant.medium), ), ), ); @@ -3709,7 +3709,7 @@ void main() { child: IconButton( onPressed: () {}, icon: const Icon(Icons.add), - style: const ButtonStyle(sizeVariant: ButtonSize.large), + style: const ButtonStyle(sizeVariant: ButtonSizeVariant.large), ), ), ); @@ -3724,7 +3724,7 @@ void main() { child: IconButton( onPressed: () {}, icon: const Icon(Icons.add), - style: const ButtonStyle(sizeVariant: ButtonSize.xLarge), + style: const ButtonStyle(sizeVariant: ButtonSizeVariant.xLarge), ), ), ); @@ -3738,7 +3738,7 @@ void main() { testWidgets('small IconButton supports narrow, standard, and wide widths', ( WidgetTester tester, ) async { - Future materialSizeFor(IconButtonWidth width) async { + Future materialSizeFor(IconButtonWidthVariant width) async { await tester.pumpWidget( buildM3EApp( child: IconButton( @@ -3751,9 +3751,9 @@ void main() { return m3eIconButtonMaterialSize(tester); } - expect(await materialSizeFor(IconButtonWidth.narrow), const Size(32.0, 40.0)); - expect(await materialSizeFor(IconButtonWidth.standard), const Size(40.0, 40.0)); - expect(await materialSizeFor(IconButtonWidth.wide), const Size(52.0, 40.0)); + expect(await materialSizeFor(IconButtonWidthVariant.narrow), const Size(32.0, 40.0)); + expect(await materialSizeFor(IconButtonWidthVariant.standard), const Size(40.0, 40.0)); + expect(await materialSizeFor(IconButtonWidthVariant.wide), const Size(52.0, 40.0)); expect(m3eIconButtonMaterial(tester).animationDuration, kThemeChangeDuration); }); @@ -3764,7 +3764,7 @@ void main() { theme: ThemeData( useMaterial3: true, iconButtonTheme: const IconButtonThemeData( - style: ButtonStyle(iconButtonWidth: IconButtonWidth.wide), + style: ButtonStyle(iconButtonWidth: IconButtonWidthVariant.wide), variant: StyleVariant.material3Expressive, ), ), @@ -3821,7 +3821,7 @@ void main() { onPressed: () {}, icon: const Icon(Icons.add), style: const ButtonStyle( - sizeVariant: ButtonSize.medium, + sizeVariant: ButtonSizeVariant.medium, shapeVariant: ButtonShapeVariant.square, ), ), @@ -3850,7 +3850,7 @@ void main() { onPressed: () {}, icon: const Icon(Icons.add), style: const ButtonStyle( - sizeVariant: ButtonSize.medium, + sizeVariant: ButtonSizeVariant.medium, shapeVariant: ButtonShapeVariant.square, ), ), @@ -3955,7 +3955,7 @@ void main() { child: IconButton.filled( onPressed: () {}, icon: const Icon(Icons.add), - style: const ButtonStyle(sizeVariant: ButtonSize.large), + style: const ButtonStyle(sizeVariant: ButtonSizeVariant.large), ), ), ); @@ -3970,7 +3970,7 @@ void main() { child: IconButton.outlined( onPressed: () {}, icon: const Icon(Icons.add), - style: const ButtonStyle(sizeVariant: ButtonSize.medium), + style: const ButtonStyle(sizeVariant: ButtonSizeVariant.medium), ), ), ); @@ -3987,7 +3987,7 @@ void main() { theme: ThemeData( useMaterial3: true, iconButtonTheme: const IconButtonThemeData( - style: ButtonStyle(sizeVariant: ButtonSize.large), + style: ButtonStyle(sizeVariant: ButtonSizeVariant.large), variant: StyleVariant.material3Expressive, ), ), @@ -4005,14 +4005,14 @@ void main() { theme: ThemeData( useMaterial3: true, iconButtonTheme: const IconButtonThemeData( - style: ButtonStyle(sizeVariant: ButtonSize.large), + style: ButtonStyle(sizeVariant: ButtonSizeVariant.large), variant: StyleVariant.material3Expressive, ), ), child: IconButton( onPressed: () {}, icon: const Icon(Icons.add), - style: const ButtonStyle(sizeVariant: ButtonSize.xSmall), + style: const ButtonStyle(sizeVariant: ButtonSizeVariant.xSmall), ), ), ); @@ -4026,7 +4026,7 @@ void main() { buildM3EApp( child: IconButtonTheme( data: const IconButtonThemeData( - style: ButtonStyle(sizeVariant: ButtonSize.medium), + style: ButtonStyle(sizeVariant: ButtonSizeVariant.medium), variant: StyleVariant.material3Expressive, ), child: IconButton(onPressed: () {}, icon: const Icon(Icons.add)), @@ -4238,22 +4238,22 @@ void main() { test('equality', () { const a = IconButtonThemeData( style: ButtonStyle( - sizeVariant: ButtonSize.small, - iconButtonWidth: IconButtonWidth.standard, + sizeVariant: ButtonSizeVariant.small, + iconButtonWidth: IconButtonWidthVariant.standard, shapeVariant: ButtonShapeVariant.round, ), ); const b = IconButtonThemeData( style: ButtonStyle( - sizeVariant: ButtonSize.small, - iconButtonWidth: IconButtonWidth.standard, + sizeVariant: ButtonSizeVariant.small, + iconButtonWidth: IconButtonWidthVariant.standard, shapeVariant: ButtonShapeVariant.round, ), ); const c = IconButtonThemeData( style: ButtonStyle( - sizeVariant: ButtonSize.large, - iconButtonWidth: IconButtonWidth.wide, + sizeVariant: ButtonSizeVariant.large, + iconButtonWidth: IconButtonWidthVariant.wide, shapeVariant: ButtonShapeVariant.square, ), ); @@ -4265,15 +4265,15 @@ void main() { test('hashCode', () { const a = IconButtonThemeData( style: ButtonStyle( - sizeVariant: ButtonSize.small, - iconButtonWidth: IconButtonWidth.narrow, + sizeVariant: ButtonSizeVariant.small, + iconButtonWidth: IconButtonWidthVariant.narrow, shapeVariant: ButtonShapeVariant.round, ), ); const b = IconButtonThemeData( style: ButtonStyle( - sizeVariant: ButtonSize.small, - iconButtonWidth: IconButtonWidth.narrow, + sizeVariant: ButtonSizeVariant.small, + iconButtonWidth: IconButtonWidthVariant.narrow, shapeVariant: ButtonShapeVariant.round, ), ); @@ -4284,25 +4284,31 @@ void main() { test('lerp', () { const a = IconButtonThemeData( style: ButtonStyle( - sizeVariant: ButtonSize.small, - iconButtonWidth: IconButtonWidth.narrow, + sizeVariant: ButtonSizeVariant.small, + iconButtonWidth: IconButtonWidthVariant.narrow, shapeVariant: ButtonShapeVariant.round, ), ); const b = IconButtonThemeData( style: ButtonStyle( - sizeVariant: ButtonSize.large, - iconButtonWidth: IconButtonWidth.wide, + sizeVariant: ButtonSizeVariant.large, + iconButtonWidth: IconButtonWidthVariant.wide, shapeVariant: ButtonShapeVariant.square, ), ); - expect(IconButtonThemeData.lerp(a, b, 0.0)?.style?.sizeVariant, ButtonSize.small); - expect(IconButtonThemeData.lerp(a, b, 0.4)?.style?.sizeVariant, ButtonSize.small); - expect(IconButtonThemeData.lerp(a, b, 0.5)?.style?.sizeVariant, ButtonSize.large); - expect(IconButtonThemeData.lerp(a, b, 1.0)?.style?.sizeVariant, ButtonSize.large); - expect(IconButtonThemeData.lerp(a, b, 0.4)?.style?.iconButtonWidth, IconButtonWidth.narrow); - expect(IconButtonThemeData.lerp(a, b, 0.5)?.style?.iconButtonWidth, IconButtonWidth.wide); + expect(IconButtonThemeData.lerp(a, b, 0.0)?.style?.sizeVariant, ButtonSizeVariant.small); + expect(IconButtonThemeData.lerp(a, b, 0.4)?.style?.sizeVariant, ButtonSizeVariant.small); + expect(IconButtonThemeData.lerp(a, b, 0.5)?.style?.sizeVariant, ButtonSizeVariant.large); + expect(IconButtonThemeData.lerp(a, b, 1.0)?.style?.sizeVariant, ButtonSizeVariant.large); + expect( + IconButtonThemeData.lerp(a, b, 0.4)?.style?.iconButtonWidth, + IconButtonWidthVariant.narrow, + ); + expect( + IconButtonThemeData.lerp(a, b, 0.5)?.style?.iconButtonWidth, + IconButtonWidthVariant.wide, + ); expect(IconButtonThemeData.lerp(a, b, 0.4)?.style?.shapeVariant, ButtonShapeVariant.round); expect(IconButtonThemeData.lerp(a, b, 0.5)?.style?.shapeVariant, ButtonShapeVariant.square); }); @@ -4310,8 +4316,8 @@ void main() { test('debugFillProperties includes size variant, width, and shape variant', () { const data = IconButtonThemeData( style: ButtonStyle( - sizeVariant: ButtonSize.medium, - iconButtonWidth: IconButtonWidth.wide, + sizeVariant: ButtonSizeVariant.medium, + iconButtonWidth: IconButtonWidthVariant.wide, shapeVariant: ButtonShapeVariant.square, ), ); @@ -4336,7 +4342,7 @@ void main() { child: IconButton( onPressed: () {}, icon: const Icon(Icons.add), - style: const ButtonStyle(sizeVariant: ButtonSize.medium), + style: const ButtonStyle(sizeVariant: ButtonSizeVariant.medium), ), ), ); diff --git a/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart b/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart index b8e5ed93347e..1f9afd190373 100644 --- a/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart +++ b/packages/material_ui/tool/gen_defaults/templates/icon_button_template.dart @@ -57,11 +57,11 @@ ${_generateOutlinedDefaults()} }) { return ''' switch (sizeVariant) { - ButtonSize.xSmall => $xSmall, - ButtonSize.small => $small, - ButtonSize.medium => $medium, - ButtonSize.large => $large, - ButtonSize.xLarge => $xLarge, + ButtonSizeVariant.xSmall => $xSmall, + ButtonSizeVariant.small => $small, + ButtonSizeVariant.medium => $medium, + ButtonSizeVariant.large => $large, + ButtonSizeVariant.xLarge => $xLarge, }'''; } @@ -120,9 +120,9 @@ switch (sizeVariant) { }) { return ''' switch (iconButtonWidth) { - IconButtonWidth.narrow => const EdgeInsetsDirectional.fromSTEB($narrowLeading, $defaultLeading, $narrowTrailing, $defaultTrailing), - IconButtonWidth.standard => const EdgeInsetsDirectional.fromSTEB($defaultLeading, $defaultLeading, $defaultTrailing, $defaultTrailing), - IconButtonWidth.wide => const EdgeInsetsDirectional.fromSTEB($wideLeading, $defaultLeading, $wideTrailing, $defaultTrailing), + IconButtonWidthVariant.narrow => const EdgeInsetsDirectional.fromSTEB($narrowLeading, $defaultLeading, $narrowTrailing, $defaultTrailing), + IconButtonWidthVariant.standard => const EdgeInsetsDirectional.fromSTEB($defaultLeading, $defaultLeading, $defaultTrailing, $defaultTrailing), + IconButtonWidthVariant.wide => const EdgeInsetsDirectional.fromSTEB($wideLeading, $defaultLeading, $wideTrailing, $defaultTrailing), }'''; } @@ -193,9 +193,9 @@ switch (iconButtonWidth) { }) { return ''' switch (iconButtonWidth) { - IconButtonWidth.narrow => const Size(${iconSize + narrowLeading + narrowTrailing}, $height), - IconButtonWidth.standard => const Size(${iconSize + defaultLeading + defaultTrailing}, $height), - IconButtonWidth.wide => const Size(${iconSize + wideLeading + wideTrailing}, $height), + IconButtonWidthVariant.narrow => const Size(${iconSize + narrowLeading + narrowTrailing}, $height), + IconButtonWidthVariant.standard => const Size(${iconSize + defaultLeading + defaultTrailing}, $height), + IconButtonWidthVariant.wide => const Size(${iconSize + wideLeading + wideTrailing}, $height), }'''; } @@ -287,8 +287,8 @@ switch (shapeVariant) { String get _variantFields { return ''' - final ButtonSize? _sizeVariant; - final IconButtonWidth? _iconButtonWidth; + final ButtonSizeVariant? _sizeVariant; + final IconButtonWidthVariant? _iconButtonWidth; final ButtonShapeVariant? _shapeVariant; '''; } @@ -296,10 +296,10 @@ switch (shapeVariant) { String get _variantGetters { return ''' @override - ButtonSize get sizeVariant => _sizeVariant ?? ButtonSize.small; + ButtonSizeVariant get sizeVariant => _sizeVariant ?? ButtonSizeVariant.small; @override - IconButtonWidth get iconButtonWidth => _iconButtonWidth ?? IconButtonWidth.standard; + IconButtonWidthVariant get iconButtonWidth => _iconButtonWidth ?? IconButtonWidthVariant.standard; @override ButtonShapeVariant get shapeVariant => _shapeVariant ?? ButtonShapeVariant.round; @@ -344,8 +344,8 @@ class $className extends ButtonStyle { $className( this.context, this.toggleable, - ButtonSize? sizeVariant, - IconButtonWidth? iconButtonWidth, + ButtonSizeVariant? sizeVariant, + IconButtonWidthVariant? iconButtonWidth, ButtonShapeVariant? shapeVariant, ) : _sizeVariant = sizeVariant, _iconButtonWidth = iconButtonWidth, @@ -443,8 +443,8 @@ class _FilledIconButtonDefaultsM3E extends ButtonStyle { _FilledIconButtonDefaultsM3E( this.context, this.toggleable, - ButtonSize? sizeVariant, - IconButtonWidth? iconButtonWidth, + ButtonSizeVariant? sizeVariant, + IconButtonWidthVariant? iconButtonWidth, ButtonShapeVariant? shapeVariant, ) : _sizeVariant = sizeVariant, _iconButtonWidth = iconButtonWidth, @@ -567,8 +567,8 @@ class _FilledTonalIconButtonDefaultsM3E extends ButtonStyle { _FilledTonalIconButtonDefaultsM3E( this.context, this.toggleable, - ButtonSize? sizeVariant, - IconButtonWidth? iconButtonWidth, + ButtonSizeVariant? sizeVariant, + IconButtonWidthVariant? iconButtonWidth, ButtonShapeVariant? shapeVariant, ) : _sizeVariant = sizeVariant, _iconButtonWidth = iconButtonWidth, @@ -691,8 +691,8 @@ class _OutlinedIconButtonDefaultsM3E extends ButtonStyle { _OutlinedIconButtonDefaultsM3E( this.context, this.toggleable, - ButtonSize? sizeVariant, - IconButtonWidth? iconButtonWidth, + ButtonSizeVariant? sizeVariant, + IconButtonWidthVariant? iconButtonWidth, ButtonShapeVariant? shapeVariant, ) : _sizeVariant = sizeVariant, _iconButtonWidth = iconButtonWidth, From a6f0d802b532049029159012727571840acf1e53 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 21:35:09 -0700 Subject: [PATCH 25/31] Clarify IconButton M3 defaults docs --- packages/material_ui/lib/src/icon_button.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/material_ui/lib/src/icon_button.dart b/packages/material_ui/lib/src/icon_button.dart index 339ba89b113f..91ac52e42258 100644 --- a/packages/material_ui/lib/src/icon_button.dart +++ b/packages/material_ui/lib/src/icon_button.dart @@ -1005,10 +1005,11 @@ class _IconButtonM3 extends ButtonStyleButton { final StyleVariant styleVariant; final bool toggleable; + // TODO(quncCccccc): Clean up [ThemeData.useMaterial3] once useMaterial3 is deprecated. /// ## Material 3 defaults /// /// If [ThemeData.useMaterial3] is true and [IconButtonThemeData.variant] is - /// not [StyleVariant.material3Expressive], the following defaults will be + /// [StyleVariant.material3], the following defaults will be /// used: /// /// * `textStyle` - null From 4c51797a3f073e3af3ced0900ad797c2e1caefe5 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 21:38:09 -0700 Subject: [PATCH 26/31] Move IconButton useMaterial3 TODO --- packages/material_ui/lib/src/icon_button.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/material_ui/lib/src/icon_button.dart b/packages/material_ui/lib/src/icon_button.dart index 91ac52e42258..d4b48314c1aa 100644 --- a/packages/material_ui/lib/src/icon_button.dart +++ b/packages/material_ui/lib/src/icon_button.dart @@ -1005,9 +1005,9 @@ class _IconButtonM3 extends ButtonStyleButton { final StyleVariant styleVariant; final bool toggleable; - // TODO(quncCccccc): Clean up [ThemeData.useMaterial3] once useMaterial3 is deprecated. /// ## Material 3 defaults /// + // TODO(quncCccccc): Clean up [ThemeData.useMaterial3] once useMaterial3 is deprecated. /// If [ThemeData.useMaterial3] is true and [IconButtonThemeData.variant] is /// [StyleVariant.material3], the following defaults will be /// used: From 85baafd92d631a99d1531010a62ceef1e2e7f62e Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 21:43:01 -0700 Subject: [PATCH 27/31] Simplify IconButton variant docs --- packages/material_ui/lib/src/icon_button_theme.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/material_ui/lib/src/icon_button_theme.dart b/packages/material_ui/lib/src/icon_button_theme.dart index b231d0c8c705..1d5905b74cf0 100644 --- a/packages/material_ui/lib/src/icon_button_theme.dart +++ b/packages/material_ui/lib/src/icon_button_theme.dart @@ -54,9 +54,7 @@ class IconButtonThemeData with Diagnosticable { /// The style variant of Material Design used by [IconButton]. /// /// Set this to [StyleVariant.material3Expressive] to opt icon buttons into - /// the Material 3 Expressive defaults. These defaults include the Material 3 - /// Expressive size, width, and shape tokens, and use - /// [MaterialTapTargetSize.padded] for the default tap target size. + /// the Material 3 Expressive style. /// /// If null, [IconButton] uses [StyleVariant.material3]. final StyleVariant? variant; From a772118d355da1dcea70afaddd9ad4285ac75f0d Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 21:51:39 -0700 Subject: [PATCH 28/31] Clean up IconButton M3E tests --- packages/material_ui/test/icon_button_test.dart | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/material_ui/test/icon_button_test.dart b/packages/material_ui/test/icon_button_test.dart index f7dd98739688..5b38f9421f8f 100644 --- a/packages/material_ui/test/icon_button_test.dart +++ b/packages/material_ui/test/icon_button_test.dart @@ -3577,7 +3577,6 @@ void main() { theme: theme ?? ThemeData( - useMaterial3: true, iconButtonTheme: const IconButtonThemeData(variant: StyleVariant.material3Expressive), ), home: Scaffold(body: Center(child: child)), @@ -3657,7 +3656,6 @@ void main() { await tester.pumpWidget( buildM3EApp( theme: ThemeData( - useMaterial3: true, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, iconButtonTheme: const IconButtonThemeData(variant: StyleVariant.material3Expressive), ), @@ -3762,7 +3760,6 @@ void main() { await tester.pumpWidget( buildM3EApp( theme: ThemeData( - useMaterial3: true, iconButtonTheme: const IconButtonThemeData( style: ButtonStyle(iconButtonWidth: IconButtonWidthVariant.wide), variant: StyleVariant.material3Expressive, @@ -3985,7 +3982,6 @@ void main() { await tester.pumpWidget( buildM3EApp( theme: ThemeData( - useMaterial3: true, iconButtonTheme: const IconButtonThemeData( style: ButtonStyle(sizeVariant: ButtonSizeVariant.large), variant: StyleVariant.material3Expressive, @@ -4003,7 +3999,6 @@ void main() { await tester.pumpWidget( buildM3EApp( theme: ThemeData( - useMaterial3: true, iconButtonTheme: const IconButtonThemeData( style: ButtonStyle(sizeVariant: ButtonSizeVariant.large), variant: StyleVariant.material3Expressive, From ba4d52b74dc589fa9ef36157580b21a8c4c34967 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 21:58:38 -0700 Subject: [PATCH 29/31] Apply M3E test theme defaults --- .../material_ui/test/icon_button_test.dart | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/packages/material_ui/test/icon_button_test.dart b/packages/material_ui/test/icon_button_test.dart index 5b38f9421f8f..263fa8fca5ed 100644 --- a/packages/material_ui/test/icon_button_test.dart +++ b/packages/material_ui/test/icon_button_test.dart @@ -3573,12 +3573,15 @@ void main() { }); Widget buildM3EApp({required Widget child, ThemeData? theme}) { + final ThemeData effectiveTheme = theme ?? ThemeData(); + final IconButtonThemeData iconButtonTheme = effectiveTheme.iconButtonTheme; return MaterialApp( - theme: - theme ?? - ThemeData( - iconButtonTheme: const IconButtonThemeData(variant: StyleVariant.material3Expressive), - ), + theme: effectiveTheme.copyWith( + iconButtonTheme: IconButtonThemeData( + style: iconButtonTheme.style, + variant: iconButtonTheme.variant ?? StyleVariant.material3Expressive, + ), + ), home: Scaffold(body: Center(child: child)), ); } @@ -3655,10 +3658,7 @@ void main() { ) async { await tester.pumpWidget( buildM3EApp( - theme: ThemeData( - materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - iconButtonTheme: const IconButtonThemeData(variant: StyleVariant.material3Expressive), - ), + theme: ThemeData(materialTapTargetSize: MaterialTapTargetSize.shrinkWrap), child: IconButton( onPressed: () {}, icon: const Icon(Icons.add), @@ -3762,7 +3762,6 @@ void main() { theme: ThemeData( iconButtonTheme: const IconButtonThemeData( style: ButtonStyle(iconButtonWidth: IconButtonWidthVariant.wide), - variant: StyleVariant.material3Expressive, ), ), child: IconButton(onPressed: () {}, icon: const Icon(Icons.add)), @@ -3984,7 +3983,6 @@ void main() { theme: ThemeData( iconButtonTheme: const IconButtonThemeData( style: ButtonStyle(sizeVariant: ButtonSizeVariant.large), - variant: StyleVariant.material3Expressive, ), ), child: IconButton(onPressed: () {}, icon: const Icon(Icons.add)), @@ -4001,7 +3999,6 @@ void main() { theme: ThemeData( iconButtonTheme: const IconButtonThemeData( style: ButtonStyle(sizeVariant: ButtonSizeVariant.large), - variant: StyleVariant.material3Expressive, ), ), child: IconButton( From 388e74855a091705d7ce8266f0bf89e5a76ec730 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 22:03:05 -0700 Subject: [PATCH 30/31] Simplify IconButton M3E test helper --- .../material_ui/test/icon_button_test.dart | 34 +++++-------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/packages/material_ui/test/icon_button_test.dart b/packages/material_ui/test/icon_button_test.dart index 263fa8fca5ed..3b0bc7412d39 100644 --- a/packages/material_ui/test/icon_button_test.dart +++ b/packages/material_ui/test/icon_button_test.dart @@ -3573,15 +3573,12 @@ void main() { }); Widget buildM3EApp({required Widget child, ThemeData? theme}) { - final ThemeData effectiveTheme = theme ?? ThemeData(); - final IconButtonThemeData iconButtonTheme = effectiveTheme.iconButtonTheme; return MaterialApp( - theme: effectiveTheme.copyWith( - iconButtonTheme: IconButtonThemeData( - style: iconButtonTheme.style, - variant: iconButtonTheme.variant ?? StyleVariant.material3Expressive, - ), - ), + theme: + theme ?? + ThemeData( + iconButtonTheme: const IconButtonThemeData(variant: StyleVariant.material3Expressive), + ), home: Scaffold(body: Center(child: child)), ); } @@ -3653,24 +3650,6 @@ void main() { expect(pressCount, 4); }); - testWidgets('xSmall size keeps 48dp tap target when theme tapTargetSize is shrinkWrap', ( - WidgetTester tester, - ) async { - await tester.pumpWidget( - buildM3EApp( - theme: ThemeData(materialTapTargetSize: MaterialTapTargetSize.shrinkWrap), - child: IconButton( - onPressed: () {}, - icon: const Icon(Icons.add), - style: const ButtonStyle(sizeVariant: ButtonSizeVariant.xSmall), - ), - ), - ); - - expect(m3eIconButtonMaterialSize(tester), const Size(32.0, 32.0)); - expect(tester.getSize(find.byType(IconButton)), const Size(48.0, 48.0)); - }); - testWidgets('styleFrom sets the size variant', (WidgetTester tester) async { await tester.pumpWidget( buildM3EApp( @@ -3762,6 +3741,7 @@ void main() { theme: ThemeData( iconButtonTheme: const IconButtonThemeData( style: ButtonStyle(iconButtonWidth: IconButtonWidthVariant.wide), + variant: StyleVariant.material3Expressive, ), ), child: IconButton(onPressed: () {}, icon: const Icon(Icons.add)), @@ -3983,6 +3963,7 @@ void main() { theme: ThemeData( iconButtonTheme: const IconButtonThemeData( style: ButtonStyle(sizeVariant: ButtonSizeVariant.large), + variant: StyleVariant.material3Expressive, ), ), child: IconButton(onPressed: () {}, icon: const Icon(Icons.add)), @@ -3999,6 +3980,7 @@ void main() { theme: ThemeData( iconButtonTheme: const IconButtonThemeData( style: ButtonStyle(sizeVariant: ButtonSizeVariant.large), + variant: StyleVariant.material3Expressive, ), ), child: IconButton( From 54f53d38da55cecc2ac38039cb3b567c94a83001 Mon Sep 17 00:00:00 2001 From: Qun Cheng Date: Mon, 17 Aug 2026 22:07:30 -0700 Subject: [PATCH 31/31] Remove blank line after IconButton template import --- packages/material_ui/tool/gen_defaults/bin/gen_defaults.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/material_ui/tool/gen_defaults/bin/gen_defaults.dart b/packages/material_ui/tool/gen_defaults/bin/gen_defaults.dart index 1aa834d1f711..f11bbe98b87e 100644 --- a/packages/material_ui/tool/gen_defaults/bin/gen_defaults.dart +++ b/packages/material_ui/tool/gen_defaults/bin/gen_defaults.dart @@ -31,7 +31,6 @@ import '../templates/bottom_sheet_template.dart'; // import '../templates/fab_template.dart'; // import '../templates/filter_chip_template.dart'; import '../templates/icon_button_template.dart'; - // import '../templates/input_chip_template.dart'; // import '../templates/input_decorator_template.dart'; // import '../templates/list_tile_template.dart';