From fae5bf7ce93c5cf3f13a4c10b6f083364af80ac2 Mon Sep 17 00:00:00 2001 From: Takagi <1103069291@qq.com> Date: Mon, 29 Jul 2024 20:41:54 +0800 Subject: [PATCH] fix: list items require multiple backspace presses to delete (#6408) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### What type of PR is this? /kind bug /area editor /milestone 2.18.x #### What this PR does / why we need it: 目前当编辑器中列表内容为空时,需要按退格键多次才能删除掉此列表内容。 本 PR 在执行单行删除逻辑之前,会检查列表是否处于活动状态,如果是则不再执行单行删除的逻辑。列表会执行 ListKeyMap 相关快捷键。 #### How to test it? 1. 在默认富文本键入一个列表。 2. 使用退格键删除这个列表。 3. 查看是否可以一次就删除。 #### Which issue(s) this PR fixes: Fixes #6389 #### Does this PR introduce a user-facing change? ```release-note 修复默认编辑器中列表项需要按多次退格键才可以删除的问题 ``` --- .../editor/src/extensions/indent/index.ts | 9 +--- .../editor/src/extensions/paragraph/index.ts | 14 ++++--- ui/packages/editor/src/utils/isListActive.ts | 42 +++++++++++++++++++ 3 files changed, 51 insertions(+), 14 deletions(-) create mode 100644 ui/packages/editor/src/utils/isListActive.ts diff --git a/ui/packages/editor/src/extensions/indent/index.ts b/ui/packages/editor/src/extensions/indent/index.ts index a8eddedf3..d49849089 100644 --- a/ui/packages/editor/src/extensions/indent/index.ts +++ b/ui/packages/editor/src/extensions/indent/index.ts @@ -7,6 +7,7 @@ import { type KeyboardShortcutCommand, } from "@/tiptap"; import { TextSelection, Transaction } from "@/tiptap/pm"; +import { isListActive } from "@/utils/isListActive"; declare module "@/tiptap" { interface Commands { @@ -222,14 +223,6 @@ const isTextIndent = (tr: Transaction, currNodePos: number) => { return false; }; -const isListActive = (editor: CoreEditor) => { - return ( - editor.isActive("bulletList") || - editor.isActive("orderedList") || - editor.isActive("taskList") - ); -}; - const isFilterActive = (editor: CoreEditor) => { return editor.isActive("table") || editor.isActive("columns"); }; diff --git a/ui/packages/editor/src/extensions/paragraph/index.ts b/ui/packages/editor/src/extensions/paragraph/index.ts index 9feb863d1..fe03c34dc 100644 --- a/ui/packages/editor/src/extensions/paragraph/index.ts +++ b/ui/packages/editor/src/extensions/paragraph/index.ts @@ -2,6 +2,7 @@ import ToolbarItem from "@/components/toolbar/ToolbarItem.vue"; import ToolbarSubItem from "@/components/toolbar/ToolbarSubItem.vue"; import { i18n } from "@/locales"; import { + CoreEditor, EditorState, ResolvedPos, TextSelection, @@ -11,6 +12,7 @@ import { } from "@/tiptap"; import type { ExtensionOptions, ToolbarItem as TypeToolbarItem } from "@/types"; import { deleteNodeByPos } from "@/utils"; +import { isListActive } from "@/utils/isListActive"; import { isEmpty } from "@/utils/isNodeEmpty"; import type { ParagraphOptions } from "@tiptap/extension-paragraph"; import TiptapParagraph from "@tiptap/extension-paragraph"; @@ -97,15 +99,15 @@ const Paragraph = TiptapParagraph.extend({ addKeyboardShortcuts() { return { - Backspace: ({ editor }) => { + Backspace: ({ editor }: { editor: CoreEditor }) => { const { state, view } = editor; const { selection } = state; - if ( - !isActive(state, Paragraph.name) || - !(selection instanceof TextSelection) || - !selection.empty - ) { + if (isListActive(editor) || !isActive(state, Paragraph.name)) { + return false; + } + + if (!(selection instanceof TextSelection) || !selection.empty) { return false; } diff --git a/ui/packages/editor/src/utils/isListActive.ts b/ui/packages/editor/src/utils/isListActive.ts new file mode 100644 index 000000000..0d2880b2f --- /dev/null +++ b/ui/packages/editor/src/utils/isListActive.ts @@ -0,0 +1,42 @@ +import { + callOrReturn, + CoreEditor, + getExtensionField, + isActive, + type NodeConfig, +} from "@/tiptap"; + +/** + * Check if a list is active + * + * @param state - The state of the editor + * @returns Whether a list is active + * @example + * ```ts + * const isActive = isListActive(editor.state); + * ``` + **/ +export const isListActive = (editor: CoreEditor) => { + const extensions = editor.extensionManager.extensions; + const listExtensions = extensions.filter((extension) => { + const context = { + name: extension.name, + options: extension.options, + storage: extension.storage, + }; + + const group = callOrReturn( + getExtensionField(extension, "group", context) + ); + + if (typeof group !== "string") { + return false; + } + + return group.split(" ").includes("list"); + }); + + return listExtensions.some((extension) => { + return isActive(editor.state, extension.name); + }); +};