use crate::{prelude::FluentBuilder as _, *};
use std::sync::Arc;
#[derive(IntoElement)]
pub struct Select {
id: SharedString,
options: Vec<SharedString>,
selected: Option<usize>,
placeholder: SharedString,
on_change:
Option<Arc<dyn Fn(usize, SharedString, &mut Window, &mut App) + Send + Sync + 'static>>,
style: StyleRefinement,
}
impl Select {
#[track_caller]
pub fn new(options: Vec<SharedString>) -> Self {
Self {
id: crate::caller_element_id("select"),
options,
selected: None,
placeholder: "请选择".into(),
on_change: None,
style: StyleRefinement::default(),
}
}
pub fn id(mut self, id: impl Into<SharedString>) -> Self {
self.id = id.into();
self
}
pub fn selected(mut self, index: Option<usize>) -> Self {
self.selected = index;
self
}
pub fn placeholder(mut self, text: impl Into<SharedString>) -> Self {
self.placeholder = text.into();
self
}
pub fn on_change<F>(mut self, f: F) -> Self
where
F: Fn(usize, SharedString, &mut Window, &mut App) + Send + Sync + 'static,
{
self.on_change = Some(Arc::new(f));
self
}
}
impl Styled for Select {
fn style(&mut self) -> &mut StyleRefinement {
&mut self.style
}
}
impl RenderOnce for Select {
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
let current = self
.selected
.and_then(|ix| self.options.get(ix).cloned())
.unwrap_or_else(|| self.placeholder.clone());
let options = self.options;
let on_change = self.on_change;
let user_style = self.style;
Button::new(self.id.clone())
.label(current)
.icon(IconName::ChevronDown)
.map(|mut this| {
this.style().refine(&user_style);
this
})
.dropdown_menu(move |menu, _, _| {
options.iter().enumerate().fold(menu, |menu, (ix, option)| {
let option = option.clone();
let on_change = on_change.clone();
menu.item(
PopupMenuItem::new(option.clone()).on_click(move |_, window, cx| {
if let Some(ref cb) = on_change {
cb(ix, option.clone(), window, cx);
}
}),
)
})
})
.match_trigger_width(true)
}
}