Merge branch 'leptos_dom_v2' of https://github.com/jquesada2016/leptos into leptos_dom_v2

This commit is contained in:
Greg Johnston 2022-12-10 14:09:43 -05:00
commit 4a9f906571
12 changed files with 122 additions and 56 deletions

View File

@ -12,6 +12,7 @@ pub use fragment::*;
use leptos_reactive::Scope; use leptos_reactive::Scope;
use std::borrow::Cow; use std::borrow::Cow;
pub use unit::*; pub use unit::*;
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
/// The core foundational leptos components. /// The core foundational leptos components.

View File

@ -1,8 +1,11 @@
use crate::{hydration::HydrationCtx, Comment, IntoView, View}; use crate::{hydration::HydrationCtx, Comment, IntoView, View};
#[cfg(all(target_arch = "wasm32", feature = "web"))] #[cfg(all(target_arch = "wasm32", feature = "web"))]
use crate::{mount_child, MountKind, Mountable}; use crate::{mount_child, MountKind, Mountable};
use leptos_reactive::{create_effect, Scope, ScopeDisposer}; use leptos_reactive::Scope;
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use leptos_reactive::{create_effect, ScopeDisposer};
use std::{borrow::Cow, cell::RefCell, rc::Rc}; use std::{borrow::Cow, cell::RefCell, rc::Rc};
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
/// The internal representation of the [`DynChild`] core-component. /// The internal representation of the [`DynChild`] core-component.

View File

