-
Notifications
You must be signed in to change notification settings - Fork 0
LayrzButton
A Material-free button component supporting ten style variants, icon rendering, loading and cooldown states, and six semantic factories.
Metadata
Mirrors: ThemedButton (layrz_theme)
Phase: M2 (Core primitives)
Domain: Buttons
Primitive: Hand-rolled (no Material ButtonStyle, RawButton, or equivalent outside Material)
Status: Confirmed scope.
LayrzButton is the sole button primitive in layrz_ui. It is not an input component and does not participate in the input contract defined in Input Contract. It renders an interactive, semantically meaningful button with text, icon, or both.
-
Simple label only:
labelText(String) only. AlabelWidget parameter is explicitly not supported. - Icon as first-class parameter: Required for FAB variants; optional for regular button variants.
- Ten style variants in five pairs: each style has a standard and FAB variant.
- Stateful affordances: loading indicator and cooldown timer, both externally driven.
- Semantic factories: six pre-configured buttons for common actions (save, cancel, info, show, edit, delete).
// Design sketch — illustrative only
class LayrzButton extends StatefulWidget {
/// The human-readable label displayed on the button.
///
/// This is the only label representation; a Widget label parameter is not supported.
final String labelText;
/// Icon displayed on the button.
///
/// For FAB variants, this icon is the only visible element.
/// For regular variants, the icon appears to the left of the text.
/// Required for FAB styles; optional for regular styles.
final IconData? icon;
/// Callback invoked when the button is tapped.
final VoidCallback? onTap;
/// Whether a loading indicator should be displayed.
///
/// When true, the button renders a loading spinner and disables interaction.
final bool isLoading;
/// Whether the button is in cooldown state.
///
/// When true, the button is disabled and displays a countdown timer.
final bool isCooldown;
/// The duration of the cooldown period.
///
/// Defaults to 5 seconds. Only used when [isCooldown] is true.
final Duration cooldownDuration;
/// Visual style of the button.
///
/// Determines appearance and interaction affordances.
/// See Variants section below.
final LayrzButtonStyle style;
/// Whether the button is disabled.
///
/// Disabled buttons do not respond to taps.
final bool isDisabled;
/// Custom color override.
///
/// If not supplied, color is determined by the theme and button style.
final Color? color;
/// Tooltip text displayed on hover or long-press.
final String? hintText;
/// Custom width override.
///
/// If null, width is calculated from content.
final double? width;
/// Custom height override.
///
/// Defaults to 40 logical pixels.
final double height;
/// Icon size in logical pixels.
///
/// Defaults to 22.
final double iconSize;
/// Spacing between icon and text in logical pixels.
///
/// Defaults to 8. Only relevant when both icon and text are present.
final double iconSeparatorSize;
/// Font size of the label text.
///
/// Defaults to 14.
final double fontSize;
/// Custom background color for the loading indicator.
///
/// Defaults to transparent.
final Color? loadingBackgroundColor;
/// Custom foreground color for the loading indicator.
///
/// Defaults to the theme's input fill color.
final Color? loadingForegroundColor;
/// Whether to display the cooldown countdown timer.
///
/// When true, shows "N seconds remaining" during cooldown.
/// Defaults to true.
final bool showCooldownRemainingDuration;
/// Tooltip position when [hintText] is supplied.
///
/// Defaults to bottom.
final LayrzTooltipPosition tooltipPosition;
/// Whether tooltips are enabled.
///
/// Defaults to true.
final bool tooltipEnabled;
/// Callback invoked when a long press is detected.
///
/// Mutually exclusive with [onTap]. Cannot supply both.
final VoidCallback? onLongPress;
/// Duration before a long-press is recognized.
///
/// Defaults to 500 milliseconds.
final Duration customLongPressDuration;
// Constructor omitted for brevity
}Six named constructors provide pre-configured buttons for common actions:
// Design sketch — illustrative only
factory LayrzButton.save({
required VoidCallback onTap,
required String labelText,
bool isLoading = false,
bool isDisabled = false,
bool isCooldown = false,
bool isMobile = false,
}) → LayrzButton
factory LayrzButton.cancel({
required VoidCallback onTap,
required String labelText,
bool isLoading = false,
bool isDisabled = false,
bool isCooldown = false,
bool isMobile = false,
}) → LayrzButton
factory LayrzButton.info({
required VoidCallback onTap,
required String labelText,
bool isLoading = false,
bool isDisabled = false,
bool isCooldown = false,
bool isMobile = false,
}) → LayrzButton
factory LayrzButton.show({
required VoidCallback onTap,
required String labelText,
bool isLoading = false,
bool isDisabled = false,
bool isCooldown = false,
bool isMobile = false,
}) → LayrzButton
factory LayrzButton.edit({
required VoidCallback onTap,
required String labelText,
bool isLoading = false,
bool isDisabled = false,
bool isCooldown = false,
bool isMobile = false,
}) → LayrzButton
factory LayrzButton.delete({
required VoidCallback onTap,
required String labelText,
bool isLoading = false,
bool isDisabled = false,
bool isCooldown = false,
bool isMobile = false,
}) → LayrzButtonEach factory:
- Supplies an appropriate icon from the
layrz_iconspackage. - Applies a semantic color (green for save/show, red for cancel/delete, orange for edit, blue for info).
- When
isMobile = true, renders as a FAB style; otherwise renders as a filled-tonal style.
Ten style variants organize into five pairs:
| Pair | Regular Style | FAB Style | Appearance |
|---|---|---|---|
| 1 | .filled |
.filledFab |
Solid background, no shadow |
| 2 | .filledTonal |
.filledTonalFab |
Semi-transparent background (20% opacity) |
| 3 | .elevated |
.elevatedFab |
Solid background with drop shadow |
| 4 | .outlined |
.outlinedFab |
Transparent background with border |
| 5 | .outlinedTonal |
.outlinedTonalFab |
Transparent background with semi-transparent border |
| 6 (legacy) | .text |
.fab |
Transparent background, minimal affordance |
FAB variants (suffixed with Fab):
- Render icon-only.
-
labelTextsupplies the tooltip and accessible name. - Typically smaller (40 × 40 logical pixels by default).
- Used for floating action buttons and icon-only toolbar buttons.
Both states are externally driven and do not manage timers internally.
LayrzButton(
labelText: 'Save',
isLoading: true, // Caller manages this flag
onTap: disabled ? null : _save,
)When isLoading = true:
- A spinner indicator replaces or overlays the text.
- The button is disabled (interaction blocked).
- Caller is responsible for managing this flag (e.g., clearing it after an async operation completes).
LayrzButton(
labelText: 'Submit',
isCooldown: _cooldownActive, // Caller owns this state
cooldownDuration: Duration(seconds: 5),
onTap: _cooldownActive ? null : _submit,
)When isCooldown = true:
- The button is disabled.
- A countdown timer is displayed (e.g., "5s remaining", "4s remaining", …).
- When the countdown reaches zero, the button returns to enabled state, but remains in the cooldown UI state until the caller sets
isCooldown = false. - The caller is responsible for detecting countdown completion and clearing the flag.
Important: onCooldownFinish callback does not exist in layrz_ui. Whoever owns the isCooldown flag is responsible for detecting when the timer completes and setting the flag to false.
The button responds to hover on desktop platforms with a visual affordance. The implementation details (opacity change, color shift, etc.) are deferred to M2 implementation and design tokens.
-
M1 Theme System (
LayrzTheme,LayrzThemeData) — colors, text styles, and theme tokens. -
M2 Tooltip Component (
LayrzTooltip) — for renderinghintTexttooltips. - layrz_icons (1.1.0, verified clean) — icon supply for both user icons and semantic factory icons.
-
Icon source for layrz_icons: Are icons accessed as static getters (e.g.,
LayrzIcon.solarOutlineInboxIn) or via a different accessor? The current layrz_theme usesLayrzIcons.solarOutlineInboxIn— confirm the exact form for layrz_ui. -
Disabled signal: Is there an explicit
disabledparameter, or doesonTap: nullsignal disabled state? (layrz_theme usesisDisabled, but the signal may differ in layrz_ui.) -
ValueListenable for cooldown: Should
isCooldownandisLoadingbeValueListenable<bool>so the caller owns the state object and the button can listen for changes? Or should they remain simpleboolparameters that the caller updates via setState?
Critical path item: A design reference (Figma, annotated screenshot, or spec) must be attached to the LayrzButton component before implementation begins. This specification must cover:
- Button chrome (padding, border radius, minimum touch target size).
- Label and icon spacing and sizing at different button heights.
- Loading indicator appearance and animation.
- Cooldown timer styling and counter update frequency.
- Hover state visual feedback.
- Disabled state appearance (grayed out, opacity reduction, or cursor style).
- Light and dark theme variants for all ten style/theme combinations (10 styles × 2 themes = 20 visual specifications minimum).
Last updated: 2026-08-13
Related documents: Input Contract, Design Tokens, Architecture, Roadmap
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