diff --git a/packages/discord.js/src/index.js b/packages/discord.js/src/index.js
index 6390956da..b06c7fa18 100644
--- a/packages/discord.js/src/index.js
+++ b/packages/discord.js/src/index.js
@@ -77,7 +77,6 @@ exports.BaseGuild = require('./structures/BaseGuild');
exports.BaseGuildEmoji = require('./structures/BaseGuildEmoji');
exports.BaseGuildTextChannel = require('./structures/BaseGuildTextChannel');
exports.BaseGuildVoiceChannel = require('./structures/BaseGuildVoiceChannel');
-exports.BaseMessageComponent = require('./structures/BaseMessageComponent');
exports.ButtonInteraction = require('./structures/ButtonInteraction');
exports.CategoryChannel = require('./structures/CategoryChannel');
exports.Channel = require('./structures/Channel').Channel;
@@ -111,9 +110,7 @@ exports.Invite = require('./structures/Invite');
exports.InviteStageInstance = require('./structures/InviteStageInstance');
exports.InviteGuild = require('./structures/InviteGuild');
exports.Message = require('./structures/Message').Message;
-exports.MessageActionRow = require('./structures/MessageActionRow');
exports.MessageAttachment = require('./structures/MessageAttachment');
-exports.MessageButton = require('./structures/MessageButton');
exports.MessageCollector = require('./structures/MessageCollector');
exports.MessageComponentInteraction = require('./structures/MessageComponentInteraction');
exports.MessageContextMenuCommandInteraction = require('./structures/MessageContextMenuCommandInteraction');
@@ -121,7 +118,6 @@ exports.MessageEmbed = require('./structures/MessageEmbed');
exports.MessageMentions = require('./structures/MessageMentions');
exports.MessagePayload = require('./structures/MessagePayload');
exports.MessageReaction = require('./structures/MessageReaction');
-exports.MessageSelectMenu = require('./structures/MessageSelectMenu');
exports.NewsChannel = require('./structures/NewsChannel');
exports.OAuth2Guild = require('./structures/OAuth2Guild');
exports.PartialGroupDMChannel = require('./structures/PartialGroupDMChannel');
@@ -180,3 +176,7 @@ exports.StageInstancePrivacyLevel = require('discord-api-types/v9').StageInstanc
exports.StickerType = require('discord-api-types/v9').StickerType;
exports.StickerFormatType = require('discord-api-types/v9').StickerFormatType;
exports.WebhookType = require('discord-api-types/v9').WebhookType;
+exports.ActionRow = require('@discordjs/builders').ActionRow;
+exports.ButtonComponent = require('@discordjs/builders').ButtonComponent;
+exports.SelectMenuComponent = require('@discordjs/builders').SelectMenuComponent;
+exports.SelectMenuOption = require('@discordjs/builders').SelectMenuOption;
diff --git a/packages/discord.js/src/structures/BaseMessageComponent.js b/packages/discord.js/src/structures/BaseMessageComponent.js
deleted file mode 100644
index aa873fab6..000000000
--- a/packages/discord.js/src/structures/BaseMessageComponent.js
+++ /dev/null
@@ -1,104 +0,0 @@
-'use strict';
-
-const { ComponentType } = require('discord-api-types/v9');
-const { TypeError } = require('../errors');
-const { Events } = require('../util/Constants');
-
-/**
- * Represents an interactive component of a Message. It should not be necessary to construct this directly.
- * See {@link MessageComponent}
- */
-class BaseMessageComponent {
- /**
- * Options for a BaseMessageComponent
- * @typedef {Object} BaseMessageComponentOptions
- * @property {MessageComponentTypeResolvable} type The type of this component
- */
-
- /**
- * Data that can be resolved into options for a MessageComponent. This can be:
- * * MessageActionRowOptions
- * * MessageButtonOptions
- * * MessageSelectMenuOptions
- * @typedef {MessageActionRowOptions|MessageButtonOptions|MessageSelectMenuOptions} MessageComponentOptions
- */
-
- /**
- * Components that can be sent in a message. These can be:
- * * MessageActionRow
- * * MessageButton
- * * MessageSelectMenu
- * @typedef {MessageActionRow|MessageButton|MessageSelectMenu} MessageComponent
- * @see {@link https://discord.com/developers/docs/interactions/message-components#component-object-component-types}
- */
-
- /**
- * Data that can be resolved to a MessageComponentType. This can be:
- * * MessageComponentType
- * * string
- * * number
- * @typedef {string|number|MessageComponentType} MessageComponentTypeResolvable
- */
-
- /**
- * @param {BaseMessageComponent|BaseMessageComponentOptions} [data={}] The options for this component
- */
- constructor(data) {
- /**
- * The type of this component
- * @type {?MessageComponentType}
- */
- this.type = 'type' in data ? BaseMessageComponent.resolveType(data.type) : null;
- }
-
- /**
- * Constructs a MessageComponent based on the type of the incoming data
- * @param {MessageComponentOptions} data Data for a MessageComponent
- * @param {Client|WebhookClient} [client] Client constructing this component
- * @returns {?MessageComponent}
- * @private
- */
- static create(data, client) {
- let component;
- let type = data.type;
-
- if (typeof type === 'string') type = ComponentType[type];
-
- switch (type) {
- case ComponentType.ActionRow: {
- const MessageActionRow = require('./MessageActionRow');
- component = data instanceof MessageActionRow ? data : new MessageActionRow(data, client);
- break;
- }
- case ComponentType.Button: {
- const MessageButton = require('./MessageButton');
- component = data instanceof MessageButton ? data : new MessageButton(data);
- break;
- }
- case ComponentType.SelectMenu: {
- const MessageSelectMenu = require('./MessageSelectMenu');
- component = data instanceof MessageSelectMenu ? data : new MessageSelectMenu(data);
- break;
- }
- default:
- if (client) {
- client.emit(Events.DEBUG, `[BaseMessageComponent] Received component with unknown type: ${data.type}`);
- } else {
- throw new TypeError('INVALID_TYPE', 'data.type', 'valid MessageComponentType');
- }
- }
- return component;
- }
-
- /**
- * Resolves the type of a MessageComponent
- * @param {MessageComponentTypeResolvable} type The type to resolve
- * @returns {MessageComponentType}
- * @private
- */
- static resolveType(type) {
- return typeof type === 'string' ? type : ComponentType[type];
- }
-}
-
-module.exports = BaseMessageComponent;
diff --git a/packages/discord.js/src/structures/Message.js b/packages/discord.js/src/structures/Message.js
index 7da715aa1..720085f40 100644
--- a/packages/discord.js/src/structures/Message.js
+++ b/packages/discord.js/src/structures/Message.js
@@ -1,10 +1,10 @@
'use strict';
+const { createComponent } = require('@discordjs/builders');
const { Collection } = require('@discordjs/collection');
const { DiscordSnowflake } = require('@sapphire/snowflake');
const { MessageType, InteractionType } = require('discord-api-types/v9');
const Base = require('./Base');
-const BaseMessageComponent = require('./BaseMessageComponent');
const ClientApplication = require('./ClientApplication');
const InteractionCollector = require('./InteractionCollector');
const MessageAttachment = require('./MessageAttachment');
@@ -138,9 +138,9 @@ class Message extends Base {
if ('components' in data) {
/**
* A list of MessageActionRows in the message
- * @type {MessageActionRow[]}
+ * @type {ActionRow[]}
*/
- this.components = data.components.map(c => BaseMessageComponent.create(c, this.client));
+ this.components = data.components.map(c => createComponent(c));
} else {
this.components = this.components?.slice() ?? [];
}
diff --git a/packages/discord.js/src/structures/MessageActionRow.js b/packages/discord.js/src/structures/MessageActionRow.js
deleted file mode 100644
index 8ad93f082..000000000
--- a/packages/discord.js/src/structures/MessageActionRow.js
+++ /dev/null
@@ -1,101 +0,0 @@
-'use strict';
-
-const { ComponentType } = require('discord-api-types/v9');
-const BaseMessageComponent = require('./BaseMessageComponent');
-
-/**
- * Represents an action row containing message components.
- * @extends {BaseMessageComponent}
- */
-class MessageActionRow extends BaseMessageComponent {
- /**
- * Components that can be placed in an action row
- * * MessageButton
- * * MessageSelectMenu
- * @typedef {MessageButton|MessageSelectMenu} MessageActionRowComponent
- */
-
- /**
- * Options for components that can be placed in an action row
- * * MessageButtonOptions
- * * MessageSelectMenuOptions
- * @typedef {MessageButtonOptions|MessageSelectMenuOptions} MessageActionRowComponentOptions
- */
-
- /**
- * Data that can be resolved into components that can be placed in an action row
- * * MessageActionRowComponent
- * * MessageActionRowComponentOptions
- * @typedef {MessageActionRowComponent|MessageActionRowComponentOptions} MessageActionRowComponentResolvable
- */
-
- /**
- * @typedef {BaseMessageComponentOptions} MessageActionRowOptions
- * @property {MessageActionRowComponentResolvable[]} [components]
- * The components to place in this action row
- */
-
- /**
- * @param {MessageActionRow|MessageActionRowOptions} [data={}] MessageActionRow to clone or raw data
- * @param {Client} [client] The client constructing this MessageActionRow, if provided
- */
- constructor(data = {}, client = null) {
- super({ type: 'ACTION_ROW' });
-
- /**
- * The components in this action row
- * @type {MessageActionRowComponent[]}
- */
- this.components = data.components?.map(c => BaseMessageComponent.create(c, client)) ?? [];
- }
-
- /**
- * Adds components to the action row.
- * @param {...MessageActionRowComponentResolvable[]} components The components to add
- * @returns {MessageActionRow}
- */
- addComponents(...components) {
- this.components.push(...components.flat(Infinity).map(c => BaseMessageComponent.create(c)));
- return this;
- }
-
- /**
- * Sets the components of the action row.
- * @param {...MessageActionRowComponentResolvable[]} components The components to set
- * @returns {MessageActionRow}
- */
- setComponents(...components) {
- this.spliceComponents(0, this.components.length, components);
- return this;
- }
-
- /**
- * Removes, replaces, and inserts components in the action row.
- * @param {number} index The index to start at
- * @param {number} deleteCount The number of components to remove
- * @param {...MessageActionRowComponentResolvable[]} [components] The replacing components
- * @returns {MessageActionRow}
- */
- spliceComponents(index, deleteCount, ...components) {
- this.components.splice(index, deleteCount, ...components.flat(Infinity).map(c => BaseMessageComponent.create(c)));
- return this;
- }
-
- /**
- * Transforms the action row to a plain object.
- * @returns {APIMessageComponent} The raw data of this action row
- */
- toJSON() {
- return {
- components: this.components.map(c => c.toJSON()),
- type: ComponentType[this.type],
- };
- }
-}
-
-module.exports = MessageActionRow;
-
-/**
- * @external APIMessageComponent
- * @see {@link https://discord.com/developers/docs/interactions/message-components#component-object}
- */
diff --git a/packages/discord.js/src/structures/MessageButton.js b/packages/discord.js/src/structures/MessageButton.js
deleted file mode 100644
index 0eaad484b..000000000
--- a/packages/discord.js/src/structures/MessageButton.js
+++ /dev/null
@@ -1,165 +0,0 @@
-'use strict';
-
-const { ButtonStyle, ComponentType } = require('discord-api-types/v9');
-const BaseMessageComponent = require('./BaseMessageComponent');
-const { RangeError } = require('../errors');
-const Util = require('../util/Util');
-
-/**
- * Represents a button message component.
- * @extends {BaseMessageComponent}
- */
-class MessageButton extends BaseMessageComponent {
- /**
- * @typedef {BaseMessageComponentOptions} MessageButtonOptions
- * @property {string} [label] The text to be displayed on this button
- * @property {string} [customId] A unique string to be sent in the interaction when clicked
- * @property {MessageButtonStyleResolvable} [style] The style of this button
- * @property {EmojiIdentifierResolvable} [emoji] The emoji to be displayed to the left of the text
- * @property {string} [url] Optional URL for link-style buttons
- * @property {boolean} [disabled=false] Disables the button to prevent interactions
- */
-
- /**
- * @param {MessageButton|MessageButtonOptions} [data={}] MessageButton to clone or raw data
- */
- constructor(data = {}) {
- super({ type: 'BUTTON' });
-
- this.setup(data);
- }
-
- setup(data) {
- /**
- * The text to be displayed on this button
- * @type {?string}
- */
- this.label = data.label ?? null;
-
- /**
- * A unique string to be sent in the interaction when clicked
- * @type {?string}
- */
- this.customId = data.custom_id ?? data.customId ?? null;
-
- /**
- * The style of this button
- * @type {?MessageButtonStyle}
- */
- this.style = data.style ? MessageButton.resolveStyle(data.style) : null;
-
- /**
- * Emoji for this button
- * @type {?RawEmoji}
- */
- this.emoji = data.emoji ? Util.resolvePartialEmoji(data.emoji) : null;
-
- /**
- * The URL this button links to, if it is a Link style button
- * @type {?string}
- */
- this.url = data.url ?? null;
-
- /**
- * Whether this button is currently disabled
- * @type {boolean}
- */
- this.disabled = data.disabled ?? false;
- }
-
- /**
- * Sets the custom id for this button
- * @param {string} customId A unique string to be sent in the interaction when clicked
- * @returns {MessageButton}
- */
- setCustomId(customId) {
- this.customId = Util.verifyString(customId, RangeError, 'BUTTON_CUSTOM_ID');
- return this;
- }
-
- /**
- * Sets the interactive status of the button
- * @param {boolean} [disabled=true] Whether this button should be disabled
- * @returns {MessageButton}
- */
- setDisabled(disabled = true) {
- this.disabled = disabled;
- return this;
- }
-
- /**
- * Set the emoji of this button
- * @param {EmojiIdentifierResolvable} emoji The emoji to be displayed on this button
- * @returns {MessageButton}
- */
- setEmoji(emoji) {
- this.emoji = Util.resolvePartialEmoji(emoji);
- return this;
- }
-
- /**
- * Sets the label of this button
- * @param {string} label The text to be displayed on this button
- * @returns {MessageButton}
- */
- setLabel(label) {
- this.label = Util.verifyString(label, RangeError, 'BUTTON_LABEL');
- return this;
- }
-
- /**
- * Sets the style of this button
- * @param {MessageButtonStyleResolvable} style The style of this button
- * @returns {MessageButton}
- */
- setStyle(style) {
- this.style = MessageButton.resolveStyle(style);
- return this;
- }
-
- /**
- * Sets the URL of this button.
- * MessageButton#style must be LINK when setting a URL
- * @param {string} url The URL of this button
- * @returns {MessageButton}
- */
- setURL(url) {
- this.url = Util.verifyString(url, RangeError, 'BUTTON_URL');
- return this;
- }
-
- /**
- * Transforms the button to a plain object.
- * @returns {APIMessageButton} The raw data of this button
- */
- toJSON() {
- return {
- custom_id: this.customId,
- disabled: this.disabled,
- emoji: this.emoji,
- label: this.label,
- style: ButtonStyle[this.style],
- type: ComponentType[this.type],
- url: this.url,
- };
- }
-
- /**
- * Data that can be resolved to a MessageButtonStyle. This can be
- * * MessageButtonStyle
- * * number
- * @typedef {number|MessageButtonStyle} MessageButtonStyleResolvable
- */
-
- /**
- * Resolves the style of a button
- * @param {MessageButtonStyleResolvable} style The style to resolve
- * @returns {MessageButtonStyle}
- * @private
- */
- static resolveStyle(style) {
- return typeof style === 'string' ? style : ButtonStyle[style];
- }
-}
-
-module.exports = MessageButton;
diff --git a/packages/discord.js/src/structures/MessagePayload.js b/packages/discord.js/src/structures/MessagePayload.js
index 7b6034d2b..2ee34f771 100644
--- a/packages/discord.js/src/structures/MessagePayload.js
+++ b/packages/discord.js/src/structures/MessagePayload.js
@@ -1,7 +1,7 @@
'use strict';
const { Buffer } = require('node:buffer');
-const BaseMessageComponent = require('./BaseMessageComponent');
+const { createComponent } = require('@discordjs/builders');
const MessageEmbed = require('./MessageEmbed');
const { RangeError } = require('../errors');
const DataResolver = require('../util/DataResolver');
@@ -138,7 +138,7 @@ class MessagePayload {
}
}
- const components = this.options.components?.map(c => BaseMessageComponent.create(c).toJSON());
+ const components = this.options.components?.map(c => createComponent(c).toJSON());
let username;
let avatarURL;
diff --git a/packages/discord.js/src/structures/MessageSelectMenu.js b/packages/discord.js/src/structures/MessageSelectMenu.js
deleted file mode 100644
index cab6c9a01..000000000
--- a/packages/discord.js/src/structures/MessageSelectMenu.js
+++ /dev/null
@@ -1,212 +0,0 @@
-'use strict';
-
-const { ComponentType } = require('discord-api-types/v9');
-const BaseMessageComponent = require('./BaseMessageComponent');
-const Util = require('../util/Util');
-
-/**
- * Represents a select menu message component
- * @extends {BaseMessageComponent}
- */
-class MessageSelectMenu extends BaseMessageComponent {
- /**
- * @typedef {BaseMessageComponentOptions} MessageSelectMenuOptions
- * @property {string} [customId] A unique string to be sent in the interaction when clicked
- * @property {string} [placeholder] Custom placeholder text to display when nothing is selected
- * @property {number} [minValues] The minimum number of selections required
- * @property {number} [maxValues] The maximum number of selections allowed
- * @property {MessageSelectOption[]} [options] Options for the select menu
- * @property {boolean} [disabled=false] Disables the select menu to prevent interactions
- */
-
- /**
- * @typedef {Object} MessageSelectOption
- * @property {string} label The text to be displayed on this option
- * @property {string} value The value to be sent for this option
- * @property {?string} description Optional description to show for this option
- * @property {?RawEmoji} emoji Emoji to display for this option
- * @property {boolean} default Render this option as the default selection
- */
-
- /**
- * @typedef {Object} MessageSelectOptionData
- * @property {string} label The text to be displayed on this option
- * @property {string} value The value to be sent for this option
- * @property {string} [description] Optional description to show for this option
- * @property {EmojiIdentifierResolvable} [emoji] Emoji to display for this option
- * @property {boolean} [default] Render this option as the default selection
- */
-
- /**
- * @param {MessageSelectMenu|MessageSelectMenuOptions} [data={}] MessageSelectMenu to clone or raw data
- */
- constructor(data = {}) {
- super({ type: 'SELECT_MENU' });
-
- this.setup(data);
- }
-
- setup(data) {
- /**
- * A unique string to be sent in the interaction when clicked
- * @type {?string}
- */
- this.customId = data.custom_id ?? data.customId ?? null;
-
- /**
- * Custom placeholder text to display when nothing is selected
- * @type {?string}
- */
- this.placeholder = data.placeholder ?? null;
-
- /**
- * The minimum number of selections required
- * @type {?number}
- */
- this.minValues = data.min_values ?? data.minValues ?? null;
-
- /**
- * The maximum number of selections allowed
- * @type {?number}
- */
- this.maxValues = data.max_values ?? data.maxValues ?? null;
-
- /**
- * Options for the select menu
- * @type {MessageSelectOption[]}
- */
- this.options = this.constructor.normalizeOptions(data.options ?? []);
-
- /**
- * Whether this select menu is currently disabled
- * @type {boolean}
- */
- this.disabled = data.disabled ?? false;
- }
-
- /**
- * Sets the custom id of this select menu
- * @param {string} customId A unique string to be sent in the interaction when clicked
- * @returns {MessageSelectMenu}
- */
- setCustomId(customId) {
- this.customId = Util.verifyString(customId, RangeError, 'SELECT_MENU_CUSTOM_ID');
- return this;
- }
-
- /**
- * Sets the interactive status of the select menu
- * @param {boolean} [disabled=true] Whether this select menu should be disabled
- * @returns {MessageSelectMenu}
- */
- setDisabled(disabled = true) {
- this.disabled = disabled;
- return this;
- }
-
- /**
- * Sets the maximum number of selections allowed for this select menu
- * @param {number} maxValues Number of selections to be allowed
- * @returns {MessageSelectMenu}
- */
- setMaxValues(maxValues) {
- this.maxValues = maxValues;
- return this;
- }
-
- /**
- * Sets the minimum number of selections required for this select menu
- * This will default the maxValues to the number of options, unless manually set
- * @param {number} minValues Number of selections to be required
- * @returns {MessageSelectMenu}
- */
- setMinValues(minValues) {
- this.minValues = minValues;
- return this;
- }
-
- /**
- * Sets the placeholder of this select menu
- * @param {string} placeholder Custom placeholder text to display when nothing is selected
- * @returns {MessageSelectMenu}
- */
- setPlaceholder(placeholder) {
- this.placeholder = Util.verifyString(placeholder, RangeError, 'SELECT_MENU_PLACEHOLDER');
- return this;
- }
-
- /**
- * Adds options to the select menu.
- * @param {...MessageSelectOptionData|MessageSelectOptionData[]} options The options to add
- * @returns {MessageSelectMenu}
- */
- addOptions(...options) {
- this.options.push(...this.constructor.normalizeOptions(options));
- return this;
- }
-
- /**
- * Sets the options of the select menu.
- * @param {...MessageSelectOptionData|MessageSelectOptionData[]} options The options to set
- * @returns {MessageSelectMenu}
- */
- setOptions(...options) {
- this.spliceOptions(0, this.options.length, options);
- return this;
- }
-
- /**
- * Removes, replaces, and inserts options in the select menu.
- * @param {number} index The index to start at
- * @param {number} deleteCount The number of options to remove
- * @param {...MessageSelectOptionData|MessageSelectOptionData[]} [options] The replacing option objects
- * @returns {MessageSelectMenu}
- */
- spliceOptions(index, deleteCount, ...options) {
- this.options.splice(index, deleteCount, ...this.constructor.normalizeOptions(...options));
- return this;
- }
-
- /**
- * Transforms the select menu into a plain object
- * @returns {APIMessageSelectMenu} The raw data of this select menu
- */
- toJSON() {
- return {
- custom_id: this.customId,
- disabled: this.disabled,
- placeholder: this.placeholder,
- min_values: this.minValues,
- max_values: this.maxValues ?? (this.minValues ? this.options.length : undefined),
- options: this.options,
- type: typeof this.type === 'string' ? ComponentType[this.type] : this.type,
- };
- }
-
- /**
- * Normalizes option input and resolves strings and emojis.
- * @param {MessageSelectOptionData} option The select menu option to normalize
- * @returns {MessageSelectOption}
- */
- static normalizeOption(option) {
- let { label, value, description, emoji } = option;
-
- label = Util.verifyString(label, RangeError, 'SELECT_OPTION_LABEL');
- value = Util.verifyString(value, RangeError, 'SELECT_OPTION_VALUE');
- emoji = emoji ? Util.resolvePartialEmoji(emoji) : null;
- description = description ? Util.verifyString(description, RangeError, 'SELECT_OPTION_DESCRIPTION', true) : null;
-
- return { label, value, description, emoji, default: option.default ?? false };
- }
-
- /**
- * Normalizes option input and resolves strings and emojis.
- * @param {...MessageSelectOptionData|MessageSelectOptionData[]} options The select menu options to normalize
- * @returns {MessageSelectOption[]}
- */
- static normalizeOptions(...options) {
- return options.flat(Infinity).map(option => this.normalizeOption(option));
- }
-}
-
-module.exports = MessageSelectMenu;
diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts
index 49ee82fe6..47d702c7a 100644
--- a/packages/discord.js/typings/index.d.ts
+++ b/packages/discord.js/typings/index.d.ts
@@ -1,8 +1,12 @@
import {
+ ActionRow,
+ ActionRowComponent,
blockQuote,
bold,
+ ButtonComponent,
channelMention,
codeBlock,
+ Component,
formatEmoji,
hideLinkEmbed,
hyperlink,
@@ -11,6 +15,7 @@ import {
memberNicknameMention,
quote,
roleMention,
+ SelectMenuComponent,
spoiler,
strikethrough,
time,
@@ -424,13 +429,6 @@ export class BaseGuildVoiceChannel extends GuildChannel {
public fetchInvites(cache?: boolean): Promise>;
}
-export class BaseMessageComponent {
- protected constructor(data?: BaseMessageComponent | BaseMessageComponentOptions);
- public type: MessageComponentTypeKey | null;
- private static create(data: MessageComponentOptions, client?: Client | WebhookClient): MessageComponent | undefined;
- private static resolveType(type: MessageComponentTypeResolvable): MessageComponentTypeKey;
-}
-
export class BitField {
public constructor(bits?: BitFieldResolvable);
public bitfield: N;
@@ -454,10 +452,10 @@ export class ButtonInteraction extends Mes
private constructor(client: Client, data: RawMessageButtonInteractionData);
public readonly component: CacheTypeReducer<
Cached,
- MessageButton,
+ ButtonComponent,
APIButtonComponent,
- MessageButton | APIButtonComponent,
- MessageButton | APIButtonComponent
+ ButtonComponent | APIButtonComponent,
+ ButtonComponent | APIButtonComponent
>;
public componentType: 'Button';
public inGuild(): this is ButtonInteraction<'raw' | 'cached'>;
@@ -1476,7 +1474,7 @@ export class Message extends Base {
public readonly channel: If;
public channelId: Snowflake;
public readonly cleanContent: string;
- public components: MessageActionRow[];
+ public components: ActionRow[];
public content: string;
public readonly createdAt: Date;
public createdTimestamp: number;
@@ -1527,7 +1525,7 @@ export class Message extends Base {
public react(emoji: EmojiIdentifierResolvable): Promise;
public removeAttachments(): Promise;
public reply(options: string | MessagePayload | ReplyMessageOptions): Promise;
- public resolveComponent(customId: string): MessageActionRowComponent | null;
+ public resolveComponent(customId: string): ActionRowComponent | null;
public startThread(options: StartThreadOptions): Promise;
public suppressEmbeds(suppress?: boolean): Promise;
public toJSON(): unknown;
@@ -1536,24 +1534,6 @@ export class Message extends Base {
public inGuild(): this is Message & this;
}
-export class MessageActionRow extends BaseMessageComponent {
- public constructor(data?: MessageActionRow | MessageActionRowOptions | APIActionRowComponent);
- public type: 'ActionRow';
- 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;
-}
-
export class MessageAttachment {
public constructor(attachment: BufferResolvable | Stream, name?: string, data?: RawMessageAttachmentData);
@@ -1576,25 +1556,6 @@ export class MessageAttachment {
public toJSON(): unknown;
}
-export class MessageButton extends BaseMessageComponent {
- public constructor(data?: MessageButton | MessageButtonOptions | APIButtonComponent);
- public customId: string | null;
- public disabled: boolean;
- public emoji: APIPartialEmoji | null;
- public label: string | null;
- public style: ButtonStyleKey | null;
- public type: 'Button';
- public url: string | null;
- public setCustomId(customId: string): this;
- public setDisabled(disabled?: boolean): this;
- public setEmoji(emoji: EmojiIdentifierResolvable): this;
- public setLabel(label: string): this;
- public setStyle(style: MessageButtonStyleResolvable): this;
- public setURL(url: string): this;
- public toJSON(): APIButtonComponent;
- private static resolveStyle(style: MessageButtonStyleResolvable): ButtonStyleKey;
-}
-
export class MessageCollector extends Collector {
public constructor(channel: TextBasedChannel, options?: MessageCollectorOptions);
private _handleChannelDeletion(channel: NonThreadGuildBasedChannel): void;
@@ -1613,10 +1574,10 @@ export class MessageComponentInteraction e
protected constructor(client: Client, data: RawMessageComponentInteractionData);
public readonly component: CacheTypeReducer<
Cached,
- MessageActionRowComponent,
+ ActionRowComponent,
Exclude,
- MessageActionRowComponent | Exclude,
- MessageActionRowComponent | Exclude
+ ActionRowComponent | Exclude,
+ ActionRowComponent | Exclude
>;
public componentType: Exclude;
public customId: string;
@@ -1776,30 +1737,6 @@ export class MessageReaction {
public toJSON(): unknown;
}
-export class MessageSelectMenu extends BaseMessageComponent {
- public constructor(data?: MessageSelectMenu | MessageSelectMenuOptions | APISelectMenuComponent);
- public customId: string | null;
- public disabled: boolean;
- public maxValues: number | null;
- public minValues: number | null;
- public options: MessageSelectOption[];
- public placeholder: string | null;
- public type: 'SelectMenu';
- public addOptions(...options: MessageSelectOptionData[] | MessageSelectOptionData[][]): this;
- public setOptions(...options: MessageSelectOptionData[] | MessageSelectOptionData[][]): this;
- public setCustomId(customId: string): this;
- public setDisabled(disabled?: boolean): this;
- public setMaxValues(maxValues: number): this;
- public setMinValues(minValues: number): this;
- public setPlaceholder(placeholder: string): this;
- public spliceOptions(
- index: number,
- deleteCount: number,
- ...options: MessageSelectOptionData[] | MessageSelectOptionData[][]
- ): this;
- public toJSON(): APISelectMenuComponent;
-}
-
export class NewsChannel extends BaseGuildTextChannel {
public threads: ThreadManager;
public type: 'GuildNews';
@@ -1951,10 +1888,10 @@ export class SelectMenuInteraction extends
public constructor(client: Client, data: RawMessageSelectMenuInteractionData);
public readonly component: CacheTypeReducer<
Cached,
- MessageSelectMenu,
+ SelectMenuComponent,
APISelectMenuComponent,
- MessageSelectMenu | APISelectMenuComponent,
- MessageSelectMenu | APISelectMenuComponent
+ SelectMenuComponent | APISelectMenuComponent,
+ SelectMenuComponent | APISelectMenuComponent
>;
public componentType: 'SelectMenu';
public values: string[];
@@ -4696,16 +4633,14 @@ export type MemberMention = UserMention | `<@!${Snowflake}>`;
export type TeamMemberMembershipStateKey = keyof typeof TeamMemberMembershipState;
-export type MessageActionRowComponent = MessageButton | MessageSelectMenu;
-
-export type MessageActionRowComponentOptions =
+export type ActionRowComponentOptions =
| (Required & MessageButtonOptions)
| (Required & MessageSelectMenuOptions);
-export type MessageActionRowComponentResolvable = MessageActionRowComponent | MessageActionRowComponentOptions;
+export type MessageActionRowComponentResolvable = ActionRowComponent | ActionRowComponentOptions;
-export interface MessageActionRowOptions extends BaseMessageComponentOptions {
- components: MessageActionRowComponentResolvable[];
+export interface ActionRowOptions extends BaseMessageComponentOptions {
+ components: ActionRowComponent[];
}
export interface MessageActivity {
@@ -4740,7 +4675,7 @@ export interface MessageCollectorOptions extends CollectorOptions<[Message]> {
maxProcessed?: number;
}
-export type MessageComponent = BaseMessageComponent | MessageActionRow | MessageButton | MessageSelectMenu;
+export type MessageComponent = Component | ActionRow | ButtonComponent | SelectMenuComponent;
export type MessageComponentCollectorOptions = Omit<
InteractionCollectorOptions,
@@ -4754,7 +4689,7 @@ export type MessageChannelComponentCollectorOptions;
allowedMentions?: MessageMentionOptions;
- components?: (MessageActionRow | (Required & MessageActionRowOptions))[];
+ components?: (ActionRow | (Required & ActionRowOptions))[];
}
export interface MessageEmbedAuthor {
@@ -4868,7 +4803,7 @@ export interface MessageOptions {
nonce?: string | number;
content?: string | null;
embeds?: (MessageEmbed | MessageEmbedOptions | APIEmbed)[];
- components?: (MessageActionRow | (Required & MessageActionRowOptions))[];
+ components?: (ActionRow | (Required & ActionRowOptions))[];
allowedMentions?: MessageMentionOptions;
files?: (FileOptions | BufferResolvable | Stream | MessageAttachment)[];
reply?: ReplyOptions;
@@ -5545,3 +5480,10 @@ export {
StickerFormatType,
WebhookType,
} from 'discord-api-types/v9';
+export {
+ ActionRow,
+ ButtonComponent,
+ SelectMenuComponent,
+ SelectMenuOption,
+ ActionRowComponent,
+} from '@discordjs/builders';
diff --git a/packages/discord.js/typings/index.test-d.ts b/packages/discord.js/typings/index.test-d.ts
index 786b40e21..0fba5b6df 100644
--- a/packages/discord.js/typings/index.test-d.ts
+++ b/packages/discord.js/typings/index.test-d.ts
@@ -1,5 +1,5 @@
import type { ChildProcess } from 'child_process';
-import type {
+import {
APIInteractionGuildMember,
APIMessage,
APIPartialChannel,
@@ -10,6 +10,7 @@ import type {
APIButtonComponent,
APISelectMenuComponent,
ApplicationCommandOptionType,
+ ComponentType,
} from 'discord-api-types/v9';
import { AuditLogEvent } from 'discord-api-types/v9';
import {
@@ -47,9 +48,7 @@ import {
Interaction,
InteractionCollector,
Message,
- MessageActionRow,
MessageAttachment,
- MessageButton,
MessageCollector,
MessageComponentInteraction,
MessageEmbed,
@@ -88,9 +87,11 @@ import {
GuildAuditLogsEntry,
GuildAuditLogs,
StageInstance,
- MessageActionRowComponent,
- MessageSelectMenu,
PartialDMChannel,
+ ActionRow,
+ ButtonComponent,
+ SelectMenuComponent,
+ ActionRowComponent,
} from '.';
import { expectAssignable, expectDeprecated, expectNotAssignable, expectNotType, expectType } from 'tsd';
@@ -668,11 +669,11 @@ client.on('interactionCreate', async interaction => {
if (!interaction.isCommand()) return;
- void new MessageActionRow();
+ void new ActionRow();
- const button = new MessageButton();
+ const button = new ButtonComponent();
- const actionRow = new MessageActionRow({ components: [button] });
+ const actionRow = new ActionRow({ type: ComponentType.ActionRow, components: [button] });
await interaction.reply({ content: 'Hi!', components: [actionRow] });
@@ -993,11 +994,11 @@ client.on('interactionCreate', async interaction => {
if (interaction.isButton()) {
expectType(interaction);
- expectType(interaction.component);
+ expectType(interaction.component);
expectType(interaction.message);
if (interaction.inCachedGuild()) {
expectAssignable(interaction);
- expectType(interaction.component);
+ expectType(interaction.component);
expectType>(interaction.message);
expectType(interaction.guild);
expectAssignable>(interaction.reply({ fetchReply: true }));
@@ -1009,7 +1010,7 @@ client.on('interactionCreate', async interaction => {
expectType>(interaction.reply({ fetchReply: true }));
} else if (interaction.inGuild()) {
expectAssignable(interaction);
- expectType(interaction.component);
+ expectType(interaction.component);
expectType(interaction.message);
expectAssignable(interaction.guild);
expectType>(interaction.reply({ fetchReply: true }));
@@ -1018,11 +1019,11 @@ client.on('interactionCreate', async interaction => {
if (interaction.isMessageComponent()) {
expectType(interaction);
- expectType(interaction.component);
+ expectType(interaction.component);
expectType(interaction.message);
if (interaction.inCachedGuild()) {
expectAssignable(interaction);
- expectType(interaction.component);
+ expectType(interaction.component);
expectType>(interaction.message);
expectType(interaction.guild);
expectAssignable>(interaction.reply({ fetchReply: true }));
@@ -1034,7 +1035,7 @@ client.on('interactionCreate', async interaction => {
expectType>(interaction.reply({ fetchReply: true }));
} else if (interaction.inGuild()) {
expectAssignable(interaction);
- expectType(interaction.component);
+ expectType(interaction.component);
expectType(interaction.message);
expectType(interaction.guild);
expectType>(interaction.reply({ fetchReply: true }));
@@ -1043,11 +1044,11 @@ client.on('interactionCreate', async interaction => {
if (interaction.isSelectMenu()) {
expectType(interaction);
- expectType(interaction.component);
+ expectType(interaction.component);
expectType(interaction.message);
if (interaction.inCachedGuild()) {
expectAssignable(interaction);
- expectType(interaction.component);
+ expectType(interaction.component);
expectType>(interaction.message);
expectType(interaction.guild);
expectType>>(interaction.reply({ fetchReply: true }));
@@ -1059,7 +1060,7 @@ client.on('interactionCreate', async interaction => {
expectType>(interaction.reply({ fetchReply: true }));
} else if (interaction.inGuild()) {
expectAssignable(interaction);
- expectType(interaction.component);
+ expectType(interaction.component);
expectType(interaction.message);
expectType(interaction.guild);
expectType>(interaction.reply({ fetchReply: true }));