inputrules.ts 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. import type { NodeType, Schema } from 'prosemirror-model';
  2. import {
  3. inputRules,
  4. wrappingInputRule,
  5. smartQuotes,
  6. emDash,
  7. ellipsis,
  8. InputRule,
  9. } from 'prosemirror-inputrules';
  10. const blockQuoteRule = (nodeType: NodeType) => wrappingInputRule(/^\s*>\s$/, nodeType);
  11. const orderedListRule = (nodeType: NodeType) =>
  12. wrappingInputRule(
  13. /^(\d+)\.\s$/,
  14. nodeType,
  15. (match) => ({ order: +match[1] }),
  16. (match, node) => node.childCount + node.attrs.order === +match[1],
  17. );
  18. const bulletListRule = (nodeType: NodeType) => wrappingInputRule(/^\s*([-+*])\s$/, nodeType);
  19. const codeRule = () => {
  20. const inputRegex = /(?:^|\s)((?:`)((?:[^`]+))(?:`))$/;
  21. return new InputRule(inputRegex, (state, match, start, end) => {
  22. const { schema } = state;
  23. const tr = state.tr.insertText(`${match[2]} `, start, end);
  24. const mark = schema.marks.code.create();
  25. return tr.addMark(start, start + match[2].length, mark);
  26. });
  27. };
  28. const linkRule = () => {
  29. const urlRegEx = /(?:https?:\/\/)?[\w-]+(?:\.[\w-]+)+\.?(?:\d+)?(?:\/\S*)?$/;
  30. return new InputRule(urlRegEx, (state, match, start, end) => {
  31. const { schema } = state;
  32. const tr = state.tr.insertText(match[0], start, end);
  33. const mark = schema.marks.link.create({ href: match[0], title: match[0] });
  34. return tr.addMark(start, start + match[0].length, mark);
  35. });
  36. };
  37. export const buildInputRules = (schema: Schema) => {
  38. const rules = [...smartQuotes, ellipsis, emDash];
  39. rules.push(blockQuoteRule(schema.nodes.blockquote));
  40. rules.push(orderedListRule(schema.nodes.ordered_list));
  41. rules.push(bulletListRule(schema.nodes.bullet_list));
  42. rules.push(codeRule());
  43. rules.push(linkRule());
  44. return inputRules({ rules });
  45. };