restructure commands

This commit is contained in:
Philipp Kühn
2020-11-18 16:43:27 +01:00
parent 03f009d5f0
commit 3cd6c55279
37 changed files with 214 additions and 231 deletions

View File

@@ -70,12 +70,12 @@ editor
Both calls would return `true` if its possible to apply the commands, and `false` in case its not. Both calls would return `true` if its possible to apply the commands, and `false` in case its not.
### Try commands ### Try commands
If you want to run a list of commands, but want only the first successful command to be applied, you can do this with the `.try()` method. This method runs one command after the other and stops at the first which returns `true`. If you want to run a list of commands, but want only the first successful command to be applied, you can do this with the `.first()` method. This method runs one command after the other and stops at the first which returns `true`.
For example, the backspace key tries to undo an input rule first. If that was successful, it stops there. If no input rule has been applied and thus cant be reverted, it runs the next command and deletes the selection, if there is one. Here is the simplified example: For example, the backspace key tries to undo an input rule first. If that was successful, it stops there. If no input rule has been applied and thus cant be reverted, it runs the next command and deletes the selection, if there is one. Here is the simplified example:
```js ```js
editor.try(({ commands }) => [ editor.first(({ commands }) => [
() => commands.undoInputRule(), () => commands.undoInputRule(),
() => commands.deleteSelection(), () => commands.deleteSelection(),
// … // …
@@ -85,7 +85,7 @@ editor.try(({ commands }) => [
Inside of commands you can do the same thing like that: Inside of commands you can do the same thing like that:
```js ```js
commands.try([ commands.first([
() => commands.undoInputRule(), () => commands.undoInputRule(),
() => commands.deleteSelection(), () => commands.deleteSelection(),
// … // …

View File

@@ -3,7 +3,10 @@ import { Command } from '../types'
import getMarkType from '../utils/getMarkType' import getMarkType from '../utils/getMarkType'
import getMarkAttributes from '../utils/getMarkAttributes' import getMarkAttributes from '../utils/getMarkAttributes'
export default (typeOrName: string | MarkType, attributes?: {}): Command => ({ tr, state, dispatch }) => { /**
* Add a mark with new attributes.
*/
export const addMark = (typeOrName: string | MarkType, attributes?: {}): Command => ({ tr, state, dispatch }) => {
const { selection } = tr const { selection } = tr
const { from, to, empty } = selection const { from, to, empty } = selection
const type = getMarkType(typeOrName, state.schema) const type = getMarkType(typeOrName, state.schema)

View File

@@ -1,6 +1,9 @@
import { Command } from '../types' import { Command } from '../types'
export default (): Command => ({ view }) => { /**
* Removes focus from the editor.
*/
export const blur = (): Command => ({ view }) => {
const element = view.dom as HTMLElement const element = view.dom as HTMLElement
element.blur() element.blur()

View File

@@ -1,5 +1,8 @@
import { Command } from '../types' import { Command } from '../types'
export default (emitUpdate: Boolean = false): Command => ({ commands }) => { /**
* Clear the whole document.
*/
export const clearContent = (emitUpdate: Boolean = false): Command => ({ commands }) => {
return commands.setContent('', emitUpdate) return commands.setContent('', emitUpdate)
} }

View File

@@ -1,7 +1,10 @@
import { liftTarget } from 'prosemirror-transform' import { liftTarget } from 'prosemirror-transform'
import { Command } from '../types' import { Command } from '../types'
export default (): Command => ({ state, tr, dispatch }) => { /**
* Normalize nodes to a simple paragraph.
*/
export const clearNodes = (): Command => ({ state, tr, dispatch }) => {
const { selection } = tr const { selection } = tr
const { from, to } = selection const { from, to } = selection

View File

@@ -1,5 +1,8 @@
import { Command } from '../types' import { Command } from '../types'
export default (fn: (props: Parameters<Command>[0]) => boolean): Command => props => { /**
* Define a command inline.
*/
export const command = (fn: (props: Parameters<Command>[0]) => boolean): Command => props => {
return fn(props) return fn(props)
} }

View File

@@ -1,6 +1,9 @@
import { deleteSelection } from 'prosemirror-commands' import { deleteSelection as originalDeleteSelection } from 'prosemirror-commands'
import { Command } from '../types' import { Command } from '../types'
export default (): Command => ({ state, dispatch }) => { /**
return deleteSelection(state, dispatch) * Delete the selection, if there is one.
*/
export const deleteSelection = (): Command => ({ state, dispatch }) => {
return originalDeleteSelection(state, dispatch)
} }

View File

@@ -4,7 +4,10 @@ import { Command } from '../types'
import getMarkType from '../utils/getMarkType' import getMarkType from '../utils/getMarkType'
import getMarkRange from '../utils/getMarkRange' import getMarkRange from '../utils/getMarkRange'
export default (typeOrName: string | MarkType): Command => ({ tr, state, dispatch }) => { /**
* Extends the text selection to the current mark.
*/
export const extendMarkRange = (typeOrName: string | MarkType): Command => ({ tr, state, dispatch }) => {
const type = getMarkType(typeOrName, state.schema) const type = getMarkType(typeOrName, state.schema)
const { doc, selection } = tr const { doc, selection } = tr
const { $from, empty } = selection const { $from, empty } = selection

View File

@@ -1,6 +1,9 @@
import { Command } from '../types' import { Command } from '../types'
export default (commands: Command[] | ((props: Parameters<Command>[0]) => Command[])): Command => props => { /**
* Runs one command after the other and stops at the first which returns true.
*/
export const first = (commands: Command[] | ((props: Parameters<Command>[0]) => Command[])): Command => props => {
const items = typeof commands === 'function' const items = typeof commands === 'function'
? commands(props) ? commands(props)
: commands : commands

View File

@@ -35,7 +35,10 @@ function resolveSelection(editor: Editor, position: FocusPosition = null): Resol
} }
} }
export default (position: FocusPosition = null): Command => ({ /**
* Focus the editor at the given position.
*/
export const focus = (position: FocusPosition = null): Command => ({
editor, editor,
view, view,
tr, tr,

View File

@@ -17,7 +17,10 @@ function selectionToInsertionEnd(tr: Transaction, startLen: number, bias: number
tr.setSelection(Selection.near(tr.doc.resolve(end as unknown as number), bias)) tr.setSelection(Selection.near(tr.doc.resolve(end as unknown as number), bias))
} }
export default (value: string): Command => ({ tr, state, dispatch }) => { /**
* Insert a string of HTML at the current position.
*/
export const insertHTML = (value: string): Command => ({ tr, state, dispatch }) => {
const { selection } = tr const { selection } = tr
const element = elementFromString(value) const element = elementFromString(value)
const slice = DOMParser.fromSchema(state.schema).parseSlice(element) const slice = DOMParser.fromSchema(state.schema).parseSlice(element)

View File

@@ -1,6 +1,9 @@
import { Command } from '../types' import { Command } from '../types'
export default (value: string): Command => ({ tr, dispatch }) => { /**
* Insert a string of text at the current position.
*/
export const insertText = (value: string): Command => ({ tr, dispatch }) => {
if (dispatch) { if (dispatch) {
tr.insertText(value) tr.insertText(value)
} }

View File

@@ -1,10 +1,13 @@
import { lift } from 'prosemirror-commands' import { lift as originalLift } from 'prosemirror-commands'
import { NodeType } from 'prosemirror-model' import { NodeType } from 'prosemirror-model'
import { Command } from '../types' import { Command } from '../types'
import nodeIsActive from '../utils/nodeIsActive' import nodeIsActive from '../utils/nodeIsActive'
import getNodeType from '../utils/getNodeType' import getNodeType from '../utils/getNodeType'
export default (typeOrName: string | NodeType, attributes = {}): Command => ({ state, dispatch }) => { /**
* Removes an existing wrap.
*/
export const lift = (typeOrName: string | NodeType, attributes = {}): Command => ({ state, dispatch }) => {
const type = getNodeType(typeOrName, state.schema) const type = getNodeType(typeOrName, state.schema)
const isActive = nodeIsActive(state, type, attributes) const isActive = nodeIsActive(state, type, attributes)
@@ -12,5 +15,5 @@ export default (typeOrName: string | NodeType, attributes = {}): Command => ({ s
return false return false
} }
return lift(state, dispatch) return originalLift(state, dispatch)
} }

View File

@@ -1,10 +1,13 @@
import { liftListItem } from 'prosemirror-schema-list' import { liftListItem as originalLiftListItem } from 'prosemirror-schema-list'
import { NodeType } from 'prosemirror-model' import { NodeType } from 'prosemirror-model'
import { Command } from '../types' import { Command } from '../types'
import getNodeType from '../utils/getNodeType' import getNodeType from '../utils/getNodeType'
export default (typeOrName: string | NodeType): Command => ({ state, dispatch }) => { /**
* Lift the list item into a wrapping list.
*/
export const liftListItem = (typeOrName: string | NodeType): Command => ({ state, dispatch }) => {
const type = getNodeType(typeOrName, state.schema) const type = getNodeType(typeOrName, state.schema)
return liftListItem(type)(state, dispatch) return originalLiftListItem(type)(state, dispatch)
} }

View File

@@ -3,7 +3,10 @@ import { Command } from '../types'
import getMarkType from '../utils/getMarkType' import getMarkType from '../utils/getMarkType'
import getMarkRange from '../utils/getMarkRange' import getMarkRange from '../utils/getMarkRange'
export default (typeOrName: string | MarkType): Command => ({ tr, state, dispatch }) => { /**
* Remove all marks in the current selection.
*/
export const removeMark = (typeOrName: string | MarkType): Command => ({ tr, state, dispatch }) => {
const { selection } = tr const { selection } = tr
const type = getMarkType(typeOrName, state.schema) const type = getMarkType(typeOrName, state.schema)
let { from, to } = selection let { from, to } = selection

View File

@@ -1,6 +1,9 @@
import { Command } from '../types' import { Command } from '../types'
export default (): Command => ({ tr, state, dispatch }) => { /**
* Remove all marks in the current selection.
*/
export const removeMarks = (): Command => ({ tr, state, dispatch }) => {
const { selection } = tr const { selection } = tr
const { from, to, empty } = selection const { from, to, empty } = selection

View File

@@ -1,18 +0,0 @@
import { NodeType } from 'prosemirror-model'
import getNodeType from '../utils/getNodeType'
import deleteProps from '../utils/deleteProps'
import { Command } from '../types'
export default (typeOrName: string | NodeType, attributes: string[]): Command => ({ tr, state, dispatch }) => {
const type = getNodeType(typeOrName, state.schema)
const { selection } = tr
const { from, to } = selection
state.doc.nodesBetween(from, to, (node, pos) => {
if (node.type === type && dispatch) {
tr.setNodeMarkup(pos, undefined, deleteProps(node.attrs, attributes))
}
})
return true
}

View File

@@ -3,7 +3,10 @@ import getNodeType from '../utils/getNodeType'
import deleteProps from '../utils/deleteProps' import deleteProps from '../utils/deleteProps'
import { Command } from '../types' import { Command } from '../types'
export default (typeOrName: string | NodeType, attributes: string | string[]): Command => ({ tr, state, dispatch }) => { /**
* Resets node attributes to the default value.
*/
export const resetNodeAttributes = (typeOrName: string | NodeType, attributes: string | string[]): Command => ({ tr, state, dispatch }) => {
const type = getNodeType(typeOrName, state.schema) const type = getNodeType(typeOrName, state.schema)
const { selection } = tr const { selection } = tr
const { from, to } = selection const { from, to } = selection

View File

@@ -1,6 +1,9 @@
import { Command } from '../types' import { Command } from '../types'
export default (): Command => ({ tr, dispatch }) => { /**
* Scroll the selection into view.
*/
export const scrollIntoView = (): Command => ({ tr, dispatch }) => {
if (dispatch) { if (dispatch) {
tr.scrollIntoView() tr.scrollIntoView()
} }

View File

@@ -1,6 +1,9 @@
import { selectAll } from 'prosemirror-commands' import { selectAll as originalSelectAll } from 'prosemirror-commands'
import { Command } from '../types' import { Command } from '../types'
export default (): Command => ({ state, dispatch }) => { /**
return selectAll(state, dispatch) * Select the whole document.
*/
export const selectAll = (): Command => ({ state, dispatch }) => {
return originalSelectAll(state, dispatch)
} }

View File

@@ -1,6 +1,9 @@
import { selectParentNode } from 'prosemirror-commands' import { selectParentNode as originalSelectParentNode } from 'prosemirror-commands'
import { Command } from '../types' import { Command } from '../types'
export default (): Command => ({ state, dispatch }) => { /**
return selectParentNode(state, dispatch) * Select the parent node.
*/
export const selectParentNode = (): Command => ({ state, dispatch }) => {
return originalSelectParentNode(state, dispatch)
} }

View File

@@ -1,10 +1,13 @@
import { NodeType } from 'prosemirror-model' import { NodeType } from 'prosemirror-model'
import { setBlockType } from 'prosemirror-commands' import { setBlockType as originalSetBlockType } from 'prosemirror-commands'
import { Command } from '../types' import { Command } from '../types'
import getNodeType from '../utils/getNodeType' import getNodeType from '../utils/getNodeType'
export default (typeOrName: string | NodeType, attrs = {}): Command => ({ state, dispatch }) => { /**
* Replace a given range with a node.
*/
export const setBlockType = (typeOrName: string | NodeType, attrs = {}): Command => ({ state, dispatch }) => {
const type = getNodeType(typeOrName, state.schema) const type = getNodeType(typeOrName, state.schema)
return setBlockType(type, attrs)(state, dispatch) return originalSetBlockType(type, attrs)(state, dispatch)
} }

View File

@@ -1,7 +1,10 @@
import { TextSelection } from 'prosemirror-state' import { TextSelection } from 'prosemirror-state'
import { Command } from '../types' import { Command } from '../types'
export default (content: string, emitUpdate: Boolean = false, parseOptions = {}): Command => ({ tr, editor, dispatch }) => { /**
* Replace the whole document with new content.
*/
export const setContent = (content: string, emitUpdate: Boolean = false, parseOptions = {}): Command => ({ tr, editor, dispatch }) => {
const { createDocument } = editor const { createDocument } = editor
const { doc } = tr const { doc } = tr
const document = createDocument(content, parseOptions) const document = createDocument(content, parseOptions)

View File

@@ -3,7 +3,10 @@ import { NodeType } from 'prosemirror-model'
import { Command } from '../types' import { Command } from '../types'
import getNodeType from '../utils/getNodeType' import getNodeType from '../utils/getNodeType'
export default (typeOrName: string | NodeType): Command => ({ state, dispatch }) => { /**
* Sink the list item down into an inner list.
*/
export const sinkListItem = (typeOrName: string | NodeType): Command => ({ state, dispatch }) => {
const type = getNodeType(typeOrName, state.schema) const type = getNodeType(typeOrName, state.schema)
return originalSinkListItem(type)(state, dispatch) return originalSinkListItem(type)(state, dispatch)

View File

@@ -28,7 +28,10 @@ function keepMarks(state: EditorState) {
} }
} }
export default (options: Partial<SplitBlockOptions> = {}): Command => ({ tr, state, dispatch }) => { /**
* Forks a new node from an existing node.
*/
export const splitBlock = (options: Partial<SplitBlockOptions> = {}): Command => ({ tr, state, dispatch }) => {
const defaultOptions: SplitBlockOptions = { const defaultOptions: SplitBlockOptions = {
withAttributes: false, withAttributes: false,
withMarks: true, withMarks: true,

View File

@@ -1,10 +1,13 @@
import { splitListItem } from 'prosemirror-schema-list' import { splitListItem as originalSplitListItem } from 'prosemirror-schema-list'
import { NodeType } from 'prosemirror-model' import { NodeType } from 'prosemirror-model'
import { Command } from '../types' import { Command } from '../types'
import getNodeType from '../utils/getNodeType' import getNodeType from '../utils/getNodeType'
export default (typeOrName: string | NodeType): Command => ({ state, dispatch }) => { /**
* Splits one list item into two list items.
*/
export const splitListItem = (typeOrName: string | NodeType): Command => ({ state, dispatch }) => {
const type = getNodeType(typeOrName, state.schema) const type = getNodeType(typeOrName, state.schema)
return splitListItem(type)(state, dispatch) return originalSplitListItem(type)(state, dispatch)
} }

View File

@@ -3,7 +3,10 @@ import { Command } from '../types'
import nodeIsActive from '../utils/nodeIsActive' import nodeIsActive from '../utils/nodeIsActive'
import getNodeType from '../utils/getNodeType' import getNodeType from '../utils/getNodeType'
export default (typeOrName: string | NodeType, toggleTypeOrName: string | NodeType, attrs = {}): Command => ({ state, commands }) => { /**
* Toggle a node with another node.
*/
export const toggleBlockType = (typeOrName: string | NodeType, toggleTypeOrName: string | NodeType, attrs = {}): Command => ({ state, commands }) => {
const type = getNodeType(typeOrName, state.schema) const type = getNodeType(typeOrName, state.schema)
const toggleType = getNodeType(toggleTypeOrName, state.schema) const toggleType = getNodeType(toggleTypeOrName, state.schema)
const isActive = nodeIsActive(state, type, attrs) const isActive = nodeIsActive(state, type, attrs)

View File

@@ -4,7 +4,10 @@ import { Command } from '../types'
import getNodeType from '../utils/getNodeType' import getNodeType from '../utils/getNodeType'
import isList from '../utils/isList' import isList from '../utils/isList'
export default (listTypeOrName: string | NodeType, itemTypeOrName: string | NodeType): Command => ({ /**
* Toggle between different list types.
*/
export const toggleList = (listTypeOrName: string | NodeType, itemTypeOrName: string | NodeType): Command => ({
editor, tr, state, dispatch, chain, commands, can, editor, tr, state, dispatch, chain, commands, can,
}) => { }) => {
const { extensions } = editor.options const { extensions } = editor.options

View File

@@ -1,10 +1,13 @@
import { toggleMark } from 'prosemirror-commands' import { toggleMark as originalToggleMark } from 'prosemirror-commands'
import { MarkType } from 'prosemirror-model' import { MarkType } from 'prosemirror-model'
import { Command } from '../types' import { Command } from '../types'
import getMarkType from '../utils/getMarkType' import getMarkType from '../utils/getMarkType'
import markIsActive from '../utils/markIsActive' import markIsActive from '../utils/markIsActive'
export default (typeOrName: string | MarkType, attributes?: {}): Command => ({ state, dispatch, commands }) => { /**
* Toggle a mark on and off.
*/
export const toggleMark = (typeOrName: string | MarkType, attributes?: {}): Command => ({ state, dispatch, commands }) => {
const type = getMarkType(typeOrName, state.schema) const type = getMarkType(typeOrName, state.schema)
const hasMarkWithDifferentAttributes = attributes const hasMarkWithDifferentAttributes = attributes
@@ -15,5 +18,5 @@ export default (typeOrName: string | MarkType, attributes?: {}): Command => ({ s
return commands.addMark(type, attributes) return commands.addMark(type, attributes)
} }
return toggleMark(type, attributes)(state, dispatch) return originalToggleMark(type, attributes)(state, dispatch)
} }

View File

@@ -4,7 +4,10 @@ import { Command } from '../types'
import nodeIsActive from '../utils/nodeIsActive' import nodeIsActive from '../utils/nodeIsActive'
import getNodeType from '../utils/getNodeType' import getNodeType from '../utils/getNodeType'
export default (typeOrName: string | NodeType, attributes = {}): Command => ({ state, dispatch }) => { /**
* Wraps nodes in another node, or removes an existing wrap.
*/
export const toggleWrap = (typeOrName: string | NodeType, attributes = {}): Command => ({ state, dispatch }) => {
const type = getNodeType(typeOrName, state.schema) const type = getNodeType(typeOrName, state.schema)
const isActive = nodeIsActive(state, type, attributes) const isActive = nodeIsActive(state, type, attributes)

View File

@@ -2,7 +2,10 @@ import { NodeType } from 'prosemirror-model'
import getNodeType from '../utils/getNodeType' import getNodeType from '../utils/getNodeType'
import { Command } from '../types' import { Command } from '../types'
export default (typeOrName: string | NodeType, attributes: {}): Command => ({ tr, state, dispatch }) => { /**
* Update attributes of a node.
*/
export const updateNodeAttributes = (typeOrName: string | NodeType, attributes: {}): Command => ({ tr, state, dispatch }) => {
const type = getNodeType(typeOrName, state.schema) const type = getNodeType(typeOrName, state.schema)
const { selection } = tr const { selection } = tr
const { from, to } = selection const { from, to } = selection

View File

@@ -1,10 +1,13 @@
import { wrapIn } from 'prosemirror-commands' import { wrapIn as originalWrapIn } from 'prosemirror-commands'
import { NodeType } from 'prosemirror-model' import { NodeType } from 'prosemirror-model'
import { Command } from '../types' import { Command } from '../types'
import nodeIsActive from '../utils/nodeIsActive' import nodeIsActive from '../utils/nodeIsActive'
import getNodeType from '../utils/getNodeType' import getNodeType from '../utils/getNodeType'
export default (typeOrName: string | NodeType, attributes = {}): Command => ({ state, dispatch }) => { /**
* Wraps nodes in another node.
*/
export const wrapIn = (typeOrName: string | NodeType, attributes = {}): Command => ({ state, dispatch }) => {
const type = getNodeType(typeOrName, state.schema) const type = getNodeType(typeOrName, state.schema)
const isActive = nodeIsActive(state, type, attributes) const isActive = nodeIsActive(state, type, attributes)
@@ -12,5 +15,5 @@ export default (typeOrName: string | NodeType, attributes = {}): Command => ({ s
return false return false
} }
return wrapIn(type, attributes)(state, dispatch) return originalWrapIn(type, attributes)(state, dispatch)
} }

View File

@@ -1,10 +1,13 @@
import { wrapInList } from 'prosemirror-schema-list' import { wrapInList as originalWrapInList } from 'prosemirror-schema-list'
import { NodeType } from 'prosemirror-model' import { NodeType } from 'prosemirror-model'
import { Command } from '../types' import { Command } from '../types'
import getNodeType from '../utils/getNodeType' import getNodeType from '../utils/getNodeType'
export default (typeOrName: string | NodeType, attrs?: {}): Command => ({ state, dispatch }) => { /**
* Wrap a node in a list.
*/
export const wrapInList = (typeOrName: string | NodeType, attrs?: {}): Command => ({ state, dispatch }) => {
const type = getNodeType(typeOrName, state.schema) const type = getNodeType(typeOrName, state.schema)
return wrapInList(type, attrs)(state, dispatch) return originalWrapInList(type, attrs)(state, dispatch)
} }

View File

@@ -1,163 +1,70 @@
import { Extension } from '../Extension' import { Extension } from '../Extension'
import addMark from '../commands/addMark' import * as addMark from '../commands/addMark'
import blur from '../commands/blur' import * as blur from '../commands/blur'
import clearContent from '../commands/clearContent' import * as clearContent from '../commands/clearContent'
import command from '../commands/command' import * as command from '../commands/command'
import clearNodes from '../commands/clearNodes' import * as clearNodes from '../commands/clearNodes'
import deleteSelection from '../commands/deleteSelection' import * as deleteSelection from '../commands/deleteSelection'
import extendMarkRange from '../commands/extendMarkRange' import * as extendMarkRange from '../commands/extendMarkRange'
import focus from '../commands/focus' import * as focus from '../commands/focus'
import insertHTML from '../commands/insertHTML' import * as insertHTML from '../commands/insertHTML'
import insertText from '../commands/insertText' import * as insertText from '../commands/insertText'
import lift from '../commands/lift' import * as lift from '../commands/lift'
import liftListItem from '../commands/liftListItem' import * as liftListItem from '../commands/liftListItem'
import removeMark from '../commands/removeMark' import * as removeMark from '../commands/removeMark'
import removeMarks from '../commands/removeMarks' import * as removeMarks from '../commands/removeMarks'
import resetNodeAttributes from '../commands/resetNodeAttributes' import * as resetNodeAttributes from '../commands/resetNodeAttributes'
import scrollIntoView from '../commands/scrollIntoView' import * as scrollIntoView from '../commands/scrollIntoView'
import selectAll from '../commands/selectAll' import * as selectAll from '../commands/selectAll'
import selectParentNode from '../commands/selectParentNode' import * as selectParentNode from '../commands/selectParentNode'
import setBlockType from '../commands/setBlockType' import * as setBlockType from '../commands/setBlockType'
import setContent from '../commands/setContent' import * as setContent from '../commands/setContent'
import sinkListItem from '../commands/sinkListItem' import * as sinkListItem from '../commands/sinkListItem'
import splitBlock from '../commands/splitBlock' import * as splitBlock from '../commands/splitBlock'
import splitListItem from '../commands/splitListItem' import * as splitListItem from '../commands/splitListItem'
import toggleBlockType from '../commands/toggleBlockType' import * as toggleBlockType from '../commands/toggleBlockType'
import toggleList from '../commands/toggleList' import * as toggleList from '../commands/toggleList'
import toggleMark from '../commands/toggleMark' import * as toggleMark from '../commands/toggleMark'
import toggleWrap from '../commands/toggleWrap' import * as toggleWrap from '../commands/toggleWrap'
import tryCommand from '../commands/try' import * as first from '../commands/first'
import updateNodeAttributes from '../commands/updateNodeAttributes' import * as updateNodeAttributes from '../commands/updateNodeAttributes'
import wrapIn from '../commands/wrapIn' import * as wrapIn from '../commands/wrapIn'
import wrapInList from '../commands/wrapInList' import * as wrapInList from '../commands/wrapInList'
export const Commands = Extension.create({ export const Commands = Extension.create({
addCommands() { addCommands() {
return { return {
/** ...addMark,
* Add a mark with new attributes. ...blur,
*/ ...clearContent,
addMark, ...clearNodes,
/** ...command,
* Removes focus from the editor. ...deleteSelection,
*/ ...extendMarkRange,
blur, ...first,
/** ...focus,
* Clear the whole document. ...insertHTML,
*/ ...insertText,
clearContent, ...lift,
/** ...liftListItem,
* Normalize nodes to a simple paragraph. ...removeMark,
*/ ...removeMarks,
clearNodes, ...resetNodeAttributes,
/** ...scrollIntoView,
* Define a command inline. ...selectAll,
*/ ...selectParentNode,
command, ...setBlockType,
/** ...setContent,
* Delete the selection, if there is one. ...sinkListItem,
*/ ...splitBlock,
deleteSelection, ...splitListItem,
/** ...toggleBlockType,
* Extends the text selection to the current mark. ...toggleList,
*/ ...toggleMark,
extendMarkRange, ...toggleWrap,
/** ...updateNodeAttributes,
* Focus the editor at the given position. ...wrapIn,
*/ ...wrapInList,
focus,
/**
* Insert a string of HTML at the current position.
*/
insertHTML,
/**
* Insert a string of text at the current position.
*/
insertText,
/**
* Removes an existing wrap.
*/
lift,
/**
* Lift the list item into a wrapping list.
*/
liftListItem,
/**
* Remove all marks in the current selection.
*/
removeMark,
/**
* Remove all marks in the current selection.
*/
removeMarks,
/**
* Resets node attributes to the default value.
*/
resetNodeAttributes,
/**
* Scroll the selection into view.
*/
scrollIntoView,
/**
* Select the whole document.
*/
selectAll,
/**
* Select the parent node.
*/
selectParentNode,
/**
* Replace a given range with a node.
*/
setBlockType,
/**
* Replace the whole document with new content.
*/
setContent,
/**
* Sink the list item down into an inner list.
*/
sinkListItem,
/**
* Forks a new node from an existing node.
*/
splitBlock,
/**
* Splits one list item into two list items.
*/
splitListItem,
/**
* Toggle a node with another node.
*/
toggleBlockType,
/**
* Toggle between different list types.
*/
toggleList,
/**
* Toggle a mark on and off.
*/
toggleMark,
/**
* Wraps nodes in another node, or removes an existing wrap.
*/
toggleWrap,
/**
* Runs one command after the other and stops at the first which returns true.
*/
try: tryCommand,
/**
* Update attributes of a node.
*/
updateNodeAttributes,
/**
* Wraps nodes in another node.
*/
wrapIn,
/**
* Wrap a node in a list.
*/
wrapInList,
} }
}, },
}) })

View File

@@ -14,21 +14,21 @@ import { Extension } from '../Extension'
export const Keymap = Extension.create({ export const Keymap = Extension.create({
addKeyboardShortcuts() { addKeyboardShortcuts() {
const handleBackspace = () => this.editor.commands.try(({ state, dispatch }) => [ const handleBackspace = () => this.editor.commands.first(({ state, dispatch }) => [
() => undoInputRule(state, dispatch), () => undoInputRule(state, dispatch),
() => deleteSelection(state, dispatch), () => deleteSelection(state, dispatch),
() => joinBackward(state, dispatch), () => joinBackward(state, dispatch),
() => selectNodeBackward(state, dispatch), () => selectNodeBackward(state, dispatch),
]) ])
const handleDelete = () => this.editor.commands.try(({ state, dispatch }) => [ const handleDelete = () => this.editor.commands.first(({ state, dispatch }) => [
() => deleteSelection(state, dispatch), () => deleteSelection(state, dispatch),
() => joinForward(state, dispatch), () => joinForward(state, dispatch),
() => selectNodeForward(state, dispatch), () => selectNodeForward(state, dispatch),
]) ])
return { return {
Enter: () => this.editor.commands.try(({ commands, state, dispatch }) => [ Enter: () => this.editor.commands.first(({ commands, state, dispatch }) => [
() => newlineInCode(state, dispatch), () => newlineInCode(state, dispatch),
() => createParagraphNear(state, dispatch), () => createParagraphNear(state, dispatch),
() => liftEmptyBlock(state, dispatch), () => liftEmptyBlock(state, dispatch),

View File

@@ -26,7 +26,7 @@ const HardBreak = Node.create({
* Add a hard break * Add a hard break
*/ */
setHardBreak: (): Command => ({ commands, state, dispatch }) => { setHardBreak: (): Command => ({ commands, state, dispatch }) => {
return commands.try([ return commands.first([
() => exitCode(state, dispatch), () => exitCode(state, dispatch),
() => { () => {
if (dispatch) { if (dispatch) {

View File

@@ -1,4 +1,5 @@
import { Command, Extension } from '@tiptap/core' import { Command, Extension } from '@tiptap/core'
import { chain } from 'cypress/types/lodash'
type TextAlignOptions = { type TextAlignOptions = {
types: string[], types: string[],