A tiny virtual DOM library
Dependencies
A tiny virtual DOM library ported from Respo.rs.
raf_loop:
if physical_equal(store.val, prev_store) → skip (same heap object)
if store.val == prev_store → skip (structurally equal)
else → diff vdom, patch DOM// ❌ WRONG — mut field, in-place mutation
struct Store {
mut count : Int // mut field!
} derive(Eq)
fn Store::update(self : Store, op : ActionOp) -> ActionOp? {
self.count 1 // mutates in place — prev_store sees this too
None
}
// caller (broken pattern):
ignore(app.store.val.update(op))
app.store.val = { ..app.store.val } // shallow copy, but fields already mutated
// Result: store.val == prev_store → render skipped → DOM frozen// ✅ CORRECT — no mut, update returns new store
struct Store {
count : Int
} derive(Eq)
fn Store::update(self : Store, op : ActionOp) -> (Store, ActionOp?) {
match op {
Increment => ({ ..self, count: self.count + 1 }, None)
}
}
// caller (correct pattern):
let (new_store, maybe_op) = app.store.val.update(op)
app.store.val = new_store
// Result: physical_equal fails (new struct) → diff runs → DOM updated{ ..self, ui: { ..self.ui, username: value } }@respo.set_debug_mode(true) // add near app startup, remove after debuggingmoon add tiye/respotype ObscureStatefn[Model : Eq, ActionOp, G] RespoApp::render_loop(self : RespoApp[Model], renderer : () -> RespoNode[ActionOp, G] raise RespoCommonError, dispatch_action : (ActionOp) -> Unit raise RespoCommonError) -> Unitpub(all) struct RespoStatesTree {
backup : Json?
cursor : Vector[String]
branches : HashMap[String, RespoStatesTree]
// private fields
}impl Default for RespoStatesTreeimpl Eq for RespoStatesTreeimpl Show for RespoStatesTreeimpl ToJson for RespoStatesTreeimpl FromJson for RespoStatesTreefn[T : Default + FromJson + ToJson] RespoStatesTree::local_pair(self : RespoStatesTree) -> (T, RespoCursor[T])let (state, cursor) = states.local_pair();impl Eq for RespoUpdateStateimpl ToJson for RespoUpdateStatefn[T, G] collect_global_handlers(tree : RespoNode[T, G], coord : Vector[RespoCoord]) -> Array[((G, DispatchFn[T]) -> Unit raise RespoCommonError, Vector[RespoCoord])]fn debug_event(event_type : String, details : String) -> Unitfn debug_log(message : String) -> Unitfn debug_render(message : String) -> Unitfn[T, G] dispatch_global_event(event : G, tree : RespoNode[T, G], dispatch : DispatchFn[T]) -> Unit raise RespoCommonErrorfn mark_need_rerender() -> Unitfn[T, U : Eq, G] render_node(mount_target : Node, store : Ref[U], renderer : () -> RespoNode[T, G] raise RespoCommonError, dispatch_action : (T) -> Unit raise RespoCommonError, _interval : Float?) -> Unit raise RespoCommonError// WRONG — mut field + in-place mutation
struct Store { mut count : Int } derive(Eq)
fn Store::update(self : Store, op : Op) -> Op? {
self.count 1 // mutates in place — prev_store sees this too!
None
}
// CORRECT — no mut, update returns new store
struct Store { count : Int } derive(Eq)
fn Store::update(self : Store, op : Op) -> (Store, Op?) {
({ ..self, count: self.count + 1 }, None)
}
// caller:
let (new_store, maybe_op) = app.store.val.update(op)
app.store.val = new_storefn set_debug_mode(enabled : Bool) -> Unitlet ui_center : Stringlet ui_column : Stringlet ui_column_dispersive : Stringlet ui_column_evenly : Stringlet ui_column_parted : Stringlet ui_font_code : Stringlet ui_font_fancy : Stringlet ui_font_normal : Stringlet ui_row : Stringlet ui_row_center : Stringlet ui_row_dispersive : Stringlet ui_row_evenly : Stringlet ui_row_middle : Stringlet ui_row_parted : StringA tiny virtual DOM library
Dependencies