1use crate::reaction::ReactionEmoji;
4use crate::TitanString;
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
13#[serde(untagged)]
14pub enum Component<'a> {
15 ActionRow(ActionRow<'a>),
17 Button(Button<'a>),
19 SelectMenu(SelectMenu<'a>),
21 TextInput(TextInput<'a>),
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
27#[serde(from = "u8", into = "u8")]
28pub enum ComponentType {
29 ActionRow = 1,
31 Button = 2,
33 StringSelect = 3,
35 TextInput = 4,
37 UserSelect = 5,
39 RoleSelect = 6,
41 MentionableSelect = 7,
43 ChannelSelect = 8,
45}
46
47impl From<u8> for ComponentType {
48 fn from(value: u8) -> Self {
49 match value {
50 2 => ComponentType::Button,
51 3 => ComponentType::StringSelect,
52 4 => ComponentType::TextInput,
53 5 => ComponentType::UserSelect,
54 6 => ComponentType::RoleSelect,
55 7 => ComponentType::MentionableSelect,
56 8 => ComponentType::ChannelSelect,
57 _ => ComponentType::ActionRow, }
59 }
60}
61
62impl From<ComponentType> for u8 {
63 fn from(value: ComponentType) -> Self {
64 value as u8
65 }
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct ActionRow<'a> {
71 #[serde(rename = "type")]
73 pub component_type: ComponentType,
74 pub components: Vec<Component<'a>>,
76}
77
78impl Default for ActionRow<'_> {
79 fn default() -> Self {
80 Self {
81 component_type: ComponentType::ActionRow,
82 components: Vec::new(),
83 }
84 }
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct Button<'a> {
90 #[serde(rename = "type")]
92 pub component_type: ComponentType,
93 pub style: ButtonStyle,
95 #[serde(default)]
97 pub label: Option<TitanString<'a>>,
98 #[serde(default)]
100 pub emoji: Option<ReactionEmoji<'a>>,
101 #[serde(default)]
103 pub custom_id: Option<TitanString<'a>>,
104 #[serde(default)]
106 pub url: Option<TitanString<'a>>,
107 #[serde(default)]
109 pub disabled: bool,
110}
111
112impl<'a> Button<'a> {
113 pub fn builder(
115 custom_id: impl Into<TitanString<'a>>,
116 style: ButtonStyle,
117 ) -> crate::builder::ButtonBuilder<'a> {
118 crate::builder::ButtonBuilder::new()
119 .custom_id(custom_id)
120 .style(style)
121 }
122
123 pub fn builder_link(url: impl Into<TitanString<'a>>) -> crate::builder::ButtonBuilder<'a> {
125 crate::builder::ButtonBuilder::new()
126 .url(url)
127 .style(ButtonStyle::Link)
128 }
129}
130#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
131#[serde(from = "u8", into = "u8")]
132pub enum ButtonStyle {
133 Primary = 1,
135 Secondary = 2,
137 Success = 3,
139 Danger = 4,
141 Link = 5,
143}
144
145impl From<u8> for ButtonStyle {
146 fn from(value: u8) -> Self {
147 match value {
148 2 => ButtonStyle::Secondary,
149 3 => ButtonStyle::Success,
150 4 => ButtonStyle::Danger,
151 5 => ButtonStyle::Link,
152 _ => ButtonStyle::Primary,
153 }
154 }
155}
156
157impl From<ButtonStyle> for u8 {
158 fn from(value: ButtonStyle) -> Self {
159 value as u8
160 }
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize)]
165pub struct SelectMenu<'a> {
166 #[serde(rename = "type")]
168 pub component_type: ComponentType,
169 pub custom_id: TitanString<'a>,
171 #[serde(default)]
173 pub options: Vec<SelectOption<'a>>,
174 #[serde(default)]
176 pub placeholder: Option<TitanString<'a>>,
177 #[serde(default)]
179 pub min_values: Option<u8>,
180 #[serde(default)]
182 pub max_values: Option<u8>,
183 #[serde(default)]
185 pub disabled: bool,
186}
187
188impl<'a> SelectMenu<'a> {
189 pub fn builder(custom_id: impl Into<TitanString<'a>>) -> crate::builder::SelectMenuBuilder<'a> {
191 crate::builder::SelectMenuBuilder::new(custom_id)
192 }
193}
194
195#[derive(Debug, Clone, Serialize, Deserialize)]
197pub struct SelectOption<'a> {
198 pub label: TitanString<'a>,
200 pub value: TitanString<'a>,
202 #[serde(default)]
204 pub description: Option<TitanString<'a>>,
205 #[serde(default)]
207 pub emoji: Option<ReactionEmoji<'a>>,
208 #[serde(default)]
210 pub default: bool,
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize)]
215pub struct TextInput<'a> {
216 #[serde(rename = "type")]
218 pub component_type: ComponentType,
219 pub custom_id: TitanString<'a>,
221 pub style: TextInputStyle,
223 pub label: TitanString<'a>,
225 #[serde(default)]
227 pub min_length: Option<u16>,
228 #[serde(default)]
230 pub max_length: Option<u16>,
231 #[serde(default)]
233 pub required: Option<bool>,
234 #[serde(default)]
236 pub value: Option<TitanString<'a>>,
237 #[serde(default)]
239 pub placeholder: Option<TitanString<'a>>,
240}
241
242#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
244#[serde(from = "u8", into = "u8")]
245pub enum TextInputStyle {
246 Short = 1,
248 Paragraph = 2,
250}
251
252impl From<u8> for TextInputStyle {
253 fn from(value: u8) -> Self {
254 match value {
255 2 => TextInputStyle::Paragraph,
256 _ => TextInputStyle::Short,
257 }
258 }
259}
260
261impl From<TextInputStyle> for u8 {
262 fn from(value: TextInputStyle) -> Self {
263 value as u8
264 }
265}