Integration Guide
The Property System is a standalone package, but it serves as the configuration foundation for higher-level Vyuh CDX editors such as the Form Editor and Dashboard Editor. This guide explains how those tools use typed properties, control abstractions, editors, and converters without exposing raw reactive_forms APIs by default.
Architecture Context
Used by the Form Editor
The Form Editor uses the Property System to define editable configuration for fields, structural blocks, validations, conditions, actions, layouts, and reference providers. Each ItemType exposes a fresh PropertyCollection for its base and item-specific properties. Each ItemInstance owns that collection and bridges PropertyCollection.valueChanges into MobX so the canvas and properties panel stay reactive.
FormEditorRegistry is also responsible for registering property-system dependencies. When a field, condition, action, layout, or provider type is registered, its declared requiredConverters and requiredEditors are added to the global PropertySystem registry with idempotent type or custom-key registration.
Field Property Collections
When a user adds a "Text Field" to a form in the editor, the field's settings panel is backed by a PropertyCollection:
// Conceptual: how a form editor ItemType creates field properties
PropertyCollection buildTextFieldProperties() {
final b = PropertyCollectionBuilder();
b.group('field', 'Field Settings');
b.string('label', 'Label', required: true);
b.string('placeholder', 'Placeholder');
b.string('helpText', 'Help Text');
b.group('validation', 'Validation');
b.boolean('required', 'Required', defaultValue: false);
b.optionalInteger('minLength', 'Min Length');
b.optionalInteger('maxLength', 'Max Length');
b.optionalText('pattern', 'Pattern (regex)');
b.group('appearance', 'Appearance');
b.boolean('multiline', 'Multiline', defaultValue: false);
b.integer('maxLines', 'Max Lines', defaultValue: 1,
visibleCondition: PropertyCollectionBuilder.whenTrue('multiline'));
return b.buildCollection();
}Key Integration Points
| Form Editor Concept | Property System Type |
|---|---|
ItemType.properties | Fresh PropertyCollection for a type's configurable properties |
ItemInstance.properties | Instance-owned PropertyCollection bridged to MobX |
| Properties panel | PropertyCollectionEditor |
| Custom property widgets | PropertyEditor<T> registered by type or custom key |
| Import/export | JsonConverter<T> plus PropertyCollection.toJson() / fromJson() |
| Dependent editor fields | visibleCondition, enabledCondition, and PropertyDerivation |
| Specialized field selectors | Custom-key editors such as field_selector |
Used by the Dashboard Editor
The Dashboard Editor uses the Property System to configure dashboard widgets (charts, tables, metrics). Each widget type has a PropertyCollection for its settings.
Widget Property Collections
// Conceptual: how the dashboard editor creates chart properties
PropertyCollection buildChartWidgetProperties() {
final b = PropertyCollectionBuilder();
b.group('data', 'Data Source');
b.string('title', 'Widget Title', required: true);
b.enumeration<String>('chartType', 'Chart Type',
options: [
EnumOption('bar', 'Bar Chart'),
EnumOption('line', 'Line Chart'),
EnumOption('pie', 'Pie Chart'),
],
defaultValue: 'bar');
b.group('display', 'Display Options');
b.boolean('showLegend', 'Show Legend', defaultValue: true);
b.boolean('showGrid', 'Show Grid', defaultValue: true,
visibleCondition: PropertyCollectionBuilder.whenIn<String>(
'chartType', {'bar', 'line'}));
return b.buildCollection();
}Key Integration Points
| Dashboard Editor Concept | Property System Type |
|---|---|
| Widget configuration | PropertyCollection |
| Widget settings panel | PropertyCollectionEditor |
| Data source selection | UnionProperty |
| Chart type selection | EnumProperty<T> |
| Conditional display options | PropertyCondition |
| Widget config serialization | toJson() / fromJson() |
Using PropertySystem in Your Own Code
You do not need to use the Form Editor or Dashboard Editor to benefit from the Property System. Common standalone use cases:
Settings Panels
class AppSettingsPanel extends StatelessWidget {
final PropertyCollection settings;
const AppSettingsPanel({super.key, required this.settings});
@override
Widget build(BuildContext context) {
return PropertyCollectionEditor(
collection: settings,
showGroups: true,
);
}
}Configuration Dialogs
Future<Map<String, dynamic>?> showConfigDialog(
BuildContext context,
PropertyCollection config,
) {
return showDialog<Map<String, dynamic>>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Configure'),
content: SizedBox(
width: 400,
child: PropertyCollectionEditor(
collection: config,
showGroups: true,
disposeCollection: false,
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Cancel'),
),
FilledButton(
onPressed: () {
if (config.isValid) {
Navigator.pop(context, config.toJson());
}
},
child: const Text('Apply'),
),
],
),
);
}Headless (No UI)
The Property System can be used without any UI for pure validation and serialization:
final b = PropertyCollectionBuilder();
b.string('name', 'Name', required: true);
b.integer('age', 'Age', validators: [PropertyValidators.min(0)]);
final collection = b.buildCollection();
collection.fromJson({'name': 'Alice', 'age': 30});
print(collection.isValid); // true
print(collection.toJson()); // {name: Alice, age: 30}Next Steps
- Building Forms Guide -- Complete form-building walkthrough
- Dashboard Config Example -- Full dashboard widget configuration
- Best Practices -- Property design guidelines