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
@@ -0,0 +1,274 @@
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 high-density data visualization with interactive attribute cycling.
10
+ #
11
+ # Users need context. A single value ("90% CPU") tells you current status, but not the trend. Full charts take up too much room.
12
+ #
13
+ # This demo showcases the <tt>Sparkline</tt> widget. It provides an interactive playground where you can cycle through data sets, directions, colors, and custom bar sets.
14
+ #
15
+ # Use it to understand how to condense history into a single line for dashboards or headers.
16
+ #
17
+ # === Example
18
+ #
19
+ # Run the demo from the terminal:
20
+ #
21
+ # ruby examples/widget_sparkline_demo/app.rb
22
+ #
23
+ # rdoc-image:/doc/images/widget_sparkline_demo.png
24
+ class WidgetSparklineDemo
25
+ def run
26
+ RatatuiRuby.run do |tui|
27
+ @tui = tui
28
+ setup
29
+ loop do
30
+ render
31
+ break if handle_input == :quit
32
+ end
33
+ end
34
+ end
35
+
36
+ private def setup
37
+ # Data sets with different characteristics
38
+ @data_sets = [
39
+ {
40
+ name: "Steady Growth",
41
+ data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
42
+ },
43
+ {
44
+ name: "With Gaps",
45
+ data: [5, nil, 8, nil, 6, nil, 9, nil, 7, nil, 10, nil],
46
+ },
47
+ {
48
+ name: "Random",
49
+ data: [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8],
50
+ },
51
+ {
52
+ name: "Sawtooth",
53
+ data: [1, 2, 3, 4, 5, 4, 3, 2, 1, 2, 3, 4],
54
+ },
55
+ {
56
+ name: "Peaks",
57
+ data: [1, 5, 1, 8, 1, 6, 1, 9, 1, 7, 1, 10],
58
+ },
59
+ ]
60
+ @data_index = 0
61
+
62
+ @directions = [
63
+ { name: "Left to Right", direction: :left_to_right },
64
+ { name: "Right to Left", direction: :right_to_left },
65
+ ]
66
+ @direction_index = 0
67
+
68
+ @styles = [
69
+ { name: "Green", style: @tui.style(fg: :green) },
70
+ { name: "Yellow", style: @tui.style(fg: :yellow) },
71
+ { name: "Red", style: @tui.style(fg: :red) },
72
+ { name: "Cyan", style: @tui.style(fg: :cyan) },
73
+ { name: "Magenta", style: @tui.style(fg: :magenta) },
74
+ ]
75
+ @style_index = 0
76
+
77
+ @absent_symbols = [
78
+ { name: "None", symbol: nil },
79
+ { name: "Dot (·)", symbol: "·" },
80
+ { name: "Square (▫)", symbol: "▫" },
81
+ { name: "Dash (-)", symbol: "-" },
82
+ { name: "Underscore (_)", symbol: "_" },
83
+ ]
84
+ @absent_symbol_index = 1
85
+
86
+ @absent_styles = [
87
+ { name: "Default", style: nil },
88
+ { name: "Dark Gray", style: @tui.style(fg: :dark_gray) },
89
+ { name: "Dim Red", style: @tui.style(fg: :red, modifiers: [:dim]) },
90
+ { name: "Dim Yellow", style: @tui.style(fg: :yellow, modifiers: [:dim]) },
91
+ ]
92
+ @absent_style_index = 0
93
+
94
+ @bar_sets = [
95
+ { name: "Default (Block)", set: nil },
96
+ {
97
+ name: "Numbers (0-8)",
98
+ set: {
99
+ 0 => "0", 1 => "1", 2 => "2", 3 => "3", 4 => "4", 5 => "5", 6 => "6", 7 => "7", 8 => "8"
100
+ },
101
+ },
102
+ { name: "ASCII (Heights)", set: [" ", "_", ".", "-", "=", "+", "*", "#", "@"] },
103
+ ]
104
+ @bar_set_index = 0
105
+
106
+ @hotkey_style = @tui.style(modifiers: [:bold, :underlined])
107
+ end
108
+
109
+ private def render
110
+ @tui.draw do |frame|
111
+ data_set = @data_sets[@data_index]
112
+ direction = @directions[@direction_index][:direction]
113
+ style = @styles[@style_index][:style]
114
+ absent_symbol = @absent_symbols[@absent_symbol_index][:symbol]
115
+ absent_value_style = @absent_styles[@absent_style_index][:style]
116
+ bar_set = @bar_sets[@bar_set_index][:set]
117
+
118
+ # Use static data for clarity when cycling options
119
+ current_data = data_set[:data]
120
+
121
+ layout = @tui.layout_split(
122
+ frame.area,
123
+ direction: :vertical,
124
+ constraints: [
125
+ @tui.constraint_fill(1),
126
+ @tui.constraint_length(6),
127
+ ]
128
+ )
129
+
130
+ # Main content area with multiple sparkline examples
131
+ main_content_area = layout[0]
132
+ main_layout = @tui.layout_split(
133
+ main_content_area,
134
+ direction: :vertical,
135
+ constraints: [
136
+ @tui.constraint_length(1),
137
+ @tui.constraint_length(3),
138
+ @tui.constraint_length(3),
139
+ @tui.constraint_length(3),
140
+ @tui.constraint_length(3),
141
+ @tui.constraint_fill(1),
142
+ ]
143
+ )
144
+
145
+ frame.render_widget(
146
+ @tui.paragraph(text: "Sparkline Widget Demo - Cycle attributes with hotkeys"),
147
+ main_layout[0]
148
+ )
149
+
150
+ # Sparkline 1: Main interactive sparkline
151
+ frame.render_widget(
152
+ @tui.sparkline(
153
+ data: current_data,
154
+ direction:,
155
+ style:,
156
+ absent_value_symbol: absent_symbol,
157
+ absent_value_style:,
158
+ bar_set:,
159
+ block: @tui.block(title: "Interactive Sparkline")
160
+ ),
161
+ main_layout[1]
162
+ )
163
+
164
+ # Sparkline 2: Same data, opposite direction
165
+ frame.render_widget(
166
+ @tui.sparkline(
167
+ data: current_data.reverse,
168
+ direction:,
169
+ style:,
170
+ absent_value_symbol: absent_symbol,
171
+ absent_value_style:,
172
+ bar_set:,
173
+ block: @tui.block(title: "Reversed Data")
174
+ ),
175
+ main_layout[2]
176
+ )
177
+
178
+ # Sparkline 3: Without absent value symbol (for comparison)
179
+ frame.render_widget(
180
+ @tui.sparkline(
181
+ data: current_data,
182
+ direction:,
183
+ style:,
184
+ bar_set:,
185
+ block: @tui.block(title: "Without Absent Marker")
186
+ ),
187
+ main_layout[3]
188
+ )
189
+
190
+ # Sparkline 4: Gap pattern responsive to absent marker controls
191
+ frame.render_widget(
192
+ @tui.sparkline(
193
+ data: [5, nil, 8, nil, 6, nil, 9, nil, 7, nil, 10, nil],
194
+ direction:,
195
+ style: @tui.style(fg: :blue),
196
+ absent_value_symbol: absent_symbol,
197
+ absent_value_style:,
198
+ bar_set:,
199
+ block: @tui.block(title: "Gap Pattern (Responsive)")
200
+ ),
201
+ main_layout[4]
202
+ )
203
+
204
+ # Bottom control panel
205
+ control_area = layout[1]
206
+ frame.render_widget(
207
+ @tui.block(
208
+ title: "Controls",
209
+ borders: [:all],
210
+ children: [
211
+ @tui.paragraph(
212
+ text: [
213
+ # Line 1: Data
214
+ @tui.text_line(spans: [
215
+ @tui.text_span(content: "↑/↓", style: @hotkey_style),
216
+ @tui.text_span(content: ": Data (#{@data_sets[@data_index][:name]})"),
217
+ ]),
218
+ # Line 2: View
219
+ @tui.text_line(spans: [
220
+ @tui.text_span(content: "d", style: @hotkey_style),
221
+ @tui.text_span(content: ": Direction (#{@directions[@direction_index][:name]}) "),
222
+ @tui.text_span(content: "c", style: @hotkey_style),
223
+ @tui.text_span(content: ": Color (#{@styles[@style_index][:name]})"),
224
+ ]),
225
+ # Line 3: Markers
226
+ @tui.text_line(spans: [
227
+ @tui.text_span(content: "m", style: @hotkey_style),
228
+ @tui.text_span(content: ": Absent Value Symbol (#{@absent_symbols[@absent_symbol_index][:name]}) "),
229
+ @tui.text_span(content: "s", style: @hotkey_style),
230
+ @tui.text_span(content: ": Absent Value Style (#{@absent_styles[@absent_style_index][:name]})"),
231
+ ]),
232
+ # Line 4: General
233
+ @tui.text_line(spans: [
234
+ @tui.text_span(content: "b", style: @hotkey_style),
235
+ @tui.text_span(content: ": Bar Set (#{@bar_sets[@bar_set_index][:name]}) "),
236
+ @tui.text_span(content: "q", style: @hotkey_style),
237
+ @tui.text_span(content: ": Quit"),
238
+ ]),
239
+ ]
240
+ ),
241
+ ]
242
+ ),
243
+ control_area
244
+ )
245
+ end
246
+ end
247
+
248
+ private def handle_input
249
+ event = @tui.poll_event
250
+
251
+ case event
252
+ in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
253
+ :quit
254
+ in type: :key, code: "up"
255
+ @data_index = (@data_index - 1) % @data_sets.length
256
+ in type: :key, code: "down"
257
+ @data_index = (@data_index + 1) % @data_sets.length
258
+ in type: :key, code: "d"
259
+ @direction_index = (@direction_index + 1) % @directions.length
260
+ in type: :key, code: "c"
261
+ @style_index = (@style_index + 1) % @styles.length
262
+ in type: :key, code: "m"
263
+ @absent_symbol_index = (@absent_symbol_index + 1) % @absent_symbols.length
264
+ in type: :key, code: "s"
265
+ @absent_style_index = (@absent_style_index + 1) % @absent_styles.length
266
+ in type: :key, code: "b"
267
+ @bar_set_index = (@bar_set_index + 1) % @bar_sets.length
268
+ else
269
+ nil
270
+ end
271
+ end
272
+ end
273
+
274
+ WidgetSparklineDemo.new.run if __FILE__ == $PROGRAM_NAME
@@ -6,7 +6,7 @@
6
6
  $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
