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
@@ -0,0 +1,166 @@
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
+ # Rich Text Example
10
+ # Demonstrates the Span and Line objects for styling individual words
11
+ # within a block of text.
12
+ class WidgetRichText
13
+ def initialize
14
+ @scroll_pos = 0
15
+ @color_index = 0
16
+ end
17
+
18
+ def run
19
+ RatatuiRuby.run do |tui|
20
+ @tui = tui
21
+ loop do
22
+ render
23
+ event = handle_input
24
+ break if event == :quit
25
+ sleep 0.05
26
+ end
27
+ end
28
+ end
29
+
30
+ private def render
31
+ @tui.draw do |frame|
32
+ layout = @tui.layout_split(
33
+ frame.area,
34
+ direction: :vertical,
35
+ constraints: [
36
+ @tui.constraint_percentage(50),
37
+ @tui.constraint_percentage(50),
38
+ ]
39
+ )
40
+ frame.render_widget(simple_text_line_example, layout[0])
41
+ frame.render_widget(complex_example, layout[1])
42
+ end
43
+ end
44
+
45
+ private def simple_text_line_example
46
+ # Example 1: A line with mixed styles
47
+ @tui.paragraph(
48
+ text: [
49
+ @tui.text_line(
50
+ spans: [
51
+ @tui.text_span(
52
+ content: "Normal text, ",
53
+ style: nil
54
+ ),
55
+ @tui.text_span(
56
+ content: "Bold Text",
57
+ style: @tui.style(modifiers: [:bold])
58
+ ),
59
+ @tui.text_span(
60
+ content: ", ",
61
+ style: nil
62
+ ),
63
+ @tui.text_span(
64
+ content: "Italic Text",
65
+ style: @tui.style(modifiers: [:italic])
66
+ ),
67
+ @tui.text_span(
68
+ content: ", ",
69
+ style: nil
70
+ ),
71
+ @tui.text_span(
72
+ content: "Red Text",
73
+ style: @tui.style(fg: :red)
74
+ ),
75
+ @tui.text_span(
76
+ content: ".",
77
+ style: nil
78
+ ),
79
+ ]
80
+ ),
81
+ @tui.text_line(spans: []),
82
+ @tui.text_line(
83
+ spans: [
84
+ @tui.text_span(content: "Integer Color Test: "),
85
+ @tui.text_span(content: "Color #{@color_index}", style: @tui.style(fg: @color_index)),
86
+ @tui.text_span(content: " (Use "),
87
+ @tui.text_span(content: "↑ ↓", style: @tui.style(modifiers: [:bold])),
88
+ @tui.text_span(content: " for +/- 1,", style: nil),
89
+ @tui.text_span(content: "→ ←", style: @tui.style(modifiers: [:bold])),
90
+ @tui.text_span(content: " for +/- 10)", style: nil),
91
+ ]
92
+ ),
93
+ ],
94
+ block: @tui.block(
95
+ title: "Simple Rich Text",
96
+ borders: [:all]
97
+ )
98
+ )
99
+ end
100
+
101
+ private def complex_example
102
+ # Example 2: Multiple lines with different styles
103
+ @tui.paragraph(
104
+ text: [
105
+ @tui.text_line(
106
+ spans: [
107
+ @tui.text_span(content: "✓ ", style: @tui.style(fg: :green, modifiers: [:bold])),
108
+ @tui.text_span(content: "Feature Complete", style: nil),
109
+ @tui.text_span(content: " - All tests passing", style: @tui.style(fg: :gray)),
110
+ ]
111
+ ),
112
+ @tui.text_line(
113
+ spans: [
114
+ @tui.text_span(content: "⚠ ", style: @tui.style(fg: :yellow, modifiers: [:bold])),
115
+ @tui.text_span(content: "Warning", style: nil),
116
+ @tui.text_span(content: " - Documentation pending", style: @tui.style(fg: :gray)),
117
+ ]
118
+ ),
119
+ @tui.text_line(
120
+ spans: [
121
+ @tui.text_span(content: "✗ ", style: @tui.style(fg: :red, modifiers: [:bold])),
122
+ @tui.text_span(content: "Not Started", style: nil),
123
+ @tui.text_span(content: " - Performance benchmarks", style: @tui.style(fg: :gray)),
124
+ ]
125
+ ),
126
+ @tui.text_line(spans: []),
127
+ @tui.text_line(
128
+ spans: [
129
+ @tui.text_span(content: "Press ", style: nil),
130
+ @tui.text_span(content: "Q", style: @tui.style(modifiers: [:bold])),
131
+ @tui.text_span(content: " to quit, ", style: nil),
132
+ @tui.text_span(content: "↑ ↓", style: @tui.style(modifiers: [:bold])),
133
+ @tui.text_span(content: " to adjust color by 1, ", style: nil),
134
+ @tui.text_span(content: "← →", style: @tui.style(modifiers: [:bold])),
135
+ @tui.text_span(content: " to adjust color by 10.", style: nil),
136
+ ]
137
+ ),
138
+ ],
139
+ block: @tui.block(
140
+ title: "Status Report",
141
+ borders: [:all]
142
+ )
143
+ )
144
+ end
145
+
146
+ private def handle_input
147
+ event = @tui.poll_event
148
+ return :quit if event == "q" || event == :esc || event == :ctrl_c
149
+
150
+ if event.left?
151
+ @color_index = (@color_index - 10) % 256
152
+ elsif event.right?
153
+ @color_index = (@color_index + 10) % 256
154
+ elsif event.up?
155
+ @color_index = (@color_index + 1) % 256
156
+ elsif event.down?
157
+ @color_index = (@color_index - 1) % 256
158
+ end
159
+
160
+ nil
161
+ end
162
+ end
163
+
164
+ if __FILE__ == $0
165
+ WidgetRichText.new.run
166
+ end
@@ -0,0 +1,37 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
+ SPDX-License-Identifier: CC-BY-SA-4.0
4
+ -->
5
+
6
+ # Scroll Text Example
7
+
8
+ Demonstrates scrolling long text content within a fixed viewport.
9
+
10
+ Sometimes text exceeds the available space. The `Paragraph` widget supports a `scroll` parameter to simulate a viewport, allowing users to pan vertically and horizontally.
11
+
12
+ ## Features Demonstrated
13
+
14
+ - **Vertical Scrolling**: Moving through lines of text.
15
+ - **Horizontal Scrolling**: Panning across long, unwrapped lines.
16
+ - **State Management**: tracking `scroll_x` and `scroll_y` offsets in the application state.
17
+
18
+ ## Hotkeys
19
+
20
+ - **Arrows (↑/↓)**: Scroll Vertically (`scroll`)
21
+ - **Arrows (←/→)**: Scroll Horizontally (`scroll`)
22
+ - **q**: Quit
23
+
24
+ ## Usage
25
+
26
+ ```bash
27
+ ruby examples/widget_scroll_text/app.rb
28
+ ```
29
+
30
+ ## Learning Outcomes
31
+
32
+ Use this example if you need to...
33
+ - Build a log viewer.
34
+ - Create a "terms and conditions" scrollbox.
35
+ - Display code snippets that might be wider than the terminal.
36
+
37
+ ![Demo](/doc/images/widget_scroll_text.png)
@@ -0,0 +1,107 @@
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
+ # Demo: Scrollable Paragraph
10
+ # Shows how to scroll through long text content using arrow keys
11
+ #
12
+ # Helper: Disable experimental warnings since we use line_count/line_width
13
+ RatatuiRuby.experimental_warnings = false
14
+
15
+ class WidgetScrollText
16
+ def run
17
+ RatatuiRuby.run do |tui|
18
+ @tui = tui
19
+ @scroll_x = 0
20
+ @scroll_y = 0
21
+
22
+ @lines = (1..100).map do |i|
23
+ "Line #{i}: " + ("This is a long line of text that can be scrolled horizontally. " * 3) + "End of line #{i}"
24
+ end
25
+ @hotkey_style = @tui.style(modifiers: [:bold, :underlined])
26
+
27
+ loop do
28
+ draw
29
+ break if handle_input == :quit
30
+ end
31
+ end
32
+ end
33
+
34
+ def render
35
+ # No-op for compatibility if needed, or alias to draw, but draw now uses @tui
36
+ draw
37
+ end
38
+
39
+ def handle_input
40
+ case @tui.poll_event
41
+ in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
42
+ :quit
43
+ in type: :key, code: "up"
44
+ @scroll_y = [@scroll_y - 1, 0].max
45
+ in type: :key, code: "down"
46
+ @scroll_y = [@scroll_y + 1, @lines.length].min
47
+ in type: :key, code: "left"
48
+ @scroll_x = [@scroll_x - 1, 0].max
49
+ in type: :key, code: "right"
50
+ @scroll_x = [@scroll_x + 1, 100].min
51
+ else
52
+ nil
53
+ end
54
+ end
55
+
56
+ private def draw
57
+ @tui.draw do |frame|
58
+ layout = @tui.layout_split(
59
+ frame.area,
60
+ direction: :vertical,
61
+ constraints: [
62
+ @tui.constraint_fill(1),
63
+ @tui.constraint_length(5),
64
+ ]
65
+ )
66
+
67
+ text = @lines.join("\n")
68
+
69
+ # Main content
70
+ main_paragraph = @tui.paragraph(
71
+ text:,
72
+ scroll: [@scroll_y, @scroll_x],
73
+ block: @tui.block(
74
+ title: "Scrollable Text (#{text.lines.count} lines)",
75
+ borders: [:all]
76
+ )
77
+ )
78
+ frame.render_widget(main_paragraph, layout[0])
79
+
80
+ # Bottom control panel
81
+ control_text = [
82
+ @tui.text_line(spans: [
83
+ @tui.text_span(content: "NAVIGATION (Size: #{main_paragraph.line_count(65535)}x#{main_paragraph.line_width})", style: @tui.style(modifiers: [:bold])),
84
+ ]),
85
+ @tui.text_line(spans: [
86
+ @tui.text_span(content: "↑/↓", style: @hotkey_style),
87
+ @tui.text_span(content: ": Vert Scroll (#{@scroll_y}/#{main_paragraph.line_count(65535)}) "),
88
+ @tui.text_span(content: "←/→", style: @hotkey_style),
89
+ @tui.text_span(content: ": Horz Scroll (#{@scroll_x}/#{main_paragraph.line_width}) "),
90
+ @tui.text_span(content: "q", style: @hotkey_style),
91
+ @tui.text_span(content: ": Quit"),
92
+ ]),
93
+ ]
94
+
95
+ control_paragraph = @tui.paragraph(
96
+ text: control_text,
97
+ block: @tui.block(
98
+ title: "Controls",
99
+ borders: [:all]
100
+ )
101
+ )
102
+ frame.render_widget(control_paragraph, layout[1])
103
+ end
104
+ end
105
+ end
106
+
107
+ WidgetScrollText.new.run if __FILE__ == $PROGRAM_NAME
@@ -0,0 +1,37 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
+ SPDX-License-Identifier: CC-BY-SA-4.0
4
+ -->
5
+
6
+ # Scrollbar Widget Example
7
+
8
+ Demonstrates explicit scrollbars for navigation feedback.
9
+
10
+ Content overflows. Users get lost in long lists. Scrollbars provide essential spatial awareness ("How far down am I?") and navigation controls.
11
+
12
+ ## Features Demonstrated
13
+
14
+ - **Orientation**: Vertical, Horizontal, and variation modes (Right/Left, Top/Bottom).
15
+ - **Styling**: Custom characters for Track, Thumb, and arrows.
16
+ - **State Integration**: Linking the scrollbar `position` to the content view state.
17
+
18
+ ## Hotkeys
19
+
20
+ - **Mouse Wheel**: Scroll content (`position`)
21
+ - **s**: Cycle Scrollbar Theme (Standard, Rounded, ASCII, Minimal)
22
+ - **o**: Cycle Orientation (`orientation`)
23
+ - **q**: Quit
24
+
25
+ ## Usage
26
+
27
+ ```bash
28
+ ruby examples/widget_scrollbar_demo/app.rb
29
+ ```
30
+
31
+ ## Learning Outcomes
32
+
33
+ Use this example if you need to...
34
+ - Add visual scroll indicators to Lists or Tables.
35
+ - Implement specialized inputs like sliders or volume controls.
36
+
37
+ ![Demo](/doc/images/widget_scrollbar_demo.png)
@@ -0,0 +1,153 @@
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 viewport navigation with interactive theme and orientation cycling.
10
+ #
11
+ # Content overflows. Users get lost in long lists without landmarks. They need to know where they are and how much is left.
12
+ #
13
+ # This demo showcases the <tt>Scrollbar</tt> widget. It provides an interactive playground where you can toggle orientations and cycle through different themes (Standard, Rounded, ASCII, Minimal) in real-time.
14
+ #
15
+ # Use it to understand how to provide spatial awareness and navigation cues for overflowing content.
16
+ #
17
+ # === Example
18
+ #
19
+ # Run the demo from the terminal:
20
+ #
21
+ # ruby examples/widget_scrollbar_demo/app.rb
22
+ #
23
+ # rdoc-image:/doc/images/widget_scrollbar_demo.png
24
+ class WidgetScrollbarDemo
25
+ def initialize
26
+ @scroll_position = 0
27
+ @content_length = 50
28
+ @lines = (1..@content_length).map { |i| "Line #{i}" }
29
+ @orientation_index = 0
30
+ @orientations = [
31
+ :vertical,
32
+ :vertical_right,
33
+ :vertical_left,
34
+ :horizontal,
35
+ :horizontal_bottom,
36
+ :horizontal_top,
37
+ ]
38
+ @theme_index = 0
39
+ @themes = [
40
+ {
41
+ name: "Standard",
42
+ track_symbol: nil,
43
+ thumb_symbol: "█",
44
+ track_style: nil,
45
+ thumb_style: nil,
46
+ begin_symbol: nil,
47
+ end_symbol: nil,
48
+ },
49
+ {
50
+ name: "Rounded",
51
+ track_symbol: "│",
52
+ thumb_symbol: "┃",
53
+ track_style: { fg: "dark_gray" },
54
+ thumb_style: { fg: "cyan" },
55
+ begin_symbol: "▲",
56
+ end_symbol: "▼",
57
+ },
58
+ {
59
+ name: "ASCII",
60
+ track_symbol: "|",
61
+ thumb_symbol: "#",
62
+ track_style: { fg: "white" },
63
+ thumb_style: { fg: "red" },
64
+ begin_symbol: "^",
65
+ end_symbol: "v",
66
+ },
67
+ {
68
+ name: "Minimal",
69
+ track_symbol: " ",
70
+ thumb_symbol: "▐",
71
+ track_style: nil,
72
+ thumb_style: { fg: "yellow" },
73
+ begin_symbol: nil,
74
+ end_symbol: nil,
75
+ },
76
+ ]
77
+ end
78
+
79
+ def run
80
+ RatatuiRuby.run do |tui|
81
+ @tui = tui
82
+ loop do
83
+ draw
84
+ event = @tui.poll_event
85
+ break if event == "q" || event == :ctrl_c
86
+
87
+ handle_event(event)
88
+ end
89
+ end
90
+ end
91
+
92
+ private def handle_event(event)
93
+ if event.mouse?
94
+ case event.kind
95
+ when "scroll_up"
96
+ @scroll_position = [@scroll_position - 1, 0].max
97
+ when "scroll_down"
98
+ @scroll_position = [@scroll_position + 1, @content_length].min
99
+ end
100
+ end
101
+
102
+ if event.key? && event.to_s == "s"
103
+ @theme_index = (@theme_index + 1) % @themes.length
104
+ end
105
+
106
+ if event.key? && event.to_s == "o"
107
+ @orientation_index = (@orientation_index + 1) % @orientations.length
108
+ end
109
+ end
110
+
111
+ private def draw
112
+ @tui.draw do |frame|
113
+ # Calculate visible lines based on scroll position
114
+ # In a real app, you'd want to know the height of the available area.
115
+ # For this demo, we'll just show all lines but offset the text.
116
+ visible_lines = @lines[@scroll_position..-1] || []
117
+
118
+ # Paragraph with content
119
+ theme = @themes[@theme_index]
120
+ orientation = @orientations[@orientation_index]
121
+
122
+ p = @tui.paragraph(
123
+ text: visible_lines.join("\n"),
124
+ block: @tui.block(
125
+ titles: [
126
+ { content: "Scroll with Mouse Wheel | Theme: #{theme[:name]} | Orientation: #{orientation}" },
127
+ { content: "Press 's' to cycle theme, 'o' to cycle orientation", position: :bottom, alignment: :center },
128
+ ],
129
+ borders: [:all]
130
+ )
131
+ )
132
+
133
+ # Scrollbar
134
+ s = @tui.scrollbar(
135
+ content_length: @content_length,
136
+ position: @scroll_position,
137
+ orientation:,
138
+ track_symbol: theme[:track_symbol],
139
+ thumb_symbol: theme[:thumb_symbol],
140
+ track_style: theme[:track_style],
141
+ thumb_style: theme[:thumb_style],
142
+ begin_symbol: theme[:begin_symbol],
143
+ end_symbol: theme[:end_symbol]
144
+ )
145
+
146
+ # Render paragraph first, then scrollbar on top
147
+ frame.render_widget(p, frame.area)
148
+ frame.render_widget(s, frame.area)
149
+ end
150
+ end
151
+ end
152
+
153
+ WidgetScrollbarDemo.new.run if __FILE__ == $PROGRAM_NAME
@@ -0,0 +1,42 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
+ SPDX-License-Identifier: CC-BY-SA-4.0
4
+ -->
5
+
6
+ # Sparkline Widget Example
7
+
8
+ Demonstrates high-density data visualization in a condensed footprint.
9
+
10
+ Users need context. A single number ("90% CPU") tells you status, but not the trend. Full charts take up too much space. Sparklines condense history into a single line, perfect for headers and dashboards.
11
+
12
+ ## Features Demonstrated
13
+
14
+ - **High Density**: Showing dozens of data points in a small area.
15
+ - **Direction**: Rendering Left-to-Right (standard) or Right-to-Left (like a scrolling ticker).
16
+ - **Gaps**: Handling `nil` values with "absent symbols" to indicate missing data.
17
+ - **Styling**: Using colors and custom characters to indicate severity or type.
18
+
19
+ ## Hotkeys
20
+
21
+ - **Up/Down (↑/↓)**: Cycle Data Set (`data`)
22
+ - **d**: Cycle Direction (`direction`)
23
+ - **c**: Cycle Color (`style`)
24
+ - **m**: Cycle Absent Value Marker Symbol (`absent_value_symbol`)
25
+ - **s**: Cycle Absent Value Marker Style (`absent_value_style`)
26
+ - **b**: Cycle Bar Character Set (`bar_set`)
27
+ - **q**: Quit
28
+
29
+ ## Usage
30
+
31
+ ```bash
32
+ ruby examples/widget_sparkline_demo/app.rb
33
+ ```
34
+
35
+ ## Learning Outcomes
36
+
37
+ Use this example if you need to...
38
+ - Add a "CPU Load" graph to your header.
39
+ - Visualize stock price trends in a list row.
40
+ - Monitor memory usage over the last 60 seconds.
41
+
42
+ ![Demo](/doc/images/widget_sparkline_demo.png)