setTextAlign.ts 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. import type { Schema, Node, NodeType } from 'prosemirror-model';
  2. import type { Transaction } from 'prosemirror-state';
  3. import type { EditorView } from 'prosemirror-view';
  4. export const setTextAlign = (tr: Transaction, schema: Schema, alignment: string) => {
  5. const { selection, doc } = tr;
  6. if (!selection || !doc) return tr;
  7. const { from, to } = selection;
  8. const { nodes } = schema;
  9. const blockquote = nodes.blockquote;
  10. const listItem = nodes.list_item;
  11. const paragraph = nodes.paragraph;
  12. interface Task {
  13. node: Node;
  14. pos: number;
  15. nodeType: NodeType;
  16. }
  17. const tasks: Task[] = [];
  18. alignment = alignment || '';
  19. const allowedNodeTypes = new Set([blockquote, listItem, paragraph]);
  20. doc.nodesBetween(from, to, (node, pos) => {
  21. const nodeType = node.type;
  22. const align = node.attrs.align || '';
  23. if (align !== alignment && allowedNodeTypes.has(nodeType)) {
  24. tasks.push({
  25. node,
  26. pos,
  27. nodeType,
  28. });
  29. }
  30. return true;
  31. });
  32. if (!tasks.length) return tr;
  33. tasks.forEach((task) => {
  34. const { node, pos, nodeType } = task;
  35. let { attrs } = node;
  36. if (alignment) attrs = { ...attrs, align: alignment };
  37. else attrs = { ...attrs, align: null };
  38. tr = tr.setNodeMarkup(pos, nodeType, attrs, node.marks);
  39. });
  40. return tr;
  41. };
  42. export const alignmentCommand = (view: EditorView, alignment: string) => {
  43. const { state } = view;
  44. const { schema, selection } = state;
  45. const tr = setTextAlign(state.tr.setSelection(selection), schema, alignment);
  46. view.dispatch(tr);
  47. };