Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/39 create switcher without injection #43

Merged
merged 28 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6a9b898
Move code inside src for tailwind example
mayank1513 Jun 27, 2024
4354fda
Add Switcher
mayank1513 Jun 27, 2024
084b4b5
Fix blocking trail overlay
mayank1513 Jun 27, 2024
29c6918
Update exports in package.json
mayank1513 Jun 27, 2024
3d3e015
docs(changeset): Enhance: Avoid unnecessary script injection when add…
mayank1513 Jun 27, 2024
7ae5ddb
fixes #39
mayank1513 Jun 27, 2024
cfeae26
style: format code with Prettier
deepsource-autofix[bot] Jun 27, 2024
97e3b2d
Update package lock file
mayank1513 Jun 27, 2024
0627dbc
Switcher tests are covered in theme switcher
mayank1513 Jun 27, 2024
34ac76d
refactor: autofix issues in 2 files
deepsource-autofix[bot] Jun 27, 2024
f93e971
fix deepsource
mayank1513 Jun 27, 2024
3c78884
Apply changesets and update CHANGELOG
mayank1513 Jun 27, 2024
eedf0eb
doc: Update doc comments for better clarity
mayank1513 Jun 27, 2024
6e02178
docs(changeset): Fix color-switch styles in containerized styles.
mayank1513 Jun 27, 2024
455aecf
RELEASING: Releasing 2 package(s)
mayank1513 Jun 27, 2024
93dad4a
Apply changesets and update CHANGELOG
mayank1513 Jun 27, 2024
aa8cbd8
fix publish script
mayank1513 Jun 27, 2024
a69e2c8
docs(changeset): Fix styles.
mayank1513 Jun 27, 2024
de22af0
fix changeset
mayank1513 Jun 27, 2024
c9ab651
attempt to fix changeset
mayank1513 Jun 27, 2024
2a042c1
RELEASING: Releasing 2 package(s)
mayank1513 Jun 27, 2024
d89d157
docs(changeset): Create Switcher without injecting scripts for contai…
mayank1513 Jun 27, 2024
d4cb151
fix changeset
mayank1513 Jun 27, 2024
d969a12
fix: manual publish
mayank1513 Jun 27, 2024
413d2be
RELEASING: Releasing 2 package(s)
mayank1513 Jun 27, 2024
a454966
Apply changesets and update CHANGELOG
mayank1513 Jun 27, 2024
961b453
fix: fix styles
mayank1513 Jun 27, 2024
9b06e4d
touch up
mayank1513 Jun 27, 2024
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/giant-moons-watch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"nextjs-themes": patch
---

Create Switcher without injecting scripts for containerized themes.
18 changes: 18 additions & 0 deletions .changeset/pre.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"mode": "exit",
"tag": "feat",
"initialVersions": {
"@example/app": "0.0.0",
"@example/pages": "0.0.0",
"@example/tailwind": "0.0.0",
"@example/vite": "0.0.0",
"nextjs-themes": "4.0.2",
"@repo/eslint-config": "0.0.0",
"@repo/typescript-config": "0.0.0",
"@repo/shared": "0.0.0",
"@repo/scripts": "0.0.0"
},
"changesets": [
"giant-moons-watch"
]
}
2 changes: 1 addition & 1 deletion examples/pages-router/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"@types/node": "^20.14.9",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"react-webgl-trails": "^0.0.2",
"react-webgl-trails": "^0.0.3",
"typescript": "^5.5.2"
}
}
3 changes: 1 addition & 2 deletions examples/pages-router/src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import "../styles/global.css";
import { Inter } from "next/font/google";
import Link from "next/link";
import { Card, Cards, LandingPage, Layout, type CardProps } from "@repo/shared/dist/server";
import { ThemeController, PageNavigatorCard, Header } from "@repo/shared";
import { ThemeController, PageNavigatorCard, Header, ScopedThemes } from "@repo/shared";
import { ColorSwitch } from "nextjs-themes/color-switch";
import { ScopedThemes } from "@repo/shared/dist/client/scoped-themes";
import { MouseTrail } from "react-webgl-trails";

const inter = Inter({ subsets: ["latin"] });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@ interface CardProps {
text: string;
}

