ratatui_ruby 0.4.0 → 0.5.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 (351) 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 +87 -171
  7. data/CHANGELOG.md +38 -1
  8. data/README.md +8 -3
  9. data/REUSE.toml +20 -0
  10. data/doc/application_architecture.md +105 -45
  11. data/doc/application_testing.md +5 -3
  12. data/doc/contributors/design/ruby_frontend.md +9 -5
  13. data/doc/contributors/developing_examples.md +76 -18
  14. data/doc/contributors/documentation_style.md +7 -0
  15. data/doc/contributors/index.md +2 -0
  16. data/doc/event_handling.md +10 -4
  17. data/doc/images/app_all_events.png +0 -0
  18. data/doc/images/app_color_picker.png +0 -0
  19. data/doc/images/verify_readme_usage.png +0 -0
  20. data/doc/images/widget_barchart_demo.png +0 -0
  21. data/doc/images/widget_block_padding.png +0 -0
  22. data/doc/images/widget_block_titles.png +0 -0
  23. data/doc/images/widget_box_demo.png +0 -0
  24. data/doc/images/widget_calendar_demo.png +0 -0
  25. data/doc/images/widget_cell_demo.png +0 -0
  26. data/doc/images/widget_chart_demo.png +0 -0
  27. data/doc/images/widget_gauge_demo.png +0 -0
  28. data/doc/images/widget_layout_split.png +0 -0
  29. data/doc/images/widget_line_gauge_demo.png +0 -0
  30. data/doc/images/widget_list_demo.png +0 -0
  31. data/doc/images/widget_ratatui_logo_demo.png +0 -0
  32. data/doc/images/widget_ratatui_mascot_demo.png +0 -0
  33. data/doc/images/widget_render.png +0 -0
  34. data/doc/images/widget_scrollbar_demo.png +0 -0
  35. data/doc/images/widget_sparkline_demo.png +0 -0
  36. data/doc/images/widget_style_colors.png +0 -0
  37. data/doc/images/widget_table_flex.png +0 -0
  38. data/doc/images/widget_tabs_demo.png +0 -0
  39. data/doc/interactive_design.md +25 -30
  40. data/doc/quickstart.md +147 -120
  41. data/examples/app_all_events/README.md +81 -0
  42. data/examples/app_all_events/app.rb +93 -0
  43. data/examples/app_all_events/model/event_color_cycle.rb +41 -0
  44. data/examples/app_all_events/model/event_entry.rb +75 -0
  45. data/examples/app_all_events/model/events.rb +180 -0
  46. data/examples/app_all_events/model/highlight.rb +57 -0
  47. data/examples/app_all_events/model/timestamp.rb +54 -0
  48. data/examples/app_all_events/test/snapshots/after_focus_lost.txt +24 -0
  49. data/examples/app_all_events/test/snapshots/after_focus_regained.txt +24 -0
  50. data/examples/app_all_events/test/snapshots/after_horizontal_resize.txt +24 -0
  51. data/examples/app_all_events/test/snapshots/after_key_a.txt +24 -0
  52. data/examples/app_all_events/test/snapshots/after_key_ctrl_x.txt +24 -0
  53. data/examples/app_all_events/test/snapshots/after_mouse_click.txt +24 -0
  54. data/examples/app_all_events/test/snapshots/after_mouse_drag.txt +24 -0
  55. data/examples/app_all_events/test/snapshots/after_multiple_events.txt +24 -0
  56. data/examples/app_all_events/test/snapshots/after_paste.txt +24 -0
  57. data/examples/app_all_events/test/snapshots/after_resize.txt +24 -0
  58. data/examples/app_all_events/test/snapshots/after_right_click.txt +24 -0
  59. data/examples/app_all_events/test/snapshots/after_vertical_resize.txt +24 -0
  60. data/examples/app_all_events/test/snapshots/initial_state.txt +24 -0
  61. data/examples/app_all_events/view/app_view.rb +78 -0
  62. data/examples/app_all_events/view/controls_view.rb +50 -0
  63. data/examples/app_all_events/view/counts_view.rb +55 -0
  64. data/examples/app_all_events/view/live_view.rb +69 -0
  65. data/examples/app_all_events/view/log_view.rb +60 -0
  66. data/examples/app_all_events/view.rb +7 -0
  67. data/examples/app_all_events/view_state.rb +42 -0
  68. data/examples/app_color_picker/README.md +94 -0
  69. data/examples/app_color_picker/app.rb +112 -0
  70. data/examples/app_color_picker/clipboard.rb +84 -0
  71. data/examples/app_color_picker/color.rb +191 -0
  72. data/examples/app_color_picker/copy_dialog.rb +170 -0
  73. data/examples/app_color_picker/harmony.rb +56 -0
  74. data/examples/app_color_picker/input.rb +142 -0
  75. data/examples/app_color_picker/palette.rb +80 -0
  76. data/examples/app_color_picker/scene.rb +201 -0
  77. data/examples/{login_form → app_login_form}/app.rb +39 -42
  78. data/examples/{map_demo → app_map_demo}/app.rb +24 -21
  79. data/examples/{table_select → app_table_select}/app.rb +68 -65
  80. data/examples/{quickstart_dsl → verify_quickstart_dsl}/app.rb +15 -6
  81. data/examples/verify_quickstart_layout/app.rb +69 -0
  82. data/examples/{quickstart_lifecycle → verify_quickstart_lifecycle}/app.rb +19 -10
  83. data/examples/verify_readme_usage/app.rb +34 -0
  84. data/examples/widget_barchart_demo/app.rb +238 -0
  85. data/examples/{block_padding → widget_block_padding}/app.rb +17 -13
  86. data/examples/{block_titles → widget_block_titles}/app.rb +25 -17
  87. data/examples/{box_demo → widget_box_demo}/app.rb +99 -65
  88. data/examples/widget_calendar_demo/app.rb +109 -0
  89. data/examples/widget_cell_demo/app.rb +104 -0
  90. data/examples/widget_chart_demo/app.rb +213 -0
  91. data/examples/widget_gauge_demo/app.rb +212 -0
  92. data/examples/widget_layout_split/app.rb +246 -0
  93. data/examples/widget_line_gauge_demo/app.rb +217 -0
  94. data/examples/widget_list_demo/app.rb +382 -0
  95. data/examples/widget_list_styles/app.rb +141 -0
  96. data/examples/widget_popup_demo/app.rb +104 -0
  97. data/examples/widget_ratatui_logo_demo/app.rb +103 -0
  98. data/examples/widget_ratatui_mascot_demo/app.rb +93 -0
  99. data/examples/widget_rect/app.rb +205 -0
  100. data/examples/widget_render/app.rb +184 -0
  101. data/examples/widget_rich_text/app.rb +137 -0
  102. data/examples/widget_scroll_text/app.rb +108 -0
  103. data/examples/widget_scrollbar_demo/app.rb +153 -0
  104. data/examples/widget_sparkline_demo/app.rb +274 -0
  105. data/examples/widget_style_colors/app.rb +19 -21
  106. data/examples/widget_table_flex/app.rb +95 -0
  107. data/examples/widget_tabs_demo/app.rb +167 -0
  108. data/ext/ratatui_ruby/Cargo.lock +1 -1
  109. data/ext/ratatui_ruby/Cargo.toml +1 -1
  110. data/ext/ratatui_ruby/src/events.rs +121 -36
  111. data/ext/ratatui_ruby/src/frame.rs +115 -0
  112. data/ext/ratatui_ruby/src/lib.rs +79 -26
  113. data/ext/ratatui_ruby/src/rendering.rs +8 -4
  114. data/ext/ratatui_ruby/src/style.rs +138 -57
  115. data/ext/ratatui_ruby/src/terminal.rs +5 -9
  116. data/ext/ratatui_ruby/src/text.rs +13 -6
  117. data/ext/ratatui_ruby/src/widgets/barchart.rs +56 -54
  118. data/ext/ratatui_ruby/src/widgets/block.rs +7 -6
  119. data/ext/ratatui_ruby/src/widgets/canvas.rs +21 -3
  120. data/ext/ratatui_ruby/src/widgets/chart.rs +20 -10
  121. data/ext/ratatui_ruby/src/widgets/layout.rs +9 -4
  122. data/ext/ratatui_ruby/src/widgets/list.rs +32 -9
  123. data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
  124. data/ext/ratatui_ruby/src/widgets/paragraph.rs +1 -1
  125. data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +19 -8
  126. data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +17 -10
  127. data/ext/ratatui_ruby/src/widgets/scrollbar.rs +4 -2
  128. data/ext/ratatui_ruby/src/widgets/sparkline.rs +14 -11
  129. data/ext/ratatui_ruby/src/widgets/table.rs +8 -4
  130. data/ext/ratatui_ruby/src/widgets/tabs.rs +11 -11
  131. data/lib/ratatui_ruby/cell.rb +3 -3
  132. data/lib/ratatui_ruby/event/key.rb +1 -1
  133. data/lib/ratatui_ruby/event/none.rb +43 -0
  134. data/lib/ratatui_ruby/event.rb +56 -4
  135. data/lib/ratatui_ruby/frame.rb +87 -0
  136. data/lib/ratatui_ruby/schema/bar_chart/bar.rb +11 -11
  137. data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +1 -5
  138. data/lib/ratatui_ruby/schema/bar_chart.rb +217 -217
  139. data/lib/ratatui_ruby/schema/block.rb +163 -168
  140. data/lib/ratatui_ruby/schema/calendar.rb +66 -67
  141. data/lib/ratatui_ruby/schema/canvas.rb +63 -63
  142. data/lib/ratatui_ruby/schema/center.rb +46 -46
  143. data/lib/ratatui_ruby/schema/chart.rb +135 -143
  144. data/lib/ratatui_ruby/schema/clear.rb +42 -42
  145. data/lib/ratatui_ruby/schema/constraint.rb +76 -76
  146. data/lib/ratatui_ruby/schema/cursor.rb +25 -25
  147. data/lib/ratatui_ruby/schema/gauge.rb +53 -53
  148. data/lib/ratatui_ruby/schema/layout.rb +87 -87
  149. data/lib/ratatui_ruby/schema/line_gauge.rb +62 -62
  150. data/lib/ratatui_ruby/schema/list.rb +86 -84
  151. data/lib/ratatui_ruby/schema/overlay.rb +31 -31
  152. data/lib/ratatui_ruby/schema/paragraph.rb +80 -80
  153. data/lib/ratatui_ruby/schema/ratatui_logo.rb +10 -6
  154. data/lib/ratatui_ruby/schema/ratatui_mascot.rb +10 -5
  155. data/lib/ratatui_ruby/schema/rect.rb +60 -60
  156. data/lib/ratatui_ruby/schema/scrollbar.rb +119 -119
  157. data/lib/ratatui_ruby/schema/shape/label.rb +1 -1
  158. data/lib/ratatui_ruby/schema/sparkline.rb +111 -110
  159. data/lib/ratatui_ruby/schema/style.rb +46 -46
  160. data/lib/ratatui_ruby/schema/table.rb +112 -119
  161. data/lib/ratatui_ruby/schema/tabs.rb +66 -67
  162. data/lib/ratatui_ruby/session/autodoc.rb +417 -0
  163. data/lib/ratatui_ruby/session.rb +40 -23
  164. data/lib/ratatui_ruby/test_helper.rb +185 -19
  165. data/lib/ratatui_ruby/version.rb +1 -1
  166. data/lib/ratatui_ruby.rb +65 -39
  167. data/{examples/sparkline_demo → sig/examples/app_all_events}/app.rbs +3 -2
  168. data/sig/examples/app_all_events/model/event_entry.rbs +16 -0
  169. data/sig/examples/app_all_events/model/events.rbs +15 -0
  170. data/sig/examples/app_all_events/model/timestamp.rbs +11 -0
  171. data/sig/examples/app_all_events/view/app_view.rbs +8 -0
  172. data/sig/examples/app_all_events/view/controls_view.rbs +6 -0
  173. data/sig/examples/app_all_events/view/counts_view.rbs +6 -0
  174. data/sig/examples/app_all_events/view/live_view.rbs +6 -0
  175. data/sig/examples/app_all_events/view/log_view.rbs +6 -0
  176. data/sig/examples/app_all_events/view.rbs +8 -0
  177. data/sig/examples/app_all_events/view_state.rbs +15 -0
  178. data/{examples/list_demo → sig/examples/app_color_picker}/app.rbs +2 -2
  179. data/sig/examples/app_login_form/app.rbs +11 -0
  180. data/sig/examples/app_map_demo/app.rbs +11 -0
  181. data/sig/examples/app_table_select/app.rbs +11 -0
  182. data/sig/examples/verify_quickstart_dsl/app.rbs +11 -0
  183. data/sig/examples/verify_quickstart_lifecycle/app.rbs +11 -0
  184. data/sig/examples/verify_readme_usage/app.rbs +11 -0
  185. data/sig/examples/widget_block_padding/app.rbs +11 -0
  186. data/sig/examples/widget_block_titles/app.rbs +11 -0
  187. data/sig/examples/widget_box_demo/app.rbs +11 -0
  188. data/sig/examples/widget_calendar_demo/app.rbs +11 -0
  189. data/sig/examples/widget_cell_demo/app.rbs +11 -0
  190. data/sig/examples/widget_chart_demo/app.rbs +11 -0
  191. data/{examples/gauge_demo → sig/examples/widget_gauge_demo}/app.rbs +4 -0
  192. data/sig/examples/widget_layout_split/app.rbs +10 -0
  193. data/sig/examples/widget_line_gauge_demo/app.rbs +11 -0
  194. data/sig/examples/widget_list_demo/app.rbs +12 -0
  195. data/sig/examples/widget_list_styles/app.rbs +11 -0
  196. data/sig/examples/widget_popup_demo/app.rbs +11 -0
  197. data/sig/examples/widget_ratatui_logo_demo/app.rbs +11 -0
  198. data/sig/examples/widget_ratatui_mascot_demo/app.rbs +11 -0
  199. data/sig/examples/widget_rect/app.rbs +12 -0
  200. data/sig/examples/widget_render/app.rbs +10 -0
  201. data/sig/examples/widget_rich_text/app.rbs +11 -0
  202. data/sig/examples/widget_scroll_text/app.rbs +11 -0
  203. data/sig/examples/widget_scrollbar_demo/app.rbs +11 -0
  204. data/sig/examples/widget_sparkline_demo/app.rbs +10 -0
  205. data/{examples → sig/examples}/widget_style_colors/app.rbs +1 -1
  206. data/sig/examples/widget_table_flex/app.rbs +11 -0
  207. data/sig/ratatui_ruby/frame.rbs +9 -0
  208. data/sig/ratatui_ruby/ratatui_ruby.rbs +3 -2
  209. data/sig/ratatui_ruby/schema/draw.rbs +4 -0
  210. data/sig/ratatui_ruby/schema/layout.rbs +1 -1
  211. data/sig/ratatui_ruby/session.rbs +94 -0
  212. data/tasks/autodoc/inventory.rb +61 -0
  213. data/tasks/autodoc/member.rb +56 -0
  214. data/tasks/autodoc/name.rb +19 -0
  215. data/tasks/autodoc/notice.rb +26 -0
  216. data/tasks/autodoc/rbs.rb +38 -0
  217. data/tasks/autodoc/rdoc.rb +45 -0
  218. data/tasks/autodoc.rake +47 -0
  219. data/tasks/bump/history.rb +2 -2
  220. data/tasks/doc.rake +600 -6
  221. data/tasks/example_viewer.html.erb +172 -0
  222. data/tasks/lint.rake +8 -4
  223. data/tasks/resources/index.html.erb +6 -0
  224. data/tasks/sourcehut.rake +4 -4
  225. data/tasks/terminal_preview/app_screenshot.rb +1 -3
  226. data/tasks/terminal_preview/crash_report.rb +7 -9
  227. data/tasks/terminal_preview/launcher_script.rb +4 -6
  228. data/tasks/terminal_preview/preview_collection.rb +4 -6
  229. data/tasks/terminal_preview/safety_confirmation.rb +3 -5
  230. data/tasks/terminal_preview/saved_screenshot.rb +7 -9
  231. data/tasks/terminal_preview/terminal_window.rb +7 -9
  232. data/tasks/test.rake +1 -1
  233. data/tasks/website/index_page.rb +3 -3
  234. data/tasks/website/version.rb +10 -10
  235. data/tasks/website/version_menu.rb +10 -12
  236. data/tasks/website/versioned_documentation.rb +49 -17
  237. data/tasks/website/website.rb +6 -8
  238. data/tasks/website.rake +4 -4
  239. metadata +156 -125
  240. data/LICENSES/BSD-2-Clause.txt +0 -9
  241. data/doc/contributors/better_dx.md +0 -543
  242. data/doc/contributors/example_analysis.md +0 -82
  243. data/doc/images/all_events.png +0 -0
  244. data/doc/images/block_padding.png +0 -0
  245. data/doc/images/block_titles.png +0 -0
  246. data/doc/images/box_demo.png +0 -0
  247. data/doc/images/calendar_demo.png +0 -0
  248. data/doc/images/cell_demo.png +0 -0
  249. data/doc/images/chart_demo.png +0 -0
  250. data/doc/images/flex_layout.png +0 -0
  251. data/doc/images/gauge_demo.png +0 -0
  252. data/doc/images/line_gauge_demo.png +0 -0
  253. data/doc/images/list_demo.png +0 -0
  254. data/doc/images/readme_usage.png +0 -0
  255. data/doc/images/scrollbar_demo.png +0 -0
  256. data/doc/images/sparkline_demo.png +0 -0
  257. data/doc/images/table_flex.png +0 -0
  258. data/examples/all_events/app.rb +0 -169
  259. data/examples/all_events/app.rbs +0 -7
  260. data/examples/all_events/test_app.rb +0 -139
  261. data/examples/analytics/app.rb +0 -258
  262. data/examples/analytics/app.rbs +0 -7
  263. data/examples/analytics/test_app.rb +0 -132
  264. data/examples/block_padding/app.rbs +0 -7
  265. data/examples/block_padding/test_app.rb +0 -31
  266. data/examples/block_titles/app.rbs +0 -7
  267. data/examples/block_titles/test_app.rb +0 -34
  268. data/examples/box_demo/app.rbs +0 -7
  269. data/examples/box_demo/test_app.rb +0 -88
  270. data/examples/calendar_demo/app.rb +0 -101
  271. data/examples/calendar_demo/app.rbs +0 -7
  272. data/examples/calendar_demo/test_app.rb +0 -108
  273. data/examples/cell_demo/app.rb +0 -108
  274. data/examples/cell_demo/app.rbs +0 -7
  275. data/examples/cell_demo/test_app.rb +0 -36
  276. data/examples/chart_demo/app.rb +0 -203
  277. data/examples/chart_demo/app.rbs +0 -7
  278. data/examples/chart_demo/test_app.rb +0 -102
  279. data/examples/custom_widget/app.rb +0 -51
  280. data/examples/custom_widget/app.rbs +0 -7
  281. data/examples/custom_widget/test_app.rb +0 -30
  282. data/examples/flex_layout/app.rb +0 -156
  283. data/examples/flex_layout/app.rbs +0 -7
  284. data/examples/flex_layout/test_app.rb +0 -65
  285. data/examples/gauge_demo/app.rb +0 -182
  286. data/examples/gauge_demo/test_app.rb +0 -120
  287. data/examples/hit_test/app.rb +0 -175
  288. data/examples/hit_test/app.rbs +0 -7
  289. data/examples/hit_test/test_app.rb +0 -102
  290. data/examples/line_gauge_demo/app.rb +0 -190
  291. data/examples/line_gauge_demo/app.rbs +0 -7
  292. data/examples/line_gauge_demo/test_app.rb +0 -129
  293. data/examples/list_demo/app.rb +0 -253
  294. data/examples/list_demo/test_app.rb +0 -237
  295. data/examples/list_styles/app.rb +0 -140
  296. data/examples/list_styles/app.rbs +0 -7
  297. data/examples/list_styles/test_app.rb +0 -157
  298. data/examples/login_form/app.rbs +0 -7
  299. data/examples/login_form/test_app.rb +0 -51
  300. data/examples/map_demo/app.rbs +0 -7
  301. data/examples/map_demo/test_app.rb +0 -149
  302. data/examples/mouse_events/app.rb +0 -97
  303. data/examples/mouse_events/app.rbs +0 -7
  304. data/examples/mouse_events/test_app.rb +0 -53
  305. data/examples/popup_demo/app.rb +0 -103
  306. data/examples/popup_demo/app.rbs +0 -7
  307. data/examples/popup_demo/test_app.rb +0 -54
  308. data/examples/quickstart_dsl/app.rbs +0 -7
  309. data/examples/quickstart_dsl/test_app.rb +0 -29
  310. data/examples/quickstart_lifecycle/app.rbs +0 -7
  311. data/examples/quickstart_lifecycle/test_app.rb +0 -29
  312. data/examples/ratatui_logo_demo/app.rb +0 -79
  313. data/examples/ratatui_logo_demo/app.rbs +0 -7
  314. data/examples/ratatui_logo_demo/test_app.rb +0 -51
  315. data/examples/ratatui_mascot_demo/app.rb +0 -84
  316. data/examples/ratatui_mascot_demo/app.rbs +0 -7
  317. data/examples/ratatui_mascot_demo/test_app.rb +0 -47
  318. data/examples/readme_usage/app.rb +0 -29
  319. data/examples/readme_usage/app.rbs +0 -7
  320. data/examples/readme_usage/test_app.rb +0 -29
  321. data/examples/rich_text/app.rb +0 -141
  322. data/examples/rich_text/app.rbs +0 -7
  323. data/examples/rich_text/test_app.rb +0 -166
  324. data/examples/scroll_text/app.rb +0 -103
  325. data/examples/scroll_text/app.rbs +0 -7
  326. data/examples/scroll_text/test_app.rb +0 -110
  327. data/examples/scrollbar_demo/app.rb +0 -143
  328. data/examples/scrollbar_demo/app.rbs +0 -7
  329. data/examples/scrollbar_demo/test_app.rb +0 -77
  330. data/examples/sparkline_demo/app.rb +0 -240
  331. data/examples/sparkline_demo/test_app.rb +0 -107
  332. data/examples/table_flex/app.rb +0 -65
  333. data/examples/table_flex/app.rbs +0 -7
  334. data/examples/table_flex/test_app.rb +0 -36
  335. data/examples/table_select/app.rbs +0 -7
  336. data/examples/table_select/test_app.rb +0 -180
  337. data/examples/widget_style_colors/test_app.rb +0 -48
  338. /data/doc/images/{analytics.png → app_analytics.png} +0 -0
  339. /data/doc/images/{custom_widget.png → app_custom_widget.png} +0 -0
  340. /data/doc/images/{login_form.png → app_login_form.png} +0 -0
  341. /data/doc/images/{map_demo.png → app_map_demo.png} +0 -0
  342. /data/doc/images/{mouse_events.png → app_mouse_events.png} +0 -0
  343. /data/doc/images/{table_select.png → app_table_select.png} +0 -0
  344. /data/doc/images/{quickstart_dsl.png → verify_quickstart_dsl.png} +0 -0
  345. /data/doc/images/{ratatui_logo_demo.png → verify_quickstart_layout.png} +0 -0
  346. /data/doc/images/{quickstart_lifecycle.png → verify_quickstart_lifecycle.png} +0 -0
  347. /data/doc/images/{list_styles.png → widget_list_styles.png} +0 -0
  348. /data/doc/images/{popup_demo.png → widget_popup_demo.png} +0 -0
  349. /data/doc/images/{hit_test.png → widget_rect.png} +0 -0
  350. /data/doc/images/{rich_text.png → widget_rich_text.png} +0 -0
  351. /data/doc/images/{scroll_text.png → widget_scroll_text.png} +0 -0
