aboutsummaryrefslogtreecommitdiff
path: root/src/lib/Markdown/InlineSyntax.tsx
blob: bf5669ddf3089e96b358704119d5131e0e3b21c3 (plain)
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import React from 'react';
import { Link } from '@material-ui/core';
import axios from 'axios';

import { InlineParserPropTypes } from './types';

interface RegexPair {
  global: RegExp;
  local: RegExp;
}

interface Emoji {
  name: string;
  char: string;
}

const enclosureRegex = (e: string): RegexPair => ({
  local: new RegExp(`${e}([^${e}]+)${e}`),
  global: new RegExp(`(${e}[^${e}]+${e})`)
});

const regex: Record<string, RegexPair> = {
  conceal: {
    global: /(!?\[.+?\]\(.+?\))/g,
    local: /!?\[(.+?)\]\((.+?)\)/
  },
  rawLink: {
    global: /((?:(?:[A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www\.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)(?:(?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[.!/\\\w]*))?)/,
    local: /&^/
  },
  emoji: enclosureRegex(':'),
  bold: enclosureRegex('\\*\\*'),
  italic: enclosureRegex('\\*'),
  code: enclosureRegex('`'),
  strikeThrough: enclosureRegex('~~'),
}

const splitter = new RegExp(Object.values(regex).map(pair => pair.global.source).join('|'));

const emojiList: Emoji[] = [];
axios.get('https://unpkg.com/emojilib@2.4.0/emojis.json').then(response => {
  Object.keys(response.data).forEach(name => emojiList.push({ name, char: response.data[name].char }));
});


const InlineSyntax: React.FC<InlineParserPropTypes> = ({ line }) => {
  if (!line) return null;

  const matchConceal = regex.conceal.local.exec(line);
  if (matchConceal) {
    if (line[0] === '!') return <img src={matchConceal[2]} alt={matchConceal[1]} style={{ maxWidth: '100%', maxHeight: '100%' }} />;
    return <Link href={matchConceal[2]}>{matchConceal[1]}</Link>;
  }

  const matchEmoji = line.match(regex.emoji.local);
  if (matchEmoji) {
    const emoji = emojiList.find(emoji => emoji.name === matchEmoji[1]);
    return <span>{emoji ? emoji.char : line}</span>;
  }

  const matchCode = line.match(regex.code.local);
  if (matchCode) return <span style={{ background: 'rgba(255, 255, 255, .1)' }}>{matchCode[1]}</span>;

  const matchBold = line.match(regex.bold.local);
  if (matchBold) return <b>{matchBold[1]}</b>;

  const matchItalic = line.match(regex.italic.local);
  if (matchItalic) return <i>{matchItalic[1]}</i>;

  const matchStrikeThrough = line.match(regex.strikeThrough.local);
  if (matchStrikeThrough) return <span style={{textDecoration: 'line-through' }}>{matchStrikeThrough[1]}</span>;

  if (line.match(regex.rawLink.global)) return <Link href={line}>{line}</Link>;

  return <>{line}</>;
}


export { splitter };
export default InlineSyntax;