One page per element and API group of zgx-script. Each gives the signature, every option with its type and default, a short example and the gotchas. The examples are complete scripts: cargo test -p zgx-script --test reference_docs runs every one headless and type checks it in strict mode.
| Page | |
|---|---|
| Containers | column, row, div, overlay, grid |
| Text | text, rich, span, markdown |
| Controls | button, input, textarea, checkbox, slider, progress |
| Images and canvas | image, svg, canvas, path, linear, bitmap, shader |
| Scrolling | scroll, scroll_x, list |
| Dynamic content | show, switch, each, presence |
| Overlays and menus | modal, popover, menu, menu_item, submenu, context_menu |
| Web views, terminals, commands | webview, web, terminal, term, command |
| State and components | state, shared, persist, use_state, computed, effect, batch, ref, component, on_mount, slot, contribute, actions |
| Animation | the anime global (anime.js v4), tween, spring, loop |
| Properties | every style property, grouped |
| Design systems | variants, raw, theme.strict: component variants and the design lint |
| Events | pointer, keyboard, focus, lifecycle, drag and drop |
| App structure | splitting an app across modules with shared state |
Signatures are Luau types from zgx.d.luau, the file editors and zgx check use. Its export types are global type names a script can use in its own annotations:
| Type | |
|---|---|
Node |
what element functions return; a child |
Child |
a node, a string (text, {name} shows state), a function returning text, a list of them, false or nil |
State<T> |
Rust-owned state holding a T (see State) |
Reactive<T> |
what a property takes: a T, a state of a T, a function returning one, or a binding |
Props |
every element's properties: styles, identity, events (no children) |
ContainerProps |
Props and children |
Styles |
plain style values, for hover, active, focus, disabled |
Color, Length |
"#rrggbb", "rgb(…)", 0xrrggbb; points or "50%", "auto" |
Element, Ref |
a mounted node, and what follows one (see Events) |
Merge<A, B> |
A with B's properties: Merge<ContainerProps, { title: string }> |
VariantProps<R> |
a ui.variants recipe's axes as props (see Design systems) |
Each element function also has its own props type (InputProps, ListProps, EachOptions…), named on its page. Every props and options table is closed: an unknown key is an error, which luau-lsp reports as the key's type not being number (Expected this to be 'number', but got '"bgg"', for bgg). A missing required option (an input's value) is reported as a missing field.
zgx check app.luau (or a directory) runs luau-lsp in strict mode with these types; scripting has the editor setup. In a debug build a hot-reloading host runs the same check after every save and shows the errors in the window's banner, when luau-lsp is installed.
Luau infers a callback's parameters from how its body uses them when the callback is passed to a generic function, which misfires, so the few callbacks whose argument is the script's own data take it as any: each's row function, presence's content function, drag payloads, a web page's messages. Annotate those parameters to have them checked:
type Task = { id: string, title: string, done: boolean }
local tasks = ui.state("tasks", {} :: { Task })
return ui.each(tasks, function(task: Task)
return ui.text { task.title }
end)State takes the type of its initial value. Give nil and empty tables a type, as above: ui.state("selected", nil :: string?).