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

@@ -287,4 +287,4 @@
],
"linebreak-style": 0
}
}
}

View File

@@ -43,12 +43,14 @@ class BaseMessageComponent {
/**
* @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
* @type {?MessageComponentType}
*/
this.rawData = componentData;
this.type = 'type' in data ? BaseMessageComponent.resolveType(data.type) : null;
}
@@ -90,6 +92,41 @@ class BaseMessageComponent {
component = data instanceof TextInputComponent ? data : new TextInputComponent(data);
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:
if (client) {
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) {
/**
* A list of MessageActionRows in the message
* @type {MessageActionRow[]}
* A list of components in the message
* @type {MessageActionRow[] | ContainerComponent[]}
*/
this.components = data.components.map(c => BaseMessageComponent.create(c, this.client));
} else {

View File

@@ -42,7 +42,7 @@ class MessageActionRow extends BaseMessageComponent {
* @param {Client} [client] The client constructing this MessageActionRow, if provided
*/
constructor(data = {}, client = null) {
super({ type: 'ACTION_ROW' });
super({ type: 'ACTION_ROW' }, data);
/**
* 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
*/
constructor(data = {}) {
super({ type: 'BUTTON' });
super({ type: 'BUTTON' }, data);
this.setup(data);
}

View File

@@ -42,7 +42,7 @@ class MessageSelectMenu extends BaseMessageComponent {
* @param {MessageSelectMenu|MessageSelectMenuOptions} [data={}] MessageSelectMenu to clone or raw data
*/
constructor(data = {}) {
super({ type: BaseMessageComponent.resolveType(data.type) ?? 'STRING_SELECT' });
super({ type: BaseMessageComponent.resolveType(data.type) ?? 'STRING_SELECT' }, 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
*/
constructor(data = {}) {
super({ type: 'TEXT_INPUT' });
super({ type: 'TEXT_INPUT' }, 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',
'MENTIONABLE_SELECT',
'CHANNEL_SELECT',
'SECTION',
'TEXT_DISPLAY',
'THUMBNAIL',
'MEDIA_GALLERY',
'FILE',
'SEPARATOR',
null,
null,
'CONTAINER',
]);
/**
@@ -1796,6 +1805,8 @@ exports.RelationshipTypes = createEnum([
'IMPLICIT',
]);
exports.SeparatorSpacingSizes = createEnum([null, 'SMALL', 'LARGE']);
exports._cleanupSymbol = Symbol('djsCleanup');
function keyMirror(arr) {
@@ -1855,6 +1866,7 @@ function createEnum(keys) {
* @property {Object<InteractionType, number>} InteractionTypes The type of an {@link Interaction} object.
* @property {InviteScope[]} InviteScopes The scopes of an invite.
* @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<MessageButtonStyle, number>} MessageButtonStyles The style of a message button.
* @property {Object<MessageComponentType, number>} MessageComponentTypes The type of a message component.

View File

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

23
typings/enums.d.ts vendored
View File

@@ -226,6 +226,24 @@ export const enum MessageComponentTypes {
ROLE_SELECT = 6,
MENTIONABLE_SELECT = 7,
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 {
@@ -325,3 +343,8 @@ export const enum RelationshipTypes {
PENDING_OUTGOING = 4,
IMPLICIT = 5,
}
export const enum SeparatorSpacingSizes {
SMALL = 1,
LARGE = 2,
}

120
typings/index.d.ts vendored
View File

@@ -92,6 +92,7 @@ import {
MembershipStates,
MessageButtonStyles,
MessageComponentTypes,
MessageComponentInteractables,
MessageTypes,
MFALevels,
NSFWLevels,
@@ -116,6 +117,7 @@ import {
PollLayoutTypes,
ReactionTypes,
MessageReferenceTypes,
SeparatorSpacingSizes,
} from './enums';
import {
APIApplicationRoleConnectionMetadata,
@@ -178,6 +180,15 @@ import {
RawWelcomeScreenData,
RawWidgetData,
RawWidgetMemberData,
APIUnfurledMediaItem,
APIContainerComponent,
APIFileComponent,
APISectionComponent,
APISeparatorComponent,
APIThumbnailComponent,
APITextDisplayComponent,
APIMediaGalleryComponent,
APIMediaGalleryItem,
} from './rawDataTypes';
import { Socket } from 'node:dgram';
@@ -1594,8 +1605,8 @@ export class GuildAuditLogsEntry<
TAction = TActionRaw extends keyof GuildAuditLogsIds
? GuildAuditLogsIds[TActionRaw]
: TActionRaw extends null
? 'ALL'
: TActionRaw,
? 'ALL'
: TActionRaw,
TActionType extends GuildAuditLogsActionType = TAction extends keyof GuildAuditLogsTypes
? GuildAuditLogsTypes[TAction][1]
: 'ALL',
@@ -1942,10 +1953,10 @@ export type CacheTypeReducer<
> = [State] extends ['cached']
? CachedType
: [State] extends ['raw']
? RawType
: [State] extends ['raw' | 'cached']
? PresentType
: Fallback;
? RawType
: [State] extends ['raw' | 'cached']
? PresentType
: Fallback;
export class Interaction<Cached extends CacheType = CacheType> extends Base {
// This a technique used to brand different cached types. Or else we'll get `never` errors on typeguard checks.
@@ -2122,7 +2133,7 @@ export interface StringMappedInteractionTypes<Cached extends CacheType = CacheTy
export type WrapBooleanCache<T extends boolean> = If<T, 'cached', CacheType>;
export type MappedInteractionTypes<Cached extends boolean = boolean> = EnumValueMapped<
typeof MessageComponentTypes,
typeof MessageComponentInteractables,
{
BUTTON: ButtonInteraction<WrapBooleanCache<Cached>>;
STRING_SELECT: StringSelectInteraction<WrapBooleanCache<Cached>>;
@@ -2299,6 +2310,77 @@ export class MessageButton extends BaseMessageComponent {
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> {
public constructor(channel: TextBasedChannel, options?: MessageCollectorOptions);
private _handleChannelDeletion(channel: NonThreadGuildBasedChannel): void;
@@ -6833,8 +6915,8 @@ export type GuildScheduledEventResolvable = Snowflake | GuildScheduledEvent;
export type GuildScheduledEventSetStatusArg<T extends GuildScheduledEventStatus> = T extends 'SCHEDULED'
? 'ACTIVE' | 'CANCELED'
: T extends 'ACTIVE'
? 'COMPLETED'
: never;
? 'COMPLETED'
: never;
export type GuildScheduledEventStatus = keyof typeof GuildScheduledEventStatuses;
@@ -7077,9 +7159,9 @@ export type MessageComponentOptions =
| MessageButtonOptions
| 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'> &
Pick<MessageOptions, 'flags' | 'stickers'>;
@@ -7984,14 +8066,14 @@ export type WSEventType =
export type Serialized<T> = T extends symbol | bigint | (() => any)
? never
: T extends number | string | boolean | undefined
? T
: T extends { toJSON(): infer R }
? R
: T extends ReadonlyArray<infer V>
? Serialized<V>[]
: T extends ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>
? {}
: { [K in keyof T]: Serialized<T[K]> };
? T
: T extends { toJSON(): infer R }
? R
: T extends ReadonlyArray<infer V>
? Serialized<V>[]
: T extends ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>
? {}
: { [K in keyof T]: Serialized<T[K]> };
//#endregion

View File

@@ -87,6 +87,8 @@ import {
GuildVerificationLevel,
GuildFeature,
LocalizationMap,
APIActionRowComponent,
APIActionRowComponentTypes,
} from 'discord-api-types/v10';
import { GuildChannel, Guild, PermissionOverwrites } from '.';
import type {
@@ -95,6 +97,8 @@ import type {
AutoModerationRuleKeywordPresetTypes,
AutoModerationRuleTriggerTypes,
ApplicationRoleConnectionMetadataTypes,
MessageComponentTypes,
SeparatorSpacingSizes,
} from './enums';
export type RawActivityData = GatewayActivity;
@@ -340,3 +344,54 @@ export interface APIApplicationRoleConnectionMetadata {
description: string;
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;
}