Skip to content

Commit

Permalink
Merge pull request #25 from react18-tools/scoped-css
Browse files Browse the repository at this point in the history
Add support for Scoped CSS or CSS modules
  • Loading branch information
mayank1513 authored Feb 27, 2024
2 parents 2da0d4f + 6bc0dfd commit 49e18b0
Show file tree
Hide file tree
Showing 17 changed files with 93 additions and 39 deletions.
1 change: 1 addition & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ jobs:
- run: node lite.js && pnpm build && pnpm publish-package && node scope.js && pnpm publish-package
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
OWNER: ${{ github.event.repository.owner.login }}

- name: Mark scoped package as deprecated
run: |
Expand Down
8 changes: 8 additions & 0 deletions examples/app-router/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# app-router

## 0.0.20

### Patch Changes

- Updated dependencies
- [email protected]
- [email protected]

## 0.0.19

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion examples/app-router/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "app-router",
"version": "0.0.19",
"version": "0.0.20",
"private": true,
"scripts": {
"dev": "next dev --port 3002",
Expand Down
8 changes: 8 additions & 0 deletions examples/pages-router/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# nextjs-pages-router

## 1.0.15

### Patch Changes

- Updated dependencies
- [email protected]
- [email protected]

## 1.0.14

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion examples/pages-router/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pages-router",
"version": "1.0.14",
"version": "1.0.15",
"private": true,
"scripts": {
"dev": "next dev --port 3003",
Expand Down
8 changes: 8 additions & 0 deletions examples/simple-multi-theme/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# simple-multi-theme

## 1.0.15

### Patch Changes

- Updated dependencies
- [email protected]
- [email protected]

## 1.0.14

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion examples/simple-multi-theme/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "simple-multi-theme",
"version": "1.0.14",
"version": "1.0.15",
"private": true,
"scripts": {
"dev": "next dev --port 3001",
Expand Down
7 changes: 7 additions & 0 deletions examples/tailwind/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# tailwind

## 0.1.9

### Patch Changes

- Updated dependencies
- [email protected]

## 0.1.8

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion examples/tailwind/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tailwind",
"version": "0.1.8",
"version": "0.1.9",
"private": true,
"scripts": {
"dev": "next dev",
Expand Down
8 changes: 8 additions & 0 deletions examples/vite/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# vite-example

## 0.0.20

### Patch Changes

- Updated dependencies
- [email protected]
- [email protected]

## 0.0.19

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion examples/vite/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "vite-example",
"private": true,
"version": "0.0.19",
"version": "0.0.20",
"type": "module",
"scripts": {
"dev": "vite --port 3001",
Expand Down
6 changes: 6 additions & 0 deletions lib/nextjs-themes/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# nextjs-themes

## 3.1.0

### Minor Changes

- Add support for CSS modules and minor fixes.

## 3.0.0

### Major Changes
Expand Down
2 changes: 1 addition & 1 deletion lib/nextjs-themes/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": "3.0.0",
"version": "3.1.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.",
"main": "./index.ts",
"types": "./index.ts",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { act, cleanup, fireEvent, render, renderHook, screen } from "@testing-library/react";
import { ColorSwitch } from "./color-switch";
import { useTheme } from "../../hooks";
import { afterEach, describe, test } from "vitest";

describe("color-switch", () => {
afterEach(cleanup);
Expand Down
12 changes: 8 additions & 4 deletions lib/nextjs-themes/src/client/theme-switcher/theme-switcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export interface ThemeSwitcherProps {
forcedColorScheme?: ColorSchemeType;
targetSelector?: string;
themeTransition?: string;
/** provide styles object imported from CSS/SCSS modules, if you are using CSS/SCSS modules. */
styles?: Record<string, string>;
}

function useMediaQuery(setThemeState: SetStateAction<ThemeStoreType>) {
Expand Down Expand Up @@ -63,14 +65,16 @@ export interface UpdateProps {

const updateDOM = (
{ resolvedTheme, resolvedColorScheme, resolvedColorSchemePref, th }: UpdateProps,
targetSelector?: string,
props: ThemeSwitcherProps,
) => {
const { targetSelector, styles } = props;
const target = document.querySelector(targetSelector || `#${DEFAULT_ID}`);
let classes = [resolvedColorScheme, `theme-${resolvedTheme}`, `th-${th}`, `csp-${resolvedColorSchemePref}`];
if (styles) classes = classes.map(cls => styles[cls] ?? cls);
/** don't apply theme to documentElement for localized targets */
[target, targetSelector && target ? null : document.documentElement].forEach(target => {
/** ensuring that class 'dark' is always present when dark color scheme is applied to support Tailwind */
if (target)
target.className = `${resolvedColorScheme} theme-${resolvedTheme} th-${th} csp-${resolvedColorSchemePref}`;
if (target) target.className = classes.join(" ");
target?.setAttribute("data-th", th);
target?.setAttribute("data-theme", resolvedTheme);
target?.setAttribute("data-color-scheme", resolvedColorScheme);
Expand Down Expand Up @@ -112,7 +116,7 @@ export function useThemeSwitcher(props: ThemeSwitcherProps) {
const restoreTransitions = disableAnimation(props.themeTransition);

const resolvedData = resolveTheme(themeState, props);
const shouldCreateCookie = updateDOM(resolvedData, props.targetSelector);
const shouldCreateCookie = updateDOM(resolvedData, props);
if (tInit < Date.now() - 300) {
const stateStr = encodeState(themeState);
const key = props.targetSelector || DEFAULT_ID;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,41 @@ export interface NextJsSSRThemeSwitcherProps extends HTMLProps<HTMLElement> {
forcedPages?: ForcedPage[];
/** id of target element to apply classes to. This is useful when you want to apply theme only to specific container. */
targetId?: string;
/** provide styles object imported from CSS/SCSS modules, if you are using CSS/SCSS modules. */
styles?: Record<string, string>;
}

function getDataProps(resolvedData: UpdateProps, styles?: Record<string, string>) {
const dataProps: DataProps = { className: "" };
let classeNames = [];
if (resolvedData.resolvedColorScheme !== undefined) {
dataProps["data-color-scheme"] = resolvedData.resolvedColorScheme;
classeNames.push(resolvedData.resolvedColorScheme);
}
if (resolvedData.resolvedTheme !== undefined) {
dataProps["data-theme"] = resolvedData.resolvedTheme;
classeNames.push(`theme-${resolvedData.resolvedTheme}`);
}
if (resolvedData.th) {
dataProps["data-th"] = resolvedData.th;
classeNames.push(`th-${resolvedData.th}`);
}
if (resolvedData.resolvedColorSchemePref !== undefined) {
dataProps["data-csp"] = resolvedData.resolvedColorSchemePref;
classeNames.push(`csp-${resolvedData.resolvedColorSchemePref}`);
}
if (styles) classeNames = classeNames.map(cls => styles[cls] ?? cls);
dataProps.className = classeNames.join(" ");
return dataProps;
}

function sharedServerComponentRenderer(
{ children, tag, forcedPages, targetId, ...props }: NextJsSSRThemeSwitcherProps,
{ children, tag, forcedPages, targetId, styles, ...props }: NextJsSSRThemeSwitcherProps,
defaultTag: "div" | "html",
) {
const Tag: keyof JSX.IntrinsicElements = tag || defaultTag;
const state = cookies().get(DEFAULT_ID)?.value;
const key = targetId ? `#${targetId}` : DEFAULT_ID;
const state = cookies().get(key)?.value;

const path = headers().get("referer");
const forcedPage = forcedPages?.find(forcedPage =>
Expand All @@ -34,8 +61,8 @@ function sharedServerComponentRenderer(
: forcedPage?.props;
const themeState = state ? (parseState(state) as ThemeStoreType) : undefined;
const resolvedData = resolveTheme(themeState, forcedPageProps);
const dataProps = getDataProps(resolvedData);
if(targetId) dataProps.className += " nth-scoped";
const dataProps = getDataProps(resolvedData, styles);
if (targetId) dataProps.className += styles?.[" nth-scoped"] ?? " nth-scoped";

return (
// @ts-expect-error -> svg props and html element props conflict
Expand All @@ -45,27 +72,6 @@ function sharedServerComponentRenderer(
);
}

function getDataProps(resolvedData: UpdateProps) {
const dataProps: DataProps = { className: "" };
if (resolvedData.resolvedColorScheme !== undefined) {
dataProps["data-color-scheme"] = resolvedData.resolvedColorScheme;
dataProps.className = resolvedData.resolvedColorScheme;
}
if (resolvedData.resolvedTheme !== undefined) {
dataProps["data-theme"] = resolvedData.resolvedTheme;
dataProps.className += `theme-${resolvedData.resolvedTheme}`;
}
if (resolvedData.th) {
dataProps["data-th"] = resolvedData.th;
dataProps.className += ` th-${resolvedData.th}`;
}
if (resolvedData.resolvedColorSchemePref !== undefined) {
dataProps["data-csp"] = resolvedData.resolvedColorSchemePref;
dataProps.className += ` csp-${resolvedData.resolvedColorSchemePref}`;
}
return dataProps;
}

/**
* @example
* ```tsx
Expand Down
5 changes: 1 addition & 4 deletions lib/nextjs-themes/vitest.setup.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import useRGS from "r18gs";
import { vi, beforeEach } from "vitest";
import { DEFAULT_ID, initialState } from "./src/constants";
import { act, renderHook } from "@testing-library/react";
import { vi } from "vitest";

// mock matchMedia
Object.defineProperty(window, "matchMedia", {
Expand Down

0 comments on commit 49e18b0

Please sign in to comment.