Skip to content

Fix/79643 rtc awareness mixed block selection - #79836

Merged
ingeniumed merged 20 commits into
WordPress:trunkfrom
giteshsarvaiya:fix/79643-rtc-awareness-mixed-block-selection
Aug 5, 2026
Merged

ingeniumed merged 20 commits into
WordPress:trunkfrom
giteshsarvaiya:fix/79643-rtc-awareness-mixed-block-selection

Conversation

@giteshsarvaiya

@giteshsarvaiya giteshsarvaiya commented Jul 2, 2026 •

Copy link
Copy Markdown
Contributor

What?

Closes #79643

Fixes RTC selection awareness for multi-block selections that span mixed block types (e.g. paragraph → image, heading → video). Previously the overlay rendered nothing when a collaborator's selection included any block without a RichText field. After this PR, text blocks show a semi-transparent fill overlay and non-text blocks show a CSS outline border, with a single avatar on the topmost block.

Why?

When a collaborator selects across multiple blocks, the awareness system sends two endpoints — one for each side of the selection. Both endpoints were treated identically, as if they always carried a character-level cursor position. Blocks without a RichText field (image, spacer, button, etc.) have no character position, so resolving the endpoint threw and the overlay silently produced nothing for the entire selection.

Beyond fixing the immediate bug, this PR also makes the collaborators overlay significantly more maintainable going forward:

  • Type safety at the data layer: the new SelectionEndpoint discriminated union means TypeScript will catch any misuse at compile time. Before this PR, a caller could pass a text cursor position to code expecting a block position with no error — the failure only surfaced at runtime in the overlay.
  • Dead code removed: getFullBlockSelectionRects and an always-empty MultiBlockResult.rects field were removed rather than left dormant.
  • Consistent naming: CursorEndpoint / WholeBlockEndpoint align with the existing SelectionType.Cursor / SelectionType.WholeBlock enum values already used throughout the codebase.
  • Documented non-obvious decisions: the Yjs anchoring strategy, direction-normalisation requirement, and avatar placement rule are now explained inline.

Visual approach: why not CSS outline for all blocks?

An earlier version of this PR used a CSS outline (is-collaborator-selected class + --collaborator-outline-color) applied uniformly to every block in the selection range. This was simple to implement but had meaningful drawbacks. The current PR uses a two-track approach instead.

CSS outline only (previous approach)

Pros Simple — one rendering mechanism for all block types. Works regardless of block content or type. No dependency on DOM Range API or font rendering.
Cons A thin border around a block does not read as "selected" — users expect a fill for selected content, not just a border. Does not match what the doer sees (they see a blue fill; the observer saw a box). The entire last block was shown as selected even when only a partial selection reached into it, making the overlay misleading for long paragraphs.

Mixed overlay + border (current approach)

Pros Text blocks get a semi-transparent fill (15% opacity) that reads unmistakably as "selected content." Non-text blocks (image, spacer) get a CSS border — correct, because you cannot meaningfully highlight text inside an image. The last block in the selection shows only the selected portion via text-level DOM Range rects, so the visual accurately mirrors what the doer selected. Overall closer to how every other collaborative editor (Google Docs, Notion, Figma) represents remote selections.
Cons Two rendering paths add complexity. Text block detection uses innerText.trim() as a heuristic — an empty paragraph block would be treated as a non-text block and shown with a border instead of a fill. Partial text-level rects for the last block depend on the DOM Range API and a fallback element-resolution chain, which could theoretically fail for unusual custom blocks.

The heuristic tradeoffs are acceptable: empty blocks carry no content to highlight, and the fallback chain ([data-wp-block-attribute-key] → [contenteditable] → p/h1-h6/…) covers all standard Gutenberg blocks.

Bugs fixed

Mixed-type multi-block selection renders nothing — When the selection spanned a non-text block (image, spacer, video), the overlay produced nothing. The root cause: both endpoints were resolved as if they always carried a character-level cursor position. Non-text blocks have no Y.Text anchor, so getCursorPosition returned null and the entire selection was dropped silently. Fixed by introducing a SelectionEndpoint discriminated union (CursorEndpoint / WholeBlockEndpoint) so each endpoint is resolved via the correct anchor type independently.

WholeBlock keyboard selection as an endpoint renders nothing — Selecting an image block via keyboard (Alt+click / arrow navigation) produces a WholeBlockEndpoint with no character offset. use-render-cursors had no branch for this — it fell through to single-block logic, resolveSelection threw, and the selection was dropped. Fixed by the same discriminated union: WholeBlockEndpoint is now resolved via its Y.Array slot position rather than a Y.Text offset.

Ctrl+A (select entire post) not visible to collaborators — Ctrl+A produces a SelectionInMultipleBlocks with WholeBlockEndpoint on both sides. The overlay had no path for this combination — the entire selection was silently dropped, so collaborators saw nothing. Fixed as a consequence of the two changes above: both endpoints are now resolvable regardless of block type.

Backward selection also works — All three fixes above apply regardless of selection direction. Endpoints are normalised to DOM order internally before any rect computation, so dragging from image → paragraph is identical to paragraph → image on the observer's side.

List block showing per-item stripes instead of one unified highlight — When a selection endpoint lands inside a list, Yjs resolves it to the specific core/list-item (the innermost block with a Y.Text), not the parent core/list. The sibling list-items between that endpoint and the other selection end then appeared as individual middle blocks, each getting its own fill rect, producing a striped banded look rather than one rect covering the whole list.

The fix promotes each endpoint to its nearest [data-block] ancestor before computing rects:

// cursor-dom-utils.ts — new helper
export const blockContainerOf = ( el: HTMLElement ): HTMLElement =>
    el.parentElement?.closest< HTMLElement >( '[data-block]' ) ?? el;

blockContainerOf walks up the DOM from the resolved endpoint element and returns the nearest element with a data-block attribute — the parent block. If the element is already a top-level block it returns itself unchanged.

Applied in computeMultiBlockOverlayRects:

const effectiveFirstEl = blockContainerOf( docFirstEl ); // list-item → list block
const effectiveLastEl  = blockContainerOf( docLastEl  ); // paragraph → itself (no parent)

const middleEls = getBlocksBetween( effectiveFirstId, effectiveLastId, editorDocument )
    .filter( el => ! effectiveFirstEl.contains( el ) && ! effectiveLastEl.contains( el ) );

With effectiveFirstEl = the list block, getBlocksBetween(listId, joId) returns the list-items in the DOM range — but the .filter removes every element the list block .contains(), which is all of them. middleEls becomes empty. The list block is then rendered as a single full bounding-box rect covering all its items.

When both endpoints promote to the same container (e.g. selecting from list-item 1 to list-item 3, all inside one list), an early return emits exactly one rect for the container:

if ( effectiveFirstId && effectiveFirstId === effectiveLastId ) {
    return effectiveFirstEl.innerText?.trim()
        ? { selectionRects: [ blockBoundingRect( effectiveFirstEl, overlayRect ) ] }
        : {};
}

Approaches considered and rejected:

  1. Skip descendants of start/end elements in getBlocksBetween — Would work when the list block itself is the endpoint, but not when a list-item is the endpoint: siblings of a list-item are not its descendants, so no filtering would occur.

  2. Post-process middleEls to merge consecutive items with the same [data-block] parent — Works but requires an extra DOM traversal per middle block and couples the merging logic to the iteration order. More moving parts for the same outcome.

  3. Promote before DOM-order normalization — Direction normalization uses the raw endpoint elements for isNodeBefore comparison. Promoting first would compare container elements, which could give wrong ordering when both endpoints share the same container.

The chosen approach — promote after normalization, filter descendants, check equality — is one helper function, two .contains() calls, and one equality check. It generalises to any nesting depth (columns inside groups, etc.) without additional code.


Video of behavior before this PR

before.mp4

Video of behavior after this PR

after-fixing-multiselect.mp4

How?

The fix is split across 5 commits, layered from the data model up to the overlay rendering.


Commit 1 — core-data: add CursorEndpoint/WholeBlockEndpoint discriminated union

Introduces a SelectionEndpoint discriminated union so the receiver knows how to resolve each side of a multi-block selection:

  • CursorEndpoint (kind: 'cursor'): the endpoint lands inside a RichText field with a known character offset. Anchored to a Y.Text relative position. Any block type can produce this — a paragraph mid-word, a table cell, a heading.
  • WholeBlockEndpoint (kind: 'whole-block'): no character offset — either the block has no RichText field (image, spacer) or it is selected as a whole block via keyboard. Anchored to the block's slot in its parent Y.Array.

getSelectionEndpoint tries a Y.Text anchor first; if the selection carries no character offset it falls back to the Y.Array slot anchor.

Also updates all test fixtures and assertions to use the renamed endpoint types.


Commit 2 — editor: fix getBlocksBetween to skip blocks already covered by a parent

getBlocksBetween previously returned all [data-block] elements between the two endpoints, including nested ones. Selecting a list block would return both the list and each of its list items, causing every item to be double-highlighted.

The fix: skip any block element that is a descendant of a block already in the result. JSDoc updated to reflect the new behaviour.


Commit 3 — editor: handle SelectionInMultipleBlocks in the collaborators overlay

The main fix. Three files change together as one logical unit:

use-render-cursors — a dedicated branch now resolves each endpoint independently via its kind discriminant, avoiding the throw that occurred for non-text endpoints.

compute-selection — the multi-block path is wired up; no cursor coords are emitted (avatar comes from use-block-highlighting only). MultiBlockResult.rects (always empty) and getFullBlockSelectionRects (no callers) are removed as dead code.

use-block-highlighting — extended to cover SelectionInMultipleBlocks. Resolves start/end block IDs, normalises to DOM order, collects intermediate blocks via getBlocksBetween, applies highlights, and places the avatar on the topmost block only. Non-obvious decisions (Yjs direction normalisation, avatar placement rule, as any cast) are documented inline.


Commit 4 — editor: mixed visual treatment for multi-block awareness (overlay + outline)

Replaces CSS-outline-only highlighting with a two-track visual system:

Text blocks (innerText.trim() is non-empty — paragraph, heading, list, etc.):

  • Full bounding-box semi-transparent fill (15% opacity) via selectionRects
  • First block: full bounding-box when cursor starts at offset 0; partial text-level rects when it starts mid-block
  • Middle blocks: always the full bounding-box
  • Last block: always partial text-level rects from 0 to the cursor offset, so the unselected tail is not covered

Non-text blocks (image, spacer — innerText empty):

  • CSS is-collaborator-selected outline only; no fill so image content is not obscured

Also in this commit:

  • Stale CSS class bug fixed: is-collaborator-selected is reset for every block on each render before being conditionally re-applied, preventing it from persisting when a block transitions between selection types
  • resolveTargetElement gets a richer fallback chain ([data-wp-block-attribute-key] → [contenteditable] → p/h1–h6/pre/blockquote/…) so partial text rects work even when the block is not actively focused by the observer
  • Text block detection uses innerText.trim() because [contenteditable="true"] and [data-wp-block-attribute-key] are absent on blocks the observer has not clicked into

Commit 5 — editor: promote inner blocks to container for multi-block highlights

Fixes the list-item striping bug described in Case 4 above. See the Case 4 section for a detailed explanation of the root cause, the fix, and the approaches considered.

