"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Canvas = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const studio_shared_1 = require("@remotion/studio-shared");
const react_1 = require("react");
const remotion_1 = require("remotion");
const client_id_1 = require("../helpers/client-id");
const colors_1 = require("../helpers/colors");
const get_asset_metadata_1 = require("../helpers/get-asset-metadata");
const get_effective_translation_1 = require("../helpers/get-effective-translation");
const install_required_package_1 = require("../helpers/install-required-package");
const open_in_editor_1 = require("../helpers/open-in-editor");
const remote_asset_drag_1 = require("../helpers/remote-asset-drag");
const smooth_zoom_1 = require("../helpers/smooth-zoom");
const use_keybinding_1 = require("../helpers/use-keybinding");
const canvas_ref_1 = require("../state/canvas-ref");
const editor_guides_1 = require("../state/editor-guides");
const editor_zoom_gestures_1 = require("../state/editor-zoom-gestures");
const call_api_1 = require("./call-api");
const ConfirmationDialog_1 = require("./ConfirmationDialog");
const EditorGuides_1 = __importDefault(require("./EditorGuides"));
const EditorRuler_1 = require("./EditorRuler");
const use_is_ruler_visible_1 = require("./EditorRuler/use-is-ruler-visible");
const effect_drag_and_drop_1 = require("./effect-drag-and-drop");
const element_drag_and_drop_1 = require("./element-drag-and-drop");
const import_assets_1 = require("./import-assets");
const layout_1 = require("./layout");
const Preview_1 = require("./Preview");
const ResetZoomButton_1 = require("./ResetZoomButton");
const use_resolved_stack_1 = require("./Timeline/use-resolved-stack");
const elementInstallCompositionIdStyle = {
    fontFamily: 'monospace',
    fontSize: 13,
};
const elementInstallDependencyListStyle = {
    marginTop: 8,
    marginBottom: 0,
    paddingLeft: 24,
    listStyleType: 'disc',
};
const elementInstallDependencyStyle = {
    color: 'inherit',
    fontFamily: 'monospace',
    fontSize: 13,
    lineHeight: 1.5,
};
const elementInstallCodeDetailsStyle = {
    marginTop: 12,
    fontSize: 13,
};
const elementInstallCodeSummaryStyle = {
    cursor: 'pointer',
    fontSize: 13,
    fontWeight: 500,
};
const elementInstallCodeBlockStyle = {
    marginTop: 8,
    marginBottom: 0,
    maxHeight: 240,
    overflow: 'auto',
    padding: 12,
    borderRadius: 6,
    backgroundColor: 'rgba(255, 255, 255, 0.06)',
    fontSize: 12,
    lineHeight: 1.5,
    whiteSpace: 'pre',
};
const getContainerStyle = (editorZoomGestures) => ({
    flex: 1,
    display: 'flex',
    overflow: 'hidden',
    position: 'relative',
    backgroundColor: colors_1.BACKGROUND,
    ...(editorZoomGestures ? { touchAction: 'none' } : {}),
});
const resetZoom = {
    position: 'absolute',
    top: layout_1.SPACING_UNIT * 2,
    right: layout_1.SPACING_UNIT * 2,
};
const ZOOM_PX_FACTOR = 0.003;
const isFileDragEvent = (event) => {
    var _a;
    var _b;
    return Array.from((_b = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.types) !== null && _b !== void 0 ? _b : []).includes('Files');
};
const isAssetDragEvent = (event) => {
    var _a;
    var _b;
    return Array.from((_b = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.types) !== null && _b !== void 0 ? _b : []).includes(studio_shared_1.ASSET_DRAG_MIME_TYPE);
};
const isComponentDragEvent = (event) => {
    var _a;
    var _b;
    return Array.from((_b = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.types) !== null && _b !== void 0 ? _b : []).includes(studio_shared_1.COMPONENT_DRAG_MIME_TYPE);
};
const isCompositionDragEvent = (event) => {
    var _a;
    var _b;
    return Array.from((_b = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.types) !== null && _b !== void 0 ? _b : []).includes(studio_shared_1.COMPOSITION_DRAG_MIME_TYPE);
};
const isElementDragEvent = (event) => {
    var _a;
    var _b;
    return Array.from((_b = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.types) !== null && _b !== void 0 ? _b : []).includes(studio_shared_1.ELEMENT_DRAG_MIME_TYPE);
};
const isSfxDragEvent = (event) => {
    var _a;
    var _b;
    return Array.from((_b = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.types) !== null && _b !== void 0 ? _b : []).includes(studio_shared_1.SFX_DRAG_MIME_TYPE);
};
const isRemoteAssetDragEvent = (event) => {
    return (!isFileDragEvent(event) &&
        !isAssetDragEvent(event) &&
        !isCompositionDragEvent(event) &&
        !isComponentDragEvent(event) &&
        !isElementDragEvent(event) &&
        !isSfxDragEvent(event) &&
        (0, remote_asset_drag_1.hasRemoteAssetDragData)(event.dataTransfer));
};
const getAssetDragPath = (event) => {
    var _a, _b;
    var _c;
    const value = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData(studio_shared_1.ASSET_DRAG_MIME_TYPE);
    if (!value) {
        return null;
    }
    return (_c = (_b = (0, studio_shared_1.parseAssetDragData)(value)) === null || _b === void 0 ? void 0 : _b.assetPath) !== null && _c !== void 0 ? _c : null;
};
const getCompositionDragData = (event) => {
    var _a;
    const value = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData(studio_shared_1.COMPOSITION_DRAG_MIME_TYPE);
    if (!value) {
        return null;
    }
    return (0, studio_shared_1.parseCompositionDragData)(value);
};
const getComponentDragData = (event) => {
    var _a;
    for (const type of [
        studio_shared_1.COMPONENT_DRAG_MIME_TYPE,
        'application/json',
        'text/plain',
    ]) {
        const value = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData(type);
        if (!value) {
            continue;
        }
        const parsed = (0, studio_shared_1.parseComponentDragData)(value);
        if (parsed) {
            return parsed;
        }
    }
    return null;
};
const getSfxDragUrl = (event) => {
    const { dataTransfer } = event;
    if (!dataTransfer) {
        return null;
    }
    for (const type of [studio_shared_1.SFX_DRAG_MIME_TYPE, 'application/json', 'text/plain']) {
        const value = dataTransfer.getData(type);
        if (!value) {
            continue;
        }
        const parsed = (0, studio_shared_1.parseSfxDragData)(value);
        if (parsed) {
            return parsed.sfx.url;
        }
    }
    return null;
};
const getDropPosition = ({ clientX, clientY, contentDimensions, previewSize, size, }) => {
    if (contentDimensions === null || contentDimensions === 'none') {
        return null;
    }
    const scale = remotion_1.Internals.calculateScale({
        canvasSize: size,
        compositionHeight: contentDimensions.height,
        compositionWidth: contentDimensions.width,
        previewSize: previewSize.size,
    });
    const { centerX, centerY } = (0, get_effective_translation_1.getCenterPointWhileScrolling)({
        size,
        clientX,
        clientY,
        compositionWidth: contentDimensions.width,
        compositionHeight: contentDimensions.height,
        scale,
        translation: previewSize.translation,
    });
    return { centerX, centerY };
};
const isDragEventInsideCanvas = (event) => {
    const { current } = canvas_ref_1.canvasRef;
    if (!current) {
        return false;
    }
    const targetIsNode = event.target instanceof Node;
    if (targetIsNode && current.contains(event.target)) {
        return true;
    }
    const rect = current.getBoundingClientRect();
    return (event.clientX >= rect.left &&
        event.clientX <= rect.right &&
        event.clientY >= rect.top &&
        event.clientY <= rect.bottom);
};
const Canvas = ({ canvasContent, size }) => {
    var _a, _b;
    const { setSize, size: previewSize } = (0, react_1.useContext)(remotion_1.Internals.PreviewSizeContext);
    const { editorZoomGestures } = (0, react_1.useContext)(editor_zoom_gestures_1.EditorZoomGesturesContext);
    const previewSnapshotRef = (0, react_1.useRef)({
        previewSize,
        canvasSize: size,
        contentDimensions: null,
    });
    const pinchBaseZoomRef = (0, react_1.useRef)(null);
    const suppressWheelFromWebKitPinchRef = (0, react_1.useRef)(false);
    const touchPinchRef = (0, react_1.useRef)(null);
    const keybindings = (0, use_keybinding_1.useKeybinding)();
    const confirm = (0, ConfirmationDialog_1.useConfirmationDialog)();
    const config = remotion_1.Internals.useUnsafeVideoConfig();
    const areRulersVisible = (0, use_is_ruler_visible_1.useIsRulerVisible)();
    const { editorShowGuides } = (0, react_1.useContext)(editor_guides_1.EditorShowGuidesContext);
    const { compositions } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
    const { previewServerState, subscribeToEvent } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
    const previewServerClientId = previewServerState.type === 'connected'
        ? previewServerState.clientId
        : null;
    const [isAddingAsset, setIsAddingAsset] = (0, react_1.useState)(false);
    const [installingElementName, setInstallingElementName] = (0, react_1.useState)(null);
    const [pendingElementInstallRequests, setPendingElementInstallRequests] = (0, react_1.useState)([]);
    const [activeElementInstallRequest, setActiveElementInstallRequest] = (0, react_1.useState)(null);
    const lastFocusedAtRef = (0, react_1.useRef)(typeof document === 'undefined' || document.hasFocus() ? Date.now() : null);
    const [assetResolution, setAssetResolution] = (0, react_1.useState)(null);
    const currentCompositionId = canvasContent.type === 'composition' ? canvasContent.compositionId : null;
    const currentComposition = (0, react_1.useMemo)(() => {
        var _a;
        if (currentCompositionId === null) {
            return null;
        }
        return ((_a = compositions.find((composition) => composition.id === currentCompositionId)) !== null && _a !== void 0 ? _a : null);
    }, [compositions, currentCompositionId]);
    const resolvedCompositionLocation = (0, use_resolved_stack_1.useResolvedStack)((_a = currentComposition === null || currentComposition === void 0 ? void 0 : currentComposition.stack) !== null && _a !== void 0 ? _a : null);
    const compositionFile = (_b = resolvedCompositionLocation === null || resolvedCompositionLocation === void 0 ? void 0 : resolvedCompositionLocation.source) !== null && _b !== void 0 ? _b : null;
    const compositionComponentInfo = (0, open_in_editor_1.useCachedCompositionComponentInfo)({
        compositionFile,
        compositionId: currentCompositionId,
    });
    const canInstallElements = previewServerClientId !== null &&
        !window.remotion_isReadOnlyStudio &&
        (compositionComponentInfo === null || compositionComponentInfo === void 0 ? void 0 : compositionComponentInfo.canAddSequence) === true &&
        currentCompositionId !== null &&
        compositionFile !== null;
    const canDropAssets = canInstallElements && !isAddingAsset;
    const contentDimensions = (0, react_1.useMemo)(() => {
        if ((canvasContent.type === 'asset' ||
            canvasContent.type === 'output' ||
            canvasContent.type === 'output-blob') &&
            assetResolution &&
            assetResolution.type === 'found') {
            return assetResolution.dimensions;
        }
        if (config) {
            return { width: config.width, height: config.height };
        }
        return null;
    }, [assetResolution, config, canvasContent]);
    const isFit = previewSize.size === 'auto';
    previewSnapshotRef.current = {
        previewSize,
        canvasSize: size,
        contentDimensions,
    };
    const onWheel = (0, react_1.useCallback)((e) => {
        const ev = e;
        if (!editorZoomGestures) {
            return;
        }
        if (!size) {
            return;
        }
        if (!contentDimensions || contentDimensions === 'none') {
            return;
        }
        const wantsToZoom = ev.ctrlKey || ev.metaKey;
        if (!wantsToZoom && isFit) {
            return;
        }
        if (suppressWheelFromWebKitPinchRef.current && wantsToZoom) {
            ev.preventDefault();
            return;
        }
        ev.preventDefault();
        setSize((prevSize) => {
            const scale = remotion_1.Internals.calculateScale({
                canvasSize: size,
                compositionHeight: contentDimensions.height,
                compositionWidth: contentDimensions.width,
                previewSize: prevSize.size,
            });
            if (wantsToZoom) {
                const oldSize = prevSize.size === 'auto' ? scale : prevSize.size;
                const smoothened = (0, smooth_zoom_1.smoothenZoom)(oldSize);
                const added = smoothened + ev.deltaY * ZOOM_PX_FACTOR;
                const unsmoothened = (0, smooth_zoom_1.unsmoothenZoom)(added);
                return (0, get_effective_translation_1.applyZoomAroundFocalPoint)({
                    canvasSize: size,
                    contentDimensions,
                    previewSizeBefore: prevSize,
                    oldNumericSize: oldSize,
                    newNumericSize: unsmoothened,
                    clientX: ev.clientX,
                    clientY: ev.clientY,
                });
            }
            const effectiveTranslation = (0, get_effective_translation_1.getEffectiveTranslation)({
                translation: prevSize.translation,
                canvasSize: size,
                compositionHeight: contentDimensions.height,
                compositionWidth: contentDimensions.width,
                scale,
            });
            return {
                ...prevSize,
                translation: (0, get_effective_translation_1.getEffectiveTranslation)({
                    translation: {
                        x: effectiveTranslation.x + ev.deltaX,
                        y: effectiveTranslation.y + ev.deltaY,
                    },
                    canvasSize: size,
                    compositionHeight: contentDimensions.height,
                    compositionWidth: contentDimensions.width,
                    scale,
                }),
            };
        });
    }, [editorZoomGestures, contentDimensions, isFit, setSize, size]);
    (0, react_1.useEffect)(() => {
        const { current } = canvas_ref_1.canvasRef;
        if (!current) {
            return;
        }
        current.addEventListener('wheel', onWheel, { passive: false });
        return () => {
            current.removeEventListener('wheel', onWheel);
        };
    }, [onWheel]);
    const supportsWebKitPinch = typeof window !== 'undefined' && 'GestureEvent' in window;
    (0, react_1.useEffect)(() => {
        const { current } = canvas_ref_1.canvasRef;
        if (!current || !editorZoomGestures || !supportsWebKitPinch) {
            return;
        }
        const endWebKitPinch = () => {
            pinchBaseZoomRef.current = null;
            suppressWheelFromWebKitPinchRef.current = false;
        };
        const onGestureStart = (event) => {
            const e = event;
            const snap = previewSnapshotRef.current;
            const canvasSz = snap.canvasSize;
            const cdim = snap.contentDimensions;
            if (!canvasSz || !cdim || cdim === 'none') {
                return;
            }
            e.preventDefault();
            suppressWheelFromWebKitPinchRef.current = true;
            const fitted = remotion_1.Internals.calculateScale({
                canvasSize: canvasSz,
                compositionHeight: cdim.height,
                compositionWidth: cdim.width,
                previewSize: snap.previewSize.size,
            });
            pinchBaseZoomRef.current =
                snap.previewSize.size === 'auto' ? fitted : snap.previewSize.size;
        };
        const onGestureChange = (event) => {
            const e = event;
            const base = pinchBaseZoomRef.current;
            const snap = previewSnapshotRef.current;
            const canvasSz = snap.canvasSize;
            const cdim = snap.contentDimensions;
            if (base === null || !canvasSz || !cdim || cdim === 'none') {
                return;
            }
            const dimensions = cdim;
            e.preventDefault();
            setSize((prevSize) => {
                const scale = remotion_1.Internals.calculateScale({
                    canvasSize: canvasSz,
                    compositionHeight: dimensions.height,
                    compositionWidth: dimensions.width,
                    previewSize: prevSize.size,
                });
                const oldNumeric = prevSize.size === 'auto' ? scale : prevSize.size;
                return (0, get_effective_translation_1.applyZoomAroundFocalPoint)({
                    canvasSize: canvasSz,
                    contentDimensions: dimensions,
                    previewSizeBefore: prevSize,
                    oldNumericSize: oldNumeric,
                    newNumericSize: base * e.scale,
                    clientX: e.clientX,
                    clientY: e.clientY,
                });
            });
        };
        const onGestureEnd = () => {
            endWebKitPinch();
        };
        current.addEventListener('gesturestart', onGestureStart, {
            passive: false,
        });
        current.addEventListener('gesturechange', onGestureChange, {
            passive: false,
        });
        current.addEventListener('gestureend', onGestureEnd);
        current.addEventListener('gesturecancel', onGestureEnd);
        return () => {
            current.removeEventListener('gesturestart', onGestureStart);
            current.removeEventListener('gesturechange', onGestureChange);
            current.removeEventListener('gestureend', onGestureEnd);
            current.removeEventListener('gesturecancel', onGestureEnd);
        };
    }, [editorZoomGestures, setSize, supportsWebKitPinch]);
    (0, react_1.useEffect)(() => {
        const { current } = canvas_ref_1.canvasRef;
        if (!current || !editorZoomGestures) {
            return;
        }
        const onTouchStart = (event) => {
            if (event.touches.length !== 2) {
                touchPinchRef.current = null;
                return;
            }
            const snap = previewSnapshotRef.current;
            if (!snap.canvasSize ||
                !snap.contentDimensions ||
                snap.contentDimensions === 'none') {
                return;
            }
            const [t0, t1] = [event.touches[0], event.touches[1]];
            const initialDistance = Math.hypot(t1.clientX - t0.clientX, t1.clientY - t0.clientY);
            if (initialDistance < 1e-6) {
                return;
            }
            const fitted = remotion_1.Internals.calculateScale({
                canvasSize: snap.canvasSize,
                compositionHeight: snap.contentDimensions.height,
                compositionWidth: snap.contentDimensions.width,
                previewSize: snap.previewSize.size,
            });
            const initialZoom = snap.previewSize.size === 'auto' ? fitted : snap.previewSize.size;
            touchPinchRef.current = { initialDistance, initialZoom };
        };
        const onTouchMove = (event) => {
            const pinch = touchPinchRef.current;
            const snap = previewSnapshotRef.current;
            if (pinch === null ||
                event.touches.length !== 2 ||
                !snap.canvasSize ||
                !snap.contentDimensions ||
                snap.contentDimensions === 'none') {
                return;
            }
            event.preventDefault();
            const [t0, t1] = [event.touches[0], event.touches[1]];
            const dist = Math.hypot(t1.clientX - t0.clientX, t1.clientY - t0.clientY);
            const ratio = dist / pinch.initialDistance;
            const clientX = (t0.clientX + t1.clientX) / 2;
            const clientY = (t0.clientY + t1.clientY) / 2;
            setSize((prevSize) => {
                const canvasSz = snap.canvasSize;
                const cdim = snap.contentDimensions;
                const scale = remotion_1.Internals.calculateScale({
                    canvasSize: canvasSz,
                    compositionHeight: cdim.height,
                    compositionWidth: cdim.width,
                    previewSize: prevSize.size,
                });
                const oldNumeric = prevSize.size === 'auto' ? scale : prevSize.size;
                return (0, get_effective_translation_1.applyZoomAroundFocalPoint)({
                    canvasSize: canvasSz,
                    contentDimensions: cdim,
                    previewSizeBefore: prevSize,
                    oldNumericSize: oldNumeric,
                    newNumericSize: pinch.initialZoom * ratio,
                    clientX,
                    clientY,
                });
            });
        };
        const onTouchEnd = (event) => {
            if (event.touches.length < 2) {
                touchPinchRef.current = null;
            }
        };
        current.addEventListener('touchstart', onTouchStart, { passive: true });
        current.addEventListener('touchmove', onTouchMove, { passive: false });
        current.addEventListener('touchend', onTouchEnd);
        current.addEventListener('touchcancel', onTouchEnd);
        return () => {
            current.removeEventListener('touchstart', onTouchStart);
            current.removeEventListener('touchmove', onTouchMove);
            current.removeEventListener('touchend', onTouchEnd);
            current.removeEventListener('touchcancel', onTouchEnd);
        };
    }, [editorZoomGestures, setSize]);
    const onReset = (0, react_1.useCallback)(() => {
        setSize(() => {
            return {
                translation: {
                    x: 0,
                    y: 0,
                },
                size: 'auto',
            };
        });
    }, [setSize]);
    const onZoomIn = (0, react_1.useCallback)(() => {
        if (!contentDimensions || contentDimensions === 'none') {
            return;
        }
        if (!size) {
            return;
        }
        setSize((prevSize) => {
            const scale = remotion_1.Internals.calculateScale({
                canvasSize: size,
                compositionHeight: contentDimensions.height,
                compositionWidth: contentDimensions.width,
                previewSize: prevSize.size,
            });
            return {
                translation: {
                    x: 0,
                    y: 0,
                },
                size: Math.min(smooth_zoom_1.MAX_ZOOM, scale * 2),
            };
        });
    }, [contentDimensions, setSize, size]);
    const onZoomOut = (0, react_1.useCallback)(() => {
        if (!contentDimensions || contentDimensions === 'none') {
            return;
        }
        if (!size) {
            return;
        }
        setSize((prevSize) => {
            const scale = remotion_1.Internals.calculateScale({
                canvasSize: size,
                compositionHeight: contentDimensions.height,
                compositionWidth: contentDimensions.width,
                previewSize: prevSize.size,
            });
            return {
                translation: {
                    x: 0,
                    y: 0,
                },
                size: Math.max(smooth_zoom_1.MIN_ZOOM, scale / 2),
            };
        });
    }, [contentDimensions, setSize, size]);
    (0, react_1.useEffect)(() => {
        const resetBinding = keybindings.registerKeybinding({
            event: 'keydown',
            key: '0',
            commandCtrlKey: false,
            callback: onReset,
            preventDefault: true,
            triggerIfInputFieldFocused: false,
            keepRegisteredWhenNotHighestContext: false,
        });
        const zoomIn = keybindings.registerKeybinding({
            event: 'keydown',
            key: '+',
            commandCtrlKey: false,
            callback: onZoomIn,
            preventDefault: true,
            triggerIfInputFieldFocused: false,
            keepRegisteredWhenNotHighestContext: false,
        });
        const zoomOut = keybindings.registerKeybinding({
            event: 'keydown',
            key: '-',
            commandCtrlKey: false,
            callback: onZoomOut,
            preventDefault: true,
            triggerIfInputFieldFocused: false,
            keepRegisteredWhenNotHighestContext: false,
        });
        return () => {
            resetBinding.unregister();
            zoomIn.unregister();
            zoomOut.unregister();
        };
    }, [keybindings, onReset, onZoomIn, onZoomOut]);
    const fetchMetadata = (0, react_1.useCallback)(async () => {
        setAssetResolution(null);
        if (canvasContent.type === 'composition') {
            return;
        }
        const metadata = await (0, get_asset_metadata_1.getAssetMetadata)(canvasContent, canvasContent.type === 'asset');
        setAssetResolution(metadata);
    }, [canvasContent]);
    (0, react_1.useEffect)(() => {
        if (canvasContent.type !== 'asset') {
            return;
        }
        const file = (0, remotion_1.watchStaticFile)(canvasContent.asset, () => {
            fetchMetadata();
        });
        return () => {
            file.cancel();
        };
    }, [canvasContent, fetchMetadata]);
    (0, react_1.useEffect)(() => {
        fetchMetadata();
    }, [fetchMetadata]);
    const updateElementInstallTarget = (0, react_1.useCallback)((requestId) => {
        if (previewServerClientId === null) {
            return;
        }
        (0, call_api_1.callApi)('/api/update-element-install-target', {
            requestId,
            clientId: previewServerClientId,
            compositionFile: canInstallElements ? compositionFile : null,
            compositionId: canInstallElements ? currentCompositionId : null,
            canInstall: canInstallElements,
            lastFocusedAt: lastFocusedAtRef.current,
            readOnly: window.remotion_isReadOnlyStudio,
            studioUrl: window.location.href,
        }).catch(() => undefined);
    }, [
        canInstallElements,
        compositionFile,
        currentCompositionId,
        previewServerClientId,
    ]);
    (0, react_1.useEffect)(() => {
        const markFocused = () => {
            lastFocusedAtRef.current = Date.now();
        };
        window.addEventListener('focus', markFocused);
        document.addEventListener('pointerdown', markFocused, { capture: true });
        return () => {
            window.removeEventListener('focus', markFocused);
            document.removeEventListener('pointerdown', markFocused, { capture: true });
        };
    }, []);
    (0, react_1.useEffect)(() => {
        return subscribeToEvent('request-element-install-target', (event) => {
            if (event.type !== 'request-element-install-target') {
                return;
            }
            updateElementInstallTarget(event.requestId);
        });
    }, [subscribeToEvent, updateElementInstallTarget]);
    (0, react_1.useEffect)(() => {
        if (installingElementName === null) {
            return;
        }
        const previousTitle = document.title;
        document.title = `📦 Install ${installingElementName} - Remotion Studio`;
        return () => {
            document.title = previousTitle;
        };
    }, [installingElementName]);
    (0, react_1.useEffect)(() => {
        if (previewServerClientId === null) {
            return;
        }
        return subscribeToEvent('element-install-request', (event) => {
            if (event.type !== 'element-install-request' ||
                event.request.clientId !== previewServerClientId) {
                return;
            }
            setPendingElementInstallRequests((requests) => [
                ...requests,
                event.request,
            ]);
        });
    }, [previewServerClientId, subscribeToEvent]);
    (0, react_1.useEffect)(() => {
        if (activeElementInstallRequest !== null ||
            pendingElementInstallRequests.length === 0) {
            return;
        }
        const [nextRequest, ...remainingRequests] = pendingElementInstallRequests;
        if (!nextRequest) {
            throw new Error('Expected pending Element install request');
        }
        setActiveElementInstallRequest(nextRequest);
        setPendingElementInstallRequests(remainingRequests);
    }, [activeElementInstallRequest, pendingElementInstallRequests]);
    (0, react_1.useEffect)(() => {
        if (activeElementInstallRequest === null) {
            return;
        }
        let canceled = false;
        const handleInstallRequest = async () => {
            setInstallingElementName(activeElementInstallRequest.element.displayName);
            const missingPackages = (0, install_required_package_1.getMissingPackages)(activeElementInstallRequest.element.dependencies);
            const accepted = await confirm({
                title: 'Install Element',
                message: (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: ["Install \u201C", activeElementInstallRequest.element.displayName, "\u201D into", ' ', jsx_runtime_1.jsx("code", { style: elementInstallCompositionIdStyle, children: activeElementInstallRequest.compositionId }), ' ', "composition? This will create an Element source file and update the composition source.", missingPackages.length > 0 ? (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
                                jsx_runtime_1.jsx("br", {}), jsx_runtime_1.jsx("br", {}),
                                "The following dependencies will also be installed:",
                                jsx_runtime_1.jsx("ul", { style: elementInstallDependencyListStyle, children: missingPackages.map((packageName) => (jsx_runtime_1.jsx("li", { style: elementInstallDependencyStyle, children: packageName }, packageName))) })
                            ] })) : null, jsx_runtime_1.jsxs("details", { style: elementInstallCodeDetailsStyle, children: [
                                jsx_runtime_1.jsx("summary", { style: elementInstallCodeSummaryStyle, children: "Preview Element source" }), jsx_runtime_1.jsx("pre", { style: elementInstallCodeBlockStyle, children: jsx_runtime_1.jsx("code", { children: activeElementInstallRequest.element.sourceCode }) })
                            ] })
                    ] })),
                confirmLabel: 'Install',
                cancelLabel: 'Cancel',
            });
            if (accepted && !canceled) {
                await (0, import_assets_1.insertElement)({
                    element: activeElementInstallRequest.element,
                    compositionFile: activeElementInstallRequest.compositionFile,
                    compositionId: activeElementInstallRequest.compositionId,
                    dropPosition: null,
                });
            }
        };
        handleInstallRequest()
            .finally(() => {
            if (canceled) {
                return;
            }
            setInstallingElementName(null);
            setActiveElementInstallRequest(null);
        })
            .catch((err) => {
            setTimeout(() => {
                throw err;
            }, 0);
        });
        return () => {
            canceled = true;
        };
    }, [activeElementInstallRequest, confirm]);
    const onDragOver = (0, react_1.useCallback)((event) => {
        if (!canDropAssets ||
            (!isFileDragEvent(event) &&
                !isAssetDragEvent(event) &&
                !isCompositionDragEvent(event) &&
                !isComponentDragEvent(event) &&
                !isElementDragEvent(event) &&
                !isSfxDragEvent(event) &&
                !isRemoteAssetDragEvent(event)) ||
            !isDragEventInsideCanvas(event)) {
            return;
        }
        event.preventDefault();
        if (event.dataTransfer) {
            event.dataTransfer.dropEffect = 'copy';
        }
    }, [canDropAssets]);
    const onDrop = (0, react_1.useCallback)(async (event) => {
        var _a;
        var _b;
        if (!canDropAssets ||
            compositionFile === null ||
            currentCompositionId === null ||
            (!isFileDragEvent(event) &&
                !isAssetDragEvent(event) &&
                !isCompositionDragEvent(event) &&
                !isComponentDragEvent(event) &&
                !isElementDragEvent(event) &&
                !isSfxDragEvent(event) &&
                !isRemoteAssetDragEvent(event)) ||
            !isDragEventInsideCanvas(event)) {
            return;
        }
        if (event.dataTransfer &&
            (0, effect_drag_and_drop_1.getEffectDragData)(event.dataTransfer) !== null) {
            event.preventDefault();
            return;
        }
        event.preventDefault();
        event.stopPropagation();
        setIsAddingAsset(true);
        try {
            const dropPosition = getDropPosition({
                clientX: event.clientX,
                clientY: event.clientY,
                contentDimensions,
                previewSize,
                size,
            });
            if (isFileDragEvent(event)) {
                const files = Array.from((_b = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.files) !== null && _b !== void 0 ? _b : []);
                if (files.length === 0) {
                    return;
                }
                await (0, import_assets_1.importAssets)({
                    files,
                    compositionFile,
                    compositionId: currentCompositionId,
                    dropPosition,
                });
            }
            else if (isAssetDragEvent(event)) {
                const assetPath = getAssetDragPath(event);
                if (assetPath === null) {
                    return;
                }
                await (0, import_assets_1.insertExistingAssets)({
                    assetPaths: [assetPath],
                    compositionFile,
                    compositionId: currentCompositionId,
                    dropPosition,
                });
            }
            else if (isSfxDragEvent(event)) {
                const url = getSfxDragUrl(event);
                if (url === null) {
                    return;
                }
                await (0, import_assets_1.insertRemoteAudio)({
                    url,
                    compositionFile,
                    compositionId: currentCompositionId,
                });
            }
            else if (isCompositionDragEvent(event)) {
                const compositionDragData = getCompositionDragData(event);
                if (compositionDragData === null) {
                    return;
                }
                await (0, import_assets_1.insertComposition)({
                    composition: compositionDragData,
                    compositionFile,
                    compositionId: currentCompositionId,
                    dropPosition,
                });
            }
            else {
                const elementDragData = (0, element_drag_and_drop_1.getElementDragData)(event.dataTransfer);
                if (elementDragData !== null) {
                    await (0, import_assets_1.insertElement)({
                        element: elementDragData.element,
                        compositionFile,
                        compositionId: currentCompositionId,
                        dropPosition,
                    });
                    return;
                }
                const componentDragData = getComponentDragData(event);
                if (componentDragData !== null) {
                    await (0, import_assets_1.insertComponent)({
                        component: componentDragData.component,
                        compositionFile,
                        compositionId: currentCompositionId,
                        dropPosition,
                    });
                    return;
                }
                const url = (0, remote_asset_drag_1.getRemoteAssetUrlFromDataTransfer)(event.dataTransfer);
                if (url === null) {
                    return;
                }
                await (0, import_assets_1.importRemoteAsset)({
                    url,
                    compositionFile,
                    compositionId: currentCompositionId,
                    dropPosition,
                });
            }
        }
        finally {
            setIsAddingAsset(false);
        }
    }, [
        canDropAssets,
        compositionFile,
        contentDimensions,
        currentCompositionId,
        previewSize,
        size,
    ]);
    (0, react_1.useEffect)(() => {
        if (!canDropAssets) {
            return;
        }
        document.addEventListener('dragover', onDragOver, { capture: true });
        document.addEventListener('drop', onDrop, { capture: true });
        return () => {
            document.removeEventListener('dragover', onDragOver, { capture: true });
            document.removeEventListener('drop', onDrop, { capture: true });
        };
    }, [canDropAssets, onDragOver, onDrop]);
    return (jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [
            jsx_runtime_1.jsxs("div", { ref: canvas_ref_1.canvasRef, style: getContainerStyle(editorZoomGestures), children: [size ? (jsx_runtime_1.jsx(Preview_1.VideoPreview, { canvasContent: canvasContent, contentDimensions: contentDimensions, canvasSize: size, assetMetadata: assetResolution, onRetryAssetMetadata: fetchMetadata })) : null, isFit ? null : (jsx_runtime_1.jsx("div", { style: resetZoom, className: "css-reset", children: jsx_runtime_1.jsx(ResetZoomButton_1.ResetZoomButton, { onClick: onReset }) })), editorShowGuides && canvasContent.type === 'composition' && (jsx_runtime_1.jsx(EditorGuides_1.default, { canvasSize: size, contentDimensions: contentDimensions, assetMetadata: assetResolution }))] }), areRulersVisible && (jsx_runtime_1.jsx(EditorRuler_1.EditorRulers, { contentDimensions: contentDimensions, canvasSize: size, assetMetadata: assetResolution, containerRef: canvas_ref_1.canvasRef }))] }));
};
exports.Canvas = Canvas;
