diff options
Diffstat (limited to 'frontend/src/components')
| -rw-r--r-- | frontend/src/components/DeckyGlobalComponentsState.tsx | 12 | ||||
| -rw-r--r-- | frontend/src/components/DeckyMenuState.tsx | 147 |
2 files changed, 153 insertions, 6 deletions
diff --git a/frontend/src/components/DeckyGlobalComponentsState.tsx b/frontend/src/components/DeckyGlobalComponentsState.tsx index fe45588b..e3fd6342 100644 --- a/frontend/src/components/DeckyGlobalComponentsState.tsx +++ b/frontend/src/components/DeckyGlobalComponentsState.tsx @@ -14,13 +14,13 @@ export class DeckyGlobalComponentsState { return { components: this._components }; } - addComponent(path: string, component: FC) { - this._components.set(path, component); + addComponent(name: string, component: FC) { + this._components.set(name, component); this.notifyUpdate(); } - removeComponent(path: string) { - this._components.delete(path); + removeComponent(name: string) { + this._components.delete(name); this.notifyUpdate(); } @@ -30,8 +30,8 @@ export class DeckyGlobalComponentsState { } interface DeckyGlobalComponentsContext extends PublicDeckyGlobalComponentsState { - addComponent(path: string, component: FC): void; - removeComponent(path: string): void; + addComponent(name: string, component: FC): void; + removeComponent(name: string): void; } const DeckyGlobalComponentsContext = createContext<DeckyGlobalComponentsContext>(null as any); diff --git a/frontend/src/components/DeckyMenuState.tsx b/frontend/src/components/DeckyMenuState.tsx new file mode 100644 index 00000000..a4a6a999 --- /dev/null +++ b/frontend/src/components/DeckyMenuState.tsx @@ -0,0 +1,147 @@ +import { CustomMainMenuItem, ItemPatch, OverlayPatch } from 'decky-frontend-lib'; +import { FC, ReactNode, createContext, useContext, useEffect, useState } from 'react'; + +interface PublicDeckyMenuState { + items: Set<CustomMainMenuItem>; + itemPatches: Map<string, Set<ItemPatch>>; + overlayPatches: Set<OverlayPatch>; + overlayComponents: Set<ReactNode>; +} + +export class DeckyMenuState { + private _items = new Set<CustomMainMenuItem>(); + private _itemPatches = new Map<string, Set<ItemPatch>>(); + private _overlayPatches = new Set<OverlayPatch>(); + private _overlayComponents = new Set<ReactNode>(); + + public eventBus = new EventTarget(); + + publicState(): PublicDeckyMenuState { + return { + items: this._items, + itemPatches: this._itemPatches, + overlayPatches: this._overlayPatches, + overlayComponents: this._overlayComponents, + }; + } + + addItem(item: CustomMainMenuItem) { + this._items.add(item); + this.notifyUpdate(); + return item; + } + + addPatch(path: string, patch: ItemPatch) { + let patchList = this._itemPatches.get(path); + if (!patchList) { + patchList = new Set(); + this._itemPatches.set(path, patchList); + } + patchList.add(patch); + this.notifyUpdate(); + return patch; + } + + addOverlayPatch(patch: OverlayPatch) { + this._overlayPatches.add(patch); + this.notifyUpdate(); + return patch; + } + + addOverlayComponent(component: ReactNode) { + this._overlayComponents.add(component); + this.notifyUpdate(); + return component; + } + + removePatch(path: string, patch: ItemPatch) { + const patchList = this._itemPatches.get(path); + patchList?.delete(patch); + if (patchList?.size == 0) { + this._itemPatches.delete(path); + } + this.notifyUpdate(); + } + + removeItem(item: CustomMainMenuItem) { + this._items.delete(item); + this.notifyUpdate(); + return item; + } + + removeOverlayPatch(patch: OverlayPatch) { + this._overlayPatches.delete(patch); + this.notifyUpdate(); + } + + removeOverlayComponent(component: ReactNode) { + this._overlayComponents.delete(component); + this.notifyUpdate(); + } + + private notifyUpdate() { + this.eventBus.dispatchEvent(new Event('update')); + } +} + +interface DeckyMenuStateContext extends PublicDeckyMenuState { + addItem: DeckyMenuState['addItem']; + addPatch: DeckyMenuState['addPatch']; + addOverlayPatch: DeckyMenuState['addOverlayPatch']; + addOverlayComponent: DeckyMenuState['addOverlayComponent']; + removePatch: DeckyMenuState['removePatch']; + removeOverlayPatch: DeckyMenuState['removeOverlayPatch']; + removeOverlayComponent: DeckyMenuState['removeOverlayComponent']; + removeItem: DeckyMenuState['removeItem']; +} + +const DeckyMenuStateContext = createContext<DeckyMenuStateContext>(null as any); + +export const useDeckyMenuState = () => useContext(DeckyMenuStateContext); + +interface Props { + deckyMenuState: DeckyMenuState; +} + +export const DeckyMenuStateContextProvider: FC<Props> = ({ children, deckyMenuState }) => { + const [publicDeckyMenuState, setPublicDeckyMenuState] = useState<PublicDeckyMenuState>({ + ...deckyMenuState.publicState(), + }); + + useEffect(() => { + function onUpdate() { + setPublicDeckyMenuState({ ...deckyMenuState.publicState() }); + } + + deckyMenuState.eventBus.addEventListener('update', onUpdate); + + return () => deckyMenuState.eventBus.removeEventListener('update', onUpdate); + }, []); + + const addItem = deckyMenuState.addItem.bind(deckyMenuState); + const addPatch = deckyMenuState.addPatch.bind(deckyMenuState); + const addOverlayPatch = deckyMenuState.addOverlayPatch.bind(deckyMenuState); + const addOverlayComponent = deckyMenuState.addOverlayComponent.bind(deckyMenuState); + const removePatch = deckyMenuState.removePatch.bind(deckyMenuState); + const removeOverlayPatch = deckyMenuState.removeOverlayPatch.bind(deckyMenuState); + const removeOverlayComponent = deckyMenuState.removeOverlayComponent.bind(deckyMenuState); + const removeItem = deckyMenuState.removeItem.bind(deckyMenuState); + + return ( + <DeckyMenuStateContext.Provider + value={{ + ...publicDeckyMenuState, + addItem, + addPatch, + addOverlayPatch, + addOverlayComponent, + removePatch, + removeOverlayPatch, + removeOverlayComponent, + removeItem, + }} + > + {children} + </DeckyMenuStateContext.Provider> + ); +}; |
