-
Notifications
You must be signed in to change notification settings - Fork 0
LayrzButtonGroup
A responsive button group that renders actions as either a row of buttons or a single trigger opening a dropdown menu, depending on viewport width.
Metadata
Mirrors: ThemedActionsButtons (layrz_theme)
Phase: M2 (Core primitives)
Domain: Buttons
Primitive: Wrap + LayrzDropdownMenu (responsive collapse)
Status: Confirmed scope.
LayrzButtonGroup manages a collection of dropdown items rendered as a row of LayrzButton instances (converted from LayrzDropdownEntry) or as a dropdown menu. On narrow viewports (below the md breakpoint, 960px), it automatically collapses into a single trigger button that opens a dropdown menu listing the items.
Key principle: Items are the source of truth — they drive both row and dropdown modes. Dropdown menu items pass through unchanged; row mode converts LayrzDropdownEntry items to labelled buttons and silently skips LayrzDropdownLabel items.
-
Items as the data model: Takes
List<LayrzDropdownItem>(entries and labels), not buttons. - Responsive collapse: Automatically switches between row and dropdown modes at viewport breakpoints.
-
Nullable mode switch: A single boolean parameter (
useDropdown) gates the behavior; nullability is the switch rather than an enum, preventing invalid combinations. -
Entry-to-button conversion:
LayrzDropdownEntryinstances are converted to labelledLayrzButtoninstances in row mode. Labels are skipped (not rendered in row mode, only in dropdown mode). -
Semantic color mapping: Entry color dots (from semantic factories or explicit
color) map to buttoncolorin row mode; buttons always usetype: custom. - Auto-close on selection: Dropdown entries close the menu automatically after tapping.
-
Stable trigger naming: The trigger requires an explicit accessible name (the
triggerHintTextparameter), not derived from its contents. Platform overflow menus identify the control, not enumerate its actions.
class LayrzButtonGroup extends StatelessWidget {
/// The items rendered by this group, in order.
///
/// Must be a list of [LayrzDropdownItem] instances (either [LayrzDropdownEntry]
/// or [LayrzDropdownLabel]). The items pass directly to the dropdown menu in
/// dropdown mode. In row mode, only [LayrzDropdownEntry] items are converted
/// to labelled buttons; [LayrzDropdownLabel] items are silently skipped.
/// An empty list renders nothing in both modes.
final List<LayrzDropdownItem> items;
/// Forces the render mode. When null, the mode follows the responsive breakpoint,
/// collapsing to the dropdown below `md`.
///
/// - `true`: always render dropdown mode
/// - `false`: always render row mode
/// - `null` (default): switch automatically at the md breakpoint
final bool? useDropdown;
/// Gap between buttons in row mode. Defaults to `tokens.spacing.base`.
///
/// Only applies in row mode. Unused in dropdown mode.
final double? spacing;
/// Icon shown on the collapsed trigger. Defaults to the overflow-dots icon.
///
/// Only applies in dropdown mode.
final IconData? triggerIcon;
/// Accessible name and tooltip for the collapsed trigger button.
///
/// Shown as the trigger's tooltip on hover and announced by screen readers.
/// Platform overflow menus render a stable control name rather than enumerating
/// their contents, so this is required unconditionally — even though [useDropdown]
/// defaults to null and the group may collapse at any viewport width, the caller
/// always knows the semantic name to assign.
final String triggerHintText;
/// Horizontal alignment of the dropdown panel against the trigger.
///
/// Defaults to [LayrzDropdownMenuAlignment.start].
/// Only applies in dropdown mode.
final LayrzDropdownMenuAlignment alignment;
/// Creates a new [LayrzButtonGroup].
///
/// The [items] and [triggerHintText] parameters are required. All others
/// are optional with sensible defaults./// Creates a [LayrzButtonGroup] with a caller-supplied trigger widget.
///
/// The [builder] receives the menu [MenuController] and must wire it to the
/// trigger's own tap handler. This allows the caller to supply any trigger
/// widget and style it freely.
///
/// In row mode, the builder is never called and the group renders its items
/// as usual.
const LayrzButtonGroup.builder({
required List<LayrzDropdownItem> items,
required LayrzDropdownMenuBuilder builder,
bool? useDropdown,
double? spacing,
LayrzDropdownMenuAlignment alignment = LayrzDropdownMenuAlignment.start,
});LayrzButtonGroup(
triggerHintText: 'Table actions',
items: [
LayrzDropdownEntry.save(labelText: 'Save', onTap: () { }),
LayrzDropdownEntry.edit(labelText: 'Edit', onTap: () { }),
LayrzDropdownEntry.delete(labelText: 'Delete', onTap: () { }),
],
useDropdown: false,
)Renders three labelled buttons in a horizontal row.
LayrzButtonGroup(
triggerHintText: 'Table actions',
items: [
LayrzDropdownLabel(labelText: 'Modify'),
LayrzDropdownEntry.save(labelText: 'Save', onTap: () { }),
LayrzDropdownEntry.edit(labelText: 'Edit', onTap: () { }),
LayrzDropdownLabel(labelText: 'Danger Zone'),
LayrzDropdownEntry.delete(labelText: 'Delete', onTap: () { }),
],
useDropdown: true,
)Renders a single trigger button. When tapped, opens a menu showing all entries and labels. Labels organize entries into sections and render only in dropdown mode.
LayrzButtonGroup(
triggerHintText: 'Actions',
items: [
LayrzDropdownEntry.save(labelText: 'Save', onTap: () { }),
LayrzDropdownEntry.delete(labelText: 'Delete', onTap: () { }),
],
// useDropdown: null (default) — switches automatically at md breakpoint
)At or above 960px, renders two labelled buttons. Below 960px, collapses to a single trigger opening the dropdown menu.
LayrzButtonGroup.builder(
items: [
LayrzDropdownEntry.save(labelText: 'Save', onTap: () { }),
LayrzDropdownEntry.delete(labelText: 'Delete', onTap: () { }),
],
useDropdown: true,
builder: (context, controller) => LayrzButton(
labelText: 'Options',
icon: LayrzIcons.solarOutlineSettings,
style: LayrzButtonStyle.outlinedFab,
onTap: controller.isOpen ? controller.close : controller.open,
),
)Uses a custom button as the trigger, allowing full control over its styling.
In row mode, each LayrzDropdownEntry is converted to a LayrzButton with these rules:
| Entry Property | Button Property |
|---|---|
labelText |
labelText |
icon |
icon |
onTap |
onTap (nulled if disabled) |
enabled |
isDisabled (inverted) |
color |
color (with type: custom) |
shortcut |
(dropped — LayrzButton has no shortcut field) |
The button style is always LayrzButtonStyle.elevated (a labelled, non-Fab button).
Label skipping: LayrzDropdownLabel items are completely omitted in row mode. They serve only to organize entries in the dropdown menu.
-
LayrzButton— Individual action button -
LayrzDropdownMenu— The underlying menu used in dropdown mode -
LayrzDropdownEntry— A selectable menu entry (used in both modes) -
LayrzDropdownLabel— A non-interactive section heading (dropdown mode only)
Made with ❤️ by Golden M, Inc.
- LayrzAnchoredPanel
- LayrzBottomSheet
- LayrzDialog
- LayrzDropdownMenu
- LayrzResponsiveModal
- LayrzPageTransition
- LayrzTextInput
- LayrzSelectableAction
- LayrzSelectionToolbar
- LayrzTextSelectionControls
- LayrzSelectionMagnifier
- LayrzSelectionHandlePainter
- LayrzTextAreaInput
- LayrzComboBoxInput
- LayrzNumberInput
- LayrzPasswordInput
- LayrzCheckboxInput
- LayrzRadioInput
- LayrzSelectInput
- LayrzMultiSelectInput
- LayrzSearchInput
- LayrzDualListInput
- LayrzDurationInput
- LayrzSlider
- LayrzStepper