feat(builders)!: Support select in modals (#11034)

BREAKING CHANGE: Text inputs no longer accept a label.
BREAKING CHANGE: Modals now only set labels instead of action rows.
This commit is contained in:
Jiralite
2025-09-05 20:56:14 +04:00
committed by GitHub
parent ddf9f818e8
commit f7c77a73de
13 changed files with 364 additions and 115 deletions

View File

@@ -1,17 +1,22 @@
import { ComponentType, TextInputStyle, type APIModalInteractionResponseCallbackData } from 'discord-api-types/v10';
import { describe, test, expect } from 'vitest';
import { ActionRowBuilder, ModalBuilder, TextInputBuilder } from '../../src/index.js';
import { ModalBuilder, TextInputBuilder, LabelBuilder } from '../../src/index.js';
const modal = () => new ModalBuilder();
const textInput = () =>
new ActionRowBuilder().addTextInputComponent(
new TextInputBuilder().setCustomId('text').setLabel(':3').setStyle(TextInputStyle.Short),
);
const label = () =>
new LabelBuilder()
.setLabel('label')
.setTextInputComponent(new TextInputBuilder().setCustomId('text').setStyle(TextInputStyle.Short));
describe('Modals', () => {
test('GIVEN valid fields THEN builder does not throw', () => {
expect(() => modal().setTitle('test').setCustomId('foobar').setActionRows(textInput()).toJSON()).not.toThrowError();
expect(() => modal().setTitle('test').setCustomId('foobar').addActionRows(textInput()).toJSON()).not.toThrowError();
expect(() =>
modal().setTitle('test').setCustomId('foobar').setLabelComponents(label()).toJSON(),
).not.toThrowError();
expect(() =>
modal().setTitle('test').setCustomId('foobar').setLabelComponents(label()).toJSON(),
).not.toThrowError();
});
test('GIVEN invalid fields THEN builder does throw', () => {
@@ -21,34 +26,33 @@ describe('Modals', () => {
});
test('GIVEN valid input THEN valid JSON outputs are given', () => {
const modalData: APIModalInteractionResponseCallbackData = {
const modalData = {
title: 'title',
custom_id: 'custom id',
components: [
{
type: ComponentType.ActionRow,
components: [
{
type: ComponentType.TextInput,
label: 'label',
style: TextInputStyle.Paragraph,
custom_id: 'custom id',
},
],
type: ComponentType.Label,
id: 33,
label: 'label',
description: 'description',
component: {
type: ComponentType.TextInput,
style: TextInputStyle.Paragraph,
custom_id: 'custom id',
},
},
{
type: ComponentType.ActionRow,
components: [
{
type: ComponentType.TextInput,
label: 'label',
style: TextInputStyle.Paragraph,
custom_id: 'custom id',
},
],
type: ComponentType.Label,
label: 'label',
description: 'description',
component: {
type: ComponentType.TextInput,
style: TextInputStyle.Paragraph,
custom_id: 'custom id',
},
},
],
};
} satisfies APIModalInteractionResponseCallbackData;
expect(new ModalBuilder(modalData).toJSON()).toEqual(modalData);
@@ -56,16 +60,19 @@ describe('Modals', () => {
modal()
.setTitle(modalData.title)
.setCustomId('custom id')
.setActionRows(
new ActionRowBuilder().addTextInputComponent(
new TextInputBuilder().setCustomId('custom id').setLabel('label').setStyle(TextInputStyle.Paragraph),
),
.setLabelComponents(
new LabelBuilder()
.setId(33)
.setLabel('label')
.setDescription('description')
.setTextInputComponent(new TextInputBuilder().setCustomId('custom id').setStyle(TextInputStyle.Paragraph)),
)
.addLabelComponents(
new LabelBuilder()
.setLabel('label')
.setDescription('description')
.setTextInputComponent(new TextInputBuilder().setCustomId('custom id').setStyle(TextInputStyle.Paragraph)),
)
.addActionRows([
new ActionRowBuilder().addTextInputComponent(
new TextInputBuilder().setCustomId('custom id').setLabel('label').setStyle(TextInputStyle.Paragraph),
),
])
.toJSON(),
).toEqual(modalData);
});