ratatui_ruby 0.9.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. checksums.yaml +4 -4
  2. data/.builds/ruby-3.2.yml +1 -1
  3. data/.builds/ruby-3.3.yml +1 -1
  4. data/.builds/ruby-3.4.yml +1 -1
  5. data/.builds/ruby-4.0.0.yml +1 -1
  6. data/AGENTS.md +2 -1
  7. data/CHANGELOG.md +98 -0
  8. data/REUSE.toml +5 -0
  9. data/Rakefile +1 -1
  10. data/Steepfile +49 -0
  11. data/doc/concepts/debugging.md +401 -0
  12. data/doc/getting_started/quickstart.md +8 -3
  13. data/doc/images/app_all_events.png +0 -0
  14. data/doc/images/app_color_picker.png +0 -0
  15. data/doc/images/app_debugging_showcase.gif +0 -0
  16. data/doc/images/app_debugging_showcase.png +0 -0
  17. data/doc/images/app_login_form.png +0 -0
  18. data/doc/images/app_stateful_interaction.png +0 -0
  19. data/doc/images/verify_quickstart_dsl.png +0 -0
  20. data/doc/images/verify_quickstart_layout.png +0 -0
  21. data/doc/images/verify_quickstart_lifecycle.png +0 -0
  22. data/doc/images/verify_readme_usage.png +0 -0
  23. data/doc/images/widget_barchart.png +0 -0
  24. data/doc/images/widget_block.png +0 -0
  25. data/doc/images/widget_box.png +0 -0
  26. data/doc/images/widget_calendar.png +0 -0
  27. data/doc/images/widget_canvas.png +0 -0
  28. data/doc/images/widget_cell.png +0 -0
  29. data/doc/images/widget_center.png +0 -0
  30. data/doc/images/widget_chart.png +0 -0
  31. data/doc/images/widget_gauge.png +0 -0
  32. data/doc/images/widget_layout_split.png +0 -0
  33. data/doc/images/widget_line_gauge.png +0 -0
  34. data/doc/images/widget_list.png +0 -0
  35. data/doc/images/widget_map.png +0 -0
  36. data/doc/images/widget_overlay.png +0 -0
  37. data/doc/images/widget_popup.png +0 -0
  38. data/doc/images/widget_ratatui_logo.png +0 -0
  39. data/doc/images/widget_ratatui_mascot.png +0 -0
  40. data/doc/images/widget_rect.png +0 -0
  41. data/doc/images/widget_render.png +0 -0
  42. data/doc/images/widget_rich_text.png +0 -0
  43. data/doc/images/widget_scroll_text.png +0 -0
  44. data/doc/images/widget_scrollbar.png +0 -0
  45. data/doc/images/widget_sparkline.png +0 -0
  46. data/doc/images/widget_style_colors.png +0 -0
  47. data/doc/images/widget_table.png +0 -0
  48. data/doc/images/widget_tabs.png +0 -0
  49. data/doc/images/widget_text_width.png +0 -0
  50. data/doc/troubleshooting/async.md +4 -0
  51. data/examples/app_debugging_showcase/README.md +119 -0
  52. data/examples/app_debugging_showcase/app.rb +318 -0
  53. data/examples/widget_canvas/app.rb +19 -14
  54. data/examples/widget_gauge/app.rb +18 -3
  55. data/examples/widget_layout_split/app.rb +10 -4
  56. data/examples/widget_list/app.rb +22 -6
  57. data/examples/widget_rect/app.rb +7 -6
  58. data/examples/widget_rich_text/app.rb +62 -37
  59. data/examples/widget_style_colors/app.rb +26 -47
  60. data/examples/widget_table/app.rb +28 -5
  61. data/examples/widget_text_width/app.rb +6 -4
  62. data/ext/ratatui_ruby/Cargo.lock +48 -1
  63. data/ext/ratatui_ruby/Cargo.toml +6 -2
  64. data/ext/ratatui_ruby/src/color.rs +82 -0
  65. data/ext/ratatui_ruby/src/errors.rs +28 -0
  66. data/ext/ratatui_ruby/src/events.rs +15 -14
  67. data/ext/ratatui_ruby/src/lib.rs +56 -0
  68. data/ext/ratatui_ruby/src/rendering.rs +3 -1
  69. data/ext/ratatui_ruby/src/style.rs +48 -21
  70. data/ext/ratatui_ruby/src/terminal.rs +40 -9
  71. data/ext/ratatui_ruby/src/text.rs +21 -9
  72. data/ext/ratatui_ruby/src/widgets/chart.rs +2 -1
  73. data/ext/ratatui_ruby/src/widgets/layout.rs +90 -2
  74. data/ext/ratatui_ruby/src/widgets/list.rs +6 -5
  75. data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
  76. data/ext/ratatui_ruby/src/widgets/table.rs +7 -6
  77. data/ext/ratatui_ruby/src/widgets/table_state.rs +55 -0
  78. data/ext/ratatui_ruby/src/widgets/tabs.rs +3 -2
  79. data/lib/ratatui_ruby/buffer/cell.rb +25 -15
  80. data/lib/ratatui_ruby/buffer.rb +134 -2
  81. data/lib/ratatui_ruby/cell.rb +13 -5
  82. data/lib/ratatui_ruby/debug.rb +215 -0
  83. data/lib/ratatui_ruby/event/key.rb +3 -2
  84. data/lib/ratatui_ruby/event.rb +1 -1
  85. data/lib/ratatui_ruby/layout/constraint.rb +49 -0
  86. data/lib/ratatui_ruby/layout/layout.rb +119 -13
  87. data/lib/ratatui_ruby/layout/position.rb +55 -0
  88. data/lib/ratatui_ruby/layout/rect.rb +188 -0
  89. data/lib/ratatui_ruby/layout/size.rb +55 -0
  90. data/lib/ratatui_ruby/layout.rb +4 -0
  91. data/lib/ratatui_ruby/style/color.rb +149 -0
  92. data/lib/ratatui_ruby/style/style.rb +51 -4
  93. data/lib/ratatui_ruby/style.rb +2 -0
  94. data/lib/ratatui_ruby/symbols.rb +435 -0
  95. data/lib/ratatui_ruby/synthetic_events.rb +1 -1
  96. data/lib/ratatui_ruby/table_state.rb +51 -0
  97. data/lib/ratatui_ruby/terminal_lifecycle.rb +2 -1
  98. data/lib/ratatui_ruby/test_helper/event_injection.rb +6 -1
  99. data/lib/ratatui_ruby/test_helper.rb +9 -0
  100. data/lib/ratatui_ruby/text/line.rb +245 -0
  101. data/lib/ratatui_ruby/text/span.rb +158 -0
  102. data/lib/ratatui_ruby/text.rb +99 -0
  103. data/lib/ratatui_ruby/tui/canvas_factories.rb +103 -0
  104. data/lib/ratatui_ruby/tui/core.rb +13 -2
  105. data/lib/ratatui_ruby/tui/layout_factories.rb +50 -3
  106. data/lib/ratatui_ruby/tui/state_factories.rb +42 -0
  107. data/lib/ratatui_ruby/tui/text_factories.rb +40 -0
  108. data/lib/ratatui_ruby/tui/widget_factories.rb +135 -60
  109. data/lib/ratatui_ruby/tui.rb +22 -1
  110. data/lib/ratatui_ruby/version.rb +1 -1
  111. data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +2 -0
  112. data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +2 -0
  113. data/lib/ratatui_ruby/widgets/bar_chart.rb +30 -20
  114. data/lib/ratatui_ruby/widgets/block.rb +14 -6
  115. data/lib/ratatui_ruby/widgets/calendar.rb +2 -0
  116. data/lib/ratatui_ruby/widgets/canvas.rb +56 -0
  117. data/lib/ratatui_ruby/widgets/cell.rb +2 -0
  118. data/lib/ratatui_ruby/widgets/center.rb +2 -0
  119. data/lib/ratatui_ruby/widgets/chart.rb +6 -0
  120. data/lib/ratatui_ruby/widgets/clear.rb +2 -0
  121. data/lib/ratatui_ruby/widgets/coerceable_widget.rb +77 -0
  122. data/lib/ratatui_ruby/widgets/cursor.rb +2 -0
  123. data/lib/ratatui_ruby/widgets/gauge.rb +61 -3
  124. data/lib/ratatui_ruby/widgets/line_gauge.rb +66 -4
  125. data/lib/ratatui_ruby/widgets/list.rb +87 -3
  126. data/lib/ratatui_ruby/widgets/list_item.rb +2 -0
  127. data/lib/ratatui_ruby/widgets/overlay.rb +2 -0
  128. data/lib/ratatui_ruby/widgets/paragraph.rb +4 -0
  129. data/lib/ratatui_ruby/widgets/ratatui_logo.rb +2 -0
  130. data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +2 -0
  131. data/lib/ratatui_ruby/widgets/row.rb +45 -0
  132. data/lib/ratatui_ruby/widgets/scrollbar.rb +2 -0
  133. data/lib/ratatui_ruby/widgets/shape/label.rb +2 -0
  134. data/lib/ratatui_ruby/widgets/sparkline.rb +21 -13
  135. data/lib/ratatui_ruby/widgets/table.rb +13 -3
  136. data/lib/ratatui_ruby/widgets/tabs.rb +6 -4
  137. data/lib/ratatui_ruby/widgets.rb +1 -0
  138. data/lib/ratatui_ruby.rb +40 -9
  139. data/sig/examples/app_all_events/model/app_model.rbs +23 -0
  140. data/sig/examples/app_all_events/model/event_entry.rbs +15 -8
  141. data/sig/examples/app_all_events/model/timestamp.rbs +1 -1
  142. data/sig/examples/app_all_events/view.rbs +1 -1
  143. data/sig/examples/app_stateful_interaction/app.rbs +5 -5
  144. data/sig/examples/widget_block_demo/app.rbs +6 -6
  145. data/sig/manifest.yaml +5 -0
  146. data/sig/patches/data.rbs +26 -0
  147. data/sig/patches/debugger__.rbs +8 -0
  148. data/sig/ratatui_ruby/buffer/cell.rbs +46 -0
  149. data/sig/ratatui_ruby/buffer.rbs +18 -0
  150. data/sig/ratatui_ruby/cell.rbs +44 -0
  151. data/sig/ratatui_ruby/clear.rbs +18 -0
  152. data/sig/ratatui_ruby/constraint.rbs +26 -0
  153. data/sig/ratatui_ruby/debug.rbs +45 -0
  154. data/sig/ratatui_ruby/draw.rbs +30 -0
  155. data/sig/ratatui_ruby/event.rbs +68 -8
  156. data/sig/ratatui_ruby/frame.rbs +4 -4
  157. data/sig/ratatui_ruby/interfaces.rbs +25 -0
  158. data/sig/ratatui_ruby/layout/constraint.rbs +39 -0
  159. data/sig/ratatui_ruby/layout/layout.rbs +45 -0
  160. data/sig/ratatui_ruby/layout/position.rbs +18 -0
  161. data/sig/ratatui_ruby/layout/rect.rbs +64 -0
  162. data/sig/ratatui_ruby/layout/size.rbs +18 -0
  163. data/sig/ratatui_ruby/output_guard.rbs +23 -0
  164. data/sig/ratatui_ruby/ratatui_ruby.rbs +83 -4
  165. data/sig/ratatui_ruby/rect.rbs +17 -0
  166. data/sig/ratatui_ruby/style/color.rbs +22 -0
  167. data/sig/ratatui_ruby/style/style.rbs +29 -0
  168. data/sig/ratatui_ruby/symbols.rbs +141 -0
  169. data/sig/ratatui_ruby/synthetic_events.rbs +21 -0
  170. data/sig/ratatui_ruby/table_state.rbs +6 -0
  171. data/sig/ratatui_ruby/terminal_lifecycle.rbs +31 -0
  172. data/sig/ratatui_ruby/test_helper/event_injection.rbs +2 -2
  173. data/sig/ratatui_ruby/test_helper/snapshot.rbs +22 -3
  174. data/sig/ratatui_ruby/test_helper/style_assertions.rbs +8 -1
  175. data/sig/ratatui_ruby/test_helper/test_doubles.rbs +7 -3
  176. data/sig/ratatui_ruby/text/line.rbs +27 -0
  177. data/sig/ratatui_ruby/text/span.rbs +23 -0
  178. data/sig/ratatui_ruby/text.rbs +12 -0
  179. data/sig/ratatui_ruby/tui/buffer_factories.rbs +1 -1
  180. data/sig/ratatui_ruby/tui/canvas_factories.rbs +23 -5
  181. data/sig/ratatui_ruby/tui/core.rbs +2 -2
  182. data/sig/ratatui_ruby/tui/layout_factories.rbs +16 -2
  183. data/sig/ratatui_ruby/tui/state_factories.rbs +8 -3
  184. data/sig/ratatui_ruby/tui/style_factories.rbs +3 -1
  185. data/sig/ratatui_ruby/tui/text_factories.rbs +7 -4
  186. data/sig/ratatui_ruby/tui/widget_factories.rbs +123 -30
  187. data/sig/ratatui_ruby/widgets/bar_chart.rbs +95 -0
  188. data/sig/ratatui_ruby/widgets/block.rbs +51 -0
  189. data/sig/ratatui_ruby/widgets/calendar.rbs +45 -0
  190. data/sig/ratatui_ruby/widgets/canvas.rbs +95 -0
  191. data/sig/ratatui_ruby/widgets/chart.rbs +91 -0
  192. data/sig/ratatui_ruby/widgets/coerceable_widget.rbs +26 -0
  193. data/sig/ratatui_ruby/widgets/gauge.rbs +44 -0
  194. data/sig/ratatui_ruby/widgets/line_gauge.rbs +48 -0
  195. data/sig/ratatui_ruby/widgets/list.rbs +63 -0
  196. data/sig/ratatui_ruby/widgets/misc.rbs +158 -0
  197. data/sig/ratatui_ruby/widgets/paragraph.rbs +45 -0
  198. data/sig/ratatui_ruby/widgets/row.rbs +43 -0
  199. data/sig/ratatui_ruby/widgets/scrollbar.rbs +53 -0
  200. data/sig/ratatui_ruby/widgets/shape/label.rbs +37 -0
  201. data/sig/ratatui_ruby/widgets/sparkline.rbs +45 -0
  202. data/sig/ratatui_ruby/widgets/table.rbs +78 -0
  203. data/sig/ratatui_ruby/widgets/tabs.rbs +44 -0
  204. data/sig/ratatui_ruby/{schema/list_item.rbs → widgets.rbs} +4 -4
  205. data/tasks/steep.rake +11 -0
  206. metadata +80 -63
  207. data/doc/contributors/v1.0.0_blockers.md +0 -870
  208. data/doc/troubleshooting/debugging.md +0 -101
  209. data/lib/ratatui_ruby/schema/bar_chart/bar.rb +0 -47
  210. data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +0 -25
  211. data/lib/ratatui_ruby/schema/bar_chart.rb +0 -287
  212. data/lib/ratatui_ruby/schema/block.rb +0 -198
  213. data/lib/ratatui_ruby/schema/calendar.rb +0 -84
  214. data/lib/ratatui_ruby/schema/canvas.rb +0 -239
  215. data/lib/ratatui_ruby/schema/center.rb +0 -67
  216. data/lib/ratatui_ruby/schema/chart.rb +0 -159
  217. data/lib/ratatui_ruby/schema/clear.rb +0 -62
  218. data/lib/ratatui_ruby/schema/constraint.rb +0 -151
  219. data/lib/ratatui_ruby/schema/cursor.rb +0 -50
  220. data/lib/ratatui_ruby/schema/gauge.rb +0 -72
  221. data/lib/ratatui_ruby/schema/layout.rb +0 -122
  222. data/lib/ratatui_ruby/schema/line_gauge.rb +0 -80
  223. data/lib/ratatui_ruby/schema/list.rb +0 -135
  224. data/lib/ratatui_ruby/schema/list_item.rb +0 -51
  225. data/lib/ratatui_ruby/schema/overlay.rb +0 -51
  226. data/lib/ratatui_ruby/schema/paragraph.rb +0 -107
  227. data/lib/ratatui_ruby/schema/ratatui_logo.rb +0 -31
  228. data/lib/ratatui_ruby/schema/ratatui_mascot.rb +0 -36
  229. data/lib/ratatui_ruby/schema/rect.rb +0 -174
  230. data/lib/ratatui_ruby/schema/row.rb +0 -76
  231. data/lib/ratatui_ruby/schema/scrollbar.rb +0 -143
  232. data/lib/ratatui_ruby/schema/shape/label.rb +0 -76
  233. data/lib/ratatui_ruby/schema/sparkline.rb +0 -142
  234. data/lib/ratatui_ruby/schema/style.rb +0 -97
  235. data/lib/ratatui_ruby/schema/table.rb +0 -141
  236. data/lib/ratatui_ruby/schema/tabs.rb +0 -85
  237. data/lib/ratatui_ruby/schema/text.rb +0 -217
  238. data/sig/examples/app_all_events/model/events.rbs +0 -15
  239. data/sig/examples/app_all_events/view_state.rbs +0 -21
  240. data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +0 -22
  241. data/sig/ratatui_ruby/schema/bar_chart/bar_group.rbs +0 -19
  242. data/sig/ratatui_ruby/schema/bar_chart.rbs +0 -38
  243. data/sig/ratatui_ruby/schema/block.rbs +0 -18
  244. data/sig/ratatui_ruby/schema/calendar.rbs +0 -23
  245. data/sig/ratatui_ruby/schema/canvas.rbs +0 -81
  246. data/sig/ratatui_ruby/schema/center.rbs +0 -17
  247. data/sig/ratatui_ruby/schema/chart.rbs +0 -39
  248. data/sig/ratatui_ruby/schema/constraint.rbs +0 -30
  249. data/sig/ratatui_ruby/schema/cursor.rbs +0 -16
  250. data/sig/ratatui_ruby/schema/draw.rbs +0 -33
  251. data/sig/ratatui_ruby/schema/gauge.rbs +0 -23
  252. data/sig/ratatui_ruby/schema/layout.rbs +0 -27
  253. data/sig/ratatui_ruby/schema/line_gauge.rbs +0 -24
  254. data/sig/ratatui_ruby/schema/list.rbs +0 -28
  255. data/sig/ratatui_ruby/schema/overlay.rbs +0 -15
  256. data/sig/ratatui_ruby/schema/paragraph.rbs +0 -20
  257. data/sig/ratatui_ruby/schema/ratatui_logo.rbs +0 -14
  258. data/sig/ratatui_ruby/schema/ratatui_mascot.rbs +0 -17
  259. data/sig/ratatui_ruby/schema/rect.rbs +0 -48
  260. data/sig/ratatui_ruby/schema/row.rbs +0 -28
  261. data/sig/ratatui_ruby/schema/scrollbar.rbs +0 -42
  262. data/sig/ratatui_ruby/schema/sparkline.rbs +0 -22
  263. data/sig/ratatui_ruby/schema/style.rbs +0 -19
  264. data/sig/ratatui_ruby/schema/table.rbs +0 -32
  265. data/sig/ratatui_ruby/schema/tabs.rbs +0 -21
  266. data/sig/ratatui_ruby/schema/text.rbs +0 -31
  267. /data/lib/ratatui_ruby/{schema/draw.rb → draw.rb} +0 -0
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ # SPDX-License-Identifier: AGPL-3.0-or-later
9
+
10
+ module RatatuiRuby
11
+ module Widgets
12
+ # Options hash type for List constructor arguments.
13
+ type list_options = {
14
+ ?items: Array[String | Text::Span | Text::Line | ListItem],
15
+ ?selected_index: _ToI?,
16
+ ?offset: _ToI?,
17
+ ?style: Style::Style?,
18
+ ?highlight_style: Style::Style?,
19
+ ?highlight_symbol: String?,
20
+ ?repeat_highlight_symbol: bool,
21
+ ?highlight_spacing: Symbol,
22
+ ?direction: Symbol,
23
+ ?scroll_padding: _ToI?,
24
+ ?block: Widgets::Block?
25
+ }
26
+
27
+ class List < Data
28
+ HIGHLIGHT_ALWAYS: Symbol
29
+ HIGHLIGHT_WHEN_SELECTED: Symbol
30
+ HIGHLIGHT_NEVER: Symbol
31
+ DIRECTION_TOP_TO_BOTTOM: Symbol
32
+ DIRECTION_BOTTOM_TO_TOP: Symbol
33
+
34
+ attr_reader items: Array[String | Text::Span | Text::Line | ListItem]
35
+ attr_reader selected_index: Integer?
36
+ attr_reader offset: Integer?
37
+ attr_reader style: Style::Style?
38
+ attr_reader highlight_style: Style::Style?
39
+ attr_reader highlight_symbol: String?
40
+ attr_reader repeat_highlight_symbol: bool
41
+ attr_reader highlight_spacing: Symbol
42
+ attr_reader direction: Symbol
43
+ attr_reader scroll_padding: Integer?
44
+ attr_reader block: Widgets::Block?
45
+
46
+ include CoerceableWidget
47
+
48
+ def self.coerce_args: (list_options first, ?list_options kwargs) -> List
49
+ | (nil first, list_options kwargs) -> List
50
+
51
+ def self.new: (?items: Array[String | Text::Span | Text::Line | ListItem], ?selected_index: _ToI?, ?offset: _ToI?, ?style: Style::Style?, ?highlight_style: Style::Style?, ?highlight_symbol: String?, ?repeat_highlight_symbol: bool, ?highlight_spacing: Symbol, ?direction: Symbol, ?scroll_padding: _ToI?, ?block: Widgets::Block?) -> List
52
+ def initialize: (?items: Array[String | Text::Span | Text::Line | ListItem], ?selected_index: _ToI?, ?offset: _ToI?, ?style: Style::Style?, ?highlight_style: Style::Style?, ?highlight_symbol: String?, ?repeat_highlight_symbol: bool, ?highlight_spacing: Symbol, ?direction: Symbol, ?scroll_padding: _ToI?, ?block: Widgets::Block?) -> void
53
+
54
+ def selected?: () -> bool
55
+ def empty?: () -> bool
56
+ def len: () -> Integer
57
+ alias length len
58
+ alias size len
59
+ # NOTE: No 'selection' alias - use selected_index or selected_item
60
+ def selected_item: () -> (String | Text::Span | Text::Line | ListItem)?
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ # SPDX-License-Identifier: AGPL-3.0-or-later
9
+
10
+ module RatatuiRuby
11
+ module Widgets
12
+ # Options hash type for Cell constructor arguments.
13
+ type cell_options = {
14
+ ?content: String | Text::Span | Text::Line | Paragraph,
15
+ ?style: Style::Style?
16
+ }
17
+
18
+ # Options hash type for Center constructor arguments.
19
+ type center_options = {
20
+ ?child: widget,
21
+ ?width_percent: _ToF,
22
+ ?height_percent: _ToF
23
+ }
24
+
25
+ # Options hash type for Cursor constructor arguments.
26
+ type cursor_options = {
27
+ ?x: _ToI,
28
+ ?y: _ToI
29
+ }
30
+
31
+ # NOTE: line_gauge_options and LineGauge are now defined in line_gauge.rbs
32
+
33
+ # Options hash type for ListItem constructor arguments.
34
+ type list_item_options = {
35
+ ?content: String | Text::Span | Text::Line,
36
+ ?style: Style::Style?
37
+ }
38
+
39
+ # Options hash type for Overlay constructor arguments.
40
+ type overlay_options = {
41
+ ?layers: Array[widget]
42
+ }
43
+
44
+ # Options hash type for Clear constructor arguments.
45
+ type clear_options = {
46
+ ?block: Widgets::Block?
47
+ }
48
+
49
+ # Options hash type for RatatuiLogo constructor arguments (empty).
50
+ type ratatui_logo_options = { }
51
+
52
+ # Options hash type for RatatuiMascot constructor arguments.
53
+ type ratatui_mascot_options = {
54
+ ?block: Widgets::Block?
55
+ }
56
+
57
+ class Cell < Data
58
+ attr_reader content: String | Text::Span | Text::Line | Paragraph
59
+ attr_reader style: Style::Style?
60
+
61
+ include CoerceableWidget
62
+
63
+ def self.coerce_args: (cell_options first, ?cell_options kwargs) -> Cell
64
+ | (nil first, cell_options kwargs) -> Cell
65
+
66
+ def self.new: (content: String | Text::Span | Text::Line | Paragraph, ?style: Style::Style?) -> Cell
67
+ def initialize: (content: String | Text::Span | Text::Line | Paragraph, ?style: Style::Style?) -> void
68
+ end
69
+
70
+ class Center < Data
71
+ attr_reader child: widget
72
+ attr_reader width_percent: Float
73
+ attr_reader height_percent: Float
74
+
75
+ include CoerceableWidget
76
+
77
+ def self.coerce_args: (center_options first, ?center_options kwargs) -> Center
78
+ | (nil first, center_options kwargs) -> Center
79
+
80
+ def self.new: (child: widget, ?width_percent: _ToF, ?height_percent: _ToF) -> Center
81
+ def initialize: (child: widget, ?width_percent: _ToF, ?height_percent: _ToF) -> void
82
+ end
83
+
84
+ class Cursor < Data
85
+ attr_reader x: Integer
86
+ attr_reader y: Integer
87
+
88
+ include CoerceableWidget
89
+
90
+ def self.coerce_args: (cursor_options first, ?cursor_options kwargs) -> Cursor
91
+ | (nil first, cursor_options kwargs) -> Cursor
92
+
93
+ def self.new: (x: _ToI, y: _ToI) -> Cursor
94
+ def initialize: (x: _ToI, y: _ToI) -> void
95
+ end
96
+
97
+ # NOTE: LineGauge is now defined in line_gauge.rbs
98
+
99
+ class ListItem < Data
100
+ attr_reader content: String | Text::Span | Text::Line
101
+ attr_reader style: Style::Style?
102
+
103
+ include CoerceableWidget
104
+
105
+ def self.coerce_args: (list_item_options first, ?list_item_options kwargs) -> ListItem
106
+ | (nil first, list_item_options kwargs) -> ListItem
107
+
108
+ def self.new: (content: String | Text::Span | Text::Line, ?style: Style::Style?) -> ListItem
109
+ def initialize: (content: String | Text::Span | Text::Line, ?style: Style::Style?) -> void
110
+ end
111
+
112
+ class Overlay < Data
113
+ attr_reader layers: Array[widget]
114
+
115
+ include CoerceableWidget
116
+
117
+ def self.coerce_args: (overlay_options first, ?overlay_options kwargs) -> Overlay
118
+ | (nil first, overlay_options kwargs) -> Overlay
119
+
120
+ def self.new: (?layers: Array[widget]) -> Overlay
121
+ def initialize: (?layers: Array[widget]) -> void
122
+ end
123
+
124
+ class Clear < Data
125
+ attr_reader block: Widgets::Block?
126
+
127
+ include CoerceableWidget
128
+
129
+ def self.coerce_args: (clear_options first, ?clear_options kwargs) -> Clear
130
+ | (nil first, clear_options kwargs) -> Clear
131
+
132
+ def self.new: (?block: Widgets::Block?) -> Clear
133
+ def initialize: (?block: Widgets::Block?) -> void
134
+ end
135
+
136
+ class RatatuiLogo < Data
137
+ include CoerceableWidget
138
+
139
+ def self.coerce_args: (ratatui_logo_options first, ?ratatui_logo_options kwargs) -> RatatuiLogo
140
+ | (nil first, ratatui_logo_options kwargs) -> RatatuiLogo
141
+
142
+ def self.new: () -> RatatuiLogo
143
+ def initialize: () -> void
144
+ end
145
+
146
+ class RatatuiMascot < Data
147
+ attr_reader block: Widgets::Block?
148
+
149
+ include CoerceableWidget
150
+
151
+ def self.coerce_args: (ratatui_mascot_options first, ?ratatui_mascot_options kwargs) -> RatatuiMascot
152
+ | (nil first, ratatui_mascot_options kwargs) -> RatatuiMascot
153
+
154
+ def self.new: (?block: Widgets::Block?) -> RatatuiMascot
155
+ def initialize: (?block: Widgets::Block?) -> void
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ # SPDX-License-Identifier: AGPL-3.0-or-later
9
+
10
+ module RatatuiRuby
11
+ module Widgets
12
+ # Options hash type for Paragraph constructor arguments.
13
+ type paragraph_options = {
14
+ ?text: String,
15
+ ?style: Style::Style?,
16
+ ?fg: (String | Symbol)?,
17
+ ?bg: (String | Symbol)?,
18
+ ?block: Widgets::Block?,
19
+ ?wrap: bool,
20
+ ?alignment: Symbol,
21
+ ?scroll: [_ToI, _ToI]
22
+ }
23
+
24
+ class Paragraph < Data
25
+ attr_reader text: String
26
+ attr_reader style: Style::Style?
27
+ attr_reader block: Widgets::Block?
28
+ attr_reader wrap: bool
29
+ attr_reader alignment: Symbol
30
+ attr_reader scroll: [Integer, Integer]
31
+
32
+ include CoerceableWidget
33
+
34
+ def self.coerce_args: (paragraph_options first, ?paragraph_options kwargs) -> Paragraph
35
+ | (nil first, paragraph_options kwargs) -> Paragraph
36
+
37
+ # Legacy constructor with fg/bg convenience params
38
+ def self.new: (text: String, ?style: Style::Style?, ?fg: (String | Symbol)?, ?bg: (String | Symbol)?, ?block: Widgets::Block?, ?wrap: bool, ?alignment: Symbol, ?scroll: [_ToI, _ToI]) -> Paragraph
39
+ # Instance initialize
40
+ def initialize: (?text: String, ?style: Style::Style?, ?block: Widgets::Block?, ?wrap: bool, ?alignment: Symbol, ?scroll: Array[Integer]) -> void
41
+ def line_count: (Integer width) -> Integer
42
+ def line_width: () -> Integer
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ # SPDX-License-Identifier: AGPL-3.0-or-later
9
+
10
+ module RatatuiRuby
11
+ module Widgets
12
+ # Options hash type for Row constructor arguments.
13
+ type row_options = {
14
+ ?cells: Array[Row::cell_content],
15
+ ?style: Style::Style?,
16
+ ?height: Integer?,
17
+ ?top_margin: Integer?,
18
+ ?bottom_margin: Integer?
19
+ }
20
+
21
+ class Row < Data
22
+ type cell_content = String | Text::Span | Text::Line | Paragraph | Cell
23
+
24
+ attr_reader cells: Array[cell_content]
25
+ attr_reader style: Style::Style?
26
+ attr_reader height: Integer?
27
+ attr_reader top_margin: Integer?
28
+ attr_reader bottom_margin: Integer?
29
+
30
+ include CoerceableWidget
31
+
32
+ def self.coerce_args: (row_options first, ?row_options kwargs) -> Row
33
+ | (nil first, row_options kwargs) -> Row
34
+
35
+ def self.new: (cells: Array[cell_content], ?style: Style::Style?, ?height: Integer?, ?top_margin: Integer?, ?bottom_margin: Integer?) -> Row
36
+ def initialize: (cells: Array[cell_content], ?style: Style::Style?, ?height: Integer?, ?top_margin: Integer?, ?bottom_margin: Integer?) -> void
37
+
38
+ # Returns a new Row with strikethrough styling enabled.
39
+ def enable_strikethrough: () -> Row
40
+ alias strikethrough enable_strikethrough
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ # SPDX-License-Identifier: AGPL-3.0-or-later
9
+
10
+ module RatatuiRuby
11
+ module Widgets
12
+ # Options hash type for Scrollbar constructor arguments.
13
+ type scrollbar_options = {
14
+ ?content_length: _ToI,
15
+ ?position: _ToI,
16
+ ?orientation: Symbol,
17
+ ?thumb_symbol: String,
18
+ ?thumb_style: Style::Style?,
19
+ ?track_symbol: String?,
20
+ ?track_style: Style::Style?,
21
+ ?begin_symbol: String?,
22
+ ?begin_style: Style::Style?,
23
+ ?end_symbol: String?,
24
+ ?end_style: Style::Style?,
25
+ ?style: Style::Style?,
26
+ ?block: Widgets::Block?
27
+ }
28
+
29
+ class Scrollbar < Data
30
+ attr_reader content_length: Integer
31
+ attr_reader position: Integer
32
+ attr_reader orientation: Symbol
33
+ attr_reader thumb_symbol: String
34
+ attr_reader thumb_style: Style::Style?
35
+ attr_reader track_symbol: String?
36
+ attr_reader track_style: Style::Style?
37
+ attr_reader begin_symbol: String?
38
+ attr_reader begin_style: Style::Style?
39
+ attr_reader end_symbol: String?
40
+ attr_reader end_style: Style::Style?
41
+ attr_reader style: Style::Style?
42
+ attr_reader block: Widgets::Block?
43
+
44
+ include CoerceableWidget
45
+
46
+ def self.coerce_args: (scrollbar_options first, ?scrollbar_options kwargs) -> Scrollbar
47
+ | (nil first, scrollbar_options kwargs) -> Scrollbar
48
+
49
+ def self.new: (content_length: _ToI, position: _ToI, ?orientation: Symbol, ?thumb_symbol: String, ?thumb_style: Style::Style?, ?track_symbol: String?, ?track_style: Style::Style?, ?begin_symbol: String?, ?begin_style: Style::Style?, ?end_symbol: String?, ?end_style: Style::Style?, ?style: Style::Style?, ?block: Widgets::Block?) -> Scrollbar
50
+ def initialize: (content_length: _ToI, position: _ToI, ?orientation: Symbol, ?thumb_symbol: String, ?thumb_style: Style::Style?, ?track_symbol: String?, ?track_style: Style::Style?, ?begin_symbol: String?, ?begin_style: Style::Style?, ?end_symbol: String?, ?end_style: Style::Style?, ?style: Style::Style?, ?block: Widgets::Block?) -> void
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ # SPDX-License-Identifier: AGPL-3.0-or-later
9
+
10
+ module RatatuiRuby
11
+ module Widgets
12
+ module Shape
13
+ # Options hash type for Shape::Label constructor arguments.
14
+ type label_options = {
15
+ ?x: _ToF,
16
+ ?y: _ToF,
17
+ ?text: String | Text::Line,
18
+ ?style: Style::Style?
19
+ }
20
+
21
+ class Label < Data
22
+ attr_reader x: Float
23
+ attr_reader y: Float
24
+ attr_reader text: String | Text::Line
25
+ attr_reader style: Style::Style?
26
+
27
+ include CoerceableWidget
28
+
29
+ def self.coerce_args: (label_options first, ?label_options kwargs) -> Label
30
+ | (nil first, label_options kwargs) -> Label
31
+
32
+ def self.new: (x: _ToF, y: _ToF, text: String | Text::Line, ?style: Style::Style?) -> Label
33
+ def initialize: (x: _ToF, y: _ToF, text: String | Text::Line, ?style: Style::Style?) -> void
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ # SPDX-License-Identifier: AGPL-3.0-or-later
9
+
10
+ module RatatuiRuby
11
+ module Widgets
12
+ # Options hash type for Sparkline constructor arguments.
13
+ type sparkline_options = {
14
+ ?data: Array[_ToI?],
15
+ ?max: _ToI?,
16
+ ?style: Style::Style?,
17
+ ?block: Widgets::Block?,
18
+ ?direction: (:left_to_right | :right_to_left)?,
19
+ ?absent_value_symbol: String?,
20
+ ?absent_value_style: Style::Style?,
21
+ ?bar_set: Hash[Symbol, String]?
22
+ }
23
+
24
+ class Sparkline < Data
25
+ BAR_KEYS: Array[Symbol]
26
+
27
+ attr_reader data: Array[Integer?]
28
+ attr_reader max: Integer?
29
+ attr_reader style: Style::Style?
30
+ attr_reader block: Widgets::Block?
31
+ attr_reader direction: (:left_to_right | :right_to_left)?
32
+ attr_reader absent_value_symbol: String?
33
+ attr_reader absent_value_style: Style::Style?
34
+ attr_reader bar_set: Hash[Symbol, String]?
35
+
36
+ include CoerceableWidget
37
+
38
+ def self.coerce_args: (sparkline_options first, ?sparkline_options kwargs) -> Sparkline
39
+ | (nil first, sparkline_options kwargs) -> Sparkline
40
+
41
+ def self.new: (data: Array[_ToI?], ?max: _ToI?, ?style: Style::Style?, ?block: Widgets::Block?, ?direction: (:left_to_right | :right_to_left)?, ?absent_value_symbol: String?, ?absent_value_style: Style::Style?, ?bar_set: Hash[Symbol, String]?) -> Sparkline
42
+ def initialize: (data: Array[_ToI?], ?max: _ToI?, ?style: Style::Style?, ?block: Widgets::Block?, ?direction: (:left_to_right | :right_to_left)?, ?absent_value_symbol: String?, ?absent_value_style: Style::Style?, ?bar_set: Hash[Symbol, String]?) -> void
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ # SPDX-License-Identifier: AGPL-3.0-or-later
9
+
10
+ module RatatuiRuby
11
+ module Widgets
12
+ # Options hash type for Table constructor arguments.
13
+ # Used by coerce_args for DWIM bare-hash acceptance.
14
+ type table_options = {
15
+ ?header: Array[String | Paragraph]?,
16
+ ?rows: Array[Array[String | Paragraph | Style::Style | _ToS]],
17
+ ?widths: Array[Layout::Constraint | Integer],
18
+ ?row_highlight_style: Style::Style?,
19
+ ?highlight_symbol: String?,
20
+ ?highlight_spacing: Symbol,
21
+ ?column_highlight_style: Style::Style?,
22
+ ?cell_highlight_style: Style::Style?,
23
+ ?selected_row: _ToI?,
24
+ ?selected_column: _ToI?,
25
+ ?offset: _ToI?,
26
+ ?block: Widgets::Block?,
27
+ ?footer: Array[String | Paragraph]?,
28
+ ?flex: Symbol,
29
+ ?style: style_input?,
30
+ ?column_spacing: _ToI
31
+ }
32
+
33
+ class Table < Data
34
+ HIGHLIGHT_ALWAYS: Symbol
35
+ HIGHLIGHT_WHEN_SELECTED: Symbol
36
+ HIGHLIGHT_NEVER: Symbol
37
+ FLEX_LEGACY: Symbol
38
+ FLEX_START: Symbol
39
+ FLEX_CENTER: Symbol
40
+ FLEX_END: Symbol
41
+ FLEX_SPACE_BETWEEN: Symbol
42
+ FLEX_SPACE_AROUND: Symbol
43
+ FLEX_SPACE_EVENLY: Symbol
44
+
45
+ attr_reader header: Array[String | Paragraph]?
46
+ attr_reader rows: Array[Array[String | Paragraph | Style::Style | _ToS]]
47
+ attr_reader widths: Array[Layout::Constraint]
48
+ attr_reader block: Widgets::Block?
49
+ attr_reader footer: Array[String | Paragraph]?
50
+ attr_reader flex: Symbol
51
+ attr_reader style: style_input?
52
+ attr_reader column_spacing: Integer?
53
+ attr_reader highlight_spacing: Symbol
54
+ attr_reader column_highlight_style: Style::Style?
55
+ attr_reader selected_column: Integer?
56
+ attr_reader offset: Integer?
57
+ attr_reader row_highlight_style: Style::Style?
58
+ attr_reader highlight_symbol: String?
59
+ attr_reader cell_highlight_style: Style::Style?
60
+ attr_reader selected_row: Integer?
61
+
62
+ include CoerceableWidget
63
+
64
+ # DWIM hash coercion: accepts bare Hash (first arg) or keyword arguments.
65
+ def self.coerce_args: (table_options first, ?table_options kwargs) -> Table
66
+ | (nil first, table_options kwargs) -> Table
67
+
68
+ def self.new: (?header: Array[String | Paragraph]?, ?rows: Array[Array[String | Paragraph | Style::Style | _ToS]], ?widths: Array[Layout::Constraint | Integer], ?row_highlight_style: Style::Style?, ?highlight_symbol: String?, ?highlight_spacing: Symbol, ?column_highlight_style: Style::Style?, ?cell_highlight_style: Style::Style?, ?selected_row: _ToI?, ?selected_column: _ToI?, ?offset: _ToI?, ?block: Widgets::Block?, ?footer: Array[String | Paragraph]?, ?flex: Symbol, ?style: style_input?, ?column_spacing: _ToI) -> Table
69
+ def initialize: (?header: Array[String | Paragraph]?, ?rows: Array[Array[String | Paragraph | Style::Style | _ToS]], ?widths: Array[Layout::Constraint | Integer], ?row_highlight_style: Style::Style?, ?highlight_symbol: String?, ?highlight_spacing: Symbol, ?column_highlight_style: Style::Style?, ?cell_highlight_style: Style::Style?, ?selected_row: _ToI?, ?selected_column: _ToI?, ?offset: _ToI?, ?block: Widgets::Block?, ?footer: Array[String | Paragraph]?, ?flex: Symbol, ?style: style_input?, ?column_spacing: _ToI) -> void
70
+
71
+ def row_selected?: () -> bool
72
+ def column_selected?: () -> bool
73
+ def cell_selected?: () -> bool
74
+ def empty?: () -> bool
75
+ # NOTE: No 'selection' alias - use selected_row or selected_column
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ # SPDX-License-Identifier: AGPL-3.0-or-later
9
+
10
+ module RatatuiRuby
11
+ module Widgets
12
+ # Options hash type for Tabs constructor arguments.
13
+ type tabs_options = {
14
+ ?titles: Array[String | _ToS],
15
+ ?selected_index: _ToI,
16
+ ?block: Widgets::Block?,
17
+ ?divider: String?,
18
+ ?highlight_style: Style::Style?,
19
+ ?style: Style::Style?,
20
+ ?padding_left: (String | Text::Line | _ToI),
21
+ ?padding_right: (String | Text::Line | _ToI)
22
+ }
23
+
24
+ class Tabs < Data
25
+ attr_reader titles: Array[String | _ToS]
26
+ attr_reader selected_index: Integer
27
+ attr_reader block: Widgets::Block?
28
+ attr_reader divider: String?
29
+ attr_reader highlight_style: Style::Style?
30
+ attr_reader style: Style::Style?
31
+ attr_reader padding_left: Integer
32
+ attr_reader padding_right: Integer
33
+
34
+ include CoerceableWidget
35
+
36
+ def self.coerce_args: (tabs_options first, ?tabs_options kwargs) -> Tabs
37
+ | (nil first, tabs_options kwargs) -> Tabs
38
+
39
+ def self.new: (?titles: Array[String | _ToS], ?selected_index: _ToI, ?block: Widgets::Block?, ?divider: String?, ?highlight_style: Style::Style?, ?style: Style::Style?, ?padding_left: (String | Text::Line | _ToI), ?padding_right: (String | Text::Line | _ToI)) -> Tabs
40
+ def initialize: (?titles: Array[String | _ToS], ?selected_index: _ToI, ?block: Widgets::Block?, ?divider: String?, ?highlight_style: Style::Style?, ?style: Style::Style?, ?padding_left: (String | Text::Line | _ToI), ?padding_right: (String | Text::Line | _ToI)) -> void
41
+ def width: () -> Integer
42
+ end
43
+ end
44
+ end
@@ -8,9 +8,9 @@
8
8
  # SPDX-License-Identifier: AGPL-3.0-or-later
9
9
 
10
10
  module RatatuiRuby
11
- class ListItem < Data
12
- attr_reader content: String | Text::Span | Text::Line
13
- attr_reader style: Style?
14
- def self.new: (content: String | Text::Span | Text::Line, ?style: Style?) -> ListItem
11
+ module Widgets
12
+ # Widget interface - any object with a widget-like render contract
13
+ interface _Widget
14
+ end
15
15
  end
16
16
  end
data/tasks/steep.rake ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
7
+
8
+ desc "Run Steep type checker"
9
+ task :steep do
10
+ sh "bundle exec steep check"
11
+ end