summaryrefslogtreecommitdiff
path: root/doc/development/fe_guide/keyboard_shortcuts.md
diff options
context:
space:
mode:
Diffstat (limited to 'doc/development/fe_guide/keyboard_shortcuts.md')
-rw-r--r--doc/development/fe_guide/keyboard_shortcuts.md98
1 files changed, 98 insertions, 0 deletions
diff --git a/doc/development/fe_guide/keyboard_shortcuts.md b/doc/development/fe_guide/keyboard_shortcuts.md
new file mode 100644
index 00000000000..da9b3702a8d
--- /dev/null
+++ b/doc/development/fe_guide/keyboard_shortcuts.md
@@ -0,0 +1,98 @@
+# Implementing keyboard shortcuts
+
+We use [Mousetrap](https://craig.is/killing/mice) to implement keyboard
+shortcuts in GitLab.
+
+Mousetrap provides an API that allows keyboard shortcut strings (like
+`mod+shift+p` or `p b`) to be bound to a JavaScript handler:
+
+```javascript
+// Don't do this; see note below
+Mousetrap.bind('p b', togglePerformanceBar)
+```
+
+However, associating a hard-coded key sequence to a handler (as shown above)
+prevents these keyboard shortcuts from being customized or disabled by users.
+
+To allow keyboard shortcuts to be customized, commands are defined in
+`~/behaviors/shortcuts/keybindings.js`. The `keysFor` method is responsible for
+returning the correct key sequence for the provided command:
+
+```javascript
+import { keysFor, TOGGLE_PERFORMANCE_BAR } from '~/behaviors/shortcuts/keybindings'
+
+Mousetrap.bind(keysFor(TOGGLE_PERFORMANCE_BAR), togglePerformanceBar);
+```
+
+## Shortcut customization
+
+`keybindings.js` stores keyboard shortcut customizations as a JSON string in
+`localStorage`. When `keybindings.js` is first imported, it fetches any
+customizations from `localStorage` and merges these customizations into the
+default set of keybindings. There is no UI to edit these customizations.
+
+## Adding new shortcuts
+
+Because keyboard shortcuts can be customized or disabled by end users,
+developers are encouraged to build _lots_ of keyboard shortcuts into GitLab.
+Shortcuts that are less likely to be used should be
+[disabled](#disabling-shortcuts) by default.
+
+To add a new shortcut, define and export a new command string in
+`keybindings.js`:
+
+```javascript
+export const MAKE_COFFEE = 'foodAndBeverage.makeCoffee';
+```
+
+Next, add a new command definition under the appropriate group in the
+`keybindingGroups` array:
+
+```javascript
+{
+ description: s__('KeyboardShortcuts|Make coffee'),
+ command: MAKE_COFFEE,
+ defaultKeys: ['mod+shift+c'],
+ customKeys: customizations[MAKE_COFFEE],
+}
+```
+
+Finally, in the application code, import the `keysFor` function and the new
+command and bind the shortcut to the handler using Mousetrap:
+
+```javascript
+import { keysFor, MAKE_COFFEE } from '~/behaviors/shortcuts/keybindings'
+
+Mousetrap.bind(keysFor(MAKE_COFFEE), makeCoffee);
+```
+
+See the existing the command definitions in `keybindings.js` for more examples.
+
+## Disabling shortcuts
+
+A shortcut can be disabled, also known as _unassigned_, by assigning the
+shortcut to an empty array `[]`. For example, to introduce a new shortcut that
+is disabled by default, a command can be defined like this:
+
+```javascript
+export const MAKE_MOCHA = 'foodAndBeverage.makeMocha';
+
+{
+ description: s__('KeyboardShortcuts|Make a mocha'),
+ command: MAKE_MOCHA,
+ defaultKeys: [],
+ customKeys: customizations[MAKE_MOCHA],
+}
+```
+
+## Make cross-platform shortcuts
+
+It's difficult to make shortcuts that work well in all platforms and browsers.
+This is one of the reasons that being able to customize and disable shortcuts is
+so important.
+
+One important way to make keyboard shortcuts more portable is to use the `mod`
+shortcut string, which resolves to `command` on Mac and `ctrl` otherwise.
+
+See [Mousetrap's documentation](https://craig.is/killing/mice#api.bind.combo)
+for more information.