From 4a41da1e8fe9fc8916d4d3601ce4928858d0eb11 Mon Sep 17 00:00:00 2001 From: Mayank Kumar Chaudhari Date: Fri, 19 Apr 2024 18:13:23 +0530 Subject: [PATCH 1/6] Fix non-null assertion --- examples/vite/src/main.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/vite/src/main.tsx b/examples/vite/src/main.tsx index 1f270783..684a45aa 100644 --- a/examples/vite/src/main.tsx +++ b/examples/vite/src/main.tsx @@ -3,7 +3,10 @@ import ReactDOM from "react-dom/client"; import App from "./App.tsx"; import { SharedRootLayout } from "shared-ui"; -ReactDOM.createRoot(document.getElementById("root")!).render( +const rootElement = document.getElementById("root"); +if (!rootElement) throw new Error("Root element not found"); + +ReactDOM.createRoot(rootElement).render( From 7916a8a3b90da8689dc5c8cb1f530e7c79feaddd Mon Sep 17 00:00:00 2001 From: Mayank Kumar Chaudhari Date: Sat, 20 Apr 2024 08:05:12 +0530 Subject: [PATCH 2/6] refactor --- lib/r18gs/src/use-rgs.ts | 79 +++++++++++++------------- packages/shared-ui/src/root-layout.tsx | 2 +- 2 files changed, 40 insertions(+), 41 deletions(-) diff --git a/lib/r18gs/src/use-rgs.ts b/lib/r18gs/src/use-rgs.ts index b7818137..f70d3eab 100644 --- a/lib/r18gs/src/use-rgs.ts +++ b/lib/r18gs/src/use-rgs.ts @@ -1,27 +1,41 @@ /* eslint-disable @typescript-eslint/non-nullable-type-assertion-style -- as ! operator is forbidden by eslint*/ import { useSyncExternalStore } from "react"; -interface React18GlobalStore { - listeners: (() => void)[]; - value: unknown; -} - -export type SetterArgType = T | ((prevState: T) => T); - +type Listener = () => void; +type SetterArgType = T | ((prevState: T) => T); +type Subscriber = (l: Listener) => () => void; export type SetStateAction = (val: SetterArgType) => void; +/** + * This is a hack to reduce lib size + readability + not encouraging direct access to globalThis + */ +const [VALUE, LISTENERS, SETTER, SUBSCRIBER] = [0, 1, 2, 3]; +type RGS = [unknown, Listener[], SetStateAction, Subscriber]; + declare global { // eslint-disable-next-line no-var -- var required for global declaration. - var rgs: Record; - // eslint-disable-next-line no-var -- var required for global declaration. - var setters: Record | undefined>; - // eslint-disable-next-line no-var -- var required for global declaration. - var subscribers: Record void) => () => void) | undefined>; + var rgs: Record; } globalThis.rgs = {}; -globalThis.setters = {}; -globalThis.subscribers = {}; + +function init(key: string, value?: T) { + const listeners: Listener[] = []; + const setter: SetStateAction = val => { + const rgs = globalThis.rgs[key] as RGS; + rgs[VALUE] = val instanceof Function ? val(rgs[VALUE] as T) : val; + (rgs[LISTENERS] as Listener[]).forEach(listener => listener()); + }; + const subscriber: Subscriber = listener => { + const rgs = globalThis.rgs[key] as RGS; + const listeners = rgs[LISTENERS] as Listener[]; + listeners.push(listener); + return () => { + rgs[LISTENERS] = listeners.filter(l => l !== listener); + }; + }; + globalThis.rgs[key] = [value, listeners, setter as SetStateAction, subscriber]; +} /** * Use this hook similar to `useState` hook. @@ -34,34 +48,19 @@ globalThis.subscribers = {}; * const [state, setState] = useRGS("counter", 1); * ``` */ -export default function useRGS(key: string, value?: T): [T, (val: SetterArgType) => void] { - if (!globalThis.subscribers[key]) { - globalThis.subscribers[key] = (listener: () => void) => { - if (!globalThis.rgs[key]) { - /** opportunity to add initializer */ - globalThis.rgs[key] = { listeners: [], value }; - } - const rgs = globalThis.rgs[key] as React18GlobalStore; - rgs.listeners.push(listener); - return () => { - rgs.listeners = rgs.listeners.filter(l => l !== listener); - }; - }; - } - const subscribe = globalThis.subscribers[key] as (listener: () => void) => () => void; +export default function useRGS( + key: string, + value?: T, + serverValue?: T, +): [T, (val: SetterArgType) => void] { + if (!globalThis.rgs[key]) init(key, value); - if (!globalThis.setters[key]) { - globalThis.setters[key] = val => { - const rgs = globalThis.rgs[key] as React18GlobalStore; - rgs.value = val instanceof Function ? val(rgs.value as T) : val; - /** opportunity to add custom listener */ - for (const listener of rgs.listeners) listener(); - }; - } - const setRGState = globalThis.setters[key] as SetStateAction; + const rgs = globalThis.rgs[key] as RGS; - const getSnapshot = () => (globalThis.rgs[key]?.value ?? value) as T; + const setRGState = rgs[SETTER] as SetStateAction; + const getSnap = () => (rgs[VALUE] ?? value) as T; + const getServerSnap = () => (serverValue ?? value) as T; - const val = useSyncExternalStore(subscribe, getSnapshot, getSnapshot); + const val = useSyncExternalStore(rgs[SUBSCRIBER] as Subscriber, getSnap, getServerSnap); return [val, setRGState]; } diff --git a/packages/shared-ui/src/root-layout.tsx b/packages/shared-ui/src/root-layout.tsx index 650b82d8..171001ae 100644 --- a/packages/shared-ui/src/root-layout.tsx +++ b/packages/shared-ui/src/root-layout.tsx @@ -1,7 +1,7 @@ import "./globals.css"; import "nthul-lite/styles.css"; import { ThemeSwitcher } from "nthul-lite/client/theme-switcher"; -import { ForkMe } from "@mayank1513/fork-me/server"; // todo: import directory not supported in remix +import { ForkMe } from "@mayank1513/fork-me/server"; import type { HTMLProps } from "react"; import styles from "./root-layout.module.css"; import { Cards } from "./cards"; From a4915ebf92e56513498c83c3f4c25bbb4123c3e2 Mon Sep 17 00:00:00 2001 From: Mayank Kumar Chaudhari Date: Sat, 20 Apr 2024 08:13:21 +0530 Subject: [PATCH 3/6] Add doc comments. --- lib/r18gs/src/use-rgs.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/r18gs/src/use-rgs.ts b/lib/r18gs/src/use-rgs.ts index f70d3eab..8f100850 100644 --- a/lib/r18gs/src/use-rgs.ts +++ b/lib/r18gs/src/use-rgs.ts @@ -19,13 +19,16 @@ declare global { globalThis.rgs = {}; +/** Initialize the named store when invoked for the first time. */ function init(key: string, value?: T) { const listeners: Listener[] = []; + /** setter function to set the state. */ const setter: SetStateAction = val => { const rgs = globalThis.rgs[key] as RGS; rgs[VALUE] = val instanceof Function ? val(rgs[VALUE] as T) : val; (rgs[LISTENERS] as Listener[]).forEach(listener => listener()); }; + /** subscriber function to subscribe to the store. */ const subscriber: Subscriber = listener => { const rgs = globalThis.rgs[key] as RGS; const listeners = rgs[LISTENERS] as Listener[]; @@ -57,9 +60,12 @@ export default function useRGS( const rgs = globalThis.rgs[key] as RGS; + /** Function to set the state. */ const setRGState = rgs[SETTER] as SetStateAction; + /** Function to get snapshot of the state. */ const getSnap = () => (rgs[VALUE] ?? value) as T; - const getServerSnap = () => (serverValue ?? value) as T; + /** Function to get server snapshot. Returns server value is provided else the default value. */ + const getServerSnap = () => (serverValue ?? rgs[VALUE] ?? value) as T; const val = useSyncExternalStore(rgs[SUBSCRIBER] as Subscriber, getSnap, getServerSnap); return [val, setRGState]; From 722837ffefd5f7c91aa7a1927baa422d4c3d2deb Mon Sep 17 00:00:00 2001 From: Mayank Kumar Chaudhari Date: Sat, 20 Apr 2024 08:45:04 +0530 Subject: [PATCH 4/6] Use Map in place of object --- lib/r18gs/src/use-rgs.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/r18gs/src/use-rgs.ts b/lib/r18gs/src/use-rgs.ts index 8f100850..d4cd0015 100644 --- a/lib/r18gs/src/use-rgs.ts +++ b/lib/r18gs/src/use-rgs.ts @@ -14,30 +14,32 @@ type RGS = [unknown, Listener[], SetStateAction, Subscriber]; declare global { // eslint-disable-next-line no-var -- var required for global declaration. - var rgs: Record; + var rgs: Map; } -globalThis.rgs = {}; +let g = globalThis; +g.rgs = new Map(); +let globalRGS = g.rgs; /** Initialize the named store when invoked for the first time. */ function init(key: string, value?: T) { const listeners: Listener[] = []; /** setter function to set the state. */ const setter: SetStateAction = val => { - const rgs = globalThis.rgs[key] as RGS; + const rgs = globalRGS.get(key) as RGS; rgs[VALUE] = val instanceof Function ? val(rgs[VALUE] as T) : val; (rgs[LISTENERS] as Listener[]).forEach(listener => listener()); }; /** subscriber function to subscribe to the store. */ const subscriber: Subscriber = listener => { - const rgs = globalThis.rgs[key] as RGS; + const rgs = globalRGS.get(key) as RGS; const listeners = rgs[LISTENERS] as Listener[]; listeners.push(listener); return () => { rgs[LISTENERS] = listeners.filter(l => l !== listener); }; }; - globalThis.rgs[key] = [value, listeners, setter as SetStateAction, subscriber]; + globalRGS.set(key, [value, listeners, setter as SetStateAction, subscriber]); } /** @@ -56,9 +58,9 @@ export default function useRGS( value?: T, serverValue?: T, ): [T, (val: SetterArgType) => void] { - if (!globalThis.rgs[key]) init(key, value); + if (!globalRGS.has(key)) init(key, value); - const rgs = globalThis.rgs[key] as RGS; + const rgs = globalRGS.get(key) as RGS; /** Function to set the state. */ const setRGState = rgs[SETTER] as SetStateAction; From 3f4ebca233e7be10f73f89126a65554eef9208f2 Mon Sep 17 00:00:00 2001 From: Mayank Kumar Chaudhari Date: Sat, 20 Apr 2024 08:51:13 +0530 Subject: [PATCH 5/6] touch up --- lib/r18gs/src/use-rgs.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/r18gs/src/use-rgs.ts b/lib/r18gs/src/use-rgs.ts index d4cd0015..82127b1a 100644 --- a/lib/r18gs/src/use-rgs.ts +++ b/lib/r18gs/src/use-rgs.ts @@ -14,32 +14,32 @@ type RGS = [unknown, Listener[], SetStateAction, Subscriber]; declare global { // eslint-disable-next-line no-var -- var required for global declaration. - var rgs: Map; + var rgs: Record; } -let g = globalThis; -g.rgs = new Map(); -let globalRGS = g.rgs; +const globalThisForBetterMinification = globalThis; +globalThisForBetterMinification.rgs = {}; +const globalRGS = globalThisForBetterMinification.rgs; /** Initialize the named store when invoked for the first time. */ function init(key: string, value?: T) { const listeners: Listener[] = []; /** setter function to set the state. */ const setter: SetStateAction = val => { - const rgs = globalRGS.get(key) as RGS; + const rgs = globalRGS[key] as RGS; rgs[VALUE] = val instanceof Function ? val(rgs[VALUE] as T) : val; (rgs[LISTENERS] as Listener[]).forEach(listener => listener()); }; /** subscriber function to subscribe to the store. */ const subscriber: Subscriber = listener => { - const rgs = globalRGS.get(key) as RGS; + const rgs = globalRGS[key] as RGS; const listeners = rgs[LISTENERS] as Listener[]; listeners.push(listener); return () => { rgs[LISTENERS] = listeners.filter(l => l !== listener); }; }; - globalRGS.set(key, [value, listeners, setter as SetStateAction, subscriber]); + globalRGS[key] = [value, listeners, setter as SetStateAction, subscriber]; } /** @@ -58,9 +58,9 @@ export default function useRGS( value?: T, serverValue?: T, ): [T, (val: SetterArgType) => void] { - if (!globalRGS.has(key)) init(key, value); + if (!globalRGS[key]) init(key, value); - const rgs = globalRGS.get(key) as RGS; + const rgs = globalRGS[key] as RGS; /** Function to set the state. */ const setRGState = rgs[SETTER] as SetStateAction; From d67f13dacad1a24b4454df921615f7c1602689b5 Mon Sep 17 00:00:00 2001 From: Mayank Kumar Chaudhari Date: Sat, 20 Apr 2024 08:54:10 +0530 Subject: [PATCH 6/6] Changelog --- examples/nextjs/CHANGELOG.md | 8 ++++++++ examples/nextjs/package.json | 2 +- examples/remix/CHANGELOG.md | 8 ++++++++ examples/remix/package.json | 2 +- examples/vite/CHANGELOG.md | 8 ++++++++ examples/vite/package.json | 2 +- lib/r18gs/CHANGELOG.md | 6 ++++++ lib/r18gs/package.json | 2 +- 8 files changed, 34 insertions(+), 4 deletions(-) diff --git a/examples/nextjs/CHANGELOG.md b/examples/nextjs/CHANGELOG.md index a3822100..4b086744 100644 --- a/examples/nextjs/CHANGELOG.md +++ b/examples/nextjs/CHANGELOG.md @@ -1,5 +1,13 @@ # nextjs-example +## 0.0.7 + +### Patch Changes + +- Updated dependencies + - r18gs@0.1.1 + - shared-ui@0.0.0 + ## 0.0.6 ### Patch Changes diff --git a/examples/nextjs/package.json b/examples/nextjs/package.json index 53649462..fdaba98e 100644 --- a/examples/nextjs/package.json +++ b/examples/nextjs/package.json @@ -1,6 +1,6 @@ { "name": "nextjs-example", - "version": "0.0.6", + "version": "0.0.7", "private": true, "scripts": { "dev": "next dev", diff --git a/examples/remix/CHANGELOG.md b/examples/remix/CHANGELOG.md index 27807026..c56202dd 100644 --- a/examples/remix/CHANGELOG.md +++ b/examples/remix/CHANGELOG.md @@ -1,5 +1,13 @@ # remix-example +## 0.0.7 + +### Patch Changes + +- Updated dependencies + - r18gs@0.1.1 + - shared-ui@0.0.0 + ## 0.0.6 ### Patch Changes diff --git a/examples/remix/package.json b/examples/remix/package.json index 6043f6e3..82f6ead7 100644 --- a/examples/remix/package.json +++ b/examples/remix/package.json @@ -1,6 +1,6 @@ { "name": "remix-example", - "version": "0.0.6", + "version": "0.0.7", "private": true, "sideEffects": false, "type": "module", diff --git a/examples/vite/CHANGELOG.md b/examples/vite/CHANGELOG.md index b121cf9e..c85b9955 100644 --- a/examples/vite/CHANGELOG.md +++ b/examples/vite/CHANGELOG.md @@ -1,5 +1,13 @@ # vite-example +## 0.0.7 + +### Patch Changes + +- Updated dependencies + - r18gs@0.1.1 + - shared-ui@0.0.0 + ## 0.0.6 ### Patch Changes diff --git a/examples/vite/package.json b/examples/vite/package.json index 05b3b2d1..482e89ec 100644 --- a/examples/vite/package.json +++ b/examples/vite/package.json @@ -1,7 +1,7 @@ { "name": "vite-example", "private": true, - "version": "0.0.6", + "version": "0.0.7", "type": "module", "scripts": { "dev": "vite --port 3001", diff --git a/lib/r18gs/CHANGELOG.md b/lib/r18gs/CHANGELOG.md index 27071ee1..1e012731 100644 --- a/lib/r18gs/CHANGELOG.md +++ b/lib/r18gs/CHANGELOG.md @@ -1,5 +1,11 @@ # r18gs +## 0.1.1 + +### Patch Changes + +- Refactor without changing the exposed APIs. Some libraries using internal APIs may face temporary issues. + ## 0.1.0 ### Minor Changes diff --git a/lib/r18gs/package.json b/lib/r18gs/package.json index be52ef33..69dbfb73 100644 --- a/lib/r18gs/package.json +++ b/lib/r18gs/package.json @@ -2,7 +2,7 @@ "name": "r18gs", "author": "Mayank Kumar Chaudhari ", "private": false, - "version": "0.1.0", + "version": "0.1.1", "description": "A simple yet elegant, light weight, react18 global store to replace Zustand for better tree shaking.", "main": "./index.ts", "types": "./index.ts",