'use client';
import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime";
import { DndContext } from '@dnd-kit/core';
import React, { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';
import { usePopupWindow } from '../../hooks/usePopupWindow.js';
import { useDocumentInfo } from '../../providers/DocumentInfo/index.js';
import { usePreferences } from '../../providers/Preferences/index.js';
import { formatAbsoluteURL } from '../../utilities/formatAbsoluteURL.js';
import { customCollisionDetection } from './collisionDetection.js';
import { LivePreviewContext } from './context.js';
import { sizeReducer } from './sizeReducer.js';
/**
   * This specifically relates to `admin.preview` function in the config instead of live preview.
   */ /**
   * This specifically relates to `admin.preview` function in the config instead of live preview.
   */ export const LivePreviewProvider = ({ breakpoints: incomingBreakpoints, children, isLivePreviewEnabled, isLivePreviewing: incomingIsLivePreviewing, isPreviewEnabled, previewURL: previewURLFromProps, typeofLivePreviewURL, url: urlFromProps })=>{
    const [previewWindowType, setPreviewWindowType] = useState('iframe');
    const [isLivePreviewing, setIsLivePreviewing] = useState(incomingIsLivePreviewing);
    const breakpoints = useMemo(()=>[
            ...incomingBreakpoints || [],
            {
                name: 'responsive',
                height: '100%',
                label: 'Responsive',
                width: '100%'
            }
        ], [
        incomingBreakpoints
    ]);
    const [url, setURL] = useState('');
    const [previewURL, setPreviewURL] = useState(previewURLFromProps);
    const { isPopupOpen, openPopupWindow, popupRef } = usePopupWindow({
        eventType: 'payload-live-preview',
        url
    });
    const [appIsReady, setAppIsReady] = useState(false);
    const [listeningForMessages, setListeningForMessages] = useState(false);
    const { collectionSlug, globalSlug } = useDocumentInfo();
    const isFirstRender = useRef(true);
    const { setPreference } = usePreferences();
    const iframeRef = React.useRef(null);
    const [loadedURL, setLoadedURL] = useState();
    const [zoom, setZoom] = useState(1);
    const [position, setPosition] = useState({
        x: 0,
        y: 0
    });
    const [size, setSize] = React.useReducer(sizeReducer, {
        height: 0,
        width: 0
    });
    const [measuredDeviceSize, setMeasuredDeviceSize] = useState({
        height: 0,
        width: 0
    });
    const [breakpoint, setBreakpoint] = React.useState('responsive');
    /**
   * A "middleware" callback fn that does some additional work before `setURL`.
   * This is what we provide through context, bc it:
   *  - ensures the URL is absolute
   *  - resets `appIsReady` to `false` while the new URL is loading
   */ const setLivePreviewURL = useCallback((_incomingURL)=>{
        let incomingURL;
        if (typeof _incomingURL === 'string') {
            incomingURL = formatAbsoluteURL(_incomingURL);
        }
        if (!incomingURL) {
            setIsLivePreviewing(false);
        }
        if (incomingURL !== url) {
            setAppIsReady(false);
            setURL(incomingURL);
        }
    }, [
        url
    ]);
    /**
   * `url` needs to be relative to the window, which cannot be done on initial render.
   */ useEffect(()=>{
        if (typeof urlFromProps === 'string') {
            setURL(formatAbsoluteURL(urlFromProps));
        }
    }, [
        urlFromProps
    ]);
    // The toolbar needs to freely drag and drop around the page
    const handleDragEnd = (ev)=>{
        // only update position if the toolbar is completely within the preview area
        // otherwise reset it back to the previous position
        // TODO: reset to the nearest edge of the preview area
        if (ev.over && ev.over.id === 'live-preview-area') {
            const newPos = {
                x: position.x + ev.delta.x,
                y: position.y + ev.delta.y
            };
            setPosition(newPos);
        } else {}
    };
    // reset
    const setWidth = useCallback((width)=>{
        setSize({
            type: 'width',
            value: width
        });
    }, [
        setSize
    ]);
    const setHeight = useCallback((height)=>{
        setSize({
            type: 'height',
            value: height
        });
    }, [
        setSize
    ]);
    // explicitly set new width and height when as new breakpoints are selected
    // exclude `custom` breakpoint as it is handled by the `setWidth` and `setHeight` directly
    useEffect(()=>{
        const foundBreakpoint = breakpoints?.find((bp)=>bp.name === breakpoint);
        if (foundBreakpoint && breakpoint !== 'responsive' && breakpoint !== 'custom' && typeof foundBreakpoint?.width === 'number' && typeof foundBreakpoint?.height === 'number') {
            setSize({
                type: 'reset',
                value: {
                    height: foundBreakpoint.height,
                    width: foundBreakpoint.width
                }
            });
        }
    }, [
        breakpoint,
        breakpoints
    ]);
    /**
   * Receive the `ready` message from the popup window
   * This indicates that the app is ready to receive `window.postMessage` events
   * This is also the only cross-origin way of detecting when a popup window has loaded
   * Unlike iframe elements which have an `onLoad` handler, there is no way to access `window.open` on popups
   */ useEffect(()=>{
        const handleMessage = (event)=>{
            if (url?.startsWith(event.origin) && event.data && typeof event.data === 'object' && event.data.type === 'payload-live-preview') {
                if (event.data.ready) {
                    setAppIsReady(true);
                }
            }
        };
        window.addEventListener('message', handleMessage);
        setListeningForMessages(true);
        return ()=>{
            window.removeEventListener('message', handleMessage);
        };
    }, [
        url,
        listeningForMessages
    ]);
    const handleWindowChange = useCallback((type)=>{
        setAppIsReady(false);
        setPreviewWindowType(type);
        if (type === 'popup') {
            openPopupWindow();
        }
    }, [
        openPopupWindow
    ]);
    // when the user closes the popup window, switch back to the iframe
    // the `usePopupWindow` reports the `isPopupOpen` state for us to use here
    useEffect(()=>{
        const newPreviewWindowType = isPopupOpen ? 'popup' : 'iframe';
        if (newPreviewWindowType !== previewWindowType) {
            handleWindowChange('iframe');
        }
    }, [
        previewWindowType,
        isPopupOpen,
        handleWindowChange
    ]);
    useEffect(()=>{
        if (isFirstRender.current) {
            isFirstRender.current = false;
            return;
        }
        void setPreference(collectionSlug ? `collection-${collectionSlug}` : `global-${globalSlug}`, {
            editViewType: isLivePreviewing ? 'live-preview' : 'default'
        }, true);
    }, [
        isLivePreviewing,
        setPreference,
        collectionSlug,
        globalSlug
    ]);
    const dndContextID = useId();
    return /*#__PURE__*/ _jsxDEV(LivePreviewContext, {
        value: {
            appIsReady,
            breakpoint,
            breakpoints,
            iframeRef,
            isLivePreviewEnabled,
            isLivePreviewing,
            isPopupOpen,
            isPreviewEnabled,
            listeningForMessages,
            loadedURL,
            measuredDeviceSize,
            openPopupWindow,
            popupRef,
            previewURL,
            previewWindowType,
            setAppIsReady,
            setBreakpoint,
            setHeight,
            setIsLivePreviewing,
            setLoadedURL,
            setMeasuredDeviceSize,
            setPreviewURL,
            setPreviewWindowType: handleWindowChange,
            setSize,
            setToolbarPosition: setPosition,
            setURL: setLivePreviewURL,
            setWidth,
            setZoom,
            size,
            toolbarPosition: position,
            typeofLivePreviewURL,
            url,
            zoom
        },
        children: /*#__PURE__*/ _jsxDEV(DndContext, {
            collisionDetection: customCollisionDetection,
            // Provide stable ID to fix hydration issues: https://github.com/clauderic/dnd-kit/issues/926
            id: dndContextID,
            onDragEnd: handleDragEnd,
            children: children
        }, void 0, false, {
            fileName: "src/providers/LivePreview/index.tsx",
            lineNumber: 291,
            columnNumber: 7
        }, this)
    }, void 0, false, {
        fileName: "src/providers/LivePreview/index.tsx",
        lineNumber: 254,
        columnNumber: 5
    }, this);
};

//# sourceMappingURL=index.js.map