Drag Drop Editor Blueprint
Drag-and-drop page composition system with nested zones, collision detection, and component reordering
| Feature | drag-drop-editor |
| Category | UI |
| Version | 1.0.0 |
| Tags | drag-and-drop, editor, composition, visual-builder, page-builder |
| YAML Source | View on GitHub |
| JSON API | drag-drop-editor.json |
Actors
| ID | Name | Type | Description |
|---|---|---|---|
user | Editor User | human | Person composing a page by dragging and dropping components |
collision_engine | Collision Detection Engine | system | Determines valid drop targets and insertion positions during drag operations |
zone_manager | Zone Manager | system | Tracks nested drop zones and determines deepest valid target |
Fields
| Name | Type | Required | Label | Description |
|---|---|---|---|---|
drag_mode | select | Yes | Drag Mode | Validations: required |
dragged_item | json | No | Currently Dragged Item | |
zone_compound | text | Yes | Zone Identifier (parentId:slotName) | Validations: pattern |
source_zone | text | No | Source Zone | |
source_index | number | No | Source Index | |
destination_zone | text | No | Destination Zone | |
destination_index | number | No | Destination Index | |
preview_index | json | No | Preview State | |
collision_direction | select | No | Collision Direction |
States
State field: drag_state
Values:
| State | Initial | Terminal |
|---|---|---|
idle | Yes | |
dragging | ||
hovering_target | ||
dropped | Yes | |
cancelled | Yes |
Transitions:
| Name | From | To | Actor | Condition |
|---|---|---|---|---|
idle | dragging | user | Pointer moves 5px or 200ms delay elapsed after mousedown/touchstart | |
dragging | hovering_target | collision_engine | Pointer is over a valid drop zone that accepts the component type | |
hovering_target | hovering_target | collision_engine | Pointer moves to a different valid zone | |
hovering_target | dragging | collision_engine | Pointer leaves all valid drop zones | |
dragging | cancelled | user | User presses Escape or pointer leaves the editor | |
hovering_target | cancelled | user | User presses Escape | |
hovering_target | dropped | user | User releases pointer over valid drop zone |
Rules
- drag_activation:
- pointer_distance_px: 5
- delay_ms: 200
- delay_tolerance_px: 10
- touch_delay_ms: 200
- collision_detection:
- algorithm: midpoint-with-direction
- midpoint_offset_percent: 5
- direction_interval_px: 10
- zone_buffer_px: 6
- fallback_enabled: true
- zone_management:
- zone_change_debounce_ms: 100
- depth_priority: true
- self_drop_prevention: true
- descendant_drop_prevention: true
- drag_axis:
- auto_detection: true
- inline_axis: x
- block_axis: y
- dynamic_axis: true
- animation:
- drop_transition_ms: 200
- preview_immediate: true
- position_sync:
- measure_interval_ms: 100
- uses_resize_observer: true
- uses_scroll_listener: true
Outcomes
Insert_new_component (Priority: 1)
Given:
- user drags a component type from the palette
- user drops it on a valid zone that accepts that component type
Then:
- create_record target:
component_instance— Create new component instance with generated unique ID and default props - set_field target:
content_tree— Insert component at destination zone and index - emit_event event:
editor.component.inserted - set_field target:
selected_item— Select the newly inserted component
Result: New component appears at drop position, is selected for editing
Move_existing_component (Priority: 2)
Given:
- user drags an existing component from the canvas
- user drops it on a valid zone at a different position
Then:
- set_field target:
content_tree— Remove component from source zone and insert at destination zone - emit_event event:
editor.component.moved - set_field target:
selected_item— Select the moved component at its new position
Result: Component appears at new position, original position is empty
Reorder_within_zone (Priority: 3)
Given:
- user drags a component within the same zone
- destination index differs from source index
Then:
- set_field target:
content_tree— Move component from source index to destination index within the same zone - emit_event event:
editor.component.reordered
Result: Component order updated within the zone
Drop_on_self (Priority: 4) — Error: DROP_ON_SELF
Given:
- target component is the same as the dragged component
Then:
- emit_event event:
editor.drag.rejected
Result: Drag cancelled, component returns to original position
Drop_on_descendant (Priority: 5) — Error: DROP_ON_DESCENDANT
Given:
- target zone belongs to a descendant of the dragged component
Then:
- emit_event event:
editor.drag.rejected
Result: Drag cancelled, component returns to original position
Drop_type_not_allowed (Priority: 6) — Error: DROP_TYPE_NOT_ALLOWED
Given:
- target zone has an allow list that does not include the dragged component type
- OR target zone has a disallow list that includes the dragged component type
Then:
- emit_event event:
editor.drag.rejected
Result: Zone does not accept this component type, drop rejected
Drag_cancelled (Priority: 7)
Given:
- user presses Escape during drag
- OR pointer leaves the editor bounds
- OR drop target is void/invalid
Then:
- set_field target:
preview_index— Clear all previews - transition_state field:
drag_statefrom:draggingto:cancelled - emit_event event:
editor.drag.cancelled
Result: Component returns to original position, no state change
Preview_updates_during_drag (Priority: 8)
Given:
- drag is in progress
- pointer moves over a new valid target
Then:
- set_field target:
preview_index— Update preview to show insertion indicator at new target position
Result: Visual preview shows where the component will land before user releases
Errors
| Code | Status | Message | Retry |
|---|---|---|---|
DROP_ON_SELF | 400 | Cannot drop a component onto itself | No |
DROP_ON_DESCENDANT | 400 | Cannot drop a component into its own child | No |
DROP_TYPE_NOT_ALLOWED | 400 | This zone does not accept that component type | No |
Events
| Event | Description | Payload |
|---|---|---|
editor.component.inserted | A new component was dragged from palette and placed on canvas | component_id, component_type, destination_zone, destination_index |
editor.component.moved | An existing component was moved to a different position | component_id, source_zone, source_index, destination_zone, destination_index |
editor.component.reordered | A component was reordered within the same zone | component_id, zone, old_index, new_index |
editor.drag.cancelled | A drag operation was cancelled without placing the component | component_id, drag_mode |
editor.drag.rejected | A drop was rejected due to validation rules | component_id, reason |
Related Blueprints
| Feature | Relationship | Reason |
|---|---|---|
| component-registry | required | Drag-and-drop needs the component registry to know what’s draggable and what zones accept |
| content-tree | required | All insert/move/reorder operations modify the content tree |
| editor-state | required | Drag state, selection, and preview state managed by the central store |
| undo-redo | recommended | All drag operations should be undoable |
AGI Readiness
Goals
Reliable Drag Drop Editor
Drag-and-drop page composition system with nested zones, collision detection, and component reordering
Success Metrics:
| Metric | Target | Measurement |
|---|---|---|
| success_rate | >= 99% | Successful operations divided by total attempts |
| error_rate | < 1% | Failed operations divided by total attempts |
Autonomy
Level: semi_autonomous
Human Checkpoints:
- before transitioning to a terminal state
Escalation Triggers:
error_rate > 5
Tradeoffs
| Prefer | Over | Reason |
|---|---|---|
| accessibility | aesthetics | UI must be usable by all users including those with disabilities |
Coordination
Protocol: orchestrated
Consumes:
| Capability | From | Fallback |
|---|---|---|
component_registry | component-registry | degrade |
content_tree | content-tree | degrade |
editor_state | editor-state | degrade |
Safety
| Action | Permission | Cooldown | Max Auto |
|---|---|---|---|
| insert_new_component | autonomous | - | - |
| move_existing_component | autonomous | - | - |
| reorder_within_zone | autonomous | - | - |
| drop_on_self | autonomous | - | - |
| drop_on_descendant | autonomous | - | - |
| drop_type_not_allowed | autonomous | - | - |
| drag_cancelled | supervised | - | - |
| preview_updates_during_drag | supervised | - | - |