refactor(core): improve editor gap appendParagraph function (#8567)

close AF-1257

Every time we clicked on an empty space at the bottom, a new Paragraph block was created.
Now we change it so that if there is already an empty Paragraph block at the bottom, we focus it instead of creating a new one.
This commit is contained in:
JimmFly
2024-10-24 10:53:18 +00:00
parent 6d7c0d45ce
commit 10963da706
3 changed files with 83 additions and 7 deletions

View File

@@ -1,11 +1,15 @@
import type { DocMode } from '@blocksuite/affine/blocks'; import {
type DocMode,
type NoteBlockModel,
NoteDisplayMode,
} from '@blocksuite/affine/blocks';
import type { import type {
AffineEditorContainer, AffineEditorContainer,
DocTitle, DocTitle,
EdgelessEditor, EdgelessEditor,
PageEditor, PageEditor,
} from '@blocksuite/affine/presets'; } from '@blocksuite/affine/presets';
import { type Doc, Slot } from '@blocksuite/affine/store'; import { type BlockModel, type Doc, Slot } from '@blocksuite/affine/store';
import clsx from 'clsx'; import clsx from 'clsx';
import type React from 'react'; import type React from 'react';
import { import {
@@ -126,10 +130,26 @@ export const BlocksuiteEditorContainer = forwardRef<
const handleClickPageModeBlank = useCallback(() => { const handleClickPageModeBlank = useCallback(() => {
if (shared || page.readonly) return; if (shared || page.readonly) return;
affineEditorContainerProxy.host?.std.command.exec( const std = affineEditorContainerProxy.host?.std;
'appendParagraph' as never, if (!std) {
{} return;
); }
const note = getLastNoteBlock(page);
if (note) {
const lastBlock = note.lastChild();
if (
lastBlock &&
lastBlock.flavour === 'affine:paragraph' &&
lastBlock.text?.length === 0
) {
std.command.exec('focusBlockEnd' as never, {
focusBlock: std.view.getBlock(lastBlock.id) as never,
});
return;
}
}
std.command.exec('appendParagraph' as never, {});
}, [affineEditorContainerProxy, page, shared]); }, [affineEditorContainerProxy, page, shared]);
return ( return (
@@ -162,3 +182,32 @@ export const BlocksuiteEditorContainer = forwardRef<
</div> </div>
); );
}); });
// copy from '@blocksuite/affine-shared/utils'
export function getLastNoteBlock(doc: Doc) {
let note: NoteBlockModel | null = null;
if (!doc.root) return null;
const { children } = doc.root;
for (let i = children.length - 1; i >= 0; i--) {
const child = children[i];
if (
matchFlavours(child, ['affine:note']) &&
child.displayMode !== NoteDisplayMode.EdgelessOnly
) {
note = child as NoteBlockModel;
break;
}
}
return note;
}
export function matchFlavours<Key extends (keyof BlockSuite.BlockModels)[]>(
model: BlockModel | null,
expected: Key
): model is BlockSuite.BlockModels[Key[number]] {
return (
!!model &&
expected.some(
key => (model.flavour as keyof BlockSuite.BlockModels) === key
)
);
}

View File

@@ -1,6 +1,8 @@
import { cssVar } from '@toeverything/theme'; import { cssVar } from '@toeverything/theme';
import { style, type StyleRule } from '@vanilla-extract/css'; import { style, type StyleRule } from '@vanilla-extract/css';
const editorBottomPadding = 32;
export const docEditorRoot = style({ export const docEditorRoot = style({
display: 'block', display: 'block',
background: cssVar('backgroundPrimaryColor'), background: cssVar('backgroundPrimaryColor'),
@@ -29,10 +31,13 @@ export const docEditorGap = style({
display: 'block', display: 'block',
width: '100%', width: '100%',
margin: '0 auto', margin: '0 auto',
paddingTop: 50, // hack to cover the bottom padding of the editor
marginTop: -editorBottomPadding,
paddingTop: 50 + editorBottomPadding,
paddingBottom: 50, paddingBottom: 50,
cursor: 'text', cursor: 'text',
flexGrow: 1, flexGrow: 1,
zIndex: 1,
}); });
const titleTagBasic = style({ const titleTagBasic = style({

View File

@@ -64,3 +64,25 @@ test('link page is useable', async ({ page }) => {
page.locator('.doc-title-container:has-text("page1")') page.locator('.doc-title-container:has-text("page1")')
).toBeVisible(); ).toBeVisible();
}); });
test('append paragraph when click editor gap', async ({ page }) => {
await openHomePage(page);
await waitForEditorLoad(page);
await clickNewPageButton(page);
await waitForEditorLoad(page);
const title = getBlockSuiteEditorTitle(page);
await title.pressSequentially('test title');
await page.keyboard.press('ArrowDown');
await page.keyboard.insertText('test content');
const paragraph = page.locator('affine-paragraph');
const numParagraphs = await paragraph.count();
await page.locator('[data-testid=page-editor-blank]').click();
expect(await paragraph.count()).toBe(numParagraphs + 1);
// click the gap again, should not append another paragraph
await page.locator('[data-testid=page-editor-blank]').click();
expect(await paragraph.count()).toBe(numParagraphs + 1);
});