import { FC, ReactNode, createContext, useContext, useEffect, useState } from 'react'; import { EUIMode } from '../../globals/steam-client/shared'; interface PublicMillenniumGlobalComponentsState { components: Map>; } export class MillenniumGlobalComponentsState { // TODO a set would be better private _components = new Map>([ [EUIMode.GamePad, new Map()], [EUIMode.Desktop, new Map()], ]); public eventBus = new EventTarget(); publicState(): PublicMillenniumGlobalComponentsState { return { components: this._components }; } addComponent(path: string, component: FC, uiMode: EUIMode) { const components = this._components.get(uiMode); if (!components) throw new Error(`UI mode ${uiMode} not supported.`); components.set(path, component); this.notifyUpdate(); } removeComponent(path: string, uiMode: EUIMode) { const components = this._components.get(uiMode); if (!components) throw new Error(`UI mode ${uiMode} not supported.`); components.delete(path); this.notifyUpdate(); } private notifyUpdate() { this.eventBus.dispatchEvent(new Event('update')); } } interface MillenniumGlobalComponentsContext extends PublicMillenniumGlobalComponentsState { addComponent(path: string, component: FC, uiMode: EUIMode): void; removeComponent(path: string, uiMode: EUIMode): void; } const MillenniumGlobalComponentsContext = createContext(null as any); export const useMillenniumGlobalComponentsState = () => useContext(MillenniumGlobalComponentsContext); interface Props { millenniumGlobalComponentsState: MillenniumGlobalComponentsState; children: ReactNode; } export const MillenniumGlobalComponentsStateContextProvider: FC = ({ children, millenniumGlobalComponentsState: millenniumGlobalComponentsState }) => { const [publicMillenniumGlobalComponentsState, setPublicMillenniumGlobalComponentsState] = useState({ ...millenniumGlobalComponentsState.publicState(), }); useEffect(() => { function onUpdate() { setPublicMillenniumGlobalComponentsState({ ...millenniumGlobalComponentsState.publicState() }); } millenniumGlobalComponentsState.eventBus.addEventListener('update', onUpdate); return () => millenniumGlobalComponentsState.eventBus.removeEventListener('update', onUpdate); }, []); const addComponent = millenniumGlobalComponentsState.addComponent.bind(millenniumGlobalComponentsState); const removeComponent = millenniumGlobalComponentsState.removeComponent.bind(millenniumGlobalComponentsState); return ( {children} ); };