INTELLIGENT PROPERTY ORGANIZATION

Comprehensive guidelines for AI-assisted development within the Editor platform

🎯 Intelligent Property Organization Pattern

Overview

This document defines the standard pattern for organizing widget properties in GoGrab Space, ensuring consistency, clarity, and optimal user experience across all widgets.


🧩 Core Principles

1. Logical Grouping

Properties are organized by their purpose, not their technical type:

2. Theme vs Manual Styling

┌─────────────────────────────────────────────────┐
│          THEME-BASED (Default)                  │
│  ✅ Uses predefined theme classes               │
│  ✅ Consistent across platform                  │
│  ✅ Automatically responsive                    │
│  ✅ Platform-agnostic                           │
│  Example: "Primary", "Secondary", "Outline"     │
└─────────────────────────────────────────────────┘
                      ↓
              User selects "Custom"
                      ↓
┌─────────────────────────────────────────────────┐
│         MANUAL STYLES (Advanced)                │
│  🎨 Full control over individual properties     │
│  🎨 Background color, text color, borders       │
│  🎨 Saved as platform-agnostic JSON             │
│  🎨 Convertible to CSS, React Native, Flutter   │
└─────────────────────────────────────────────────┘

3. Conditional Visibility

Property groups should be contextually aware:


📋 Standard Property Group Structure

Button Widget (Reference Implementation)

/**
 * Group 1: Content (Order: 25)
 * What the button displays
 */
BUTTON_WIDGET_GROUP_CONTENT: PropertyGroup = {
  id: 'button-content',
  title: 'Content',
  icon: 'fa-font',
  order: 25,
  expanded: true,
  properties: [
    { key: 'properties.text', label: 'Text', type: 'string' },
    { key: 'properties.leftIcon', label: 'Left Icon', type: 'string' },
    { key: 'properties.rightIcon', label: 'Right Icon', type: 'string' },
  ],
};

/**
 * Group 2: Appearance (Order: 30)
 * Theme-based visual styling
 */
BUTTON_WIDGET_GROUP_APPEARANCE: PropertyGroup = {
  id: 'appearance',
  title: 'Appearance',
  icon: 'fa-palette',
  order: 30,
  expanded: true,
  properties: [
    {
      key: 'properties.buttonType',
      label: 'Variant',
      type: 'select',
      options: [
        { value: 'primary', label: 'Primary (Theme)' },
        { value: 'secondary', label: 'Secondary (Theme)' },
        { value: 'outline', label: 'Outline' },
        { value: 'text', label: 'Plain Text' },
        { value: 'custom', label: 'Custom (Manual)' }, // ✅ Triggers Custom Styles group
      ],
    },
    {
      key: 'properties.size',
      label: 'Size',
      type: 'select',
      options: [
        { value: 'small', label: 'Small' },
        { value: 'medium', label: 'Medium' },
        { value: 'large', label: 'Large' },
      ],
    },
    { key: 'properties.shape', label: 'Shape', type: 'select' },
    { key: 'properties.effect', label: 'Hover Effect', type: 'select' },
  ],
};

/**
 * Group 3: Custom Styles (Order: 31)
 * Manual style overrides - ONLY visible when variant = "Custom"
 */
BUTTON_WIDGET_GROUP_CUSTOM_STYLES: PropertyGroup = {
  id: 'button-custom-styles',
  title: 'Custom Styles',
  icon: 'fa-paint-brush',
  order: 31, // RIGHT AFTER Appearance
  expanded: true,
  isVisible: (widget: Widget) => getWidgetConfig(widget).buttonType === 'custom', // ✅ Conditional
  properties: [
    { key: 'styles.backgroundColor', label: 'Background Color', type: 'color', responsive: true },
    { key: 'styles.color', label: 'Text Color', type: 'color', responsive: true },
    { key: 'styles.borderWidth', label: 'Border Width', type: 'number', responsive: true },
    { key: 'styles.borderColor', label: 'Border Color', type: 'color', responsive: true },
    { key: 'styles.borderRadius', label: 'Border Radius', type: 'number', responsive: true },
    { key: 'styles.opacity', label: 'Opacity', type: 'number', responsive: true },
  ],
};

