diff --git a/packages/discord.js/src/errors/ErrorCodes.js b/packages/discord.js/src/errors/ErrorCodes.js index ec0c56386..8594339c9 100644 --- a/packages/discord.js/src/errors/ErrorCodes.js +++ b/packages/discord.js/src/errors/ErrorCodes.js @@ -168,6 +168,8 @@ * @property {'ModalSubmitInteractionFieldNotFound'} ModalSubmitInteractionFieldNotFound * @property {'ModalSubmitInteractionFieldType'} ModalSubmitInteractionFieldType + * @property {'ModalSubmitInteractionFieldEmpty'} ModalSubmitInteractionFieldEmpty + * @property {'ModalSubmitInteractionFieldInvalidChannelType'} ModalSubmitInteractionFieldInvalidChannelType * @property {'InvalidMissingScopes'} InvalidMissingScopes * @property {'InvalidScopesWithPermissions'} InvalidScopesWithPermissions @@ -327,6 +329,8 @@ const keys = [ 'ModalSubmitInteractionFieldNotFound', 'ModalSubmitInteractionFieldType', + 'ModalSubmitInteractionFieldEmpty', + 'ModalSubmitInteractionFieldInvalidChannelType', 'InvalidMissingScopes', 'InvalidScopesWithPermissions', diff --git a/packages/discord.js/src/errors/Messages.js b/packages/discord.js/src/errors/Messages.js index 03e9a1c4f..3c09f7abf 100644 --- a/packages/discord.js/src/errors/Messages.js +++ b/packages/discord.js/src/errors/Messages.js @@ -161,6 +161,10 @@ const Messages = { `Required field with custom id "${customId}" not found.`, [DjsErrorCodes.ModalSubmitInteractionFieldType]: (customId, type, expected) => `Field with custom id "${customId}" is of type: ${type}; expected ${expected}.`, + [DjsErrorCodes.ModalSubmitInteractionFieldEmpty]: (customId, type) => + `Required field with custom id "${customId}" is of type: ${type}; expected a non-empty value.`, + [DjsErrorCodes.ModalSubmitInteractionFieldInvalidChannelType]: (customId, type, expected) => + `The type of channel of the field with custom id "${customId}" is: ${type}; expected ${expected}.`, [DjsErrorCodes.InvalidMissingScopes]: 'At least one valid scope must be provided for the invite', [DjsErrorCodes.InvalidScopesWithPermissions]: 'Permissions cannot be set without the bot scope.', diff --git a/packages/discord.js/src/structures/CommandInteraction.js b/packages/discord.js/src/structures/CommandInteraction.js index 2951a55f2..5d61e8317 100644 --- a/packages/discord.js/src/structures/CommandInteraction.js +++ b/packages/discord.js/src/structures/CommandInteraction.js @@ -80,12 +80,17 @@ class CommandInteraction extends BaseInteraction { } /** - * Represents the resolved data of a received command interaction. - * @typedef {Object} CommandInteractionResolvedData + * @typedef {Object} BaseInteractionResolvedData * @property {Collection} [users] The resolved users * @property {Collection} [members] The resolved guild members * @property {Collection} [roles] The resolved roles * @property {Collection} [channels] The resolved channels + */ + + /** + * Represents the resolved data of a received command interaction. + * + * @typedef {BaseInteractionResolvedData} CommandInteractionResolvedData * @property {Collection} [messages] The resolved messages * @property {Collection} [attachments] The resolved attachments */ diff --git a/packages/discord.js/src/structures/Message.js b/packages/discord.js/src/structures/Message.js index de9bf5386..71ac76895 100644 --- a/packages/discord.js/src/structures/Message.js +++ b/packages/discord.js/src/structures/Message.js @@ -623,7 +623,7 @@ class Message extends Base { * Similar to createReactionCollector but in promise form. * Resolves with a collection of reactions that pass the specified filter. * @param {AwaitReactionsOptions} [options={}] Optional options to pass to the internal collector - * @returns {Promise>} + * @returns {Promise>} * @example * // Create a reaction collector * const filter = (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someId' diff --git a/packages/discord.js/src/structures/ModalSubmitFields.js b/packages/discord.js/src/structures/ModalSubmitFields.js index af44499fd..419265853 100644 --- a/packages/discord.js/src/structures/ModalSubmitFields.js +++ b/packages/discord.js/src/structures/ModalSubmitFields.js @@ -4,29 +4,44 @@ const { Collection } = require('@discordjs/collection'); const { ComponentType } = require('discord-api-types/v10'); const { DiscordjsTypeError, ErrorCodes } = require('../errors'); +/** + * @typedef {Object} ModalSelectedMentionables + * @property {Collection} users The selected users + * @property {Collection} members The selected members + * @property {Collection} roles The selected roles + */ + /** * Represents the serialized fields from a modal submit interaction */ class ModalSubmitFields { - constructor(components) { + constructor(components, resolved) { /** * The components within the modal * - * @type {Array} + * @type {Array} */ this.components = components; + /** + * The interaction resolved data + * + * @name ModalSubmitFields#resolved + * @type {?Readonly} + */ + Object.defineProperty(this, 'resolved', { value: resolved ? Object.freeze(resolved) : null }); + /** * The extracted fields from the modal * @type {Collection} */ this.fields = components.reduce((accumulator, next) => { - // NOTE: for legacy support of action rows in modals, which has `components` + // For legacy support of action rows if ('components' in next) { for (const component of next.components) accumulator.set(component.customId, component); } - // For label component + // For label components if ('component' in next) { accumulator.set(next.component.customId, next.component); } @@ -52,13 +67,39 @@ class ModalSubmitFields { return field; } + /** + * Gets a component by custom id and property and checks its type. + * + * @param {string} customId The custom id of the component. + * @param {ComponentType[]} allowedTypes The allowed types of the component. + * @param {string[]} properties The properties to check for for `required`. + * @param {boolean} required Whether to throw an error if the component value(s) are not found. + * @returns {ModalData} The option, if found. + * @private + */ + _getTypedComponent(customId, allowedTypes, properties, required) { + const component = this.getField(customId); + if (!allowedTypes.includes(component.type)) { + throw new DiscordjsTypeError( + ErrorCodes.ModalSubmitInteractionFieldNotFound, + customId, + component.type, + allowedTypes.join(', '), + ); + } else if (required && properties.every(prop => component[prop] === null || component[prop] === undefined)) { + throw new DiscordjsTypeError(ErrorCodes.ModalSubmitInteractionFieldEmpty, customId, component.type); + } + + return component; + } + /** * Gets the value of a text input component given a custom id * @param {string} customId The custom id of the text input component * @returns {string} */ getTextInputValue(customId) { - return this.getField(customId, ComponentType.TextInput).value; + return this._getTypedComponent(customId, [ComponentType.TextInput]).value; } /** @@ -68,7 +109,112 @@ class ModalSubmitFields { * @returns {string[]} */ getStringSelectValues(customId) { - return this.getField(customId, ComponentType.StringSelect).values; + return this._getTypedComponent(customId, [ComponentType.StringSelect]).values; + } + + /** + * Gets users component + * + * @param {string} customId The custom id of the component + * @param {boolean} [required=false] Whether to throw an error if the component value is not found or empty + * @returns {?Collection} The selected users, or null if none were selected and not required + */ + getSelectedUsers(customId, required = false) { + const component = this._getTypedComponent( + customId, + [ComponentType.UserSelect, ComponentType.MentionableSelect], + ['users'], + required, + ); + return component.users ?? null; + } + + /** + * Gets roles component + * + * @param {string} customId The custom id of the component + * @param {boolean} [required=false] Whether to throw an error if the component value is not found or empty + * @returns {?Collection} The selected roles, or null if none were selected and not required + */ + getSelectedRoles(customId, required = false) { + const component = this._getTypedComponent( + customId, + [ComponentType.RoleSelect, ComponentType.MentionableSelect], + ['roles'], + required, + ); + return component.roles ?? null; + } + + /** + * Gets channels component + * + * @param {string} customId The custom id of the component + * @param {boolean} [required=false] Whether to throw an error if the component value is not found or empty + * @param {ChannelType[]} [channelTypes=[]] The allowed types of channels. If empty, all channel types are allowed. + * @returns {?Collection} The selected channels, + * or null if none were selected and not required + */ + getSelectedChannels(customId, required = false, channelTypes = []) { + const component = this._getTypedComponent(customId, [ComponentType.ChannelSelect], ['channels'], required); + const channels = component.channels; + if (channels && channelTypes.length > 0) { + for (const channel of channels.values()) { + if (!channelTypes.includes(channel.type)) { + throw new DiscordjsTypeError( + ErrorCodes.ModalSubmitInteractionComponentInvalidChannelType, + customId, + channel.type, + channelTypes.join(', '), + ); + } + } + } + + return channels ?? null; + } + + /** + * Gets members component + * + * @param {string} customId The custom id of the component + * @returns {?Collection} The selected members, + * or null if none were selected or the users were not present in the guild + */ + getSelectedMembers(customId) { + const component = this._getTypedComponent( + customId, + [ComponentType.UserSelect, ComponentType.MentionableSelect], + ['members'], + false, + ); + return component.members ?? null; + } + + /** + * Gets mentionables component + * + * @param {string} customId The custom id of the component + * @param {boolean} [required=false] Whether to throw an error if the component value is not found or empty + * @returns {?ModalSelectedMentionables} The selected mentionables, or null if none were selected and not required + */ + getSelectedMentionables(customId, required = false) { + const component = this._getTypedComponent( + customId, + [ComponentType.MentionableSelect], + ['users', 'members', 'roles'], + required, + ); + + if (component.users || component.members || component.roles) { + return { + users: component.users ?? new Collection(), + members: component.members ?? new Collection(), + roles: component.roles ?? new Collection(), + }; + } + + return null; } } diff --git a/packages/discord.js/src/structures/ModalSubmitInteraction.js b/packages/discord.js/src/structures/ModalSubmitInteraction.js index 79a7a6987..f7239cf8d 100644 --- a/packages/discord.js/src/structures/ModalSubmitInteraction.js +++ b/packages/discord.js/src/structures/ModalSubmitInteraction.js @@ -1,46 +1,53 @@ 'use strict'; +const { Collection } = require('@discordjs/collection'); const { lazy } = require('@discordjs/util'); const BaseInteraction = require('./BaseInteraction'); const InteractionWebhook = require('./InteractionWebhook'); const ModalSubmitFields = require('./ModalSubmitFields'); const InteractionResponses = require('./interfaces/InteractionResponses'); +const { transformResolved } = require('../util/Util'); const getMessage = lazy(() => require('./Message').Message); /** * @typedef {Object} BaseModalData * @property {ComponentType} type The component type of the field - * @property {string} customId The custom id of the field * @property {number} id The id of the field */ /** * @typedef {BaseModalData} TextInputModalData + * @property {string} customId The custom id of the field * @property {string} value The value of the field */ /** - * @typedef {BaseModalData} StringSelectModalData + * @typedef {BaseModalData} SelectMenuModalData + * @property {string} customId The custom id of the field * @property {string[]} values The values of the field + * @property {Collection} [members] The resolved members + * @property {Collection} [users] The resolved users + * @property {Collection} [roles] The resolved roles + * @property {Collection} [channels] The resolved channels */ /** - * @typedef {TextInputModalData | StringSelectModalData} ModalData + * @typedef {BaseModalData} TextDisplayModalData */ /** - * @typedef {Object} LabelModalData + * @typedef {SelectMenuModalData|TextInputModalData} ModalData + */ + +/** + * @typedef {BaseModalData} LabelModalData * @property {ModalData} component The component within the label - * @property {ComponentType} type The component type of the label - * @property {number} id The id of the label */ /** - * @typedef {Object} ActionRowModalData + * @typedef {BaseModalData} ActionRowModalData * @property {TextInputModalData[]} components The components of this action row - * @property {ComponentType} type The component type of the action row - * @property {number} id The id of the action row */ /** @@ -70,15 +77,20 @@ class ModalSubmitInteraction extends BaseInteraction { /** * The components within the modal * - * @type {Array} + * @type {Array} */ - this.components = data.data.components?.map(component => ModalSubmitInteraction.transformComponent(component)); + this.components = data.data.components?.map(component => + ModalSubmitInteraction.transformComponent(component, data.data.resolved), + ); /** * The fields within the modal * @type {ModalSubmitFields} */ - this.fields = new ModalSubmitFields(this.components); + this.fields = new ModalSubmitFields( + this.components, + transformResolved({ client: this.client, guild: this.guild, channel: this.channel }, data.data.resolved), + ); /** * Whether the reply to this interaction has been deferred @@ -108,14 +120,15 @@ class ModalSubmitInteraction extends BaseInteraction { /** * Transforms component data to discord.js-compatible data * @param {*} rawComponent The data to transform + * @param {APIInteractionDataResolved} [resolved] The resolved data for the interaction * @returns {ModalData[]} */ - static transformComponent(rawComponent) { + static transformComponent(rawComponent, resolved) { if ('components' in rawComponent) { return { type: rawComponent.type, id: rawComponent.id, - components: rawComponent.components.map(component => this.transformComponent(component)), + components: rawComponent.components.map(component => this.transformComponent(component, resolved)), }; } @@ -123,18 +136,50 @@ class ModalSubmitInteraction extends BaseInteraction { return { type: rawComponent.type, id: rawComponent.id, - component: this.transformComponent(rawComponent.component), + component: this.transformComponent(rawComponent.component, resolved), }; } const data = { type: rawComponent.type, - customId: rawComponent.custom_id, id: rawComponent.id, }; + // Text display components do not have custom ids. + if (rawComponent.custom_id) data.customId = rawComponent.custom_id; + if (rawComponent.value) data.value = rawComponent.value; - if (rawComponent.values) data.values = rawComponent.values; + + if (rawComponent.values) { + data.values = rawComponent.values; + if (resolved) { + const resolveCollection = (resolvedData, resolver) => { + const collection = new Collection(); + for (const value of data.values) { + if (resolvedData?.[value]) { + collection.set(value, resolver(resolvedData[value])); + } + } + + return collection.size ? collection : null; + }; + + const users = resolveCollection(resolved.users, user => this.client.users._add(user)); + if (users) data.users = users; + + const channels = resolveCollection( + resolved.channels, + channel => this.client.channels._add(channel, this.guild) ?? channel, + ); + if (channels) data.channels = channels; + + const members = resolveCollection(resolved.members, member => this.guild?.members._add(member) ?? member); + if (members) data.members = members; + + const roles = resolveCollection(resolved.roles, role => this.guild?.roles._add(role) ?? role); + if (roles) data.roles = roles; + } + } return data; } diff --git a/packages/discord.js/src/util/APITypes.js b/packages/discord.js/src/util/APITypes.js index 8ad10cc1f..ae9c35012 100644 --- a/packages/discord.js/src/util/APITypes.js +++ b/packages/discord.js/src/util/APITypes.js @@ -245,6 +245,11 @@ * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APISelectMenuOption} */ +/** + * @external APISelectMenuDefaultValue + * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APISelectMenuDefaultValue} + */ + /** * @external APISticker * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APISticker} diff --git a/packages/discord.js/src/util/Components.js b/packages/discord.js/src/util/Components.js index f8a40da08..b75f2945b 100644 --- a/packages/discord.js/src/util/Components.js +++ b/packages/discord.js/src/util/Components.js @@ -18,14 +18,19 @@ const { ComponentType } = require('discord-api-types/v10'); * @typedef {Object} ModalComponentData * @property {string} title The title of the modal * @property {string} customId The custom id of the modal - * @property {Array} components The components within this modal + * @property {Array} components The components within this modal + */ + +/** + * @typedef {StringSelectMenuComponentData|TextInputComponentData|UserSelectMenuComponentData| + * RoleSelectMenuComponentData|MentionableSelectMenuComponentData|ChannelSelectMenuComponentData} ComponentInLabelData */ /** * @typedef {BaseComponentData} LabelData * @property {string} label The label to use * @property {string} [description] The optional description for the label - * @property {StringSelectMenuComponentData|TextInputComponentData} component The component within the label + * @property {ComponentInLabelData} component The component within the label */ /** @@ -39,16 +44,41 @@ const { ComponentType } = require('discord-api-types/v10'); */ /** - * @typedef {BaseComponentData} StringSelectMenuComponentData + * @typedef {BaseComponentData} BaseSelectMenuComponentData * @property {string} customId The custom id of the select menu * @property {boolean} [disabled] Whether the select menu is disabled or not * @property {number} [maxValues] The maximum amount of options that can be selected * @property {number} [minValues] The minimum amount of options that can be selected - * @property {SelectMenuComponentOptionData[]} [options] The options in this select menu * @property {string} [placeholder] The placeholder of the select menu * @property {boolean} [required] Whether this component is required in modals */ +/** + * @typedef {BaseSelectMenuComponentData} StringSelectMenuComponentData + * @property {SelectMenuComponentOptionData[]} [options] The options in this select menu + */ + +/** + * @typedef {BaseSelectMenuComponentData} UserSelectMenuComponentData + * @property {APISelectMenuDefaultValue[]} [defaultValues] The default selected values in this select menu + */ + +/** + * @typedef {BaseSelectMenuComponentData} RoleSelectMenuComponentData + * @property {APISelectMenuDefaultValue[]} [defaultValues] The default selected values in this select menu + */ + +/** + * @typedef {BaseSelectMenuComponentData} MentionableSelectMenuComponentData + * @property {APISelectMenuDefaultValue[]} [defaultValues] The default selected values in this select menu + */ + +/** + * @typedef {BaseSelectMenuComponentData} ChannelSelectMenuComponentData + * @property {APISelectMenuDefaultValue[]} [defaultValues] The default selected values in this select menu + * @property {ChannelType[]} [channelTypes] The types of channels that can be selected + */ + /** * @typedef {object} SelectMenuComponentOptionData * @property {string} label The label of the option diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index b256e3aac..46da36cc4 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -353,7 +353,13 @@ export class ActionRowBuilder< ): ActionRowBuilder; } -export type ComponentInLabelData = StringSelectMenuComponentData | TextInputComponentData; +export type ComponentInLabelData = + | StringSelectMenuComponentData + | TextInputComponentData + | UserSelectMenuComponentData + | ChannelSelectMenuComponentData + | RoleSelectMenuComponentData + | MentionableSelectMenuComponentData; export interface LabelData extends BaseComponentData { component: ComponentInLabelData; @@ -2775,46 +2781,116 @@ export interface ModalComponentData { | JSONEncodable | APILabelComponent> | ActionRowData | LabelData + | TextDisplayComponentData )[]; } export interface BaseModalData { - customId: string; id: number; type: Type; } export interface TextInputModalData extends BaseModalData { + customId: string; value: string; } -export interface StringSelectModalData extends BaseModalData { +export interface SelectMenuModalData + extends BaseModalData< + | ComponentType.ChannelSelect + | ComponentType.MentionableSelect + | ComponentType.RoleSelect + | ComponentType.StringSelect + | ComponentType.UserSelect + > { + channels?: ReadonlyCollection< + Snowflake, + CacheTypeReducer + >; + customId: string; + members?: ReadonlyCollection>; + roles?: ReadonlyCollection>; + users?: ReadonlyCollection; values: readonly string[]; } -export type ModalData = StringSelectModalData | TextInputModalData; +export type ModalData = SelectMenuModalData | TextInputModalData; -export interface LabelModalData { +export interface LabelModalData extends BaseModalData { component: readonly ModalData[]; - id: number; - type: ComponentType.Label; } -export interface ActionRowModalData { - type: ComponentType.ActionRow; +export interface ActionRowModalData extends BaseModalData { components: readonly TextInputModalData[]; } -export class ModalSubmitFields { - private constructor(components: readonly (ActionRowModalData | LabelModalData)[]); - public components: (ActionRowModalData | LabelModalData)[]; - public fields: Collection; - public getField( +export interface TextDisplayModalData extends BaseModalData {} + +export interface ModalSelectedMentionables { + members: NonNullable['members']>; + roles: NonNullable['roles']>; + users: NonNullable['users']>; +} + +export class ModalSubmitFields { + private constructor( + components: readonly (ActionRowModalData | LabelModalData | TextDisplayModalData)[], + resolved?: BaseInteractionResolvedData, + ); + public components: (ActionRowModalData | LabelModalData | TextDisplayModalData)[]; + public resolved: Readonly> | null; + public fields: Collection; + public getField(customId: string, type: Type): Extract; + public getField(customId: string, type?: ComponentType): ModalData; + private _getTypedComponent( customId: string, - type: Type, - ): { type: Type } & (StringSelectModalData | TextInputModalData); - public getField(customId: string, type?: ComponentType): StringSelectModalData | TextInputModalData; + allowedTypes: readonly ComponentType[], + properties: string, + required: boolean, + ): ModalData; public getTextInputValue(customId: string): string; public getStringSelectValues(customId: string): readonly string[]; + public getSelectedUsers(customId: string, required: true): ReadonlyCollection; + public getSelectedUsers(customId: string, required?: boolean): ReadonlyCollection | null; + public getSelectedMembers(customId: string): NonNullable['members']> | null; + public getSelectedChannels( + customId: string, + required: true, + channelTypes?: readonly Type[], + ): ReadonlyCollection< + Snowflake, + Extract< + NonNullable['channel']>, + { + type: Type extends ChannelType.AnnouncementThread | ChannelType.PublicThread + ? ChannelType.AnnouncementThread | ChannelType.PublicThread + : Type; + } + > + >; + public getSelectedChannels( + customId: string, + required?: boolean, + channelTypes?: readonly Type[], + ): ReadonlyCollection< + Snowflake, + Extract< + NonNullable['channel']>, + { + type: Type extends ChannelType.AnnouncementThread | ChannelType.PublicThread + ? ChannelType.AnnouncementThread | ChannelType.PublicThread + : Type; + } + > + > | null; + + public getSelectedRoles(customId: string, required: true): NonNullable['roles']>; + public getSelectedRoles( + customId: string, + required?: boolean, + ): NonNullable['roles']> | null; + + public getSelectedMentionables(customId: string, required: true): ModalSelectedMentionables; + public getSelectedMentionables(customId: string, required?: boolean): ModalSelectedMentionables | null; } export interface ModalMessageModalSubmitInteraction @@ -2839,7 +2915,7 @@ export class ModalSubmitInteraction extend public type: InteractionType.ModalSubmit; public readonly customId: string; public readonly components: (ActionRowModalData | LabelModalData)[]; - public readonly fields: ModalSubmitFields; + public readonly fields: ModalSubmitFields; public deferred: boolean; public ephemeral: boolean | null; public message: Message> | null; @@ -4556,6 +4632,8 @@ export enum DiscordjsErrorCodes { ModalSubmitInteractionFieldNotFound = 'ModalSubmitInteractionFieldNotFound', ModalSubmitInteractionFieldType = 'ModalSubmitInteractionFieldType', + ModalSubmitInteractionFieldEmpty = 'ModalSubmitInteractionComponentEmpty', + ModalSubmitInteractionFieldInvalidChannelType = 'ModalSubmitInteractionFieldInvalidChannelType', InvalidMissingScopes = 'InvalidMissingScopes', InvalidScopesWithPermissions = 'InvalidScopesWithPermissions', @@ -6095,13 +6173,17 @@ export interface CommandInteractionOption message?: Message>; } -export interface CommandInteractionResolvedData { - users?: ReadonlyCollection; +export interface BaseInteractionResolvedData { + channels?: ReadonlyCollection>; members?: ReadonlyCollection>; roles?: ReadonlyCollection>; - channels?: ReadonlyCollection>; - messages?: ReadonlyCollection>; + users?: ReadonlyCollection; +} + +export interface CommandInteractionResolvedData + extends BaseInteractionResolvedData { attachments?: ReadonlyCollection; + messages?: ReadonlyCollection>; } export interface AutocompleteFocusedOption extends Pick { @@ -7266,12 +7348,12 @@ export interface BaseSelectMenuComponentData extends BaseComponentData { maxValues?: number; minValues?: number; placeholder?: string; + required?: true; } export interface StringSelectMenuComponentData extends BaseSelectMenuComponentData { type: ComponentType.StringSelect; options: readonly SelectMenuComponentOptionData[]; - required?: boolean; } export interface UserSelectMenuComponentData extends BaseSelectMenuComponentData { diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts index f64e54c9c..c89ce65a1 100644 --- a/packages/discord.js/typings/index.test-d.ts +++ b/packages/discord.js/typings/index.test-d.ts @@ -2568,13 +2568,13 @@ chatInputInteraction.showModal({ chatInputInteraction.showModal({ title: 'abc', - custom_id: 'abc', + customId: 'abc', components: [ { type: ComponentType.Label, label: 'label', component: { - custom_id: 'aa', + customId: 'aa', type: ComponentType.TextInput, style: TextInputStyle.Short, label: 'label', @@ -2583,7 +2583,7 @@ chatInputInteraction.showModal({ { components: [ { - custom_id: 'aa', + customId: 'aa', label: 'label', style: TextInputStyle.Short, type: ComponentType.TextInput, @@ -2591,6 +2591,31 @@ chatInputInteraction.showModal({ ], type: ComponentType.ActionRow, }, + { + type: ComponentType.Label, + label: 'Lll', + component: { + customId: 'aa', + type: ComponentType.UserSelect, + }, + }, + { + type: ComponentType.Label, + label: 'Lll', + component: { + customId: 'aa', + type: ComponentType.ChannelSelect, + channelTypes: [ChannelType.GuildText, ChannelType.GuildVoice], + }, + }, + { + type: ComponentType.Label, + label: 'Lll', + component: { + customId: 'aa', + type: ComponentType.RoleSelect, + }, + }, ], });