mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-02 04:56:07 +00:00
feat: components V2 (#337)
* feat: components v2 * fix: build * chore: apply formatting * refactor(components): some types * refactor(types): replace TopLevelComponents with APITopLevelComponent in REST * fix: unify components * refactor(TextDisplay): rename content method to setContent for clarity * refactor(builders): add missing builder from component * fix: touche * feat(webhook): webhook params for components v2 --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
f03eb57ed5
commit
589a59c5f6
@ -9,6 +9,7 @@ import type {
|
|||||||
RESTPatchAPIWebhookResult,
|
RESTPatchAPIWebhookResult,
|
||||||
RESTPatchAPIWebhookWithTokenJSONBody,
|
RESTPatchAPIWebhookWithTokenJSONBody,
|
||||||
RESTPatchAPIWebhookWithTokenMessageJSONBody,
|
RESTPatchAPIWebhookWithTokenMessageJSONBody,
|
||||||
|
RESTPatchAPIWebhookWithTokenMessageQuery,
|
||||||
RESTPatchAPIWebhookWithTokenMessageResult,
|
RESTPatchAPIWebhookWithTokenMessageResult,
|
||||||
RESTPatchAPIWebhookWithTokenResult,
|
RESTPatchAPIWebhookWithTokenResult,
|
||||||
RESTPostAPIWebhookWithTokenGitHubQuery,
|
RESTPostAPIWebhookWithTokenGitHubQuery,
|
||||||
@ -33,7 +34,9 @@ export interface WebhookRoutes {
|
|||||||
token: string,
|
token: string,
|
||||||
): {
|
): {
|
||||||
get(args?: RestArgumentsNoBody): Promise<RESTGetAPIWebhookWithTokenResult>;
|
get(args?: RestArgumentsNoBody): Promise<RESTGetAPIWebhookWithTokenResult>;
|
||||||
patch(args: RestArguments<RESTPatchAPIWebhookWithTokenJSONBody>): Promise<RESTPatchAPIWebhookWithTokenResult>;
|
patch(
|
||||||
|
args: RestArguments<RESTPatchAPIWebhookWithTokenJSONBody, RESTPatchAPIWebhookWithTokenMessageQuery>,
|
||||||
|
): Promise<RESTPatchAPIWebhookWithTokenResult>;
|
||||||
delete(args?: RestArgumentsNoBody): Promise<RESTDeleteAPIWebhookWithTokenResult>;
|
delete(args?: RestArgumentsNoBody): Promise<RESTDeleteAPIWebhookWithTokenResult>;
|
||||||
post(
|
post(
|
||||||
args: RestArguments<RESTPostAPIWebhookWithTokenJSONBody, RESTPostAPIWebhookWithTokenQuery>,
|
args: RestArguments<RESTPostAPIWebhookWithTokenJSONBody, RESTPostAPIWebhookWithTokenQuery>,
|
||||||
|
@ -7,13 +7,13 @@ import {
|
|||||||
} from '../types';
|
} from '../types';
|
||||||
import { BaseComponentBuilder } from './Base';
|
import { BaseComponentBuilder } from './Base';
|
||||||
import { fromComponent } from './index';
|
import { fromComponent } from './index';
|
||||||
import type { BuilderComponents, FixedComponents } from './types';
|
import type { ActionBuilderComponents, FixedComponents } from './types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an Action Row component in a message.
|
* Represents an Action Row component in a message.
|
||||||
* @template T - The type of components in the Action Row.
|
* @template T - The type of components in the Action Row.
|
||||||
*/
|
*/
|
||||||
export class ActionRow<T extends BuilderComponents> extends BaseComponentBuilder<
|
export class ActionRow<T extends ActionBuilderComponents = ActionBuilderComponents> extends BaseComponentBuilder<
|
||||||
APIActionRowComponent<APIActionRowComponentTypes>
|
APIActionRowComponent<APIActionRowComponentTypes>
|
||||||
> {
|
> {
|
||||||
/**
|
/**
|
||||||
@ -50,8 +50,8 @@ export class ActionRow<T extends BuilderComponents> extends BaseComponentBuilder
|
|||||||
* @example
|
* @example
|
||||||
* actionRow.setComponents([buttonComponent1, buttonComponent2]);
|
* actionRow.setComponents([buttonComponent1, buttonComponent2]);
|
||||||
*/
|
*/
|
||||||
setComponents(component: FixedComponents<T>[]): this {
|
setComponents(...component: RestOrArray<FixedComponents<T>>): this {
|
||||||
this.components = [...component];
|
this.components = component.flat() as FixedComponents<T>[];
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
import { type EmojiResolvable, resolvePartialEmoji } from '../common';
|
import { type EmojiResolvable, resolvePartialEmoji } from '../common';
|
||||||
import { type APIButtonComponent, type APIMessageComponentEmoji, type ButtonStyle, ComponentType } from '../types';
|
import { type APIButtonComponent, type APIMessageComponentEmoji, type ButtonStyle, ComponentType } from '../types';
|
||||||
|
import { BaseComponentBuilder } from './Base';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a button component.
|
* Represents a button component.
|
||||||
* @template Type - The type of the button component.
|
* @template Type - The type of the button component.
|
||||||
*/
|
*/
|
||||||
export class Button {
|
export class Button extends BaseComponentBuilder<APIButtonComponent> {
|
||||||
/**
|
constructor(data: Partial<APIButtonComponent> = {}) {
|
||||||
* Creates a new Button instance.
|
super({ type: ComponentType.Button, ...data });
|
||||||
* @param data - The initial data for the button.
|
|
||||||
*/
|
|
||||||
constructor(public data: Partial<APIButtonComponent> = {}) {
|
|
||||||
this.data.type = ComponentType.Button;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,12 +73,4 @@ export class Button {
|
|||||||
(this.data as Extract<APIButtonComponent, { sku_id?: string }>).sku_id = skuId;
|
(this.data as Extract<APIButtonComponent, { sku_id?: string }>).sku_id = skuId;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the Button instance to its JSON representation.
|
|
||||||
* @returns The JSON representation of the Button instance.
|
|
||||||
*/
|
|
||||||
toJSON() {
|
|
||||||
return { ...this.data } as Partial<APIButtonComponent>;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
100
src/builders/Container.ts
Normal file
100
src/builders/Container.ts
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
import { type ActionRow, fromComponent } from '.';
|
||||||
|
import { type ColorResolvable, type RestOrArray, resolveColor } from '../common';
|
||||||
|
import { type APIContainerComponent, ComponentType } from '../types';
|
||||||
|
import { BaseComponentBuilder } from './Base';
|
||||||
|
import type { File } from './File';
|
||||||
|
import type { MediaGallery } from './MediaGallery';
|
||||||
|
import type { Section } from './Section';
|
||||||
|
import type { Separator } from './Separator';
|
||||||
|
import type { TextDisplay } from './TextDisplay';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the possible component types that can be added to a Container.
|
||||||
|
*/
|
||||||
|
export type ContainerBuilderComponents = ActionRow | TextDisplay | Section | MediaGallery | Separator | File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a container component builder.
|
||||||
|
* Containers group other components together.
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const container = new Container()
|
||||||
|
* .addComponents(
|
||||||
|
* new TextDisplay('This is text inside a container!'),
|
||||||
|
* new ActionRow().addComponents(new Button().setLabel('Click me!'))
|
||||||
|
* )
|
||||||
|
* .setColor('Blue');
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export class Container extends BaseComponentBuilder<APIContainerComponent> {
|
||||||
|
/**
|
||||||
|
* The components held within this container.
|
||||||
|
*/
|
||||||
|
components: ContainerBuilderComponents[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new Container.
|
||||||
|
* @param data Optional initial data for the container.
|
||||||
|
*/
|
||||||
|
constructor({ components, ...data }: Partial<APIContainerComponent> = {}) {
|
||||||
|
super({ ...data, type: ComponentType.Container });
|
||||||
|
this.components = (components?.map(fromComponent) ?? []) as ContainerBuilderComponents[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds components to the container.
|
||||||
|
* @param components The components to add. Can be a single component, an array of components, or multiple components as arguments.
|
||||||
|
* @returns The updated Container instance.
|
||||||
|
*/
|
||||||
|
addComponents(...components: RestOrArray<ContainerBuilderComponents>) {
|
||||||
|
this.components = this.components.concat(components.flat());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the components for the container, replacing any existing components.
|
||||||
|
* @param components The components to set. Can be a single component, an array of components, or multiple components as arguments.
|
||||||
|
* @returns The updated Container instance.
|
||||||
|
*/
|
||||||
|
setComponents(...components: RestOrArray<ContainerBuilderComponents>) {
|
||||||
|
this.components = components.flat();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the container's content should be visually marked as a spoiler.
|
||||||
|
* @param spoiler Whether the content is a spoiler (defaults to true).
|
||||||
|
* @returns The updated Container instance.
|
||||||
|
*/
|
||||||
|
setSpoiler(spoiler = true) {
|
||||||
|
this.data.spoiler = spoiler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the accent color for the container.
|
||||||
|
* @param color The color resolvable (e.g., hex code, color name, integer).
|
||||||
|
* @returns The updated Container instance.
|
||||||
|
*/
|
||||||
|
setColor(color: ColorResolvable) {
|
||||||
|
this.data.accent_color = resolveColor(color);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ID for the container.
|
||||||
|
* @param id The ID to set.
|
||||||
|
* @returns The updated Container instance.
|
||||||
|
*/
|
||||||
|
setId(id: number) {
|
||||||
|
this.data.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
...this.data,
|
||||||
|
components: this.components.map(c => c.toJSON()),
|
||||||
|
} as APIContainerComponent;
|
||||||
|
}
|
||||||
|
}
|
52
src/builders/File.ts
Normal file
52
src/builders/File.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { type APIFileComponent, ComponentType } from '../types';
|
||||||
|
import { BaseComponentBuilder } from './Base';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a file component builder.
|
||||||
|
* Used to display files within containers.
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const file = new File()
|
||||||
|
* .setMedia('https://example.com/image.png')
|
||||||
|
* .setSpoiler();
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export class File extends BaseComponentBuilder<APIFileComponent> {
|
||||||
|
/**
|
||||||
|
* Constructs a new File component.
|
||||||
|
* @param data Optional initial data for the file component.
|
||||||
|
*/
|
||||||
|
constructor(data: Partial<APIFileComponent> = {}) {
|
||||||
|
super({ type: ComponentType.File, ...data });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ID for the file component.
|
||||||
|
* @param id The ID to set.
|
||||||
|
* @returns The updated File instance.
|
||||||
|
*/
|
||||||
|
setId(id: number) {
|
||||||
|
this.data.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the media URL for the file.
|
||||||
|
* @param url The URL of the file to display.
|
||||||
|
* @returns The updated File instance.
|
||||||
|
*/
|
||||||
|
setMedia(url: string) {
|
||||||
|
this.data.file = { url };
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the file should be visually marked as a spoiler.
|
||||||
|
* @param spoiler Whether the file is a spoiler (defaults to true).
|
||||||
|
* @returns The updated File instance.
|
||||||
|
*/
|
||||||
|
setSpoiler(spoiler = true) {
|
||||||
|
this.data.spoiler = spoiler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
112
src/builders/MediaGallery.ts
Normal file
112
src/builders/MediaGallery.ts
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import type { RestOrArray } from '../common';
|
||||||
|
import { type APIMediaGalleryComponent, type APIMediaGalleryItems, ComponentType } from '../types';
|
||||||
|
import { BaseComponentBuilder } from './Base';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a media gallery component builder.
|
||||||
|
* Used to display a collection of media items.
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const gallery = new MediaGallery()
|
||||||
|
* .addItems(
|
||||||
|
* new MediaGalleryItem().setMedia('https://example.com/image1.png').setDescription('Image 1'),
|
||||||
|
* new MediaGalleryItem().setMedia('https://example.com/image2.jpg').setSpoiler()
|
||||||
|
* );
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export class MediaGallery extends BaseComponentBuilder<APIMediaGalleryComponent> {
|
||||||
|
items: MediaGalleryItem[];
|
||||||
|
/**
|
||||||
|
* Constructs a new MediaGallery.
|
||||||
|
* @param data Optional initial data for the media gallery.
|
||||||
|
*/
|
||||||
|
constructor({ items, ...data }: Partial<APIMediaGalleryComponent> = {}) {
|
||||||
|
super({ type: ComponentType.MediaGallery, ...data });
|
||||||
|
this.items = (items?.map(i => new MediaGalleryItem(i)) ?? []) as MediaGalleryItem[];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Sets the ID for the media gallery component.
|
||||||
|
* @param id The ID to set.
|
||||||
|
* @returns The updated MediaGallery instance.
|
||||||
|
*/
|
||||||
|
setId(id: number) {
|
||||||
|
this.data.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds items to the media gallery.
|
||||||
|
* @param items The items to add. Can be a single item, an array of items, or multiple items as arguments.
|
||||||
|
* @returns The updated MediaGallery instance.
|
||||||
|
*/
|
||||||
|
addItems(...items: RestOrArray<MediaGalleryItem>) {
|
||||||
|
this.items = this.items.concat(items.flat());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the items for the media gallery, replacing any existing items.
|
||||||
|
* @param items The items to set. Can be a single item, an array of items, or multiple items as arguments.
|
||||||
|
* @returns The updated MediaGallery instance.
|
||||||
|
*/
|
||||||
|
setItems(...items: RestOrArray<MediaGalleryItem>) {
|
||||||
|
this.items = items.flat();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
...this.data,
|
||||||
|
items: this.items.map(i => i.toJSON()),
|
||||||
|
} as APIMediaGalleryComponent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an item within a MediaGallery.
|
||||||
|
*/
|
||||||
|
export class MediaGalleryItem {
|
||||||
|
/**
|
||||||
|
* Constructs a new MediaGalleryItem.
|
||||||
|
* @param data Optional initial data for the media gallery item.
|
||||||
|
*/
|
||||||
|
constructor(public data: Partial<APIMediaGalleryItems> = {}) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the media URL for this gallery item.
|
||||||
|
* @param url The URL of the media.
|
||||||
|
* @returns The updated MediaGalleryItem instance.
|
||||||
|
*/
|
||||||
|
setMedia(url: string) {
|
||||||
|
this.data.media = { url };
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the description for this gallery item.
|
||||||
|
* @param desc The description text.
|
||||||
|
* @returns The updated MediaGalleryItem instance.
|
||||||
|
*/
|
||||||
|
setDescription(desc: string) {
|
||||||
|
this.data.description = desc;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this gallery item should be visually marked as a spoiler.
|
||||||
|
* @param spoiler Whether the item is a spoiler (defaults to true).
|
||||||
|
* @returns The updated MediaGalleryItem instance.
|
||||||
|
*/
|
||||||
|
setSpoiler(spoiler = true) {
|
||||||
|
this.data.spoiler = spoiler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts this MediaGalleryItem instance to its JSON representation.
|
||||||
|
* @returns The JSON representation of the item data.
|
||||||
|
*/
|
||||||
|
toJSON() {
|
||||||
|
return { ...this.data };
|
||||||
|
}
|
||||||
|
}
|
55
src/builders/Section.ts
Normal file
55
src/builders/Section.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { type Button, fromComponent } from '.';
|
||||||
|
import type { RestOrArray } from '../common';
|
||||||
|
import { type APISectionComponent, ComponentType } from '../types';
|
||||||
|
import { BaseComponentBuilder } from './Base';
|
||||||
|
import type { TextDisplay } from './TextDisplay';
|
||||||
|
import type { Thumbnail } from './Thumbnail';
|
||||||
|
|
||||||
|
export class Section<
|
||||||
|
Ac extends Button | Thumbnail = Button | Thumbnail,
|
||||||
|
> extends BaseComponentBuilder<APISectionComponent> {
|
||||||
|
components: TextDisplay[];
|
||||||
|
accessory!: Ac;
|
||||||
|
constructor({ components, accessory, ...data }: Partial<APISectionComponent> = {}) {
|
||||||
|
super({ type: ComponentType.Section, ...data });
|
||||||
|
this.components = (components?.map(component => fromComponent(component)) ?? []) as TextDisplay[];
|
||||||
|
if (accessory) this.accessory = fromComponent(accessory) as Ac;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds components to this section.
|
||||||
|
* @param components The components to add
|
||||||
|
* @example section.addComponents(new TextDisplay().content('Hello'));
|
||||||
|
*/
|
||||||
|
addComponents(...components: RestOrArray<TextDisplay>) {
|
||||||
|
this.components = this.components.concat(components.flat());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the components for this section.
|
||||||
|
* @param components The components to set
|
||||||
|
* @example section.setComponents(new TextDisplay().content('Hello'));
|
||||||
|
*/
|
||||||
|
setComponents(...components: RestOrArray<TextDisplay>) {
|
||||||
|
this.components = components.flat();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
setAccessory(accessory: Ac) {
|
||||||
|
this.accessory = accessory;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts this section to JSON.
|
||||||
|
* @returns The JSON representation of this section
|
||||||
|
*/
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
...this.data,
|
||||||
|
components: this.components.map(component => component.toJSON()),
|
||||||
|
accessory: this.accessory.toJSON(),
|
||||||
|
} as APISectionComponent;
|
||||||
|
}
|
||||||
|
}
|
54
src/builders/Separator.ts
Normal file
54
src/builders/Separator.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { type APISeparatorComponent, ComponentType, type Spacing } from '../types';
|
||||||
|
import { BaseComponentBuilder } from './Base';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a separator component builder.
|
||||||
|
* Used to add visual spacing or dividers between components.
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* // A simple separator for spacing
|
||||||
|
* const spacingSeparator = new Separator().setSpacing(Spacing.Small);
|
||||||
|
*
|
||||||
|
* // A separator acting as a visual divider
|
||||||
|
* const dividerSeparator = new Separator().setDivider(true);
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export class Separator extends BaseComponentBuilder<APISeparatorComponent> {
|
||||||
|
/**
|
||||||
|
* Constructs a new Separator component.
|
||||||
|
* @param data Optional initial data for the separator component.
|
||||||
|
*/
|
||||||
|
constructor(data: Partial<APISeparatorComponent> = {}) {
|
||||||
|
super({ type: ComponentType.Separator, ...data });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ID for the separator component.
|
||||||
|
* @param id The ID to set.
|
||||||
|
* @returns The updated Separator instance.
|
||||||
|
*/
|
||||||
|
setId(id: number) {
|
||||||
|
this.data.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this separator should act as a visual divider.
|
||||||
|
* @param divider Whether to render as a divider (defaults to false).
|
||||||
|
* @returns The updated Separator instance.
|
||||||
|
*/
|
||||||
|
setDivider(divider = false) {
|
||||||
|
this.data.divider = divider;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the amount of spacing this separator provides.
|
||||||
|
* @param spacing The desired spacing level ('None', 'Small', 'Medium', 'Large').
|
||||||
|
* @returns The updated Separator instance.
|
||||||
|
*/
|
||||||
|
setSpacing(spacing: Spacing) {
|
||||||
|
this.data.spacing = spacing;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
40
src/builders/TextDisplay.ts
Normal file
40
src/builders/TextDisplay.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { type APITextDispalyComponent, ComponentType } from '../types';
|
||||||
|
import { BaseComponentBuilder } from './Base';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a text display component builder.
|
||||||
|
* Used to display simple text content.
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const text = new TextDisplay().content('Hello, world!');
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export class TextDisplay extends BaseComponentBuilder<APITextDispalyComponent> {
|
||||||
|
/**
|
||||||
|
* Constructs a new TextDisplay component.
|
||||||
|
* @param data Optional initial data for the text display component.
|
||||||
|
*/
|
||||||
|
constructor(data: Partial<APITextDispalyComponent> = {}) {
|
||||||
|
super({ type: ComponentType.TextDisplay, ...data });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ID for the text display component.
|
||||||
|
* @param id The ID to set.
|
||||||
|
* @returns The updated TextDisplay instance.
|
||||||
|
*/
|
||||||
|
setId(id: number) {
|
||||||
|
this.data.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the text content to display.
|
||||||
|
* @param content The text content.
|
||||||
|
* @returns The updated TextDisplay instance.
|
||||||
|
*/
|
||||||
|
setContent(content: string) {
|
||||||
|
this.data.content = content;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
62
src/builders/Thumbnail.ts
Normal file
62
src/builders/Thumbnail.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { type APIThumbnailComponent, ComponentType } from '../types';
|
||||||
|
import { BaseComponentBuilder } from './Base';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a thumbnail component builder.
|
||||||
|
* Used to display a small image preview, often alongside other content.
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const thumbnail = new Thumbnail()
|
||||||
|
* .setMedia('https://example.com/thumbnail.jpg')
|
||||||
|
* .setDescription('A cool thumbnail');
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export class Thumbnail extends BaseComponentBuilder<APIThumbnailComponent> {
|
||||||
|
/**
|
||||||
|
* Constructs a new Thumbnail component.
|
||||||
|
* @param data Optional initial data for the thumbnail component.
|
||||||
|
*/
|
||||||
|
constructor(data: Partial<APIThumbnailComponent> = {}) {
|
||||||
|
super({ type: ComponentType.Thumbnail, ...data });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the thumbnail should be visually marked as a spoiler.
|
||||||
|
* @param spoiler Whether the thumbnail is a spoiler (defaults to true).
|
||||||
|
* @returns The updated Thumbnail instance.
|
||||||
|
*/
|
||||||
|
setSpoiler(spoiler = true) {
|
||||||
|
this.data.spoiler = spoiler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the description for the thumbnail.
|
||||||
|
* @param description The description text. Can be undefined to remove the description.
|
||||||
|
* @returns The updated Thumbnail instance.
|
||||||
|
*/
|
||||||
|
setDescription(description: string | undefined) {
|
||||||
|
this.data.description = description;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ID for the thumbnail component.
|
||||||
|
* @param id The ID to set.
|
||||||
|
* @returns The updated Thumbnail instance.
|
||||||
|
*/
|
||||||
|
setId(id: number) {
|
||||||
|
this.data.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the media URL for the thumbnail.
|
||||||
|
* @param url The URL of the image to display as a thumbnail.
|
||||||
|
* @returns The updated Thumbnail instance.
|
||||||
|
*/
|
||||||
|
setMedia(url: string) {
|
||||||
|
this.data.media = { url };
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,11 @@
|
|||||||
import { type APIActionRowComponent, type APIActionRowComponentTypes, ComponentType } from '../types';
|
import { type APIComponents, ComponentType } from '../types';
|
||||||
import { ActionRow } from './ActionRow';
|
import { ActionRow } from './ActionRow';
|
||||||
import { Button } from './Button';
|
import { Button } from './Button';
|
||||||
|
import { Container } from './Container';
|
||||||
|
import { File } from './File';
|
||||||
|
import { MediaGallery } from './MediaGallery';
|
||||||
import { TextInput } from './Modal';
|
import { TextInput } from './Modal';
|
||||||
|
import { Section } from './Section';
|
||||||
import {
|
import {
|
||||||
ChannelSelectMenu,
|
ChannelSelectMenu,
|
||||||
MentionableSelectMenu,
|
MentionableSelectMenu,
|
||||||
@ -9,29 +13,32 @@ import {
|
|||||||
StringSelectMenu,
|
StringSelectMenu,
|
||||||
UserSelectMenu,
|
UserSelectMenu,
|
||||||
} from './SelectMenu';
|
} from './SelectMenu';
|
||||||
|
import { Separator } from './Separator';
|
||||||
|
import { TextDisplay } from './TextDisplay';
|
||||||
|
import { Thumbnail } from './Thumbnail';
|
||||||
import type { BuilderComponents } from './types';
|
import type { BuilderComponents } from './types';
|
||||||
|
|
||||||
export * from './ActionRow';
|
export * from './ActionRow';
|
||||||
export * from './Attachment';
|
export * from './Attachment';
|
||||||
export * from './Base';
|
export * from './Base';
|
||||||
export * from './Button';
|
export * from './Button';
|
||||||
|
export * from './Container';
|
||||||
export * from './Embed';
|
export * from './Embed';
|
||||||
|
export * from './File';
|
||||||
|
export * from './MediaGallery';
|
||||||
export * from './Modal';
|
export * from './Modal';
|
||||||
export * from './SelectMenu';
|
|
||||||
export * from './Poll';
|
export * from './Poll';
|
||||||
|
export * from './Section';
|
||||||
|
export * from './SelectMenu';
|
||||||
|
export * from './Separator';
|
||||||
|
export * from './TextDisplay';
|
||||||
|
export * from './Thumbnail';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
|
||||||
export function fromComponent(
|
export function fromComponent(data: BuilderComponents | APIComponents): BuilderComponents {
|
||||||
data:
|
|
||||||
| BuilderComponents
|
|
||||||
| APIActionRowComponentTypes
|
|
||||||
| APIActionRowComponent<APIActionRowComponentTypes>
|
|
||||||
| ActionRow<BuilderComponents>,
|
|
||||||
): BuilderComponents | ActionRow<BuilderComponents> {
|
|
||||||
if ('toJSON' in data) {
|
if ('toJSON' in data) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case ComponentType.Button:
|
case ComponentType.Button:
|
||||||
return new Button(data);
|
return new Button(data);
|
||||||
@ -49,5 +56,19 @@ export function fromComponent(
|
|||||||
return new ChannelSelectMenu(data);
|
return new ChannelSelectMenu(data);
|
||||||
case ComponentType.ActionRow:
|
case ComponentType.ActionRow:
|
||||||
return new ActionRow(data);
|
return new ActionRow(data);
|
||||||
|
case ComponentType.Section:
|
||||||
|
return new Section(data);
|
||||||
|
case ComponentType.TextDisplay:
|
||||||
|
return new TextDisplay(data);
|
||||||
|
case ComponentType.Thumbnail:
|
||||||
|
return new Thumbnail(data);
|
||||||
|
case ComponentType.Container:
|
||||||
|
return new Container(data);
|
||||||
|
case ComponentType.MediaGallery:
|
||||||
|
return new MediaGallery(data);
|
||||||
|
case ComponentType.Separator:
|
||||||
|
return new Separator(data);
|
||||||
|
case ComponentType.File:
|
||||||
|
return new File(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,17 @@ import type {
|
|||||||
ModalSubmitInteraction,
|
ModalSubmitInteraction,
|
||||||
StringSelectMenuInteraction,
|
StringSelectMenuInteraction,
|
||||||
} from '../structures/Interaction';
|
} from '../structures/Interaction';
|
||||||
|
import type { ActionRow } from './ActionRow';
|
||||||
import type { Button } from './Button';
|
import type { Button } from './Button';
|
||||||
|
import type { Container } from './Container';
|
||||||
|
import type { File } from './File';
|
||||||
|
import type { MediaGallery } from './MediaGallery';
|
||||||
import type { TextInput } from './Modal';
|
import type { TextInput } from './Modal';
|
||||||
|
import type { Section } from './Section';
|
||||||
import type { BuilderSelectMenus } from './SelectMenu';
|
import type { BuilderSelectMenus } from './SelectMenu';
|
||||||
|
import type { Separator } from './Separator';
|
||||||
|
import type { TextDisplay } from './TextDisplay';
|
||||||
|
import type { Thumbnail } from './Thumbnail';
|
||||||
|
|
||||||
export type ComponentCallback<
|
export type ComponentCallback<
|
||||||
T extends ComponentInteraction | StringSelectMenuInteraction = ComponentInteraction | StringSelectMenuInteraction,
|
T extends ComponentInteraction | StringSelectMenuInteraction = ComponentInteraction | StringSelectMenuInteraction,
|
||||||
@ -25,7 +33,22 @@ export type ButtonID = Omit<Button, 'setURL'>;
|
|||||||
|
|
||||||
export type MessageBuilderComponents = FixedComponents<Button> | BuilderSelectMenus;
|
export type MessageBuilderComponents = FixedComponents<Button> | BuilderSelectMenus;
|
||||||
export type ModalBuilderComponents = TextInput;
|
export type ModalBuilderComponents = TextInput;
|
||||||
export type BuilderComponents = MessageBuilderComponents | TextInput;
|
export type ActionBuilderComponents = MessageBuilderComponents | TextInput;
|
||||||
|
|
||||||
|
export type BuilderComponents =
|
||||||
|
| ActionRow
|
||||||
|
| ActionBuilderComponents
|
||||||
|
| Section<Button | Thumbnail>
|
||||||
|
| Thumbnail
|
||||||
|
| TextDisplay
|
||||||
|
| Container
|
||||||
|
| Separator
|
||||||
|
| MediaGallery
|
||||||
|
| File
|
||||||
|
| TextInput;
|
||||||
|
|
||||||
|
export type TopLevelBuilders = Exclude<BuilderComponents, Thumbnail | TextInput>;
|
||||||
|
|
||||||
export type FixedComponents<T = Button> = T extends Button ? ButtonLink | ButtonID : T;
|
export type FixedComponents<T = Button> = T extends Button ? ButtonLink | ButtonID : T;
|
||||||
export interface ListenerOptions {
|
export interface ListenerOptions {
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
|
@ -1,19 +1,9 @@
|
|||||||
import type { RawFile } from '../../api';
|
import type { RawFile } from '../../api';
|
||||||
|
import type { Attachment, AttachmentBuilder, Embed, Modal, PollBuilder, TopLevelBuilders } from '../../builders';
|
||||||
import type {
|
import type {
|
||||||
ActionRow,
|
|
||||||
Attachment,
|
|
||||||
AttachmentBuilder,
|
|
||||||
BuilderComponents,
|
|
||||||
Embed,
|
|
||||||
Modal,
|
|
||||||
PollBuilder,
|
|
||||||
} from '../../builders';
|
|
||||||
import type {
|
|
||||||
APIActionRowComponent,
|
|
||||||
APIEmbed,
|
APIEmbed,
|
||||||
APIInteractionResponseCallbackData,
|
APIInteractionResponseCallbackData,
|
||||||
APIInteractionResponseChannelMessageWithSource,
|
APIInteractionResponseChannelMessageWithSource,
|
||||||
APIMessageActionRowComponent,
|
|
||||||
APIModalInteractionResponse,
|
APIModalInteractionResponse,
|
||||||
RESTAPIPollCreate,
|
RESTAPIPollCreate,
|
||||||
RESTPatchAPIChannelMessageJSONBody,
|
RESTPatchAPIChannelMessageJSONBody,
|
||||||
@ -26,7 +16,7 @@ import type { OmitInsert } from './util';
|
|||||||
|
|
||||||
export interface ResolverProps {
|
export interface ResolverProps {
|
||||||
embeds?: Embed[] | APIEmbed[] | undefined;
|
embeds?: Embed[] | APIEmbed[] | undefined;
|
||||||
components?: APIActionRowComponent<APIMessageActionRowComponent>[] | ActionRow<BuilderComponents>[] | undefined;
|
components?: TopLevelBuilders[];
|
||||||
files?: AttachmentBuilder[] | Attachment[] | RawFile[] | undefined;
|
files?: AttachmentBuilder[] | Attachment[] | RawFile[] | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import type { ActionRowMessageComponents } from './index';
|
|||||||
import { componentFactory } from './index';
|
import { componentFactory } from './index';
|
||||||
|
|
||||||
export class MessageActionRowComponent<
|
export class MessageActionRowComponent<
|
||||||
T extends ActionRowMessageComponents,
|
T extends ActionRowMessageComponents = ActionRowMessageComponents,
|
||||||
> extends BaseComponent<ComponentType.ActionRow> {
|
> extends BaseComponent<ComponentType.ActionRow> {
|
||||||
private ComponentsFactory: T[];
|
private ComponentsFactory: T[];
|
||||||
constructor(data: {
|
constructor(data: {
|
||||||
|
@ -1,13 +1,37 @@
|
|||||||
import { fromComponent } from '../builders';
|
import {
|
||||||
|
type ActionRow,
|
||||||
|
type Button,
|
||||||
|
type ChannelSelectMenu,
|
||||||
|
type Container,
|
||||||
|
type File,
|
||||||
|
type MediaGallery,
|
||||||
|
type MentionableSelectMenu,
|
||||||
|
type RoleSelectMenu,
|
||||||
|
type Section,
|
||||||
|
type Separator,
|
||||||
|
type StringSelectMenu,
|
||||||
|
type TextDisplay,
|
||||||
|
type TextInput,
|
||||||
|
type Thumbnail,
|
||||||
|
type UserSelectMenu,
|
||||||
|
fromComponent,
|
||||||
|
} from '../builders';
|
||||||
import {
|
import {
|
||||||
type APIActionRowComponent,
|
type APIActionRowComponent,
|
||||||
type APIActionRowComponentTypes,
|
type APIActionRowComponentTypes,
|
||||||
type APIButtonComponent,
|
type APIButtonComponent,
|
||||||
type APIChannelSelectComponent,
|
type APIChannelSelectComponent,
|
||||||
|
type APIContainerComponent,
|
||||||
|
type APIFileComponent,
|
||||||
|
type APIMediaGalleryComponent,
|
||||||
type APIMentionableSelectComponent,
|
type APIMentionableSelectComponent,
|
||||||
type APIRoleSelectComponent,
|
type APIRoleSelectComponent,
|
||||||
|
type APISectionComponent,
|
||||||
|
type APISeparatorComponent,
|
||||||
type APIStringSelectComponent,
|
type APIStringSelectComponent,
|
||||||
|
type APITextDispalyComponent,
|
||||||
type APITextInputComponent,
|
type APITextInputComponent,
|
||||||
|
type APIThumbnailComponent,
|
||||||
type APIUserSelectComponent,
|
type APIUserSelectComponent,
|
||||||
ComponentType,
|
ComponentType,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
@ -24,7 +48,7 @@ export class BaseComponent<T extends ComponentType> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toBuilder() {
|
toBuilder() {
|
||||||
return fromComponent(this.data);
|
return fromComponent(this.data) as BuilderComponentsMap[T];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export interface APIComponentsMap {
|
export interface APIComponentsMap {
|
||||||
@ -36,4 +60,29 @@ export interface APIComponentsMap {
|
|||||||
[ComponentType.StringSelect]: APIStringSelectComponent;
|
[ComponentType.StringSelect]: APIStringSelectComponent;
|
||||||
[ComponentType.UserSelect]: APIUserSelectComponent;
|
[ComponentType.UserSelect]: APIUserSelectComponent;
|
||||||
[ComponentType.TextInput]: APITextInputComponent;
|
[ComponentType.TextInput]: APITextInputComponent;
|
||||||
|
[ComponentType.File]: APIFileComponent;
|
||||||
|
[ComponentType.Thumbnail]: APIThumbnailComponent;
|
||||||
|
[ComponentType.Section]: APISectionComponent;
|
||||||
|
[ComponentType.Container]: APIContainerComponent;
|
||||||
|
[ComponentType.MediaGallery]: APIMediaGalleryComponent;
|
||||||
|
[ComponentType.Separator]: APISeparatorComponent;
|
||||||
|
[ComponentType.TextDisplay]: APITextDispalyComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BuilderComponentsMap {
|
||||||
|
[ComponentType.ActionRow]: ActionRow;
|
||||||
|
[ComponentType.Button]: Button;
|
||||||
|
[ComponentType.ChannelSelect]: ChannelSelectMenu;
|
||||||
|
[ComponentType.MentionableSelect]: MentionableSelectMenu;
|
||||||
|
[ComponentType.RoleSelect]: RoleSelectMenu;
|
||||||
|
[ComponentType.StringSelect]: StringSelectMenu;
|
||||||
|
[ComponentType.UserSelect]: UserSelectMenu;
|
||||||
|
[ComponentType.TextInput]: TextInput;
|
||||||
|
[ComponentType.File]: File;
|
||||||
|
[ComponentType.Thumbnail]: Thumbnail;
|
||||||
|
[ComponentType.Section]: Section;
|
||||||
|
[ComponentType.Container]: Container;
|
||||||
|
[ComponentType.MediaGallery]: MediaGallery;
|
||||||
|
[ComponentType.Separator]: Separator;
|
||||||
|
[ComponentType.TextDisplay]: TextDisplay;
|
||||||
}
|
}
|
||||||
|
23
src/components/Container.ts
Normal file
23
src/components/Container.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { type ContainerComponents, componentFactory } from '.';
|
||||||
|
import type { APIContainerComponent, ComponentType } from '../types';
|
||||||
|
import { BaseComponent } from './BaseComponent';
|
||||||
|
|
||||||
|
export class ContainerComponent extends BaseComponent<ComponentType.Container> {
|
||||||
|
_components: ContainerComponents[];
|
||||||
|
constructor(data: APIContainerComponent) {
|
||||||
|
super(data);
|
||||||
|
this._components = this.data.components.map(componentFactory) as ContainerComponents[];
|
||||||
|
}
|
||||||
|
|
||||||
|
get components() {
|
||||||
|
return this.data.components;
|
||||||
|
}
|
||||||
|
|
||||||
|
get accentColor() {
|
||||||
|
return this.data.accent_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
get spoiler() {
|
||||||
|
return this.data.spoiler;
|
||||||
|
}
|
||||||
|
}
|
16
src/components/File.ts
Normal file
16
src/components/File.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import type { ComponentType } from '../types';
|
||||||
|
import { BaseComponent } from './BaseComponent';
|
||||||
|
|
||||||
|
export class FileComponent extends BaseComponent<ComponentType.File> {
|
||||||
|
get spoiler() {
|
||||||
|
return this.data.spoiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
get file() {
|
||||||
|
return this.data.file;
|
||||||
|
}
|
||||||
|
|
||||||
|
get id() {
|
||||||
|
return this.data.id;
|
||||||
|
}
|
||||||
|
}
|
12
src/components/MediaGallery.ts
Normal file
12
src/components/MediaGallery.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import type { ComponentType } from '../types';
|
||||||
|
import { BaseComponent } from './BaseComponent';
|
||||||
|
|
||||||
|
export class MediaGalleryComponent extends BaseComponent<ComponentType.MediaGallery> {
|
||||||
|
get items() {
|
||||||
|
return this.data.items;
|
||||||
|
}
|
||||||
|
|
||||||
|
get id() {
|
||||||
|
return this.data.id;
|
||||||
|
}
|
||||||
|
}
|
23
src/components/Section.ts
Normal file
23
src/components/Section.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { componentFactory } from '.';
|
||||||
|
import type { APISectionComponent, ComponentType } from '../types';
|
||||||
|
import { BaseComponent } from './BaseComponent';
|
||||||
|
import type { ButtonComponent } from './ButtonComponent';
|
||||||
|
import type { TextDisplayComponent } from './TextDisplay';
|
||||||
|
import type { ThumbnailComponent } from './Thumbnail';
|
||||||
|
|
||||||
|
export class SectionComponent extends BaseComponent<ComponentType.Section> {
|
||||||
|
protected _components: TextDisplayComponent[];
|
||||||
|
protected _accessory: ThumbnailComponent | ButtonComponent;
|
||||||
|
constructor(data: APISectionComponent) {
|
||||||
|
super(data);
|
||||||
|
this._components = data.components?.map(componentFactory) as TextDisplayComponent[];
|
||||||
|
this._accessory = componentFactory(data.accessory) as ThumbnailComponent | ButtonComponent;
|
||||||
|
}
|
||||||
|
get components() {
|
||||||
|
return this._components;
|
||||||
|
}
|
||||||
|
|
||||||
|
get accessory() {
|
||||||
|
return this._accessory;
|
||||||
|
}
|
||||||
|
}
|
16
src/components/Separator.ts
Normal file
16
src/components/Separator.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import type { ComponentType } from '../types';
|
||||||
|
import { BaseComponent } from './BaseComponent';
|
||||||
|
|
||||||
|
export class SeparatorComponent extends BaseComponent<ComponentType.Separator> {
|
||||||
|
get id() {
|
||||||
|
return this.data.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
get spacing() {
|
||||||
|
return this.data.spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
get divider() {
|
||||||
|
return this.data.divider;
|
||||||
|
}
|
||||||
|
}
|
8
src/components/TextDisplay.ts
Normal file
8
src/components/TextDisplay.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import type { ComponentType } from '../types';
|
||||||
|
import { BaseComponent } from './BaseComponent';
|
||||||
|
|
||||||
|
export class TextDisplayComponent extends BaseComponent<ComponentType.TextDisplay> {
|
||||||
|
get content() {
|
||||||
|
return this.data.content;
|
||||||
|
}
|
||||||
|
}
|
20
src/components/Thumbnail.ts
Normal file
20
src/components/Thumbnail.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import type { ComponentType } from '../types';
|
||||||
|
import { BaseComponent } from './BaseComponent';
|
||||||
|
|
||||||
|
export class ThumbnailComponent extends BaseComponent<ComponentType.Thumbnail> {
|
||||||
|
get id() {
|
||||||
|
return this.data.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
get media() {
|
||||||
|
return this.data.media;
|
||||||
|
}
|
||||||
|
|
||||||
|
get description() {
|
||||||
|
return this.data.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
get spoiler() {
|
||||||
|
return this.data.spoiler;
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,19 @@
|
|||||||
import { type APIMessageActionRowComponent, ButtonStyle, ComponentType } from '../types';
|
import { type APIComponents, type APITopLevelComponent, ButtonStyle, ComponentType } from '../types';
|
||||||
|
import { MessageActionRowComponent } from './ActionRow';
|
||||||
import { BaseComponent } from './BaseComponent';
|
import { BaseComponent } from './BaseComponent';
|
||||||
import { ButtonComponent, LinkButtonComponent, SKUButtonComponent } from './ButtonComponent';
|
import { ButtonComponent, LinkButtonComponent, SKUButtonComponent } from './ButtonComponent';
|
||||||
import { ChannelSelectMenuComponent } from './ChannelSelectMenuComponent';
|
import { ChannelSelectMenuComponent } from './ChannelSelectMenuComponent';
|
||||||
|
import { ContainerComponent } from './Container';
|
||||||
|
import { FileComponent } from './File';
|
||||||
|
import { MediaGalleryComponent } from './MediaGallery';
|
||||||
import { MentionableSelectMenuComponent } from './MentionableSelectMenuComponent';
|
import { MentionableSelectMenuComponent } from './MentionableSelectMenuComponent';
|
||||||
import { RoleSelectMenuComponent } from './RoleSelectMenuComponent';
|
import { RoleSelectMenuComponent } from './RoleSelectMenuComponent';
|
||||||
|
import { SectionComponent } from './Section';
|
||||||
|
import { SeparatorComponent } from './Separator';
|
||||||
import { StringSelectMenuComponent } from './StringSelectMenuComponent';
|
import { StringSelectMenuComponent } from './StringSelectMenuComponent';
|
||||||
import type { TextInputComponent } from './TextInputComponent';
|
import { TextDisplayComponent } from './TextDisplay';
|
||||||
|
import { TextInputComponent } from './TextInputComponent';
|
||||||
|
import { ThumbnailComponent } from './Thumbnail';
|
||||||
import { UserSelectMenuComponent } from './UserSelectMenuComponent';
|
import { UserSelectMenuComponent } from './UserSelectMenuComponent';
|
||||||
|
|
||||||
export type MessageComponents =
|
export type MessageComponents =
|
||||||
@ -21,20 +29,37 @@ export type MessageComponents =
|
|||||||
|
|
||||||
export type ActionRowMessageComponents = Exclude<MessageComponents, TextInputComponent>;
|
export type ActionRowMessageComponents = Exclude<MessageComponents, TextInputComponent>;
|
||||||
|
|
||||||
|
export type AllComponents = MessageComponents | TopLevelComponents | ContainerComponents | BaseComponent<ComponentType>;
|
||||||
|
|
||||||
export * from './componentcommand';
|
export * from './componentcommand';
|
||||||
export * from './componentcontext';
|
export * from './componentcontext';
|
||||||
export * from './modalcommand';
|
export * from './modalcommand';
|
||||||
export * from './modalcontext';
|
export * from './modalcontext';
|
||||||
|
|
||||||
|
export type TopLevelComponents =
|
||||||
|
| SectionComponent
|
||||||
|
| ActionRowMessageComponents
|
||||||
|
| TextDisplayComponent
|
||||||
|
| ContainerComponent
|
||||||
|
| FileComponent
|
||||||
|
| MediaGalleryComponent
|
||||||
|
| BaseComponent<APITopLevelComponent['type']>;
|
||||||
|
|
||||||
|
export type ContainerComponents =
|
||||||
|
| MessageActionRowComponent
|
||||||
|
| TextDisplayComponent
|
||||||
|
| MediaGalleryComponent
|
||||||
|
| SectionComponent
|
||||||
|
| SeparatorComponent
|
||||||
|
| FileComponent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a new component instance based on the component type.
|
* Return a new component instance based on the component type.
|
||||||
*
|
*
|
||||||
* @param component The component to create.
|
* @param component The component to create.
|
||||||
* @returns The component instance.
|
* @returns The component instance.
|
||||||
*/
|
*/
|
||||||
export function componentFactory(
|
export function componentFactory(component: APIComponents): AllComponents {
|
||||||
component: APIMessageActionRowComponent,
|
|
||||||
): ActionRowMessageComponents | BaseComponent<ActionRowMessageComponents['type']> {
|
|
||||||
switch (component.type) {
|
switch (component.type) {
|
||||||
case ComponentType.Button: {
|
case ComponentType.Button: {
|
||||||
if (component.style === ButtonStyle.Link) {
|
if (component.style === ButtonStyle.Link) {
|
||||||
@ -55,7 +80,25 @@ export function componentFactory(
|
|||||||
return new UserSelectMenuComponent(component);
|
return new UserSelectMenuComponent(component);
|
||||||
case ComponentType.MentionableSelect:
|
case ComponentType.MentionableSelect:
|
||||||
return new MentionableSelectMenuComponent(component);
|
return new MentionableSelectMenuComponent(component);
|
||||||
|
case ComponentType.ActionRow:
|
||||||
|
return new MessageActionRowComponent(component as any);
|
||||||
|
case ComponentType.Container:
|
||||||
|
return new ContainerComponent(component);
|
||||||
|
case ComponentType.File:
|
||||||
|
return new FileComponent(component);
|
||||||
|
case ComponentType.MediaGallery:
|
||||||
|
return new MediaGalleryComponent(component);
|
||||||
|
case ComponentType.Section:
|
||||||
|
return new SectionComponent(component);
|
||||||
|
case ComponentType.TextDisplay:
|
||||||
|
return new TextDisplayComponent(component);
|
||||||
|
case ComponentType.Separator:
|
||||||
|
return new SeparatorComponent(component);
|
||||||
|
case ComponentType.Thumbnail:
|
||||||
|
return new ThumbnailComponent(component);
|
||||||
|
case ComponentType.TextInput:
|
||||||
|
return new TextInputComponent(component);
|
||||||
default:
|
default:
|
||||||
return new BaseComponent<ActionRowMessageComponents['type']>(component);
|
return new BaseComponent<ComponentType>(component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,6 +148,7 @@ export class BaseInteraction<
|
|||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
return {
|
return {
|
||||||
type: body.type,
|
type: body.type,
|
||||||
|
// @ts-expect-error
|
||||||
data: BaseInteraction.transformBody(body.data ?? {}, files, self),
|
data: BaseInteraction.transformBody(body.data ?? {}, files, self),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -330,7 +331,6 @@ export class BaseInteraction<
|
|||||||
case ApplicationCommandType.PrimaryEntryPoint:
|
case ApplicationCommandType.PrimaryEntryPoint:
|
||||||
return new EntryPointInteraction(client, gateway as APIEntryPointCommandInteraction, __reply);
|
return new EntryPointInteraction(client, gateway as APIEntryPointCommandInteraction, __reply);
|
||||||
}
|
}
|
||||||
// biome-ignore lint/suspicious/noFallthroughSwitchClause: bad interaction between biome and ts-server
|
|
||||||
case InteractionType.MessageComponent:
|
case InteractionType.MessageComponent:
|
||||||
switch (gateway.data.component_type) {
|
switch (gateway.data.component_type) {
|
||||||
case ComponentType.Button:
|
case ComponentType.Button:
|
||||||
@ -357,6 +357,8 @@ export class BaseInteraction<
|
|||||||
gateway as APIMessageComponentSelectMenuInteraction,
|
gateway as APIMessageComponentSelectMenuInteraction,
|
||||||
__reply,
|
__reply,
|
||||||
);
|
);
|
||||||
|
default:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
case InteractionType.ModalSubmit:
|
case InteractionType.ModalSubmit:
|
||||||
return new ModalSubmitInteraction(client, gateway);
|
return new ModalSubmitInteraction(client, gateway);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { type AllChannels, Embed, type ReturnCache } from '..';
|
import { type AllChannels, Embed, type ReturnCache, componentFactory } from '..';
|
||||||
import type { ListenerOptions } from '../builders';
|
import type { ListenerOptions } from '../builders';
|
||||||
import {
|
import {
|
||||||
type GuildMemberStructure,
|
type GuildMemberStructure,
|
||||||
@ -15,8 +15,7 @@ import { type ObjectToLower, toCamelCase } from '../common';
|
|||||||
import { Formatter } from '../common';
|
import { Formatter } from '../common';
|
||||||
import type { EmojiResolvable } from '../common/types/resolvables';
|
import type { EmojiResolvable } from '../common/types/resolvables';
|
||||||
import type { MessageCreateBodyRequest, MessageUpdateBodyRequest } from '../common/types/write';
|
import type { MessageCreateBodyRequest, MessageUpdateBodyRequest } from '../common/types/write';
|
||||||
import type { ActionRowMessageComponents } from '../components';
|
import type { TopLevelComponents } from '../components';
|
||||||
import { MessageActionRowComponent } from '../components/ActionRow';
|
|
||||||
import type {
|
import type {
|
||||||
APIChannelMention,
|
APIChannelMention,
|
||||||
APIEmbed,
|
APIEmbed,
|
||||||
@ -37,7 +36,7 @@ export interface BaseMessage
|
|||||||
guildId?: string;
|
guildId?: string;
|
||||||
author: UserStructure;
|
author: UserStructure;
|
||||||
member?: GuildMemberStructure;
|
member?: GuildMemberStructure;
|
||||||
components: MessageActionRowComponent<ActionRowMessageComponents>[];
|
components: TopLevelComponents[];
|
||||||
poll?: PollStructure;
|
poll?: PollStructure;
|
||||||
mentions: {
|
mentions: {
|
||||||
roles: string[];
|
roles: string[];
|
||||||
@ -55,7 +54,7 @@ export class BaseMessage extends DiscordBase {
|
|||||||
channels: data.mention_channels ?? [],
|
channels: data.mention_channels ?? [],
|
||||||
users: [],
|
users: [],
|
||||||
};
|
};
|
||||||
this.components = data.components?.map(x => new MessageActionRowComponent(x)) ?? [];
|
this.components = (data.components?.map(componentFactory) as TopLevelComponents[]) ?? [];
|
||||||
this.embeds = data.embeds.map(embed => new InMessageEmbed(embed));
|
this.embeds = data.embeds.map(embed => new InMessageEmbed(embed));
|
||||||
this.patch(data);
|
this.patch(data);
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,9 @@ import type {
|
|||||||
*/
|
*/
|
||||||
import type {
|
import type {
|
||||||
APIWebhook,
|
APIWebhook,
|
||||||
RESTGetAPIWebhookWithTokenMessageQuery,
|
|
||||||
RESTPatchAPIWebhookJSONBody,
|
RESTPatchAPIWebhookJSONBody,
|
||||||
RESTPatchAPIWebhookWithTokenJSONBody,
|
RESTPatchAPIWebhookWithTokenJSONBody,
|
||||||
|
RESTPatchAPIWebhookWithTokenMessageQuery,
|
||||||
RESTPostAPIWebhookWithTokenQuery,
|
RESTPostAPIWebhookWithTokenQuery,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import type { AllChannels } from './channels';
|
import type { AllChannels } from './channels';
|
||||||
@ -181,7 +181,7 @@ export class Webhook extends DiscordBase {
|
|||||||
/** Type definition for parameters of editing a message through a webhook. */
|
/** Type definition for parameters of editing a message through a webhook. */
|
||||||
export type MessageWebhookMethodEditParams = MessageWebhookPayload<
|
export type MessageWebhookMethodEditParams = MessageWebhookPayload<
|
||||||
MessageWebhookUpdateBodyRequest,
|
MessageWebhookUpdateBodyRequest,
|
||||||
{ messageId: string; query?: RESTGetAPIWebhookWithTokenMessageQuery }
|
{ messageId: string; query?: RESTPatchAPIWebhookWithTokenMessageQuery }
|
||||||
>;
|
>;
|
||||||
/** Type definition for parameters of writing a message through a webhook. */
|
/** Type definition for parameters of writing a message through a webhook. */
|
||||||
export type MessageWebhookMethodWriteParams = MessageWebhookPayload<
|
export type MessageWebhookMethodWriteParams = MessageWebhookPayload<
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Collection, Formatter, type RawFile, type ReturnCache } from '..';
|
import { Collection, Formatter, type RawFile, type ReturnCache } from '..';
|
||||||
import { ActionRow, Embed, PollBuilder, resolveAttachment } from '../builders';
|
import { Embed, PollBuilder, resolveAttachment } from '../builders';
|
||||||
import type { Overwrites } from '../cache/resources/overwrites';
|
import type { Overwrites } from '../cache/resources/overwrites';
|
||||||
import {
|
import {
|
||||||
type BaseChannelStructure,
|
type BaseChannelStructure,
|
||||||
@ -353,8 +353,8 @@ export class MessagesMethods extends DiscordBase {
|
|||||||
const payload = {
|
const payload = {
|
||||||
allowed_mentions: self.options?.allowedMentions,
|
allowed_mentions: self.options?.allowedMentions,
|
||||||
...body,
|
...body,
|
||||||
components: body.components?.map(x => (x instanceof ActionRow ? x.toJSON() : x)) ?? undefined,
|
embeds: body.embeds?.map(x => (x instanceof Embed ? x.toJSON() : x)),
|
||||||
embeds: body.embeds?.map(x => (x instanceof Embed ? x.toJSON() : x)) ?? undefined,
|
components: body.components?.map(x => ('toJSON' in x ? x.toJSON() : x)) ?? undefined,
|
||||||
poll: poll ? (poll instanceof PollBuilder ? poll.toJSON() : poll) : undefined,
|
poll: poll ? (poll instanceof PollBuilder ? poll.toJSON() : poll) : undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { Snowflake } from '../../index';
|
import type { ComponentType, Snowflake } from '../../index';
|
||||||
import type { ComponentType } from '../channel';
|
|
||||||
import type { APIBaseInteraction, InteractionType } from '../interactions';
|
import type { APIBaseInteraction, InteractionType } from '../interactions';
|
||||||
import type {
|
import type {
|
||||||
APIDMInteractionWrapper,
|
APIDMInteractionWrapper,
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import type { APIActionRowComponent, APIModalActionRowComponent } from '../channel';
|
|
||||||
import type {
|
import type {
|
||||||
|
APIActionRowComponent,
|
||||||
APIBaseInteraction,
|
APIBaseInteraction,
|
||||||
APIDMInteractionWrapper,
|
APIDMInteractionWrapper,
|
||||||
APIGuildInteractionWrapper,
|
APIGuildInteractionWrapper,
|
||||||
|
APIModalActionRowComponent,
|
||||||
ComponentType,
|
ComponentType,
|
||||||
InteractionType,
|
InteractionType,
|
||||||
} from '../index';
|
} from '../index';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import type { MakeRequired } from '../../../common';
|
import type { MakeRequired } from '../../../common';
|
||||||
import type { RESTPostAPIWebhookWithTokenJSONBody } from '../../index';
|
import type { RESTPostAPIWebhookWithTokenJSONBody } from '../../index';
|
||||||
import type { APIActionRowComponent, APIModalActionRowComponent } from '../channel';
|
|
||||||
import type { MessageFlags } from '../index';
|
import type { APIActionRowComponent, APIModalActionRowComponent, MessageFlags } from '../index';
|
||||||
import type { APIApplicationCommandOptionChoice } from './applicationCommands';
|
import type { APIApplicationCommandOptionChoice } from './applicationCommands';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,7 +3,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { PickRequired } from '../../common';
|
import type { PickRequired } from '../../common';
|
||||||
import type { ChannelType, OverwriteType, Permissions, Snowflake, VideoQualityMode } from '../index';
|
import type {
|
||||||
|
APITopLevelComponent,
|
||||||
|
ChannelFlags,
|
||||||
|
ChannelType,
|
||||||
|
OverwriteType,
|
||||||
|
Permissions,
|
||||||
|
Snowflake,
|
||||||
|
VideoQualityMode,
|
||||||
|
} from '../index';
|
||||||
import type { APIApplication } from './application';
|
import type { APIApplication } from './application';
|
||||||
import type { APIPartialEmoji } from './emoji';
|
import type { APIPartialEmoji } from './emoji';
|
||||||
import type { APIGuildMember } from './guild';
|
import type { APIGuildMember } from './guild';
|
||||||
@ -579,7 +587,7 @@ export interface APIMessage {
|
|||||||
*
|
*
|
||||||
* See https://support-dev.discord.com/hc/articles/4404772028055
|
* See https://support-dev.discord.com/hc/articles/4404772028055
|
||||||
*/
|
*/
|
||||||
components?: APIActionRowComponent<APIMessageActionRowComponent>[];
|
components?: APITopLevelComponent[];
|
||||||
/**
|
/**
|
||||||
* Sent if the message contains stickers
|
* Sent if the message contains stickers
|
||||||
*
|
*
|
||||||
@ -813,6 +821,14 @@ export enum MessageFlags {
|
|||||||
* This message is a voice message
|
* This message is a voice message
|
||||||
*/
|
*/
|
||||||
IsVoiceMessage = 1 << 13,
|
IsVoiceMessage = 1 << 13,
|
||||||
|
/**
|
||||||
|
* This message has a snapshot (via Message Forwarding)
|
||||||
|
*/
|
||||||
|
HasSnapshot = 1 << 14,
|
||||||
|
/**
|
||||||
|
* This message allows you to create fully component driven messages
|
||||||
|
*/
|
||||||
|
IsComponentsV2 = 1 << 15,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1498,403 +1514,3 @@ export interface APIAllowedMentions {
|
|||||||
*/
|
*/
|
||||||
replied_user?: boolean;
|
replied_user?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#component-object
|
|
||||||
*/
|
|
||||||
export interface APIBaseComponent<T extends ComponentType> {
|
|
||||||
/**
|
|
||||||
* The type of the component
|
|
||||||
*/
|
|
||||||
type: T;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#component-object-component-types
|
|
||||||
*/
|
|
||||||
export enum ComponentType {
|
|
||||||
/**
|
|
||||||
* Action Row component
|
|
||||||
*/
|
|
||||||
ActionRow = 1,
|
|
||||||
/**
|
|
||||||
* Button component
|
|
||||||
*/
|
|
||||||
Button,
|
|
||||||
/**
|
|
||||||
* Select menu for picking from defined text options
|
|
||||||
*/
|
|
||||||
StringSelect,
|
|
||||||
/**
|
|
||||||
* Text Input component
|
|
||||||
*/
|
|
||||||
TextInput,
|
|
||||||
/**
|
|
||||||
* Select menu for users
|
|
||||||
*/
|
|
||||||
UserSelect,
|
|
||||||
/**
|
|
||||||
* Select menu for roles
|
|
||||||
*/
|
|
||||||
RoleSelect,
|
|
||||||
/**
|
|
||||||
* Select menu for users and roles
|
|
||||||
*/
|
|
||||||
MentionableSelect,
|
|
||||||
/**
|
|
||||||
* Select menu for channels
|
|
||||||
*/
|
|
||||||
ChannelSelect,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#action-rows
|
|
||||||
*/
|
|
||||||
export interface APIActionRowComponent<T extends APIActionRowComponentTypes>
|
|
||||||
extends APIBaseComponent<ComponentType.ActionRow> {
|
|
||||||
/**
|
|
||||||
* The components in the ActionRow
|
|
||||||
*/
|
|
||||||
components: T[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#buttons
|
|
||||||
*/
|
|
||||||
export interface APIButtonComponentBase<Style extends ButtonStyle> extends APIBaseComponent<ComponentType.Button> {
|
|
||||||
/**
|
|
||||||
* The label to be displayed on the button
|
|
||||||
*/
|
|
||||||
label?: string;
|
|
||||||
/**
|
|
||||||
* The style of the button
|
|
||||||
*/
|
|
||||||
style: Style;
|
|
||||||
/**
|
|
||||||
* The emoji to display to the left of the text
|
|
||||||
*/
|
|
||||||
emoji?: APIMessageComponentEmoji;
|
|
||||||
/**
|
|
||||||
* The status of the button
|
|
||||||
*/
|
|
||||||
disabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface APIMessageComponentEmoji {
|
|
||||||
/**
|
|
||||||
* Emoji id
|
|
||||||
*/
|
|
||||||
id?: Snowflake;
|
|
||||||
/**
|
|
||||||
* Emoji name
|
|
||||||
*/
|
|
||||||
name?: string;
|
|
||||||
/**
|
|
||||||
* Whether this emoji is animated
|
|
||||||
*/
|
|
||||||
animated?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface APIButtonComponentWithCustomId
|
|
||||||
extends APIButtonComponentBase<
|
|
||||||
ButtonStyle.Danger | ButtonStyle.Primary | ButtonStyle.Secondary | ButtonStyle.Success
|
|
||||||
> {
|
|
||||||
/**
|
|
||||||
* The custom_id to be sent in the interaction when clicked
|
|
||||||
*/
|
|
||||||
custom_id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface APIButtonComponentWithURL extends APIButtonComponentBase<ButtonStyle.Link> {
|
|
||||||
/**
|
|
||||||
* The URL to direct users to when clicked for Link buttons
|
|
||||||
*/
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface APIButtonComponentWithSKUId
|
|
||||||
extends Omit<APIButtonComponentBase<ButtonStyle.Premium>, 'custom_id' | 'emoji' | 'label'> {
|
|
||||||
/**
|
|
||||||
* The id for a purchasable SKU
|
|
||||||
*/
|
|
||||||
sku_id: Snowflake;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type APIButtonComponent =
|
|
||||||
| APIButtonComponentWithCustomId
|
|
||||||
| APIButtonComponentWithSKUId
|
|
||||||
| APIButtonComponentWithURL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#button-object-button-styles
|
|
||||||
*/
|
|
||||||
export enum ButtonStyle {
|
|
||||||
Primary = 1,
|
|
||||||
Secondary,
|
|
||||||
Success,
|
|
||||||
Danger,
|
|
||||||
Link,
|
|
||||||
Premium,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#text-inputs-text-input-styles
|
|
||||||
*/
|
|
||||||
export enum TextInputStyle {
|
|
||||||
Short = 1,
|
|
||||||
Paragraph,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
|
||||||
*/
|
|
||||||
export interface APIBaseSelectMenuComponent<
|
|
||||||
T extends
|
|
||||||
| ComponentType.ChannelSelect
|
|
||||||
| ComponentType.MentionableSelect
|
|
||||||
| ComponentType.RoleSelect
|
|
||||||
| ComponentType.StringSelect
|
|
||||||
| ComponentType.UserSelect,
|
|
||||||
> extends APIBaseComponent<T> {
|
|
||||||
/**
|
|
||||||
* A developer-defined identifier for the select menu, max 100 characters
|
|
||||||
*/
|
|
||||||
custom_id: string;
|
|
||||||
/**
|
|
||||||
* Custom placeholder text if nothing is selected, max 150 characters
|
|
||||||
*/
|
|
||||||
placeholder?: string;
|
|
||||||
/**
|
|
||||||
* The minimum number of items that must be chosen; min 0, max 25
|
|
||||||
*
|
|
||||||
* @default 1
|
|
||||||
*/
|
|
||||||
min_values?: number;
|
|
||||||
/**
|
|
||||||
* The maximum number of items that can be chosen; max 25
|
|
||||||
*
|
|
||||||
* @default 1
|
|
||||||
*/
|
|
||||||
max_values?: number;
|
|
||||||
/**
|
|
||||||
* Disable the select
|
|
||||||
*
|
|
||||||
* @default false
|
|
||||||
*/
|
|
||||||
disabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface APIBaseAutoPopulatedSelectMenuComponent<
|
|
||||||
T extends
|
|
||||||
| ComponentType.ChannelSelect
|
|
||||||
| ComponentType.MentionableSelect
|
|
||||||
| ComponentType.RoleSelect
|
|
||||||
| ComponentType.UserSelect,
|
|
||||||
D extends SelectMenuDefaultValueType,
|
|
||||||
> extends APIBaseSelectMenuComponent<T> {
|
|
||||||
/**
|
|
||||||
* List of default values for auto-populated select menu components
|
|
||||||
*/
|
|
||||||
default_values?: APISelectMenuDefaultValue<D>[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
|
||||||
*/
|
|
||||||
export interface APIStringSelectComponent extends APIBaseSelectMenuComponent<ComponentType.StringSelect> {
|
|
||||||
/**
|
|
||||||
* Specified choices in a select menu; max 25
|
|
||||||
*/
|
|
||||||
options: APISelectMenuOption[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
|
||||||
*/
|
|
||||||
export type APIUserSelectComponent = APIBaseAutoPopulatedSelectMenuComponent<
|
|
||||||
ComponentType.UserSelect,
|
|
||||||
SelectMenuDefaultValueType.User
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
|
||||||
*/
|
|
||||||
export type APIRoleSelectComponent = APIBaseAutoPopulatedSelectMenuComponent<
|
|
||||||
ComponentType.RoleSelect,
|
|
||||||
SelectMenuDefaultValueType.Role
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
|
||||||
*/
|
|
||||||
export type APIMentionableSelectComponent = APIBaseAutoPopulatedSelectMenuComponent<
|
|
||||||
ComponentType.MentionableSelect,
|
|
||||||
SelectMenuDefaultValueType.Role | SelectMenuDefaultValueType.User
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
|
||||||
*/
|
|
||||||
export interface APIChannelSelectComponent
|
|
||||||
extends APIBaseAutoPopulatedSelectMenuComponent<ComponentType.ChannelSelect, SelectMenuDefaultValueType.Channel> {
|
|
||||||
/**
|
|
||||||
* List of channel types to include in the ChannelSelect component
|
|
||||||
*/
|
|
||||||
channel_types?: ChannelType[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-default-value-structure
|
|
||||||
*/
|
|
||||||
export enum SelectMenuDefaultValueType {
|
|
||||||
Channel = 'channel',
|
|
||||||
Role = 'role',
|
|
||||||
User = 'user',
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-default-value-structure
|
|
||||||
*/
|
|
||||||
export interface APISelectMenuDefaultValue<T extends SelectMenuDefaultValueType> {
|
|
||||||
type: T;
|
|
||||||
id: Snowflake;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type APIAutoPopulatedSelectMenuComponent =
|
|
||||||
| APIChannelSelectComponent
|
|
||||||
| APIMentionableSelectComponent
|
|
||||||
| APIRoleSelectComponent
|
|
||||||
| APIUserSelectComponent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
|
||||||
*/
|
|
||||||
export type APISelectMenuComponent =
|
|
||||||
| APIChannelSelectComponent
|
|
||||||
| APIMentionableSelectComponent
|
|
||||||
| APIRoleSelectComponent
|
|
||||||
| APIStringSelectComponent
|
|
||||||
| APIUserSelectComponent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-option-structure
|
|
||||||
*/
|
|
||||||
export interface APISelectMenuOption {
|
|
||||||
/**
|
|
||||||
* The user-facing name of the option (max 100 chars)
|
|
||||||
*/
|
|
||||||
label: string;
|
|
||||||
/**
|
|
||||||
* The dev-defined value of the option (max 100 chars)
|
|
||||||
*/
|
|
||||||
value: string;
|
|
||||||
/**
|
|
||||||
* An additional description of the option (max 100 chars)
|
|
||||||
*/
|
|
||||||
description?: string;
|
|
||||||
/**
|
|
||||||
* The emoji to display to the left of the option
|
|
||||||
*/
|
|
||||||
emoji?: APIMessageComponentEmoji;
|
|
||||||
/**
|
|
||||||
* Whether this option should be already-selected by default
|
|
||||||
*/
|
|
||||||
default?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#text-inputs-text-input-structure
|
|
||||||
*/
|
|
||||||
export interface APITextInputComponent extends APIBaseComponent<ComponentType.TextInput> {
|
|
||||||
/**
|
|
||||||
* One of text input styles
|
|
||||||
*/
|
|
||||||
style: TextInputStyle;
|
|
||||||
/**
|
|
||||||
* The custom id for the text input
|
|
||||||
*/
|
|
||||||
custom_id: string;
|
|
||||||
/**
|
|
||||||
* Text that appears on top of the text input field, max 45 characters
|
|
||||||
*/
|
|
||||||
label: string;
|
|
||||||
/**
|
|
||||||
* Placeholder for the text input
|
|
||||||
*/
|
|
||||||
placeholder?: string;
|
|
||||||
/**
|
|
||||||
* The pre-filled text in the text input
|
|
||||||
*/
|
|
||||||
value?: string;
|
|
||||||
/**
|
|
||||||
* Minimal length of text input
|
|
||||||
*/
|
|
||||||
min_length?: number;
|
|
||||||
/**
|
|
||||||
* Maximal length of text input
|
|
||||||
*/
|
|
||||||
max_length?: number;
|
|
||||||
/**
|
|
||||||
* Whether or not this text input is required or not
|
|
||||||
*/
|
|
||||||
required?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/resources/channel#channel-object-channel-flags
|
|
||||||
*/
|
|
||||||
export enum ChannelFlags {
|
|
||||||
/**
|
|
||||||
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
|
||||||
*/
|
|
||||||
GuildFeedRemoved = 1 << 0,
|
|
||||||
/**
|
|
||||||
* This thread is pinned to the top of its parent forum channel
|
|
||||||
*/
|
|
||||||
Pinned = 1 << 1,
|
|
||||||
/**
|
|
||||||
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
|
||||||
*/
|
|
||||||
ActiveChannelsRemoved = 1 << 2,
|
|
||||||
/**
|
|
||||||
* Whether a tag is required to be specified when creating a thread in a forum channel.
|
|
||||||
* Tags are specified in the `applied_tags` field
|
|
||||||
*/
|
|
||||||
RequireTag = 1 << 4,
|
|
||||||
/**
|
|
||||||
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
|
||||||
*/
|
|
||||||
IsSpam = 1 << 5,
|
|
||||||
/**
|
|
||||||
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
|
||||||
*/
|
|
||||||
IsGuildResourceChannel = 1 << 7,
|
|
||||||
/**
|
|
||||||
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
|
||||||
*/
|
|
||||||
ClydeAI = 1 << 8,
|
|
||||||
/**
|
|
||||||
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
|
||||||
*/
|
|
||||||
IsScheduledForDeletion = 1 << 9,
|
|
||||||
/**
|
|
||||||
* Whether media download options are hidden.
|
|
||||||
*/
|
|
||||||
HideMediaDownloadOptions = 1 << 15,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#message-components
|
|
||||||
*/
|
|
||||||
export type APIMessageComponent = APIActionRowComponent<APIMessageActionRowComponent> | APIMessageActionRowComponent;
|
|
||||||
export type APIModalComponent = APIActionRowComponent<APIModalActionRowComponent> | APIModalActionRowComponent;
|
|
||||||
|
|
||||||
export type APIActionRowComponentTypes = APIMessageActionRowComponent | APIModalActionRowComponent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://discord.com/developers/docs/interactions/message-components#message-components
|
|
||||||
*/
|
|
||||||
export type APIMessageActionRowComponent = APIButtonComponent | APISelectMenuComponent;
|
|
||||||
|
|
||||||
// Modal components
|
|
||||||
export type APIModalActionRowComponent = APITextInputComponent;
|
|
||||||
|
594
src/types/payloads/components.ts
Normal file
594
src/types/payloads/components.ts
Normal file
@ -0,0 +1,594 @@
|
|||||||
|
import type { APIAttachment, Snowflake } from '..';
|
||||||
|
import type { Identify, MakeRequired } from '../../common';
|
||||||
|
import type { ChannelType } from '../utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#component-object
|
||||||
|
*/
|
||||||
|
export interface APIBaseComponent<T extends ComponentType> {
|
||||||
|
/**
|
||||||
|
* The type of the component
|
||||||
|
*/
|
||||||
|
type: T;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#component-object-component-types
|
||||||
|
*/
|
||||||
|
export enum ComponentType {
|
||||||
|
/**
|
||||||
|
* Action Row component
|
||||||
|
*/
|
||||||
|
ActionRow = 1,
|
||||||
|
/**
|
||||||
|
* Button component
|
||||||
|
*/
|
||||||
|
Button,
|
||||||
|
/**
|
||||||
|
* Select menu for picking from defined text options
|
||||||
|
*/
|
||||||
|
StringSelect,
|
||||||
|
/**
|
||||||
|
* Text Input component
|
||||||
|
*/
|
||||||
|
TextInput,
|
||||||
|
/**
|
||||||
|
* Select menu for users
|
||||||
|
*/
|
||||||
|
UserSelect,
|
||||||
|
/**
|
||||||
|
* Select menu for roles
|
||||||
|
*/
|
||||||
|
RoleSelect,
|
||||||
|
/**
|
||||||
|
* Select menu for users and roles
|
||||||
|
*/
|
||||||
|
MentionableSelect,
|
||||||
|
/**
|
||||||
|
* Select menu for channels
|
||||||
|
*/
|
||||||
|
ChannelSelect,
|
||||||
|
/**
|
||||||
|
* Section for accessory
|
||||||
|
*/
|
||||||
|
Section,
|
||||||
|
/**
|
||||||
|
* Text display component
|
||||||
|
*/
|
||||||
|
TextDisplay,
|
||||||
|
/**
|
||||||
|
* Thumbnail component
|
||||||
|
*/
|
||||||
|
Thumbnail,
|
||||||
|
/**
|
||||||
|
* Media Gallery component
|
||||||
|
*/
|
||||||
|
MediaGallery,
|
||||||
|
/**
|
||||||
|
* File component
|
||||||
|
*/
|
||||||
|
File,
|
||||||
|
/**
|
||||||
|
* Separator component
|
||||||
|
*/
|
||||||
|
Separator,
|
||||||
|
/**
|
||||||
|
* Container component
|
||||||
|
*/
|
||||||
|
Container = 17,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#action-rows
|
||||||
|
*/
|
||||||
|
export interface APIActionRowComponent<T extends APIActionRowComponentTypes>
|
||||||
|
extends APIBaseComponent<ComponentType.ActionRow> {
|
||||||
|
/**
|
||||||
|
* The components in the ActionRow
|
||||||
|
*/
|
||||||
|
components: T[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#buttons
|
||||||
|
*/
|
||||||
|
export interface APIButtonComponentBase<Style extends ButtonStyle> extends APIBaseComponent<ComponentType.Button> {
|
||||||
|
/**
|
||||||
|
* The label to be displayed on the button
|
||||||
|
*/
|
||||||
|
label?: string;
|
||||||
|
/**
|
||||||
|
* The style of the button
|
||||||
|
*/
|
||||||
|
style: Style;
|
||||||
|
/**
|
||||||
|
* The emoji to display to the left of the text
|
||||||
|
*/
|
||||||
|
emoji?: APIMessageComponentEmoji;
|
||||||
|
/**
|
||||||
|
* The status of the button
|
||||||
|
*/
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface APIMessageComponentEmoji {
|
||||||
|
/**
|
||||||
|
* Emoji id
|
||||||
|
*/
|
||||||
|
id?: Snowflake;
|
||||||
|
/**
|
||||||
|
* Emoji name
|
||||||
|
*/
|
||||||
|
name?: string;
|
||||||
|
/**
|
||||||
|
* Whether this emoji is animated
|
||||||
|
*/
|
||||||
|
animated?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface APIButtonComponentWithCustomId
|
||||||
|
extends APIButtonComponentBase<
|
||||||
|
ButtonStyle.Danger | ButtonStyle.Primary | ButtonStyle.Secondary | ButtonStyle.Success
|
||||||
|
> {
|
||||||
|
/**
|
||||||
|
* The custom_id to be sent in the interaction when clicked
|
||||||
|
*/
|
||||||
|
custom_id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface APIButtonComponentWithURL extends APIButtonComponentBase<ButtonStyle.Link> {
|
||||||
|
/**
|
||||||
|
* The URL to direct users to when clicked for Link buttons
|
||||||
|
*/
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface APIButtonComponentWithSKUId
|
||||||
|
extends Omit<APIButtonComponentBase<ButtonStyle.Premium>, 'custom_id' | 'emoji' | 'label'> {
|
||||||
|
/**
|
||||||
|
* The id for a purchasable SKU
|
||||||
|
*/
|
||||||
|
sku_id: Snowflake;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type APIButtonComponent =
|
||||||
|
| APIButtonComponentWithCustomId
|
||||||
|
| APIButtonComponentWithSKUId
|
||||||
|
| APIButtonComponentWithURL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#button-object-button-styles
|
||||||
|
*/
|
||||||
|
export enum ButtonStyle {
|
||||||
|
Primary = 1,
|
||||||
|
Secondary,
|
||||||
|
Success,
|
||||||
|
Danger,
|
||||||
|
Link,
|
||||||
|
Premium,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#text-inputs-text-input-styles
|
||||||
|
*/
|
||||||
|
export enum TextInputStyle {
|
||||||
|
Short = 1,
|
||||||
|
Paragraph,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||||
|
*/
|
||||||
|
export interface APIBaseSelectMenuComponent<
|
||||||
|
T extends
|
||||||
|
| ComponentType.ChannelSelect
|
||||||
|
| ComponentType.MentionableSelect
|
||||||
|
| ComponentType.RoleSelect
|
||||||
|
| ComponentType.StringSelect
|
||||||
|
| ComponentType.UserSelect,
|
||||||
|
> extends APIBaseComponent<T> {
|
||||||
|
/**
|
||||||
|
* A developer-defined identifier for the select menu, max 100 characters
|
||||||
|
*/
|
||||||
|
custom_id: string;
|
||||||
|
/**
|
||||||
|
* Custom placeholder text if nothing is selected, max 150 characters
|
||||||
|
*/
|
||||||
|
placeholder?: string;
|
||||||
|
/**
|
||||||
|
* The minimum number of items that must be chosen; min 0, max 25
|
||||||
|
*
|
||||||
|
* @default 1
|
||||||
|
*/
|
||||||
|
min_values?: number;
|
||||||
|
/**
|
||||||
|
* The maximum number of items that can be chosen; max 25
|
||||||
|
*
|
||||||
|
* @default 1
|
||||||
|
*/
|
||||||
|
max_values?: number;
|
||||||
|
/**
|
||||||
|
* Disable the select
|
||||||
|
*
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface APIBaseAutoPopulatedSelectMenuComponent<
|
||||||
|
T extends
|
||||||
|
| ComponentType.ChannelSelect
|
||||||
|
| ComponentType.MentionableSelect
|
||||||
|
| ComponentType.RoleSelect
|
||||||
|
| ComponentType.UserSelect,
|
||||||
|
D extends SelectMenuDefaultValueType,
|
||||||
|
> extends APIBaseSelectMenuComponent<T> {
|
||||||
|
/**
|
||||||
|
* List of default values for auto-populated select menu components
|
||||||
|
*/
|
||||||
|
default_values?: APISelectMenuDefaultValue<D>[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||||
|
*/
|
||||||
|
export interface APIStringSelectComponent extends APIBaseSelectMenuComponent<ComponentType.StringSelect> {
|
||||||
|
/**
|
||||||
|
* Specified choices in a select menu; max 25
|
||||||
|
*/
|
||||||
|
options: APISelectMenuOption[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||||
|
*/
|
||||||
|
export type APIUserSelectComponent = APIBaseAutoPopulatedSelectMenuComponent<
|
||||||
|
ComponentType.UserSelect,
|
||||||
|
SelectMenuDefaultValueType.User
|
||||||
|
>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||||
|
*/
|
||||||
|
export type APIRoleSelectComponent = APIBaseAutoPopulatedSelectMenuComponent<
|
||||||
|
ComponentType.RoleSelect,
|
||||||
|
SelectMenuDefaultValueType.Role
|
||||||
|
>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||||
|
*/
|
||||||
|
export type APIMentionableSelectComponent = APIBaseAutoPopulatedSelectMenuComponent<
|
||||||
|
ComponentType.MentionableSelect,
|
||||||
|
SelectMenuDefaultValueType.Role | SelectMenuDefaultValueType.User
|
||||||
|
>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||||
|
*/
|
||||||
|
export interface APIChannelSelectComponent
|
||||||
|
extends APIBaseAutoPopulatedSelectMenuComponent<ComponentType.ChannelSelect, SelectMenuDefaultValueType.Channel> {
|
||||||
|
/**
|
||||||
|
* List of channel types to include in the ChannelSelect component
|
||||||
|
*/
|
||||||
|
channel_types?: ChannelType[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-default-value-structure
|
||||||
|
*/
|
||||||
|
export enum SelectMenuDefaultValueType {
|
||||||
|
Channel = 'channel',
|
||||||
|
Role = 'role',
|
||||||
|
User = 'user',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-default-value-structure
|
||||||
|
*/
|
||||||
|
export interface APISelectMenuDefaultValue<T extends SelectMenuDefaultValueType> {
|
||||||
|
type: T;
|
||||||
|
id: Snowflake;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type APIAutoPopulatedSelectMenuComponent =
|
||||||
|
| APIChannelSelectComponent
|
||||||
|
| APIMentionableSelectComponent
|
||||||
|
| APIRoleSelectComponent
|
||||||
|
| APIUserSelectComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||||
|
*/
|
||||||
|
export type APISelectMenuComponent =
|
||||||
|
| APIChannelSelectComponent
|
||||||
|
| APIMentionableSelectComponent
|
||||||
|
| APIRoleSelectComponent
|
||||||
|
| APIStringSelectComponent
|
||||||
|
| APIUserSelectComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-option-structure
|
||||||
|
*/
|
||||||
|
export interface APISelectMenuOption {
|
||||||
|
/**
|
||||||
|
* The user-facing name of the option (max 100 chars)
|
||||||
|
*/
|
||||||
|
label: string;
|
||||||
|
/**
|
||||||
|
* The dev-defined value of the option (max 100 chars)
|
||||||
|
*/
|
||||||
|
value: string;
|
||||||
|
/**
|
||||||
|
* An additional description of the option (max 100 chars)
|
||||||
|
*/
|
||||||
|
description?: string;
|
||||||
|
/**
|
||||||
|
* The emoji to display to the left of the option
|
||||||
|
*/
|
||||||
|
emoji?: APIMessageComponentEmoji;
|
||||||
|
/**
|
||||||
|
* Whether this option should be already-selected by default
|
||||||
|
*/
|
||||||
|
default?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#text-inputs-text-input-structure
|
||||||
|
*/
|
||||||
|
export interface APITextInputComponent extends APIBaseComponent<ComponentType.TextInput> {
|
||||||
|
/**
|
||||||
|
* One of text input styles
|
||||||
|
*/
|
||||||
|
style: TextInputStyle;
|
||||||
|
/**
|
||||||
|
* The custom id for the text input
|
||||||
|
*/
|
||||||
|
custom_id: string;
|
||||||
|
/**
|
||||||
|
* Text that appears on top of the text input field, max 45 characters
|
||||||
|
*/
|
||||||
|
label: string;
|
||||||
|
/**
|
||||||
|
* Placeholder for the text input
|
||||||
|
*/
|
||||||
|
placeholder?: string;
|
||||||
|
/**
|
||||||
|
* The pre-filled text in the text input
|
||||||
|
*/
|
||||||
|
value?: string;
|
||||||
|
/**
|
||||||
|
* Minimal length of text input
|
||||||
|
*/
|
||||||
|
min_length?: number;
|
||||||
|
/**
|
||||||
|
* Maximal length of text input
|
||||||
|
*/
|
||||||
|
max_length?: number;
|
||||||
|
/**
|
||||||
|
* Whether or not this text input is required or not
|
||||||
|
*/
|
||||||
|
required?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/resources/channel#channel-object-channel-flags
|
||||||
|
*/
|
||||||
|
export enum ChannelFlags {
|
||||||
|
/**
|
||||||
|
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
||||||
|
*/
|
||||||
|
GuildFeedRemoved = 1 << 0,
|
||||||
|
/**
|
||||||
|
* This thread is pinned to the top of its parent forum channel
|
||||||
|
*/
|
||||||
|
Pinned = 1 << 1,
|
||||||
|
/**
|
||||||
|
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
||||||
|
*/
|
||||||
|
ActiveChannelsRemoved = 1 << 2,
|
||||||
|
/**
|
||||||
|
* Whether a tag is required to be specified when creating a thread in a forum channel.
|
||||||
|
* Tags are specified in the `applied_tags` field
|
||||||
|
*/
|
||||||
|
RequireTag = 1 << 4,
|
||||||
|
/**
|
||||||
|
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
||||||
|
*/
|
||||||
|
IsSpam = 1 << 5,
|
||||||
|
/**
|
||||||
|
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
||||||
|
*/
|
||||||
|
IsGuildResourceChannel = 1 << 7,
|
||||||
|
/**
|
||||||
|
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
||||||
|
*/
|
||||||
|
ClydeAI = 1 << 8,
|
||||||
|
/**
|
||||||
|
* @unstable This channel flag is currently not documented by Discord but has a known value which we will try to keep up to date.
|
||||||
|
*/
|
||||||
|
IsScheduledForDeletion = 1 << 9,
|
||||||
|
/**
|
||||||
|
* Whether media download options are hidden.
|
||||||
|
*/
|
||||||
|
HideMediaDownloadOptions = 1 << 15,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#message-components
|
||||||
|
*/
|
||||||
|
export type APIMessageComponent = APIActionRowComponent<APIMessageActionRowComponent> | APIMessageActionRowComponent;
|
||||||
|
export type APIModalComponent = APIActionRowComponent<APIModalActionRowComponent> | APIModalActionRowComponent;
|
||||||
|
|
||||||
|
export type APIActionRowComponentTypes = APIMessageActionRowComponent | APIModalActionRowComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/interactions/message-components#message-components
|
||||||
|
*/
|
||||||
|
export type APIMessageActionRowComponent = APIButtonComponent | APISelectMenuComponent;
|
||||||
|
|
||||||
|
export type APIComponents =
|
||||||
|
| APIMessageActionRowComponent
|
||||||
|
| APIModalActionRowComponent
|
||||||
|
| APIContainerComponent
|
||||||
|
| APIContainerComponents
|
||||||
|
| APITopLevelComponent;
|
||||||
|
|
||||||
|
// Modal components
|
||||||
|
export type APIModalActionRowComponent = APITextInputComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/components/reference#section
|
||||||
|
*
|
||||||
|
* A Section is a top-level layout component that allows you to join text contextually with an accessory.
|
||||||
|
*/
|
||||||
|
export interface APISectionComponent {
|
||||||
|
/** 9 for section component */
|
||||||
|
type: ComponentType.Section;
|
||||||
|
/** Optional identifier for component */
|
||||||
|
id?: number;
|
||||||
|
/** One to three text components */
|
||||||
|
components: APITextDispalyComponent[];
|
||||||
|
/** A thumbnail or a button component, with a future possibility of adding more compatible components */
|
||||||
|
accessory: APIButtonComponent | APIThumbnailComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/components/reference#text-display
|
||||||
|
*
|
||||||
|
* A Text Display is a top-level content component that allows you to add text to your message formatted with markdown and mention users and roles. This is similar to the content field of a message, but allows you to add multiple text components, controlling the layout of your message.
|
||||||
|
* Text Displays are only available in messages.
|
||||||
|
*/
|
||||||
|
export interface APITextDispalyComponent {
|
||||||
|
/** 10 for text display */
|
||||||
|
type: ComponentType.TextDisplay;
|
||||||
|
/** Optional identifier for component */
|
||||||
|
id?: number;
|
||||||
|
/** Text that will be displayed similar to a message */
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/components/reference#thumbnail
|
||||||
|
*
|
||||||
|
* A Thumbnail is a content component that is a small image only usable as an accessory in a section. The preview comes from an url or attachment through the unfurled media item structure.
|
||||||
|
* Thumbnails are only available in messages as an accessory in a section.
|
||||||
|
*/
|
||||||
|
export interface APIThumbnailComponent {
|
||||||
|
/** 11 for thumbnail */
|
||||||
|
type: ComponentType.Thumbnail;
|
||||||
|
/** Optional identifier for component */
|
||||||
|
id?: number;
|
||||||
|
/** A url or attachment */
|
||||||
|
media: APIUnfurledMediaItem;
|
||||||
|
/** Alt text for the media */
|
||||||
|
description?: string;
|
||||||
|
/** Whether the thumbnail should be a spoiler (or blurred out). Defaults to false */
|
||||||
|
spoiler?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/components/reference#media-gallery
|
||||||
|
*
|
||||||
|
* A Media Gallery is a top-level content component that allows you to display 1-10 media attachments in an organized gallery format. Each item can have optional descriptions and can be marked as spoilers.
|
||||||
|
* Media Galleries are only available in messages.
|
||||||
|
*/
|
||||||
|
export interface APIMediaGalleryComponent {
|
||||||
|
/** 12 for media gallery */
|
||||||
|
type: ComponentType.MediaGallery;
|
||||||
|
/** Optional identifier for component */
|
||||||
|
id?: number;
|
||||||
|
/** 1 to 10 media gallery items */
|
||||||
|
items: APIMediaGalleryItems[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface APIMediaGalleryItems {
|
||||||
|
/** A url or attachment */
|
||||||
|
media: APIUnfurledMediaItem;
|
||||||
|
/** Alt text for the media */
|
||||||
|
description?: string;
|
||||||
|
/** Whether the thumbnail should be a spoiler (or blurred out). Defaults to false */
|
||||||
|
spoiler?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/components/reference#file
|
||||||
|
*
|
||||||
|
* A File is a top-level component that allows you to display an uploaded file as an attachment to the message and reference it in the component. Each file component can only display 1 attached file, but you can upload multiple files and add them to different file components within your payload. This is similar to the embeds field of a message but allows you to control the layout of your message by using this anywhere as a component.
|
||||||
|
* Files are only available in messages.
|
||||||
|
*/
|
||||||
|
export interface APIFileComponent {
|
||||||
|
/** 13 for file */
|
||||||
|
type: ComponentType.File;
|
||||||
|
/** Optional identifier for component */
|
||||||
|
id?: number;
|
||||||
|
/** This unfurled media item is unique in that it only supports attachment references using the attachment://<filename> syntax */
|
||||||
|
file: APIUnfurledMediaItem;
|
||||||
|
/** Whether the media should be a spoiler (or blurred out). Defaults to false */
|
||||||
|
spoiler?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/components/reference#separator
|
||||||
|
*
|
||||||
|
* A Separator is a top-level layout component that adds vertical padding and visual division between other components.
|
||||||
|
*/
|
||||||
|
export interface APISeparatorComponent {
|
||||||
|
/** 14 for separator */
|
||||||
|
type: ComponentType.Separator;
|
||||||
|
/** Optional identifier for component */
|
||||||
|
id?: number;
|
||||||
|
/** Whether a visual divider should be displayed in the component. Defaults to true */
|
||||||
|
divider?: boolean;
|
||||||
|
/** Size of separator padding—1 for small padding, 2 for large padding. Defaults to 1 */
|
||||||
|
spacing?: Spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum Spacing {
|
||||||
|
/** For small padding */
|
||||||
|
Small = 1,
|
||||||
|
/** For large padding */
|
||||||
|
Large,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type APIContainerComponents =
|
||||||
|
| APIActionRowComponent<APIActionRowComponentTypes>
|
||||||
|
| APITextDispalyComponent
|
||||||
|
| APISectionComponent
|
||||||
|
| APIMediaGalleryComponent
|
||||||
|
| APIFileComponent
|
||||||
|
| APISeparatorComponent
|
||||||
|
| APIThumbnailComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/components/reference#container
|
||||||
|
*/
|
||||||
|
export interface APIContainerComponent {
|
||||||
|
/** 15 for container */
|
||||||
|
type: ComponentType.Container;
|
||||||
|
/** Optional identifier for component */
|
||||||
|
id?: number;
|
||||||
|
/** Up to 10 components of the type action row, text display, section, media gallery, separator, or file */
|
||||||
|
components: APIContainerComponents[];
|
||||||
|
/** Color for the accent on the container as RGB from 0x000000 to 0xFFFFFF */
|
||||||
|
accent_color?: number;
|
||||||
|
/** Whether the container should be a spoiler (or blurred out). Defaults to false. */
|
||||||
|
spoiler?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://discord.com/developers/docs/components/reference#unfurled-media-item-structure
|
||||||
|
*/
|
||||||
|
export interface APIUnfurledMediaItem
|
||||||
|
extends Identify<
|
||||||
|
MakeRequired<Partial<Pick<APIAttachment, 'url' | 'proxy_url' | 'height' | 'width' | 'content_type'>>, 'url'>
|
||||||
|
> {}
|
||||||
|
|
||||||
|
export type APITopLevelComponent =
|
||||||
|
| APIContainerComponent
|
||||||
|
| APIActionRowComponent<APIActionRowComponentTypes>
|
||||||
|
| APIFileComponent
|
||||||
|
| APIMediaGalleryComponent
|
||||||
|
| APISectionComponent
|
||||||
|
| APISeparatorComponent
|
||||||
|
| APITextDispalyComponent;
|
@ -20,6 +20,7 @@ export * from './voice';
|
|||||||
export * from './webhook';
|
export * from './webhook';
|
||||||
export * from './monetization';
|
export * from './monetization';
|
||||||
export * from './soundboard';
|
export * from './soundboard';
|
||||||
|
export * from './components';
|
||||||
|
|
||||||
import type { LocaleString } from '../rest';
|
import type { LocaleString } from '../rest';
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import type { ChannelType, OverwriteType, Permissions, Snowflake, VideoQualityMode } from '..';
|
import type { ChannelType, OverwriteType, Permissions, Snowflake, VideoQualityMode } from '..';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
APIActionRowComponent,
|
|
||||||
APIAllowedMentions,
|
APIAllowedMentions,
|
||||||
APIAttachment,
|
APIAttachment,
|
||||||
APIChannel,
|
APIChannel,
|
||||||
@ -11,10 +10,10 @@ import type {
|
|||||||
APIGuildForumDefaultReactionEmoji,
|
APIGuildForumDefaultReactionEmoji,
|
||||||
APIGuildForumTag,
|
APIGuildForumTag,
|
||||||
APIMessage,
|
APIMessage,
|
||||||
APIMessageActionRowComponent,
|
|
||||||
APIMessageReference,
|
APIMessageReference,
|
||||||
APIThreadList,
|
APIThreadList,
|
||||||
APIThreadMember,
|
APIThreadMember,
|
||||||
|
APITopLevelComponent,
|
||||||
APIUser,
|
APIUser,
|
||||||
ChannelFlags,
|
ChannelFlags,
|
||||||
ForumLayoutType,
|
ForumLayoutType,
|
||||||
@ -294,7 +293,7 @@ export interface RESTPostAPIChannelMessageJSONBody {
|
|||||||
*
|
*
|
||||||
* See https://discord.com/developers/docs/interactions/message-components#component-object
|
* See https://discord.com/developers/docs/interactions/message-components#component-object
|
||||||
*/
|
*/
|
||||||
components?: APIActionRowComponent<APIMessageActionRowComponent>[] | undefined;
|
components?: APITopLevelComponent[] | undefined;
|
||||||
/**
|
/**
|
||||||
* IDs of up to 3 stickers in the server to send in the message
|
* IDs of up to 3 stickers in the server to send in the message
|
||||||
*
|
*
|
||||||
@ -442,7 +441,7 @@ export interface RESTPatchAPIChannelMessageJSONBody {
|
|||||||
*
|
*
|
||||||
* See https://discord.com/developers/docs/interactions/message-components#component-object
|
* See https://discord.com/developers/docs/interactions/message-components#component-object
|
||||||
*/
|
*/
|
||||||
components?: APIActionRowComponent<APIMessageActionRowComponent>[] | null | undefined;
|
components?: APITopLevelComponent[] | null | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import type { Snowflake } from '..';
|
import type { Snowflake } from '..';
|
||||||
import type {
|
import type {
|
||||||
APIActionRowComponent,
|
|
||||||
APIAllowedMentions,
|
APIAllowedMentions,
|
||||||
APIEmbed,
|
APIEmbed,
|
||||||
APIMessage,
|
APIMessage,
|
||||||
APIMessageActionRowComponent,
|
APITopLevelComponent,
|
||||||
APIWebhook,
|
APIWebhook,
|
||||||
MessageFlags,
|
MessageFlags,
|
||||||
} from '../payloads';
|
} from '../payloads';
|
||||||
@ -136,7 +135,7 @@ export interface RESTPostAPIWebhookWithTokenJSONBody {
|
|||||||
*
|
*
|
||||||
* See https://discord.com/developers/docs/interactions/message-components#component-object
|
* See https://discord.com/developers/docs/interactions/message-components#component-object
|
||||||
*/
|
*/
|
||||||
components?: APIActionRowComponent<APIMessageActionRowComponent>[] | undefined;
|
components?: APITopLevelComponent[] | undefined;
|
||||||
/**
|
/**
|
||||||
* Attachment objects with filename and description
|
* Attachment objects with filename and description
|
||||||
*/
|
*/
|
||||||
@ -190,6 +189,14 @@ export interface RESTPostAPIWebhookWithTokenQuery {
|
|||||||
* Available only if the {@link RESTPostAPIWebhookWithTokenJSONBody.thread_name} JSON body property is not specified
|
* Available only if the {@link RESTPostAPIWebhookWithTokenJSONBody.thread_name} JSON body property is not specified
|
||||||
*/
|
*/
|
||||||
thread_id?: Snowflake;
|
thread_id?: Snowflake;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to respect the components field of the request. When enabled, allows application-owned webhooks to use all components and
|
||||||
|
* non-owned webhooks to use non-interactive components.
|
||||||
|
*
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
with_components?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -208,7 +215,7 @@ export type RESTPostAPIWebhookWithTokenWaitResult = APIMessage;
|
|||||||
/**
|
/**
|
||||||
* https://discord.com/developers/docs/resources/webhook#execute-slackcompatible-webhook-query-string-params
|
* https://discord.com/developers/docs/resources/webhook#execute-slackcompatible-webhook-query-string-params
|
||||||
*/
|
*/
|
||||||
export type RESTPostAPIWebhookWithTokenSlackQuery = RESTPostAPIWebhookWithTokenQuery;
|
export type RESTPostAPIWebhookWithTokenSlackQuery = Omit<RESTPostAPIWebhookWithTokenQuery, 'with_components'>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://discord.com/developers/docs/resources/webhook#execute-slackcompatible-webhook
|
* https://discord.com/developers/docs/resources/webhook#execute-slackcompatible-webhook
|
||||||
@ -226,7 +233,7 @@ export type RESTPostAPIWebhookWithTokenSlackWaitResult = APIMessage;
|
|||||||
/**
|
/**
|
||||||
* https://discord.com/developers/docs/resources/webhook#execute-githubcompatible-webhook-query-string-params
|
* https://discord.com/developers/docs/resources/webhook#execute-githubcompatible-webhook-query-string-params
|
||||||
*/
|
*/
|
||||||
export type RESTPostAPIWebhookWithTokenGitHubQuery = RESTPostAPIWebhookWithTokenQuery;
|
export type RESTPostAPIWebhookWithTokenGitHubQuery = Omit<RESTPostAPIWebhookWithTokenQuery, 'with_components'>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://discord.com/developers/docs/resources/webhook#execute-githubcompatible-webhook
|
* https://discord.com/developers/docs/resources/webhook#execute-githubcompatible-webhook
|
||||||
@ -269,6 +276,7 @@ export type RESTPatchAPIWebhookWithTokenMessageJSONBody = AddUndefinedToPossibly
|
|||||||
attachments?: RESTAPIAttachment[] | undefined;
|
attachments?: RESTAPIAttachment[] | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type RESTPatchAPIWebhookWithTokenMessageQuery = Omit<RESTPostAPIWebhookWithTokenQuery, 'wait'>;
|
||||||
/**
|
/**
|
||||||
* https://discord.com/developers/docs/resources/webhook#edit-webhook-message
|
* https://discord.com/developers/docs/resources/webhook#edit-webhook-message
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user