Skip to content

Commit

Permalink
Merge pull request #8 from react18-tools/patch/update-rgs
Browse files Browse the repository at this point in the history
Patch/update rgs
  • Loading branch information
mayank1513 committed Jun 13, 2024
2 parents 9139366 + 807465c commit 0bbc043
Show file tree
Hide file tree
Showing 12 changed files with 100 additions and 33 deletions.
6 changes: 6 additions & 0 deletions lib/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# nextjs-darkmode

## 0.1.1

### Patch Changes

- 70a2236: Fix: FOUC

## 0.1.0

### Minor Changes
Expand Down
4 changes: 2 additions & 2 deletions lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "nextjs-darkmode",
"author": "Mayank Kumar Chaudhari <https://mayank-chaudhari.vercel.app>",
"private": false,
"version": "0.1.0",
"version": "0.1.1",
"description": "Unleash the Power of React Server Components! Use dark/light mode on your site with confidence, without losing any advantages of React Server Components",
"license": "MPL-2.0",
"main": "./dist/index.js",
Expand Down Expand Up @@ -67,7 +67,7 @@
"vitest": "^1.6.0"
},
"dependencies": {
"r18gs": "^1.0.2"
"r18gs": "^1.1.0"
},
"peerDependencies": {
"@types/react": "16.8 - 19",
Expand Down
13 changes: 10 additions & 3 deletions lib/src/client/core/core.test.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { act, cleanup, fireEvent, render, renderHook } from "@testing-library/react";
import { afterEach, beforeEach, describe, test } from "vitest";
import { ServerTarget } from "../../server";
import { Core } from "./core";
import { useMode } from "../../hooks";
import { COOKIE_KEY, DARK, LIGHT, SYSTEM } from "../../constants";
import { COOKIE_KEY, DARK, LIGHT, MEDIA } from "../../constants";

describe("theme-switcher", () => {
afterEach(cleanup);
Expand Down Expand Up @@ -35,5 +34,13 @@ describe("theme-switcher", () => {
expect(hook.result.current.mode).toBe(DARK);
});

test.todo("test media change event -- not supported by fireEvent");
test("test media change event", async ({ expect }) => {
const hook = renderHook(() => useMode());
await act(() => {
// globalThis.window.media = LIGHT as ResolvedScheme;
// @ts-expect-error -- ok
matchMedia(MEDIA).onchange?.();
});
expect(hook.result.current.mode).toBe(DARK);
});
});
10 changes: 2 additions & 8 deletions lib/src/client/core/core.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { COOKIE_KEY, DARK, LIGHT, SYSTEM, modes } from "../../constants";
import { COOKIE_KEY, DARK, LIGHT, MEDIA, SYSTEM, modes } from "../../constants";
import { ColorSchemePreference, Store, useStore } from "../../utils";
import { useEffect } from "react";

Expand Down Expand Up @@ -41,17 +41,11 @@ export const Core = ({ t, nonce }: CoreProps) => {
const resolvedMode = mode === SYSTEM ? systemMode : mode; // resolvedMode is the actual mode that will be used

useEffect(() => {
const media = matchMedia(`(prefers-color-scheme: ${DARK})`);
const media = matchMedia(MEDIA);
/** Updating media: prefers-color-scheme*/
const updateSystemColorScheme = () =>
setThemeState(state => ({ ...state, s: media.matches ? DARK : LIGHT }) as Store);
updateSystemColorScheme();
media.addEventListener("change", updateSystemColorScheme);

setThemeState(state => ({
...state,
m: (localStorage.getItem(COOKIE_KEY) ?? SYSTEM) as ColorSchemePreference,
}));
/** Sync the tabs */
const storageListener = (e: StorageEvent): void => {
if (e.key === COOKIE_KEY)
Expand Down
2 changes: 2 additions & 0 deletions lib/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ export const LIGHT: ColorSchemePreference = "light";

export const COOKIE_KEY = "gx";
export const modes: ColorSchemePreference[] = [SYSTEM, DARK, LIGHT];

export const MEDIA = `(prefers-color-scheme: ${DARK})`;
13 changes: 11 additions & 2 deletions lib/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import useRGS from "r18gs";
import { DARK, SYSTEM } from "./constants";
import { COOKIE_KEY, DARK, LIGHT, MEDIA, SYSTEM } from "./constants";

export type ColorSchemePreference = "system" | "dark" | "light";
export type ResolvedScheme = "dark" | "light";
Expand All @@ -14,4 +14,13 @@ const DEFAULT_STORE_VAL: Store = {
};

/** local abstaction of RGS to avoid multiple imports */
export const useStore = () => useRGS<Store>("ndm", DEFAULT_STORE_VAL);
export const useStore = () =>
useRGS<Store>("ndm", () =>
typeof localStorage === "undefined"
? /* v8 ignore next */
DEFAULT_STORE_VAL
: {
m: (localStorage.getItem(COOKIE_KEY) ?? SYSTEM) as ColorSchemePreference,
s: (matchMedia(MEDIA).matches ? DARK : LIGHT) as ResolvedScheme,
},
);
11 changes: 8 additions & 3 deletions lib/vitest.setup.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { vi } from "vitest";

const mediaListeners: (() => void)[] = [];
// mock matchMedia
Object.defineProperty(window, "matchMedia", {
writable: true,
value: vi.fn().mockImplementation((query: string) => ({
matches: query.includes(window.media),
media: query,
onchange: null,
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
onchange() {
this.matches = query.includes(window.media);
mediaListeners.forEach(listener => listener());
},
addEventListener: (_: string, listener: () => void) => mediaListeners.push(listener),
removeEventListener: (_: string, listener: () => void) =>
mediaListeners.splice(mediaListeners.indexOf(listener), 1),
dispatchEvent: vi.fn(),
})),
});
Expand Down
7 changes: 7 additions & 0 deletions packages/shared/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# @repo/shared

## 0.0.5

### Patch Changes

- Updated dependencies [70a2236]
- [email protected]

## 0.0.4

### Patch Changes
Expand Down
4 changes: 2 additions & 2 deletions packages/shared/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@repo/shared",
"version": "0.0.4",
"version": "0.0.5",
"private": true,
"sideEffects": false,
"main": "./dist/index.js",
Expand Down Expand Up @@ -42,7 +42,7 @@
"@repo/scripts": "workspace:*",
"nextjs-darkmode": "workspace:*",
"nextjs-themes": "^3.1.1",
"r18gs": "^1.0.2",
"r18gs": "^1.1.0",
"react-live": "^4.1.6",
"react18-loaders": "^1.1.1"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/shared/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default defineConfig({
test: {
environment: "jsdom",
globals: true,
setupFiles: [],
setupFiles: ["vitest.setup.ts"],
coverage: {
include: ["src/**"],
exclude: ["src/**/index.ts", "src/**/declaration.d.ts"],
Expand Down
37 changes: 37 additions & 0 deletions packages/shared/vitest.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { vi } from "vitest";

const mediaListeners: (() => void)[] = [];
// mock matchMedia
Object.defineProperty(window, "matchMedia", {
writable: true,
value: vi.fn().mockImplementation((query: string) => ({
matches: query.includes(window.media),
media: query,
onchange() {
this.matches = query.includes(window.media);
mediaListeners.forEach(listener => listener());
},
addEventListener: (_: string, listener: () => void) => mediaListeners.push(listener),
removeEventListener: (_: string, listener: () => void) =>
mediaListeners.splice(mediaListeners.indexOf(listener), 1),
dispatchEvent: vi.fn(),
})),
});

declare global {
interface Window {
media: "dark" | "light";
}
// skipcq: JS-0102
var cookies: Record<string, { value: string }>; // eslint-disable-line no-var -- let is not supported in defining global due to block scope
}
Object.defineProperty(window, "media", {
writable: true,
value: "dark",
});

globalThis.cookies = {};

vi.mock("next/headers", () => ({
cookies: () => ({ get: (cookieName: string) => globalThis.cookies[cookieName] }),
}));
24 changes: 12 additions & 12 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 0bbc043

Please sign in to comment.