mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
fix timeline zoom + selection box issues
This commit is contained in:
@@ -281,7 +281,6 @@ use-timeline-snapping.ts
|
|||||||
use-timeline-zoom.ts
|
use-timeline-zoom.ts
|
||||||
export function useTimelineZoom({
|
export function useTimelineZoom({
|
||||||
containerRef,
|
containerRef,
|
||||||
isInTimeline = false,
|
|
||||||
minZoom = TIMELINE_CONSTANTS.ZOOM_MIN,
|
minZoom = TIMELINE_CONSTANTS.ZOOM_MIN,
|
||||||
}: UseTimelineZoomProps): UseTimelineZoomReturn
|
}: UseTimelineZoomProps): UseTimelineZoomReturn
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ export function Timeline() {
|
|||||||
const bookmarksScrollRef = useRef<HTMLDivElement>(null);
|
const bookmarksScrollRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
// state
|
// state
|
||||||
const [isInTimeline, setIsInTimeline] = useState(false);
|
|
||||||
const [isResizing, setIsResizing] = useState(false);
|
const [isResizing, setIsResizing] = useState(false);
|
||||||
const [currentSnapPoint, setCurrentSnapPoint] = useState<SnapPoint | null>(
|
const [currentSnapPoint, setCurrentSnapPoint] = useState<SnapPoint | null>(
|
||||||
null,
|
null,
|
||||||
@@ -98,7 +97,6 @@ export function Timeline() {
|
|||||||
|
|
||||||
const { zoomLevel, setZoomLevel, handleWheel } = useTimelineZoom({
|
const { zoomLevel, setZoomLevel, handleWheel } = useTimelineZoom({
|
||||||
containerRef: timelineRef,
|
containerRef: timelineRef,
|
||||||
isInTimeline,
|
|
||||||
minZoom: minZoomLevel,
|
minZoom: minZoomLevel,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -187,8 +185,6 @@ export function Timeline() {
|
|||||||
}
|
}
|
||||||
{...dragProps}
|
{...dragProps}
|
||||||
aria-label="Timeline"
|
aria-label="Timeline"
|
||||||
onMouseEnter={() => setIsInTimeline(true)}
|
|
||||||
onMouseLeave={() => setIsInTimeline(false)}
|
|
||||||
>
|
>
|
||||||
<TimelineToolbar
|
<TimelineToolbar
|
||||||
zoomLevel={zoomLevel}
|
zoomLevel={zoomLevel}
|
||||||
@@ -400,6 +396,7 @@ export function Timeline() {
|
|||||||
onResizeStateChange={handleResizeStateChange}
|
onResizeStateChange={handleResizeStateChange}
|
||||||
onElementMouseDown={handleElementMouseDown}
|
onElementMouseDown={handleElementMouseDown}
|
||||||
onElementClick={handleElementClick}
|
onElementClick={handleElementClick}
|
||||||
|
onTrackMouseDown={handleSelectionMouseDown}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ContextMenuTrigger>
|
</ContextMenuTrigger>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ interface TimelineTrackContentProps {
|
|||||||
element: TimelineElementType;
|
element: TimelineElementType;
|
||||||
track: TimelineTrack;
|
track: TimelineTrack;
|
||||||
}) => void;
|
}) => void;
|
||||||
|
onTrackMouseDown?: (event: React.MouseEvent) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TimelineTrackContent({
|
export function TimelineTrackContent({
|
||||||
@@ -43,6 +44,7 @@ export function TimelineTrackContent({
|
|||||||
onResizeStateChange,
|
onResizeStateChange,
|
||||||
onElementMouseDown,
|
onElementMouseDown,
|
||||||
onElementClick,
|
onElementClick,
|
||||||
|
onTrackMouseDown,
|
||||||
}: TimelineTrackContentProps) {
|
}: TimelineTrackContentProps) {
|
||||||
const editor = useEditor();
|
const editor = useEditor();
|
||||||
const { isElementSelected, clearElementSelection } = useElementSelection();
|
const { isElementSelected, clearElementSelection } = useElementSelection();
|
||||||
@@ -65,6 +67,9 @@ export function TimelineTrackContent({
|
|||||||
<button
|
<button
|
||||||
className={cn("size-full", hasSelectedElements && "bg-panel-accent/35")}
|
className={cn("size-full", hasSelectedElements && "bg-panel-accent/35")}
|
||||||
onClick={clearElementSelection}
|
onClick={clearElementSelection}
|
||||||
|
onMouseDown={(event) => {
|
||||||
|
onTrackMouseDown?.(event);
|
||||||
|
}}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<div className="relative h-full min-w-full">
|
<div className="relative h-full min-w-full">
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants";
|
|||||||
|
|
||||||
interface UseTimelineZoomProps {
|
interface UseTimelineZoomProps {
|
||||||
containerRef: RefObject<HTMLDivElement>;
|
containerRef: RefObject<HTMLDivElement>;
|
||||||
isInTimeline?: boolean;
|
|
||||||
minZoom?: number;
|
minZoom?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,7 +20,6 @@ interface UseTimelineZoomReturn {
|
|||||||
|
|
||||||
export function useTimelineZoom({
|
export function useTimelineZoom({
|
||||||
containerRef,
|
containerRef,
|
||||||
isInTimeline = false,
|
|
||||||
minZoom = TIMELINE_CONSTANTS.ZOOM_MIN,
|
minZoom = TIMELINE_CONSTANTS.ZOOM_MIN,
|
||||||
}: UseTimelineZoomProps): UseTimelineZoomReturn {
|
}: UseTimelineZoomProps): UseTimelineZoomReturn {
|
||||||
const [zoomLevel, setZoomLevel] = useState(1);
|
const [zoomLevel, setZoomLevel] = useState(1);
|
||||||
@@ -65,9 +63,9 @@ export function useTimelineZoom({
|
|||||||
const isInContainer = containerRef.current?.contains(
|
const isInContainer = containerRef.current?.contains(
|
||||||
event.target as Node,
|
event.target as Node,
|
||||||
);
|
);
|
||||||
const shouldPrevent =
|
// only check isInContainer, not isInTimeline state - the state check
|
||||||
isInTimeline && isZoomKeyPressed && Boolean(isInContainer);
|
// causes race conditions where the closure captures stale state
|
||||||
if (shouldPrevent) {
|
if (isZoomKeyPressed && isInContainer) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -80,7 +78,7 @@ export function useTimelineZoom({
|
|||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener("wheel", preventZoom, { capture: true });
|
document.removeEventListener("wheel", preventZoom, { capture: true });
|
||||||
};
|
};
|
||||||
}, [isInTimeline, containerRef]);
|
}, [containerRef]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
zoomLevel,
|
zoomLevel,
|
||||||
|
|||||||
Reference in New Issue
Block a user