diff --git a/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts b/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts
index 4d0b08fa94..a1d095387e 100644
--- a/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts
+++ b/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts
@@ -104,6 +104,7 @@ export type TableOfContents = {
maxHeadingLevel: number;
};
+// TODO Docusaurus v4: use interface + declaration merging to enhance
// Theme config after validation/normalization
export type ThemeConfig = {
docs: {
diff --git a/packages/docusaurus-theme-live-codeblock/src/theme-live-codeblock.d.ts b/packages/docusaurus-theme-live-codeblock/src/theme-live-codeblock.d.ts
index 1047302e70..6b2909123f 100644
--- a/packages/docusaurus-theme-live-codeblock/src/theme-live-codeblock.d.ts
+++ b/packages/docusaurus-theme-live-codeblock/src/theme-live-codeblock.d.ts
@@ -39,6 +39,33 @@ declare module '@theme/Playground' {
export default function Playground(props: LiveProviderProps): ReactNode;
}
+declare module '@theme/Playground/Preview' {
+ import type {ReactNode} from 'react';
+
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
+ export interface Props {}
+
+ export default function PlaygroundPreview(props: Props): ReactNode;
+}
+
+declare module '@theme/Playground/Editor' {
+ import type {ReactNode} from 'react';
+
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
+ export interface Props {}
+
+ export default function PlaygroundEditor(props: Props): ReactNode;
+}
+
+declare module '@theme/Playground/Header' {
+ import type {ReactNode} from 'react';
+
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
+ export interface Props {}
+
+ export default function PlaygroundHeader(props: Props): ReactNode;
+}
+
declare module '@theme/ReactLiveScope' {
type Scope = {
[key: string]: unknown;
diff --git a/packages/docusaurus-theme-live-codeblock/src/theme/Playground/Editor/index.tsx b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/Editor/index.tsx
new file mode 100644
index 0000000000..3ba90571cb
--- /dev/null
+++ b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/Editor/index.tsx
@@ -0,0 +1,23 @@
+/**
+ * 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, {type ReactNode} from 'react';
+import {LiveEditor} from 'react-live';
+import useIsBrowser from '@docusaurus/useIsBrowser';
+import styles from './styles.module.css';
+
+export default function PlaygroundEditor(): ReactNode {
+ const isBrowser = useIsBrowser();
+ return (
+
+ );
+}
diff --git a/packages/docusaurus-theme-live-codeblock/src/theme/Playground/Editor/styles.module.css b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/Editor/styles.module.css
new file mode 100644
index 0000000000..3b5165baf9
--- /dev/null
+++ b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/Editor/styles.module.css
@@ -0,0 +1,17 @@
+/**
+ * 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.
+ */
+
+.playgroundEditor {
+ font: var(--ifm-code-font-size) / var(--ifm-pre-line-height)
+ var(--ifm-font-family-monospace) !important;
+ /* rtl:ignore */
+ direction: ltr;
+}
+
+.playgroundEditor pre {
+ border-radius: 0;
+}
diff --git a/packages/docusaurus-theme-live-codeblock/src/theme/Playground/Header/index.tsx b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/Header/index.tsx
new file mode 100644
index 0000000000..5d1e4d2499
--- /dev/null
+++ b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/Header/index.tsx
@@ -0,0 +1,19 @@
+/**
+ * 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, {type ReactNode} from 'react';
+import clsx from 'clsx';
+
+import styles from './styles.module.css';
+
+export default function PlaygroundHeader({
+ children,
+}: {
+ children: ReactNode;
+}): ReactNode {
+ return
{children}
;
+}
diff --git a/packages/docusaurus-theme-live-codeblock/src/theme/Playground/Header/styles.module.css b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/Header/styles.module.css
new file mode 100644
index 0000000000..092af7825d
--- /dev/null
+++ b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/Header/styles.module.css
@@ -0,0 +1,21 @@
+/**
+ * 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.
+ */
+
+.playgroundHeader {
+ letter-spacing: 0.08rem;
+ padding: 0.75rem;
+ text-transform: uppercase;
+ font-weight: bold;
+ background: var(--ifm-color-emphasis-200);
+ color: var(--ifm-color-content);
+ font-size: var(--ifm-code-font-size);
+}
+
+.playgroundHeader:first-of-type {
+ background: var(--ifm-color-emphasis-600);
+ color: var(--ifm-color-content-inverse);
+}
diff --git a/packages/docusaurus-theme-live-codeblock/src/theme/Playground/Preview/index.tsx b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/Preview/index.tsx
new file mode 100644
index 0000000000..b4f6e1ef88
--- /dev/null
+++ b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/Preview/index.tsx
@@ -0,0 +1,59 @@
+/**
+ * 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, {type ReactNode} from 'react';
+import {LiveError, LivePreview} from 'react-live';
+import BrowserOnly from '@docusaurus/BrowserOnly';
+import {ErrorBoundaryErrorMessageFallback} from '@docusaurus/theme-common';
+import ErrorBoundary from '@docusaurus/ErrorBoundary';
+import Translate from '@docusaurus/Translate';
+import PlaygroundHeader from '@theme/Playground/Header';
+
+import styles from './styles.module.css';
+
+function Loader() {
+ // Is it worth improving/translating?
+ // eslint-disable-next-line @docusaurus/no-untranslated-text
+ return Loading...
;
+}
+
+function PlaygroundLivePreview(): ReactNode {
+ // No SSR for the live preview
+ // See https://github.com/facebook/docusaurus/issues/5747
+ return (
+ }>
+ {() => (
+ <>
+ (
+
+ )}>
+
+
+
+ >
+ )}
+
+ );
+}
+
+export default function PlaygroundPreview(): ReactNode {
+ return (
+ <>
+
+
+ Result
+
+
+
+ >
+ );
+}
diff --git a/packages/docusaurus-theme-live-codeblock/src/theme/Playground/Preview/styles.module.css b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/Preview/styles.module.css
new file mode 100644
index 0000000000..b22c113f10
--- /dev/null
+++ b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/Preview/styles.module.css
@@ -0,0 +1,11 @@
+/**
+ * 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.
+ */
+
+.playgroundPreview {
+ padding: 1rem;
+ background-color: var(--ifm-pre-background);
+}
diff --git a/packages/docusaurus-theme-live-codeblock/src/theme/Playground/index.tsx b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/index.tsx
index 37cda3ee02..1a078c549b 100644
--- a/packages/docusaurus-theme-live-codeblock/src/theme/Playground/index.tsx
+++ b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/index.tsx
@@ -6,137 +6,74 @@
*/
import React, {type ReactNode} from 'react';
-import clsx from 'clsx';
-import useIsBrowser from '@docusaurus/useIsBrowser';
-import {LiveProvider, LiveEditor, LiveError, LivePreview} from 'react-live';
-import Translate from '@docusaurus/Translate';
-import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
-import BrowserOnly from '@docusaurus/BrowserOnly';
-import {
- ErrorBoundaryErrorMessageFallback,
- usePrismTheme,
-} from '@docusaurus/theme-common';
-import ErrorBoundary from '@docusaurus/ErrorBoundary';
+import {LiveProvider} from 'react-live';
+import {usePrismTheme, useThemeConfig} from '@docusaurus/theme-common';
+import PlaygroundPreview from '@theme/Playground/Preview';
+import PlaygroundEditor from '@theme/Playground/Editor';
import type {Props} from '@theme/Playground';
import type {ThemeConfig} from '@docusaurus/theme-live-codeblock';
import styles from './styles.module.css';
-function Header({children}: {children: ReactNode}) {
- return {children}
;
-}
-
-function LivePreviewLoader() {
- // Is it worth improving/translating?
- // eslint-disable-next-line @docusaurus/no-untranslated-text
- return Loading...
;
-}
-
-function Preview() {
- // No SSR for the live preview
- // See https://github.com/facebook/docusaurus/issues/5747
- return (
- }>
- {() => (
- <>
- (
-
- )}>
-
-
-
- >
- )}
-
- );
-}
-
-function ResultWithHeader() {
- return (
- <>
-
- {/* https://github.com/facebook/docusaurus/issues/5747 */}
-
- >
- );
-}
-
-function ThemedLiveEditor() {
- const isBrowser = useIsBrowser();
- return (
-
- );
-}
-
-function EditorWithHeader() {
- return (
- <>
-
-
- >
- );
-}
-
// this should rather be a stable function
// see https://github.com/facebook/docusaurus/issues/9630#issuecomment-1855682643
const DEFAULT_TRANSFORM_CODE = (code: string) => `${code};`;
+type PlaygroundProviderProps = Omit & {
+ code: string | undefined;
+ children: ReactNode;
+};
+
+function PlaygroundProvider(props: PlaygroundProviderProps): ReactNode {
+ const prismTheme = usePrismTheme();
+ const noInline = props.metastring?.includes('noInline') ?? false;
+ return (
+
+
+
+ );
+}
+
+function useLiveCodeBlockThemeConfig() {
+ const themeConfig = useThemeConfig() as unknown as ThemeConfig;
+ return themeConfig.liveCodeBlock;
+}
+
+function PlaygroundContent(): ReactNode {
+ const {playgroundPosition} = useLiveCodeBlockThemeConfig();
+ return (
+ <>
+ {playgroundPosition === 'top' ? (
+ <>
+
+
+ >
+ ) : (
+ <>
+
+
+ >
+ )}
+ >
+ );
+}
+
export default function Playground({
children,
transformCode,
...props
}: Props): ReactNode {
- const {
- siteConfig: {themeConfig},
- } = useDocusaurusContext();
- const {
- liveCodeBlock: {playgroundPosition},
- } = themeConfig as ThemeConfig;
- const prismTheme = usePrismTheme();
-
- const noInline = props.metastring?.includes('noInline') ?? false;
-
return (
-
- {playgroundPosition === 'top' ? (
- <>
-
-
- >
- ) : (
- <>
-
-
- >
- )}
-
+
+
+
);
}
diff --git a/packages/docusaurus-theme-live-codeblock/src/theme/Playground/styles.module.css b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/styles.module.css
index 6696d31335..a0387c648c 100644
--- a/packages/docusaurus-theme-live-codeblock/src/theme/Playground/styles.module.css
+++ b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/styles.module.css
@@ -26,19 +26,3 @@
background: var(--ifm-color-emphasis-600);
color: var(--ifm-color-content-inverse);
}
-
-.playgroundEditor {
- font: var(--ifm-code-font-size) / var(--ifm-pre-line-height)
- var(--ifm-font-family-monospace) !important;
- /* rtl:ignore */
- direction: ltr;
-}
-
-.playgroundEditor pre {
- border-radius: 0;
-}
-
-.playgroundPreview {
- padding: 1rem;
- background-color: var(--ifm-pre-background);
-}