@effect-tui/react 0.15.2 → 2.0.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 (313) hide show
  1. package/README.md +11 -2
  2. package/dist/src/codeblock.d.ts +1 -1
  3. package/dist/src/codeblock.d.ts.map +1 -1
  4. package/dist/src/codeblock.js +2 -2
  5. package/dist/src/codeblock.js.map +1 -1
  6. package/dist/src/components/ListView.d.ts +4 -4
  7. package/dist/src/components/ListView.d.ts.map +1 -1
  8. package/dist/src/components/ListView.js +16 -17
  9. package/dist/src/components/ListView.js.map +1 -1
  10. package/dist/src/components/Markdown.js +3 -3
  11. package/dist/src/components/Markdown.js.map +1 -1
  12. package/dist/src/components/MultilineTextInput.d.ts.map +1 -1
  13. package/dist/src/components/MultilineTextInput.js +133 -305
  14. package/dist/src/components/MultilineTextInput.js.map +1 -1
  15. package/dist/src/components/TextInput.d.ts.map +1 -1
  16. package/dist/src/components/TextInput.js +51 -98
  17. package/dist/src/components/TextInput.js.map +1 -1
  18. package/dist/src/components/text-editing.d.ts +61 -0
  19. package/dist/src/components/text-editing.d.ts.map +1 -1
  20. package/dist/src/components/text-editing.js +131 -0
  21. package/dist/src/components/text-editing.js.map +1 -1
  22. package/dist/src/console/ConsolePopover.d.ts +7 -1
  23. package/dist/src/console/ConsolePopover.d.ts.map +1 -1
  24. package/dist/src/console/ConsolePopover.js +55 -74
  25. package/dist/src/console/ConsolePopover.js.map +1 -1
  26. package/dist/src/debug/DebugOverlay.d.ts.map +1 -1
  27. package/dist/src/debug/DebugOverlay.js +3 -57
  28. package/dist/src/debug/DebugOverlay.js.map +1 -1
  29. package/dist/src/debug/DiagnosticsPanel.js +1 -1
  30. package/dist/src/debug/DiagnosticsPanel.js.map +1 -1
  31. package/dist/src/dev.d.ts +5 -117
  32. package/dist/src/dev.d.ts.map +1 -1
  33. package/dist/src/dev.js +3 -333
  34. package/dist/src/dev.js.map +1 -1
  35. package/dist/src/hooks/use-scroll.d.ts +31 -35
  36. package/dist/src/hooks/use-scroll.d.ts.map +1 -1
  37. package/dist/src/hooks/use-scroll.js +51 -90
  38. package/dist/src/hooks/use-scroll.js.map +1 -1
  39. package/dist/src/hosts/base.d.ts +13 -2
  40. package/dist/src/hosts/base.d.ts.map +1 -1
  41. package/dist/src/hosts/base.js +74 -2
  42. package/dist/src/hosts/base.js.map +1 -1
  43. package/dist/src/hosts/box.d.ts +2 -2
  44. package/dist/src/hosts/box.d.ts.map +1 -1
  45. package/dist/src/hosts/box.js +29 -2
  46. package/dist/src/hosts/box.js.map +1 -1
  47. package/dist/src/hosts/canvas.d.ts +24 -4
  48. package/dist/src/hosts/canvas.d.ts.map +1 -1
  49. package/dist/src/hosts/canvas.js +107 -41
  50. package/dist/src/hosts/canvas.js.map +1 -1
  51. package/dist/src/hosts/codeblock.d.ts +10 -12
  52. package/dist/src/hosts/codeblock.d.ts.map +1 -1
  53. package/dist/src/hosts/codeblock.js +38 -35
  54. package/dist/src/hosts/codeblock.js.map +1 -1
  55. package/dist/src/hosts/flex-container.d.ts +3 -3
  56. package/dist/src/hosts/flex-container.d.ts.map +1 -1
  57. package/dist/src/hosts/flex-container.js +20 -5
  58. package/dist/src/hosts/flex-container.js.map +1 -1
  59. package/dist/src/hosts/index.d.ts +3 -2
  60. package/dist/src/hosts/index.d.ts.map +1 -1
  61. package/dist/src/hosts/index.js +2 -1
  62. package/dist/src/hosts/index.js.map +1 -1
  63. package/dist/src/hosts/layout-helpers.d.ts +10 -0
  64. package/dist/src/hosts/layout-helpers.d.ts.map +1 -0
  65. package/dist/src/hosts/layout-helpers.js +10 -0
  66. package/dist/src/hosts/layout-helpers.js.map +1 -0
  67. package/dist/src/hosts/leaf.d.ts +14 -0
  68. package/dist/src/hosts/leaf.d.ts.map +1 -0
  69. package/dist/src/hosts/leaf.js +31 -0
  70. package/dist/src/hosts/leaf.js.map +1 -0
  71. package/dist/src/hosts/overlay-item.d.ts +2 -2
  72. package/dist/src/hosts/overlay-item.d.ts.map +1 -1
  73. package/dist/src/hosts/overlay-item.js +7 -2
  74. package/dist/src/hosts/overlay-item.js.map +1 -1
  75. package/dist/src/hosts/overlay.d.ts +2 -2
  76. package/dist/src/hosts/overlay.d.ts.map +1 -1
  77. package/dist/src/hosts/overlay.js +6 -9
  78. package/dist/src/hosts/overlay.js.map +1 -1
  79. package/dist/src/hosts/scroll.d.ts +54 -26
  80. package/dist/src/hosts/scroll.d.ts.map +1 -1
  81. package/dist/src/hosts/scroll.js +185 -87
  82. package/dist/src/hosts/scroll.js.map +1 -1
  83. package/dist/src/hosts/single-child.d.ts.map +1 -1
  84. package/dist/src/hosts/single-child.js +2 -0
  85. package/dist/src/hosts/single-child.js.map +1 -1
  86. package/dist/src/hosts/spacer.d.ts +3 -3
  87. package/dist/src/hosts/spacer.d.ts.map +1 -1
  88. package/dist/src/hosts/spacer.js +8 -3
  89. package/dist/src/hosts/spacer.js.map +1 -1
  90. package/dist/src/hosts/text.d.ts +22 -18
  91. package/dist/src/hosts/text.d.ts.map +1 -1
  92. package/dist/src/hosts/text.js +108 -131
  93. package/dist/src/hosts/text.js.map +1 -1
  94. package/dist/src/hosts/vstack.js +1 -1
  95. package/dist/src/hosts/vstack.js.map +1 -1
  96. package/dist/src/hosts/zstack.d.ts +3 -3
  97. package/dist/src/hosts/zstack.d.ts.map +1 -1
  98. package/dist/src/hosts/zstack.js +13 -8
  99. package/dist/src/hosts/zstack.js.map +1 -1
  100. package/dist/src/index.d.ts +2 -2
  101. package/dist/src/index.d.ts.map +1 -1
  102. package/dist/src/internal/dev/hmr.d.ts +20 -0
  103. package/dist/src/internal/dev/hmr.d.ts.map +1 -0
  104. package/dist/src/internal/dev/hmr.js +93 -0
  105. package/dist/src/internal/dev/hmr.js.map +1 -0
  106. package/dist/src/internal/dev/runtime.d.ts +24 -0
  107. package/dist/src/internal/dev/runtime.d.ts.map +1 -0
  108. package/dist/src/internal/dev/runtime.js +135 -0
  109. package/dist/src/internal/dev/runtime.js.map +1 -0
  110. package/dist/src/internal/dev/ui.d.ts +13 -0
  111. package/dist/src/internal/dev/ui.d.ts.map +1 -0
  112. package/dist/src/internal/dev/ui.js +51 -0
  113. package/dist/src/internal/dev/ui.js.map +1 -0
  114. package/dist/src/internal/renderer/context.d.ts +9 -0
  115. package/dist/src/internal/renderer/context.d.ts.map +1 -0
  116. package/dist/src/internal/renderer/context.js +22 -0
  117. package/dist/src/internal/renderer/context.js.map +1 -0
  118. package/dist/src/internal/renderer/core/FrameBuilder.d.ts +18 -0
  119. package/dist/src/internal/renderer/core/FrameBuilder.d.ts.map +1 -0
  120. package/dist/src/internal/renderer/core/FrameBuilder.js +40 -0
  121. package/dist/src/internal/renderer/core/FrameBuilder.js.map +1 -0
  122. package/dist/src/internal/renderer/core/RendererState.d.ts +41 -0
  123. package/dist/src/internal/renderer/core/RendererState.d.ts.map +1 -0
  124. package/dist/src/internal/renderer/core/RendererState.js +70 -0
  125. package/dist/src/internal/renderer/core/RendererState.js.map +1 -0
  126. package/dist/src/internal/renderer/core/index.d.ts +3 -0
  127. package/dist/src/internal/renderer/core/index.d.ts.map +1 -0
  128. package/dist/src/internal/renderer/core/index.js +3 -0
  129. package/dist/src/internal/renderer/core/index.js.map +1 -0
  130. package/dist/src/internal/renderer/index.d.ts +40 -0
  131. package/dist/src/internal/renderer/index.d.ts.map +1 -0
  132. package/dist/src/internal/renderer/index.js +543 -0
  133. package/dist/src/internal/renderer/index.js.map +1 -0
  134. package/dist/src/internal/renderer/input/InputProcessor.d.ts +30 -0
  135. package/dist/src/internal/renderer/input/InputProcessor.d.ts.map +1 -0
  136. package/dist/src/internal/renderer/input/InputProcessor.js +122 -0
  137. package/dist/src/internal/renderer/input/InputProcessor.js.map +1 -0
  138. package/dist/src/internal/renderer/input/index.d.ts +2 -0
  139. package/dist/src/internal/renderer/input/index.d.ts.map +1 -0
  140. package/dist/src/internal/renderer/input/index.js +2 -0
  141. package/dist/src/internal/renderer/input/index.js.map +1 -0
  142. package/dist/src/internal/renderer/lifecycle/EventBus.d.ts +42 -0
  143. package/dist/src/internal/renderer/lifecycle/EventBus.d.ts.map +1 -0
  144. package/dist/src/internal/renderer/lifecycle/EventBus.js +97 -0
  145. package/dist/src/internal/renderer/lifecycle/EventBus.js.map +1 -0
  146. package/dist/src/internal/renderer/lifecycle/ProcessLifecycle.d.ts +13 -0
  147. package/dist/src/internal/renderer/lifecycle/ProcessLifecycle.d.ts.map +1 -0
  148. package/dist/src/internal/renderer/lifecycle/ProcessLifecycle.js +111 -0
  149. package/dist/src/internal/renderer/lifecycle/ProcessLifecycle.js.map +1 -0
  150. package/dist/src/internal/renderer/lifecycle/RenderCache.d.ts +3 -0
  151. package/dist/src/internal/renderer/lifecycle/RenderCache.d.ts.map +1 -0
  152. package/dist/src/internal/renderer/lifecycle/RenderCache.js +9 -0
  153. package/dist/src/internal/renderer/lifecycle/RenderCache.js.map +1 -0
  154. package/dist/src/internal/renderer/lifecycle/index.d.ts +4 -0
  155. package/dist/src/internal/renderer/lifecycle/index.d.ts.map +1 -0
  156. package/dist/src/internal/renderer/lifecycle/index.js +4 -0
  157. package/dist/src/internal/renderer/lifecycle/index.js.map +1 -0
  158. package/dist/src/internal/renderer/modes/FullscreenRenderer.d.ts +12 -0
  159. package/dist/src/internal/renderer/modes/FullscreenRenderer.d.ts.map +1 -0
  160. package/dist/src/internal/renderer/modes/FullscreenRenderer.js +54 -0
  161. package/dist/src/internal/renderer/modes/FullscreenRenderer.js.map +1 -0
  162. package/dist/src/internal/renderer/modes/InlineRenderer.d.ts +25 -0
  163. package/dist/src/internal/renderer/modes/InlineRenderer.d.ts.map +1 -0
  164. package/dist/src/internal/renderer/modes/InlineRenderer.js +166 -0
  165. package/dist/src/internal/renderer/modes/InlineRenderer.js.map +1 -0
  166. package/dist/src/internal/renderer/modes/RendererMode.d.ts +42 -0
  167. package/dist/src/internal/renderer/modes/RendererMode.d.ts.map +1 -0
  168. package/dist/src/internal/renderer/modes/RendererMode.js +2 -0
  169. package/dist/src/internal/renderer/modes/RendererMode.js.map +1 -0
  170. package/dist/src/internal/renderer/modes/StaticContentRenderer.d.ts +25 -0
  171. package/dist/src/internal/renderer/modes/StaticContentRenderer.d.ts.map +1 -0
  172. package/dist/src/internal/renderer/modes/StaticContentRenderer.js +49 -0
  173. package/dist/src/internal/renderer/modes/StaticContentRenderer.js.map +1 -0
  174. package/dist/src/internal/renderer/modes/index.d.ts +5 -0
  175. package/dist/src/internal/renderer/modes/index.d.ts.map +1 -0
  176. package/dist/src/internal/renderer/modes/index.js +4 -0
  177. package/dist/src/internal/renderer/modes/index.js.map +1 -0
  178. package/dist/src/internal/renderer/terminal/KeyboardCapabilityProbe.d.ts +13 -0
  179. package/dist/src/internal/renderer/terminal/KeyboardCapabilityProbe.d.ts.map +1 -0
  180. package/dist/src/internal/renderer/terminal/KeyboardCapabilityProbe.js +75 -0
  181. package/dist/src/internal/renderer/terminal/KeyboardCapabilityProbe.js.map +1 -0
  182. package/dist/src/internal/renderer/terminal/TerminalSetup.d.ts +29 -0
  183. package/dist/src/internal/renderer/terminal/TerminalSetup.d.ts.map +1 -0
  184. package/dist/src/internal/renderer/terminal/TerminalSetup.js +82 -0
  185. package/dist/src/internal/renderer/terminal/TerminalSetup.js.map +1 -0
  186. package/dist/src/internal/renderer/terminal/index.d.ts +3 -0
  187. package/dist/src/internal/renderer/terminal/index.d.ts.map +1 -0
  188. package/dist/src/internal/renderer/terminal/index.js +3 -0
  189. package/dist/src/internal/renderer/terminal/index.js.map +1 -0
  190. package/dist/src/internal/renderer/types.d.ts +122 -0
  191. package/dist/src/internal/renderer/types.d.ts.map +1 -0
  192. package/dist/src/internal/renderer/types.js +2 -0
  193. package/dist/src/internal/renderer/types.js.map +1 -0
  194. package/dist/src/motion/hooks.d.ts +1 -1
  195. package/dist/src/motion/hooks.js +1 -1
  196. package/dist/src/reconciler/host-config.js +2 -2
  197. package/dist/src/reconciler/host-config.js.map +1 -1
  198. package/dist/src/reconciler/types.d.ts +5 -1
  199. package/dist/src/reconciler/types.d.ts.map +1 -1
  200. package/dist/src/renderer-context.d.ts +1 -8
  201. package/dist/src/renderer-context.d.ts.map +1 -1
  202. package/dist/src/renderer-context.js +1 -21
  203. package/dist/src/renderer-context.js.map +1 -1
  204. package/dist/src/renderer-types.d.ts +1 -115
  205. package/dist/src/renderer-types.d.ts.map +1 -1
  206. package/dist/src/renderer.d.ts +1 -31
  207. package/dist/src/renderer.d.ts.map +1 -1
  208. package/dist/src/renderer.js +1 -495
  209. package/dist/src/renderer.js.map +1 -1
  210. package/dist/src/test/render-tui.d.ts +3 -3
  211. package/dist/src/test/render-tui.d.ts.map +1 -1
  212. package/dist/src/test/render-tui.js +16 -9
  213. package/dist/src/test/render-tui.js.map +1 -1
  214. package/dist/src/utils/alignment.d.ts +1 -1
  215. package/dist/src/utils/alignment.d.ts.map +1 -1
  216. package/dist/src/utils/alignment.js +0 -2
  217. package/dist/src/utils/alignment.js.map +1 -1
  218. package/dist/src/utils/border.d.ts +1 -1
  219. package/dist/src/utils/border.d.ts.map +1 -1
  220. package/dist/src/utils/border.js +2 -0
  221. package/dist/src/utils/border.js.map +1 -1
  222. package/dist/src/utils/console-helpers.d.ts +19 -0
  223. package/dist/src/utils/console-helpers.d.ts.map +1 -0
  224. package/dist/src/utils/console-helpers.js +61 -0
  225. package/dist/src/utils/console-helpers.js.map +1 -0
  226. package/dist/src/utils/index.d.ts +2 -1
  227. package/dist/src/utils/index.d.ts.map +1 -1
  228. package/dist/src/utils/index.js +2 -1
  229. package/dist/src/utils/index.js.map +1 -1
  230. package/dist/src/utils/styles.d.ts +8 -1
  231. package/dist/src/utils/styles.d.ts.map +1 -1
  232. package/dist/src/utils/styles.js +10 -8
  233. package/dist/src/utils/styles.js.map +1 -1
  234. package/dist/src/utils/text-layout.d.ts +22 -0
  235. package/dist/src/utils/text-layout.d.ts.map +1 -0
  236. package/dist/src/utils/text-layout.js +37 -0
  237. package/dist/src/utils/text-layout.js.map +1 -0
  238. package/dist/src/utils/text-wrap.d.ts +31 -1
  239. package/dist/src/utils/text-wrap.d.ts.map +1 -1
  240. package/dist/src/utils/text-wrap.js +205 -48
  241. package/dist/src/utils/text-wrap.js.map +1 -1
  242. package/dist/src/visualize/index.js +1 -1
  243. package/dist/src/visualize/index.js.map +1 -1
  244. package/dist/tsconfig.tsbuildinfo +1 -1
  245. package/package.json +2 -2
  246. package/src/codeblock.tsx +2 -2
  247. package/src/components/ListView.tsx +21 -23
  248. package/src/components/Markdown.tsx +3 -3
  249. package/src/components/MultilineTextInput.tsx +138 -344
  250. package/src/components/TextInput.tsx +54 -99
  251. package/src/components/text-editing.ts +180 -0
  252. package/src/console/ConsolePopover.tsx +124 -107
  253. package/src/debug/DebugOverlay.ts +15 -74
  254. package/src/debug/DiagnosticsPanel.tsx +1 -1
  255. package/src/dev.tsx +5 -458
  256. package/src/hooks/use-scroll.ts +85 -145
  257. package/src/hosts/base.ts +86 -3
  258. package/src/hosts/box.ts +37 -2
  259. package/src/hosts/canvas.ts +128 -42
  260. package/src/hosts/codeblock.ts +48 -35
  261. package/src/hosts/flex-container.ts +25 -6
  262. package/src/hosts/index.ts +11 -2
  263. package/src/hosts/layout-helpers.ts +20 -0
  264. package/src/hosts/leaf.ts +36 -0
  265. package/src/hosts/overlay-item.ts +8 -2
  266. package/src/hosts/overlay.ts +13 -11
  267. package/src/hosts/scroll.ts +228 -106
  268. package/src/hosts/single-child.ts +2 -0
  269. package/src/hosts/spacer.ts +8 -3
  270. package/src/hosts/text.ts +126 -132
  271. package/src/hosts/vstack.ts +1 -1
  272. package/src/hosts/zstack.ts +14 -9
  273. package/src/index.ts +2 -2
  274. package/src/internal/dev/hmr.ts +101 -0
  275. package/src/internal/dev/runtime.ts +170 -0
  276. package/src/internal/dev/ui.tsx +87 -0
  277. package/src/internal/renderer/context.ts +27 -0
  278. package/src/{renderer → internal/renderer}/core/FrameBuilder.ts +2 -2
  279. package/src/internal/renderer/index.ts +689 -0
  280. package/src/{renderer → internal/renderer}/input/InputProcessor.ts +10 -1
  281. package/src/{renderer → internal/renderer}/lifecycle/EventBus.ts +9 -1
  282. package/src/internal/renderer/lifecycle/ProcessLifecycle.ts +125 -0
  283. package/src/internal/renderer/lifecycle/index.ts +3 -0
  284. package/src/{renderer → internal/renderer}/modes/InlineRenderer.ts +5 -2
  285. package/src/{renderer → internal/renderer}/modes/RendererMode.ts +1 -1
  286. package/src/{renderer → internal/renderer}/modes/StaticContentRenderer.ts +5 -2
  287. package/src/internal/renderer/terminal/KeyboardCapabilityProbe.ts +91 -0
  288. package/src/{renderer/lifecycle → internal/renderer/terminal}/TerminalSetup.ts +4 -22
  289. package/src/internal/renderer/terminal/index.ts +2 -0
  290. package/src/internal/renderer/types.ts +129 -0
  291. package/src/motion/hooks.ts +1 -1
  292. package/src/reconciler/host-config.ts +2 -2
  293. package/src/reconciler/types.ts +7 -1
  294. package/src/renderer-context.ts +1 -27
  295. package/src/renderer-types.ts +10 -123
  296. package/src/renderer.ts +1 -619
  297. package/src/test/render-tui.ts +16 -10
  298. package/src/utils/alignment.ts +1 -3
  299. package/src/utils/border.ts +11 -1
  300. package/src/utils/console-helpers.ts +86 -0
  301. package/src/utils/index.ts +15 -1
  302. package/src/utils/styles.ts +16 -4
  303. package/src/utils/text-layout.ts +65 -0
  304. package/src/utils/text-wrap.ts +261 -48
  305. package/src/visualize/index.tsx +1 -1
  306. package/src/renderer/lifecycle/ResizeManager.ts +0 -65
  307. package/src/renderer/lifecycle/index.ts +0 -4
  308. /package/src/{renderer → internal/renderer}/core/RendererState.ts +0 -0
  309. /package/src/{renderer → internal/renderer}/core/index.ts +0 -0
  310. /package/src/{renderer → internal/renderer}/input/index.ts +0 -0
  311. /package/src/{renderer → internal/renderer}/lifecycle/RenderCache.ts +0 -0
  312. /package/src/{renderer → internal/renderer}/modes/FullscreenRenderer.ts +0 -0
  313. /package/src/{renderer → internal/renderer}/modes/index.ts +0 -0
