perspective_viewer/custom_elements/
function_dropdown.rs

1// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2// ┃ ██████ ██████ ██████       █      █      █      █      █ █▄  ▀███ █       ┃
3// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█  ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄  ▀█ █ ▀▀▀▀▀ ┃
4// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄   █ ▄▄▄▄▄ ┃
5// ┃ █      ██████ █  ▀█▄       █ ██████      █      ███▌▐███ ███████▄ █       ┃
6// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7// ┃ Copyright (c) 2017, the Perspective Authors.                              ┃
8// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9// ┃ This file is part of the Perspective library, distributed under the terms ┃
10// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
13use std::cell::RefCell;
14use std::rc::Rc;
15
16use perspective_client::config::{COMPLETIONS, CompletionItemSuggestion};
17use perspective_js::utils::global;
18use wasm_bindgen::JsCast;
19use wasm_bindgen::prelude::*;
20use web_sys::*;
21use yew::html::ImplicitClone;
22use yew::*;
23
24use crate::components::function_dropdown::*;
25use crate::custom_elements::modal::*;
26use crate::*;
27
28#[wasm_bindgen]
29#[derive(Clone)]
30pub struct FunctionDropDownElement {
31    modal: ModalElement<FunctionDropDown>,
32    target: Rc<RefCell<Option<HtmlElement>>>,
33}
34
35impl PartialEq for FunctionDropDownElement {
36    fn eq(&self, _other: &Self) -> bool {
37        true
38    }
39}
40
41impl ImplicitClone for FunctionDropDownElement {}
42
43impl FunctionDropDownElement {
44    pub fn reautocomplete(&self) {
45        ApiFuture::spawn(
46            self.modal
47                .clone()
48                .open(self.target.borrow().clone().unwrap(), None),
49        );
50    }
51
52    pub fn autocomplete(
53        &self,
54        input: String,
55        target: HtmlElement,
56        callback: Callback<CompletionItemSuggestion>,
57    ) -> ApiResult<()> {
58        let values = filter_values(&input);
59        if values.is_empty() {
60            self.modal.hide()?;
61        } else {
62            self.modal.send_message_batch(vec![
63                FunctionDropDownMsg::SetCallback(callback),
64                FunctionDropDownMsg::SetValues(values),
65            ]);
66
67            ApiFuture::spawn(self.modal.clone().open(target, None));
68        }
69
70        Ok(())
71    }
72
73    pub fn item_select(&self) {
74        self.modal.send_message(FunctionDropDownMsg::ItemSelect);
75    }
76
77    pub fn item_down(&self) {
78        self.modal.send_message(FunctionDropDownMsg::ItemDown);
79    }
80
81    pub fn item_up(&self) {
82        self.modal.send_message(FunctionDropDownMsg::ItemUp);
83    }
84
85    pub fn hide(&self) -> ApiResult<()> {
86        self.modal.hide()
87    }
88
89    pub fn connected_callback(&self) {}
90}
91
92impl Default for FunctionDropDownElement {
93    fn default() -> Self {
94        let dropdown = global::document()
95            .create_element("perspective-dropdown")
96            .unwrap()
97            .unchecked_into::<HtmlElement>();
98
99        let props = props!(FunctionDropDownProps {});
100        let modal = ModalElement::new(dropdown, props, false, None);
101        Self {
102            modal,
103            target: Default::default(),
104        }
105    }
106}
107
108fn filter_values(input: &str) -> Vec<CompletionItemSuggestion> {
109    let input = input.to_lowercase();
110    COMPLETIONS
111        .iter()
112        .filter(|x| x.label.to_lowercase().starts_with(&input))
113        .cloned()
114        .collect::<Vec<_>>()
115}