Skip to content

fix: preserve undo history when pasting into the chat input#492

Draft
laileni-aws wants to merge 2 commits into
aws:mainfrom
laileni-aws:fix/chat-input-paste-undo
Draft

fix: preserve undo history when pasting into the chat input#492
laileni-aws wants to merge 2 commits into
aws:mainfrom
laileni-aws:fix/chat-input-paste-undo

Conversation

@laileni-aws

Copy link
Copy Markdown
Contributor

Summary

Pasting text into the chat prompt input broke undo: pressing Ctrl/Cmd+Z after a paste did not undo the pasted text correctly. This PR inserts pasted text in a way that participates in the browser's native undo history.

Problem

The prompt input's paste handler prevented the default paste and inserted the clipboard text by manually creating and inserting a DOM text node at the cursor:

e.preventDefault();
const text = e.clipboardData?.getData('text/plain');
// ...
range.insertNode(document.createTextNode(text));

Directly mutating the DOM this way does not add an entry to the browser's undo stack, so after a paste the editor's undo history is inconsistent and Ctrl/Cmd+Z does not undo the paste as expected.

Fix

Insert the pasted text with document.execCommand('insertText', false, text), which performs the insertion through the editing pipeline and records it in the native undo history. If execCommand is unavailable (or returns false), fall back to the previous manual text-node insertion so behavior is preserved in environments that do not support it.

let inserted = false;
try {
  inserted = document.execCommand('insertText', false, text);
} catch {
  inserted = false;
}
if (!inserted) {
  // fallback: manual insertion at the cursor
}

Testing

  • Added unit tests in src/components/__test__/chat-item/prompt-text-input.spec.ts:
    • paste inserts text via execCommand('insertText') (the undo-preserving path) and fires the input event;
    • when execCommand is unavailable, the handler falls back to manual insertion and the text still appears;
    • paste events with no text are ignored.
  • The execCommand test was confirmed to fail against the previous manual-insertion implementation and pass with this change.
  • Full unit test suite passes (npx jest): 844 tests.
  • eslint and prettier --check pass; production build (npm run build) succeeds.

Additional change

  • ui-tests/__test__/flows/quick-action-commands-header.ts: coerced the result of a Playwright evaluate call to a boolean with Boolean(...) before using it in a condition, satisfying @typescript-eslint/strict-boolean-expressions and keeping the repo lint gate green.

Notes

  • document.execCommand is deprecated but remains the only widely supported way to insert text into a contenteditable element while preserving the native undo stack; the fallback keeps the previous behavior where it is not available.

The chat prompt input handled paste by manually inserting a text node
at the cursor, which bypasses the browser's native undo stack. As a
result, undo (Ctrl/Cmd+Z) did not work correctly after pasting.

Insert the pasted text with document.execCommand('insertText'), which
records the change in the undo history, and fall back to the previous
manual insertion when execCommand is unavailable. Adds tests for the
execCommand path, the fallback path, and empty-paste handling.
Keeps the repo lint gate green (strict-boolean-expressions).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant