
Kagura
A front-end framework that runs on WebAssembly written in Rust.
Hello World
extern crate kagura;
extern crate wasm_bindgen;
use kagura::prelude::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(start)]
pub fn main() {
let node = web_sys::window()
.unwrap()
.document()
.unwrap()
.get_element_by_id("app")
.unwrap();
Kagura::mount(node.into(), || {
vec![Html::h1(
Attributes::new(),
Events::new(),
vec![Html::text("Hello Kagura")],
)]
});
}
Usage
Tutorial
tutorial for v0.13
Create a project
See /project-template/^0.13 in this repogitory. This is a template of project of Kagura. You can custamize to use.
project template for ^0.13
Mount to web_sys::Node
Kagura::mount(web_sys::Node, impl FnMut() -> Vec<Html<Terminator>>)
Terminator is a component, which is a marker of root of dom. And, Kagura only changes children of mounted web_sys::Node.
Create a component
use kagura::html::component::Cmd;
use kagura::prelude::*;
pub struct Props {}
pub enum Msg {
Clicked,
}
pub enum On {}
pub struct MyComponent {
greeting: String,
}
impl Component for MyComponent {
type Props = Props;
type Msg = Msg;
type Sub = On;
}
impl Constructor for MyComponent {
fn constructor(_props: &Self::Props) -> Self {
Self {
greeting: String::from("Hello world"),
}
}
}
impl Update for MyComponent {
fn update(&mut self, _props: &Props, msg: Msg) -> Cmd<Self> {
match msg {
Msg::Clicked => {
self.greeting = String::from("Hello from Kagura");
Cmd::none()
}
}
}
}
impl Render for MyComponent {
fn render(&self, _props: &Props, _children: Vec<Html<Self>>) -> Html<Self> {
Html::div(
Attributes::new(),
Events::new(),
vec![
Html::h1(
Attributes::new(),
Events::new(),
vec![Html::text(&self.greeting)],
),
Html::button(
Attributes::new(),
Events::new().on_click(
|_| Msg::Clicked,
),
vec![Html::text("change greeting")],
),
],
)
}
}
Mount a component
There are default-implemented function in Constructor trait.
Self means the component which mounts to. DemirootComp means the component which is mounted to.
fn with_children<DemirootComp: Component>(
props: Self::Props,
sub: Sub<Self::Sub, DemirootComp::Msg>,
children: Vec<Html<DemirootComp>>,
) -> Html<DemirootComp>;
fn with_child<DemirootComp: Component>(
props: Self::Props,
sub: Sub<Self::Sub, DemirootComp::Msg>,
child: Html<DemirootComp>,
) -> Html<DemirootComp>;
fn empty<DemirootComp: Component>(
props: Self::Props,
sub: Sub<Self::Sub, DemirootComp::Msg>,
) -> Html<DemirootComp>;
This is a example:
extern crate js_sys;
extern crate kagura;
extern crate wasm_bindgen;
extern crate web_sys;
use kagura::prelude::*;
use wasm_bindgen::prelude::*;
mod my_component;
use my_component::MyComponent;
#[wasm_bindgen(start)]
pub fn main() {
Kagura::mount(entry_point(), || {
vec![MyComponent::empty(
my_component::Props {},
component::Sub::none(),
)]
});
}
fn entry_point() -> web_sys::Node {
web_sys::window()
.unwrap()
.document()
.unwrap()
.get_element_by_id("app")
.unwrap()
.into()
}
This exmaple is mounting MyComponent to Terminator. And, in customed component, like MyComponent, you can do too in render. like this:
impl Render for MyComponent {
fn render(&self, _props: &Props, _children: Vec<Html<Self>>) -> Html<Self> {
CustomedComponent::empty(
customed_component::Props {},
component::Sub::none(),
)
}
}