ratatui_ruby 0.4.0 → 0.6.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 (441) 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 +98 -176
  7. data/CHANGELOG.md +80 -6
  8. data/README.md +19 -7
  9. data/REUSE.toml +15 -0
  10. data/doc/application_architecture.md +179 -45
  11. data/doc/application_testing.md +80 -32
  12. data/doc/contributors/design/ruby_frontend.md +48 -8
  13. data/doc/contributors/design/rust_backend.md +1 -0
  14. data/doc/contributors/developing_examples.md +191 -48
  15. data/doc/contributors/documentation_style.md +7 -0
  16. data/doc/contributors/examples_audit/p1_high.md +21 -0
  17. data/doc/contributors/examples_audit/p2_moderate.md +81 -0
  18. data/doc/contributors/examples_audit.md +41 -0
  19. data/doc/contributors/index.md +2 -0
  20. data/doc/event_handling.md +21 -7
  21. data/doc/images/app_all_events.png +0 -0
  22. data/doc/images/app_color_picker.png +0 -0
  23. data/doc/images/app_login_form.png +0 -0
  24. data/doc/images/app_stateful_interaction.png +0 -0
  25. data/doc/images/verify_quickstart_dsl.png +0 -0
  26. data/doc/images/verify_quickstart_layout.png +0 -0
  27. data/doc/images/verify_quickstart_lifecycle.png +0 -0
  28. data/doc/images/verify_readme_usage.png +0 -0
  29. data/doc/images/widget_barchart_demo.png +0 -0
  30. data/doc/images/widget_block_demo.png +0 -0
  31. data/doc/images/widget_box_demo.png +0 -0
  32. data/doc/images/widget_calendar_demo.png +0 -0
  33. data/doc/images/widget_canvas_demo.png +0 -0
  34. data/doc/images/widget_cell_demo.png +0 -0
  35. data/doc/images/widget_center_demo.png +0 -0
  36. data/doc/images/widget_chart_demo.png +0 -0
  37. data/doc/images/widget_gauge_demo.png +0 -0
  38. data/doc/images/widget_layout_split.png +0 -0
  39. data/doc/images/widget_line_gauge_demo.png +0 -0
  40. data/doc/images/widget_list_demo.png +0 -0
  41. data/doc/images/widget_overlay_demo.png +0 -0
  42. data/doc/images/widget_ratatui_logo_demo.png +0 -0
  43. data/doc/images/widget_ratatui_mascot_demo.png +0 -0
  44. data/doc/images/widget_render.png +0 -0
  45. data/doc/images/widget_rich_text.png +0 -0
  46. data/doc/images/widget_scroll_text.png +0 -0
  47. data/doc/images/widget_scrollbar_demo.png +0 -0
  48. data/doc/images/widget_sparkline_demo.png +0 -0
  49. data/doc/images/widget_style_colors.png +0 -0
  50. data/doc/images/widget_table_demo.png +0 -0
  51. data/doc/images/widget_table_flex.png +0 -0
  52. data/doc/images/widget_tabs_demo.png +0 -0
  53. data/doc/images/widget_text_width.png +0 -0
  54. data/doc/interactive_design.md +25 -30
  55. data/doc/quickstart.md +150 -130
  56. data/doc/terminal_limitations.md +92 -0
  57. data/examples/app_all_events/README.md +99 -0
  58. data/examples/app_all_events/app.rb +96 -0
  59. data/examples/app_all_events/model/app_model.rb +157 -0
  60. data/examples/app_all_events/model/event_color_cycle.rb +41 -0
  61. data/examples/app_all_events/model/event_entry.rb +92 -0
  62. data/examples/app_all_events/model/msg.rb +37 -0
  63. data/examples/app_all_events/model/timestamp.rb +54 -0
  64. data/examples/app_all_events/update.rb +73 -0
  65. data/examples/app_all_events/view/app_view.rb +78 -0
  66. data/examples/app_all_events/view/controls_view.rb +52 -0
  67. data/examples/app_all_events/view/counts_view.rb +59 -0
  68. data/examples/app_all_events/view/live_view.rb +70 -0
  69. data/examples/app_all_events/view/log_view.rb +55 -0
  70. data/examples/app_all_events/view.rb +7 -0
  71. data/examples/app_color_picker/README.md +134 -0
  72. data/examples/app_color_picker/app.rb +74 -0
  73. data/examples/app_color_picker/clipboard.rb +84 -0
  74. data/examples/app_color_picker/color.rb +191 -0
  75. data/examples/app_color_picker/controls.rb +90 -0
  76. data/examples/app_color_picker/copy_dialog.rb +166 -0
  77. data/examples/app_color_picker/export_pane.rb +126 -0
  78. data/examples/app_color_picker/harmony.rb +56 -0
  79. data/examples/app_color_picker/input.rb +174 -0
  80. data/examples/app_color_picker/main_container.rb +178 -0
  81. data/examples/app_color_picker/palette.rb +109 -0
  82. data/examples/app_login_form/README.md +47 -0
  83. data/examples/{login_form → app_login_form}/app.rb +38 -42
  84. data/examples/app_stateful_interaction/README.md +31 -0
  85. data/examples/app_stateful_interaction/app.rb +272 -0
  86. data/examples/timeout_demo.rb +43 -0
  87. data/examples/verify_quickstart_dsl/README.md +48 -0
  88. data/examples/{quickstart_dsl → verify_quickstart_dsl}/app.rb +17 -6
  89. data/examples/verify_quickstart_layout/README.md +71 -0
  90. data/examples/verify_quickstart_layout/app.rb +71 -0
  91. data/examples/verify_quickstart_lifecycle/README.md +56 -0
  92. data/examples/verify_quickstart_lifecycle/app.rb +54 -0
  93. data/examples/verify_readme_usage/README.md +43 -0
  94. data/examples/verify_readme_usage/app.rb +40 -0
  95. data/examples/widget_barchart_demo/README.md +49 -0
  96. data/examples/widget_barchart_demo/app.rb +238 -0
  97. data/examples/widget_block_demo/README.md +34 -0
  98. data/examples/widget_block_demo/app.rb +256 -0
  99. data/examples/widget_box_demo/README.md +45 -0
  100. data/examples/{box_demo → widget_box_demo}/app.rb +99 -65
  101. data/examples/widget_calendar_demo/README.md +39 -0
  102. data/examples/widget_calendar_demo/app.rb +109 -0
  103. data/examples/widget_canvas_demo/README.md +27 -0
  104. data/examples/widget_canvas_demo/app.rb +123 -0
  105. data/examples/widget_cell_demo/README.md +36 -0
  106. data/examples/widget_cell_demo/app.rb +111 -0
  107. data/examples/widget_center_demo/README.md +29 -0
  108. data/examples/widget_center_demo/app.rb +116 -0
  109. data/examples/widget_chart_demo/README.md +41 -0
  110. data/examples/widget_chart_demo/app.rb +218 -0
  111. data/examples/widget_gauge_demo/README.md +41 -0
  112. data/examples/widget_gauge_demo/app.rb +212 -0
  113. data/examples/widget_layout_split/README.md +44 -0
  114. data/examples/widget_layout_split/app.rb +246 -0
  115. data/examples/widget_line_gauge_demo/README.md +41 -0
  116. data/examples/widget_line_gauge_demo/app.rb +217 -0
  117. data/examples/widget_list_demo/README.md +49 -0
  118. data/examples/widget_list_demo/app.rb +366 -0
  119. data/examples/widget_map_demo/README.md +39 -0
  120. data/examples/{map_demo → widget_map_demo}/app.rb +24 -21
  121. data/examples/widget_overlay_demo/app.rb +248 -0
  122. data/examples/widget_popup_demo/README.md +36 -0
  123. data/examples/widget_popup_demo/app.rb +104 -0
  124. data/examples/widget_ratatui_logo_demo/README.md +34 -0
  125. data/examples/widget_ratatui_logo_demo/app.rb +103 -0
  126. data/examples/widget_ratatui_mascot_demo/README.md +34 -0
  127. data/examples/widget_ratatui_mascot_demo/app.rb +93 -0
  128. data/examples/widget_rect/README.md +38 -0
  129. data/examples/widget_rect/app.rb +205 -0
  130. data/examples/widget_render/README.md +37 -0
  131. data/examples/widget_render/app.rb +184 -0
  132. data/examples/widget_rich_text/README.md +35 -0
  133. data/examples/widget_rich_text/app.rb +166 -0
  134. data/examples/widget_scroll_text/README.md +37 -0
  135. data/examples/widget_scroll_text/app.rb +107 -0
  136. data/examples/widget_scrollbar_demo/README.md +37 -0
  137. data/examples/widget_scrollbar_demo/app.rb +153 -0
  138. data/examples/widget_sparkline_demo/README.md +42 -0
  139. data/examples/widget_sparkline_demo/app.rb +275 -0
  140. data/examples/widget_style_colors/README.md +34 -0
  141. data/examples/widget_style_colors/app.rb +19 -21
  142. data/examples/widget_table_demo/README.md +48 -0
  143. data/examples/widget_table_demo/app.rb +239 -0
  144. data/examples/widget_tabs_demo/README.md +41 -0
  145. data/examples/widget_tabs_demo/app.rb +181 -0
  146. data/examples/widget_text_width/README.md +35 -0
  147. data/examples/widget_text_width/app.rb +106 -0
  148. data/ext/ratatui_ruby/Cargo.lock +11 -4
  149. data/ext/ratatui_ruby/Cargo.toml +2 -1
  150. data/ext/ratatui_ruby/src/events.rs +359 -62
  151. data/ext/ratatui_ruby/src/frame.rs +227 -0
  152. data/ext/ratatui_ruby/src/lib.rs +110 -27
  153. data/ext/ratatui_ruby/src/rendering.rs +8 -4
  154. data/ext/ratatui_ruby/src/string_width.rs +101 -0
  155. data/ext/ratatui_ruby/src/style.rs +138 -57
  156. data/ext/ratatui_ruby/src/terminal.rs +42 -22
  157. data/ext/ratatui_ruby/src/text.rs +14 -7
  158. data/ext/ratatui_ruby/src/widgets/barchart.rs +74 -54
  159. data/ext/ratatui_ruby/src/widgets/block.rs +7 -6
  160. data/ext/ratatui_ruby/src/widgets/canvas.rs +21 -3
  161. data/ext/ratatui_ruby/src/widgets/chart.rs +20 -10
  162. data/ext/ratatui_ruby/src/widgets/gauge.rs +9 -2
  163. data/ext/ratatui_ruby/src/widgets/layout.rs +9 -4
  164. data/ext/ratatui_ruby/src/widgets/line_gauge.rs +9 -2
  165. data/ext/ratatui_ruby/src/widgets/list.rs +211 -12
  166. data/ext/ratatui_ruby/src/widgets/list_state.rs +137 -0
  167. data/ext/ratatui_ruby/src/widgets/mod.rs +3 -0
  168. data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
  169. data/ext/ratatui_ruby/src/widgets/paragraph.rs +1 -1
  170. data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +19 -8
  171. data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +17 -10
  172. data/ext/ratatui_ruby/src/widgets/scrollbar.rs +97 -3
  173. data/ext/ratatui_ruby/src/widgets/scrollbar_state.rs +169 -0
  174. data/ext/ratatui_ruby/src/widgets/sparkline.rs +14 -11
  175. data/ext/ratatui_ruby/src/widgets/table.rs +121 -5
  176. data/ext/ratatui_ruby/src/widgets/table_state.rs +121 -0
  177. data/ext/ratatui_ruby/src/widgets/tabs.rs +11 -11
  178. data/lib/ratatui_ruby/cell.rb +7 -7
  179. data/lib/ratatui_ruby/event/key/character.rb +35 -0
  180. data/lib/ratatui_ruby/event/key/media.rb +44 -0
  181. data/lib/ratatui_ruby/event/key/modifier.rb +95 -0
  182. data/lib/ratatui_ruby/event/key/navigation.rb +55 -0
  183. data/lib/ratatui_ruby/event/key/system.rb +45 -0
  184. data/lib/ratatui_ruby/event/key.rb +112 -52
  185. data/lib/ratatui_ruby/event/mouse.rb +3 -3
  186. data/lib/ratatui_ruby/event/none.rb +43 -0
  187. data/lib/ratatui_ruby/event/paste.rb +1 -1
  188. data/lib/ratatui_ruby/event.rb +56 -4
  189. data/lib/ratatui_ruby/frame.rb +183 -0
  190. data/lib/ratatui_ruby/list_state.rb +88 -0
  191. data/lib/ratatui_ruby/schema/bar_chart/bar.rb +13 -13
  192. data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +1 -5
  193. data/lib/ratatui_ruby/schema/bar_chart.rb +217 -217
  194. data/lib/ratatui_ruby/schema/block.rb +163 -168
  195. data/lib/ratatui_ruby/schema/calendar.rb +66 -67
  196. data/lib/ratatui_ruby/schema/canvas.rb +63 -63
  197. data/lib/ratatui_ruby/schema/center.rb +46 -46
  198. data/lib/ratatui_ruby/schema/chart.rb +135 -143
  199. data/lib/ratatui_ruby/schema/clear.rb +42 -42
  200. data/lib/ratatui_ruby/schema/constraint.rb +76 -76
  201. data/lib/ratatui_ruby/schema/cursor.rb +30 -25
  202. data/lib/ratatui_ruby/schema/gauge.rb +54 -52
  203. data/lib/ratatui_ruby/schema/layout.rb +87 -87
  204. data/lib/ratatui_ruby/schema/line_gauge.rb +62 -62
  205. data/lib/ratatui_ruby/schema/list.rb +103 -80
  206. data/lib/ratatui_ruby/schema/list_item.rb +41 -0
  207. data/lib/ratatui_ruby/schema/overlay.rb +31 -31
  208. data/lib/ratatui_ruby/schema/paragraph.rb +80 -80
  209. data/lib/ratatui_ruby/schema/ratatui_logo.rb +10 -6
  210. data/lib/ratatui_ruby/schema/ratatui_mascot.rb +10 -5
  211. data/lib/ratatui_ruby/schema/rect.rb +99 -56
  212. data/lib/ratatui_ruby/schema/scrollbar.rb +119 -119
  213. data/lib/ratatui_ruby/schema/shape/label.rb +1 -1
  214. data/lib/ratatui_ruby/schema/sparkline.rb +111 -110
  215. data/lib/ratatui_ruby/schema/style.rb +66 -46
  216. data/lib/ratatui_ruby/schema/table.rb +126 -115
  217. data/lib/ratatui_ruby/schema/tabs.rb +66 -67
  218. data/lib/ratatui_ruby/schema/text.rb +69 -1
  219. data/lib/ratatui_ruby/scrollbar_state.rb +112 -0
  220. data/lib/ratatui_ruby/session/autodoc.rb +482 -0
  221. data/lib/ratatui_ruby/session.rb +55 -23
  222. data/lib/ratatui_ruby/table_state.rb +90 -0
  223. data/lib/ratatui_ruby/test_helper/event_injection.rb +169 -0
  224. data/lib/ratatui_ruby/test_helper/snapshot.rb +390 -0
  225. data/lib/ratatui_ruby/test_helper/style_assertions.rb +351 -0
  226. data/lib/ratatui_ruby/test_helper/terminal.rb +127 -0
  227. data/lib/ratatui_ruby/test_helper/test_doubles.rb +68 -0
  228. data/lib/ratatui_ruby/test_helper.rb +66 -193
  229. data/lib/ratatui_ruby/version.rb +1 -1
  230. data/lib/ratatui_ruby.rb +100 -51
  231. data/{examples/sparkline_demo → sig/examples/app_all_events}/app.rbs +3 -2
  232. data/sig/examples/app_all_events/model/event_entry.rbs +16 -0
  233. data/sig/examples/app_all_events/model/events.rbs +15 -0
  234. data/sig/examples/app_all_events/model/timestamp.rbs +11 -0
  235. data/sig/examples/app_all_events/view/app_view.rbs +8 -0
  236. data/sig/examples/app_all_events/view/controls_view.rbs +6 -0
  237. data/sig/examples/app_all_events/view/counts_view.rbs +6 -0
  238. data/sig/examples/app_all_events/view/live_view.rbs +6 -0
  239. data/sig/examples/app_all_events/view/log_view.rbs +6 -0
  240. data/sig/examples/app_all_events/view.rbs +8 -0
  241. data/sig/examples/app_all_events/view_state.rbs +15 -0
  242. data/{examples/list_demo → sig/examples/app_color_picker}/app.rbs +2 -2
  243. data/sig/examples/app_login_form/app.rbs +11 -0
  244. data/sig/examples/app_stateful_interaction/app.rbs +33 -0
  245. data/sig/examples/verify_quickstart_dsl/app.rbs +11 -0
  246. data/sig/examples/verify_quickstart_lifecycle/app.rbs +11 -0
  247. data/sig/examples/verify_readme_usage/app.rbs +11 -0
  248. data/sig/examples/widget_block_demo/app.rbs +32 -0
  249. data/sig/examples/widget_box_demo/app.rbs +11 -0
  250. data/sig/examples/widget_calendar_demo/app.rbs +11 -0
  251. data/sig/examples/widget_cell_demo/app.rbs +11 -0
  252. data/sig/examples/widget_chart_demo/app.rbs +11 -0
  253. data/{examples/gauge_demo → sig/examples/widget_gauge_demo}/app.rbs +4 -0
  254. data/sig/examples/widget_layout_split/app.rbs +10 -0
  255. data/sig/examples/widget_line_gauge_demo/app.rbs +11 -0
  256. data/sig/examples/widget_list_demo/app.rbs +12 -0
  257. data/sig/examples/widget_map_demo/app.rbs +11 -0
  258. data/sig/examples/widget_popup_demo/app.rbs +11 -0
  259. data/sig/examples/widget_ratatui_logo_demo/app.rbs +11 -0
  260. data/sig/examples/widget_ratatui_mascot_demo/app.rbs +11 -0
  261. data/sig/examples/widget_rect/app.rbs +12 -0
  262. data/sig/examples/widget_render/app.rbs +10 -0
  263. data/sig/examples/widget_rich_text/app.rbs +11 -0
  264. data/sig/examples/widget_scroll_text/app.rbs +11 -0
  265. data/sig/examples/widget_scrollbar_demo/app.rbs +11 -0
  266. data/sig/examples/widget_sparkline_demo/app.rbs +10 -0
  267. data/{examples → sig/examples}/widget_style_colors/app.rbs +1 -1
  268. data/sig/examples/widget_table_demo/app.rbs +11 -0
  269. data/sig/examples/widget_text_width/app.rbs +10 -0
  270. data/sig/ratatui_ruby/event.rbs +11 -1
  271. data/sig/ratatui_ruby/frame.rbs +11 -0
  272. data/sig/ratatui_ruby/list_state.rbs +13 -0
  273. data/sig/ratatui_ruby/ratatui_ruby.rbs +5 -4
  274. data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +3 -3
  275. data/sig/ratatui_ruby/schema/draw.rbs +4 -0
  276. data/sig/ratatui_ruby/schema/gauge.rbs +2 -2
  277. data/sig/ratatui_ruby/schema/layout.rbs +1 -1
  278. data/sig/ratatui_ruby/schema/line_gauge.rbs +2 -2
  279. data/sig/ratatui_ruby/schema/list.rbs +4 -2
  280. data/sig/ratatui_ruby/schema/list_item.rbs +10 -0
  281. data/sig/ratatui_ruby/schema/rect.rbs +3 -0
  282. data/sig/ratatui_ruby/schema/style.rbs +3 -3
  283. data/sig/ratatui_ruby/schema/table.rbs +3 -1
  284. data/sig/ratatui_ruby/schema/text.rbs +8 -6
  285. data/sig/ratatui_ruby/scrollbar_state.rbs +18 -0
  286. data/sig/ratatui_ruby/session.rbs +107 -0
  287. data/sig/ratatui_ruby/table_state.rbs +15 -0
  288. data/sig/ratatui_ruby/test_helper/event_injection.rbs +16 -0
  289. data/sig/ratatui_ruby/test_helper/snapshot.rbs +12 -0
  290. data/sig/ratatui_ruby/test_helper/style_assertions.rbs +64 -0
  291. data/sig/ratatui_ruby/test_helper/terminal.rbs +14 -0
  292. data/sig/ratatui_ruby/test_helper/test_doubles.rbs +22 -0
  293. data/sig/ratatui_ruby/test_helper.rbs +5 -4
  294. data/tasks/autodoc/examples.rb +79 -0
  295. data/tasks/autodoc/inventory.rb +63 -0
  296. data/tasks/autodoc/member.rb +56 -0
  297. data/tasks/autodoc/name.rb +19 -0
  298. data/tasks/autodoc/notice.rb +26 -0
  299. data/tasks/autodoc/rbs.rb +38 -0
  300. data/tasks/autodoc/rdoc.rb +45 -0
  301. data/tasks/autodoc.rake +53 -0
  302. data/tasks/bump/changelog.rb +3 -3
  303. data/tasks/bump/history.rb +2 -2
  304. data/tasks/bump/links.rb +67 -0
  305. data/tasks/doc.rake +600 -6
  306. data/tasks/example_viewer.html.erb +172 -0
  307. data/tasks/lint.rake +8 -4
  308. data/tasks/resources/index.html.erb +6 -0
  309. data/tasks/sourcehut.rake +70 -30
  310. data/tasks/terminal_preview/app_screenshot.rb +14 -6
  311. data/tasks/terminal_preview/crash_report.rb +7 -9
  312. data/tasks/terminal_preview/launcher_script.rb +4 -6
  313. data/tasks/terminal_preview/preview_collection.rb +4 -6
  314. data/tasks/terminal_preview/safety_confirmation.rb +3 -5
  315. data/tasks/terminal_preview/saved_screenshot.rb +10 -11
  316. data/tasks/terminal_preview/terminal_window.rb +7 -9
  317. data/tasks/test.rake +1 -1
  318. data/tasks/website/index_page.rb +3 -3
  319. data/tasks/website/version.rb +10 -10
  320. data/tasks/website/version_menu.rb +10 -12
  321. data/tasks/website/versioned_documentation.rb +49 -17
  322. data/tasks/website/website.rb +6 -8
  323. data/tasks/website.rake +4 -4
  324. metadata +232 -127
  325. data/LICENSES/BSD-2-Clause.txt +0 -9
  326. data/doc/contributors/better_dx.md +0 -543
  327. data/doc/contributors/example_analysis.md +0 -82
  328. data/doc/images/all_events.png +0 -0
  329. data/doc/images/block_padding.png +0 -0
  330. data/doc/images/block_titles.png +0 -0
  331. data/doc/images/box_demo.png +0 -0
  332. data/doc/images/calendar_demo.png +0 -0
  333. data/doc/images/cell_demo.png +0 -0
  334. data/doc/images/chart_demo.png +0 -0
  335. data/doc/images/flex_layout.png +0 -0
  336. data/doc/images/gauge_demo.png +0 -0
  337. data/doc/images/line_gauge_demo.png +0 -0
  338. data/doc/images/list_demo.png +0 -0
  339. data/doc/images/list_styles.png +0 -0
  340. data/doc/images/login_form.png +0 -0
  341. data/doc/images/quickstart_dsl.png +0 -0
  342. data/doc/images/quickstart_lifecycle.png +0 -0
  343. data/doc/images/readme_usage.png +0 -0
  344. data/doc/images/rich_text.png +0 -0
  345. data/doc/images/scroll_text.png +0 -0
  346. data/doc/images/scrollbar_demo.png +0 -0
  347. data/doc/images/sparkline_demo.png +0 -0
  348. data/doc/images/table_flex.png +0 -0
  349. data/doc/images/table_select.png +0 -0
  350. data/examples/all_events/app.rb +0 -169
  351. data/examples/all_events/app.rbs +0 -7
  352. data/examples/all_events/test_app.rb +0 -139
  353. data/examples/analytics/app.rb +0 -258
  354. data/examples/analytics/app.rbs +0 -7
  355. data/examples/analytics/test_app.rb +0 -132
  356. data/examples/block_padding/app.rb +0 -63
  357. data/examples/block_padding/app.rbs +0 -7
  358. data/examples/block_padding/test_app.rb +0 -31
  359. data/examples/block_titles/app.rb +0 -61
  360. data/examples/block_titles/app.rbs +0 -7
  361. data/examples/block_titles/test_app.rb +0 -34
  362. data/examples/box_demo/app.rbs +0 -7
  363. data/examples/box_demo/test_app.rb +0 -88
  364. data/examples/calendar_demo/app.rb +0 -101
  365. data/examples/calendar_demo/app.rbs +0 -7
  366. data/examples/calendar_demo/test_app.rb +0 -108
  367. data/examples/cell_demo/app.rb +0 -108
  368. data/examples/cell_demo/app.rbs +0 -7
  369. data/examples/cell_demo/test_app.rb +0 -36
  370. data/examples/chart_demo/app.rb +0 -203
  371. data/examples/chart_demo/app.rbs +0 -7
  372. data/examples/chart_demo/test_app.rb +0 -102
  373. data/examples/custom_widget/app.rb +0 -51
  374. data/examples/custom_widget/app.rbs +0 -7
  375. data/examples/custom_widget/test_app.rb +0 -30
  376. data/examples/flex_layout/app.rb +0 -156
  377. data/examples/flex_layout/app.rbs +0 -7
  378. data/examples/flex_layout/test_app.rb +0 -65
  379. data/examples/gauge_demo/app.rb +0 -182
  380. data/examples/gauge_demo/test_app.rb +0 -120
  381. data/examples/hit_test/app.rb +0 -175
  382. data/examples/hit_test/app.rbs +0 -7
  383. data/examples/hit_test/test_app.rb +0 -102
  384. data/examples/line_gauge_demo/app.rb +0 -190
  385. data/examples/line_gauge_demo/app.rbs +0 -7
  386. data/examples/line_gauge_demo/test_app.rb +0 -129
  387. data/examples/list_demo/app.rb +0 -253
  388. data/examples/list_demo/test_app.rb +0 -237
  389. data/examples/list_styles/app.rb +0 -140
  390. data/examples/list_styles/app.rbs +0 -7
  391. data/examples/list_styles/test_app.rb +0 -157
  392. data/examples/login_form/app.rbs +0 -7
  393. data/examples/login_form/test_app.rb +0 -51
  394. data/examples/map_demo/app.rbs +0 -7
  395. data/examples/map_demo/test_app.rb +0 -149
  396. data/examples/mouse_events/app.rb +0 -97
  397. data/examples/mouse_events/app.rbs +0 -7
  398. data/examples/mouse_events/test_app.rb +0 -53
  399. data/examples/popup_demo/app.rb +0 -103
  400. data/examples/popup_demo/app.rbs +0 -7
  401. data/examples/popup_demo/test_app.rb +0 -54
  402. data/examples/quickstart_dsl/app.rbs +0 -7
  403. data/examples/quickstart_dsl/test_app.rb +0 -29
  404. data/examples/quickstart_lifecycle/app.rb +0 -39
  405. data/examples/quickstart_lifecycle/app.rbs +0 -7
  406. data/examples/quickstart_lifecycle/test_app.rb +0 -29
  407. data/examples/ratatui_logo_demo/app.rb +0 -79
  408. data/examples/ratatui_logo_demo/app.rbs +0 -7
  409. data/examples/ratatui_logo_demo/test_app.rb +0 -51
  410. data/examples/ratatui_mascot_demo/app.rb +0 -84
  411. data/examples/ratatui_mascot_demo/app.rbs +0 -7
  412. data/examples/ratatui_mascot_demo/test_app.rb +0 -47
  413. data/examples/readme_usage/app.rb +0 -29
  414. data/examples/readme_usage/app.rbs +0 -7
  415. data/examples/readme_usage/test_app.rb +0 -29
  416. data/examples/rich_text/app.rb +0 -141
  417. data/examples/rich_text/app.rbs +0 -7
  418. data/examples/rich_text/test_app.rb +0 -166
  419. data/examples/scroll_text/app.rb +0 -103
  420. data/examples/scroll_text/app.rbs +0 -7
  421. data/examples/scroll_text/test_app.rb +0 -110
  422. data/examples/scrollbar_demo/app.rb +0 -143
  423. data/examples/scrollbar_demo/app.rbs +0 -7
  424. data/examples/scrollbar_demo/test_app.rb +0 -77
  425. data/examples/sparkline_demo/app.rb +0 -240
  426. data/examples/sparkline_demo/test_app.rb +0 -107
  427. data/examples/table_flex/app.rb +0 -65
  428. data/examples/table_flex/app.rbs +0 -7
  429. data/examples/table_flex/test_app.rb +0 -36
  430. data/examples/table_select/app.rb +0 -198
  431. data/examples/table_select/app.rbs +0 -7
  432. data/examples/table_select/test_app.rb +0 -180
  433. data/examples/widget_style_colors/test_app.rb +0 -48
  434. data/tasks/bump/comparison_links.rb +0 -41
  435. /data/doc/images/{analytics.png → app_analytics.png} +0 -0
  436. /data/doc/images/{custom_widget.png → app_custom_widget.png} +0 -0
  437. /data/doc/images/{mouse_events.png → app_mouse_events.png} +0 -0
  438. /data/doc/images/{map_demo.png → widget_map_demo.png} +0 -0
  439. /data/doc/images/{popup_demo.png → widget_popup_demo.png} +0 -0
  440. /data/doc/images/{hit_test.png → widget_rect.png} +0 -0
  441. /data/{doc/images/ratatui_logo_demo.png → exe/.gitkeep} +0 -0
