forked from mirrors/material_3_expressive
Add expanded and linearMainAxisAlignment options to ButtonGroupM3E for improved layout control
This commit is contained in:
parent
582af894f3
commit
76daccbc71
6 changed files with 101 additions and 27 deletions
|
|
@ -39,6 +39,14 @@ class ButtonGroupSection extends StatelessWidget {
|
||||||
title: 'ButtonGroupM3E — vertical, menu overflow',
|
title: 'ButtonGroupM3E — vertical, menu overflow',
|
||||||
child: _demoVertical(context),
|
child: _demoVertical(context),
|
||||||
),
|
),
|
||||||
|
SectionCard(
|
||||||
|
title: 'ButtonGroupM3E — centered (expanded)',
|
||||||
|
child: _demoAlignedCenter(context),
|
||||||
|
),
|
||||||
|
SectionCard(
|
||||||
|
title: 'ButtonGroupM3E — right aligned (expanded)',
|
||||||
|
child: _demoAlignedRight(context),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -48,14 +56,7 @@ class ButtonGroupSection extends StatelessWidget {
|
||||||
width: 280,
|
width: 280,
|
||||||
child: ButtonGroupM3E(
|
child: ButtonGroupM3E(
|
||||||
actions: [
|
actions: [
|
||||||
for (final label in [
|
for (final label in ['One', 'Two', 'Three', 'Four', 'Five', 'Six'])
|
||||||
'One',
|
|
||||||
'Two',
|
|
||||||
'Three',
|
|
||||||
'Four',
|
|
||||||
'Five Button',
|
|
||||||
'Six'
|
|
||||||
])
|
|
||||||
ButtonGroupM3EAction(label: Text(label), onPressed: () {}),
|
ButtonGroupM3EAction(label: Text(label), onPressed: () {}),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -97,10 +98,10 @@ class ButtonGroupSection extends StatelessWidget {
|
||||||
child: ButtonGroupM3E(
|
child: ButtonGroupM3E(
|
||||||
type: ButtonGroupM3EType.connected,
|
type: ButtonGroupM3EType.connected,
|
||||||
dividerColor: Theme.of(context).colorScheme.outlineVariant,
|
dividerColor: Theme.of(context).colorScheme.outlineVariant,
|
||||||
style: ButtonM3EStyle.tonal,
|
|
||||||
actions: [
|
actions: [
|
||||||
for (final label in ['Low', 'Med', 'High'])
|
for (final label in ['Low', 'Med', 'High'])
|
||||||
ButtonGroupM3EAction(
|
ButtonGroupM3EAction(
|
||||||
|
style: ButtonM3EStyle.tonal,
|
||||||
label: Text(label),
|
label: Text(label),
|
||||||
onPressed: () {},
|
onPressed: () {},
|
||||||
),
|
),
|
||||||
|
|
@ -136,15 +137,9 @@ class ButtonGroupSection extends StatelessWidget {
|
||||||
dividerColor: Theme.of(context).colorScheme.outlineVariant,
|
dividerColor: Theme.of(context).colorScheme.outlineVariant,
|
||||||
style: ButtonM3EStyle.tonal,
|
style: ButtonM3EStyle.tonal,
|
||||||
actions: [
|
actions: [
|
||||||
for (final label in [
|
for (final label in ['One', 'Two', 'Three', 'Four', 'Five', 'Six'])
|
||||||
'One',
|
|
||||||
'Two',
|
|
||||||
'Three',
|
|
||||||
'Four',
|
|
||||||
'Five Button',
|
|
||||||
'Six'
|
|
||||||
])
|
|
||||||
ButtonGroupM3EAction(
|
ButtonGroupM3EAction(
|
||||||
|
style: ButtonM3EStyle.tonal,
|
||||||
label: Text(label),
|
label: Text(label),
|
||||||
onPressed: () {},
|
onPressed: () {},
|
||||||
),
|
),
|
||||||
|
|
@ -165,4 +160,31 @@ class ButtonGroupSection extends StatelessWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _demoAlignedCenter(BuildContext context) {
|
||||||
|
return ButtonGroupM3E(
|
||||||
|
expanded: true,
|
||||||
|
linearMainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
actions: const [
|
||||||
|
ButtonGroupM3EAction(label: Text('Center 1')),
|
||||||
|
ButtonGroupM3EAction(label: Text('Center 2')),
|
||||||
|
ButtonGroupM3EAction(label: Text('Center 3')),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _demoAlignedRight(BuildContext context) {
|
||||||
|
return ButtonGroupM3E(
|
||||||
|
expanded: true,
|
||||||
|
linearMainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
overflow: ButtonGroupM3EOverflow.menu,
|
||||||
|
actions: const [
|
||||||
|
ButtonGroupM3EAction(label: Text('Right 1')),
|
||||||
|
ButtonGroupM3EAction(label: Text('Right 2')),
|
||||||
|
ButtonGroupM3EAction(label: Text('Right 3')),
|
||||||
|
ButtonGroupM3EAction(label: Text('Right 4')),
|
||||||
|
ButtonGroupM3EAction(label: Text('Right 5')),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
|
## 0.3.1
|
||||||
|
- New: `expanded` and `linearMainAxisAlignment` options for non-wrap layouts. When `expanded` is true, the group uses `MainAxisSize.max` and aligns items per `linearMainAxisAlignment` (or mapped from `alignment`). This enables internal center/right alignment without extra wrappers.
|
||||||
|
- Fix: Connected + menu overflow now consistently inserts a 2px gap before the overflow trigger (when `showDividers=false`) and uses a stricter width-fitting algorithm with a small epsilon to eliminate minor RenderFlex overflows.
|
||||||
|
- UX: Dropdown overflow popup is anchored bottom-right of the overflow button, has intrinsic width to fit its buttons, and aligns its internal buttons to the right.
|
||||||
|
|
||||||
## 0.3.0
|
## 0.3.0
|
||||||
- Breaking: Removed legacy `children` parameter. Use `actions: List<ButtonGroupM3EAction>` instead.
|
- Breaking: Removed legacy `children` parameter. Use `actions: List<ButtonGroupM3EAction>` instead.
|
||||||
- Breaking: Renamed `groupSelection` API to `selection` for clarity.
|
- Breaking: Renamed `groupSelection` API to `selection` for clarity.
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,8 @@ class ButtonGroupM3E extends StatefulWidget {
|
||||||
this.selection = false,
|
this.selection = false,
|
||||||
this.selectedIndex,
|
this.selectedIndex,
|
||||||
this.overflowMenuStyle = ButtonGroupM3EOverflowMenuStyle.dropdown,
|
this.overflowMenuStyle = ButtonGroupM3EOverflowMenuStyle.dropdown,
|
||||||
|
this.expanded = false,
|
||||||
|
this.linearMainAxisAlignment,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Declarative actions to build buttons. Overrides [children] when not empty.
|
/// Declarative actions to build buttons. Overrides [children] when not empty.
|
||||||
|
|
@ -146,6 +148,13 @@ class ButtonGroupM3E extends StatefulWidget {
|
||||||
/// How to display the overflow menu when [overflow] == menu. Defaults to dropdown.
|
/// How to display the overflow menu when [overflow] == menu. Defaults to dropdown.
|
||||||
final ButtonGroupM3EOverflowMenuStyle overflowMenuStyle;
|
final ButtonGroupM3EOverflowMenuStyle overflowMenuStyle;
|
||||||
|
|
||||||
|
/// When true, Row/Column uses MainAxisSize.max enabling internal end alignment.
|
||||||
|
final bool expanded;
|
||||||
|
|
||||||
|
/// Explicit mainAxis alignment for non-wrap (Row/Column) layouts.
|
||||||
|
/// If null falls back to mapping of [alignment] (WrapAlignment) for convenience.
|
||||||
|
final MainAxisAlignment? linearMainAxisAlignment;
|
||||||
|
|
||||||
bool get _connected => type == ButtonGroupM3EType.connected;
|
bool get _connected => type == ButtonGroupM3EType.connected;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -270,14 +279,23 @@ class _ButtonGroupM3EState extends State<ButtonGroupM3E> {
|
||||||
final list = _buildItemList(
|
final list = _buildItemList(
|
||||||
context, spacing, dividerColor, dividerThickness,
|
context, spacing, dividerColor, dividerThickness,
|
||||||
count: _effectiveActions.length);
|
count: _effectiveActions.length);
|
||||||
|
|
||||||
|
final mainAlign =
|
||||||
|
widget.linearMainAxisAlignment ?? _mapWrapToMain(widget.alignment);
|
||||||
|
final mainSize = widget.expanded ? MainAxisSize.max : MainAxisSize.min;
|
||||||
|
|
||||||
return widget.direction == Axis.horizontal
|
return widget.direction == Axis.horizontal
|
||||||
? Row(
|
? Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: mainSize,
|
||||||
|
mainAxisAlignment:
|
||||||
|
widget.expanded ? mainAlign : MainAxisAlignment.start,
|
||||||
crossAxisAlignment: _mapCross(widget.crossAxisAlignment),
|
crossAxisAlignment: _mapCross(widget.crossAxisAlignment),
|
||||||
children: list,
|
children: list,
|
||||||
)
|
)
|
||||||
: Column(
|
: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: mainSize,
|
||||||
|
mainAxisAlignment:
|
||||||
|
widget.expanded ? mainAlign : MainAxisAlignment.start,
|
||||||
crossAxisAlignment: _mapCross(widget.crossAxisAlignment),
|
crossAxisAlignment: _mapCross(widget.crossAxisAlignment),
|
||||||
children: list,
|
children: list,
|
||||||
);
|
);
|
||||||
|
|
@ -289,6 +307,10 @@ class _ButtonGroupM3EState extends State<ButtonGroupM3E> {
|
||||||
final list = _buildItemList(
|
final list = _buildItemList(
|
||||||
context, spacing, dividerColor, dividerThickness,
|
context, spacing, dividerColor, dividerThickness,
|
||||||
count: _effectiveActions.length);
|
count: _effectiveActions.length);
|
||||||
|
|
||||||
|
final mainAlign =
|
||||||
|
widget.linearMainAxisAlignment ?? _mapWrapToMain(widget.alignment);
|
||||||
|
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (context, constraints) {
|
builder: (context, constraints) {
|
||||||
final isBounded = widget.direction == Axis.horizontal
|
final isBounded = widget.direction == Axis.horizontal
|
||||||
|
|
@ -297,12 +319,18 @@ class _ButtonGroupM3EState extends State<ButtonGroupM3E> {
|
||||||
|
|
||||||
final core = widget.direction == Axis.horizontal
|
final core = widget.direction == Axis.horizontal
|
||||||
? Row(
|
? Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize:
|
||||||
|
widget.expanded ? MainAxisSize.max : MainAxisSize.min,
|
||||||
|
mainAxisAlignment:
|
||||||
|
widget.expanded ? mainAlign : MainAxisAlignment.start,
|
||||||
crossAxisAlignment: _mapCross(widget.crossAxisAlignment),
|
crossAxisAlignment: _mapCross(widget.crossAxisAlignment),
|
||||||
children: list,
|
children: list,
|
||||||
)
|
)
|
||||||
: Column(
|
: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize:
|
||||||
|
widget.expanded ? MainAxisSize.max : MainAxisSize.min,
|
||||||
|
mainAxisAlignment:
|
||||||
|
widget.expanded ? mainAlign : MainAxisAlignment.start,
|
||||||
crossAxisAlignment: _mapCross(widget.crossAxisAlignment),
|
crossAxisAlignment: _mapCross(widget.crossAxisAlignment),
|
||||||
children: list,
|
children: list,
|
||||||
);
|
);
|
||||||
|
|
@ -444,17 +472,25 @@ class _ButtonGroupM3EState extends State<ButtonGroupM3E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
final coreChildren = visibleList;
|
final coreChildren = visibleList;
|
||||||
|
final mainAlign =
|
||||||
|
widget.linearMainAxisAlignment ?? _mapWrapToMain(widget.alignment);
|
||||||
final core = widget.direction == Axis.horizontal
|
final core = widget.direction == Axis.horizontal
|
||||||
? ClipRect(
|
? ClipRect(
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize:
|
||||||
|
widget.expanded ? MainAxisSize.max : MainAxisSize.min,
|
||||||
|
mainAxisAlignment:
|
||||||
|
widget.expanded ? mainAlign : MainAxisAlignment.start,
|
||||||
crossAxisAlignment: _mapCross(widget.crossAxisAlignment),
|
crossAxisAlignment: _mapCross(widget.crossAxisAlignment),
|
||||||
children: coreChildren,
|
children: coreChildren,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: ClipRect(
|
: ClipRect(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize:
|
||||||
|
widget.expanded ? MainAxisSize.max : MainAxisSize.min,
|
||||||
|
mainAxisAlignment:
|
||||||
|
widget.expanded ? mainAlign : MainAxisAlignment.start,
|
||||||
crossAxisAlignment: _mapCross(widget.crossAxisAlignment),
|
crossAxisAlignment: _mapCross(widget.crossAxisAlignment),
|
||||||
children: coreChildren,
|
children: coreChildren,
|
||||||
),
|
),
|
||||||
|
|
@ -765,6 +801,15 @@ class _ButtonGroupM3EState extends State<ButtonGroupM3E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MainAxisAlignment _mapWrapToMain(WrapAlignment w) => switch (w) {
|
||||||
|
WrapAlignment.start => MainAxisAlignment.start,
|
||||||
|
WrapAlignment.end => MainAxisAlignment.end,
|
||||||
|
WrapAlignment.center => MainAxisAlignment.center,
|
||||||
|
WrapAlignment.spaceBetween => MainAxisAlignment.spaceBetween,
|
||||||
|
WrapAlignment.spaceAround => MainAxisAlignment.spaceAround,
|
||||||
|
WrapAlignment.spaceEvenly => MainAxisAlignment.spaceEvenly,
|
||||||
|
};
|
||||||
|
|
||||||
Widget _buildOverflowTrigger(
|
Widget _buildOverflowTrigger(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
double spacing,
|
double spacing,
|
||||||
|
|
@ -830,7 +875,6 @@ class _ButtonGroupM3EState extends State<ButtonGroupM3E> {
|
||||||
_removeOverflowEntry();
|
_removeOverflowEntry();
|
||||||
|
|
||||||
final overlay = Overlay.of(context, rootOverlay: true);
|
final overlay = Overlay.of(context, rootOverlay: true);
|
||||||
if (overlay == null) return;
|
|
||||||
|
|
||||||
_overflowEntry = OverlayEntry(
|
_overflowEntry = OverlayEntry(
|
||||||
builder: (ctx) {
|
builder: (ctx) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: button_group_m3e
|
name: button_group_m3e
|
||||||
description: Wrapper-only Button Group for Material 3 Expressive (layout, shape, size propagation).
|
description: Wrapper-only Button Group for Material 3 Expressive (layout, shape, size propagation).
|
||||||
version: 0.3.0
|
version: 0.3.1
|
||||||
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/button_group_m3e
|
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/button_group_m3e
|
||||||
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,5 @@
|
||||||
|
## 0.3.7
|
||||||
|
- Updated button_group_m3e to 0.3.1.
|
||||||
|
|
||||||
## 0.1.0
|
## 0.1.0
|
||||||
- Changelog initialized.
|
- Changelog initialized.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: m3e_collection
|
name: m3e_collection
|
||||||
description: Aggregated exports of all Material 3 Expressive components for Flutter.
|
description: Aggregated exports of all Material 3 Expressive components for Flutter.
|
||||||
version: 0.3.6
|
version: 0.3.7
|
||||||
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/m3e_collection
|
repository: https://github.com/EmilyMoonstone/material_3_expressive/tree/main/packages/m3e_collection
|
||||||
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
issue_tracker: https://github.com/EmilyMonestone/material_3_expressive/issues
|
||||||
|
|
||||||
|
|
@ -9,7 +9,7 @@ environment:
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
app_bar_m3e: ^0.1.2
|
app_bar_m3e: ^0.1.2
|
||||||
button_group_m3e: ^0.3.0
|
button_group_m3e: ^0.3.1
|
||||||
button_m3e: ^0.1.2
|
button_m3e: ^0.1.2
|
||||||
expressive_refresh: ^0.1.2
|
expressive_refresh: ^0.1.2
|
||||||
fab_m3e: ^0.1.1
|
fab_m3e: ^0.1.1
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue