Skip to content

Commit 2fecd59

Browse files
authored
feat(docs): fix theme flicker (#4271)
* feat(desgn-tokens): build a data-theme css file * feat(css-theme): add the index file for theme * feat(css-theme): add the index file for theme * feat(css-theme): added tests and working * chore(ci): changeset * feat(docs): added prop to theme provider table * chore(ci): lint fix * chore(ci): lint fix * feat(docs): implement fix with CSS variables * fix(docs): build
1 parent b5e73f1 commit 2fecd59

File tree

8 files changed

+51
-12
lines changed

8 files changed

+51
-12
lines changed

packages/paste-website/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@
175175
"micromark-extension-mdxjs": "^2.0.0",
176176
"minimist": "^1.2.8",
177177
"next": "^14.0.0",
178+
"nookies": "^2.5.2",
178179
"openai": "^4.79.1",
179180
"pretty-format": "^28.1.0",
180181
"prism-react-renderer": "^1.3.5",

packages/paste-website/src/components/color-swatch/ColorGradient.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export const ColorGradient: React.FC<
6565
> = ({ aliasPrefix, makeTall = "false", index = 0 }) => {
6666
const [show, setShow] = React.useState(false);
6767
const { theme } = useDarkModeContext();
68-
const aliasValues = getAliasValuesFromPrefix(aliasPrefix, theme);
68+
const aliasValues = getAliasValuesFromPrefix(aliasPrefix, theme || "twilio");
6969
const count = aliasValues.length - 1;
7070

7171
function handleVisibilityChange(isVisible: boolean): void {

packages/paste-website/src/components/shortcodes/live-preview/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ const LivePreview: React.FC<React.PropsWithChildren<LivePreviewProps>> = ({
4949

5050
const overflow = showOverflow ? "visible" : "auto";
5151

52+
if (!previewTheme) return null;
53+
5254
return (
5355
<Box marginBottom="space110" data-cy="live-preview">
5456
<LiveProvider

packages/paste-website/src/context/PreviewThemeContext.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from "react";
22

33
type PreviewThemeContextValue = {
4-
theme: string;
4+
theme?: string;
55
selectTheme: (theme: string) => void;
66
};
77

packages/paste-website/src/hooks/useDarkMode.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import type { ValueOf } from "@twilio-paste/types";
2+
import { parseCookies, setCookie } from "nookies";
23
import * as React from "react";
34

4-
import { SimpleStorage } from "../utils/SimpleStorage";
5-
6-
export type UseDarkModeReturn = [ValidThemeName, () => void, boolean];
5+
export type UseDarkModeReturn = [ValidThemeName | undefined, () => void, boolean];
76

87
const ValidThemes = {
98
DEFAULT: "twilio",
@@ -13,15 +12,16 @@ const ValidThemes = {
1312
type ValidThemeName = ValueOf<typeof ValidThemes>;
1413

1514
const isValidTheme = (themeName: ValidThemeName): boolean => {
16-
return themeName === ValidThemes.DEFAULT || themeName === ValidThemes.DARK;
15+
return Object.values(ValidThemes).includes(themeName);
1716
};
1817

1918
export const useDarkMode = (): UseDarkModeReturn => {
20-
const [theme, setTheme] = React.useState<ValidThemeName>(ValidThemes.DEFAULT);
19+
const [theme, setTheme] = React.useState<ValidThemeName>();
2120
const [componentMounted, setComponentMounted] = React.useState(false);
2221

2322
const setMode = (mode: ValidThemeName): void => {
24-
SimpleStorage.set("theme", mode);
23+
setCookie(null, "paste-docs-theme", mode, { path: "/" });
24+
document.body.dataset.theme = mode;
2525
setTheme(mode);
2626
};
2727

@@ -34,7 +34,7 @@ export const useDarkMode = (): UseDarkModeReturn => {
3434
};
3535

3636
React.useEffect(() => {
37-
const localTheme = SimpleStorage.get("theme") as ValidThemeName;
37+
const localTheme = parseCookies()["paste-docs-theme"] as ValidThemeName;
3838

3939
if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches && !localTheme) {
4040
setMode(ValidThemes.DARK);

packages/paste-website/src/pages/_app.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { datadogRum } from "@datadog/browser-rum";
2+
import "@twilio-paste/design-tokens/dist/themes/twilio-dark/tokens.data-theme.css";
3+
import "@twilio-paste/design-tokens/dist/themes/twilio/tokens.custom-properties.css";
24
import { Theme } from "@twilio-paste/theme";
35
import type { AppProps } from "next/app";
46
import Head from "next/head";
@@ -22,7 +24,7 @@ const App = ({ Component, pageProps }: AppProps): React.ReactElement => {
2224
const router = useRouter();
2325
const localStorageKey = "cookie-consent-accepted";
2426
const [theme, toggleMode, componentMounted] = useDarkMode();
25-
const [previewTheme, setPreviewTheme] = React.useState("twilio");
27+
const [previewTheme, setPreviewTheme] = React.useState<string | undefined>();
2628
const [cookiesAccepted, setCookiesAccepted] = React.useState<null | string>();
2729

2830
React.useEffect(() => {
@@ -111,7 +113,7 @@ const App = ({ Component, pageProps }: AppProps): React.ReactElement => {
111113
</>
112114
)}
113115
<Theme.Provider
114-
theme={theme}
116+
useCSSVariables={true}
115117
customBreakpoints={SITE_BREAKPOINTS}
116118
disableAnimations={inCypress()}
117119
cacheProviderProps={{ key: "next" }}

packages/paste-website/src/pages/_document.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,22 @@ class _Document extends Document {
3333
<link rel="apple-touch-icon" sizes="512x512" href="/icons/icon-512x512.png" />
3434
</Head>
3535
<body>
36+
<script
37+
type="text/javascript"
38+
// eslint-disable-next-line react/no-danger
39+
dangerouslySetInnerHTML={{
40+
__html: `
41+
let parts = typeof document !== "undefined" && document?.cookie.split("paste-docs-theme=");
42+
let cookie = parts.length == 2 ?parts?.pop().split(";").shift() : null;
43+
if(cookie){
44+
document.body.dataset.theme = cookie;
45+
}
46+
else if(window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches){
47+
document.body.dataset.theme = "twilio-dark";
48+
}
49+
`,
50+
}}
51+
/>
3652
<noscript key="noscript">This app works best with JavaScript enabled.</noscript>
3753
<Main />
3854
<NextScript />

yarn.lock

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16312,6 +16312,7 @@ __metadata:
1631216312
micromark-extension-mdxjs: ^2.0.0
1631316313
minimist: ^1.2.8
1631416314
next: ^14.0.0
16315+
nookies: ^2.5.2
1631516316
openai: ^4.79.1
1631616317
pretty-format: ^28.1.0
1631716318
prism-react-renderer: ^1.3.5
@@ -22379,7 +22380,7 @@ __metadata:
2237922380
languageName: node
2238022381
linkType: hard
2238122382

22382-
"cookie@npm:~0.4.1":
22383+
"cookie@npm:^0.4.1, cookie@npm:~0.4.1":
2238322384
version: 0.4.2
2238422385
resolution: "cookie@npm:0.4.2"
2238522386
checksum: a00833c998bedf8e787b4c342defe5fa419abd96b32f4464f718b91022586b8f1bafbddd499288e75c037642493c83083da426c6a9080d309e3bd90fd11baa9b
@@ -35778,6 +35779,16 @@ fsevents@^1.2.7:
3577835779
languageName: node
3577935780
linkType: hard
3578035781

35782+
"nookies@npm:^2.5.2":
35783+
version: 2.5.2
35784+
resolution: "nookies@npm:2.5.2"
35785+
dependencies:
35786+
cookie: ^0.4.1
35787+
set-cookie-parser: ^2.4.6
35788+
checksum: 4cc6fd8d0ab9fce840ccdb161eefe9dee581f441429fc729f279924491ebd1c12c220f889b6e315d66f8ea00bef944966969c966c957a6b9918ced7d7f9cc8a8
35789+
languageName: node
35790+
linkType: hard
35791+
3578135792
"nopt@npm:^4.0.3":
3578235793
version: 4.0.3
3578335794
resolution: "nopt@npm:4.0.3"
@@ -41682,6 +41693,13 @@ resolve@^2.0.0-next.3:
4168241693
languageName: node
4168341694
linkType: hard
4168441695

41696+
"set-cookie-parser@npm:^2.4.6":
41697+
version: 2.7.1
41698+
resolution: "set-cookie-parser@npm:2.7.1"
41699+
checksum: 2ef8b351094712f8f7df6d63ed4b10350b24a5b515772690e7dec227df85fcef5bc451c7765f484fd9f36694ece5438d1456407d017f237d0d3351d7dbbd3587
41700+
languageName: node
41701+
linkType: hard
41702+
4168541703
"set-function-length@npm:^1.1.1":
4168641704
version: 1.1.1
4168741705
resolution: "set-function-length@npm:1.1.1"

0 commit comments

Comments
 (0)