diff --git a/src/api/Settings.ts b/src/api/Settings.ts index c7aacef90..a803b8d46 100644 --- a/src/api/Settings.ts +++ b/src/api/Settings.ts @@ -117,7 +117,7 @@ const saveSettingsOnFrequentAction = debounce(async () => { } }, 60_000); -type SubscriptionCallback = ((newValue: any, path: string) => void) & { _paths?: Array; }; +type SubscriptionCallback = ((newValue: any, path: string) => void) & { _paths?: Array; _exact?: boolean; }; const subscriptions = new Set(); const proxyCache = {} as Record; @@ -174,7 +174,12 @@ function makeProxy(settings: any, root = settings, path = ""): Settings { const setPath = `${path}${path && "."}${p}`; delete proxyCache[setPath]; for (const subscription of subscriptions) { - if (!subscription._paths || subscription._paths.includes(setPath)) { + if ( + !subscription._paths || + (subscription._exact + ? subscription._paths.includes(setPath) + : subscription._paths.some(p => setPath.startsWith(p))) + ) { subscription(v, setPath); } } @@ -212,11 +217,14 @@ export const Settings = makeProxy(settings); * @returns Settings */ // TODO: Representing paths as essentially "string[].join('.')" wont allow dots in paths, change to "paths?: string[][]" later -export function useSettings(paths?: UseSettings[]) { +export function useSettings(paths?: UseSettings[], exact = true) { const [, forceUpdate] = React.useReducer(() => ({}), {}); const onUpdate: SubscriptionCallback = paths - ? (value, path) => paths.includes(path as UseSettings) && forceUpdate() + ? (value, path) => + (exact + ? paths.includes(path as UseSettings) + : paths.some(p => path.startsWith(p))) && forceUpdate() : forceUpdate; React.useEffect(() => { @@ -242,10 +250,11 @@ type ResolvePropDeep = P extends "" ? T : * @example addSettingsListener("", (newValue, path) => console.log(`${path} is now ${newValue}`)) * addSettingsListener("plugins.Unindent.enabled", v => console.log("Unindent is now", v ? "enabled" : "disabled")) */ -export function addSettingsListener(path: Path, onUpdate: (newValue: Settings[Path], path: Path) => void): void; -export function addSettingsListener(path: Path, onUpdate: (newValue: Path extends "" ? any : ResolvePropDeep, path: Path extends "" ? string : Path) => void): void; -export function addSettingsListener(path: string, onUpdate: (newValue: any, path: string) => void) { +export function addSettingsListener(path: Path, onUpdate: (newValue: Settings[Path], path: Path) => void, exact?: boolean): void; +export function addSettingsListener(path: Path, onUpdate: (newValue: Path extends "" ? any : ResolvePropDeep, path: Path extends "" ? string : Path) => void, exact?: boolean): void; +export function addSettingsListener(path: string, onUpdate: (newValue: any, path: string) => void, exact = true) { ((onUpdate as SubscriptionCallback)._paths ??= []).push(path); + (onUpdate as SubscriptionCallback)._exact = exact; subscriptions.add(onUpdate); } diff --git a/src/components/VencordSettings/ThemesTab.tsx b/src/components/VencordSettings/ThemesTab.tsx index 18d67da16..410988f32 100644 --- a/src/components/VencordSettings/ThemesTab.tsx +++ b/src/components/VencordSettings/ThemesTab.tsx @@ -141,7 +141,7 @@ interface UserCSSSettingsModalProps { function UserCSSSettingsModal({ modalProps, theme }: UserCSSSettingsModalProps) { // @ts-expect-error UseSettings<> can't determine this is a valid key - const themeSettings = useSettings(["userCssVars"]).userCssVars[theme.id]; + const themeSettings = useSettings(["userCssVars"], false).userCssVars[theme.id]; const controls: ReactNode[] = []; diff --git a/src/utils/quickCss.ts b/src/utils/quickCss.ts index c70c880f4..836ea58ee 100644 --- a/src/utils/quickCss.ts +++ b/src/utils/quickCss.ts @@ -99,7 +99,7 @@ document.addEventListener("DOMContentLoaded", () => { addSettingsListener("themeLinks", initThemes); addSettingsListener("enabledThemes", initThemes); - addSettingsListener("userCssVars", initThemes); + addSettingsListener("userCssVars", initThemes, false); if (!IS_WEB) VencordNative.quickCss.addThemeChangeListener(initThemes);