Skip to main content

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