mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-09 16:13:31 +01:00
feat: components v2 (#10847)
* feat: components v2 * fix: tests * fix: merge * fix: lint * Update packages/discord.js/src/util/Components.js * fix: forward-port fixes from v14 * fix: getter * fix: missing UnfurledMediaItem#toJSON() * fix: find interactive component in container * docs(APIMediaGalleryItem): Correct tag * fix: forward port * Apply suggestions from code review Co-authored-by: Danial Raza <danialrazafb@gmail.com> --------- Co-authored-by: Vlad Frangu <me@vladfrangu.dev> Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> Co-authored-by: Danial Raza <danialrazafb@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/lintstagedrc.schema.json",
|
"$schema": "https://json.schemastore.org/lintstagedrc.schema.json",
|
||||||
"*": "prettier --ignore-unknown --write",
|
"*": "prettier --ignore-unknown --write",
|
||||||
"{src/**,test/**,typings/**,scripts/**}.{mjs,js,ts}": "cross-env ESLINT_USE_FLAT_CONFIG=false eslint --ext mjs,js,ts --fix"
|
"{src/**,test/**,typings/**,scripts/**}.{mjs,js,ts}": "cross-env ESLINT_USE_FLAT_CONFIG=false eslint --fix --format=pretty"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,12 +131,14 @@ exports.CommandInteraction = require('./structures/CommandInteraction.js').Comma
|
|||||||
exports.CommandInteractionOptionResolver =
|
exports.CommandInteractionOptionResolver =
|
||||||
require('./structures/CommandInteractionOptionResolver.js').CommandInteractionOptionResolver;
|
require('./structures/CommandInteractionOptionResolver.js').CommandInteractionOptionResolver;
|
||||||
exports.Component = require('./structures/Component.js').Component;
|
exports.Component = require('./structures/Component.js').Component;
|
||||||
|
exports.ContainerComponent = require('./structures/ContainerComponent.js').ContainerComponent;
|
||||||
exports.ContextMenuCommandInteraction =
|
exports.ContextMenuCommandInteraction =
|
||||||
require('./structures/ContextMenuCommandInteraction.js').ContextMenuCommandInteraction;
|
require('./structures/ContextMenuCommandInteraction.js').ContextMenuCommandInteraction;
|
||||||
exports.DMChannel = require('./structures/DMChannel.js').DMChannel;
|
exports.DMChannel = require('./structures/DMChannel.js').DMChannel;
|
||||||
exports.Embed = require('./structures/Embed.js').Embed;
|
exports.Embed = require('./structures/Embed.js').Embed;
|
||||||
exports.Emoji = require('./structures/Emoji.js').Emoji;
|
exports.Emoji = require('./structures/Emoji.js').Emoji;
|
||||||
exports.Entitlement = require('./structures/Entitlement.js').Entitlement;
|
exports.Entitlement = require('./structures/Entitlement.js').Entitlement;
|
||||||
|
exports.FileComponent = require('./structures/FileComponent.js').FileComponent;
|
||||||
exports.ForumChannel = require('./structures/ForumChannel.js').ForumChannel;
|
exports.ForumChannel = require('./structures/ForumChannel.js').ForumChannel;
|
||||||
exports.Guild = require('./structures/Guild.js').Guild;
|
exports.Guild = require('./structures/Guild.js').Guild;
|
||||||
exports.GuildAuditLogs = require('./structures/GuildAuditLogs.js').GuildAuditLogs;
|
exports.GuildAuditLogs = require('./structures/GuildAuditLogs.js').GuildAuditLogs;
|
||||||
@@ -165,6 +167,8 @@ exports.InteractionWebhook = require('./structures/InteractionWebhook.js').Inter
|
|||||||
exports.Invite = require('./structures/Invite.js').Invite;
|
exports.Invite = require('./structures/Invite.js').Invite;
|
||||||
exports.InviteGuild = require('./structures/InviteGuild.js').InviteGuild;
|
exports.InviteGuild = require('./structures/InviteGuild.js').InviteGuild;
|
||||||
exports.MediaChannel = require('./structures/MediaChannel.js').MediaChannel;
|
exports.MediaChannel = require('./structures/MediaChannel.js').MediaChannel;
|
||||||
|
exports.MediaGalleryComponent = require('./structures/MediaGalleryComponent.js').MediaGalleryComponent;
|
||||||
|
exports.MediaGalleryItem = require('./structures/MediaGalleryItem.js').MediaGalleryItem;
|
||||||
exports.MentionableSelectMenuComponent =
|
exports.MentionableSelectMenuComponent =
|
||||||
require('./structures/MentionableSelectMenuComponent.js').MentionableSelectMenuComponent;
|
require('./structures/MentionableSelectMenuComponent.js').MentionableSelectMenuComponent;
|
||||||
exports.MentionableSelectMenuInteraction =
|
exports.MentionableSelectMenuInteraction =
|
||||||
@@ -196,6 +200,8 @@ exports.RichPresenceAssets = require('./structures/Presence.js').RichPresenceAss
|
|||||||
exports.Role = require('./structures/Role.js').Role;
|
exports.Role = require('./structures/Role.js').Role;
|
||||||
exports.RoleSelectMenuComponent = require('./structures/RoleSelectMenuComponent.js').RoleSelectMenuComponent;
|
exports.RoleSelectMenuComponent = require('./structures/RoleSelectMenuComponent.js').RoleSelectMenuComponent;
|
||||||
exports.RoleSelectMenuInteraction = require('./structures/RoleSelectMenuInteraction.js').RoleSelectMenuInteraction;
|
exports.RoleSelectMenuInteraction = require('./structures/RoleSelectMenuInteraction.js').RoleSelectMenuInteraction;
|
||||||
|
exports.SectionComponent = require('./structures/SectionComponent.js').SectionComponent;
|
||||||
|
exports.SeparatorComponent = require('./structures/SeparatorComponent.js').SeparatorComponent;
|
||||||
exports.SKU = require('./structures/SKU.js').SKU;
|
exports.SKU = require('./structures/SKU.js').SKU;
|
||||||
exports.SoundboardSound = require('./structures/SoundboardSound.js').SoundboardSound;
|
exports.SoundboardSound = require('./structures/SoundboardSound.js').SoundboardSound;
|
||||||
exports.StageChannel = require('./structures/StageChannel.js').StageChannel;
|
exports.StageChannel = require('./structures/StageChannel.js').StageChannel;
|
||||||
@@ -209,11 +215,14 @@ exports.Subscription = require('./structures/Subscription.js').Subscription;
|
|||||||
exports.Team = require('./structures/Team.js').Team;
|
exports.Team = require('./structures/Team.js').Team;
|
||||||
exports.TeamMember = require('./structures/TeamMember.js').TeamMember;
|
exports.TeamMember = require('./structures/TeamMember.js').TeamMember;
|
||||||
exports.TextChannel = require('./structures/TextChannel.js').TextChannel;
|
exports.TextChannel = require('./structures/TextChannel.js').TextChannel;
|
||||||
|
exports.TextDisplayComponent = require('./structures/TextDisplayComponent.js').TextDisplayComponent;
|
||||||
exports.TextInputComponent = require('./structures/TextInputComponent.js').TextInputComponent;
|
exports.TextInputComponent = require('./structures/TextInputComponent.js').TextInputComponent;
|
||||||
exports.ThreadChannel = require('./structures/ThreadChannel.js').ThreadChannel;
|
exports.ThreadChannel = require('./structures/ThreadChannel.js').ThreadChannel;
|
||||||
exports.ThreadMember = require('./structures/ThreadMember.js').ThreadMember;
|
exports.ThreadMember = require('./structures/ThreadMember.js').ThreadMember;
|
||||||
exports.ThreadOnlyChannel = require('./structures/ThreadOnlyChannel.js').ThreadOnlyChannel;
|
exports.ThreadOnlyChannel = require('./structures/ThreadOnlyChannel.js').ThreadOnlyChannel;
|
||||||
|
exports.ThumbnailComponent = require('./structures/ThumbnailComponent.js').ThumbnailComponent;
|
||||||
exports.Typing = require('./structures/Typing.js').Typing;
|
exports.Typing = require('./structures/Typing.js').Typing;
|
||||||
|
exports.UnfurledMediaItem = require('./structures/UnfurledMediaItem.js').UnfurledMediaItem;
|
||||||
exports.User = require('./structures/User.js').User;
|
exports.User = require('./structures/User.js').User;
|
||||||
exports.UserContextMenuCommandInteraction =
|
exports.UserContextMenuCommandInteraction =
|
||||||
require('./structures/UserContextMenuCommandInteraction.js').UserContextMenuCommandInteraction;
|
require('./structures/UserContextMenuCommandInteraction.js').UserContextMenuCommandInteraction;
|
||||||
|
|||||||
@@ -14,6 +14,15 @@ class Component {
|
|||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id of this component
|
||||||
|
* @type {number}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get id() {
|
||||||
|
return this.data.id;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the component
|
* The type of the component
|
||||||
* @type {ComponentType}
|
* @type {ComponentType}
|
||||||
|
|||||||
60
packages/discord.js/src/structures/ContainerComponent.js
Normal file
60
packages/discord.js/src/structures/ContainerComponent.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { Component } = require('./Component.js');
|
||||||
|
const { createComponent } = require('../util/Components.js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a container component
|
||||||
|
* @extends {Component}
|
||||||
|
*/
|
||||||
|
class ContainerComponent extends Component {
|
||||||
|
constructor({ components, ...data }) {
|
||||||
|
super(data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The components in this container
|
||||||
|
* @type {Component[]}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.components = components.map(component => createComponent(component));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The accent color of this container
|
||||||
|
* @type {?number}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get accentColor() {
|
||||||
|
return this.data.accent_color ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The hex accent color of this container
|
||||||
|
* @type {?string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get hexAccentColor() {
|
||||||
|
return typeof this.data.accent_color === 'number'
|
||||||
|
? `#${this.data.accent_color.toString(16).padStart(6, '0')}`
|
||||||
|
: (this.data.accent_color ?? null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this container is spoilered
|
||||||
|
* @type {boolean}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get spoiler() {
|
||||||
|
return this.data.spoiler ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the API-compatible JSON for this component
|
||||||
|
* @returns {APIContainerComponent}
|
||||||
|
*/
|
||||||
|
toJSON() {
|
||||||
|
return { ...this.data, components: this.components.map(component => component.toJSON()) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.ContainerComponent = ContainerComponent;
|
||||||
40
packages/discord.js/src/structures/FileComponent.js
Normal file
40
packages/discord.js/src/structures/FileComponent.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { Component } = require('./Component.js');
|
||||||
|
const { UnfurledMediaItem } = require('./UnfurledMediaItem.js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a file component
|
||||||
|
* @extends {Component}
|
||||||
|
*/
|
||||||
|
class FileComponent extends Component {
|
||||||
|
constructor({ file, ...data }) {
|
||||||
|
super(data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The media associated with this file
|
||||||
|
* @type {UnfurledMediaItem}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.file = new UnfurledMediaItem(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this thumbnail is spoilered
|
||||||
|
* @type {boolean}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get spoiler() {
|
||||||
|
return this.data.spoiler ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the API-compatible JSON for this component
|
||||||
|
* @returns {APIFileComponent}
|
||||||
|
*/
|
||||||
|
toJSON() {
|
||||||
|
return { ...this.data, file: this.file.toJSON() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.FileComponent = FileComponent;
|
||||||
31
packages/discord.js/src/structures/MediaGalleryComponent.js
Normal file
31
packages/discord.js/src/structures/MediaGalleryComponent.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { Component } = require('./Component.js');
|
||||||
|
const { MediaGalleryItem } = require('./MediaGalleryItem.js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a media gallery component
|
||||||
|
* @extends {Component}
|
||||||
|
*/
|
||||||
|
class MediaGalleryComponent extends Component {
|
||||||
|
constructor({ items, ...data }) {
|
||||||
|
super(data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The items in this media gallery
|
||||||
|
* @type {MediaGalleryItem[]}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.items = items.map(item => new MediaGalleryItem(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the API-compatible JSON for this component
|
||||||
|
* @returns {APIMediaGalleryComponent}
|
||||||
|
*/
|
||||||
|
toJSON() {
|
||||||
|
return { ...this.data, items: this.items.map(item => item.toJSON()) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.MediaGalleryComponent = MediaGalleryComponent;
|
||||||
51
packages/discord.js/src/structures/MediaGalleryItem.js
Normal file
51
packages/discord.js/src/structures/MediaGalleryItem.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { UnfurledMediaItem } = require('./UnfurledMediaItem.js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an item in a media gallery
|
||||||
|
*/
|
||||||
|
class MediaGalleryItem {
|
||||||
|
constructor({ media, ...data }) {
|
||||||
|
/**
|
||||||
|
* The API data associated with this component
|
||||||
|
* @type {APIMediaGalleryItem}
|
||||||
|
*/
|
||||||
|
this.data = data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The media associated with this media gallery item
|
||||||
|
* @type {UnfurledMediaItem}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.media = new UnfurledMediaItem(media);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The description of this media gallery item
|
||||||
|
* @type {?string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get description() {
|
||||||
|
return this.data.description ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this media gallery item is spoilered
|
||||||
|
* @type {boolean}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get spoiler() {
|
||||||
|
return this.data.spoiler ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the API-compatible JSON for this component
|
||||||
|
* @returns {APIMediaGalleryItem}
|
||||||
|
*/
|
||||||
|
toJSON() {
|
||||||
|
return { ...this.data, media: this.media.toJSON() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.MediaGalleryItem = MediaGalleryItem;
|
||||||
@@ -23,7 +23,7 @@ const { ReactionCollector } = require('./ReactionCollector.js');
|
|||||||
const { Sticker } = require('./Sticker.js');
|
const { Sticker } = require('./Sticker.js');
|
||||||
const { DiscordjsError, ErrorCodes } = require('../errors/index.js');
|
const { DiscordjsError, ErrorCodes } = require('../errors/index.js');
|
||||||
const { ReactionManager } = require('../managers/ReactionManager.js');
|
const { ReactionManager } = require('../managers/ReactionManager.js');
|
||||||
const { createComponent } = require('../util/Components.js');
|
const { createComponent, findComponentByCustomId } = require('../util/Components.js');
|
||||||
const { NonSystemMessageTypes, MaxBulkDeletableMessageAge, UndeletableMessageTypes } = require('../util/Constants.js');
|
const { NonSystemMessageTypes, MaxBulkDeletableMessageAge, UndeletableMessageTypes } = require('../util/Constants.js');
|
||||||
const { MessageFlagsBitField } = require('../util/MessageFlagsBitField.js');
|
const { MessageFlagsBitField } = require('../util/MessageFlagsBitField.js');
|
||||||
const { PermissionsBitField } = require('../util/PermissionsBitField.js');
|
const { PermissionsBitField } = require('../util/PermissionsBitField.js');
|
||||||
@@ -151,10 +151,10 @@ class Message extends Base {
|
|||||||
|
|
||||||
if ('components' in data) {
|
if ('components' in data) {
|
||||||
/**
|
/**
|
||||||
* An array of action rows in the message.
|
* An array of components in the message.
|
||||||
* <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged intent
|
* <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged intent
|
||||||
* in a guild for messages that do not mention the client.</info>
|
* in a guild for messages that do not mention the client.</info>
|
||||||
* @type {ActionRow[]}
|
* @type {Component[]}
|
||||||
*/
|
*/
|
||||||
this.components = data.components.map(component => createComponent(component));
|
this.components = data.components.map(component => createComponent(component));
|
||||||
} else {
|
} else {
|
||||||
@@ -1032,7 +1032,7 @@ class Message extends Base {
|
|||||||
* @returns {?MessageActionRowComponent}
|
* @returns {?MessageActionRowComponent}
|
||||||
*/
|
*/
|
||||||
resolveComponent(customId) {
|
resolveComponent(customId) {
|
||||||
return this.components.flatMap(row => row.components).find(component => component.customId === customId) ?? null;
|
return findComponentByCustomId(this.components, customId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ const { lazy } = require('@discordjs/util');
|
|||||||
const { BaseInteraction } = require('./BaseInteraction.js');
|
const { BaseInteraction } = require('./BaseInteraction.js');
|
||||||
const { InteractionWebhook } = require('./InteractionWebhook.js');
|
const { InteractionWebhook } = require('./InteractionWebhook.js');
|
||||||
const { InteractionResponses } = require('./interfaces/InteractionResponses.js');
|
const { InteractionResponses } = require('./interfaces/InteractionResponses.js');
|
||||||
|
const { findComponentByCustomId } = require('../util/Components.js');
|
||||||
|
|
||||||
const getMessage = lazy(() => require('./Message.js').Message);
|
const getMessage = lazy(() => require('./Message.js').Message);
|
||||||
|
|
||||||
@@ -79,13 +80,11 @@ class MessageComponentInteraction extends BaseInteraction {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The component which was interacted with
|
* The component which was interacted with
|
||||||
* @type {MessageActionRowComponent|APIMessageActionRowComponent}
|
* @type {MessageActionRowComponent|APIComponentInMessageActionRow}
|
||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
get component() {
|
get component() {
|
||||||
return this.message.components
|
return findComponentByCustomId(this.message.components, this.customId);
|
||||||
.flatMap(row => row.components)
|
|
||||||
.find(component => (component.customId ?? component.custom_id) === this.customId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are here only for documentation purposes - they are implemented by InteractionResponses
|
// These are here only for documentation purposes - they are implemented by InteractionResponses
|
||||||
|
|||||||
@@ -217,7 +217,10 @@ class MessagePayload {
|
|||||||
components,
|
components,
|
||||||
username,
|
username,
|
||||||
avatar_url: avatarURL,
|
avatar_url: avatarURL,
|
||||||
allowed_mentions: content === undefined && message_reference === undefined ? undefined : allowedMentions,
|
allowed_mentions:
|
||||||
|
this.isMessage && message_reference === undefined && this.target.author.id !== this.target.client.user.id
|
||||||
|
? undefined
|
||||||
|
: allowedMentions,
|
||||||
flags,
|
flags,
|
||||||
message_reference,
|
message_reference,
|
||||||
attachments: this.options.attachments,
|
attachments: this.options.attachments,
|
||||||
|
|||||||
42
packages/discord.js/src/structures/SectionComponent.js
Normal file
42
packages/discord.js/src/structures/SectionComponent.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { Component } = require('./Component.js');
|
||||||
|
const { createComponent } = require('../util/Components.js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a section component
|
||||||
|
* @extends {Component}
|
||||||
|
*/
|
||||||
|
class SectionComponent extends Component {
|
||||||
|
constructor({ accessory, components, ...data }) {
|
||||||
|
super(data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The components in this section
|
||||||
|
* @type {Component[]}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.components = components.map(component => createComponent(component));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The accessory component of this section
|
||||||
|
* @type {Component}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.accessory = createComponent(accessory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the API-compatible JSON for this component
|
||||||
|
* @returns {APISectionComponent}
|
||||||
|
*/
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
...this.data,
|
||||||
|
accessory: this.accessory.toJSON(),
|
||||||
|
components: this.components.map(component => component.toJSON()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.SectionComponent = SectionComponent;
|
||||||
30
packages/discord.js/src/structures/SeparatorComponent.js
Normal file
30
packages/discord.js/src/structures/SeparatorComponent.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { SeparatorSpacingSize } = require('discord-api-types/v10');
|
||||||
|
const { Component } = require('./Component.js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a separator component
|
||||||
|
* @extends {Component}
|
||||||
|
*/
|
||||||
|
class SeparatorComponent extends Component {
|
||||||
|
/**
|
||||||
|
* The spacing of this separator
|
||||||
|
* @type {SeparatorSpacingSize}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get spacing() {
|
||||||
|
return this.data.spacing ?? SeparatorSpacingSize.Small;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this separator is a divider
|
||||||
|
* @type {boolean}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get divider() {
|
||||||
|
return this.data.divider ?? true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.SeparatorComponent = SeparatorComponent;
|
||||||
20
packages/discord.js/src/structures/TextDisplayComponent.js
Normal file
20
packages/discord.js/src/structures/TextDisplayComponent.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { Component } = require('./Component.js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a text display component
|
||||||
|
* @extends {Component}
|
||||||
|
*/
|
||||||
|
class TextDisplayComponent extends Component {
|
||||||
|
/**
|
||||||
|
* The content of this text display
|
||||||
|
* @type {string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get content() {
|
||||||
|
return this.data.content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.TextDisplayComponent = TextDisplayComponent;
|
||||||
49
packages/discord.js/src/structures/ThumbnailComponent.js
Normal file
49
packages/discord.js/src/structures/ThumbnailComponent.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { Component } = require('./Component.js');
|
||||||
|
const { UnfurledMediaItem } = require('./UnfurledMediaItem.js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a thumbnail component
|
||||||
|
* @extends {Component}
|
||||||
|
*/
|
||||||
|
class ThumbnailComponent extends Component {
|
||||||
|
constructor({ media, ...data }) {
|
||||||
|
super(data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The media associated with this thumbnail
|
||||||
|
* @type {UnfurledMediaItem}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.media = new UnfurledMediaItem(media);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The description of this thumbnail
|
||||||
|
* @type {?string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get description() {
|
||||||
|
return this.data.description ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this thumbnail is spoilered
|
||||||
|
* @type {boolean}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get spoiler() {
|
||||||
|
return this.data.spoiler ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the API-compatible JSON for this component
|
||||||
|
* @returns {APIThumbnailComponent}
|
||||||
|
*/
|
||||||
|
toJSON() {
|
||||||
|
return { ...this.data, media: this.media.toJSON() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.ThumbnailComponent = ThumbnailComponent;
|
||||||
33
packages/discord.js/src/structures/UnfurledMediaItem.js
Normal file
33
packages/discord.js/src/structures/UnfurledMediaItem.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a media item in a component
|
||||||
|
*/
|
||||||
|
class UnfurledMediaItem {
|
||||||
|
constructor(data) {
|
||||||
|
/**
|
||||||
|
* The API data associated with this media item
|
||||||
|
* @type {APIUnfurledMediaItem}
|
||||||
|
*/
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL of this media item
|
||||||
|
* @type {string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get url() {
|
||||||
|
return this.data.url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the API-compatible JSON for this media item
|
||||||
|
* @returns {APIUnfurledMediaItem}
|
||||||
|
*/
|
||||||
|
toJSON() {
|
||||||
|
return { ...this.data };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.UnfurledMediaItem = UnfurledMediaItem;
|
||||||
@@ -77,8 +77,11 @@ class TextBasedChannel {
|
|||||||
* (see {@link https://discord.com/developers/docs/resources/message#allowed-mentions-object here} for more details)
|
* (see {@link https://discord.com/developers/docs/resources/message#allowed-mentions-object here} for more details)
|
||||||
* @property {Array<(AttachmentBuilder|Attachment|AttachmentPayload|BufferResolvable)>} [files]
|
* @property {Array<(AttachmentBuilder|Attachment|AttachmentPayload|BufferResolvable)>} [files]
|
||||||
* The files to send with the message.
|
* The files to send with the message.
|
||||||
* @property {Array<(ActionRowBuilder|ActionRow|APIActionRowComponent)>} [components]
|
* @property {Array<(ActionRowBuilder|MessageTopLevelComponent|APIMessageTopLevelComponent)>} [components]
|
||||||
* Action rows containing interactive components for the message (buttons, select menus)
|
* Action rows containing interactive components for the message (buttons, select menus) and other
|
||||||
|
* top-level components.
|
||||||
|
* <info>When using components v2, the flag {@link MessageFlags.IsComponentsV2} needs to be set
|
||||||
|
* and `content`, `embeds`, `stickers`, and `poll` cannot be used.</info>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -98,7 +101,9 @@ class TextBasedChannel {
|
|||||||
* that message will be returned and no new message will be created
|
* that message will be returned and no new message will be created
|
||||||
* @property {StickerResolvable[]} [stickers=[]] The stickers to send in the message
|
* @property {StickerResolvable[]} [stickers=[]] The stickers to send in the message
|
||||||
* @property {MessageFlags} [flags] Which flags to set for the message.
|
* @property {MessageFlags} [flags] Which flags to set for the message.
|
||||||
* <info>Only `MessageFlags.SuppressEmbeds` and `MessageFlags.SuppressNotifications` can be set.</info>
|
* <info>Only {@link MessageFlags.SuppressEmbeds}, {@link MessageFlags.SuppressNotifications} and
|
||||||
|
* {@link MessageFlags.IsComponentsV2} can be set.</info>
|
||||||
|
* <info>{@link MessageFlags.IsComponentsV2} is required if passing components that aren't action rows</info>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -60,6 +60,11 @@
|
|||||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIChannelSelectComponent}
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIChannelSelectComponent}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @external APIContainerComponent
|
||||||
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIContainerComponent}
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @external APIEmbed
|
* @external APIEmbed
|
||||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmbed}
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmbed}
|
||||||
@@ -80,6 +85,11 @@
|
|||||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmoji}
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmoji}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @external APIFileComponent
|
||||||
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIFileComponent}
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @external APIGuild
|
* @external APIGuild
|
||||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuild}
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuild}
|
||||||
@@ -135,6 +145,16 @@
|
|||||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIInteractionGuildMember}
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIInteractionGuildMember}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @external APIMediaGalleryComponent
|
||||||
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIMediaGalleryComponent}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @external APIMediaGalleryItem
|
||||||
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIMediaGalleryItem}
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @external APIMentionableSelectComponent
|
* @external APIMentionableSelectComponent
|
||||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIMentionableSelectComponent}
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIMentionableSelectComponent}
|
||||||
@@ -146,8 +166,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @external APIMessageActionRowComponent
|
* @external APIComponentInMessageActionRow
|
||||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIMessageActionRowComponent}
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIComponentInMessageActionRow}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -165,6 +185,11 @@
|
|||||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIMessageInteractionMetadata}
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIMessageInteractionMetadata}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @external APIMessageTopLevelComponent
|
||||||
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIMessageTopLevelComponent}
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @external APIModalInteractionResponse
|
* @external APIModalInteractionResponse
|
||||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIModalInteractionResponse}
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIModalInteractionResponse}
|
||||||
@@ -210,6 +235,11 @@
|
|||||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APISelectMenuOption}
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APISelectMenuOption}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @external APISectionComponent
|
||||||
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APISectionComponent}
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @external APISticker
|
* @external APISticker
|
||||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APISticker}
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APISticker}
|
||||||
@@ -225,6 +255,16 @@
|
|||||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APITextInputComponent}
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APITextInputComponent}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @external APIThumbnailComponent
|
||||||
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIThumbnailComponent}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @external APIUnfurledMediaItem
|
||||||
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIUnfurledMediaItem}
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @external APIUser
|
* @external APIUser
|
||||||
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIUser}
|
* @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIUser}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ const { ComponentType } = require('discord-api-types/v10');
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} BaseComponentData
|
* @typedef {Object} BaseComponentData
|
||||||
|
* @property {number} [id] the id of this component
|
||||||
* @property {ComponentType} type The type of component
|
* @property {ComponentType} type The type of component
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -15,30 +16,30 @@ const { ComponentType } = require('discord-api-types/v10');
|
|||||||
/**
|
/**
|
||||||
* @typedef {BaseComponentData} ButtonComponentData
|
* @typedef {BaseComponentData} ButtonComponentData
|
||||||
* @property {ButtonStyle} style The style of the button
|
* @property {ButtonStyle} style The style of the button
|
||||||
* @property {?boolean} disabled Whether this button is disabled
|
* @property {boolean} [disabled] Whether this button is disabled
|
||||||
* @property {string} label The label of this button
|
* @property {string} label The label of this button
|
||||||
* @property {?APIMessageComponentEmoji} emoji The emoji on this button
|
* @property {APIMessageComponentEmoji} [emoji] The emoji on this button
|
||||||
* @property {?string} customId The custom id of the button
|
* @property {string} [customId] The custom id of the button
|
||||||
* @property {?string} url The URL of the button
|
* @property {string} [url] The URL of the button
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} SelectMenuComponentOptionData
|
* @typedef {Object} SelectMenuComponentOptionData
|
||||||
* @property {string} label The label of the option
|
* @property {string} label The label of the option
|
||||||
* @property {string} value The value of the option
|
* @property {string} value The value of the option
|
||||||
* @property {?string} description The description of the option
|
* @property {string} [description] The description of the option
|
||||||
* @property {?APIMessageComponentEmoji} emoji The emoji on the option
|
* @property {APIMessageComponentEmoji} [emoji] The emoji on the option
|
||||||
* @property {?boolean} default Whether this option is selected by default
|
* @property {boolean} [default] Whether this option is selected by default
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {BaseComponentData} SelectMenuComponentData
|
* @typedef {BaseComponentData} SelectMenuComponentData
|
||||||
* @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 {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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,15 +51,81 @@ const { ComponentType } = require('discord-api-types/v10');
|
|||||||
* @property {string} customId The custom id of the text input
|
* @property {string} customId The custom id of the text input
|
||||||
* @property {TextInputStyle} style The style of the text input
|
* @property {TextInputStyle} style The style of the text input
|
||||||
* @property {string} label The text that appears on top of the text input field
|
* @property {string} label The text that appears on top of the text input field
|
||||||
* @property {?number} minLength The minimum number of characters that can be entered in the text input
|
* @property {number} [minLength] The minimum number of characters that can be entered in the text input
|
||||||
* @property {?number} maxLength The maximum number of characters that can be entered in the text input
|
* @property {number} [maxLength] The maximum number of characters that can be entered in the text input
|
||||||
* @property {?boolean} required Whether or not the text input is required or not
|
* @property {boolean} [required] Whether or not the text input is required or not
|
||||||
* @property {?string} value The pre-filled text in the text input
|
* @property {string} [value] The pre-filled text in the text input
|
||||||
* @property {?string} placeholder Placeholder for the text input
|
* @property {string} [placeholder] Placeholder for the text input
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {ActionRowData|ButtonComponentData|SelectMenuComponentData|TextInputComponentData} ComponentData
|
* @typedef {Object} UnfurledMediaItemData
|
||||||
|
* @property {string} url The url of this media item. Accepts either http:, https: or attachment: protocol
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {BaseComponentData} ThumbnailComponentData
|
||||||
|
* @property {UnfurledMediaItemData} media The media for the thumbnail
|
||||||
|
* @property {string} [description] The description of the thumbnail
|
||||||
|
* @property {boolean} [spoiler] Whether the thumbnail should be spoilered
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {BaseComponentData} FileComponentData
|
||||||
|
* @property {UnfurledMediaItemData} file The file media in this component
|
||||||
|
* @property {boolean} [spoiler] Whether the file should be spoilered
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} MediaGalleryItemData
|
||||||
|
* @property {UnfurledMediaItemData} media The media for the media gallery item
|
||||||
|
* @property {string} [description] The description of the media gallery item
|
||||||
|
* @property {boolean} [spoiler] Whether the media gallery item should be spoilered
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {BaseComponentData} MediaGalleryComponentData
|
||||||
|
* @property {MediaGalleryItemData[]} items The media gallery items in this media gallery component
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {BaseComponentData} SeparatorComponentData
|
||||||
|
* @property {SeparatorSpacingSize} [spacing] The spacing size of this component
|
||||||
|
* @property {boolean} [divider] Whether the separator shows as a divider
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {BaseComponentData} SectionComponentData
|
||||||
|
* @property {Components[]} components The components in this section
|
||||||
|
* @property {ButtonComponentData|ThumbnailComponentData} accessory The accessory shown next to this section
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {BaseComponentData} TextDisplayComponentData
|
||||||
|
* @property {string} content The content displayed in this component
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {ActionRowData|FileComponentData|MediaGalleryComponentData|SectionComponentData|
|
||||||
|
* SeparatorComponentData|TextDisplayComponentData} ComponentInContainerData
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {BaseComponentData} ContainerComponentData
|
||||||
|
* @property {ComponentInContainerData} components The components in this container
|
||||||
|
* @property {?number} [accentColor] The accent color of this container
|
||||||
|
* @property {boolean} [spoiler] Whether the container should be spoilered
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {ActionRowData|ButtonComponentData|SelectMenuComponentData|TextInputComponentData|
|
||||||
|
* ThumbnailComponentData|FileComponentData|MediaGalleryComponentData|SeparatorComponentData|
|
||||||
|
* SectionComponentData|TextDisplayComponentData|ContainerComponentData} ComponentData
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {ActionRow|ContainerComponent|FileComponent|MediaGalleryComponent|
|
||||||
|
* SectionComponent|SeparatorComponent|TextDisplayComponent} MessageTopLevelComponent
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -71,16 +138,58 @@ function createComponent(data) {
|
|||||||
return data instanceof Component ? data : new (ComponentTypeToClass[data.type] ?? Component)(data);
|
return data instanceof Component ? data : new (ComponentTypeToClass[data.type] ?? Component)(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts all interactive components from the component tree
|
||||||
|
* @param {Component|APIMessageComponent} component The component to find all interactive components in
|
||||||
|
* @returns {Array<Component|APIMessageComponent>}
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
function extractInteractiveComponents(component) {
|
||||||
|
switch (component.type) {
|
||||||
|
case ComponentType.ActionRow:
|
||||||
|
return component.components;
|
||||||
|
case ComponentType.Section:
|
||||||
|
return [...component.components, component.accessory];
|
||||||
|
case ComponentType.Container:
|
||||||
|
return component.components.flatMap(extractInteractiveComponents);
|
||||||
|
default:
|
||||||
|
return [component];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a component by customId in nested components
|
||||||
|
* @param {Array<Component|APIMessageComponent>} components The components to search in
|
||||||
|
* @param {string} customId The customId to search for
|
||||||
|
* @returns {Component|APIMessageComponent}
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
function findComponentByCustomId(components, customId) {
|
||||||
|
return (
|
||||||
|
components
|
||||||
|
.flatMap(extractInteractiveComponents)
|
||||||
|
.find(component => (component.customId ?? component.custom_id) === customId) ?? null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
exports.createComponent = createComponent;
|
exports.createComponent = createComponent;
|
||||||
|
exports.findComponentByCustomId = findComponentByCustomId;
|
||||||
|
|
||||||
const { ActionRow } = require('../structures/ActionRow.js');
|
const { ActionRow } = require('../structures/ActionRow.js');
|
||||||
const { ButtonComponent } = require('../structures/ButtonComponent.js');
|
const { ButtonComponent } = require('../structures/ButtonComponent.js');
|
||||||
const { ChannelSelectMenuComponent } = require('../structures/ChannelSelectMenuComponent.js');
|
const { ChannelSelectMenuComponent } = require('../structures/ChannelSelectMenuComponent.js');
|
||||||
const { Component } = require('../structures/Component.js');
|
const { Component } = require('../structures/Component.js');
|
||||||
|
const { ContainerComponent } = require('../structures/ContainerComponent.js');
|
||||||
|
const { FileComponent } = require('../structures/FileComponent.js');
|
||||||
|
const { MediaGalleryComponent } = require('../structures/MediaGalleryComponent.js');
|
||||||
const { MentionableSelectMenuComponent } = require('../structures/MentionableSelectMenuComponent.js');
|
const { MentionableSelectMenuComponent } = require('../structures/MentionableSelectMenuComponent.js');
|
||||||
const { RoleSelectMenuComponent } = require('../structures/RoleSelectMenuComponent.js');
|
const { RoleSelectMenuComponent } = require('../structures/RoleSelectMenuComponent.js');
|
||||||
|
const { SectionComponent } = require('../structures/SectionComponent.js');
|
||||||
|
const { SeparatorComponent } = require('../structures/SeparatorComponent.js');
|
||||||
const { StringSelectMenuComponent } = require('../structures/StringSelectMenuComponent.js');
|
const { StringSelectMenuComponent } = require('../structures/StringSelectMenuComponent.js');
|
||||||
|
const { TextDisplayComponent } = require('../structures/TextDisplayComponent.js');
|
||||||
const { TextInputComponent } = require('../structures/TextInputComponent.js');
|
const { TextInputComponent } = require('../structures/TextInputComponent.js');
|
||||||
|
const { ThumbnailComponent } = require('../structures/ThumbnailComponent.js');
|
||||||
const { UserSelectMenuComponent } = require('../structures/UserSelectMenuComponent.js');
|
const { UserSelectMenuComponent } = require('../structures/UserSelectMenuComponent.js');
|
||||||
|
|
||||||
const ComponentTypeToClass = {
|
const ComponentTypeToClass = {
|
||||||
@@ -92,4 +201,11 @@ const ComponentTypeToClass = {
|
|||||||
[ComponentType.RoleSelect]: RoleSelectMenuComponent,
|
[ComponentType.RoleSelect]: RoleSelectMenuComponent,
|
||||||
[ComponentType.MentionableSelect]: MentionableSelectMenuComponent,
|
[ComponentType.MentionableSelect]: MentionableSelectMenuComponent,
|
||||||
[ComponentType.ChannelSelect]: ChannelSelectMenuComponent,
|
[ComponentType.ChannelSelect]: ChannelSelectMenuComponent,
|
||||||
|
[ComponentType.Container]: ContainerComponent,
|
||||||
|
[ComponentType.TextDisplay]: TextDisplayComponent,
|
||||||
|
[ComponentType.File]: FileComponent,
|
||||||
|
[ComponentType.MediaGallery]: MediaGalleryComponent,
|
||||||
|
[ComponentType.Section]: SectionComponent,
|
||||||
|
[ComponentType.Separator]: SeparatorComponent,
|
||||||
|
[ComponentType.Thumbnail]: ThumbnailComponent,
|
||||||
};
|
};
|
||||||
|
|||||||
156
packages/discord.js/test/messages.js
Normal file
156
packages/discord.js/test/messages.js
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { Buffer } = require('node:buffer');
|
||||||
|
const { createReadStream } = require('node:fs');
|
||||||
|
const { readFile } = require('node:fs/promises');
|
||||||
|
const path = require('node:path');
|
||||||
|
const process = require('node:process');
|
||||||
|
const { setTimeout: sleep } = require('node:timers/promises');
|
||||||
|
const { fetch } = require('undici');
|
||||||
|
const {
|
||||||
|
Client,
|
||||||
|
GatewayIntentBits,
|
||||||
|
AttachmentBuilder,
|
||||||
|
EmbedBuilder,
|
||||||
|
MessageFlags,
|
||||||
|
ComponentType,
|
||||||
|
} = require('../src/index.js');
|
||||||
|
|
||||||
|
const client = new Client({
|
||||||
|
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent],
|
||||||
|
});
|
||||||
|
|
||||||
|
const buffer = l =>
|
||||||
|
fetch(l)
|
||||||
|
.then(res => res.arrayBuffer())
|
||||||
|
.then(Buffer.from);
|
||||||
|
|
||||||
|
const linkA = 'https://discord.js.org/static/logo.svg';
|
||||||
|
const fileA = path.join(__dirname, 'blobReach.png');
|
||||||
|
|
||||||
|
const embed = () => new EmbedBuilder();
|
||||||
|
const attach = (attachment, name) => new AttachmentBuilder(attachment, { name });
|
||||||
|
|
||||||
|
const tests = [
|
||||||
|
m => m.channel.send('x'),
|
||||||
|
|
||||||
|
m => m.channel.send({ content: 'x', embeds: [{ description: 'a' }] }),
|
||||||
|
m => m.channel.send({ embeds: [{ description: 'a' }] }),
|
||||||
|
m => m.channel.send({ files: [{ attachment: fileA }] }),
|
||||||
|
m =>
|
||||||
|
m.channel.send({
|
||||||
|
embeds: [{ description: 'a' }],
|
||||||
|
files: [{ attachment: fileA, name: 'xyz.png' }],
|
||||||
|
}),
|
||||||
|
|
||||||
|
m => m.channel.send({ content: 'x', embeds: [embed().setDescription('a')] }),
|
||||||
|
m => m.channel.send({ embeds: [embed().setDescription('a')] }),
|
||||||
|
m => m.channel.send({ embeds: [embed().setDescription('a'), embed().setDescription('b')] }),
|
||||||
|
|
||||||
|
m => m.channel.send({ content: 'x', files: [attach(fileA)] }),
|
||||||
|
m => m.channel.send({ files: [fileA] }),
|
||||||
|
m => m.channel.send({ files: [attach(fileA)] }),
|
||||||
|
async m => m.channel.send({ files: [await buffer(linkA)] }),
|
||||||
|
async m => m.channel.send({ files: [{ attachment: await buffer(linkA) }] }),
|
||||||
|
m => m.channel.send({ files: [attach(fileA), attach(fileA)] }),
|
||||||
|
|
||||||
|
m => m.channel.send({ embeds: [{ description: 'a' }] }).then(m2 => m2.edit('x')),
|
||||||
|
m => m.channel.send({ embeds: [embed().setDescription('a')] }).then(m2 => m2.edit('x')),
|
||||||
|
|
||||||
|
m => m.channel.send('x').then(m2 => m2.edit({ embeds: [{ description: 'a' }] })),
|
||||||
|
m => m.channel.send('x').then(m2 => m2.edit({ embeds: [embed().setDescription('a')] })),
|
||||||
|
|
||||||
|
m => m.channel.send({ embeds: [{ description: 'a' }] }).then(m2 => m2.edit({ content: 'x', embeds: [] })),
|
||||||
|
m => m.channel.send({ embeds: [embed().setDescription('a')] }).then(m2 => m2.edit({ content: 'x', embeds: [] })),
|
||||||
|
|
||||||
|
m => m.channel.send({ content: 'x', embeds: [embed().setDescription('a')], files: [attach(fileA)] }),
|
||||||
|
m => m.channel.send({ content: 'x', files: [attach(fileA), attach(fileA)] }),
|
||||||
|
|
||||||
|
m => m.channel.send({ embeds: [embed().setDescription('a')], files: [attach(fileA)] }),
|
||||||
|
m =>
|
||||||
|
m.channel.send({
|
||||||
|
embeds: [embed().setImage('attachment://two.png')],
|
||||||
|
files: [attach(fileA, 'two.png')],
|
||||||
|
}),
|
||||||
|
m => m.channel.send({ content: 'x', files: [attach(fileA)] }),
|
||||||
|
m => m.channel.send({ files: [fileA] }),
|
||||||
|
m => m.channel.send({ files: [attach(fileA)] }),
|
||||||
|
async m => m.channel.send({ files: [await readFile(fileA)] }),
|
||||||
|
|
||||||
|
m => m.channel.send({ content: 'x', files: [attach(createReadStream(fileA))] }),
|
||||||
|
m => m.channel.send({ files: [createReadStream(fileA)] }),
|
||||||
|
m => m.channel.send({ files: [{ attachment: createReadStream(fileA) }] }),
|
||||||
|
|
||||||
|
m => m.reply({ content: 'x', allowedMentions: { repliedUser: false } }),
|
||||||
|
m => m.reply({ content: 'x', allowedMentions: { repliedUser: true } }),
|
||||||
|
m => m.reply({ content: 'x' }),
|
||||||
|
m => m.reply({ content: `${m.author}`, allowedMentions: { repliedUser: false } }),
|
||||||
|
m => m.reply({ content: `${m.author}`, allowedMentions: { parse: ['users'], repliedUser: false } }),
|
||||||
|
m => m.reply({ content: `${m.author}`, allowedMentions: { parse: ['users'], repliedUser: true } }),
|
||||||
|
m => m.reply({ content: `${m.author}` }),
|
||||||
|
|
||||||
|
m => m.edit({ flags: MessageFlags.SuppressEmbeds }),
|
||||||
|
m => m.edit({ flags: MessageFlags.SuppressEmbeds, allowedMentions: { repliedUser: false } }),
|
||||||
|
|
||||||
|
m =>
|
||||||
|
m
|
||||||
|
.reply({ content: 'x', allowedMentions: { repliedUser: false } })
|
||||||
|
.then(msg => msg.edit({ content: 'a', allowedMentions: { repliedUser: true } })),
|
||||||
|
|
||||||
|
m =>
|
||||||
|
m.channel.send({
|
||||||
|
components: [{ type: ComponentType.TextDisplay, content: `${m.author}` }],
|
||||||
|
flags: MessageFlags.IsComponentsV2,
|
||||||
|
}),
|
||||||
|
m =>
|
||||||
|
m.channel.send({
|
||||||
|
components: [{ type: ComponentType.TextDisplay, content: `${m.author}` }],
|
||||||
|
flags: MessageFlags.IsComponentsV2,
|
||||||
|
allowedMentions: { parse: ['users'] },
|
||||||
|
}),
|
||||||
|
m =>
|
||||||
|
m.channel.send({
|
||||||
|
components: [{ type: ComponentType.TextDisplay, content: `${m.author}` }],
|
||||||
|
flags: MessageFlags.IsComponentsV2,
|
||||||
|
allowedMentions: { parse: [] },
|
||||||
|
}),
|
||||||
|
m =>
|
||||||
|
m.reply({
|
||||||
|
components: [{ type: ComponentType.TextDisplay, content: `${m.author}` }],
|
||||||
|
flags: MessageFlags.IsComponentsV2,
|
||||||
|
allowedMentions: { parse: [], repliedUser: true },
|
||||||
|
}),
|
||||||
|
m =>
|
||||||
|
m.reply({
|
||||||
|
components: [{ type: ComponentType.TextDisplay, content: `${m.author}` }],
|
||||||
|
flags: MessageFlags.IsComponentsV2,
|
||||||
|
allowedMentions: { parse: [], repliedUser: false },
|
||||||
|
}),
|
||||||
|
|
||||||
|
m => m.channel.send('Done!'),
|
||||||
|
];
|
||||||
|
|
||||||
|
client.on('messageCreate', async message => {
|
||||||
|
if (message.author.id !== process.env.OWNER) return;
|
||||||
|
const match = message.content.match(/^do (.+)$/);
|
||||||
|
if (match?.[1] === 'it') {
|
||||||
|
/* eslint-disable no-await-in-loop */
|
||||||
|
for (const [i, test] of tests.entries()) {
|
||||||
|
await message.channel.send(`**#${i}**\n\`\`\`js\n${test.toString()}\`\`\``);
|
||||||
|
await test(message).catch(e => message.channel.send(`Error!\n\`\`\`\n${e}\`\`\``));
|
||||||
|
await sleep(1_000);
|
||||||
|
}
|
||||||
|
/* eslint-enable no-await-in-loop */
|
||||||
|
} else if (match) {
|
||||||
|
const n = parseInt(match[1]) || 0;
|
||||||
|
const test = tests.slice(n)[0];
|
||||||
|
const i = tests.indexOf(test);
|
||||||
|
await message.channel.send(`**#${i}**\n\`\`\`js\n${test.toString()}\`\`\``);
|
||||||
|
await test(message).catch(e => message.channel.send(`Error!\n\`\`\`\n${e}\`\`\``));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
client.login();
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
process.on('unhandledRejection', console.error);
|
||||||
185
packages/discord.js/typings/index.d.ts
vendored
185
packages/discord.js/typings/index.d.ts
vendored
@@ -161,6 +161,18 @@ import {
|
|||||||
RESTAPIPoll,
|
RESTAPIPoll,
|
||||||
EntryPointCommandHandlerType,
|
EntryPointCommandHandlerType,
|
||||||
APISoundboardSound,
|
APISoundboardSound,
|
||||||
|
APIComponentInContainer,
|
||||||
|
APIContainerComponent,
|
||||||
|
APIThumbnailComponent,
|
||||||
|
APISectionComponent,
|
||||||
|
APITextDisplayComponent,
|
||||||
|
APIUnfurledMediaItem,
|
||||||
|
APIMediaGalleryItem,
|
||||||
|
APIMediaGalleryComponent,
|
||||||
|
APISeparatorComponent,
|
||||||
|
SeparatorSpacingSize,
|
||||||
|
APIFileComponent,
|
||||||
|
APIMessageTopLevelComponent,
|
||||||
} from 'discord-api-types/v10';
|
} from 'discord-api-types/v10';
|
||||||
import { ChildProcess } from 'node:child_process';
|
import { ChildProcess } from 'node:child_process';
|
||||||
import { Stream } from 'node:stream';
|
import { Stream } from 'node:stream';
|
||||||
@@ -690,15 +702,37 @@ export class ButtonInteraction<Cached extends CacheType = CacheType> extends Mes
|
|||||||
export type AnyComponent =
|
export type AnyComponent =
|
||||||
| APIMessageComponent
|
| APIMessageComponent
|
||||||
| APIModalComponent
|
| APIModalComponent
|
||||||
| APIActionRowComponent<APIComponentInMessageActionRow | APIComponentInModalActionRow>;
|
| APIActionRowComponent<APIComponentInMessageActionRow | APIComponentInModalActionRow>
|
||||||
|
| AnyComponentV2;
|
||||||
|
|
||||||
export class Component<RawComponentData extends AnyComponent = AnyComponent> {
|
export class Component<RawComponentData extends AnyComponent = AnyComponent> {
|
||||||
public readonly data: Readonly<RawComponentData>;
|
public readonly data: Readonly<RawComponentData>;
|
||||||
|
public get id(): RawComponentData['id'];
|
||||||
public get type(): RawComponentData['type'];
|
public get type(): RawComponentData['type'];
|
||||||
public toJSON(): RawComponentData;
|
public toJSON(): RawComponentData;
|
||||||
public equals(other: this | RawComponentData): boolean;
|
public equals(other: this | RawComponentData): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type AnyComponentV2 = APIComponentInContainer | APIContainerComponent | APIThumbnailComponent;
|
||||||
|
|
||||||
|
export type TopLevelComponent =
|
||||||
|
| ActionRow<MessageActionRowComponent>
|
||||||
|
| ContainerComponent
|
||||||
|
| FileComponent
|
||||||
|
| MediaGalleryComponent
|
||||||
|
| SectionComponent
|
||||||
|
| SeparatorComponent
|
||||||
|
| TextDisplayComponent;
|
||||||
|
|
||||||
|
export type TopLevelComponentData =
|
||||||
|
| ActionRowData<MessageActionRowComponentData>
|
||||||
|
| ContainerComponentData
|
||||||
|
| FileComponentData
|
||||||
|
| MediaGalleryComponentData
|
||||||
|
| SectionComponentData
|
||||||
|
| SeparatorComponentData
|
||||||
|
| TextDisplayComponentData;
|
||||||
|
|
||||||
export class ButtonComponent extends Component<APIButtonComponent> {
|
export class ButtonComponent extends Component<APIButtonComponent> {
|
||||||
private constructor(data: APIButtonComponent);
|
private constructor(data: APIButtonComponent);
|
||||||
public get style(): ButtonStyle;
|
public get style(): ButtonStyle;
|
||||||
@@ -980,6 +1014,40 @@ export class ClientVoiceManager {
|
|||||||
public adapters: Map<Snowflake, InternalDiscordGatewayAdapterLibraryMethods>;
|
public adapters: Map<Snowflake, InternalDiscordGatewayAdapterLibraryMethods>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ComponentInContainer =
|
||||||
|
| ActionRow<MessageActionRowComponent>
|
||||||
|
| FileComponent
|
||||||
|
| MediaGalleryComponent
|
||||||
|
| SectionComponent
|
||||||
|
| SeparatorComponent
|
||||||
|
| TextDisplayComponent;
|
||||||
|
|
||||||
|
export type ComponentInContainerData =
|
||||||
|
| ActionRowData<ActionRowComponentData>
|
||||||
|
| FileComponentData
|
||||||
|
| MediaGalleryComponentData
|
||||||
|
| SectionComponentData
|
||||||
|
| SeparatorComponentData
|
||||||
|
| TextDisplayComponentData;
|
||||||
|
|
||||||
|
export interface ContainerComponentData<
|
||||||
|
ComponentType extends JSONEncodable<APIComponentInContainer> | ComponentInContainerData =
|
||||||
|
| JSONEncodable<APIComponentInContainer>
|
||||||
|
| ComponentInContainerData,
|
||||||
|
> extends BaseComponentData {
|
||||||
|
components: readonly ComponentType[];
|
||||||
|
accentColor?: number;
|
||||||
|
spoiler?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ContainerComponent extends Component<APIContainerComponent> {
|
||||||
|
private constructor(data: APIContainerComponent);
|
||||||
|
public get accentColor(): number;
|
||||||
|
public get hexAccentColor(): HexColorString;
|
||||||
|
public get spoiler(): boolean;
|
||||||
|
public readonly components: ComponentInContainer[];
|
||||||
|
}
|
||||||
|
|
||||||
export { Collection, ReadonlyCollection } from '@discordjs/collection';
|
export { Collection, ReadonlyCollection } from '@discordjs/collection';
|
||||||
|
|
||||||
export interface CollectorEventTypes<Key, Value, Extras extends unknown[] = []> {
|
export interface CollectorEventTypes<Key, Value, Extras extends unknown[] = []> {
|
||||||
@@ -1277,6 +1345,16 @@ export class Entitlement extends Base {
|
|||||||
public isGuildSubscription(): this is this & { guildId: Snowflake; guild: Guild };
|
public isGuildSubscription(): this is this & { guildId: Snowflake; guild: Guild };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FileComponentData extends BaseComponentData {
|
||||||
|
file: UnfurledMediaItemData;
|
||||||
|
spoiler?: boolean;
|
||||||
|
}
|
||||||
|
export class FileComponent extends Component<APIFileComponent> {
|
||||||
|
private constructor(data: APIFileComponent);
|
||||||
|
public readonly file: UnfurledMediaItem;
|
||||||
|
public get spoiler(): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export class Guild extends AnonymousGuild {
|
export class Guild extends AnonymousGuild {
|
||||||
private constructor(client: Client<true>, data: RawGuildData);
|
private constructor(client: Client<true>, data: RawGuildData);
|
||||||
private _sortedRoles(): Collection<Snowflake, Role>;
|
private _sortedRoles(): Collection<Snowflake, Role>;
|
||||||
@@ -1967,6 +2045,27 @@ export class LimitedCollection<Key, Value> extends Collection<Key, Value> {
|
|||||||
public keepOverLimit: ((value: Value, key: Key, collection: this) => boolean) | null;
|
public keepOverLimit: ((value: Value, key: Key, collection: this) => boolean) | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MediaGalleryComponentData extends BaseComponentData {
|
||||||
|
items: readonly MediaGalleryItemData[];
|
||||||
|
}
|
||||||
|
export class MediaGalleryComponent extends Component<APIMediaGalleryComponent> {
|
||||||
|
private constructor(data: APIMediaGalleryComponent);
|
||||||
|
public readonly items: MediaGalleryItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MediaGalleryItemData {
|
||||||
|
media: UnfurledMediaItemData;
|
||||||
|
description?: string;
|
||||||
|
spoiler?: boolean;
|
||||||
|
}
|
||||||
|
export class MediaGalleryItem {
|
||||||
|
private constructor(data: APIMediaGalleryItem);
|
||||||
|
public readonly data: APIMediaGalleryItem;
|
||||||
|
public readonly media: UnfurledMediaItem;
|
||||||
|
public get description(): string | null;
|
||||||
|
public get spoiler(): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface MessageCall {
|
export interface MessageCall {
|
||||||
get endedAt(): Date | null;
|
get endedAt(): Date | null;
|
||||||
endedTimestamp: number | null;
|
endedTimestamp: number | null;
|
||||||
@@ -2039,7 +2138,7 @@ export class Message<InGuild extends boolean = boolean> extends Base {
|
|||||||
public get channel(): If<InGuild, GuildTextBasedChannel, TextBasedChannel>;
|
public get channel(): If<InGuild, GuildTextBasedChannel, TextBasedChannel>;
|
||||||
public channelId: Snowflake;
|
public channelId: Snowflake;
|
||||||
public get cleanContent(): string;
|
public get cleanContent(): string;
|
||||||
public components: ActionRow<MessageActionRowComponent>[];
|
public components: TopLevelComponent[];
|
||||||
public content: string;
|
public content: string;
|
||||||
public get createdAt(): Date;
|
public get createdAt(): Date;
|
||||||
public createdTimestamp: number;
|
public createdTimestamp: number;
|
||||||
@@ -2774,6 +2873,20 @@ export class RoleFlagsBitField extends BitField<RoleFlagsString> {
|
|||||||
public static resolve(bit?: BitFieldResolvable<RoleFlagsString, number>): number;
|
public static resolve(bit?: BitFieldResolvable<RoleFlagsString, number>): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SectionComponentData extends BaseComponentData {
|
||||||
|
accessory: ButtonComponentData | ThumbnailComponentData;
|
||||||
|
components: readonly TextDisplayComponentData[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SectionComponent<
|
||||||
|
AccessoryType extends ButtonComponent | ThumbnailComponent = ButtonComponent | ThumbnailComponent,
|
||||||
|
> extends Component<APISectionComponent> {
|
||||||
|
private constructor(data: APISectionComponent);
|
||||||
|
public readonly accessory: AccessoryType;
|
||||||
|
public readonly components: TextDisplayComponent[];
|
||||||
|
public toJSON(): APISectionComponent;
|
||||||
|
}
|
||||||
|
|
||||||
export class StringSelectMenuInteraction<
|
export class StringSelectMenuInteraction<
|
||||||
Cached extends CacheType = CacheType,
|
Cached extends CacheType = CacheType,
|
||||||
> extends MessageComponentInteraction<Cached> {
|
> extends MessageComponentInteraction<Cached> {
|
||||||
@@ -2889,6 +3002,16 @@ export type SelectMenuInteraction<Cached extends CacheType = CacheType> =
|
|||||||
|
|
||||||
export type SelectMenuType = APISelectMenuComponent['type'];
|
export type SelectMenuType = APISelectMenuComponent['type'];
|
||||||
|
|
||||||
|
export interface SeparatorComponentData extends BaseComponentData {
|
||||||
|
spacing?: SeparatorSpacingSize;
|
||||||
|
divider?: boolean;
|
||||||
|
}
|
||||||
|
export class SeparatorComponent extends Component<APISeparatorComponent> {
|
||||||
|
private constructor(data: APISeparatorComponent);
|
||||||
|
public get spacing(): SeparatorSpacingSize;
|
||||||
|
public get divider(): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ShardEventTypes {
|
export interface ShardEventTypes {
|
||||||
death: [process: ChildProcess | Worker];
|
death: [process: ChildProcess | Worker];
|
||||||
disconnect: [];
|
disconnect: [];
|
||||||
@@ -3235,6 +3358,15 @@ export class TextChannel extends BaseGuildTextChannel {
|
|||||||
public type: ChannelType.GuildText;
|
public type: ChannelType.GuildText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TextDisplayComponentData extends BaseComponentData {
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TextDisplayComponent extends Component<APITextDisplayComponent> {
|
||||||
|
private constructor(data: APITextDisplayComponent);
|
||||||
|
public get content(): string;
|
||||||
|
}
|
||||||
|
|
||||||
export type ForumThreadChannel = PublicThreadChannel<true>;
|
export type ForumThreadChannel = PublicThreadChannel<true>;
|
||||||
export type TextThreadChannel = PublicThreadChannel<false> | PrivateThreadChannel;
|
export type TextThreadChannel = PublicThreadChannel<false> | PrivateThreadChannel;
|
||||||
export type AnyThreadChannel = TextThreadChannel | ForumThreadChannel;
|
export type AnyThreadChannel = TextThreadChannel | ForumThreadChannel;
|
||||||
@@ -3330,6 +3462,19 @@ export class ThreadMemberFlagsBitField extends BitField<ThreadMemberFlagsString>
|
|||||||
public static resolve(bit?: BitFieldResolvable<ThreadMemberFlagsString, number>): number;
|
public static resolve(bit?: BitFieldResolvable<ThreadMemberFlagsString, number>): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ThumbnailComponentData extends BaseComponentData {
|
||||||
|
media: UnfurledMediaItemData;
|
||||||
|
description?: string;
|
||||||
|
spoiler?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ThumbnailComponent extends Component<APIThumbnailComponent> {
|
||||||
|
private constructor(data: APIThumbnailComponent);
|
||||||
|
public readonly media: UnfurledMediaItem;
|
||||||
|
public get description(): string | null;
|
||||||
|
public get spoiler(): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export class Typing extends Base {
|
export class Typing extends Base {
|
||||||
private constructor(channel: TextBasedChannel, user: PartialUser, data?: RawTypingData);
|
private constructor(channel: TextBasedChannel, user: PartialUser, data?: RawTypingData);
|
||||||
public channel: TextBasedChannel;
|
public channel: TextBasedChannel;
|
||||||
@@ -3349,6 +3494,16 @@ export interface AvatarDecorationData {
|
|||||||
skuId: Snowflake;
|
skuId: Snowflake;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UnfurledMediaItemData {
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UnfurledMediaItem {
|
||||||
|
private constructor(data: APIUnfurledMediaItem);
|
||||||
|
public readonly data: APIUnfurledMediaItem;
|
||||||
|
public get url(): string;
|
||||||
|
}
|
||||||
|
|
||||||
// tslint:disable-next-line no-empty-interface
|
// tslint:disable-next-line no-empty-interface
|
||||||
export interface User extends PartialTextBasedChannelFields<false> {}
|
export interface User extends PartialTextBasedChannelFields<false> {}
|
||||||
export class User extends Base {
|
export class User extends Base {
|
||||||
@@ -3481,7 +3636,9 @@ export function createChannel(
|
|||||||
export type ComponentData =
|
export type ComponentData =
|
||||||
| MessageActionRowComponentData
|
| MessageActionRowComponentData
|
||||||
| ModalActionRowComponentData
|
| ModalActionRowComponentData
|
||||||
| ActionRowData<MessageActionRowComponentData | ModalActionRowComponentData>;
|
| ComponentInContainerData
|
||||||
|
| ContainerComponentData
|
||||||
|
| ThumbnailComponentData;
|
||||||
|
|
||||||
export interface SendSoundboardSoundOptions {
|
export interface SendSoundboardSoundOptions {
|
||||||
soundId: Snowflake;
|
soundId: Snowflake;
|
||||||
@@ -6201,8 +6358,11 @@ export interface InteractionReplyOptions extends BaseMessageOptionsWithPoll {
|
|||||||
withResponse?: boolean;
|
withResponse?: boolean;
|
||||||
flags?:
|
flags?:
|
||||||
| BitFieldResolvable<
|
| BitFieldResolvable<
|
||||||
Extract<MessageFlagsString, 'Ephemeral' | 'SuppressEmbeds' | 'SuppressNotifications'>,
|
Extract<MessageFlagsString, 'Ephemeral' | 'SuppressEmbeds' | 'SuppressNotifications' | 'IsComponentsV2'>,
|
||||||
MessageFlags.Ephemeral | MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications
|
| MessageFlags.Ephemeral
|
||||||
|
| MessageFlags.SuppressEmbeds
|
||||||
|
| MessageFlags.SuppressNotifications
|
||||||
|
| MessageFlags.IsComponentsV2
|
||||||
>
|
>
|
||||||
| undefined;
|
| undefined;
|
||||||
}
|
}
|
||||||
@@ -6364,8 +6524,10 @@ export interface BaseMessageOptions {
|
|||||||
)[];
|
)[];
|
||||||
components?: readonly (
|
components?: readonly (
|
||||||
| JSONEncodable<APIActionRowComponent<APIComponentInActionRow>>
|
| JSONEncodable<APIActionRowComponent<APIComponentInActionRow>>
|
||||||
|
| JSONEncodable<APIMessageTopLevelComponent>
|
||||||
|
| TopLevelComponentData
|
||||||
| ActionRowData<MessageActionRowComponentData | MessageActionRowComponentBuilder>
|
| ActionRowData<MessageActionRowComponentData | MessageActionRowComponentBuilder>
|
||||||
| APIActionRowComponent<APIComponentInActionRow>
|
| APIMessageTopLevelComponent
|
||||||
)[];
|
)[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6380,8 +6542,8 @@ export interface BaseMessageCreateOptions extends BaseMessageOptionsWithPoll {
|
|||||||
stickers?: readonly StickerResolvable[];
|
stickers?: readonly StickerResolvable[];
|
||||||
flags?:
|
flags?:
|
||||||
| BitFieldResolvable<
|
| BitFieldResolvable<
|
||||||
Extract<MessageFlagsString, 'SuppressEmbeds' | 'SuppressNotifications'>,
|
Extract<MessageFlagsString, 'SuppressEmbeds' | 'SuppressNotifications' | 'IsComponentsV2'>,
|
||||||
MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications
|
MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications | MessageFlags.IsComponentsV2
|
||||||
>
|
>
|
||||||
| undefined;
|
| undefined;
|
||||||
}
|
}
|
||||||
@@ -6401,7 +6563,12 @@ export interface MessageEditAttachmentData {
|
|||||||
export interface MessageEditOptions extends Omit<BaseMessageOptions, 'content'> {
|
export interface MessageEditOptions extends Omit<BaseMessageOptions, 'content'> {
|
||||||
content?: string | null;
|
content?: string | null;
|
||||||
attachments?: readonly (Attachment | MessageEditAttachmentData)[];
|
attachments?: readonly (Attachment | MessageEditAttachmentData)[];
|
||||||
flags?: BitFieldResolvable<Extract<MessageFlagsString, 'SuppressEmbeds'>, MessageFlags.SuppressEmbeds> | undefined;
|
flags?:
|
||||||
|
| BitFieldResolvable<
|
||||||
|
Extract<MessageFlagsString, 'SuppressEmbeds' | 'IsComponentsV2'>,
|
||||||
|
MessageFlags.SuppressEmbeds | MessageFlags.IsComponentsV2
|
||||||
|
>
|
||||||
|
| undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MessageReactionResolvable = MessageReaction | Snowflake | string;
|
export type MessageReactionResolvable = MessageReaction | Snowflake | string;
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ import {
|
|||||||
GuildScheduledEventRecurrenceRuleMonth,
|
GuildScheduledEventRecurrenceRuleMonth,
|
||||||
GuildScheduledEventRecurrenceRuleWeekday,
|
GuildScheduledEventRecurrenceRuleWeekday,
|
||||||
APIButtonComponentWithCustomId,
|
APIButtonComponentWithCustomId,
|
||||||
|
MessageFlags,
|
||||||
|
APITextInputComponent,
|
||||||
} from 'discord-api-types/v10';
|
} from 'discord-api-types/v10';
|
||||||
import {
|
import {
|
||||||
ApplicationCommand,
|
ApplicationCommand,
|
||||||
@@ -214,6 +216,15 @@ import {
|
|||||||
PrimaryButtonBuilder,
|
PrimaryButtonBuilder,
|
||||||
resolveColor,
|
resolveColor,
|
||||||
createComponentBuilder,
|
createComponentBuilder,
|
||||||
|
SectionComponentData,
|
||||||
|
TextDisplayComponentData,
|
||||||
|
ThumbnailComponentData,
|
||||||
|
UnfurledMediaItemData,
|
||||||
|
MediaGalleryComponentData,
|
||||||
|
MediaGalleryItemData,
|
||||||
|
SeparatorComponentData,
|
||||||
|
FileComponentData,
|
||||||
|
ContainerComponentData,
|
||||||
} from './index.js';
|
} from './index.js';
|
||||||
import { expectAssignable, expectNotAssignable, expectNotType, expectType } from 'tsd';
|
import { expectAssignable, expectNotAssignable, expectNotType, expectType } from 'tsd';
|
||||||
import type { ContextMenuCommandBuilder, ChatInputCommandBuilder } from '@discordjs/builders';
|
import type { ContextMenuCommandBuilder, ChatInputCommandBuilder } from '@discordjs/builders';
|
||||||
@@ -353,8 +364,6 @@ client.on('interactionCreate', async interaction => {
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
interaction.reply({ content: 'Hi!', components: [[button]] });
|
interaction.reply({ content: 'Hi!', components: [[button]] });
|
||||||
|
|
||||||
void new ActionRowBuilder({});
|
|
||||||
|
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
await interaction.reply({ content: 'Hi!', components: [button] });
|
await interaction.reply({ content: 'Hi!', components: [button] });
|
||||||
|
|
||||||
@@ -654,6 +663,57 @@ client.on('messageCreate', async message => {
|
|||||||
components: [row, rawButtonsRow, buttonsRow, rawStringSelectMenuRow, stringSelectRow],
|
components: [row, rawButtonsRow, buttonsRow, rawStringSelectMenuRow, stringSelectRow],
|
||||||
embeds: [embed, embedData],
|
embeds: [embed, embedData],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const rawTextDisplay: TextDisplayComponentData = {
|
||||||
|
type: ComponentType.TextDisplay,
|
||||||
|
content: 'test',
|
||||||
|
};
|
||||||
|
|
||||||
|
const rawMedia: UnfurledMediaItemData = { url: 'https://discord.js.org' };
|
||||||
|
|
||||||
|
const rawThumbnail: ThumbnailComponentData = {
|
||||||
|
type: ComponentType.Thumbnail,
|
||||||
|
media: rawMedia,
|
||||||
|
spoiler: true,
|
||||||
|
description: 'test',
|
||||||
|
};
|
||||||
|
|
||||||
|
const rawSection: SectionComponentData = {
|
||||||
|
type: ComponentType.Section,
|
||||||
|
components: [rawTextDisplay],
|
||||||
|
accessory: rawThumbnail,
|
||||||
|
};
|
||||||
|
|
||||||
|
const rawMediaGalleryItem: MediaGalleryItemData = {
|
||||||
|
media: rawMedia,
|
||||||
|
description: 'test',
|
||||||
|
spoiler: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const rawMediaGallery: MediaGalleryComponentData = {
|
||||||
|
type: ComponentType.MediaGallery,
|
||||||
|
items: [rawMediaGalleryItem, rawMediaGalleryItem, rawMediaGalleryItem],
|
||||||
|
};
|
||||||
|
|
||||||
|
const rawSeparator: SeparatorComponentData = {
|
||||||
|
type: ComponentType.Separator,
|
||||||
|
spacing: 1,
|
||||||
|
divider: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const rawFile: FileComponentData = {
|
||||||
|
type: ComponentType.File,
|
||||||
|
file: rawMedia,
|
||||||
|
};
|
||||||
|
|
||||||
|
const rawContainer: ContainerComponentData = {
|
||||||
|
type: ComponentType.Container,
|
||||||
|
components: [rawSection, rawSeparator, rawMediaGallery, rawFile],
|
||||||
|
accentColor: 0xff00ff,
|
||||||
|
spoiler: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
channel.send({ flags: MessageFlags.IsComponentsV2, components: [rawContainer] });
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('messageDelete', ({ client }) => expectType<Client<true>>(client));
|
client.on('messageDelete', ({ client }) => expectType<Client<true>>(client));
|
||||||
@@ -2530,8 +2590,11 @@ new PrimaryButtonBuilder(buttonData);
|
|||||||
declare const buttonComp: ButtonComponent;
|
declare const buttonComp: ButtonComponent;
|
||||||
createComponentBuilder(buttonComp.toJSON());
|
createComponentBuilder(buttonComp.toJSON());
|
||||||
|
|
||||||
|
declare const textInputData: APITextInputComponent;
|
||||||
|
new TextInputBuilder(textInputData);
|
||||||
|
|
||||||
declare const textInputComp: TextInputComponent;
|
declare const textInputComp: TextInputComponent;
|
||||||
new TextInputBuilder(textInputComp);
|
new TextInputBuilder(textInputComp.toJSON());
|
||||||
|
|
||||||
declare const embedData: APIEmbed;
|
declare const embedData: APIEmbed;
|
||||||
new EmbedBuilder(embedData);
|
new EmbedBuilder(embedData);
|
||||||
|
|||||||
Reference in New Issue
Block a user