Class: Charming::Components::Form

Inherits:
Charming::Component show all
Defined in:
lib/charming/presentation/components/form.rb,
lib/charming/presentation/components/form/note.rb,
lib/charming/presentation/components/form/field.rb,
lib/charming/presentation/components/form/input.rb,
lib/charming/presentation/components/form/select.rb,
lib/charming/presentation/components/form/builder.rb,
lib/charming/presentation/components/form/confirm.rb,
lib/charming/presentation/components/form/textarea.rb

Overview

Form is a multi-field form component with built-in focus traversal, validation, and submit/cancel handling. Fields are produced by ‘Form::Builder` (see `controller.form`) and bound to a per-form mutable state hash. Tab/Shift+Tab cycles focus through focusable fields, Enter advances to the next field (or submits on the last), Escape cancels, and Ctrl+S submits from any field.

Exception: inside a Textarea field, Enter inserts a newline (it’s a text editor) —leave it with Tab and submit with Ctrl+S, matching charm.sh’s huh behavior.

Defined Under Namespace

Classes: Builder, Confirm, Field, Input, Note, Select, Textarea

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from View

#focused?, #layout_assigns

Constructor Details

#initialize(fields:, state: nil, theme: nil) ⇒ Form

fields is the array of form field objects. state is a hash for storing field values/errors and the current focus index; usually ‘session[form_name]`.



19
20
21
22
23
24
25
# File 'lib/charming/presentation/components/form.rb', line 19

def initialize(fields:, state: nil, theme: nil)
  super(theme: theme)
  @fields = fields
  @state = normalize_state(state || {})
  bind_fields
  clamp_focus
end

Instance Attribute Details

#fieldsObject (readonly)

The list of field objects and the mutable state hash the form is bound to.



15
16
17
# File 'lib/charming/presentation/components/form.rb', line 15

def fields
  @fields
end

#stateObject (readonly)

The list of field objects and the mutable state hash the form is bound to.



15
16
17
# File 'lib/charming/presentation/components/form.rb', line 15

def state
  @state
end

Instance Method Details

#captures_text?Boolean

Forms accept free-typed text (their input/textarea fields do), so printable characters route here before global/content key bindings.

Returns:

  • (Boolean)


43
44
45
# File 'lib/charming/presentation/components/form.rb', line 43

def captures_text?
  true
end

#handle_key(event) ⇒ Object

Handles key events: Escape cancels, Ctrl+S submits, Tab cycles focus, Enter advances or submits, and unhandled keys are passed to the focused field.



29
30
31
32
33
34
35
36
37
38
39
# File 'lib/charming/presentation/components/form.rb', line 29

def handle_key(event)
  key = Charming.key_of(event)
  return :cancelled if key == :escape
  return submit if submit_shortcut?(event)
  return move_focus(tab_direction(event)) if key == :tab

  result = handle_current_field(event)
  return result if result

  advance_or_submit if key == :enter
end

#renderObject

Renders each field on its own line, marking the active field with ‘active: true`.



53
54
55
56
57
# File 'lib/charming/presentation/components/form.rb', line 53

def render
  fields.each_with_index.map do |field, index|
    field.render(active: index == state[:focus_index])
  end.join("\n")
end

#valuesObject

Returns a hash of ‘=> value` for the current field values.



48
49
50
# File 'lib/charming/presentation/components/form.rb', line 48

def values
  state[:values]
end