nastech-tui 0.0.1

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 (424) hide show
  1. package/.prettierrc +11 -0
  2. package/README.md +346 -0
  3. package/eslint.config.mjs +111 -0
  4. package/package.json +51 -0
  5. package/packages/nastech-ink/ambient.d.ts +83 -0
  6. package/packages/nastech-ink/index.d.ts +40 -0
  7. package/packages/nastech-ink/index.js +1 -0
  8. package/packages/nastech-ink/nastech-ink/ambient.d.ts +83 -0
  9. package/packages/nastech-ink/nastech-ink/index.d.ts +40 -0
  10. package/packages/nastech-ink/nastech-ink/index.js +1 -0
  11. package/packages/nastech-ink/nastech-ink/package.json +54 -0
  12. package/packages/nastech-ink/nastech-ink/src/bootstrap/state.ts +9 -0
  13. package/packages/nastech-ink/nastech-ink/src/entry-exports.ts +32 -0
  14. package/packages/nastech-ink/nastech-ink/src/hooks/use-stderr.ts +15 -0
  15. package/packages/nastech-ink/nastech-ink/src/hooks/use-stdout.ts +15 -0
  16. package/packages/nastech-ink/nastech-ink/src/ink/Ansi.tsx +435 -0
  17. package/packages/nastech-ink/nastech-ink/src/ink/app-mouse.test.ts +123 -0
  18. package/packages/nastech-ink/nastech-ink/src/ink/bidi.ts +145 -0
  19. package/packages/nastech-ink/nastech-ink/src/ink/cache-eviction.ts +45 -0
  20. package/packages/nastech-ink/nastech-ink/src/ink/clearTerminal.ts +68 -0
  21. package/packages/nastech-ink/nastech-ink/src/ink/colorize.test.ts +60 -0
  22. package/packages/nastech-ink/nastech-ink/src/ink/colorize.ts +277 -0
  23. package/packages/nastech-ink/nastech-ink/src/ink/components/AlternateScreen.tsx +133 -0
  24. package/packages/nastech-ink/nastech-ink/src/ink/components/App.tsx +830 -0
  25. package/packages/nastech-ink/nastech-ink/src/ink/components/AppContext.ts +20 -0
  26. package/packages/nastech-ink/nastech-ink/src/ink/components/Box.tsx +294 -0
  27. package/packages/nastech-ink/nastech-ink/src/ink/components/Button.tsx +236 -0
  28. package/packages/nastech-ink/nastech-ink/src/ink/components/ClockContext.tsx +133 -0
  29. package/packages/nastech-ink/nastech-ink/src/ink/components/CursorAdvanceContext.ts +35 -0
  30. package/packages/nastech-ink/nastech-ink/src/ink/components/CursorDeclarationContext.ts +28 -0
  31. package/packages/nastech-ink/nastech-ink/src/ink/components/ErrorOverview.tsx +130 -0
  32. package/packages/nastech-ink/nastech-ink/src/ink/components/Link.tsx +38 -0
  33. package/packages/nastech-ink/nastech-ink/src/ink/components/Newline.tsx +43 -0
  34. package/packages/nastech-ink/nastech-ink/src/ink/components/NoSelect.tsx +73 -0
  35. package/packages/nastech-ink/nastech-ink/src/ink/components/RawAnsi.tsx +61 -0
  36. package/packages/nastech-ink/nastech-ink/src/ink/components/ScrollBox.tsx +290 -0
  37. package/packages/nastech-ink/nastech-ink/src/ink/components/Spacer.tsx +23 -0
  38. package/packages/nastech-ink/nastech-ink/src/ink/components/StdinContext.ts +25 -0
  39. package/packages/nastech-ink/nastech-ink/src/ink/components/TerminalFocusContext.tsx +63 -0
  40. package/packages/nastech-ink/nastech-ink/src/ink/components/TerminalSizeContext.tsx +7 -0
  41. package/packages/nastech-ink/nastech-ink/src/ink/components/Text.test.ts +38 -0
  42. package/packages/nastech-ink/nastech-ink/src/ink/components/Text.tsx +336 -0
  43. package/packages/nastech-ink/nastech-ink/src/ink/constants.ts +6 -0
  44. package/packages/nastech-ink/nastech-ink/src/ink/cursor.ts +5 -0
  45. package/packages/nastech-ink/nastech-ink/src/ink/devtools.ts +2 -0
  46. package/packages/nastech-ink/nastech-ink/src/ink/dom.ts +495 -0
  47. package/packages/nastech-ink/nastech-ink/src/ink/events/click-event.ts +38 -0
  48. package/packages/nastech-ink/nastech-ink/src/ink/events/cmd-shortcuts.test.ts +65 -0
  49. package/packages/nastech-ink/nastech-ink/src/ink/events/dispatcher.ts +242 -0
  50. package/packages/nastech-ink/nastech-ink/src/ink/events/emitter.ts +40 -0
  51. package/packages/nastech-ink/nastech-ink/src/ink/events/event-handlers.ts +84 -0
  52. package/packages/nastech-ink/nastech-ink/src/ink/events/event.ts +11 -0
  53. package/packages/nastech-ink/nastech-ink/src/ink/events/focus-event.ts +18 -0
  54. package/packages/nastech-ink/nastech-ink/src/ink/events/input-event.ts +176 -0
  55. package/packages/nastech-ink/nastech-ink/src/ink/events/keyboard-event.ts +57 -0
  56. package/packages/nastech-ink/nastech-ink/src/ink/events/mouse-event.ts +18 -0
  57. package/packages/nastech-ink/nastech-ink/src/ink/events/paste-event.ts +10 -0
  58. package/packages/nastech-ink/nastech-ink/src/ink/events/resize-event.ts +12 -0
  59. package/packages/nastech-ink/nastech-ink/src/ink/events/terminal-event.ts +107 -0
  60. package/packages/nastech-ink/nastech-ink/src/ink/events/terminal-focus-event.ts +19 -0
  61. package/packages/nastech-ink/nastech-ink/src/ink/focus.ts +219 -0
  62. package/packages/nastech-ink/nastech-ink/src/ink/frame.ts +124 -0
  63. package/packages/nastech-ink/nastech-ink/src/ink/get-max-width.ts +27 -0
  64. package/packages/nastech-ink/nastech-ink/src/ink/global.d.ts +1 -0
  65. package/packages/nastech-ink/nastech-ink/src/ink/hit-test.test.ts +38 -0
  66. package/packages/nastech-ink/nastech-ink/src/ink/hit-test.ts +224 -0
  67. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-animation-frame.ts +62 -0
  68. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-app.ts +9 -0
  69. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-cursor-advance.ts +33 -0
  70. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-declared-cursor.ts +75 -0
  71. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-external-process.ts +27 -0
  72. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-input.ts +95 -0
  73. package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-interval.ts +71 -0
  74. package/packages/nastech-ink/package.json +57 -0
  75. package/packages/nastech-ink/src/bootstrap/state.ts +9 -0
  76. package/packages/nastech-ink/src/entry-exports.ts +32 -0
  77. package/packages/nastech-ink/src/hooks/use-stderr.ts +15 -0
  78. package/packages/nastech-ink/src/hooks/use-stdout.ts +15 -0
  79. package/packages/nastech-ink/src/ink/Ansi.tsx +435 -0
  80. package/packages/nastech-ink/src/ink/app-mouse.test.ts +123 -0
  81. package/packages/nastech-ink/src/ink/app-rawmode-mouse.test.ts +91 -0
  82. package/packages/nastech-ink/src/ink/bidi.ts +145 -0
  83. package/packages/nastech-ink/src/ink/cache-eviction.ts +45 -0
  84. package/packages/nastech-ink/src/ink/clearTerminal.ts +68 -0
  85. package/packages/nastech-ink/src/ink/colorize.test.ts +60 -0
  86. package/packages/nastech-ink/src/ink/colorize.ts +277 -0
  87. package/packages/nastech-ink/src/ink/components/AlternateScreen.tsx +133 -0
  88. package/packages/nastech-ink/src/ink/components/App.tsx +855 -0
  89. package/packages/nastech-ink/src/ink/components/AppContext.ts +20 -0
  90. package/packages/nastech-ink/src/ink/components/Box.tsx +294 -0
  91. package/packages/nastech-ink/src/ink/components/Button.tsx +236 -0
  92. package/packages/nastech-ink/src/ink/components/ClockContext.tsx +133 -0
  93. package/packages/nastech-ink/src/ink/components/CursorAdvanceContext.ts +35 -0
  94. package/packages/nastech-ink/src/ink/components/CursorDeclarationContext.ts +28 -0
  95. package/packages/nastech-ink/src/ink/components/ErrorOverview.tsx +130 -0
  96. package/packages/nastech-ink/src/ink/components/Link.tsx +38 -0
  97. package/packages/nastech-ink/src/ink/components/Newline.tsx +43 -0
  98. package/packages/nastech-ink/src/ink/components/NoSelect.tsx +73 -0
  99. package/packages/nastech-ink/src/ink/components/RawAnsi.tsx +61 -0
  100. package/packages/nastech-ink/src/ink/components/ScrollBox.tsx +290 -0
  101. package/packages/nastech-ink/src/ink/components/Spacer.tsx +23 -0
  102. package/packages/nastech-ink/src/ink/components/StdinContext.ts +25 -0
  103. package/packages/nastech-ink/src/ink/components/TerminalFocusContext.tsx +63 -0
  104. package/packages/nastech-ink/src/ink/components/TerminalSizeContext.tsx +7 -0
  105. package/packages/nastech-ink/src/ink/components/Text.test.ts +38 -0
  106. package/packages/nastech-ink/src/ink/components/Text.tsx +336 -0
  107. package/packages/nastech-ink/src/ink/constants.ts +6 -0
  108. package/packages/nastech-ink/src/ink/cursor.ts +5 -0
  109. package/packages/nastech-ink/src/ink/devtools.ts +2 -0
  110. package/packages/nastech-ink/src/ink/dom.ts +495 -0
  111. package/packages/nastech-ink/src/ink/events/click-event.ts +38 -0
  112. package/packages/nastech-ink/src/ink/events/cmd-shortcuts.test.ts +65 -0
  113. package/packages/nastech-ink/src/ink/events/dispatcher.ts +242 -0
  114. package/packages/nastech-ink/src/ink/events/emitter.ts +40 -0
  115. package/packages/nastech-ink/src/ink/events/event-handlers.ts +84 -0
  116. package/packages/nastech-ink/src/ink/events/event.ts +11 -0
  117. package/packages/nastech-ink/src/ink/events/focus-event.ts +18 -0
  118. package/packages/nastech-ink/src/ink/events/input-event.ts +176 -0
  119. package/packages/nastech-ink/src/ink/events/keyboard-event.ts +57 -0
  120. package/packages/nastech-ink/src/ink/events/mouse-event.ts +18 -0
  121. package/packages/nastech-ink/src/ink/events/paste-event.ts +10 -0
  122. package/packages/nastech-ink/src/ink/events/resize-event.ts +12 -0
  123. package/packages/nastech-ink/src/ink/events/terminal-event.ts +107 -0
  124. package/packages/nastech-ink/src/ink/events/terminal-focus-event.ts +19 -0
  125. package/packages/nastech-ink/src/ink/focus.ts +219 -0
  126. package/packages/nastech-ink/src/ink/frame.ts +124 -0
  127. package/packages/nastech-ink/src/ink/get-max-width.ts +27 -0
  128. package/packages/nastech-ink/src/ink/global.d.ts +1 -0
  129. package/packages/nastech-ink/src/ink/hit-test.test.ts +38 -0
  130. package/packages/nastech-ink/src/ink/hit-test.ts +224 -0
  131. package/packages/nastech-ink/src/ink/hooks/use-animation-frame.ts +62 -0
  132. package/packages/nastech-ink/src/ink/hooks/use-app.ts +9 -0
  133. package/packages/nastech-ink/src/ink/hooks/use-cursor-advance.ts +33 -0
  134. package/packages/nastech-ink/src/ink/hooks/use-declared-cursor.ts +75 -0
  135. package/packages/nastech-ink/src/ink/hooks/use-external-process.ts +27 -0
  136. package/packages/nastech-ink/src/ink/hooks/use-input.ts +95 -0
  137. package/packages/nastech-ink/src/ink/hooks/use-interval.ts +71 -0
  138. package/packages/nastech-ink/src/ink/hooks/use-search-highlight.ts +56 -0
  139. package/packages/nastech-ink/src/ink/hooks/use-selection.ts +101 -0
  140. package/packages/nastech-ink/src/ink/hooks/use-stdin.ts +9 -0
  141. package/packages/nastech-ink/src/ink/hooks/use-tab-status.ts +71 -0
  142. package/packages/nastech-ink/src/ink/hooks/use-terminal-focus.ts +18 -0
  143. package/packages/nastech-ink/src/ink/hooks/use-terminal-title.ts +34 -0
  144. package/packages/nastech-ink/src/ink/hooks/use-terminal-viewport.ts +100 -0
  145. package/packages/nastech-ink/src/ink/hyperlinkHover.ts +52 -0
  146. package/packages/nastech-ink/src/ink/ink-cursor-advance.test.ts +234 -0
  147. package/packages/nastech-ink/src/ink/ink-resize.test.ts +50 -0
  148. package/packages/nastech-ink/src/ink/ink.tsx +2705 -0
  149. package/packages/nastech-ink/src/ink/instances.ts +10 -0
  150. package/packages/nastech-ink/src/ink/layout/engine.ts +6 -0
  151. package/packages/nastech-ink/src/ink/layout/geometry.ts +98 -0
  152. package/packages/nastech-ink/src/ink/layout/node.ts +145 -0
  153. package/packages/nastech-ink/src/ink/layout/yoga.ts +313 -0
  154. package/packages/nastech-ink/src/ink/line-width-cache.ts +38 -0
  155. package/packages/nastech-ink/src/ink/log-update.test.ts +223 -0
  156. package/packages/nastech-ink/src/ink/log-update.ts +752 -0
  157. package/packages/nastech-ink/src/ink/lru.ts +14 -0
  158. package/packages/nastech-ink/src/ink/measure-element.ts +23 -0
  159. package/packages/nastech-ink/src/ink/measure-text.ts +50 -0
  160. package/packages/nastech-ink/src/ink/node-cache.ts +53 -0
  161. package/packages/nastech-ink/src/ink/optimizer.ts +99 -0
  162. package/packages/nastech-ink/src/ink/output.ts +845 -0
  163. package/packages/nastech-ink/src/ink/parse-keypress.test.ts +133 -0
  164. package/packages/nastech-ink/src/ink/parse-keypress.ts +848 -0
  165. package/packages/nastech-ink/src/ink/reconciler.ts +382 -0
  166. package/packages/nastech-ink/src/ink/render-border.ts +206 -0
  167. package/packages/nastech-ink/src/ink/render-node-to-output.ts +1582 -0
  168. package/packages/nastech-ink/src/ink/render-to-screen.ts +236 -0
  169. package/packages/nastech-ink/src/ink/renderer.ts +169 -0
  170. package/packages/nastech-ink/src/ink/root.ts +204 -0
  171. package/packages/nastech-ink/src/ink/screen.ts +1590 -0
  172. package/packages/nastech-ink/src/ink/searchHighlight.ts +91 -0
  173. package/packages/nastech-ink/src/ink/selection.test.ts +82 -0
  174. package/packages/nastech-ink/src/ink/selection.ts +1143 -0
  175. package/packages/nastech-ink/src/ink/squash-text-nodes.ts +74 -0
  176. package/packages/nastech-ink/src/ink/stringWidth.ts +341 -0
  177. package/packages/nastech-ink/src/ink/styles.ts +750 -0
  178. package/packages/nastech-ink/src/ink/supports-hyperlinks.ts +51 -0
  179. package/packages/nastech-ink/src/ink/tabstops.ts +44 -0
  180. package/packages/nastech-ink/src/ink/terminal-focus-state.ts +52 -0
  181. package/packages/nastech-ink/src/ink/terminal-querier.ts +222 -0
  182. package/packages/nastech-ink/src/ink/terminal.test.ts +15 -0
  183. package/packages/nastech-ink/src/ink/terminal.ts +299 -0
  184. package/packages/nastech-ink/src/ink/termio/ansi.ts +75 -0
  185. package/packages/nastech-ink/src/ink/termio/csi.ts +334 -0
  186. package/packages/nastech-ink/src/ink/termio/dec.ts +99 -0
  187. package/packages/nastech-ink/src/ink/termio/esc.ts +69 -0
  188. package/packages/nastech-ink/src/ink/termio/osc.test.ts +191 -0
  189. package/packages/nastech-ink/src/ink/termio/osc.ts +724 -0
  190. package/packages/nastech-ink/src/ink/termio/parser.ts +467 -0
  191. package/packages/nastech-ink/src/ink/termio/sgr.ts +362 -0
  192. package/packages/nastech-ink/src/ink/termio/tokenize.test.ts +185 -0
  193. package/packages/nastech-ink/src/ink/termio/tokenize.ts +350 -0
  194. package/packages/nastech-ink/src/ink/termio/types.ts +230 -0
  195. package/packages/nastech-ink/src/ink/termio.ts +42 -0
  196. package/packages/nastech-ink/src/ink/useTerminalNotification.ts +110 -0
  197. package/packages/nastech-ink/src/ink/warn.ts +15 -0
  198. package/packages/nastech-ink/src/ink/widest-line.ts +22 -0
  199. package/packages/nastech-ink/src/ink/wrap-text.test.ts +17 -0
  200. package/packages/nastech-ink/src/ink/wrap-text.ts +144 -0
  201. package/packages/nastech-ink/src/ink/wrapAnsi.ts +13 -0
  202. package/packages/nastech-ink/src/native-ts/yoga-layout/enums.ts +112 -0
  203. package/packages/nastech-ink/src/native-ts/yoga-layout/index.ts +2326 -0
  204. package/packages/nastech-ink/src/utils/debug.ts +6 -0
  205. package/packages/nastech-ink/src/utils/earlyInput.ts +131 -0
  206. package/packages/nastech-ink/src/utils/env.ts +66 -0
  207. package/packages/nastech-ink/src/utils/envUtils.ts +13 -0
  208. package/packages/nastech-ink/src/utils/execFileNoThrow.test.ts +146 -0
  209. package/packages/nastech-ink/src/utils/execFileNoThrow.ts +115 -0
  210. package/packages/nastech-ink/src/utils/fullscreen.ts +3 -0
  211. package/packages/nastech-ink/src/utils/intl.ts +87 -0
  212. package/packages/nastech-ink/src/utils/log.ts +7 -0
  213. package/packages/nastech-ink/src/utils/semver.ts +57 -0
  214. package/packages/nastech-ink/src/utils/sliceAnsi.ts +106 -0
  215. package/packages/nastech-ink/text-input.d.ts +2 -0
  216. package/packages/nastech-ink/text-input.js +1 -0
  217. package/scripts/build.mjs +61 -0
  218. package/scripts/profile-tui.mjs +121 -0
  219. package/src/__tests__/activeSessionSwitcher.test.ts +157 -0
  220. package/src/__tests__/appChromeStatusRule.test.tsx +84 -0
  221. package/src/__tests__/appChromeStatusRuleDevCredits.test.tsx +73 -0
  222. package/src/__tests__/approvalAction.test.ts +50 -0
  223. package/src/__tests__/asCommandDispatch.test.ts +27 -0
  224. package/src/__tests__/blockLayout.test.ts +122 -0
  225. package/src/__tests__/clipboard.test.ts +369 -0
  226. package/src/__tests__/constants.test.ts +53 -0
  227. package/src/__tests__/createGatewayEventHandler.test.ts +1091 -0
  228. package/src/__tests__/createSlashHandler.test.ts +822 -0
  229. package/src/__tests__/creditsCommand.test.ts +144 -0
  230. package/src/__tests__/cursorDriftRegression.test.ts +114 -0
  231. package/src/__tests__/details.test.ts +115 -0
  232. package/src/__tests__/emoji.test.ts +64 -0
  233. package/src/__tests__/externalLink.test.ts +144 -0
  234. package/src/__tests__/forceTruecolor.test.ts +191 -0
  235. package/src/__tests__/gatewayClient.test.ts +394 -0
  236. package/src/__tests__/gatewayRecovery.test.ts +47 -0
  237. package/src/__tests__/markdown.test.ts +331 -0
  238. package/src/__tests__/mathUnicode.test.ts +293 -0
  239. package/src/__tests__/memoryMonitor.test.ts +102 -0
  240. package/src/__tests__/messageLine.test.ts +19 -0
  241. package/src/__tests__/messages.test.ts +92 -0
  242. package/src/__tests__/orchestratorPromptSession.test.ts +64 -0
  243. package/src/__tests__/osc52.test.ts +67 -0
  244. package/src/__tests__/parentLog.test.ts +75 -0
  245. package/src/__tests__/paths.test.ts +70 -0
  246. package/src/__tests__/platform.test.ts +556 -0
  247. package/src/__tests__/precisionWheel.test.ts +44 -0
  248. package/src/__tests__/prompt.test.ts +31 -0
  249. package/src/__tests__/providers.test.ts +65 -0
  250. package/src/__tests__/reasoning.test.ts +76 -0
  251. package/src/__tests__/rpc.test.ts +27 -0
  252. package/src/__tests__/scroll.test.ts +99 -0
  253. package/src/__tests__/slashParity.test.ts +123 -0
  254. package/src/__tests__/spawnHistoryStore.test.ts +46 -0
  255. package/src/__tests__/stateIsolation.test.ts +46 -0
  256. package/src/__tests__/statusBarTicker.test.ts +18 -0
  257. package/src/__tests__/statusRule.test.ts +32 -0
  258. package/src/__tests__/streamingMarkdown.test.ts +121 -0
  259. package/src/__tests__/subagentTree.test.ts +407 -0
  260. package/src/__tests__/syntax.test.ts +45 -0
  261. package/src/__tests__/terminalModes.test.ts +39 -0
  262. package/src/__tests__/terminalParity.test.ts +77 -0
  263. package/src/__tests__/terminalSetup.test.ts +386 -0
  264. package/src/__tests__/termux.test.ts +35 -0
  265. package/src/__tests__/termuxComposerLayout.test.ts +40 -0
  266. package/src/__tests__/text.test.ts +233 -0
  267. package/src/__tests__/textInputBurstInput.test.ts +40 -0
  268. package/src/__tests__/textInputCursorSourceOfTruth.test.ts +50 -0
  269. package/src/__tests__/textInputFastEcho.test.ts +200 -0
  270. package/src/__tests__/textInputLineNav.test.ts +55 -0
  271. package/src/__tests__/textInputPassThrough.test.ts +59 -0
  272. package/src/__tests__/textInputRightClick.test.ts +48 -0
  273. package/src/__tests__/textInputWrap.test.ts +151 -0
  274. package/src/__tests__/theme.test.ts +311 -0
  275. package/src/__tests__/turnControllerNotice.test.ts +43 -0
  276. package/src/__tests__/turnStore.test.ts +66 -0
  277. package/src/__tests__/useCompletion.test.ts +35 -0
  278. package/src/__tests__/useComposerState.test.ts +59 -0
  279. package/src/__tests__/useConfigSync.test.ts +460 -0
  280. package/src/__tests__/useInputHandlers.test.ts +77 -0
  281. package/src/__tests__/useQueue.test.ts +28 -0
  282. package/src/__tests__/useSessionLifecycle.test.ts +60 -0
  283. package/src/__tests__/useVirtualHistoryHeights.test.ts +39 -0
  284. package/src/__tests__/viewport.test.ts +58 -0
  285. package/src/__tests__/viewportStore.test.ts +85 -0
  286. package/src/__tests__/virtualHeights.test.ts +96 -0
  287. package/src/__tests__/virtualHistoryClamp.test.ts +19 -0
  288. package/src/__tests__/virtualHistoryOffsetCache.test.ts +282 -0
  289. package/src/__tests__/wheelAccel.test.ts +138 -0
  290. package/src/app/createGatewayEventHandler.ts +833 -0
  291. package/src/app/createSlashHandler.ts +130 -0
  292. package/src/app/delegationStore.ts +77 -0
  293. package/src/app/gatewayContext.tsx +19 -0
  294. package/src/app/gatewayRecovery.ts +35 -0
  295. package/src/app/inputSelectionStore.ts +15 -0
  296. package/src/app/interfaces.ts +394 -0
  297. package/src/app/overlayStore.ts +53 -0
  298. package/src/app/scroll.ts +71 -0
  299. package/src/app/setupHandoff.ts +54 -0
  300. package/src/app/slash/commands/core.ts +648 -0
  301. package/src/app/slash/commands/credits.ts +57 -0
  302. package/src/app/slash/commands/debug.ts +48 -0
  303. package/src/app/slash/commands/ops.ts +717 -0
  304. package/src/app/slash/commands/session.ts +554 -0
  305. package/src/app/slash/commands/setup.ts +20 -0
  306. package/src/app/slash/registry.ts +20 -0
  307. package/src/app/slash/types.ts +21 -0
  308. package/src/app/spawnHistoryStore.ts +159 -0
  309. package/src/app/turnController.ts +866 -0
  310. package/src/app/turnStore.ts +85 -0
  311. package/src/app/uiStore.ts +44 -0
  312. package/src/app/useComposerState.ts +367 -0
  313. package/src/app/useConfigSync.ts +288 -0
  314. package/src/app/useInputHandlers.ts +576 -0
  315. package/src/app/useLongRunToolCharms.ts +69 -0
  316. package/src/app/useMainApp.ts +1039 -0
  317. package/src/app/useSessionLifecycle.ts +366 -0
  318. package/src/app/useSubmission.ts +429 -0
  319. package/src/app.tsx +25 -0
  320. package/src/banner.ts +93 -0
  321. package/src/components/activeSessionSwitcher.tsx +635 -0
  322. package/src/components/agentsOverlay.tsx +1073 -0
  323. package/src/components/appChrome.tsx +554 -0
  324. package/src/components/appLayout.tsx +444 -0
  325. package/src/components/appOverlays.tsx +254 -0
  326. package/src/components/branding.tsx +466 -0
  327. package/src/components/fpsOverlay.tsx +30 -0
  328. package/src/components/helpHint.tsx +73 -0
  329. package/src/components/markdown.tsx +1119 -0
  330. package/src/components/maskedPrompt.tsx +34 -0
  331. package/src/components/messageLine.tsx +237 -0
  332. package/src/components/modelPicker.tsx +527 -0
  333. package/src/components/overlayControls.tsx +50 -0
  334. package/src/components/pluginsHub.tsx +238 -0
  335. package/src/components/prompts.tsx +276 -0
  336. package/src/components/queuedMessages.tsx +64 -0
  337. package/src/components/sessionPicker.tsx +227 -0
  338. package/src/components/skillsHub.tsx +308 -0
  339. package/src/components/streamingAssistant.tsx +110 -0
  340. package/src/components/streamingMarkdown.tsx +174 -0
  341. package/src/components/textInput.tsx +1340 -0
  342. package/src/components/themed.tsx +30 -0
  343. package/src/components/thinking.tsx +1224 -0
  344. package/src/components/todoPanel.tsx +93 -0
  345. package/src/config/env.ts +64 -0
  346. package/src/config/limits.ts +13 -0
  347. package/src/config/timing.ts +6 -0
  348. package/src/content/charms.ts +1 -0
  349. package/src/content/faces.ts +17 -0
  350. package/src/content/fortunes.ts +30 -0
  351. package/src/content/hotkeys.ts +37 -0
  352. package/src/content/placeholders.ts +13 -0
  353. package/src/content/setup.ts +17 -0
  354. package/src/content/verbs.ts +38 -0
  355. package/src/domain/blockLayout.ts +146 -0
  356. package/src/domain/details.ts +76 -0
  357. package/src/domain/messages.ts +91 -0
  358. package/src/domain/paths.ts +16 -0
  359. package/src/domain/providers.ts +11 -0
  360. package/src/domain/roles.ts +9 -0
  361. package/src/domain/slash.ts +10 -0
  362. package/src/domain/usage.ts +3 -0
  363. package/src/domain/viewport.ts +51 -0
  364. package/src/entry.tsx +104 -0
  365. package/src/gatewayClient.ts +730 -0
  366. package/src/gatewayTypes.ts +568 -0
  367. package/src/hooks/useCompletion.ts +112 -0
  368. package/src/hooks/useGitBranch.ts +72 -0
  369. package/src/hooks/useInputHistory.ts +11 -0
  370. package/src/hooks/useQueue.ts +76 -0
  371. package/src/hooks/useVirtualHistory.ts +554 -0
  372. package/src/lib/circularBuffer.ts +48 -0
  373. package/src/lib/clipboard.ts +182 -0
  374. package/src/lib/editor.test.ts +74 -0
  375. package/src/lib/editor.ts +47 -0
  376. package/src/lib/emoji.ts +55 -0
  377. package/src/lib/externalCli.ts +16 -0
  378. package/src/lib/externalLink.ts +435 -0
  379. package/src/lib/forceTruecolor.ts +60 -0
  380. package/src/lib/fpsStore.ts +51 -0
  381. package/src/lib/fuzzy.test.ts +109 -0
  382. package/src/lib/fuzzy.ts +177 -0
  383. package/src/lib/gracefulExit.ts +47 -0
  384. package/src/lib/history.ts +82 -0
  385. package/src/lib/inputMetrics.ts +203 -0
  386. package/src/lib/liveProgress.test.ts +116 -0
  387. package/src/lib/liveProgress.ts +79 -0
  388. package/src/lib/mathUnicode.ts +770 -0
  389. package/src/lib/memory.test.ts +155 -0
  390. package/src/lib/memory.ts +188 -0
  391. package/src/lib/memoryMonitor.ts +109 -0
  392. package/src/lib/messages.test.ts +29 -0
  393. package/src/lib/messages.ts +8 -0
  394. package/src/lib/openExternalUrl.test.ts +217 -0
  395. package/src/lib/openExternalUrl.ts +158 -0
  396. package/src/lib/osc52.ts +73 -0
  397. package/src/lib/parentLog.ts +57 -0
  398. package/src/lib/perfPane.tsx +107 -0
  399. package/src/lib/platform.ts +409 -0
  400. package/src/lib/precisionWheel.ts +48 -0
  401. package/src/lib/prompt.ts +35 -0
  402. package/src/lib/reasoning.ts +55 -0
  403. package/src/lib/rpc.ts +41 -0
  404. package/src/lib/subagentTree.ts +355 -0
  405. package/src/lib/syntax.ts +117 -0
  406. package/src/lib/terminalModes.ts +51 -0
  407. package/src/lib/terminalParity.ts +78 -0
  408. package/src/lib/terminalSetup.ts +444 -0
  409. package/src/lib/termux.ts +29 -0
  410. package/src/lib/text.test.ts +18 -0
  411. package/src/lib/text.ts +339 -0
  412. package/src/lib/todo.test.ts +21 -0
  413. package/src/lib/todo.ts +9 -0
  414. package/src/lib/viewportStore.ts +124 -0
  415. package/src/lib/virtualHeights.ts +145 -0
  416. package/src/lib/wheelAccel.ts +190 -0
  417. package/src/protocol/interpolation.ts +3 -0
  418. package/src/protocol/paste.ts +1 -0
  419. package/src/theme.ts +589 -0
  420. package/src/types/nastech-ink.d.ts +176 -0
  421. package/src/types.ts +212 -0
  422. package/tsconfig.build.json +9 -0
  423. package/tsconfig.json +19 -0
  424. package/vitest.config.ts +7 -0
