import { createContext, FC, ReactChildren, useCallback, useContext, useMemo, useState } from "react"; import { InitSettings } from "Types/extension"; type ContextSetter = (fn: (prev: InitSettings[K]) => InitSettings[K]) => void; type ContextValue = (readonly [InitSettings[K], ContextSetter]) | null; type ContextType = ReturnType | null>>; type HookEvents = | "beforeUpdate" | "afterUpdate"; type Hooks = { [event in HookEvents]: ((prevState: InitSettings[K], update: InitSettings[K]) => void) | null }; type ProviderProps = { children: ReactChildren, init: InitSettings[K], updater: (prevState: InitSettings[K]) => void }; export type SettingsProvider = FC>; class SettingsManager { context: ContextType; hooks: Partial>; constructor(hooks: Partial> = {}) { this.context = createContext>(null); this.hooks = hooks; } Provider: SettingsProvider = ({ children, init, updater }) => { const [settings, _setSettings] = useState(init); const setSettings = useCallback>((updateFn) => { _setSettings((prevState) => { const update = updateFn(prevState); this.hooks.beforeUpdate?.(prevState, update); updater(update); this.hooks.afterUpdate?.(prevState, update); return update; }); }, [updater]); const contextValue = useMemo(() => [settings, setSettings] as const, [settings, setSettings]); return ( {children} ); }; useSettings = () => { const context = useContext(this.context); if (!context) { throw new Error("No context provided"); } return context; }; } export { SettingsManager };