Disambiguate expressions in rsx by requiring curlies
This commit is contained in:
53 files changed
+398
-372
No files matched your search
@@ -76,7 +76,11 @@ fn app(cx: Scope) -> Element {
|
|||||||
|
|
||||||
"Hover, click, type or scroll to see the info down below"
|
"Hover, click, type or scroll to see the info down below"
|
||||||
}
|
}
|
||||||
div { events.read().iter().map(|event| rsx!( div { "{event:?}" } )) }
|
div {
|
||||||
|
for event in events.read().iter() {
|
||||||
|
div { "{event:?}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@@ -58,13 +58,13 @@ fn app(cx: Scope) -> Element {
|
|||||||
};
|
};
|
||||||
|
|
||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
style { include_str!("./assets/calculator.css") }
|
style { {include_str!("./assets/calculator.css")} }
|
||||||
div { id: "wrapper",
|
div { id: "wrapper",
|
||||||
div { class: "app",
|
div { class: "app",
|
||||||
div { class: "calculator",
|
div { class: "calculator",
|
||||||
tabindex: "0",
|
tabindex: "0",
|
||||||
onkeydown: handle_key_down_event,
|
onkeydown: handle_key_down_event,
|
||||||
div { class: "calculator-display", val.to_string() }
|
div { class: "calculator-display", "{val}" }
|
||||||
div { class: "calculator-keypad",
|
div { class: "calculator-keypad",
|
||||||
div { class: "input-keys",
|
div { class: "input-keys",
|
||||||
div { class: "function-keys",
|
div { class: "function-keys",
|
||||||
@@ -103,14 +103,14 @@ fn app(cx: Scope) -> Element {
|
|||||||
div { class: "digit-keys",
|
div { class: "digit-keys",
|
||||||
button { class: "calculator-key key-0", onclick: move |_| input_digit(0), "0" }
|
button { class: "calculator-key key-0", onclick: move |_| input_digit(0), "0" }
|
||||||
button { class: "calculator-key key-dot", onclick: move |_| val.make_mut().push('.'), "●" }
|
button { class: "calculator-key key-dot", onclick: move |_| val.make_mut().push('.'), "●" }
|
||||||
(1..10).map(|k| rsx!{
|
for k in 1..10 {
|
||||||
button {
|
button {
|
||||||
class: "calculator-key {k}",
|
class: "calculator-key {k}",
|
||||||
name: "key-{k}",
|
name: "key-{k}",
|
||||||
onclick: move |_| input_digit(k),
|
onclick: move |_| input_digit(k),
|
||||||
"{k}"
|
"{k}"
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
div { class: "operator-keys",
|
div { class: "operator-keys",
|
||||||
|
|||||||
+2
-2
@@ -32,12 +32,12 @@ fn app(cx: Scope) -> Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
emails_sent.read().iter().map(|message| cx.render(rsx! {
|
for message in emails_sent.read().iter() {
|
||||||
li {
|
li {
|
||||||
h3 { "email" }
|
h3 { "email" }
|
||||||
span {"{message}"}
|
span {"{message}"}
|
||||||
}
|
}
|
||||||
}))
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ fn app(cx: Scope) -> Element {
|
|||||||
loop {
|
loop {
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(10)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(10)).await;
|
||||||
if let Some(element) = elements.read().get(focused) {
|
if let Some(element) = elements.read().get(focused) {
|
||||||
element.set_focus(true);
|
_ = element.set_focus(true).await;
|
||||||
} else {
|
} else {
|
||||||
focused = 0;
|
focused = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -62,7 +62,7 @@ fn ClientList(cx: Scope) -> Element {
|
|||||||
Link { to: Route::ClientAdd {}, class: "pure-button pure-button-primary", "Add Client" }
|
Link { to: Route::ClientAdd {}, class: "pure-button pure-button-primary", "Add Client" }
|
||||||
Link { to: Route::Settings {}, class: "pure-button", "Settings" }
|
Link { to: Route::Settings {}, class: "pure-button", "Settings" }
|
||||||
|
|
||||||
clients.read().iter().map(|client| rsx! {
|
for client in clients.read().iter() {
|
||||||
div {
|
div {
|
||||||
class: "client",
|
class: "client",
|
||||||
style: "margin-bottom: 50px",
|
style: "margin-bottom: 50px",
|
||||||
@@ -70,7 +70,7 @@ fn ClientList(cx: Scope) -> Element {
|
|||||||
p { "Name: {client.first_name} {client.last_name}" }
|
p { "Name: {client.first_name} {client.last_name}" }
|
||||||
p { "Description: {client.description}" }
|
p { "Description: {client.description}" }
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -14,9 +14,9 @@ fn app(cx: Scope) -> Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render! {
|
render! {
|
||||||
(0..count).map(|_| rsx!{
|
{(0..count).map(|_| rsx!{
|
||||||
drop_child {}
|
drop_child {}
|
||||||
})
|
})}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -39,9 +39,9 @@ fn ChildWithRef(cx: Scope) -> Element {
|
|||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
ul {
|
ul {
|
||||||
names.read().iter().map(|f| rsx!{
|
for name in names.read().iter() {
|
||||||
li { "hello: {f}" }
|
li { "hello: {name}" }
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
button {
|
button {
|
||||||
onclick: move |_| {
|
onclick: move |_| {
|
||||||
|
|||||||
@@ -28,12 +28,12 @@ fn app(cx: Scope) -> Element {
|
|||||||
link { href:"https://fonts.googleapis.com/icon?family=Material+Icons", rel:"stylesheet", }
|
link { href:"https://fonts.googleapis.com/icon?family=Material+Icons", rel:"stylesheet", }
|
||||||
header {
|
header {
|
||||||
i { class: "material-icons icon-menu", "menu" }
|
i { class: "material-icons icon-menu", "menu" }
|
||||||
h1 { "Files: ", files.read().current() }
|
h1 { "Files: ", {files.read().current()} }
|
||||||
span { }
|
span { }
|
||||||
i { class: "material-icons", onclick: move |_| files.write().go_up(), "logout" }
|
i { class: "material-icons", onclick: move |_| files.write().go_up(), "logout" }
|
||||||
}
|
}
|
||||||
main {
|
main {
|
||||||
files.read().path_names.iter().enumerate().map(|(dir_id, path)| {
|
{files.read().path_names.iter().enumerate().map(|(dir_id, path)| {
|
||||||
let path_end = path.split('/').last().unwrap_or(path.as_str());
|
let path_end = path.split('/').last().unwrap_or(path.as_str());
|
||||||
let icon_type = if path_end.contains('.') {
|
let icon_type = if path_end.contains('.') {
|
||||||
"description"
|
"description"
|
||||||
@@ -52,15 +52,13 @@ fn app(cx: Scope) -> Element {
|
|||||||
h1 { "{path_end}" }
|
h1 { "{path_end}" }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}),
|
})},
|
||||||
files.read().err.as_ref().map(|err| {
|
if let Some(err) = files.read().err.as_ref() {
|
||||||
rsx! (
|
div {
|
||||||
div {
|
code { "{err}" }
|
||||||
code { "{err}" }
|
button { onclick: move |_| files.write().clear_err(), "x" }
|
||||||
button { onclick: move |_| files.write().clear_err(), "x" }
|
}
|
||||||
}
|
}
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -66,9 +66,9 @@ fn app(cx: Scope) -> Element {
|
|||||||
}
|
}
|
||||||
table {
|
table {
|
||||||
tbody {
|
tbody {
|
||||||
items.read().iter().enumerate().map(|(id, item)| {
|
for (id, item) in items.read().iter().enumerate() {
|
||||||
let is_in_danger = if (*selected).map(|s| s == id).unwrap_or(false) {"danger"} else {""};
|
tr {
|
||||||
rsx!(tr { class: "{is_in_danger}",
|
class: if (*selected).map(|s| s == id).unwrap_or(false) { "danger" },
|
||||||
td { class:"col-md-1" }
|
td { class:"col-md-1" }
|
||||||
td { class:"col-md-1", "{item.key}" }
|
td { class:"col-md-1", "{item.key}" }
|
||||||
td { class:"col-md-1", onclick: move |_| selected.set(Some(id)),
|
td { class:"col-md-1", onclick: move |_| selected.set(Some(id)),
|
||||||
@@ -80,8 +80,9 @@ fn app(cx: Scope) -> Element {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
td { class: "col-md-6" }
|
td { class: "col-md-6" }
|
||||||
})
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span { class: "preloadicon glyphicon glyphicon-remove", aria_hidden: "true" }
|
span { class: "preloadicon glyphicon glyphicon-remove", aria_hidden: "true" }
|
||||||
|
|||||||
+3
-3
@@ -37,7 +37,7 @@ const FIELDS: &[(&str, &str)] = &[
|
|||||||
fn app(cx: Scope) -> Element {
|
fn app(cx: Scope) -> Element {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div { margin_left: "30px",
|
div { margin_left: "30px",
|
||||||
select_example(cx),
|
{select_example(cx)},
|
||||||
div {
|
div {
|
||||||
// handling inputs on divs will catch all input events below
|
// handling inputs on divs will catch all input events below
|
||||||
// so the value of our input event will be either huey, dewey, louie, or true/false (because of the checkboxe)
|
// so the value of our input event will be either huey, dewey, louie, or true/false (because of the checkboxe)
|
||||||
@@ -114,7 +114,7 @@ fn app(cx: Scope) -> Element {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FIELDS.iter().map(|(field, value)| rsx! {
|
for (field, value) in FIELDS.iter() {
|
||||||
div {
|
div {
|
||||||
input {
|
input {
|
||||||
id: "{field}",
|
id: "{field}",
|
||||||
@@ -131,7 +131,7 @@ fn app(cx: Scope) -> Element {
|
|||||||
}
|
}
|
||||||
br {}
|
br {}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ pub fn LogOut(cx: Scope<ClientProps>) -> Element {
|
|||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
rsx! {
|
rsx! {
|
||||||
div { format!{"Failed to load disconnection url: {:?}", error} }
|
div { "Failed to load disconnection url: {error:?}" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -143,9 +143,9 @@ pub fn LoadClient(cx: Scope) -> Element {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
|
log::info! {"Failed to load client: {:?}", error};
|
||||||
rsx! {
|
rsx! {
|
||||||
div { format!{"Failed to load client: {:?}", error} }
|
div { "Failed to load client: {error:?}" }
|
||||||
log::info!{"Failed to load client: {:?}", error},
|
|
||||||
Outlet::<Route> {}
|
Outlet::<Route> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,7 +184,7 @@ pub fn AuthHeader(cx: Scope) -> Element {
|
|||||||
Ok(email) => {
|
Ok(email) => {
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
div {
|
||||||
div { email }
|
div { {email} }
|
||||||
LogOut { client_id: client_props.client_id, client: client_props.client }
|
LogOut { client_id: client_props.client_id, client: client_props.client }
|
||||||
Outlet::<Route> {}
|
Outlet::<Route> {}
|
||||||
}
|
}
|
||||||
@@ -207,7 +207,7 @@ pub fn AuthHeader(cx: Scope) -> Element {
|
|||||||
log::info!("Other issue with token");
|
log::info!("Other issue with token");
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
div {
|
||||||
div { error.to_string() }
|
div { "{error}" }
|
||||||
Outlet::<Route> {}
|
Outlet::<Route> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ use dioxus::prelude::*;
|
|||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn NotFound(cx: Scope, route: Vec<String>) -> Element {
|
pub fn NotFound(cx: Scope, route: Vec<String>) -> Element {
|
||||||
let routes = route.join("");
|
render! {
|
||||||
render! {rsx! {div{routes}}}
|
div{
|
||||||
|
{route.join("")}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -39,11 +39,11 @@ fn app(cx: Scope) -> Element {
|
|||||||
let state = use_ref(cx, Calculator::new);
|
let state = use_ref(cx, Calculator::new);
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
style { include_str!("./assets/calculator.css") }
|
style { {include_str!("./assets/calculator.css")} }
|
||||||
div { id: "wrapper",
|
div { id: "wrapper",
|
||||||
div { class: "app",
|
div { class: "app",
|
||||||
div { class: "calculator", onkeypress: move |evt| state.write().handle_keydown(evt),
|
div { class: "calculator", onkeypress: move |evt| state.write().handle_keydown(evt),
|
||||||
div { class: "calculator-display", state.read().formatted_display() }
|
div { class: "calculator-display", {state.read().formatted_display()} }
|
||||||
div { class: "calculator-keypad",
|
div { class: "calculator-keypad",
|
||||||
div { class: "input-keys",
|
div { class: "input-keys",
|
||||||
div { class: "function-keys",
|
div { class: "function-keys",
|
||||||
@@ -74,14 +74,14 @@ fn app(cx: Scope) -> Element {
|
|||||||
onclick: move |_| state.write().input_dot(),
|
onclick: move |_| state.write().input_dot(),
|
||||||
"●"
|
"●"
|
||||||
}
|
}
|
||||||
(1..10).map(move |k| rsx!{
|
for k in 1..10 {
|
||||||
CalculatorKey {
|
CalculatorKey {
|
||||||
key: "{k}",
|
key: "{k}",
|
||||||
name: "key-{k}",
|
name: "key-{k}",
|
||||||
onclick: move |_| state.write().input_digit(k),
|
onclick: move |_| state.write().input_digit(k),
|
||||||
"{k}"
|
"{k}"
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
div { class: "operator-keys",
|
div { class: "operator-keys",
|
||||||
@@ -130,7 +130,7 @@ fn CalculatorKey<'a>(cx: Scope<'a, CalculatorKeyProps<'a>>) -> Element {
|
|||||||
button {
|
button {
|
||||||
class: "calculator-key {cx.props.name}",
|
class: "calculator-key {cx.props.name}",
|
||||||
onclick: move |e| cx.props.onclick.call(e),
|
onclick: move |e| cx.props.onclick.call(e),
|
||||||
&cx.props.children
|
{&cx.props.children}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ fn app(cx: Scope) -> Element {
|
|||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
div {
|
div {
|
||||||
h1 {"Select an option"}
|
h1 {"Select an option"}
|
||||||
h3 { "The radio is... ", state.is_playing(), "!" }
|
h3 { "The radio is... ", {state.is_playing()}, "!" }
|
||||||
button { onclick: move |_| state.make_mut().reduce(PlayerAction::Pause),
|
button { onclick: move |_| state.make_mut().reduce(PlayerAction::Pause),
|
||||||
"Pause"
|
"Pause"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ impl FromQuery for ManualBlogQuerySegments {
|
|||||||
fn BlogPost(cx: Scope, query_params: ManualBlogQuerySegments) -> Element {
|
fn BlogPost(cx: Scope, query_params: ManualBlogQuerySegments) -> Element {
|
||||||
render! {
|
render! {
|
||||||
div{"This is your blogpost with a query segment:"}
|
div{"This is your blogpost with a query segment:"}
|
||||||
div{format!("{:?}", query_params)}
|
div{ "{query_params:?}" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ fn BlogPost(cx: Scope, query_params: ManualBlogQuerySegments) -> Element {
|
|||||||
fn AutomaticBlogPost(cx: Scope, name: String, surname: String) -> Element {
|
fn AutomaticBlogPost(cx: Scope, name: String, surname: String) -> Element {
|
||||||
render! {
|
render! {
|
||||||
div{"This is your blogpost with a query segment:"}
|
div{"This is your blogpost with a query segment:"}
|
||||||
div{format!("name={}&surname={}", name, surname)}
|
div{ "name={name}&surname={surname}" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,17 +36,17 @@ fn example(cx: Scope) -> Element {
|
|||||||
div { id: "asd",
|
div { id: "asd",
|
||||||
"your neighborhood spiderman"
|
"your neighborhood spiderman"
|
||||||
|
|
||||||
items.iter().cycle().take(5).map(|f| rsx!{
|
for item in items.iter().cycle().take(5) {
|
||||||
div { "{f.a}" }
|
div { "{item.a}" }
|
||||||
})
|
}
|
||||||
|
|
||||||
things_list.iter().map(|f| rsx!{
|
for thing in things_list.iter() {
|
||||||
div { "{f.a}" "{f.b}" }
|
div { "{thing.a}" "{thing.b}" }
|
||||||
})
|
}
|
||||||
|
|
||||||
mything_read.as_ref().map(|f| rsx! {
|
if let Some(f) = mything_read.as_ref() {
|
||||||
div { "{f}" }
|
div { "{f}" }
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
|||||||
+17
-16
@@ -61,7 +61,7 @@ fn App(cx: Scope) -> Element {
|
|||||||
h1 {"Some text"}
|
h1 {"Some text"}
|
||||||
h1 {"Some text with {formatting}"}
|
h1 {"Some text with {formatting}"}
|
||||||
h1 {"Formatting basic expressions {formatting_tuple.0} and {formatting_tuple.1}"}
|
h1 {"Formatting basic expressions {formatting_tuple.0} and {formatting_tuple.1}"}
|
||||||
h1 {"Formatting without interpolation " formatting_tuple.0 "and" formatting_tuple.1 }
|
h1 {"Formatting without interpolation " {formatting_tuple.0} "and" {formatting_tuple.1} }
|
||||||
h2 {
|
h2 {
|
||||||
"Multiple"
|
"Multiple"
|
||||||
"Text"
|
"Text"
|
||||||
@@ -94,10 +94,10 @@ fn App(cx: Scope) -> Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Expressions can be used in element position too:
|
// Expressions can be used in element position too:
|
||||||
rsx!(p { "More templating!" }),
|
{rsx!(p { "More templating!" })},
|
||||||
|
|
||||||
// Iterators
|
// Iterators
|
||||||
(0..10).map(|i| rsx!(li { "{i}" })),
|
{(0..10).map(|i| rsx!(li { "{i}" }))},
|
||||||
|
|
||||||
// Iterators within expressions
|
// Iterators within expressions
|
||||||
{
|
{
|
||||||
@@ -117,24 +117,25 @@ fn App(cx: Scope) -> Element {
|
|||||||
// Conditional rendering
|
// Conditional rendering
|
||||||
// Dioxus conditional rendering is based around None/Some. We have no special syntax for conditionals.
|
// 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
|
// You can convert a bool condition to rsx! with .then and .or
|
||||||
true.then(|| rsx!(div {})),
|
{true.then(|| rsx!(div {}))},
|
||||||
|
|
||||||
// Alternatively, you can use the "if" syntax - but both branches must be resolve to Element
|
// Alternatively, you can use the "if" syntax - but both branches must be resolve to Element
|
||||||
if false {
|
if false {
|
||||||
rsx!(h1 {"Top text"})
|
h1 {"Top text"}
|
||||||
} else {
|
} else {
|
||||||
rsx!(h1 {"Bottom text"})
|
h1 {"Bottom text"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using optionals for diverging branches
|
// Using optionals for diverging branches
|
||||||
if true {
|
// Note that since this is wrapped in curlies, it's interpreted as an expression
|
||||||
|
{if true {
|
||||||
Some(rsx!(h1 {"Top text"}))
|
Some(rsx!(h1 {"Top text"}))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}}
|
||||||
|
|
||||||
// returning "None" without a diverging branch is a bit noisy... but rare in practice
|
// returning "None" without a diverging branch is a bit noisy... but rare in practice
|
||||||
None as Option<()>,
|
{None as Option<()>},
|
||||||
|
|
||||||
// can also just use empty fragments
|
// can also just use empty fragments
|
||||||
Fragment {}
|
Fragment {}
|
||||||
@@ -169,13 +170,13 @@ fn App(cx: Scope) -> Element {
|
|||||||
|
|
||||||
// Can pass in props directly as an expression
|
// Can pass in props directly as an expression
|
||||||
{
|
{
|
||||||
let props = TallerProps {a: "hello", children: cx.render(rsx!(()))};
|
let props = TallerProps {a: "hello", children: None };
|
||||||
rsx!(Taller { ..props })
|
rsx!(Taller { ..props })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spreading can also be overridden manually
|
// Spreading can also be overridden manually
|
||||||
Taller {
|
Taller {
|
||||||
..TallerProps { a: "ballin!", children: cx.render(rsx!(()) )},
|
..TallerProps { a: "ballin!", children: None },
|
||||||
a: "not ballin!"
|
a: "not ballin!"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,16 +205,16 @@ fn App(cx: Scope) -> Element {
|
|||||||
|
|
||||||
// helper functions
|
// helper functions
|
||||||
// Anything that implements IntoVnode can be dropped directly into Rsx
|
// Anything that implements IntoVnode can be dropped directly into Rsx
|
||||||
helper(cx, "hello world!")
|
{helper(cx, "hello world!")}
|
||||||
|
|
||||||
// Strings can be supplied directly
|
// Strings can be supplied directly
|
||||||
String::from("Hello world!")
|
{String::from("Hello world!")}
|
||||||
|
|
||||||
// So can format_args
|
// So can format_args
|
||||||
format_args!("Hello {}!", "world")
|
{format_args!("Hello {}!", "world")}
|
||||||
|
|
||||||
// Or we can shell out to a helper function
|
// Or we can shell out to a helper function
|
||||||
format_dollars(10, 50)
|
{format_dollars(10, 50)}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -269,7 +270,7 @@ pub struct TallerProps<'a> {
|
|||||||
#[component]
|
#[component]
|
||||||
pub fn Taller<'a>(cx: Scope<'a, TallerProps<'a>>) -> Element {
|
pub fn Taller<'a>(cx: Scope<'a, TallerProps<'a>>) -> Element {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
&cx.props.children
|
{&cx.props.children}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ fn app(cx: Scope) -> Element {
|
|||||||
button {
|
button {
|
||||||
onclick: move |_| {
|
onclick: move |_| {
|
||||||
if let Some(header) = header_element.read().as_ref() {
|
if let Some(header) = header_element.read().as_ref() {
|
||||||
header.scroll_to(ScrollBehavior::Smooth);
|
_ = header.scroll_to(ScrollBehavior::Smooth);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Scroll to top"
|
"Scroll to top"
|
||||||
|
|||||||
+3
-3
@@ -31,7 +31,7 @@ fn app(cx: Scope) -> Element {
|
|||||||
|
|
||||||
// We can do boolean operations on the current signal value
|
// We can do boolean operations on the current signal value
|
||||||
if count.value() > 5 {
|
if count.value() > 5 {
|
||||||
rsx!{ h2 { "High five!" } }
|
h2 { "High five!" }
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can cleanly map signals with iterators
|
// We can cleanly map signals with iterators
|
||||||
@@ -41,9 +41,9 @@ fn app(cx: Scope) -> Element {
|
|||||||
|
|
||||||
// We can also use the signal value as a slice
|
// We can also use the signal value as a slice
|
||||||
if let [ref first, .., ref last] = saved_values.read().as_slice() {
|
if let [ref first, .., ref last] = saved_values.read().as_slice() {
|
||||||
rsx! { li { "First and last: {first}, {last}" } }
|
li { "First and last: {first}, {last}" }
|
||||||
} else {
|
} else {
|
||||||
rsx! { "No saved values" }
|
"No saved values"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -8,17 +8,17 @@ fn app(cx: Scope) -> Element {
|
|||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
div {
|
div {
|
||||||
// Use Map directly to lazily pull elements
|
// Use Map directly to lazily pull elements
|
||||||
(0..10).map(|f| rsx! { "{f}" }),
|
{(0..10).map(|f| rsx! { "{f}" })},
|
||||||
|
|
||||||
// Collect into an intermediate collection if necessary, and call into_iter
|
// Collect into an intermediate collection if necessary, and call into_iter
|
||||||
["a", "b", "c", "d", "e", "f"]
|
{["a", "b", "c", "d", "e", "f"]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|f| rsx! { "{f}" })
|
.map(|f| rsx! { "{f}" })
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.into_iter(),
|
.into_iter()},
|
||||||
|
|
||||||
// Use optionals
|
// Use optionals
|
||||||
Some(rsx! { "Some" }),
|
{Some(rsx! { "Some" })},
|
||||||
|
|
||||||
// use a for loop where the body itself is RSX
|
// use a for loop where the body itself is RSX
|
||||||
for name in 0..10 {
|
for name in 0..10 {
|
||||||
@@ -27,7 +27,7 @@ fn app(cx: Scope) -> Element {
|
|||||||
|
|
||||||
// Or even use an unterminated conditional
|
// Or even use an unterminated conditional
|
||||||
if true {
|
if true {
|
||||||
rsx!{ "hello world!" }
|
"hello world!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
|||||||
+1
-1
@@ -97,7 +97,7 @@ pub fn Die<'a>(cx: Scope<'a, DieProps<'a>>) -> Element {
|
|||||||
fill: "{fill}",
|
fill: "{fill}",
|
||||||
}
|
}
|
||||||
|
|
||||||
dots
|
{dots}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
+33
-35
@@ -52,30 +52,30 @@ pub fn app(cx: Scope<()>) -> Element {
|
|||||||
TodoHeader { todos: todos }
|
TodoHeader { todos: todos }
|
||||||
section { class: "main",
|
section { class: "main",
|
||||||
if !todos.is_empty() {
|
if !todos.is_empty() {
|
||||||
rsx! {
|
input {
|
||||||
input {
|
id: "toggle-all",
|
||||||
id: "toggle-all",
|
class: "toggle-all",
|
||||||
class: "toggle-all",
|
r#type: "checkbox",
|
||||||
r#type: "checkbox",
|
onchange: move |_| {
|
||||||
onchange: move |_| {
|
let check = active_todo_count != 0;
|
||||||
let check = active_todo_count != 0;
|
for (_, item) in todos.make_mut().iter_mut() {
|
||||||
for (_, item) in todos.make_mut().iter_mut() {
|
item.checked = check;
|
||||||
item.checked = check;
|
}
|
||||||
}
|
},
|
||||||
},
|
checked: if active_todo_count == 0 { "true" } else { "false" },
|
||||||
checked: if active_todo_count == 0 { "true" } else { "false" },
|
|
||||||
}
|
|
||||||
label { r#for: "toggle-all" }
|
|
||||||
}
|
}
|
||||||
|
label { r#for: "toggle-all" }
|
||||||
}
|
}
|
||||||
ul { class: "todo-list",
|
ul { class: "todo-list",
|
||||||
filtered_todos.iter().map(|id| rsx!(TodoEntry {
|
for id in filtered_todos.iter() {
|
||||||
key: "{id}",
|
TodoEntry {
|
||||||
id: *id,
|
key: "{id}",
|
||||||
todos: todos,
|
id: *id,
|
||||||
}))
|
todos: todos,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
(!todos.is_empty()).then(|| rsx!(
|
if !todos.is_empty() {
|
||||||
ListFooter {
|
ListFooter {
|
||||||
active_todo_count: active_todo_count,
|
active_todo_count: active_todo_count,
|
||||||
active_todo_text: active_todo_text,
|
active_todo_text: active_todo_text,
|
||||||
@@ -83,7 +83,7 @@ pub fn app(cx: Scope<()>) -> Element {
|
|||||||
todos: todos,
|
todos: todos,
|
||||||
filter: filter,
|
filter: filter,
|
||||||
}
|
}
|
||||||
))
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PageFooter {}
|
PageFooter {}
|
||||||
@@ -172,7 +172,7 @@ pub fn TodoEntry<'a>(cx: Scope<'a, TodoEntryProps<'a>>) -> Element {
|
|||||||
prevent_default: "onclick"
|
prevent_default: "onclick"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is_editing.then(|| rsx!{
|
if **is_editing {
|
||||||
input {
|
input {
|
||||||
class: "edit",
|
class: "edit",
|
||||||
value: "{todo.contents}",
|
value: "{todo.contents}",
|
||||||
@@ -186,7 +186,7 @@ pub fn TodoEntry<'a>(cx: Scope<'a, TodoEntryProps<'a>>) -> Element {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -220,29 +220,27 @@ pub fn ListFooter<'a>(cx: Scope<'a, ListFooterProps<'a>>) -> Element {
|
|||||||
}
|
}
|
||||||
ul { class: "filters",
|
ul { class: "filters",
|
||||||
for (state , state_text , url) in [
|
for (state , state_text , url) in [
|
||||||
(FilterState::All, "All", "#/"),
|
(FilterState::All, "All", "#/"),
|
||||||
(FilterState::Active, "Active", "#/active"),
|
(FilterState::Active, "Active", "#/active"),
|
||||||
(FilterState::Completed, "Completed", "#/completed"),
|
(FilterState::Completed, "Completed", "#/completed"),
|
||||||
] {
|
] {
|
||||||
li {
|
li {
|
||||||
a {
|
a {
|
||||||
href: url,
|
href: url,
|
||||||
class: selected(state),
|
class: selected(state),
|
||||||
onclick: move |_| cx.props.filter.set(state),
|
onclick: move |_| cx.props.filter.set(state),
|
||||||
prevent_default: "onclick",
|
prevent_default: "onclick",
|
||||||
state_text
|
{state_text}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if cx.props.show_clear_completed {
|
if cx.props.show_clear_completed {
|
||||||
cx.render(rsx! {
|
button {
|
||||||
button {
|
class: "clear-completed",
|
||||||
class: "clear-completed",
|
onclick: move |_| cx.props.todos.make_mut().retain(|_, todo| !todo.checked),
|
||||||
onclick: move |_| cx.props.todos.make_mut().retain(|_, todo| !todo.checked),
|
"Clear completed"
|
||||||
"Clear completed"
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use dioxus_rsx::{AttributeType, BodyNode, ElementAttrValue, ForLoop};
|
use dioxus_rsx::{AttributeType, BodyNode, ElementAttrValue, ForLoop, IfChain};
|
||||||
use proc_macro2::{LineColumn, Span};
|
use proc_macro2::{LineColumn, Span};
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, VecDeque},
|
collections::{HashMap, VecDeque},
|
||||||
fmt::{Result, Write},
|
fmt::{Result, Write},
|
||||||
};
|
};
|
||||||
use syn::{spanned::Spanned, Expr, ExprIf};
|
use syn::{spanned::Spanned, Expr};
|
||||||
|
|
||||||
use crate::buffer::Buffer;
|
use crate::buffer::Buffer;
|
||||||
use crate::ifmt_to_string;
|
use crate::ifmt_to_string;
|
||||||
@@ -231,8 +231,9 @@ impl<'a> Writer<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_if_chain(&mut self, ifchain: &ExprIf) -> std::fmt::Result {
|
fn write_if_chain(&mut self, ifchain: &IfChain) -> std::fmt::Result {
|
||||||
self.write_raw_expr(ifchain.span())
|
todo!()
|
||||||
|
// self.write_raw_expr(ifchain.span())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ fn create() {
|
|||||||
fn create_list() {
|
fn create_list() {
|
||||||
let mut dom = VirtualDom::new(|cx| {
|
let mut dom = VirtualDom::new(|cx| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
(0..3).map(|f| rsx!( div { "hello" } ))
|
{(0..3).map(|f| rsx!( div { "hello" } ))}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ fn create_components() {
|
|||||||
fn Child<'a>(cx: Scope<'a, ChildProps<'a>>) -> Element {
|
fn Child<'a>(cx: Scope<'a, ChildProps<'a>>) -> Element {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
h1 {}
|
h1 {}
|
||||||
div { &cx.props.children }
|
div { {&cx.props.children} }
|
||||||
p {}
|
p {}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -163,10 +163,10 @@ fn anchors() {
|
|||||||
let mut dom = VirtualDom::new(|cx| {
|
let mut dom = VirtualDom::new(|cx| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
if true {
|
if true {
|
||||||
rsx!( div { "hello" } )
|
div { "hello" }
|
||||||
}
|
}
|
||||||
if false {
|
if false {
|
||||||
rsx!( div { "goodbye" } )
|
div { "goodbye" }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use dioxus_core::ElementId;
|
|||||||
#[test]
|
#[test]
|
||||||
fn empty_fragment_creates_nothing() {
|
fn empty_fragment_creates_nothing() {
|
||||||
fn app(cx: Scope) -> Element {
|
fn app(cx: Scope) -> Element {
|
||||||
cx.render(rsx!(()))
|
cx.render(rsx!({ () }))
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut vdom = VirtualDom::new(app);
|
let mut vdom = VirtualDom::new(app);
|
||||||
@@ -43,18 +43,18 @@ fn fragments_nested() {
|
|||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
div { "hello" }
|
div { "hello" }
|
||||||
div { "goodbye" }
|
div { "goodbye" }
|
||||||
rsx! {
|
{rsx! {
|
||||||
div { "hello" }
|
div { "hello" }
|
||||||
div { "goodbye" }
|
div { "goodbye" }
|
||||||
rsx! {
|
{rsx! {
|
||||||
div { "hello" }
|
div { "hello" }
|
||||||
div { "goodbye" }
|
div { "goodbye" }
|
||||||
rsx! {
|
{rsx! {
|
||||||
div { "hello" }
|
div { "hello" }
|
||||||
div { "goodbye" }
|
div { "goodbye" }
|
||||||
}
|
}}
|
||||||
}
|
}}
|
||||||
}
|
}}
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ fn fragments_across_components() {
|
|||||||
let world = "world";
|
let world = "world";
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
"hellO!"
|
"hellO!"
|
||||||
world
|
{world}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ fn list_fragments() {
|
|||||||
fn app(cx: Scope) -> Element {
|
fn app(cx: Scope) -> Element {
|
||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
h1 {"hello"}
|
h1 {"hello"}
|
||||||
(0..6).map(|f| rsx!( span { "{f}" }))
|
{(0..6).map(|f| rsx!( span { "{f}" }))}
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ use dioxus_core::ElementId;
|
|||||||
fn app(cx: Scope) -> Element {
|
fn app(cx: Scope) -> Element {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
(0..3).map(|i| rsx! {
|
for i in 0..3 {
|
||||||
div {
|
div {
|
||||||
h1 { "hello world! "}
|
h1 { "hello world! "}
|
||||||
p { "{i}" }
|
p { "{i}" }
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ fn nested_passthru_creates() {
|
|||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn PassThru<'a>(cx: Scope<'a>, children: Element<'a>) -> Element {
|
fn PassThru<'a>(cx: Scope<'a>, children: Element<'a>) -> Element {
|
||||||
cx.render(rsx!(children))
|
cx.render(rsx!({ children }))
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut dom = VirtualDom::new(App);
|
let mut dom = VirtualDom::new(App);
|
||||||
@@ -60,7 +60,7 @@ fn nested_passthru_creates_add() {
|
|||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn ChildComp<'a>(cx: Scope, children: Element<'a>) -> Element {
|
fn ChildComp<'a>(cx: Scope, children: Element<'a>) -> Element {
|
||||||
cx.render(rsx! { children })
|
cx.render(rsx! { {children} })
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut dom = VirtualDom::new(App);
|
let mut dom = VirtualDom::new(App);
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ fn component_swap() {
|
|||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
h1 {
|
h1 {
|
||||||
"NavBar"
|
"NavBar"
|
||||||
(0..3).map(|_| rsx!(nav_link {}))
|
{(0..3).map(|_| rsx!(nav_link {}))}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ fn keyed_diffing_out_of_order() {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
cx.render(rsx!({ order.iter().map(|i| rsx!(div { key: "{i}" })) }))
|
||||||
});
|
});
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -59,7 +59,7 @@ fn keyed_diffing_out_of_order_adds() {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
cx.render(rsx!({ order.iter().map(|i| rsx!(div { key: "{i}" })) }))
|
||||||
});
|
});
|
||||||
|
|
||||||
_ = dom.rebuild();
|
_ = dom.rebuild();
|
||||||
@@ -85,7 +85,7 @@ fn keyed_diffing_out_of_order_adds_3() {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
cx.render(rsx!({ order.iter().map(|i| rsx!(div { key: "{i}" })) }))
|
||||||
});
|
});
|
||||||
|
|
||||||
_ = dom.rebuild();
|
_ = dom.rebuild();
|
||||||
@@ -111,7 +111,7 @@ fn keyed_diffing_out_of_order_adds_4() {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
cx.render(rsx!({ order.iter().map(|i| rsx!(div { key: "{i}" })) }))
|
||||||
});
|
});
|
||||||
|
|
||||||
_ = dom.rebuild();
|
_ = dom.rebuild();
|
||||||
@@ -137,7 +137,7 @@ fn keyed_diffing_out_of_order_adds_5() {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
cx.render(rsx!({ order.iter().map(|i| rsx!(div { key: "{i}" })) }))
|
||||||
});
|
});
|
||||||
|
|
||||||
_ = dom.rebuild();
|
_ = dom.rebuild();
|
||||||
@@ -162,7 +162,7 @@ fn keyed_diffing_additions() {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
cx.render(rsx!({ order.iter().map(|i| rsx!(div { key: "{i}" })) }))
|
||||||
});
|
});
|
||||||
|
|
||||||
_ = dom.rebuild();
|
_ = dom.rebuild();
|
||||||
@@ -187,7 +187,7 @@ fn keyed_diffing_additions_and_moves_on_ends() {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
cx.render(rsx!({ order.iter().map(|i| rsx!(div { key: "{i}" })) }))
|
||||||
});
|
});
|
||||||
|
|
||||||
_ = dom.rebuild();
|
_ = dom.rebuild();
|
||||||
@@ -216,7 +216,7 @@ fn keyed_diffing_additions_and_moves_in_middle() {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
cx.render(rsx!({ order.iter().map(|i| rsx!(div { key: "{i}" })) }))
|
||||||
});
|
});
|
||||||
|
|
||||||
_ = dom.rebuild();
|
_ = dom.rebuild();
|
||||||
@@ -250,7 +250,7 @@ fn controlled_keyed_diffing_out_of_order() {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
cx.render(rsx!({ order.iter().map(|i| rsx!(div { key: "{i}" })) }))
|
||||||
});
|
});
|
||||||
|
|
||||||
_ = dom.rebuild();
|
_ = dom.rebuild();
|
||||||
@@ -284,7 +284,7 @@ fn controlled_keyed_diffing_out_of_order_max_test() {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
cx.render(rsx!({ order.iter().map(|i| rsx!(div { key: "{i}" })) }))
|
||||||
});
|
});
|
||||||
|
|
||||||
_ = dom.rebuild();
|
_ = dom.rebuild();
|
||||||
@@ -313,7 +313,7 @@ fn remove_list() {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
cx.render(rsx!({ order.iter().map(|i| rsx!(div { key: "{i}" })) }))
|
||||||
});
|
});
|
||||||
|
|
||||||
_ = dom.rebuild();
|
_ = dom.rebuild();
|
||||||
@@ -338,7 +338,7 @@ fn no_common_keys() {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.render(rsx!(order.iter().map(|i| rsx!(div { key: "{i}" }))))
|
cx.render(rsx!({ order.iter().map(|i| rsx!(div { key: "{i}" })) }))
|
||||||
});
|
});
|
||||||
|
|
||||||
_ = dom.rebuild();
|
_ = dom.rebuild();
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ fn list_creates_one_by_one() {
|
|||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
(0..gen).map(|i| rsx! {
|
for i in 0..gen {
|
||||||
div { "{i}" }
|
div { "{i}" }
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@@ -78,9 +78,9 @@ fn removes_one_by_one() {
|
|||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
(0..gen).map(|i| rsx! {
|
for i in 0..gen {
|
||||||
div { "{i}" }
|
div { "{i}" }
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@@ -153,10 +153,10 @@ fn list_shrink_multiroot() {
|
|||||||
let mut dom = VirtualDom::new(|cx| {
|
let mut dom = VirtualDom::new(|cx| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
(0..cx.generation()).map(|i| rsx! {
|
for i in 0..cx.generation() {
|
||||||
div { "{i}" }
|
div { "{i}" }
|
||||||
div { "{i}" }
|
div { "{i}" }
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@@ -214,10 +214,10 @@ fn removes_one_by_one_multiroot() {
|
|||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
(0..gen).map(|i| rsx! {
|
{(0..gen).map(|i| rsx! {
|
||||||
div { "{i}" }
|
div { "{i}" }
|
||||||
div { "{i}" }
|
div { "{i}" }
|
||||||
})
|
})}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@@ -276,9 +276,9 @@ fn removes_one_by_one_multiroot() {
|
|||||||
fn two_equal_fragments_are_equal_static() {
|
fn two_equal_fragments_are_equal_static() {
|
||||||
let mut dom = VirtualDom::new(|cx| {
|
let mut dom = VirtualDom::new(|cx| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
(0..5).map(|_| rsx! {
|
for _ in 0..5 {
|
||||||
div { "hello" }
|
div { "hello" }
|
||||||
})
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -290,9 +290,9 @@ fn two_equal_fragments_are_equal_static() {
|
|||||||
fn two_equal_fragments_are_equal() {
|
fn two_equal_fragments_are_equal() {
|
||||||
let mut dom = VirtualDom::new(|cx| {
|
let mut dom = VirtualDom::new(|cx| {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
(0..5).map(|i| rsx! {
|
for i in 0..5 {
|
||||||
div { "hello {i}" }
|
div { "hello {i}" }
|
||||||
})
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -311,7 +311,9 @@ fn remove_many() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
(0..num).map(|i| rsx! { div { "hello {i}" } })
|
for i in 0..num {
|
||||||
|
div { "hello {i}" }
|
||||||
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -58,11 +58,11 @@ fn app(cx: Scope) -> Element {
|
|||||||
*CLICKS.lock().unwrap() += 1;
|
*CLICKS.lock().unwrap() += 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
vec![
|
{vec![
|
||||||
render! {
|
render! {
|
||||||
problematic_child {}
|
problematic_child {}
|
||||||
}
|
}
|
||||||
].into_iter()
|
].into_iter()}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ fn events_generate() {
|
|||||||
"Click me!"
|
"Click me!"
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
_ => cx.render(rsx!(())),
|
_ => None,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ fn App(cx: Scope) -> Element {
|
|||||||
}
|
}
|
||||||
button { onclick: move |_| idx -= 1, "-" }
|
button { onclick: move |_| idx -= 1, "-" }
|
||||||
ul {
|
ul {
|
||||||
(0..**idx).map(|i| rsx! {
|
{(0..**idx).map(|i| rsx! {
|
||||||
ChildExample { i: i, onhover: onhover }
|
ChildExample { i: i, onhover: onhover }
|
||||||
})
|
})}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ fn test_memory_leak() {
|
|||||||
cx.spawn(async {});
|
cx.spawn(async {});
|
||||||
|
|
||||||
if val == 2 || val == 4 {
|
if val == 2 || val == 4 {
|
||||||
return cx.render(rsx!(()));
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = cx.use_hook(|| String::from("numbers: "));
|
let name = cx.use_hook(|| String::from("numbers: "));
|
||||||
@@ -73,7 +73,7 @@ fn memo_works_properly() {
|
|||||||
let val = cx.generation();
|
let val = cx.generation();
|
||||||
|
|
||||||
if val == 2 || val == 4 {
|
if val == 2 || val == 4 {
|
||||||
return cx.render(rsx!(()));
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = cx.use_hook(|| String::from("asd"));
|
let name = cx.use_hook(|| String::from("asd"));
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ async fn it_works() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.render(rsx!(()))
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut dom = VirtualDom::new(app);
|
let mut dom = VirtualDom::new(app);
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ fn check_html_renders(cx: Scope) -> Element {
|
|||||||
h1 {
|
h1 {
|
||||||
"text"
|
"text"
|
||||||
}
|
}
|
||||||
dyn_element
|
{dyn_element}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ fn app(cx: Scope) -> Element {
|
|||||||
|
|
||||||
"Hover, click, type or scroll to see the info down below"
|
"Hover, click, type or scroll to see the info down below"
|
||||||
}
|
}
|
||||||
div { width: "80%", height: "50%", flex_direction: "column", events_rendered }
|
div { width: "80%", height: "50%", flex_direction: "column", {events_rendered} }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -27,26 +27,25 @@ fn Button(cx: Scope<ButtonProps>) -> Element {
|
|||||||
height: "100%",
|
height: "100%",
|
||||||
background_color: "{color}",
|
background_color: "{color}",
|
||||||
tabindex: "{cx.props.layer}",
|
tabindex: "{cx.props.layer}",
|
||||||
onkeydown: |e| {
|
onkeydown: move |e| {
|
||||||
if let Code::Space = e.inner().code() {
|
if let Code::Space = e.inner().code() {
|
||||||
toggle.modify(|f| !f);
|
toggle.modify(|f| !f);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onclick: |_| {
|
onclick: move |_| {
|
||||||
toggle.modify(|f| !f);
|
toggle.modify(|f| !f);
|
||||||
},
|
},
|
||||||
onmouseenter: |_|{
|
onmouseenter: move |_| {
|
||||||
hovered.set(true);
|
hovered.set(true);
|
||||||
},
|
},
|
||||||
onmouseleave: |_|{
|
onmouseleave: move |_|{
|
||||||
hovered.set(false);
|
hovered.set(false);
|
||||||
},
|
},
|
||||||
justify_content: "center",
|
justify_content: "center",
|
||||||
align_items: "center",
|
align_items: "center",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flex_direction: "column",
|
flex_direction: "column",
|
||||||
|
p{ "tabindex: {cx.props.layer}" }
|
||||||
p{"tabindex: {cx.props.layer}"}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -58,37 +57,28 @@ fn app(cx: Scope) -> Element {
|
|||||||
flex_direction: "column",
|
flex_direction: "column",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
|
for y in 1..8 {
|
||||||
(1..8).map(|y|
|
div {
|
||||||
rsx!{
|
display: "flex",
|
||||||
div{
|
flex_direction: "row",
|
||||||
display: "flex",
|
width: "100%",
|
||||||
flex_direction: "row",
|
height: "100%",
|
||||||
width: "100%",
|
for x in 1..8 {
|
||||||
height: "100%",
|
if (x + y) % 2 == 0 {
|
||||||
(1..8).map(|x|{
|
div {
|
||||||
if (x + y) % 2 == 0{
|
width: "100%",
|
||||||
rsx!{
|
height: "100%",
|
||||||
div{
|
background_color: "rgb(100, 100, 100)",
|
||||||
width: "100%",
|
|
||||||
height: "100%",
|
|
||||||
background_color: "rgb(100, 100, 100)",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else{
|
} else {
|
||||||
let layer = (x + y) % 3;
|
Button {
|
||||||
rsx!{
|
color_offset: x * y,
|
||||||
Button{
|
layer: ((x + y) % 3) as u16,
|
||||||
color_offset: x * y,
|
|
||||||
layer: layer as u16,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -14,32 +14,25 @@ fn app(cx: Scope) -> Element {
|
|||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
flex_direction: "column",
|
flex_direction: "column",
|
||||||
(0..=steps).map(|x|
|
for x in 0..=steps {
|
||||||
{
|
div { width: "100%", height: "100%", flex_direction: "row",
|
||||||
let hue = x as f32*360.0/steps as f32;
|
for y in 0..=steps {
|
||||||
rsx! {
|
{
|
||||||
div{
|
let hue = x as f32*360.0/steps as f32;
|
||||||
width: "100%",
|
let alpha = y as f32*100.0/steps as f32;
|
||||||
height: "100%",
|
rsx! {
|
||||||
flex_direction: "row",
|
div {
|
||||||
(0..=steps).map(|y|
|
left: "{x}px",
|
||||||
{
|
top: "{y}px",
|
||||||
let alpha = y as f32*100.0/steps as f32;
|
width: "10%",
|
||||||
rsx! {
|
height: "100%",
|
||||||
div {
|
background_color: "hsl({hue}, 100%, 50%, {alpha}%)",
|
||||||
left: "{x}px",
|
|
||||||
top: "{y}px",
|
|
||||||
width: "10%",
|
|
||||||
height: "100%",
|
|
||||||
background_color: "hsl({hue}, 100%, 50%, {alpha}%)",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -19,9 +19,9 @@ fn app(cx: Scope) -> Element {
|
|||||||
ul {
|
ul {
|
||||||
flex_direction: "column",
|
flex_direction: "column",
|
||||||
padding_left: "3px",
|
padding_left: "3px",
|
||||||
(0..10).map(|i| rsx!(
|
for i in 0..10 {
|
||||||
"> hello {i}"
|
"> hello {i}"
|
||||||
))
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -71,32 +71,28 @@ fn Grid(cx: Scope<GridProps>) -> Element {
|
|||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
flex_direction: "column",
|
flex_direction: "column",
|
||||||
(0..size).map(|x|
|
for x in 0..size {
|
||||||
{
|
div{
|
||||||
rsx! {
|
width: "100%",
|
||||||
div{
|
height: "100%",
|
||||||
width: "100%",
|
flex_direction: "row",
|
||||||
height: "100%",
|
for y in 0..size {
|
||||||
flex_direction: "row",
|
{
|
||||||
(0..size).map(|y|
|
let alpha = y as f32*100.0/size as f32 + counts.read()[x*size + y] as f32;
|
||||||
{
|
let key = format!("{}-{}", x, y);
|
||||||
let alpha = y as f32*100.0/size as f32 + counts.read()[x*size + y] as f32;
|
rsx! {
|
||||||
let key = format!("{}-{}", x, y);
|
Box {
|
||||||
rsx! {
|
x: x,
|
||||||
Box {
|
y: y,
|
||||||
x: x,
|
alpha: 100.0,
|
||||||
y: y,
|
hue: alpha,
|
||||||
alpha: 100.0,
|
key: "{key}",
|
||||||
hue: alpha,
|
|
||||||
key: "{key}",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,12 @@ fn app(cx: Scope) -> Element {
|
|||||||
cx.render(rsx! (
|
cx.render(rsx! (
|
||||||
table {
|
table {
|
||||||
tbody {
|
tbody {
|
||||||
(0..10_000_usize).map(|f| {
|
for f in 0..10_000_usize {
|
||||||
let label = Label::new(&mut rng);
|
table_row {
|
||||||
rsx!( table_row { row_id: f, label: label } )
|
row_id: f,
|
||||||
})
|
label: Label::new(&mut rng)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -306,15 +306,10 @@ fn persist_removes() {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
render!(
|
render!(
|
||||||
div{
|
div {
|
||||||
(0..children).map(|i|{
|
for i in 0..children {
|
||||||
rsx!{
|
p { key: "{i}", "{i}" }
|
||||||
p{
|
}
|
||||||
key: "{i}",
|
|
||||||
"{i}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -387,15 +382,10 @@ fn persist_instertions_before() {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
render!(
|
render!(
|
||||||
div{
|
div {
|
||||||
(0..children).map(|i|{
|
for i in 0..children {
|
||||||
rsx!{
|
p { key: "{i}", "{i}" }
|
||||||
p{
|
}
|
||||||
key: "{i}",
|
|
||||||
"{i}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -446,14 +436,9 @@ fn persist_instertions_after() {
|
|||||||
};
|
};
|
||||||
render!(
|
render!(
|
||||||
div{
|
div{
|
||||||
(0..children).map(|i|{
|
for i in 0..children {
|
||||||
rsx!{
|
p { key: "{i}", "{i}" }
|
||||||
p{
|
}
|
||||||
key: "{i}",
|
|
||||||
"{i}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ fn Route1(cx: Scope, user_id: usize, dynamic: usize, query: String, extra: Strin
|
|||||||
fn Route2(cx: Scope, user_id: usize) -> Element {
|
fn Route2(cx: Scope, user_id: usize) -> Element {
|
||||||
render! {
|
render! {
|
||||||
pre { "Route2{{\n\tuser_id:{user_id}\n}}" }
|
pre { "Route2{{\n\tuser_id:{user_id}\n}}" }
|
||||||
(0..*user_id).map(|i| rsx!{ p { "{i}" } }),
|
{(0..*user_id).map(|i| rsx!{ p { "{i}" } })},
|
||||||
p { "Footer" }
|
p { "Footer" }
|
||||||
Link {
|
Link {
|
||||||
to: Route::Route3 {
|
to: Route::Route3 {
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ pub fn GoBackButton<'a>(cx: Scope<'a, HistoryButtonProps<'a>>) -> Element {
|
|||||||
disabled: "{disabled}",
|
disabled: "{disabled}",
|
||||||
prevent_default: "onclick",
|
prevent_default: "onclick",
|
||||||
onclick: move |_| router.go_back(),
|
onclick: move |_| router.go_back(),
|
||||||
children
|
{children}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,7 +149,7 @@ pub fn GoForwardButton<'a>(cx: Scope<'a, HistoryButtonProps<'a>>) -> Element {
|
|||||||
disabled: "{disabled}",
|
disabled: "{disabled}",
|
||||||
prevent_default: "onclick",
|
prevent_default: "onclick",
|
||||||
onclick: move |_| router.go_forward(),
|
onclick: move |_| router.go_forward(),
|
||||||
children
|
{children}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -250,7 +250,7 @@ pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element {
|
|||||||
id: "{id}",
|
id: "{id}",
|
||||||
rel: "{rel}",
|
rel: "{rel}",
|
||||||
target: "{tag_target}",
|
target: "{tag_target}",
|
||||||
children
|
{children}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+115
-66
@@ -6,7 +6,8 @@ use syn::{
|
|||||||
braced,
|
braced,
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
spanned::Spanned,
|
spanned::Spanned,
|
||||||
token, Expr, ExprIf, LitStr, Pat, Result,
|
token::{self, Brace},
|
||||||
|
Expr, ExprIf, LitStr, Pat, Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -15,14 +16,14 @@ Parse
|
|||||||
-> Component {}
|
-> Component {}
|
||||||
-> component()
|
-> component()
|
||||||
-> "text {with_args}"
|
-> "text {with_args}"
|
||||||
-> (0..10).map(|f| rsx!("asd")), // <--- notice the comma - must be a complete expr
|
-> {(0..10).map(|f| rsx!("asd"))} // <--- notice the curly braces
|
||||||
*/
|
*/
|
||||||
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
||||||
pub enum BodyNode {
|
pub enum BodyNode {
|
||||||
Element(Element),
|
Element(Element),
|
||||||
Component(Component),
|
Component(Component),
|
||||||
ForLoop(ForLoop),
|
ForLoop(ForLoop),
|
||||||
IfChain(ExprIf),
|
IfChain(IfChain),
|
||||||
Text(IfmtInput),
|
Text(IfmtInput),
|
||||||
RawExpr(Expr),
|
RawExpr(Expr),
|
||||||
}
|
}
|
||||||
@@ -112,7 +113,27 @@ impl Parse for BodyNode {
|
|||||||
return Ok(BodyNode::IfChain(stream.parse()?));
|
return Ok(BodyNode::IfChain(stream.parse()?));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(BodyNode::RawExpr(stream.parse::<Expr>()?))
|
// Match statements are special but have no special arm syntax
|
||||||
|
// we could allow arm syntax if we wanted
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// match {
|
||||||
|
// val => div {}
|
||||||
|
// other_val => div {}
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
if stream.peek(Token![match]) {
|
||||||
|
return Ok(BodyNode::RawExpr(stream.parse::<Expr>()?));
|
||||||
|
}
|
||||||
|
|
||||||
|
if stream.peek(token::Brace) {
|
||||||
|
return Ok(BodyNode::RawExpr(stream.parse::<Expr>()?));
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(syn::Error::new(
|
||||||
|
stream.span(),
|
||||||
|
"Expected a valid body node.\nExpressions must be wrapped in curly braces.",
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,71 +172,52 @@ impl ToTokens for BodyNode {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
BodyNode::IfChain(chain) => {
|
BodyNode::IfChain(chain) => {
|
||||||
if is_if_chain_terminated(chain) {
|
let mut body = TokenStream2::new();
|
||||||
tokens.append_all(quote! {
|
let mut terminated = false;
|
||||||
{
|
|
||||||
let ___nodes = (#chain).into_dyn_node(__cx);
|
let mut elif = Some(chain);
|
||||||
___nodes
|
|
||||||
}
|
while let Some(chain) = elif {
|
||||||
});
|
let IfChain {
|
||||||
} else {
|
if_token,
|
||||||
let ExprIf {
|
|
||||||
cond,
|
cond,
|
||||||
then_branch,
|
then_branch,
|
||||||
|
else_if_branch,
|
||||||
else_branch,
|
else_branch,
|
||||||
..
|
|
||||||
} = chain;
|
} = chain;
|
||||||
|
|
||||||
let mut body = TokenStream2::new();
|
let mut renderer: TemplateRenderer = TemplateRenderer {
|
||||||
|
roots: then_branch,
|
||||||
|
location: None,
|
||||||
|
};
|
||||||
|
|
||||||
body.append_all(quote! {
|
body.append_all(quote! { #if_token #cond { Some({#renderer}) } });
|
||||||
if #cond {
|
|
||||||
Some(#then_branch)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut elif = else_branch;
|
if let Some(next) = else_if_branch {
|
||||||
|
body.append_all(quote! { else });
|
||||||
while let Some((_, ref branch)) = elif {
|
elif = Some(next);
|
||||||
match branch.as_ref() {
|
} else if let Some(else_branch) = else_branch {
|
||||||
Expr::If(ref eelif) => {
|
renderer.roots = else_branch;
|
||||||
let ExprIf {
|
body.append_all(quote! { else { Some({#renderer}) } });
|
||||||
cond,
|
terminated = true;
|
||||||
then_branch,
|
break;
|
||||||
else_branch,
|
} else {
|
||||||
..
|
elif = None;
|
||||||
} = eelif;
|
|
||||||
|
|
||||||
body.append_all(quote! {
|
|
||||||
else if #cond {
|
|
||||||
Some(#then_branch)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
elif = else_branch;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
body.append_all(quote! {
|
|
||||||
else {
|
|
||||||
#branch
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !terminated {
|
||||||
body.append_all(quote! {
|
body.append_all(quote! {
|
||||||
else { None }
|
else { None }
|
||||||
});
|
});
|
||||||
|
|
||||||
tokens.append_all(quote! {
|
|
||||||
{
|
|
||||||
let ___nodes = (#body).into_dyn_node(__cx);
|
|
||||||
___nodes
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tokens.append_all(quote! {
|
||||||
|
{
|
||||||
|
let ___nodes = (#body).into_dyn_node(__cx);
|
||||||
|
___nodes
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,26 +242,73 @@ impl Parse for ForLoop {
|
|||||||
let in_token: Token![in] = input.parse()?;
|
let in_token: Token![in] = input.parse()?;
|
||||||
let expr: Expr = input.call(Expr::parse_without_eager_brace)?;
|
let expr: Expr = input.call(Expr::parse_without_eager_brace)?;
|
||||||
|
|
||||||
let content;
|
let (brace_token, body) = parse_buffer_as_braced_children(input)?;
|
||||||
let brace_token = braced!(content in input);
|
|
||||||
|
|
||||||
let mut children = vec![];
|
|
||||||
|
|
||||||
while !content.is_empty() {
|
|
||||||
children.push(content.parse()?);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
for_token,
|
for_token,
|
||||||
pat,
|
pat,
|
||||||
in_token,
|
in_token,
|
||||||
body: children,
|
body,
|
||||||
expr: Box::new(expr),
|
|
||||||
brace_token,
|
brace_token,
|
||||||
|
expr: Box::new(expr),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
||||||
|
pub struct IfChain {
|
||||||
|
pub if_token: Token![if],
|
||||||
|
pub cond: Box<Expr>,
|
||||||
|
pub then_branch: Vec<BodyNode>,
|
||||||
|
pub else_if_branch: Option<Box<IfChain>>,
|
||||||
|
pub else_branch: Option<Vec<BodyNode>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for IfChain {
|
||||||
|
fn parse(input: ParseStream) -> Result<Self> {
|
||||||
|
let if_token: Token![if] = input.parse()?;
|
||||||
|
|
||||||
|
// stolen from ExprIf
|
||||||
|
let cond = Box::new(input.call(Expr::parse_without_eager_brace)?);
|
||||||
|
|
||||||
|
let (_, then_branch) = parse_buffer_as_braced_children(input)?;
|
||||||
|
|
||||||
|
let mut else_branch = None;
|
||||||
|
let mut else_if_branch = None;
|
||||||
|
|
||||||
|
// if the next token is `else`, set the else branch as the next if chain
|
||||||
|
if input.peek(Token![else]) {
|
||||||
|
input.parse::<Token![else]>()?;
|
||||||
|
if input.peek(Token![if]) {
|
||||||
|
else_if_branch = Some(Box::new(input.parse::<IfChain>()?));
|
||||||
|
} else {
|
||||||
|
let (_, else_branch_nodes) = parse_buffer_as_braced_children(input)?;
|
||||||
|
else_branch = Some(else_branch_nodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
cond,
|
||||||
|
if_token,
|
||||||
|
then_branch,
|
||||||
|
else_if_branch,
|
||||||
|
else_branch,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_buffer_as_braced_children(
|
||||||
|
input: &syn::parse::ParseBuffer<'_>,
|
||||||
|
) -> Result<(Brace, Vec<BodyNode>)> {
|
||||||
|
let content;
|
||||||
|
let brace_token = braced!(content in input);
|
||||||
|
let mut then_branch = vec![];
|
||||||
|
while !content.is_empty() {
|
||||||
|
then_branch.push(content.parse()?);
|
||||||
|
}
|
||||||
|
Ok((brace_token, then_branch))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn is_if_chain_terminated(chain: &ExprIf) -> bool {
|
pub(crate) fn is_if_chain_terminated(chain: &ExprIf) -> bool {
|
||||||
let mut current = chain;
|
let mut current = chain;
|
||||||
loop {
|
loop {
|
||||||
|
|||||||
@@ -242,7 +242,9 @@ fn to_string_works() {
|
|||||||
div {}
|
div {}
|
||||||
div { "nest 2" }
|
div { "nest 2" }
|
||||||
"{dyn2}"
|
"{dyn2}"
|
||||||
(0..5).map(|i| rsx! { div { "finalize {i}" } })
|
for i in (0..5) {
|
||||||
|
div { "finalize {i}" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ fn text_nodes() {
|
|||||||
fn app(cx: Scope) -> Element {
|
fn app(cx: Scope) -> Element {
|
||||||
let dynamic_text = "hello";
|
let dynamic_text = "hello";
|
||||||
render! {
|
render! {
|
||||||
div { dynamic_text }
|
div { {dynamic_text} }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ fn components_hydrate() {
|
|||||||
fn Child2(cx: Scope) -> Element {
|
fn Child2(cx: Scope) -> Element {
|
||||||
let dyn_text = "hello";
|
let dyn_text = "hello";
|
||||||
render! {
|
render! {
|
||||||
div { dyn_text }
|
div { {dyn_text} }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,11 +159,7 @@ fn components_hydrate() {
|
|||||||
fn Child4(cx: Scope) -> Element {
|
fn Child4(cx: Scope) -> Element {
|
||||||
render! {
|
render! {
|
||||||
for _ in 0..2 {
|
for _ in 0..2 {
|
||||||
render! {
|
{render! { "{1}" }}
|
||||||
render! {
|
|
||||||
"{1}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ fn lists() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
dioxus_ssr::render_lazy(rsx! {
|
dioxus_ssr::render_lazy(rsx! {
|
||||||
ul {
|
ul {
|
||||||
(0..5).map(|i| rsx! {
|
for i in 0..5 {
|
||||||
li { "item {i}" }
|
li { "item {i}" }
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
"<ul><li>item 0</li><li>item 1</li><li>item 2</li><li>item 3</li><li>item 4</li></ul>"
|
"<ul><li>item 0</li><li>item 1</li><li>item 2</li><li>item 3</li><li>item 4</li></ul>"
|
||||||
@@ -53,9 +53,9 @@ fn components() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
dioxus_ssr::render_lazy(rsx! {
|
dioxus_ssr::render_lazy(rsx! {
|
||||||
div {
|
div {
|
||||||
(0..5).map(|name| rsx! {
|
for name in 0..5 {
|
||||||
MyComponent { name: name }
|
MyComponent { name: name }
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
"<div><div>component 0</div><div>component 1</div><div>component 2</div><div>component 3</div><div>component 4</div></div>"
|
"<div><div>component 0</div><div>component 1</div><div>component 2</div><div>component 3</div><div>component 4</div></div>"
|
||||||
@@ -67,7 +67,9 @@ fn fragments() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
dioxus_ssr::render_lazy(rsx! {
|
dioxus_ssr::render_lazy(rsx! {
|
||||||
div {
|
div {
|
||||||
(0..5).map(|_| rsx! (()))
|
for _ in 0..5 {
|
||||||
|
{()}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
"<div></div>"
|
"<div></div>"
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ fn app(cx: Scope) -> Element {
|
|||||||
"asd"
|
"asd"
|
||||||
Bapp {}
|
Bapp {}
|
||||||
}
|
}
|
||||||
(0..10).map(|f| rsx!{
|
{(0..10).map(|f| rsx!{
|
||||||
div {
|
div {
|
||||||
"thing {f}"
|
"thing {f}"
|
||||||
}
|
}
|
||||||
})
|
})}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,11 @@ fn app(cx: Scope) -> Element {
|
|||||||
start();
|
start();
|
||||||
*count.write() += 1;
|
*count.write() += 1;
|
||||||
},
|
},
|
||||||
// format is needed as {count} does not seemed to work in `if` within content
|
if **started {
|
||||||
if **started { format!("Current score: {}", count.write()) } else { "Start".to_string() }
|
"Current score: {count.read()}"
|
||||||
|
} else {
|
||||||
|
"Start"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ fn rehydrates() {
|
|||||||
},
|
},
|
||||||
"listener test"
|
"listener test"
|
||||||
}
|
}
|
||||||
false.then(|| rsx!{ "hello" })
|
{false.then(|| rsx!{ "hello" })}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user