This repository has been archived by the owner on Jan 5, 2022. It is now read-only.
/
CodeBlock.js
74 lines (69 loc) · 2.18 KB
/
CodeBlock.js
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
import React, { memo, useCallback, useMemo, useState, useEffect } from 'react';
import Prism from 'prismjs';
import components from 'prismjs/components';
import 'prismjs/themes/prism.css'; // or another theme
const nativeLanguages = components.languages;
const nativePairs = Object.assign(
...Object.entries(nativeLanguages).map(([key, value]) => ({
[key]: { key, lang: value },
}))
);
const pairs = Object.assign(
...Object.entries(nativePairs)
.filter(([key, value]) => value.lang.alias)
.map(([key, value]) => {
const alias = Array.isArray(value.lang.alias)
? value.lang.alias
: [value.lang.alias];
return Object.assign(...alias.map(a => ({ [a]: value })));
}),
nativePairs
);
const importLang = async language => {
const { key, lang } = pairs[language];
if (!key) {
return;
}
if (lang.require) {
const req = Array.isArray(lang.require) ? lang.require : [lang.require];
await Promise.all(req.map(language => importLang(language)));
}
await import(`prismjs/components/prism-${key}`);
};
const CodeBlock = ({ children, className }) => {
const language = useMemo(
() => (className ? className.replace(/language-/, '') : ''),
[className]
);
const { key } = useMemo(() => pairs[language] || {}, [language]);
const canBeHighlighted = useMemo(() => Boolean(key), [key]);
const [isReady, setIsReady] = useState(!canBeHighlighted);
useEffect(() => {
let isCanceled = false;
setIsReady(!canBeHighlighted);
if (canBeHighlighted) {
(async () => {
await importLang(language);
if (isCanceled) return;
setIsReady(true);
})();
}
return () => {
isCanceled = true;
};
}, [canBeHighlighted, language]);
const html = useMemo(() => {
if (!isReady || !canBeHighlighted) {
return Prism.util.encode(children);
}
return Prism.highlight(children, Prism.languages[language], language);
}, [canBeHighlighted, children, isReady, language]);
const createMarkup = useCallback(() => ({ __html: html }), [html]);
return (
<code
className={`language-${language}`}
dangerouslySetInnerHTML={createMarkup()}
/>
);
};
export default memo(CodeBlock);