// Counter with Html Module (Type-safe HTML)
// Compile with: lux compile examples/web/counter_html.lux --target js -o examples/web/counter_html.js
//
// This version uses the Html module for type-safe HTML construction
// instead of string concatenation. The Html module provides:
// - Type-safe element constructors (div, button, etc.)
// - Type-safe attribute constructors (class, onClick, etc.)
// - Automatic HTML escaping
// ============================================================================
// Model
// ============================================================================
type Model = | Counter(Int)
fn getCount(m: Model): Int = match m { Counter(n) => n }
fn init(): Model = Counter(0)
// ============================================================================
// Messages
// ============================================================================
type Msg = | Increment | Decrement | Reset
// ============================================================================
// Update
// ============================================================================
fn update(model: Model, msg: Msg): Model =
match msg {
Increment => Counter(getCount(model) + 1),
Decrement => Counter(getCount(model) - 1),
Reset => Counter(0)
}
// ============================================================================
// View - Type-safe HTML using Html module
// ============================================================================
fn view(model: Model): String = {
let count = getCount(model)
// Build HTML tree using Html module
let title = Html.h1([], [Html.text("Lux Counter")])
let display = Html.div([Html.class("display")], [Html.text(toString(count))])
let decBtn = Html.button(
[Html.attr("onclick", "dispatch('Decrement')")],
[Html.text("-")]
)
let resetBtn = Html.button(
[Html.attr("onclick", "dispatch('Reset')")],
[Html.text("Reset")]
)
let incBtn = Html.button(
[Html.attr("onclick", "dispatch('Increment')")],
[Html.text("+")]
)
let buttons = Html.div([Html.class("buttons")], [decBtn, resetBtn, incBtn])
let container = Html.div([Html.class("counter")], [title, display, buttons])
// Render to HTML string
Html.render(container)
}
// ============================================================================
// Export for browser runtime
// ============================================================================
fn luxInit(): Model = init()
fn luxUpdate(model: Model, msgName: String): Model =
match msgName {
"Increment" => update(model, Increment),
"Decrement" => update(model, Decrement),
"Reset" => update(model, Reset),
_ => model
}
fn luxView(model: Model): String = view(model)