@effect-tui/react 0.1.3 → 0.1.4

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 (442) hide show
  1. package/dist/jsx-runtime.d.ts +13 -0
  2. package/dist/jsx-runtime.d.ts.map +1 -1
  3. package/dist/jsx-runtime.js.map +1 -1
  4. package/dist/src/codeblock.d.ts.map +1 -1
  5. package/dist/src/codeblock.js.map +1 -1
  6. package/dist/src/components/Divider.d.ts +18 -0
  7. package/dist/src/components/Divider.d.ts.map +1 -0
  8. package/dist/src/components/Divider.js +17 -0
  9. package/dist/src/components/Divider.js.map +1 -0
  10. package/dist/src/components/Markdown.d.ts +66 -0
  11. package/dist/src/components/Markdown.d.ts.map +1 -0
  12. package/dist/src/components/Markdown.js +226 -0
  13. package/dist/src/components/Markdown.js.map +1 -0
  14. package/dist/src/components/MultilineTextInput.d.ts +65 -0
  15. package/dist/src/components/MultilineTextInput.d.ts.map +1 -0
  16. package/dist/src/components/MultilineTextInput.js +607 -0
  17. package/dist/src/components/MultilineTextInput.js.map +1 -0
  18. package/dist/src/components/Overlay.d.ts +46 -0
  19. package/dist/src/components/Overlay.d.ts.map +1 -0
  20. package/dist/src/components/Overlay.js +11 -0
  21. package/dist/src/components/Overlay.js.map +1 -0
  22. package/dist/src/components/Static.d.ts +44 -0
  23. package/dist/src/components/Static.d.ts.map +1 -0
  24. package/dist/src/components/Static.js +53 -0
  25. package/dist/src/components/Static.js.map +1 -0
  26. package/dist/src/components/TextInput.d.ts +53 -0
  27. package/dist/src/components/TextInput.d.ts.map +1 -0
  28. package/dist/src/components/TextInput.js +210 -0
  29. package/dist/src/components/TextInput.js.map +1 -0
  30. package/dist/src/components/index.d.ts +7 -0
  31. package/dist/src/components/index.d.ts.map +1 -0
  32. package/dist/src/components/index.js +7 -0
  33. package/dist/src/components/index.js.map +1 -0
  34. package/dist/src/components/text-editing.d.ts +62 -0
  35. package/dist/src/components/text-editing.d.ts.map +1 -0
  36. package/dist/src/components/text-editing.js +385 -0
  37. package/dist/src/components/text-editing.js.map +1 -0
  38. package/dist/src/console/ConsoleCapture.d.ts +36 -0
  39. package/dist/src/console/ConsoleCapture.d.ts.map +1 -0
  40. package/dist/src/console/ConsoleCapture.js +210 -0
  41. package/dist/src/console/ConsoleCapture.js.map +1 -0
  42. package/dist/src/console/ConsolePopover.d.ts +18 -0
  43. package/dist/src/console/ConsolePopover.d.ts.map +1 -0
  44. package/dist/src/console/ConsolePopover.js +324 -0
  45. package/dist/src/console/ConsolePopover.js.map +1 -0
  46. package/dist/src/console/clipboard.d.ts +10 -0
  47. package/dist/src/console/clipboard.d.ts.map +1 -0
  48. package/dist/src/console/clipboard.js +74 -0
  49. package/dist/src/console/clipboard.js.map +1 -0
  50. package/dist/src/console/index.d.ts +5 -0
  51. package/dist/src/console/index.d.ts.map +1 -0
  52. package/dist/src/console/index.js +33 -0
  53. package/dist/src/console/index.js.map +1 -0
  54. package/dist/src/console/useConsole.d.ts +44 -0
  55. package/dist/src/console/useConsole.d.ts.map +1 -0
  56. package/dist/src/console/useConsole.js +91 -0
  57. package/dist/src/console/useConsole.js.map +1 -0
  58. package/dist/src/debug/DebugOverlay.d.ts +49 -0
  59. package/dist/src/debug/DebugOverlay.d.ts.map +1 -0
  60. package/dist/src/debug/DebugOverlay.js +438 -0
  61. package/dist/src/debug/DebugOverlay.js.map +1 -0
  62. package/dist/src/debug/DiagnosticsPanel.d.ts.map +1 -1
  63. package/dist/src/debug/DiagnosticsPanel.js.map +1 -1
  64. package/dist/src/dev/Toast.d.ts +19 -0
  65. package/dist/src/dev/Toast.d.ts.map +1 -0
  66. package/dist/src/dev/Toast.js +72 -0
  67. package/dist/src/dev/Toast.js.map +1 -0
  68. package/dist/src/dev/index.d.ts +2 -0
  69. package/dist/src/dev/index.d.ts.map +1 -0
  70. package/dist/src/dev/index.js +3 -0
  71. package/dist/src/dev/index.js.map +1 -0
  72. package/dist/src/dev.d.ts +114 -0
  73. package/dist/src/dev.d.ts.map +1 -0
  74. package/dist/src/dev.js +373 -0
  75. package/dist/src/dev.js.map +1 -0
  76. package/dist/src/highlight.d.ts +3 -3
  77. package/dist/src/highlight.d.ts.map +1 -1
  78. package/dist/src/highlight.js.map +1 -1
  79. package/dist/src/hmr-plugin.d.ts +2 -0
  80. package/dist/src/hmr-plugin.d.ts.map +1 -0
  81. package/dist/src/hmr-plugin.js +53 -0
  82. package/dist/src/hmr-plugin.js.map +1 -0
  83. package/dist/src/hooks/index.d.ts +4 -0
  84. package/dist/src/hooks/index.d.ts.map +1 -1
  85. package/dist/src/hooks/index.js +2 -0
  86. package/dist/src/hooks/index.js.map +1 -1
  87. package/dist/src/hooks/use-keyboard.d.ts +11 -0
  88. package/dist/src/hooks/use-keyboard.d.ts.map +1 -1
  89. package/dist/src/hooks/use-keyboard.js +22 -4
  90. package/dist/src/hooks/use-keyboard.js.map +1 -1
  91. package/dist/src/hooks/use-mouse.d.ts +24 -0
  92. package/dist/src/hooks/use-mouse.d.ts.map +1 -0
  93. package/dist/src/hooks/use-mouse.js +41 -0
  94. package/dist/src/hooks/use-mouse.js.map +1 -0
  95. package/dist/src/hooks/use-paste.d.ts +11 -0
  96. package/dist/src/hooks/use-paste.d.ts.map +1 -1
  97. package/dist/src/hooks/use-paste.js +17 -3
  98. package/dist/src/hooks/use-paste.js.map +1 -1
  99. package/dist/src/hooks/use-scroll.d.ts +79 -0
  100. package/dist/src/hooks/use-scroll.d.ts.map +1 -0
  101. package/dist/src/hooks/use-scroll.js +239 -0
  102. package/dist/src/hooks/use-scroll.js.map +1 -0
  103. package/dist/src/hooks/useFrameStats.js.map +1 -1
  104. package/dist/src/hosts/base.d.ts +62 -1
  105. package/dist/src/hosts/base.d.ts.map +1 -1
  106. package/dist/src/hosts/base.js +118 -5
  107. package/dist/src/hosts/base.js.map +1 -1
  108. package/dist/src/hosts/box.d.ts +7 -7
  109. package/dist/src/hosts/box.d.ts.map +1 -1
  110. package/dist/src/hosts/box.js +30 -23
  111. package/dist/src/hosts/box.js.map +1 -1
  112. package/dist/src/hosts/canvas.d.ts +8 -8
  113. package/dist/src/hosts/canvas.d.ts.map +1 -1
  114. package/dist/src/hosts/canvas.js +13 -22
  115. package/dist/src/hosts/canvas.js.map +1 -1
  116. package/dist/src/hosts/codeblock.d.ts +7 -7
  117. package/dist/src/hosts/codeblock.d.ts.map +1 -1
  118. package/dist/src/hosts/codeblock.js +11 -20
  119. package/dist/src/hosts/codeblock.js.map +1 -1
  120. package/dist/src/hosts/flex-container.d.ts +45 -0
  121. package/dist/src/hosts/flex-container.d.ts.map +1 -0
  122. package/dist/src/hosts/flex-container.js +90 -0
  123. package/dist/src/hosts/flex-container.js.map +1 -0
  124. package/dist/src/hosts/hstack.d.ts +6 -11
  125. package/dist/src/hosts/hstack.d.ts.map +1 -1
  126. package/dist/src/hosts/hstack.js +6 -41
  127. package/dist/src/hosts/hstack.js.map +1 -1
  128. package/dist/src/hosts/index.d.ts +4 -0
  129. package/dist/src/hosts/index.d.ts.map +1 -1
  130. package/dist/src/hosts/index.js +10 -0
  131. package/dist/src/hosts/index.js.map +1 -1
  132. package/dist/src/hosts/overlay-item.d.ts +32 -0
  133. package/dist/src/hosts/overlay-item.d.ts.map +1 -0
  134. package/dist/src/hosts/overlay-item.js +54 -0
  135. package/dist/src/hosts/overlay-item.js.map +1 -0
  136. package/dist/src/hosts/overlay.d.ts +30 -0
  137. package/dist/src/hosts/overlay.d.ts.map +1 -0
  138. package/dist/src/hosts/overlay.js +105 -0
  139. package/dist/src/hosts/overlay.js.map +1 -0
  140. package/dist/src/hosts/scroll.d.ts +56 -0
  141. package/dist/src/hosts/scroll.d.ts.map +1 -0
  142. package/dist/src/hosts/scroll.js +204 -0
  143. package/dist/src/hosts/scroll.js.map +1 -0
  144. package/dist/src/hosts/single-child.d.ts +16 -0
  145. package/dist/src/hosts/single-child.d.ts.map +1 -0
  146. package/dist/src/hosts/single-child.js +45 -0
  147. package/dist/src/hosts/single-child.js.map +1 -0
  148. package/dist/src/hosts/spacer.d.ts.map +1 -1
  149. package/dist/src/hosts/spacer.js +7 -3
  150. package/dist/src/hosts/spacer.js.map +1 -1
  151. package/dist/src/hosts/text.d.ts +9 -6
  152. package/dist/src/hosts/text.d.ts.map +1 -1
  153. package/dist/src/hosts/text.js +49 -22
  154. package/dist/src/hosts/text.js.map +1 -1
  155. package/dist/src/hosts/vstack.d.ts +6 -11
  156. package/dist/src/hosts/vstack.d.ts.map +1 -1
  157. package/dist/src/hosts/vstack.js +6 -41
  158. package/dist/src/hosts/vstack.js.map +1 -1
  159. package/dist/src/hosts/zstack.d.ts.map +1 -1
  160. package/dist/src/hosts/zstack.js +16 -5
  161. package/dist/src/hosts/zstack.js.map +1 -1
  162. package/dist/src/index.d.ts +9 -2
  163. package/dist/src/index.d.ts.map +1 -1
  164. package/dist/src/index.js +10 -2
  165. package/dist/src/index.js.map +1 -1
  166. package/dist/src/inline/index.d.ts.map +1 -1
  167. package/dist/src/inline/index.js.map +1 -1
  168. package/dist/src/motion/color-motion-value.d.ts.map +1 -1
  169. package/dist/src/motion/color-motion-value.js.map +1 -1
  170. package/dist/src/motion/color.d.ts +1 -29
  171. package/dist/src/motion/color.d.ts.map +1 -1
  172. package/dist/src/motion/color.js +2 -170
  173. package/dist/src/motion/color.js.map +1 -1
  174. package/dist/src/motion/color.test.js.map +1 -1
  175. package/dist/src/motion/event-emitter.d.ts.map +1 -1
  176. package/dist/src/motion/event-emitter.js.map +1 -1
  177. package/dist/src/motion/frame.js.map +1 -1
  178. package/dist/src/motion/hooks.d.ts.map +1 -1
  179. package/dist/src/motion/hooks.js +8 -3
  180. package/dist/src/motion/hooks.js.map +1 -1
  181. package/dist/src/motion/index.d.ts.map +1 -1
  182. package/dist/src/motion/index.js.map +1 -1
  183. package/dist/src/motion/motion-value.d.ts.map +1 -1
  184. package/dist/src/motion/motion-value.js.map +1 -1
  185. package/dist/src/motion/motion-value.test.js.map +1 -1
  186. package/dist/src/motion/spring-math.d.ts +6 -1
  187. package/dist/src/motion/spring-math.d.ts.map +1 -1
  188. package/dist/src/motion/spring-math.js +6 -1
  189. package/dist/src/motion/spring-math.js.map +1 -1
  190. package/dist/src/motion/types.d.ts.map +1 -1
  191. package/dist/src/motion/types.js.map +1 -1
  192. package/dist/src/profiler.js.map +1 -1
  193. package/dist/src/reconciler/host-config.d.ts +5 -5
  194. package/dist/src/reconciler/host-config.d.ts.map +1 -1
  195. package/dist/src/reconciler/host-config.js +43 -51
  196. package/dist/src/reconciler/host-config.js.map +1 -1
  197. package/dist/src/reconciler/noop-methods.d.ts +29 -0
  198. package/dist/src/reconciler/noop-methods.d.ts.map +1 -0
  199. package/dist/src/reconciler/noop-methods.js +43 -0
  200. package/dist/src/reconciler/noop-methods.js.map +1 -0
  201. package/dist/src/reconciler/types.d.ts +68 -14
  202. package/dist/src/reconciler/types.d.ts.map +1 -1
  203. package/dist/src/remote/Procedures.d.ts +22 -0
  204. package/dist/src/remote/Procedures.d.ts.map +1 -0
  205. package/dist/src/remote/Procedures.js +42 -0
  206. package/dist/src/remote/Procedures.js.map +1 -0
  207. package/dist/src/remote/Router.d.ts +20 -0
  208. package/dist/src/remote/Router.d.ts.map +1 -0
  209. package/dist/src/remote/Router.js +26 -0
  210. package/dist/src/remote/Router.js.map +1 -0
  211. package/dist/src/remote/Server.d.ts +6 -0
  212. package/dist/src/remote/Server.d.ts.map +1 -0
  213. package/dist/src/remote/Server.js +53 -0
  214. package/dist/src/remote/Server.js.map +1 -0
  215. package/dist/src/remote/index.d.ts +18 -0
  216. package/dist/src/remote/index.d.ts.map +1 -0
  217. package/dist/src/remote/index.js +74 -0
  218. package/dist/src/remote/index.js.map +1 -0
  219. package/dist/src/renderer/core/FrameBuilder.d.ts +18 -0
  220. package/dist/src/renderer/core/FrameBuilder.d.ts.map +1 -0
  221. package/dist/src/renderer/core/FrameBuilder.js +38 -0
  222. package/dist/src/renderer/core/FrameBuilder.js.map +1 -0
  223. package/dist/src/renderer/core/RendererState.d.ts +41 -0
  224. package/dist/src/renderer/core/RendererState.d.ts.map +1 -0
  225. package/dist/src/renderer/core/RendererState.js +70 -0
  226. package/dist/src/renderer/core/RendererState.js.map +1 -0
  227. package/dist/src/renderer/core/index.d.ts +3 -0
  228. package/dist/src/renderer/core/index.d.ts.map +1 -0
  229. package/dist/src/renderer/core/index.js +3 -0
  230. package/dist/src/renderer/core/index.js.map +1 -0
  231. package/dist/src/renderer/input/InputProcessor.d.ts +25 -0
  232. package/dist/src/renderer/input/InputProcessor.d.ts.map +1 -0
  233. package/dist/src/renderer/input/InputProcessor.js +81 -0
  234. package/dist/src/renderer/input/InputProcessor.js.map +1 -0
  235. package/dist/src/renderer/input/index.d.ts +2 -0
  236. package/dist/src/renderer/input/index.d.ts.map +1 -0
  237. package/dist/src/renderer/input/index.js +2 -0
  238. package/dist/src/renderer/input/index.js.map +1 -0
  239. package/dist/src/renderer/lifecycle/EventBus.d.ts +41 -0
  240. package/dist/src/renderer/lifecycle/EventBus.d.ts.map +1 -0
  241. package/dist/src/renderer/lifecycle/EventBus.js +78 -0
  242. package/dist/src/renderer/lifecycle/EventBus.js.map +1 -0
  243. package/dist/src/renderer/lifecycle/ResizeManager.d.ts +34 -0
  244. package/dist/src/renderer/lifecycle/ResizeManager.d.ts.map +1 -0
  245. package/dist/src/renderer/lifecycle/ResizeManager.js +47 -0
  246. package/dist/src/renderer/lifecycle/ResizeManager.js.map +1 -0
  247. package/dist/src/renderer/lifecycle/TerminalSetup.d.ts +36 -0
  248. package/dist/src/renderer/lifecycle/TerminalSetup.d.ts.map +1 -0
  249. package/dist/src/renderer/lifecycle/TerminalSetup.js +82 -0
  250. package/dist/src/renderer/lifecycle/TerminalSetup.js.map +1 -0
  251. package/dist/src/renderer/lifecycle/index.d.ts +4 -0
  252. package/dist/src/renderer/lifecycle/index.d.ts.map +1 -0
  253. package/dist/src/renderer/lifecycle/index.js +4 -0
  254. package/dist/src/renderer/lifecycle/index.js.map +1 -0
  255. package/dist/src/renderer/modes/FullscreenRenderer.d.ts +12 -0
  256. package/dist/src/renderer/modes/FullscreenRenderer.d.ts.map +1 -0
  257. package/dist/src/renderer/modes/FullscreenRenderer.js +52 -0
  258. package/dist/src/renderer/modes/FullscreenRenderer.js.map +1 -0
  259. package/dist/src/renderer/modes/InlineRenderer.d.ts +22 -0
  260. package/dist/src/renderer/modes/InlineRenderer.d.ts.map +1 -0
  261. package/dist/src/renderer/modes/InlineRenderer.js +154 -0
  262. package/dist/src/renderer/modes/InlineRenderer.js.map +1 -0
  263. package/dist/src/renderer/modes/RendererMode.d.ts +42 -0
  264. package/dist/src/renderer/modes/RendererMode.d.ts.map +1 -0
  265. package/dist/src/renderer/modes/RendererMode.js +2 -0
  266. package/dist/src/renderer/modes/RendererMode.js.map +1 -0
  267. package/dist/src/renderer/modes/StaticContentRenderer.d.ts +25 -0
  268. package/dist/src/renderer/modes/StaticContentRenderer.d.ts.map +1 -0
  269. package/dist/src/renderer/modes/StaticContentRenderer.js +47 -0
  270. package/dist/src/renderer/modes/StaticContentRenderer.js.map +1 -0
  271. package/dist/src/renderer/modes/index.d.ts +5 -0
  272. package/dist/src/renderer/modes/index.d.ts.map +1 -0
  273. package/dist/src/renderer/modes/index.js +4 -0
  274. package/dist/src/renderer/modes/index.js.map +1 -0
  275. package/dist/src/renderer-context.d.ts +9 -0
  276. package/dist/src/renderer-context.d.ts.map +1 -0
  277. package/dist/src/renderer-context.js +22 -0
  278. package/dist/src/renderer-context.js.map +1 -0
  279. package/dist/src/renderer-types.d.ts +103 -0
  280. package/dist/src/renderer-types.d.ts.map +1 -0
  281. package/dist/src/renderer-types.js +2 -0
  282. package/dist/src/renderer-types.js.map +1 -0
  283. package/dist/src/renderer.d.ts +4 -86
  284. package/dist/src/renderer.d.ts.map +1 -1
  285. package/dist/src/renderer.js +213 -384
  286. package/dist/src/renderer.js.map +1 -1
  287. package/dist/src/test/index.d.ts.map +1 -1
  288. package/dist/src/test/index.js.map +1 -1
  289. package/dist/src/test/mock-streams.d.ts.map +1 -1
  290. package/dist/src/test/mock-streams.js.map +1 -1
  291. package/dist/src/test/render-tui.d.ts.map +1 -1
  292. package/dist/src/test/render-tui.js +2 -5
  293. package/dist/src/test/render-tui.js.map +1 -1
  294. package/dist/src/trace/SpanTree.d.ts.map +1 -1
  295. package/dist/src/trace/SpanTree.js +21 -11
  296. package/dist/src/trace/SpanTree.js.map +1 -1
  297. package/dist/src/trace/format-value.d.ts +15 -0
  298. package/dist/src/trace/format-value.d.ts.map +1 -0
  299. package/dist/src/trace/format-value.js +77 -0
  300. package/dist/src/trace/format-value.js.map +1 -0
  301. package/dist/src/trace/index.d.ts.map +1 -1
  302. package/dist/src/trace/index.js.map +1 -1
  303. package/dist/src/trace/location.js +1 -1
  304. package/dist/src/trace/location.js.map +1 -1
  305. package/dist/src/trace/span-processor.d.ts.map +1 -1
  306. package/dist/src/trace/span-processor.js.map +1 -1
  307. package/dist/src/trace/span-state.d.ts +19 -2
  308. package/dist/src/trace/span-state.d.ts.map +1 -1
  309. package/dist/src/trace/span-state.js +62 -31
  310. package/dist/src/trace/span-state.js.map +1 -1
  311. package/dist/src/trace/tui-logger.js.map +1 -1
  312. package/dist/src/utils/border.d.ts +1 -1
  313. package/dist/src/utils/border.d.ts.map +1 -1
  314. package/dist/src/utils/border.js +6 -0
  315. package/dist/src/utils/border.js.map +1 -1
  316. package/dist/src/utils/flex-layout.d.ts +2 -1
  317. package/dist/src/utils/flex-layout.d.ts.map +1 -1
  318. package/dist/src/utils/flex-layout.js +22 -33
  319. package/dist/src/utils/flex-layout.js.map +1 -1
  320. package/dist/src/utils/index.d.ts +1 -1
  321. package/dist/src/utils/index.d.ts.map +1 -1
  322. package/dist/src/utils/index.js +1 -1
  323. package/dist/src/utils/index.js.map +1 -1
  324. package/dist/src/utils/padding.d.ts.map +1 -1
  325. package/dist/src/utils/padding.js.map +1 -1
  326. package/dist/src/utils/styles.d.ts +20 -1
  327. package/dist/src/utils/styles.d.ts.map +1 -1
  328. package/dist/src/utils/styles.js +36 -1
  329. package/dist/src/utils/styles.js.map +1 -1
  330. package/dist/src/visualize/index.d.ts +8 -19
  331. package/dist/src/visualize/index.d.ts.map +1 -1
  332. package/dist/src/visualize/index.js +11 -25
  333. package/dist/src/visualize/index.js.map +1 -1
  334. package/dist/tsconfig.tsbuildinfo +1 -1
  335. package/jsx-dev-runtime.ts +5 -0
  336. package/jsx-runtime.ts +54 -0
  337. package/package.json +124 -92
  338. package/src/codeblock.tsx +34 -34
  339. package/src/components/Divider.tsx +23 -0
  340. package/src/components/Markdown.tsx +380 -0
  341. package/src/components/MultilineTextInput.tsx +749 -0
  342. package/src/components/Overlay.tsx +56 -0
  343. package/src/components/Static.tsx +68 -0
  344. package/src/components/TextInput.tsx +285 -0
  345. package/src/components/index.ts +6 -0
  346. package/src/components/text-editing.ts +464 -0
  347. package/src/console/ConsoleCapture.ts +272 -0
  348. package/src/console/ConsolePopover.tsx +487 -0
  349. package/src/console/clipboard.ts +81 -0
  350. package/src/console/index.ts +42 -0
  351. package/src/console/useConsole.ts +129 -0
  352. package/src/debug/DebugOverlay.ts +557 -0
  353. package/src/debug/DiagnosticsPanel.tsx +27 -27
  354. package/src/dev/Toast.tsx +117 -0
  355. package/src/dev/index.ts +2 -0
  356. package/src/dev.tsx +489 -0
  357. package/src/highlight.ts +46 -46
  358. package/src/hmr-plugin.ts +61 -0
  359. package/src/hooks/index.ts +4 -0
  360. package/src/hooks/use-keyboard.ts +44 -24
  361. package/src/hooks/use-mouse.ts +51 -0
  362. package/src/hooks/use-paste.ts +21 -6
  363. package/src/hooks/use-scroll.ts +386 -0
  364. package/src/hooks/useFrameStats.ts +17 -17
  365. package/src/hosts/base.ts +180 -59
  366. package/src/hosts/box.ts +117 -94
  367. package/src/hosts/canvas.ts +137 -141
  368. package/src/hosts/codeblock.ts +117 -133
  369. package/src/hosts/flex-container.ts +124 -0
  370. package/src/hosts/hstack.ts +11 -59
  371. package/src/hosts/index.ts +24 -14
  372. package/src/hosts/overlay-item.ts +72 -0
  373. package/src/hosts/overlay.ts +125 -0
  374. package/src/hosts/scroll.ts +255 -0
  375. package/src/hosts/single-child.ts +52 -0
  376. package/src/hosts/spacer.ts +30 -26
  377. package/src/hosts/text.ts +198 -164
  378. package/src/hosts/vstack.ts +11 -59
  379. package/src/hosts/zstack.ts +79 -67
  380. package/src/index.ts +44 -19
  381. package/src/inline/index.tsx +123 -123
  382. package/src/motion/color-motion-value.ts +67 -67
  383. package/src/motion/color.test.ts +107 -107
  384. package/src/motion/color.ts +9 -190
  385. package/src/motion/event-emitter.ts +20 -20
  386. package/src/motion/frame.ts +35 -35
  387. package/src/motion/hooks.ts +144 -139
  388. package/src/motion/index.ts +10 -10
  389. package/src/motion/motion-value.test.ts +207 -207
  390. package/src/motion/motion-value.ts +112 -112
  391. package/src/motion/spring-math.ts +88 -83
  392. package/src/motion/types.ts +25 -25
  393. package/src/profiler.ts +50 -50
  394. package/src/reconciler/host-config.ts +152 -174
  395. package/src/reconciler/noop-methods.ts +55 -0
  396. package/src/reconciler/types.ts +112 -46
  397. package/src/remote/Procedures.ts +52 -0
  398. package/src/remote/Router.ts +58 -0
  399. package/src/remote/Server.ts +76 -0
  400. package/src/remote/index.ts +90 -0
  401. package/src/renderer/core/FrameBuilder.ts +49 -0
  402. package/src/renderer/core/RendererState.ts +80 -0
  403. package/src/renderer/core/index.ts +2 -0
  404. package/src/renderer/input/InputProcessor.ts +94 -0
  405. package/src/renderer/input/index.ts +1 -0
  406. package/src/renderer/lifecycle/EventBus.ts +90 -0
  407. package/src/renderer/lifecycle/ResizeManager.ts +65 -0
  408. package/src/renderer/lifecycle/TerminalSetup.ts +105 -0
  409. package/src/renderer/lifecycle/index.ts +3 -0
  410. package/src/renderer/modes/FullscreenRenderer.ts +53 -0
  411. package/src/renderer/modes/InlineRenderer.ts +178 -0
  412. package/src/renderer/modes/RendererMode.ts +46 -0
  413. package/src/renderer/modes/StaticContentRenderer.ts +56 -0
  414. package/src/renderer/modes/index.ts +4 -0
  415. package/src/renderer-context.ts +27 -0
  416. package/src/renderer-types.ts +109 -0
  417. package/src/renderer.ts +391 -642
  418. package/src/test/index.ts +5 -5
  419. package/src/test/mock-streams.ts +115 -115
  420. package/src/test/render-tui.ts +84 -87
  421. package/src/utils/border.ts +79 -73
  422. package/src/utils/flex-layout.ts +80 -93
  423. package/src/utils/index.ts +1 -1
  424. package/src/utils/padding.ts +27 -27
  425. package/src/utils/styles.ts +50 -7
  426. package/src/visualize/index.tsx +225 -240
  427. package/dist/src/output.d.ts +0 -47
  428. package/dist/src/output.d.ts.map +0 -1
  429. package/dist/src/output.js +0 -125
  430. package/dist/src/output.js.map +0 -1
  431. package/dist/src/terminal.d.ts +0 -37
  432. package/dist/src/terminal.d.ts.map +0 -1
  433. package/dist/src/terminal.js +0 -65
  434. package/dist/src/terminal.js.map +0 -1
  435. package/src/output.ts +0 -156
  436. package/src/terminal.ts +0 -67
  437. package/src/trace/SpanTree.tsx +0 -195
  438. package/src/trace/index.tsx +0 -205
  439. package/src/trace/location.ts +0 -90
  440. package/src/trace/span-processor.ts +0 -65
  441. package/src/trace/span-state.ts +0 -286
  442. package/src/trace/tui-logger.ts +0 -72
