Skip to main content

Focus

Focus handling keeps canvas keyboard shortcuts from stealing keystrokes meant for a text field. Whenever the user is typing into an <input>, <textarea>, <select>, or any contenteditable host, global handlers must stand down.

isEditableTargetโ€‹

isEditableTarget returns true when the given node is an <input>, <textarea>, <select>, or contenteditable element. It is exported from both @oh-just-another/editor and @oh-just-another/state. Note it checks exactly the node you pass โ€” inside a shadow root, resolve the real focused node first with event.composedPath()[0] (where event.target would be retargeted to the host), which is what bindEditorHotkeys does internally.

import { isEditableTarget } from "@oh-just-another/editor";

window.addEventListener("keydown", (ev) => {
if (isEditableTarget(ev.target)) return; // user is typing โ€” leave it alone
// ... canvas shortcut handling
});

Built into hotkey bindingโ€‹

bindEditorHotkeys already applies this check for you: keystrokes aimed at an editable target are left alone, with one exception โ€” Escape still passes through, blurring the field first.

import { bindEditorHotkeys } from "@oh-just-another/editor";

const unbind = bindEditorHotkeys(editor); // listens on window by default
// later: unbind();

Scope shortcuts to a specific element (useful when several editors share a page, or the editor lives in a shadow root) via the target option:

bindEditorHotkeys(editor, { target: editor.hostElement });

So for the common case you never call isEditableTarget directly โ€” it is the guard that makes canvas hotkeys coexist with text editing.