Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 | import {Absolute, BorderBox, Flex, Relative, Text} from '@primer/components'
import htmlReactParser from 'html-react-parser'
import githubTheme from 'prism-react-renderer/themes/github'
import React, { useState } from 'react'
import reactElementToJsxString from 'react-element-to-jsx-string'
import {LiveEditor, LiveError, LivePreview, LiveProvider} from 'react-live'
import {ThemeContext} from 'styled-components'
import scope from '../live-code-scope'
import ClipboardCopy from './clipboard-copy'
import LivePreviewWrapper from './live-preview-wrapper'
const languageTransformers = {
html: html => htmlToJsx(html),
jsx: jsx => wrapWithFragment(jsx),
}
function htmlToJsx(html) {
try {
const reactElement = htmlReactParser(removeNewlines(html))
// The output of htmlReactParser could be a single React element
// or an array of React elements. reactElementToJsxString does not accept arrays
// so we have to wrap the output in React fragment.
return reactElementToJsxString(<>{reactElement}</>)
} catch (error) {
return wrapWithFragment(html)
}
}
function removeNewlines(string) {
return string.replace(/(\r\n|\n|\r)/gm, '')
}
function wrapWithFragment(jsx) {
return `<React.Fragment>${jsx}</React.Fragment>`
}
function LiveCode({code, language, noinline}) {
const theme = React.useContext(ThemeContext)
const [liveCode, setLiveCode] = useState(code)
const handleChange = (updatedLiveCode) => setLiveCode(updatedLiveCode)
return (
<BorderBox
flexDirection="column"
mb={3}
>
<LiveProvider
scope={scope}
code={liveCode}
transformCode={languageTransformers[language]}
noInline={noinline}
>
<LivePreviewWrapper>
<LivePreview />
</LivePreviewWrapper>
<Relative>
<LiveEditor
onChange={handleChange}
theme={githubTheme}
ignoreTabKey={true}
padding={theme.space[3]}
style={{
fontFamily: theme.fonts.mono,
fontSize: '85%',
borderBottomLeftRadius: theme.radii[2],
borderBottomRightRadius: theme.radii[2],
}}
/>
<Absolute top={0} right={0} p={2}>
<ClipboardCopy value={liveCode} />
</Absolute>
</Relative>
<Text
as={LiveError}
m={0}
p={3}
fontFamily="mono"
fontSize={1}
color="white"
bg="red.5"
/>
</LiveProvider>
</BorderBox>
)
}
export default LiveCode
|