diff --git a/integration/rendering.test.tsx b/integration/rendering.test.tsx index 170e940..521c3c5 100644 --- a/integration/rendering.test.tsx +++ b/integration/rendering.test.tsx @@ -5,7 +5,14 @@ import React from "react" import { omit } from "../src/helpers/omit.js" import { raise } from "../src/helpers/raise.js" import type { ReacordRoot } from "../src/main.js" -import { Button, createRoot, Embed, EmbedField, Text } from "../src/main.js" +import { + ActionRow, + Button, + createRoot, + Embed, + EmbedField, + Text, +} from "../src/main.js" import { testBotToken, testChannelId } from "./test-environment.js" const client = new Client({ @@ -121,6 +128,9 @@ test("kitchen sink", async () => { complex button text + + + , ) await assertMessages([ @@ -212,6 +222,17 @@ test("kitchen sink", async () => { }, ], }, + { + type: "ACTION_ROW", + components: [ + { + type: "BUTTON", + label: "new action row", + style: "SECONDARY", + disabled: false, + }, + ], + }, ], }, ]) diff --git a/src/action-row.tsx b/src/action-row.tsx new file mode 100644 index 0000000..b82be05 --- /dev/null +++ b/src/action-row.tsx @@ -0,0 +1,45 @@ +import type { + MessageActionRowComponentOptions, + MessageOptions, +} from "discord.js" +import React from "react" +import { ContainerInstance } from "./container-instance.js" + +export type ActionRowProps = { + children: React.ReactNode +} + +export function ActionRow(props: ActionRowProps) { + return ( + new ActionRowInstance()}> + {props.children} + + ) +} + +class ActionRowInstance extends ContainerInstance { + readonly name = "ActionRow" + + constructor() { + super({ warnOnNonTextChildren: false }) + } + + // eslint-disable-next-line class-methods-use-this + override renderToMessage(options: MessageOptions) { + const row = { + type: "ACTION_ROW" as const, + components: [] as MessageActionRowComponentOptions[], + } + + for (const child of this.children) { + if (!child.renderToActionRow) { + console.warn(`${child.name} is not an action row component`) + continue + } + child.renderToActionRow(row) + } + + options.components ??= [] + options.components.push(row) + } +} diff --git a/src/base-instance.ts b/src/base-instance.ts index d426db1..10187da 100644 --- a/src/base-instance.ts +++ b/src/base-instance.ts @@ -1,4 +1,8 @@ -import type { MessageEmbedOptions, MessageOptions } from "discord.js" +import type { + MessageActionRowOptions, + MessageEmbedOptions, + MessageOptions, +} from "discord.js" export abstract class BaseInstance { /** The name of the JSX element represented by this instance */ @@ -14,4 +18,8 @@ export abstract class BaseInstance { /** If this element can be a child of an embed, * the function to modify the embed options */ renderToEmbed?(options: MessageEmbedOptions): void + + /** If this element can be a child of an action row, + * the function to modify the action row options */ + renderToActionRow?(options: MessageActionRowOptions): void } diff --git a/src/button.tsx b/src/button.tsx index 6e942e2..04ac77b 100644 --- a/src/button.tsx +++ b/src/button.tsx @@ -2,6 +2,7 @@ import type { BaseMessageComponentOptions, EmojiResolvable, MessageActionRowOptions, + MessageButtonOptions, MessageButtonStyle, MessageOptions, } from "discord.js" @@ -36,6 +37,17 @@ class ButtonInstance extends ContainerInstance { super({ warnOnNonTextChildren: true }) } + private getButtonOptions(): Required & + MessageButtonOptions { + return { + ...pick(this.props, "emoji", "disabled"), + type: "BUTTON", + style: this.props.style ? toUpper(this.props.style) : "SECONDARY", + label: this.getChildrenText(), + customId: nanoid(), + } + } + override renderToMessage(options: MessageOptions) { options.components ??= [] @@ -56,12 +68,10 @@ class ButtonInstance extends ContainerInstance { options.components.push(actionRow) } - actionRow.components.push({ - ...pick(this.props, "emoji", "disabled"), - type: "BUTTON", - style: this.props.style ? toUpper(this.props.style) : "SECONDARY", - label: this.getChildrenText(), - customId: nanoid(), - }) + actionRow.components.push(this.getButtonOptions()) + } + + override renderToActionRow(row: MessageActionRowOptions) { + row.components.push(this.getButtonOptions()) } } diff --git a/src/main.ts b/src/main.ts index 7d56fd2..e9e235c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,7 @@ -export * from "./button" -export * from "./embed" -export * from "./embed-field" -export * from "./root" -export * from "./text" +/* eslint-disable import/no-unused-modules */ +export * from "./action-row.js" +export * from "./button.js" +export * from "./embed-field.js" +export * from "./embed.js" +export * from "./root.js" +export * from "./text.js"