diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-04-20 11:31:17 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-04-20 11:31:17 +0200 |
| commit | 3e89d2998588f8e35c524e523ba2ee853f0f6475 (patch) | |
| tree | 57221f96c1259b3b07e3ddf8c1adefc502b9d8eb /apps/web/src/lib/clipboard | |
| parent | 729d10592f4e802f91c555c309ff3ba4b119f843 (diff) | |
| download | opencut-3e89d2998588f8e35c524e523ba2ee853f0f6475.tar.gz | |
refactor: restructure files to their domains, new preview overlay system, and dep graph
Diffstat (limited to 'apps/web/src/lib/clipboard')
| -rw-r--r-- | apps/web/src/lib/clipboard/handlers/elements.ts | 48 | ||||
| -rw-r--r-- | apps/web/src/lib/clipboard/handlers/index.ts | 49 | ||||
| -rw-r--r-- | apps/web/src/lib/clipboard/handlers/keyframes.ts | 170 | ||||
| -rw-r--r-- | apps/web/src/lib/clipboard/index.ts | 2 | ||||
| -rw-r--r-- | apps/web/src/lib/clipboard/types.ts | 79 |
5 files changed, 0 insertions, 348 deletions
diff --git a/apps/web/src/lib/clipboard/handlers/elements.ts b/apps/web/src/lib/clipboard/handlers/elements.ts deleted file mode 100644 index 1b58ac78..00000000 --- a/apps/web/src/lib/clipboard/handlers/elements.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { PasteCommand } from "@/lib/commands/timeline"; -import type { ClipboardHandler } from "../types"; - -export const ElementsClipboardHandler = { - type: "elements", - - canCopy({ selectedElements }) { - return selectedElements.length > 0; - }, - - copy({ editor, selectedElements }) { - if (selectedElements.length === 0) { - return null; - } - - const results = editor.timeline.getElementsWithTracks({ - elements: selectedElements, - }); - const items = results.map(({ track, element }) => { - const { id: _elementId, ...elementWithoutId } = element; - return { - trackId: track.id, - trackType: track.type, - element: elementWithoutId, - }; - }); - - if (items.length === 0) { - return null; - } - - return { - type: "elements", - items, - }; - }, - - paste(entry, context) { - if (entry.items.length === 0) { - return null; - } - - return new PasteCommand({ - time: context.time, - clipboardItems: entry.items, - }); - }, -} satisfies ClipboardHandler<"elements">; diff --git a/apps/web/src/lib/clipboard/handlers/index.ts b/apps/web/src/lib/clipboard/handlers/index.ts deleted file mode 100644 index 29d4d1d0..00000000 --- a/apps/web/src/lib/clipboard/handlers/index.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { - ClipboardEntry, - ClipboardEntryType, - ClipboardHandler, - ClipboardHandlerMap, - CopyContext, - PasteContext, -} from "../types"; -import { ElementsClipboardHandler } from "./elements"; -import { KeyframesClipboardHandler } from "./keyframes"; - -export const clipboardHandlers = { - elements: ElementsClipboardHandler, - keyframes: KeyframesClipboardHandler, -} satisfies ClipboardHandlerMap; - -export const clipboardCopyHandlers = [ - KeyframesClipboardHandler, - ElementsClipboardHandler, -] as const satisfies readonly ClipboardHandler<ClipboardEntryType>[]; - -export function copyClipboardEntry({ - context, -}: { - context: CopyContext; -}): ClipboardEntry | null { - for (const handler of clipboardCopyHandlers) { - if (!handler.canCopy(context)) { - continue; - } - - return handler.copy(context); - } - - return null; -} - -export function buildPasteClipboardCommand({ - entry, - context, -}: { - entry: ClipboardEntry; - context: PasteContext; -}) { - const handler = clipboardHandlers[entry.type] as ClipboardHandler< - typeof entry.type - >; - return handler.paste(entry as never, context); -} diff --git a/apps/web/src/lib/clipboard/handlers/keyframes.ts b/apps/web/src/lib/clipboard/handlers/keyframes.ts deleted file mode 100644 index b746c179..00000000 --- a/apps/web/src/lib/clipboard/handlers/keyframes.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { getKeyframeById } from "@/lib/animation"; -import type { SelectedKeyframeRef } from "@/lib/animation/types"; -import type { TimelineElement } from "@/lib/timeline"; -import { PasteKeyframesCommand } from "@/lib/commands/timeline"; -import type { - ClipboardHandler, - KeyframeClipboardCurvePatch, - KeyframeClipboardItem, -} from "../types"; - -function resolveSingleSourceElement({ - selectedKeyframes, -}: { - selectedKeyframes: SelectedKeyframeRef[]; -}) { - const firstKeyframe = selectedKeyframes[0]; - if (!firstKeyframe) { - return null; - } - - const sourceElement = { - trackId: firstKeyframe.trackId, - elementId: firstKeyframe.elementId, - }; - const isSingleSource = selectedKeyframes.every( - (keyframe) => - keyframe.trackId === sourceElement.trackId && - keyframe.elementId === sourceElement.elementId, - ); - - return isSingleSource ? sourceElement : null; -} - -function getCurvePatches({ - element, - propertyPath, - keyframeId, -}: { - element: TimelineElement; - propertyPath: KeyframeClipboardItem["propertyPath"]; - keyframeId: string; -}): KeyframeClipboardCurvePatch[] { - const binding = element.animations?.bindings[propertyPath]; - if (!binding) { - return []; - } - - return binding.components.flatMap((component) => { - const channel = element.animations?.channels[component.channelId]; - if (channel?.kind !== "scalar") { - return []; - } - - const keyframe = channel.keys.find( - (candidate) => candidate.id === keyframeId, - ); - if (!keyframe) { - return []; - } - - return [ - { - componentKey: component.key, - patch: { - leftHandle: keyframe.leftHandle ?? null, - rightHandle: keyframe.rightHandle ?? null, - segmentToNext: keyframe.segmentToNext, - tangentMode: keyframe.tangentMode, - }, - }, - ]; - }); -} - -function buildClipboardItem({ - element, - propertyPath, - keyframeId, -}: { - element: TimelineElement; - propertyPath: KeyframeClipboardItem["propertyPath"]; - keyframeId: string; -}): (Omit<KeyframeClipboardItem, "timeOffset"> & { time: number }) | null { - const keyframe = getKeyframeById({ - animations: element.animations, - propertyPath, - keyframeId, - }); - if (!keyframe) { - return null; - } - - return { - propertyPath, - time: keyframe.time, - value: keyframe.value, - interpolation: keyframe.interpolation, - curvePatches: getCurvePatches({ - element, - propertyPath, - keyframeId, - }), - }; -} - -export const KeyframesClipboardHandler = { - type: "keyframes", - - canCopy({ selectedKeyframes }) { - return selectedKeyframes.length > 0; - }, - - copy({ editor, selectedKeyframes }) { - const sourceElement = resolveSingleSourceElement({ selectedKeyframes }); - if (!sourceElement) { - return null; - } - - const [result] = editor.timeline.getElementsWithTracks({ - elements: [sourceElement], - }); - if (!result) { - return null; - } - - const rawItems = selectedKeyframes.flatMap((keyframeRef) => { - const item = buildClipboardItem({ - element: result.element, - propertyPath: keyframeRef.propertyPath, - keyframeId: keyframeRef.keyframeId, - }); - return item ? [item] : []; - }); - if (rawItems.length === 0) { - return null; - } - - const minTime = Math.min(...rawItems.map((item) => item.time)); - const items = rawItems - .map(({ time, ...item }) => ({ - ...item, - timeOffset: time - minTime, - })) - .sort( - (left, right) => - left.timeOffset - right.timeOffset || - left.propertyPath.localeCompare(right.propertyPath), - ); - - return { - type: "keyframes", - sourceElement, - items, - }; - }, - - paste(entry, { selectedElements, time }) { - const targetElement = selectedElements[0]; - if (!targetElement || entry.items.length === 0) { - return null; - } - - return new PasteKeyframesCommand({ - trackId: targetElement.trackId, - elementId: targetElement.elementId, - time, - clipboardItems: entry.items, - }); - }, -} satisfies ClipboardHandler<"keyframes">; diff --git a/apps/web/src/lib/clipboard/index.ts b/apps/web/src/lib/clipboard/index.ts deleted file mode 100644 index 76d5bddf..00000000 --- a/apps/web/src/lib/clipboard/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./types"; -export * from "./handlers"; diff --git a/apps/web/src/lib/clipboard/types.ts b/apps/web/src/lib/clipboard/types.ts deleted file mode 100644 index 41e107ef..00000000 --- a/apps/web/src/lib/clipboard/types.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { EditorCore } from "@/core"; -import type { - AnimationInterpolation, - AnimationPath, - AnimationValue, - ScalarCurveKeyframePatch, - SelectedKeyframeRef, -} from "@/lib/animation/types"; -import type { Command } from "@/lib/commands/base-command"; -import type { - CreateTimelineElement, - ElementRef, - TrackType, -} from "@/lib/timeline"; - -export interface ElementClipboardItem { - trackId: string; - trackType: TrackType; - element: CreateTimelineElement; -} - -export interface KeyframeClipboardCurvePatch { - componentKey: string; - patch: ScalarCurveKeyframePatch; -} - -export interface KeyframeClipboardItem { - propertyPath: AnimationPath; - timeOffset: number; - value: AnimationValue; - interpolation: AnimationInterpolation; - curvePatches: KeyframeClipboardCurvePatch[]; -} - -export interface ElementsClipboardEntry { - type: "elements"; - items: ElementClipboardItem[]; -} - -export interface KeyframesClipboardEntry { - type: "keyframes"; - sourceElement: ElementRef; - items: KeyframeClipboardItem[]; -} - -export interface ClipboardEntryByType { - elements: ElementsClipboardEntry; - keyframes: KeyframesClipboardEntry; -} - -export type ClipboardEntry = ClipboardEntryByType[keyof ClipboardEntryByType]; -export type ClipboardEntryType = keyof ClipboardEntryByType; - -export interface CopyContext { - editor: EditorCore; - selectedElements: ElementRef[]; - selectedKeyframes: SelectedKeyframeRef[]; -} - -export interface PasteContext { - editor: EditorCore; - selectedElements: ElementRef[]; - selectedKeyframes: SelectedKeyframeRef[]; - time: number; -} - -export interface ClipboardHandler<TType extends ClipboardEntryType> { - type: TType; - canCopy(context: CopyContext): boolean; - copy(context: CopyContext): ClipboardEntryByType[TType] | null; - paste( - entry: ClipboardEntryByType[TType], - context: PasteContext, - ): Command | null; -} - -export type ClipboardHandlerMap = { - [TType in ClipboardEntryType]: ClipboardHandler<TType>; -}; |
