Skip to content

LayrzSelectableAction

Kenny Mochizuki Escalona edited this page Aug 21, 2026 · 2 revisions

LayrzSelectableAction

A text selection toolbar action for use in LayrzTextInput and page-wide text selection.

Metadata
Domain: Selection
Phase: M2 (Selection framework)
Status: Shipped in 0.0.12.


Overview

LayrzSelectableAction represents a single action (button) in a text selection context menu toolbar. The built-in actions (copy, cut, paste, select all) are provided as static instances; custom actions can be created to extend the toolbar with application-specific operations.

Actions are provided to LayrzTextInput via the actions parameter:

  • When null, the field offers all four built-in actions (copy, cut, paste, select all) as permitted by field state
  • When const {}, the toolbar is suppressed entirely
  • When populated with a custom set, the set is intersected with what the field's state permits (e.g., an obscured field never offers copy or cut)

Built-In Actions

Four actions are always available:

Action Type Behavior Suppressed When
Copy 'copy' Copies selected text to clipboard obscureText: true
Cut 'cut' Cuts selected text to clipboard obscureText: true or readOnly: true
Paste 'paste' Pastes clipboard content at cursor readOnly: true
Select All 'selectAll' Selects all field content Never

Access built-in actions via static getters:

LayrzSelectableAction.copy();        // Copy button
LayrzSelectableAction.cut();         // Cut button
LayrzSelectableAction.paste();       // Paste button
LayrzSelectableAction.selectAll();   // Select all button

Custom Actions

Custom actions override the defaults for a specific field:

final customAction = LayrzSelectableAction(
  label: (context) => 'Share',  // Label function for localization
  onPressed: () => _shareText(),
);

LayrzTextInput(
  labelText: 'Message',
  actions: {customAction},  // Replaces built-ins with just "Share"
)

Important: Deduplication

  • Built-in actions dedupe by kind (type field): only one copy/cut/paste/selectAll may appear in the toolbar, even if multiple are added
  • Custom actions dedupe only by identity — two separate instances with identical labels are treated as distinct actions

Consequence: A const set of custom actions is impossible. The type overrides operator==, making const instances unhashable as set members:

// This will NOT compile:
const actions = {
  LayrzSelectableAction(label: (_) => 'Custom', onPressed: () {}),  // Dart error
};

Workaround: Use a static final instead:

static final customActions = {
  LayrzSelectableAction(label: (_) => 'Custom', onPressed: () {}),
};

LayrzTextInput(
  labelText: 'Field',
  actions: customActions,  // ✓ Works
)

Filtering by Field State

When a set of actions is provided to a field, it is automatically filtered to respect field state:

// Provided to field
actions: {
  LayrzSelectableAction.copy(),
  LayrzSelectableAction.cut(),
  LayrzSelectableAction.selectAll(),
}

// With obscureText: true, the field internally becomes:
// {selectAll}  (copy and cut are removed)

// With readOnly: true, the field internally becomes:
// {copy, selectAll}  (cut is removed, paste was already absent)

This filtering is transparent — the caller provides the set they want; the field silently removes actions it cannot support.


Page-Wide Selection

Page-wide text selection (outside of input fields, under LayrzLayout's SelectableRegion) offers a copy-only toolbar:

  • Only the copy button is shown
  • This is hardcoded and cannot be customized

The page toolbar is separate from field toolbars and does not use the LayrzSelectableAction system.


Usage Examples

Field with Built-In Actions (Default)

LayrzTextInput(
  labelText: 'Email',
  // actions: null (default) → copy, cut, paste, selectAll
)

Field with No Toolbar

LayrzTextInput(
  labelText: 'Secret',
  actions: const {},  // Suppress toolbar entirely
)

Field with Custom Action

final shareAction = LayrzSelectableAction(
  label: (context) => 'Share',
  onPressed: () => _shareText(),
);

LayrzTextInput(
  labelText: 'Message',
  actions: {shareAction, LayrzSelectableAction.copy()},
)

Field with Custom + Built-In Actions

static final customActions = {
  LayrzSelectableAction(label: (_) => 'Translate', onPressed: _translate),
  LayrzSelectableAction(label: (_) => 'Email', onPressed: _emailText),
};

LayrzTextInput(
  labelText: 'Text',
  actions: {
    ...customActions,
    LayrzSelectableAction.copy(),
    LayrzSelectableAction.selectAll(),
  },
)

Technical Notes

  • Deduplication by kind: Built-in actions use a type field (e.g., 'copy', 'cut') to dedupe within the toolbar; only one instance of each kind is shown
  • Deduplication by identity: Custom actions dedupe only by instance identity (identical), not by label or callback
  • Intersection with field state: The field automatically removes actions it cannot support (e.g., copy from an obscured field), so filtering is not the caller's responsibility
  • Localization: The label parameter is a function of BuildContext, allowing labels to reflect the current locale at render time

Last updated: 2026-08-20
Related documents: LayrzTextInput, Selection (D50)

Clone this wiki locally