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

@@ -9,12 +9,16 @@ html[data-theme='light'] {
--yg-color-preview-background: var(--ifm-color-primary-lighter);
--yg-color-playground-background: var(--ifm-color-gray-200);
--yg-color-editor-border: var(--ifm-color-gray-400);
--yg-color-editor-fallback-bg: rgb(246, 248, 250);
--yg-color-editor-fallback-text: rgb(0, 0, 159);
}
html[data-theme='dark'] {
--yg-color-preview-background: var(--ifm-color-primary-dark);
--yg-color-playground-background: var(--ifm-color-background);
--yg-color-editor-border: var(--ifm-color-gray-800);
--yg-color-editor-fallback-bg: rgb(40, 44, 52);
--yg-color-editor-fallback-text: rgb(209, 154, 102);
}
.wrapper {
@@ -47,8 +51,8 @@ html[data-theme='dark'] {
.editorToolbar {
position: absolute;
top: 10px;
right: 10px;
top: var(--ifm-pre-padding);
right: var(--ifm-pre-padding);
}
.playgroundEditor {
@@ -62,6 +66,12 @@ html[data-theme='dark'] {
box-shadow: var(--ifm-global-shadow-lw);
min-height: 100%;
border-radius: 0;
padding: var(--ifm-pre-padding) !important;
}
.liveEditorFallback {
background-color: var(--yg-color-editor-fallback-bg);
color: var(--yg-color-editor-fallback-text);
}
.previewColumn {

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};