functional Web UI framework for MoonBit
Dependencies
moon install moonbit-community/warren
warren new my-project
cd my-project
warren devusing @rabbita {type Html, type Val}
using @html {button, div, h1}
///|
enum Msg {
Inc
Dec
}
///|
fn counter() -> Val[Html] {
let (count, emit) = @rabbita.create_pure_state(0, update=fn(count, msg) {
match msg {
Inc => count + 1
Dec => count - 1
}
})
count.view(count => {
div([
h1(count.to_string()),
button(on_click=emit(Inc), "+"),
button(on_click=emit(Dec), "-"),
])
})
}
///|
fn main {
@rabbita.new(counter).mount("app")
}type Apppub enum Status[T] {
Pending
Loaded(T)
Failed(Error)
}type Val[A]fn todo_item(id : Int, title : Val[String]) -> Val[Html] {
title.view(title => @html.li("\{id}: \{title}"))
}
fn todo_list(todos : Val[Vector[(Int, String)]]) -> Val[Html] {
let rows = todos.assoc(todo_item)
rows.view(rows => @html.ul(rows))
}priv enum Tab {
First
Second
} derive(Eq)
impl @rabbita.Enumerate for Tab with fn tag(self) {
match self {
First => "first"
Second => "second"
}
}
fn first_tab() -> Val[Html] {
Val::constant(@html.h1("First"))
}
fn second_tab() -> Val[Html] {
Val::constant(@html.h1("Second"))
}
fn tab_content(tab : Val[Tab]) -> Val[Html] {
tab.enumerate(tab => {
match tab {
First => first_tab()
Second => second_tab()
}
})
}priv enum Page {
Home
Settings
} derive(Eq)
impl @rabbita.Enumerate for Page with fn tag(self) {
match self {
Home => "home"
Settings => "settings"
}
}
fn home_page() -> Val[Html] {
Val::constant(@html.h1("Home"))
}
fn settings_page() -> Val[Html] {
Val::constant(@html.h1("Settings"))
}
fn page_content(page : Val[Page]) -> Val[Html] {
page.switch(page => {
match page {
Home => home_page()
Settings => settings_page()
}
})
}#deprecated("Use `create_state` inside a `() -> Val[Html]` component; return `(Model, Cmd)` from `update`, then map the model to `Html`.")
fn[Model, Msg] cell(model~ : Model, update~ : (Emit[Msg], Msg, Model) -> (Cmd, Model), view~ : (Emit[Msg], Model) -> Html, subscriptions? : (Emit[Msg], Model) -> Sub) -> (() -> Val[Html])#deprecated("Use `create_state` inside a component and pass its returned `Emit` explicitly where it is needed.")
fn[Model, Msg] cell_with_emit(model~ : Model, update~ : (Emit[Msg], Msg, Model) -> (Cmd, Model), view~ : (Emit[Msg], Model) -> Html, subscriptions? : (Emit[Msg], Model) -> Sub) -> (Emit[Msg], () -> Val[Html])priv enum Msg {
Inc
Dec
}
fn counter() -> Val[Html] {
let (count, emit) = @rabbita.create_pure_state(0, update=fn(count, msg) {
match msg {
Inc => count + 1
Dec => count - 1
}
})
count.view(count => {
@html.div([
@html.button(on_click=emit(Dec), "-"),
@html.span(count.to_string()),
@html.button(on_click=emit(Inc), "+"),
])
})
}fn chapter() -> Val[Html] {
// Import "moonbit-community/rabbita/http" as @http in moon.pkg.
let chapter = @rabbita.create_resource(inject => {
@http.get("/chapter.md").expect_text(inject)
})
chapter.view(status => {
match status {
Pending => @html.p("Loading...")
Loaded(text) => @html.pre(text)
Failed(_) => @html.p("Failed to load chapter")
}
})
}priv enum CounterMsg {
Increment
IncrementLater
}
fn counter() -> Val[Html] {
let (count, emit) = @rabbita.create_state(0, update=fn(count, msg, emit) {
match msg {
Increment => (count + 1, @rabbita.none)
IncrementLater => (count, @rabbita.delay(emit(Increment), 1000))
}
})
count.view(count => {
@html.button(on_click=emit(IncrementLater), count.to_string())
})
}priv enum Msg {
Inc
Dec
}
fn delayed_counter() -> Val[Html] {
let (count, emit) = @rabbita.create_state_with_init(
init=fn(emit) { (0, @rabbita.delay(emit(Inc), 1000)) },
update=fn(count, msg, _) {
match msg {
Inc => (count + 1, @rabbita.none)
Dec => (count - 1, @rabbita.none)
}
},
)
count.view(count => {
@html.div([
@html.button(on_click=emit(Dec), "-"),
@html.span(count.to_string()),
@html.button(on_click=emit(Inc), "+"),
])
})
}priv enum Msg {
Inc
Dec
}
fn stepped_counter(step : Val[Int]) -> Val[Html] {
let (count, emit) = @rabbita.create_state_with_input(
input=step,
init=fn(_, _) { (0, @rabbita.none) },
update=fn(count, step, msg, _) {
match msg {
Inc => (count + step, @rabbita.none)
Dec => (count - step, @rabbita.none)
}
},
)
count.view(count => {
@html.div([
@html.button(on_click=emit(Dec), "-"),
@html.span(count.to_string()),
@html.button(on_click=emit(Inc), "+"),
])
})
}fn toggle() -> Val[Html] {
let (open, set_open) = @rabbita.create_variable(false)
open.view(is_open => {
@html.button(
on_click=set_open(v => !v),
if is_open {
"Close"
} else {
"Open"
},
)
})
}#deprecated("Use `create_pure_state` inside a component and pass its returned `Emit` explicitly where it is needed.")
fn[Model, Msg] simple_cell_with_emit(model~ : Model, update~ : (Msg, Model) -> Model, view~ : (Emit[Msg], Model) -> Html, subscriptions? : (Emit[Msg], Model) -> Sub) -> (Emit[Msg], () -> Val[Html])functional Web UI framework for MoonBit
Dependencies