+75
packages/core-extensions/src/componentEditor/index.ts
+75
packages/core-extensions/src/componentEditor/index.ts
···
1
+
import { ExtensionWebpackModule, Patch } from "@moonlight-mod/types";
2
+
3
+
export const patches: Patch[] = [
4
+
// dm list
5
+
{
6
+
find: ".interactiveSystemDM]:",
7
+
replace: [
8
+
{
9
+
match: /decorators:(\i\.isSystemDM\(\)\?\(0,\i\.jsx\)\(.+?verified:!0}\):null)/,
10
+
replacement: (_, decorators) =>
11
+
`decorators:require("componentEditor_dmList").default._patchDecorators([${decorators}],arguments[0])`
12
+
},
13
+
{
14
+
match: /(?<=selected:\i,)children:\[/,
15
+
replacement: 'children:require("componentEditor_dmList").default._patchItems(['
16
+
},
17
+
{
18
+
match: /(?<=onMouseDown:\i}\))]/,
19
+
replacement: "],arguments[0])"
20
+
}
21
+
],
22
+
hardFail: true
23
+
},
24
+
25
+
// member list
26
+
{
27
+
find: ".lostPermission",
28
+
replace: [
29
+
{
30
+
match: /(?<=\(0,\i\.jsxs\)\(\i\.Fragment,{)children:(\[\i\(\),.+?\i\(\)])/,
31
+
replacement: (_, decorators) =>
32
+
`children:require("componentEditor_memberList").default._patchDecorators(${decorators},arguments[0])`
33
+
},
34
+
{
35
+
match: /name:null==\i\?\(0,\i\.jsx\)\("span"/,
36
+
replacement: (orig: string) =>
37
+
`children:require("componentEditor_memberList").default._patchItems([],arguments[0]),${orig}`
38
+
}
39
+
]
40
+
},
41
+
42
+
// messages
43
+
{
44
+
find: '},"new-member")),',
45
+
replace: [
46
+
{
47
+
match: /(?<=\.BADGES]=)(\i);/,
48
+
replacement: (_, badges) =>
49
+
`require("componentEditor_messages").default._patchUsernameBadges(${badges},arguments[0]);`
50
+
},
51
+
{
52
+
match: /(?<=className:\i,)badges:(\i)/,
53
+
replacement: (_, badges) =>
54
+
`badges:require("componentEditor_messages").default._patchBadges(${badges},arguments[0])`
55
+
},
56
+
{
57
+
match: /(?<=username:\(0,\i\.jsxs\)\(\i\.Fragment,{)children:(\[.+?,\i])/,
58
+
replacement: (_, elements) =>
59
+
`children:require("componentEditor_messages").default._patchUsername(${elements},arguments[0])`
60
+
}
61
+
]
62
+
}
63
+
];
64
+
65
+
export const webpackModules: Record<string, ExtensionWebpackModule> = {
66
+
dmList: {
67
+
dependencies: [{ id: "react" }]
68
+
},
69
+
memberList: {
70
+
dependencies: [{ id: "react" }]
71
+
},
72
+
messages: {
73
+
dependencies: [{ id: "react" }]
74
+
}
75
+
};
+11
packages/core-extensions/src/componentEditor/manifest.json
+11
packages/core-extensions/src/componentEditor/manifest.json
···
1
+
{
2
+
"$schema": "https://moonlight-mod.github.io/manifest.schema.json",
3
+
"id": "componentEditor",
4
+
"apiLevel": 2,
5
+
"meta": {
6
+
"name": "Component Editor",
7
+
"tagline": "A library to add to commonly patched components",
8
+
"authors": ["Cynosphere"],
9
+
"tags": ["library"]
10
+
}
11
+
}
+61
packages/core-extensions/src/componentEditor/webpackModules/dmList.tsx
+61
packages/core-extensions/src/componentEditor/webpackModules/dmList.tsx
···
1
+
import {
2
+
DMList,
3
+
DMListItem,
4
+
DMListDecorator,
5
+
DMListAnchorIndicies,
6
+
DMListDecoratorAnchorIndicies
7
+
} from "@moonlight-mod/types/coreExtensions/componentEditor";
8
+
import React from "@moonlight-mod/wp/react";
9
+
10
+
const items: Record<string, DMListItem> = {};
11
+
const decorators: Record<string, DMListDecorator> = {};
12
+
13
+
function addEntries(
14
+
elements: React.ReactNode[],
15
+
entries: Record<string, DMListItem | DMListDecorator>,
16
+
indicies: Partial<Record<keyof typeof DMListAnchorIndicies | keyof typeof DMListDecoratorAnchorIndicies, number>>,
17
+
props: any
18
+
) {
19
+
const originalElements = [...elements];
20
+
for (const [id, entry] of Object.entries(entries)) {
21
+
const component = <entry.component {...props} key={id} />;
22
+
23
+
if (entry.anchor === undefined) {
24
+
if (entry.before) {
25
+
elements.splice(0, 0, component);
26
+
} else {
27
+
elements.push(component);
28
+
}
29
+
} else {
30
+
const index = elements.indexOf(originalElements[indicies[entry.anchor]!]);
31
+
elements.splice(index! + (entry.before ? 0 : 1), 0, component);
32
+
}
33
+
}
34
+
}
35
+
36
+
export const dmList: DMList = {
37
+
addItem(id, component, anchor, before = false) {
38
+
items[id] = {
39
+
component,
40
+
anchor,
41
+
before
42
+
};
43
+
},
44
+
addDecorator(id, component, anchor, before = false) {
45
+
decorators[id] = {
46
+
component,
47
+
anchor,
48
+
before
49
+
};
50
+
},
51
+
_patchItems(elements, props) {
52
+
addEntries(elements, items, DMListAnchorIndicies, props);
53
+
return elements;
54
+
},
55
+
_patchDecorators(elements, props) {
56
+
addEntries(elements, decorators, DMListDecoratorAnchorIndicies, props);
57
+
return elements;
58
+
}
59
+
};
60
+
61
+
export default dmList;
+50
packages/core-extensions/src/componentEditor/webpackModules/memberList.tsx
+50
packages/core-extensions/src/componentEditor/webpackModules/memberList.tsx
···
1
+
import {
2
+
MemberList,
3
+
MemberListDecorator,
4
+
MemberListDecoratorAnchorIndicies
5
+
} from "@moonlight-mod/types/coreExtensions/componentEditor";
6
+
import React from "@moonlight-mod/wp/react";
7
+
8
+
const items: Record<string, React.FC<any>> = {};
9
+
const decorators: Record<string, MemberListDecorator> = {};
10
+
11
+
export const memberList: MemberList = {
12
+
addItem(id, component) {
13
+
items[id] = component;
14
+
},
15
+
addDecorator(id, component, anchor, before = false) {
16
+
decorators[id] = {
17
+
component,
18
+
anchor,
19
+
before
20
+
};
21
+
},
22
+
_patchItems(elements, props) {
23
+
for (const [id, Component] of Object.entries(items)) {
24
+
elements.push(<Component {...props} key={id} />);
25
+
}
26
+
27
+
return elements;
28
+
},
29
+
_patchDecorators(elements, props) {
30
+
const originalElements = [...elements];
31
+
for (const [id, entry] of Object.entries(decorators)) {
32
+
const component = <entry.component {...props} key={id} />;
33
+
34
+
if (entry.anchor === undefined) {
35
+
if (entry.before) {
36
+
elements.splice(0, 0, component);
37
+
} else {
38
+
elements.push(component);
39
+
}
40
+
} else {
41
+
const index = elements.indexOf(originalElements[MemberListDecoratorAnchorIndicies[entry.anchor]!]);
42
+
elements.splice(index! + (entry.before ? 0 : 1), 0, component);
43
+
}
44
+
}
45
+
46
+
return elements;
47
+
}
48
+
};
49
+
50
+
export default memberList;
+82
packages/core-extensions/src/componentEditor/webpackModules/messages.tsx
+82
packages/core-extensions/src/componentEditor/webpackModules/messages.tsx
···
1
+
import {
2
+
MessageBadge,
3
+
MessageBadgeIndicies,
4
+
Messages,
5
+
MessageUsername,
6
+
MessageUsernameBadge,
7
+
MessageUsernameBadgeIndicies,
8
+
MessageUsernameIndicies
9
+
} from "@moonlight-mod/types/coreExtensions/componentEditor";
10
+
import React from "@moonlight-mod/wp/react";
11
+
12
+
const username: Record<string, MessageUsername> = {};
13
+
const usernameBadges: Record<string, MessageUsernameBadge> = {};
14
+
const badges: Record<string, MessageBadge> = {};
15
+
16
+
function addEntries(
17
+
elements: React.ReactNode[],
18
+
entries: Record<string, MessageUsername | MessageUsernameBadge | MessageBadge>,
19
+
indicies: Partial<
20
+
Record<
21
+
| keyof typeof MessageUsernameIndicies
22
+
| keyof typeof MessageUsernameBadgeIndicies
23
+
| keyof typeof MessageBadgeIndicies,
24
+
number
25
+
>
26
+
>,
27
+
props: any
28
+
) {
29
+
const originalElements = [...elements];
30
+
for (const [id, entry] of Object.entries(entries)) {
31
+
const component = <entry.component {...props} key={id} />;
32
+
33
+
if (entry.anchor === undefined) {
34
+
if (entry.before) {
35
+
elements.splice(0, 0, component);
36
+
} else {
37
+
elements.push(component);
38
+
}
39
+
} else {
40
+
const index = elements.indexOf(originalElements[indicies[entry.anchor]!]);
41
+
elements.splice(index! + (entry.before ? 0 : 1), 0, component);
42
+
}
43
+
}
44
+
}
45
+
46
+
export const messages: Messages = {
47
+
addToUsername(id, component, anchor, before = false) {
48
+
username[id] = {
49
+
component,
50
+
anchor,
51
+
before
52
+
};
53
+
},
54
+
addUsernameBadge(id, component, anchor, before = false) {
55
+
usernameBadges[id] = {
56
+
component,
57
+
anchor,
58
+
before
59
+
};
60
+
},
61
+
addBadge(id, component, anchor, before = false) {
62
+
badges[id] = {
63
+
component,
64
+
anchor,
65
+
before
66
+
};
67
+
},
68
+
_patchUsername(elements, props) {
69
+
addEntries(elements, username, MessageUsernameIndicies, props);
70
+
return elements;
71
+
},
72
+
_patchUsernameBadges(elements, props) {
73
+
addEntries(elements, usernameBadges, MessageUsernameBadgeIndicies, props);
74
+
return elements;
75
+
},
76
+
_patchBadges(elements, props) {
77
+
addEntries(elements, badges, MessageBadgeIndicies, props);
78
+
return elements;
79
+
}
80
+
};
81
+
82
+
export default messages;
+1
packages/types/src/coreExtensions.ts
+1
packages/types/src/coreExtensions.ts
+145
packages/types/src/coreExtensions/componentEditor.ts
+145
packages/types/src/coreExtensions/componentEditor.ts
···
1
+
type Patcher<T> = (elements: React.ReactNode[], props: T) => React.ReactNode[];
2
+
3
+
//#region DM List
4
+
export type DMListAnchors =
5
+
| "content"
6
+
| "favorite-server-indicator"
7
+
| "ignored-indicator"
8
+
| "blocked-indicator"
9
+
| "close-button"
10
+
| undefined;
11
+
export type DMListDecoratorAnchors = "system-tag" | undefined;
12
+
13
+
export enum DMListAnchorIndicies {
14
+
content = 0,
15
+
"favorite-server-indicator",
16
+
"ignored-indicator",
17
+
"blocked-indicator",
18
+
"close-button"
19
+
}
20
+
export enum DMListDecoratorAnchorIndicies {
21
+
"system-tag" = 0
22
+
}
23
+
24
+
export type DMListItem = {
25
+
component: React.FC<any>;
26
+
anchor: DMListAnchors;
27
+
before: boolean;
28
+
};
29
+
export type DMListDecorator = {
30
+
component: React.FC<any>;
31
+
anchor: DMListDecoratorAnchors;
32
+
before: boolean;
33
+
};
34
+
35
+
export type DMList = {
36
+
addItem: (id: string, component: React.FC<any>, anchor?: DMListAnchors, before?: boolean) => void;
37
+
addDecorator: (id: string, component: React.FC<any>, anchor?: DMListDecoratorAnchors, before?: boolean) => void;
38
+
//TODO: fix props type
39
+
/**
40
+
* @private
41
+
*/
42
+
_patchItems: Patcher<any>;
43
+
/**
44
+
* @private
45
+
*/
46
+
_patchDecorators: Patcher<any>;
47
+
};
48
+
//#endregion
49
+
50
+
//#region Member List
51
+
export type MemberListDecoratorAnchors = "bot-tag" | "owner-crown" | "boost-icon" | undefined;
52
+
53
+
export enum MemberListDecoratorAnchorIndicies {
54
+
"bot-tag" = 0,
55
+
"owner-crown",
56
+
"boost-icon"
57
+
}
58
+
59
+
export type MemberListDecorator = {
60
+
component: React.FC<any>;
61
+
anchor: MemberListDecoratorAnchors;
62
+
before: boolean;
63
+
};
64
+
65
+
export type MemberList = {
66
+
addItem: (id: string, component: React.FC<any>) => void;
67
+
addDecorator: (id: string, component: React.FC<any>, anchor?: MemberListDecoratorAnchors, before?: boolean) => void;
68
+
//TODO: fix props type
69
+
/**
70
+
* @private
71
+
*/
72
+
_patchItems: Patcher<any>;
73
+
/**
74
+
* @private
75
+
*/
76
+
_patchDecorators: Patcher<any>;
77
+
};
78
+
//#endregion
79
+
80
+
//#region Messages
81
+
export type MessageUsernameAnchors = "communication-disabled" | "username" | undefined;
82
+
export type MessageUsernameBadgeAnchors =
83
+
| "nitro-author"
84
+
| "role-icon"
85
+
| "new-member"
86
+
| "leaderboard-champion"
87
+
| "connections"
88
+
| undefined;
89
+
export type MessageBadgeAnchors = "silent" | "potion" | undefined;
90
+
91
+
export type MessageUsername = {
92
+
component: React.FC<any>;
93
+
anchor: MessageUsernameAnchors;
94
+
before: boolean;
95
+
};
96
+
export type MessageUsernameBadge = {
97
+
component: React.FC<any>;
98
+
anchor: MessageUsernameBadgeAnchors;
99
+
before: boolean;
100
+
};
101
+
export type MessageBadge = {
102
+
component: React.FC<any>;
103
+
anchor: MessageBadgeAnchors;
104
+
before: boolean;
105
+
};
106
+
107
+
export enum MessageUsernameIndicies {
108
+
"communication-disabled" = 0,
109
+
username
110
+
}
111
+
export enum MessageUsernameBadgeIndicies {
112
+
"nitro-author" = 0,
113
+
"role-icon",
114
+
"new-member",
115
+
"leaderboard-champion",
116
+
connections
117
+
}
118
+
export enum MessageBadgeIndicies {
119
+
silent = 0,
120
+
potion
121
+
}
122
+
123
+
export type Messages = {
124
+
addToUsername: (id: string, component: React.FC<any>, anchor?: MessageUsernameAnchors, before?: boolean) => void;
125
+
addUsernameBadge: (
126
+
id: string,
127
+
component: React.FC<any>,
128
+
anchor?: MessageUsernameBadgeAnchors,
129
+
before?: boolean
130
+
) => void;
131
+
addBadge: (id: string, component: React.FC<any>, anchor?: MessageBadgeAnchors, before?: boolean) => void;
132
+
/**
133
+
* @private
134
+
*/
135
+
_patchUsername: Patcher<any>;
136
+
/**
137
+
* @private
138
+
*/
139
+
_patchUsernameBadges: Patcher<any>;
140
+
/**
141
+
* @private
142
+
*/
143
+
_patchBadges: Patcher<any>;
144
+
};
145
+
//#endregion
+5
packages/types/src/discord/require.ts
+5
packages/types/src/discord/require.ts
···
1
1
import { AppPanels } from "../coreExtensions/appPanels";
2
2
import { Commands } from "../coreExtensions/commands";
3
+
import { DMList, MemberList, Messages } from "../coreExtensions/componentEditor";
3
4
import { ContextMenu, EvilItemParser } from "../coreExtensions/contextMenu";
4
5
import { Markdown } from "../coreExtensions/markdown";
5
6
import { Moonbase } from "../coreExtensions/moonbase";
···
12
13
declare function WebpackRequire(id: "appPanels_appPanels"): AppPanels;
13
14
14
15
declare function WebpackRequire(id: "commands_commands"): Commands;
16
+
17
+
declare function WebpackRequire(id: "componentEditor_dmList"): DMList;
18
+
declare function WebpackRequire(id: "componentEditor_memberList"): MemberList;
19
+
declare function WebpackRequire(id: "componentEditor_messages"): Messages;
15
20
16
21
declare function WebpackRequire(id: "contextMenu_evilMenu"): EvilItemParser;
17
22
declare function WebpackRequire(id: "contextMenu_contextMenu"): ContextMenu;
+16
packages/types/src/import.d.ts
+16
packages/types/src/import.d.ts
···
12
12
13
13
declare module "@moonlight-mod/wp/common_stores";
14
14
15
+
declare module "@moonlight-mod/wp/componentEditor_dmList" {
16
+
import { CoreExtensions } from "@moonlight-mod/types";
17
+
export const dmList: CoreExtensions.ComponentEditor.DMList;
18
+
export default dmList;
19
+
}
20
+
declare module "@moonlight-mod/wp/componentEditor_memberList" {
21
+
import { CoreExtensions } from "@moonlight-mod/types";
22
+
export const memberList: CoreExtensions.ComponentEditor.MemberList;
23
+
export default memberList;
24
+
}
25
+
declare module "@moonlight-mod/wp/componentEditor_messages" {
26
+
import { CoreExtensions } from "@moonlight-mod/types";
27
+
export const message: CoreExtensions.ComponentEditor.Messages;
28
+
export default message;
29
+
}
30
+
15
31
declare module "@moonlight-mod/wp/contextMenu_evilMenu" {
16
32
import { CoreExtensions } from "@moonlight-mod/types";
17
33
const EvilParser: CoreExtensions.ContextMenu.EvilItemParser;