Drag & Drop Experience Library
Standalone directives + services that power the modular canvas interactions.
Overview
@libs-ux/drag-drop encapsulates the reusable drag + drop UX that we now rely on inside the Modular Universe, widget palettes, and future editors. The library lives at libs/libs-ux/drag-drop and exposes:
- DraggableDirective (
libDraggable) – Handle-aware directive that registers drag metadata and toggles browser drag state. - DropZoneDirective (
libDropZone) – Smart drop target that emits relative positioning (top / bottom / inside) with configurable hit areas. - DragDropService – Signal-based store that keeps the current drag item, hovered zone, and drop intent.
- Models –
DragData,DragEntityType, andDropPositiontypes for strong typing across canvases.
The service + directives are completely standalone, so applications can import only what they need without dragging Angular CDK dependencies into every surface.
Library Exports
import {
DragDropService,
DragData,
DraggableDirective,
DropZoneDirective
} from '@libs-ux/drag-drop';
| Export | Description |
|---|---|
DraggableDirective |
Adds dragstart, handle locking, custom drag image support, and active styling. |
DropZoneDirective |
Detects top/inside/bottom regions, applies visual classes (drop-top, drop-bottom, drop-inside) and emits { data, position }. |
DragDropService |
Holds dragItem, dragOverId, and dropPosition as Angular signals. |
DragData |
Type-safe payload describing the entity being moved. |
Usage Pattern
@Component({
standalone: true,
imports: [CommonModule, DraggableDirective, DropZoneDirective],
template: `
<div class="palette-item"
libDraggable
[dragData]="getDragData(widget)"
[dragHandle]="'.drag-handle'">
<span class="drag-handle">⋮⋮</span>
{{ widget.name }}
</div>
<section class="canvas"
libDropZone
zoneId="hero-grid"
(itemDrop)="onWidgetDrop($event)">
</section>
`
})
export class WidgetPaletteComponent {
getDragData(widget: SpaceWidget): DragData {
return { type: 'widget', data: widget, source: 'palette' };
}
onWidgetDrop(event: { data: DragData; position: DropPosition }): void {
// 1. event.data contains the dragged module/widget.
// 2. event.position tells you whether we hovered top / bottom / inside.
}
}
Drop Zone Tuning
DropZoneDirective exposes an edgeThreshold input (default 0.32). Increase it if you want bigger “before / after” zones or decrease it if you need precise nesting.
<div libDropZone
[zoneId]="section.id"
[edgeThreshold]="0.4"
[allowedTypes]="['section']"
(itemDrop)="handleSectionDrop($event)">
</div>
Visual Feedback Enhancements
The directive now emits CSS classes (drop-top, drop-bottom, drop-inside) that the Modular Universe styles use to render:
- Neon guide bars above/below sections for clarity.
- Pulsing dashed outlines when nesting inside a container.
- Direction-aware swapping (dragging upward automatically inserts before, downward inserts after).
The section-level SCSS lives in grid-section.component.scss. Other canvases can mirror the same classes for consistent visuals.
Integration Checklist
- Import from the library – never use relative paths into another feature package.
- Provide drag metadata – include
type,data, andsourceinDragDataso drop handlers can branch without introspection. - Handle
position– top/bottom should reorder arrays, inside should nest or assign content. - Reset state –
DragDropService.endDrag()is called automatically by the directives but can be invoked manually if a workflow cancels mid-flight. - Customize thresholds –
edgeThresholdandallowedTypeskeep drop zones predictable between tools (canvas vs. palette).
Testing & Maintenance
- Lint/Test commands:
nx lint @libs-ux/drag-drop,nx test @libs-ux/drag-drop. - Build:
nx build @libs-ux/drag-drop(custom builder runstools/scripts/build/build-angular-library.js). - Shared styling: Section visuals rely on standard classes only (
drop-top, etc.). Keep theme overrides in the consuming component rather than the library.
Migration Notes
- All existing imports under
libs/libs-structural/modular-universe/src/lib/directives&services/drag-drop.servicehave been removed. Use@libs-ux/drag-dropmoving forward. - If another surface needs drag support, add
DraggableDirective/DropZoneDirectiveto itsimportsarray and reuse the same event contract. - The previous Angular CDK implementation is fully retired. Do not reintroduce
CdkDrag/CdkDropListwithout explicit approval.