@deepseek-harness-tui/dsh-tui 0.8.7 → 0.9.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 (229) hide show
  1. package/README.md +29 -10
  2. package/bin/dsh-tui.js +1 -1
  3. package/lib/types/commands.d.ts.map +1 -1
  4. package/lib/types/commands.js +4 -2
  5. package/lib/types/components/ActivityPicker.d.ts +4 -1
  6. package/lib/types/components/ActivityPicker.d.ts.map +1 -1
  7. package/lib/types/components/ActivityPicker.js +2 -2
  8. package/lib/types/components/BtwPanel.d.ts.map +1 -1
  9. package/lib/types/components/BtwPanel.js +1 -1
  10. package/lib/types/components/Chat/SubagentMessage.d.ts +2 -1
  11. package/lib/types/components/Chat/SubagentMessage.d.ts.map +1 -1
  12. package/lib/types/components/Chat/SubagentMessage.js +11 -3
  13. package/lib/types/components/CommandSuggestions.d.ts +21 -4
  14. package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
  15. package/lib/types/components/CommandSuggestions.js +41 -14
  16. package/lib/types/components/EffortSlider.d.ts +4 -1
  17. package/lib/types/components/EffortSlider.d.ts.map +1 -1
  18. package/lib/types/components/EffortSlider.js +4 -2
  19. package/lib/types/components/ExtensionDialog.js +6 -2
  20. package/lib/types/components/FileSuggestions.d.ts +26 -5
  21. package/lib/types/components/FileSuggestions.d.ts.map +1 -1
  22. package/lib/types/components/FileSuggestions.js +53 -16
  23. package/lib/types/components/GoalTodoPanel.d.ts +26 -2
  24. package/lib/types/components/GoalTodoPanel.d.ts.map +1 -1
  25. package/lib/types/components/GoalTodoPanel.js +86 -17
  26. package/lib/types/components/HelpMenu.d.ts +7 -1
  27. package/lib/types/components/HelpMenu.d.ts.map +1 -1
  28. package/lib/types/components/HelpMenu.js +12 -4
  29. package/lib/types/components/HistorySearchDialog.d.ts +4 -1
  30. package/lib/types/components/HistorySearchDialog.d.ts.map +1 -1
  31. package/lib/types/components/HistorySearchDialog.js +2 -2
  32. package/lib/types/components/LangPicker.d.ts +14 -0
  33. package/lib/types/components/LangPicker.d.ts.map +1 -0
  34. package/lib/types/components/LangPicker.js +17 -0
  35. package/lib/types/components/LoadedContextPanel.d.ts.map +1 -1
  36. package/lib/types/components/LoadedContextPanel.js +3 -1
  37. package/lib/types/components/LogoV2.d.ts +5 -1
  38. package/lib/types/components/LogoV2.d.ts.map +1 -1
  39. package/lib/types/components/LogoV2.js +12 -3
  40. package/lib/types/components/Markdown.d.ts.map +1 -1
  41. package/lib/types/components/Markdown.js +12 -3
  42. package/lib/types/components/MessageList.d.ts +43 -2
  43. package/lib/types/components/MessageList.d.ts.map +1 -1
  44. package/lib/types/components/MessageList.js +553 -41
  45. package/lib/types/components/ModelPicker.d.ts +4 -1
  46. package/lib/types/components/ModelPicker.d.ts.map +1 -1
  47. package/lib/types/components/ModelPicker.js +2 -2
  48. package/lib/types/components/PermissionsPicker.d.ts +21 -0
  49. package/lib/types/components/PermissionsPicker.d.ts.map +1 -0
  50. package/lib/types/components/PermissionsPicker.js +27 -0
  51. package/lib/types/components/PlanPicker.d.ts +15 -0
  52. package/lib/types/components/PlanPicker.d.ts.map +1 -0
  53. package/lib/types/components/PlanPicker.js +18 -0
  54. package/lib/types/components/PresetPicker.d.ts +4 -1
  55. package/lib/types/components/PresetPicker.d.ts.map +1 -1
  56. package/lib/types/components/PresetPicker.js +2 -2
  57. package/lib/types/components/PromptInput.d.ts +4 -3
  58. package/lib/types/components/PromptInput.d.ts.map +1 -1
  59. package/lib/types/components/PromptInput.js +273 -50
  60. package/lib/types/components/RewindPicker.d.ts +12 -1
  61. package/lib/types/components/RewindPicker.d.ts.map +1 -1
  62. package/lib/types/components/RewindPicker.js +6 -4
  63. package/lib/types/components/ScrollbarGutter.d.ts +28 -0
  64. package/lib/types/components/ScrollbarGutter.d.ts.map +1 -0
  65. package/lib/types/components/ScrollbarGutter.js +68 -0
  66. package/lib/types/components/Select.d.ts +8 -1
  67. package/lib/types/components/Select.d.ts.map +1 -1
  68. package/lib/types/components/Select.js +4 -2
  69. package/lib/types/components/SkillsPicker.d.ts +4 -1
  70. package/lib/types/components/SkillsPicker.d.ts.map +1 -1
  71. package/lib/types/components/SkillsPicker.js +2 -2
  72. package/lib/types/components/SubagentCard.d.ts +2 -1
  73. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  74. package/lib/types/components/SubagentCard.js +6 -1
  75. package/lib/types/components/SubagentDashboard.d.ts +4 -0
  76. package/lib/types/components/SubagentDashboard.d.ts.map +1 -1
  77. package/lib/types/components/SubagentDashboard.js +9 -1
  78. package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
  79. package/lib/types/components/SubagentDetailScene.js +5 -4
  80. package/lib/types/components/SuggestionCard.d.ts +63 -0
  81. package/lib/types/components/SuggestionCard.d.ts.map +1 -0
  82. package/lib/types/components/SuggestionCard.js +77 -0
  83. package/lib/types/components/ThemePicker.d.ts +4 -1
  84. package/lib/types/components/ThemePicker.d.ts.map +1 -1
  85. package/lib/types/components/ThemePicker.js +2 -2
  86. package/lib/types/components/ThinkingToggle.d.ts +4 -1
  87. package/lib/types/components/ThinkingToggle.d.ts.map +1 -1
  88. package/lib/types/components/ThinkingToggle.js +2 -2
  89. package/lib/types/components/TimelineRail.d.ts +53 -0
  90. package/lib/types/components/TimelineRail.d.ts.map +1 -0
  91. package/lib/types/components/TimelineRail.js +190 -0
  92. package/lib/types/components/WorkspaceFlowPicker.d.ts +6 -1
  93. package/lib/types/components/WorkspaceFlowPicker.d.ts.map +1 -1
  94. package/lib/types/components/WorkspaceFlowPicker.js +4 -2
  95. package/lib/types/components/WorkspaceMenuPicker.d.ts +19 -0
  96. package/lib/types/components/WorkspaceMenuPicker.d.ts.map +1 -0
  97. package/lib/types/components/WorkspaceMenuPicker.js +19 -0
  98. package/lib/types/components/WorkspacePicker.d.ts +4 -1
  99. package/lib/types/components/WorkspacePicker.d.ts.map +1 -1
  100. package/lib/types/components/WorkspacePicker.js +2 -2
  101. package/lib/types/components/approvals/ApprovalPanel.d.ts.map +1 -1
  102. package/lib/types/components/approvals/ApprovalPanel.js +5 -1
  103. package/lib/types/components/design-system/ListItem.d.ts +8 -1
  104. package/lib/types/components/design-system/ListItem.d.ts.map +1 -1
  105. package/lib/types/components/design-system/ListItem.js +8 -3
  106. package/lib/types/components/messages/AssistantTextMessage.d.ts +5 -2
  107. package/lib/types/components/messages/AssistantTextMessage.d.ts.map +1 -1
  108. package/lib/types/components/messages/AssistantTextMessage.js +6 -2
  109. package/lib/types/components/messages/AssistantThinkingMessage.d.ts +2 -1
  110. package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
  111. package/lib/types/components/messages/AssistantThinkingMessage.js +10 -4
  112. package/lib/types/components/messages/AssistantToolUseMessage.d.ts +8 -1
  113. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  114. package/lib/types/components/messages/AssistantToolUseMessage.js +4 -2
  115. package/lib/types/components/messages/UserPromptMessage.d.ts +2 -1
  116. package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
  117. package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
  118. package/lib/types/components/questions/AskUserQuestionPanel.js +34 -2
  119. package/lib/types/components/questions/PlanReviewPanel.d.ts.map +1 -1
  120. package/lib/types/components/questions/PlanReviewPanel.js +13 -2
  121. package/lib/types/components/sessions/SessionListRow.d.ts +4 -1
  122. package/lib/types/components/sessions/SessionListRow.d.ts.map +1 -1
  123. package/lib/types/components/sessions/SessionListRow.js +4 -2
  124. package/lib/types/components/trajectory/HotspotView.d.ts +7 -1
  125. package/lib/types/components/trajectory/HotspotView.d.ts.map +1 -1
  126. package/lib/types/components/trajectory/HotspotView.js +8 -2
  127. package/lib/types/components/trajectory/Ledger.d.ts +9 -1
  128. package/lib/types/components/trajectory/Ledger.d.ts.map +1 -1
  129. package/lib/types/components/trajectory/Ledger.js +23 -5
  130. package/lib/types/components/trajectory/WaveBand.d.ts +10 -1
  131. package/lib/types/components/trajectory/WaveBand.d.ts.map +1 -1
  132. package/lib/types/components/trajectory/WaveBand.js +7 -2
  133. package/lib/types/dsh-adapter/channel.d.ts +27 -6
  134. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  135. package/lib/types/dsh-adapter/channel.js +432 -66
  136. package/lib/types/dsh-adapter/contract.d.ts +58 -18
  137. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  138. package/lib/types/dsh-adapter/contract.js +124 -36
  139. package/lib/types/dsh-adapter/index.d.ts +10 -2
  140. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  141. package/lib/types/dsh-adapter/index.js +10 -13
  142. package/lib/types/dsh-adapter/plugin.d.ts +0 -9
  143. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  144. package/lib/types/dsh-adapter/plugin.js +136 -6
  145. package/lib/types/i18n.d.ts +194 -16
  146. package/lib/types/i18n.d.ts.map +1 -1
  147. package/lib/types/i18n.js +73 -10
  148. package/lib/types/ink/components/AlternateScreen.d.ts.map +1 -1
  149. package/lib/types/ink/components/AlternateScreen.js +13 -1
  150. package/lib/types/ink/components/App.d.ts +12 -1
  151. package/lib/types/ink/components/App.d.ts.map +1 -1
  152. package/lib/types/ink/components/App.js +101 -4
  153. package/lib/types/ink/components/ClockContext.d.ts.map +1 -1
  154. package/lib/types/ink/components/ClockContext.js +2 -0
  155. package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
  156. package/lib/types/ink/components/ScrollBox.js +170 -91
  157. package/lib/types/ink/constants.d.ts +9 -0
  158. package/lib/types/ink/constants.d.ts.map +1 -1
  159. package/lib/types/ink/constants.js +9 -0
  160. package/lib/types/ink/events/click-event.d.ts +7 -16
  161. package/lib/types/ink/events/click-event.d.ts.map +1 -1
  162. package/lib/types/ink/events/click-event.js +16 -19
  163. package/lib/types/ink/events/event-handlers.d.ts +11 -1
  164. package/lib/types/ink/events/event-handlers.d.ts.map +1 -1
  165. package/lib/types/ink/events/event-handlers.js +2 -0
  166. package/lib/types/ink/events/input-event.d.ts +9 -0
  167. package/lib/types/ink/events/input-event.d.ts.map +1 -1
  168. package/lib/types/ink/events/input-event.js +4 -0
  169. package/lib/types/ink/events/pointer-event.d.ts +61 -0
  170. package/lib/types/ink/events/pointer-event.d.ts.map +1 -0
  171. package/lib/types/ink/events/pointer-event.js +61 -0
  172. package/lib/types/ink/events/wheel-event.d.ts +17 -0
  173. package/lib/types/ink/events/wheel-event.d.ts.map +1 -0
  174. package/lib/types/ink/events/wheel-event.js +20 -0
  175. package/lib/types/ink/geometry-trace.d.ts +51 -0
  176. package/lib/types/ink/geometry-trace.d.ts.map +1 -0
  177. package/lib/types/ink/geometry-trace.js +83 -0
  178. package/lib/types/ink/hit-test.d.ts +56 -1
  179. package/lib/types/ink/hit-test.d.ts.map +1 -1
  180. package/lib/types/ink/hit-test.js +146 -8
  181. package/lib/types/ink/ink.d.ts +58 -1
  182. package/lib/types/ink/ink.d.ts.map +1 -1
  183. package/lib/types/ink/ink.js +268 -52
  184. package/lib/types/ink/node-cache.d.ts +5 -0
  185. package/lib/types/ink/node-cache.d.ts.map +1 -1
  186. package/lib/types/ink/parse-keypress.d.ts +8 -0
  187. package/lib/types/ink/parse-keypress.d.ts.map +1 -1
  188. package/lib/types/ink/parse-keypress.js +101 -12
  189. package/lib/types/ink/render-node-to-output.d.ts +16 -3
  190. package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
  191. package/lib/types/ink/render-node-to-output.js +144 -25
  192. package/lib/types/ink/selection.d.ts +29 -4
  193. package/lib/types/ink/selection.d.ts.map +1 -1
  194. package/lib/types/ink/selection.js +41 -5
  195. package/lib/types/ink/timeline-rail.d.ts +138 -0
  196. package/lib/types/ink/timeline-rail.d.ts.map +1 -0
  197. package/lib/types/ink/timeline-rail.js +179 -0
  198. package/lib/types/ink/wrap-text.d.ts.map +1 -1
  199. package/lib/types/ink/wrap-text.js +47 -5
  200. package/lib/types/screens/Chat.d.ts.map +1 -1
  201. package/lib/types/screens/Chat.js +819 -337
  202. package/lib/types/screens/SessionBrowser.d.ts.map +1 -1
  203. package/lib/types/screens/SessionBrowser.js +56 -29
  204. package/lib/types/screens/Settings.d.ts.map +1 -1
  205. package/lib/types/screens/Settings.js +64 -22
  206. package/lib/types/screens/StatusLine.d.ts +2 -1
  207. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  208. package/lib/types/screens/StatusLine.js +17 -1
  209. package/lib/types/screens/TrajectoryScene.d.ts.map +1 -1
  210. package/lib/types/screens/TrajectoryScene.js +81 -14
  211. package/lib/types/screens/chatOverlay.d.ts +221 -0
  212. package/lib/types/screens/chatOverlay.d.ts.map +1 -0
  213. package/lib/types/screens/chatOverlay.js +114 -0
  214. package/lib/types/tips.d.ts.map +1 -1
  215. package/lib/types/tips.js +64 -10
  216. package/lib/types/tuiDisplayPrefs.d.ts +15 -0
  217. package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
  218. package/lib/types/tuiDisplayPrefs.js +9 -0
  219. package/lib/types/utils/debug.d.ts +10 -0
  220. package/lib/types/utils/debug.d.ts.map +1 -1
  221. package/lib/types/utils/debug.js +24 -0
  222. package/lib/types/utils/fileSuggestions.d.ts +19 -0
  223. package/lib/types/utils/fileSuggestions.d.ts.map +1 -0
  224. package/lib/types/utils/fileSuggestions.js +40 -0
  225. package/lib/types/utils/mentions.d.ts.map +1 -1
  226. package/lib/types/utils/mentions.js +3 -1
  227. package/lib/types/utils/paths.d.ts.map +1 -1
  228. package/lib/types/utils/paths.js +1 -0
  229. package/package.json +69 -66
