Breaking change: the builder macros now use method call syntax rather than function call syntax

This commit is contained in:
Pauan 2018-07-14 13:26:52 -10:00
parent 4c0368fd9f
commit 34709737c8
6 changed files with 134 additions and 318 deletions

View File

@ -24,8 +24,8 @@ fn make_animated_box(value: u32, broadcaster: AnimatedMapBroadcaster) -> Dom {
let high: f64 = (value + 60) as f64;
html!("div", {
future(animation.signal().for_each(clone!(animation => move |x| {
let x: f64= x.into();
.future(animation.signal().for_each(clone!(animation => move |x| {
let x: f64 = x.into_f64();
if x == 0.0 {
animation.animate_to(Percentage::new(1.0));
@ -35,58 +35,58 @@ fn make_animated_box(value: u32, broadcaster: AnimatedMapBroadcaster) -> Dom {
}
Ok(())
})));
})))
event(clone!(hover_animation => move |_: MouseOverEvent| {
.event(clone!(hover_animation => move |_: MouseOverEvent| {
hover_animation.animate_to(Percentage::new(1.0));
}));
}))
event(clone!(hover_animation => move |_: MouseOutEvent| {
.event(clone!(hover_animation => move |_: MouseOutEvent| {
hover_animation.animate_to(Percentage::new(0.0));
}));
}))
style("border-radius", "10px");
.style("border-radius", "10px")
style_signal("width", animation.signal()
.style_signal("width", animation.signal()
.map(|t| easing::in_out(t, easing::cubic))
.map(|t| Some(format!("{}px", t.range_inclusive(167.0, 500.0)))));
.map(|t| Some(format!("{}px", t.range_inclusive(167.0, 500.0)))))
style("position", "relative");
.style("position", "relative")
style_signal("margin-left", animation.signal()
.style_signal("margin-left", animation.signal()
.map(|t| t.invert())
.map(|t| easing::in_out(t, easing::cubic))
.map(|t| Some(format!("{}px", t.range_inclusive(20.0, 0.0)))));
.map(|t| Some(format!("{}px", t.range_inclusive(20.0, 0.0)))))
style_signal("left", broadcaster.signal()
.style_signal("left", broadcaster.signal()
.map(|t| easing::in_out(t, easing::cubic))
.map(|t| Some(format!("{}px", t.range_inclusive(100.0, 0.0)))));
.map(|t| Some(format!("{}px", t.range_inclusive(100.0, 0.0)))))
style_signal("height", map_ref! {
.style_signal("height", map_ref! {
let animation = broadcaster.signal().map(|t| easing::in_out(t, easing::cubic)),
let hover = hover_animation.signal().map(|t| easing::out(t, easing::cubic)) =>
Some(format!("{}px", animation.range_inclusive(0.0, hover.range_inclusive(5.0, 15.0))))
});
})
style_signal("background-color", animation.signal()
.style_signal("background-color", animation.signal()
.map(|t| easing::in_out(t, easing::cubic))
.map(move |t| Some(format!("hsl({}, {}%, {}%)",
t.range_inclusive(low, high),
t.range_inclusive(50.0, 100.0),
t.range_inclusive(50.0, 100.0)))));
t.range_inclusive(50.0, 100.0)))))
style("border-style", "solid");
.style("border-style", "solid")
style_signal("border-width", broadcaster.signal()
.style_signal("border-width", broadcaster.signal()
.map(|t| easing::in_out(t, easing::cubic))
.map(|t| Some(format!("{}px", t.range_inclusive(0.0, 5.0)))));
.map(|t| Some(format!("{}px", t.range_inclusive(0.0, 5.0)))))
style_signal("border-color", animation.signal()
.style_signal("border-color", animation.signal()
.map(|t| easing::in_out(t, easing::cubic))
.map(move |t| Some(format!("hsl({}, {}%, {}%)",
t.range_inclusive(high, low),
t.range_inclusive(100.0, 50.0),
t.range_inclusive(100.0, 50.0)))));
t.range_inclusive(100.0, 50.0)))))
})
}
@ -144,23 +144,23 @@ fn main() {
for _ in 0..1 {
dominator::append_dom(&dominator::body(),
html!("div", {
style("display", "flex");
.style("display", "flex")
children(&mut [
.children(&mut [
html!("div", {
children_signal_vec(state.boxes.signal_vec()
.children_signal_vec(state.boxes.signal_vec()
.animated_map(2000.0, |value, t| {
make_animated_box(value, t)
}));
}))
}),
html!("div", {
children_signal_vec(state.boxes.signal_vec()
.children_signal_vec(state.boxes.signal_vec()
.animated_map(2000.0, |value, t| {
make_animated_box(value, t)
}));
}))
}),
]);
])
})
);
}

