twilight_model/channel/message/component/button.rs
1use crate::{
2 channel::message::EmojiReactionType,
3 id::{marker::SkuMarker, Id},
4};
5use serde::{Deserialize, Serialize};
6
7/// Clickable [`Component`] below messages.
8///
9/// [`Component`]: super::Component
10#[derive(Clone, Debug, Eq, Hash, PartialEq)]
11pub struct Button {
12 /// Optional identifier for the button.
13 pub id: Option<i32>,
14 /// User defined identifier for the button.
15 ///
16 /// This field is required when using the following [`ButtonStyle`]s:
17 ///
18 /// - [`ButtonStyle::Danger`]
19 /// - [`ButtonStyle::Primary`]
20 /// - [`ButtonStyle::Secondary`]
21 /// - [`ButtonStyle::Success`]
22 pub custom_id: Option<String>,
23 /// Whether the button is disabled.
24 ///
25 /// Defaults to `false`.
26 pub disabled: bool,
27 /// Visual emoji for clients to display with the button.
28 pub emoji: Option<EmojiReactionType>,
29 /// Text appearing on the button.
30 pub label: Option<String>,
31 /// Style variant of the button.
32 pub style: ButtonStyle,
33 /// URL for buttons of a [`ButtonStyle::Link`] style.
34 pub url: Option<String>,
35 /// The ID of the SKU that is attached to the button.
36 ///
37 /// This field is required when using the [`ButtonStyle::Premium`] style.
38 pub sku_id: Option<Id<SkuMarker>>,
39}
40
41/// Style of a [`Button`].
42// Keep in sync with `twilight-validate::component`!
43#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
44#[non_exhaustive]
45#[serde(from = "u8", into = "u8")]
46pub enum ButtonStyle {
47 /// Button indicates a primary action.
48 ///
49 /// Selecting this button style requires specifying the
50 /// [`Button::custom_id`] field.
51 Primary,
52 /// Button indicates a secondary action.
53 ///
54 /// Selecting this button style requires specifying the
55 /// [`Button::custom_id`] field.
56 Secondary,
57 /// Button indicates a successful action.
58 ///
59 /// Selecting this button style requires specifying the
60 /// [`Button::custom_id`] field.
61 Success,
62 /// Button indicates a dangerous action.
63 ///
64 /// Selecting this button style requires specifying the
65 /// [`Button::custom_id`] field.
66 Danger,
67 /// Button indicates an action with a link.
68 ///
69 /// Selecting this button style requires specifying the [`Button::url`]
70 /// field.
71 Link,
72 /// Button indicates a premium upgrade action.
73 ///
74 /// Selecting this button style requires specifying the [`Button::sku_id`]
75 /// field.
76 /// The following fields are not available for this button style: [`Button::custom_id`], [`Button::label`], [`Button::url`] & [`Button::emoji`].
77 /// Premium button styles do not fire an interaction event.
78 Premium,
79 /// Variant value is unknown to the library.
80 Unknown(u8),
81}
82
83impl From<u8> for ButtonStyle {
84 fn from(value: u8) -> Self {
85 match value {
86 1 => ButtonStyle::Primary,
87 2 => ButtonStyle::Secondary,
88 3 => ButtonStyle::Success,
89 4 => ButtonStyle::Danger,
90 5 => ButtonStyle::Link,
91 6 => ButtonStyle::Premium,
92 unknown => ButtonStyle::Unknown(unknown),
93 }
94 }
95}
96
97impl From<ButtonStyle> for u8 {
98 fn from(value: ButtonStyle) -> Self {
99 match value {
100 ButtonStyle::Primary => 1,
101 ButtonStyle::Secondary => 2,
102 ButtonStyle::Success => 3,
103 ButtonStyle::Danger => 4,
104 ButtonStyle::Link => 5,
105 ButtonStyle::Premium => 6,
106 ButtonStyle::Unknown(unknown) => unknown,
107 }
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use serde_test::Token;
115 use static_assertions::{assert_fields, assert_impl_all};
116 use std::{fmt::Debug, hash::Hash};
117
118 assert_fields!(Button: custom_id, disabled, emoji, label, style, url);
119 assert_impl_all!(Button: Clone, Debug, Eq, Hash, PartialEq, Send, Sync);
120
121 assert_impl_all!(
122 ButtonStyle: Clone,
123 Copy,
124 Debug,
125 Deserialize<'static>,
126 Eq,
127 Hash,
128 PartialEq,
129 Send,
130 Serialize,
131 Sync
132 );
133
134 #[test]
135 fn button_style() {
136 serde_test::assert_tokens(&ButtonStyle::Primary, &[Token::U8(1)]);
137 serde_test::assert_tokens(&ButtonStyle::Secondary, &[Token::U8(2)]);
138 serde_test::assert_tokens(&ButtonStyle::Success, &[Token::U8(3)]);
139 serde_test::assert_tokens(&ButtonStyle::Danger, &[Token::U8(4)]);
140 serde_test::assert_tokens(&ButtonStyle::Link, &[Token::U8(5)]);
141 serde_test::assert_tokens(&ButtonStyle::Premium, &[Token::U8(6)]);
142 serde_test::assert_tokens(&ButtonStyle::Unknown(99), &[Token::U8(99)]);
143 }
144}