@@ -1,5 +1,5 @@
1
1
  import type { KeyMsg, MouseMsg } from "@effect-tui/core"
2
- import type { FrameStats, PasteMsg } from "../../renderer-types.js"
2
+ import type { FrameStats, PasteMsg } from "../types.js"
3
3
 
4
4
  /**
5
5
  * Centralized event subscription management for the renderer.
@@ -97,4 +97,12 @@ export class EventBus {
97
97
  get hasFrameHandlers(): boolean {
98
98
  return this.frameHandlers.size > 0
99
99
  }
100
+
101
+ clear(): void {
102
+ this.keyHandlers.clear()
103
+ this.mouseHandlers.clear()
104
+ this.pasteHandlers.clear()
105
+ this.resizeHandlers.clear()
106
+ this.frameHandlers.clear()
107
+ }
100
108
  }
@@ -0,0 +1,125 @@
1
+ type ExitHandler = () => void
2
+ type SignalHandler = (signal: NodeJS.Signals) => void
3
+ type UncaughtHandler = (err: Error) => void
4
+ type RejectionHandler = (reason: unknown) => void
5
+
6
+ export interface ProcessHandlers {
7
+ onExit?: ExitHandler
8
+ onSignal?: SignalHandler
9
+ onUncaughtException?: UncaughtHandler
10
+ onUnhandledRejection?: RejectionHandler
11
+ }
12
+
13
+ const exitHandlers = new Set<ExitHandler>()
14
+ const signalHandlers = new Set<SignalHandler>()
15
+ const uncaughtHandlers = new Set<UncaughtHandler>()
16
+ const rejectionHandlers = new Set<RejectionHandler>()
17
+
18
+ let exitListenerAttached = false
19
+ let signalListenersAttached = false
20
+ let uncaughtListenerAttached = false
21
+ let rejectionListenerAttached = false
22
+
23
+ const dispatchExit = () => {
24
+ for (const handler of exitHandlers) handler()
25
+ }
26
+
27
+ const dispatchSignal = (signal: NodeJS.Signals) => {
28
+ for (const handler of signalHandlers) handler(signal)
29
+ }
30
+
31
+ const dispatchUncaught = (err: Error) => {
32
+ for (const handler of uncaughtHandlers) handler(err)
33
+ }
34
+
35
+ const dispatchRejection = (reason: unknown) => {
36
+ for (const handler of rejectionHandlers) handler(reason)
37
+ }
38
+
39
+ const ensureExitListener = () => {
40
+ if (exitListenerAttached) return
41
+ process.on("exit", dispatchExit)
42
+ exitListenerAttached = true
43
+ }
44
+
45
+ const ensureSignalListeners = () => {
46
+ if (signalListenersAttached) return
47
+ process.on("SIGINT", dispatchSignal)
48
+ process.on("SIGTERM", dispatchSignal)
49
+ signalListenersAttached = true
50
+ }
51
+
52
+ const ensureUncaughtListener = () => {
53
+ if (uncaughtListenerAttached) return
54
+ process.on("uncaughtException", dispatchUncaught)
55
+ uncaughtListenerAttached = true
56
+ }
57
+
58
+ const ensureRejectionListener = () => {
59
+ if (rejectionListenerAttached) return
60
+ process.on("unhandledRejection", dispatchRejection)
61
+ rejectionListenerAttached = true
62
+ }
63
+
64
+ const maybeDetachExitListener = () => {
65
+ if (!exitListenerAttached || exitHandlers.size > 0) return
66
+ process.off("exit", dispatchExit)
67
+ exitListenerAttached = false
68
+ }
69
+
70
+ const maybeDetachSignalListeners = () => {
71
+ if (!signalListenersAttached || signalHandlers.size > 0) return
72
+ process.off("SIGINT", dispatchSignal)
73
+ process.off("SIGTERM", dispatchSignal)
74
+ signalListenersAttached = false
75
+ }
76
+
77
+ const maybeDetachUncaughtListener = () => {
78
+ if (!uncaughtListenerAttached || uncaughtHandlers.size > 0) return
79
+ process.off("uncaughtException", dispatchUncaught)
80
+ uncaughtListenerAttached = false
81
+ }
82
+
83
+ const maybeDetachRejectionListener = () => {
84
+ if (!rejectionListenerAttached || rejectionHandlers.size > 0) return
85
+ process.off("unhandledRejection", dispatchRejection)
86
+ rejectionListenerAttached = false
87
+ }
88
+
89
+ export const registerProcessHandlers = (handlers: ProcessHandlers): (() => void) => {
90
+ if (handlers.onExit) {
91
+ exitHandlers.add(handlers.onExit)
92
+ ensureExitListener()
93
+ }
94
+ if (handlers.onSignal) {
95
+ signalHandlers.add(handlers.onSignal)
96
+ ensureSignalListeners()
97
+ }
98
+ if (handlers.onUncaughtException) {
99
+ uncaughtHandlers.add(handlers.onUncaughtException)
100
+ ensureUncaughtListener()
101
+ }
102
+ if (handlers.onUnhandledRejection) {
103
+ rejectionHandlers.add(handlers.onUnhandledRejection)
104
+ ensureRejectionListener()
105
+ }
106
+
107
+ return () => {
108
+ if (handlers.onExit) {
109
+ exitHandlers.delete(handlers.onExit)
110
+ maybeDetachExitListener()
111
+ }
112
+ if (handlers.onSignal) {
113
+ signalHandlers.delete(handlers.onSignal)
114
+ maybeDetachSignalListeners()
115
+ }
116
+ if (handlers.onUncaughtException) {
117
+ uncaughtHandlers.delete(handlers.onUncaughtException)
118
+ maybeDetachUncaughtListener()
119
+ }
120
+ if (handlers.onUnhandledRejection) {
121
+ rejectionHandlers.delete(handlers.onUnhandledRejection)
122
+ maybeDetachRejectionListener()
123
+ }
124
+ }
125
+ }
@@ -0,0 +1,3 @@
1
+ export { EventBus } from "./EventBus.js"
2
+ export { registerProcessHandlers, type ProcessHandlers } from "./ProcessLifecycle.js"
3
+ export { getRenderCache, type RenderCache } from "./RenderCache.js"
@@ -163,12 +163,15 @@ export class InlineRenderer implements RendererMode {
163
163
  return this._needsFullRerender
164
164
  }
165
165
 
166
- /** Clear the full rerender flag after handling */
166
+ /** Clear the full rerender flag after handling (keeps previousHeight for cursor tracking) */
167
167
  clearFullRerenderFlag(): void {
168
168
  this._needsFullRerender = false
169
- this.previousHeight = 0
169
+ // DON'T reset previousHeight - we need it for cursor positioning in generateOutput.
170
+ // After clear+replay static, the cursor is at end of static content.
171
+ // generateOutput will use previousHeight to know where dynamic content should go.
170
172
  this.previousStartRow = 0
171
173
  this.printedWidths = []
174
+ this._forceFullOutput = true // Force full output to resync rendering
172
175
  }
