mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-09 16:13:31 +01:00
feat!: text display and other select menus for modal (#11097)
BREAKING CHANGE: `ModalSubmitFields` is no longer exported BREAKING CHANGE: `ModalSubmitInteraction#fields` is removed BREAKING CHANGE: `ModalSubmitInteraction#components` is now `ModalOptionResolver` BREAKING CHANGE: `DjsErrorCodes#ModalSubmitInteractionFieldNotFound` & `DjsErrorCodes#ModalSubmitInteractionFieldType` are now renamed to `DjsErrorCodes#ModalSubmitInteractionComponentNotFound` & `DjsErrorCodes#ModalSubmitInteractionComponentType` respectively --------- Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
This commit is contained in:
@@ -114,8 +114,10 @@
|
|||||||
* @property {'CommandInteractionOptionInvalidChannelType'} CommandInteractionOptionInvalidChannelType
|
* @property {'CommandInteractionOptionInvalidChannelType'} CommandInteractionOptionInvalidChannelType
|
||||||
* @property {'AutocompleteInteractionOptionNoFocusedOption'} AutocompleteInteractionOptionNoFocusedOption
|
* @property {'AutocompleteInteractionOptionNoFocusedOption'} AutocompleteInteractionOptionNoFocusedOption
|
||||||
*
|
*
|
||||||
* @property {'ModalSubmitInteractionFieldNotFound'} ModalSubmitInteractionFieldNotFound
|
* @property {'ModalSubmitInteractionComponentNotFound'} ModalSubmitInteractionComponentNotFound
|
||||||
* @property {'ModalSubmitInteractionFieldType'} ModalSubmitInteractionFieldType
|
* @property {'ModalSubmitInteractionComponentType'} ModalSubmitInteractionComponentType
|
||||||
|
* @property {'ModalSubmitInteractionComponentEmpty'} ModalSubmitInteractionComponentEmpty
|
||||||
|
* @property {'ModalSubmitInteractionComponentInvalidChannelType'} ModalSubmitInteractionComponentInvalidChannelType
|
||||||
*
|
*
|
||||||
* @property {'InvalidMissingScopes'} InvalidMissingScopes
|
* @property {'InvalidMissingScopes'} InvalidMissingScopes
|
||||||
* @property {'InvalidScopesWithPermissions'} InvalidScopesWithPermissions
|
* @property {'InvalidScopesWithPermissions'} InvalidScopesWithPermissions
|
||||||
@@ -248,8 +250,10 @@ const keys = [
|
|||||||
'CommandInteractionOptionInvalidChannelType',
|
'CommandInteractionOptionInvalidChannelType',
|
||||||
'AutocompleteInteractionOptionNoFocusedOption',
|
'AutocompleteInteractionOptionNoFocusedOption',
|
||||||
|
|
||||||
'ModalSubmitInteractionFieldNotFound',
|
'ModalSubmitInteractionComponentNotFound',
|
||||||
'ModalSubmitInteractionFieldType',
|
'ModalSubmitInteractionComponentType',
|
||||||
|
'ModalSubmitInteractionComponentEmpty',
|
||||||
|
'ModalSubmitInteractionComponentInvalidChannelType',
|
||||||
|
|
||||||
'InvalidMissingScopes',
|
'InvalidMissingScopes',
|
||||||
'InvalidScopesWithPermissions',
|
'InvalidScopesWithPermissions',
|
||||||
|
|||||||
@@ -127,10 +127,14 @@ const Messages = {
|
|||||||
`The type of channel of the option "${name}" is: ${type}; expected ${expected}.`,
|
`The type of channel of the option "${name}" is: ${type}; expected ${expected}.`,
|
||||||
[ErrorCodes.AutocompleteInteractionOptionNoFocusedOption]: 'No focused option for autocomplete interaction.',
|
[ErrorCodes.AutocompleteInteractionOptionNoFocusedOption]: 'No focused option for autocomplete interaction.',
|
||||||
|
|
||||||
[ErrorCodes.ModalSubmitInteractionFieldNotFound]: customId =>
|
[ErrorCodes.ModalSubmitInteractionComponentNotFound]: customId =>
|
||||||
`Required field with custom id "${customId}" not found.`,
|
`Required component with custom id "${customId}" not found.`,
|
||||||
[ErrorCodes.ModalSubmitInteractionFieldType]: (customId, type, expected) =>
|
[ErrorCodes.ModalSubmitInteractionComponentType]: (customId, type, expected) =>
|
||||||
`Field with custom id "${customId}" is of type: ${type}; expected ${expected}.`,
|
`Component with custom id "${customId}" is of type: ${type}; expected ${expected}.`,
|
||||||
|
[ErrorCodes.ModalSubmitInteractionComponentEmpty]: (customId, type) =>
|
||||||
|
`Required component with custom id "${customId}" is of type: ${type}; expected a non-empty value.`,
|
||||||
|
[ErrorCodes.ModalSubmitInteractionComponentInvalidChannelType]: (customId, type, expected) =>
|
||||||
|
`The type of channel of the component with custom id "${customId}" is: ${type}; expected ${expected}.`,
|
||||||
|
|
||||||
[ErrorCodes.InvalidMissingScopes]: 'At least one valid scope must be provided for the invite',
|
[ErrorCodes.InvalidMissingScopes]: 'At least one valid scope must be provided for the invite',
|
||||||
[ErrorCodes.InvalidScopesWithPermissions]: 'Permissions cannot be set without the bot scope.',
|
[ErrorCodes.InvalidScopesWithPermissions]: 'Permissions cannot be set without the bot scope.',
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ exports.MessageContextMenuCommandInteraction =
|
|||||||
exports.MessageMentions = require('./structures/MessageMentions.js').MessageMentions;
|
exports.MessageMentions = require('./structures/MessageMentions.js').MessageMentions;
|
||||||
exports.MessagePayload = require('./structures/MessagePayload.js').MessagePayload;
|
exports.MessagePayload = require('./structures/MessagePayload.js').MessagePayload;
|
||||||
exports.MessageReaction = require('./structures/MessageReaction.js').MessageReaction;
|
exports.MessageReaction = require('./structures/MessageReaction.js').MessageReaction;
|
||||||
exports.ModalSubmitFields = require('./structures/ModalSubmitFields.js').ModalSubmitFields;
|
exports.ModalComponentResolver = require('./structures/ModalComponentResolver.js').ModalComponentResolver;
|
||||||
exports.ModalSubmitInteraction = require('./structures/ModalSubmitInteraction.js').ModalSubmitInteraction;
|
exports.ModalSubmitInteraction = require('./structures/ModalSubmitInteraction.js').ModalSubmitInteraction;
|
||||||
exports.OAuth2Guild = require('./structures/OAuth2Guild.js').OAuth2Guild;
|
exports.OAuth2Guild = require('./structures/OAuth2Guild.js').OAuth2Guild;
|
||||||
exports.PartialGroupDMChannel = require('./structures/PartialGroupDMChannel.js').PartialGroupDMChannel;
|
exports.PartialGroupDMChannel = require('./structures/PartialGroupDMChannel.js').PartialGroupDMChannel;
|
||||||
|
|||||||
@@ -91,13 +91,17 @@ class CommandInteraction extends BaseInteraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the resolved data of a received command interaction.
|
* @typedef {Object} BaseInteractionResolvedData
|
||||||
*
|
|
||||||
* @typedef {Object} CommandInteractionResolvedData
|
|
||||||
* @property {Collection<Snowflake, User>} [users] The resolved users
|
* @property {Collection<Snowflake, User>} [users] The resolved users
|
||||||
* @property {Collection<Snowflake, GuildMember|APIGuildMember>} [members] The resolved guild members
|
* @property {Collection<Snowflake, GuildMember|APIGuildMember>} [members] The resolved guild members
|
||||||
* @property {Collection<Snowflake, Role|APIRole>} [roles] The resolved roles
|
* @property {Collection<Snowflake, Role|APIRole>} [roles] The resolved roles
|
||||||
* @property {Collection<Snowflake, BaseChannel|APIChannel>} [channels] The resolved channels
|
* @property {Collection<Snowflake, BaseChannel|APIChannel>} [channels] The resolved channels
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the resolved data of a received command interaction.
|
||||||
|
*
|
||||||
|
* @typedef {BaseInteractionResolvedData} CommandInteractionResolvedData
|
||||||
* @property {Collection<Snowflake, Message|APIMessage>} [messages] The resolved messages
|
* @property {Collection<Snowflake, Message|APIMessage>} [messages] The resolved messages
|
||||||
* @property {Collection<Snowflake, Attachment>} [attachments] The resolved attachments
|
* @property {Collection<Snowflake, Attachment>} [attachments] The resolved attachments
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -634,7 +634,7 @@ class Message extends Base {
|
|||||||
* Resolves with a collection of reactions that pass the specified filter.
|
* Resolves with a collection of reactions that pass the specified filter.
|
||||||
*
|
*
|
||||||
* @param {AwaitReactionsOptions} [options={}] Optional options to pass to the internal collector
|
* @param {AwaitReactionsOptions} [options={}] Optional options to pass to the internal collector
|
||||||
* @returns {Promise<Collection<string | Snowflake, MessageReaction>>}
|
* @returns {Promise<Collection<string|Snowflake, MessageReaction>>}
|
||||||
* @example
|
* @example
|
||||||
* // Create a reaction collector
|
* // Create a reaction collector
|
||||||
* const filter = (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someId'
|
* const filter = (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someId'
|
||||||
|
|||||||
228
packages/discord.js/src/structures/ModalComponentResolver.js
Normal file
228
packages/discord.js/src/structures/ModalComponentResolver.js
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { Collection } = require('@discordjs/collection');
|
||||||
|
const { ComponentType } = require('discord-api-types/v10');
|
||||||
|
const { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ModalSelectedMentionables
|
||||||
|
* @property {Collection<Snowflake, User>} users The selected users
|
||||||
|
* @property {Collection<Snowflake, GuildMember | APIGuildMember>} members The selected members
|
||||||
|
* @property {Collection<Snowflake, Role | APIRole>} roles The selected roles
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A resolver for modal submit components
|
||||||
|
*/
|
||||||
|
class ModalComponentResolver {
|
||||||
|
constructor(client, components, resolved) {
|
||||||
|
/**
|
||||||
|
* The client that instantiated this.
|
||||||
|
*
|
||||||
|
* @name ModalComponentResolver#client
|
||||||
|
* @type {Client}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
Object.defineProperty(this, 'client', { value: client });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interaction resolved data
|
||||||
|
*
|
||||||
|
* @name ModalComponentResolver#resolved
|
||||||
|
* @type {?Readonly<BaseInteractionResolvedData>}
|
||||||
|
*/
|
||||||
|
Object.defineProperty(this, 'resolved', { value: resolved ? Object.freeze(resolved) : null });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The components within the modal
|
||||||
|
*
|
||||||
|
* @type {Array<ActionRowModalData|LabelModalData|TextDisplayModalData>}
|
||||||
|
*/
|
||||||
|
this.data = components;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bottom-level components of the interaction
|
||||||
|
*
|
||||||
|
* @type {Collection<string, ModalData>}
|
||||||
|
*/
|
||||||
|
this.hoistedComponents = components.reduce((accumulator, next) => {
|
||||||
|
// For legacy support of action rows
|
||||||
|
if ('components' in next) {
|
||||||
|
for (const component of next.components) accumulator.set(component.customId, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For label components
|
||||||
|
if ('component' in next) {
|
||||||
|
accumulator.set(next.component.customId, next.component);
|
||||||
|
}
|
||||||
|
|
||||||
|
return accumulator;
|
||||||
|
}, new Collection());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a component by custom id.
|
||||||
|
*
|
||||||
|
* @property {string} customId The custom id of the component.
|
||||||
|
* @returns {ModalData}
|
||||||
|
*/
|
||||||
|
getComponent(customId) {
|
||||||
|
const component = this.hoistedComponents.get(customId);
|
||||||
|
|
||||||
|
if (!component) throw new DiscordjsTypeError(ErrorCodes.ModalSubmitInteractionComponentNotFound, customId);
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.getComponent(customId);
|
||||||
|
if (!allowedTypes.includes(component.type)) {
|
||||||
|
throw new DiscordjsTypeError(
|
||||||
|
ErrorCodes.ModalSubmitInteractionComponentType,
|
||||||
|
customId,
|
||||||
|
component.type,
|
||||||
|
allowedTypes.join(', '),
|
||||||
|
);
|
||||||
|
} else if (required && properties.every(prop => component[prop] === null || component[prop] === undefined)) {
|
||||||
|
throw new DiscordjsTypeError(ErrorCodes.ModalSubmitInteractionComponentEmpty, customId, component.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of a text input component
|
||||||
|
*
|
||||||
|
* @param {string} customId The custom id of the text input component
|
||||||
|
* @param {?boolean} required Whether to throw an error if the component value is not found or empty
|
||||||
|
* @returns {?string}
|
||||||
|
*/
|
||||||
|
getTextInputValue(customId, required = false) {
|
||||||
|
return this._getTypedComponent(customId, [ComponentType.TextInput], ['value'], required).value ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the values of a string select component
|
||||||
|
*
|
||||||
|
* @param {string} customId The custom id of the string select component
|
||||||
|
* @returns {string[]}
|
||||||
|
*/
|
||||||
|
getStringSelectValues(customId) {
|
||||||
|
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<Snowflake, User>} 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<Snowflake, Role|APIRole>} 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<Snowflake, GuildChannel|ThreadChannel|APIChannel>} 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<Snowflake, GuildMember|APIGuildMember>} 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.ModalComponentResolver = ModalComponentResolver;
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const { Collection } = require('@discordjs/collection');
|
|
||||||
const { ComponentType } = require('discord-api-types/v10');
|
|
||||||
const { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the serialized fields from a modal submit interaction
|
|
||||||
*/
|
|
||||||
class ModalSubmitFields {
|
|
||||||
constructor(components) {
|
|
||||||
/**
|
|
||||||
* The components within the modal
|
|
||||||
*
|
|
||||||
* @type {Array<ActionRowModalData | LabelModalData>}
|
|
||||||
*/
|
|
||||||
this.components = components;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The extracted fields from the modal
|
|
||||||
*
|
|
||||||
* @type {Collection<string, ModalData>}
|
|
||||||
*/
|
|
||||||
this.fields = components.reduce((accumulator, next) => {
|
|
||||||
// NOTE: for legacy support of action rows in modals, which has `components`
|
|
||||||
if ('components' in next) {
|
|
||||||
for (const component of next.components) accumulator.set(component.customId, component);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For label component
|
|
||||||
if ('component' in next) {
|
|
||||||
accumulator.set(next.component.customId, next.component);
|
|
||||||
}
|
|
||||||
|
|
||||||
return accumulator;
|
|
||||||
}, new Collection());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a field given a custom id from a component
|
|
||||||
*
|
|
||||||
* @param {string} customId The custom id of the component
|
|
||||||
* @param {ComponentType} [type] The type of the component
|
|
||||||
* @returns {ModalData}
|
|
||||||
*/
|
|
||||||
getField(customId, type) {
|
|
||||||
const field = this.fields.get(customId);
|
|
||||||
if (!field) throw new DiscordjsTypeError(ErrorCodes.ModalSubmitInteractionFieldNotFound, customId);
|
|
||||||
|
|
||||||
if (type !== undefined && type !== field.type) {
|
|
||||||
throw new DiscordjsTypeError(ErrorCodes.ModalSubmitInteractionFieldType, customId, field.type, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
return field;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the values of a string select component given a custom id
|
|
||||||
*
|
|
||||||
* @param {string} customId The custom id of the string select component
|
|
||||||
* @returns {string[]}
|
|
||||||
*/
|
|
||||||
getStringSelectValues(customId) {
|
|
||||||
return this.getField(customId, ComponentType.StringSelect).values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.ModalSubmitFields = ModalSubmitFields;
|
|
||||||
@@ -1,46 +1,53 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const { Collection } = require('@discordjs/collection');
|
||||||
const { lazy } = require('@discordjs/util');
|
const { lazy } = require('@discordjs/util');
|
||||||
|
const { transformResolved } = require('../util/Util.js');
|
||||||
const { BaseInteraction } = require('./BaseInteraction.js');
|
const { BaseInteraction } = require('./BaseInteraction.js');
|
||||||
const { InteractionWebhook } = require('./InteractionWebhook.js');
|
const { InteractionWebhook } = require('./InteractionWebhook.js');
|
||||||
const { ModalSubmitFields } = require('./ModalSubmitFields.js');
|
const { ModalComponentResolver } = require('./ModalComponentResolver.js');
|
||||||
const { InteractionResponses } = require('./interfaces/InteractionResponses.js');
|
const { InteractionResponses } = require('./interfaces/InteractionResponses.js');
|
||||||
|
|
||||||
const getMessage = lazy(() => require('./Message.js').Message);
|
const getMessage = lazy(() => require('./Message.js').Message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} BaseModalData
|
* @typedef {Object} BaseModalData
|
||||||
* @property {ComponentType} type The component type of the field
|
* @property {ComponentType} type The component type of the component
|
||||||
* @property {string} customId The custom id of the field
|
* @property {number} id The id of the component
|
||||||
* @property {number} id The id of the field
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {BaseModalData} SelectMenuModalData
|
||||||
|
* @property {string} customId The custom id of the component
|
||||||
|
* @property {string[]} values The values of the component
|
||||||
|
* @property {Collection<string, GuildMember|APIGuildMember>} [members] The resolved members
|
||||||
|
* @property {Collection<string, User|APIUser>} [users] The resolved users
|
||||||
|
* @property {Collection<string, Role|APIRole>} [roles] The resolved roles
|
||||||
|
* @property {Collection<string, BaseChannel|APIChannel>} [channels] The resolved channels
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {BaseModalData} TextInputModalData
|
* @typedef {BaseModalData} TextInputModalData
|
||||||
* @property {string} value The value of the field
|
* @property {string} customId The custom id of the component
|
||||||
|
* @property {string} value The value of the component
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {BaseModalData} StringSelectModalData
|
* @typedef {BaseModalData} TextDisplayModalData
|
||||||
* @property {string[]} values The values of the field
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {TextInputModalData | StringSelectModalData} ModalData
|
* @typedef {SelectMenuModalData|TextInputModalData} ModalData
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} LabelModalData
|
* @typedef {BaseModalData} LabelModalData
|
||||||
* @property {ModalData} component The component within the label
|
* @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 {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
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -73,16 +80,13 @@ class ModalSubmitInteraction extends BaseInteraction {
|
|||||||
/**
|
/**
|
||||||
* The components within the modal
|
* The components within the modal
|
||||||
*
|
*
|
||||||
* @type {Array<ActionRowModalData | LabelModalData>}
|
* @type {ModalComponentResolver}
|
||||||
*/
|
*/
|
||||||
this.components = data.data.components?.map(component => ModalSubmitInteraction.transformComponent(component));
|
this.components = new ModalComponentResolver(
|
||||||
|
this.client,
|
||||||
/**
|
data.data.components?.map(component => this.transformComponent(component, data.data.resolved)),
|
||||||
* The fields within the modal
|
transformResolved({ client: this.client, guild: this.guild, channel: this.channel }, data.data.resolved),
|
||||||
*
|
);
|
||||||
* @type {ModalSubmitFields}
|
|
||||||
*/
|
|
||||||
this.fields = new ModalSubmitFields(this.components);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the reply to this interaction has been deferred
|
* Whether the reply to this interaction has been deferred
|
||||||
@@ -117,15 +121,16 @@ class ModalSubmitInteraction extends BaseInteraction {
|
|||||||
* Transforms component data to discord.js-compatible data
|
* Transforms component data to discord.js-compatible data
|
||||||
*
|
*
|
||||||
* @param {*} rawComponent The data to transform
|
* @param {*} rawComponent The data to transform
|
||||||
|
* @param {APIInteractionDataResolved} resolved The resolved data for the interaction
|
||||||
* @returns {ModalData[]}
|
* @returns {ModalData[]}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
static transformComponent(rawComponent) {
|
transformComponent(rawComponent, resolved) {
|
||||||
if ('components' in rawComponent) {
|
if ('components' in rawComponent) {
|
||||||
return {
|
return {
|
||||||
type: rawComponent.type,
|
type: rawComponent.type,
|
||||||
id: rawComponent.id,
|
id: rawComponent.id,
|
||||||
components: rawComponent.components.map(component => this.transformComponent(component)),
|
components: rawComponent.components.map(component => this.transformComponent(component, resolved)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,18 +138,50 @@ class ModalSubmitInteraction extends BaseInteraction {
|
|||||||
return {
|
return {
|
||||||
type: rawComponent.type,
|
type: rawComponent.type,
|
||||||
id: rawComponent.id,
|
id: rawComponent.id,
|
||||||
component: this.transformComponent(rawComponent.component),
|
component: this.transformComponent(rawComponent.component, resolved),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
type: rawComponent.type,
|
type: rawComponent.type,
|
||||||
customId: rawComponent.custom_id,
|
|
||||||
id: rawComponent.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.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;
|
return data;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,11 +19,12 @@ const { ComponentType } = require('discord-api-types/v10');
|
|||||||
* @typedef {Object} ModalComponentData
|
* @typedef {Object} ModalComponentData
|
||||||
* @property {string} title The title of the modal
|
* @property {string} title The title of the modal
|
||||||
* @property {string} customId The custom id of the modal
|
* @property {string} customId The custom id of the modal
|
||||||
* @property {LabelData[]} components The components within this modal
|
* @property {Array<TextDisplayComponentData|LabelData>} components The components within this modal
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {StringSelectMenuComponentData|TextInputComponentData} ComponentInLabelData
|
* @typedef {StringSelectMenuComponentData|TextInputComponentData|UserSelectMenuComponentData|
|
||||||
|
* RoleSelectMenuComponentData|MentionableSelectMenuComponentData|ChannelSelectMenuComponentData} ComponentInLabelData
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,16 +45,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 {string} customId The custom id of the select menu
|
||||||
* @property {boolean} [disabled] Whether the select menu is disabled or not
|
* @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} [maxValues] The maximum amount of options that can be selected
|
||||||
* @property {number} [minValues] The minimum 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 {string} [placeholder] The placeholder of the select menu
|
||||||
* @property {boolean} [required] Whether this component is required in modals
|
* @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
|
* @typedef {Object} SelectMenuComponentOptionData
|
||||||
* @property {string} label The label of the option
|
* @property {string} label The label of the option
|
||||||
|
|||||||
131
packages/discord.js/typings/index.d.ts
vendored
131
packages/discord.js/typings/index.d.ts
vendored
@@ -272,7 +272,13 @@ export interface ActionRowData<ComponentType extends ActionRowComponentData | JS
|
|||||||
components: readonly ComponentType[];
|
components: readonly ComponentType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ComponentInLabelData = StringSelectMenuComponentData | TextInputComponentData;
|
export type ComponentInLabelData =
|
||||||
|
| ChannelSelectMenuComponentData
|
||||||
|
| MentionableSelectMenuComponentData
|
||||||
|
| RoleSelectMenuComponentData
|
||||||
|
| StringSelectMenuComponentData
|
||||||
|
| TextInputComponentData
|
||||||
|
| UserSelectMenuComponentData;
|
||||||
export interface LabelData extends BaseComponentData {
|
export interface LabelData extends BaseComponentData {
|
||||||
component: ComponentInLabelData;
|
component: ComponentInLabelData;
|
||||||
description?: string;
|
description?: string;
|
||||||
@@ -2540,48 +2546,114 @@ export interface MessageReactionEventDetails {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ModalComponentData {
|
export interface ModalComponentData {
|
||||||
components: readonly LabelData[];
|
components: readonly (LabelData | TextDisplayComponentData)[];
|
||||||
customId: string;
|
customId: string;
|
||||||
title: string;
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseModalData<Type extends ComponentType> {
|
export interface BaseModalData<Type extends ComponentType> {
|
||||||
customId: string;
|
|
||||||
id: number;
|
id: number;
|
||||||
type: Type;
|
type: Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TextInputModalData extends BaseModalData<ComponentType.TextInput> {
|
export interface TextInputModalData extends BaseModalData<ComponentType.TextInput> {
|
||||||
|
customId: string;
|
||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StringSelectModalData extends BaseModalData<ComponentType.StringSelect> {
|
export interface SelectMenuModalData<Cached extends CacheType = CacheType>
|
||||||
|
extends BaseModalData<
|
||||||
|
| ComponentType.ChannelSelect
|
||||||
|
| ComponentType.MentionableSelect
|
||||||
|
| ComponentType.RoleSelect
|
||||||
|
| ComponentType.StringSelect
|
||||||
|
| ComponentType.UserSelect
|
||||||
|
> {
|
||||||
|
channels?: ReadonlyCollection<
|
||||||
|
Snowflake,
|
||||||
|
CacheTypeReducer<Cached, GuildBasedChannel, APIInteractionDataResolvedChannel>
|
||||||
|
>;
|
||||||
|
customId: string;
|
||||||
|
members?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, GuildMember, APIInteractionDataResolvedGuildMember>>;
|
||||||
|
roles?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Role, APIRole>>;
|
||||||
|
users?: ReadonlyCollection<Snowflake, User>;
|
||||||
values: readonly string[];
|
values: readonly string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ModalData = StringSelectModalData | TextInputModalData;
|
export type ModalData = SelectMenuModalData | TextInputModalData;
|
||||||
|
|
||||||
export interface LabelModalData {
|
export interface LabelModalData extends BaseModalData<ComponentType.Label> {
|
||||||
component: readonly ModalData[];
|
component: readonly ModalData[];
|
||||||
id: number;
|
|
||||||
type: ComponentType.Label;
|
|
||||||
}
|
}
|
||||||
export interface ActionRowModalData {
|
export interface ActionRowModalData extends BaseModalData<ComponentType.ActionRow> {
|
||||||
components: readonly TextInputModalData[];
|
components: readonly TextInputModalData[];
|
||||||
type: ComponentType.ActionRow;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ModalSubmitFields {
|
export interface TextDisplayModalData extends BaseModalData<ComponentType.TextDisplay> {}
|
||||||
private constructor(components: readonly (ActionRowModalData | LabelModalData)[]);
|
|
||||||
public components: (ActionRowModalData | LabelModalData)[];
|
export interface ModalSelectedMentionables<Cached extends CacheType = CacheType> {
|
||||||
public fields: Collection<string, StringSelectModalData | TextInputModalData>;
|
members: NonNullable<SelectMenuModalData<Cached>['members']>;
|
||||||
public getField<Type extends ComponentType>(
|
roles: NonNullable<SelectMenuModalData<Cached>['roles']>;
|
||||||
|
users: NonNullable<SelectMenuModalData<Cached>['users']>;
|
||||||
|
}
|
||||||
|
export class ModalComponentResolver<Cached extends CacheType = CacheType> {
|
||||||
|
private constructor(client: Client<true>, components: readonly ModalData[], resolved: BaseInteractionResolvedData);
|
||||||
|
public readonly client: Client<true>;
|
||||||
|
public readonly data: readonly (ActionRowModalData | LabelModalData | TextDisplayModalData)[];
|
||||||
|
public readonly resolved: Readonly<BaseInteractionResolvedData<Cached>> | null;
|
||||||
|
public readonly hoistedComponents: ReadonlyCollection<string, ModalData>;
|
||||||
|
public getComponent(customId: string): ModalData;
|
||||||
|
private _getTypedComponent(
|
||||||
customId: string,
|
customId: string,
|
||||||
type: Type,
|
allowedTypes: readonly ComponentType[],
|
||||||
): { type: Type } & (StringSelectModalData | TextInputModalData);
|
properties: string,
|
||||||
public getField(customId: string, type?: ComponentType): StringSelectModalData | TextInputModalData;
|
required: boolean,
|
||||||
public getTextInputValue(customId: string): string;
|
): ModalData;
|
||||||
|
public getTextInputValue(customId: string, required: true): string;
|
||||||
|
public getTextInputValue(customId: string, required?: boolean): string | null;
|
||||||
public getStringSelectValues(customId: string): readonly string[];
|
public getStringSelectValues(customId: string): readonly string[];
|
||||||
|
public getSelectedUsers(customId: string, required: true): ReadonlyCollection<Snowflake, User>;
|
||||||
|
public getSelectedUsers(customId: string, required?: boolean): ReadonlyCollection<Snowflake, User> | null;
|
||||||
|
public getSelectedMembers(customId: string): NonNullable<SelectMenuModalData<Cached>['members']> | null;
|
||||||
|
public getSelectedChannels<const Type extends ChannelType = ChannelType>(
|
||||||
|
customId: string,
|
||||||
|
required: true,
|
||||||
|
channelTypes?: readonly Type[],
|
||||||
|
): ReadonlyCollection<
|
||||||
|
Snowflake,
|
||||||
|
Extract<
|
||||||
|
NonNullable<CommandInteractionOption<Cached>['channel']>,
|
||||||
|
{
|
||||||
|
type: Type extends ChannelType.AnnouncementThread | ChannelType.PublicThread
|
||||||
|
? ChannelType.AnnouncementThread | ChannelType.PublicThread
|
||||||
|
: Type;
|
||||||
|
}
|
||||||
|
>
|
||||||
|
>;
|
||||||
|
public getSelectedChannels<const Type extends ChannelType = ChannelType>(
|
||||||
|
customId: string,
|
||||||
|
required?: boolean,
|
||||||
|
channelTypes?: readonly Type[],
|
||||||
|
): ReadonlyCollection<
|
||||||
|
Snowflake,
|
||||||
|
Extract<
|
||||||
|
NonNullable<CommandInteractionOption<Cached>['channel']>,
|
||||||
|
{
|
||||||
|
type: Type extends ChannelType.AnnouncementThread | ChannelType.PublicThread
|
||||||
|
? ChannelType.AnnouncementThread | ChannelType.PublicThread
|
||||||
|
: Type;
|
||||||
|
}
|
||||||
|
>
|
||||||
|
> | null;
|
||||||
|
|
||||||
|
public getSelectedRoles(customId: string, required: true): NonNullable<SelectMenuModalData<Cached>['roles']>;
|
||||||
|
public getSelectedRoles(
|
||||||
|
customId: string,
|
||||||
|
required?: boolean,
|
||||||
|
): NonNullable<SelectMenuModalData<Cached>['roles']> | null;
|
||||||
|
|
||||||
|
public getSelectedMentionables(customId: string, required: true): ModalSelectedMentionables<Cached>;
|
||||||
|
public getSelectedMentionables(customId: string, required?: boolean): ModalSelectedMentionables<Cached> | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ModalMessageModalSubmitInteraction<Cached extends CacheType = CacheType>
|
export interface ModalMessageModalSubmitInteraction<Cached extends CacheType = CacheType>
|
||||||
@@ -2604,8 +2676,7 @@ export class ModalSubmitInteraction<Cached extends CacheType = CacheType> extend
|
|||||||
private constructor(client: Client<true>, data: APIModalSubmitInteraction);
|
private constructor(client: Client<true>, data: APIModalSubmitInteraction);
|
||||||
public type: InteractionType.ModalSubmit;
|
public type: InteractionType.ModalSubmit;
|
||||||
public readonly customId: string;
|
public readonly customId: string;
|
||||||
public readonly components: (ActionRowModalData | LabelModalData)[];
|
public readonly components: ModalComponentResolver<Cached>;
|
||||||
public readonly fields: ModalSubmitFields;
|
|
||||||
public deferred: boolean;
|
public deferred: boolean;
|
||||||
public ephemeral: boolean | null;
|
public ephemeral: boolean | null;
|
||||||
public message: Message<BooleanCache<Cached>> | null;
|
public message: Message<BooleanCache<Cached>> | null;
|
||||||
@@ -4021,8 +4092,10 @@ export enum DiscordjsErrorCodes {
|
|||||||
CommandInteractionOptionNoSubcommandGroup = 'CommandInteractionOptionNoSubcommandGroup',
|
CommandInteractionOptionNoSubcommandGroup = 'CommandInteractionOptionNoSubcommandGroup',
|
||||||
AutocompleteInteractionOptionNoFocusedOption = 'AutocompleteInteractionOptionNoFocusedOption',
|
AutocompleteInteractionOptionNoFocusedOption = 'AutocompleteInteractionOptionNoFocusedOption',
|
||||||
|
|
||||||
ModalSubmitInteractionFieldNotFound = 'ModalSubmitInteractionFieldNotFound',
|
ModalSubmitInteractionComponentNotFound = 'ModalSubmitInteractionComponentNotFound',
|
||||||
ModalSubmitInteractionFieldType = 'ModalSubmitInteractionFieldType',
|
ModalSubmitInteractionComponentType = 'ModalSubmitInteractionComponentType',
|
||||||
|
ModalSubmitInteractionComponentEmpty = 'ModalSubmitInteractionComponentEmpty',
|
||||||
|
ModalSubmitInteractionComponentInvalidChannelType = 'ModalSubmitInteractionComponentInvalidChannelType',
|
||||||
|
|
||||||
InvalidMissingScopes = 'InvalidMissingScopes',
|
InvalidMissingScopes = 'InvalidMissingScopes',
|
||||||
InvalidScopesWithPermissions = 'InvalidScopesWithPermissions',
|
InvalidScopesWithPermissions = 'InvalidScopesWithPermissions',
|
||||||
@@ -5548,15 +5621,19 @@ export interface CommandInteractionOption<Cached extends CacheType = CacheType>
|
|||||||
value?: boolean | number | string;
|
value?: boolean | number | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CommandInteractionResolvedData<Cached extends CacheType = CacheType> {
|
export interface BaseInteractionResolvedData<Cached extends CacheType = CacheType> {
|
||||||
attachments?: ReadonlyCollection<Snowflake, Attachment>;
|
|
||||||
channels?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Channel, APIInteractionDataResolvedChannel>>;
|
channels?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Channel, APIInteractionDataResolvedChannel>>;
|
||||||
members?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, GuildMember, APIInteractionDataResolvedGuildMember>>;
|
members?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, GuildMember, APIInteractionDataResolvedGuildMember>>;
|
||||||
messages?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Message, APIMessage>>;
|
|
||||||
roles?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Role, APIRole>>;
|
roles?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Role, APIRole>>;
|
||||||
users?: ReadonlyCollection<Snowflake, User>;
|
users?: ReadonlyCollection<Snowflake, User>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CommandInteractionResolvedData<Cached extends CacheType = CacheType>
|
||||||
|
extends BaseInteractionResolvedData<Cached> {
|
||||||
|
attachments?: ReadonlyCollection<Snowflake, Attachment>;
|
||||||
|
messages?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Message, APIMessage>>;
|
||||||
|
}
|
||||||
|
|
||||||
export interface AutocompleteFocusedOption {
|
export interface AutocompleteFocusedOption {
|
||||||
focused: true;
|
focused: true;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -6691,11 +6768,11 @@ export interface BaseSelectMenuComponentData extends BaseComponentData {
|
|||||||
maxValues?: number;
|
maxValues?: number;
|
||||||
minValues?: number;
|
minValues?: number;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
required?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StringSelectMenuComponentData extends BaseSelectMenuComponentData {
|
export interface StringSelectMenuComponentData extends BaseSelectMenuComponentData {
|
||||||
options: readonly SelectMenuComponentOptionData[];
|
options: readonly SelectMenuComponentOptionData[];
|
||||||
required?: boolean;
|
|
||||||
type: ComponentType.StringSelect;
|
type: ComponentType.StringSelect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2609,6 +2609,31 @@ await chatInputInteraction.showModal({
|
|||||||
},
|
},
|
||||||
label: 'yo',
|
label: 'yo',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: ComponentType.Label,
|
||||||
|
component: {
|
||||||
|
type: ComponentType.UserSelect,
|
||||||
|
customId: 'user',
|
||||||
|
},
|
||||||
|
label: 'aa',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: ComponentType.Label,
|
||||||
|
component: {
|
||||||
|
type: ComponentType.RoleSelect,
|
||||||
|
customId: 'role',
|
||||||
|
},
|
||||||
|
label: 'bb',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: ComponentType.Label,
|
||||||
|
component: {
|
||||||
|
type: ComponentType.ChannelSelect,
|
||||||
|
customId: 'channel',
|
||||||
|
channelTypes: [ChannelType.GuildText, ChannelType.GuildVoice],
|
||||||
|
},
|
||||||
|
label: 'cc',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user