@@ -6,7 +6,22 @@
6
6
  $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
7
  require "ratatui_ruby"
8
8
 
9
- class BoxDemoApp
9
+ # Demonstrates visual container attributes with interactive cycling.
10
+ #
11
+ # Widgets often float in void. Without boundaries, interfaces become a chaotic mess of text. Users need structure to parse information.
12
+ #
13
+ # This demo showcases the <tt>Block</tt> widget. It provides an interactive playground where you can cycle through different border types, colors, and title alignments in real-time.
14
+ #
15
+ # Use it to understand how to define distinct areas and create visual hierarchy in your terminal interface.
16
+ #
17
+ # === Example
18
+ #
19
+ # Run the demo from the terminal:
20
+ #
21
+ # ruby examples/widget_box_demo/app.rb
22
+ #
23
+ # rdoc-image:/doc/images/widget_box_demo.png
24
+ class WidgetBoxDemo
10
25
  def initialize
11
26
  # Border Types (ratatui native styles)
12
27
  @border_types = [
@@ -15,7 +30,7 @@ class BoxDemoApp
15
30
  { name: "Double", type: :double },
16
31
  { name: "Thick", type: :thick },
17
32
  { name: "Quadrant Inside", type: :quadrant_inside },
18
- { name: "Quadrant Outside", type: :quadrant_outside }
33
+ { name: "Quadrant Outside", type: :quadrant_outside },
19
34
  ]
