utkarshkukreti / draco

Draco is a Rust library for building client side web applications with Web Assembly.
Apache License 2.0
303 stars 18 forks source link

Draco

Draco is a Rust library to build client side web applications with Web Assembly.

Live Examples with Annotated Source | Starter

Note: This is the README for upcoming Draco 0.2. The README for the latest released version is here.

Overview

The "Hello, World!" of Draco (with comments here):

use wasm_bindgen::prelude::*;

struct HelloWorld;

impl draco::Application for HelloWorld {
    type Message = ();

    fn view(&self) -> draco::VNode<Self::Message> {
        draco::html::h1().with("Hello, world!").into()
    }
}

#[wasm_bindgen(start)]
pub fn start() {
    draco::start(HelloWorld, draco::select("main").expect("<main>").into());
}

Draco is modeled after The Elm Architecture and Redux. A Draco application implements the draco::Application trait, which includes one type and two functions.

pub trait Application {
    type Message;

    fn update(&mut self, message: Self::Message, mailbox: &Mailbox<Self::Message>) {}
    fn view(&self) -> Node<Self::Message>;
}

The view function maps &self to an HTML/SVG Node. The Node can emit Messages on certain events.

The update function takes &mut self, a Message and a draco::Mailbox. This function may update its fields based on the value of the Message. This function may also send more messages to itself or spawn a Future which will send a message when it resolves, through the Mailbox.

Counter

This Counter example (with comments here) demonstrates an application which updates an integer value based on 3 types of messages emitted from the view.

use wasm_bindgen::prelude::*;

#[derive(Default)]
pub struct Counter {
    value: i32,
}

pub enum Message {
    Increment,
    Decrement,
    Reset,
}

impl draco::Application for Counter {
    type Message = Message;

    fn update(&mut self, message: Self::Message, _: &draco::Mailbox<Self::Message>) {
        match message {
            Message::Increment => self.value += 1,
            Message::Decrement => self.value -= 1,
            Message::Reset => self.value = 0,
        }
    }

    fn view(&self) -> draco::VNode<Self::Message> {
        use draco::html as h;
        h::div()
            .with((
                h::button().on("click", |_| Message::Decrement).with("-"),
                " ",
                self.value,
                " ",
                h::button().with("+").on("click", |_| Message::Increment),
                " ",
                h::button().with("Reset").on("click", |_| Message::Reset),
            ))
            .into()
    }
}

#[wasm_bindgen(start)]
pub fn start() {
    draco::start(
        Counter::default(),
        draco::select("main").expect("<main>").into(),
    );
}