diff --git a/plugins/text-editor-resources/src/components/extension/listkeymap.ts b/plugins/text-editor-resources/src/components/extension/listkeymap.ts new file mode 100644 index 0000000000..eb1c9e842e --- /dev/null +++ b/plugins/text-editor-resources/src/components/extension/listkeymap.ts @@ -0,0 +1,88 @@ +// +// Copyright © 2024 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { type Editor } from '@tiptap/core' +import ListKeymap, { type ListKeymapOptions, listHelpers } from '@tiptap/extension-list-keymap' + +/** + * Workaround for the original ListKeymap extension issue that + * https://github.com/ueberdosis/tiptap/issues/4368 + */ +export const ListKeymapExtension = ListKeymap.extend({ + addKeyboardShortcuts () { + const handleBackspace = (editor: Editor): boolean => { + let handled = false + + if (!editor.state.selection.empty) { + return false + } + + this.options.listTypes.forEach(({ itemName, wrapperNames }) => { + if (editor.state.schema.nodes[itemName] === undefined) { + return + } + if (listHelpers.handleBackspace(editor, itemName, wrapperNames)) { + handled = true + } + }) + + return handled + } + + const handleDelete = (editor: Editor): boolean => { + let handled = false + + if (!editor.state.selection.empty) { + return false + } + + this.options.listTypes.forEach(({ itemName }) => { + if (editor.state.schema.nodes[itemName] === undefined) { + return + } + if (listHelpers.handleDelete(editor, itemName)) { + handled = true + } + }) + + return handled + } + + const handleBackspaceSafe = (editor: Editor): boolean => { + try { + return handleBackspace(editor) + } catch (e) { + console.log(e) + return false + } + } + + const handleDeleteSafe = (editor: Editor): boolean => { + try { + return handleDelete(editor) + } catch (e) { + console.log(e) + return false + } + } + + return { + Backspace: ({ editor }) => handleBackspaceSafe(editor), + 'Mod-Backspace': ({ editor }) => handleBackspaceSafe(editor), + Delete: ({ editor }) => handleDeleteSafe(editor), + 'Mod-Delete': ({ editor }) => handleDeleteSafe(editor) + } + } +}) diff --git a/plugins/text-editor-resources/src/kits/editor-kit.ts b/plugins/text-editor-resources/src/kits/editor-kit.ts index 3c986bd86f..f16deb5bf7 100644 --- a/plugins/text-editor-resources/src/kits/editor-kit.ts +++ b/plugins/text-editor-resources/src/kits/editor-kit.ts @@ -19,7 +19,6 @@ import { CodeExtension, codeOptions } from '@hcengineering/text' import textEditor, { type ActionContext, type ExtensionCreator, type TextEditorMode } from '@hcengineering/text-editor' import { type AnyExtension, type Editor, Extension } from '@tiptap/core' import { type Level } from '@tiptap/extension-heading' -import ListKeymap from '@tiptap/extension-list-keymap' import TableHeader from '@tiptap/extension-table-header' import 'prosemirror-codemark/dist/codemark.css' @@ -30,6 +29,7 @@ import { FileExtension, type FileOptions } from '../components/extension/fileExt import { HardBreakExtension } from '../components/extension/hardBreak' import { ImageExtension, type ImageOptions } from '../components/extension/imageExt' import { InlineToolbarExtension } from '../components/extension/inlineToolbar' +import { ListKeymapExtension } from '../components/extension/listkeymap' import { NodeUuidExtension } from '../components/extension/nodeUuid' import { ParagraphExtension } from '../components/extension/paragraph' import { SubmitExtension, type SubmitOptions } from '../components/extension/submit' @@ -195,7 +195,7 @@ async function buildEditorKit (): Promise> { staticKitExtensions.push([ 500, - ListKeymap.configure({ + ListKeymapExtension.configure({ listTypes: [ { itemName: 'listItem',