@@ -1,7 +1,9 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useImperativeHandle, useRef, useState } from 'react';
2
+ import { useCallback, useImperativeHandle, useRef, useState } from 'react';
3
+ import { FRAME_INTERVAL_MS } from '../constants.js';
3
4
  import { markScrollActivity } from '../../bootstrap/state.js';
4
5
  import { markDirty, scheduleRenderFrom } from '../dom.js';
6
+ import { noteFrameCause } from '../geometry-trace.js';
5
7
  import { markCommitStart } from '../reconciler.js';
6
8
  import Box from './Box.js';
7
9
  /**
@@ -27,18 +29,56 @@ function ScrollBox({ children, ref, stickyScroll, ...style }) {
27
29
  const [, forceRender] = useState(0);
28
30
  const listenersRef = useRef(new Set());
29
31
  const renderQueuedRef = useRef(false);
32
+ // The imperative handle, kept in a ref so the onWheel handler below can
33
+ // call scrollBy through the full public path (clamp bounds, sticky
34
+ // clearing, subscriber notify) instead of duplicating its logic.
35
+ const handleRef = useRef(null);
30
36
  const notify = () => {
31
37
  for (const l of listenersRef.current)
32
38
  l();
33
39
  };
40
+ // Input-edge intent coalescing (Qwen Code's 16ms wheel merge, Crush's
41
+ // pre-queue filter): subscribers drive React state (MessageList's mount
42
+ // window, Chat's sticky flag, the timeline rail), so notifying per wheel
43
+ // EVENT runs a full React commit per event — a fast flick is 10-30
44
+ // events, each re-running the offsets/window/timeline loops on a big
45
+ // session. The scrollTop mutation and the ink render are already
46
+ // frame-throttled; this aligns the React commits to the same frame
47
+ // budget. Both edges defer to a microtask: the remaining input events of
48
+ // the same stdin batch then land BEFORE any commit, and one commit
49
+ // covers the whole batch (the sync leading edge used to run a full
50
+ // commit inside the wheel dispatch itself — pure input latency).
51
+ const notifyQueuedRef = useRef(false);
52
+ const lastNotifyAtRef = useRef(-Infinity);
53
+ const notifyCoalesced = () => {
54
+ const since = performance.now() - lastNotifyAtRef.current;
55
+ if (!notifyQueuedRef.current && since >= FRAME_INTERVAL_MS) {
56
+ notifyQueuedRef.current = true;
57
+ lastNotifyAtRef.current = performance.now();
58
+ queueMicrotask(() => {
59
+ notifyQueuedRef.current = false;
60
+ notify();
61
+ });
62
+ return;
63
+ }
64
+ if (notifyQueuedRef.current)
65
+ return;
66
+ notifyQueuedRef.current = true;
67
+ setTimeout(() => {
68
+ notifyQueuedRef.current = false;
69
+ lastNotifyAtRef.current = performance.now();
70
+ notify();
71
+ }, Math.max(0, FRAME_INTERVAL_MS - since));
72
+ };
34
73
  function scrollMutated(el) {
35
74
  // Signal background intervals (IDE poll, LSP poll, GCS fetch, orphan
36
75
  // check) to skip their next tick — they compete for the event loop and
37
76
  // contributed to 1402ms max frame gaps during scroll drain.
38
77
  markScrollActivity();
78
+ noteFrameCause('scroll');
39
79
  markDirty(el);
40
80
  markCommitStart();
41
- notify();
81
+ notifyCoalesced();
42
82
  if (renderQueuedRef.current)
43
83
  return;
44
84
  renderQueuedRef.current = true;
@@ -47,99 +87,138 @@ function ScrollBox({ children, ref, stickyScroll, ...style }) {
47
87
  scheduleRenderFrom(el);
48
88
  });
49
89
  }
50
- useImperativeHandle(ref, () => ({
51
- scrollTo(y) {
52
- const el = domRef.current;
53
- if (!el)
54
- return;
55
- // Explicit false overrides the DOM attribute so manual scroll
56
- // breaks stickiness. Render code checks ?? precedence.
57
- el.stickyScroll = false;
58
- el.pendingScrollDelta = undefined;
59
- el.scrollAnchor = undefined;
60
- el.scrollTop = Math.max(0, Math.floor(y));
61
- scrollMutated(el);
62
- },
63
- scrollToElement(el, offset = 0) {
64
- const box = domRef.current;
65
- if (!box)
66
- return;
67
- box.stickyScroll = false;
68
- box.pendingScrollDelta = undefined;
69
- box.scrollAnchor = {
70
- el,
71
- offset
72
- };
73
- scrollMutated(box);
74
- },
75
- scrollBy(dy) {
76
- const el = domRef.current;
77
- if (!el)
78
- return;
79
- el.stickyScroll = false;
80
- // Wheel input cancels any in-flight anchor seek — user override.
81
- el.scrollAnchor = undefined;
82
- // Accumulate in pendingScrollDelta; renderer drains it at a capped
83
- // rate so fast flicks show intermediate frames. Pure accumulator:
84
- // scroll-up followed by scroll-down naturally cancels.
85
- el.pendingScrollDelta = (el.pendingScrollDelta ?? 0) + Math.floor(dy);
86
- scrollMutated(el);
87
- },
88
- scrollToBottom() {
89
- const el = domRef.current;
90
- if (!el)
91
- return;
92
- el.pendingScrollDelta = undefined;
93
- el.stickyScroll = true;
94
- markDirty(el);
95
- notify();
96
- forceRender(n => n + 1);
97
- },
98
- getScrollTop() {
99
- return domRef.current?.scrollTop ?? 0;
100
- },
101
- getPendingDelta() {
102
- // Accumulated-but-not-yet-drained delta. useVirtualScroll needs
103
- // this to mount the union [committed, committed+pending] range —
104
- // otherwise intermediate drain frames find no children (blank).
105
- return domRef.current?.pendingScrollDelta ?? 0;
106
- },
107
- getScrollHeight() {
108
- return domRef.current?.scrollHeight ?? 0;
109
- },
110
- getFreshScrollHeight() {
111
- const content = domRef.current?.childNodes[0];
112
- return content?.yogaNode?.getComputedHeight() ?? domRef.current?.scrollHeight ?? 0;
113
- },
114
- getViewportHeight() {
115
- return domRef.current?.scrollViewportHeight ?? 0;
116
- },
117
- getViewportTop() {
118
- return domRef.current?.scrollViewportTop ?? 0;
119
- },
120
- isSticky() {
121
- const el = domRef.current;
122
- if (!el)
123
- return false;
124
- return el.stickyScroll ?? Boolean(el.attributes['stickyScroll']);
125
- },
126
- subscribe(listener) {
127
- listenersRef.current.add(listener);
128
- return () => listenersRef.current.delete(listener);
129
- },
130
- setClampBounds(min, max) {
131
- const el = domRef.current;
132
- if (!el)
133
- return;
134
- el.scrollClampMin = min;
135
- el.scrollClampMax = max;
136
- }
137
- }),
90
+ useImperativeHandle(ref, () => {
91
+ const handle = {
92
+ scrollTo(y) {
93
+ const el = domRef.current;
94
+ if (!el)
95
+ return;
96
+ // Explicit false overrides the DOM attribute so manual scroll
97
+ // breaks stickiness. Render code checks ?? precedence.
98
+ el.stickyScroll = false;
99
+ el.pendingScrollDelta = undefined;
100
+ el.scrollAnchor = undefined;
101
+ el.scrollTop = Math.max(0, Math.floor(y));
102
+ scrollMutated(el);
103
+ },
104
+ scrollToElement(el, offset = 0) {
105
+ const box = domRef.current;
106
+ if (!box)
107
+ return;
108
+ box.stickyScroll = false;
109
+ box.pendingScrollDelta = undefined;
110
+ box.scrollAnchor = {
111
+ el,
112
+ offset
113
+ };
114
+ scrollMutated(box);
115
+ },
116
+ scrollBy(dy) {
117
+ const el = domRef.current;
118
+ if (!el)
119
+ return;
120
+ el.stickyScroll = false;
121
+ // Wheel input cancels any in-flight anchor seek — user override.
122
+ el.scrollAnchor = undefined;
123
+ // Accumulate in pendingScrollDelta; renderer drains it at a capped
124
+ // rate so fast flicks show intermediate frames. Pure accumulator:
125
+ // scroll-up followed by scroll-down naturally cancels.
126
+ el.pendingScrollDelta = (el.pendingScrollDelta ?? 0) + Math.floor(dy);
127
+ scrollMutated(el);
128
+ },
129
+ scrollToBottom() {
130
+ const el = domRef.current;
131
+ if (!el)
132
+ return;
133
+ el.scrollAnchor = undefined;
134
+ const viewportH = el.scrollViewportHeight ?? 0;
135
+ const maxScroll = Math.max(0, (el.scrollHeight ?? 0) - viewportH);
136
+ const distance = maxScroll - (el.scrollTop ?? 0);
137
+ if (distance > viewportH && viewportH > 0) {
138
+ // FAR jump: drain instead of teleport. The viewport would land on
139
+ // rows that were never mounted — their spacer heights are
140
+ // DEFAULT_ROW_HEIGHT estimates, so the topPad swallows the view
141
+ // (blank transcript) AND it is a fixed point: unmounted rows never
142
+ // measure, nothing retried until the next wheel event. The drain
143
+ // walks the exact wheel path instead: proportional steps, the
144
+ // virtualization window follows per commit (it mounts the union of
145
+ // committed + pending), the visual clamp pins to the mounted edge
146
+ // while rows measure as they enter — no blank at any distance. The
147
+ // renderer's at-bottom re-pin restores sticky when it lands
148
+ // (stickyScroll=false + pending undefined + scrollTop >= maxScroll).
149
+ el.stickyScroll = false;
150
+ el.pendingScrollDelta = (el.pendingScrollDelta ?? 0) + distance;
151
+ scrollMutated(el);
152
+ return;
153
+ }
154
+ el.pendingScrollDelta = undefined;
155
+ el.stickyScroll = true;
156
+ // DOM-direct pre-write of the target (near jumps only): the notify
157
+ // below triggers MessageList's window recompute, and its React commit
158
+ // must read the NEW scrollTop — the old order (notify first, renderer
159
+ // moves scrollTop later) left the window one commit behind. The
160
+ // renderer's sticky branch re-pins scrollTop to the exact fresh
161
+ // maxScroll next frame, so a stale cached height costs one frame.
162
+ el.scrollTop = maxScroll;
163
+ scrollMutated(el);
164
+ forceRender(n => n + 1);
165
+ },
166
+ getScrollTop() {
167
+ return domRef.current?.scrollTop ?? 0;
168
+ },
169
+ getPendingDelta() {
170
+ // Accumulated-but-not-yet-drained delta. useVirtualScroll needs
171
+ // this to mount the union [committed, committed+pending] range —
172
+ // otherwise intermediate drain frames find no children (blank).
173
+ return domRef.current?.pendingScrollDelta ?? 0;
174
+ },
175
+ getScrollHeight() {
176
+ return domRef.current?.scrollHeight ?? 0;
177
+ },
178
+ getFreshScrollHeight() {
179
+ const content = domRef.current?.childNodes[0];
180
+ return content?.yogaNode?.getComputedHeight() ?? domRef.current?.scrollHeight ?? 0;
181
+ },
182
+ getViewportHeight() {
183
+ return domRef.current?.scrollViewportHeight ?? 0;
184
+ },
185
+ getViewportTop() {
186
+ return domRef.current?.scrollViewportTop ?? 0;
187
+ },
188
+ isSticky() {
189
+ const el = domRef.current;
190
+ if (!el)
191
+ return false;
192
+ return el.stickyScroll ?? Boolean(el.attributes['stickyScroll']);
193
+ },
194
+ subscribe(listener) {
195
+ listenersRef.current.add(listener);
196
+ return () => listenersRef.current.delete(listener);
197
+ },
198
+ setClampBounds(min, max) {
199
+ const el = domRef.current;
200
+ if (!el)
201
+ return;
202
+ el.scrollClampMin = min;
203
+ el.scrollClampMax = max;
204
+ }
205
+ };
206
+ handleRef.current = handle;
207
+ return handle;
208
+ },
138
209
  // notify/scrollMutated are inline (no useCallback) but only close over
139
210
  // refs + imports — stable. Empty deps avoids rebuilding the handle on
140
211
  // every render (which re-registers the ref = churn).
141
212
  // eslint-disable-next-line react-hooks/exhaustive-deps
142
213
  []);
214
+ // Position-routed wheel events (pointer over this box) scroll THIS box
215
+ // through the public scrollBy path — clamp bounds, sticky clearing, and
216
+ // subscriber notify all apply. Horizontal wheel (deltaX) has no renderer
217
+ // support yet (no scrollLeft in the DOM model) and is ignored.
218
+ const handleWheel = useCallback((e) => {
219
+ if (e.deltaY !== 0)
220
+ handleRef.current?.scrollBy(e.deltaY);
221
+ }, []);
143
222
  // Structure: outer viewport (overflow:scroll, constrained height) >
144
223
  // inner content (flexGrow:1, flexShrink:0 — fills at least the viewport
145
224
  // but grows beyond it for tall content). flexGrow:1 lets children use
@@ -159,7 +238,7 @@ function ScrollBox({ children, ref, stickyScroll, ...style }) {
159
238
  // must reach React subscribers too — see dom.ts onStickyRestore.
160
239
  el.onStickyRestore = notify;
161
240
  }
162
- }, style: {
241
+ }, onWheel: handleWheel, style: {
163
242
  flexWrap: 'nowrap',
164
243
  flexDirection: style.flexDirection ?? 'row',
165
244
  flexGrow: style.flexGrow ?? 0,
@@ -1,3 +1,12 @@
1
1
  /** Shared frame interval for render throttling and animations (~60fps). */
