Package

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:

ComponentKey propsNotes
ButtononClick, disabledText is the children
Inputvalue, placeholder, type, onChange, disabledPassword type masks input
Selectvalue, options, onChange, disabledClick cycles options
Checkboxchecked, label, onChange, disabledClick toggles
Textareavalue, placeholder, rows, onChange, disabledMulti-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 button

CSS 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

ExportWhat it is
WindowBase class for components
h / VNodeHyperscript + Virtual DOM node
diff / PatchVirtual DOM diffing
useState / useEffect / memoHooks
Renderer / EventLoopTUI rendering + event loop
GuiRenderer / GuiEventLoopGUI 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.