72 lines
2.2 KiB
TypeScript
72 lines
2.2 KiB
TypeScript
import { Extension, CommandProps } from '@tiptap/core'
|
||
import { Node as ProseMirrorNode } from '@tiptap/pm/model'
|
||
|
||
const INDENT_CLASS_NAME = 'text-indent'
|
||
|
||
|
||
// Вспомогательная функция для добавления/удаления CSS-класса
|
||
const toggleCssClass = (currentClasses: string | null | undefined, className: string): string | null => {
|
||
const classes = new Set((currentClasses || '').split(' ').filter(Boolean))
|
||
|
||
if (classes.has(className)) {
|
||
classes.delete(className)
|
||
} else {
|
||
classes.add(className)
|
||
}
|
||
|
||
return classes.size > 0 ? Array.from(classes).join(' ') : null
|
||
}
|
||
|
||
export const Indent = Extension.create({
|
||
name: 'indent',
|
||
|
||
addCommands() {
|
||
return {
|
||
toggleIndent:
|
||
() =>
|
||
({ tr, state, dispatch }: CommandProps): boolean => {
|
||
const { selection } = state
|
||
const { from, to } = selection
|
||
let changed = false
|
||
|
||
tr.doc.nodesBetween(from, to, (node: ProseMirrorNode, pos: number) => {
|
||
if (node.type.name === 'paragraph') {
|
||
const currentClasses = node.attrs.class as string | null | undefined
|
||
const newClasses = toggleCssClass(currentClasses, INDENT_CLASS_NAME)
|
||
|
||
if (newClasses !== currentClasses) {
|
||
tr.setNodeMarkup(pos, undefined, {
|
||
...node.attrs,
|
||
class: newClasses,
|
||
})
|
||
changed = true
|
||
}
|
||
}
|
||
return false // Не углубляться
|
||
})
|
||
|
||
if (changed && dispatch) {
|
||
dispatch(tr.scrollIntoView())
|
||
return true
|
||
}
|
||
|
||
return false
|
||
},
|
||
}
|
||
},
|
||
|
||
// Можно убрать, если не используешь
|
||
addStorage() {
|
||
return {
|
||
isActive: (state: any): boolean => {
|
||
const { $from } = state.selection
|
||
const node = $from.node($from.depth)
|
||
if (node?.type.name === 'paragraph') {
|
||
return (node.attrs.class || '').split(' ').includes(INDENT_CLASS_NAME)
|
||
}
|
||
return false
|
||
},
|
||
}
|
||
},
|
||
})
|