import type { Schema, Node, NodeType } from 'prosemirror-model'; import type { Transaction } from 'prosemirror-state'; import type { EditorView } from 'prosemirror-view'; export const setTextAlign = (tr: Transaction, schema: Schema, alignment: string) => { const { selection, doc } = tr; if (!selection || !doc) return tr; const { from, to } = selection; const { nodes } = schema; const blockquote = nodes.blockquote; const listItem = nodes.list_item; const paragraph = nodes.paragraph; interface Task { node: Node; pos: number; nodeType: NodeType; } const tasks: Task[] = []; alignment = alignment || ''; const allowedNodeTypes = new Set([blockquote, listItem, paragraph]); doc.nodesBetween(from, to, (node, pos) => { const nodeType = node.type; const align = node.attrs.align || ''; if (align !== alignment && allowedNodeTypes.has(nodeType)) { tasks.push({ node, pos, nodeType, }); } return true; }); if (!tasks.length) return tr; tasks.forEach((task) => { const { node, pos, nodeType } = task; let { attrs } = node; if (alignment) attrs = { ...attrs, align: alignment }; else attrs = { ...attrs, align: null }; tr = tr.setNodeMarkup(pos, nodeType, attrs, node.marks); }); return tr; }; export const alignmentCommand = (view: EditorView, alignment: string) => { const { state } = view; const { schema, selection } = state; const tr = setTextAlign(state.tr.setSelection(selection), schema, alignment); view.dispatch(tr); };