Skip to content

Commit

Permalink
refactor: supressHydrationWarning and improve readability
Browse files Browse the repository at this point in the history
  • Loading branch information
mayank1513 committed Jun 17, 2024
1 parent f6f728a commit 16e536d
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 12 deletions.
4 changes: 2 additions & 2 deletions lib/src/client/core/core.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { act, cleanup, fireEvent, render, renderHook } from "@testing-library/react";
import { afterEach, beforeEach, describe, test } from "vitest";
import { Core, s } from "./core";
import { Core, noFOUCScript } from "./core";
import { useMode } from "../../hooks";
import { DARK, LIGHT } from "../../constants";

Expand All @@ -9,7 +9,7 @@ describe("theme-switcher", () => {
afterEach(cleanup);

beforeEach(() => {
s(STORAGE_KEY);
noFOUCScript(STORAGE_KEY);
render(<Core />);
});

Expand Down
29 changes: 24 additions & 5 deletions lib/src/client/core/core.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { DARK, LIGHT } from "../../constants";
import { ColorSchemePreference, ResolvedScheme, Store, useStore } from "../../utils";
import { useEffect } from "react";
import { memo, useEffect } from "react";

declare global {
// skipcq: JS-0102, JS-0239
var u: (mode: ColorSchemePreference, systemMode: ResolvedScheme) => void;
// skipcq: JS-0102, JS-0239
var m: MediaQueryList;
}

/** function to be injected in script tag for avoiding FOUC */
export const s = (storageKey: string) => {
export const noFOUCScript = (storageKey: string) => {
const [SYSTEM, DARK] = ["system", "dark"] as const;
window.u = (mode: ColorSchemePreference, systemMode: ResolvedScheme) => {
const resolvedMode = mode === SYSTEM ? systemMode : mode;
Expand All @@ -30,6 +32,23 @@ export const s = (storageKey: string) => {
let media: MediaQueryList,
updateDOM: (mode: ColorSchemePreference, systemMode: ResolvedScheme) => void;

interface ScriptProps {
/** nonce */
n?: string;
/** storageKey */
k: string;
}

/** Avoid rerender of script */
const Script = memo(({ n, k }: ScriptProps) => (
<script
suppressHydrationWarning
// skipcq: JS-0440
dangerouslySetInnerHTML={{ __html: `(${noFOUCScript.toString()})('${k}')` }}
nonce={n}
/>
));

export interface CoreProps {
/** themeTransition: force apply CSS transition property to all the elements during theme switching. E.g., `all .3s`
* @defaultValue 'none'
Expand Down Expand Up @@ -70,7 +89,7 @@ const modifyTransition = (themeTransition = "none", nonce = "") => {
*/
export const Core = ({ t, nonce, k = "o" }: CoreProps) => {
// handle client side exceptions when script is not run. <- for client side apps like vite or CRA
if (typeof window !== "undefined" && !window.m) s(k);
if (typeof window !== "undefined" && !window.m) noFOUCScript(k);

const [{ m: mode, s: systemMode }, setThemeState] = useStore();

Expand All @@ -79,7 +98,7 @@ export const Core = ({ t, nonce, k = "o" }: CoreProps) => {
[media, updateDOM] = [m, u];
/** Updating media: prefers-color-scheme*/
media.addEventListener("change", () =>
setThemeState(state => ({ ...state, s: media.matches ? DARK : LIGHT }) as Store),
setThemeState(state => ({ ...state, s: media.matches ? DARK : LIGHT })),
);
/** Sync the tabs */
addEventListener("storage", (e: StorageEvent): void => {
Expand All @@ -93,5 +112,5 @@ export const Core = ({ t, nonce, k = "o" }: CoreProps) => {
restoreTransitions();
}, [systemMode, mode, t, nonce]);

return <script dangerouslySetInnerHTML={{ __html: `(${s.toString()})('${k}')` }} nonce={nonce} />;
return <Script {...{ n: nonce, k }} />;
};
6 changes: 3 additions & 3 deletions lib/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ColorSchemePreference } from "./utils";
import { ColorSchemePreference, ResolvedScheme } from "./utils";

export const SYSTEM: ColorSchemePreference = "system";
export const DARK: ColorSchemePreference = "dark";
export const LIGHT: ColorSchemePreference = "";
export const DARK: ResolvedScheme = "dark";
export const LIGHT: ResolvedScheme = "";

export const modes: ColorSchemePreference[] = [SYSTEM, DARK, LIGHT];
2 changes: 1 addition & 1 deletion lib/src/hooks/use-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const useMode = (): UseModeYeild => {
return {
mode,
systemMode,
resolvedMode: (mode === SYSTEM ? systemMode : mode) as ResolvedScheme, // resolvedMode is the actual mode that will be used
resolvedMode: (mode === SYSTEM ? systemMode : mode) as ResolvedScheme,
setMode,
};
};
2 changes: 1 addition & 1 deletion lib/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface Store {
/** local abstaction of RGS to avoid multiple imports */
export const useStore = () =>
useRGS<Store>("ndm", () => {
if (typeof document === "undefined") return { m: SYSTEM, s: DARK as ResolvedScheme };
if (typeof document === "undefined") return { m: SYSTEM, s: DARK };
const el = document.documentElement;
return {
m: (el.getAttribute("data-m") ?? SYSTEM) as ColorSchemePreference,
Expand Down

0 comments on commit 16e536d

Please sign in to comment.