Repository navigation
Blocks V3: keep the caret in inline text editing when the preview re-renders - #575
Open
wojtekpiskorz wants to merge 1 commit into
Open
wojtekpiskorz wants to merge 1 commit into
wojtekpiskorz wants to merge 1 commit into
Conversation
…renders Typing into an inline editable field fetches the block preview again. React still holds the previous preview's text for the contentEditable element, so the commit writes the new text into its text node, and setting nodeValue moves the selection inside it to offset 0: the next keystrokes land at the start of the field. Wrap the parsed preview in PreserveContentEditableSelection, which reads the selection of the focused inline editable element of the block as character offsets in getSnapshotBeforeUpdate() and restores it in componentDidUpdate(). Adds Jest tests in block-edit.test.js and an E2E test with a fixture block using acf_inline_text_editing_attrs(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Unlinked AccountsThe following contributors have not linked their GitHub and WordPress.org accounts: @wojtekpiskorz. Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When you type into an inline editable field (
acf_inline_text_editing_attrs()), the block fetches its preview again. When that preview renders, the caret jumps to the start of the field, so the next keystrokes land there: typingAAA, pausing, then typingBBBat the end ofAccessiblegivesBBBAccessibleAAA.Cause. The browser edits the contentEditable text itself, so React still holds the text of the previous preview. When the new preview commits, React writes the new text into the text node, even though the DOM already shows it. Setting a text node's
nodeValuemoves any selection inside it to offset 0 (DOM "replace data"). The full analysis is in the issue.What changed
PreserveContentEditableSelectioncomponent (assets/src/js/pro/blocks-v3/components/preserve-content-editable-selection.js) wraps the parsed preview inBlockEditInner.getSnapshotBeforeUpdate()), it reads the selection as character offsets, but only when focus is on an inline editable element ([data-acf-inline-contenteditable]) inside this block.componentDidUpdate()), it puts the selection back if that element still has focus.It is a class component because
getSnapshotBeforeUpdate()is the only way to read the DOM after React renders but before it writes; hooks have no equivalent.I considered keeping React from rewriting the focused element, and rejected it. React rewrites any text it manages, so this would mean taking the element's text out of React's control. While it has focus, the element would then not show what the server renders, for example a value a render template transforms (such as
wptexturize()curling quotes).How to test
tests/e2e/plugins/scf-test-inline-editing-block.phpand add the "SCF Inline Editing Block" to a post.AAA, wait about a second, typeBBB. Before this change:BBBHelloAAA. After:HelloAAABBB.Tests
tests/js/blocks-v3/block-edit.test.js, "inline text editing"): three cases (end of text, middle of text, server text shorter than typed). All three fail on trunk with the caret at offset 0 and pass with this change. Full suite: 38 suites, 962 tests pass.tests/e2e/block-v3-inline-editing.spec.ts, new fixture blockscf/inline-editing-block): typing at the end of one field, and in the middle of another. On trunk they fail withBBBHelloAAAandYWoXrld. With this change they pass on WordPress 7.1.3 (five runs in a row), 6.9 and trunk (7.2-beta1). The full E2E suite passes on 7.1.3 (260 tests); only Chromium was run.The Blocks V3 sources are a readable port of ACF PRO's code, so a later ACF backport that replaces
block-edit.jshas to keep the wrapper.Closes #574
The Blocks V3 code is based on ACF PRO 6.7.0.2, and the ACF changelog up to 6.8.10 lists no fix, so ACF PRO probably has the same bug. Not checked against ACF PRO itself.
Use of AI Tools
This PR was written with Claude Code (Claude Opus 5.5): the root-cause analysis, code, tests and this description. I reviewed the changes and take responsibility for them.
🤖 Generated with Claude Code