Loading packages/chat/lib/components/YapContext.tsx +60 −6 Original line number Diff line number Diff line import type { MXUserID } from "@/lib/const"; import type { MXRoomID, MXUserID } from "@/lib/const"; import { MXClient } from "@/lib/MXClient"; import type React from "react"; import { createContext, useContext, useMemo, useReducer } from "react"; import { createContext, useCallback, useContext, useMemo, useReducer, } from "react"; type State = { stage: "INIT"; Loading @@ -9,15 +15,28 @@ type State = { }; type Actions = ["login"] | ["ready"]; const context = createContext<{ type InternalAPI = { state: State; dispatch: React.ActionDispatch<[Actions]>; }>( }; type PublicAPI = { ready: () => unknown; doLogin: () => unknown; openChat: (withWho: MXUserID | MXRoomID) => unknown; setSystem: (handler: (mxid: MXUserID) => boolean) => unknown; }; const context = createContext<InternalAPI & PublicAPI>( // eslint-disable-next-line @typescript-eslint/no-explicit-any null as any, ); export const useYap = () => useContext(context); // eslint-disable-next-line react-refresh/only-export-components export const useYap: < Mode extends "Internal" | "" = "", >() => Mode extends "Internal" ? InternalAPI & PublicAPI : PublicAPI = () => useContext(context); export const YapContext = ({ children }: React.PropsWithChildren) => { // @ts-expect-error ignore Loading @@ -39,6 +58,37 @@ export const YapContext = ({ children }: React.PropsWithChildren) => { }, ); const doLogin = useCallback(() => { window.open(client.getLoginUrl(window.location.href), "_self"); }, [client]); const openChat = useCallback((withWho: MXUserID | MXRoomID) => {}, []); const setSystem = useCallback( (handler: (mxid: MXUserID) => boolean) => {}, [], ); const ready = useCallback(() => { const params = new URLSearchParams(window.location.search); if (params.has("loginToken")) { console.debug( "YapContext: Attempting to login with loginToken query parameter...", ); client .login() .then((success) => { console.debug( "YapContext: Finished processing loginToken", success ? "and logged in" : "", ); }) .catch((e) => { console.error("YapContext: Failed to process loginToken", e); }); } }, [client]); // todo: // - migrate to new, public, context // - ready state to trigger url parsing for login Loading @@ -46,6 +96,10 @@ export const YapContext = ({ children }: React.PropsWithChildren) => { // - replacement definitions & handlers in props return ( <context.Provider value={{ state, dispatch }}>{children}</context.Provider> <context.Provider value={{ state, dispatch, doLogin, openChat, setSystem, ready }} > {children} </context.Provider> ); }; packages/chat/lib/lib/MXClient.ts +3 −1 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ export class MXClient extends EventEmitter<MXEvents> { const params = new URLSearchParams(window.location.search); if (!params.has("loginToken")) { console.warn("MXClient#login called but no loginToken found"); return; return false; } const loginToken = params.get("loginToken")!; params.delete("loginToken"); Loading @@ -76,6 +76,8 @@ export class MXClient extends EventEmitter<MXEvents> { accessToken: loginReq.access_token, userId: loginReq.user_id, }); return true; } private setupListeners() { Loading packages/chat/lib/main.ts +1 −0 Original line number Diff line number Diff line export { MatrixChat } from "./components/MatrixChat"; export { Yapper } from "./components/Yapper"; export { YapContext } from "./components/YapContext"; export type { MXEventID, MXRoomID, MXUserID } from "./lib/const"; packages/chat/src/App.tsx +7 −5 Original line number Diff line number Diff line Loading @@ -17,15 +17,17 @@ function App() { document.querySelector("html")?.classList[!dark ? "remove" : "add"]("dark"); }, [dark]); useEffect(() => { yap.ready(); }, [yap]); return ( <> <div>hello this is the demo app</div> <button onClick={() => setDark((d) => !d)}>toggle dark</button> <details> <summary>hi</summary> abc </details> <button onClick={() => yap.dispatch(["login"])}>try login</button> <button onClick={() => yap.doLogin()}>try login</button> <button onClick={() => alert("not impl")}>open chat with (...)</button> <button onClick={() => alert("not impl")}>open room (...)</button> <Sidebar> <MatrixChat /> </Sidebar> Loading Loading
packages/chat/lib/components/YapContext.tsx +60 −6 Original line number Diff line number Diff line import type { MXUserID } from "@/lib/const"; import type { MXRoomID, MXUserID } from "@/lib/const"; import { MXClient } from "@/lib/MXClient"; import type React from "react"; import { createContext, useContext, useMemo, useReducer } from "react"; import { createContext, useCallback, useContext, useMemo, useReducer, } from "react"; type State = { stage: "INIT"; Loading @@ -9,15 +15,28 @@ type State = { }; type Actions = ["login"] | ["ready"]; const context = createContext<{ type InternalAPI = { state: State; dispatch: React.ActionDispatch<[Actions]>; }>( }; type PublicAPI = { ready: () => unknown; doLogin: () => unknown; openChat: (withWho: MXUserID | MXRoomID) => unknown; setSystem: (handler: (mxid: MXUserID) => boolean) => unknown; }; const context = createContext<InternalAPI & PublicAPI>( // eslint-disable-next-line @typescript-eslint/no-explicit-any null as any, ); export const useYap = () => useContext(context); // eslint-disable-next-line react-refresh/only-export-components export const useYap: < Mode extends "Internal" | "" = "", >() => Mode extends "Internal" ? InternalAPI & PublicAPI : PublicAPI = () => useContext(context); export const YapContext = ({ children }: React.PropsWithChildren) => { // @ts-expect-error ignore Loading @@ -39,6 +58,37 @@ export const YapContext = ({ children }: React.PropsWithChildren) => { }, ); const doLogin = useCallback(() => { window.open(client.getLoginUrl(window.location.href), "_self"); }, [client]); const openChat = useCallback((withWho: MXUserID | MXRoomID) => {}, []); const setSystem = useCallback( (handler: (mxid: MXUserID) => boolean) => {}, [], ); const ready = useCallback(() => { const params = new URLSearchParams(window.location.search); if (params.has("loginToken")) { console.debug( "YapContext: Attempting to login with loginToken query parameter...", ); client .login() .then((success) => { console.debug( "YapContext: Finished processing loginToken", success ? "and logged in" : "", ); }) .catch((e) => { console.error("YapContext: Failed to process loginToken", e); }); } }, [client]); // todo: // - migrate to new, public, context // - ready state to trigger url parsing for login Loading @@ -46,6 +96,10 @@ export const YapContext = ({ children }: React.PropsWithChildren) => { // - replacement definitions & handlers in props return ( <context.Provider value={{ state, dispatch }}>{children}</context.Provider> <context.Provider value={{ state, dispatch, doLogin, openChat, setSystem, ready }} > {children} </context.Provider> ); };
packages/chat/lib/lib/MXClient.ts +3 −1 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ export class MXClient extends EventEmitter<MXEvents> { const params = new URLSearchParams(window.location.search); if (!params.has("loginToken")) { console.warn("MXClient#login called but no loginToken found"); return; return false; } const loginToken = params.get("loginToken")!; params.delete("loginToken"); Loading @@ -76,6 +76,8 @@ export class MXClient extends EventEmitter<MXEvents> { accessToken: loginReq.access_token, userId: loginReq.user_id, }); return true; } private setupListeners() { Loading
packages/chat/lib/main.ts +1 −0 Original line number Diff line number Diff line export { MatrixChat } from "./components/MatrixChat"; export { Yapper } from "./components/Yapper"; export { YapContext } from "./components/YapContext"; export type { MXEventID, MXRoomID, MXUserID } from "./lib/const";
packages/chat/src/App.tsx +7 −5 Original line number Diff line number Diff line Loading @@ -17,15 +17,17 @@ function App() { document.querySelector("html")?.classList[!dark ? "remove" : "add"]("dark"); }, [dark]); useEffect(() => { yap.ready(); }, [yap]); return ( <> <div>hello this is the demo app</div> <button onClick={() => setDark((d) => !d)}>toggle dark</button> <details> <summary>hi</summary> abc </details> <button onClick={() => yap.dispatch(["login"])}>try login</button> <button onClick={() => yap.doLogin()}>try login</button> <button onClick={() => alert("not impl")}>open chat with (...)</button> <button onClick={() => alert("not impl")}>open room (...)</button> <Sidebar> <MatrixChat /> </Sidebar> Loading