Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix FOUC of Prism Theme #7867

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
14 changes: 13 additions & 1 deletion packages/docusaurus-theme-classic/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import path from 'path';
import {createRequire} from 'module';
import rtlcss from 'rtlcss';
import {readDefaultCodeTranslationMessages} from '@docusaurus/theme-translations';
import {generateScriptForSSR} from 'prism-react-renderer';
import {getTranslationFiles, translateThemeConfig} from './translations';
import type {LoadContext, Plugin} from '@docusaurus/types';
import type {ThemeConfig} from '@docusaurus/theme-common';
Expand Down Expand Up @@ -107,7 +108,7 @@ export default function themeClassic(
const {
announcementBar,
colorMode,
prism: {additionalLanguages},
prism: {additionalLanguages, theme, darkTheme},
} = themeConfig;
const {customCss} = options;
const {direction} = localeConfigs[currentLocale]!;
Expand Down Expand Up @@ -198,6 +199,17 @@ ${noFlashColorMode(colorMode)}
${announcementBar ? AnnouncementBarInlineJavaScript : ''}
`,
},
{
tagName: 'script',
innerHTML: generateScriptForSSR(
[theme, darkTheme],
`() => (
document.documentElement.getAttribute('data-theme') === 'dark'
? '${darkTheme.id}'
: '${theme.id}'
)`,
),
},
],
};
},
Expand Down
3 changes: 3 additions & 0 deletions packages/docusaurus-theme-classic/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const DEFAULT_CONFIG: ThemeConfig = {
prism: {
additionalLanguages: [],
theme: defaultPrismTheme,
darkTheme: defaultPrismTheme,
magicComments: [
{
className: 'theme-code-block-highlighted-line',
Expand Down Expand Up @@ -377,10 +378,12 @@ export const ThemeConfigSchema = Joi.object<ThemeConfig>({
}).optional(),
prism: Joi.object({
theme: Joi.object({
id: Joi.string(),
plain: Joi.alternatives().try(Joi.array(), Joi.object()).required(),
styles: Joi.alternatives().try(Joi.array(), Joi.object()).required(),
}).default(DEFAULT_CONFIG.prism.theme),
darkTheme: Joi.object({
id: Joi.string(),
plain: Joi.alternatives().try(Joi.array(), Joi.object()).required(),
styles: Joi.alternatives().try(Joi.array(), Joi.object()).required(),
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,17 @@

import React, {type ComponentProps} from 'react';
import clsx from 'clsx';
import {ThemeClassNames, usePrismTheme} from '@docusaurus/theme-common';
import {getPrismCssVariables} from '@docusaurus/theme-common/internal';
import {ThemeClassNames} from '@docusaurus/theme-common';
import styles from './styles.module.css';

export default function CodeBlockContainer<T extends 'div' | 'pre'>({
as: As,
...props
}: {as: T} & ComponentProps<T>): JSX.Element {
const prismTheme = usePrismTheme();
const prismCssVariables = getPrismCssVariables(prismTheme);
return (
<As
// Polymorphic components are hard to type, without `oneOf` generics
{...(props as any)}
style={prismCssVariables}
className={clsx(
props.className,
styles.codeBlockContainer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,12 @@ export default function CodeBlockString({
theme={prismTheme}
code={code}
language={(language ?? 'text') as Language}>
{({className, tokens, getLineProps, getTokenProps}) => (
{({className, tokens, getLineProps, getTokenProps, style}) => (
<pre
/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
tabIndex={0}
ref={wordWrap.codeBlockRef}
style={style}
className={clsx(className, styles.codeBlock, 'thin-scrollbar')}>
<code
className={clsx(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
*/

import React, {isValidElement, type ReactNode} from 'react';
import useIsBrowser from '@docusaurus/useIsBrowser';
import ElementContent from '@theme/CodeBlock/Content/Element';
import StringContent from '@theme/CodeBlock/Content/String';
import type {Props} from '@theme/CodeBlock';
Expand All @@ -29,17 +28,8 @@ export default function CodeBlock({
children: rawChildren,
...props
}: Props): JSX.Element {
// The Prism theme on SSR is always the default theme but the site theme can
// be in a different mode. React hydration doesn't update DOM styles that come
// from SSR. Hence force a re-render after mounting to apply the current
// relevant styles.
const isBrowser = useIsBrowser();
const children = maybeStringifyChildren(rawChildren);
const CodeBlockComp =
typeof children === 'string' ? StringContent : ElementContent;
return (
<CodeBlockComp key={String(isBrowser)} {...props}>
{children as string}
</CodeBlockComp>
);
return <CodeBlockComp {...props}>{children as string}</CodeBlockComp>;
}
1 change: 0 additions & 1 deletion packages/docusaurus-theme-common/src/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,4 @@ export {useLockBodyScroll} from './hooks/useLockBodyScroll';
export {useSearchPage} from './hooks/useSearchPage';
export {useCodeWordWrap} from './hooks/useCodeWordWrap';
export {useSkipToContent} from './hooks/useSkipToContent';
export {getPrismCssVariables} from './utils/codeBlockUtils';
export {useBackToTopButton} from './hooks/useBackToTopButton';
18 changes: 0 additions & 18 deletions packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/

import type {CSSProperties} from 'react';
import rangeParser from 'parse-numeric-range';
import type {PrismTheme} from 'prism-react-renderer';

const codeBlockTitleRegex = /title=(?<quote>["'])(?<title>.*?)\1/;
const metastringLinesRangeRegex = /\{(?<range>[\d,-]+)\}/;
Expand Down Expand Up @@ -233,19 +231,3 @@ export function parseLines(
});
return {lineClassNames, code};
}

export function getPrismCssVariables(prismTheme: PrismTheme): CSSProperties {
const mapping: {[name: keyof PrismTheme['plain']]: string} = {
color: '--prism-color',
backgroundColor: '--prism-background-color',
};

const properties: {[key: string]: string} = {};
Object.entries(prismTheme.plain).forEach(([key, value]) => {
const varName = mapping[key];
if (varName && typeof value === 'string') {
properties[varName] = value;
}
});
return properties;
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export type AnnouncementBarConfig = {

export type PrismConfig = {
theme: PrismTheme;
darkTheme?: PrismTheme;
darkTheme: PrismTheme;
defaultLanguage?: string;
additionalLanguages: string[];
magicComments: MagicCommentConfig[];
Expand Down
1 change: 1 addition & 0 deletions website/src/utils/prismDark.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import darkTheme from 'prism-react-renderer/themes/vsDark/index.cjs.js';

export default {
id: 'prismDark',
plain: {
color: '#D4D4D4',
backgroundColor: '#212121',
Expand Down