Files
discord.js/packages/builders/src/components/checkbox/CheckboxGroup.ts

175 lines
5.2 KiB
TypeScript

import type { APICheckboxGroupComponent, APICheckboxGroupOption } from 'discord-api-types/v10';
import { ComponentType } from 'discord-api-types/v10';
import type { RestOrArray } from '../../util/normalizeArray';
import { normalizeArray } from '../../util/normalizeArray';
import { ComponentBuilder } from '../Component';
import { checkboxGroupOptionPredicate, checkboxGroupPredicate } from './Assertions';
import { CheckboxGroupOptionBuilder } from './CheckboxGroupOption';
/**
* A builder that creates API-compatible JSON data for checkbox groups.
*/
export class CheckboxGroupBuilder extends ComponentBuilder<APICheckboxGroupComponent> {
/**
* The options within this checkbox group.
*/
public readonly options: CheckboxGroupOptionBuilder[];
/**
* Creates a new checkbox group from API data.
*
* @param data - The API data to create this checkbox group with
* @example
* Creating a checkbox group from an API data object:
* ```ts
* const checkboxGroup = new CheckboxGroupBuilder({
* custom_id: 'select_options',
* options: [
* { label: 'Option 1', value: 'option_1' },
* { label: 'Option 2', value: 'option_2' },
* ],
* });
* ```
* @example
* Creating a checkbox group using setters and API data:
* ```ts
* const checkboxGroup = new CheckboxGroupBuilder()
* .setCustomId('choose_items')
* .setOptions([
* { label: 'Item A', value: 'item_a' },
* { label: 'Item B', value: 'item_b' },
* ])
* .setMinValues(1)
* .setMaxValues(2);
* ```
*/
public constructor(data?: Partial<APICheckboxGroupComponent>) {
const { options, ...initData } = data ?? {};
super({ ...initData, type: ComponentType.CheckboxGroup });
this.options = options?.map((option: APICheckboxGroupOption) => new CheckboxGroupOptionBuilder(option)) ?? [];
}
/**
* Sets the custom id of this checkbox group.
*
* @param customId - The custom id to use
*/
public setCustomId(customId: string) {
this.data.custom_id = customId;
return this;
}
/**
* Adds options to this checkbox group.
*
* @param options - The options to add
*/
public addOptions(...options: RestOrArray<APICheckboxGroupOption | CheckboxGroupOptionBuilder>) {
const normalizedOptions = normalizeArray(options);
this.options.push(
...normalizedOptions.map((normalizedOption) => {
// I do this because TS' duck typing causes issues,
// if I put in a RadioGroupOption, TS lets it pass but
// it fails to convert to a checkbox group option at runtime
const json = 'toJSON' in normalizedOption ? normalizedOption.toJSON() : normalizedOption;
const option = new CheckboxGroupOptionBuilder(json);
checkboxGroupOptionPredicate.parse(option.toJSON());
return option;
}),
);
return this;
}
/**
* Sets the options for this checkbox group.
*
* @param options - The options to use
*/
public setOptions(...options: RestOrArray<APICheckboxGroupOption | CheckboxGroupOptionBuilder>) {
return this.spliceOptions(0, this.options.length, ...options);
}
/**
* Removes, replaces, or inserts options for this checkbox group.
*
* @remarks
* This method behaves similarly
* to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.
* It's useful for modifying and adjusting the order of existing options.
* @param index - The index to start at
* @param deleteCount - The number of options to remove
* @param options - The replacing option objects or builders
*/
public spliceOptions(
index: number,
deleteCount: number,
...options: RestOrArray<APICheckboxGroupOption | CheckboxGroupOptionBuilder>
) {
const normalizedOptions = normalizeArray(options);
const clone = [...this.options];
clone.splice(
index,
deleteCount,
...normalizedOptions.map((normalizedOption) => {
// I do this because TS' duck typing causes issues,
// if I put in a RadioGroupOption, TS lets it pass but
// it fails to convert to a checkbox group option at runtime
const json = 'toJSON' in normalizedOption ? normalizedOption.toJSON() : normalizedOption;
const option = new CheckboxGroupOptionBuilder(json);
checkboxGroupOptionPredicate.parse(option.toJSON());
return option;
}),
);
this.options.splice(0, this.options.length, ...clone);
return this;
}
/**
* Sets the minimum number of options that must be selected.
*
* @param minValues - The minimum number of options that must be selected
*/
public setMinValues(minValues: number) {
this.data.min_values = minValues;
return this;
}
/**
* Sets the maximum number of options that can be selected.
*
* @param maxValues - The maximum number of options that can be selected
*/
public setMaxValues(maxValues: number) {
this.data.max_values = maxValues;
return this;
}
/**
* Sets whether selecting options is required.
*
* @param required - Whether selecting options is required
*/
public setRequired(required: boolean) {
this.data.required = required;
return this;
}
/**
* {@inheritDoc ComponentBuilder.toJSON}
*/
public override toJSON(): APICheckboxGroupComponent {
const data = {
...this.data,
options: this.options.map((option) => option.toJSON()),
};
checkboxGroupPredicate.parse(data);
return data as APICheckboxGroupComponent;
}
}