serez-ui
React-style UI library for Serez Code. Components, a transparent Virtual DOM, and hooks — the same code runs in the terminal (TUI) or in a real native window (GUI).
Install
sz install serez-ui
The model
You write components as classes that extend Window and return JSX from render(). State lives inthis fields; mutating it inside an event handler triggers a re-render through the Virtual DOM. JSX is written in .szx files and translated to plain .sz before running.
Quick start
A counter, rendered in a real native window:
import "serez-ui"
class Counter:Window {
public Counter() {
super()
this.count = 0
}
public render() {
return (
<div>
<h1>Counter</h1>
<hr />
<h2>{this.count}</h2>
<Button onClick={() => { this.count = this.count + 1 }}>Increment</Button>
<Button onClick={() => { this.count = 0 }}>Reset</Button>
</div>
)
}
}
let app = new Counter()
let loop = new GuiEventLoop(app)
loop.setTitle("Counter")
loop.setSize(520, 420)
loop.start()Building .szx files
JSX lives in .szx files. The wrapper translates and runs them in one step:
# Windows & "serez-ui\tools\szx.ps1" apps\counter.szx # Linux / macOS ./serez-ui/tools/szx.sh apps/counter.szx
Built-in components
Structure uses primitive HTML-like tags the renderer draws directly (div, h1, h2, h3, p, span, hr, ul, li, section, form). For interaction, serez-ui ships five form components:
| Component | Key props | Notes |
|---|---|---|
Button | onClick, disabled | Text is the children |
Input | value, placeholder, type, onChange, disabled | Password type masks input |
Select | value, options, onChange, disabled | Click cycles options |
Checkbox | checked, label, onChange, disabled | Click toggles |
Textarea | value, placeholder, rows, onChange, disabled | Multi-line input |
<Input value={this.name} placeholder="your name" onChange={(v) => { this.name = v }} />
<Select value={this.mode} options={["fast", "normal", "slow"]} onChange={(v) => { this.mode = v }} />
<Checkbox checked={this.agreed} label="I agree" onChange={(b) => { this.agreed = b }} />
<Button onClick={save} disabled={!this.canSave}>Save</Button>TUI and GUI
The same component runs in two renderers — just pick the event loop:
// Terminal (TUI) — draws with Unicode, keyboard + mouse
let loop = new EventLoop(app)
loop.start() // quit with q or Esc
// Native window (GUI) — pixels via the Gui backend
let loop = new GuiEventLoop(app)
loop.setTitle("My App")
loop.setSize(560, 460)
loop.start() // quit with Esc or the close buttonCSS with logic (.szs)
Style with a CSS dialect that supports reactive conditions. A selector can carry a condition evaluated against the state exposed by styleVars():
/* counter.szs */
:import {
count: count;
}
body (count == 0) { background-color: #0f172a; }
body (count != 0) { background-color: #14532d; }
h1 { color: #ffd166; }
Button { background-color: #2563eb; color: #ffffff; }Load the stylesheet into the loop:
loop.setStylesheet(parseCss(File.read("apps/counter.szs")))API surface
| Export | What it is |
|---|---|
Window | Base class for components |
h / VNode | Hyperscript + Virtual DOM node |
diff / Patch | Virtual DOM diffing |
useState / useEffect / memo | Hooks |
Renderer / EventLoop | TUI rendering + event loop |
GuiRenderer / GuiEventLoop | GUI rendering + event loop |
parseCss | .szs stylesheet parser |
Packaging
Ship a serez-ui app as a self-contained installer (the runtime travels inside, no Serez Code needed on the target) with serez-pack.