90 lines
2.3 KiB
TypeScript
90 lines
2.3 KiB
TypeScript
import { nanoid } from "nanoid"
|
|
import type { ReactNode } from "react"
|
|
import React from "react"
|
|
import { isInstanceOf } from "../../../helpers/is-instance-of"
|
|
import { ReacordElement } from "../../internal/element.js"
|
|
import type { ComponentInteraction } from "../../internal/interaction"
|
|
import type { MessageOptions } from "../../internal/message"
|
|
import { getNextActionRow } from "../../internal/message"
|
|
import { Node } from "../../internal/node.js"
|
|
import { OptionNode } from "./option-node"
|
|
|
|
export type SelectProps = {
|
|
children?: ReactNode
|
|
value?: string
|
|
values?: string[]
|
|
placeholder?: string
|
|
multiple?: boolean
|
|
minValues?: number
|
|
maxValues?: number
|
|
disabled?: boolean
|
|
onSelect?: (event: SelectEvent) => void
|
|
onSelectValue?: (value: string) => void
|
|
onSelectMultiple?: (values: string[]) => void
|
|
}
|
|
|
|
export type SelectEvent = {
|
|
values: string[]
|
|
}
|
|
|
|
export function Select(props: SelectProps) {
|
|
return (
|
|
<ReacordElement props={props} createNode={() => new SelectNode(props)}>
|
|
{props.children}
|
|
</ReacordElement>
|
|
)
|
|
}
|
|
|
|
class SelectNode extends Node<SelectProps> {
|
|
readonly customId = nanoid()
|
|
|
|
override modifyMessageOptions(message: MessageOptions): void {
|
|
const actionRow = getNextActionRow(message)
|
|
|
|
const options = [...this.children]
|
|
.filter(isInstanceOf(OptionNode))
|
|
.map((node) => node.options)
|
|
|
|
const {
|
|
multiple,
|
|
value,
|
|
values,
|
|
minValues = 0,
|
|
maxValues = 25,
|
|
children,
|
|
onSelect,
|
|
onSelectValue,
|
|
onSelectMultiple,
|
|
...props
|
|
} = this.props
|
|
|
|
actionRow.push({
|
|
...props,
|
|
type: "select",
|
|
customId: this.customId,
|
|
options,
|
|
values: [...(values || []), ...(value ? [value] : [])],
|
|
minValues: multiple ? minValues : undefined,
|
|
maxValues: multiple ? Math.max(minValues, maxValues) : undefined,
|
|
})
|
|
}
|
|
|
|
override handleComponentInteraction(
|
|
interaction: ComponentInteraction,
|
|
): boolean {
|
|
if (
|
|
interaction.type === "select" &&
|
|
interaction.customId === this.customId &&
|
|
!this.props.disabled
|
|
) {
|
|
this.props.onSelect?.({ values: interaction.values })
|
|
this.props.onSelectMultiple?.(interaction.values)
|
|
if (interaction.values[0]) {
|
|
this.props.onSelectValue?.(interaction.values[0])
|
|
}
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
}
|