wip, resize, debugging
This commit is contained in:
parent
e2cf4d1e04
commit
8b8a1e3127
7 changed files with 289 additions and 9 deletions
|
|
@ -1,10 +1,30 @@
|
|||
import { eventBus } from '../core/EventBus';
|
||||
import { CoreEvents } from '../constants/CoreEvents';
|
||||
import { calendarConfig } from '../core/CalendarConfig';
|
||||
|
||||
export class ResizeHandleManager {
|
||||
private resizeZoneHeight = 15; // Must match CSS ::after height
|
||||
private cachedEvents: HTMLElement[] = [];
|
||||
|
||||
// Resize state
|
||||
private isResizing = false;
|
||||
private resizingElement: HTMLElement | null = null;
|
||||
private initialHeight = 0;
|
||||
private initialMouseY = 0;
|
||||
private targetHeight = 0;
|
||||
private currentHeight = 0;
|
||||
private animationFrameId: number | null = null;
|
||||
|
||||
// Snap configuration
|
||||
private snapIntervalMinutes = 15;
|
||||
private hourHeightPx: number;
|
||||
|
||||
constructor() {
|
||||
const gridSettings = calendarConfig.getGridSettings();
|
||||
this.hourHeightPx = gridSettings.hourHeight;
|
||||
this.snapIntervalMinutes = gridSettings.snapInterval;
|
||||
}
|
||||
|
||||
public initialize(): void {
|
||||
this.refreshEventCache();
|
||||
this.setupEventListeners();
|
||||
|
|
@ -17,16 +37,33 @@ export class ResizeHandleManager {
|
|||
}
|
||||
|
||||
private setupEventListeners(): void {
|
||||
// Hover detection (only when not resizing and mouse button is up)
|
||||
document.addEventListener('mousemove', (e: MouseEvent) => {
|
||||
this.handleGlobalMouseMove(e);
|
||||
if (!this.isResizing) {
|
||||
// Only check for resize zones when mouse button is up
|
||||
if (e.buttons === 0) {
|
||||
this.handleGlobalMouseMove(e);
|
||||
}
|
||||
} else {
|
||||
this.handleMouseMove(e);
|
||||
}
|
||||
});
|
||||
|
||||
// Resize mouse handling
|
||||
document.addEventListener('mousedown', (e: MouseEvent) => {
|
||||
this.handleMouseDown(e);
|
||||
});
|
||||
|
||||
document.addEventListener('mouseup', (e: MouseEvent) => {
|
||||
this.handleMouseUp(e);
|
||||
});
|
||||
|
||||
// Cache refresh
|
||||
eventBus.on(CoreEvents.GRID_RENDERED, () => this.refreshEventCache());
|
||||
eventBus.on(CoreEvents.EVENTS_RENDERED, () => this.refreshEventCache());
|
||||
eventBus.on(CoreEvents.EVENT_CREATED, () => this.refreshEventCache());
|
||||
eventBus.on(CoreEvents.EVENT_UPDATED, () => this.refreshEventCache());
|
||||
eventBus.on(CoreEvents.EVENT_DELETED, () => this.refreshEventCache());
|
||||
eventBus.on('drag:end', () => this.refreshEventCache());
|
||||
}
|
||||
|
||||
private handleGlobalMouseMove(e: MouseEvent): void {
|
||||
|
|
@ -34,6 +71,11 @@ export class ResizeHandleManager {
|
|||
const events = this.cachedEvents;
|
||||
|
||||
events.forEach(eventElement => {
|
||||
// Skip the element we're currently resizing
|
||||
if (this.resizingElement === eventElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rect = eventElement.getBoundingClientRect();
|
||||
const mouseY = e.clientY;
|
||||
const mouseX = e.clientX;
|
||||
|
|
@ -73,4 +115,121 @@ export class ResizeHandleManager {
|
|||
}
|
||||
eventElement.removeAttribute('data-resize-hover');
|
||||
}
|
||||
|
||||
private handleMouseDown(e: MouseEvent): void {
|
||||
const target = e.target as HTMLElement;
|
||||
const eventElement = target.closest<HTMLElement>('swp-event[data-resize-hover="true"]');
|
||||
|
||||
if (!eventElement) return;
|
||||
|
||||
// Check if click is in bottom resize zone
|
||||
const rect = eventElement.getBoundingClientRect();
|
||||
const distanceFromBottom = rect.bottom - e.clientY;
|
||||
|
||||
if (distanceFromBottom >= 0 && distanceFromBottom <= this.resizeZoneHeight) {
|
||||
// START RESIZE
|
||||
e.stopPropagation(); // Prevent DragDropManager from handling
|
||||
e.preventDefault();
|
||||
|
||||
this.isResizing = true;
|
||||
this.resizingElement = eventElement;
|
||||
this.initialHeight = eventElement.offsetHeight;
|
||||
this.initialMouseY = e.clientY;
|
||||
|
||||
// Set high z-index on event-group if exists, otherwise on event itself
|
||||
const eventGroup = eventElement.closest<HTMLElement>('swp-event-group');
|
||||
if (eventGroup) {
|
||||
eventGroup.style.zIndex = '1000';
|
||||
} else {
|
||||
eventElement.style.zIndex = '1000';
|
||||
}
|
||||
|
||||
console.log('🔄 Resize started', this.initialHeight);
|
||||
}
|
||||
}
|
||||
|
||||
private handleMouseMove(e: MouseEvent): void {
|
||||
if (!this.isResizing || !this.resizingElement) return;
|
||||
|
||||
const deltaY = e.clientY - this.initialMouseY;
|
||||
const rawHeight = this.initialHeight + deltaY;
|
||||
|
||||
// Apply minimum height
|
||||
this.targetHeight = Math.max(30, rawHeight);
|
||||
|
||||
// Start animation loop if not already running
|
||||
if (this.animationFrameId === null) {
|
||||
this.currentHeight = this.resizingElement.offsetHeight;
|
||||
this.animate();
|
||||
}
|
||||
}
|
||||
|
||||
private animate(): void {
|
||||
if (!this.isResizing || !this.resizingElement) {
|
||||
this.animationFrameId = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// Smooth interpolation towards target
|
||||
const diff = this.targetHeight - this.currentHeight;
|
||||
const step = diff * 0.3; // 30% of distance per frame
|
||||
|
||||
// Update if difference is significant
|
||||
if (Math.abs(diff) > 0.5) {
|
||||
this.currentHeight += step;
|
||||
|
||||
const swpEvent = this.resizingElement as any;
|
||||
if (swpEvent.updateHeight) {
|
||||
swpEvent.updateHeight(this.currentHeight);
|
||||
}
|
||||
|
||||
this.animationFrameId = requestAnimationFrame(() => this.animate());
|
||||
} else {
|
||||
// Close enough - snap to target
|
||||
this.currentHeight = this.targetHeight;
|
||||
const swpEvent = this.resizingElement as any;
|
||||
if (swpEvent.updateHeight) {
|
||||
swpEvent.updateHeight(this.currentHeight);
|
||||
}
|
||||
this.animationFrameId = null;
|
||||
}
|
||||
}
|
||||
|
||||
private handleMouseUp(e: MouseEvent): void {
|
||||
if (!this.isResizing || !this.resizingElement) return;
|
||||
|
||||
// Cancel animation
|
||||
if (this.animationFrameId !== null) {
|
||||
cancelAnimationFrame(this.animationFrameId);
|
||||
this.animationFrameId = null;
|
||||
}
|
||||
|
||||
// Snap to grid on mouse up
|
||||
const snapDistancePx = (this.snapIntervalMinutes / 60) * this.hourHeightPx;
|
||||
const currentHeight = this.resizingElement.offsetHeight;
|
||||
const snappedHeight = Math.round(currentHeight / snapDistancePx) * snapDistancePx;
|
||||
const finalHeight = Math.max(30, snappedHeight);
|
||||
|
||||
const swpEvent = this.resizingElement as any;
|
||||
if (swpEvent.updateHeight) {
|
||||
swpEvent.updateHeight(finalHeight);
|
||||
}
|
||||
|
||||
console.log('✅ Resize ended', finalHeight);
|
||||
|
||||
// Clear z-index on event-group if exists, otherwise on event itself
|
||||
const eventGroup = this.resizingElement.closest<HTMLElement>('swp-event-group');
|
||||
if (eventGroup) {
|
||||
eventGroup.style.zIndex = '';
|
||||
} else {
|
||||
this.resizingElement.style.zIndex = '';
|
||||
}
|
||||
|
||||
// Cleanup state
|
||||
this.isResizing = false;
|
||||
this.resizingElement = null;
|
||||
|
||||
// Refresh cache for future operations
|
||||
this.refreshEventCache();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue