fix: don't insert empty child for comment/doctype (closes #2549) (#2581)

This commit is contained in:
Greg Johnston 2024-05-08 07:19:57 -04:00 committed by GitHub
parent 6a8e4bb453
commit f3f3a053ba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 69 additions and 66 deletions

View file

@ -2,41 +2,41 @@ use crate::{html::ElementDescriptor, HtmlElement};
use leptos_reactive::{create_render_effect, signal_prelude::*};
use std::cell::Cell;
/// Contains a shared reference to a DOM node created while using the `view`
/// macro to create your UI.
///
/// ```
/// # use leptos::{*, logging::log};
/// use leptos::html::Input;
///
/// #[component]
/// pub fn MyComponent() -> impl IntoView {
/// let input_ref = create_node_ref::<Input>();
///
/// let on_click = move |_| {
/// let node =
/// input_ref.get().expect("input_ref should be loaded by now");
/// // `node` is strongly typed
/// // it is dereferenced to an `HtmlInputElement` automatically
/// log!("value is {:?}", node.value())
/// };
///
/// view! {
/// <div>
/// // `node_ref` loads the input
/// <input _ref=input_ref type="text"/>
/// // the button consumes it
/// <button on:click=on_click>"Click me"</button>
/// </div>
/// }
/// }
/// ```
#[cfg_attr(not(debug_assertions), repr(transparent))]
pub struct NodeRef<T: ElementDescriptor + 'static> {
element: RwSignal<Option<HtmlElement<T>>>,
#[cfg(debug_assertions)]
defined_at: &'static std::panic::Location<'static>,
}
/// Contains a shared reference to a DOM node created while using the `view`
/// macro to create your UI.
///
/// ```
/// # use leptos::{*, logging::log};
/// use leptos::html::Input;
///
/// #[component]
/// pub fn MyComponent() -> impl IntoView {
/// let input_ref = create_node_ref::<Input>();
///
/// let on_click = move |_| {
/// let node =
/// input_ref.get().expect("input_ref should be loaded by now");
/// // `node` is strongly typed
/// // it is dereferenced to an `HtmlInputElement` automatically
/// log!("value is {:?}", node.value())
/// };
///
/// view! {
/// <div>
/// // `node_ref` loads the input
/// <input _ref=input_ref type="text"/>
/// // the button consumes it
/// <button on:click=on_click>"Click me"</button>
/// </div>
/// }
/// }
/// ```
#[cfg_attr(not(debug_assertions), repr(transparent))]
pub struct NodeRef<T: ElementDescriptor + 'static> {
element: RwSignal<Option<HtmlElement<T>>>,
#[cfg(debug_assertions)]
defined_at: &'static std::panic::Location<'static>,
}
/// Creates a shared reference to a DOM node created while using the `view`
/// macro to create your UI.
@ -71,9 +71,9 @@ use std::cell::Cell;
#[inline(always)]
pub fn create_node_ref<T: ElementDescriptor + 'static>() -> NodeRef<T> {
NodeRef {
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
element: create_rw_signal(None),
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
element: create_rw_signal(None),
}
}
@ -155,10 +155,9 @@ impl<T: ElementDescriptor + 'static> NodeRef<T> {
if current.is_some() {
crate::debug_warn!(
"You are setting the NodeRef defined at {}, which has \
already been filled \
Its possible this is intentional, but its also \
possible that youre accidentally using the same NodeRef \
for multiple _ref attributes.",
already been filled Its possible this is intentional, \
but its also possible that youre accidentally using \
the same NodeRef for multiple _ref attributes.",
self.defined_at
);
}

View file

@ -298,34 +298,38 @@ pub(crate) fn element_to_tokens(
let children = node
.children
.iter()
.map(|node| match node {
Node::Fragment(fragment) => fragment_to_tokens(
&fragment.children,
true,
parent_type,
None,
global_class,
None,
)
.unwrap_or(quote_spanned! {
Span::call_site()=> ::leptos::leptos_dom::Unit
}),
Node::Text(node) => quote! { #node },
.filter_map(|node| match node {
Node::Fragment(fragment) => Some(
fragment_to_tokens(
&fragment.children,
true,
parent_type,
None,
global_class,
None,
)
.unwrap_or(quote_spanned! {
Span::call_site()=> ::leptos::leptos_dom::Unit
}),
),
Node::Text(node) => Some(quote! { #node }),
Node::RawText(node) => {
let text = node.to_string_best();
let text = syn::LitStr::new(&text, node.span());
quote! { #text }
Some(quote! { #text })
}
Node::Block(node) => quote! { #node },
Node::Element(node) => element_to_tokens(
node,
parent_type,
None,
global_class,
None,
)
.unwrap_or_default(),
Node::Comment(_) | Node::Doctype(_) => quote! {},
Node::Block(node) => Some(quote! { #node }),
Node::Element(node) => Some(
element_to_tokens(
node,
parent_type,
None,
global_class,
None,
)
.unwrap_or_default(),
),
Node::Comment(_) | Node::Doctype(_) => None,
})
.map(|node| quote!(.child(#node)));