"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = FontSize;
const tslib_1 = require("tslib");
const list_1 = require("@lexical/list");
const utils_1 = require("@lexical/utils");
const lexical_1 = require("lexical");
const react_1 = tslib_1.__importStar(require("react"));
const selection_1 = require("@lexical/selection");
const heading_1 = require("./heading");
/**
 * Finds the list item that owns a node.
 * @param node Node inside or equal to a list item.
 * @returns Matching list item, or null when the node is not in a list item.
 */
function getListItemNode(node) {
    return (0, list_1.$isListItemNode)(node) ? node : (0, utils_1.$findMatchingParent)(node, (parent) => (0, list_1.$isListItemNode)(parent));
}
/**
 * Gets selected list items from the current range.
 * @param selection Current range selection.
 * @returns Unique list item nodes touched by the selection.
 */
function getSelectedListItems(selection) {
    const listItemNodes = new Set();
    const selectedNodes = [selection.anchor.getNode(), selection.focus.getNode(), ...selection.getNodes()];
    for (const node of selectedNodes) {
        const listItemNode = getListItemNode(node);
        if (listItemNode !== null) {
            listItemNodes.add(listItemNode);
        }
    }
    return listItemNodes;
}
/**
 * Reads heading metadata from selected list items.
 * @param selection Current range selection.
 * @returns Selected list heading tag, or null when the selection is normal list text.
 */
function getSelectedListHeadingTag(selection) {
    for (const listItemNode of getSelectedListItems(selection)) {
        const headingTag = (0, heading_1.getListItemHeadingTag)(listItemNode);
        if (headingTag !== null) {
            return headingTag;
        }
    }
    return null;
}
/**
 * Applies font size to selected list items and their marker style.
 * @param listItemNodes List items touched by the selection.
 * @param fontSize Font size to apply.
 * @param headingTag Heading type to preserve, or null for normal list text.
 * @param shouldApplyMarkerStyle True when the list marker should receive the selected size.
 */
function applyListItemFontSize(listItemNodes, fontSize, headingTag, shouldApplyMarkerStyle) {
    for (const listItemNode of listItemNodes) {
        (0, heading_1.setListItemHeadingTag)(listItemNode.getKey(), headingTag);
        if (!shouldApplyMarkerStyle) {
            continue;
        }
        const listItemStyle = {
            ...(0, selection_1.getStyleObjectFromCSS)(listItemNode.getTextStyle()),
            'font-size': fontSize,
        };
        if (headingTag === null) {
            delete listItemStyle['--phx-list-heading'];
        }
        else {
            listItemStyle['--phx-list-heading'] = headingTag;
        }
        listItemNode.setTextStyle((0, selection_1.getCSSFromStyleObject)(listItemStyle));
    }
}
/**
 * Gets the active range selection, restoring the previous range when toolbar focus cleared it.
 * @returns Current or restored range selection, or a root-end selection as a final fallback.
 */
function getActiveRangeSelection() {
    const selection = (0, lexical_1.$getSelection)();
    if ((0, lexical_1.$isRangeSelection)(selection)) {
        return selection;
    }
    const previousSelection = (0, lexical_1.$getPreviousSelection)();
    if ((0, lexical_1.$isRangeSelection)(previousSelection)) {
        const restoredSelection = previousSelection.clone();
        (0, lexical_1.$setSelection)(restoredSelection);
        return restoredSelection;
    }
    return (0, lexical_1.$getRoot)().selectEnd();
}
/**
 * Renders controls for applying inline font size to the current selection.
 * @param props Font size control props.
 * @param props.fontSize Current selected font size.
 * @param props.editor Active Lexical editor.
 * @param props.listHeadingTag Current list heading type that should survive font-size changes.
 * @returns Font size toolbar controls.
 */
