feat(modals): modals, input text components and modal submits, v13 style (#7431)

This commit is contained in:
Ryan Munro
2022-04-09 19:36:49 +10:00
committed by GitHub
parent 5e8162a137
commit e1cdcfa9a6
20 changed files with 836 additions and 56 deletions

13
typings/enums.d.ts vendored
View File

@@ -111,6 +111,7 @@ export const enum InteractionResponseTypes {
DEFERRED_MESSAGE_UPDATE = 6,
UPDATE_MESSAGE = 7,
APPLICATION_COMMAND_AUTOCOMPLETE_RESULT = 8,
MODAL = 9,
}
export const enum InteractionTypes {
@@ -118,6 +119,7 @@ export const enum InteractionTypes {
APPLICATION_COMMAND = 2,
MESSAGE_COMPONENT = 3,
APPLICATION_COMMAND_AUTOCOMPLETE = 4,
MODAL_SUBMIT = 5,
}
export const enum InviteTargetType {
@@ -142,6 +144,12 @@ export const enum MessageComponentTypes {
ACTION_ROW = 1,
BUTTON = 2,
SELECT_MENU = 3,
TEXT_INPUT = 4,
}
export const enum ModalComponentTypes {
ACTION_ROW = 1,
TEXT_INPUT = 4,
}
export const enum MFALevels {
@@ -184,6 +192,11 @@ export const enum StickerTypes {
GUILD = 2,
}
export const enum TextInputStyles {
SHORT = 1,
PARAGRAPH = 2,
}
export const enum VerificationLevels {
NONE = 0,
LOW = 1,

238
typings/index.d.ts vendored
View File

@@ -22,6 +22,7 @@ import {
import { Collection } from '@discordjs/collection';
import {
APIActionRowComponent,
APIActionRowComponentTypes,
APIApplicationCommand,
APIApplicationCommandInteractionData,
APIApplicationCommandOption,
@@ -35,7 +36,9 @@ import {
APIInteractionDataResolvedGuildMember,
APIInteractionGuildMember,
APIMessage,
APIMessageActionRowComponent,
APIMessageComponent,
APIModalActionRowComponent,
APIOverwrite,
APIPartialChannel,
APIPartialEmoji,
@@ -43,6 +46,7 @@ import {
APIRole,
APISelectMenuComponent,
APITemplateSerializedSourceGuild,
APITextInputComponent,
APIUser,
GatewayVoiceServerUpdateDispatchData,
GatewayVoiceStateUpdateDispatchData,
@@ -71,6 +75,7 @@ import {
MessageButtonStyles,
MessageComponentTypes,
MessageTypes,
ModalComponentTypes,
MFALevels,
NSFWLevels,
OverwriteTypes,
@@ -78,6 +83,7 @@ import {
PrivacyLevels,
StickerFormatTypes,
StickerTypes,
TextInputStyles,
VerificationLevels,
WebhookTypes,
GuildScheduledEventEntityTypes,
@@ -117,6 +123,7 @@ import {
RawMessagePayloadData,
RawMessageReactionData,
RawMessageSelectMenuInteractionData,
RawModalSubmitInteractionData,
RawOAuth2GuildData,
RawPartialGroupDMChannelData,
RawPartialMessageData,
@@ -130,6 +137,7 @@ import {
RawStickerPackData,
RawTeamData,
RawTeamMemberData,
RawTextInputComponentData,
RawThreadChannelData,
RawThreadMemberData,
RawTypingData,
@@ -360,6 +368,9 @@ export abstract class BaseCommandInteraction<Cached extends CacheType = CacheTyp
public ephemeral: boolean | null;
public replied: boolean;
public webhook: InteractionWebhook;
public awaitModalSubmit(
options: AwaitModalSubmitOptions<ModalSubmitInteraction>,
): Promise<ModalSubmitInteraction<Cached>>;
public inGuild(): this is BaseCommandInteraction<'raw' | 'cached'>;
public inCachedGuild(): this is BaseCommandInteraction<'cached'>;
public inRawGuild(): this is BaseCommandInteraction<'raw'>;
@@ -371,6 +382,7 @@ export abstract class BaseCommandInteraction<Cached extends CacheType = CacheTyp
public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<GuildCacheMessage<Cached>>;
public reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
public reply(options: string | MessagePayload | InteractionReplyOptions): Promise<void>;
public showModal(modal: Modal | ModalOptions): Promise<void>;
private transformOption(
option: APIApplicationCommandOption,
resolved: APIApplicationCommandInteractionData['resolved'],
@@ -1366,6 +1378,7 @@ export class Interaction<Cached extends CacheType = CacheType> extends Base {
public isUserContextMenu(): this is UserContextMenuInteraction<Cached>;
public isMessageContextMenu(): this is MessageContextMenuInteraction<Cached>;
public isMessageComponent(): this is MessageComponentInteraction<Cached>;
public isModalSubmit(): this is ModalSubmitInteraction<Cached>;
public isSelectMenu(): this is SelectMenuInteraction<Cached>;
public isRepliable(): this is this & InteractionResponseFields<Cached>;
}
@@ -1501,6 +1514,7 @@ export type MappedInteractionTypes<Cached extends boolean = boolean> = EnumValue
BUTTON: ButtonInteraction<WrapBooleanCache<Cached>>;
SELECT_MENU: SelectMenuInteraction<WrapBooleanCache<Cached>>;
ACTION_ROW: MessageComponentInteraction<WrapBooleanCache<Cached>>;
TEXT_INPUT: ModalSubmitInteraction<WrapBooleanCache<Cached>>;
}
>;
@@ -1578,22 +1592,20 @@ export class Message<Cached extends boolean = boolean> extends Base {
public inGuild(): this is Message<true> & this;
}
export class MessageActionRow extends BaseMessageComponent {
public constructor(data?: MessageActionRow | MessageActionRowOptions | APIActionRowComponent);
export class MessageActionRow<
T extends MessageActionRowComponent | ModalActionRowComponent = MessageActionRowComponent,
U = T extends ModalActionRowComponent ? ModalActionRowComponentResolvable : MessageActionRowComponentResolvable,
V = T extends ModalActionRowComponent
? APIActionRowComponent<APIModalActionRowComponent>
: APIActionRowComponent<APIMessageActionRowComponent>,
> extends BaseMessageComponent {
public constructor(data?: MessageActionRow<T> | MessageActionRowOptions<U> | V);
public type: 'ACTION_ROW';
public components: MessageActionRowComponent[];
public addComponents(
...components: MessageActionRowComponentResolvable[] | MessageActionRowComponentResolvable[][]
): this;
public setComponents(
...components: MessageActionRowComponentResolvable[] | MessageActionRowComponentResolvable[][]
): this;
public spliceComponents(
index: number,
deleteCount: number,
...components: MessageActionRowComponentResolvable[] | MessageActionRowComponentResolvable[][]
): this;
public toJSON(): APIActionRowComponent;
public components: T[];
public addComponents(...components: U[] | U[][]): this;
public setComponents(...components: U[] | U[][]): this;
public spliceComponents(index: number, deleteCount: number, ...components: U[] | U[][]): this;
public toJSON(): V;
}
export class MessageAttachment {
@@ -1656,9 +1668,9 @@ export class MessageComponentInteraction<Cached extends CacheType = CacheType> e
public readonly component: CacheTypeReducer<
Cached,
MessageActionRowComponent,
Exclude<APIMessageComponent, APIActionRowComponent>,
MessageActionRowComponent | Exclude<APIMessageComponent, APIActionRowComponent>,
MessageActionRowComponent | Exclude<APIMessageComponent, APIActionRowComponent>
Exclude<APIMessageComponent, APIActionRowComponent<APIMessageActionRowComponent>>,
MessageActionRowComponent | Exclude<APIMessageComponent, APIActionRowComponent<APIMessageActionRowComponent>>,
MessageActionRowComponent | Exclude<APIMessageComponent, APIActionRowComponent<APIMessageActionRowComponent>>
>;
public componentType: Exclude<MessageComponentType, 'ACTION_ROW'>;
public customId: string;
@@ -1668,6 +1680,9 @@ export class MessageComponentInteraction<Cached extends CacheType = CacheType> e
public message: GuildCacheMessage<Cached>;
public replied: boolean;
public webhook: InteractionWebhook;
public awaitModalSubmit(
options: AwaitModalSubmitOptions<ModalSubmitInteraction>,
): Promise<ModalSubmitInteraction<Cached>>;
public inGuild(): this is MessageComponentInteraction<'raw' | 'cached'>;
public inCachedGuild(): this is MessageComponentInteraction<'cached'>;
public inRawGuild(): this is MessageComponentInteraction<'raw'>;
@@ -1681,6 +1696,7 @@ export class MessageComponentInteraction<Cached extends CacheType = CacheType> e
public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<GuildCacheMessage<Cached>>;
public reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
public reply(options: string | MessagePayload | InteractionReplyOptions): Promise<void>;
public showModal(modal: Modal | ModalOptions): Promise<void>;
public update(options: InteractionUpdateOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
public update(options: string | MessagePayload | InteractionUpdateOptions): Promise<void>;
@@ -1842,6 +1858,82 @@ export class MessageSelectMenu extends BaseMessageComponent {
public toJSON(): APISelectMenuComponent;
}
export class Modal {
public constructor(data?: Modal | ModalOptions);
public components: MessageActionRow<ModalActionRowComponent>[];
public customId: string | null;
public title: string | null;
public addComponents(
...components: (
| MessageActionRow<ModalActionRowComponent>
| (Required<BaseMessageComponentOptions> & MessageActionRowOptions<ModalActionRowComponentResolvable>)
)[]
): this;
public setComponents(
...components: (
| MessageActionRow<ModalActionRowComponent>
| (Required<BaseMessageComponentOptions> & MessageActionRowOptions<ModalActionRowComponentResolvable>)
)[]
): this;
public setCustomId(customId: string): this;
public spliceComponents(
index: number,
deleteCount: number,
...components: (
| MessageActionRow<ModalActionRowComponent>
| (Required<BaseMessageComponentOptions> & MessageActionRowOptions<ModalActionRowComponentResolvable>)
)[]
): this;
public setTitle(title: string): this;
public toJSON(): RawModalSubmitInteractionData;
}
export class ModalSubmitFieldsResolver {
constructor(components: PartialModalActionRow[]);
private readonly _fields: PartialTextInputData[];
public getField(customId: string): PartialTextInputData;
public getTextInputValue(customId: string): string;
}
export interface ModalMessageModalSubmitInteraction<Cached extends CacheType = CacheType>
extends ModalSubmitInteraction<Cached> {
message: GuildCacheMessage<Cached> | null;
update(options: InteractionUpdateOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
update(options: string | MessagePayload | InteractionUpdateOptions): Promise<void>;
deferUpdate(options: InteractionDeferUpdateOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
deferUpdate(options?: InteractionDeferUpdateOptions): Promise<void>;
inGuild(): this is ModalMessageModalSubmitInteraction<'raw' | 'cached'>;
inCachedGuild(): this is ModalMessageModalSubmitInteraction<'cached'>;
inRawGuild(): this is ModalMessageModalSubmitInteraction<'raw'>;
}
export class ModalSubmitInteraction<Cached extends CacheType = CacheType> extends Interaction<Cached> {
protected constructor(client: Client, data: RawModalSubmitInteractionData);
public customId: string;
public components: PartialModalActionRow[];
public deferred: boolean;
public ephemeral: boolean | null;
public fields: ModalSubmitFieldsResolver;
public replied: false;
public webhook: InteractionWebhook;
public reply(options: InteractionReplyOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
public reply(options: string | MessagePayload | InteractionReplyOptions): Promise<void>;
public deleteReply(): Promise<void>;
public editReply(options: string | MessagePayload | WebhookEditMessageOptions): Promise<GuildCacheMessage<Cached>>;
public deferReply(options: InteractionDeferReplyOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
public deferReply(options?: InteractionDeferReplyOptions): Promise<void>;
public deferUpdate(options: InteractionDeferUpdateOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
public deferUpdate(options?: InteractionDeferUpdateOptions): Promise<void>;
public fetchReply(): Promise<GuildCacheMessage<Cached>>;
public followUp(options: string | MessagePayload | InteractionReplyOptions): Promise<GuildCacheMessage<Cached>>;
public inGuild(): this is ModalSubmitInteraction<'raw' | 'cached'>;
public inCachedGuild(): this is ModalSubmitInteraction<'cached'>;
public inRawGuild(): this is ModalSubmitInteraction<'raw'>;
public isFromMessage(): this is ModalMessageModalSubmitInteraction<Cached>;
public update(options: InteractionUpdateOptions & { fetchReply: true }): Promise<GuildCacheMessage<Cached>>;
public update(options: string | MessagePayload | InteractionUpdateOptions): Promise<void>;
}
export class NewsChannel extends BaseGuildTextChannel {
public threads: ThreadManager<AllowedThreadTypeForNewsChannel>;
public type: 'GUILD_NEWS';
@@ -2319,6 +2411,28 @@ export class TextChannel extends BaseGuildTextChannel {
public setRateLimitPerUser(rateLimitPerUser: number, reason?: string): Promise<TextChannel>;
}
export class TextInputComponent extends BaseMessageComponent {
public constructor(data?: TextInputComponent | TextInputComponentOptions);
public customId: string | null;
public label: string | null;
public required: boolean;
public maxLength: number | null;
public minLength: number | null;
public placeholder: string | null;
public style: TextInputStyle;
public value: string | null;
public setCustomId(customId: string): this;
public setLabel(label: string): this;
public setRequired(required?: boolean): this;
public setMaxLength(maxLength: number): this;
public setMinLength(minLength: number): this;
public setPlaceholder(placeholder: string): this;
public setStyle(style: TextInputStyleResolvable): this;
public setValue(value: string): this;
public toJSON(): RawTextInputComponentData;
public static resolveStyle(style: TextInputStyleResolvable): TextInputStyle;
}
export class ThreadChannel extends TextBasedChannelMixin(Channel) {
private constructor(guild: Guild, data?: RawThreadChannelData, client?: Client, fromInteraction?: boolean);
public archived: boolean | null;
@@ -2865,6 +2979,8 @@ export const Constants: {
InteractionResponseTypes: EnumHolder<typeof InteractionResponseTypes>;
MessageComponentTypes: EnumHolder<typeof MessageComponentTypes>;
MessageButtonStyles: EnumHolder<typeof MessageButtonStyles>;
ModalComponentTypes: EnumHolder<typeof ModalComponentTypes>;
TextInputStyles: EnumHolder<typeof TextInputStyles>;
MFALevels: EnumHolder<typeof MFALevels>;
NSFWLevels: EnumHolder<typeof NSFWLevels>;
PrivacyLevels: EnumHolder<typeof PrivacyLevels>;
@@ -3808,6 +3924,13 @@ export interface AwaitMessagesOptions extends MessageCollectorOptions {
errors?: string[];
}
export type AwaitModalSubmitOptions<T extends ModalSubmitInteraction> = Omit<
ModalSubmitInteractionCollectorOptions<T>,
'max' | 'maxComponents' | 'maxUsers'
> & {
time: number;
};
export interface AwaitReactionsOptions extends ReactionCollectorOptions {
errors?: string[];
}
@@ -4920,11 +5043,6 @@ export interface ImageURLOptions extends Omit<StaticImageURLOptions, 'format'> {
format?: DynamicImageFormat;
}
export interface IntegrationAccount {
id: string | Snowflake;
name: string;
}
export type IntegrationType = 'twitch' | 'youtube' | 'discord';
export interface InteractionCollectorOptions<T extends Interaction, Cached extends CacheType = CacheType>
@@ -5044,10 +5162,26 @@ export type MessageActionRowComponentOptions =
| (Required<BaseMessageComponentOptions> & MessageButtonOptions)
| (Required<BaseMessageComponentOptions> & MessageSelectMenuOptions);
export type MessageActionRowComponentResolvable = MessageActionRowComponent | MessageActionRowComponentOptions;
export type MessageActionRowComponentResolvable =
| MessageActionRowComponent
| MessageActionRowComponentOptions
| APIMessageActionRowComponent;
export interface MessageActionRowOptions extends BaseMessageComponentOptions {
components: MessageActionRowComponentResolvable[];
export type ModalActionRowComponent = TextInputComponent;
export type ModalActionRowComponentOptions = TextInputComponentOptions;
export type ModalActionRowComponentResolvable =
| ModalActionRowComponent
| ModalActionRowComponentOptions
| APIModalActionRowComponent;
export interface MessageActionRowOptions<
T extends
| MessageActionRowComponentResolvable
| ModalActionRowComponentResolvable = MessageActionRowComponentResolvable,
> extends BaseMessageComponentOptions {
components: T[];
}
export interface MessageActivity {
@@ -5084,15 +5218,13 @@ export interface MessageCollectorOptions extends CollectorOptions<[Message]> {
export type MessageComponent = BaseMessageComponent | MessageActionRow | MessageButton | MessageSelectMenu;
export type MessageComponentCollectorOptions<T extends MessageComponentInteraction> = Omit<
export type MessageComponentCollectorOptions<T extends MessageComponentInteraction | ModalSubmitInteraction> = Omit<
InteractionCollectorOptions<T>,
'channel' | 'message' | 'guild' | 'interactionType'
>;
export type MessageChannelComponentCollectorOptions<T extends MessageComponentInteraction> = Omit<
InteractionCollectorOptions<T>,
'channel' | 'guild' | 'interactionType'
>;
export type MessageChannelComponentCollectorOptions<T extends MessageComponentInteraction | ModalSubmitInteraction> =
Omit<InteractionCollectorOptions<T>, 'channel' | 'guild' | 'interactionType'>;
export type MessageComponentOptions =
| BaseMessageComponentOptions
@@ -5276,6 +5408,19 @@ export type MessageType = keyof typeof MessageTypes;
export type MFALevel = keyof typeof MFALevels;
export interface ModalOptions {
components:
| MessageActionRow<ModalActionRowComponent>[]
| MessageActionRowOptions<ModalActionRowComponentResolvable>[];
customId: string;
title: string;
}
export type ModalSubmitInteractionCollectorOptions<T extends ModalSubmitInteraction> = Omit<
InteractionCollectorOptions<T>,
'channel' | 'message' | 'guild' | 'interactionType'
>;
export interface MultipleShardRespawnOptions {
shardDelay?: number;
respawnDelay?: number;
@@ -5301,6 +5446,18 @@ export type OverwriteResolvable = PermissionOverwrites | OverwriteData;
export type OverwriteType = 'member' | 'role';
export interface PartialModalActionRow {
type: MessageComponentType;
components: PartialTextInputData[];
}
export interface PartialTextInputData {
value: string;
// TODO: use dapi types
type: MessageComponentType;
customId: string;
}
export type PermissionFlags = Record<PermissionString, bigint>;
export type PermissionOverwriteOptions = Partial<Record<PermissionString, boolean | null>>;
@@ -5647,6 +5804,25 @@ export type TextBasedChannel = Extract<AnyChannel, { messages: MessageManager }>
export type TextBasedChannelTypes = TextBasedChannel['type'];
export interface TextInputComponentOptions extends BaseMessageComponentOptions {
customId?: string;
label?: string;
minLength?: number;
maxLength?: number;
placeholder?: string;
required?: boolean;
style?: TextInputStyleResolvable;
value?: string;
}
export type TextInputStyle = keyof typeof TextInputStyles;
export type TextInputStyleResolvable = TextInputStyle | TextInputStyles;
export interface IntegrationAccount {
id: string | Snowflake;
name: string;
}
export type VoiceBasedChannel = Extract<AnyChannel, { bitrate: number }>;
export type GuildBasedChannel = Extract<AnyChannel, { guild: Guild }>;

View File

@@ -679,6 +679,8 @@ client.on('interaction', async interaction => {
void new MessageActionRow();
void new MessageActionRow({});
const button = new MessageButton();
const actionRow = new MessageActionRow({ components: [button] });
@@ -688,9 +690,6 @@ client.on('interaction', async interaction => {
// @ts-expect-error
interaction.reply({ content: 'Hi!', components: [[button]] });
// @ts-expect-error
void new MessageActionRow({});
// @ts-expect-error
await interaction.reply({ content: 'Hi!', components: [button] });

View File

@@ -76,8 +76,13 @@ import {
RESTPostAPIWebhookWithTokenJSONBody,
Snowflake,
APIGuildScheduledEvent,
APIActionRowComponent,
APITextInputComponent,
APIModalActionRowComponent,
APIModalSubmitInteraction,
} from 'discord-api-types/v9';
import { GuildChannel, Guild, PermissionOverwrites } from '.';
import { GuildChannel, Guild, PermissionOverwrites, InteractionType } from '.';
import type { InteractionTypes, MessageComponentTypes } from './enums';
export type RawActivityData = GatewayActivity;
@@ -141,6 +146,9 @@ export type RawMessageComponentInteractionData = APIMessageComponentInteraction;
export type RawMessageButtonInteractionData = APIMessageButtonInteractionData;
export type RawMessageSelectMenuInteractionData = APIMessageSelectMenuInteractionData;
export type RawTextInputComponentData = APITextInputComponent;
export type RawModalSubmitInteractionData = APIModalSubmitInteraction;
export type RawInviteData =
| APIExtendedInvite
| APIInvite