@tiptap/core
Version:
headless rich text editor
46 lines (38 loc) • 1.72 kB
text/typescript
import { NodeType } from '@tiptap/pm/model'
import { getNodeType } from '../helpers/getNodeType.js'
import { isNodeActive } from '../helpers/isNodeActive.js'
import { RawCommands } from '../types.js'
declare module '@tiptap/core' {
interface Commands<ReturnType> {
toggleNode: {
/**
* Toggle a node with another node.
* @param typeOrName The type or name of the node.
* @param toggleTypeOrName The type or name of the node to toggle.
* @param attributes The attributes of the node.
* @example editor.commands.toggleNode('heading', 'paragraph')
*/
toggleNode: (
typeOrName: string | NodeType,
toggleTypeOrName: string | NodeType,
attributes?: Record<string, any>,
) => ReturnType
}
}
}
export const toggleNode: RawCommands['toggleNode'] = (typeOrName, toggleTypeOrName, attributes = {}) => ({ state, commands }) => {
const type = getNodeType(typeOrName, state.schema)
const toggleType = getNodeType(toggleTypeOrName, state.schema)
const isActive = isNodeActive(state, type, attributes)
let attributesToCopy: Record<string, any> | undefined
if (state.selection.$anchor.sameParent(state.selection.$head)) {
// only copy attributes if the selection is pointing to a node of the same type
attributesToCopy = state.selection.$anchor.parent.attrs
}
if (isActive) {
return commands.setNode(toggleType, attributesToCopy)
}
// If the node is not active, we want to set the new node type with the given attributes
// Copying over the attributes from the current node if the selection is pointing to a node of the same type
return commands.setNode(type, { ...attributesToCopy, ...attributes })
}