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