20
35
  @border_type_index = 0
21
36
 
@@ -23,14 +38,32 @@ class BoxDemoApp
23
38
  # NOTE: We define these ONCE in initialize for efficiency.
24
39
  @border_sets = [
25
40
  { name: "None", set: nil },
26
- { name: "Digits (Short)", set: {
27
- tl: "1", tr: "2", bl: "3", br: "4",
28
- vl: "5", vr: "6", ht: "7", hb: "8"
29
- }},
30
- { name: "Letters (Long)", set: {
31
- top_left: "A", top_right: "B", bottom_left: "C", bottom_right: "D",
32
- vertical_left: "E", vertical_right: "F", horizontal_top: "G", horizontal_bottom: "H"
33
- }}
41
+ {
42
+ name: "Digits (Short)",
43
+ set: {
44
+ tl: "1",
45
+ tr: "2",
46
+ bl: "3",
47
+ br: "4",
48
+ vl: "5",
49
+ vr: "6",
50
+ ht: "7",
51
+ hb: "8",
52
+ },
53
+ },
54
+ {
55
+ name: "Letters (Long)",
56
+ set: {
57
+ top_left: "A",
58
+ top_right: "B",
59
+ bottom_left: "C",
60
+ bottom_right: "D",
61
+ vertical_left: "E",
62
+ vertical_right: "F",
63
+ horizontal_top: "G",
64
+ horizontal_bottom: "H",
65
+ },
66
+ },
34
67
  ]
