From e17afd45598ae1f8ad283b44f925cecdd7561c56 Mon Sep 17 00:00:00 2001 From: Greg Johnston Date: Sat, 14 Jan 2023 14:09:23 -0500 Subject: [PATCH] Handle custom elements correctly --- leptos_dom/src/html.rs | 60 ++++++++++++++++++++++++++++++++++++++++ leptos_macro/src/view.rs | 2 +- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/leptos_dom/src/html.rs b/leptos_dom/src/html.rs index 613300ab0..c1fce3611 100644 --- a/leptos_dom/src/html.rs +++ b/leptos_dom/src/html.rs @@ -165,6 +165,66 @@ pub struct Custom { id: HydrationKey, } +impl Custom { + pub fn new(name: impl Into>) -> Self { + let name = name.into(); + let id = HydrationCtx::id(); + + #[cfg(all(target_arch = "wasm32", feature = "web"))] + let element = if HydrationCtx::is_hydrating() { + if let Some(el) = crate::document().get_element_by_id(&format!("_{id}")) { + #[cfg(debug_assertions)] + assert_eq!( + el.node_name().to_ascii_uppercase(), + name.to_ascii_uppercase(), + "SSR and CSR elements have the same `TopoId` but different node \ + kinds. This is either a discrepancy between SSR and CSR rendering + logic, which is considered a bug, or it can also be a \ + leptos hydration issue." + ); + + el.remove_attribute("id").unwrap(); + + el.unchecked_into() + } else if let Ok(Some(el)) = + crate::document().query_selector(&format!("[leptos-hk=_{id}]")) + { + #[cfg(debug_assertions)] + assert_eq!( + el.node_name().to_ascii_uppercase(), + name.to_ascii_uppercase(), + "SSR and CSR elements have the same `TopoId` but different node \ + kinds. This is either a discrepancy between SSR and CSR rendering + logic, which is considered a bug, or it can also be a \ + leptos hydration issue." + ); + + el.remove_attribute("leptos-hk").unwrap(); + + el.unchecked_into() + } else { + gloo::console::warn!( + "element with id", + format!("_{id}"), + "not found, ignoring it for hydration" + ); + + crate::document().create_element(&name).unwrap() + } + } else { + crate::document().create_element(&name).unwrap() + }; + + Self { + name, + #[cfg(all(target_arch = "wasm32", feature = "web"))] + element: element.unchecked_into(), + #[cfg(not(all(target_arch = "wasm32", feature = "web")))] + id, + } + } +} + #[cfg(all(target_arch = "wasm32", feature = "web"))] impl std::ops::Deref for Custom { type Target = web_sys::HtmlElement; diff --git a/leptos_macro/src/view.rs b/leptos_macro/src/view.rs index 941f67c5a..1516b6175 100644 --- a/leptos_macro/src/view.rs +++ b/leptos_macro/src/view.rs @@ -554,7 +554,7 @@ fn element_to_tokens(cx: &Ident, node: &NodeElement, mut parent_type: TagType) - let tag = node.name.to_string(); let name = if is_custom_element(&tag) { let name = node.name.to_string(); - quote! { leptos::leptos_dom::custom(#cx, #name) } + quote! { leptos::leptos_dom::custom(#cx, leptos::leptos_dom::Custom::new(#name)) } } else if is_svg_element(&tag) { let name = &node.name; parent_type = TagType::Svg;