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}