35
68
  @border_set_index = 0
36
69
 
@@ -39,26 +72,26 @@ class BoxDemoApp
39
72
  { name: "Red", color: "red" },
40
73
  { name: "Blue", color: "blue" },
41
74
  { name: "Yellow", color: "yellow" },
42
- { name: "Magenta", color: "magenta" }
75
+ { name: "Magenta", color: "magenta" },
43
76
  ]
44
77
  @color_index = 0
45
78
 
46
79
  @title_alignments = [
47
80
  { name: "Left", alignment: :left },
48
81
  { name: "Center", alignment: :center },
49
- { name: "Right", alignment: :right }
82
+ { name: "Right", alignment: :right },
50
83
  ]
51
84
  @title_alignment_index = 0
52
85
 
53
86
  @styles = [
54
87
  { name: "Default", style: nil },
55
- { name: "Blue on White", style: { fg: "blue", bg: "white", modifiers: [:bold] } }
88
+ { name: "Blue on White", style: { fg: "blue", bg: "white", modifiers: [:bold] } },
56
89
  ]
57
90
  @style_index = 0
58
91
 
59
92
  @title_styles = [
60
93
  { name: "Default", style: nil },
61
- { name: "Yellow Bold Underlined", style: { fg: "yellow", modifiers: [:bold, :underlined] } }
94
+ { name: "Yellow Bold Underlined", style: { fg: "yellow", modifiers: [:bold, :underlined] } },
62
95
  ]
