aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVendicated <vendicated@riseup.net>2022-08-31 04:07:16 +0200
committerVendicated <vendicated@riseup.net>2022-08-31 04:07:16 +0200
commit98cb301df53305f397ac6e1b4e603c930820f228 (patch)
tree8c3bc642d0871a38f99aa2c2e8586bd7310cb361
parentcb288e204dd531b31f957f82150398d22930fdeb (diff)
downloadVencord-98cb301df53305f397ac6e1b4e603c930820f228.tar.gz
Vencord-98cb301df53305f397ac6e1b4e603c930820f228.tar.bz2
Vencord-98cb301df53305f397ac6e1b4e603c930820f228.zip
Make Settings & Settings Page
-rwxr-xr-xbuild.mjs2
-rw-r--r--src/Vencord.ts2
-rw-r--r--src/VencordNative.ts37
-rw-r--r--src/api/settings.ts81
-rw-r--r--src/components/Settings.tsx84
-rw-r--r--src/ipcMain.ts28
-rw-r--r--src/plugins/index.ts5
-rw-r--r--src/plugins/messageActions.ts3
-rw-r--r--src/plugins/noTrack.ts3
-rw-r--r--src/plugins/settings.ts3
-rw-r--r--src/utils/IpcEvents.ts22
-rw-r--r--src/utils/ipcEvents.ts3
-rw-r--r--src/utils/misc.tsx61
-rw-r--r--src/utils/patchWebpack.ts12
-rw-r--r--src/utils/quickCss.ts6
-rw-r--r--src/utils/types.ts2
-rw-r--r--src/webpack/index.ts (renamed from src/utils/webpack.ts)17
-rw-r--r--tsconfig.json2
18 files changed, 330 insertions, 43 deletions
diff --git a/build.mjs b/build.mjs
index f2a4447..c3bac3b 100755
--- a/build.mjs
+++ b/build.mjs
@@ -117,7 +117,7 @@ await Promise.all([
],
sourcemap: "inline",
watch,
- minify: true
+ minify: false,
})
]).then(res => {
const took = performance.now() - begin;
diff --git a/src/Vencord.ts b/src/Vencord.ts
index 4364468..8ef272b 100644
--- a/src/Vencord.ts
+++ b/src/Vencord.ts
@@ -1,5 +1,5 @@
export * as Plugins from "./plugins";
-export * as Webpack from "./utils/webpack";
+export * as Webpack from "./webpack";
export * as Api from "./api";
export * as Components from "./components";
diff --git a/src/VencordNative.ts b/src/VencordNative.ts
index 7fbe6df..fc1e690 100644
--- a/src/VencordNative.ts
+++ b/src/VencordNative.ts
@@ -1,12 +1,33 @@
-import { IPC_QUICK_CSS_UPDATE, IPC_GET_QUICK_CSS } from './utils/ipcEvents';
-import { ipcRenderer } from 'electron';
+import IPC_EVENTS from './utils/IpcEvents';
+import { IpcRenderer, ipcRenderer } from 'electron';
export default {
- handleQuickCssUpdate(cb: (s: string) => void) {
- ipcRenderer.on(IPC_QUICK_CSS_UPDATE, (_, css) => {
- cb(css);
- });
+ getVersions: () => process.versions,
+ ipc: {
+ send(event: string, ...args: any[]) {
+ if (event in IPC_EVENTS) ipcRenderer.send(event, ...args);
+ else throw new Error(`Event ${event} not allowed.`);
+ },
+ sendSync(event: string, ...args: any[]) {
+ if (event in IPC_EVENTS) return ipcRenderer.sendSync(event, ...args);
+ else throw new Error(`Event ${event} not allowed.`);
+ },
+ on(event: string, listener: Parameters<IpcRenderer["on"]>[1]) {
+ if (event in IPC_EVENTS) ipcRenderer.on(event, listener);
+ else throw new Error(`Event ${event} not allowed.`);
+ },
+ invoke(event: string, ...args: any[]) {
+ if (event in IPC_EVENTS) return ipcRenderer.invoke(event, ...args);
+ else throw new Error(`Event ${event} not allowed.`);
+ }
},
- getQuickCss: () => ipcRenderer.invoke(IPC_GET_QUICK_CSS) as Promise<string>,
- getVersions: () => process.versions
+ require(mod: string) {
+ const settings = ipcRenderer.sendSync(IPC_EVENTS.GET_SETTINGS);
+ try {
+ if (!JSON.parse(settings).unsafeRequire) throw "no";
+ } catch {
+ throw new Error("Unsafe require is not allowed. Enable it in settings and try again.");
+ }
+ return require(mod);
+ }
}; \ No newline at end of file
diff --git a/src/api/settings.ts b/src/api/settings.ts
new file mode 100644
index 0000000..253c726
--- /dev/null
+++ b/src/api/settings.ts
@@ -0,0 +1,81 @@
+import plugins from "plugins";
+import IpcEvents from "../utils/IpcEvents";
+import { React } from "../webpack";
+import { mergeDefaults } from '../utils/misc';
+
+interface Settings {
+ unsafeRequire: boolean;
+ plugins: {
+ [plugin: string]: {
+ enabled: boolean;
+ [setting: string]: any;
+ };
+ };
+}
+
+const DefaultSettings: Settings = {
+ unsafeRequire: false,
+ plugins: {}
+};
+
+for (const plugin of plugins) {
+ DefaultSettings.plugins[plugin.name] = {
+ enabled: plugin.required ?? false
+ };
+}
+
+try {
+ var settings = JSON.parse(VencordNative.ipc.sendSync(IpcEvents.GET_SETTINGS)) as Settings;
+ for (const key in DefaultSettings) {
+ settings[key] ??= DefaultSettings[key];
+ }
+ mergeDefaults(settings, DefaultSettings);
+} catch (err) {
+ console.error("Corrupt settings file. ", err);
+ var settings = mergeDefaults({} as Settings, DefaultSettings);
+}
+
+const subscriptions = new Set<() => void>();
+
+function makeProxy(settings: Settings, root = settings): Settings {
+ return new Proxy(settings, {
+ get(target, p) {
+ const v = target[p];
+ if (typeof v === "object" && !Array.isArray(v)) return makeProxy(v, root);
+ return v;
+ },
+ set(target, p, v) {
+ if (target[p] === v) return true;
+
+ target[p] = v;
+ for (const subscription of subscriptions) {
+ subscription();
+ }
+ VencordNative.ipc.invoke(IpcEvents.SET_SETTINGS, JSON.stringify(root));
+ return true;
+ }
+ });
+}
+
+/**
+ * A smart settings object. Altering props automagically saves
+ * the updated settings to disk.
+ */
+export const Settings = makeProxy(settings);
+
+/**
+ * Settings hook for React components. Returns a smart settings
+ * object that automagically triggers a rerender if any properties
+ * are altered
+ * @returns Settings
+ */
+export function useSettings() {
+ const [, forceUpdate] = React.useReducer(x => ({}), {});
+
+ React.useEffect(() => {
+ subscriptions.add(forceUpdate);
+ return () => void subscriptions.delete(forceUpdate);
+ }, []);
+
+ return Settings;
+} \ No newline at end of file
diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx
index f996448..4499c9f 100644
--- a/src/components/Settings.tsx
+++ b/src/components/Settings.tsx
@@ -1,4 +1,84 @@
+import { lazy, LazyComponent, useAwaiter } from "../utils/misc";
+import { findByDisplayName, Forms } from '../webpack';
+import Plugins from 'plugins';
+import { useSettings } from "../api/settings";
+import { findByProps } from '../webpack/index';
+import IpcEvents from "../utils/IpcEvents";
+
+// Lazy spam because this is ran before React is a thing. Todo: Fix that and clean this up lmao
+
+const SwitchItem = LazyComponent<React.PropsWithChildren<{
+ value: boolean;
+ onChange: (v: boolean) => void;
+ note?: string;
+ tooltipNote?: string;
+ disabled?: boolean;
+}>>(() => findByDisplayName("SwitchItem").default);
+
+const getButton = lazy(() => findByProps("ButtonLooks", "default"));
+const Button = LazyComponent(() => getButton().default);
+const getFlex = lazy(() => findByDisplayName("Flex"));
+const Flex = LazyComponent(() => getFlex().default);
+const FlexChild = LazyComponent(() => getFlex().default.Child);
+const getMargins = lazy(() => findByProps("marginTop8", "marginBottom8"));
+
export default function Settings(props) {
- console.log(props);
- return (<p>Hi</p>);
+ const settingsDir = useAwaiter(() => VencordNative.ipc.invoke(IpcEvents.GET_SETTINGS_DIR), "Loading...");
+ const settings = useSettings();
+
+ return (
+ <Forms.FormSection tag="h1" title="Vencord">
+ <Forms.FormText>SettingsDir: {settingsDir}</Forms.FormText>
+ <Flex className={getMargins().marginTop8 + " " + getMargins().marginBottom8}>
+ <FlexChild>
+ <Button
+ onClick={() => VencordNative.ipc.invoke(IpcEvents.OPEN_PATH, settingsDir)}
+ size={getButton().ButtonSizes.SMALL}
+ disabled={settingsDir === "Loading..."}
+ >
+ Launch Directory
+ </Button>
+ </FlexChild>
+ <FlexChild>
+ <Button
+ onClick={() => VencordNative.ipc.invoke(IpcEvents.OPEN_PATH, settingsDir + "/quickCss.css")}
+ size={getButton().ButtonSizes.SMALL}
+ disabled={settingsDir === "Loading..."}
+ >
+ Open QuickCSS File
+ </Button>
+ </FlexChild>
+ </Flex>
+ <Forms.FormTitle tag="h5">Settings</Forms.FormTitle>
+ <SwitchItem
+ value={settings.unsafeRequire}
+ onChange={v => settings.unsafeRequire = v}
+ note="Enables VencordNative.require. Useful for testing, very bad for security. Leave this off unless you need it."
+ >
+ Enable Ensafe Require
+ </SwitchItem>
+ <Forms.FormDivider />
+ <Forms.FormTitle tag="h5">Plugins</Forms.FormTitle>
+ {Plugins.map(p => (
+ <SwitchItem
+ disabled={p.required === true}
+ key={p.name}
+ value={settings.plugins[p.name].enabled}
+ onChange={v => {
+ settings.plugins[p.name].enabled = v;
+ if (v) {
+ p.dependencies?.forEach(d => {
+ settings.plugins[d].enabled = true;
+ });
+ }
+ }}
+ note={p.description}
+ tooltipNote={p.required ? "This plugin is required. Thus you cannot disable it." : undefined}
+ >
+ {p.name}
+ </SwitchItem>
+ ))
+ }
+ </Forms.FormSection >
+ );
} \ No newline at end of file
diff --git a/src/ipcMain.ts b/src/ipcMain.ts
index c8fba37..38a16ab 100644
--- a/src/ipcMain.ts
+++ b/src/ipcMain.ts
@@ -1,25 +1,39 @@
-import { app, BrowserWindow, ipcMain } from "electron";
-import { fstat, watch } from "fs";
-import { open, readFile } from "fs/promises";
+import { app, BrowserWindow, ipcMain, shell } from "electron";
+import { readFileSync, watch } from "fs";
+import { open, readFile, writeFile } from "fs/promises";
import { join } from 'path';
-import { IPC_GET_SETTINGS_DIR, IPC_GET_QUICK_CSS, IPC_QUICK_CSS_UPDATE } from './utils/ipcEvents';
+import IpcEvents from './utils/IpcEvents';
const DATA_DIR = join(app.getPath("userData"), "..", "Vencord");
const SETTINGS_DIR = join(DATA_DIR, "settings");
const QUICKCSS_PATH = join(SETTINGS_DIR, "quickCss.css");
+const SETTINGS_FILE = join(SETTINGS_DIR, "settings.json");
function readCss() {
return readFile(QUICKCSS_PATH, "utf-8").catch(() => "");
}
-ipcMain.handle(IPC_GET_SETTINGS_DIR, () => SETTINGS_DIR);
-ipcMain.handle(IPC_GET_QUICK_CSS, () => readCss());
+function readSettings() {
+ try {
+ return readFileSync(SETTINGS_FILE, "utf-8");
+ } catch {
+ return "{}";
+ }
+}
+
+ipcMain.handle(IpcEvents.GET_SETTINGS_DIR, () => SETTINGS_DIR);
+ipcMain.handle(IpcEvents.GET_QUICK_CSS, () => readCss());
+// .on because we need Settings synchronously (ipcRenderer.sendSync)
+ipcMain.on(IpcEvents.GET_SETTINGS, (e) => e.returnValue = readSettings());
+ipcMain.handle(IpcEvents.SET_SETTINGS, (_, s) => void writeFile(SETTINGS_FILE, s));
+ipcMain.handle(IpcEvents.OPEN_PATH, (_, path) => shell.openPath(path));
+ipcMain.handle(IpcEvents.OPEN_EXTERNAL, (_, url) => shell.openExternal(url));
export function initIpc(mainWindow: BrowserWindow) {
open(QUICKCSS_PATH, "a+").then(fd => {
fd.close();
watch(QUICKCSS_PATH, async () => {
- mainWindow.webContents.postMessage(IPC_QUICK_CSS_UPDATE, await readCss());
+ mainWindow.webContents.postMessage(IpcEvents.QUICK_CSS_UPDATE, await readCss());
});
});
}
diff --git a/src/plugins/index.ts b/src/plugins/index.ts
index d5b419b..ae67f4f 100644
--- a/src/plugins/index.ts
+++ b/src/plugins/index.ts
@@ -1,4 +1,5 @@
import Plugins from "plugins";
+import { Settings } from "../api/settings";
import Logger from "../utils/logger";
import { Patch } from "../utils/types";
@@ -7,7 +8,7 @@ const logger = new Logger("PluginManager", "#a6d189");
export const plugins = Plugins;
export const patches = [] as Patch[];
-for (const plugin of Plugins) if (plugin.patches) {
+for (const plugin of Plugins) if (plugin.patches && Settings.plugins[plugin.name].enabled) {
for (const patch of plugin.patches) {
patch.plugin = plugin.name;
if (!Array.isArray(patch.replacement)) patch.replacement = [patch.replacement];
@@ -16,7 +17,7 @@ for (const plugin of Plugins) if (plugin.patches) {
}
export function startAll() {
- for (const plugin of plugins) if (plugin.start) {
+ for (const plugin of plugins) if (plugin.start && Settings.plugins[plugin.name].enabled) {
try {
logger.info("Starting plugin", plugin.name);
plugin.start();
diff --git a/src/plugins/messageActions.ts b/src/plugins/messageActions.ts
index c2857cb..5519cf7 100644
--- a/src/plugins/messageActions.ts
+++ b/src/plugins/messageActions.ts
@@ -1,11 +1,12 @@
import { MessageClicks } from "../api";
import definePlugin from "../utils/types";
-import { find, findByProps } from "../utils/webpack";
+import { find, findByProps } from "../webpack";
export default definePlugin({
name: "MessageQuickActions",
description: "Quick Delete, Quick edit",
author: "Vendicated",
+ dependencies: ["MessageClicksApi"],
start() {
const { deleteMessage, startEditMessage } = findByProps("deleteMessage");
const { can } = findByProps("can", "initialize");
diff --git a/src/plugins/noTrack.ts b/src/plugins/noTrack.ts
index 6d3a0ba..642d88c 100644
--- a/src/plugins/noTrack.ts
+++ b/src/plugins/noTrack.ts
@@ -1,5 +1,5 @@
import definePlugin from "../utils/types";
-import { findByProps } from "../utils/webpack";
+import { findByProps } from "../webpack";
const DO_NOTHING = () => void 0;
@@ -7,6 +7,7 @@ export default definePlugin({
name: "NoTrack",
description: "Disable Discord's tracking and crash reporting",
author: "Vendicated",
+ required: true,
start() {
findByProps("getSuperPropertiesBase64", "track").track = DO_NOTHING;
findByProps("submitLiveCrashReport").submitLiveCrashReport = DO_NOTHING;
diff --git a/src/plugins/settings.ts b/src/plugins/settings.ts
index fa214f0..63c36d6 100644
--- a/src/plugins/settings.ts
+++ b/src/plugins/settings.ts
@@ -5,6 +5,7 @@ export default definePlugin({
name: "Settings",
description: "Adds Settings UI and debug info",
author: "Vendicated",
+ required: true,
patches: [{
find: "default.versionHash",
replacement: [
@@ -28,7 +29,7 @@ export default definePlugin({
}, {
find: "Messages.ACTIVITY_SETTINGS",
replacement: {
- match: /\{section:(.{1,2})\.SectionTypes\.HEADER,label:(.{1,2})\.default\.Messages\.ACTIVITY_SETTINGS\}/,
+ match: /\{section:(.{1,2})\.SectionTypes\.HEADER,\s*label:(.{1,2})\.default\.Messages\.ACTIVITY_SETTINGS\}/,
replace: (m, mod) =>
`{section:${mod}.SectionTypes.HEADER,label:"Vencord"},` +
`{section:"Vencord",label:"Vencord",element:Vencord.Components.Settings},` +
diff --git a/src/utils/IpcEvents.ts b/src/utils/IpcEvents.ts
new file mode 100644
index 0000000..70ba502
--- /dev/null
+++ b/src/utils/IpcEvents.ts
@@ -0,0 +1,22 @@
+type Enum<T extends Record<string, string>> = {
+ [k in keyof T]: T[k];
+} & { [v in keyof T as T[v]]: v; };
+
+function strEnum<T extends Record<string, string>>(obj: T): T {
+ const o = {} as T;
+ for (const key in obj) {
+ o[key] = obj[key] as any;
+ o[obj[key]] = key as any;
+ };
+ return o;
+}
+
+export default strEnum({
+ QUICK_CSS_UPDATE: "VencordQuickCssUpdate",
+ GET_QUICK_CSS: "VencordGetQuickCss",
+ GET_SETTINGS_DIR: "VencordGetSettingsDir",
+ GET_SETTINGS: "VencordGetSettings",
+ SET_SETTINGS: "VencordSetSettings",
+ OPEN_EXTERNAL: "VencordOpenExternal",
+ OPEN_PATH: "VencordOpenPath",
+} as const); \ No newline at end of file
diff --git a/src/utils/ipcEvents.ts b/src/utils/ipcEvents.ts
deleted file mode 100644
index 1920023..0000000
--- a/src/utils/ipcEvents.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export const IPC_QUICK_CSS_UPDATE = "VencordQuickCssUpdate";
-export const IPC_GET_QUICK_CSS = "VencordGetQuickCss";
-export const IPC_GET_SETTINGS_DIR = "VencordGetSettingsDir"; \ No newline at end of file
diff --git a/src/utils/misc.tsx b/src/utils/misc.tsx
new file mode 100644
index 0000000..ded052b
--- /dev/null
+++ b/src/utils/misc.tsx
@@ -0,0 +1,61 @@
+import { React } from "../webpack";
+
+/**
+ * Makes a lazy function. On first call, the value is computed.
+ * On subsequent calls, the same computed value will be returned
+ * @param factory Factory function
+ */
+export function lazy<T>(factory: () => T): () => T {
+ let cache: T;
+ return () => {
+ return cache ?? (cache = factory());
+ };
+}
+
+/**
+ * Await a promise
+ * @param factory Factory
+ * @param fallbackValue The fallback value that will be used until the promise resolved
+ * @returns A state that will either be null or the result of the promise
+ */
+export function useAwaiter<T>(factory: () => Promise<T>, fallbackValue: T | null = null): T | null {
+ const [res, setRes] = React.useState<T | null>(fallbackValue);
+
+ React.useEffect(() => {
+ factory().then(setRes);
+ }, []);
+
+ return res;
+}
+
+/**
+ * A lazy component. The factory method is called on first render. For example useful
+ * for const Component = LazyComponent(() => findByDisplayName("...").default)
+ * @param factory Function returning a Component
+ * @returns Result of factory function
+ */
+export function LazyComponent<T = any>(factory: () => React.ComponentType<T>) {
+ return (props: T) => {
+ const Component = React.useMemo(factory, []);
+ return <Component {...props} />;
+ };
+}
+
+/**
+ * Recursively merges defaults into an object and returns the same object
+ * @param obj Object
+ * @param defaults Defaults
+ * @returns obj
+ */
+export function mergeDefaults<T>(obj: T, defaults: T): T {
+ for (const key in defaults) {
+ const v = defaults[key];
+ if (typeof v === "object" && !Array.isArray(v)) {
+ obj[key] ??= {} as any;
+ mergeDefaults(obj[key], v);
+ } else {
+ obj[key] ??= v;
+ }
+ }
+ return obj;
+} \ No newline at end of file
diff --git a/src/utils/patchWebpack.ts b/src/utils/patchWebpack.ts
index 0e94694..9f4b435 100644
--- a/src/utils/patchWebpack.ts
+++ b/src/utils/patchWebpack.ts
@@ -1,6 +1,6 @@
import { WEBPACK_CHUNK } from './constants';
import Logger from "./logger";
-import { _initWebpack } from "./webpack";
+import { _initWebpack } from "../webpack";
let webpackChunk: any[];
@@ -83,9 +83,13 @@ function patchPush() {
const lastCode = code;
try {
const newCode = code.replace(replacement.match, replacement.replace);
- const newMod = (0, eval)(`// Webpack Module ${id} - Patched by ${[...patchedBy].join(", ")}\n${newCode}\n//# sourceURL=WebpackModule${id}`);
- code = newCode;
- mod = newMod;
+ if (newCode === code) {
+ logger.warn(`Patch by ${patch.plugin} had no effect: ${replacement.match}`);
+ } else {
+ const newMod = (0, eval)(`// Webpack Module ${id} - Patched by ${[...patchedBy].join(", ")}\n${newCode}\n//# sourceURL=WebpackModule${id}`);
+ code = newCode;
+ mod = newMod;
+ }
} catch (err) {
logger.error("Failed to apply patch of", patch.plugin, err);
code = lastCode;
diff --git a/src/utils/quickCss.ts b/src/utils/quickCss.ts
index 724fde8..5c9e830 100644
--- a/src/utils/quickCss.ts
+++ b/src/utils/quickCss.ts
@@ -1,6 +1,8 @@
+import IpcEvents from "./IpcEvents";
+
document.addEventListener("DOMContentLoaded", async () => {
const style = document.createElement("style");
document.head.appendChild(style);
- VencordNative.handleQuickCssUpdate((css: string) => style.innerText = css);
- style.innerText = await VencordNative.getQuickCss();
+ VencordNative.ipc.on(IpcEvents.QUICK_CSS_UPDATE, (_, css: string) => style.innerText = css);
+ style.innerText = await VencordNative.ipc.invoke(IpcEvents.GET_QUICK_CSS);
});
diff --git a/src/utils/types.ts b/src/utils/types.ts
index 282ca0e..520b506 100644
--- a/src/utils/types.ts
+++ b/src/utils/types.ts
@@ -20,6 +20,8 @@ export interface Plugin {
author: string;
start?(): void;
patches?: Patch[];
+ dependencies?: string[],
+ required?: boolean;
}
// @ts-ignore lole
diff --git a/src/utils/webpack.ts b/src/webpack/index.ts
index 3f21106..2c5a455 100644
--- a/src/utils/webpack.ts
+++ b/src/webpack/index.ts
@@ -1,5 +1,4 @@
import { startAll } from "../plugins";
-import Logger from "./logger";
let webpackCache: typeof window.webpackChunkdiscord_app;
@@ -9,11 +8,10 @@ export const listeners = new Set<CallbackFn>();
type FilterFn = (mod: any) => boolean;
type CallbackFn = (mod: any) => void;
-export let Common: {
- React: typeof import("react"),
- FluxDispatcher: any;
- UserStore: any;
-} = {} as any;
+export let React: typeof import("react");
+export let FluxDispatcher: any;
+export let Forms: any;
+export let UserStore: any;
export function _initWebpack(instance: typeof window.webpackChunkdiscord_app) {
if (webpackCache !== void 0) throw "no.";
@@ -24,9 +22,9 @@ export function _initWebpack(instance: typeof window.webpackChunkdiscord_app) {
// Abandon Hope All Ye Who Enter Here
let started = false;
- waitFor("getCurrentUser", x => Common.UserStore = x);
+ waitFor("getCurrentUser", x => UserStore = x);
waitFor(["dispatch", "subscribe"], x => {
- Common.FluxDispatcher = x;
+ FluxDispatcher = x;
const cb = () => {
console.info("Connection open");
x.unsubscribe("CONNECTION_OPEN", cb);
@@ -34,7 +32,8 @@ export function _initWebpack(instance: typeof window.webpackChunkdiscord_app) {
};
x.subscribe("CONNECTION_OPEN", cb);
});
- waitFor("useState", x => Common.React = x);
+ waitFor("useState", x => (React = x));
+ waitFor("FormSection", x => Forms = x);
}
export function find(filter: FilterFn, getDefault = true) {
diff --git a/tsconfig.json b/tsconfig.json
index 6489d93..d17ff09 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -9,7 +9,7 @@
"noImplicitAny": false,
"target": "ESNEXT",
// https://esbuild.github.io/api/#jsx-factory
- "jsxFactory": "Vencord.Webpack.Common.React.createElement",
+ "jsxFactory": "Vencord.Webpack.React.createElement",
"jsx": "react"
},
"include": ["src/**/*"]