Workaround Docusaurus prism highlighting hydration bug (#1519)

Summary:
Pull Request resolved: https://github.com/facebook/yoga/pull/1519

See https://github.com/facebook/docusaurus/issues/9629

We use prism to render the code for the inline editor. Prism renders colors to style directly, and the color chosen is dependent on a setting that may not be available at SSR time.

This adds an SSR-specific representation of the code, missing some of the nuances in token colorization (similar to https://github.com/facebook/docusaurus/pull/7373). This adds a little bit of jank compared to perfect SSR, but fixes cases where the mode is incorrect, and is a lot less jank then the more generic solution used by theme-live-codeblock of keeping the rendering of the opposite color until rehydration.

Preview: https://yoga-website-next-git-fork-nickgerleman-exp-2f8171-fbopensource.vercel.app/

Reviewed By: yungsters

Differential Revision: D52163722

fbshipit-source-id: 312dc52134f0084d40f78147190151700ee10ff7
This commit is contained in:
Nick Gerleman
2023-12-19 12:46:26 -08:00
committed by Facebook GitHub Bot
parent 3f6f04cb92
commit 2caa8ac8cb
2 changed files with 43 additions and 9 deletions

View File

@@ -27,6 +27,7 @@ import type {FlexStyle} from './FlexStyle';
import type {StyleNode} from './YogaViewer';
import styles from './Playground.module.css';
import useIsBrowser from '@docusaurus/useIsBrowser';
export type Props = Readonly<{
code: string;
@@ -37,6 +38,7 @@ export type Props = Readonly<{
export default function Playground({code, height, autoFocus}: Props) {
const prismTheme = usePrismTheme();
const editorScrollRef = useRef<HTMLDivElement>(null);
const isBrowser = useIsBrowser();
const [liveCode, setLiveCode] = useState(code);
const [hasCodeChanged, setHasCodeChanged] = useState(false);
@@ -72,6 +74,11 @@ export default function Playground({code, height, autoFocus}: Props) {
? ({'--yg-playground-height': height} as React.CSSProperties)
: undefined;
const handleCodeChange = useCallback((code: string) => {
setHasCodeChanged(true);
setLiveCode(code);
}, []);
return (
<LiveProvider
code={liveCode}
@@ -86,13 +93,15 @@ export default function Playground({code, height, autoFocus}: Props) {
className={styles.editorToolbar}
style={{paddingRight: scrollbarWidth + 'px'}}
/>
<LiveEditor
className={clsx(styles.playgroundEditor)}
onChange={useCallback((code: string) => {
setHasCodeChanged(true);
setLiveCode(code);
}, [])}
/>
{isBrowser ? (
<LiveEditor
className={clsx(styles.playgroundEditor)}
onChange={handleCodeChange}
/>
) : (
<LiveEditorFallback code={liveCode} />
)}
</div>
</div>
<div className={clsx(styles.previewColumn)}>
@@ -105,6 +114,21 @@ export default function Playground({code, height, autoFocus}: Props) {
);
}
/**
* Provides a non-editable approximation of the LiveEditor result, without
* relying on prism rendering, for use during SSR.
* See https://github.com/facebook/docusaurus/issues/9629
*/
function LiveEditorFallback({code}: Readonly<{code: string}>) {
return (
<div className={clsx(styles.playgroundEditor)}>
<pre className={clsx('prism-code', styles.liveEditorFallback)}>
{code}
</pre>
</div>
);
}
type RootLiveNodeProps = Readonly<{
children: React.ReactNode;
config?: {useWebDefaults?: boolean};