fix(builders): text display component support for modals (#11155)

This commit is contained in:
Vlad Frangu
2025-10-08 21:17:19 +03:00
committed by GitHub
parent 9a60e4033b
commit 99b8436117
2 changed files with 42 additions and 6 deletions

View File

@@ -2,6 +2,7 @@ import { s } from '@sapphire/shapeshift';
import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../../components/ActionRow.js'; import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../../components/ActionRow.js';
import { customIdValidator } from '../../components/Assertions.js'; import { customIdValidator } from '../../components/Assertions.js';
import { LabelBuilder } from '../../components/label/Label.js'; import { LabelBuilder } from '../../components/label/Label.js';
import { TextDisplayBuilder } from '../../components/v2/TextDisplay.js';
import { isValidationEnabled } from '../../util/validation.js'; import { isValidationEnabled } from '../../util/validation.js';
export const titleValidator = s export const titleValidator = s
@@ -10,7 +11,7 @@ export const titleValidator = s
.lengthLessThanOrEqual(45) .lengthLessThanOrEqual(45)
.setValidationEnabled(isValidationEnabled); .setValidationEnabled(isValidationEnabled);
export const componentsValidator = s export const componentsValidator = s
.union([s.instance(ActionRowBuilder), s.instance(LabelBuilder)]) .union([s.instance(ActionRowBuilder), s.instance(LabelBuilder), s.instance(TextDisplayBuilder)])
.array() .array()
.lengthGreaterThanOrEqual(1) .lengthGreaterThanOrEqual(1)
.setValidationEnabled(isValidationEnabled); .setValidationEnabled(isValidationEnabled);
@@ -18,7 +19,7 @@ export const componentsValidator = s
export function validateRequiredParameters( export function validateRequiredParameters(
customId?: string, customId?: string,
title?: string, title?: string,
components?: (ActionRowBuilder<ModalActionRowComponentBuilder> | LabelBuilder)[], components?: (ActionRowBuilder<ModalActionRowComponentBuilder> | LabelBuilder | TextDisplayBuilder)[],
) { ) {
customIdValidator.parse(customId); customIdValidator.parse(customId);
titleValidator.parse(title); titleValidator.parse(title);

View File

@@ -7,6 +7,7 @@ import type {
APIComponentInModalActionRow, APIComponentInModalActionRow,
APILabelComponent, APILabelComponent,
APIModalInteractionResponseCallbackData, APIModalInteractionResponseCallbackData,
APITextDisplayComponent,
} from 'discord-api-types/v10'; } from 'discord-api-types/v10';
import { ComponentType } from 'discord-api-types/v10'; import { ComponentType } from 'discord-api-types/v10';
import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../../components/ActionRow.js'; import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../../components/ActionRow.js';
@@ -14,6 +15,7 @@ import { customIdValidator } from '../../components/Assertions.js';
import { createComponentBuilder, resolveBuilder } from '../../components/Components.js'; import { createComponentBuilder, resolveBuilder } from '../../components/Components.js';
import { LabelBuilder } from '../../components/label/Label.js'; import { LabelBuilder } from '../../components/label/Label.js';
import { TextInputBuilder } from '../../components/textInput/TextInput.js'; import { TextInputBuilder } from '../../components/textInput/TextInput.js';
import { TextDisplayBuilder } from '../../components/v2/TextDisplay.js';
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js'; import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
import { titleValidator, validateRequiredParameters } from './Assertions.js'; import { titleValidator, validateRequiredParameters } from './Assertions.js';
@@ -29,7 +31,8 @@ export class ModalBuilder implements JSONEncodable<APIModalInteractionResponseCa
/** /**
* The components within this modal. * The components within this modal.
*/ */
public readonly components: (ActionRowBuilder<ModalActionRowComponentBuilder> | LabelBuilder)[] = []; public readonly components: (ActionRowBuilder<ModalActionRowComponentBuilder> | LabelBuilder | TextDisplayBuilder)[] =
[];
/** /**
* Creates a new modal from API data. * Creates a new modal from API data.
@@ -68,24 +71,31 @@ export class ModalBuilder implements JSONEncodable<APIModalInteractionResponseCa
* Adds components to this modal. * Adds components to this modal.
* *
* @param components - The components to add * @param components - The components to add
* @deprecated Use {@link ModalBuilder.addLabelComponents} or {@link ModalBuilder.addActionRowComponents} instead * @deprecated Use {@link ModalBuilder.addLabelComponents} or {@link ModalBuilder.addTextDisplayComponents} instead
*/ */
public addComponents( public addComponents(
...components: RestOrArray< ...components: RestOrArray<
| ActionRowBuilder<ModalActionRowComponentBuilder> | ActionRowBuilder<ModalActionRowComponentBuilder>
| APIActionRowComponent<APIComponentInModalActionRow> | APIActionRowComponent<APIComponentInModalActionRow>
| APILabelComponent | APILabelComponent
| APITextDisplayComponent
| APITextInputComponent | APITextInputComponent
| LabelBuilder | LabelBuilder
| TextDisplayBuilder
| TextInputBuilder | TextInputBuilder
> >
) { ) {
this.components.push( this.components.push(
...normalizeArray(components).map((component, idx) => { ...normalizeArray(components).map((component, idx) => {
if (component instanceof ActionRowBuilder || component instanceof LabelBuilder) { if (
component instanceof ActionRowBuilder ||
component instanceof LabelBuilder ||
component instanceof TextDisplayBuilder
) {
return component; return component;
} }
// Deprecated support
if (component instanceof TextInputBuilder) { if (component instanceof TextInputBuilder) {
return new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(component); return new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(component);
} }
@@ -99,6 +109,11 @@ export class ModalBuilder implements JSONEncodable<APIModalInteractionResponseCa
return new LabelBuilder(component); return new LabelBuilder(component);
} }
if (component.type === ComponentType.TextDisplay) {
return new TextDisplayBuilder(component);
}
// Deprecated, should go in a label component
if (component.type === ComponentType.TextInput) { if (component.type === ComponentType.TextInput) {
return new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents( return new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(
new TextInputBuilder(component), new TextInputBuilder(component),
@@ -128,6 +143,24 @@ export class ModalBuilder implements JSONEncodable<APIModalInteractionResponseCa
return this; return this;
} }
/**
* Adds text display components to this modal.
*
* @param components - The components to add
*/
public addTextDisplayComponents(
...components: RestOrArray<
APITextDisplayComponent | TextDisplayBuilder | ((builder: TextDisplayBuilder) => TextDisplayBuilder)
>
) {
const normalized = normalizeArray(components);
const resolved = normalized.map((row) => resolveBuilder(row, TextDisplayBuilder));
this.components.push(...resolved);
return this;
}
/** /**
* Adds action rows to this modal. * Adds action rows to this modal.
* *
@@ -211,7 +244,9 @@ export class ModalBuilder implements JSONEncodable<APIModalInteractionResponseCa
* @param components - The components to set * @param components - The components to set
* @deprecated Use {@link ModalBuilder.setLabelComponents} instead * @deprecated Use {@link ModalBuilder.setLabelComponents} instead
*/ */
public setComponents(...components: RestOrArray<ActionRowBuilder<ModalActionRowComponentBuilder> | LabelBuilder>) { public setComponents(
...components: RestOrArray<ActionRowBuilder<ModalActionRowComponentBuilder> | LabelBuilder | TextDisplayBuilder>
) {
this.components.splice(0, this.components.length, ...normalizeArray(components)); this.components.splice(0, this.components.length, ...normalizeArray(components));
return this; return this;
} }