Deal w/ merge issues and get SSR working

This commit is contained in:
Greg Johnston 2022-12-05 16:04:02 -05:00
parent dbb0fca1cb
commit 0230b1ffa5
7 changed files with 381 additions and 519 deletions

View File

@ -46,7 +46,7 @@ pub struct EachRepr {
document_fragment: web_sys::DocumentFragment,
#[cfg(debug_assertions)]
opening: Comment,
children: Rc<RefCell<Vec<Option<EachItem>>>>,
pub(crate) children: Rc<RefCell<Vec<Option<EachItem>>>>,
closing: Comment,
}
@ -112,12 +112,12 @@ impl Mountable for EachRepr {
/// The internal representation of an [`EachKey`] item.
#[derive(Debug)]
struct EachItem {
pub(crate) struct EachItem {
#[cfg(all(target_arch = "wasm32", feature = "web"))]
document_fragment: web_sys::DocumentFragment,
#[cfg(debug_assertions)]
opening: Comment,
child: View,
pub(crate) child: View,
closing: Comment,
}

View File

@ -259,17 +259,23 @@ impl<El: IntoElement> HtmlElement<El> {
else {
let mut attr = attr.into_attribute(cx);
while let Attribute::Fn(f) = attr {
self.dynamic = true;
attr = f();
}
match attr {
Attribute::String(value) => self.attr(name, value),
Attribute::String(value) => {
self.attrs.push((name, value.into()));
self
},
Attribute::Bool(include) => if include {
self.attr_bool(name)
self.attrs.push((name, "".into()));
self
} else {
self
},
Attribute::Option(maybe) => if let Some(value) = maybe {
self.attr(name, value)
self.attrs.push((name, value.into()));
self
} else {
self
}
@ -279,7 +285,7 @@ impl<El: IntoElement> HtmlElement<El> {
}
}
#[doc(hidden)]
/// Adds a class to an element.
#[track_caller]
pub fn class(
mut self,
@ -289,96 +295,87 @@ impl<El: IntoElement> HtmlElement<El> {
) -> Self {
let name = name.into();
cfg_if! {
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
create_effect(
self.cx,
clone!([{ *self.element.get_element() } as element], move |_| {
if let Some(value) = f() {
let value = value.into();
element.set_attribute(intern(&name), intern(&value)).unwrap();
} else {
element.remove_attribute(intern(&name)).unwrap();
}
}),
);
} else {
if let Some(value) = f() {
let value = value.into();
self.attrs.push((name, value));
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
let el = self.element.get_element();
let class_list = el.class_list();
let value = class.into_class(cx);
match value {
Class::Fn(f) => {
create_render_effect(cx, move |old| {
let new = f();
if old.as_ref() != Some(&new) && (old.is_some() || new) {
class_expression(&class_list, &name, new)
}
new
});
}
}
}
self
}
/// Creates a boolean attribute which changes automatically when it's
/// signal changes.
#[track_caller]
pub fn dyn_attr_bool<F>(
self,
name: impl Into<Cow<'static, str>>,
f: F,
) -> Self
where
F: Fn() -> bool + 'static,
{
self.dyn_attr(name, move || f().then_some(""))
}
/// Addes the provided classes to the element. You can call this
/// as many times as needed, seperating the classes by spaces.
#[track_caller]
pub fn class(self, classes: impl Into<Cow<'static, str>>) -> Self {
self.attr("class", classes)
}
/// Addes the provided classes to the element when the predicate is true.
/// You can call this as many times as needed, seperating the classes
/// by spaces.
#[track_caller]
pub fn class_bool(
self,
classes: impl Into<Cow<'static, str>>,
predicate: bool,
) -> Self {
if predicate {
self.class(classes)
} else {
Class::Value(value) => class_expression(&class_list, &name, value),
};
self
}
else {
let mut class = class.into_class(cx);
let include = match class {
Class::Value(include) => include,
Class::Fn(f) => {
self.dynamic = true;
f()
}
};
if include {
if let Some((_, ref mut value)) = self.attrs.iter_mut().find(|(name, _)| name == "class") {
*value = format!("{value} {name}").into();
self
} else {
self.attrs.push(("class".into(), name));
self
}
} else {
self
}
}
}
}
#[doc(hidden)]
/// Sets a property on an element.
#[track_caller]
pub fn prop(
self,
mut self,
cx: Scope,
name: impl Into<Cow<'static, str>>,
value: impl IntoProperty,
) -> Self {
#[cfg(all(target_arch = "wasm32", feature = "web"))]
{
let name = name.into();
let value = value.into();
let name: &str = &name;
js_sys::Reflect::set(&self, &name.into(), &value)
.expect("set property to not err");
cfg_if! {
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
let name = name.into();
let value = value.into_property(cx);
let el = self.element.get_element();
match value {
Property::Fn(f) => {
let el = el.clone();
create_render_effect(cx, move |old| {
let new = f();
let prop_name = wasm_bindgen::intern(&name);
if old.as_ref() != Some(&new) && !(old.is_none() && new == wasm_bindgen::JsValue::UNDEFINED) {
property_expression(&el, &prop_name, new.clone())
}
new
});
}
Property::Value(value) => {
let prop_name = wasm_bindgen::intern(&name);
property_expression(&el, &prop_name, value)
},
};
self
}
else {
self.dynamic = true;
self
}
}
self
}
///
/// Binds the element reference to [`NodeRef`].
pub fn node_ref(self, node_ref: &NodeRef) -> Self {
#[cfg(all(target_arch = "wasm32", feature = "web"))]
node_ref.load(&self);
self
}
/// Adds an event listener to this element.
@ -417,29 +414,13 @@ impl<El: IntoElement> HtmlElement<El> {
mount_child(MountKind::Append(self.element.get_element()), &child.into_view(cx))
}
else {
self.children.push(Box::new(move |cx| child.into_node(cx)));
self.children.push(Box::new(move |cx| child.into_view(cx)));
}
}
self
}
/// Creates a child which will automatically re-render when
/// it's signal dependencies change.
pub fn dyn_child<CF, N>(mut self, child_fn: CF) -> Self
where
CF: Fn() -> N + 'static,
N: IntoView,
{
cfg_if! {
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
mount_child(MountKind::Append(self.element.get_element()), &DynChild::new(child_fn).into_view(self.cx))
} else {
self
.children
.push(Box::new(move |cx| DynChild::new(child_fn).into_node(cx)));
}
}
}
impl<El: IntoElement> IntoView for HtmlElement<El> {
#[cfg_attr(debug_assertions, instrument(level = "trace", name = "<HtmlElement />", skip_all, fields(tag = %self.element.name())))]
@ -572,154 +553,6 @@ macro_rules! generate_html_tags {
}
}
// view! macro helpers
use crate::macro_helpers::*;
use leptos_reactive::create_render_effect;
impl<El: IntoElement> HtmlElement<El> {
#[doc(hidden)]
#[track_caller]
pub fn _attr(
mut self,
cx: Scope,
name: impl Into<Cow<'static, str>>,
attr: impl IntoAttribute,
) -> Self {
let name = name.into();
cfg_if! {
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
let el = self.element.get_element();
let value = attr.into_attribute(cx);
match value {
Attribute::Fn(f) => {
let el = el.clone();
create_render_effect(cx, move |old| {
let new = f();
if old.as_ref() != Some(&new) {
attribute_expression(&el, &name, new.clone());
}
new
});
}
_ => attribute_expression(el, &name, value),
};
self
}
else {
let mut attr = attr.into_attribute(cx);
while let Attribute::Fn(f) = attr {
attr = f();
}
match attr {
Attribute::String(value) => self.attr(name, value),
Attribute::Bool(include) => if include {
self.attr_bool(name)
} else {
self
},
Attribute::Option(maybe) => if let Some(value) = maybe {
self.attr(name, value)
} else {
self
}
_ => unreachable!()
}
}
}
}
#[doc(hidden)]
#[track_caller]
pub fn _class(
mut self,
cx: Scope,
name: impl Into<Cow<'static, str>>,
class: impl IntoClass,
) -> Self {
let name = name.into();
cfg_if! {
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
let el = self.element.get_element();
let class_list = el.class_list();
let value = class.into_class(cx);
match value {
Class::Fn(f) => {
create_render_effect(cx, move |old| {
let new = f();
if old.as_ref() != Some(&new) && (old.is_some() || new) {
class_expression(&class_list, &name, new)
}
new
});
}
Class::Value(value) => class_expression(&class_list, &name, value),
};
self
}
else {
let mut class = class.into_class(cx);
match class {
Class::Value(include) => self.class_bool(name, include),
Class::Fn(f) => self.class_bool(name, f())
}
}
}
}
#[doc(hidden)]
#[track_caller]
pub fn _prop(
mut self,
cx: Scope,
name: impl Into<Cow<'static, str>>,
value: impl IntoProperty,
) -> Self {
cfg_if! {
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
let name = name.into();
let value = value.into_property(cx);
let el = self.element.get_element();
match value {
Property::Fn(f) => {
let el = el.clone();
create_render_effect(cx, move |old| {
let new = f();
let prop_name = wasm_bindgen::intern(&name);
if old.as_ref() != Some(&new) && !(old.is_none() && new == wasm_bindgen::JsValue::UNDEFINED) {
property_expression(&el, &prop_name, new.clone())
}
new
});
}
Property::Value(value) => {
let prop_name = wasm_bindgen::intern(&name);
property_expression(&el, &prop_name, value)
},
};
self
}
else {
self
}
}
}
#[doc(hidden)]
#[track_caller]
pub fn _child(mut self, cx: Scope, child: impl IntoChild) -> Self {
let child = child.into_child(cx);
cfg_if! {
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
mount_child(MountKind::Append(self.element.get_element()), &child.into_view(cx))
}
else {
self.children.push(Box::new(move |cx| child.into_node(cx)));
}
}
self
}
}
generate_html_tags![
// ==========================
// Main root

View File

@ -1,7 +1,7 @@
use std::rc::Rc;
use leptos_reactive::Scope;
use wasm_bindgen::UnwrapThrowExt;
use wasm_bindgen::{intern, UnwrapThrowExt};
/// Represents the different possible values an attribute node could have.
///
@ -153,12 +153,14 @@ pub fn attribute_expression(
) {
match value {
Attribute::String(value) => {
let value = wasm_bindgen::intern(&value);
if attr_name == "inner_html" {
el.set_inner_html(&value);
} else {
let attr_name = wasm_bindgen::intern(attr_name);
el.set_attribute(attr_name, &value).unwrap_throw();
if attr_name == "class" && !value.is_empty() {
let value = wasm_bindgen::intern(&value);
if attr_name == "inner_html" {
el.set_inner_html(&value);
} else {
let attr_name = wasm_bindgen::intern(attr_name);
el.set_attribute(attr_name, &value).unwrap_throw();
}
}
}
Attribute::Option(value) => {

View File

@ -1,6 +1,6 @@
use crate::{
text, Component, ComponentRepr, DynChild, EachKey, Element, Fragment,
HtmlElement, IntoElement, IntoView, Text, Unit, View,
Component, ComponentRepr, DynChild, EachKey, Element, Fragment, HtmlElement,
IntoElement, IntoView, Text, Unit, View,
};
use cfg_if::cfg_if;
use leptos_reactive::{create_effect, Scope};
@ -26,7 +26,7 @@ impl IntoView for Child {
match self {
Child::Node(node) => node,
Child::Unit => Unit.into_view(cx),
Child::Text(data) => text(data),
Child::Text(data) => crate::html::text(data),
Child::Fn(f) => DynChild::new(move || {
let mut value = (f.borrow_mut())();
while let Child::Fn(f) = value {

View File

@ -1,11 +1,11 @@
use cfg_if::cfg_if;
use itertools::Itertools;
use std::{borrow::Cow, fmt::Display, iter::once};
use std::{borrow::Cow, fmt::Display};
use crate::{CoreComponent, Node};
use crate::{CoreComponent, View};
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
impl Node {
impl View {
/// Consumes the node and renders it into an HTML string.
pub fn render_to_string(self) -> Cow<'static, str> {
self.render_to_string_with_id(Default::default())
@ -13,8 +13,8 @@ impl Node {
fn render_to_string_with_id(self, id: TopoId) -> Cow<'static, str> {
match self {
Node::Text(node) => node.content,
Node::Component(node) => {
View::Text(node) => node.content,
View::Component(node) => {
let depth = id.first_child().depth;
let content = node
.children
@ -32,7 +32,7 @@ impl Node {
}
}
}
Node::CoreComponent(node) => {
View::CoreComponent(node) => {
let content = match node {
CoreComponent::Unit(_) => " ".into(),
CoreComponent::DynChild(node) => {
@ -69,7 +69,7 @@ impl Node {
}
}
}
Node::Element(el) => {
View::Element(el) => {
let tag_name = el.name;
let mut has_id = false;
let mut attrs = el
@ -182,7 +182,7 @@ mod tests {
use leptos::*;
#[component]
fn Counter(cx: Scope, initial_value: i32) -> Node {
fn Counter(cx: Scope, initial_value: i32) -> View {
let (value, set_value) = create_signal(cx, initial_value);
view! {
cx,

View File

@ -3,160 +3,164 @@
use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::{quote, ToTokens, TokenStreamExt};
use syn::{
parse::{Parse, ParseStream},
punctuated::Punctuated,
*,
parse::{Parse, ParseStream},
punctuated::Punctuated,
*,
};
pub struct InlinePropsBody {
pub attrs: Vec<Attribute>,
pub vis: syn::Visibility,
pub fn_token: Token![fn],
pub ident: Ident,
pub cx_token: Box<Pat>,
pub generics: Generics,
pub paren_token: token::Paren,
pub inputs: Punctuated<FnArg, Token![,]>,
// pub fields: FieldsNamed,
pub output: ReturnType,
pub where_clause: Option<WhereClause>,
pub block: Box<Block>,
pub attrs: Vec<Attribute>,
pub vis: syn::Visibility,
pub fn_token: Token![fn],
pub ident: Ident,
pub cx_token: Box<Pat>,
pub generics: Generics,
pub paren_token: token::Paren,
pub inputs: Punctuated<FnArg, Token![,]>,
// pub fields: FieldsNamed,
pub output: ReturnType,
pub where_clause: Option<WhereClause>,
pub block: Box<Block>,
}
/// The custom rusty variant of parsing rsx!
impl Parse for InlinePropsBody {
fn parse(input: ParseStream) -> Result<Self> {
let attrs: Vec<Attribute> = input.call(Attribute::parse_outer)?;
let vis: Visibility = input.parse()?;
fn parse(input: ParseStream) -> Result<Self> {
let attrs: Vec<Attribute> = input.call(Attribute::parse_outer)?;
let vis: Visibility = input.parse()?;
let fn_token = input.parse()?;
let ident = input.parse()?;
let generics: Generics = input.parse()?;
let fn_token = input.parse()?;
let ident = input.parse()?;
let generics: Generics = input.parse()?;
let content;
let paren_token = syn::parenthesized!(content in input);
let content;
let paren_token = syn::parenthesized!(content in input);
let first_arg: FnArg = content.parse()?;
let cx_token = {
match first_arg {
FnArg::Receiver(_) => panic!("first argument must not be a receiver argument"),
FnArg::Typed(f) => f.pat,
}
};
let first_arg: FnArg = content.parse()?;
let cx_token = {
match first_arg {
FnArg::Receiver(_) => {
panic!("first argument must not be a receiver argument")
}
FnArg::Typed(f) => f.pat,
}
};
let _: Result<Token![,]> = content.parse();
let _: Result<Token![,]> = content.parse();
let inputs = syn::punctuated::Punctuated::parse_terminated(&content)?;
let inputs = syn::punctuated::Punctuated::parse_terminated(&content)?;
let output = input.parse()?;
let output = input.parse()?;
let where_clause = input
.peek(syn::token::Where)
.then(|| input.parse())
.transpose()?;
let where_clause = input
.peek(syn::token::Where)
.then(|| input.parse())
.transpose()?;
let block = input.parse()?;
let block = input.parse()?;
Ok(Self {
vis,
fn_token,
ident,
generics,
paren_token,
inputs,
output,
where_clause,
block,
cx_token,
attrs,
})
}
Ok(Self {
vis,
fn_token,
ident,
generics,
paren_token,
inputs,
output,
where_clause,
block,
cx_token,
attrs,
})
}
}
/// Serialize the same way, regardless of flavor
impl ToTokens for InlinePropsBody {
fn to_tokens(&self, out_tokens: &mut TokenStream2) {
let Self {
vis,
ident,
generics,
inputs,
output,
where_clause,
block,
cx_token,
attrs,
..
} = self;
fn to_tokens(&self, out_tokens: &mut TokenStream2) {
let Self {
vis,
ident,
generics,
inputs,
output,
where_clause,
block,
cx_token,
attrs,
..
} = self;
let fields = inputs.iter().map(|f| {
let typed_arg = match f {
FnArg::Receiver(_) => todo!(),
FnArg::Typed(t) => t,
};
if let Type::Path(pat) = &*typed_arg.ty {
if pat.path.segments[0].ident == "Option" {
quote! {
#[doc = "My comment."]
#[builder(default, setter(strip_option, into))]
#vis #f
}
} else {
quote! { #vis #f }
}
} else {
quote! { #vis #f }
let fields = inputs.iter().map(|f| {
let typed_arg = match f {
FnArg::Receiver(_) => todo!(),
FnArg::Typed(t) => t,
};
if let Type::Path(pat) = &*typed_arg.ty {
if pat.path.segments[0].ident == "Option" {
quote! {
#[doc = "My comment."]
#[builder(default, setter(strip_option, into))]
#vis #f
}
} else {
quote! { #vis #f }
}
} else {
quote! { #vis #f }
}
});
let component_name_str = ident.to_string();
let struct_name = Ident::new(&format!("{}Props", ident), Span::call_site());
let field_names = inputs.iter().filter_map(|f| match f {
FnArg::Receiver(_) => todo!(),
FnArg::Typed(t) => Some(&t.pat),
});
let first_lifetime =
if let Some(GenericParam::Lifetime(lt)) = generics.params.first() {
Some(lt)
} else {
None
};
let modifiers = quote! { #[derive(leptos::TypedBuilder)] };
let (_scope_lifetime, fn_generics, struct_generics) =
if let Some(lt) = first_lifetime {
let struct_generics: Punctuated<_, token::Comma> = generics
.params
.iter()
.map(|it| match it {
GenericParam::Type(tp) => {
let mut tp = tp.clone();
tp.bounds.push(parse_quote!( 'a ));
GenericParam::Type(tp)
}
});
_ => it.clone(),
})
.collect();
let component_name_str = ident.to_string();
let struct_name = Ident::new(&format!("{}Props", ident), Span::call_site());
(
quote! { #lt, },
generics.clone(),
quote! { <#struct_generics> },
)
} else {
let lifetime: LifetimeDef = parse_quote! { 'a };
let field_names = inputs.iter().filter_map(|f| match f {
FnArg::Receiver(_) => todo!(),
FnArg::Typed(t) => Some(&t.pat),
});
let mut fn_generics = generics.clone();
fn_generics
.params
.insert(0, GenericParam::Lifetime(lifetime.clone()));
let first_lifetime = if let Some(GenericParam::Lifetime(lt)) = generics.params.first() {
Some(lt)
} else {
None
};
(quote! { #lifetime, }, fn_generics, quote! { #generics })
};
let modifiers = quote! { #[derive(leptos::TypedBuilder)] };
let (_scope_lifetime, fn_generics, struct_generics) = if let Some(lt) = first_lifetime {
let struct_generics: Punctuated<_, token::Comma> = generics
.params
.iter()
.map(|it| match it {
GenericParam::Type(tp) => {
let mut tp = tp.clone();
tp.bounds.push(parse_quote!( 'a ));
GenericParam::Type(tp)
}
_ => it.clone(),
})
.collect();
(
quote! { #lt, },
generics.clone(),
quote! { <#struct_generics> },
)
} else {
let lifetime: LifetimeDef = parse_quote! { 'a };
let mut fn_generics = generics.clone();
fn_generics
.params
.insert(0, GenericParam::Lifetime(lifetime.clone()));
(quote! { #lifetime, }, fn_generics, quote! { #generics })
};
out_tokens.append_all(quote! {
out_tokens.append_all(quote! {
#modifiers
#[allow(non_camel_case_types)]
#vis struct #struct_name #struct_generics
@ -175,8 +179,8 @@ impl ToTokens for InlinePropsBody {
#component_name_str,
move |#cx_token| #block
)
.into_node(#cx_token)
.into_view(#cx_token)
}
});
}
}
}

View File

@ -1,116 +1,138 @@
use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote, quote_spanned};
use std::collections::HashMap;
use syn::{spanned::Spanned, ExprPath};
use syn_rsx::{Node, NodeAttribute, NodeElement, NodeName};
use crate::{is_component_node, Mode};
macro_rules! generate_event_types {
[$m:ident, $([$web_sys_event:ident, [$($event:ident),* $(,)?]]),* $(,)?] => {
$(
$(
$m.insert(stringify!($event).to_ascii_lowercase(), stringify!($event));
)*
)*
};
}
lazy_static::lazy_static! {
static ref EVENTS: HashMap<String, &'static str> = {
let mut m = HashMap::new();
generate_event_types![m,
// ClipboardEvent is unstable
[Event, [Copy, Cut, Paste]],
[
CompositionEvent,
[CompositionEnd, CompositionStart, CompositionUpdate]
],
[KeyboardEvent, [KeyDown, Keypress, Keyup]],
[FocusEvent, [Focus, FocusOut, FocusIn, Blur]],
[Event, [Change, Input, Invalid, Reset]],
[
MouseEvent,
[
Click,
ContextMenu,
DoubleClick,
DblClick,
Drag,
DragEnd,
DragEnter,
DragExit,
DragLeave,
DragOver,
DragStart,
Drop,
MouseDown,
MouseEnter,
MouseLeave,
MouseMove,
MouseOut,
MouseOver,
MouseUp,
]
],
[Event, [Scroll]],
[Event, [SubmitEvent]],
[
PointerEvent,
[
PointerDown,
PointerMove,
PointerUp,
PointerCancel,
GotPointerCapture,
LostPointerCapture,
PointerEnter,
PointerLeave,
PointerOver,
PointerOut,
]
],
[Event, [Select]],
[TouchEvent, [TouchCancel, TouchEnd, TouchMove, TouchStart]],
[WheelEvent, [Wheel]],
[
Event,
[
Abort,
CanPlay,
CanPlayThrough,
DurationChange,
Emptied,
Encrypted,
Ended,
Error,
LoadedData,
LoadedMetadata,
LoadStart,
Pause,
Play,
Playing,
Progress,
RateChange,
Seeked,
Seeking,
Stalled,
Suspend,
TimeUpdate,
VolumeChange,
Waiting,
]
],
[
AnimationEvent,
[AnimationStart, AnimationEnd, AnimationIteration,]
],
[TransitionEvent, [TransitionEnd]],
[Event, [Toggle]]
];
m
};
}
const TYPED_EVENTS: [&str; 126] = [
"afterprint",
"beforeprint",
"beforeunload",
"gamepadconnected",
"gamepaddisconnected",
"hashchange",
"languagechange",
"message",
"messageerror",
"offline",
"online",
"pagehide",
"pageshow",
"popstate",
"rejectionhandled",
"storage",
"unhandledrejection",
"unload",
"abort",
"animationcancel",
"animationend",
"animationiteration",
"animationstart",
"auxclick",
"beforeinput",
"blur",
"canplay",
"canplaythrough",
"change",
"click",
"close",
"compositionend",
"compositionstart",
"compositionupdate",
"contextmenu",
"cuechange",
"dblclick",
"drag",
"dragend",
"dragenter",
"dragleave",
"dragover",
"dragstart",
"drop",
"durationchange",
"emptied",
"ended",
"error",
"focus",
"focusin",
"focusout",
"formdata",
"gotpointercapture",
"input",
"invalid",
"keydown",
"keypress",
"keyup",
"load",
"loadeddata",
"loadedmetadata",
"loadstart",
"lostpointercapture",
"mousedown",
"mouseenter",
"mouseleave",
"mousemove",
"mouseout",
"mouseover",
"mouseup",
"pause",
"play",
"playing",
"pointercancel",
"pointerdown",
"pointerenter",
"pointerleave",
"pointermove",
"pointerout",
"pointerover",
"pointerup",
"progress",
"ratechange",
"reset",
"resize",
"scroll",
"securitypolicyviolation",
"seeked",
"seeking",
"select",
"selectionchange",
"selectstart",
"slotchange",
"stalled",
"submit",
"suspend",
"timeupdate",
"toggle",
"touchcancel",
"touchend",
"touchmove",
"touchstart",
"transitioncancel",
"transitionend",
"transitionrun",
"transitionstart",
"volumechange",
"waiting",
"webkitanimationend",
"webkitanimationiteration",
"webkitanimationstart",
"webkittransitionend",
"wheel",
"DOMContentLoaded",
"devicemotion",
"deviceorientation",
"orientationchange",
"copy",
"cut",
"paste",
"fullscreenchange",
"fullscreenerror",
"pointerlockchange",
"pointerlockerror",
"readystatechange",
"visibilitychange",
];
pub(crate) fn render_view(
cx: &Ident,
@ -120,7 +142,7 @@ pub(crate) fn render_view(
if nodes.is_empty() {
let span = Span::call_site();
quote_spanned! {
span => leptos::Unit.into_node(#cx)
span => leptos::Unit.into_view(#cx)
}
} else if nodes.len() == 1 {
node_to_tokens(cx, &nodes[0], mode)
@ -139,14 +161,14 @@ fn fragment_to_tokens(
let node = node_to_tokens(cx, node, mode);
let span = node.span();
quote_spanned! {
span => #node.into_node(#cx),
span => #node.into_view(#cx),
}
});
quote_spanned! {
span => {
vec![
#(#nodes)*
].into_node(#cx)
].into_view(#cx)
}
}
}
@ -168,7 +190,7 @@ fn node_to_tokens(cx: &Ident, node: &Node, mode: Mode) -> TokenStream {
let span = node.value.span();
let value = node.value.as_ref();
quote_spanned! {
span => #value.into_node(#cx)
span => #value.into_view(#cx)
}
}
Node::Attribute(node) => attribute_to_tokens(cx, node, mode),
@ -222,14 +244,14 @@ fn element_to_tokens(
Node::Comment(_) | Node::Doctype(_) | Node::Attribute(_) => quote! {},
};
quote! {
._child(cx, #child)
.child(cx, #child)
}
});
quote_spanned! {
span => #name
#(#attrs)*
#(#children)*
.into_node(#cx)
.into_view(#cx)
}
}
}
@ -250,7 +272,7 @@ fn attribute_to_tokens(
.expect("'_ref' needs to be passed a variable name");
quote_spanned! {
span => #[allow(unused_braces)]
._ref(#value)
.ref(#value)
}
/* } else {
todo!()
@ -263,10 +285,11 @@ fn attribute_to_tokens(
.as_ref()
.expect("event listener attributes need a value")
.as_ref();
let event_type = EVENTS
.get(&name.to_string())
let event_type = TYPED_EVENTS
.iter()
.find(|e| **e == name)
.copied()
.unwrap_or_else(|| panic!("couldn't parse event name {name}"));
.unwrap_or("Custom");
let event_type = event_type
.parse::<TokenStream>()
.expect("couldn't parse event name");
@ -285,7 +308,7 @@ fn attribute_to_tokens(
.as_ref();
//if mode != Mode::Ssr {
quote_spanned! {
span => ._prop(#cx, #name, #[allow(unused_braces)] #value)
span => .prop(#cx, #name, #[allow(unused_braces)] #value)
}
/* } else {
todo!()
@ -298,7 +321,7 @@ fn attribute_to_tokens(
.as_ref();
//if mode != Mode::Ssr {
quote_spanned! {
span => ._class(#cx, #name, #[allow(unused_braces)] #value)
span => .class(#cx, #name, #[allow(unused_braces)] #value)
}
/* } else {
todo!()
@ -315,7 +338,7 @@ fn attribute_to_tokens(
};
//if mode != Mode::Ssr {
quote_spanned! {
span => ._attr(#cx, #name, #[allow(unused_braces)] #value)
span => .attr(#cx, #name, #[allow(unused_braces)] #value)
}
/* } else {
quote! { }