@ -1,18 +1,20 @@
use crate::{hydration::HydrationCtx, Comment, CoreComponent, IntoView, View}; use crate::{hydration::HydrationCtx, Comment, CoreComponent, IntoView, View};
#[cfg(all(target_arch = "wasm32", feature = "web"))] #[cfg(all(target_arch = "wasm32", feature = "web"))]
use crate::{mount_child, MountKind, Mountable, RANGE}; use crate::{mount_child, MountKind, Mountable, RANGE};
use leptos_reactive::{create_effect, Scope}; #[cfg(all(target_arch = "wasm32", feature = "web"))]
use leptos_reactive::create_effect;
use leptos_reactive::Scope;
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use rustc_hash::FxHasher; use rustc_hash::FxHasher;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{ #[cfg(all(target_arch = "wasm32", feature = "web"))]
borrow::Cow, use std::hash::BuildHasherDefault;
cell::RefCell, use std::{borrow::Cow, cell::RefCell, hash::Hash, rc::Rc};
hash::{BuildHasherDefault, Hash},
rc::Rc,
};
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
#[cfg(all(target_arch = "wasm32", feature = "web"))]
type FxIndexSet<T> = indexmap::IndexSet<T, BuildHasherDefault<FxHasher>>; type FxIndexSet<T> = indexmap::IndexSet<T, BuildHasherDefault<FxHasher>>;
#[cfg(all(target_arch = "wasm32", feature = "web"))] #[cfg(all(target_arch = "wasm32", feature = "web"))]
@ -269,12 +271,14 @@ where
key_fn, key_fn,
} = self; } = self;
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
let _ = key_fn;
let component = EachRepr::default(); let component = EachRepr::default();
let children = component.children.clone();
#[cfg(all(target_arch = "wasm32", feature = "web"))] #[cfg(all(target_arch = "wasm32", feature = "web"))]
let closing = component.closing.node.clone(); let (children, closing) =
(component.children.clone(), component.closing.node.clone());
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(all(target_arch = "wasm32", feature = "web"))] { if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
@ -341,6 +345,7 @@ where
struct HashRun<T>(#[educe(Debug(ignore))] T); struct HashRun<T>(#[educe(Debug(ignore))] T);
/// Calculates the operations need to get from `a` to `b`. /// Calculates the operations need to get from `a` to `b`.
#[cfg(all(target_arch = "wasm32", feature = "web"))]
fn diff<K: Eq + Hash>(from: &FxIndexSet<K>, to: &FxIndexSet<K>) -> Diff { fn diff<K: Eq + Hash>(from: &FxIndexSet<K>, to: &FxIndexSet<K>) -> Diff {
if from.is_empty() && to.is_empty() { if from.is_empty() && to.is_empty() {
return Diff::default(); return Diff::default();
@ -428,6 +433,7 @@ fn diff<K: Eq + Hash>(from: &FxIndexSet<K>, to: &FxIndexSet<K>) -> Diff {
diffs diffs
} }
#[cfg(all(target_arch = "wasm32", feature = "web"))]
fn apply_opts<K: Eq + Hash>( fn apply_opts<K: Eq + Hash>(
from: &FxIndexSet<K>, from: &FxIndexSet<K>,
to: &FxIndexSet<K>, to: &FxIndexSet<K>,
@ -463,6 +469,7 @@ fn apply_opts<K: Eq + Hash>(
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
#[allow(unused)]
struct Diff { struct Diff {
removed: SmallVec<[DiffOpRemove; 8]>, removed: SmallVec<[DiffOpRemove; 8]>,
moved: SmallVec<[DiffOpMove; 8]>, moved: SmallVec<[DiffOpMove; 8]>,
@ -471,6 +478,7 @@ struct Diff {
} }
#[derive(Debug)] #[derive(Debug)]
#[allow(unused)]
struct DiffOpMove { struct DiffOpMove {
from: usize, from: usize,
to: usize, to: usize,
@ -478,17 +486,20 @@ struct DiffOpMove {
} }
#[derive(Debug)] #[derive(Debug)]
#[allow(unused)]
struct DiffOpAdd { struct DiffOpAdd {
at: usize, at: usize,
mode: DiffOpAddMode, mode: DiffOpAddMode,
} }
#[derive(Debug)] #[derive(Debug)]
#[allow(unused)]
struct DiffOpRemove { struct DiffOpRemove {
at: usize, at: usize,
} }
#[derive(Default, Debug)] #[derive(Default, Debug)]
#[allow(unused)]
enum DiffOpAddMode { enum DiffOpAddMode {
#[default] #[default]
Normal, Normal,

View File

@ -1,6 +1,7 @@
#[cfg(all(target_arch = "wasm32", feature = "web"))] #[cfg(all(target_arch = "wasm32", feature = "web"))]
use crate::Mountable; use crate::Mountable;
use crate::{hydration::HydrationCtx, Comment, CoreComponent, IntoView, View}; use crate::{hydration::HydrationCtx, Comment, CoreComponent, IntoView, View};
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
/// The internal representation of the [`Unit`] core-component. /// The internal representation of the [`Unit`] core-component.

View File

@ -1,9 +1,11 @@
pub mod typed; pub mod typed;
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use crate::window; use crate::window;
use std::{borrow::Cow, cell::RefCell, collections::HashSet}; use std::{borrow::Cow, cell::RefCell, collections::HashSet};
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use wasm_bindgen::{ use wasm_bindgen::{
closure::Closure, convert::FromWasmAbi, intern, JsCast, JsValue, convert::FromWasmAbi, intern, prelude::Closure, JsCast, JsValue,
UnwrapThrowExt, UnwrapThrowExt,
}; };
@ -12,6 +14,7 @@ thread_local! {
} }
/// Adds an event listener to the `Window`. /// Adds an event listener to the `Window`.
#[cfg(all(target_arch = "wasm32", feature = "web"))]
pub fn window_event_listener( pub fn window_event_listener(
event_name: &str, event_name: &str,
cb: impl Fn(web_sys::Event) + 'static, cb: impl Fn(web_sys::Event) + 'static,
@ -23,6 +26,7 @@ pub fn window_event_listener(
} }
/// Adds an event listener to the target DOM element using implicit event delegation. /// Adds an event listener to the target DOM element using implicit event delegation.
#[cfg(all(target_arch = "wasm32", feature = "web"))]
pub fn add_event_listener<E>( pub fn add_event_listener<E>(
target: &web_sys::Element, target: &web_sys::Element,
event_name: Cow<'static, str>, event_name: Cow<'static, str>,
@ -37,6 +41,7 @@ pub fn add_event_listener<E>(
} }
#[doc(hidden)] #[doc(hidden)]
#[cfg(all(target_arch = "wasm32", feature = "web"))]
pub fn add_event_listener_undelegated<E>( pub fn add_event_listener_undelegated<E>(
target: &web_sys::Element, target: &web_sys::Element,
event_name: &str, event_name: &str,
@ -50,6 +55,7 @@ pub fn add_event_listener_undelegated<E>(
} }
// cf eventHandler in ryansolid/dom-expressions // cf eventHandler in ryansolid/dom-expressions
#[cfg(all(target_arch = "wasm32", feature = "web"))]
pub(crate) fn add_delegated_event_listener(event_name: Cow<'static, str>) { pub(crate) fn add_delegated_event_listener(event_name: Cow<'static, str>) {
GLOBAL_EVENTS.with(|global_events| { GLOBAL_EVENTS.with(|global_events| {
let mut events = global_events.borrow_mut(); let mut events = global_events.borrow_mut();
@ -113,6 +119,7 @@ pub(crate) fn add_delegated_event_listener(event_name: Cow<'static, str>) {
}) })
} }
#[cfg(all(target_arch = "wasm32", feature = "web"))]
pub(crate) fn event_delegation_key(event_name: &str) -> String { pub(crate) fn event_delegation_key(event_name: &str) -> String {
let event_name = intern(event_name); let event_name = intern(event_name);
let mut n = String::from("$$$"); let mut n = String::from("$$$");

View File

@ -1,11 +1,16 @@
#[cfg(all(target_arch = "wasm32", feature = "web"))] #[cfg(all(target_arch = "wasm32", feature = "web"))]
use crate::events::*; use crate::events::*;
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use crate::macro_helpers::Property;
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use crate::macro_helpers::{
attribute_expression, class_expression, property_expression,
};
use crate::{ use crate::{
ev::EventDescriptor, ev::EventDescriptor,
hydration::HydrationCtx, hydration::HydrationCtx,
macro_helpers::{ macro_helpers::{
attribute_expression, class_expression, property_expression, Attribute, Attribute, Class, IntoAttribute, IntoChild, IntoClass, IntoProperty,
Class, IntoAttribute, IntoChild, IntoClass, IntoProperty, Property,
}, },
Element, Fragment, IntoView, NodeRef, Text, View, Element, Fragment, IntoView, NodeRef, Text, View,
}; };
@ -15,10 +20,15 @@ use crate::{mount_child, MountKind};
use std::cell::OnceCell; use std::cell::OnceCell;
use cfg_if::cfg_if; use cfg_if::cfg_if;
use leptos_reactive::{create_render_effect, Scope}; #[cfg(all(target_arch = "wasm32", feature = "web"))]
use leptos_reactive::create_render_effect;
use leptos_reactive::Scope;
#[cfg(not(all(target_arch = "wasm32", feature = "web")))] #[cfg(not(all(target_arch = "wasm32", feature = "web")))]
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use std::{borrow::Cow, cell::LazyCell, fmt, ops::Deref}; use std::{borrow::Cow, fmt};
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use std::{cell::LazyCell, ops::Deref};
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
/// Trait alias for the trait bounts on [`IntoElement`]. /// Trait alias for the trait bounts on [`IntoElement`].
@ -61,14 +71,45 @@ pub trait IntoElement: IntoElementBounds {
fn hydration_id(&self) -> usize; fn hydration_id(&self) -> usize;
} }
/// Trait for converting [`web_sys::Element`] to [`HtmlElement`].
pub trait ToHtmlElement {
/// Converts the type to [`HtmlElement`].
fn to_leptos_element(self, cx: Scope) -> HtmlElement<AnyElement>;
}
impl<T> ToHtmlElement for T
where
T: AsRef<web_sys::Element>,
{
fn to_leptos_element(self, cx: Scope) -> HtmlElement<AnyElement> {
#[cfg(all(target_arch = "wasm32", feature = "web"))]
{
let el = self.as_ref().clone().unchecked_into();
let element = AnyElement {
name: "".into(),
is_void: false,
element: el,
};
HtmlElement { cx, element }
}
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
{
let _ = cx;
unreachable!();
}
}
}
/// Represents potentially any element. /// Represents potentially any element.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[cfg_attr(all(target_arch = "wasm32", feature = "web"), derive(educe::Educe))] #[cfg_attr(all(target_arch = "wasm32", feature = "web"), derive(educe::Educe))]
#[cfg_attr(all(target_arch = "wasm32", feature = "web"), educe(Deref))] #[cfg_attr(all(target_arch = "wasm32", feature = "web"), educe(Deref))]
pub struct AnyElement { pub struct AnyElement {
name: Cow<'static, str>, name: Cow<'static, str>,
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
dynamic: bool,
#[cfg(all(target_arch = "wasm32", feature = "web"))] #[cfg(all(target_arch = "wasm32", feature = "web"))]
#[educe(Deref)] #[educe(Deref)]
element: web_sys::HtmlElement, element: web_sys::HtmlElement,
@ -151,7 +192,6 @@ cfg_if! {
pub(crate) cx: Scope, pub(crate) cx: Scope,
pub(crate) element: El, pub(crate) element: El,
pub(crate) id: OnceCell<Cow<'static, str>>, pub(crate) id: OnceCell<Cow<'static, str>>,
pub(crate) dynamic: bool,
#[educe(Debug(ignore))] #[educe(Debug(ignore))]
pub(crate) attrs: SmallVec<[(Cow<'static, str>, Cow<'static, str>); 4]>, pub(crate) attrs: SmallVec<[(Cow<'static, str>, Cow<'static, str>); 4]>,
#[educe(Debug(ignore))] #[educe(Debug(ignore))]
@ -173,7 +213,6 @@ impl<El: IntoElement> HtmlElement<El> {
Self { Self {
cx, cx,
id: Default::default(), id: Default::default(),
dynamic: false,
attrs: smallvec![], attrs: smallvec![],
children: smallvec![], children: smallvec![],
element, element,
@ -203,7 +242,6 @@ impl<El: IntoElement> HtmlElement<El> {
let Self { let Self {
cx, cx,
id, id,
dynamic,
attrs, attrs,
children, children,
element, element,
@ -212,12 +250,10 @@ impl<El: IntoElement> HtmlElement<El> {
HtmlElement { HtmlElement {
cx, cx,
id, id,
dynamic,
attrs, attrs,
children, children,
element: AnyElement { element: AnyElement {
name: element.name(), name: element.name(),
dynamic,
is_void: element.is_void(), is_void: element.is_void(),
id: element.hydration_id(), id: element.hydration_id(),
}, },
@ -257,6 +293,9 @@ impl<El: IntoElement> HtmlElement<El> {
#[cfg(all(target_arch = "wasm32", feature = "web"))] #[cfg(all(target_arch = "wasm32", feature = "web"))]
node_ref.load(&self); node_ref.load(&self);
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
let _ = node_ref;
self self
} }
@ -295,7 +334,6 @@ impl<El: IntoElement> HtmlElement<El> {
let mut attr = attr.into_attribute(this.cx); let mut attr = attr.into_attribute(this.cx);
while let Attribute::Fn(_, f) = attr { while let Attribute::Fn(_, f) = attr {
this.dynamic = true;
attr = f(); attr = f();
} }
match attr { match attr {
@ -357,10 +395,7 @@ impl<El: IntoElement> HtmlElement<El> {
let include = match class { let include = match class {
Class::Value(include) => include, Class::Value(include) => include,
Class::Fn(_, f) => { Class::Fn(_, f) => f(),
this.dynamic = true;
f()
}
}; };
if include { if include {
@ -408,17 +443,15 @@ impl<El: IntoElement> HtmlElement<El> {
property_expression(el, prop_name, value) property_expression(el, prop_name, value)
} }
}; };
self
} }
#[cfg(not(all(target_arch = "wasm32", feature = "web")))] #[cfg(not(all(target_arch = "wasm32", feature = "web")))]
{ {
let mut this = self; let _ = name;
let _ = value;
this.dynamic = true;
this
} }
self
} }
/// Adds an event listener to this element. /// Adds an event listener to this element.
@ -451,13 +484,10 @@ impl<El: IntoElement> HtmlElement<El> {
#[cfg(not(all(target_arch = "wasm32", feature = "web")))] #[cfg(not(all(target_arch = "wasm32", feature = "web")))]
{ {
let mut this = self;
this.dynamic = true;
_ = event; _ = event;
_ = event_handler; _ = event_handler;
this self
} }
} }
@ -499,7 +529,6 @@ impl<El: IntoElement> IntoView for HtmlElement<El> {
element, element,
mut attrs, mut attrs,
children, children,
dynamic,
.. ..
} = self; } = self;
@ -514,7 +543,6 @@ impl<El: IntoElement> IntoView for HtmlElement<El> {
attrs.push(("id".into(), format!("_{}", id).into())); attrs.push(("id".into(), format!("_{}", id).into()));
} }
element.dynamic = dynamic;
element.attrs = attrs; element.attrs = attrs;
element.children.extend(children); element.children.extend(children);
@ -572,6 +600,7 @@ macro_rules! generate_html_tags {
),* $(,)?) => { ),* $(,)?) => {
paste::paste! { paste::paste! {
$( $(
#[cfg(all(target_arch = "wasm32", feature = "web"))]
#[thread_local] #[thread_local]
static [<$tag:upper>]: LazyCell<web_sys::HtmlElement> = LazyCell::new(|| { static [<$tag:upper>]: LazyCell<web_sys::HtmlElement> = LazyCell::new(|| {
crate::document() crate::document()

View File

@ -1,8 +1,10 @@
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use std::cell::LazyCell; use std::cell::LazyCell;
/// We can tell if we start in hydration mode by checking to see if the /// We can tell if we start in hydration mode by checking to see if the
/// id "_0" is present in the DOM. If it is, we know we are hydrating from /// id "_0" is present in the DOM. If it is, we know we are hydrating from
/// the server, if not, we are starting off in CSR /// the server, if not, we are starting off in CSR
#[cfg(all(target_arch = "wasm32", feature = "web"))]
#[thread_local] #[thread_local]
static mut IS_HYDRATING: LazyCell<bool> = LazyCell::new(|| { static mut IS_HYDRATING: LazyCell<bool> = LazyCell::new(|| {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -35,12 +37,14 @@ impl HydrationCtx {
unsafe { ID = 0 }; unsafe { ID = 0 };
} }
#[cfg(all(target_arch = "wasm32", feature = "web"))]
pub(crate) fn stop_hydrating() { pub(crate) fn stop_hydrating() {
unsafe { unsafe {
std::mem::take(&mut IS_HYDRATING); std::mem::take(&mut IS_HYDRATING);
} }
} }
#[cfg(all(target_arch = "wasm32", feature = "web"))]
pub(crate) fn is_hydrating() -> bool { pub(crate) fn is_hydrating() -> bool {
unsafe { *IS_HYDRATING } unsafe { *IS_HYDRATING }
} }

View File

@ -29,11 +29,16 @@ pub use logging::*;
pub use node_ref::*; pub use node_ref::*;
#[cfg(not(all(target_arch = "wasm32", feature = "web")))] #[cfg(not(all(target_arch = "wasm32", feature = "web")))]
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{borrow::Cow, cell::LazyCell, fmt}; use std::borrow::Cow;
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use std::{cell::LazyCell, fmt};
pub use wasm_bindgen; pub use wasm_bindgen;
use wasm_bindgen::{JsCast, UnwrapThrowExt}; #[cfg(all(target_arch = "wasm32", feature = "web"))]
use wasm_bindgen::JsCast;
use wasm_bindgen::UnwrapThrowExt;
pub use web_sys; pub use web_sys;
#[cfg(all(target_arch = "wasm32", feature = "web"))]
#[thread_local] #[thread_local]
static COMMENT: LazyCell<web_sys::Node> = static COMMENT: LazyCell<web_sys::Node> =
LazyCell::new(|| document().create_comment("").unchecked_into()); LazyCell::new(|| document().create_comment("").unchecked_into());
@ -128,7 +133,6 @@ cfg_if! {
pub struct Element { pub struct Element {
name: Cow<'static, str>, name: Cow<'static, str>,
is_void: bool, is_void: bool,
dynamic: bool,
attrs: SmallVec<[(Cow<'static, str>, Cow<'static, str>); 4]>, attrs: SmallVec<[(Cow<'static, str>, Cow<'static, str>); 4]>,
children: Vec<View>, children: Vec<View>,
id: usize, id: usize,
@ -158,7 +162,6 @@ impl Element {
Self { Self {
name: el.name(), name: el.name(),
is_void: el.is_void(), is_void: el.is_void(),
dynamic: false,
attrs: Default::default(), attrs: Default::default(),
children: Default::default(), children: Default::default(),
id: el.hydration_id(), id: el.hydration_id(),
@ -183,6 +186,12 @@ impl Comment {
) -> Self { ) -> Self {
let content = content.into(); let content = content.into();
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
{
let _ = id;
let _ = closing;
}
#[cfg(all(target_arch = "wasm32", feature = "web"))] #[cfg(all(target_arch = "wasm32", feature = "web"))]
let node = COMMENT.clone_node().unwrap(); let node = COMMENT.clone_node().unwrap();
@ -339,6 +348,7 @@ impl View {
} }
} }
#[cfg(all(target_arch = "wasm32", feature = "web"))]
fn get_text(&self) -> Option<&Text> { fn get_text(&self) -> Option<&Text> {
if let Self::Text(t) = self { if let Self::Text(t) = self {
Some(t) Some(t)

View File

@ -1,6 +1,7 @@
use std::rc::Rc; use std::rc::Rc;
use leptos_reactive::Scope; use leptos_reactive::Scope;
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use wasm_bindgen::UnwrapThrowExt; use wasm_bindgen::UnwrapThrowExt;
/// Represents the different possible values an attribute node could have. /// Represents the different possible values an attribute node could have.
@ -146,6 +147,7 @@ attr_type!(f32);
attr_type!(f64); attr_type!(f64);
attr_type!(char); attr_type!(char);
#[cfg(all(target_arch = "wasm32", feature = "web"))]
pub fn attribute_expression( pub fn attribute_expression(
el: &web_sys::Element, el: &web_sys::Element,
attr_name: &str, attr_name: &str,

View File

@ -1,4 +1,5 @@
use leptos_reactive::Scope; use leptos_reactive::Scope;
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use wasm_bindgen::UnwrapThrowExt; use wasm_bindgen::UnwrapThrowExt;
/// Represents the different possible values a single class on an element could have, /// Represents the different possible values a single class on an element could have,
@ -65,6 +66,7 @@ impl<T: IntoClass> IntoClass for (Scope, T) {
} }
} }
#[cfg(all(target_arch = "wasm32", feature = "web"))]
pub fn class_expression( pub fn class_expression(
class_list: &web_sys::DomTokenList, class_list: &web_sys::DomTokenList,
class_name: &str, class_name: &str,

View File

@ -1,5 +1,7 @@
use leptos_reactive::Scope; use leptos_reactive::Scope;
use wasm_bindgen::{JsValue, UnwrapThrowExt}; use wasm_bindgen::JsValue;
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use wasm_bindgen::UnwrapThrowExt;
/// Represents the different possible values an element property could have, /// Represents the different possible values an element property could have,
/// allowing you to do fine-grained updates to single fields. /// allowing you to do fine-grained updates to single fields.
@ -74,6 +76,7 @@ prop_type!(f32);
prop_type!(f64); prop_type!(f64);
prop_type!(bool); prop_type!(bool);
#[cfg(all(target_arch = "wasm32", feature = "web"))]
pub fn property_expression( pub fn property_expression(
el: &web_sys::Element, el: &web_sys::Element,
prop_name: &str, prop_name: &str,

View File

@ -3,7 +3,7 @@
use crate::{CoreComponent, HydrationCtx, View}; use crate::{CoreComponent, HydrationCtx, View};
use cfg_if::cfg_if; use cfg_if::cfg_if;
use itertools::Itertools; use itertools::Itertools;
use std::{borrow::Cow, fmt::Display}; use std::borrow::Cow;
impl View { impl View {
/// Consumes the node and renders it into an HTML string. /// Consumes the node and renders it into an HTML string.
@ -123,17 +123,14 @@ impl View {
} }
View::Element(el) => { View::Element(el) => {
let tag_name = el.name; let tag_name = el.name;
let mut has_id = false;
let mut attrs = el let attrs = el
.attrs .attrs
.into_iter() .into_iter()
.map(|(name, value)| -> Cow<'static, str> { .map(|(name, value)| -> Cow<'static, str> {
if value.is_empty() { if value.is_empty() {
format!(" {name}").into() format!(" {name}").into()
} else { } else {
if name == "id" {
has_id = true;
}
format!( format!(
" {name}=\"{}\"", " {name}=\"{}\"",
html_escape::encode_double_quoted_attribute(&value) html_escape::encode_double_quoted_attribute(&value)
@ -143,10 +140,6 @@ impl View {
}) })
.join(""); .join("");
if !has_id && el.dynamic {
attrs.push_str(&format!(" id=\"_{}\"", el.id));
}
if el.is_void { if el.is_void {
format!("<{tag_name}{attrs}/>").into() format!("<{tag_name}{attrs}/>").into()
} else { } else {