Skip to content

Instantly share code, notes, and snippets.

@isBatak
Last active May 20, 2022 16:13
Show Gist options
  • Save isBatak/6749463aca6d14516bc6e37ae5971189 to your computer and use it in GitHub Desktop.
Save isBatak/6749463aca6d14516bc6e37ae5971189 to your computer and use it in GitHub Desktop.
How to create Live Code editor and Chakra UI styled props as a Markdown code meta!
const components = {
pre: CodeEditor,
};
function MyApp({ Component, pageProps, ...rest }) {
return (
<ChakraProvider theme={theme}>
<MDXProvider components={components}>
<Component {...pageProps} />
</MDXProvider>
</ChakraProvider>
);
}
export default MyApp;
export interface ICodeEditorProps {
children: ReactNode;
className?: string;
path?: string;
code?: string;
isLive?: boolean;
title?: string;
lang?: Language;
}
export const CodeEditor: FC<ICodeEditorProps> = ({ children, className, path, code, title, isLive, lang, ...rest }) => {
if (isLive) {
return <CodeRunner title={title} initialCode={code} {...rest} />;
}
return children;
};
import * as Chakra from '@chakra-ui/react';
import { Textarea } from '@chakra-ui/react';
import { FC, ReactNode, useState } from 'react';
import { FaEye, FaCode } from 'react-icons/fa';
import { useRunner } from 'react-runner';
import { CodeMirror as CM } from 'react-runner-codemirror';
const { chakra, Box, Button, ButtonGroup, Flex, Heading, Stack } = Chakra;
const scope = {
import: {
'@chakra-ui/react': Chakra,
},
};
const CodeMirror = chakra(CM);
export interface ICodeRunnerProps extends Omit<Chakra.HTMLChakraProps<'div'>, 'title'> {
title?: ReactNode;
initialCode?: string;
}
export const CodeRunner: FC<ICodeRunnerProps> = ({ title, initialCode = '', ...props }) => {
const [code, onChange] = useState(initialCode);
const { element, error } = useRunner({ code, scope });
return (
<Box ring="1" ringColor="gray.200" rounded="lg" {...props}>
<CodeMirror filename={`index.js`} defaultValue={code} onChange={(newCodes) => onChange(newCodes)} />
<Box>{element}</Box>
{error && <pre>{error}</pre>}
</Box>
);
};
import { remarkMdxCodeMeta } from './plugins/remark/remark-mdx-code-meta.mjs';
import nextMDX from '@next/mdx';
const withMDX = nextMDX({
extension: /\.mdx?$/,
/** @type {import('@mdx-js/loader').Options} */
options: {
remarkPlugins: [remarkMdxCodeMeta],
providerImportSource: '@mdx-js/react',
},
});
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
};
export default withMDX(nextConfig);
import { Parser } from 'acorn';
import jsx from 'acorn-jsx';
import { visit } from 'unist-util-visit';
const parser = Parser.extend(jsx());
export const transformer = (ast) => {
visit(ast, 'code', ({ meta, lang, value }, index, parent) => {
const code = JSON.stringify(`${value}\n`);
const langAttribute = lang ? `lang="${lang}"` : '';
const codeAttribute = `code="${value}"`;
const codeProps = lang ? `className="language-${lang}"` : '';
const template = `<pre ${meta} ${langAttribute} ${codeAttribute}><code ${codeProps}>{${code}}</code></pre>`;
const estree = parser.parse(template, { ecmaVersion: 'latest' });
parent.children[index] = { type: 'mdxFlowExpression', template, data: { estree } };
});
};
export const remarkMdxCodeMeta = () => transformer;

Live Editor 🤘

import { Button } from '@chakra-ui/react'

export default function Demo() {
  return (
    <Button m={2}>Button</Button>
  );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment