diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-03-25 16:47:22 +0100 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-03-29 15:48:22 +0200 |
| commit | 8db3bead13441a5882d8689dfc6a9f09c82375d9 (patch) | |
| tree | e9d0cafa93904ffcbec3188c37961bcc16c6422d /apps/web/src/hooks/use-editor.ts | |
| parent | 39ea298a9ccba3104c549c0ca079c231981811f5 (diff) | |
| download | opencut-8db3bead13441a5882d8689dfc6a9f09c82375d9.tar.gz | |
feat: masks, properties refactor, shaders, storage migrations, and more
Diffstat (limited to 'apps/web/src/hooks/use-editor.ts')
| -rw-r--r-- | apps/web/src/hooks/use-editor.ts | 63 |
1 files changed, 41 insertions, 22 deletions
diff --git a/apps/web/src/hooks/use-editor.ts b/apps/web/src/hooks/use-editor.ts index ff3e2db1..e211a85b 100644 --- a/apps/web/src/hooks/use-editor.ts +++ b/apps/web/src/hooks/use-editor.ts @@ -1,39 +1,58 @@ import { useCallback, useMemo, useRef, useSyncExternalStore } from "react"; import { EditorCore } from "@/core"; -export function useEditor(): EditorCore { +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<T>(selector: (editor: EditorCore) => T): T; +export function useEditor<T>( + selector?: (editor: EditorCore) => T, +): EditorCore | T { const editor = useMemo(() => EditorCore.getInstance(), []); - const versionRef = useRef(0); + const selectorRef = useRef(selector); + selectorRef.current = selector; - const subscribe = useCallback( - (onStoreChange: () => void) => { - const handleStoreChange = () => { - versionRef.current += 1; - onStoreChange(); - }; + const snapshotCacheRef = useRef<unknown>(undefined); + const subscribeAll = useCallback( + (onChange: () => void) => { const unsubscribers = [ - editor.playback.subscribe(handleStoreChange), - editor.timeline.subscribe(handleStoreChange), - editor.scenes.subscribe(handleStoreChange), - editor.project.subscribe(handleStoreChange), - editor.media.subscribe(handleStoreChange), - editor.renderer.subscribe(handleStoreChange), - editor.selection.subscribe(handleStoreChange), + 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 () => { - for (const unsubscribe of unsubscribers) { + unsubscribers.forEach((unsubscribe) => { unsubscribe(); - } + }); }; }, [editor], ); - const getSnapshot = useCallback(() => versionRef.current, []); - - useSyncExternalStore(subscribe, getSnapshot, getSnapshot); + 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 editor; + return useSyncExternalStore( + selector ? subscribeAll : subscribeNone, + getSnapshot, + getSnapshot, + ) as EditorCore | T; } |
