Added IconsHelper and updated Keyboard to support require_inside flag

This commit is contained in:
2026-02-20 20:35:09 +01:00
parent b09763b1eb
commit 13f292fc9d
12 changed files with 219 additions and 76 deletions

View File

@@ -21,19 +21,47 @@
## Key Features
### Multiple Simultaneous Triggers
### Scope Control with `require_inside`
**IMPORTANT**: If multiple elements listen to the same combination, **ALL** of them will be triggered:
Each combination can declare whether it should only trigger when the focus is **inside** the registered element, or fire **globally** regardless of focus.
| `require_inside` | Behavior |
|-----------------|----------|
| `true` (default) | Triggers only if focus is inside the element or one of its children |
| `false` | Triggers regardless of where the focus is (global shortcut) |
```javascript
add_keyboard_support('modal', '{"esc": "/close-modal"}');
add_keyboard_support('editor', '{"esc": "/cancel-edit"}');
add_keyboard_support('sidebar', '{"esc": "/hide-sidebar"}');
// Only fires when focus is inside #tree-panel
add_keyboard_support('tree-panel', '{"esc": {"hx-post": "/cancel", "require_inside": true}}');
// Pressing ESC will trigger all 3 URLs simultaneously
// Fires anywhere on the page
add_keyboard_support('app', '{"ctrl+n": {"hx-post": "/new", "require_inside": false}}');
```
This is crucial for use cases like the ESC key, which often needs to cancel multiple actions at once (close modal, cancel edit, hide panels, etc.).
**Python usage (`Keyboard` component):**
```python
# Default: require_inside=True — fires only when inside the element
Keyboard(self, _id="-kb").add("esc", self.commands.cancel())
# Explicit global shortcut
Keyboard(self, _id="-kb").add("ctrl+n", self.commands.new_item(), require_inside=False)
```
### Multiple Simultaneous Triggers
**IMPORTANT**: If multiple elements listen to the same combination, all of them whose `require_inside` condition is satisfied will be triggered simultaneously:
```javascript
add_keyboard_support('modal', '{"esc": {"hx-post": "/close-modal", "require_inside": true}}');
add_keyboard_support('editor', '{"esc": {"hx-post": "/cancel-edit", "require_inside": true}}');
add_keyboard_support('sidebar', '{"esc": {"hx-post": "/hide-sidebar", "require_inside": false}}');
// Pressing ESC while focus is inside 'editor':
// - 'modal' → skipped (require_inside: true, focus not inside)
// - 'editor' → triggered ✓
// - 'sidebar' → triggered ✓ (require_inside: false)
```
### Smart Timeout Logic (Longest Match)
@@ -232,6 +260,8 @@ The library automatically adds these parameters to every request:
- `has_focus` - Boolean indicating if the element had focus
- `is_inside` - Boolean indicating if the focus is inside the element (element itself or any child)
Note: `require_inside` controls **whether** the action fires; `is_inside` is an informational parameter sent **with** the request after it fires.
Example final request:
```javascript
htmx.ajax('POST', '/save-url', {