"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.$isImageNode = exports.$createImageNode = exports.ImageNode = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const lexical_1 = require("lexical");
const LexicalComposerContext_1 = require("@lexical/react/LexicalComposerContext");
const useLexicalNodeSelection_1 = require("@lexical/react/useLexicalNodeSelection");
const utils_1 = require("@lexical/utils");
const imageCache = new Set();
function useSuspenseImage(src) {
    if (!imageCache.has(src)) {
        throw new Promise((resolve) => {
            const img = new Image();
            img.src = src;
            img.onload = () => {
                imageCache.add(src);
                resolve();
            };
        });
    }
}
function LazyImage({ altText, className, imageRef, src, width, height, maxWidth }) {
    useSuspenseImage(src);
    return ((0, jsx_runtime_1.jsx)("img", { className: className, src: src, alt: altText, ref: imageRef, style: {
            height: `${height}${height === 'inherit' ? '' : 'px'}`,
            maxWidth,
            width: `${width}${width === 'inherit' ? '' : 'px'}`
        } }));
}
function ImageComponent({ src, altText, nodeKey, maxWidth }) {
    const imageRef = (0, react_1.useRef)(null);
    const buttonRef = (0, react_1.useRef)(null);
    const [isSelected, setSelected, clearSelection] = (0, useLexicalNodeSelection_1.useLexicalNodeSelection)(nodeKey);
    const [editor] = (0, LexicalComposerContext_1.useLexicalComposerContext)();
    const activeEditorRef = (0, react_1.useRef)(null);
    const onDelete = (0, react_1.useCallback)((payload) => {
        if (isSelected && (0, lexical_1.$isNodeSelection)((0, lexical_1.$getSelection)())) {
            const event = payload;
            event.preventDefault();
            const node = (0, lexical_1.$getNodeByKey)(nodeKey);
            if ($isImageNode(node)) {
                node.remove();
            }
            setSelected(false);
        }
        return false;
    }, [isSelected, nodeKey, setSelected]);
    const onEnter = (0, react_1.useCallback)((event) => {
        const latestSelection = (0, lexical_1.$getSelection)();
        const buttonElem = buttonRef.current;
        if (isSelected && (0, lexical_1.$isNodeSelection)(latestSelection) && latestSelection.getNodes().length === 1) {
            if (buttonElem !== null && buttonElem !== document.activeElement) {
                event.preventDefault();
                buttonElem.focus();
                return true;
            }
        }
        return false;
    }, [isSelected]);
    const onEscape = (0, react_1.useCallback)((event) => {
        if (buttonRef.current === event.target) {
            (0, lexical_1.$setSelection)(null);
            editor.update(() => {
                setSelected(true);
                const parentRootElement = editor.getRootElement();
                if (parentRootElement !== null) {
                    parentRootElement.focus();
                }
            });
            return true;
        }
        return false;
    }, [editor, setSelected]);
    (0, react_1.useEffect)(() => {
        const unregister = (0, utils_1.mergeRegister)(editor.registerCommand(lexical_1.SELECTION_CHANGE_COMMAND, (_, activeEditor) => {
            activeEditorRef.current = activeEditor;
            return false;
        }, lexical_1.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical_1.CLICK_COMMAND, (payload) => {
            const event = payload;
            if (event.target === imageRef.current) {
                if (event.shiftKey) {
                    setSelected(!isSelected);
                }
                else {
                    clearSelection();
                    setSelected(true);
                }
                return true;
            }
            return false;
        }, lexical_1.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical_1.KEY_DELETE_COMMAND, onDelete, lexical_1.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical_1.KEY_BACKSPACE_COMMAND, onDelete, lexical_1.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical_1.KEY_ENTER_COMMAND, onEnter, lexical_1.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical_1.KEY_ESCAPE_COMMAND, onEscape, lexical_1.COMMAND_PRIORITY_LOW));
        return () => {
            unregister();
        };
    }, [clearSelection, editor, isSelected, nodeKey, onDelete, onEnter, onEscape, setSelected]);
    return ((0, jsx_runtime_1.jsx)(react_1.Suspense, Object.assign({ fallback: null }, { children: (0, jsx_runtime_1.jsx)(LazyImage, { className: isSelected ? `selected` : null, src: src, altText: altText, imageRef: imageRef, maxWidth: maxWidth }) })));
}
function convertImageElement(domNode) {
    if (domNode instanceof HTMLImageElement) {
        const { alt: altText, src } = domNode;
        const node = $createImageNode({ altText, src, maxWidth: '100%' });
        return { node };
    }
    return null;
}
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
class ImageNode extends lexical_1.DecoratorNode {
    constructor(src, altText, maxWidth, key) {
        super(key);
        this.__src = src;
        this.__altText = altText;
        this.__maxWidth = maxWidth;
    }
    static getType() {
        return 'image';
    }
    static clone(node) {
        return new ImageNode(node.__src, node.__altText, node.__maxWidth, node.__key);
    }
    setWidthAndHeight(width, height) {
        const writable = this.getWritable();
        // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
        // @ts-ignore
        writable.__width = width;
        // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
        // @ts-ignore
        writable.__height = height;
    }
    // View
    createDOM(config) {
        const div = document.createElement('div');
        const theme = config.theme;
        const className = theme.image;
        if (className !== undefined) {
            div.className = className;
        }
        return div;
    }
    updateDOM() {
        return false;
    }
    static importDOM() {
        // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
        // @ts-ignore
        const dom = lexical_1.TextNode.importDOM();
        return Object.assign({ img: (node) => ({
                conversion: convertImageElement,
                priority: 0
            }) }, dom);
    }
    exportDOM() {
        const element = document.createElement('img');
        element.setAttribute('src', this.__src);
        element.setAttribute('alt', this.__altText);
        element.setAttribute('style', `max-width: ${this.__maxWidth}px;`);
        return { element };
    }
    decorate() {
        return (0, jsx_runtime_1.jsx)(ImageComponent, { src: this.__src, altText: this.__altText, maxWidth: this.__maxWidth, nodeKey: this.getKey() });
    }
    static importJSON(serializedNode) {
        const { altText, maxWidth, src } = serializedNode;
        const node = $createImageNode({
            altText,
            src,
            maxWidth
        });
        return node;
    }
    exportJSON() {
        return {
            // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
            // @ts-ignore
            altText: this.getAltText(),
            maxWidth: this.__maxWidth,
            // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
            // @ts-ignore
            src: this.getSrc(),
            type: 'image',
            version: 1
        };
    }
}
exports.ImageNode = ImageNode;
function $createImageNode({ src, altText, maxWidth }) {
    return new ImageNode(src, altText, maxWidth);
}
exports.$createImageNode = $createImageNode;
function $isImageNode(node) {
    return node.getType() === 'image';
}
exports.$isImageNode = $isImageNode;
