import preferencesAccess from './'; import type { AllPreferences } from './'; export interface ReactHooks { useState: (initialValue: T) => [T, (newValue: T) => void]; useEffect: ( effectFn: () => () => void, dependencies: readonly unknown[] ) => void; } /** Use as: const enableMaps = usePreference('enableMaps', React); */ export function usePreference( key: K, { useState, useEffect }: ReactHooks ): AllPreferences[K] { const [value, setValue] = useState(preferencesAccess.getPreferences()[key]); useEffect(() => { return preferencesAccess.onPreferenceValueChanged(key, (value) => { setValue(value); }); }, [key]); return value; } type FirstArgument = F extends (...args: [infer A, ...any]) => any ? A : F extends { new (...args: [infer A, ...any]): any } ? A : never; type OptionalOmit = Omit & Partial>; /** Use as: const WrappedComponent = withPreferences(Component, ['enableMaps', 'trackUsageStatistics'], React); */ export function withPreferences< C extends ((...args: any[]) => any) | { new (...args: any[]): any }, K extends keyof AllPreferences, R >( component: C, keys: K[], React: ReactHooks & { createElement: (component: C, props: unknown) => R } ): (props: OptionalOmit, K>) => R { return function (props: OptionalOmit, K>): R { const prefs = Object.fromEntries( keys.map((key) => [key, usePreference(key, React)]) ); return React.createElement(component, { ...prefs, ...props }); }; }