-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Add duplicate for zoom, annotation, and audio timeline items #959
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| import type { Span } from "dnd-timeline"; | ||
| import { type Dispatch, type MutableRefObject, type SetStateAction, useCallback } from "react"; | ||
| import { placeSpanAfter } from "../timeline/hooks/utils/timelineDuplicateUtils"; | ||
| import { | ||
| clampFocusToDepth, | ||
| DEFAULT_AUTO_ZOOM_DEPTH, | ||
|
|
@@ -170,6 +171,48 @@ export function useZoomRegionCommands({ | |
| [selectedZoomId, setSelectedZoomId, setZoomRegions], | ||
| ); | ||
|
|
||
| const handleZoomDuplicate = useCallback( | ||
| (id: string, totalMs: number): boolean => { | ||
| let createdId: string | null = null; | ||
| setZoomRegions((current) => { | ||
|
Comment on lines
+176
to
+177
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift Do not use the functional updater as a synchronous result.
Make current regions synchronously available from the state owner. Resolve the source, placement, and ID before scheduling. Keep the scheduled updater pure without replacing current-state behavior with a stale render snapshot. 🤖 Prompt for AI Agents |
||
| const source = current.find((region) => region.id === id); | ||
| if (!source) return current; | ||
|
|
||
| const placed = placeSpanAfter(source, totalMs); | ||
| if (!placed) return current; | ||
|
|
||
| createdId = `zoom-${nextZoomIdRef.current++}`; | ||
| return [ | ||
| ...current, | ||
| { | ||
| ...source, | ||
| id: createdId, | ||
| startMs: placed.startMs, | ||
| endMs: placed.endMs, | ||
| focus: { ...source.focus }, | ||
| }, | ||
| ]; | ||
| }); | ||
|
|
||
| if (!createdId) return false; | ||
| setSelectedZoomId(createdId); | ||
| setSelectedAnnotationId(null); | ||
| setSelectedAudioId(null); | ||
| setSelectedCaptionId(null); | ||
| setActiveEffectSection("zoom"); | ||
| return true; | ||
| }, | ||
| [ | ||
| nextZoomIdRef, | ||
| setActiveEffectSection, | ||
| setSelectedAnnotationId, | ||
| setSelectedAudioId, | ||
| setSelectedCaptionId, | ||
| setSelectedZoomId, | ||
| setZoomRegions, | ||
| ], | ||
| ); | ||
|
|
||
| return { | ||
| handleSelectZoom, | ||
| handleZoomAdded, | ||
|
|
@@ -179,5 +222,6 @@ export function useZoomRegionCommands({ | |
| handleZoomDepthChange, | ||
| handleZoomModeChange, | ||
| handleZoomDelete, | ||
| handleZoomDuplicate, | ||
| }; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Do not use the functional updater as a synchronous result.
useTimelineStatepasses its ReactsetAnnotationRegionssetter touseAnnotationRegionCommands. React can defer the updater until afterhandleAnnotationDuplicatereturns. The updater can then assigncreatedIdafter theif (!createdId)check. The command returnsfalse, so the duplicate action can show its failure toast while the appended annotation remains unselected.Keep source lookup and
placeSpanAfterbased on the current region list. Do not use a stale render-time snapshot. MakeuseTimelineStatemaintain a current-regions ref and update it synchronously for every region update. Compute the duplicate andcreatedIdfrom that ref, then queue a pure state update and select the new annotation.🤖 Prompt for AI Agents