ink-prompt 0.2.2 → 0.2.3

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.
@@ -73,18 +73,64 @@ export const MultilineInput = ({ value, onChange, onSubmit, placeholder, showCur
73
73
  const terminalWidth = useTerminalWidth(width);
74
74
  const { stdin } = useStdin();
75
75
  const lastRawInput = useRef('');
76
+ const pasteActive = useRef(false);
77
+ const pasteBuffer = useRef('');
78
+ const suppressNextInput = useRef(false);
79
+ const textInput = useTextInput({ initialValue: value ?? '', width: terminalWidth, undoDebounceMs, pasteThreshold, formatPastePlaceholder });
80
+ const textInputRef = useRef(textInput);
81
+ useEffect(() => {
82
+ textInputRef.current = textInput;
83
+ }, [textInput]);
76
84
  useEffect(() => {
77
85
  if (!stdin || !isActive)
78
86
  return;
87
+ const PASTE_START = '\x1b[200~';
88
+ const PASTE_END = '\x1b[201~';
89
+ // Enable bracketed paste mode so terminal-mediated pastes (e.g. Cmd+V on
90
+ // macOS) are wrapped in \x1b[200~ ... \x1b[201~ markers we can detect.
91
+ process.stdout.write('\x1b[?2004h');
79
92
  const handleData = (data) => {
80
- lastRawInput.current = data.toString();
93
+ const str = data.toString();
94
+ lastRawInput.current = str;
95
+ const hasStart = str.includes(PASTE_START);
96
+ const hasEnd = str.includes(PASTE_END);
97
+ if (!pasteActive.current && !hasStart)
98
+ return;
99
+ let remaining = str;
100
+ if (!pasteActive.current && hasStart) {
101
+ pasteActive.current = true;
102
+ pasteBuffer.current = '';
103
+ remaining = remaining.slice(remaining.indexOf(PASTE_START) + PASTE_START.length);
104
+ }
105
+ // Suppress the useInput dispatch for any chunk that participates in a paste.
106
+ suppressNextInput.current = true;
107
+ if (pasteActive.current) {
108
+ const endIdx = remaining.indexOf(PASTE_END);
109
+ if (endIdx === -1) {
110
+ pasteBuffer.current += remaining;
111
+ }
112
+ else {
113
+ pasteBuffer.current += remaining.slice(0, endIdx);
114
+ const pasted = pasteBuffer.current;
115
+ pasteActive.current = false;
116
+ pasteBuffer.current = '';
117
+ // Defer to next tick so the insert isn't tangled with React's
118
+ // current render/dispatch cycle for this stdin chunk.
119
+ queueMicrotask(() => {
120
+ textInputRef.current?.insert(pasted);
121
+ });
122
+ }
123
+ }
81
124
  };
82
125
  stdin.on('data', handleData);
83
126
  return () => {
127
+ process.stdout.write('\x1b[?2004l');
84
128
  stdin.off('data', handleData);
129
+ pasteActive.current = false;
130
+ pasteBuffer.current = '';
131
+ suppressNextInput.current = false;
85
132
  };
86
133
  }, [stdin, isActive]);
87
- const textInput = useTextInput({ initialValue: value ?? '', width: terminalWidth, undoDebounceMs, pasteThreshold, formatPastePlaceholder });
88
134
  const { isPasting, paste: clipboardPaste } = useClipboardPaste({
89
135
  enableImagePaste,
90
136
  maxImageSizeBytes,
@@ -168,6 +214,12 @@ export const MultilineInput = ({ value, onChange, onSubmit, placeholder, showCur
168
214
  paste: handlePaste,
169
215
  };
170
216
  useInput((input, key) => {
217
+ if (suppressNextInput.current) {
218
+ // This stdin chunk is part of a bracketed paste — already handled by the
219
+ // raw 'data' listener. Don't dispatch as keystrokes.
220
+ suppressNextInput.current = false;
221
+ return;
222
+ }
171
223
  log(`[USEINPUT] input="${input.replace(/[\x00-\x1F\x7F-￿]/g, c => `\\x${c.charCodeAt(0).toString(16)}`)}" key=${JSON.stringify(key)} rawLen=${lastRawInput.current?.length || 0}`);
172
224
  handleKey(key, input, textInput.buffer, actions, textInput.cursor, lastRawInput.current, terminalWidth);
173
225
  }, { isActive });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ink-prompt",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "A React Ink component for prompts",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",