173
176
 
174
177
  reset(): void {
@@ -1,5 +1,5 @@
1
1
  import type { CellBuffer, Palette } from "@effect-tui/core"
2
- import type { TuiWriteStream } from "../../renderer-types.js"
2
+ import type { TuiWriteStream } from "../types.js"
3
3
 
4
4
  /**
5
5
  * Context passed to render mode output generation.
@@ -1,6 +1,6 @@
1
1
  import { CellBuffer, emitRowWithReset, type Palette, rowContentWidth } from "@effect-tui/core"
2
- import type { HostInstance } from "../../reconciler/types.js"
3
- import type { TuiWriteStream } from "../../renderer-types.js"
2
+ import type { HostInstance } from "../../../reconciler/types.js"
3
+ import type { TuiWriteStream } from "../types.js"
4
4
 
5
5
  /**
6
6
  * Renders static content to scrollback (inline mode only).
@@ -31,6 +31,9 @@ export class StaticContentRenderer {
31
31
  * Caller clears dynamic area first, then appends this output.
32
32
  */
33
33
  render(staticNode: HostInstance, frameWidth: number): string {
34
+ // Pre-frame cache prep (optional)
35
+ staticNode.prepareFrame?.()
36
+
34
37
  // Measure and layout static content
35
38
  const staticSize = staticNode.measure(frameWidth, Number.MAX_SAFE_INTEGER)
36
39
  staticNode.layout({ x: 0, y: 0, w: frameWidth, h: staticSize.h })
@@ -0,0 +1,91 @@
1
+ import { ANSI } from "@effect-tui/core"
2
+ import type { TuiWriteStream } from "../types.js"
3
+
4
+ type ProbeOptions = {
5
+ stdout: TuiWriteStream
6
+ timeoutMs?: number
7
+ onResolved: (supportsKitty: boolean) => void
8
+ }
9
+
10
+ export type KeyboardCapabilityProbe = {
11
+ start(): void
12
+ handleInput(input: string): string
13
+ }
14
+
15
+ const kittyResponseRe = /^\x1b\[\?\d+(?:;\d+)?u$/
16
+
17
+ export function createKeyboardCapabilityProbe(options: ProbeOptions): KeyboardCapabilityProbe {
18
+ const timeoutMs = options.timeoutMs ?? 150
19
+ let active = false
20
+ let resolved = false
21
+ let buffer = ""
22
+ let timer: ReturnType<typeof setTimeout> | null = null
23
+
24
+ const resolve = (supportsKitty: boolean) => {
25
+ if (resolved) return
26
+ resolved = true
27
+ active = false
28
+ buffer = ""
29
+ if (timer) {
30
+ clearTimeout(timer)
31
+ timer = null
32
+ }
33
+ options.onResolved(supportsKitty)
34
+ }
35
+
36
+ const handleCapabilitySequence = (sequence: string) => {
37
+ if (kittyResponseRe.test(sequence)) {
38
+ resolve(true)
39
+ } else if (sequence.includes("kitty")) {
40
+ resolve(true)
41
+ }
42
+ }
43
+
44
+ const handleInput = (input: string): string => {
45
+ if (!active) return input
46
+ let data = buffer + input
47
+ buffer = ""
48
+ let output = ""
49
+ let i = 0
50
+
51
+ while (i < data.length) {
52
+ if (data.startsWith("\x1b[?", i)) {
53
+ const end = data.indexOf("u", i + 3)
54
+ if (end === -1) {
55
+ buffer = data.slice(i)
56
+ break
57
+ }
58
+ const seq = data.slice(i, end + 1)
59
+ handleCapabilitySequence(seq)
60
+ i = end + 1
61
+ continue
62
+ }
63
+ if (data.startsWith("\x1bP>|", i)) {
64
+ const end = data.indexOf("\x1b\\", i + 4)
65
+ if (end === -1) {
66
+ buffer = data.slice(i)
67
+ break
68
+ }
69
+ const seq = data.slice(i, end + 2)
70
+ handleCapabilitySequence(seq)
71
+ i = end + 2
72
+ continue
73
+ }
74
+
75
+ output += data[i] as string
76
+ i += 1
77
+ }
78
+
79
+ return output
80
+ }
81
+
82
+ return {
83
+ start() {
84
+ if (resolved || active) return
85
+ active = true
86
+ options.stdout.write(ANSI.keyboard.query)
87
+ timer = setTimeout(() => resolve(false), timeoutMs)
88
+ },
89
+ handleInput,
90
+ }
91
+ }
@@ -1,19 +1,11 @@
1
1
  import { ANSI, Terminal } from "@effect-tui/core"
2
- import type { TuiReadStream, TuiWriteStream } from "../../renderer-types.js"
2
+ import type { TuiReadStream, TuiWriteStream } from "../types.js"
3
3
 
4
4
  export interface TerminalSetupConfig {
5
5
  mode: "fullscreen" | "inline"
6
6
  enablePaste: boolean
7
7
  enableMouse: boolean
8
8
  skipTerminalSetup: boolean
9
- /**
10
- * Enable Kitty keyboard protocol for enhanced modifier detection.
11
- * When enabled, Ctrl+Shift+C can be distinguished from Ctrl+C.
12
- * Supported by: Kitty, iTerm2 3.5+, WezTerm, Ghostty, foot, Contour, rio.
13
- * Gracefully ignored by terminals that don't support it.
14
- * @default true
15
- */
16
- enableKittyKeyboard?: boolean
17
9
  }
18
10
 
19
11
  /**
@@ -53,14 +45,6 @@ export class TerminalSetup {
53
45
  this.stdout.write(ANSI.mouse.enable)
54
46
  }
55
47
 
56
- // Enable enhanced keyboard protocols for modifier detection
57
- // This allows distinguishing Ctrl+Shift+C from Ctrl+C on supported terminals
58
- // NOTE: Many terminals intercept Ctrl+Shift+C for their own copy function!
59
- if (this.config.enableKittyKeyboard !== false) {
60
- this.stdout.write(ANSI.keyboard.enable(1)) // Kitty protocol (flag 1 = disambiguate)
61
- this.stdout.write(ANSI.modifyOtherKeys.enable) // xterm protocol (mode 2)
62
- }
63
-
64
48
  if (this.stdin.isTTY && this.stdin.setRawMode) {
65
49
  this.stdin.setRawMode(true)
66
50
  this.stdin.resume?.()
@@ -85,11 +69,9 @@ export class TerminalSetup {
85
69
  // This ensures all sequences are flushed together before process exit
86
70
  let output = ""
87
71
 
88
- // Disable enhanced keyboard protocols first
89
- if (this.config.enableKittyKeyboard !== false) {
90
- output += ANSI.keyboard.disable
91
- output += ANSI.modifyOtherKeys.disable
92
- }
72
+ // Disable enhanced keyboard protocols first (safe to send regardless of support)
73
+ output += ANSI.keyboard.disable
74
+ output += ANSI.modifyOtherKeys.disable
93
75
 
94
76
  if (this.config.enableMouse) {
95
77
  output += ANSI.mouse.disable
@@ -0,0 +1,2 @@
1
+ export { createKeyboardCapabilityProbe, type KeyboardCapabilityProbe } from "./KeyboardCapabilityProbe.js"
2
+ export { TerminalSetup, type TerminalSetupConfig } from "./TerminalSetup.js"
@@ -0,0 +1,129 @@
1
+ import type { KeyMsg, MouseMsg } from "@effect-tui/core"
2
+ import type { HostContext, HostInstance } from "../../reconciler/types.js"
3
+
4
+ export type PasteMsg = {
5
+ type: "paste"
6
+ text: string
7
+ /** Set by renderer to allow handlers to stop further propagation. */
8
+ defaultPrevented?: boolean
9
+ preventDefault?: () => void
10
+ }
11
+
12
+ /** Minimal write stream interface for renderer output */
13
+ export interface TuiWriteStream {
14
+ write(s: string): void
15
+ columns: number
16
+ rows: number
17
+ on(event: string, cb: () => void): void
18
+ removeListener(event: string, cb: () => void): void
19
+ }
20
+
21
+ /** Minimal read stream interface for renderer input */
22
+ export interface TuiReadStream {
23
+ isTTY?: boolean
24
+ setRawMode?(mode: boolean): void
25
+ resume?(): void
26
+ on(event: string, cb: (data: Buffer) => void): void
27
+ removeListener(event: string, cb: (data: Buffer) => void): void
28
+ }
29
+
30
+ export interface TuiRenderer {
31
+ /** Terminal width */
32
+ width: number
33
+ /** Terminal height */
34
+ height: number
35
+ /** Request a re-render */
36
+ requestRender(): void
37
+ /** Subscribe to per-frame stats (if enabled). */
38
+ onFrameStats?(handler: (stats: FrameStats) => void): () => void
39
+ /** Subscribe to keyboard events */
40
+ onKey(handler: (key: KeyMsg) => void): () => void
41
+ /** Subscribe to mouse events (clicks, scroll, etc.) */
42
+ onMouse(handler: (mouse: MouseMsg) => void): () => void
43
+ /** Subscribe to paste events (bracketed paste mode). */
44
+ onPaste?(handler: (paste: PasteMsg) => void): () => void
45
+ /** Subscribe to resize events */
46
+ onResize(handler: (width: number, height: number) => void): () => void
47
+ /** Stop the renderer */
48
+ stop(): void
49
+ /** Manually trigger one render frame (only in manualMode) */
50
+ renderNow(): void
51
+ /**
52
+ * Get the current screen as ANSI string (for screenshots/debugging).
53
+ * Returns the last rendered frame with all ANSI color codes intact.
54
+ */
55
+ getScreenshot(): string
56
+ /** Dispatch a key event (for remote control) */
57
+ dispatchKey?(key: KeyMsg): void
58
+ /** Dispatch a paste event (for remote control) */
59
+ dispatchPaste?(text: string): void
60
+ /** Dispatch a resize event (for remote control) */
61
+ dispatchResize?(width: number, height: number): void
62
+ }
63
+
64
+ /** Internal renderer type with container reference */
65
+ export interface TuiRendererInternal extends TuiRenderer {
66
+ _container: Container | null
67
+ }
68
+
69
+ export interface Container {
70
+ root: HostInstance | null
71
+ ctx: HostContext
72
+ /** @internal Static content root node (for Static component) */
73
+ staticRoot?: HostInstance | null
74
+ /** @internal Flag indicating static content needs flushing */
75
+ staticDirty?: boolean
76
+ }
77
+
78
+ export interface RendererOptions {
79
+ fps?: number
80
+ stdout?: NodeJS.WriteStream | TuiWriteStream
81
+ stdin?: NodeJS.ReadStream | TuiReadStream
82
+ /** Render mode: "fullscreen" uses alternate buffer, "inline" renders in-place */
83
+ mode?: "fullscreen" | "inline"
84
+ /** Exit the process on Ctrl+C unless preventDefault was called. Defaults to true. */
85
+ exitOnCtrlC?: boolean
86
+ /** Handle SIGINT/SIGTERM and process exit cleanup. Defaults to true. */
87
+ handleSignals?: boolean
88
+ /** Exit the process after handling SIGINT/SIGTERM. Defaults to true. */
89
+ exitOnSignal?: boolean
90
+ /** Exit the process on render errors after logging to terminal. Defaults to true. */
91
+ exitOnRenderError?: boolean
92
+ /** Override exit codes for signals. Defaults: SIGINT=130, SIGTERM=143. */
93
+ signalExitCodes?: Partial<Record<"SIGINT" | "SIGTERM", number>>
94
+ /** Enable diffed rendering (per-line). Defaults to true in runtime, false in manualMode (tests). */
95
+ diff?: boolean
96
+ /** Skip automatic render loop. Call renderNow() manually to render frames. */
97
+ manualMode?: boolean
98
+ /** Skip fullscreen/raw mode setup (for testing) */
99
+ skipTerminalSetup?: boolean
100
+ /** Enable bracketed paste (default true). */
101
+ enablePaste?: boolean
102
+ /** Enable mouse mode for scroll wheel events (default true in fullscreen). */
103
+ enableMouse?: boolean
104
+ /** Enable Kitty/xterm keyboard protocols for enhanced modifier detection (default true). */
105
+ enableKittyKeyboard?: boolean
106
+ /** Emoji width handling: 1 or 2 forces width. */
107
+ emojiWidth?: 1 | 2
108
+ /** Optional per-frame diagnostics hook. Called after each frame is written. */
109
+ debug?: {
110
+ onFrame?: (stats: FrameStats) => void
111
+ }
112
+ }
113
+
114
+ export interface FrameStats {
115
+ mode: "fullscreen" | "inline"
116
+ width: number
117
+ height: number
118
+ contentHeight: number
119
+ bytes: number
120
+ frameMs: number
121
+ phases: {
122
+ clear: number
123
+ layout: number
124
+ render: number
125
+ diffMs: number
126
+ write: number
127
+ }
128
+ timestamp: number
129
+ }
@@ -221,7 +221,7 @@ export function useColorMotionValue(initial: ColorInput): ColorMotionValue {
221
221
  * // In canvas draw callback
222
222
  * <canvas draw={(ctx) => {
223
223
  * const { r, g, b } = colorMv.get()
224
- * ctx.fill(0, 0, 10, 5, "█", { fg: Colors.rgb(r, g, b) })
224
+ * ctx.fillRect(0, 0, 10, 5, "█", { fg: Colors.rgb(r, g, b) })
225
225
  * }} />
226
226
  */
227
227
  export function useColorSpring(
@@ -110,8 +110,8 @@ const hostConfig = {
110
110
 
111
111
  resetAfterCommit(container: Container) {
112
112
  // If static content is dirty, flush immediately (bypassing throttle)
113
- if (container.staticDirty && container.ctx.requestImmediateRender) {
114
- container.ctx.requestImmediateRender()
113
+ if (container.staticDirty && container.ctx.requestRenderNow) {
114
+ container.ctx.requestRenderNow()
115
115
  } else {
116
116
  container.ctx.requestRender()
117
117
  }
@@ -32,6 +32,12 @@ export interface HostInstance {
32
32
  /** Optional pre-frame hook for cache prep (called before measure/layout/render). */
33
33
  prepareFrame?(): void
34
34
 
35
+ /** @internal Mark layout-related caches dirty. */
36
+ invalidateLayout?(): void
37
+
38
+ /** @internal Mark render-related caches dirty. */
39
+ invalidateRender?(): void
40
+
35
41
  /** Update props from React */
36
42
  updateProps(props: Record<string, unknown>): void
37
43
 
@@ -51,7 +57,7 @@ export interface HostInstance {
51
57
  export interface HostContext {
52
58
  requestRender(): void
53
59
  /** @internal Trigger immediate render (bypasses throttling) for static content */
54
- requestImmediateRender?(): void
60
+ requestRenderNow?(): void
55
61
  }
56
62
 
57
63
  /**
@@ -1,27 +1 @@
1
- import { createContext, useContext, useEffect, useState } from "react"
2
- import type { TuiRenderer } from "./renderer-types.js"
3
-
4
- // Context for accessing renderer in components
5
- export const RendererContext = createContext<TuiRenderer | null>(null)
6
-
7
- export function useRenderer(): TuiRenderer {
8
- const renderer = useContext(RendererContext)
9
- if (!renderer) {
10
- throw new Error("useRenderer must be used within a TUI renderer")
11
- }
12
- return renderer
13
- }
14
-
15
- /** Hook that returns terminal size and re-renders on resize */
16
- export function useTerminalSize(): { width: number; height: number } {
17
- const renderer = useRenderer()
18
- const [size, setSize] = useState({ width: renderer.width, height: renderer.height })
19
-
20
- useEffect(() => {
21
- return renderer.onResize((width, height) => {
22
- setSize({ width, height })
23
- })
24
- }, [renderer])
25
-
26
- return size
27
- }
1
+ export { RendererContext, useRenderer, useTerminalSize } from "./internal/renderer/context.js"
@@ -1,123 +1,10 @@
1
- import type { KeyMsg, MouseMsg } from "@effect-tui/core"
2
- import type { HostContext, HostInstance } from "./reconciler/types.js"
3
-
4
- export type PasteMsg = {
5
- type: "paste"
6
- text: string
7
- /** Set by renderer to allow handlers to stop further propagation. */
8
- defaultPrevented?: boolean
9
- preventDefault?: () => void
10
- }
11
-
12
- /** Minimal write stream interface for renderer output */
13
- export interface TuiWriteStream {
14
- write(s: string): void
15
- columns: number
16
- rows: number
17
- on(event: string, cb: () => void): void
18
- removeListener(event: string, cb: () => void): void
19
- }
20
-
21
- /** Minimal read stream interface for renderer input */
22
- export interface TuiReadStream {
23
- isTTY?: boolean
24
- setRawMode?(mode: boolean): void
25
- resume?(): void
26
- on(event: string, cb: (data: Buffer) => void): void
27
- removeListener(event: string, cb: (data: Buffer) => void): void
28
- }
29
-
30
- export interface TuiRenderer {
31
- /** Terminal width */
32
- width: number
33
- /** Terminal height */
34
- height: number
35
- /** Request a re-render */
36
- requestRender(): void
37
- /** Subscribe to per-frame stats (if enabled). */
38
- onFrameStats?(handler: (stats: FrameStats) => void): () => void
39
- /** Subscribe to keyboard events */
40
- onKey(handler: (key: KeyMsg) => void): () => void
41
- /** Subscribe to mouse events (clicks, scroll, etc.) */
42
- onMouse(handler: (mouse: MouseMsg) => void): () => void
43
- /** Subscribe to paste events (bracketed paste mode). */
44
- onPaste?(handler: (paste: PasteMsg) => void): () => void
45
- /** Subscribe to resize events */
46
- onResize(handler: (width: number, height: number) => void): () => void
47
- /** Stop the renderer */
48
- stop(): void
49
- /** Manually trigger one render frame (only in manualMode) */
50
- flush(): void
51
- /**
52
- * Get the current screen as ANSI string (for screenshots/debugging).
53
- * Returns the last rendered frame with all ANSI color codes intact.
54
- */
55
- getScreenshot(): string
56
- /** Dispatch a key event (for remote control) */
57
- dispatchKey?(key: KeyMsg): void
58
- /** Dispatch a paste event (for remote control) */
59
- dispatchPaste?(text: string): void
60
- /** Dispatch a resize event (for remote control) */
61
- dispatchResize?(width: number, height: number): void
62
- }
63
-
64
- /** Internal renderer type with container reference */
65
- export interface TuiRendererInternal extends TuiRenderer {
66
- _container: Container | null
67
- }
68
-
69
- export interface Container {
70
- root: HostInstance | null
71
- ctx: HostContext
72
- /** @internal Static content root node (for Static component) */
73
- staticRoot?: HostInstance | null
74
- /** @internal Flag indicating static content needs flushing */
75
- staticDirty?: boolean
76
- }
77
-
78
- export interface RendererOptions {
79
- fps?: number
80
- stdout?: NodeJS.WriteStream | TuiWriteStream
81
- stdin?: NodeJS.ReadStream | TuiReadStream
82
- /** Render mode: "fullscreen" uses alternate buffer, "inline" renders in-place */
83
- mode?: "fullscreen" | "inline"
84
- /** Exit the process on Ctrl+C unless preventDefault was called. Defaults to true. */
85
- exitOnCtrlC?: boolean
86
- /** Handle SIGINT/SIGTERM and process exit cleanup. Defaults to true. */
87
- handleSignals?: boolean
88
- /** Exit the process after handling SIGINT/SIGTERM. Defaults to true. */
89
- exitOnSignal?: boolean
90
- /** Override exit codes for signals. Defaults: SIGINT=130, SIGTERM=143. */
91
- signalExitCodes?: Partial<Record<"SIGINT" | "SIGTERM", number>>
92
- /** Enable diffed rendering (per-line). Defaults to true in runtime, false in manualMode (tests). */
93
- diff?: boolean
94
- /** Skip automatic render loop. Call flush() manually to render frames. */
95
- manualMode?: boolean
96
- /** Skip fullscreen/raw mode setup (for testing) */
97
- skipTerminalSetup?: boolean
98
- /** Enable bracketed paste (default true). */
99
- enablePaste?: boolean
100
- /** Enable mouse mode for scroll wheel events (default true in fullscreen). */
101
- enableMouse?: boolean
102
- /** Optional per-frame diagnostics hook. Called after each frame is written. */
103
- debug?: {
104
- onFrame?: (stats: FrameStats) => void
105
- }
106
- }
107
-
108
- export interface FrameStats {
109
- mode: "fullscreen" | "inline"
110
- width: number
111
- height: number
112
- contentHeight: number
113
- bytes: number
114
- frameMs: number
115
- phases: {
116
- clear: number
117
- layout: number
118
- render: number
119
- diffAnsi: number
120
- write: number
121
- }
122
- timestamp: number
123
- }
1
+ export type {
2
+ Container,
3
+ FrameStats,
4
+ PasteMsg,
5
+ RendererOptions,
6
+ TuiReadStream,
7
+ TuiRenderer,
8
+ TuiRendererInternal,
9
+ TuiWriteStream,
10
+ } from "./internal/renderer/types.js"