Local literal
Form input state. Tab selection. Filter chips. Anything the user mutates within the screen.
Xuda Developer Studio
Routes point to programs. Programs render the screen. Internally a program has four parts:
progFields (its reactive state), progDataSource (an optional binding to a
table or a subscription), progEvents (lifecycle and custom event handlers), and
progUi (the tree of nodes that renders to DOM). Programs compose by referencing each other
with xu-panel.
project.programs[id].
The shape is small and stable. properties tells the studio what kind of program this is and
how to label it in menus. progFields, progDataSource,
progEvents, and progUi hold the actual behavior.
{
_id: 'prog_user_detail',
properties: {
menuType: 'component',
renderType: 'form',
menuName: 'User detail',
menuTitle: 'User detail'
},
progFields: [
{ data: { field_id: '_id', type: 'literal' } },
{ data: { field_id: 'name', type: 'literal' } },
{ data: { field_id: 'email', type: 'literal' } },
{ data: { field_id: 'fullLabel', type: 'virtual' },
props: { propExpressions: { fieldValue: '@name + \" <\" + @email + \">\"' } } }
],
progDataSource: {
dataSourceType: 'table',
dataSourceTableId: 'tbl_users',
dataSourceQuery: '({ _id: @route.params.id })',
dataSourceLimit: 1
},
progEvents: [
{ name: 'on_mounted', workflow: [/* ... */] },
{ name: 'on_route_changed', workflow: [/* ... */] }
],
progUi: [/* element tree, see the next section */]
}
Each program field has the same { data, props } structure you saw in tables and globals.
The set of types is the same: literal, virtual, datasource,
plugin. The difference is the lifetime: program fields live for as long as the program is
mounted. When the user navigates away, they reset.
Form input state. Tab selection. Filter chips. Anything the user mutates within the screen.
Totals, formatted strings, summaries. Pure functions of other fields. Re-evaluated when dependencies change.
The fields exposed by the program's progDataSource. They map row columns onto local field ids.
A field whose value comes from a library plugin call. The runtime invokes the plugin on mount and on dependency change.
The form widget renders a required indicator and the workflow validates before submission.
Initial value applied when the program mounts and the field has no other source.
A program with no datasource is a static form. A program with a table datasource is a list
or a detail view. A program with an array datasource iterates over an in-memory list. A
program with a subscription datasource receives push updates from the broker chain. The
renderType property tells the runtime which iteration model to use.
The most common kind. Set dataSourceTableId, an optional query, and order/limit. Combine with renderType: 'list' for a list, or renderType: 'form' + dataSourceLimit: 1 for a detail view.
Useful when you have data in a global or computed in a virtual field. Set dataSourceInput to an expression that evaluates to an array. _KEY and _VAL are exposed per row.
Open a subscription on the native Xuda backend (or any plugin that supports it). New events flow into the program scope; the tree re-renders when the data changes.
Omit progDataSource entirely. The program renders once, with whatever progFields it has, and waits for events.
A workflow is a list of steps. Each step has an action (built in: update,
navigate, upsert, delete, toast, alert,
plugin) and a payload. Steps run in order; later steps see the state mutations of earlier
steps. The runtime fires built-in events you can listen to (on_mounted,
on_unmounted, on_route_changed) and you can dispatch your own custom events.
progEvents: [
{
name: 'on_mounted',
workflow: [
{ data: { action: 'plugin',
plugin: '@xuda.io/xuda-library-plugin-firebase-auth',
method: 'currentUser',
resultField: 'localUser' } },
{ data: { action: 'update',
name: { value: '@title: \"Welcome \" + @localUser.name' } } },
{ data: { action: 'toast',
name: { value: '\"Loaded\"' } } }
]
}
]
xu-panel[program].
Build small focused programs and compose them. A header program, a sidebar program, a content program.
The host program drops an <xu-panel program="prog_header"></xu-panel> wherever it
wants the embedded one to render. The runtime mounts the inner program and gives it its own scope. The
outer scope is still readable through globals.
progUi: [
{ type: 'element', tagName: 'div', attributes: { class: 'app-shell' },
children: [
{ type: 'element', tagName: 'xu-panel', attributes: { program: 'prog_header' } },
{ type: 'element', tagName: 'main', attributes: { class: 'app-content' },
children: [
{ type: 'element', tagName: 'xu-panel', attributes: { program: 'prog_user_detail' } }
]
},
{ type: 'element', tagName: 'xu-panel', attributes: { program: 'prog_footer' } }
]
}
]
The studio uses renderType to pick a default editor layout (a single record form, a list
table, a detail card). The runtime uses it to decide whether to wrap the tree in an
xu-single-view or an xu-multi-view. You can override the wrapping yourself
inside progUi; the property just sets the default.
Wraps the tree in xu-single-view. Used for create/edit screens and most static pages.
Wraps the tree in xu-multi-view. The runtime iterates over the datasource and renders the tree once per row, exposing _KEY and _VAL.
Single record, richer default layout. Same wrapping as form; different studio defaults.
A reusable fragment for embedding via xu-panel. Hidden from the navigation menu.