/** Card */
export default function Card({ href, title, text }: CardProps) {
return (
<a
href={href}
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
target="_blank"
rel="noopener noreferrer">
<h2 className={`mb-3 text-2xl font-semibold`}>
{title + " "}
<h2 className={"mb-3 text-2xl font-semibold"}>
{`${title} `}
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
-&gt;
</span>
</h2>
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>{text}</p>
<p className={"m-0 max-w-[30ch] text-sm opacity-50"}>{text}</p>
</a>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@

body {
color: rgb(var(--foreground-rgb));
background: linear-gradient(to bottom, transparent, rgb(var(--background-end-rgb))) rgb(var(--background-start-rgb));
background: linear-gradient(to bottom, transparent, rgb(var(--background-end-rgb)))
rgb(var(--background-start-rgb));
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const metadata: Metadata = {
description: "Generated by Mayank <https://github.com/mayank1513>",
};

/** Layout */
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Image from "next/image";
import { ColorSwitch } from "nextjs-themes";
import Card from "./_components/card";

/** Home */
export default function Home() {
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
Expand Down Expand Up @@ -50,13 +51,13 @@ export default function Home() {
<StarMe
gitHubUrl="https://github.com/react18-tools/nextjs-themes"
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30">
<h2 className={`mb-3 text-2xl font-semibold`}>
<h2 className={"mb-3 text-2xl font-semibold"}>
Star Me{" "}
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
-&gt;
</span>
</h2>
<p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
<p className={"m-0 max-w-[30ch] text-sm opacity-50"}>
Explore and star official <code>nextjs-themes</code> repo.
</p>
</StarMe>
Expand Down
24 changes: 24 additions & 0 deletions lib/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,29 @@
# nextjs-themes

## 4.0.3-feat.0

### Patch Changes

- d89d157: Create Switcher without injecting scripts for containerized themes.

## 4.0.3

### Patch Changes

- 6e02178: Fix color-switch styles in containerized styles.

## 4.0.3-feat_39.0

### Patch Changes

- 6e02178: Fix color-switch styles in containerized styles.

## 4.0.2

### Patch Changes

- 3d3e015: Enhance: Avoid unnecessary script injection when adding contenarized themes for a target other than html element.

## 4.0.1

### Patch Changes
Expand Down
12 changes: 11 additions & 1 deletion lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "nextjs-themes",
"author": "Mayank Kumar Chaudhari <https://mayank-chaudhari.vercel.app>",
"private": false,
"version": "4.0.1",
"version": "4.0.3-feat.0",
"description": "Unleash the Power of React Server Components! Use multiple themes 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 @@ -46,6 +46,16 @@
"import": "./dist/client/theme-switcher/index.mjs",
"types": "./dist/client/theme-switcher/index.d.ts"
},
"./client/switcher": {
"require": "./dist/client/switcher/index.js",
"import": "./dist/client/switcher/index.mjs",
"types": "./dist/client/switcher/index.d.ts"
},
"./switcher": {
"require": "./dist/client/switcher/index.js",
"import": "./dist/client/switcher/index.mjs",
"types": "./dist/client/switcher/index.d.ts"
},
"./client/force-color-scheme": {
"require": "./dist/client/force-color-scheme/index.js",
"import": "./dist/client/force-color-scheme/index.mjs",
Expand Down
17 changes: 6 additions & 11 deletions lib/src/client/color-switch/color-switch.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@
all: unset;
position: relative;
box-shadow: none;
color: #aaa;
color: currentColor;
border-radius: 50%;
border: 1px dashed gray;
border: 1px dashed currentColor;
cursor: pointer;
--s: 25px;
height: var(--s);
width: var(--s);
transition: all 0.3s ease-in-out 0s !important;
}

[data-csp="system"] .s::after,
[data-csp="system"] ~ .s::after,
[data-csp="system"] ~ * .s::after {
.system.s::after {
position: absolute;
height: 100%;
width: 100%;
Expand All @@ -25,21 +23,18 @@
display: flex;
align-items: center;
justify-content: center;
opacity: 0.5;
content: "A";
}

[data-csp="dark"] .s,
[data-csp="dark"] ~ .s,
[data-csp="dark"] ~ * .s {
.dark.s {
box-shadow: calc(var(--s) / 4) calc(var(--s) / -4) calc(var(--s) / 8) inset #fff;
border: none;
background: transparent;
animation: a linear 0.5s;
}

[data-csp="light"] .s,
[data-csp="light"] ~ .s,
[data-csp="light"] ~ * .s {
.light.s {
box-shadow: 0 0 50px 10px yellow;
background-color: yellow;
border: 1px solid orangered;
Expand Down
5 changes: 2 additions & 3 deletions lib/src/client/color-switch/color-switch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,11 @@ export const ColorSwitch = ({
className,
...props
}: ColorSwitchProps) => {
const { toggleColorScheme } = useTheme(targetSelector);
const { toggleColorScheme, colorSchemePref } = useTheme(targetSelector);

const cls = [styles.s, className].join(" ");
return (
<button
className={cls}
className={[styles.s, styles[colorSchemePref], className].join(" ")}
data-testid="color-switch"
// skipcq: JS-0417
onClick={() => toggleColorScheme(skipSystem)}
Expand Down
4 changes: 4 additions & 0 deletions lib/src/client/switcher/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use client";

// component exports
export * from "./switcher";
78 changes: 78 additions & 0 deletions lib/src/client/switcher/switcher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { useEffect } from "react";
import { ThemeSwitcherProps } from "../theme-switcher";
import { DARK, DEFAULT_ID, LIGHT } from "../../constants";
import { useForcedStore, useThemeStore } from "../../store";
import type { ResolveFunc, UpdateDOMFunc, UpdateForcedPropsFunc } from "../theme-switcher/no-fouc";

let media: MediaQueryList;
let updateDOM: UpdateDOMFunc;
let resolveTheme: ResolveFunc;
let updateForcedProps: UpdateForcedPropsFunc;
let updateForcedState: UpdateForcedPropsFunc;

/** disable transition while switching theme */
const modifyTransition = (themeTransition = "none") => {
const css = document.createElement("style");
/** split by ';' to prevent CSS injection */
css.textContent = `transition:${themeTransition.split(";")[0]}!important;`;
document.head.appendChild(css);

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

/**
* The Core component applies classes and transitions without injecting any scripts. Use ThemeSwitcher only once per page. For scoped styles, use this component instead.
*
* Please note that you need to use suitable techniques to increase specificity of CSS selecors when using data- attributes for targetting a container which is within another themed container (including the html if you have used ThemeSwitcher without targetSelector)
*
* @example
* ```tsx
* <Switcher targetSelector="#container1" />
* ```
*/
export const Switcher = ({
forcedTheme,
forcedColorScheme,
targetSelector,
themeTransition,
}: ThemeSwitcherProps) => {
const k = targetSelector || `#${DEFAULT_ID}`;

const [state, setState] = useThemeStore(targetSelector);
const [forced] = useForcedStore(targetSelector);

useEffect(() => {
if (typeof m !== "undefined")
[media, updateDOM, resolveTheme, updateForcedProps, updateForcedState] = [m, u, r, f, g];

media.addEventListener("change", () =>
setState(state => ({ ...state, s: media.matches ? DARK : LIGHT })),
);
addEventListener("storage", e => {
if (e.key === k) setState(state => ({ ...state, ...JSON.parse(e.newValue || "{}") }));
});
}, []);

useEffect(() => {
const restoreThansitions = modifyTransition(themeTransition);
updateDOM(resolveTheme(state), k);
restoreThansitions();
localStorage.setItem(k, JSON.stringify(state));
}, [state]);

useEffect(() => {
updateForcedProps(forcedTheme, forcedColorScheme);
updateDOM(resolveTheme(state), k);
}, [forcedColorScheme, forcedTheme]);

useEffect(() => {
updateForcedState(forced.f, forced.fc);
updateDOM(resolveTheme(state), k);
}, [forced]);
return null;
};
8 changes: 8 additions & 0 deletions lib/src/client/theme-switcher/no-fouc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ declare global {
var g: UpdateForcedPropsFunc;
}

export type ScriptArgs = [
string,
ThemeStoreType,
Record<string, string> | undefined,
string | undefined,
ColorSchemeType | undefined,
];

/** @internal Script to be injected for avoiding FOUC */
export const noFOUCScript = (
key: string,
Expand Down
Loading
Loading