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:
committed by
Facebook GitHub Bot
parent
3f6f04cb92
commit
2caa8ac8cb
@@ -9,12 +9,16 @@ html[data-theme='light'] {
|
|||||||
--yg-color-preview-background: var(--ifm-color-primary-lighter);
|
--yg-color-preview-background: var(--ifm-color-primary-lighter);
|
||||||
--yg-color-playground-background: var(--ifm-color-gray-200);
|
--yg-color-playground-background: var(--ifm-color-gray-200);
|
||||||
--yg-color-editor-border: var(--ifm-color-gray-400);
|
--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'] {
|
html[data-theme='dark'] {
|
||||||
--yg-color-preview-background: var(--ifm-color-primary-dark);
|
--yg-color-preview-background: var(--ifm-color-primary-dark);
|
||||||
--yg-color-playground-background: var(--ifm-color-background);
|
--yg-color-playground-background: var(--ifm-color-background);
|
||||||
--yg-color-editor-border: var(--ifm-color-gray-800);
|
--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 {
|
.wrapper {
|
||||||
@@ -47,8 +51,8 @@ html[data-theme='dark'] {
|
|||||||
|
|
||||||
.editorToolbar {
|
.editorToolbar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 10px;
|
top: var(--ifm-pre-padding);
|
||||||
right: 10px;
|
right: var(--ifm-pre-padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
.playgroundEditor {
|
.playgroundEditor {
|
||||||
@@ -62,6 +66,12 @@ html[data-theme='dark'] {
|
|||||||
box-shadow: var(--ifm-global-shadow-lw);
|
box-shadow: var(--ifm-global-shadow-lw);
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
border-radius: 0;
|
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 {
|
.previewColumn {
|
||||||
|
@@ -27,6 +27,7 @@ import type {FlexStyle} from './FlexStyle';
|
|||||||
import type {StyleNode} from './YogaViewer';
|
import type {StyleNode} from './YogaViewer';
|
||||||
|
|
||||||
import styles from './Playground.module.css';
|
import styles from './Playground.module.css';
|
||||||
|
import useIsBrowser from '@docusaurus/useIsBrowser';
|
||||||
|
|
||||||
export type Props = Readonly<{
|
export type Props = Readonly<{
|
||||||
code: string;
|
code: string;
|
||||||
@@ -37,6 +38,7 @@ export type Props = Readonly<{
|
|||||||
export default function Playground({code, height, autoFocus}: Props) {
|
export default function Playground({code, height, autoFocus}: Props) {
|
||||||
const prismTheme = usePrismTheme();
|
const prismTheme = usePrismTheme();
|
||||||
const editorScrollRef = useRef<HTMLDivElement>(null);
|
const editorScrollRef = useRef<HTMLDivElement>(null);
|
||||||
|
const isBrowser = useIsBrowser();
|
||||||
|
|
||||||
const [liveCode, setLiveCode] = useState(code);
|
const [liveCode, setLiveCode] = useState(code);
|
||||||
const [hasCodeChanged, setHasCodeChanged] = useState(false);
|
const [hasCodeChanged, setHasCodeChanged] = useState(false);
|
||||||
@@ -72,6 +74,11 @@ export default function Playground({code, height, autoFocus}: Props) {
|
|||||||
? ({'--yg-playground-height': height} as React.CSSProperties)
|
? ({'--yg-playground-height': height} as React.CSSProperties)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
const handleCodeChange = useCallback((code: string) => {
|
||||||
|
setHasCodeChanged(true);
|
||||||
|
setLiveCode(code);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LiveProvider
|
<LiveProvider
|
||||||
code={liveCode}
|
code={liveCode}
|
||||||
@@ -86,13 +93,15 @@ export default function Playground({code, height, autoFocus}: Props) {
|
|||||||
className={styles.editorToolbar}
|
className={styles.editorToolbar}
|
||||||
style={{paddingRight: scrollbarWidth + 'px'}}
|
style={{paddingRight: scrollbarWidth + 'px'}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{isBrowser ? (
|
||||||
<LiveEditor
|
<LiveEditor
|
||||||
className={clsx(styles.playgroundEditor)}
|
className={clsx(styles.playgroundEditor)}
|
||||||
onChange={useCallback((code: string) => {
|
onChange={handleCodeChange}
|
||||||
setHasCodeChanged(true);
|
|
||||||
setLiveCode(code);
|
|
||||||
}, [])}
|
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<LiveEditorFallback code={liveCode} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={clsx(styles.previewColumn)}>
|
<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<{
|
type RootLiveNodeProps = Readonly<{
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
config?: {useWebDefaults?: boolean};
|
config?: {useWebDefaults?: boolean};
|
||||||
|
Reference in New Issue
Block a user