View File

@ -1,12 +0,0 @@
[package]
name = "test"
version = "0.1.0"
authors = ["Pauan <pcxunlimited@gmail.com>"]
[dependencies]
dominator = { path = "../.." }
futures-signals = "0.1.0"
[dependencies.stdweb]
version = "0.4.0"
features = ["experimental_features_which_may_break_on_minor_version_bumps"]

View File

@ -1 +0,0 @@
default-target = "wasm32-unknown-unknown"

View File

@ -1,171 +0,0 @@
#[macro_use]
extern crate stdweb;
#[macro_use]
extern crate dominator;
#[macro_use]
extern crate futures_signals;
use std::rc::Rc;
use stdweb::web::{document, HtmlElement};
use stdweb::web::event::ClickEvent;
use stdweb::web::IParentNode;
use futures_signals::signal;
use futures_signals::signal_vec;
use futures_signals::signal::Signal;
use futures_signals::signal_vec::SignalVec;
use dominator::traits::*;
use dominator::{Dom, text};
fn main() {
stylesheet!("div", {
style("border", "5px solid black");
});
let foobar = class! {
style("border-right", "10px solid purple");
};
/*let media_query = stylesheet!(format!("@media (max-width: 500px) .{}", foobar), {
style("border-left", "10px solid teal");
});*/
let mut count = 0;
let (sender_count, receiver_count) = signal::unsync::mutable(count);
let mut width: u32 = 10;
let (sender1, receiver1) = signal::unsync::mutable(width);
let (sender2, receiver2) = signal::unsync::mutable(vec![width]);
let (sender3, receiver3) = signal::unsync::mutable(vec![width]);
let (text_sender, text_receiver) = signal::unsync::mutable(format!("{}", width));
let (mut sender_elements, receiver_elements) = signal_vec::unsync::mutable();
/*let style_width = receiver1.switch(move |x| {
receiver2.clone().switch(move |y| {
receiver3.clone().map(move |z| {
Some(format!("{}px", x + y[0] + z[0]))
})
})
});*/
let style_width = map_clone! {
let x: Rc<u32> = receiver1,
let y: Rc<Vec<u32>> = receiver2,
let z: Rc<Vec<u32>> = receiver3 =>
Some(format!("{}px", *x + y[0] + z[0]))
};
let mut elements_index = 0;
let mut increment = move || {
elements_index += 1;
elements_index
};
sender_elements.push((increment(), 1));
sender_elements.push((increment(), 2));
sender_elements.push((increment(), 3));
sender_elements.push((increment(), 4));
sender_elements.push((increment(), 5));
sender_elements.push((increment(), 6));
sender_elements.push((increment(), 7));
dominator::append_dom(&document().query_selector("body").unwrap().unwrap(),
html!("div", {
style("border", "10px solid blue");
children(&mut [
text("Testing testing!!!"),
text(text_receiver.dynamic()),
text(receiver_count.map(|x| format!(" - {}", x)).dynamic()),
html!("div", {
style("width", style_width.dynamic());
style("height", "50px");
style("background-color", "green");
event(move |event: ClickEvent| {
count += 1;
width += 5;
console!(log, &event);
sender1.set(width).unwrap();
sender2.set(vec![width]).unwrap();
sender3.set(vec![width]).unwrap();
text_sender.set(format!("{}", width)).unwrap();
sender_count.set(count).unwrap();
sender_elements.push((increment(), 8));
sender_elements.push((increment(), 0));
sender_elements.push((increment(), 5));
sender_elements.push((increment(), 9));
});
children(
receiver_elements
.filter_map(|(x, y)| {
if y > 2 {
Some((x, y + 100))
} else {
None
}
})
.sort_by(|&(_, a), &(_, b)| {
a.cmp(&b).reverse()
})
.map(|(x, y)| {
html!("div", {
style("border", "5px solid red");
style("width", "100px");
style("height", "50px");
children(&mut [
text(format!("({}, {})", x, y))
]);
})
})
.dynamic()
);
}),
html!("div", {
style("width", "50px");
style("height", "50px");
style("background-color", "red");
class(&foobar, true);
children(&mut [
html!("div", {
style("width", "10px");
style("height", "10px");
style("background-color", "orange");
})
]);
}),
Dom::with_state(Rc::new(vec![1, 2, 3]), |a| {
html!("div", {
style("width", "100px");
style("height", "100px");
style("background-color", "orange");
class("foo", true);
class("bar", false);
event(clone!({ a } move |event: ClickEvent| {
console!(log, &*a, &event);
}));
})
}),
html!("input", {
focused(true);
}),
]);
})
);
}

View File

@ -129,38 +129,38 @@ fn get_checked(event: &ChangeEvent) -> bool {
#[inline]
fn simple(kind: &str, children: &mut [Dom]) -> Dom {
html!(kind, {
children(children);
.children(children)
})
}
#[inline]
fn link(href: &str, t: &str) -> Dom {
html!("a", {
attribute("href", href);
children(&mut [
.attribute("href", href)
.children(&mut [
text(t),
]);
])
})
}
fn filter_button(state: Rc<State>, kind: Filter) -> Dom {
html!("a", {
class_signal("selected", state.filter.signal()
.map(clone!(kind => move |filter| filter == kind)));
.class_signal("selected", state.filter.signal()
.map(clone!(kind => move |filter| filter == kind)))
attribute("href", match kind {
.attribute("href", match kind {
Filter::Active => "#/active",
Filter::Completed => "#/completed",
Filter::All => "#/",
});
})
children(&mut [
.children(&mut [
text(match kind {
Filter::Active => "Active",
Filter::Completed => "Completed",
Filter::All => "All",
})
]);
])
})
}
@ -179,26 +179,26 @@ fn main() {
dominator::append_dom(&body,
html!("section", {
class("todoapp");
children(&mut [
.class("todoapp")
.children(&mut [
html!("header", {
class("header");
children(&mut [
.class("header")
.children(&mut [
simple("h1", &mut [
text("todos"),
]),
html!("input", {
focused(true);
class("new-todo");
attribute("placeholder", "What needs to be done?");
.focused(true)
.class("new-todo")
.attribute("placeholder", "What needs to be done?")
property_signal("value", state.new_todo_title.signal_cloned());
.property_signal("value", state.new_todo_title.signal_cloned())
event(clone!(state => move |event: InputEvent| {
.event(clone!(state => move |event: InputEvent| {
state.new_todo_title.set_neq(get_value(&event));
}));
}))
event(clone!(state => move |event: KeyDownEvent| {
.event(clone!(state => move |event: KeyDownEvent| {
if event.key() == "Enter" {
event.prevent_default();
@ -221,32 +221,32 @@ fn main() {
state.serialize();
}
}
}));
}))
}),
]);
])
}),
html!("section", {
class("main");
.class("main")
// Hide if it doesn't have any todos.
property_signal("hidden", state.todo_list.signal_vec_cloned()
.property_signal("hidden", state.todo_list.signal_vec_cloned()
.len()
.map(|len| len == 0));
.map(|len| len == 0))
children(&mut [
.children(&mut [
html!("input", {
class("toggle-all");
attribute("id", "toggle-all");
attribute("type", "checkbox");
.class("toggle-all")
.attribute("id", "toggle-all")
.attribute("type", "checkbox")
property_signal("checked", state.todo_list.signal_vec_cloned()
.property_signal("checked", state.todo_list.signal_vec_cloned()
.map_signal(|todo| todo.completed.signal())
.filter(|completed| !completed)
.len()
.map(|len| len != 0));
.map(|len| len != 0))
event(clone!(state => move |event: ChangeEvent| {
.event(clone!(state => move |event: ChangeEvent| {
let checked = !get_checked(&event);
{
@ -258,28 +258,28 @@ fn main() {
}
state.serialize();
}));
}))
}),
html!("label", {
attribute("for", "toggle-all");
children(&mut [
.attribute("for", "toggle-all")
.children(&mut [
text("Mark all as complete"),
]);
])
}),
html!("ul", {
class("todo-list");
.class("todo-list")
children_signal_vec(state.todo_list.signal_vec_cloned()
.children_signal_vec(state.todo_list.signal_vec_cloned()
.map(clone!(state => move |todo| {
html!("li", {
class_signal("editing", todo.editing.signal_cloned()
.map(|x| x.is_some()));
.class_signal("editing", todo.editing.signal_cloned()
.map(|x| x.is_some()))
class_signal("completed", todo.completed.signal());
.class_signal("completed", todo.completed.signal())
property_signal("hidden",
.property_signal("hidden",
map_ref!(
let filter = state.filter.signal(),
let completed = todo.completed.signal() =>
@ -289,58 +289,58 @@ fn main() {
Filter::All => true,
}
)
.dedupe_map(|show| !*show));
.dedupe_map(|show| !*show))
children(&mut [
.children(&mut [
html!("div", {
class("view");
children(&mut [
.class("view")
.children(&mut [
html!("input", {
attribute("type", "checkbox");
class("toggle");
.attribute("type", "checkbox")
.class("toggle")
property_signal("checked", todo.completed.signal());
.property_signal("checked", todo.completed.signal())
event(clone!(state, todo => move |event: ChangeEvent| {
.event(clone!(state, todo => move |event: ChangeEvent| {
todo.completed.set_neq(get_checked(&event));
state.serialize();
}));
}))
}),
html!("label", {
event(clone!(todo => move |_: DoubleClickEvent| {
.event(clone!(todo => move |_: DoubleClickEvent| {
todo.editing.set_neq(Some(todo.title.get_cloned()));
}));
}))
children(&mut [
.children(&mut [
text_signal(todo.title.signal_cloned()),
]);
])
}),
html!("button", {
class("destroy");
event(clone!(state, todo => move |_: ClickEvent| {
.class("destroy")
.event(clone!(state, todo => move |_: ClickEvent| {
state.remove_todo(&todo);
state.serialize();
}));
}))
}),
]);
])
}),
html!("input", {
class("edit");
.class("edit")
property_signal("value", todo.editing.signal_cloned()
.map(|x| x.unwrap_or_else(|| "".to_owned())));
.property_signal("value", todo.editing.signal_cloned()
.map(|x| x.unwrap_or_else(|| "".to_owned())))
property_signal("hidden", todo.editing.signal_cloned()
.map(|x| x.is_none()));
.property_signal("hidden", todo.editing.signal_cloned()
.map(|x| x.is_none()))
// TODO dedupe this somehow ?
focused_signal(todo.editing.signal_cloned()
.map(|x| x.is_some()));
.focused_signal(todo.editing.signal_cloned()
.map(|x| x.is_some()))
event(clone!(todo => move |event: KeyDownEvent| {
.event(clone!(todo => move |event: KeyDownEvent| {
let key = event.key();
if key == "Enter" {
@ -350,14 +350,14 @@ fn main() {
} else if key == "Escape" {
todo.editing.set_neq(None);
}
}));
}))
event(clone!(todo => move |event: InputEvent| {
.event(clone!(todo => move |event: InputEvent| {
todo.editing.set_neq(Some(get_value(&event)));
}));
}))
// TODO global_event ?
event(clone!(state, todo => move |_: BlurEvent| {
.event(clone!(state, todo => move |_: BlurEvent| {
if let Some(title) = todo.editing.replace(None) {
if let Some(title) = trim(&title) {
todo.title.set_neq(title);
@ -368,28 +368,28 @@ fn main() {
state.serialize();
}
}));
}))
}),
]);
])
})
})));
})))
}),
]);
])
}),
html!("footer", {
class("footer");
.class("footer")
// Hide if it doesn't have any todos.
property_signal("hidden", state.todo_list.signal_vec_cloned()
.property_signal("hidden", state.todo_list.signal_vec_cloned()
.len()
.map(|len| len == 0));
.map(|len| len == 0))
children(&mut [
.children(&mut [
html!("span", {
class("todo-count");
.class("todo-count")
children_signal_vec(state.todo_list.signal_vec_cloned()
.children_signal_vec(state.todo_list.signal_vec_cloned()
.map_signal(|todo| todo.completed.signal())
.filter(|completed| !completed)
.len()
@ -406,11 +406,11 @@ fn main() {
}),
]
})
.to_signal_vec());
.to_signal_vec())
}),
html!("ul", {
class("filters");
children(&mut [
.class("filters")
.children(&mut [
simple("li", &mut [
filter_button(state.clone(), Filter::All),
]),
@ -420,37 +420,37 @@ fn main() {
simple("li", &mut [
filter_button(state.clone(), Filter::Completed),
]),
]);
])
}),
html!("button", {
class("clear-completed");
.class("clear-completed")
// Hide if it doesn't have any completed items.
property_signal("hidden", state.todo_list.signal_vec_cloned()
.property_signal("hidden", state.todo_list.signal_vec_cloned()
.map_signal(|todo| todo.completed.signal())
.filter(|completed| *completed)
.len()
.map(|len| len == 0));
.map(|len| len == 0))
event(clone!(state => move |_: ClickEvent| {
.event(clone!(state => move |_: ClickEvent| {
state.todo_list.retain(|todo| todo.completed.get() == false);
state.serialize();
}));
}))
children(&mut [
.children(&mut [
text("Clear completed"),
]);
])
}),
]);
])
}),
]);
])
}),
);
dominator::append_dom(&body,
html!("footer", {
class("info");
children(&mut [
.class("info")
.children(&mut [
simple("p", &mut [
text("Double-click to edit a todo"),
]),
@ -462,7 +462,7 @@ fn main() {
text("Part of "),
link("http://todomvc.com", "TodoMVC"),
]),
]);
])
}),
);
}

