feat(string-prompt): Adds string prompt to menu item
This commit is contained in:
parent
1d73ee8a78
commit
5c7c9c9f87
6 changed files with 164 additions and 26 deletions
|
|
@ -2,12 +2,21 @@ import {EventHandler} from "../Events/EventHandler";
|
|||
import {Container} from "../Container/Container";
|
||||
import {AnyMenuItem, MenuAction, MenuItemType, TraversalPath} from "./MenuRenderer.types";
|
||||
import {randomUUID} from "node:crypto";
|
||||
import {ActionRowBuilder, ButtonBuilder, ButtonStyle, CommandInteraction, EmbedBuilder, MessageFlags} from "discord.js";
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
ButtonStyle,
|
||||
CommandInteraction,
|
||||
EmbedBuilder,
|
||||
MessageComponentInteraction,
|
||||
MessageFlags
|
||||
} from "discord.js";
|
||||
import {Nullable} from "../types/Nullable";
|
||||
import {IconCache} from "../Icons/IconCache";
|
||||
import {MessageActionRowComponentBuilder} from "@discordjs/builders";
|
||||
import {ComponentInteractionEvent} from "../Events/ComponentInteractionEvent";
|
||||
import {MenuTraversal} from "./MenuTraversal";
|
||||
import {Prompt} from "./Modals/Prompt";
|
||||
|
||||
export class MenuRenderer {
|
||||
private readonly menuId: string;
|
||||
|
|
@ -15,6 +24,10 @@ export class MenuRenderer {
|
|||
|
||||
private exitButton: ButtonBuilder;
|
||||
private backButton: ButtonBuilder;
|
||||
private static MAX_BUTTON_PER_ROW = 5;
|
||||
private static MAX_ROWS = 5;
|
||||
private static SYSTEM_ROW_COUNT = 1;
|
||||
private static MAX_USER_ROW_COUNT = MenuRenderer.MAX_ROWS - MenuRenderer.SYSTEM_ROW_COUNT;
|
||||
|
||||
constructor(
|
||||
private readonly traversal: MenuTraversal,
|
||||
|
|
@ -62,26 +75,38 @@ export class MenuRenderer {
|
|||
}
|
||||
|
||||
const rows = [
|
||||
this.getComponentForMenuItem(this.traversal.currentMenuItem),
|
||||
...this.getComponentForMenuItem(this.traversal.currentMenuItem),
|
||||
navigation
|
||||
];
|
||||
|
||||
return rows.filter(row => row.components.length > 0);
|
||||
}
|
||||
|
||||
private getComponentForMenuItem(menuItem: AnyMenuItem): ActionRowBuilder<MessageActionRowComponentBuilder> {
|
||||
private getComponentForMenuItem(menuItem: AnyMenuItem): ActionRowBuilder<MessageActionRowComponentBuilder>[] {
|
||||
if (menuItem.type === MenuItemType.Collection) {
|
||||
const navigation = new ActionRowBuilder<ButtonBuilder>();
|
||||
navigation.setComponents(
|
||||
...menuItem.children.map(item => new ButtonBuilder()
|
||||
.setLabel(item.label)
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
.setCustomId(this.getInteractionId("MOVE", item.traversalKey))
|
||||
.setEmoji(this.iconCache?.get(item.type === MenuItemType.Field ? 'pen_solid' : "folder_solid") ?? '')
|
||||
)
|
||||
)
|
||||
const rowCount = Math.ceil(menuItem.children.length / MenuRenderer.MAX_BUTTON_PER_ROW);
|
||||
if (rowCount > MenuRenderer.MAX_USER_ROW_COUNT) {
|
||||
throw new TypeError(
|
||||
`A collection can only have a max of ${MenuRenderer.MAX_USER_ROW_COUNT * MenuRenderer.MAX_BUTTON_PER_ROW} entries!`
|
||||
);
|
||||
}
|
||||
|
||||
return navigation
|
||||
return Array.from(Array(rowCount).keys())
|
||||
.map((index) => {
|
||||
const childStart = index * MenuRenderer.MAX_BUTTON_PER_ROW;
|
||||
return menuItem.children.toSpliced(childStart, MenuRenderer.MAX_BUTTON_PER_ROW);
|
||||
})
|
||||
.reverse()
|
||||
.map((items) => new ActionRowBuilder<ButtonBuilder>()
|
||||
.setComponents(
|
||||
...items.map(item => new ButtonBuilder()
|
||||
.setLabel(item.label)
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
.setCustomId(this.getInteractionId("MOVE", item.traversalKey))
|
||||
.setEmoji(this.iconCache?.get(item.type === MenuItemType.Field ? 'pen_solid' : "folder_solid") ?? '')
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (menuItem.type === MenuItemType.Field) {
|
||||
|
|
@ -89,10 +114,10 @@ export class MenuRenderer {
|
|||
path: this.traversal.path
|
||||
})
|
||||
action.setCustomId(this.getInteractionId("SET", this.traversal.stringifiedPath));
|
||||
return new ActionRowBuilder<MessageActionRowComponentBuilder>().setComponents([action]);
|
||||
return [new ActionRowBuilder<MessageActionRowComponentBuilder>().setComponents([action])];
|
||||
}
|
||||
|
||||
return new ActionRowBuilder();
|
||||
return [new ActionRowBuilder()];
|
||||
}
|
||||
|
||||
private getEmbed(): EmbedBuilder {
|
||||
|
|
@ -120,7 +145,7 @@ export class MenuRenderer {
|
|||
return `${this.menuId};${action};${parameter ?? ''}`
|
||||
}
|
||||
|
||||
private handleUIEvents(ev: ComponentInteractionEvent) {
|
||||
private async handleUIEvents(ev: ComponentInteractionEvent) {
|
||||
if (!ev.interaction.customId.startsWith(this.menuId)) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -154,7 +179,38 @@ export class MenuRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
ev.interaction.update({
|
||||
let updateInteraction: unknown = ev.interaction;
|
||||
|
||||
if (this.traversal.currentMenuItem.type === MenuItemType.Prompt) {
|
||||
const prompt = new Prompt(<EventHandler>this.eventHandler);
|
||||
|
||||
const currentValue = this.traversal.currentMenuItem;
|
||||
const currentValuePath = [...this.traversal.path];
|
||||
|
||||
const row = currentValue.getActionRowBuilder({
|
||||
path: currentValuePath
|
||||
});
|
||||
row.setLabel(currentValue.label);
|
||||
row.setValue(currentValue.getCurrentValue({path: currentValuePath}));
|
||||
row.setPlaceholder(currentValue.description ?? '');
|
||||
|
||||
this.traversal.travelBack();
|
||||
const value = await prompt.requestValue(
|
||||
this.traversal.currentMenuItem.label,
|
||||
row,
|
||||
ev.interaction
|
||||
);
|
||||
|
||||
currentValue.setValue(
|
||||
value.value,
|
||||
{
|
||||
path: currentValuePath
|
||||
}
|
||||
)
|
||||
updateInteraction = value.interaction;
|
||||
}
|
||||
|
||||
updateInteraction.update({
|
||||
components: this.getActionRows(),
|
||||
embeds: [ this.getEmbed() ]
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue