Commit 8e5e9de
* 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 <[email protected]>
Co-authored-by: dabowman <[email protected]>
Co-authored-by: ciampo <[email protected]>
Co-authored-by: jameskoster <[email protected]>
Co-authored-by: maxschmeling <[email protected]>
Co-authored-by: chriszarate <[email protected]>
Co-authored-by: jasmussen <[email protected]>
Co-authored-by: Mamaduka <[email protected]>
Co-authored-by: tyxla <[email protected]>
1 parent 74a4f25 commit 8e5e9de
30 files changed
Lines changed: 1457 additions & 552 deletions
File tree
- packages
- components
- src
- avatar
- editor
- src
- components
- collab-sidebar
- collaborators-overlay
- collaborators-presence
- avatar-group
- test
- avatar
- test
- styles
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
7 | 18 | | |
8 | 19 | | |
9 | 20 | | |
| |||
This file was deleted.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
18 | | - | |
19 | 17 | | |
20 | 18 | | |
21 | 19 | | |
| |||
36 | 34 | | |
37 | 35 | | |
38 | 36 | | |
39 | | - | |
40 | | - | |
41 | 37 | | |
42 | 38 | | |
43 | 39 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
5 | | - | |
6 | 4 | | |
7 | 5 | | |
8 | 6 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
106 | 106 | | |
107 | 107 | | |
108 | 108 | | |
| 109 | + | |
109 | 110 | | |
110 | 111 | | |
111 | 112 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
22 | | - | |
23 | | - | |
| 22 | + | |
| 23 | + | |
24 | 24 | | |
25 | 25 | | |
26 | | - | |
27 | | - | |
28 | | - | |
29 | | - | |
30 | | - | |
31 | | - | |
32 | | - | |
33 | | - | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
34 | 33 | | |
35 | 34 | | |
36 | 35 | | |
| |||
Lines changed: 126 additions & 0 deletions
| 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 | + | |
Lines changed: 43 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
3 | | - | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
4 | 7 | | |
| 8 | + | |
| 9 | + | |
5 | 10 | | |
6 | 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 | + | |
0 commit comments