packages/docusaurus-theme-live-codeblock/src/theme/Playground/index.tsx (102 lines of code) (raw):
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import React from 'react';
import {LiveProvider, LiveEditor, LiveError, LivePreview} from 'react-live';
import clsx from 'clsx';
import Translate from '@docusaurus/Translate';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import BrowserOnly from '@docusaurus/BrowserOnly';
import {usePrismTheme} from '@docusaurus/theme-common';
import styles from './styles.module.css';
import useIsBrowser from '@docusaurus/useIsBrowser';
import type {Props} from '@theme/Playground';
import type {ThemeConfig} from '@docusaurus/theme-live-codeblock';
function Header({children}: {children: React.ReactNode}) {
return <div className={clsx(styles.playgroundHeader)}>{children}</div>;
}
function LivePreviewLoader() {
// Is it worth improving/translating?
return <div>Loading...</div>;
}
function ResultWithHeader() {
return (
<>
<Header>
<Translate
id="theme.Playground.result"
description="The result label of the live codeblocks">
Result
</Translate>
</Header>
{/* https://github.com/facebook/docusaurus/issues/5747 */}
<div className={styles.playgroundPreview}>
<BrowserOnly fallback={<LivePreviewLoader />}>
{() => (
<>
<LivePreview />
<LiveError />
</>
)}
</BrowserOnly>
</div>
</>
);
}
function ThemedLiveEditor() {
const isBrowser = useIsBrowser();
return (
<LiveEditor
// We force remount the editor on hydration,
// otherwise dark prism theme is not applied
key={String(isBrowser)}
className={styles.playgroundEditor}
/>
);
}
function EditorWithHeader() {
return (
<>
<Header>
<Translate
id="theme.Playground.liveEditor"
description="The live editor label of the live codeblocks">
Live Editor
</Translate>
</Header>
<ThemedLiveEditor />
</>
);
}
export default function Playground({
children,
transformCode,
...props
}: Props): JSX.Element {
const {
siteConfig: {themeConfig},
} = useDocusaurusContext();
const {
liveCodeBlock: {playgroundPosition},
} = themeConfig as ThemeConfig;
const prismTheme = usePrismTheme();
return (
<div className={styles.playgroundContainer}>
{/* @ts-expect-error: type incompatibility with refs */}
<LiveProvider
code={children.replace(/\n$/, '')}
transformCode={transformCode || ((code) => `${code};`)}
theme={prismTheme}
{...props}>
{playgroundPosition === 'top' ? (
<>
<ResultWithHeader />
<EditorWithHeader />
</>
) : (
<>
<EditorWithHeader />
<ResultWithHeader />
</>
)}
</LiveProvider>
</div>
);
}