/**
 * Group 4: Actions (Order: 100)
 * Behavior and interactions
 */
BUTTON_WIDGET_GROUP_ACTION: PropertyGroup = {
  id: 'button-action',
  title: 'Actions',
  icon: 'fa-bolt',
  order: 100,
  expanded: false, // ✅ Collapsed by default (advanced)
  properties: [
    { key: 'properties.action', label: 'Action Type', type: 'select' },
    { key: 'properties.eventName', label: 'Event Name', type: 'string', visible: (w) => w.properties.action === 'event' },
    { key: 'properties.link', label: 'URL', type: 'string', visible: (w) => w.properties.action === 'link' },
    { key: 'properties.disabled', label: 'Disabled', type: 'boolean' },
  ],
};

🏗️ Architecture Integration

Platform-Agnostic Styling

When a user selects "Custom" variant and modifies styles, the data is saved as:

{
  "widgetId": "button-123",
  "properties": {
    "buttonType": "custom"  // ✅ Triggers Custom Styles group
  },
  "styles": {
    "base": {  // ✅ Responsive breakpoint
      "backgroundColor": "#f73ba9",
      "color": "#ffffff",
      "borderWidth": 2,
      "borderColor": "#000000",
      "borderRadius": 8,
      "opacity": 1
    },
    "md": { /* tablet styles */ },
    "lg": { /* desktop styles */ }
  }
}

This data structure:

Style Conversion Flow

                      User Changes Property
                              ↓
                    ┌─────────────────────┐
                    │  PropertyEditor     │
                    │  (color picker)     │
                    └─────────────────────┘
                              ↓
                    ┌─────────────────────┐
                    │  PropertiesPanel    │
                    │  (debounced queue)  │
                    └─────────────────────┘
                              ↓
                    ┌─────────────────────┐
                    │  EditorService      │
                    │  (flash-persist)    │
                    └─────────────────────┘
                              ↓
                    ┌─────────────────────┐
                    │  ButtonWidget       │
                    │  (customStyles())   │
                    └─────────────────────┘
                              ↓
                    ┌─────────────────────┐
                    │  UiButtonComponent  │
                    │  (inline styles)    │
                    └─────────────────────┘
                              ↓
                         DOM Updates!

📊 Property Group Order Standards

Use these constants for consistent ordering:

export const GROUP_ORDER = {
  INFORMATION: 10,   // Basic info (name, ID, description)
  LAYOUT: 20,        // Position, size, alignment
  APPEARANCE: 30,    // Theme-based styling (variant, size, shape)
  CUSTOM_STYLES: 31, // Manual style overrides (conditional)
  FONT: 35,          // Typography
  SPACING: 40,       // Padding, margin
  ANIMATION: 50,     // Motion and transitions
  ACTIONS: 100,      // Behavior (advanced, collapsed by default)
};

✅ Implementation Checklist

When creating/updating a widget's property groups:

1. Content Group

2. Appearance Group

3. Custom Styles Group

4. Actions Group


🚀 Benefits

For Users

For Developers

For Platform


📚 Apply This Pattern To

Next widgets to update using this pattern:

  1. TextWidget → Separate content from appearance from custom typography
  2. ImageWidget → Source vs display properties vs custom dimensions
  3. CardWidget → Content vs layout vs custom styling
  4. FormWidgets (Input, Select, etc.) → Value vs validation vs appearance
  5. LayoutWidgets (Grid, Flex) → Children vs layout mode vs custom spacing

🔗 Related Documentation


Last Updated: December 6, 2024
Implementation: Button Widget (reference)
Pattern Status: ✅ ACTIVE - Apply to all widgets