Skip to content

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:

dart
// 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 ConceptProperty System Type
ItemType.propertiesFresh PropertyCollection for a type's configurable properties
ItemInstance.propertiesInstance-owned PropertyCollection bridged to MobX
Properties panelPropertyCollectionEditor
Custom property widgetsPropertyEditor<T> registered by type or custom key
Import/exportJsonConverter<T> plus PropertyCollection.toJson() / fromJson()
Dependent editor fieldsvisibleCondition, enabledCondition, and PropertyDerivation
Specialized field selectorsCustom-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 ​

dart
// 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 ConceptProperty System Type
Widget configurationPropertyCollection
Widget settings panelPropertyCollectionEditor
Data source selectionUnionProperty
Chart type selectionEnumProperty<T>
Conditional display optionsPropertyCondition
Widget config serializationtoJson() / 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 ​

dart
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 ​

dart
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:

dart
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 ​