mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-14 10:33:30 +01:00
feat: components v2 in builders (#10788)
* feat: thumbnail component * chore: just a temp file to track remaining components * feat: file component * feat: section component * feat: text display component * chore: bump alpha version of dtypes * chore: simplify ComponentBuilder base type * feat: MediaGallery * feat: Section builder * chore: tests for sections * chore: forgot you * chore: docs * fix: missing comma * fix: my bad * feat: container builder * chore: requested changes * chore: missed u * chore: type tests * chore: setId/clearId * chore: apply suggestions from code review * chore: unify pick * chore: some requested changes * chore: tests and small fixes * chore: added tests that need fixing * fix: tests * chore: cleanup on isle protected * docs: remove locale * chore: types for new message builder * chore: fix tests * chore: attempt 1 at message builder assertions * chore: apply suggestions * Update packages/builders/src/messages/Assertions.ts Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> * Update packages/builders/src/components/v2/Thumbnail.ts Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> * fix: tests * chore: fmt * Apply suggestions from code review Co-authored-by: Denis-Adrian Cristea <didinele.dev@gmail.com> * chore: fix pnpm lockfile revert --------- Co-authored-by: Qjuh <76154676+Qjuh@users.noreply.github.com> Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> Co-authored-by: Denis-Adrian Cristea <didinele.dev@gmail.com>
This commit is contained in:
232
packages/builders/src/components/v2/Container.ts
Normal file
232
packages/builders/src/components/v2/Container.ts
Normal file
@@ -0,0 +1,232 @@
|
||||
import type {
|
||||
APIActionRowComponent,
|
||||
APIFileComponent,
|
||||
APITextDisplayComponent,
|
||||
APIContainerComponent,
|
||||
APIComponentInContainer,
|
||||
APIMediaGalleryComponent,
|
||||
APISectionComponent,
|
||||
} from 'discord-api-types/v10';
|
||||
import { ComponentType } from 'discord-api-types/v10';
|
||||
import type { APIComponentInMessageActionRow, APISeparatorComponent } from 'discord-api-types/v9';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
|
||||
import { resolveBuilder } from '../../util/resolveBuilder';
|
||||
import { validate } from '../../util/validation';
|
||||
import { ActionRowBuilder } from '../ActionRow.js';
|
||||
import { ComponentBuilder } from '../Component.js';
|
||||
import { createComponentBuilder } from '../Components';
|
||||
import { containerPredicate } from './Assertions';
|
||||
import { FileBuilder } from './File.js';
|
||||
import { MediaGalleryBuilder } from './MediaGallery';
|
||||
import { SectionBuilder } from './Section';
|
||||
import { SeparatorBuilder } from './Separator.js';
|
||||
import { TextDisplayBuilder } from './TextDisplay';
|
||||
|
||||
export type ContainerComponentBuilders =
|
||||
| ActionRowBuilder
|
||||
| FileBuilder
|
||||
| MediaGalleryBuilder
|
||||
| SectionBuilder
|
||||
| SeparatorBuilder
|
||||
| TextDisplayBuilder;
|
||||
|
||||
export interface ContainerBuilderData extends Partial<Omit<APIContainerComponent, 'components'>> {
|
||||
components: ContainerComponentBuilders[];
|
||||
}
|
||||
|
||||
export class ContainerBuilder extends ComponentBuilder<APIContainerComponent> {
|
||||
protected readonly data: ContainerBuilderData;
|
||||
|
||||
public constructor({ components = [], ...rest }: Partial<APIContainerComponent> = {}) {
|
||||
super();
|
||||
this.data = {
|
||||
...structuredClone(rest),
|
||||
components: components.map((component) => createComponentBuilder(component)),
|
||||
type: ComponentType.Container,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the accent color of this container.
|
||||
*
|
||||
* @param color - The color to use
|
||||
*/
|
||||
public setAccentColor(color: number) {
|
||||
this.data.accent_color = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the accent color of this container.
|
||||
*/
|
||||
public clearAccentColor() {
|
||||
this.data.accent_color = undefined;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the spoiler status of this container.
|
||||
*
|
||||
* @param spoiler - The spoiler status to use
|
||||
*/
|
||||
public setSpoiler(spoiler = true) {
|
||||
this.data.spoiler = spoiler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds action row components to this container.
|
||||
*
|
||||
* @param input - The action row to add
|
||||
*/
|
||||
public addActionRowComponents(
|
||||
...input: RestOrArray<
|
||||
| ActionRowBuilder
|
||||
| APIActionRowComponent<APIComponentInMessageActionRow>
|
||||
| ((builder: ActionRowBuilder) => ActionRowBuilder)
|
||||
>
|
||||
): this {
|
||||
const normalized = normalizeArray(input);
|
||||
const resolved = normalized.map((component) => resolveBuilder(component, ActionRowBuilder));
|
||||
|
||||
this.data.components.push(...resolved);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds file components to this container.
|
||||
*
|
||||
* @param input - The file components to add
|
||||
*/
|
||||
public addFileComponents(
|
||||
...input: RestOrArray<APIFileComponent | FileBuilder | ((builder: FileBuilder) => FileBuilder)>
|
||||
): this {
|
||||
const normalized = normalizeArray(input);
|
||||
const resolved = normalized.map((component) => resolveBuilder(component, FileBuilder));
|
||||
|
||||
this.data.components.push(...resolved);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds media gallery components to this container.
|
||||
*
|
||||
* @param input - The media gallery components to add
|
||||
*/
|
||||
public addMediaGalleryComponents(
|
||||
...input: RestOrArray<
|
||||
APIMediaGalleryComponent | MediaGalleryBuilder | ((builder: MediaGalleryBuilder) => MediaGalleryBuilder)
|
||||
>
|
||||
): this {
|
||||
const normalized = normalizeArray(input);
|
||||
const resolved = normalized.map((component) => resolveBuilder(component, MediaGalleryBuilder));
|
||||
|
||||
this.data.components.push(...resolved);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds section components to this container.
|
||||
*
|
||||
* @param input - The section components to add
|
||||
*/
|
||||
public addSectionComponents(
|
||||
...input: RestOrArray<APISectionComponent | SectionBuilder | ((builder: SectionBuilder) => SectionBuilder)>
|
||||
): this {
|
||||
const normalized = normalizeArray(input);
|
||||
const resolved = normalized.map((component) => resolveBuilder(component, SectionBuilder));
|
||||
|
||||
this.data.components.push(...resolved);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds separator components to this container.
|
||||
*
|
||||
* @param input - The separator components to add
|
||||
*/
|
||||
public addSeparatorComponents(
|
||||
...input: RestOrArray<APISeparatorComponent | SeparatorBuilder | ((builder: SeparatorBuilder) => SeparatorBuilder)>
|
||||
): this {
|
||||
const normalized = normalizeArray(input);
|
||||
const resolved = normalized.map((component) => resolveBuilder(component, SeparatorBuilder));
|
||||
|
||||
this.data.components.push(...resolved);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds text display components to this container.
|
||||
*
|
||||
* @param input - The text display components to add
|
||||
*/
|
||||
public addTextDisplayComponents(
|
||||
...input: RestOrArray<
|
||||
APITextDisplayComponent | TextDisplayBuilder | ((builder: TextDisplayBuilder) => TextDisplayBuilder)
|
||||
>
|
||||
): this {
|
||||
const normalized = normalizeArray(input);
|
||||
const resolved = normalized.map((component) => resolveBuilder(component, TextDisplayBuilder));
|
||||
|
||||
this.data.components.push(...resolved);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes, replaces, or inserts components for this container
|
||||
*
|
||||
* @remarks
|
||||
* This method behaves similarly
|
||||
* to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.
|
||||
*
|
||||
* It's useful for modifying and adjusting order of the already-existing components of a container.
|
||||
* @example
|
||||
* Remove the first component:
|
||||
* ```ts
|
||||
* container.spliceComponents(0, 1);
|
||||
* ```
|
||||
* @example
|
||||
* Remove the first n components:
|
||||
* ```ts
|
||||
* const n = 4;
|
||||
* container.spliceComponents(0, n);
|
||||
* ```
|
||||
* @example
|
||||
* Remove the last component:
|
||||
* ```ts
|
||||
* container.spliceComponents(-1, 1);
|
||||
* ```
|
||||
* @param index - The index to start at
|
||||
* @param deleteCount - The number of components to remove
|
||||
* @param components - The replacing component objects
|
||||
*/
|
||||
public spliceComponents(
|
||||
index: number,
|
||||
deleteCount: number,
|
||||
...components: RestOrArray<APIComponentInContainer | ContainerComponentBuilders>
|
||||
): this {
|
||||
const normalized = normalizeArray(components);
|
||||
const resolved = normalized.map((component) =>
|
||||
component instanceof ComponentBuilder ? component : createComponentBuilder(component),
|
||||
);
|
||||
|
||||
this.data.components.splice(index, deleteCount, ...resolved);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc ComponentBuilder.toJSON}
|
||||
*/
|
||||
public override toJSON(validationOverride?: boolean): APIContainerComponent {
|
||||
const { components, ...rest } = this.data;
|
||||
|
||||
const data = {
|
||||
...structuredClone(rest),
|
||||
components: components.map((component) => component.toJSON(false)),
|
||||
};
|
||||
|
||||
validate(containerPredicate, data, validationOverride);
|
||||
|
||||
return data as APIContainerComponent;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user