Equicord/src/api/GifPickerContextMenu.tsx
Jakub Bednarski 046281c768
feat(plugin): add gifMaker v2 (#1161)
* feat(plugin): add gifMaker v2

* fix(gifMaker): address code review

* fix(gifMaker): remove unused fps useEffect

* fix(gifMaker): address code review p2

* fix(gifMaker): address code review - error boundary, blob release, fix imports and style

* perf(gifMaker): use worker to offload gif creation task, import gifenc as esm module

* [autofix.ci] apply automated fixes

* fix(gifMaker): lint errors

* fix(gifMaker): detect existing color palette

* worker worker worker worker worker

* api and some fixes

* fix thororen fix

* fix

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: thororen1234 <78185467+thororen1234@users.noreply.github.com>
2026-06-15 20:30:30 -04:00

68 lines
2.2 KiB
TypeScript

/*
* Vencord, a Discord client mod
* Copyright (c) 2025 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { Logger } from "@utils/Logger";
import { ContextMenuApi, FluxDispatcher, Menu, React } from "@webpack/common";
import type { ReactNode } from "react";
const logger = new Logger("GifPickerContextMenu");
export type GifPickerContextMenuItemFactory = (instance: any, e: React.MouseEvent) => ReactNode | void;
interface HandlerEntry {
render: GifPickerContextMenuItemFactory;
priority: number;
}
const handlers = new Map<string, HandlerEntry>();
/**
* Register a context menu item factory for GIF picker items.
* @param id Unique ID, typically the plugin name.
* @param render Function that receives the GIF item and returns ReactNode(s) to inject.
* @param priority Lower numbers appear first. Defaults to 0.
*/
export function addGifPickerContextMenuPatch(id: string, render: GifPickerContextMenuItemFactory, priority = 0) {
handlers.set(id, { render, priority });
}
/**
* Remove a previously registered context menu item factory.
* @param id Unique ID used when registering.
*/
export function removeGifPickerContextMenuPatch(id: string) {
handlers.delete(id);
}
/** @internal Called by ExtraContextMenusAPI to render the merged context menu. */
export function _openGifPickerContextMenu(e: React.MouseEvent, instance) {
if (!handlers.size) return;
const items: React.ReactNode[] = [];
for (const [id, { render }] of Array.from(handlers).sort(([, a], [, b]) => a.priority - b.priority)) {
try {
const node = render(instance, e);
if (node) items.push(node);
} catch (err) {
logger.error(`Failed to render context menu for ${id}`, err);
}
}
if (!items.length) return;
ContextMenuApi.openContextMenu(e, () => <GifPickerContextMenuRoot items={items} />);
}
function GifPickerContextMenuRoot({ items }: { items: React.ReactNode[]; }) {
return (
<Menu.Menu
navId="gif-picker-context"
onClose={() => FluxDispatcher.dispatch({ type: "CONTEXT_MENU_CLOSE" })}
aria-label="GIF Options"
>
{items}
</Menu.Menu>
);
}