this repo has no description
1import { InternalItem, Menu, MenuElement } from "@moonlight-mod/types/coreExtensions/contextMenu";
2import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
3import parser from "@moonlight-mod/wp/contextMenu_evilMenu";
4
5// NOTE: We originally had item as a function that returned this, but it didn't
6// quite know how to work out the type and thought it was a JSX element (it
7// *technically* was). This has less type safety, but a @ts-expect-error has
8// zero, so it's better than nothing.
9type ReturnType = MenuElement | MenuElement[];
10
11type Patch = {
12 navId: string;
13 item: React.FC<any>;
14 anchor: string | RegExp;
15 before: boolean;
16};
17
18function addItem<T = any>(navId: string, item: React.FC<T>, anchor: string | RegExp, before = false) {
19 if (anchor instanceof RegExp && anchor.flags.includes("g"))
20 throw new Error("anchor regular expression should not be global");
21 patches.push({ navId, item, anchor, before });
22}
23
24const patches: Patch[] = [];
25function _patchMenu(props: React.ComponentProps<Menu>, items: InternalItem[]) {
26 const matches = patches.filter((p) => p.navId === props.navId);
27 if (!matches.length) return items;
28
29 for (const patch of matches) {
30 const idx = items.findIndex((i) =>
31 typeof patch.anchor === "string" ? i.key === patch.anchor : patch.anchor.test(i.key!)
32 );
33 if (idx === -1) continue;
34 items.splice(idx + 1 - +patch.before, 0, ...parser(patch.item(menuProps) as ReturnType));
35 }
36
37 return items;
38}
39
40let menuProps: any;
41function _saveProps(self: any, el: any) {
42 menuProps = el.props;
43
44 const original = self.props.closeContextMenu;
45 self.props.closeContextMenu = function (...args: any[]) {
46 menuProps = undefined;
47 return original?.apply(this, args);
48 };
49
50 return el;
51}
52
53module.exports = {
54 patches,
55 addItem,
56 _patchMenu,
57 _saveProps
58};
59
60// Unmangle Menu elements
61// spacepack.require.m[moonlight.moonmap.modules["discord/modules/menus/web/Menu"]].toString();
62const code =
63 spacepack.require.m[
64 spacepack.findByCode("Menu API only allows Items and groups of Items as children.")[0].id
65 ].toString();
66
67let MangledMenu;
68
69const typeRegex = /if\(.\.type===(.)\.(.+?)\).+?type:"(.+?)"/g;
70const typeMap: Record<string, string | undefined> = {
71 checkbox: "MenuCheckboxItem",
72 control: "MenuControlItem",
73 groupstart: "MenuGroup",
74 customitem: "MenuItem",
75 radio: "MenuRadioItem",
76 separator: "MenuSeparator"
77};
78
79for (const [, modIdent, mangled, type] of code.matchAll(typeRegex)) {
80 if (!MangledMenu) {
81 const modId = code.match(new RegExp(`${modIdent}=.\\((\\d+?)\\)`))![1];
82 MangledMenu = spacepack.require(modId);
83 }
84
85 const prop = typeMap[type];
86 if (!prop) continue;
87 module.exports[prop] = MangledMenu[mangled];
88}