63
96
  @title_style_index = 0
64
97
 
@@ -66,15 +99,18 @@ class BoxDemoApp
66
99
  { name: "Default (no border style)", style: nil },
67
100
  { name: "Bold Red", style: { fg: "red", modifiers: [:bold] } },
68
101
  { name: "Cyan Italic", style: { fg: "cyan", modifiers: [:italic] } },
69
- { name: "Magenta Dim", style: { fg: "magenta", modifiers: [:dim] } }
102
+ { name: "Magenta Dim", style: { fg: "magenta", modifiers: [:dim] } },
70
103
  ]
71
104
  @border_style_index = 0
72
105
 
73
- @hotkey_style = RatatuiRuby::Style.new(modifiers: [:bold, :underlined])
106
+ @hotkey_style = nil # Initialized in run when tui is available
74
107
  end
75
108
 
76
109
  def run
77
- RatatuiRuby.run do
110
+ RatatuiRuby.run do |tui|
111
+ @tui = tui
112
+ @hotkey_style = tui.style(modifiers: [:bold, :underlined])
113
+
78
114
  loop do
79
115
  render
80
116
  break if handle_input == :quit
@@ -82,13 +118,11 @@ class BoxDemoApp
82
118
  end
83
119
  end
84
120
 
85
- private
86
-
87
- def render
121
+ private def render
88
122
  # Get current values
