@townco/ui 0.1.6 → 0.1.7

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 (250) hide show
  1. package/README.md +11 -11
  2. package/dist/core/hooks/use-chat-input.d.ts +17 -17
  3. package/dist/core/hooks/use-chat-input.js +55 -64
  4. package/dist/core/hooks/use-chat-messages.d.ts +11 -11
  5. package/dist/core/hooks/use-chat-messages.js +114 -121
  6. package/dist/core/hooks/use-chat-session.d.ts +5 -5
  7. package/dist/core/hooks/use-chat-session.js +80 -78
  8. package/dist/core/index.d.ts +1 -1
  9. package/dist/core/index.js +1 -1
  10. package/dist/core/schemas/chat.d.ts +56 -83
  11. package/dist/core/schemas/chat.js +25 -27
  12. package/dist/core/store/chat-store.d.ts +22 -28
  13. package/dist/core/store/chat-store.js +50 -59
  14. package/dist/gui/components/Button.d.ts +7 -23
  15. package/dist/gui/components/Button.js +27 -40
  16. package/dist/gui/components/Card.d.ts +7 -26
  17. package/dist/gui/components/Card.js +8 -54
  18. package/dist/gui/components/ChatInput.d.ts +36 -58
  19. package/dist/gui/components/ChatInput.js +121 -191
  20. package/dist/gui/components/ChatSecondaryPanel.d.ts +11 -14
  21. package/dist/gui/components/ChatSecondaryPanel.js +38 -115
  22. package/dist/gui/components/ChatStatus.d.ts +2 -4
  23. package/dist/gui/components/ChatStatus.js +34 -45
  24. package/dist/gui/components/Conversation.d.ts +14 -17
  25. package/dist/gui/components/Conversation.js +83 -143
  26. package/dist/gui/components/Dialog.d.ts +11 -57
  27. package/dist/gui/components/Dialog.js +8 -84
  28. package/dist/gui/components/HeightTransition.d.ts +7 -12
  29. package/dist/gui/components/HeightTransition.js +77 -88
  30. package/dist/gui/components/Input.d.ts +6 -13
  31. package/dist/gui/components/Input.js +16 -27
  32. package/dist/gui/components/Label.d.ts +1 -7
  33. package/dist/gui/components/Label.js +2 -12
  34. package/dist/gui/components/MarkdownRenderer.d.ts +4 -6
  35. package/dist/gui/components/MarkdownRenderer.js +81 -178
  36. package/dist/gui/components/Message.d.ts +18 -25
  37. package/dist/gui/components/Message.js +23 -44
  38. package/dist/gui/components/MessageContent.d.ts +22 -29
  39. package/dist/gui/components/MessageContent.js +85 -157
  40. package/dist/gui/components/Reasoning.d.ts +24 -30
  41. package/dist/gui/components/Reasoning.js +60 -187
  42. package/dist/gui/components/Response.d.ts +9 -11
  43. package/dist/gui/components/Response.js +90 -229
  44. package/dist/gui/components/Select.d.ts +10 -69
  45. package/dist/gui/components/Select.js +12 -118
  46. package/dist/gui/components/Tabs.d.ts +4 -24
  47. package/dist/gui/components/Tabs.js +4 -32
  48. package/dist/gui/components/Task.d.ts +24 -28
  49. package/dist/gui/components/Task.js +31 -164
  50. package/dist/gui/components/Textarea.d.ts +7 -15
  51. package/dist/gui/components/Textarea.js +46 -63
  52. package/dist/gui/components/ThinkingBlock.d.ts +10 -20
  53. package/dist/gui/components/ThinkingBlock.js +35 -134
  54. package/dist/gui/components/TodoList.d.ts +10 -12
  55. package/dist/gui/components/TodoList.js +7 -22
  56. package/dist/gui/components/TodoListItem.d.ts +6 -9
  57. package/dist/gui/components/TodoListItem.js +4 -18
  58. package/dist/gui/components/index.d.ts +8 -59
  59. package/dist/gui/components/index.js +8 -42
  60. package/dist/gui/lib/utils.js +1 -1
  61. package/dist/index.d.ts +1 -1
  62. package/dist/index.js +1 -1
  63. package/dist/index.test.js +1 -0
  64. package/dist/sdk/client/acp-client.d.ts +76 -88
  65. package/dist/sdk/client/acp-client.js +217 -215
  66. package/dist/sdk/index.d.ts +1 -1
  67. package/dist/sdk/index.js +1 -1
  68. package/dist/sdk/schemas/agent.d.ts +64 -111
  69. package/dist/sdk/schemas/agent.js +24 -24
  70. package/dist/sdk/schemas/message.d.ts +147 -245
  71. package/dist/sdk/schemas/message.js +40 -40
  72. package/dist/sdk/schemas/session.d.ts +135 -219
  73. package/dist/sdk/schemas/session.js +27 -27
  74. package/dist/sdk/transports/http.d.ts +55 -55
  75. package/dist/sdk/transports/http.js +469 -472
  76. package/dist/sdk/transports/stdio.d.ts +20 -20
  77. package/dist/sdk/transports/stdio.js +286 -289
  78. package/dist/sdk/transports/types.d.ts +42 -42
  79. package/dist/sdk/transports/websocket.d.ts +12 -12
  80. package/dist/sdk/transports/websocket.js +46 -52
  81. package/dist/tui/components/ChatView.d.ts +2 -4
  82. package/dist/tui/components/ChatView.js +18 -51
  83. package/dist/tui/components/GameOfLife.js +35 -64
  84. package/dist/tui/components/InputBox.d.ts +11 -18
  85. package/dist/tui/components/InputBox.js +10 -70
  86. package/dist/tui/components/MessageList.d.ts +2 -4
  87. package/dist/tui/components/MessageList.js +10 -37
  88. package/dist/tui/components/MultiSelect.d.ts +10 -15
  89. package/dist/tui/components/MultiSelect.js +73 -116
  90. package/dist/tui/components/ReadlineInput.d.ts +6 -12
  91. package/dist/tui/components/ReadlineInput.js +237 -252
  92. package/dist/tui/components/SingleSelect.d.ts +9 -15
  93. package/dist/tui/components/SingleSelect.js +43 -84
  94. package/dist/tui/components/StatusBar.d.ts +6 -11
  95. package/dist/tui/components/StatusBar.js +67 -102
  96. package/dist/tui/index.d.ts +1 -1
  97. package/dist/tui/index.js +1 -1
  98. package/package.json +2 -2
  99. package/dist/core/hooks/index.d.ts.map +0 -1
  100. package/dist/core/hooks/index.js.map +0 -1
  101. package/dist/core/hooks/use-chat-input.d.ts.map +0 -1
  102. package/dist/core/hooks/use-chat-input.js.map +0 -1
  103. package/dist/core/hooks/use-chat-messages.d.ts.map +0 -1
  104. package/dist/core/hooks/use-chat-messages.js.map +0 -1
  105. package/dist/core/hooks/use-chat-session.d.ts.map +0 -1
  106. package/dist/core/hooks/use-chat-session.js.map +0 -1
  107. package/dist/core/hooks/use-media-query.d.ts +0 -39
  108. package/dist/core/hooks/use-media-query.js +0 -80
  109. package/dist/core/index.d.ts.map +0 -1
  110. package/dist/core/index.js.map +0 -1
  111. package/dist/core/schemas/chat.d.ts.map +0 -1
  112. package/dist/core/schemas/chat.js.map +0 -1
  113. package/dist/core/schemas/index.d.ts.map +0 -1
  114. package/dist/core/schemas/index.js.map +0 -1
  115. package/dist/core/store/chat-store.d.ts.map +0 -1
  116. package/dist/core/store/chat-store.js.map +0 -1
  117. package/dist/gui/components/Button.d.ts.map +0 -1
  118. package/dist/gui/components/Button.js.map +0 -1
  119. package/dist/gui/components/Card.d.ts.map +0 -1
  120. package/dist/gui/components/Card.js.map +0 -1
  121. package/dist/gui/components/ChatHeader.d.ts +0 -65
  122. package/dist/gui/components/ChatHeader.js +0 -189
  123. package/dist/gui/components/ChatInput.d.ts.map +0 -1
  124. package/dist/gui/components/ChatInput.js.map +0 -1
  125. package/dist/gui/components/ChatInterface.d.ts +0 -12
  126. package/dist/gui/components/ChatInterface.d.ts.map +0 -1
  127. package/dist/gui/components/ChatInterface.js +0 -204
  128. package/dist/gui/components/ChatInterface.js.map +0 -1
  129. package/dist/gui/components/ChatLayout.d.ts +0 -82
  130. package/dist/gui/components/ChatLayout.js +0 -232
  131. package/dist/gui/components/ChatPanelTabContent.d.ts +0 -27
  132. package/dist/gui/components/ChatPanelTabContent.js +0 -93
  133. package/dist/gui/components/ChatPreview.d.ts +0 -12
  134. package/dist/gui/components/ChatPreview.d.ts.map +0 -1
  135. package/dist/gui/components/ChatPreview.js +0 -214
  136. package/dist/gui/components/ChatPreview.js.map +0 -1
  137. package/dist/gui/components/ChatSecondaryPanel.d.ts.map +0 -1
  138. package/dist/gui/components/ChatSecondaryPanel.js.map +0 -1
  139. package/dist/gui/components/ChatSidebar.d.ts +0 -27
  140. package/dist/gui/components/ChatSidebar.js +0 -57
  141. package/dist/gui/components/ChatStatus.d.ts.map +0 -1
  142. package/dist/gui/components/ChatStatus.js.map +0 -1
  143. package/dist/gui/components/ChatView.d.ts +0 -8
  144. package/dist/gui/components/ChatView.d.ts.map +0 -1
  145. package/dist/gui/components/ChatView.js +0 -42
  146. package/dist/gui/components/ChatView.js.map +0 -1
  147. package/dist/gui/components/ConfigPanel.d.ts +0 -20
  148. package/dist/gui/components/ConfigPanel.d.ts.map +0 -1
  149. package/dist/gui/components/ConfigPanel.js +0 -225
  150. package/dist/gui/components/ConfigPanel.js.map +0 -1
  151. package/dist/gui/components/Conversation.d.ts.map +0 -1
  152. package/dist/gui/components/Conversation.js.map +0 -1
  153. package/dist/gui/components/Dialog.d.ts.map +0 -1
  154. package/dist/gui/components/Dialog.js.map +0 -1
  155. package/dist/gui/components/DropdownMenu.d.ts +0 -108
  156. package/dist/gui/components/DropdownMenu.js +0 -215
  157. package/dist/gui/components/HeightTransition.d.ts.map +0 -1
  158. package/dist/gui/components/HeightTransition.js.map +0 -1
  159. package/dist/gui/components/Input.d.ts.map +0 -1
  160. package/dist/gui/components/Input.js.map +0 -1
  161. package/dist/gui/components/InputBox.d.ts +0 -21
  162. package/dist/gui/components/InputBox.d.ts.map +0 -1
  163. package/dist/gui/components/InputBox.js +0 -90
  164. package/dist/gui/components/InputBox.js.map +0 -1
  165. package/dist/gui/components/Label.d.ts.map +0 -1
  166. package/dist/gui/components/Label.js.map +0 -1
  167. package/dist/gui/components/MarkdownRenderer.d.ts.map +0 -1
  168. package/dist/gui/components/MarkdownRenderer.js.map +0 -1
  169. package/dist/gui/components/Message.d.ts.map +0 -1
  170. package/dist/gui/components/Message.js.map +0 -1
  171. package/dist/gui/components/MessageContent.d.ts.map +0 -1
  172. package/dist/gui/components/MessageContent.js.map +0 -1
  173. package/dist/gui/components/MessageList.d.ts.map +0 -1
  174. package/dist/gui/components/MessageList.js.map +0 -1
  175. package/dist/gui/components/PlaygroundLayout.d.ts +0 -14
  176. package/dist/gui/components/PlaygroundLayout.d.ts.map +0 -1
  177. package/dist/gui/components/PlaygroundLayout.js +0 -49
  178. package/dist/gui/components/PlaygroundLayout.js.map +0 -1
  179. package/dist/gui/components/Reasoning.d.ts.map +0 -1
  180. package/dist/gui/components/Reasoning.js.map +0 -1
  181. package/dist/gui/components/Response.d.ts.map +0 -1
  182. package/dist/gui/components/Response.js.map +0 -1
  183. package/dist/gui/components/Select.d.ts.map +0 -1
  184. package/dist/gui/components/Select.js.map +0 -1
  185. package/dist/gui/components/Sonner.d.ts +0 -7
  186. package/dist/gui/components/Sonner.js +0 -34
  187. package/dist/gui/components/StatusBar.d.ts +0 -12
  188. package/dist/gui/components/StatusBar.d.ts.map +0 -1
  189. package/dist/gui/components/StatusBar.js +0 -58
  190. package/dist/gui/components/StatusBar.js.map +0 -1
  191. package/dist/gui/components/Tabs.d.ts.map +0 -1
  192. package/dist/gui/components/Tabs.js.map +0 -1
  193. package/dist/gui/components/Task.d.ts.map +0 -1
  194. package/dist/gui/components/Task.js.map +0 -1
  195. package/dist/gui/components/Textarea.d.ts.map +0 -1
  196. package/dist/gui/components/Textarea.js.map +0 -1
  197. package/dist/gui/components/ThinkingBlock.d.ts.map +0 -1
  198. package/dist/gui/components/ThinkingBlock.js.map +0 -1
  199. package/dist/gui/components/TodoList.d.ts.map +0 -1
  200. package/dist/gui/components/TodoList.js.map +0 -1
  201. package/dist/gui/components/TodoListItem.d.ts.map +0 -1
  202. package/dist/gui/components/TodoListItem.js.map +0 -1
  203. package/dist/gui/components/index.d.ts.map +0 -1
  204. package/dist/gui/components/index.js.map +0 -1
  205. package/dist/gui/index.d.ts.map +0 -1
  206. package/dist/gui/index.js.map +0 -1
  207. package/dist/gui/lib/utils.d.ts.map +0 -1
  208. package/dist/gui/lib/utils.js.map +0 -1
  209. package/dist/index.d.ts.map +0 -1
  210. package/dist/index.js.map +0 -1
  211. package/dist/sdk/client/acp-client.d.ts.map +0 -1
  212. package/dist/sdk/client/acp-client.js.map +0 -1
  213. package/dist/sdk/client/index.d.ts.map +0 -1
  214. package/dist/sdk/client/index.js.map +0 -1
  215. package/dist/sdk/index.d.ts.map +0 -1
  216. package/dist/sdk/index.js.map +0 -1
  217. package/dist/sdk/schemas/agent.d.ts.map +0 -1
  218. package/dist/sdk/schemas/agent.js.map +0 -1
  219. package/dist/sdk/schemas/index.d.ts.map +0 -1
  220. package/dist/sdk/schemas/index.js.map +0 -1
  221. package/dist/sdk/schemas/message.d.ts.map +0 -1
  222. package/dist/sdk/schemas/message.js.map +0 -1
  223. package/dist/sdk/schemas/session.d.ts.map +0 -1
  224. package/dist/sdk/schemas/session.js.map +0 -1
  225. package/dist/sdk/transports/http.d.ts.map +0 -1
  226. package/dist/sdk/transports/http.js.map +0 -1
  227. package/dist/sdk/transports/index.d.ts.map +0 -1
  228. package/dist/sdk/transports/index.js.map +0 -1
  229. package/dist/sdk/transports/stdio.d.ts.map +0 -1
  230. package/dist/sdk/transports/stdio.js.map +0 -1
  231. package/dist/sdk/transports/types.d.ts.map +0 -1
  232. package/dist/sdk/transports/types.js.map +0 -1
  233. package/dist/sdk/transports/websocket.d.ts.map +0 -1
  234. package/dist/sdk/transports/websocket.js.map +0 -1
  235. package/dist/tui/components/ChatView.d.ts.map +0 -1
  236. package/dist/tui/components/ChatView.js.map +0 -1
  237. package/dist/tui/components/GameOfLife.d.ts.map +0 -1
  238. package/dist/tui/components/GameOfLife.js.map +0 -1
  239. package/dist/tui/components/InputBox.d.ts.map +0 -1
  240. package/dist/tui/components/InputBox.js.map +0 -1
  241. package/dist/tui/components/MessageList.d.ts.map +0 -1
  242. package/dist/tui/components/MessageList.js.map +0 -1
  243. package/dist/tui/components/ReadlineInput.d.ts.map +0 -1
  244. package/dist/tui/components/ReadlineInput.js.map +0 -1
  245. package/dist/tui/components/StatusBar.d.ts.map +0 -1
  246. package/dist/tui/components/StatusBar.js.map +0 -1
  247. package/dist/tui/components/index.d.ts.map +0 -1
  248. package/dist/tui/components/index.js.map +0 -1
  249. package/dist/tui/index.d.ts.map +0 -1
  250. package/dist/tui/index.js.map +0 -1
