From 08f1b6a3c98c6194550c4ef5a175929b6b8ddf72 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Wed, 12 Jun 2024 17:06:20 -0300 Subject: [PATCH] LazyComponents: Allow accessing inner; Improve typings --- src/debug/runReporter.ts | 5 +++-- src/plugins/moreUserTags/index.tsx | 3 ++- src/utils/lazyReact.tsx | 12 ++++++++--- src/webpack/common/types/menu.d.ts | 2 +- src/webpack/webpack.tsx | 34 ++++++++++++++---------------- 5 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/debug/runReporter.ts b/src/debug/runReporter.ts index 16287c878..697a5c87c 100644 --- a/src/debug/runReporter.ts +++ b/src/debug/runReporter.ts @@ -4,6 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +import { SYM_LAZY_COMPONENT_INNER } from "@utils/lazyReact"; import { Logger } from "@utils/Logger"; import { SYM_PROXY_INNER_GET, SYM_PROXY_INNER_VALUE } from "@utils/proxyInner"; import * as Webpack from "@webpack"; @@ -64,8 +65,8 @@ async function runReporter() { result = findResult[SYM_PROXY_INNER_VALUE]; } - if (findResult.$$vencordInner != null) { - result = findResult.$$vencordInner(); + if (findResult[SYM_LAZY_COMPONENT_INNER] != null) { + result = findResult[SYM_LAZY_COMPONENT_INNER](); } } diff --git a/src/plugins/moreUserTags/index.tsx b/src/plugins/moreUserTags/index.tsx index d60414ff5..2710e840c 100644 --- a/src/plugins/moreUserTags/index.tsx +++ b/src/plugins/moreUserTags/index.tsx @@ -19,6 +19,7 @@ import { definePluginSettings } from "@api/Settings"; import { Flex } from "@components/Flex"; import { Devs } from "@utils/constants"; +import { LazyComponentType } from "@utils/lazyReact"; import { Margins } from "@utils/margins"; import definePlugin, { OptionType } from "@utils/types"; import { findByProps, findComponentByCode } from "@webpack"; @@ -56,7 +57,7 @@ const PermissionUtil = findByProps("computePermissions", "canEveryoneRole") as { computePermissions({ ...args }): bigint; }; -const Tag = findComponentByCode(".DISCORD_SYSTEM_MESSAGE_BOT_TAG_TOOLTIP_OFFICIAL,") as React.ComponentType<{ type?: number, className?: string, useRemSizes?: boolean; }> & { Types: Record; }; +const Tag = findComponentByCode(".DISCORD_SYSTEM_MESSAGE_BOT_TAG_TOOLTIP_OFFICIAL,") as LazyComponentType<{ type?: number, className?: string, useRemSizes?: boolean; }> & { Types: Record; }; const isWebhook = (message: Message, user: User) => !!message?.webhookId && user.isNonUserBot(); diff --git a/src/utils/lazyReact.tsx b/src/utils/lazyReact.tsx index 3a8a9ebc0..20988e1ec 100644 --- a/src/utils/lazyReact.tsx +++ b/src/utils/lazyReact.tsx @@ -6,6 +6,10 @@ import { makeLazy } from "./lazy"; +export type LazyComponentType = React.ComponentType & Record; + +export const SYM_LAZY_COMPONENT_INNER = Symbol.for("vencord.lazyComponent.inner"); + /** * A lazy component. The factory method is called on first render. * @@ -13,10 +17,10 @@ import { makeLazy } from "./lazy"; * @param attempts How many times to try to get the component before giving up * @returns Result of factory function */ -export function LazyComponent(factory: () => React.ComponentType, attempts = 5) { +export function LazyComponent(factory: () => LazyComponentType, attempts = 5) { const get = makeLazy(factory, attempts, { isIndirect: true }); - let InnerComponent = null as React.ComponentType | null; + let InnerComponent = null as LazyComponentType | null; let lazyFailedLogged = false; const LazyComponent = (props: T) => { @@ -39,5 +43,7 @@ export function LazyComponent(factory: () => React.Compo return InnerComponent && ; }; - return LazyComponent as React.ComponentType; + LazyComponent[SYM_LAZY_COMPONENT_INNER] = () => InnerComponent; + + return LazyComponent as LazyComponentType; } diff --git a/src/webpack/common/types/menu.d.ts b/src/webpack/common/types/menu.d.ts index 0b8ab5c66..d5f92d630 100644 --- a/src/webpack/common/types/menu.d.ts +++ b/src/webpack/common/types/menu.d.ts @@ -18,7 +18,7 @@ import type { ComponentType, CSSProperties, MouseEvent, PropsWithChildren, ReactNode, UIEvent } from "react"; -type RC = ComponentType>>; +type RC = ComponentType>>; export interface Menu { Menu: RC<{ diff --git a/src/webpack/webpack.tsx b/src/webpack/webpack.tsx index ad74279be..d38b71336 100644 --- a/src/webpack/webpack.tsx +++ b/src/webpack/webpack.tsx @@ -5,7 +5,7 @@ */ import { makeLazy, proxyLazy } from "@utils/lazy"; -import { LazyComponent } from "@utils/lazyReact"; +import { LazyComponent, LazyComponentType, SYM_LAZY_COMPONENT_INNER } from "@utils/lazyReact"; import { Logger } from "@utils/Logger"; import { canonicalizeMatch } from "@utils/patches"; import { ProxyInner, proxyInner, SYM_PROXY_INNER_VALUE } from "@utils/proxyInner"; @@ -196,13 +196,13 @@ export function find(filter: FilterFn, callback: (mod: any) => an * @param parse A function that takes the found component as its first argument and returns a component. Useful if you want to wrap the found component in something. Defaults to the original component * @returns The component if found, or a noop component */ -export function findComponent(filter: FilterFn, parse: (component: any) => React.ComponentType = m => m, { isIndirect = false }: { isIndirect?: boolean; } = {}) { +export function findComponent(filter: FilterFn, parse: (component: any) => LazyComponentType = m => m, { isIndirect = false }: { isIndirect?: boolean; } = {}) { if (typeof filter !== "function") throw new Error("Invalid filter. Expected a function got " + typeof filter); if (typeof parse !== "function") throw new Error("Invalid component parse. Expected a function got " + typeof parse); - let InnerComponent = null as React.ComponentType | null; + let InnerComponent = null as LazyComponentType | null; let findFailedLogged = false; const WrapperComponent = (props: T) => { @@ -214,23 +214,21 @@ export function findComponent(filter: FilterFn, parse: ( return InnerComponent && ; }; + WrapperComponent[SYM_LAZY_COMPONENT_INNER] = () => InnerComponent; + waitFor(filter, (v: any) => { const parsedComponent = parse(v); InnerComponent = parsedComponent; Object.assign(WrapperComponent, parsedComponent); }, { isIndirect: true }); - if (IS_REPORTER) { - WrapperComponent.$$vencordInner = () => InnerComponent; - - if (!isIndirect) { - webpackSearchHistory.push(["findComponent", [WrapperComponent, filter]]); - } + if (IS_REPORTER && !isIndirect) { + webpackSearchHistory.push(["findComponent", [WrapperComponent, filter]]); } if (InnerComponent !== null) return InnerComponent; - return WrapperComponent as React.ComponentType; + return WrapperComponent as LazyComponentType; } /** @@ -243,13 +241,13 @@ export function findComponent(filter: FilterFn, parse: ( * @param parse A function that takes the found component as its first argument and returns a component. Useful if you want to wrap the found component in something. Defaults to the original component * @returns The component if found, or a noop component */ -export function findExportedComponent(...props: string[] | [...string[], (component: any) => React.ComponentType]) { - const parse = (typeof props.at(-1) === "function" ? props.pop() : m => m) as (component: any) => React.ComponentType; +export function findExportedComponent(...props: string[] | [...string[], (component: any) => LazyComponentType]) { + const parse = (typeof props.at(-1) === "function" ? props.pop() : m => m) as (component: any) => LazyComponentType; const newProps = props as string[]; const filter = filters.byProps(...newProps); - let InnerComponent = null as React.ComponentType | null; + let InnerComponent = null as LazyComponentType | null; let findFailedLogged = false; const WrapperComponent = (props: T) => { @@ -261,6 +259,7 @@ export function findExportedComponent(...props: string[] return InnerComponent && ; }; + WrapperComponent[SYM_LAZY_COMPONENT_INNER] = () => InnerComponent; waitFor(filter, (v: any) => { const parsedComponent = parse(v[newProps[0]]); @@ -269,13 +268,12 @@ export function findExportedComponent(...props: string[] }, { isIndirect: true }); if (IS_REPORTER) { - WrapperComponent.$$vencordInner = () => InnerComponent; webpackSearchHistory.push(["findExportedComponent", [WrapperComponent, ...newProps]]); } if (InnerComponent !== null) return InnerComponent; - return WrapperComponent as React.ComponentType; + return WrapperComponent as LazyComponentType; } /** @@ -288,8 +286,8 @@ export function findExportedComponent(...props: string[] * @param parse A function that takes the found component as its first argument and returns a component. Useful if you want to wrap the found component in something. Defaults to the original component * @returns The component if found, or a noop component */ -export function findComponentByCode(...code: string[] | [...string[], (component: any) => React.ComponentType]) { - const parse = (typeof code.at(-1) === "function" ? code.pop() : m => m) as (component: any) => React.ComponentType; +export function findComponentByCode(...code: string[] | [...string[], (component: any) => LazyComponentType]) { + const parse = (typeof code.at(-1) === "function" ? code.pop() : m => m) as (component: any) => LazyComponentType; const newCode = code as string[]; const ComponentResult = findComponent(filters.componentByCode(...newCode), parse, { isIndirect: true }); @@ -518,7 +516,7 @@ export function webpackDependantLazy(factory: () => T, attempts?: * @param attempts How many times to try to get the component before giving up * @returns Result of factory function */ -export function webpackDependantLazyComponent(factory: () => any, attempts?: number) { +export function webpackDependantLazyComponent(factory: () => any, attempts?: number) { if (IS_REPORTER) webpackSearchHistory.push(["webpackDependantLazyComponent", [factory]]); return LazyComponent(factory, attempts);