@effect-tui/react 0.1.1 → 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 +31 -26
  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 -96
  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
package/src/hosts/text.ts CHANGED
@@ -1,175 +1,209 @@
1
- import { displayWidth, parseColor, type CellBuffer, type Palette, type ColorLike } from "@effect-tui/core"
1
+ import { displayWidth, type CellBuffer, type Palette, type Color } from "@effect-tui/core"
2
2
  import type { HostContext, Rect, Size, CommonProps } from "../reconciler/types.js"
3
- import { BaseHost } from "./base.js"
3
+ import { BaseHost, getInheritedBg } from "./base.js"
4
+ import { resolveBgStyle, styleIdFromProps } from "../utils/index.js"
4
5
 
5
6
  export interface TextProps extends CommonProps {
6
- fg?: ColorLike
7
- bg?: ColorLike
8
- bold?: boolean
9
- italic?: boolean
10
- underline?: boolean
11
- inverse?: boolean
12
- /** If true, wrap text to multiple lines (default: false, text is truncated) */
13
- wrap?: boolean
7
+ fg?: Color
8
+ bg?: Color
9
+ bold?: boolean
10
+ italic?: boolean
11
+ underline?: boolean
12
+ inverse?: boolean
13
+ /** If true, wrap text to multiple lines (default: false, text is truncated) */
14
+ wrap?: boolean
14
15
  }
15
16
 
