From 2272598d420cf078aaa3928246bfa3a414f6eddb Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Mon, 13 Apr 2026 04:40:56 +0200 Subject: feat: clipboard with keyframe paste Made-with: Cursor --- apps/web/src/hooks/use-editor.ts | 117 ++++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 58 deletions(-) (limited to 'apps/web/src/hooks/use-editor.ts') diff --git a/apps/web/src/hooks/use-editor.ts b/apps/web/src/hooks/use-editor.ts index bafa6cf7..1a5ca8ae 100644 --- a/apps/web/src/hooks/use-editor.ts +++ b/apps/web/src/hooks/use-editor.ts @@ -1,58 +1,59 @@ -import { useCallback, useMemo, useRef, useSyncExternalStore } from "react"; -import { EditorCore } from "@/core"; - -function isShallowEqual(a: unknown, b: unknown): boolean { - if (Object.is(a, b)) return true; - if (!Array.isArray(a) || !Array.isArray(b)) return false; - if (a.length !== b.length) return false; - return a.every((item, i) => Object.is(item, b[i])); -} - -const subscribeNone = () => () => {}; - -export function useEditor(): EditorCore; -export function useEditor(selector: (editor: EditorCore) => T): T; -export function useEditor( - selector?: (editor: EditorCore) => T, -): EditorCore | T { - const editor = useMemo(() => EditorCore.getInstance(), []); - const selectorRef = useRef(selector); - selectorRef.current = selector; - - const snapshotCacheRef = useRef(undefined); - - const subscribeAll = useCallback( - (onChange: () => void) => { - const unsubscribers = [ - editor.playback.subscribe(onChange), - editor.timeline.subscribe(onChange), - editor.scenes.subscribe(onChange), - editor.project.subscribe(onChange), - editor.media.subscribe(onChange), - editor.renderer.subscribe(onChange), - editor.selection.subscribe(onChange), - ]; - return () => { - unsubscribers.forEach((unsubscribe) => { - unsubscribe(); - }); - }; - }, - [editor], - ); - - const getSnapshot = useCallback(() => { - const next = selectorRef.current ? selectorRef.current(editor) : editor; - if (isShallowEqual(snapshotCacheRef.current, next)) { - return snapshotCacheRef.current; - } - snapshotCacheRef.current = next; - return next; - }, [editor]); - - return useSyncExternalStore( - selector ? subscribeAll : subscribeNone, - getSnapshot, - getSnapshot, - ) as EditorCore | T; -} +import { useCallback, useMemo, useRef, useSyncExternalStore } from "react"; +import { EditorCore } from "@/core"; + +function isShallowEqual(a: unknown, b: unknown): boolean { + if (Object.is(a, b)) return true; + if (!Array.isArray(a) || !Array.isArray(b)) return false; + if (a.length !== b.length) return false; + return a.every((item, i) => Object.is(item, b[i])); +} + +const subscribeNone = () => () => {}; + +export function useEditor(): EditorCore; +export function useEditor(selector: (editor: EditorCore) => T): T; +export function useEditor( + selector?: (editor: EditorCore) => T, +): EditorCore | T { + const editor = useMemo(() => EditorCore.getInstance(), []); + const selectorRef = useRef(selector); + selectorRef.current = selector; + + const snapshotCacheRef = useRef(undefined); + + const subscribeAll = useCallback( + (onChange: () => void) => { + const unsubscribers = [ + editor.playback.subscribe(onChange), + editor.timeline.subscribe(onChange), + editor.scenes.subscribe(onChange), + editor.project.subscribe(onChange), + editor.media.subscribe(onChange), + editor.renderer.subscribe(onChange), + editor.selection.subscribe(onChange), + editor.clipboard.subscribe(onChange), + ]; + return () => { + unsubscribers.forEach((unsubscribe) => { + unsubscribe(); + }); + }; + }, + [editor], + ); + + const getSnapshot = useCallback(() => { + const next = selectorRef.current ? selectorRef.current(editor) : editor; + if (isShallowEqual(snapshotCacheRef.current, next)) { + return snapshotCacheRef.current; + } + snapshotCacheRef.current = next; + return next; + }, [editor]); + + return useSyncExternalStore( + selector ? subscribeAll : subscribeNone, + getSnapshot, + getSnapshot, + ) as EditorCore | T; +} -- cgit v1.3.1