@@ -0,0 +1,58 @@
1
+ // RPC handlers for remote session control
2
+ import type { Rpc } from "@effect/rpc"
3
+ import { Effect, Layer, Context } from "effect"
4
+ import type { KeyMsg } from "@effect-tui/core"
5
+ import { TuiRpcs } from "./Procedures.js"
6
+
7
+ // Service interface for the TUI session
8
+ export interface TuiSessionImpl {
9
+ readonly getScreenshot: () => string
10
+ readonly dispatchKey: (key: KeyMsg) => void
11
+ readonly dispatchPaste: (text: string) => void
12
+ readonly dispatchResize: (width: number, height: number) => void
13
+ readonly getInfo: () => { pid: number; width: number; height: number }
14
+ }
15
+
16
+ export class TuiSession extends Context.Tag("TuiSession")<
17
+ TuiSession,
18
+ TuiSessionImpl
19
+ >() {}
20
+
21
+ // Create the RPC handlers layer
22
+ export const HandlersLive: Layer.Layer<
23
+ | Rpc.Handler<"Screenshot">
24
+ | Rpc.Handler<"SendKey">
25
+ | Rpc.Handler<"Paste">
26
+ | Rpc.Handler<"Resize">
27
+ | Rpc.Handler<"Info">,
28
+ never,
29
+ TuiSession
30
+ > = TuiRpcs.toLayer(
31
+ Effect.gen(function* () {
32
+ const session = yield* TuiSession
33
+
34
+ return {
35
+ Screenshot: () => Effect.sync(() => session.getScreenshot()),
36
+
37
+ SendKey: ({ name, text, ctrl, shift, meta }) =>
38
+ Effect.sync(() => {
39
+ const key: KeyMsg = {
40
+ type: "key",
41
+ name: name as KeyMsg["name"],
42
+ text,
43
+ ctrl: ctrl ?? false,
44
+ shift: shift ?? false,
45
+ meta: meta ?? false,
46
+ }
47
+ session.dispatchKey(key)
48
+ }),
49
+
50
+ Paste: ({ text }) => Effect.sync(() => session.dispatchPaste(text)),
51
+
52
+ Resize: ({ width, height }) =>
53
+ Effect.sync(() => session.dispatchResize(width, height)),
54
+
55
+ Info: () => Effect.sync(() => session.getInfo()),
56
+ }
57
+ }),
58
+ )
@@ -0,0 +1,76 @@
1
+ // Remote server that exposes TUI session via Unix socket
2
+ import { Effect, Layer } from "effect"
3
+ import { RpcSerialization, RpcServer } from "@effect/rpc"
4
+ import { BunSocketServer } from "@effect/platform-bun"
5
+ import * as fs from "node:fs"
6
+ import * as path from "node:path"
7
+ import { TuiRpcs } from "./Procedures.js"
8
+ import { HandlersLive, TuiSession, type TuiSessionImpl } from "./Router.js"
9
+
10
+ // Default socket directory
11
+ const SOCKET_DIR = "/tmp/effect-tui-sessions"
12
+
13
+ // Ensure socket directory exists
14
+ const ensureSocketDir = Effect.sync(() => {
15
+ if (!fs.existsSync(SOCKET_DIR)) {
16
+ fs.mkdirSync(SOCKET_DIR, { recursive: true })
17
+ }
18
+ })
19
+
20
+ // Get socket path for current process
21
+ export const getSocketPath = (pid?: number) =>
22
+ path.join(SOCKET_DIR, `${pid ?? process.pid}.sock`)
23
+
24
+ // Clean up socket file
25
+ const cleanupSocket = (socketPath: string) =>
26
+ Effect.sync(() => {
27
+ try {
28
+ if (fs.existsSync(socketPath)) {
29
+ fs.unlinkSync(socketPath)
30
+ }
31
+ } catch {
32
+ // Ignore cleanup errors
33
+ }
34
+ })
35
+
36
+ // Create the server layer
37
+ export const makeServerLayer = (
38
+ sessionImpl: TuiSessionImpl,
39
+ socketPath?: string,
40
+ ) => {
41
+ const actualPath = socketPath ?? getSocketPath()
42
+
43
+ // Setup layer - creates directory, cleans stale socket
44
+ const SetupLive = Layer.scopedDiscard(
45
+ Effect.gen(function* () {
46
+ yield* ensureSocketDir
47
+ yield* cleanupSocket(actualPath)
48
+ yield* Effect.addFinalizer(() => cleanupSocket(actualPath))
49
+ // Use console.log so it gets captured by the debug console panel
50
+ console.log(`[remote] Listening on ${actualPath}`)
51
+ }),
52
+ )
53
+
54
+ // RPC handlers layer (needs TuiSession)
55
+ const HandlersLayer = HandlersLive.pipe(
56
+ Layer.provide(Layer.succeed(TuiSession, sessionImpl)),
57
+ )
58
+
59
+ // Full RPC server stack:
60
+ // 1. RpcServer.layer creates the RPC server, needs handlers
61
+ // 2. Handlers provide the implementation
62
+ // 3. Protocol layer provides socket protocol
63
+ // 4. Socket server provides the actual socket
64
+ const RpcLive = RpcServer.layer(TuiRpcs).pipe(
65
+ Layer.provide(HandlersLayer),
66
+ Layer.provideMerge(RpcServer.layerProtocolSocketServer),
67
+ Layer.provide(RpcSerialization.layerNdjson),
68
+ Layer.provide(
69
+ BunSocketServer.layer({
70
+ path: actualPath,
71
+ }),
72
+ ),
73
+ )
74
+
75
+ return Layer.merge(SetupLive, RpcLive)
76
+ }
@@ -0,0 +1,90 @@
1
+ // Remote session control for effect-tui
2
+ //
3
+ // Allows external tools (like Claude Code) to connect to a running TUI session
4
+ // to send keypresses and get screenshots.
5
+ //
6
+ // Usage:
7
+ // 1. Run app with EFFECT_TUI_REMOTE=1 to enable remote control
8
+ // 2. Connect using etui CLI or raw socket at /tmp/effect-tui-sessions/<pid>.sock
9
+
10
+ export { TuiRpcs } from "./Procedures.js"
11
+ export { TuiSession, HandlersLive } from "./Router.js"
12
+ export { makeServerLayer, getSocketPath } from "./Server.js"
13
+
14
+ import { Effect, Exit, Layer, Scope } from "effect"
15
+ import * as fs from "node:fs"
16
+ import type { TuiRenderer } from "../renderer-types.js"
17
+ import type { TuiSessionImpl } from "./Router.js"
18
+ import { makeServerLayer, getSocketPath } from "./Server.js"
19
+
20
+ /**
21
+ * Enable remote control for a TUI renderer.
22
+ * Starts an RPC server on a Unix socket at /tmp/effect-tui-sessions/<pid>.sock
23
+ *
24
+ * @param renderer - The TUI renderer to control
25
+ * @param socketPath - Optional custom socket path
26
+ * @returns A cleanup function to stop the server
27
+ */
28
+ export function enableRemote(
29
+ renderer: TuiRenderer,
30
+ socketPath?: string,
31
+ ): () => void {
32
+ const actualPath = socketPath ?? getSocketPath()
33
+
34
+ // Create session implementation from renderer
35
+ const session: TuiSessionImpl = {
36
+ getScreenshot: () => renderer.getScreenshot(),
37
+ dispatchKey: (key) => renderer.dispatchKey?.(key),
38
+ dispatchPaste: (text) => renderer.dispatchPaste?.(text),
39
+ dispatchResize: (width, height) => renderer.dispatchResize?.(width, height),
40
+ getInfo: () => ({
41
+ pid: process.pid,
42
+ width: renderer.width,
43
+ height: renderer.height,
44
+ }),
45
+ }
46
+
47
+ // Build and run the server layer
48
+ const serverLayer = makeServerLayer(session, actualPath)
49
+
50
+ // Use Effect runtime to manage the server lifecycle
51
+ let scope: Scope.CloseableScope | null = null
52
+
53
+ Effect.runPromise(
54
+ Effect.gen(function* () {
55
+ scope = yield* Scope.make()
56
+ yield* Layer.buildWithScope(serverLayer, scope)
57
+ }),
58
+ ).catch((err) => {
59
+ console.error("[effect-tui] Remote server error:", err)
60
+ })
61
+
62
+ // Ensure socket cleanup on process exit (Effect finalizers may not run on abrupt exit)
63
+ const cleanupSocket = () => {
64
+ try {
65
+ if (fs.existsSync(actualPath)) {
66
+ fs.unlinkSync(actualPath)
67
+ }
68
+ } catch {
69
+ // Ignore cleanup errors
70
+ }
71
+ }
72
+
73
+ // "exit" event fires synchronously on any exit (normal, SIGINT, SIGTERM, etc.)
74
+ process.on("exit", cleanupSocket)
75
+
76
+ return () => {
77
+ process.off("exit", cleanupSocket)
78
+ cleanupSocket()
79
+ if (scope) {
80
+ Effect.runPromise(Scope.close(scope, Exit.void))
81
+ }
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Check if remote control should be enabled (via EFFECT_TUI_REMOTE=1 env var)
87
+ */
88
+ export function shouldEnableRemote(): boolean {
89
+ return process.env.EFFECT_TUI_REMOTE === "1"
90
+ }
@@ -0,0 +1,49 @@
1
+ import { performance } from "node:perf_hooks"
2
+ import type { CellBuffer, Palette } from "@effect-tui/core"
3
+ import type { HostInstance } from "../../reconciler/types.js"
4
+ import * as Prof from "../../profiler.js"
5
+
6
+ export interface FrameTimings {
7
+ clear: number
8
+ layout: number
9
+ render: number
10
+ }
11
+
12
+ /**
13
+ * Handles the measure → layout → render pipeline for a single frame.
14
+ */
15
+ export class FrameBuilder {
16
+ /**
17
+ * Execute the frame pipeline: clear buffer, measure, layout, and render.
18
+ * Returns timing information for each phase.
19
+ */
20
+ build(root: HostInstance, buffer: CellBuffer, palette: Palette, width: number, height: number): FrameTimings {
21
+ // Clear buffer
22
+ let t = Prof.startPhase()
23
+ const clearStart = performance.now()
24
+ buffer.clear(0)
25
+ const clearMs = performance.now() - clearStart
26
+ Prof.endPhase("clear", t)
27
+
28
+ // Layout (measure + position)
29
+ t = Prof.startPhase()
30
+ const layoutStart = performance.now()
31
+ root.measure(width, height)
32
+ root.layout({ x: 0, y: 0, w: width, h: height })
33
+ const layoutMs = performance.now() - layoutStart
34
+ Prof.endPhase("layout", t)
35
+
36
+ // Render
37
+ t = Prof.startPhase()
38
+ const renderStart = performance.now()
39
+ root.render(buffer, palette)
40
+ const renderMs = performance.now() - renderStart
41
+ Prof.endPhase("render", t)
42
+
43
+ return {
44
+ clear: clearMs,
45
+ layout: layoutMs,
46
+ render: renderMs,
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,80 @@
1
+ import { CellBuffer, Palette } from "@effect-tui/core"
2
+
3
+ /**
4
+ * Mutable state for the renderer.
5
+ * Centralized to make state management explicit and easier to track.
6
+ */
7
+ export class RendererState {
8
+ // Dimensions
9
+ width: number
10
+ height: number
11
+ lastWidth: number
12
+
13
+ // Rendering flags
14
+ dirty = true
15
+ running = true
16
+
17
+ // Buffers (double-buffered for diffing)
18
+ prevBuffer: CellBuffer | null = null
19
+ nextBuffer: CellBuffer | null = null
20
+ readonly palette = new Palette()
21
+
22
+ // Loop handle
23
+ loop: ReturnType<typeof setInterval> | null = null
24
+
25
+ // Event handler references for cleanup
26
+ inputHandler: ((data: Buffer) => void) | null = null
27
+ resizeHandler: (() => void) | null = null
28
+
29
+ constructor(width: number, height: number) {
30
+ this.width = width
31
+ this.height = height
32
+ this.lastWidth = width
33
+ }
34
+
35
+ /**
36
+ * Ensure buffers exist and are correctly sized.
37
+ * Call this at the start of each frame.
38
+ */
39
+ ensureBuffers(width: number, height: number): void {
40
+ if (!this.prevBuffer || !this.nextBuffer || this.prevBuffer.w !== width || this.prevBuffer.h !== height) {
41
+ this.prevBuffer = new CellBuffer(width, height)
42
+ this.nextBuffer = new CellBuffer(width, height)
43
+ this.prevBuffer.clear(0)
44
+ this.nextBuffer.clear(0)
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Swap prev and next buffers after rendering.
50
+ */
51
+ swapBuffers(): void {
52
+ const tmp = this.prevBuffer
53
+ this.prevBuffer = this.nextBuffer
54
+ this.nextBuffer = tmp
55
+ }
56
+
57
+ /**
58
+ * Invalidate buffers (e.g., on resize).
59
+ */
60
+ invalidateBuffers(): void {
61
+ this.prevBuffer = null
62
+ this.nextBuffer = null
63
+ }
64
+
65
+ /**
66
+ * Mark as needing render.
67
+ */
68
+ markDirty(): void {
69
+ this.dirty = true
70
+ }
71
+
72
+ /**
73
+ * Update dimensions.
74
+ */
75
+ updateDimensions(width: number, height: number): void {
76
+ this.width = width
77
+ this.height = height
78
+ this.lastWidth = width
79
+ }
80
+ }
@@ -0,0 +1,2 @@
1
+ export { FrameBuilder, type FrameTimings } from "./FrameBuilder.js"
2
+ export { RendererState } from "./RendererState.js"
@@ -0,0 +1,94 @@
1
+ import { decodeInput, ANSI, type KeyMsg, type MouseMsg } from "@effect-tui/core"
2
+
3
+ export interface InputProcessorConfig {
4
+ exitOnCtrlC: boolean
5
+ dispatchKey: (key: KeyMsg) => boolean // Returns true if event was handled (preventDefault called)
6
+ dispatchMouse: (mouse: MouseMsg) => void
7
+ dispatchPaste: (text: string) => void
8
+ flushSync: <T>(fn: () => T) => T
9
+ onInputProcessed: () => void
10
+ }
11
+
12
+ /**
13
+ * Processes raw terminal input, handling keyboard, mouse, and bracketed paste.
14
+ */
15
+ export class InputProcessor {
16
+ private pasteActive = false
17
+ private pasteBuffer = ""
18
+
19
+ constructor(private config: InputProcessorConfig) {}
20
+
21
+ /**
22
+ * Process incoming data from stdin.
23
+ * Handles bracketed paste detection, key/mouse event decoding, and dispatch.
24
+ */
25
+ process(data: Buffer): void {
26
+ let chunk = data.toString("utf8")
27
+
28
+ while (chunk.length > 0) {
29
+ if (this.pasteActive) {
30
+ const endIdx = chunk.indexOf(ANSI.paste.endMarker)
31
+ if (endIdx >= 0) {
32
+ this.pasteBuffer += chunk.slice(0, endIdx)
33
+ this.config.dispatchPaste(this.pasteBuffer)
34
+ this.pasteBuffer = ""
35
+ this.pasteActive = false
36
+ chunk = chunk.slice(endIdx + ANSI.paste.endMarker.length)
37
+ continue
38
+ } else {
39
+ this.pasteBuffer += chunk
40
+ chunk = ""
41
+ break
42
+ }
43
+ }
44
+
45
+ const startIdx = chunk.indexOf(ANSI.paste.startMarker)
46
+ if (startIdx >= 0) {
47
+ // Emit any input before the paste start
48
+ this.emitInput(chunk.slice(0, startIdx))
49
+ this.pasteActive = true
50
+ this.pasteBuffer = ""
51
+ chunk = chunk.slice(startIdx + ANSI.paste.startMarker.length)
52
+ continue
53
+ }
54
+
55
+ // No paste markers; treat as normal input
56
+ this.emitInput(chunk)
57
+ chunk = ""
58
+ }
59
+
60
+ // Notify that input processing is complete
61
+ this.config.onInputProcessed()
62
+ }
63
+
64
+ private emitInput(str: string): void {
65
+ if (!str) return
66
+ const events = decodeInput(Buffer.from(str, "utf8"))
67
+
68
+ for (const event of events) {
69
+ if (event.type === "mouse") {
70
+ this.config.flushSync(() => {
71
+ this.config.dispatchMouse(event)
72
+ })
73
+ } else {
74
+ const wrapped: KeyMsg = {
75
+ ...event,
76
+ defaultPrevented: false,
77
+ preventDefault() {
78
+ wrapped.defaultPrevented = true
79
+ },
80
+ }
81
+
82
+ this.config.flushSync(() => {
83
+ this.config.dispatchKey(wrapped)
84
+ })
85
+
86
+ // Default Ctrl+C handling - exit unless user called preventDefault()
87
+ // Only match Ctrl+C (not Ctrl+Shift+C which should be available for copy)
88
+ if (this.config.exitOnCtrlC && !wrapped.defaultPrevented && event.ctrl && !event.shift && event.text === "c") {
89
+ process.exit(0)
90
+ }
91
+ }
92
+ }
93
+ }
94
+ }
@@ -0,0 +1 @@
1
+ export { InputProcessor, type InputProcessorConfig } from "./InputProcessor.js"
@@ -0,0 +1,90 @@
1
+ import type { KeyMsg, MouseMsg } from "@effect-tui/core"
2
+ import type { FrameStats } from "../../renderer-types.js"
3
+
4
+ /**
5
+ * Centralized event subscription management for the renderer.
6
+ * Provides type-safe subscription methods with automatic cleanup.
7
+ */
8
+ export class EventBus {
9
+ private keyHandlers = new Set<(key: KeyMsg) => void>()
10
+ private mouseHandlers = new Set<(mouse: MouseMsg) => void>()
11
+ private pasteHandlers = new Set<(text: string) => void>()
12
+ private resizeHandlers = new Set<(width: number, height: number) => void>()
13
+ private frameHandlers = new Set<(stats: FrameStats) => void>()
14
+
15
+ onKey(handler: (key: KeyMsg) => void): () => void {
16
+ this.keyHandlers.add(handler)
17
+ return () => this.keyHandlers.delete(handler)
18
+ }
19
+
20
+ onMouse(handler: (mouse: MouseMsg) => void): () => void {
21
+ this.mouseHandlers.add(handler)
22
+ return () => this.mouseHandlers.delete(handler)
23
+ }
24
+
25
+ onPaste(handler: (text: string) => void): () => void {
26
+ this.pasteHandlers.add(handler)
27
+ return () => this.pasteHandlers.delete(handler)
28
+ }
29
+
30
+ onResize(handler: (width: number, height: number) => void): () => void {
31
+ this.resizeHandlers.add(handler)
32
+ return () => this.resizeHandlers.delete(handler)
33
+ }
34
+
35
+ onFrameStats(handler: (stats: FrameStats) => void): () => void {
36
+ this.frameHandlers.add(handler)
37
+ return () => this.frameHandlers.delete(handler)
38
+ }
39
+
40
+ /**
41
+ * Dispatch a key event to all handlers.
42
+ * Stops early if preventDefault is called.
43
+ */
44
+ dispatchKey(key: KeyMsg): void {
45
+ for (const handler of this.keyHandlers) {
46
+ if (key.defaultPrevented) break
47
+ handler(key)
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Dispatch a mouse event to all handlers.
53
+ */
54
+ dispatchMouse(mouse: MouseMsg): void {
55
+ for (const handler of this.mouseHandlers) {
56
+ handler(mouse)
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Dispatch a paste event to all handlers.
62
+ */
63
+ dispatchPaste(text: string): void {
64
+ for (const handler of this.pasteHandlers) {
65
+ handler(text)
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Dispatch a resize event to all handlers.
71
+ */
72
+ dispatchResize(width: number, height: number): void {
73
+ for (const handler of this.resizeHandlers) {
74
+ handler(width, height)
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Dispatch frame stats to all handlers.
80
+ */
81
+ dispatchFrame(stats: FrameStats): void {
82
+ for (const handler of this.frameHandlers) {
83
+ handler(stats)
84
+ }
85
+ }
86
+
87
+ get hasFrameHandlers(): boolean {
88
+ return this.frameHandlers.size > 0
89
+ }
90
+ }
@@ -0,0 +1,65 @@
1
+ import type { TuiWriteStream } from "../../renderer-types.js"
2
+
3
+ export interface ResizeState {
4
+ width: number
5
+ height: number
6
+ lastWidth: number
7
+ previousHeight: number // For inline mode
8
+ inlineClearHeight: number
9
+ }
10
+
11
+ export interface ResizeResult {
12
+ newWidth: number
13
+ newHeight: number
14
+ needsFullClear: boolean // Fullscreen mode
15
+ inlineClearHeight: number // Inline mode
16
+ }
17
+
18
+ /**
19
+ * Handles terminal resize events and calculates necessary clear/redraw actions.
20
+ */
21
+ export class ResizeManager {
22
+ constructor(
23
+ private stdout: TuiWriteStream,
24
+ private mode: "fullscreen" | "inline",
25
+ ) {}
26
+
27
+ /**
28
+ * Process a resize event and determine what actions are needed.
29
+ */
30
+ handleResize(currentState: ResizeState): ResizeResult {
31
+ const newWidth = this.stdout.columns || 80
32
+ const newHeight = this.stdout.rows || 24
33
+
34
+ let needsFullClear = false
35
+ let inlineClearHeight = currentState.inlineClearHeight
36
+
37
+ if (this.mode === "fullscreen") {
38
+ // Fullscreen: defer clear to renderFrame so it's written atomically with content
39
+ needsFullClear = true
40
+ } else if (newWidth !== currentState.lastWidth || newHeight !== currentState.height) {
41
+ // Inline: on dimension change, request clear on next render
42
+ const clearHeight = Math.max(currentState.previousHeight, currentState.height, newHeight)
43
+ if (clearHeight > inlineClearHeight) {
44
+ inlineClearHeight = clearHeight
45
+ }
46
+ }
47
+
48
+ return {
49
+ newWidth,
50
+ newHeight,
51
+ needsFullClear,
52
+ inlineClearHeight,
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Get current terminal dimensions.
58
+ */
59
+ getDimensions(): { width: number; height: number } {
60
+ return {
61
+ width: this.stdout.columns || 80,
62
+ height: this.stdout.rows || 24,
63
+ }
64
+ }
65
+ }