Repository navigation
Editor: Preserve unsent note drafts when switching blocks - #80482
adamsilverstein wants to merge 13 commits into
Conversation
Starting a note and selecting another block silently discarded the draft. Stash unsent note content in a new noteDrafts map in the editor store, keyed per block for new notes and per thread for replies, so every form caches its own draft and multiple drafts can coexist. Reopen the new note form when selection returns to a block with a stashed draft, keep the floating sidebar mounted while drafts exist so that transition logic stays alive, and skip the deferred focus-outside dismissal when block selection has already moved on so it cannot close a form the transition logic just reopened. Cancel and successful submission discard the draft; implicit dismissal keeps it. Claude-Session: https://claude.ai/code/session_01QenttpdKEur99wPv3D7iUy
|
Size Change: +312 B (0%) Total Size: 7.91 MB 📦 View Changed
|
|
Flaky tests detected in a3deb5c. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/31743411578 adds and activates a new tab when pressing Enter at the end of a tab label in
|
|
Tested! Confirms the fix works as expected. Draft note content is preserved when switching between blocks; returning to a block with an unsent draft reopens the form with the draft intact. One thing I noticed: selecting a note shows a dimming overlay on the rest of the canvas. Not sure if this is pre-existing behavior unrelated to this PR, flagging in case it's useful. Screen.Recording.2026-07-24.at.7.45.09.AM.mov |
|
Thanks for testing and capturing the screencast @noruzzamans - very helpful! |
…afts # Conflicts: # packages/editor/src/components/collab-sidebar/note-form.js
|
Let's punt this to 7.2. |
…afts # Conflicts: # packages/editor/src/components/collab-sidebar/note-form.js
Trunk removed note-form.js's dataviews private-API usage and with it the lock-unlock import, but this branch still unlocks the editor store to reach the private setNoteDraft action and getNoteDraft selector.
The template registration tests reach for the "Template options" button without ensuring the document settings sidebar is open, so they depend on whatever sidebar state an earlier spec in the same shard happened to leave behind. When shard packing puts a spec that closes the sidebar ahead of this one, the button is never rendered and the tests time out. Open the sidebar explicitly via the existing idempotent helper.
…:WordPress/gutenberg into fix/preserve-note-drafts
Pick up three weeks of trunk so the branch builds and lints against the current toolchain (Prettier 3.9.6, the Jest jsdom test split, and the new changelog validator) and to clear the failing "Required changes from trunk" check. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XymJGmRuNKwf8srrtsrcLR
🤖 PR meta 🤖🎉 PropsIf you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. Updated as activity occurs, without notifying anyone named here. Add the 📦 Bundle sizeSize Change: +354 B (0%) Total Size: 8.25 MB 📦 View Changed
⚡ PerformanceShow the resultsClient side metrics exclude the server response time. front-end-block-theme
front-end-classic-theme
media-processing
media-upload
post-editor
site-editor
🏁 Flaky testsSome tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information. refuses the drop and uploads nothing in
|
|
Tested & can confirm that the patch still fixes the issue. Same behavior as described by #80482 (comment) Screen.Recording.2026-09-30.at.5.19.04.PM.mov |
…afts # Conflicts: # packages/editor/src/components/collab-sidebar/index.jsx # packages/editor/src/components/collab-sidebar/notes.jsx
|
Closing in favor of #84110. Thanks for the testing here. |
What?
Closes #73473.
Supersedes #75030 - rebuilt on top of the current notes architecture (floating notes,
selectNotestore state,useFocusOutsidedismissal). Props @Mustafabharmal for the original approach.Preserves unsent note drafts when focus moves away from a block, and caches one draft per block (plus one per reply thread) so multiple drafts can be kept at the same time, similar to Google Docs.
Why?
Starting a note and clicking another block silently discarded whatever was typed. As raised in this comment, a fix should also cache multiple drafts - one per block - rather than only the most recent one. (The other repro from #73473, losing the draft on window/tab switch, was already fixed on trunk by the
useFocusOutsidemigration in #80222, which ignores window blur.)How?
noteDraftsstate in the editor store (privatesetNoteDraftaction,getNoteDraftselector): a map of draft key → content. New-note drafts are keyed per block (new-note-${clientId}), reply drafts per thread (reply-${noteId}), so every form caches its own draft independently.NoteFormgains an optionaldraftKeyprop: it restores the stashed draft on mount, stashes edits as you type, clears the draft on successful submit, and treats Cancel/Escape as an explicit discard. Dismissing the form implicitly (focus-out) keeps the draft.notes.jsreopens the new-note form so the draft surfaces again, like a saved thread would. Stored drafts also keep the floating sidebar enabled (newhasNoteDraftsselector) so that transition logic stays mounted while a draft is waiting.AddNoterace fix: switching selection directly from an open form on one draft-carrying block to another produces a'new' → 'new'note-selection transition, which the deferreduseFocusOutsideblur callback couldn't distinguish from a plain dismissal - it would instantly close the reopened form. The form now records which block owns focus at focus time and skips the deferred dismissal when block selection has moved on, leaving the decision to the block-transition logic.NoteFormis also keyed byclientIdso each block's form remounts with its own draft.Testing Instructions
The new behavior is covered by a
Draft persistencegroup intest/e2e/specs/editor/various/block-notes.spec.jsand unit tests for thenoteDraftsreducer.