Adds header drawer and event drag interactions
Introduces HeaderDrawerRenderer and HeaderDrawerLayoutEngine to support dragging events into an all-day header drawer Enables dynamic event placement and conversion between timed and all-day events through new drag interactions Implements flexible layout calculation for header items with column and row management Extends DragDropManager to handle header zone interactions Adds new event types for header drag events
This commit is contained in:
parent
026d83eb32
commit
6723658fd9
11 changed files with 850 additions and 4 deletions
151
src/v2/features/headerdrawer/HeaderDrawerRenderer.ts
Normal file
151
src/v2/features/headerdrawer/HeaderDrawerRenderer.ts
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
import { IEventBus } from '../../types/CalendarTypes';
|
||||
import { IGridConfig } from '../../core/IGridConfig';
|
||||
import { CoreEvents } from '../../constants/CoreEvents';
|
||||
import {
|
||||
IDragEnterHeaderPayload,
|
||||
IDragMoveHeaderPayload,
|
||||
IDragLeaveHeaderPayload
|
||||
} from '../../types/DragTypes';
|
||||
|
||||
/**
|
||||
* HeaderDrawerRenderer - Handles rendering of items in the header drawer
|
||||
*
|
||||
* Listens to drag events from DragDropManager and creates/manages
|
||||
* swp-header-item elements in the header drawer.
|
||||
*
|
||||
* Uses subgrid for column alignment with parent swp-calendar-header.
|
||||
* Position items via gridArea for explicit row/column placement.
|
||||
*/
|
||||
export class HeaderDrawerRenderer {
|
||||
private currentItem: HTMLElement | null = null;
|
||||
private container: HTMLElement | null = null;
|
||||
private sourceElement: HTMLElement | null = null;
|
||||
|
||||
constructor(
|
||||
private eventBus: IEventBus,
|
||||
private gridConfig: IGridConfig
|
||||
) {
|
||||
this.setupListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup event listeners for drag events
|
||||
*/
|
||||
private setupListeners(): void {
|
||||
this.eventBus.on(CoreEvents.EVENT_DRAG_ENTER_HEADER, (e) => {
|
||||
const payload = (e as CustomEvent<IDragEnterHeaderPayload>).detail;
|
||||
this.handleDragEnter(payload);
|
||||
});
|
||||
|
||||
this.eventBus.on(CoreEvents.EVENT_DRAG_MOVE_HEADER, (e) => {
|
||||
const payload = (e as CustomEvent<IDragMoveHeaderPayload>).detail;
|
||||
this.handleDragMove(payload);
|
||||
});
|
||||
|
||||
this.eventBus.on(CoreEvents.EVENT_DRAG_LEAVE_HEADER, (e) => {
|
||||
const payload = (e as CustomEvent<IDragLeaveHeaderPayload>).detail;
|
||||
this.handleDragLeave(payload);
|
||||
});
|
||||
|
||||
this.eventBus.on(CoreEvents.EVENT_DRAG_END, () => {
|
||||
this.handleDragEnd();
|
||||
});
|
||||
|
||||
this.eventBus.on(CoreEvents.EVENT_DRAG_CANCEL, () => {
|
||||
this.cleanup();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle drag entering header zone - create preview item
|
||||
*/
|
||||
private handleDragEnter(payload: IDragEnterHeaderPayload): void {
|
||||
this.container = document.querySelector('swp-header-drawer');
|
||||
if (!this.container) return;
|
||||
|
||||
// Store reference to source element
|
||||
this.sourceElement = payload.element;
|
||||
|
||||
// Create header item
|
||||
const item = document.createElement('swp-header-item');
|
||||
item.dataset.id = payload.eventId;
|
||||
item.dataset.itemType = payload.itemType;
|
||||
item.dataset.date = payload.sourceDate;
|
||||
item.dataset.duration = String(payload.duration);
|
||||
item.textContent = payload.title;
|
||||
|
||||
// Apply color class if present
|
||||
if (payload.colorClass) {
|
||||
item.classList.add(payload.colorClass);
|
||||
}
|
||||
|
||||
// Add dragging state
|
||||
item.classList.add('dragging');
|
||||
|
||||
// Initial placement (duration determines column span)
|
||||
// gridArea format: "row / col-start / row+1 / col-end"
|
||||
const col = payload.sourceColumnIndex + 1;
|
||||
const endCol = col + payload.duration;
|
||||
item.style.gridArea = `1 / ${col} / 2 / ${endCol}`;
|
||||
|
||||
this.container.appendChild(item);
|
||||
this.currentItem = item;
|
||||
|
||||
// Hide original element while in header
|
||||
payload.element.style.visibility = 'hidden';
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle drag moving within header - update column position
|
||||
*/
|
||||
private handleDragMove(payload: IDragMoveHeaderPayload): void {
|
||||
if (!this.currentItem) return;
|
||||
|
||||
// Update column position (duration=1 for now)
|
||||
const col = payload.columnIndex + 1;
|
||||
const duration = parseInt(this.currentItem.dataset.duration || '1', 10);
|
||||
const endCol = col + duration;
|
||||
|
||||
this.currentItem.style.gridArea = `1 / ${col} / 2 / ${endCol}`;
|
||||
this.currentItem.dataset.date = payload.dateKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle drag leaving header - remove preview and restore source
|
||||
*/
|
||||
private handleDragLeave(_payload: IDragLeaveHeaderPayload): void {
|
||||
this.cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle drag end - finalize the item (it stays in header)
|
||||
*/
|
||||
private handleDragEnd(): void {
|
||||
if (!this.currentItem) return;
|
||||
|
||||
// Remove dragging state
|
||||
this.currentItem.classList.remove('dragging');
|
||||
|
||||
// Item stays - it's now permanent
|
||||
// TODO: Emit event to persist allDay=true change
|
||||
|
||||
// Clear references but leave item in DOM
|
||||
this.currentItem = null;
|
||||
this.sourceElement = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup preview item and restore source visibility
|
||||
*/
|
||||
private cleanup(): void {
|
||||
// Remove preview item
|
||||
this.currentItem?.remove();
|
||||
this.currentItem = null;
|
||||
|
||||
// Restore source element visibility
|
||||
if (this.sourceElement) {
|
||||
this.sourceElement.style.visibility = '';
|
||||
this.sourceElement = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue