|
| 1 | +# Shortcuts Plugin |
| 2 | + |
| 3 | +## Purpose |
| 4 | + |
| 5 | +`@editorjs/shortcuts-plugin` is a built-in `EditorjsPlugin` that maps keyboard shortcuts declared in a tool's `options.shortcut` to inline-tool application through the `EditorAPI`. It subscribes to tool-loaded events to collect shortcuts and to delegated keydown events to dispatch them. |
| 6 | + |
| 7 | +## Requirements |
| 8 | + |
| 9 | +### Requirement: Keyboard shortcuts plugin |
| 10 | +The system SHALL provide a `ShortcutsPlugin` (an `EditorjsPlugin`) that, on construction, subscribes to the `core:tool:loaded` and `ui:key-down` events, registers each loaded tool's string `options.shortcut`, and applies the matching inline tool to the current selection via the `EditorAPI` when its shortcut is pressed. |
| 11 | + |
| 12 | +#### Scenario: Registering a shortcut from a loaded tool |
| 13 | +- **GIVEN** a tool is loaded whose merged `options.shortcut` is a string (e.g. `CMD+B`) |
| 14 | +- **WHEN** the `core:tool:loaded` event fires |
| 15 | +- **THEN** the plugin registers a mapping from that shortcut string to the tool's name |
| 16 | + |
| 17 | +#### Scenario: Ignoring tools without a string shortcut |
| 18 | +- **GIVEN** a tool is loaded whose `options.shortcut` is absent or is not a string |
| 19 | +- **WHEN** the `core:tool:loaded` event fires |
| 20 | +- **THEN** the plugin registers no shortcut for that tool |
| 21 | + |
| 22 | +#### Scenario: Triggering an inline tool via shortcut |
| 23 | +- **GIVEN** an inline tool is registered with `options.shortcut` set to a key combination (e.g. `CMD+B`) |
| 24 | +- **WHEN** that key combination is pressed while the editor has focus |
| 25 | +- **THEN** the plugin prevents the native event's default action and applies the corresponding inline tool to the current selection via `api.selection.applyInlineTool` |
| 26 | + |
| 27 | +#### Scenario: Matching only the first registered shortcut |
| 28 | +- **GIVEN** more than one registered shortcut would match the keydown |
| 29 | +- **WHEN** the `ui:key-down` event fires |
| 30 | +- **THEN** the plugin applies only the first matching tool and stops |
| 31 | + |
| 32 | +#### Scenario: Ignoring keydown during IME composition |
| 33 | +- **GIVEN** the native keydown event has `isComposing === true` |
| 34 | +- **WHEN** the `ui:key-down` event fires |
| 35 | +- **THEN** the plugin performs no matching and leaves the native event untouched |
| 36 | + |
| 37 | +#### Scenario: Tolerating a missing caret when applying a tool |
| 38 | +- **GIVEN** applying the inline tool throws an `IndexError` (e.g. no caret in a text input) |
| 39 | +- **WHEN** a matching shortcut is dispatched |
| 40 | +- **THEN** the plugin swallows the error and leaves the editor unchanged, while any other error propagates |
| 41 | + |
| 42 | +#### Scenario: Releasing shortcuts on destroy |
| 43 | +- **GIVEN** a `ShortcutsPlugin` instance has registered shortcuts |
| 44 | +- **WHEN** `destroy()` is called |
| 45 | +- **THEN** it clears the registered shortcuts so subsequent keydowns dispatch nothing |
| 46 | + |
| 47 | +Shortcuts for block tools and block tunes (a `shortcuts` map in tool `options`) are reserved for future work and not yet implemented. |
| 48 | + |
| 49 | +Implemented in `src/index.ts`, validated by its co-located `.spec.ts`. |
0 commit comments