@wordpress/editor
Version:
Enhanced block editor for WordPress posts.
73 lines (68 loc) • 3.07 kB
JavaScript
import { useMemo } from '@wordpress/element';
import { useStyleOverride } from '@wordpress/block-editor';
import { getAvatarBorderColor, getNoteMarkerSelector } from './utils';
// Hex alpha suffixes for the rest / active states. Kept low so the marker
// reads as a soft tint at rest and gets noticeably stronger when focused or
// hovered. (0x40 ≈ 25%, 0x80 ≈ 50%.)
const REST_ALPHA = '40';
const ACTIVE_ALPHA = '80';
// Reset the browser's default `<mark>` styling so the per-author rules below
// are what readers actually see (without it, `mark` ships with a bright yellow
// background in every browser). The `core/note` anchor marker serializes as a
// `<mark>` and would otherwise inherit the yellow default in the editor canvas.
const BASE_RESET = 'mark.wp-note{background-color:transparent;color:inherit;}';
/**
* Build the CSS rule set that tints each inline-note marker with its author's
* avatar color. Pure helper extracted so it can be unit-tested without React.
*
* @param {Array} threads Unresolved note threads (each with `id` and `author`).
* @param {string|null} selectedId ID of the currently selected note, if any.
* @return {string} A serialized CSS string targeting the in-content note markers.
*/
export function buildHighlightCss( threads, selectedId = null ) {
const rules = [ BASE_RESET ];
for ( const thread of threads ?? [] ) {
if ( ! thread?.id ) {
continue;
}
const color = getAvatarBorderColor( thread.author ?? 0 );
// The `core/note` format serializes the id into `data-id`, so the marker
// can be targeted directly without a separate annotation layer.
const sel = getNoteMarkerSelector( thread.id );
rules.push( `${ sel }{background-color:${ color }${ REST_ALPHA };}` );
rules.push(
`${ sel }:hover,${ sel }:focus-within{background-color:${ color }${ ACTIVE_ALPHA };}`
);
if ( selectedId && String( selectedId ) === String( thread.id ) ) {
rules.push(
`${ sel }{background-color:${ color }${ ACTIVE_ALPHA };}`
);
}
}
return rules.join( '' );
}
/**
* Injects per-note background rules into the editor canvas so inline-note
* markers carry their author's avatar color. The `core/note` format serializes
* each marker as `<mark class="wp-note" data-id="{noteId}">`, which we target
* directly.
*
* Uses `useStyleOverride` so the styles reach the iframed canvas; a plain
* `<style>` element rendered in the sidebar would only affect the parent doc.
*
* Opacity boosts on `:hover`, `:focus-within`, and when the matching thread is
* the editor's selected note.
*
* @param {Object} props
* @param {Array} props.threads Unresolved note threads.
* @param {string|null} [props.selectedId] ID of the currently selected note.
* @return {null} Renders nothing; styles are applied via `useStyleOverride`.
*/
export function NoteHighlightStyles( { threads, selectedId } ) {
const css = useMemo(
() => buildHighlightCss( threads, selectedId ),
[ threads, selectedId ]
);
useStyleOverride( { id: 'core-note-highlights', css } );
return null;
}