View File

@ -3,7 +3,7 @@ macro_rules! builder {
($namespace:expr, $default:ty, $kind:expr => $t:ty) => {
builder!($namespace, $default, $kind => $t, {})
};
($namespace:expr, $default:ty, $kind:expr => $t:ty, { $( $name:ident( $( $args:expr ),* ); )* }) => {{
($namespace:expr, $default:ty, $kind:expr => $t:ty, { $(.$name:ident($($args:expr),*))* }) => {{
let a: $crate::DomBuilder<$t> = $crate::DomBuilder::new($crate::create_element_ns($kind, $namespace))$(.$name($($args),*))*;
let b: $crate::Dom = $crate::DomBuilder::into_dom(a);
b
@ -12,8 +12,8 @@ macro_rules! builder {
($namespace:expr, $default:ty, $kind:expr) => {
builder!($namespace, $default, $kind => $default)
};
($namespace:expr, $default:ty, $kind:expr, { $( $name:ident( $( $args:expr ),* ); )* }) => {
builder!($namespace, $default, $kind => $default, { $( $name( $( $args ),* ); )* })
($namespace:expr, $default:ty, $kind:expr, { $(.$name:ident($($args:expr),*))* }) => {
builder!($namespace, $default, $kind => $default, { $(.$name($($args),*))* })
};
}
@ -39,7 +39,7 @@ macro_rules! stylesheet {
($rule:expr) => {
stylesheet!($rule, {})
};
($rule:expr, { $( $name:ident( $( $args:expr ),* ); )* }) => {
($rule:expr, { $(.$name:ident($($args:expr),*))* }) => {
$crate::StylesheetBuilder::new($rule)$(.$name($($args),*))*.done()
};
}
@ -47,7 +47,7 @@ macro_rules! stylesheet {
#[macro_export]
macro_rules! class {
($( $name:ident( $( $args:expr ),* ); )*) => {
($(.$name:ident($($args:expr),*))*) => {
$crate::ClassBuilder::new()$(.$name($($args),*))*.done()
};
}