7
  require "ratatui_ruby"
8
8
 
9
- class ColorGradientDemo
9
+ class WidgetStyleColors
10
10
  def initialize
11
11
  @width = 80
12
12
  @height = 24
@@ -15,16 +15,16 @@ class ColorGradientDemo
15
15
  def run
16
16
  RatatuiRuby.run do |tui|
17
17
  loop do
18
- render(tui)
18
+ tui.draw do |frame|
19
+ frame.render_widget(render(tui), frame.area)
20
+ end
19
21
  event = tui.poll_event
20
- break if event&.key? && (event.ctrl_c? || event == :q)
22
+ break if event.key? && (event.ctrl_c? || event == :q)
21
23
  end
22
24
  end
23
25
  end
24
26
 
25
- private
26
-
27
- def render(tui)
27
+ private def render(tui)
28
28
  lines = []
29
29
 
30
30
  (0...@height).each do |row|
@@ -43,10 +43,10 @@ class ColorGradientDemo
43
43
  spans << span
44
44
  end
45
45
 
46
- lines << tui.text_line(spans: spans)
46
+ lines << tui.text_line(spans:)
47
47
  end
48
48
 
49
- paragraph = tui.paragraph(
49
+ tui.paragraph(
50
50
  text: lines,
51
51
  block: tui.block(
52
52
  title: "Hex Color Gradient (Press 'q' or Ctrl+C to exit)",
@@ -54,11 +54,9 @@ class ColorGradientDemo
54
54
  border_type: :rounded
55
55
  )
56
56
  )
57
-
58
- tui.draw(paragraph)
59
57
  end
60
58
 
61
- def hsl_to_rgb(hue, saturation, lightness)
59
+ private def hsl_to_rgb(hue, saturation, lightness)
62
60
  h = hue / 360.0
63
61
  s = saturation / 100.0
64
62
  l = lightness / 100.0
@@ -66,39 +64,39 @@ class ColorGradientDemo
66
64
  if s == 0
67
65
  r = g = b = l
68
66
  else
69
- q = l < 0.5 ? l * (1 + s) : l + s - (l * s)
70
- p = 2 * l - q
67
+ q = (l < 0.5) ? l * (1 + s) : l + s - (l * s)
68
+ p = (2 * l) - q
71
69
 
72
- r = hue_to_rgb(p, q, h + 1.0 / 3.0)
70
+ r = hue_to_rgb(p, q, h + (1.0 / 3.0))
73
71
  g = hue_to_rgb(p, q, h)
74
- b = hue_to_rgb(p, q, h - 1.0 / 3.0)
72
+ b = hue_to_rgb(p, q, h - (1.0 / 3.0))
75
73
  end
76
74
 
77
75
  [
78
76
  (r * 255).round,
79
77
  (g * 255).round,
80
- (b * 255).round
78
+ (b * 255).round,
81
79
  ]
82
80
  end
83
81
 
84
- def hue_to_rgb(p, q, t)
82
+ private def hue_to_rgb(p, q, t)
85
83
  t += 1 while t < 0
86
84
  t -= 1 while t > 1
87
85
 
88
86
  if t < 1.0 / 6.0
89
- p + (q - p) * 6 * t
87
+ p + ((q - p) * 6 * t)
90
88
  elsif t < 1.0 / 2.0
91
89
  q
92
90
  elsif t < 2.0 / 3.0
93
- p + (q - p) * (2.0 / 3.0 - t) * 6
91
+ p + ((q - p) * ((2.0 / 3.0) - t) * 6)
94
92
  else
95
93
  p
96
94
  end
97
95
  end
98
96
 
99
- def rgb_to_hex(rgb)
97
+ private def rgb_to_hex(rgb)
100
98
  "##{rgb.map { |c| c.to_s(16).upcase.rjust(2, '0') }.join}"
101
99
  end
102
100
  end
103
101
 
104
- ColorGradientDemo.new.run if __FILE__ == $PROGRAM_NAME
102
+ WidgetStyleColors.new.run if __FILE__ == $PROGRAM_NAME
@@ -0,0 +1,95 @@
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 structured data layout with flexible column distribution.
10
+ #
11
+ # Data is often multidimensional. You need to show relationships between fields (Name, Age, ID). Aligning columns manually in a monospaced environment is painful and error-prone.
12
+ #
13
+ # This demo showcases the <tt>Table</tt> widget's flex modes. It renders multiple tables demonstrating how data is distributed across the available space using <tt>:legacy</tt>, <tt>:space_between</tt>, and <tt>:space_around</tt> settings.
14
+ #
15
+ # Use it to understand how to build perfectly aligned grids for database records, logs, or file lists.
16
+ #
17
+ # === Example
18
+ #
19
+ # Run the demo from the terminal:
20
+ #
21
+ # ruby examples/widget_table_flex/app.rb
22
+ #
23
+ # rdoc-image:/doc/images/widget_table_flex.png
24
+ class WidgetTableFlex
25
+ def run
26
+ RatatuiRuby.run do |tui|
27
+ loop do
28
+ render(tui)
29
+ break if handle_input(tui) == :quit
30
+ end
31
+ end
32
+ end
33
+
34
+ def render(tui)
35
+ tui.draw do |frame|
36
+ chunks = tui.layout_split(
37
+ frame.area,
38
+ direction: :vertical,
39
+ constraints: [
40
+ tui.constraint_length(3),
41
+ tui.constraint_fill(1),
42
+ tui.constraint_fill(1),
43
+ tui.constraint_fill(1),
44
+ ]
45
+ )
46
+
47
+ frame.render_widget(
48
+ tui.paragraph(
49
+ text: "Table Flex Layout (press 'q' to quit)",
50
+ block: tui.block(title: "Header", borders: [:all])
51
+ ),
52
+ chunks[0]
53
+ )
54
+
55
+ frame.render_widget(
56
+ tui.table(
57
+ header: ["Legacy (Default)", "Table"],
58
+ rows: [["Item 1", "Item 2"], ["Item 3", "Item 4"]],
59
+ widths: [tui.constraint_length(20), tui.constraint_length(20)],
60
+ block: tui.block(title: "Flex: :legacy (Default)", borders: [:all])
61
+ ),
62
+ chunks[1]
63
+ )
64
+
65
+ frame.render_widget(
66
+ tui.table(
67
+ header: ["Space", "Between"],
68
+ rows: [["A", "B"], ["C", "D"]],
69
+ widths: [tui.constraint_length(20), tui.constraint_length(20)],
70
+ block: tui.block(title: "Flex: :space_between", borders: [:all]),
71
+ flex: :space_between
72
+ ),
73
+ chunks[2]
74
+ )
75
+
76
+ frame.render_widget(
77
+ tui.table(
78
+ header: ["Space", "Around"],
79
+ rows: [["E", "F"], ["G", "H"]],
80
+ widths: [tui.constraint_length(20), tui.constraint_length(20)],
81
+ block: tui.block(title: "Flex: :space_around", borders: [:all]),
82
+ flex: :space_around
83
+ ),
84
+ chunks[3]
85
+ )
86
+ end
87
+ end
88
+
89
+ def handle_input(tui)
90
+ event = tui.poll_event
91
+ :quit if event == "q" || event == :ctrl_c
92
+ end
93
+ end
94
+
95
+ WidgetTableFlex.new.run if __FILE__ == $0
@@ -0,0 +1,167 @@
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 view segregation with interactive tab navigation.
10
+ #
11
+ # Screen real estate is limited. You cannot show everything at once. Segregating content into views is necessary for complex apps.
12
+ #
13
+ # This demo showcases the <tt>Tabs</tt> widget. It provides an interactive playground where you can select tabs, cycle through dividers and styles, and adjust padding in real-time.
14
+ #
15
+ # Use it to understand how to build major mode switches or context navigation for your interface.
16
+ #
17
+ # === Example
18
+ #
19
+ # Run the demo from the terminal:
20
+ #
21
+ # ruby examples/widget_tabs_demo/app.rb
22
+ #
23
+ # rdoc-image:/doc/images/widget_tabs_demo.png
24
+ class WidgetTabsDemo
25
+ def initialize
26
+ @selected_tab = 0
27
+ @tabs = ["Revenue", "Traffic", "Errors", "Quarterly"]
28
+ @highlight_styles = nil
29
+ @highlight_style_index = 0
30
+ @divider_index = 0
31
+ @dividers = [" | ", " • ", " > ", " / "]
32
+ @base_styles = nil
33
+ @base_style_index = 0
34
+ @padding_left = 0
35
+ @padding_right = 0
36
+ @width_constraint_index = 0
37
+ @hotkey_style = nil
38
+ end
39
+
40
+ def run
41
+ RatatuiRuby.run do |tui|
42
+ @tui = tui
43
+ init_styles
44
+
45
+ loop do
46
+ render
47
+ break if handle_input == :quit
48
+ end
49
+ end
50
+ end
51
+
52
+ private def init_styles
53
+ @highlight_styles = [
54
+ { name: "Yellow Bold", style: @tui.style(fg: :yellow, modifiers: [:bold]) },
55
+ { name: "Italic Blue on White", style: @tui.style(fg: :blue, bg: :white, modifiers: [:italic]) },
56
+ { name: "Underlined Red", style: @tui.style(fg: :red, modifiers: [:underlined]) },
57
+ { name: "Reversed", style: @tui.style(modifiers: [:reversed]) },
58
+ ]
59
+ @base_styles = [
60
+ { name: "Default", style: nil },
61
+ { name: "White on Gray", style: @tui.style(fg: :white, bg: :dark_gray) },
62
+ { name: "White on Blue", style: @tui.style(fg: :white, bg: :blue) },
63
+ { name: "Italic", style: @tui.style(modifiers: [:italic]) },
64
+ ]
65
+ @hotkey_style = @tui.style(modifiers: [:bold, :underlined])
66
+ end
67
+
68
+ private def render
69
+ @tui.draw do |frame|
70
+ main_area, controls_area = @tui.layout_split(
71
+ frame.area,
72
+ direction: :vertical,
73
+ constraints: [
74
+ @tui.constraint_fill(1),
75
+ @tui.constraint_length(5),
76
+ ]
77
+ )
78
+
79
+ # Center the tabs vertically in the main area
80
+ tabs_area, = @tui.layout_split(
81
+ main_area,
82
+ direction: :vertical,
83
+ constraints: [
84
+ @tui.constraint_length(3),
85
+ ]
86
+ )
87
+
88
+ tabs = @tui.tabs(
89
+ titles: @tabs,
90
+ selected_index: @selected_tab,
91
+ block: @tui.block(title: "Tabs Demo", borders: [:all]),
92
+ divider: @dividers[@divider_index],
93
+ highlight_style: @highlight_styles[@highlight_style_index][:style],
94
+ style: @base_styles[@base_style_index][:style],
95
+ padding_left: @padding_left,
96
+ padding_right: @padding_right
97
+ )
98
+ frame.render_widget(tabs, tabs_area)
99
+
100
+ render_controls(frame, controls_area, tabs.width)
101
+ end
102
+ end
103
+
104
+ private def render_controls(frame, area, current_width)
105
+ controls = @tui.block(
106
+ title: "Controls",
107
+ borders: [:all],
108
+ children: [
109
+ @tui.paragraph(
110
+ text: [
111
+ @tui.text_line(spans: [
112
+ @tui.text_span(content: "←/→", style: @hotkey_style),
113
+ @tui.text_span(content: ": Select Tab "),
114
+ @tui.text_span(content: "h/l", style: @hotkey_style),
115
+ @tui.text_span(content: ": Pad Left (#{@padding_left}) "),
116
+ @tui.text_span(content: "j/k", style: @hotkey_style),
117
+ @tui.text_span(content: ": Pad Right (#{@padding_right}) "),
118
+ @tui.text_span(content: "q", style: @hotkey_style),
119
+ @tui.text_span(content: ": Quit"),
120
+ ]),
121
+ @tui.text_line(spans: [
122
+ @tui.text_span(content: "d", style: @hotkey_style),
123
+ @tui.text_span(content: ": Divider (#{@dividers[@divider_index]}) "),
124
+ @tui.text_span(content: "s", style: @hotkey_style),
125
+ @tui.text_span(content: ": Highlight (#{@highlight_styles[@highlight_style_index][:name]}) "),
126
+ @tui.text_span(content: "b", style: @hotkey_style),
127
+ @tui.text_span(content: ": Base Style (#{@base_styles[@base_style_index][:name]}) "),
128
+ ]),
129
+ @tui.text_line(spans: [
130
+ @tui.text_span(content: "Width: #{current_width}"),
131
+ ]),
132
+ ]
133
+ ),
134
+ ]
135
+ )
136
+ frame.render_widget(controls, area)
137
+ end
138
+
139
+ private def handle_input
140
+ case @tui.poll_event
141
+ in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
142
+ :quit
143
+ in type: :key, code: "right"
144
+ @selected_tab = (@selected_tab + 1) % @tabs.size
145
+ in type: :key, code: "left"
146
+ @selected_tab = (@selected_tab - 1) % @tabs.size
147
+ in type: :key, code: "d"
148
+ @divider_index = (@divider_index + 1) % @dividers.size
149
+ in type: :key, code: "s"
150
+ @highlight_style_index = (@highlight_style_index + 1) % @highlight_styles.size
151
+ in type: :key, code: "b"
152
+ @base_style_index = (@base_style_index + 1) % @base_styles.size
153
+ in type: :key, code: "h"
154
+ @padding_left = [@padding_left - 1, 0].max
155
+ in type: :key, code: "l"
156
+ @padding_left += 1
157
+ in type: :key, code: "j"
158
+ @padding_right = [@padding_right - 1, 0].max
159
+ in type: :key, code: "k"
160
+ @padding_right += 1
161
+ else
162
+ # Ignore other events
163
+ end
164
+ end
165
+ end
166
+
167
+ WidgetTabsDemo.new.run if __FILE__ == $0
@@ -1012,7 +1012,7 @@ dependencies = [
1012
1012
 
1013
1013
  [[package]]
1014
1014
  name = "ratatui_ruby"
1015
- version = "0.4.0"
1015
+ version = "0.5.0"
1016
1016
  dependencies = [
1017
1017
  "bumpalo",
1018
1018
  "lazy_static",
@@ -3,7 +3,7 @@
3
3
 
4
4
  [package]
5
5
  name = "ratatui_ruby"
6
- version = "0.4.0"
6
+ version = "0.5.0"
7
7
  edition = "2021"
8
8
 
9
9
  [lib]