From cd5915c8b664bed1a7b5166745a034a74c42e7f6 Mon Sep 17 00:00:00 2001 From: LTS20050703 Date: Tue, 15 Nov 2022 01:34:41 +0700 Subject: [PATCH] add new select menu components (#2583) * add new select menu components * fix: check for component type --- helpers/messages/sendMessage.ts | 16 ++++++ plugins/validations/src/components.ts | 80 ++++++++++++++++----------- types/discordeno.ts | 72 +++++++++++++++++++++++- types/shared.ts | 14 ++++- 4 files changed, 145 insertions(+), 37 deletions(-) diff --git a/helpers/messages/sendMessage.ts b/helpers/messages/sendMessage.ts index 95eaa6c06..fefd0e813 100644 --- a/helpers/messages/sendMessage.ts +++ b/helpers/messages/sendMessage.ts @@ -90,6 +90,22 @@ export async function sendMessage(bot: Bot, channelId: BigString, options: Creat }; } + if ( + subComponent.type === MessageComponentTypes.SelectMenuChannels || + subComponent.type === MessageComponentTypes.SelectMenuRoles || + subComponent.type === MessageComponentTypes.SelectMenuUsers || + subComponent.type === MessageComponentTypes.SelectMenuUsersAndRoles + ) { + return { + type: subComponent.type, + custom_id: subComponent.customId, + placeholder: subComponent.placeholder, + min_values: subComponent.minValues, + max_values: subComponent.maxValues, + disabled: "disabled" in subComponent ? subComponent.disabled : undefined, + }; + } + return { type: subComponent.type, custom_id: subComponent.customId, diff --git a/plugins/validations/src/components.ts b/plugins/validations/src/components.ts index 6c33846da..00b3af7eb 100644 --- a/plugins/validations/src/components.ts +++ b/plugins/validations/src/components.ts @@ -14,7 +14,13 @@ export function validateComponents(bot: Bot, components: MessageComponents) { if (component.components?.length > 5) throw new Error("Too many components."); else if ( component.components?.length > 1 && - component.components.some((subComponent) => subComponent.type === MessageComponentTypes.SelectMenu) + component.components.some((subComponent) => + subComponent.type === MessageComponentTypes.SelectMenu || + subComponent.type === MessageComponentTypes.SelectMenuChannels || + subComponent.type === MessageComponentTypes.SelectMenuRoles || + subComponent.type === MessageComponentTypes.SelectMenuUsers || + subComponent.type === MessageComponentTypes.SelectMenuUsersAndRoles + ) ) { throw new Error("Select component must be alone."); } @@ -48,7 +54,13 @@ export function validateComponents(bot: Bot, components: MessageComponents) { subComponent.emoji = makeEmojiFromString(subComponent.emoji); } - if (subComponent.type === MessageComponentTypes.SelectMenu) { + if ( + subComponent.type === MessageComponentTypes.SelectMenu || + subComponent.type === MessageComponentTypes.SelectMenuChannels || + subComponent.type === MessageComponentTypes.SelectMenuRoles || + subComponent.type === MessageComponentTypes.SelectMenuUsers || + subComponent.type === MessageComponentTypes.SelectMenuUsersAndRoles + ) { if ( subComponent.placeholder && !bot.utils.validateLength(subComponent.placeholder, { max: 150 }) @@ -93,44 +105,46 @@ export function validateComponents(bot: Bot, components: MessageComponents) { } } - if (subComponent.options.length < 1) throw new Error("You need at least 1 option in the select component."); + if (subComponent.type === MessageComponentTypes.SelectMenu) { + if (subComponent.options.length < 1) throw new Error("You need at least 1 option in the select component."); - if (subComponent.options.length > 25) { - throw new Error( - "You can not have more than 25 options in the select component.", - ); - } - - let defaults = 0; - - for (const option of subComponent.options) { - if (option.default) { - defaults++; - if (defaults > (subComponent.maxValues || 25)) throw new Error("You chose too many default options."); - } - - if (!bot.utils.validateLength(option.label, { max: 25 })) { + if (subComponent.options.length > 25) { throw new Error( - "The select component label can not exceed 25 characters.", + "You can not have more than 25 options in the select component.", ); } - if (!bot.utils.validateLength(option.value, { max: 100 })) { - throw new Error( - "The select component value can not exceed 100 characters.", - ); - } + let defaults = 0; - if ( - option.description && - !bot.utils.validateLength(option.description, { max: 50 }) - ) { - throw new Error( - "The select option description can not exceed 50 characters.", - ); - } + for (const option of subComponent.options) { + if (option.default) { + defaults++; + if (defaults > (subComponent.maxValues || 25)) throw new Error("You chose too many default options."); + } - option.emoji = makeEmojiFromString(option.emoji); + if (!bot.utils.validateLength(option.label, { max: 25 })) { + throw new Error( + "The select component label can not exceed 25 characters.", + ); + } + + if (!bot.utils.validateLength(option.value, { max: 100 })) { + throw new Error( + "The select component value can not exceed 100 characters.", + ); + } + + if ( + option.description && + !bot.utils.validateLength(option.description, { max: 50 }) + ) { + throw new Error( + "The select option description can not exceed 50 characters.", + ); + } + + option.emoji = makeEmojiFromString(option.emoji); + } } } diff --git a/types/discordeno.ts b/types/discordeno.ts index 0b54490b6..174cd96b7 100644 --- a/types/discordeno.ts +++ b/types/discordeno.ts @@ -21,7 +21,15 @@ export interface ActionRow { type: MessageComponentTypes.ActionRow; /** The components in this row */ components: - | [SelectMenuComponent | ButtonComponent | InputTextComponent] + | [ + | ButtonComponent + | InputTextComponent + | SelectMenuComponent + | SelectMenuChannelsComponent + | SelectMenuRolesComponent + | SelectMenuUsersComponent + | SelectMenuUsersAndRolesComponent, + ] | [ButtonComponent, ButtonComponent] | [ButtonComponent, ButtonComponent, ButtonComponent] | [ButtonComponent, ButtonComponent, ButtonComponent, ButtonComponent] @@ -71,6 +79,68 @@ export interface SelectMenuComponent { disabled?: boolean; } +export interface SelectMenuUsersComponent { + /** SelectMenuChannels Component is of type 5 */ + type: MessageComponentTypes.SelectMenuUsers; + /** A custom identifier for this component. Maximum 100 characters. */ + customId: string; + /** A custom placeholder text if nothing is selected. Maximum 150 characters. */ + placeholder?: string; + /** The minimum number of items that must be selected. Default 1. Between 1-25. */ + minValues?: number; + /** The maximum number of items that can be selected. Default 1. Between 1-25. */ + maxValues?: number; + /** Whether or not this select is disabled */ + disabled?: boolean; +} + +export interface SelectMenuRolesComponent { + /** SelectMenuChannels Component is of type 6 */ + type: MessageComponentTypes.SelectMenuRoles; + /** A custom identifier for this component. Maximum 100 characters. */ + customId: string; + /** A custom placeholder text if nothing is selected. Maximum 150 characters. */ + placeholder?: string; + /** The minimum number of items that must be selected. Default 1. Between 1-25. */ + minValues?: number; + /** The maximum number of items that can be selected. Default 1. Between 1-25. */ + maxValues?: number; + /** Whether or not this select is disabled */ + disabled?: boolean; +} + +export interface SelectMenuUsersAndRolesComponent { + /** SelectMenuChannels Component is of type 7 */ + type: MessageComponentTypes.SelectMenuUsersAndRoles; + /** A custom identifier for this component. Maximum 100 characters. */ + customId: string; + /** A custom placeholder text if nothing is selected. Maximum 150 characters. */ + placeholder?: string; + /** The minimum number of items that must be selected. Default 1. Between 1-25. */ + minValues?: number; + /** The maximum number of items that can be selected. Default 1. Between 1-25. */ + maxValues?: number; + /** The choices! Maximum of 25 items. */ + options: SelectOption[]; + /** Whether or not this select is disabled */ + disabled?: boolean; +} + +export interface SelectMenuChannelsComponent { + /** SelectMenuChannels Component is of type 8 */ + type: MessageComponentTypes.SelectMenuChannels; + /** A custom identifier for this component. Maximum 100 characters. */ + customId: string; + /** A custom placeholder text if nothing is selected. Maximum 150 characters. */ + placeholder?: string; + /** The minimum number of items that must be selected. Default 1. Between 1-25. */ + minValues?: number; + /** The maximum number of items that can be selected. Default 1. Between 1-25. */ + maxValues?: number; + /** Whether or not this select is disabled */ + disabled?: boolean; +} + export interface SelectOption { /** The user-facing name of the option. Maximum 25 characters. */ label: string; diff --git a/types/shared.ts b/types/shared.ts index 84a082757..bb87c25d9 100644 --- a/types/shared.ts +++ b/types/shared.ts @@ -97,11 +97,19 @@ export enum MessageComponentTypes { /** A container for other components */ ActionRow = 1, /** A button object */ - Button = 2, + Button, /** A select menu for picking from choices */ - SelectMenu = 3, + SelectMenu, /** A text input object */ - InputText = 4, + InputText, + /** Select menu for users */ + SelectMenuUsers, + /** Select menu for roles */ + SelectMenuRoles, + /** Select menu for users and roles */ + SelectMenuUsersAndRoles, + /** Select menu for channels */ + SelectMenuChannels, } export enum TextStyles {