1 | React Shortcuts
|
2 | =========
|
3 |
|
4 | **Manage keyboard shortcuts from one place.**
|
5 |
|
6 | [![Build Status](https://travis-ci.org/avocode/react-shortcuts.svg)][travis]
|
7 |
|
8 |
|
9 | Intro
|
10 | ------
|
11 |
|
12 |
|
13 | Managing keyboard shortcuts can sometimes get messy. Or always, if not implemented the right way.
|
14 |
|
15 | Real problems:
|
16 |
|
17 | - You can't easily tell which shortcut is bound to which component
|
18 | - You have to write a lot of boilerplate code (`addEventListeners`, `removeEventListeners`, ...)
|
19 | - Memory leaks are a real problem if components don’t remove their listeners properly
|
20 | - Platform specific shortcuts is another headache
|
21 | - It's more difficult to implement feature like user-defined shortcuts
|
22 | - You can't easily get allthe application shortcuts and display it (e.g. in settings)
|
23 |
|
24 |
|
25 | **React shortcuts to the rescue!**
|
26 | -----------
|
27 |
|
28 | With `react-shortcuts` you can declaratively manage shortcuts for each one of your React components.
|
29 |
|
30 | **Important parts of React Shortcuts:**
|
31 |
|
32 | - Your `keymap` definition
|
33 | - `ShortcutManager` which handles `keymap`
|
34 | - `<Shortcut>` component for handling shortcuts
|
35 |
|
36 | **DEMO:** http://avocode.github.io/react-shortcuts/
|
37 |
|
38 | Quick tour
|
39 | ----------
|
40 |
|
41 |
|
42 | #### 1. `npm install react-shortcuts`
|
43 |
|
44 |
|
45 | #### 2. **Define application shortcuts**
|
46 |
|
47 | Create a new JS, Coffee, JSON or CSON file wherever you want (which probably is your project root). And define the shortcuts for your React component.
|
48 |
|
49 | **Keymap definition**
|
50 |
|
51 | ```
|
52 | {
|
53 | "Namespace": {
|
54 | "Action": "Shortcut",
|
55 | "Action_2": ["Shortcut", "Shortcut"],
|
56 | "Action_3": {
|
57 | "osx": "Shortcut",
|
58 | "windows": ["Shortcut", "Shortcut"],
|
59 | "linux": "Shortcut"
|
60 | }
|
61 | }
|
62 | }
|
63 | ```
|
64 |
|
65 | - `Namespace` should ideally be the component’s `displayName`.
|
66 | - `Action` describes what will be happening. For example `MODAL_CLOSE`.
|
67 | - `Keyboard shortcut` can be a string, array of strings or an object which
|
68 | specifies platform differences (Windows, OSX, Linux). The
|
69 | shortcut may be composed of single keys (`a`, `6`,…), combinations
|
70 | (`command+shift+k`) or sequences (`up up down down left right left right B A`).
|
71 |
|
72 | > **Mousetrap** is used under the
|
73 | hood for handling the shortcuts. [Read more][mousetrap] about how you can
|
74 | specify keys.
|
75 |
|
76 |
|
77 | ##### Example `keymap` definition (in CoffeeScript):
|
78 |
|
79 |
|
80 | ```
|
81 | module.exports =
|
82 | TodoItem:
|
83 | MOVE_LEFT: 'left'
|
84 | MOVE_RIGHT: 'right'
|
85 | MOVE_UP: ['up', 'w']
|
86 | COPY:
|
87 | osx: 'command+c'
|
88 | windows: 'ctrl+c'
|
89 | linux: 'ctrl+c'
|
90 | ```
|
91 |
|
92 | Save this file as `keymap.[js|coffee|json|cson]` and require it into your main
|
93 | file.
|
94 |
|
95 | ```
|
96 | keymap = require './keymap'
|
97 | ```
|
98 |
|
99 | #### 3. Rise of the ShortcutsManager
|
100 |
|
101 | Define your keymap in whichever supported format but in the end it must be an
|
102 | object. `ShortcutsManager` can’t parse JSON and will certainly not be happy
|
103 | about the situation.
|
104 |
|
105 | ```
|
106 | keymap = require './keymap'
|
107 | ShortcutsManager = require 'react-shortcuts'
|
108 |
|
109 | shortcutManager = new ShortcutsManager(keymap)
|
110 |
|
111 | # Or like this
|
112 |
|
113 | shortcutManager = new ShortcutsManager()
|
114 | shortcutManager.setKeymap(keymap)
|
115 |
|
116 | ```
|
117 |
|
118 | #### 4. Include `shortcutManager` into getChildContext of some parent component. So that `<shortcuts>` can receive it.
|
119 |
|
120 | ```
|
121 | App = React.createClass
|
122 | displayName: 'App'
|
123 |
|
124 | childContextTypes:
|
125 | shortcuts: React.PropTypes.object.isRequired
|
126 |
|
127 | getChildContext: ->
|
128 | shortcuts: shortcutManager
|
129 |
|
130 | ```
|
131 |
|
132 | #### 5. Require the <shortcuts> component
|
133 |
|
134 | You need to require the component in the file you want to use shortcuts in.
|
135 | For example `<TodoItem>`.
|
136 |
|
137 | ```
|
138 | Shortcuts = require `react-shortcuts/component`
|
139 |
|
140 | TodoItem = React.createClass
|
141 | displayName: 'TodoItem'
|
142 |
|
143 | _handleShortcuts: (action, event) ->
|
144 | switch action
|
145 | when 'MOVE_LEFT' then console.log('moving left')
|
146 | when 'MOVE_RIGHT' then console.log('moving right')
|
147 | when 'MOVE_UP' then console.log('moving up')
|
148 | when 'COPY' then console.log('copying stuff')
|
149 |
|
150 | render: ->
|
151 |
|
152 | div className: 'todo-item',
|
153 |
|
154 | Shortcuts
|
155 | name: @constructor.displayName
|
156 | handler: @_handleShortcuts,
|
157 |
|
158 | div null,
|
159 | 'Buy some milk'
|
160 |
|
161 | ```
|
162 |
|
163 | > The `<Shortcuts>` component creates a `<shortcuts>` element in HTML, binds
|
164 | listeners and adds tabIndex to the element so that it’s focusable.
|
165 | `_handleShortcuts` is invoked when some of the defined shortcuts fire.
|
166 |
|
167 | ## Custom props for `<Shortcuts>` component
|
168 |
|
169 | - `handler`: func.isRequired
|
170 | - `name`: string.isRequired
|
171 | - `tabIndex`: number
|
172 | - Default is `-1`
|
173 | - `className`: string
|
174 | - `eventType`: string
|
175 | - Just for gourmets
|
176 | - `stopPropagation`: bool
|
177 | - `preventDefault`: bool
|
178 | - `targetNode`: DOM Node
|
179 | - Use this one with caution. It binds listeners to the provided string instead
|
180 | of the component.
|
181 | - `isGlobal`: bool
|
182 | - Use this when you have some global app wide shortcuts like `CMD+Q`.
|
183 |
|
184 |
|
185 | ## Thanks, Atom
|
186 |
|
187 |
|
188 | This library is inspired by [Atom Keymap].
|
189 |
|
190 |
|
191 | [Atom Keymap]: https://github.com/atom/atom-keymap/
|
192 | [travis]: https://travis-ci.org/avocode/react-shortcuts
|
193 | [mousetrap]: https://craig.is/killing/mice
|
194 | [keymaps]: https://github.com/atom/atom-keymap/
|