open_lark/card/components/containers/
interactive.rs1use serde::{Deserialize, Serialize};
2
3use crate::card::{
4 components::{
5 content_components::plain_text::PlainText, interactive_components::input::InputConfirm,
6 CardElement,
7 },
8 interactions::Behaviors,
9};
10
11#[derive(Debug, Serialize, Deserialize)]
13pub struct InteractiveContainer {
14 tag: String,
16 #[serde(skip_serializing_if = "Option::is_none")]
22 width: Option<String>,
23 #[serde(skip_serializing_if = "Option::is_none")]
28 height: Option<String>,
29 #[serde(skip_serializing_if = "Option::is_none")]
35 background_style: Option<String>,
36 #[serde(skip_serializing_if = "Option::is_none")]
38 has_border: Option<bool>,
39 #[serde(skip_serializing_if = "Option::is_none")]
42 border_color: Option<String>,
43 #[serde(skip_serializing_if = "Option::is_none")]
48 corner_radius: Option<String>,
49 #[serde(skip_serializing_if = "Option::is_none")]
55 padding: Option<String>,
56 behaviors: Vec<Behaviors>,
59 #[serde(skip_serializing_if = "Option::is_none")]
61 hover_tips: Option<PlainText>,
62 #[serde(skip_serializing_if = "Option::is_none")]
67 disabled: Option<bool>,
68 #[serde(skip_serializing_if = "Option::is_none")]
70 disabled_tips: Option<PlainText>,
71 #[serde(skip_serializing_if = "Option::is_none")]
76 confirm: Option<InputConfirm>,
77 elements: Vec<CardElement>,
79}
80
81impl Default for InteractiveContainer {
82 fn default() -> Self {
83 InteractiveContainer {
84 tag: "interactive_container".to_string(),
85 width: None,
86 height: None,
87 background_style: None,
88 has_border: None,
89 border_color: None,
90 corner_radius: None,
91 padding: None,
92 behaviors: vec![],
93 hover_tips: None,
94 disabled: None,
95 disabled_tips: None,
96 confirm: None,
97 elements: vec![],
98 }
99 }
100}
101
102impl InteractiveContainer {
103 pub fn new() -> Self {
104 InteractiveContainer::default()
105 }
106
107 pub fn width(mut self, width: &str) -> Self {
108 self.width = Some(width.to_string());
109 self
110 }
111
112 pub fn height(mut self, height: &str) -> Self {
113 self.height = Some(height.to_string());
114 self
115 }
116
117 pub fn background_style(mut self, background_style: &str) -> Self {
118 self.background_style = Some(background_style.to_string());
119 self
120 }
121
122 pub fn has_border(mut self, has_border: bool) -> Self {
123 self.has_border = Some(has_border);
124 self
125 }
126
127 pub fn border_color(mut self, border_color: &str) -> Self {
128 self.border_color = Some(border_color.to_string());
129 self
130 }
131
132 pub fn corner_radius(mut self, corner_radius: &str) -> Self {
133 self.corner_radius = Some(corner_radius.to_string());
134 self
135 }
136
137 pub fn padding(mut self, padding: &str) -> Self {
138 self.padding = Some(padding.to_string());
139 self
140 }
141
142 pub fn behaviors(mut self, behaviors: Vec<Behaviors>) -> Self {
143 self.behaviors = behaviors;
144 self
145 }
146
147 pub fn hover_tips(mut self, hover_tips: PlainText) -> Self {
148 self.hover_tips = Some(hover_tips);
149 self
150 }
151
152 pub fn disabled(mut self, disabled: bool) -> Self {
153 self.disabled = Some(disabled);
154 self
155 }
156
157 pub fn disabled_tips(mut self, disabled_tips: PlainText) -> Self {
158 self.disabled_tips = Some(disabled_tips);
159 self
160 }
161
162 pub fn confirm(mut self, confirm: InputConfirm) -> Self {
163 self.confirm = Some(confirm);
164 self
165 }
166
167 pub fn elements(mut self, elements: Vec<CardElement>) -> Self {
168 self.elements = elements;
169 self
170 }
171}
172
173#[cfg(test)]
174mod test {
175 use serde_json::json;
176
177 use crate::card::{
178 components::{
179 containers::interactive::InteractiveContainer,
180 content_components::plain_text::PlainText,
181 },
182 interactions::{Behaviors, CallbackBehavior, FormBehavior, OpenUrlBehavior},
183 };
184
185 #[test]
186 fn test_interactive() {
187 let interactive = InteractiveContainer::new()
188 .width("fill")
189 .height("auto")
190 .background_style("default")
191 .has_border(false)
192 .border_color("grey")
193 .corner_radius("40px")
194 .padding("10px 20px 10px 20px")
195 .behaviors(vec![
196 Behaviors::OpenUrl(
197 OpenUrlBehavior::new("https://www.baidu.com")
198 .android_url("https://developer.android.com/")
199 .ios_url("lark://msgcard/unsupported_action")
200 .pc_url("https://www.windows.com"),
201 ),
202 Behaviors::Callback(CallbackBehavior::new(json!({
203 "key": "value"
204 }))),
205 Behaviors::Form(FormBehavior::new().behavior("submit")),
206 ])
207 .hover_tips(PlainText::text("demo"))
208 .disabled(false)
209 .disabled_tips(PlainText::text("demo"))
210 .elements(vec![]);
211
212 let expect = json!({
213 "tag": "interactive_container", "width": "fill", "height": "auto", "background_style": "default", "has_border": false, "border_color": "grey", "corner_radius": "40px", "padding": "10px 20px 10px 20px", "behaviors": [
222 {
223 "type": "open_url", "default_url": "https://www.baidu.com", "android_url": "https://developer.android.com/", "ios_url": "lark://msgcard/unsupported_action", "pc_url": "https://www.windows.com" },
229 {
230 "type": "callback", "value": {
232 "key": "value"
234 }
235 },
236 {
237 "type": "form_action", "behavior": "submit" }
240 ],
241 "disabled": false,
242 "disabled_tips": { "tag": "plain_text", "content": "demo" },
243 "hover_tips": {
244 "tag": "plain_text",
245 "content": "demo"
246 },
247 "elements": [] });
249
250 assert_eq!(json!(interactive), expect);
251 }
252}