mogwai

Mogwai goes one step further than Gloo and provides patterns that make creating DOM and interacting with it declarative and function. You still interact with web-sys, but there are no event listeners or callbacks to deal with. It is inspired by Haskell and Elm, so it looks a bit functional and components use a familiar Elm update concept.

Goals

  • declarative DOM
  • elm-like components
  • explicit updates
  • small (code size)
  • fast

Example

Here is an example of a button that counts its own clicks. Simple gizmos like this don't need the elm-like component update scenario, so it looks very functional:

extern crate mogwai;
use mogwai::prelude::*;

let (tx, rx) =
  txrx_fold(
    0,
    |n:&mut i32, _:&Event| -> String {
      *n += 1;
      if *n == 1 {
        "Clicked 1 time".to_string()
      } else {
        format!("Clicked {} times", *n)
      }
    }
  );

button()
  .style("cursor", "pointer")
  .rx_text("Clicked 0 times", rx)
  .tx_on("click", tx)
  .build().unwrap()
  .run().unwrap()

Here is an example of the same thing using an elm-like approach:

use mogwai::prelude::*;

pub struct Button {
  pub clicks: i32
}

#[derive(Clone)]
pub enum ButtonIn {
  Click
}

#[derive(Clone)]
pub enum ButtonOut {
  Clicks(i32)
}

impl Component for Button {
  type ModelMsg = ButtonIn;
  type ViewMsg = ButtonOut;

  fn update(
    &mut self,
    msg: &ButtonIn,
    tx_view: &Transmitter<ButtonOut>,
    _subscriber: &Subscriber<ButtonIn>
  ) {
    match msg {
      ButtonIn::Click => {
        self.clicks += 1;
        tx_view.send(&ButtonOut::Clicks(self.clicks))
      }
    }
  }

  fn builder(
    &self,
    tx: Transmitter<ButtonIn>,
    rx: Receiver<ButtonOut>
  ) -> GizmoBuilder {
    button()
      .style("cursor", "pointer")
      .rx_text("Clicked 0 times", rx.branch_map(|msg| {
        match msg {
          ButtonOut::Clicks(n) => format!("Clicked {} times", n)
        }
      }))
      .tx_on("click", tx.contra_map(|_| ButtonIn::Click))
  }
}

Button{ clicks: 0 }
  .into_component()
  .build().unwrap()
  .run().unwrap()