diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..6bc21e2 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[workspace] +members = [ + "maple", + "maple-core", + "maple-examples", + "maple-macro", + "maple-stdui", + "maple-stdweb", + "maple-stdweb-dom", +] diff --git a/maple-core/Cargo.toml b/maple-core/Cargo.toml index 4e2d357..33736f6 100644 --- a/maple-core/Cargo.toml +++ b/maple-core/Cargo.toml @@ -1,9 +1,7 @@ -cargo-features = ["edition"] - [package] name = "maple-core" version = "0.1.0" authors = ["Andrey Tkachenko "] -edition = "2018" +edition = "2021" [dependencies] diff --git a/maple-examples/Cargo.toml b/maple-examples/Cargo.toml index 6fe4dc4..7782087 100644 --- a/maple-examples/Cargo.toml +++ b/maple-examples/Cargo.toml @@ -2,7 +2,8 @@ name = "maple-examples" version = "0.1.0" authors = ["Andrey Tkachenko "] +edition = "2021" [dependencies] maple = {path = "../maple"} -maple-stdweb-dom = {path = "../../maple-stdweb-dom"} +maple-stdweb-dom = {path = "../maple-stdweb-dom"} diff --git a/maple-macro/Cargo.toml b/maple-macro/Cargo.toml index d238736..89052da 100644 --- a/maple-macro/Cargo.toml +++ b/maple-macro/Cargo.toml @@ -1,10 +1,8 @@ -cargo-features = ["edition"] - [package] name = "maple-macro" version = "0.1.1" authors = ["Andrey Tkachenko "] -edition = "2018" +edition = "2021" [dependencies] syn = {version = "*", features=["full", "extra-traits"]} diff --git a/maple-stdui/Cargo.toml b/maple-stdui/Cargo.toml index 4e5bb25..94d68cb 100644 --- a/maple-stdui/Cargo.toml +++ b/maple-stdui/Cargo.toml @@ -1,10 +1,8 @@ -cargo-features = ["edition"] - [package] name = "maple-stdui" version = "0.1.0" authors = ["Andrey Tkachenko "] -edition = "2018" +edition = "2021" [dependencies] maple-macro = {path = "../maple-macro"} diff --git a/maple-stdweb-dom/.gitignore b/maple-stdweb-dom/.gitignore new file mode 100644 index 0000000..6936990 --- /dev/null +++ b/maple-stdweb-dom/.gitignore @@ -0,0 +1,3 @@ +/target +**/*.rs.bk +Cargo.lock diff --git a/maple-stdweb-dom/Cargo.toml b/maple-stdweb-dom/Cargo.toml new file mode 100644 index 0000000..a3b9d7c --- /dev/null +++ b/maple-stdweb-dom/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "maple-stdweb-dom" +version = "0.1.0" +authors = ["Andrey Tkachenko "] +edition = "2021" + +[dependencies] +maple-core = {path = "../maple-core"} +maple-stdweb = {path = "../maple-stdweb"} +maple-stdui = {path = "../maple-stdui"} +maple-macro = {path = "../maple-macro"} diff --git a/maple-stdweb-dom/README.md b/maple-stdweb-dom/README.md new file mode 100644 index 0000000..8283c5c --- /dev/null +++ b/maple-stdweb-dom/README.md @@ -0,0 +1 @@ +# Maple Web DOM Backend diff --git a/maple-stdweb-dom/src/canvas.rs b/maple-stdweb-dom/src/canvas.rs new file mode 100644 index 0000000..356d7bf --- /dev/null +++ b/maple-stdweb-dom/src/canvas.rs @@ -0,0 +1,56 @@ +use super::CanvasContextEngine; +use maple_core::prelude::*; +use maple_stdweb::*; +use maple_macro::view; + +impl RenderImplementation for Circle { + fn render_impl>(&self, eng: &CanvasContextEngine, _children: &C) { + eng.add(&format!(" + ctx.beginPath(); + ctx.arc({},{},{},0,2*Math.PI); + ctx.stroke(); + ", self.props.cx.unwrap(), self.props.cy.unwrap(), self.props.r.unwrap())); + } +} + +impl View for Circle { + type InputContext = DefaultContext; + type OutputContext = DefaultContext; + type Renderable + 'static> = impl Renderable; + + fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext { + ctx + } + + fn build + 'static>(self, children: Option) -> Self::Renderable { + Node::new(self, children) + } +} + + +impl RenderImplementation for Rect { + fn render_impl(&self, eng: &CanvasContextEngine, _children: &C) + where C: Renderable + { + eng.add(&format!(" + ctx.rect({},{},{},{}); + ctx.stroke(); + ", self.props.x1.unwrap(), self.props.y1.unwrap(), self.props.x2.unwrap(), self.props.y2.unwrap())); + } +} + +impl View for Rect { + type InputContext = DefaultContext; + type OutputContext = DefaultContext; + type Renderable + 'static> = impl Renderable; + + fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext { + ctx + } + + fn build(self, children: Option) -> Self::Renderable + where C: Renderable + 'static + { + Node::new(self, children) + } +} diff --git a/maple-stdweb-dom/src/components.rs b/maple-stdweb-dom/src/components.rs new file mode 100644 index 0000000..8d670cf --- /dev/null +++ b/maple-stdweb-dom/src/components.rs @@ -0,0 +1,139 @@ +use super::{HtmlEngine, CanvasContextEngine}; +use std::collections::HashMap; + +use maple_core::prelude::*; +use maple_stdweb::*; + +/** Text **/ + +impl Renderable for Text { + fn render(&self, eng: &HtmlEngine) { + if let Some(text_ref) = &self.props.text { + HtmlEngine::text(eng, text_ref); + } + } +} + +/** Div **/ + +impl RenderImplementation for Div { + fn render_impl(&self, eng: &HtmlEngine, children: &C) + where C: Renderable + { + let mut attrs = HashMap::new(); + + if let Some(class) = self.props.class { + attrs.insert("class".into(), class.into()); + } + + HtmlEngine::open(eng, "div", Some(attrs)); + children.render(eng); + HtmlEngine::close(eng, "div"); + } +} + +impl View for Div { + type InputContext = DefaultContext; + type OutputContext = DefaultContext; + type Renderable + 'static> = impl Renderable; + + fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext { + ctx + } + + fn build(self, children: Option) -> Self::Renderable + where C: Renderable + 'static + { + Node::new(self, children) + } +} + +/** Span **/ + +impl RenderImplementation for Span { + fn render_impl(&self, eng: &HtmlEngine, children: &C) + where C: Renderable + { + HtmlEngine::open(eng, "span", None); + children.render(eng); + HtmlEngine::close(eng, "span"); + } +} + +impl View for Span { + type InputContext = DefaultContext; + type OutputContext = DefaultContext; + type Renderable + 'static> = impl Renderable; + + fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext { + ctx + } + + fn build(self, children: Option) -> Self::Renderable + where C: Renderable + 'static + { + Node::new(self, children) + } +} + + +/** Button **/ + +impl RenderImplementation for Button { + fn render_impl(&self, eng: &HtmlEngine, children: &C) + where C: Renderable + { + HtmlEngine::open(eng, "button", None); + children.render(eng); + HtmlEngine::close(eng, "button"); + } +} + +impl View for Button { + type InputContext = DefaultContext; + type OutputContext = DefaultContext; + type Renderable + 'static> = impl Renderable; + + fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext { + ctx + } + + fn build(self, children: Option) -> Self::Renderable + where C: Renderable + 'static + { + Node::new(self, children) + } +} + +impl RenderImplementation for Canvas { + fn render_impl(&self, eng: &HtmlEngine, children: &C) + where C: Renderable + { + let can_eng = CanvasContextEngine::new(); + let mut attrs = HashMap::new(); + attrs.insert("id".to_string(), "myCanvas".to_string()); + + eng.open("canvas", Some(attrs)); + children.render(&can_eng); + eng.close("canvas"); + eng.script(&format!(" + var c=document.getElementById(\"myCanvas\"); + var ctx=c.getContext(\"2d\"); {};", can_eng.to_string())); + } +} + +impl View for Canvas { + type InputContext = DefaultContext; + type OutputContext = DefaultContext; + type Renderable + 'static> = impl Renderable; + + fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext { + ctx + } + + fn build(self, children: Option) -> Self::Renderable + where C: Renderable + 'static + { + Node::new(self, children) + } +} diff --git a/maple-stdweb-dom/src/lib.rs b/maple-stdweb-dom/src/lib.rs new file mode 100644 index 0000000..ecf832c --- /dev/null +++ b/maple-stdweb-dom/src/lib.rs @@ -0,0 +1,85 @@ +#![feature(never_type, proc_macro_hygiene)] +#![feature(generic_associated_types)] +#![feature(type_alias_impl_trait)] + +#[macro_use] +extern crate maple_core; +extern crate maple_stdweb; + +mod components; +mod canvas; +mod panel; +mod tabs; + +use std::cell::RefCell; +pub use self::components::*; +pub use self::canvas::*; +pub use self::panel::*; +pub use self::tabs::*; +use maple_core::prelude::*; +use std::collections::HashMap; + +pub struct CanvasContextEngine { + data: RefCell +} +impl Engine for CanvasContextEngine {} + +impl CanvasContextEngine { + pub fn new() -> Self { + return Self { + data: RefCell::new(String::new()) + } + } + + pub fn to_string(&self) -> String { + self.data.borrow().clone() + } + + pub fn add(&self, code: &str) { + self.data.borrow_mut().push_str(code); + } +} + +pub struct HtmlEngine { + data: RefCell +} +impl Engine for HtmlEngine {} + +impl HtmlEngine { + pub fn new() -> Self { + return Self { + data: RefCell::new(String::new()) + } + } + + pub fn to_string(&self) -> String { + self.data.borrow().clone() + } + + pub fn open(&self, name: &str, attrs: Option>) { + let attrs_str = if let Some(attrs_map) = attrs { + attrs_map.iter().fold(" ".to_string(), |acc, (ref l, ref r)| acc + l + "=\"" + r + "\" ") + + } else { + "".to_string() + }; + + self.data.borrow_mut() + .push_str(&format!("<{}{}>\n", name, attrs_str)); + } + + pub fn close(&self, name: &str) { + self.data.borrow_mut() + .push_str(&format!("\n", name)); + } + + pub fn text(&self, dat: &str) { + self.data.borrow_mut() + .push_str(dat); + } + + pub fn script(&self, data: &str) { + self.data.borrow_mut() + .push_str(&("")); + } +} diff --git a/maple-stdweb-dom/src/panel.rs b/maple-stdweb-dom/src/panel.rs new file mode 100644 index 0000000..d800568 --- /dev/null +++ b/maple-stdweb-dom/src/panel.rs @@ -0,0 +1,25 @@ +use maple_core::prelude::*; +use maple_macro::view; +use maple_stdweb::*; +use maple_stdui::prelude::Panel; +use super::HtmlEngine; + +impl View for Panel { + type InputContext = DefaultContext; + type OutputContext = DefaultContext; + type Renderable + 'static> = impl Renderable; + + fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext { + ctx + } + + fn build(self, children: Option) -> Self::Renderable + where C: Renderable + 'static + { + view! { +
+ { ...children } +
+ } + } +} diff --git a/maple-stdweb-dom/src/tabs.rs b/maple-stdweb-dom/src/tabs.rs new file mode 100644 index 0000000..0d99a3b --- /dev/null +++ b/maple-stdweb-dom/src/tabs.rs @@ -0,0 +1,103 @@ +use maple_core::prelude::*; +use maple_macro::view; +use maple_stdweb::*; +use maple_stdui::prelude::tabs::*; +use super::HtmlEngine; + + +impl View for Tabs { + type InputContext = DefaultContext; + type OutputContext = TabsContext; + type Renderable + 'static> = impl Renderable; + + fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext { + TabsContext::wrap(ctx) + } + + fn build(self, children: Option) -> Self::Renderable + where C: Renderable + 'static + { + view! { +
+ { ... children } +
+ } + } +} + +impl View for Header { + type InputContext = TabsContext; + type OutputContext = DefaultContext; + type Renderable + 'static> = impl Renderable; + + fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext { + self.tabs_ctx = Some(ctx.clone()); + + ctx.unwrap() + } + + fn build(self, children: Option) -> Self::Renderable + where C: Renderable + 'static + { + let tabs = self.tabs_ctx.map(|ctx| + ctx.get_tabs() + .iter() + .enumerate() + .map(|(i, tab)| view! { + + {match tab { + Some(val) => val, + None => "" + }} + + }) + .collect::>()); + + view! { +
+ { ...tabs } +
+ } + } +} + +impl View for Body { + type InputContext = TabsContext; + type OutputContext = TabsBodyContext; + type Renderable + 'static> = impl Renderable; + + fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext { + TabsBodyContext::wrap(ctx) + } + + fn build(self, children: Option) -> Self::Renderable + where C: Renderable + 'static + { + view! { +
+ { ... children } +
+ } + } +} + +impl View for Tab { + type InputContext = TabsBodyContext; + type OutputContext = DefaultContext; + type Renderable + 'static> = impl Renderable; + + fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext { + ctx.add_tab(self.props.title); + ctx.unwrap().unwrap() + } + + fn build(self, children: Option) -> Self::Renderable + where C: Renderable + 'static + { + view! { +
+ { ... children } +
+ } + } +} diff --git a/maple-stdweb/Cargo.toml b/maple-stdweb/Cargo.toml index 0820918..4d39388 100644 --- a/maple-stdweb/Cargo.toml +++ b/maple-stdweb/Cargo.toml @@ -1,10 +1,8 @@ -cargo-features = ["edition"] - [package] name = "maple-stdweb" version = "0.1.0" authors = ["Andrey Tkachenko "] -edition = "2018" +edition = "2021" [dependencies] maple-core = {path = '../maple-core'} diff --git a/maple-stdweb/src/button.rs b/maple-stdweb/src/button.rs index 2cbf59a..d9c2be8 100644 --- a/maple-stdweb/src/button.rs +++ b/maple-stdweb/src/button.rs @@ -13,7 +13,7 @@ pub struct ButtonProps { pub id: Option<&'static str>, pub name: Option<&'static str>, pub class: Option<&'static str>, - pub click: Option ButtonEvents>> + pub click: Option ButtonEvents>> } impl Component for Button { @@ -27,4 +27,4 @@ impl Component for Button { fn update(&mut self, msg: Self::Msg) -> bool { false } -} \ No newline at end of file +} diff --git a/maple-stdweb/src/canvas.rs b/maple-stdweb/src/canvas.rs index ec42943..c5dd31e 100644 --- a/maple-stdweb/src/canvas.rs +++ b/maple-stdweb/src/canvas.rs @@ -13,7 +13,7 @@ pub struct CanvasProps { pub id: Option<&'static str>, pub name: Option<&'static str>, pub class: Option<&'static str>, - pub click: Option CanvasEvents>> + pub click: Option CanvasEvents>> } impl Component for Canvas { @@ -27,4 +27,4 @@ impl Component for Canvas { fn update(&mut self, msg: Self::Msg) -> bool { true } -} \ No newline at end of file +} diff --git a/maple-stdweb/src/div.rs b/maple-stdweb/src/div.rs index 8a450f1..d891e0a 100644 --- a/maple-stdweb/src/div.rs +++ b/maple-stdweb/src/div.rs @@ -13,7 +13,7 @@ pub struct DivProps { pub id: Option<&'static str>, pub name: Option<&'static str>, pub class: Option<&'static str>, - pub click: Option DivEvents>> + pub click: Option DivEvents>> } impl Component for Div { @@ -29,4 +29,4 @@ impl Component for Div { fn update(&mut self, msg: Self::Msg) -> bool { false } -} \ No newline at end of file +} diff --git a/maple-stdweb/src/span.rs b/maple-stdweb/src/span.rs index b2de7cb..f54cd77 100644 --- a/maple-stdweb/src/span.rs +++ b/maple-stdweb/src/span.rs @@ -35,4 +35,4 @@ impl Component for Span { false } -} \ No newline at end of file +} diff --git a/maple/Cargo.toml b/maple/Cargo.toml index d044a99..67e6c32 100644 --- a/maple/Cargo.toml +++ b/maple/Cargo.toml @@ -1,13 +1,11 @@ -cargo-features = ["edition"] - [package] name = "maple" version = "0.1.0" authors = ["Andrey Tkachenko "] -edition = "2018" +edition = "2021" [dependencies] maple-core = {path = "../maple-core"} maple-macro = {path = "../maple-macro"} maple-stdui = {path = "../maple-stdui"} -maple-stdweb = {path = "../maple-stdweb"} \ No newline at end of file +maple-stdweb = {path = "../maple-stdweb"}