this repo has no description

Add Component Editor

Changed files
+446
packages
core-extensions
src
types
+75
packages/core-extensions/src/componentEditor/index.ts
···
+
import { ExtensionWebpackModule, Patch } from "@moonlight-mod/types";
+
+
export const patches: Patch[] = [
+
// dm list
+
{
+
find: ".interactiveSystemDM]:",
+
replace: [
+
{
+
match: /decorators:(\i\.isSystemDM\(\)\?\(0,\i\.jsx\)\(.+?verified:!0}\):null)/,
+
replacement: (_, decorators) =>
+
`decorators:require("componentEditor_dmList").default._patchDecorators([${decorators}],arguments[0])`
+
},
+
{
+
match: /(?<=selected:\i,)children:\[/,
+
replacement: 'children:require("componentEditor_dmList").default._patchItems(['
+
},
+
{
+
match: /(?<=onMouseDown:\i}\))]/,
+
replacement: "],arguments[0])"
+
}
+
],
+
hardFail: true
+
},
+
+
// member list
+
{
+
find: ".lostPermission",
+
replace: [
+
{
+
match: /(?<=\(0,\i\.jsxs\)\(\i\.Fragment,{)children:(\[\i\(\),.+?\i\(\)])/,
+
replacement: (_, decorators) =>
+
`children:require("componentEditor_memberList").default._patchDecorators(${decorators},arguments[0])`
+
},
+
{
+
match: /name:null==\i\?\(0,\i\.jsx\)\("span"/,
+
replacement: (orig: string) =>
+
`children:require("componentEditor_memberList").default._patchItems([],arguments[0]),${orig}`
+
}
+
]
+
},
+
+
// messages
+
{
+
find: '},"new-member")),',
+
replace: [
+
{
+
match: /(?<=\.BADGES]=)(\i);/,
+
replacement: (_, badges) =>
+
`require("componentEditor_messages").default._patchUsernameBadges(${badges},arguments[0]);`
+
},
+
{
+
match: /(?<=className:\i,)badges:(\i)/,
+
replacement: (_, badges) =>
+
`badges:require("componentEditor_messages").default._patchBadges(${badges},arguments[0])`
+
},
+
{
+
match: /(?<=username:\(0,\i\.jsxs\)\(\i\.Fragment,{)children:(\[.+?,\i])/,
+
replacement: (_, elements) =>
+
`children:require("componentEditor_messages").default._patchUsername(${elements},arguments[0])`
+
}
+
]
+
}
+
];
+
+
export const webpackModules: Record<string, ExtensionWebpackModule> = {
+
dmList: {
+
dependencies: [{ id: "react" }]
+
},
+
memberList: {
+
dependencies: [{ id: "react" }]
+
},
+
messages: {
+
dependencies: [{ id: "react" }]
+
}
+
};
+11
packages/core-extensions/src/componentEditor/manifest.json
···
+
{
+
"$schema": "https://moonlight-mod.github.io/manifest.schema.json",
+
"id": "componentEditor",
+
"apiLevel": 2,
+
"meta": {
+
"name": "Component Editor",
+
"tagline": "A library to add to commonly patched components",
+
"authors": ["Cynosphere"],
+
"tags": ["library"]
+
}
+
}
+61
packages/core-extensions/src/componentEditor/webpackModules/dmList.tsx
···
+
import {
+
DMList,
+
DMListItem,
+
DMListDecorator,
+
DMListAnchorIndicies,
+
DMListDecoratorAnchorIndicies
+
} from "@moonlight-mod/types/coreExtensions/componentEditor";
+
import React from "@moonlight-mod/wp/react";
+
+
const items: Record<string, DMListItem> = {};
+
const decorators: Record<string, DMListDecorator> = {};
+
+
function addEntries(
+
elements: React.ReactNode[],
+
entries: Record<string, DMListItem | DMListDecorator>,
+
indicies: Partial<Record<keyof typeof DMListAnchorIndicies | keyof typeof DMListDecoratorAnchorIndicies, number>>,
+
props: any
+
) {
+
const originalElements = [...elements];
+
for (const [id, entry] of Object.entries(entries)) {
+
const component = <entry.component {...props} key={id} />;
+
+
if (entry.anchor === undefined) {
+
if (entry.before) {
+
elements.splice(0, 0, component);
+
} else {
+
elements.push(component);
+
}
+
} else {
+
const index = elements.indexOf(originalElements[indicies[entry.anchor]!]);
+
elements.splice(index! + (entry.before ? 0 : 1), 0, component);
+
}
+
}
+
}
+
+
export const dmList: DMList = {
+
addItem(id, component, anchor, before = false) {
+
items[id] = {
+
component,
+
anchor,
+
before
+
};
+
},
+
addDecorator(id, component, anchor, before = false) {
+
decorators[id] = {
+
component,
+
anchor,
+
before
+
};
+
},
+
_patchItems(elements, props) {
+
addEntries(elements, items, DMListAnchorIndicies, props);
+
return elements;
+
},
+
_patchDecorators(elements, props) {
+
addEntries(elements, decorators, DMListDecoratorAnchorIndicies, props);
+
return elements;
+
}
+
};
+
+
export default dmList;
+50
packages/core-extensions/src/componentEditor/webpackModules/memberList.tsx
···
+
import {
+
MemberList,
+
MemberListDecorator,
+
MemberListDecoratorAnchorIndicies
+
} from "@moonlight-mod/types/coreExtensions/componentEditor";
+
import React from "@moonlight-mod/wp/react";
+
+
const items: Record<string, React.FC<any>> = {};
+
const decorators: Record<string, MemberListDecorator> = {};
+
+
export const memberList: MemberList = {
+
addItem(id, component) {
+
items[id] = component;
+
},
+
addDecorator(id, component, anchor, before = false) {
+
decorators[id] = {
+
component,
+
anchor,
+
before
+
};
+
},
+
_patchItems(elements, props) {
+
for (const [id, Component] of Object.entries(items)) {
+
elements.push(<Component {...props} key={id} />);
+
}
+
+
return elements;
+
},
+
_patchDecorators(elements, props) {
+
const originalElements = [...elements];
+
for (const [id, entry] of Object.entries(decorators)) {
+
const component = <entry.component {...props} key={id} />;
+
+
if (entry.anchor === undefined) {
+
if (entry.before) {
+
elements.splice(0, 0, component);
+
} else {
+
elements.push(component);
+
}
+
} else {
+
const index = elements.indexOf(originalElements[MemberListDecoratorAnchorIndicies[entry.anchor]!]);
+
elements.splice(index! + (entry.before ? 0 : 1), 0, component);
+
}
+
}
+
+
return elements;
+
}
+
};
+
+
export default memberList;
+82
packages/core-extensions/src/componentEditor/webpackModules/messages.tsx
···
+
import {
+
MessageBadge,
+
MessageBadgeIndicies,
+
Messages,
+
MessageUsername,
+
MessageUsernameBadge,
+
MessageUsernameBadgeIndicies,
+
MessageUsernameIndicies
+
} from "@moonlight-mod/types/coreExtensions/componentEditor";
+
import React from "@moonlight-mod/wp/react";
+
+
const username: Record<string, MessageUsername> = {};
+
const usernameBadges: Record<string, MessageUsernameBadge> = {};
+
const badges: Record<string, MessageBadge> = {};
+
+
function addEntries(
+
elements: React.ReactNode[],
+
entries: Record<string, MessageUsername | MessageUsernameBadge | MessageBadge>,
+
indicies: Partial<
+
Record<
+
| keyof typeof MessageUsernameIndicies
+
| keyof typeof MessageUsernameBadgeIndicies
+
| keyof typeof MessageBadgeIndicies,
+
number
+
>
+
>,
+
props: any
+
) {
+
const originalElements = [...elements];
+
for (const [id, entry] of Object.entries(entries)) {
+
const component = <entry.component {...props} key={id} />;
+
+
if (entry.anchor === undefined) {
+
if (entry.before) {
+
elements.splice(0, 0, component);
+
} else {
+
elements.push(component);
+
}
+
} else {
+
const index = elements.indexOf(originalElements[indicies[entry.anchor]!]);
+
elements.splice(index! + (entry.before ? 0 : 1), 0, component);
+
}
+
}
+
}
+
+
export const messages: Messages = {
+
addToUsername(id, component, anchor, before = false) {
+
username[id] = {
+
component,
+
anchor,
+
before
+
};
+
},
+
addUsernameBadge(id, component, anchor, before = false) {
+
usernameBadges[id] = {
+
component,
+
anchor,
+
before
+
};
+
},
+
addBadge(id, component, anchor, before = false) {
+
badges[id] = {
+
component,
+
anchor,
+
before
+
};
+
},
+
_patchUsername(elements, props) {
+
addEntries(elements, username, MessageUsernameIndicies, props);
+
return elements;
+
},
+
_patchUsernameBadges(elements, props) {
+
addEntries(elements, usernameBadges, MessageUsernameBadgeIndicies, props);
+
return elements;
+
},
+
_patchBadges(elements, props) {
+
addEntries(elements, badges, MessageBadgeIndicies, props);
+
return elements;
+
}
+
};
+
+
export default messages;
+1
packages/types/src/coreExtensions.ts
···
export * as Moonbase from "./coreExtensions/moonbase";
export * as AppPanels from "./coreExtensions/appPanels";
export * as Commands from "./coreExtensions/commands";
+
export * as ComponentEditor from "./coreExtensions/componentEditor";
+145
packages/types/src/coreExtensions/componentEditor.ts
···
+
type Patcher<T> = (elements: React.ReactNode[], props: T) => React.ReactNode[];
+
+
//#region DM List
+
export type DMListAnchors =
+
| "content"
+
| "favorite-server-indicator"
+
| "ignored-indicator"
+
| "blocked-indicator"
+
| "close-button"
+
| undefined;
+
export type DMListDecoratorAnchors = "system-tag" | undefined;
+
+
export enum DMListAnchorIndicies {
+
content = 0,
+
"favorite-server-indicator",
+
"ignored-indicator",
+
"blocked-indicator",
+
"close-button"
+
}
+
export enum DMListDecoratorAnchorIndicies {
+
"system-tag" = 0
+
}
+
+
export type DMListItem = {
+
component: React.FC<any>;
+
anchor: DMListAnchors;
+
before: boolean;
+
};
+
export type DMListDecorator = {
+
component: React.FC<any>;
+
anchor: DMListDecoratorAnchors;
+
before: boolean;
+
};
+
+
export type DMList = {
+
addItem: (id: string, component: React.FC<any>, anchor?: DMListAnchors, before?: boolean) => void;
+
addDecorator: (id: string, component: React.FC<any>, anchor?: DMListDecoratorAnchors, before?: boolean) => void;
+
//TODO: fix props type
+
/**
+
* @private
+
*/
+
_patchItems: Patcher<any>;
+
/**
+
* @private
+
*/
+
_patchDecorators: Patcher<any>;
+
};
+
//#endregion
+
+
//#region Member List
+
export type MemberListDecoratorAnchors = "bot-tag" | "owner-crown" | "boost-icon" | undefined;
+
+
export enum MemberListDecoratorAnchorIndicies {
+
"bot-tag" = 0,
+
"owner-crown",
+
"boost-icon"
+
}
+
+
export type MemberListDecorator = {
+
component: React.FC<any>;
+
anchor: MemberListDecoratorAnchors;
+
before: boolean;
+
};
+
+
export type MemberList = {
+
addItem: (id: string, component: React.FC<any>) => void;
+
addDecorator: (id: string, component: React.FC<any>, anchor?: MemberListDecoratorAnchors, before?: boolean) => void;
+
//TODO: fix props type
+
/**
+
* @private
+
*/
+
_patchItems: Patcher<any>;
+
/**
+
* @private
+
*/
+
_patchDecorators: Patcher<any>;
+
};
+
//#endregion
+
+
//#region Messages
+
export type MessageUsernameAnchors = "communication-disabled" | "username" | undefined;
+
export type MessageUsernameBadgeAnchors =
+
| "nitro-author"
+
| "role-icon"
+
| "new-member"
+
| "leaderboard-champion"
+
| "connections"
+
| undefined;
+
export type MessageBadgeAnchors = "silent" | "potion" | undefined;
+
+
export type MessageUsername = {
+
component: React.FC<any>;
+
anchor: MessageUsernameAnchors;
+
before: boolean;
+
};
+
export type MessageUsernameBadge = {
+
component: React.FC<any>;
+
anchor: MessageUsernameBadgeAnchors;
+
before: boolean;
+
};
+
export type MessageBadge = {
+
component: React.FC<any>;
+
anchor: MessageBadgeAnchors;
+
before: boolean;
+
};
+
+
export enum MessageUsernameIndicies {
+
"communication-disabled" = 0,
+
username
+
}
+
export enum MessageUsernameBadgeIndicies {
+
"nitro-author" = 0,
+
"role-icon",
+
"new-member",
+
"leaderboard-champion",
+
connections
+
}
+
export enum MessageBadgeIndicies {
+
silent = 0,
+
potion
+
}
+
+
export type Messages = {
+
addToUsername: (id: string, component: React.FC<any>, anchor?: MessageUsernameAnchors, before?: boolean) => void;
+
addUsernameBadge: (
+
id: string,
+
component: React.FC<any>,
+
anchor?: MessageUsernameBadgeAnchors,
+
before?: boolean
+
) => void;
+
addBadge: (id: string, component: React.FC<any>, anchor?: MessageBadgeAnchors, before?: boolean) => void;
+
/**
+
* @private
+
*/
+
_patchUsername: Patcher<any>;
+
/**
+
* @private
+
*/
+
_patchUsernameBadges: Patcher<any>;
+
/**
+
* @private
+
*/
+
_patchBadges: Patcher<any>;
+
};
+
//#endregion
+5
packages/types/src/discord/require.ts
···
import { AppPanels } from "../coreExtensions/appPanels";
import { Commands } from "../coreExtensions/commands";
+
import { DMList, MemberList, Messages } from "../coreExtensions/componentEditor";
import { ContextMenu, EvilItemParser } from "../coreExtensions/contextMenu";
import { Markdown } from "../coreExtensions/markdown";
import { Moonbase } from "../coreExtensions/moonbase";
···
declare function WebpackRequire(id: "appPanels_appPanels"): AppPanels;
declare function WebpackRequire(id: "commands_commands"): Commands;
+
+
declare function WebpackRequire(id: "componentEditor_dmList"): DMList;
+
declare function WebpackRequire(id: "componentEditor_memberList"): MemberList;
+
declare function WebpackRequire(id: "componentEditor_messages"): Messages;
declare function WebpackRequire(id: "contextMenu_evilMenu"): EvilItemParser;
declare function WebpackRequire(id: "contextMenu_contextMenu"): ContextMenu;
+16
packages/types/src/import.d.ts
···
declare module "@moonlight-mod/wp/common_stores";
+
declare module "@moonlight-mod/wp/componentEditor_dmList" {
+
import { CoreExtensions } from "@moonlight-mod/types";
+
export const dmList: CoreExtensions.ComponentEditor.DMList;
+
export default dmList;
+
}
+
declare module "@moonlight-mod/wp/componentEditor_memberList" {
+
import { CoreExtensions } from "@moonlight-mod/types";
+
export const memberList: CoreExtensions.ComponentEditor.MemberList;
+
export default memberList;
+
}
+
declare module "@moonlight-mod/wp/componentEditor_messages" {
+
import { CoreExtensions } from "@moonlight-mod/types";
+
export const message: CoreExtensions.ComponentEditor.Messages;
+
export default message;
+
}
+
declare module "@moonlight-mod/wp/contextMenu_evilMenu" {
import { CoreExtensions } from "@moonlight-mod/types";
const EvilParser: CoreExtensions.ContextMenu.EvilItemParser;