Key additions:

  • blockContainerOf helper exported from cursor-dom-utils — single responsibility, reused in both compute-selection and use-block-highlighting
  • Promotion applied to both endpoints before getBlocksBetween and before building the CSS outline block list, so both the fill-overlay path and the CSS-border path treat the container as one unit
  • Same-container equality check prevents emitting two rects when both endpoints happen to be inner blocks of the same parent

After running /code-review in a Claude Code (Sonnet 4.6) session, four additional bugs were found and fixed:

Commit 6 — isNodeBefore bitmask

compareDocumentPosition returns a bitmask, not an exact value. The strict
=== Node.DOCUMENT_POSITION_FOLLOWING check (=== 4) returned false when b
was a following descendant of a (result is 4 | 16 = 20), silently skipping
DOM-order normalization for nested endpoint pairs. Fixed with a bitwise AND check.

Commit 7 — blockContainerOf over-promotion

el.parentElement?.closest('[data-block]') walked arbitrarily far up the ancestor
chain. A core/list inside core/group has a non-[data-block] wrapper div
between them, so closest() would skip past the list and promote to the group —
wrong block highlighted. Fixed by checking only the immediate parentElement.

Commit 8 — null endpoint guard in use-block-highlighting

When an endpoint block is absent from the DOM (concurrent deletion),
effectiveFirstEl was null. null?.contains(el) returns undefined,
!undefined is true, so every intermediate block passed the containment
filter — spuriously highlighting the entire range. Fixed with an early return
when either endpoint element is missing.

Commit 9 — move inner-block promotion to use-render-cursors

computeMultiBlockOverlayRects is a pure computation function; DOM-based
inner-block promotion was an architectural mismatch. Moved the promote step to
use-render-cursors where resolved endpoints are built, before
computeSelectionVisual is called. computeMultiBlockOverlayRects now receives
container-level IDs directly and drops the effectiveFirstEl/wasPromoted
variables.


Testing Instructions

  1. Start wp-env with RTC enabled and open a post with paragraphs, an image block, and a heading.
  2. Open the same post in a second browser window as a different user.
  3. In window 1, drag a selection from the paragraph through the image into the heading.
  4. In window 2, verify:
    • Paragraph and heading show a semi-transparent fill overlay
    • Image block shows a CSS border outline (no fill)
    • Avatar appears on the topmost selected block only
  5. In window 1, drag a selection that ends partway through a long paragraph.
  6. In window 2, verify only the selected portion of the paragraph is highlighted — the unselected tail has no overlay.
  7. Drag in reverse (heading → paragraph) — result should be identical to step 4.
  8. Press Ctrl+A in window 1. In window 2, verify all blocks show the appropriate highlight.
  9. In window 1, drag a selection from a paragraph through a list block into another paragraph.
  10. In window 2, verify the list block shows as one unified fill rect — not one rect per list item.
  11. Verify no regressions:
    • Single-block text selection still shows highlight rects and a cursor label
    • Selecting a single image block (whole-block selection) still shows CSS outline and avatar
    • A cursor with no selection still shows the cursor label

Known issue discovered during testing

Reproduction: User A has a multi-block selection active. User B (the observer) deletes the first or last block of that selection. On User B's screen, the entire awareness overlay for User A disappears — both the selection highlight and the avatar. On User A's screen, their own selection also clears shortly after (once Yjs syncs the deletion).

Root cause — two contributing layers, both pre-existing:

  1. Rendering layer: When an endpoint block is deleted from the DOM, computeMultiBlockOverlayRects can no longer find it by [data-block] selector and returns {}, clearing all rects. This is the same defensive early-return behaviour trunk already uses for single-block WholeBlock selections — deleting a keyboard-selected block causes its CSS outline to disappear there too. Deleting a middle block does not trigger this — only the first or last block (the selection endpoints) causes the early return.

  2. Yjs layer: Once the deletion syncs to User A, their Y.RelativePosition anchor for the deleted endpoint block can no longer be resolved. resolveSelection throws, the try/catch swallows it silently, and awareness clears on User A's side too. This exists on trunk independently of this PR.

Question for reviewer: Should this be fixed here, or tracked as a separate issue?

Arguments for fixing here: the rendering-layer half of the bug is in code directly touched by this PR. A partial fix — falling back to the remaining valid blocks when an endpoint block is deleted — could be made here without touching the Yjs layer.

Arguments for a separate issue: fully eliminating the bug also requires fixing the Yjs Y.RelativePosition resolution on User A's side, which is out of scope for a rendering-focused PR. Tracking the full fix as a follow-up keeps this PR focused.

I feel I should open a separate issue, hence I am opening one, but thats just what I think, let me know your thoughts.

Edit: the new issue at #79867

Notes

  • getBlocksBetween behaviour changed (descendant filtering). It has no callers outside the overlay folder and is not in the editor package's public API barrel — low risk.
  • getFullBlockSelectionRects was removed. Same scope caveat.
  • This PR does not fix RTC: Awareness redraws are not immediate on window resize events #79645 (details block awareness) — that is a separate issue and will be a follow-up PR.

Use of AI Tools (updated)

This PR was developed with AI assistance (Claude Code, Sonnet 4.6) across two sessions:

  • Initial implementation: feature development, bug investigation, and commit structuring.
  • Post-implementation review: the /code-review command in Claude Code surfaced 6 findings (3 correctness bugs, 1 null-safety bug, 2 efficiency/architecture issues). Bugs 1–3 and the architectural finding were fixed in commits 6–9 above. The two efficiency findings (getBlocksBetween O(n²) scan and missing loop break) were deferred as low-priority given realistic document sizes.

All changes were reviewed and verified by me before submission.

@github-actions github-actions Bot added [Package] Core data /packages/core-data [Package] Editor /packages/editor First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository labels Jul 2, 2026
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

👋 Thanks for your first Pull Request and for helping build the future of Gutenberg and WordPress, @giteshsarvaiya! In case you missed it, we'd love to have you join us in our Slack community.

If you want to learn more about WordPress development in general, check out the Core Handbook full of helpful information.

@giteshsarvaiya
giteshsarvaiya force-pushed the fix/79643-rtc-awareness-mixed-block-selection branch from 4a1a626 to f082230 Compare July 4, 2026 08:57
…for multi-block selections

Introduces a SelectionEndpoint discriminated union to distinguish between two
kinds of selection endpoints in a multi-block selection:

- CursorEndpoint (kind: cursor): the endpoint lands inside a RichText field
  and carries a character-level Y.Text relative position. Any block type that
  has a text field with a known offset produces this shape.

- WholeBlockEndpoint (kind: whole-block): the endpoint has no character
  offset, either because the block has no RichText field (e.g. image, spacer)
  or it is selected as a whole block via keyboard block-selection mode. The
  anchor is pinned to the block slot in its parent Y.Array instead.

Previously both endpoint shapes were treated identically, which caused the
overlay to break when a selection spanned mixed block types (e.g. paragraph
to image) because the receiver tried to resolve a text cursor on a block that
has no Y.Text.
When a selection spans a list block, getBlocksBetween previously returned
both the list and each of its list items, causing every item to receive a
duplicate CSS outline on top of the one already applied to the parent.

The fix filters out any block element that is a descendant of a block
already collected, so each region is highlighted exactly once regardless
of nesting depth.
Fixes RTC selection awareness breaking when a collaborator selects across
blocks of different types (e.g. a paragraph into an image).

Before this change, multi-block selections fell through to the same code
path as single-block text selections, which tried to resolve a RichText
cursor on every endpoint. Non-text blocks have no Y.Text anchor, so the
resolution threw and the overlay rendered nothing.

Changes:
- use-render-cursors: adds a dedicated branch for SelectionInMultipleBlocks
  that resolves each endpoint independently via its kind (cursor vs
  whole-block), so mixed-type combinations resolve correctly.

- compute-selection: simplifies the multi-block path to return only the
  cursor position at the active end. Pixel-level selection rects across
  multiple blocks are replaced by a CSS outline approach (see below), so
  this function no longer needs to compute them.

- use-block-highlighting: extended to cover SelectionInMultipleBlocks.
  Every block in the selection range receives the is-collaborator-selected
  CSS class and a --collaborator-outline-color custom property. The avatar
  label is placed on the topmost block in document order only, avoiding
  one label per block per collaborator.
@
editor: mixed visual treatment for multi-block awareness (overlay + outline)

Replaces the earlier CSS-outline-only approach with a two-track visual
system that more closely mirrors how a selection looks to the person making it:

Text blocks (paragraph, heading, list, etc.):
  - Full bounding-box semi-transparent fill overlay via selectionRects
  - First block gets a full bounding-box when the selection starts at offset 0;
    partial text-level rects (cursor offset → end) when it starts mid-block
  - Middle blocks always get the full bounding-box fill
  - Last block always uses text-level rects (0 → cursor offset) so only the
    selected portion is highlighted, not the unselected tail

Non-text blocks (image, spacer, etc.):
  - CSS outline border only (is-collaborator-selected class +
    --collaborator-outline-color custom property)
  - No fill overlay so image content is not obscured

Additional fixes included:
  - Stale CSS class bug: is-collaborator-selected is now reset for every
    block on each render before being conditionally re-applied, preventing
    it from persisting when a block transitions between selection types
  - resolveTargetElement gains a richer fallback chain (contenteditable →
    common text elements p/h1-h6/etc.) so partial text rects work correctly
    even when the observer has not focused the block
  - Text block detection uses innerText.trim() instead of querying
    [contenteditable] or [data-wp-block-attribute-key], which are absent on
    blocks the observer has not clicked into
@
@giteshsarvaiya
giteshsarvaiya force-pushed the fix/79643-rtc-awareness-mixed-block-selection branch from f082230 to ef1fbd2 Compare July 4, 2026 11:55
When a multi-block selection starts or ends inside an inner block (e.g. a
list-item inside a list), the sibling inner blocks between the endpoint and
the other selection end appeared as individual middle blocks — each getting
its own fill rect, producing a striped banded look instead of one rect
covering the whole list.

Fix: promote each selection endpoint to its nearest [data-block] ancestor
before computing rects and block highlights. Middle blocks that are
descendants of the promoted container are filtered out. When both endpoints
promote to the same container (e.g. two list-items inside one list), a
single bounding-box rect is emitted for that container.

Adds a blockContainerOf helper to cursor-dom-utils and applies the
promotion in both compute-selection and use-block-highlighting.
@giteshsarvaiya
giteshsarvaiya marked this pull request as ready for review July 5, 2026 12:17
@giteshsarvaiya
giteshsarvaiya requested a review from nerrad as a code owner July 5, 2026 12:17
@github-actions

github-actions Bot commented Jul 5, 2026 •

Copy link
Copy Markdown

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 props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: giteshsarvaiya <giteshsarvaiya@git.wordpress.org>
Co-authored-by: alecgeatches <alecgeatches@git.wordpress.org>
Co-authored-by: ingeniumed <ingeniumed@git.wordpress.org>
Co-authored-by: t-hamano <wildworks@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@giteshsarvaiya

Copy link
Copy Markdown
Contributor Author

@props-bot refresh

@giteshsarvaiya
giteshsarvaiya marked this pull request as draft July 5, 2026 18:02
@giteshsarvaiya

Copy link
Copy Markdown
Contributor Author

