// 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)