Skip to content

Commit

Permalink
pref: Optimize list keymap
Browse files Browse the repository at this point in the history
  • Loading branch information
AirboZH committed Dec 22, 2023
1 parent cdd5cb4 commit 26a10ca
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 5 deletions.
1 change: 1 addition & 0 deletions console/packages/editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"@tiptap/extension-italic": "^2.1.10",
"@tiptap/extension-link": "^2.1.10",
"@tiptap/extension-list-item": "^2.1.10",
"@tiptap/extension-list-keymap": "^2.1.10",
"@tiptap/extension-ordered-list": "^2.1.10",
"@tiptap/extension-paragraph": "^2.1.10",
"@tiptap/extension-placeholder": "^2.1.10",
Expand Down
3 changes: 2 additions & 1 deletion console/packages/editor/src/extensions/bullet-list/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Editor, Range } from "@/tiptap/vue-3";
import TiptapBulletList from "@tiptap/extension-bullet-list";
import type { BulletListOptions } from "@tiptap/extension-bullet-list";
import ExtensionListItem from "@tiptap/extension-list-item";
import ExtensionListKeymap from "@/extensions/list-keymap";
import ToolbarItem from "@/components/toolbar/ToolbarItem.vue";
import MdiFormatListBulleted from "~icons/mdi/format-list-bulleted";
import { markRaw } from "vue";
Expand Down Expand Up @@ -57,7 +58,7 @@ const BulletList = TiptapBulletList.extend<
};
},
addExtensions() {
return [ExtensionListItem];
return [ExtensionListItem, ExtensionListKeymap];
},
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { AllSelection, EditorState, TextSelection } from "@tiptap/pm/state";

export function isAllSelection(value: unknown): value is AllSelection {
return value instanceof AllSelection;
}

export function isWholeDocSelected(state: EditorState) {
const selection = state.selection;
const selectionAtStart = TextSelection.atStart(state.doc);
const selectionAtEnd = TextSelection.atEnd(state.doc);

const selectionHasSameParent =
selectionAtStart.$from.sameParent(selection.$from) &&
selectionAtEnd.$from.sameParent(selection.$to);

const isAllTextSelection =
selectionHasSameParent &&
selectionAtStart.$from.pos === selection.$from.pos &&
selectionAtEnd.$from.pos === selection.$to.pos;

// allSelection covers cases where selection starts with a nodeSelection
// we need to check for text selection that covers the whole document as well
// ref: https://prosemirror.net/docs/ref/#state.AllSelection
return isAllSelection(state.selection) || isAllTextSelection;
}
91 changes: 91 additions & 0 deletions console/packages/editor/src/extensions/list-keymap/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import {
listHelpers,
ListKeymap,
type ListKeymapOptions,
} from "@tiptap/extension-list-keymap";
import { isWholeDocSelected } from "./helpers/isAllSelection";

/**
* Optimize the listKeymap extension until the issue with @tiptap/extension-list-keymap is resolved.
* https://github.com/ueberdosis/tiptap/issues/4395
*/
const ExtensionListKeymap = ListKeymap.extend<ListKeymapOptions>({
addKeyboardShortcuts() {
return {
Delete: ({ editor }) => {
let handled = false;
if (isWholeDocSelected(editor.state)) {
return false;
}

this.options.listTypes.forEach(({ itemName }) => {
if (editor.state.schema.nodes[itemName] === undefined) {
return;
}

if (listHelpers.handleDelete(editor, itemName)) {
handled = true;
}
});

return handled;
},
"Mod-Delete": ({ editor }) => {
let handled = false;
if (isWholeDocSelected(editor.state)) {
return false;
}

this.options.listTypes.forEach(({ itemName }) => {
if (editor.state.schema.nodes[itemName] === undefined) {
return;
}

if (listHelpers.handleDelete(editor, itemName)) {
handled = true;
}
});

return handled;
},
Backspace: ({ editor }) => {
let handled = false;
if (isWholeDocSelected(editor.state)) {
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;
},
"Mod-Backspace": ({ editor }) => {
let handled = false;
if (isWholeDocSelected(editor.state)) {
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;
},
};
},
});

export default ExtensionListKeymap;
3 changes: 2 additions & 1 deletion console/packages/editor/src/extensions/ordered-list/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Editor, Range } from "@/tiptap/vue-3";
import TiptapOrderedList from "@tiptap/extension-ordered-list";
import type { OrderedListOptions } from "@tiptap/extension-ordered-list";
import ExtensionListItem from "@tiptap/extension-list-item";
import ExtensionListKeymap from "@/extensions/list-keymap";
import ToolbarItem from "@/components/toolbar/ToolbarItem.vue";
import MdiFormatListNumbered from "~icons/mdi/format-list-numbered";
import { markRaw } from "vue";
Expand Down Expand Up @@ -58,7 +59,7 @@ const OrderedList = TiptapOrderedList.extend<
};
},
addExtensions() {
return [ExtensionListItem];
return [ExtensionListItem, ExtensionListKeymap];
},
});

Expand Down
17 changes: 14 additions & 3 deletions console/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 26a10ca

Please sign in to comment.