diff --git a/crates/macro/src/html_tree/html_tag/mod.rs b/crates/macro/src/html_tree/html_tag/mod.rs index e74f04dd417..f1e020813a3 100644 --- a/crates/macro/src/html_tree/html_tag/mod.rs +++ b/crates/macro/src/html_tree/html_tag/mod.rs @@ -137,7 +137,7 @@ impl ToTokens for HtmlTag { #vtag.add_classes(vec![#(&(#classes)),*]); }, ClassesForm::Single(classes) => quote! { - #vtag.set_classes(&(#classes)); + #vtag.set_classes(#classes); }, }); diff --git a/src/services/resize.rs b/src/services/resize.rs index 1af970ab962..c94d032cba6 100644 --- a/src/services/resize.rs +++ b/src/services/resize.rs @@ -1,8 +1,10 @@ //! This module contains the implementation of a service that listens for browser window resize events. use stdweb::Value; +use stdweb::{ + js, + web::{window, Window}, +}; use yew::callback::Callback; -use stdweb::{js, web::{window, Window}}; - /// A service that fires events when the browser window resizes. #[derive(Default)] diff --git a/src/virtual_dom/mod.rs b/src/virtual_dom/mod.rs index 69c1b49c77d..ce461f536fe 100644 --- a/src/virtual_dom/mod.rs +++ b/src/virtual_dom/mod.rs @@ -6,10 +6,10 @@ pub mod vnode; pub mod vtag; pub mod vtext; +use indexmap::set::IndexSet; use std::collections::HashMap; use std::fmt; use stdweb::web::{Element, EventListenerHandle, Node}; -use indexmap::set::IndexSet; pub use self::vcomp::VComp; pub use self::vlist::VList; @@ -41,7 +41,62 @@ type Listeners = Vec>>; type Attributes = HashMap; /// A set of classes. -type Classes = IndexSet; +#[derive(Debug)] +pub struct Classes { + set: IndexSet, +} + +impl Classes { + /// Creates empty set of classes. + pub fn new() -> Self { + Self { + set: IndexSet::new(), + } + } + + /// Adds a class to a set. + pub fn push(&mut self, class: &str) { + self.set.insert(class.into()); + } + + /// Check the set contains a class. + pub fn contains(&self, class: &str) -> bool { + self.set.contains(class) + } +} + +impl ToString for Classes { + fn to_string(&self) -> String { + let mut buf = String::new(); + for class in &self.set { + buf.push_str(class); + buf.push(' '); + } + buf.pop(); + buf + } +} + +impl From<&str> for Classes { + fn from(t: &str) -> Self { + let set = t.split_whitespace().map(String::from).collect(); + Self { set } + } +} + +impl From for Classes { + fn from(t: String) -> Self { + let set = t.split_whitespace().map(String::from).collect(); + Self { set } + } +} + +impl> From> for Classes { + fn from(t: Vec) -> Self { + let set = t.iter().map(|x| x.as_ref().to_string()).collect(); + Self { set } + } +} /// Patch for DOM node modification. enum Patch { diff --git a/src/virtual_dom/vtag.rs b/src/virtual_dom/vtag.rs index c78d9196aaa..021d359425e 100644 --- a/src/virtual_dom/vtag.rs +++ b/src/virtual_dom/vtag.rs @@ -96,7 +96,7 @@ impl VTag { pub fn add_class(&mut self, class: &str) { let class = class.trim(); if !class.is_empty() { - self.classes.insert(class.into()); + self.classes.push(class); } } @@ -107,7 +107,7 @@ impl VTag { for class in classes { let class = class.trim(); if !class.is_empty() { - self.classes.insert(class.into()); + self.classes.push(class); } } } @@ -115,8 +115,8 @@ impl VTag { /// Add classes to this virtual node. Actually it will set by /// [Element.classList.add](https://developer.mozilla.org/en-US/docs/Web/API/Element/classList) /// call later. - pub fn set_classes(&mut self, classes: &str) { - self.classes = classes.split_whitespace().map(String::from).collect(); + pub fn set_classes(&mut self, classes: impl Into) { + self.classes = classes.into(); } /// Sets `value` for an @@ -187,18 +187,21 @@ impl VTag { // Only change what is necessary. let to_add = self .classes - .difference(&ancestor.classes) + .set + .difference(&ancestor.classes.set) .map(|class| Patch::Add(class.to_owned(), ())); changes.extend(to_add); let to_remove = ancestor .classes - .difference(&self.classes) + .set + .difference(&self.classes.set) .map(|class| Patch::Remove(class.to_owned())); changes.extend(to_remove); } else { // Add everything let to_add = self .classes + .set .iter() .map(|class| Patch::Add(class.to_owned(), ())); changes.extend(to_add); @@ -558,7 +561,7 @@ impl PartialEq for VTag { return false; } - if self.classes.iter().ne(other.classes.iter()) { + if self.classes.set.iter().ne(other.classes.set.iter()) { return false; } diff --git a/tests/vtag_test.rs b/tests/vtag_test.rs index 211b11bad3f..8a55ea560c7 100644 --- a/tests/vtag_test.rs +++ b/tests/vtag_test.rs @@ -216,6 +216,24 @@ fn supports_multiple_classes_string() { } } +#[test] +fn supports_multiple_classes_vec() { + let mut classes = vec!["class-1"]; + classes.push("class-2"); + let a: VNode = html! { +
+ }; + + if let VNode::VTag(vtag) = a { + println!("{:?}", vtag.classes); + assert!(vtag.classes.contains("class-1")); + assert!(vtag.classes.contains("class-2")); + assert!(!vtag.classes.contains("class-3")); + } else { + panic!("vtag expected"); + } +} + fn assert_vtag(node: &mut VNode) -> &mut VTag { if let VNode::VTag(vtag) = node { return vtag; @@ -261,16 +279,9 @@ fn keeps_order_of_classes() {
}; - if let VNode::VTag(mut vtag) = a { + if let VNode::VTag(vtag) = a { println!("{:?}", vtag.classes); - assert_eq!( - vtag.classes.drain(..).collect::>(), - vec![ - String::from("class-1"), - String::from("class-2"), - String::from("class-3") - ] - ) + assert_eq!(vtag.classes.to_string(), "class-1 class-2 class-3"); } }