16
17
  export class TextHost extends BaseHost {
17
- fg?: ColorLike
18
- bg?: ColorLike
19
- bold = false
20
- italic = false
21
- underline = false
22
- inverse = false
23
- wrap = false // Default: truncate (no wrap)
24
-
25
- // Cache wrapped lines between measure() and render()
26
- private cachedLines: string[] | null = null
27
- private cachedWidth = 0
28
-
29
- constructor(props: TextProps, ctx: HostContext) {
30
- super("text", props, ctx)
31
- this.updateProps(props)
32
- }
33
-
34
- /** Get text content from RawTextHost children */
35
- private getContent(): string {
36
- return this.children
37
- .filter((c): c is RawTextHost => c instanceof RawTextHost)
38
- .map((c) => c.content)
39
- .join("")
40
- }
41
-
42
- measure(maxW: number, maxH: number): Size {
43
- const content = this.getContent()
44
- const rawLines = content.split("\n")
45
-
46
- if (this.wrap) {
47
- // Wrap mode: may span multiple lines. Cache result for render()
48
- this.cachedLines = rawLines.flatMap((line, idx) =>
49
- idx < rawLines.length - 1 ? [...this.wrapText(line, maxW), ""] : this.wrapText(line, maxW),
50
- )
51
- this.cachedWidth = maxW
52
- const w = this.cachedLines.reduce((max, line) => Math.max(max, displayWidth(line)), 0)
53
- return { w, h: Math.min(this.cachedLines.length, maxH) }
54
- }
55
-
56
- // Default: respect explicit newlines but do not wrap long words
57
- this.cachedLines = null
58
- const widths = rawLines.map((line) => Math.min(displayWidth(line), maxW))
59
- const w = widths.reduce((max, val) => Math.max(max, val), 0)
60
- const h = Math.min(rawLines.length, maxH)
61
- return { w, h }
62
- }
63
-
64
- /** Wrap text to fit within maxWidth */
65
- private wrapText(text: string, maxWidth: number): string[] {
66
- const result: string[] = []
67
- for (const rawLine of text.split("\n")) {
68
- if (rawLine === "") {
69
- result.push("")
70
- continue
71
- }
72
- let line = ""
73
- let lineW = 0
74
- for (const ch of rawLine) {
75
- const w = displayWidth(ch)
76
- if (lineW + w > maxWidth && line.length > 0) {
77
- result.push(line)
78
- line = ch
79
- lineW = w
80
- } else {
81
- line += ch
82
- lineW += w
83
- }
84
- }
85
- if (line.length > 0) result.push(line)
86
- }
87
- return result.length > 0 ? result : [""]
88
- }
89
-
90
- override layout(rect: Rect): void {
91
- super.layout(rect)
92
- // Layout children (RawTextHost nodes) at same position
93
- for (const child of this.children) {
94
- child.layout(rect)
95
- }
96
- }
97
-
98
- render(buffer: CellBuffer, palette: Palette): void {
99
- if (!this.rect) return
100
-
101
- const style: Record<string, unknown> = {}
102
- if (this.fg !== undefined) style.fg = typeof this.fg === "string" ? parseColor(this.fg) : this.fg
103
- if (this.bg !== undefined) style.bg = typeof this.bg === "string" ? parseColor(this.bg) : this.bg
104
- if (this.bold) style.bold = true
105
- if (this.italic) style.italic = true
106
- if (this.underline) style.underline = true
107
- if (this.inverse) style.inverse = true
108
-
109
- const styleId = palette.id(style)
110
- const content = this.getContent()
111
- const rawLines = content.split("\n")
112
-
113
- if (this.wrap) {
114
- // Wrap mode: use cached lines if width matches, otherwise rewrap
115
- const rectW = this.rect.w
116
- const lines =
117
- this.cachedLines && this.cachedWidth === rectW
118
- ? this.cachedLines
119
- : rawLines.flatMap((line, idx) =>
120
- idx < rawLines.length - 1 ? [...this.wrapText(line, rectW), ""] : this.wrapText(line, rectW),
121
- )
122
- for (let i = 0; i < lines.length && i < this.rect.h; i++) {
123
- buffer.drawText(this.rect.x, this.rect.y + i, lines[i], styleId, this.rect.w)
124
- }
125
- return
126
- }
127
-
128
- // Default: render explicit newlines, clip to width/height
129
- const maxLines = Math.min(this.rect.h, rawLines.length)
130
- for (let i = 0; i < maxLines; i++) {
131
- buffer.drawText(this.rect.x, this.rect.y + i, rawLines[i], styleId, this.rect.w)
132
- }
133
- }
134
-
135
- override updateProps(props: Record<string, unknown>): void {
136
- super.updateProps(props)
137
- // Always assign; props may be undefined when attribute is removed
138
- this.fg = props.fg as ColorLike | undefined
139
- this.bg = props.bg as ColorLike | undefined
140
- this.bold = Boolean(props.bold)
141
- this.italic = Boolean(props.italic)
142
- this.underline = Boolean(props.underline)
143
- this.inverse = Boolean(props.inverse)
144
- this.wrap = Boolean(props.wrap)
145
- }
18
+ fg?: Color
19
+ bg?: Color
20
+ bold = false
21
+ italic = false
22
+ underline = false
23
+ inverse = false
24
+ wrap = false // Default: truncate (no wrap)
25
+
26
+ // Cache wrapped lines between measure() and render()
27
+ private cachedLines: string[] | null = null
28
+ private cachedWidth = 0
29
+ // Cache content to avoid rescanning children each frame
30
+ private cachedContent: string | null = null
31
+
32
+ constructor(props: TextProps, ctx: HostContext) {
33
+ super("text", props, ctx)
34
+ this.updateProps(props)
35
+ }
36
+
37
+ /** Get text content from RawTextHost children (cached between measure and render) */
38
+ private getContent(): string {
39
+ if (this.cachedContent !== null) {
40
+ return this.cachedContent
41
+ }
42
+ this.cachedContent = this.children
43
+ .filter((c): c is RawTextHost => c instanceof RawTextHost)
44
+ .map((c) => c.content)
45
+ .join("")
46
+ return this.cachedContent
47
+ }
48
+
49
+ /** Invalidate content cache when children change */
50
+ private invalidateContent(): void {
51
+ this.cachedContent = null
52
+ this.cachedLines = null
53
+ }
54
+
55
+ measure(maxW: number, maxH: number): Size {
56
+ // Invalidate content cache at start of measure (will be recomputed on demand)
57
+ this.invalidateContent()
58
+ const content = this.getContent()
59
+ const rawLines = content.split("\n")
60
+
61
+ if (this.wrap) {
62
+ // Wrap mode: may span multiple lines. Cache result for render()
63
+ this.cachedLines = rawLines.flatMap((line, idx) =>
64
+ idx < rawLines.length - 1 ? [...this.wrapText(line, maxW), ""] : this.wrapText(line, maxW),
65
+ )
66
+ this.cachedWidth = maxW
67
+ const w = this.cachedLines.reduce((max, line) => Math.max(max, displayWidth(line)), 0)
68
+ return { w, h: Math.min(this.cachedLines.length, maxH) }
69
+ }
70
+
71
+ // Default: respect explicit newlines but do not wrap long words
72
+ this.cachedLines = null
73
+ const widths = rawLines.map((line) => Math.min(displayWidth(line), maxW))
74
+ const w = widths.reduce((max, val) => Math.max(max, val), 0)
75
+ const h = Math.min(rawLines.length, maxH)
76
+ return { w, h }
77
+ }
78
+
79
+ /** Wrap text to fit within maxWidth */
80
+ private wrapText(text: string, maxWidth: number): string[] {
81
+ const result: string[] = []
82
+ for (const rawLine of text.split("\n")) {
83
+ if (rawLine === "") {
84
+ result.push("")
85
+ continue
86
+ }
87
+ let line = ""
88
+ let lineW = 0
89
+ for (const ch of rawLine) {
90
+ const w = displayWidth(ch)
91
+ if (lineW + w > maxWidth && line.length > 0) {
92
+ result.push(line)
93
+ line = ch
94
+ lineW = w
95
+ } else {
96
+ line += ch
97
+ lineW += w
98
+ }
99
+ }
100
+ if (line.length > 0) result.push(line)
101
+ }
102
+ return result.length > 0 ? result : [""]
103
+ }
104
+
105
+ override layout(rect: Rect): void {
106
+ super.layout(rect)
107
+ // Layout children (RawTextHost nodes) at same position
108
+ for (const child of this.children) {
109
+ child.layout(rect)
110
+ }
111
+ }
112
+
113
+ render(buffer: CellBuffer, palette: Palette): void {
114
+ if (!this.rect) return
115
+
116
+ // If text has no bg, inherit from parent box for proper highlight rendering
117
+ const inheritedBg: Color | undefined = this.bg ?? getInheritedBg(this.parent)
118
+ const { value: bgValue, styleId: bgStyleId } = resolveBgStyle(palette, inheritedBg)
119
+
120
+ const styleId = styleIdFromProps(palette, {
121
+ fg: this.fg,
122
+ bg: inheritedBg,
123
+ bold: this.bold,
124
+ italic: this.italic,
125
+ underline: this.underline,
126
+ inverse: this.inverse,
127
+ })
128
+ const content = this.getContent()
129
+ const rawLines = content.split("\n")
130
+
131
+ if (this.wrap) {
132
+ // Wrap mode: use cached lines if width matches, otherwise rewrap
133
+ const rectW = this.rect.w
134
+ const lines =
135
+ this.cachedLines && this.cachedWidth === rectW
136
+ ? this.cachedLines
137
+ : rawLines.flatMap((line, idx) =>
138
+ idx < rawLines.length - 1 ? [...this.wrapText(line, rectW), ""] : this.wrapText(line, rectW),
139
+ )
140
+ const visibleLines = Math.min(lines.length, this.rect.h)
141
+ // Explicitly paint background under text lines to clear stale styles (e.g., selection highlights).
142
+ if (bgValue !== undefined && visibleLines > 0) {
143
+ buffer.fillRect(this.rect.x, this.rect.y, this.rect.w, visibleLines, " ".codePointAt(0)!, bgStyleId)
144
+ }
145
+ for (let i = 0; i < lines.length && i < this.rect.h; i++) {
146
+ // Pass actual text width to avoid overwriting parent's bg with padding
147
+ const lineWidth = Math.min(displayWidth(lines[i]), this.rect.w)
148
+ buffer.drawText(this.rect.x, this.rect.y + i, lines[i], styleId, lineWidth)
149
+ }
150
+ return
151
+ }
152
+
153
+ // Default: render explicit newlines, clip to width/height
154
+ const maxLines = Math.min(this.rect.h, rawLines.length)
155
+ if (bgValue !== undefined && maxLines > 0) {
156
+ buffer.fillRect(this.rect.x, this.rect.y, this.rect.w, maxLines, " ".codePointAt(0)!, bgStyleId)
157
+ }
158
+ for (let i = 0; i < maxLines; i++) {
159
+ // Pass actual text width to avoid overwriting parent's bg with padding
160
+ const lineWidth = Math.min(displayWidth(rawLines[i]), this.rect.w)
161
+ buffer.drawText(this.rect.x, this.rect.y + i, rawLines[i], styleId, lineWidth)
162
+ }
163
+ }
164
+
165
+ override updateProps(props: Record<string, unknown>): void {
166
+ super.updateProps(props)
167
+ // Always assign; props may be undefined when attribute is removed
168
+ this.fg = props.fg as Color | undefined
169
+ this.bg = props.bg as Color | undefined
170
+ this.bold = Boolean(props.bold)
171
+ this.italic = Boolean(props.italic)
172
+ this.underline = Boolean(props.underline)
173
+ this.inverse = Boolean(props.inverse)
174
+ this.wrap = Boolean(props.wrap)
175
+ }
146
176
  }
