mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
268 lines
9.0 KiB
Dart
268 lines
9.0 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'template.dart';
|
|
|
|
class MenuTemplate extends TokenTemplate {
|
|
const MenuTemplate(super.blockName, super.fileName, super.tokens, {
|
|
super.colorSchemePrefix = '_colors.',
|
|
});
|
|
|
|
@override
|
|
String generate() => '''
|
|
class _MenuBarDefaultsM3 extends MenuStyle {
|
|
_MenuBarDefaultsM3(this.context)
|
|
: super(
|
|
elevation: const MaterialStatePropertyAll<double?>(${elevation('md.comp.menu.container')}),
|
|
shape: const MaterialStatePropertyAll<OutlinedBorder>(_defaultMenuBorder),
|
|
alignment: AlignmentDirectional.bottomStart,
|
|
);
|
|
|
|
static const RoundedRectangleBorder _defaultMenuBorder =
|
|
${shape('md.comp.menu.container', '')};
|
|
|
|
final BuildContext context;
|
|
|
|
late final ColorScheme _colors = Theme.of(context).colorScheme;
|
|
|
|
@override
|
|
MaterialStateProperty<Color?> get backgroundColor {
|
|
return MaterialStatePropertyAll<Color?>(${componentColor('md.comp.menu.container')});
|
|
}
|
|
|
|
@override
|
|
MaterialStateProperty<Color?>? get shadowColor {
|
|
return MaterialStatePropertyAll<Color?>(${color('md.comp.menu.container.shadow-color')});
|
|
}
|
|
|
|
@override
|
|
MaterialStateProperty<Color?>? get surfaceTintColor {
|
|
return const MaterialStatePropertyAll<Color?>(${colorOrTransparent('md.comp.menu.container.surface-tint-layer')});
|
|
}
|
|
|
|
@override
|
|
MaterialStateProperty<EdgeInsetsGeometry?>? get padding {
|
|
return const MaterialStatePropertyAll<EdgeInsetsGeometry>(
|
|
EdgeInsetsDirectional.symmetric(
|
|
horizontal: _kTopLevelMenuHorizontalMinPadding
|
|
),
|
|
);
|
|
}
|
|
|
|
@override
|
|
VisualDensity get visualDensity => Theme.of(context).visualDensity;
|
|
}
|
|
|
|
class _MenuButtonDefaultsM3 extends ButtonStyle {
|
|
_MenuButtonDefaultsM3(this.context)
|
|
: super(
|
|
animationDuration: kThemeChangeDuration,
|
|
enableFeedback: true,
|
|
alignment: AlignmentDirectional.centerStart,
|
|
);
|
|
|
|
final BuildContext context;
|
|
|
|
late final ColorScheme _colors = Theme.of(context).colorScheme;
|
|
late final TextTheme _textTheme = Theme.of(context).textTheme;
|
|
|
|
@override
|
|
MaterialStateProperty<Color?>? get backgroundColor {
|
|
return ButtonStyleButton.allOrNull<Color>(Colors.transparent);
|
|
}
|
|
|
|
// No default shadow color
|
|
|
|
// No default surface tint color
|
|
|
|
@override
|
|
MaterialStateProperty<double>? get elevation {
|
|
return ButtonStyleButton.allOrNull<double>(0.0);
|
|
}
|
|
|
|
@override
|
|
MaterialStateProperty<Color?>? get foregroundColor {
|
|
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
|
|
if (states.contains(MaterialState.disabled)) {
|
|
return ${componentColor('md.comp.list.list-item.disabled.label-text')};
|
|
}
|
|
if (states.contains(MaterialState.pressed)) {
|
|
return ${componentColor('md.comp.list.list-item.pressed.label-text')};
|
|
}
|
|
if (states.contains(MaterialState.hovered)) {
|
|
return ${componentColor('md.comp.list.list-item.hover.label-text')};
|
|
}
|
|
if (states.contains(MaterialState.focused)) {
|
|
return ${componentColor('md.comp.list.list-item.focus.label-text')};
|
|
}
|
|
return ${componentColor('md.comp.list.list-item.label-text')};
|
|
});
|
|
}
|
|
|
|
@override
|
|
MaterialStateProperty<Color?>? get iconColor {
|
|
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
|
|
if (states.contains(MaterialState.disabled)) {
|
|
return ${componentColor('md.comp.list.list-item.disabled.leading-icon')};
|
|
}
|
|
if (states.contains(MaterialState.pressed)) {
|
|
return ${componentColor('md.comp.list.list-item.pressed.leading-icon.icon')};
|
|
}
|
|
if (states.contains(MaterialState.hovered)) {
|
|
return ${componentColor('md.comp.list.list-item.hover.leading-icon.icon')};
|
|
}
|
|
if (states.contains(MaterialState.focused)) {
|
|
return ${componentColor('md.comp.list.list-item.focus.leading-icon.icon')};
|
|
}
|
|
return ${componentColor('md.comp.list.list-item.leading-icon')};
|
|
});
|
|
}
|
|
|
|
// No default fixedSize
|
|
|
|
@override
|
|
MaterialStateProperty<Size>? get maximumSize {
|
|
return ButtonStyleButton.allOrNull<Size>(Size.infinite);
|
|
}
|
|
|
|
@override
|
|
MaterialStateProperty<Size>? get minimumSize {
|
|
return ButtonStyleButton.allOrNull<Size>(const Size(64.0, 48.0));
|
|
}
|
|
|
|
@override
|
|
MaterialStateProperty<MouseCursor?>? get mouseCursor {
|
|
return MaterialStateProperty.resolveWith(
|
|
(Set<MaterialState> states) {
|
|
if (states.contains(MaterialState.disabled)) {
|
|
return SystemMouseCursors.basic;
|
|
}
|
|
return SystemMouseCursors.click;
|
|
},
|
|
);
|
|
}
|
|
|
|
@override
|
|
MaterialStateProperty<Color?>? get overlayColor {
|
|
return MaterialStateProperty.resolveWith(
|
|
(Set<MaterialState> states) {
|
|
if (states.contains(MaterialState.pressed)) {
|
|
return ${componentColor('md.comp.list.list-item.pressed.state-layer')};
|
|
}
|
|
if (states.contains(MaterialState.hovered)) {
|
|
return ${componentColor('md.comp.list.list-item.hover.state-layer')};
|
|
}
|
|
if (states.contains(MaterialState.focused)) {
|
|
return ${componentColor('md.comp.list.list-item.focus.state-layer')};
|
|
}
|
|
return Colors.transparent;
|
|
},
|
|
);
|
|
}
|
|
|
|
@override
|
|
MaterialStateProperty<EdgeInsetsGeometry>? get padding {
|
|
return ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(_scaledPadding(context));
|
|
}
|
|
|
|
// No default side
|
|
|
|
@override
|
|
MaterialStateProperty<OutlinedBorder>? get shape {
|
|
return ButtonStyleButton.allOrNull<OutlinedBorder>(const RoundedRectangleBorder());
|
|
}
|
|
|
|
@override
|
|
InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory;
|
|
|
|
@override
|
|
MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize;
|
|
|
|
@override
|
|
MaterialStateProperty<TextStyle?> get textStyle {
|
|
// TODO(tahatesser): This is taken from https://m3.material.io/components/menus/specs
|
|
// Update this when the token is available.
|
|
return MaterialStatePropertyAll<TextStyle?>(_textTheme.labelLarge);
|
|
}
|
|
|
|
@override
|
|
VisualDensity? get visualDensity => Theme.of(context).visualDensity;
|
|
|
|
// The horizontal padding number comes from the spec.
|
|
EdgeInsetsGeometry _scaledPadding(BuildContext context) {
|
|
VisualDensity visualDensity = Theme.of(context).visualDensity;
|
|
// When horizontal VisualDensity is greater than zero, set it to zero
|
|
// because the [ButtonStyleButton] has already handle the padding based on the density.
|
|
// However, the [ButtonStyleButton] doesn't allow the [VisualDensity] adjustment
|
|
// to reduce the width of the left/right padding, so we need to handle it here if
|
|
// the density is less than zero, such as on desktop platforms.
|
|
if (visualDensity.horizontal > 0) {
|
|
visualDensity = VisualDensity(vertical: visualDensity.vertical);
|
|
}
|
|
// Since the threshold paddings used below are empirical values determined
|
|
// at a font size of 14.0, 14.0 is used as the base value for scaling the
|
|
// padding.
|
|
final double fontSize = Theme.of(context).textTheme.labelLarge?.fontSize ?? 14.0;
|
|
final double fontSizeRatio = MediaQuery.textScalerOf(context).scale(fontSize) / 14.0;
|
|
return ButtonStyleButton.scaledPadding(
|
|
EdgeInsets.symmetric(horizontal: math.max(
|
|
_kMenuViewPadding,
|
|
_kLabelItemDefaultSpacing + visualDensity.baseSizeAdjustment.dx,
|
|
)),
|
|
EdgeInsets.symmetric(horizontal: math.max(
|
|
_kMenuViewPadding,
|
|
8 + visualDensity.baseSizeAdjustment.dx,
|
|
)),
|
|
const EdgeInsets.symmetric(horizontal: _kMenuViewPadding),
|
|
fontSizeRatio,
|
|
);
|
|
}
|
|
}
|
|
|
|
class _MenuDefaultsM3 extends MenuStyle {
|
|
_MenuDefaultsM3(this.context)
|
|
: super(
|
|
elevation: const MaterialStatePropertyAll<double?>(${elevation('md.comp.menu.container')}),
|
|
shape: const MaterialStatePropertyAll<OutlinedBorder>(_defaultMenuBorder),
|
|
alignment: AlignmentDirectional.topEnd,
|
|
);
|
|
|
|
static const RoundedRectangleBorder _defaultMenuBorder =
|
|
${shape('md.comp.menu.container', '')};
|
|
|
|
final BuildContext context;
|
|
|
|
late final ColorScheme _colors = Theme.of(context).colorScheme;
|
|
|
|
@override
|
|
MaterialStateProperty<Color?> get backgroundColor {
|
|
return MaterialStatePropertyAll<Color?>(${componentColor('md.comp.menu.container')});
|
|
}
|
|
|
|
@override
|
|
MaterialStateProperty<Color?>? get surfaceTintColor {
|
|
return ${componentColor('md.comp.menu.container.surface-tint-layer') == 'null'
|
|
? 'const MaterialStatePropertyAll<Color?>(Colors.transparent)'
|
|
: 'MaterialStatePropertyAll<Color?>(${componentColor('md.comp.menu.container.surface-tint-layer')})'
|
|
};
|
|
}
|
|
|
|
@override
|
|
MaterialStateProperty<Color?>? get shadowColor {
|
|
return MaterialStatePropertyAll<Color?>(${color('md.comp.menu.container.shadow-color')});
|
|
}
|
|
|
|
@override
|
|
MaterialStateProperty<EdgeInsetsGeometry?>? get padding {
|
|
return const MaterialStatePropertyAll<EdgeInsetsGeometry>(
|
|
EdgeInsetsDirectional.symmetric(vertical: _kMenuVerticalMinPadding),
|
|
);
|
|
}
|
|
|
|
@override
|
|
VisualDensity get visualDensity => Theme.of(context).visualDensity;
|
|
}
|
|
''';
|
|
}
|