mirror of
https://github.com/yewprint/yewprint
synced 2024-11-28 22:40:22 +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 {
|
pub struct Example {
|
||||||
props: ExampleProps,
|
props: ExampleProps,
|
||||||
|
link: ComponentLink<Self>,
|
||||||
|
log_level: LogLevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
|
@ -14,14 +16,19 @@ pub struct ExampleProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Example {
|
impl Component for Example {
|
||||||
type Message = ();
|
type Message = LogLevel;
|
||||||
type Properties = ExampleProps;
|
type Properties = ExampleProps;
|
||||||
|
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||||
Example { props }
|
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
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,21 +44,34 @@ impl Component for Example {
|
||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div style="width: 400px; text-align: center;">
|
<div style="width: 400px; text-align: center;">
|
||||||
<HtmlSelect
|
<HtmlSelect<LogLevel>
|
||||||
options={vec![
|
options={vec![
|
||||||
("trace".to_string(), "TRACE".to_string()),
|
(LogLevel::Trace, "TRACE".to_string()),
|
||||||
("debug".to_string(), "DEBUG".to_string()),
|
(LogLevel::Debug, "DEBUG".to_string()),
|
||||||
("info".to_string(), "INFO".to_string()),
|
(LogLevel::Info, "INFO".to_string()),
|
||||||
("warn".to_string(), "WARN".to_string()),
|
(LogLevel::Warn, "WARN".to_string()),
|
||||||
("error".to_string(), "ERROR".to_string()),
|
(LogLevel::Error, "ERROR".to_string()),
|
||||||
("off".to_string(), "OFF".to_string()),
|
(LogLevel::Off, "OFF".to_string()),
|
||||||
]}
|
]}
|
||||||
minimal=self.props.minimal
|
minimal=self.props.minimal
|
||||||
fill=self.props.fill
|
fill=self.props.fill
|
||||||
disabled=self.props.disabled
|
disabled=self.props.disabled
|
||||||
large=self.props.large
|
large=self.props.large
|
||||||
|
value=Some(self.log_level)
|
||||||
|
onchange=self.link.callback(|x| x)
|
||||||
|
title=format!("Selected: {:?}", self.log_level)
|
||||||
/>
|
/>
|
||||||
</div>
|
</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 crate::{ConditionalClass, Icon, IconName};
|
||||||
|
use std::collections::hash_map::DefaultHasher;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct HtmlSelect {
|
pub struct HtmlSelect<T: Clone + PartialEq + Hash + 'static> {
|
||||||
props: Props,
|
props: Props<T>,
|
||||||
|
link: ComponentLink<Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct Props {
|
pub struct Props<T: Clone + PartialEq + 'static> {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub fill: ConditionalClass,
|
pub fill: ConditionalClass,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -20,23 +23,32 @@ pub struct Props {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub title: Option<String>,
|
pub title: Option<String>,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub onchange: Callback<ChangeData>,
|
pub onchange: Callback<T>,
|
||||||
|
pub options: Vec<(T, String)>,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub options: Vec<(String, String)>,
|
pub value: Option<T>,
|
||||||
#[prop_or_default]
|
|
||||||
pub value: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for HtmlSelect {
|
impl<T: Clone + PartialEq + Hash + 'static> Component for HtmlSelect<T> {
|
||||||
type Message = ();
|
type Message = ChangeData;
|
||||||
type Properties = Props;
|
type Properties = Props<T>;
|
||||||
|
|
||||||
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||||
HtmlSelect { props }
|
Self { props, link }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||||
true
|
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 {
|
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||||
|
@ -53,7 +65,25 @@ impl Component for HtmlSelect {
|
||||||
.props
|
.props
|
||||||
.options
|
.options
|
||||||
.iter()
|
.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>();
|
.collect::<Html>();
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
|
@ -68,8 +98,16 @@ impl Component for HtmlSelect {
|
||||||
>
|
>
|
||||||
<select
|
<select
|
||||||
disabled=*self.props.disabled
|
disabled=*self.props.disabled
|
||||||
onchange={self.props.onchange.clone()}
|
onchange={self.link.callback(|x| x)}
|
||||||
value={self.props.value.clone()}
|
value?={
|
||||||
|
self.props.value
|
||||||
|
.as_ref()
|
||||||
|
.map(|value| {
|
||||||
|
let mut hasher = DefaultHasher::new();
|
||||||
|
value.hash(&mut hasher);
|
||||||
|
hasher.finish()
|
||||||
|
})
|
||||||
|
}
|
||||||
title?={self.props.title.clone()}
|
title?={self.props.title.clone()}
|
||||||
>
|
>
|
||||||
{option_children}
|
{option_children}
|
||||||
|
|
Loading…
Reference in a new issue