147
177
 
148
178
  /** Special host for raw text nodes (React text children) */
149
179
  export class RawTextHost extends BaseHost {
150
- content = ""
151
-
152
- constructor(text: string, ctx: HostContext) {
153
- super("rawtext", {}, ctx)
154
- this.content = text
155
- }
156
-
157
- measure(maxW: number, _maxH: number): Size {
158
- const w = Math.min(displayWidth(this.content), maxW)
159
- return { w, h: 1 }
160
- }
161
-
162
- render(buffer: CellBuffer, palette: Palette): void {
163
- if (!this.rect) return
164
- const styleId = palette.id({})
165
- buffer.drawText(this.rect.x, this.rect.y, this.content, styleId, this.rect.w)
166
- }
167
-
168
- updateText(text: string): void {
169
- this.content = text
170
- }
171
-
172
- override updateProps(_props: Record<string, unknown>): void {
173
- // Raw text has no props
174
- }
180
+ content = ""
181
+
182
+ constructor(text: string, ctx: HostContext) {
183
+ super("rawtext", {}, ctx)
184
+ this.content = text
185
+ }
186
+
187
+ measure(maxW: number, _maxH: number): Size {
188
+ const w = Math.min(displayWidth(this.content), maxW)
189
+ return { w, h: 1 }
190
+ }
191
+
192
+ render(buffer: CellBuffer, palette: Palette): void {
193
+ if (!this.rect) return
194
+ // Inherit bg from parent for proper highlight rendering
195
+ const inheritedBg = getInheritedBg(this.parent)
196
+ const styleId = styleIdFromProps(palette, { bg: inheritedBg })
197
+ // Pass actual text width to avoid overwriting parent's bg with padding
198
+ const textWidth = Math.min(displayWidth(this.content), this.rect.w)
199
+ buffer.drawText(this.rect.x, this.rect.y, this.content, styleId, textWidth)
200
+ }
201
+
202
+ updateText(text: string): void {
203
+ this.content = text
204
+ }
205
+
206
+ override updateProps(_props: Record<string, unknown>): void {
207
+ // Raw text has no props
208
+ }
175
209
  }
