discordjs-choice-selectmenu-builder
Version:
An utility builder to represent arrays as paginated Discord select menus.
376 lines (372 loc) • 15.7 kB
text/typescript
import { Collection, ButtonStyle, Interaction, ActionRowBuilder, StringSelectMenuBuilder, ButtonBuilder } from 'discord.js';
declare class PageManager<T> {
constructor(array: T[], selected: Collection<number, T>, minChoices: number, maxChoices?: number, currentPage?: number);
/**
* The length that a single select menu page can have.
*/
length: number;
/**
* A reference to the array to paginate.
*/
array: T[];
/**
* A reference to the selected elements.
*/
selected: Collection<number, T>;
/**
* The 0-indexed page the builder is currently on.
* This is always in the range `0 <= current <= max`
*/
current: number;
/**
* The minimum amount of choices that a user must make.
* Note that it only prevents selecting less than this value, it
* can still be visually shown without any selections.
*/
minChoices: number;
/**
* The maximum amount of choices that a user may make.
* This value defaults to `options.length`.
*/
maxChoices?: number;
get carrySelected(): boolean;
/**
* The maximum 0-indexed page the builder can reach.
* This property is derived from the page's length
*/
get max(): number;
getPage(pageNumber?: number): [index: number, element: T][];
/**
* Returns a slice of the array, along with its actual index location.
* @param start - The start of the slice.
* @param end - The end of the slice.
* @param removeSelected - Removes selected indeces from the sliced array.
*/
private getSlice;
/**
* Get the end index of the page starting from the start parameter.
* Will include more elements if the keys exist on the page.
* @param start - The offset to base the end index on.
* @param selectedIndeces - The selected indeces
*/
private getEndIndex;
first(): void;
previous(): void;
next(): void;
last(): void;
private hasFreePageMovement;
}
/**
* Represents a callback function that is passed to Array prototype methods such as
* `.map()`, `.filter()` and `.forEach()` .
*/
type ArrayCallback<T, ReturnValue> = (element: T, index: number, array: T[]) => ReturnValue;
type PageSelectComponent<ChoiceType> = {
/**
* The custom ID that this select menu uses.
*/
customId?: string;
/**
* A collection of selected values and the index they are found at.
* The key is used to ensure pagination is applied correctly
* The values represent the selected items of the array.
*/
selected: Collection<number, ChoiceType>;
/**
* The placeholder to display on the select menu.
*/
placeholder?: string | ((minChoices: number, maxChoices: number) => string);
/**
* The callback function to transform an array element into a readable
* label string. Note that discord's character limit on labels apply.
* @param option - An element from the `options` array.
* @param index - The element's index in the `options` array.
* @returns - A string that must be below Discord's character limit for
* select menu option labels.
* @see {@link https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-option-structure}
*/
labelFn: (option: ChoiceType, index: number) => string;
/**
* The callback function to transform an array element into a readable
* description string. Note that discord's character limit on descriptions apply.
* Will not create a description by default.
* @param option - An element from the `options` array.
* @param index - The element's index in the `options` array.
* @returns - A string that must be below Discord's character limit for
* select menu option descriptions.
* @see {@link https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-option-structure}
*/
descriptionFn?: (option: ChoiceType, index: number) => string;
/**
* Contains data related to pages and methods to change them.
*/
pages: PageManager<ChoiceType>;
/**
* The button style for the nagivator buttons, which include
* ⏮️,◀️,▶️, and ⏭️.
* Note that navigator buttons only show up if there are more
* options than the defined page length of this builder.
*/
navigatorStyle: Exclude<ButtonStyle, ButtonStyle.Link>;
/**
* The button style for the center button displaying the available
* pages.
* Note that navigator buttons only show up if there are more
* options than the defined page length of this builder.
*/
pageLabelStyle: Exclude<ButtonStyle, ButtonStyle.Link>;
};
type ChoiceSelectMenuBuilderLimits = {
/**
* The maximum amount of select menu options that
* discord accepts. As of Jan 26 2025, it is 25.
*/
MenuLength: 25;
/**
* The maximum amount of characters that an option label
* may have. As of Jan 26 2025, it is 100.
*/
OptionLabel: 100;
/**
* The maximum amount of characters that an option description
* may have. As of Jan 26 2025, it is 100.
*/
OptionDescription: 100;
};
/**
* The three types of Tuples that are generated
* by the UserChoiceComponent. It either includes
* only the select menu, or it also includes
* the page buttons. If there are no elements
* present, it will return empty.
*/
type PageSelectMenuActionRow = [] | [menu: ActionRowBuilder<StringSelectMenuBuilder>] | [
pageButtons: ActionRowBuilder<ButtonBuilder>,
menu: ActionRowBuilder<StringSelectMenuBuilder>
];
/**
* Represents the three main types of setting values as selected.
* - If the passed type is a function, that function will be called to set the values.
* - If the passed type is an array, it will default to `Array#includes()`.
* - Otherwise, `Object.is()` equality is used.
*/
type ChoiceSelectCallback<ChoiceType> = ChoiceType | ChoiceType[] | ArrayCallback<ChoiceType, boolean>;
declare class ChoiceSelectMenuBuilder<ChoiceType> {
/**
* Manages a select menu interface to select elements in an array.
* @param choices - The array of choices to represent.
* @param selected - A callback function that defines what values are chosen.
*/
constructor(choices: ChoiceType[], selected?: ChoiceSelectCallback<ChoiceType>);
/**
* Configure the discord limits that this builder uses.
* As they may change over the years, this provides a way to
* update them for compatability.
* @param config The config options to update to new values. If a property is omitted, it is
* reset to the initial value.
*/
static configureLimits(config: Partial<ChoiceSelectMenuBuilderLimits>): void;
/**
* The limits that Discord enforces on certain select menu related properties.
* Updated as of Jan 26, 2025.
*/
protected static DiscordLimits: ChoiceSelectMenuBuilderLimits;
protected static EnforceDiscordLimits: boolean;
/**
* Contains all data related to this builder instance.
*/
data: PageSelectComponent<ChoiceType>;
/**
* The reference to the array this builder represents.
*/
options: ChoiceType[];
/**
* Sets the custom ID of this builder.
* @param {string} customId - The custom ID to set
*/
setCustomId(customId: string): this;
/**
* Set the minimum amount of choices of this builder. Defaults to
* 0 for every new instance.
* @param amount - The minimum amount of choices to select in this menu.
*/
setMinChoices(amount: number): this;
/**
* Set the maximum amount of choices of this select menu.
* @param amount - The maximum amount of choices to select in this menu.
*/
setMaxChoices(amount: number): this;
/**
* Sets the callback function to transform an array element into a readable
* label string. Discord's label character limit applies.
* @param labelFn - The callback function to transform the element.
* The returned string must be below Discord's label character limit.
* @see {@link https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-option-structure}
*/
setLabel(labelFn: PageSelectComponent<ChoiceType>['labelFn']): this;
/**
* Sets the callback function to transform an array element into a readable
* description string. Discord's description character limit applies.
* Will not create a description by default.
* @param descriptionFn - The callback function to transform the element.
* The returned string must be below Discord's description character limit.
* @see {@link https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-option-structure}
*/
setDescription(descriptionFn: NonNullable<PageSelectComponent<ChoiceType>['descriptionFn']> | null): this;
/**
* Set the button styles for the navigator buttons.
* @param style - The style to apply on the navigator buttons.
*/
setNavigatorStyle(style: Exclude<ButtonStyle, ButtonStyle.Link>): this;
/**
* Set the button styles for the center button displaying the current page.
* @param style - The style to apply on the center button displaying the current page.
*/
setPageLabelStyle(style: Exclude<ButtonStyle, ButtonStyle.Link>): this;
/**
* Set the placeholder of this builder's select menu.
* @param placeholder - A static string to set as placeholder, or
* a callback function to dynamically set the placeholder. Passes
* the minimum and maximum choices of the current select menu.
*
* The placeholder must be below Discord's placeholder character limit.
* @see {@link https://discord.com/developers/docs/interactions/message-components#select-menu-object-select-menu-structure
*/
setPlaceholder(placeholder: string | ((minChoices: number, maxChoices: number) => string) | null): this;
/**
* Set the selected values of this builder.
* @param selected - A callback function or an object / array of objects to use.
* - If the passed type is a function, that function will be called to set the values.
* - If the passed type is an array, it will default to `Array#includes()`.
* - Otherwise, `Object.is()` equality is used.
*/
setValues(selected: ChoiceSelectCallback<ChoiceType>): this;
/**
* Add the selected values of this builder.
* @param selected - A callback function or an object / array of objects to use.
* - If the passed type is a function, that function will be called to set the values.
* - If the passed type is an array, it will default to `Array#includes()`.
* - Otherwise, `Object.is()` equality is used.
*/
addValues(selected: ChoiceSelectCallback<ChoiceType>): this;
/**
* Filters the selected values based on the provided function.
* @param valueFn - The callback function to use as filter. If this function
* returns false, the selected value is removed from this menu.
*/
filterValues(valueFn: (value: ChoiceType, index: number) => boolean): this;
/**
* Clears all selected values from this menu.
*/
clearValues(): this;
/**
* Removes the last selected value and returns it.
* If there are no selected values, it will return undefined.
*
* This value may be undefined even if `minChoices > 0`.
*/
popValue(): ChoiceType | undefined;
/**
* Returns a shallow copy of options that are visible on the current page.
* If no page is specified, it will return the current page.
* @param page - The page to fetch options from.
*/
optionsOnPage(page?: number): ChoiceType[];
/**
* Determines the selected values on the current page. If no
* parameter is provided, it will take the current page.
*
* Note that if `minChoices > 0`, selected values will always exist on the page.
* @param page - The page to fetch the selected options from.
*/
selectedOnPage(onPage?: number): ChoiceType[];
/**
* The selected values of this select menu.
* Returns a shallow copy of the provided choices.
* If you only need the first property, consider using
* {@link ChoiceSelectMenuBuilder#firstValue}
*
* This array may be empty even if `minChoices > 0`.
*/
get values(): ChoiceType[];
/**
* The first selected value of this select menu.
*
* This value may be undefined even if `minChoices > 0`.
*/
get firstValue(): ChoiceType | undefined;
/**
* Provides default function behaviour for non-functions passed to
* methods.
* ```
* const selected = [1, 2, 3];
* selectMenu.narrowSelectCallback(selected) // this is now (v) => selected.includes(v)
* ```
* @param selected - The provided value or function to narrow down into a select function.
* @returns - A function callback that can be used in `Array.prototype.filter()` and the like.
*/
private narrowSelectCallback;
/**
* Changes the paginated menu to the first page. If the maximum
* amount of choices has been reached, it only skips to pages with
* selections on it.
*/
toFirstPage(): this;
/**
* Changes the paginated menu to the previous page. If the maximum
* amount of choices has been reached, only skips to pages with
* selections on it.
*/
toPreviousPage(): this;
/**
* Changes the paginated menu to the next page. If the maximum
* amount of choices has been reached, only skips to pages with
* selections on it.
*/
toNextPage(): this;
/**
* Changes the paginated menu to the last page. If the maximum
* amount of choices has been reached, it only skips to pages with
* selections on it.
*/
toLastPage(): this;
/**
* Creates the action row based on this builder.
* If the `choices` array is empty, no select menu will be generated.
* If the array exceeds discord's limit for select menus,
* a second row of page buttons will be passed.
*/
toActionRow(): PageSelectMenuActionRow;
/**
* Determines whether or not the interaction belongs to this builder.
* If the interaction belongs to this builder, it handles the received
* interaction response.
* @param interaction - The component interaction response to check
*/
isInteraction(interaction: Interaction): boolean;
/**
* Determines whether or not the interaction belongs to this builder.
* @param interaction - The interaction to narrow
*/
private hasComponent;
/**
* Parses an array of values (from a select menu)
* into the selected values. This assumes that the StringSelectMenuInteraction
* belongs to this ChoiceSelectMenuBuilder. If that assumption is not met or there
* is some issue with the custom IDs, they will be filtered out.
* @param values - The values to transform into selected values.
*/
private updateSelectedFromValues;
/**
* Transforms the provided option into a usable API Select Menu Option.
* @param row - The row to transform, including its index and element.
*/
private toAPISelectMenuOption;
/**
* Generates the page buttons for the currently selected page.
* Disables buttons dependent on what page the user is on and
* how many choices are remaining.
*/
private get navigatorButtons();
}
export { type ArrayCallback, type ChoiceSelectCallback, ChoiceSelectMenuBuilder };