mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-27 02:42:25 +08:00
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:
@@ -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
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user