@@ -0,0 +1,107 @@
1
+ import { Event } from './event.js'
2
+
3
+ type EventPhase = 'none' | 'capturing' | 'at_target' | 'bubbling'
4
+
5
+ type TerminalEventInit = {
6
+ bubbles?: boolean
7
+ cancelable?: boolean
8
+ }
9
+
10
+ /**
11
+ * Base class for all terminal events with DOM-style propagation.
12
+ *
13
+ * Extends Event so existing event types (ClickEvent, InputEvent,
14
+ * TerminalFocusEvent) share a common ancestor and can migrate later.
15
+ *
16
+ * Mirrors the browser's Event API: target, currentTarget, eventPhase,
17
+ * stopPropagation(), preventDefault(), timeStamp.
18
+ */
19
+ export class TerminalEvent extends Event {
20
+ readonly type: string
21
+ readonly timeStamp: number
22
+ readonly bubbles: boolean
23
+ readonly cancelable: boolean
24
+
25
+ private _target: EventTarget | null = null
26
+ private _currentTarget: EventTarget | null = null
27
+ private _eventPhase: EventPhase = 'none'
28
+ private _propagationStopped = false
29
+ private _defaultPrevented = false
30
+
31
+ constructor(type: string, init?: TerminalEventInit) {
32
+ super()
33
+ this.type = type
34
+ this.timeStamp = performance.now()
35
+ this.bubbles = init?.bubbles ?? true
36
+ this.cancelable = init?.cancelable ?? true
37
+ }
38
+
39
+ get target(): EventTarget | null {
40
+ return this._target
41
+ }
42
+
43
+ get currentTarget(): EventTarget | null {
44
+ return this._currentTarget
45
+ }
46
+
47
+ get eventPhase(): EventPhase {
48
+ return this._eventPhase
49
+ }
50
+
51
+ get defaultPrevented(): boolean {
52
+ return this._defaultPrevented
53
+ }
54
+
55
+ stopPropagation(): void {
56
+ this._propagationStopped = true
57
+ }
58
+
59
+ override stopImmediatePropagation(): void {
60
+ super.stopImmediatePropagation()
61
+ this._propagationStopped = true
62
+ }
63
+
64
+ preventDefault(): void {
65
+ if (this.cancelable) {
66
+ this._defaultPrevented = true
67
+ }
68
+ }
69
+
70
+ // -- Internal setters used by the Dispatcher
71
+
72
+ /** @internal */
73
+ _setTarget(target: EventTarget): void {
74
+ this._target = target
75
+ }
76
+
77
+ /** @internal */
78
+ _setCurrentTarget(target: EventTarget | null): void {
79
+ this._currentTarget = target
80
+ }
81
+
82
+ /** @internal */
83
+ _setEventPhase(phase: EventPhase): void {
84
+ this._eventPhase = phase
85
+ }
86
+
87
+ /** @internal */
88
+ _isPropagationStopped(): boolean {
89
+ return this._propagationStopped
90
+ }
91
+
92
+ /** @internal */
93
+ _isImmediatePropagationStopped(): boolean {
94
+ return this.didStopImmediatePropagation()
95
+ }
96
+
97
+ /**
98
+ * Hook for subclasses to do per-node setup before each handler fires.
99
+ * Default is a no-op.
100
+ */
101
+ _prepareForTarget(_target: EventTarget): void {}
102
+ }
103
+
104
+ export type EventTarget = {
105
+ parentNode: EventTarget | undefined
106
+ _eventHandlers?: Record<string, unknown>
107
+ }
@@ -0,0 +1,19 @@
1
+ import { Event } from './event.js'
2
+
3
+ export type TerminalFocusEventType = 'terminalfocus' | 'terminalblur'
4
+
5
+ /**
6
+ * Event fired when the terminal window gains or loses focus.
7
+ *
8
+ * Uses DECSET 1004 focus reporting - the terminal sends:
9
+ * - CSI I (\x1b[I) when the terminal gains focus
10
+ * - CSI O (\x1b[O) when the terminal loses focus
11
+ */
12
+ export class TerminalFocusEvent extends Event {
13
+ readonly type: TerminalFocusEventType
14
+
15
+ constructor(type: TerminalFocusEventType) {
16
+ super()
17
+ this.type = type
18
+ }
19
+ }
@@ -0,0 +1,219 @@
1
+ import type { DOMElement } from './dom.js'
2
+ import { FocusEvent } from './events/focus-event.js'
3
+
4
+ const MAX_FOCUS_STACK = 32
5
+
6
+ /**
7
+ * DOM-like focus manager for the Ink terminal UI.
8
+ *
9
+ * Pure state — tracks activeElement and a focus stack. Has no reference
10
+ * to the tree; callers pass the root when tree walks are needed.
11
+ *
12
+ * Stored on the root DOMElement so any node can reach it by walking
13
+ * parentNode (like browser's `node.ownerDocument`).
14
+ */
15
+ export class FocusManager {
16
+ activeElement: DOMElement | null = null
17
+ private dispatchFocusEvent: (target: DOMElement, event: FocusEvent) => boolean
18
+ private enabled = true
19
+ private focusStack: DOMElement[] = []
20
+
21
+ constructor(dispatchFocusEvent: (target: DOMElement, event: FocusEvent) => boolean) {
22
+ this.dispatchFocusEvent = dispatchFocusEvent
23
+ }
24
+
25
+ focus(node: DOMElement): void {
26
+ if (node === this.activeElement) {
27
+ return
28
+ }
29
+
30
+ if (!this.enabled) {
31
+ return
32
+ }
33
+
34
+ const previous = this.activeElement
35
+
36
+ if (previous) {
37
+ // Deduplicate before pushing to prevent unbounded growth from Tab cycling
38
+ const idx = this.focusStack.indexOf(previous)
39
+
40
+ if (idx !== -1) {
41
+ this.focusStack.splice(idx, 1)
42
+ }
43
+
44
+ this.focusStack.push(previous)
45
+
46
+ if (this.focusStack.length > MAX_FOCUS_STACK) {
47
+ this.focusStack.shift()
48
+ }
49
+
50
+ this.dispatchFocusEvent(previous, new FocusEvent('blur', node))
51
+ }
52
+
53
+ this.activeElement = node
54
+ this.dispatchFocusEvent(node, new FocusEvent('focus', previous))
55
+ }
56
+
57
+ blur(): void {
58
+ if (!this.activeElement) {
59
+ return
60
+ }
61
+
62
+ const previous = this.activeElement
63
+ this.activeElement = null
64
+ this.dispatchFocusEvent(previous, new FocusEvent('blur', null))
65
+ }
66
+
67
+ /**
68
+ * Called by the reconciler when a node is removed from the tree.
69
+ * Handles both the exact node and any focused descendant within
70
+ * the removed subtree. Dispatches blur and restores focus from stack.
71
+ */
72
+ handleNodeRemoved(node: DOMElement, root: DOMElement): void {
73
+ // Remove the node and any descendants from the stack
74
+ this.focusStack = this.focusStack.filter(n => n !== node && isInTree(n, root))
75
+
76
+ // Check if activeElement is the removed node OR a descendant
77
+ if (!this.activeElement) {
78
+ return
79
+ }
80
+
81
+ if (this.activeElement !== node && isInTree(this.activeElement, root)) {
82
+ return
83
+ }
84
+
85
+ const removed = this.activeElement
86
+ this.activeElement = null
87
+ this.dispatchFocusEvent(removed, new FocusEvent('blur', null))
88
+
89
+ // Restore focus to the most recent still-mounted element
90
+ while (this.focusStack.length > 0) {
91
+ const candidate = this.focusStack.pop()!
92
+
93
+ if (isInTree(candidate, root)) {
94
+ this.activeElement = candidate
95
+ this.dispatchFocusEvent(candidate, new FocusEvent('focus', removed))
96
+
97
+ return
98
+ }
99
+ }
100
+ }
101
+
102
+ handleAutoFocus(node: DOMElement): void {
103
+ this.focus(node)
104
+ }
105
+
106
+ handleClickFocus(node: DOMElement): void {
107
+ const tabIndex = node.attributes['tabIndex']
108
+
109
+ if (typeof tabIndex !== 'number') {
110
+ return
111
+ }
112
+
113
+ this.focus(node)
114
+ }
115
+
116
+ enable(): void {
117
+ this.enabled = true
118
+ }
119
+
120
+ disable(): void {
121
+ this.enabled = false
122
+ }
123
+
124
+ focusNext(root: DOMElement): void {
125
+ this.moveFocus(1, root)
126
+ }
127
+
128
+ focusPrevious(root: DOMElement): void {
129
+ this.moveFocus(-1, root)
130
+ }
131
+
132
+ private moveFocus(direction: 1 | -1, root: DOMElement): void {
133
+ if (!this.enabled) {
134
+ return
135
+ }
136
+
137
+ const tabbable = collectTabbable(root)
138
+
139
+ if (tabbable.length === 0) {
140
+ return
141
+ }
142
+
143
+ const currentIndex = this.activeElement ? tabbable.indexOf(this.activeElement) : -1
144
+
145
+ const nextIndex =
146
+ currentIndex === -1
147
+ ? direction === 1
148
+ ? 0
149
+ : tabbable.length - 1
150
+ : (currentIndex + direction + tabbable.length) % tabbable.length
151
+
152
+ const next = tabbable[nextIndex]
153
+
154
+ if (next) {
155
+ this.focus(next)
156
+ }
157
+ }
158
+ }
159
+
160
+ function collectTabbable(root: DOMElement): DOMElement[] {
161
+ const result: DOMElement[] = []
162
+ walkTree(root, result)
163
+
164
+ return result
165
+ }
166
+
167
+ function walkTree(node: DOMElement, result: DOMElement[]): void {
168
+ const tabIndex = node.attributes['tabIndex']
169
+
170
+ if (typeof tabIndex === 'number' && tabIndex >= 0) {
171
+ result.push(node)
172
+ }
173
+
174
+ for (const child of node.childNodes) {
175
+ if (child.nodeName !== '#text') {
176
+ walkTree(child, result)
177
+ }
178
+ }
179
+ }
180
+
181
+ function isInTree(node: DOMElement, root: DOMElement): boolean {
182
+ let current: DOMElement | undefined = node
183
+
184
+ while (current) {
185
+ if (current === root) {
186
+ return true
187
+ }
188
+
189
+ current = current.parentNode
190
+ }
191
+
192
+ return false
193
+ }
194
+
195
+ /**
196
+ * Walk up to root and return it. The root is the node that holds
197
+ * the FocusManager — like browser's `node.getRootNode()`.
198
+ */
199
+ export function getRootNode(node: DOMElement): DOMElement {
200
+ let current: DOMElement | undefined = node
201
+
202
+ while (current) {
203
+ if (current.focusManager) {
204
+ return current
205
+ }
206
+
207
+ current = current.parentNode
208
+ }
209
+
210
+ throw new Error('Node is not in a tree with a FocusManager')
211
+ }
212
+
213
+ /**
214
+ * Walk up to root and return its FocusManager.
215
+ * Like browser's `node.ownerDocument` — focus belongs to the root.
216
+ */
217
+ export function getFocusManager(node: DOMElement): FocusManager {
218
+ return getRootNode(node).focusManager!
219
+ }
@@ -0,0 +1,124 @@
1
+ import type { Cursor } from './cursor.js'
2
+ import type { Size } from './layout/geometry.js'
3
+ import type { ScrollHint } from './render-node-to-output.js'
4
+ import { type CharPool, createScreen, type HyperlinkPool, type Screen, type StylePool } from './screen.js'
5
+
6
+ export type Frame = {
7
+ readonly screen: Screen
8
+ readonly viewport: Size
9
+ readonly cursor: Cursor
10
+ /** DECSTBM scroll optimization hint (alt-screen only, null otherwise). */
11
+ readonly scrollHint?: ScrollHint | null
12
+ /** A ScrollBox has remaining pendingScrollDelta — schedule another frame. */
13
+ readonly scrollDrainPending?: boolean
14
+ /** Absolute overlay moved/resized — schedule corrective frame without prevScreen. */
15
+ readonly absoluteOverlayMoved?: boolean
16
+ }
17
+
18
+ export function emptyFrame(
19
+ rows: number,
20
+ columns: number,
21
+ stylePool: StylePool,
22
+ charPool: CharPool,
23
+ hyperlinkPool: HyperlinkPool
24
+ ): Frame {
25
+ return {
26
+ screen: createScreen(0, 0, stylePool, charPool, hyperlinkPool),
27
+ viewport: { width: columns, height: rows },
28
+ cursor: { x: 0, y: 0, visible: true }
29
+ }
30
+ }
31
+
32
+ export type FlickerReason = 'resize' | 'offscreen' | 'clear'
33
+
34
+ export type FrameEvent = {
35
+ durationMs: number
36
+ /** Phase breakdown in ms + patch count. Populated when the ink instance
37
+ * has frame-timing instrumentation enabled (via onFrame wiring). */
38
+ phases?: {
39
+ /** createRenderer output: DOM → yoga layout → screen buffer */
40
+ renderer: number
41
+ /** LogUpdate.render(): screen diff → Patch[] (the hot path this PR optimizes) */
42
+ diff: number
43
+ /** optimize(): patch merge/dedupe */
44
+ optimize: number
45
+ /** writeDiffToTerminal(): serialize patches → ANSI → stdout */
46
+ write: number
47
+ /** Pre-optimize patch count (proxy for how much changed this frame) */
48
+ patches: number
49
+ /** Post-optimize patch count. */
50
+ optimizedPatches: number
51
+ /** Bytes written to stdout this frame. */
52
+ writeBytes: number
53
+ /** Whether stdout.write returned false. */
54
+ backpressure: boolean
55
+ /** Previous stdout.write callback latency; 0 if drained before next frame. */
56
+ prevFrameDrainMs: number
57
+ /** yoga calculateLayout() time (runs in resetAfterCommit, before onRender) */
58
+ yoga: number
59
+ /** React reconcile time: scrollMutated → resetAfterCommit. 0 if no commit. */
60
+ commit: number
61
+ /** layoutNode() calls this frame (recursive, includes cache-hit returns) */
62
+ yogaVisited: number
63
+ /** measureFunc (text wrap/width) calls — the expensive part */
64
+ yogaMeasured: number
65
+ /** early returns via _hasL single-slot cache */
66
+ yogaCacheHits: number
67
+ /** total yoga Node instances alive (create - free). Growth = leak. */
68
+ yogaLive: number
69
+ }
70
+ flickers: Array<{
71
+ desiredHeight: number
72
+ availableHeight: number
73
+ reason: FlickerReason
74
+ }>
75
+ }
76
+
77
+ export type Patch =
78
+ | { type: 'stdout'; content: string }
79
+ | { type: 'clear'; count: number }
80
+ | {
81
+ type: 'clearTerminal'
82
+ reason: FlickerReason
83
+ // Populated by log-update when a scrollback diff triggers the reset.
84
+ debug?: { triggerY: number; prevLine: string; nextLine: string }
85
+ }
86
+ | { type: 'cursorHide' }
87
+ | { type: 'cursorShow' }
88
+ | { type: 'cursorMove'; x: number; y: number }
89
+ | { type: 'cursorTo'; col: number }
90
+ | { type: 'carriageReturn' }
91
+ | { type: 'hyperlink'; uri: string }
92
+ // Pre-serialized style transition string from StylePool.transition() —
93
+ // cached by (fromId, toId), zero allocations after warmup.
94
+ | { type: 'styleStr'; str: string }
95
+
96
+ export type Diff = Patch[]
97
+
98
+ /**
99
+ * Determines whether the screen should be cleared based on the current and previous frame.
100
+ * Returns the reason for clearing, or undefined if no clear is needed.
101
+ *
102
+ * Screen clearing is triggered when:
103
+ * 1. Terminal has been resized (viewport dimensions changed) → 'resize'
104
+ * 2. Current frame screen height exceeds available terminal rows → 'offscreen'
105
+ * 3. Previous frame screen height exceeded available terminal rows → 'offscreen'
106
+ */
107
+ export function shouldClearScreen(prevFrame: Frame, frame: Frame): FlickerReason | undefined {
108
+ const didResize =
109
+ frame.viewport.height !== prevFrame.viewport.height || frame.viewport.width !== prevFrame.viewport.width
110
+
111
+ if (didResize) {
112
+ return 'resize'
113
+ }
114
+
115
+ const currentFrameOverflows = frame.screen.height >= frame.viewport.height
116
+
117
+ const previousFrameOverflowed = prevFrame.screen.height >= prevFrame.viewport.height
118
+
119
+ if (currentFrameOverflows || previousFrameOverflowed) {
120
+ return 'offscreen'
121
+ }
122
+
123
+ return undefined
124
+ }
@@ -0,0 +1,27 @@
1
+ import { LayoutEdge, type LayoutNode } from './layout/node.js'
2
+
3
+ /**
4
+ * Returns the yoga node's content width (computed width minus padding and
5
+ * border).
6
+ *
7
+ * Warning: can return a value WIDER than the parent container. In a
8
+ * column-direction flex parent, width is the cross axis — align-items:
9
+ * stretch never shrinks children below their intrinsic size, so the text
10
+ * node overflows (standard CSS behavior). Yoga measures leaf nodes in two
11
+ * passes: the AtMost pass determines width, the Exactly pass determines
12
+ * height. getComputedWidth() reflects the wider AtMost result while
13
+ * getComputedHeight() reflects the narrower Exactly result. Callers that
14
+ * use this for wrapping should clamp to actual available screen space so
15
+ * the rendered line count stays consistent with the layout height.
16
+ */
17
+ const getMaxWidth = (yogaNode: LayoutNode): number => {
18
+ return (
19
+ yogaNode.getComputedWidth() -
20
+ yogaNode.getComputedPadding(LayoutEdge.Left) -
21
+ yogaNode.getComputedPadding(LayoutEdge.Right) -
22
+ yogaNode.getComputedBorder(LayoutEdge.Left) -
23
+ yogaNode.getComputedBorder(LayoutEdge.Right)
24
+ )
25
+ }
26
+
27
+ export default getMaxWidth
@@ -0,0 +1,38 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import { appendChildNode, createNode } from './dom.js'
4
+ import { dispatchClick, hitTest } from './hit-test.js'
5
+ import { nodeCache } from './node-cache.js'
6
+
7
+ const rect = (node: ReturnType<typeof createNode>, x: number, y: number, width: number, height: number) => {
8
+ nodeCache.set(node, { x, y, width, height })
9
+ }
10
+
11
+ describe('hit-test', () => {
12
+ it('hits absolutely positioned children that paint outside their parent rect', () => {
13
+ const root = createNode('ink-root')
14
+ const parent = createNode('ink-box')
15
+ const wrapper = createNode('ink-box')
16
+ const overlay = createNode('ink-box')
17
+ const row = createNode('ink-box')
18
+ const seen: string[] = []
19
+
20
+ appendChildNode(root, parent)
21
+ appendChildNode(parent, wrapper)
22
+ appendChildNode(wrapper, overlay)
23
+ appendChildNode(overlay, row)
24
+
25
+ overlay.style.position = 'absolute'
26
+ row._eventHandlers = { onClick: () => seen.push('row') }
27
+
28
+ rect(root, 0, 0, 120, 40)
29
+ rect(parent, 0, 30, 120, 1)
30
+ rect(wrapper, 0, 30, 120, 1)
31
+ rect(overlay, 0, 20, 96, 6)
32
+ rect(row, 1, 22, 80, 1)
33
+
34
+ expect(hitTest(root, 2, 22)).toBe(row)
35
+ expect(dispatchClick(root, 2, 22)).toBe(true)
36
+ expect(seen).toEqual(['row'])
37
+ })
38
+ })