Unite with maple-stdweb-dom
This commit is contained in:
parent
16ea88b644
commit
8ff19b3bf2
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"maple",
|
||||
"maple-core",
|
||||
"maple-examples",
|
||||
"maple-macro",
|
||||
"maple-stdui",
|
||||
"maple-stdweb",
|
||||
"maple-stdweb-dom",
|
||||
]
|
@ -1,9 +1,7 @@
|
||||
cargo-features = ["edition"]
|
||||
|
||||
[package]
|
||||
name = "maple-core"
|
||||
version = "0.1.0"
|
||||
authors = ["Andrey Tkachenko <andreytkachenko64@gmail.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
@ -2,7 +2,8 @@
|
||||
name = "maple-examples"
|
||||
version = "0.1.0"
|
||||
authors = ["Andrey Tkachenko <andreytkachenko64@gmail.com>"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
maple = {path = "../maple"}
|
||||
maple-stdweb-dom = {path = "../../maple-stdweb-dom"}
|
||||
maple-stdweb-dom = {path = "../maple-stdweb-dom"}
|
||||
|
@ -1,10 +1,8 @@
|
||||
cargo-features = ["edition"]
|
||||
|
||||
[package]
|
||||
name = "maple-macro"
|
||||
version = "0.1.1"
|
||||
authors = ["Andrey Tkachenko <andreytkachenko64@gmail.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
syn = {version = "*", features=["full", "extra-traits"]}
|
||||
|
@ -1,10 +1,8 @@
|
||||
cargo-features = ["edition"]
|
||||
|
||||
[package]
|
||||
name = "maple-stdui"
|
||||
version = "0.1.0"
|
||||
authors = ["Andrey Tkachenko <andreytkachenko64@gmail.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
maple-macro = {path = "../maple-macro"}
|
||||
|
3
maple-stdweb-dom/.gitignore
vendored
Normal file
3
maple-stdweb-dom/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
11
maple-stdweb-dom/Cargo.toml
Normal file
11
maple-stdweb-dom/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "maple-stdweb-dom"
|
||||
version = "0.1.0"
|
||||
authors = ["Andrey Tkachenko <andreytkachenko64@gmail.com>"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
maple-core = {path = "../maple-core"}
|
||||
maple-stdweb = {path = "../maple-stdweb"}
|
||||
maple-stdui = {path = "../maple-stdui"}
|
||||
maple-macro = {path = "../maple-macro"}
|
1
maple-stdweb-dom/README.md
Normal file
1
maple-stdweb-dom/README.md
Normal file
@ -0,0 +1 @@
|
||||
# Maple Web DOM Backend
|
56
maple-stdweb-dom/src/canvas.rs
Normal file
56
maple-stdweb-dom/src/canvas.rs
Normal file
@ -0,0 +1,56 @@
|
||||
use super::CanvasContextEngine;
|
||||
use maple_core::prelude::*;
|
||||
use maple_stdweb::*;
|
||||
use maple_macro::view;
|
||||
|
||||
impl RenderImplementation<CanvasContextEngine, !> for Circle {
|
||||
fn render_impl<C: Renderable<!>>(&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<CanvasContextEngine, !> for Circle {
|
||||
type InputContext = DefaultContext;
|
||||
type OutputContext = DefaultContext;
|
||||
type Renderable<C: Renderable<!> + 'static> = impl Renderable<CanvasContextEngine>;
|
||||
|
||||
fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext {
|
||||
ctx
|
||||
}
|
||||
|
||||
fn build<C: Renderable<!> + 'static>(self, children: Option<C>) -> Self::Renderable<C> {
|
||||
Node::new(self, children)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl RenderImplementation<CanvasContextEngine, !> for Rect {
|
||||
fn render_impl<C>(&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<CanvasContextEngine, !> for Rect {
|
||||
type InputContext = DefaultContext;
|
||||
type OutputContext = DefaultContext;
|
||||
type Renderable<C: Renderable<!> + 'static> = impl Renderable<CanvasContextEngine>;
|
||||
|
||||
fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext {
|
||||
ctx
|
||||
}
|
||||
|
||||
fn build<C>(self, children: Option<C>) -> Self::Renderable<C>
|
||||
where C: Renderable<!> + 'static
|
||||
{
|
||||
Node::new(self, children)
|
||||
}
|
||||
}
|
139
maple-stdweb-dom/src/components.rs
Normal file
139
maple-stdweb-dom/src/components.rs
Normal file
@ -0,0 +1,139 @@
|
||||
use super::{HtmlEngine, CanvasContextEngine};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use maple_core::prelude::*;
|
||||
use maple_stdweb::*;
|
||||
|
||||
/** Text **/
|
||||
|
||||
impl Renderable<HtmlEngine> for Text {
|
||||
fn render(&self, eng: &HtmlEngine) {
|
||||
if let Some(text_ref) = &self.props.text {
|
||||
HtmlEngine::text(eng, text_ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Div **/
|
||||
|
||||
impl RenderImplementation<HtmlEngine, HtmlEngine> for Div {
|
||||
fn render_impl<C>(&self, eng: &HtmlEngine, children: &C)
|
||||
where C: Renderable<HtmlEngine>
|
||||
{
|
||||
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<HtmlEngine, HtmlEngine> for Div {
|
||||
type InputContext = DefaultContext;
|
||||
type OutputContext = DefaultContext;
|
||||
type Renderable<C: Renderable<HtmlEngine> + 'static> = impl Renderable<HtmlEngine>;
|
||||
|
||||
fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext {
|
||||
ctx
|
||||
}
|
||||
|
||||
fn build<C>(self, children: Option<C>) -> Self::Renderable<C>
|
||||
where C: Renderable<HtmlEngine> + 'static
|
||||
{
|
||||
Node::new(self, children)
|
||||
}
|
||||
}
|
||||
|
||||
/** Span **/
|
||||
|
||||
impl RenderImplementation<HtmlEngine, HtmlEngine> for Span {
|
||||
fn render_impl<C>(&self, eng: &HtmlEngine, children: &C)
|
||||
where C: Renderable<HtmlEngine>
|
||||
{
|
||||
HtmlEngine::open(eng, "span", None);
|
||||
children.render(eng);
|
||||
HtmlEngine::close(eng, "span");
|
||||
}
|
||||
}
|
||||
|
||||
impl View<HtmlEngine, HtmlEngine> for Span {
|
||||
type InputContext = DefaultContext;
|
||||
type OutputContext = DefaultContext;
|
||||
type Renderable<C: Renderable<HtmlEngine> + 'static> = impl Renderable<HtmlEngine>;
|
||||
|
||||
fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext {
|
||||
ctx
|
||||
}
|
||||
|
||||
fn build<C>(self, children: Option<C>) -> Self::Renderable<C>
|
||||
where C: Renderable<HtmlEngine> + 'static
|
||||
{
|
||||
Node::new(self, children)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Button **/
|
||||
|
||||
impl RenderImplementation<HtmlEngine, HtmlEngine> for Button {
|
||||
fn render_impl<C>(&self, eng: &HtmlEngine, children: &C)
|
||||
where C: Renderable<HtmlEngine>
|
||||
{
|
||||
HtmlEngine::open(eng, "button", None);
|
||||
children.render(eng);
|
||||
HtmlEngine::close(eng, "button");
|
||||
}
|
||||
}
|
||||
|
||||
impl View<HtmlEngine, HtmlEngine> for Button {
|
||||
type InputContext = DefaultContext;
|
||||
type OutputContext = DefaultContext;
|
||||
type Renderable<C: Renderable<HtmlEngine> + 'static> = impl Renderable<HtmlEngine>;
|
||||
|
||||
fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext {
|
||||
ctx
|
||||
}
|
||||
|
||||
fn build<C>(self, children: Option<C>) -> Self::Renderable<C>
|
||||
where C: Renderable<HtmlEngine> + 'static
|
||||
{
|
||||
Node::new(self, children)
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderImplementation<HtmlEngine, CanvasContextEngine> for Canvas {
|
||||
fn render_impl<C>(&self, eng: &HtmlEngine, children: &C)
|
||||
where C: Renderable<CanvasContextEngine>
|
||||
{
|
||||
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<HtmlEngine, CanvasContextEngine> for Canvas {
|
||||
type InputContext = DefaultContext;
|
||||
type OutputContext = DefaultContext;
|
||||
type Renderable<C: Renderable<CanvasContextEngine> + 'static> = impl Renderable<HtmlEngine>;
|
||||
|
||||
fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext {
|
||||
ctx
|
||||
}
|
||||
|
||||
fn build<C>(self, children: Option<C>) -> Self::Renderable<C>
|
||||
where C: Renderable<CanvasContextEngine> + 'static
|
||||
{
|
||||
Node::new(self, children)
|
||||
}
|
||||
}
|
85
maple-stdweb-dom/src/lib.rs
Normal file
85
maple-stdweb-dom/src/lib.rs
Normal file
@ -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<String>
|
||||
}
|
||||
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<String>
|
||||
}
|
||||
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<HashMap<String, String>>) {
|
||||
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(&("<script>".to_string() + data + "</script>"));
|
||||
}
|
||||
}
|
25
maple-stdweb-dom/src/panel.rs
Normal file
25
maple-stdweb-dom/src/panel.rs
Normal file
@ -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<HtmlEngine, HtmlEngine> for Panel {
|
||||
type InputContext = DefaultContext;
|
||||
type OutputContext = DefaultContext;
|
||||
type Renderable<C: Renderable<HtmlEngine> + 'static> = impl Renderable<HtmlEngine>;
|
||||
|
||||
fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext {
|
||||
ctx
|
||||
}
|
||||
|
||||
fn build<C>(self, children: Option<C>) -> Self::Renderable<C>
|
||||
where C: Renderable<HtmlEngine> + 'static
|
||||
{
|
||||
view! {
|
||||
<Div class="panel">
|
||||
{ ...children }
|
||||
</Div>
|
||||
}
|
||||
}
|
||||
}
|
103
maple-stdweb-dom/src/tabs.rs
Normal file
103
maple-stdweb-dom/src/tabs.rs
Normal file
@ -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<HtmlEngine, HtmlEngine> for Tabs {
|
||||
type InputContext = DefaultContext;
|
||||
type OutputContext = TabsContext<DefaultContext>;
|
||||
type Renderable<C: Renderable<HtmlEngine> + 'static> = impl Renderable<HtmlEngine>;
|
||||
|
||||
fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext {
|
||||
TabsContext::wrap(ctx)
|
||||
}
|
||||
|
||||
fn build<C>(self, children: Option<C>) -> Self::Renderable<C>
|
||||
where C: Renderable<HtmlEngine> + 'static
|
||||
{
|
||||
view! {
|
||||
<Div class="tabs">
|
||||
{ ... children }
|
||||
</Div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl View<HtmlEngine, HtmlEngine> for Header {
|
||||
type InputContext = TabsContext<DefaultContext>;
|
||||
type OutputContext = DefaultContext;
|
||||
type Renderable<C: Renderable<HtmlEngine> + 'static> = impl Renderable<HtmlEngine>;
|
||||
|
||||
fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext {
|
||||
self.tabs_ctx = Some(ctx.clone());
|
||||
|
||||
ctx.unwrap()
|
||||
}
|
||||
|
||||
fn build<C>(self, children: Option<C>) -> Self::Renderable<C>
|
||||
where C: Renderable<HtmlEngine> + 'static
|
||||
{
|
||||
let tabs = self.tabs_ctx.map(|ctx|
|
||||
ctx.get_tabs()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, tab)| view! {
|
||||
<Span class="tab-title" click={move |_| HeaderEvent::Click(i)}>
|
||||
{match tab {
|
||||
Some(val) => val,
|
||||
None => "<No title>"
|
||||
}}
|
||||
</Span>
|
||||
})
|
||||
.collect::<Vec<_>>());
|
||||
|
||||
view! {
|
||||
<Div class="tabs-header">
|
||||
{ ...tabs }
|
||||
</Div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl View<HtmlEngine, HtmlEngine> for Body {
|
||||
type InputContext = TabsContext<DefaultContext>;
|
||||
type OutputContext = TabsBodyContext<DefaultContext>;
|
||||
type Renderable<T: Renderable<HtmlEngine> + 'static> = impl Renderable<HtmlEngine>;
|
||||
|
||||
fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext {
|
||||
TabsBodyContext::wrap(ctx)
|
||||
}
|
||||
|
||||
fn build<C>(self, children: Option<C>) -> Self::Renderable<C>
|
||||
where C: Renderable<HtmlEngine> + 'static
|
||||
{
|
||||
view! {
|
||||
<Div class="tab">
|
||||
{ ... children }
|
||||
</Div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl View<HtmlEngine, HtmlEngine> for Tab {
|
||||
type InputContext = TabsBodyContext<DefaultContext>;
|
||||
type OutputContext = DefaultContext;
|
||||
type Renderable<T: Renderable<HtmlEngine> + 'static> = impl Renderable<HtmlEngine>;
|
||||
|
||||
fn receive_context(&mut self, ctx: Self::InputContext) -> Self::OutputContext {
|
||||
ctx.add_tab(self.props.title);
|
||||
ctx.unwrap().unwrap()
|
||||
}
|
||||
|
||||
fn build<C>(self, children: Option<C>) -> Self::Renderable<C>
|
||||
where C: Renderable<HtmlEngine> + 'static
|
||||
{
|
||||
view! {
|
||||
<Div class="tab">
|
||||
{ ... children }
|
||||
</Div>
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,8 @@
|
||||
cargo-features = ["edition"]
|
||||
|
||||
[package]
|
||||
name = "maple-stdweb"
|
||||
version = "0.1.0"
|
||||
authors = ["Andrey Tkachenko <andreytkachenko64@gmail.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
maple-core = {path = '../maple-core'}
|
||||
|
@ -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<Box<Fn() -> ButtonEvents>>
|
||||
pub click: Option<Box<dyn Fn() -> ButtonEvents>>
|
||||
}
|
||||
|
||||
impl Component for Button {
|
||||
@ -27,4 +27,4 @@ impl Component for Button {
|
||||
fn update(&mut self, msg: Self::Msg) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Box<Fn() -> CanvasEvents>>
|
||||
pub click: Option<Box<dyn Fn() -> CanvasEvents>>
|
||||
}
|
||||
|
||||
impl Component for Canvas {
|
||||
@ -27,4 +27,4 @@ impl Component for Canvas {
|
||||
fn update(&mut self, msg: Self::Msg) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Box<Fn() -> DivEvents>>
|
||||
pub click: Option<Box<dyn Fn() -> DivEvents>>
|
||||
}
|
||||
|
||||
impl Component for Div {
|
||||
@ -29,4 +29,4 @@ impl Component for Div {
|
||||
fn update(&mut self, msg: Self::Msg) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,4 +35,4 @@ impl Component for Span {
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,11 @@
|
||||
cargo-features = ["edition"]
|
||||
|
||||
[package]
|
||||
name = "maple"
|
||||
version = "0.1.0"
|
||||
authors = ["Andrey Tkachenko <andreytkachenko64@gmail.com>"]
|
||||
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"}
|
||||
maple-stdweb = {path = "../maple-stdweb"}
|
||||
|
Loading…
Reference in New Issue
Block a user