@@ -1,255 +1,240 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
1
2
  import { Text, useInput } from "ink";
2
3
  import React, { useState } from "react";
3
- import {
4
- Fragment as _Fragment,
5
- jsx as _jsx,
6
- jsxs as _jsxs,
7
- } from "react/jsx-runtime";
8
- export function ReadlineInput({
9
- value,
10
- onChange,
11
- onSubmit,
12
- onEscape,
13
- placeholder = "",
14
- }) {
15
- const [cursorOffset, setCursorOffset] = useState(0);
16
- useInput((input, key) => {
17
- // Handle Esc: Call escape handler
18
- if (key.escape) {
19
- if (onEscape) {
20
- onEscape();
21
- }
22
- return;
23
- }
24
- // Handle special keys
25
- if (key.return) {
26
- const cursorPos = value.length + cursorOffset;
27
- // Shift+Enter: Insert backslash and newline
28
- if (key.shift) {
29
- const newValue = `${value.slice(0, cursorPos)}\\\n${value.slice(cursorPos)}`;
30
- onChange(newValue);
31
- if (cursorOffset < 0) {
32
- setCursorOffset(cursorOffset - 2);
33
- }
34
- return;
35
- }
36
- // Check if cursor is at end and last character is backslash (line continuation)
37
- if (cursorPos === value.length && value.endsWith("\\")) {
38
- // Remove backslash and add newline (line continuation)
39
- const newValue = `${value.slice(0, -1)}\n`;
40
- onChange(newValue);
41
- setCursorOffset(0); // Move cursor to end
42
- return;
43
- }
44
- // Alt+Enter adds a newline, Enter submits
45
- if (key.meta) {
46
- const newValue = `${value.slice(0, cursorPos)}\n${value.slice(cursorPos)}`;
47
- onChange(newValue);
48
- if (cursorOffset < 0) {
49
- setCursorOffset(cursorOffset - 1);
50
- }
51
- } else {
52
- onSubmit();
53
- }
54
- return;
55
- }
56
- if (key.ctrl) {
57
- // Ctrl+A: Move to beginning of line
58
- if (input === "a") {
59
- setCursorOffset(-value.length);
60
- return;
61
- }
62
- // Ctrl+E: Move to end of line
63
- if (input === "e") {
64
- setCursorOffset(0);
65
- return;
66
- }
67
- // Ctrl+W: Delete word backward
68
- if (input === "w") {
69
- const cursorPos = value.length + cursorOffset;
70
- const before = value.slice(0, cursorPos);
71
- const after = value.slice(cursorPos);
72
- // Find the start of the word to delete
73
- const match = before.match(/\s*\S*$/);
74
- if (match) {
75
- const newBefore = before.slice(0, -match[0].length);
76
- onChange(newBefore + after);
77
- setCursorOffset(-after.length);
78
- }
79
- return;
80
- }
81
- // Ctrl+U: Delete from cursor to beginning of line
82
- if (input === "u") {
83
- const cursorPos = value.length + cursorOffset;
84
- onChange(value.slice(cursorPos));
85
- setCursorOffset(-value.slice(cursorPos).length);
86
- return;
87
- }
88
- // Ctrl+K: Delete from cursor to end of line
89
- if (input === "k") {
90
- const cursorPos = value.length + cursorOffset;
91
- onChange(value.slice(0, cursorPos));
92
- setCursorOffset(0);
93
- return;
94
- }
95
- // Ctrl+D: Delete character forward
96
- if (input === "d") {
97
- const cursorPos = value.length + cursorOffset;
98
- if (cursorPos < value.length) {
99
- onChange(value.slice(0, cursorPos) + value.slice(cursorPos + 1));
100
- }
101
- return;
102
- }
103
- // Ctrl+B: Move backward one character
104
- if (input === "b") {
105
- const cursorPos = value.length + cursorOffset;
106
- if (cursorPos > 0) {
107
- setCursorOffset(cursorOffset - 1);
108
- }
109
- return;
110
- }
111
- // Ctrl+F: Move forward one character
112
- if (input === "f") {
113
- const cursorPos = value.length + cursorOffset;
114
- if (cursorPos < value.length) {
115
- setCursorOffset(cursorOffset + 1);
116
- }
117
- return;
118
- }
119
- }
120
- // Handle backspace
121
- if (key.backspace || key.delete) {
122
- const cursorPos = value.length + cursorOffset;
123
- if (cursorPos > 0) {
124
- onChange(value.slice(0, cursorPos - 1) + value.slice(cursorPos));
125
- if (cursorOffset < 0) {
126
- setCursorOffset(cursorOffset + 1);
127
- }
128
- }
129
- return;
130
- }
131
- // Handle left/right arrow keys
132
- if (key.leftArrow) {
133
- const cursorPos = value.length + cursorOffset;
134
- if (cursorPos > 0) {
135
- setCursorOffset(cursorOffset - 1);
136
- }
137
- return;
138
- }
139
- if (key.rightArrow) {
140
- const cursorPos = value.length + cursorOffset;
141
- if (cursorPos < value.length) {
142
- setCursorOffset(cursorOffset + 1);
143
- }
144
- return;
145
- }
146
- // Handle up/down arrow keys for multi-line navigation
147
- if (key.upArrow) {
148
- const cursorPos = value.length + cursorOffset;
149
- const lines = value.split("\n");
150
- // Find which line we're on and our position within it
151
- let currentLineIndex = 0;
152
- let charCount = 0;
153
- let posInLine = cursorPos;
154
- for (let i = 0; i < lines.length; i++) {
155
- const line = lines[i];
156
- if (!line) continue;
157
- const lineLength = line.length + (i < lines.length - 1 ? 1 : 0); // +1 for \n
158
- if (charCount + lineLength > cursorPos || i === lines.length - 1) {
159
- currentLineIndex = i;
160
- posInLine = cursorPos - charCount;
161
- break;
162
- }
163
- charCount += lineLength;
164
- }
165
- // Move to previous line if possible
166
- if (currentLineIndex > 0) {
167
- const prevLine = lines[currentLineIndex - 1];
168
- const currentLine = lines[currentLineIndex];
169
- if (prevLine && currentLine) {
170
- const prevLineStart = charCount - currentLine.length - 1;
171
- const targetPos = Math.min(posInLine, prevLine.length);
172
- const newCursorPos = prevLineStart + targetPos;
173
- setCursorOffset(newCursorPos - value.length);
174
- }
175
- }
176
- return;
177
- }
178
- if (key.downArrow) {
179
- const cursorPos = value.length + cursorOffset;
180
- const lines = value.split("\n");
181
- // Find which line we're on and our position within it
182
- let currentLineIndex = 0;
183
- let charCount = 0;
184
- let posInLine = cursorPos;
185
- for (let i = 0; i < lines.length; i++) {
186
- const line = lines[i];
187
- if (!line) continue;
188
- const lineLength = line.length + (i < lines.length - 1 ? 1 : 0); // +1 for \n
189
- if (charCount + lineLength > cursorPos || i === lines.length - 1) {
190
- currentLineIndex = i;
191
- posInLine = cursorPos - charCount;
192
- break;
193
- }
194
- charCount += lineLength;
195
- }
196
- // Move to next line if possible
197
- if (currentLineIndex < lines.length - 1) {
198
- const nextLine = lines[currentLineIndex + 1];
199
- const currentLine = lines[currentLineIndex];
200
- if (nextLine && currentLine) {
201
- const nextLineStart = charCount + currentLine.length + 1;
202
- const targetPos = Math.min(posInLine, nextLine.length);
203
- const newCursorPos = nextLineStart + targetPos;
204
- setCursorOffset(newCursorPos - value.length);
205
- }
206
- }
207
- return;
208
- }
209
- // Regular character input and paste detection
210
- // Ink automatically detects paste and sends the whole string at once
211
- if (!key.ctrl && !key.meta && input.length > 0) {
212
- const cursorPos = value.length + cursorOffset;
213
- // Check if this is a paste with more than 3 lines
214
- let contentToInsert = input;
215
- if (input.length > 1) {
216
- // Pasted content (more than 1 char at once)
217
- const lines = input.split("\n");
218
- if (lines.length > 3) {
219
- contentToInsert = `[Pasted +${lines.length} lines]`;
220
- }
221
- }
222
- const newValue =
223
- value.slice(0, cursorPos) + contentToInsert + value.slice(cursorPos);
224
- onChange(newValue);
225
- // Keep cursor at the same relative position
226
- if (cursorOffset < 0) {
227
- setCursorOffset(cursorOffset - contentToInsert.length);
228
- }
229
- }
230
- });
231
- // Reset cursor when value changes externally (e.g., after submit)
232
- React.useEffect(() => {
233
- if (value.length === 0) {
234
- setCursorOffset(0);
235
- }
236
- }, [value]);
237
- // Display the input with cursor
238
- const cursorPos = value.length + cursorOffset;
239
- // Show placeholder if empty
240
- if (value.length === 0) {
241
- return _jsxs(_Fragment, {
242
- children: [
243
- _jsx(Text, { inverse: true, children: " " }),
244
- _jsx(Text, { dimColor: true, children: placeholder }),
245
- ],
246
- });
247
- }
248
- // Show value with cursor
249
- const before = value.slice(0, cursorPos);
250
- const cursor = value[cursorPos] || " ";
251
- const after = value.slice(cursorPos + 1);
252
- return _jsxs(Text, {
253
- children: [before, _jsx(Text, { inverse: true, children: cursor }), after],
254
- });
4
+ export function ReadlineInput({ value, onChange, onSubmit, onEscape, placeholder = "", }) {
5
+ const [cursorOffset, setCursorOffset] = useState(0);
6
+ useInput((input, key) => {
7
+ // Handle Esc: Call escape handler
8
+ if (key.escape) {
9
+ if (onEscape) {
10
+ onEscape();
11
+ }
12
+ return;
13
+ }
14
+ // Handle special keys
15
+ if (key.return) {
16
+ const cursorPos = value.length + cursorOffset;
17
+ // Shift+Enter: Insert backslash and newline
18
+ if (key.shift) {
19
+ const newValue = `${value.slice(0, cursorPos)}\\\n${value.slice(cursorPos)}`;
20
+ onChange(newValue);
21
+ if (cursorOffset < 0) {
22
+ setCursorOffset(cursorOffset - 2);
23
+ }
24
+ return;
25
+ }
26
+ // Check if cursor is at end and last character is backslash (line continuation)
27
+ if (cursorPos === value.length && value.endsWith("\\")) {
28
+ // Remove backslash and add newline (line continuation)
29
+ const newValue = `${value.slice(0, -1)}\n`;
30
+ onChange(newValue);
31
+ setCursorOffset(0); // Move cursor to end
32
+ return;
33
+ }
34
+ // Alt+Enter adds a newline, Enter submits
35
+ if (key.meta) {
36
+ const newValue = `${value.slice(0, cursorPos)}\n${value.slice(cursorPos)}`;
37
+ onChange(newValue);
38
+ if (cursorOffset < 0) {
39
+ setCursorOffset(cursorOffset - 1);
40
+ }
41
+ }
42
+ else {
43
+ onSubmit();
44
+ }
45
+ return;
46
+ }
47
+ if (key.ctrl) {
48
+ // Ctrl+A: Move to beginning of line
49
+ if (input === "a") {
50
+ setCursorOffset(-value.length);
51
+ return;
52
+ }
53
+ // Ctrl+E: Move to end of line
54
+ if (input === "e") {
55
+ setCursorOffset(0);
56
+ return;
57
+ }
58
+ // Ctrl+W: Delete word backward
59
+ if (input === "w") {
60
+ const cursorPos = value.length + cursorOffset;
61
+ const before = value.slice(0, cursorPos);
62
+ const after = value.slice(cursorPos);
63
+ // Find the start of the word to delete
64
+ const match = before.match(/\s*\S*$/);
65
+ if (match) {
66
+ const newBefore = before.slice(0, -match[0].length);
67
+ onChange(newBefore + after);
68
+ setCursorOffset(-after.length);
69
+ }
70
+ return;
71
+ }
72
+ // Ctrl+U: Delete from cursor to beginning of line
73
+ if (input === "u") {
74
+ const cursorPos = value.length + cursorOffset;
75
+ onChange(value.slice(cursorPos));
76
+ setCursorOffset(-value.slice(cursorPos).length);
77
+ return;
78
+ }
79
+ // Ctrl+K: Delete from cursor to end of line
80
+ if (input === "k") {
81
+ const cursorPos = value.length + cursorOffset;
82
+ onChange(value.slice(0, cursorPos));
83
+ setCursorOffset(0);
84
+ return;
85
+ }
86
+ // Ctrl+D: Delete character forward
87
+ if (input === "d") {
88
+ const cursorPos = value.length + cursorOffset;
89
+ if (cursorPos < value.length) {
90
+ onChange(value.slice(0, cursorPos) + value.slice(cursorPos + 1));
91
+ }
92
+ return;
93
+ }
94
+ // Ctrl+B: Move backward one character
95
+ if (input === "b") {
96
+ const cursorPos = value.length + cursorOffset;
97
+ if (cursorPos > 0) {
98
+ setCursorOffset(cursorOffset - 1);
99
+ }
100
+ return;
101
+ }
102
+ // Ctrl+F: Move forward one character
103
+ if (input === "f") {
104
+ const cursorPos = value.length + cursorOffset;
105
+ if (cursorPos < value.length) {
106
+ setCursorOffset(cursorOffset + 1);
107
+ }
108
+ return;
109
+ }
110
+ }
111
+ // Handle backspace
112
+ if (key.backspace || key.delete) {
113
+ const cursorPos = value.length + cursorOffset;
114
+ if (cursorPos > 0) {
115
+ onChange(value.slice(0, cursorPos - 1) + value.slice(cursorPos));
116
+ if (cursorOffset < 0) {
117
+ setCursorOffset(cursorOffset + 1);
118
+ }
119
+ }
120
+ return;
121
+ }
122
+ // Handle left/right arrow keys
123
+ if (key.leftArrow) {
124
+ const cursorPos = value.length + cursorOffset;
125
+ if (cursorPos > 0) {
126
+ setCursorOffset(cursorOffset - 1);
127
+ }
128
+ return;
129
+ }
130
+ if (key.rightArrow) {
131
+ const cursorPos = value.length + cursorOffset;
132
+ if (cursorPos < value.length) {
133
+ setCursorOffset(cursorOffset + 1);
134
+ }
135
+ return;
136
+ }
137
+ // Handle up/down arrow keys for multi-line navigation
138
+ if (key.upArrow) {
139
+ const cursorPos = value.length + cursorOffset;
140
+ const lines = value.split("\n");
141
+ // Find which line we're on and our position within it
142
+ let currentLineIndex = 0;
143
+ let charCount = 0;
144
+ let posInLine = cursorPos;
145
+ for (let i = 0; i < lines.length; i++) {
146
+ const line = lines[i];
147
+ if (!line)
148
+ continue;
149
+ const lineLength = line.length + (i < lines.length - 1 ? 1 : 0); // +1 for \n
150
+ if (charCount + lineLength > cursorPos || i === lines.length - 1) {
151
+ currentLineIndex = i;
152
+ posInLine = cursorPos - charCount;
153
+ break;
154
+ }
155
+ charCount += lineLength;
156
+ }
157
+ // Move to previous line if possible
158
+ if (currentLineIndex > 0) {
159
+ const prevLine = lines[currentLineIndex - 1];
160
+ const currentLine = lines[currentLineIndex];
161
+ if (prevLine && currentLine) {
162
+ const prevLineStart = charCount - currentLine.length - 1;
163
+ const targetPos = Math.min(posInLine, prevLine.length);
164
+ const newCursorPos = prevLineStart + targetPos;
165
+ setCursorOffset(newCursorPos - value.length);
166
+ }
167
+ }
168
+ return;
169
+ }
170
+ if (key.downArrow) {
171
+ const cursorPos = value.length + cursorOffset;
172
+ const lines = value.split("\n");
173
+ // Find which line we're on and our position within it
174
+ let currentLineIndex = 0;
175
+ let charCount = 0;
176
+ let posInLine = cursorPos;
177
+ for (let i = 0; i < lines.length; i++) {
178
+ const line = lines[i];
179
+ if (!line)
180
+ continue;
181
+ const lineLength = line.length + (i < lines.length - 1 ? 1 : 0); // +1 for \n
182
+ if (charCount + lineLength > cursorPos || i === lines.length - 1) {
183
+ currentLineIndex = i;
184
+ posInLine = cursorPos - charCount;
185
+ break;
186
+ }
187
+ charCount += lineLength;
188
+ }
189
+ // Move to next line if possible
190
+ if (currentLineIndex < lines.length - 1) {
191
+ const nextLine = lines[currentLineIndex + 1];
192
+ const currentLine = lines[currentLineIndex];
193
+ if (nextLine && currentLine) {
194
+ const nextLineStart = charCount + currentLine.length + 1;
195
+ const targetPos = Math.min(posInLine, nextLine.length);
196
+ const newCursorPos = nextLineStart + targetPos;
197
+ setCursorOffset(newCursorPos - value.length);
198
+ }
199
+ }
200
+ return;
201
+ }
202
+ // Regular character input and paste detection
203
+ // Ink automatically detects paste and sends the whole string at once
204
+ if (!key.ctrl && !key.meta && input.length > 0) {
205
+ const cursorPos = value.length + cursorOffset;
206
+ // Check if this is a paste with more than 3 lines
207
+ let contentToInsert = input;
208
+ if (input.length > 1) {
209
+ // Pasted content (more than 1 char at once)
210
+ const lines = input.split("\n");
211
+ if (lines.length > 3) {
212
+ contentToInsert = `[Pasted +${lines.length} lines]`;
213
+ }
214
+ }
215
+ const newValue = value.slice(0, cursorPos) + contentToInsert + value.slice(cursorPos);
216
+ onChange(newValue);
217
+ // Keep cursor at the same relative position
218
+ if (cursorOffset < 0) {
219
+ setCursorOffset(cursorOffset - contentToInsert.length);
220
+ }
221
+ }
222
+ });
223
+ // Reset cursor when value changes externally (e.g., after submit)
224
+ React.useEffect(() => {
225
+ if (value.length === 0) {
226
+ setCursorOffset(0);
227
+ }
228
+ }, [value]);
229
+ // Display the input with cursor
230
+ const cursorPos = value.length + cursorOffset;
231
+ // Show placeholder if empty
232
+ if (value.length === 0) {
233
+ return (_jsxs(_Fragment, { children: [_jsx(Text, { inverse: true, children: " " }), _jsx(Text, { dimColor: true, children: placeholder })] }));
234
+ }
235
+ // Show value with cursor
236
+ const before = value.slice(0, cursorPos);
237
+ const cursor = value[cursorPos] || " ";
238
+ const after = value.slice(cursorPos + 1);
239
+ return (_jsxs(Text, { children: [before, _jsx(Text, { inverse: true, children: cursor }), after] }));
255
240
  }
@@ -1,19 +1,13 @@
1
1
  export interface SingleSelectOption {
2
- label: string;
3
- value: string;
4
- description?: string;
2
+ label: string;
3
+ value: string;
4
+ description?: string;
5
5
  }
6
6
  export interface SingleSelectProps {
7
- options: SingleSelectOption[];
8
- selected: string | null;
9
- onChange: (selected: string) => void;
10
- onSubmit: (selected: string) => void;
11
- onCancel?: () => void;
7
+ options: SingleSelectOption[];
8
+ selected: string | null;
9
+ onChange: (selected: string) => void;
10
+ onSubmit: (selected: string) => void;
11
+ onCancel?: () => void;
12
12
  }
13
- export declare function SingleSelect({
14
- options,
15
- selected: _selected,
16
- onChange,
17
- onSubmit,
18
- onCancel,
19
- }: SingleSelectProps): import("react/jsx-runtime").JSX.Element;
13
+ export declare function SingleSelect({ options, selected: _selected, onChange, onSubmit, onCancel, }: SingleSelectProps): import("react/jsx-runtime").JSX.Element;