Skip to content

Commit 31b46e1

Browse files
committed
feat: add button handling
1 parent 4271d1d commit 31b46e1

File tree

5 files changed

+77
-17
lines changed

5 files changed

+77
-17
lines changed

src/define.ts

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import {
22
ActionRowBuilder,
3-
type ModalActionRowComponentBuilder,
43
ModalBuilder,
54
TextInputBuilder,
65
EmbedBuilder,
76
AttachmentBuilder,
8-
type BufferResolvable
7+
type BufferResolvable,
8+
ButtonBuilder,
9+
ButtonStyle,
10+
type AnyComponentBuilder,
11+
type RestOrArray
912
} from 'discord.js'
1013
import type { Stream } from 'node:stream'
1114
import type {
15+
ButtonOptions,
1216
CommandConfig,
1317
CommandExecute,
1418
ContextMenuCallback,
@@ -123,6 +127,16 @@ export const definePrecondition: DefinePrecondition &
123127
return { name, callback }
124128
}
125129

130+
export const defineActionRow = <
131+
T extends AnyComponentBuilder = AnyComponentBuilder
132+
>(
133+
...components: RestOrArray<T>
134+
): ActionRowBuilder<T> => {
135+
const builder = new ActionRowBuilder<T>().addComponents(...components)
136+
137+
return builder
138+
}
139+
126140
export const defineModal = (options: ModalOptions): ModalBuilder => {
127141
const builder = new ModalBuilder()
128142
.setCustomId(options.id)
@@ -150,10 +164,7 @@ export const defineModal = (options: ModalOptions): ModalBuilder => {
150164
if (input.required) {
151165
inputBuilder.setRequired(input.required)
152166
}
153-
const row =
154-
new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(
155-
inputBuilder
156-
)
167+
const row = defineActionRow(inputBuilder)
157168

158169
builder.addComponents(row)
159170
}
@@ -189,3 +200,24 @@ export const defineEmbed = (options: EmbedOptions) => {
189200
export const defineAttachment = (args: BufferResolvable | Stream) => {
190201
return new AttachmentBuilder(args)
191202
}
203+
204+
export const defineButton = (options: ButtonOptions) => {
205+
const builder = new ButtonBuilder()
206+
.setCustomId(options.id)
207+
.setStyle(options.style ? ButtonStyle[options.style] : ButtonStyle.Primary)
208+
209+
if (options.label) {
210+
builder.setLabel(options.label)
211+
}
212+
if (options.emoji) {
213+
builder.setEmoji(options.emoji)
214+
}
215+
if (options.url) {
216+
builder.setURL(options.url)
217+
}
218+
if (options.disabled) {
219+
builder.setDisabled(options.disabled)
220+
}
221+
222+
return builder
223+
}

src/register.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@ export const registerEvents = (harmonix: Harmonix) => {
3434
event.callback(interaction)
3535
})
3636
})
37+
harmonix.client?.on(Events.InteractionCreate, (interaction) => {
38+
if (!interaction.isButton()) return
39+
const event = harmonix.events
40+
.filter((evt) => evt.options.type === 'button')
41+
.find((evt) => evt.options.name === interaction.customId)
42+
43+
if (!event) return
44+
ctx.call(harmonix, () => {
45+
event.callback(interaction)
46+
})
47+
})
3748
}
3849

3950
export const registerCommands = (harmonix: Harmonix) => {

src/resolve.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@ export const resolveEvent = (
3030
name: event.options.name || filename(_evtPath).split('.')[0],
3131
once: event.options.once || filename(_evtPath).endsWith('.once'),
3232
type:
33-
event.options.type || filename(dirname(_evtPath)) === 'modals'
34-
? 'modal'
35-
: undefined
33+
event.options.type ||
34+
((['modals', 'buttons'].includes(filename(dirname(_evtPath)))
35+
? filename(dirname(_evtPath)).slice(0, -1)
36+
: undefined) as EventOptions['type'])
3637
}
3738

3839
return { options, callback: event.callback }

src/types/events.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
import type { ClientEvents, ModalSubmitInteraction } from 'discord.js'
1+
import type {
2+
ButtonInteraction,
3+
ClientEvents,
4+
ModalSubmitInteraction
5+
} from 'discord.js'
26

37
export interface HarmonixEvents extends ClientEvents {
48
modal: [interaction: ModalSubmitInteraction]
9+
button: [interaction: ButtonInteraction]
510
}
611

712
export type EventCallback<Event extends keyof HarmonixEvents | any = any> = (
@@ -11,7 +16,7 @@ export type EventCallback<Event extends keyof HarmonixEvents | any = any> = (
1116
export interface EventOptions {
1217
name?: string
1318
once?: boolean
14-
type?: 'modal'
19+
type?: 'modal' | 'button'
1520
}
1621

1722
export type DefineEvent = <Event extends keyof HarmonixEvents = any>(

src/types/rich.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import {
2-
type ColorResolvable,
3-
type EmbedAuthorOptions,
4-
type EmbedFooterOptions,
5-
type APIEmbedField,
6-
type TextInputStyle
1+
import type {
2+
ColorResolvable,
3+
EmbedAuthorOptions,
4+
EmbedFooterOptions,
5+
APIEmbedField,
6+
TextInputStyle,
7+
ButtonStyle,
8+
ComponentEmojiResolvable
79
} from 'discord.js'
810

911
interface TextInput {
@@ -39,3 +41,12 @@ export interface EmbedOptions {
3941
export type EmbedSetters = {
4042
[K in keyof EmbedOptions]: (value: EmbedOptions[K]) => void
4143
}
44+
45+
export interface ButtonOptions {
46+
id: string
47+
label?: string
48+
style?: keyof typeof ButtonStyle
49+
emoji?: ComponentEmojiResolvable
50+
url?: string
51+
disabled?: boolean
52+
}

0 commit comments

Comments
 (0)