Class: Charming::Components::Table

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

Overview

Table renders tabular data with a header row, a selected row highlight, and keyboard navigation. Mouse clicks within the body area also select rows. The table is rendered via tty-table and the selected row is overlaid with reverse-video ANSI styling.

Constant Summary collapse

KEY_ACTIONS =

Maps navigation keys to the instance methods that move the selection. Shared with List and Viewport via KeyboardHandler.

{
  up: :move_up,
  down: :move_down,
  home: :move_home,
  end: :move_end,
  page_up: :page_up,
  page_down: :page_down
}.freeze
HEADER_HEIGHT =

Number of terminal rows occupied by the table’s top border and header line. Used by the mouse handler to translate absolute row coordinates to body rows.

2

Constants included from KeyboardHandler

KeyboardHandler::VIM_KEYMAP

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Charming::Component

#captures_text?

Methods inherited from View

#focused?, #layout_assigns

Constructor Details

#initialize(header:, rows: [], selected_index: 0, keymap: :vim, theme: nil, height: nil) ⇒ Table

header is an array of column labels. rows is the array of body rows (each either a String, an Array, or a Hash of column-value pairs). selected_index defaults to 0. keymap selects the keybinding style (‘:vim` enables h/j/k/l → left/down/up/right). height optionally limits the visible body rows; the window auto-scrolls to keep the selection in view, and page up/down move by a full window.



36
37
38
39
40
41
42
43
# File 'lib/charming/presentation/components/table.rb', line 36

def initialize(header:, rows: [], selected_index: 0, keymap: :vim, theme: nil, height: nil)
  super(theme: theme)
  @header = Array(header).map(&:to_s)
  @rows = Array(rows)
  @selected_index = clamp_index(selected_index)
  @keymap = keymap
  @height = height
end

Instance Attribute Details

#headerObject (readonly)

The header row, the body rows, and the currently selected row index, respectively.



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

def header
  @header
end

#rowsObject (readonly)

The header row, the body rows, and the currently selected row index, respectively.



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

def rows
  @rows
end

#selected_indexObject (readonly)

The header row, the body rows, and the currently selected row index, respectively.



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

def selected_index
  @selected_index
end

Instance Method Details

#handle_key(event) ⇒ Object

Handles key events. Returns ‘[:selected, row]` on Enter; otherwise delegates to the KeyboardHandler for navigation keys.



47
48
49
50
51
52
53
54
# File 'lib/charming/presentation/components/table.rb', line 47

def handle_key(event)
  return nil if rows.empty?

  case Charming.key_of(event)
  when :enter then [:selected, selected_row]
  else super
  end
end

#handle_mouse(event) ⇒ Object

Handles mouse events: a click within the body area selects the clicked row (relative to the visible window when a height is set). Returns :handled on a successful click.



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

def handle_mouse(event)
  return nil if rows.empty?
  return nil unless event.respond_to?(:click?) && event.click?

  clicked = event.y - HEADER_HEIGHT
  return nil if clicked.negative? || clicked >= visible_row_count

  @selected_index = viewport_start + clicked
  :handled
end

#renderObject

Renders the table to a string. Returns a placeholder when both header and rows are empty.



76
77
78
79
80
81
82
83
84
85
# File 'lib/charming/presentation/components/table.rb', line 76

def render
  return "(empty table)" if header.empty? && rows.empty?

  normalized = rows.map { |row| normalize_row(row) }
  lines = TTY::Table.new(header: header, rows: normalized)
    .render(:unicode)
    .lines(chomp: true)

  compact_layout(lines)
end

#selected_rowObject

Returns the currently selected row, or nil when the table is empty.



71
72
73
# File 'lib/charming/presentation/components/table.rb', line 71

def selected_row
  rows[selected_index]
end