From 6884451324b348a1cfb47613142c89e41eb69b11 Mon Sep 17 00:00:00 2001 From: lawvs <18554747+lawvs@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:53:03 +0800 Subject: [PATCH 1/3] fix: backspace with root id --- .../editor-blocks/src/blocks/text/TextView.tsx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/libs/components/editor-blocks/src/blocks/text/TextView.tsx b/libs/components/editor-blocks/src/blocks/text/TextView.tsx index 2a9d77d577..e2ee5bba8d 100644 --- a/libs/components/editor-blocks/src/blocks/text/TextView.tsx +++ b/libs/components/editor-blocks/src/blocks/text/TextView.tsx @@ -2,13 +2,11 @@ import { useState } from 'react'; import { CustomText, TextProps } from '@toeverything/components/common'; import { - mergeGroup, + BlockPendantProvider, RenderBlockChildren, splitGroup, supportChildren, - unwrapGroup, useOnSelect, - BlockPendantProvider, } from '@toeverything/components/editor-core'; import { styled } from '@toeverything/components/ui'; import { Protocol } from '@toeverything/datasource/db-service'; @@ -95,13 +93,21 @@ export const TextView = ({ await block.setType('text'); return true; } + if (editor.getRootBlockId() === block.id) { + // Can not delete + return false; + } const parentBlock = await block.parent(); if (!parentBlock) { return false; } + const preParent = await parentBlock.previousSibling(); - if (Protocol.Block.Type.group === parentBlock.type) { + if ( + Protocol.Block.Type.group === parentBlock.type || + editor.getRootBlockId() === parentBlock.id + ) { const children = await block.children(); const preNode = await block.physicallyPerviousSibling(); // FIXME support children do not means has textBlock From 6e58dff08835d11a3bff85da26bd9fb697638c04 Mon Sep 17 00:00:00 2001 From: lawvs <18554747+lawvs@users.noreply.github.com> Date: Mon, 15 Aug 2022 17:04:42 +0800 Subject: [PATCH 2/3] refactor: batch api --- .../src/blocks/text/TextView.tsx | 11 ++- .../editor-core/src/editor/editor.ts | 83 ++++++++++++------- 2 files changed, 58 insertions(+), 36 deletions(-) diff --git a/libs/components/editor-blocks/src/blocks/text/TextView.tsx b/libs/components/editor-blocks/src/blocks/text/TextView.tsx index e2ee5bba8d..04411b386b 100644 --- a/libs/components/editor-blocks/src/blocks/text/TextView.tsx +++ b/libs/components/editor-blocks/src/blocks/text/TextView.tsx @@ -83,8 +83,8 @@ export const TextView = ({ return true; }; - const onBackspace: TextProps['handleBackSpace'] = async props => { - return await editor.withSuspend(async () => { + const onBackspace: TextProps['handleBackSpace'] = editor.withBatch( + async props => { const { isCollAndStart } = props; if (!isCollAndStart) { return false; @@ -114,7 +114,6 @@ export const TextView = ({ // TODO: abstract this part of code if (preNode) { if (supportChildren(preNode)) { - editor.suspend(true); await editor.selectionManager.activePreviousNode( block.id, 'end' @@ -133,7 +132,6 @@ export const TextView = ({ } await preNode.append(...children); await block.remove(); - editor.suspend(false); } else { // TODO: point does not clear await editor.selectionManager.activePreviousNode( @@ -200,8 +198,9 @@ export const TextView = ({ ); } return true; - }); - }; + } + ); + const handleConvert = async ( toType: string, options?: Record diff --git a/libs/components/editor-core/src/editor/editor.ts b/libs/components/editor-core/src/editor/editor.ts index 24854735f4..16cca74950 100644 --- a/libs/components/editor-core/src/editor/editor.ts +++ b/libs/components/editor-core/src/editor/editor.ts @@ -2,40 +2,40 @@ import HotKeys from 'hotkeys-js'; import LRUCache from 'lru-cache'; -import { services } from '@toeverything/datasource/db-service'; +import type { PatchNode } from '@toeverything/components/ui'; import type { BlockFlavors, ReturnEditorBlock, UpdateEditorBlock, } from '@toeverything/datasource/db-service'; -import type { PatchNode } from '@toeverything/components/ui'; +import { services } from '@toeverything/datasource/db-service'; -import { AsyncBlock } from './block'; -import type { WorkspaceAndBlockId } from './block'; -import type { BaseView } from './views/base-view'; -import { SelectionManager } from './selection'; -import { Hooks, PluginManager } from './plugin'; -import { EditorCommands } from './commands'; -import { - Virgo, - HooksRunner, - PluginHooks, - PluginCreator, - StorageManager, - VirgoSelection, - PluginManagerInterface, -} from './types'; -import { KeyboardManager } from './keyboard'; -import { MouseManager } from './mouse'; -import { ScrollManager } from './scroll'; -import assert from 'assert'; -import { domToRect, last, Point, sleep } from '@toeverything/utils'; import { Commands } from '@toeverything/datasource/commands'; +import { domToRect, last, Point, sleep } from '@toeverything/utils'; +import assert from 'assert'; +import type { WorkspaceAndBlockId } from './block'; +import { AsyncBlock } from './block'; +import { BlockHelper } from './block/block-helper'; import { BrowserClipboard } from './clipboard/browser-clipboard'; import { ClipboardPopulator } from './clipboard/clipboard-populator'; -import { BlockHelper } from './block/block-helper'; -import { DragDropManager } from './drag-drop'; +import { EditorCommands } from './commands'; import { EditorConfig } from './config'; +import { DragDropManager } from './drag-drop'; +import { KeyboardManager } from './keyboard'; +import { MouseManager } from './mouse'; +import { Hooks, PluginManager } from './plugin'; +import { ScrollManager } from './scroll'; +import { SelectionManager } from './selection'; +import { + HooksRunner, + PluginCreator, + PluginHooks, + PluginManagerInterface, + StorageManager, + Virgo, + VirgoSelection, +} from './types'; +import type { BaseView } from './views/base-view'; export interface EditorCtorProps { workspace: string; @@ -148,18 +148,41 @@ export class Editor implements Virgo { public get container() { return this.ui_container; } - // preference to use withSuspend + + /** + * Use it discreetly. + * Preference to use {@link withBatch} + */ public suspend(flag: boolean) { services.api.editorBlock.suspend(this.workspace, flag); } - public async withSuspend any>( + // TODO support suspend recursion + private _isSuspend = false; + public withBatch Promise>(fn: T): T { + return (async (...args) => { + if (this._isSuspend) { + console.warn( + 'The editor currently has suspend! Please do not call batch method repeatedly!' + ); + } + this._isSuspend = true; + services.api.editorBlock.suspend(this.workspace, true); + const result = await fn(...args); + services.api.editorBlock.suspend(this.workspace, false); + this._isSuspend = false; + return result; + }) as T; + } + + /** + * Use it discreetly. + * Preference to use {@link withBatch} + */ + public async batch any>( fn: T ): Promise>> { - services.api.editorBlock.suspend(this.workspace, true); - const result = await fn(); - services.api.editorBlock.suspend(this.workspace, false); - return result; + return this.withBatch(fn)(); } public setReactRenderRoot(props: { From cc3dc1716d0c6bb467219ef9c8356678846c38ec Mon Sep 17 00:00:00 2001 From: lawvs <18554747+lawvs@users.noreply.github.com> Date: Mon, 15 Aug 2022 17:07:18 +0800 Subject: [PATCH 3/3] fix: text enter with root id --- .../src/blocks/text/TextView.tsx | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/libs/components/editor-blocks/src/blocks/text/TextView.tsx b/libs/components/editor-blocks/src/blocks/text/TextView.tsx index 04411b386b..79912ebd02 100644 --- a/libs/components/editor-blocks/src/blocks/text/TextView.tsx +++ b/libs/components/editor-blocks/src/blocks/text/TextView.tsx @@ -67,19 +67,31 @@ export const TextView = ({ const { contentBeforeSelection, contentAfterSelection } = splitContents; const before = [...contentBeforeSelection.content]; const after = [...contentAfterSelection.content]; - const _nextBlockChildren = await block.children(); - const _nextBlock = await editor.createBlock('text'); - await _nextBlock.setProperty('text', { + const nextBlockChildren = await block.children(); + const nextBlock = await editor.createBlock('text'); + if (!nextBlock) { + throw new Error('Failed to create text block'); + } + await nextBlock.setProperty('text', { value: after as CustomText[], }); - _nextBlock.append(..._nextBlockChildren); - block.removeChildren(); await block.setProperty('text', { value: before as CustomText[], }); - await block.after(_nextBlock); - editor.selectionManager.activeNodeByNodeId(_nextBlock.id); + if (editor.getRootBlockId() === block.id) { + // If the block is the root block, + // new block can not append as next sibling, + // all new blocks should be append as children. + await block.insert(0, [nextBlock]); + editor.selectionManager.activeNodeByNodeId(nextBlock.id); + return true; + } + await nextBlock.append(...nextBlockChildren); + await block.removeChildren(); + await block.after(nextBlock); + + editor.selectionManager.activeNodeByNodeId(nextBlock.id); return true; };