diff --git a/src/features/editor/ui/HighlightButton.tsx b/src/features/editor/ui/HighlightButton.tsx index a305b36..e7dca88 100644 --- a/src/features/editor/ui/HighlightButton.tsx +++ b/src/features/editor/ui/HighlightButton.tsx @@ -7,13 +7,16 @@ import { Highlighter } from 'lucide-react' import { useCallback } from 'react' /** - * Yellow highlight color value used for the highlight style. + * Unique identifier for the highlighter style. + * Uses a dedicated value ("highlight") instead of BlockNote's built-in + * colour names so that the highlighter and the color-picker's yellow + * are treated as separate styles. */ -const HIGHLIGHT_COLOR = 'yellow' +const HIGHLIGHT_STYLE = 'highlight' /** - * Toggle button that applies or removes a yellow highlight on the - * selected text using BlockNote's built-in `backgroundColor` style. + * Toggle button that applies or removes a fluorescent-yellow highlight + * on the selected text using a custom `backgroundColor` style value. * * The button is hidden when the editor is read-only or no inline * content is selected. It appears active (pressed) when the @@ -26,13 +29,17 @@ export const HighlightButton = () => { const state = useEditorState({ editor, selector: ({ editor }) => { + // Hide the button when the editor is in read-only mode. if (!editor.isEditable) { return undefined } + // Collect the blocks covered by the current selection (or the block at cursor). const selectedBlocks = editor.getSelection()?.blocks || [ editor.getTextCursorPosition().block, ] + + // Hide the button when none of the selected blocks contain inline content. const hasContent = selectedBlocks.some( (block) => block.content !== undefined ) @@ -40,24 +47,30 @@ export const HighlightButton = () => { return undefined } + // Determine whether the highlight style is already applied to the selection. const activeBg = editor.getActiveStyles().backgroundColor - return { active: activeBg === HIGHLIGHT_COLOR } + return { active: activeBg === HIGHLIGHT_STYLE } }, }) + /** + * Toggles the fluorescent highlight on the current editor selection. + * + * Focuses the editor first, then adds or removes the custom + * `backgroundColor: "highlight"` style depending on whether the + * highlight is already active on the selection. + */ const toggleHighlight = useCallback(() => { editor.focus() // eslint-disable-next-line @typescript-eslint/no-explicit-any - const style = { backgroundColor: HIGHLIGHT_COLOR } as any - const isHighlighted = - editor.getActiveStyles().backgroundColor === HIGHLIGHT_COLOR + const style = { backgroundColor: HIGHLIGHT_STYLE } as any - if (isHighlighted) { + if (state?.active) { editor.removeStyles(style) } else { editor.addStyles(style) } - }, [editor]) + }, [editor, state]) if (state === undefined) { return null diff --git a/src/index.css b/src/index.css index 23adffc..dbe3ffc 100644 --- a/src/index.css +++ b/src/index.css @@ -240,6 +240,19 @@ body { color: oklch(0.828 0.111 54); } +/* + * Highlighter markers – shared shape. + * + * Both "yellow" (colour-picker) and "highlight" (dedicated highlighter) use + * the same padding / margin / border-radius to emulate a highlighter stroke. + */ +span[data-style-type="backgroundColor"][data-value="yellow"], +span[data-style-type="backgroundColor"][data-value="highlight"] { + padding: 0.1em 0.15em; + margin-right: 0.1em; + border-radius: 0.2em; +} + /* * Highlighter marker (yellow) - light mode. * @@ -249,9 +262,6 @@ body { */ span[data-style-type="backgroundColor"][data-value="yellow"] { background-color: oklch(0.92 0.17 90); - padding: 0.1em 0.15em; - margin-right: 0.1em; - border-radius: 0.2em; } /* @@ -265,6 +275,24 @@ span[data-style-type="backgroundColor"][data-value="yellow"] { color: oklch(0.25 0.05 85); } +/* + * Highlighter marker (fluorescent) - light mode. + * + * Dedicated highlighter style that is independent from the colour + * picker's "yellow" so the two can use different shades. + */ +span[data-style-type="backgroundColor"][data-value="highlight"] { + background-color: oklch(0.96 0.11 95); +} + +/* + * Highlighter marker (fluorescent) - dark mode. + */ +.dark span[data-style-type="backgroundColor"][data-value="highlight"] { + background-color: oklch(0.75 0.10 95); + color: oklch(0.25 0.05 85); +} + /* * Override BlockNote link colour in dark mode. * @@ -496,28 +524,39 @@ html.cursor-autohide-hidden * { cursor: none !important; } -html.cursor-autohide-hidden [role="dialog"], -html.cursor-autohide-hidden [role="menu"], -html.cursor-autohide-hidden [role="listbox"], -html.cursor-autohide-hidden .bn-suggestion-menu, -html.cursor-autohide-hidden .bn-link-toolbar, -html.cursor-autohide-hidden .bn-color-picker-dropdown, -html.cursor-autohide-hidden .bn-formatting-toolbar, -html.cursor-autohide-hidden .bn-table-handle-menu, -html.cursor-autohide-hidden [data-slot="select-content"], -html.cursor-autohide-hidden [data-slot="dropdown-menu-content"] { +/* + * Interactive overlays that keep the cursor visible during auto-hide. + * + * The `:is()` pseudo-class avoids repeating the `html.cursor-autohide-hidden` + * ancestor for every selector. The first rule targets the overlay containers + * themselves; the second targets their descendants. + */ +html.cursor-autohide-hidden :is( + [role="dialog"], + [role="menu"], + [role="listbox"], + .bn-suggestion-menu, + .bn-link-toolbar, + .bn-color-picker-dropdown, + .bn-formatting-toolbar, + .bn-table-handle-menu, + [data-slot="select-content"], + [data-slot="dropdown-menu-content"] +) { cursor: auto !important; } -html.cursor-autohide-hidden [role="dialog"] *, -html.cursor-autohide-hidden [role="menu"] *, -html.cursor-autohide-hidden [role="listbox"] *, -html.cursor-autohide-hidden .bn-suggestion-menu *, -html.cursor-autohide-hidden .bn-link-toolbar *, -html.cursor-autohide-hidden .bn-color-picker-dropdown *, -html.cursor-autohide-hidden .bn-formatting-toolbar *, -html.cursor-autohide-hidden .bn-table-handle-menu *, -html.cursor-autohide-hidden [data-slot="select-content"] *, -html.cursor-autohide-hidden [data-slot="dropdown-menu-content"] * { +html.cursor-autohide-hidden :is( + [role="dialog"], + [role="menu"], + [role="listbox"], + .bn-suggestion-menu, + .bn-link-toolbar, + .bn-color-picker-dropdown, + .bn-formatting-toolbar, + .bn-table-handle-menu, + [data-slot="select-content"], + [data-slot="dropdown-menu-content"] +) * { cursor: auto !important; }