Keybindings#
The ngapp.keybindings module provides a reusable keybinding manager
with a floating mode indicator and a help overlay. It supports global
shortcuts, per-component bindings, two-level modal keys, and
visibility-based activation.
Quick start#
from ngapp.app import App
from ngapp.components import Div
from ngapp.keybindings import KeybindingManager, keybinding_styles
class MyApp(App):
def __init__(self):
super().__init__()
self.kb = KeybindingManager(self)
self.kb.add("h", self.kb.toggle_help, "Show shortcuts", "General")
self.add_keybinding("escape", lambda e: self.kb.on_escape())
# Include the indicator and overlay in your layout
super().__init__(
Div("Hello"),
self.kb.indicator,
self.kb.help_overlay,
)
keybinding_styles.inject(self)
Global bindings#
Use kb.add(key, callback, description, group) to register shortcuts
that are always active regardless of which component is visible:
kb.add("ctrl+s", self.save, "Save", "General")
kb.add("ctrl+b", self.toggle_sidebar, "Toggle sidebar", "Panels")
Component bindings (exclusive)#
If your app shows one main component at a time (e.g. tabs), use
kb.set_component(comp) to swap keybindings when the active view changes.
The component must implement get_keybindings():
class MyView:
def get_keybindings(self):
return {
"flat": [
("w", self.toggle_wireframe, "Toggle wireframe", "Display"),
],
"modes": [
("s", "Show", [
("e", self.toggle_edges, "Toggle edges"),
("v", self.toggle_volumes, "Toggle volumes"),
]),
],
}
Then in your app:
def on_tab_changed(self, comp):
self.kb.set_component(comp)
Component bindings (visibility-based)#
For apps where multiple panels can be visible simultaneously, use
activate_component / deactivate_component:
# When component becomes visible
self.kb.activate_component(panel)
# When component is hidden
self.kb.deactivate_component(panel)
Multiple components can be active at the same time. Their bindings are merged (last-activated wins on conflicts).
Modal keys (modes)#
Modes provide a two-level keybinding: pressing a trigger key (e.g. s)
enters a mode, showing a floating indicator with available sub-keys.
Pressing a sub-key executes the action and exits the mode. Escape
cancels.
Define modes in get_keybindings():
"modes": [
("s", "Show", [
("w", self.toggle_wireframe, "Toggle wireframe"),
("e", self.toggle_edges, "Toggle edges"),
]),
]
Custom theme#
Pass a Theme to customize the indicator/overlay colors:
from ngapp.style import Theme
from ngapp.keybindings import KeybindingManager
my_theme = Theme(accent="#FF6B35", hint="#94a3b8", muted="#666", border="#ddd")
kb = KeybindingManager(app, theme=my_theme)
API reference#
Reusable keybinding manager with floating indicator and help overlay.
Provides KeybindingManager — a two-layer (global + component)
keybinding dispatcher with a floating mode indicator and a help overlay
showing all registered shortcuts.
Usage:
from ngapp.keybindings import KeybindingManager
class MyApp(App):
def __init__(self):
super().__init__()
self.kb = KeybindingManager(self)
self.kb.add("h", self.kb.toggle_help, "Show shortcuts", "General")
self.add_keybinding("escape", lambda e: self.kb.on_escape())
- class ngapp.keybindings.HelpOverlay(manager)#
Floating overlay showing all registered keybindings.
- hide()#
- show()#
- class ngapp.keybindings.KeybindingManager(app, after_action=None, theme=None)#
Two-layer keybinding manager with floating indicator and help overlay.
Global bindings (
add) are always active. Component bindings come fromcomp.get_keybindings()and are swapped on everyset_component()call so only relevant shortcuts are shown.get_keybindings()returns:{ "flat": [(key, callback, description, group), ...], "modes": [(trigger_key, mode_name, [(key, cb, desc), ...]), ...], }
Parameters#
- appApp or Component
The app (or root component) that owns the keybindings. Must support
add_keybinding(key, callback).- after_actioncallable, optional
Called after every keybinding action (e.g. to refresh UI).
- themeTheme, optional
Custom theme tokens for the indicator colors.
- activate_component(comp)#
Activate a component’s keybindings (additive).
Call this when a component becomes visible. Multiple components can be active simultaneously. Use
deactivate_component()when the component is hidden.The component must implement
get_keybindings()returning:{"flat": [(key, cb, desc, group), ...], "modes": [(trigger, name, [(key, cb, desc), ...]), ...]}
- add(key, callback, description, group='General')#
Register a global keybinding (always active).
- deactivate_component(comp)#
Deactivate a component’s keybindings.
Call this when a component becomes hidden.
- property entries#
- on_escape()#
- set_component(comp)#
Swap component bindings (exclusive). Only these + global are active.
This deactivates all previously active components and activates only the given one. Use
activate_component()/deactivate_component()for non-exclusive visibility-based activation.
- toggle_help()#