fix(editor): prevent cursor jumping to title when pressing backspace on the begin of edgeless note (#12410)

Close [BS-3492](https://linear.app/affine-design/issue/BS-3492/白板上的note,在开头按退格键,光标会到page-block的title上)

### Before

https://github.com/user-attachments/assets/334504f2-30f3-4ce2-ba60-a2688a811b53

### After

https://github.com/user-attachments/assets/be26be6c-6cfc-4f69-82b7-1127e0d10a1a

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **Bug Fixes**
  - Improved behavior when deleting a note block to ensure the cursor focus does not incorrectly jump to the page title after pressing backspace.

- **Tests**
  - Added a new test to verify that focus remains within the note block after deletion, preventing unwanted cursor movement to the page title.
  - Introduced a utility to check if the document title is focused during tests.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
L-Sun
2025-05-22 03:40:16 +00:00
parent ef717e617c
commit dd816f3284
3 changed files with 43 additions and 28 deletions

View File

@@ -8,6 +8,7 @@ import {
EdgelessTextBlockModel,
ImageBlockModel,
ListBlockModel,
NoteBlockModel,
ParagraphBlockModel,
type RootBlockModel,
} from '@blocksuite/affine-model';
@@ -19,7 +20,6 @@ import { EMBED_BLOCK_MODEL_LIST } from '@blocksuite/affine-shared/consts';
import type { ExtendedModel } from '@blocksuite/affine-shared/types';
import {
focusTitle,
getDocTitleInlineEditor,
getPrevContentBlock,
matchModels,
} from '@blocksuite/affine-shared/utils';
@@ -122,41 +122,39 @@ function handleNoPreviousSibling(editorHost: EditorHost, model: ExtendedModel) {
const text = model.text;
const parent = doc.getParent(model);
if (!parent) return false;
const titleEditor = getDocTitleInlineEditor(editorHost);
// Probably no title, e.g. in edgeless mode
if (!titleEditor) {
if (
matchModels(parent, [EdgelessTextBlockModel]) ||
model.children.length > 0
) {
if (matchModels(parent, [NoteBlockModel]) && parent.isPageBlock()) {
const rootModel = model.store.root as RootBlockModel;
const title = rootModel.props.title;
doc.captureSync();
let textLength = 0;
if (text) {
textLength = text.length;
title.join(text);
}
// Preserve at least one block to be able to focus on container click
if (doc.getNext(model) || model.children.length > 0) {
doc.deleteBlock(model, {
bringChildrenTo: parent,
});
return true;
} else {
text?.clear();
}
return false;
focusTitle(editorHost, title.length - textLength);
return true;
}
const rootModel = model.store.root as RootBlockModel;
const title = rootModel.props.title;
doc.captureSync();
let textLength = 0;
if (text) {
textLength = text.length;
title.join(text);
}
// Preserve at least one block to be able to focus on container click
if (doc.getNext(model) || model.children.length > 0) {
const parent = doc.getParent(model);
if (!parent) return false;
if (
matchModels(parent, [EdgelessTextBlockModel]) ||
model.children.length > 0
) {
doc.deleteBlock(model, {
bringChildrenTo: parent,
});
} else {
text?.clear();
return true;
}
focusTitle(editorHost, title.length - textLength);
return true;
return false;
}