Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions apps/example/src/commands/modal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Command, Modal, ActionRow, ModalSubmitInteraction, TextInputComponent, ModalSubmitComponent } from 'disploy';
import { TextInputStyle } from 'discord-api-types/v10';

export default {
name: 'modal',
description: 'show a cool modal',

async run(interaction) {
const modal = new Modal()
.setCustomId("cool-modal")
.setComponents([
new ActionRow()
.setComponents([
new TextInputComponent()
.setCustomId("favNum")
.setLabel("What is your favorite number?")
.setStyle(TextInputStyle.Short)
.setMinLength(1)
.setRequired(true)
.setPlaceholder("10")
])
]);
interaction.showModal(modal);
},

async modalSubmit(interaction: ModalSubmitInteraction) {
const favNumComp: ModalSubmitComponent = interaction.components[0]?.get("favNum") as ModalSubmitComponent;
const favNum: string = favNumComp?.getValue();
interaction.reply({
content: `Nice favorite number: ${favNum ?? "10"}.`
});
}
} satisfies Command;
2 changes: 2 additions & 0 deletions packages/disploy/src/commands/Command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import type { ChatInputInteraction } from '../structs';
import type { CommandInteraction } from '../structs/CommandInteraction';
import type { MessageContextMenuInteraction } from '../structs/MessageContextMenuInteraction';
import type { UserContextMenuInteraction } from '../structs/UserContextMenuInteraction';
import type { ModalSubmitInteraction } from '../structs';

export interface ApplicationCommand {
name: string;
type?: ApplicationCommandType;
run(interaction: CommandInteraction): void | Promise<void>;
modalSubmit?(interaction: ModalSubmitInteraction): void | Promise<void>;
}

export interface ChatInputCommand extends ApplicationCommand {
Expand Down
26 changes: 26 additions & 0 deletions packages/disploy/src/structs/ActionRow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ComponentType } from 'discord-api-types/v10';
import type { ActionRowComponent } from './ActionRowComponent';

export class ActionRow {
public type: ComponentType;
public components: ActionRowComponent[];

public addComponents(components: ActionRowComponent[]) {
this.components.push(...components);
return this;
}

public setComponents(components: ActionRowComponent[]) {
this.components = components;
return this;
}

public get(customId: string) {
return this.components.filter((component) => component.customId === customId)[0];
}

public constructor(components?: ActionRowComponent[]) {
this.type = ComponentType.ActionRow;
this.components = components ?? [];
}
}
13 changes: 13 additions & 0 deletions packages/disploy/src/structs/ActionRowComponent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { ComponentType } from 'discord-api-types/v10';

export class ActionRowComponent {
public customId?: string;
public type?: ComponentType;

public setCustomId(id: string) {
this.customId = id;
return this;
}

public constructor() {}
}
13 changes: 13 additions & 0 deletions packages/disploy/src/structs/CommandInteraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { RouterEvents } from '../router';
import { BaseInteraction } from './BaseInteraction';
import { GuildMember } from './GuildMember';
import { User } from './User';
import { Modal } from './Modal';

