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

153 lines
4.6 KiB
TypeScript

import type { APIRadioGroupComponent, APIRadioGroupOption } 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 { radioGroupOptionPredicate, radioGroupPredicate } from './Assertions';
import { RadioGroupOptionBuilder } from './RadioGroupOption';
/**
* A builder that creates API-compatible JSON data for radio groups.
*/
export class RadioGroupBuilder extends ComponentBuilder<APIRadioGroupComponent> {
/**
* The options within this radio group.
*/
public readonly options: RadioGroupOptionBuilder[];
/**
* Creates a new radio group from API data.
*
* @param data - The API data to create this radio group with
* @example
* Creating a radio group from an API data object:
* ```ts
* const radioGroup = new RadioGroupBuilder({
* custom_id: 'select_options',
* options: [
* { label: 'Option 1', value: 'option_1' },
* { label: 'Option 2', value: 'option_2' },
* ],
* });
* ```
* @example
* Creating a radio group using setters and API data:
* ```ts
* const radioGroup = new RadioGroupBuilder()
* .setCustomId('choose_items')
* .setOptions([
* { label: 'Item A', value: 'item_a' },
* { label: 'Item B', value: 'item_b' },
* ])
* ```
*/
public constructor(data?: Partial<APIRadioGroupComponent>) {
const { options, ...initData } = data ?? {};
super({ ...initData, type: ComponentType.RadioGroup });
this.options = options?.map((option: APIRadioGroupOption) => new RadioGroupOptionBuilder(option)) ?? [];
}
/**
* Sets the custom id of this radio group.
*
* @param customId - The custom id to use
*/
public setCustomId(customId: string) {
this.data.custom_id = customId;
return this;
}
/**
* Adds options to this radio group.
*
* @param options - The options to add
*/
public addOptions(...options: RestOrArray<APIRadioGroupOption | RadioGroupOptionBuilder>) {
const normalizedOptions = normalizeArray(options);
this.options.push(
...normalizedOptions.map((normalizedOption) => {
// I do this because TS' duck typing causes issues,
// if I put in a CheckboxGroupOption, 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 RadioGroupOptionBuilder(json);
radioGroupOptionPredicate.parse(option.toJSON());
return option;
}),
);
return this;
}
/**
* Sets the options for this radio group.
*
* @param options - The options to use
*/
public setOptions(...options: RestOrArray<APIRadioGroupOption | RadioGroupOptionBuilder>) {
return this.spliceOptions(0, this.options.length, ...options);
}
/**
* Removes, replaces, or inserts options for this radio 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<APIRadioGroupOption | RadioGroupOptionBuilder>
) {
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 CheckboxGroupOption, TS lets it pass but
// it fails to convert to a radio group option at runtime
const json = 'toJSON' in normalizedOption ? normalizedOption.toJSON() : normalizedOption;
const option = new RadioGroupOptionBuilder(json);
radioGroupOptionPredicate.parse(option.toJSON());
return option;
}),
);
this.options.splice(0, this.options.length, ...clone);
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(): APIRadioGroupComponent {
const data = {
...this.data,
options: this.options.map((option) => option.toJSON()),
};
radioGroupPredicate.parse(data);
return data as APIRadioGroupComponent;
}
}