action row component

This commit is contained in:
MapleLeaf
2021-12-21 23:47:42 -06:00
parent f53c6dba22
commit 7b3ce42138
5 changed files with 100 additions and 14 deletions

View File

@@ -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 <Text>button</Text> text
</Button>
<Button disabled>disabled button</Button>
<ActionRow>
<Button>new action row</Button>
</ActionRow>
</>,
)
await assertMessages([
@@ -212,6 +222,17 @@ test("kitchen sink", async () => {
},
],
},
{
type: "ACTION_ROW",
components: [
{
type: "BUTTON",
label: "new action row",
style: "SECONDARY",
disabled: false,
},
],
},
],
},
])

45
src/action-row.tsx Normal file
View File

@@ -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 (
<reacord-element createInstance={() => new ActionRowInstance()}>
{props.children}
</reacord-element>
)
}
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)
}
}

View File

@@ -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
}

View File

@@ -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<BaseMessageComponentOptions> &
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())
}
}

View File

@@ -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"