Builtin Library
README.md
edui (module)
The editor UI framework, built on the CSS-parity ui.* surface. edui is
editor-only — gameplay and normal UI author raw ui.* widget trees
({ type, style, props, children }) and need no framework. edui provides the
one thing a framework earns its keep for: editor chrome — a reactive app, a
dock shell, and chrome primitives (panels, trees, toolbars, inspector rows,
context menus, drag-and-drop). It replaces the deprecated zui for the editor.
The reactive core (edui.app)
ui.* dispatches interaction through string callback ids — a widget
carries props.onClick = "<id>", and the screen's registered env receives
onCallback(id, data). Closures can't cross the FFI boundary, so raw ui.*
makes you manage those ids by hand.
An edui app hides that. During a build it allocates an id per closure and
records id→closure; its single onCallback looks the id up, calls the closure,
and rebuilds:
local edui = require("@builtin::modules.edui")
local count = 0
local app = edui.createApp("counter", { layer = editorMask })
app:mount(function(a)
return {
type = "vertical",
children = {
{ type = "label", props = { text = "count: " .. count } },
{ type = "button", props = { text = "+1",
onClick = a:cb(function() count += 1 end, "inc") } },
},
}
end)
app:cb(closure, key?)— allocate a callback id forclosure. Pass a stablekeyso the id survives rebuilds (required for focus / drag /ui.widgetState).app:dispatch(id, data)— what the broadcast calls; routes id→closure and rebuilds. Returns whether this app owned the id.app:markDirty()— request a rebuild (coalesced during an in-progress build).app:rebuild()/app:mount(fn)/app:unmount()— lifecycle.edui.current()— the app whose builder is running (the primitives use it so you don't thread the app through every call).
Builder and handler errors are logged, never thrown — one bad build never wedges the editor.