| import type { Schema } from 'prosemirror-model' | |
| import { type Transaction, TextSelection, AllSelection } from 'prosemirror-state' | |
| import type { EditorView } from 'prosemirror-view' | |
| import { isList } from '../utils' | |
| type IndentKey = 'indent' | 'textIndent' | |
| function setNodeIndentMarkup(tr: Transaction, pos: number, delta: number, indentKey: IndentKey): Transaction { | |
| if (!tr.doc) return tr | |
| const node = tr.doc.nodeAt(pos) | |
| if (!node) return tr | |
| const minIndent = 0 | |
| const maxIndent = 8 | |
| let indent = (node.attrs[indentKey] || 0) + delta | |
| if (indent < minIndent) indent = minIndent | |
| if (indent > maxIndent) indent = maxIndent | |
| if (indent === node.attrs[indentKey]) return tr | |
| const nodeAttrs = { | |
| ...node.attrs, | |
| [indentKey]: indent, | |
| } | |
| return tr.setNodeMarkup(pos, node.type, nodeAttrs, node.marks) | |
| } | |
| const setIndent = (tr: Transaction, schema: Schema, delta: number, indentKey: IndentKey): Transaction => { | |
| const { selection, doc } = tr | |
| if (!selection || !doc) return tr | |
| if (!(selection instanceof TextSelection || selection instanceof AllSelection)) return tr | |
| const { from, to } = selection | |
| doc.nodesBetween(from, to, (node, pos) => { | |
| const nodeType = node.type | |
| if (nodeType.name === 'paragraph' || nodeType.name === 'blockquote') { | |
| tr = setNodeIndentMarkup(tr, pos, delta, indentKey) | |
| return false | |
| } | |
| else if (isList(node, schema)) return false | |
| return true | |
| }) | |
| return tr | |
| } | |
| export const indentCommand = (view: EditorView, delta: number) => { | |
| const { state } = view | |
| const { schema, selection } = state | |
| const tr = setIndent( | |
| state.tr.setSelection(selection), | |
| schema, | |
| delta, | |
| 'indent', | |
| ) | |
| if (tr.docChanged) { | |
| view.dispatch(tr) | |
| return true | |
| } | |
| return false | |
| } | |
| export const textIndentCommand = (view: EditorView, delta: number) => { | |
| const { state } = view | |
| const { schema, selection } = state | |
| const tr = setIndent( | |
| state.tr.setSelection(selection), | |
| schema, | |
| delta, | |
| 'textIndent', | |
| ) | |
| if (tr.docChanged) { | |
| view.dispatch(tr) | |
| return true | |
| } | |
| return false | |
| } |