Fix collapsed mode bug and update navigation rail theme properties

This commit is contained in:
Emily Pauli 2025-10-26 15:39:17 +01:00
commit 27b1dfd9ef
9 changed files with 47 additions and 24 deletions

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:m3e_design/m3e_design.dart'; import 'package:m3e_design/m3e_design.dart';
import 'app_bar_m3e_enums.dart'; import 'app_bar_m3e_enums.dart';
@immutable @immutable
@ -24,7 +25,8 @@ class _AppBarMetrics {
_AppBarMetrics metricsFor(BuildContext context, AppBarM3EDensity density) { _AppBarMetrics metricsFor(BuildContext context, AppBarM3EDensity density) {
final theme = Theme.of(context); final theme = Theme.of(context);
final m3e = theme.extension<M3ETheme>() ?? M3ETheme.defaults(theme.colorScheme); final m3e =
theme.extension<M3ETheme>() ?? M3ETheme.defaults(theme.colorScheme);
final sp = m3e.spacing; final sp = m3e.spacing;
// Heights (approx per M3 specs; can be tuned via Theme extension in m3e_design if desired) // Heights (approx per M3 specs; can be tuned via Theme extension in m3e_design if desired)
@ -54,21 +56,26 @@ _AppBarMetrics metricsFor(BuildContext context, AppBarM3EDensity density) {
Color backgroundFor(BuildContext context) { Color backgroundFor(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final m3e = theme.extension<M3ETheme>() ?? M3ETheme.defaults(theme.colorScheme); final m3e =
theme.extension<M3ETheme>() ?? M3ETheme.defaults(theme.colorScheme);
// Prefer container surfaces for bars // Prefer container surfaces for bars
return m3e.colors.surfaceContainerHigh; return m3e.colors.surfaceContainerHigh;
} }
TextStyle titleStyleFor(BuildContext context, {bool collapsed = true}) { TextStyle titleStyleFor(BuildContext context, {bool collapsed = true}) {
final theme = Theme.of(context); final theme = Theme.of(context);
final m3e = theme.extension<M3ETheme>() ?? M3ETheme.defaults(theme.colorScheme); final m3e =
theme.extension<M3ETheme>() ?? M3ETheme.defaults(theme.colorScheme);
return collapsed ? m3e.type.titleLarge : m3e.type.headlineSmallEmphasized; return collapsed ? m3e.type.titleLarge : m3e.type.headlineSmallEmphasized;
} }
ShapeBorder shapeFor(BuildContext context, AppBarM3EShapeFamily family) { ShapeBorder shapeFor(BuildContext context, AppBarM3EShapeFamily family) {
final theme = Theme.of(context); final theme = Theme.of(context);
final m3e = theme.extension<M3ETheme>() ?? M3ETheme.defaults(theme.colorScheme); final m3e =
final set = family == AppBarM3EShapeFamily.round ? m3e.shapes.round : m3e.shapes.square; theme.extension<M3ETheme>() ?? M3ETheme.defaults(theme.colorScheme);
final set = family == AppBarM3EShapeFamily.round
? m3e.shapes.round
: m3e.shapes.square;
// Use medium size radius for the bar container by default // Use medium size radius for the bar container by default
return RoundedRectangleBorder(borderRadius: set.md); return RoundedRectangleBorder(borderRadius: set.sm);
} }

View file

@ -1,6 +1,6 @@
name: app_bar_m3e name: app_bar_m3e
description: Expressive App Bar (Material 3 Expressive) with small/medium/large variants and Sliver integration. description: Expressive App Bar (Material 3 Expressive) with small/medium/large variants and Sliver integration.
version: 0.1.1 version: 0.1.2
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/app_bar_m3e repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/app_bar_m3e
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues

View file

@ -20,7 +20,7 @@ dependencies:
m3e_design: ^0.2.1 m3e_design: ^0.2.1
material_new_shapes: ^1.0.0 material_new_shapes: ^1.0.0
navigation_bar_m3e: ^0.1.1 navigation_bar_m3e: ^0.1.1
navigation_rail_m3e: ^0.3.4 navigation_rail_m3e: ^0.3.5
progress_indicator_m3e: ^0.1.1 progress_indicator_m3e: ^0.1.1
slider_m3e: ^0.1.1 slider_m3e: ^0.1.1
split_button_m3e: ^0.2.1 split_button_m3e: ^0.2.1

View file

@ -1,3 +1,6 @@
## 0.3.5
- fix bug with collapsed mode
## 0.3.4 ## 0.3.4
- add optional background parameter to NavigationRailM3E - add optional background parameter to NavigationRailM3E

View file

@ -441,8 +441,11 @@ class _NavigationRailM3EState extends State<NavigationRailM3E>
final all = widget.sections.expand((s) => s.destinations).toList(); final all = widget.sections.expand((s) => s.destinations).toList();
for (int i = 0; i < all.length; i++) { for (int i = 0; i < all.length; i++) {
children.add(Padding( children.add(Padding(
padding: const EdgeInsetsDirectional.only( padding: EdgeInsetsDirectional.only(
start: 16.0, end: 16.0, top: 8.0, bottom: 8.0), start: 16.0,
end: 16.0,
top: theme.itemVerticalGap,
bottom: theme.itemVerticalGap),
child: RailItem( child: RailItem(
destination: all[i], destination: all[i],
selected: i == widget.selectedIndex, selected: i == widget.selectedIndex,

View file

@ -36,9 +36,8 @@ class RailItem extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context).extension<NavigationRailM3ETheme>() ?? final theme = Theme.of(context).extension<NavigationRailM3ETheme>() ??
const NavigationRailM3ETheme(); const NavigationRailM3ETheme();
final height = destination.short final height =
? theme.itemCollapsedHeight expanded ? theme.itemExpandedHeight : theme.itemCollapsedHeight;
: theme.itemExpandedHeight;
final Widget button = RailItemButtonM3E( final Widget button = RailItemButtonM3E(
icon: destination.icon, icon: destination.icon,

View file

@ -20,6 +20,7 @@ class RailItemButtonM3E extends StatelessWidget {
this.semanticLabel, this.semanticLabel,
this.suppressInk = false, this.suppressInk = false,
this.badgeCount, this.badgeCount,
this.heightOverride,
}); });
/// Icon to display. /// Icon to display.
@ -52,16 +53,22 @@ class RailItemButtonM3E extends StatelessWidget {
/// Optional numeric badge value to show. /// Optional numeric badge value to show.
final int? badgeCount; final int? badgeCount;
/// Optional min height to enforce for the tap target. When null, defaults
/// to the theme's [NavigationRailM3ETheme.itemExpandedHeight] or
/// [itemCollapsedHeight] depending on [expanded].
final double? heightOverride;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context).extension<NavigationRailM3ETheme>() ?? final theme = Theme.of(context).extension<NavigationRailM3ETheme>() ??
const NavigationRailM3ETheme(); const NavigationRailM3ETheme();
final tokens = NavigationRailTokensAdapter(context); final tokens = NavigationRailTokensAdapter(context);
final double height = final double defaultHeight =
expanded ? theme.itemCollapsedHeight : theme.itemCollapsedHeight; expanded ? theme.itemExpandedHeight : theme.itemCollapsedHeight;
final bool selected = isSelected; final double height = heightOverride ?? defaultHeight;
final bool selected = isSelected;
// Colors and shape per state. // Colors and shape per state.
final Color fg = final Color fg =
selected ? tokens.activeIconAndLabel : tokens.inactiveIconAndLabel; selected ? tokens.activeIconAndLabel : tokens.inactiveIconAndLabel;
@ -76,8 +83,10 @@ class RailItemButtonM3E extends StatelessWidget {
Widget content; Widget content;
if (expanded) { if (expanded) {
final textExpended = Flexible( final textExpanded = Flexible(
child: DefaultTextStyle.merge( child: DefaultTextStyle.merge(
// Use a readable style in expanded mode.
style: Theme.of(context).textTheme.labelLarge!,
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
child: Text(label, semanticsLabel: semanticLabel ?? label), child: Text(label, semanticsLabel: semanticLabel ?? label),
@ -95,7 +104,7 @@ class RailItemButtonM3E extends StatelessWidget {
child: effectiveIcon, child: effectiveIcon,
), ),
SizedBox(width: theme.iconLabelGap), SizedBox(width: theme.iconLabelGap),
textExpended, textExpanded,
], ],
), ),
), ),
@ -138,15 +147,17 @@ class RailItemButtonM3E extends StatelessWidget {
); );
} }
// Material/Ink wrapper. Respect [suppressInk] to avoid flicker during transitions.
final bool noInk = suppressInk || !expanded;
final Material material = Material( final Material material = Material(
color: bg, color: bg,
shape: shape, shape: shape,
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
child: InkWell( child: InkWell(
onTap: onPressed, onTap: onPressed,
splashFactory: expanded ? null : NoSplash.splashFactory, splashFactory: noInk ? NoSplash.splashFactory : null,
hoverColor: expanded ? null : Colors.transparent, hoverColor: noInk ? Colors.transparent : null,
highlightColor: expanded ? null : Colors.transparent, highlightColor: noInk ? Colors.transparent : null,
child: Padding( child: Padding(
// Horizontal padding similar to ButtonM3E sm; for collapsed, none. // Horizontal padding similar to ButtonM3E sm; for collapsed, none.
padding: expanded padding: expanded

View file

@ -10,12 +10,12 @@ class NavigationRailM3ETheme extends ThemeExtension<NavigationRailM3ETheme> {
this.expandedMinWidth = 220.0, this.expandedMinWidth = 220.0,
this.expandedMaxWidth = 360.0, this.expandedMaxWidth = 360.0,
this.itemExpandedHeight = 40.0, this.itemExpandedHeight = 40.0,
this.itemCollapsedHeight = 56.0, this.itemCollapsedHeight = 66.0,
this.iconSize = 24.0, this.iconSize = 24.0,
this.indicatorLeading = 16.0, this.indicatorLeading = 16.0,
this.indicatorTrailing = 16.0, this.indicatorTrailing = 16.0,
this.iconLabelGap = 8.0, this.iconLabelGap = 8.0,
this.itemVerticalGap = 6.0, this.itemVerticalGap = 4.0,
this.headerMinSpace = 40.0, this.headerMinSpace = 40.0,
this.sectionHeaderSpacingTop = 12.0, this.sectionHeaderSpacingTop = 12.0,
this.sectionHeaderSpacingBottom = 8.0, this.sectionHeaderSpacingBottom = 8.0,

View file

@ -1,6 +1,6 @@
name: navigation_rail_m3e name: navigation_rail_m3e
description: Material 3 Expressive navigation rail (collapsed & expanded) with modal/standard modes, badges, sections, and m3e_design token integration. description: Material 3 Expressive navigation rail (collapsed & expanded) with modal/standard modes, badges, sections, and m3e_design token integration.
version: 0.3.4 version: 0.3.5
homepage: https://github.com/EmilyMonestone/material_3_expressive homepage: https://github.com/EmilyMonestone/material_3_expressive
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/navigation_rail_m3e repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/navigation_rail_m3e
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues