import { Extension } from "@tiptap/core" export interface IndentOptions { types: string[] minLevel: number maxLevel: number } declare module "@tiptap/core" { interface Commands { indent: { /** * Increase indent level */ increaseIndent: () => ReturnType /** * Decrease indent level */ decreaseIndent: () => ReturnType } } } export const Indent = Extension.create({ name: "indent", addOptions() { return { types: ["paragraph", "heading"], minLevel: 0, maxLevel: 8, } }, addGlobalAttributes() { return [ { types: this.options.types, attributes: { indent: { default: 0, parseHTML: element => { const dataIndent = element.getAttribute("data-indent") return dataIndent ? Number.parseInt(dataIndent, 10) : 0 }, renderHTML: attributes => { if (!attributes.indent || attributes.indent === 0) { return {} } return { "data-indent": attributes.indent, style: `margin-left: ${attributes.indent * 1.5}rem`, } }, }, }, }, ] }, addCommands() { return { increaseIndent: () => ({ commands, state }) => { const { selection } = state const { $from } = selection const node = $from.node() // Check if the current node type is supported if (!this.options.types.includes(node.type.name)) { return false } const currentIndent = node.attrs.indent || 0 const newIndent = Math.min(this.options.maxLevel, currentIndent + 1) return commands.updateAttributes(node.type.name, { indent: newIndent }) }, decreaseIndent: () => ({ commands, state }) => { const { selection } = state const { $from } = selection const node = $from.node() // Check if the current node type is supported if (!this.options.types.includes(node.type.name)) { return false } const currentIndent = node.attrs.indent || 0 const newIndent = Math.max(this.options.minLevel, currentIndent - 1) return commands.updateAttributes(node.type.name, { indent: newIndent }) }, } }, addKeyboardShortcuts() { return { Tab: () => this.editor.commands.increaseIndent(), "Shift-Tab": () => this.editor.commands.decreaseIndent(), } }, })