perspective_viewer/components/
function_dropdown.rs1use perspective_client::config::CompletionItemSuggestion;
14use web_sys::*;
15use yew::prelude::*;
16
17use super::modal::*;
18use crate::utils::WeakScope;
19
20static CSS: &str = include_str!(concat!(env!("OUT_DIR"), "/css/function-dropdown.css"));
21
22pub enum FunctionDropDownMsg {
23 SetValues(Vec<CompletionItemSuggestion>),
24 SetCallback(Callback<CompletionItemSuggestion>),
25 ItemDown,
26 ItemUp,
27 ItemSelect,
28}
29
30pub struct FunctionDropDown {
31 values: Option<Vec<CompletionItemSuggestion>>,
32 selected: usize,
33 on_select: Option<Callback<CompletionItemSuggestion>>,
34}
35
36#[derive(Properties, PartialEq)]
37pub struct FunctionDropDownProps {
38 #[prop_or_default]
39 pub weak_link: WeakScope<FunctionDropDown>,
40}
41
42impl ModalLink<FunctionDropDown> for FunctionDropDownProps {
43 fn weak_link(&self) -> &'_ WeakScope<FunctionDropDown> {
44 &self.weak_link
45 }
46}
47
48impl Component for FunctionDropDown {
49 type Message = FunctionDropDownMsg;
50 type Properties = FunctionDropDownProps;
51
52 fn create(ctx: &Context<Self>) -> Self {
53 ctx.set_modal_link();
54 Self {
55 values: Some(vec![]),
56 selected: 0,
57 on_select: None,
58 }
59 }
60
61 fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
62 match msg {
63 FunctionDropDownMsg::SetCallback(callback) => {
64 self.on_select = Some(callback);
65 false
66 },
67 FunctionDropDownMsg::SetValues(values) => {
68 self.values = Some(values);
69 self.selected = 0;
70 true
71 },
72 FunctionDropDownMsg::ItemSelect => {
73 if let Some(ref values) = self.values {
74 match values.get(self.selected) {
75 None => {
76 console::error_1(&"Selected out-of-bounds".into());
77 false
78 },
79 Some(x) => {
80 self.on_select.as_ref().unwrap().emit(*x);
81 false
82 },
83 }
84 } else {
85 console::error_1(&"No Values".into());
86 false
87 }
88 },
89 FunctionDropDownMsg::ItemDown => {
90 self.selected += 1;
91 if let Some(ref values) = self.values {
92 if self.selected >= values.len() {
93 self.selected = 0;
94 };
95 };
96
97 true
98 },
99 FunctionDropDownMsg::ItemUp => {
100 if let Some(ref values) = self.values {
101 if self.selected < 1 {
102 self.selected = values.len();
103 }
104 }
105
106 self.selected -= 1;
107 true
108 },
109 }
110 }
111
112 fn changed(&mut self, _ctx: &Context<Self>, _old: &Self::Properties) -> bool {
113 false
114 }
115
116 fn view(&self, _ctx: &Context<Self>) -> Html {
117 let body = html! {
118 if let Some(ref values) = self.values {
119 if !values.is_empty() {
120 { for values
121 .iter()
122 .enumerate()
123 .map(|(idx, value)| {
124 let click = self.on_select.as_ref().unwrap().reform({
125 let value = *value;
126 move |_: MouseEvent| value
127 });
128
129 html! {
130 if idx == self.selected {
131 <div onmousedown={ click } class="selected">
132 <span style="font-weight:500">{ value.label }</span>
133 <br/>
134 <span style="padding-left:12px">{ value.documentation }</span>
135 </div>
136 } else {
137 <div onmousedown={ click }>
138 <span style="font-weight:500">{ value.label }</span>
139 <br/>
140 <span style="padding-left:12px">{ value.documentation }</span>
141 </div>
142 }
143 }
144 }) }
145 }
146 }
147 };
148
149 html! { <><style>{ &CSS }</style>{ body }</> }
150 }
151}