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,
lib/charming/presentation/components/form/multiselect.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, Multiselect, 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[:forms][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)


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

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

#handle_paste(event) ⇒ Object

Forwards pasted text to the currently focused field. Text fields insert it at their cursor; other fields ignore it.



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

def handle_paste(event)
  current_field&.handle_paste(event)
end

#renderObject

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



59
60
61
62
63
# File 'lib/charming/presentation/components/form.rb', line 59

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 {field_name => value} for the current field values.



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

def values
  state[:values]
end