2
2
  export declare const FRAME_INTERVAL_MS = 16;
3
+ /**
4
+ * In-flight pty gate threshold (bytes) for scroll-drain frames — Grok
5
+ * Build's Presenter in_flight gate. While stdout holds more unflushed
6
+ * output than this, drain frames hold off instead of stacking latency
7
+ * into a slow ConPTY/ssh link. Sized above one full-screen diff (~4KB at
8
+ * 100 cols) so the gate only trips on genuine backlog, never on a single
9
+ * in-transit frame.
10
+ */
11
+ export declare const PTY_BACKLOG_BYTES = 8192;
3
12
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/ink/constants.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,eAAO,MAAM,iBAAiB,KAAK,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/ink/constants.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,eAAO,MAAM,iBAAiB,KAAK,CAAA;AAEnC;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,OAAO,CAAA"}
@@ -1,2 +1,11 @@
1
1
  /** Shared frame interval for render throttling and animations (~60fps). */
2
2
  export const FRAME_INTERVAL_MS = 16;
3
+ /**
4
+ * In-flight pty gate threshold (bytes) for scroll-drain frames — Grok
5
+ * Build's Presenter in_flight gate. While stdout holds more unflushed
6
+ * output than this, drain frames hold off instead of stacking latency
7
+ * into a slow ConPTY/ssh link. Sized above one full-screen diff (~4KB at
8
+ * 100 cols) so the gate only trips on genuine backlog, never on a single
9
+ * in-transit frame.
10
+ */
11
+ export const PTY_BACKLOG_BYTES = 8192;
@@ -1,25 +1,16 @@
1
- import { Event } from './event.js';
1
+ import { PointerEvent, type PointerEventInit } from './pointer-event.js';
2
2
  /**
3
3
  * Mouse click event. Fired on left-button release without drag, only when
4
4
  * mouse tracking is enabled (i.e. inside <AlternateScreen>).
5
5
  *
6
6
  * Bubbles from the deepest hit node up through parentNode. Call
7
7
  * stopImmediatePropagation() to prevent ancestors' onClick from firing.
8
+ *
9
+ * Extends PointerEvent: `shift`/`alt`/`ctrl` expose the modifiers the
10
+ * terminal reported on the release, and `localCol`/`localRow` are recomputed
11
+ * per handler so containers see coordinates relative to themselves.
8
12
  */
