Compare commits

..

No commits in common. "07a9279682594b43953a12bbfe2cfdb6f1eb69f6" and "7eeaa3247396c0e27a190e5f6a78a6bfbea3366e" have entirely different histories.

36 changed files with 142 additions and 149 deletions

View file

@ -17,6 +17,7 @@
*/
import ErrorBoundary from "@components/ErrorBoundary";
import { ComponentType, HTMLProps } from "react";
import Plugins from "~plugins";
@ -29,7 +30,7 @@ export interface ProfileBadge {
/** The tooltip to show on hover. Required for image badges */
description?: string;
/** Custom component for the badge (tooltip not included) */
component?: React.ComponentType<ProfileBadge & BadgeUserArgs>;
component?: ComponentType<ProfileBadge & BadgeUserArgs>;
/** The custom image to use */
image?: string;
link?: string;
@ -38,7 +39,7 @@ export interface ProfileBadge {
/** Should the user display this badge? */
shouldShow?(userInfo: BadgeUserArgs): boolean;
/** Optional props (e.g. style) for the badge, ignored for component badges */
props?: React.ComponentPropsWithoutRef<"img">;
props?: HTMLProps<HTMLImageElement>;
/** Insert at start or end? */
position?: BadgePosition;
/** The badge name to display, Discord uses this. Required for component badges */

View file

@ -19,17 +19,18 @@
import ErrorBoundary from "@components/ErrorBoundary";
import { Logger } from "@utils/Logger";
import { Channel, Message } from "discord-types/general";
import type { ComponentType, MouseEventHandler } from "react";
const logger = new Logger("MessagePopover");
export interface ButtonItem {
key?: string,
label: string,
icon: React.ComponentType<AnyRecord>,
icon: ComponentType<any>,
message: Message,
channel: Channel,
onClick?: React.MouseEventHandler<HTMLButtonElement>,
onContextMenu?: React.MouseEventHandler<HTMLButtonElement>;
onClick?: MouseEventHandler<HTMLButtonElement>,
onContextMenu?: MouseEventHandler<HTMLButtonElement>;
}
export type getButtonItem = (message: Message) => ButtonItem | null;

View file

@ -18,7 +18,7 @@
import { Logger } from "@utils/Logger";
import { Margins } from "@utils/margins";
import { LazyComponent, LazyComponentType } from "@utils/react";
import { LazyComponent } from "@utils/react";
import { React } from "@webpack/common";
import { ErrorCard } from "./ErrorCard";
@ -104,8 +104,8 @@ const ErrorBoundary = LazyComponent(() => {
}
};
}) as
LazyComponentType<React.PropsWithChildren<Props>> & {
wrap<T extends AnyRecord>(Component: React.ComponentType<T>, errorBoundaryProps?: Omit<Props<T>, "wrappedProps">): React.FunctionComponent<T>;
React.ComponentType<React.PropsWithChildren<Props>> & {
wrap<T extends object = any>(Component: React.ComponentType<T>, errorBoundaryProps?: Omit<Props<T>, "wrappedProps">): React.FunctionComponent<T>;
};
ErrorBoundary.wrap = (Component, errorBoundaryProps) => props => (

View file

@ -292,10 +292,10 @@ export default function PluginSettings() {
if (!pluginFilter(p)) continue;
const isRequired = p.required || p.isDependency || depMap[p.name]?.some(d => settings.plugins[d].enabled);
const isRequired = p.required || depMap[p.name]?.some(d => settings.plugins[d].enabled);
if (isRequired) {
const tooltipText = p.required || !depMap[p.name]
const tooltipText = p.required
? "This plugin is required for Vencord to function."
: makeDependencyList(depMap[p.name]?.filter(d => settings.plugins[d].enabled));

View file

@ -8,12 +8,13 @@ import "./quickActions.css";
import { classNameFactory } from "@api/Styles";
import { Card } from "@webpack/common";
import type { ComponentType, PropsWithChildren, ReactNode } from "react";
const cl = classNameFactory("vc-settings-quickActions-");
export interface QuickActionProps {
Icon: React.ComponentType<{ className?: string; }>;
text: React.ReactNode;
Icon: ComponentType<{ className?: string; }>;
text: ReactNode;
action?: () => void;
disabled?: boolean;
}
@ -29,7 +30,7 @@ export function QuickAction(props: QuickActionProps) {
);
}
export function QuickActionCard(props: React.PropsWithChildren) {
export function QuickActionCard(props: PropsWithChildren) {
return (
<Card className={cl("card")}>
{props.children}

View file

@ -24,8 +24,9 @@ import { handleComponentFailed } from "@components/handleComponentFailed";
import { Margins } from "@utils/margins";
import { onlyOnce } from "@utils/onlyOnce";
import { Forms, Text } from "@webpack/common";
import type { ComponentType, PropsWithChildren } from "react";
export function SettingsTab({ title, children }: React.PropsWithChildren<{ title: string; }>) {
export function SettingsTab({ title, children }: PropsWithChildren<{ title: string; }>) {
return (
<Forms.FormSection>
<Text
@ -43,7 +44,7 @@ export function SettingsTab({ title, children }: React.PropsWithChildren<{ title
export const handleSettingsTabError = onlyOnce(handleComponentFailed);
export function wrapTab<P extends AnyRecord>(component: React.ComponentType<P>, tab: string) {
export function wrapTab(component: ComponentType<any>, tab: string) {
return ErrorBoundary.wrap(component, {
message: `Failed to render the ${tab} tab. If this issue persists, try using the installer to reinstall!`,
onError: handleSettingsTabError,

6
src/globals.d.ts vendored
View file

@ -19,10 +19,6 @@
import { LoDashStatic } from "lodash";
declare global {
type AnyRecord = Record<PropertyKey, any>;
type AnyComponentType<P extends AnyRecord = AnyRecord> = React.ComponentType<P & AnyRecord> & AnyRecord;
type AnyComponentTypeWithChildren<P extends AnyRecord = AnyRecord> = AnyComponentType<React.PropsWithChildren<P>>;
/**
* This exists only at build time, so references to it in patches should insert it
* via String interpolation OR use different replacement code based on this
@ -68,7 +64,7 @@ declare global {
export var Vesktop: any;
export var VesktopNative: any;
interface Window extends AnyRecord {
interface Window extends Record<PropertyKey, any> {
_: LoDashStatic;
}
}

View file

@ -142,7 +142,7 @@ export default definePlugin({
required: true,
description: "Helps us provide support to you",
authors: [Devs.Ven],
dependencies: ["UserSettingsAPI", "MessageAccessoriesAPI"],
dependencies: ["CommandsAPI", "UserSettingsAPI", "MessageAccessoriesAPI"],
settings,

View file

@ -23,7 +23,7 @@ const UserProfile = findComponentByCode("UserProfilePopoutWrapper: user cannot b
const styles = findByProps("accountProfilePopoutWrapper");
let openAlternatePopout = false;
let accountPanelRef: React.MutableRefObject<AnyRecord | null> = { current: null };
let accountPanelRef: React.MutableRefObject<Record<PropertyKey, any> | null> = { current: null };
const AccountPanelContextMenu = ErrorBoundary.wrap(() => {
const { prioritizeServerProfile } = settings.use(["prioritizeServerProfile"]);

View file

@ -28,6 +28,7 @@ import * as Webpack from "@webpack";
import { cacheFindAll, cacheFindModuleId, extract, filters, searchFactories } from "@webpack";
import * as Common from "@webpack/common";
import { loadLazyChunks } from "debug/loadLazyChunks";
import type { ComponentType } from "react";
const DESKTOP_ONLY = (f: string) => () => {
throw new Error(`'${f}' is Discord Desktop only.`);
@ -128,7 +129,7 @@ function makeShortcuts() {
canonicalizeReplacement,
preEnable: (plugin: string) => (Vencord.Settings.plugins[plugin] ??= { enabled: true }).enabled = true,
fakeRender: (component: React.ComponentType<AnyRecord>, props: any) => {
fakeRender: (component: ComponentType, props: any) => {
const prevWin = fakeRenderWin?.deref();
const win = prevWin?.closed === false
? prevWin

View file

@ -7,10 +7,11 @@
import { NoopComponent } from "@utils/react";
import { findComponentByCode } from "@webpack";
import { React } from "@webpack/common";
import type { ComponentType, HTMLProps, PropsWithChildren } from "react";
import { AvatarDecoration } from "../..";
type DecorationGridItemComponent = AnyComponentTypeWithChildren<React.ComponentPropsWithoutRef<"div"> & {
type DecorationGridItemComponent = ComponentType<PropsWithChildren<HTMLProps<HTMLDivElement>> & {
onSelect: () => void,
isSelected: boolean,
}>;
@ -18,9 +19,9 @@ type DecorationGridItemComponent = AnyComponentTypeWithChildren<React.ComponentP
export let DecorationGridItem: DecorationGridItemComponent = NoopComponent;
export const setDecorationGridItem = v => DecorationGridItem = v;
export const AvatarDecorationModalPreview = findComponentByCode(".shopPreviewBanner", component => React.memo(component));
export const AvatarDecorationModalPreview = findComponentByCode<any>(".shopPreviewBanner", component => React.memo(component));
type DecorationGridDecorationComponent = AnyComponentType<React.ComponentPropsWithoutRef<"div"> & {
type DecorationGridDecorationComponent = React.ComponentType<HTMLProps<HTMLDivElement> & {
avatarDecoration: AvatarDecoration;
onSelect: () => void,
isSelected: boolean,

View file

@ -27,6 +27,7 @@ export default definePlugin({
name: "FriendInvites",
description: "Create and manage friend invite links via slash commands (/create friend invite, /view friend invites, /revoke friend invites).",
authors: [Devs.afn, Devs.Dziurwa],
dependencies: ["CommandsAPI"],
commands: [
{
name: "create friend invite",

View file

@ -26,7 +26,7 @@ import definePlugin, { OptionType } from "@utils/types";
import { Menu, ReactDOM } from "@webpack/common";
import type { Root } from "react-dom/client";
import { Magnifier } from "./components/Magnifier";
import { Magnifier, MagnifierProps } from "./components/Magnifier";
import { ELEMENT_ID } from "./constants";
import styles from "./styles.css?managed";
@ -201,7 +201,7 @@ export default definePlugin({
},
// to stop from rendering twice /shrug
currentMagnifierElement: null as React.ReactNode,
currentMagnifierElement: null as React.FunctionComponentElement<MagnifierProps & JSX.IntrinsicAttributes> | null,
element: null as HTMLDivElement | null,
Magnifier,

View file

@ -107,11 +107,6 @@ for (const p of pluginsValues) if (isPluginEnabled(p.name)) {
settings[d].enabled = true;
dep.isDependency = true;
});
if (p.commands?.length) {
Plugins.CommandsAPI.isDependency = true;
settings.CommandsAPI.enabled = true;
}
}
for (const p of pluginsValues) {

View file

@ -84,6 +84,8 @@ export default definePlugin({
authors: [Devs.Luna],
settings,
dependencies: ["CommandsAPI"],
async start() {
for (const tag of await getTags()) createTagCommand(tag);
},

View file

@ -33,6 +33,7 @@ export default definePlugin({
name: "MoreCommands",
description: "echo, lenny, mock",
authors: [Devs.Arjix, Devs.echo, Devs.Samu],
dependencies: ["CommandsAPI"],
commands: [
{
name: "echo",

View file

@ -24,6 +24,7 @@ export default definePlugin({
name: "MoreKaomoji",
description: "Adds more Kaomoji to discord. ヽ(´▽`)/",
authors: [Devs.JacobTm],
dependencies: ["CommandsAPI"],
commands: [
{ name: "dissatisfaction", description: " " },
{ name: "smug", description: "ಠ_ಠ" },

View file

@ -88,6 +88,7 @@ export default definePlugin({
name: "petpet",
description: "Adds a /petpet slash command to create headpet gifs from any image",
authors: [Devs.Ven],
dependencies: ["CommandsAPI"],
commands: [
{
inputType: ApplicationCommandInputType.BUILT_IN,

View file

@ -13,6 +13,7 @@ import definePlugin, { OptionType } from "@utils/types";
import { findComponentByCode } from "@webpack";
import { ChannelStore, GuildMemberStore, i18n, Text, Tooltip } from "@webpack/common";
import { Message } from "discord-types/general";
import { FunctionComponent, ReactNode } from "react";
const CountDown = findComponentByCode(".MAX_AGE_NEVER");
@ -74,7 +75,7 @@ export default definePlugin({
}
],
TooltipWrapper: ErrorBoundary.wrap(({ message, children, text }: { message: Message; children: React.FunctionComponent<AnyRecord>; text: React.ReactNode; }) => {
TooltipWrapper: ErrorBoundary.wrap(({ message, children, text }: { message: Message; children: FunctionComponent<any>; text: ReactNode; }) => {
if (settings.store.displayStyle === DisplayStyle.Tooltip) return <Tooltip
children={children}
text={renderTimeout(message, false)}

View file

@ -88,7 +88,7 @@ export default definePlugin({
name: "SilentTyping",
authors: [Devs.Ven, Devs.Rini, Devs.ImBanana],
description: "Hide that you are typing",
dependencies: ["ChatInputButtonAPI"],
dependencies: ["CommandsAPI", "ChatInputButtonAPI"],
settings,
contextMenus: {
"textarea-context": ChatBarContextCheckbox

View file

@ -76,6 +76,7 @@ export default definePlugin({
name: "SpotifyShareCommands",
description: "Share your current Spotify track, album or artist via slash command (/track, /album, /artist)",
authors: [Devs.katlyn],
dependencies: ["CommandsAPI"],
commands: [
{
name: "track",

View file

@ -17,7 +17,7 @@ const selectVoiceChannel = findProp("selectVoiceChannel", "selectChannel");
const VoiceStateStore = findStore("VoiceStateStore");
const UserSummaryItem = findComponentByCode("defaultRenderUser", "showDefaultAvatarsForNullUsers");
interface IconProps extends React.ComponentPropsWithoutRef<"div"> {
interface IconProps extends React.HTMLAttributes<HTMLDivElement> {
size?: number;
}

View file

@ -23,6 +23,7 @@ import { sleep } from "@utils/misc";
import { Queue } from "@utils/Queue";
import definePlugin from "@utils/types";
import { Constants, FluxDispatcher, RestAPI, UserProfileStore, UserStore, useState } from "@webpack/common";
import { type ComponentType, type ReactNode } from "react";
// LYING to the type checker here
const UserFlags = Constants.UserFlags as Record<string, number>;
@ -59,14 +60,14 @@ interface MentionProps {
channelId?: string;
content: any;
};
parse: (content: any, props: MentionProps["props"]) => React.ReactNode;
parse: (content: any, props: MentionProps["props"]) => ReactNode;
props: {
key: string;
formatInline: boolean;
noStyleAndInteraction: boolean;
};
RoleMention: AnyComponentType;
UserMention: AnyComponentType;
RoleMention: ComponentType<any>;
UserMention: ComponentType<any>;
}
async function getUser(id: string) {

View file

@ -29,6 +29,7 @@ import definePlugin from "@utils/types";
import { chooseFile } from "@utils/web";
import { find, findByProps, findStore } from "@webpack";
import { Button, Card, Constants, FluxDispatcher, Forms, lodash, Menu, MessageActions, PermissionsBits, PermissionStore, RestAPI, SelectedChannelStore, showToast, SnowflakeUtils, Toasts, useEffect, useState } from "@webpack/common";
import { ComponentType } from "react";
import { VoiceRecorderDesktop } from "./DesktopRecorder";
import { settings } from "./settings";
@ -40,7 +41,7 @@ const CloudUpload = find(m => m.prototype?.trackUploadFinished);
const PendingReplyStore = findStore("PendingReplyStore");
const OptionClasses = findByProps("optionName", "optionIcon", "optionLabel");
export type VoiceRecorder = AnyComponentType<{
export type VoiceRecorder = ComponentType<{
setAudioBlob(blob: Blob): void;
onRecordingChange?(recording: boolean): void;
}>;

View file

@ -17,7 +17,7 @@ export function makeLazy<T>(factory: () => T, attempts = 5, { isIndirect = false
let tries = 0;
let cache: T;
const getter: LazyFunction<T> = function () {
const getter = () => {
if (!cache && attempts > tries) {
tries++;
cache = factory();
@ -30,6 +30,7 @@ export function makeLazy<T>(factory: () => T, attempts = 5, { isIndirect = false
};
getter.$$vencordLazyFailed = () => tries === attempts;
return getter;
}
@ -68,11 +69,17 @@ const handler: ProxyHandler<any> = {
*
* @param factory Factory returning the result
* @param attempts How many times to try to evaluate the factory before giving up
* @param err The error message to throw when the factory fails
* @param primitiveErr The error message to throw when factory result is a primitive
* @param errMsg The error message to throw when the factory fails
* @param primitiveErrMsg The error message to throw when factory result is a primitive
* @returns Result of factory function
*/
export function proxyLazy<T = any>(factory: () => T, attempts = 5, err: string | (() => string) = `proxyLazy factory failed:\n${factory}`, primitiveErr = "proxyLazy called on a primitive value.", isChild = false): T {
export function proxyLazy<T = any>(
factory: () => T,
attempts = 5,
errMsg: string | (() => string) = `proxyLazy factory failed:\n${factory}`,
primitiveErrMsg = "proxyLazy called on a primitive value.",
isChild = false
): T {
const get = makeLazy(factory, attempts, { isIndirect: true });
let isSameTick = true;
@ -86,7 +93,7 @@ export function proxyLazy<T = any>(factory: () => T, attempts = 5, err: string |
}
if (!proxyDummy[SYM_LAZY_CACHED]) {
throw new Error(typeof err === "string" ? err : err());
throw new Error(typeof errMsg === "string" ? errMsg : errMsg());
} else {
if (typeof proxyDummy[SYM_LAZY_CACHED] === "function") {
proxy.toString = proxyDummy[SYM_LAZY_CACHED].toString.bind(proxyDummy[SYM_LAZY_CACHED]);
@ -122,8 +129,8 @@ export function proxyLazy<T = any>(factory: () => T, attempts = 5, err: string |
return Reflect.get(lazyTarget, p, lazyTarget);
},
attempts,
err,
primitiveErr,
errMsg,
primitiveErrMsg,
true
);
}
@ -133,7 +140,7 @@ export function proxyLazy<T = any>(factory: () => T, attempts = 5, err: string |
return Reflect.get(lazyTarget, p, lazyTarget);
}
throw new Error(primitiveErr);
throw new Error(primitiveErrMsg);
}
});

View file

@ -6,12 +6,9 @@
import { makeLazy } from "./lazy";
export const SYM_LAZY_COMPONENT_INNER = Symbol.for("vencord.lazyComponent.inner");
export type LazyComponentType<T extends object = any> = React.ComponentType<T> & Record<PropertyKey, any>;
export type LazyComponentType<P extends AnyRecord = AnyRecord> = React.FunctionComponent<P> & AnyRecord & {
[SYM_LAZY_COMPONENT_INNER]: () => AnyComponentType<P> | null;
};
export type AnyLazyComponentType<P extends AnyRecord = AnyRecord> = LazyComponentType<P & AnyRecord>;
export const SYM_LAZY_COMPONENT_INNER = Symbol.for("vencord.lazyComponent.inner");
/**
* A lazy component. The factory method is called on first render.
@ -20,16 +17,15 @@ export type AnyLazyComponentType<P extends AnyRecord = AnyRecord> = LazyComponen
* @param attempts How many times to try to get the component before giving up
* @returns Result of factory function
*/
export function LazyComponent<P extends AnyRecord>(factory: () => React.ComponentType<P>, attempts = 5, err: string | (() => string) = `LazyComponent factory failed:\n${factory}`): LazyComponentType<P> {
export function LazyComponent<T extends object = any>(factory: () => LazyComponentType<T>, attempts = 5, errMsg: string | (() => string) = `LazyComponent factory failed:\n${factory}`) {
const get = makeLazy(factory, attempts, { isIndirect: true });
let InnerComponent = null as AnyComponentType<P> | null;
let InnerComponent = null as LazyComponentType<T> | null;
let lazyFailedLogged = false;
const LazyComponent: LazyComponentType<P> = function (props) {
const LazyComponent = (props: T) => {
if (!get.$$vencordLazyFailed()) {
const ResultComponent = get();
if (ResultComponent != null) {
InnerComponent = ResultComponent;
Object.assign(LazyComponent, ResultComponent);
@ -41,7 +37,7 @@ export function LazyComponent<P extends AnyRecord>(factory: () => React.Componen
lazyFailedLogged = true;
}
console.error(typeof err === "string" ? err : err());
console.error(typeof errMsg === "string" ? errMsg : errMsg());
}
return InnerComponent && <InnerComponent {...props} />;
@ -49,5 +45,5 @@ export function LazyComponent<P extends AnyRecord>(factory: () => React.Componen
LazyComponent[SYM_LAZY_COMPONENT_INNER] = () => InnerComponent;
return LazyComponent;
return LazyComponent as LazyComponentType<T>;
}

View file

@ -17,6 +17,7 @@
*/
import { findByProps, findComponentByCode } from "@webpack";
import type { ComponentType, PropsWithChildren, ReactNode, Ref } from "react";
import { NoopComponent } from "./react";
@ -46,10 +47,10 @@ export interface ModalOptions {
onCloseCallback?: (() => void);
}
type RenderFunction = (props: ModalProps) => React.ReactNode;
type RenderFunction = (props: ModalProps) => ReactNode;
type Modals = {
ModalRoot: AnyComponentTypeWithChildren<{
ModalRoot: ComponentType<PropsWithChildren<{
transitionState: ModalTransitionState;
size?: ModalSize;
role?: "alertdialog" | "dialog";
@ -58,8 +59,8 @@ type Modals = {
"aria-label"?: string;
"aria-labelledby"?: string;
onAnimationEnd?(): string;
}>;
ModalHeader: AnyComponentTypeWithChildren<{
}>>;
ModalHeader: ComponentType<PropsWithChildren<{
/** Flex.Justify.START */
justify?: string;
/** Flex.Direction.HORIZONTAL */
@ -71,13 +72,14 @@ type Modals = {
separator?: boolean;
className?: string;
}>;
}>>;
/** This also accepts Scroller props but good luck with that */
ModalContent: AnyComponentTypeWithChildren<{
ModalContent: ComponentType<PropsWithChildren<{
className?: string;
scrollerRef?: React.Ref<HTMLElement>;
}>;
ModalFooter: AnyComponentTypeWithChildren<{
scrollerRef?: Ref<HTMLElement>;
[prop: string]: any;
}>>;
ModalFooter: ComponentType<PropsWithChildren<{
/** Flex.Justify.START */
justify?: string;
/** Flex.Direction.HORIZONTAL_REVERSE */
@ -89,8 +91,8 @@ type Modals = {
separator?: boolean;
className?: string;
}>;
ModalCloseButton: AnyComponentType<{
}>>;
ModalCloseButton: ComponentType<{
focusProps?: any;
onClick(): void;
withCircleBackground?: boolean;
@ -121,8 +123,8 @@ export type ImageModalProps = {
height?: number;
animated?: boolean;
responsive?: boolean;
renderLinkComponent(props: any): React.ReactNode;
renderForwardComponent(props: any): React.ReactNode;
renderLinkComponent(props: any): ReactNode;
renderForwardComponent(props: any): ReactNode;
maxWidth?: number;
maxHeight?: number;
shouldAnimate?: boolean;

View file

@ -42,18 +42,22 @@ const handler: ProxyHandler<any> = {
* IMPORTANT:
* Destructuring at top level is not supported for proxyInner.
*
* @param err The error message to throw when the inner value is not set
* @param primitiveErr The error message to throw when the inner value is a primitive
* @param errMsg The error message to throw when the inner value is not set
* @param primitiveErrMsg The error message to throw when the inner value is a primitive
* @returns A proxy which will act like the inner value when accessed
*/
export function proxyInner<T = any>(err: string | (() => string) = "Proxy inner value is undefined, setInnerValue was never called.", primitiveErr = "proxyInner called on a primitive value. This can happen if you try to destructure a primitive at the same tick as the proxy was created.", isChild = false): [proxy: T, setInnerValue: (innerValue: T) => void] {
export function proxyInner<T = any>(
errMsg: string | (() => string) = "Proxy inner value is undefined, setInnerValue was never called.",
primitiveErrMsg = "proxyInner called on a primitive value. This can happen if you try to destructure a primitive at the same tick as the proxy was created.",
isChild = false
): [proxy: T, setInnerValue: (innerValue: T) => void] {
let isSameTick = true;
if (!isChild) setTimeout(() => isSameTick = false, 0);
const proxyDummy = Object.assign(function () { }, {
[SYM_PROXY_INNER_GET]: function () {
if (proxyDummy[SYM_PROXY_INNER_VALUE] == null) {
throw new Error(typeof err === "string" ? err : err());
throw new Error(typeof errMsg === "string" ? errMsg : errMsg());
}
return proxyDummy[SYM_PROXY_INNER_VALUE];
@ -81,7 +85,7 @@ export function proxyInner<T = any>(err: string | (() => string) = "Proxy inner
"\nConsider not destructuring, using findProp or if you really need to destructure, using mapMangledModule instead."
);
const [recursiveProxy, recursiveSetInnerValue] = proxyInner(err, primitiveErr, true);
const [recursiveProxy, recursiveSetInnerValue] = proxyInner(errMsg, primitiveErrMsg, true);
recursiveSetInnerValues.push((innerValue: T) => {
// Set the inner value of the destructured value as the prop value p of the parent
@ -96,7 +100,7 @@ export function proxyInner<T = any>(err: string | (() => string) = "Proxy inner
return Reflect.get(innerTarget, p, innerTarget);
}
throw new Error(primitiveErr);
throw new Error(primitiveErrMsg);
}
});

View file

@ -72,13 +72,13 @@ export interface PluginDef {
stop?(): void;
patches?: Omit<Patch, "plugin">[];
/**
* List of commands that your plugin wants to register
* List of commands. If you specify these, you must add CommandsAPI to dependencies
*/
commands?: Command[];
/**
* A list of other plugins that your plugin depends on.
* These will automatically be enabled and loaded before your plugin
* Generally these will be API plugins
* Common examples are CommandsAPI, MessageEventsAPI...
*/
dependencies?: string[],
/**

View file

@ -5,7 +5,7 @@
*/
import { makeLazy, proxyLazy } from "@utils/lazy";
import { AnyLazyComponentType, LazyComponent, SYM_LAZY_COMPONENT_INNER } 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, SYM_PROXY_INNER_GET, SYM_PROXY_INNER_VALUE } from "@utils/proxyInner";
@ -51,13 +51,12 @@ export type ModCallbackInfo = {
factory: AnyModuleFactory;
};
export type FactoryListernFn = (factory: AnyModuleFactory) => void;
export type ModListenerFn = (module: ModuleExports, info: ModListenerInfo) => void;
export type ModCallbackFn = ((module: ModuleExports, info: ModCallbackInfo) => void) & {
$$vencordCallbackCalled?: () => boolean;
};
export const factoryListeners = new Set<FactoryListernFn>();
export const factoryListeners = new Set<(factory: AnyModuleFactory) => void>();
export const moduleListeners = new Set<ModListenerFn>();
export const waitForSubscriptions = new Map<FilterFn, ModCallbackFn>();
@ -171,14 +170,16 @@ function printFilter(filter: FilterFn) {
return String(filter);
}
function wrapWebpackComponent<P extends AnyRecord>(err: string | (() => string)): [WrapperComponent: AnyLazyComponentType<P>, setInnerComponent: (rawComponent: any, parsedComponent: React.ComponentType<P>) => void] {
let InnerComponent = null as AnyComponentType<P> | null;
function wrapWebpackComponent<T extends object = any>(
errMsg: string | (() => string)
): [WrapperComponent: LazyComponentType<T>, setInnerComponent: (rawComponent: any, parsedComponent: LazyComponentType<T>) => void] {
let InnerComponent = null as LazyComponentType<T> | null;
let findFailedLogged = false;
const WrapperComponent: AnyLazyComponentType<P> = function (props) {
const WrapperComponent = (props: T) => {
if (InnerComponent === null && !findFailedLogged) {
findFailedLogged = true;
logger.error(typeof err === "string" ? err : err());
logger.error(typeof errMsg === "string" ? errMsg : errMsg());
}
return InnerComponent && <InnerComponent {...props} />;
@ -186,7 +187,7 @@ function wrapWebpackComponent<P extends AnyRecord>(err: string | (() => string))
WrapperComponent[SYM_LAZY_COMPONENT_INNER] = () => InnerComponent;
function setInnerComponent(RawComponent: any, ParsedComponent: React.ComponentType<P>) {
function setInnerComponent(RawComponent: any, ParsedComponent: LazyComponentType<T>) {
InnerComponent = ParsedComponent;
Object.assign(WrapperComponent, RawComponent);
}
@ -281,7 +282,7 @@ export function find<T = any>(filter: FilterFn, parse: (module: ModuleExports) =
* @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<P extends AnyRecord>(filter: FilterFn, parse: (component: ModuleExports) => React.ComponentType<P> = m => m, { isIndirect = false }: { isIndirect?: boolean; } = {}) {
export function findComponent<T extends object = any>(filter: FilterFn, parse: (component: ModuleExports) => LazyComponentType<T> = m => m, { isIndirect = false }: { isIndirect?: boolean; } = {}) {
if (typeof filter !== "function") {
throw new Error("Invalid filter. Expected a function got " + typeof filter);
}
@ -289,14 +290,14 @@ export function findComponent<P extends AnyRecord>(filter: FilterFn, parse: (com
throw new Error("Invalid component parse. Expected a function got " + typeof parse);
}
const [WrapperComponent, setInnerComponent] = wrapWebpackComponent<P>(`Webpack find matched no module. Filter: ${printFilter(filter)}`);
const [WrapperComponent, setInnerComponent] = wrapWebpackComponent<T>(`Webpack find matched no module. Filter: ${printFilter(filter)}`);
waitFor(filter, m => setInnerComponent(m, parse(m)), { isIndirect: true });
if (IS_REPORTER && !isIndirect) {
webpackSearchHistory.push(["findComponent", [WrapperComponent, filter]]);
}
if (WrapperComponent[SYM_LAZY_COMPONENT_INNER]() != null) return WrapperComponent[SYM_LAZY_COMPONENT_INNER]() as AnyLazyComponentType<P>;
if (WrapperComponent[SYM_LAZY_COMPONENT_INNER]() != null) return WrapperComponent[SYM_LAZY_COMPONENT_INNER]() as LazyComponentType<T>;
return WrapperComponent;
}
@ -311,20 +312,20 @@ export function findComponent<P extends AnyRecord>(filter: FilterFn, parse: (com
* @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<P extends AnyRecord>(...props: PropsFilter | [...PropsFilter, (component: ModuleExports) => React.ComponentType<P>]) {
const parse = (typeof props.at(-1) === "function" ? props.pop() : m => m) as (component: ModuleExports) => React.ComponentType<P>;
export function findExportedComponent<T extends object = any>(...props: PropsFilter | [...PropsFilter, (component: ModuleExports) => LazyComponentType<T>]) {
const parse = (typeof props.at(-1) === "function" ? props.pop() : m => m) as (component: ModuleExports) => LazyComponentType<T>;
const newProps = props as PropsFilter;
const filter = filters.byProps(...newProps);
const [WrapperComponent, setInnerComponent] = wrapWebpackComponent<P>(`Webpack find matched no module. Filter: ${printFilter(filter)}`);
const [WrapperComponent, setInnerComponent] = wrapWebpackComponent<T>(`Webpack find matched no module. Filter: ${printFilter(filter)}`);
waitFor(filter, m => setInnerComponent(m[newProps[0]], parse(m[newProps[0]])), { isIndirect: true });
if (IS_REPORTER) {
webpackSearchHistory.push(["findExportedComponent", [WrapperComponent, ...newProps]]);
}
if (WrapperComponent[SYM_LAZY_COMPONENT_INNER]() != null) return WrapperComponent[SYM_LAZY_COMPONENT_INNER]() as AnyLazyComponentType<P>;
if (WrapperComponent[SYM_LAZY_COMPONENT_INNER]() != null) return WrapperComponent[SYM_LAZY_COMPONENT_INNER]() as LazyComponentType<T>;
return WrapperComponent;
}
@ -339,11 +340,11 @@ export function findExportedComponent<P extends AnyRecord>(...props: PropsFilter
* @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<P extends AnyRecord>(...code: CodeFilter | [...CodeFilter, (component: ModuleExports) => React.ComponentType<P>]) {
const parse = (typeof code.at(-1) === "function" ? code.pop() : m => m) as (component: ModuleExports) => React.ComponentType<P>;
export function findComponentByCode<T extends object = any>(...code: CodeFilter | [...CodeFilter, (component: ModuleExports) => LazyComponentType<T>]) {
const parse = (typeof code.at(-1) === "function" ? code.pop() : m => m) as (component: ModuleExports) => LazyComponentType<T>;
const newCode = code as CodeFilter;
const ComponentResult = findComponent<P>(filters.componentByCode(...newCode), parse, { isIndirect: true });
const ComponentResult = findComponent<T>(filters.componentByCode(...newCode), parse, { isIndirect: true });
if (IS_REPORTER) {
webpackSearchHistory.push(["findComponentByCode", [ComponentResult, ...newCode]]);
@ -362,11 +363,11 @@ export function findComponentByCode<P extends AnyRecord>(...code: CodeFilter | [
* @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 findComponentByFields<P extends AnyRecord>(...fields: PropsFilter | [...PropsFilter, (component: ModuleExports) => React.ComponentType<P>]) {
const parse = (typeof fields.at(-1) === "function" ? fields.pop() : m => m) as (component: ModuleExports) => React.ComponentType<P>;
export function findComponentByFields<T extends object = any>(...fields: PropsFilter | [...PropsFilter, (component: ModuleExports) => LazyComponentType<T>]) {
const parse = (typeof fields.at(-1) === "function" ? fields.pop() : m => m) as (component: ModuleExports) => LazyComponentType<T>;
const newFields = fields as PropsFilter;
const ComponentResult = findComponent<P>(filters.componentByFields(...newFields), parse, { isIndirect: true });
const ComponentResult = findComponent<T>(filters.componentByFields(...newFields), parse, { isIndirect: true });
if (IS_REPORTER) {
webpackSearchHistory.push(["findComponentByCode", [ComponentResult, ...newFields]]);
@ -496,14 +497,14 @@ export function mapMangledModule<S extends PropertyKey>(code: CodeFilterWithSing
const mapperFilter = mappers[newName];
// Wrapper to select whether the parent factory filter or child mapper filter failed when the error is thrown
const errorWrapper = () => `Webpack mapMangledModule ${callbackCalled ? "mapper" : "factory"} filter matched no module. Filter: ${printFilter(callbackCalled ? mapperFilter : factoryFilter)}`;
const errorMsgWrapper = () => `Webpack mapMangledModule ${callbackCalled ? "mapper" : "factory"} filter matched no module. Filter: ${printFilter(callbackCalled ? mapperFilter : factoryFilter)}`;
if (mapperFilter.$$vencordIsComponentFilter) {
const [WrapperComponent, setInnerComponent] = wrapWebpackComponent(errorWrapper);
const [WrapperComponent, setInnerComponent] = wrapWebpackComponent(errorMsgWrapper);
mapping[newName] = WrapperComponent;
wrapperComponentSetters[newName] = setInnerComponent;
} else {
const [proxy, setInnerValue] = proxyInner(errorWrapper, "Webpack find with proxy called on a primitive value. This may happen if you are trying to destructure a mapMangledModule primitive value on top level.");
const [proxy, setInnerValue] = proxyInner(errorMsgWrapper, "Webpack find with proxy called on a primitive value. This may happen if you are trying to destructure a mapMangledModule primitive value on top level.");
mapping[newName] = proxy;
proxyInnerSetters[newName] = setInnerValue;
}
@ -603,12 +604,12 @@ export function webpackDependantLazy<T = any>(factory: () => T, attempts?: numbe
* @param attempts How many times to try to get the component before giving up
* @returns Result of factory function
*/
export function webpackDependantLazyComponent<P extends AnyRecord>(factory: () => any, attempts?: number) {
export function webpackDependantLazyComponent<T extends object = any>(factory: () => any, attempts?: number) {
if (IS_REPORTER) {
webpackSearchHistory.push(["webpackDependantLazyComponent", [factory]]);
}
return LazyComponent<P>(factory, attempts, `Webpack dependant LazyComponent factory failed:\n${factory}`);
return LazyComponent<T>(factory, attempts, `Webpack dependant LazyComponent factory failed:\n${factory}`);
}
export const DefaultExtractAndLoadChunksRegex = /(?:(?:Promise\.all\(\[)?(\i\.e\("?[^)]+?"?\)[^\]]*?)(?:\]\))?|Promise\.resolve\(\))\.then\(\i\.bind\(\i,"?([^)]+?)"?\)\)/;

View file

@ -44,8 +44,6 @@ export let Avatar: t.Avatar = NoopComponent;
export let FocusLock: t.FocusLock = NoopComponent;
export let useToken: t.useToken;
export let Icons = {} as t.Icons;
export const MaskedLink = findComponentByCode<t.MaskedLinkProps>("MASKED_LINK)");
export const Timestamp = findComponentByCode<t.TimestampProps>(".Messages.MESSAGE_EDITED_TIMESTAMP_A11Y_LABEL.format");
export const Flex = findComponent(filters.byProps("Justify", "Align", "Wrap")) as t.Flex;
@ -78,6 +76,5 @@ export const Forms = findByProps<t.Forms>("FormItem", "Button", m => {
Heading
} = m);
Icons = m;
return m;
});

View file

@ -18,8 +18,6 @@
import type { ComponentType, CSSProperties, FunctionComponent, HtmlHTMLAttributes, HTMLProps, KeyboardEvent, MouseEvent, PropsWithChildren, PropsWithRef, ReactNode, Ref } from "react";
import { IconNames } from "./iconNames";
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";
export type FormTextTypes = Record<"DEFAULT" | "INPUT_PLACEHOLDER" | "DESCRIPTION" | "LABEL_BOLD" | "LABEL_SELECTED" | "LABEL_DESCRIPTOR" | "ERROR" | "SUCCESS", string>;
export type HeadingTag = `h${1 | 2 | 3 | 4 | 5 | 6}`;
@ -78,7 +76,7 @@ export type Forms = {
};
export type Tooltip = ComponentType<{
text: ReactNode | ComponentType;
text: ReactNode;
children: FunctionComponent<{
onClick(): void;
onMouseEnter(): void;
@ -518,10 +516,3 @@ export type Avatar = ComponentType<PropsWithChildren<{
type FocusLock = ComponentType<PropsWithChildren<{
containerRef: RefObject<HTMLElement>;
}>>;
export type Icon = AnyComponentType<React.ComponentPropsWithoutRef<"svg"> & {
size?: string;
colorClass?: string;
}>;
export type Icons = Record<IconNames, Icon>;

File diff suppressed because one or more lines are too long

View file

@ -16,10 +16,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import type { CSSProperties, MouseEvent, ReactNode, UIEvent } from "react";
import type { ComponentType, CSSProperties, MouseEvent, PropsWithChildren, ReactNode, UIEvent } from "react";
type RC<C> = ComponentType<PropsWithChildren<C & Record<PropertyKey, any>>>;
export interface Menu {
Menu: AnyComponentTypeWithChildren<{
Menu: RC<{
navId: string;
onClose(): void;
className?: string;
@ -27,31 +29,31 @@ export interface Menu {
hideScroller?: boolean;
onSelect?(): void;
}>;
MenuSeparator: AnyComponentType;
MenuGroup: AnyComponentTypeWithChildren<{
MenuSeparator: ComponentType;
MenuGroup: RC<{
label?: string;
}>;
MenuItem: AnyComponentTypeWithChildren<{
MenuItem: RC<{
id: string;
label: ReactNode;
action?(e: MouseEvent): void;
icon?: AnyComponentType<any>;
icon?: ComponentType<any>;
color?: string;
render?: AnyComponentType<any>;
render?: ComponentType<any>;
onChildrenScroll?: Function;
childRowHeight?: number;
listClassName?: string;
disabled?: boolean;
}>;
MenuCheckboxItem: AnyComponentTypeWithChildren<{
MenuCheckboxItem: RC<{
id: string;
label: string;
checked: boolean;
action?(e: MouseEvent): void;
disabled?: boolean;
}>;
MenuRadioItem: AnyComponentTypeWithChildren<{
MenuRadioItem: RC<{
id: string;
group: string;
label: string;
@ -59,19 +61,19 @@ export interface Menu {
action?(e: MouseEvent): void;
disabled?: boolean;
}>;
MenuControlItem: AnyComponentTypeWithChildren<{
MenuControlItem: RC<{
id: string;
interactive?: boolean;
}>;
MenuSliderControl: AnyComponentTypeWithChildren<{
MenuSliderControl: RC<{
minValue: number,
maxValue: number,
value: number,
onChange(value: number): void,
renderValue?(value: number): string,
}>;
MenuSearchControl: AnyComponentTypeWithChildren<{
query: string;
MenuSearchControl: RC<{
query: string
onChange(query: string): void;
placeholder?: string;
}>;

View file

@ -241,7 +241,7 @@ export interface Constants {
export type ActiveView = LiteralUnion<"emoji" | "gif" | "sticker" | "soundboard", string>;
export interface ExpressionPickerStoreState extends AnyRecord {
export interface ExpressionPickerStoreState extends Record<PropertyKey, any> {
activeView: ActiveView | null;
lastActiveView: ActiveView | null;
activeViewType: any | null;

View file

@ -72,7 +72,7 @@ export type WebpackRequire = ((moduleId: PropertyKey) => ModuleExports) & {
// * });
// * @returns fromObject
// */
// es: (this: WebpackRequire, fromObject: AnyRecord, toObject: AnyRecord) => AnyRecord;
// es: (this: WebpackRequire, fromObject: Record<PropertyKey, any>, toObject: Record<PropertyKey, any>) => Record<PropertyKey, any>;
/**
* Creates an async module. A module that exports something that is a Promise, or requires an export from an async module.
*
@ -132,7 +132,7 @@ export type WebpackRequire = ((moduleId: PropertyKey) => ModuleExports) & {
* }
* // exports is now { exportName: someExportedValue } (but each value is actually a getter)
*/
d: (this: WebpackRequire, exports: AnyRecord, definiton: AnyRecord) => void;
d: (this: WebpackRequire, exports: Record<PropertyKey, any>, definiton: Record<PropertyKey, any>) => void;
/** The chunk handlers, which are used to ensure the files of the chunks are loaded, or load if necessary */
f: ChunkHandlers;
/**