Vzorci UI in render-ui
Source:
tests/schemas/08-patterns.orb
Orb UI is driven entirely by render-ui effects inside state machine transitions. There is no JSX, no template files, no separate component tree — the state machine is the UI logic.
Kako render-ui deluje
["render-ui", "slot", { "type": "pattern", ...props }]
| Argument | Description |
|---|---|
"slot" | Where on the page the component renders |
{ "type": "..." } | Which pattern component to use |
...props | Pattern-specific configuration |
To clear a slot:
[
"izrisi-vmesnik",
"slot",
null
]
Rezine
Slots divide the page into named regions. Each slot is owned by one trait at a time.
| Slot | Typical use |
|---|---|
main | Primary content area |
modal | Modal dialogs (forms, confirmations) |
drawer | Side panel (detail view) |
sidebar | Persistent side navigation |
overlay | Full-screen overlays |
hud-top / hud-bottom | Persistent headers/footers |
toast | Notification toasts |
Kategorije vzorcev
Prikazni vzorci
entity-table — Data table with columns, sorting, and row actions.
[
"izrisi-vmesnik",
"main",
{
"tip": "entity-table",
"entiteta": "Product",
"columns": [
"name",
"price",
"stock",
"category"
],
"itemActions": [
{
"dogodek": "VIEW",
"oznaka": "View"
},
{
"dogodek": "EDIT",
"oznaka": "Edit"
},
{
"dogodek": "DELETE",
"oznaka": "Delete"
}
]
}
]
entity-detail — Read-only detail view for a single record.
[
"izrisi-vmesnik",
"main",
{
"tip": "entity-detail",
"entiteta": "Product",
"polja": [
"name",
"description",
"price",
"stock",
"category"
]
}
]
stats — Dashboard stat cards (counts, totals, summaries).
[
"izrisi-vmesnik",
"main",
{
"tip": "stats",
"elementi": [
{
"oznaka": "Total Products",
"value": "@entiteta.count"
},
{
"oznaka": "Out of Stock",
"value": "@entiteta.outOfStock"
}
]
}
]
Obrazcni vzorci
form — Auto-generated form for an entity. Renders all fields or a specified subset.
[
"izrisi-vmesnik",
"main",
{
"tip": "form",
"entiteta": "Product",
"polja": [
{
"ime": "name",
"oznaka": "Product Name",
"obvezno": true
},
{
"ime": "description",
"oznaka": "Description",
"tip": "textarea"
},
{
"ime": "price",
"oznaka": "Price",
"tip": "number",
"obvezno": true
},
{
"ime": "stock",
"oznaka": "Stock",
"tip": "number"
},
{
"ime": "category",
"oznaka": "Category"
}
]
}
]
form-section — A form inside a modal or drawer, with submit/cancel wired to events.
[
"izrisi-vmesnik",
"modal",
{
"tip": "form-section",
"entiteta": "Task",
"polja": [
"title",
"priority",
"dueDate"
],
"submitEvent": "SAVE",
"cancelEvent": "CANCEL"
}
]
Important: Use
submitEventandcancelEvent(notonSubmit/onCancel— those are deprecated).
Navigacijski in naslovni vzorci
page-header — Page title with optional action buttons.
[
"izrisi-vmesnik",
"main",
{
"tip": "page-header",
"naziv": "Products",
"subtitle": "Manage your product catalog",
"actions": [
{
"dogodek": "CREATE",
"oznaka": "New Product",
"varianta": "primary"
}
]
}
]
breadcrumb — Navigation trail.
[
"izrisi-vmesnik",
"main",
{
"tip": "breadcrumb",
"elementi": [
{
"oznaka": "Products",
"pot": "/products"
},
{
"oznaka": "@entiteta.name"
}
]
}
]
Vzorci stanj
empty-state — Shown when a list has no items.
[
"izrisi-vmesnik",
"main",
{
"tip": "empty-state",
"naziv": "No products yet",
"opis": "Add your first product to get started",
"actions": [
{
"dogodek": "CREATE",
"oznaka": "Add Product"
}
]
}
]
loading-state — Spinner while data loads.
[
"izrisi-vmesnik",
"main",
{
"tip": "loading-state",
"naziv": "Loading products..."
}
]
UI voden s stanji: celoten primer
The power of render-ui is that it changes based on state. Different states render different components into the same slot. Here's the full ProductCRUD trait from 08-patterns.orb:
{
"ime": "ProductCRUD",
"povezanaEntiteta": "Product",
"kategorija": "interaction",
"strojStanj": {
"stanja": [
{
"ime": "listing",
"jeZacetno": true
},
{
"ime": "viewing"
},
{
"ime": "editing"
},
{
"ime": "creating"
}
],
"dogodki": [
{
"kljuc": "INIT",
"ime": "Initialize"
},
{
"kljuc": "VIEW",
"ime": "View Product",
"podatki": [
{
"ime": "id",
"tip": "niz",
"obvezno": true
}
]
},
{
"kljuc": "EDIT",
"ime": "Edit Product"
},
{
"kljuc": "CREATE",
"ime": "Create Product"
},
{
"kljuc": "SAVE",
"ime": "Save"
},
{
"kljuc": "CANCEL",
"ime": "Cancel"
},
{
"kljuc": "BACK",
"ime": "Back to List"
},
{
"kljuc": "DELETE",
"ime": "Delete Product",
"podatki": [
{
"ime": "id",
"tip": "niz",
"obvezno": true
}
]
}
],
"prehodi": [
{
"iz": "listing",
"dogodek": "INIT",
"do": "listing",
"ucinki": [
[
"pridobi",
"Product"
],
[
"izrisi-vmesnik",
"main",
{
"tip": "entity-table",
"entiteta": "Product",
"columns": [
"name",
"price",
"stock",
"category"
],
"itemActions": [
{
"dogodek": "VIEW",
"oznaka": "View"
},
{
"dogodek": "EDIT",
"oznaka": "Edit"
},
{
"dogodek": "DELETE",
"oznaka": "Delete"
}
]
}
]
]
},
{
"iz": "listing",
"dogodek": "VIEW",
"do": "viewing",
"ucinki": [
[
"pridobi",
"Product",
"@podatki.id"
],
[
"izrisi-vmesnik",
"main",
{
"tip": "entity-detail",
"entiteta": "Product",
"polja": [
"name",
"description",
"price",
"stock",
"category"
]
}
]
]
},
{
"iz": "listing",
"dogodek": "CREATE",
"do": "creating",
"ucinki": [
[
"izrisi-vmesnik",
"main",
{
"tip": "form",
"entiteta": "Product",
"polja": [
{
"ime": "name",
"oznaka": "Product Name",
"obvezno": true
},
{
"ime": "description",
"oznaka": "Description",
"tip": "textarea"
},
{
"ime": "price",
"oznaka": "Price",
"tip": "number",
"obvezno": true
},
{
"ime": "stock",
"oznaka": "Stock",
"tip": "number"
},
{
"ime": "category",
"oznaka": "Category"
}
]
}
]
]
},
{
"iz": "viewing",
"dogodek": "EDIT",
"do": "editing",
"ucinki": [
[
"izrisi-vmesnik",
"main",
{
"tip": "form",
"entiteta": "Product",
"mode": "edit"
}
]
]
},
{
"iz": "viewing",
"dogodek": "BACK",
"do": "listing",
"ucinki": [
[
"pojdi",
"/products"
]
]
},
{
"iz": "editing",
"dogodek": "SAVE",
"do": "viewing",
"ucinki": [
[
"shrani",
"update",
"Product",
"@entiteta"
],
[
"obvesti",
"success",
"Product saved successfully"
]
]
},
{
"iz": "editing",
"dogodek": "CANCEL",
"do": "viewing"
},
{
"iz": "creating",
"dogodek": "SAVE",
"do": "listing",
"ucinki": [
[
"shrani",
"update",
"Product",
"@entiteta"
],
[
"obvesti",
"success",
"Product created successfully"
],
[
"pojdi",
"/products"
]
]
},
{
"iz": "creating",
"dogodek": "CANCEL",
"do": "listing",
"ucinki": [
[
"pojdi",
"/products"
]
]
},
{
"iz": "listing",
"dogodek": "DELETE",
"do": "listing",
"ucinki": [
[
"shrani",
"delete",
"Product",
"@podatki.id"
],
[
"obvesti",
"info",
"Product deleted"
]
]
}
]
}
}
With pages:
"pages": [
{
"name": "ProductListPage",
"path": "/products",
"traits": [{ "ref": "ProductCRUD", "linkedEntity": "Product" }]
},
{
"name": "ProductDetailPage",
"path": "/products/:id",
"traits": [{ "ref": "ProductCRUD", "linkedEntity": "Product" }]
}
]
What the state machine renders per state:
| State | main slot renders |
|---|---|
listing | entity-table with row actions |
viewing | entity-detail with fields |
editing | form in edit mode |
creating | form with all fields |
Referenca lastnosti akcij
Actions are defined inside the pattern props, not as separate patterns.
| Pattern | How to wire actions |
|---|---|
entity-table | itemActions: [{ "event": "EDIT", "label": "Edit" }] |
entity-detail | actions: [{ "event": "EDIT", "label": "Edit" }] |
form-section | submitEvent: "SAVE", cancelEvent: "CANCEL" |
page-header | actions: [{ "event": "CREATE", "label": "New" }] |
empty-state | actions: [{ "event": "CREATE", "label": "Add" }] |
Vezave v lastnostih vzorcev
Pattern props accept bindings to read live data:
| Binding | Resolves to |
|---|---|
@entity.field | Current entity field value |
@payload.field | Event payload field |
@state | Current state name |
@now | Current timestamp |
Example:
{
"tip": "stats",
"naziv": "Cart Total: $@entity.total"
}
Naslednji koraki
- Guards & Business Rules — add conditions to control when transitions fire
- Cross-Orbital Communication — connect orbitals together
- Building a Full App — put multiple orbitals together