Repository navigation
Keep a contenteditable's edits after it loses focus - #212
Conversation
With preserveChanges, an editing host the user edited keeps its children, like a focused one. The browser keeps no dirty flag for contenteditable, so an input listener on the document notes the editing hosts the user edits. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ty1qRyEwpQjwuLDTJTSb59
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Firefox types after the last element when the caret follows it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ty1qRyEwpQjwuLDTJTSb59
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fb8bda6bc7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
isContentEditable throws for SVG and MathML elements, which a preserving morph visits once any edit was seen. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ty1qRyEwpQjwuLDTJTSb59
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a27f8383d7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ty1qRyEwpQjwuLDTJTSb59
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 750ed8b2b3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| document, | ||
| "input", | ||
| (event) => { | ||
| if (!event.isTrusted) return |
There was a problem hiding this comment.
Distinguish trusted scripted edits from user input
In browsers implementing editing commands, application code such as document.execCommand("insertText", false, value) generates an input event whose isTrusted value is true, so this guard marks a script-modified editor and later prevents server markup from replacing it. Unlike the already-covered dispatchEvent case, the fresh evidence is that the execCommand algorithm explicitly creates a trusted input event; therefore trust alone does not establish that the user edited the content.
AGENTS.md reference: AGENTS.md:L31-L31
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Leaving this as is. In practice, execCommand runs because of a user action, like a rich-text toolbar's bold button or a paste handler, and those edits are the user's too, so keeping them is what we want. An app that rewrites an editor through execCommand without the user asking, and then expects server markup to replace that, is unusual. morphlex-clobber covers it.
Generated by Claude Code
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ty1qRyEwpQjwuLDTJTSb59
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 59311e8b12
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Form controls also get trusted input events, and keep their own record of the user's changes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ty1qRyEwpQjwuLDTJTSb59
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: db806455ac
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
A form control inside an editor inherits isContentEditable but isn't an editing host. Elements inside an editor no longer each walk up to it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ty1qRyEwpQjwuLDTJTSb59
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 059077ca41
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Requested by Joel · project thread
Before: with
preserveChanges, a contenteditable only kept what the user typed while it was focused. Typing a note and then clicking a Save button blurs the editor, so the morph that follows reset the note to the server's markup.After: a contenteditable the user edited keeps its content under
preserveChanges, focused or not, just like a typed input keeps its value. Untouched editors, and editors changed only by script, still follow the markup, andmorphlex-clobberstill lets the server replace an edited one.The browser keeps no dirty flag for contenteditable, so morphlex now adds one capturing
inputlistener to the document when it loads and notes the editing hosts that get aninputevent (the first node of its composed path, so editors in shadow roots count). Joel picked this over keeping every editor.How:
visitChildNodesalready pins the children of the focused editor. It now also pins them when the element is, or is inside, a noted editing host that's stillisContentEditable. The check is skipped entirely until the firstinputevent.Known limit, shared with the existing focused-editor behaviour: the editor's old content isn't known, so among identical unkeyed sibling editors an untouched one can take the edited one's target and the two swap places (content is kept either way). An id avoids it.
Benchmark vs main (perf-sweep harness, Chromium, 15 rounds): all scenarios within noise, from -11% to +5%.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Ty1qRyEwpQjwuLDTJTSb59
Generated by Claude Code