Skip to content

LayrzButton

Kenny Mochizuki Escalona edited this page Aug 13, 2026 · 7 revisions

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.


Overview

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.

Design Principles

  • Simple label only: labelText (String) only. A label Widget 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).

API Structure

Core Constructor

// 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
}

Semantic Factories

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,
}) → LayrzButton

Each factory:

  • Supplies an appropriate icon from the layrz_icons package.
  • 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.

Variants

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 Rendering

FAB variants (suffixed with Fab):

  • Render icon-only.
  • labelText supplies the tooltip and accessible name.
  • Typically smaller (40 × 40 logical pixels by default).
  • Used for floating action buttons and icon-only toolbar buttons.

Loading and Cooldown State

Both states are externally driven and do not manage timers internally.

Loading State

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).

Cooldown State

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.


Hover Effect

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.


Dependencies

  • M1 Theme System (LayrzTheme, LayrzThemeData) — colors, text styles, and theme tokens.
  • M2 Tooltip Component (LayrzTooltip) — for rendering hintText tooltips.
  • layrz_icons (1.1.0, verified clean) — icon supply for both user icons and semantic factory icons.

Open Questions

  • Icon source for layrz_icons: Are icons accessed as static getters (e.g., LayrzIcon.solarOutlineInboxIn) or via a different accessor? The current layrz_theme uses LayrzIcons.solarOutlineInboxIn — confirm the exact form for layrz_ui.

  • Disabled signal: Is there an explicit disabled parameter, or does onTap: null signal disabled state? (layrz_theme uses isDisabled, but the signal may differ in layrz_ui.)

  • ValueListenable for cooldown: Should isCooldown and isLoading be ValueListenable<bool> so the caller owns the state object and the button can listen for changes? Or should they remain simple bool parameters that the caller updates via setState?


Design Reference

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

Clone this wiki locally