Skip to content

Commit 0652a43

Browse files
committed
Added spread operator in dom! macro
1 parent 2cd7f76 commit 0652a43

File tree

5 files changed

+61
-12
lines changed

5 files changed

+61
-12
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
* Enums nad newtypes support in `AutoJsJson`
1212
* `bind!` macro now accepts namespaced variables, f. ex. `bind!(state.value, || value + 100)`
1313
* Components now accept value without attribute name if the names matches (`color={color}``{color}`)
14+
* In `dom!` macro `..` operator now spreads iterable into children (`<ul>{..items}</ul>`)
1415

1516
### Changed
1617

crates/vertigo-macro/src/html_parser.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use proc_macro::TokenStream;
22
use proc_macro2::{Span, TokenStream as TokenStream2};
3-
use quote::quote;
4-
use syn::{Expr, __private::ToTokens};
3+
use quote::{quote, ToTokens};
4+
use syn::Expr;
55
use syn_rsx::{parse, Node, NodeType};
66

77
pub(crate) fn dom_inner(input: TokenStream) -> TokenStream {
@@ -301,10 +301,22 @@ fn convert_node(node: Node, convert_to_dom_node: bool) -> TokenStream2 {
301301
let Some(block) = extract_value(child, parent_span) else {
302302
continue;
303303
};
304-
305-
out_child.push(quote! {
306-
.child(vertigo::EmbedDom::embed(#block))
307-
});
304+
let block_str = block.to_string();
305+
if block_str.starts_with("..") {
306+
let value: TokenStream2 = block.into_iter().skip(2).collect();
307+
out_child.push(quote! {
308+
.children(
309+
#value
310+
.into_iter()
311+
.map(|item| vertigo::EmbedDom::embed(item))
312+
.collect::<Vec<_>>()
313+
)
314+
});
315+
} else {
316+
out_child.push(quote! {
317+
.child(vertigo::EmbedDom::embed(#block))
318+
});
319+
}
308320
}
309321
node_type => {
310322
emit_error!(
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use crate::dom;
2+
use crate::{self as vertigo, DomNode};
3+
4+
#[test]
5+
fn children_from_iter() {
6+
let list = (0..10)
7+
.map(|i| dom! { <li>{i}</li> });
8+
9+
let node = dom! {
10+
<ul>
11+
"Children: "
12+
{..list}
13+
</ul>
14+
};
15+
16+
let DomNode::Node { node } = node else {
17+
panic!("Expected DomNode::Node")
18+
};
19+
20+
assert_eq!(node.get_children().len(), 11);
21+
}
22+
23+
#[test]
24+
fn children_from_iter_inline() {
25+
let node = dom! {
26+
<ul>
27+
"Children: "
28+
{..(0..10).map(|i| dom! { <li>{i}</li> })}
29+
</ul>
30+
};
31+
32+
let DomNode::Node { node } = node else {
33+
panic!("Expected DomNode::Node")
34+
};
35+
36+
assert_eq!(node.get_children().len(), 11);
37+
}

crates/vertigo/src/tests/dom/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
mod component;
2+
mod list_spread;
23
mod params;

demo/app/src/app/js_api_access/mod.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use vertigo::{bind, component, css, document, dom, dom_element, window, JsValue, Value};
1+
use vertigo::{bind, component, css, document, dom, window, JsValue, Value};
22

33
#[derive(Default, PartialEq)]
44
pub struct State {
@@ -12,10 +12,8 @@ pub fn JsApiAccess() {
1212
let container_css = css!{"
1313
"};
1414

15-
let items = dom_element!{ <ol /> }
16-
.children(
17-
(1..201).map(|i| dom! { <li>"List item" {i}</li> }).collect()
18-
);
15+
let items = (1..201)
16+
.map(|i| dom! { <li>"List item" {i}</li> });
1917

2018
let to_bottom = || {
2119
let max_y = window!("scrollMaxY");
@@ -53,7 +51,7 @@ pub fn JsApiAccess() {
5351
<button on_click={ask}>"Ask"</button>
5452
" Answer: " {state.answer}
5553
</p>
56-
{items}
54+
<ol>{..items}</ol>
5755
<button on_click={|| { window!("scrollTo()", 0, 0); }}>"to top"</button>
5856
</div>
5957
}

0 commit comments

Comments
 (0)