diff options
| author | Ven <vendicated@riseup.net> | 2023-01-25 03:25:29 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-01-25 03:25:29 +0100 |
| commit | f19504f8282702bc6945a3d97acbee1a1fbe1b8d (patch) | |
| tree | 0a84a831dbd4e3fa040b6b1287db4d309de7c5d9 /src | |
| parent | a38ac956dfaf53711a4cddea73ae1b8cf617211a (diff) | |
| download | Vencord-f19504f8282702bc6945a3d97acbee1a1fbe1b8d.tar.gz Vencord-f19504f8282702bc6945a3d97acbee1a1fbe1b8d.tar.bz2 Vencord-f19504f8282702bc6945a3d97acbee1a1fbe1b8d.zip | |
split up webpack commons into categories & type everything (#455)
Diffstat (limited to 'src')
24 files changed, 930 insertions, 372 deletions
diff --git a/src/Vencord.ts b/src/Vencord.ts index 82d5af0..ac8579b 100644 --- a/src/Vencord.ts +++ b/src/Vencord.ts @@ -32,7 +32,7 @@ import { PlainSettings, Settings } from "./api/settings"; import { patches, PMLogger, startAllPlugins } from "./plugins"; import { checkForUpdates, rebuild, update, UpdateLogger } from "./utils/updater"; import { onceReady } from "./webpack"; -import { Router } from "./webpack/common"; +import { SettingsRouter } from "./webpack/common"; export let Components: any; @@ -71,7 +71,7 @@ async function init() { "View Update", () => { popNotice(); - Router.open("VencordUpdater"); + SettingsRouter.open("VencordUpdater"); } ); }, 10_000); diff --git a/src/components/PluginSettings/index.tsx b/src/components/PluginSettings/index.tsx index f439753..34e6828 100644 --- a/src/components/PluginSettings/index.tsx +++ b/src/components/PluginSettings/index.tsx @@ -326,7 +326,9 @@ export default ErrorBoundary.wrap(function PluginSettings() { <div className={cl("grid")}> {plugins} </div> - <Forms.FormDivider /> + + <Forms.FormDivider className={Margins.marginTop20} /> + <Forms.FormTitle tag="h5" className={classes(Margins.marginTop20, Margins.marginBottom8)}> Required Plugins </Forms.FormTitle> diff --git a/src/components/VencordSettings/BackupRestoreTab.tsx b/src/components/VencordSettings/BackupRestoreTab.tsx index 546db35..2ea0452 100644 --- a/src/components/VencordSettings/BackupRestoreTab.tsx +++ b/src/components/VencordSettings/BackupRestoreTab.tsx @@ -45,7 +45,7 @@ function BackupRestoreTab() { </Text> <Flex> <Button - onClick={uploadSettingsBackup} + onClick={() => uploadSettingsBackup()} size={Button.Sizes.SMALL} > Import Settings diff --git a/src/components/VencordSettings/ThemesTab.tsx b/src/components/VencordSettings/ThemesTab.tsx index 69fcc29..b59590c 100644 --- a/src/components/VencordSettings/ThemesTab.tsx +++ b/src/components/VencordSettings/ThemesTab.tsx @@ -75,7 +75,7 @@ function Validators({ themeLinks }: { themeLinks: string[]; }) { export default ErrorBoundary.wrap(function () { const settings = useSettings(); - const ref = React.useRef<HTMLTextAreaElement>(); + const ref = React.useRef<HTMLTextAreaElement>(null); function onBlur() { settings.themeLinks = [...new Set( diff --git a/src/components/VencordSettings/index.tsx b/src/components/VencordSettings/index.tsx index 2ab9407..acd81c3 100644 --- a/src/components/VencordSettings/index.tsx +++ b/src/components/VencordSettings/index.tsx @@ -21,7 +21,7 @@ import "./settingsStyles.css"; import { classNameFactory } from "@api/Styles"; import ErrorBoundary from "@components/ErrorBoundary"; import { findByCodeLazy } from "@webpack"; -import { Forms, Router, Text } from "@webpack/common"; +import { Forms, SettingsRouter, Text } from "@webpack/common"; import BackupRestoreTab from "./BackupRestoreTab"; import PluginsTab from "./PluginsTab"; @@ -65,7 +65,7 @@ function Settings(props: SettingsProps) { look={TabBar.Looks.BRAND} className={cl("tab-bar")} selectedItem={tab} - onItemSelect={Router.open} + onItemSelect={SettingsRouter.open} > {Object.entries(SettingsTabs).map(([key, { name, component }]) => { if (!component) return null; diff --git a/src/ipcMain/updater/git.ts b/src/ipcMain/updater/git.ts index e787b8f..89c2d3c 100644 --- a/src/ipcMain/updater/git.ts +++ b/src/ipcMain/updater/git.ts @@ -28,7 +28,7 @@ const VENCORD_SRC_DIR = join(__dirname, ".."); const execFile = promisify(cpExecFile); -const isFlatpak = Boolean(process.env.FLATPAK_ID?.includes("discordapp") || process.env.FLATPAK_ID?.includes("Discord")); +const isFlatpak = process.platform === "linux" && Boolean(process.env.FLATPAK_ID?.includes("discordapp") || process.env.FLATPAK_ID?.includes("Discord")); if (process.platform === "darwin") process.env.PATH = `/usr/local/bin:${process.env.PATH}`; diff --git a/src/ipcMain/updater/http.ts b/src/ipcMain/updater/http.ts index 25dc5ba..cc10631 100644 --- a/src/ipcMain/updater/http.ts +++ b/src/ipcMain/updater/http.ts @@ -49,7 +49,7 @@ async function calculateGitChanges() { const res = await githubGet(`/compare/${gitHash}...HEAD`); const data = JSON.parse(res.toString("utf-8")); - return data.commits.map(c => ({ + return data.commits.map((c: any) => ({ // github api only sends the long sha hash: c.sha.slice(0, 7), author: c.author.login, diff --git a/src/plugins/settings.tsx b/src/plugins/settings.tsx index 36bf525..67d1f8d 100644 --- a/src/plugins/settings.tsx +++ b/src/plugins/settings.tsx @@ -22,7 +22,7 @@ import { Devs } from "@utils/constants"; import Logger from "@utils/Logger"; import { LazyComponent } from "@utils/misc"; import definePlugin, { OptionType } from "@utils/types"; -import { Router } from "@webpack/common"; +import { SettingsRouter } from "@webpack/common"; import gitHash from "~git-hash"; @@ -69,7 +69,7 @@ export default definePlugin({ }], makeSettingsCategories({ ID }: { ID: Record<string, unknown>; }) { - const makeOnClick = (tab: string) => () => Router.open(tab); + const makeOnClick = (tab: string) => () => SettingsRouter.open(tab); const cats = [ { diff --git a/src/plugins/spotifyControls/SpotifyStore.ts b/src/plugins/spotifyControls/SpotifyStore.ts index 641ba1a..ceac577 100644 --- a/src/plugins/spotifyControls/SpotifyStore.ts +++ b/src/plugins/spotifyControls/SpotifyStore.ts @@ -76,10 +76,6 @@ export const SpotifyStore = proxyLazy(() => { const API_BASE = "https://api.spotify.com/v1/me/player"; class SpotifyStore extends Store { - constructor(dispatcher: any, handlers: any) { - super(dispatcher, handlers); - } - public mPosition = 0; private start = 0; diff --git a/src/plugins/viewRaw.tsx b/src/plugins/viewRaw.tsx index fc7a42a..5105203 100644 --- a/src/plugins/viewRaw.tsx +++ b/src/plugins/viewRaw.tsx @@ -98,7 +98,7 @@ function openViewRawModal(msg: Message) { <> <Forms.FormTitle tag="h5">Content</Forms.FormTitle> <CodeBlock content={msg.content} lang="" /> - <Forms.FormDivider classes={Margins.marginBottom20} /> + <Forms.FormDivider className={Margins.marginBottom20} /> </> )} diff --git a/src/utils/misc.tsx b/src/utils/misc.tsx index 0ef7ffb..c64d9e1 100644 --- a/src/utils/misc.tsx +++ b/src/utils/misc.tsx @@ -153,34 +153,6 @@ export function sleep(ms: number): Promise<void> { } /** - * Wraps a Function into a try catch block and logs any errors caught - * Due to the nature of this function, not all paths return a result. - * Thus, for consistency, the returned functions will always return void or Promise<void> - * - * @param name Name identifying the wrapped function. This will appear in the logged errors - * @param func Function (async or sync both work) - * @param thisObject Optional thisObject - * @returns Wrapped Function - */ -export function suppressErrors<F extends Function>(name: string, func: F, thisObject?: any): F { - return (func.constructor.name === "AsyncFunction" - ? async function (this: any) { - try { - await func.apply(thisObject ?? this, arguments); - } catch (e) { - console.error(`Caught an Error in ${name || "anonymous"}\n`, e); - } - } - : function (this: any) { - try { - func.apply(thisObject ?? this, arguments); - } catch (e) { - console.error(`Caught an Error in ${name || "anonymous"}\n`, e); - } - }) as any as F; -} - -/** * Wrap the text in ``` with an optional language */ export function makeCodeblock(text: string, language?: string) { diff --git a/src/utils/modal.tsx b/src/utils/modal.tsx index 73dd009..3174cac 100644 --- a/src/utils/modal.tsx +++ b/src/utils/modal.tsx @@ -17,6 +17,9 @@ */ import { filters, mapMangledModuleLazy } from "@webpack"; +import type { ComponentType, PropsWithChildren, ReactNode, Ref } from "react"; + +import { LazyComponent } from "./misc"; export enum ModalSize { SMALL = "small", @@ -44,16 +47,7 @@ export interface ModalOptions { onCloseCallback?: (() => void); } -interface ModalRootProps { - transitionState: ModalTransitionState; - children: React.ReactNode; - size?: ModalSize; - role?: "alertdialog" | "dialog"; - className?: string; - onAnimationEnd?(): string; -} - -type RenderFunction = (props: ModalProps) => React.ReactNode; +type RenderFunction = (props: ModalProps) => ReactNode; export const Modals = mapMangledModuleLazy(".closeWithCircleBackground", { ModalRoot: filters.byCode(".root"), @@ -61,13 +55,63 @@ export const Modals = mapMangledModuleLazy(".closeWithCircleBackground", { ModalContent: filters.byCode(".content"), ModalFooter: filters.byCode(".footerSeparator"), ModalCloseButton: filters.byCode(".closeWithCircleBackground"), -}); +}) as { + ModalRoot: ComponentType<PropsWithChildren<{ + transitionState: ModalTransitionState; + size?: ModalSize; + role?: "alertdialog" | "dialog"; + className?: string; + fullscreenOnMobile?: boolean; + "aria-label"?: string; + "aria-labelledby"?: string; + onAnimationEnd?(): string; + }>>; + ModalHeader: ComponentType<PropsWithChildren<{ + /** Flex.Justify.START */ + justify?: string; + /** Flex.Direction.HORIZONTAL */ + direction?: string; + /** Flex.Align.CENTER */ + align?: string; + /** Flex.Wrap.NO_WRAP */ + wrap?: string; + separator?: boolean; + + className?: string; + }>>; + /** This also accepts Scroller props but good luck with that */ + ModalContent: ComponentType<PropsWithChildren<{ + className?: string; + scrollerRef?: Ref<HTMLElement>; + [prop: string]: any; + }>>; + ModalFooter: ComponentType<PropsWithChildren<{ + /** Flex.Justify.START */ + justify?: string; + /** Flex.Direction.HORIZONTAL_REVERSE */ + direction?: string; + /** Flex.Align.STRETCH */ + align?: string; + /** Flex.Wrap.NO_WRAP */ + wrap?: string; + separator?: boolean; + + className?: string; + }>>; + ModalCloseButton: ComponentType<{ + focusProps?: any; + onClick(): void; + withCircleBackground?: boolean; + hideOnFullscreen?: boolean; + className?: string; + }>; +}; -export const ModalRoot = (props: ModalRootProps) => <Modals.ModalRoot {...props} />; -export const ModalHeader = (props: any) => <Modals.ModalHeader {...props} />; -export const ModalContent = (props: any) => <Modals.ModalContent {...props} />; -export const ModalFooter = (props: any) => <Modals.ModalFooter {...props} />; -export const ModalCloseButton = (props: any) => <Modals.ModalCloseButton {...props} />; +export const ModalRoot = LazyComponent(() => Modals.ModalRoot); +export const ModalHeader = LazyComponent(() => Modals.ModalHeader); +export const ModalContent = LazyComponent(() => Modals.ModalContent); +export const ModalFooter = LazyComponent(() => Modals.ModalFooter); +export const ModalCloseButton = LazyComponent(() => Modals.ModalCloseButton); const ModalAPI = mapMangledModuleLazy("onCloseRequest:null!=", { openModal: filters.byCode("onCloseRequest:null!="), diff --git a/src/webpack/common.tsx b/src/webpack/common.tsx deleted file mode 100644 index 562332a..0000000 --- a/src/webpack/common.tsx +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2022 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ - -import { LazyComponent } from "@utils/misc"; -import { proxyLazy } from "@utils/proxyLazy"; -import { - _resolveReady, - filters, findByCode, findByCodeLazy, findByPropsLazy, mapMangledModule, mapMangledModuleLazy, waitFor -} from "@webpack"; -import type Components from "discord-types/components"; -import { User } from "discord-types/general"; -import type Other from "discord-types/other"; -import type Stores from "discord-types/stores"; - -export const Margins = findByPropsLazy("marginTop20"); - -export let FluxDispatcher: Other.FluxDispatcher; -export const Flux = findByPropsLazy("connectStores"); - -export let React: typeof import("react"); -export let useState: typeof React.useState; -export let useEffect: typeof React.useEffect; -export let useMemo: typeof React.useMemo; -export let useRef: typeof React.useRef; - -export const ReactDOM: typeof import("react-dom") = findByPropsLazy("createPortal", "render"); - -export const RestAPI = findByPropsLazy("getAPIBaseURL", "get"); -export const moment: typeof import("moment") = findByPropsLazy("parseTwoDigitYear"); - -export const hljs: typeof import("highlight.js") = findByPropsLazy("highlight"); - -export const MessageStore = findByPropsLazy("getRawMessages") as Omit<Stores.MessageStore, "getMessages"> & { - getMessages(chanId: string): any; -}; -export const PermissionStore = findByPropsLazy("can", "getGuildPermissions"); -export const PrivateChannelsStore = findByPropsLazy("openPrivateChannel"); -export const GuildChannelStore = findByPropsLazy("getChannels"); -export const ReadStateStore = findByPropsLazy("lastMessageId"); -export const PresenceStore = findByPropsLazy("setCurrentUserOnConnectionOpen"); -export let GuildStore: Stores.GuildStore; -export let UserStore: Stores.UserStore; -export let SelectedChannelStore: Stores.SelectedChannelStore; -export let SelectedGuildStore: any; -export let ChannelStore: Stores.ChannelStore; -export let GuildMemberStore: Stores.GuildMemberStore; -export let RelationshipStore: Stores.RelationshipStore & { - /** Get the date (as a string) that the relationship was created */ - getSince(userId: string): string; -}; - -export const Forms = {} as { - FormTitle: Components.FormTitle; - FormSection: any; - FormDivider: any; - FormText: Components.FormText; -}; -export let Card: Components.Card; -export let Button: any; -export const ButtonLooks = findByPropsLazy("BLANK", "FILLED", "INVERTED") as Record<"FILLED" | "INVERTED" | "OUTLINED" | "LINK" | "BLANK", string>; -export let Switch: any; -export let Tooltip: Components.Tooltip; -export let Timestamp: any; -export let Router: any; -export let TextInput: any; -export let Text: (props: TextProps) => JSX.Element; -export const TextArea = findByCodeLazy("handleSetRef", "textArea") as React.ComponentType<React.PropsWithRef<any>>; -export const ButtonWrapperClasses = findByPropsLazy("buttonWrapper", "buttonContent") as Record<string, string>; - -export const Select = LazyComponent(() => findByCode("optionClassName", "popoutPosition", "autoFocus", "maxVisibleItems")); -export const Slider = LazyComponent(() => findByCode("closestMarkerIndex", "stickToMarkers")); - -export let SnowflakeUtils: { fromTimestamp: (timestamp: number) => string, extractTimestamp: (snowflake: string) => number; }; -waitFor(["fromTimestamp", "extractTimestamp"], m => SnowflakeUtils = m); - -export let Parser: any; -export let Alerts: { - show(alert: { - title: any; - body: React.ReactNode; - className?: string; - confirmColor?: string; - cancelText?: string; - confirmText?: string; - secondaryConfirmText?: string; - onCancel?(): void; - onConfirm?(): void; - onConfirmSecondary?(): void; - }): void; - /** This is a noop, it does nothing. */ - close(): void; -}; -const ToastType = { - MESSAGE: 0, - SUCCESS: 1, - FAILURE: 2, - CUSTOM: 3 -}; -const ToastPosition = { - TOP: 0, - BOTTOM: 1 -}; - -export const Toasts = { - Type: ToastType, - Position: ToastPosition, - // what's less likely than getting 0 from Math.random()? Getting it twice in a row - genId: () => (Math.random() || Math.random()).toString(36).slice(2), - - // hack to merge with the following interface, dunno if there's a better way - ...{} as { - show(data: { - message: string, - id: string, - /** - * Toasts.Type - */ - type: number, - options?: { - /** - * Toasts.Position - */ - position?: number; - component?: React.ReactNode, - duration?: number; - }; - }): void; - pop(): void; - } -}; - -export const UserUtils = { - fetchUser: findByCodeLazy(".USER(", "getUser") as (id: string) => Promise<User>, -}; - -export const Clipboard = mapMangledModuleLazy('document.queryCommandEnabled("copy")||document.queryCommandSupported("copy")', { - copy: filters.byCode(".default.copy("), - SUPPORTS_COPY: x => typeof x === "boolean", -}); - -export const NavigationRouter = mapMangledModuleLazy("Transitioning to external path", { - transitionTo: filters.byCode("Transitioning to external path"), - transitionToGuild: filters.byCode("transitionToGuild"), - goBack: filters.byCode("goBack()"), - goForward: filters.byCode("goForward()"), -}); - -waitFor("useState", m => { - React = m; - ({ useEffect, useState, useMemo, useRef } = React); -}); - -waitFor(["dispatch", "subscribe"], m => { - FluxDispatcher = m; - const cb = () => { - m.unsubscribe("CONNECTION_OPEN", cb); - _resolveReady(); - }; - m.subscribe("CONNECTION_OPEN", cb); -}); - -waitFor(["getCurrentUser", "initialize"], m => UserStore = m); -waitFor("getSortedPrivateChannels", m => ChannelStore = m); -waitFor("getCurrentlySelectedChannelId", m => SelectedChannelStore = m); -waitFor("getLastSelectedGuildId", m => SelectedGuildStore = m); -waitFor("getGuildCount", m => GuildStore = m); -waitFor(["getMember", "initialize"], m => GuildMemberStore = m); -waitFor("getRelationshipType", m => RelationshipStore = m); - -waitFor(["Hovers", "Looks", "Sizes"], m => Button = m); - -waitFor(filters.byCode("tooltipNote", "ringTarget"), m => Switch = m); - -waitFor(filters.byCode(".Messages.MESSAGE_EDITED_TIMESTAMP_A11Y_LABEL.format"), m => Timestamp = m); - -waitFor(["Positions", "Colors"], m => Tooltip = m); -waitFor(m => m.Types?.PRIMARY === "cardPrimary", m => Card = m); - -waitFor(filters.byCode("errorSeparator"), m => Forms.FormTitle = m); -waitFor(filters.byCode("titleClassName", "sectionTitle"), m => Forms.FormSection = m); -waitFor(m => m.Types?.INPUT_PLACEHOLDER, m => Forms.FormText = m); - -waitFor(m => { - if (typeof m !== "function") return false; - const s = m.toString(); - return s.length < 200 && s.includes(".divider"); -}, m => Forms.FormDivider = m); - -// This is the same module but this is easier -waitFor(filters.byCode("currentToast?"), m => Toasts.show = m); -waitFor(filters.byCode("currentToast:null"), m => Toasts.pop = m); - -waitFor(["show", "close"], m => Alerts = m); -waitFor("parseTopic", m => Parser = m); - -waitFor(["open", "saveAccountChanges"], m => Router = m); -waitFor(["defaultProps", "Sizes", "contextType"], m => TextInput = m); - -waitFor(m => { - if (typeof m !== "function") return false; - const s = m.toString(); - return (s.length < 1500 && s.includes("data-text-variant") && s.includes("always-white")); -}, m => Text = m); - -export type TextProps = React.PropsWithChildren & { - variant: TextVariant; - style?: React.CSSProperties; - color?: string; - tag?: "div" | "span" | "p" | "strong" | `h${1 | 2 | 3 | 4 | 5 | 6}`; - selectable?: boolean; - lineClamp?: number; - id?: string; - className?: string; -}; - -export type TextVariant = "heading-sm/normal" | "heading-sm/medium" | "heading-sm/semibold" | "heading-sm/bold" | "heading-md/normal" | "heading-md/medium" | "heading-md/semibold" | "heading-md/bold" | "heading-lg/normal" | "heading-lg/medium" | "heading-lg/semibold" | "heading-lg/bold" | "heading-xl/normal" | "heading-xl/medium" | "heading-xl/bold" | "heading-xxl/normal" | "heading-xxl/medium" | "heading-xxl/bold" | "eyebrow" | "heading-deprecated-14/normal" | "heading-deprecated-14/medium" | "heading-deprecated-14/bold" | "text-xxs/normal" | "text-xxs/medium" | "text-xxs/semibold" | "text-xxs/bold" | "text-xs/normal" | "text-xs/medium" | "text-xs/semibold" | "text-xs/bold" | "text-sm/normal" | "text-sm/medium" | "text-sm/semibold" | "text-sm/bold" | "text-md/normal" | "text-md/medium" | "text-md/semibold" | "text-md/bold" | "text-lg/normal" | "text-lg/medium" | "text-lg/semibold" | "text-lg/bold" | "display-sm" | "display-md" | "display-lg" | "code"; - -type RC<C> = React.ComponentType<React.PropsWithChildren<C & Record<string, any>>>; -interface Menu { - ContextMenu: RC<{ - navId: string; - onClose(): void; - className?: string; - style?: React.CSSProperties; - hideScroller?: boolean; - onSelect?(): void; - }>; - MenuSeparator: React.ComponentType; - MenuGroup: RC<any>; - MenuItem: RC<{ - id: string; - label: string; - render?: React.ComponentType; - onChildrenScroll?: Function; - childRowHeight?: number; - listClassName?: string; - }>; - MenuCheckboxItem: RC<{ - id: string; - }>; - MenuRadioItem: RC<{ - id: string; - }>; - MenuControlItem: RC<{ - id: string; - interactive?: boolean; - }>; -} - -/** - * Discord's Context menu items. - * To use anything but Menu.ContextMenu, your plugin HAS TO - * depend on MenuItemDeobfuscatorAPI. Otherwise they will throw - */ -export const Menu = proxyLazy(() => { - const hasDeobfuscator = Vencord.Settings.plugins.MenuItemDeobfuscatorAPI.enabled; - const menuItems = ["MenuSeparator", "MenuGroup", "MenuItem", "MenuCheckboxItem", "MenuRadioItem", "MenuControlItem"]; - - const map = mapMangledModule("♫ ⊂(。◕‿‿◕。⊂) ♪", { - ContextMenu: filters.byCode("getContainerProps"), - ...Object.fromEntries((hasDeobfuscator ? menuItems : []).map(s => [s, (m: any) => m.name === s])) - }) as Menu; - - if (!hasDeobfuscator) { - for (const m of menuItems) - Object.defineProperty(map, m, { - get() { - throw new Error("MenuItemDeobfuscator must be enabled to use this."); - } - }); - } - - return map; -}); - -export const ContextMenu = mapMangledModuleLazy('type:"CONTEXT_MENU_OPEN"', { - open: filters.byCode("stopPropagation"), - openLazy: m => m.toString().length < 50, - close: filters.byCode("CONTEXT_MENU_CLOSE") -}) as { - close(): void; - open( - event: React.UIEvent, - render?: Menu["ContextMenu"], - options?: { enableSpellCheck?: boolean; }, - renderLazy?: () => Promise<Menu["ContextMenu"]> - ): void; - openLazy( - event: React.UIEvent, - renderLazy?: () => Promise<Menu["ContextMenu"]>, - options?: { enableSpellCheck?: boolean; } - ): void; -}; - -export const MaskedLinkStore = mapMangledModuleLazy('"MaskedLinkStore"', { - openUntrustedLink: filters.byCode(".apply(this,arguments)") -}); diff --git a/src/webpack/common/components.ts b/src/webpack/common/components.ts new file mode 100644 index 0000000..be585c3 --- /dev/null +++ b/src/webpack/common/components.ts @@ -0,0 +1,53 @@ +/* + * Vencord, a modification for Discord's desktop app + * Copyright (c) 2023 Vendicated and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +// eslint-disable-next-line path-alias/no-relative +import { filters, findByPropsLazy } from "../webpack"; +import { waitForComponent } from "./internal"; +import * as t from "./types/components"; + +export const Forms = { + FormTitle: waitForComponent<t.FormTitle>("FormTitle", filters.byCode("errorSeparator")), + FormSection: waitForComponent<t.FormSection>("FormSection", filters.byCode("titleClassName", "sectionTitle")), + FormDivider: waitForComponent<t.FormDivider>("FormDivider", m => { + if (typeof m !== "function") return false; + const s = m.toString(); + return s.length < 200 && s.includes(".divider"); + }), + FormText: waitForComponent<t.FormText>("FormText", m => m.Types?.INPUT_PLACEHOLDER), +}; + +export const Card = waitForComponent<t.Card>("Card", m => m.Types?.PRIMARY === "cardPrimary"); +export const Button = waitForComponent<t.Button>("Button", ["Hovers", "Looks", "Sizes"]); +export const Switch = waitForComponent<t.Switch>("Switch", filters.byCode("tooltipNote", "ringTarget")); +export const Tooltip = waitForComponent<t.Tooltip>("Tooltip", ["Positions", "Colors"]); +export const Timestamp = waitForComponent<t.Timestamp>("Timestamp", filters.byCode(".Messages.MESSAGE_EDITED_TIMESTAMP_A11Y_LABEL.format")); +export const TextInput = waitForComponent<t.TextInput>("TextInput", ["defaultProps", "Sizes", "contextType"]); +export const TextArea = waitForComponent<t.TextArea>("TextArea", filters.byCode("handleSetRef", "textArea")); +export const Text = waitForComponent<t.Text>("Text", m => { + if (typeof m !== "function") return false; + const s = m.toString(); + return (s.length < 1500 && s.includes("data-text-variant") && s.includes("always-white")); +}); +export const Select = waitForComponent<t.Select>("Select", filters.byCode("optionClassName", "popoutPosition", "autoFocus", "maxVisibleItems")); +export const Slider = waitForComponent<t.Slider>("Slider", filters.byCode("closestMarkerIndex", "stickToMarkers")); +export const Flex = waitForComponent<t.Flex>("Flex", ["Justify", "Align", "Wrap"]); + +export const ButtonWrapperClasses = findByPropsLazy("buttonWrapper", "buttonContent") as Record<string, string>; +export const Margins: t.Margins = findByPropsLazy("marginTop20"); +export const ButtonLooks: t.ButtonLooks = findByPropsLazy("BLANK", "FILLED", "INVERTED"); diff --git a/src/webpack/common/index.ts b/src/webpack/common/index.ts new file mode 100644 index 0000000..dff7826 --- /dev/null +++ b/src/webpack/common/index.ts @@ -0,0 +1,27 @@ +/* + * Vencord, a modification for Discord's desktop app + * Copyright (c) 2023 Vendicated and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FIT |
