| 
						
						
						
					 | 
				
				 | 
				
					@ -1,4 +1,9 @@ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { clamp, debounce, normaliseAngleDifference } from "../../util/index.ts"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						clamp, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						debounce, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						normaliseAngleDifference, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						throttle, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} from "../../util/index.ts"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					interface Vec2 { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						x: number; | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -27,6 +32,7 @@ export function makeDraggable(card: HTMLElement, opts: DraggableOpts = {}) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						let rotation = opts.initialRotation ?? 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						let dragging = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						const state = { dragging }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						let offsetLocal: Vec2 = { x: 0, y: 0 }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						let velocity: Vec2 = { x: 0, y: 0 }; | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -36,10 +42,15 @@ export function makeDraggable(card: HTMLElement, opts: DraggableOpts = {}) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						const dampingFactor = 0.7; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						const springFactor = 0.2; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						const maxAngularVelocity = 0.95; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						const momentumDampening = 0.98; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						const RESIZE_DEBOUNCE_MS = 100; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						const VIEWPORT_CHECK_INTERVAL_MS = 100; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// Adjust damping factors (base + velocity-dependent part)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						const baseDamping = 0.98; // Base exponential damping
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						const angularVelocityDecay = 0.99; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						const velocityDecay = 0.005; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						const maxEffectiveSpeed = 50; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// --- State ---
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						let lastMousePosition: Vec2 = { x: 0, y: 0 }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						let activePointerId: number | null = null; | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -48,9 +59,9 @@ export function makeDraggable(card: HTMLElement, opts: DraggableOpts = {}) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// --- Helpers ---
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						const checkViewportExit = debounce(() => { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						const checkViewportExit = throttle(() => { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							// Don't check if we're dragging, user may still be able to move the card back into view
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if (dragging) return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if (state.dragging) return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							const rect = card.getBoundingClientRect(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							const outside = | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -70,7 +81,7 @@ export function makeDraggable(card: HTMLElement, opts: DraggableOpts = {}) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						const down = (e: PointerEvent) => { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if (activePointerId !== null) return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							dragging = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							state.dragging = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							activePointerId = e.pointerId; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							card.style.cursor = "grabbing"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							card.setPointerCapture(e.pointerId); | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -90,7 +101,7 @@ export function makeDraggable(card: HTMLElement, opts: DraggableOpts = {}) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						}; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						const move = (e: PointerEvent) => { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if (!dragging || e.pointerId !== activePointerId) return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if (!state.dragging || e.pointerId !== activePointerId) return; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							const mx = e.pageX; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							const my = e.pageY; | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -135,7 +146,7 @@ export function makeDraggable(card: HTMLElement, opts: DraggableOpts = {}) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						const up = (e: PointerEvent) => { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if (e.pointerId === activePointerId) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								dragging = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								state.dragging = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								activePointerId = null; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								card.style.cursor = "grab"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								// Momentum is handled in the render loop
 | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -179,21 +190,36 @@ export function makeDraggable(card: HTMLElement, opts: DraggableOpts = {}) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						// --- Render Loop ---
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						function render() { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if (!dragging) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								if (Math.abs(angularVelocity) > 0.01) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if (!state.dragging) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								// --- Angular Momentum ---
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								if (Math.abs(angularVelocity) > 0.001) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									// Simple exponential damping
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									rotation += angularVelocity; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									angularVelocity *= momentumDampening; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									angularVelocity *= angularVelocityDecay; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								} else angularVelocity = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								// --- Linear Momentum ---
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								const speed = Math.sqrt( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									velocity.x * velocity.x + velocity.y * velocity.y, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								if (speed > 0.01) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									center.x += velocity.x * 0.4; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									center.y += velocity.y * 0.4; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									velocity.x *= momentumDampening; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									velocity.y *= momentumDampening; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									// Calculate speed-dependent damping
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									// Clamp speed influence to avoid excessive damping
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									const speedInfluence = | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
										Math.min(speed, maxEffectiveSpeed) / maxEffectiveSpeed; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									const currentDamping = | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
										baseDamping * (1 - speedInfluence * velocityDecay); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									// Ensure damping doesn't go below a minimum or above 1
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									const effectiveDamping = clamp(currentDamping, 0.8, 0.995); // Adjust min/max clamp
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									velocity.x *= effectiveDamping; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									velocity.y *= effectiveDamping; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									center.x += velocity.x; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									center.y += velocity.y; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								} else velocity = { x: 0, y: 0 }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
				 | 
				
					
  |