(el, pointer)
| 290 | // --- Core Drag Logic --- |
| 291 | |
| 292 | startDrag(el, pointer) { |
| 293 | // Double check state |
| 294 | if (this.dragState) { |
| 295 | this.destroy(); |
| 296 | return; |
| 297 | } |
| 298 | |
| 299 | if (navigator.vibrate) navigator.vibrate(30); |
| 300 | |
| 301 | const rect = el.getBoundingClientRect(); |
| 302 | const ghost = el.cloneNode(true); |
| 303 | ghost.classList.add("tool-ghost"); |
| 304 | ghost.style.width = rect.width + "px"; |
| 305 | ghost.style.height = rect.height + "px"; |
| 306 | |
| 307 | document.body.appendChild(ghost); |
| 308 | el.classList.add("dragging"); |
| 309 | |
| 310 | const type = el.dataset.type; |
| 311 | const index = Number.parseInt(el.dataset.index, 10); |
| 312 | |
| 313 | this.dragState = { |
| 314 | el, |
| 315 | type, // 'active' or 'source' |
| 316 | index, // slot index (active) or item ID (source) |
| 317 | ghost, |
| 318 | offsetX: pointer.clientX - rect.left - rect.width / 2, |
| 319 | offsetY: pointer.clientY - rect.top - rect.height / 2, |
| 320 | }; |
| 321 | |
| 322 | this.updateDrag(pointer); |
| 323 | } |
| 324 | |
| 325 | updateDrag(pointer) { |
| 326 | const { ghost } = this.dragState; |
no test coverage detected