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