Refactors event positioning and drag-and-drop

Centralizes event position calculations into `PositionUtils` for consistency and reusability across managers and renderers.

Improves drag-and-drop functionality by emitting events for all-day event conversion and streamlining position calculations during drag operations.

Introduces `AllDayManager` and `AllDayEventRenderer` to manage and render all-day events in the calendar header. This allows dragging events to the header to convert them to all-day events.
This commit is contained in:
Janus Knudsen 2025-09-13 00:39:56 +02:00
parent 8b96376d1f
commit 7054c0d40a
9 changed files with 404 additions and 72 deletions

View file

@ -6,6 +6,7 @@
import { IEventBus } from '../types/CalendarTypes';
import { calendarConfig } from '../core/CalendarConfig';
import { DateCalculator } from '../utils/DateCalculator';
import { PositionUtils } from '../utils/PositionUtils';
interface CachedElements {
scrollContainer: HTMLElement | null;
@ -93,14 +94,13 @@ export class DragDropManager {
// Listen for header mouseover events
this.eventBus.on('header:mouseover', (event) => {
const { element, targetDate, headerRenderer } = (event as CustomEvent).detail;
const { targetDate, headerRenderer } = (event as CustomEvent).detail;
if (this.draggedEventId && targetDate) {
// Emit event to convert to all-day
this.eventBus.emit('drag:convert-to-allday', {
eventId: this.draggedEventId,
targetDate,
element,
originalElement: this.originalElement,
headerRenderer
});
}
@ -110,7 +110,7 @@ export class DragDropManager {
this.eventBus.on('column:mouseover', (event) => {
const { targetColumn, targetY } = (event as CustomEvent).detail;
if ((event as any).buttons === 1 && this.draggedEventId && this.isAllDayEventBeingDragged()) {
if (this.draggedEventId && this.isAllDayEventBeingDragged()) {
// Emit event to convert to timed
this.eventBus.emit('drag:convert-to-timed', {
eventId: this.draggedEventId,
@ -291,7 +291,7 @@ export class DragDropManager {
}
/**
* Consolidated position calculation method
* Consolidated position calculation method using PositionUtils
*/
private calculateDragPosition(mousePosition: Position): { column: string | null; snappedY: number } {
const column = this.detectColumn(mousePosition.x, mousePosition.y);
@ -310,15 +310,14 @@ export class DragDropManager {
const columnElement = this.getCachedColumnElement(targetColumn);
if (!columnElement) return mouseY;
const columnRect = columnElement.getBoundingClientRect();
const relativeY = mouseY - columnRect.top - this.mouseOffset.y;
const relativeY = PositionUtils.getPositionFromCoordinate(mouseY, columnElement);
// Return free position (no snapping)
return Math.max(0, relativeY);
}
/**
* Optimized snap position calculation with caching (used only on drop)
* Optimized snap position calculation using PositionUtils
*/
private calculateSnapPosition(mouseY: number, column: string | null = null): number {
const targetColumn = column || this.currentColumn;
@ -327,11 +326,8 @@ export class DragDropManager {
const columnElement = this.getCachedColumnElement(targetColumn);
if (!columnElement) return mouseY;
const columnRect = columnElement.getBoundingClientRect();
const relativeY = mouseY - columnRect.top - this.mouseOffset.y;
// Snap to nearest interval using DateCalculator precision
const snappedY = Math.round(relativeY / this.snapDistancePx) * this.snapDistancePx;
// Use PositionUtils for consistent snapping behavior
const snappedY = PositionUtils.getPositionFromCoordinate(mouseY, columnElement);
return Math.max(0, snappedY);
}