1use serde::{Deserialize, Serialize};
4
5use crate::node::{ActionId, Common, IntoNode, Key, Node};
6use crate::text::Line;
7
8#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
10#[serde(rename_all = "camelCase")]
11pub struct SelectOption {
12 pub value: String,
14 pub label: Line,
16 #[serde(default, skip_serializing_if = "Option::is_none")]
18 pub description: Option<String>,
19}
20
21impl SelectOption {
22 #[must_use]
24 pub fn new(value: impl Into<String>, label: impl Into<Line>) -> Self {
25 Self {
26 value: value.into(),
27 label: label.into(),
28 description: None,
29 }
30 }
31
32 #[must_use]
34 pub fn description(mut self, description: impl Into<String>) -> Self {
35 self.description = Some(description.into());
36 self
37 }
38}
39
40impl From<(&str, &str)> for SelectOption {
41 fn from((value, label): (&str, &str)) -> Self {
42 Self::new(value, label)
43 }
44}
45
46#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
48#[serde(rename_all = "camelCase")]
49pub struct Select {
50 #[serde(flatten)]
52 pub common: Common,
53 pub options: Vec<SelectOption>,
55 #[serde(default, skip_serializing_if = "Option::is_none")]
57 pub value: Option<String>,
58 #[serde(default, skip_serializing_if = "Option::is_none")]
60 pub placeholder: Option<String>,
61 #[serde(default, skip_serializing_if = "Option::is_none")]
63 pub disabled: Option<bool>,
64 #[serde(default, skip_serializing_if = "Option::is_none")]
66 pub on_change: Option<ActionId>,
67}
68
69impl Select {
70 #[must_use]
72 pub fn new(
73 key: impl Into<Key>,
74 options: impl IntoIterator<Item = impl Into<SelectOption>>,
75 ) -> Self {
76 let mut common = Common::new();
77 common.key = Some(key.into());
78 Self {
79 common,
80 options: options.into_iter().map(Into::into).collect(),
81 value: None,
82 placeholder: None,
83 disabled: None,
84 on_change: None,
85 }
86 }
87
88 #[must_use]
90 pub fn value(mut self, value: impl Into<String>) -> Self {
91 self.value = Some(value.into());
92 self
93 }
94
95 #[must_use]
97 pub fn placeholder(mut self, placeholder: impl Into<String>) -> Self {
98 self.placeholder = Some(placeholder.into());
99 self
100 }
101
102 #[must_use]
104 pub fn disabled(mut self, disabled: bool) -> Self {
105 self.disabled = Some(disabled);
106 self
107 }
108
109 #[must_use]
111 pub fn on_change(mut self, action: impl Into<ActionId>) -> Self {
112 self.on_change = Some(action.into());
113 self
114 }
115}
116
117impl IntoNode for Select {}
118impl From<Select> for Node {
119 fn from(s: Select) -> Self {
120 Node::Select(s)
121 }
122}