mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-04 22:16:08 +00:00
feat: components
This commit is contained in:
parent
d10adfdec3
commit
484ed2c0f7
8
mod.ts
8
mod.ts
@ -3,7 +3,6 @@ export * from "./structures/Attachment.ts";
|
|||||||
export * from "./structures/Base.ts";
|
export * from "./structures/Base.ts";
|
||||||
export * from "./structures/BaseGuild.ts";
|
export * from "./structures/BaseGuild.ts";
|
||||||
export * from "./structures/BaseChannel.ts";
|
export * from "./structures/BaseChannel.ts";
|
||||||
export * from "./structures/Component.ts";
|
|
||||||
export * from "./structures/DMChannel.ts";
|
export * from "./structures/DMChannel.ts";
|
||||||
export * from "./structures/Embed.ts";
|
export * from "./structures/Embed.ts";
|
||||||
export * from "./structures/Emoji.ts";
|
export * from "./structures/Emoji.ts";
|
||||||
@ -25,6 +24,13 @@ export * from "./structures/VoiceChannel.ts";
|
|||||||
export * from "./structures/WelcomeChannel.ts";
|
export * from "./structures/WelcomeChannel.ts";
|
||||||
export * from "./structures/WelcomeScreen.ts";
|
export * from "./structures/WelcomeScreen.ts";
|
||||||
|
|
||||||
|
export * from "./structures/components/ActionRowComponent.ts";
|
||||||
|
export * from "./structures/components/ButtonComponent.ts";
|
||||||
|
export * from "./structures/components/Component.ts";
|
||||||
|
export * from "./structures/components/LinkButtonComponent.ts";
|
||||||
|
export * from "./structures/components/SelectMenuComponent.ts";
|
||||||
|
export * from "./structures/components/TextInputComponent.ts";
|
||||||
|
|
||||||
export * from "./session/Session.ts";
|
export * from "./session/Session.ts";
|
||||||
|
|
||||||
export * from "./util/shared/flags.ts";
|
export * from "./util/shared/flags.ts";
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
import type { Session } from "../session/Session.ts";
|
|
||||||
import type { DiscordComponent, MessageComponentTypes } from "../vendor/external.ts";
|
|
||||||
import Emoji from "./Emoji.ts";
|
|
||||||
|
|
||||||
export class Component {
|
|
||||||
constructor(session: Session, data: DiscordComponent) {
|
|
||||||
this.session = session;
|
|
||||||
this.customId = data.custom_id;
|
|
||||||
this.type = data.type;
|
|
||||||
this.components = data.components?.map((component) => new Component(session, component));
|
|
||||||
this.disabled = !!data.disabled;
|
|
||||||
|
|
||||||
if (data.emoji) {
|
|
||||||
this.emoji = new Emoji(session, data.emoji);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.maxValues = data.max_values;
|
|
||||||
this.minValues = data.min_values;
|
|
||||||
this.label = data.label;
|
|
||||||
this.value = data.value;
|
|
||||||
this.options = data.options ?? [];
|
|
||||||
this.placeholder = data.placeholder;
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly session: Session;
|
|
||||||
|
|
||||||
customId?: string;
|
|
||||||
type: MessageComponentTypes;
|
|
||||||
components?: Component[];
|
|
||||||
disabled: boolean;
|
|
||||||
emoji?: Emoji;
|
|
||||||
maxValues?: number;
|
|
||||||
minValues?: number;
|
|
||||||
label?: string;
|
|
||||||
value?: string;
|
|
||||||
// deno-lint-ignore no-explicit-any
|
|
||||||
options: any[];
|
|
||||||
placeholder?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Component;
|
|
@ -38,6 +38,9 @@ export interface ApplicationCommandOptionChoice {
|
|||||||
value: string | number;
|
value: string | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: abstract Interaction, CommandInteraction, ComponentInteraction, PingInteraction, etc
|
||||||
|
|
||||||
|
|
||||||
export class Interaction implements Model {
|
export class Interaction implements Model {
|
||||||
constructor(session: Session, data: DiscordInteraction) {
|
constructor(session: Session, data: DiscordInteraction) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
|
@ -8,11 +8,13 @@ import type {
|
|||||||
DiscordUser,
|
DiscordUser,
|
||||||
FileContent,
|
FileContent,
|
||||||
} from "../vendor/external.ts";
|
} from "../vendor/external.ts";
|
||||||
|
import type { Component } from "./components/Component.ts";
|
||||||
import type { GetReactions } from "../util/Routes.ts";
|
import type { GetReactions } from "../util/Routes.ts";
|
||||||
import { MessageFlags } from "../util/shared/flags.ts";
|
import { MessageFlags } from "../util/shared/flags.ts";
|
||||||
import User from "./User.ts";
|
import User from "./User.ts";
|
||||||
import Member from "./Member.ts";
|
import Member from "./Member.ts";
|
||||||
import Attachment from "./Attachment.ts";
|
import Attachment from "./Attachment.ts";
|
||||||
|
import BaseComponent from "./components/Component.ts";
|
||||||
import * as Routes from "../util/Routes.ts";
|
import * as Routes from "../util/Routes.ts";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,6 +82,8 @@ export class Message implements Model {
|
|||||||
if (data.guild_id && data.member) {
|
if (data.guild_id && data.member) {
|
||||||
this.member = new Member(session, { ...data.member, user: data.author }, data.guild_id);
|
this.member = new Member(session, { ...data.member, user: data.author }, data.guild_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.components = data.components?.map((component) => BaseComponent.from(session, component));
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly session: Session;
|
readonly session: Session;
|
||||||
@ -95,6 +99,7 @@ export class Message implements Model {
|
|||||||
|
|
||||||
attachments: Attachment[];
|
attachments: Attachment[];
|
||||||
member?: Member;
|
member?: Member;
|
||||||
|
components?: Component[];
|
||||||
|
|
||||||
get url() {
|
get url() {
|
||||||
return `https://discord.com/channels/${this.guildId ?? "@me"}/${this.channelId}/${this.id}`;
|
return `https://discord.com/channels/${this.guildId ?? "@me"}/${this.channelId}/${this.id}`;
|
||||||
|
39
structures/components/ActionRowComponent.ts
Normal file
39
structures/components/ActionRowComponent.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import type { Session } from "../../session/Session.ts";
|
||||||
|
import type { DiscordComponent } from "../../vendor/external.ts";
|
||||||
|
import type { ActionRowComponent, Component } from "./Component.ts";
|
||||||
|
import { MessageComponentTypes, ButtonStyles } from "../../vendor/external.ts";
|
||||||
|
import BaseComponent from "./Component.ts";
|
||||||
|
import Button from "./ButtonComponent.ts";
|
||||||
|
import LinkButton from "./LinkButtonComponent.ts";
|
||||||
|
import SelectMenu from "./SelectMenuComponent.ts";
|
||||||
|
import InputText from "./TextInputComponent.ts";
|
||||||
|
|
||||||
|
export class ActionRow extends BaseComponent implements ActionRowComponent {
|
||||||
|
constructor(session: Session, data: DiscordComponent) {
|
||||||
|
super(data.type);
|
||||||
|
|
||||||
|
this.session = session;
|
||||||
|
this.type = data.type as MessageComponentTypes.ActionRow;
|
||||||
|
this.components = data.components!.map((component) => {
|
||||||
|
switch (component.type) {
|
||||||
|
case MessageComponentTypes.Button:
|
||||||
|
if (component.style === ButtonStyles.Link) {
|
||||||
|
return new LinkButton(session, component);
|
||||||
|
}
|
||||||
|
return new Button(session, component);
|
||||||
|
case MessageComponentTypes.SelectMenu:
|
||||||
|
return new SelectMenu(session, component);
|
||||||
|
case MessageComponentTypes.InputText:
|
||||||
|
return new InputText(session, component);
|
||||||
|
case MessageComponentTypes.ActionRow:
|
||||||
|
throw new Error("Cannot have an action row inside an action row");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly session: Session;
|
||||||
|
override type: MessageComponentTypes.ActionRow;
|
||||||
|
components: Array<Exclude<Component, ActionRowComponent>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ActionRow;
|
33
structures/components/ButtonComponent.ts
Normal file
33
structures/components/ButtonComponent.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import type { Session } from "../../session/Session.ts";
|
||||||
|
import type { DiscordComponent, ButtonStyles } from "../../vendor/external.ts";
|
||||||
|
import type { ButtonComponent } from "./Component.ts";
|
||||||
|
import { MessageComponentTypes } from "../../vendor/external.ts";
|
||||||
|
import BaseComponent from "./Component.ts";
|
||||||
|
import Emoji from "../Emoji.ts";
|
||||||
|
|
||||||
|
export class Button extends BaseComponent implements ButtonComponent {
|
||||||
|
constructor(session: Session, data: DiscordComponent) {
|
||||||
|
super(data.type);
|
||||||
|
|
||||||
|
this.session = session;
|
||||||
|
this.type = data.type as MessageComponentTypes.Button;
|
||||||
|
this.customId = data.custom_id;
|
||||||
|
this.label = data.label;
|
||||||
|
this.style = data.style as number;
|
||||||
|
this.disabled = data.disabled;
|
||||||
|
|
||||||
|
if (data.emoji) {
|
||||||
|
this.emoji = new Emoji(session, data.emoji);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly session: Session;
|
||||||
|
override type: MessageComponentTypes.Button;
|
||||||
|
customId?: string;
|
||||||
|
label?: string;
|
||||||
|
style: ButtonStyles.Primary | ButtonStyles.Secondary | ButtonStyles.Success | ButtonStyles.Danger;
|
||||||
|
disabled?: boolean;
|
||||||
|
emoji?: Emoji;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Button;
|
122
structures/components/Component.ts
Normal file
122
structures/components/Component.ts
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
import type { Session } from "../../session/Session.ts";
|
||||||
|
import type { DiscordComponent } from "../../vendor/external.ts";
|
||||||
|
import type Emoji from "../Emoji.ts";
|
||||||
|
import { ButtonStyles, MessageComponentTypes, TextStyles } from "../../vendor/external.ts";
|
||||||
|
|
||||||
|
// TODO: fix circular dependencies
|
||||||
|
import ActionRow from "./ActionRowComponent.ts";
|
||||||
|
import Button from "./ButtonComponent.ts";
|
||||||
|
import LinkButton from "./ButtonComponent.ts";
|
||||||
|
import SelectMenu from "./SelectMenuComponent.ts";
|
||||||
|
import TextInput from "./TextInputComponent.ts";
|
||||||
|
|
||||||
|
export class BaseComponent {
|
||||||
|
constructor(type: MessageComponentTypes) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
type: MessageComponentTypes;
|
||||||
|
|
||||||
|
isActionRow(): this is ActionRowComponent {
|
||||||
|
return this.type === MessageComponentTypes.ActionRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
isButton(): this is ButtonComponent {
|
||||||
|
return this.type === MessageComponentTypes.Button;
|
||||||
|
}
|
||||||
|
|
||||||
|
isSelectMenu(): this is SelectMenuComponent {
|
||||||
|
return this.type === MessageComponentTypes.SelectMenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
isTextInput(): this is TextInputComponent {
|
||||||
|
return this.type === MessageComponentTypes.InputText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component factory
|
||||||
|
* @internal
|
||||||
|
* */
|
||||||
|
static from(session: Session, component: DiscordComponent): Component {
|
||||||
|
switch (component.type) {
|
||||||
|
case MessageComponentTypes.ActionRow:
|
||||||
|
return new ActionRow(session, component);
|
||||||
|
case MessageComponentTypes.Button:
|
||||||
|
if (component.style === ButtonStyles.Link) {
|
||||||
|
return new LinkButton(session, component);
|
||||||
|
}
|
||||||
|
return new Button(session, component);
|
||||||
|
case MessageComponentTypes.SelectMenu:
|
||||||
|
return new SelectMenu(session, component);
|
||||||
|
case MessageComponentTypes.InputText:
|
||||||
|
return new TextInput(session, component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Action Row Component */
|
||||||
|
export interface ActionRowComponent {
|
||||||
|
type: MessageComponentTypes.ActionRow;
|
||||||
|
components: Array<Exclude<Component, ActionRowComponent>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** All Components */
|
||||||
|
export type Component =
|
||||||
|
| ActionRowComponent
|
||||||
|
| ButtonComponent
|
||||||
|
| LinkButtonComponent
|
||||||
|
| SelectMenuComponent
|
||||||
|
| TextInputComponent;
|
||||||
|
|
||||||
|
/** Button Component */
|
||||||
|
export interface ButtonComponent {
|
||||||
|
type: MessageComponentTypes.Button;
|
||||||
|
style: ButtonStyles.Primary | ButtonStyles.Secondary | ButtonStyles.Success | ButtonStyles.Danger;
|
||||||
|
label?: string;
|
||||||
|
emoji?: Emoji;
|
||||||
|
customId?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Link Button Component */
|
||||||
|
export interface LinkButtonComponent {
|
||||||
|
type: MessageComponentTypes.Button;
|
||||||
|
style: ButtonStyles.Link;
|
||||||
|
label?: string;
|
||||||
|
url: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Select Menu Component */
|
||||||
|
export interface SelectMenuComponent {
|
||||||
|
type: MessageComponentTypes.SelectMenu;
|
||||||
|
customId: string;
|
||||||
|
options: SelectMenuOption[];
|
||||||
|
placeholder?: string;
|
||||||
|
minValue?: number;
|
||||||
|
maxValue?: number;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Text Input Component */
|
||||||
|
export interface TextInputComponent {
|
||||||
|
type: MessageComponentTypes.InputText;
|
||||||
|
customId: string;
|
||||||
|
style: TextStyles;
|
||||||
|
label: string;
|
||||||
|
minLength?: number;
|
||||||
|
maxLength?: number;
|
||||||
|
required?: boolean;
|
||||||
|
value?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SelectMenuOption {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
description?: string;
|
||||||
|
emoji?: Emoji;
|
||||||
|
default?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BaseComponent;
|
33
structures/components/LinkButtonComponent.ts
Normal file
33
structures/components/LinkButtonComponent.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import type { Session } from "../../session/Session.ts";
|
||||||
|
import type { DiscordComponent, ButtonStyles } from "../../vendor/external.ts";
|
||||||
|
import type { LinkButtonComponent } from "./Component.ts";
|
||||||
|
import { MessageComponentTypes } from "../../vendor/external.ts";
|
||||||
|
import BaseComponent from "./Component.ts";
|
||||||
|
import Emoji from "../Emoji.ts";
|
||||||
|
|
||||||
|
export class LinkButton extends BaseComponent implements LinkButtonComponent {
|
||||||
|
constructor(session: Session, data: DiscordComponent) {
|
||||||
|
super(data.type);
|
||||||
|
|
||||||
|
this.session = session;
|
||||||
|
this.type = data.type as MessageComponentTypes.Button;
|
||||||
|
this.url = data.url!;
|
||||||
|
this.label = data.label;
|
||||||
|
this.style = data.style as number;
|
||||||
|
this.disabled = data.disabled;
|
||||||
|
|
||||||
|
if (data.emoji) {
|
||||||
|
this.emoji = new Emoji(session, data.emoji);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly session: Session;
|
||||||
|
override type: MessageComponentTypes.Button;
|
||||||
|
url: string;
|
||||||
|
label?: string;
|
||||||
|
style: ButtonStyles.Link;
|
||||||
|
disabled?: boolean;
|
||||||
|
emoji?: Emoji;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LinkButton;
|
39
structures/components/SelectMenuComponent.ts
Normal file
39
structures/components/SelectMenuComponent.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import type { Session } from "../../session/Session.ts";
|
||||||
|
import type { DiscordComponent } from "../../vendor/external.ts";
|
||||||
|
import type { SelectMenuComponent, SelectMenuOption } from "./Component.ts";
|
||||||
|
import { MessageComponentTypes } from "../../vendor/external.ts";
|
||||||
|
import BaseComponent from "./Component.ts";
|
||||||
|
import Emoji from "../Emoji.ts";
|
||||||
|
|
||||||
|
export class SelectMenu extends BaseComponent implements SelectMenuComponent {
|
||||||
|
constructor(session: Session, data: DiscordComponent) {
|
||||||
|
super(data.type);
|
||||||
|
|
||||||
|
this.session = session;
|
||||||
|
this.type = data.type as MessageComponentTypes.SelectMenu;
|
||||||
|
this.customId = data.custom_id!;
|
||||||
|
this.options = data.options!.map((option) => {
|
||||||
|
return <SelectMenuOption>{
|
||||||
|
label: option.label,
|
||||||
|
description: option.description,
|
||||||
|
emoji: option.emoji || new Emoji(session, option.emoji!),
|
||||||
|
value: option.value,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
this.placeholder = data.placeholder;
|
||||||
|
this.minValues = data.min_values;
|
||||||
|
this.maxValues = data.max_values;
|
||||||
|
this.disabled = data.disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly session: Session;
|
||||||
|
override type: MessageComponentTypes.SelectMenu;
|
||||||
|
customId: string;
|
||||||
|
options: SelectMenuOption[];
|
||||||
|
placeholder?: string;
|
||||||
|
minValues?: number;
|
||||||
|
maxValues?: number;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SelectMenu;
|
38
structures/components/TextInputComponent.ts
Normal file
38
structures/components/TextInputComponent.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import type { Session } from "../../session/Session.ts";
|
||||||
|
import type { DiscordComponent } from "../../vendor/external.ts";
|
||||||
|
import type { TextInputComponent } from "./Component.ts";
|
||||||
|
import { MessageComponentTypes, TextStyles } from "../../vendor/external.ts";
|
||||||
|
import BaseComponent from "./Component.ts";
|
||||||
|
|
||||||
|
export class TextInput extends BaseComponent implements TextInputComponent {
|
||||||
|
constructor(session: Session, data: DiscordComponent) {
|
||||||
|
super(data.type);
|
||||||
|
|
||||||
|
this.session = session;
|
||||||
|
this.type = data.type as MessageComponentTypes.InputText;
|
||||||
|
this.customId = data.custom_id!;
|
||||||
|
this.label = data.label!;
|
||||||
|
this.style = data.style as TextStyles;
|
||||||
|
|
||||||
|
this.placeholder = data.placeholder;
|
||||||
|
this.value = data.value;
|
||||||
|
|
||||||
|
// @ts-ignore: vendor bug
|
||||||
|
this.minLength = data.min_length;
|
||||||
|
|
||||||
|
// @ts-ignore: vendor bug
|
||||||
|
this.maxLength = data.max_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly session: Session;
|
||||||
|
override type: MessageComponentTypes.InputText;
|
||||||
|
style: TextStyles;
|
||||||
|
customId: string;
|
||||||
|
label: string;
|
||||||
|
placeholder?: string;
|
||||||
|
value?: string;
|
||||||
|
minLength?: number;
|
||||||
|
maxLength?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TextInput;
|
Loading…
x
Reference in New Issue
Block a user