setTextIndent.ts 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import type { Schema } from 'prosemirror-model';
  2. import { type Transaction, TextSelection, AllSelection } from 'prosemirror-state';
  3. import type { EditorView } from 'prosemirror-view';
  4. import { isList } from '../utils';
  5. type IndentKey = 'indent' | 'textIndent';
  6. function setNodeIndentMarkup(
  7. tr: Transaction,
  8. pos: number,
  9. delta: number,
  10. indentKey: IndentKey,
  11. ): Transaction {
  12. if (!tr.doc) return tr;
  13. const node = tr.doc.nodeAt(pos);
  14. if (!node) return tr;
  15. const minIndent = 0;
  16. const maxIndent = 8;
  17. let indent = (node.attrs[indentKey] || 0) + delta;
  18. if (indent < minIndent) indent = minIndent;
  19. if (indent > maxIndent) indent = maxIndent;
  20. if (indent === node.attrs[indentKey]) return tr;
  21. const nodeAttrs = {
  22. ...node.attrs,
  23. [indentKey]: indent,
  24. };
  25. return tr.setNodeMarkup(pos, node.type, nodeAttrs, node.marks);
  26. }
  27. const setIndent = (
  28. tr: Transaction,
  29. schema: Schema,
  30. delta: number,
  31. indentKey: IndentKey,
  32. ): Transaction => {
  33. const { selection, doc } = tr;
  34. if (!selection || !doc) return tr;
  35. if (!(selection instanceof TextSelection || selection instanceof AllSelection)) return tr;
  36. const { from, to } = selection;
  37. doc.nodesBetween(from, to, (node, pos) => {
  38. const nodeType = node.type;
  39. if (nodeType.name === 'paragraph' || nodeType.name === 'blockquote') {
  40. tr = setNodeIndentMarkup(tr, pos, delta, indentKey);
  41. return false;
  42. } else if (isList(node, schema)) return false;
  43. return true;
  44. });
  45. return tr;
  46. };
  47. export const indentCommand = (view: EditorView, delta: number) => {
  48. const { state } = view;
  49. const { schema, selection } = state;
  50. const tr = setIndent(state.tr.setSelection(selection), schema, delta, 'indent');
  51. if (tr.docChanged) {
  52. view.dispatch(tr);
  53. return true;
  54. }
  55. return false;
  56. };
  57. export const textIndentCommand = (view: EditorView, delta: number) => {
  58. const { state } = view;
  59. const { schema, selection } = state;
  60. const tr = setIndent(state.tr.setSelection(selection), schema, delta, 'textIndent');
  61. if (tr.docChanged) {
  62. view.dispatch(tr);
  63. return true;
  64. }
  65. return false;
  66. };