83 lines
2.4 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
anchorId: string;
15
before: boolean;
16
};
17
18
function addItem<T = any>(navId: string, item: React.FC<T>, anchorId: string, before = false) {
19
patches.push({ navId, item, anchorId, before });
20
}
21
22
const patches: Patch[] = [];
23
function _patchMenu(props: React.ComponentProps<Menu>, items: InternalItem[]) {
24
const matches = patches.filter((p) => p.navId === props.navId);
25
if (!matches.length) return items;
26
27
for (const patch of matches) {
28
const idx = items.findIndex((i) => i.key === patch.anchorId);
29
if (idx === -1) continue;
30
items.splice(idx + 1 - +patch.before, 0, ...parser(patch.item(menuProps) as ReturnType));
31
}
32
33
return items;
34
}
35
36
let menuProps: any;
37
function _saveProps(self: any, el: any) {
38
menuProps = el.props;
39
40
const original = self.props.closeContextMenu;
41
self.props.closeContextMenu = function (...args: any[]) {
42
menuProps = undefined;
43
return original?.apply(this, args);
44
};
45
46
return el;
47
}
48
49
module.exports = {
50
patches,
51
addItem,
52
_patchMenu,
53
_saveProps
54
};
55
56
// Unmangle Menu elements
57
const code =
58
spacepack.require.m[
59
spacepack.findByCode("Menu API only allows Items and groups of Items as children.")[0].id
60
].toString();
61
62
let MangledMenu;
63
64
const typeRegex = /if\(.\.type===(.)\.(.+?)\).+?type:"(.+?)"/g;
65
const typeMap: Record<string, string | undefined> = {
66
checkbox: "MenuCheckboxItem",
67
control: "MenuControlItem",
68
groupstart: "MenuGroup",
69
customitem: "MenuItem",
70
radio: "MenuRadioItem",
71
separator: "MenuSeparator"
72
};
73
74
for (const [, modIdent, mangled, type] of code.matchAll(typeRegex)) {
75
if (!MangledMenu) {
76
const modId = code.match(new RegExp(`${modIdent}=.\\((\\d+?)\\)`))![1];
77
MangledMenu = spacepack.require(modId);
78
}
79
80
const prop = typeMap[type];
81
if (!prop) continue;
82
module.exports[prop] = MangledMenu[mangled];
83
}
84