fix: Improve backspace handling (#2284), fix #2281

* improve backspace handling

* revert codeblock changes

* revert codeblock changes

* fix tests

Co-authored-by: Philipp Kühn <philippkuehn@MacBook-Pro-von-Philipp.local>
This commit is contained in:
Philipp Kühn 2021-12-16 13:55:32 +01:00 committed by GitHub
parent 10248f2763
commit 8ed485ba53
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,3 +1,6 @@
import { Plugin, PluginKey, Selection } from 'prosemirror-state'
import { createChainableState } from '../helpers/createChainableState'
import { CommandManager } from '../CommandManager'
import { Extension } from '../Extension'
export const Keymap = Extension.create({
@ -6,6 +9,24 @@ export const Keymap = Extension.create({
addKeyboardShortcuts() {
const handleBackspace = () => this.editor.commands.first(({ commands }) => [
() => commands.undoInputRule(),
// maybe convert first text block node to default node
() => commands.command(({ tr }) => {
const { selection, doc } = tr
const { empty, $anchor } = selection
const { pos, parent } = $anchor
const isAtStart = Selection.atStart(doc).from === pos
if (
!empty
|| !isAtStart
|| !parent.type.isTextblock
|| parent.textContent.length
) {
return false
}
return commands.clearNodes()
}),
() => commands.deleteSelection(),
() => commands.joinBackward(),
() => commands.selectNodeBackward(),
@ -33,4 +54,53 @@ export const Keymap = Extension.create({
'Mod-a': () => this.editor.commands.selectAll(),
}
},
addProseMirrorPlugins() {
return [
// With this plugin we check if the whole document was selected and deleted.
// In this case we will additionally call `clearNodes()` to convert e.g. a heading
// to a paragraph if necessary.
// This is an alternative to ProseMirror's `AllSelection`, which doesnt work well
// with many other commands.
new Plugin({
key: new PluginKey('clearDocument'),
appendTransaction: (transactions, oldState, newState) => {
const docChanges = transactions.some(transaction => transaction.docChanged)
&& !oldState.doc.eq(newState.doc)
if (!docChanges) {
return
}
const { empty, from, to } = oldState.selection
const allFrom = Selection.atStart(oldState.doc).from
const allEnd = Selection.atEnd(oldState.doc).to
const allWasSelected = from === allFrom && to === allEnd
const isEmpty = newState.doc.textBetween(0, newState.doc.content.size, ' ', ' ').length === 0
if (empty || !allWasSelected || !isEmpty) {
return
}
const tr = newState.tr
const state = createChainableState({
state: newState,
transaction: tr,
})
const { commands } = new CommandManager({
editor: this.editor,
state,
})
commands.clearNodes()
if (!tr.steps.length) {
return
}
return tr
},
}),
]
},
})