Hi @nerrad ! I'm working on this issue — the bugs reported by @alecgeatches are now resolved.
I'm currently testing to confirm no new regressions are introduced by the PR. So far, I've tested all the edge cases I could think of and haven't found any new issues. I'll take one more day to finish verifying before converting this out of Draft.
In the meantime, feel free to check out the PR — it already implements the fix for the reported bugs.

@giteshsarvaiya
giteshsarvaiya marked this pull request as ready for review July 8, 2026 08:24
compareDocumentPosition returns a bitmask. When b is a following
descendant of a the result is FOLLOWING | CONTAINED_BY (4 | 16 = 20),
not 4. The strict === 4 check returned false, silently skipping the
start/end swap for any endpoint pair where one element is nested inside
the other (e.g. a list-item resolved before blockContainerOf runs).

Fix: use a bitwise AND so any value with the FOLLOWING bit set returns true.
The previous closest('[data-block]') call walked arbitrarily far up the
ancestor chain. A core/list nested inside core/group has a non-[data-block]
wrapper div between them, so closest() would skip past the list and
promote to the group — wrong block gets highlighted.

The correct scope is the immediate parentElement: if the direct parent is
itself a [data-block] element (as in list-item → list), promote; otherwise
leave the element as-is.
When an endpoint block is absent from the DOM (e.g. deleted by a
concurrent edit), the previous code set effectiveFirstEl/effectiveLastEl
to null via a ternary. null?.contains(el) evaluates to undefined and
!undefined is true, so every intermediate block passed the containment
filter — spuriously highlighting the entire selection range.

Add an early return when either endpoint element is missing. Also remove
the null-guard ternaries that are now unreachable, letting TypeScript
narrow firstEl/lastEl to HTMLElement directly.
…render-cursors

computeMultiBlockOverlayRects is a pure computation function; DOM-based
inner-block promotion (list-item → list) was an architectural mismatch.

Move the promotion step to use-render-cursors, where resolved endpoints
are built before computeSelectionVisual is called. A promote() helper
checks if the resolved element's immediate parentElement is a [data-block]
container and rewrites localClientId + nulls out richTextOffset if so.
This matches the same boundary check used by blockContainerOf.

computeMultiBlockOverlayRects now trusts that its inputs are already
container-level IDs: it drops the effectiveFirstEl/effectiveLastEl/wasPromoted
variables and uses docFirstEl/docLastEl directly. The same-container early
return becomes a simple localClientId equality check.
@alecgeatches alecgeatches added [Feature] Real-time Collaboration Phase 3 of the Gutenberg roadmap around real-time collaboration [Type] Bug An existing feature does not function as intended labels Jul 14, 2026
@ingeniumed

Copy link
Copy Markdown
Contributor

👋🏾 @giteshsarvaiya I've added @alecgeatches and I as reviewers on your PR. Could you fix the merge conflicts and we can take a look? Thanks for putting it up!

@giteshsarvaiya

giteshsarvaiya commented Jul 31, 2026 •

Copy link
Copy Markdown
Contributor Author

@ingeniumed @alecgeatches Thanks for taking a look! I've resolved the merge conflicts. Looking forward to your feedback.

Comment thread packages/core-data/src/types.ts Outdated
* Any block type can produce a CursorEndpoint — a paragraph mid-word, a
* table cell, a heading — as long as the selection carries a character offset.
*/
export type CursorEndpoint = {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the explanation in the comments, but I'm not sure why we need these two new types. CursorEndpoint appears to contain exactly the same data as SelectionCursor, and WholeBlockEndpoint also matches SelectionWholeBlock.

If we need the endpoint concept, can we use a type SelectionEndpoint = SelectionCursor | SelectionWholeBlock instead and reuse the same inner types? I think we could also drop areEndpointsEqual() and related endpoint-specific functions in this PR unless we need a new wrapping type for a good reason.

// endEndpoint in the document. Normalise to DOM order so
// getBlocksBetween and the avatar-placement logic below always
// operate top-to-bottom.
const startEl =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This element-finding logic overlaps with computeMultiBlockOverlayRects() (get DOM elements, find nodes between). Could we extract shared logic and use the same in both places? Ideally this will reduce useBlockHighlighting's size at it's getting pretty big, and also make the logic between the two functions exactly the same.

}

