From a5b9200e4793df0b2f44861a18a84b668063a4c7 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 10 May 2022 18:13:05 -0500 Subject: [PATCH 01/22] calculate absolute position --- packages/native-core/Cargo.toml | 2 +- packages/tui/Cargo.toml | 2 +- packages/tui/src/lib.rs | 11 +++++++++-- packages/tui/src/render.rs | 13 +++++++++---- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/packages/native-core/Cargo.toml b/packages/native-core/Cargo.toml index 284a9394a..4e7112eb0 100644 --- a/packages/native-core/Cargo.toml +++ b/packages/native-core/Cargo.toml @@ -15,7 +15,7 @@ dioxus-core = { path = "../core", version = "^0.2.1" } dioxus-html = { path = "../html", version = "^0.2.1" } dioxus-core-macro = { path = "../core-macro", version = "^0.2.1" } -stretch2 = "0.4.2" +stretch2 = { git = "https://github.com/mockersf/stretch/", branch = "remove_round_layout_changes" } smallvec = "1.6" fxhash = "0.2" anymap = "0.12.1" diff --git a/packages/tui/Cargo.toml b/packages/tui/Cargo.toml index efa312772..d9ccb8584 100644 --- a/packages/tui/Cargo.toml +++ b/packages/tui/Cargo.toml @@ -23,7 +23,7 @@ crossterm = "0.23.0" anyhow = "1.0.42" tokio = { version = "1.15.0", features = ["full"] } futures = "0.3.19" -stretch2 = "0.4.2" +stretch2 = { git = "https://github.com/mockersf/stretch/", branch = "remove_round_layout_changes" } smallvec = "1.6" fxhash = "0.2" anymap = "0.12.1" diff --git a/packages/tui/src/lib.rs b/packages/tui/src/lib.rs index 012d92fed..3f647ffd1 100644 --- a/packages/tui/src/lib.rs +++ b/packages/tui/src/lib.rs @@ -17,7 +17,7 @@ use layout::StretchLayout; use std::cell::RefCell; use std::rc::Rc; use std::{io, time::Duration}; -use stretch2::{prelude::Size, Stretch}; +use stretch2::{geometry::Point, prelude::Size, Stretch}; use style_attributes::StyleModifier; use tui::{backend::CrosstermBackend, layout::Rect, Terminal}; @@ -166,7 +166,14 @@ fn render_vdom( // size is guaranteed to not change when rendering resize(frame.size(), &mut stretch.borrow_mut(), &rdom); let root = &rdom[0]; - render::render_vnode(frame, &stretch.borrow(), &rdom, root, cfg); + render::render_vnode( + frame, + &stretch.borrow(), + &rdom, + root, + cfg, + Point::zero(), + ); })?; } else { resize( diff --git a/packages/tui/src/render.rs b/packages/tui/src/render.rs index 3e75f3a5e..4df83f8b6 100644 --- a/packages/tui/src/render.rs +++ b/packages/tui/src/render.rs @@ -22,6 +22,7 @@ pub(crate) fn render_vnode( rdom: &Dom, node: &Node, cfg: Config, + parent_location: Point, ) { use dioxus_native_core::real_dom::NodeType; @@ -29,7 +30,11 @@ pub(crate) fn render_vnode( return; } - let Layout { location, size, .. } = layout.layout(node.state.layout.node.unwrap()).unwrap(); + let Layout { + mut location, size, .. + } = layout.layout(node.state.layout.node.unwrap()).unwrap(); + location.x += parent_location.x; + location.y += parent_location.y; let Point { x, y } = location; let Size { width, height } = size; @@ -57,7 +62,7 @@ pub(crate) fn render_vnode( text, style: node.state.style.core, }; - let area = Rect::new(*x as u16, *y as u16, *width as u16, *height as u16); + let area = Rect::new(x as u16, y as u16, *width as u16, *height as u16); // the renderer will panic if a node is rendered out of range even if the size is zero if area.width > 0 && area.height > 0 { @@ -65,7 +70,7 @@ pub(crate) fn render_vnode( } } NodeType::Element { children, .. } => { - let area = Rect::new(*x as u16, *y as u16, *width as u16, *height as u16); + let area = Rect::new(x as u16, y as u16, *width as u16, *height as u16); // the renderer will panic if a node is rendered out of range even if the size is zero if area.width > 0 && area.height > 0 { @@ -73,7 +78,7 @@ pub(crate) fn render_vnode( } for c in children { - render_vnode(frame, layout, rdom, &rdom[c.0], cfg); + render_vnode(frame, layout, rdom, &rdom[c.0], cfg, location); } } NodeType::Placeholder => unreachable!(), From 8d453f52bd0f1e088812c20e4ed553dcb6595a78 Mon Sep 17 00:00:00 2001 From: duanzhou Date: Thu, 19 May 2022 23:58:48 +0800 Subject: [PATCH 02/22] Example: SVG Basic shapes from https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Basic_Shapes --- examples/svg_basic.rs | 75 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 examples/svg_basic.rs diff --git a/examples/svg_basic.rs b/examples/svg_basic.rs new file mode 100644 index 000000000..40eb80b23 --- /dev/null +++ b/examples/svg_basic.rs @@ -0,0 +1,75 @@ +use dioxus::prelude::*; + +fn app(cx: Scope) -> Element { + cx.render(rsx!( svg { + width: "200", + height: "250", + xmlns: "http://www.w3.org/2000/svg", + version: "1.1", + rect { + x: "10", + y: "10", + width: "30", + height: "30", + stroke: "black", + fill: "transparent", + stroke_width: "5", + } + rect { + x: "60", + y: "10", + width: "30", + height: "30", + stroke: "black", + fill: "transparent", + stroke_width: "5", + } + circle { + cx: "25", + cy: "75", + r: "20", + stroke: "red", + fill: "transparent", + stroke_width: "5", + } + ellipse { + cx: "75", + cy: "75", + rx: "20", + ry: "5", + stroke: "red", + fill: "transparent", + stroke_width: "5", + } + line { + x1: "10", + x2: "50", + y1: "110", + y2: "150", + stroke: "orange", + stroke_width: "5", + } + polyline { + points: "60 110 65 120 70 115 75 130 80 125 85 140 90 135 95 150 100 145", + stroke: "orange", + fill: "transparent", + stroke_width: "5", + } + polygon { + points: "50 160 55 180 70 180 60 190 65 205 50 195 35 205 40 190 30 180 45 180", + stroke: "green", + fill: "transparent", + stroke_width: "5", + } + path { + d: "M20,230 Q40,205 50,230 T90,230", + fill: "none", + stroke: "blue", + stroke_width: "5", + } + })) +} + +fn main() { + dioxus::desktop::launch(app); +} From a55b56b4031e835c03553e27a3be5d98cadb7d9e Mon Sep 17 00:00:00 2001 From: Muhannad Alrusayni Date: Fri, 29 Apr 2022 02:00:12 +0300 Subject: [PATCH 03/22] feat: Support generic components in `rsx!()` macro --- packages/core-macro/src/rsx/component.rs | 55 ++++++++++++++++- packages/core-macro/src/rsx/errors.rs | 26 ++++++++ packages/core-macro/src/rsx/node.rs | 79 ++++++++++++++---------- 3 files changed, 126 insertions(+), 34 deletions(-) diff --git a/packages/core-macro/src/rsx/component.rs b/packages/core-macro/src/rsx/component.rs index 5b0a38b87..d0ade9058 100644 --- a/packages/core-macro/src/rsx/component.rs +++ b/packages/core-macro/src/rsx/component.rs @@ -18,19 +18,63 @@ use quote::{quote, ToTokens, TokenStreamExt}; use syn::{ ext::IdentExt, parse::{Parse, ParseBuffer, ParseStream}, - token, Expr, Ident, LitStr, Result, Token, + token, AngleBracketedGenericArguments, Expr, Ident, LitStr, PathArguments, Result, Token, }; pub struct Component { pub name: syn::Path, + pub prop_gen_args: Option, pub body: Vec, pub children: Vec, pub manual_props: Option, } +impl Component { + pub fn validate_component_path(path: &syn::Path) -> Result<()> { + // ensure path segments doesn't have PathArguments, only the last + // segment is allowed to have one. + if path + .segments + .iter() + .take(path.segments.len() - 1) + .any(|seg| seg.arguments != PathArguments::None) + { + component_path_cannot_have_arguments!(path); + } + + // ensure last segment only have value of None or AngleBracketed + if !matches!( + path.segments.last().unwrap().arguments, + PathArguments::None | PathArguments::AngleBracketed(_) + ) { + invalid_component_path!(path); + } + + // if matches!( + // path.segments.last().unwrap().arguments, + // PathArguments::AngleBracketed(_) + // ) { + // proc_macro_error::abort!(path, "path: {}", path.to_token_stream().to_string()); + // } + + Ok(()) + } +} + impl Parse for Component { fn parse(stream: ParseStream) -> Result { - let name = syn::Path::parse_mod_style(stream)?; + let mut name = stream.parse::()?; + Component::validate_component_path(&name)?; + + // extract the path arguments from the path into prop_gen_args + let prop_gen_args = name.segments.last_mut().and_then(|seg| { + if let PathArguments::AngleBracketed(args) = seg.arguments.clone() { + seg.arguments = PathArguments::None; + Some(args) + } else { + None + } + }); let content: ParseBuffer; @@ -64,6 +108,7 @@ impl Parse for Component { Ok(Self { name, + prop_gen_args, body, children, manual_props, @@ -74,6 +119,7 @@ impl Parse for Component { impl ToTokens for Component { fn to_tokens(&self, tokens: &mut TokenStream2) { let name = &self.name; + let prop_gen_args = &self.prop_gen_args; let mut has_key = None; @@ -101,7 +147,10 @@ impl ToTokens for Component { }} } None => { - let mut toks = quote! { fc_to_builder(#name) }; + let mut toks = match prop_gen_args { + Some(gen_args) => quote! { fc_to_builder::#gen_args(#name) }, + None => quote! { fc_to_builder(#name) }, + }; for field in &self.body { match field.name.to_string().as_str() { "key" => { diff --git a/packages/core-macro/src/rsx/errors.rs b/packages/core-macro/src/rsx/errors.rs index 27e2c7f98..07134e4f0 100644 --- a/packages/core-macro/src/rsx/errors.rs +++ b/packages/core-macro/src/rsx/errors.rs @@ -13,3 +13,29 @@ macro_rules! attr_after_element { ) }; } + +macro_rules! component_path_cannot_have_arguments { + ($span:expr) => { + proc_macro_error::abort!( + $span, + "expected a path without arguments"; + help = "try remove the path arguments" + ) + }; +} + +macro_rules! component_ident_cannot_use_paren { + ($span:expr, $com_name:ident) => { + proc_macro_error::abort!( + $span, + "Invalid component syntax"; + help = "try replace {} (..) to {} {{..}}", $com_name, $com_name; + ) + }; +} + +macro_rules! invalid_component_path { + ($span:expr) => { + proc_macro_error::abort!($span, "Invalid component path syntax") + }; +} diff --git a/packages/core-macro/src/rsx/node.rs b/packages/core-macro/src/rsx/node.rs index d5d701767..fa651cebf 100644 --- a/packages/core-macro/src/rsx/node.rs +++ b/packages/core-macro/src/rsx/node.rs @@ -4,7 +4,7 @@ use proc_macro2::TokenStream as TokenStream2; use quote::{quote, ToTokens, TokenStreamExt}; use syn::{ parse::{Parse, ParseStream}, - token, Expr, LitStr, Result, Token, + token, Expr, LitStr, PathArguments, Result, Token, }; /* @@ -28,39 +28,56 @@ impl Parse for BodyNode { return Ok(BodyNode::Text(stream.parse()?)); } - // div {} -> el - // Div {} -> comp - if stream.peek(syn::Ident) && stream.peek2(token::Brace) { - if stream - .fork() - .parse::()? - .to_string() - .chars() - .next() - .unwrap() - .is_ascii_uppercase() - { - return Ok(BodyNode::Component(stream.parse()?)); - } else { - return Ok(BodyNode::Element(stream.parse::()?)); + let body_stream = stream.fork(); + if let Ok(path) = body_stream.parse::() { + // this is an Element if path match of: + // - one ident + // - followed by `{` + // - have no `PathArguments` + // - starts with lowercase + // + // example: + // div {} + if let Some(ident) = path.get_ident() { + if body_stream.peek(token::Brace) + && ident + .to_string() + .chars() + .next() + .unwrap() + .is_ascii_lowercase() + { + return Ok(BodyNode::Element(stream.parse::()?)); + } } - } - // component() -> comp - // ::component {} -> comp - // ::component () -> comp - if (stream.peek(syn::Ident) && stream.peek2(token::Paren)) - || (stream.peek(Token![::])) - || (stream.peek(Token![:]) && stream.peek2(Token![:])) - { - return Ok(BodyNode::Component(stream.parse::()?)); - } + // Otherwise this should be Component, allowed syntax: + // - syn::Path + // - PathArguments can only apper in last segment + // - followed by `{` or `(`, note `(` cannot be used with one ident + // + // example + // Div {} + // ::Div {} + // crate::Div {} + // component() + // ::component {} + // ::component () + // crate::component{} + // crate::component() + // Input<'_, String> {} + // crate::Input<'_, i32> {} + if body_stream.peek(token::Brace) || body_stream.peek(token::Paren) { + // this syntax is not allowd: + // Div () -> comp + if path.segments.len() == 1 && body_stream.peek(token::Paren) { + let com_ident = &path.segments.iter().next().unwrap().ident; + component_ident_cannot_use_paren!(path, com_ident); + } - // crate::component{} -> comp - // crate::component() -> comp - if let Ok(pat) = stream.fork().parse::() { - if pat.segments.len() > 1 { - return Ok(BodyNode::Component(stream.parse::()?)); + Component::validate_component_path(&path)?; + + return Ok(BodyNode::Component(stream.parse()?)); } } From 0b5b7f09dba636e59aa12bb542de4ab123e87e9b Mon Sep 17 00:00:00 2001 From: Muhannad Alrusayni Date: Fri, 6 May 2022 11:11:34 +0300 Subject: [PATCH 04/22] feat: Support generic component with `inline_props` with some limitation --- packages/core-macro/src/inlineprops.rs | 18 +++++++++++++++--- packages/core-macro/src/props/mod.rs | 4 +++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/core-macro/src/inlineprops.rs b/packages/core-macro/src/inlineprops.rs index 782d13a48..05d9d5240 100644 --- a/packages/core-macro/src/inlineprops.rs +++ b/packages/core-macro/src/inlineprops.rs @@ -17,6 +17,7 @@ pub struct InlinePropsBody { pub inputs: Punctuated, // pub fields: FieldsNamed, pub output: ReturnType, + pub where_clause: Option, pub block: Box, } @@ -28,7 +29,7 @@ impl Parse for InlinePropsBody { let fn_token = input.parse()?; let ident = input.parse()?; - let generics = input.parse()?; + let generics: Generics = input.parse()?; let content; let paren_token = syn::parenthesized!(content in input); @@ -47,6 +48,11 @@ impl Parse for InlinePropsBody { let output = input.parse()?; + let where_clause = input + .peek(syn::token::Where) + .then(|| input.parse()) + .transpose()?; + let block = input.parse()?; Ok(Self { @@ -57,6 +63,7 @@ impl Parse for InlinePropsBody { paren_token, inputs, output, + where_clause, block, cx_token, attrs, @@ -73,6 +80,7 @@ impl ToTokens for InlinePropsBody { generics, inputs, output, + where_clause, block, cx_token, attrs, @@ -136,12 +144,16 @@ impl ToTokens for InlinePropsBody { out_tokens.append_all(quote! { #modifiers #[allow(non_camel_case_types)] - #vis struct #struct_name #struct_generics { + #vis struct #struct_name #struct_generics + #where_clause + { #(#fields),* } #(#attrs)* - #vis fn #ident #fn_generics (#cx_token: Scope<#scope_lifetime #struct_name #generics>) #output { + #vis fn #ident #fn_generics (#cx_token: Scope<#scope_lifetime #struct_name #generics>) #output + #where_clause + { let #struct_name { #(#field_names),* } = &cx.props; #block } diff --git a/packages/core-macro/src/props/mod.rs b/packages/core-macro/src/props/mod.rs index 6c65c5944..92772df00 100644 --- a/packages/core-macro/src/props/mod.rs +++ b/packages/core-macro/src/props/mod.rs @@ -653,7 +653,9 @@ Finally, call `.build()` to create the instance of `{name}`. } } - impl #impl_generics dioxus::prelude::Properties for #name #ty_generics{ + impl #impl_generics dioxus::prelude::Properties for #name #ty_generics + #b_generics_where_extras_predicates + { type Builder = #builder_name #generics_with_empty; const IS_STATIC: bool = #is_static; fn builder() -> Self::Builder { From 5b079075d7081006d1119ab734e18ce0eeb193f2 Mon Sep 17 00:00:00 2001 From: Muhannad Alrusayni Date: Fri, 6 May 2022 11:30:48 +0300 Subject: [PATCH 05/22] refactor: clean up commented code. --- packages/core-macro/src/rsx/component.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/core-macro/src/rsx/component.rs b/packages/core-macro/src/rsx/component.rs index d0ade9058..d316c833b 100644 --- a/packages/core-macro/src/rsx/component.rs +++ b/packages/core-macro/src/rsx/component.rs @@ -50,13 +50,6 @@ impl Component { invalid_component_path!(path); } - // if matches!( - // path.segments.last().unwrap().arguments, - // PathArguments::AngleBracketed(_) - // ) { - // proc_macro_error::abort!(path, "path: {}", path.to_token_stream().to_string()); - // } - Ok(()) } } From 690efade8840cd2744891600071f7460cba52df9 Mon Sep 17 00:00:00 2001 From: Muhannad Alrusayni Date: Sat, 7 May 2022 06:47:16 +0300 Subject: [PATCH 06/22] fix: Support `Input::<..>` style to for generic components before that, we accepted this style `Input<..>` but to be consistent with Rust syntax this is dropped now. > For reference, the two ways of specifying explicit type parameters in > Rust are: > // for functions > let _ = foo::(); > > // for structs > let _ = Foo:: { ... }; > > by @jkelleyrtp --- packages/core-macro/src/rsx/component.rs | 2 +- packages/core-macro/src/rsx/node.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core-macro/src/rsx/component.rs b/packages/core-macro/src/rsx/component.rs index d316c833b..91c8c4903 100644 --- a/packages/core-macro/src/rsx/component.rs +++ b/packages/core-macro/src/rsx/component.rs @@ -141,7 +141,7 @@ impl ToTokens for Component { } None => { let mut toks = match prop_gen_args { - Some(gen_args) => quote! { fc_to_builder::#gen_args(#name) }, + Some(gen_args) => quote! { fc_to_builder #gen_args(#name) }, None => quote! { fc_to_builder(#name) }, }; for field in &self.body { diff --git a/packages/core-macro/src/rsx/node.rs b/packages/core-macro/src/rsx/node.rs index fa651cebf..baccf5371 100644 --- a/packages/core-macro/src/rsx/node.rs +++ b/packages/core-macro/src/rsx/node.rs @@ -65,10 +65,10 @@ impl Parse for BodyNode { // ::component () // crate::component{} // crate::component() - // Input<'_, String> {} - // crate::Input<'_, i32> {} + // Input:: {} + // crate::Input:: {} if body_stream.peek(token::Brace) || body_stream.peek(token::Paren) { - // this syntax is not allowd: + // NOTE: this syntax is not allowd: // Div () -> comp if path.segments.len() == 1 && body_stream.peek(token::Paren) { let com_ident = &path.segments.iter().next().unwrap().ident; From 37f7fe2ac679b06b24fdc4b3def3b15ee79c2b65 Mon Sep 17 00:00:00 2001 From: Muhannad Alrusayni Date: Sat, 7 May 2022 07:04:47 +0300 Subject: [PATCH 07/22] fix: Element must be of lowercase letters only --- packages/core-macro/src/rsx/node.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/core-macro/src/rsx/node.rs b/packages/core-macro/src/rsx/node.rs index baccf5371..a7ab7c413 100644 --- a/packages/core-macro/src/rsx/node.rs +++ b/packages/core-macro/src/rsx/node.rs @@ -33,19 +33,13 @@ impl Parse for BodyNode { // this is an Element if path match of: // - one ident // - followed by `{` - // - have no `PathArguments` - // - starts with lowercase + // - all chars lowercase // // example: // div {} if let Some(ident) = path.get_ident() { if body_stream.peek(token::Brace) - && ident - .to_string() - .chars() - .next() - .unwrap() - .is_ascii_lowercase() + && ident.to_string().chars().all(char::is_lowercase) { return Ok(BodyNode::Element(stream.parse::()?)); } From 062f986841ba89e42782b4642597d08243ca3442 Mon Sep 17 00:00:00 2001 From: Muhannad Alrusayni Date: Sat, 7 May 2022 13:21:24 +0300 Subject: [PATCH 08/22] refactor: Remove unused types from scope --- packages/core-macro/src/rsx/node.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core-macro/src/rsx/node.rs b/packages/core-macro/src/rsx/node.rs index a7ab7c413..8a13025ed 100644 --- a/packages/core-macro/src/rsx/node.rs +++ b/packages/core-macro/src/rsx/node.rs @@ -4,7 +4,7 @@ use proc_macro2::TokenStream as TokenStream2; use quote::{quote, ToTokens, TokenStreamExt}; use syn::{ parse::{Parse, ParseStream}, - token, Expr, LitStr, PathArguments, Result, Token, + token, Expr, LitStr, Result, }; /* From 03a14f4a8669388780b5693be0ab288a7a0ad4da Mon Sep 17 00:00:00 2001 From: Muhannad Alrusayni Date: Sat, 7 May 2022 13:39:57 +0300 Subject: [PATCH 09/22] fix: element start with lowercase letter again :D --- packages/core-macro/src/rsx/node.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/core-macro/src/rsx/node.rs b/packages/core-macro/src/rsx/node.rs index 8a13025ed..ba6469fe7 100644 --- a/packages/core-macro/src/rsx/node.rs +++ b/packages/core-macro/src/rsx/node.rs @@ -33,13 +33,18 @@ impl Parse for BodyNode { // this is an Element if path match of: // - one ident // - followed by `{` - // - all chars lowercase + // - 1st char is lowercase // // example: // div {} if let Some(ident) = path.get_ident() { if body_stream.peek(token::Brace) - && ident.to_string().chars().all(char::is_lowercase) + && ident + .to_string() + .chars() + .next() + .unwrap() + .is_ascii_lowercase() { return Ok(BodyNode::Element(stream.parse::()?)); } From 252f9343b8c940c368012b10d4eb7958d1f66443 Mon Sep 17 00:00:00 2001 From: Muhannad Alrusayni Date: Sat, 7 May 2022 13:45:17 +0300 Subject: [PATCH 10/22] fix: Support `Div ()` as component previously I from some reason I thought this not allowed syntax. Some test failed because of my misunderstood, so now I fix this :D --- packages/core-macro/src/rsx/errors.rs | 10 ---------- packages/core-macro/src/rsx/node.rs | 8 +------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/packages/core-macro/src/rsx/errors.rs b/packages/core-macro/src/rsx/errors.rs index 07134e4f0..476f42eff 100644 --- a/packages/core-macro/src/rsx/errors.rs +++ b/packages/core-macro/src/rsx/errors.rs @@ -24,16 +24,6 @@ macro_rules! component_path_cannot_have_arguments { }; } -macro_rules! component_ident_cannot_use_paren { - ($span:expr, $com_name:ident) => { - proc_macro_error::abort!( - $span, - "Invalid component syntax"; - help = "try replace {} (..) to {} {{..}}", $com_name, $com_name; - ) - }; -} - macro_rules! invalid_component_path { ($span:expr) => { proc_macro_error::abort!($span, "Invalid component path syntax") diff --git a/packages/core-macro/src/rsx/node.rs b/packages/core-macro/src/rsx/node.rs index ba6469fe7..1f1c19131 100644 --- a/packages/core-macro/src/rsx/node.rs +++ b/packages/core-macro/src/rsx/node.rs @@ -57,6 +57,7 @@ impl Parse for BodyNode { // // example // Div {} + // Div () // ::Div {} // crate::Div {} // component() @@ -67,13 +68,6 @@ impl Parse for BodyNode { // Input:: {} // crate::Input:: {} if body_stream.peek(token::Brace) || body_stream.peek(token::Paren) { - // NOTE: this syntax is not allowd: - // Div () -> comp - if path.segments.len() == 1 && body_stream.peek(token::Paren) { - let com_ident = &path.segments.iter().next().unwrap().ident; - component_ident_cannot_use_paren!(path, com_ident); - } - Component::validate_component_path(&path)?; return Ok(BodyNode::Component(stream.parse()?)); From af8cd51258d7a97478f1f569e6da2374c8b941c5 Mon Sep 17 00:00:00 2001 From: Muhannad Alrusayni Date: Tue, 10 May 2022 05:57:44 +0300 Subject: [PATCH 11/22] test: Add test for generic components --- examples/rsx_usage.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/examples/rsx_usage.rs b/examples/rsx_usage.rs index 490aea844..774eb0ead 100644 --- a/examples/rsx_usage.rs +++ b/examples/rsx_usage.rs @@ -46,6 +46,9 @@ fn main() { /// This type alias specifies the type for you so you don't need to write "None as Option<()>" const NONE_ELEMENT: Option<()> = None; +use core::{fmt, str::FromStr}; +use std::fmt::Display; + use baller::Baller; use dioxus::prelude::*; @@ -187,6 +190,15 @@ fn app(cx: Scope) -> Element { text: "using functionc all syntax" ) + // Components can be geneirc too + // This component takes i32 type to give you typed input + TypedInput::> {} + // Type inference can be used too + TypedInput { initial: 10.0 } + // geneircs with the `inline_props` macro + label(text: "hello geneirc world!") + label(text: 99.9) + // helper functions // Single values must be wrapped in braces or `Some` to satisfy `IntoIterator` [helper(&cx, "hello world!")] @@ -227,9 +239,35 @@ pub fn Taller<'a>(cx: Scope<'a, TallerProps<'a>>) -> Element { }) } +#[derive(Props, PartialEq)] +pub struct TypedInputProps { + #[props(optional, default)] + initial: Option, +} + +#[allow(non_snake_case)] +pub fn TypedInput(_: Scope>) -> Element +where + T: FromStr + fmt::Display, + ::Err: std::fmt::Display, +{ + todo!() +} + #[inline_props] fn with_inline<'a>(cx: Scope<'a>, text: &'a str) -> Element { cx.render(rsx! { p { "{text}" } }) } + +// generic component with inline_props too +#[inline_props] +fn label(cx: Scope, text: T) -> Element +where + T: Display, +{ + cx.render(rsx! { + p { "{text}" } + }) +} From dded91a58972f0a9957ea81c813725be2e198f0f Mon Sep 17 00:00:00 2001 From: Muhannad Alrusayni Date: Fri, 13 May 2022 09:46:47 +0300 Subject: [PATCH 12/22] doc: put docs in once place instead of two --- packages/core-macro/src/lib.rs | 147 +-------------------------------- 1 file changed, 1 insertion(+), 146 deletions(-) diff --git a/packages/core-macro/src/lib.rs b/packages/core-macro/src/lib.rs index 931933386..8407a3733 100644 --- a/packages/core-macro/src/lib.rs +++ b/packages/core-macro/src/lib.rs @@ -29,152 +29,7 @@ pub fn derive_typed_builder(input: proc_macro::TokenStream) -> proc_macro::Token /// /// ## Complete Reference Guide: /// ``` -/// const Example: Component = |cx| { -/// let formatting = "formatting!"; -/// let formatting_tuple = ("a", "b"); -/// let lazy_fmt = format_args!("lazily formatted text"); -/// cx.render(rsx! { -/// div { -/// // Elements -/// div {} -/// h1 {"Some text"} -/// h1 {"Some text with {formatting}"} -/// h1 {"Formatting basic expressions {formatting_tuple.0} and {formatting_tuple.1}"} -/// h2 { -/// "Multiple" -/// "Text" -/// "Blocks" -/// "Use comments as separators in html" -/// } -/// div { -/// h1 {"multiple"} -/// h2 {"nested"} -/// h3 {"elements"} -/// } -/// div { -/// class: "my special div" -/// h1 {"Headers and attributes!"} -/// } -/// div { -/// // pass simple rust expressions in -/// class: lazy_fmt, -/// id: format_args!("attributes can be passed lazily with std::fmt::Arguments"), -/// div { -/// class: { -/// const WORD: &str = "expressions"; -/// format_args!("Arguments can be passed in through curly braces for complex {}", WORD) -/// } -/// } -/// } -/// -/// // Expressions can be used in element position too: -/// {rsx!(p { "More templating!" })} -/// {html!(

"Even HTML templating!!"

)} -/// -/// // Iterators -/// {(0..10).map(|i| rsx!(li { "{i}" }))} -/// {{ -/// let data = std::collections::HashMap::<&'static str, &'static str>::new(); -/// // Iterators *should* have keys when you can provide them. -/// // Keys make your app run faster. Make sure your keys are stable, unique, and predictable. -/// // Using an "ID" associated with your data is a good idea. -/// data.into_iter().map(|(k, v)| rsx!(li { key: "{k}" "{v}" })) -/// }} -/// -/// // Matching -/// {match true { -/// true => rsx!(h1 {"Top text"}), -/// false => rsx!(h1 {"Bottom text"}) -/// }} -/// -/// // Conditional rendering -/// // Dioxus conditional rendering is based around None/Some. We have no special syntax for conditionals. -/// // You can convert a bool condition to rsx! with .then and .or -/// {true.then(|| rsx!(div {}))} -/// -/// // True conditions -/// {if true { -/// rsx!(h1 {"Top text"}) -/// } else { -/// rsx!(h1 {"Bottom text"}) -/// }} -/// -/// // returning "None" is a bit noisy... but rare in practice -/// {None as Option<()>} -/// -/// // Use the Dioxus type-alias for less noise -/// {NONE_ELEMENT} -/// -/// // can also just use empty fragments -/// Fragment {} -/// -/// // Fragments let you insert groups of nodes without a parent. -/// // This lets you make components that insert elements as siblings without a container. -/// div {"A"} -/// Fragment { -/// div {"B"} -/// div {"C"} -/// Fragment { -/// "D" -/// Fragment { -/// "heavily nested fragments is an antipattern" -/// "they cause Dioxus to do unnecessary work" -/// "don't use them carelessly if you can help it" -/// } -/// } -/// } -/// -/// // Components -/// // Can accept any paths -/// // Notice how you still get syntax highlighting and IDE support :) -/// Baller {} -/// baller::Baller { } -/// crate::baller::Baller {} -/// -/// // Can take properties -/// Taller { a: "asd" } -/// -/// // Can take optional properties -/// Taller { a: "asd" } -/// -/// // Can pass in props directly as an expression -/// {{ -/// let props = TallerProps {a: "hello"}; -/// rsx!(Taller { ..props }) -/// }} -/// -/// // Spreading can also be overridden manually -/// Taller { -/// ..TallerProps { a: "ballin!" } -/// a: "not ballin!" -/// } -/// -/// // Can take children too! -/// Taller { a: "asd", div {"hello world!"} } -/// } -/// }) -/// }; -/// -/// mod baller { -/// use super::*; -/// pub struct BallerProps {} -/// -/// /// This component totally balls -/// pub fn Baller(cx: Scope) -> DomTree { -/// todo!() -/// } -/// } -/// -/// #[derive(Debug, PartialEq, Props)] -/// pub struct TallerProps { -/// a: &'static str, -/// } -/// -/// /// This component is taller than most :) -/// pub fn Taller(cx: Scope) -> DomTree { -/// let b = true; -/// todo!() -/// } +#[doc = include_str!("../../../examples/rsx_usage.rs")] /// ``` #[proc_macro_error::proc_macro_error] #[proc_macro] From dcfe60c164dafce96cd65d8dcd6fec1467f13b07 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 10 Jun 2022 17:23:30 -0500 Subject: [PATCH 13/22] use taffy instead of stretch2 --- packages/native-core/Cargo.toml | 2 +- packages/native-core/src/layout_attributes.rs | 32 ++++++----------- packages/tui/Cargo.toml | 2 +- packages/tui/src/hooks.rs | 8 ++--- packages/tui/src/layout.rs | 23 ++++++------- packages/tui/src/lib.rs | 34 +++++++++---------- packages/tui/src/render.rs | 6 ++-- packages/tui/src/style_attributes.rs | 4 +-- 8 files changed, 49 insertions(+), 62 deletions(-) diff --git a/packages/native-core/Cargo.toml b/packages/native-core/Cargo.toml index 4e7112eb0..1c54e0711 100644 --- a/packages/native-core/Cargo.toml +++ b/packages/native-core/Cargo.toml @@ -15,7 +15,7 @@ dioxus-core = { path = "../core", version = "^0.2.1" } dioxus-html = { path = "../html", version = "^0.2.1" } dioxus-core-macro = { path = "../core-macro", version = "^0.2.1" } -stretch2 = { git = "https://github.com/mockersf/stretch/", branch = "remove_round_layout_changes" } +taffy = "0.1.0" smallvec = "1.6" fxhash = "0.2" anymap = "0.12.1" diff --git a/packages/native-core/src/layout_attributes.rs b/packages/native-core/src/layout_attributes.rs index 45461a3f9..578acb304 100644 --- a/packages/native-core/src/layout_attributes.rs +++ b/packages/native-core/src/layout_attributes.rs @@ -1,6 +1,6 @@ /* - [ ] pub display: Display, -- [x] pub position_type: PositionType, --> kinda, stretch doesnt support everything +- [x] pub position_type: PositionType, --> kinda, taffy doesnt support everything - [ ] pub direction: Direction, - [x] pub flex_direction: FlexDirection, @@ -9,7 +9,7 @@ - [x] pub flex_shrink: f32, - [x] pub flex_basis: Dimension, -- [x] pub overflow: Overflow, ---> kinda implemented... stretch doesnt have support for directional overflow +- [x] pub overflow: Overflow, ---> kinda implemented... taffy doesnt have support for directional overflow - [x] pub align_items: AlignItems, - [x] pub align_self: AlignSelf, @@ -29,7 +29,10 @@ - [ ] pub aspect_ratio: Number, */ -use stretch2::{prelude::*, style::PositionType}; +use taffy::{ + prelude::*, + style::{FlexDirection, PositionType}, +}; /// applies the entire html namespace defined in dioxus-html pub fn apply_layout_attributes(name: &str, value: &str, style: &mut Style) { @@ -109,13 +112,7 @@ pub fn apply_layout_attributes(name: &str, value: &str, style: &mut Style) { "counter-reset" => {} "cursor" => {} - "direction" => { - match value { - "ltr" => style.direction = Direction::LTR, - "rtl" => style.direction = Direction::RTL, - _ => {} - } - } + "direction" => {} "display" => apply_display(name, value, style), @@ -283,18 +280,9 @@ pub fn parse_value(value: &str) -> Option { } } -fn apply_overflow(name: &str, value: &str, style: &mut Style) { +fn apply_overflow(name: &str, _value: &str, _style: &mut Style) { match name { - // todo: add more overflow support to stretch2 - "overflow" | "overflow-x" | "overflow-y" => { - style.overflow = match value { - "auto" => Overflow::Visible, - "hidden" => Overflow::Hidden, - "scroll" => Overflow::Scroll, - "visible" => Overflow::Visible, - _ => Overflow::Visible, - }; - } + // todo: add overflow support to taffy _ => {} } } @@ -307,7 +295,7 @@ fn apply_display(_name: &str, value: &str, style: &mut Style) { } // TODO: there are way more variants - // stretch needs to be updated to handle them + // taffy needs to be updated to handle them // // "block" => Display::Block, // "inline" => Display::Inline, diff --git a/packages/tui/Cargo.toml b/packages/tui/Cargo.toml index d9ccb8584..bfc1c8902 100644 --- a/packages/tui/Cargo.toml +++ b/packages/tui/Cargo.toml @@ -23,7 +23,7 @@ crossterm = "0.23.0" anyhow = "1.0.42" tokio = { version = "1.15.0", features = ["full"] } futures = "0.3.19" -stretch2 = { git = "https://github.com/mockersf/stretch/", branch = "remove_round_layout_changes" } +taffy = "0.1.0" smallvec = "1.6" fxhash = "0.2" anymap = "0.12.1" diff --git a/packages/tui/src/hooks.rs b/packages/tui/src/hooks.rs index 9def817a8..c7cc83280 100644 --- a/packages/tui/src/hooks.rs +++ b/packages/tui/src/hooks.rs @@ -12,7 +12,7 @@ use std::{ sync::Arc, time::{Duration, Instant}, }; -use stretch2::{prelude::Layout, Stretch}; +use taffy::{prelude::Layout, Taffy}; use crate::{Dom, Node}; @@ -163,7 +163,7 @@ impl InnerInputState { &mut self, evts: &mut [EventCore], resolved_events: &mut Vec, - layout: &Stretch, + layout: &Taffy, dom: &mut Dom, ) { let previous_mouse = self.mouse.as_ref().map(|m| (m.0.clone(), m.1.clone())); @@ -185,7 +185,7 @@ impl InnerInputState { &self, previous_mouse: Option<(MouseData, Vec)>, resolved_events: &mut Vec, - layout: &Stretch, + layout: &Taffy, dom: &mut Dom, ) { fn layout_contains_point(layout: &Layout, point: (i32, i32)) -> bool { @@ -513,7 +513,7 @@ impl RinkInputHandler { ) } - pub(crate) fn get_events(&self, layout: &Stretch, dom: &mut Dom) -> Vec { + pub(crate) fn get_events(&self, layout: &Taffy, dom: &mut Dom) -> Vec { let mut resolved_events = Vec::new(); (*self.state).borrow_mut().update( diff --git a/packages/tui/src/layout.rs b/packages/tui/src/layout.rs index c13435896..231eb1285 100644 --- a/packages/tui/src/layout.rs +++ b/packages/tui/src/layout.rs @@ -6,7 +6,7 @@ use dioxus_native_core::layout_attributes::apply_layout_attributes; use dioxus_native_core::node_ref::{AttributeMask, NodeMask, NodeView}; use dioxus_native_core::state::ChildDepState; use dioxus_native_core_macro::sorted_str_slice; -use stretch2::prelude::*; +use taffy::prelude::*; #[derive(Debug, Clone, Copy, PartialEq)] pub(crate) enum PossiblyUninitalized { @@ -28,13 +28,13 @@ impl Default for PossiblyUninitalized { } #[derive(Clone, PartialEq, Default, Debug)] -pub(crate) struct StretchLayout { +pub(crate) struct TaffyLayout { pub style: Style, pub node: PossiblyUninitalized, } -impl ChildDepState for StretchLayout { - type Ctx = Rc>; +impl ChildDepState for TaffyLayout { + type Ctx = Rc>; type DepState = Self; // use tag to force this to be called when a node is built const NODE_MASK: NodeMask = @@ -53,7 +53,7 @@ impl ChildDepState for StretchLayout { Self::DepState: 'a, { let mut changed = false; - let mut stretch = ctx.borrow_mut(); + let mut taffy = ctx.borrow_mut(); let mut style = Style::default(); if let Some(text) = node.text() { let char_len = text.chars().count(); @@ -70,11 +70,10 @@ impl ChildDepState for StretchLayout { }; if let PossiblyUninitalized::Initialized(n) = self.node { if self.style != style { - stretch.set_style(n, style).unwrap(); + taffy.set_style(n, style).unwrap(); } } else { - self.node = - PossiblyUninitalized::Initialized(stretch.new_node(style, &[]).unwrap()); + self.node = PossiblyUninitalized::Initialized(taffy.new_node(style, &[]).unwrap()); changed = true; } } else { @@ -100,14 +99,14 @@ impl ChildDepState for StretchLayout { if let PossiblyUninitalized::Initialized(n) = self.node { if self.style != style { - stretch.set_style(n, style).unwrap(); + taffy.set_style(n, style).unwrap(); } - if stretch.children(n).unwrap() != child_layout { - stretch.set_children(n, &child_layout).unwrap(); + if taffy.children(n).unwrap() != child_layout { + taffy.set_children(n, &child_layout).unwrap(); } } else { self.node = PossiblyUninitalized::Initialized( - stretch.new_node(style, &child_layout).unwrap(), + taffy.new_node(style, &child_layout).unwrap(), ); changed = true; } diff --git a/packages/tui/src/lib.rs b/packages/tui/src/lib.rs index 3f647ffd1..22d70524e 100644 --- a/packages/tui/src/lib.rs +++ b/packages/tui/src/lib.rs @@ -13,12 +13,12 @@ use futures::{ channel::mpsc::{UnboundedReceiver, UnboundedSender}, pin_mut, StreamExt, }; -use layout::StretchLayout; +use layout::TaffyLayout; use std::cell::RefCell; use std::rc::Rc; use std::{io, time::Duration}; -use stretch2::{geometry::Point, prelude::Size, Stretch}; use style_attributes::StyleModifier; +use taffy::{geometry::Point, prelude::Size, Taffy}; use tui::{backend::CrosstermBackend, layout::Rect, Terminal}; mod config; @@ -37,8 +37,8 @@ type Node = dioxus_native_core::real_dom::Node; #[derive(Debug, Clone, State, Default)] struct NodeState { - #[child_dep_state(layout, RefCell)] - layout: StretchLayout, + #[child_dep_state(layout, RefCell)] + layout: TaffyLayout, // depends on attributes, the C component of it's parent and a u8 context #[parent_dep_state(style)] style: StyleModifier, @@ -88,9 +88,9 @@ pub fn launch_cfg(app: Component<()>, cfg: Config) { let mut rdom: Dom = RealDom::new(); let mutations = dom.rebuild(); let to_update = rdom.apply_mutations(vec![mutations]); - let stretch = Rc::new(RefCell::new(Stretch::new())); + let taffy = Rc::new(RefCell::new(Taffy::new())); let mut any_map = AnyMap::new(); - any_map.insert(stretch.clone()); + any_map.insert(taffy.clone()); let _to_rerender = rdom.update_state(&dom, to_update, any_map).unwrap(); render_vdom( @@ -99,7 +99,7 @@ pub fn launch_cfg(app: Component<()>, cfg: Config) { handler, cfg, rdom, - stretch, + taffy, register_event, ) .unwrap(); @@ -111,7 +111,7 @@ fn render_vdom( handler: RinkInputHandler, cfg: Config, mut rdom: Dom, - stretch: Rc>, + taffy: Rc>, mut register_event: impl FnMut(crossterm::event::Event), ) -> Result<()> { tokio::runtime::Builder::new_current_thread() @@ -146,17 +146,17 @@ fn render_vdom( if !to_rerender.is_empty() || resized { resized = false; - fn resize(dims: Rect, stretch: &mut Stretch, rdom: &Dom) { + fn resize(dims: Rect, taffy: &mut Taffy, rdom: &Dom) { let width = dims.width; let height = dims.height; let root_node = rdom[0].state.layout.node.unwrap(); - stretch + taffy .compute_layout( root_node, Size { - width: stretch2::prelude::Number::Defined((width - 1) as f32), - height: stretch2::prelude::Number::Defined((height - 1) as f32), + width: taffy::prelude::Number::Defined((width - 1) as f32), + height: taffy::prelude::Number::Defined((height - 1) as f32), }, ) .unwrap(); @@ -164,11 +164,11 @@ fn render_vdom( if let Some(terminal) = &mut terminal { terminal.draw(|frame| { // size is guaranteed to not change when rendering - resize(frame.size(), &mut stretch.borrow_mut(), &rdom); + resize(frame.size(), &mut taffy.borrow_mut(), &rdom); let root = &rdom[0]; render::render_vnode( frame, - &stretch.borrow(), + &taffy.borrow(), &rdom, root, cfg, @@ -183,7 +183,7 @@ fn render_vdom( width: 300, height: 300, }, - &mut stretch.borrow_mut(), + &mut taffy.borrow_mut(), &rdom, ); } @@ -223,7 +223,7 @@ fn render_vdom( } { - let evts = handler.get_events(&stretch.borrow(), &mut rdom); + let evts = handler.get_events(&taffy.borrow(), &mut rdom); for e in evts { vdom.handle_message(SchedulerMsg::Event(e)); } @@ -232,7 +232,7 @@ fn render_vdom( let to_update = rdom.apply_mutations(mutations); // update the style and layout let mut any_map = AnyMap::new(); - any_map.insert(stretch.clone()); + any_map.insert(taffy.clone()); to_rerender = rdom.update_state(vdom, to_update, any_map).unwrap(); } } diff --git a/packages/tui/src/render.rs b/packages/tui/src/render.rs index 4df83f8b6..f4d72cb26 100644 --- a/packages/tui/src/render.rs +++ b/packages/tui/src/render.rs @@ -1,9 +1,9 @@ use dioxus_native_core::layout_attributes::UnitSystem; use std::io::Stdout; -use stretch2::{ +use taffy::{ geometry::Point, prelude::{Layout, Size}, - Stretch, + Taffy, }; use tui::{backend::CrosstermBackend, layout::Rect}; @@ -18,7 +18,7 @@ const RADIUS_MULTIPLIER: [f32; 2] = [1.0, 0.5]; pub(crate) fn render_vnode( frame: &mut tui::Frame>, - layout: &Stretch, + layout: &Taffy, rdom: &Dom, node: &Node, cfg: Config, diff --git a/packages/tui/src/style_attributes.rs b/packages/tui/src/style_attributes.rs index fd8d51cb3..210fedb34 100644 --- a/packages/tui/src/style_attributes.rs +++ b/packages/tui/src/style_attributes.rs @@ -1,6 +1,6 @@ /* - [ ] pub display: Display, -- [x] pub position_type: PositionType, --> kinda, stretch doesnt support everything +- [x] pub position_type: PositionType, --> kinda, taffy doesnt support everything - [ ] pub direction: Direction, - [x] pub flex_direction: FlexDirection, @@ -9,7 +9,7 @@ - [x] pub flex_shrink: f32, - [x] pub flex_basis: Dimension, -- [x] pub overflow: Overflow, ---> kinda implemented... stretch doesnt have support for directional overflow +- [x] pub overflow: Overflow, ---> kinda implemented... taffy doesnt have support for directional overflow - [x] pub align_items: AlignItems, - [x] pub align_self: AlignSelf, From 44686e217fb329867ec2b62e336d7b0c1369cb8f Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 10 Jun 2022 17:33:19 -0500 Subject: [PATCH 14/22] remove empty match --- packages/native-core/src/layout_attributes.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/native-core/src/layout_attributes.rs b/packages/native-core/src/layout_attributes.rs index 578acb304..9ae9e3c83 100644 --- a/packages/native-core/src/layout_attributes.rs +++ b/packages/native-core/src/layout_attributes.rs @@ -280,11 +280,8 @@ pub fn parse_value(value: &str) -> Option { } } -fn apply_overflow(name: &str, _value: &str, _style: &mut Style) { - match name { - // todo: add overflow support to taffy - _ => {} - } +fn apply_overflow(_name: &str, _value: &str, _style: &mut Style) { + // todo: add overflow support to taffy } fn apply_display(_name: &str, value: &str, style: &mut Style) { From 69ecc9caafc8b501a2be24d1bfff0e5d0ecc6a2e Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 10 Jun 2022 17:47:43 -0500 Subject: [PATCH 15/22] update tui tests --- packages/tui/tests/margin.rs | 82 ++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/packages/tui/tests/margin.rs b/packages/tui/tests/margin.rs index 53e8978e5..3151f3ba7 100644 --- a/packages/tui/tests/margin.rs +++ b/packages/tui/tests/margin.rs @@ -1,15 +1,13 @@ -use stretch2 as stretch; - #[test] fn margin_and_flex_row() { - let mut stretch = stretch::Stretch::new(); - let node0 = stretch + let mut taffy = taffy::Taffy::new(); + let node0 = taffy .new_node( - stretch::style::Style { + taffy::style::Style { flex_grow: 1f32, - margin: stretch::geometry::Rect { - start: stretch::style::Dimension::Points(10f32), - end: stretch::style::Dimension::Points(10f32), + margin: taffy::geometry::Rect { + start: taffy::style::Dimension::Points(10f32), + end: taffy::style::Dimension::Points(10f32), ..Default::default() }, ..Default::default() @@ -17,50 +15,50 @@ fn margin_and_flex_row() { &[], ) .unwrap(); - let node = stretch + let node = taffy .new_node( - stretch::style::Style { - size: stretch::geometry::Size { - width: stretch::style::Dimension::Points(100f32), - height: stretch::style::Dimension::Points(100f32), + taffy::style::Style { + size: taffy::geometry::Size { + width: taffy::style::Dimension::Points(100f32), + height: taffy::style::Dimension::Points(100f32), }, ..Default::default() }, &[node0], ) .unwrap(); - stretch - .compute_layout(node, stretch::geometry::Size::undefined()) + taffy + .compute_layout(node, taffy::geometry::Size::undefined()) .unwrap(); - assert_eq!(stretch.layout(node).unwrap().size.width, 100f32); - assert_eq!(stretch.layout(node).unwrap().size.height, 100f32); - assert_eq!(stretch.layout(node).unwrap().location.x, 0f32); - assert_eq!(stretch.layout(node).unwrap().location.y, 0f32); - assert_eq!(stretch.layout(node0).unwrap().size.width, 80f32); - assert_eq!(stretch.layout(node0).unwrap().size.height, 100f32); - assert_eq!(stretch.layout(node0).unwrap().location.x, 10f32); - assert_eq!(stretch.layout(node0).unwrap().location.y, 0f32); + assert_eq!(taffy.layout(node).unwrap().size.width, 100f32); + assert_eq!(taffy.layout(node).unwrap().size.height, 100f32); + assert_eq!(taffy.layout(node).unwrap().location.x, 0f32); + assert_eq!(taffy.layout(node).unwrap().location.y, 0f32); + assert_eq!(taffy.layout(node0).unwrap().size.width, 80f32); + assert_eq!(taffy.layout(node0).unwrap().size.height, 100f32); + assert_eq!(taffy.layout(node0).unwrap().location.x, 10f32); + assert_eq!(taffy.layout(node0).unwrap().location.y, 0f32); } #[test] fn margin_and_flex_row2() { - let mut stretch = stretch::Stretch::new(); - let node0 = stretch + let mut taffy = taffy::Taffy::new(); + let node0 = taffy .new_node( - stretch::style::Style { + taffy::style::Style { flex_grow: 1f32, - margin: stretch::geometry::Rect { + margin: taffy::geometry::Rect { // left - start: stretch::style::Dimension::Points(10f32), + start: taffy::style::Dimension::Points(10f32), // right? - end: stretch::style::Dimension::Points(10f32), + end: taffy::style::Dimension::Points(10f32), // top? - // top: stretch::style::Dimension::Points(10f32), + // top: taffy::style::Dimension::Points(10f32), // bottom? - // bottom: stretch::style::Dimension::Points(10f32), + // bottom: taffy::style::Dimension::Points(10f32), ..Default::default() }, ..Default::default() @@ -69,12 +67,12 @@ fn margin_and_flex_row2() { ) .unwrap(); - let node = stretch + let node = taffy .new_node( - stretch::style::Style { - size: stretch::geometry::Size { - width: stretch::style::Dimension::Points(100f32), - height: stretch::style::Dimension::Points(100f32), + taffy::style::Style { + size: taffy::geometry::Size { + width: taffy::style::Dimension::Points(100f32), + height: taffy::style::Dimension::Points(100f32), }, ..Default::default() }, @@ -82,12 +80,12 @@ fn margin_and_flex_row2() { ) .unwrap(); - stretch - .compute_layout(node, stretch::geometry::Size::undefined()) + taffy + .compute_layout(node, taffy::geometry::Size::undefined()) .unwrap(); - assert_eq!(stretch.layout(node).unwrap().size.width, 100f32); - assert_eq!(stretch.layout(node).unwrap().size.height, 100f32); - assert_eq!(stretch.layout(node).unwrap().location.x, 0f32); - assert_eq!(stretch.layout(node).unwrap().location.y, 0f32); + assert_eq!(taffy.layout(node).unwrap().size.width, 100f32); + assert_eq!(taffy.layout(node).unwrap().size.height, 100f32); + assert_eq!(taffy.layout(node).unwrap().location.x, 0f32); + assert_eq!(taffy.layout(node).unwrap().location.y, 0f32); } From 29b3503da898b0c64aca885c76db2ca93a092009 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 10 Jun 2022 17:49:04 -0500 Subject: [PATCH 16/22] fmt --- packages/tui/src/hooks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tui/src/hooks.rs b/packages/tui/src/hooks.rs index 8cadd6739..d4ba6a2cf 100644 --- a/packages/tui/src/hooks.rs +++ b/packages/tui/src/hooks.rs @@ -17,8 +17,8 @@ use std::{ sync::Arc, time::{Duration, Instant}, }; -use taffy::{prelude::Layout, Taffy}; use taffy::geometry::{Point, Size}; +use taffy::{prelude::Layout, Taffy}; use crate::{Dom, Node}; From 287cef96b19c671c683792ccf0e3d998ca6775bb Mon Sep 17 00:00:00 2001 From: xTeKc <81730792+xTeKc@users.noreply.github.com> Date: Sun, 12 Jun 2022 04:02:21 -0400 Subject: [PATCH 17/22] fix link --- docs/guide/src/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/src/README.md b/docs/guide/src/README.md index c20258066..778cabe4a 100644 --- a/docs/guide/src/README.md +++ b/docs/guide/src/README.md @@ -71,7 +71,7 @@ Desktop APIs will likely be in flux as we figure out better patterns than our El [Jump to the getting started guide for Desktop.](/reference/platforms/desktop) Examples: -- [File explorer](https://github.com/dioxusLabs/file-explorer/) +- [File explorer](https://github.com/DioxusLabs/example-projects/blob/master/file-explorer) - [WiFi scanner](https://github.com/DioxusLabs/example-projects/blob/master/wifi-scanner) [![File ExplorerExample](https://raw.githubusercontent.com/DioxusLabs/example-projects/master/file-explorer/image.png)](https://github.com/DioxusLabs/example-projects/tree/master/file-explorer) From af951f30ce277bdb86e235e8f14126022c68ff0d Mon Sep 17 00:00:00 2001 From: xTeKc <81730792+xTeKc@users.noreply.github.com> Date: Sun, 12 Jun 2022 04:10:42 -0400 Subject: [PATCH 18/22] update dead link --- docs/guide/src/setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/src/setup.md b/docs/guide/src/setup.md index 5e4c9e347..3244ce301 100644 --- a/docs/guide/src/setup.md +++ b/docs/guide/src/setup.md @@ -59,7 +59,7 @@ When using Debian/bullseye `libappindicator3-dev` is no longer available but rep sudo apt install libwebkit2gtk-4.0-dev libgtk-3-dev libayatana-appindicator3-dev ``` -If you run into issues, make sure you have all the basics installed, as outlined in the [Tauri docs](https://tauri.studio/en/docs/get-started/setup-linux). +If you run into issues, make sure you have all the basics installed, as outlined in the [Tauri docs](https://tauri.studio/v1/guides/getting-started/prerequisites#setting-up-linux). ### macOS From c97f051bbd198d3177de6bef362b8ba16a00ae72 Mon Sep 17 00:00:00 2001 From: Yin Jifeng Date: Mon, 13 Jun 2022 18:32:03 +0800 Subject: [PATCH 19/22] fermi: set atom value even it doesn't exist --- packages/fermi/src/root.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/fermi/src/root.rs b/packages/fermi/src/root.rs index c7c234ddb..f77930c75 100644 --- a/packages/fermi/src/root.rs +++ b/packages/fermi/src/root.rs @@ -74,6 +74,13 @@ impl AtomRoot { } } else { log::trace!("no atoms found for {:?}", ptr); + atoms.insert( + ptr, + Slot { + value: Rc::new(value), + subscribers: HashSet::new(), + }, + ); } } From 7576426c936c7184eab073f0cc669cd4852f5597 Mon Sep 17 00:00:00 2001 From: Yin Jifeng Date: Mon, 13 Jun 2022 18:37:49 +0800 Subject: [PATCH 20/22] core: cleanup tasks polling fn --- packages/core/src/virtual_dom.rs | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 2b1de0767..333fef513 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -337,29 +337,12 @@ impl VirtualDom { let scopes = &mut self.scopes; let task_poll = poll_fn(|cx| { - // - let mut any_pending = false; - let mut tasks = scopes.tasks.tasks.borrow_mut(); - let mut to_remove = vec![]; + tasks.retain(|_, task| task.as_mut().poll(cx).is_pending()); - // this would be better served by retain - for (id, task) in tasks.iter_mut() { - if task.as_mut().poll(cx).is_ready() { - to_remove.push(*id); - } else { - any_pending = true; - } - } - - for id in to_remove { - tasks.remove(&id); - } - - // Resolve the future if any singular task is ready - match any_pending { - true => Poll::Pending, - false => Poll::Ready(()), + match tasks.is_empty() { + true => Poll::Ready(()), + false => Poll::Pending, } }); From 814235f1456fa81babd21a76b4b30ddd8617fba7 Mon Sep 17 00:00:00 2001 From: Yin Jifeng Date: Mon, 13 Jun 2022 18:40:17 +0800 Subject: [PATCH 21/22] docs: update func names --- packages/core/src/scopes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/scopes.rs b/packages/core/src/scopes.rs index 010c63b03..27520dfd1 100644 --- a/packages/core/src/scopes.rs +++ b/packages/core/src/scopes.rs @@ -609,7 +609,7 @@ impl ScopeState { /// Create a subscription that schedules a future render for the reference component /// - /// ## Notice: you should prefer using prepare_update and get_scope_id + /// ## Notice: you should prefer using schedule_update_any and scope_id pub fn schedule_update(&self) -> Arc { let (chan, id) = (self.tasks.sender.clone(), self.scope_id()); Arc::new(move || { From 3cbf8ed6fafca4cacb03790a5ac366dedbe5118c Mon Sep 17 00:00:00 2001 From: Yin Jifeng Date: Mon, 13 Jun 2022 18:42:24 +0800 Subject: [PATCH 22/22] fix: remove task id from scope when success --- packages/core/src/scopes.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/core/src/scopes.rs b/packages/core/src/scopes.rs index 27520dfd1..8db5efe56 100644 --- a/packages/core/src/scopes.rs +++ b/packages/core/src/scopes.rs @@ -1000,12 +1000,11 @@ impl TaskQueue { fn remove(&self, id: TaskId) { if let Ok(mut tasks) = self.tasks.try_borrow_mut() { let _ = tasks.remove(&id); + if let Some(task_map) = self.task_map.borrow_mut().get_mut(&id.scope) { + task_map.remove(&id); + } } - // the task map is still around, but it'll be removed when the scope is unmounted - if let Some(task_map) = self.task_map.borrow_mut().get_mut(&id.scope) { - task_map.remove(&id); - } } pub(crate) fn has_tasks(&self) -> bool {