Appearance
Form System Quick Reference
🎯 Visual Overview: Frontend ↔ Engine Connection
APPLICATION-FRONTEND CREATIVE-ENGINE
═══════════════════════ ═══════════════════
📁 Form Block Structure 📁 Form Rendering
├── FormConfiguration.vue ├── CreativeFormBlock.vue
├── FormInputConfiguration.vue ├── FormInputBase.vue
└── Form/configs/ └── components/
├── TextInputConfiguration.vue ├── FormTextInput.vue
├── EmailInputConfiguration.vue ├── FormEmailInput.vue
├── PhoneInputConfiguration.vue ├── FormPhoneInput.vue
└── [Type]InputConfiguration.vue └── Form[Type]Input.vue
📁 Data Layer 📁 Data Layer
├── constants/inputTypes.ts ├── utils/constants.ts (BLOCKS)
├── Blocks/data/types.ts ├── payload-v2/index.ts
└── Blocks/data/defaults.ts └── stores/formStore.ts🔗 File Relationships Map
1. Block Registration
Frontend: constants/blocks.ts Engine: utils/constants.ts
├── BLOCKS.FORM = 'formProperties' → ├── BLOCKS.FORM = 'formProperties'
└── BLOCKS.FORM_INPUT = 'formInput' → └── BLOCKS.FORM_INPUT = 'formInput'2. Type Definitions
Frontend: Blocks/data/types.ts Engine: payload-v2/index.ts
├── FormProperties interface → ├── FormProperties interface
├── FormInputProperties interface → ├── FormInputProperties interface
└── Input type unions → └── CreativeBlocks interface3. Default Values
Frontend: Blocks/data/defaults.ts Engine: stores/formStore.ts
├── formDefaults object → ├── getFormProperties()
├── formInputDefaults object → ├── validateInput()
└── blockDefaults map → └── Default validation rules4. Input Type System
Frontend: constants/inputTypes.ts Engine: components/Form[Type]Input.vue
├── INPUT_TYPES constant → ├── Individual input components
├── getInputTypeDefinition() → ├── Type-specific validation
└── Short codes (T, E, P, etc.) → └── Rendering logic per type⚡ Quick Development Workflow
Adding New Input Type
- Frontend → Add to
inputTypes.tsINPUT_TYPES - Frontend → Create
[Type]InputConfiguration.vue - Frontend → Register in
FormInputConfiguration.vue - Engine → Create
Form[Type]Input.vuecomponent - Engine → Add validation in
formStore.ts - Engine → Register in
FormInputBase.vue
Styling Form Elements
- Frontend → Update configuration components
- Engine → Update style computed properties
- Both → Follow style system architecture patterns
Debugging Form Issues
- Data Flow: Frontend Vuex → Engine DataStore (iframe)
- Real-time: Changes save but need iframe reload
- Validation: Check
formStore.tsvalidation logic - Rendering: Check individual Form[Type]Input components
🎨 Style System Integration
Form Block Styling
Frontend: FormConfiguration.vue Engine: CreativeFormBlock.vue
├── Uses configurationLogic mixin → ├── Direct DataStore access
├── Border/Background sections → ├── Computed styles property
└── updateValue() pattern → └── Template style bindingForm Input Styling
Frontend: [Type]InputConfiguration Engine: Form[Type]Input.vue
├── Individual style sections → ├── StyleAndClassNameMixin
├── Type-specific properties → ├── Input-specific styling
└── Validation configuration → └── Error state handling🔧 Key Patterns
Data Updates
- Frontend:
updateValue(property, value)via mixin - Engine: Direct DataStore property access
- Communication: Iframe postMessage (limited real-time)
Subblock Management
- Pattern:
getSubBlocks(parentBlock)utility - Sorting: By
orderproperty - Identification:
blockName+blockType+parent
Type-Aware Numbering
- Per-type counters: T1, T2, E1, E2, P1, P2
- Persistent: Survives reordering/deletion
- Display: "Text Input #1", "Email Input #2"
🔄 Modern Vue Syntax Guidelines
Both Application-Frontend and Creative-Engine use Vue 2.7.16 with TypeScript and Vite, which supports modern Vue 3-like syntax while maintaining Vue 2 compatibility.
Template Syntax
vue
<!-- ✅ CORRECT: Modern Vue 2.7 syntax (no 'this') -->
<template>
<div>
<h2>{{ title }}</h2>
<div :class="{ active: isActive }">
{{ message }}
</div>
<button @click="handleClick">
{{ buttonText }}
</button>
</div>
</template>
<!-- ❌ AVOID: Legacy Vue 2 syntax (with 'this') -->
<template>
<div>
<h2>{{ this.title }}</h2>
<div :class="{ active: this.isActive }">
{{ this.message }}
</div>
<button @click="this.handleClick">
{{ this.buttonText }}
</button>
</div>
</template>Script Section
js
// Script section MUST still use 'this'
export default {
computed: {
formattedTitle() {
return this.title.toUpperCase(); // 'this' required
},
},
methods: {
handleClick() {
this.isActive = !this.isActive; // 'this' required
},
},
};Component Setup
ts
// Modern defineComponent style
import { defineComponent } from 'vue';
export default defineComponent({
name: 'FormInput',
emits: ['update', 'validate'], // Explicitly declare emitted events
props: {
value: { type: String, default: '' },
},
// Rest of component...
});Key Benefits
- Future Compatibility: Closer to Vue 3 composition API style
- Cleaner Templates: Less verbose without
thisin templates - Emits Declaration: Better documentation of component events
- TypeScript Support: Improved type checking with defineComponent
All new form system components should follow this modern syntax pattern.
🚀 Implementation Strategy
Phases of Development
Phase 1: Foundation Phase 2: Components Phase 3: Integration
├── BaseInput.vue ├── TextInput.vue ├── Dynamic Loading
├── ValidationHelpers ├── NumberInput.vue ├── Component Map
└── Common Props └── DateInput.vue └── CleanupPhase 1: Foundation Components
Create validation helpers for each input type in
validationHelpers.tstypescriptexport const validateTextInput = (value, rules) => { ... } export const validateNumberInput = (value, rules) => { ... }Build BaseInputConfiguration component with:
- Common input properties (label, placeholder)
- Shared styling sections (background, border, layout)
- Font settings for both label and input
- Base template structure with slots for type-specific content
Phase 2: Type-Specific Components
Each component focuses solely on its unique validation requirements:
| Component | File | Validation Fields |
|---|---|---|
| TextInputConfiguration | TextInputConfiguration.vue | minLength, maxLength, pattern |
| NumberInputConfiguration | NumberInputConfiguration.vue | min, max, step |
| DateInputConfiguration | DateInputConfiguration.vue | min (date), max (date) |
| SelectInputConfiguration | SelectInputConfiguration.vue | options list |
Phase 3: Integration
Update main container component to use dynamic loading:
vue
<component :is="inputConfigurationComponent" :block-data="blockData" :path="path" />
<script>
computed: {
inputConfigurationComponent() {
const type = this.blockData.type || 'text'
const componentMap = {
'text': 'TextInputConfiguration',
'number': 'NumberInputConfiguration',
// ... other mappings
}
return componentMap[type] || 'TextInputConfiguration'
}
}
</script>Migration Strategy
- Incremental Approach: Start with text inputs (most common)
- Maintain Compatibility: Ensure all existing form configurations work
- Progressive Rollout: Add one input type at a time
- Testing Focus: Unit test each component before integration
Plan
Phase 1: Decide what should be included and excluded
[x] Remove success message from form block and keep on child level
[x] Remove error message from block and keep on child level
[x] Remove success and error message from defaults in AF
[x] Remove success and error message from defaults in CE
[x] Make imports in @FormInputConfiguration.vue correct
[x] Make imports in @BaseInputConfiguration.vue correct
[x] Make imports in same order as in @AddBlockTool.vue
[x] Reorder imports and components object correct in order of appearance
[] Make the @FormConfiguration.vue styling work
- [] Layout
- [x] Alignment
- [x] Connect FlexAlignmentSection horizontalAlignment/verticalAlignment to form block flexDirection/alignItems/justifyContent props
- [x] Ensure alignment values map correctly to CSS flex properties in CreativeFormBlock.vue
- [x] Offset
- [x] Connect PositionSection x/y coordinates to form block position styles
- [x] Update position type (relative/absolute) handling in CreativeFormBlock styles
- [x] Padding
- [x] Properly bind PaddingSection values to form block padding styles
- [x] Ensure padding values with units (px/%) are correctly processed in CreativeFormBlock
- [x] Size (Add this to the form block)
- [x] Add SizeSection component with width/height bindings to FormConfiguration.vue
- [x] Ensure size values are properly applied in CreativeFormBlock's computed styles
- [x] Gap
- [x] Connect GapSection value to form block's gap style property
- [x] Add support for both px and % units for gap in CreativeFormBlock.vue
- [] Border: set default as curved
- [x] Effects
- [x] Connect BoxShadowSection settings to form block shadow styles
- [x] Connect RotationSection rotation value to form block transform style
- [x] Connect them both to render
- [x] Alignment
Phase 2: Finish form submit button styles
- [] Layout
[x] Remove optional from all styles in defaults.ts
[x] Check for text/font defaults and use it under styles object if it looks right
[x] Add better FormSubmitButtonTextSection logic
[x] Add engine support for fontStyleDefaults
- [x] Make text align work
[x] Uncomment FormSubmitButtonLayoutSection
[x] Make FormSubmitButtonLayoutSection work
Phase 2.5: Add title styling
- [] Add title styling to FormConfiguration.vue
Phase 3: Commit FormConfiguration.vue and related components
- [] Commit FormConfiguration.vue
- [] Commit related components
Phase 4: Make sure reordering of input blocks actually reorders them in DOM as well
Phase 5: Add default styles to input blocks
- [] Add default styles to input blocks