File size: 1,725 Bytes
c20f20c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import type { NodeType, Schema } from 'prosemirror-model';
import {
  inputRules,
  wrappingInputRule,
  smartQuotes,
  emDash,
  ellipsis,
  InputRule,
} from 'prosemirror-inputrules';

const blockQuoteRule = (nodeType: NodeType) => wrappingInputRule(/^\s*>\s$/, nodeType);

const orderedListRule = (nodeType: NodeType) =>
  wrappingInputRule(
    /^(\d+)\.\s$/,
    nodeType,
    (match) => ({ order: +match[1] }),
    (match, node) => node.childCount + node.attrs.order === +match[1],
  );

const bulletListRule = (nodeType: NodeType) => wrappingInputRule(/^\s*([-+*])\s$/, nodeType);

const codeRule = () => {
  const inputRegex = /(?:^|\s)((?:`)((?:[^`]+))(?:`))$/;

  return new InputRule(inputRegex, (state, match, start, end) => {
    const { schema } = state;

    const tr = state.tr.insertText(`${match[2]} `, start, end);
    const mark = schema.marks.code.create();

    return tr.addMark(start, start + match[2].length, mark);
  });
};

const linkRule = () => {
  const urlRegEx = /(?:https?:\/\/)?[\w-]+(?:\.[\w-]+)+\.?(?:\d+)?(?:\/\S*)?$/;

  return new InputRule(urlRegEx, (state, match, start, end) => {
    const { schema } = state;

    const tr = state.tr.insertText(match[0], start, end);
    const mark = schema.marks.link.create({ href: match[0], title: match[0] });

    return tr.addMark(start, start + match[0].length, mark);
  });
};

export const buildInputRules = (schema: Schema) => {
  const rules = [...smartQuotes, ellipsis, emDash];
  rules.push(blockQuoteRule(schema.nodes.blockquote));
  rules.push(orderedListRule(schema.nodes.ordered_list));
  rules.push(bulletListRule(schema.nodes.bullet_list));
  rules.push(codeRule());
  rules.push(linkRule());

  return inputRules({ rules });
};