mirror of
https://github.com/yewprint/yewprint
synced 2024-11-25 04:50:20 +00:00
Improvements over HtmlSelect to allow using hashable objects (#47)
This commit is contained in:
parent
5b6b643290
commit
58933276c9
2 changed files with 87 additions and 29 deletions
|
@ -3,6 +3,8 @@ use yewprint::HtmlSelect;
|
|||
|
||||
pub struct Example {
|
||||
props: ExampleProps,
|
||||
link: ComponentLink<Self>,
|
||||
log_level: LogLevel,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
|
@ -14,14 +16,19 @@ pub struct ExampleProps {
|
|||
}
|
||||
|
||||
impl Component for Example {
|
||||
type Message = ();
|
||||
type Message = LogLevel;
|
||||
type Properties = ExampleProps;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
Example { props }
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
Example {
|
||||
props,
|
||||
link,
|
||||
log_level: LogLevel::Info,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
self.log_level = msg;
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -37,21 +44,34 @@ impl Component for Example {
|
|||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div style="width: 400px; text-align: center;">
|
||||
<HtmlSelect
|
||||
<HtmlSelect<LogLevel>
|
||||
options={vec![
|
||||
("trace".to_string(), "TRACE".to_string()),
|
||||
("debug".to_string(), "DEBUG".to_string()),
|
||||
("info".to_string(), "INFO".to_string()),
|
||||
("warn".to_string(), "WARN".to_string()),
|
||||
("error".to_string(), "ERROR".to_string()),
|
||||
("off".to_string(), "OFF".to_string()),
|
||||
(LogLevel::Trace, "TRACE".to_string()),
|
||||
(LogLevel::Debug, "DEBUG".to_string()),
|
||||
(LogLevel::Info, "INFO".to_string()),
|
||||
(LogLevel::Warn, "WARN".to_string()),
|
||||
(LogLevel::Error, "ERROR".to_string()),
|
||||
(LogLevel::Off, "OFF".to_string()),
|
||||
]}
|
||||
minimal=self.props.minimal
|
||||
fill=self.props.fill
|
||||
disabled=self.props.disabled
|
||||
large=self.props.large
|
||||
value=Some(self.log_level)
|
||||
onchange=self.link.callback(|x| x)
|
||||
title=format!("Selected: {:?}", self.log_level)
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq)]
|
||||
pub enum LogLevel {
|
||||
Trace,
|
||||
Debug,
|
||||
Info,
|
||||
Warn,
|
||||
Error,
|
||||
Off,
|
||||
}
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
use crate::{ConditionalClass, Icon, IconName};
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct HtmlSelect {
|
||||
props: Props,
|
||||
pub struct HtmlSelect<T: Clone + PartialEq + Hash + 'static> {
|
||||
props: Props<T>,
|
||||
link: ComponentLink<Self>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct Props {
|
||||
pub struct Props<T: Clone + PartialEq + 'static> {
|
||||
#[prop_or_default]
|
||||
pub fill: ConditionalClass,
|
||||
#[prop_or_default]
|
||||
|
@ -20,23 +23,32 @@ pub struct Props {
|
|||
#[prop_or_default]
|
||||
pub title: Option<String>,
|
||||
#[prop_or_default]
|
||||
pub onchange: Callback<ChangeData>,
|
||||
pub onchange: Callback<T>,
|
||||
pub options: Vec<(T, String)>,
|
||||
#[prop_or_default]
|
||||
pub options: Vec<(String, String)>,
|
||||
#[prop_or_default]
|
||||
pub value: String,
|
||||
pub value: Option<T>,
|
||||
}
|
||||
|
||||
impl Component for HtmlSelect {
|
||||
type Message = ();
|
||||
type Properties = Props;
|
||||
impl<T: Clone + PartialEq + Hash + 'static> Component for HtmlSelect<T> {
|
||||
type Message = ChangeData;
|
||||
type Properties = Props<T>;
|
||||
|
||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||
HtmlSelect { props }
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
Self { props, link }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
true
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
let i = if let ChangeData::Select(select) = msg {
|
||||
select.selected_index()
|
||||
} else {
|
||||
unreachable!("unexpected ChangeData variant: {:?}", msg);
|
||||
};
|
||||
if i >= 0 {
|
||||
let i = i as usize;
|
||||
let variant = self.props.options[i].0.clone();
|
||||
self.props.onchange.emit(variant);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
|
@ -53,7 +65,25 @@ impl Component for HtmlSelect {
|
|||
.props
|
||||
.options
|
||||
.iter()
|
||||
.map(|(value, label)| html!(<option value=value>{label}</option>))
|
||||
.map(|(value, label)| {
|
||||
let selected = self
|
||||
.props
|
||||
.value
|
||||
.as_ref()
|
||||
.map(|x| value == x)
|
||||
.unwrap_or_default();
|
||||
let value = {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
value.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
};
|
||||
|
||||
html! {
|
||||
<option selected=selected value=value>
|
||||
{label}
|
||||
</option>
|
||||
}
|
||||
})
|
||||
.collect::<Html>();
|
||||
|
||||
html! {
|
||||
|
@ -68,8 +98,16 @@ impl Component for HtmlSelect {
|
|||
>
|
||||
<select
|
||||
disabled=*self.props.disabled
|
||||
onchange={self.props.onchange.clone()}
|
||||
value={self.props.value.clone()}
|
||||
onchange={self.link.callback(|x| x)}
|
||||
value?={
|
||||
self.props.value
|
||||
.as_ref()
|
||||
.map(|value| {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
value.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
})
|
||||
}
|
||||
title?={self.props.title.clone()}
|
||||
>
|
||||
{option_children}
|
||||
|
|
Loading…
Reference in a new issue