import { createContext, useCallback, useContext, useState } from 'react' type CommandInvocationContext = { location?: string } export type Command = { label: string id: string handler?: (context: CommandInvocationContext) => void href?: string disabled?: boolean // TODO: Keybinding? } const CommandRegistryContext = createContext( undefined ) type CommandRegistry = { registry: Map register: (...elements: Command[]) => void unregister: (...id: string[]) => void } export const CommandRegistryProvider: React.FC = ({ children }) => { const [registry, setRegistry] = useState(new Map()) const register = useCallback((...elements: Command[]) => { setRegistry( registry => new Map([ ...registry, ...elements.map(element => [element.id, element] as const), ]) ) }, []) const unregister = useCallback((...ids: string[]) => { setRegistry( registry => new Map([...registry].filter(([key]) => !ids.includes(key))) ) }, []) return ( {children} ) } export const useCommandRegistry = (): CommandRegistry => { const context = useContext(CommandRegistryContext) if (!context) { throw new Error( 'useCommandRegistry must be used within a CommandRegistryProvider' ) } return context }