summaryrefslogtreecommitdiff
path: root/frontend/src/components/DeckyGlobalComponentsState.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/components/DeckyGlobalComponentsState.tsx')
-rw-r--r--frontend/src/components/DeckyGlobalComponentsState.tsx74
1 files changed, 74 insertions, 0 deletions
diff --git a/frontend/src/components/DeckyGlobalComponentsState.tsx b/frontend/src/components/DeckyGlobalComponentsState.tsx
new file mode 100644
index 00000000..fe45588b
--- /dev/null
+++ b/frontend/src/components/DeckyGlobalComponentsState.tsx
@@ -0,0 +1,74 @@
+import { FC, createContext, useContext, useEffect, useState } from 'react';
+
+interface PublicDeckyGlobalComponentsState {
+ components: Map<string, FC>;
+}
+
+export class DeckyGlobalComponentsState {
+ // TODO a set would be better
+ private _components = new Map<string, FC>();
+
+ public eventBus = new EventTarget();
+
+ publicState(): PublicDeckyGlobalComponentsState {
+ return { components: this._components };
+ }
+
+ addComponent(path: string, component: FC) {
+ this._components.set(path, component);
+ this.notifyUpdate();
+ }
+
+ removeComponent(path: string) {
+ this._components.delete(path);
+ this.notifyUpdate();
+ }
+
+ private notifyUpdate() {
+ this.eventBus.dispatchEvent(new Event('update'));
+ }
+}
+
+interface DeckyGlobalComponentsContext extends PublicDeckyGlobalComponentsState {
+ addComponent(path: string, component: FC): void;
+ removeComponent(path: string): void;
+}
+
+const DeckyGlobalComponentsContext = createContext<DeckyGlobalComponentsContext>(null as any);
+
+export const useDeckyGlobalComponentsState = () => useContext(DeckyGlobalComponentsContext);
+
+interface Props {
+ deckyGlobalComponentsState: DeckyGlobalComponentsState;
+}
+
+export const DeckyGlobalComponentsStateContextProvider: FC<Props> = ({
+ children,
+ deckyGlobalComponentsState: deckyGlobalComponentsState,
+}) => {
+ const [publicDeckyGlobalComponentsState, setPublicDeckyGlobalComponentsState] =
+ useState<PublicDeckyGlobalComponentsState>({
+ ...deckyGlobalComponentsState.publicState(),
+ });
+
+ useEffect(() => {
+ function onUpdate() {
+ setPublicDeckyGlobalComponentsState({ ...deckyGlobalComponentsState.publicState() });
+ }
+
+ deckyGlobalComponentsState.eventBus.addEventListener('update', onUpdate);
+
+ return () => deckyGlobalComponentsState.eventBus.removeEventListener('update', onUpdate);
+ }, []);
+
+ const addComponent = deckyGlobalComponentsState.addComponent.bind(deckyGlobalComponentsState);
+ const removeComponent = deckyGlobalComponentsState.removeComponent.bind(deckyGlobalComponentsState);
+
+ return (
+ <DeckyGlobalComponentsContext.Provider
+ value={{ ...publicDeckyGlobalComponentsState, addComponent, removeComponent }}
+ >
+ {children}
+ </DeckyGlobalComponentsContext.Provider>
+ );
+};