@andymcloid/trakk 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"trakk.esm.js","sources":["../src/trakk-engine.js","../src/trakk.js"],"sourcesContent":["/**\n * Event Emitter for Trakk Engine\n */\nclass EventEmitter {\n constructor() {\n this.events = {};\n }\n\n on(event, callback) {\n if (!this.events[event]) {\n this.events[event] = [];\n }\n this.events[event].push(callback);\n }\n\n off(event, callback) {\n if (!this.events[event]) return;\n this.events[event] = this.events[event].filter(cb => cb !== callback);\n }\n\n emit(event, data) {\n if (!this.events[event]) return true;\n this.events[event].forEach(callback => callback(data));\n return true;\n }\n}\n\n/**\n * Trakk Engine - Core animation timeline player\n * Can run independently from the editor\n */\nexport class TrakkEngine extends EventEmitter {\n constructor() {\n super();\n\n this._timerId = null;\n this._playRate = 1;\n this._currentTime = 0;\n this._playState = 'paused';\n this._prev = 0;\n\n this._effectMap = {};\n this._actionMap = {};\n this._actionSortIds = [];\n\n this._next = 0;\n this._activeActionIds = [];\n }\n\n get isPlaying() {\n return this._playState === 'playing';\n }\n\n get isPaused() {\n return this._playState === 'paused';\n }\n\n set effects(effects) {\n this._effectMap = effects;\n }\n\n set data(data) {\n if (this.isPlaying) this.pause();\n this._dealData(data);\n this._dealClear();\n this._dealEnter(this._currentTime);\n }\n\n /**\n * Set playback rate\n */\n setPlayRate(rate) {\n if (rate <= 0) {\n console.error('Error: rate cannot be less than 0!');\n return false;\n }\n this._playRate = rate;\n this.emit('afterSetPlayRate', { rate, engine: this });\n return true;\n }\n\n getPlayRate() {\n return this._playRate;\n }\n\n /**\n * Re-render current time\n */\n reRender() {\n if (this.isPlaying) return;\n this._tickAction(this._currentTime);\n }\n\n /**\n * Set playback time\n */\n setTime(time, isTick = false) {\n this._currentTime = time;\n this._next = 0;\n this._dealLeave(time);\n this._dealEnter(time);\n\n if (isTick) {\n this.emit('setTimeByTick', { time, engine: this });\n } else {\n this.emit('afterSetTime', { time, engine: this });\n }\n return true;\n }\n\n getTime() {\n return this._currentTime;\n }\n\n /**\n * Play timeline\n */\n play({ toTime, autoEnd } = {}) {\n const currentTime = this.getTime();\n if (this.isPlaying || (toTime && toTime <= currentTime)) return false;\n\n this._playState = 'playing';\n this._startOrStop('start');\n this.emit('play', { engine: this });\n\n this._timerId = requestAnimationFrame((time) => {\n this._prev = time;\n this._tick({ now: time, autoEnd, to: toTime });\n });\n return true;\n }\n\n /**\n * Pause playback\n */\n pause() {\n if (this.isPlaying) {\n this._playState = 'paused';\n this._startOrStop('stop');\n this.emit('paused', { engine: this });\n }\n if (this._timerId) {\n cancelAnimationFrame(this._timerId);\n }\n }\n\n _end() {\n this.pause();\n this.emit('ended', { engine: this });\n }\n\n _startOrStop(type) {\n for (let i = 0; i < this._activeActionIds.length; i++) {\n const actionId = this._activeActionIds[i];\n const action = this._actionMap[actionId];\n const effect = this._effectMap[action?.effectId];\n\n if (type === 'start') {\n effect?.source?.start?.({ action, effect, engine: this, isPlaying: this.isPlaying, time: this.getTime() });\n } else if (type === 'stop') {\n effect?.source?.stop?.({ action, effect, engine: this, isPlaying: this.isPlaying, time: this.getTime() });\n }\n }\n }\n\n _tick(data) {\n if (this.isPaused) return;\n const { now, autoEnd, to } = data;\n\n let currentTime = this.getTime() + (Math.min(1000, now - this._prev) / 1000) * this._playRate;\n this._prev = now;\n\n if (to && to <= currentTime) currentTime = to;\n this.setTime(currentTime, true);\n\n this._tickAction(currentTime);\n\n if (!to && autoEnd && this._next >= this._actionSortIds.length && this._activeActionIds.length === 0) {\n this._end();\n return;\n }\n\n if (to && to <= currentTime) {\n this._end();\n return;\n }\n\n if (this.isPaused) return;\n this._timerId = requestAnimationFrame((time) => {\n this._tick({ now: time, autoEnd, to });\n });\n }\n\n _tickAction(time) {\n this._dealEnter(time);\n this._dealLeave(time);\n\n const length = this._activeActionIds.length;\n for (let i = 0; i < length; i++) {\n const actionId = this._activeActionIds[i];\n const action = this._actionMap[actionId];\n const effect = this._effectMap[action.effectId];\n if (effect?.source?.update) {\n effect.source.update({ time, action, isPlaying: this.isPlaying, effect, engine: this });\n }\n }\n }\n\n _dealClear() {\n while (this._activeActionIds.length) {\n const actionId = this._activeActionIds.shift();\n const action = this._actionMap[actionId];\n const effect = this._effectMap[action?.effectId];\n if (effect?.source?.leave) {\n effect.source.leave({ action, effect, engine: this, isPlaying: this.isPlaying, time: this.getTime() });\n }\n }\n this._next = 0;\n }\n\n _dealEnter(time) {\n while (this._actionSortIds[this._next]) {\n const actionId = this._actionSortIds[this._next];\n const action = this._actionMap[actionId];\n\n if (!action.disable) {\n if (action.start > time) break;\n if (action.end > time && !this._activeActionIds.includes(actionId)) {\n const effect = this._effectMap[action.effectId];\n if (effect?.source?.enter) {\n effect.source.enter({ action, effect, isPlaying: this.isPlaying, time, engine: this });\n }\n this._activeActionIds.push(actionId);\n }\n }\n this._next++;\n }\n }\n\n _dealLeave(time) {\n let i = 0;\n while (this._activeActionIds[i]) {\n const actionId = this._activeActionIds[i];\n const action = this._actionMap[actionId];\n\n if (action.start > time || action.end < time) {\n const effect = this._effectMap[action.effectId];\n if (effect?.source?.leave) {\n effect.source.leave({ action, effect, isPlaying: this.isPlaying, time, engine: this });\n }\n this._activeActionIds.splice(i, 1);\n continue;\n }\n i++;\n }\n }\n\n _dealData(data) {\n const actions = [];\n data.forEach(row => {\n // Support both new schema (blocks) and old schema (actions/items)\n const items = row.blocks || row.items || row.actions || [];\n actions.push(...items);\n });\n const sortActions = actions.sort((a, b) => a.start - b.start);\n const actionMap = {};\n const actionSortIds = [];\n\n sortActions.forEach(action => {\n actionSortIds.push(action.id);\n actionMap[action.id] = { ...action };\n });\n this._actionMap = actionMap;\n this._actionSortIds = actionSortIds;\n }\n}\n","import { TrakkEngine } from './trakk-engine.js';\n\n/**\n * Utility functions\n */\nconst parserTimeToPixel = (time, { startLeft, scale, scaleWidth }) => {\n return (time / scale) * scaleWidth + startLeft;\n};\n\nconst parserPixelToTime = (pixel, { startLeft, scale, scaleWidth }) => {\n return ((pixel - startLeft) / scaleWidth) * scale;\n};\n\n/**\n * Trakk - Timeline Editor Web Component\n */\nexport class Trakk extends HTMLElement {\n constructor() {\n super();\n\n // Default configuration\n this.config = {\n scale: 1,\n scaleWidth: 160,\n scaleCount: 20,\n scaleSplitCount: 10,\n startLeft: 120,\n contentPadding: 0,\n minScaleCount: 10,\n maxScaleCount: Infinity,\n rowHeight: 32,\n autoScroll: true,\n hideCursor: false,\n disableDrag: false,\n gridSnap: true,\n grid: 1\n };\n\n // Callback functions\n this.callbacks = {\n onActionMoveStart: null,\n onActionMoving: null,\n onActionMoveEnd: null,\n onActionResizeStart: null,\n onActionResizing: null,\n onActionResizeEnd: null,\n onClickRow: null,\n onClickAction: null,\n onDoubleClickRow: null,\n onDoubleClickAction: null,\n onContextMenuRow: null,\n onContextMenuAction: null,\n onCursorDragStart: null,\n onCursorDrag: null,\n onCursorDragEnd: null,\n onClickTimeArea: null,\n getActionRender: null,\n getScaleRender: null\n };\n\n // State\n this.tracks = [];\n this.cursorTime = 0;\n this.isPlaying = false;\n this._scrollX = 0;\n this._scrollY = 0;\n\n // DOM refs\n this.timeAreaEl = null;\n this.timeAreaWrapperEl = null;\n this.editAreaEl = null;\n this.labelColumnEl = null;\n this.labelInnerEl = null;\n this.cursorEl = null;\n\n // Engine\n this.engine = new TrakkEngine();\n\n // Drag state\n this.dragState = {\n isDragging: false,\n isActuallyDragging: false, // Only true after threshold\n type: null,\n action: null,\n row: null,\n rowIndex: null,\n startX: 0,\n startY: 0,\n currentLeft: 0,\n currentWidth: 0,\n deltaX: 0,\n totalDeltaX: 0 // Track total movement\n };\n\n }\n\n connectedCallback() {\n this.className = 'timeline-editor';\n this.render();\n this._setupEngineListeners();\n this._setupResizeObserver();\n }\n\n disconnectedCallback() {\n this.engine.pause();\n this._cleanup();\n }\n\n _cleanup() {\n document.removeEventListener('mousemove', this._boundHandleMouseMove);\n document.removeEventListener('mouseup', this._boundHandleMouseUp);\n if (this._resizeObserver) {\n this._resizeObserver.disconnect();\n }\n }\n\n _setupResizeObserver() {\n // Watch for container size changes\n this._resizeObserver = new ResizeObserver((entries) => {\n for (let entry of entries) {\n // Re-render on resize to update layout\n if (this.editAreaEl) {\n this._updateCursorPosition();\n }\n }\n });\n this._resizeObserver.observe(this);\n }\n\n /**\n * Set timeline data\n */\n setData(tracks) {\n this.tracks = tracks || [];\n this.engine.data = this.tracks;\n this.render();\n }\n\n /**\n * Update configuration\n */\n setConfig(newConfig) {\n Object.assign(this.config, newConfig);\n this.render();\n }\n\n /**\n * Set callback functions\n */\n setCallbacks(callbacks) {\n Object.assign(this.callbacks, callbacks);\n }\n\n /**\n * Set a single callback\n */\n on(event, callback) {\n if (this.callbacks.hasOwnProperty(event)) {\n this.callbacks[event] = callback;\n }\n }\n\n /**\n * Get current timeline data (for export)\n */\n getData() {\n return {\n tracks: this.tracks\n };\n }\n\n /**\n * Export timeline to JSON string\n */\n exportJSON() {\n return JSON.stringify(this.getData(), null, 2);\n }\n\n /**\n * Import timeline from JSON string\n */\n importJSON(jsonString) {\n try {\n const data = JSON.parse(jsonString);\n // Support both old (editorData) and new (tracks) formats\n const tracks = data.tracks || data.editorData || [];\n this.setData(tracks);\n return true;\n } catch (e) {\n console.error('Failed to import timeline data:', e);\n return false;\n }\n }\n\n /**\n * Save to localStorage\n */\n saveToLocalStorage(key = 'timeline-data') {\n try {\n localStorage.setItem(key, this.exportJSON());\n return true;\n } catch (e) {\n console.error('Failed to save to localStorage:', e);\n return false;\n }\n }\n\n /**\n * Load from localStorage\n */\n loadFromLocalStorage(key = 'timeline-data') {\n try {\n const data = localStorage.getItem(key);\n if (data) {\n return this.importJSON(data);\n }\n return false;\n } catch (e) {\n console.error('Failed to load from localStorage:', e);\n return false;\n }\n }\n\n /**\n * Set current time\n */\n setTime(time) {\n this.cursorTime = Math.max(0, time);\n this.engine.setTime(this.cursorTime);\n this._updateCursorPosition();\n }\n\n /**\n * Get current time\n */\n getTime() {\n return this.engine.getTime();\n }\n\n /**\n * Get total time (end time of the last block across all tracks)\n */\n getTotalTime() {\n let maxEnd = 0;\n for (const track of this.tracks) {\n const blocks = track.blocks || track.items || track.actions || [];\n for (const block of blocks) {\n if (block.end > maxEnd) {\n maxEnd = block.end;\n }\n }\n }\n return maxEnd;\n }\n\n /**\n * Play timeline\n */\n play(options = {}) {\n return this.engine.play(options);\n }\n\n /**\n * Pause timeline\n */\n pause() {\n this.engine.pause();\n }\n\n /**\n * Sync engine data with current tracks (call after modifying tracks)\n */\n _syncEngineData() {\n this.engine.data = this.tracks;\n }\n\n /**\n * Emit change event and sync engine\n */\n _emitChange() {\n this._syncEngineData();\n this.dispatchEvent(new CustomEvent('change', {\n detail: { tracks: this.tracks }\n }));\n }\n\n /**\n * Expand timeline if an action extends beyond current bounds\n * @param {number} endTime - The end time to check against\n * @returns {boolean} - Whether the timeline was expanded\n */\n _expandTimelineIfNeeded(endTime) {\n // Add 2 scale units of margin beyond the end time\n const marginScales = 2;\n const requiredScales = Math.ceil(endTime / this.config.scale) + marginScales;\n\n if (requiredScales > this.config.scaleCount) {\n // Respect maxScaleCount limit\n const newScaleCount = Math.min(requiredScales, this.config.maxScaleCount);\n if (newScaleCount > this.config.scaleCount) {\n this.config.scaleCount = newScaleCount;\n this._updateTimelineWidth();\n return true;\n }\n }\n return false;\n }\n\n /**\n * Update timeline width without full re-render (for dynamic expansion)\n */\n _updateTimelineWidth() {\n const contentPadding = this.config.contentPadding;\n const totalWidth = this.config.scaleCount * this.config.scaleWidth + contentPadding;\n\n // Update rows container width\n const rowsContainer = this.editAreaEl?.querySelector('.timeline-editor-rows');\n if (rowsContainer) {\n rowsContainer.style.width = `${totalWidth}px`;\n rowsContainer.style.minWidth = `${totalWidth}px`;\n }\n\n // Update each row width\n const rows = this.editAreaEl?.querySelectorAll('.timeline-editor-edit-row');\n if (rows) {\n rows.forEach(row => {\n row.style.width = `${totalWidth}px`;\n });\n }\n\n // Re-render time area to add new ticks\n this._rerenderTimeArea();\n }\n\n /**\n * Re-render time area (for dynamic expansion)\n */\n _rerenderTimeArea() {\n if (!this.timeAreaEl) return;\n\n // Create new time area content\n const newTimeArea = this._createTimeArea();\n\n // Replace old time area\n this.timeAreaEl.replaceWith(newTimeArea);\n this.timeAreaEl = newTimeArea;\n\n // Restore scroll sync\n this._syncTimeAreaScroll();\n }\n\n /**\n * Setup engine event listeners\n */\n _setupEngineListeners() {\n this.engine.on('play', () => {\n this.isPlaying = true;\n this.classList.add('timeline-editor-playing');\n // Jump to cursor immediately when play starts (not gradual scroll)\n this._scrollToCursorImmediate();\n });\n\n this.engine.on('paused', () => {\n this.isPlaying = false;\n this.classList.remove('timeline-editor-playing');\n });\n\n this.engine.on('setTimeByTick', ({ time }) => {\n this.cursorTime = time;\n this._updateCursorPosition(true); // Auto-scroll during playback\n });\n\n this.engine.on('afterSetTime', ({ time }) => {\n this.cursorTime = time;\n this._updateCursorPosition(false); // No auto-scroll for manual time set\n });\n }\n\n /**\n * Render the timeline editor\n */\n render() {\n this.innerHTML = '';\n\n // Time area (header row with ruler)\n this.timeAreaEl = this._createTimeArea();\n this.appendChild(this.timeAreaEl);\n\n // Cursor (created before content wrapper so it's behind label column)\n if (!this.config.hideCursor) {\n this.cursorEl = this._createCursor();\n this.appendChild(this.cursorEl);\n }\n\n // Set CSS custom properties for dynamic values\n this.style.setProperty('--timeline-start-left', `${this.config.startLeft}px`);\n this.style.setProperty('--timeline-content-padding', `${this.config.contentPadding}px`);\n this.style.setProperty('--timeline-scale-width', `${this.config.scaleWidth}px`);\n\n // Spacer div to cover cursor line between time area and content\n const spacer = document.createElement('div');\n spacer.className = 'timeline-editor-spacer';\n spacer.style.cssText = `\n height: 10px;\n width: calc(var(--timeline-start-left) - 4px);\n background-color: #191b1d;\n flex-shrink: 0;\n position: relative;\n z-index: 101;\n `;\n this.appendChild(spacer);\n\n // Main content wrapper (labels + edit area side by side)\n const contentWrapper = document.createElement('div');\n contentWrapper.className = 'timeline-editor-content';\n contentWrapper.style.cssText = `\n display: flex;\n flex: 1 1 0;\n overflow: hidden;\n position: relative;\n min-height: 0;\n min-width: 0;\n height: 0;\n `;\n\n // Frozen label column\n this.labelColumnEl = this._createLabelColumn();\n contentWrapper.appendChild(this.labelColumnEl);\n\n // Edit area (scrollable)\n this.editAreaEl = this._createEditArea();\n contentWrapper.appendChild(this.editAreaEl);\n\n this.appendChild(contentWrapper);\n\n // Restore scroll position and sync\n if (this._scrollX > 0) {\n this.editAreaEl.scrollLeft = this._scrollX;\n this._syncTimeAreaScroll();\n }\n if (this._scrollY > 0) {\n this.editAreaEl.scrollTop = this._scrollY;\n this._syncLabelColumnScroll();\n }\n this._updateCursorPosition();\n }\n\n /**\n * Create time area (ruler)\n */\n _createTimeArea() {\n const timeArea = document.createElement('div');\n timeArea.className = 'timeline-editor-time-area';\n\n // Content padding to push content away from label column edge\n const contentPadding = this.config.contentPadding;\n\n // Create a wrapper that will be scrolled\n const wrapper = document.createElement('div');\n wrapper.className = 'timeline-editor-time-area-wrapper';\n const totalWidth = this.config.scaleCount * this.config.scaleWidth + this.config.startLeft + contentPadding;\n wrapper.style.width = `${totalWidth}px`;\n wrapper.style.height = '100%';\n wrapper.style.position = 'relative';\n\n const interact = document.createElement('div');\n interact.className = 'timeline-editor-time-area-interact';\n interact.style.width = `${totalWidth}px`;\n\n // Calculate total number of tick marks including subdivisions\n const totalTicks = this.config.scaleCount * this.config.scaleSplitCount;\n const tickWidth = this.config.scaleWidth / this.config.scaleSplitCount;\n\n for (let i = 0; i <= totalTicks; i++) {\n const unit = document.createElement('div');\n const isBig = i % this.config.scaleSplitCount === 0;\n unit.className = `timeline-editor-time-unit ${isBig ? 'timeline-editor-time-unit-big' : ''}`;\n unit.style.width = `${tickWidth}px`;\n\n // Position first tick at startLeft + contentPadding to clear the blocker\n // The blocker covers the full startLeft area, so we add contentPadding to push \"0.0s\" label into view\n if (i === 0) {\n unit.style.marginLeft = `${this.config.startLeft + contentPadding - tickWidth + 1}px`;\n }\n\n if (isBig) {\n const scale = document.createElement('div');\n scale.className = 'timeline-editor-time-unit-scale';\n const scaleValue = (i / this.config.scaleSplitCount) * this.config.scale;\n\n // Use custom render if provided\n if (this.callbacks.getScaleRender) {\n const customContent = this.callbacks.getScaleRender(scaleValue);\n if (typeof customContent === 'string') {\n scale.innerHTML = customContent;\n } else if (customContent instanceof HTMLElement) {\n scale.innerHTML = '';\n scale.appendChild(customContent);\n }\n } else {\n // First tick shows \"0s\", others show decimal like \"1.0s\"\n scale.textContent = i === 0 ? '0s' : `${scaleValue.toFixed(1)}s`;\n }\n\n unit.appendChild(scale);\n }\n\n interact.appendChild(unit);\n }\n\n wrapper.appendChild(interact);\n timeArea.appendChild(wrapper);\n\n // Store wrapper reference for scroll sync\n this.timeAreaWrapperEl = wrapper;\n\n // Click handler for time area\n timeArea.addEventListener('click', (e) => {\n if (this.isPlaying) return;\n const rect = timeArea.getBoundingClientRect();\n // Account for contentPadding in time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding;\n const time = parserPixelToTime(x, this.config);\n\n // Callback\n if (this.callbacks.onClickTimeArea) {\n const result = this.callbacks.onClickTimeArea(e, { time });\n if (result === false) return;\n }\n\n this.setTime(Math.max(0, time));\n });\n\n return timeArea;\n }\n\n /**\n * Create frozen label column\n */\n _createLabelColumn() {\n const labelColumn = document.createElement('div');\n labelColumn.className = 'timeline-editor-label-column';\n labelColumn.style.cssText = `\n width: ${this.config.startLeft}px;\n flex-shrink: 0;\n overflow: hidden;\n background-color: #191b1d;\n border-right: 1px solid rgba(255, 255, 255, 0.1);\n z-index: 200;\n position: relative;\n `;\n\n // Inner container that will be transformed for scroll sync\n const labelInner = document.createElement('div');\n labelInner.className = 'timeline-editor-label-inner';\n this.labelInnerEl = labelInner;\n\n this.tracks.forEach((row, rowIndex) => {\n const labelRow = this._createLabelRow(row, rowIndex);\n labelInner.appendChild(labelRow);\n });\n\n labelColumn.appendChild(labelInner);\n return labelColumn;\n }\n\n /**\n * Create a label row (for frozen column)\n */\n _createLabelRow(row, rowIndex) {\n const labelRow = document.createElement('div');\n labelRow.className = 'timeline-editor-label-row';\n labelRow.style.cssText = `\n height: ${row.rowHeight || this.config.rowHeight}px;\n display: flex;\n align-items: center;\n padding: 0 8px;\n color: rgba(255, 255, 255, 0.7);\n font-size: 12px;\n font-weight: 500;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n box-sizing: border-box;\n position: relative;\n `;\n\n if (rowIndex === 0) {\n labelRow.style.borderTop = '1px solid rgba(255, 255, 255, 0.1)';\n }\n\n labelRow.dataset.rowId = row.id;\n labelRow.dataset.rowIndex = rowIndex;\n\n // Label text\n const labelText = document.createElement('span');\n labelText.className = 'timeline-editor-label-text';\n labelText.textContent = row.name || '';\n labelText.style.cssText = `\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n `;\n labelRow.appendChild(labelText);\n\n // Make label editable on dblclick (unless locked)\n if (!row.locked) {\n labelRow.style.cursor = 'text';\n labelRow.addEventListener('dblclick', (e) => {\n e.stopPropagation();\n this._startLabelEdit(labelRow, labelText, row);\n });\n }\n\n // Show locked indicator\n if (row.locked) {\n const lockIcon = document.createElement('span');\n lockIcon.className = 'timeline-editor-lock-icon';\n lockIcon.style.cssText = `\n width: 10px;\n height: 10px;\n margin-left: 6px;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='rgba(255,255,255,0.4)'%3E%3Cpath d='M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z'/%3E%3C/svg%3E\");\n background-size: contain;\n background-repeat: no-repeat;\n flex-shrink: 0;\n `;\n labelRow.appendChild(lockIcon);\n }\n\n // Add delete button (unless noDelete is set)\n if (!row.noDelete) {\n const deleteBtn = document.createElement('div');\n deleteBtn.className = 'timeline-editor-row-delete';\n deleteBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n this._deleteTrack(row);\n });\n labelRow.appendChild(deleteBtn);\n }\n\n return labelRow;\n }\n\n /**\n * Create edit area (rows and actions)\n */\n _createEditArea() {\n const editArea = document.createElement('div');\n editArea.className = 'timeline-editor-edit-area';\n\n // Extra padding to match the time area tick offset (content pushed away from label edge)\n const contentPadding = this.config.contentPadding;\n const totalWidth = this.config.scaleCount * this.config.scaleWidth + contentPadding;\n\n // Create rows container\n const rowsContainer = document.createElement('div');\n rowsContainer.className = 'timeline-editor-rows';\n rowsContainer.style.position = 'relative';\n rowsContainer.style.width = `${totalWidth}px`;\n rowsContainer.style.minWidth = `${totalWidth}px`;\n\n this.tracks.forEach((row, rowIndex) => {\n const rowEl = this._createRow(row, rowIndex, totalWidth, contentPadding);\n rowsContainer.appendChild(rowEl);\n });\n\n editArea.appendChild(rowsContainer);\n\n // Sync scroll with time area and label column\n editArea.addEventListener('scroll', () => {\n this._scrollX = editArea.scrollLeft;\n this._scrollY = editArea.scrollTop;\n this._syncTimeAreaScroll();\n this._syncLabelColumnScroll();\n this._updateCursorPosition();\n });\n\n return editArea;\n }\n\n /**\n * Sync label column scroll with edit area (vertical only)\n */\n _syncLabelColumnScroll() {\n if (!this.labelInnerEl) return;\n this.labelInnerEl.style.transform = `translateY(-${this._scrollY}px)`;\n }\n\n /**\n * Create a row (edit area only, no label - labels are in frozen column)\n */\n _createRow(row, rowIndex, totalWidth, contentPadding) {\n const rowEl = document.createElement('div');\n rowEl.className = 'timeline-editor-edit-row';\n rowEl.style.height = `${row.rowHeight || this.config.rowHeight}px`;\n rowEl.style.width = `${totalWidth}px`;\n\n // Offset background grid by contentPadding to align with time ruler (size comes from CSS variable)\n rowEl.style.backgroundPosition = `${contentPadding}px 0`;\n\n rowEl.dataset.rowId = row.id;\n rowEl.dataset.rowIndex = rowIndex;\n\n // Click handler\n rowEl.addEventListener('click', (e) => {\n // Only if clicking directly on the row (not on an action)\n if (e.target === rowEl) {\n // Cancel any active editing when clicking empty track area\n this._cancelActiveEditing();\n\n if (this.callbacks.onClickRow) {\n const rect = e.currentTarget.getBoundingClientRect();\n // Edit area starts at 0, account for contentPadding, add startLeft for correct time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding + this.config.startLeft;\n const time = parserPixelToTime(x, this.config);\n this.callbacks.onClickRow(e, { row, time });\n }\n }\n });\n\n // Double-click handler\n rowEl.addEventListener('dblclick', (e) => {\n if (e.target === rowEl && this.callbacks.onDoubleClickRow) {\n const rect = e.currentTarget.getBoundingClientRect();\n // Edit area starts at 0, account for contentPadding, add startLeft for correct time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding + this.config.startLeft;\n const time = parserPixelToTime(x, this.config);\n this.callbacks.onDoubleClickRow(e, { row, time });\n }\n });\n\n // Context menu handler\n rowEl.addEventListener('contextmenu', (e) => {\n if (e.target === rowEl && this.callbacks.onContextMenuRow) {\n e.preventDefault();\n const rect = e.currentTarget.getBoundingClientRect();\n // Edit area starts at 0, account for contentPadding, add startLeft for correct time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding + this.config.startLeft;\n const time = parserPixelToTime(x, this.config);\n this.callbacks.onContextMenuRow(e, { row, time });\n }\n });\n\n // Add mousedown handler for creating new items via drag on empty space\n rowEl.addEventListener('mousedown', (e) => {\n // Only if clicking directly on the row (not on an action)\n if (e.target === rowEl || e.target === rowEl.querySelector('.timeline-editor-row-label')) {\n this._handleRowDragStart(e, row, rowIndex);\n }\n });\n\n // Create items for this row (fallback to actions for backward compatibility)\n const items = row.blocks || row.items || row.actions || [];\n items.forEach((item) => {\n const actionEl = this._createAction(item, row, rowIndex);\n rowEl.appendChild(actionEl);\n });\n\n return rowEl;\n }\n\n /**\n * Start editing a track label\n */\n _startLabelEdit(labelRow, labelText, row) {\n if (labelRow.querySelector('input')) return; // Already editing\n\n const currentName = row.name || '';\n const input = document.createElement('input');\n input.type = 'text';\n input.value = currentName;\n input.className = 'timeline-editor-row-label-input';\n input.style.cssText = `\n flex: 1;\n min-width: 0;\n background: transparent;\n border: none;\n border-bottom: 1px solid rgba(255,255,255,0.3);\n color: inherit;\n font: inherit;\n outline: none;\n padding: 0;\n margin: 0;\n user-select: text;\n box-sizing: border-box;\n `;\n\n let editFinished = false;\n const finishEdit = () => {\n // Prevent double execution\n if (editFinished) return;\n editFinished = true;\n\n const newName = input.value.trim();\n row.name = newName;\n labelText.textContent = newName;\n labelText.style.display = '';\n input.remove();\n\n // Emit change event\n this._emitChange();\n this.dispatchEvent(new CustomEvent('trackrenamed', {\n detail: { track: row, name: newName }\n }));\n };\n\n input.addEventListener('blur', finishEdit);\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n input.blur();\n } else if (e.key === 'Escape') {\n input.value = currentName;\n input.blur();\n }\n });\n\n labelText.style.display = 'none';\n labelRow.insertBefore(input, labelText);\n input.focus();\n input.select();\n }\n\n /**\n * Delete a track\n */\n _deleteTrack(row) {\n // Remove from tracks array\n const idx = this.tracks.indexOf(row);\n if (idx > -1) {\n this.tracks.splice(idx, 1);\n }\n\n // Re-render\n this.render();\n\n // Emit events\n this._emitChange();\n this.dispatchEvent(new CustomEvent('trackdeleted', {\n detail: { track: row }\n }));\n }\n\n /**\n * Delete a block from a track\n */\n _deleteBlock(block, row) {\n const blocks = row.blocks || row.items || row.actions || [];\n const idx = blocks.indexOf(block);\n if (idx > -1) {\n blocks.splice(idx, 1);\n }\n\n // Re-render\n this.render();\n\n // Emit events\n this._emitChange();\n this.dispatchEvent(new CustomEvent('blockdeleted', {\n detail: { block, track: row }\n }));\n }\n\n /**\n * Start editing a block name\n */\n _startBlockNameEdit(actionEl, block, row) {\n const content = actionEl.querySelector('.timeline-editor-action-content');\n if (!content || content.querySelector('input')) return; // Already editing\n\n const currentName = block.name || '';\n const input = document.createElement('input');\n input.type = 'text';\n input.value = currentName;\n input.className = 'timeline-editor-block-name-input';\n input.style.cssText = `\n width: 100%;\n background: transparent;\n border: none;\n border-bottom: 1px solid rgba(255,255,255,0.3);\n color: inherit;\n font: inherit;\n outline: none;\n padding: 0;\n text-align: center;\n user-select: text;\n `;\n\n let editFinished = false;\n const finishEdit = () => {\n // Prevent double execution\n if (editFinished) return;\n editFinished = true;\n\n const newName = input.value.trim();\n block.name = newName;\n\n // Remove input and restore content\n input.remove();\n\n // Update content display\n if (this.callbacks.getActionRender) {\n const customContent = this.callbacks.getActionRender(block, row);\n if (typeof customContent === 'string') {\n content.innerHTML = customContent;\n }\n } else {\n content.textContent = newName;\n }\n\n // Emit change event\n this._emitChange();\n this.dispatchEvent(new CustomEvent('blockrenamed', {\n detail: { block, track: row, name: newName }\n }));\n };\n\n input.addEventListener('blur', finishEdit);\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n input.blur();\n } else if (e.key === 'Escape') {\n input.value = currentName;\n input.blur();\n }\n e.stopPropagation();\n });\n input.addEventListener('mousedown', (e) => e.stopPropagation());\n input.addEventListener('click', (e) => e.stopPropagation());\n\n content.innerHTML = '';\n content.appendChild(input);\n input.focus();\n input.select();\n }\n\n /**\n * Cancel any active block name editing by blurring input fields\n */\n _cancelActiveEditing() {\n const activeInput = this.querySelector('.timeline-editor-block-name-input');\n if (activeInput) {\n activeInput.blur();\n }\n const activeLabelInput = this.querySelector('.timeline-editor-row-label-input');\n if (activeLabelInput) {\n activeLabelInput.blur();\n }\n }\n\n /**\n * Handle drag start on empty row space to create new item\n */\n _handleRowDragStart(e, row, rowIndex) {\n if (this.isPlaying || this.config.disableDrag || row.locked) return;\n\n // Only left mouse button\n if (e.button !== 0) return;\n\n e.preventDefault();\n\n // Use editAreaEl for consistent coordinate calculation (same as _updateNewItemFromDrag)\n const rect = this.editAreaEl.getBoundingClientRect();\n const contentPadding = this.config.contentPadding;\n // Edit area starts at 0, account for contentPadding, add startLeft for correct time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding + this.config.startLeft;\n const startTime = parserPixelToTime(x, this.config);\n\n // Setup drag state for item creation\n this.dragState.isDragging = true;\n this.dragState.isActuallyDragging = false;\n this.dragState.type = 'item-create';\n this.dragState.row = row;\n this.dragState.rowIndex = rowIndex;\n this.dragState.startX = e.clientX;\n this.dragState.startTime = startTime;\n this.dragState.totalDeltaX = 0;\n this.dragState.newItem = null;\n this.dragState.newItemEl = null;\n\n this._boundHandleMouseMove = this._handleMouseMove.bind(this);\n this._boundHandleMouseUp = this._handleMouseUp.bind(this);\n\n document.addEventListener('mousemove', this._boundHandleMouseMove);\n document.addEventListener('mouseup', this._boundHandleMouseUp);\n }\n\n /**\n * Create an action element\n */\n _createAction(action, row, rowIndex) {\n const actionEl = document.createElement('div');\n actionEl.className = 'timeline-editor-action';\n if (action.selected) {\n actionEl.classList.add('selected');\n }\n\n // Content padding to match time ruler offset\n const contentPadding = this.config.contentPadding;\n // Edit area starts at 0 (label column is separate), so subtract startLeft, then add contentPadding\n const left = parserTimeToPixel(action.start, this.config) - this.config.startLeft + contentPadding;\n const width = parserTimeToPixel(action.end, this.config) - this.config.startLeft + contentPadding - left;\n\n actionEl.style.left = `${left}px`;\n actionEl.style.width = `${width}px`;\n actionEl.dataset.actionId = action.id;\n actionEl.dataset.rowIndex = rowIndex;\n\n // Content\n const content = document.createElement('div');\n content.className = 'timeline-editor-action-content';\n\n // Use custom render if provided\n if (this.callbacks.getActionRender) {\n const customContent = this.callbacks.getActionRender(action, row);\n if (typeof customContent === 'string') {\n content.innerHTML = customContent;\n } else if (customContent instanceof HTMLElement) {\n content.innerHTML = '';\n content.appendChild(customContent);\n }\n } else {\n // Display block name - only show if explicitly set (non-empty string)\n // Don't fall back to id as that creates ugly display\n content.textContent = action.name || '';\n }\n actionEl.appendChild(content);\n\n // Resize handles (only if not locked)\n if (action.flexible !== false && !row.locked) {\n const leftStretch = document.createElement('div');\n leftStretch.className = 'timeline-editor-action-left-stretch';\n actionEl.appendChild(leftStretch);\n\n const rightStretch = document.createElement('div');\n rightStretch.className = 'timeline-editor-action-right-stretch';\n actionEl.appendChild(rightStretch);\n\n leftStretch.addEventListener('mousedown', (e) => this._handleResizeStart(e, action, row, rowIndex, 'left'));\n rightStretch.addEventListener('mousedown', (e) => this._handleResizeStart(e, action, row, rowIndex, 'right'));\n }\n\n // Add drag listener for moving (only if not locked)\n if (action.movable !== false && !row.locked) {\n actionEl.addEventListener('mousedown', (e) => {\n // Ignore if clicking on resize handles\n if (e.target.classList.contains('timeline-editor-action-left-stretch') ||\n e.target.classList.contains('timeline-editor-action-right-stretch')) {\n return;\n }\n this._handleMoveStart(e, action, row, rowIndex);\n });\n }\n\n // Visual indicator for locked track\n if (row.locked) {\n actionEl.classList.add('timeline-editor-action-locked');\n actionEl.style.cursor = 'default';\n }\n\n // Add delete button for block (unless noDelete is set on block or track is locked)\n if (!action.noDelete && !row.locked) {\n const deleteBtn = document.createElement('div');\n deleteBtn.className = 'timeline-editor-action-delete';\n deleteBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n this._deleteBlock(action, row);\n });\n deleteBtn.addEventListener('mousedown', (e) => {\n e.stopPropagation(); // Prevent drag start\n });\n actionEl.appendChild(deleteBtn);\n }\n\n // Click event\n actionEl.addEventListener('click', (e) => {\n if (this.callbacks.onClickAction) {\n const rect = this.editAreaEl.getBoundingClientRect();\n // Edit area starts at 0, account for contentPadding, add startLeft for correct time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding + this.config.startLeft;\n const time = parserPixelToTime(x, this.config);\n this.callbacks.onClickAction(e, { action, row, time });\n }\n });\n\n // Double-click event - edit block name (unless locked)\n actionEl.addEventListener('dblclick', (e) => {\n e.stopPropagation();\n\n // Allow callback to handle or prevent\n if (this.callbacks.onDoubleClickAction) {\n const rect = this.editAreaEl.getBoundingClientRect();\n // Edit area starts at 0, account for contentPadding, add startLeft for correct time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding + this.config.startLeft;\n const time = parserPixelToTime(x, this.config);\n const result = this.callbacks.onDoubleClickAction(e, { action, row, time });\n if (result === false) return;\n }\n\n // Start editing block name (unless track is locked)\n if (!row.locked) {\n this._startBlockNameEdit(actionEl, action, row);\n }\n });\n\n // Context menu event\n actionEl.addEventListener('contextmenu', (e) => {\n if (this.callbacks.onContextMenuAction) {\n e.preventDefault();\n const rect = this.editAreaEl.getBoundingClientRect();\n // Edit area starts at 0, account for contentPadding, add startLeft for correct time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding + this.config.startLeft;\n const time = parserPixelToTime(x, this.config);\n this.callbacks.onContextMenuAction(e, { action, row, time });\n }\n });\n\n return actionEl;\n }\n\n /**\n * Create cursor\n */\n _createCursor() {\n const cursor = document.createElement('div');\n cursor.className = 'timeline-editor-cursor';\n\n const cursorTop = document.createElement('div');\n cursorTop.className = 'timeline-editor-cursor-top';\n cursor.appendChild(cursorTop);\n\n const cursorArea = document.createElement('div');\n cursorArea.className = 'timeline-editor-cursor-area';\n cursor.appendChild(cursorArea);\n\n // Cursor drag\n cursorArea.addEventListener('mousedown', (e) => this._handleCursorDragStart(e));\n\n return cursor;\n }\n\n /**\n * Update cursor position\n * @param {boolean} shouldAutoScroll - Whether to auto-scroll to keep cursor visible (only during playback/drag)\n */\n _updateCursorPosition(shouldAutoScroll = false) {\n if (!this.cursorEl) return;\n const contentPadding = this.config.contentPadding;\n // parserTimeToPixel includes startLeft, which now represents the label column width\n // The cursor is positioned relative to the whole timeline including label column\n // Add contentPadding to align with the offset content\n const left = parserTimeToPixel(this.cursorTime, this.config) + contentPadding;\n // Cursor position relative to viewport, accounting for scroll\n this.cursorEl.style.left = `${left - this._scrollX}px`;\n\n // Auto-scroll to keep cursor visible (only when explicitly requested, e.g. during playback)\n if (shouldAutoScroll && this.config.autoScroll && this.editAreaEl) {\n this._autoScrollToCursor(left);\n }\n }\n\n /**\n * Scroll to cursor immediately (no gradual scroll) - used when play starts\n */\n _scrollToCursorImmediate() {\n if (!this.editAreaEl || !this.config.autoScroll) return;\n\n const contentPadding = this.config.contentPadding;\n const cursorLeft = parserTimeToPixel(this.cursorTime, this.config) + contentPadding;\n const editAreaWidth = this.editAreaEl.clientWidth;\n const cursorInEditArea = cursorLeft - this.config.startLeft;\n\n const scrollMargin = 50;\n const visibleLeft = this._scrollX;\n const visibleRight = this._scrollX + editAreaWidth;\n\n // Only jump if cursor is outside visible area\n if (cursorInEditArea < visibleLeft + scrollMargin || cursorInEditArea > visibleRight - scrollMargin) {\n // Center cursor in view (or near left edge if at start)\n const targetScrollX = Math.max(0, cursorInEditArea - editAreaWidth / 3);\n this.editAreaEl.scrollLeft = targetScrollX;\n }\n }\n\n /**\n * Auto-scroll edit area to keep cursor visible\n */\n _autoScrollToCursor(cursorLeft) {\n const editAreaWidth = this.editAreaEl.clientWidth;\n // Cursor position in edit area coordinates (subtract startLeft since edit area doesn't include label column)\n const cursorInEditArea = cursorLeft - this.config.startLeft;\n\n // Define margin - scroll when cursor is within this distance from edge\n const scrollMargin = 50;\n // Maximum scroll step per update for smooth scrolling\n const maxScrollStep = 8;\n\n // Check if cursor is outside visible area\n const visibleLeft = this._scrollX;\n const visibleRight = this._scrollX + editAreaWidth;\n\n let targetScrollX = null;\n\n if (cursorInEditArea < visibleLeft + scrollMargin) {\n // Cursor is too far left - scroll left\n targetScrollX = Math.max(0, cursorInEditArea - scrollMargin);\n } else if (cursorInEditArea > visibleRight - scrollMargin) {\n // Cursor is too far right - scroll right\n targetScrollX = cursorInEditArea - editAreaWidth + scrollMargin;\n }\n\n if (targetScrollX !== null) {\n // Smooth scroll: move gradually towards target instead of jumping\n const delta = targetScrollX - this._scrollX;\n const step = Math.sign(delta) * Math.min(Math.abs(delta), maxScrollStep);\n this.editAreaEl.scrollLeft = this._scrollX + step;\n }\n }\n\n /**\n * Sync time area scroll with edit area\n */\n _syncTimeAreaScroll() {\n if (!this.timeAreaWrapperEl) {\n // Fallback: try to find wrapper if reference is lost\n this.timeAreaWrapperEl = this.timeAreaEl?.querySelector('.timeline-editor-time-area-wrapper');\n }\n if (!this.timeAreaWrapperEl) return;\n this.timeAreaWrapperEl.style.transform = `translateX(-${this._scrollX}px)`;\n }\n\n /**\n * Handle cursor drag start\n */\n _handleCursorDragStart(e) {\n if (this.isPlaying || this.config.disableDrag) return;\n e.preventDefault();\n e.stopPropagation();\n\n // Callback\n if (this.callbacks.onCursorDragStart) {\n const result = this.callbacks.onCursorDragStart(e, { time: this.cursorTime });\n if (result === false) return;\n }\n\n this.dragState.isDragging = true;\n this.dragState.type = 'cursor';\n this.dragState.startX = e.clientX;\n\n this._boundHandleMouseMove = this._handleMouseMove.bind(this);\n this._boundHandleMouseUp = this._handleMouseUp.bind(this);\n\n document.addEventListener('mousemove', this._boundHandleMouseMove);\n document.addEventListener('mouseup', this._boundHandleMouseUp);\n }\n\n /**\n * Handle action move start\n */\n _handleMoveStart(e, action, row, rowIndex) {\n if (this.isPlaying || this.config.disableDrag) return;\n e.preventDefault();\n e.stopPropagation();\n\n // Cancel any active editing before starting drag\n this._cancelActiveEditing();\n\n this.dragState.isDragging = true;\n this.dragState.isActuallyDragging = false;\n this.dragState.type = 'action-move';\n this.dragState.action = action;\n this.dragState.row = row;\n this.dragState.rowIndex = rowIndex;\n this.dragState.startX = e.clientX;\n this.dragState.deltaX = 0;\n this.dragState.totalDeltaX = 0;\n this.dragState.currentLeft = parserTimeToPixel(action.start, this.config);\n this.dragState.currentWidth = parserTimeToPixel(action.end, this.config) - this.dragState.currentLeft;\n\n this._boundHandleMouseMove = this._handleMouseMove.bind(this);\n this._boundHandleMouseUp = this._handleMouseUp.bind(this);\n\n document.addEventListener('mousemove', this._boundHandleMouseMove);\n document.addEventListener('mouseup', this._boundHandleMouseUp);\n }\n\n /**\n * Handle action resize start\n */\n _handleResizeStart(e, action, row, rowIndex, direction) {\n if (this.isPlaying || this.config.disableDrag) return;\n e.preventDefault();\n e.stopPropagation();\n\n // Cancel any active editing before starting resize\n this._cancelActiveEditing();\n\n this.dragState.isDragging = true;\n this.dragState.isActuallyDragging = false;\n this.dragState.type = `action-resize-${direction}`;\n this.dragState.action = action;\n this.dragState.row = row;\n this.dragState.rowIndex = rowIndex;\n this.dragState.startX = e.clientX;\n this.dragState.deltaX = 0;\n this.dragState.totalDeltaX = 0;\n this.dragState.currentLeft = parserTimeToPixel(action.start, this.config);\n this.dragState.currentWidth = parserTimeToPixel(action.end, this.config) - this.dragState.currentLeft;\n\n this._boundHandleMouseMove = this._handleMouseMove.bind(this);\n this._boundHandleMouseUp = this._handleMouseUp.bind(this);\n\n document.addEventListener('mousemove', this._boundHandleMouseMove);\n document.addEventListener('mouseup', this._boundHandleMouseUp);\n }\n\n /**\n * Handle mouse move (unified for all drag types)\n */\n _handleMouseMove(e) {\n if (!this.dragState.isDragging) return;\n\n if (this.dragState.type === 'cursor') {\n this._handleCursorDrag(e);\n } else if (this.dragState.type === 'action-move') {\n const dx = e.clientX - this.dragState.startX;\n this.dragState.startX = e.clientX;\n this.dragState.deltaX += dx;\n this.dragState.totalDeltaX += Math.abs(dx);\n\n // Only trigger callback after moving 3px (threshold)\n if (!this.dragState.isActuallyDragging && this.dragState.totalDeltaX > 3) {\n this.dragState.isActuallyDragging = true;\n\n // Trigger callback now that we're actually dragging\n if (this.callbacks.onActionMoveStart) {\n const result = this.callbacks.onActionMoveStart({\n action: this.dragState.action,\n row: this.dragState.row\n });\n if (result === false) {\n this._cancelDrag();\n return;\n }\n }\n }\n\n if (this.dragState.isActuallyDragging) {\n this._handleActionMove();\n }\n } else if (this.dragState.type === 'action-resize-left') {\n const dx = e.clientX - this.dragState.startX;\n this.dragState.startX = e.clientX;\n this.dragState.deltaX += dx;\n this.dragState.totalDeltaX += Math.abs(dx);\n\n // Only trigger callback after moving 3px\n if (!this.dragState.isActuallyDragging && this.dragState.totalDeltaX > 3) {\n this.dragState.isActuallyDragging = true;\n\n if (this.callbacks.onActionResizeStart) {\n const result = this.callbacks.onActionResizeStart({\n action: this.dragState.action,\n row: this.dragState.row,\n direction: 'left'\n });\n if (result === false) {\n this._cancelDrag();\n return;\n }\n }\n }\n\n if (this.dragState.isActuallyDragging) {\n this._handleActionResizeLeft();\n }\n } else if (this.dragState.type === 'action-resize-right') {\n const dx = e.clientX - this.dragState.startX;\n this.dragState.startX = e.clientX;\n this.dragState.deltaX += dx;\n this.dragState.totalDeltaX += Math.abs(dx);\n\n // Only trigger callback after moving 3px\n if (!this.dragState.isActuallyDragging && this.dragState.totalDeltaX > 3) {\n this.dragState.isActuallyDragging = true;\n\n if (this.callbacks.onActionResizeStart) {\n const result = this.callbacks.onActionResizeStart({\n action: this.dragState.action,\n row: this.dragState.row,\n direction: 'right'\n });\n if (result === false) {\n this._cancelDrag();\n return;\n }\n }\n }\n\n if (this.dragState.isActuallyDragging) {\n this._handleActionResizeRight();\n }\n } else if (this.dragState.type === 'item-create') {\n const dx = e.clientX - this.dragState.startX;\n this.dragState.totalDeltaX += Math.abs(dx - (this.dragState.lastDx || 0));\n this.dragState.lastDx = dx;\n\n // Only create item after moving 3px (threshold)\n if (!this.dragState.isActuallyDragging && this.dragState.totalDeltaX > 3) {\n this.dragState.isActuallyDragging = true;\n this._createNewItemFromDrag();\n }\n\n if (this.dragState.isActuallyDragging && this.dragState.newItem) {\n this._updateNewItemFromDrag(e);\n }\n }\n }\n\n /**\n * Create new block when drag threshold is reached\n */\n _createNewItemFromDrag() {\n const row = this.dragState.row;\n const rowIndex = this.dragState.rowIndex;\n const startTime = Math.max(0, this.dragState.startTime);\n\n // Create new block with minimal duration (will expand as user drags)\n const newBlock = {\n id: `block-${Date.now()}`,\n name: '',\n start: startTime,\n end: startTime + 0.1, // Minimal initial duration\n flexible: true,\n movable: true,\n metadata: {}\n };\n\n // Add to row data (ensure blocks array exists)\n if (!row.blocks) row.blocks = [];\n row.blocks.push(newBlock);\n this.dragState.newItem = newBlock;\n\n // Create and append the visual element\n const rowEl = this.editAreaEl.querySelector(`[data-row-index=\"${rowIndex}\"]`);\n if (rowEl) {\n const actionEl = this._createAction(newBlock, row, rowIndex);\n actionEl.classList.add('creating');\n rowEl.appendChild(actionEl);\n this.dragState.newItemEl = actionEl;\n }\n }\n\n /**\n * Update new item size as user drags\n */\n _updateNewItemFromDrag(e) {\n const newItem = this.dragState.newItem;\n if (!newItem) return;\n\n const rect = this.editAreaEl.getBoundingClientRect();\n const contentPadding = this.config.contentPadding;\n // Edit area starts at 0, account for contentPadding, add startLeft for correct time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding + this.config.startLeft;\n const currentTime = parserPixelToTime(x, this.config);\n\n // Determine start and end based on drag direction\n const startTime = this.dragState.startTime;\n if (currentTime > startTime) {\n newItem.start = Math.max(0, startTime);\n newItem.end = currentTime;\n } else {\n newItem.start = Math.max(0, currentTime);\n newItem.end = startTime;\n }\n\n // Expand timeline if item extends beyond current bounds\n this._expandTimelineIfNeeded(newItem.end);\n\n // Update visual element (subtract startLeft since edit area starts at 0, add contentPadding)\n if (this.dragState.newItemEl) {\n const contentPadding = this.config.contentPadding;\n const left = parserTimeToPixel(newItem.start, this.config) - this.config.startLeft + contentPadding;\n const width = parserTimeToPixel(newItem.end, this.config) - this.config.startLeft + contentPadding - left;\n this.dragState.newItemEl.style.left = `${left}px`;\n this.dragState.newItemEl.style.width = `${Math.max(10, width)}px`;\n }\n }\n\n /**\n * Handle mouse up (unified)\n */\n _handleMouseUp(e) {\n if (!this.dragState.isDragging) return;\n\n const dragType = this.dragState.type;\n const action = this.dragState.action;\n const row = this.dragState.row;\n const wasActuallyDragging = this.dragState.isActuallyDragging;\n\n // Only trigger end callbacks if we actually dragged (past threshold)\n if (wasActuallyDragging) {\n // End callbacks\n if (dragType === 'cursor' && this.callbacks.onCursorDragEnd) {\n this.callbacks.onCursorDragEnd(e, { time: this.cursorTime });\n } else if (dragType === 'action-move' && this.callbacks.onActionMoveEnd) {\n this.callbacks.onActionMoveEnd({ action, row });\n } else if ((dragType === 'action-resize-left' || dragType === 'action-resize-right') && this.callbacks.onActionResizeEnd) {\n this.callbacks.onActionResizeEnd({ action, row });\n } else if (dragType === 'item-create' && this.dragState.newItem) {\n // Finalize item creation\n const newItem = this.dragState.newItem;\n if (this.dragState.newItemEl) {\n this.dragState.newItemEl.classList.remove('creating');\n }\n\n // Emit events\n this._emitChange();\n this.dispatchEvent(new CustomEvent('itemcreated', {\n detail: { item: newItem, row: row }\n }));\n }\n\n if (dragType && dragType.startsWith('action-')) {\n // Emit change event only if we actually moved/resized\n this._emitChange();\n }\n } else if (dragType === 'item-create' && this.dragState.newItem) {\n // User didn't drag enough - remove the item\n const row = this.dragState.row;\n const newItem = this.dragState.newItem;\n const items = row.blocks || row.items || row.actions || [];\n const idx = items.indexOf(newItem);\n if (idx > -1) {\n items.splice(idx, 1);\n }\n if (this.dragState.newItemEl) {\n this.dragState.newItemEl.remove();\n }\n }\n\n this.dragState.isDragging = false;\n this.dragState.isActuallyDragging = false;\n this.dragState.type = null;\n this.dragState.action = null;\n this.dragState.row = null;\n this.dragState.totalDeltaX = 0;\n this.dragState.newItem = null;\n this.dragState.newItemEl = null;\n this.dragState.lastDx = 0;\n\n document.removeEventListener('mousemove', this._boundHandleMouseMove);\n document.removeEventListener('mouseup', this._boundHandleMouseUp);\n }\n\n /**\n * Cancel drag operation\n */\n _cancelDrag() {\n this.dragState.isDragging = false;\n this.dragState.isActuallyDragging = false;\n this.dragState.type = null;\n this.dragState.action = null;\n this.dragState.row = null;\n this.dragState.totalDeltaX = 0;\n this.dragState.newItem = null;\n this.dragState.newItemEl = null;\n this.dragState.lastDx = 0;\n\n document.removeEventListener('mousemove', this._boundHandleMouseMove);\n document.removeEventListener('mouseup', this._boundHandleMouseUp);\n }\n\n /**\n * Handle cursor drag\n */\n _handleCursorDrag(e) {\n if (!this.editAreaEl) return;\n const rect = this.editAreaEl.getBoundingClientRect();\n const contentPadding = this.config.contentPadding;\n // Edit area starts at 0, account for contentPadding, add startLeft for correct time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding + this.config.startLeft;\n const time = Math.max(0, parserPixelToTime(x, this.config));\n\n // Callback\n if (this.callbacks.onCursorDrag) {\n const result = this.callbacks.onCursorDrag(e, { time });\n if (result === false) return;\n }\n\n // Update time and cursor with auto-scroll during drag\n this.cursorTime = time;\n this.engine.setTime(time);\n this._updateCursorPosition(true);\n }\n\n /**\n * Handle action move\n */\n _handleActionMove() {\n const action = this.dragState.action;\n const row = this.dragState.row;\n const grid = this.config.gridSnap ? this.config.scaleWidth / 10 : 1;\n\n // Only apply when accumulated delta exceeds grid\n if (Math.abs(this.dragState.deltaX) >= grid) {\n const count = parseInt(this.dragState.deltaX / grid);\n let newLeft = this.dragState.currentLeft + count * grid;\n\n // Apply grid snapping\n if (this.config.gridSnap) {\n const gridOffset = (newLeft - this.config.startLeft) % grid;\n if (gridOffset !== 0) {\n newLeft = this.config.startLeft + grid * Math.round((newLeft - this.config.startLeft) / grid);\n }\n }\n\n // Bounds check\n newLeft = Math.max(this.config.startLeft, newLeft);\n\n // Update current position\n this.dragState.currentLeft = newLeft;\n this.dragState.deltaX = this.dragState.deltaX % grid;\n\n const startTime = parserPixelToTime(newLeft, this.config);\n const duration = action.end - action.start;\n\n // Callback\n if (this.callbacks.onActionMoving) {\n const result = this.callbacks.onActionMoving({\n action,\n row,\n start: startTime,\n end: startTime + duration\n });\n if (result === false) return;\n }\n\n action.start = startTime;\n action.end = startTime + duration;\n\n // Expand timeline if action extends beyond current bounds\n this._expandTimelineIfNeeded(action.end);\n\n this._updateActionElement(action, this.dragState.rowIndex);\n }\n }\n\n /**\n * Handle action resize left\n */\n _handleActionResizeLeft() {\n const action = this.dragState.action;\n const row = this.dragState.row;\n const grid = this.config.gridSnap ? this.config.scaleWidth / 10 : 1;\n\n // Only apply when accumulated delta exceeds grid\n if (Math.abs(this.dragState.deltaX) >= grid) {\n const count = parseInt(this.dragState.deltaX / grid);\n let newLeft = this.dragState.currentLeft + count * grid;\n\n // Apply grid snapping\n if (this.config.gridSnap) {\n const gridOffset = (newLeft - this.config.startLeft) % grid;\n if (gridOffset !== 0) {\n newLeft = this.config.startLeft + grid * Math.round((newLeft - this.config.startLeft) / grid);\n }\n }\n\n // Keep right edge fixed\n const rightEdge = this.dragState.currentLeft + this.dragState.currentWidth;\n\n // Minimum width and bounds\n newLeft = Math.max(this.config.startLeft, newLeft);\n const minWidth = 10;\n newLeft = Math.min(newLeft, rightEdge - minWidth);\n\n const newWidth = rightEdge - newLeft;\n\n // Update state\n this.dragState.currentLeft = newLeft;\n this.dragState.currentWidth = newWidth;\n this.dragState.deltaX = this.dragState.deltaX % grid;\n\n const startTime = parserPixelToTime(newLeft, this.config);\n\n // Callback\n if (this.callbacks.onActionResizing) {\n const result = this.callbacks.onActionResizing({\n action,\n row,\n start: Math.max(0, startTime),\n end: action.end\n });\n if (result === false) return;\n }\n\n action.start = Math.max(0, startTime);\n\n this._updateActionElement(action, this.dragState.rowIndex);\n }\n }\n\n /**\n * Handle action resize right\n */\n _handleActionResizeRight() {\n const action = this.dragState.action;\n const row = this.dragState.row;\n const grid = this.config.gridSnap ? this.config.scaleWidth / 10 : 1;\n\n // Only apply when accumulated delta exceeds grid\n if (Math.abs(this.dragState.deltaX) >= grid) {\n const count = parseInt(this.dragState.deltaX / grid);\n let newWidth = this.dragState.currentWidth + count * grid;\n\n // Apply grid snapping to right edge\n const rightPos = this.dragState.currentLeft + newWidth;\n if (this.config.gridSnap) {\n const gridOffset = (rightPos - this.config.startLeft) % grid;\n if (gridOffset !== 0) {\n const snappedRight = this.config.startLeft + grid * Math.round((rightPos - this.config.startLeft) / grid);\n newWidth = snappedRight - this.dragState.currentLeft;\n }\n }\n\n // Minimum width\n const minWidth = 10;\n newWidth = Math.max(minWidth, newWidth);\n\n // Update state\n this.dragState.currentWidth = newWidth;\n this.dragState.deltaX = this.dragState.deltaX % grid;\n\n const endPixel = this.dragState.currentLeft + newWidth;\n const endTime = parserPixelToTime(endPixel, this.config);\n\n // Callback\n if (this.callbacks.onActionResizing) {\n const result = this.callbacks.onActionResizing({\n action,\n row,\n start: action.start,\n end: Math.max(action.start + 0.1, endTime)\n });\n if (result === false) return;\n }\n\n action.end = Math.max(action.start + 0.1, endTime);\n\n // Expand timeline if action extends beyond current bounds\n this._expandTimelineIfNeeded(action.end);\n\n this._updateActionElement(action, this.dragState.rowIndex);\n }\n }\n\n /**\n * Update action element visually\n */\n _updateActionElement(action, rowIndex) {\n const rowEl = this.editAreaEl.querySelector(`[data-row-index=\"${rowIndex}\"]`);\n if (!rowEl) return;\n\n const actionEl = rowEl.querySelector(`[data-action-id=\"${action.id}\"]`);\n if (!actionEl) return;\n\n // Content padding to match time ruler offset\n const contentPadding = this.config.contentPadding;\n // Edit area starts at 0 (label column is separate), so subtract startLeft, then add contentPadding\n const left = parserTimeToPixel(action.start, this.config) - this.config.startLeft + contentPadding;\n const width = parserTimeToPixel(action.end, this.config) - this.config.startLeft + contentPadding - left;\n\n actionEl.style.left = `${left}px`;\n actionEl.style.width = `${width}px`;\n }\n}\n\n// Register the custom element\nif (!customElements.get('trakk-editor')) {\n customElements.define('trakk-editor', Trakk);\n}\n"],"names":["EventEmitter","constructor","this","events","on","event","callback","push","off","filter","cb","emit","data","forEach","TrakkEngine","super","_timerId","_playRate","_currentTime","_playState","_prev","_effectMap","_actionMap","_actionSortIds","_next","_activeActionIds","isPlaying","isPaused","effects","pause","_dealData","_dealClear","_dealEnter","setPlayRate","rate","console","error","engine","getPlayRate","reRender","_tickAction","setTime","time","isTick","_dealLeave","getTime","play","toTime","autoEnd","currentTime","_startOrStop","requestAnimationFrame","_tick","now","to","cancelAnimationFrame","_end","type","i","length","actionId","action","effect","effectId","source","start","stop","Math","min","update","shift","leave","disable","end","includes","enter","splice","actions","row","items","blocks","sortActions","sort","a","b","actionMap","actionSortIds","id","parserTimeToPixel","startLeft","scale","scaleWidth","parserPixelToTime","pixel","Trakk","HTMLElement","config","scaleCount","scaleSplitCount","contentPadding","minScaleCount","maxScaleCount","Infinity","rowHeight","autoScroll","hideCursor","disableDrag","gridSnap","grid","callbacks","onActionMoveStart","onActionMoving","onActionMoveEnd","onActionResizeStart","onActionResizing","onActionResizeEnd","onClickRow","onClickAction","onDoubleClickRow","onDoubleClickAction","onContextMenuRow","onContextMenuAction","onCursorDragStart","onCursorDrag","onCursorDragEnd","onClickTimeArea","getActionRender","getScaleRender","tracks","cursorTime","_scrollX","_scrollY","timeAreaEl","timeAreaWrapperEl","editAreaEl","labelColumnEl","labelInnerEl","cursorEl","dragState","isDragging","isActuallyDragging","rowIndex","startX","startY","currentLeft","currentWidth","deltaX","totalDeltaX","connectedCallback","className","render","_setupEngineListeners","_setupResizeObserver","disconnectedCallback","_cleanup","document","removeEventListener","_boundHandleMouseMove","_boundHandleMouseUp","_resizeObserver","disconnect","ResizeObserver","entries","entry","_updateCursorPosition","observe","setData","setConfig","newConfig","Object","assign","setCallbacks","hasOwnProperty","getData","exportJSON","JSON","stringify","importJSON","jsonString","parse","editorData","e","saveToLocalStorage","key","localStorage","setItem","loadFromLocalStorage","getItem","max","getTotalTime","maxEnd","track","block","options","_syncEngineData","_emitChange","dispatchEvent","CustomEvent","detail","_expandTimelineIfNeeded","endTime","requiredScales","ceil","newScaleCount","_updateTimelineWidth","totalWidth","rowsContainer","querySelector","style","width","minWidth","rows","querySelectorAll","_rerenderTimeArea","newTimeArea","_createTimeArea","replaceWith","_syncTimeAreaScroll","classList","add","_scrollToCursorImmediate","remove","innerHTML","appendChild","_createCursor","setProperty","spacer","createElement","cssText","contentWrapper","_createLabelColumn","_createEditArea","scrollLeft","scrollTop","_syncLabelColumnScroll","timeArea","wrapper","height","position","interact","totalTicks","tickWidth","unit","isBig","marginLeft","scaleValue","customContent","textContent","toFixed","addEventListener","rect","getBoundingClientRect","x","clientX","left","labelColumn","labelInner","labelRow","_createLabelRow","borderTop","dataset","rowId","labelText","name","locked","cursor","stopPropagation","_startLabelEdit","lockIcon","noDelete","deleteBtn","_deleteTrack","editArea","rowEl","_createRow","transform","backgroundPosition","target","_cancelActiveEditing","currentTarget","preventDefault","_handleRowDragStart","item","actionEl","_createAction","currentName","input","value","editFinished","newName","trim","display","blur","insertBefore","focus","select","idx","indexOf","_deleteBlock","_startBlockNameEdit","content","activeInput","activeLabelInput","button","startTime","newItem","newItemEl","_handleMouseMove","bind","_handleMouseUp","selected","flexible","leftStretch","rightStretch","_handleResizeStart","movable","contains","_handleMoveStart","cursorTop","cursorArea","_handleCursorDragStart","shouldAutoScroll","_autoScrollToCursor","cursorLeft","editAreaWidth","clientWidth","cursorInEditArea","visibleLeft","visibleRight","targetScrollX","delta","step","sign","abs","direction","_handleCursorDrag","dx","_cancelDrag","_handleActionMove","_handleActionResizeLeft","_handleActionResizeRight","lastDx","_createNewItemFromDrag","_updateNewItemFromDrag","newBlock","Date","metadata","dragType","startsWith","count","parseInt","newLeft","round","duration","_updateActionElement","rightEdge","newWidth","rightPos","endPixel","customElements","get","define"],"mappings":"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"}
1
+ {"version":3,"file":"trakk.esm.js","sources":["../src/trakk-engine.js","../src/trakk.js"],"sourcesContent":["/**\n * Event Emitter for Trakk Engine\n */\nclass EventEmitter {\n constructor() {\n this.events = {};\n }\n\n on(event, callback) {\n if (!this.events[event]) {\n this.events[event] = [];\n }\n this.events[event].push(callback);\n }\n\n off(event, callback) {\n if (!this.events[event]) return;\n this.events[event] = this.events[event].filter(cb => cb !== callback);\n }\n\n emit(event, data) {\n if (!this.events[event]) return true;\n this.events[event].forEach(callback => callback(data));\n return true;\n }\n}\n\n/**\n * Trakk Engine - Core animation timeline player\n * Can run independently from the editor\n */\nexport class TrakkEngine extends EventEmitter {\n constructor() {\n super();\n\n this._timerId = null;\n this._playRate = 1;\n this._currentTime = 0;\n this._playState = 'paused';\n this._prev = 0;\n\n this._effectMap = {};\n this._actionMap = {};\n this._actionSortIds = [];\n\n this._next = 0;\n this._activeActionIds = [];\n }\n\n get isPlaying() {\n return this._playState === 'playing';\n }\n\n get isPaused() {\n return this._playState === 'paused';\n }\n\n set effects(effects) {\n this._effectMap = effects;\n }\n\n set data(data) {\n if (this.isPlaying) this.pause();\n this._dealData(data);\n this._dealClear();\n this._dealEnter(this._currentTime);\n }\n\n /**\n * Set playback rate\n */\n setPlayRate(rate) {\n if (rate <= 0) {\n console.error('Error: rate cannot be less than 0!');\n return false;\n }\n this._playRate = rate;\n this.emit('afterSetPlayRate', { rate, engine: this });\n return true;\n }\n\n getPlayRate() {\n return this._playRate;\n }\n\n /**\n * Re-render current time\n */\n reRender() {\n if (this.isPlaying) return;\n this._tickAction(this._currentTime);\n }\n\n /**\n * Set playback time\n */\n setTime(time, isTick = false) {\n this._currentTime = time;\n this._next = 0;\n this._dealLeave(time);\n this._dealEnter(time);\n\n if (isTick) {\n this.emit('setTimeByTick', { time, engine: this });\n } else {\n this.emit('afterSetTime', { time, engine: this });\n }\n return true;\n }\n\n getTime() {\n return this._currentTime;\n }\n\n /**\n * Play timeline\n */\n play({ toTime, autoEnd } = {}) {\n const currentTime = this.getTime();\n if (this.isPlaying || (toTime && toTime <= currentTime)) return false;\n\n this._playState = 'playing';\n this._startOrStop('start');\n this.emit('play', { engine: this });\n\n this._timerId = requestAnimationFrame((time) => {\n this._prev = time;\n this._tick({ now: time, autoEnd, to: toTime });\n });\n return true;\n }\n\n /**\n * Pause playback\n */\n pause() {\n if (this.isPlaying) {\n this._playState = 'paused';\n this._startOrStop('stop');\n this.emit('paused', { engine: this });\n }\n if (this._timerId) {\n cancelAnimationFrame(this._timerId);\n }\n }\n\n _end() {\n this.pause();\n this.emit('ended', { engine: this });\n }\n\n _startOrStop(type) {\n for (let i = 0; i < this._activeActionIds.length; i++) {\n const actionId = this._activeActionIds[i];\n const action = this._actionMap[actionId];\n const effect = this._effectMap[action?.effectId];\n\n if (type === 'start') {\n effect?.source?.start?.({ action, effect, engine: this, isPlaying: this.isPlaying, time: this.getTime() });\n } else if (type === 'stop') {\n effect?.source?.stop?.({ action, effect, engine: this, isPlaying: this.isPlaying, time: this.getTime() });\n }\n }\n }\n\n _tick(data) {\n if (this.isPaused) return;\n const { now, autoEnd, to } = data;\n\n let currentTime = this.getTime() + (Math.min(1000, now - this._prev) / 1000) * this._playRate;\n this._prev = now;\n\n if (to && to <= currentTime) currentTime = to;\n this.setTime(currentTime, true);\n\n this._tickAction(currentTime);\n\n if (!to && autoEnd && this._next >= this._actionSortIds.length && this._activeActionIds.length === 0) {\n this._end();\n return;\n }\n\n if (to && to <= currentTime) {\n this._end();\n return;\n }\n\n if (this.isPaused) return;\n this._timerId = requestAnimationFrame((time) => {\n this._tick({ now: time, autoEnd, to });\n });\n }\n\n _tickAction(time) {\n this._dealEnter(time);\n this._dealLeave(time);\n\n const length = this._activeActionIds.length;\n for (let i = 0; i < length; i++) {\n const actionId = this._activeActionIds[i];\n const action = this._actionMap[actionId];\n const effect = this._effectMap[action.effectId];\n if (effect?.source?.update) {\n effect.source.update({ time, action, isPlaying: this.isPlaying, effect, engine: this });\n }\n }\n }\n\n _dealClear() {\n while (this._activeActionIds.length) {\n const actionId = this._activeActionIds.shift();\n const action = this._actionMap[actionId];\n const effect = this._effectMap[action?.effectId];\n if (effect?.source?.leave) {\n effect.source.leave({ action, effect, engine: this, isPlaying: this.isPlaying, time: this.getTime() });\n }\n }\n this._next = 0;\n }\n\n _dealEnter(time) {\n while (this._actionSortIds[this._next]) {\n const actionId = this._actionSortIds[this._next];\n const action = this._actionMap[actionId];\n\n if (!action.disable) {\n if (action.start > time) break;\n if (action.end > time && !this._activeActionIds.includes(actionId)) {\n const effect = this._effectMap[action.effectId];\n if (effect?.source?.enter) {\n effect.source.enter({ action, effect, isPlaying: this.isPlaying, time, engine: this });\n }\n this._activeActionIds.push(actionId);\n }\n }\n this._next++;\n }\n }\n\n _dealLeave(time) {\n let i = 0;\n while (this._activeActionIds[i]) {\n const actionId = this._activeActionIds[i];\n const action = this._actionMap[actionId];\n\n if (action.start > time || action.end < time) {\n const effect = this._effectMap[action.effectId];\n if (effect?.source?.leave) {\n effect.source.leave({ action, effect, isPlaying: this.isPlaying, time, engine: this });\n }\n this._activeActionIds.splice(i, 1);\n continue;\n }\n i++;\n }\n }\n\n _dealData(data) {\n const actions = [];\n data.forEach(row => {\n // Support both new schema (blocks) and old schema (actions/items)\n const items = row.blocks || row.items || row.actions || [];\n actions.push(...items);\n });\n const sortActions = actions.sort((a, b) => a.start - b.start);\n const actionMap = {};\n const actionSortIds = [];\n\n sortActions.forEach(action => {\n actionSortIds.push(action.id);\n actionMap[action.id] = { ...action };\n });\n this._actionMap = actionMap;\n this._actionSortIds = actionSortIds;\n }\n}\n","import { TrakkEngine } from './trakk-engine.js';\n\n/**\n * Utility functions\n */\nconst parserTimeToPixel = (time, { startLeft, scale, scaleWidth }) => {\n return (time / scale) * scaleWidth + startLeft;\n};\n\nconst parserPixelToTime = (pixel, { startLeft, scale, scaleWidth }) => {\n return ((pixel - startLeft) / scaleWidth) * scale;\n};\n\n/**\n * Trakk - Timeline Editor Web Component\n */\nexport class Trakk extends HTMLElement {\n constructor() {\n super();\n\n // Default configuration\n this.config = {\n scale: 1,\n scaleWidth: 160,\n scaleCount: 20,\n scaleSplitCount: 10,\n startLeft: 120,\n contentPadding: 0,\n minScaleCount: 10,\n maxScaleCount: Infinity,\n rowHeight: 32,\n autoScroll: true,\n hideCursor: false,\n disableDrag: false,\n gridSnap: true,\n grid: 1,\n allowOverlap: false\n };\n\n // Callback functions\n this.callbacks = {\n onActionMoveStart: null,\n onActionMoving: null,\n onActionMoveEnd: null,\n onActionResizeStart: null,\n onActionResizing: null,\n onActionResizeEnd: null,\n onClickRow: null,\n onClickAction: null,\n onDoubleClickRow: null,\n onDoubleClickAction: null,\n onContextMenuRow: null,\n onContextMenuAction: null,\n onCursorDragStart: null,\n onCursorDrag: null,\n onCursorDragEnd: null,\n onClickTimeArea: null,\n getActionRender: null,\n getScaleRender: null\n };\n\n // State\n this.tracks = [];\n this.cursorTime = 0;\n this.isPlaying = false;\n this._scrollX = 0;\n this._scrollY = 0;\n this._selectedAction = null; // Currently selected action {action, row}\n\n // DOM refs\n this.timeAreaEl = null;\n this.timeAreaWrapperEl = null;\n this.editAreaEl = null;\n this.labelColumnEl = null;\n this.labelInnerEl = null;\n this.cursorEl = null;\n\n // Engine\n this.engine = new TrakkEngine();\n\n // Drag state\n this.dragState = {\n isDragging: false,\n isActuallyDragging: false, // Only true after threshold\n type: null,\n action: null,\n row: null,\n rowIndex: null,\n startX: 0,\n startY: 0,\n currentLeft: 0,\n currentWidth: 0,\n deltaX: 0,\n totalDeltaX: 0 // Track total movement\n };\n\n }\n\n connectedCallback() {\n this.className = 'timeline-editor';\n this.render();\n this._setupEngineListeners();\n this._setupResizeObserver();\n }\n\n disconnectedCallback() {\n this.engine.pause();\n this._cleanup();\n }\n\n _cleanup() {\n document.removeEventListener('mousemove', this._boundHandleMouseMove);\n document.removeEventListener('mouseup', this._boundHandleMouseUp);\n if (this._resizeObserver) {\n this._resizeObserver.disconnect();\n }\n }\n\n _setupResizeObserver() {\n // Watch for container size changes\n this._resizeObserver = new ResizeObserver((entries) => {\n for (let entry of entries) {\n // Re-render on resize to update layout\n if (this.editAreaEl) {\n this._updateCursorPosition();\n }\n }\n });\n this._resizeObserver.observe(this);\n }\n\n /**\n * Set timeline data\n */\n setData(tracks) {\n this.tracks = tracks || [];\n this.engine.data = this.tracks;\n this.render();\n }\n\n /**\n * Update configuration\n */\n setConfig(newConfig) {\n Object.assign(this.config, newConfig);\n this.render();\n }\n\n /**\n * Set callback functions\n */\n setCallbacks(callbacks) {\n Object.assign(this.callbacks, callbacks);\n }\n\n /**\n * Set a single callback\n */\n on(event, callback) {\n if (this.callbacks.hasOwnProperty(event)) {\n this.callbacks[event] = callback;\n }\n }\n\n /**\n * Get current timeline data (for export)\n */\n getData() {\n return {\n tracks: this.tracks\n };\n }\n\n /**\n * Export timeline to JSON string\n */\n exportJSON() {\n return JSON.stringify(this.getData(), null, 2);\n }\n\n /**\n * Import timeline from JSON string\n */\n importJSON(jsonString) {\n try {\n const data = JSON.parse(jsonString);\n // Support both old (editorData) and new (tracks) formats\n const tracks = data.tracks || data.editorData || [];\n this.setData(tracks);\n return true;\n } catch (e) {\n console.error('Failed to import timeline data:', e);\n return false;\n }\n }\n\n /**\n * Save to localStorage\n */\n saveToLocalStorage(key = 'timeline-data') {\n try {\n localStorage.setItem(key, this.exportJSON());\n return true;\n } catch (e) {\n console.error('Failed to save to localStorage:', e);\n return false;\n }\n }\n\n /**\n * Load from localStorage\n */\n loadFromLocalStorage(key = 'timeline-data') {\n try {\n const data = localStorage.getItem(key);\n if (data) {\n return this.importJSON(data);\n }\n return false;\n } catch (e) {\n console.error('Failed to load from localStorage:', e);\n return false;\n }\n }\n\n /**\n * Set current time\n */\n setTime(time) {\n this.cursorTime = Math.max(0, time);\n this.engine.setTime(this.cursorTime);\n this._updateCursorPosition();\n }\n\n /**\n * Get current time\n */\n getTime() {\n return this.engine.getTime();\n }\n\n /**\n * Get total time (end time of the last block across all tracks)\n */\n getTotalTime() {\n let maxEnd = 0;\n for (const track of this.tracks) {\n const blocks = track.blocks || track.items || track.actions || [];\n for (const block of blocks) {\n if (block.end > maxEnd) {\n maxEnd = block.end;\n }\n }\n }\n return maxEnd;\n }\n\n /**\n * Play timeline\n */\n play(options = {}) {\n return this.engine.play(options);\n }\n\n /**\n * Pause timeline\n */\n pause() {\n this.engine.pause();\n }\n\n /**\n * Sync engine data with current tracks (call after modifying tracks)\n */\n _syncEngineData() {\n this.engine.data = this.tracks;\n }\n\n /**\n * Emit change event and sync engine\n */\n _emitChange() {\n this._syncEngineData();\n this.dispatchEvent(new CustomEvent('change', {\n detail: { tracks: this.tracks }\n }));\n }\n\n /**\n * Select an action (block)\n * @param {Object|null} action - The action to select, or null to deselect\n * @param {Object|null} row - The row containing the action\n */\n selectAction(action, row = null) {\n // Remove previous selection\n const prevSelected = this.querySelector('.timeline-editor-action.selected');\n if (prevSelected) {\n prevSelected.classList.remove('selected');\n }\n\n // Update state\n const previousSelection = this._selectedAction;\n this._selectedAction = action ? { action, row } : null;\n\n // Add selection class to new action\n if (action) {\n const actionEl = this.querySelector(`[data-action-id=\"${action.id}\"]`);\n if (actionEl) {\n actionEl.classList.add('selected');\n }\n }\n\n // Emit select event\n this._emitSelect(action, row);\n }\n\n /**\n * Get the currently selected action\n * @returns {Object|null} - The selected action and row, or null\n */\n getSelectedAction() {\n return this._selectedAction;\n }\n\n /**\n * Deselect any selected action\n */\n deselectAction() {\n this.selectAction(null, null);\n }\n\n /**\n * Emit select event\n */\n _emitSelect(action, row) {\n this.dispatchEvent(new CustomEvent('select', {\n detail: action ? { action, row } : null\n }));\n }\n\n /**\n * Check if a time range would overlap with other actions in the same row\n * @param {Object} row - The row to check\n * @param {string} actionId - The action being moved/resized (to exclude from check)\n * @param {number} start - Proposed start time\n * @param {number} end - Proposed end time\n * @returns {boolean} - True if there would be an overlap\n */\n _wouldOverlap(row, actionId, start, end) {\n if (!row.blocks) return false;\n\n for (const block of row.blocks) {\n // Skip the action being moved/resized\n if (block.id === actionId) continue;\n\n // Check for overlap: ranges overlap if start1 < end2 AND end1 > start2\n if (start < block.end && end > block.start) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Get valid (non-overlapping) position for an action\n * @param {Object} row - The row containing the action\n * @param {string} actionId - The action being moved/resized\n * @param {number} proposedStart - Proposed start time\n * @param {number} proposedEnd - Proposed end time\n * @param {string} mode - 'move' or 'resize-left' or 'resize-right'\n * @returns {{start: number, end: number}} - Valid start and end times\n */\n _getValidPosition(row, actionId, proposedStart, proposedEnd, mode = 'move') {\n // If overlap is allowed, just return proposed values\n if (this.config.allowOverlap) {\n return { start: proposedStart, end: proposedEnd };\n }\n\n const duration = proposedEnd - proposedStart;\n\n // If no overlap, return proposed values\n if (!this._wouldOverlap(row, actionId, proposedStart, proposedEnd)) {\n return { start: proposedStart, end: proposedEnd };\n }\n\n // Find the blocking actions\n const otherBlocks = (row.blocks || [])\n .filter(b => b.id !== actionId)\n .sort((a, b) => a.start - b.start);\n\n if (mode === 'move') {\n // For move: find the closest valid position\n let bestStart = proposedStart;\n let bestEnd = proposedEnd;\n let minDistance = Infinity;\n\n // Try snapping to left edge of each blocking action\n for (const block of otherBlocks) {\n // Try placing before this block\n const candidateEnd = block.start;\n const candidateStart = candidateEnd - duration;\n if (candidateStart >= 0 && !this._wouldOverlap(row, actionId, candidateStart, candidateEnd)) {\n const distance = Math.abs(proposedStart - candidateStart);\n if (distance < minDistance) {\n minDistance = distance;\n bestStart = candidateStart;\n bestEnd = candidateEnd;\n }\n }\n\n // Try placing after this block\n const candidateStart2 = block.end;\n const candidateEnd2 = candidateStart2 + duration;\n if (!this._wouldOverlap(row, actionId, candidateStart2, candidateEnd2)) {\n const distance = Math.abs(proposedStart - candidateStart2);\n if (distance < minDistance) {\n minDistance = distance;\n bestStart = candidateStart2;\n bestEnd = candidateEnd2;\n }\n }\n }\n\n return { start: bestStart, end: bestEnd };\n } else if (mode === 'resize-left') {\n // For resize-left: find the maximum start we can have\n let maxStart = proposedStart;\n for (const block of otherBlocks) {\n if (block.end > proposedStart && block.end <= proposedEnd) {\n maxStart = Math.max(maxStart, block.end);\n }\n }\n return { start: maxStart, end: proposedEnd };\n } else if (mode === 'resize-right') {\n // For resize-right: find the minimum end we can have\n let minEnd = proposedEnd;\n for (const block of otherBlocks) {\n if (block.start < proposedEnd && block.start >= proposedStart) {\n minEnd = Math.min(minEnd, block.start);\n }\n }\n return { start: proposedStart, end: minEnd };\n }\n\n return { start: proposedStart, end: proposedEnd };\n }\n\n /**\n * Expand timeline if an action extends beyond current bounds\n * @param {number} endTime - The end time to check against\n * @returns {boolean} - Whether the timeline was expanded\n */\n _expandTimelineIfNeeded(endTime) {\n // Add 2 scale units of margin beyond the end time\n const marginScales = 2;\n const requiredScales = Math.ceil(endTime / this.config.scale) + marginScales;\n\n if (requiredScales > this.config.scaleCount) {\n // Respect maxScaleCount limit\n const newScaleCount = Math.min(requiredScales, this.config.maxScaleCount);\n if (newScaleCount > this.config.scaleCount) {\n this.config.scaleCount = newScaleCount;\n this._updateTimelineWidth();\n return true;\n }\n }\n return false;\n }\n\n /**\n * Update timeline width without full re-render (for dynamic expansion)\n */\n _updateTimelineWidth() {\n const contentPadding = this.config.contentPadding;\n const totalWidth = this.config.scaleCount * this.config.scaleWidth + contentPadding;\n\n // Update rows container width\n const rowsContainer = this.editAreaEl?.querySelector('.timeline-editor-rows');\n if (rowsContainer) {\n rowsContainer.style.width = `${totalWidth}px`;\n rowsContainer.style.minWidth = `${totalWidth}px`;\n }\n\n // Update each row width\n const rows = this.editAreaEl?.querySelectorAll('.timeline-editor-edit-row');\n if (rows) {\n rows.forEach(row => {\n row.style.width = `${totalWidth}px`;\n });\n }\n\n // Re-render time area to add new ticks\n this._rerenderTimeArea();\n }\n\n /**\n * Re-render time area (for dynamic expansion)\n */\n _rerenderTimeArea() {\n if (!this.timeAreaEl) return;\n\n // Create new time area content\n const newTimeArea = this._createTimeArea();\n\n // Replace old time area\n this.timeAreaEl.replaceWith(newTimeArea);\n this.timeAreaEl = newTimeArea;\n\n // Restore scroll sync\n this._syncTimeAreaScroll();\n }\n\n /**\n * Setup engine event listeners\n */\n _setupEngineListeners() {\n this.engine.on('play', () => {\n this.isPlaying = true;\n this.classList.add('timeline-editor-playing');\n // Jump to cursor immediately when play starts (not gradual scroll)\n this._scrollToCursorImmediate();\n });\n\n this.engine.on('paused', () => {\n this.isPlaying = false;\n this.classList.remove('timeline-editor-playing');\n });\n\n this.engine.on('setTimeByTick', ({ time }) => {\n this.cursorTime = time;\n this._updateCursorPosition(true); // Auto-scroll during playback\n });\n\n this.engine.on('afterSetTime', ({ time }) => {\n this.cursorTime = time;\n this._updateCursorPosition(false); // No auto-scroll for manual time set\n });\n }\n\n /**\n * Render the timeline editor\n */\n render() {\n this.innerHTML = '';\n\n // Time area (header row with ruler)\n this.timeAreaEl = this._createTimeArea();\n this.appendChild(this.timeAreaEl);\n\n // Cursor (created before content wrapper so it's behind label column)\n if (!this.config.hideCursor) {\n this.cursorEl = this._createCursor();\n this.appendChild(this.cursorEl);\n }\n\n // Set CSS custom properties for dynamic values\n this.style.setProperty('--timeline-start-left', `${this.config.startLeft}px`);\n this.style.setProperty('--timeline-content-padding', `${this.config.contentPadding}px`);\n this.style.setProperty('--timeline-scale-width', `${this.config.scaleWidth}px`);\n\n // Spacer div to cover cursor line between time area and content\n const spacer = document.createElement('div');\n spacer.className = 'timeline-editor-spacer';\n spacer.style.cssText = `\n height: 10px;\n width: calc(var(--timeline-start-left) - 4px);\n background-color: #191b1d;\n flex-shrink: 0;\n position: relative;\n z-index: 101;\n `;\n this.appendChild(spacer);\n\n // Main content wrapper (labels + edit area side by side)\n const contentWrapper = document.createElement('div');\n contentWrapper.className = 'timeline-editor-content';\n contentWrapper.style.cssText = `\n display: flex;\n flex: 1 1 0;\n overflow: hidden;\n position: relative;\n min-height: 0;\n min-width: 0;\n height: 0;\n `;\n\n // Frozen label column\n this.labelColumnEl = this._createLabelColumn();\n contentWrapper.appendChild(this.labelColumnEl);\n\n // Edit area (scrollable)\n this.editAreaEl = this._createEditArea();\n contentWrapper.appendChild(this.editAreaEl);\n\n this.appendChild(contentWrapper);\n\n // Restore scroll position and sync\n if (this._scrollX > 0) {\n this.editAreaEl.scrollLeft = this._scrollX;\n this._syncTimeAreaScroll();\n }\n if (this._scrollY > 0) {\n this.editAreaEl.scrollTop = this._scrollY;\n this._syncLabelColumnScroll();\n }\n this._updateCursorPosition();\n }\n\n /**\n * Create time area (ruler)\n */\n _createTimeArea() {\n const timeArea = document.createElement('div');\n timeArea.className = 'timeline-editor-time-area';\n\n // Content padding to push content away from label column edge\n const contentPadding = this.config.contentPadding;\n\n // Create a wrapper that will be scrolled\n const wrapper = document.createElement('div');\n wrapper.className = 'timeline-editor-time-area-wrapper';\n const totalWidth = this.config.scaleCount * this.config.scaleWidth + this.config.startLeft + contentPadding;\n wrapper.style.width = `${totalWidth}px`;\n wrapper.style.height = '100%';\n wrapper.style.position = 'relative';\n\n const interact = document.createElement('div');\n interact.className = 'timeline-editor-time-area-interact';\n interact.style.width = `${totalWidth}px`;\n\n // Calculate total number of tick marks including subdivisions\n const totalTicks = this.config.scaleCount * this.config.scaleSplitCount;\n const tickWidth = this.config.scaleWidth / this.config.scaleSplitCount;\n\n for (let i = 0; i <= totalTicks; i++) {\n const unit = document.createElement('div');\n const isBig = i % this.config.scaleSplitCount === 0;\n unit.className = `timeline-editor-time-unit ${isBig ? 'timeline-editor-time-unit-big' : ''}`;\n unit.style.width = `${tickWidth}px`;\n\n // Position first tick at startLeft + contentPadding to clear the blocker\n // The blocker covers the full startLeft area, so we add contentPadding to push \"0.0s\" label into view\n if (i === 0) {\n unit.style.marginLeft = `${this.config.startLeft + contentPadding - tickWidth + 1}px`;\n }\n\n if (isBig) {\n const scale = document.createElement('div');\n scale.className = 'timeline-editor-time-unit-scale';\n const scaleValue = (i / this.config.scaleSplitCount) * this.config.scale;\n\n // Use custom render if provided\n if (this.callbacks.getScaleRender) {\n const customContent = this.callbacks.getScaleRender(scaleValue);\n if (typeof customContent === 'string') {\n scale.innerHTML = customContent;\n } else if (customContent instanceof HTMLElement) {\n scale.innerHTML = '';\n scale.appendChild(customContent);\n }\n } else {\n // First tick shows \"0s\", others show decimal like \"1.0s\"\n scale.textContent = i === 0 ? '0s' : `${scaleValue.toFixed(1)}s`;\n }\n\n unit.appendChild(scale);\n }\n\n interact.appendChild(unit);\n }\n\n wrapper.appendChild(interact);\n timeArea.appendChild(wrapper);\n\n // Store wrapper reference for scroll sync\n this.timeAreaWrapperEl = wrapper;\n\n // Click handler for time area\n timeArea.addEventListener('click', (e) => {\n if (this.isPlaying) return;\n const rect = timeArea.getBoundingClientRect();\n // Account for contentPadding in time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding;\n const time = parserPixelToTime(x, this.config);\n\n // Callback\n if (this.callbacks.onClickTimeArea) {\n const result = this.callbacks.onClickTimeArea(e, { time });\n if (result === false) return;\n }\n\n this.setTime(Math.max(0, time));\n });\n\n return timeArea;\n }\n\n /**\n * Create frozen label column\n */\n _createLabelColumn() {\n const labelColumn = document.createElement('div');\n labelColumn.className = 'timeline-editor-label-column';\n labelColumn.style.cssText = `\n width: ${this.config.startLeft}px;\n flex-shrink: 0;\n overflow: hidden;\n background-color: #191b1d;\n border-right: 1px solid rgba(255, 255, 255, 0.1);\n z-index: 200;\n position: relative;\n `;\n\n // Inner container that will be transformed for scroll sync\n const labelInner = document.createElement('div');\n labelInner.className = 'timeline-editor-label-inner';\n this.labelInnerEl = labelInner;\n\n this.tracks.forEach((row, rowIndex) => {\n const labelRow = this._createLabelRow(row, rowIndex);\n labelInner.appendChild(labelRow);\n });\n\n labelColumn.appendChild(labelInner);\n return labelColumn;\n }\n\n /**\n * Create a label row (for frozen column)\n */\n _createLabelRow(row, rowIndex) {\n const labelRow = document.createElement('div');\n labelRow.className = 'timeline-editor-label-row';\n labelRow.style.cssText = `\n height: ${row.rowHeight || this.config.rowHeight}px;\n display: flex;\n align-items: center;\n padding: 0 8px;\n color: rgba(255, 255, 255, 0.7);\n font-size: 12px;\n font-weight: 500;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n box-sizing: border-box;\n position: relative;\n `;\n\n if (rowIndex === 0) {\n labelRow.style.borderTop = '1px solid rgba(255, 255, 255, 0.1)';\n }\n\n labelRow.dataset.rowId = row.id;\n labelRow.dataset.rowIndex = rowIndex;\n\n // Label text\n const labelText = document.createElement('span');\n labelText.className = 'timeline-editor-label-text';\n labelText.textContent = row.name || '';\n labelText.style.cssText = `\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n `;\n labelRow.appendChild(labelText);\n\n // Make label editable on dblclick (unless locked)\n if (!row.locked) {\n labelRow.style.cursor = 'text';\n labelRow.addEventListener('dblclick', (e) => {\n e.stopPropagation();\n this._startLabelEdit(labelRow, labelText, row);\n });\n }\n\n // Show locked indicator\n if (row.locked) {\n const lockIcon = document.createElement('span');\n lockIcon.className = 'timeline-editor-lock-icon';\n lockIcon.style.cssText = `\n width: 10px;\n height: 10px;\n margin-left: 6px;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='rgba(255,255,255,0.4)'%3E%3Cpath d='M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z'/%3E%3C/svg%3E\");\n background-size: contain;\n background-repeat: no-repeat;\n flex-shrink: 0;\n `;\n labelRow.appendChild(lockIcon);\n }\n\n // Add delete button (unless noDelete is set)\n if (!row.noDelete) {\n const deleteBtn = document.createElement('div');\n deleteBtn.className = 'timeline-editor-row-delete';\n deleteBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n this._deleteTrack(row);\n });\n labelRow.appendChild(deleteBtn);\n }\n\n return labelRow;\n }\n\n /**\n * Create edit area (rows and actions)\n */\n _createEditArea() {\n const editArea = document.createElement('div');\n editArea.className = 'timeline-editor-edit-area';\n\n // Extra padding to match the time area tick offset (content pushed away from label edge)\n const contentPadding = this.config.contentPadding;\n const totalWidth = this.config.scaleCount * this.config.scaleWidth + contentPadding;\n\n // Create rows container\n const rowsContainer = document.createElement('div');\n rowsContainer.className = 'timeline-editor-rows';\n rowsContainer.style.position = 'relative';\n rowsContainer.style.width = `${totalWidth}px`;\n rowsContainer.style.minWidth = `${totalWidth}px`;\n\n this.tracks.forEach((row, rowIndex) => {\n const rowEl = this._createRow(row, rowIndex, totalWidth, contentPadding);\n rowsContainer.appendChild(rowEl);\n });\n\n editArea.appendChild(rowsContainer);\n\n // Sync scroll with time area and label column\n editArea.addEventListener('scroll', () => {\n this._scrollX = editArea.scrollLeft;\n this._scrollY = editArea.scrollTop;\n this._syncTimeAreaScroll();\n this._syncLabelColumnScroll();\n this._updateCursorPosition();\n });\n\n // Click on edit area (not on action) deselects\n editArea.addEventListener('click', (e) => {\n // Only deselect if clicking directly on edit area or row, not on an action\n if (this._selectedAction) {\n this.deselectAction();\n }\n });\n\n return editArea;\n }\n\n /**\n * Sync label column scroll with edit area (vertical only)\n */\n _syncLabelColumnScroll() {\n if (!this.labelInnerEl) return;\n this.labelInnerEl.style.transform = `translateY(-${this._scrollY}px)`;\n }\n\n /**\n * Create a row (edit area only, no label - labels are in frozen column)\n */\n _createRow(row, rowIndex, totalWidth, contentPadding) {\n const rowEl = document.createElement('div');\n rowEl.className = 'timeline-editor-edit-row';\n rowEl.style.height = `${row.rowHeight || this.config.rowHeight}px`;\n rowEl.style.width = `${totalWidth}px`;\n\n // Offset background grid by contentPadding to align with time ruler (size comes from CSS variable)\n rowEl.style.backgroundPosition = `${contentPadding}px 0`;\n\n rowEl.dataset.rowId = row.id;\n rowEl.dataset.rowIndex = rowIndex;\n\n // Click handler\n rowEl.addEventListener('click', (e) => {\n // Only if clicking directly on the row (not on an action)\n if (e.target === rowEl) {\n // Cancel any active editing when clicking empty track area\n this._cancelActiveEditing();\n\n if (this.callbacks.onClickRow) {\n const rect = e.currentTarget.getBoundingClientRect();\n // Edit area starts at 0, account for contentPadding, add startLeft for correct time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding + this.config.startLeft;\n const time = parserPixelToTime(x, this.config);\n this.callbacks.onClickRow(e, { row, time });\n }\n }\n });\n\n // Double-click handler\n rowEl.addEventListener('dblclick', (e) => {\n if (e.target === rowEl && this.callbacks.onDoubleClickRow) {\n const rect = e.currentTarget.getBoundingClientRect();\n // Edit area starts at 0, account for contentPadding, add startLeft for correct time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding + this.config.startLeft;\n const time = parserPixelToTime(x, this.config);\n this.callbacks.onDoubleClickRow(e, { row, time });\n }\n });\n\n // Context menu handler\n rowEl.addEventListener('contextmenu', (e) => {\n if (e.target === rowEl && this.callbacks.onContextMenuRow) {\n e.preventDefault();\n const rect = e.currentTarget.getBoundingClientRect();\n // Edit area starts at 0, account for contentPadding, add startLeft for correct time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding + this.config.startLeft;\n const time = parserPixelToTime(x, this.config);\n this.callbacks.onContextMenuRow(e, { row, time });\n }\n });\n\n // Add mousedown handler for creating new items via drag on empty space\n rowEl.addEventListener('mousedown', (e) => {\n // Only if clicking directly on the row (not on an action)\n if (e.target === rowEl || e.target === rowEl.querySelector('.timeline-editor-row-label')) {\n this._handleRowDragStart(e, row, rowIndex);\n }\n });\n\n // Create items for this row (fallback to actions for backward compatibility)\n const items = row.blocks || row.items || row.actions || [];\n items.forEach((item) => {\n const actionEl = this._createAction(item, row, rowIndex);\n rowEl.appendChild(actionEl);\n });\n\n return rowEl;\n }\n\n /**\n * Start editing a track label\n */\n _startLabelEdit(labelRow, labelText, row) {\n if (labelRow.querySelector('input')) return; // Already editing\n\n const currentName = row.name || '';\n const input = document.createElement('input');\n input.type = 'text';\n input.value = currentName;\n input.className = 'timeline-editor-row-label-input';\n input.style.cssText = `\n flex: 1;\n min-width: 0;\n background: transparent;\n border: none;\n border-bottom: 1px solid rgba(255,255,255,0.3);\n color: inherit;\n font: inherit;\n outline: none;\n padding: 0;\n margin: 0;\n user-select: text;\n box-sizing: border-box;\n `;\n\n let editFinished = false;\n const finishEdit = () => {\n // Prevent double execution\n if (editFinished) return;\n editFinished = true;\n\n const newName = input.value.trim();\n row.name = newName;\n labelText.textContent = newName;\n labelText.style.display = '';\n input.remove();\n\n // Emit change event\n this._emitChange();\n this.dispatchEvent(new CustomEvent('trackrenamed', {\n detail: { track: row, name: newName }\n }));\n };\n\n input.addEventListener('blur', finishEdit);\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n input.blur();\n } else if (e.key === 'Escape') {\n input.value = currentName;\n input.blur();\n }\n });\n\n labelText.style.display = 'none';\n labelRow.insertBefore(input, labelText);\n input.focus();\n input.select();\n }\n\n /**\n * Delete a track\n */\n _deleteTrack(row) {\n // Remove from tracks array\n const idx = this.tracks.indexOf(row);\n if (idx > -1) {\n this.tracks.splice(idx, 1);\n }\n\n // Re-render\n this.render();\n\n // Emit events\n this._emitChange();\n this.dispatchEvent(new CustomEvent('trackdeleted', {\n detail: { track: row }\n }));\n }\n\n /**\n * Delete a block from a track\n */\n _deleteBlock(block, row) {\n const blocks = row.blocks || row.items || row.actions || [];\n const idx = blocks.indexOf(block);\n if (idx > -1) {\n blocks.splice(idx, 1);\n }\n\n // Re-render\n this.render();\n\n // Emit events\n this._emitChange();\n this.dispatchEvent(new CustomEvent('blockdeleted', {\n detail: { block, track: row }\n }));\n }\n\n /**\n * Start editing a block name\n */\n _startBlockNameEdit(actionEl, block, row) {\n const content = actionEl.querySelector('.timeline-editor-action-content');\n if (!content || content.querySelector('input')) return; // Already editing\n\n const currentName = block.name || '';\n const input = document.createElement('input');\n input.type = 'text';\n input.value = currentName;\n input.className = 'timeline-editor-block-name-input';\n input.style.cssText = `\n width: 100%;\n background: transparent;\n border: none;\n border-bottom: 1px solid rgba(255,255,255,0.3);\n color: inherit;\n font: inherit;\n outline: none;\n padding: 0;\n text-align: center;\n user-select: text;\n `;\n\n let editFinished = false;\n const finishEdit = () => {\n // Prevent double execution\n if (editFinished) return;\n editFinished = true;\n\n const newName = input.value.trim();\n block.name = newName;\n\n // Remove input and restore content\n input.remove();\n\n // Update content display\n if (this.callbacks.getActionRender) {\n const customContent = this.callbacks.getActionRender(block, row);\n if (typeof customContent === 'string') {\n content.innerHTML = customContent;\n }\n } else {\n content.textContent = newName;\n }\n\n // Emit change event\n this._emitChange();\n this.dispatchEvent(new CustomEvent('blockrenamed', {\n detail: { block, track: row, name: newName }\n }));\n };\n\n input.addEventListener('blur', finishEdit);\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n input.blur();\n } else if (e.key === 'Escape') {\n input.value = currentName;\n input.blur();\n }\n e.stopPropagation();\n });\n input.addEventListener('mousedown', (e) => e.stopPropagation());\n input.addEventListener('click', (e) => e.stopPropagation());\n\n content.innerHTML = '';\n content.appendChild(input);\n input.focus();\n input.select();\n }\n\n /**\n * Cancel any active block name editing by blurring input fields\n */\n _cancelActiveEditing() {\n const activeInput = this.querySelector('.timeline-editor-block-name-input');\n if (activeInput) {\n activeInput.blur();\n }\n const activeLabelInput = this.querySelector('.timeline-editor-row-label-input');\n if (activeLabelInput) {\n activeLabelInput.blur();\n }\n }\n\n /**\n * Handle drag start on empty row space to create new item\n */\n _handleRowDragStart(e, row, rowIndex) {\n if (this.isPlaying || this.config.disableDrag || row.locked) return;\n\n // Only left mouse button\n if (e.button !== 0) return;\n\n e.preventDefault();\n\n // Use editAreaEl for consistent coordinate calculation (same as _updateNewItemFromDrag)\n const rect = this.editAreaEl.getBoundingClientRect();\n const contentPadding = this.config.contentPadding;\n // Edit area starts at 0, account for contentPadding, add startLeft for correct time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding + this.config.startLeft;\n const startTime = parserPixelToTime(x, this.config);\n\n // Setup drag state for item creation\n this.dragState.isDragging = true;\n this.dragState.isActuallyDragging = false;\n this.dragState.type = 'item-create';\n this.dragState.row = row;\n this.dragState.rowIndex = rowIndex;\n this.dragState.startX = e.clientX;\n this.dragState.startTime = startTime;\n this.dragState.totalDeltaX = 0;\n this.dragState.newItem = null;\n this.dragState.newItemEl = null;\n\n this._boundHandleMouseMove = this._handleMouseMove.bind(this);\n this._boundHandleMouseUp = this._handleMouseUp.bind(this);\n\n document.addEventListener('mousemove', this._boundHandleMouseMove);\n document.addEventListener('mouseup', this._boundHandleMouseUp);\n }\n\n /**\n * Create an action element\n */\n _createAction(action, row, rowIndex) {\n const actionEl = document.createElement('div');\n actionEl.className = 'timeline-editor-action';\n if (action.selected) {\n actionEl.classList.add('selected');\n }\n\n // Content padding to match time ruler offset\n const contentPadding = this.config.contentPadding;\n // Edit area starts at 0 (label column is separate), so subtract startLeft, then add contentPadding\n const left = parserTimeToPixel(action.start, this.config) - this.config.startLeft + contentPadding;\n const width = parserTimeToPixel(action.end, this.config) - this.config.startLeft + contentPadding - left;\n\n actionEl.style.left = `${left}px`;\n actionEl.style.width = `${width}px`;\n actionEl.dataset.actionId = action.id;\n actionEl.dataset.rowIndex = rowIndex;\n\n // Content\n const content = document.createElement('div');\n content.className = 'timeline-editor-action-content';\n\n // Use custom render if provided\n if (this.callbacks.getActionRender) {\n const customContent = this.callbacks.getActionRender(action, row);\n if (typeof customContent === 'string') {\n content.innerHTML = customContent;\n } else if (customContent instanceof HTMLElement) {\n content.innerHTML = '';\n content.appendChild(customContent);\n }\n } else {\n // Display block name - only show if explicitly set (non-empty string)\n // Don't fall back to id as that creates ugly display\n content.textContent = action.name || '';\n }\n actionEl.appendChild(content);\n\n // Resize handles (only if not locked)\n if (action.flexible !== false && !row.locked) {\n const leftStretch = document.createElement('div');\n leftStretch.className = 'timeline-editor-action-left-stretch';\n actionEl.appendChild(leftStretch);\n\n const rightStretch = document.createElement('div');\n rightStretch.className = 'timeline-editor-action-right-stretch';\n actionEl.appendChild(rightStretch);\n\n leftStretch.addEventListener('mousedown', (e) => this._handleResizeStart(e, action, row, rowIndex, 'left'));\n rightStretch.addEventListener('mousedown', (e) => this._handleResizeStart(e, action, row, rowIndex, 'right'));\n }\n\n // Add drag listener for moving (only if not locked)\n if (action.movable !== false && !row.locked) {\n actionEl.addEventListener('mousedown', (e) => {\n // Ignore if clicking on resize handles\n if (e.target.classList.contains('timeline-editor-action-left-stretch') ||\n e.target.classList.contains('timeline-editor-action-right-stretch')) {\n return;\n }\n this._handleMoveStart(e, action, row, rowIndex);\n });\n }\n\n // Visual indicator for locked track\n if (row.locked) {\n actionEl.classList.add('timeline-editor-action-locked');\n actionEl.style.cursor = 'default';\n }\n\n // Add delete button for block (unless noDelete is set on block or track is locked)\n if (!action.noDelete && !row.locked) {\n const deleteBtn = document.createElement('div');\n deleteBtn.className = 'timeline-editor-action-delete';\n deleteBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n this._deleteBlock(action, row);\n });\n deleteBtn.addEventListener('mousedown', (e) => {\n e.stopPropagation(); // Prevent drag start\n });\n actionEl.appendChild(deleteBtn);\n }\n\n // Select on mousedown (immediate feedback, only if track is not locked)\n if (!row.locked) {\n actionEl.addEventListener('mousedown', (e) => {\n // Ignore if clicking on resize handles or delete button\n if (e.target.classList.contains('timeline-editor-action-left-stretch') ||\n e.target.classList.contains('timeline-editor-action-right-stretch') ||\n e.target.classList.contains('timeline-editor-action-delete')) {\n return;\n }\n this.selectAction(action, row);\n });\n }\n\n // Click event (for callback only, selection handled in mousedown)\n actionEl.addEventListener('click', (e) => {\n e.stopPropagation(); // Prevent deselection from edit area click\n\n if (this.callbacks.onClickAction) {\n const rect = this.editAreaEl.getBoundingClientRect();\n // Edit area starts at 0, account for contentPadding, add startLeft for correct time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding + this.config.startLeft;\n const time = parserPixelToTime(x, this.config);\n this.callbacks.onClickAction(e, { action, row, time });\n }\n });\n\n // Double-click event - edit block name (unless locked)\n actionEl.addEventListener('dblclick', (e) => {\n e.stopPropagation();\n\n // Allow callback to handle or prevent\n if (this.callbacks.onDoubleClickAction) {\n const rect = this.editAreaEl.getBoundingClientRect();\n // Edit area starts at 0, account for contentPadding, add startLeft for correct time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding + this.config.startLeft;\n const time = parserPixelToTime(x, this.config);\n const result = this.callbacks.onDoubleClickAction(e, { action, row, time });\n if (result === false) return;\n }\n\n // Start editing block name (unless track is locked)\n if (!row.locked) {\n this._startBlockNameEdit(actionEl, action, row);\n }\n });\n\n // Context menu event\n actionEl.addEventListener('contextmenu', (e) => {\n if (this.callbacks.onContextMenuAction) {\n e.preventDefault();\n const rect = this.editAreaEl.getBoundingClientRect();\n // Edit area starts at 0, account for contentPadding, add startLeft for correct time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding + this.config.startLeft;\n const time = parserPixelToTime(x, this.config);\n this.callbacks.onContextMenuAction(e, { action, row, time });\n }\n });\n\n return actionEl;\n }\n\n /**\n * Create cursor\n */\n _createCursor() {\n const cursor = document.createElement('div');\n cursor.className = 'timeline-editor-cursor';\n\n const cursorTop = document.createElement('div');\n cursorTop.className = 'timeline-editor-cursor-top';\n cursor.appendChild(cursorTop);\n\n const cursorArea = document.createElement('div');\n cursorArea.className = 'timeline-editor-cursor-area';\n cursor.appendChild(cursorArea);\n\n // Cursor drag\n cursorArea.addEventListener('mousedown', (e) => this._handleCursorDragStart(e));\n\n return cursor;\n }\n\n /**\n * Update cursor position\n * @param {boolean} shouldAutoScroll - Whether to auto-scroll to keep cursor visible (only during playback/drag)\n */\n _updateCursorPosition(shouldAutoScroll = false) {\n if (!this.cursorEl) return;\n const contentPadding = this.config.contentPadding;\n // parserTimeToPixel includes startLeft, which now represents the label column width\n // The cursor is positioned relative to the whole timeline including label column\n // Add contentPadding to align with the offset content\n const left = parserTimeToPixel(this.cursorTime, this.config) + contentPadding;\n // Cursor position relative to viewport, accounting for scroll\n this.cursorEl.style.left = `${left - this._scrollX}px`;\n\n // Auto-scroll to keep cursor visible (only when explicitly requested, e.g. during playback)\n if (shouldAutoScroll && this.config.autoScroll && this.editAreaEl) {\n this._autoScrollToCursor(left);\n }\n }\n\n /**\n * Scroll to cursor immediately (no gradual scroll) - used when play starts\n */\n _scrollToCursorImmediate() {\n if (!this.editAreaEl || !this.config.autoScroll) return;\n\n const contentPadding = this.config.contentPadding;\n const cursorLeft = parserTimeToPixel(this.cursorTime, this.config) + contentPadding;\n const editAreaWidth = this.editAreaEl.clientWidth;\n const cursorInEditArea = cursorLeft - this.config.startLeft;\n\n const scrollMargin = 50;\n const visibleLeft = this._scrollX;\n const visibleRight = this._scrollX + editAreaWidth;\n\n // Only jump if cursor is outside visible area\n if (cursorInEditArea < visibleLeft + scrollMargin || cursorInEditArea > visibleRight - scrollMargin) {\n // Center cursor in view (or near left edge if at start)\n const targetScrollX = Math.max(0, cursorInEditArea - editAreaWidth / 3);\n this.editAreaEl.scrollLeft = targetScrollX;\n }\n }\n\n /**\n * Auto-scroll edit area to keep cursor visible\n */\n _autoScrollToCursor(cursorLeft) {\n const editAreaWidth = this.editAreaEl.clientWidth;\n // Cursor position in edit area coordinates (subtract startLeft since edit area doesn't include label column)\n const cursorInEditArea = cursorLeft - this.config.startLeft;\n\n // Define margin - scroll when cursor is within this distance from edge\n const scrollMargin = 50;\n // Maximum scroll step per update for smooth scrolling\n const maxScrollStep = 8;\n\n // Check if cursor is outside visible area\n const visibleLeft = this._scrollX;\n const visibleRight = this._scrollX + editAreaWidth;\n\n let targetScrollX = null;\n\n if (cursorInEditArea < visibleLeft + scrollMargin) {\n // Cursor is too far left - scroll left\n targetScrollX = Math.max(0, cursorInEditArea - scrollMargin);\n } else if (cursorInEditArea > visibleRight - scrollMargin) {\n // Cursor is too far right - scroll right\n targetScrollX = cursorInEditArea - editAreaWidth + scrollMargin;\n }\n\n if (targetScrollX !== null) {\n // Smooth scroll: move gradually towards target instead of jumping\n const delta = targetScrollX - this._scrollX;\n const step = Math.sign(delta) * Math.min(Math.abs(delta), maxScrollStep);\n this.editAreaEl.scrollLeft = this._scrollX + step;\n }\n }\n\n /**\n * Sync time area scroll with edit area\n */\n _syncTimeAreaScroll() {\n if (!this.timeAreaWrapperEl) {\n // Fallback: try to find wrapper if reference is lost\n this.timeAreaWrapperEl = this.timeAreaEl?.querySelector('.timeline-editor-time-area-wrapper');\n }\n if (!this.timeAreaWrapperEl) return;\n this.timeAreaWrapperEl.style.transform = `translateX(-${this._scrollX}px)`;\n }\n\n /**\n * Handle cursor drag start\n */\n _handleCursorDragStart(e) {\n if (this.isPlaying || this.config.disableDrag) return;\n e.preventDefault();\n e.stopPropagation();\n\n // Callback\n if (this.callbacks.onCursorDragStart) {\n const result = this.callbacks.onCursorDragStart(e, { time: this.cursorTime });\n if (result === false) return;\n }\n\n this.dragState.isDragging = true;\n this.dragState.type = 'cursor';\n this.dragState.startX = e.clientX;\n\n this._boundHandleMouseMove = this._handleMouseMove.bind(this);\n this._boundHandleMouseUp = this._handleMouseUp.bind(this);\n\n document.addEventListener('mousemove', this._boundHandleMouseMove);\n document.addEventListener('mouseup', this._boundHandleMouseUp);\n }\n\n /**\n * Handle action move start\n */\n _handleMoveStart(e, action, row, rowIndex) {\n if (this.isPlaying || this.config.disableDrag) return;\n e.preventDefault();\n e.stopPropagation();\n\n // Cancel any active editing before starting drag\n this._cancelActiveEditing();\n\n this.dragState.isDragging = true;\n this.dragState.isActuallyDragging = false;\n this.dragState.type = 'action-move';\n this.dragState.action = action;\n this.dragState.row = row;\n this.dragState.rowIndex = rowIndex;\n this.dragState.startX = e.clientX;\n this.dragState.deltaX = 0;\n this.dragState.totalDeltaX = 0;\n this.dragState.currentLeft = parserTimeToPixel(action.start, this.config);\n this.dragState.currentWidth = parserTimeToPixel(action.end, this.config) - this.dragState.currentLeft;\n\n this._boundHandleMouseMove = this._handleMouseMove.bind(this);\n this._boundHandleMouseUp = this._handleMouseUp.bind(this);\n\n document.addEventListener('mousemove', this._boundHandleMouseMove);\n document.addEventListener('mouseup', this._boundHandleMouseUp);\n }\n\n /**\n * Handle action resize start\n */\n _handleResizeStart(e, action, row, rowIndex, direction) {\n if (this.isPlaying || this.config.disableDrag) return;\n e.preventDefault();\n e.stopPropagation();\n\n // Cancel any active editing before starting resize\n this._cancelActiveEditing();\n\n this.dragState.isDragging = true;\n this.dragState.isActuallyDragging = false;\n this.dragState.type = `action-resize-${direction}`;\n this.dragState.action = action;\n this.dragState.row = row;\n this.dragState.rowIndex = rowIndex;\n this.dragState.startX = e.clientX;\n this.dragState.deltaX = 0;\n this.dragState.totalDeltaX = 0;\n this.dragState.currentLeft = parserTimeToPixel(action.start, this.config);\n this.dragState.currentWidth = parserTimeToPixel(action.end, this.config) - this.dragState.currentLeft;\n\n this._boundHandleMouseMove = this._handleMouseMove.bind(this);\n this._boundHandleMouseUp = this._handleMouseUp.bind(this);\n\n document.addEventListener('mousemove', this._boundHandleMouseMove);\n document.addEventListener('mouseup', this._boundHandleMouseUp);\n }\n\n /**\n * Handle mouse move (unified for all drag types)\n */\n _handleMouseMove(e) {\n if (!this.dragState.isDragging) return;\n\n if (this.dragState.type === 'cursor') {\n this._handleCursorDrag(e);\n } else if (this.dragState.type === 'action-move') {\n const dx = e.clientX - this.dragState.startX;\n this.dragState.startX = e.clientX;\n this.dragState.deltaX += dx;\n this.dragState.totalDeltaX += Math.abs(dx);\n\n // Only trigger callback after moving 3px (threshold)\n if (!this.dragState.isActuallyDragging && this.dragState.totalDeltaX > 3) {\n this.dragState.isActuallyDragging = true;\n\n // Trigger callback now that we're actually dragging\n if (this.callbacks.onActionMoveStart) {\n const result = this.callbacks.onActionMoveStart({\n action: this.dragState.action,\n row: this.dragState.row\n });\n if (result === false) {\n this._cancelDrag();\n return;\n }\n }\n }\n\n if (this.dragState.isActuallyDragging) {\n this._handleActionMove();\n }\n } else if (this.dragState.type === 'action-resize-left') {\n const dx = e.clientX - this.dragState.startX;\n this.dragState.startX = e.clientX;\n this.dragState.deltaX += dx;\n this.dragState.totalDeltaX += Math.abs(dx);\n\n // Only trigger callback after moving 3px\n if (!this.dragState.isActuallyDragging && this.dragState.totalDeltaX > 3) {\n this.dragState.isActuallyDragging = true;\n\n if (this.callbacks.onActionResizeStart) {\n const result = this.callbacks.onActionResizeStart({\n action: this.dragState.action,\n row: this.dragState.row,\n direction: 'left'\n });\n if (result === false) {\n this._cancelDrag();\n return;\n }\n }\n }\n\n if (this.dragState.isActuallyDragging) {\n this._handleActionResizeLeft();\n }\n } else if (this.dragState.type === 'action-resize-right') {\n const dx = e.clientX - this.dragState.startX;\n this.dragState.startX = e.clientX;\n this.dragState.deltaX += dx;\n this.dragState.totalDeltaX += Math.abs(dx);\n\n // Only trigger callback after moving 3px\n if (!this.dragState.isActuallyDragging && this.dragState.totalDeltaX > 3) {\n this.dragState.isActuallyDragging = true;\n\n if (this.callbacks.onActionResizeStart) {\n const result = this.callbacks.onActionResizeStart({\n action: this.dragState.action,\n row: this.dragState.row,\n direction: 'right'\n });\n if (result === false) {\n this._cancelDrag();\n return;\n }\n }\n }\n\n if (this.dragState.isActuallyDragging) {\n this._handleActionResizeRight();\n }\n } else if (this.dragState.type === 'item-create') {\n const dx = e.clientX - this.dragState.startX;\n this.dragState.totalDeltaX += Math.abs(dx - (this.dragState.lastDx || 0));\n this.dragState.lastDx = dx;\n\n // Only create item after moving 3px (threshold)\n if (!this.dragState.isActuallyDragging && this.dragState.totalDeltaX > 3) {\n this.dragState.isActuallyDragging = true;\n this._createNewItemFromDrag();\n }\n\n if (this.dragState.isActuallyDragging && this.dragState.newItem) {\n this._updateNewItemFromDrag(e);\n }\n }\n }\n\n /**\n * Create new block when drag threshold is reached\n */\n _createNewItemFromDrag() {\n const row = this.dragState.row;\n const rowIndex = this.dragState.rowIndex;\n const startTime = Math.max(0, this.dragState.startTime);\n\n // Create new block with minimal duration (will expand as user drags)\n const newBlock = {\n id: `block-${Date.now()}`,\n name: '',\n start: startTime,\n end: startTime + 0.1, // Minimal initial duration\n flexible: true,\n movable: true,\n metadata: {}\n };\n\n // Add to row data (ensure blocks array exists)\n if (!row.blocks) row.blocks = [];\n row.blocks.push(newBlock);\n this.dragState.newItem = newBlock;\n\n // Create and append the visual element\n const rowEl = this.editAreaEl.querySelector(`[data-row-index=\"${rowIndex}\"]`);\n if (rowEl) {\n const actionEl = this._createAction(newBlock, row, rowIndex);\n actionEl.classList.add('creating');\n rowEl.appendChild(actionEl);\n this.dragState.newItemEl = actionEl;\n }\n }\n\n /**\n * Update new item size as user drags\n */\n _updateNewItemFromDrag(e) {\n const newItem = this.dragState.newItem;\n if (!newItem) return;\n\n const rect = this.editAreaEl.getBoundingClientRect();\n const contentPadding = this.config.contentPadding;\n // Edit area starts at 0, account for contentPadding, add startLeft for correct time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding + this.config.startLeft;\n const currentTime = parserPixelToTime(x, this.config);\n\n // Determine start and end based on drag direction\n const startTime = this.dragState.startTime;\n if (currentTime > startTime) {\n newItem.start = Math.max(0, startTime);\n newItem.end = currentTime;\n } else {\n newItem.start = Math.max(0, currentTime);\n newItem.end = startTime;\n }\n\n // Expand timeline if item extends beyond current bounds\n this._expandTimelineIfNeeded(newItem.end);\n\n // Update visual element (subtract startLeft since edit area starts at 0, add contentPadding)\n if (this.dragState.newItemEl) {\n const contentPadding = this.config.contentPadding;\n const left = parserTimeToPixel(newItem.start, this.config) - this.config.startLeft + contentPadding;\n const width = parserTimeToPixel(newItem.end, this.config) - this.config.startLeft + contentPadding - left;\n this.dragState.newItemEl.style.left = `${left}px`;\n this.dragState.newItemEl.style.width = `${Math.max(10, width)}px`;\n }\n }\n\n /**\n * Handle mouse up (unified)\n */\n _handleMouseUp(e) {\n if (!this.dragState.isDragging) return;\n\n const dragType = this.dragState.type;\n const action = this.dragState.action;\n const row = this.dragState.row;\n const wasActuallyDragging = this.dragState.isActuallyDragging;\n\n // Only trigger end callbacks if we actually dragged (past threshold)\n if (wasActuallyDragging) {\n // End callbacks\n if (dragType === 'cursor' && this.callbacks.onCursorDragEnd) {\n this.callbacks.onCursorDragEnd(e, { time: this.cursorTime });\n } else if (dragType === 'action-move' && this.callbacks.onActionMoveEnd) {\n this.callbacks.onActionMoveEnd({ action, row });\n } else if ((dragType === 'action-resize-left' || dragType === 'action-resize-right') && this.callbacks.onActionResizeEnd) {\n this.callbacks.onActionResizeEnd({ action, row });\n } else if (dragType === 'item-create' && this.dragState.newItem) {\n // Finalize item creation\n const newItem = this.dragState.newItem;\n if (this.dragState.newItemEl) {\n this.dragState.newItemEl.classList.remove('creating');\n }\n\n // Emit events\n this._emitChange();\n this.dispatchEvent(new CustomEvent('itemcreated', {\n detail: { item: newItem, row: row }\n }));\n }\n\n if (dragType && dragType.startsWith('action-')) {\n // Emit change event only if we actually moved/resized\n this._emitChange();\n }\n } else if (dragType === 'item-create' && this.dragState.newItem) {\n // User didn't drag enough - remove the item\n const row = this.dragState.row;\n const newItem = this.dragState.newItem;\n const items = row.blocks || row.items || row.actions || [];\n const idx = items.indexOf(newItem);\n if (idx > -1) {\n items.splice(idx, 1);\n }\n if (this.dragState.newItemEl) {\n this.dragState.newItemEl.remove();\n }\n }\n\n this.dragState.isDragging = false;\n this.dragState.isActuallyDragging = false;\n this.dragState.type = null;\n this.dragState.action = null;\n this.dragState.row = null;\n this.dragState.totalDeltaX = 0;\n this.dragState.newItem = null;\n this.dragState.newItemEl = null;\n this.dragState.lastDx = 0;\n\n document.removeEventListener('mousemove', this._boundHandleMouseMove);\n document.removeEventListener('mouseup', this._boundHandleMouseUp);\n }\n\n /**\n * Cancel drag operation\n */\n _cancelDrag() {\n this.dragState.isDragging = false;\n this.dragState.isActuallyDragging = false;\n this.dragState.type = null;\n this.dragState.action = null;\n this.dragState.row = null;\n this.dragState.totalDeltaX = 0;\n this.dragState.newItem = null;\n this.dragState.newItemEl = null;\n this.dragState.lastDx = 0;\n\n document.removeEventListener('mousemove', this._boundHandleMouseMove);\n document.removeEventListener('mouseup', this._boundHandleMouseUp);\n }\n\n /**\n * Handle cursor drag\n */\n _handleCursorDrag(e) {\n if (!this.editAreaEl) return;\n const rect = this.editAreaEl.getBoundingClientRect();\n const contentPadding = this.config.contentPadding;\n // Edit area starts at 0, account for contentPadding, add startLeft for correct time conversion\n const x = e.clientX - rect.left + this._scrollX - contentPadding + this.config.startLeft;\n const time = Math.max(0, parserPixelToTime(x, this.config));\n\n // Callback\n if (this.callbacks.onCursorDrag) {\n const result = this.callbacks.onCursorDrag(e, { time });\n if (result === false) return;\n }\n\n // Update time and cursor with auto-scroll during drag\n this.cursorTime = time;\n this.engine.setTime(time);\n this._updateCursorPosition(true);\n }\n\n /**\n * Handle action move\n */\n _handleActionMove() {\n const action = this.dragState.action;\n const row = this.dragState.row;\n const grid = this.config.gridSnap ? this.config.scaleWidth / 10 : 1;\n\n // Only apply when accumulated delta exceeds grid\n if (Math.abs(this.dragState.deltaX) >= grid) {\n const count = parseInt(this.dragState.deltaX / grid);\n let newLeft = this.dragState.currentLeft + count * grid;\n\n // Apply grid snapping\n if (this.config.gridSnap) {\n const gridOffset = (newLeft - this.config.startLeft) % grid;\n if (gridOffset !== 0) {\n newLeft = this.config.startLeft + grid * Math.round((newLeft - this.config.startLeft) / grid);\n }\n }\n\n // Bounds check\n newLeft = Math.max(this.config.startLeft, newLeft);\n\n // Update current position\n this.dragState.currentLeft = newLeft;\n this.dragState.deltaX = this.dragState.deltaX % grid;\n\n const duration = action.end - action.start;\n let startTime = parserPixelToTime(newLeft, this.config);\n let endTime = startTime + duration;\n\n // Check for overlap and get valid position\n const validPos = this._getValidPosition(row, action.id, startTime, endTime, 'move');\n startTime = validPos.start;\n endTime = validPos.end;\n\n // Callback\n if (this.callbacks.onActionMoving) {\n const result = this.callbacks.onActionMoving({\n action,\n row,\n start: startTime,\n end: endTime\n });\n if (result === false) return;\n }\n\n action.start = startTime;\n action.end = endTime;\n\n // Expand timeline if action extends beyond current bounds\n this._expandTimelineIfNeeded(action.end);\n\n this._updateActionElement(action, this.dragState.rowIndex);\n }\n }\n\n /**\n * Handle action resize left\n */\n _handleActionResizeLeft() {\n const action = this.dragState.action;\n const row = this.dragState.row;\n const grid = this.config.gridSnap ? this.config.scaleWidth / 10 : 1;\n\n // Only apply when accumulated delta exceeds grid\n if (Math.abs(this.dragState.deltaX) >= grid) {\n const count = parseInt(this.dragState.deltaX / grid);\n let newLeft = this.dragState.currentLeft + count * grid;\n\n // Apply grid snapping\n if (this.config.gridSnap) {\n const gridOffset = (newLeft - this.config.startLeft) % grid;\n if (gridOffset !== 0) {\n newLeft = this.config.startLeft + grid * Math.round((newLeft - this.config.startLeft) / grid);\n }\n }\n\n // Keep right edge fixed\n const rightEdge = this.dragState.currentLeft + this.dragState.currentWidth;\n\n // Minimum width and bounds\n newLeft = Math.max(this.config.startLeft, newLeft);\n const minWidth = 10;\n newLeft = Math.min(newLeft, rightEdge - minWidth);\n\n const newWidth = rightEdge - newLeft;\n\n // Update state\n this.dragState.currentLeft = newLeft;\n this.dragState.currentWidth = newWidth;\n this.dragState.deltaX = this.dragState.deltaX % grid;\n\n let startTime = Math.max(0, parserPixelToTime(newLeft, this.config));\n const endTime = action.end;\n\n // Check for overlap and get valid position\n const validPos = this._getValidPosition(row, action.id, startTime, endTime, 'resize-left');\n startTime = validPos.start;\n\n // Callback\n if (this.callbacks.onActionResizing) {\n const result = this.callbacks.onActionResizing({\n action,\n row,\n start: startTime,\n end: endTime\n });\n if (result === false) return;\n }\n\n action.start = startTime;\n\n this._updateActionElement(action, this.dragState.rowIndex);\n }\n }\n\n /**\n * Handle action resize right\n */\n _handleActionResizeRight() {\n const action = this.dragState.action;\n const row = this.dragState.row;\n const grid = this.config.gridSnap ? this.config.scaleWidth / 10 : 1;\n\n // Only apply when accumulated delta exceeds grid\n if (Math.abs(this.dragState.deltaX) >= grid) {\n const count = parseInt(this.dragState.deltaX / grid);\n let newWidth = this.dragState.currentWidth + count * grid;\n\n // Apply grid snapping to right edge\n const rightPos = this.dragState.currentLeft + newWidth;\n if (this.config.gridSnap) {\n const gridOffset = (rightPos - this.config.startLeft) % grid;\n if (gridOffset !== 0) {\n const snappedRight = this.config.startLeft + grid * Math.round((rightPos - this.config.startLeft) / grid);\n newWidth = snappedRight - this.dragState.currentLeft;\n }\n }\n\n // Minimum width\n const minWidth = 10;\n newWidth = Math.max(minWidth, newWidth);\n\n // Update state\n this.dragState.currentWidth = newWidth;\n this.dragState.deltaX = this.dragState.deltaX % grid;\n\n const endPixel = this.dragState.currentLeft + newWidth;\n const startTime = action.start;\n let endTime = Math.max(startTime + 0.1, parserPixelToTime(endPixel, this.config));\n\n // Check for overlap and get valid position\n const validPos = this._getValidPosition(row, action.id, startTime, endTime, 'resize-right');\n endTime = validPos.end;\n\n // Callback\n if (this.callbacks.onActionResizing) {\n const result = this.callbacks.onActionResizing({\n action,\n row,\n start: startTime,\n end: endTime\n });\n if (result === false) return;\n }\n\n action.end = endTime;\n\n // Expand timeline if action extends beyond current bounds\n this._expandTimelineIfNeeded(action.end);\n\n this._updateActionElement(action, this.dragState.rowIndex);\n }\n }\n\n /**\n * Update action element visually\n */\n _updateActionElement(action, rowIndex) {\n const rowEl = this.editAreaEl.querySelector(`[data-row-index=\"${rowIndex}\"]`);\n if (!rowEl) return;\n\n const actionEl = rowEl.querySelector(`[data-action-id=\"${action.id}\"]`);\n if (!actionEl) return;\n\n // Content padding to match time ruler offset\n const contentPadding = this.config.contentPadding;\n // Edit area starts at 0 (label column is separate), so subtract startLeft, then add contentPadding\n const left = parserTimeToPixel(action.start, this.config) - this.config.startLeft + contentPadding;\n const width = parserTimeToPixel(action.end, this.config) - this.config.startLeft + contentPadding - left;\n\n actionEl.style.left = `${left}px`;\n actionEl.style.width = `${width}px`;\n }\n}\n\n// Register the custom element\nif (!customElements.get('trakk-editor')) {\n customElements.define('trakk-editor', Trakk);\n}\n"],"names":["EventEmitter","constructor","this","events","on","event","callback","push","off","filter","cb","emit","data","forEach","TrakkEngine","super","_timerId","_playRate","_currentTime","_playState","_prev","_effectMap","_actionMap","_actionSortIds","_next","_activeActionIds","isPlaying","isPaused","effects","pause","_dealData","_dealClear","_dealEnter","setPlayRate","rate","console","error","engine","getPlayRate","reRender","_tickAction","setTime","time","isTick","_dealLeave","getTime","play","toTime","autoEnd","currentTime","_startOrStop","requestAnimationFrame","_tick","now","to","cancelAnimationFrame","_end","type","i","length","actionId","action","effect","effectId","source","start","stop","Math","min","update","shift","leave","disable","end","includes","enter","splice","actions","row","items","blocks","sortActions","sort","a","b","actionMap","actionSortIds","id","parserTimeToPixel","startLeft","scale","scaleWidth","parserPixelToTime","pixel","Trakk","HTMLElement","config","scaleCount","scaleSplitCount","contentPadding","minScaleCount","maxScaleCount","Infinity","rowHeight","autoScroll","hideCursor","disableDrag","gridSnap","grid","allowOverlap","callbacks","onActionMoveStart","onActionMoving","onActionMoveEnd","onActionResizeStart","onActionResizing","onActionResizeEnd","onClickRow","onClickAction","onDoubleClickRow","onDoubleClickAction","onContextMenuRow","onContextMenuAction","onCursorDragStart","onCursorDrag","onCursorDragEnd","onClickTimeArea","getActionRender","getScaleRender","tracks","cursorTime","_scrollX","_scrollY","_selectedAction","timeAreaEl","timeAreaWrapperEl","editAreaEl","labelColumnEl","labelInnerEl","cursorEl","dragState","isDragging","isActuallyDragging","rowIndex","startX","startY","currentLeft","currentWidth","deltaX","totalDeltaX","connectedCallback","className","render","_setupEngineListeners","_setupResizeObserver","disconnectedCallback","_cleanup","document","removeEventListener","_boundHandleMouseMove","_boundHandleMouseUp","_resizeObserver","disconnect","ResizeObserver","entries","entry","_updateCursorPosition","observe","setData","setConfig","newConfig","Object","assign","setCallbacks","hasOwnProperty","getData","exportJSON","JSON","stringify","importJSON","jsonString","parse","editorData","e","saveToLocalStorage","key","localStorage","setItem","loadFromLocalStorage","getItem","max","getTotalTime","maxEnd","track","block","options","_syncEngineData","_emitChange","dispatchEvent","CustomEvent","detail","selectAction","prevSelected","querySelector","classList","remove","actionEl","add","_emitSelect","getSelectedAction","deselectAction","_wouldOverlap","_getValidPosition","proposedStart","proposedEnd","mode","duration","otherBlocks","bestStart","bestEnd","minDistance","candidateEnd","candidateStart","distance","abs","candidateStart2","candidateEnd2","maxStart","minEnd","_expandTimelineIfNeeded","endTime","requiredScales","ceil","newScaleCount","_updateTimelineWidth","totalWidth","rowsContainer","style","width","minWidth","rows","querySelectorAll","_rerenderTimeArea","newTimeArea","_createTimeArea","replaceWith","_syncTimeAreaScroll","_scrollToCursorImmediate","innerHTML","appendChild","_createCursor","setProperty","spacer","createElement","cssText","contentWrapper","_createLabelColumn","_createEditArea","scrollLeft","scrollTop","_syncLabelColumnScroll","timeArea","wrapper","height","position","interact","totalTicks","tickWidth","unit","isBig","marginLeft","scaleValue","customContent","textContent","toFixed","addEventListener","rect","getBoundingClientRect","x","clientX","left","labelColumn","labelInner","labelRow","_createLabelRow","borderTop","dataset","rowId","labelText","name","locked","cursor","stopPropagation","_startLabelEdit","lockIcon","noDelete","deleteBtn","_deleteTrack","editArea","rowEl","_createRow","transform","backgroundPosition","target","_cancelActiveEditing","currentTarget","preventDefault","_handleRowDragStart","item","_createAction","currentName","input","value","editFinished","newName","trim","display","blur","insertBefore","focus","select","idx","indexOf","_deleteBlock","_startBlockNameEdit","content","activeInput","activeLabelInput","button","startTime","newItem","newItemEl","_handleMouseMove","bind","_handleMouseUp","selected","flexible","leftStretch","rightStretch","_handleResizeStart","movable","contains","_handleMoveStart","cursorTop","cursorArea","_handleCursorDragStart","shouldAutoScroll","_autoScrollToCursor","cursorLeft","editAreaWidth","clientWidth","cursorInEditArea","visibleLeft","visibleRight","targetScrollX","delta","step","sign","direction","_handleCursorDrag","dx","_cancelDrag","_handleActionMove","_handleActionResizeLeft","_handleActionResizeRight","lastDx","_createNewItemFromDrag","_updateNewItemFromDrag","newBlock","Date","metadata","dragType","startsWith","count","parseInt","newLeft","round","validPos","_updateActionElement","rightEdge","newWidth","rightPos","endPixel","customElements","get","define"],"mappings":"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"}