Preskoči na vsebino

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.

OrderLifecycleFulfillment/orders/track
Orbital Unit = Entity + Traits + Pages

Kako render-ui deluje

["render-ui", "slot", { "type": "pattern", ...props }]
ArgumentDescription
"slot"Where on the page the component renders
{ "type": "..." }Which pattern component to use
...propsPattern-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.

SlotTypical use
mainPrimary content area
modalModal dialogs (forms, confirmations)
drawerSide panel (detail view)
sidebarPersistent side navigation
overlayFull-screen overlays
hud-top / hud-bottomPersistent headers/footers
toastNotification 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 submitEvent and cancelEvent (not onSubmit/onCancel — those are deprecated).


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:

Statemain slot renders
listingentity-table with row actions
viewingentity-detail with fields
editingform in edit mode
creatingform with all fields

Referenca lastnosti akcij

Actions are defined inside the pattern props, not as separate patterns.

PatternHow to wire actions
entity-tableitemActions: [{ "event": "EDIT", "label": "Edit" }]
entity-detailactions: [{ "event": "EDIT", "label": "Edit" }]
form-sectionsubmitEvent: "SAVE", cancelEvent: "CANCEL"
page-headeractions: [{ "event": "CREATE", "label": "New" }]
empty-stateactions: [{ "event": "CREATE", "label": "Add" }]

Vezave v lastnostih vzorcev

Pattern props accept bindings to read live data:

BindingResolves to
@entity.fieldCurrent entity field value
@payload.fieldEvent payload field
@stateCurrent state name
@nowCurrent timestamp

Example:

{
"tip": "stats",
"naziv": "Cart Total: $@entity.total"
}

Naslednji koraki