@@ -1,64 +1,16 @@
1
- import type { CellBuffer, Palette } from "@effect-tui/core"
2
- import type { HostContext, Rect, Size, CommonProps } from "../reconciler/types.js"
3
- import { BaseHost } from "./base.js"
4
- import { measureFlex, layoutFlex, type FlexAlignment } from "../utils/index.js"
1
+ import type { HostContext, CommonProps } from "../reconciler/types.js"
2
+ import { FlexContainerHost, type FlexContainerProps } from "./flex-container.js"
5
3
 
6
4
  export interface VStackProps extends CommonProps {
7
- spacing?: number
8
- alignment?: "leading" | "center" | "trailing"
5
+ spacing?: number
6
+ alignment?: "leading" | "center" | "trailing"
9
7
  }
10
8
 
11
- // Map VStack alignment names to generic flex alignment
12
- function toFlexAlignment(alignment: "leading" | "center" | "trailing"): FlexAlignment {
13
- switch (alignment) {
14
- case "leading":
15
- return "start"
16
- case "center":
17
- return "center"
18
- case "trailing":
19
- return "end"
20
- }
21
- }
22
-
23
- export class VStackHost extends BaseHost {
24
- spacing = 0
25
- alignment: "leading" | "center" | "trailing" = "leading"
26
- private cachedSizes: Size[] = []
27
-
28
- constructor(props: VStackProps, ctx: HostContext) {
29
- super("vstack", props, ctx)
30
- this.updateProps(props)
31
- }
32
-
33
- measure(maxW: number, maxH: number): Size {
34
- const result = measureFlex("vertical", this.children, this.spacing, maxH, maxW)
35
- this.cachedSizes = result.sizes
36
- return result.totalSize
37
- }
38
-
39
- override layout(rect: Rect): void {
40
- super.layout(rect)
41
- const stretchCross = this.alignment === "leading"
42
- layoutFlex(
43
- "vertical",
44
- this.children,
45
- this.cachedSizes,
46
- rect,
47
- this.spacing,
48
- toFlexAlignment(this.alignment),
49
- stretchCross,
50
- )
51
- }
52
-
53
- render(buffer: CellBuffer, palette: Palette): void {
54
- for (const child of this.children) {
55
- child.render(buffer, palette)
56
- }
57
- }
58
-
59
- override updateProps(props: Record<string, unknown>): void {
60
- super.updateProps(props)
61
- if (props.spacing !== undefined) this.spacing = props.spacing as number
62
- if (props.alignment !== undefined) this.alignment = props.alignment as "leading" | "center" | "trailing"
63
- }
9
+ /**
10
+ * VStackHost lays out children vertically with optional spacing and cross-axis alignment.
11
+ */
12
+ export class VStackHost extends FlexContainerHost<"vertical"> {
13
+ constructor(props: VStackProps, ctx: HostContext) {
14
+ super("vertical", "vstack", props as FlexContainerProps<"vertical">, ctx, "leading")
15
+ }
64
16
  }
@@ -3,75 +3,87 @@ import type { HostContext, Rect, Size, CommonProps } from "../reconciler/types.j
3
3
  import { BaseHost } from "./base.js"
4
4
 
5
5
  export interface ZStackProps extends CommonProps {
6
- alignment?: { h?: "leading" | "center" | "trailing"; v?: "top" | "center" | "bottom" }
6
+ alignment?: { h?: "leading" | "center" | "trailing"; v?: "top" | "center" | "bottom" }
7
7
  }
8
8
 
9
9
  // Overlay children in the same rect, honoring alignment for each child.
10
10
  export class ZStackHost extends BaseHost {
11
- alignmentH: "leading" | "center" | "trailing" = "center"
12
- alignmentV: "top" | "center" | "bottom" = "center"
13
- private cachedSizes: Size[] = []
14
-
15
- constructor(props: ZStackProps, ctx: HostContext) {
16
- super("zstack", props, ctx)
17
- this.updateProps(props)
18
- }
19
-
20
- measure(maxW: number, maxH: number): Size {
21
- let maxChildW = 0
22
- let maxChildH = 0
23
- this.cachedSizes = []
24
-
25
- for (const child of this.children) {
26
- const size = child.measure(maxW, maxH)
27
- this.cachedSizes.push(size)
28
- maxChildW = Math.max(maxChildW, size.w)
29
- maxChildH = Math.max(maxChildH, size.h)
30
- }
31
-
32
- return {
33
- w: Math.min(maxW, maxChildW),
34
- h: Math.min(maxH, maxChildH),
35
- }
36
- }
37
-
38
- override layout(rect: Rect): void {
39
- super.layout(rect)
40
-
41
- for (let i = 0; i < this.children.length; i++) {
42
- const child = this.children[i]
43
- const size = this.cachedSizes[i] ?? child.measure(rect.w, rect.h)
44
-
45
- let x = rect.x
46
- let y = rect.y
47
-
48
- if (this.alignmentH === "center") x += Math.floor((rect.w - size.w) / 2)
49
- else if (this.alignmentH === "trailing") x += Math.max(0, rect.w - size.w)
50
-
51
- if (this.alignmentV === "center") y += Math.floor((rect.h - size.h) / 2)
52
- else if (this.alignmentV === "bottom") y += Math.max(0, rect.h - size.h)
53
-
54
- child.layout({
55
- x,
56
- y,
57
- w: Math.min(rect.w, size.w),
58
- h: Math.min(rect.h, size.h),
59
- })
60
- }
61
- }
62
-
63
- render(buffer: CellBuffer, palette: Palette): void {
64
- for (const child of this.children) {
65
- child.render(buffer, palette)
66
- }
67
- }
68
-
69
- override updateProps(props: Record<string, unknown>): void {
70
- super.updateProps(props)
71
- if (props.alignment !== undefined) {
72
- const a = props.alignment as ZStackProps["alignment"]
73
- if (a?.h) this.alignmentH = a.h
74
- if (a?.v) this.alignmentV = a.v
75
- }
76
- }
11
+ alignmentH: "leading" | "center" | "trailing" = "center"
12
+ alignmentV: "top" | "center" | "bottom" = "center"
13
+ private cachedSizes: Size[] = []
14
+
15
+ constructor(props: ZStackProps, ctx: HostContext) {
16
+ super("zstack", props, ctx)
17
+ this.updateProps(props)
18
+ }
19
+
20
+ measure(maxW: number, maxH: number): Size {
21
+ // Apply frame constraints to what we propose to children
22
+ const constrained = this.constrainProposal(maxW, maxH)
23
+
24
+ let maxChildW = 0
25
+ let maxChildH = 0
26
+ this.cachedSizes = []
27
+
28
+ for (const child of this.children) {
29
+ const size = child.measure(constrained.w, constrained.h)
30
+ this.cachedSizes.push(size)
31
+ maxChildW = Math.max(maxChildW, size.w)
32
+ maxChildH = Math.max(maxChildH, size.h)
33
+ }
34
+
35
+ const naturalSize = {
36
+ w: Math.min(constrained.w, maxChildW),
37
+ h: Math.min(constrained.h, maxChildH),
38
+ }
39
+
40
+ // Apply frame constraints to what we report to parent
41
+ return this.constrainResult(naturalSize)
42
+ }
43
+
44
+ override layout(rect: Rect): void {
45
+ super.layout(rect)
46
+
47
+ for (let i = 0; i < this.children.length; i++) {
48
+ const child = this.children[i]
49
+ const size = this.cachedSizes[i] ?? child.measure(rect.w, rect.h)
50
+
51
+ let x = rect.x
52
+ let y = rect.y
53
+
54
+ if (this.alignmentH === "center") x += Math.floor((rect.w - size.w) / 2)
55
+ else if (this.alignmentH === "trailing") x += Math.max(0, rect.w - size.w)
56
+
57
+ if (this.alignmentV === "center") y += Math.floor((rect.h - size.h) / 2)
58
+ else if (this.alignmentV === "bottom") y += Math.max(0, rect.h - size.h)
59
+
60
+ child.layout({
61
+ x,
62
+ y,
63
+ w: Math.min(rect.w, size.w),
64
+ h: Math.min(rect.h, size.h),
65
+ })
66
+ }
67
+ }
68
+
69
+ render(buffer: CellBuffer, palette: Palette): void {
70
+ for (const child of this.children) {
71
+ if (child.rect) {
72
+ buffer.withClip(child.rect.x, child.rect.y, child.rect.w, child.rect.h, () => {
73
+ child.render(buffer, palette)
74
+ })
75
+ } else {
76
+ child.render(buffer, palette)
77
+ }
78
+ }
79
+ }
80
+
81
+ override updateProps(props: Record<string, unknown>): void {
82
+ super.updateProps(props)
83
+ if (props.alignment !== undefined) {
84
+ const a = props.alignment as ZStackProps["alignment"]
85
+ if (a?.h) this.alignmentH = a.h
86
+ if (a?.v) this.alignmentV = a.v
87
+ }
88
+ }
77
89
  }