diff --git a/src/extensions/markdown/Breaks/index.ts b/src/extensions/markdown/Breaks/index.ts index 08d4514e..252cd668 100644 --- a/src/extensions/markdown/Breaks/index.ts +++ b/src/extensions/markdown/Breaks/index.ts @@ -1,9 +1,12 @@ -import type {NodeType} from 'prosemirror-model'; +import type {Node, NodeType} from 'prosemirror-model'; +import {TextSelection} from 'prosemirror-state'; import {chainCommands, exitCode} from 'prosemirror-commands'; import {logger} from '../../../logger'; import type {ExtensionAuto, Keymap} from '../../../core'; import {isMac} from '../../../utils/platform'; +import {isTextSelection} from '../../../utils/selection'; import {BreaksSpecs, BreaksSpecsOptions, hbType, sbType} from './BreaksSpecs'; +import {pType} from '../../base/BaseSchema/BaseSchemaSpecs'; export {BreaksSpecs, BreakNodeName, hbType, sbType} from './BreaksSpecs'; @@ -45,6 +48,38 @@ export const Breaks: ExtensionAuto = (builder, opts) => { const addBr = (br: NodeType) => chainCommands(exitCode, (state, dispatch) => { + const {selection: sel, schema} = state; + if ( + !isTextSelection(sel) || + !sel.empty || + // breaks can only be in the paragraph + sel.$cursor?.parent.type !== pType(schema) + ) + return false; + + if (isBreakNode(sel.$cursor.nodeBefore)) { + if (dispatch) { + const { + $cursor, + $cursor: {pos}, + } = sel; + const from = isBreakNode($cursor.nodeAfter) ? pos + 1 : pos; + const posEnd = $cursor.end(); + const posAfter = $cursor.after(); + + const contentAfter = state.doc.slice(from, posEnd, false).content; + + let tr = state.tr.insert(posAfter, pType(schema).create(null, contentAfter)); + tr = tr + .setSelection(TextSelection.create(tr.doc, posAfter + 1)) + .scrollIntoView() + .delete(pos, posEnd) // remove content after current pos (it's moved to next para) + .delete(pos - 1, pos); // remove break before current pos ($cursor.nodeBefore) + dispatch(tr); + } + return true; + } + dispatch?.(state.tr.replaceSelectionWith(br.create()).scrollIntoView()); return true; }); @@ -59,3 +94,7 @@ declare global { } } } + +function isBreakNode(node?: Node | null | undefined): boolean { + return Boolean(node?.type.spec.isBreak); +}