Skip to content

Commit b767b57

Browse files
authored
Merge pull request #12 from react18-tools/refactor
Refactor
2 parents 89b234f + d11601d commit b767b57

File tree

10 files changed

+104
-74
lines changed

10 files changed

+104
-74
lines changed

.github/workflows/publish.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ on:
88

99
jobs:
1010
publish:
11-
# Don't run just after creating repo from template
12-
# Also avoid running after merging set-up PR
13-
if: github.run_number > 2 && github.event.repository.owner.login == 'react18-tools'
11+
if: github.event.repository.owner.login == 'react18-tools'
1412
runs-on: ubuntu-latest
1513
permissions:
1614
contents: write
@@ -35,7 +33,7 @@ jobs:
3533
- name: Test
3634
run: pnpm test
3735
- name: Copy Readme file
38-
run: cp ./README.md ./lib # will be uncommented while rebranding
36+
run: cp ./README.md ./lib
3937
- name: Apply changesets, publish and create release, branches and tags
4038
run: node ./scripts/publish.js
4139
env:

lib/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# nthul
22

3+
## 1.0.1
4+
5+
### Patch Changes
6+
7+
- Refactor to minify
8+
39
## 1.0.0
410

511
### Major Changes

lib/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "nthul",
33
"author": "Mayank Kumar Chaudhari <https://mayank-chaudhari.vercel.app>",
44
"private": false,
5-
"version": "1.0.0",
5+
"version": "1.0.1",
66
"description": "Unleash the Power of React Server Components! Use multiple themes on your site with confidence, without losing any advantages of React Server Components.",
77
"license": "MPL-2.0",
88
"main": "./dist/index.js",

