From 4d127a038bf768eded68aae3cfa5c1b12241bdac Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Fri, 27 Mar 2026 00:55:15 +0100 Subject: chore: normalize line endings --- legacy/timeline/use-selection-box.ts | 530 +++++++++++++++++------------------ 1 file changed, 265 insertions(+), 265 deletions(-) (limited to 'legacy/timeline') diff --git a/legacy/timeline/use-selection-box.ts b/legacy/timeline/use-selection-box.ts index 027d3d76..979bb480 100644 --- a/legacy/timeline/use-selection-box.ts +++ b/legacy/timeline/use-selection-box.ts @@ -1,265 +1,265 @@ -import { useCallback, useEffect, useRef, useState } from "react"; -import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants"; -import { getCumulativeHeightBefore, getTrackHeight } from "@/lib/timeline"; -import { useEditor } from "../use-editor"; - -interface UseSelectionBoxProps { - containerRef: React.RefObject; - headerRef?: React.RefObject; - onSelectionComplete: ({ - elements, - isAdditive, - }: { - elements: { trackId: string; elementId: string }[]; - isAdditive: boolean; - }) => void; - isEnabled?: boolean; - tracksScrollRef: React.RefObject; - zoomLevel: number; -} - -interface SelectionBoxState { - startPos: { x: number; y: number }; - currentPos: { x: number; y: number }; - isActive: boolean; - isAdditive: boolean; -} - -interface SelectionRectangle { - left: number; - top: number; - right: number; - bottom: number; -} - -function getNormalizedRectangle({ - startPos, - endPos, -}: { - startPos: { x: number; y: number }; - endPos: { x: number; y: number }; -}): SelectionRectangle { - return { - left: Math.min(startPos.x, endPos.x), - top: Math.min(startPos.y, endPos.y), - right: Math.max(startPos.x, endPos.x), - bottom: Math.max(startPos.y, endPos.y), - }; -} - -function getSelectionRectangleInContent({ - container, - scrollContainer, - startPos, - endPos, -}: { - container: HTMLElement; - scrollContainer: HTMLDivElement | null; - startPos: { x: number; y: number }; - endPos: { x: number; y: number }; -}): SelectionRectangle { - const containerRect = container.getBoundingClientRect(); - const scrollRect = scrollContainer?.getBoundingClientRect() ?? containerRect; - const scrollLeft = scrollContainer?.scrollLeft ?? 0; - const scrollTop = scrollContainer?.scrollTop ?? 0; - - const adjustedStart = { - x: startPos.x - containerRect.left + scrollLeft, - y: startPos.y - scrollRect.top + scrollTop, - }; - const adjustedEnd = { - x: endPos.x - containerRect.left + scrollLeft, - y: endPos.y - scrollRect.top + scrollTop, - }; - - return getNormalizedRectangle({ - startPos: adjustedStart, - endPos: adjustedEnd, - }); -} - -function isRectangleIntersecting({ - elementRectangle, - selectionRectangle, -}: { - elementRectangle: SelectionRectangle; - selectionRectangle: SelectionRectangle; -}): boolean { - return !( - elementRectangle.right < selectionRectangle.left || - elementRectangle.left > selectionRectangle.right || - elementRectangle.bottom < selectionRectangle.top || - elementRectangle.top > selectionRectangle.bottom - ); -} - -export function useSelectionBox({ - containerRef, - headerRef, - onSelectionComplete, - isEnabled = true, - tracksScrollRef, - zoomLevel, -}: UseSelectionBoxProps) { - const editor = useEditor(); - const [selectionBox, setSelectionBox] = useState( - null, - ); - const justFinishedSelectingRef = useRef(false); - - const handleMouseDown = useCallback( - ({ clientX, clientY, shiftKey, ctrlKey, metaKey }: React.MouseEvent) => { - if (!isEnabled) return; - - setSelectionBox({ - startPos: { x: clientX, y: clientY }, - currentPos: { x: clientX, y: clientY }, - isActive: false, - isAdditive: shiftKey || ctrlKey || metaKey, - }); - }, - [isEnabled], - ); - - const selectElementsInBox = useCallback( - ({ - startPos, - endPos, - isAdditive, - }: { - startPos: { x: number; y: number }; - endPos: { x: number; y: number }; - isAdditive: boolean; - }) => { - if (!containerRef.current) return; - - const tracks = editor.timeline.getTracks(); - const container = containerRef.current; - const selectionRectangle = getSelectionRectangleInContent({ - container, - scrollContainer: tracksScrollRef.current, - startPos, - endPos, - }); - const pixelsPerSecond = TIMELINE_CONSTANTS.PIXELS_PER_SECOND * zoomLevel; - const timelineHeaderHeight = - headerRef?.current?.getBoundingClientRect().height ?? 0; - const selectedElements: { trackId: string; elementId: string }[] = []; - - for (const [trackIndex, track] of tracks.entries()) { - const trackTop = getCumulativeHeightBefore({ - tracks, - trackIndex, - }); - const trackHeight = getTrackHeight({ type: track.type }); - const elementTop = - timelineHeaderHeight + TIMELINE_CONSTANTS.PADDING_TOP_PX + trackTop; - const elementBottom = elementTop + trackHeight; - - for (const element of track.elements) { - const elementLeft = element.startTime * pixelsPerSecond; - const elementRight = elementLeft + element.duration * pixelsPerSecond; - - const elementRectangle = { - left: elementLeft, - top: elementTop, - right: elementRight, - bottom: elementBottom, - }; - - const intersects = isRectangleIntersecting({ - elementRectangle, - selectionRectangle, - }); - - if (intersects) { - selectedElements.push({ - trackId: track.id, - elementId: element.id, - }); - } - } - } - onSelectionComplete({ elements: selectedElements, isAdditive }); - }, - [ - containerRef, - headerRef, - onSelectionComplete, - editor, - tracksScrollRef, - zoomLevel, - ], - ); - - useEffect(() => { - if (!selectionBox) return; - - const handleMouseMove = ({ clientX, clientY }: MouseEvent) => { - const deltaX = Math.abs(clientX - selectionBox.startPos.x); - const deltaY = Math.abs(clientY - selectionBox.startPos.y); - const shouldActivate = deltaX > 5 || deltaY > 5; - - const newSelectionBox = { - ...selectionBox, - currentPos: { x: clientX, y: clientY }, - isActive: shouldActivate || selectionBox.isActive, - }; - - setSelectionBox(newSelectionBox); - - if (newSelectionBox.isActive) { - selectElementsInBox({ - startPos: newSelectionBox.startPos, - endPos: newSelectionBox.currentPos, - isAdditive: newSelectionBox.isAdditive, - }); - } - }; - - const handleMouseUp = () => { - if (selectionBox?.isActive) { - justFinishedSelectingRef.current = true; - requestAnimationFrame(() => { - justFinishedSelectingRef.current = false; - }); - } - setSelectionBox(null); - }; - - window.addEventListener("mousemove", handleMouseMove); - window.addEventListener("mouseup", handleMouseUp); - - return () => { - window.removeEventListener("mousemove", handleMouseMove); - window.removeEventListener("mouseup", handleMouseUp); - }; - }, [selectionBox, selectElementsInBox]); - - useEffect(() => { - if (!selectionBox) return; - - const previousBodyUserSelect = document.body.style.userSelect; - const container = containerRef.current; - const previousContainerUserSelect = container?.style.userSelect ?? ""; - - document.body.style.userSelect = "none"; - if (container) container.style.userSelect = "none"; - - return () => { - document.body.style.userSelect = previousBodyUserSelect; - if (container) container.style.userSelect = previousContainerUserSelect; - }; - }, [selectionBox, containerRef]); - - const shouldIgnoreClick = useCallback(() => { - return justFinishedSelectingRef.current; - }, []); - - return { - selectionBox, - handleMouseDown, - isSelecting: selectionBox?.isActive || false, - shouldIgnoreClick, - }; -} +import { useCallback, useEffect, useRef, useState } from "react"; +import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants"; +import { getCumulativeHeightBefore, getTrackHeight } from "@/lib/timeline"; +import { useEditor } from "../use-editor"; + +interface UseSelectionBoxProps { + containerRef: React.RefObject; + headerRef?: React.RefObject; + onSelectionComplete: ({ + elements, + isAdditive, + }: { + elements: { trackId: string; elementId: string }[]; + isAdditive: boolean; + }) => void; + isEnabled?: boolean; + tracksScrollRef: React.RefObject; + zoomLevel: number; +} + +interface SelectionBoxState { + startPos: { x: number; y: number }; + currentPos: { x: number; y: number }; + isActive: boolean; + isAdditive: boolean; +} + +interface SelectionRectangle { + left: number; + top: number; + right: number; + bottom: number; +} + +function getNormalizedRectangle({ + startPos, + endPos, +}: { + startPos: { x: number; y: number }; + endPos: { x: number; y: number }; +}): SelectionRectangle { + return { + left: Math.min(startPos.x, endPos.x), + top: Math.min(startPos.y, endPos.y), + right: Math.max(startPos.x, endPos.x), + bottom: Math.max(startPos.y, endPos.y), + }; +} + +function getSelectionRectangleInContent({ + container, + scrollContainer, + startPos, + endPos, +}: { + container: HTMLElement; + scrollContainer: HTMLDivElement | null; + startPos: { x: number; y: number }; + endPos: { x: number; y: number }; +}): SelectionRectangle { + const containerRect = container.getBoundingClientRect(); + const scrollRect = scrollContainer?.getBoundingClientRect() ?? containerRect; + const scrollLeft = scrollContainer?.scrollLeft ?? 0; + const scrollTop = scrollContainer?.scrollTop ?? 0; + + const adjustedStart = { + x: startPos.x - containerRect.left + scrollLeft, + y: startPos.y - scrollRect.top + scrollTop, + }; + const adjustedEnd = { + x: endPos.x - containerRect.left + scrollLeft, + y: endPos.y - scrollRect.top + scrollTop, + }; + + return getNormalizedRectangle({ + startPos: adjustedStart, + endPos: adjustedEnd, + }); +} + +function isRectangleIntersecting({ + elementRectangle, + selectionRectangle, +}: { + elementRectangle: SelectionRectangle; + selectionRectangle: SelectionRectangle; +}): boolean { + return !( + elementRectangle.right < selectionRectangle.left || + elementRectangle.left > selectionRectangle.right || + elementRectangle.bottom < selectionRectangle.top || + elementRectangle.top > selectionRectangle.bottom + ); +} + +export function useSelectionBox({ + containerRef, + headerRef, + onSelectionComplete, + isEnabled = true, + tracksScrollRef, + zoomLevel, +}: UseSelectionBoxProps) { + const editor = useEditor(); + const [selectionBox, setSelectionBox] = useState( + null, + ); + const justFinishedSelectingRef = useRef(false); + + const handleMouseDown = useCallback( + ({ clientX, clientY, shiftKey, ctrlKey, metaKey }: React.MouseEvent) => { + if (!isEnabled) return; + + setSelectionBox({ + startPos: { x: clientX, y: clientY }, + currentPos: { x: clientX, y: clientY }, + isActive: false, + isAdditive: shiftKey || ctrlKey || metaKey, + }); + }, + [isEnabled], + ); + + const selectElementsInBox = useCallback( + ({ + startPos, + endPos, + isAdditive, + }: { + startPos: { x: number; y: number }; + endPos: { x: number; y: number }; + isAdditive: boolean; + }) => { + if (!containerRef.current) return; + + const tracks = editor.timeline.getTracks(); + const container = containerRef.current; + const selectionRectangle = getSelectionRectangleInContent({ + container, + scrollContainer: tracksScrollRef.current, + startPos, + endPos, + }); + const pixelsPerSecond = TIMELINE_CONSTANTS.PIXELS_PER_SECOND * zoomLevel; + const timelineHeaderHeight = + headerRef?.current?.getBoundingClientRect().height ?? 0; + const selectedElements: { trackId: string; elementId: string }[] = []; + + for (const [trackIndex, track] of tracks.entries()) { + const trackTop = getCumulativeHeightBefore({ + tracks, + trackIndex, + }); + const trackHeight = getTrackHeight({ type: track.type }); + const elementTop = + timelineHeaderHeight + TIMELINE_CONSTANTS.PADDING_TOP_PX + trackTop; + const elementBottom = elementTop + trackHeight; + + for (const element of track.elements) { + const elementLeft = element.startTime * pixelsPerSecond; + const elementRight = elementLeft + element.duration * pixelsPerSecond; + + const elementRectangle = { + left: elementLeft, + top: elementTop, + right: elementRight, + bottom: elementBottom, + }; + + const intersects = isRectangleIntersecting({ + elementRectangle, + selectionRectangle, + }); + + if (intersects) { + selectedElements.push({ + trackId: track.id, + elementId: element.id, + }); + } + } + } + onSelectionComplete({ elements: selectedElements, isAdditive }); + }, + [ + containerRef, + headerRef, + onSelectionComplete, + editor, + tracksScrollRef, + zoomLevel, + ], + ); + + useEffect(() => { + if (!selectionBox) return; + + const handleMouseMove = ({ clientX, clientY }: MouseEvent) => { + const deltaX = Math.abs(clientX - selectionBox.startPos.x); + const deltaY = Math.abs(clientY - selectionBox.startPos.y); + const shouldActivate = deltaX > 5 || deltaY > 5; + + const newSelectionBox = { + ...selectionBox, + currentPos: { x: clientX, y: clientY }, + isActive: shouldActivate || selectionBox.isActive, + }; + + setSelectionBox(newSelectionBox); + + if (newSelectionBox.isActive) { + selectElementsInBox({ + startPos: newSelectionBox.startPos, + endPos: newSelectionBox.currentPos, + isAdditive: newSelectionBox.isAdditive, + }); + } + }; + + const handleMouseUp = () => { + if (selectionBox?.isActive) { + justFinishedSelectingRef.current = true; + requestAnimationFrame(() => { + justFinishedSelectingRef.current = false; + }); + } + setSelectionBox(null); + }; + + window.addEventListener("mousemove", handleMouseMove); + window.addEventListener("mouseup", handleMouseUp); + + return () => { + window.removeEventListener("mousemove", handleMouseMove); + window.removeEventListener("mouseup", handleMouseUp); + }; + }, [selectionBox, selectElementsInBox]); + + useEffect(() => { + if (!selectionBox) return; + + const previousBodyUserSelect = document.body.style.userSelect; + const container = containerRef.current; + const previousContainerUserSelect = container?.style.userSelect ?? ""; + + document.body.style.userSelect = "none"; + if (container) container.style.userSelect = "none"; + + return () => { + document.body.style.userSelect = previousBodyUserSelect; + if (container) container.style.userSelect = previousContainerUserSelect; + }; + }, [selectionBox, containerRef]); + + const shouldIgnoreClick = useCallback(() => { + return justFinishedSelectingRef.current; + }, []); + + return { + selectionBox, + handleMouseDown, + isSelecting: selectionBox?.isActive || false, + shouldIgnoreClick, + }; +} -- cgit v1.3.1