diff --git a/examples/drops.rs b/examples/drops.rs index 956545e35..6328a3f64 100644 --- a/examples/drops.rs +++ b/examples/drops.rs @@ -14,9 +14,9 @@ fn app(cx: Scope) -> Element { } render! { - {(0..count).map(|_| rsx!{ + for _ in 0..count { drop_child {} - })} + } } } diff --git a/examples/dynamic_asset.rs b/examples/dynamic_asset.rs index 51dcfac3a..ac2ad82c1 100644 --- a/examples/dynamic_asset.rs +++ b/examples/dynamic_asset.rs @@ -17,11 +17,9 @@ fn app(cx: Scope) -> Element { response.respond(Response::new(include_bytes!("./assets/logo.png").to_vec())); }); - cx.render(rsx! { + render! { div { - img { - src: "/logos/logo.png" - } + img { src: "/logos/logo.png" } } - }) + } } diff --git a/examples/error_handle.rs b/examples/error_handle.rs index 21b16ec45..5461032fd 100644 --- a/examples/error_handle.rs +++ b/examples/error_handle.rs @@ -22,9 +22,7 @@ fn DemoC(cx: Scope, x: i32) -> Element { result.throw()?; - cx.render(rsx! { - h1 { - "{x}" - } - }) + render! { + h1 { "{x}" } + } } diff --git a/examples/file_explorer.rs b/examples/file_explorer.rs index a99ac3232..ea89fab77 100644 --- a/examples/file_explorer.rs +++ b/examples/file_explorer.rs @@ -35,18 +35,17 @@ fn app(cx: Scope) -> Element { main { {files.read().path_names.iter().enumerate().map(|(dir_id, path)| { let path_end = path.split('/').last().unwrap_or(path.as_str()); - let icon_type = if path_end.contains('.') { - "description" - } else { - "folder" - }; rsx! ( div { class: "folder", key: "{path}", i { class: "material-icons", onclick: move |_| files.write().enter_dir(dir_id), - "{icon_type}" + if path_end.contains('.') { + "description" + } else { + "folder" + } p { class: "cooltip", "0 folders / 0 files" } } h1 { "{path_end}" } diff --git a/examples/generic_component.rs b/examples/generic_component.rs index 3d6171a9b..ec8eeb660 100644 --- a/examples/generic_component.rs +++ b/examples/generic_component.rs @@ -7,9 +7,9 @@ fn main() { } fn app(cx: Scope) -> Element { - cx.render(rsx! { generic_child { - data: 0i32 - } }) + render! { + generic_child { data: 0 } + } } #[derive(PartialEq, Props)] @@ -18,9 +18,7 @@ struct GenericChildProps { } fn generic_child(cx: Scope>) -> Element { - let data = &cx.props.data; - - cx.render(rsx! { div { - "{data}" - } }) + render! { + div { "{&cx.props.data}" } + } } diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 9553f5c7e..52d9e9886 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -5,7 +5,7 @@ fn main() { } fn app(cx: Scope) -> Element { - cx.render(rsx! ( + render! { div { "Hello, world!" } - )) + } } diff --git a/examples/pattern_model.rs b/examples/pattern_model.rs index 13b5409e1..6dd3e8825 100644 --- a/examples/pattern_model.rs +++ b/examples/pattern_model.rs @@ -35,11 +35,13 @@ fn main() { dioxus_desktop::launch_cfg(app, cfg); } +const STYLE: &str = include_str!("./assets/calculator.css"); + fn app(cx: Scope) -> Element { let state = use_ref(cx, Calculator::new); cx.render(rsx! { - style { {include_str!("./assets/calculator.css")} } + style { {STYLE} } div { id: "wrapper", div { class: "app", div { class: "calculator", onkeypress: move |evt| state.write().handle_keydown(evt), diff --git a/examples/shared_state.rs b/examples/shared_state.rs index 487aa3fe3..65ec76a71 100644 --- a/examples/shared_state.rs +++ b/examples/shared_state.rs @@ -51,26 +51,23 @@ pub fn App(cx: Scope) -> Element { #[component] fn DataEditor(cx: Scope, id: usize) -> Element { - let cool_data = use_shared_state::(cx).unwrap().read(); + let data = use_shared_state::(cx)?; - let my_data = &cool_data.view(id).unwrap(); - - render!(p { - "{my_data}" - }) + render! { + p { + {data.read().view(id)?} + } + } } #[component] fn DataView(cx: Scope, id: usize) -> Element { - let cool_data = use_shared_state::(cx).unwrap(); + let data = use_shared_state::(cx)?; - let oninput = |e: FormEvent| cool_data.write().set(*id, e.value()); - - let cool_data = cool_data.read(); - let my_data = &cool_data.view(id).unwrap(); - - render!(input { - oninput: oninput, - value: "{my_data}" - }) + render! { + input { + oninput: move |e: FormEvent| data.write().set(*id, e.value()), + value: data.read().view(id)? + } + } } diff --git a/examples/shorthand.rs b/examples/shorthand.rs index 09214147f..2d71b046b 100644 --- a/examples/shorthand.rs +++ b/examples/shorthand.rs @@ -11,22 +11,35 @@ fn app(cx: Scope) -> Element { let class = "class"; let id = "id"; - // todo: i'd like it for children to be inferred + // todo: i'd like it for children on elements to be inferred as the children of the element + // also should shorthands understand references/dereferences? + // ie **a, *a, &a, &mut a, etc let children = render! { "Child" }; + let onclick = move |_| println!("Clicked!"); render! { div { class, id, {&children} } - Component { a, b, c, children } - Component { a, ..ComponentProps { a: 1, b: 2, c: 3, children: None } } + Component { a, b, c, children, onclick } + Component { a, ..ComponentProps { a: 1, b: 2, c: 3, children: None, onclick: Default::default() } } } } #[component] -fn Component<'a>(cx: Scope<'a>, a: i32, b: i32, c: i32, children: Element<'a>) -> Element { +fn Component<'a>( + cx: Scope<'a>, + a: i32, + b: i32, + c: i32, + children: Element<'a>, + onclick: EventHandler<'a, ()>, +) -> Element { render! { div { "{a}" } div { "{b}" } div { "{c}" } div { {children} } + div { + onclick: move |_| onclick.call(()), + } } } diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index 01812bef5..f30fdbcf3 100644 --- a/packages/core/src/nodes.rs +++ b/packages/core/src/nodes.rs @@ -804,6 +804,15 @@ impl<'a, 'b> IntoDynNode<'b> for &'a str { } } +impl IntoDynNode<'_> for &String { + fn into_dyn_node(self, cx: &ScopeState) -> DynamicNode { + DynamicNode::Text(VText { + value: cx.bump().alloc_str(&self), + id: Default::default(), + }) + } +} + impl IntoDynNode<'_> for String { fn into_dyn_node(self, cx: &ScopeState) -> DynamicNode { DynamicNode::Text(VText { @@ -898,6 +907,12 @@ impl<'a> IntoAttributeValue<'a> for String { } } +impl<'a> IntoAttributeValue<'a> for &String { + fn into_value(self, cx: &'a Bump) -> AttributeValue<'a> { + AttributeValue::Text(cx.alloc_str(&self)) + } +} + impl<'a> IntoAttributeValue<'a> for f64 { fn into_value(self, _: &'a Bump) -> AttributeValue<'a> { AttributeValue::Float(self) diff --git a/packages/rsx/src/attribute.rs b/packages/rsx/src/attribute.rs index c5d3383b0..f3df1d1c0 100644 --- a/packages/rsx/src/attribute.rs +++ b/packages/rsx/src/attribute.rs @@ -109,17 +109,25 @@ impl ToTokens for ElementAttrNamed { }; let attribute = { + let value = &self.attr.value; + let is_shorthand_event = match &attr.value { + ElementAttrValue::Shorthand(s) => s.to_string().starts_with("on"), + _ => false, + }; + match &attr.value { ElementAttrValue::AttrLiteral(_) | ElementAttrValue::AttrExpr(_) | ElementAttrValue::Shorthand(_) - | ElementAttrValue::AttrOptionalExpr { .. } => { + | ElementAttrValue::AttrOptionalExpr { .. } + if !is_shorthand_event => + { let name = &self.attr.name; let ns = ns(name); let volitile = volitile(name); let attribute = attribute(name); - let value = &self.attr.value; let value = quote! { #value }; + quote! { __cx.attr( #attribute, @@ -131,12 +139,13 @@ impl ToTokens for ElementAttrNamed { } ElementAttrValue::EventTokens(tokens) => match &self.attr.name { ElementAttrName::BuiltIn(name) => { - quote! { - dioxus_elements::events::#name(__cx, #tokens) - } + quote! { dioxus_elements::events::#name(__cx, #tokens) } } ElementAttrName::Custom(_) => todo!(), }, + _ => { + quote! { dioxus_elements::events::#value(__cx, #value) } + } } }; diff --git a/packages/rsx/src/component.rs b/packages/rsx/src/component.rs index c7f4c1828..3fef27539 100644 --- a/packages/rsx/src/component.rs +++ b/packages/rsx/src/component.rs @@ -241,6 +241,9 @@ impl ContentField { impl ToTokens for ContentField { fn to_tokens(&self, tokens: &mut TokenStream2) { match self { + ContentField::Shorthand(i) if i.to_string().starts_with("on") => { + tokens.append_all(quote! { __cx.event_handler(#i) }) + } ContentField::Shorthand(i) => tokens.append_all(quote! { #i }), ContentField::ManExpr(e) => e.to_tokens(tokens), ContentField::Formatted(s) => tokens.append_all(quote! { __cx.raw_text(#s) }),