-
Notifications
You must be signed in to change notification settings - Fork 5
/
mlc.jsx
116 lines (106 loc) · 4.44 KB
/
mlc.jsx
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import React from 'react'
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
import Admonition from '@theme/Admonition'
import reactrLanguageSupport from '@site/reactr-lang.json'
import Link from '@docusaurus/Link'
import useBaseUrl from '@docusaurus/useBaseUrl'
// List of supported languages
const LANGS = Object.keys(reactrLanguageSupport)
// Mappings of language alternatives to their canonical counterparts
const LANG_ALTS = new Map()
// Expand alts and map them to the canonical lang
Object.entries(reactrLanguageSupport).forEach(([ canonical, metadata ]) => {
metadata.alts?.forEach(alt => {
LANG_ALTS.set(alt, canonical)
})
})
/* Creates a new iteratable, ordered list of supported languages filtered by only the code blocks present in the component */
const getCodeBlockLangs = (children) =>
LANGS
.filter(lang => !!getCodeBlockForLang(lang, children))
.map(lang => reactrLanguageSupport[lang])
/* Finds the lang type of the code block in the supplied React component */
const getCodeBlockLangType = (component) => {
/* Works with toplevel <CodeBlock> elements */
if (component.props.mdxType === 'CodeBlock') return component.props.language
/* Works with markdown fenced code blocks: ```lang ... */
if (component.props.mdxType === 'pre' && component.props.children?.props.mdxType === 'code') return component.props.children.props.className.replace('language-','')
/* NOTE: this breaks if multiple children exist (props becomes an []) */
/* TODO: divs? */
return null
}
/* Normalize language definition alternatives to canonical language id */
const normalizeAlts = (lang) => {
return LANG_ALTS.get(lang) ?? lang
}
/* Returns from a list of Code Block children the one that corresponds with the selected language */
const getCodeBlockForLang = (lang, children) => {
// Try to find the requested language block in the list of child components
let component
React.Children.forEach(children,
block => {
if (lang === normalizeAlts(getCodeBlockLangType(block))) {
component = block
}
}
)
// Component not found
if (!component) console.log(lang, ' not found.')
/* Allow the changing the effective syntax highlighting scheme using the 'highlight' field */
if (component && reactrLanguageSupport[lang].highlighting) {
/* Change highlighting for CodeBlock components */
if (component.props.mdxType === 'CodeBlock') {
/* Replace the component with a new one with an overridden language prop */
return React.cloneElement(
component,
{ language: reactrLanguageSupport[lang].highlighting }
)
}
/* Change highlighting for markdown fenced code blocks */
if (component.props.mdxType === 'pre' && component.props.children?.props.mdxType === 'code') {
/* We clone the wrapper element untouched then change the embedded code block's highlighting in the className */
return React.cloneElement(
component, {},
React.cloneElement(
component.props.children,
{ className: 'language-'+reactrLanguageSupport[lang].highlighting }
)
)
}
}
return component
}
const reactrLanguageStatusBadges = (status) => {
if (status === "stable") {
return <Link to={useBaseUrl('reactr/language-support#stable')}>
<Admonition type="tip" title="STATUS: STABLE" />
</Link>
}
if (status === "beta") {
return <Link to={useBaseUrl('reactr/language-support#beta')}>
<Admonition type="info" title="STATUS: BETA" />
</Link>
}
if (status === "preview") {
return <Link to={useBaseUrl('reactr/language-support#preview')}>
<Admonition type="caution" title="STATUS: PREVIEW" />
</Link>
}
}
export const MultiLanguageCodeBlock = ({children}) => (
<>
<Tabs groupId="reactr-language" defaultValue={getCodeBlockLangs(children)?.[0].lang ?? null}>
{getCodeBlockLangs(children).map(
({lang,name,status}) =>
<TabItem
value={lang}
label={name}
>
{reactrLanguageStatusBadges(status)}
{getCodeBlockForLang(lang, children)}
</TabItem>
)}
</Tabs>
</>
);