From a450431a9b95a40af12e8b0dc0ad222955035a87 Mon Sep 17 00:00:00 2001 From: Narin Luangrath Date: Fri, 22 Jul 2022 16:06:29 -0700 Subject: [PATCH 01/19] chore(Highlight.js): fix --- src/components/Highlight.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Highlight.js b/src/components/Highlight.js index c14892f..a63c04d 100755 --- a/src/components/Highlight.js +++ b/src/components/Highlight.js @@ -16,6 +16,7 @@ import type { PrismLib, PrismTheme, PrismToken, + StyleObj, } from "../types"; type Props = { @@ -79,7 +80,7 @@ class Highlight extends Component { return output; }; - getStyleForToken = ({ types, empty }: Token) => { + getStyleForToken = ({ types, empty }: Token): StyleObj | void => { const typesSize = types.length; const themeDict = this.getThemeDict(this.props); @@ -92,7 +93,6 @@ class Highlight extends Component { } const baseStyle = empty ? { display: "inline-block" } : {}; - // $FlowFixMe const typeStyles = types.map((type) => themeDict[type]); return Object.assign(baseStyle, ...typeStyles); }; From f4d294a50e90a56c56af8faeb9b49f9c7fb60666 Mon Sep 17 00:00:00 2001 From: Narin Luangrath Date: Fri, 22 Jul 2022 17:33:44 -0700 Subject: [PATCH 02/19] improv(utils): add themeWithCssVariables function --- .../__tests__/themeWithCssVariables.test.js | 46 ++++++++++++++ src/utils/themeWithCssVariables.js | 63 +++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 src/utils/__tests__/themeWithCssVariables.test.js create mode 100644 src/utils/themeWithCssVariables.js diff --git a/src/utils/__tests__/themeWithCssVariables.test.js b/src/utils/__tests__/themeWithCssVariables.test.js new file mode 100644 index 0000000..844a274 --- /dev/null +++ b/src/utils/__tests__/themeWithCssVariables.test.js @@ -0,0 +1,46 @@ +import themeWithCssVariables from "../themeWithCssVariables"; + +describe("themeWithCssVariables", () => { + it("creates a visually equivalent theme with one type per style entry", () => { + const input = { + plain: { color: "red" }, + styles: [ + { + types: ["type1", "type2"], + style: { color: "green" }, + }, + { + types: ["type1"], + style: { fontWeight: "bold" }, + languages: "javascript", + }, + ], + }; + + const { theme, variables } = themeWithCssVariables(input); + expect(theme).toEqual({ + plain: { color: "var(--plain-color)" }, + styles: [ + { + types: ["type1"], + style: { color: "var(--type1-color)" }, + }, + { + types: ["type2"], + style: { color: "var(--type2-color)" }, + }, + { + types: ["type1"], + style: { fontWeight: "var(--type1-fontWeight)" }, + languages: "javascript", + }, + ], + }); + expect(variables).toEqual({ + "--plain-color": "red", + "--type1-color": "green", + "--type2-color": "green", + "--type1-fontWeight": "bold", + }); + }); +}); diff --git a/src/utils/themeWithCssVariables.js b/src/utils/themeWithCssVariables.js new file mode 100644 index 0000000..9479c1b --- /dev/null +++ b/src/utils/themeWithCssVariables.js @@ -0,0 +1,63 @@ +import { PrismTheme, StyleObj } from "../types"; + +/** + * Returns a new PrismTheme `t` that is visually equivalent + * to `theme` but `t.styles[i].types` always has length 1 + */ +const flattenThemeTypes = (theme: PrismTheme): PrismTheme => { + const { plain, styles } = theme; + + return { + plain: { ...plain }, + styles: styles.reduce((acc, x) => { + const { types, style, ...rest } = x; + const flatStyle = types.map((type) => ({ + types: [type], + style: { ...style }, + ...rest, + })); + acc.push(...flatStyle); + return acc; + }, []), + }; +}; + +/** + * Returns a PrismTheme that is visually equivalent to `theme` + * but with CSS Variables instead of fixed values (e.g. + * `var(--plain-color)` instead of `"#F8F8F2"`). + * + * Also returns a mapping from CSS Variable to value (i.e. an + * object with key `--plain-color` and value `"#F8F8F2"`) + */ +const themeWithCssVariables = ( + theme: PrismTheme +): { theme: PrismTheme, variables: StyleObj } => { + const flatTheme = flattenThemeTypes(theme); + const variables: StyleObj = {}; + + const { plain, styles } = flatTheme; + + Object.entries(plain).forEach(([key, value]) => { + const varName = `--plain-${key}`; + variables[varName] = value; + // Will not modify `theme` because `flattenThemeTypes` + // deep clones the original `theme` object + plain[key] = `var(${varName})`; + }); + + // `types` should have length 1 + styles.forEach(({ style, types }) => { + Object.entries(style).forEach(([key, value]) => { + const varName = `--${types[0]}-${key}`; + variables[varName] = value; + // Will not modify `theme` because `flattenThemeTypes` + // deep clones the original `theme` object + style[key] = `var(${varName})`; + }); + }); + + return { theme: flatTheme, variables }; +}; + +export default themeWithCssVariables; From 75c8cdf57eb77aef41b1958f07d62363642a1003 Mon Sep 17 00:00:00 2001 From: Narin Luangrath Date: Mon, 25 Jul 2022 22:24:28 -0700 Subject: [PATCH 03/19] improv(themeToDict.js): add optional third arg for root styles --- src/utils/__tests__/themeToDict.test.js | 15 +++++++++++++++ src/utils/themeToDict.js | 14 +++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/utils/__tests__/themeToDict.test.js b/src/utils/__tests__/themeToDict.test.js index 405473f..e0ffd00 100755 --- a/src/utils/__tests__/themeToDict.test.js +++ b/src/utils/__tests__/themeToDict.test.js @@ -72,4 +72,19 @@ describe("themeToDict", () => { expect(themeToDict(input, "ocaml").test).toEqual(undefined); }); + + it("passes along third argument to root styles", () => { + const input = { + plain: { + backgroundColor: "green", + }, + styles: [], + }; + const styleObj = { color: "red" }; + + expect(themeToDict(input, "js", styleObj).root).toEqual({ + backgroundColor: "green", + ...styleObj, + }); + }); }); diff --git a/src/utils/themeToDict.js b/src/utils/themeToDict.js index 07d463c..88daf91 100755 --- a/src/utils/themeToDict.js +++ b/src/utils/themeToDict.js @@ -8,7 +8,11 @@ export type ThemeDict = { [type: string]: StyleObj, }; -const themeToDict = (theme: PrismTheme, language: Language): ThemeDict => { +const themeToDict = ( + theme: PrismTheme, + language: Language, + rootStyles?: StyleObj +): ThemeDict => { const { plain } = theme; // $FlowFixMe @@ -22,16 +26,16 @@ const themeToDict = (theme: PrismTheme, language: Language): ThemeDict => { themeEntry.types.forEach((type) => { // $FlowFixMe - const accStyle: StyleObj = { ...acc[type], ...style }; - - acc[type] = accStyle; + acc[type] = { ...acc[type], ...style }; }); return acc; }, base); // $FlowFixMe - themeDict.root = (plain: StyleObj); + themeDict.root = ((rootStyles + ? { ...rootStyles, ...plain } + : plain): StyleObj); // $FlowFixMe themeDict.plain = ({ ...plain, backgroundColor: null }: StyleObj); From c659b2c267948a3de9704e967d85d0ce3f9e7513 Mon Sep 17 00:00:00 2001 From: Narin Luangrath Date: Mon, 25 Jul 2022 22:39:08 -0700 Subject: [PATCH 04/19] test(Highlight.test.js): add additional data attribute for raw style object --- src/components/__tests__/Highlight.test.js | 84 ++++++++++++------- .../__snapshots__/Highlight.test.js.snap | 46 ++++++++++ 2 files changed, 102 insertions(+), 28 deletions(-) diff --git a/src/components/__tests__/Highlight.test.js b/src/components/__tests__/Highlight.test.js index 060b85a..2af380d 100755 --- a/src/components/__tests__/Highlight.test.js +++ b/src/components/__tests__/Highlight.test.js @@ -13,6 +13,38 @@ const exampleCode = ` return () => ; `.trim(); +// The `data-style` properties are added because `react-test-renderer` +// will parse your style object into a string. However, CSS Variable +// references (e.g. color: var(--custom-color)) will be erased and +// hexadecimal colors (e.g. #000000) will be converted to rgb +// (e.g. rgb(0, 0, 0)). We don't want that. +const TestComponent = ({ + className, + style, + tokens, + getLineProps, + getTokenProps, +}) => ( +
+    {tokens.map((line, i) => {
+      const lineProps = getLineProps({ line, key: i });
+      return (
+        
+ {line.map((token, key) => { + const tokenProps = getTokenProps({ token, key }); + return ( + + ); + })} +
+ ); + })} +
+); + describe("", () => { afterEach(cleanup); @@ -21,15 +53,13 @@ describe("", () => { const { container } = render( {({ className, style, tokens, getLineProps, getTokenProps }) => ( -
-              {tokens.map((line, i) => (
-                
- {line.map((token, key) => ( - - ))} -
- ))} -
+ )}
); @@ -45,15 +75,13 @@ describe("", () => { language="abcdefghijklmnop" > {({ className, style, tokens, getLineProps, getTokenProps }) => ( -
-              {tokens.map((line, i) => (
-                
- {line.map((token, key) => ( - - ))} -
- ))} -
+ )}
); @@ -70,20 +98,20 @@ describe("", () => { language="jsx" > {({ className, style, tokens, getLineProps, getTokenProps }) => ( -
-              {tokens.map((line, i) => (
-                
- {line.map((token, key) => ( - - ))} -
- ))} -
+ )}
); - expect(container.innerHTML.includes("style")).toBeFalsy(); + expect(container.querySelector("pre[style]")).toBeFalsy(); // Root + expect(container.querySelector("div[style]")).toBeFalsy(); // Lines + expect(container.querySelector("span[style]")).toBeFalsy(); // Tokens }); }); diff --git a/src/components/__tests__/__snapshots__/Highlight.test.js.snap b/src/components/__tests__/__snapshots__/Highlight.test.js.snap index fa0b8ca..8e985fa 100644 --- a/src/components/__tests__/__snapshots__/Highlight.test.js.snap +++ b/src/components/__tests__/__snapshots__/Highlight.test.js.snap @@ -4,20 +4,24 @@ exports[` snapshots renders correctly 1`] = `
     
( function @@ -29,18 +33,21 @@ exports[` snapshots renders correctly 1`] = ` someDemo ( ) @@ -52,6 +59,7 @@ exports[` snapshots renders correctly 1`] = ` { @@ -62,6 +70,7 @@ exports[` snapshots renders correctly 1`] = `
snapshots renders correctly 1`] = ` var @@ -82,6 +92,7 @@ exports[` snapshots renders correctly 1`] = ` = @@ -93,12 +104,14 @@ exports[` snapshots renders correctly 1`] = ` "Hello World!" ; @@ -109,6 +122,7 @@ exports[` snapshots renders correctly 1`] = `
snapshots renders correctly 1`] = ` console . log ( @@ -146,12 +164,14 @@ exports[` snapshots renders correctly 1`] = ` ) ; @@ -162,6 +182,7 @@ exports[` snapshots renders correctly 1`] = `
snapshots renders correctly 1`] = ` /> } ) ( ) ; @@ -203,10 +229,12 @@ exports[` snapshots renders correctly 1`] = `
@@ -215,6 +243,7 @@ exports[` snapshots renders correctly 1`] = `
snapshots renders correctly 1`] = ` /> return @@ -233,12 +263,14 @@ exports[` snapshots renders correctly 1`] = ` ( ) @@ -250,6 +282,7 @@ exports[` snapshots renders correctly 1`] = ` => @@ -261,30 +294,35 @@ exports[` snapshots renders correctly 1`] = ` < App /> ; @@ -298,10 +336,12 @@ exports[` snapshots renders unsupported languages correctly 1`] = `
     
snapshots renders unsupported languages correctly 1`] = `
snapshots renders unsupported languages correctly 1`] = `
snapshots renders unsupported languages correctly 1`] = `
snapshots renders unsupported languages correctly 1`] = `
@@ -354,6 +399,7 @@ exports[` snapshots renders unsupported languages correctly 1`] = `
Date: Tue, 26 Jul 2022 10:18:56 -0700 Subject: [PATCH 05/19] fix(themeToDict.js): got messed up by prettier --- src/utils/themeToDict.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/utils/themeToDict.js b/src/utils/themeToDict.js index 88daf91..7d78890 100755 --- a/src/utils/themeToDict.js +++ b/src/utils/themeToDict.js @@ -34,8 +34,10 @@ const themeToDict = ( // $FlowFixMe themeDict.root = ((rootStyles - ? { ...rootStyles, ...plain } - : plain): StyleObj); + ? // $FlowFixMe + { ...rootStyles, ...plain } + : // $FlowFixMe + plain): StyleObj); // $FlowFixMe themeDict.plain = ({ ...plain, backgroundColor: null }: StyleObj); From fe5f39012106ccbc4aa53ad10567a9f4fa9a8e7b Mon Sep 17 00:00:00 2001 From: Narin Luangrath Date: Tue, 26 Jul 2022 10:26:31 -0700 Subject: [PATCH 06/19] refactor(Highlight.js): use css variables as placeholders --- src/components/Highlight.js | 12 +- .../__snapshots__/Highlight.test.js.snap | 131 ++++++------------ 2 files changed, 53 insertions(+), 90 deletions(-) diff --git a/src/components/Highlight.js b/src/components/Highlight.js index a63c04d..5bf5bab 100755 --- a/src/components/Highlight.js +++ b/src/components/Highlight.js @@ -3,6 +3,7 @@ import React, { Component, type Node } from "react"; import normalizeTokens from "../utils/normalizeTokens"; import themeToDict, { type ThemeDict } from "../utils/themeToDict"; +import themeWithCssVariables from "../utils/themeWithCssVariables"; import type { Language, @@ -43,10 +44,13 @@ class Highlight extends Component { this.prevTheme = props.theme; this.prevLanguage = props.language; - - const themeDict = props.theme - ? themeToDict(props.theme, props.language) - : undefined; + let themeDict; + if (props.theme) { + // Replace CSS Values with CSS Variable placeholders + // This is necessary for SSR support + const { theme, variables } = themeWithCssVariables(props.theme); + themeDict = themeToDict(theme, props.language, variables); + } return (this.themeDict = themeDict); }; diff --git a/src/components/__tests__/__snapshots__/Highlight.test.js.snap b/src/components/__tests__/__snapshots__/Highlight.test.js.snap index 8e985fa..9f246b5 100644 --- a/src/components/__tests__/__snapshots__/Highlight.test.js.snap +++ b/src/components/__tests__/__snapshots__/Highlight.test.js.snap @@ -4,25 +4,22 @@ exports[` snapshots renders correctly 1`] = `
     
( function @@ -33,22 +30,19 @@ exports[` snapshots renders correctly 1`] = ` someDemo ( ) @@ -59,8 +53,7 @@ exports[` snapshots renders correctly 1`] = ` { @@ -70,8 +63,7 @@ exports[` snapshots renders correctly 1`] = `
snapshots renders correctly 1`] = ` var @@ -92,8 +83,7 @@ exports[` snapshots renders correctly 1`] = ` = @@ -104,15 +94,13 @@ exports[` snapshots renders correctly 1`] = ` "Hello World!" ; @@ -122,8 +110,7 @@ exports[` snapshots renders correctly 1`] = `
snapshots renders correctly 1`] = ` . log ( @@ -164,15 +148,13 @@ exports[` snapshots renders correctly 1`] = ` ) ; @@ -182,44 +164,38 @@ exports[` snapshots renders correctly 1`] = `
} ) ( ) ; @@ -229,8 +205,7 @@ exports[` snapshots renders correctly 1`] = `
snapshots renders correctly 1`] = `
return @@ -263,15 +236,13 @@ exports[` snapshots renders correctly 1`] = ` ( ) @@ -282,8 +253,7 @@ exports[` snapshots renders correctly 1`] = ` => @@ -294,36 +264,31 @@ exports[` snapshots renders correctly 1`] = ` < App /> ; @@ -336,13 +301,12 @@ exports[` snapshots renders unsupported languages correctly 1`] = `
     
snapshots renders unsupported languages correctly 1`] = `
snapshots renders unsupported languages correctly 1`] = `
snapshots renders unsupported languages correctly 1`] = `
snapshots renders unsupported languages correctly 1`] = `
snapshots renders unsupported languages correctly 1`] = `
Date: Tue, 26 Jul 2022 15:17:33 -0700 Subject: [PATCH 07/19] improv: add id field to PrismTheme type --- src/themes/dracula.js | 1 + src/themes/duotoneDark.js | 1 + src/themes/duotoneLight.js | 1 + src/themes/github.js | 1 + src/themes/nightOwl.js | 1 + src/themes/nightOwlLight.js | 1 + src/themes/oceanicNext.js | 1 + src/themes/okaidia.js | 1 + src/themes/palenight.js | 1 + src/themes/shadesOfPurple.js | 1 + src/themes/synthwave84.js | 1 + src/themes/ultramin.js | 1 + src/themes/vsDark.js | 1 + src/themes/vsLight.js | 1 + src/types.js | 1 + src/utils/themeWithCssVariables.js | 3 ++- tools/themeFromVsCode/README.md | 1 + tools/themeFromVsCode/src/index.js | 1 + 18 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/themes/dracula.js b/src/themes/dracula.js index 0e75bab..32f6dec 100755 --- a/src/themes/dracula.js +++ b/src/themes/dracula.js @@ -5,6 +5,7 @@ import type { PrismTheme } from "../types"; var theme: PrismTheme = { + id: "dracula", plain: { color: "#F8F8F2", backgroundColor: "#282A36", diff --git a/src/themes/duotoneDark.js b/src/themes/duotoneDark.js index 7c2e441..46e10dc 100755 --- a/src/themes/duotoneDark.js +++ b/src/themes/duotoneDark.js @@ -7,6 +7,7 @@ import type { PrismTheme } from "../types"; var theme: PrismTheme = { + id: "duotoneDark", plain: { backgroundColor: "#2a2734", color: "#9a86fd", diff --git a/src/themes/duotoneLight.js b/src/themes/duotoneLight.js index a9ea232..3486da1 100755 --- a/src/themes/duotoneLight.js +++ b/src/themes/duotoneLight.js @@ -7,6 +7,7 @@ import type { PrismTheme } from "../types"; var theme: PrismTheme = { + id: "duotoneLight", plain: { backgroundColor: "#faf8f5", color: "#728fcb", diff --git a/src/themes/github.js b/src/themes/github.js index fff27f2..cba7916 100644 --- a/src/themes/github.js +++ b/src/themes/github.js @@ -4,6 +4,7 @@ import type { PrismTheme } from "../types"; var theme: PrismTheme = { + id: "github", plain: { color: "#393A34", backgroundColor: "#f6f8fa", diff --git a/src/themes/nightOwl.js b/src/themes/nightOwl.js index 2aa84e1..bd7c104 100755 --- a/src/themes/nightOwl.js +++ b/src/themes/nightOwl.js @@ -5,6 +5,7 @@ import type { PrismTheme } from "../types"; var theme: PrismTheme = { + id: "nightOwl", plain: { color: "#d6deeb", backgroundColor: "#011627", diff --git a/src/themes/nightOwlLight.js b/src/themes/nightOwlLight.js index f6bc4de..22d98d4 100644 --- a/src/themes/nightOwlLight.js +++ b/src/themes/nightOwlLight.js @@ -5,6 +5,7 @@ import type { PrismTheme } from "../types"; var theme: PrismTheme = { + id: "nightOwlLight", plain: { color: "#403f53", backgroundColor: "#FBFBFB", diff --git a/src/themes/oceanicNext.js b/src/themes/oceanicNext.js index 025fe72..2efb78f 100755 --- a/src/themes/oceanicNext.js +++ b/src/themes/oceanicNext.js @@ -23,6 +23,7 @@ var colors = { }; var theme: PrismTheme = { + id: "oceanicNext", plain: { backgroundColor: "#282c34", color: "#ffffff", diff --git a/src/themes/okaidia.js b/src/themes/okaidia.js index e9cf183..d935e36 100644 --- a/src/themes/okaidia.js +++ b/src/themes/okaidia.js @@ -7,6 +7,7 @@ import type { PrismTheme } from "../types"; var theme: PrismTheme = { + id: "okaidia", plain: { color: "#f8f8f2", backgroundColor: "#272822", diff --git a/src/themes/palenight.js b/src/themes/palenight.js index caa8323..97d7c2d 100644 --- a/src/themes/palenight.js +++ b/src/themes/palenight.js @@ -4,6 +4,7 @@ import type { PrismTheme } from "../types"; var theme: PrismTheme = { + id: "palenight", plain: { color: "#bfc7d5", backgroundColor: "#292d3e", diff --git a/src/themes/shadesOfPurple.js b/src/themes/shadesOfPurple.js index 0fde229..f8c5813 100644 --- a/src/themes/shadesOfPurple.js +++ b/src/themes/shadesOfPurple.js @@ -7,6 +7,7 @@ import type { PrismTheme } from "../types"; var theme: PrismTheme = { + id: "shadesOfPurple", plain: { color: "#9EFEFF", backgroundColor: "#2D2A55", diff --git a/src/themes/synthwave84.js b/src/themes/synthwave84.js index b583b11..a234a36 100644 --- a/src/themes/synthwave84.js +++ b/src/themes/synthwave84.js @@ -8,6 +8,7 @@ import type { PrismTheme } from "../types"; var theme: PrismTheme = { + id: "synthwave84", plain: { background: "#2a2139", backgroundColor: "linear-gradient(to bottom, #2a2139 75%, #34294f)", diff --git a/src/themes/ultramin.js b/src/themes/ultramin.js index 5d124f5..f6b48a6 100755 --- a/src/themes/ultramin.js +++ b/src/themes/ultramin.js @@ -5,6 +5,7 @@ import type { PrismTheme } from "../types"; var theme: PrismTheme = { + id: "ultramin", plain: { color: "#282a2e", backgroundColor: "#ffffff", diff --git a/src/themes/vsDark.js b/src/themes/vsDark.js index 7cd61bb..6e14f6e 100644 --- a/src/themes/vsDark.js +++ b/src/themes/vsDark.js @@ -4,6 +4,7 @@ import type { PrismTheme } from "../types"; var theme: PrismTheme = { + id: "vsDark", plain: { color: "#9CDCFE", backgroundColor: "#1E1E1E", diff --git a/src/themes/vsLight.js b/src/themes/vsLight.js index 0f2a799..c13b832 100644 --- a/src/themes/vsLight.js +++ b/src/themes/vsLight.js @@ -4,6 +4,7 @@ import type { PrismTheme } from "../types"; var theme: PrismTheme = { + id: "vsLight", plain: { color: "#000000", backgroundColor: "#ffffff", diff --git a/src/types.js b/src/types.js index f1a4d13..a438fe0 100755 --- a/src/types.js +++ b/src/types.js @@ -113,6 +113,7 @@ export type PrismThemeEntry = { }; export type PrismTheme = { + id?: string, plain: PrismThemeEntry, styles: Array<{ types: string[], diff --git a/src/utils/themeWithCssVariables.js b/src/utils/themeWithCssVariables.js index 9479c1b..49091ea 100644 --- a/src/utils/themeWithCssVariables.js +++ b/src/utils/themeWithCssVariables.js @@ -5,9 +5,10 @@ import { PrismTheme, StyleObj } from "../types"; * to `theme` but `t.styles[i].types` always has length 1 */ const flattenThemeTypes = (theme: PrismTheme): PrismTheme => { - const { plain, styles } = theme; + const { plain, styles, id } = theme; return { + id, plain: { ...plain }, styles: styles.reduce((acc, x) => { const { types, style, ...rest } = x; diff --git a/tools/themeFromVsCode/README.md b/tools/themeFromVsCode/README.md index e7ce730..38804bc 100644 --- a/tools/themeFromVsCode/README.md +++ b/tools/themeFromVsCode/README.md @@ -3,3 +3,4 @@ 1. Open this directory and run `npm install` 2. Save your VSCode theme in a file called `theme.json` in this directory (`ctrl`/`cmd` + `shift` + `p` -> `Developer: Generate Color Theme From Current Settings`) 3. Run `npm start` and your theme will be created in a file called `outputTheme.js` (inside root same as the `README.md` file) +4. (SSR only) Edit the `id` attribute of the generated theme. \ No newline at end of file diff --git a/tools/themeFromVsCode/src/index.js b/tools/themeFromVsCode/src/index.js index 8e83470..0e47fae 100755 --- a/tools/themeFromVsCode/src/index.js +++ b/tools/themeFromVsCode/src/index.js @@ -10,6 +10,7 @@ const theme = JSON5.parse(themeString); const prismTheme = collectAllSettings(theme.tokenColors); const json = { + id: '@TODO', plain: { color: theme.colors['editor.foreground'], backgroundColor: theme.colors['editor.background'], From aff1614ab7461ceaa9d8991153ff7a9fc9e99a2a Mon Sep 17 00:00:00 2001 From: Narin Luangrath Date: Tue, 26 Jul 2022 15:49:00 -0700 Subject: [PATCH 08/19] feat: add SSR / FOUC support --- README.md | 27 +++++ src/components/Highlight.js | 16 ++- src/index.js | 3 +- .../__tests__/generateScriptForSSR.test.js | 100 ++++++++++++++++++ src/utils/generateScriptForSSR.js | 33 ++++++ 5 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 src/utils/__tests__/generateScriptForSSR.test.js create mode 100644 src/utils/generateScriptForSSR.js diff --git a/README.md b/README.md index e463524..1284717 100755 --- a/README.md +++ b/README.md @@ -391,6 +391,33 @@ property limits styles to highlighted languages. When converting a Prism CSS theme it's mostly just necessary to use classes as `types` and convert the declarations to object-style-syntax and put them on `style`. +### SSR Support / Avoiding FOUC + +If your React app supports "light mode / dark mode" you need to do additional work to avoid a flash of unstyled content (FOUC). Generate the following script tag and inject it into your HTML so it runs _before_ your content loads. + +```js +import { generateScriptForSSR } from 'prism-react-renderer' +import duotoneDark from 'prism-react-renderer/themes/duotoneDark'; +import duotoneLight from 'prism-react-renderer/themes/duotoneLight'; + +// Gatsby +export const onRenderBody = ({ setPreBodyComponents }) => { + // A stringified function returning the `id` of the + // theme you wish to render on the initial page load + const getThemeIdFuncStr = ` + () => window.localStorage.get('color-mode') || 'duotoneLight' + `.trim() + + const codeToRunOnClient = generateScriptForSSR( + [duotoneDark, duotonLight], // Include whatever themes `getThemeIdFuncStr` might return + getThemeIdFuncStr + ) + setPreBodyComponents(