feat: Components V2

Merge pull request #1649 from TotallyTung/main
Todo !?
This commit is contained in:
Elysia
2025-07-08 18:15:17 +07:00
committed by GitHub
21 changed files with 615 additions and 28 deletions

View File

@@ -43,12 +43,14 @@ class BaseMessageComponent {
/** /**
* @param {BaseMessageComponent|BaseMessageComponentOptions} [data={}] The options for this component * @param {BaseMessageComponent|BaseMessageComponentOptions} [data={}] The options for this component
* @param {MessageComponentOptions} [componentData={}] The raw data for component
*/ */
constructor(data) { constructor(data, componentData = {}) {
/** /**
* The type of this component * The type of this component
* @type {?MessageComponentType} * @type {?MessageComponentType}
*/ */
this.rawData = componentData;
this.type = 'type' in data ? BaseMessageComponent.resolveType(data.type) : null; this.type = 'type' in data ? BaseMessageComponent.resolveType(data.type) : null;
} }
@@ -90,6 +92,41 @@ class BaseMessageComponent {
component = data instanceof TextInputComponent ? data : new TextInputComponent(data); component = data instanceof TextInputComponent ? data : new TextInputComponent(data);
break; break;
} }
case MessageComponentTypes.SECTION: {
const SectionComponent = require('./SectionComponent');
component = data instanceof SectionComponent ? data : new SectionComponent(data);
break;
}
case MessageComponentTypes.TEXT_DISPLAY: {
const TextDisplayComponent = require('./TextDisplayComponent');
component = data instanceof TextDisplayComponent ? data : new TextDisplayComponent(data);
break;
}
case MessageComponentTypes.THUMBNAIL: {
const ThumbnailComponent = require('./ThumbnailComponent');
component = data instanceof ThumbnailComponent ? data : new ThumbnailComponent(data);
break;
}
case MessageComponentTypes.MEDIA_GALLERY: {
const MediaGalleryComponent = require('./MediaGalleryComponent');
component = data instanceof MediaGalleryComponent ? data : new MediaGalleryComponent(data);
break;
}
case MessageComponentTypes.FILE: {
const FileComponent = require('./FileComponent');
component = data instanceof FileComponent ? data : new FileComponent(data);
break;
}
case MessageComponentTypes.SEPARATOR: {
const SeparatorComponent = require('./SeparatorComponent');
component = data instanceof SeparatorComponent ? data : new SeparatorComponent(data);
break;
}
case MessageComponentTypes.CONTAINER: {
const ContainerComponent = require('./ContainerComponent');
component = data instanceof ContainerComponent ? data : new ContainerComponent(data);
break;
}
default: default:
if (client) { if (client) {
client.emit(Events.DEBUG, `[BaseMessageComponent] Received component with unknown type: ${data.type}`); client.emit(Events.DEBUG, `[BaseMessageComponent] Received component with unknown type: ${data.type}`);

View File

@@ -0,0 +1,51 @@
'use strict';
const BaseMessageComponent = require('./BaseMessageComponent');
const { MessageComponentTypes } = require('../util/Constants');
class ContainerComponent extends BaseMessageComponent {
/**
* @typedef {MessageActionRow|TextDisplayComponent|SectionComponent|MediaGalleryComponent|SeparatorComponent|FileComponent} ContainerComponents
* @property {ContainerComponents[]} [components] Components of the type action row, text display, section, media gallery, separator, or file
* @property {Number} [accent_color] Color for the accent on the container as RGB from 0x000000 to 0xFFFFFF
* @property {Boolean} [spoiler] Whether the container should be a spoiler (or blurred out). Defaults to false.
*/
/**
* @param {ContainerComponent | APIContainerComponent} [data={}] The data
*/
constructor(data = {}) {
super({ type: 'CONTAINER' }, data);
/**
* Components of the type action row, text display, section, media gallery, separator, or file
* @type {ContainerComponents[]}
*/
this.components = data.components?.map(c => BaseMessageComponent.create(c)) ?? [];
/**
* Color for the accent on the container as RGB from 0x000000 to 0xFFFFFF
* @type {Number}
*/
this.accent_color = data.accent_color ?? null;
/**
* Whether the container should be a spoiler (or blurred out). Defaults to false.
* @type {Boolean}
*/
this.spoiler = data.spoiler ?? false;
}
/**
* @returns {APIContainerComponent}
*/
toJSON() {
return {
type: MessageComponentTypes[this.type],
components: this.components.map(c => c.toJSON()),
accent_color: this.accent_color,
spoiler: this.spoiler,
};
}
}
module.exports = ContainerComponent;

View File

@@ -0,0 +1,44 @@
'use strict';
const BaseMessageComponent = require('./BaseMessageComponent');
const UnfurledMediaItem = require('./UnfurledMediaItem');
const { MessageComponentTypes } = require('../util/Constants');
class FileComponent extends BaseMessageComponent {
/**
* @property {UnfurledMediaItem} [file] This unfurled media item is unique in that it only supports attachment references using the attachment://<filename> syntax
* @property {Boolean} [spoiler] Whether the container should be a spoiler (or blurred out). Defaults to false.
*/
/**
* @param {FileComponent | APIFileComponent} [data={}] The data
*/
constructor(data = {}) {
super({ type: 'FILE' }, data);
/**
* This unfurled media item is unique in that it only supports attachment references using the attachment://<filename> syntax
* @type {UnfurledMediaItem}
*/
this.file = new UnfurledMediaItem(data.file);
/**
* Whether the container should be a spoiler (or blurred out). Defaults to false.
* @type {Boolean}
*/
this.spoiler = data.spoiler ?? false;
}
/**
* @returns {APIFileComponent}
*/
toJSON() {
return {
type: MessageComponentTypes[this.type],
file: this.content,
spoiler: this.spoiler,
};
}
}
module.exports = FileComponent;

View File

@@ -0,0 +1,36 @@
'use strict';
const BaseMessageComponent = require('./BaseMessageComponent');
const MediaGalleryItem = require('./MediaGalleryItem');
const { MessageComponentTypes } = require('../util/Constants');
class MediaGalleryComponent extends BaseMessageComponent {
/**
* @property {MediaGalleryItem[]} [items] 1 to 10 media gallery items
*/
/**
* @param {MediaGalleryComponent | APIMediaGalleryComponent} [data={}] The data
*/
constructor(data = {}) {
super({ type: 'MEDIA_GALLERY' }, data);
/**
* 1 to 10 media gallery items
* @type {MediaGalleryItem[]}
*/
this.items = data.items?.map(item => new MediaGalleryItem(item)) ?? [];
}
/**
* @returns {APIMediaGalleryComponent}
*/
toJSON() {
return {
type: MessageComponentTypes[this.type],
items: this.items.map(c => c.toJSON()),
};
}
}
module.exports = MediaGalleryComponent;

View File

@@ -0,0 +1,47 @@
'use strict';
const UnfurledMediaItem = require('./UnfurledMediaItem');
class MediaGalleryItem {
/**
* @property {UnfurledMediaItem} [media] A url or attachment
* @property {String} [description] Alt text for the media, max 1024 characters
* @property {Boolean} [spoiler] Whether the media should be a spoiler (or blurred out). Defaults to false
*/
/**
* @param {MediaGalleryItem | APIMediaGalleryItem} [data={}] The data
*/
constructor(data = {}) {
/**
* A url or attachment
* @type {UnfurledMediaItem}
*/
this.media = new UnfurledMediaItem(data.media);
/**
* Alt text for the media, max 1024 characters
* @type {String}
*/
this.description = data.description ?? null;
/**
* Whether the media should be a spoiler (or blurred out). Defaults to false
* @type {Boolean}
*/
this.spoiler = data.spoiler ?? false;
}
/**
* @returns {APIMediaGalleryItem}
*/
toJSON() {
return {
media: this.media.toJSON(),
description: this.description,
spoiler: this.spoiler,
};
}
}
module.exports = MediaGalleryItem;

View File

@@ -162,8 +162,8 @@ class Message extends Base {
if ('components' in data) { if ('components' in data) {
/** /**
* A list of MessageActionRows in the message * A list of components in the message
* @type {MessageActionRow[]} * @type {MessageActionRow[] | ContainerComponent[]}
*/ */
this.components = data.components.map(c => BaseMessageComponent.create(c, this.client)); this.components = data.components.map(c => BaseMessageComponent.create(c, this.client));
} else { } else {

View File

@@ -42,7 +42,7 @@ class MessageActionRow extends BaseMessageComponent {
* @param {Client} [client] The client constructing this MessageActionRow, if provided * @param {Client} [client] The client constructing this MessageActionRow, if provided
*/ */
constructor(data = {}, client = null) { constructor(data = {}, client = null) {
super({ type: 'ACTION_ROW' }); super({ type: 'ACTION_ROW' }, data);
/** /**
* The components in this action row * The components in this action row

View File

@@ -24,7 +24,7 @@ class MessageButton extends BaseMessageComponent {
* @param {MessageButton|MessageButtonOptions} [data={}] MessageButton to clone or raw data * @param {MessageButton|MessageButtonOptions} [data={}] MessageButton to clone or raw data
*/ */
constructor(data = {}) { constructor(data = {}) {
super({ type: 'BUTTON' }); super({ type: 'BUTTON' }, data);
this.setup(data); this.setup(data);
} }

View File

@@ -42,7 +42,7 @@ class MessageSelectMenu extends BaseMessageComponent {
* @param {MessageSelectMenu|MessageSelectMenuOptions} [data={}] MessageSelectMenu to clone or raw data * @param {MessageSelectMenu|MessageSelectMenuOptions} [data={}] MessageSelectMenu to clone or raw data
*/ */
constructor(data = {}) { constructor(data = {}) {
super({ type: BaseMessageComponent.resolveType(data.type) ?? 'STRING_SELECT' }); super({ type: BaseMessageComponent.resolveType(data.type) ?? 'STRING_SELECT' }, data);
this.setup(data); this.setup(data);
} }

View File

@@ -0,0 +1,43 @@
'use strict';
const BaseMessageComponent = require('./BaseMessageComponent');
const { MessageComponentTypes } = require('../util/Constants');
class SectionComponent extends BaseMessageComponent {
/**
* @property {TextDisplayComponent[]} [components] One to three text components
* @property {ThumbnailComponent|MessageButton} [accessory] A thumbnail or a button component, with a future possibility of adding more compatible components
*/
/**
* @param {SectionComponent | APISectionComponent} [data={}] The data
*/
constructor(data = {}) {
super({ type: 'SECTION' }, data);
/**
* One to three text components
* @type {TextDisplayComponent[]}
*/
this.components = data.components?.map(c => BaseMessageComponent.create(c)) ?? [];
/**
* A thumbnail or a button component, with a future possibility of adding more compatible components
* @type {ThumbnailComponent|MessageButton}
*/
this.accessory = BaseMessageComponent.create(data.accessory) ?? null;
}
/**
* @returns {APISectionComponent}
*/
toJSON() {
return {
type: MessageComponentTypes[this.type],
components: this.components.map(c => c.toJSON()),
accessory: this.accessory.toJSON(),
};
}
}
module.exports = SectionComponent;

View File

@@ -0,0 +1,43 @@
'use strict';
const BaseMessageComponent = require('./BaseMessageComponent');
const { MessageComponentTypes, SeparatorSpacingSizes } = require('../util/Constants');
class SeparatorComponent extends BaseMessageComponent {
/**
* @property {SeparatorSpacingSizes} [spacing] Size of separator padding — SeparatorSpacingSizes.SMALL for small padding, SeparatorSpacingSizes.LARGE for large padding. Defaults to SeparatorSpacingSizes.SMALL
* @property {Boolean} [divider] Whether a visual divider should be displayed in the component. Defaults to true
*/
/**
* @param {SeparatorComponent | APISeparatorComponent} [data={}] The data
*/
constructor(data = {}) {
super({ type: 'SEPARATOR' }, data);
/**
* Size of separator padding — SeparatorSpacingSizes.SMALL for small padding, SeparatorSpacingSizes.LARGE for large padding. Defaults to SeparatorSpacingSizes.SMALL
* @type {SeparatorSpacingSizes}
*/
this.spacing = data.spacing ?? SeparatorSpacingSizes.SMALL;
/**
* Whether a visual divider should be displayed in the component. Defaults to true
* @type {Boolean}
*/
this.divider = data.divider ?? true;
}
/**
* @returns {APISeparatorComponent}
*/
toJSON() {
return {
type: MessageComponentTypes[this.type],
spacing: this.spacing,
divider: this.divider,
};
}
}
module.exports = SeparatorComponent;

View File

@@ -0,0 +1,35 @@
'use strict';
const BaseMessageComponent = require('./BaseMessageComponent');
const { MessageComponentTypes } = require('../util/Constants');
class TextDisplayComponent extends BaseMessageComponent {
/**
* @property {String} [content] Text that will be displayed similar to a message
*/
/**
* @param {TextDisplayComponent | APITextDisplayComponent} [data={}] The data
*/
constructor(data = {}) {
super({ type: 'TEXT_DISPLAY' }, data);
/**
* Text that will be displayed similar to a message
* @type {String}
*/
this.content = data.content ?? null;
}
/**
* @returns {APITextDisplayComponent}
*/
toJSON() {
return {
type: MessageComponentTypes[this.type],
content: this.content,
};
}
}
module.exports = TextDisplayComponent;

View File

@@ -27,7 +27,7 @@ class TextInputComponent extends BaseMessageComponent {
* @param {TextInputComponent|TextInputComponentOptions} [data={}] TextInputComponent to clone or raw data * @param {TextInputComponent|TextInputComponentOptions} [data={}] TextInputComponent to clone or raw data
*/ */
constructor(data = {}) { constructor(data = {}) {
super({ type: 'TEXT_INPUT' }); super({ type: 'TEXT_INPUT' }, data);
this.setup(data); this.setup(data);
} }

View File

@@ -0,0 +1,52 @@
'use strict';
const BaseMessageComponent = require('./BaseMessageComponent');
const UnfurledMediaItem = require('./UnfurledMediaItem');
const { MessageComponentTypes } = require('../util/Constants');
class ThumbnailComponent extends BaseMessageComponent {
/**
* @property {UnfurledMediaItem} [media] A url or attachment
* @property {String} [description] Alt text for the media, max 1024 characters
* @property {Boolean} [spoiler] Whether the thumbnail should be a spoiler (or blurred out). Defaults to false
*/
/**
* @param {ThumbnailComponent | APIThumbnailComponent} [data={}] The data
*/
constructor(data = {}) {
super({ type: 'THUMBNAIL' }, data);
/**
* A url or attachment
* @type {UnfurledMediaItem}
*/
this.media = new UnfurledMediaItem(data.media);
/**
* Alt text for the media, max 1024 characters
* @type {String}
*/
this.description = data.description ?? null;
/**
* Whether the thumbnail should be a spoiler (or blurred out). Defaults to false
* @type {Boolean}
*/
this.spoiler = data.spoiler ?? false;
}
/**
* @returns {APIThumbnailComponent}
*/
toJSON() {
return {
type: MessageComponentTypes[this.type],
media: this.media.toJSON(),
description: this.description,
spoiler: this.spoiler,
};
}
}
module.exports = ThumbnailComponent;

View File

@@ -0,0 +1,27 @@
'use strict';
class UnfurledMediaItem {
/**
* @property {string} [url] Supports arbitrary urls and `attachment://<filename>` references
*/
/**
* @param {UnfurledMediaItem | APIUnfurledMediaItem} [data={}] The data
*/
constructor(data = {}) {
/**
* @type {string}
*/
this.url = data.url ?? null;
}
/**
*
* @returns {APIUnfurledMediaItem}
*/
toJSON() {
return {
url: this.url,
};
}
}
module.exports = UnfurledMediaItem;

View File

@@ -1615,6 +1615,15 @@ exports.MessageComponentTypes = createEnum([
'ROLE_SELECT', 'ROLE_SELECT',
'MENTIONABLE_SELECT', 'MENTIONABLE_SELECT',
'CHANNEL_SELECT', 'CHANNEL_SELECT',
'SECTION',
'TEXT_DISPLAY',
'THUMBNAIL',
'MEDIA_GALLERY',
'FILE',
'SEPARATOR',
null,
null,
'CONTAINER',
]); ]);
/** /**
@@ -1796,6 +1805,8 @@ exports.RelationshipTypes = createEnum([
'IMPLICIT', 'IMPLICIT',
]); ]);
exports.SeparatorSpacingSizes = createEnum([null, 'SMALL', 'LARGE']);
exports._cleanupSymbol = Symbol('djsCleanup'); exports._cleanupSymbol = Symbol('djsCleanup');
function keyMirror(arr) { function keyMirror(arr) {
@@ -1855,6 +1866,7 @@ function createEnum(keys) {
* @property {Object<InteractionType, number>} InteractionTypes The type of an {@link Interaction} object. * @property {Object<InteractionType, number>} InteractionTypes The type of an {@link Interaction} object.
* @property {InviteScope[]} InviteScopes The scopes of an invite. * @property {InviteScope[]} InviteScopes The scopes of an invite.
* @property {Object<RelationshipType, number>} RelationshipTypes Relationship Enums * @property {Object<RelationshipType, number>} RelationshipTypes Relationship Enums
* * @property {Object<SeparatorSpacingSize, number>} SeparatorSpacingSize Relationship Enums
* @property {Object<MembershipState, number>} MembershipStates The value set for a team members membership state. * @property {Object<MembershipState, number>} MembershipStates The value set for a team members membership state.
* @property {Object<MessageButtonStyle, number>} MessageButtonStyles The style of a message button. * @property {Object<MessageButtonStyle, number>} MessageButtonStyles The style of a message button.
* @property {Object<MessageComponentType, number>} MessageComponentTypes The type of a message component. * @property {Object<MessageComponentType, number>} MessageComponentTypes The type of a message component.

View File

@@ -57,7 +57,7 @@ MessageFlags.FLAGS = {
SUPPRESS_NOTIFICATIONS: 1 << 12, SUPPRESS_NOTIFICATIONS: 1 << 12,
IS_VOICE_MESSAGE: 1 << 13, IS_VOICE_MESSAGE: 1 << 13,
HAS_SNAPSHOT: 1 << 14, HAS_SNAPSHOT: 1 << 14,
IS_UIKIT_COMPONENTS: 1 << 15, IS_COMPONENTS_V2: 1 << 15,
}; };
module.exports = MessageFlags; module.exports = MessageFlags;

23
typings/enums.d.ts vendored
View File

@@ -226,6 +226,24 @@ export const enum MessageComponentTypes {
ROLE_SELECT = 6, ROLE_SELECT = 6,
MENTIONABLE_SELECT = 7, MENTIONABLE_SELECT = 7,
CHANNEL_SELECT = 8, CHANNEL_SELECT = 8,
SECTION = 9,
TEXT_DISPLAY = 10,
THUMBNAIL = 11,
MEDIA_GALLERY = 12,
FILE = 13,
SEPARATOR = 14,
CONTAINER = 17,
}
export const enum MessageComponentInteractables {
ACTION_ROW = 1,
BUTTON = 2,
STRING_SELECT = 3,
TEXT_INPUT = 4,
USER_SELECT = 5,
ROLE_SELECT = 6,
MENTIONABLE_SELECT = 7,
CHANNEL_SELECT = 8,
} }
export const enum SelectMenuComponentTypes { export const enum SelectMenuComponentTypes {
@@ -325,3 +343,8 @@ export const enum RelationshipTypes {
PENDING_OUTGOING = 4, PENDING_OUTGOING = 4,
IMPLICIT = 5, IMPLICIT = 5,
} }
export const enum SeparatorSpacingSizes {
SMALL = 1,
LARGE = 2,
}

88
typings/index.d.ts vendored
View File

@@ -92,6 +92,7 @@ import {
MembershipStates, MembershipStates,
MessageButtonStyles, MessageButtonStyles,
MessageComponentTypes, MessageComponentTypes,
MessageComponentInteractables,
MessageTypes, MessageTypes,
MFALevels, MFALevels,
NSFWLevels, NSFWLevels,
@@ -116,6 +117,7 @@ import {
PollLayoutTypes, PollLayoutTypes,
ReactionTypes, ReactionTypes,
MessageReferenceTypes, MessageReferenceTypes,
SeparatorSpacingSizes,
} from './enums'; } from './enums';
import { import {
APIApplicationRoleConnectionMetadata, APIApplicationRoleConnectionMetadata,
@@ -178,6 +180,15 @@ import {
RawWelcomeScreenData, RawWelcomeScreenData,
RawWidgetData, RawWidgetData,
RawWidgetMemberData, RawWidgetMemberData,
APIUnfurledMediaItem,
APIContainerComponent,
APIFileComponent,
APISectionComponent,
APISeparatorComponent,
APIThumbnailComponent,
APITextDisplayComponent,
APIMediaGalleryComponent,
APIMediaGalleryItem,
} from './rawDataTypes'; } from './rawDataTypes';
import { Socket } from 'node:dgram'; import { Socket } from 'node:dgram';
@@ -2122,7 +2133,7 @@ export interface StringMappedInteractionTypes<Cached extends CacheType = CacheTy
export type WrapBooleanCache<T extends boolean> = If<T, 'cached', CacheType>; export type WrapBooleanCache<T extends boolean> = If<T, 'cached', CacheType>;
export type MappedInteractionTypes<Cached extends boolean = boolean> = EnumValueMapped< export type MappedInteractionTypes<Cached extends boolean = boolean> = EnumValueMapped<
typeof MessageComponentTypes, typeof MessageComponentInteractables,
{ {
BUTTON: ButtonInteraction<WrapBooleanCache<Cached>>; BUTTON: ButtonInteraction<WrapBooleanCache<Cached>>;
STRING_SELECT: StringSelectInteraction<WrapBooleanCache<Cached>>; STRING_SELECT: StringSelectInteraction<WrapBooleanCache<Cached>>;
@@ -2299,6 +2310,77 @@ export class MessageButton extends BaseMessageComponent {
private static resolveStyle(style: MessageButtonStyleResolvable): MessageButtonStyle; private static resolveStyle(style: MessageButtonStyleResolvable): MessageButtonStyle;
} }
export class UnfurledMediaItem {
public constructor(data?: UnfurledMediaItem | APIUnfurledMediaItem);
public url: string | null;
public toJSON(): APIUnfurledMediaItem;
}
export class MediaGalleryItem {
public constructor(data?: MediaGalleryItem | APIMediaGalleryItem);
public media: UnfurledMediaItem;
public description: string | null;
public spoiler: boolean;
public toJSON(): APIMediaGalleryItem;
}
export class MediaGalleryComponent extends BaseMessageComponent {
public constructor(data?: MediaGalleryComponent | APIMediaGalleryComponent);
public items: MediaGalleryItem[];
public toJSON(): APIMediaGalleryComponent;
}
export class FileComponent extends BaseMessageComponent {
public constructor(data?: FileComponent | APIFileComponent);
public file: UnfurledMediaItem;
public spoiler: boolean;
public toJSON(): APIFileComponent;
}
export class SeparatorComponent extends BaseMessageComponent {
public constructor(data?: SeparatorComponent | APISeparatorComponent);
public spacing: SeparatorSpacingSizes;
public divider: boolean;
public toJSON(): APISeparatorComponent;
}
export class TextDisplayComponent extends BaseMessageComponent {
public constructor(data?: TextDisplayComponent | APITextDisplayComponent);
public content: string | null;
public toJSON(): APITextDisplayComponent;
}
export class ThumbnailComponent extends BaseMessageComponent {
public constructor(data?: ThumbnailComponent | APIThumbnailComponent);
public media: UnfurledMediaItem;
public description: string | null;
public spoiler: boolean;
}
export class SectionComponent<T extends ThumbnailComponent | MessageButton> extends BaseMessageComponent {
public constructor(data?: SectionComponent<T> | APISectionComponent);
public components: TextDisplayComponent[];
public accessory: T[];
public toJSON(): APISectionComponent;
}
export class ContainerComponent<
U extends ThumbnailComponent | MessageButton,
T extends
| MessageActionRow
| TextDisplayComponent
| SectionComponent<U>
| MediaGalleryComponent
| SeparatorComponent
| FileComponent,
> extends BaseMessageComponent {
public constructor(data?: ContainerComponent<U, T> | APIContainerComponent);
public components: T[];
public accent_color: number | null;
public spoiler: boolean;
public toJSON(): APIContainerComponent;
}
export class MessageCollector extends Collector<Snowflake, Message> { export class MessageCollector extends Collector<Snowflake, Message> {
public constructor(channel: TextBasedChannel, options?: MessageCollectorOptions); public constructor(channel: TextBasedChannel, options?: MessageCollectorOptions);
private _handleChannelDeletion(channel: NonThreadGuildBasedChannel): void; private _handleChannelDeletion(channel: NonThreadGuildBasedChannel): void;
@@ -7077,9 +7159,9 @@ export type MessageComponentOptions =
| MessageButtonOptions | MessageButtonOptions
| MessageSelectMenuOptions; | MessageSelectMenuOptions;
export type MessageComponentType = keyof typeof MessageComponentTypes; export type MessageComponentType = keyof typeof MessageComponentInteractables;
export type MessageComponentTypeResolvable = MessageComponentType | MessageComponentTypes; export type MessageComponentTypeResolvable = MessageComponentType | MessageComponentInteractables;
export type GuildForumThreadMessageCreateOptions = Omit<MessageOptions, 'poll'> & export type GuildForumThreadMessageCreateOptions = Omit<MessageOptions, 'poll'> &
Pick<MessageOptions, 'flags' | 'stickers'>; Pick<MessageOptions, 'flags' | 'stickers'>;

View File

@@ -87,6 +87,8 @@ import {
GuildVerificationLevel, GuildVerificationLevel,
GuildFeature, GuildFeature,
LocalizationMap, LocalizationMap,
APIActionRowComponent,
APIActionRowComponentTypes,
} from 'discord-api-types/v10'; } from 'discord-api-types/v10';
import { GuildChannel, Guild, PermissionOverwrites } from '.'; import { GuildChannel, Guild, PermissionOverwrites } from '.';
import type { import type {
@@ -95,6 +97,8 @@ import type {
AutoModerationRuleKeywordPresetTypes, AutoModerationRuleKeywordPresetTypes,
AutoModerationRuleTriggerTypes, AutoModerationRuleTriggerTypes,
ApplicationRoleConnectionMetadataTypes, ApplicationRoleConnectionMetadataTypes,
MessageComponentTypes,
SeparatorSpacingSizes,
} from './enums'; } from './enums';
export type RawActivityData = GatewayActivity; export type RawActivityData = GatewayActivity;
@@ -340,3 +344,54 @@ export interface APIApplicationRoleConnectionMetadata {
description: string; description: string;
description_localizations?: LocalizationMap; description_localizations?: LocalizationMap;
} }
export interface APIBaseComponent<T extends MessageComponentTypes> {
type: T;
id?: number;
}
export interface APIUnfurledMediaItem {
url: string;
}
export interface APIMediaGalleryItem {
media: APIUnfurledMediaItem;
description: string;
spoiler: boolean;
}
export interface APISeparatorComponent extends APIBaseComponent<MessageComponentTypes.SEPARATOR> {
spacing: SeparatorSpacingSizes;
divider: boolean;
}
export interface APITextDisplayComponent extends APIBaseComponent<MessageComponentTypes.TEXT_DISPLAY> {
content: string;
}
export interface APIThumbnailComponent extends APIBaseComponent<MessageComponentTypes.THUMBNAIL> {
media: APIUnfurledMediaItem;
description: string;
spoiler: boolean;
}
export interface APIFileComponent extends APIBaseComponent<MessageComponentTypes.FILE> {
file: APIUnfurledMediaItem;
spoiler: boolean;
}
export interface APIMediaGalleryComponent extends APIBaseComponent<MessageComponentTypes.MEDIA_GALLERY> {
items: APIMediaGalleryItem;
}
export interface APISectionComponent extends APIBaseComponent<MessageComponentTypes.SECTION> {
components: APITextDisplayComponent[];
accessory: APIThumbnailComponent | APIMessageButtonInteractionData
}
export type APIContainerComponents = APIActionRowComponent<APIActionRowComponentTypes> | APITextDisplayComponent | APISectionComponent | APIMediaGalleryComponent | APISeparatorComponent | APIFileComponent;
export interface APIContainerComponent extends APIBaseComponent<MessageComponentTypes.CONTAINER> {
components: APIContainerComponents[];
accent_color: number;
spoiler: boolean;
}