diff --git a/src/components/VencordSettings/PatchHelperTab.tsx b/src/components/VencordSettings/PatchHelperTab.tsx index f930a40d..55822069 100644 --- a/src/components/VencordSettings/PatchHelperTab.tsx +++ b/src/components/VencordSettings/PatchHelperTab.tsx @@ -18,12 +18,13 @@ import { CodeBlock } from "@components/CodeBlock"; import { debounce } from "@shared/debounce"; +import { copyToClipboard } from "@utils/clipboard"; import { Margins } from "@utils/margins"; import { canonicalizeMatch, canonicalizeReplace } from "@utils/patches"; import { makeCodeblock } from "@utils/text"; import { Patch, ReplaceFn } from "@utils/types"; import { search } from "@webpack"; -import { Button, Clipboard, Forms, Parser, React, Switch, TextArea, TextInput } from "@webpack/common"; +import { Button, Forms, Parser, React, Switch, TextArea, TextInput } from "@webpack/common"; import { SettingsTab, wrapTab } from "./shared"; @@ -381,8 +382,8 @@ function PatchHelper() { <> Code - - + + )} diff --git a/src/plugins/_api/memberListDecorators/index.tsx b/src/plugins/_api/memberListDecorators/index.tsx index 39c82a1e..365c21f3 100644 --- a/src/plugins/_api/memberListDecorators/index.tsx +++ b/src/plugins/_api/memberListDecorators/index.tsx @@ -35,9 +35,10 @@ export default definePlugin({ { match: /let\{[^}]*lostPermissionTooltipText:\i[^}]*\}=(\i),/, replace: "$&vencordProps=$1," - }, { - match: /#{intl::GUILD_OWNER}(?=.+?decorators:(\i)\(\)).+?\1=?\(\)=>.+?children:\[/, - replace: "$&(typeof vencordProps=='undefined'?null:Vencord.Api.MemberListDecorators.__getDecorators(vencordProps))," + }, + { + match: /children:\[(?=.{0,300},lostPermissionTooltipText:)/, + replace: "children:[(typeof vencordProps!=='undefined'&&Vencord.Api.MemberListDecorators.__getDecorators(vencordProps))," } ] }, diff --git a/src/plugins/betterRoleContext/index.tsx b/src/plugins/betterRoleContext/index.tsx index afef6390..a9bab1a7 100644 --- a/src/plugins/betterRoleContext/index.tsx +++ b/src/plugins/betterRoleContext/index.tsx @@ -7,11 +7,12 @@ import { definePluginSettings } from "@api/Settings"; import { getUserSettingLazy } from "@api/UserSettings"; import { ImageIcon } from "@components/Icons"; +import { copyToClipboard } from "@utils/clipboard"; import { Devs } from "@utils/constants"; import { getCurrentGuild, openImageModal } from "@utils/discord"; import definePlugin, { OptionType } from "@utils/types"; import { findByPropsLazy } from "@webpack"; -import { Clipboard, GuildStore, Menu, PermissionStore } from "@webpack/common"; +import { GuildStore, Menu, PermissionStore } from "@webpack/common"; const GuildSettingsActions = findByPropsLazy("open", "selectRole", "updateGuild"); @@ -87,7 +88,7 @@ export default definePlugin({ Clipboard.copy(role.colorString!)} + action={() => copyToClipboard(role.colorString!)} icon={AppearanceIcon} /> ); diff --git a/src/plugins/betterRoleDot/index.ts b/src/plugins/betterRoleDot/index.ts index 3a8a1456..bdafe02c 100644 --- a/src/plugins/betterRoleDot/index.ts +++ b/src/plugins/betterRoleDot/index.ts @@ -18,8 +18,8 @@ import { Settings } from "@api/Settings"; import { Devs } from "@utils/constants"; +import { copyWithToast } from "@utils/misc"; import definePlugin, { OptionType } from "@utils/types"; -import { Clipboard, Toasts } from "@webpack/common"; export default definePlugin({ name: "BetterRoleDot", @@ -84,15 +84,6 @@ export default definePlugin({ }, copyToClipBoard(color: string) { - Clipboard.copy(color); - Toasts.show({ - message: "Copied to Clipboard!", - type: Toasts.Type.SUCCESS, - id: Toasts.genId(), - options: { - duration: 1000, - position: Toasts.Position.BOTTOM - } - }); + copyWithToast(color); }, }); diff --git a/src/plugins/copyUserURLs/index.tsx b/src/plugins/copyUserURLs/index.tsx index 7af8502d..9e15cc82 100644 --- a/src/plugins/copyUserURLs/index.tsx +++ b/src/plugins/copyUserURLs/index.tsx @@ -18,9 +18,10 @@ import { NavContextMenuPatchCallback } from "@api/ContextMenu"; import { LinkIcon } from "@components/Icons"; +import { copyToClipboard } from "@utils/clipboard"; import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; -import { Clipboard, Menu } from "@webpack/common"; +import { Menu } from "@webpack/common"; import type { Channel, User } from "discord-types/general"; interface UserContextProps { @@ -36,7 +37,7 @@ const UserContextMenuPatch: NavContextMenuPatchCallback = (children, { user }: U Clipboard.copy(``)} + action={() => copyToClipboard(``)} icon={LinkIcon} /> ); diff --git a/src/plugins/decor/ui/components/DecorationContextMenu.tsx b/src/plugins/decor/ui/components/DecorationContextMenu.tsx index 7c1542f6..db3f0090 100644 --- a/src/plugins/decor/ui/components/DecorationContextMenu.tsx +++ b/src/plugins/decor/ui/components/DecorationContextMenu.tsx @@ -5,7 +5,8 @@ */ import { CopyIcon, DeleteIcon } from "@components/Icons"; -import { Alerts, Clipboard, ContextMenuApi, Menu, UserStore } from "@webpack/common"; +import { copyToClipboard } from "@utils/clipboard"; +import { Alerts, ContextMenuApi, Menu, UserStore } from "@webpack/common"; import { Decoration } from "../../lib/api"; import { useCurrentUserDecorationsStore } from "../../lib/stores/CurrentUserDecorationsStore"; @@ -23,7 +24,7 @@ export default function DecorationContextMenu({ decoration }: { decoration: Deco id={cl("decoration-context-menu-copy-hash")} label="Copy Decoration Hash" icon={CopyIcon} - action={() => Clipboard.copy(decoration.hash)} + action={() => copyToClipboard(decoration.hash)} /> {decoration.authorId === UserStore.getCurrentUser().id && `${rest1}ircColor=$self.calculateNameColorForListContext(arguments[0]),${rest2}color:ircColor` + match: /(?<=roleName:\i,)color:/, + replace: "color:$self.calculateNameColorForListContext(arguments[0]),originalColor:" }, predicate: () => settings.store.memberListColors } diff --git a/src/plugins/permissionsViewer/components/RolesAndUsersPermissions.tsx b/src/plugins/permissionsViewer/components/RolesAndUsersPermissions.tsx index 02662fe9..ed620d7f 100644 --- a/src/plugins/permissionsViewer/components/RolesAndUsersPermissions.tsx +++ b/src/plugins/permissionsViewer/components/RolesAndUsersPermissions.tsx @@ -19,10 +19,11 @@ import ErrorBoundary from "@components/ErrorBoundary"; import { Flex } from "@components/Flex"; import { InfoIcon, OwnerCrownIcon } from "@components/Icons"; +import { copyToClipboard } from "@utils/clipboard"; import { getIntlMessage, getUniqueUsername } from "@utils/discord"; import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal"; import { findByCodeLazy } from "@webpack"; -import { Clipboard, ContextMenuApi, FluxDispatcher, GuildMemberStore, GuildStore, i18n, Menu, PermissionsBits, ScrollerThin, Text, Tooltip, useEffect, useMemo, UserStore, useState, useStateFromStores } from "@webpack/common"; +import { ContextMenuApi, FluxDispatcher, GuildMemberStore, GuildStore, i18n, Menu, PermissionsBits, ScrollerThin, Text, Tooltip, useEffect, useMemo, UserStore, useState, useStateFromStores } from "@webpack/common"; import { UnicodeEmoji } from "@webpack/types"; import type { Guild, Role, User } from "discord-types/general"; @@ -228,7 +229,7 @@ function RoleContextMenu({ guild, roleId, onClose }: { guild: Guild; roleId: str id={cl("copy-role-id")} label={getIntlMessage("COPY_ID_ROLE")} action={() => { - Clipboard.copy(roleId); + copyToClipboard(roleId); }} /> @@ -269,7 +270,7 @@ function UserContextMenu({ userId }: { userId: string; }) { id={cl("copy-user-id")} label={getIntlMessage("COPY_ID_USER")} action={() => { - Clipboard.copy(userId); + copyToClipboard(userId); }} /> diff --git a/src/plugins/shikiCodeblocks.desktop/components/ButtonRow.tsx b/src/plugins/shikiCodeblocks.desktop/components/ButtonRow.tsx index 6f0690d9..408de154 100644 --- a/src/plugins/shikiCodeblocks.desktop/components/ButtonRow.tsx +++ b/src/plugins/shikiCodeblocks.desktop/components/ButtonRow.tsx @@ -16,9 +16,6 @@ * along with this program. If not, see . */ -import { Clipboard } from "@webpack/common"; -import { JSX } from "react"; - import { cl } from "../utils/misc"; import { CopyButton } from "./CopyButton"; @@ -28,20 +25,14 @@ export interface ButtonRowProps { } export function ButtonRow({ content, theme }: ButtonRowProps) { - const buttons: JSX.Element[] = []; - - if (Clipboard.SUPPORTS_COPY) { - buttons.push( - - ); - } - - return
{buttons}
; + return
+ +
; } diff --git a/src/plugins/shikiCodeblocks.desktop/hooks/useCopyCooldown.ts b/src/plugins/shikiCodeblocks.desktop/hooks/useCopyCooldown.ts index 414500bd..d3f35fb2 100644 --- a/src/plugins/shikiCodeblocks.desktop/hooks/useCopyCooldown.ts +++ b/src/plugins/shikiCodeblocks.desktop/hooks/useCopyCooldown.ts @@ -16,13 +16,14 @@ * along with this program. If not, see . */ -import { Clipboard, React } from "@webpack/common"; +import { copyToClipboard } from "@utils/clipboard"; +import { React } from "@webpack/common"; export function useCopyCooldown(cooldown: number) { const [copyCooldown, setCopyCooldown] = React.useState(false); function copy(text: string) { - Clipboard.copy(text); + copyToClipboard(text); setCopyCooldown(true); setTimeout(() => { diff --git a/src/plugins/shikiCodeblocks.desktop/previewExample.tsx b/src/plugins/shikiCodeblocks.desktop/previewExample.tsx index 508153b4..db7edcf0 100644 --- a/src/plugins/shikiCodeblocks.desktop/previewExample.tsx +++ b/src/plugins/shikiCodeblocks.desktop/previewExample.tsx @@ -2,7 +2,7 @@ import React from "react"; const handleClick = async () => - console.log((await import("@webpack/common")).Clipboard.copy("\u200b")); + console.log((await import("@utils/clipboard")).copyToClipboard("\u200b")); export const Example: React.FC<{ real: boolean, diff --git a/src/plugins/webContextMenus.web/index.ts b/src/plugins/webContextMenus.web/index.ts index 07eb4a3e..a0f84dd6 100644 --- a/src/plugins/webContextMenus.web/index.ts +++ b/src/plugins/webContextMenus.web/index.ts @@ -17,11 +17,12 @@ */ import { definePluginSettings } from "@api/Settings"; +import { copyToClipboard } from "@utils/clipboard"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; import { saveFile } from "@utils/web"; import { filters, mapMangledModuleLazy } from "@webpack"; -import { Clipboard, ComponentDispatch } from "@webpack/common"; +import { ComponentDispatch } from "@webpack/common"; const ctxMenuCallbacks = mapMangledModuleLazy('.tagName)==="TEXTAREA"||', { contextMenuCallbackWeb: filters.byCode('.tagName)==="INPUT"||'), @@ -114,7 +115,7 @@ export default definePlugin({ // Fix silly Discord calling the non web support copy { match: /\i\.\i\.copy/, - replace: "Vencord.Webpack.Common.Clipboard.copy" + replace: "Vencord.Util.copyToClipboard" } ] }, @@ -223,7 +224,7 @@ export default definePlugin({ }, { match: /\i\.\i\.copy(?=\(\i)/, - replace: "Vencord.Webpack.Common.Clipboard.copy" + replace: "Vencord.Util.copyToClipboard" } ], all: true, @@ -288,7 +289,7 @@ export default definePlugin({ const selection = document.getSelection(); if (!selection) return; - Clipboard.copy(selection.toString()); + copyToClipboard(selection.toString()); }, cut() { diff --git a/src/utils/clipboard.ts b/src/utils/clipboard.ts new file mode 100644 index 00000000..c098a549 --- /dev/null +++ b/src/utils/clipboard.ts @@ -0,0 +1,9 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2025 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +export function copyToClipboard(text: string): Promise { + return IS_DISCORD_DESKTOP ? DiscordNative.clipboard.copy(text) : navigator.clipboard.writeText(text); +} diff --git a/src/utils/index.ts b/src/utils/index.ts index ed347fdc..70ac9d42 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -19,6 +19,7 @@ export * from "../shared/debounce"; export * from "../shared/onceDefined"; export * from "./ChangeList"; +export * from "./clipboard"; export * from "./constants"; export * from "./discord"; export * from "./guards"; diff --git a/src/utils/misc.ts b/src/utils/misc.ts index adca15d3..7f9f6e59 100644 --- a/src/utils/misc.ts +++ b/src/utils/misc.ts @@ -16,8 +16,9 @@ * along with this program. If not, see . */ -import { Clipboard, Toasts } from "@webpack/common"; +import { Toasts } from "@webpack/common"; +import { copyToClipboard } from "./clipboard"; import { DevsById } from "./constants"; /** @@ -35,12 +36,8 @@ export function sleep(ms: number): Promise { return new Promise(r => setTimeout(r, ms)); } -export function copyWithToast(text: string, toastMessage = "Copied to clipboard!") { - if (Clipboard.SUPPORTS_COPY) { - Clipboard.copy(text); - } else { - toastMessage = "Your browser does not support copying to clipboard"; - } +export async function copyWithToast(text: string, toastMessage = "Copied to clipboard!") { + await copyToClipboard(text); Toasts.show({ message: toastMessage, id: Toasts.genId(), diff --git a/src/webpack/common/utils.ts b/src/webpack/common/utils.ts index f5535b19..0396f0f3 100644 --- a/src/webpack/common/utils.ts +++ b/src/webpack/common/utils.ts @@ -149,11 +149,6 @@ export const ApplicationAssetUtils = mapMangledModuleLazy("getAssetImage: size m getAssets: filters.byCode(".assets") }); -export const Clipboard: t.Clipboard = mapMangledModuleLazy('queryCommandEnabled("copy")', { - copy: filters.byCode(".copy("), - SUPPORTS_COPY: e => typeof e === "boolean" -}); - export const NavigationRouter: t.NavigationRouter = mapMangledModuleLazy("Transitioning to ", { transitionTo: filters.byCode("transitionTo -"), transitionToGuild: filters.byCode("transitionToGuild -"),