Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/pretty-boats-refuse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"nextjs-darkmode": patch
---

Optimize
4 changes: 1 addition & 3 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,11 @@ jobs:
git pull
- run: npm i -g pnpm && pnpm i
name: Install dependencies
- name: Test
run: npm test
- run: git status && git clean -f -d && git status
name: clean up working directory
- run: npx @turbo/codemod update . && pnpm update --latest -r
name: Update dependencies
- run: pnpm build
- run: pnpm build --filter @example/nextjs
name: Build all apps to make sure it is not broken due to dependency upgrades
- name: Run unit tests
run: pnpm test
Expand Down
8 changes: 0 additions & 8 deletions examples/nextjs-pages/.eslintrc.js

This file was deleted.

4 changes: 4 additions & 0 deletions examples/nextjs-pages/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { nextJsConfig } from "@repo/eslint-config/next.js";

/** @type {import("eslint").Linter.Config} */
export default nextJsConfig;
8 changes: 0 additions & 8 deletions examples/nextjs/.eslintrc.js

This file was deleted.

4 changes: 4 additions & 0 deletions examples/nextjs/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { nextJsConfig } from "@repo/eslint-config/next.js";

/** @type {import("eslint").Linter.Config} */
export default nextJsConfig;
1 change: 1 addition & 0 deletions examples/nextjs/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
8 changes: 0 additions & 8 deletions examples/tailwind/.eslintrc.js

This file was deleted.

4 changes: 4 additions & 0 deletions examples/tailwind/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { nextJsConfig } from "@repo/eslint-config/next.js";

/** @type {import("eslint").Linter.Config} */
export default nextJsConfig;
8 changes: 0 additions & 8 deletions examples/vite/.eslintrc.js

This file was deleted.

4 changes: 4 additions & 0 deletions examples/vite/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { config } from "@repo/eslint-config/react.js";

/** @type {import("eslint").Linter.Config} */
export default config;
8 changes: 0 additions & 8 deletions lib/.eslintrc.js

This file was deleted.

4 changes: 4 additions & 0 deletions lib/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { config } from "@repo/eslint-config/react.js";

