/**
 * Editor FORMATTING commands for compose menus.
 *
 * The clipboard half of these menus moved to components/edit-menu.ts, which
 * every menu in the app now shares — compose's editors, compose's recipient
 * fields, and each main-window surface. What stays here is what's specific to
 * a rich editor: bold/italic/link/clear, and the word-expansion they act on.
 *
 * These exist because mailx has THREE right-click menus over the same editor
 * and they kept drifting apart:
 *   - msger's native menu, with app items appended (compose.ts dispatches
 *     them through window.__msgerContextCommand)
 *   - the TinyMCE spell menu (spellcheck.ts)
 *   - the Quill spell menu (editor.ts)
 *
 * The spell menus call preventDefault and REPLACE the native menu, so a
 * right-click on a misspelled word — the single most likely right-click in a
 * draft — produced a menu with spelling actions and nothing else: no Cut, no
 * Copy, no Paste, no formatting (Bob 2026-08-07, "what happened to all the
 * previous menu options"). Taking over a menu means taking over ALL of it, so
 * the commands live here and every menu builds from the same set.
 *
 * Engine-agnostic: pass the underlying editor (TinyMCE Editor or Quill). The
 * TinyMCE and Quill paths differ enough that each command branches, but the
 * branching happens once, here, instead of in each menu.
 */
import { editMenuItems } from "../components/edit-menu.js";
function isTinyEditor(ne) {
    return !!ne && typeof ne.execCommand === "function" && !!ne.selection;
}
/** Expand a collapsed caret to the word under it, so "right-click a word →
 *  Copy" (or Bold) acts on that word rather than on nothing. Matches what the
 *  native-menu formatting items have always done. */
function expandToWord(ne) {
    if (isTinyEditor(ne)) {
        try {
            if (ne.selection.isCollapsed() && typeof ne.selection.expand === "function") {
                ne.selection.expand({ type: "word" });
            }
        }
        catch { /* older TinyMCE — command still applies at the caret */ }
        return;
    }
    if (ne && typeof ne.getSelection === "function" && typeof ne.setSelection === "function") {
        const sel = ne.getSelection();
        if (!sel || sel.length > 0)
            return;
        const text = ne.getText();
        let a = sel.index, b = sel.index;
        while (a > 0 && /\S/.test(text[a - 1]))
            a--;
        while (b < text.length && /\S/.test(text[b]))
            b++;
        if (b > a)
            ne.setSelection(a, b - a);
    }
}
/** Bold / Italic / Underline / Strikethrough / Link / Clear formatting, acting
 *  on the selection or, with a collapsed caret, the word under it. */
export function runFormatCommand(ne, id) {
    if (!ne)
        return;
    expandToWord(ne);
    if (isTinyEditor(ne)) {
        const cmd = {
            bold: "Bold", italic: "Italic", underline: "Underline",
            strike: "Strikethrough", link: "mceLink", clear: "RemoveFormat",
        };
        if (cmd[id])
            ne.execCommand(cmd[id]);
        return;
    }
    if (typeof ne.format !== "function" || typeof ne.getSelection !== "function")
        return;
    const sel = ne.getSelection();
    if (!sel || sel.length === 0)
        return;
    const cur = ne.getFormat(sel);
    switch (id) {
        case "bold":
            ne.format("bold", !cur.bold);
            break;
        case "italic":
            ne.format("italic", !cur.italic);
            break;
        case "underline":
            ne.format("underline", !cur.underline);
            break;
        case "strike":
            ne.format("strike", !cur.strike);
            break;
        case "clear":
            ne.removeFormat(sel.index, sel.length);
            break;
        // Quill's link dialog lives in its keyboard binding — Ctrl+K.
        case "link":
            try {
                ne.root.dispatchEvent(new KeyboardEvent("keydown", { key: "K", ctrlKey: true, bubbles: true, cancelable: true }));
            }
            catch { /* */ }
            break;
    }
}
/** The standard editing block appended to any menu that REPLACES the native
 *  one. `onError` reports a refused clipboard read rather than swallowing it.
 *  `showSource` is optional — only the TinyMCE path has a source dialog. */
export function standardEditItems(getEditor, opts = {}) {
    const fmt = (id) => () => runFormatCommand(getEditor(), id);
    // Clipboard block comes from the shared implementation — the same one the
    // main window's menus use, so the two can't drift apart again.
    const items = [
        { label: "", action: () => { }, separator: true },
        ...editMenuItems({ engine: getEditor() }, { onError: opts.onError }),
        { label: "", action: () => { }, separator: true },
        { label: "Bold", action: fmt("bold") },
        { label: "Italic", action: fmt("italic") },
        { label: "Underline", action: fmt("underline") },
        { label: "Strikethrough", action: fmt("strike") },
        { label: "Link…", action: fmt("link") },
        { label: "Clear formatting", action: fmt("clear") },
    ];
    if (opts.showSource) {
        items.push({ label: "", action: () => { }, separator: true });
        items.push({ label: "View HTML source…", action: opts.showSource });
    }
    return items;
}
//# sourceMappingURL=edit-commands.js.map