use crate::prelude::*;
pub struct Dropdown {
pub is_open: Signal<bool>,
pub placement: Signal<Placement>,
pub show_arrow: Signal<bool>,
pub arrow_size: Signal<Length>,
pub should_reposition: Signal<bool>,
}
impl Dropdown {
pub fn new<F, L>(cx: &mut Context, trigger: L, content: F) -> Handle<Self>
where
L: 'static + Fn(&mut Context),
F: 'static + Fn(&mut Context),
{
let is_open = Signal::new(false);
let placement = Signal::new(Placement::Bottom);
let show_arrow = Signal::new(true);
let arrow_size = Signal::new(Length::Value(LengthValue::Px(4.0)));
let should_reposition = Signal::new(true);
Self { is_open, placement, show_arrow, arrow_size, should_reposition }.build(
cx,
move |cx| {
(trigger)(cx);
Binding::new(cx, is_open, move |cx| {
let is_open = is_open.get();
if is_open {
Popover::new(cx, |cx| {
(content)(cx);
})
.on_blur(|cx| cx.emit(PopupEvent::Close))
.placement(placement)
.show_arrow(show_arrow)
.arrow_size(arrow_size)
.should_reposition(should_reposition);
}
})
},
)
}
}
impl View for Dropdown {
fn element(&self) -> Option<&'static str> {
Some("dropdown")
}
fn event(&mut self, _cx: &mut EventContext, event: &mut Event) {
event.map(|popup_event, meta| match popup_event {
PopupEvent::Open => {
self.is_open.set_if_changed(true);
meta.consume();
}
PopupEvent::Close => {
self.is_open.set_if_changed(false);
meta.consume();
}
PopupEvent::Switch => {
self.is_open.set(!self.is_open.get());
meta.consume();
}
});
}
}
impl Handle<'_, Dropdown> {
pub fn placement(self, placement: impl Res<Placement> + 'static) -> Self {
let placement = placement.to_signal(self.cx);
self.bind(placement, move |handle| {
let placement = placement.get();
handle.modify(|dropdown| {
dropdown.placement.set(placement);
});
})
}
pub fn show_arrow(self, show_arrow: impl Res<bool> + 'static) -> Self {
let show_arrow = show_arrow.to_signal(self.cx);
self.bind(show_arrow, move |handle| {
let show_arrow = show_arrow.get();
handle.modify(|dropdown| {
dropdown.show_arrow.set(show_arrow);
});
})
}
pub fn arrow_size<U: Into<Length> + Clone + 'static>(
self,
size: impl Res<U> + 'static,
) -> Self {
let size = size.to_signal(self.cx);
self.bind(size, move |handle| {
let size = size.get();
let size = size;
handle.modify(|dropdown| {
dropdown.arrow_size.set(size.into());
});
})
}
pub fn should_reposition(self, flag: impl Res<bool> + 'static) -> Self {
let flag = flag.to_signal(self.cx);
self.bind(flag, move |handle| {
let flag = flag.get();
handle.modify(|dropdown| {
dropdown.should_reposition.set(flag);
});
})
}
}