Skip to content

Editor: Polish real-time collaboration presence UI and move Avatar to editor package#75652

Merged
ciampo merged 46 commits intoWordPress:trunkfrom
dabowman:improve/real-time-collaboration-ui-polish
Mar 9, 2026
Merged

Editor: Polish real-time collaboration presence UI and move Avatar to editor package#75652
ciampo merged 46 commits intoWordPress:trunkfrom
dabowman:improve/real-time-collaboration-ui-polish

Conversation

@dabowman
Copy link
Contributor

What?

Polishes the real-time collaboration (RTC) presence UI — the collaborator button, list popover, and block highlight labels — and moves the Avatar and AvatarGroup components from @wordpress/components private APIs into the @wordpress/editor package where they are consumed.

Why?

Follow-up to #75595. That PR introduced the collaborator overlay with cursor and block highlight rendering. This PR refines the visual design of the presence UI to match the Figma spec and addresses component ownership:

  • Avatar belongs in editor, not components — The Avatar component is tightly coupled to the RTC collaboration feature and is not yet general-purpose. Keeping it in @wordpress/components as a private API adds unnecessary coupling and prevents the editor package from owning its own styling (e.g. $components-color-accent is restricted to the components package by stylelint).
  • Presence button needed polish — Background color states (resting, hover, pressed) and max avatar count didn't match the design.
  • List popover didn't match spec — Layout, typography, hover states, and header design were out of sync with the Figma design.
  • Block highlight labels were missing — The collaborator block highlight outline needed an avatar badge label positioned above it to identify who selected the block.

How?

Avatar component changes (badgevariant, statusdimmed)

  • Replaced badge boolean prop with variant: 'badge' enum (extensible for future variants)
  • Replaced status string prop with dimmed boolean (simpler API for the single use case)
  • Added contrast-aware badge text color using colord — automatically switches to dark text when borderColor is light
  • Moved background-color from root to .is-badge so non-badge avatars don't show a colored background behind the white ring

