This document describes the operators available in the schema system for declarative UI logic.
- Data Access Operators
- Transformation Operators
- Action Operators
- Conditional Operators
- Comparison Operators
Access reactive store values.
Syntax:
{
$store: 'storeName.propertyPath';
}Examples:
// Simple property access
{
$store: 'userStore.name';
}
// Nested property access
{
$store: 'userStore.profile.email';
}
// Array access
{
$store: 'templateStore.templates';
}Notes:
- Returns an accessor (function) for reactive updates
- Cannot access entire store (must specify property)
- Automatically unwraps nested accessors
Transform arrays or single objects by selecting/reshaping properties.
Syntax:
{
$map: {
items: <source>,
select: { <key>: '<value>' | '$item.<path>' }
}
}Examples:
Transform array:
{
$map: {
items: { $store: 'templateStore.templates' },
select: {
id: '$item.id',
name: '$item.meta.name',
icon: '$item.meta.icon'
}
}
}
// Input: [{ id: '1', meta: { name: 'Default', icon: 'home' } }, ...]
// Output: [{ id: '1', name: 'Default', icon: 'home' }, ...]Transform single object:
{
$map: {
items: { $store: 'templateStore.currentTemplate' },
select: {
id: '$item.id',
name: '$item.meta.name',
icon: '$item.meta.icon'
}
}
}
// Input: { id: 'default', meta: { name: 'Default', icon: 'home' } }
// Output: { id: 'default', name: 'Default', icon: 'home' }With constants:
{
$map: {
items: [{ id: 1 }, { id: 2 }],
select: {
id: '$item.id',
type: 'template', // constant value
active: true
}
}
}
// Output: [{ id: 1, type: 'template', active: true }, ...]Notes:
- Use
$item.<path>to reference properties from source items - Supports both arrays and single objects
- Returns accessor if source is an accessor
- Nested property paths supported:
$item.user.profile.email
Extract specific properties from an object.
Syntax:
{
$pick: {
from: <source>,
props: ['<prop1>', '<prop2>', ...]
}
}Example:
{
$pick: {
from: { $store: 'userStore.profile' },
props: ['name', 'email']
}
}
// Input: { name: 'Alice', email: 'alice@example.com', id: '123', role: 'admin' }
// Output: { name: 'Alice', email: 'alice@example.com' }Use Cases:
- Simple property extraction (subset of object)
- For transformation/reshaping, use
$mapinstead
Evaluate JavaScript expressions with context variables.
Syntax:
{
$expr: '<javascript-expression>';
}Examples:
// Template literals
{
$expr: '`/space/${space.uuid}`';
}
// Calculations
{
$expr: 'count * 2 + 1';
}
// Conditionals
{
$expr: 'user.role === "admin" ? "Edit" : "View"';
}Notes:
- Has access to context variables
- Returns evaluated result
- Use with caution - errors return
undefined
Call store methods, with support for argument extraction from callbacks.
Syntax:
{
$action: 'storeName.methodName',
args?: [<arg1>, <arg2>, ...]
}Examples:
Simple action:
{
onClick: {
$action: 'modalStore.openModal',
args: ['settings']
}
}Extract property from callback argument:
{
onSelect: {
$action: 'templateStore.switchTemplate',
args: ['$arg.id'] // Extract .id from first callback argument
}
}
// When onSelect is called with { id: 'abc', name: 'Template' }
// Calls: templateStore.switchTemplate('abc')Deep property extraction:
{
onSubmit: {
$action: 'userStore.updateEmail',
args: ['$arg.user.profile.email']
}
}Pass entire argument:
{
onChange: {
$action: 'formStore.updateField',
args: ['$arg'] // Pass entire first argument
}
}Mixed arguments:
{
onUpdate: {
$action: 'store.update',
args: [
'$arg.id', // Extract from callback
'static-value', // Static value
{ $expr: 'context.id' } // Dynamic value
]
}
}Notes:
$arg- passes entire first callback argument$arg.<path>- extracts property from first callback argument- Automatically extracts
event.target.valuefrom DOM events - Supports relative path navigation for
routeStore.navigate
Conditional rendering based on boolean condition.
Syntax:
{
$if: {
condition: <boolean-expression>,
then: <schema-node>,
else?: <schema-node>
}
}Example:
{
type: '$if',
props: {
condition: { $store: 'modalStore.isOpen' },
then: {
type: 'we-modal',
props: { ... },
children: [ ... ]
},
else: {
type: 'we-text',
children: ['Modal closed']
}
}
}Notes:
elsebranch is optional- Automatically unwraps accessors in condition
Logical NOT operator.
Syntax:
{ $not: <boolean-expression> }Example:
{
condition: {
$not: {
$store: 'userStore.isLoggedIn';
}
}
}Equality comparison.
Syntax:
{ $eq: [<value1>, <value2>] }Example:
{
condition: {
$eq: [{ $store: 'userStore.role' }, 'admin'];
}
}Not equal comparison.
Syntax:
{ $ne: [<value1>, <value2>] }Example:
{
condition: {
$ne: [{ $store: 'templateStore.currentId' }, 'default'];
}
}Operators can be composed together for complex logic:
{
type: 'PopoverMenu',
props: {
// Transform array of templates
options: {
$map: {
items: { $store: 'templateStore.templates' },
select: {
id: '$item.id',
name: '$item.meta.name',
icon: '$item.meta.icon'
}
}
},
// Transform single template object
selectedOption: {
$map: {
items: { $store: 'templateStore.currentTemplate' },
select: {
id: '$item.id',
name: '$item.meta.name',
icon: '$item.meta.icon'
}
}
},
// Extract id from selected option and pass to action
onSelect: {
$action: 'templateStore.switchTemplate',
args: ['$arg.id']
}
}
}- Use
$mapfor transformation,$pickfor simple extraction - Use
$arg.<path>to extract properties in action callbacks - Keep expressions simple - complex logic should be in stores
- Leverage composition - combine operators for complex scenarios
- Handle edge cases - operators return safe defaults (empty arrays, undefined, etc.)
- Missing store/property: Returns
undefined - Invalid
$expr: Returnsundefinedand logs error - Non-array/object in
$map: Returns[] - Missing action method: Returns
undefined - Invalid
$argpath: Returnsundefined