diff --git a/package.json b/package.json index a7dca5793..057175f9c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vencord", "private": "true", - "version": "1.11.2", + "version": "1.11.3", "description": "The cutest Discord client mod", "homepage": "https://github.com/Vendicated/Vencord#readme", "bugs": { diff --git a/src/components/PluginSettings/PluginModal.tsx b/src/components/PluginSettings/PluginModal.tsx index 3f7965d58..7baeba081 100644 --- a/src/components/PluginSettings/PluginModal.tsx +++ b/src/components/PluginSettings/PluginModal.tsx @@ -37,6 +37,7 @@ import { Constructor } from "type-fest"; import { PluginMeta } from "~plugins"; import { + ISettingCustomElementProps, ISettingElementProps, SettingBooleanComponent, SettingCustomComponent, @@ -74,7 +75,7 @@ function makeDummyUser(user: { username: string; id?: string; avatar?: string; } return newUser; } -const Components: Record>> = { +const Components: Record | ISettingCustomElementProps>> = { [OptionType.STRING]: SettingTextComponent, [OptionType.NUMBER]: SettingNumericComponent, [OptionType.BIGINT]: SettingNumericComponent, diff --git a/src/components/PluginSettings/components/SettingCustomComponent.tsx b/src/components/PluginSettings/components/SettingCustomComponent.tsx index af7192f3f..25e8c9c6a 100644 --- a/src/components/PluginSettings/components/SettingCustomComponent.tsx +++ b/src/components/PluginSettings/components/SettingCustomComponent.tsx @@ -18,8 +18,8 @@ import { PluginOptionComponent } from "@utils/types"; -import { ISettingElementProps } from "."; +import { ISettingCustomElementProps } from "."; -export function SettingCustomComponent({ option, onChange, onError }: ISettingElementProps) { +export function SettingCustomComponent({ option, onChange, onError }: ISettingCustomElementProps) { return option.component({ setValue: onChange, setError: onError, option }); } diff --git a/src/components/PluginSettings/components/index.ts b/src/components/PluginSettings/components/index.ts index d307b4e68..c38f209b7 100644 --- a/src/components/PluginSettings/components/index.ts +++ b/src/components/PluginSettings/components/index.ts @@ -18,7 +18,7 @@ import { DefinedSettings, PluginOptionBase } from "@utils/types"; -export interface ISettingElementProps { +interface ISettingElementPropsBase { option: T; onChange(newValue: any): void; pluginSettings: { @@ -30,6 +30,9 @@ export interface ISettingElementProps { definedSettings?: DefinedSettings; } +export type ISettingElementProps = ISettingElementPropsBase; +export type ISettingCustomElementProps> = ISettingElementPropsBase; + export * from "../../Badge"; export * from "./SettingBooleanComponent"; export * from "./SettingCustomComponent"; diff --git a/src/plugins/_api/chatButtons.ts b/src/plugins/_api/chatButtons.ts index 86ca195e0..184b01584 100644 --- a/src/plugins/_api/chatButtons.ts +++ b/src/plugins/_api/chatButtons.ts @@ -16,6 +16,7 @@ export default definePlugin({ { find: '"sticker")', replacement: { + // FIXME(Bundler change related): Remove old compatiblity once enough time has passed match: /return\((!)?\i\.\i(?:\|\||&&)(?=\(\i\.isDM.+?(\i)\.push)/, replace: (m, not, children) => not ? `${m}(Vencord.Api.ChatButtons._injectButtons(${children},arguments[0]),true)&&` diff --git a/src/plugins/_api/messageEvents.ts b/src/plugins/_api/messageEvents.ts index 97ed1746d..9dfc55e27 100644 --- a/src/plugins/_api/messageEvents.ts +++ b/src/plugins/_api/messageEvents.ts @@ -37,12 +37,9 @@ export default definePlugin({ { find: ".handleSendMessage,onResize", replacement: { - // props.chatInputType...then((function(isMessageValid)... var parsedMessage = b.c.parse(channel,... var replyOptions = f.g.getSendMessageOptionsForReply(pendingReply); - // Lookbehind: validateMessage)({openWarningPopout:..., type: i.props.chatInputType, content: t, stickers: r, ...}).then((function(isMessageValid) - match: /(\{openWarningPopout:.{0,100}type:this.props.chatInputType.+?\.then\()(\i=>\{.+?let (\i)=\i\.\i\.parse\((\i),.+?let (\i)=\i\.\i\.getSendMessageOptions\(\{.+?\}\);)(?<=\)\(({.+?})\)\.then.+?)/, - // props.chatInputType...then((async function(isMessageValid)... var replyOptions = f.g.getSendMessageOptionsForReply(pendingReply); if(await Vencord.api...) return { shoudClear:true, shouldRefocus:true }; - replace: (_, rest1, rest2, parsedMessage, channel, replyOptions, extra) => "" + - `${rest1}async ${rest2}` + + // https://regex101.com/r/hBlXpl/1 + match: /let (\i)=\i\.\i\.parse\((\i),.+?let (\i)=\i\.\i\.getSendMessageOptions\(\{.+?\}\);(?<=\)\(({.+?})\)\.then.+?)/, + replace: (m, parsedMessage, channel, replyOptions, extra) => m + `if(await Vencord.Api.MessageEvents._handlePreSend(${channel}.id,${parsedMessage},${extra},${replyOptions}))` + "return{shouldClear:false,shouldRefocus:true};" } @@ -52,8 +49,7 @@ export default definePlugin({ replacement: { match: /let\{id:\i}=(\i),{id:\i}=(\i);return \i\.useCallback\((\i)=>\{/, replace: (m, message, channel, event) => - // the message param is shadowed by the event param, so need to alias them - `const vcMsg=${message},vcChan=${channel};${m}Vencord.Api.MessageEvents._handleClick(vcMsg, vcChan, ${event});` + `const vcMsg=${message},vcChan=${channel};${m}Vencord.Api.MessageEvents._handleClick(vcMsg,vcChan,${event});` } } ] diff --git a/src/plugins/_core/settings.tsx b/src/plugins/_core/settings.tsx index 75fa91470..f48f38e03 100644 --- a/src/plugins/_core/settings.tsx +++ b/src/plugins/_core/settings.tsx @@ -65,6 +65,7 @@ export default definePlugin({ replace: (_, sectionTypes, commaOrSemi, elements, element) => `${commaOrSemi} $self.addSettings(${elements}, ${element}, ${sectionTypes}) ${commaOrSemi}` }, { + // FIXME(Bundler change related): Remove old compatiblity once enough time has passed match: /({(?=.+?function (\i).{0,160}(\i)=\i\.useMemo.{0,140}return \i\.useMemo\(\(\)=>\i\(\3).+?(?:function\(\){return |\(\)=>))\2/, replace: (_, rest, settingsHook) => `${rest}$self.wrapSettingsHook(${settingsHook})` } diff --git a/src/plugins/alwaysAnimate/index.ts b/src/plugins/alwaysAnimate/index.ts index fc528466f..a5297445b 100644 --- a/src/plugins/alwaysAnimate/index.ts +++ b/src/plugins/alwaysAnimate/index.ts @@ -43,8 +43,8 @@ export default definePlugin({ // Status emojis find: "#{intl::GUILD_OWNER}),children:", replacement: { - match: /(?<=\.activityEmoji,.+?animate:)\i/, - replace: "!0" + match: /(\.CUSTOM_STATUS.+?animate:)\i/, + replace: (_, rest) => `${rest}!0` } }, { diff --git a/src/plugins/betterFolders/FolderSideBar.tsx b/src/plugins/betterFolders/FolderSideBar.tsx index 53d24ed93..5203b14d2 100644 --- a/src/plugins/betterFolders/FolderSideBar.tsx +++ b/src/plugins/betterFolders/FolderSideBar.tsx @@ -17,14 +17,13 @@ */ import ErrorBoundary from "@components/ErrorBoundary"; -import { findByPropsLazy, findComponentByCodeLazy, findStoreLazy } from "@webpack"; -import { useStateFromStores } from "@webpack/common"; +import { findComponentByCodeLazy, findStoreLazy } from "@webpack"; +import { Animations, useStateFromStores } from "@webpack/common"; import type { CSSProperties } from "react"; import { ExpandedGuildFolderStore, settings } from "."; const ChannelRTCStore = findStoreLazy("ChannelRTCStore"); -const Animations = findByPropsLazy("a", "animated", "useTransition"); const GuildsBar = findComponentByCodeLazy('("guildsnav")'); export default ErrorBoundary.wrap(guildsBarProps => { diff --git a/src/plugins/clientTheme/index.tsx b/src/plugins/clientTheme/index.tsx index 4c1668aae..2dc7ccf6c 100644 --- a/src/plugins/clientTheme/index.tsx +++ b/src/plugins/clientTheme/index.tsx @@ -91,15 +91,12 @@ function ThemeSettings() { const settings = definePluginSettings({ color: { - description: "Color your Discord client theme will be based around. Light mode isn't supported", type: OptionType.COMPONENT, default: "313338", - component: () => + component: ThemeSettings }, resetColor: { - description: "Reset Theme Color", type: OptionType.COMPONENT, - default: "313338", component: () => ( + ) } }); diff --git a/src/plugins/messageTags/index.ts b/src/plugins/messageTags/index.ts index 5a5d03fdb..49e88c42d 100644 --- a/src/plugins/messageTags/index.ts +++ b/src/plugins/messageTags/index.ts @@ -89,7 +89,7 @@ export default definePlugin({ settings, async start() { - // TODO: Remove DataStore tags migration once enough time has passed + // TODO(OptionType.CUSTOM Related): Remove DataStore tags migration once enough time has passed const oldTags = await DataStore.get(DATA_KEY); if (oldTags != null) { // @ts-ignore diff --git a/src/plugins/noScreensharePreview/index.ts b/src/plugins/noScreensharePreview/index.ts deleted file mode 100644 index d4bb9c1eb..000000000 --- a/src/plugins/noScreensharePreview/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2022 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . -*/ - -import { getUserSettingLazy } from "@api/UserSettings"; -import { Devs } from "@utils/constants"; -import definePlugin from "@utils/types"; - -const DisableStreamPreviews = getUserSettingLazy("voiceAndVideo", "disableStreamPreviews")!; - -// @TODO: Delete this plugin in the future -export default definePlugin({ - name: "NoScreensharePreview", - description: "Disables screenshare previews from being sent.", - authors: [Devs.Nuckyz], - - start() { - if (!DisableStreamPreviews.getSetting()) { - DisableStreamPreviews.updateSetting(true); - } - }, - - stop() { - if (DisableStreamPreviews.getSetting()) { - DisableStreamPreviews.updateSetting(false); - } - } -}); diff --git a/src/plugins/notificationVolume/index.ts b/src/plugins/notificationVolume/index.ts index bc3c7539d..d320d76f1 100644 --- a/src/plugins/notificationVolume/index.ts +++ b/src/plugins/notificationVolume/index.ts @@ -25,9 +25,9 @@ export default definePlugin({ settings, patches: [ { - find: "_ensureAudio(){", + find: "ensureAudio(){", replacement: { - match: /(?=Math\.min\(\i\.\i\.getOutputVolume\(\)\/100)/, + match: /(?=Math\.min\(\i\.\i\.getOutputVolume\(\)\/100)/g, replace: "$self.settings.store.notificationVolume/100*" }, }, diff --git a/src/plugins/openInApp/index.ts b/src/plugins/openInApp/index.ts index e344f1458..1c90b5290 100644 --- a/src/plugins/openInApp/index.ts +++ b/src/plugins/openInApp/index.ts @@ -100,6 +100,7 @@ export default definePlugin({ replace: "true" }, { + // FIXME(Bundler change related): Remove old compatiblity once enough time has passed match: /(!)?\(0,\i\.isDesktop\)\(\)/, replace: (_, not) => not ? "false" : "true" } diff --git a/src/plugins/permissionFreeWill/index.ts b/src/plugins/permissionFreeWill/index.ts index 510d9cb3b..8a6135145 100644 --- a/src/plugins/permissionFreeWill/index.ts +++ b/src/plugins/permissionFreeWill/index.ts @@ -46,6 +46,7 @@ export default definePlugin({ find: "#{intl::ONBOARDING_CHANNEL_THRESHOLD_WARNING}", replacement: [ { + // FIXME(Bundler change related): Remove old compatiblity once enough time has passed match: /{(?:\i:(?:function\(\){return |\(\)=>)\i}?,?){2}}/, replace: m => m.replaceAll(canonicalizeMatch(/(function\(\){return |\(\)=>)\i/g), "$1()=>Promise.resolve(true)") } diff --git a/src/plugins/pinDms/data.ts b/src/plugins/pinDms/data.ts index 2f4a1156e..d689bd2af 100644 --- a/src/plugins/pinDms/data.ts +++ b/src/plugins/pinDms/data.ts @@ -155,7 +155,7 @@ export function moveChannel(channelId: string, direction: -1 | 1) { swapElementsInArray(category.channels, a, b); } -// TODO: Remove DataStore PinnedDms migration once enough time has passed +// TODO(OptionType.CUSTOM Related): Remove DataStore PinnedDms migration once enough time has passed async function migrateData() { if (Settings.plugins.PinDMs.dmSectioncollapsed != null) { settings.store.dmSectionCollapsed = Settings.plugins.PinDMs.dmSectioncollapsed; diff --git a/src/plugins/quickReply/index.ts b/src/plugins/quickReply/index.ts index 4a7060c59..f6ca5b459 100644 --- a/src/plugins/quickReply/index.ts +++ b/src/plugins/quickReply/index.ts @@ -196,7 +196,7 @@ function nextReply(isUp: boolean) { channel, message, shouldMention: shouldMention(message), - showMentionToggle: channel.isPrivate() && message.author.id !== meId, + showMentionToggle: !channel.isPrivate() && message.author.id !== meId, _isQuickReply: true }); ComponentDispatch.dispatchToLastSubscribed("TEXTAREA_FOCUS"); diff --git a/src/plugins/reviewDB/auth.tsx b/src/plugins/reviewDB/auth.tsx index 4cd81f2ea..8d9789dd7 100644 --- a/src/plugins/reviewDB/auth.tsx +++ b/src/plugins/reviewDB/auth.tsx @@ -7,15 +7,12 @@ import { DataStore } from "@api/index"; import { Logger } from "@utils/Logger"; import { openModal } from "@utils/modal"; -import { findByPropsLazy } from "@webpack"; -import { showToast, Toasts, UserStore } from "@webpack/common"; +import { OAuth2AuthorizeModal, showToast, Toasts, UserStore } from "@webpack/common"; import { ReviewDBAuth } from "./entities"; const DATA_STORE_KEY = "rdb-auth"; -const { OAuth2AuthorizeModal } = findByPropsLazy("OAuth2AuthorizeModal"); - export let Auth: ReviewDBAuth = {}; export async function initAuth() { diff --git a/src/plugins/reviewDB/settings.tsx b/src/plugins/reviewDB/settings.tsx index eeebd0aa1..2b58d080c 100644 --- a/src/plugins/reviewDB/settings.tsx +++ b/src/plugins/reviewDB/settings.tsx @@ -27,7 +27,6 @@ import { cl } from "./utils"; export const settings = definePluginSettings({ authorize: { type: OptionType.COMPONENT, - description: "Authorize with ReviewDB", component: () => ( diff --git a/src/plugins/showHiddenChannels/index.tsx b/src/plugins/showHiddenChannels/index.tsx index 382990d06..09291b825 100644 --- a/src/plugins/showHiddenChannels/index.tsx +++ b/src/plugins/showHiddenChannels/index.tsx @@ -108,6 +108,7 @@ export default definePlugin({ }, { // Prevent Discord from trying to connect to hidden voice channels + // FIXME(Bundler change related): Remove old compatiblity once enough time has passed match: /(?=(\|\||&&)\i\.\i\.selectVoiceChannel\((\i)\.id\))/, replace: (_, condition, channel) => condition === "||" ? `||$self.isHiddenChannel(${channel})` @@ -124,6 +125,7 @@ export default definePlugin({ { find: ".AUDIENCE),{isSubscriptionGated", replacement: { + // FIXME(Bundler change related): Remove old compatiblity once enough time has passed match: /(!)?(\i)\.isRoleSubscriptionTemplatePreviewChannel\(\)/, replace: (m, not, channel) => not ? `${m}&&!$self.isHiddenChannel(${channel})` @@ -177,6 +179,7 @@ export default definePlugin({ }, // Make voice channels also appear as muted if they are muted { + // FIXME(Bundler change related): Remove old compatiblity once enough time has passed match: /(?<=\.wrapper:\i\.notInteractive,)(.+?)(if\()?(\i)(?:\)return |\?)(\i\.MUTED)/, replace: (_, otherClasses, isIf, isMuted, mutedClassExpression) => isIf ? `${isMuted}?${mutedClassExpression}:"",${otherClasses}if(${isMuted})return ""` @@ -190,6 +193,7 @@ export default definePlugin({ { // Make muted channels also appear as unread if hide unreads is false, using the HiddenIconWithMutedStyle and the channel is hidden predicate: () => settings.store.hideUnreads === false && settings.store.showMode === ShowMode.HiddenIconWithMutedStyle, + // FIXME(Bundler change related): Remove old compatiblity once enough time has passed match: /(?<=\.LOCKED(?:;if\(|:))(?<={channel:(\i).+?)/, replace: (_, channel) => `!$self.isHiddenChannel(${channel})&&` }, diff --git a/src/plugins/textReplace/index.tsx b/src/plugins/textReplace/index.tsx index 3d1e891d1..d5d6f4dc8 100644 --- a/src/plugins/textReplace/index.tsx +++ b/src/plugins/textReplace/index.tsx @@ -45,7 +45,6 @@ const makeEmptyRuleArray = () => [makeEmptyRule()]; const settings = definePluginSettings({ replace: { type: OptionType.COMPONENT, - description: "", component: () => { const { stringRules, regexRules } = settings.use(["stringRules", "regexRules"]); @@ -245,7 +244,7 @@ export default definePlugin({ }, async start() { - // TODO: Remove DataStore rules migrations once enough time has passed + // TODO(OptionType.CUSTOM Related): Remove DataStore rules migrations once enough time has passed const oldStringRules = await DataStore.get(STRING_RULES_KEY); if (oldStringRules != null) { settings.store.stringRules = oldStringRules; diff --git a/src/plugins/typingIndicator/index.tsx b/src/plugins/typingIndicator/index.tsx index 642dcc29f..e6903bcde 100644 --- a/src/plugins/typingIndicator/index.tsx +++ b/src/plugins/typingIndicator/index.tsx @@ -100,16 +100,24 @@ function TypingIndicator({ channelId, guildId }: { channelId: string; guildId: s {props => (
{((settings.store.indicatorMode & IndicatorMode.Avatars) === IndicatorMode.Avatars) && ( - UserStore.getUser(id))} - guildId={guildId} - renderIcon={false} - max={3} - showDefaultAvatarsForNullUsers - showUserPopout - size={16} - className="vc-typing-indicator-avatars" - /> +
{ + e.stopPropagation(); + e.preventDefault(); + }} + onKeyPress={e => e.stopPropagation()} + > + UserStore.getUser(id))} + guildId={guildId} + renderIcon={false} + max={3} + showDefaultAvatarsForNullUsers + showUserPopout + size={16} + className="vc-typing-indicator-avatars" + /> +
)} {((settings.store.indicatorMode & IndicatorMode.Dots) === IndicatorMode.Dots) && (
diff --git a/src/plugins/webContextMenus.web/index.ts b/src/plugins/webContextMenus.web/index.ts index 661238052..0af47ded8 100644 --- a/src/plugins/webContextMenus.web/index.ts +++ b/src/plugins/webContextMenus.web/index.ts @@ -20,10 +20,13 @@ import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; import { saveFile } from "@utils/web"; -import { findByPropsLazy } from "@webpack"; +import { filters, mapMangledModuleLazy } from "@webpack"; import { Clipboard, ComponentDispatch } from "@webpack/common"; -const ctxMenuCallbacks = findByPropsLazy("contextMenuCallbackNative"); +const ctxMenuCallbacks = mapMangledModuleLazy('.tagName)==="TEXTAREA"||', { + contextMenuCallbackWeb: filters.byCode('.tagName)==="INPUT"||'), + contextMenuCallbackNative: filters.byCode('.tagName)==="TEXTAREA"||') +}); async function fetchImage(url: string) { const res = await fetch(url); diff --git a/src/plugins/whoReacted/index.tsx b/src/plugins/whoReacted/index.tsx index 803cc7156..aea57fef2 100644 --- a/src/plugins/whoReacted/index.tsx +++ b/src/plugins/whoReacted/index.tsx @@ -93,7 +93,7 @@ function makeRenderMoreUsers(users: User[]) { }; } -function handleClickAvatar(event: React.MouseEvent) { +function handleClickAvatar(event: React.UIEvent) { event.stopPropagation(); } @@ -165,7 +165,7 @@ export default definePlugin({
-
+
; } -const Modals: Modals = mapMangledModuleLazy(':"thin")', { +export const Modals: Modals = mapMangledModuleLazy(':"thin")', { ModalRoot: filters.componentByCode('.MODAL,"aria-labelledby":'), ModalHeader: filters.componentByCode(",id:"), ModalContent: filters.componentByCode(".content,"), diff --git a/src/utils/types.ts b/src/utils/types.ts index 54de59e34..8f0ec3860 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -198,15 +198,16 @@ export type SettingsChecks = { (IsDisabled> & IsValid, DefinedSettings>); }; -export type PluginSettingDef = (PluginSettingCustomDef & Pick) | (( - | PluginSettingStringDef - | PluginSettingNumberDef - | PluginSettingBooleanDef - | PluginSettingSelectDef - | PluginSettingSliderDef - | PluginSettingComponentDef - | PluginSettingBigIntDef -) & PluginSettingCommon); +export type PluginSettingDef = + (PluginSettingCustomDef & Pick) | + (PluginSettingComponentDef & Omit) | (( + | PluginSettingStringDef + | PluginSettingNumberDef + | PluginSettingBooleanDef + | PluginSettingSelectDef + | PluginSettingSliderDef + | PluginSettingBigIntDef + ) & PluginSettingCommon); export interface PluginSettingCommon { description: string; @@ -226,12 +227,14 @@ export interface PluginSettingCommon { */ target?: "WEB" | "DESKTOP" | "BOTH"; } + interface IsDisabled { /** * Checks if this setting should be disabled */ disabled?(this: D): boolean; } + interface IsValid { /** * Prevents the user from saving settings if this is false or a string @@ -320,7 +323,7 @@ type PluginSettingType = O extends PluginSettingStri O extends PluginSettingBooleanDef ? boolean : O extends PluginSettingSelectDef ? O["options"][number]["value"] : O extends PluginSettingSliderDef ? number : - O extends PluginSettingComponentDef ? any : + O extends PluginSettingComponentDef ? O extends { default: infer Default; } ? Default : any : O extends PluginSettingCustomDef ? O extends { default: infer Default; } ? Default : any : never; @@ -382,7 +385,7 @@ export type PluginOptionNumber = (PluginSettingNumberDef | PluginSettingBigIntDe export type PluginOptionBoolean = PluginSettingBooleanDef & PluginSettingCommon & IsDisabled & IsValid; export type PluginOptionSelect = PluginSettingSelectDef & PluginSettingCommon & IsDisabled & IsValid; export type PluginOptionSlider = PluginSettingSliderDef & PluginSettingCommon & IsDisabled & IsValid; -export type PluginOptionComponent = PluginSettingComponentDef & PluginSettingCommon; +export type PluginOptionComponent = PluginSettingComponentDef & Omit; export type PluginOptionCustom = PluginSettingCustomDef & Pick; export type PluginNative any>> = { diff --git a/src/webpack/common/components.ts b/src/webpack/common/components.ts index 7f5c86498..dfe00e337 100644 --- a/src/webpack/common/components.ts +++ b/src/webpack/common/components.ts @@ -95,3 +95,8 @@ export const MaskedLink = waitForComponent("MaskedLink", filters.c export const Timestamp = waitForComponent("Timestamp", filters.componentByCode("#{intl::MESSAGE_EDITED_TIMESTAMP_A11Y_LABEL}")); export const Flex = waitForComponent("Flex", ["Justify", "Align", "Wrap"]); export const OAuth2AuthorizeModal = waitForComponent("OAuth2AuthorizeModal", filters.componentByCode(".authorize),children:", ".contentBackground")); + +export const Animations = mapMangledModuleLazy(".assign({colorNames:", { + Transition: filters.componentByCode('["items","children"]', ",null,"), + animated: filters.byProps("div", "text") +}); diff --git a/src/webpack/common/menu.ts b/src/webpack/common/menu.ts index b4df183b0..c45b69964 100644 --- a/src/webpack/common/menu.ts +++ b/src/webpack/common/menu.ts @@ -36,6 +36,7 @@ waitFor(m => m.name === "MenuCheckboxItem", (_, id) => { waitFor(filters.componentByCode('path:["empty"]'), m => Menu.Menu = m); waitFor(filters.componentByCode("sliderContainer", "slider", "handleSize:16", "=100"), m => Menu.MenuSliderControl = m); +waitFor(filters.componentByCode('role:"searchbox', "top:2", "query:"), m => Menu.MenuSearchControl = m); export const ContextMenuApi: t.ContextMenuApi = mapMangledModuleLazy('type:"CONTEXT_MENU_OPEN', { closeContextMenu: filters.byCode("CONTEXT_MENU_CLOSE"), diff --git a/src/webpack/patchWebpack.ts b/src/webpack/patchWebpack.ts index 0fddf472f..1122d55bb 100644 --- a/src/webpack/patchWebpack.ts +++ b/src/webpack/patchWebpack.ts @@ -24,7 +24,7 @@ import { WebpackInstance } from "discord-types/other"; import { traceFunction } from "../debug/Tracer"; import { patches } from "../plugins"; -import { _initWebpack, beforeInitListeners, factoryListeners, moduleListeners, subscriptions, wreq } from "."; +import { _initWebpack, _shouldIgnoreModule, beforeInitListeners, factoryListeners, moduleListeners, subscriptions, wreq } from "."; const logger = new Logger("WebpackInterceptor", "#8caaee"); @@ -173,35 +173,9 @@ function patchFactories(factories: Record { const filter = filters.byCode(...code); return m => { - if (filter(m)) return true; - if (!m.$$typeof) return false; - if (m.type) - return m.type.render - ? filter(m.type.render) // memo + forwardRef - : filter(m.type); // memo - if (m.render) return filter(m.render); // forwardRef + let inner = m; + + while (inner != null) { + if (filter(inner)) return true; + else if (!inner.$$typeof) return false; + else if (inner.type) inner = inner.type; // memos + else if (inner.render) inner = inner.render; // forwardRefs + else return false; + } + return false; }; } @@ -95,6 +98,38 @@ export function _initWebpack(webpackRequire: WebpackInstance) { cache = webpackRequire.c; } +// Credits to Zerebos for implementing this in BD, thus giving the idea for us to implement it too +const TypedArray = Object.getPrototypeOf(Int8Array); + +function _shouldIgnoreValue(value: any) { + if (value == null) return true; + if (value === window) return true; + if (value === document || value === document.documentElement) return true; + if (value[Symbol.toStringTag] === "DOMTokenList") return true; + if (value instanceof TypedArray) return true; + + return false; +} + +export function _shouldIgnoreModule(exports: any) { + if (_shouldIgnoreValue(exports)) { + return true; + } + + if (typeof exports !== "object") { + return false; + } + + let allNonEnumerable = true; + for (const exportKey in exports) { + if (!_shouldIgnoreValue(exports[exportKey])) { + allNonEnumerable = false; + } + } + + return allNonEnumerable; +} + let devToolsOpen = false; if (IS_DEV && IS_DISCORD_DESKTOP) { // At this point in time, DiscordNative has not been exposed yet, so setImmediate is needed @@ -121,7 +156,7 @@ export const find = traceFunction("find", function find(filter: FilterFn, { isIn for (const key in cache) { const mod = cache[key]; - if (!mod.loaded || !mod?.exports) continue; + if (!mod?.loaded || mod.exports == null) continue; if (filter(mod.exports)) { return isWaitFor ? [mod.exports, key] : mod.exports; @@ -129,11 +164,6 @@ export const find = traceFunction("find", function find(filter: FilterFn, { isIn if (typeof mod.exports !== "object") continue; - if (mod.exports.default && filter(mod.exports.default)) { - const found = mod.exports.default; - return isWaitFor ? [found, key] : found; - } - for (const nestedMod in mod.exports) { const nested = mod.exports[nestedMod]; if (nested && filter(nested)) { @@ -156,16 +186,15 @@ export function findAll(filter: FilterFn) { const ret = [] as any[]; for (const key in cache) { const mod = cache[key]; - if (!mod.loaded || !mod?.exports) continue; + if (!mod?.loaded || mod.exports == null) continue; if (filter(mod.exports)) ret.push(mod.exports); - else if (typeof mod.exports !== "object") + + if (typeof mod.exports !== "object") continue; - if (mod.exports.default && filter(mod.exports.default)) - ret.push(mod.exports.default); - else for (const nestedMod in mod.exports) { + for (const nestedMod in mod.exports) { const nested = mod.exports[nestedMod]; if (nested && filter(nested)) ret.push(nested); } @@ -204,7 +233,7 @@ export const findBulk = traceFunction("findBulk", function findBulk(...filterFns outer: for (const key in cache) { const mod = cache[key]; - if (!mod.loaded || !mod?.exports) continue; + if (!mod?.loaded || mod.exports == null) continue; for (let j = 0; j < length; j++) { const filter = filters[j]; @@ -221,13 +250,6 @@ export const findBulk = traceFunction("findBulk", function findBulk(...filterFns if (typeof mod.exports !== "object") continue; - if (mod.exports.default && filter(mod.exports.default)) { - results[j] = mod.exports.default; - filters[j] = undefined; - if (++found === length) break outer; - break; - } - for (const nestedMod in mod.exports) { const nested = mod.exports[nestedMod]; if (nested && filter(nested)) {