9
- export declare class ClickEvent extends Event {
10
- /** 0-indexed screen column of the click */
11
- readonly col: number;
12
- /** 0-indexed screen row of the click */
13
- readonly row: number;
14
- /**
15
- * Click column relative to the current handler's Box (col - box.x).
16
- * Recomputed by dispatchClick before each handler fires, so an onClick
17
- * on a container sees coords relative to that container, not to any
18
- * child the click landed on.
19
- */
20
- localCol: number;
21
- /** Click row relative to the current handler's Box (row - box.y). */
22
- localRow: number;
13
+ export declare class ClickEvent extends PointerEvent {
23
14
  /**
24
15
  * True if the clicked cell has no visible content (unwritten in the
25
16
  * screen buffer — both packed words are 0). Handlers can check this to
@@ -27,6 +18,6 @@ export declare class ClickEvent extends Event {
27
18
  * clicks on empty terminal space don't toggle state.
28
19
  */
29
20
  readonly cellIsBlank: boolean;
30
- constructor(col: number, row: number, cellIsBlank: boolean);
21
+ constructor(col: number, row: number, cellIsBlank: boolean, init?: PointerEventInit);
31
22
  }
32
23
  //# sourceMappingURL=click-event.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"click-event.d.ts","sourceRoot":"","sources":["../../../../src/ink/events/click-event.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAElC;;;;;;GAMG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACnC,2CAA2C;IAC3C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,wCAAwC;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB;;;;;OAKG;IACH,QAAQ,SAAI;IACZ,qEAAqE;IACrE,QAAQ,SAAI;IACZ;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;gBAEjB,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO;CAM3D"}
1
+ {"version":3,"file":"click-event.d.ts","sourceRoot":"","sources":["../../../../src/ink/events/click-event.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAExE;;;;;;;;;;GAUG;AACH,qBAAa,UAAW,SAAQ,YAAY;IAC1C;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;gBAG3B,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,OAAO,EACpB,IAAI,CAAC,EAAE,gBAAgB;CAa1B"}
@@ -1,25 +1,16 @@
1
- import { Event } from './event.js';
1
+ import { PointerEvent } from './pointer-event.js';
2
2
  /**
3
3
  * Mouse click event. Fired on left-button release without drag, only when
4
4
  * mouse tracking is enabled (i.e. inside <AlternateScreen>).
5
5
  *
6
6
  * Bubbles from the deepest hit node up through parentNode. Call
7
7
  * stopImmediatePropagation() to prevent ancestors' onClick from firing.
8
+ *
9
+ * Extends PointerEvent: `shift`/`alt`/`ctrl` expose the modifiers the
10
+ * terminal reported on the release, and `localCol`/`localRow` are recomputed
11
+ * per handler so containers see coordinates relative to themselves.
8
12
  */
9
- export class ClickEvent extends Event {
10
- /** 0-indexed screen column of the click */
11
- col;
12
- /** 0-indexed screen row of the click */
13
- row;
14
- /**
15
- * Click column relative to the current handler's Box (col - box.x).
16
- * Recomputed by dispatchClick before each handler fires, so an onClick
17
- * on a container sees coords relative to that container, not to any
18
- * child the click landed on.
19
- */
20
- localCol = 0;
21
- /** Click row relative to the current handler's Box (row - box.y). */
22
- localRow = 0;
13
+ export class ClickEvent extends PointerEvent {
23
14
  /**
24
15
  * True if the clicked cell has no visible content (unwritten in the
25
16
  * screen buffer — both packed words are 0). Handlers can check this to
@@ -27,10 +18,16 @@ export class ClickEvent extends Event {
27
18
  * clicks on empty terminal space don't toggle state.
28
19
  */
29
20
  cellIsBlank;
30
- constructor(col, row, cellIsBlank) {
31
- super();
32
- this.col = col;
33
- this.row = row;
21
+ constructor(col, row, cellIsBlank, init) {
22
+ // A click is by definition a left-button release without drag. Normalize
23
+ // the low button bits to 0 (left) while preserving modifier bits
24
+ // (0x04 shift / 0x08 alt / 0x10 ctrl) from the release byte.
25
+ const button = init?.button ?? 0;
26
+ super('click', col, row, {
27
+ ...init,
28
+ action: 'release',
29
+ button: button & ~0x03,
30
+ });
34
31
  this.cellIsBlank = cellIsBlank;
35
32
  }
36
33
  }
@@ -2,13 +2,22 @@ import type { ClickEvent } from './click-event.js';
2
2
  import type { FocusEvent } from './focus-event.js';
3
3
  import type { KeyboardEvent } from './keyboard-event.js';
4
4
  import type { PasteEvent } from './paste-event.js';
5
+ import type { PointerEvent } from './pointer-event.js';
5
6
  import type { ResizeEvent } from './resize-event.js';
7
+ import type { WheelEvent } from './wheel-event.js';
6
8
  type KeyboardEventHandler = (event: KeyboardEvent) => void;
7
9
  type FocusEventHandler = (event: FocusEvent) => void;
8
10
  type PasteEventHandler = (event: PasteEvent) => void;
9
11
  type ResizeEventHandler = (event: ResizeEvent) => void;
10
12
  type ClickEventHandler = (event: ClickEvent) => void;
11
- type HoverEventHandler = () => void;
13
+ /**
14
+ * Hover handlers receive the pointer position. Existing `() => void`
15
+ * handlers remain assignable (a function taking fewer parameters is
16
+ * assignable to one taking more), so this widening is fully backwards
17
+ * compatible.
18
+ */
19
+ type HoverEventHandler = (event: PointerEvent) => void;
20
+ type WheelEventHandler = (event: WheelEvent) => void;
12
21
  /**
13
22
  * Props for event handlers on Box and other host components.
14
23
  *
@@ -29,6 +38,7 @@ export type EventHandlerProps = {
29
38
  onClick?: ClickEventHandler;
30
39
  onMouseEnter?: HoverEventHandler;
31
40
  onMouseLeave?: HoverEventHandler;
41
+ onWheel?: WheelEventHandler;
32
42
  };
33
43
  /**
34
44
  * Reverse lookup: event type string → handler prop names.
@@ -1 +1 @@
1
- {"version":3,"file":"event-handlers.d.ts","sourceRoot":"","sources":["../../../../src/ink/events/event-handlers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD,KAAK,oBAAoB,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;AAC1D,KAAK,iBAAiB,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;AACpD,KAAK,iBAAiB,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;AACpD,KAAK,kBAAkB,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAA;AACtD,KAAK,iBAAiB,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;AACpD,KAAK,iBAAiB,GAAG,MAAM,IAAI,CAAA;AAEnC;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,SAAS,CAAC,EAAE,oBAAoB,CAAA;IAChC,gBAAgB,CAAC,EAAE,oBAAoB,CAAA;IAEvC,OAAO,CAAC,EAAE,iBAAiB,CAAA;IAC3B,cAAc,CAAC,EAAE,iBAAiB,CAAA;IAClC,MAAM,CAAC,EAAE,iBAAiB,CAAA;IAC1B,aAAa,CAAC,EAAE,iBAAiB,CAAA;IAEjC,OAAO,CAAC,EAAE,iBAAiB,CAAA;IAC3B,cAAc,CAAC,EAAE,iBAAiB,CAAA;IAElC,QAAQ,CAAC,EAAE,kBAAkB,CAAA;IAE7B,OAAO,CAAC,EAAE,iBAAiB,CAAA;IAC3B,YAAY,CAAC,EAAE,iBAAiB,CAAA;IAChC,YAAY,CAAC,EAAE,iBAAiB,CAAA;CACjC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CACpC,MAAM,EACN;IAAE,MAAM,CAAC,EAAE,MAAM,iBAAiB,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,iBAAiB,CAAA;CAAE,CAQxE,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,aAa9B,CAAA"}
1
+ {"version":3,"file":"event-handlers.d.ts","sourceRoot":"","sources":["../../../../src/ink/events/event-handlers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD,KAAK,oBAAoB,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;AAC1D,KAAK,iBAAiB,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;AACpD,KAAK,iBAAiB,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;AACpD,KAAK,kBAAkB,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAA;AACtD,KAAK,iBAAiB,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;AACpD;;;;;GAKG;AACH,KAAK,iBAAiB,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAA;AACtD,KAAK,iBAAiB,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;AAEpD;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,SAAS,CAAC,EAAE,oBAAoB,CAAA;IAChC,gBAAgB,CAAC,EAAE,oBAAoB,CAAA;IAEvC,OAAO,CAAC,EAAE,iBAAiB,CAAA;IAC3B,cAAc,CAAC,EAAE,iBAAiB,CAAA;IAClC,MAAM,CAAC,EAAE,iBAAiB,CAAA;IAC1B,aAAa,CAAC,EAAE,iBAAiB,CAAA;IAEjC,OAAO,CAAC,EAAE,iBAAiB,CAAA;IAC3B,cAAc,CAAC,EAAE,iBAAiB,CAAA;IAElC,QAAQ,CAAC,EAAE,kBAAkB,CAAA;IAE7B,OAAO,CAAC,EAAE,iBAAiB,CAAA;IAC3B,YAAY,CAAC,EAAE,iBAAiB,CAAA;IAChC,YAAY,CAAC,EAAE,iBAAiB,CAAA;IAChC,OAAO,CAAC,EAAE,iBAAiB,CAAA;CAC5B,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CACpC,MAAM,EACN;IAAE,MAAM,CAAC,EAAE,MAAM,iBAAiB,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,iBAAiB,CAAA;CAAE,CASxE,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,aAc9B,CAAA"}
@@ -9,6 +9,7 @@ export const HANDLER_FOR_EVENT = {
9
9
  paste: { bubble: 'onPaste', capture: 'onPasteCapture' },
10
10
  resize: { bubble: 'onResize' },
11
11
  click: { bubble: 'onClick' },
12
+ wheel: { bubble: 'onWheel' },
12
13
  };
13
14
  /**
14
15
  * Set of all event handler prop names, for the reconciler to detect
@@ -27,4 +28,5 @@ export const EVENT_HANDLER_PROPS = new Set([
27
28
  'onClick',
28
29
  'onMouseEnter',
29
30
  'onMouseLeave',
31
+ 'onWheel',
30
32
  ]);
@@ -13,6 +13,8 @@ export type Key = {
13
13
  pageUp: boolean;
14
14
  wheelUp: boolean;
15
15
  wheelDown: boolean;
16
+ wheelLeft: boolean;
17
+ wheelRight: boolean;
16
18
  home: boolean;
17
19
  end: boolean;
18
20
  return: boolean;
@@ -25,6 +27,13 @@ export type Key = {
25
27
  delete: boolean;
26
28
  meta: boolean;
27
29
  super: boolean;
30
+ /**
31
+ * Pointer column (0-indexed) when the key is a wheel event — the SGR/X10
32
+ * sequence carries the position. Undefined for non-wheel keys.
33
+ */
34
+ mouseCol?: number;
35
+ /** Pointer row (0-indexed) when the key is a wheel event. See mouseCol. */
36
+ mouseRow?: number;
28
37
  };
29
38
  /**
30
39
  * Event fired for each input chunk received from stdin (a typed character or
@@ -1 +1 @@
1
- {"version":3,"file":"input-event.d.ts","sourceRoot":"","sources":["../../../../src/ink/events/input-event.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAC1E,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAElC;;;GAGG;AACH,MAAM,MAAM,GAAG,GAAG;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,OAAO,CAAA;IAClB,SAAS,EAAE,OAAO,CAAA;IAClB,UAAU,EAAE,OAAO,CAAA;IACnB,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,OAAO,CAAA;IACf,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,OAAO,CAAA;IAClB,IAAI,EAAE,OAAO,CAAA;IACb,GAAG,EAAE,OAAO,CAAA;IACZ,MAAM,EAAE,OAAO,CAAA;IACf,MAAM,EAAE,OAAO,CAAA;IACf,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,OAAO,CAAA;IACd,EAAE,EAAE,OAAO,CAAA;IACX,GAAG,EAAE,OAAO,CAAA;IACZ,SAAS,EAAE,OAAO,CAAA;IAClB,MAAM,EAAE,OAAO,CAAA;IACf,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAuKD;;;GAGG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACnC;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;IAE5B;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAA;IAEjB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB;;;wBAGoB;IACpB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;gBAEd,QAAQ,EAAE,SAAS;CAShC"}
1
+ {"version":3,"file":"input-event.d.ts","sourceRoot":"","sources":["../../../../src/ink/events/input-event.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAC1E,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAElC;;;GAGG;AACH,MAAM,MAAM,GAAG,GAAG;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,OAAO,CAAA;IAClB,SAAS,EAAE,OAAO,CAAA;IAClB,UAAU,EAAE,OAAO,CAAA;IACnB,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,OAAO,CAAA;IACf,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,OAAO,CAAA;IAClB,SAAS,EAAE,OAAO,CAAA;IAClB,UAAU,EAAE,OAAO,CAAA;IACnB,IAAI,EAAE,OAAO,CAAA;IACb,GAAG,EAAE,OAAO,CAAA;IACZ,MAAM,EAAE,OAAO,CAAA;IACf,MAAM,EAAE,OAAO,CAAA;IACf,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,OAAO,CAAA;IACd,EAAE,EAAE,OAAO,CAAA;IACX,GAAG,EAAE,OAAO,CAAA;IACZ,SAAS,EAAE,OAAO,CAAA;IAClB,MAAM,EAAE,OAAO,CAAA;IACf,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,OAAO,CAAA;IACd;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AA2KD;;;GAGG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACnC;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;IAE5B;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAA;IAEjB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB;;;wBAGoB;IACpB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;gBAEd,QAAQ,EAAE,SAAS;CAShC"}
@@ -10,6 +10,8 @@ function parseKey(keypress) {
10
10
  pageUp: keypress.name === 'pageup',
11
11
  wheelUp: keypress.name === 'wheelup',
12
12
  wheelDown: keypress.name === 'wheeldown',
13
+ wheelLeft: keypress.name === 'wheelleft',
14
+ wheelRight: keypress.name === 'wheelright',
13
15
  home: keypress.name === 'home',
14
16
  end: keypress.name === 'end',
15
17
  return: keypress.name === 'return',
@@ -29,6 +31,8 @@ function parseKey(keypress) {
29
31
  // protocol CSI u sequences. Distinct from meta (Alt/Option) so
30
32
  // bindings like cmd+c can be expressed separately from opt+c.
31
33
  super: keypress.super,
34
+ mouseCol: keypress.mouseCol,
35
+ mouseRow: keypress.mouseRow,
32
36
  };
33
37
  let input = keypress.ctrl ? keypress.name : keypress.sequence;
34
38
  // Handle undefined input case
@@ -0,0 +1,61 @@
1
+ import { TerminalEvent, type EventTarget } from './terminal-event.js';
2
+ /**
3
+ * Pointer action reported by the terminal protocol.
4
+ *
5
+ * - `press`: a button went down (SGR `M` terminator / X10 press)
6
+ * - `release`: a button came up (SGR `m` terminator; X10 cannot report this)
7
+ * - `move`: pointer motion (SGR drag bit or mode-1003 no-button motion)
8
+ */
9
+ export type PointerAction = 'press' | 'release' | 'move';
10
+ /** Optional state when constructing a {@link PointerEvent}. */
11
+ export type PointerEventInit = {
12
+ /** Raw protocol button byte (SGR bits: 0x04 shift, 0x08 alt, 0x10 ctrl). */
13
+ button?: number;
14
+ action?: PointerAction;
15
+ bubbles?: boolean;
16
+ cancelable?: boolean;
17
+ };
18
+ /**
19
+ * Base class for pointer-derived terminal events (click, wheel, hover).
20
+ *
21
+ * Carries the raw SGR/X10 button byte so handlers can read modifier flags
22
+ * (`shift`/`alt`/`ctrl`) without re-parsing the escape sequence, plus
23
+ * per-handler local coordinates: `_prepareForTarget` recomputes
24
+ * `localCol`/`localRow` from the nodeCache rect before each handler fires,
25
+ * so an onClick on a container sees coordinates relative to that container,
26
+ * not to the child the pointer actually landed on.
27
+ *
28
+ * `meta` is deliberately always false: xterm.js drops metaKey before SGR
29
+ * encoding (the SGR bit we call "meta" is wired to alt), so no pointer
30
+ * protocol can distinguish it reliably.
31
+ */
32
+ export declare class PointerEvent extends TerminalEvent {
33
+ /** 0-indexed screen column of the pointer. */
34
+ readonly col: number;
35
+ /** 0-indexed screen row of the pointer. */
36
+ readonly row: number;
37
+ /** Raw protocol button byte (SGR encoding). */
38
+ readonly button: number;
39
+ /** Which pointer action produced this event. */
40
+ readonly action: PointerAction;
41
+ /** Shift held (SGR button bit 0x04). */
42
+ readonly shift: boolean;
43
+ /** Alt/Option held (SGR button bit 0x08). */
44
+ readonly alt: boolean;
45
+ /** Ctrl held (SGR button bit 0x10). */
46
+ readonly ctrl: boolean;
47
+ /** Always false — see class doc. */
48
+ readonly meta = false;
49
+ /** Column relative to the current handler's node (set during dispatch). */
50
+ localCol: number;
51
+ /** Row relative to the current handler's node (set during dispatch). */
52
+ localRow: number;
53
+ constructor(type: string, col: number, row: number, init?: PointerEventInit);
54
+ /**
55
+ * Refresh localCol/localRow for the node whose handler is about to run.
56
+ * Nodes without a cached rect (not rendered this frame) get 0,0 — handlers
57
+ * should prefer absolute col/row when that distinction matters.
58
+ */
59
+ _prepareForTarget(target: EventTarget): void;
60
+ }
61
+ //# sourceMappingURL=pointer-event.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pointer-event.d.ts","sourceRoot":"","sources":["../../../../src/ink/events/pointer-event.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAErE;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAA;AAExD,+DAA+D;AAC/D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,aAAa,CAAA;IACtB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,YAAa,SAAQ,aAAa;IAC7C,8CAA8C;IAC9C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,2CAA2C;IAC3C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,+CAA+C;IAC/C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,gDAAgD;IAChD,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;IAC9B,wCAAwC;IACxC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,6CAA6C;IAC7C,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;IACrB,uCAAuC;IACvC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,oCAAoC;IACpC,QAAQ,CAAC,IAAI,SAAQ;IACrB,2EAA2E;IAC3E,QAAQ,SAAI;IACZ,wEAAwE;IACxE,QAAQ,SAAI;gBAEA,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,gBAAgB;IAc3E;;;;OAIG;IACM,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;CAKtD"}