Equicord/src/api/ChatButtons.tsx
thororen1234 e907ea3236
Reapply "Fix Broken Patches"
This reverts commit 5050e18c4e.
2025-11-11 09:47:53 -05:00

137 lines
4.5 KiB
TypeScript

/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import "./ChatButton.css";
import ErrorBoundary from "@components/ErrorBoundary";
import { Logger } from "@utils/Logger";
import { classes } from "@utils/misc";
import { Channel } from "@vencord/discord-types";
import { waitFor } from "@webpack";
import { ButtonWrapperClasses, Clickable, Tooltip } from "@webpack/common";
import { HTMLProps, JSX, MouseEventHandler, ReactNode } from "react";
let ChannelTextAreaClasses: Record<"button" | "buttonContainer", string>;
waitFor(["buttonContainer", "channelTextArea"], m => ChannelTextAreaClasses = m);
export interface ChatBarProps {
channel: Channel;
disabled: boolean;
isEmpty: boolean;
type: {
analyticsName: string;
attachments: boolean;
autocomplete: {
addReactionShortcut: boolean,
forceChatLayer: boolean,
reactions: boolean;
},
commands: {
enabled: boolean;
},
drafts: {
type: number,
commandType: number,
autoSave: boolean;
},
emojis: {
button: boolean;
},
gifs: {
button: boolean,
allowSending: boolean;
},
gifts: {
button: boolean;
},
permissions: {
requireSendMessages: boolean;
},
showThreadPromptOnReply: boolean,
stickers: {
button: boolean,
allowSending: boolean,
autoSuggest: boolean;
},
users: {
allowMentioning: boolean;
},
submit: {
button: boolean,
ignorePreference: boolean,
disableEnterToSubmit: boolean,
clearOnSubmit: boolean,
useDisabledStylesOnSubmit: boolean;
},
uploadLongMessages: boolean,
upsellLongMessages: {
iconOnly: boolean;
},
showCharacterCount: boolean,
sedReplace: boolean;
};
}
export type ChatBarButtonFactory = (props: ChatBarProps & { isMainChat: boolean; }) => JSX.Element | null;
const buttonFactories = new Map<string, ChatBarButtonFactory>();
const logger = new Logger("ChatButtons");
export function _injectButtons(buttons: { key: string, node: ReactNode; }[], order: Record<string, number | null>, props: ChatBarProps) {
if (props.disabled) return;
let anchorIndex = -100;
let currentOrder = anchorIndex - 1;
for (const [key, Button] of buttonFactories) {
order[key] = anchorIndex;
order.submit && (order.submit = ++currentOrder);
anchorIndex = currentOrder + 1;
buttons.push({
key,
node: <ErrorBoundary noop key={key} onError={e => logger.error(`Failed to render ${key}`, e.error)}>
<Button {...props} isMainChat={props.type.analyticsName === "normal"} />
</ErrorBoundary>
});
}
}
export const addChatBarButton = (id: string, button: ChatBarButtonFactory) => buttonFactories.set(id, button);
export const removeChatBarButton = (id: string) => buttonFactories.delete(id);
export interface ChatBarButtonProps {
children: ReactNode;
tooltip: string;
onClick: MouseEventHandler;
onContextMenu?: MouseEventHandler;
onAuxClick?: MouseEventHandler;
buttonProps?: Omit<HTMLProps<HTMLDivElement>, "size" | "onClick" | "onContextMenu" | "onAuxClick">;
}
export const ChatBarButton = ErrorBoundary.wrap((props: ChatBarButtonProps) => {
return (
<Tooltip text={props.tooltip}>
{({ onMouseEnter, onMouseLeave }) => (
<div className={`expression-picker-chat-input-button ${ChannelTextAreaClasses?.buttonContainer ?? ""} vc-chatbar-button`}>
<Clickable
aria-label={props.tooltip}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
className={classes(ButtonWrapperClasses?.button, ChannelTextAreaClasses?.button)}
onClick={props.onClick}
onContextMenu={props.onContextMenu}
onAuxClick={props.onAuxClick}
{...props.buttonProps}
>
<div className={ButtonWrapperClasses?.buttonWrapper}>
{props.children}
</div>
</Clickable>
</div>
)}
</Tooltip>
);
}, { noop: true });