fix: keep empty title clicks in h1

This commit is contained in:
lucaronin
2026-04-24 20:13:34 +02:00
parent 135a8a0adf
commit 4701485ee5
3 changed files with 128 additions and 3 deletions

View File

@@ -334,4 +334,44 @@ describe('SingleEditorView', () => {
expect(onChange).toHaveBeenCalledTimes(1)
})
it('routes clicks on the empty title wrapper back into the H1 block', async () => {
const editor = createEditor()
render(
<SingleEditorView
editor={editor as never}
entries={[makeEntry()]}
onNavigateWikilink={vi.fn()}
/>,
)
const container = screen.getByTestId('blocknote-view').closest('.editor__blocknote-container')
expect(container).toBeTruthy()
const titleBlockOuter = document.createElement('div')
titleBlockOuter.className = 'bn-block-outer'
const titleBlock = document.createElement('div')
titleBlock.className = 'bn-block'
const titleHeading = document.createElement('div')
titleHeading.setAttribute('data-content-type', 'heading')
titleHeading.setAttribute('data-level', '1')
const inlineHeading = document.createElement('div')
inlineHeading.className = 'bn-inline-content'
titleHeading.appendChild(inlineHeading)
titleBlock.appendChild(titleHeading)
titleBlockOuter.appendChild(titleBlock)
container?.appendChild(titleBlockOuter)
fireEvent.click(titleBlockOuter)
await act(async () => {
await Promise.resolve()
})
expect(editor.setTextCursorPosition).toHaveBeenCalledWith('heading-block', 'end')
expect(editor.focus).toHaveBeenCalled()
})
})

View File

@@ -141,13 +141,22 @@ function isSelectionInsideElement(element: HTMLElement): boolean {
return Boolean(anchorElement && element.contains(anchorElement))
}
const TITLE_HEADING_SELECTOR = 'h1, [data-content-type="heading"][data-level="1"], [data-content-type="heading"]:not([data-level])'
const TITLE_HEADING_WRAPPER_SELECTOR = '.bn-block-outer, .bn-block'
function findTitleHeadingElement(target: HTMLElement): HTMLElement | null {
const directHeading = target.closest<HTMLElement>(TITLE_HEADING_SELECTOR)
if (directHeading) return directHeading
const titleWrapper = target.closest<HTMLElement>(TITLE_HEADING_WRAPPER_SELECTOR)
return titleWrapper?.querySelector<HTMLElement>(TITLE_HEADING_SELECTOR) ?? null
}
function queueTitleHeadingCursorRepair(
target: HTMLElement,
editor: ReturnType<typeof useCreateBlockNote>,
): boolean {
const titleHeading = target.closest<HTMLElement>(
'h1, [data-content-type="heading"][data-level="1"], [data-content-type="heading"]:not([data-level])',
)
const titleHeading = findTitleHeadingElement(target)
if (!titleHeading) return false
queueMicrotask(() => {