From dbdd3b78e1f0aada1834dec5c6ee83449db9d220 Mon Sep 17 00:00:00 2001 From: Finn Bear Date: Thu, 9 May 2024 19:25:22 -0700 Subject: [PATCH] Namespace support for `VRaw`. (#3640) * WIP. * fmt. * Fix parameter order. * Cleanup. * Change the docs. * WIP test. * fmt. * Cast node to element. * Fix test. * Fix html in test. * Typo. --- packages/yew/src/dom_bundle/braw.rs | 48 ++++++++++++++++++++++++--- packages/yew/src/dom_bundle/utils.rs | 13 ++++++++ packages/yew/src/virtual_dom/vnode.rs | 4 +-- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/packages/yew/src/dom_bundle/braw.rs b/packages/yew/src/dom_bundle/braw.rs index 0d122a87c7e..753aab38d34 100644 --- a/packages/yew/src/dom_bundle/braw.rs +++ b/packages/yew/src/dom_bundle/braw.rs @@ -3,6 +3,7 @@ use web_sys::{Element, Node}; use super::{BNode, BSubtree, DomSlot, Reconcilable, ReconcileTarget}; use crate::html::AnyScope; +use crate::virtual_dom::vtag::{MATHML_NAMESPACE, SVG_NAMESPACE}; use crate::virtual_dom::VRaw; use crate::AttrValue; @@ -14,8 +15,10 @@ pub struct BRaw { } impl BRaw { - fn create_elements(html: &str) -> Vec { - let div = gloo::utils::document().create_element("div").unwrap(); + fn create_elements(html: &str, parent_namespace: Option<&str>) -> Vec { + let div = gloo::utils::document() + .create_element_ns(parent_namespace, "div") + .unwrap(); div.set_inner_html(html); let children = div.child_nodes(); let children = js_sys::Array::from(&children); @@ -71,7 +74,21 @@ impl Reconcilable for VRaw { parent: &Element, slot: DomSlot, ) -> (DomSlot, Self::Bundle) { - let elements = BRaw::create_elements(&self.html); + let namespace = if parent + .namespace_uri() + .map_or(false, |ns| ns == SVG_NAMESPACE) + { + Some(SVG_NAMESPACE) + } else if parent + .namespace_uri() + .map_or(false, |ns| ns == MATHML_NAMESPACE) + { + Some(MATHML_NAMESPACE) + } else { + None + }; + + let elements = BRaw::create_elements(&self.html, namespace); let count = elements.len(); let mut iter = elements.into_iter(); let reference = iter.next(); @@ -160,7 +177,9 @@ mod tests { use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; use super::*; - use crate::dom_bundle::utils::{setup_parent, setup_parent_and_sibling, SIBLING_CONTENT}; + use crate::dom_bundle::utils::{ + setup_parent, setup_parent_and_sibling, setup_parent_svg, SIBLING_CONTENT, + }; use crate::virtual_dom::VNode; wasm_bindgen_test_configure!(run_in_browser); @@ -173,7 +192,26 @@ mod tests { let elem = VNode::from_html_unchecked(HTML.into()); let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end()); assert_braw(&mut elem); - assert_eq!(parent.inner_html(), HTML) + assert_eq!(parent.inner_html(), HTML); + } + + #[test] + fn braw_works_svg() { + let (root, scope, parent) = setup_parent_svg(); + + const HTML: &str = r#""#; + let elem = VNode::from_html_unchecked(HTML.into()); + let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end()); + assert_braw(&mut elem); + assert_eq!(parent.inner_html(), HTML); + assert_eq!( + parent + .first_child() + .unwrap() + .unchecked_into::() + .namespace_uri(), + Some(SVG_NAMESPACE.to_owned()) + ); } #[test] diff --git a/packages/yew/src/dom_bundle/utils.rs b/packages/yew/src/dom_bundle/utils.rs index f4227fd13a7..0f502ceffa0 100644 --- a/packages/yew/src/dom_bundle/utils.rs +++ b/packages/yew/src/dom_bundle/utils.rs @@ -64,6 +64,7 @@ mod tests { use crate::dom_bundle::{BSubtree, DomSlot}; use crate::html::AnyScope; + use crate::virtual_dom::vtag::SVG_NAMESPACE; pub fn setup_parent() -> (BSubtree, AnyScope, Element) { let scope = AnyScope::test(); @@ -75,6 +76,18 @@ mod tests { (root, scope, parent) } + pub fn setup_parent_svg() -> (BSubtree, AnyScope, Element) { + let scope = AnyScope::test(); + let parent = document() + .create_element_ns(Some(SVG_NAMESPACE), "svg") + .unwrap(); + let root = BSubtree::create_root(&parent); + + document().body().unwrap().append_child(&parent).unwrap(); + + (root, scope, parent) + } + pub const SIBLING_CONTENT: &str = "END"; pub(crate) fn setup_parent_and_sibling() -> (BSubtree, AnyScope, Element, DomSlot) { diff --git a/packages/yew/src/virtual_dom/vnode.rs b/packages/yew/src/virtual_dom/vnode.rs index 8ed18f29c9f..7a4f35b4c6b 100644 --- a/packages/yew/src/virtual_dom/vnode.rs +++ b/packages/yew/src/virtual_dom/vnode.rs @@ -76,8 +76,8 @@ impl VNode { /// /// # Behavior in browser /// - /// In the browser, this function creates an element, sets the passed HTML to its `innerHTML` - /// and inserts the contents of it into the DOM. + /// In the browser, this function creates an element with the same XML namespace as the parent, + /// sets the passed HTML to its `innerHTML` and inserts the contents of it into the DOM. /// /// # Behavior on server ///