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

View file

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

View file

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

View file

@ -292,10 +292,10 @@ export default function PluginSettings() {
if (!pluginFilter(p)) continue; 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) { if (isRequired) {
const tooltipText = p.required || !depMap[p.name] const tooltipText = p.required
? "This plugin is required for Vencord to function." ? "This plugin is required for Vencord to function."
: makeDependencyList(depMap[p.name]?.filter(d => settings.plugins[d].enabled)); : 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 { classNameFactory } from "@api/Styles";
import { Card } from "@webpack/common"; import { Card } from "@webpack/common";
import type { ComponentType, PropsWithChildren, ReactNode } from "react";
const cl = classNameFactory("vc-settings-quickActions-"); const cl = classNameFactory("vc-settings-quickActions-");
export interface QuickActionProps { export interface QuickActionProps {
Icon: React.ComponentType<{ className?: string; }>; Icon: ComponentType<{ className?: string; }>;
text: React.ReactNode; text: ReactNode;
action?: () => void; action?: () => void;
disabled?: boolean; disabled?: boolean;
} }
@ -29,7 +30,7 @@ export function QuickAction(props: QuickActionProps) {
); );
} }
export function QuickActionCard(props: React.PropsWithChildren) { export function QuickActionCard(props: PropsWithChildren) {
return ( return (
<Card className={cl("card")}> <Card className={cl("card")}>
{props.children} {props.children}

View file

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

6
src/globals.d.ts vendored
View file

@ -19,10 +19,6 @@
import { LoDashStatic } from "lodash"; import { LoDashStatic } from "lodash";
declare global { 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 * 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 * via String interpolation OR use different replacement code based on this
@ -68,7 +64,7 @@ declare global {
export var Vesktop: any; export var Vesktop: any;
export var VesktopNative: any; export var VesktopNative: any;
interface Window extends AnyRecord { interface Window extends Record<PropertyKey, any> {
_: LoDashStatic; _: LoDashStatic;
} }
} }

View file

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

View file

@ -23,7 +23,7 @@ const UserProfile = findComponentByCode("UserProfilePopoutWrapper: user cannot b
const styles = findByProps("accountProfilePopoutWrapper"); const styles = findByProps("accountProfilePopoutWrapper");
let openAlternatePopout = false; 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 AccountPanelContextMenu = ErrorBoundary.wrap(() => {
const { prioritizeServerProfile } = settings.use(["prioritizeServerProfile"]); 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 { cacheFindAll, cacheFindModuleId, extract, filters, searchFactories } from "@webpack";
import * as Common from "@webpack/common"; import * as Common from "@webpack/common";
import { loadLazyChunks } from "debug/loadLazyChunks"; import { loadLazyChunks } from "debug/loadLazyChunks";
import type { ComponentType } from "react";
const DESKTOP_ONLY = (f: string) => () => { const DESKTOP_ONLY = (f: string) => () => {
throw new Error(`'${f}' is Discord Desktop only.`); throw new Error(`'${f}' is Discord Desktop only.`);
@ -128,7 +129,7 @@ function makeShortcuts() {
canonicalizeReplacement, canonicalizeReplacement,
preEnable: (plugin: string) => (Vencord.Settings.plugins[plugin] ??= { enabled: true }).enabled = true, 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 prevWin = fakeRenderWin?.deref();
const win = prevWin?.closed === false const win = prevWin?.closed === false
? prevWin ? prevWin

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -13,6 +13,7 @@ import definePlugin, { OptionType } from "@utils/types";
import { findComponentByCode } from "@webpack"; import { findComponentByCode } from "@webpack";
import { ChannelStore, GuildMemberStore, i18n, Text, Tooltip } from "@webpack/common"; import { ChannelStore, GuildMemberStore, i18n, Text, Tooltip } from "@webpack/common";
import { Message } from "discord-types/general"; import { Message } from "discord-types/general";
import { FunctionComponent, ReactNode } from "react";
const CountDown = findComponentByCode(".MAX_AGE_NEVER"); 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 if (settings.store.displayStyle === DisplayStyle.Tooltip) return <Tooltip
children={children} children={children}
text={renderTimeout(message, false)} text={renderTimeout(message, false)}

View file

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

View file

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

View file

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

View file

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

View file

@ -29,6 +29,7 @@ import definePlugin from "@utils/types";
import { chooseFile } from "@utils/web"; import { chooseFile } from "@utils/web";
import { find, findByProps, findStore } from "@webpack"; 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 { 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 { VoiceRecorderDesktop } from "./DesktopRecorder";
import { settings } from "./settings"; import { settings } from "./settings";
@ -40,7 +41,7 @@ const CloudUpload = find(m => m.prototype?.trackUploadFinished);
const PendingReplyStore = findStore("PendingReplyStore"); const PendingReplyStore = findStore("PendingReplyStore");
const OptionClasses = findByProps("optionName", "optionIcon", "optionLabel"); const OptionClasses = findByProps("optionName", "optionIcon", "optionLabel");
export type VoiceRecorder = AnyComponentType<{ export type VoiceRecorder = ComponentType<{
setAudioBlob(blob: Blob): void; setAudioBlob(blob: Blob): void;
onRecordingChange?(recording: boolean): 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 tries = 0;
let cache: T; let cache: T;
const getter: LazyFunction<T> = function () { const getter = () => {
if (!cache && attempts > tries) { if (!cache && attempts > tries) {
tries++; tries++;
cache = factory(); cache = factory();
@ -30,6 +30,7 @@ export function makeLazy<T>(factory: () => T, attempts = 5, { isIndirect = false
}; };
getter.$$vencordLazyFailed = () => tries === attempts; getter.$$vencordLazyFailed = () => tries === attempts;
return getter; return getter;
} }
@ -68,11 +69,17 @@ const handler: ProxyHandler<any> = {
* *
* @param factory Factory returning the result * @param factory Factory returning the result
* @param attempts How many times to try to evaluate the factory before giving up * @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 errMsg The error message to throw when the factory fails
* @param primitiveErr The error message to throw when factory result is a primitive * @param primitiveErrMsg The error message to throw when factory result is a primitive
* @returns Result of factory function * @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 }); const get = makeLazy(factory, attempts, { isIndirect: true });
let isSameTick = true; let isSameTick = true;
@ -86,7 +93,7 @@ export function proxyLazy<T = any>(factory: () => T, attempts = 5, err: string |
} }
if (!proxyDummy[SYM_LAZY_CACHED]) { if (!proxyDummy[SYM_LAZY_CACHED]) {
throw new Error(typeof err === "string" ? err : err()); throw new Error(typeof errMsg === "string" ? errMsg : errMsg());
} else { } else {
if (typeof proxyDummy[SYM_LAZY_CACHED] === "function") { if (typeof proxyDummy[SYM_LAZY_CACHED] === "function") {
proxy.toString = proxyDummy[SYM_LAZY_CACHED].toString.bind(proxyDummy[SYM_LAZY_CACHED]); 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); return Reflect.get(lazyTarget, p, lazyTarget);
}, },
attempts, attempts,
err, errMsg,
primitiveErr, primitiveErrMsg,
true true
); );
} }
@ -133,7 +140,7 @@ export function proxyLazy<T = any>(factory: () => T, attempts = 5, err: string |
return Reflect.get(lazyTarget, p, lazyTarget); return Reflect.get(lazyTarget, p, lazyTarget);
} }
throw new Error(primitiveErr); throw new Error(primitiveErrMsg);
} }
}); });

View file

@ -6,12 +6,9 @@
import { makeLazy } from "./lazy"; 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 & { export const SYM_LAZY_COMPONENT_INNER = Symbol.for("vencord.lazyComponent.inner");
[SYM_LAZY_COMPONENT_INNER]: () => AnyComponentType<P> | null;
};
export type AnyLazyComponentType<P extends AnyRecord = AnyRecord> = LazyComponentType<P & AnyRecord>;
/** /**
* A lazy component. The factory method is called on first render. * 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 * @param attempts How many times to try to get the component before giving up
* @returns Result of factory function * @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 }); const get = makeLazy(factory, attempts, { isIndirect: true });
let InnerComponent = null as AnyComponentType<P> | null; let InnerComponent = null as LazyComponentType<T> | null;
let lazyFailedLogged = false; let lazyFailedLogged = false;
const LazyComponent: LazyComponentType<P> = function (props) { const LazyComponent = (props: T) => {
if (!get.$$vencordLazyFailed()) { if (!get.$$vencordLazyFailed()) {
const ResultComponent = get(); const ResultComponent = get();
if (ResultComponent != null) { if (ResultComponent != null) {
InnerComponent = ResultComponent; InnerComponent = ResultComponent;
Object.assign(LazyComponent, ResultComponent); Object.assign(LazyComponent, ResultComponent);
@ -41,7 +37,7 @@ export function LazyComponent<P extends AnyRecord>(factory: () => React.Componen
lazyFailedLogged = true; lazyFailedLogged = true;
} }
console.error(typeof err === "string" ? err : err()); console.error(typeof errMsg === "string" ? errMsg : errMsg());
} }
return InnerComponent && <InnerComponent {...props} />; return InnerComponent && <InnerComponent {...props} />;
@ -49,5 +45,5 @@ export function LazyComponent<P extends AnyRecord>(factory: () => React.Componen
LazyComponent[SYM_LAZY_COMPONENT_INNER] = () => InnerComponent; 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 { findByProps, findComponentByCode } from "@webpack";
import type { ComponentType, PropsWithChildren, ReactNode, Ref } from "react";
import { NoopComponent } from "./react"; import { NoopComponent } from "./react";
@ -46,10 +47,10 @@ export interface ModalOptions {
onCloseCallback?: (() => void); onCloseCallback?: (() => void);
} }
type RenderFunction = (props: ModalProps) => React.ReactNode; type RenderFunction = (props: ModalProps) => ReactNode;
type Modals = { type Modals = {
ModalRoot: AnyComponentTypeWithChildren<{ ModalRoot: ComponentType<PropsWithChildren<{
transitionState: ModalTransitionState; transitionState: ModalTransitionState;
size?: ModalSize; size?: ModalSize;
role?: "alertdialog" | "dialog"; role?: "alertdialog" | "dialog";
@ -58,8 +59,8 @@ type Modals = {
"aria-label"?: string; "aria-label"?: string;
"aria-labelledby"?: string; "aria-labelledby"?: string;
onAnimationEnd?(): string; onAnimationEnd?(): string;
}>; }>>;
ModalHeader: AnyComponentTypeWithChildren<{ ModalHeader: ComponentType<PropsWithChildren<{
/** Flex.Justify.START */ /** Flex.Justify.START */
justify?: string; justify?: string;
/** Flex.Direction.HORIZONTAL */ /** Flex.Direction.HORIZONTAL */
@ -71,13 +72,14 @@ type Modals = {
separator?: boolean; separator?: boolean;
className?: string; className?: string;
}>; }>>;
/** This also accepts Scroller props but good luck with that */ /** This also accepts Scroller props but good luck with that */
ModalContent: AnyComponentTypeWithChildren<{ ModalContent: ComponentType<PropsWithChildren<{
className?: string; className?: string;
scrollerRef?: React.Ref<HTMLElement>; scrollerRef?: Ref<HTMLElement>;
}>; [prop: string]: any;
ModalFooter: AnyComponentTypeWithChildren<{ }>>;
ModalFooter: ComponentType<PropsWithChildren<{
/** Flex.Justify.START */ /** Flex.Justify.START */
justify?: string; justify?: string;
/** Flex.Direction.HORIZONTAL_REVERSE */ /** Flex.Direction.HORIZONTAL_REVERSE */
@ -89,8 +91,8 @@ type Modals = {
separator?: boolean; separator?: boolean;
className?: string; className?: string;
}>; }>>;
ModalCloseButton: AnyComponentType<{ ModalCloseButton: ComponentType<{
focusProps?: any; focusProps?: any;
onClick(): void; onClick(): void;
withCircleBackground?: boolean; withCircleBackground?: boolean;
@ -121,8 +123,8 @@ export type ImageModalProps = {
height?: number; height?: number;
animated?: boolean; animated?: boolean;
responsive?: boolean; responsive?: boolean;
renderLinkComponent(props: any): React.ReactNode; renderLinkComponent(props: any): ReactNode;
renderForwardComponent(props: any): React.ReactNode; renderForwardComponent(props: any): ReactNode;
maxWidth?: number; maxWidth?: number;
maxHeight?: number; maxHeight?: number;
shouldAnimate?: boolean; shouldAnimate?: boolean;

View file

@ -42,18 +42,22 @@ const handler: ProxyHandler<any> = {
* IMPORTANT: * IMPORTANT:
* Destructuring at top level is not supported for proxyInner. * Destructuring at top level is not supported for proxyInner.
* *
* @param err The error message to throw when the inner value is not set * @param errMsg 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 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 * @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; let isSameTick = true;
if (!isChild) setTimeout(() => isSameTick = false, 0); if (!isChild) setTimeout(() => isSameTick = false, 0);
const proxyDummy = Object.assign(function () { }, { const proxyDummy = Object.assign(function () { }, {
[SYM_PROXY_INNER_GET]: function () { [SYM_PROXY_INNER_GET]: function () {
if (proxyDummy[SYM_PROXY_INNER_VALUE] == null) { 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]; 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." "\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) => { recursiveSetInnerValues.push((innerValue: T) => {
// Set the inner value of the destructured value as the prop value p of the parent // 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); 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; stop?(): void;
patches?: Omit<Patch, "plugin">[]; 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[]; commands?: Command[];
/** /**
* A list of other plugins that your plugin depends on. * A list of other plugins that your plugin depends on.
* These will automatically be enabled and loaded before your plugin * These will automatically be enabled and loaded before your plugin
* Generally these will be API plugins * Common examples are CommandsAPI, MessageEventsAPI...
*/ */
dependencies?: string[], dependencies?: string[],
/** /**

View file

@ -5,7 +5,7 @@
*/ */
import { makeLazy, proxyLazy } from "@utils/lazy"; 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 { Logger } from "@utils/Logger";
import { canonicalizeMatch } from "@utils/patches"; import { canonicalizeMatch } from "@utils/patches";
import { proxyInner, SYM_PROXY_INNER_GET, SYM_PROXY_INNER_VALUE } from "@utils/proxyInner"; import { proxyInner, SYM_PROXY_INNER_GET, SYM_PROXY_INNER_VALUE } from "@utils/proxyInner";
@ -51,13 +51,12 @@ export type ModCallbackInfo = {
factory: AnyModuleFactory; factory: AnyModuleFactory;
}; };
export type FactoryListernFn = (factory: AnyModuleFactory) => void;
export type ModListenerFn = (module: ModuleExports, info: ModListenerInfo) => void; export type ModListenerFn = (module: ModuleExports, info: ModListenerInfo) => void;
export type ModCallbackFn = ((module: ModuleExports, info: ModCallbackInfo) => void) & { export type ModCallbackFn = ((module: ModuleExports, info: ModCallbackInfo) => void) & {
$$vencordCallbackCalled?: () => boolean; $$vencordCallbackCalled?: () => boolean;
}; };
export const factoryListeners = new Set<FactoryListernFn>(); export const factoryListeners = new Set<(factory: AnyModuleFactory) => void>();
export const moduleListeners = new Set<ModListenerFn>(); export const moduleListeners = new Set<ModListenerFn>();
export const waitForSubscriptions = new Map<FilterFn, ModCallbackFn>(); export const waitForSubscriptions = new Map<FilterFn, ModCallbackFn>();
@ -171,14 +170,16 @@ function printFilter(filter: FilterFn) {
return String(filter); return String(filter);
} }
function wrapWebpackComponent<P extends AnyRecord>(err: string | (() => string)): [WrapperComponent: AnyLazyComponentType<P>, setInnerComponent: (rawComponent: any, parsedComponent: React.ComponentType<P>) => void] { function wrapWebpackComponent<T extends object = any>(
let InnerComponent = null as AnyComponentType<P> | null; errMsg: string | (() => string)
): [WrapperComponent: LazyComponentType<T>, setInnerComponent: (rawComponent: any, parsedComponent: LazyComponentType<T>) => void] {
let InnerComponent = null as LazyComponentType<T> | null;
let findFailedLogged = false; let findFailedLogged = false;
const WrapperComponent: AnyLazyComponentType<P> = function (props) { const WrapperComponent = (props: T) => {
if (InnerComponent === null && !findFailedLogged) { if (InnerComponent === null && !findFailedLogged) {
findFailedLogged = true; findFailedLogged = true;
logger.error(typeof err === "string" ? err : err()); logger.error(typeof errMsg === "string" ? errMsg : errMsg());
} }
return InnerComponent && <InnerComponent {...props} />; return InnerComponent && <InnerComponent {...props} />;
@ -186,7 +187,7 @@ function wrapWebpackComponent<P extends AnyRecord>(err: string | (() => string))
WrapperComponent[SYM_LAZY_COMPONENT_INNER] = () => InnerComponent; WrapperComponent[SYM_LAZY_COMPONENT_INNER] = () => InnerComponent;
function setInnerComponent(RawComponent: any, ParsedComponent: React.ComponentType<P>) { function setInnerComponent(RawComponent: any, ParsedComponent: LazyComponentType<T>) {
InnerComponent = ParsedComponent; InnerComponent = ParsedComponent;
Object.assign(WrapperComponent, RawComponent); 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 * @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 * @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") { if (typeof filter !== "function") {
throw new Error("Invalid filter. Expected a function got " + typeof filter); 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); 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 }); waitFor(filter, m => setInnerComponent(m, parse(m)), { isIndirect: true });
if (IS_REPORTER && !isIndirect) { if (IS_REPORTER && !isIndirect) {
webpackSearchHistory.push(["findComponent", [WrapperComponent, filter]]); 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; 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 * @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 * @returns The component if found, or a noop component
*/ */
export function findExportedComponent<P extends AnyRecord>(...props: PropsFilter | [...PropsFilter, (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) => React.ComponentType<P>; const parse = (typeof props.at(-1) === "function" ? props.pop() : m => m) as (component: ModuleExports) => LazyComponentType<T>;
const newProps = props as PropsFilter; const newProps = props as PropsFilter;
const filter = filters.byProps(...newProps); 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 }); waitFor(filter, m => setInnerComponent(m[newProps[0]], parse(m[newProps[0]])), { isIndirect: true });
if (IS_REPORTER) { if (IS_REPORTER) {
webpackSearchHistory.push(["findExportedComponent", [WrapperComponent, ...newProps]]); 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; 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 * @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 * @returns The component if found, or a noop component
*/ */
export function findComponentByCode<P extends AnyRecord>(...code: CodeFilter | [...CodeFilter, (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) => React.ComponentType<P>; const parse = (typeof code.at(-1) === "function" ? code.pop() : m => m) as (component: ModuleExports) => LazyComponentType<T>;
const newCode = code as CodeFilter; 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) { if (IS_REPORTER) {
webpackSearchHistory.push(["findComponentByCode", [ComponentResult, ...newCode]]); 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 * @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 * @returns The component if found, or a noop component
*/ */
export function findComponentByFields<P extends AnyRecord>(...fields: PropsFilter | [...PropsFilter, (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) => React.ComponentType<P>; const parse = (typeof fields.at(-1) === "function" ? fields.pop() : m => m) as (component: ModuleExports) => LazyComponentType<T>;
const newFields = fields as PropsFilter; 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) { if (IS_REPORTER) {
webpackSearchHistory.push(["findComponentByCode", [ComponentResult, ...newFields]]); webpackSearchHistory.push(["findComponentByCode", [ComponentResult, ...newFields]]);
@ -496,14 +497,14 @@ export function mapMangledModule<S extends PropertyKey>(code: CodeFilterWithSing
const mapperFilter = mappers[newName]; const mapperFilter = mappers[newName];
// Wrapper to select whether the parent factory filter or child mapper filter failed when the error is thrown // 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) { if (mapperFilter.$$vencordIsComponentFilter) {
const [WrapperComponent, setInnerComponent] = wrapWebpackComponent(errorWrapper); const [WrapperComponent, setInnerComponent] = wrapWebpackComponent(errorMsgWrapper);
mapping[newName] = WrapperComponent; mapping[newName] = WrapperComponent;
wrapperComponentSetters[newName] = setInnerComponent; wrapperComponentSetters[newName] = setInnerComponent;
} else { } 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; mapping[newName] = proxy;
proxyInnerSetters[newName] = setInnerValue; 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 * @param attempts How many times to try to get the component before giving up
* @returns Result of factory function * @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) { if (IS_REPORTER) {
webpackSearchHistory.push(["webpackDependantLazyComponent", [factory]]); 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,"?([^)]+?)"?\)\)/; 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 FocusLock: t.FocusLock = NoopComponent;
export let useToken: t.useToken; export let useToken: t.useToken;
export let Icons = {} as t.Icons;
export const MaskedLink = findComponentByCode<t.MaskedLinkProps>("MASKED_LINK)"); export const MaskedLink = findComponentByCode<t.MaskedLinkProps>("MASKED_LINK)");
export const Timestamp = findComponentByCode<t.TimestampProps>(".Messages.MESSAGE_EDITED_TIMESTAMP_A11Y_LABEL.format"); 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; 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 Heading
} = m); } = m);
Icons = m;
return 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 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 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 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}`; export type HeadingTag = `h${1 | 2 | 3 | 4 | 5 | 6}`;
@ -78,7 +76,7 @@ export type Forms = {
}; };
export type Tooltip = ComponentType<{ export type Tooltip = ComponentType<{
text: ReactNode | ComponentType; text: ReactNode;
children: FunctionComponent<{ children: FunctionComponent<{
onClick(): void; onClick(): void;
onMouseEnter(): void; onMouseEnter(): void;
@ -518,10 +516,3 @@ export type Avatar = ComponentType<PropsWithChildren<{
type FocusLock = ComponentType<PropsWithChildren<{ type FocusLock = ComponentType<PropsWithChildren<{
containerRef: RefObject<HTMLElement>; 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/>. * 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 { export interface Menu {
Menu: AnyComponentTypeWithChildren<{ Menu: RC<{
navId: string; navId: string;
onClose(): void; onClose(): void;
className?: string; className?: string;
@ -27,31 +29,31 @@ export interface Menu {
hideScroller?: boolean; hideScroller?: boolean;
onSelect?(): void; onSelect?(): void;
}>; }>;
MenuSeparator: AnyComponentType; MenuSeparator: ComponentType;
MenuGroup: AnyComponentTypeWithChildren<{ MenuGroup: RC<{
label?: string; label?: string;
}>; }>;
MenuItem: AnyComponentTypeWithChildren<{ MenuItem: RC<{
id: string; id: string;
label: ReactNode; label: ReactNode;
action?(e: MouseEvent): void; action?(e: MouseEvent): void;
icon?: AnyComponentType<any>; icon?: ComponentType<any>;
color?: string; color?: string;
render?: AnyComponentType<any>; render?: ComponentType<any>;
onChildrenScroll?: Function; onChildrenScroll?: Function;
childRowHeight?: number; childRowHeight?: number;
listClassName?: string; listClassName?: string;
disabled?: boolean; disabled?: boolean;
}>; }>;
MenuCheckboxItem: AnyComponentTypeWithChildren<{ MenuCheckboxItem: RC<{
id: string; id: string;
label: string; label: string;
checked: boolean; checked: boolean;
action?(e: MouseEvent): void; action?(e: MouseEvent): void;
disabled?: boolean; disabled?: boolean;
}>; }>;
MenuRadioItem: AnyComponentTypeWithChildren<{ MenuRadioItem: RC<{
id: string; id: string;
group: string; group: string;
label: string; label: string;
@ -59,19 +61,19 @@ export interface Menu {
action?(e: MouseEvent): void; action?(e: MouseEvent): void;
disabled?: boolean; disabled?: boolean;
}>; }>;
MenuControlItem: AnyComponentTypeWithChildren<{ MenuControlItem: RC<{
id: string; id: string;
interactive?: boolean; interactive?: boolean;
}>; }>;
MenuSliderControl: AnyComponentTypeWithChildren<{ MenuSliderControl: RC<{
minValue: number, minValue: number,
maxValue: number, maxValue: number,
value: number, value: number,
onChange(value: number): void, onChange(value: number): void,
renderValue?(value: number): string, renderValue?(value: number): string,
}>; }>;
MenuSearchControl: AnyComponentTypeWithChildren<{ MenuSearchControl: RC<{
query: string; query: string
onChange(query: string): void; onChange(query: string): void;
placeholder?: string; placeholder?: string;
}>; }>;

View file

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

View file

@ -72,7 +72,7 @@ export type WebpackRequire = ((moduleId: PropertyKey) => ModuleExports) & {
// * }); // * });
// * @returns fromObject // * @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. * 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) * // 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 */ /** The chunk handlers, which are used to ensure the files of the chunks are loaded, or load if necessary */
f: ChunkHandlers; f: ChunkHandlers;
/** /**