diff --git a/benches/benches.rs b/benches/benches.rs
index b3d96fe..94ce1c3 100755
--- a/benches/benches.rs
+++ b/benches/benches.rs
@@ -17,16 +17,16 @@ use std::convert::TryInto;
/// The simplest thing we can render: `
`.
struct Empty;
-impl Render for Empty {
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a> Render<'a> for Empty {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
div(&cx).finish()
}
}
/// Render a list that is `self.0` items long, has attributes and listeners.
struct SimpleList(usize);
-impl Render for SimpleList {
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a> Render<'a> for SimpleList {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
let mut children = bumpalo::collections::Vec::with_capacity_in(self.0, cx.bump);
children.extend((0..self.0).map(|_| {
li(&cx)
diff --git a/crates/js-api/src/lib.rs b/crates/js-api/src/lib.rs
index 6532695..54f9dec 100644
--- a/crates/js-api/src/lib.rs
+++ b/crates/js-api/src/lib.rs
@@ -99,8 +99,8 @@ impl GreetingViaJs {
/// And finally the `Render` implementation! This adds a `
` element and some
/// text around whatever the inner JS `Greeting` component renders.
-impl Render for GreetingViaJs {
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a> Render<'a> for GreetingViaJs {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
use dodrio::builder::*;
p(&cx)
.children([
@@ -216,8 +216,8 @@ impl JsRender {
}
}
-impl Render for JsRender {
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a> Render<'a> for JsRender {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
create(cx, self.render())
}
}
diff --git a/examples/counter/src/lib.rs b/examples/counter/src/lib.rs
index 0bbf035..ff44df3 100755
--- a/examples/counter/src/lib.rs
+++ b/examples/counter/src/lib.rs
@@ -26,8 +26,8 @@ impl Counter {
// The `Render` implementation for `Counter`s displays the current count and has
// buttons to increment and decrement the count.
-impl Render for Counter {
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a> Render<'a> for Counter {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
use dodrio::builder::*;
// Stringify the count as a bump-allocated string.
diff --git a/examples/game-of-life/src/lib.rs b/examples/game-of-life/src/lib.rs
index 54e9064..e6b0039 100644
--- a/examples/game-of-life/src/lib.rs
+++ b/examples/game-of-life/src/lib.rs
@@ -126,8 +126,8 @@ impl Universe {
}
/// The rendering implementation for our Game of Life.
-impl Render for Universe {
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a> Render<'a> for Universe {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
use dodrio::builder::*;
let mut rows = bumpalo::collections::Vec::with_capacity_in(self.height as usize, cx.bump);
diff --git a/examples/hello-world/src/lib.rs b/examples/hello-world/src/lib.rs
index f14c1f4..55f50da 100644
--- a/examples/hello-world/src/lib.rs
+++ b/examples/hello-world/src/lib.rs
@@ -10,8 +10,8 @@ struct Hello {
// The `Render` implementation describes how to render a `Hello` component into
// HTML.
-impl Render for Hello {
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a> Render<'a> for Hello {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
let msg = bumpalo::format!(in cx.bump, "Hello, {}!", self.who);
let msg = msg.into_bump_str();
p(&cx).children([text(msg)]).finish()
diff --git a/examples/input-form/src/lib.rs b/examples/input-form/src/lib.rs
index e7e5500..08073ac 100644
--- a/examples/input-form/src/lib.rs
+++ b/examples/input-form/src/lib.rs
@@ -23,8 +23,8 @@ impl SayHelloTo {
// The `Render` implementation has a text `` and a `
` that shows a
// greeting to the ``'s value.
-impl Render for SayHelloTo {
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a> Render<'a> for SayHelloTo {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
use dodrio::builder::*;
div(&cx)
diff --git a/examples/js-component/src/lib.rs b/examples/js-component/src/lib.rs
index 0629a71..d9c94f2 100644
--- a/examples/js-component/src/lib.rs
+++ b/examples/js-component/src/lib.rs
@@ -31,8 +31,8 @@ impl GreetingViaJs {
/// Here's the `Render` implementation! This adds a `
` element and some text
/// around whatever the inner JS `Greeting` component renders.
-impl Render for GreetingViaJs {
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a> Render<'a> for GreetingViaJs {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
use dodrio::builder::*;
p(&cx)
.children([text("JavaScript says: "), self.js.render(cx)])
diff --git a/examples/moire/src/lib.rs b/examples/moire/src/lib.rs
index df16018..abca33b 100644
--- a/examples/moire/src/lib.rs
+++ b/examples/moire/src/lib.rs
@@ -104,8 +104,8 @@ impl Moire {
}
}
-impl Render for Moire {
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a> Render<'a> for Moire {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
use dodrio::builder::*;
let elapsed = web_sys::window()
diff --git a/examples/sierpinski-triangle/src/lib.rs b/examples/sierpinski-triangle/src/lib.rs
index 9c4b1b3..0ac3f96 100644
--- a/examples/sierpinski-triangle/src/lib.rs
+++ b/examples/sierpinski-triangle/src/lib.rs
@@ -85,8 +85,8 @@ impl Container {
}
}
-impl Render for Container {
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a> Render<'a> for Container {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
use dodrio::builder::div;
let elapsed = web_sys::window()
diff --git a/examples/todomvc/src/todo.rs b/examples/todomvc/src/todo.rs
index e64e9a9..2ec4f9e 100644
--- a/examples/todomvc/src/todo.rs
+++ b/examples/todomvc/src/todo.rs
@@ -116,8 +116,8 @@ impl Todo {
}
}
-impl Render for Todo {
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a, C: TodoActions> Render<'a> for Todo {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
use dodrio::{
builder::*,
bumpalo::{self, collections::String},
diff --git a/examples/todomvc/src/todos.rs b/examples/todomvc/src/todos.rs
index 447e6b6..e9e709b 100755
--- a/examples/todomvc/src/todos.rs
+++ b/examples/todomvc/src/todos.rs
@@ -289,8 +289,8 @@ impl Todos {
}
}
-impl Render for Todos {
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a, C: TodosActions> Render<'a> for Todos {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
use dodrio::builder::*;
div(&cx)
diff --git a/src/cached.rs b/src/cached.rs
index 86d96dc..48d1137 100644
--- a/src/cached.rs
+++ b/src/cached.rs
@@ -45,8 +45,8 @@ where
/// count: u32,
/// }
///
- /// impl Render for Counter {
- /// fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+ /// impl<'a> Render<'a> for Counter {
+ /// fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
/// // ...
/// # unimplemented!()
/// }
@@ -85,8 +85,8 @@ where
/// who: String
/// }
///
- /// impl Render for Hello {
- /// fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+ /// impl<'a> Render<'a> for Hello {
+ /// fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
/// use dodrio::builder::*;
/// let greeting = bumpalo::format!(in cx.bump, "Hello, {}!", self.who);
/// p(&cx)
@@ -143,11 +143,11 @@ where
}
}
-impl Render for Cached
+impl<'a, R> Render<'a> for Cached
where
- R: 'static + Default + Render,
+ R: 'static + Default + for<'b> Render<'b>,
{
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
let template = cx.template::();
let cached = match self.cached.get() {
// This does-the-cache-contain-this-id check is necessary because
diff --git a/src/change_list/mod.rs b/src/change_list/mod.rs
index 41342b7..e3af69d 100644
--- a/src/change_list/mod.rs
+++ b/src/change_list/mod.rs
@@ -233,9 +233,9 @@ impl ChangeListBuilder<'_> {
self.state.emitter.replace_with();
}
- pub fn set_attribute(&mut self, name: &str, value: &str) {
+ pub fn set_attribute(&mut self, name: &str, value: &str, is_namespaced: bool) {
debug_assert!(self.traversal_is_committed());
- if name == "class" {
+ if name == "class" && !is_namespaced {
let class_id = self.ensure_string(value);
debug!("emit: set_class({:?})", value);
self.state.emitter.set_class(class_id.into());
diff --git a/src/diff.rs b/src/diff.rs
index 15f199a..139dda4 100644
--- a/src/diff.rs
+++ b/src/diff.rs
@@ -78,7 +78,7 @@ pub(crate) fn diff(
return;
}
diff_listeners(change_list, registry, old_listeners, new_listeners);
- diff_attributes(change_list, old_attributes, new_attributes);
+ diff_attributes(change_list, old_attributes, new_attributes, new_namespace.is_some());
diff_children(
cached_set,
change_list,
@@ -204,26 +204,26 @@ fn diff_listeners(
// [... node]
//
// The change list stack is left unchanged.
-fn diff_attributes(change_list: &mut ChangeListBuilder, old: &[Attribute], new: &[Attribute]) {
+fn diff_attributes(change_list: &mut ChangeListBuilder, old: &[Attribute], new: &[Attribute], is_namespaced: bool) {
// Do O(n^2) passes to add/update and remove attributes, since
// there are almost always very few attributes.
'outer: for new_attr in new {
if new_attr.is_volatile() {
change_list.commit_traversal();
- change_list.set_attribute(new_attr.name, new_attr.value);
+ change_list.set_attribute(new_attr.name, new_attr.value, is_namespaced);
} else {
for old_attr in old {
if old_attr.name == new_attr.name {
if old_attr.value != new_attr.value {
change_list.commit_traversal();
- change_list.set_attribute(new_attr.name, new_attr.value);
+ change_list.set_attribute(new_attr.name, new_attr.value, is_namespaced);
}
continue 'outer;
}
}
change_list.commit_traversal();
- change_list.set_attribute(new_attr.name, new_attr.value);
+ change_list.set_attribute(new_attr.name, new_attr.value, is_namespaced);
}
}
@@ -953,7 +953,7 @@ fn create(
}
for attr in attributes {
- change_list.set_attribute(&attr.name, &attr.value);
+ change_list.set_attribute(&attr.name, &attr.value, namespace.is_some());
}
// Fast path: if there is a single text child, it is faster to
diff --git a/src/lib.rs b/src/lib.rs
index 20aeb29..a6c7fd6 100755
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -18,8 +18,8 @@
//! }
//! }
//!
-//! impl<'who> Render for Hello<'who> {
-//! fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+//! impl<'a, 'who> Render<'a> for Hello<'who> {
+//! fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
//! use dodrio::builder::*;
//!
//! let id = bumpalo::format!(in cx.bump, "hello-{}", self.who);
diff --git a/src/render.rs b/src/render.rs
index 0e33beb..066758f 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -21,8 +21,8 @@ use wasm_bindgen::UnwrapThrowExt;
///
/// pub struct MyComponent;
///
-/// impl Render for MyComponent {
-/// fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+/// impl<'a> Render<'a> for MyComponent {
+/// fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
/// use dodrio::builder::*;
///
/// p(&cx)
@@ -35,26 +35,26 @@ use wasm_bindgen::UnwrapThrowExt;
/// }
/// }
/// ```
-pub trait Render {
+pub trait Render<'a> {
/// Render `self` as a virtual DOM. Use the given context's `Bump` for
/// temporary allocations.
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a>;
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a>;
}
-impl<'r, R> Render for &'r R
+impl<'a, 'r, R> Render<'a> for &'r R
where
- R: Render,
+ R: Render<'a>,
{
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
(**self).render(cx)
}
}
-impl Render for Rc
+impl<'a, R> Render<'a> for Rc
where
- R: Render,
+ R: Render<'a>,
{
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
(**self).render(cx)
}
}
@@ -69,7 +69,7 @@ where
/// You do not need to implement this trait by hand: there is a blanket
/// implementation for all `Render` types that fulfill the `RootRender`
/// requirements.
-pub trait RootRender: Any + Render {
+pub trait RootRender: Any + for<'a> Render<'a> {
/// Get this `&RootRender` trait object as an `&Any` trait object reference.
fn as_any(&self) -> &dyn Any;
@@ -80,7 +80,7 @@ pub trait RootRender: Any + Render {
impl RootRender for T
where
- T: Any + Render,
+ T: Any + for<'a> Render<'a>,
{
fn as_any(&self) -> &dyn Any {
self
@@ -138,4 +138,31 @@ mod tests {
#[allow(dead_code)]
fn takes_dyn_render(_: &dyn super::RootRender) {}
}
+
+ #[test]
+ fn render_bump_scoped_child() {
+ use crate::{builder::*, bumpalo::collections::String, Node, Render, RenderContext};
+
+ struct Child<'a> {
+ name: &'a str,
+ }
+
+ impl<'a> Render<'a> for Child<'a> {
+ fn render(&self, _cx: &mut RenderContext<'a>) -> Node<'a> {
+ text(self.name)
+ }
+ }
+
+ struct Parent;
+
+ impl<'a> Render<'a> for Parent {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+ let child_name = String::from_str_in("child", cx.bump).into_bump_str();
+
+ div(&cx)
+ .children([Child { name: child_name }.render(cx)])
+ .finish()
+ }
+ }
+ }
}
diff --git a/src/render_context.rs b/src/render_context.rs
index 34abb63..674af4a 100644
--- a/src/render_context.rs
+++ b/src/render_context.rs
@@ -69,7 +69,7 @@ impl<'a> RenderContext<'a> {
/// Get or create the cached template for `Cached`.
pub(crate) fn template(&mut self) -> Option
where
- R: 'static + Default + Render,
+ R: 'static + Default + for<'b> Render<'b>,
{
let template_id = Cached::::template_id();
if let Some(cache_id) = self.templates.get(&template_id).cloned() {
diff --git a/tests/web/cached.rs b/tests/web/cached.rs
index 965f782..b2ebb8b 100644
--- a/tests/web/cached.rs
+++ b/tests/web/cached.rs
@@ -18,8 +18,8 @@ impl CountRenders {
}
}
-impl Render for CountRenders {
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a> Render<'a> for CountRenders {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
let count = self.render_count.get() + 1;
self.render_count.set(count);
@@ -153,8 +153,8 @@ impl Default for Id {
}
}
-impl Render for Id {
- fn render<'a>(&self, _cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a> Render<'a> for Id {
+ fn render(&self, _cx: &mut RenderContext<'a>) -> Node<'a> {
text(self.0)
}
}
diff --git a/tests/web/events.rs b/tests/web/events.rs
index 000c669..a0edea4 100644
--- a/tests/web/events.rs
+++ b/tests/web/events.rs
@@ -24,8 +24,8 @@ impl EventContainer {
}
}
-impl Render for EventContainer {
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a> Render<'a> for EventContainer {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
use dodrio::builder::*;
div(&cx)
.attr("id", "target")
@@ -126,8 +126,8 @@ impl ListensOnlyOnFirstRender {
}
}
-impl Render for ListensOnlyOnFirstRender {
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a> Render<'a> for ListensOnlyOnFirstRender {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
use dodrio::builder::*;
let count = self.count.get();
diff --git a/tests/web/js_api.rs b/tests/web/js_api.rs
index 4e20f3f..cd43306 100644
--- a/tests/web/js_api.rs
+++ b/tests/web/js_api.rs
@@ -35,8 +35,8 @@ impl WrapJs {
}
}
-impl Render for WrapJs {
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a> Render<'a> for WrapJs {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
div(&cx)
.attr("class", "wrap-js")
.children([self.inner.render(cx)])
diff --git a/tests/web/keyed.rs b/tests/web/keyed.rs
index ff2c536..73fd18f 100644
--- a/tests/web/keyed.rs
+++ b/tests/web/keyed.rs
@@ -7,8 +7,8 @@ use wasm_bindgen_test::*;
struct Keyed(u16);
-impl Render for Keyed {
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+impl<'a> Render<'a> for Keyed {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
let key = bumpalo::format!(in cx.bump, "{}", self.0).into_bump_str();
div(&cx)
.attr("class", "keyed")
@@ -33,8 +33,8 @@ where
async fn assert_keyed(before: Before, after: After) -> Result<(), JsValue>
where
- Before: 'static + Render,
- After: 'static + Render,
+ Before: 'static + for<'a> Render<'a>,
+ After: 'static + for<'a> Render<'a>,
{
#[wasm_bindgen(module = "/tests/web/keyed.js")]
extern "C" {
diff --git a/tests/web/main.rs b/tests/web/main.rs
index 6cb1ead..9ac8872 100644
--- a/tests/web/main.rs
+++ b/tests/web/main.rs
@@ -50,7 +50,7 @@ pub fn init_logging() {
/// Assert that the `container` contains the physical DOM tree that matches
/// `r`'s rendered virtual DOM.
-pub fn assert_rendered(container: &web_sys::Element, r: &R) {
+pub fn assert_rendered Render<'a>>(container: &web_sys::Element, r: &R) {
init_logging();
let cached_set = &RefCell::new(CachedSet::default());
@@ -155,11 +155,11 @@ pub struct RenderFn(F)
where
F: for<'a> Fn(&mut RenderContext<'a>) -> Node<'a>;
-impl Render for RenderFn
+impl<'a, F> Render<'a> for RenderFn
where
- F: for<'a> Fn(&mut RenderContext<'a>) -> Node<'a>,
+ F: for<'b> Fn(&mut RenderContext<'b>) -> Node<'b>,
{
- fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
(self.0)(cx)
}
}
@@ -169,8 +169,8 @@ where
/// the physical DOM tree correctly matches `after`.
pub async fn assert_before_after(before: R, after: S) -> Result<(), JsValue>
where
- R: 'static + Render,
- S: 'static + Render,
+ R: 'static + for<'a> Render<'a>,
+ S: 'static + for<'a> Render<'a>,
{
let container = create_element("div");
diff --git a/tests/web/render.rs b/tests/web/render.rs
index 5ff4e12..13c3f03 100644
--- a/tests/web/render.rs
+++ b/tests/web/render.rs
@@ -1,6 +1,7 @@
use super::{assert_rendered, before_after, create_element, RenderFn};
-use dodrio::{builder::*, Vdom};
+use dodrio::{builder::*, bumpalo::collections::String, Node, Render, RenderContext, Vdom};
use std::rc::Rc;
+use wasm_bindgen::{ JsCast};
use wasm_bindgen_test::*;
#[wasm_bindgen_test]
@@ -34,6 +35,93 @@ fn container_is_emptied_upon_drop() {
assert!(container.first_child().is_none());
}
+/// Renders a child with a lifetime scoped to the RenderContext bump arena.
+#[wasm_bindgen_test]
+fn render_bump_scoped_node() {
+ struct Child<'a> {
+ name: &'a str,
+ }
+
+ impl<'a> Render<'a> for Child<'a> {
+ fn render(&self, _cx: &mut RenderContext<'a>) -> Node<'a> {
+ text(self.name)
+ }
+ }
+
+ struct Parent;
+
+ impl<'a> Render<'a> for Parent {
+ fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
+ let child_name = String::from_str_in("child", cx.bump).into_bump_str();
+
+ div(&cx)
+ .children([Child { name: child_name }.render(cx)])
+ .finish()
+ }
+ }
+
+ let parent = Rc::new(RenderFn(|cx| {
+ Parent.render(cx)
+ }));
+
+ let container = create_element("div");
+ let _vdom = Vdom::new(&container, parent.clone());
+
+ assert_rendered(&container, &parent);
+}
+
+/// Originally, dodrio would use the className property for SVGs.
+///
+/// This is problematic because when SVG elements are created, the className is flagged as a read
+/// only property, so setting it causes an exception to be thrown. Here's an example of how this
+/// happens:
+///
+/// let elem = web_sys::window()
+/// .unwrap()
+/// .document()
+/// .unwrap()
+/// .create_element_ns(Some("http://www.w3.org/2000/svg"), "svg")
+/// .unwrap();
+///
+/// elem.set_class_name("does-not-work");
+///
+/// -----------------------------------------------------------------------------------------------
+///
+/// wasm-bindgen: imported JS function that was not marked as `catch` threw an error:
+/// setting getter-only property "className"
+///
+/// -----------------------------------------------------------------------------------------------
+///
+/// Now, dodrio passes the 'class' attribute of all namespaced elements into set_attribute. This
+/// satisfies the restrictions on SVG and keeps the optimized path for non-namespaced elements
+#[wasm_bindgen_test(async)]
+async fn test_svg_set_class() {
+ let container = create_element("div");
+
+
+ let valid_svg = Rc::new(RenderFn(|cx| {
+ ElementBuilder::new(cx.bump, "svg")
+ .namespace(Some("http://www.w3.org/2000/svg"))
+ .attr("class", "works")
+ .finish()
+ }));
+
+ let vdom = Vdom::new(&container, valid_svg.clone());
+ let weak = vdom.weak();
+
+ weak.render().await.unwrap();
+
+ assert_eq!(
+ "works",
+ container.first_child()
+ .expect("unable to get svg")
+ .dyn_ref::()
+ .expect("svg should be an element")
+ .get_attribute("class")
+ .expect("unable to get 'class' of svg")
+ );
+}
+
before_after! {
same_text {
before(_cx) {