diff --git a/examples/app-router/src/app/layout.tsx b/examples/app-router/src/app/layout.tsx index a4258407..22ba8022 100644 --- a/examples/app-router/src/app/layout.tsx +++ b/examples/app-router/src/app/layout.tsx @@ -7,6 +7,7 @@ import Link from "next/link"; import { Cards, LandingPage } from "@repo/shared/dist/server"; import { PageNavigatorCard, ThemeController } from "@repo/shared"; import { ColorSwitch } from "nextjs-themes/color-switch"; +import { ScopedThemes } from "@repo/shared/dist/client/scoped-themes"; const inter = Inter({ subsets: ["latin"] }); @@ -22,6 +23,7 @@ export default function RootLayout({ children }: { children: React.ReactNode }): + {" "} diff --git a/examples/pages-router/src/pages/_app.tsx b/examples/pages-router/src/pages/_app.tsx index a21467e5..fbac75a7 100644 --- a/examples/pages-router/src/pages/_app.tsx +++ b/examples/pages-router/src/pages/_app.tsx @@ -9,6 +9,7 @@ import Link from "next/link"; import { Card, Cards, LandingPage } from "@repo/shared/dist/server"; import { ThemeController, PageNavigatorCard } from "@repo/shared"; import { ColorSwitch } from "nextjs-themes/color-switch"; +import { ScopedThemes } from "@repo/shared/dist/client/scoped-themes"; const inter = Inter({ subsets: ["latin"] }); @@ -38,6 +39,7 @@ export default function App({ Component, pageProps }: _AppProps) { + {staticCards.map(card => ( diff --git a/lib/CHANGELOG.md b/lib/CHANGELOG.md index cad8986d..8eec2ad0 100644 --- a/lib/CHANGELOG.md +++ b/lib/CHANGELOG.md @@ -1,5 +1,11 @@ # nextjs-themes +## 4.0.1 + +### Patch Changes + +- a2fd744: Update forced components to use targetSelector + ## 4.0.0 ### Major Changes diff --git a/lib/package.json b/lib/package.json index 68f92a0d..4386cafc 100644 --- a/lib/package.json +++ b/lib/package.json @@ -2,7 +2,7 @@ "name": "nextjs-themes", "author": "Mayank Kumar Chaudhari ", "private": false, - "version": "4.0.0", + "version": "4.0.1", "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", diff --git a/lib/src/client/force-color-scheme/force-color-scheme.tsx b/lib/src/client/force-color-scheme/force-color-scheme.tsx index 931cf67e..c0816b0a 100644 --- a/lib/src/client/force-color-scheme/force-color-scheme.tsx +++ b/lib/src/client/force-color-scheme/force-color-scheme.tsx @@ -4,8 +4,11 @@ import { useForcedStore } from "../../store"; import { ColorSchemeType } from "../../types"; /** Force color scheme on a page */ -export const ForceColorScheme = (props: { colorScheme: ColorSchemeType }) => { - const [_, setState] = useForcedStore(); +export const ForceColorScheme = (props: { + colorScheme: ColorSchemeType; + targetSelector?: string; +}) => { + const [_, setState] = useForcedStore(props.targetSelector); useEffect(() => { setState(state => ({ ...state, fc: props.colorScheme })); return () => { diff --git a/lib/src/client/force-theme/force-theme.tsx b/lib/src/client/force-theme/force-theme.tsx index ee5be25d..dbfeb812 100644 --- a/lib/src/client/force-theme/force-theme.tsx +++ b/lib/src/client/force-theme/force-theme.tsx @@ -3,8 +3,8 @@ import { useEffect } from "react"; import { useForcedStore } from "../../store"; /** Force theme on a page */ -export const ForceTheme = (props: { theme: string }) => { - const [_, setState] = useForcedStore(); +export const ForceTheme = (props: { theme: string; targetSelector?: string }) => { + const [_, setState] = useForcedStore(props.targetSelector); useEffect(() => { setState(state => ({ ...state, f: props.theme })); return () => { diff --git a/lib/src/client/theme-switcher/no-fouc.ts b/lib/src/client/theme-switcher/no-fouc.ts index 9c51423f..54303bd5 100644 --- a/lib/src/client/theme-switcher/no-fouc.ts +++ b/lib/src/client/theme-switcher/no-fouc.ts @@ -2,7 +2,7 @@ import type { ThemeStoreType } from "../../store"; import type { ColorSchemeType, ResolvedColorSchemeType } from "../../types"; type ValuesType = [ResolvedColorSchemeType, ColorSchemeType, string, string]; -export type UpdateDOMFunc = (values: ValuesType) => void; +export type UpdateDOMFunc = (values: ValuesType, targetSelector: string) => void; export type ResolveFunc = (store: ThemeStoreType) => ValuesType; @@ -34,7 +34,7 @@ export const noFOUCScript = ( ) => { window.m = matchMedia("(prefers-color-scheme: dark)"); const keys = ["color-scheme", "csp", "theme", "th"]; - window.u = values => { + window.u = (values, key) => { const el = document.querySelector(key) ?? document.documentElement; let classes = []; keys.forEach((key, index) => { @@ -80,5 +80,5 @@ export const noFOUCScript = ( forcedTheme ?? store.t, ] as ValuesType; }; - u(r(store)); + u(r(store), key); }; diff --git a/lib/src/client/theme-switcher/theme-switcher.tsx b/lib/src/client/theme-switcher/theme-switcher.tsx index 70444086..ebac54c2 100644 --- a/lib/src/client/theme-switcher/theme-switcher.tsx +++ b/lib/src/client/theme-switcher/theme-switcher.tsx @@ -106,19 +106,19 @@ const Switcher = ({ useEffect(() => { const restoreThansitions = modifyTransition(themeTransition); - updateDOM(resolveTheme(state)); + updateDOM(resolveTheme(state), k); restoreThansitions(); localStorage.setItem(k, JSON.stringify(state)); }, [state]); useEffect(() => { updateForcedProps(forcedTheme, forcedColorScheme); - updateDOM(resolveTheme(state)); + updateDOM(resolveTheme(state), k); }, [forcedColorScheme, forcedTheme]); useEffect(() => { updateForcedState(forced.f, forced.fc); - updateDOM(resolveTheme(state)); + updateDOM(resolveTheme(state), k); }, [forced]); return null; }; diff --git a/packages/shared/CHANGELOG.md b/packages/shared/CHANGELOG.md index 2ba1f54a..62c4d454 100644 --- a/packages/shared/CHANGELOG.md +++ b/packages/shared/CHANGELOG.md @@ -1,5 +1,12 @@ # @repo/shared +## 0.0.7 + +### Patch Changes + +- Updated dependencies [a2fd744] + - nextjs-themes@4.0.1 + ## 0.0.6 ### Patch Changes diff --git a/packages/shared/package.json b/packages/shared/package.json index 94f13dbd..e6b54a6d 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,6 +1,6 @@ { "name": "@repo/shared", - "version": "0.0.6", + "version": "0.0.7", "private": true, "sideEffects": false, "main": "./dist/index.js", diff --git a/packages/shared/src/client/demo/demo.module.scss b/packages/shared/src/client/demo/demo.module.scss deleted file mode 100644 index d519e9d1..00000000 --- a/packages/shared/src/client/demo/demo.module.scss +++ /dev/null @@ -1,29 +0,0 @@ -.demo { - width: var(--max-width); - max-width: 95vw; - display: flex; - margin: auto; - margin-bottom: 3rem; - border-radius: 1rem; - overflow: hidden; - box-shadow: 0 0 8px -2px var(--text-color); - & > * { - flex-grow: 1; - } -} - -.preview { - padding: 10px; -} - -.center { - display: flex; - align-items: center; - justify-content: center; - height: 100%; - width: 100%; -} - -.code { - font-family: var(--font-mono); -} diff --git a/packages/shared/src/client/demo/demo.test.tsx b/packages/shared/src/client/demo/demo.test.tsx deleted file mode 100644 index ff21ac54..00000000 --- a/packages/shared/src/client/demo/demo.test.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { cleanup, render } from "@testing-library/react"; -import { afterEach, describe, test } from "vitest"; -import { Demo } from "./demo"; - -describe.concurrent("demo", () => { - afterEach(cleanup); - - test("Dummy test - test if renders without errors", () => { - render(); - }); -}); diff --git a/packages/shared/src/client/demo/demo.tsx b/packages/shared/src/client/demo/demo.tsx deleted file mode 100644 index 10f8ebdf..00000000 --- a/packages/shared/src/client/demo/demo.tsx +++ /dev/null @@ -1,24 +0,0 @@ -"use client"; - -import styles from "./demo.module.scss"; -import { LiveProvider, LiveEditor, LivePreview } from "react-live"; -import { Dots1, Dots2, Bars1, Bars2 } from "react18-loaders/dist/server"; - -const code = ` -// available components Dots1, Dots2, Bars1, Bars2 -
- -
-`; - -/** React live demo */ -export function Demo() { - return ( - -
- - -
-
- ); -} diff --git a/packages/shared/src/client/index.ts b/packages/shared/src/client/index.ts index 56067660..64839f6b 100644 --- a/packages/shared/src/client/index.ts +++ b/packages/shared/src/client/index.ts @@ -7,7 +7,7 @@ */ // client component exports -export * from "./demo"; +export * from "./scoped-themes"; export * from "./header"; export * from "./global-loader"; export * from "./drawer-button"; diff --git a/packages/shared/src/client/demo/index.ts b/packages/shared/src/client/scoped-themes/index.ts similarity index 52% rename from packages/shared/src/client/demo/index.ts rename to packages/shared/src/client/scoped-themes/index.ts index 14920cfb..f5ac7bd4 100644 --- a/packages/shared/src/client/demo/index.ts +++ b/packages/shared/src/client/scoped-themes/index.ts @@ -1,4 +1,4 @@ "use client"; // component exports -export * from "./demo"; +export * from "./scoped-themes"; diff --git a/packages/shared/src/client/scoped-themes/scoped-themes.tsx b/packages/shared/src/client/scoped-themes/scoped-themes.tsx new file mode 100644 index 00000000..55fc6744 --- /dev/null +++ b/packages/shared/src/client/scoped-themes/scoped-themes.tsx @@ -0,0 +1,20 @@ +"use client"; +import { ColorSwitch, ThemeSwitcher } from "nextjs-themes"; +import { ThemeController } from "../theme-controller"; + +export function ScopedThemes() { + const id = "scoped-themes"; + const targetSelector = `#${id}`; + return ( +
+

+ Apply themes locally using targetSelector +

+ + + +
+ ); +} diff --git a/packages/shared/src/client/theme-controller/color-scheme-preference.tsx b/packages/shared/src/client/theme-controller/color-scheme-preference.tsx index 48fcad7a..bd98fbd9 100644 --- a/packages/shared/src/client/theme-controller/color-scheme-preference.tsx +++ b/packages/shared/src/client/theme-controller/color-scheme-preference.tsx @@ -7,8 +7,8 @@ import styles from "./theme-controller.module.scss"; const colorSchemes: ColorSchemeType[] = ["", "system", "light", "dark"]; -export function ColorSchemePreference() { - const { colorSchemePref, setColorSchemePref } = useTheme(); +export function ColorSchemePreference({ targetSelector }: { targetSelector?: string }) { + const { colorSchemePref, setColorSchemePref } = useTheme(targetSelector); const handleChange: (e: ChangeEvent) => void = e => setColorSchemePref(e.target.value as ColorSchemeType); diff --git a/packages/shared/src/client/theme-controller/theme-controller.tsx b/packages/shared/src/client/theme-controller/theme-controller.tsx index 5efe7684..6261f062 100644 --- a/packages/shared/src/client/theme-controller/theme-controller.tsx +++ b/packages/shared/src/client/theme-controller/theme-controller.tsx @@ -2,16 +2,21 @@ import styles from "./theme-controller.module.scss"; import { ColorSchemePreference } from "./color-scheme-preference"; import { ThemeSelector } from "./theme-selector"; -export function ThemeController() { +export interface ThemeControllerProps { + targetSelector?: string; +} + +/** ThemeController */ +export function ThemeController({ targetSelector }: ThemeControllerProps) { return (
- - + +
- - + +
); diff --git a/packages/shared/src/client/theme-controller/theme-selector.tsx b/packages/shared/src/client/theme-controller/theme-selector.tsx index 4dab1d28..6b5cff74 100644 --- a/packages/shared/src/client/theme-controller/theme-selector.tsx +++ b/packages/shared/src/client/theme-controller/theme-selector.tsx @@ -6,13 +6,14 @@ import type { ChangeEvent } from "react"; import { Select } from "../select"; import styles from "./theme-controller.module.scss"; import { darkThemes, lightThemes } from "./themes"; +import { ThemeControllerProps } from "./theme-controller"; -interface ThemeSelectorProps { +interface ThemeSelectorProps extends ThemeControllerProps { scope: "" | "dark" | "light"; } -export function ThemeSelector({ scope }: ThemeSelectorProps) { - const { colorSchemePref, theme, setTheme } = useThemeStates(scope); +export function ThemeSelector({ scope, targetSelector }: ThemeSelectorProps) { + const { colorSchemePref, theme, setTheme } = useThemeStates(scope, targetSelector); const themes = useMemo(() => { switch (scope) { case "": @@ -49,9 +50,9 @@ function getClassName(scope: ThemeSelectorProps["scope"], colorSchemePref: Color return colorSchemePref === "system" ? styles[scope] : ""; } -function useThemeStates(scope: ThemeSelectorProps["scope"]) { +function useThemeStates(scope: ThemeSelectorProps["scope"], targetSelector?: string) { const { colorSchemePref, theme, darkTheme, lightTheme, setTheme, setDarkTheme, setLightTheme } = - useTheme(); + useTheme(targetSelector); switch (scope) { case "": return { colorSchemePref, theme, setTheme }; diff --git a/packages/shared/src/global.scss b/packages/shared/src/global.scss index 23d0ed8f..8e1d624d 100644 --- a/packages/shared/src/global.scss +++ b/packages/shared/src/global.scss @@ -21,7 +21,7 @@ /* dark themes */ .dark, -.dark ~ * { +.scoped.dark { --bg-color: #000; --text-color: #9ca3af; --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0)); @@ -41,7 +41,7 @@ /* light themes */ .light, -.light ~ * { +.scoped.light { --bg-color: #fff; --text-color: #534c40; --primary-glow: conic-gradient( @@ -56,29 +56,29 @@ /* dark themes */ [data-theme="dark"], -[data-theme="dark"] ~ * { +[data-theme="dark"].scoped { --bg-color: #000; --text-color: #fff; } [data-theme="gray"], -[data-theme="gray"] ~ * { +[data-theme="gray"].scoped { --bg-color: gray; --text-color: #fff; } [data-theme="dark-blue"], -[data-theme="dark-blue"] ~ * { +[data-theme="dark-blue"].scoped { --bg-color: #006; --text-color: #ff0; } [data-theme="dark"], -[data-theme="dark"] ~ *, +[data-theme="dark"].scoped, [data-theme="gray"], -[data-theme="gray"] ~ *, +[data-theme="gray"].scoped, [data-theme="dark-blue"], -[data-theme="dark-blue"] ~ * { +[data-theme="dark-blue"].scoped { --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0)); --secondary-glow: linear-gradient( to bottom right, @@ -105,19 +105,19 @@ /* light themes */ [data-theme="white"], -[data-theme="white"] ~ * { +[data-theme="white"].scoped { --bg-color: #fff; --text-color: #000; } [data-theme="yellow"], -[data-theme="yellow"] ~ * { +[data-theme="yellow"].scoped { --bg-color: #ff0; --text-color: #00f; } [data-theme="orange"], -[data-theme="orange"] ~ * { +[data-theme="orange"].scoped { --bg-color: #ffa500; --text-color: #05f; }