lib/src/client/color-switch/color-switch.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ interface ColorSwitchProps extends HTMLProps<HTMLDivElement> {
2727
*
2828
* @source - Source code
2929
*/
30-
export function ColorSwitch({ targetId, skipSystem, size, ...props }: ColorSwitchProps) {
30+
export const ColorSwitch = ({ targetId, skipSystem, size, ...props }: ColorSwitchProps) => {
3131
const {
3232
setColorSchemePreference,
3333
resolvedColorScheme: rcs,

lib/src/client/theme-switcher/theme-switcher.tsx

Lines changed: 33 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import useRGS from "r18gs";
21
import type { SetStateAction } from "r18gs";
32
import type { ColorSchemePreference, ThemeState } from "../../constants";
4-
import { DEFAULT_ID, DEFAULT_THEME_STATE } from "../../constants";
3+
import { DEFAULT_ID, useRGSMinify } from "../../constants";
54
import { useEffect } from "react";
6-
5+
const useEffectMinify = useEffect;
76
export interface ThemeSwitcherProps {
87
/** id of target element to apply classes to. This is useful when you want to apply theme only to specific container. */
98
targetId?: string;
@@ -17,11 +16,11 @@ export interface ThemeSwitcherProps {
1716

1817
/** Add media query listener */
1918
const useMediaQuery = (setThemeState: SetStateAction<ThemeState>) => {
20-
useEffect(() => {
19+
useEffectMinify(() => {
2120
// set event listener for media
2221
const media = matchMedia("(prefers-color-scheme: dark)");
2322
const updateSystemColorScheme = () => {
24-
setThemeState(state => ({ ...state, systemColorScheme: media.matches ? "dark" : "light" }));
23+
setThemeState(state => ({ ...state, s: media.matches ? "dark" : "light" }));
2524
};
2625
updateSystemColorScheme();
2726
media.addEventListener("change", updateSystemColorScheme);
@@ -31,65 +30,57 @@ const useMediaQuery = (setThemeState: SetStateAction<ThemeState>) => {
3130
}, [setThemeState]);
3231
};
3332

34-
export interface LoadSyncedStateProps extends ThemeSwitcherProps {
35-
setThemeState: SetStateAction<ThemeState>;
36-
}
37-
38-
const parseState = (str?: string | null) => {
33+
const parseState = (str?: string | null): Partial<ThemeState> => {
3934
const parts = (str ?? ",system").split(",") as [string, ColorSchemePreference];
40-
return { theme: parts[0], colorSchemePreference: parts[1] };
35+
return { t: parts[0], c: parts[1] };
4136
};
4237

4338
let tInit = 0;
4439

45-
const useLoadSyncedState = ({ dontSync, targetId, setThemeState }: LoadSyncedStateProps) => {
46-
useEffect(() => {
40+
const useLoadSyncedState = ( setThemeState: SetStateAction<ThemeState>, dontSync?:boolean, targetId?:string ) => {
41+
useEffectMinify(() => {
4742
if (dontSync) return;
4843
tInit = Date.now();
4944
const key = targetId ?? DEFAULT_ID;
5045
setThemeState(state => ({ ...state, ...parseState(localStorage.getItem(key)) }));
51-
const storageListener = (e: StorageEvent) => {
46+
const storageListener = (e: StorageEvent):void => {
5247
if (e.key === key) setThemeState(state => ({ ...state, ...parseState(e.newValue) }));
5348
};
54-
window.addEventListener("storage", storageListener);
49+
addEventListener("storage", storageListener);
50+
// skipcq: JS-0045
5551
return () => {
56-
window.removeEventListener("storage", storageListener);
52+
removeEventListener("storage", storageListener);
5753
};
5854
}, [dontSync, setThemeState, targetId]);
5955
};
6056

6157
const modifyTransition = (themeTransition = "none", targetId?: string) => {
62-
const css = document.createElement("style");
58+
const documentMinify = document;
59+
const css = documentMinify.createElement("style");
6360
/** split by ';' to prevent CSS injection */
6461
const transition = `transition: ${themeTransition.split(";")[0]} !important;`;
6562
const targetSelector = targetId
6663
? `#${targetId},#${targetId} *,#${targetId} ~ *,#${targetId} ~ * *`
6764
: "*";
6865
css.appendChild(
69-
document.createTextNode(
66+
documentMinify.createTextNode(
7067
`${targetSelector}{-webkit-${transition}-moz-${transition}-o-${transition}-ms-${transition}${transition}}`,
7168
),
7269
);
73-
document.head.appendChild(css);
70+
documentMinify.head.appendChild(css);
7471

7572
return () => {
7673
// Force restyle
77-
(() => window.getComputedStyle(document.body))();
74+
(() => getComputedStyle(documentMinify.body))();
7875
// Wait for next tick before removing
7976
setTimeout(() => {
80-
document.head.removeChild(css);
77+
documentMinify.head.removeChild(css);
8178
}, 1);
8279
};
8380
};
8481

85-
export interface ApplyClassesProps {
86-
targets: (HTMLElement | null)[];
87-
theme: string;
88-
resolvedColorScheme: "light" | "dark";
89-
styles?: Record<string, string>;
90-
}
91-
92-
const applyClasses = ({ targets, theme, resolvedColorScheme, styles }: ApplyClassesProps) => {
82+
/** Apply classes to the targets */
83+
const applyClasses = ( targets: (HTMLElement | null)[], theme: string, resolvedColorScheme: "light" | "dark", styles?: Record<string, string>) => {
9384
let cls = ["dark", "light", `th-${theme}`, resolvedColorScheme];
9485
if (styles) cls = cls.map(c => styles[c] ?? c);
9586

@@ -104,29 +95,24 @@ const applyClasses = ({ targets, theme, resolvedColorScheme, styles }: ApplyClas
10495
});
10596
};
10697

107-
export interface UpdateDOMProps {
108-
targetId?: string;
109-
themeState: ThemeState;
110-
dontSync?: boolean;
111-
styles?: Record<string, string>;
112-
}
113-
114-
const updateDOM = ({ targetId, themeState, dontSync, styles }: UpdateDOMProps) => {
115-
const { theme, colorSchemePreference: csp, systemColorScheme: scs } = themeState;
98+
/** Update DOM */
99+
const updateDOM = (themeState: ThemeState, targetId?: string, dontSync?: boolean, styles?:Record<string, string>) => {
100+
const { t: theme, c: csp, s: scs } = themeState;
116101
const resolvedColorScheme = csp === "system" ? scs : csp;
117102
const key = targetId ?? DEFAULT_ID;
118103
// update DOM
119104
let shoulCreateCookie = false;
120-
const target = document.getElementById(key);
105+
const documentMinify = document;
106+
const target = documentMinify.getElementById(key);
121107
shoulCreateCookie = !dontSync && target?.getAttribute("data-nth") === "next";
122108

123109
/** do not update documentElement for local targets */
124-
const targets = targetId ? [target] : [target, document.documentElement];
110+
const targets = targetId ? [target] : [target, documentMinify.documentElement];
125111

126-
applyClasses({ targets, styles, resolvedColorScheme, theme });
112+
applyClasses( targets,theme, resolvedColorScheme, styles);
127113

128114
if (shoulCreateCookie)
129-
document.cookie = `${key}=${theme},${resolvedColorScheme}; max-age=31536000; SameSite=Strict;`;
115+
documentMinify.cookie = `${key}=${theme},${resolvedColorScheme}; max-age=31536000; SameSite=Strict;`;
130116
};
131117

132118
/**
@@ -140,22 +126,19 @@ export const ThemeSwitcher = ({
140126
styles,
141127
}: ThemeSwitcherProps) => {
142128
if (targetId === "") throw new Error("id can not be an empty string");
143-
const [themeState, setThemeState] = useRGS<ThemeState>(
144-
targetId ?? DEFAULT_ID,
145-
DEFAULT_THEME_STATE,
146-
);
129+
const [themeState, setThemeState] = useRGSMinify(targetId);
147130

148131
useMediaQuery(setThemeState);
149132

150-
useLoadSyncedState({ dontSync, targetId, setThemeState });
133+
useLoadSyncedState(setThemeState , dontSync, targetId);
151134

152135
/** update DOM and storage */
153-
useEffect(() => {
136+
useEffectMinify(() => {
154137
const restoreTransitions = modifyTransition(themeTransition, targetId);
155-
updateDOM({ targetId, themeState, dontSync, styles });
138+
updateDOM(themeState, targetId, dontSync, styles);
156139
if (!dontSync && tInit < Date.now() - 300) {
157140
// save to localStorage
158-
const { theme, colorSchemePreference } = themeState;
141+
const { t: theme, c: colorSchemePreference } = themeState;
159142
const stateToSave = [theme, colorSchemePreference].join(",");
160143
const key = targetId ?? DEFAULT_ID;
161144
localStorage.setItem(key, stateToSave);

lib/src/constants.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
1+
import useRGS from "r18gs";
2+
13
/** shared constants -- keep in separate files for better tree-shaking and dependency injection */
24
export const DEFAULT_ID = "nthul";
35

46
export type ColorSchemePreference = "system" | "dark" | "light";
57

68
export interface ThemeState {
7-
colorSchemePreference: ColorSchemePreference;
8-
systemColorScheme: "dark" | "light";
9-
theme: string;
9+
/** ColorSchemePreference */
10+
c: ColorSchemePreference;
11+
/** SystemColorScheme */
12+
s: "dark" | "light";
13+
/** Theme */
14+
t: string;
1015
}
1116

12-
export const DEFAULT_THEME_STATE = {
13-
colorSchemePreference: "system" as ColorSchemePreference,
14-
systemColorScheme: "light" as "light" | "dark",
15-
theme: "",
17+
const DEFAULT_THEME_STATE:ThemeState = {
18+
c: "system" as ColorSchemePreference,
19+
s: "light",
20+
t: "",
1621
};
22+
23+
/** To avoid multiple r18gs imports */
24+
export const useRGSMinify = (targetId?:string) => useRGS<ThemeState>(targetId??DEFAULT_ID, DEFAULT_THEME_STATE);

lib/src/hooks/use-theme.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import useRGS from "r18gs";
2-
import type { ColorSchemePreference, ThemeState } from "../constants";
3-
import { DEFAULT_ID, DEFAULT_THEME_STATE } from "../constants";
1+
import type { ColorSchemePreference } from "../constants";
2+
import { useRGSMinify } from "../constants";
43

54
export interface UseTheme {
65
theme: string;
@@ -17,16 +16,18 @@ export interface UseTheme {
1716
* @returns themeState and setter fucntions
1817
*/
1918
export const useTheme = (targetId?: string): UseTheme => {
20-
const [themeState, setState] = useRGS<ThemeState>(targetId ?? DEFAULT_ID, DEFAULT_THEME_STATE);
21-
const { colorSchemePreference: csp, systemColorScheme: scs } = themeState;
19+
const [themeState, setState] = useRGSMinify(targetId);
20+
const { c: csp, s: scs, t } = themeState;
2221
return {
23-
...themeState,
22+
theme: t,
23+
colorSchemePreference: csp,
24+
systemColorScheme: scs,
2425
resolvedColorScheme: csp === "system" ? scs : csp,
2526
setColorSchemePreference: (colorSchemePreference: ColorSchemePreference) => {
26-
setState({ ...themeState, colorSchemePreference });
27+
setState({ ...themeState, c: colorSchemePreference });
2728
},
2829
setTheme: (theme: string) => {
29-
setState({ ...themeState, theme });
30+
setState({ ...themeState, t: theme });
3031
},
3132
};
3233
};

packages/shared/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# @repo/shared
22

3+
## 0.0.2
4+
5+
### Patch Changes
6+
7+
- Updated dependencies
8+
9+
310
## 0.0.1
411

512
### Patch Changes

packages/shared/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@repo/shared",
3-
"version": "0.0.1",
3+
"version": "0.0.2",
44
"private": true,
55
"sideEffects": false,
66
"main": "./dist/index.js",

scripts/publish.js

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
/** It is assumed that this is called only from the default branch. */
2-
const { execSync } = require("child_process");
2+
const { execSync, exec } = require("child_process");
3+
const fs = require("fs");
4+
const path = require("path");
35

46
// Apply changesets if any -- e.g., coming from pre-release branches
57
try {
@@ -16,7 +18,8 @@ try {
1618
// no changesets to be applied
1719
}
1820

19-
const { version: VERSION, name } = require("../lib/package.json");
21+
const packageJSON = require("../lib/package.json");
22+
const { version: VERSION, name } = packageJSON;
2023
const LATEST_VERSION = execSync(`npm view ${name} version`).toString();
2124

2225
console.log({ VERSION, LATEST_VERSION });
@@ -39,3 +42,27 @@ execSync("cd lib && pnpm build && npm publish --provenance --access public");
3942
execSync(
4043
`gh release create ${VERSION} --generate-notes --latest -n "$(sed '1,/^## /d;/^## /,$d' CHANGELOG.md)" --title "Release v${VERSION}"`,
4144
);
45+
46+
// update canonicals
47+
48+
const publishCanonical = (canonical) => {
49+
packageJSON.name = canonical;
50+
fs.writeFileSync(pkgPath, JSON.stringify(packageJSON, null, 2));
51+
exec("cd lib && pnpm build && npm publish --provenance --access public");
52+
}
53+
54+
const canonicals = [`@mayank1513/${name}`, 'nextjs-themes-ultra']
55+
const pkgPath = path.join(__dirname, "../lib/package.json");
56+
canonicals.forEach(publishCanonical);
57+
58+
// lite version
59+
packageJson.peerDependencies.r18gs = "^1";
60+
delete packageJson.dependencies;
61+
62+
const liteCanonicals = ['nthul-lite', '@mayank1513/nthul-lite', 'nextjs-themes-ultralite'];
63+
64+
liteCanonicals.forEach(publishCanonical);
65+
66+
const toDeprecate = ['@mayank1513/nthul', '@mayank1513/nthul-lite']
67+
68+
toDeprecate.forEach(pkg => exec(`npm deprecate ${pkg} "Please use <https://www.npmjs.com/package/${pkg.slice('/')[1]}> instead. We initially created scoped packages to have similarities with the GitHub Public Repository (which requires packages to be scoped). We are no longer using GPR and thus deprecating all scoped packages for which corresponding un-scoped packages exist.`))

0 commit comments

Comments
 (0)