Repository navigation
Ghost placeholder + sidebar descriptor for moved blocks - #78412
adamsilverstein wants to merge 15 commits into
Conversation
|
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 If 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. |
d7a8301 to
6cc7282
Compare
|
Size Change: +1.46 kB (+0.02%) Total Size: 7.52 MB 📦 View Changed
|
|
Thanks for the testing and the sharp follow-ups - all three are addressed:
Each change has unit/HOC coverage. Thanks again! |
786095b to
e5f2827
Compare
2ca8de9 to
f2d1c3a
Compare
fd51a25 to
454ce57
Compare
f2d1c3a to
688d72e
Compare
454ce57 to
9d3b2a7
Compare
688d72e to
8b90242
Compare
9d3b2a7 to
c877200
Compare
8b90242 to
b5e52e8
Compare
c877200 to
497eb54
Compare
b5e52e8 to
ce3c626
Compare
497eb54 to
21d380f
Compare
useSelect returns a stable signature string; the index is rebuilt via useMemo only when placement-affecting state changes, avoiding the @wordpress/data 'different values' re-render warning.
A move ghost marks where a block came from by rendering next to the block's old previous sibling. When that sibling is itself pending-moved it still exists in the tree, so the prior `blockExists` check accepted it as an anchor and the ghost followed the sibling to its new position instead of staying at the original spot. Exclude every pending-moved block from anchor selection in `buildMoveGhostIndex` (both the recorded previous-sibling anchor and the first-child fallback), and mirror the exclusion in the overlay move-signature so the memoized index recomputes when only an anchor's moved-state changes.
The move ghost was fully aria-hidden and the destination "Suggested move" tab was a hardcoded English string baked into CSS `content`, so screen-reader users got no signal that a block moved and non-English users saw an untranslated tab. - Ghost: expose it as a `role="note"` with a VisuallyHidden original-position sentence; keep the decorative label/icon/excerpt aria-hidden so the struck-through old content isn't read as live text. - Destination: render the tab text from a `data-suggestion-move-label` attribute (set by the HOC, translated via `__()`) instead of a CSS string literal, and add a VisuallyHidden "Suggested move destination" cue so the move is announced on the canvas, not just in the sidebar. Tests cover the note role, the hidden decorative duplicates, the localized data attribute, and the destination cue.
When a moved block had no surviving sibling in its old parent (it was an only child, or every sibling also moved away), the ghost had nothing to anchor to and silently disappeared, leaving no original-position cue for that case. Add an `insideParent` index keyed on the old parent so the ghost renders just below the now-empty container. It's skipped at the root (no parent block to anchor on) and when the old parent is itself gone or pending-moved (anchoring there would drag the ghost to the parent's destination, the same displacement the anchor guard already prevents). The overlay move-signature gains a parent-usable bit so the memoized index recomputes when only the parent's existence or moved-state changes. Unit tests cover the only-child fallback, the all-siblings-moved case, the moved/removed-parent guard, and the root no-op; an HOC test asserts the ghost renders below the emptied parent.
…nchor-guard commit Commit 44a4ef2 (the move-ghost anchor guard) inadvertently staged 11 unrelated files left over from a stray lint --fix pass, including a broken edit to resizable-frame (an eslint-disable directive was removed, leaving an empty JSX expression) and removed playwright-await disables in perf-utils. Restore all 11 files to their pre-suggestion state; none of them belong to the move-ghost feature.
ce3c626 to
55be6bc
Compare
21d380f to
43ec8b0
Compare
|
Superseded by the fresh-stack restructure of Suggest mode (#73411). The feature has been re-sliced from this 16-deep stack onto current
The whole feature now sits behind a Suggestion Mode experiment (Settings → Experiments → Collaboration). Closing in favour of the new stack — details: #73411 (comment) |

Closes #78409. Stacked on #77979 (base branch
suggest-mode-6c-move-ui).What
Follow-up to the structural-suggestion stack, addressing review feedback from @saroshaga on #77979: a block-move suggestion previously only decorated the block at its new position, and the sidebar text was vague ("Moved <block> from a previous block to a different block").
This PR adds:
--suggestion-author-colorvariable so it visually pairs with the decorated block at the destination.BlockMoveDiffnow computes direction/distance from the capturedfromIndexvs. the live index: "Moved up 3 blocks" / "Moved down 1 block" for same-parent moves, "Moved into Group" / "Moved to top level" for cross-parent moves.How
Presentational only — no block-editor store mutation, nothing syncs via CRDT. The block continues to exist exactly once in the tree.
move-ghost-index.js— purebuildMoveGhostIndexturning pending-move markers into an{ after, before }anchor index (null-anchor / first-child and missing-anchor fall back to the old parent's first sibling; empty old parent → no ghost).overlay-context.js— a single O(n) scan inSuggestionOverlayProviderexposes the index on context (a stable signature string keepsuseSelectreferentially stable; the index rebuilds viauseMemoonly on placement-affecting changes), avoiding an O(n²) per-block scan.with-suggestion-overlay.js— the existingwithSuggestionBlockClassNameHOC renders<SuggestionMoveGhost>siblings around the anchor block.suggestion-move-ghost.js— the presentational ghost (aria-hidden,pointer-events: none, never in the block list).content-suggestion.scss— canvas-loaded ghost styling reusing the stack's suggestion-color tokens.suggestion-diff.js— exported puredescribeMove+ rewrittenBlockMoveDiff.Out of scope (deferred)
A drawn connector/arrow between the ghost and the destination is intentionally not included — it needs an SVG overlay spanning two DOM positions inside the scrolling iframe canvas (reposition on scroll/resize), a separate risk profile. Tracked for later evaluation in #78409.
Testing
Refs #77434, #77979.