Merge pull request #43 from domin-mnd/main
This commit is contained in:
12
README.md
12
README.md
@@ -24,19 +24,21 @@ pnpm add reacord react discord.js
|
|||||||
|
|
||||||
<!-- prettier-ignore -->
|
<!-- prettier-ignore -->
|
||||||
```tsx
|
```tsx
|
||||||
import * as React from "react"
|
import { useState } from "react"
|
||||||
import { Embed, Button } from "reacord"
|
import { Embed, Button } from "reacord"
|
||||||
|
|
||||||
function Counter() {
|
function Counter() {
|
||||||
const [count, setCount] = React.useState(0)
|
const [count, setCount] = useState(0)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Embed title="Counter">
|
<Embed title="Counter">
|
||||||
This button has been clicked {count} times.
|
This button has been clicked {count} times.
|
||||||
</Embed>
|
</Embed>
|
||||||
<Button onClick={() => setCount(count + 1)}>
|
<Button
|
||||||
+1
|
label="+1"
|
||||||
</Button>
|
onClick={() => setCount(count + 1)}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { raise } from "@reacord/helpers/raise.js"
|
import { raise } from "@reacord/helpers/raise.js"
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
|
Embed,
|
||||||
|
EmbedField,
|
||||||
Link,
|
Link,
|
||||||
Option,
|
Option,
|
||||||
ReacordDiscordJs,
|
ReacordDiscordJs,
|
||||||
@@ -11,7 +13,6 @@ import type { TextChannel } from "discord.js"
|
|||||||
import { ChannelType, Client, IntentsBitField } from "discord.js"
|
import { ChannelType, Client, IntentsBitField } from "discord.js"
|
||||||
import "dotenv/config"
|
import "dotenv/config"
|
||||||
import { kebabCase } from "lodash-es"
|
import { kebabCase } from "lodash-es"
|
||||||
import * as React from "react"
|
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
|
|
||||||
const client = new Client({ intents: IntentsBitField.Flags.Guilds })
|
const client = new Client({ intents: IntentsBitField.Flags.Guilds })
|
||||||
@@ -53,9 +54,57 @@ await createTest("basic", (channel) => {
|
|||||||
reacord.createChannelMessage(channel).render("Hello, world!")
|
reacord.createChannelMessage(channel).render("Hello, world!")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
await createTest("readme counter", (channel) => {
|
||||||
|
interface EmbedCounterProps {
|
||||||
|
count: number
|
||||||
|
visible: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
function EmbedCounter({ count, visible }: EmbedCounterProps) {
|
||||||
|
if (!visible) return <></>
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Embed title="the counter">
|
||||||
|
<EmbedField name="is it even?">{count % 2 ? "no" : "yes"}</EmbedField>
|
||||||
|
</Embed>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Counter() {
|
||||||
|
const [showEmbed, setShowEmbed] = useState(false)
|
||||||
|
const [count, setCount] = useState(0)
|
||||||
|
const instance = useInstance()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
this button was clicked {count} times
|
||||||
|
<EmbedCounter count={count} visible={showEmbed} />
|
||||||
|
<Button
|
||||||
|
style="primary"
|
||||||
|
label="clicc"
|
||||||
|
onClick={() => setCount(count + 1)}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
style="secondary"
|
||||||
|
label={showEmbed ? "hide embed" : "show embed"}
|
||||||
|
onClick={() => setShowEmbed(!showEmbed)}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
style="danger"
|
||||||
|
label="deactivate"
|
||||||
|
onClick={() => instance.destroy()}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
reacord.createChannelMessage(channel).render(<Counter />)
|
||||||
|
})
|
||||||
|
|
||||||
await createTest("counter", (channel) => {
|
await createTest("counter", (channel) => {
|
||||||
const Counter = () => {
|
function Counter() {
|
||||||
const [count, setCount] = React.useState(0)
|
const [count, setCount] = useState(0)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
count: {count}
|
count: {count}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ slug: getting-started
|
|||||||
|
|
||||||
# Getting Started
|
# Getting Started
|
||||||
|
|
||||||
These guides assume some familiarity with [JavaScript](https://developer.mozilla.org/en-US/docs/Web/javascript), [React](https://reactjs.org), [Discord.js](https://discord.js.org) and the [Discord API](https://discord.dev). Keep these pages as reference if you need it.
|
These guides assume some familiarity with [JavaScript](https://developer.mozilla.org/en-US/docs/Web/javascript), [TypeScript](https://www.typescriptlang.org/), [React](https://reactjs.org), [Discord.js](https://discord.js.org) and the [Discord API](https://discord.dev). Keep these pages as reference if you need it.
|
||||||
|
|
||||||
## Setup from template
|
## Setup from template
|
||||||
|
|
||||||
@@ -29,31 +29,16 @@ pnpm add reacord react discord.js
|
|||||||
|
|
||||||
Create a Discord.js client and a Reacord instance:
|
Create a Discord.js client and a Reacord instance:
|
||||||
|
|
||||||
```js
|
```ts
|
||||||
// main.jsx
|
import { Client, Events } from "discord.js"
|
||||||
import { Client } from "discord.js"
|
|
||||||
import { ReacordDiscordJs } from "reacord"
|
import { ReacordDiscordJs } from "reacord"
|
||||||
|
|
||||||
const client = new Client()
|
const client = new Client()
|
||||||
const reacord = new ReacordDiscordJs(client)
|
const reacord = new ReacordDiscordJs(client)
|
||||||
|
|
||||||
client.on("ready", () => {
|
client.once(Events.ClientReady, () => {
|
||||||
console.log("Ready!")
|
console.log("Ready!")
|
||||||
})
|
})
|
||||||
|
|
||||||
await client.login(process.env.BOT_TOKEN)
|
await client.login(process.env.BOT_TOKEN)
|
||||||
```
|
```
|
||||||
|
|
||||||
To use JSX in your code, run it with [tsx](https://npm.im/tsx):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install -D tsx
|
|
||||||
npx tsx main.tsx
|
|
||||||
```
|
|
||||||
|
|
||||||
For production, I recommend compiling it with [tsup](https://npm.im/tsup):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install -D tsup
|
|
||||||
npx tsup src/main.tsx --target node20
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ slug: sending-messages
|
|||||||
|
|
||||||
You can send messages via Reacord to a channel like so.
|
You can send messages via Reacord to a channel like so.
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
client.on("ready", () => {
|
client.once(Events.ClientReady, () => {
|
||||||
const channel = await client.channels.fetch("abc123deadbeef")
|
const channel = await client.channels.fetch("abc123deadbeef")
|
||||||
reacord.createChannelMessage(channel).render("Hello, world!")
|
reacord.createChannelMessage(channel).render("Hello, world!")
|
||||||
})
|
})
|
||||||
@@ -19,7 +19,9 @@ The `.createChannelMessage()` function creates a **Reacord instance**. You can p
|
|||||||
|
|
||||||
Components rendered through this instance can include state and effects, and the message on Discord will update automatically.
|
Components rendered through this instance can include state and effects, and the message on Discord will update automatically.
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
|
||||||
function Uptime() {
|
function Uptime() {
|
||||||
const [startTime] = useState(Date.now())
|
const [startTime] = useState(Date.now())
|
||||||
const [currentTime, setCurrentTime] = useState(Date.now())
|
const [currentTime, setCurrentTime] = useState(Date.now())
|
||||||
@@ -34,7 +36,7 @@ function Uptime() {
|
|||||||
return <>this message has been shown for {currentTime - startTime}ms</>
|
return <>this message has been shown for {currentTime - startTime}ms</>
|
||||||
}
|
}
|
||||||
|
|
||||||
client.on("ready", () => {
|
client.once(Events.ClientReady, () => {
|
||||||
const instance = reacord.createChannelMessage(channel)
|
const instance = reacord.createChannelMessage(channel)
|
||||||
instance.render(<Uptime />)
|
instance.render(<Uptime />)
|
||||||
})
|
})
|
||||||
@@ -42,10 +44,14 @@ client.on("ready", () => {
|
|||||||
|
|
||||||
The instance can be rendered to multiple times, which will update the message each time.
|
The instance can be rendered to multiple times, which will update the message each time.
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
const Hello = ({ subject }) => <>Hello, {subject}!</>
|
interface HelloProps {
|
||||||
|
subject: string
|
||||||
|
}
|
||||||
|
|
||||||
client.on("ready", () => {
|
const Hello = ({ subject }: HelloProps) => <>Hello, {subject}!</>
|
||||||
|
|
||||||
|
client.once(Events.ClientReady, () => {
|
||||||
const instance = reacord.createChannelMessage(channel)
|
const instance = reacord.createChannelMessage(channel)
|
||||||
instance.render(<Hello subject="World" />)
|
instance.render(<Hello subject="World" />)
|
||||||
instance.render(<Hello subject="Moon" />)
|
instance.render(<Hello subject="Moon" />)
|
||||||
@@ -54,7 +60,7 @@ client.on("ready", () => {
|
|||||||
|
|
||||||
You can specify various options for the message:
|
You can specify various options for the message:
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
const instance = reacord.createChannelMessage(channel, {
|
const instance = reacord.createChannelMessage(channel, {
|
||||||
tts: true,
|
tts: true,
|
||||||
reply: {
|
reply: {
|
||||||
@@ -75,7 +81,7 @@ If you no longer want to use the instance, you can clean it up in a few ways:
|
|||||||
|
|
||||||
By default, Reacord has a max limit on the number of active instances, and deactivates older instances to conserve memory. This can be configured through the Reacord options:
|
By default, Reacord has a max limit on the number of active instances, and deactivates older instances to conserve memory. This can be configured through the Reacord options:
|
||||||
|
|
||||||
```js
|
```ts
|
||||||
const reacord = new ReacordDiscordJs(client, {
|
const reacord = new ReacordDiscordJs(client, {
|
||||||
// after sending four messages,
|
// after sending four messages,
|
||||||
// the first one will be deactivated
|
// the first one will be deactivated
|
||||||
@@ -91,29 +97,29 @@ This section also applies to other kinds of application commands, such as contex
|
|||||||
|
|
||||||
To reply to a command interaction, use the `.createInteractionReply()` function. This function returns an instance that works the same way as the one from `.createChannelMessage()`. Here's an example:
|
To reply to a command interaction, use the `.createInteractionReply()` function. This function returns an instance that works the same way as the one from `.createChannelMessage()`. Here's an example:
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
import { Client } from "discord.js"
|
import { Client, Events } from "discord.js"
|
||||||
import { Button, ReacordDiscordJs } from "reacord"
|
import { Button, ReacordDiscordJs } from "reacord"
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
|
|
||||||
const client = new Client({ intents: [] })
|
const client = new Client({ intents: [] })
|
||||||
const reacord = new ReacordDiscordJs(client)
|
const reacord = new ReacordDiscordJs(client)
|
||||||
|
|
||||||
client.on("ready", () => {
|
client.once(Events.ClientReady, () => {
|
||||||
client.application?.commands.create({
|
client.application?.commands.create({
|
||||||
name: "ping",
|
name: "ping",
|
||||||
description: "pong!",
|
description: "pong!",
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
client.on("interactionCreate", (interaction) => {
|
client.on(Events.InteractionCreate, (interaction) => {
|
||||||
if (interaction.isCommand() && interaction.commandName === "ping") {
|
if (interaction.isCommand() && interaction.commandName === "ping") {
|
||||||
// Use the createInteractionReply() function instead of createChannelMessage
|
// Use the createInteractionReply() function instead of createChannelMessage
|
||||||
reacord.createInteractionReply(interaction).render(<>pong!</>)
|
reacord.createInteractionReply(interaction).render(<>pong!</>)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
client.login(process.env.DISCORD_TOKEN)
|
await client.login(process.env.DISCORD_TOKEN)
|
||||||
```
|
```
|
||||||
|
|
||||||
<aside>
|
<aside>
|
||||||
@@ -122,15 +128,26 @@ This example uses <a href="https://discord.com/developers/docs/interactions/appl
|
|||||||
|
|
||||||
However, the process of creating commands can get really repetitive and error-prone. A command framework could help with this, or you could make a small helper:
|
However, the process of creating commands can get really repetitive and error-prone. A command framework could help with this, or you could make a small helper:
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
function handleCommands(client, commands) {
|
import type { Client, CommandInteraction } from "discord.js"
|
||||||
client.on("ready", () => {
|
|
||||||
|
interface Command {
|
||||||
|
// Command name
|
||||||
|
name: string
|
||||||
|
// A mandatory description for the command
|
||||||
|
description: string
|
||||||
|
// Specific handler for the command
|
||||||
|
run: (interaction: CommandInteraction) => Promise<void> | void
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCommands(client: Client, commands: Command[]) {
|
||||||
|
client.once(Events.ClientReady, () => {
|
||||||
for (const { name, description } of commands) {
|
for (const { name, description } of commands) {
|
||||||
client.application?.commands.create({ name, description })
|
client.application?.commands.create({ name, description })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
client.on("interactionCreate", (interaction) => {
|
client.on(Events.InteractionCreate, (interaction) => {
|
||||||
if (interaction.isCommand()) {
|
if (interaction.isCommand()) {
|
||||||
for (const command of commands) {
|
for (const command of commands) {
|
||||||
if (interaction.commandName === command.name) {
|
if (interaction.commandName === command.name) {
|
||||||
@@ -142,7 +159,7 @@ function handleCommands(client, commands) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
handleCommands(client, [
|
handleCommands(client, [
|
||||||
{
|
{
|
||||||
name: "ping",
|
name: "ping",
|
||||||
@@ -165,7 +182,7 @@ handleCommands(client, [
|
|||||||
|
|
||||||
Ephemeral replies are replies that only appear for one user. To create them, use the `.createInteractionReply()` function and provide `ephemeral` option.
|
Ephemeral replies are replies that only appear for one user. To create them, use the `.createInteractionReply()` function and provide `ephemeral` option.
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
handleCommands(client, [
|
handleCommands(client, [
|
||||||
{
|
{
|
||||||
name: "pong",
|
name: "pong",
|
||||||
@@ -183,7 +200,7 @@ handleCommands(client, [
|
|||||||
|
|
||||||
Additionally interaction replies may have `tts` option to turn on text-to-speech ability for the reply. To create such reply, use `.createInteractionReply()` function and provide `tts` option.
|
Additionally interaction replies may have `tts` option to turn on text-to-speech ability for the reply. To create such reply, use `.createInteractionReply()` function and provide `tts` option.
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
handleCommands(client, [
|
handleCommands(client, [
|
||||||
{
|
{
|
||||||
name: "pong",
|
name: "pong",
|
||||||
|
|||||||
@@ -8,10 +8,15 @@ slug: embeds
|
|||||||
|
|
||||||
Reacord comes with an `<Embed />` component for sending rich embeds.
|
Reacord comes with an `<Embed />` component for sending rich embeds.
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
import { Embed } from "reacord"
|
import { Embed } from "reacord"
|
||||||
|
|
||||||
function FancyMessage({ title, description }) {
|
interface FancyMessageProps {
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function FancyMessage({ title, description }: FancyMessageProps) {
|
||||||
return (
|
return (
|
||||||
<Embed
|
<Embed
|
||||||
title={title}
|
title={title}
|
||||||
@@ -23,7 +28,7 @@ function FancyMessage({ title, description }) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
reacord
|
reacord
|
||||||
.createChannelMessage(channel)
|
.createChannelMessage(channel)
|
||||||
.render(<FancyMessage title="Hello" description="World" />)
|
.render(<FancyMessage title="Hello" description="World" />)
|
||||||
@@ -31,10 +36,15 @@ reacord
|
|||||||
|
|
||||||
Reacord also comes with multiple embed components, for defining embeds on a piece-by-piece basis. This enables composition:
|
Reacord also comes with multiple embed components, for defining embeds on a piece-by-piece basis. This enables composition:
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
import { Embed, EmbedTitle } from "reacord"
|
import { Embed, EmbedTitle } from "reacord"
|
||||||
|
|
||||||
function FancyDetails({ title, description }) {
|
interface FancyDetailsProps {
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function FancyDetails({ title, description }: FancyDetailsProps) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<EmbedTitle>{title}</EmbedTitle>
|
<EmbedTitle>{title}</EmbedTitle>
|
||||||
@@ -44,7 +54,11 @@ function FancyDetails({ title, description }) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function FancyMessage({ children }) {
|
interface FancyMessageProps {
|
||||||
|
children: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
function FancyMessage({ children }: FancyMessageProps) {
|
||||||
return (
|
return (
|
||||||
<Embed color={0x00ff00} timestamp={Date.now()}>
|
<Embed color={0x00ff00} timestamp={Date.now()}>
|
||||||
{children}
|
{children}
|
||||||
@@ -53,7 +67,7 @@ function FancyMessage({ children }) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
reacord.createChannelMessage(channel).render(
|
reacord.createChannelMessage(channel).render(
|
||||||
<FancyMessage>
|
<FancyMessage>
|
||||||
<FancyDetails title="Hello" description="World" />
|
<FancyDetails title="Hello" description="World" />
|
||||||
|
|||||||
@@ -8,10 +8,11 @@ slug: buttons
|
|||||||
|
|
||||||
Use the `<Button />` component to create a message with a button, and use the `onClick` callback to respond to button clicks.
|
Use the `<Button />` component to create a message with a button, and use the `onClick` callback to respond to button clicks.
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
import { Button } from "reacord"
|
import { Button } from "reacord"
|
||||||
|
import { useState } from "react"
|
||||||
|
|
||||||
function Counter() {
|
export function Counter() {
|
||||||
const [count, setCount] = useState(0)
|
const [count, setCount] = useState(0)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -25,12 +26,12 @@ function Counter() {
|
|||||||
|
|
||||||
The `onClick` callback receives an `event` object. It includes some information, such as the user who clicked the button, and functions for creating new replies in response. These functions return message instances.
|
The `onClick` callback receives an `event` object. It includes some information, such as the user who clicked the button, and functions for creating new replies in response. These functions return message instances.
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
import { Button } from "reacord"
|
import { Button, type ComponentEvent } from "reacord"
|
||||||
|
|
||||||
function TheButton() {
|
export function SuspiciousButton() {
|
||||||
function handleClick(event) {
|
function handleClick(event: ComponentEvent) {
|
||||||
const name = event.guild.member.displayName || event.user.username
|
const name = event.guild.member.displayName ?? event.user.username
|
||||||
|
|
||||||
const publicReply = event.reply(`${name} clicked the button. wow`)
|
const publicReply = event.reply(`${name} clicked the button. wow`)
|
||||||
setTimeout(() => publicReply.destroy(), 3000)
|
setTimeout(() => publicReply.destroy(), 3000)
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ slug: links
|
|||||||
|
|
||||||
In Discord, links are a type of button, and they work similarly. Clicking on it leads you to the given URL. They only have one style, and can't be listened to for clicks.
|
In Discord, links are a type of button, and they work similarly. Clicking on it leads you to the given URL. They only have one style, and can't be listened to for clicks.
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
import { Link } from "reacord"
|
import { Link } from "reacord"
|
||||||
|
|
||||||
function AwesomeLinks() {
|
export function AwesomeLinks() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Link label="look at this" url="https://google.com" />
|
<Link label="look at this" url="https://google.com" />
|
||||||
|
|||||||
@@ -8,9 +8,16 @@ slug: select-menus
|
|||||||
|
|
||||||
To create a select menu, use the `Select` component, and pass a list of `Option` components as children. Use the `value` prop to set a currently selected value. You can respond to changes in the value via `onChangeValue`.
|
To create a select menu, use the `Select` component, and pass a list of `Option` components as children. Use the `value` prop to set a currently selected value. You can respond to changes in the value via `onChangeValue`.
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
export function FruitSelect({ onConfirm }) {
|
import { Button, Option, Select } from "reacord"
|
||||||
const [value, setValue] = useState()
|
import { useState } from "react"
|
||||||
|
|
||||||
|
interface FruitSelectProps {
|
||||||
|
onConfirm: (choice: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export function FruitSelect({ onConfirm }: FruitSelectProps) {
|
||||||
|
const [value, setValue] = useState<string>()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -35,7 +42,7 @@ export function FruitSelect({ onConfirm }) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
const instance = reacord.createChannelMessage(channel).render(
|
const instance = reacord.createChannelMessage(channel).render(
|
||||||
<FruitSelect
|
<FruitSelect
|
||||||
onConfirm={(value) => {
|
onConfirm={(value) => {
|
||||||
@@ -48,9 +55,13 @@ const instance = reacord.createChannelMessage(channel).render(
|
|||||||
|
|
||||||
For a multi-select, use the `multiple` prop, then you can use `values` and `onChangeMultiple` to handle multiple values.
|
For a multi-select, use the `multiple` prop, then you can use `values` and `onChangeMultiple` to handle multiple values.
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
export function FruitSelect({ onConfirm }) {
|
interface FruitSelectProps {
|
||||||
const [values, setValues] = useState([])
|
onConfirm: (choices: string[]) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export function FruitSelect({ onConfirm }: FruitSelectProps) {
|
||||||
|
const [values, setValues] = useState<string[]>([])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ slug: use-instance
|
|||||||
|
|
||||||
You can use `useInstance` to get the current [instance](/guides/sending-messages) within a component. This can be used to let a component destroy or deactivate itself.
|
You can use `useInstance` to get the current [instance](/guides/sending-messages) within a component. This can be used to let a component destroy or deactivate itself.
|
||||||
|
|
||||||
```jsx
|
```tsx
|
||||||
import { Button, useInstance } from "reacord"
|
import { Button, useInstance } from "reacord"
|
||||||
|
|
||||||
function SelfDestruct() {
|
export function SelfDestruct() {
|
||||||
const instance = useInstance()
|
const instance = useInstance()
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
Reference in New Issue
Block a user