perspective_viewer/components/containers/
dropdown_menu.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::marker::PhantomData;
14use std::rc::Rc;
15
16use web_sys::*;
17use yew::prelude::*;
18
19use super::select::SelectItem;
20use crate::components::style::LocalStyle;
21use crate::*;
22
23pub type DropDownMenuItem<T> = SelectItem<T>;
24
25pub type DropDownMenuMsg = ();
26
27#[derive(Properties, PartialEq)]
28pub struct DropDownMenuProps<T>
29where
30    T: Into<Html> + Clone + PartialEq + 'static,
31{
32    pub values: Rc<Vec<DropDownMenuItem<T>>>,
33    pub callback: Callback<T>,
34}
35
36pub struct DropDownMenu<T>
37where
38    T: Into<Html> + Clone + PartialEq + 'static,
39{
40    _props: PhantomData<T>,
41}
42
43impl<T> Component for DropDownMenu<T>
44where
45    T: Into<Html> + Clone + PartialEq + 'static,
46{
47    type Message = DropDownMenuMsg;
48    type Properties = DropDownMenuProps<T>;
49
50    fn create(_ctx: &Context<Self>) -> Self {
51        Self {
52            _props: Default::default(),
53        }
54    }
55
56    fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
57        false
58    }
59
60    fn view(&self, ctx: &Context<Self>) -> Html {
61        let values = &ctx.props().values;
62        let body = if !values.is_empty() {
63            values
64                .iter()
65                .map(|value| match value {
66                    DropDownMenuItem::Option(x) => {
67                        let click = ctx.props().callback.reform({
68                            let value = x.clone();
69                            move |_: MouseEvent| value.clone()
70                        });
71
72                        html! {
73                            <span onmousedown={click} class="selected">{ x.clone().into() }</span>
74                        }
75                    },
76                    DropDownMenuItem::OptGroup(name, xs) => {
77                        html! {
78                            <>
79                                <span class="dropdown-group-label">{ name }</span>
80                                <div class="dropdown-group-container">
81                                    { xs.iter().map(|x| {
82                                    let click = ctx.props().callback.reform({
83                                        let value = x.clone();
84                                        move |_: MouseEvent| value.clone()
85                                    });
86                                    html! {
87                                        <span onmousedown={ click }>
88                                            { x.clone().into() }
89                                        </span>
90                                    }
91                                }).collect::<Html>() }
92                                </div>
93                            </>
94                        }
95                    },
96                })
97                .collect::<Html>()
98        } else {
99            html! { <span class="no-results">{ "No Completions" }</span> }
100        };
101
102        html! { <><LocalStyle href={css!("containers/dropdown-menu")} />{ body }</> }
103    }
104}