Improves drag and drop functionality

Refactors drag and drop to use the original element as the source and introduces edge scrolling.

This change aims to enhance the user experience during drag and drop operations by ensuring the correct element is used as the source, fixing issues, and by automatically scrolling the view when the dragged element reaches the edge of the scrollable area.
This commit is contained in:
Janus C. H. Knudsen 2025-10-12 22:00:02 +02:00
parent 8df1f6c4f1
commit e620c919aa
6 changed files with 120 additions and 121 deletions

View file

@ -4,7 +4,7 @@
*/
import { IEventBus } from '../types/CalendarTypes';
import { DragMoveEventPayload } from '../types/EventTypes';
import { DragMoveEventPayload, DragStartEventPayload } from '../types/EventTypes';
export class EdgeScrollManager {
private scrollableContent: HTMLElement | null = null;
@ -13,6 +13,10 @@ export class EdgeScrollManager {
private isDragging = false;
private lastTs = 0;
private rect: DOMRect | null = null;
private draggedClone: HTMLElement | null = null;
private initialScrollTop = 0;
private initialCloneTop = 0;
private scrollListener: ((e: Event) => void) | null = null;
// Constants - fixed values as per requirements
private readonly OUTER_ZONE = 100; // px from edge (slow zone)
@ -31,6 +35,10 @@ export class EdgeScrollManager {
if (this.scrollableContent) {
// Disable smooth scroll for instant auto-scroll
this.scrollableContent.style.scrollBehavior = 'auto';
// Add scroll listener
this.scrollListener = this.handleScroll.bind(this);
this.scrollableContent.addEventListener('scroll', this.scrollListener, { passive: true });
}
}, 100);
@ -38,12 +46,20 @@ export class EdgeScrollManager {
}
private subscribeToEvents(): void {
// Listen to drag events from DragDropManager
this.eventBus.on('drag:start', () => this.startDrag());
this.eventBus.on('drag:start', (event: Event) => {
let customEvent = event as CustomEvent<DragStartEventPayload>;
this.draggedClone = customEvent.detail.draggedClone;
this.startDrag();
});
this.eventBus.on('drag:move', (event: Event) => {
const customEvent = event as CustomEvent<DragMoveEventPayload>;
let customEvent = event as CustomEvent<DragMoveEventPayload>;
this.draggedClone = customEvent.detail.draggedClone;
this.updateMouseY(customEvent.detail.mousePosition.y);
});
this.eventBus.on('drag:end', () => this.stopDrag());
this.eventBus.on('drag:cancelled', () => this.stopDrag());
}
@ -52,6 +68,16 @@ export class EdgeScrollManager {
console.log('🎬 EdgeScrollManager: Starting drag');
this.isDragging = true;
this.lastTs = performance.now();
// Gem initial scroll position OG clone position
this.initialScrollTop = this.scrollableContent?.scrollTop || 0;
this.initialCloneTop = parseFloat(this.draggedClone?.style.top || '0');
console.log('💾 EdgeScrollManager: Saved initial state', {
initialScrollTop: this.initialScrollTop,
initialCloneTop: this.initialCloneTop
});
if (this.scrollRAF === null) {
this.scrollRAF = requestAnimationFrame((ts) => this.scrollTick(ts));
}
@ -74,6 +100,28 @@ export class EdgeScrollManager {
}
this.rect = null;
this.lastTs = 0;
this.draggedClone = null;
this.initialScrollTop = 0;
this.initialCloneTop = 0;
}
private handleScroll(): void {
if (!this.isDragging || !this.draggedClone || !this.scrollableContent) return;
const currentScrollTop = this.scrollableContent.scrollTop;
const totalScrollDelta = currentScrollTop - this.initialScrollTop;
// Beregn ny position baseret på initial position + total scroll delta
const newTop = this.initialCloneTop + totalScrollDelta;
this.draggedClone.style.top = `${newTop}px`;
console.log('📜 EdgeScrollManager: Scroll event - updated clone', {
initialScrollTop: this.initialScrollTop,
currentScrollTop,
totalScrollDelta,
initialCloneTop: this.initialCloneTop,
newTop
});
}
private scrollTick(ts: number): void {
@ -97,23 +145,15 @@ export class EdgeScrollManager {
// Check top edge
if (distTop < this.INNER_ZONE) {
// Inner zone (0-50px) - fast speed
vy = -this.FAST_SPEED_PXS;
console.log('⬆️ EdgeScrollManager: Top FAST', { distTop, vy });
} else if (distTop < this.OUTER_ZONE) {
// Outer zone (50-100px) - slow speed
vy = -this.SLOW_SPEED_PXS;
console.log('⬆️ EdgeScrollManager: Top SLOW', { distTop, vy });
}
// Check bottom edge
else if (distBot < this.INNER_ZONE) {
// Inner zone (0-50px) - fast speed
vy = this.FAST_SPEED_PXS;
console.log('⬇️ EdgeScrollManager: Bottom FAST', { distBot, vy });
} else if (distBot < this.OUTER_ZONE) {
// Outer zone (50-100px) - slow speed
vy = this.SLOW_SPEED_PXS;
console.log('⬇️ EdgeScrollManager: Bottom SLOW', { distBot, vy });
}
}