@@ -21,10 +21,13 @@ Structure your event loop into three clear phases:
21
21
 
22
22
  ```ruby
23
23
  def run
24
- RatatuiRuby.run do
24
+ RatatuiRuby.run do |tui|
25
+ @tui = tui
25
26
  loop do
26
- calculate_layout # Phase 1: Geometry (once per frame)
27
- render # Phase 2: Draw
27
+ @tui.draw do |frame|
28
+ calculate_layout(frame.area) # Phase 1: Geometry (once per frame)
29
+ render(frame) # Phase 2: Draw
30
+ end
28
31
  break if handle_input == :quit # Phase 3: Input
29
32
  end
30
33
  end
@@ -33,29 +36,27 @@ end
33
36
 
34
37
  **Phase 1: Layout Calculation**
35
38
 
36
- Call this before rendering and event handling. It's the single source of truth for geometry:
39
+ Call this inside your `draw` block. It uses the current terminal area provided by the frame:
37
40
 
38
41
  ```ruby
39
- def calculate_layout
40
- full_area = RatatuiRuby::Rect.new(x: 0, y: 0, width: 80, height: 24)
41
-
42
+ def calculate_layout(area)
42
43
  # Main area vs sidebar (70% / 30%)
43
- main_area, @sidebar_area = RatatuiRuby::Layout.split(
44
- full_area,
44
+ main_area, @sidebar_area = @tui.layout_split(
45
+ area,
45
46
  direction: :horizontal,
46
47
  constraints: [
47
- RatatuiRuby::Constraint.percentage(70),
48
- RatatuiRuby::Constraint.percentage(30),
48
+ @tui.constraint_percentage(70),
49
+ @tui.constraint_percentage(30),
49
50
  ]
50
51
  )
51
52
 
52
53
  # Within main area, left vs right panels
53
- @left_rect, @right_rect = RatatuiRuby::Layout.split(
54
+ @left_rect, @right_rect = @tui.layout_split(
54
55
  main_area,
55
56
  direction: :horizontal,
56
57
  constraints: [
57
- RatatuiRuby::Constraint.percentage(@left_ratio),
58
- RatatuiRuby::Constraint.percentage(100 - @left_ratio)
58
+ @tui.constraint_percentage(@left_ratio),
59
+ @tui.constraint_percentage(100 - @left_ratio)
59
60
  ]
60
61
  )
61
62
  end
@@ -66,10 +67,9 @@ end
66
67
  Reuse the cached rects. Build and draw:
67
68
 
68
69
  ```ruby
69
- def render
70
- left_panel = build_widget(@left_rect)
71
- right_panel = build_widget(@right_rect)
72
- # ... draw ...
70
+ def render(frame)
71
+ frame.render_widget(build_widget(@left_rect), @left_rect)
72
+ frame.render_widget(build_widget(@right_rect), @right_rect)
73
73
  end
74
74
  ```
75
75
 
@@ -80,7 +80,6 @@ Reuse the cached rects. Test clicks:
80
80
  ```ruby
81
81
  def handle_input
82
82
  event = RatatuiRuby.poll_event
83
- return unless event
84
83
 
85
84
  case event
86
85
  in type: :mouse, kind: "down", x:, y:
@@ -104,18 +103,14 @@ end
104
103
 
105
104
  ## Layout.split
106
105
 
107
- `Layout.split` computes layout geometry without rendering. It returns an array of `Rect` objects.
106
+ `Layout.split` computes layout geometry without rendering. It returns an array of `Rect` objects. While you can call `RatatuiRuby::Layout.split` directly, we recommend using the `Session` helper (`tui.layout_split`) for cleaner application code.
108
107
 
109
108
  ```ruby
110
- rects = Layout.split(
111
- area,
112
- direction: :horizontal,
113
- constraints: [Constraint.percentage(70), Constraint.percentage(30)]
114
- )
115
-
116
- left, right = rects
117
- # left is a Rect describing the left 70% of the area
118
- # right is a Rect describing the right 30% of the area
109
+ # Preferred (Session API)
110
+ left, right = tui.layout_split(area, constraints: [...])
111
+
112
+ # Manual (Core API)
113
+ left, right = RatatuiRuby::Layout.split(area, constraints: [...])
119
114
  ```
120
115
 
121
- Use it to establish the single source of truth in `calculate_layout`. Reuse the results in both render and event handling.
116
+ Use it to establish the single source of truth inside your `draw` block. Store the results in instance variables and reuse them in both `render` and `handle_input`.
data/doc/quickstart.md CHANGED
@@ -29,22 +29,22 @@ gem install ratatui_ruby
29
29
  ```
30
30
 
31
31
 
32
- ## Basic Application
32
+ ## Tutorials
33
+
34
+ ### Basic Application
33
35
 
34
36
  Here is a "Hello World" application that demonstrates the core lifecycle of a **ratatui_ruby** app.
35
37
 
38
+ <!-- SYNC:START:../examples/verify_quickstart_lifecycle/app.rb:main -->
36
39
  ```ruby
37
- require "ratatui_ruby"
38
-
39
40
  # 1. Initialize the terminal
40
41
  RatatuiRuby.init_terminal
41
-
42
+
42
43
  begin
43
44
  # The Main Loop
44
45
  loop do
45
46
  # 2. Create your UI (Immediate Mode)
46
47
  # We define a Paragraph widget inside a Block with a title and borders.
47
- # Other widgets include RatatuiRuby::RatatuiMascot, RatatuiRuby::RatatuiLogo, etc.
48
48
  view = RatatuiRuby::Paragraph.new(
49
49
  text: "Hello, Ratatui! Press 'q' to quit.",
50
50
  alignment: :center,
@@ -56,38 +56,43 @@ begin
56
56
  style: { fg: "white" }
57
57
  )
58
58
  )
59
-
59
+
60
60
  # 3. Draw the UI
61
- RatatuiRuby.draw(view)
62
-
61
+ RatatuiRuby.draw do |frame|
62
+ frame.render_widget(view, frame.area)
63
+ end
64
+
63
65
  # 4. Poll for events
64
- event = RatatuiRuby.poll_event
65
- break if event == "q" || event == :ctrl_c
66
+ case RatatuiRuby.poll_event
67
+ in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
68
+ break
69
+ else
70
+ nil
71
+ end
66
72
  end
67
73
  ensure
68
74
  # 5. Restore the terminal to its original state
69
75
  RatatuiRuby.restore_terminal
70
76
  end
71
77
  ```
78
+ <!-- SYNC:END -->
72
79
 
73
- ![quickstart_lifecycle](./images/quickstart_lifecycle.png)
80
+ ![quickstart_lifecycle](./images/verify_quickstart_lifecycle.png)
74
81
 
75
- ### How it works
82
+ #### How it works
76
83
 
77
84
  1. **`RatatuiRuby.init_terminal`**: Enters raw mode and switches to the alternate screen.
78
- 2. **Immediate Mode UI**: On every iteration of the loop, you describe what the UI should look like by creating `Data` objects (like `Paragraph` and `Block`).
79
- 3. **`RatatuiRuby.draw(view)`**: The Ruby UI tree is passed to the Rust backend, which renders it to the terminal.
80
- 4. **`RatatuiRuby.poll_event`**: Checks for keyboard, mouse, or resize events.
81
- 5. **`RatatuiRuby.restore_terminal`**: Crucial for leaving raw mode and returning the user to their shell properly. Always wrap your loop in a `begin...ensure` block to guarantee this runs.
85
+ 2. **Immediate Mode UI**: On every iteration, describe your UI by creating `Data` objects (e.g., `Paragraph`, `Block`).
86
+ 3. **`RatatuiRuby.draw { |frame| ... }`**: The block receives a `Frame` object as a canvas. Render widgets onto specific areas. Nothing is drawn until the block finishes, ensuring flicker-free updates.
87
+ 4. **`RatatuiRuby.poll_event`**: Returns a typed `Event` object with predicates like `key?`, `mouse?`, `resize?`, etc. Returns `RatatuiRuby::Event::None` if no events are pending. Use predicates to check event type without pattern matching.
88
+ 5. **`RatatuiRuby.restore_terminal`**: Essential for leaving raw mode and returning to the shell. Always wrap your loop in `begin...ensure` to guarantee this runs.
82
89
 
83
90
  ### Idiomatic Session
84
91
 
85
92
  You can simplify your code by using `RatatuiRuby.run`. This method handles the terminal lifecycle for you, yielding a `Session` object with factory methods for widgets.
86
93
 
87
- ```rb
88
- require "ratatui_ruby"
89
-
90
- # 1. Initialize the terminal and ensure it is restored.
94
+ <!-- SYNC:START:../examples/verify_quickstart_dsl/app.rb:main -->
95
+ ```ruby
91
96
  RatatuiRuby.run do |tui|
92
97
  loop do
93
98
  # 2. Create your UI with methods instead of classes.
@@ -104,168 +109,183 @@ RatatuiRuby.run do |tui|
104
109
  )
105
110
 
106
111
  # 3. Use RatatuiRuby methods, too.
107
- tui.draw(view)
108
- event = tui.poll_event
109
-
110
- break if event == "q" || event == :ctrl_c
112
+ tui.draw do |frame|
113
+ frame.render_widget(view, frame.area)
114
+ end
115
+
116
+ # 4. Poll for events with pattern matching
117
+ case tui.poll_event
118
+ in { type: :key, code: "q" }
119
+ break
120
+ else
121
+ # Ignore other events
122
+ end
111
123
  end
112
124
  end
113
-
125
+ ```
126
+ <!-- SYNC:END -->
114
127
 
115
128
  #### How it works
116
129
 
117
130
  1. **`RatatuiRuby.run`**: This context manager initializes the terminal before the block starts and ensures `restore_terminal` is called when the block exits (even if an error occurs).
118
131
  2. **Widget Shorthand**: The block yields a `Session` object (here named `tui`). This object provides factory methods for every widget, allowing you to write `tui.paragraph(...)` instead of the more verbose `RatatuiRuby::Paragraph.new(...)`.
119
- 3. **Method Shorthand**: The session object also provides aliases for module functions of `RatatuiRuby`, allowing you to write `tui.draw(...)` instead of the more verbose `RatatuiRuby::draw(...)`.
132
+ 3. **Method Shorthand**: The session object also provides aliases for module functions of `RatatuiRuby`, allowing you to write `tui.draw(...)` instead of the more verbose `RatatuiRuby.draw(...)`.
133
+ 4. **Pattern Matching for Events**: Use `case...in` with pattern matching for elegant event dispatch. Always include an `else` clause at the end to catch unmatched event types (mouse, resize, paste, focus, etc.), otherwise Ruby raises `NoMatchingPatternError`.
120
134
 
121
135
  For a deeper dive into the available application architectures (Manual vs Managed), see [Application Architecture](./application_architecture.md).
122
136
 
123
- ## Examples
124
-
125
- To see more complex layouts and widget usage, check out the `examples/` directory in the repository.
137
+ ### Adding Layouts
126
138
 
127
- ### [Analytics](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/analytics/app.rb)
139
+ Real-world applications often need to split the screen into multiple areas. `RatatuiRuby::Layout` lets you do this easily.
128
140
 
129
- Demonstrates the use of `Tabs` and `BarChart` widgets. Features custom highlight styles, base styles, dividers for the tabs, and dynamic width calculation. The `BarChart` showcases both standard and grouped bars (Quarterly view), highlighting features like `group_gap` spacing, toggling `BarChart::direction`, customizing label/value styles, cycling custom `BarChart::bar_set` characters, and switching between Full and Mini height modes.
141
+ <!-- SYNC:START:../examples/verify_quickstart_layout/app.rb:main -->
142
+ ```ruby
143
+ loop do
144
+ tui.draw do |frame|
145
+ # 1. Split the screen
146
+ top, bottom = tui.layout_split(
147
+ frame.area,
148
+ direction: :vertical,
149
+ constraints: [
150
+ tui.constraint_percentage(75),
151
+ tui.constraint_percentage(25),
152
+ ]
153
+ )
130
154
 
131
- ![analytics](./images/analytics.png)
155
+ # 2. Render Top Widget
156
+ frame.render_widget(
157
+ tui.paragraph(
158
+ text: "Hello, Ratatui!",
159
+ alignment: :center,
160
+ block: tui.block(title: "Content", borders: [:all], border_color: "cyan")
161
+ ),
162
+ top
163
+ )
132
164
 
133
- ### [All Events](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/all_events/app.rb)
165
+ # 3. Render Bottom Widget with Styled Text
166
+ # We use a Line of Spans to style specific characters
167
+ text_line = tui.text_line(
168
+ spans: [
169
+ tui.text_span(content: "Press '"),
170
+ tui.text_span(
171
+ content: "q",
172
+ style: tui.style(modifiers: [:bold, :underlined])
173
+ ),
174
+ tui.text_span(content: "' to quit."),
175
+ ],
176
+ alignment: :center
177
+ )
134
178
 
135
- A comprehensive demonstration of every event type supported by **ratatui_ruby**: Key, Mouse, Resize, Paste, and Focus events.
179
+ frame.render_widget(
180
+ tui.paragraph(
181
+ text: text_line,
182
+ block: tui.block(title: "Controls", borders: [:all])
183
+ ),
184
+ bottom
185
+ )
186
+ end
136
187
 
137
- ![all_events](./images/all_events.png)
188
+ case tui.poll_event
189
+ in { type: :key, code: "q" }
190
+ break
191
+ else
192
+ # Ignore other events
193
+ end
194
+ end
195
+ ```
196
+ <!-- SYNC:END -->
138
197
 
139
- ### [Block Padding](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/block_padding/app.rb)
198
+ #### How it works
140
199
 
141
- Demonstrates the `padding` property of the `Block` widget, supporting both uniform and directional padding.
200
+ 1. **`tui.layout_split` (`RatatuiRuby::Layout.split`)**: Takes an area (like `frame.area`) and splits it into multiple sub-areas based on constraints.
201
+ 2. **`tui.constraint_*` (`RatatuiRuby::Constraint`)**: Defines how space is distributed (e.g., `percentage`, `length`, `min`, `max`).
202
+ 3. **`Frame#render_widget(widget, rect)`**: You pass the specific area (like `top` or `bottom`) to render the widget into that exact region.
203
+ 4. **`tui.text_span` (`RatatuiRuby::Text::Span`)**: Allows for rich styling within a single line of text.
142
204
 
143
- ![block_padding](./images/block_padding.png)
205
+ ## Examples
144
206
 
145
- ### [Block Titles](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/block_titles/app.rb)
207
+ These examples showcase the full power of **ratatui_ruby**. You can find their source code in the [examples directory](../examples).
146
208
 
147
- Demonstrates the `Block` widget's ability to render multiple titles with individual alignment and positioning (top/bottom).
209
+ ### Sample Applications
148
210
 
149
- ![block_titles](./images/block_titles.png)
211
+ Full-featured examples demonstrating complex layouts and real-world TUI patterns.
150
212
 
151
- ### [Box Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/box_demo/app.rb)
152
213
 
153
- A simple demonstration of `Block` and `Paragraph` widgets, reacting to key presses to change colors, border types, border styles, and title styling. Features the new `border_style` parameter for applying colors and modifiers (bold, italic) to borders independently of the content background.
154
214
 
155
- ![box_demo](./images/box_demo.png)
215
+ #### [All Events](../examples/app_all_events/app.rb)
156
216
 
157
- ### [Calendar Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/calendar_demo/app.rb)
217
+ Handling terminal events is unpredictable. Developers need to know exactly what the terminal sends for `Ctrl+C` or a mouse drag.
158
218
 
159
- Demonstrates the `Calendar` widget with interactive attribute cycling. Features event highlighting (dates with specific styles), toggleable month/weekday headers, and surrounding month visibility (with custom styling) via keyboard shortcuts. Press `h` to toggle month header, `w` to toggle weekday header, `s` to toggle surrounding month dates, and `e` to toggle events.
219
+ This app captures and visualizes every event—keys, mouse, resize, paste, and focus.
160
220
 
161
- ![calendar_demo](./images/calendar_demo.png)
221
+ Use it to debug your input handling or verify terminal behavior.
162
222
 
163
- ### [Chart Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/chart_demo/app.rb)
223
+ **What you'll learn:**
164
224
 
165
- Demonstrates the `Chart` widget with both scatter and line datasets, including custom axes. Features customizable axis label alignment and legend positioning.
225
+ * **Proto-TEA Architecture**: Implements unidirectional data flow (Model-View-Update) with immutable state and pure functions.
226
+ * **Event Handling**: Captures and distinguishes all input types, including modifiers (`Ctrl+C`) and focus changes.
227
+ * **Scalable Structure**: Organizes a non-trivial application into small, focused classes instead of a monolithic script.
166
228
 
167
- ![chart_demo](./images/chart_demo.png)
229
+ ![all_events](./images/app_all_events.png)
168
230
 
169
- ### [Custom Widget (Escape Hatch)](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/custom_widget/app.rb)
231
+ #### [Color Picker](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/app_color_picker/app.rb)
170
232
 
171
- Demonstrates how to define a custom widget in pure Ruby using the `render(area, buffer)` escape hatch for low-level drawing.
233
+ Interactive tools require complex state. Mapping mouse clicks to widgets and handling modal dialogs creates messy code if handled in the main loop.
172
234
 
173
- ![custom_widget](./images/custom_widget.png)
235
+ This app implements a full Color Picker using a "Proto-Kit (Component-Based)" pattern. Each component encapsulates its own rendering, state, and event handling.
174
236
 
175
- ### [Flex Layout](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/flex_layout/app.rb)
237
+ Use it to build forms, editors, and mouse-driven tools.
176
238
 
177
- Demonstrates modern layout features including `Constraint.fill` and `Constraint.ratio` for proportional space distribution and `flex: :space_between` for evenly distributing fixed-size elements.
239
+ **What you'll learn:**
178
240
 
179
- ![flex_layout](./images/flex_layout.png)
241
+ * **Proto-Kit Architecture**: Self-contained components with `render(tui, frame, area)` and `handle_event(event)`.
242
+ * **Encapsulated Hit Testing**: Components cache their render area and check `contains?` internally.
243
+ * **Modal Dialogs**: Implements overlay patterns that intercept input via Chain of Responsibility.
180
244
 
181
- ### [LineGauge Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/line_gauge_demo/app.rb)
245
+ #### [Custom Widget (Escape Hatch)](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/app_custom_widget/app.rb)
182
246
 
183
- Demonstrates the `LineGauge` widget with customizable filled and unfilled symbols, base style support via the `style` parameter, independent styling for filled/unfilled portions, and interactive ratio cycling with arrow keys.
247
+ Demonstrates how to define a custom widget in pure Ruby using the `render(area, buffer)` escape hatch for low-level drawing.
184
248
 
185
- ![line_gauge_demo](./images/line_gauge_demo.png)
249
+ ![custom_widget](./images/app_custom_widget.png)
186
250
 
187
- ### [List Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/list_demo/app.rb)
251
+ #### [Layout Split Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/widget_layout_split/app.rb)
188
252
 
189
- Demonstrates the `List` widget with interactive attribute cycling. Features multiple item sets to browse, customizable highlight styles and symbols, and exploration of all List options including direction, highlight spacing, repeat symbol mode, scroll padding, and base styling. The sidebar provides hotkey documentation for discovering all List features, including the new `p` key to adjust scroll padding.
253
+ Demonstrates `Layout.split` with interactive attribute cycling. Features hotkey controls For direction (vertical/horizontal), all 7 flex modes (legacy, start, center, end, space_between, space_around, space_evenly), and constraint types (fill, length, percentage, min, ratio).
190
254
 
191
- ![list_demo](./images/list_demo.png)
255
+ ![widget_layout_split](./images/widget_layout_split.png)
192
256
 
193
- ### [Login Form](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/login_form/app.rb)
257
+ #### [Login Form](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/app_login_form/app.rb)
194
258
 
195
259
  Shows how to use `Overlay`, `Center`, and `Cursor` to build a modal login form with text input.
196
260
 
197
- ![login_form](./images/login_form.png)
198
-
199
- ### [Map Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/map_demo/app.rb)
200
-
201
- Exhibits the `Canvas` widget's power, rendering a world map with city labels, animated circles, and lines.
202
-
203
- ![map_demo](./images/map_demo.png)
204
-
205
- ### [Mouse Events](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/mouse_events/app.rb)
206
-
207
- Detailed plumbing of mouse events, including clicks, drags, and movement tracking.
208
-
209
- ![mouse_events](./images/mouse_events.png)
210
-
211
- ### [Popup Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/popup_demo/app.rb)
212
-
213
- Demonstrates the `Clear` widget and how to prevent "style bleed" when rendering opaque popups over colored backgrounds.
214
-
215
- ![popup_demo](./images/popup_demo.png)
216
-
217
- ### [Ratatui Logo Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/ratatui_logo_demo/app.rb)
218
-
219
- Demonstrates the `RatatuiLogo` widget.
220
-
221
-
222
- ![ratatui_logo_demo](./images/ratatui_logo_demo.png)
223
-
224
- ### [Rich Text](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/rich_text/app.rb)
225
-
226
- Demonstrates `Text::Span` and `Text::Line` for creating styled text with inline formatting, enabling word-level control over colors and text modifiers.
227
-
228
- ![rich_text](./images/rich_text.png)
229
-
230
- ### [Scrollbar Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/scrollbar_demo/app.rb)
231
-
232
- A demonstration of the `Scrollbar` widget, featuring mouse wheel scrolling and extensive customization of symbols and styles.
233
-
234
- ![scrollbar_demo](./images/scrollbar_demo.png)
235
-
236
- ### [Scroll Text](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/scroll_text/app.rb)
237
-
238
- Demonstrates the `Paragraph` widget's scroll functionality, allowing navigation through long text content using arrow keys for both horizontal and vertical scrolling.
239
-
240
- ![scroll_text](./images/scroll_text.png)
241
-
242
- ### [Sparkline Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/sparkline_demo/app.rb)
243
-
244
- Demonstrates the `Sparkline` widget with interactive attribute cycling. Features multiple data sets with different patterns (steady growth, gaps, random, sawtooth, peaks), and explores all `Sparkline` options including direction, color, the new `absent_value_symbol` and `absent_value_style` parameters for distinguishing zero/absent values from low data, and the new `bar_set` parameter for custom bar characters.
245
-
246
- ![sparkline_demo](./images/sparkline_demo.png)
247
-
248
- ### [Gauge Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/gauge_demo/app.rb)
249
-
250
- Demonstrates the `Gauge` widget with interactive attribute cycling. Features multiple gauge instances with customizable ratio, gauge color, background style, Unicode toggle, and label modes. The sidebar provides hotkey documentation for exploring all Gauge options, including the distinction between `style` (background) and `gauge_style` (filled bar).
251
-
252
- ![gauge_demo](./images/gauge_demo.png)
253
-
254
- ### [Table Select](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/table_select/app.rb)
255
-
256
- Demonstrates interactive row selection in the `Table` widget with keyboard navigation, highlighting selected rows with custom styles and symbols, applying a base style, and dynamically adjusting `column_spacing`. Also demonstrates `column_highlight_style` and the new `cell_highlight_style` for precise selection visualization.
261
+ ![login_form](./images/app_login_form.png)
257
262
 
258
- ![table_select](./images/table_select.png)
259
263
 
260
- ### [Table Flex](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/table_flex/app.rb)
261
264
 
262
- Demonstrates different flex modes in the `Table` widget, such as `:space_between` and `:space_around`, allowing for modern, responsive table layouts.
263
265
 
264
- ![table_flex](./images/table_flex.png)
265
266
 
266
- ### [Widget Style Colors](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/widget_style_colors/app.rb)
267
267
 
268
- Demonstrates hexadecimal color code support in Style parameters. Renders an 80x24 color gradient using HSL-to-RGB conversion and #RRGGBB hex codes, showcasing 24-bit true color rendering on capable terminals.
268
+ ### Widget Demos
269
269
 
270
- ![widget_style_colors](./images/widget_style_colors.png)
270
+ These smaller, focused examples demonstrate specific widgets and their configuration options.
271
271
 
272
+ * [Bar Chart](../examples/widget_barchart_demo/app.rb)
273
+ * [Block (Interactive Demo)](../examples/widget_block_demo/app.rb)
274
+ * [Box (Block/Paragraph)](../examples/widget_box_demo/app.rb)
275
+ * [Calendar](../examples/widget_calendar_demo/app.rb)
276
+ * [Chart](../examples/widget_chart_demo/app.rb)
277
+ * [Gauge](../examples/widget_gauge_demo/app.rb)
278
+ * [Line Gauge](../examples/widget_line_gauge_demo/app.rb)
279
+ * [List](../examples/widget_list_demo/app.rb)
280
+ * [Map (Canvas)](../examples/widget_map_demo/app.rb)
281
+ * [Popup (Clear)](../examples/widget_popup_demo/app.rb)
282
+ * [Rect](../examples/widget_rect/app.rb)
283
+ * [Ratatui Logo](../examples/widget_ratatui_logo_demo/app.rb)
284
+ * [Ratatui Mascot](../examples/widget_ratatui_mascot_demo/app.rb)
285
+ * [Rich Text](../examples/widget_rich_text/app.rb)
286
+ * [Scrollbar](../examples/widget_scrollbar_demo/app.rb)
287
+ * [Scroll Text](../examples/widget_scroll_text/app.rb)
288
+ * [Sparkline](../examples/widget_sparkline_demo/app.rb)
289
+ * [Table (Selection)](../examples/widget_table_demo/app.rb)
290
+ * [Tabs](../examples/widget_tabs_demo/app.rb)
291
+ * [Widget Style Colors](../examples/widget_style_colors/app.rb)
@@ -0,0 +1,92 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
3
+ SPDX-License-Identifier: CC-BY-SA-4.0
4
+ -->
5
+
6
+ # Terminal Limitations
7
+
8
+ Some behaviors are outside the control of `ratatui_ruby`. This document explains common pitfalls that affect your application or your users, but cannot be fixed in the library.
9
+
10
+ ## Keyboard Event Interception
11
+
12
+ ### The Problem
13
+
14
+ Your application receives a key event, but the modifier flags are missing. You pressed Ctrl+PageUp, but the event shows `code="page_up"` with `modifiers=[]`.
15
+
16
+ ### The Cause
17
+
18
+ Terminal emulators intercept certain key combinations for their own features. The key press never reaches your application—the terminal consumes it first.
19
+
20
+ Common culprits on macOS:
21
+
22
+ | Key Combination | Terminal Behavior |
23
+ |---------------------|--------------------------------------|
24
+ | Ctrl+PageUp/Down | Switch tabs (Terminal.app, iTerm2) |
25
+ | Ctrl+Tab | Switch tabs |
26
+ | Cmd+T / Cmd+N | New tab / New window |
27
+ | Cmd+C / Cmd+V | Copy / Paste (not Ctrl) |
28
+
29
+ Linux terminals vary widely. Windows Terminal and ConEmu have their own defaults.
30
+
31
+ ### The Solution
32
+
33
+ 1. **Test with different terminals.** Kitty, WezTerm, and Alacritty pass more key combinations through to applications by default. If a key works in Kitty but not Terminal.app, the terminal is the issue.
34
+
35
+ 2. **Reconfigure your terminal.** Most terminal emulators let you unbind or remap default shortcuts in their settings.
36
+
37
+ 3. **Use alternative key bindings.** If your users will run your application in various terminals, design your keybindings to avoid commonly intercepted combinations:
38
+ - Use Alt+PageUp instead of Ctrl+PageUp
39
+ - Use Ctrl+J/K instead of Ctrl+Up/Down
40
+ - Avoid Ctrl+Tab entirely
41
+
42
+ 4. **Document requirements.** If your application depends on specific key combinations, document the terminal requirements for your users.
43
+
44
+ ### Enhanced Keyboard Protocol
45
+
46
+ Some terminals support the [Kitty keyboard protocol](https://sw.kovidgoyal.net/kitty/keyboard-protocol/), which provides unambiguous key event reporting including:
47
+
48
+ - Individual modifier key events (LeftShift vs RightShift)
49
+ - Media keys (Play, Pause, Volume controls)
50
+ - Repeat and release events
51
+
52
+ Terminals with full protocol support:
53
+ - Kitty
54
+ - WezTerm
55
+ - Foot
56
+ - Alacritty (partial)
57
+
58
+ Standard terminals (Terminal.app, iTerm2, GNOME Terminal) do not support the enhanced protocol.
59
+
60
+ **RatatuiRuby Status:** The underlying library (crossterm) supports this protocol, but RatatuiRuby does not yet expose a way to enable it. The key code mappings for media keys and individual modifier keys exist, but they will only be received from terminals that enable the protocol by default. This is planned for a future release.
61
+
62
+ ## Mouse Event Limitations
63
+
64
+ ### The Problem
65
+
66
+ Mouse events work in some terminals but not others. Or they work, but only up to certain coordinates.
67
+
68
+ ### The Cause
69
+
70
+ Mouse reporting requires terminal escape sequence support. Older terminals may not support:
71
+
72
+ - SGR mouse mode (coordinates > 223)
73
+ - Mouse motion tracking
74
+ - Button-event tracking
75
+
76
+ ### The Solution
77
+
78
+ Ensure your terminal supports modern mouse modes. Most actively maintained terminals do. If running in a legacy environment, test mouse functionality and provide keyboard alternatives.
79
+
80
+ ## Focus Events
81
+
82
+ ### The Problem
83
+
84
+ `Event::FocusGained` and `Event::FocusLost` are never received.
85
+
86
+ ### The Cause
87
+
88
+ Focus event reporting requires explicit terminal support and configuration. Some terminals don't support it at all.
89
+
90
+ ### The Solution
91
+
92
+ Don't rely on focus events for critical functionality. Treat them as nice-to-have enhancements. If your application shows stale data when the user returns, periodically refresh instead of waiting for focus events.