import { setBlockType } from "prosemirror-commands"; import { EditorState } from "prosemirror-state"; import { UxCommand } from "../constants"; import { closest } from "../pquery"; import { HeadingAttrs, schema } from "../schema"; import { Command, Dispatch } from "../types"; /** * Defines the behaviour for pressing 'backspace' at the start of a heading. * * It attempts to convert the heading to a paragraph. */ export function escapeFromStart(state: EditorState, dispatch?: Dispatch) { const selection = state.selection; // Escaping a heading only works on an empty selection. if (!selection.empty) { return false; } const $pos = selection.$from; // Verify we're at the start of the heading. if ($pos.start($pos.depth) !== $pos.pos) { return false; } const parent = $pos.node($pos.depth); // Ensure we're actually in a heading. if (parent.type !== schema.nodes.h) { return false; } // Ensure we can actually replace it with a paragraph (taken from // textblockTypeInputRule, and probably a little overkill). if (!$pos.node(-1).canReplaceWith($pos.index(-1), $pos.indexAfter(-1), schema.nodes.h)) { return false; } if (dispatch !== undefined) dispatch(state.tr.setNodeMarkup($pos.before(), schema.nodes.p)); return true; } const toggleHeading = (level: number): Command => (state, dispatch) => { const { $anchor } = state.selection; let match; if (closest($anchor, node => node.type === schema.nodes.p) !== null) { return setBlockType(schema.nodes.h, { l: level } as HeadingAttrs)(state, dispatch); } else if ((match = closest($anchor, node => node.type === schema.nodes.h)) !== null) { if ((match.node.attrs as HeadingAttrs).l === level) { return setBlockType(schema.nodes.p)(state, dispatch); } else { return setBlockType(schema.nodes.h, { l: level } as HeadingAttrs)(state, dispatch); } } return false; }; export const toggleHeading1 = toggleHeading(1); export const toggleHeading2 = toggleHeading(2); export const ux = { [UxCommand.DeleteBackward]: escapeFromStart, [UxCommand.ToggleHeading1]: toggleHeading1, [UxCommand.ToggleHeading2]: toggleHeading2 };