import { createContext, useContext, useMemo, type ReactNode } from "react"; import type { TimelineElement } from "../player"; import type { CompositionDimensions } from "../components/renders/RenderQueue"; export interface StudioShellValue { projectId: string; activeCompPath: string | null; setActiveCompPath: (path: string | null) => void; showToast: (message: string, tone?: "error" | "info") => void; previewIframeRef: React.MutableRefObject; editHistory: { canUndo: boolean; canRedo: boolean; undoLabel: string | undefined; redoLabel: string | undefined; }; handleUndo: () => Promise; handleRedo: () => Promise; renderQueue: { jobs: unknown[]; isRendering: boolean; deleteRender: (jobId: string) => void; clearCompleted: () => void; startRender: (options: unknown) => Promise; }; compositionDimensions: CompositionDimensions | null; waitForPendingDomEditSaves: () => Promise; handlePreviewIframeRef: (iframe: HTMLIFrameElement | null) => void; timelineVisible: boolean; toggleTimelineVisibility: () => void; } export interface StudioPlaybackValue { captionEditMode: boolean; compositionLoading: boolean; refreshKey: number; setRefreshKey: React.Dispatch>; timelineElements: TimelineElement[]; isPlaying: boolean; refreshPreviewDocumentVersion: () => void; } export type StudioContextValue = StudioShellValue & StudioPlaybackValue; const StudioShellContext = createContext(null); const StudioPlaybackContext = createContext(null); export function useStudioShellContext(): StudioShellValue { const ctx = useContext(StudioShellContext); if (!ctx) throw new Error("useStudioShellContext must be used within StudioShellProvider"); return ctx; } export function useStudioPlaybackContext(): StudioPlaybackValue { const ctx = useContext(StudioPlaybackContext); if (!ctx) throw new Error("useStudioPlaybackContext must be used within StudioPlaybackProvider"); return ctx; } /** @deprecated Use useStudioShellContext and/or useStudioPlaybackContext instead. */ export function useStudioContext(): StudioContextValue { const shell = useStudioShellContext(); const playback = useStudioPlaybackContext(); return useMemo(() => ({ ...shell, ...playback }), [shell, playback]); } export function StudioShellProvider({ value, children, }: { value: StudioShellValue; children: ReactNode; }) { const { projectId, activeCompPath, setActiveCompPath, showToast, previewIframeRef, editHistory, handleUndo, handleRedo, renderQueue, compositionDimensions, waitForPendingDomEditSaves, handlePreviewIframeRef, timelineVisible, toggleTimelineVisibility, } = value; const stable = useMemo( () => ({ projectId, activeCompPath, setActiveCompPath, showToast, previewIframeRef, editHistory, handleUndo, handleRedo, renderQueue, compositionDimensions, waitForPendingDomEditSaves, handlePreviewIframeRef, timelineVisible, toggleTimelineVisibility, }), [ projectId, activeCompPath, compositionDimensions, timelineVisible, editHistory, renderQueue, setActiveCompPath, showToast, previewIframeRef, handleUndo, handleRedo, waitForPendingDomEditSaves, handlePreviewIframeRef, toggleTimelineVisibility, ], ); return {children}; } export function StudioPlaybackProvider({ value, children, }: { value: StudioPlaybackValue; children: ReactNode; }) { const { captionEditMode, compositionLoading, refreshKey, setRefreshKey, timelineElements, isPlaying, refreshPreviewDocumentVersion, } = value; const stable = useMemo( () => ({ captionEditMode, compositionLoading, refreshKey, setRefreshKey, timelineElements, isPlaying, refreshPreviewDocumentVersion, }), [ captionEditMode, compositionLoading, refreshKey, timelineElements, isPlaying, setRefreshKey, refreshPreviewDocumentVersion, ], ); return {children}; } /** @deprecated Use StudioShellProvider and StudioPlaybackProvider instead. */ export function StudioProvider({ value, children, }: { value: StudioContextValue; children: ReactNode; }) { return ( {children} ); }