mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-09 16:13:31 +01:00
feat: new select menus (#8793)
* feat(builders): new select menus * chore: better re-exporting of deprecated classes * feat: new select menus * chore: typings * chore: add missing todo comment * chore: finish updating tests * chore: add runtime deprecation warnings * chore: format deprecation warning * feat(BaseInteraction): isAnySelectMenu * chore: requested changes * fix: deprecation comments * chore: update @deprecated comments in typings * chore: add tests for select menu type narrowing * fix: bad auto imports Co-authored-by: Julian Vennen <julian@aternos.org> * fix: properly handle resolved members * fix: collectors * chore: suggested changes Co-authored-by: Almeida <almeidx@pm.me> * fix(typings): bad class extends * feat(ChannelSelectMenuBuilder): validation * chore: update todo comment * refactor(ChannelSelectMenu): better handling of channel_types state * chore: style nit * chore: suggested nits Co-authored-by: Aura Román <kyradiscord@gmail.com> Co-authored-by: Julian Vennen <julian@aternos.org> Co-authored-by: Almeida <almeidx@pm.me> Co-authored-by: Aura Román <kyradiscord@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
@@ -9,8 +9,8 @@ import {
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
createComponentBuilder,
|
||||
SelectMenuBuilder,
|
||||
SelectMenuOptionBuilder,
|
||||
StringSelectMenuBuilder,
|
||||
StringSelectMenuOptionBuilder,
|
||||
} from '../../src/index.js';
|
||||
|
||||
const rowWithButtonData: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||
@@ -29,7 +29,7 @@ const rowWithSelectMenuData: APIActionRowComponent<APIMessageActionRowComponent>
|
||||
type: ComponentType.ActionRow,
|
||||
components: [
|
||||
{
|
||||
type: ComponentType.SelectMenu,
|
||||
type: ComponentType.StringSelect,
|
||||
custom_id: '1234',
|
||||
options: [
|
||||
{
|
||||
@@ -73,7 +73,7 @@ describe('Action Row Components', () => {
|
||||
url: 'https://google.com',
|
||||
},
|
||||
{
|
||||
type: ComponentType.SelectMenu,
|
||||
type: ComponentType.StringSelect,
|
||||
placeholder: 'test',
|
||||
custom_id: 'test',
|
||||
options: [
|
||||
@@ -108,7 +108,7 @@ describe('Action Row Components', () => {
|
||||
type: ComponentType.ActionRow,
|
||||
components: [
|
||||
{
|
||||
type: ComponentType.SelectMenu,
|
||||
type: ComponentType.StringSelect,
|
||||
custom_id: '1234',
|
||||
options: [
|
||||
{
|
||||
@@ -134,17 +134,17 @@ describe('Action Row Components', () => {
|
||||
|
||||
test('GIVEN valid builder options THEN valid JSON output is given 2', () => {
|
||||
const button = new ButtonBuilder().setLabel('test').setStyle(ButtonStyle.Primary).setCustomId('123');
|
||||
const selectMenu = new SelectMenuBuilder()
|
||||
const selectMenu = new StringSelectMenuBuilder()
|
||||
.setCustomId('1234')
|
||||
.setMaxValues(10)
|
||||
.setMinValues(12)
|
||||
.setOptions(
|
||||
new SelectMenuOptionBuilder().setLabel('one').setValue('one'),
|
||||
new SelectMenuOptionBuilder().setLabel('two').setValue('two'),
|
||||
new StringSelectMenuOptionBuilder().setLabel('one').setValue('one'),
|
||||
new StringSelectMenuOptionBuilder().setLabel('two').setValue('two'),
|
||||
)
|
||||
.setOptions([
|
||||
new SelectMenuOptionBuilder().setLabel('one').setValue('one'),
|
||||
new SelectMenuOptionBuilder().setLabel('two').setValue('two'),
|
||||
new StringSelectMenuOptionBuilder().setLabel('one').setValue('one'),
|
||||
new StringSelectMenuOptionBuilder().setLabel('two').setValue('two'),
|
||||
]);
|
||||
|
||||
expect(new ActionRowBuilder().addComponents(button).toJSON()).toEqual(rowWithButtonData);
|
||||
|
||||
@@ -13,12 +13,12 @@ import {
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
createComponentBuilder,
|
||||
SelectMenuBuilder,
|
||||
StringSelectMenuBuilder,
|
||||
TextInputBuilder,
|
||||
} from '../../src/index.js';
|
||||
|
||||
describe('createComponentBuilder', () => {
|
||||
test.each([ButtonBuilder, SelectMenuBuilder, TextInputBuilder])(
|
||||
test.each([ButtonBuilder, StringSelectMenuBuilder, TextInputBuilder])(
|
||||
'passing an instance of %j should return itself',
|
||||
(Builder) => {
|
||||
const builder = new Builder();
|
||||
@@ -45,14 +45,14 @@ describe('createComponentBuilder', () => {
|
||||
expect(createComponentBuilder(button)).toBeInstanceOf(ButtonBuilder);
|
||||
});
|
||||
|
||||
test('GIVEN a select menu component THEN returns a SelectMenuBuilder', () => {
|
||||
test('GIVEN a select menu component THEN returns a StringSelectMenuBuilder', () => {
|
||||
const selectMenu: APISelectMenuComponent = {
|
||||
custom_id: 'abc',
|
||||
options: [],
|
||||
type: ComponentType.SelectMenu,
|
||||
type: ComponentType.StringSelect,
|
||||
};
|
||||
|
||||
expect(createComponentBuilder(selectMenu)).toBeInstanceOf(SelectMenuBuilder);
|
||||
expect(createComponentBuilder(selectMenu)).toBeInstanceOf(StringSelectMenuBuilder);
|
||||
});
|
||||
|
||||
test('GIVEN a text input component THEN returns a TextInputBuilder', () => {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { ComponentType, type APISelectMenuComponent, type APISelectMenuOption } from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { SelectMenuBuilder, SelectMenuOptionBuilder } from '../../src/index.js';
|
||||
import { StringSelectMenuBuilder, StringSelectMenuOptionBuilder } from '../../src/index.js';
|
||||
|
||||
const selectMenu = () => new SelectMenuBuilder();
|
||||
const selectMenuOption = () => new SelectMenuOptionBuilder();
|
||||
const selectMenu = () => new StringSelectMenuBuilder();
|
||||
const selectMenuOption = () => new StringSelectMenuOptionBuilder();
|
||||
|
||||
const longStr = 'a'.repeat(256);
|
||||
|
||||
@@ -165,16 +165,16 @@ describe('Select Menu Components', () => {
|
||||
|
||||
test('GIVEN valid JSON input THEN valid JSON history is correct', () => {
|
||||
expect(
|
||||
new SelectMenuBuilder(selectMenuDataWithoutOptions)
|
||||
.addOptions(new SelectMenuOptionBuilder(selectMenuOptionData))
|
||||
new StringSelectMenuBuilder(selectMenuDataWithoutOptions)
|
||||
.addOptions(new StringSelectMenuOptionBuilder(selectMenuOptionData))
|
||||
.toJSON(),
|
||||
).toEqual(selectMenuData);
|
||||
expect(
|
||||
new SelectMenuBuilder(selectMenuDataWithoutOptions)
|
||||
.addOptions([new SelectMenuOptionBuilder(selectMenuOptionData)])
|
||||
new StringSelectMenuBuilder(selectMenuDataWithoutOptions)
|
||||
.addOptions([new StringSelectMenuOptionBuilder(selectMenuOptionData)])
|
||||
.toJSON(),
|
||||
).toEqual(selectMenuData);
|
||||
expect(new SelectMenuOptionBuilder(selectMenuOptionData).toJSON()).toEqual(selectMenuOptionData);
|
||||
expect(new StringSelectMenuOptionBuilder(selectMenuOptionData).toJSON()).toEqual(selectMenuOptionData);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"dependencies": {
|
||||
"@discordjs/util": "workspace:^",
|
||||
"@sapphire/shapeshift": "^3.7.0",
|
||||
"discord-api-types": "^0.37.14",
|
||||
"discord-api-types": "^0.37.15",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"ts-mixer": "^6.0.1",
|
||||
"tslib": "^2.4.0"
|
||||
|
||||
@@ -11,14 +11,24 @@ import { normalizeArray, type RestOrArray } from '../util/normalizeArray.js';
|
||||
import { ComponentBuilder } from './Component.js';
|
||||
import { createComponentBuilder } from './Components.js';
|
||||
import type { ButtonBuilder } from './button/Button.js';
|
||||
import type { SelectMenuBuilder } from './selectMenu/SelectMenu.js';
|
||||
import type { ChannelSelectMenuBuilder } from './selectMenu/ChannelSelectMenu.js';
|
||||
import type { MentionableSelectMenuBuilder } from './selectMenu/MentionableSelectMenu.js';
|
||||
import type { RoleSelectMenuBuilder } from './selectMenu/RoleSelectMenu.js';
|
||||
import type { StringSelectMenuBuilder } from './selectMenu/StringSelectMenu.js';
|
||||
import type { UserSelectMenuBuilder } from './selectMenu/UserSelectMenu.js';
|
||||
import type { TextInputBuilder } from './textInput/TextInput.js';
|
||||
|
||||
export type MessageComponentBuilder =
|
||||
| ActionRowBuilder<MessageActionRowComponentBuilder>
|
||||
| MessageActionRowComponentBuilder;
|
||||
export type ModalComponentBuilder = ActionRowBuilder<ModalActionRowComponentBuilder> | ModalActionRowComponentBuilder;
|
||||
export type MessageActionRowComponentBuilder = ButtonBuilder | SelectMenuBuilder;
|
||||
export type MessageActionRowComponentBuilder =
|
||||
| ButtonBuilder
|
||||
| ChannelSelectMenuBuilder
|
||||
| MentionableSelectMenuBuilder
|
||||
| RoleSelectMenuBuilder
|
||||
| StringSelectMenuBuilder
|
||||
| UserSelectMenuBuilder;
|
||||
export type ModalActionRowComponentBuilder = TextInputBuilder;
|
||||
export type AnyComponentBuilder = MessageActionRowComponentBuilder | ModalActionRowComponentBuilder;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { s } from '@sapphire/shapeshift';
|
||||
import { ButtonStyle, type APIMessageComponentEmoji } from 'discord-api-types/v10';
|
||||
import { ButtonStyle, ChannelType, type APIMessageComponentEmoji } from 'discord-api-types/v10';
|
||||
import { isValidationEnabled } from '../util/validation.js';
|
||||
import { SelectMenuOptionBuilder } from './selectMenu/SelectMenuOption.js';
|
||||
import { StringSelectMenuOptionBuilder } from './selectMenu/StringSelectMenuOption.js';
|
||||
|
||||
export const customIdValidator = s.string
|
||||
.lengthGreaterThanOrEqual(1)
|
||||
@@ -46,7 +46,7 @@ export const jsonOptionValidator = s
|
||||
})
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const optionValidator = s.instance(SelectMenuOptionBuilder).setValidationEnabled(isValidationEnabled);
|
||||
export const optionValidator = s.instance(StringSelectMenuOptionBuilder).setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const optionsValidator = optionValidator.array
|
||||
.lengthGreaterThanOrEqual(0)
|
||||
@@ -56,7 +56,7 @@ export const optionsLengthValidator = s.number.int
|
||||
.lessThanOrEqual(25)
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export function validateRequiredSelectMenuParameters(options: SelectMenuOptionBuilder[], customId?: string) {
|
||||
export function validateRequiredSelectMenuParameters(options: StringSelectMenuOptionBuilder[], customId?: string) {
|
||||
customIdValidator.parse(customId);
|
||||
optionsValidator.parse(options);
|
||||
}
|
||||
@@ -68,6 +68,8 @@ export function validateRequiredSelectMenuOptionParameters(label?: string, value
|
||||
labelValueDescriptionValidator.parse(value);
|
||||
}
|
||||
|
||||
export const channelTypesValidator = s.nativeEnum(ChannelType).array.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const urlValidator = s.string
|
||||
.url({
|
||||
allowedProtocols: ['http:', 'https:', 'discord:'],
|
||||
|
||||
@@ -7,14 +7,22 @@ import {
|
||||
} from './ActionRow.js';
|
||||
import { ComponentBuilder } from './Component.js';
|
||||
import { ButtonBuilder } from './button/Button.js';
|
||||
import { SelectMenuBuilder } from './selectMenu/SelectMenu.js';
|
||||
import { ChannelSelectMenuBuilder } from './selectMenu/ChannelSelectMenu.js';
|
||||
import { MentionableSelectMenuBuilder } from './selectMenu/MentionableSelectMenu.js';
|
||||
import { RoleSelectMenuBuilder } from './selectMenu/RoleSelectMenu.js';
|
||||
import { StringSelectMenuBuilder } from './selectMenu/StringSelectMenu.js';
|
||||
import { UserSelectMenuBuilder } from './selectMenu/UserSelectMenu.js';
|
||||
import { TextInputBuilder } from './textInput/TextInput.js';
|
||||
|
||||
export interface MappedComponentTypes {
|
||||
[ComponentType.ActionRow]: ActionRowBuilder<AnyComponentBuilder>;
|
||||
[ComponentType.Button]: ButtonBuilder;
|
||||
[ComponentType.SelectMenu]: SelectMenuBuilder;
|
||||
[ComponentType.StringSelect]: StringSelectMenuBuilder;
|
||||
[ComponentType.TextInput]: TextInputBuilder;
|
||||
[ComponentType.UserSelect]: UserSelectMenuBuilder;
|
||||
[ComponentType.RoleSelect]: RoleSelectMenuBuilder;
|
||||
[ComponentType.MentionableSelect]: MentionableSelectMenuBuilder;
|
||||
[ComponentType.ChannelSelect]: ChannelSelectMenuBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,10 +47,18 @@ export function createComponentBuilder(
|
||||
return new ActionRowBuilder(data);
|
||||
case ComponentType.Button:
|
||||
return new ButtonBuilder(data);
|
||||
case ComponentType.SelectMenu:
|
||||
return new SelectMenuBuilder(data);
|
||||
case ComponentType.StringSelect:
|
||||
return new StringSelectMenuBuilder(data);
|
||||
case ComponentType.TextInput:
|
||||
return new TextInputBuilder(data);
|
||||
case ComponentType.UserSelect:
|
||||
return new UserSelectMenuBuilder(data);
|
||||
case ComponentType.RoleSelect:
|
||||
return new RoleSelectMenuBuilder(data);
|
||||
case ComponentType.MentionableSelect:
|
||||
return new MentionableSelectMenuBuilder(data);
|
||||
case ComponentType.ChannelSelect:
|
||||
return new ChannelSelectMenuBuilder(data);
|
||||
default:
|
||||
// @ts-expect-error: This case can still occur if we get a newer unsupported component type
|
||||
throw new Error(`Cannot properly serialize component type: ${data.type}`);
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import type { APISelectMenuComponent } from 'discord-api-types/v10';
|
||||
import { customIdValidator, disabledValidator, minMaxValidator, placeholderValidator } from '../Assertions.js';
|
||||
import { ComponentBuilder } from '../Component.js';
|
||||
|
||||
export class BaseSelectMenuBuilder<
|
||||
SelectMenuType extends APISelectMenuComponent,
|
||||
> extends ComponentBuilder<SelectMenuType> {
|
||||
/**
|
||||
* Sets the placeholder for this select menu
|
||||
*
|
||||
* @param placeholder - The placeholder to use for this select menu
|
||||
*/
|
||||
public setPlaceholder(placeholder: string) {
|
||||
this.data.placeholder = placeholderValidator.parse(placeholder);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum values that must be selected in the select menu
|
||||
*
|
||||
* @param minValues - The minimum values that must be selected
|
||||
*/
|
||||
public setMinValues(minValues: number) {
|
||||
this.data.min_values = minMaxValidator.parse(minValues);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum values that must be selected in the select menu
|
||||
*
|
||||
* @param maxValues - The maximum values that must be selected
|
||||
*/
|
||||
public setMaxValues(maxValues: number) {
|
||||
this.data.max_values = minMaxValidator.parse(maxValues);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the custom id for this select menu
|
||||
*
|
||||
* @param customId - The custom id to use for this select menu
|
||||
*/
|
||||
public setCustomId(customId: string) {
|
||||
this.data.custom_id = customIdValidator.parse(customId);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this select menu is disabled
|
||||
*
|
||||
* @param disabled - Whether this select menu is disabled
|
||||
*/
|
||||
public setDisabled(disabled = true) {
|
||||
this.data.disabled = disabledValidator.parse(disabled);
|
||||
return this;
|
||||
}
|
||||
|
||||
public toJSON(): SelectMenuType {
|
||||
customIdValidator.parse(this.data.custom_id);
|
||||
return {
|
||||
...this.data,
|
||||
} as SelectMenuType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import type { APIChannelSelectComponent, ChannelType } from 'discord-api-types/v10';
|
||||
import { ComponentType } from 'discord-api-types/v10';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
|
||||
import { channelTypesValidator, customIdValidator } from '../Assertions.js';
|
||||
import { BaseSelectMenuBuilder } from './BaseSelectMenu.js';
|
||||
|
||||
export class ChannelSelectMenuBuilder extends BaseSelectMenuBuilder<APIChannelSelectComponent> {
|
||||
/**
|
||||
* Creates a new select menu from API data
|
||||
*
|
||||
* @param data - The API data to create this select menu with
|
||||
* @example
|
||||
* Creating a select menu from an API data object
|
||||
* ```ts
|
||||
* const selectMenu = new ChannelSelectMenuBuilder({
|
||||
* custom_id: 'a cool select menu',
|
||||
* placeholder: 'select an option',
|
||||
* max_values: 2,
|
||||
* });
|
||||
* ```
|
||||
* @example
|
||||
* Creating a select menu using setters and API data
|
||||
* ```ts
|
||||
* const selectMenu = new ChannelSelectMenuBuilder({
|
||||
* custom_id: 'a cool select menu',
|
||||
* })
|
||||
* .addChannelTypes(ChannelType.GuildText, ChannelType.GuildAnnouncement)
|
||||
* .setMinValues(2)
|
||||
* ```
|
||||
*/
|
||||
public constructor(data?: Partial<APIChannelSelectComponent>) {
|
||||
super({ ...data, type: ComponentType.ChannelSelect });
|
||||
}
|
||||
|
||||
public addChannelTypes(...types: RestOrArray<ChannelType>) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
types = normalizeArray(types);
|
||||
|
||||
this.data.channel_types ??= [];
|
||||
this.data.channel_types.push(...channelTypesValidator.parse(types));
|
||||
return this;
|
||||
}
|
||||
|
||||
public setChannelTypes(...types: RestOrArray<ChannelType>) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
types = normalizeArray(types);
|
||||
|
||||
this.data.channel_types ??= [];
|
||||
this.data.channel_types.splice(0, this.data.channel_types.length, ...channelTypesValidator.parse(types));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc ComponentBuilder.toJSON}
|
||||
*/
|
||||
public override toJSON(): APIChannelSelectComponent {
|
||||
customIdValidator.parse(this.data.custom_id);
|
||||
|
||||
return {
|
||||
...this.data,
|
||||
} as APIChannelSelectComponent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import type { APIMentionableSelectComponent } from 'discord-api-types/v10';
|
||||
import { ComponentType } from 'discord-api-types/v10';
|
||||
import { BaseSelectMenuBuilder } from './BaseSelectMenu.js';
|
||||
|
||||
export class MentionableSelectMenuBuilder extends BaseSelectMenuBuilder<APIMentionableSelectComponent> {
|
||||
/**
|
||||
* Creates a new select menu from API data
|
||||
*
|
||||
* @param data - The API data to create this select menu with
|
||||
* @example
|
||||
* Creating a select menu from an API data object
|
||||
* ```ts
|
||||
* const selectMenu = new MentionableSelectMenuBuilder({
|
||||
* custom_id: 'a cool select menu',
|
||||
* placeholder: 'select an option',
|
||||
* max_values: 2,
|
||||
* });
|
||||
* ```
|
||||
* @example
|
||||
* Creating a select menu using setters and API data
|
||||
* ```ts
|
||||
* const selectMenu = new MentionableSelectMenuBuilder({
|
||||
* custom_id: 'a cool select menu',
|
||||
* })
|
||||
* .setMinValues(1)
|
||||
* ```
|
||||
*/
|
||||
public constructor(data?: Partial<APIMentionableSelectComponent>) {
|
||||
super({ ...data, type: ComponentType.MentionableSelect });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import type { APIRoleSelectComponent } from 'discord-api-types/v10';
|
||||
import { ComponentType } from 'discord-api-types/v10';
|
||||
import { BaseSelectMenuBuilder } from './BaseSelectMenu.js';
|
||||
|
||||
export class RoleSelectMenuBuilder extends BaseSelectMenuBuilder<APIRoleSelectComponent> {
|
||||
/**
|
||||
* Creates a new select menu from API data
|
||||
*
|
||||
* @param data - The API data to create this select menu with
|
||||
* @example
|
||||
* Creating a select menu from an API data object
|
||||
* ```ts
|
||||
* const selectMenu = new RoleSelectMenuBuilder({
|
||||
* custom_id: 'a cool select menu',
|
||||
* placeholder: 'select an option',
|
||||
* max_values: 2,
|
||||
* });
|
||||
* ```
|
||||
* @example
|
||||
* Creating a select menu using setters and API data
|
||||
* ```ts
|
||||
* const selectMenu = new RoleSelectMenuBuilder({
|
||||
* custom_id: 'a cool select menu',
|
||||
* })
|
||||
* .setMinValues(1)
|
||||
* ```
|
||||
*/
|
||||
public constructor(data?: Partial<APIRoleSelectComponent>) {
|
||||
super({ ...data, type: ComponentType.RoleSelect });
|
||||
}
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
import { ComponentType, type APISelectMenuComponent, type APISelectMenuOption } from 'discord-api-types/v10';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
|
||||
import {
|
||||
customIdValidator,
|
||||
disabledValidator,
|
||||
jsonOptionValidator,
|
||||
minMaxValidator,
|
||||
optionsLengthValidator,
|
||||
placeholderValidator,
|
||||
validateRequiredSelectMenuParameters,
|
||||
} from '../Assertions.js';
|
||||
import { ComponentBuilder } from '../Component.js';
|
||||
import { SelectMenuOptionBuilder } from './SelectMenuOption.js';
|
||||
|
||||
/**
|
||||
* Represents a select menu component
|
||||
*/
|
||||
export class SelectMenuBuilder extends ComponentBuilder<APISelectMenuComponent> {
|
||||
/**
|
||||
* The options within this select menu
|
||||
*/
|
||||
public readonly options: SelectMenuOptionBuilder[];
|
||||
|
||||
/**
|
||||
* Creates a new select menu from API data
|
||||
*
|
||||
* @param data - The API data to create this select menu with
|
||||
* @example
|
||||
* Creating a select menu from an API data object
|
||||
* ```ts
|
||||
* const selectMenu = new SelectMenuBuilder({
|
||||
* custom_id: 'a cool select menu',
|
||||
* placeholder: 'select an option',
|
||||
* max_values: 2,
|
||||
* options: [
|
||||
* { label: 'option 1', value: '1' },
|
||||
* { label: 'option 2', value: '2' },
|
||||
* { label: 'option 3', value: '3' },
|
||||
* ],
|
||||
* });
|
||||
* ```
|
||||
* @example
|
||||
* Creating a select menu using setters and API data
|
||||
* ```ts
|
||||
* const selectMenu = new SelectMenuBuilder({
|
||||
* custom_id: 'a cool select menu',
|
||||
* })
|
||||
* .setMinValues(1)
|
||||
* .addOptions({
|
||||
* label: 'Catchy',
|
||||
* value: 'catch',
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
public constructor(data?: Partial<APISelectMenuComponent>) {
|
||||
const { options, ...initData } = data ?? {};
|
||||
super({ type: ComponentType.SelectMenu, ...initData });
|
||||
this.options = options?.map((option) => new SelectMenuOptionBuilder(option)) ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the placeholder for this select menu
|
||||
*
|
||||
* @param placeholder - The placeholder to use for this select menu
|
||||
*/
|
||||
public setPlaceholder(placeholder: string) {
|
||||
this.data.placeholder = placeholderValidator.parse(placeholder);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum values that must be selected in the select menu
|
||||
*
|
||||
* @param minValues - The minimum values that must be selected
|
||||
*/
|
||||
public setMinValues(minValues: number) {
|
||||
this.data.min_values = minMaxValidator.parse(minValues);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum values that must be selected in the select menu
|
||||
*
|
||||
* @param maxValues - The maximum values that must be selected
|
||||
*/
|
||||
public setMaxValues(maxValues: number) {
|
||||
this.data.max_values = minMaxValidator.parse(maxValues);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the custom id for this select menu
|
||||
*
|
||||
* @param customId - The custom id to use for this select menu
|
||||
*/
|
||||
public setCustomId(customId: string) {
|
||||
this.data.custom_id = customIdValidator.parse(customId);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this select menu is disabled
|
||||
*
|
||||
* @param disabled - Whether this select menu is disabled
|
||||
*/
|
||||
public setDisabled(disabled = true) {
|
||||
this.data.disabled = disabledValidator.parse(disabled);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds options to this select menu
|
||||
*
|
||||
* @param options - The options to add to this select menu
|
||||
* @returns
|
||||
*/
|
||||
public addOptions(...options: RestOrArray<APISelectMenuOption | SelectMenuOptionBuilder>) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
options = normalizeArray(options);
|
||||
optionsLengthValidator.parse(this.options.length + options.length);
|
||||
this.options.push(
|
||||
...options.map((option) =>
|
||||
option instanceof SelectMenuOptionBuilder
|
||||
? option
|
||||
: new SelectMenuOptionBuilder(jsonOptionValidator.parse(option)),
|
||||
),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the options on this select menu
|
||||
*
|
||||
* @param options - The options to set on this select menu
|
||||
*/
|
||||
public setOptions(...options: RestOrArray<APISelectMenuOption | SelectMenuOptionBuilder>) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
options = normalizeArray(options);
|
||||
optionsLengthValidator.parse(options.length);
|
||||
this.options.splice(
|
||||
0,
|
||||
this.options.length,
|
||||
...options.map((option) =>
|
||||
option instanceof SelectMenuOptionBuilder
|
||||
? option
|
||||
: new SelectMenuOptionBuilder(jsonOptionValidator.parse(option)),
|
||||
),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc ComponentBuilder.toJSON}
|
||||
*/
|
||||
public toJSON(): APISelectMenuComponent {
|
||||
validateRequiredSelectMenuParameters(this.options, this.data.custom_id);
|
||||
|
||||
return {
|
||||
...this.data,
|
||||
options: this.options.map((option) => option.toJSON()),
|
||||
} as APISelectMenuComponent;
|
||||
}
|
||||
}
|
||||
106
packages/builders/src/components/selectMenu/StringSelectMenu.ts
Normal file
106
packages/builders/src/components/selectMenu/StringSelectMenu.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import type { APIStringSelectComponent } from 'discord-api-types/v10';
|
||||
import { ComponentType, type APISelectMenuOption } from 'discord-api-types/v10';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
|
||||
import { jsonOptionValidator, optionsLengthValidator, validateRequiredSelectMenuParameters } from '../Assertions.js';
|
||||
import { BaseSelectMenuBuilder } from './BaseSelectMenu.js';
|
||||
import { StringSelectMenuOptionBuilder } from './StringSelectMenuOption.js';
|
||||
|
||||
/**
|
||||
* Represents a string select menu component
|
||||
*/
|
||||
export class StringSelectMenuBuilder extends BaseSelectMenuBuilder<APIStringSelectComponent> {
|
||||
/**
|
||||
* The options within this select menu
|
||||
*/
|
||||
public readonly options: StringSelectMenuOptionBuilder[];
|
||||
|
||||
/**
|
||||
* Creates a new select menu from API data
|
||||
*
|
||||
* @param data - The API data to create this select menu with
|
||||
* @example
|
||||
* Creating a select menu from an API data object
|
||||
* ```ts
|
||||
* const selectMenu = new StringSelectMenuBuilder({
|
||||
* custom_id: 'a cool select menu',
|
||||
* placeholder: 'select an option',
|
||||
* max_values: 2,
|
||||
* options: [
|
||||
* { label: 'option 1', value: '1' },
|
||||
* { label: 'option 2', value: '2' },
|
||||
* { label: 'option 3', value: '3' },
|
||||
* ],
|
||||
* });
|
||||
* ```
|
||||
* @example
|
||||
* Creating a select menu using setters and API data
|
||||
* ```ts
|
||||
* const selectMenu = new StringSelectMenuBuilder({
|
||||
* custom_id: 'a cool select menu',
|
||||
* })
|
||||
* .setMinValues(1)
|
||||
* .addOptions({
|
||||
* label: 'Catchy',
|
||||
* value: 'catch',
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
public constructor(data?: Partial<APIStringSelectComponent>) {
|
||||
const { options, ...initData } = data ?? {};
|
||||
super({ ...initData, type: ComponentType.StringSelect });
|
||||
this.options = options?.map((option: APISelectMenuOption) => new StringSelectMenuOptionBuilder(option)) ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds options to this select menu
|
||||
*
|
||||
* @param options - The options to add to this select menu
|
||||
* @returns
|
||||
*/
|
||||
public addOptions(...options: RestOrArray<APISelectMenuOption | StringSelectMenuOptionBuilder>) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
options = normalizeArray(options);
|
||||
optionsLengthValidator.parse(this.options.length + options.length);
|
||||
this.options.push(
|
||||
...options.map((option) =>
|
||||
option instanceof StringSelectMenuOptionBuilder
|
||||
? option
|
||||
: new StringSelectMenuOptionBuilder(jsonOptionValidator.parse(option)),
|
||||
),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the options on this select menu
|
||||
*
|
||||
* @param options - The options to set on this select menu
|
||||
*/
|
||||
public setOptions(...options: RestOrArray<APISelectMenuOption | StringSelectMenuOptionBuilder>) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
options = normalizeArray(options);
|
||||
optionsLengthValidator.parse(options.length);
|
||||
this.options.splice(
|
||||
0,
|
||||
this.options.length,
|
||||
...options.map((option) =>
|
||||
option instanceof StringSelectMenuOptionBuilder
|
||||
? option
|
||||
: new StringSelectMenuOptionBuilder(jsonOptionValidator.parse(option)),
|
||||
),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc ComponentBuilder.toJSON}
|
||||
*/
|
||||
public override toJSON(): APIStringSelectComponent {
|
||||
validateRequiredSelectMenuParameters(this.options, this.data.custom_id);
|
||||
|
||||
return {
|
||||
...this.data,
|
||||
options: this.options.map((option) => option.toJSON()),
|
||||
} as APIStringSelectComponent;
|
||||
}
|
||||
}
|
||||
@@ -8,15 +8,15 @@ import {
|
||||
} from '../Assertions.js';
|
||||
|
||||
/**
|
||||
* Represents a option within a select menu component
|
||||
* Represents an option within a string select menu component
|
||||
*/
|
||||
export class SelectMenuOptionBuilder implements JSONEncodable<APISelectMenuOption> {
|
||||
export class StringSelectMenuOptionBuilder implements JSONEncodable<APISelectMenuOption> {
|
||||
/**
|
||||
* Creates a new select menu option from API data
|
||||
* Creates a new string select menu option from API data
|
||||
*
|
||||
* @param data - The API data to create this select menu option with
|
||||
* @param data - The API data to create this string select menu option with
|
||||
* @example
|
||||
* Creating a select menu option from an API data object
|
||||
* Creating a string select menu option from an API data object
|
||||
* ```ts
|
||||
* const selectMenuOption = new SelectMenuOptionBuilder({
|
||||
* label: 'catchy label',
|
||||
@@ -24,7 +24,7 @@ export class SelectMenuOptionBuilder implements JSONEncodable<APISelectMenuOptio
|
||||
* });
|
||||
* ```
|
||||
* @example
|
||||
* Creating a select menu option using setters and API data
|
||||
* Creating a string select menu option using setters and API data
|
||||
* ```ts
|
||||
* const selectMenuOption = new SelectMenuOptionBuilder({
|
||||
* default: true,
|
||||
@@ -0,0 +1,31 @@
|
||||
import type { APIUserSelectComponent } from 'discord-api-types/v10';
|
||||
import { ComponentType } from 'discord-api-types/v10';
|
||||
import { BaseSelectMenuBuilder } from './BaseSelectMenu.js';
|
||||
|
||||
export class UserSelectMenuBuilder extends BaseSelectMenuBuilder<APIUserSelectComponent> {
|
||||
/**
|
||||
* Creates a new select menu from API data
|
||||
*
|
||||
* @param data - The API data to create this select menu with
|
||||
* @example
|
||||
* Creating a select menu from an API data object
|
||||
* ```ts
|
||||
* const selectMenu = new UserSelectMenuBuilder({
|
||||
* custom_id: 'a cool select menu',
|
||||
* placeholder: 'select an option',
|
||||
* max_values: 2,
|
||||
* });
|
||||
* ```
|
||||
* @example
|
||||
* Creating a select menu using setters and API data
|
||||
* ```ts
|
||||
* const selectMenu = new UserSelectMenuBuilder({
|
||||
* custom_id: 'a cool select menu',
|
||||
* })
|
||||
* .setMinValues(1)
|
||||
* ```
|
||||
*/
|
||||
public constructor(data?: Partial<APIUserSelectComponent>) {
|
||||
super({ ...data, type: ComponentType.UserSelect });
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,27 @@ export * from './components/textInput/TextInput.js';
|
||||
export * as TextInputAssertions from './components/textInput/Assertions.js';
|
||||
export * from './interactions/modals/Modal.js';
|
||||
export * as ModalAssertions from './interactions/modals/Assertions.js';
|
||||
export * from './components/selectMenu/SelectMenu.js';
|
||||
export * from './components/selectMenu/SelectMenuOption.js';
|
||||
|
||||
export * from './components/selectMenu/BaseSelectMenu.js';
|
||||
export * from './components/selectMenu/ChannelSelectMenu.js';
|
||||
export * from './components/selectMenu/MentionableSelectMenu.js';
|
||||
export * from './components/selectMenu/RoleSelectMenu.js';
|
||||
export * from './components/selectMenu/StringSelectMenu.js';
|
||||
// TODO: Remove those aliases in v2
|
||||
export {
|
||||
/**
|
||||
* @deprecated Will be removed in the next major version, use {@link StringSelectMenuBuilder} instead.
|
||||
*/
|
||||
StringSelectMenuBuilder as SelectMenuBuilder,
|
||||
} from './components/selectMenu/StringSelectMenu.js';
|
||||
export {
|
||||
/**
|
||||
* @deprecated Will be removed in the next major version, use {@link StringSelectMenuOptionBuilder} instead.
|
||||
*/
|
||||
StringSelectMenuOptionBuilder as SelectMenuOptionBuilder,
|
||||
} from './components/selectMenu/StringSelectMenuOption.js';
|
||||
export * from './components/selectMenu/StringSelectMenuOption.js';
|
||||
export * from './components/selectMenu/UserSelectMenu.js';
|
||||
|
||||
export * as SlashCommandAssertions from './interactions/slashCommands/Assertions.js';
|
||||
export * from './interactions/slashCommands/SlashCommandBuilder.js';
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
"@discordjs/util": "workspace:^",
|
||||
"@sapphire/snowflake": "^3.2.2",
|
||||
"@types/ws": "^8.5.3",
|
||||
"discord-api-types": "^0.37.14",
|
||||
"discord-api-types": "^0.37.15",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"lodash.snakecase": "^4.1.1",
|
||||
"tslib": "^2.4.0",
|
||||
|
||||
@@ -4,11 +4,15 @@ const { InteractionType, ComponentType, ApplicationCommandType } = require('disc
|
||||
const Action = require('./Action');
|
||||
const AutocompleteInteraction = require('../../structures/AutocompleteInteraction');
|
||||
const ButtonInteraction = require('../../structures/ButtonInteraction');
|
||||
const ChannelSelectMenuInteraction = require('../../structures/ChannelSelectMenuInteraction');
|
||||
const ChatInputCommandInteraction = require('../../structures/ChatInputCommandInteraction');
|
||||
const MentionableSelectMenuInteraction = require('../../structures/MentionableSelectMenuInteraction');
|
||||
const MessageContextMenuCommandInteraction = require('../../structures/MessageContextMenuCommandInteraction');
|
||||
const ModalSubmitInteraction = require('../../structures/ModalSubmitInteraction');
|
||||
const SelectMenuInteraction = require('../../structures/SelectMenuInteraction');
|
||||
const RoleSelectMenuInteraction = require('../../structures/RoleSelectMenuInteraction');
|
||||
const StringSelectMenuInteraction = require('../../structures/StringSelectMenuInteraction');
|
||||
const UserContextMenuCommandInteraction = require('../../structures/UserContextMenuCommandInteraction');
|
||||
const UserSelectMenuInteraction = require('../../structures/UserSelectMenuInteraction');
|
||||
const Events = require('../../util/Events');
|
||||
|
||||
class InteractionCreateAction extends Action {
|
||||
@@ -49,8 +53,20 @@ class InteractionCreateAction extends Action {
|
||||
case ComponentType.Button:
|
||||
InteractionClass = ButtonInteraction;
|
||||
break;
|
||||
case ComponentType.SelectMenu:
|
||||
InteractionClass = SelectMenuInteraction;
|
||||
case ComponentType.StringSelect:
|
||||
InteractionClass = StringSelectMenuInteraction;
|
||||
break;
|
||||
case ComponentType.UserSelect:
|
||||
InteractionClass = UserSelectMenuInteraction;
|
||||
break;
|
||||
case ComponentType.RoleSelect:
|
||||
InteractionClass = RoleSelectMenuInteraction;
|
||||
break;
|
||||
case ComponentType.MentionableSelect:
|
||||
InteractionClass = MentionableSelectMenuInteraction;
|
||||
break;
|
||||
case ComponentType.ChannelSelect:
|
||||
InteractionClass = ChannelSelectMenuInteraction;
|
||||
break;
|
||||
default:
|
||||
client.emit(
|
||||
|
||||
@@ -154,9 +154,27 @@ exports.ReactionEmoji = require('./structures/ReactionEmoji');
|
||||
exports.RichPresenceAssets = require('./structures/Presence').RichPresenceAssets;
|
||||
exports.Role = require('./structures/Role').Role;
|
||||
exports.SelectMenuBuilder = require('./structures/SelectMenuBuilder');
|
||||
exports.ChannelSelectMenuBuilder = require('./structures/ChannelSelectMenuBuilder');
|
||||
exports.MentionableSelectMenuBuilder = require('./structures/MentionableSelectMenuBuilder');
|
||||
exports.RoleSelectMenuBuilder = require('./structures/RoleSelectMenuBuilder');
|
||||
exports.StringSelectMenuBuilder = require('./structures/StringSelectMenuBuilder');
|
||||
exports.UserSelectMenuBuilder = require('./structures/UserSelectMenuBuilder');
|
||||
exports.BaseSelectMenuComponent = require('./structures/BaseSelectMenuComponent');
|
||||
exports.SelectMenuComponent = require('./structures/SelectMenuComponent');
|
||||
exports.ChannelSelectMenuComponent = require('./structures/ChannelSelectMenuComponent');
|
||||
exports.MentionableSelectMenuComponent = require('./structures/MentionableSelectMenuComponent');
|
||||
exports.RoleSelectMenuComponent = require('./structures/RoleSelectMenuComponent');
|
||||
exports.StringSelectMenuComponent = require('./structures/StringSelectMenuComponent');
|
||||
exports.UserSelectMenuComponent = require('./structures/UserSelectMenuComponent');
|
||||
exports.SelectMenuInteraction = require('./structures/SelectMenuInteraction');
|
||||
exports.ChannelSelectMenuInteraction = require('./structures/ChannelSelectMenuInteraction');
|
||||
exports.MentionableSelectMenuInteraction = require('./structures/MentionableSelectMenuInteraction');
|
||||
exports.MentionableSelectMenuInteraction = require('./structures/MentionableSelectMenuInteraction');
|
||||
exports.RoleSelectMenuInteraction = require('./structures/RoleSelectMenuInteraction');
|
||||
exports.StringSelectMenuInteraction = require('./structures/StringSelectMenuInteraction');
|
||||
exports.UserSelectMenuInteraction = require('./structures/UserSelectMenuInteraction');
|
||||
exports.SelectMenuOptionBuilder = require('./structures/SelectMenuOptionBuilder');
|
||||
exports.StringSelectMenuOptionBuilder = require('./structures/StringSelectMenuOptionBuilder');
|
||||
exports.StageChannel = require('./structures/StageChannel');
|
||||
exports.StageInstance = require('./structures/StageInstance').StageInstance;
|
||||
exports.Sticker = require('./structures/Sticker').Sticker;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
const { deprecate } = require('node:util');
|
||||
const { DiscordSnowflake } = require('@sapphire/snowflake');
|
||||
const { InteractionType, ApplicationCommandType, ComponentType } = require('discord-api-types/v10');
|
||||
const Base = require('./Base');
|
||||
const { SelectMenuTypes } = require('../util/Constants');
|
||||
const PermissionsBitField = require('../util/PermissionsBitField');
|
||||
|
||||
/**
|
||||
@@ -268,12 +270,63 @@ class BaseInteraction extends Base {
|
||||
return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.Button;
|
||||
}
|
||||
|
||||
// TODO: Get rid of this in the next major
|
||||
/**
|
||||
* Indicates whether this interaction is a {@link SelectMenuInteraction}.
|
||||
* Indicates whether this interaction is a {@link StringSelectMenuInteraction}.
|
||||
* @returns {boolean}
|
||||
*
|
||||
* @deprecated Use {@link Interaction#isStringSelectMenu} instead
|
||||
*/
|
||||
isSelectMenu() {
|
||||
return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.SelectMenu;
|
||||
return this.isStringSelectMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this interaction is a select menu of any known type.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isAnySelectMenu() {
|
||||
return this.type === InteractionType.MessageComponent && SelectMenuTypes.includes(this.componentType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this interaction is a {@link StringSelectMenuInteraction}.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isStringSelectMenu() {
|
||||
return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.StringSelect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this interaction is a {@link UserSelectMenuInteraction}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isUserSelectMenu() {
|
||||
return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.UserSelect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this interaction is a {@link RoleSelectMenuInteraction}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isRoleSelectMenu() {
|
||||
return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.RoleSelect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this interaction is a {@link ChannelSelectMenuInteraction}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isChannelSelectMenu() {
|
||||
return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.ChannelSelect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this interaction is a {@link MenionableSelectMenuInteraction}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isMentionableSelectMenu() {
|
||||
return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.MentionableSelect;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,4 +338,9 @@ class BaseInteraction extends Base {
|
||||
}
|
||||
}
|
||||
|
||||
BaseInteraction.prototype.isSelectMenu = deprecate(
|
||||
BaseInteraction.prototype.isSelectMenu,
|
||||
'BaseInteraction#isSelectMenu() is deprecated. Use BaseInteraction#isStringSelectMenu() instead.',
|
||||
);
|
||||
|
||||
module.exports = BaseInteraction;
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
'use strict';
|
||||
|
||||
const Component = require('./Component');
|
||||
|
||||
/**
|
||||
* Represents a select menu component
|
||||
* @extends {Component}
|
||||
*/
|
||||
class BaseSelectMenuComponent extends Component {
|
||||
/**
|
||||
* The placeholder for this select menu
|
||||
* @type {?string}
|
||||
* @readonly
|
||||
*/
|
||||
get placeholder() {
|
||||
return this.data.placeholder ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum amount of options that can be selected
|
||||
* @type {?number}
|
||||
* @readonly
|
||||
*/
|
||||
get maxValues() {
|
||||
return this.data.max_values ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The minimum amount of options that must be selected
|
||||
* @type {?number}
|
||||
* @readonly
|
||||
*/
|
||||
get minValues() {
|
||||
return this.data.min_values ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The custom id of this select menu
|
||||
* @type {string}
|
||||
* @readonly
|
||||
*/
|
||||
get customId() {
|
||||
return this.data.custom_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this select menu is disabled
|
||||
* @type {?boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get disabled() {
|
||||
return this.data.disabled ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BaseSelectMenuComponent;
|
||||
@@ -0,0 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
const { ChannelSelectMenuBuilder: BuildersChannelSelectMenu, isJSONEncodable } = require('@discordjs/builders');
|
||||
const { toSnakeCase } = require('../util/Transformers');
|
||||
|
||||
/**
|
||||
* Class used to build select menu components to be sent through the API
|
||||
* @extends {BuildersChannelSelectMenu}
|
||||
*/
|
||||
class ChannelSelectMenuBuilder extends BuildersChannelSelectMenu {
|
||||
constructor(data = {}) {
|
||||
super(toSnakeCase(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new select menu builder from json data
|
||||
* @param {JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent} other The other data
|
||||
* @returns {ChannelSelectMenuBuilder}
|
||||
*/
|
||||
static from(other) {
|
||||
if (isJSONEncodable(other)) {
|
||||
return new this(other.toJSON());
|
||||
}
|
||||
return new this(other);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ChannelSelectMenuBuilder;
|
||||
|
||||
/**
|
||||
* @external BuildersChannelSelectMenu
|
||||
* @see {@link https://discord.js.org/#/docs/builders/main/class/ChannelSelectMenuBuilder}
|
||||
*/
|
||||
@@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
const BaseSelectMenuComponent = require('./BaseSelectMenuComponent');
|
||||
|
||||
/**
|
||||
* Represents a channel select menu component
|
||||
* @extends {BaseSelectMenuComponent}
|
||||
*/
|
||||
class ChannelSelectMenuComponent extends BaseSelectMenuComponent {
|
||||
/**
|
||||
* The options in this select menu
|
||||
* @type {?(ChannelType[])}
|
||||
* @readonly
|
||||
*/
|
||||
get channelTypes() {
|
||||
return this.data.channel_types ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ChannelSelectMenuComponent;
|
||||
@@ -0,0 +1,25 @@
|
||||
'use strict';
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const MessageComponentInteraction = require('./MessageComponentInteraction');
|
||||
|
||||
/**
|
||||
* Represents a {@link ComponentType.ChannelSelect} select menu interaction.
|
||||
* @extends {MessageComponentInteraction}
|
||||
*/
|
||||
class ChannelSelectMenuInteraction extends MessageComponentInteraction {
|
||||
constructor(client, data) {
|
||||
super(client, data);
|
||||
|
||||
/**
|
||||
* Collection of the selected channels
|
||||
* @type {Collection<Snowflake, Channel|APIChannel>}
|
||||
*/
|
||||
this.channels = new Collection();
|
||||
for (const channel of Object.values(data.data.resolved.channels)) {
|
||||
this.channels.set(channel.id, this.client.channels._add(channel, this.guild) ?? channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ChannelSelectMenuInteraction;
|
||||
@@ -147,10 +147,17 @@ class InteractionCollector extends Collector {
|
||||
* @event InteractionCollector#collect
|
||||
* @param {BaseInteraction} interaction The interaction that was collected
|
||||
*/
|
||||
|
||||
if (this.interactionType && interaction.type !== this.interactionType) return null;
|
||||
if (this.componentType && interaction.componentType !== this.componentType) return null;
|
||||
if (this.messageId && interaction.message?.id !== this.messageId) return null;
|
||||
if (this.messageInteractionId && interaction.message?.interaction?.id !== this.messageInteractionId) return null;
|
||||
if (
|
||||
this.messageInteractionId &&
|
||||
interaction.message?.interaction?.id &&
|
||||
interaction.message.interaction.id !== this.messageInteractionId
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
if (this.channelId && interaction.channelId !== this.channelId) return null;
|
||||
if (this.guildId && interaction.guildId !== this.guildId) return null;
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
const { MentionableSelectMenuBuilder: BuildersMentionableSelectMenu, isJSONEncodable } = require('@discordjs/builders');
|
||||
const { toSnakeCase } = require('../util/Transformers');
|
||||
|
||||
/**
|
||||
* Class used to build select menu components to be sent through the API
|
||||
* @extends {BuildersMentionableSelectMenu}
|
||||
*/
|
||||
class MentionableSelectMenuBuilder extends BuildersMentionableSelectMenu {
|
||||
constructor(data = {}) {
|
||||
super(toSnakeCase(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new select menu builder from json data
|
||||
* @param {JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent} other The other data
|
||||
* @returns {MentionableSelectMenuBuilder}
|
||||
*/
|
||||
static from(other) {
|
||||
if (isJSONEncodable(other)) {
|
||||
return new this(other.toJSON());
|
||||
}
|
||||
return new this(other);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MentionableSelectMenuBuilder;
|
||||
|
||||
/**
|
||||
* @external BuildersMentionableSelectMenu
|
||||
* @see {@link https://discord.js.org/#/docs/builders/main/class/MentionableSelectMenuBuilder}
|
||||
*/
|
||||
@@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
const BaseSelectMenuComponent = require('./BaseSelectMenuComponent');
|
||||
|
||||
/**
|
||||
* Represents a mentionable select menu component
|
||||
* @extends {BaseSelectMenuComponent}
|
||||
*/
|
||||
class MentionableSelectMenuComponent extends BaseSelectMenuComponent {}
|
||||
|
||||
module.exports = MentionableSelectMenuComponent;
|
||||
@@ -0,0 +1,65 @@
|
||||
'use strict';
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const MessageComponentInteraction = require('./MessageComponentInteraction');
|
||||
const Events = require('../util/Events');
|
||||
|
||||
/**
|
||||
* Represents a {@link ComponentType.MentionableSelect} select menu interaction.
|
||||
* @extends {MessageComponentInteraction}
|
||||
*/
|
||||
class MentionableSelectMenuInteraction extends MessageComponentInteraction {
|
||||
constructor(client, data) {
|
||||
super(client, data);
|
||||
|
||||
const { members, users, roles } = data.data.resolved ?? {};
|
||||
|
||||
/**
|
||||
* Collection of the selected users
|
||||
* @type {Collection<Snowflake, User>}
|
||||
*/
|
||||
this.users = new Collection();
|
||||
|
||||
/**
|
||||
* Collection of the selected users
|
||||
* @type {Collection<Snowflake, GuildMember|APIGuildMember>}
|
||||
*/
|
||||
this.members = new Collection();
|
||||
|
||||
/**
|
||||
* Collection of the selected roles
|
||||
* @type {Collection<Snowflake, Role|APIRole>}
|
||||
*/
|
||||
this.roles = new Collection();
|
||||
|
||||
if (members) {
|
||||
for (const [id, member] of Object.entries(members)) {
|
||||
const user = users[id];
|
||||
if (!user) {
|
||||
this.client.emit(
|
||||
Events.Debug,
|
||||
`[MentionableSelectMenuInteraction] Received a member without a user, skipping ${id}`,
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.members.set(id, this.guild?.members._add({ user, ...member }) ?? { user, ...member });
|
||||
}
|
||||
}
|
||||
|
||||
if (users) {
|
||||
for (const user of Object.values(users)) {
|
||||
this.users.set(user.id, this.client.users._add(user));
|
||||
}
|
||||
}
|
||||
|
||||
if (roles) {
|
||||
for (const role of Object.values(roles)) {
|
||||
this.roles.set(role.id, this.guild?.roles._add(role) ?? role);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MentionableSelectMenuInteraction;
|
||||
33
packages/discord.js/src/structures/RoleSelectMenuBuilder.js
Normal file
33
packages/discord.js/src/structures/RoleSelectMenuBuilder.js
Normal file
@@ -0,0 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
const { RoleSelectMenuBuilder: BuildersRoleSelectMenu, isJSONEncodable } = require('@discordjs/builders');
|
||||
const { toSnakeCase } = require('../util/Transformers');
|
||||
|
||||
/**
|
||||
* Class used to build select menu components to be sent through the API
|
||||
* @extends {BuildersRoleSelectMenu}
|
||||
*/
|
||||
class RoleSelectMenuBuilder extends BuildersRoleSelectMenu {
|
||||
constructor(data = {}) {
|
||||
super(toSnakeCase(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new select menu builder from json data
|
||||
* @param {JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent} other The other data
|
||||
* @returns {RoleSelectMenuBuilder}
|
||||
*/
|
||||
static from(other) {
|
||||
if (isJSONEncodable(other)) {
|
||||
return new this(other.toJSON());
|
||||
}
|
||||
return new this(other);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RoleSelectMenuBuilder;
|
||||
|
||||
/**
|
||||
* @external BuildersRoleSelectMenu
|
||||
* @see {@link https://discord.js.org/#/docs/builders/main/class/RoleSelectMenuBuilder}
|
||||
*/
|
||||
@@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
const BaseSelectMenuComponent = require('./BaseSelectMenuComponent');
|
||||
|
||||
/**
|
||||
* Represents a role select menu component
|
||||
* @extends {BaseSelectMenuComponent}
|
||||
*/
|
||||
class RoleSelectMenuComponent extends BaseSelectMenuComponent {}
|
||||
|
||||
module.exports = RoleSelectMenuComponent;
|
||||
@@ -0,0 +1,25 @@
|
||||
'use strict';
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const MessageComponentInteraction = require('./MessageComponentInteraction');
|
||||
|
||||
/**
|
||||
* Represents a {@link ComponentType.RoleSelect} select menu interaction.
|
||||
* @extends {MessageComponentInteraction}
|
||||
*/
|
||||
class RoleSelectMenuInteraction extends MessageComponentInteraction {
|
||||
constructor(client, data) {
|
||||
super(client, data);
|
||||
|
||||
/**
|
||||
* Collection of the selected roles
|
||||
* @type {Collection<Snowflake, Role|APIRole>}
|
||||
*/
|
||||
this.roles = new Collection();
|
||||
for (const role of Object.values(data.data.resolved.roles)) {
|
||||
this.roles.set(role.id, this.guild?.roles._add(role) ?? role);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RoleSelectMenuInteraction;
|
||||
@@ -1,78 +1,25 @@
|
||||
'use strict';
|
||||
|
||||
const { SelectMenuBuilder: BuildersSelectMenu, isJSONEncodable, normalizeArray } = require('@discordjs/builders');
|
||||
const { toSnakeCase } = require('../util/Transformers');
|
||||
const { resolvePartialEmoji } = require('../util/Util');
|
||||
const process = require('node:process');
|
||||
const StringSelectMenuBuilder = require('./StringSelectMenuBuilder');
|
||||
|
||||
let deprecationEmitted = false;
|
||||
|
||||
/**
|
||||
* Class used to build select menu components to be sent through the API
|
||||
* @extends {BuildersSelectMenu}
|
||||
* @deprecated Use {@link StringSelectMenuBuilder} instead.
|
||||
*/
|
||||
class SelectMenuBuilder extends BuildersSelectMenu {
|
||||
constructor({ options, ...data } = {}) {
|
||||
super(
|
||||
toSnakeCase({
|
||||
...data,
|
||||
options: options?.map(({ emoji, ...option }) => ({
|
||||
...option,
|
||||
emoji: emoji && typeof emoji === 'string' ? resolvePartialEmoji(emoji) : emoji,
|
||||
})),
|
||||
}),
|
||||
class SelectMenuBuilder extends StringSelectMenuBuilder {
|
||||
constructor(...params) {
|
||||
super(...params);
|
||||
|
||||
if (!deprecationEmitted) {
|
||||
process.emitWarning(
|
||||
'The SelectMenuBuilder class is deprecated, use StringSelectMenuBuilder instead.',
|
||||
'DeprecationWarning',
|
||||
);
|
||||
deprecationEmitted = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a select menu option emoji
|
||||
* @param {SelectMenuOptionData|JSONEncodable<APISelectMenuOption>} selectMenuOption The option to normalize
|
||||
* @returns {Array<SelectMenuOptionBuilder|APISelectMenuOption>}
|
||||
* @private
|
||||
*/
|
||||
static normalizeEmoji(selectMenuOption) {
|
||||
if (isJSONEncodable(selectMenuOption)) {
|
||||
return selectMenuOption;
|
||||
}
|
||||
|
||||
const { emoji, ...option } = selectMenuOption;
|
||||
return {
|
||||
...option,
|
||||
emoji: typeof emoji === 'string' ? resolvePartialEmoji(emoji) : emoji,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds options to this select menu
|
||||
* @param {RestOrArray<APISelectMenuOption>} options The options to add to this select menu
|
||||
* @returns {SelectMenuBuilder}
|
||||
*/
|
||||
addOptions(...options) {
|
||||
return super.addOptions(normalizeArray(options).map(option => SelectMenuBuilder.normalizeEmoji(option)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the options on this select menu
|
||||
* @param {RestOrArray<APISelectMenuOption>} options The options to set on this select menu
|
||||
* @returns {SelectMenuBuilder}
|
||||
*/
|
||||
setOptions(...options) {
|
||||
return super.setOptions(normalizeArray(options).map(option => SelectMenuBuilder.normalizeEmoji(option)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new select menu builder from json data
|
||||
* @param {JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent} other The other data
|
||||
* @returns {SelectMenuBuilder}
|
||||
*/
|
||||
static from(other) {
|
||||
if (isJSONEncodable(other)) {
|
||||
return new this(other.toJSON());
|
||||
}
|
||||
return new this(other);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SelectMenuBuilder;
|
||||
|
||||
/**
|
||||
* @external BuildersSelectMenu
|
||||
* @see {@link https://discord.js.org/#/docs/builders/main/class/SelectMenuBuilder}
|
||||
*/
|
||||
|
||||
@@ -1,64 +1,24 @@
|
||||
'use strict';
|
||||
|
||||
const Component = require('./Component');
|
||||
const process = require('node:process');
|
||||
const StringSelectMenuComponent = require('./StringSelectMenuComponent');
|
||||
|
||||
let deprecationEmitted = false;
|
||||
|
||||
/**
|
||||
* Represents a select menu component
|
||||
* @extends {Component}
|
||||
* @deprecated Use {@link StringSelectMenuComponent} instead.
|
||||
*/
|
||||
class SelectMenuComponent extends Component {
|
||||
/**
|
||||
* The placeholder for this select menu
|
||||
* @type {?string}
|
||||
* @readonly
|
||||
*/
|
||||
get placeholder() {
|
||||
return this.data.placeholder ?? null;
|
||||
class SelectMenuComponent extends StringSelectMenuComponent {
|
||||
constructor(...params) {
|
||||
super(...params);
|
||||
|
||||
if (!deprecationEmitted) {
|
||||
process.emitWarning(
|
||||
'The SelectMenuComponent class is deprecated, use StringSelectMenuComponent instead.',
|
||||
'DeprecationWarning',
|
||||
);
|
||||
deprecationEmitted = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum amount of options that can be selected
|
||||
* @type {?number}
|
||||
* @readonly
|
||||
*/
|
||||
get maxValues() {
|
||||
return this.data.max_values ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The minimum amount of options that must be selected
|
||||
* @type {?number}
|
||||
* @readonly
|
||||
*/
|
||||
get minValues() {
|
||||
return this.data.min_values ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The custom id of this select menu
|
||||
* @type {string}
|
||||
* @readonly
|
||||
*/
|
||||
get customId() {
|
||||
return this.data.custom_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this select menu is disabled
|
||||
* @type {?boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get disabled() {
|
||||
return this.data.disabled ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The options in this select menu
|
||||
* @type {APISelectMenuOption[]}
|
||||
* @readonly
|
||||
*/
|
||||
get options() {
|
||||
return this.data.options;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
'use strict';
|
||||
|
||||
const MessageComponentInteraction = require('./MessageComponentInteraction');
|
||||
const process = require('node:process');
|
||||
const StringSelectMenuInteraction = require('./StringSelectMenuInteraction');
|
||||
|
||||
let deprecationEmitted = false;
|
||||
|
||||
/**
|
||||
* Represents a select menu interaction.
|
||||
* @extends {MessageComponentInteraction}
|
||||
* @deprecated Use {@link StringSelectMenuInteraction} instead.
|
||||
*/
|
||||
class SelectMenuInteraction extends MessageComponentInteraction {
|
||||
constructor(client, data) {
|
||||
super(client, data);
|
||||
class SelectMenuInteraction extends StringSelectMenuInteraction {
|
||||
constructor(...params) {
|
||||
super(...params);
|
||||
|
||||
/**
|
||||
* The values selected, if the component which was interacted with was a select menu
|
||||
* @type {string[]}
|
||||
*/
|
||||
this.values = data.data.values ?? [];
|
||||
if (!deprecationEmitted) {
|
||||
process.emitWarning(
|
||||
'The SelectMenuInteraction class is deprecated, use StringSelectMenuInteraction instead.',
|
||||
'DeprecationWarning',
|
||||
);
|
||||
deprecationEmitted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,50 +1,25 @@
|
||||
'use strict';
|
||||
|
||||
const { SelectMenuOptionBuilder: BuildersSelectMenuOption, isJSONEncodable } = require('@discordjs/builders');
|
||||
const { toSnakeCase } = require('../util/Transformers');
|
||||
const { resolvePartialEmoji } = require('../util/Util');
|
||||
const process = require('node:process');
|
||||
const StringSelectMenuOptionBuilder = require('./StringSelectMenuOptionBuilder');
|
||||
|
||||
let deprecationEmitted = false;
|
||||
|
||||
/**
|
||||
* Represents a select menu option builder.
|
||||
* @extends {BuildersSelectMenuOption}
|
||||
* @deprecated Use {@link StringSelectMenuOptionBuilder} instead.
|
||||
*/
|
||||
class SelectMenuOptionBuilder extends BuildersSelectMenuOption {
|
||||
constructor({ emoji, ...data } = {}) {
|
||||
super(
|
||||
toSnakeCase({
|
||||
...data,
|
||||
emoji: emoji && typeof emoji === 'string' ? resolvePartialEmoji(emoji) : emoji,
|
||||
}),
|
||||
class SelectMenuOptionBuilder extends StringSelectMenuOptionBuilder {
|
||||
constructor(...params) {
|
||||
super(...params);
|
||||
|
||||
if (!deprecationEmitted) {
|
||||
process.emitWarning(
|
||||
'The SelectMenuOptionBuilder class is deprecated, use StringSelectMenuOptionBuilder instead.',
|
||||
'DeprecationWarning',
|
||||
);
|
||||
deprecationEmitted = true;
|
||||
}
|
||||
/**
|
||||
* Sets the emoji to display on this option
|
||||
* @param {ComponentEmojiResolvable} emoji The emoji to display on this option
|
||||
* @returns {SelectMenuOptionBuilder}
|
||||
*/
|
||||
setEmoji(emoji) {
|
||||
if (typeof emoji === 'string') {
|
||||
return super.setEmoji(resolvePartialEmoji(emoji));
|
||||
}
|
||||
return super.setEmoji(emoji);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new select menu option builder from JSON data
|
||||
* @param {JSONEncodable<APISelectMenuOption>|APISelectMenuOption} other The other data
|
||||
* @returns {SelectMenuOptionBuilder}
|
||||
*/
|
||||
static from(other) {
|
||||
if (isJSONEncodable(other)) {
|
||||
return new this(other.toJSON());
|
||||
}
|
||||
return new this(other);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SelectMenuOptionBuilder;
|
||||
|
||||
/**
|
||||
* @external BuildersSelectMenuOption
|
||||
* @see {@link https://discord.js.org/#/docs/builders/main/class/SelectMenuOptionBuilder}
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
'use strict';
|
||||
|
||||
const { SelectMenuBuilder: BuildersSelectMenu, isJSONEncodable, normalizeArray } = require('@discordjs/builders');
|
||||
const { toSnakeCase } = require('../util/Transformers');
|
||||
const { resolvePartialEmoji } = require('../util/Util');
|
||||
|
||||
/**
|
||||
* Class used to build select menu components to be sent through the API
|
||||
* @extends {BuildersSelectMenu}
|
||||
*/
|
||||
class StringSelectMenuBuilder extends BuildersSelectMenu {
|
||||
constructor({ options, ...data } = {}) {
|
||||
super(
|
||||
toSnakeCase({
|
||||
...data,
|
||||
options: options?.map(({ emoji, ...option }) => ({
|
||||
...option,
|
||||
emoji: emoji && typeof emoji === 'string' ? resolvePartialEmoji(emoji) : emoji,
|
||||
})),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a select menu option emoji
|
||||
* @param {SelectMenuOptionData|JSONEncodable<APISelectMenuOption>} selectMenuOption The option to normalize
|
||||
* @returns {SelectMenuOptionBuilder|APISelectMenuOption}
|
||||
* @private
|
||||
*/
|
||||
static normalizeEmoji(selectMenuOption) {
|
||||
if (isJSONEncodable(selectMenuOption)) {
|
||||
return selectMenuOption;
|
||||
}
|
||||
|
||||
const { emoji, ...option } = selectMenuOption;
|
||||
return {
|
||||
...option,
|
||||
emoji: typeof emoji === 'string' ? resolvePartialEmoji(emoji) : emoji,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds options to this select menu
|
||||
* @param {RestOrArray<APISelectMenuOption>} options The options to add to this select menu
|
||||
* @returns {StringSelectMenuBuilder}
|
||||
*/
|
||||
addOptions(...options) {
|
||||
return super.addOptions(normalizeArray(options).map(option => StringSelectMenuBuilder.normalizeEmoji(option)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the options on this select menu
|
||||
* @param {RestOrArray<APISelectMenuOption>} options The options to set on this select menu
|
||||
* @returns {StringSelectMenuBuilder}
|
||||
*/
|
||||
setOptions(...options) {
|
||||
return super.setOptions(normalizeArray(options).map(option => StringSelectMenuBuilder.normalizeEmoji(option)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new select menu builder from json data
|
||||
* @param {JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent} other The other data
|
||||
* @returns {StringSelectMenuBuilder}
|
||||
*/
|
||||
static from(other) {
|
||||
if (isJSONEncodable(other)) {
|
||||
return new this(other.toJSON());
|
||||
}
|
||||
return new this(other);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = StringSelectMenuBuilder;
|
||||
|
||||
/**
|
||||
* @external BuildersSelectMenu
|
||||
* @see {@link https://discord.js.org/#/docs/builders/main/class/SelectMenuBuilder}
|
||||
*/
|
||||
@@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
const BaseSelectMenuComponent = require('./BaseSelectMenuComponent');
|
||||
|
||||
/**
|
||||
* Represents a string select menu component
|
||||
* @extends {BaseSelectMenuComponent}
|
||||
*/
|
||||
class StringSelectMenuComponent extends BaseSelectMenuComponent {
|
||||
/**
|
||||
* The options in this select menu
|
||||
* @type {APISelectMenuOption[]}
|
||||
* @readonly
|
||||
*/
|
||||
get options() {
|
||||
return this.data.options;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = StringSelectMenuComponent;
|
||||
@@ -0,0 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
const MessageComponentInteraction = require('./MessageComponentInteraction');
|
||||
|
||||
/**
|
||||
* Represents a {@link ComponentType.StringSelect} select menu interaction.
|
||||
* @extends {MessageComponentInteraction}
|
||||
*/
|
||||
class StringSelectMenuInteraction extends MessageComponentInteraction {
|
||||
constructor(client, data) {
|
||||
super(client, data);
|
||||
|
||||
/**
|
||||
* The values selected
|
||||
* @type {string[]}
|
||||
*/
|
||||
this.values = data.data.values ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = StringSelectMenuInteraction;
|
||||
@@ -0,0 +1,51 @@
|
||||
'use strict';
|
||||
|
||||
const { SelectMenuOptionBuilder: BuildersSelectMenuOption, isJSONEncodable } = require('@discordjs/builders');
|
||||
const { toSnakeCase } = require('../util/Transformers');
|
||||
const { resolvePartialEmoji } = require('../util/Util');
|
||||
|
||||
/**
|
||||
* Represents a select menu option builder.
|
||||
* @extends {BuildersSelectMenuOption}
|
||||
*/
|
||||
class StringSelectMenuOptionBuilder extends BuildersSelectMenuOption {
|
||||
constructor({ emoji, ...data } = {}) {
|
||||
super(
|
||||
toSnakeCase({
|
||||
...data,
|
||||
emoji: emoji && typeof emoji === 'string' ? resolvePartialEmoji(emoji) : emoji,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the emoji to display on this option
|
||||
* @param {ComponentEmojiResolvable} emoji The emoji to display on this option
|
||||
* @returns {StringSelectMenuOptionBuilder}
|
||||
*/
|
||||
setEmoji(emoji) {
|
||||
if (typeof emoji === 'string') {
|
||||
return super.setEmoji(resolvePartialEmoji(emoji));
|
||||
}
|
||||
return super.setEmoji(emoji);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new select menu option builder from JSON data
|
||||
* @param {JSONEncodable<APISelectMenuOption>|APISelectMenuOption} other The other data
|
||||
* @returns {StringSelectMenuOptionBuilder}
|
||||
*/
|
||||
static from(other) {
|
||||
if (isJSONEncodable(other)) {
|
||||
return new this(other.toJSON());
|
||||
}
|
||||
return new this(other);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = StringSelectMenuOptionBuilder;
|
||||
|
||||
/**
|
||||
* @external BuildersSelectMenuOption
|
||||
* @see {@link https://discord.js.org/#/docs/builders/main/class/SelectMenuOptionBuilder}
|
||||
*/
|
||||
33
packages/discord.js/src/structures/UserSelectMenuBuilder.js
Normal file
33
packages/discord.js/src/structures/UserSelectMenuBuilder.js
Normal file
@@ -0,0 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
const { UserSelectMenuBuilder: BuildersUserSelectMenu, isJSONEncodable } = require('@discordjs/builders');
|
||||
const { toSnakeCase } = require('../util/Transformers');
|
||||
|
||||
/**
|
||||
* Class used to build select menu components to be sent through the API
|
||||
* @extends {BuildersUserSelectMenu}
|
||||
*/
|
||||
class UserSelectMenuBuilder extends BuildersUserSelectMenu {
|
||||
constructor(data = {}) {
|
||||
super(toSnakeCase(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new select menu builder from json data
|
||||
* @param {JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent} other The other data
|
||||
* @returns {UserSelectMenuBuilder}
|
||||
*/
|
||||
static from(other) {
|
||||
if (isJSONEncodable(other)) {
|
||||
return new this(other.toJSON());
|
||||
}
|
||||
return new this(other);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UserSelectMenuBuilder;
|
||||
|
||||
/**
|
||||
* @external BuildersUserSelectMenu
|
||||
* @see {@link https://discord.js.org/#/docs/builders/main/class/UserSelectMenuBuilder}
|
||||
*/
|
||||
@@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
const BaseSelectMenuComponent = require('./BaseSelectMenuComponent');
|
||||
|
||||
/**
|
||||
* Represents a user select menu component
|
||||
* @extends {BaseSelectMenuComponent}
|
||||
*/
|
||||
class UserSelectMenuComponent extends BaseSelectMenuComponent {}
|
||||
|
||||
module.exports = UserSelectMenuComponent;
|
||||
@@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const MessageComponentInteraction = require('./MessageComponentInteraction');
|
||||
const Events = require('../util/Events');
|
||||
|
||||
/**
|
||||
* Represents a {@link ComponentType.UserSelect} select menu interaction.
|
||||
* @extends {MessageComponentInteraction}
|
||||
*/
|
||||
class UserSelectMenuInteraction extends MessageComponentInteraction {
|
||||
constructor(client, data) {
|
||||
super(client, data);
|
||||
|
||||
/**
|
||||
* Collection of the selected users
|
||||
* @type {Collection<Snowflake, User>}
|
||||
*/
|
||||
this.users = new Collection();
|
||||
|
||||
/**
|
||||
* Collection of the selected members
|
||||
* @type {Collection<Snowflake, GuildMember|APIGuildMember>}
|
||||
*/
|
||||
this.members = new Collection();
|
||||
|
||||
for (const user of Object.values(data.data.resolved.users)) {
|
||||
this.users.set(user.id, this.client.users._add(user));
|
||||
}
|
||||
|
||||
if (data.data.resolved.members) {
|
||||
for (const [id, member] of Object.entries(data.data.resolved.members)) {
|
||||
const user = data.data.resolved.users[id];
|
||||
if (!user) {
|
||||
this.client.emit(
|
||||
Events.Debug,
|
||||
`[UserSelectMenuInteraction] Received a member without a user, skipping ${id}`,
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.members.set(id, this.guild?.members._add({ user, ...member }) ?? { user, ...member });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UserSelectMenuInteraction;
|
||||
@@ -82,10 +82,18 @@ function createComponent(data) {
|
||||
return new ActionRow(data);
|
||||
case ComponentType.Button:
|
||||
return new ButtonComponent(data);
|
||||
case ComponentType.SelectMenu:
|
||||
return new SelectMenuComponent(data);
|
||||
case ComponentType.StringSelect:
|
||||
return new StringSelectMenuComponent(data);
|
||||
case ComponentType.TextInput:
|
||||
return new TextInputComponent(data);
|
||||
case ComponentType.UserSelect:
|
||||
return new UserSelectMenuComponent(data);
|
||||
case ComponentType.RoleSelect:
|
||||
return new RoleSelectMenuComponent(data);
|
||||
case ComponentType.MentionableSelect:
|
||||
return new MentionableSelectMenuComponent(data);
|
||||
case ComponentType.ChannelSelect:
|
||||
return new ChannelSelectMenuComponent(data);
|
||||
default:
|
||||
return new Component(data);
|
||||
}
|
||||
@@ -106,10 +114,18 @@ function createComponentBuilder(data) {
|
||||
return new ActionRowBuilder(data);
|
||||
case ComponentType.Button:
|
||||
return new ButtonBuilder(data);
|
||||
case ComponentType.SelectMenu:
|
||||
return new SelectMenuBuilder(data);
|
||||
case ComponentType.StringSelect:
|
||||
return new StringSelectMenuBuilder(data);
|
||||
case ComponentType.TextInput:
|
||||
return new TextInputBuilder(data);
|
||||
case ComponentType.UserSelect:
|
||||
return new UserSelectMenuBuilder(data);
|
||||
case ComponentType.RoleSelect:
|
||||
return new RoleSelectMenuBuilder(data);
|
||||
case ComponentType.MentionableSelect:
|
||||
return new MentionableSelectMenuBuilder(data);
|
||||
case ComponentType.ChannelSelect:
|
||||
return new ChannelSelectMenuBuilder(data);
|
||||
default:
|
||||
return new ComponentBuilder(data);
|
||||
}
|
||||
@@ -121,11 +137,19 @@ const ActionRow = require('../structures/ActionRow');
|
||||
const ActionRowBuilder = require('../structures/ActionRowBuilder');
|
||||
const ButtonBuilder = require('../structures/ButtonBuilder');
|
||||
const ButtonComponent = require('../structures/ButtonComponent');
|
||||
const ChannelSelectMenuBuilder = require('../structures/ChannelSelectMenuBuilder');
|
||||
const ChannelSelectMenuComponent = require('../structures/ChannelSelectMenuComponent');
|
||||
const Component = require('../structures/Component');
|
||||
const SelectMenuBuilder = require('../structures/SelectMenuBuilder');
|
||||
const SelectMenuComponent = require('../structures/SelectMenuComponent');
|
||||
const MentionableSelectMenuBuilder = require('../structures/MentionableSelectMenuBuilder');
|
||||
const MentionableSelectMenuComponent = require('../structures/MentionableSelectMenuComponent');
|
||||
const RoleSelectMenuBuilder = require('../structures/RoleSelectMenuBuilder');
|
||||
const RoleSelectMenuComponent = require('../structures/RoleSelectMenuComponent');
|
||||
const StringSelectMenuBuilder = require('../structures/StringSelectMenuBuilder');
|
||||
const StringSelectMenuComponent = require('../structures/StringSelectMenuComponent');
|
||||
const TextInputBuilder = require('../structures/TextInputBuilder');
|
||||
const TextInputComponent = require('../structures/TextInputComponent');
|
||||
const UserSelectMenuBuilder = require('../structures/UserSelectMenuBuilder');
|
||||
const UserSelectMenuComponent = require('../structures/UserSelectMenuComponent');
|
||||
|
||||
/**
|
||||
* @external JSONEncodable
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const { ChannelType, MessageType } = require('discord-api-types/v10');
|
||||
const { ChannelType, MessageType, ComponentType } = require('discord-api-types/v10');
|
||||
|
||||
/**
|
||||
* The name of an item to be swept in Sweepers
|
||||
@@ -113,6 +113,23 @@ exports.ThreadChannelTypes = [ChannelType.AnnouncementThread, ChannelType.Public
|
||||
*/
|
||||
exports.VoiceBasedChannelTypes = [ChannelType.GuildVoice, ChannelType.GuildStageVoice];
|
||||
|
||||
/**
|
||||
* The types of select menus. The available types are:
|
||||
* * {@link ComponentType.StringSelect}
|
||||
* * {@link ComponentType.UserSelect}
|
||||
* * {@link ComponentType.RoleSelect}
|
||||
* * {@link ComponentType.MentionableSelect}
|
||||
* * {@link ComponentType.ChannelSelect}
|
||||
* @typedef {ComponentType[]} SelectMenuTypes
|
||||
*/
|
||||
exports.SelectMenuTypes = [
|
||||
ComponentType.StringSelect,
|
||||
ComponentType.UserSelect,
|
||||
ComponentType.RoleSelect,
|
||||
ComponentType.MentionableSelect,
|
||||
ComponentType.ChannelSelect,
|
||||
];
|
||||
|
||||
/**
|
||||
* @typedef {Object} Constants Constants that can be used in an enum or object-like way.
|
||||
* @property {SweeperKey[]} SweeperKeys The possible names of items that can be swept in sweepers
|
||||
@@ -120,4 +137,5 @@ exports.VoiceBasedChannelTypes = [ChannelType.GuildVoice, ChannelType.GuildStage
|
||||
* @property {TextBasedChannelTypes} TextBasedChannelTypes The types of channels that are text-based
|
||||
* @property {ThreadChannelTypes} ThreadChannelTypes The types of channels that are threads
|
||||
* @property {VoiceBasedChannelTypes} VoiceBasedChannelTypes The types of channels that are voice-based
|
||||
* @property {SelectMenuTypes} SelectMenuTypes The types of components that are select menus.
|
||||
*/
|
||||
|
||||
286
packages/discord.js/typings/index.d.ts
vendored
286
packages/discord.js/typings/index.d.ts
vendored
@@ -14,14 +14,17 @@ import {
|
||||
italic,
|
||||
quote,
|
||||
roleMention,
|
||||
SelectMenuBuilder as BuilderSelectMenuComponent,
|
||||
ChannelSelectMenuBuilder as BuilderChannelSelectMenuComponent,
|
||||
MentionableSelectMenuBuilder as BuilderMentionableSelectMenuComponent,
|
||||
RoleSelectMenuBuilder as BuilderRoleSelectMenuComponent,
|
||||
StringSelectMenuBuilder as BuilderStringSelectMenuComponent,
|
||||
UserSelectMenuBuilder as BuilderUserSelectMenuComponent,
|
||||
TextInputBuilder as BuilderTextInputComponent,
|
||||
SelectMenuOptionBuilder as BuildersSelectMenuOption,
|
||||
spoiler,
|
||||
strikethrough,
|
||||
time,
|
||||
TimestampStyles,
|
||||
TimestampStylesString,
|
||||
underscore,
|
||||
userMention,
|
||||
ModalActionRowComponentBuilder,
|
||||
@@ -35,7 +38,6 @@ import { Collection } from '@discordjs/collection';
|
||||
import { BaseImageURLOptions, ImageURLOptions, RawFile, REST, RESTOptions } from '@discordjs/rest';
|
||||
import {
|
||||
APIActionRowComponent,
|
||||
APIApplicationCommand,
|
||||
APIApplicationCommandInteractionData,
|
||||
APIApplicationCommandOption,
|
||||
APIAuditLogChange,
|
||||
@@ -126,6 +128,17 @@ import {
|
||||
TextChannelType,
|
||||
ChannelFlags,
|
||||
SortOrderType,
|
||||
APIMessageStringSelectInteractionData,
|
||||
APIMessageUserSelectInteractionData,
|
||||
APIStringSelectComponent,
|
||||
APIUserSelectComponent,
|
||||
APIRoleSelectComponent,
|
||||
APIMentionableSelectComponent,
|
||||
APIChannelSelectComponent,
|
||||
APIGuildMember,
|
||||
APIMessageRoleSelectInteractionData,
|
||||
APIMessageMentionableSelectInteractionData,
|
||||
APIMessageChannelSelectInteractionData,
|
||||
} from 'discord-api-types/v10';
|
||||
import { ChildProcess } from 'node:child_process';
|
||||
import { EventEmitter } from 'node:events';
|
||||
@@ -158,13 +171,11 @@ import {
|
||||
RawInviteData,
|
||||
RawInviteGuildData,
|
||||
RawInviteStageInstance,
|
||||
RawAttachmentData,
|
||||
RawMessageButtonInteractionData,
|
||||
RawMessageComponentInteractionData,
|
||||
RawMessageData,
|
||||
RawMessagePayloadData,
|
||||
RawMessageReactionData,
|
||||
RawMessageSelectMenuInteractionData,
|
||||
RawOAuth2GuildData,
|
||||
RawPartialGroupDMChannelData,
|
||||
RawPartialMessageData,
|
||||
@@ -242,7 +253,11 @@ export interface BaseComponentData {
|
||||
export type MessageActionRowComponentData =
|
||||
| JSONEncodable<APIMessageActionRowComponent>
|
||||
| ButtonComponentData
|
||||
| SelectMenuComponentData;
|
||||
| StringSelectMenuComponentData
|
||||
| UserSelectMenuComponentData
|
||||
| RoleSelectMenuComponentData
|
||||
| MentionableSelectMenuComponentData
|
||||
| ChannelSelectMenuComponentData;
|
||||
|
||||
export type ModalActionRowComponentData = JSONEncodable<APIModalActionRowComponent> | TextInputComponentData;
|
||||
|
||||
@@ -269,7 +284,13 @@ export class ActionRowBuilder<T extends AnyComponentBuilder = AnyComponentBuilde
|
||||
): ActionRowBuilder;
|
||||
}
|
||||
|
||||
export type MessageActionRowComponent = ButtonComponent | SelectMenuComponent;
|
||||
export type MessageActionRowComponent =
|
||||
| ButtonComponent
|
||||
| StringSelectMenuComponent
|
||||
| UserSelectMenuComponent
|
||||
| RoleSelectMenuComponent
|
||||
| MentionableSelectMenuComponent
|
||||
| ChannelSelectMenuComponent;
|
||||
export type ModalActionRowComponent = TextInputComponent;
|
||||
|
||||
export class ActionRow<T extends MessageActionRowComponent | ModalActionRowComponent> extends Component<
|
||||
@@ -604,8 +625,8 @@ export class ButtonBuilder extends BuilderButtonComponent {
|
||||
public override setEmoji(emoji: ComponentEmojiResolvable): this;
|
||||
}
|
||||
|
||||
export class SelectMenuBuilder extends BuilderSelectMenuComponent {
|
||||
public constructor(data?: Partial<SelectMenuComponentData | APISelectMenuComponent>);
|
||||
export class StringSelectMenuBuilder extends BuilderStringSelectMenuComponent {
|
||||
public constructor(data?: Partial<StringSelectMenuComponentData | APIStringSelectComponent>);
|
||||
private static normalizeEmoji(
|
||||
selectMenuOption: JSONEncodable<APISelectMenuOption> | SelectMenuComponentOptionData,
|
||||
): (APISelectMenuOption | SelectMenuOptionBuilder)[];
|
||||
@@ -615,7 +636,34 @@ export class SelectMenuBuilder extends BuilderSelectMenuComponent {
|
||||
public override setOptions(
|
||||
...options: RestOrArray<BuildersSelectMenuOption | SelectMenuComponentOptionData | APISelectMenuOption>
|
||||
): this;
|
||||
public static from(other: JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent): SelectMenuBuilder;
|
||||
public static from(other: JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent): StringSelectMenuBuilder;
|
||||
}
|
||||
|
||||
export {
|
||||
/** @deprecated Use {@link StringSelectMenuBuilder} instead */
|
||||
StringSelectMenuBuilder as SelectMenuBuilder,
|
||||
};
|
||||
|
||||
export class UserSelectMenuBuilder extends BuilderUserSelectMenuComponent {
|
||||
public constructor(data?: Partial<UserSelectMenuComponentData | APIUserSelectComponent>);
|
||||
public static from(other: JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent): UserSelectMenuBuilder;
|
||||
}
|
||||
|
||||
export class RoleSelectMenuBuilder extends BuilderRoleSelectMenuComponent {
|
||||
public constructor(data?: Partial<RoleSelectMenuComponentData | APIRoleSelectComponent>);
|
||||
public static from(other: JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent): RoleSelectMenuBuilder;
|
||||
}
|
||||
|
||||
export class MentionableSelectMenuBuilder extends BuilderMentionableSelectMenuComponent {
|
||||
public constructor(data?: Partial<MentionableSelectMenuComponentData | APIMentionableSelectComponent>);
|
||||
public static from(
|
||||
other: JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent,
|
||||
): MentionableSelectMenuBuilder;
|
||||
}
|
||||
|
||||
export class ChannelSelectMenuBuilder extends BuilderChannelSelectMenuComponent {
|
||||
public constructor(data?: Partial<ChannelSelectMenuComponentData | APIChannelSelectComponent>);
|
||||
public static from(other: JSONEncodable<APISelectMenuComponent> | APISelectMenuComponent): ChannelSelectMenuBuilder;
|
||||
}
|
||||
|
||||
export class SelectMenuOptionBuilder extends BuildersSelectMenuOption {
|
||||
@@ -639,16 +687,34 @@ export class TextInputComponent extends Component<APITextInputComponent> {
|
||||
public get value(): string;
|
||||
}
|
||||
|
||||
export class SelectMenuComponent extends Component<APISelectMenuComponent> {
|
||||
private constructor(data: APISelectMenuComponent);
|
||||
export class BaseSelectMenuComponent<Data extends APISelectMenuComponent> extends Component<Data> {
|
||||
protected constructor(data: Data);
|
||||
public get placeholder(): string | null;
|
||||
public get maxValues(): number | null;
|
||||
public get minValues(): number | null;
|
||||
public get customId(): string;
|
||||
public get disabled(): boolean | null;
|
||||
}
|
||||
|
||||
export class StringSelectMenuComponent extends BaseSelectMenuComponent<APIStringSelectComponent> {
|
||||
public get options(): APISelectMenuOption[];
|
||||
}
|
||||
|
||||
export {
|
||||
/** @deprecated Use {@link StringSelectMenuComponent} instead */
|
||||
StringSelectMenuComponent as SelectMenuComponent,
|
||||
};
|
||||
|
||||
export class UserSelectMenuComponent extends BaseSelectMenuComponent<APIUserSelectComponent> {}
|
||||
|
||||
export class RoleSelectMenuComponent extends BaseSelectMenuComponent<APIRoleSelectComponent> {}
|
||||
|
||||
export class MentionableSelectMenuComponent extends BaseSelectMenuComponent<APIMentionableSelectComponent> {}
|
||||
|
||||
export class ChannelSelectMenuComponent extends BaseSelectMenuComponent<APIChannelSelectComponent> {
|
||||
public getChannelTypes(): ChannelType[] | null;
|
||||
}
|
||||
|
||||
export interface EmbedData {
|
||||
title?: string;
|
||||
type?: EmbedType;
|
||||
@@ -1501,7 +1567,7 @@ export type Interaction<Cached extends CacheType = CacheType> =
|
||||
| ChatInputCommandInteraction<Cached>
|
||||
| MessageContextMenuCommandInteraction<Cached>
|
||||
| UserContextMenuCommandInteraction<Cached>
|
||||
| SelectMenuInteraction<Cached>
|
||||
| AnySelectMenuInteraction<Cached>
|
||||
| ButtonInteraction<Cached>
|
||||
| AutocompleteInteraction<Cached>
|
||||
| ModalSubmitInteraction<Cached>;
|
||||
@@ -1550,7 +1616,14 @@ export class BaseInteraction<Cached extends CacheType = CacheType> extends Base
|
||||
public isMessageContextMenuCommand(): this is MessageContextMenuCommandInteraction<Cached>;
|
||||
public isModalSubmit(): this is ModalSubmitInteraction<Cached>;
|
||||
public isUserContextMenuCommand(): this is UserContextMenuCommandInteraction<Cached>;
|
||||
public isSelectMenu(): this is SelectMenuInteraction<Cached>;
|
||||
/** @deprecated Use {@link BaseInteraction#isStringSelectMenu} instead */
|
||||
public isSelectMenu(): this is StringSelectMenuInteraction<Cached>;
|
||||
public isAnySelectMenu(): this is AnySelectMenuInteraction<Cached>;
|
||||
public isStringSelectMenu(): this is StringSelectMenuInteraction<Cached>;
|
||||
public isUserSelectMenu(): this is UserSelectMenuInteraction<Cached>;
|
||||
public isRoleSelectMenu(): this is RoleSelectMenuInteraction<Cached>;
|
||||
public isMentionableSelectMenu(): this is MentionableSelectMenuInteraction<Cached>;
|
||||
public isChannelSelectMenu(): this is ChannelSelectMenuInteraction<Cached>;
|
||||
public isRepliable(): this is RepliableInteraction<Cached>;
|
||||
}
|
||||
|
||||
@@ -1673,7 +1746,11 @@ export type AwaitMessageCollectorOptionsParams<T extends MessageComponentType, C
|
||||
|
||||
export interface StringMappedInteractionTypes<Cached extends CacheType = CacheType> {
|
||||
Button: ButtonInteraction<Cached>;
|
||||
SelectMenu: SelectMenuInteraction<Cached>;
|
||||
StringSelectMenu: StringSelectMenuInteraction<Cached>;
|
||||
UserSelectMenu: UserSelectMenuInteraction<Cached>;
|
||||
RoleSelectMenu: RoleSelectMenuInteraction<Cached>;
|
||||
MentionableSelectMenu: MentionableSelectMenuInteraction<Cached>;
|
||||
ChannelSelectMenu: ChannelSelectMenuInteraction<Cached>;
|
||||
ActionRow: MessageComponentInteraction<Cached>;
|
||||
}
|
||||
|
||||
@@ -1681,7 +1758,11 @@ export type WrapBooleanCache<T extends boolean> = If<T, 'cached', CacheType>;
|
||||
|
||||
export interface MappedInteractionTypes<Cached extends boolean = boolean> {
|
||||
[ComponentType.Button]: ButtonInteraction<WrapBooleanCache<Cached>>;
|
||||
[ComponentType.SelectMenu]: SelectMenuInteraction<WrapBooleanCache<Cached>>;
|
||||
[ComponentType.StringSelect]: StringSelectMenuInteraction<WrapBooleanCache<Cached>>;
|
||||
[ComponentType.UserSelect]: UserSelectMenuInteraction<WrapBooleanCache<Cached>>;
|
||||
[ComponentType.RoleSelect]: RoleSelectMenuInteraction<WrapBooleanCache<Cached>>;
|
||||
[ComponentType.MentionableSelect]: MentionableSelectMenuInteraction<WrapBooleanCache<Cached>>;
|
||||
[ComponentType.ChannelSelect]: ChannelSelectMenuInteraction<WrapBooleanCache<Cached>>;
|
||||
}
|
||||
|
||||
export class Message<InGuild extends boolean = boolean> extends Base {
|
||||
@@ -2254,22 +2335,116 @@ export class Role extends Base {
|
||||
public toString(): RoleMention;
|
||||
}
|
||||
|
||||
export class SelectMenuInteraction<Cached extends CacheType = CacheType> extends MessageComponentInteraction<Cached> {
|
||||
public constructor(client: Client<true>, data: RawMessageSelectMenuInteractionData);
|
||||
export class StringSelectMenuInteraction<
|
||||
Cached extends CacheType = CacheType,
|
||||
> extends MessageComponentInteraction<Cached> {
|
||||
public constructor(client: Client<true>, data: APIMessageStringSelectInteractionData);
|
||||
public get component(): CacheTypeReducer<
|
||||
Cached,
|
||||
SelectMenuComponent,
|
||||
APISelectMenuComponent,
|
||||
SelectMenuComponent | APISelectMenuComponent,
|
||||
SelectMenuComponent | APISelectMenuComponent
|
||||
StringSelectMenuComponent,
|
||||
APIStringSelectComponent,
|
||||
StringSelectMenuComponent | APIStringSelectComponent,
|
||||
StringSelectMenuComponent | APIStringSelectComponent
|
||||
>;
|
||||
public componentType: ComponentType.SelectMenu;
|
||||
public componentType: ComponentType.StringSelect;
|
||||
public values: string[];
|
||||
public inGuild(): this is SelectMenuInteraction<'raw' | 'cached'>;
|
||||
public inCachedGuild(): this is SelectMenuInteraction<'cached'>;
|
||||
public inRawGuild(): this is SelectMenuInteraction<'raw'>;
|
||||
public inGuild(): this is StringSelectMenuInteraction<'raw' | 'cached'>;
|
||||
public inCachedGuild(): this is StringSelectMenuInteraction<'cached'>;
|
||||
public inRawGuild(): this is StringSelectMenuInteraction<'raw'>;
|
||||
}
|
||||
|
||||
export {
|
||||
/** @deprecated Use {@link StringSelectMenuInteraction} instead */
|
||||
StringSelectMenuInteraction as SelectMenuInteraction,
|
||||
};
|
||||
|
||||
export class UserSelectMenuInteraction<
|
||||
Cached extends CacheType = CacheType,
|
||||
> extends MessageComponentInteraction<Cached> {
|
||||
public constructor(client: Client<true>, data: APIMessageUserSelectInteractionData);
|
||||
public get component(): CacheTypeReducer<
|
||||
Cached,
|
||||
UserSelectMenuComponent,
|
||||
APIUserSelectComponent,
|
||||
UserSelectMenuComponent | APIUserSelectComponent,
|
||||
UserSelectMenuComponent | APIUserSelectComponent
|
||||
>;
|
||||
public componentType: ComponentType.UserSelect;
|
||||
public users: Collection<Snowflake, User>;
|
||||
public members: Collection<Snowflake, CacheTypeReducer<Cached, GuildMember, APIGuildMember>>;
|
||||
public inGuild(): this is UserSelectMenuInteraction<'raw' | 'cached'>;
|
||||
public inCachedGuild(): this is UserSelectMenuInteraction<'cached'>;
|
||||
public inRawGuild(): this is UserSelectMenuInteraction<'raw'>;
|
||||
}
|
||||
|
||||
export class RoleSelectMenuInteraction<
|
||||
Cached extends CacheType = CacheType,
|
||||
> extends MessageComponentInteraction<Cached> {
|
||||
public constructor(client: Client<true>, data: APIMessageRoleSelectInteractionData);
|
||||
public get component(): CacheTypeReducer<
|
||||
Cached,
|
||||
RoleSelectMenuComponent,
|
||||
APIRoleSelectComponent,
|
||||
RoleSelectMenuComponent | APIRoleSelectComponent,
|
||||
RoleSelectMenuComponent | APIRoleSelectComponent
|
||||
>;
|
||||
public componentType: ComponentType.RoleSelect;
|
||||
public roles: Collection<Snowflake, CacheTypeReducer<Cached, Role, APIRole>>;
|
||||
public inGuild(): this is RoleSelectMenuInteraction<'raw' | 'cached'>;
|
||||
public inCachedGuild(): this is RoleSelectMenuInteraction<'cached'>;
|
||||
public inRawGuild(): this is RoleSelectMenuInteraction<'raw'>;
|
||||
}
|
||||
|
||||
export class MentionableSelectMenuInteraction<
|
||||
Cached extends CacheType = CacheType,
|
||||
> extends MessageComponentInteraction<Cached> {
|
||||
public constructor(client: Client<true>, data: APIMessageMentionableSelectInteractionData);
|
||||
public get component(): CacheTypeReducer<
|
||||
Cached,
|
||||
MentionableSelectMenuComponent,
|
||||
APIMentionableSelectComponent,
|
||||
MentionableSelectMenuComponent | APIMentionableSelectComponent,
|
||||
MentionableSelectMenuComponent | APIMentionableSelectComponent
|
||||
>;
|
||||
public componentType: ComponentType.MentionableSelect;
|
||||
public users: Collection<Snowflake, User>;
|
||||
public members: Collection<Snowflake, CacheTypeReducer<Cached, GuildMember, APIGuildMember>>;
|
||||
public roles: Collection<Snowflake, CacheTypeReducer<Cached, Role, APIRole>>;
|
||||
public inGuild(): this is MentionableSelectMenuInteraction<'raw' | 'cached'>;
|
||||
public inCachedGuild(): this is MentionableSelectMenuInteraction<'cached'>;
|
||||
public inRawGuild(): this is MentionableSelectMenuInteraction<'raw'>;
|
||||
}
|
||||
|
||||
export class ChannelSelectMenuInteraction<
|
||||
Cached extends CacheType = CacheType,
|
||||
> extends MessageComponentInteraction<Cached> {
|
||||
public constructor(client: Client<true>, data: APIMessageChannelSelectInteractionData);
|
||||
public get component(): CacheTypeReducer<
|
||||
Cached,
|
||||
ChannelSelectMenuComponent,
|
||||
APIChannelSelectComponent,
|
||||
ChannelSelectMenuComponent | APIChannelSelectComponent,
|
||||
ChannelSelectMenuComponent | APIChannelSelectComponent
|
||||
>;
|
||||
public componentType: ComponentType.ChannelSelect;
|
||||
public channels: Collection<Snowflake, CacheTypeReducer<Cached, Channel, APIChannel>>;
|
||||
public inGuild(): this is ChannelSelectMenuInteraction<'raw' | 'cached'>;
|
||||
public inCachedGuild(): this is ChannelSelectMenuInteraction<'cached'>;
|
||||
public inRawGuild(): this is ChannelSelectMenuInteraction<'raw'>;
|
||||
}
|
||||
|
||||
// Ideally this should be named SelectMenuInteraction, but that's the name of the "old" StringSelectMenuInteraction, meaning
|
||||
// the type name is reserved as a re-export to prevent a breaking change from being made, as such:
|
||||
// TODO: Rename this to SelectMenuInteraction in the next major
|
||||
export type AnySelectMenuInteraction<Cached extends CacheType = CacheType> =
|
||||
| StringSelectMenuInteraction<Cached>
|
||||
| UserSelectMenuInteraction<Cached>
|
||||
| RoleSelectMenuInteraction<Cached>
|
||||
| MentionableSelectMenuInteraction<Cached>
|
||||
| ChannelSelectMenuInteraction<Cached>;
|
||||
|
||||
export type SelectMenuType = APISelectMenuComponent['type'];
|
||||
|
||||
export interface ShardEventTypes {
|
||||
death: [process: ChildProcess | Worker];
|
||||
disconnect: [];
|
||||
@@ -2770,14 +2945,22 @@ export function parseWebhookURL(url: string): WebhookClientDataIdWithToken | nul
|
||||
|
||||
export interface MappedComponentBuilderTypes {
|
||||
[ComponentType.Button]: ButtonBuilder;
|
||||
[ComponentType.SelectMenu]: SelectMenuBuilder;
|
||||
[ComponentType.StringSelect]: StringSelectMenuBuilder;
|
||||
[ComponentType.UserSelect]: UserSelectMenuBuilder;
|
||||
[ComponentType.RoleSelect]: RoleSelectMenuBuilder;
|
||||
[ComponentType.MentionableSelect]: MentionableSelectMenuBuilder;
|
||||
[ComponentType.ChannelSelect]: ChannelSelectMenuBuilder;
|
||||
[ComponentType.ActionRow]: ActionRowBuilder;
|
||||
[ComponentType.TextInput]: TextInputBuilder;
|
||||
}
|
||||
|
||||
export interface MappedComponentTypes {
|
||||
[ComponentType.Button]: ButtonComponent;
|
||||
[ComponentType.SelectMenu]: SelectMenuComponent;
|
||||
[ComponentType.StringSelect]: StringSelectMenuComponent;
|
||||
[ComponentType.UserSelect]: UserSelectMenuComponent;
|
||||
[ComponentType.RoleSelect]: RoleSelectMenuComponent;
|
||||
[ComponentType.MentionableSelect]: MentionableSelectMenuComponent;
|
||||
[ComponentType.ChannelSelect]: ChannelSelectMenuComponent;
|
||||
[ComponentType.ActionRow]: ActionRowComponent;
|
||||
[ComponentType.TextInput]: TextInputComponent;
|
||||
}
|
||||
@@ -3116,6 +3299,7 @@ export const Constants: {
|
||||
TextBasedChannelTypes: TextBasedChannelTypes[];
|
||||
ThreadChannelTypes: ThreadChannelType[];
|
||||
VoiceBasedChannelTypes: VoiceBasedChannelTypes[];
|
||||
SelectMenuTypes: SelectMenuType[];
|
||||
};
|
||||
|
||||
export const version: string;
|
||||
@@ -5144,7 +5328,11 @@ export interface IntegrationAccount {
|
||||
export type IntegrationType = 'twitch' | 'youtube' | 'discord';
|
||||
|
||||
export type CollectedInteraction<Cached extends CacheType = CacheType> =
|
||||
| SelectMenuInteraction<Cached>
|
||||
| StringSelectMenuInteraction<Cached>
|
||||
| UserSelectMenuInteraction<Cached>
|
||||
| RoleSelectMenuInteraction<Cached>
|
||||
| MentionableSelectMenuInteraction<Cached>
|
||||
| ChannelSelectMenuInteraction<Cached>
|
||||
| ButtonInteraction<Cached>
|
||||
| ModalSubmitInteraction<Cached>;
|
||||
|
||||
@@ -5216,7 +5404,13 @@ export interface MakeErrorOptions {
|
||||
stack: string;
|
||||
}
|
||||
|
||||
export type ActionRowComponentOptions = ButtonComponentData | SelectMenuComponentData;
|
||||
export type ActionRowComponentOptions =
|
||||
| ButtonComponentData
|
||||
| StringSelectMenuComponentData
|
||||
| UserSelectMenuComponentData
|
||||
| RoleSelectMenuComponentData
|
||||
| MentionableSelectMenuComponentData
|
||||
| ChannelSelectMenuComponentData;
|
||||
|
||||
export type MessageActionRowComponentResolvable = MessageActionRowComponent | ActionRowComponentOptions;
|
||||
|
||||
@@ -5253,7 +5447,11 @@ export type MessageComponent =
|
||||
| Component
|
||||
| ActionRowBuilder<MessageActionRowComponentBuilder | ModalActionRowComponentBuilder>
|
||||
| ButtonComponent
|
||||
| SelectMenuComponent;
|
||||
| StringSelectMenuComponent
|
||||
| UserSelectMenuComponent
|
||||
| RoleSelectMenuComponent
|
||||
| MentionableSelectMenuComponent
|
||||
| ChannelSelectMenuComponent;
|
||||
|
||||
export type CollectedMessageInteraction<Cached extends CacheType = CacheType> = Exclude<
|
||||
CollectedInteraction<Cached>,
|
||||
@@ -5351,16 +5549,36 @@ export interface MessageReference {
|
||||
|
||||
export type MessageResolvable = Message | Snowflake;
|
||||
|
||||
export interface SelectMenuComponentData extends BaseComponentData {
|
||||
type: ComponentType.SelectMenu;
|
||||
export interface BaseSelectMenuComponentData extends BaseComponentData {
|
||||
customId: string;
|
||||
disabled?: boolean;
|
||||
maxValues?: number;
|
||||
minValues?: number;
|
||||
options?: SelectMenuComponentOptionData[];
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
export interface StringSelectMenuComponentData extends BaseSelectMenuComponentData {
|
||||
type: ComponentType.StringSelect;
|
||||
options?: SelectMenuComponentOptionData[];
|
||||
}
|
||||
|
||||
export interface UserSelectMenuComponentData extends BaseSelectMenuComponentData {
|
||||
type: ComponentType.UserSelect;
|
||||
}
|
||||
|
||||
export interface RoleSelectMenuComponentData extends BaseSelectMenuComponentData {
|
||||
type: ComponentType.RoleSelect;
|
||||
}
|
||||
|
||||
export interface MentionableSelectMenuComponentData extends BaseSelectMenuComponentData {
|
||||
type: ComponentType.MentionableSelect;
|
||||
}
|
||||
|
||||
export interface ChannelSelectMenuComponentData extends BaseSelectMenuComponentData {
|
||||
type: ComponentType.ChannelSelect;
|
||||
channelTypes?: ChannelType[];
|
||||
}
|
||||
|
||||
export interface MessageSelectOption {
|
||||
default: boolean;
|
||||
description: string | null;
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
APIEmbed,
|
||||
ApplicationCommandType,
|
||||
APIMessage,
|
||||
APIStringSelectComponent,
|
||||
} from 'discord-api-types/v10';
|
||||
import {
|
||||
ApplicationCommand,
|
||||
@@ -72,7 +73,6 @@ import {
|
||||
ReactionCollector,
|
||||
Role,
|
||||
RoleManager,
|
||||
SelectMenuInteraction,
|
||||
Serialized,
|
||||
ShardClientUtil,
|
||||
ShardingManager,
|
||||
@@ -113,7 +113,7 @@ import {
|
||||
ButtonBuilder,
|
||||
EmbedBuilder,
|
||||
MessageActionRowComponent,
|
||||
SelectMenuBuilder,
|
||||
StringSelectMenuBuilder,
|
||||
TextInputBuilder,
|
||||
TextInputComponent,
|
||||
Embed,
|
||||
@@ -141,6 +141,13 @@ import {
|
||||
ChannelFlagsBitField,
|
||||
GuildForumThreadManager,
|
||||
GuildTextThreadManager,
|
||||
AnySelectMenuInteraction,
|
||||
StringSelectMenuInteraction,
|
||||
StringSelectMenuComponent,
|
||||
UserSelectMenuInteraction,
|
||||
RoleSelectMenuInteraction,
|
||||
ChannelSelectMenuInteraction,
|
||||
MentionableSelectMenuInteraction,
|
||||
} from '.';
|
||||
import { expectAssignable, expectNotAssignable, expectNotType, expectType } from 'tsd';
|
||||
import type { ContextMenuCommandBuilder, SlashCommandBuilder } from '@discordjs/builders';
|
||||
@@ -361,14 +368,14 @@ client.on('messageCreate', async message => {
|
||||
expectAssignable<InteractionCollector<ButtonInteraction>>(buttonCollector);
|
||||
|
||||
// Verify that select menus interaction are inferred.
|
||||
const selectMenuCollector = message.createMessageComponentCollector({ componentType: ComponentType.SelectMenu });
|
||||
expectAssignable<Promise<SelectMenuInteraction>>(
|
||||
message.awaitMessageComponent({ componentType: ComponentType.SelectMenu }),
|
||||
const selectMenuCollector = message.createMessageComponentCollector({ componentType: ComponentType.StringSelect });
|
||||
expectAssignable<Promise<StringSelectMenuInteraction>>(
|
||||
message.awaitMessageComponent({ componentType: ComponentType.StringSelect }),
|
||||
);
|
||||
expectAssignable<Promise<SelectMenuInteraction>>(
|
||||
channel.awaitMessageComponent({ componentType: ComponentType.SelectMenu }),
|
||||
expectAssignable<Promise<StringSelectMenuInteraction>>(
|
||||
channel.awaitMessageComponent({ componentType: ComponentType.StringSelect }),
|
||||
);
|
||||
expectAssignable<InteractionCollector<SelectMenuInteraction>>(selectMenuCollector);
|
||||
expectAssignable<InteractionCollector<StringSelectMenuInteraction>>(selectMenuCollector);
|
||||
|
||||
// Verify that message component interactions are default collected types.
|
||||
const defaultCollector = message.createMessageComponentCollector();
|
||||
@@ -405,9 +412,9 @@ client.on('messageCreate', async message => {
|
||||
});
|
||||
|
||||
message.createMessageComponentCollector({
|
||||
componentType: ComponentType.SelectMenu,
|
||||
componentType: ComponentType.StringSelect,
|
||||
filter: i => {
|
||||
expectType<SelectMenuInteraction>(i);
|
||||
expectType<StringSelectMenuInteraction>(i);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
@@ -428,9 +435,9 @@ client.on('messageCreate', async message => {
|
||||
});
|
||||
|
||||
message.awaitMessageComponent({
|
||||
componentType: ComponentType.SelectMenu,
|
||||
componentType: ComponentType.StringSelect,
|
||||
filter: i => {
|
||||
expectType<SelectMenuInteraction>(i);
|
||||
expectType<StringSelectMenuInteraction>(i);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
@@ -464,9 +471,9 @@ client.on('messageCreate', async message => {
|
||||
});
|
||||
|
||||
channel.awaitMessageComponent({
|
||||
componentType: ComponentType.SelectMenu,
|
||||
componentType: ComponentType.StringSelect,
|
||||
filter: i => {
|
||||
expectType<SelectMenuInteraction<'cached'>>(i);
|
||||
expectType<StringSelectMenuInteraction<'cached'>>(i);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
@@ -489,9 +496,9 @@ client.on('messageCreate', async message => {
|
||||
const selectsRow: ActionRowData<MessageActionRowComponentData> = {
|
||||
type: ComponentType.ActionRow,
|
||||
components: [
|
||||
new SelectMenuBuilder(),
|
||||
new StringSelectMenuBuilder(),
|
||||
{
|
||||
type: ComponentType.SelectMenu,
|
||||
type: ComponentType.StringSelect,
|
||||
label: 'select menu',
|
||||
options: [{ label: 'test', value: 'test' }],
|
||||
customId: 'test',
|
||||
@@ -1122,8 +1129,8 @@ client.on('guildCreate', async g => {
|
||||
new ButtonBuilder(),
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Primary, label: 'string', customId: 'foo' },
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Link, label: 'test', url: 'test' },
|
||||
{ type: ComponentType.SelectMenu, customId: 'foo' },
|
||||
new SelectMenuBuilder(),
|
||||
{ type: ComponentType.StringSelect, customId: 'foo' },
|
||||
new StringSelectMenuBuilder(),
|
||||
// @ts-expect-error
|
||||
{ type: ComponentType.TextInput, style: TextInputStyle.Paragraph, customId: 'foo', label: 'test' },
|
||||
// @ts-expect-error
|
||||
@@ -1136,7 +1143,7 @@ client.on('guildCreate', async g => {
|
||||
components: [
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Primary, label: 'string', customId: 'foo' },
|
||||
{ type: ComponentType.Button, style: ButtonStyle.Link, label: 'test', url: 'test' },
|
||||
{ type: ComponentType.SelectMenu, customId: 'foo' },
|
||||
{ type: ComponentType.StringSelect, customId: 'foo' },
|
||||
],
|
||||
});
|
||||
|
||||
@@ -1508,7 +1515,7 @@ if (interaction.inGuild()) {
|
||||
|
||||
client.on('interactionCreate', async interaction => {
|
||||
if (interaction.type === InteractionType.MessageComponent) {
|
||||
expectType<SelectMenuInteraction | ButtonInteraction>(interaction);
|
||||
expectType<AnySelectMenuInteraction | ButtonInteraction>(interaction);
|
||||
expectType<MessageActionRowComponent | APIButtonComponent | APISelectMenuComponent>(interaction.component);
|
||||
expectType<Message>(interaction.message);
|
||||
if (interaction.inCachedGuild()) {
|
||||
@@ -1640,25 +1647,28 @@ client.on('interactionCreate', async interaction => {
|
||||
}
|
||||
}
|
||||
|
||||
if (interaction.type === InteractionType.MessageComponent && interaction.componentType === ComponentType.SelectMenu) {
|
||||
expectType<SelectMenuInteraction>(interaction);
|
||||
expectType<SelectMenuComponent | APISelectMenuComponent>(interaction.component);
|
||||
if (
|
||||
interaction.type === InteractionType.MessageComponent &&
|
||||
interaction.componentType === ComponentType.StringSelect
|
||||
) {
|
||||
expectType<StringSelectMenuInteraction>(interaction);
|
||||
expectType<StringSelectMenuComponent | APIStringSelectComponent>(interaction.component);
|
||||
expectType<Message>(interaction.message);
|
||||
if (interaction.inCachedGuild()) {
|
||||
expectAssignable<SelectMenuInteraction>(interaction);
|
||||
expectAssignable<StringSelectMenuInteraction>(interaction);
|
||||
expectType<SelectMenuComponent>(interaction.component);
|
||||
expectType<Message<true>>(interaction.message);
|
||||
expectType<Guild>(interaction.guild);
|
||||
expectType<Promise<Message<true>>>(interaction.reply({ fetchReply: true }));
|
||||
} else if (interaction.inRawGuild()) {
|
||||
expectAssignable<SelectMenuInteraction>(interaction);
|
||||
expectType<APISelectMenuComponent>(interaction.component);
|
||||
expectAssignable<StringSelectMenuInteraction>(interaction);
|
||||
expectType<APIStringSelectComponent>(interaction.component);
|
||||
expectType<Message<false>>(interaction.message);
|
||||
expectType<null>(interaction.guild);
|
||||
expectType<Promise<Message<false>>>(interaction.reply({ fetchReply: true }));
|
||||
} else if (interaction.inGuild()) {
|
||||
expectAssignable<SelectMenuInteraction>(interaction);
|
||||
expectType<SelectMenuComponent | APISelectMenuComponent>(interaction.component);
|
||||
expectAssignable<StringSelectMenuInteraction>(interaction);
|
||||
expectType<SelectMenuComponent | APIStringSelectComponent>(interaction.component);
|
||||
expectType<Message>(interaction.message);
|
||||
expectType<Guild | null>(interaction.guild);
|
||||
expectType<Promise<Message>>(interaction.reply({ fetchReply: true }));
|
||||
@@ -1882,7 +1892,7 @@ const button = new ButtonBuilder({
|
||||
customId: 'test',
|
||||
});
|
||||
|
||||
const selectMenu = new SelectMenuBuilder({
|
||||
const selectMenu = new StringSelectMenuBuilder({
|
||||
maxValues: 10,
|
||||
minValues: 2,
|
||||
customId: 'test',
|
||||
@@ -1892,7 +1902,7 @@ new ActionRowBuilder({
|
||||
components: [selectMenu.toJSON(), button.toJSON()],
|
||||
});
|
||||
|
||||
new SelectMenuBuilder({
|
||||
new StringSelectMenuBuilder({
|
||||
customId: 'foo',
|
||||
});
|
||||
|
||||
@@ -1951,10 +1961,10 @@ chatInputInteraction.showModal({
|
||||
});
|
||||
|
||||
declare const selectMenuData: APISelectMenuComponent;
|
||||
SelectMenuBuilder.from(selectMenuData);
|
||||
StringSelectMenuBuilder.from(selectMenuData);
|
||||
|
||||
declare const selectMenuComp: SelectMenuComponent;
|
||||
SelectMenuBuilder.from(selectMenuComp);
|
||||
StringSelectMenuBuilder.from(selectMenuComp);
|
||||
|
||||
declare const buttonData: APIButtonComponent;
|
||||
ButtonBuilder.from(buttonData);
|
||||
@@ -2025,3 +2035,22 @@ expectType<Readonly<ChannelFlagsBitField>>(categoryChannel.flags);
|
||||
expectType<Readonly<ChannelFlagsBitField>>(threadChannel.flags);
|
||||
|
||||
expectType<null>(partialGroupDMChannel.flags);
|
||||
|
||||
// Select menu type narrowing
|
||||
if (interaction.isAnySelectMenu()) {
|
||||
expectType<AnySelectMenuInteraction>(interaction);
|
||||
}
|
||||
|
||||
declare const anySelectMenu: AnySelectMenuInteraction;
|
||||
|
||||
if (anySelectMenu.isStringSelectMenu()) {
|
||||
expectType<StringSelectMenuInteraction>(anySelectMenu);
|
||||
} else if (anySelectMenu.isUserSelectMenu()) {
|
||||
expectType<UserSelectMenuInteraction>(anySelectMenu);
|
||||
} else if (anySelectMenu.isRoleSelectMenu()) {
|
||||
expectType<RoleSelectMenuInteraction>(anySelectMenu);
|
||||
} else if (anySelectMenu.isChannelSelectMenu()) {
|
||||
expectType<ChannelSelectMenuInteraction>(anySelectMenu);
|
||||
} else if (anySelectMenu.isMentionableSelectMenu()) {
|
||||
expectType<MentionableSelectMenuInteraction>(anySelectMenu);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"@discordjs/util": "workspace:^",
|
||||
"@sapphire/async-queue": "^1.5.0",
|
||||
"@sapphire/snowflake": "^3.2.2",
|
||||
"discord-api-types": "^0.37.14",
|
||||
"discord-api-types": "^0.37.15",
|
||||
"file-type": "^18.0.0",
|
||||
"tslib": "^2.4.0",
|
||||
"undici": "^5.11.0"
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
"homepage": "https://discord.js.org",
|
||||
"dependencies": {
|
||||
"@types/ws": "^8.5.3",
|
||||
"discord-api-types": "^0.37.14",
|
||||
"discord-api-types": "^0.37.15",
|
||||
"prism-media": "^1.3.4",
|
||||
"tslib": "^2.4.0",
|
||||
"ws": "^8.9.0"
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
"@sapphire/async-queue": "^1.5.0",
|
||||
"@types/ws": "^8.5.3",
|
||||
"@vladfrangu/async_event_emitter": "^2.1.2",
|
||||
"discord-api-types": "^0.37.14",
|
||||
"discord-api-types": "^0.37.15",
|
||||
"tslib": "^2.4.0",
|
||||
"ws": "^8.9.0"
|
||||
},
|
||||
|
||||
18
yarn.lock
18
yarn.lock
@@ -2063,7 +2063,7 @@ __metadata:
|
||||
"@types/node": 16.11.68
|
||||
"@vitest/coverage-c8": ^0.24.3
|
||||
cross-env: ^7.0.3
|
||||
discord-api-types: ^0.37.14
|
||||
discord-api-types: ^0.37.15
|
||||
esbuild-plugin-version-injector: ^1.0.0
|
||||
eslint: ^8.25.0
|
||||
eslint-config-neon: ^0.1.39
|
||||
@@ -2250,7 +2250,7 @@ __metadata:
|
||||
"@types/node": 16.11.68
|
||||
"@vitest/coverage-c8": ^0.24.3
|
||||
cross-env: ^7.0.3
|
||||
discord-api-types: ^0.37.14
|
||||
discord-api-types: ^0.37.15
|
||||
esbuild-plugin-version-injector: ^1.0.0
|
||||
eslint: ^8.25.0
|
||||
eslint-config-neon: ^0.1.39
|
||||
@@ -2354,7 +2354,7 @@ __metadata:
|
||||
"@types/node": 16.11.68
|
||||
"@types/ws": ^8.5.3
|
||||
cross-env: ^7.0.3
|
||||
discord-api-types: ^0.37.14
|
||||
discord-api-types: ^0.37.15
|
||||
esbuild-plugin-version-injector: ^1.0.0
|
||||
eslint: ^8.25.0
|
||||
eslint-config-neon: ^0.1.39
|
||||
@@ -2444,7 +2444,7 @@ __metadata:
|
||||
"@vitest/coverage-c8": ^0.24.3
|
||||
"@vladfrangu/async_event_emitter": ^2.1.2
|
||||
cross-env: ^7.0.3
|
||||
discord-api-types: ^0.37.14
|
||||
discord-api-types: ^0.37.15
|
||||
esbuild-plugin-version-injector: ^1.0.0
|
||||
eslint: ^8.25.0
|
||||
eslint-config-neon: ^0.1.39
|
||||
@@ -8256,10 +8256,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"discord-api-types@npm:^0.37.14":
|
||||
version: 0.37.14
|
||||
resolution: "discord-api-types@npm:0.37.14"
|
||||
checksum: 8f45f202e66acfd7b25624c8f4d225b363d9d8991d766959bcf246761548b99e21c12d9f7eafe00903913af66058595e5e56329dfb219eab8bb75a84f6413983
|
||||
"discord-api-types@npm:^0.37.15":
|
||||
version: 0.37.15
|
||||
resolution: "discord-api-types@npm:0.37.15"
|
||||
checksum: c54d2feeb8074509bdda430fb8ec0f6ff315512e7327d47399e0e7a78bbd0a6f0f0dcfc4b5e39825eb6141a13f33efa942711af89c9a5936a721cfc1e1d69d19
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -8276,7 +8276,7 @@ __metadata:
|
||||
"@sapphire/snowflake": ^3.2.2
|
||||
"@types/node": 16.11.68
|
||||
"@types/ws": ^8.5.3
|
||||
discord-api-types: ^0.37.14
|
||||
discord-api-types: ^0.37.15
|
||||
dtslint: ^4.2.1
|
||||
eslint: ^8.25.0
|
||||
eslint-formatter-pretty: ^4.1.0
|
||||
|
||||
Reference in New Issue
Block a user