functional Web UI framework for MoonBit
Dependencies
using @html {div, h1, button}
enum Msg {
Inc
Dec
}
fn main {
let app = simple_cell(
model=0,
update=(msg, model) => match msg {
Inc => model + 1
Dec => model - 1
},
view=(emit, model) => div [
h1("\{model}"),
button(on_click=emit(Inc), "+"),
button(on_click=emit(Dec), "-"),
],
)
new(app).mount("app")
}using @html {fragment, input, nothing, ul, li, p}
using @list {type List, empty}
struct Model {
value : String
items : Map[String, Bool]
}
enum Msg {
Add
Change(String)
Done(String)
}
/// The todo plan
fn plan(name : String) -> Cell {
@rabbita.simple_cell(
model={ value: "", items: {} },
update=(msg, model) => {
let { value, items } = model
match msg {
Add => { value: "", items: items..set(value, false) }
Done(key) => { ..model, items: items..set(key, true) }
Change(value) => { ..model, value, }
}
},
view=(emit, model) => {
let { value, items } = model
let items = items.map((todo, done) => {
let text_style = if done { "text-decoration: line-through" } else { "" }
li(style=[text_style], [
p(todo),
button(on_click=emit(Done(todo)), "done"),
])
})
div(style=["border: 1px solid black", "padding: 1em"], [
h1(name),
ul(items),
input(input_type=Text, value~, on_change=s => emit(Change(s))),
button(on_click=emit(Add), "add"),
])
},
)
}
/// Main app
test {
struct Model {
plans : List[Cell]
}
enum Msg {
NewPlan
}
let app = @rabbita.simple_cell(
model={ plans: empty() },
update=(msg, model) => {
let id = model.plans.length()
match msg {
NewPlan => { plans: model.plans.add(plan("plan \{id}")) }
}
},
view=(emit, model) => {
fragment([
div(model.plans.map(x => x.view())),
button(on_click=emit(NewPlan), "new plan"),
])
},
)
@rabbita.new(app).mount("app")
}type Cell┌─────────────────┐
│ ▼
│ ┌──────────┐
│ │ user │
│ └────┬─────┘
│ │ msg,model
│ ▼
│ ┌────────────┐ msg,model
│ │ update() │◄────────────┐
│ └──┬───────┬─┘ │
│ none,model│ │ │
│ ▼ │ │
│ ┌────────┐ │cmd,model │
│ │ view() │ │ │
│ └────┬───┘ │ │
│ │ │ │
│ html│ ▼ │
│ │ ┌─────────┐ │
└──────────────┘ │ runtime │─────────┘
└─────────┘┌─────────────────┐
│ ▼
│ ┌──────────┐
│ │ user │
│ └────┬─────┘
│ │ msg,model
│ ▼
│ ┌────────────┐ msg,model
│ │ update() │◄────────────┐
│ └──┬───────┬─┘ │
│ none,model│ │ │
│ ▼ │ │
│ ┌────────┐ │cmd,model │
│ │ view() │ │ │
│ └────┬───┘ │ │
│ │ │ │
│ html│ ▼ │
│ │ ┌─────────┐ │
└──────────────┘ │ runtime │─────────┘
└─────────┘test "render html to string" {
let page = @rabbita.static_cell(
@html.ul(["todo1", "todo2"].map(x => @html.li(x))),
)
inspect(
@rabbita.render_to_string(page),
content=(
#|<ul><li>todo1</li><li>todo2</li></ul>
),
)
} ┌──────┐
│ user │◀─────────┐
└──────┘ │
│ msg, model │
▼ │
┌──────────┐ │
│ update() │ │ html
└──────────┘ │
│ model │
▼ │
┌────────┐ │
│ view() │─────────┘
└────────┘button(on_click=emit(MyMsg), "click me")test "counter" {
let app = @rabbita.simple_cell(
model=0,
update=(_ : Unit, count) => count + 1,
view=(emit, count) => {
@html.div([
@html.h1("You clicked \{count} times."),
@html.button(on_click=emit(()), "+"),
])
},
)
ignore(app)
}functional Web UI framework for MoonBit
Dependencies