import { eventBus } from '../core/EventBus'; export class ResizeHandleManager { constructor(config, positionUtils) { this.config = config; this.positionUtils = positionUtils; this.isResizing = false; this.targetEl = null; this.startY = 0; this.startDurationMin = 0; this.animationId = null; this.currentHeight = 0; this.targetHeight = 0; this.pointerCaptured = false; // Constants for better maintainability this.ANIMATION_SPEED = 0.35; this.Z_INDEX_RESIZING = '1000'; this.EVENT_REFRESH_THRESHOLD = 0.5; this.onMouseOver = (e) => { const target = e.target; const eventElement = target.closest('swp-event'); if (eventElement && !this.isResizing) { // Check if handle already exists if (!eventElement.querySelector(':scope > swp-resize-handle')) { const handle = this.createResizeHandle(); eventElement.appendChild(handle); } } }; this.onPointerDown = (e) => { const handle = e.target.closest('swp-resize-handle'); if (!handle) return; const element = handle.parentElement; this.startResizing(element, e); }; this.onPointerMove = (e) => { if (!this.isResizing || !this.targetEl) return; this.updateResizeHeight(e.clientY); }; this.animate = () => { if (!this.isResizing || !this.targetEl) { this.animationId = null; return; } const diff = this.targetHeight - this.currentHeight; if (Math.abs(diff) > this.EVENT_REFRESH_THRESHOLD) { this.currentHeight += diff * this.ANIMATION_SPEED; this.targetEl.updateHeight?.(this.currentHeight); this.animationId = requestAnimationFrame(this.animate); } else { this.finalizeAnimation(); } }; this.onPointerUp = (e) => { if (!this.isResizing || !this.targetEl) return; this.cleanupAnimation(); this.snapToGrid(); this.emitResizeEndEvent(); this.cleanupResizing(e); }; const grid = this.config.gridSettings; this.snapMin = grid.snapInterval; this.minDurationMin = this.snapMin; } initialize() { this.attachGlobalListeners(); } destroy() { this.removeEventListeners(); } removeEventListeners() { const calendarContainer = document.querySelector('swp-calendar-container'); if (calendarContainer) { calendarContainer.removeEventListener('mouseover', this.onMouseOver, true); } document.removeEventListener('pointerdown', this.onPointerDown, true); document.removeEventListener('pointermove', this.onPointerMove, true); document.removeEventListener('pointerup', this.onPointerUp, true); } createResizeHandle() { const handle = document.createElement('swp-resize-handle'); handle.setAttribute('aria-label', 'Resize event'); handle.setAttribute('role', 'separator'); return handle; } attachGlobalListeners() { const calendarContainer = document.querySelector('swp-calendar-container'); if (calendarContainer) { calendarContainer.addEventListener('mouseover', this.onMouseOver, true); } document.addEventListener('pointerdown', this.onPointerDown, true); document.addEventListener('pointermove', this.onPointerMove, true); document.addEventListener('pointerup', this.onPointerUp, true); } startResizing(element, event) { this.targetEl = element; this.isResizing = true; this.startY = event.clientY; const startHeight = element.offsetHeight; this.startDurationMin = Math.max(this.minDurationMin, Math.round(this.positionUtils.pixelsToMinutes(startHeight))); this.setZIndexForResizing(element); this.capturePointer(event); document.documentElement.classList.add('swp--resizing'); event.preventDefault(); } setZIndexForResizing(element) { const container = element.closest('swp-event-group') ?? element; this.prevZ = container.style.zIndex; container.style.zIndex = this.Z_INDEX_RESIZING; } capturePointer(event) { try { event.target.setPointerCapture?.(event.pointerId); this.pointerCaptured = true; } catch (error) { console.warn('Pointer capture failed:', error); } } updateResizeHeight(currentY) { const deltaY = currentY - this.startY; const startHeight = this.positionUtils.minutesToPixels(this.startDurationMin); const rawHeight = startHeight + deltaY; const minHeight = this.positionUtils.minutesToPixels(this.minDurationMin); this.targetHeight = Math.max(minHeight, rawHeight); if (this.animationId == null) { this.currentHeight = this.targetEl?.offsetHeight; this.animate(); } } finalizeAnimation() { if (!this.targetEl) return; this.currentHeight = this.targetHeight; this.targetEl.updateHeight?.(this.currentHeight); this.animationId = null; } cleanupAnimation() { if (this.animationId != null) { cancelAnimationFrame(this.animationId); this.animationId = null; } } snapToGrid() { if (!this.targetEl) return; const currentHeight = this.targetEl.offsetHeight; const snapDistancePx = this.positionUtils.minutesToPixels(this.snapMin); const snappedHeight = Math.round(currentHeight / snapDistancePx) * snapDistancePx; const minHeight = this.positionUtils.minutesToPixels(this.minDurationMin); const finalHeight = Math.max(minHeight, snappedHeight) - 3; // Small gap to grid lines this.targetEl.updateHeight?.(finalHeight); } emitResizeEndEvent() { if (!this.targetEl) return; const eventId = this.targetEl.dataset.eventId || ''; const resizeEndPayload = { eventId, element: this.targetEl, finalHeight: this.targetEl.offsetHeight }; eventBus.emit('resize:end', resizeEndPayload); } cleanupResizing(event) { this.restoreZIndex(); this.releasePointer(event); this.isResizing = false; this.targetEl = null; document.documentElement.classList.remove('swp--resizing'); } restoreZIndex() { if (!this.targetEl || this.prevZ === undefined) return; const container = this.targetEl.closest('swp-event-group') ?? this.targetEl; container.style.zIndex = this.prevZ; this.prevZ = undefined; } releasePointer(event) { if (!this.pointerCaptured) return; try { event.target.releasePointerCapture?.(event.pointerId); this.pointerCaptured = false; } catch (error) { console.warn('Pointer release failed:', error); } } } //# sourceMappingURL=ResizeHandleManager.js.map