feat: add stdlib and browser examples
- stdlib/html.lux: Type-safe HTML construction - stdlib/browser.lux: Browser utilities - examples/web/: Counter app with DOM manipulation - examples/counter.lux: Simple counter example Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
154
examples/web/README.md
Normal file
154
examples/web/README.md
Normal file
@@ -0,0 +1,154 @@
|
||||
# Lux Web Examples
|
||||
|
||||
Interactive browser examples demonstrating Lux compiled to JavaScript.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# 1. Compile the counter example
|
||||
lux compile examples/web/counter.lux --target js -o examples/web/counter.js
|
||||
|
||||
# 2. Start a local server
|
||||
cd examples/web
|
||||
./serve.sh
|
||||
|
||||
# 3. Open in browser
|
||||
# http://localhost:8080/index.html
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Counter (String-based)
|
||||
|
||||
A simple counter demonstrating the TEA (The Elm Architecture) pattern using string concatenation for HTML:
|
||||
|
||||
```lux
|
||||
fn view(model: Model): String = {
|
||||
"<div>" + toString(getCount(model)) + "</div>"
|
||||
}
|
||||
```
|
||||
|
||||
### Counter with Html Module (Type-safe)
|
||||
|
||||
The same counter using the type-safe Html module:
|
||||
|
||||
```lux
|
||||
fn view(model: Model): String = {
|
||||
let count = getCount(model)
|
||||
let display = Html.div([Html.class("display")], [Html.text(toString(count))])
|
||||
Html.render(display)
|
||||
}
|
||||
```
|
||||
|
||||
Compile with:
|
||||
```bash
|
||||
lux compile examples/web/counter_html.lux --target js -o examples/web/counter_html.js
|
||||
```
|
||||
|
||||
## The Elm Architecture (TEA)
|
||||
|
||||
Both examples follow the TEA pattern:
|
||||
|
||||
- **Model**: Application state (`Counter(Int)`)
|
||||
- **Msg**: Events (`Increment`, `Decrement`, `Reset`)
|
||||
- **Update**: State transitions `(Model, Msg) -> Model`
|
||||
- **View**: HTML rendering `Model -> Html` or `Model -> String`
|
||||
|
||||
## Available Modules
|
||||
|
||||
### Html Module
|
||||
|
||||
Type-safe HTML construction:
|
||||
|
||||
```lux
|
||||
// Elements
|
||||
Html.div(attrs, children)
|
||||
Html.span(attrs, children)
|
||||
Html.button(attrs, children)
|
||||
Html.input(attrs, children)
|
||||
Html.h1(attrs, children)
|
||||
// ... 30+ elements
|
||||
|
||||
// Attributes
|
||||
Html.class("name")
|
||||
Html.id("id")
|
||||
Html.href("url")
|
||||
Html.style("...")
|
||||
Html.attr("name", "value")
|
||||
|
||||
// Events
|
||||
Html.onClick(handler)
|
||||
Html.onInput(handler)
|
||||
Html.on("event", handler)
|
||||
|
||||
// Text
|
||||
Html.text("content")
|
||||
|
||||
// Rendering
|
||||
Html.render(node) // -> String (for innerHTML)
|
||||
Html.renderToDom(node) // -> Element (for appendChild)
|
||||
```
|
||||
|
||||
### Dom Effect
|
||||
|
||||
Direct DOM manipulation:
|
||||
|
||||
```lux
|
||||
fn main(): Unit with {Dom} = {
|
||||
match Dom.querySelector("#app") {
|
||||
Some(el) => Dom.setTextContent(el, "Hello!"),
|
||||
None => ()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Available operations:
|
||||
- `querySelector`, `querySelectorAll`, `getElementById`
|
||||
- `createElement`, `createTextNode`, `appendChild`
|
||||
- `setTextContent`, `getTextContent`, `setInnerHtml`
|
||||
- `setAttribute`, `getAttribute`, `addClass`, `removeClass`
|
||||
- `addEventListener`, `focus`, `blur`
|
||||
- `getValue`, `setValue` (for inputs)
|
||||
- `scrollTo`, `getWindowSize`, `getBoundingClientRect`
|
||||
|
||||
## How It Works
|
||||
|
||||
1. Lux code is compiled to JavaScript using `lux compile --target js`
|
||||
2. The HTML page loads the compiled JS
|
||||
3. A minimal runtime handles the TEA loop:
|
||||
- `luxInit_lux()` creates initial state
|
||||
- `luxUpdate_lux(model, msg)` handles state updates
|
||||
- `luxView_lux(model)` renders HTML
|
||||
- `dispatch(msg)` triggers updates and re-renders
|
||||
|
||||
## TEA Runtime
|
||||
|
||||
For applications using the Html module with event handlers, you can use the built-in TEA runtime:
|
||||
|
||||
```javascript
|
||||
Lux.app({
|
||||
init: luxInit_lux(),
|
||||
update: (model, msg) => luxUpdate_lux(model, msg),
|
||||
view: (model, dispatch) => luxView_lux(model),
|
||||
root: "#app"
|
||||
});
|
||||
```
|
||||
|
||||
Or for string-based views:
|
||||
|
||||
```javascript
|
||||
Lux.simpleApp({
|
||||
init: luxInit_lux(),
|
||||
update: (model, msg) => luxUpdate_lux(model, msg),
|
||||
view: (model) => luxView_lux(model),
|
||||
root: "#app"
|
||||
});
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
To modify an example:
|
||||
|
||||
1. Edit the `.lux` file
|
||||
2. Recompile: `lux compile <file>.lux --target js -o <file>.js`
|
||||
3. Refresh the browser
|
||||
Reference in New Issue
Block a user