@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart';
66import 'package:flutter/rendering.dart' ;
77import 'package:flutter/widgets.dart' ;
88
9+ import 'color_scheme.dart' ;
910import 'constants.dart' ;
1011import 'debug.dart' ;
1112import 'divider.dart' ;
@@ -17,6 +18,7 @@ import 'material.dart';
1718import 'material_localizations.dart' ;
1819import 'material_state.dart' ;
1920import 'popup_menu_theme.dart' ;
21+ import 'text_theme.dart' ;
2022import 'theme.dart' ;
2123import 'tooltip.dart' ;
2224
@@ -224,6 +226,7 @@ class PopupMenuItem<T> extends PopupMenuEntry<T> {
224226 this .height = kMinInteractiveDimension,
225227 this .padding,
226228 this .textStyle,
229+ this .labelTextStyle,
227230 this .mouseCursor,
228231 required this .child,
229232 }) : assert (enabled != null ),
@@ -263,6 +266,16 @@ class PopupMenuItem<T> extends PopupMenuEntry<T> {
263266 /// of [ThemeData.textTheme] is used.
264267 final TextStyle ? textStyle;
265268
269+ /// The label style of the popup menu item.
270+ ///
271+ /// When [ThemeData.useMaterial3] is true, this styles the text of the popup menu item.
272+ ///
273+ /// If this property is null, then [PopupMenuThemeData.labelTextStyle] is used.
274+ /// If [PopupMenuThemeData.labelTextStyle] is also null, then [TextTheme.labelLarge]
275+ /// is used with the [ColorScheme.onSurface] color when popup menu item is enabled and
276+ /// the [ColorScheme.onSurface] color with 0.38 opacity when the popup menu item is disabled.
277+ final MaterialStateProperty <TextStyle ?>? labelTextStyle;
278+
266279 /// {@template flutter.material.popupmenu.mouseCursor}
267280 /// The cursor for a mouse pointer when it enters or is hovering over the
268281 /// widget.
@@ -336,9 +349,20 @@ class PopupMenuItemState<T, W extends PopupMenuItem<T>> extends State<W> {
336349 Widget build (BuildContext context) {
337350 final ThemeData theme = Theme .of (context);
338351 final PopupMenuThemeData popupMenuTheme = PopupMenuTheme .of (context);
339- TextStyle style = widget.textStyle ?? popupMenuTheme.textStyle ?? theme.textTheme.titleMedium! ;
340-
341- if (! widget.enabled) {
352+ final PopupMenuThemeData defaults = theme.useMaterial3 ? _PopupMenuDefaultsM3 (context) : _PopupMenuDefaultsM2 (context);
353+ final Set <MaterialState > states = < MaterialState > {
354+ if (! widget.enabled) MaterialState .disabled,
355+ };
356+
357+ TextStyle style = theme.useMaterial3
358+ ? (widget.labelTextStyle? .resolve (states)
359+ ?? popupMenuTheme.labelTextStyle? .resolve (states)!
360+ ?? defaults.labelTextStyle! .resolve (states)! )
361+ : (widget.textStyle
362+ ?? popupMenuTheme.textStyle
363+ ?? defaults.textStyle! );
364+
365+ if (! widget.enabled && ! theme.useMaterial3) {
342366 style = style.copyWith (color: theme.disabledColor);
343367 }
344368
@@ -537,7 +561,9 @@ class _PopupMenu<T> extends StatelessWidget {
537561 Widget build (BuildContext context) {
538562 final double unit = 1.0 / (route.items.length + 1.5 ); // 1.0 for the width and 0.5 for the last item's fade.
539563 final List <Widget > children = < Widget > [];
564+ final ThemeData theme = Theme .of (context);
540565 final PopupMenuThemeData popupMenuTheme = PopupMenuTheme .of (context);
566+ final PopupMenuThemeData defaults = theme.useMaterial3 ? _PopupMenuDefaultsM3 (context) : _PopupMenuDefaultsM2 (context);
541567
542568 for (int i = 0 ; i < route.items.length; i += 1 ) {
543569 final double start = (i + 1 ) * unit;
@@ -598,11 +624,13 @@ class _PopupMenu<T> extends StatelessWidget {
598624 return FadeTransition (
599625 opacity: opacity.animate (route.animation! ),
600626 child: Material (
601- shape: route.shape ?? popupMenuTheme.shape,
602- color: route.color ?? popupMenuTheme.color,
627+ shape: route.shape ?? popupMenuTheme.shape ?? defaults.shape ,
628+ color: route.color ?? popupMenuTheme.color ?? defaults.color ,
603629 clipBehavior: clipBehavior,
604630 type: MaterialType .card,
605- elevation: route.elevation ?? popupMenuTheme.elevation ?? 8.0 ,
631+ elevation: route.elevation ?? popupMenuTheme.elevation ?? defaults.elevation! ,
632+ shadowColor: route.shadowColor ?? popupMenuTheme.shadowColor ?? defaults.shadowColor,
633+ surfaceTintColor: route.surfaceTintColor ?? popupMenuTheme.surfaceTintColor ?? defaults.surfaceTintColor,
606634 child: Align (
607635 alignment: AlignmentDirectional .topEnd,
608636 widthFactor: width.evaluate (route.animation! ),
@@ -757,6 +785,8 @@ class _PopupMenuRoute<T> extends PopupRoute<T> {
757785 required this .items,
758786 this .initialValue,
759787 this .elevation,
788+ this .surfaceTintColor,
789+ this .shadowColor,
760790 required this .barrierLabel,
761791 this .semanticLabel,
762792 this .shape,
@@ -771,6 +801,8 @@ class _PopupMenuRoute<T> extends PopupRoute<T> {
771801 final List <Size ?> itemSizes;
772802 final T ? initialValue;
773803 final double ? elevation;
804+ final Color ? surfaceTintColor;
805+ final Color ? shadowColor;
774806 final String ? semanticLabel;
775807 final ShapeBorder ? shape;
776808 final Color ? color;
@@ -911,6 +943,8 @@ Future<T?> showMenu<T>({
911943 required List <PopupMenuEntry <T >> items,
912944 T ? initialValue,
913945 double ? elevation,
946+ Color ? shadowColor,
947+ Color ? surfaceTintColor,
914948 String ? semanticLabel,
915949 ShapeBorder ? shape,
916950 Color ? color,
@@ -941,6 +975,8 @@ Future<T?> showMenu<T>({
941975 items: items,
942976 initialValue: initialValue,
943977 elevation: elevation,
978+ shadowColor: shadowColor,
979+ surfaceTintColor: surfaceTintColor,
944980 semanticLabel: semanticLabel,
945981 barrierLabel: MaterialLocalizations .of (context).modalBarrierDismissLabel,
946982 shape: shape,
@@ -1006,6 +1042,8 @@ class PopupMenuButton<T> extends StatefulWidget {
10061042 this .onCanceled,
10071043 this .tooltip,
10081044 this .elevation,
1045+ this .shadowColor,
1046+ this .surfaceTintColor,
10091047 this .padding = const EdgeInsets .all (8.0 ),
10101048 this .child,
10111049 this .splashRadius,
@@ -1058,6 +1096,22 @@ class PopupMenuButton<T> extends StatefulWidget {
10581096 /// Defaults to 8, the appropriate elevation for popup menus.
10591097 final double ? elevation;
10601098
1099+ /// The color used to paint the shadow below the menu.
1100+ ///
1101+ /// If null then the ambient [PopupMenuThemeData.shadowColor] is used.
1102+ /// If that is null too, then the overall theme's [ThemeData.shadowColor]
1103+ /// (default black) is used.
1104+ final Color ? shadowColor;
1105+
1106+ /// The color used as an overlay on [color] to indicate elevation.
1107+ ///
1108+ /// If null, [PopupMenuThemeData.surfaceTintColor] is used. If that
1109+ /// is also null, the default value is [ColorScheme.surfaceTint] .
1110+ ///
1111+ /// See [Material.surfaceTintColor] for more details on how this
1112+ /// overlay is applied.
1113+ final Color ? surfaceTintColor;
1114+
10611115 /// Matches IconButton's 8 dps padding by default. In some cases, notably where
10621116 /// this button appears as the trailing element of a list item, it's useful to be able
10631117 /// to set the padding to zero.
@@ -1207,6 +1261,8 @@ class PopupMenuButtonState<T> extends State<PopupMenuButton<T>> {
12071261 showMenu <T ?>(
12081262 context: context,
12091263 elevation: widget.elevation ?? popupMenuTheme.elevation,
1264+ shadowColor: widget.shadowColor ?? popupMenuTheme.shadowColor,
1265+ surfaceTintColor: widget.surfaceTintColor ?? popupMenuTheme.surfaceTintColor,
12101266 items: items,
12111267 initialValue: widget.initialValue,
12121268 position: position,
@@ -1240,6 +1296,7 @@ class PopupMenuButtonState<T> extends State<PopupMenuButton<T>> {
12401296
12411297 @override
12421298 Widget build (BuildContext context) {
1299+ final IconThemeData iconTheme = IconTheme .of (context);
12431300 final bool enableFeedback = widget.enableFeedback
12441301 ?? PopupMenuTheme .of (context).enableFeedback
12451302 ?? true ;
@@ -1263,7 +1320,8 @@ class PopupMenuButtonState<T> extends State<PopupMenuButton<T>> {
12631320 icon: widget.icon ?? Icon (Icons .adaptive.more),
12641321 padding: widget.padding,
12651322 splashRadius: widget.splashRadius,
1266- iconSize: widget.iconSize,
1323+ iconSize: widget.iconSize ?? iconTheme.size,
1324+ color: widget.color ?? iconTheme.color,
12671325 tooltip: widget.tooltip ?? MaterialLocalizations .of (context).showMenuTooltip,
12681326 onPressed: widget.enabled ? showButtonMenu : null ,
12691327 enableFeedback: enableFeedback,
@@ -1290,3 +1348,57 @@ class _EffectiveMouseCursor extends MaterialStateMouseCursor {
12901348 @override
12911349 String get debugDescription => 'MaterialStateMouseCursor(PopupMenuItemState)' ;
12921350}
1351+
1352+ class _PopupMenuDefaultsM2 extends PopupMenuThemeData {
1353+ _PopupMenuDefaultsM2 (this .context)
1354+ : super (elevation: 8.0 );
1355+
1356+ final BuildContext context;
1357+ late final ThemeData _theme = Theme .of (context);
1358+ late final TextTheme _textTheme = _theme.textTheme;
1359+
1360+ @override
1361+ TextStyle ? get textStyle => _textTheme.subtitle1;
1362+ }
1363+
1364+ // BEGIN GENERATED TOKEN PROPERTIES - PopupMenu
1365+
1366+ // Do not edit by hand. The code between the "BEGIN GENERATED" and
1367+ // "END GENERATED" comments are generated from data in the Material
1368+ // Design token database by the script:
1369+ // dev/tools/gen_defaults/bin/gen_defaults.dart.
1370+
1371+ // Token database version: v0_132
1372+
1373+ class _PopupMenuDefaultsM3 extends PopupMenuThemeData {
1374+ _PopupMenuDefaultsM3 (this .context)
1375+ : super (elevation: 3.0 );
1376+
1377+ final BuildContext context;
1378+ late final ThemeData _theme = Theme .of (context);
1379+ late final ColorScheme _colors = _theme.colorScheme;
1380+ late final TextTheme _textTheme = _theme.textTheme;
1381+
1382+ @override MaterialStateProperty <TextStyle ?>? get labelTextStyle {
1383+ return MaterialStateProperty .resolveWith ((Set <MaterialState > states) {
1384+ final TextStyle style = _textTheme.labelLarge! ;
1385+ if (states.contains (MaterialState .disabled)) {
1386+ return style.apply (color: _colors.onSurface.withOpacity (0.38 ));
1387+ }
1388+ return style.apply (color: _colors.onSurface);
1389+ });
1390+ }
1391+
1392+ @override
1393+ Color ? get color => _colors.surface;
1394+
1395+ @override
1396+ Color ? get shadowColor => _colors.shadow;
1397+
1398+ @override
1399+ Color ? get surfaceTintColor => _colors.surfaceTint;
1400+
1401+ @override
1402+ ShapeBorder ? get shape => const RoundedRectangleBorder (borderRadius: BorderRadius .all (Radius .circular (4.0 )));
1403+ }
1404+ // END GENERATED TOKEN PROPERTIES - PopupMenu
0 commit comments