framer-motion
Version:
A simple and powerful JavaScript animation library
1 lines • 8.67 kB
Source Map (JSON)
{"version":3,"file":"auto-scroll.mjs","sources":["../../../../../src/components/Reorder/utils/auto-scroll.ts"],"sourcesContent":["const threshold = 50\nconst maxSpeed = 25\n\nconst overflowStyles = new Set([\"auto\", \"scroll\"])\n\n// Track initial scroll limits per scrollable element (Bug 1 fix)\nconst initialScrollLimits = new WeakMap<HTMLElement, number>()\n\n// Track auto-scroll active state per edge: \"start\" (top/left) or \"end\" (bottom/right)\ntype ActiveEdge = \"start\" | \"end\" | null\nconst activeScrollEdge = new WeakMap<HTMLElement, ActiveEdge>()\n\n// Track which group element is currently dragging to clear state on end\nlet currentGroupElement: Element | null = null\n\nexport function resetAutoScrollState(): void {\n if (currentGroupElement) {\n const scrollableAncestor = findScrollableAncestor(\n currentGroupElement,\n \"y\"\n )\n if (scrollableAncestor) {\n activeScrollEdge.delete(scrollableAncestor)\n initialScrollLimits.delete(scrollableAncestor)\n }\n // Also try x axis\n const scrollableAncestorX = findScrollableAncestor(\n currentGroupElement,\n \"x\"\n )\n if (scrollableAncestorX && scrollableAncestorX !== scrollableAncestor) {\n activeScrollEdge.delete(scrollableAncestorX)\n initialScrollLimits.delete(scrollableAncestorX)\n }\n currentGroupElement = null\n }\n}\n\nfunction isScrollableElement(element: Element, axis: \"x\" | \"y\"): boolean {\n const style = getComputedStyle(element)\n const overflow = axis === \"x\" ? style.overflowX : style.overflowY\n return overflowStyles.has(overflow)\n}\n\nfunction findScrollableAncestor(\n element: Element | null,\n axis: \"x\" | \"y\"\n): HTMLElement | null {\n let current = element?.parentElement\n while (current) {\n if (isScrollableElement(current, axis)) {\n return current\n }\n current = current.parentElement\n }\n return null\n}\n\nfunction getScrollAmount(\n pointerPosition: number,\n scrollElement: HTMLElement,\n axis: \"x\" | \"y\"\n): { amount: number; edge: ActiveEdge } {\n const rect = scrollElement.getBoundingClientRect()\n\n const start = axis === \"x\" ? rect.left : rect.top\n const end = axis === \"x\" ? rect.right : rect.bottom\n\n const distanceFromStart = pointerPosition - start\n const distanceFromEnd = end - pointerPosition\n\n if (distanceFromStart < threshold) {\n const intensity = 1 - distanceFromStart / threshold\n return { amount: -maxSpeed * intensity * intensity, edge: \"start\" }\n } else if (distanceFromEnd < threshold) {\n const intensity = 1 - distanceFromEnd / threshold\n return { amount: maxSpeed * intensity * intensity, edge: \"end\" }\n }\n\n return { amount: 0, edge: null }\n}\n\nexport function autoScrollIfNeeded(\n groupElement: Element | null,\n pointerPosition: number,\n axis: \"x\" | \"y\",\n velocity: number\n): void {\n if (!groupElement) return\n\n // Track the group element for cleanup\n currentGroupElement = groupElement\n\n const scrollableAncestor = findScrollableAncestor(groupElement, axis)\n if (!scrollableAncestor) return\n\n const { amount: scrollAmount, edge } = getScrollAmount(\n pointerPosition,\n scrollableAncestor,\n axis\n )\n\n // If not in any threshold zone, clear all state\n if (edge === null) {\n activeScrollEdge.delete(scrollableAncestor)\n initialScrollLimits.delete(scrollableAncestor)\n return\n }\n\n const currentActiveEdge = activeScrollEdge.get(scrollableAncestor)\n\n // If not currently scrolling this edge, check velocity to see if we should start\n if (currentActiveEdge !== edge) {\n // Only start scrolling if velocity is towards the edge\n const shouldStart =\n (edge === \"start\" && velocity < 0) ||\n (edge === \"end\" && velocity > 0)\n if (!shouldStart) return\n\n // Activate this edge\n activeScrollEdge.set(scrollableAncestor, edge)\n\n // Record initial scroll limit (prevents infinite scroll)\n const maxScroll =\n axis === \"x\"\n ? scrollableAncestor.scrollWidth -\n scrollableAncestor.clientWidth\n : scrollableAncestor.scrollHeight -\n scrollableAncestor.clientHeight\n initialScrollLimits.set(scrollableAncestor, maxScroll)\n }\n\n // Cap scrolling at initial limit (prevents infinite scroll)\n if (scrollAmount > 0) {\n const initialLimit = initialScrollLimits.get(scrollableAncestor)!\n const currentScroll =\n axis === \"x\"\n ? scrollableAncestor.scrollLeft\n : scrollableAncestor.scrollTop\n if (currentScroll >= initialLimit) return\n }\n\n // Apply scroll\n if (axis === \"x\") {\n scrollableAncestor.scrollLeft += scrollAmount\n } else {\n scrollableAncestor.scrollTop += scrollAmount\n }\n}\n"],"names":[],"mappings":"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"}