"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const jsx_runtime_1 = require("react/jsx-runtime");
const lexical_1 = require("lexical");
const link_1 = require("@lexical/link");
const list_1 = require("@lexical/list");
const LexicalComposerContext_1 = require("@lexical/react/LexicalComposerContext");
const LexicalDecoratorBlockNode_1 = require("@lexical/react/LexicalDecoratorBlockNode");
const rich_text_1 = require("@lexical/rich-text");
const selection_1 = require("@lexical/selection");
const table_1 = require("@lexical/table");
const utils_1 = require("@lexical/utils");
const React = tslib_1.__importStar(require("react"));
const react_1 = require("react");
const editor_1 = require("../../../utils/editor");
const material_1 = require("@mui/material");
const react_intl_1 = require("react-intl");
const styles_1 = require("@mui/material/styles");
const system_1 = require("@mui/system");
const ImagePlugin_1 = tslib_1.__importDefault(require("./ImagePlugin"));
const EmojiPlugin_1 = tslib_1.__importDefault(require("./EmojiPlugin"));
const LexicalHorizontalRuleNode_1 = require("@lexical/react/LexicalHorizontalRuleNode");
const constants_1 = require("../constants");
const blockTypeToBlockIcon = {
    h1: 'format_heading_1',
    h2: 'format_heading_2',
    h3: 'format_heading_3',
    bullet: 'format_list_bulleted',
    number: 'format_list_numbered',
    quote: 'format_quote',
    paragraph: 'format_paragraph'
};
const rootTypeToRootName = {
    root: 'Root',
    table: 'Table'
};
const FORMATS = ['bold', 'underline', 'italic', 'strikethrough', 'subscript', 'superscript'];
const ALIGNMENTS = ['left', 'right', 'center', 'justify'];
function BlockFormatIconButton({ className = '', editor, blockType, disabled = false }) {
    // STATE
    const [anchorEl, setAnchorEl] = React.useState(null);
    // FORMAT METHODS
    const formatParagraph = () => {
        editor.update(() => {
            const selection = (0, lexical_1.$getSelection)();
            if ((0, lexical_1.$isRangeSelection)(selection) || (0, table_1.$isTableSelection)(selection)) {
                (0, selection_1.$setBlocksType)(selection, () => (0, lexical_1.$createParagraphNode)());
            }
        });
    };
    const formatHeading = (headingSize) => {
        if (blockType !== headingSize) {
            editor.update(() => {
                const selection = (0, lexical_1.$getSelection)();
                if ((0, lexical_1.$isRangeSelection)(selection) || (0, table_1.$isTableSelection)(selection)) {
                    (0, selection_1.$setBlocksType)(selection, () => (0, rich_text_1.$createHeadingNode)(headingSize));
                }
            });
        }
    };
    const formatBulletList = () => {
        if (blockType !== 'bullet') {
            editor.dispatchCommand(list_1.INSERT_UNORDERED_LIST_COMMAND, undefined);
        }
        else {
            editor.dispatchCommand(list_1.REMOVE_LIST_COMMAND, undefined);
        }
    };
    const formatNumberedList = () => {
        if (blockType !== 'number') {
            editor.dispatchCommand(list_1.INSERT_ORDERED_LIST_COMMAND, undefined);
        }
        else {
            editor.dispatchCommand(list_1.REMOVE_LIST_COMMAND, undefined);
        }
    };
    const formatQuote = () => {
        if (blockType !== 'quote') {
            editor.update(() => {
                const selection = (0, lexical_1.$getSelection)();
                if ((0, lexical_1.$isRangeSelection)(selection) || (0, table_1.$isTableSelection)(selection)) {
                    (0, selection_1.$setBlocksType)(selection, () => (0, rich_text_1.$createQuoteNode)());
                }
            });
        }
    };
    // HANDLERS
    const handleSelect = (block) => (event) => {
        switch (block) {
            case 'bullet':
                formatBulletList();
                break;
            case 'number':
                formatNumberedList();
                break;
            case 'paragraph':
                formatParagraph();
                break;
            case 'quote':
                formatQuote();
                break;
            default:
                formatHeading(block);
                break;
        }
        setAnchorEl(null);
    };
    const handleOpen = (event) => {
        setAnchorEl(event.currentTarget);
    };
    const handleClose = () => {
        setAnchorEl(null);
    };
    return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ className: className, disabled: disabled, onClick: handleOpen }, { children: (0, jsx_runtime_1.jsx)(material_1.Tooltip, Object.assign({ title: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.editor.toolbarPlugin.blockType", defaultMessage: "ui.editor.toolbarPlugin.blockType" }) }, { children: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(material_1.Icon, { children: blockTypeToBlockIcon[blockType] }), (0, jsx_runtime_1.jsx)(material_1.Icon, { children: anchorEl ? 'expand_less' : 'expand_more' })] }) })) })), (0, jsx_runtime_1.jsx)(material_1.Menu, Object.assign({ anchorEl: anchorEl, open: Boolean(anchorEl), onClose: handleClose }, { children: Object.keys(blockTypeToBlockIcon).map((block) => ((0, jsx_runtime_1.jsx)(material_1.MenuItem, Object.assign({ onClick: handleSelect(block) }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: blockTypeToBlockIcon[block] }) }), block))) }))] }));
}
const classes = {
    root: `${constants_1.PREFIX}-toolbar-plugin-root`,
    blockFormat: `${constants_1.PREFIX}-block-format`
};
const Root = (0, styles_1.styled)(material_1.Box, {
    name: constants_1.PREFIX,
    slot: 'ToolbarPluginRoot'
})(() => ({}));
function ToolbarPlugin(inProps) {
    // PROPS
    const props = (0, system_1.useThemeProps)({
        props: inProps,
        name: constants_1.PREFIX
    });
    const { uploadImage = false } = props;
    // STATE
    const [editor] = (0, LexicalComposerContext_1.useLexicalComposerContext)();
    const [activeEditor, setActiveEditor] = (0, react_1.useState)(editor);
    const [blockType, setBlockType] = (0, react_1.useState)('paragraph');
    const [rootType, setRootType] = (0, react_1.useState)('root');
    const [selectedElementKey, setSelectedElementKey] = (0, react_1.useState)(null);
    const [isLink, setIsLink] = (0, react_1.useState)(false);
    const [isEditable, setIsEditable] = (0, react_1.useState)(() => editor.isEditable());
    const [formats, setFormats] = (0, react_1.useState)([]);
    const [alignment, setAlignment] = (0, react_1.useState)(ALIGNMENTS[0]);
    const $updateToolbar = (0, react_1.useCallback)(() => {
        const selection = (0, lexical_1.$getSelection)();
        if ((0, lexical_1.$isRangeSelection)(selection)) {
            const anchorNode = selection.anchor.getNode();
            let element = anchorNode.getKey() === 'root'
                ? anchorNode
                : (0, utils_1.$findMatchingParent)(anchorNode, (e) => {
                    const parent = e.getParent();
                    return parent !== null && (0, lexical_1.$isRootOrShadowRoot)(parent);
                });
            if (element === null) {
                element = anchorNode.getTopLevelElementOrThrow();
            }
            const elementKey = element.getKey();
            const elementDOM = activeEditor.getElementByKey(elementKey);
            // Update text format
            setFormats(FORMATS.filter((f) => selection.hasFormat(f)));
            // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
            // @ts-ignore
            setAlignment(ALIGNMENTS.find((a) => element.getFormatType() === a) || ALIGNMENTS[0]);
            // Update links
            const node = (0, editor_1.getSelectedNode)(selection);
            const parent = node.getParent();
            if ((0, link_1.$isLinkNode)(parent) || (0, link_1.$isLinkNode)(node)) {
                setIsLink(true);
            }
            else {
                setIsLink(false);
            }
            const tableNode = (0, utils_1.$findMatchingParent)(node, table_1.$isTableNode);
            if ((0, table_1.$isTableNode)(tableNode)) {
                setRootType('table');
            }
            else {
                setRootType('root');
            }
            if (elementDOM !== null) {
                setSelectedElementKey(elementKey);
                if ((0, list_1.$isListNode)(element)) {
                    const parentList = (0, utils_1.$getNearestNodeOfType)(anchorNode, list_1.ListNode);
                    const type = parentList ? parentList.getListType() : element.getListType();
                    setBlockType(type);
                }
                else {
                    // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
                    // @ts-ignore
                    const type = (0, rich_text_1.$isHeadingNode)(element) ? element.getTag() : element.getType();
                    if (type in blockTypeToBlockIcon) {
                        setBlockType(type);
                    }
                }
            }
        }
    }, [activeEditor]);
    (0, react_1.useEffect)(() => {
        return editor.registerCommand(lexical_1.SELECTION_CHANGE_COMMAND, (_payload, newEditor) => {
            $updateToolbar();
            setActiveEditor(newEditor);
            return false;
        }, lexical_1.COMMAND_PRIORITY_CRITICAL);
    }, [editor, $updateToolbar]);
    (0, react_1.useEffect)(() => {
        return (0, utils_1.mergeRegister)(editor.registerEditableListener((editable) => {
            setIsEditable(editable);
        }), activeEditor.registerUpdateListener(({ editorState }) => {
            editorState.read(() => {
                $updateToolbar();
            });
        }));
    }, [$updateToolbar, activeEditor, editor]);
    const clearFormatting = (0, react_1.useCallback)(() => {
        activeEditor.update(() => {
            const selection = (0, lexical_1.$getSelection)();
            if ((0, lexical_1.$isRangeSelection)(selection)) {
                const anchor = selection.anchor;
                const focus = selection.focus;
                const nodes = selection.getNodes();
                if (anchor.key === focus.key && anchor.offset === focus.offset) {
                    return;
                }
                nodes.forEach((node, idx) => {
                    // We split the first and last node by the selection
                    // So that we don't format unselected text inside those nodes
                    if ((0, lexical_1.$isTextNode)(node)) {
                        if (idx === 0 && anchor.offset !== 0) {
                            node = node.splitText(anchor.offset)[1] || node;
                        }
                        if (idx === nodes.length - 1) {
                            // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
                            // @ts-ignore
                            node = node.splitText(focus.offset)[0] || node;
                        }
                        // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
                        // @ts-ignore
                        if (node.__style !== '') {
                            // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
                            // @ts-ignore
                            node.setStyle('');
                        }
                        // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
                        // @ts-ignore
                        if (node.__format !== 0) {
                            // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
                            // @ts-ignore
                            node.setFormat(0);
                            (0, utils_1.$getNearestBlockElementAncestorOrThrow)(node).setFormat('');
                        }
                    }
                    else if ((0, rich_text_1.$isHeadingNode)(node) || (0, rich_text_1.$isQuoteNode)(node)) {
                        node.replace((0, lexical_1.$createParagraphNode)(), true);
                    }
                    else if ((0, LexicalDecoratorBlockNode_1.$isDecoratorBlockNode)(node)) {
                        node.setFormat('');
                    }
                });
            }
        });
    }, [activeEditor]);
    const insertLink = (0, react_1.useCallback)(() => {
        if (!isLink) {
            editor.dispatchCommand(link_1.TOGGLE_LINK_COMMAND, 'https://');
        }
        else {
            editor.dispatchCommand(link_1.TOGGLE_LINK_COMMAND, null);
        }
    }, [editor, isLink]);
    return ((0, jsx_runtime_1.jsxs)(Root, Object.assign({ className: classes.root }, { children: [blockType in blockTypeToBlockIcon && activeEditor === editor && ((0, jsx_runtime_1.jsx)(BlockFormatIconButton, { className: classes.blockFormat, disabled: !isEditable, blockType: blockType, editor: editor })), (0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ disabled: !isEditable, onClick: () => {
                    activeEditor.dispatchCommand(lexical_1.FORMAT_ELEMENT_COMMAND, ALIGNMENTS[(ALIGNMENTS.findIndex((a) => alignment === a) + 1) % ALIGNMENTS.length]);
                } }, { children: (0, jsx_runtime_1.jsx)(material_1.Tooltip, Object.assign({ title: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: `ui.editor.toolbarPlugin.${alignment}`, defaultMessage: `ui.editor.toolbarPlugin.${alignment}` }) }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: `format_align_${alignment}` }) })) })), (0, jsx_runtime_1.jsx)(material_1.ToggleButtonGroup, Object.assign({ value: formats }, { children: FORMATS.map((format) => ((0, jsx_runtime_1.jsx)(material_1.ToggleButton, Object.assign({ value: format, disabled: !isEditable, onClick: () => {
                        activeEditor.dispatchCommand(lexical_1.FORMAT_TEXT_COMMAND, format);
                    } }, { children: (0, jsx_runtime_1.jsx)(material_1.Tooltip, Object.assign({ title: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: `ui.editor.toolbarPlugin.${format}`, defaultMessage: `ui.editor.toolbarPlugin.${format}` }) }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: `format_${format}` }) })) }), format))) })), (0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ disabled: !isEditable, onClick: clearFormatting }, { children: (0, jsx_runtime_1.jsx)(material_1.Tooltip, Object.assign({ title: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.editor.toolbarPlugin.clear", defaultMessage: "ui.editor.toolbarPlugin.clear" }) }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "format_clear" }) })) })), (0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ disabled: !isEditable, onClick: () => {
                    activeEditor.dispatchCommand(LexicalHorizontalRuleNode_1.INSERT_HORIZONTAL_RULE_COMMAND, undefined);
                } }, { children: (0, jsx_runtime_1.jsx)(material_1.Tooltip, Object.assign({ title: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.editor.toolbarPlugin.horizontalRule", defaultMessage: "ui.editor.toolbarPlugin.horizontalRule" }) }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "format_horizontal_rule" }) })) })), uploadImage && (0, jsx_runtime_1.jsx)(ImagePlugin_1.default, {}), (0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ disabled: !isEditable, onClick: insertLink }, { children: (0, jsx_runtime_1.jsx)(material_1.Tooltip, Object.assign({ title: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.editor.toolbarPlugin.link", defaultMessage: "ui.editor.toolbarPlugin.link" }) }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "format_link" }) })) })), (0, jsx_runtime_1.jsx)(EmojiPlugin_1.default, {})] })));
}
exports.default = ToolbarPlugin;
