fix: preserve image selection while hovering toolbar

This commit is contained in:
lucaronin
2026-04-19 10:48:45 +02:00
parent 9ecefc90d5
commit 862af864d3
3 changed files with 74 additions and 1 deletions

View File

@@ -1,9 +1,21 @@
import type {
BlockNoteEditor,
BlockSchema,
InlineContentSchema,
StyleSchema,
} from '@blocknote/core'
import { useEffect, useRef, type RefObject } from 'react'
type RectLike = Pick<DOMRect, 'left' | 'right' | 'top' | 'bottom'>
const HOVER_BRIDGE_PADDING_X = 8
const HOVER_BRIDGE_PADDING_Y = 8
const FORMATTING_TOOLBAR_FILE_BLOCK_TYPES = new Set([
'audio',
'file',
'image',
'video',
])
function isVisibleRect(rect: RectLike) {
return rect.right > rect.left && rect.bottom > rect.top
@@ -90,6 +102,32 @@ export function shouldSuppressFormattingToolbarHoverUpdate({
)
}
function getActiveFormattingToolbarFileBlockId(
editor: BlockNoteEditor<BlockSchema, InlineContentSchema, StyleSchema>,
) {
const selectedBlock =
editor.getSelection()?.blocks[0] ?? editor.getTextCursorPosition().block
return FORMATTING_TOOLBAR_FILE_BLOCK_TYPES.has(selectedBlock.type)
? selectedBlock.id
: null
}
function restoreFormattingToolbarFileBlockSelection(
editor: BlockNoteEditor<BlockSchema, InlineContentSchema, StyleSchema>,
selectedFileBlockIdRef: RefObject<string | null>,
) {
const selectedFileBlockId = selectedFileBlockIdRef.current
if (!selectedFileBlockId) return
if (getActiveFormattingToolbarFileBlockId(editor) === selectedFileBlockId) return
try {
editor.setTextCursorPosition(selectedFileBlockId)
} catch {
// The image block may have been deleted or replaced while the toolbar stayed open.
}
}
function useLastSelectedFormattingToolbarFileBlockId(
selectedFileBlockId: string | null,
isOpen: boolean,
@@ -120,10 +158,12 @@ function getFormattingToolbarHoverGuardEnvironment(container: HTMLElement | null
}
function createFormattingToolbarHoverGuardHandler({
editor,
container,
doc,
selectedFileBlockIdRef,
}: {
editor: BlockNoteEditor<BlockSchema, InlineContentSchema, StyleSchema>
container: HTMLElement
doc: Document
selectedFileBlockIdRef: RefObject<string | null>
@@ -141,15 +181,18 @@ function createFormattingToolbarHoverGuardHandler({
return
}
restoreFormattingToolbarFileBlockSelection(editor, selectedFileBlockIdRef)
event.stopPropagation()
}
}
export function useBlockNoteFormattingToolbarHoverGuard({
editor,
container,
selectedFileBlockId,
isOpen,
}: {
editor: BlockNoteEditor<BlockSchema, InlineContentSchema, StyleSchema>
container: HTMLElement | null
selectedFileBlockId: string | null
isOpen: boolean
@@ -166,6 +209,7 @@ export function useBlockNoteFormattingToolbarHoverGuard({
if (!environment) return
const handleMouseMove = createFormattingToolbarHoverGuardHandler({
editor,
container: environment.container,
doc: environment.doc,
selectedFileBlockIdRef: lastSelectedFileBlockIdRef,
@@ -175,5 +219,5 @@ export function useBlockNoteFormattingToolbarHoverGuard({
return () => {
environment.view.removeEventListener('mousemove', handleMouseMove, true)
}
}, [container, isOpen, lastSelectedFileBlockIdRef])
}, [container, editor, isOpen, lastSelectedFileBlockIdRef])
}

View File

@@ -476,6 +476,7 @@ export function TolariaFormattingToolbarController(props: {
})
useBlockNoteFormattingToolbarHoverGuard({
editor,
container:
editor.domElement?.closest('.editor__blocknote-container') ??
editor.domElement ??