|
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 |
|
} |