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}