Class: Charming::Components::TextInput

Inherits:
Charming::Component show all
Includes:
KeyboardHandler
Defined in:
lib/charming/presentation/components/text_input.rb

Overview

TextInput is a single-line text editor component. Supports printable character insertion, cursor movement (left/right/home/end), and deletion (backspace/delete). The component exposes its value and cursor positions as reader methods; when an explicit width: is given, the rendered output is padded to that width via a UI::Style.

Options:

  • masked: true renders every character as * (password entry)
  • history: [...] enables REPL-style recall — up/down cycle through prior values

Constant Summary collapse

KEY_ACTIONS =

Maps editing keys (left/right/home/end/backspace/delete) to the instance methods they dispatch via KeyboardHandler. Each symbol key (e.g., :left) maps to a method (e.g., :move_left) that adjusts cursor position or text content.

{
  left: :move_left,
  right: :move_right,
  home: :move_home,
  end: :move_end,
  backspace: :delete_before_cursor,
  delete: :delete_at_cursor
}.freeze

Constants included from KeyboardHandler

KeyboardHandler::VIM_KEYMAP

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from View

#focused?, #layout_assigns

Constructor Details

#initialize(value: "", placeholder: "", width: nil, cursor: nil, masked: false, history: nil) ⇒ TextInput

value is the initial text. placeholder is shown when the value is empty. width optionally constrains the rendered output width; cursor defaults to the end. masked renders characters as *. history is an array of prior values cycled with up/down (most recent last, like a shell).



35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/charming/presentation/components/text_input.rb', line 35

def initialize(value: "", placeholder: "", width: nil, cursor: nil, masked: false, history: nil)
  super()
  @value = value.dup
  @placeholder = placeholder
  @width = width
  @cursor = cursor || @value.length
  @masked = masked
  @history = history
  @history_index = nil
  @draft = nil
  clamp_position
end

Instance Attribute Details

#cursorObject (readonly)

The current input string and the character offset of the cursor within it.



29
30
31
# File 'lib/charming/presentation/components/text_input.rb', line 29

def cursor
  @cursor
end

#valueObject (readonly)

The current input string and the character offset of the cursor within it.



29
30
31
# File 'lib/charming/presentation/components/text_input.rb', line 29

def value
  @value
end

Instance Method Details

#captures_text?Boolean

Free-typed characters belong to this component while it is focused.

Returns:

  • (Boolean)


49
50
51
# File 'lib/charming/presentation/components/text_input.rb', line 49

def captures_text?
  true
end

#handle_key(event) ⇒ Object

Handles key events. Inserts printable characters, submits on Enter (returning [:submitted, value] so a focused slot dispatches <slot>_submitted(value)), recalls history on up/down (when enabled), otherwise dispatches via KEY_ACTIONS. Returns :handled or [:submitted, value] when the event was consumed, nil otherwise.



58
59
60
61
62
63
64
65
66
# File 'lib/charming/presentation/components/text_input.rb', line 58

def handle_key(event)
  return :handled if character_event?(event) && insert(event.char)

  key = Charming.key_of(event)
  return [:submitted, value] if key == :enter
  return :handled if history_event(key)

  super
end

#handle_paste(event) ⇒ Object

Inserts pasted text at the cursor (newlines and control characters are stripped — this is a single-line input). Returns :handled.



70
71
72
73
74
# File 'lib/charming/presentation/components/text_input.rb', line 70

def handle_paste(event)
  sanitized = event.text.to_s.gsub(/[[:cntrl:]]/, "")
  insert(sanitized) unless sanitized.empty?
  :handled
end

#renderObject

Renders the value with a cursor marker. When width was given at construction, the output is padded to that width via the configured style.



78
79
80
81
# File 'lib/charming/presentation/components/text_input.rb', line 78

def render
  rendered = render_value
  @width ? style.width(@width).render(rendered) : rendered
end