/** @type {import("eslint").Linter.Config} */
export default config;
2 changes: 1 addition & 1 deletion lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"vitest": "^2.1.8"
},
"dependencies": {
"r18gs": "^3.0.1"
"r18gs": "2.0.2"
},
"peerDependencies": {
"@types/react": "16.8 - 19",
Expand Down
2 changes: 1 addition & 1 deletion lib/src/client/core/core.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ describe("theme-switcher", () => {
await act(() => {
// globalThis.window.media = LIGHT as ResolvedScheme;
// @ts-expect-error -- ok
m.onchange?.();
q.onchange?.();
});
expect(hook.result.current.mode).toBe(DARK);
});
Expand Down
30 changes: 15 additions & 15 deletions lib/src/client/core/core.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { DARK, LIGHT } from "../../constants";
import { ColorSchemePreference, ResolvedScheme, useStore } from "../../utils";
import { useEffect } from "react";
import { noFOUCScript } from "./no-fouc";

let media: MediaQueryList,
Expand Down Expand Up @@ -36,17 +35,18 @@ export interface CoreProps {

/** Modify transition globally to avoid patched transitions */
const modifyTransition = (themeTransition = "none", nonce = "") => {
const css = document.createElement("style");
const doc = document;
const css = doc.createElement("style");
/** split by ';' to prevent CSS injection */
css.textContent = `*,*:after,*:before{transition:${themeTransition.split(";")[0]} !important;}`;
nonce && css.setAttribute("nonce", nonce);
document.head.appendChild(css);
css.setAttribute("nonce", nonce);
doc.head.appendChild(css);

return () => {
// Force restyle
getComputedStyle(document.body);
getComputedStyle(doc.body);
// Wait for next tick before removing
setTimeout(() => document.head.removeChild(css), 1);
setTimeout(() => doc.head.removeChild(css), 1);
};
};

Expand All @@ -62,14 +62,15 @@ const modifyTransition = (themeTransition = "none", nonce = "") => {
* @source - Source code
*/
export const Core = ({ t, nonce, k = "o" }: CoreProps) => {
const isWindowDefined = typeof window != "undefined";
// handle client side exceptions when script is not run. <- for client side apps like vite or CRA
if (typeof window !== "undefined" && !window.m) noFOUCScript(k);
if (isWindowDefined && !window.q) noFOUCScript(k);

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

useEffect(() => {
if (!updateDOM && isWindowDefined) {
// store global functions to local variables to avoid any interference
[media, updateDOM] = [m, u];
[media, updateDOM] = [q, u];
/** Updating media: prefers-color-scheme*/
media.addEventListener("change", () =>
setThemeState(state => ({ ...state, s: media.matches ? DARK : LIGHT })),
Expand All @@ -78,13 +79,12 @@ export const Core = ({ t, nonce, k = "o" }: CoreProps) => {
addEventListener("storage", (e: StorageEvent): void => {
e.key === k && setThemeState(state => ({ ...state, m: e.newValue as ColorSchemePreference }));
});
}, []);

useEffect(() => {
}
if (updateDOM) {
const restoreTransitions = modifyTransition(t, nonce);
updateDOM(mode, systemMode);
updateDOM(m, s);
restoreTransitions();
}, [systemMode, mode, t, nonce]);
}

return <Script {...{ n: nonce, k }} />;
};
6 changes: 3 additions & 3 deletions lib/src/client/core/no-fouc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ declare global {
// skipcq: JS-0102, JS-C1002, JS-0239
var u: (mode: ColorSchemePreference, systemMode: ResolvedScheme) => void;
// skipcq: JS-0102, JS-C1002, JS-0239
var m: MediaQueryList;
var q: MediaQueryList;
}

/** function to be injected in script tag for avoiding FOUC */
Expand All @@ -23,6 +23,6 @@ export const noFOUCScript = (storageKey: string) => {
// System mode is decided by current system state and need not be stored in localStorage
localStorage.setItem(storageKey, mode);
};
window.m = matchMedia(`(prefers-color-scheme: ${DARK})`);
u((localStorage.getItem(storageKey) ?? SYSTEM) as ColorSchemePreference, m.matches ? DARK : "");
window.q = matchMedia(`(prefers-color-scheme: ${DARK})`);
u((localStorage.getItem(storageKey) ?? SYSTEM) as ColorSchemePreference, q.matches ? DARK : "");
};
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 };
if (typeof document == "undefined") return { m: SYSTEM, s: DARK };
const [m, s] = ["m", "sm"].map(dt => document.documentElement.getAttribute("data-" + dt));
return {
m: (m ?? SYSTEM) as ColorSchemePreference,
Expand Down
32 changes: 32 additions & 0 deletions packages/config-eslint/base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import js from "@eslint/js";
import eslintConfigPrettier from "eslint-config-prettier";
import turboPlugin from "eslint-plugin-turbo";
import tseslint from "typescript-eslint";
import onlyWarn from "eslint-plugin-only-warn";

/**
* A shared ESLint configuration for the repository.
*
* @type {import("eslint").Linter.Config}
* */
export const config = [
js.configs.recommended,
eslintConfigPrettier,
...tseslint.configs.recommended,
{
plugins: {
turbo: turboPlugin,
},
rules: {
"turbo/no-undeclared-env-vars": "warn",
},
},
{
plugins: {
onlyWarn,
},
},
{
ignores: ["dist/**"],
},
];
34 changes: 0 additions & 34 deletions packages/config-eslint/index.js

This file was deleted.

80 changes: 43 additions & 37 deletions packages/config-eslint/next.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,49 @@
const { resolve } = require("node:path");
import js from "@eslint/js";
import eslintConfigPrettier from "eslint-config-prettier";
import tseslint from "typescript-eslint";
import pluginReactHooks from "eslint-plugin-react-hooks";
import pluginReact from "eslint-plugin-react";
import globals from "globals";
import pluginNext from "@next/eslint-plugin-next";
import { config as baseConfig } from "./base.js";

const project = resolve(process.cwd(), "tsconfig.json");

/*
* This is a custom ESLint configuration for use with
* Next.js apps.
*
* This config extends the Vercel Engineering Style Guide.
* For more information, see https://github.com/vercel/style-guide
/**
* A custom ESLint configuration for libraries that use Next.js.
*
*/

module.exports = {
extends: [
"@vercel/style-guide/eslint/node",
"@vercel/style-guide/eslint/typescript",
"@vercel/style-guide/eslint/browser",
"@vercel/style-guide/eslint/react",
"@vercel/style-guide/eslint/next",
"eslint-config-turbo",
].map(require.resolve),
parserOptions: {
project,
},
globals: {
React: true,
JSX: true,
},
plugins: ["only-warn"],
settings: {
"import/resolver": {
typescript: {
project,
* @type {import("eslint").Linter.Config}
* */
export const nextJsConfig = [
...baseConfig,
js.configs.recommended,
eslintConfigPrettier,
...tseslint.configs.recommended,
{
...pluginReact.configs.flat.recommended,
languageOptions: {
...pluginReact.configs.flat.recommended.languageOptions,
globals: {
...globals.serviceworker,
},
},
},
ignorePatterns: [".*.js", "node_modules/", "dist/"],
// add rules configurations here
rules: {
"import/no-default-export": "off",
{
plugins: {
"@next/next": pluginNext,
},
rules: {
...pluginNext.configs.recommended.rules,
...pluginNext.configs["core-web-vitals"].rules,
},
},
{
plugins: {
"react-hooks": pluginReactHooks,
},
settings: { react: { version: "detect" } },
rules: {
...pluginReactHooks.configs.recommended.rules,
// React scope no longer necessary with new JSX transform.
"react/react-in-jsx-scope": "off",
},
},
};
];
19 changes: 13 additions & 6 deletions packages/config-eslint/package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
{
"name": "@repo/eslint-config",
"license": "MIT",
"version": "0.0.0",
"type": "module",
"private": true,
"devDependencies": {
"@vercel/style-guide": "^6.0.0",
"eslint-config-turbo": "^2.3.3",
"eslint-plugin-mdx": "^3.1.5",
"@next/eslint-plugin-next": "^15.1.1",
"@typescript-eslint/eslint-plugin": "^8.18.1",
"@typescript-eslint/parser": "^8.18.1",
"eslint": "^9.17.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-only-warn": "^1.1.0",
"eslint-plugin-storybook": "^0.11.1"
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-turbo": "^2.3.3",
"globals": "^15.14.0",
"typescript": "^5.7.2",
"typescript-eslint": "^8.18.1"
}
}
}
Loading
Loading