The vocabulary a view tree is described with, and the two contracts a renderer
consumes it through. Shared by the platform UI libraries — sui, aui, wui,
cui, qui — and sitting above rui,
which owns state and change propagation.
nui describes what a node is. It renders nothing.
A view tree is consumed in one of two ways, and which one is not a matter of taste — it is dictated by the host:
- Pull — the host diffs and re-renders on its own (SwiftUI, Jetpack Compose).
The native renderer walks the tree on demand and asks for one thing at a time.
Diffing on the Haxe side would duplicate work the framework already does.
→
NodeSource<Node> - Push — the host diffs nothing (Qt/Silica, a terminal). It has to be told
what changed, so Haxe holds the tree, compares it with the previous one, and
applies targeted patches.
→
Node+PropValue+NodeSink<Native>
Both express the same vocabulary: type, children, key, typed properties, an
ordered modifier chain, actions.
import nui.Node;
import nui.PropValue;
var view = new Node("VStack")
.child(new Node("Text").prop("text", PString("Bonjour")))
.child(new Node("Button", "add").prop("label", PString("Ajouter")));Documentation: docs/ (docsify — docsify serve docs, or any static server).
Usually transitive: a backend that has adopted the model declares it. Standalone:
haxelib git nui https://github.com/lapavoiserie/nuiYoung. The vocabulary and both contracts are defined and covered by
test/Check.hx (23 checks, including a toy implementation of each contract to
prove both are satisfiable):
haxe -cp src -cp test -main Check --interp # rapide
haxe -cp src -cp test -main Check -cpp bin && ./bin/Check # et sur cible compiléeRun both. --interp tolerates things a compiled target does not — notably
switch on a null enum, which segfaults under hxcpp and is exactly how an absent
property behaves.
No backend has adopted it yet — that is the next step, aui first, since its
existing bridge is a strict subset of sui's and the gap is pure filling-in.
MIT.