refactor: rendering button
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import { Button } from "../src/main.js"
|
import { Button } from "../src.new/components/button.js"
|
||||||
|
|
||||||
export function Counter() {
|
export function Counter() {
|
||||||
const [count, setCount] = React.useState(0)
|
const [count, setCount] = React.useState(0)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
this button was clicked {count} times
|
this button was clicked {count} times
|
||||||
<Button onClick={() => setCount(count + 1)}>clicc</Button>
|
<Button label="clicc" onClick={() => setCount(count + 1)} />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { Client } from "discord.js"
|
import { Client } from "discord.js"
|
||||||
import "dotenv/config"
|
import "dotenv/config"
|
||||||
|
import React from "react"
|
||||||
import { InstanceManager } from "../src.new/main.js"
|
import { InstanceManager } from "../src.new/main.js"
|
||||||
import { createCommandHandler } from "./command-handler.js"
|
import { createCommandHandler } from "./command-handler.js"
|
||||||
|
import { Counter } from "./counter.js"
|
||||||
|
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
intents: ["GUILDS"],
|
intents: ["GUILDS"],
|
||||||
@@ -14,7 +16,7 @@ createCommandHandler(client, [
|
|||||||
name: "counter",
|
name: "counter",
|
||||||
description: "shows a counter button",
|
description: "shows a counter button",
|
||||||
run: (interaction) => {
|
run: (interaction) => {
|
||||||
manager.create(interaction).render("hi world")
|
manager.create(interaction).render(<Counter />)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|||||||
28
src.new/components/button.tsx
Normal file
28
src.new/components/button.tsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import type {
|
||||||
|
EmojiResolvable,
|
||||||
|
MessageButtonStyle,
|
||||||
|
MessageComponentInteraction,
|
||||||
|
} from "discord.js"
|
||||||
|
import React from "react"
|
||||||
|
import { Node } from "../node.js"
|
||||||
|
|
||||||
|
export type ButtonProps = {
|
||||||
|
label?: string
|
||||||
|
style?: Exclude<Lowercase<MessageButtonStyle>, "link">
|
||||||
|
disabled?: boolean
|
||||||
|
emoji?: EmojiResolvable
|
||||||
|
onClick?: (interaction: MessageComponentInteraction) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ButtonTag = "reacord-button"
|
||||||
|
|
||||||
|
export function Button(props: ButtonProps) {
|
||||||
|
return React.createElement(ButtonTag, props)
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ButtonNode extends Node {
|
||||||
|
readonly name = "button"
|
||||||
|
constructor(public props: ButtonProps) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import type { ReactNode } from "react"
|
|
||||||
import React from "react"
|
|
||||||
|
|
||||||
export type TextProps = {
|
|
||||||
children?: ReactNode
|
|
||||||
}
|
|
||||||
|
|
||||||
export const TextTag = "reacord-text"
|
|
||||||
|
|
||||||
export function Text(props: TextProps) {
|
|
||||||
return React.createElement(TextTag, props)
|
|
||||||
}
|
|
||||||
|
|
||||||
export class TextElementNode {}
|
|
||||||
14
src.new/jsx.d.ts
vendored
Normal file
14
src.new/jsx.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import type { ReactNode } from "react"
|
||||||
|
import type { Node } from "./node"
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
namespace JSX {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
||||||
|
interface IntrinsicElements {
|
||||||
|
"reacord-element": {
|
||||||
|
createNode: () => Node
|
||||||
|
children?: ReactNode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src.new/node.ts
Normal file
3
src.new/node.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export abstract class Node {
|
||||||
|
abstract get name(): string
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import type { HostConfig } from "react-reconciler"
|
import type { HostConfig } from "react-reconciler"
|
||||||
import ReactReconciler from "react-reconciler"
|
import ReactReconciler from "react-reconciler"
|
||||||
import { raise } from "../src/helpers/raise.js"
|
import { raise } from "../src/helpers/raise.js"
|
||||||
|
import { ButtonNode } from "./components/button.js"
|
||||||
|
import type { Node } from "./node.js"
|
||||||
import type { RootNode } from "./root-node.js"
|
import type { RootNode } from "./root-node.js"
|
||||||
import { TextNode } from "./text-node.js"
|
import { TextNode } from "./text-node.js"
|
||||||
|
|
||||||
@@ -8,7 +10,7 @@ const config: HostConfig<
|
|||||||
string, // Type,
|
string, // Type,
|
||||||
Record<string, unknown>, // Props,
|
Record<string, unknown>, // Props,
|
||||||
RootNode, // Container,
|
RootNode, // Container,
|
||||||
never, // Instance,
|
Node, // Instance,
|
||||||
TextNode, // TextInstance,
|
TextNode, // TextInstance,
|
||||||
never, // SuspenseInstance,
|
never, // SuspenseInstance,
|
||||||
never, // HydratableInstance,
|
never, // HydratableInstance,
|
||||||
@@ -32,7 +34,10 @@ const config: HostConfig<
|
|||||||
getRootHostContext: () => ({}),
|
getRootHostContext: () => ({}),
|
||||||
getChildHostContext: () => ({}),
|
getChildHostContext: () => ({}),
|
||||||
|
|
||||||
createInstance: () => raise("not implemented"),
|
createInstance: (type, props) => {
|
||||||
|
if (type === "reacord-button") return new ButtonNode(props)
|
||||||
|
raise(`Unknown type: ${type}`)
|
||||||
|
},
|
||||||
createTextInstance: (text) => new TextNode(text),
|
createTextInstance: (text) => new TextNode(text),
|
||||||
shouldSetTextContent: () => false,
|
shouldSetTextContent: () => false,
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,21 @@
|
|||||||
import type { CommandInteraction, MessageOptions } from "discord.js"
|
import type { CommandInteraction, MessageOptions } from "discord.js"
|
||||||
import type { TextNode } from "./text-node.js"
|
import { MessageActionRow } from "discord.js"
|
||||||
|
import { nanoid } from "nanoid"
|
||||||
|
import { last } from "../src/helpers/last.js"
|
||||||
|
import { toUpper } from "../src/helpers/to-upper.js"
|
||||||
|
import { ButtonNode } from "./components/button.js"
|
||||||
|
import { Node } from "./node.js"
|
||||||
|
import { TextNode } from "./text-node.js"
|
||||||
|
|
||||||
export class RootNode {
|
export class RootNode extends Node {
|
||||||
private children = new Set<TextNode>()
|
readonly name = "root"
|
||||||
|
private children = new Set<Node>()
|
||||||
|
|
||||||
constructor(private interaction: CommandInteraction) {}
|
constructor(private interaction: CommandInteraction) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
add(child: TextNode) {
|
add(child: Node) {
|
||||||
this.children.add(child)
|
this.children.add(child)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14,7 +23,7 @@ export class RootNode {
|
|||||||
this.children.clear()
|
this.children.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(child: TextNode) {
|
remove(child: Node) {
|
||||||
this.children.delete(child)
|
this.children.delete(child)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,13 +31,37 @@ export class RootNode {
|
|||||||
this.interaction.reply(this.getMessageOptions()).catch(console.error)
|
this.interaction.reply(this.getMessageOptions()).catch(console.error)
|
||||||
}
|
}
|
||||||
|
|
||||||
getMessageOptions() {
|
private getMessageOptions(): MessageOptions {
|
||||||
const options: MessageOptions = {}
|
let content = ""
|
||||||
|
let components: MessageActionRow[] = []
|
||||||
|
|
||||||
for (const child of this.children) {
|
for (const child of this.children) {
|
||||||
options.content = (options.content ?? "") + child.text
|
if (child instanceof TextNode) {
|
||||||
|
content += child.text
|
||||||
}
|
}
|
||||||
|
|
||||||
return options
|
if (child instanceof ButtonNode) {
|
||||||
|
let actionRow = last(components)
|
||||||
|
if (
|
||||||
|
!actionRow ||
|
||||||
|
actionRow.components.length >= 5 ||
|
||||||
|
actionRow.components[0]?.type === "SELECT_MENU"
|
||||||
|
) {
|
||||||
|
actionRow = new MessageActionRow()
|
||||||
|
components.push(actionRow)
|
||||||
|
}
|
||||||
|
|
||||||
|
actionRow.addComponents({
|
||||||
|
type: "BUTTON",
|
||||||
|
customId: nanoid(),
|
||||||
|
style: toUpper(child.props.style ?? "secondary"),
|
||||||
|
disabled: child.props.disabled,
|
||||||
|
emoji: child.props.emoji,
|
||||||
|
label: child.props.label,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { content, components }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
export class TextNode {
|
import { Node } from "./node.js"
|
||||||
constructor(public text: string) {}
|
|
||||||
|
export class TextNode extends Node {
|
||||||
|
readonly name = "text"
|
||||||
|
constructor(public text: string) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user