@libs-ui/components-drag-drop
v0.2.352-3
Published
## Overview
Downloads
4,280
Readme
Drag and Drop Component Documentation
Overview
The Drag and Drop component provides a powerful and flexible way to implement drag and drop functionality in your Angular applications. It supports various scenarios including container-to-container dragging, virtual scrolling, and custom drag boundaries.
Quick Start
Installation
npm install @libs-ui/drag-dropBasic Implementation
import { LibsUiComponentsDragContainerDirective, LibsUiDragItemDirective } from '@libs-ui/drag-drop';
@Component({
selector: 'app-drag-drop-demo',
template: `
<div
LibsUiComponentsDragContainerDirective
[items]="items">
<div
*ngFor="let item of items"
LibsUiDragItemDirective
[item]="item">
{{ item.name }}
</div>
</div>
`,
standalone: true,
imports: [LibsUiComponentsDragContainerDirective, LibsUiDragItemDirective],
})
export class DragDropDemoComponent {
items = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
{ id: 3, name: 'Item 3' },
];
}Features
1. Container-to-Container Drag
@Component({
template: `
<div class="container">
<h3>Source</h3>
<div LibsUiComponentsDragContainerDirective
[items]="sourceItems"
[groupName]="'source'"
[dropToGroupName]="['target']">
<div *ngFor="let item of sourceItems"
LibsUiDragItemDirective
[item]="item">
{{ item.name }}
</div>
</div>
</div>
<div class="container">
<h3>Target</h3>
<div LibsUiComponentsDragContainerDirective
[items]="targetItems"
[groupName]="'target'"
[dropToGroupName]="['source']">
<div *ngFor="let item of targetItems"
LibsUiDragItemDirective
[item]="item">
{{ item.name }}
</div>
</div>
</div>
`,
styles: [`
.container {
border: 1px solid #ccc;
padding: 10px;
margin: 10px;
min-height: 200px;
}
`]
})2. Virtual Scrolling Support
@Component({
template: `
<virtual-scroller [items]="items">
<div LibsUiComponentsDragContainerDirective [items]="items">
<div *ngFor="let item of items"
LibsUiDragItemDirective
[item]="item"
[itemInContainerVirtualScroll]="true"
[fieldId]="'id'">
{{ item.name }}
</div>
</div>
</virtual-scroller>
`
})3. Custom Drag Boundaries
@Component({
template: `
<div class="boundary-container">
<div LibsUiComponentsDragContainerDirective
[items]="items"
[dragBoundary]="true">
<div *ngFor="let item of items"
LibsUiDragItemDirective
[item]="item"
[dragBoundary]="true">
{{ item.name }}
</div>
</div>
</div>
`,
styles: [`
.boundary-container {
position: relative;
width: 500px;
height: 500px;
border: 2px solid #333;
}
`]
})Configuration Options
Container Directive
| Property | Type | Default | Description |
| ---------------------- | ------------------------------ | ------------------------- | ---------------------------- |
| mode | 'move' | 'copy' | 'deepCopy' | 'move' | Drag operation mode |
| directionDrag | 'horizontal' | 'vertical' | undefined | Drag direction |
| groupName | string | 'groupDragAndDropDefault' | Group identifier |
| dropToGroupName | string[] | null | Allowed drop targets |
| disableDragContainer | boolean | false | Disable drag functionality |
| placeholder | boolean | true | Show placeholder during drag |
Item Directive
| Property | Type | Default | Description |
| ------------------------------ | ------- | --------- | ------------------------------------- |
| fieldId | string | '' | Item identifier field |
| item | any | undefined | Item data |
| itemInContainerVirtualScroll | boolean | false | Enable virtual scroll support |
| dragBoundary | boolean | false | Restrict drag to container boundaries |
| zIndex | number | 1300 | Drag element z-index |
Events
Container Events
@Component({
template: `
<div LibsUiComponentsDragContainerDirective
(outDragStartContainer)="onDragStart($event)"
(outDragOverContainer)="onDragOver($event)"
(outDragLeaveContainer)="onDragLeave($event)"
(outDragEndContainer)="onDragEnd($event)"
(outDroppedContainer)="onDrop($event)">
<!-- Items -->
</div>
`
})Item Events
@Component({
template: `
<div LibsUiDragItemDirective
(outDragStart)="onItemDragStart($event)"
(outDragOver)="onItemDragOver($event)"
(outDragLeave)="onItemDragLeave($event)"
(outDragEnd)="onItemDragEnd($event)"
(outDropped)="onItemDrop($event)">
<!-- Item content -->
</div>
`
})Interfaces
Event Interfaces
interface IDragging {
mousePosition: IMousePosition;
elementDrag: HTMLElement;
elementKeepContainer?: boolean;
itemDragInfo?: IItemDragInfo;
}
interface IDragStart {
mousePosition: IMousePosition;
elementDrag: HTMLElement;
itemDragInfo?: IItemDragInfo;
}
interface IDragOver {
mousePosition: IMousePosition;
elementDrag: HTMLElement;
elementDragOver: HTMLElement;
itemDragInfo?: IItemDragInfo;
}
interface IDragLeave {
elementDrag: HTMLElement;
elementDragLeave: HTMLElement;
itemDragInfo?: IItemDragInfo;
}
interface IDragEnd {
mousePosition: IMousePosition;
elementDrag: HTMLElement;
itemDragInfo?: IItemDragInfo;
}
interface IDrop {
elementDrag: HTMLElement;
elementDrop: HTMLElement;
itemDragInfo?: IItemDragInfo;
}
interface IItemDragInfo {
item: object;
itemsMove?: WritableSignal<Array<unknown>>;
indexDrag?: number;
indexDrop?: number;
itemsDrag: WritableSignal<Array<unknown>>;
itemsDrop?: WritableSignal<Array<unknown>>;
containerDrag?: HTMLElement;
containerDrop?: HTMLElement;
}
interface IDragItemInContainerVirtualScroll {
itemDragInfo?: IItemDragInfo;
elementDrag: HTMLElement;
distanceStartElementAndMouseTop: number;
distanceStartElementAndMouseLeft: number;
elementContainer?: HTMLElement;
dragBoundary?: boolean;
dragBoundaryAcceptMouseLeaveContainer?: boolean;
ignoreStopEvent?: boolean;
}
interface IMousePosition {
clientX: number;
clientY: number;
}
interface IDragDropFunctionControlEvent {
setAttributeElementAndItemDrag: () => Promise<void>;
}Styling
Default Classes
/* Container */
.libs-ui-drag-drop-container {
position: relative;
min-height: 100px;
}
/* Item */
.libs-ui-drag-drop-item {
cursor: move;
transition: transform 0.2s;
}
/* Dragging */
.libs-ui-drag-drop-item-dragging {
opacity: 0.8;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
/* Placeholder */
.libs-ui-drag-drop-item-placeholder {
background: #f0f0f0;
border: 2px dashed #ccc;
}Custom Styling
@Component({
template: `
<div
LibsUiComponentsDragContainerDirective
[stylesOverride]="customStyles">
<!-- Items -->
</div>
`,
})
export class CustomStyledComponent {
customStyles = [
{
className: 'custom-container',
styles: `
.custom-container {
background: #f5f5f5;
border-radius: 8px;
padding: 15px;
}
`,
},
];
}Best Practices
Performance Optimization
- Use virtual scrolling for lists with more than 100 items
- Implement proper event throttling
- Clean up event listeners in ngOnDestroy
User Experience
- Provide clear visual feedback during drag operations
- Implement smooth animations
- Handle edge cases (container boundaries, scrolling)
Accessibility
- Ensure keyboard navigation support
- Provide proper ARIA labels
- Support screen readers
Troubleshooting
Common Issues
Drag Not Working
- Verify container and item configurations
- Check event bindings
- Ensure proper group settings
Performance Issues
- Implement virtual scrolling
- Use event throttling
- Optimize event handlers
Container Boundaries
- Verify dragBoundary settings
- Check container dimensions
- Ensure proper event handling
Examples
Basic List
@Component({
template: `
<div class="list-container">
<div LibsUiComponentsDragContainerDirective [items]="items">
<div *ngFor="let item of items"
class="list-item"
LibsUiDragItemDirective
[item]="item">
<span class="item-icon">📋</span>
<span class="item-text">{{ item.name }}</span>
</div>
</div>
</div>
`,
styles: [`
.list-container {
max-width: 400px;
margin: 20px auto;
}
.list-item {
padding: 10px;
margin: 5px 0;
background: white;
border: 1px solid #ddd;
border-radius: 4px;
display: flex;
align-items: center;
}
.item-icon {
margin-right: 10px;
}
`]
})Kanban Board
@Component({
template: `
<div class="kanban-board">
<div *ngFor="let column of columns"
class="kanban-column"
LibsUiComponentsDragContainerDirective
[items]="column.items"
[groupName]="column.id">
<h3>{{ column.title }}</h3>
<div *ngFor="let item of column.items"
class="kanban-item"
LibsUiDragItemDirective
[item]="item">
{{ item.title }}
</div>
</div>
</div>
`,
styles: [`
.kanban-board {
display: flex;
gap: 20px;
padding: 20px;
}
.kanban-column {
flex: 1;
background: #f5f5f5;
padding: 15px;
border-radius: 8px;
}
.kanban-item {
background: white;
padding: 10px;
margin: 5px 0;
border-radius: 4px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
`]
})