Skip to content

Commit

Permalink
fix(page): delete nested item in the middle should not change the hie…
Browse files Browse the repository at this point in the history
…rarchy of its siblings below (#4933)
  • Loading branch information
Flrande committed Sep 29, 2023
1 parent dd640ee commit bf8a101
Show file tree
Hide file tree
Showing 6 changed files with 293 additions and 57 deletions.
61 changes: 44 additions & 17 deletions packages/blocks/src/components/rich-text/rich-text-operations.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { assertExists } from '@blocksuite/global/utils';
import type { BaseBlockModel, Page } from '@blocksuite/store';
import type { Page } from '@blocksuite/store';
import { type BaseBlockModel } from '@blocksuite/store';
import { Text } from '@blocksuite/store';

import { supportsChildren } from '../../__internal__/utils/common.js';
Expand All @@ -23,7 +24,7 @@ import {
focusTitle,
} from '../../__internal__/utils/selection.js';
import type { ExtendedModel } from '../../__internal__/utils/types.js';
import type { ListBlockModel, PageBlockModel } from '../../models.js';
import { type ListBlockModel, type PageBlockModel } from '../../models.js';

export function handleBlockEndEnter(page: Page, model: ExtendedModel) {
const parent = page.getParent(model);
Expand Down Expand Up @@ -408,12 +409,6 @@ function handleCodeBlockForwardDelete(_page: Page, model: ExtendedModel) {
return true;
}

function handleDatabaseBlockBackspace(page: Page, model: ExtendedModel) {
if (!isInsideBlockByFlavour(page, model, 'affine:database')) return false;

return true;
}

function handleDatabaseBlockForwardDelete(page: Page, model: ExtendedModel) {
if (!isInsideBlockByFlavour(page, model, 'affine:database')) return false;

Expand Down Expand Up @@ -578,8 +573,12 @@ function handleNoPreviousSibling(page: Page, model: ExtendedModel) {
}

// Preserve at least one block to be able to focus on container click
if (page.getNextSibling(model)) {
page.deleteBlock(model);
if (page.getNextSibling(model) || model.children.length > 0) {
const parent = page.getParent(model);
assertExists(parent);
page.deleteBlock(model, {
bringChildrenTo: parent,
});
} else {
text?.clear();
}
Expand All @@ -593,6 +592,25 @@ function handleParagraphDeleteActions(page: Page, model: ExtendedModel) {
const previousSibling = getPreviousBlock(model);
if (!previousSibling) {
return handleNoPreviousSibling(page, model);
} else if (
matchFlavours(previousSibling, ['affine:paragraph', 'affine:list'])
) {
const modelIndex = parent.children.indexOf(model);
if (
(modelIndex === -1 || modelIndex === parent.children.length - 1) &&
parent.role === 'content'
)
return false;
const lengthBeforeJoin = previousSibling.text?.length ?? 0;
previousSibling.text?.join(model.text as Text);
page.deleteBlock(model, {
bringChildrenTo: parent,
});
asyncSetVRange(previousSibling, {
index: lengthBeforeJoin,
length: 0,
});
return true;
}

// TODO handle in block service
Expand Down Expand Up @@ -622,18 +640,28 @@ function handleParagraphBlockBackspace(page: Page, model: ExtendedModel) {
return true;
}

// Before press backspace
// - line1
// - line2
// - |aaa
// - line3
//
// After press backspace
// - line1
// - line2|aaa
// - line3
const isHandled = handleParagraphDeleteActions(page, model);
if (isHandled) return true;

// Before
// Before press backspace
// - line1
// - | <- cursor here, press backspace
// - line3
// - line2
// - |aaa
//
// After
// After press backspace
// - line1
// - | <- cursor here
// - line3
// - line2
// - |aaa
handleOutdent(page, model);
return true;
}
Expand Down Expand Up @@ -788,7 +816,6 @@ export function handleLineStartBackspace(page: Page, model: ExtendedModel) {
handleListBlockBackspace(page, model) ||
handleParagraphBlockBackspace(page, model)
) {
handleDatabaseBlockBackspace(page, model);
return;
}

Expand Down
4 changes: 2 additions & 2 deletions tests/hotkey.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ import {
pressArrowLeft,
pressArrowRight,
pressArrowUp,
pressBackspace,
pressEnter,
pressForwardDelete,
pressShiftTab,
pressTab,
readClipboardText,
redoByClick,
Expand Down Expand Up @@ -1159,7 +1159,7 @@ test.describe('keyboard operation to move block up or down', () => {
await pressTab(page);
await type(page, 'world');
await pressEnter(page);
await pressBackspace(page);
await pressShiftTab(page);
await type(page, 'foo');
await assertRichTexts(page, ['hello', 'world', 'foo']);
await assertBlockChildrenIds(page, '2', ['3']);
Expand Down
42 changes: 35 additions & 7 deletions tests/list.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
focusRichText,
initEmptyParagraphState,
initThreeLists,
pressArrowLeft,
pressArrowUp,
pressBackspace,
pressBackspaceWithShortKey,
Expand Down Expand Up @@ -505,12 +506,13 @@ test.describe('indent correctly when deleting list item', () => {
await pressEnter(page);
await type(page, 'd');
await pressArrowUp(page);
await pressBackspace(page);
await pressArrowLeft(page);
await pressBackspace(page);
await pressBackspace(page);

await assertBlockChildrenIds(page, '3', ['4']);
await assertBlockChildrenIds(page, '7', ['6']);
await assertBlockChildrenIds(page, '3', ['4', '6']);
await assertRichTexts(page, ['a', 'bc', 'd']);
await assertRichTextVRange(page, 1, 1);
});

test('merge two lists', async ({ page }) => {
Expand Down Expand Up @@ -552,26 +554,52 @@ test.describe('indent correctly when deleting list item', () => {
});

test('delete list item with nested children items', async ({ page }) => {
await enterPlaygroundWithList(page); // 0(1(2,3,4))
await enterPlaygroundWithList(page);

await focusRichText(page, 0);
await type(page, '1');

await focusRichText(page, 1);
await pressTab(page);
await type(page, '2');

await focusRichText(page, 2);
await pressTab(page);
await pressTab(page);
await type(page, '3');

await pressEnter(page); // 0(1(2,3,4,5))
await type(page, '3');
await pressEnter(page);
await type(page, '4');

await focusRichText(page, 1);
await pressArrowLeft(page);
// 1
// |2
// 3
// 4

await pressBackspace(page);
await waitNextFrame(page);
// 1
// |2 (transformed to paragraph)
// 3
// 4

await pressBackspace(page);
await pressBackspace(page); // 0(1(2,4,5))
await waitNextFrame(page);
// 1
// |2
// 3
// 4

await pressBackspace(page);
await waitNextFrame(page);
// 1|2
// 3
// 4

await assertRichTextVRange(page, 0, 1);
await assertRichTexts(page, ['12', '3', '4']);
await assertBlockChildrenIds(page, '1', ['2', '4', '5']);
});

Expand Down
5 changes: 5 additions & 0 deletions tests/markdown.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -520,10 +520,15 @@ test('inline code should work when pressing Enter followed by Backspace twice',

await type(page, '`test`');
await pressSpace(page);
await waitNextFrame(page);
await pressArrowLeft(page);
await waitNextFrame(page);
await pressEnter(page);
await waitNextFrame(page);
await pressBackspace(page);
await waitNextFrame(page);
await pressEnter(page);
await waitNextFrame(page);
await pressBackspace(page);

await assertRichTexts(page, ['test']);
Expand Down
Loading

3 comments on commit bf8a101

@vercel
Copy link

@vercel vercel bot commented on bf8a101 Sep 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

blocksuite – ./packages/playground

blocksuite-toeverything.vercel.app
blocksuite-five.vercel.app
blocksuite-git-master-toeverything.vercel.app

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Size Report

Bundles

Entry Size Gzip Brotli
examples/basic 11 MB (+2.22 kB) 2.17 MB (+34 B) 1.35 MB (+1.97 kB)

Packages

Name Size Gzip Brotli
blocks 1.51 MB (+310 B) 377 kB (-35 B) 285 kB (+127 B)
editor 8.85 kB 3.33 kB 2.92 kB
store 60.3 kB 17.4 kB 15.6 kB
virgo 30.2 kB 8.6 kB 7.7 kB

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Size Report

Bundles

Entry Size Gzip Brotli
examples/basic 11 MB 2.17 MB 1.35 MB

Packages

Name Size Gzip Brotli
blocks 1.51 MB 377 kB 285 kB
editor 8.85 kB 3.33 kB 2.92 kB
store 60.3 kB 17.4 kB 15.6 kB
virgo 30.2 kB 8.6 kB 7.7 kB

Please sign in to comment.