Move to editor package

  • Moved Avatar and AvatarGroup from packages/components/src/avatar{,-group}/ to packages/editor/src/components/collaborators-presence/avatar{,-group}/
  • Removed from @wordpress/components private APIs (private-apis.ts) and style.scss
  • Consumers import directly (import Avatar from './avatar') instead of using unlock()
  • Added colord to editor package.json
  • Uses var(--wp-admin-theme-color, #3858e9) instead of $components-color-accent (which is restricted by stylelint outside the components package)
  • Component types use Props & Omit<React.HTMLAttributes<HTMLDivElement>, keyof Props> instead of WordPressComponentProps (not publicly exported)

Presence button polish

  • Container handles background color (resting $gray-100, hover/pressed $gray-200); inner Button stays transparent in all states
  • AvatarGroup max={4} to match design
  • Overflow count has margin-inline-end for right padding

Collaborators list popover

  • Full-width list items with no border-radius, $grid-unit-15 $grid-unit-20 padding
  • Header: normal-case title + count, closeSmall icon at 24px
  • Name: $font-size-medium / $font-weight-medium
  • Hover: theme-tinted rgba(#3858e9, 0.04)

Block highlight avatar labels

  • Each highlighted block now shows an Avatar badge (variant="badge", size="small") at its top-left corner
  • Positioned 8px above the outline via transform: translateY(calc(-100% - 8px))
  • Label expands on hover to show the collaborator's name
  • useBlockHighlighting refactored to return BlockHighlightData[] (same pattern as useRenderCursors)

Overlay inline styles

  • Updated compiled Avatar CSS in COLLABORATORS_OVERLAY_STYLES to stay in sync with the SCSS source
  • Dimmed/status-indicator styles intentionally omitted (not used in overlay)

Testing Instructions

Note: RTC collaboration features require a collaborative editing environment with multiple users connected to the same post via the sync provider.

  1. Open a post in the editor with RTC/collaboration enabled
  2. Have a second user connect to the same post
  3. Presence button: Verify the collaborator avatars appear in the header toolbar, stacked with a +N overflow count when > 4 users. Check hover/pressed background states match surrounding toolbar items.
  4. Collaborators list: Click the avatar group to open the popover. Verify:
    • Header shows "Collaborators" with count and close button
    • Each row shows avatar with colored border and user name
    • Rows highlight on hover with a subtle tint
  5. Cursor labels: Move the second user's cursor within a block. Verify the pill-shaped avatar badge appears at the cursor position and expands on hover to show the name.
  6. Block highlight labels: Have the second user select an entire block. Verify:
    • The block gets a colored outline
    • An avatar badge appears above the top-left corner of the outline
    • The badge expands on hover to show the collaborator's name
  7. For users without a custom Gravatar, verify initials are shown instead of a placeholder image.

Keyboard testing

  1. Tab to the collaborator avatars button in the header toolbar
  2. Press Enter/Space to open the popover
  3. Verify focus moves into the popover
  4. Press Escape to close — verify focus returns to the trigger button

Screenshots or screencast

@dabowman dabowman requested a review from ajitbohra as a code owner February 18, 2026 01:09
@github-actions
Copy link

github-actions bot commented Feb 18, 2026

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.

Unlinked Accounts

The following contributors have not linked their GitHub and WordPress.org accounts: @claude.

Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases.

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

Unlinked contributors: claude.

Co-authored-by: dabowman <davidabowman@git.wordpress.org>
Co-authored-by: ciampo <mciampini@git.wordpress.org>
Co-authored-by: jameskoster <jameskoster@git.wordpress.org>
Co-authored-by: maxschmeling <maxschmeling@git.wordpress.org>
Co-authored-by: chriszarate <czarate@git.wordpress.org>
Co-authored-by: jasmussen <joen@git.wordpress.org>
Co-authored-by: Mamaduka <mamaduka@git.wordpress.org>

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

@github-actions github-actions bot added [Package] Components /packages/components [Package] Editor /packages/editor labels Feb 18, 2026
@chriszarate chriszarate added [Type] Task Issues or PRs that have been broken down into an individual action to take [Feature] Real-time Collaboration Phase 3 of the Gutenberg roadmap around real-time collaboration labels Feb 18, 2026
Copy link
Contributor

@ciampo ciampo left a comment

Choose a reason for hiding this comment

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

Thank you for working on this! I left some initial comments.

In general, I'd prefer smaller PRs that focused on single tasks — for example, one PR that moves the code to the editor package, and one or more follow-up PRs that apply the rest of the changes (as grouped under the "How" section in the PR description)

@ciampo ciampo requested review from a team February 18, 2026 11:36
@jasmussen
Copy link
Contributor

Thanks for the ping. In general I ihave some trust that this can move forward on a dev heavy side while it's still relatively exotic, but if you need any visual reviews, are you able to provide screenshots? It can be a bit tricky to review this particular feature.

@dabowman
Copy link
Contributor Author

@jasmussen here's a screenshot of the current state of the UI with a bunch of collaborators in a session. You can also see the same colors being used between notes and the collab components.

Screenshot 2026-02-18 at 9 19 31 AM

@dabowman dabowman requested a review from ciampo February 18, 2026 17:24
@dabowman
Copy link
Contributor Author

@ciampo I tried to make that big css string a bit more friendly. I split it into two dedicated files. One for the avatar component and one for the rest of the overlay styling. I also added a file of variables that maps to the scss variables we'd like to reference but can't. That way the css is at least pulling what it can from a shared file that we can map to the system and try to keep in sync. The core issue is that we can't really add a lot of styles to the iframe without putting stuff in the block-editor package or adding some plumbing to allow us to enqueue styles from here to get compiled with the rest of the block-editor styles. It's a bit janky but hopefully this makes it a bit more sustainable until folks have time to build out a more permanent solution.

@jasmussen
Copy link
Contributor

Looks good!

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refines the real-time collaboration (RTC) presence UI in the editor (presence button + list popover + block highlight labels) and relocates the RTC-specific Avatar/AvatarGroup components from @wordpress/components private APIs into @wordpress/editor, including updating iframe-injected overlay styles.

Changes:

  • Move Avatar and AvatarGroup into packages/editor and update consumers to import them directly (removing unlock( componentsPrivateApis ) usage).
  • Polish presence button + collaborators list popover styling and update avatar rendering API (variant="badge", dimmed).
  • Extend the overlay to render avatar badge labels for whole-block selections, with updated iframe CSS injection.

Reviewed changes

Copilot reviewed 20 out of 24 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/editor/src/style.scss Includes new Avatar/AvatarGroup SCSS in editor bundle.
packages/editor/src/components/collaborators-presence/styles/collaborators-presence.scss Updates presence button container/pressed styling behavior.
packages/editor/src/components/collaborators-presence/styles/collaborators-list.scss Restyles collaborators list popover (layout/typography/hover/focus).
packages/editor/src/components/collaborators-presence/list.tsx Switches to editor-owned Avatar and uses dimmed state.
packages/editor/src/components/collaborators-presence/index.tsx Switches to editor-owned Avatar/AvatarGroup and adjusts max avatars.
packages/editor/src/components/collaborators-presence/avatar/types.ts Updates Avatar public props (variant, dimmed) and IconType import.
packages/editor/src/components/collaborators-presence/avatar/styles.scss Adds editor-scoped Avatar styles + badge + dimmed styling.
packages/editor/src/components/collaborators-presence/avatar/index.ts Re-exports Avatar component and types.
packages/editor/src/components/collaborators-presence/avatar/component.tsx New Avatar implementation (contrast-aware badge text via colord).
packages/editor/src/components/collaborators-presence/avatar-group/types.ts Defines AvatarGroup props in editor package.
packages/editor/src/components/collaborators-presence/avatar-group/styles.scss Adds editor-scoped AvatarGroup styles (overlap + overflow).
packages/editor/src/components/collaborators-presence/avatar-group/index.ts Re-exports AvatarGroup component and types.
packages/editor/src/components/collaborators-presence/avatar-group/component.tsx New AvatarGroup implementation for editor package.
packages/editor/src/components/collaborators-overlay/use-block-highlighting.ts Refactors highlighting hook to return highlight label render data.
packages/editor/src/components/collaborators-overlay/overlay.tsx Injects new iframe CSS strings and renders block highlight avatar labels.
packages/editor/src/components/collaborators-overlay/overlay-iframe-styles.ts New overlay positioning CSS for iframe injection.
packages/editor/src/components/collaborators-overlay/collaborator-styles.ts Centralizes compiled design-token constants used in injected CSS.
packages/editor/src/components/collaborators-overlay/avatar-iframe-styles.ts New injected CSS for editor-owned Avatar inside iframe.
packages/editor/src/components/collab-sidebar/utils.js Updates deterministic avatar border color palette.
packages/editor/package.json Adds colord dependency for contrast-aware color logic.
packages/components/src/style.scss Removes Avatar/AvatarGroup SCSS from components bundle.
packages/components/src/private-apis.ts Removes Avatar/AvatarGroup from components private API surface.
packages/components/src/avatar/component.tsx Removes components-owned Avatar implementation.
package-lock.json Locks new colord dependency.
Comments suppressed due to low confidence (1)

packages/editor/src/components/collaborators-presence/avatar-group/component.tsx:38

  • The overflow indicator’s aria-label string ("${overflowCount} more") is not localized. Since this is user-facing for screen readers, it should use @wordpress/i18n (and ideally include context like “more collaborators”).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Mamaduka
Copy link
Member

Not sure if this was already reported, but new avatars doesn't seem to be work with Safari.

Screeenshot

CleanShot 2026-02-25 at 19 13 58

@dabowman dabowman force-pushed the improve/real-time-collaboration-ui-polish branch from 936299d to 3f6d791 Compare February 26, 2026 17:48
Comment on lines +55 to +68
// Combine both delayed rerenders so layout changes recompute everything.
const rerenderAfterDelay = useCallback( () => {
const cleanupCursors = rerenderCursorsAfterDelay();
const cleanupHighlights = rerenderHighlightsAfterDelay();
return () => {
cleanupCursors();
cleanupHighlights();
};
}, [ rerenderCursorsAfterDelay, rerenderHighlightsAfterDelay ] );

// Detect layout changes on overlay (e.g. turning on "Show Template") and window
// resizes, and re-render the cursors.
const resizeObserverRef = useResizeObserver( rerenderCursorsAfterDelay );
useEffect( rerenderCursorsAfterDelay, [ rerenderCursorsAfterDelay ] );
// resizes, and re-render the cursors and block highlights.
const resizeObserverRef = useResizeObserver( rerenderAfterDelay );
useEffect( rerenderAfterDelay, [ rerenderAfterDelay ] );
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it necessary to run the rerenderAfterDelay when it changes? Having a useEffect where the function is also the dependency seems strange.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

that makes sense, I refactored.

@dabowman dabowman force-pushed the improve/real-time-collaboration-ui-polish branch from 3dcf828 to 4e314cb Compare February 26, 2026 21:37
@ciampo ciampo self-requested a review February 27, 2026 21:47
@dabowman dabowman force-pushed the improve/real-time-collaboration-ui-polish branch 3 times, most recently from ba09641 to 7defc1b Compare March 6, 2026 16:19
unhighlightBlocks( blocksIdsToUnhighlight );
// Highlight blocks and compute positions for avatar labels.
const results: BlockHighlightData[] = [];
const overlayRect = overlayElement?.getBoundingClientRect() ?? null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Use of getBoundingClientRect() in render. No need for action on this david, just flagging for @alecgeatches

dabowman and others added 11 commits March 6, 2026 11:56
Re-implement tests for Avatar (34 tests) and AvatarGroup (11 tests)
that were previously moved to the add/avatar-component branch.
Updated for the editor package: class prefix (editor-avatar), custom
property names (--editor-avatar-*), i18n overflow labels, and new
inline backgroundImage Safari fix coverage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…n in Avatar

Switches the Avatar component from CSS background-image to a real <img>
element with a useImageLoadingStatus preloader hook. This eliminates the
Safari bug where url() in CSS custom properties silently fails (including
the unfixable dimmed state which used a ::before pseudo-element), and adds
proper image load/error detection so broken URLs gracefully fall back to
initials instead of showing empty colored circles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The side-channel `new Image()` preloader is blocked by Safari's Intelligent
Tracking Prevention for third-party domains like Gravatar, causing avatars
to silently fall back to initials. Replaces the preloader with native
`<img onLoad/onError>` events — the `<img>` is always in the DOM (when src
is truthy) at opacity 0, becoming visible via CSS when the load event fires.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use $gray-900 instead of $black for status indicator color, keep
useImageLoadingStatus as a private import, and add a test for the
src-change reset path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove the intermediate `rerenderAfterDelay` useCallback wrapper and
inline the logic directly into useResizeObserver and useEffect. This
eliminates the unusual pattern of a function being both the effect
callback and its own dependency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move the Avatar/AvatarGroup removal changelog entry from the 32.2.0
versioned section to the Unreleased section to fix the changelog CI check.

https://claude.ai/code/session_019NSHrF2BYtbLUikSpAwUPU
Replace useEffect-based status reset in useImageLoadingStatus with
synchronous derived state to fix a race condition when images load
from browser cache.

The useEffect (passive effect) runs after the DOM commit. When the
overlay avatar renders inside the editor iframe, the Gravatar image
is already cached (loaded earlier by the toolbar avatar), so the
img element's load event fires between the commit and useEffect.
The useEffect then resets status back to 'loading', but onLoad
won't fire again, leaving the avatar stuck showing initials.

The fix uses React's standard "store previous props in state"
pattern so the reset happens synchronously during render, before
the commit, eliminating the race window.

https://claude.ai/code/session_019NSHrF2BYtbLUikSpAwUPU
Safari enforces Cross-Origin-Resource-Policy headers strictly for
images loaded inside iframes. The overlay avatars render inside
the editor iframe via createPortal, so Gravatar images are blocked
by CORP and fall back to initials.

Adding crossOrigin="anonymous" makes the browser issue a CORS
request instead of an opaque one. Gravatar supports CORS
(Access-Control-Allow-Origin: *), and CORS requests are exempt
from CORP enforcement, fixing the issue in Safari.

https://claude.ai/code/session_019NSHrF2BYtbLUikSpAwUPU
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dabowman dabowman force-pushed the improve/real-time-collaboration-ui-polish branch from b50fc0b to 8d5387c Compare March 6, 2026 18:56
@dabowman
Copy link
Contributor Author

dabowman commented Mar 9, 2026

@chriszarate @maxschmeling I think this is ready to go. No merge conflicts. Tests are passing. I addressed all feedback from @ciampo and fixed that weird Safari rendering issue with the avatars. I think we're all set.

@ciampo ciampo merged commit 2bb53b1 into WordPress:trunk Mar 9, 2026
48 of 49 checks passed
@github-actions github-actions bot added this to the Gutenberg 22.8 milestone Mar 9, 2026
@ciampo
Copy link
Contributor

ciampo commented Mar 10, 2026

@chriszarate @maxschmeling @dabowman just wanted to flag that this PR is merged, but not backported to wp/7.0. I don't know if you intented to backport it at all, but flagging just in case.

@chriszarate chriszarate added the Backport to WP 7.0 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta label Mar 10, 2026
@chriszarate
Copy link
Contributor

@chriszarate @maxschmeling @dabowman just wanted to flag that this PR is merged, but not backported to wp/7.0. I don't know if you intented to backport it at all, but flagging just in case.

Thanks, backported

@github-actions
Copy link

There was a conflict while trying to cherry-pick the commit to the wp/7.0 branch. Please resolve the conflict manually and create a PR to the wp/7.0 branch.

PRs to wp/7.0 are similar to PRs to trunk, but you should base your PR on the wp/7.0 branch instead of trunk.

# Checkout the wp/7.0 branch instead of trunk.
git checkout wp/7.0

# Create a new branch for your PR.
git checkout -b my-branch

# Cherry-pick the commit.
git cherry-pick 2bb53b10ce353e4785574f8267076639cadff48b

# Check which files have conflicts.
git status

# Resolve the conflict...
# Add the resolved files to the staging area.
git status
git add .
git cherry-pick --continue

# Push the branch to the repository
git push origin my-branch

# Create a PR and set the base to the wp/7.0 branch.
# See https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-base-branch-of-a-pull-request.

chriszarate pushed a commit that referenced this pull request Mar 10, 2026
… editor package (#75652)

* Components: Add stories and tests for Avatar and AvatarGroup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Components: Avatar: Replace `status` string prop with `dimmed` boolean

The free-form `status` string generated `is-{status}` CSS modifier
classes intended for ad-hoc external styling — a pattern incompatible
with CSS modules. Replace with a `dimmed` boolean that bakes the
visual dimming behavior directly into the component.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Use Avatar `dimmed` prop for disconnected collaborators

Replace inline `opacity: 0.5` on the list item button with the
Avatar component's `dimmed` prop, which provides proper desaturation
and luminosity blending instead of a blunt container opacity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Copy avatar color palette into collaborators-overlay

Add `avatar-colors.ts` with an independent color palette for the
overlay and presence components, decoupled from collab-sidebar/utils.
Update all four consumers to import from the new module.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Components: Avatar: Auto-detect badge text color from borderColor contrast

Use colord's WCAG AA readability check to set the badge name color
to black or white based on the borderColor luminance. Also update
the overlay's compiled Avatar styles to read the new custom property.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Components: Avatar: Add usage guidance to size prop JSDoc

Describe when each size should be used rather than raw pixel
values, following the same pattern as Button's size prop.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Components: Avatar: Replace `badge` boolean with `variant` enum prop

Aligns with the pattern used by Button, Popover, and other
components in the library. The CSS class changes from `has-badge`
to `is-badge` to match the `is-{variant}` convention.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Components: Avatar: Refine dimmed state and move background to badge variant

Move status indicator outside __image so it stays at full opacity when
dimmed. Simplify dimmed CSS to opacity: 0.5 with $gray-700 background
and border. Move outer background-color to badge variant only so it
doesn't bleed through the dimmed 50% opacity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Polish collaborators-presence button states and max avatars

Update hover and pressed backgrounds to both use $gray-200 and increase
the visible avatar count from 3 to 4.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Update collaborators list popover to match design

Restyle the collaborators presence list to match the Figma specs:
- Remove uppercase header, use flex layout with gap for title + count
- Switch close icon from `close` to `closeSmall` at 24px
- Replace hardcoded values with design tokens ($border-width,
  $sidebar-width, $border-width-focus-fallback)
- Full-width list items with 12px/16px padding, no border-radius
- Name text: 13px medium weight with ellipsis truncation
- Theme-tinted hover state (rgba #3858e9 4%)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Move Avatar and AvatarGroup from components to collaborators-presence

The components team wants more time to review before adding new
components to the package. Since Avatar and AvatarGroup are only
consumed by the real-time collaboration UI, move them into the
editor's collaborators-presence folder where they can iterate
independently. They can be promoted back to @wordpress/components
when the team is ready.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Add avatar label above collaborator block highlights

Renders a small Avatar badge at the top-left of each highlighted block,
positioned $grid-unit-10 above the outline, so users can see who selected
a block at a glance and hover to reveal the collaborator's name.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Clean up collaborators overlay and presence code for PR

- Remove unused avatar background color exports and arrays
- Fix JSDoc on getAvatarBorderColor to match actual return
- Refactor useBlockHighlighting: useMemo → useCallback, type
  userStates as PostEditorAwarenessState[] to eliminate any casts,
  use Set for O(1) lookups in unhighlight loop
- Update inline style comment to reference correct SCSS source path
  and note intentionally omitted dimmed/status-indicator styles
- Remove whitespace in collaborator count span
- Remove stories and tests (moved to add/avatar-component branch)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Unify collaborator avatar colors across collab-sidebar and overlay

Replaces the separate avatar-colors.ts palette with the existing
getAvatarBorderColor in collab-sidebar/utils.js, updated to use the
WordPress.org Design Library colors agreed on with the design team.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Rename Avatar CSS prefix from components- to editor-

Renames class names and custom properties to follow the editor package
convention now that Avatar lives in the editor package.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Clarify overlay block label comment

The Avatar isn't restyled — it's positioned as a label for block highlights.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Update package-lock.json for colord dependency in editor

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Address PR review feedback on avatar styles

- Replace hardcoded #000 with #1e1e1e ($gray-900) in badge text contrast
  check to match the design system's text color
- Replace --wp-components-color-accent with --wp-admin-theme-color in
  overlay inline styles (components package variable not available in iframe)
- Add token comments (e.g. /* $font-size-medium */) to hardcoded values
  in the overlay inline styles for maintainability
- Update top-level comment to reference editor package instead of
  wp-components

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Split overlay iframe styles into dedicated modules

Extract the monolithic CSS string from overlay.tsx into three focused
files with clear responsibilities:

- collaborator-styles.ts: compiled design tokens from @wordpress/base-styles,
  used as the single source of truth for values that can't be imported as Sass
  inside the editor canvas iframe.
- avatar-iframe-styles.ts: Avatar component CSS (mirrors avatar/styles.scss)
  using token constants instead of hardcoded values with comments.
- overlay-iframe-styles.ts: overlay layout, cursors, block highlights, and
  animations. Adds z-index layering so cursor lines always render below
  avatar labels across users.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Add overflow: hidden fallback for Safari avatar rendering

Safari < 17 does not support `overflow: clip`. Add `overflow: hidden`
before `overflow: clip` as a fallback, matching the established pattern
used by the Cover block.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Memoize colord() contrast check and guard role=img in Avatar

Wrap the colord().isReadable() call in useMemo so it only recomputes
when borderColor changes instead of on every render. Also guard
role="img" and aria-label to only be set when name is provided,
avoiding an unlabeled image role.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Refactor useBlockHighlighting to invalidation-token pattern

Move all DOM mutations into useEffect, replacing the previous
useCallback + useMemo approach. Add a recomputeToken state variable
that rerenderHighlightsAfterDelay bumps via setTimeout, keeping the
delayed rerender pure and stable across renders.

Add cleanup effect that removes is-collaborator-selected classes and
--collaborator-outline-color properties from block elements on unmount.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Use theme color variables for collaborators list hover/active

Replace hardcoded #3858e9 with rgba(var(--wp-admin-theme-color--rgb))
for hover and active states, matching the established pattern in
edit-site and dataviews. Make active slightly darker (0.08) than
hover (0.04). Fix focus-visible fallback to use #3858e9.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Add color name comments to avatar border color palette

Add inline comments identifying each hex color in the
AVATAR_BORDER_COLORS array for easier reference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Internationalize AvatarGroup overflow label

Use sprintf and _n from @wordpress/i18n for the overflow count
aria-label so it is translatable and properly pluralized.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Use useCallback instead of useMemo for rerenderAfterDelay

Replace useMemo wrapping a function factory with useCallback, which
is the idiomatic React pattern for memoizing callback functions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Replace hardcoded colors with named constants in Avatar

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Clarify avatar border color palette comment

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Deduplicate block highlights by blockId

When multiple collaborators select the same block, only the first
one in the array gets the outline and avatar label.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Hoist overlay rect computation out of highlight loop

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Components: Add CHANGELOG entry for Avatar removal

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Refactor useRenderCursors to invalidation-token pattern

Replace useMemo(() => () => {}) with useEffect + recomputeToken state,
matching the pattern already used in useBlockHighlighting. This makes
rerenderCursorsAfterDelay a stable useCallback with empty dependencies,
reducing unnecessary effect re-runs from useResizeObserver.

Also fix getComputedStyle to use the iframe's defaultView instead of the
parent window, which is correct for cross-frame style resolution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Capture ref value in useBlockHighlighting effect cleanup

Copies `highlightedBlockIds.current` into a local variable at the
top of the effect so the cleanup closure always references the same
Set instance, fixing the react-hooks/exhaustive-deps warning.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Guard resolveSelection calls against stale Yjs positions

Wrap resolveSelection() calls in try/catch blocks in both
useBlockHighlighting and useRenderCursors hooks. The underlying
createAbsolutePositionFromRelativePosition can throw when Yjs
document positions become stale after edits.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Fix Safari avatar rendering with inline backgroundImage

Safari does not resolve url() values inside CSS custom properties,
causing avatar gravatar images to silently fail and show only the
blue background-color fallback.

Set backgroundImage as an inline style directly on the
.editor-avatar__image span, bypassing the custom property. The
--editor-avatar-url custom property is kept for the dimmed state's
::before pseudo-element. Skip the inline style when dimmed to avoid
conflicting with the dimmed state's background-image: none rule.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Re-add Avatar and AvatarGroup component tests

Re-implement tests for Avatar (34 tests) and AvatarGroup (11 tests)
that were previously moved to the add/avatar-component branch.
Updated for the editor package: class prefix (editor-avatar), custom
property names (--editor-avatar-*), i18n overflow labels, and new
inline backgroundImage Safari fix coverage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Replace background-image with <img> element and load detection in Avatar

Switches the Avatar component from CSS background-image to a real <img>
element with a useImageLoadingStatus preloader hook. This eliminates the
Safari bug where url() in CSS custom properties silently fails (including
the unfixable dimmed state which used a ::before pseudo-element), and adds
proper image load/error detection so broken URLs gracefully fall back to
initials instead of showing empty colored circles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Use native img events instead of Image() preloader for Avatar

The side-channel `new Image()` preloader is blocked by Safari's Intelligent
Tracking Prevention for third-party domains like Gravatar, causing avatars
to silently fall back to initials. Replaces the preloader with native
`<img onLoad/onError>` events — the `<img>` is always in the DOM (when src
is truthy) at opacity 0, becoming visible via CSS when the load event fires.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Clean up Avatar review findings

Use $gray-900 instead of $black for status indicator color, keep
useImageLoadingStatus as a private import, and add a test for the
src-change reset path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Simplify overlay rerender logic

Remove the intermediate `rerenderAfterDelay` useCallback wrapper and
inline the logic directly into useResizeObserver and useEffect. This
eliminates the unusual pattern of a function being both the effect
callback and its own dependency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Components: Move changelog entry to Unreleased section

Move the Avatar/AvatarGroup removal changelog entry from the 32.2.0
versioned section to the Unreleased section to fix the changelog CI check.

https://claude.ai/code/session_019NSHrF2BYtbLUikSpAwUPU

* Editor: Fix overlay avatar falling back to initials for cached images

Replace useEffect-based status reset in useImageLoadingStatus with
synchronous derived state to fix a race condition when images load
from browser cache.

The useEffect (passive effect) runs after the DOM commit. When the
overlay avatar renders inside the editor iframe, the Gravatar image
is already cached (loaded earlier by the toolbar avatar), so the
img element's load event fires between the commit and useEffect.
The useEffect then resets status back to 'loading', but onLoad
won't fire again, leaving the avatar stuck showing initials.

The fix uses React's standard "store previous props in state"
pattern so the reset happens synchronously during render, before
the commit, eliminating the race window.

https://claude.ai/code/session_019NSHrF2BYtbLUikSpAwUPU

* Editor: Add crossOrigin to avatar img for Safari iframe CORP compliance

Safari enforces Cross-Origin-Resource-Policy headers strictly for
images loaded inside iframes. The overlay avatars render inside
the editor iframe via createPortal, so Gravatar images are blocked
by CORP and fall back to initials.

Adding crossOrigin="anonymous" makes the browser issue a CORS
request instead of an opaque one. Gravatar supports CORS
(Access-Control-Allow-Origin: *), and CORS requests are exempt
from CORP enforcement, fixing the issue in Safari.

https://claude.ai/code/session_019NSHrF2BYtbLUikSpAwUPU

* Editor: Pass rerender delay into overlay hooks instead of hardcoding

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Editor: Stabilize resize observer callback with useCallback

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Editor: Extract useDebouncedRecompute to debounce overlay rerenders

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Unlinked contributors: claude.

Co-authored-by: dabowman <davidabowman@git.wordpress.org>
Co-authored-by: ciampo <mciampini@git.wordpress.org>
Co-authored-by: jameskoster <jameskoster@git.wordpress.org>
Co-authored-by: maxschmeling <maxschmeling@git.wordpress.org>
Co-authored-by: chriszarate <czarate@git.wordpress.org>
Co-authored-by: jasmussen <joen@git.wordpress.org>
Co-authored-by: Mamaduka <mamaduka@git.wordpress.org>
alecgeatches added a commit that referenced this pull request Mar 11, 2026
* Add full-selection highlighting

* Fix backwards selection cursor placement and selection across blocks

* Add selection range tests

* Export ResolvedSelection from core-data for use in overlay

* Refactor useRenderCursors() into three files, split on DOM and selection tasks.

* Fix type export

* Fix selection direction when using undo/redo

* Add e2e tests for full selection awareness

* Reduce opacity of selection rectangle in overlay

* Pre-compute overlayRect, pre-compute DOM elements where possible

* Rename "CursorContext" to "OverlayContext"

* Extract CursorCoords type, add rect collection types for readability

* Fix type error

* Remerge collaborator styling fix from #75700

* Deduplicate selection rects when text is formatted

* Fix merge of view.getComputedStyle() fix from #75652

Co-authored-by: alecgeatches <alecgeatches@git.wordpress.org>
Co-authored-by: maxschmeling <maxschmeling@git.wordpress.org>
Co-authored-by: chriszarate <czarate@git.wordpress.org>
chriszarate pushed a commit that referenced this pull request Mar 11, 2026
… editor package (#75652)

* Components: Add stories and tests for Avatar and AvatarGroup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Components: Avatar: Replace `status` string prop with `dimmed` boolean

The free-form `status` string generated `is-{status}` CSS modifier
classes intended for ad-hoc external styling — a pattern incompatible
with CSS modules. Replace with a `dimmed` boolean that bakes the
visual dimming behavior directly into the component.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Use Avatar `dimmed` prop for disconnected collaborators

Replace inline `opacity: 0.5` on the list item button with the
Avatar component's `dimmed` prop, which provides proper desaturation
and luminosity blending instead of a blunt container opacity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Copy avatar color palette into collaborators-overlay

Add `avatar-colors.ts` with an independent color palette for the
overlay and presence components, decoupled from collab-sidebar/utils.
Update all four consumers to import from the new module.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Components: Avatar: Auto-detect badge text color from borderColor contrast

Use colord's WCAG AA readability check to set the badge name color
to black or white based on the borderColor luminance. Also update
the overlay's compiled Avatar styles to read the new custom property.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Components: Avatar: Add usage guidance to size prop JSDoc

Describe when each size should be used rather than raw pixel
values, following the same pattern as Button's size prop.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Components: Avatar: Replace `badge` boolean with `variant` enum prop

Aligns with the pattern used by Button, Popover, and other
components in the library. The CSS class changes from `has-badge`
to `is-badge` to match the `is-{variant}` convention.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Components: Avatar: Refine dimmed state and move background to badge variant

Move status indicator outside __image so it stays at full opacity when
dimmed. Simplify dimmed CSS to opacity: 0.5 with $gray-700 background
and border. Move outer background-color to badge variant only so it
doesn't bleed through the dimmed 50% opacity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Polish collaborators-presence button states and max avatars

Update hover and pressed backgrounds to both use $gray-200 and increase
the visible avatar count from 3 to 4.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Update collaborators list popover to match design

Restyle the collaborators presence list to match the Figma specs:
- Remove uppercase header, use flex layout with gap for title + count
- Switch close icon from `close` to `closeSmall` at 24px
- Replace hardcoded values with design tokens ($border-width,
  $sidebar-width, $border-width-focus-fallback)
- Full-width list items with 12px/16px padding, no border-radius
- Name text: 13px medium weight with ellipsis truncation
- Theme-tinted hover state (rgba #3858e9 4%)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Move Avatar and AvatarGroup from components to collaborators-presence

The components team wants more time to review before adding new
components to the package. Since Avatar and AvatarGroup are only
consumed by the real-time collaboration UI, move them into the
editor's collaborators-presence folder where they can iterate
independently. They can be promoted back to @wordpress/components
when the team is ready.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Add avatar label above collaborator block highlights

Renders a small Avatar badge at the top-left of each highlighted block,
positioned $grid-unit-10 above the outline, so users can see who selected
a block at a glance and hover to reveal the collaborator's name.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Clean up collaborators overlay and presence code for PR

- Remove unused avatar background color exports and arrays
- Fix JSDoc on getAvatarBorderColor to match actual return
- Refactor useBlockHighlighting: useMemo → useCallback, type
  userStates as PostEditorAwarenessState[] to eliminate any casts,
  use Set for O(1) lookups in unhighlight loop
- Update inline style comment to reference correct SCSS source path
  and note intentionally omitted dimmed/status-indicator styles
- Remove whitespace in collaborator count span
- Remove stories and tests (moved to add/avatar-component branch)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Unify collaborator avatar colors across collab-sidebar and overlay

Replaces the separate avatar-colors.ts palette with the existing
getAvatarBorderColor in collab-sidebar/utils.js, updated to use the
WordPress.org Design Library colors agreed on with the design team.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Rename Avatar CSS prefix from components- to editor-

Renames class names and custom properties to follow the editor package
convention now that Avatar lives in the editor package.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Clarify overlay block label comment

The Avatar isn't restyled — it's positioned as a label for block highlights.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Update package-lock.json for colord dependency in editor

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Address PR review feedback on avatar styles

- Replace hardcoded #000 with #1e1e1e ($gray-900) in badge text contrast
  check to match the design system's text color
- Replace --wp-components-color-accent with --wp-admin-theme-color in
  overlay inline styles (components package variable not available in iframe)
- Add token comments (e.g. /* $font-size-medium */) to hardcoded values
  in the overlay inline styles for maintainability
- Update top-level comment to reference editor package instead of
  wp-components

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Split overlay iframe styles into dedicated modules

Extract the monolithic CSS string from overlay.tsx into three focused
files with clear responsibilities:

- collaborator-styles.ts: compiled design tokens from @wordpress/base-styles,
  used as the single source of truth for values that can't be imported as Sass
  inside the editor canvas iframe.
- avatar-iframe-styles.ts: Avatar component CSS (mirrors avatar/styles.scss)
  using token constants instead of hardcoded values with comments.
- overlay-iframe-styles.ts: overlay layout, cursors, block highlights, and
  animations. Adds z-index layering so cursor lines always render below
  avatar labels across users.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Add overflow: hidden fallback for Safari avatar rendering

Safari < 17 does not support `overflow: clip`. Add `overflow: hidden`
before `overflow: clip` as a fallback, matching the established pattern
used by the Cover block.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Memoize colord() contrast check and guard role=img in Avatar

Wrap the colord().isReadable() call in useMemo so it only recomputes
when borderColor changes instead of on every render. Also guard
role="img" and aria-label to only be set when name is provided,
avoiding an unlabeled image role.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Refactor useBlockHighlighting to invalidation-token pattern

Move all DOM mutations into useEffect, replacing the previous
useCallback + useMemo approach. Add a recomputeToken state variable
that rerenderHighlightsAfterDelay bumps via setTimeout, keeping the
delayed rerender pure and stable across renders.

Add cleanup effect that removes is-collaborator-selected classes and
--collaborator-outline-color properties from block elements on unmount.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Use theme color variables for collaborators list hover/active

Replace hardcoded #3858e9 with rgba(var(--wp-admin-theme-color--rgb))
for hover and active states, matching the established pattern in
edit-site and dataviews. Make active slightly darker (0.08) than
hover (0.04). Fix focus-visible fallback to use #3858e9.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Add color name comments to avatar border color palette

Add inline comments identifying each hex color in the
AVATAR_BORDER_COLORS array for easier reference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Internationalize AvatarGroup overflow label

Use sprintf and _n from @wordpress/i18n for the overflow count
aria-label so it is translatable and properly pluralized.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Use useCallback instead of useMemo for rerenderAfterDelay

Replace useMemo wrapping a function factory with useCallback, which
is the idiomatic React pattern for memoizing callback functions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Replace hardcoded colors with named constants in Avatar

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Clarify avatar border color palette comment

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Deduplicate block highlights by blockId

When multiple collaborators select the same block, only the first
one in the array gets the outline and avatar label.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Hoist overlay rect computation out of highlight loop

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Components: Add CHANGELOG entry for Avatar removal

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Refactor useRenderCursors to invalidation-token pattern

Replace useMemo(() => () => {}) with useEffect + recomputeToken state,
matching the pattern already used in useBlockHighlighting. This makes
rerenderCursorsAfterDelay a stable useCallback with empty dependencies,
reducing unnecessary effect re-runs from useResizeObserver.

Also fix getComputedStyle to use the iframe's defaultView instead of the
parent window, which is correct for cross-frame style resolution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Capture ref value in useBlockHighlighting effect cleanup

Copies `highlightedBlockIds.current` into a local variable at the
top of the effect so the cleanup closure always references the same
Set instance, fixing the react-hooks/exhaustive-deps warning.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Guard resolveSelection calls against stale Yjs positions

Wrap resolveSelection() calls in try/catch blocks in both
useBlockHighlighting and useRenderCursors hooks. The underlying
createAbsolutePositionFromRelativePosition can throw when Yjs
document positions become stale after edits.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Fix Safari avatar rendering with inline backgroundImage

Safari does not resolve url() values inside CSS custom properties,
causing avatar gravatar images to silently fail and show only the
blue background-color fallback.

Set backgroundImage as an inline style directly on the
.editor-avatar__image span, bypassing the custom property. The
--editor-avatar-url custom property is kept for the dimmed state's
::before pseudo-element. Skip the inline style when dimmed to avoid
conflicting with the dimmed state's background-image: none rule.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Re-add Avatar and AvatarGroup component tests

Re-implement tests for Avatar (34 tests) and AvatarGroup (11 tests)
that were previously moved to the add/avatar-component branch.
Updated for the editor package: class prefix (editor-avatar), custom
property names (--editor-avatar-*), i18n overflow labels, and new
inline backgroundImage Safari fix coverage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Replace background-image with <img> element and load detection in Avatar

Switches the Avatar component from CSS background-image to a real <img>
element with a useImageLoadingStatus preloader hook. This eliminates the
Safari bug where url() in CSS custom properties silently fails (including
the unfixable dimmed state which used a ::before pseudo-element), and adds
proper image load/error detection so broken URLs gracefully fall back to
initials instead of showing empty colored circles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Use native img events instead of Image() preloader for Avatar

The side-channel `new Image()` preloader is blocked by Safari's Intelligent
Tracking Prevention for third-party domains like Gravatar, causing avatars
to silently fall back to initials. Replaces the preloader with native
`<img onLoad/onError>` events — the `<img>` is always in the DOM (when src
is truthy) at opacity 0, becoming visible via CSS when the load event fires.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Clean up Avatar review findings

Use $gray-900 instead of $black for status indicator color, keep
useImageLoadingStatus as a private import, and add a test for the
src-change reset path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Editor: Simplify overlay rerender logic

Remove the intermediate `rerenderAfterDelay` useCallback wrapper and
inline the logic directly into useResizeObserver and useEffect. This
eliminates the unusual pattern of a function being both the effect
callback and its own dependency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Components: Move changelog entry to Unreleased section

Move the Avatar/AvatarGroup removal changelog entry from the 32.2.0
versioned section to the Unreleased section to fix the changelog CI check.

https://claude.ai/code/session_019NSHrF2BYtbLUikSpAwUPU

* Editor: Fix overlay avatar falling back to initials for cached images

Replace useEffect-based status reset in useImageLoadingStatus with
synchronous derived state to fix a race condition when images load
from browser cache.

The useEffect (passive effect) runs after the DOM commit. When the
overlay avatar renders inside the editor iframe, the Gravatar image
is already cached (loaded earlier by the toolbar avatar), so the
img element's load event fires between the commit and useEffect.
The useEffect then resets status back to 'loading', but onLoad
won't fire again, leaving the avatar stuck showing initials.

The fix uses React's standard "store previous props in state"
pattern so the reset happens synchronously during render, before
the commit, eliminating the race window.

https://claude.ai/code/session_019NSHrF2BYtbLUikSpAwUPU

* Editor: Add crossOrigin to avatar img for Safari iframe CORP compliance

Safari enforces Cross-Origin-Resource-Policy headers strictly for
images loaded inside iframes. The overlay avatars render inside
the editor iframe via createPortal, so Gravatar images are blocked
by CORP and fall back to initials.

Adding crossOrigin="anonymous" makes the browser issue a CORS
request instead of an opaque one. Gravatar supports CORS
(Access-Control-Allow-Origin: *), and CORS requests are exempt
from CORP enforcement, fixing the issue in Safari.

https://claude.ai/code/session_019NSHrF2BYtbLUikSpAwUPU

* Editor: Pass rerender delay into overlay hooks instead of hardcoding

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Editor: Stabilize resize observer callback with useCallback

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Editor: Extract useDebouncedRecompute to debounce overlay rerenders

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Unlinked contributors: claude.

Co-authored-by: dabowman <davidabowman@git.wordpress.org>
Co-authored-by: ciampo <mciampini@git.wordpress.org>
Co-authored-by: jameskoster <jameskoster@git.wordpress.org>
Co-authored-by: maxschmeling <maxschmeling@git.wordpress.org>
Co-authored-by: chriszarate <czarate@git.wordpress.org>
Co-authored-by: jasmussen <joen@git.wordpress.org>
Co-authored-by: Mamaduka <mamaduka@git.wordpress.org>
tyxla added a commit that referenced this pull request Mar 11, 2026
… editor package (#75652) (#76365)

* Components: Add stories and tests for Avatar and AvatarGroup



* Components: Avatar: Replace `status` string prop with `dimmed` boolean

The free-form `status` string generated `is-{status}` CSS modifier
classes intended for ad-hoc external styling — a pattern incompatible
with CSS modules. Replace with a `dimmed` boolean that bakes the
visual dimming behavior directly into the component.



* Editor: Use Avatar `dimmed` prop for disconnected collaborators

Replace inline `opacity: 0.5` on the list item button with the
Avatar component's `dimmed` prop, which provides proper desaturation
and luminosity blending instead of a blunt container opacity.



* Editor: Copy avatar color palette into collaborators-overlay

Add `avatar-colors.ts` with an independent color palette for the
overlay and presence components, decoupled from collab-sidebar/utils.
Update all four consumers to import from the new module.



* Components: Avatar: Auto-detect badge text color from borderColor contrast

Use colord's WCAG AA readability check to set the badge name color
to black or white based on the borderColor luminance. Also update
the overlay's compiled Avatar styles to read the new custom property.



* Components: Avatar: Add usage guidance to size prop JSDoc

Describe when each size should be used rather than raw pixel
values, following the same pattern as Button's size prop.



* Components: Avatar: Replace `badge` boolean with `variant` enum prop

Aligns with the pattern used by Button, Popover, and other
components in the library. The CSS class changes from `has-badge`
to `is-badge` to match the `is-{variant}` convention.



* Components: Avatar: Refine dimmed state and move background to badge variant

Move status indicator outside __image so it stays at full opacity when
dimmed. Simplify dimmed CSS to opacity: 0.5 with $gray-700 background
and border. Move outer background-color to badge variant only so it
doesn't bleed through the dimmed 50% opacity.



* Editor: Polish collaborators-presence button states and max avatars

Update hover and pressed backgrounds to both use $gray-200 and increase
the visible avatar count from 3 to 4.



* Editor: Update collaborators list popover to match design

Restyle the collaborators presence list to match the Figma specs:
- Remove uppercase header, use flex layout with gap for title + count
- Switch close icon from `close` to `closeSmall` at 24px
- Replace hardcoded values with design tokens ($border-width,
  $sidebar-width, $border-width-focus-fallback)
- Full-width list items with 12px/16px padding, no border-radius
- Name text: 13px medium weight with ellipsis truncation
- Theme-tinted hover state (rgba #3858e9 4%)



* Editor: Move Avatar and AvatarGroup from components to collaborators-presence

The components team wants more time to review before adding new
components to the package. Since Avatar and AvatarGroup are only
consumed by the real-time collaboration UI, move them into the
editor's collaborators-presence folder where they can iterate
independently. They can be promoted back to @wordpress/components
when the team is ready.



* Editor: Add avatar label above collaborator block highlights

Renders a small Avatar badge at the top-left of each highlighted block,
positioned $grid-unit-10 above the outline, so users can see who selected
a block at a glance and hover to reveal the collaborator's name.



* Editor: Clean up collaborators overlay and presence code for PR

- Remove unused avatar background color exports and arrays
- Fix JSDoc on getAvatarBorderColor to match actual return
- Refactor useBlockHighlighting: useMemo → useCallback, type
  userStates as PostEditorAwarenessState[] to eliminate any casts,
  use Set for O(1) lookups in unhighlight loop
- Update inline style comment to reference correct SCSS source path
  and note intentionally omitted dimmed/status-indicator styles
- Remove whitespace in collaborator count span
- Remove stories and tests (moved to add/avatar-component branch)



* Editor: Unify collaborator avatar colors across collab-sidebar and overlay

Replaces the separate avatar-colors.ts palette with the existing
getAvatarBorderColor in collab-sidebar/utils.js, updated to use the
WordPress.org Design Library colors agreed on with the design team.



* Editor: Rename Avatar CSS prefix from components- to editor-

Renames class names and custom properties to follow the editor package
convention now that Avatar lives in the editor package.



* Editor: Clarify overlay block label comment

The Avatar isn't restyled — it's positioned as a label for block highlights.



* Update package-lock.json for colord dependency in editor



* Editor: Address PR review feedback on avatar styles

- Replace hardcoded #000 with #1e1e1e ($gray-900) in badge text contrast
  check to match the design system's text color
- Replace --wp-components-color-accent with --wp-admin-theme-color in
  overlay inline styles (components package variable not available in iframe)
- Add token comments (e.g. /* $font-size-medium */) to hardcoded values
  in the overlay inline styles for maintainability
- Update top-level comment to reference editor package instead of
  wp-components



* Editor: Split overlay iframe styles into dedicated modules

Extract the monolithic CSS string from overlay.tsx into three focused
files with clear responsibilities:

- collaborator-styles.ts: compiled design tokens from @wordpress/base-styles,
  used as the single source of truth for values that can't be imported as Sass
  inside the editor canvas iframe.
- avatar-iframe-styles.ts: Avatar component CSS (mirrors avatar/styles.scss)
  using token constants instead of hardcoded values with comments.
- overlay-iframe-styles.ts: overlay layout, cursors, block highlights, and
  animations. Adds z-index layering so cursor lines always render below
  avatar labels across users.



* Editor: Add overflow: hidden fallback for Safari avatar rendering

Safari < 17 does not support `overflow: clip`. Add `overflow: hidden`
before `overflow: clip` as a fallback, matching the established pattern
used by the Cover block.



* Editor: Memoize colord() contrast check and guard role=img in Avatar

Wrap the colord().isReadable() call in useMemo so it only recomputes
when borderColor changes instead of on every render. Also guard
role="img" and aria-label to only be set when name is provided,
avoiding an unlabeled image role.



* Editor: Refactor useBlockHighlighting to invalidation-token pattern

Move all DOM mutations into useEffect, replacing the previous
useCallback + useMemo approach. Add a recomputeToken state variable
that rerenderHighlightsAfterDelay bumps via setTimeout, keeping the
delayed rerender pure and stable across renders.

Add cleanup effect that removes is-collaborator-selected classes and
--collaborator-outline-color properties from block elements on unmount.



* Editor: Use theme color variables for collaborators list hover/active

Replace hardcoded #3858e9 with rgba(var(--wp-admin-theme-color--rgb))
for hover and active states, matching the established pattern in
edit-site and dataviews. Make active slightly darker (0.08) than
hover (0.04). Fix focus-visible fallback to use #3858e9.



* Editor: Add color name comments to avatar border color palette

Add inline comments identifying each hex color in the
AVATAR_BORDER_COLORS array for easier reference.



* Editor: Internationalize AvatarGroup overflow label

Use sprintf and _n from @wordpress/i18n for the overflow count
aria-label so it is translatable and properly pluralized.



* Editor: Use useCallback instead of useMemo for rerenderAfterDelay

Replace useMemo wrapping a function factory with useCallback, which
is the idiomatic React pattern for memoizing callback functions.



* Editor: Replace hardcoded colors with named constants in Avatar



* Editor: Clarify avatar border color palette comment



* Editor: Deduplicate block highlights by blockId

When multiple collaborators select the same block, only the first
one in the array gets the outline and avatar label.



* Editor: Hoist overlay rect computation out of highlight loop



* Components: Add CHANGELOG entry for Avatar removal



* Editor: Refactor useRenderCursors to invalidation-token pattern

Replace useMemo(() => () => {}) with useEffect + recomputeToken state,
matching the pattern already used in useBlockHighlighting. This makes
rerenderCursorsAfterDelay a stable useCallback with empty dependencies,
reducing unnecessary effect re-runs from useResizeObserver.

Also fix getComputedStyle to use the iframe's defaultView instead of the
parent window, which is correct for cross-frame style resolution.



* Editor: Capture ref value in useBlockHighlighting effect cleanup

Copies `highlightedBlockIds.current` into a local variable at the
top of the effect so the cleanup closure always references the same
Set instance, fixing the react-hooks/exhaustive-deps warning.



* Editor: Guard resolveSelection calls against stale Yjs positions

Wrap resolveSelection() calls in try/catch blocks in both
useBlockHighlighting and useRenderCursors hooks. The underlying
createAbsolutePositionFromRelativePosition can throw when Yjs
document positions become stale after edits.



* Editor: Fix Safari avatar rendering with inline backgroundImage

Safari does not resolve url() values inside CSS custom properties,
causing avatar gravatar images to silently fail and show only the
blue background-color fallback.

Set backgroundImage as an inline style directly on the
.editor-avatar__image span, bypassing the custom property. The
--editor-avatar-url custom property is kept for the dimmed state's
::before pseudo-element. Skip the inline style when dimmed to avoid
conflicting with the dimmed state's background-image: none rule.



* Editor: Re-add Avatar and AvatarGroup component tests

Re-implement tests for Avatar (34 tests) and AvatarGroup (11 tests)
that were previously moved to the add/avatar-component branch.
Updated for the editor package: class prefix (editor-avatar), custom
property names (--editor-avatar-*), i18n overflow labels, and new
inline backgroundImage Safari fix coverage.



* Editor: Replace background-image with <img> element and load detection in Avatar

Switches the Avatar component from CSS background-image to a real <img>
element with a useImageLoadingStatus preloader hook. This eliminates the
Safari bug where url() in CSS custom properties silently fails (including
the unfixable dimmed state which used a ::before pseudo-element), and adds
proper image load/error detection so broken URLs gracefully fall back to
initials instead of showing empty colored circles.



* Editor: Use native img events instead of Image() preloader for Avatar

The side-channel `new Image()` preloader is blocked by Safari's Intelligent
Tracking Prevention for third-party domains like Gravatar, causing avatars
to silently fall back to initials. Replaces the preloader with native
`<img onLoad/onError>` events — the `<img>` is always in the DOM (when src
is truthy) at opacity 0, becoming visible via CSS when the load event fires.



* Editor: Clean up Avatar review findings

Use $gray-900 instead of $black for status indicator color, keep
useImageLoadingStatus as a private import, and add a test for the
src-change reset path.



* Editor: Simplify overlay rerender logic

Remove the intermediate `rerenderAfterDelay` useCallback wrapper and
inline the logic directly into useResizeObserver and useEffect. This
eliminates the unusual pattern of a function being both the effect
callback and its own dependency.



* Components: Move changelog entry to Unreleased section

Move the Avatar/AvatarGroup removal changelog entry from the 32.2.0
versioned section to the Unreleased section to fix the changelog CI check.

https://claude.ai/code/session_019NSHrF2BYtbLUikSpAwUPU

* Editor: Fix overlay avatar falling back to initials for cached images

Replace useEffect-based status reset in useImageLoadingStatus with
synchronous derived state to fix a race condition when images load
from browser cache.

The useEffect (passive effect) runs after the DOM commit. When the
overlay avatar renders inside the editor iframe, the Gravatar image
is already cached (loaded earlier by the toolbar avatar), so the
img element's load event fires between the commit and useEffect.
The useEffect then resets status back to 'loading', but onLoad
won't fire again, leaving the avatar stuck showing initials.

The fix uses React's standard "store previous props in state"
pattern so the reset happens synchronously during render, before
the commit, eliminating the race window.

https://claude.ai/code/session_019NSHrF2BYtbLUikSpAwUPU

* Editor: Add crossOrigin to avatar img for Safari iframe CORP compliance

Safari enforces Cross-Origin-Resource-Policy headers strictly for
images loaded inside iframes. The overlay avatars render inside
the editor iframe via createPortal, so Gravatar images are blocked
by CORP and fall back to initials.

Adding crossOrigin="anonymous" makes the browser issue a CORS
request instead of an opaque one. Gravatar supports CORS
(Access-Control-Allow-Origin: *), and CORS requests are exempt
from CORP enforcement, fixing the issue in Safari.

https://claude.ai/code/session_019NSHrF2BYtbLUikSpAwUPU

* Editor: Pass rerender delay into overlay hooks instead of hardcoding



* Editor: Stabilize resize observer callback with useCallback



* Editor: Extract useDebouncedRecompute to debounce overlay rerenders



---------

Unlinked contributors: claude.

Co-authored-by: David Bowman <dabowman@gmail.com>
Co-authored-by: dabowman <davidabowman@git.wordpress.org>
Co-authored-by: ciampo <mciampini@git.wordpress.org>
Co-authored-by: jameskoster <jameskoster@git.wordpress.org>
Co-authored-by: maxschmeling <maxschmeling@git.wordpress.org>
Co-authored-by: chriszarate <czarate@git.wordpress.org>
Co-authored-by: jasmussen <joen@git.wordpress.org>
Co-authored-by: Mamaduka <mamaduka@git.wordpress.org>
Co-authored-by: tyxla <tyxla@git.wordpress.org>
gutenbergplugin pushed a commit that referenced this pull request Mar 11, 2026
* Add full-selection highlighting

* Fix backwards selection cursor placement and selection across blocks

* Add selection range tests

* Export ResolvedSelection from core-data for use in overlay

* Refactor useRenderCursors() into three files, split on DOM and selection tasks.

* Fix type export

* Fix selection direction when using undo/redo

* Add e2e tests for full selection awareness

* Reduce opacity of selection rectangle in overlay

* Pre-compute overlayRect, pre-compute DOM elements where possible

* Rename "CursorContext" to "OverlayContext"

* Extract CursorCoords type, add rect collection types for readability

* Fix type error

* Remerge collaborator styling fix from #75700

* Deduplicate selection rects when text is formatted

* Fix merge of view.getComputedStyle() fix from #75652

Co-authored-by: alecgeatches <alecgeatches@git.wordpress.org>
Co-authored-by: maxschmeling <maxschmeling@git.wordpress.org>
Co-authored-by: chriszarate <czarate@git.wordpress.org>
@chriszarate chriszarate added Backported to WP Core Pull request that has been successfully merged into WP Core and removed Backport to WP 7.0 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta labels Mar 11, 2026
pento pushed a commit to WordPress/wordpress-develop that referenced this pull request Mar 12, 2026
This updates the pinned hash from the `gutenberg` from `9b8144036fa5faf75de43d4502ff9809fcf689ad` to `8c78d87453509661a9f28f978ba2c242d515563b`.

The following changes are included:

- Navigation Editor: Allow any blocks to be inserted by gating contentOnly insertion rules to section blocks (WordPress/gutenberg#76189)
- Add `fetchpriority=low` to `IMG` tags in collapsed Details blocks (WordPress/gutenberg#76269)
- Connectors: Add logo URL support for custom AI providers (WordPress/gutenberg#76190)
- Cover Block: Add a playlist parameter to loop YouTube background videos. (WordPress/gutenberg#76004)
- Connectors: Memoize getConnectors selector (WordPress/gutenberg#76339)
- HTML Block: Fix broken layout (WordPress/gutenberg#76278)
- Tests: Skip connector logo URL tests when AI Client is unavailable (WordPress/gutenberg#76343)
- Navigation Overlay: Explicitly set fetchpriority for images (WordPress/gutenberg#76208)
- Connectors: Show API key source for env vars and wp-config constants (WordPress/gutenberg#76355)
- Connectors: Move API key validation and masking to REST dispatch level (WordPress/gutenberg#76327)
- Connectors: Replace apiFetch with core-data store selectors (WordPress/gutenberg#76333)
- Do not sync local attributes (WordPress/gutenberg#76267)
- Add `fetchpriority=low` to `IMG` tags in collapsed Accordion Item blocks (WordPress/gutenberg#76336)
- Implement disconnection debounce after initial connection (WordPress/gutenberg#76114)
- Allow Post Content to be edited when 'Show template' is active and Post content is nested in a Template Part (WordPress/gutenberg#76305)
- Fix: Document Bar: Back button flickers (WordPress/gutenberg#76320)
- RTC: Move event hooks from editor to core-data (WordPress/gutenberg#76358)
- fix(navigation): prevent right-justified submenu overflow in custom overlays (WordPress/gutenberg#76360)
- Connectors: Add connectors registry for extensibility (WordPress/gutenberg#76364)
- Connectors: Add empty state when no connectors are registered (WordPress/gutenberg#76375)
- Temp: Disable RTC in the site editor (WordPress/gutenberg#76223)
- Connectors: Add AI Experiments plugin callout with install/activate functionality (WordPress/gutenberg#76379)
- Editor: Polish real-time collaboration presence UI and move Avatar to editor package (WordPress/gutenberg#75652) (WordPress/gutenberg#76365)
- RTC: Add collaborator selection highlighting in rich text (WordPress/gutenberg#76107)
- Sync changes from `wp_enqueue_global_styles()` to Gutenberg override (WordPress/gutenberg#76127)
- [RTC] Fix performance regression on post save (WordPress/gutenberg#76370)
- Media: Enable AVIF support for client-side uploads (WordPress/gutenberg#76371)
- Connectors: Move plugin status computation to script module data (WordPress/gutenberg#76409)
- Revisions: Skip rendered fields in REST API responses (WordPress/gutenberg#76347)
- E2E Tests: Add connector setup flow tests with test AI provider (WordPress/gutenberg#76433)
- RTC: Place sync connection modal in front of popover (WordPress/gutenberg#76431)
- Connectors: Sync PHP code with WordPress Core (WordPress/gutenberg#76443)
- Editor: Show own presence in collaborative editing sessions (WordPress/gutenberg#76413) (WordPress/gutenberg#76445)

A full list of changes can be found on GitHub: https://github.com/WordPress/gutenberg/compare/9b8144036fa5faf75de43d4502ff9809fcf689ad…8c78d87453509661a9f28f978ba2c242d515563b.

Log created with:

git log --reverse --format="- %s" 9b8144036fa5faf75de43d4502ff9809fcf689ad..8c78d87453509661a9f28f978ba2c242d515563b | sed 's|#\([0-9][0-9]*\)|https://github.com/WordPress/gutenberg/pull/\1|g; /github\.com\/WordPress\/gutenberg\/pull/!d' | pbcopy

See #64595.


git-svn-id: https://develop.svn.wordpress.org/trunk@61988 602fd350-edb4-49c9-b593-d223f7449a82
markjaquith pushed a commit to markjaquith/WordPress that referenced this pull request Mar 12, 2026
This updates the pinned hash from the `gutenberg` from `9b8144036fa5faf75de43d4502ff9809fcf689ad` to `8c78d87453509661a9f28f978ba2c242d515563b`.

The following changes are included:

- Navigation Editor: Allow any blocks to be inserted by gating contentOnly insertion rules to section blocks (WordPress/gutenberg#76189)
- Add `fetchpriority=low` to `IMG` tags in collapsed Details blocks (WordPress/gutenberg#76269)
- Connectors: Add logo URL support for custom AI providers (WordPress/gutenberg#76190)
- Cover Block: Add a playlist parameter to loop YouTube background videos. (WordPress/gutenberg#76004)
- Connectors: Memoize getConnectors selector (WordPress/gutenberg#76339)
- HTML Block: Fix broken layout (WordPress/gutenberg#76278)
- Tests: Skip connector logo URL tests when AI Client is unavailable (WordPress/gutenberg#76343)
- Navigation Overlay: Explicitly set fetchpriority for images (WordPress/gutenberg#76208)
- Connectors: Show API key source for env vars and wp-config constants (WordPress/gutenberg#76355)
- Connectors: Move API key validation and masking to REST dispatch level (WordPress/gutenberg#76327)
- Connectors: Replace apiFetch with core-data store selectors (WordPress/gutenberg#76333)
- Do not sync local attributes (WordPress/gutenberg#76267)
- Add `fetchpriority=low` to `IMG` tags in collapsed Accordion Item blocks (WordPress/gutenberg#76336)
- Implement disconnection debounce after initial connection (WordPress/gutenberg#76114)
- Allow Post Content to be edited when 'Show template' is active and Post content is nested in a Template Part (WordPress/gutenberg#76305)
- Fix: Document Bar: Back button flickers (WordPress/gutenberg#76320)
- RTC: Move event hooks from editor to core-data (WordPress/gutenberg#76358)
- fix(navigation): prevent right-justified submenu overflow in custom overlays (WordPress/gutenberg#76360)
- Connectors: Add connectors registry for extensibility (WordPress/gutenberg#76364)
- Connectors: Add empty state when no connectors are registered (WordPress/gutenberg#76375)
- Temp: Disable RTC in the site editor (WordPress/gutenberg#76223)
- Connectors: Add AI Experiments plugin callout with install/activate functionality (WordPress/gutenberg#76379)
- Editor: Polish real-time collaboration presence UI and move Avatar to editor package (WordPress/gutenberg#75652) (WordPress/gutenberg#76365)
- RTC: Add collaborator selection highlighting in rich text (WordPress/gutenberg#76107)
- Sync changes from `wp_enqueue_global_styles()` to Gutenberg override (WordPress/gutenberg#76127)
- [RTC] Fix performance regression on post save (WordPress/gutenberg#76370)
- Media: Enable AVIF support for client-side uploads (WordPress/gutenberg#76371)
- Connectors: Move plugin status computation to script module data (WordPress/gutenberg#76409)
- Revisions: Skip rendered fields in REST API responses (WordPress/gutenberg#76347)
- E2E Tests: Add connector setup flow tests with test AI provider (WordPress/gutenberg#76433)
- RTC: Place sync connection modal in front of popover (WordPress/gutenberg#76431)
- Connectors: Sync PHP code with WordPress Core (WordPress/gutenberg#76443)
- Editor: Show own presence in collaborative editing sessions (WordPress/gutenberg#76413) (WordPress/gutenberg#76445)

A full list of changes can be found on GitHub: https://github.com/WordPress/gutenberg/compare/9b8144036fa5faf75de43d4502ff9809fcf689ad…8c78d87453509661a9f28f978ba2c242d515563b.

Log created with:

git log --reverse --format="- %s" 9b8144036fa5faf75de43d4502ff9809fcf689ad..8c78d87453509661a9f28f978ba2c242d515563b | sed 's|#\([0-9][0-9]*\)|https://github.com/WordPress/gutenberg/pull/\1|g; /github\.com\/WordPress\/gutenberg\/pull/!d' | pbcopy

See #64595.

Built from https://develop.svn.wordpress.org/trunk@61988


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

Labels

Backported to WP Core Pull request that has been successfully merged into WP Core [Feature] Real-time Collaboration Phase 3 of the Gutenberg roadmap around real-time collaboration [Package] Components /packages/components [Package] Editor /packages/editor [Type] Task Issues or PRs that have been broken down into an individual action to take

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants