Skip to content

Commit

Permalink
Refactor for Sapphire v4 (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
killbasa committed Jan 8, 2023
1 parent 54e9137 commit 90f81d7
Show file tree
Hide file tree
Showing 10 changed files with 365 additions and 332 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module.exports = {
tsconfigRootDir: __dirname,
},
rules: {
'@typescript-eslint/require-await': 0,
'@typescript-eslint/no-base-to-string': 0,
'@typescript-eslint/member-ordering': 0
}
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/cd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ name: CD
on:
push:
tags:
- '@kbotdev/*@*.*.*'
- '@kbotdev/*@[0-9]+.[0-9]+.[0-9]+'

jobs:
release:
name: Release
runs-on: ubuntu-latest

if: ${{ github.repository_owner == 'kbot-discord' && github.ref == 'refs/heads/main' }}
if: github.repository_owner == 'kbot-discord'

permissions:
contents: write
Expand All @@ -35,7 +35,7 @@ jobs:
name: Publish
runs-on: ubuntu-latest

if: ${{ github.repository_owner == 'kbot-discord' && github.ref == 'refs/heads/main' }}
if: github.repository_owner == 'kbot-discord'

strategy:
fail-fast: false
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,24 @@
"devDependencies": {
"@microsoft/tsdoc": "^0.14.2",
"@sapphire/eslint-config": "^4.3.8",
"@sapphire/framework": "^3.1.4",
"@sapphire/framework": "^4.0.0",
"@sapphire/prettier-config": "^1.4.4",
"@sapphire/ts-config": "^3.3.4",
"@types/node": "^18.11.18",
"@typescript-eslint/eslint-plugin": "^5.48.0",
"@typescript-eslint/parser": "^5.48.0",
"@vitest/coverage-c8": "^0.26.3",
"discord-api-types": "^0.33.5",
"discord.js": "^13.12.0",
"discord-api-types": "^0.37.26",
"discord.js": "^14.7.1",
"eslint": "^8.31.0",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-prettier": "^4.2.1",
"husky": "^8.0.3",
"lint-staged": "^13.1.0",
"prettier": "^2.8.1",
"prettier": "^2.8.2",
"tsup": "^6.5.0",
"turbo": "^1.6.3",
"typedoc": "^0.23.23",
"typedoc": "^0.23.24",
"typescript": "^4.9.4",
"vitest": "^0.26.3"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/custom-id/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"@microsoft/tsdoc": "^0.14.2",
"@vitest/coverage-c8": "^0.26.3",
"tsup": "^6.5.0",
"typedoc": "^0.23.23",
"typedoc": "^0.23.24",
"typescript": "^4.9.4",
"vitest": "^0.26.3"
},
Expand Down
7 changes: 3 additions & 4 deletions packages/menus/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,14 @@
},
"homepage": "https://github.com/KBot-discord/utilities/tree/main/packages/menus",
"dependencies": {
"@sapphire/discord.js-utilities": "^5.1.2",
"discord.js": "^13.12.0",
"tslib": "^2.4.1"
"@sapphire/discord.js-utilities": "^6.0.0",
"discord.js": "^14.7.1"
},
"devDependencies": {
"@microsoft/tsdoc": "^0.14.2",
"@vitest/coverage-c8": "^0.26.3",
"tsup": "^6.5.0",
"typedoc": "^0.23.23",
"typedoc": "^0.23.24",
"typescript": "^4.9.4",
"vitest": "^0.26.3"
},
Expand Down
118 changes: 62 additions & 56 deletions packages/menus/src/lib/structures/Menu.ts
Original file line number Diff line number Diff line change
@@ -1,81 +1,87 @@
import {
type NonModalInteraction,
type AnyInteractableInteraction,
isAnyInteraction,
safelyReplyToInteraction,
isMessageInstance,
isGuildBasedChannel
isGuildBasedChannel,
safelyReplyToInteraction
} from '@sapphire/discord.js-utilities';
import type { APIMessage } from 'discord-api-types/v10';
import {
type SelectMenuComponentOptionData,
ActionRowBuilder,
ButtonBuilder,
StringSelectMenuBuilder,
ButtonStyle,
ComponentType,
type User,
userMention,
type APIMessage,
type Message,
InteractionCollector,
type MessageComponentInteraction,
type User,
type ButtonInteraction,
type StringSelectMenuInteraction,
type WebhookEditMessageOptions,
type MessageOptions,
type InteractionReplyOptions,
type BaseMessageOptions,
type TextBasedChannel,
Constants,
type ButtonInteraction,
type SelectMenuInteraction,
InteractionType,
type Collection,
type Snowflake,
Formatters,
MessageSelectMenu,
MessageActionRow,
MessageButton,
MessageSelectOptionData
type Snowflake
} from 'discord.js';
import type {
MenuPageRowUnion,
MenuArrowFunction,
MenuSelectMenuOptionsFunction,
MenuStopReasons,
MenuWrongUserInteractionReplyFunction,
MenuPage,
MenuOptions,
MenuArrowFunction
MenuStopReasons
} from '../types/MenuPageTypes';
import { isFunction, isNullOrUndefined, isObject } from '../util';
import { MenuPageBuilder } from './MenuPageBuilder';
import { MenuPagesBuilder } from './MenuPagesBuilder';

export class Menu {
public static defaultRows(options: MessageSelectOptionData[], placeholder?: string): MessageActionRow[] {
public static defaultRows(
options: SelectMenuComponentOptionData[],
placeholder?: string
): ActionRowBuilder<ButtonBuilder | StringSelectMenuBuilder>[] {
return [
new MessageActionRow().setComponents([
new MessageButton({
new ActionRowBuilder<MenuPageRowUnion>().setComponents([
new ButtonBuilder({
customId: '@kbotdev/menus.firstPage',
style: 'PRIMARY',
style: ButtonStyle.Primary,
emoji: '⏪',
type: Constants.MessageComponentTypes.BUTTON
type: ComponentType.Button
}),
new MessageButton({
new ButtonBuilder({
customId: '@kbotdev/menus.previousPage',
style: 'PRIMARY',
style: ButtonStyle.Primary,
emoji: '◀️',
type: Constants.MessageComponentTypes.BUTTON
type: ComponentType.Button
}),
new MessageButton({
new ButtonBuilder({
customId: '@kbotdev/menus.nextPage',
style: 'PRIMARY',
style: ButtonStyle.Primary,
emoji: '▶️',
type: Constants.MessageComponentTypes.BUTTON
type: ComponentType.Button
}),
new MessageButton({
new ButtonBuilder({
customId: '@kbotdev/menus.goToLastPage',
style: 'PRIMARY',
style: ButtonStyle.Primary,
emoji: '⏩',
type: Constants.MessageComponentTypes.BUTTON
type: ComponentType.Button
}),
new MessageButton({
new ButtonBuilder({
customId: '@kbotdev/menus.stop',
style: 'DANGER',
style: ButtonStyle.Danger,
emoji: '⏹️',
type: Constants.MessageComponentTypes.BUTTON
type: ComponentType.Button
})
]),
new MessageActionRow().setComponents([
new MessageSelectMenu({
new ActionRowBuilder<MenuPageRowUnion>().setComponents([
new StringSelectMenuBuilder({
customId: '@kbotdev/menus.goToPage',
type: Constants.MessageComponentTypes.SELECT_MENU,
type: ComponentType.StringSelect,
options,
placeholder
})
Expand Down Expand Up @@ -119,18 +125,18 @@ export class Menu {
public static selectMenuOptions: MenuSelectMenuOptionsFunction = (pageIndex) => ({ label: `Page ${pageIndex}` });

public static wrongUserInteractionReply: MenuWrongUserInteractionReplyFunction = (targetUser: User) => ({
content: `This menu is only for ${Formatters.userMention(targetUser.id)}.`,
content: `This menu is only for ${userMention(targetUser.id)}.`,
ephemeral: true,
allowedMentions: { users: [], roles: [] }
});

public pages: MenuPage[] = [];

public rows: MessageActionRow[] = [];
public rows: ActionRowBuilder<MenuPageRowUnion>[] = [];

public response: APIMessage | Message | NonModalInteraction | null = null;
public response: APIMessage | Message | AnyInteractableInteraction | null = null;

public collector: InteractionCollector<MessageComponentInteraction> | null = null;
public collector: InteractionCollector<ButtonInteraction | StringSelectMenuInteraction> | null = null;

public index = 0;

Expand All @@ -157,17 +163,17 @@ export class Menu {
return this;
}

public setSharedRows(rows: MessageActionRow[]): this {
public setSharedRows(rows: ActionRowBuilder<MenuPageRowUnion>[]): this {
this.rows = [];
return this.addSharedRows([...rows]);
}

public addSharedRows(rows: MessageActionRow[]): this {
public addSharedRows(rows: ActionRowBuilder<MenuPageRowUnion>[]): this {
for (const row of rows) this.addSharedRow(row);
return this;
}

public addSharedRow(row: MessageActionRow): this {
public addSharedRow(row: ActionRowBuilder<MenuPageRowUnion>): this {
this.rows.push(row);
return this;
}
Expand Down Expand Up @@ -211,15 +217,15 @@ export class Menu {

this.pages[currentIndex] = builtPage;

const response = this.response as NonModalInteraction;
const response = this.response as AnyInteractableInteraction;
return response.editReply(builtPage);
}

public resolveMenuPageBuilder(builder: MenuPageBuilder | ((page: MenuPageBuilder) => MenuPageBuilder)): MenuPageBuilder {
return isFunction(builder) ? builder(new MenuPageBuilder()) : builder;
}

public async run(messageOrInteraction: Message | NonModalInteraction, target?: User): Promise<this> {
public async run(messageOrInteraction: Message | AnyInteractableInteraction, target?: User): Promise<this> {
target ??= isAnyInteraction(messageOrInteraction) ? messageOrInteraction.user : messageOrInteraction.author;

const menu = Menu.handlers.get(target.id);
Expand Down Expand Up @@ -251,7 +257,7 @@ export class Menu {
return this;
}

protected async setUpMessage(messageOrInteraction: Message | NonModalInteraction): Promise<void> {
protected async setUpMessage(messageOrInteraction: Message | AnyInteractableInteraction): Promise<void> {
if (this.pages.length > 1) {
const selectMenuOptions = await Promise.all(
this.pages.map(async (_, index) => {
Expand All @@ -278,7 +284,7 @@ export class Menu {
if (this.response.replied || this.response.deferred) {
await this.response.editReply(homePage as WebhookEditMessageOptions);
} else {
await this.response.reply(homePage as WebhookEditMessageOptions);
await this.response.reply(homePage as InteractionReplyOptions);
}
} else if (isMessageInstance(this.response)) {
await this.response.edit(homePage as WebhookEditMessageOptions);
Expand All @@ -291,12 +297,12 @@ export class Menu {
this.response = await messageOrInteraction.reply({ ...homePage, fetchReply: true, ephemeral: false });
}
} else {
this.response = await messageOrInteraction.channel.send(homePage as MessageOptions);
this.response = await messageOrInteraction.channel.send(homePage as BaseMessageOptions);
}
}

protected setUpCollector(channel: TextBasedChannel, targetUser: User): void {
this.collector = new InteractionCollector<MessageComponentInteraction>(targetUser.client, {
this.collector = new InteractionCollector<ButtonInteraction | StringSelectMenuInteraction>(targetUser.client, {
filter: (interaction) =>
!isNullOrUndefined(this.response) && //
interaction.isMessageComponent() &&
Expand All @@ -308,7 +314,7 @@ export class Menu {

channel,

interactionType: Constants.InteractionTypes.MESSAGE_COMPONENT,
interactionType: InteractionType.MessageComponent,

...(this.response && !isAnyInteraction(this.response)
? {
Expand All @@ -325,7 +331,7 @@ export class Menu {
return this.applyFooter(pageWithComponents, index);
}

protected async handleCollect(targetUser: User, interaction: ButtonInteraction | SelectMenuInteraction): Promise<void> {
protected async handleCollect(targetUser: User, interaction: ButtonInteraction | StringSelectMenuInteraction): Promise<void> {
if (interaction.user.id === targetUser.id) {
this.response = interaction;

Expand Down Expand Up @@ -361,7 +367,7 @@ export class Menu {
}
}

protected async handleEnd(_: Collection<Snowflake, ButtonInteraction | SelectMenuInteraction>, reason: MenuStopReasons): Promise<void> {
protected async handleEnd(_: Collection<Snowflake, ButtonInteraction | StringSelectMenuInteraction>, reason: MenuStopReasons): Promise<void> {
if (
(reason === 'time' || reason === 'idle') &&
this.response !== null &&
Expand Down Expand Up @@ -397,8 +403,8 @@ export class Menu {
const idx = page.embeds.length - 1;
const lastEmbed = page.embeds[idx];
if (lastEmbed) {
lastEmbed.footer ??= { text: '' };
lastEmbed.footer.text = `${index + 1} / ${this.pages.length}`;
lastEmbed.data.footer ??= { text: '' };
lastEmbed.data.footer.text = `${index + 1} / ${this.pages.length}`;
}

return { ...page, embeds: page.embeds };
Expand Down
Loading

0 comments on commit 90f81d7

Please sign in to comment.