yuanqing / create-figma-plugin

:battery: The comprehensive toolkit for developing plugins and widgets for Figma and FigJam
https://yuanqing.github.io/create-figma-plugin/
MIT License
948 stars 91 forks source link

Improvement/recipe: Escape to close and undo support #129

Open airtable-JayRansijn opened 2 years ago

airtable-JayRansijn commented 2 years ago

I found this escape and undo handling pretty useful to enable for a plugin, possibly some utils to help could be nice, More info here: https://forum.figma.com/t/pass-shortcuts-to-figma-when-focused-on-the-plugin-window-and-vice-versa/10229/2

Types

export interface KeyActionHandler extends EventHandler {
    name: "KEY_ACTION";
    handler: (message: { action: 'Escape' | 'Undo' }) => void;
}

In UI code

useEffect(() => {
    // https://forum.figma.com/t/pass-shortcuts-to-figma-when-focused-on-the-plugin-window-and-vice-versa/10229/2
    function onKeyDown(e: KeyboardEvent) {
        if (e.key === "Escape") {
            // Close plugin when pressing Escape
            emit<KeyActionHandler>("KEY_ACTION", { action: "Escape" });
        } else if (e.key === "z" && !e.shiftKey && !e.altKey) {
            // Undo the action in Figma
            const isMac = navigator.userAgent.indexOf("Macintosh") >= 0;
            const isCmd = isMac && e.metaKey && !e.ctrlKey;
            const isCtrl = !isMac && !e.metaKey && e.ctrlKey;
            if (isCmd || isCtrl) {
                emit<KeyActionHandler>("KEY_ACTION", { action: "Undo" });
            }
        }
    }
    window.addEventListener("keydown", onKeyDown);
    return () => {
        window.removeEventListener("keydown", onKeyDown);
    };
}, []);

In plugin code

on<KeyActionHandler>(
    "KEY_ACTION",
    function onKeyAction(message) {
        switch (message.action) {
            case "Escape":
                figma.closePlugin()
                break
            case 'Undo':
                const currentSelection = figma.currentPage.selection;
                figma.triggerUndo()
                figma.currentPage.selection = currentSelection;
                break
        }
    }
);
airtable-JayRansijn commented 2 years ago

FIxed. One issue I am noticing is that it throws out the selection, perhaps it needs to save and reset the selection on trigger undo.