diff --git a/.eslintrc.json b/.eslintrc.json index 283382f..9850c65 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -287,4 +287,4 @@ ], "linebreak-style": 0 } -} \ No newline at end of file +} diff --git a/src/structures/BaseMessageComponent.js b/src/structures/BaseMessageComponent.js index 8ae40df..026380b 100644 --- a/src/structures/BaseMessageComponent.js +++ b/src/structures/BaseMessageComponent.js @@ -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}`); diff --git a/src/structures/ContainerComponent.js b/src/structures/ContainerComponent.js new file mode 100644 index 00000000..3f44e9c --- /dev/null +++ b/src/structures/ContainerComponent.js @@ -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; diff --git a/src/structures/FileComponent.js b/src/structures/FileComponent.js new file mode 100644 index 00000000..0418a40 --- /dev/null +++ b/src/structures/FileComponent.js @@ -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:// 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:// 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; diff --git a/src/structures/MediaGalleryComponent.js b/src/structures/MediaGalleryComponent.js new file mode 100644 index 00000000..b7ea099 --- /dev/null +++ b/src/structures/MediaGalleryComponent.js @@ -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; diff --git a/src/structures/MediaGalleryItem.js b/src/structures/MediaGalleryItem.js new file mode 100644 index 00000000..4d145c8 --- /dev/null +++ b/src/structures/MediaGalleryItem.js @@ -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; diff --git a/src/structures/Message.js b/src/structures/Message.js index e5385bb..cb2c202 100644 --- a/src/structures/Message.js +++ b/src/structures/Message.js @@ -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 { diff --git a/src/structures/MessageActionRow.js b/src/structures/MessageActionRow.js index d2115d6..1e9ca5b 100644 --- a/src/structures/MessageActionRow.js +++ b/src/structures/MessageActionRow.js @@ -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 diff --git a/src/structures/MessageButton.js b/src/structures/MessageButton.js index a94c1ec..670e07b 100644 --- a/src/structures/MessageButton.js +++ b/src/structures/MessageButton.js @@ -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); } diff --git a/src/structures/MessageSelectMenu.js b/src/structures/MessageSelectMenu.js index 3a118dd..d2658ca 100644 --- a/src/structures/MessageSelectMenu.js +++ b/src/structures/MessageSelectMenu.js @@ -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); } diff --git a/src/structures/SectionComponent.js b/src/structures/SectionComponent.js new file mode 100644 index 00000000..cfe6600 --- /dev/null +++ b/src/structures/SectionComponent.js @@ -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; diff --git a/src/structures/SeparatorComponent.js b/src/structures/SeparatorComponent.js new file mode 100644 index 00000000..78ab6f2 --- /dev/null +++ b/src/structures/SeparatorComponent.js @@ -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; diff --git a/src/structures/TextDisplayComponent.js b/src/structures/TextDisplayComponent.js new file mode 100644 index 00000000..8fb96dc --- /dev/null +++ b/src/structures/TextDisplayComponent.js @@ -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; diff --git a/src/structures/TextInputComponent.js b/src/structures/TextInputComponent.js index af60ac1..684f366 100644 --- a/src/structures/TextInputComponent.js +++ b/src/structures/TextInputComponent.js @@ -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); } diff --git a/src/structures/ThumbnailComponent.js b/src/structures/ThumbnailComponent.js new file mode 100644 index 00000000..d8ab1de --- /dev/null +++ b/src/structures/ThumbnailComponent.js @@ -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; diff --git a/src/structures/UnfurledMediaItem.js b/src/structures/UnfurledMediaItem.js new file mode 100644 index 00000000..ea988be --- /dev/null +++ b/src/structures/UnfurledMediaItem.js @@ -0,0 +1,27 @@ +'use strict'; + +class UnfurledMediaItem { + /** + * @property {string} [url] Supports arbitrary urls and `attachment://` 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; diff --git a/src/util/Constants.js b/src/util/Constants.js index 02857a6..bc1e28d 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -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} InteractionTypes The type of an {@link Interaction} object. * @property {InviteScope[]} InviteScopes The scopes of an invite. * @property {Object} RelationshipTypes Relationship Enums + * * @property {Object} SeparatorSpacingSize Relationship Enums * @property {Object} MembershipStates The value set for a team members membership state. * @property {Object} MessageButtonStyles The style of a message button. * @property {Object} MessageComponentTypes The type of a message component. diff --git a/src/util/MessageFlags.js b/src/util/MessageFlags.js index 2a461e8..73c67b7 100644 --- a/src/util/MessageFlags.js +++ b/src/util/MessageFlags.js @@ -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; diff --git a/typings/enums.d.ts b/typings/enums.d.ts index 4c8ddc0..d65c6c4 100644 --- a/typings/enums.d.ts +++ b/typings/enums.d.ts @@ -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, +} diff --git a/typings/index.d.ts b/typings/index.d.ts index 0457c56..eb9aee9 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -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 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 = If; export type MappedInteractionTypes = EnumValueMapped< - typeof MessageComponentTypes, + typeof MessageComponentInteractables, { BUTTON: ButtonInteraction>; STRING_SELECT: StringSelectInteraction>; @@ -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 extends BaseMessageComponent { + public constructor(data?: SectionComponent | APISectionComponent); + public components: TextDisplayComponent[]; + public accessory: T[]; + public toJSON(): APISectionComponent; +} + +export class ContainerComponent< + U extends ThumbnailComponent | MessageButton, + T extends + | MessageActionRow + | TextDisplayComponent + | SectionComponent + | MediaGalleryComponent + | SeparatorComponent + | FileComponent, +> extends BaseMessageComponent { + public constructor(data?: ContainerComponent | APIContainerComponent); + public components: T[]; + public accent_color: number | null; + public spoiler: boolean; + public toJSON(): APIContainerComponent; +} + export class MessageCollector extends Collector { 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 '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 & Pick; @@ -7984,14 +8066,14 @@ export type WSEventType = export type Serialized = T extends symbol | bigint | (() => any) ? never : T extends number | string | boolean | undefined - ? T - : T extends { toJSON(): infer R } - ? R - : T extends ReadonlyArray - ? Serialized[] - : T extends ReadonlyMap | ReadonlySet - ? {} - : { [K in keyof T]: Serialized }; + ? T + : T extends { toJSON(): infer R } + ? R + : T extends ReadonlyArray + ? Serialized[] + : T extends ReadonlyMap | ReadonlySet + ? {} + : { [K in keyof T]: Serialized }; //#endregion diff --git a/typings/rawDataTypes.d.ts b/typings/rawDataTypes.d.ts index f71348e..ae606a2 100644 --- a/typings/rawDataTypes.d.ts +++ b/typings/rawDataTypes.d.ts @@ -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 { + type: T; + id?: number; +} + +export interface APIUnfurledMediaItem { + url: string; +} + +export interface APIMediaGalleryItem { + media: APIUnfurledMediaItem; + description: string; + spoiler: boolean; +} + +export interface APISeparatorComponent extends APIBaseComponent { + spacing: SeparatorSpacingSizes; + divider: boolean; +} + +export interface APITextDisplayComponent extends APIBaseComponent { + content: string; +} + +export interface APIThumbnailComponent extends APIBaseComponent { + media: APIUnfurledMediaItem; + description: string; + spoiler: boolean; +} + +export interface APIFileComponent extends APIBaseComponent { + file: APIUnfurledMediaItem; + spoiler: boolean; +} + +export interface APIMediaGalleryComponent extends APIBaseComponent { + items: APIMediaGalleryItem; +} + +export interface APISectionComponent extends APIBaseComponent { + components: APITextDisplayComponent[]; + accessory: APIThumbnailComponent | APIMessageButtonInteractionData +} + +export type APIContainerComponents = APIActionRowComponent | APITextDisplayComponent | APISectionComponent | APIMediaGalleryComponent | APISeparatorComponent | APIFileComponent; +export interface APIContainerComponent extends APIBaseComponent { + components: APIContainerComponents[]; + accent_color: number; + spoiler: boolean; +} \ No newline at end of file