88 lines
2.7 kB
1
import { InternalItem, Menu, MenuElement } from "@moonlight-mod/types/coreExtensions/contextMenu";
2
import spacepack from "@moonlight-mod/wp/spacepack_spacepack";
3
import 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.
9
type ReturnType = MenuElement | MenuElement[];
10
11
type Patch = {
12
navId: string;
13
item: React.FC<any>;
14
anchor: string | RegExp;
15
before: boolean;
16
};
17
18
function 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
24
const patches: Patch[] = [];
25
function _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
40
let menuProps: any;
41
function _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
53
module.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();
62
const code =
63
spacepack.require.m[
64
spacepack.findByCode("Menu API only allows Items and groups of Items as children.")[0].id
65
].toString();
66
67
let MangledMenu;
68
69
const typeRegex = /if\(.\.type===(.)\.(.+?)\).+?type:"(.+?)"/g;
70
const 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
79
for (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
}
89