MoonBit Hypermedia X - A type-safe HDA library for MoonBit/Wasm
Dependencies
{
"deps": {
"f4ah6o/mhx": "0.1.0"
}
}<!-- Simple GET request -->
<button mx-get="/api/data" mx-target="#result">
Load Data
</button>
<!-- POST with trigger modifiers -->
<form mx-post="/api/submit" mx-trigger="submit" mx-swap="outerHTML">
<input name="email" type="email" />
<button type="submit">Submit</button>
</form>
<!-- Click with delay and filter -->
<button mx-get="/api/action"
mx-trigger="click[ctrlKey] delay:500ms">
Ctrl+Click (with 500ms delay)
</button>
<!-- Debounced input -->
<input mx-get="/api/search"
mx-trigger="input changed debounce:300ms"
mx-target="#search-results"
name="q" />| Attribute | Description |
|---|---|
| mx-get | Issue GET request to URL |
| mx-post | Issue POST request to URL |
| mx-put | Issue PUT request to URL |
| mx-patch | Issue PATCH request to URL |
| mx-delete | Issue DELETE request to URL |
| mx-trigger | Event that triggers the request |
| mx-target | CSS selector for response target |
| mx-swap | How to swap the response into DOM |
| mx-sync | Request synchronization strategy |
| mx-vals | JSON values to include in request |
event[filter] modifier:value, event2[filter2]| Strategy | Description |
|---|---|
| innerHTML | Replace inner content (default) |
| outerHTML | Replace entire element |
| beforebegin | Insert before element |
| afterbegin | Insert at start of element |
| beforeend | Insert at end of element |
| afterend | Insert after element |
| delete | Remove the element |
| none | No swap, just trigger events |
src/
+-- ffi/ # FFI bindings + mhx_ffi.js
| +-- element.mbt, document.mbt, event.mbt
| +-- fetch.mbt, mutation_observer.mbt
| +-- mhx_ffi.js # JS glue code
+-- event/ # Event system
| +-- delegation.mbt, cache.mbt, handler.mbt, timing.mbt
+-- network/ # HTTP layer
| +-- request.mbt, manager.mbt, async_fetch.mbt
+-- swap/ # DOM swap operations
+-- core/ # Main integration
+-- mhx.mbt, error.mbt// Initialize mhx on document load
fn main {
@core.init_mhx()
}// Process newly added elements
let element = document.query_selector("#new-content")
@core.process(element)// Set custom error handler
@core.set_error_handler(fn(error : MhxError) {
match error {
Parse(msg, pos) => console.error("Parse error: " + msg)
Network(status, msg) => console.error("Network error: " + msg)
Timeout => console.error("Request timed out")
_ => console.error("Error: " + error.to_string())
}
})# Check types
moon check --target js
# Run tests
moon test --target js
# Format code
moon fmt
# Build
moon build --target js| Feature | htmx | mhx |
|---|---|---|
| Language | JavaScript | MoonBit/Wasm |
| Attribute prefix | hx-* | mx-* |
| Parsing | Regex/string split | Parser combinator |
| Type safety | Runtime | Compile-time |
| Error messages | Generic | Precise location |
| Bundle size | ~14KB gzip | <10KB (estimated) |
| DOM interop | Native | WasmGC + externref |
// Using generic attr function for mx-* attributes
let button = @tmpx.button(
[
@tmpx.attr("mx-get", "/api/data"),
@tmpx.attr("mx-target", "#result"),
@tmpx.attr("mx-swap", "innerHTML"),
],
[@tmpx.text("Load Data")],
)fn ticket_card(id : Int, title : String) -> @tmpx.Node {
@tmpx.div(
[
@tmpx.class_("card"),
@tmpx.attr("mx-get", "/partials/ticket/\{id}"),
@tmpx.attr("mx-target", "#pane-center"),
@tmpx.attr("mx-swap", "innerHTML"),
@tmpx.attr("mx-trigger", "click"),
],
[
@tmpx.h2([], [@tmpx.text("Ticket #\{id}")]),
@tmpx.p([], [@tmpx.text(title)]),
],
)
}
fn search_form() -> @tmpx.Node {
@tmpx.input_(
[
@tmpx.type_("text"),
@tmpx.name_("q"),
@tmpx.attr("mx-get", "/api/search"),
@tmpx.attr("mx-trigger", "input changed debounce:300ms"),
@tmpx.attr("mx-target", "#search-results"),
],
)
}Server (MoonBit + tmpx) Browser (MoonBit/Wasm + mhx)
+------------------------+ +---------------------------+
| Generate HTML with | | Parse mx-* attributes |
| mx-* attributes using | ----> | Handle events |
| tmpx templates | <---- | Fetch HTML fragments |
| Return HTML fragments | | Swap into DOM |
+------------------------+ +---------------------------+moon -C mhx.mbt build --target jsMoonBit Hypermedia X - A type-safe HDA library for MoonBit/Wasm
Dependencies