Repository navigation
Commit cbda05f
[Real-time collaboration] Refine collaborator overlay with Avatar component integration (#75595)
* Add CollaboratorsOverlay with cursor and block highlight rendering
Initial implementation of the real-time collaboration overlay system:
cursor rendering via CursorRegistry, block selection highlighting,
overlay style injection into the editor iframe, and BlockCanvasCover
SlotFill integration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Render awareness cursors with JSX instead of manual DOM manipulation
* big fix
Bug: useBlockHighlighting crashes with TypeError: Cannot read properties of undefined (reading 'WholeBlock') when two users edit the same post.
Cause: In use-block-highlighting.ts:15, SelectionType is destructured from unlock(coreDataPrivateApis), but it was never added to the private APIs in private-apis.js. It's undefined at runtime.
Fix: Import SelectionType directly from @wordpress/core-data (it's already a public export), matching the pattern in use-render-cursors.ts. Remove it from the unlock() destructure.
* update collaborator avatar styles
* refining styles to pull from design system.
* Add WCAG-compliant collaborator color derivation using OKLCH
Replace the naive RGB lightness-shift color system with a contrast-aware
pipeline that derives two purpose-specific colors per collaborator from
seed colors in the palette:
- strokeColor: meets 3.1:1 contrast against white (WCAG 2.1 SC 1.4.11
for UI components like borders and block highlights)
- backgroundColor: meets 7:1 contrast against white (WCAG 2.1 SC 1.4.3
AA for white text on colored cursor labels)
Colors are manipulated in OKLCH space (Björn Ottosson's OKLAB) for
perceptually uniform darkening — only lightness is reduced while chroma
and hue are preserved. This avoids the hue drift that CIE LCH exhibits
when darkening blues. The implementation is ~60 lines of pure math with
zero external dependencies.
Also updates the seed palette to use more vibrant, distinct colors and
replaces the RGB-shift overflow strategy with OKLCH hue rotation for
generating new colors when all palette slots are taken.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Align collaborator block highlight with core selection outline
Replace the inline box-shadow approach for RTC block highlighting with
the same outline-based method core uses for `.is-highlighted` blocks.
This ensures consistent outline style, width, offset, and zoom scaling
across both the default selection and collaborator highlights.
- Switch from inline `style.boxShadow` to a `.is-collaborator-selected`
CSS class with a `--collaborator-outline-color` custom property
- Reuse the `selected-block-focus()` mixin from `@wordpress/base-styles`
- Add `:not(:focus)` guard so the user's own selection always wins
- Extract shared `collaborator-contrast-shadow()` mixin used by both the
block highlight and avatar components
- Add compiled `COLLABORATOR_CONTRAST_SHADOW` constant for iframe styles
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Update collaborator cursor label to pill-shaped avatar badge
Redesign the cursor label from a plain text tag to a pill-shaped badge
with the collaborator's avatar. The label defaults to showing just the
avatar circle and expands on hover to reveal the username.
- Add `collaborator-avatar()` mixin for shared avatar styles between
the presence list and cursor label, using `--avatar-url` CSS custom
property
- Restyle cursor label as a flex pill with avatar + name, white outline
contrast ring, and hover expand transition
- Add white outline + elevation shadow to cursor caret for contrast
- Fix block highlight inset shadow: use a wider inset that extends past
the outline so the white inner ring remains visible
- Consolidate `collaborator-contrast-shadow()` to include inset ring,
fixing the `--with-color-border` avatar variant losing its inner ring
- Sync all changes to `overlay-iframe-styles.ts` for iframe injection
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add avatar initials fallback and refine cursor overlay styles
When a collaborator has no custom Gravatar, display their first two
initials on their assigned background color instead of the default
placeholder image. A shared gravatar-check utility detects real vs
default avatars by preloading with `d=404` and caching the result
for both the React presence avatar and the imperative cursor overlay.
Also refines cursor overlay visuals: Safari-style blink animation,
rounded caret edges, label centered on caret midpoint, and
box-sizing fix for accurate avatar dimensions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add @ts-expect-error for untyped @wordpress/block-editor import
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Components: Use Avatar and AvatarGroup in RTC collaborator UI
Replace custom avatar implementations across the collaborators-presence
and collaborators-overlay features with the new Avatar and AvatarGroup
private components from @wordpress/components.
- Add Avatar and AvatarGroup components to the RTC branch (copied from
add/avatar-component) and register them as private APIs
- Replace hand-rolled avatar in presence toolbar with AvatarGroup
- Replace custom avatar in collaborators list with Avatar component
- Replace manual cursor label markup in overlay with Avatar badge mode
- Inject compiled Avatar CSS into the iframe via useStyleOverride since
wp-components styles are excluded from the editor canvas
- Rename `has-border-color` modifier to `has-avatar-border-color` to
avoid collision with the WordPress block support class of the same name
- Add `width: max-content` to overlay Avatar so CSS Grid fr units resolve
correctly in the absolutely-positioned context
- Delete old avatar.tsx, avatar.scss, and _collaborator-mixins.scss
- Remove unused COLLABORATOR_CONTRAST_SHADOW constant
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add Gravatar default detection for Avatar initials fallback
WordPress always returns a Gravatar URL even when the user has no custom
image. Add a utility that rewrites the URL with `d=404` and preloads it
to detect default placeholders. When a default is detected, `undefined`
is passed as the Avatar `src`, triggering its built-in initials fallback.
- Add `gravatar-check.ts` with async image preload, module-level cache,
and callback queue for multiple consumers
- Add `useResolveGravatars` hook to initiate checks and trigger
re-renders when results arrive
- Integrate into cursor overlay (use-render-cursors), presence toolbar,
and collaborators list via `resolveGravatarUrl(getAvatarUrl(urls))`
- Re-enable inner white ring box-shadow on bordered avatar images
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Move collaborator colors from core-data to editor package
Replace the OKLCH color generation system in core-data with the simpler
`AVATAR_BORDER_COLORS` array from `collab-sidebar/utils.js`. All editor
consumers now use `getAvatarBorderColor(userId)` for a single color per
collaborator (border, cursor, and block highlight), removing the need for
separate stroke/background derivation and ~230 lines of color math.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix CSS collision with block supports `[style*=border-color]` selector
Rename `--components-avatar-border-color` to `--components-avatar-outline-color`
to avoid matching `html :where([style*="border-color"])` in block-library's
common.scss, which forces `border-style: solid` on any element whose style
attribute contains the substring "border-color". Also adds explicit type
parameter to `useMergeRefs` to fix TS2322.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Components: Add CHANGELOG entry for Avatar and AvatarGroup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Block Editor: Remove duplicate BlockCanvasCover slot
The squash/rebase accidentally introduced a second BlockCanvasCover.Slot
after the block content in both iframe and non-iframe paths. This extra
Slot rendered a container element below .editor-styles-wrapper, causing
the padding appender's click-to-append to fail — clicks near the bottom
of the canvas would hit the Slot element instead of the editor's 40vh
padding area, bypassing the target check. The existing Slot before the
content is sufficient since the cover uses position: absolute.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Remove custom gravatar resolver
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: chriszarate <chris.zarate@automattic.com>
Co-authored-by: Max Schmeling <max.schmeling@automattic.com>1 parent a6cc8c2 commit cbda05f
28 files changed
Lines changed: 691 additions & 388 deletions
File tree
- packages
- components
- src
- avatar-group
- avatar
- core-data/src
- awareness
- test
- hooks/test
- editor/src/components
- collaborators-overlay
- collaborators-presence
- styles
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
| 22 | + | |
22 | 23 | | |
23 | 24 | | |
24 | 25 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
0 commit comments