function FontSize({ fontSize, editor, listHeadingTag, }) {
    const FONT_SIZES = [
        12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 36, 40, 44, 48, 52, 56, 60, 64, 72,
        80, 96,
    ];
    const minFontSize = FONT_SIZES[0];
    const maxFontSize = FONT_SIZES[FONT_SIZES.length - 1];
    const hasFontSize = fontSize !== null;
    const disabledDecrease = !hasFontSize || fontSize <= minFontSize;
    const disabledIncrease = !hasFontSize || fontSize >= maxFontSize;
    const ref = (0, react_1.useRef)(null);
    const [showDropdown, setShowDropDown] = (0, react_1.useState)(false);
    const handleChangeSize = (nextSize) => {
        const nextFontSize = `${nextSize}px`;
        editor.update(() => {
            const rangeSelection = getActiveRangeSelection();
            const selectedListItems = getSelectedListItems(rangeSelection);
            const selectedListHeadingTag = listHeadingTag !== null && listHeadingTag !== void 0 ? listHeadingTag : getSelectedListHeadingTag(rangeSelection);
            (0, selection_1.$patchStyleText)(rangeSelection, {
                'font-size': nextFontSize,
            });
            if (selectedListItems.size > 0) {
                applyListItemFontSize(selectedListItems, nextFontSize, selectedListHeadingTag, !rangeSelection.isCollapsed());
            }
            if (rangeSelection.isCollapsed()) {
                const anchorNode = rangeSelection.anchor.getNode();
                const targetNode = (0, lexical_1.$isElementNode)(anchorNode)
                    ? anchorNode
                    : (0, lexical_1.$isTextNode)(anchorNode)
                        ? anchorNode.getTopLevelElement()
                        : null;
                if ((0, lexical_1.$isElementNode)(targetNode) && targetNode.isEmpty()) {
                    const targetNodeKey = targetNode.getKey();
                    const styles = (0, selection_1.getStyleObjectFromCSS)(targetNode.getStyle());
                    targetNode.setStyle((0, selection_1.getCSSFromStyleObject)({
                        ...styles,
                        'font-size': nextFontSize,
                    }));
                    targetNode.setTextStyle((0, selection_1.getCSSFromStyleObject)({ 'font-size': nextFontSize }));
                    const applyFontSizeToTargetElement = () => {
                        const targetElement = editor.getElementByKey(targetNodeKey);
                        targetElement === null || targetElement === void 0 ? void 0 : targetElement.style.setProperty('font-size', nextFontSize);
                    };
                    if (typeof queueMicrotask === 'function') {
                        queueMicrotask(applyFontSizeToTargetElement);
                    }
                    requestAnimationFrame(applyFontSizeToTargetElement);
                }
            }
        });
        setShowDropDown(false);
        editor.focus();
    };
    const handleIncre = (value) => {
        if (!hasFontSize) {
            return;
        }
        const nextFontSize = fontSize + value;
        if (nextFontSize < minFontSize || nextFontSize > maxFontSize) {
            return;
        }
        handleChangeSize(nextFontSize);
    };
    (0, react_1.useEffect)(() => {
        function handleClickOutside(event) {
            if (!ref.current)
                return;
            if (!ref.current.contains(event.target)) {
                setShowDropDown(false);
            }
        }
        document.addEventListener('mousedown', handleClickOutside);
        return () => {
            document.removeEventListener('mousedown', handleClickOutside);
        };
    }, []);
    return (react_1.default.createElement("div", { ref: ref, className: 'relative flex' },
        showDropdown && (react_1.default.createElement("div", { className: 'absolute right-9 top-[110%] z-50 w-16 max-h-60 overflow-auto rounded-md border bg-white shadow' }, FONT_SIZES.map((size) => {
            return (react_1.default.createElement("button", { onMouseDown: (event) => event.preventDefault(), onClick: () => handleChangeSize(size), key: size, type: 'button', className: 'w-full px-2 py-1 text-left text-[12px] hover:bg-gray-100' },
                size,
                "px"));
        }))),
        react_1.default.createElement("div", { className: 'flex items-center gap-x-2' },
            react_1.default.createElement("button", { type: 'button', "data-color-button": 'true', disabled: disabledDecrease, className: `p-1 rounded-md duration-200 ${disabledDecrease ? 'cursor-not-allowed opacity-50' : 'cursor-pointer hover:bg-gray-200'}`, onMouseDown: (event) => event.preventDefault(), onClick: () => handleIncre(-1) },
                react_1.default.createElement("span", null,
                    react_1.default.createElement("svg", { width: '20', height: '20', viewBox: '0 0 20 20', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' },
                        react_1.default.createElement("path", { fillRule: 'evenodd', clipRule: 'evenodd', d: 'M6 10C6 9.58579 6.33579 9.25 6.75 9.25H13.25C13.6642 9.25 14 9.58579 14 10C14 10.4142 13.6642 10.75 13.25 10.75H6.75C6.33579 10.75 6 10.4142 6 10Z', fill: '#1F2937' }))))),
        react_1.default.createElement("div", { className: 'flex items-center gap-x-2' },
            react_1.default.createElement("div", { className: 'relative flex items-center' },
                react_1.default.createElement("button", { type: 'button', onMouseDown: (event) => event.preventDefault(), onClick: () => setShowDropDown((prev) => !prev), className: 'inline-flex h-5 w-10 items-center justify-center p-0 text-xs leading-5 text-center bg-transparent bg-white border border-gray-500 rounded-md focus:ring-0 focus:border-gray-500' }, fontSize !== null && fontSize !== void 0 ? fontSize : ''))),
        react_1.default.createElement("div", { className: 'flex items-center gap-x-2' },
            react_1.default.createElement("button", { type: 'button', "data-color-button": 'true', disabled: disabledIncrease, className: `p-1 rounded-md duration-200 ${disabledIncrease ? 'cursor-not-allowed opacity-50' : 'cursor-pointer hover:bg-gray-200'}`, onMouseDown: (event) => event.preventDefault(), onClick: () => handleIncre(1) },
                react_1.default.createElement("span", null,
                    react_1.default.createElement("svg", { width: '20', height: '20', viewBox: '0 0 20 20', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' },
                        react_1.default.createElement("path", { d: 'M10.75 6.75C10.75 6.33579 10.4142 6 10 6C9.58579 6 9.25 6.33579 9.25 6.75L9.25 9.25H6.75C6.33579 9.25 6 9.58579 6 10C6 10.4142 6.33579 10.75 6.75 10.75H9.25L9.25 13.25C9.25 13.6642 9.58579 14 10 14C10.4142 14 10.75 13.6642 10.75 13.25V10.75H13.25C13.6642 10.75 14 10.4142 14 10C14 9.58579 13.6642 9.25 13.25 9.25H10.75V6.75Z', fill: '#1F2937' })))),
            react_1.default.createElement("div", { className: 'w-[1px] h-5 bg-gray-300' }))));
}
//# sourceMappingURL=font-size.js.map