89
123
  border_type_config = @border_types[@border_type_index]
90
124
  border_set_config = @border_sets[@border_set_index]
91
-
125
+
92
126
  color_config = @colors[@color_index]
93
127
  title_alignment_config = @title_alignments[@title_alignment_index]
94
128
  style_config = @styles[@style_index]
@@ -106,7 +140,7 @@ class BoxDemoApp
106
140
  type_display += " (Overridden)"
107
141
  end
108
142
 
109
- block = RatatuiRuby::Block.new(
143
+ block = @tui.block(
110
144
  title: "Box Demo",
111
145
  title_alignment: title_alignment_config[:alignment],
112
146
  title_style: title_style_config[:style],
@@ -119,72 +153,73 @@ class BoxDemoApp
119
153
  )
120
154
 
121
155
  # Main content
122
- main_panel = RatatuiRuby::Paragraph.new(
156
+ main_panel = @tui.paragraph(
123
157
  text: "Arrow Keys: Change Color\n\nCurrent Color: #{color_config[:name]}",
124
- block: block,
158
+ block:,
125
159
  fg: style_config[:style] ? nil : color_config[:color],
126
160
  style: style_config[:style],
127
161
  alignment: :center
128
162
  )
129
163
 
130
164
  # Bottom control panel
131
- control_panel = RatatuiRuby::Block.new(
165
+ control_panel = @tui.block(
132
166
  title: "Controls",
133
167
  borders: [:all],
134
168
  children: [
135
- RatatuiRuby::Paragraph.new(
169
+ @tui.paragraph(
136
170
  text: [
137
171
  # Line 1: Main Controls
138
- RatatuiRuby::Text::Line.new(spans: [
139
- RatatuiRuby::Text::Span.new(content: "↑↓←→", style: @hotkey_style),
140
- RatatuiRuby::Text::Span.new(content: ": Color (#{color_config[:name]}) "),
141
- RatatuiRuby::Text::Span.new(content: "q", style: @hotkey_style),
142
- RatatuiRuby::Text::Span.new(content: ": Quit")
172
+ @tui.text_line(spans: [
173
+ @tui.text_span(content: "↑↓←→", style: @hotkey_style),
174
+ @tui.text_span(content: ": Color (#{color_config[:name]}) "),
175
+ @tui.text_span(content: "q", style: @hotkey_style),
176
+ @tui.text_span(content: ": Quit"),
143
177
  ]),
144
178
  # Line 2: Borders
145
- RatatuiRuby::Text::Line.new(spans: [
146
- RatatuiRuby::Text::Span.new(content: "space", style: @hotkey_style),
147
- RatatuiRuby::Text::Span.new(content: ": Border Type (#{type_display}) "),
148
- RatatuiRuby::Text::Span.new(content: "c", style: @hotkey_style),
149
- RatatuiRuby::Text::Span.new(content: ": Border Set (#{border_set_config[:name]})")
179
+ @tui.text_line(spans: [
180
+ @tui.text_span(content: "space", style: @hotkey_style),
181
+ @tui.text_span(content: ": Border Type (#{type_display}) "),
182
+ @tui.text_span(content: "c", style: @hotkey_style),
183
+ @tui.text_span(content: ": Border Set (#{border_set_config[:name]})"),
150
184
  ]),
151
185
  # Line 3: Styles
152
- RatatuiRuby::Text::Line.new(spans: [
153
- RatatuiRuby::Text::Span.new(content: "s", style: @hotkey_style),
154
- RatatuiRuby::Text::Span.new(content: ": Style (#{style_config[:name]}) "),
155
- RatatuiRuby::Text::Span.new(content: "b", style: @hotkey_style),
156
- RatatuiRuby::Text::Span.new(content: ": Border Style (#{border_style_config[:name]})")
186
+ @tui.text_line(spans: [
187
+ @tui.text_span(content: "s", style: @hotkey_style),
188
+ @tui.text_span(content: ": Style (#{style_config[:name]}) "),
189
+ @tui.text_span(content: "b", style: @hotkey_style),
190
+ @tui.text_span(content: ": Border Style (#{border_style_config[:name]})"),
157
191
  ]),
158
192
  # Line 4: Title
159
- RatatuiRuby::Text::Line.new(spans: [
160
- RatatuiRuby::Text::Span.new(content: "enter", style: @hotkey_style),
161
- RatatuiRuby::Text::Span.new(content: ": Align Title (#{title_alignment_config[:name]}) "),
162
- RatatuiRuby::Text::Span.new(content: "t", style: @hotkey_style),
163
- RatatuiRuby::Text::Span.new(content: ": Title Style (#{title_style_config[:name]})")
164
- ])
193
+ @tui.text_line(spans: [
194
+ @tui.text_span(content: "enter", style: @hotkey_style),
195
+ @tui.text_span(content: ": Align Title (#{title_alignment_config[:name]}) "),
196
+ @tui.text_span(content: "t", style: @hotkey_style),
197
+ @tui.text_span(content: ": Title Style (#{title_style_config[:name]})"),
198
+ ]),
165
199
  ]
166
- )
200
+ ),
167
201
  ]
168
202
  )
169
203
 
170
- # Vertical Layout
171
- layout = RatatuiRuby::Layout.new(
172
- direction: :vertical,
173
- constraints: [
174
- RatatuiRuby::Constraint.fill(1),
175
- RatatuiRuby::Constraint.length(6),
176
- ],
177
- children: [main_panel, control_panel]
178
- )
179
-
180
- # 2. Render
181
- RatatuiRuby.draw(layout)
204
+ # 2. Render with Frame API
205
+ @tui.draw do |frame|
206
+ main_rect, control_rect = @tui.layout_split(
207
+ frame.area,
208
+ direction: :vertical,
209
+ constraints: [
210
+ @tui.constraint_fill(1),
211
+ @tui.constraint_length(6),
212
+ ]
213
+ )
214
+ frame.render_widget(main_panel, main_rect)
215
+ frame.render_widget(control_panel, control_rect)
216
+ end
182
217
  end
183
218
 
184
- def handle_input
219
+ private def handle_input
185
220
  # 3. Events
186
- case RatatuiRuby.poll_event
187
- in {type: :key, code: "q"} | {type: :key, code: "c", modifiers: ["ctrl"]}
221
+ case @tui.poll_event
222
+ in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
188
223
  :quit
189
224
  in type: :key, code: "up"
190
225
  @color_index = (@color_index - 1) % @colors.size
@@ -212,5 +247,4 @@ class BoxDemoApp
212
247
  end
213
248
  end
214
249
 
215
- BoxDemoApp.new.run if __FILE__ == $0
216
-
250
+ WidgetBoxDemo.new.run if __FILE__ == $0
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
+ # SPDX-License-Identifier: AGPL-3.0-or-later
5
+
6
+ $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
+ require "ratatui_ruby"
8
+
9
+ # Demonstrates monthly calendar attributes with interactive cycling.
10
+ #
11
+ # Dates are complex. Rendering them in a grid requires calculation of leap years, month lengths, and day-of-week offsets.
12
+ # Use this widget to skip the boilerplate.
13
+ #
14
+ # This demo showcases the <tt>Calendar</tt> widget. It provides an interactive playground where you can toggle headers, weekday labels, and event highlights in real-time.
15
+ #
16
+ # Use it to understand how to render time-based data grids efficiently.
17
+ #
18
+ # === Example
19
+ #
20
+ # Run the demo from the terminal:
21
+ #
22
+ # ruby examples/widget_calendar_demo/app.rb
23
+ #
24
+ # rdoc-image:/doc/images/widget_calendar_demo.png
25
+ class WidgetCalendarDemo
26
+ def run
27
+ RatatuiRuby.run do |tui|
28
+ show_header = true
29
+ show_weekdays = true
30
+ show_surrounding = false
31
+ show_events = true
32
+ hotkey_style = tui.style(modifiers: [:bold])
33
+
34
+ loop do
35
+ now = Time.now
36
+ surrounding_style = show_surrounding ? tui.style(fg: "gray", modifiers: [:dim]) : nil
37
+
38
+ events_map = if show_events
39
+ {
40
+ now => tui.style(fg: "green", modifiers: [:bold]),
41
+ (now + (86400 * 2)) => tui.style(fg: "red", modifiers: [:underlined]),
42
+ (now - (86400 * 5)) => tui.style(fg: "blue", bg: "white"),
43
+ }
44
+ else
45
+ {}
46
+ end
47
+
48
+ calendar = tui.calendar(
49
+ year: now.year,
50
+ month: now.month,
51
+ events: events_map,
52
+ header_style: tui.style(fg: "yellow", modifiers: [:bold]),
53
+ show_month_header: show_header,
54
+ show_weekdays_header: show_weekdays,
55
+ show_surrounding: surrounding_style,
56
+ block: tui.block(borders: [:top, :left, :right])
57
+ )
58
+
59
+ controls = tui.paragraph(
60
+ text: [
61
+ tui.text_line(spans: [
62
+ tui.text_span(content: " h/w/s/e", style: hotkey_style),
63
+ tui.text_span(content: ": Toggle Header/Weekdays/Surrounding/Events "),
64
+ tui.text_span(content: "q", style: hotkey_style),
65
+ tui.text_span(content: ": Quit"),
66
+ ]),
67
+ tui.text_line(spans: [
68
+ tui.text_span(content: " Events: ", style: hotkey_style),
69
+ tui.text_span(content: "Today (Green), +2d (Red), -5d (Blue) (#{show_events ? 'On' : 'Off'})"),
70
+ ]),
71
+ ],
72
+ block: tui.block(title: " Controls ", borders: [:all])
73
+ )
74
+
75
+ tui.draw do |frame|
76
+ calendar_area, controls_area = tui.layout_split(
77
+ frame.area,
78
+ direction: :vertical,
79
+ constraints: [
80
+ tui.constraint_min(0),
81
+ tui.constraint_length(4),
82
+ ]
83
+ )
84
+ frame.render_widget(calendar, calendar_area)
85
+ frame.render_widget(controls, controls_area)
86
+ end
87
+
88
+ case tui.poll_event
89
+ in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
90
+ break
91
+ in type: :key, code: "h"
92
+ show_header = !show_header
93
+ in type: :key, code: "w"
94
+ show_weekdays = !show_weekdays
95
+ in type: :key, code: "s"
96
+ show_surrounding = !show_surrounding
97
+ in type: :key, code: "e"
98
+ show_events = !show_events
99
+ else
100
+ nil
101
+ end
102
+
103
+ sleep 0.05
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ WidgetCalendarDemo.new.run if __FILE__ == $PROGRAM_NAME
@@ -0,0 +1,104 @@
1
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ #
3
+ # SPDX-License-Identifier: AGPL-3.0-or-later
4
+
5
+ # frozen_string_literal: true
6
+
7
+ $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
8
+ require "ratatui_ruby"
9
+
10
+ # A custom widget that fills its area with a checkered pattern using Cell objects.
11
+ class CheckeredBackground
12
+ def render(area)
13
+ cell = RatatuiRuby::Cell.new(char: "░", fg: :dark_gray)
14
+ commands = []
15
+ area.height.times do |y|
16
+ area.width.times do |x|
17
+ # Checkerboard logic
18
+ if (x + y).even?
19
+ # Use a dim cell for the background pattern
20
+ commands << RatatuiRuby::Draw.cell(area.x + x, area.y + y, cell)
21
+ end
22
+ end
23
+ end
24
+ commands
25
+ end
26
+ end
27
+
28
+ class WidgetCellDemo
29
+ def main
30
+ RatatuiRuby.run do |tui|
31
+ # Define some reusable cells for our table
32
+ ok_cell = RatatuiRuby::Cell.new(char: "OK", fg: :green)
33
+ fail_cell = RatatuiRuby::Cell.new(char: "FAIL", fg: :red, modifiers: ["bold"])
34
+ pending_cell = RatatuiRuby::Cell.new(char: "...", fg: :yellow, modifiers: ["dim"])
35
+
36
+ # A mix of Strings and Cells in rows
37
+ rows = [
38
+ ["Database", ok_cell],
39
+ ["Cache", ok_cell],
40
+ ["Worker", fail_cell],
41
+ ["Analytics", pending_cell],
42
+ ["Web Server", RatatuiRuby::Cell.new(char: "RESTARTING", fg: :blue, modifiers: ["rapid_blink"])],
43
+ ]
44
+
45
+ table = RatatuiRuby::Table.new(
46
+ header: ["Service", RatatuiRuby::Cell.new(char: "Status", modifiers: ["underlined"])],
47
+ rows:,
48
+ widths: [
49
+ RatatuiRuby::Constraint.percentage(70),
50
+ RatatuiRuby::Constraint.percentage(30),
51
+ ],
52
+ block: RatatuiRuby::Block.new(title: "System Status", borders: :all),
53
+ column_spacing: 1
54
+ )
55
+
56
+ # Main loop
57
+ loop do
58
+ tui.draw do |frame|
59
+ # Create a layout that holds both widgets
60
+ # We use a vertical layout:
61
+ # Top: Custom CheckeredBackground with specific height
62
+ # Bottom: Table using remaining space
63
+ top_area, bottom_area = RatatuiRuby::Layout.split(
64
+ frame.area,
65
+ direction: :vertical,
66
+ constraints: [
67
+ RatatuiRuby::Constraint.length(10), # Top section
68
+ RatatuiRuby::Constraint.min(0), # Bottom section
69
+ ]
70
+ )
71
+
72
+ # Top Child: An Overlay of Paragraph on top of CheckeredBackground
73
+ overlay = RatatuiRuby::Overlay.new(
74
+ layers: [
75
+ CheckeredBackground.new,
76
+ RatatuiRuby::Center.new(
77
+ width_percent: 50,
78
+ height_percent: 50,
79
+ child: RatatuiRuby::Paragraph.new(
80
+ text: "Custom Widget Demo\n(CheckeredBackground)",
81
+ alignment: :center,
82
+ block: RatatuiRuby::Block.new(borders: :all, title: "Overlay")
83
+ )
84
+ ),
85
+ ]
86
+ )
87
+ frame.render_widget(overlay, top_area)
88
+
89
+ # Bottom Child: The Table
90
+ frame.render_widget(table, bottom_area)
91
+ end
92
+
93
+ event = RatatuiRuby.poll_event
94
+ if event.is_a?(RatatuiRuby::Event::Key) && (event.code == "q" || (event.code == "c" && event.modifiers.include?("ctrl")))
95
+ break
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ if __FILE__ == $0
103
+ WidgetCellDemo.new.main
104
+ end