if ( overlayRect && ! usersWithAvatar.has( color ) ) {
usersWithAvatar.add( color );

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usersWithAvatar should probably use user IDs instead of colors, since we only have 7 colors built-in. It's okay if multiple users have the same color when more than 7 users are present, but I think this logic will skip any users after the first 7.

@alecgeatches alecgeatches left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@giteshsarvaiya Thank you for your work here! I left some code comments above, and also noticed that scroll-to-avatar stops working with multiblock selection:

scroll-to-avatar.mov

Above, I show clicking an avatar works for selection within a block, but when a user has multiblock selection running the jump-to-avatar button doesn't work anymore.

Overall I think this works well and didn't see any other issues in my testing. I'd like to take another run once you've had a look at the code comments, but I think this looks pretty good already.

Clicking a collaborator's avatar in the presence list did nothing when
that user had a SelectionInMultipleBlocks selection active. The cursor
registry only held elements for cursor/single-block states; highlight
avatar elements rendered for multi-block selections were never registered,
so scrollToCursor returned false silently.

Fix: thread clientId through BlockHighlightData, wrap each highlight
Avatar in a positioned div captured via the existing setCursorRef/
cursorRefsMap pattern, and sync both cursor and highlight elements in
one unified registry effect. The pulse animation on scroll is extended
to cover block-label avatars via a shared keyframe parameterised with
--label-base-transform, keeping the CSS DRY.
Only 7 colors exist in the palette so with 8+ collaborators, users
sharing a color would have their avatar label skipped entirely. Key by
collaboratorInfo.id (the WordPress user ID) instead — consistent with
how user identity is used everywhere else in this file.
…f SelectionEndpoint = SelectionCursor | SelectionWholeBlock

CursorEndpoint and WholeBlockEndpoint duplicated SelectionCursor and
SelectionWholeBlock with a different discriminant field (kind vs type).
Reuse the existing types so SelectionEndpoint = SelectionCursor |
SelectionWholeBlock, and simplify resolveEndpoint callers to pass the
endpoint directly to resolveSelection.

Also fixes a latent type error where BlockEntry.userId was typed as
string but collaboratorInfo.id is number, and fills in the missing
clientId/userId fields on the same-container early-return path.
@giteshsarvaiya

Copy link
Copy Markdown
Contributor Author

Thanks @alecgeatches for the review and the walkthrough video, it made the issue easy to reproduce.

I've addressed all four points:

  • Fixed the scroll-to-avatar regression.
  • Switched usersWithAvatar to key by user ID.
  • Dropped the redundant CursorEndpoint/WholeBlockEndpoint types in favour of SelectionEndpoint = SelectionCursor | SelectionWholeBlock.
  • Extracted the shared querySelector + normalise + promote + middle-blocks pattern into a getOrderedBlockRange helper in cursor-dom-utils.ts, now used by both useBlockHighlighting and computeMultiBlockOverlayRects.

The PR is ready for a second round of review.

Adds getOrderedBlockRange() to cursor-dom-utils, consolidating the
repeated query + DOM-order normalisation + blockContainerOf promotion +
getBlocksBetween/filter pattern that existed independently in both
useBlockHighlighting and computeMultiBlockOverlayRects.

Returns { firstEl, firstId, lastEl, lastId, middleEls, sameContainer }
so callers get IDs alongside elements (no extra getAttribute calls) and
a clear sameContainer flag instead of comparing IDs manually.

getBlocksBetween and isNodeBefore are now internal helpers (no longer
exported) since all external callers have been replaced by
getOrderedBlockRange.
@giteshsarvaiya
giteshsarvaiya force-pushed the fix/79643-rtc-awareness-mixed-block-selection branch from b4949df to 71cf639 Compare August 3, 2026 07:29

@alecgeatches alecgeatches left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@giteshsarvaiya Good job on the fixes! I ran through testing and all is working well for me. I'm seeing one failed e2e run, doubt it's related, will see if that passes with a trunk merge. Thank you!

@alecgeatches
alecgeatches enabled auto-merge (squash) August 3, 2026 16:57
@alecgeatches
alecgeatches disabled auto-merge August 3, 2026 21:21
@giteshsarvaiya

Copy link
Copy Markdown
Contributor Author

hooray! the tests passed.

@ingeniumed
ingeniumed merged commit 09e1e7a into WordPress:trunk Aug 5, 2026
42 checks passed
@ingeniumed

Copy link
Copy Markdown
Contributor

I've gone ahead and merged this in. Thanks for working on this!

@github-actions github-actions Bot added this to the Gutenberg 23.8 milestone Aug 5, 2026
@giteshsarvaiya
giteshsarvaiya deleted the fix/79643-rtc-awareness-mixed-block-selection branch August 5, 2026 06:12
shail-mehta pushed a commit that referenced this pull request Aug 12, 2026
* core-data: add CursorEndpoint/WholeBlockEndpoint discriminated union for multi-block selections

Introduces a SelectionEndpoint discriminated union to distinguish between two
kinds of selection endpoints in a multi-block selection:

- CursorEndpoint (kind: cursor): the endpoint lands inside a RichText field
  and carries a character-level Y.Text relative position. Any block type that
  has a text field with a known offset produces this shape.

- WholeBlockEndpoint (kind: whole-block): the endpoint has no character
  offset, either because the block has no RichText field (e.g. image, spacer)
  or it is selected as a whole block via keyboard block-selection mode. The
  anchor is pinned to the block slot in its parent Y.Array instead.

Previously both endpoint shapes were treated identically, which caused the
overlay to break when a selection spanned mixed block types (e.g. paragraph
to image) because the receiver tried to resolve a text cursor on a block that
has no Y.Text.

* editor: fix getBlocksBetween to skip blocks already covered by a parent

When a selection spans a list block, getBlocksBetween previously returned
both the list and each of its list items, causing every item to receive a
duplicate CSS outline on top of the one already applied to the parent.

The fix filters out any block element that is a descendant of a block
already collected, so each region is highlighted exactly once regardless
of nesting depth.

* editor: handle SelectionInMultipleBlocks in the collaborators overlay

Fixes RTC selection awareness breaking when a collaborator selects across
blocks of different types (e.g. a paragraph into an image).

Before this change, multi-block selections fell through to the same code
path as single-block text selections, which tried to resolve a RichText
cursor on every endpoint. Non-text blocks have no Y.Text anchor, so the
resolution threw and the overlay rendered nothing.

Changes:
- use-render-cursors: adds a dedicated branch for SelectionInMultipleBlocks
  that resolves each endpoint independently via its kind (cursor vs
  whole-block), so mixed-type combinations resolve correctly.

- compute-selection: simplifies the multi-block path to return only the
  cursor position at the active end. Pixel-level selection rects across
  multiple blocks are replaced by a CSS outline approach (see below), so
  this function no longer needs to compute them.

- use-block-highlighting: extended to cover SelectionInMultipleBlocks.
  Every block in the selection range receives the is-collaborator-selected
  CSS class and a --collaborator-outline-color custom property. The avatar
  label is placed on the topmost block in document order only, avoiding
  one label per block per collaborator.

* @
editor: mixed visual treatment for multi-block awareness (overlay + outline)

Replaces the earlier CSS-outline-only approach with a two-track visual
system that more closely mirrors how a selection looks to the person making it:

Text blocks (paragraph, heading, list, etc.):
  - Full bounding-box semi-transparent fill overlay via selectionRects
  - First block gets a full bounding-box when the selection starts at offset 0;
    partial text-level rects (cursor offset → end) when it starts mid-block
  - Middle blocks always get the full bounding-box fill
  - Last block always uses text-level rects (0 → cursor offset) so only the
    selected portion is highlighted, not the unselected tail

Non-text blocks (image, spacer, etc.):
  - CSS outline border only (is-collaborator-selected class +
    --collaborator-outline-color custom property)
  - No fill overlay so image content is not obscured

Additional fixes included:
  - Stale CSS class bug: is-collaborator-selected is now reset for every
    block on each render before being conditionally re-applied, preventing
    it from persisting when a block transitions between selection types
  - resolveTargetElement gains a richer fallback chain (contenteditable →
    common text elements p/h1-h6/etc.) so partial text rects work correctly
    even when the observer has not focused the block
  - Text block detection uses innerText.trim() instead of querying
    [contenteditable] or [data-wp-block-attribute-key], which are absent on
    blocks the observer has not clicked into
@

* editor: promote inner blocks to container for multi-block highlights

When a multi-block selection starts or ends inside an inner block (e.g. a
list-item inside a list), the sibling inner blocks between the endpoint and
the other selection end appeared as individual middle blocks — each getting
its own fill rect, producing a striped banded look instead of one rect
covering the whole list.

Fix: promote each selection endpoint to its nearest [data-block] ancestor
before computing rects and block highlights. Middle blocks that are
descendants of the promoted container are filtered out. When both endpoints
promote to the same container (e.g. two list-items inside one list), a
single bounding-box rect is emitted for that container.

Adds a blockContainerOf helper to cursor-dom-utils and applies the
promotion in both compute-selection and use-block-highlighting.

* editor: fix isNodeBefore bitmask check for nested-block endpoints

compareDocumentPosition returns a bitmask. When b is a following
descendant of a the result is FOLLOWING | CONTAINED_BY (4 | 16 = 20),
not 4. The strict === 4 check returned false, silently skipping the
start/end swap for any endpoint pair where one element is nested inside
the other (e.g. a list-item resolved before blockContainerOf runs).

Fix: use a bitwise AND so any value with the FOLLOWING bit set returns true.

* editor: fix blockContainerOf to promote only direct-parent containers

The previous closest('[data-block]') call walked arbitrarily far up the
ancestor chain. A core/list nested inside core/group has a non-[data-block]
wrapper div between them, so closest() would skip past the list and
promote to the group — wrong block gets highlighted.

The correct scope is the immediate parentElement: if the direct parent is
itself a [data-block] element (as in list-item → list), promote; otherwise
leave the element as-is.

* editor: guard against missing endpoint elements in block highlighting

When an endpoint block is absent from the DOM (e.g. deleted by a
concurrent edit), the previous code set effectiveFirstEl/effectiveLastEl
to null via a ternary. null?.contains(el) evaluates to undefined and
!undefined is true, so every intermediate block passed the containment
filter — spuriously highlighting the entire selection range.

Add an early return when either endpoint element is missing. Also remove
the null-guard ternaries that are now unreachable, letting TypeScript
narrow firstEl/lastEl to HTMLElement directly.

* editor: move inner-block promotion out of compute-selection into use-render-cursors

computeMultiBlockOverlayRects is a pure computation function; DOM-based
inner-block promotion (list-item → list) was an architectural mismatch.

Move the promotion step to use-render-cursors, where resolved endpoints
are built before computeSelectionVisual is called. A promote() helper
checks if the resolved element's immediate parentElement is a [data-block]
container and rewrites localClientId + nulls out richTextOffset if so.
This matches the same boundary check used by blockContainerOf.

computeMultiBlockOverlayRects now trusts that its inputs are already
container-level IDs: it drops the effectiveFirstEl/effectiveLastEl/wasPromoted
variables and uses docFirstEl/docLastEl directly. The same-container early
return becomes a simple localClientId equality check.

* editor: fix scroll-to-avatar for multi-block selections

Clicking a collaborator's avatar in the presence list did nothing when
that user had a SelectionInMultipleBlocks selection active. The cursor
registry only held elements for cursor/single-block states; highlight
avatar elements rendered for multi-block selections were never registered,
so scrollToCursor returned false silently.

Fix: thread clientId through BlockHighlightData, wrap each highlight
Avatar in a positioned div captured via the existing setCursorRef/
cursorRefsMap pattern, and sync both cursor and highlight elements in
one unified registry effect. The pulse animation on scroll is extended
to cover block-label avatars via a shared keyframe parameterised with
--label-base-transform, keeping the CSS DRY.

* editor: key usersWithAvatar by user ID instead of color

Only 7 colors exist in the palette so with 8+ collaborators, users
sharing a color would have their avatar label skipped entirely. Key by
collaboratorInfo.id (the WordPress user ID) instead — consistent with
how user identity is used everywhere else in this file.

* core-data, editor: drop CursorEndpoint/WholeBlockEndpoint in favour of SelectionEndpoint = SelectionCursor | SelectionWholeBlock

CursorEndpoint and WholeBlockEndpoint duplicated SelectionCursor and
SelectionWholeBlock with a different discriminant field (kind vs type).
Reuse the existing types so SelectionEndpoint = SelectionCursor |
SelectionWholeBlock, and simplify resolveEndpoint callers to pass the
endpoint directly to resolveSelection.

Also fixes a latent type error where BlockEntry.userId was typed as
string but collaboratorInfo.id is number, and fills in the missing
clientId/userId fields on the same-container early-return path.

* editor: extract shared block-range DOM logic into getOrderedBlockRange

Adds getOrderedBlockRange() to cursor-dom-utils, consolidating the
repeated query + DOM-order normalisation + blockContainerOf promotion +
getBlocksBetween/filter pattern that existed independently in both
useBlockHighlighting and computeMultiBlockOverlayRects.

Returns { firstEl, firstId, lastEl, lastId, middleEls, sameContainer }
so callers get IDs alongside elements (no extra getAttribute calls) and
a clear sameContainer flag instead of comparing IDs manually.

getBlocksBetween and isNodeBefore are now internal helpers (no longer
exported) since all external callers have been replaced by
getOrderedBlockRange.

---------

Co-authored-by: giteshsarvaiya <giteshsarvaiya@git.wordpress.org>
Co-authored-by: alecgeatches <alecgeatches@git.wordpress.org>
Co-authored-by: ingeniumed <ingeniumed@git.wordpress.org>
Co-authored-by: t-hamano <wildworks@git.wordpress.org>
wporg-sync pushed a commit to WordPress/wordpress-develop that referenced this pull request Sep 8, 2026
This updates the pinned commit hash of the Gutenberg repository from `5a0417990a9404cc2562cdd35e3054cb0d3e546e` (version `23.7.0`) to `ae8b34d78e1abc6d1c866fdc00080a1452de82ad` (version `23.8.0`).

A full list of changes included in this commit can be found on GitHub: https://github.com/WordPress/gutenberg/compare/v23.7.0..v23.8.0.

- Fix: New route-based admin pages are empty when no JS (WordPress/gutenberg#80628)
- Report flaky tests: declare @types/node (WordPress/gutenberg#80838)
- Storybook e2e: add small, compact and icon examples to button matrix (WordPress/gutenberg#80793)
- ESLint: Drop @eslint/compat fixup for jest-dom and testing-library (WordPress/gutenberg#80842)
- Storybook: Use SelectControl in Motion tokens story (WordPress/gutenberg#80790)
- Writing flow: forward delete an empty paragraph without breaking apart the next block (WordPress/gutenberg#80813)
- ToggleControl: Add "With Visual" Storybook story (WordPress/gutenberg#80803)
- Bump the github-actions group across 1 directory with 5 updates (WordPress/gutenberg#80684)
- Update Ariakit packages (WordPress/gutenberg#80765)
- Components: Update Floating UI to 2.1.9 (WordPress/gutenberg#80761)
- Improve pre-flight npm access checks (WordPress/gutenberg#80334)
- Ensure static checks can run for private mirrors (WordPress/gutenberg#80817)
- Components: Update react-day-picker to 9.14.0 (WordPress/gutenberg#80792)
- Testing: Remove the jest-puppeteer-axe package (WordPress/gutenberg#80775)
- Tools: Use native agent skill discovery (WordPress/gutenberg#80811)
- Table of Contents: Replace "Convert to static list" with confirmed "Detach" action (WordPress/gutenberg#80844)
- Page List: Rename the Edit action to Detach and confirm it in a dialog (WordPress/gutenberg#80847)
- URLInput: Simplify keyboard handling and fix arrow keys with a text selection (WordPress/gutenberg#80780)
- Upload Media: Fail the item when the /finalize request fails (WordPress/gutenberg#80725)
- Jest preset: support self-referencing via exports (WordPress/gutenberg#80837)
- Fix template `modified` and `date` return value for file templates (WordPress/gutenberg#80733)
- Element: Make the package importable in React 19 (WordPress/gutenberg#80053)
- Add CheckboxControl with-visual Storybook story. (WordPress/gutenberg#80849)
- UI: Add Combobox.InputGroup primitive (WordPress/gutenberg#80869)
- Block Editor: Clear the moving animation's z-index when it finishes (WordPress/gutenberg#80824)
- SearchableChipSelect: Add form primitive to @wordpress/ui (WordPress/gutenberg#80779)
- Playlist: Add track icon (WordPress/gutenberg#80959)
- Flaky tests: fix router navigate latest HTML (WordPress/gutenberg#80178)
- Components: Update polymorphism types to allow all attributes when specifying `as` (WordPress/gutenberg#80705)
- Block JSON schema & PHP-only blocks: Add `autoRegister` support (WordPress/gutenberg#80173)
- Boot: Adjust specificity of the image reset styles so components can size their own images (WordPress/gutenberg#80845)
- Components: Opt-in ConfirmDialog for auto-documentation (WordPress/gutenberg#80866)
- RichText: don't apply input transform when there's no onReplace (WordPress/gutenberg#80978)
- Quote: Ensure paragraph placeholder appears after deleting nested blocks (WordPress/gutenberg#77151)
- Block editor: make the Group action wrap blocks with a group transform (WordPress/gutenberg#80891)
- Copy: preserve the block when its entire text is selected (WordPress/gutenberg#80994)
- Add opt-out for block style state controls (WordPress/gutenberg#80956)
- Upgrade Playwright to v1.62 (WordPress/gutenberg#81001)
- List View: Speed up opening by removing a forced style recalculation (WordPress/gutenberg#80929)
- Widget Dashboard: preserve widget chrome flex layout (WordPress/gutenberg#80570)
- Widget Primitives: document actions as verbs, not links (WordPress/gutenberg#80974)
- Core Data: add missing @wordpress/base-styles dependency (WordPress/gutenberg#81012)
- Ignore node_modules in schema integration test globs (WordPress/gutenberg#81013)
- RichText: fix paste handler crash when pasting files (WordPress/gutenberg#81010)
- Docs: Add VS Code setup guidance (WordPress/gutenberg#77913)
- Perf Tests: Merge selection event windows instead of summing durations (WordPress/gutenberg#81002)
- Storybook: move smoke-test deps into the storybook workspace (WordPress/gutenberg#81017)
- Unit Tests: Reorganise the jest config file. (WordPress/gutenberg#80940)
- Performance Tests: Ignore the locally generated artifacts directory (WordPress/gutenberg#81024)
- Editor: Remove sidebar tabs focus sync effect (WordPress/gutenberg#81020)
- Widgets: carry a declarative `icon` through the widget pipeline (WordPress/gutenberg#80969)
- RTC: Remove excess autosave notices (when not useful) (WordPress/gutenberg#80539)
- UI: Use focus styles from base-styles (WordPress/gutenberg#80635)
- Automated Testing: Add Storybook component documentation regression testing (WordPress/gutenberg#80655)
- Pass Playlist controls to track blocks (WordPress/gutenberg#80368)
- Components: Deprecate Surface (WordPress/gutenberg#80943)
- Tabs: Support Home and End keys for keyboard navigation (WordPress/gutenberg#80912)
- Fix typos in code `comments` and `JSDoc` (WordPress/gutenberg#81045)
- Interface: Remove incorrect aria-expanded from pin-to-toolbar button (WordPress/gutenberg#79874)
- List View: Speed up opening by removing a second render pass (WordPress/gutenberg#80935)
- Docs: Use `gutenberg` instead of `Gutenberg` in package name (WordPress/gutenberg#81051)
- Fix ESLint warnings for 'navigateRegionsProps' spread (WordPress/gutenberg#81052)
- Tests: Replace page-level selectors with locators in e2e specs (WordPress/gutenberg#81053)
- RTC: Disable custom autosave controller when RTC is disabled (WordPress/gutenberg#80769)
- Background: Fix the legacy gradient UI where a gradient cannot be selected (WordPress/gutenberg#81056)
- Rename blockStatesEnabled setting to blockStatesEditingEnabled (WordPress/gutenberg#81058)
- Background: Fix the legacy gradient UI where a gradient cannot be selected - Add missing change log (WordPress/gutenberg#81060)
- Declare missing prettier and stylelint workspace dependencies (WordPress/gutenberg#81065)
- Notes: Display shortcut for form action buttons (WordPress/gutenberg#81064)
- View config: lowercase dynamic filter names (WordPress/gutenberg#81068)
- CI: cache the system packages Playwright dowloads for WebKit (WordPress/gutenberg#80846)
- List View: Collapse off-window placeholder rows into a single spacer row (WordPress/gutenberg#80953)
- devops: balance Playwright shards by duration (WordPress/gutenberg#79479)
- Views: honor developer-defined view config overrides (WordPress/gutenberg#80832)
- Components: Migrate ItemGroup to SCSS module (WordPress/gutenberg#80797)
- Test: Add Vitest migration routing guardrails (WordPress/gutenberg#81036)
- Visual revisions: Add a code diff view inside the editor (WordPress/gutenberg#80314)
- Bump actions/labeler from 6.1.0 to 7.0.0 in /.github/workflows (WordPress/gutenberg#80966)
- Visual revisions: add shareable urls (WordPress/gutenberg#79934)
- Fix e2e tests that break when shard rebalancing changes their neighbors (WordPress/gutenberg#81117)
- Query: guard non-scalar queryId to avoid fatal in enhanced pagination (WordPress/gutenberg#80724)
- Replace deprecated useResizeObserver for useScaleCanvas (WordPress/gutenberg#67508)
- CI: Add job timeouts to E2E, static checks, bundle size, and create block (WordPress/gutenberg#80801)
- Allow organization or repository variable to dictate the Actions runner (WordPress/gutenberg#81087)
- List View: Only subscribe to the block subtree for rows that can show images (WordPress/gutenberg#81076)
- Editor: Migrate settings sidebar to Tabs from @wordpress/ui (WordPress/gutenberg#81054)
- Notes: Email users mentioned in a note (WordPress/gutenberg#79606)
- List View: Narrow the dependants of the memoized List View tree (WordPress/gutenberg#81129)
- List View: Pass only minimal required data to sub-tree branches (WordPress/gutenberg#81111)
- DataViews: Add `time` field type and control (WordPress/gutenberg#80830)
- Post Author Biography: Fix horizontal overflow with long unbroken text (WordPress/gutenberg#81018)
- Link Control: Restore the preview title underline (WordPress/gutenberg#81083)
- Views: Add React to the package's dev dependencies (WordPress/gutenberg#81139)
- feat: Add target param in proxy (WordPress/gutenberg#81141)
- Fix: flaky revisions pagination e2e cross-page diff assertion (WordPress/gutenberg#81119)
- Button: Suppress UA focus ring when focused and pressed (WordPress/gutenberg#81113)
- View config: add reference docs (WordPress/gutenberg#81149)
- Editor: Fix document tools button focus ring (WordPress/gutenberg#81115)
- List View: Replace expand/collapse callbacks with reducer dispatch (WordPress/gutenberg#81138)
- CI: resolve Playwright through the workspace that declares it (WordPress/gutenberg#81137)
- CI: build once and reuse the build across e2e tests shards (WordPress/gutenberg#81031)
- Fix: Tabs block: Start with empty tab labels with placeholders (WordPress/gutenberg#81009)
- Interface: Increase footer breadcrumb height to prevent focus ring clipping (WordPress/gutenberg#81145)
- Editor: clarify autosave failure notice (WordPress/gutenberg#76470)
- Theme: Omit color properties when neither provided nor inherited (WordPress/gutenberg#80600)
- Post editor: Add ThemeProvider for admin color schemes (WordPress/gutenberg#81112)
- Core Data: saveDirtyEntities: improve messaging of server errors (WordPress/gutenberg#81151)
- Global Styles: kebab-case preset slugs when converting references to custom properties (WordPress/gutenberg#80583)
- Revise CODEOWNERS for package ownership (removing nerrad) (WordPress/gutenberg#81175)
- Build: Wrap script bundles in an IIFE to contain 'use strict' (WordPress/gutenberg#79792)
- Media: Improve the HEIC upload error and keep any upload errors up until dismissed (WordPress/gutenberg#81130)
- Block Supports: Guard against non-string attribute values to avoid fatal errors (WordPress/gutenberg#80501)
- Video: Hide settings for the GIF variation (WordPress/gutenberg#81142)
- Video: clarify the Video variation description (WordPress/gutenberg#81181)
- Media Editor: Render sidebar tabs via ComplementaryArea's render prop (WordPress/gutenberg#81133)
- Bump docker/login-action (WordPress/gutenberg#80962)
- Bump actions/setup-node from 6.4.0 to 7.0.0 in /.github/setup-node (WordPress/gutenberg#80963)
- fix(admin-ui): reset the wp-admin li margin that misaligns Breadcrumbs (WordPress/gutenberg#81134)
- Bump astral-sh/setup-uv from 8.3.2 to 9.0.0 in /.github/workflows (WordPress/gutenberg#80964)
- Fix/79643 rtc awareness mixed block selection (WordPress/gutenberg#79836)
- Agents: Add a defensive data design skill and route to the copy guide (WordPress/gutenberg#81131)
- ESLint: Ban `@ts-ignore` in favour of `@ts-expect-error` (WordPress/gutenberg#81148)
- Types: Replace remaining `@ts-expect-error` suppressions with proper typing (WordPress/gutenberg#81200)
- Button: turn on the width setting by default in theme.json (WordPress/gutenberg#81196)
- Notes: fix the mention notification email composition (WordPress/gutenberg#81187)
- Edit Widgets: Fix header toolbar button focus ring (WordPress/gutenberg#81176)
- List View: Reduce per-row store subscriptions (WordPress/gutenberg#81136)
- Customizer widgets: Add ThemeProvider for admin color schemes (WordPress/gutenberg#81174)
- Blocks: Declare the `@types/react-is` devDependency (WordPress/gutenberg#81203)
- Widgets editor: Add ThemeProvider for admin color schemes (WordPress/gutenberg#81173)
- PanelColorSettings: Restore the missing space below the panel header (WordPress/gutenberg#81155)
- Remove the editableRoot opt-in from the paragraph block (WordPress/gutenberg#81184)
- Media Attached to: Fix issue with the popover unexpectedly flipping, tweak wording (WordPress/gutenberg#81206)
- Components: Add allowForms prop to SandBox component (WordPress/gutenberg#76471)
- Ensure device preview is always accurate when window is zoomed in (WordPress/gutenberg#81193)
- DataViews: Pass only eligible items to a bulk action callback (WordPress/gutenberg#81198)
- DataViews: Make grid and table item preview aspect ratio configurable (WordPress/gutenberg#79329)
- Block Editor: Return false from isBlockSelected when there is no client ID (WordPress/gutenberg#81212)
- Blocks: Update hpq to 1.4.0 and drop the ts-expect-error suppressions (WordPress/gutenberg#81199)
- DataViews: Fix the between `date` filter losing a manually typed date on blur (WordPress/gutenberg#81150)
- Block Editor: Fix Select all freezing on large posts (WordPress/gutenberg#81210)
- List View: Split the context and drop dead props to cut re-renders on expand and collapse (WordPress/gutenberg#81159)
- Docs: Fix broken Figma links on the design resources page. (WordPress/gutenberg#81166)
- Blocks: Support static block templates in block type settings (WordPress/gutenberg#80027)
- AGENTS: Update development tips section (WordPress/gutenberg#81224)
- URLInput: Skip search requests while an IME composition is in progress (WordPress/gutenberg#80602)
- Components: Deprecate Animate (WordPress/gutenberg#80931)
- Fix: Trunk e2e failures caused by the navigation spec leaving plain permalinks (WordPress/gutenberg#81238)
- Use p elements for callout alerts in components docs (WordPress/gutenberg#81234)
- Storybook: Enable design system theme tool globally (WordPress/gutenberg#81116)
- Media: Cover client-side big image scaling and orphaned files (WordPress/gutenberg#81061)
- Footnotes: guard against invalid post meta values (WordPress/gutenberg#81201)
- Block editor: unify what a new sibling block inherits (WordPress/gutenberg#81250)
- Global Styles: Remove unused duplicate font family preview utilities (WordPress/gutenberg#81194)
- Docs: explain how the theme.json schema fixtures work (WordPress/gutenberg#81263)
- theme.json schema: fix block pseudo-classes and custom states (WordPress/gutenberg#81209)
- List View: Migrate label wrapper to UI Stack and drop Badge from the anchor (WordPress/gutenberg#81266)
- Docs: Remove dependency group import guidance (WordPress/gutenberg#81245)
- ESLint: Define dependency import rules (WordPress/gutenberg#81246)
- Flaky tests: Report as a PR comment only, stop creating issues (WordPress/gutenberg#81218)
- Dashboard Widgets: remove the Hello Dolly download action (WordPress/gutenberg#81272)
- Block Directory: Make downloadable block item labels translatable. (WordPress/gutenberg#81237)
- Icons: move the inline image icon into the library (WordPress/gutenberg#81271)
- Update phpcs, wpcs dependencies (WordPress/gutenberg#81279)
- fix: add optional chaining for empty reusable block (WordPress/gutenberg#81165) (WordPress/gutenberg#81177)
- DataViews: Inline the kebabCase utility from components (WordPress/gutenberg#81284)
- Navigation: Complete the DocBlocks for the responsive container and overlay style helpers (WordPress/gutenberg#80622)
- Style states: fix state deselection when selecting the already selected block (WordPress/gutenberg#81277)
- Fix missing return value in force_filtered_html_on_import footnotes filter (WordPress/gutenberg#81293)
- Packages: Recover July 29 npm release metadata (WordPress/gutenberg#81303)
- Global styles: render element styles set only inside a breakpoint (WordPress/gutenberg#81265)
- Style states: Fix phantom pseudo element style output (WordPress/gutenberg#81291)
- Docs: remove breakpoint-only element style example from global styles guide (WordPress/gutenberg#81308)
- Render viewport state element styles in the editor (WordPress/gutenberg#81307)
- theme.json schema: responsive states belong to blocks (WordPress/gutenberg#81253)
- theme.json schema: allow responsive states on block style variations (WordPress/gutenberg#81309)
- Block Inspector: Disable the 'Edit original' button when the entity ID is missing (WordPress/gutenberg#81288)
- Site Editor: Decode HTML entities in Identity fields (WordPress/gutenberg#81269)
- Document editEntityRecord's options.isCached param (WordPress/gutenberg#81318)
- Theme: Colocate plugin tests with implementations (WordPress/gutenberg#81247)
- Block Editor: Bail out of hasSelectedInnerBlock when there is no clientId (WordPress/gutenberg#81315)
- ESLint: Replace strict config with bulk suppressions (WordPress/gutenberg#81248)
- Block Library: Document security patch releases (WordPress/gutenberg#81295)
- ESLint: Remove legacy import suppressions (WordPress/gutenberg#81338)
- Components: Migrate Spinner styles from Emotion to SCSS module (WordPress/gutenberg#80511)
- DataViews: Use the public `@wordpress/ui` Badge instead of the private one (WordPress/gutenberg#81236)
- Pert Tests: Avoid inflating interaction metrics with startTracing (WordPress/gutenberg#81264)
- Block Editor: Simplify InspectorControlsFill rendering logic (WordPress/gutenberg#81286)
- Keycodes: Make `withIgnoreIMEEvents` a public API (WordPress/gutenberg#81343)
- Docs: Fix broken links to the removed JavaScript build setup guide. (WordPress/gutenberg#81232)
- Markdownlint: disable the MD033 (no-inline-html) rule project-wide (WordPress/gutenberg#81213)
- Docs: Fix typo in block file structure guide (WordPress/gutenberg#81348)
- Playlist: Normalize Waveform Player configuration handling (WordPress/gutenberg#81342)
- Site editor: fix unreadable sidebar hover color (WordPress/gutenberg#81317)
- Global Styles: Migrate font size presets to the shared preset layer (WordPress/gutenberg#79811)
- Block Editor: Convert useBlockVisibility hook to TypeScript (WordPress/gutenberg#80390)
- Scope breakpoint media queries to screen so printing does not look like a resize (WordPress/gutenberg#81367)
- New `kebab-case` package: extract utility and migrate private API calls (WordPress/gutenberg#81294)
- Remove content types experiment (WordPress/gutenberg#81340)
- Editor: Keep the canvas height stable while resizing the canvas (WordPress/gutenberg#81163)
- Dashboard Widgets: add icon and relevance to the widget action envelope (WordPress/gutenberg#81275)
- Playlist: Improve audio conversion and track selection (WordPress/gutenberg#80926)
- Try: Set post navigation link icon to next. (WordPress/gutenberg#81384)
- UI: Derive Base UI direction from WordPress i18n (WordPress/gutenberg#80399)
- DataViews:  Fix `array` field type validation for empty values (WordPress/gutenberg#81378)
- Bump github/codeql-action/upload-sarif (WordPress/gutenberg#81287)
- Bump actions/stale from 10.4.0 to 11.0.0 in /.github/workflows (WordPress/gutenberg#81219)
- Monitor all setup-related composite Actions. (WordPress/gutenberg#81192)
- IconButton: Improve keyboard shortcut accessibility (WordPress/gutenberg#80402)
- Interface: Stop the secondary sidebar animating into place on page load (WordPress/gutenberg#81362)
- Fix: flaky list view paste block styles e2e test (WordPress/gutenberg#81229)
- Docs: Add error message guidance. (WordPress/gutenberg#81143)
- wp-build: Render the no-JS fallback in the generated page templates (WordPress/gutenberg#81365)
- Changed Build Process Link and remove unused tags (WordPress/gutenberg#81360)
- Scripts: Prevent a UTF-8 BOM in the middle of extracted CSS (WordPress/gutenberg#81383)
- Global Styles: Migrate shadows presets to use the preset management layer. (WordPress/gutenberg#79812)
- Global Styles: report border, shadow, outline, filter and dimension changes (WordPress/gutenberg#81407)
- Dashboard Widgets: split action icons into wire and resolved forms (WordPress/gutenberg#81381)
- Block Editor: Fix Escape from the block toolbar and stop redundant last focus dispatches (WordPress/gutenberg#81319)
- Block Mover: Add the keyboard shortcut to the buttons' spoken description (WordPress/gutenberg#81380)
- Format Library: Remove unused CSS rule (WordPress/gutenberg#77831)
- Core Data: Fix post staying dirty after saving edited post meta with RTC enabled (WordPress/gutenberg#81392)
- Widget Dashboard: host-tunable tile spacing via public custom properties (WordPress/gutenberg#81352)
- DataForm: Fix hidden fields validation (WordPress/gutenberg#81377)
- Tools: Make agent setup a workspace (WordPress/gutenberg#81418)
- Test: Add private Vitest config and migrate a pilot test (WordPress/gutenberg#81037)
- Interface: Let CSS own the ComplementaryArea width and use AnimatePresence custom for exit (WordPress/gutenberg#81363)
- Notes: Fix text wrapping for long usernames in collaboration sidebar (WordPress/gutenberg#81406)
- DataViews: vendor `ValidatedSelectControl` (WordPress/gutenberg#81391)
- UI: Add `Calendar` and `RangeCalendar`, moved from `components` private APIs (WordPress/gutenberg#81337)
- Feature: Tabs block: consider using the tab title in the Document Overview instead of a generic "Tab" label (WordPress/gutenberg#81427)
- fix: order site identity changes predictably (WordPress/gutenberg#81283)
- Docs: Fix broken link to the Node.js debugging guide. (WordPress/gutenberg#81398)
- Navigation Overlay Close: Inherit typography and color from the overlay (WordPress/gutenberg#80751)
- Fix: Regression: Tabs block: Start with empty tab labels with placeholders (WordPress/gutenberg#81429)
- components/Menu: Restore Modal focus return when menu items close (WordPress/gutenberg#81164)
- DataViews: Move the rich text control into the editor package (WordPress/gutenberg#81430)
- Components: Remove ValidatedTextControl private API (WordPress/gutenberg#80680)
- Cover: Avoid passing null as the featured image size (WordPress/gutenberg#81444)
- DataViews: vendor `ValidatedNumberControl` (WordPress/gutenberg#81433)
- DataViews: vendor ValidatedCheckboxControl (WordPress/gutenberg#81435)
- DataViews: vendor ValidatedRadioControl (WordPress/gutenberg#81434)
- UI: Upgrade React DayPicker to version 10 (WordPress/gutenberg#81439)
- Block editor: render a real default block in place of the default appender (WordPress/gutenberg#81231)
- Spacing Sizes Control: Make the control label translatable independently of the input aria label. (WordPress/gutenberg#81240)
- Writing flow: stop the caret on containers that do not merge with the text flow (WordPress/gutenberg#81456)
- Remove an unmodified wrapper when all its inner blocks are removed (WordPress/gutenberg#42503)
- Normalize block gap values in layout (WordPress/gutenberg#81460)
- Docs: Add Block Actions Readme (WordPress/gutenberg#69408)
- Block editor: disclose the nested block count of a multi selection (WordPress/gutenberg#80745)
- Fix: flaky autosave shareable URL revisions e2e test. (WordPress/gutenberg#81455)
- Fix empty list block with anchor persisting after backspace deletion (WordPress/gutenberg#77000)
- Docs: Add Block List Readme (WordPress/gutenberg#69432)
- Docs: Add Block Lock Readme (WordPress/gutenberg#69434)
- Backport core fixes for finalize route (WordPress/gutenberg#81465)
- ESLint: Rename root eslint.config.cjs to eslint.config.mjs (WordPress/gutenberg#81468)
- Update 23.8 release branch  (WordPress/gutenberg#81486)
- RTC: Couple RTC and polling provider as an opt-in experiment (WordPress/gutenberg#80658)
- Align collaboration migration version markers with the 23.8.0 release (WordPress/gutenberg#81789)

Fixes #66066.

git-svn-id: https://develop.svn.wordpress.org/trunk@63534 602fd350-edb4-49c9-b593-d223f7449a82
wporg-sync pushed a commit to WordPress/WordPress that referenced this pull request Sep 8, 2026
This updates the pinned commit hash of the Gutenberg repository from `5a0417990a9404cc2562cdd35e3054cb0d3e546e` (version `23.7.0`) to `ae8b34d78e1abc6d1c866fdc00080a1452de82ad` (version `23.8.0`).

A full list of changes included in this commit can be found on GitHub: https://github.com/WordPress/gutenberg/compare/v23.7.0..v23.8.0.

- Fix: New route-based admin pages are empty when no JS (WordPress/gutenberg#80628)
- Report flaky tests: declare @types/node (WordPress/gutenberg#80838)
- Storybook e2e: add small, compact and icon examples to button matrix (WordPress/gutenberg#80793)
- ESLint: Drop @eslint/compat fixup for jest-dom and testing-library (WordPress/gutenberg#80842)
- Storybook: Use SelectControl in Motion tokens story (WordPress/gutenberg#80790)
- Writing flow: forward delete an empty paragraph without breaking apart the next block (WordPress/gutenberg#80813)
- ToggleControl: Add "With Visual" Storybook story (WordPress/gutenberg#80803)
- Bump the github-actions group across 1 directory with 5 updates (WordPress/gutenberg#80684)
- Update Ariakit packages (WordPress/gutenberg#80765)
- Components: Update Floating UI to 2.1.9 (WordPress/gutenberg#80761)
- Improve pre-flight npm access checks (WordPress/gutenberg#80334)
- Ensure static checks can run for private mirrors (WordPress/gutenberg#80817)
- Components: Update react-day-picker to 9.14.0 (WordPress/gutenberg#80792)
- Testing: Remove the jest-puppeteer-axe package (WordPress/gutenberg#80775)
- Tools: Use native agent skill discovery (WordPress/gutenberg#80811)
- Table of Contents: Replace "Convert to static list" with confirmed "Detach" action (WordPress/gutenberg#80844)
- Page List: Rename the Edit action to Detach and confirm it in a dialog (WordPress/gutenberg#80847)
- URLInput: Simplify keyboard handling and fix arrow keys with a text selection (WordPress/gutenberg#80780)
- Upload Media: Fail the item when the /finalize request fails (WordPress/gutenberg#80725)
- Jest preset: support self-referencing via exports (WordPress/gutenberg#80837)
- Fix template `modified` and `date` return value for file templates (WordPress/gutenberg#80733)
- Element: Make the package importable in React 19 (WordPress/gutenberg#80053)
- Add CheckboxControl with-visual Storybook story. (WordPress/gutenberg#80849)
- UI: Add Combobox.InputGroup primitive (WordPress/gutenberg#80869)
- Block Editor: Clear the moving animation's z-index when it finishes (WordPress/gutenberg#80824)
- SearchableChipSelect: Add form primitive to @wordpress/ui (WordPress/gutenberg#80779)
- Playlist: Add track icon (WordPress/gutenberg#80959)
- Flaky tests: fix router navigate latest HTML (WordPress/gutenberg#80178)
- Components: Update polymorphism types to allow all attributes when specifying `as` (WordPress/gutenberg#80705)
- Block JSON schema & PHP-only blocks: Add `autoRegister` support (WordPress/gutenberg#80173)
- Boot: Adjust specificity of the image reset styles so components can size their own images (WordPress/gutenberg#80845)
- Components: Opt-in ConfirmDialog for auto-documentation (WordPress/gutenberg#80866)
- RichText: don't apply input transform when there's no onReplace (WordPress/gutenberg#80978)
- Quote: Ensure paragraph placeholder appears after deleting nested blocks (WordPress/gutenberg#77151)
- Block editor: make the Group action wrap blocks with a group transform (WordPress/gutenberg#80891)
- Copy: preserve the block when its entire text is selected (WordPress/gutenberg#80994)
- Add opt-out for block style state controls (WordPress/gutenberg#80956)
- Upgrade Playwright to v1.62 (WordPress/gutenberg#81001)
- List View: Speed up opening by removing a forced style recalculation (WordPress/gutenberg#80929)
- Widget Dashboard: preserve widget chrome flex layout (WordPress/gutenberg#80570)
- Widget Primitives: document actions as verbs, not links (WordPress/gutenberg#80974)
- Core Data: add missing @wordpress/base-styles dependency (WordPress/gutenberg#81012)
- Ignore node_modules in schema integration test globs (WordPress/gutenberg#81013)
- RichText: fix paste handler crash when pasting files (WordPress/gutenberg#81010)
- Docs: Add VS Code setup guidance (WordPress/gutenberg#77913)
- Perf Tests: Merge selection event windows instead of summing durations (WordPress/gutenberg#81002)
- Storybook: move smoke-test deps into the storybook workspace (WordPress/gutenberg#81017)
- Unit Tests: Reorganise the jest config file. (WordPress/gutenberg#80940)
- Performance Tests: Ignore the locally generated artifacts directory (WordPress/gutenberg#81024)
- Editor: Remove sidebar tabs focus sync effect (WordPress/gutenberg#81020)
- Widgets: carry a declarative `icon` through the widget pipeline (WordPress/gutenberg#80969)
- RTC: Remove excess autosave notices (when not useful) (WordPress/gutenberg#80539)
- UI: Use focus styles from base-styles (WordPress/gutenberg#80635)
- Automated Testing: Add Storybook component documentation regression testing (WordPress/gutenberg#80655)
- Pass Playlist controls to track blocks (WordPress/gutenberg#80368)
- Components: Deprecate Surface (WordPress/gutenberg#80943)
- Tabs: Support Home and End keys for keyboard navigation (WordPress/gutenberg#80912)
- Fix typos in code `comments` and `JSDoc` (WordPress/gutenberg#81045)
- Interface: Remove incorrect aria-expanded from pin-to-toolbar button (WordPress/gutenberg#79874)
- List View: Speed up opening by removing a second render pass (WordPress/gutenberg#80935)
- Docs: Use `gutenberg` instead of `Gutenberg` in package name (WordPress/gutenberg#81051)
- Fix ESLint warnings for 'navigateRegionsProps' spread (WordPress/gutenberg#81052)
- Tests: Replace page-level selectors with locators in e2e specs (WordPress/gutenberg#81053)
- RTC: Disable custom autosave controller when RTC is disabled (WordPress/gutenberg#80769)
- Background: Fix the legacy gradient UI where a gradient cannot be selected (WordPress/gutenberg#81056)
- Rename blockStatesEnabled setting to blockStatesEditingEnabled (WordPress/gutenberg#81058)
- Background: Fix the legacy gradient UI where a gradient cannot be selected - Add missing change log (WordPress/gutenberg#81060)
- Declare missing prettier and stylelint workspace dependencies (WordPress/gutenberg#81065)
- Notes: Display shortcut for form action buttons (WordPress/gutenberg#81064)
- View config: lowercase dynamic filter names (WordPress/gutenberg#81068)
- CI: cache the system packages Playwright dowloads for WebKit (WordPress/gutenberg#80846)
- List View: Collapse off-window placeholder rows into a single spacer row (WordPress/gutenberg#80953)
- devops: balance Playwright shards by duration (WordPress/gutenberg#79479)
- Views: honor developer-defined view config overrides (WordPress/gutenberg#80832)
- Components: Migrate ItemGroup to SCSS module (WordPress/gutenberg#80797)
- Test: Add Vitest migration routing guardrails (WordPress/gutenberg#81036)
- Visual revisions: Add a code diff view inside the editor (WordPress/gutenberg#80314)
- Bump actions/labeler from 6.1.0 to 7.0.0 in /.github/workflows (WordPress/gutenberg#80966)
- Visual revisions: add shareable urls (WordPress/gutenberg#79934)
- Fix e2e tests that break when shard rebalancing changes their neighbors (WordPress/gutenberg#81117)
- Query: guard non-scalar queryId to avoid fatal in enhanced pagination (WordPress/gutenberg#80724)
- Replace deprecated useResizeObserver for useScaleCanvas (WordPress/gutenberg#67508)
- CI: Add job timeouts to E2E, static checks, bundle size, and create block (WordPress/gutenberg#80801)
- Allow organization or repository variable to dictate the Actions runner (WordPress/gutenberg#81087)
- List View: Only subscribe to the block subtree for rows that can show images (WordPress/gutenberg#81076)
- Editor: Migrate settings sidebar to Tabs from @wordpress/ui (WordPress/gutenberg#81054)
- Notes: Email users mentioned in a note (WordPress/gutenberg#79606)
- List View: Narrow the dependants of the memoized List View tree (WordPress/gutenberg#81129)
- List View: Pass only minimal required data to sub-tree branches (WordPress/gutenberg#81111)
- DataViews: Add `time` field type and control (WordPress/gutenberg#80830)
- Post Author Biography: Fix horizontal overflow with long unbroken text (WordPress/gutenberg#81018)
- Link Control: Restore the preview title underline (WordPress/gutenberg#81083)
- Views: Add React to the package's dev dependencies (WordPress/gutenberg#81139)
- feat: Add target param in proxy (WordPress/gutenberg#81141)
- Fix: flaky revisions pagination e2e cross-page diff assertion (WordPress/gutenberg#81119)
- Button: Suppress UA focus ring when focused and pressed (WordPress/gutenberg#81113)
- View config: add reference docs (WordPress/gutenberg#81149)
- Editor: Fix document tools button focus ring (WordPress/gutenberg#81115)
- List View: Replace expand/collapse callbacks with reducer dispatch (WordPress/gutenberg#81138)
- CI: resolve Playwright through the workspace that declares it (WordPress/gutenberg#81137)
- CI: build once and reuse the build across e2e tests shards (WordPress/gutenberg#81031)
- Fix: Tabs block: Start with empty tab labels with placeholders (WordPress/gutenberg#81009)
- Interface: Increase footer breadcrumb height to prevent focus ring clipping (WordPress/gutenberg#81145)
- Editor: clarify autosave failure notice (WordPress/gutenberg#76470)
- Theme: Omit color properties when neither provided nor inherited (WordPress/gutenberg#80600)
- Post editor: Add ThemeProvider for admin color schemes (WordPress/gutenberg#81112)
- Core Data: saveDirtyEntities: improve messaging of server errors (WordPress/gutenberg#81151)
- Global Styles: kebab-case preset slugs when converting references to custom properties (WordPress/gutenberg#80583)
- Revise CODEOWNERS for package ownership (removing nerrad) (WordPress/gutenberg#81175)
- Build: Wrap script bundles in an IIFE to contain 'use strict' (WordPress/gutenberg#79792)
- Media: Improve the HEIC upload error and keep any upload errors up until dismissed (WordPress/gutenberg#81130)
- Block Supports: Guard against non-string attribute values to avoid fatal errors (WordPress/gutenberg#80501)
- Video: Hide settings for the GIF variation (WordPress/gutenberg#81142)
- Video: clarify the Video variation description (WordPress/gutenberg#81181)
- Media Editor: Render sidebar tabs via ComplementaryArea's render prop (WordPress/gutenberg#81133)
- Bump docker/login-action (WordPress/gutenberg#80962)
- Bump actions/setup-node from 6.4.0 to 7.0.0 in /.github/setup-node (WordPress/gutenberg#80963)
- fix(admin-ui): reset the wp-admin li margin that misaligns Breadcrumbs (WordPress/gutenberg#81134)
- Bump astral-sh/setup-uv from 8.3.2 to 9.0.0 in /.github/workflows (WordPress/gutenberg#80964)
- Fix/79643 rtc awareness mixed block selection (WordPress/gutenberg#79836)
- Agents: Add a defensive data design skill and route to the copy guide (WordPress/gutenberg#81131)
- ESLint: Ban `@ts-ignore` in favour of `@ts-expect-error` (WordPress/gutenberg#81148)
- Types: Replace remaining `@ts-expect-error` suppressions with proper typing (WordPress/gutenberg#81200)
- Button: turn on the width setting by default in theme.json (WordPress/gutenberg#81196)
- Notes: fix the mention notification email composition (WordPress/gutenberg#81187)
- Edit Widgets: Fix header toolbar button focus ring (WordPress/gutenberg#81176)
- List View: Reduce per-row store subscriptions (WordPress/gutenberg#81136)
- Customizer widgets: Add ThemeProvider for admin color schemes (WordPress/gutenberg#81174)
- Blocks: Declare the `@types/react-is` devDependency (WordPress/gutenberg#81203)
- Widgets editor: Add ThemeProvider for admin color schemes (WordPress/gutenberg#81173)
- PanelColorSettings: Restore the missing space below the panel header (WordPress/gutenberg#81155)
- Remove the editableRoot opt-in from the paragraph block (WordPress/gutenberg#81184)
- Media Attached to: Fix issue with the popover unexpectedly flipping, tweak wording (WordPress/gutenberg#81206)
- Components: Add allowForms prop to SandBox component (WordPress/gutenberg#76471)
- Ensure device preview is always accurate when window is zoomed in (WordPress/gutenberg#81193)
- DataViews: Pass only eligible items to a bulk action callback (WordPress/gutenberg#81198)
- DataViews: Make grid and table item preview aspect ratio configurable (WordPress/gutenberg#79329)
- Block Editor: Return false from isBlockSelected when there is no client ID (WordPress/gutenberg#81212)
- Blocks: Update hpq to 1.4.0 and drop the ts-expect-error suppressions (WordPress/gutenberg#81199)
- DataViews: Fix the between `date` filter losing a manually typed date on blur (WordPress/gutenberg#81150)
- Block Editor: Fix Select all freezing on large posts (WordPress/gutenberg#81210)
- List View: Split the context and drop dead props to cut re-renders on expand and collapse (WordPress/gutenberg#81159)
- Docs: Fix broken Figma links on the design resources page. (WordPress/gutenberg#81166)
- Blocks: Support static block templates in block type settings (WordPress/gutenberg#80027)
- AGENTS: Update development tips section (WordPress/gutenberg#81224)
- URLInput: Skip search requests while an IME composition is in progress (WordPress/gutenberg#80602)
- Components: Deprecate Animate (WordPress/gutenberg#80931)
- Fix: Trunk e2e failures caused by the navigation spec leaving plain permalinks (WordPress/gutenberg#81238)
- Use p elements for callout alerts in components docs (WordPress/gutenberg#81234)
- Storybook: Enable design system theme tool globally (WordPress/gutenberg#81116)
- Media: Cover client-side big image scaling and orphaned files (WordPress/gutenberg#81061)
- Footnotes: guard against invalid post meta values (WordPress/gutenberg#81201)
- Block editor: unify what a new sibling block inherits (WordPress/gutenberg#81250)
- Global Styles: Remove unused duplicate font family preview utilities (WordPress/gutenberg#81194)
- Docs: explain how the theme.json schema fixtures work (WordPress/gutenberg#81263)
- theme.json schema: fix block pseudo-classes and custom states (WordPress/gutenberg#81209)
- List View: Migrate label wrapper to UI Stack and drop Badge from the anchor (WordPress/gutenberg#81266)
- Docs: Remove dependency group import guidance (WordPress/gutenberg#81245)
- ESLint: Define dependency import rules (WordPress/gutenberg#81246)
- Flaky tests: Report as a PR comment only, stop creating issues (WordPress/gutenberg#81218)
- Dashboard Widgets: remove the Hello Dolly download action (WordPress/gutenberg#81272)
- Block Directory: Make downloadable block item labels translatable. (WordPress/gutenberg#81237)
- Icons: move the inline image icon into the library (WordPress/gutenberg#81271)
- Update phpcs, wpcs dependencies (WordPress/gutenberg#81279)
- fix: add optional chaining for empty reusable block (WordPress/gutenberg#81165) (WordPress/gutenberg#81177)
- DataViews: Inline the kebabCase utility from components (WordPress/gutenberg#81284)
- Navigation: Complete the DocBlocks for the responsive container and overlay style helpers (WordPress/gutenberg#80622)
- Style states: fix state deselection when selecting the already selected block (WordPress/gutenberg#81277)
- Fix missing return value in force_filtered_html_on_import footnotes filter (WordPress/gutenberg#81293)
- Packages: Recover July 29 npm release metadata (WordPress/gutenberg#81303)
- Global styles: render element styles set only inside a breakpoint (WordPress/gutenberg#81265)
- Style states: Fix phantom pseudo element style output (WordPress/gutenberg#81291)
- Docs: remove breakpoint-only element style example from global styles guide (WordPress/gutenberg#81308)
- Render viewport state element styles in the editor (WordPress/gutenberg#81307)
- theme.json schema: responsive states belong to blocks (WordPress/gutenberg#81253)
- theme.json schema: allow responsive states on block style variations (WordPress/gutenberg#81309)
- Block Inspector: Disable the 'Edit original' button when the entity ID is missing (WordPress/gutenberg#81288)
- Site Editor: Decode HTML entities in Identity fields (WordPress/gutenberg#81269)
- Document editEntityRecord's options.isCached param (WordPress/gutenberg#81318)
- Theme: Colocate plugin tests with implementations (WordPress/gutenberg#81247)
- Block Editor: Bail out of hasSelectedInnerBlock when there is no clientId (WordPress/gutenberg#81315)
- ESLint: Replace strict config with bulk suppressions (WordPress/gutenberg#81248)
- Block Library: Document security patch releases (WordPress/gutenberg#81295)
- ESLint: Remove legacy import suppressions (WordPress/gutenberg#81338)
- Components: Migrate Spinner styles from Emotion to SCSS module (WordPress/gutenberg#80511)
- DataViews: Use the public `@wordpress/ui` Badge instead of the private one (WordPress/gutenberg#81236)
- Pert Tests: Avoid inflating interaction metrics with startTracing (WordPress/gutenberg#81264)
- Block Editor: Simplify InspectorControlsFill rendering logic (WordPress/gutenberg#81286)
- Keycodes: Make `withIgnoreIMEEvents` a public API (WordPress/gutenberg#81343)
- Docs: Fix broken links to the removed JavaScript build setup guide. (WordPress/gutenberg#81232)
- Markdownlint: disable the MD033 (no-inline-html) rule project-wide (WordPress/gutenberg#81213)
- Docs: Fix typo in block file structure guide (WordPress/gutenberg#81348)
- Playlist: Normalize Waveform Player configuration handling (WordPress/gutenberg#81342)
- Site editor: fix unreadable sidebar hover color (WordPress/gutenberg#81317)
- Global Styles: Migrate font size presets to the shared preset layer (WordPress/gutenberg#79811)
- Block Editor: Convert useBlockVisibility hook to TypeScript (WordPress/gutenberg#80390)
- Scope breakpoint media queries to screen so printing does not look like a resize (WordPress/gutenberg#81367)
- New `kebab-case` package: extract utility and migrate private API calls (WordPress/gutenberg#81294)
- Remove content types experiment (WordPress/gutenberg#81340)
- Editor: Keep the canvas height stable while resizing the canvas (WordPress/gutenberg#81163)
- Dashboard Widgets: add icon and relevance to the widget action envelope (WordPress/gutenberg#81275)
- Playlist: Improve audio conversion and track selection (WordPress/gutenberg#80926)
- Try: Set post navigation link icon to next. (WordPress/gutenberg#81384)
- UI: Derive Base UI direction from WordPress i18n (WordPress/gutenberg#80399)
- DataViews:  Fix `array` field type validation for empty values (WordPress/gutenberg#81378)
- Bump github/codeql-action/upload-sarif (WordPress/gutenberg#81287)
- Bump actions/stale from 10.4.0 to 11.0.0 in /.github/workflows (WordPress/gutenberg#81219)
- Monitor all setup-related composite Actions. (WordPress/gutenberg#81192)
- IconButton: Improve keyboard shortcut accessibility (WordPress/gutenberg#80402)
- Interface: Stop the secondary sidebar animating into place on page load (WordPress/gutenberg#81362)
- Fix: flaky list view paste block styles e2e test (WordPress/gutenberg#81229)
- Docs: Add error message guidance. (WordPress/gutenberg#81143)
- wp-build: Render the no-JS fallback in the generated page templates (WordPress/gutenberg#81365)
- Changed Build Process Link and remove unused tags (WordPress/gutenberg#81360)
- Scripts: Prevent a UTF-8 BOM in the middle of extracted CSS (WordPress/gutenberg#81383)
- Global Styles: Migrate shadows presets to use the preset management layer. (WordPress/gutenberg#79812)
- Global Styles: report border, shadow, outline, filter and dimension changes (WordPress/gutenberg#81407)
- Dashboard Widgets: split action icons into wire and resolved forms (WordPress/gutenberg#81381)
- Block Editor: Fix Escape from the block toolbar and stop redundant last focus dispatches (WordPress/gutenberg#81319)
- Block Mover: Add the keyboard shortcut to the buttons' spoken description (WordPress/gutenberg#81380)
- Format Library: Remove unused CSS rule (WordPress/gutenberg#77831)
- Core Data: Fix post staying dirty after saving edited post meta with RTC enabled (WordPress/gutenberg#81392)
- Widget Dashboard: host-tunable tile spacing via public custom properties (WordPress/gutenberg#81352)
- DataForm: Fix hidden fields validation (WordPress/gutenberg#81377)
- Tools: Make agent setup a workspace (WordPress/gutenberg#81418)
- Test: Add private Vitest config and migrate a pilot test (WordPress/gutenberg#81037)
- Interface: Let CSS own the ComplementaryArea width and use AnimatePresence custom for exit (WordPress/gutenberg#81363)
- Notes: Fix text wrapping for long usernames in collaboration sidebar (WordPress/gutenberg#81406)
- DataViews: vendor `ValidatedSelectControl` (WordPress/gutenberg#81391)
- UI: Add `Calendar` and `RangeCalendar`, moved from `components` private APIs (WordPress/gutenberg#81337)
- Feature: Tabs block: consider using the tab title in the Document Overview instead of a generic "Tab" label (WordPress/gutenberg#81427)
- fix: order site identity changes predictably (WordPress/gutenberg#81283)
- Docs: Fix broken link to the Node.js debugging guide. (WordPress/gutenberg#81398)
- Navigation Overlay Close: Inherit typography and color from the overlay (WordPress/gutenberg#80751)
- Fix: Regression: Tabs block: Start with empty tab labels with placeholders (WordPress/gutenberg#81429)
- components/Menu: Restore Modal focus return when menu items close (WordPress/gutenberg#81164)
- DataViews: Move the rich text control into the editor package (WordPress/gutenberg#81430)
- Components: Remove ValidatedTextControl private API (WordPress/gutenberg#80680)
- Cover: Avoid passing null as the featured image size (WordPress/gutenberg#81444)
- DataViews: vendor `ValidatedNumberControl` (WordPress/gutenberg#81433)
- DataViews: vendor ValidatedCheckboxControl (WordPress/gutenberg#81435)
- DataViews: vendor ValidatedRadioControl (WordPress/gutenberg#81434)
- UI: Upgrade React DayPicker to version 10 (WordPress/gutenberg#81439)
- Block editor: render a real default block in place of the default appender (WordPress/gutenberg#81231)
- Spacing Sizes Control: Make the control label translatable independently of the input aria label. (WordPress/gutenberg#81240)
- Writing flow: stop the caret on containers that do not merge with the text flow (WordPress/gutenberg#81456)
- Remove an unmodified wrapper when all its inner blocks are removed (WordPress/gutenberg#42503)
- Normalize block gap values in layout (WordPress/gutenberg#81460)
- Docs: Add Block Actions Readme (WordPress/gutenberg#69408)
- Block editor: disclose the nested block count of a multi selection (WordPress/gutenberg#80745)
- Fix: flaky autosave shareable URL revisions e2e test. (WordPress/gutenberg#81455)
- Fix empty list block with anchor persisting after backspace deletion (WordPress/gutenberg#77000)
- Docs: Add Block List Readme (WordPress/gutenberg#69432)
- Docs: Add Block Lock Readme (WordPress/gutenberg#69434)
- Backport core fixes for finalize route (WordPress/gutenberg#81465)
- ESLint: Rename root eslint.config.cjs to eslint.config.mjs (WordPress/gutenberg#81468)
- Update 23.8 release branch  (WordPress/gutenberg#81486)
- RTC: Couple RTC and polling provider as an opt-in experiment (WordPress/gutenberg#80658)
- Align collaboration migration version markers with the 23.8.0 release (WordPress/gutenberg#81789)

Fixes #66066.
Built from https://develop.svn.wordpress.org/trunk@63534


git-svn-id: http://core.svn.wordpress.org/trunk@62710 1a063a9b-81f0-0310-95a4-ce76da25c4cd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Real-time Collaboration Phase 3 of the Gutenberg roadmap around real-time collaboration First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository [Package] Core data /packages/core-data [Package] Editor /packages/editor [Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RTC: Awareness redraws are not immediate on window resize events RTC: Selection awareness across mixed-type blocks doesn't work

3 participants