fix comms

This commit is contained in:
superdinmc
2025-11-11 09:36:55 +07:00 Unverified
parent ef25566b65
commit 7b4e6b46ef
5 changed files with 68 additions and 41 deletions
+4 -1
View File
@@ -25,7 +25,10 @@ export function VersionCheck() {
const [count, setCount] = useState<string | number>("...");
const [debug, setDebug] = comms.var("debug");
useKey("f2", () => setDebug(!debug));
useKey("F2", () => {
setDebug((x) => !x);
});
// console.log(`Debug mode ${debug ? "enabled" : "disabled"}`);
useEffect(() => {
const es = new ReconnectingEventSource(`/api/active`, {});
+1 -1
View File
@@ -47,9 +47,9 @@ export default function RootLayout({
/>
<Providers>
<AnimatePresence mode="wait">{children}</AnimatePresence>
<VersionCheck />
</Providers>
<Toaster theme="dark" richColors closeButton />
<VersionCheck />
</body>
</html>
);
BIN
View File
Binary file not shown.
+61 -38
View File
@@ -2,7 +2,7 @@
import { createContext, use, useEffect, useRef, useState } from "react";
type WebsiteComms = Partial<{ manual: boolean, debug: boolean }>;
type WebsiteComms = Partial<{ manual: boolean; debug: boolean }>;
type WebsiteSignals = { beforeSubmit: undefined } & WebsiteComms;
@@ -18,14 +18,19 @@ type WebsiteCommsMutator = {
listener: (value: WebsiteSignals[K]) => void,
): void;
emit<K extends keyof WebsiteSignals>(key: K, value: WebsiteSignals[K]): void;
active: boolean;
};
export const CommsContext = createContext<WebsiteCommsMutator>({
get: () => undefined,
get: () => {
console.error("Inter-component communication used outside of provider.");
return undefined;
},
set: () => undefined,
on: () => () => undefined,
off: () => undefined,
emit: () => undefined,
active: false,
});
export default function CommsProvider({
@@ -33,63 +38,81 @@ export default function CommsProvider({
}: {
children: React.ReactNode;
}) {
const [store, setStore] = useState<WebsiteComms>({});
const storeRef = useRef<WebsiteComms>({});
const [, forceUpdate] = useState({});
const listeners = useRef<{
[K in keyof WebsiteSignals]?: Array<(value: WebsiteSignals[K]) => void>;
}>({});
return (
<CommsContext
value={{
get: (k) => store[k],
set: (k, v) => {
setStore((x) => ({ ...x, [k]: v }));
(listeners.current[k] || []).map((l) => l(v));
},
on: (k, listener) => {
// @ts-expect-error
listeners.current[k] = [...(listeners.current[k] || []), listener];
return () => {
// @ts-expect-error
listeners.current[k] = listeners.current[k]?.filter(
(l) => l !== listener,
);
};
},
off: (k, listener) => {
// @ts-expect-error
listeners.current[k] = (listeners.current[k] || []).filter(
(l) => l !== listener,
);
},
emit: (k, value) => {
(listeners.current[k] || []).map((l) => l(value));
},
}}
>
{children}
</CommsContext>
);
const contextValue = useRef<WebsiteCommsMutator>({
get: (k) => storeRef.current[k],
set: (k, v) => {
storeRef.current = { ...storeRef.current, [k]: v };
(listeners.current[k] || []).map((l) => l(v));
forceUpdate({});
},
on: (k, listener) => {
// @ts-expect-error
listeners.current[k] = [...(listeners.current[k] || []), listener];
return () => {
// @ts-expect-error
listeners.current[k] = listeners.current[k]?.filter(
(l) => l !== listener,
);
};
},
off: (k, listener) => {
// @ts-expect-error
listeners.current[k] = (listeners.current[k] || []).filter(
(l) => l !== listener,
);
},
emit: (k, value) => {
(listeners.current[k] || []).map((l) => l(value));
},
active: true,
});
return <CommsContext value={contextValue.current}>{children}</CommsContext>;
}
export const comms = {
var(name: keyof WebsiteComms) {
const comms = use(CommsContext);
const [state, setState] = useState(comms.get(name));
if(!comms.active) {
console.warn("Inter-component communication used outside of provider. Using local state instead.");
}
const [state, setState] = useState(comms.active?comms.get(name): undefined);
useEffect(() => {
function listener(value: WebsiteComms[typeof name]) {
setState(value);
}
return comms.on(name, listener);
}, [comms, name]);
}, [name]);
return [state, comms.set.bind(comms, name)] as const;
function mutator(
value:
| WebsiteComms[typeof name]
| ((prev: WebsiteComms[typeof name]) => WebsiteComms[typeof name]),
) {
const v = typeof value === "function" ? value(comms.get(name)) : value;
if(comms.active) comms.set(name, v);
else setState(v);
}
return [state, mutator] as const;
},
event<K extends keyof WebsiteSignals>(
key: K,
listener: (ev: WebsiteSignals[K]) => void,
) {
const comms = use(CommsContext);
if (!comms.active) {
console.warn(
"Inter-component communication used outside of provider. No events will be emitted.",
);
}
useEffect(() => {
return comms.on(key, listener);
}, [comms, key, listener]);
+2 -1
View File
@@ -79,7 +79,8 @@
"uuidv7": "^1.0.2",
"vaul": "^1.1.2",
"yaml": "^2.8.1",
"zod": "^4.1.12"
"zod": "^4.1.12",
"zustand": "^5.0.8"
},
"devDependencies": {
"@better-auth/cli": "^1.3.34",