export class CommandInteraction extends BaseInteraction {
/**
Expand Down Expand Up @@ -53,9 +54,21 @@ export class CommandInteraction extends BaseInteraction {
});
}

public showModal(modal: DiscordPayload<Modal>) {
if (modal instanceof Modal) {
modal = modal.toJSON();
}
return void this.app.router.emit(RouterEvents.Respond(this.id), {
type: InteractionResponseType.Modal,
data: modal,
});
}

public async editReply(payload: APIInteractionResponseCallbackData) {
return await this.app.rest.patch(Routes.webhookMessage(this.app.clientId, this.token), {
...payload,
});
}
}

export type DiscordPayload<T> = T | unknown;
43 changes: 43 additions & 0 deletions packages/disploy/src/structs/Modal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { ActionRow } from './ActionRow';

export class Modal {
public customId?: string;
public title?: string;
public components: ActionRow[] = [];

public setCustomId(id: string) {
this.customId = id;
return this;
}

public setTitle(title: string) {
this.title = title;
return this;
}

public setComponents(components: ActionRow[]) {
this.components = components;
return this;
}

public addComponents(components: ActionRow[]) {
this.components.push(...components);
return this;
}

public toJSON() {
return JSON.stringify(this);
}

public constructor(raw?: RawModalBuilder) {
this.title = raw?.title ?? undefined;
this.customId = raw?.customId ?? undefined;
this.components = raw?.components ?? [];
}
}

class RawModalBuilder {
title?: string;
customId?: string;
components?: ActionRow[];
}
35 changes: 35 additions & 0 deletions packages/disploy/src/structs/ModalActionRowComponent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { ActionRowComponent } from './ActionRowComponent';

export class ModalActionRowComponent extends ActionRowComponent {
public required?: boolean;
public value?: string;
public placeholder?: string;

public setRequired(required: boolean) {
this.required = required;
return this;
}

public setValue(value: string) {
this.value = value;
return this;
}

public setPlaceholder(placeholder: string) {
this.placeholder = placeholder;
return this;
}

public constructor(raw?: RawModalActionComponent) {
super();
this.required = raw?.required ?? undefined;
this.value = raw?.value ?? undefined;
this.placeholder = raw?.placeholder ?? undefined;
}
}

class RawModalActionComponent {
required?: boolean;
value?: string;
placeholder?: string;
}
17 changes: 17 additions & 0 deletions packages/disploy/src/structs/ModalSubmitComponent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ActionRowComponent } from './ActionRowComponent';
import type { ModalSubmitComponent as APIModalSubmitComponent } from 'discord-api-types/v10';

export class ModalSubmitComponent extends ActionRowComponent {
public value: string;

public getValue() {
return this.value;
}

public constructor(raw: APIModalSubmitComponent) {
super();
this.type = raw.type;
this.customId = raw.custom_id;
this.value = raw.value;
}
}
31 changes: 31 additions & 0 deletions packages/disploy/src/structs/ModalSubmitInteraction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { BaseInteraction } from './BaseInteraction';
import type { APIModalSubmitInteraction } from 'discord-api-types/v10';
import type { App } from '../client';
import { ActionRow } from './ActionRow';
import { ModalSubmitComponent } from './ModalSubmitComponent';
import { APIInteractionResponseCallbackData, InteractionResponseType } from 'discord-api-types/v10';
import { RouterEvents } from '../router';

export class ModalSubmitInteraction extends BaseInteraction {
public customId: string;
public components: ActionRow[];

public reply(payload: APIInteractionResponseCallbackData) {
return void this.app.router.emit(RouterEvents.Respond(this.id), {
type: InteractionResponseType.ChannelMessageWithSource,
data: payload,
});
}

public constructor(app: App, raw: APIModalSubmitInteraction) {
super(app, raw);
this.customId = raw.data.custom_id;
this.components = raw.data.components.map((rawActionRow) => {
return new ActionRow().setComponents(
rawActionRow.components.map((rawModalSubmitComponent) => {
return new ModalSubmitComponent(rawModalSubmitComponent);
}),
);
});
}
}
45 changes: 45 additions & 0 deletions packages/disploy/src/structs/TextInputComponent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { ModalActionRowComponent } from './ModalActionRowComponent';
import { ComponentType, TextInputStyle } from 'discord-api-types/v10';

export class TextInputComponent extends ModalActionRowComponent {
public style?: TextInputStyle;
public label?: string;
public minLength?: number;
public maxLength?: number;

public setStyle(style: TextInputStyle) {
this.style = style;
return this;
}

public setLabel(label: string) {
this.label = label;
return this;
}

public setMinLength(length: number) {
this.minLength = length;
return this;
}

public setMaxLength(length: number) {
this.maxLength = length;
return this;
}

public constructor(raw?: RawTextInputComponent) {
super();
this.type = ComponentType.TextInput;
this.style = raw?.style ?? undefined;
this.label = raw?.label ?? undefined;
this.minLength = raw?.minLength ?? undefined;
this.maxLength = raw?.maxLength ?? undefined;
}
}

class RawTextInputComponent {
public style?: TextInputStyle;
public label?: string;
public minLength?: number;
public maxLength?: number;
}
7 changes: 7 additions & 0 deletions packages/disploy/src/structs/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
export * from './ActionRow';
export * from './ActionRowComponent';
export * from './BaseInteraction';
export * from './ChatInputInteraction';
export * from './ChatInputInteractionOptions';
export * from './Guild';
export * from './GuildMember';
export * from './managers';
export * from './Modal';
export * from './ModalActionRowComponent';
export * from './ModalSubmitComponent';
export * from './ModalSubmitInteraction';
export * from './TextInputComponent';
export * from './User';