Skip to content

Add opt-in scoped hotkeys - #1377

Open
captbaritone wants to merge 3 commits into
masterfrom
scoped-hotkeys
Open

captbaritone wants to merge 3 commits into
masterfrom
scoped-hotkeys

Conversation

@captbaritone

@captbaritone captbaritone commented Oct 12, 2026 •

Copy link
Copy Markdown
Owner

enableHotkeys: true installs a document-level keydown listener. On a page with its own keyboard interactions, that means Webamp intercepts keys like X, C, V and the arrow keys everywhere, so an embedder in that situation can't turn hotkeys on.

This adds a scoped mode:

new Webamp({ enableHotkeys: "scoped" });
Value Behavior
true Hotkeys are handled anywhere in the page (unchanged).
"scoped" Hotkeys are only handled while focus is within Webamp.
false / omitted Hotkeys are disabled (unchanged default).

Implementation

  • bindHotkeys(dispatch, target = document) takes an optional element to listen on.
  • App now binds hotkeys for both modes. It listens on document for true and on Webamp's root DOM node (#webamp) for "scoped". Keys pressed inside Webamp bubble to the root node, and keys pressed elsewhere never reach it.
  • The constructor no longer binds hotkeys. They're unbound when the React root unmounts, which dispose() triggers.

Behavior change for enableHotkeys: true: hotkeys now start working once Webamp renders, instead of as soon as it's constructed. Previously they also worked while the skin was loading, and on instances that were never rendered.

API shape: I extended enableHotkeys to boolean | "scoped" rather than adding a separate option such as hotkeys: "scoped" | "global" | false. That keeps it backward compatible and avoids two options that overlap. Happy to switch if you'd prefer a new option.

Docs are updated in the constructor options and hotkeys pages.

Testing

  • New hotkeys.test.ts covers:
    • document-wide by default
    • only events within the target when one is given
    • unbinding stops handling
  • tsc, eslint, prettier --check and vitest run pass locally.

@netlify

netlify Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for tourmaline-kringle-c98715 ready!

Name Link
🔨 Latest commit e69098c
🔍 Latest deploy log https://app.netlify.com/projects/tourmaline-kringle-c98715/deploys/6ad10b52d8d01a7c22014a21
😎 Deploy Preview https://deploy-preview-1377--tourmaline-kringle-c98715.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions

github-actions Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Size Change: +29 B (+0.01%)

Total Size: 490 kB

📦 View Changed
Filename Size Change
packages/webamp/built/webamp.bundle.min.js 298 kB +55 B (+0.02%)
packages/webamp/built/webamp.lazy-bundle.min.js 192 kB -26 B (-0.01%)

compressed-size-action

@captbaritone
captbaritone force-pushed the scoped-hotkeys branch 3 times, most recently from 05cfd28 to 948a764 Compare October 15, 2026 17:00
enableHotkeys now also accepts "scoped", which only handles hotkeys while
focus is within Webamp. This lets embedders with their own keyboard
interactions enable hotkeys without Webamp intercepting keys page-wide.

Scoped hotkeys attach the existing hotkey listener to Webamp's root DOM node
instead of the document. enableHotkeys: true behaves exactly as before.
Rather than binding global hotkeys in the constructor and scoped hotkeys in
<App>, bind both in <App>, choosing the document or Webamp's DOM node as the
target. Hotkeys are unbound when the React root unmounts (on dispose()).

This means enableHotkeys: true now takes effect once Webamp renders rather
than when it is constructed.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant