diff --git a/src/rich-text/commands/index.ts b/src/rich-text/commands/index.ts index 0c66224b..d0597549 100644 --- a/src/rich-text/commands/index.ts +++ b/src/rich-text/commands/index.ts @@ -532,7 +532,7 @@ export function exitInclusiveMarkCommand( dispatch: (tr: Transaction) => void ) { const $cursor = (state.selection).$cursor; - const marks = state.storedMarks || $cursor.marks(); + const marks = state.storedMarks || $cursor?.marks(); if (!marks?.length) { return false; @@ -546,7 +546,7 @@ export function exitInclusiveMarkCommand( } // check if we're at the end of the exitable mark - const nextNode = $cursor.nodeAfter; + const nextNode = $cursor?.nodeAfter; let endExitables: Mark[]; let tr = state.tr; diff --git a/src/rich-text/key-bindings.ts b/src/rich-text/key-bindings.ts index eda9c81a..962b4f41 100644 --- a/src/rich-text/key-bindings.ts +++ b/src/rich-text/key-bindings.ts @@ -2,7 +2,6 @@ import { toggleMark, wrapIn, setBlockType, - exitCode, baseKeymap, } from "prosemirror-commands"; import { redo, undo } from "prosemirror-history"; @@ -26,12 +25,12 @@ import { moveToPreviousCellCommand, moveSelectionAfterTableCommand, insertRichTextTableCommand, - exitInclusiveMarkCommand, indentCodeBlockLinesCommand, unindentCodeBlockLinesCommand, toggleHeadingLevel, toggleTagLinkCommand, toggleList, + exitInclusiveMarkCommand, } from "./commands"; export function allKeymaps( @@ -86,9 +85,8 @@ export function allKeymaps( "Mod-,": toggleMark(schema.marks.sub), "Mod-.": toggleMark(schema.marks.sup), "Mod-'": toggleMark(schema.marks.kbd), - // users expect to be able to leave certain blocks/marks using the arrow keys + // exit inline code block using the right arrow key "ArrowRight": exitInclusiveMarkCommand, - "ArrowDown": exitCode, }); const keymaps = [ diff --git a/test/rich-text/commands/index.test.ts b/test/rich-text/commands/index.test.ts index e22c3177..bf31c10b 100644 --- a/test/rich-text/commands/index.test.ts +++ b/test/rich-text/commands/index.test.ts @@ -1,4 +1,4 @@ -import { EditorState, Transaction } from "prosemirror-state"; +import { EditorState, TextSelection, Transaction } from "prosemirror-state"; import { exitInclusiveMarkCommand, insertRichTextHorizontalRuleCommand, @@ -733,7 +733,7 @@ describe("commands", () => { ); }); - describe("exitMarkCommand", () => { + describe("exitInclusiveMarkCommand", () => { it("all exitable marks should also be inclusive: true", () => { Object.keys(testRichTextSchema.marks).forEach((markName) => { const mark = testRichTextSchema.marks[markName]; @@ -783,6 +783,23 @@ describe("commands", () => { expect(exitInclusiveMarkCommand(state, null)).toBe(true); } ); + + it("should handle the case when $cursor is null", () => { + // suppress console.warn + const consoleWarnSpy = jest + .spyOn(console, "warn") + .mockImplementation(() => {}); + + let state = createState("this is my state", []); + state = state.apply( + state.tr.setSelection(TextSelection.create(state.doc, 0, null)) + ); + expect((state.selection).$cursor).toBeNull(); + expect(() => exitInclusiveMarkCommand(state, null)).not.toThrow(); + + // restore console.warn + consoleWarnSpy.mockRestore(); + }); }); describe("indentCodeBlockLinesCommand", () => {