Enables event resizing via drag handles
Adds a resize handle manager to handle mouse hover effects on calendar events and display a resize indicator. This allows users to visually identify and initiate event resizing by hovering near the bottom edge of an event.
This commit is contained in:
parent
7d7a8d9208
commit
a9819a8bf1
4 changed files with 130 additions and 61 deletions
|
|
@ -8,6 +8,7 @@ import { ViewManager } from '../managers/ViewManager';
|
|||
import { CalendarManager } from '../managers/CalendarManager';
|
||||
import { DragDropManager } from '../managers/DragDropManager';
|
||||
import { AllDayManager } from '../managers/AllDayManager';
|
||||
import { ResizeHandleManager } from '../managers/ResizeHandleManager';
|
||||
import { CalendarManagers } from '../types/ManagerTypes';
|
||||
|
||||
/**
|
||||
|
|
@ -39,6 +40,7 @@ export class ManagerFactory {
|
|||
const viewManager = new ViewManager(eventBus);
|
||||
const dragDropManager = new DragDropManager(eventBus);
|
||||
const allDayManager = new AllDayManager(eventManager);
|
||||
const resizeHandleManager = new ResizeHandleManager();
|
||||
|
||||
// CalendarManager depends on all other managers
|
||||
const calendarManager = new CalendarManager(
|
||||
|
|
@ -49,7 +51,7 @@ export class ManagerFactory {
|
|||
scrollManager
|
||||
);
|
||||
|
||||
|
||||
|
||||
return {
|
||||
eventManager,
|
||||
eventRenderer,
|
||||
|
|
@ -59,7 +61,8 @@ export class ManagerFactory {
|
|||
viewManager,
|
||||
calendarManager,
|
||||
dragDropManager,
|
||||
allDayManager
|
||||
allDayManager,
|
||||
resizeHandleManager
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -67,9 +70,10 @@ export class ManagerFactory {
|
|||
* Initialize all managers in the correct order
|
||||
*/
|
||||
public async initializeManagers(managers: CalendarManagers): Promise<void> {
|
||||
|
||||
|
||||
try {
|
||||
await managers.calendarManager.initialize?.();
|
||||
managers.resizeHandleManager.initialize();
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
|
|
|
|||
89
src/managers/ResizeHandleManager.ts
Normal file
89
src/managers/ResizeHandleManager.ts
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
export class ResizeHandleManager {
|
||||
private resizeZoneHeight =15; // Must match CSS ::after height
|
||||
private lastHoveredEvent: HTMLElement | null = null;
|
||||
|
||||
public initialize(): void {
|
||||
this.setupEventListeners();
|
||||
}
|
||||
|
||||
private setupEventListeners(): void {
|
||||
|
||||
// Listen to global mouseover from document
|
||||
document.addEventListener('mouseover', (e: MouseEvent) => {
|
||||
this.handleGlobalMouseOver(e);
|
||||
});
|
||||
|
||||
document.addEventListener('mousemove', (e: MouseEvent) => {
|
||||
this.handleGlobalMouseMove(e);
|
||||
});
|
||||
|
||||
document.addEventListener('mouseout', (e: MouseEvent) => {
|
||||
this.handleGlobalMouseOut(e);
|
||||
});
|
||||
}
|
||||
|
||||
private handleGlobalMouseOver(e: MouseEvent): void {
|
||||
const target = e.target as HTMLElement;
|
||||
const eventElement = target.closest<HTMLElement>('swp-day-columns swp-event');
|
||||
|
||||
if (eventElement) {
|
||||
this.lastHoveredEvent = eventElement;
|
||||
}
|
||||
}
|
||||
|
||||
private handleGlobalMouseMove(e: MouseEvent): void {
|
||||
// Check all events to see if mouse is in their resize zone
|
||||
const events = document.querySelectorAll<HTMLElement>('swp-day-columns swp-event');
|
||||
|
||||
events.forEach(eventElement => {
|
||||
const rect = eventElement.getBoundingClientRect();
|
||||
const mouseY = e.clientY;
|
||||
const mouseX = e.clientX;
|
||||
|
||||
// Check if mouse is within element bounds horizontally
|
||||
const isInHorizontalBounds = mouseX >= rect.left && mouseX <= rect.right;
|
||||
|
||||
// Check if mouse is in bottom 25px of the element
|
||||
const distanceFromBottom = rect.bottom - mouseY;
|
||||
const isInResizeZone = distanceFromBottom >= 0 && distanceFromBottom <= this.resizeZoneHeight;
|
||||
|
||||
if (isInHorizontalBounds && isInResizeZone) {
|
||||
this.showResizeIndicator(eventElement);
|
||||
console.log('✅ In resize zone - bottom 25px');
|
||||
} else {
|
||||
this.hideResizeIndicator(eventElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private showResizeIndicator(eventElement: HTMLElement): void {
|
||||
// Check if indicator already exists
|
||||
let indicator = eventElement.querySelector<HTMLElement>('swp-resize-indicator');
|
||||
|
||||
if (!indicator) {
|
||||
indicator = document.createElement('swp-resize-indicator');
|
||||
eventElement.appendChild(indicator);
|
||||
}
|
||||
|
||||
eventElement.setAttribute('data-resize-hover', 'true');
|
||||
}
|
||||
|
||||
private hideResizeIndicator(eventElement: HTMLElement): void {
|
||||
const indicator = eventElement.querySelector<HTMLElement>('swp-resize-indicator');
|
||||
if (indicator) {
|
||||
indicator.remove();
|
||||
}
|
||||
eventElement.removeAttribute('data-resize-hover');
|
||||
}
|
||||
|
||||
private handleGlobalMouseOut(e: MouseEvent): void {
|
||||
const target = e.target as HTMLElement;
|
||||
const eventElement = target.closest<HTMLElement>('swp-day-columns swp-event');
|
||||
|
||||
if (eventElement) {
|
||||
// Don't remove immediately - let mousemove handle it
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ export interface CalendarManagers {
|
|||
calendarManager: CalendarManager;
|
||||
dragDropManager: unknown; // Avoid interface conflicts
|
||||
allDayManager: unknown; // Avoid interface conflicts
|
||||
resizeHandleManager: ResizeHandleManager;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -70,6 +71,10 @@ export interface AllDayManager extends IManager {
|
|||
[key: string]: unknown; // Allow any properties from actual implementation
|
||||
}
|
||||
|
||||
export interface ResizeHandleManager extends IManager {
|
||||
// ResizeHandleManager handles hover effects for resize handles
|
||||
}
|
||||
|
||||
export interface ResourceData {
|
||||
resources: Resource[];
|
||||
assignments?: ResourceAssignment[];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue